diff --git a/.cargo/config.toml b/.cargo/config.toml
index 0e465b2d..8db457df 100644
--- a/.cargo/config.toml
+++ b/.cargo/config.toml
@@ -1,2 +1,4 @@
-[target.wasm32-unknown-unknown]
-rustflags = ["--cfg", "getrandom_backend=\"wasm_js\""]
+[env]
+TS_RS_EXPORT_DIR = { value = "ui/src/generated", relative = true }
+TS_RS_IMPORT_EXTENSION = "ts"
+TS_RS_LARGE_INT = "number"
diff --git a/.github/actions/setup/action.yml b/.github/actions/setup/action.yml
new file mode 100644
index 00000000..c914319f
--- /dev/null
+++ b/.github/actions/setup/action.yml
@@ -0,0 +1,37 @@
+name: Set up Gate
+description: Check out the pinned Hellas workspace and load Gate's locked development tools
+runs:
+ using: composite
+ steps:
+ - name: Read Hellas revision
+ id: hellas
+ shell: bash
+ working-directory: ${{ github.workspace }}/gate
+ run: |
+ revision=$(<.hellas-revision)
+ if [[ ! "$revision" =~ ^[0-9a-f]{40}$ ]]; then
+ echo "::error::.hellas-revision must contain one full commit SHA"
+ exit 1
+ fi
+ printf 'revision=%s\n' "$revision" >> "$GITHUB_OUTPUT"
+
+ - name: Check out Hellas
+ uses: actions/checkout@v5
+ with:
+ repository: hellas-ai/hellas
+ ref: ${{ steps.hellas.outputs.revision }}
+ path: hellas
+ persist-credentials: false
+
+ - name: Install Nix
+ uses: cachix/install-nix-action@v31
+ with:
+ github_access_token: ${{ github.token }}
+
+ - name: Cache Rust dependencies
+ uses: Swatinem/rust-cache@v2
+ with:
+ workspaces: gate -> target
+ key: ${{ runner.arch }}-${{ hashFiles('gate/flake.lock', 'gate/.hellas-revision') }}
+ cache-bin: false
+ cmd-format: nix develop --no-update-lock-file "${{ github.workspace }}/gate" --command {0}
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
deleted file mode 100644
index 2406f094..00000000
--- a/.github/dependabot.yml
+++ /dev/null
@@ -1,12 +0,0 @@
-version: 2
-updates:
- - package-ecosystem: "cargo"
- directory: "/"
- schedule:
- interval: "daily"
- open-pull-requests-limit: 10
-
- - package-ecosystem: "github-actions"
- directory: "/"
- schedule:
- interval: "weekly"
\ No newline at end of file
diff --git a/.github/scripts/macos-keychain.sh b/.github/scripts/macos-keychain.sh
new file mode 100644
index 00000000..b851fc05
--- /dev/null
+++ b/.github/scripts/macos-keychain.sh
@@ -0,0 +1,55 @@
+#!/usr/bin/env bash
+set -euo pipefail
+
+: "${RUNNER_TEMP:?This script requires a GitHub Actions runner}"
+keychain="$RUNNER_TEMP/gate-signing.keychain-db"
+certificate="$RUNNER_TEMP/gate-signing.p12"
+search_list="$RUNNER_TEMP/gate-keychain-search-list.txt"
+
+case "${1:-}" in
+ setup)
+ : "${APPLE_CERTIFICATE:?Missing APPLE_CERTIFICATE}"
+ : "${APPLE_CERTIFICATE_PASSWORD:?Missing APPLE_CERTIFICATE_PASSWORD}"
+ : "${APPLE_SIGNING_IDENTITY:?Missing APPLE_SIGNING_IDENTITY}"
+ : "${KEYCHAIN_PASSWORD:?Missing KEYCHAIN_PASSWORD}"
+ if [[ "$APPLE_SIGNING_IDENTITY" != "Developer ID Application:"* &&
+ ! "$APPLE_SIGNING_IDENTITY" =~ ^[0-9A-Fa-f]{40}$ ]]; then
+ echo "APPLE_SIGNING_IDENTITY must be a Developer ID Application name or certificate SHA-1" >&2
+ exit 1
+ fi
+ umask 077
+ /usr/bin/security list-keychains -d user > "$search_list"
+ printf '%s' "$APPLE_CERTIFICATE" | /usr/bin/base64 --decode > "$certificate"
+ /usr/bin/security create-keychain -p "$KEYCHAIN_PASSWORD" "$keychain"
+ /usr/bin/security set-keychain-settings -lut 21600 "$keychain"
+ /usr/bin/security unlock-keychain -p "$KEYCHAIN_PASSWORD" "$keychain"
+ /usr/bin/security import "$certificate" -P "$APPLE_CERTIFICATE_PASSWORD" \
+ -k "$keychain" -t cert -f pkcs12 -T /usr/bin/codesign
+ /usr/bin/security set-key-partition-list -S apple-tool:,apple:,codesign: \
+ -s -k "$KEYCHAIN_PASSWORD" "$keychain"
+ keychains=("$keychain")
+ while IFS= read -r previous; do
+ keychains+=("$previous")
+ done < <(sed -E 's/^[[:space:]]*"//; s/"[[:space:]]*$//' "$search_list")
+ /usr/bin/security list-keychains -d user -s "${keychains[@]}"
+ /usr/bin/security find-identity -v -p codesigning "$keychain"
+ rm -f "$certificate"
+ ;;
+ cleanup)
+ if [[ -f "$search_list" ]]; then
+ keychains=()
+ while IFS= read -r previous; do
+ keychains+=("$previous")
+ done < <(sed -E 's/^[[:space:]]*"//; s/"[[:space:]]*$//' "$search_list")
+ /usr/bin/security list-keychains -d user -s "${keychains[@]}"
+ fi
+ if [[ -f "$keychain" ]]; then
+ /usr/bin/security delete-keychain "$keychain"
+ fi
+ rm -f "$certificate"
+ ;;
+ *)
+ echo "Usage: macos-keychain.sh setup|cleanup" >&2
+ exit 1
+ ;;
+esac
diff --git a/.github/scripts/package-macos-release.sh b/.github/scripts/package-macos-release.sh
new file mode 100644
index 00000000..adab8673
--- /dev/null
+++ b/.github/scripts/package-macos-release.sh
@@ -0,0 +1,77 @@
+#!/usr/bin/env bash
+set -euo pipefail
+
+: "${CARGO_TARGET_DIR:?Missing CARGO_TARGET_DIR}"
+: "${RUNNER_TEMP:?This script requires a GitHub Actions runner}"
+: "${APPLE_SIGNING_IDENTITY:?Missing APPLE_SIGNING_IDENTITY}"
+: "${APPLE_ID:?Missing APPLE_ID}"
+: "${APPLE_PASSWORD:?Missing APPLE_PASSWORD}"
+: "${APPLE_TEAM_ID:?Missing APPLE_TEAM_ID}"
+: "${GITHUB_REF_NAME:?Missing release tag}"
+
+version=$(python3 .github/scripts/release-version.py "$GITHUB_REF_NAME")
+app="$CARGO_TARGET_DIR/aarch64-apple-darwin/release/bundle/macos/Hellas Gate.app"
+release_dir=$(mktemp -d "$RUNNER_TEMP/gate-release.XXXXXX")
+staging=$(mktemp -d "$RUNNER_TEMP/gate-dmg.XXXXXX")
+mountpoint=$(mktemp -d "$RUNNER_TEMP/gate-mount.XXXXXX")
+extraction=$(mktemp -d "$RUNNER_TEMP/gate-zip.XXXXXX")
+archive="$release_dir/Hellas-Gate_${version}_aarch64.app.zip"
+dmg="$release_dir/Hellas-Gate_${version}_aarch64.dmg"
+mounted=false
+
+cleanup() {
+ if [[ "$mounted" == true ]]; then
+ /usr/bin/hdiutil detach "$mountpoint" || true
+ fi
+}
+trap cleanup EXIT
+
+notarize() {
+ local artifact=$1
+ local report=$2
+ if ! /usr/bin/xcrun notarytool submit "$artifact" \
+ --apple-id "$APPLE_ID" --password "$APPLE_PASSWORD" --team-id "$APPLE_TEAM_ID" \
+ --wait --timeout 30m --output-format json > "$report"; then
+ cat "$report"
+ return 1
+ fi
+ cat "$report"
+ if [[ "$(/usr/bin/plutil -extract status raw -o - "$report")" != Accepted ]]; then
+ local submission
+ submission=$(/usr/bin/plutil -extract id raw -o - "$report")
+ /usr/bin/xcrun notarytool log "$submission" \
+ --apple-id "$APPLE_ID" --password "$APPLE_PASSWORD" --team-id "$APPLE_TEAM_ID" || true
+ return 1
+ fi
+}
+
+bash .github/scripts/verify-macos-app.sh "$app"
+/usr/bin/ditto -c -k --sequesterRsrc --keepParent "$app" "$archive"
+notarize "$archive" "$release_dir/app-notarization.json"
+/usr/bin/xcrun stapler staple "$app"
+bash .github/scripts/verify-macos-app.sh "$app" --notarized
+
+# Build the disk image from the stapled app so both delivery formats work offline.
+/usr/bin/ditto "$app" "$staging/Hellas Gate.app"
+ln -s /Applications "$staging/Applications"
+/usr/bin/hdiutil create -volname 'Hellas Gate' -srcfolder "$staging" -format UDZO "$dmg"
+/usr/bin/codesign --force --sign "$APPLE_SIGNING_IDENTITY" --timestamp "$dmg"
+/usr/bin/codesign --verify --strict --verbose=2 "$dmg"
+notarize "$dmg" "$release_dir/dmg-notarization.json"
+/usr/bin/xcrun stapler staple "$dmg"
+/usr/bin/xcrun stapler validate "$dmg"
+/usr/sbin/spctl --assess --type open --context context:primary-signature --verbose=2 "$dmg"
+/usr/bin/hdiutil verify "$dmg"
+/usr/bin/hdiutil attach "$dmg" -readonly -nobrowse -mountpoint "$mountpoint"
+mounted=true
+bash .github/scripts/verify-macos-app.sh "$mountpoint/Hellas Gate.app" --notarized
+/usr/bin/hdiutil detach "$mountpoint"
+mounted=false
+
+# Recreate the zip after stapling; ditto preserves executable modes and symlinks.
+/usr/bin/ditto -c -k --sequesterRsrc --keepParent "$app" "$archive"
+/usr/bin/ditto -x -k "$archive" "$extraction"
+bash .github/scripts/verify-macos-app.sh "$extraction/Hellas Gate.app" --notarized
+test -s "$dmg"
+test -s "$archive"
+printf 'GATE_RELEASE_DIR=%s\n' "$release_dir" >> "$GITHUB_ENV"
diff --git a/.github/scripts/release-version.py b/.github/scripts/release-version.py
new file mode 100644
index 00000000..bbd4da7c
--- /dev/null
+++ b/.github/scripts/release-version.py
@@ -0,0 +1,26 @@
+"""Validate Cargo/Tauri version agreement, and optionally the release tag."""
+
+import json
+import re
+import sys
+import tomllib
+from pathlib import Path
+
+root = Path(__file__).resolve().parents[2]
+workspace = tomllib.loads((root / "Cargo.toml").read_text())
+package = tomllib.loads((root / "src-tauri/Cargo.toml").read_text())["package"]
+config = json.loads((root / "src-tauri/tauri.conf.json").read_text())
+version = workspace["workspace"]["package"]["version"]
+package_version = package["version"]
+if package_version == {"workspace": True}:
+ package_version = version
+
+if not re.fullmatch(r"\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?", version):
+ sys.exit(f"Invalid release version: {version}")
+if config["version"] != version or package_version != version:
+ sys.exit("Cargo workspace, desktop package, and Tauri versions must agree")
+if len(sys.argv) > 2:
+ sys.exit("Usage: release-version.py [vVERSION]")
+if len(sys.argv) == 2 and sys.argv[1] != f"v{version}":
+ sys.exit(f"Release tag must be v{version}, got {sys.argv[1]}")
+print(version)
diff --git a/.github/scripts/verify-macos-app.sh b/.github/scripts/verify-macos-app.sh
new file mode 100644
index 00000000..0ab3423f
--- /dev/null
+++ b/.github/scripts/verify-macos-app.sh
@@ -0,0 +1,24 @@
+#!/usr/bin/env bash
+set -euo pipefail
+
+app=${1:?Usage: verify-macos-app.sh APP [--notarized]}
+version=$(python3 .github/scripts/release-version.py)
+plist="$app/Contents/Info.plist"
+test -f "$plist"
+[[ "$(/usr/libexec/PlistBuddy -c 'Print :CFBundleIdentifier' "$plist")" == ai.hellas.gate ]]
+[[ "$(/usr/libexec/PlistBuddy -c 'Print :CFBundleShortVersionString' "$plist")" == "$version" ]]
+executable=$(/usr/libexec/PlistBuddy -c 'Print :CFBundleExecutable' "$plist")
+test -x "$app/Contents/MacOS/$executable"
+[[ "$(/usr/bin/lipo -archs "$app/Contents/MacOS/$executable")" == arm64 ]]
+/usr/bin/codesign --verify --deep --strict --verbose=2 "$app"
+
+if [[ "${2:-}" == --notarized ]]; then
+ : "${APPLE_TEAM_ID:?APPLE_TEAM_ID is required to verify a release}"
+ details=$(/usr/bin/codesign --display --verbose=4 "$app" 2>&1)
+ printf '%s\n' "$details"
+ printf '%s\n' "$details" | grep -q '^Authority=Developer ID Application:'
+ printf '%s\n' "$details" | grep -Fqx "TeamIdentifier=$APPLE_TEAM_ID"
+ printf '%s\n' "$details" | grep -Eq '^CodeDirectory .*flags=.*runtime'
+ /usr/bin/xcrun stapler validate "$app"
+ /usr/sbin/spctl --assess --type execute --verbose=2 "$app"
+fi
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 0b9291a2..c2be0089 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -2,239 +2,96 @@ name: CI
on:
push:
- branches: [ master ]
+ branches: [master]
pull_request:
- branches: [ master ]
+ branches: [master]
+ merge_group:
+ workflow_dispatch:
+
+permissions:
+ contents: read
+
+concurrency:
+ group: ci-${{ github.event.pull_request.number || github.ref }}
+ cancel-in-progress: true
env:
CARGO_TERM_COLOR: always
+ CARGO_TARGET_DIR: ${{ github.workspace }}/gate/target
RUST_BACKTRACE: 1
+defaults:
+ run:
+ shell: bash
+ working-directory: gate
+
jobs:
- test:
- name: Test
- runs-on: ubuntu-latest
+ linux:
+ name: Linux checks
+ runs-on: ubuntu-24.04
+ timeout-minutes: 90
steps:
- - uses: actions/checkout@v5
- - uses: mkroening/rust-toolchain-toml@main
- - uses: Swatinem/rust-cache@v2
+ - uses: actions/checkout@v5
+ with:
+ path: gate
+ persist-credentials: false
+ - uses: ./gate/.github/actions/setup
- # Linux-specific dependencies
- - name: Install Linux dependencies
- if: runner.os == 'Linux'
- run: |
- sudo apt-get update
- sudo apt-get install -y libgtk-3-dev libwebkit2gtk-4.1-dev libayatana-appindicator3-dev librsvg2-dev clang xdg-utils
+ - name: Check formatting
+ run: nix develop --no-update-lock-file --command cargo fmt --all -- --check
- - name: Check formatting
- run: cargo fmt --all -- --check
-
- - name: Clippy
- run: cargo clippy --workspace --all-features -- -D warnings
-
- - name: Build
- run: cargo build --all-features
-
- - name: Test
- run: cargo test --all-features
-
- gui-build:
- name: GUI Build
- needs: test
- runs-on: ${{ matrix.os }}
- strategy:
- fail-fast: false
- matrix:
- include:
- - os: ubuntu-latest
- target: x86_64-unknown-linux-gnu
- - os: macos-latest
- target: x86_64-apple-darwin
- - os: macos-latest
- target: aarch64-apple-darwin
- - os: windows-latest
- target: x86_64-pc-windows-msvc
- steps:
- - uses: actions/checkout@v5
-
- # Install Rust toolchain
- - uses: mkroening/rust-toolchain-toml@main
- - uses: Swatinem/rust-cache@v2
-
- # Import Apple certificate for macOS builds
- - name: Import Apple Certificate
- if: runner.os == 'macOS' && github.event_name != 'pull_request'
- env:
- APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }}
- APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
- KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }}
- run: |
- # Create variables
- CERTIFICATE_PATH=$RUNNER_TEMP/build_certificate.p12
- KEYCHAIN_PATH=$RUNNER_TEMP/app-signing.keychain-db
-
- # Import certificate from secrets
- echo -n "$APPLE_CERTIFICATE" | base64 --decode -o $CERTIFICATE_PATH
-
- # Create temporary keychain
- security create-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
- security set-keychain-settings -lut 21600 $KEYCHAIN_PATH
- security unlock-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
-
- # Import certificate to keychain
- security import $CERTIFICATE_PATH -P "$APPLE_CERTIFICATE_PASSWORD" -A -t cert -f pkcs12 -k $KEYCHAIN_PATH
- security set-key-partition-list -S apple-tool:,apple: -k "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
- security list-keychain -d user -s $KEYCHAIN_PATH
-
- # Add WASM target
- - name: Add WASM target
- run: rustup target add wasm32-unknown-unknown
-
- # Cache cargo-installed tools
- - name: Cache cargo tools
- uses: actions/cache@v4
- with:
- path: ~/.cargo/bin
- key: ${{ runner.os }}-cargo-tools-trunk-tauri-${{ hashFiles('**/Cargo.lock') }}
- restore-keys: |
- ${{ runner.os }}-cargo-tools-trunk-tauri-
- ${{ runner.os }}-cargo-tools-
-
- # Install build tools
- - name: Install build tools
- shell: bash
- run: |
- # Check if trunk is already installed
- if ! command -v trunk &> /dev/null; then
- echo "Installing trunk..."
- cargo install trunk --locked
- else
- echo "trunk is already installed"
- fi
-
- # Check if tauri is already installed
- if ! command -v cargo-tauri &> /dev/null; then
- echo "Installing tauri-cli..."
- cargo install tauri-cli --locked
- else
- echo "tauri-cli is already installed"
- fi
-
- # Install tailwindcss standalone CLI
- - name: Install tailwindcss
- shell: bash
- run: |
- # Map runner OS and arch to tailwind binary names
- case "${{ runner.os }}-${{ runner.arch }}" in
- "Linux-X64") BINARY="tailwindcss-linux-x64"; DEST="/usr/local/bin/tailwindcss" ;;
- "macOS-X64") BINARY="tailwindcss-macos-x64"; DEST="/usr/local/bin/tailwindcss" ;;
- "macOS-ARM64") BINARY="tailwindcss-macos-arm64"; DEST="/usr/local/bin/tailwindcss" ;;
- "Windows-X64") BINARY="tailwindcss-windows-x64.exe"; DEST="$HOME/.cargo/bin/tailwindcss.exe" ;;
- esac
-
- echo "Installing $BINARY to $DEST"
- curl -sL "https://github.com/tailwindlabs/tailwindcss/releases/download/v4.1.11/${BINARY}" -o "$DEST"
- chmod +x "$DEST"
-
- # Linux-specific dependencies
- - name: Install Linux dependencies
- if: runner.os == 'Linux'
- run: |
- sudo apt-get update
- sudo apt-get install -y libgtk-3-dev libwebkit2gtk-4.1-dev libayatana-appindicator3-dev librsvg2-dev clang xdg-utils
-
- # Windows-specific dependencies
- - name: Install Windows dependencies
- if: runner.os == 'Windows'
- shell: cmd
- run: |
- vcpkg install openssl:x64-windows-static
- vcpkg install openssl:x64-windows-static-md
- vcpkg integrate install
-
- # Build frontends and GUI (without signing for PRs)
- - name: Build GUI
- if: github.event_name == 'pull_request'
- env:
- OPENSSL_STATIC: 1
- run: cd crates/gui && cargo tauri build
-
- # Build frontends and GUI with signing (for pushes to master)
- - name: Build GUI and Sign
- if: github.event_name != 'pull_request'
- env:
- OPENSSL_STATIC: 1
- APPLE_SIGNING_IDENTITY: ${{ secrets.APPLE_SIGNING_IDENTITY }}
- APPLE_ID: ${{ secrets.APPLE_ID }}
- APPLE_PASSWORD: ${{ secrets.APPLE_PASSWORD }}
- APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
- run: cd crates/gui && cargo tauri build
+ - name: Clippy
+ run: nix develop --no-update-lock-file --command cargo clippy --locked --workspace --all-targets --all-features -- -D warnings
- # Notarize macOS app
- - name: Notarize macOS App
- if: runner.os == 'macOS' && github.event_name != 'pull_request'
- env:
- APPLE_ID: ${{ secrets.APPLE_ID }}
- APPLE_PASSWORD: ${{ secrets.APPLE_PASSWORD }}
- APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
- run: |
- # Find the DMG file
- DMG_FILE=$(find target/release/bundle/dmg -name "*.dmg" | head -1)
+ - name: Rust tests
+ run: nix develop --no-update-lock-file --command cargo test --locked --workspace --all-features
- if [ -n "$DMG_FILE" ]; then
- echo "Notarizing $DMG_FILE..."
+ - name: Generate and check TypeScript bindings
+ run: |
+ rm -f -- ui/src/generated/*.ts
+ nix develop --no-update-lock-file --command make bindings
+ changes=$(git status --porcelain --untracked-files=all -- ui/src/generated)
+ if [[ -n "$changes" ]]; then
+ printf '%s\n' "$changes"
+ git diff -- ui/src/generated
+ echo "::error::Generated bindings are stale; run make bindings and commit the result"
+ exit 1
+ fi
- # Submit for notarization
- xcrun notarytool submit "$DMG_FILE" \
- --apple-id "$APPLE_ID" \
- --password "$APPLE_PASSWORD" \
- --team-id "$APPLE_TEAM_ID" \
- --wait
+ - name: Typecheck and build frontend
+ run: nix develop --no-update-lock-file --command make ui-build
- # Staple the notarization ticket
- xcrun stapler staple "$DMG_FILE"
+ macos:
+ name: macOS ARM64 app
+ runs-on: macos-15
+ timeout-minutes: 120
+ steps:
+ - uses: actions/checkout@v5
+ with:
+ path: gate
+ persist-credentials: false
+ - uses: ./gate/.github/actions/setup
- echo "Notarization complete!"
- else
- echo "No DMG file found"
- exit 1
- fi
+ - name: Build app
+ env:
+ APPLE_SIGNING_IDENTITY: '-'
+ run: nix develop --no-update-lock-file --command cargo tauri build --target aarch64-apple-darwin --bundles app -- --locked
- - name: Find and prepare artifacts
- shell: bash
- run: |
- mkdir -p artifacts
-
- # Tauri outputs to target/release/bundle
- if [[ "${{ runner.os }}" == "macOS" ]]; then
- # macOS: Look for DMG and app bundles
- if [[ -d "target/release/bundle" ]]; then
- echo "Found macOS bundles"
- cp -r target/release/bundle/dmg/*.dmg artifacts/ 2>/dev/null || true
- cp -r target/release/bundle/macos/*.app artifacts/ 2>/dev/null || true
- fi
- elif [[ "${{ runner.os }}" == "Linux" ]]; then
- # Linux: Look for deb and AppImage files
- if [[ -d "target/release/bundle" ]]; then
- echo "Found Linux bundles"
- cp -r target/release/bundle/deb/*.deb artifacts/ 2>/dev/null || true
- cp -r target/release/bundle/appimage/*.AppImage artifacts/ 2>/dev/null || true
- fi
- elif [[ "${{ runner.os }}" == "Windows" ]]; then
- # Windows: Look for MSI files
- if [[ -d "target/release/bundle" ]]; then
- echo "Found Windows bundles"
- cp -r target/release/bundle/msi/*.msi artifacts/ 2>/dev/null || true
- fi
- fi
-
- # List what we found
- echo "Artifacts found:"
- ls -la artifacts/ || echo "No artifacts directory"
-
- - name: Upload artifacts
- uses: actions/upload-artifact@v4
- with:
- name: gate-gui-${{ matrix.target }}
- path: artifacts/*
- if-no-files-found: warn
+ - name: Validate app bundle
+ run: bash .github/scripts/verify-macos-app.sh "$CARGO_TARGET_DIR/aarch64-apple-darwin/release/bundle/macos/Hellas Gate.app"
+
+ ci:
+ name: CI
+ if: ${{ always() }}
+ needs: [linux, macos]
+ runs-on: ubuntu-24.04
+ timeout-minutes: 5
+ steps:
+ - name: Require every check to pass
+ working-directory: .
+ env:
+ LINUX_RESULT: ${{ needs.linux.result }}
+ MACOS_RESULT: ${{ needs.macos.result }}
+ run: |
+ printf 'Linux: %s\nmacOS: %s\n' "$LINUX_RESULT" "$MACOS_RESULT"
+ [[ "$LINUX_RESULT" == success && "$MACOS_RESULT" == success ]]
diff --git a/.github/workflows/dependabot-auto-merge.yml b/.github/workflows/dependabot-auto-merge.yml
deleted file mode 100644
index aa431799..00000000
--- a/.github/workflows/dependabot-auto-merge.yml
+++ /dev/null
@@ -1,28 +0,0 @@
-name: Dependabot auto-merge
-on: pull_request
-
-permissions:
- contents: write
- pull-requests: write
-
-jobs:
- dependabot:
- runs-on: ubuntu-latest
- if: github.actor == 'dependabot[bot]'
- steps:
- - name: Dependabot metadata
- id: metadata
- uses: dependabot/fetch-metadata@v2
- with:
- github-token: "${{ secrets.GITHUB_TOKEN }}"
-
- - name: Enable auto-merge for Dependabot PRs
- if: |
- steps.metadata.outputs.update-type == 'version-update:semver-patch' ||
- steps.metadata.outputs.update-type == 'version-update:semver-minor'
- run: |
- echo "Enabling auto-merge for ${{ steps.metadata.outputs.update-type }} update"
- gh pr merge --auto --squash "$PR_URL"
- env:
- PR_URL: ${{github.event.pull_request.html_url}}
- GH_TOKEN: ${{secrets.GITHUB_TOKEN}}
\ No newline at end of file
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
new file mode 100644
index 00000000..ccae49e2
--- /dev/null
+++ b/.github/workflows/release.yml
@@ -0,0 +1,84 @@
+name: Release macOS app
+
+on:
+ push:
+ tags: ['v*']
+
+permissions:
+ contents: read
+
+concurrency:
+ group: release-${{ github.ref }}
+ cancel-in-progress: false
+
+env:
+ CARGO_TERM_COLOR: always
+ CARGO_TARGET_DIR: ${{ github.workspace }}/gate/target
+ RUST_BACKTRACE: 1
+
+defaults:
+ run:
+ shell: bash
+ working-directory: gate
+
+jobs:
+ release:
+ name: Signed macOS ARM64 release
+ runs-on: macos-15
+ timeout-minutes: 150
+ permissions:
+ contents: write
+ steps:
+ - uses: actions/checkout@v5
+ with:
+ path: gate
+ persist-credentials: false
+
+ - name: Validate release version
+ run: python3 .github/scripts/release-version.py "$GITHUB_REF_NAME"
+
+ - uses: ./gate/.github/actions/setup
+
+ - name: Import Developer ID certificate
+ env:
+ APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }}
+ APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
+ APPLE_SIGNING_IDENTITY: ${{ secrets.APPLE_SIGNING_IDENTITY }}
+ KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }}
+ run: bash .github/scripts/macos-keychain.sh setup
+
+ - name: Build signed app
+ env:
+ APPLE_SIGNING_IDENTITY: ${{ secrets.APPLE_SIGNING_IDENTITY }}
+ run: nix develop --no-update-lock-file --command cargo tauri build --target aarch64-apple-darwin --bundles app -- --locked
+
+ - name: Notarize and package app and DMG
+ env:
+ APPLE_SIGNING_IDENTITY: ${{ secrets.APPLE_SIGNING_IDENTITY }}
+ APPLE_ID: ${{ secrets.APPLE_ID }}
+ APPLE_PASSWORD: ${{ secrets.APPLE_PASSWORD }}
+ APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
+ run: bash .github/scripts/package-macos-release.sh
+
+ - name: Publish release assets
+ env:
+ GH_TOKEN: ${{ github.token }}
+ run: |
+ version=$(python3 .github/scripts/release-version.py "$GITHUB_REF_NAME")
+ dmg="$GATE_RELEASE_DIR/Hellas-Gate_${version}_aarch64.dmg"
+ archive="$GATE_RELEASE_DIR/Hellas-Gate_${version}_aarch64.app.zip"
+ test -s "$dmg"
+ test -s "$archive"
+ if gh release view "$GITHUB_REF_NAME" --repo "$GITHUB_REPOSITORY" >/dev/null 2>&1; then
+ gh release upload "$GITHUB_REF_NAME" "$dmg" "$archive" --repo "$GITHUB_REPOSITORY" --clobber
+ else
+ flags=()
+ if [[ "$version" == *-* ]]; then flags+=(--prerelease); fi
+ gh release create "$GITHUB_REF_NAME" "$dmg" "$archive" \
+ --repo "$GITHUB_REPOSITORY" --verify-tag --generate-notes \
+ --title "Hellas Gate $GITHUB_REF_NAME" "${flags[@]}"
+ fi
+
+ - name: Remove signing credentials
+ if: ${{ always() }}
+ run: bash .github/scripts/macos-keychain.sh cleanup
diff --git a/.github/workflows/update-flake.yml b/.github/workflows/update-flake.yml
deleted file mode 100644
index d511bf4f..00000000
--- a/.github/workflows/update-flake.yml
+++ /dev/null
@@ -1,51 +0,0 @@
-name: Update Flake
-
-on:
- schedule:
- # Run daily at 3:00 UTC
- - cron: '0 3 * * *'
- workflow_dispatch:
-
-jobs:
- update-flake:
- runs-on: ubuntu-latest
- steps:
- - uses: actions/checkout@v5
- with:
- token: ${{ secrets.GITHUB_TOKEN }}
-
- - uses: cachix/install-nix-action@v31
- with:
- github_access_token: ${{ secrets.GITHUB_TOKEN }}
-
- - name: Configure Git
- run: |
- git config --global user.email "41898282+github-actions[bot]@users.noreply.github.com"
- git config --global user.name "github-actions[bot]"
-
- - name: Update flake inputs
- run: |
- nix flake update --commit-lock-file
-
- - name: Check if updates were made
- id: check-updates
- run: |
- if git diff --quiet HEAD~1 HEAD -- flake.lock; then
- echo "updated=false" >> $GITHUB_OUTPUT
- else
- echo "updated=true" >> $GITHUB_OUTPUT
- fi
-
- - name: Create Pull Request
- if: steps.check-updates.outputs.updated == 'true'
- uses: peter-evans/create-pull-request@v7
- with:
- token: ${{ secrets.GITHUB_TOKEN }}
- commit-message: "chore: update flake.lock"
- title: "chore: update flake.lock"
- body: |
- Automated update of flake.lock dependencies.
-
- This PR was automatically created by the update-flake workflow.
- branch: update-flake-lock
- delete-branch: true
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
index 93959d1c..a5e9850d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,98 +1,13 @@
-#= Rust
-*result
-.claude/
-target/
-**/*.rs.bk
-*.pdb
-
-# IDE
-.idea/
-.vscode/
-*.swp
-*.swo
-*~
-.DS_Store
-
-# Environment
-.env
-.env.local
-.env.*.local
-
-# Logs
-*.log
-logs/
-
-# Testing
-tarpaulin-report.html
-cobertura.xml
-
-# Generated protobuf files
-crates/gate-proto/src/pb/
-
-# Benchmarking
/target/
-/benches/target/
+/src-tauri/gen/
+/result
+/result-*
+/.direnv/
-# Documentation
-/target/doc/
-
-# Temporary files
-*.tmp
-*.temp
-
-# OS
-.DS_Store
-Thumbs.db
-
-# Python (for any scripts)
-__pycache__/
-*.py[cod]
-*$py.class
-.Python
-venv/
-ENV/
-
-# Node (for any tooling)
-node_modules/
-npm-debug.log*
-yarn-debug.log*
-yarn-error.log*
-
-# Credentials (extra safety)
-*.pem
-*.key
-*.cert
-*.crt
-
-# Database files
+.env
+.env.*
*.db
*.db-shm
*.db-wal
-
-# Frontend build artifacts
-crates/gui/gen/
-crates/gui/resources/
-# Frontend build artifacts
-crates/frontend-daemon/dist/
-crates/frontend-daemon/assets/tailwind.output.css
-crates/frontend-tauri/dist/
-crates/frontend-tauri/assets/tailwind.output.css
-crates/frontend-relay/dist/
-crates/frontend-relay/assets/tailwind.output.css
-
-# Test files (temporary)
-crates/chat-ui/test_*.rs
-crates/chat-ui/tests/debug_*.rs
-crates/chat-ui/tests/quick_test.rs
-
-# Local development directories
-gate/
-/config/
-worktrees/
-
-# Tauri
-crates/gui/target/
-# Don't ignore icons, they're needed for the build
-# crates/gui/icons/
-gate-debug/
-.direnv/
+*.log
+.DS_Store
diff --git a/.hellas-revision b/.hellas-revision
new file mode 100644
index 00000000..63a58c5f
--- /dev/null
+++ b/.hellas-revision
@@ -0,0 +1 @@
+b4cdcd450d555f73fc8b3dd9d1af371917ff3a7c
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index d258220a..7c7c96d0 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -1,146 +1,18 @@
-# Contributing to Gate
-
-Thanks for your interest in improving Gate!
-
-Your contributions will be made to the project under both the Apache 2.0 and
-the MIT licenses.
-
-We accept contributions in the form of:
-
-- Pull Requests (via GitHub)
-- Bug reports (via GitHub issues)
-- User feedback (via [discord](https://discord.gg/YWZCWPrNTb))
-
-We do **not** currently accept contributions for:
-
-- Formatting (e.g., `cargo fmt`)
-- Spelling and grammar
-
-# Asking for help
-
-If you'd like help, contact us on [discord](https://discord.gg/YWZCWPrNTb).
-
-# Coding Guidelines
-
-General guidelines:
-- This is a production-grade codebase. No hacks, no shortcuts, no 'do this later'.
-- This is a greenfield project. We want the highest-quality code possible, so if we need to refactor or change things, its better to do it sooner than later.
-- Complexity is our enemy- we should strive to keep our codebase as simple as possible (but no simpler)
-- We are free to change whatever we need in this project in order to achieve our goals
-
-# Crate organisation
-## Core Crate
-This crate contains the core hellas data types, traits, etc.
-- Needs to compile across wide range of platforms, including wasm32
-- Any platform-specific dependencies (or stuff which doesn't compile for a target) MUST be feature-gated and disabled by default
-- Feature-specific code (e.g tlsforward functionality) should NOT be added to this crate
-- If at any point we find ourselves adding complexity, consider what we could refactor to make it better
-- We should always leave codebase in a better state than we found it-
- - If we remove the last usage of a function argument, remove it from the function signature and fix callers
- - If we remove the last usage of a function/method- remove it
-
-# Imports
-- In general, there should never be more than two-levels of `::` nesting- e.g instead of using `std::sync::Arc`, add `use std::sync::Arc` and just use `Arc`.
-- If we have a large number of imports from the same crate (common when loading e.g DTO types from client library):
- - Use wildcard imports (esp if upstream crate has a `::prelude` module):
- ```
- use some_client::types::*;
- fn accept(foo: FooType, bar: BarType) -> BazType;
- ```
- - Or module imports (should be used sparingly- `as ` should only be used when we have similarly-named type modules, to avoid confusion):
- ```
- use some_client_a::types as a_types;
- use some_client_b::types as b_types:
- fn convert(foo: a_types::Foo) -> b_types::Foo;
- ```
-- If we need conditional dependencies (e,g for `wasm`, whatever platform):
- - Make a single conditional and put all the imports in it, don't make a new conditional for each import
-- Put imports at the top of the file. We should not have import in e.g functions unless strictly necessary- ask my permission for this.
-
-# Types
-- We are very big of type safety. We should be using the type system as much as possible to help us.
-- This means stuff like:
- - Deriving the `From/Into/TryInto/TryFrom` traits instead of custom conversion functions.
- - No "magic variables"- consts and strings etc should be defined at module level `const WHATEVER_NAME: &str = "whatever-thingy"`, if appropriate
- - Avoid unstructured data- we should perform ser/de at our system boundaries as soon as possible
- - Try to avoid `Option<>` as much as possible- lets think about whether we can refactor to remove ambiguity
- - Return structured errors, not Strings
-
-# Style / Formatting
-- This repo runs *strict* formatting and clippy checks. Don't worry so much about formatting as we can run `cargo fmt` before committing
-- Clippy has lots of lints for unidiomatic code, try to add code that complies with these. e.g:
- - don't use `format!("my var: {}", var)` when you could use `format!("my var: {var}")`
- - no match blocks where if/else would suffice
- - appropriate use of `default` `self` etc.
-- Try to write concise, terse code when possible. I don't mean doing everything on one line with one-character variables and semicolons- just use your common sense.
-- When fixing clippy lints, do NOT do 'lazy fixes'; do NOT 'ignore' them, by e.g:
- - renaming variables to start with `_my_unused_var`- we should just remove the symbol altogether.
- - adding #[allow(whatever)] - unless there is really good reason- ask me for explicit permission to do this
-
-# Logging / Tracing
-We use the `tracing` crate throughout this repo.
-- Be very sparing with what is logged and at what level- noisy/spammy logs are worse than clean ones. If a code path is expected, it shouldn't be higher level than debug.
-- We use OLTP library to export traces from e.g http servers. We should make new spans when necessary
-- We must pass along correlation ids, trace parents etc, if present. For cross-service tracing.
-- Adding explicit `use tracing::{info, warn};` etc imports cause a lot of code churn- `macro_use` them in crate root and skip importing.
-
-# Comments
-- This is a production-grade codebase, and as such documentation is very important.
-- However, too many noisy/spamming/useless comments are bad too. They get out of date and are WORSE than useless.
-- Do NOT leave comments like this:
- - `identity: LocalIdentity, // Store identity in handle` - this is obvious, just don't write it
- - `identity: self.identity.clone(), // Use stored identity` - again
- - Totally useless: ```
- // Update state
- self.state_tx.send(TlsForwardState::Connecting)?;
- ```
- - Confusing- why is it telling us about auth middleware?!: ```
- /// Create the configuration routes
- pub fn router() -> axum::Router> {
- axum::Router::new().route("/api/config", routing::get(get_config).put(update_config))
- // Note: auth middleware is applied when converting to the final router
- }
- ```
-- If a comment IS necessary, put it in standard rustdoc syntax. Don't go overboard with stuff like examples, defaults
-- When refactoring code, feel free to drive-by cleanup any examples of these comments you see.
-
-# Dependencies
-- Relying too much on external libraries has various downsides- it bloats the code, may introduce security issues, forces strange api
-- However we also don't want to re-invent the wheel and write too much code ourselves, and re-implementing tricky stuff like encryption has its own security issues
-- In short, just be smart about adding dependencies. If you do need to add one:
- - Consider if it should be added as a workspace dependency- if more than one crate needs it
- - Should some other crate be re-exporting the dependency? For example, all our http code should be in `http` crate- probably that should re-export e.g `reqwest`
- - Be aware of features- when adding a crate, first check the available features. Probably we want to turn off the default features and just enable the ones we want
- - When adding a dependency to Cargo.toml, use coarse versions- e.g `thiserror = "1.0"`, `tracing = "0.2"`
- - If we remove the last remaining usage of a dependency in a crate, make sure to remove it from dependencies
-
-# Error Handling
-- This is production code, we should not have panic!(), unimplemented!(), todo!() anywhere- always return a Result.
- - In library code (ie, shared code that is used in different contexts):
- - Define a crate-level error type, using `thiserror`
- - Avoid using `.map_err` wherever possible- use the `#[from]` helper in `thiserror`
- - In application code (ie, code invoked directly by user, `main.rs`, etc)
- - It's fine to use `anyhow`
- - Add context where appropriate so backtraces, error messages are useful
-- Try to avoid `map_err()` wherever possible- this means not only using `From` but `Into`- for example:
- - If you are writing HTTP handlers, your functions may return something like `impl IntoResponse`. We should implement
- `IntoResponse` (e,g map errors, to http status codes, format as json, give description)
- - If you are writing Tauri commands and they expect Result, implement `Into` for our errors
-
-# Visibility
-- We should think carefully about the visibility of all the code we write. Overuse of `pub` makes the library API enormous
-and brittle, not to mention slows compiling/linking.
-- If code is strictly heirachical, we can avoid making anything `pub` other than top-level crate exports. If not, we can use
-e.g `pub(crate)`
-
-# When embarking on a task
-- Read ALL relevant information BEFORE starting to code. This includes the planning stage as well as implementation itself.
-- Do not 'wait until i need to' to read existing code, do it proactively
-- If you are at all unsure about the interface you're using, search for documentation, online if neccesary.
-- If the interface is not behaving as you expect, read the documentation and fully understand whats different to what you expected, don't just bash away
-
-# TODOs, Refactoring
-- If during the process of implementing or planning some task, you see some beneficial refactoring that could be done, but is unrelated to ask in hand:
- - write a paragraph item to docs/REFACTOR_TODOS.md
- - this file should be treated as append-only- do not e.g update tasks in-progress here, add completed tasks etc.
- - dont start working on this refactor unless you are explicitly told to.
+# Contributing
+
+Prepare the sibling Hellas checkout at the revision in `.hellas-revision` as
+described in the README. Enter the pinned environment with `nix develop`, then
+run `make check` before submitting changes. The flake routes Rust build output
+to `/tmp/hellas-gate-target` unless `CARGO_TARGET_DIR` is set, and supplies the
+frontend tools directly; do not run `npm install` or create caches in this
+checkout. Commit regenerated `ui/src/generated` definitions when Rust DTOs
+change; CI rejects generated binding drift.
+
+Gate should stay a thin desktop host. Protocol types, verification, transports,
+and reusable client/provider/gateway behavior belong in the sibling `hellas`
+workspace. Platform app integration, lifecycle policy, local persistence, and
+the Tauri UI belong here.
+
+Do not add an internal HTTP control plane, a companion daemon, a second protocol
+implementation, or a package-publication step. Keep Tauri invocations in
+`ui/src/api.ts`, and keep the corresponding DTOs derived from Rust.
diff --git a/Cargo.lock b/Cargo.lock
index e5ccf799..4a66389c 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -4,14 +4,15 @@ version = 4
[[package]]
name = "acto"
-version = "0.7.4"
+version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a026259da4f1a13b4af60cda453c392de64c58c12d239c560923e0382f42f2b9"
+checksum = "598381761ee991bf2f1455f700380e2191fb370dc9df1ee764f348b7f089d8b6"
dependencies = [
"parking_lot",
"pin-project-lite",
"rustc_version",
- "smol_str",
+ "smol_str 0.1.24",
+ "sync_wrapper",
"tokio",
"tracing",
]
@@ -24,13 +25,47 @@ checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa"
[[package]]
name = "aead"
-version = "0.6.0-rc.2"
+version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ac8202ab55fcbf46ca829833f347a82a2a4ce0596f0304ac322c2d100030cd56"
+checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0"
dependencies = [
- "bytes",
- "crypto-common 0.2.0-rc.4",
- "inout",
+ "crypto-common 0.1.6",
+ "generic-array",
+]
+
+[[package]]
+name = "aead"
+version = "0.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1973cfbc1a2daf9cf550e74e1f088c28e7f7d8c1e1418fb6c9dc5184b7e84c99"
+dependencies = [
+ "crypto-common 0.2.2",
+ "inout 0.2.2",
+]
+
+[[package]]
+name = "aes"
+version = "0.8.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0"
+dependencies = [
+ "cfg-if",
+ "cipher 0.4.4",
+ "cpufeatures 0.2.17",
+]
+
+[[package]]
+name = "aes-gcm"
+version = "0.10.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "831010a0f742e1209b3bcea8fab6a8e149051ba6099432c8cb2cc117dec3ead1"
+dependencies = [
+ "aead 0.5.2",
+ "aes",
+ "cipher 0.4.4",
+ "ctr",
+ "ghash",
+ "subtle",
]
[[package]]
@@ -49,9 +84,9 @@ dependencies = [
[[package]]
name = "aho-corasick"
-version = "1.1.3"
+version = "1.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
+checksum = "c982642fa9e8606056828ee9a8505737230110bb1099153c79efe865c59d12ba"
dependencies = [
"memchr",
]
@@ -64,9 +99,9 @@ checksum = "cc7bb162ec39d46ab1ca8c77bf72e890535becd1751bb45f64c597edb4c8c6b3"
[[package]]
name = "alloc-stdlib"
-version = "0.2.2"
+version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "94fb8275041c72129eb51b7d0322c29b8387a0386127718b096429201a5d6ece"
+checksum = "0e76a019e91224d279006ff972f1e984179a6e9feb050adba6ce8274aef23195"
dependencies = [
"alloc-no-stdlib",
]
@@ -79,87 +114,13 @@ checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923"
[[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 = "anstream"
-version = "0.6.20"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3ae563653d1938f79b1ab1b5e668c87c76a9930414574a6583a7b7e11a8e6192"
-dependencies = [
- "anstyle",
- "anstyle-parse 0.2.7",
- "anstyle-query",
- "anstyle-wincon",
- "colorchoice",
- "is_terminal_polyfill",
- "utf8parse",
-]
-
-[[package]]
-name = "anstream"
-version = "1.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "824a212faf96e9acacdbd09febd34438f8f711fb84e09a8916013cd7815ca28d"
-dependencies = [
- "anstyle",
- "anstyle-parse 1.0.0",
- "anstyle-query",
- "anstyle-wincon",
- "colorchoice",
- "is_terminal_polyfill",
- "utf8parse",
-]
-
-[[package]]
-name = "anstyle"
-version = "1.0.14"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "940b3a0ca603d1eade50a4846a2afffd5ef57a9feac2c0e2ec2e14f9ead76000"
-
-[[package]]
-name = "anstyle-parse"
-version = "0.2.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2"
-dependencies = [
- "utf8parse",
-]
-
-[[package]]
-name = "anstyle-parse"
-version = "1.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "52ce7f38b242319f7cabaa6813055467063ecdc9d355bbb4ce0c68908cd8130e"
-dependencies = [
- "utf8parse",
-]
-
-[[package]]
-name = "anstyle-query"
-version = "1.1.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9e231f6134f61b71076a3eab506c379d4f36122f2af15a9ff04415ea4c3339e2"
-dependencies = [
- "windows-sys 0.60.2",
-]
-
-[[package]]
-name = "anstyle-wincon"
-version = "3.0.10"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3e0633414522a32ffaac8ac6cc8f748e090c5717661fddeea04219e2344f5f2a"
-dependencies = [
- "anstyle",
- "once_cell_polyfill",
- "windows-sys 0.60.2",
-]
-
[[package]]
name = "anyhow"
version = "1.0.104"
@@ -167,238 +128,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "330a5ed07fa54e4702c9d6c4174f74427fc0ef6e214bbd677ae50a5099946470"
[[package]]
-name = "arraydeque"
-version = "0.5.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7d902e3d592a523def97af8f317b08ce16b7ab854c1985a0c671e6f15cebc236"
-
-[[package]]
-name = "arrayref"
-version = "0.3.9"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb"
-
-[[package]]
-name = "arrayvec"
-version = "0.7.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50"
-
-[[package]]
-name = "asn1-rs"
-version = "0.6.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5493c3bedbacf7fd7382c6346bbd66687d12bbaad3a89a2d2c303ee6cf20b048"
-dependencies = [
- "asn1-rs-derive 0.5.1",
- "asn1-rs-impl",
- "displaydoc",
- "nom",
- "num-traits",
- "rusticata-macros",
- "thiserror 1.0.69",
- "time",
-]
-
-[[package]]
-name = "asn1-rs"
-version = "0.7.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "56624a96882bb8c26d61312ae18cb45868e5a9992ea73c58e45c3101e56a1e60"
-dependencies = [
- "asn1-rs-derive 0.6.0",
- "asn1-rs-impl",
- "displaydoc",
- "nom",
- "num-traits",
- "rusticata-macros",
- "thiserror 2.0.20",
- "time",
-]
-
-[[package]]
-name = "asn1-rs-derive"
-version = "0.5.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "965c2d33e53cb6b267e148a4cb0760bc01f4904c1cd4bb4002a085bb016d1490"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn 2.0.106",
- "synstructure",
-]
-
-[[package]]
-name = "asn1-rs-derive"
-version = "0.6.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3109e49b1e4909e9db6515a30c633684d68cdeaa252f215214cb4fa1a5bfee2c"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn 2.0.106",
- "synstructure",
-]
-
-[[package]]
-name = "asn1-rs-impl"
-version = "0.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7b18050c2cd6fe86c3a76584ef5e0baf286d038cda203eb6223df2cc413565f7"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn 2.0.106",
-]
-
-[[package]]
-name = "assert-json-diff"
-version = "2.0.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "47e4f2b81832e72834d7518d8487a0396a28cc408186a2e8854c0f98011faf12"
-dependencies = [
- "serde",
- "serde_json",
-]
-
-[[package]]
-name = "async-broadcast"
-version = "0.7.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "435a87a52755b8f27fcf321ac4f04b2802e337c8c4872923137471ec39c37532"
-dependencies = [
- "event-listener",
- "event-listener-strategy",
- "futures-core",
- "pin-project-lite",
-]
-
-[[package]]
-name = "async-channel"
-version = "2.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "924ed96dd52d1b75e9c1a3e6275715fd320f5f9439fb5a4a11fa51f4221158d2"
-dependencies = [
- "concurrent-queue",
- "event-listener-strategy",
- "futures-core",
- "pin-project-lite",
-]
-
-[[package]]
-name = "async-compat"
-version = "0.2.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a1ba85bc55464dcbf728b56d97e119d673f4cf9062be330a9a26f3acf504a590"
-dependencies = [
- "futures-core",
- "futures-io",
- "once_cell",
- "pin-project-lite",
- "tokio",
-]
-
-[[package]]
-name = "async-compression"
-version = "0.4.30"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "977eb15ea9efd848bb8a4a1a2500347ed7f0bf794edf0dc3ddcf439f43d36b23"
-dependencies = [
- "compression-codecs",
- "compression-core",
- "futures-core",
- "pin-project-lite",
- "tokio",
-]
-
-[[package]]
-name = "async-executor"
-version = "1.13.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "497c00e0fd83a72a79a39fcbd8e3e2f055d6f6c7e025f3b3d91f4f8e76527fb8"
-dependencies = [
- "async-task",
- "concurrent-queue",
- "fastrand",
- "futures-lite",
- "pin-project-lite",
- "slab",
-]
-
-[[package]]
-name = "async-io"
-version = "2.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "19634d6336019ef220f09fd31168ce5c184b295cbf80345437cc36094ef223ca"
-dependencies = [
- "async-lock",
- "cfg-if",
- "concurrent-queue",
- "futures-io",
- "futures-lite",
- "parking",
- "polling",
- "rustix",
- "slab",
- "windows-sys 0.60.2",
-]
-
-[[package]]
-name = "async-lock"
-version = "3.4.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5fd03604047cee9b6ce9de9f70c6cd540a0520c813cbd49bae61f33ab80ed1dc"
-dependencies = [
- "event-listener",
- "event-listener-strategy",
- "pin-project-lite",
-]
-
-[[package]]
-name = "async-process"
-version = "2.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "65daa13722ad51e6ab1a1b9c01299142bc75135b337923cfa10e79bbbd669f00"
-dependencies = [
- "async-channel",
- "async-io",
- "async-lock",
- "async-signal",
- "async-task",
- "blocking",
- "cfg-if",
- "event-listener",
- "futures-lite",
- "rustix",
-]
-
-[[package]]
-name = "async-recursion"
-version = "1.1.1"
+name = "arc-swap"
+version = "1.9.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11"
+checksum = "c049c0be4daef0b145cb3555416b3b8ef5b7888a38aea1a3a155801fe7b0810b"
dependencies = [
- "proc-macro2",
- "quote",
- "syn 2.0.106",
+ "rustversion",
]
[[package]]
-name = "async-signal"
-version = "0.2.12"
+name = "arrayvec"
+version = "0.7.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f567af260ef69e1d52c2b560ce0ea230763e6fbb9214a85d768760a920e3e3c1"
+checksum = "d3fb67a6e08acf24fdeccbac2cb6ac4305825bd1f117462e0e6f2f193345ad56"
dependencies = [
- "async-io",
- "async-lock",
- "atomic-waker",
- "cfg-if",
- "futures-core",
- "futures-io",
- "rustix",
- "signal-hook-registry",
- "slab",
- "windows-sys 0.60.2",
+ "zeroize",
]
[[package]]
@@ -420,15 +164,9 @@ checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.106",
+ "syn 2.0.119",
]
-[[package]]
-name = "async-task"
-version = "4.7.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de"
-
[[package]]
name = "async-trait"
version = "0.1.92"
@@ -437,7 +175,7 @@ checksum = "82f6aeea286b8eb4dd3431a1be1b59d290ace00f5bfd8e2a159bc2a05e2c1667"
dependencies = [
"proc-macro2",
"quote",
- "syn 3.0.2",
+ "syn 3.0.5",
]
[[package]]
@@ -474,24 +212,6 @@ dependencies = [
"system-deps",
]
-[[package]]
-name = "atoi"
-version = "2.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f28d99ec8bfea296261ca1af174f24225171fea9664ba9003cbebee704810528"
-dependencies = [
- "num-traits",
-]
-
-[[package]]
-name = "atomic-polyfill"
-version = "1.0.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8cf2bce30dfe09ef0bfaef228b9d414faaf7e563035494d7fe092dba54b300f4"
-dependencies = [
- "critical-section",
-]
-
[[package]]
name = "atomic-waker"
version = "1.1.2"
@@ -505,16 +225,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "16e2cdb6d5ed835199484bb92bb8b3edd526effe995c61732580439c1a67e2e9"
dependencies = [
"base64 0.22.1",
- "http 1.5.0",
+ "http",
"log",
"url",
]
[[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 = "aws-lc-rs"
@@ -523,6 +243,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b281d307588d634de920874890732659e2e7672f72b5e10e81badc1a8a83621e"
dependencies = [
"aws-lc-sys",
+ "untrusted 0.7.1",
"zeroize",
]
@@ -546,17 +267,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "31b698c5f9a010f6573133b09e0de5408834d0c82f8d7475a89fc1867a71cd90"
dependencies = [
"axum-core",
- "axum-macros",
"bytes",
"form_urlencoded",
"futures-util",
- "http 1.5.0",
+ "http",
"http-body",
"http-body-util",
"hyper",
"hyper-util",
"itoa",
- "matchit 0.8.4",
+ "matchit",
"memchr",
"mime",
"percent-encoding",
@@ -570,17 +290,18 @@ dependencies = [
"tower",
"tower-layer",
"tower-service",
+ "tracing",
]
[[package]]
name = "axum-core"
-version = "0.5.5"
+version = "0.5.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "59446ce19cd142f8833f856eb31f3eb097812d1479ab224f54d72428ca21ea22"
+checksum = "08c78f31d7b1291f7ee735c1c6780ccde7785daae9a9206026862dab7d8792d1"
dependencies = [
"bytes",
"futures-core",
- "http 1.5.0",
+ "http",
"http-body",
"http-body-util",
"mime",
@@ -588,24 +309,14 @@ dependencies = [
"sync_wrapper",
"tower-layer",
"tower-service",
-]
-
-[[package]]
-name = "axum-macros"
-version = "0.5.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7aa268c23bfbbd2c4363b9cd302a4f504fb2a9dfe7e3451d66f35dd392e20aca"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn 2.0.106",
+ "tracing",
]
[[package]]
name = "backon"
-version = "1.5.2"
+version = "1.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "592277618714fbcecda9a02ba7a8781f319d26532a88553bbacc77ba5d2b3a8d"
+checksum = "cffb0e931875b666fc4fcb20fee52e9bbd1ef836fd9e9e04ec21555f9f85f7ef"
dependencies = [
"fastrand",
"gloo-timers",
@@ -613,16 +324,38 @@ dependencies = [
]
[[package]]
-name = "base16ct"
-version = "0.3.0"
+name = "base-x"
+version = "0.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d8b59d472eab27ade8d770dcb11da7201c11234bef9f82ce7aa517be028d462b"
+checksum = "4cbbc9d0964165b47557570cce6c952866c2678457aca742aafc9fb771d30270"
[[package]]
-name = "base32"
-version = "0.5.1"
+name = "base16ct"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf"
+
+[[package]]
+name = "base16ct"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fd307490d624467aa6f74b0eabb77633d1f758a7b25f12bceb0b22e08d9726f6"
+
+[[package]]
+name = "base256emoji"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b5e9430d9a245a77c92176e649af6e275f20839a48389859d1661e9a128d077c"
+dependencies = [
+ "const-str",
+ "match-lookup",
+]
+
+[[package]]
+name = "base45"
+version = "3.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "022dfe9eb35f19ebbcb51e0b40a5ab759f46ad60cadf7297e0bd085afb50e076"
+checksum = "240e56f4d3c453c36faacb695c535a4d5f8c7d23dac175014f32eb0a71012a03"
[[package]]
name = "base64"
@@ -650,29 +383,15 @@ checksum = "ac07cdecf99051d9a5238b80f35af32cdeba5b336e55d957b318b50137e18da5"
[[package]]
name = "base64ct"
-version = "1.8.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "55248b47b0caf0546f7988906588779981c43bb1bc9d0c44087278f80cdb44ba"
-
-[[package]]
-name = "base64urlsafedata"
-version = "0.5.5"
+version = "1.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b08e33815c87d8cadcddb1e74ac307368a3751fbe40c961538afa21a1899f21c"
-dependencies = [
- "base64 0.21.7",
- "pastey",
- "serde",
-]
+checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06"
[[package]]
-name = "bincode"
-version = "1.3.3"
+name = "beef"
+version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad"
-dependencies = [
- "serde",
-]
+checksum = "3a8241f3ebb85c056b509d4327ad0358fbbba6ffb340bf388f26350aeda225b1"
[[package]]
name = "bit-set"
@@ -680,7 +399,7 @@ version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08807e080ed7f9d5433fa9b275196cfc35414f66a0c79d864dc51a0d825231a3"
dependencies = [
- "bit-vec 0.8.0",
+ "bit-vec",
]
[[package]]
@@ -689,15 +408,6 @@ version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7"
-[[package]]
-name = "bit-vec"
-version = "0.9.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b71798fca2c1fe1086445a7258a4bc81e6e49dcd24c8d0dd9a1e57395b603f51"
-dependencies = [
- "serde",
-]
-
[[package]]
name = "bitflags"
version = "1.3.2"
@@ -706,24 +416,25 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "bitflags"
-version = "2.9.4"
+version = "2.13.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2261d10cca569e4643e526d8dc2e62e433cc8aba21ab764233731f8d369bf394"
+checksum = "3ded4057c258ba199e2d26386d3af3780957ecaee6c4ef4041c6b4b8b97c0b06"
dependencies = [
- "serde",
+ "serde_core",
]
[[package]]
name = "blake3"
-version = "1.8.2"
+version = "1.8.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3888aaa89e4b2a40fca9848e400f6a658a5a3978de7be858e209cafa8be9a4a0"
+checksum = "6d9e454fc11f76977dc803893aff6304ed33d6a26efae8696573bea74baa27ae"
dependencies = [
- "arrayref",
"arrayvec",
"cc",
"cfg-if",
"constant_time_eq",
+ "cpufeatures 0.3.1",
+ "zeroize",
]
[[package]]
@@ -737,73 +448,49 @@ dependencies = [
[[package]]
name = "block-buffer"
-version = "0.11.0-rc.5"
+version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e9ef36a6fcdb072aa548f3da057640ec10859eb4e91ddf526ee648d50c76a949"
+checksum = "d2f6c7dbe95a6ed67ad9f18e57daf93a2f034c524b99fd2b76d18fdfeb6660aa"
dependencies = [
"hybrid-array",
- "zeroize",
-]
-
-[[package]]
-name = "block2"
-version = "0.5.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2c132eebf10f5cad5289222520a4a058514204aed6d791f1cf4fe8088b82d15f"
-dependencies = [
- "objc2 0.5.2",
]
[[package]]
name = "block2"
-version = "0.6.1"
+version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "340d2f0bdb2a43c1d3cd40513185b2bd7def0aa1052f956455114bc98f82dcf2"
+checksum = "cdeb9d870516001442e364c5220d3574d2da8dc765554b4a617230d33fa58ef5"
dependencies = [
- "objc2 0.6.4",
+ "objc2",
]
[[package]]
-name = "blocking"
-version = "1.6.2"
+name = "blst"
+version = "0.3.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e83f8d02be6967315521be875afa792a316e28d57b5a2d401897e2a7921b7f21"
+checksum = "c20659f9bbee16cbbd2f7393e40ab6309f5a98f76a2eb57a995ec508b72387fe"
dependencies = [
- "async-channel",
- "async-task",
- "futures-io",
- "futures-lite",
- "piper",
+ "cc",
+ "glob",
+ "threadpool",
+ "zeroize",
]
[[package]]
name = "borsh"
-version = "1.5.7"
+version = "1.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ad8646f98db542e39fc66e68a20b2144f6a732636df7c2354e74645faaa433ce"
+checksum = "553c5d846a6ba5150c65e3b1b8ec073bcf1abc20f9b7220de384a4443ea4e20a"
dependencies = [
- "borsh-derive",
+ "bytes",
"cfg_aliases",
]
-[[package]]
-name = "borsh-derive"
-version = "1.5.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fdd1d3c0c2f5833f22386f252fe8ed005c7f59fdcddeef025c01b4c3b9fd9ac3"
-dependencies = [
- "once_cell",
- "proc-macro-crate 3.3.0",
- "proc-macro2",
- "quote",
- "syn 2.0.106",
-]
-
[[package]]
name = "brotli"
-version = "8.0.2"
+version = "8.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4bd8b9603c7aa97359dbd97ecf258968c95f3adddd6db2f7e7a5bef101c84560"
+checksum = "5cc91aac060a7a1e25823bdccbfb6af1875b88f17c6daac97894eed8207166b3"
dependencies = [
"alloc-no-stdlib",
"alloc-stdlib",
@@ -812,39 +499,34 @@ dependencies = [
[[package]]
name = "brotli-decompressor"
-version = "5.0.0"
+version = "5.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "874bb8112abecc98cbd6d81ea4fa7e94fb9449648c93cc89aa40c81c24d7de03"
+checksum = "3a32acac15fe1967bc3986b2a6347dffc965602354ea6f450ad07e8bfd253583"
dependencies = [
"alloc-no-stdlib",
"alloc-stdlib",
]
[[package]]
-name = "bumpalo"
-version = "3.19.0"
+name = "bs58"
+version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43"
+checksum = "bf88ba1141d185c399bee5288d850d63b8369520c1eafc32a0430b5b6c287bf4"
+dependencies = [
+ "tinyvec",
+]
[[package]]
-name = "bytemuck"
-version = "1.23.2"
+name = "bumpalo"
+version = "3.20.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3995eaeebcdf32f91f980d360f78732ddc061097ab4e39991ae7a6ace9194677"
-dependencies = [
- "bytemuck_derive",
-]
+checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649"
[[package]]
-name = "bytemuck_derive"
-version = "1.10.1"
+name = "bytemuck"
+version = "1.25.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4f154e572231cb6ba2bd1176980827e3d5dc04cc183a75dea38109fbdd672d29"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn 2.0.106",
-]
+checksum = "95832e849adfb21180ccb6826a99da14e5d266ae5c2e668e1602cf234f153797"
[[package]]
name = "byteorder"
@@ -867,7 +549,7 @@ version = "0.18.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ca26ef0159422fb77631dc9d17b102f253b876fe1586b03b803e63a309b4ee2"
dependencies = [
- "bitflags 2.9.4",
+ "bitflags 2.13.2",
"cairo-sys-rs",
"glib",
"libc",
@@ -888,11 +570,11 @@ dependencies = [
[[package]]
name = "camino"
-version = "1.1.12"
+version = "1.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dd0b03af37dad7a14518b7691d81acb0f8222604ad3d1b02f6b4bed5188c0cd5"
+checksum = "bbbad30e4b4c14a39e3cc8aed085a12a327257c316619c93581e017bc52be591"
dependencies = [
- "serde",
+ "serde_core",
]
[[package]]
@@ -938,49 +620,19 @@ dependencies = [
]
[[package]]
-name = "catgrad"
-version = "0.1.1"
-source = "git+https://github.com/hellas-ai/catgrad#746f7e586528ecc5cc0cd8ecaba97d6611b9ddb5"
-dependencies = [
- "gemm",
- "half",
- "log",
- "memmap2",
- "num-traits",
- "num_cpus",
- "open-hypergraphs",
- "rayon",
- "serde",
- "serde_json",
- "test-log",
-]
-
-[[package]]
-name = "catgrad-llm"
-version = "0.1.1"
-source = "git+https://github.com/hellas-ai/catgrad#746f7e586528ecc5cc0cd8ecaba97d6611b9ddb5"
+name = "cbor4ii"
+version = "0.2.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b544cf8c89359205f4f990d0e6f3828db42df85b5dac95d09157a250eb0749c4"
dependencies = [
- "catgrad",
- "half",
- "hf-hub",
- "log",
- "memmap2",
- "minijinja",
- "minijinja-contrib",
- "open-hypergraphs",
- "rayon",
- "safetensors",
"serde",
- "serde_json",
- "thiserror 2.0.20",
- "tokenizers",
]
[[package]]
name = "cc"
-version = "1.2.36"
+version = "1.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5252b3d2648e5eedbc1a6f501e3c795e07025c1e93bbf8bbdd6eef7f447a6d54"
+checksum = "a3eb0f42d6c360dc3f8a821f6bf2fdea7f72bfd36b3076eb0e6d1e9e0752fff4"
dependencies = [
"find-msvc-tools",
"jobserver",
@@ -1023,20 +675,32 @@ checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
[[package]]
name = "cfg_aliases"
-version = "0.2.1"
+version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724"
+checksum = "f079e83a288787bcd14a6aea84cee5c87a67c5a3e660c30f557a3d24761b3527"
[[package]]
name = "chacha20"
-version = "0.10.0-rc.2"
+version = "0.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9bd162f2b8af3e0639d83f28a637e4e55657b7a74508dba5a9bf4da523d5c9e9"
+checksum = "65c35e4b699c7e15ccbe7ee35c005e4fc0a278d22238a2857e6ce2dadeda1b06"
dependencies = [
"cfg-if",
- "cipher",
- "cpufeatures",
- "zeroize",
+ "cipher 0.5.2",
+ "cpufeatures 0.3.1",
+ "rand_core 0.10.1",
+]
+
+[[package]]
+name = "chacha20poly1305"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9b89e1c441e926b9c82a8d023f6e1b7ae0adcfaa7d621814e4d60789bac751cb"
+dependencies = [
+ "aead 0.6.1",
+ "chacha20",
+ "cipher 0.5.2",
+ "poly1305",
]
[[package]]
@@ -1046,93 +710,87 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1aa79e62e7697b8e29b513a68abacf485adcd1fe8284a4316c5ae868e6633327"
dependencies = [
"iana-time-zone",
- "js-sys",
"num-traits",
"serde",
- "wasm-bindgen",
"windows-link 0.2.1",
]
[[package]]
-name = "cipher"
-version = "0.5.0-rc.1"
+name = "ciborium"
+version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1e12a13eb01ded5d32ee9658d94f553a19e804204f2dc811df69ab4d9e0cb8c7"
+checksum = "42e69ffd6f0917f5c029256a24d0161db17cea3997d185db0d35926308770f0e"
dependencies = [
- "block-buffer 0.11.0-rc.5",
- "crypto-common 0.2.0-rc.4",
- "inout",
- "zeroize",
+ "ciborium-io",
+ "ciborium-ll",
+ "serde",
]
[[package]]
-name = "clap"
-version = "4.6.6"
+name = "ciborium-io"
+version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "473c7e07f409a8d772161724aa8db6a765a2532a70f9667eeb7b49d3d02fbdca"
-dependencies = [
- "clap_builder",
- "clap_derive",
-]
+checksum = "05afea1e0a06c9be33d539b876f1ce3692f4afea2cb41f740e7743225ed1c757"
[[package]]
-name = "clap_builder"
-version = "4.6.6"
+name = "ciborium-ll"
+version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7b48fea5a88e9ae728a2dcbedbfc0e730f7d60da42e1cb049a83c9fb8b789889"
+checksum = "57663b653d948a338bfb3eeba9bb2fd5fcfaecb9e199e87e1eda4d9e8b240fd9"
dependencies = [
- "anstream 1.0.0",
- "anstyle",
- "clap_lex",
- "strsim",
+ "ciborium-io",
+ "half",
]
[[package]]
-name = "clap_derive"
-version = "4.6.4"
+name = "cid"
+version = "0.11.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d012d2b9d65aca7f18f4d9878a045bc17899bba951561ba5ec3c2ba1eed9a061"
+checksum = "21a304f95f84d169a6f31c4d0a30d784643aaa0bbc9c1e449a2c23e963ec4971"
dependencies = [
- "heck 0.5.0",
- "proc-macro2",
- "quote",
- "syn 3.0.2",
+ "multibase",
+ "multihash",
+ "serde",
+ "serde_bytes",
+ "unsigned-varint",
]
[[package]]
-name = "clap_lex"
-version = "1.0.0"
+name = "cipher"
+version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3a822ea5bc7590f9d40f1ba12c0dc3c2760f3482c6984db1573ad11031420831"
+checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad"
+dependencies = [
+ "crypto-common 0.1.6",
+ "inout 0.1.4",
+]
[[package]]
-name = "cloudflare"
-version = "0.14.0"
+name = "cipher"
+version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1678b3295890df5895480a7c080430e73df2b7101f1763f62a3b32dd532f1d37"
+checksum = "e8cf2a2c93cd704877c0858356ed03480ff301ee950b43f1cbe4573b088bfa6c"
dependencies = [
- "chrono",
- "http 1.5.0",
- "reqwest 0.12.28",
- "serde",
- "serde_json",
- "serde_urlencoded",
- "serde_with",
- "thiserror 2.0.20",
- "url",
- "urlencoding",
- "uuid",
+ "block-buffer 0.12.1",
+ "crypto-common 0.2.2",
+ "inout 0.2.2",
]
[[package]]
name = "cmake"
-version = "0.1.54"
+version = "0.1.58"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e7caa3f9de89ddbe2c607f4101924c5abec803763ae9534e4f4d7d8f84aa81f0"
+checksum = "c0f78a02292a74a88ac736019ab962ece0bc380e3f977bf72e376c5d78ff0678"
dependencies = [
"cc",
]
+[[package]]
+name = "cmov"
+version = "0.5.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0c9ea0ac24bc397ab3c98583a3c9ba74fa56b09a4449bbe172b9b1ddb016027a"
+
[[package]]
name = "cobs"
version = "0.3.0"
@@ -1142,161 +800,231 @@ dependencies = [
"thiserror 2.0.20",
]
-[[package]]
-name = "colorchoice"
-version = "1.0.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75"
-
[[package]]
name = "combine"
-version = "4.6.7"
+version = "4.6.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd"
+checksum = "cfc320937d09e6de266b31b9afb480f197d7a861be86be7cb2ea7e5d1bfffc5e"
dependencies = [
"bytes",
"memchr",
]
[[package]]
-name = "compact_str"
-version = "0.9.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3fdb1325a1cece981e8a296ab8f0f9b63ae357bd0784a9faaf548cc7b480707a"
+name = "commonware-codec"
+version = "2026.7.0"
+source = "git+https://github.com/commonwarexyz/monorepo?rev=4c3ebe4274d908557d91b637240e8b93609fb32f#4c3ebe4274d908557d91b637240e8b93609fb32f"
dependencies = [
- "castaway",
+ "bytes",
"cfg-if",
- "itoa",
- "rustversion",
- "ryu",
- "serde",
- "static_assertions",
+ "commonware-codec-macros",
+ "commonware-macros",
+ "paste",
+ "rand_chacha 0.10.0",
+ "thiserror 2.0.20",
]
[[package]]
-name = "compression-codecs"
-version = "0.4.30"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "485abf41ac0c8047c07c87c72c8fb3eb5197f6e9d7ded615dfd1a00ae00a0f64"
+name = "commonware-codec-macros"
+version = "2026.7.0"
+source = "git+https://github.com/commonwarexyz/monorepo?rev=4c3ebe4274d908557d91b637240e8b93609fb32f#4c3ebe4274d908557d91b637240e8b93609fb32f"
dependencies = [
- "brotli",
- "compression-core",
- "flate2",
- "memchr",
- "zstd",
- "zstd-safe",
+ "proc-macro-crate 3.5.0",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.119",
]
[[package]]
-name = "compression-core"
-version = "0.4.29"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e47641d3deaf41fb1538ac1f54735925e275eaf3bf4d55c81b137fba797e5cbb"
+name = "commonware-cryptography"
+version = "2026.7.0"
+source = "git+https://github.com/commonwarexyz/monorepo?rev=4c3ebe4274d908557d91b637240e8b93609fb32f#4c3ebe4274d908557d91b637240e8b93609fb32f"
+dependencies = [
+ "ahash",
+ "anyhow",
+ "aws-lc-rs",
+ "blake3",
+ "blst",
+ "bytes",
+ "cfg-if",
+ "chacha20poly1305",
+ "commonware-codec",
+ "commonware-formatting",
+ "commonware-macros",
+ "commonware-math",
+ "commonware-parallel",
+ "commonware-utils",
+ "cpufeatures 0.3.1",
+ "crc-fast",
+ "ctutils",
+ "curve25519-dalek",
+ "ecdsa 0.17.0",
+ "fixedbitset",
+ "getrandom 0.2.17",
+ "getrandom 0.4.3",
+ "hashbrown 0.17.1",
+ "num-rational",
+ "num-traits",
+ "once_cell",
+ "p256",
+ "rand 0.10.2",
+ "rand_chacha 0.10.0",
+ "rand_core 0.10.1",
+ "sha2 0.11.0",
+ "thiserror 2.0.20",
+ "x25519-dalek",
+ "zeroize",
+]
[[package]]
-name = "concurrent-queue"
-version = "2.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973"
+name = "commonware-formatting"
+version = "2026.7.0"
+source = "git+https://github.com/commonwarexyz/monorepo?rev=4c3ebe4274d908557d91b637240e8b93609fb32f#4c3ebe4274d908557d91b637240e8b93609fb32f"
dependencies = [
- "crossbeam-utils",
+ "commonware-macros",
+ "const-hex",
]
[[package]]
-name = "config"
-version = "0.15.25"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b85f248a4de22d204ceabc6299d89d2c70fbd7f09fea53c06c852369652d8139"
+name = "commonware-macros"
+version = "2026.7.0"
+source = "git+https://github.com/commonwarexyz/monorepo?rev=4c3ebe4274d908557d91b637240e8b93609fb32f#4c3ebe4274d908557d91b637240e8b93609fb32f"
dependencies = [
- "async-trait",
- "convert_case",
- "json5",
- "pathdiff",
- "ron",
- "rust-ini",
- "serde-untagged",
- "serde_core",
- "serde_json",
- "toml 1.1.5+spec-1.1.0",
- "winnow 1.0.4",
- "yaml-rust2",
+ "commonware-macros-impl",
+ "tokio",
]
[[package]]
-name = "console"
-version = "0.15.11"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "054ccb5b10f9f2cbf51eb355ca1d05c2d279ce1804688d0db74b4733a5aeafd8"
+name = "commonware-macros-impl"
+version = "2026.7.0"
+source = "git+https://github.com/commonwarexyz/monorepo?rev=4c3ebe4274d908557d91b637240e8b93609fb32f#4c3ebe4274d908557d91b637240e8b93609fb32f"
dependencies = [
- "encode_unicode",
- "libc",
- "once_cell",
- "unicode-width",
- "windows-sys 0.59.0",
+ "proc-macro-crate 3.5.0",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.119",
+ "toml 1.1.6+spec-1.1.0",
]
[[package]]
-name = "console_error_panic_hook"
-version = "0.1.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc"
+name = "commonware-math"
+version = "2026.7.0"
+source = "git+https://github.com/commonwarexyz/monorepo?rev=4c3ebe4274d908557d91b637240e8b93609fb32f#4c3ebe4274d908557d91b637240e8b93609fb32f"
dependencies = [
- "cfg-if",
- "wasm-bindgen",
+ "bytes",
+ "commonware-codec",
+ "commonware-macros",
+ "commonware-parallel",
+ "commonware-utils",
+ "rand_core 0.10.1",
]
[[package]]
-name = "const-oid"
-version = "0.9.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8"
+name = "commonware-parallel"
+version = "2026.7.0"
+source = "git+https://github.com/commonwarexyz/monorepo?rev=4c3ebe4274d908557d91b637240e8b93609fb32f#4c3ebe4274d908557d91b637240e8b93609fb32f"
+dependencies = [
+ "cfg-if",
+ "commonware-macros",
+ "dashmap",
+ "futures",
+ "rayon",
+]
[[package]]
-name = "const-oid"
-version = "0.10.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0dabb6555f92fb9ee4140454eb5dcd14c7960e1225c6d1a6cc361f032947713e"
+name = "commonware-utils"
+version = "2026.7.0"
+source = "git+https://github.com/commonwarexyz/monorepo?rev=4c3ebe4274d908557d91b637240e8b93609fb32f#4c3ebe4274d908557d91b637240e8b93609fb32f"
+dependencies = [
+ "ahash",
+ "bytes",
+ "cfg-if",
+ "commonware-codec",
+ "commonware-formatting",
+ "commonware-macros",
+ "futures",
+ "getrandom 0.2.17",
+ "getrandom 0.3.4",
+ "getrandom 0.4.3",
+ "hashbrown 0.17.1",
+ "num-bigint",
+ "num-integer",
+ "num-rational",
+ "num-traits",
+ "parking_lot",
+ "pin-project",
+ "rand 0.10.2",
+ "thiserror 2.0.20",
+ "tokio",
+ "tracing",
+ "zeroize",
+]
[[package]]
-name = "const-random"
-version = "0.1.18"
+name = "compact_str"
+version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "87e00182fe74b066627d63b85fd550ac2998d4b0bd86bfed477a0ae4c7c71359"
+checksum = "9dfdd1c2274d9aa354115b09dc9a901d6c5576818cdf70d14cae2bdb47df00ab"
dependencies = [
- "const-random-macro",
+ "castaway",
+ "cfg-if",
+ "itoa",
+ "rustversion",
+ "ryu",
+ "serde",
+ "static_assertions",
]
[[package]]
-name = "const-random-macro"
-version = "0.1.16"
+name = "const-hex"
+version = "1.19.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f9d839f2a20b0aee515dc581a6172f2321f96cab76c1a38a4c584a194955390e"
+checksum = "188c2337969e01e04cca32b92011b72db2b43a8b7fc2ae60741db78f7873724e"
dependencies = [
- "getrandom 0.2.16",
- "once_cell",
- "tiny-keccak",
+ "cfg-if",
+ "cpufeatures 0.2.17",
+ "proptest",
+ "serde_core",
]
+[[package]]
+name = "const-oid"
+version = "0.9.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8"
+
+[[package]]
+name = "const-oid"
+version = "0.10.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a6ef517f0926dd24a1582492c791b6a4818a4d94e789a334894aa15b0d12f55c"
+
+[[package]]
+name = "const-str"
+version = "0.4.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2f421161cb492475f1661ddc9815a745a1c894592070661180fdec3d4872e9c3"
+
[[package]]
name = "constant_time_eq"
-version = "0.3.1"
+version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7c74b8349d32d297c9134b8c88677813a227df8f779daa29bfc29c183fe3dca6"
+checksum = "3d52eff69cd5e647efe296129160853a42795992097e8af39800e1060caeea9b"
[[package]]
name = "convert_case"
-version = "0.6.0"
+version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ec182b0ca2f35d8fc196cf3404988fd8b8c739a4d270ff118a398feb0cbec1ca"
+checksum = "633458d4ef8c78b72454de2d54fd6ab2e60f9e02be22f3c6104cdc8a4e0fceb9"
dependencies = [
"unicode-segmentation",
]
[[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",
@@ -1304,24 +1032,14 @@ dependencies = [
[[package]]
name = "cordyceps"
-version = "0.3.4"
+version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "688d7fbb8092b8de775ef2536f36c8c31f2bc4006ece2e8d8ad2d17d00ce0a2a"
+checksum = "5b9ab7e0ca1d179628fa0172b2b97203c7fa0cd81be2448bd446fb9559ca9261"
dependencies = [
"loom",
"tracing",
]
-[[package]]
-name = "core-foundation"
-version = "0.9.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f"
-dependencies = [
- "core-foundation-sys",
- "libc",
-]
-
[[package]]
name = "core-foundation"
version = "0.10.1"
@@ -1338,29 +1056,16 @@ version = "0.8.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
-[[package]]
-name = "core-graphics"
-version = "0.24.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fa95a34622365fa5bbf40b20b75dba8dfa8c94c734aea8ac9a5ca38af14316f1"
-dependencies = [
- "bitflags 2.9.4",
- "core-foundation 0.10.1",
- "core-graphics-types",
- "foreign-types 0.5.0",
- "libc",
-]
-
[[package]]
name = "core-graphics"
version = "0.25.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "064badf302c3194842cf2c5d61f56cc88e54a759313879cdf03abdd27d0c3b97"
dependencies = [
- "bitflags 2.9.4",
- "core-foundation 0.10.1",
+ "bitflags 2.13.2",
+ "core-foundation",
"core-graphics-types",
- "foreign-types 0.5.0",
+ "foreign-types",
"libc",
]
@@ -1370,11 +1075,17 @@ version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3d44a101f213f6c4cdc1853d4b78aef6db6bdfa3468798cc1d9912f4735013eb"
dependencies = [
- "bitflags 2.9.4",
- "core-foundation 0.10.1",
+ "bitflags 2.13.2",
+ "core-foundation",
"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"
@@ -1384,26 +1095,45 @@ 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 = "crc"
-version = "3.3.0"
+version = "3.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9710d3b3739c2e349eb44fe848ad0b7c8cb1e42bd87ee49371df2f7acaf3e675"
+checksum = "5eb8a2a1cd12ab0d987a5d5e825195d372001a4094a0376319d5a0ad71c1ba0d"
dependencies = [
"crc-catalog",
]
[[package]]
name = "crc-catalog"
-version = "2.4.0"
+version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5"
+checksum = "217698eaf96b4a3f0bc4f3662aaa55bdf913cd54d7204591faa790070c6d0853"
+
+[[package]]
+name = "crc-fast"
+version = "1.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e75b2483e97a5a7da73ac68a05b629f9c53cff58d8ed1c77866079e18b00dba5"
+dependencies = [
+ "digest 0.10.7",
+ "spin 0.10.1",
+]
[[package]]
name = "crc32fast"
-version = "1.5.0"
+version = "1.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511"
+checksum = "01a7799fd6b852db0e61728dde9a204c423b44d689dbd432522543614b490e78"
dependencies = [
"cfg-if",
]
@@ -1416,18 +1146,18 @@ 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-deque"
-version = "0.8.6"
+version = "0.8.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51"
+checksum = "622f3fc73690be383c7214310406f28a90e6edeadc3cea882f9d71e495b9711a"
dependencies = [
"crossbeam-epoch",
"crossbeam-utils",
@@ -1435,27 +1165,18 @@ dependencies = [
[[package]]
name = "crossbeam-epoch"
-version = "0.9.18"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e"
-dependencies = [
- "crossbeam-utils",
-]
-
-[[package]]
-name = "crossbeam-queue"
-version = "0.3.12"
+version = "0.9.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0f58bbc28f91df819d0aa2a2c00cd19754769c2fad90579b3592b1c9ba7a3115"
+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"
@@ -1464,55 +1185,52 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5"
[[package]]
-name = "crypto-common"
-version = "0.1.6"
+name = "crypto-bigint"
+version = "0.5.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
+checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76"
dependencies = [
"generic-array",
- "typenum",
+ "rand_core 0.6.4",
+ "subtle",
+ "zeroize",
]
[[package]]
-name = "crypto-common"
-version = "0.2.0-rc.4"
+name = "crypto-bigint"
+version = "0.7.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6a8235645834fbc6832939736ce2f2d08192652269e11010a6240f61b908a1c6"
+checksum = "1a52aa3fcda4e6302a9f48734f234d35d4721b96f8fe07d073f07ce9df4f0271"
dependencies = [
+ "cpubits",
+ "ctutils",
+ "getrandom 0.4.3",
"hybrid-array",
- "rand_core 0.9.3",
+ "num-traits",
+ "rand_core 0.10.1",
+ "subtle",
+ "zeroize",
]
[[package]]
-name = "crypto_box"
-version = "0.10.0-pre.0"
+name = "crypto-common"
+version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2bda4de3e070830cf3a27a394de135b6709aefcc54d1e16f2f029271254a6ed9"
+checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
dependencies = [
- "aead",
- "chacha20",
- "crypto_secretbox",
- "curve25519-dalek",
- "salsa20",
- "serdect",
- "subtle",
- "zeroize",
+ "generic-array",
+ "typenum",
]
[[package]]
-name = "crypto_secretbox"
-version = "0.2.0-pre.0"
+name = "crypto-common"
+version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "54532aae6546084a52cef855593daf9555945719eeeda9974150e0def854873e"
+checksum = "ce6e4c961d6cd6c9a86db418387425e8bdeaf05b3c8bc1411e6dca4c252f1453"
dependencies = [
- "aead",
- "chacha20",
- "cipher",
+ "getrandom 0.4.3",
"hybrid-array",
- "poly1305",
- "salsa20",
- "subtle",
- "zeroize",
+ "rand_core 0.10.1",
]
[[package]]
@@ -1535,7 +1253,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331"
dependencies = [
"quote",
- "syn 2.0.106",
+ "syn 2.0.119",
]
[[package]]
@@ -1554,18 +1272,37 @@ version = "0.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "52560adf09603e58c9a7ee1fe1dcb95a16927b17c127f0ac02d6e768a0e25bc1"
+[[package]]
+name = "ctr"
+version = "0.9.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835"
+dependencies = [
+ "cipher 0.4.4",
+]
+
+[[package]]
+name = "ctutils"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7d5515a3834141de9eafb9717ad39eea8247b5674e6066c404e8c4b365d2a29e"
+dependencies = [
+ "cmov",
+ "subtle",
+]
+
[[package]]
name = "curve25519-dalek"
-version = "5.0.0-pre.1"
+version = "5.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6f9200d1d13637f15a6acb71e758f64624048d85b31a5fdbfd8eca1e2687d0b7"
+checksum = "b5eed333089e2e1c1ac8c6c0398e5e2497b4c9926ca6d0365ed1e099afa5bc23"
dependencies = [
"cfg-if",
- "cpufeatures",
+ "cpufeatures 0.3.1",
"curve25519-dalek-derive",
- "digest 0.11.0-rc.3",
+ "digest 0.11.3",
"fiat-crypto",
- "rand_core 0.9.3",
+ "rand_core 0.10.1",
"rustc_version",
"serde",
"subtle",
@@ -1580,7 +1317,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.106",
+ "syn 2.0.119",
]
[[package]]
@@ -1595,12 +1332,12 @@ dependencies = [
[[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 0.21.3",
- "darling_macro 0.21.3",
+ "darling_core 0.24.1",
+ "darling_macro 0.24.1",
]
[[package]]
@@ -1614,21 +1351,20 @@ dependencies = [
"proc-macro2",
"quote",
"strsim",
- "syn 2.0.106",
+ "syn 2.0.119",
]
[[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.106",
+ "syn 3.0.5",
]
[[package]]
@@ -1639,25 +1375,25 @@ checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead"
dependencies = [
"darling_core 0.20.11",
"quote",
- "syn 2.0.106",
+ "syn 2.0.119",
]
[[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 0.21.3",
+ "darling_core 0.24.1",
"quote",
- "syn 2.0.106",
+ "syn 3.0.5",
]
[[package]]
name = "dary_heap"
-version = "0.3.7"
+version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "04d2cd9c18b9f454ed67da600630b021a8a80bf33f8c95896ab33aaf1c26b728"
+checksum = "8b1e3a325bc115f096c8b77bbf027a7c2592230e70be2d985be950d3d5e60ebe"
dependencies = [
"serde",
]
@@ -1678,113 +1414,113 @@ dependencies = [
[[package]]
name = "data-encoding"
-version = "2.9.0"
+version = "2.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2a2330da5de22e8a3cb63252ce2abb30116bf5265e89c0e01bc17015ce30a476"
+checksum = "4583a4551df46e2792f82ceeac45e850d2e2d5debba0b91f102385cda5b11f06"
[[package]]
-name = "dbus"
-version = "0.9.11"
+name = "data-encoding-macro"
+version = "0.1.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b942602992bb7acfd1f51c49811c58a610ef9181b6e66f3e519d79b540a3bf73"
+checksum = "c6a127ecbb3c4632e1525380e04c0c3fcf8dcb44d32a79ea290d8a36906edcd8"
dependencies = [
- "libc",
- "libdbus-sys",
- "windows-sys 0.61.0",
+ "data-encoding",
+ "data-encoding-macro-internal",
]
[[package]]
-name = "deadpool"
-version = "0.12.3"
+name = "data-encoding-macro-internal"
+version = "0.1.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0be2b1d1d6ec8d846f05e137292d0b89133caf95ef33695424c09568bdd39b1b"
+checksum = "c54e03a951783e8b327515db3f2a2fd0e3bed362a96b066f341ce66ed49b4ead"
dependencies = [
- "deadpool-runtime 0.1.4",
- "lazy_static",
- "num_cpus",
- "tokio",
+ "data-encoding",
+ "syn 3.0.5",
]
[[package]]
-name = "deadpool"
-version = "0.13.1"
+name = "dbus"
+version = "0.9.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3e98a7e119cd347f4201e1159b19831029e203e2d8b790547708e8157b4acf1e"
+checksum = "3ab69f03cc8c4340c9c8e315114e1658e6775a9b16a04357973aa21cec22b32e"
dependencies = [
- "deadpool-runtime 0.3.1",
- "tokio",
+ "libc",
+ "libdbus-sys",
+ "windows-sys 0.61.2",
]
[[package]]
-name = "deadpool-runtime"
-version = "0.1.4"
+name = "defmt"
+version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "092966b41edc516079bdf31ec78a2e0588d1d0c08f78b91d8307215928642b2b"
+checksum = "e2953bfe4f93bbd20cc71198842756f77d161884c99ebbabc41d80231ded88d1"
+dependencies = [
+ "bitflags 1.3.2",
+ "defmt-macros",
+]
[[package]]
-name = "deadpool-runtime"
-version = "0.3.1"
+name = "defmt-macros"
+version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2657f61fb1dd8bf37a8d51093cc7cee4e77125b22f7753f49b289f831bec2bae"
+checksum = "bad9c72e7ca2137e0dc3813245a0d282fd6daad32fd800af018306a9169b5fe8"
+dependencies = [
+ "defmt-parser",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.119",
+]
[[package]]
-name = "der"
-version = "0.7.10"
+name = "defmt-parser"
+version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb"
+checksum = "10d60334b3b2e7c9d91ef8150abfb6fa4c1c39ebbcf4a81c2e346aad939fee3e"
dependencies = [
- "const-oid 0.9.6",
- "pem-rfc7468 0.7.0",
- "zeroize",
+ "thiserror 2.0.20",
]
[[package]]
name = "der"
-version = "0.8.0-rc.9"
+version = "0.7.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e9d8dd2f26c86b27a2a8ea2767ec7f9df7a89516e4794e54ac01ee618dda3aa4"
+checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb"
dependencies = [
- "const-oid 0.10.1",
- "pem-rfc7468 1.0.0-rc.3",
+ "const-oid 0.9.6",
+ "der_derive",
+ "flagset",
"zeroize",
]
[[package]]
-name = "der-parser"
-version = "9.0.0"
+name = "der"
+version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5cd0a5c643689626bec213c4d8bd4d96acc8ffdb4ad4bb6bc16abf27d5f4b553"
+checksum = "a878c850e9e421b20262e9b41f9c860e4785fa07541c266b62ff9d1ef998a80a"
dependencies = [
- "asn1-rs 0.6.2",
- "displaydoc",
- "nom",
- "num-bigint",
- "num-traits",
- "rusticata-macros",
+ "const-oid 0.10.2",
+ "pem-rfc7468",
+ "zeroize",
]
[[package]]
-name = "der-parser"
-version = "10.0.0"
+name = "der_derive"
+version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "07da5016415d5a3c4dd39b11ed26f915f52fc4e0dc197d87908bc916e51bc1a6"
+checksum = "8034092389675178f570469e6c3b0465d3d30b4505c294a6550db47f3c17ad18"
dependencies = [
- "asn1-rs 0.7.1",
- "displaydoc",
- "nom",
- "num-bigint",
- "num-traits",
- "rusticata-macros",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.119",
]
[[package]]
name = "deranged"
-version = "0.5.3"
+version = "0.5.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d630bccd429a5bb5a64b5e94f693bfc48c9f8566418fda4c494cc94f911f87cc"
+checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c"
dependencies = [
- "powerfmt",
- "serde",
+ "serde_core",
]
[[package]]
@@ -1805,7 +1541,7 @@ dependencies = [
"darling 0.20.11",
"proc-macro2",
"quote",
- "syn 2.0.106",
+ "syn 2.0.119",
]
[[package]]
@@ -1815,27 +1551,29 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ab63b0e2bf4d5928aff72e83a7dace85d7bba5fe12dcc3c5a572d78caffd3f3c"
dependencies = [
"derive_builder_core",
- "syn 2.0.106",
+ "syn 2.0.119",
]
[[package]]
name = "derive_more"
-version = "2.0.1"
+version = "2.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "093242cf7570c207c83073cf82f79706fe7b8317e98620a47d5be7c3d8497678"
+checksum = "d751e9e49156b02b44f9c1815bcb94b984cdcc4396ecc32521c739452808b134"
dependencies = [
"derive_more-impl",
]
[[package]]
name = "derive_more-impl"
-version = "2.0.1"
+version = "2.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bda628edc44c4bb645fbe0f758797143e4e07926f7ebf4e9bdfbd3d2ce621df3"
+checksum = "799a97264921d8623a957f6c3b9011f3b5492f557bbb7a5a19b7fa6d06ba8dcb"
dependencies = [
+ "convert_case",
"proc-macro2",
"quote",
- "syn 2.0.106",
+ "rustc_version",
+ "syn 2.0.119",
"unicode-xid",
]
@@ -1859,22 +1597,14 @@ dependencies = [
[[package]]
name = "digest"
-version = "0.11.0-rc.3"
+version = "0.11.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dac89f8a64533a9b0eaa73a68e424db0fb1fd6271c74cc0125336a05f090568d"
+checksum = "f1dd6dbb5841937940781866fa1281a1ff7bd3bf827091440879f9994983d5c2"
dependencies = [
- "block-buffer 0.11.0-rc.5",
- "const-oid 0.10.1",
- "crypto-common 0.2.0-rc.4",
-]
-
-[[package]]
-name = "directories"
-version = "6.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "16f5094c54661b38d03bd7e50df373292118db60b585c08a411c6d840017fe7d"
-dependencies = [
- "dirs-sys",
+ "block-buffer 0.12.1",
+ "const-oid 0.10.2",
+ "crypto-common 0.2.2",
+ "ctutils",
]
[[package]]
@@ -1895,48 +1625,37 @@ dependencies = [
"libc",
"option-ext",
"redox_users",
- "windows-sys 0.61.0",
+ "windows-sys 0.61.2",
]
[[package]]
name = "dispatch2"
-version = "0.3.0"
+version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "89a09f22a6c6069a18470eb92d2298acf25463f14256d24778e1230d789a2aec"
+checksum = "1e0e367e4e7da84520dedcac1901e4da967309406d1e51017ae1abfb97adbd38"
dependencies = [
- "bitflags 2.9.4",
- "block2 0.6.1",
+ "bitflags 2.13.2",
+ "block2",
"libc",
- "objc2 0.6.4",
+ "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.106",
-]
-
-[[package]]
-name = "dlopen2"
-version = "0.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "09b4f5f101177ff01b8ec4ecc81eead416a8aa42819a2869311b3420fa114ffa"
-dependencies = [
- "libc",
- "once_cell",
- "winapi",
+ "syn 3.0.5",
]
[[package]]
name = "dlopen2"
-version = "0.8.0"
+version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b54f373ccf864bf587a89e880fb7610f8d73f3045f13580948ccbcaff26febff"
+checksum = "5e2c5bd4158e66d1e215c49b837e11d62f3267b30c92f1d171c4d3105e3dc4d4"
dependencies = [
"dlopen2_derive",
"libc",
@@ -1946,29 +1665,20 @@ dependencies = [
[[package]]
name = "dlopen2_derive"
-version = "0.4.1"
+version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "788160fb30de9cdd857af31c6a2675904b16ece8fc2737b2c7127ba368c9d0f4"
+checksum = "0fbbb781877580993a8707ec48672673ec7b81eeba04cfd2310bd28c08e47c8f"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.106",
-]
-
-[[package]]
-name = "dlv-list"
-version = "0.5.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "442039f5147480ba31067cb00ada1adae6892028e40e45fc5de7b7df6dcc1b5f"
-dependencies = [
- "const-random",
+ "syn 2.0.119",
]
[[package]]
name = "document-features"
-version = "0.2.11"
+version = "0.2.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "95249b50c6c185bee49034bcb378a49dc2b5dff0be90ff6616d31d64febab05d"
+checksum = "d4b8a88685455ed29a21542a33abd9cb6510b6b129abadabdcef0f4c55bc8f61"
dependencies = [
"litrs",
]
@@ -1988,18 +1698,6 @@ dependencies = [
"tendril",
]
-[[package]]
-name = "dotenvy"
-version = "0.15.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b"
-
-[[package]]
-name = "downcast"
-version = "0.11.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1435fa1053d8b2fbbe9be7e97eca7f33d37b28409959813daefc1446a14247f1"
-
[[package]]
name = "dpi"
version = "0.1.2"
@@ -2011,9 +1709,9 @@ dependencies = [
[[package]]
name = "dtoa"
-version = "1.0.10"
+version = "1.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d6add3b8cff394282be81f3fc1a0605db594ed69890078ca6e2cab1c408bcf04"
+checksum = "4c3cf4824e2d5f025c7b531afcb2325364084a16806f6d47fbc1f5fbd9960590"
[[package]]
name = "dtoa-short"
@@ -2052,155 +1750,147 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555"
[[package]]
-name = "dyn-stack"
-version = "0.13.0"
+name = "ecdsa"
+version = "0.16.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "490bd48eb68fffcfed519b4edbfd82c69cbe741d175b84f0e0cbe8c57cbe0bdd"
+checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca"
dependencies = [
- "bytemuck",
+ "der 0.7.10",
+ "digest 0.10.7",
+ "elliptic-curve 0.13.8",
+ "rfc6979 0.4.0",
+ "signature 2.2.0",
+ "spki 0.7.3",
+]
+
+[[package]]
+name = "ecdsa"
+version = "0.17.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c0681a4fc24c767085329728d8dfba959af91228aa4610cca4f8ce317ba46ae0"
+dependencies = [
+ "der 0.8.2",
+ "digest 0.11.3",
+ "elliptic-curve 0.14.1",
+ "rfc6979 0.6.0",
+ "signature 3.0.0",
+ "spki 0.8.0",
+ "zeroize",
]
[[package]]
name = "ed25519"
-version = "3.0.0-rc.1"
+version = "3.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9ef49c0b20c0ad088893ad2a790a29c06a012b3f05bcfc66661fd22a94b32129"
+checksum = "29fcf32e6c73d1079f83ab4d782de2d81620346a5f38c6237a86a22f8368980a"
dependencies = [
- "pkcs8 0.11.0-rc.7",
- "serde",
- "signature 3.0.0-rc.4",
+ "pkcs8 0.11.0",
+ "serdect",
+ "signature 3.0.0",
]
[[package]]
name = "ed25519-dalek"
-version = "3.0.0-pre.1"
+version = "3.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ad207ed88a133091f83224265eac21109930db09bedcad05d5252f2af2de20a1"
+checksum = "6ebaa1a2bf1290ab3bfe5a7b771d050ebffab2711c19a81691c683a5144a25de"
dependencies = [
"curve25519-dalek",
"ed25519",
- "rand_core 0.9.3",
+ "rand_core 0.10.1",
"serde",
- "sha2 0.11.0-rc.2",
- "signature 3.0.0-rc.4",
+ "sha2 0.11.0",
+ "signature 3.0.0",
"subtle",
"zeroize",
]
[[package]]
name = "either"
-version = "1.15.0"
+version = "1.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719"
-dependencies = [
- "serde",
-]
+checksum = "252afb9ae5eaa683babdc6a068b3f5726eb19e05070c731f9b2a23a7c3e8ed34"
[[package]]
-name = "embed-resource"
-version = "3.0.5"
+name = "elliptic-curve"
+version = "0.13.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4c6d81016d6c977deefb2ef8d8290da019e27cc26167e102185da528e6c0ab38"
+checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47"
dependencies = [
- "cc",
- "memchr",
- "rustc_version",
- "toml 0.9.12+spec-1.1.0",
- "vswhom",
- "winreg 0.55.0",
+ "base16ct 0.2.0",
+ "crypto-bigint 0.5.5",
+ "digest 0.10.7",
+ "ff 0.13.1",
+ "generic-array",
+ "group 0.13.0",
+ "pkcs8 0.10.2",
+ "rand_core 0.6.4",
+ "sec1 0.7.3",
+ "subtle",
+ "zeroize",
]
[[package]]
-name = "embed_plist"
-version = "1.2.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4ef6b89e5b37196644d8796de5268852ff179b44e96276cf4290264843743bb7"
-
-[[package]]
-name = "embedded-io"
-version = "0.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ef1a6892d9eef45c8fa6b9e0086428a2cca8491aca8f787c534a3d6d0bcb3ced"
-
-[[package]]
-name = "embedded-io"
-version = "0.6.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "edd0f118536f44f5ccd48bcb8b111bdc3de888b58c74639dfb034a357d0f206d"
-
-[[package]]
-name = "encode_unicode"
-version = "1.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0"
-
-[[package]]
-name = "encoding_rs"
-version = "0.8.35"
+name = "elliptic-curve"
+version = "0.14.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3"
+checksum = "9d65aa39b3a5c1c9c1b745c9a019234bb7a21b77abcb4f4d266d706e2d577d65"
dependencies = [
- "cfg-if",
+ "base16ct 1.0.0",
+ "crypto-bigint 0.7.5",
+ "crypto-common 0.2.2",
+ "digest 0.11.3",
+ "ff 0.14.0",
+ "group 0.14.0",
+ "hybrid-array",
+ "pkcs8 0.11.0",
+ "rand_core 0.10.1",
+ "sec1 0.8.1",
+ "subtle",
+ "zeroize",
]
[[package]]
-name = "endi"
-version = "1.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a3d8a32ae18130a3c84dd492d4215c3d913c3b07c6b63c2eb3eb7ff1101ab7bf"
-
-[[package]]
-name = "enum-as-inner"
-version = "0.6.1"
+name = "embed-resource"
+version = "3.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a1e6a265c649f3f5979b601d26f1d05ada116434c87741c9493cb56218f76cbc"
+checksum = "fbfdaacccebec3b28e4866b8973543c7647797db5ada1bdab552e48fe665fbbd"
dependencies = [
- "heck 0.5.0",
- "proc-macro2",
- "quote",
- "syn 2.0.106",
+ "cc",
+ "memchr",
+ "rustc_version",
+ "toml 1.1.6+spec-1.1.0",
+ "vswhom",
+ "winreg",
]
[[package]]
-name = "enumflags2"
-version = "0.7.12"
+name = "embed_plist"
+version = "1.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1027f7680c853e056ebcec683615fb6fbbc07dbaa13b4d5d9442b146ded4ecef"
-dependencies = [
- "enumflags2_derive",
- "serde",
-]
+checksum = "4ef6b89e5b37196644d8796de5268852ff179b44e96276cf4290264843743bb7"
[[package]]
-name = "enumflags2_derive"
-version = "0.7.12"
+name = "embedded-io"
+version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "67c78a4d8fdf9953a5c9d458f9efe940fd97a0cab0941c075a813ac594733827"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn 2.0.106",
-]
+checksum = "ef1a6892d9eef45c8fa6b9e0086428a2cca8491aca8f787c534a3d6d0bcb3ced"
[[package]]
-name = "env_filter"
-version = "0.1.3"
+name = "embedded-io"
+version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "186e05a59d4c50738528153b83b0b0194d3a29507dfec16eccd4b342903397d0"
-dependencies = [
- "log",
-]
+checksum = "edd0f118536f44f5ccd48bcb8b111bdc3de888b58c74639dfb034a357d0f206d"
[[package]]
-name = "env_logger"
-version = "0.11.8"
+name = "enum-assoc"
+version = "1.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "13c863f0904021b108aa8b2f55046443e6b1ebde8fd4a15c399893aae4fa069f"
+checksum = "0590c4a94da3372e83493b956755a6e2266830b6e4e3b101afe66e3f39477b91"
dependencies = [
- "anstream 0.6.20",
- "anstyle",
- "env_filter",
- "log",
+ "proc-macro2",
+ "quote",
+ "syn 3.0.5",
]
[[package]]
@@ -2211,11 +1901,12 @@ checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
[[package]]
name = "erased-serde"
-version = "0.4.6"
+version = "0.4.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e004d887f51fcb9fef17317a2f3525c887d8aa3f4f50fed920816a688284a5b7"
+checksum = "d2add8a07dd6a8d93ff627029c51de145e12686fbc36ecb298ac22e74cf02dec"
dependencies = [
"serde",
+ "serde_core",
"typeid",
]
@@ -2226,7 +1917,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb"
dependencies = [
"libc",
- "windows-sys 0.61.0",
+ "windows-sys 0.61.2",
]
[[package]]
@@ -2234,55 +1925,40 @@ name = "esaxx-rs"
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d817e038c30374a4bcb22f94d0a8a0e216958d4c3dcde369b1439fec4bdda6e6"
-dependencies = [
- "cc",
-]
[[package]]
-name = "etcetera"
-version = "0.8.0"
+name = "fastrand"
+version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "136d1b5283a1ab77bd9257427ffd09d8667ced0570b6f938942bc7568ed5b943"
-dependencies = [
- "cfg-if",
- "home",
- "windows-sys 0.48.0",
-]
+checksum = "da7c62ceae207dd37ea5b845da6a0696c799f85e97da1ab5b7910be3c1c80223"
[[package]]
-name = "event-listener"
-version = "5.4.1"
+name = "fdeflate"
+version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e13b66accf52311f30a0db42147dadea9850cb48cd070028831ae5f5d4b856ab"
+checksum = "1e6853b52649d4ac5c0bd02320cddc5ba956bdb407c4b75a2c6b75bf51500f8c"
dependencies = [
- "concurrent-queue",
- "parking",
- "pin-project-lite",
+ "simd-adler32",
]
[[package]]
-name = "event-listener-strategy"
-version = "0.5.4"
+name = "ff"
+version = "0.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8be9f3dfaaffdae2972880079a491a1a8bb7cbed0b8dd7a347f668b4150a3b93"
+checksum = "c0b50bfb653653f9ca9095b427bed08ab8d75a137839d9ad64eb11810d5b6393"
dependencies = [
- "event-listener",
- "pin-project-lite",
+ "rand_core 0.6.4",
+ "subtle",
]
[[package]]
-name = "fastrand"
-version = "2.3.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be"
-
-[[package]]
-name = "fdeflate"
-version = "0.3.7"
+name = "ff"
+version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1e6853b52649d4ac5c0bd02320cddc5ba956bdb407c4b75a2c6b75bf51500f8c"
+checksum = "a1f686ab92a9fb0eaf188f6c6c87b89490baa6fdb0db4544ba4dc47f7942489f"
dependencies = [
- "simd-adler32",
+ "rand_core 0.10.1",
+ "subtle",
]
[[package]]
@@ -2303,29 +1979,42 @@ dependencies = [
[[package]]
name = "find-msvc-tools"
-version = "0.1.1"
+version = "0.1.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3e0f1c7c3a72c66fd80abe965175f7523475c0489a87d3ff9d6e8c87d87a9d2d"
+
+[[package]]
+name = "fixedbitset"
+version = "0.5.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99"
+
+[[package]]
+name = "flagset"
+version = "0.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7fd99930f64d146689264c637b5af2f0233a933bef0d8570e2526bf9e083192d"
+checksum = "b7ac824320a75a52197e8f2d787f6a38b6718bb6897a35142d749af3c0e8f4fe"
[[package]]
name = "flate2"
-version = "1.1.2"
+version = "1.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4a3d7db9596fecd151c5f638c0ee5d5bd487b6e0ea232e5dc96d5250f6f94b1d"
+checksum = "6e634e2e0ebac1ee034020da1ca582e17ffe4e0f5e985823721e168928136dcb"
dependencies = [
"crc32fast",
- "miniz_oxide",
+ "miniz_oxide 0.9.1",
+ "zlib-rs",
]
[[package]]
name = "flume"
-version = "0.11.1"
+version = "0.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "da0e4dd2a88388a1f4ccc7c9ce104604dab68d9f408dc34cd45823d5a9069095"
+checksum = "5e139bc46ca777eb5efaf62df0ab8cc5fd400866427e56c68b22e414e53bd3be"
dependencies = [
"futures-core",
"futures-sink",
- "spin 0.9.8",
+ "spin 0.9.9",
]
[[package]]
@@ -2346,15 +2035,6 @@ version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb"
-[[package]]
-name = "foreign-types"
-version = "0.3.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
-dependencies = [
- "foreign-types-shared 0.1.1",
-]
-
[[package]]
name = "foreign-types"
version = "0.5.0"
@@ -2362,26 +2042,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.106",
+ "syn 3.0.5",
]
-[[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"
@@ -2397,12 +2071,6 @@ dependencies = [
"percent-encoding",
]
-[[package]]
-name = "fragile"
-version = "2.0.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "28dd6caf6059519a65843af8fe2a3ae298b14b80179855aeb4adc2c1934ee619"
-
[[package]]
name = "fs_extra"
version = "1.3.0"
@@ -2426,15 +2094,15 @@ dependencies = [
[[package]]
name = "futures-buffered"
-version = "0.2.12"
+version = "0.2.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a8e0e1f38ec07ba4abbde21eed377082f17ccb988be9d988a5adbf4bafc118fd"
+checksum = "4421cb78ee172b6b06080093479d3c50f058e7c81b7d577bbb8d118d551d4cd5"
dependencies = [
"cordyceps",
"diatomic-waker",
"futures-core",
"pin-project-lite",
- "spin 0.10.0",
+ "spin 0.10.1",
]
[[package]]
@@ -2464,17 +2132,6 @@ dependencies = [
"futures-util",
]
-[[package]]
-name = "futures-intrusive"
-version = "0.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1d930c203dd0b6ff06e0201a4a2fe9149b43c684fd4420555b26d21b1a02956f"
-dependencies = [
- "futures-core",
- "lock_api",
- "parking_lot",
-]
-
[[package]]
name = "futures-io"
version = "0.3.34"
@@ -2502,7 +2159,7 @@ checksum = "9fb9654ba8355388abeb8dcb4fc62f511300867002afc858860463bdd9fe0c44"
dependencies = [
"proc-macro2",
"quote",
- "syn 3.0.2",
+ "syn 3.0.5",
]
[[package]]
@@ -2535,411 +2192,75 @@ dependencies = [
]
[[package]]
-name = "gate-chat-ui"
-version = "0.1.0"
+name = "gdk"
+version = "0.18.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d9f245958c627ac99d8e529166f9823fb3b838d1d41fd2b297af3075093c2691"
dependencies = [
- "anyhow",
- "base64 0.23.1",
- "console_error_panic_hook",
- "gloo-net 0.6.0",
- "gloo-timers",
- "js-sys",
- "serde",
- "serde_json",
- "tokio-test",
- "wasm-bindgen",
- "wasm-bindgen-futures",
- "wasm-bindgen-test",
- "web-sys",
- "yew",
+ "cairo-rs",
+ "gdk-pixbuf",
+ "gdk-sys",
+ "gio",
+ "glib",
+ "libc",
+ "pango",
]
[[package]]
-name = "gate-core"
-version = "0.1.0"
+name = "gdk-pixbuf"
+version = "0.18.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "50e1f5f1b0bfb830d6ccc8066d18db35c487b1b2b1e8589b5dfe9f07e8defaec"
dependencies = [
- "anyhow",
- "async-stream",
- "async-trait",
- "chrono",
- "config",
- "futures",
- "getrandom 0.4.3",
- "hex",
- "http 1.5.0",
- "js-sys",
- "mockall",
- "opentelemetry",
- "opentelemetry-otlp",
- "opentelemetry_sdk",
- "rand 0.9.5",
- "rust_decimal",
- "serde",
- "serde_json",
- "sqlx-d1",
- "thiserror 2.0.20",
- "tokio",
- "tracing",
- "tracing-opentelemetry",
- "tracing-subscriber",
- "url",
- "uuid",
- "worker",
+ "gdk-pixbuf-sys",
+ "gio",
+ "glib",
+ "libc",
+ "once_cell",
]
[[package]]
-name = "gate-daemon"
-version = "0.1.0"
+name = "gdk-pixbuf-sys"
+version = "0.18.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3f9839ea644ed9c97a34d129ad56d38a25e6756f99f3a88e15cd39c20629caf7"
dependencies = [
- "anyhow",
- "async-trait",
- "axum",
- "base64 0.23.1",
- "catgrad-llm",
- "chrono",
- "clap",
- "config",
- "directories",
- "dotenvy",
- "futures",
- "gate-core",
- "gate-http",
- "gate-p2p",
- "gate-sqlx",
- "gate-tlsforward",
- "hex",
- "hyper-util",
- "iroh",
- "rand 0.9.5",
- "rcgen",
- "reqwest 0.12.28",
- "rustls",
- "serde",
- "serde_json",
- "tempfile",
- "thiserror 2.0.20",
- "tokio",
- "tokio-rustls",
- "tower",
- "tower-http 0.7.1",
- "tracing",
- "tracing-subscriber",
- "uuid",
- "webauthn-rs",
+ "gio-sys",
+ "glib-sys",
+ "gobject-sys",
+ "libc",
+ "system-deps",
]
[[package]]
-name = "gate-fixtures"
-version = "0.1.0"
+name = "gdk-sys"
+version = "0.18.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5c2d13f38594ac1e66619e188c6d5a1adb98d11b2fcf7894fc416ad76aa2f3f7"
dependencies = [
- "serde",
- "serde_json",
- "walkdir",
+ "cairo-sys-rs",
+ "gdk-pixbuf-sys",
+ "gio-sys",
+ "glib-sys",
+ "gobject-sys",
+ "libc",
+ "pango-sys",
+ "pkg-config",
+ "system-deps",
]
[[package]]
-name = "gate-frontend-common"
-version = "0.1.0"
+name = "gdkwayland-sys"
+version = "0.18.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "140071d506d223f7572b9f09b5e155afbd77428cd5cc7af8f2694c41d98dfe69"
dependencies = [
- "base64 0.23.1",
- "gate-chat-ui",
- "gate-http",
- "getrandom 0.4.3",
- "gloo",
- "js-sys",
- "once_cell",
- "reqwest 0.12.28",
- "serde",
- "serde_json",
- "thiserror 2.0.20",
- "tracing",
- "tracing-subscriber",
- "tracing-web",
- "wasm-bindgen",
- "wasm-bindgen-futures",
- "wasm-bindgen-test",
- "wasm-logger",
- "web-sys",
- "yew",
- "yew-router",
-]
-
-[[package]]
-name = "gate-frontend-daemon"
-version = "0.1.0"
-dependencies = [
- "chrono",
- "gate-chat-ui",
- "gate-frontend-common",
- "getrandom 0.4.3",
- "gloo",
- "reqwest 0.12.28",
- "serde",
- "serde-wasm-bindgen",
- "serde_json",
- "tracing",
- "tracing-subscriber",
- "tracing-web",
- "wasm-bindgen",
- "wasm-bindgen-futures",
- "wasm-bindgen-test",
- "wasm-logger",
- "web-sys",
- "yew",
- "yew-router",
-]
-
-[[package]]
-name = "gate-frontend-relay"
-version = "0.1.0"
-dependencies = [
- "gate-frontend-common",
- "gloo-net 0.6.0",
- "gloo-timers",
- "serde",
- "serde_json",
- "tracing",
- "tracing-subscriber",
- "tracing-web",
- "wasm-bindgen",
- "wasm-bindgen-futures",
- "wasm-bindgen-test",
- "wasm-logger",
- "web-sys",
- "yew",
- "yew-router",
-]
-
-[[package]]
-name = "gate-frontend-tauri"
-version = "0.1.0"
-dependencies = [
- "gate-chat-ui",
- "gate-frontend-common",
- "getrandom 0.4.3",
- "gloo-events",
- "gloo-timers",
- "gloo-utils",
- "js-sys",
- "serde",
- "serde-wasm-bindgen",
- "serde_json",
- "tracing",
- "tracing-subscriber",
- "tracing-web",
- "wasm-bindgen",
- "wasm-bindgen-futures",
- "wasm-bindgen-test",
- "wasm-logger",
- "web-sys",
- "yew",
- "yew-router",
-]
-
-[[package]]
-name = "gate-gui"
-version = "0.1.0"
-dependencies = [
- "anyhow",
- "axum",
- "gate-core",
- "gate-daemon",
- "gate-http",
- "gate-p2p",
- "gate-sqlx",
- "gate-tlsforward",
- "hex",
- "rand 0.9.5",
- "rustls",
- "serde",
- "serde_json",
- "tauri",
- "tauri-build",
- "tauri-plugin-opener",
- "tokio",
- "tracing",
- "tracing-subscriber",
-]
-
-[[package]]
-name = "gate-http"
-version = "0.1.0"
-dependencies = [
- "anyhow",
- "async-trait",
- "axum",
- "base64 0.23.1",
- "bytes",
- "chrono",
- "futures",
- "gate-core",
- "getrandom 0.4.3",
- "http 1.5.0",
- "http-body-util",
- "hyper",
- "hyper-util",
- "jsonwebtoken",
- "opentelemetry",
- "rand 0.9.5",
- "reqwest 0.12.28",
- "rust_decimal",
- "serde",
- "serde_json",
- "sha2 0.10.9",
- "thiserror 2.0.20",
- "tokio",
- "tower",
- "tower-http 0.7.1",
- "tracing",
- "tracing-subscriber",
- "url",
- "uuid",
- "webauthn-rs",
- "wiremock",
-]
-
-[[package]]
-name = "gate-p2p"
-version = "0.1.0"
-dependencies = [
- "anyhow",
- "futures",
- "iroh",
- "thiserror 2.0.20",
- "tokio",
- "tracing",
-]
-
-[[package]]
-name = "gate-sqlx"
-version = "0.1.0"
-dependencies = [
- "async-trait",
- "chrono",
- "gate-core",
- "serde",
- "serde_json",
- "sqlx",
- "tokio",
- "tracing",
-]
-
-[[package]]
-name = "gate-tlsforward"
-version = "0.1.0"
-dependencies = [
- "anyhow",
- "async-trait",
- "axum",
- "bytes",
- "chrono",
- "clap",
- "cloudflare",
- "config",
- "dashmap",
- "deadpool 0.13.1",
- "directories",
- "futures",
- "gate-core",
- "gate-daemon",
- "gate-http",
- "gate-p2p",
- "gate-tlsforward",
- "hex",
- "http 1.5.0",
- "http-body-util",
- "hyper",
- "hyper-util",
- "instant-acme",
- "iroh",
- "n0-future",
- "rand 0.9.5",
- "rcgen",
- "serde",
- "serde_json",
- "tempfile",
- "thiserror 2.0.20",
- "tokio",
- "tokio-rustls",
- "tokio-test",
- "tower",
- "tracing",
- "tracing-subscriber",
- "trust-dns-resolver",
- "uuid",
- "x509-parser 0.18.1",
-]
-
-[[package]]
-name = "gdk"
-version = "0.18.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d9f245958c627ac99d8e529166f9823fb3b838d1d41fd2b297af3075093c2691"
-dependencies = [
- "cairo-rs",
- "gdk-pixbuf",
- "gdk-sys",
- "gio",
- "glib",
- "libc",
- "pango",
-]
-
-[[package]]
-name = "gdk-pixbuf"
-version = "0.18.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "50e1f5f1b0bfb830d6ccc8066d18db35c487b1b2b1e8589b5dfe9f07e8defaec"
-dependencies = [
- "gdk-pixbuf-sys",
- "gio",
- "glib",
- "libc",
- "once_cell",
-]
-
-[[package]]
-name = "gdk-pixbuf-sys"
-version = "0.18.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3f9839ea644ed9c97a34d129ad56d38a25e6756f99f3a88e15cd39c20629caf7"
-dependencies = [
- "gio-sys",
- "glib-sys",
- "gobject-sys",
- "libc",
- "system-deps",
-]
-
-[[package]]
-name = "gdk-sys"
-version = "0.18.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5c2d13f38594ac1e66619e188c6d5a1adb98d11b2fcf7894fc416ad76aa2f3f7"
-dependencies = [
- "cairo-sys-rs",
- "gdk-pixbuf-sys",
- "gio-sys",
- "glib-sys",
- "gobject-sys",
- "libc",
- "pango-sys",
- "pkg-config",
- "system-deps",
-]
-
-[[package]]
-name = "gdkwayland-sys"
-version = "0.18.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "140071d506d223f7572b9f09b5e155afbd77428cd5cc7af8f2694c41d98dfe69"
-dependencies = [
- "gdk-sys",
- "glib-sys",
- "gobject-sys",
- "libc",
- "pkg-config",
- "system-deps",
+ "gdk-sys",
+ "glib-sys",
+ "gobject-sys",
+ "libc",
+ "pkg-config",
+ "system-deps",
]
[[package]]
@@ -2970,153 +2291,42 @@ dependencies = [
]
[[package]]
-name = "gemm"
-version = "0.18.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ab96b703d31950f1aeddded248bc95543c9efc7ac9c4a21fda8703a83ee35451"
-dependencies = [
- "dyn-stack",
- "gemm-c32",
- "gemm-c64",
- "gemm-common",
- "gemm-f16",
- "gemm-f32",
- "gemm-f64",
- "num-complex",
- "num-traits",
- "paste",
- "raw-cpuid",
- "seq-macro",
-]
-
-[[package]]
-name = "gemm-c32"
-version = "0.18.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f6db9fd9f40421d00eea9dd0770045a5603b8d684654816637732463f4073847"
-dependencies = [
- "dyn-stack",
- "gemm-common",
- "num-complex",
- "num-traits",
- "paste",
- "raw-cpuid",
- "seq-macro",
-]
-
-[[package]]
-name = "gemm-c64"
-version = "0.18.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dfcad8a3d35a43758330b635d02edad980c1e143dc2f21e6fd25f9e4eada8edf"
-dependencies = [
- "dyn-stack",
- "gemm-common",
- "num-complex",
- "num-traits",
- "paste",
- "raw-cpuid",
- "seq-macro",
-]
-
-[[package]]
-name = "gemm-common"
-version = "0.18.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a352d4a69cbe938b9e2a9cb7a3a63b7e72f9349174a2752a558a8a563510d0f3"
-dependencies = [
- "bytemuck",
- "dyn-stack",
- "half",
- "libm",
- "num-complex",
- "num-traits",
- "once_cell",
- "paste",
- "pulp",
- "raw-cpuid",
- "rayon",
- "seq-macro",
- "sysctl",
-]
-
-[[package]]
-name = "gemm-f16"
-version = "0.18.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cff95ae3259432f3c3410eaa919033cd03791d81cebd18018393dc147952e109"
-dependencies = [
- "dyn-stack",
- "gemm-common",
- "gemm-f32",
- "half",
- "num-complex",
- "num-traits",
- "paste",
- "raw-cpuid",
- "rayon",
- "seq-macro",
-]
-
-[[package]]
-name = "gemm-f32"
-version = "0.18.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bc8d3d4385393304f407392f754cd2dc4b315d05063f62cf09f47b58de276864"
-dependencies = [
- "dyn-stack",
- "gemm-common",
- "num-complex",
- "num-traits",
- "paste",
- "raw-cpuid",
- "seq-macro",
-]
-
-[[package]]
-name = "gemm-f64"
-version = "0.18.2"
+name = "gearhash"
+version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "35b2a4f76ce4b8b16eadc11ccf2e083252d8237c1b589558a49b0183545015bd"
-dependencies = [
- "dyn-stack",
- "gemm-common",
- "num-complex",
- "num-traits",
- "paste",
- "raw-cpuid",
- "seq-macro",
-]
+checksum = "616e8f476a586f1b078d9eece21f7a071f27997e709e2b471f5697deea53bda9"
[[package]]
name = "generator"
-version = "0.8.7"
+version = "0.8.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "605183a538e3e2a9c1038635cc5c2d194e2ee8fd0d1b66b8349fad7dbacce5a2"
+checksum = "b3b854b0e584ead1a33f18b2fcad7cf7be18b3875c78816b753639aa501513ae"
dependencies = [
"cc",
"cfg-if",
"libc",
"log",
"rustversion",
- "windows 0.61.3",
+ "windows-link 0.2.1",
+ "windows-result 0.4.1",
]
[[package]]
name = "generic-array"
-version = "0.14.7"
+version = "0.14.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
+checksum = "4bb6743198531e02858aeaea5398fcc883e71851fcbcb5a2f773e2fb6cb1edf2"
dependencies = [
"typenum",
"version_check",
+ "zeroize",
]
[[package]]
name = "getrandom"
-version = "0.2.16"
+version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592"
+checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0"
dependencies = [
"cfg-if",
"js-sys",
@@ -3149,9 +2359,20 @@ dependencies = [
"js-sys",
"libc",
"r-efi 6.0.0",
+ "rand_core 0.10.1",
"wasm-bindgen",
]
+[[package]]
+name = "ghash"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f0d8a4362ccb29cb0b265253fb0a2728f592895ee6854fd9bc13f2ffda266ff1"
+dependencies = [
+ "opaque-debug",
+ "polyval",
+]
+
[[package]]
name = "gio"
version = "0.18.4"
@@ -3190,7 +2411,7 @@ version = "0.18.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "233daaf6e83ae6a12a52055f568f9d7cf4671dabb78ff9560ab6da230ce00ee5"
dependencies = [
- "bitflags 2.9.4",
+ "bitflags 2.13.2",
"futures-channel",
"futures-core",
"futures-executor",
@@ -3200,187 +2421,42 @@ dependencies = [
"glib-macros",
"glib-sys",
"gobject-sys",
- "libc",
- "memchr",
- "once_cell",
- "smallvec",
- "thiserror 1.0.69",
-]
-
-[[package]]
-name = "glib-macros"
-version = "0.18.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0bb0228f477c0900c880fd78c8759b95c7636dbd7842707f49e132378aa2acdc"
-dependencies = [
- "heck 0.4.1",
- "proc-macro-crate 2.0.0",
- "proc-macro-error",
- "proc-macro2",
- "quote",
- "syn 2.0.106",
-]
-
-[[package]]
-name = "glib-sys"
-version = "0.18.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "063ce2eb6a8d0ea93d2bf8ba1957e78dbab6be1c2220dd3daca57d5a9d869898"
-dependencies = [
- "libc",
- "system-deps",
-]
-
-[[package]]
-name = "glob"
-version = "0.3.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280"
-
-[[package]]
-name = "gloo"
-version = "0.11.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d15282ece24eaf4bd338d73ef580c6714c8615155c4190c781290ee3fa0fd372"
-dependencies = [
- "gloo-console",
- "gloo-dialogs",
- "gloo-events",
- "gloo-file",
- "gloo-history",
- "gloo-net 0.5.0",
- "gloo-render",
- "gloo-storage",
- "gloo-timers",
- "gloo-utils",
- "gloo-worker",
-]
-
-[[package]]
-name = "gloo-console"
-version = "0.3.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2a17868f56b4a24f677b17c8cb69958385102fa879418052d60b50bc1727e261"
-dependencies = [
- "gloo-utils",
- "js-sys",
- "serde",
- "wasm-bindgen",
- "web-sys",
-]
-
-[[package]]
-name = "gloo-dialogs"
-version = "0.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bf4748e10122b01435750ff530095b1217cf6546173459448b83913ebe7815df"
-dependencies = [
- "wasm-bindgen",
- "web-sys",
-]
-
-[[package]]
-name = "gloo-events"
-version = "0.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "27c26fb45f7c385ba980f5fa87ac677e363949e065a083722697ef1b2cc91e41"
-dependencies = [
- "wasm-bindgen",
- "web-sys",
-]
-
-[[package]]
-name = "gloo-file"
-version = "0.3.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "97563d71863fb2824b2e974e754a81d19c4a7ec47b09ced8a0e6656b6d54bd1f"
-dependencies = [
- "futures-channel",
- "gloo-events",
- "js-sys",
- "wasm-bindgen",
- "web-sys",
-]
-
-[[package]]
-name = "gloo-history"
-version = "0.2.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "903f432be5ba34427eac5e16048ef65604a82061fe93789f2212afc73d8617d6"
-dependencies = [
- "getrandom 0.2.16",
- "gloo-events",
- "gloo-utils",
- "serde",
- "serde-wasm-bindgen",
- "serde_urlencoded",
- "thiserror 1.0.69",
- "wasm-bindgen",
- "web-sys",
-]
-
-[[package]]
-name = "gloo-net"
-version = "0.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "43aaa242d1239a8822c15c645f02166398da4f8b5c4bae795c1f5b44e9eee173"
-dependencies = [
- "futures-channel",
- "futures-core",
- "futures-sink",
- "gloo-utils",
- "http 0.2.12",
- "js-sys",
- "pin-project",
- "serde",
- "serde_json",
+ "libc",
+ "memchr",
+ "once_cell",
+ "smallvec",
"thiserror 1.0.69",
- "wasm-bindgen",
- "wasm-bindgen-futures",
- "web-sys",
]
[[package]]
-name = "gloo-net"
-version = "0.6.0"
+name = "glib-macros"
+version = "0.18.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c06f627b1a58ca3d42b45d6104bf1e1a03799df472df00988b6ba21accc10580"
+checksum = "0bb0228f477c0900c880fd78c8759b95c7636dbd7842707f49e132378aa2acdc"
dependencies = [
- "gloo-utils",
- "http 1.5.0",
- "js-sys",
- "serde",
- "serde_json",
- "thiserror 1.0.69",
- "wasm-bindgen",
- "wasm-bindgen-futures",
- "web-sys",
+ "heck 0.4.1",
+ "proc-macro-crate 2.0.2",
+ "proc-macro-error",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.119",
]
[[package]]
-name = "gloo-render"
-version = "0.2.0"
+name = "glib-sys"
+version = "0.18.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "56008b6744713a8e8d98ac3dcb7d06543d5662358c9c805b4ce2167ad4649833"
+checksum = "063ce2eb6a8d0ea93d2bf8ba1957e78dbab6be1c2220dd3daca57d5a9d869898"
dependencies = [
- "wasm-bindgen",
- "web-sys",
+ "libc",
+ "system-deps",
]
[[package]]
-name = "gloo-storage"
-version = "0.3.0"
+name = "glob"
+version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fbc8031e8c92758af912f9bc08fbbadd3c6f3cfcbf6b64cdf3d6a81f0139277a"
-dependencies = [
- "gloo-utils",
- "js-sys",
- "serde",
- "serde_json",
- "thiserror 1.0.69",
- "wasm-bindgen",
- "web-sys",
-]
+checksum = "e4eba85ea1d0a966a983acd07deee566e67395d2d96b6fb39e62b5a833f1eb0b"
[[package]]
name = "gloo-timers"
@@ -3395,58 +2471,36 @@ dependencies = [
]
[[package]]
-name = "gloo-utils"
-version = "0.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0b5555354113b18c547c1d3a98fbf7fb32a9ff4f6fa112ce823a21641a0ba3aa"
-dependencies = [
- "js-sys",
- "serde",
- "serde_json",
- "wasm-bindgen",
- "web-sys",
-]
-
-[[package]]
-name = "gloo-worker"
-version = "0.5.0"
+name = "gobject-sys"
+version = "0.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "085f262d7604911c8150162529cefab3782e91adb20202e8658f7275d2aefe5d"
+checksum = "0850127b514d1c4a4654ead6dedadb18198999985908e6ffe4436f53c785ce44"
dependencies = [
- "bincode",
- "futures",
- "gloo-utils",
- "gloo-worker-macros",
- "js-sys",
- "pinned",
- "serde",
- "thiserror 1.0.69",
- "wasm-bindgen",
- "wasm-bindgen-futures",
- "web-sys",
+ "glib-sys",
+ "libc",
+ "system-deps",
]
[[package]]
-name = "gloo-worker-macros"
-version = "0.1.0"
+name = "group"
+version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "956caa58d4857bc9941749d55e4bd3000032d8212762586fa5705632967140e7"
+checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63"
dependencies = [
- "proc-macro-crate 1.3.1",
- "proc-macro2",
- "quote",
- "syn 2.0.106",
+ "ff 0.13.1",
+ "rand_core 0.6.4",
+ "subtle",
]
[[package]]
-name = "gobject-sys"
-version = "0.18.0"
+name = "group"
+version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0850127b514d1c4a4654ead6dedadb18198999985908e6ffe4436f53c785ce44"
+checksum = "7fd1a1c7a5206c5b7a3f5a0d7ccd3ff85d0c8f5133d62a02680255b0004af5f4"
dependencies = [
- "glib-sys",
- "libc",
- "system-deps",
+ "ff 0.14.0",
+ "rand_core 0.10.1",
+ "subtle",
]
[[package]]
@@ -3498,22 +2552,22 @@ dependencies = [
"proc-macro-error",
"proc-macro2",
"quote",
- "syn 2.0.106",
+ "syn 2.0.119",
]
[[package]]
name = "h2"
-version = "0.4.14"
+version = "0.4.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "171fefbc92fe4a4de27e0698d6a5b392d6a0e333506bc49133760b3bcf948733"
+checksum = "ef8e5e5a340588f4452631496976cf8636d4a7ecf600239fdc27615d2530bc16"
dependencies = [
"atomic-waker",
"bytes",
"fnv",
"futures-core",
"futures-sink",
- "http 1.5.0",
- "indexmap 2.12.0",
+ "http",
+ "indexmap 2.14.2",
"slab",
"tokio",
"tokio-util",
@@ -3522,23 +2576,13 @@ dependencies = [
[[package]]
name = "half"
-version = "2.6.0"
+version = "2.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "459196ed295495a68f7d7fe1d84f6c4b7ff0e21fe3017b2f283c6fac3ad803c9"
+checksum = "6ea2d84b969582b4b1864a92dc5d27cd2b77b622a8d79306834f1be5ba20d84b"
dependencies = [
- "bytemuck",
"cfg-if",
"crunchy",
- "num-traits",
-]
-
-[[package]]
-name = "hash32"
-version = "0.2.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b0c35f58762feb77d74ebe43bdbc3210f09be9fe6742234d573bacc26ed92b67"
-dependencies = [
- "byteorder",
+ "zerocopy",
]
[[package]]
@@ -3559,16 +2603,14 @@ version = "0.15.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1"
dependencies = [
- "allocator-api2",
- "equivalent",
"foldhash 0.1.5",
]
[[package]]
name = "hashbrown"
-version = "0.16.0"
+version = "0.17.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5419bdc4f6a9207fbeba6d11b604d481addf78ecd10c11ad51e76c2f6482748d"
+checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a"
dependencies = [
"allocator-api2",
"equivalent",
@@ -3576,54 +2618,308 @@ dependencies = [
]
[[package]]
-name = "hashlink"
-version = "0.10.0"
+name = "heck"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
+
+[[package]]
+name = "heck"
+version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7382cf6263419f2d8df38c55d7da83da5c18aef87fc7a7fc1fb1e344edfe14c1"
+checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
+
+[[package]]
+name = "hellas-adaptors"
+version = "0.1.0"
dependencies = [
- "hashbrown 0.15.5",
+ "futures-core",
+ "futures-util",
+ "hellas-rpc",
+ "serde",
+ "serde_json",
+ "thiserror 2.0.20",
]
[[package]]
-name = "hashlink"
-version = "0.11.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "824e001ac4f3012dd16a264bec811403a67ca9deb6c102fc5049b32c4574b35f"
+name = "hellas-attestation"
+version = "0.1.0"
+dependencies = [
+ "base64 0.22.1",
+ "ciborium",
+ "hellas-rpc",
+ "p256",
+ "rustls-pki-types",
+ "rustls-webpki",
+ "serde",
+ "serde_bytes",
+ "sha2 0.11.0",
+ "thiserror 2.0.20",
+ "x509-cert",
+]
+
+[[package]]
+name = "hellas-chain"
+version = "0.1.0"
+dependencies = [
+ "base64ct",
+ "bs58",
+ "bytes",
+ "commonware-codec",
+ "commonware-cryptography",
+ "commonware-parallel",
+ "hellas-genesis",
+ "hellas-kernel",
+ "hellas-rpc",
+ "hellas-wire",
+ "p256",
+ "rand 0.10.2",
+ "serde",
+ "serde_json",
+ "sha2 0.11.0",
+ "thiserror 2.0.20",
+ "tracing",
+ "url",
+]
+
+[[package]]
+name = "hellas-client"
+version = "0.1.0"
+dependencies = [
+ "async-stream",
+ "futures",
+ "hellas-attestation",
+ "hellas-rpc",
+ "hellas-wire",
+ "iroh",
+ "iroh-mdns-address-lookup",
+ "rand 0.10.2",
+ "thiserror 2.0.20",
+ "tokio",
+]
+
+[[package]]
+name = "hellas-executor"
+version = "0.1.0"
+dependencies = [
+ "async-trait",
+ "futures-core",
+ "futures-util",
+ "hellas-chain",
+ "hellas-kernel",
+ "hellas-rpc",
+ "hellas-wire",
+ "hellas-work",
+ "libc",
+ "prometheus-client",
+ "rand 0.10.2",
+ "serde",
+ "serde_json",
+ "thiserror 2.0.20",
+ "tokio",
+ "tokio-stream",
+ "tracing",
+ "uuid",
+ "zeroize",
+]
+
+[[package]]
+name = "hellas-gate"
+version = "0.1.0"
+dependencies = [
+ "anyhow",
+ "cc",
+ "futures",
+ "hellas-attestation",
+ "hellas-rpc",
+ "hellas-sdk",
+ "hellas-wire",
+ "libc",
+ "serde",
+ "serde_json",
+ "tauri",
+ "tauri-build",
+ "tempfile",
+ "thiserror 2.0.20",
+ "tokio",
+ "tracing",
+ "tracing-subscriber",
+ "ts-rs",
+]
+
+[[package]]
+name = "hellas-gateway"
+version = "0.1.0"
+dependencies = [
+ "anyhow",
+ "async-stream",
+ "axum",
+ "futures",
+ "hellas-adaptors",
+ "hellas-client",
+ "hellas-presentation",
+ "hellas-rpc",
+ "hellas-wire",
+ "iroh",
+ "prometheus-client",
+ "rand 0.10.2",
+ "reqwest",
+ "serde",
+ "serde_json",
+ "thiserror 2.0.20",
+ "tokio",
+ "tower",
+ "tracing",
+]
+
+[[package]]
+name = "hellas-genesis"
+version = "0.1.0"
+dependencies = [
+ "serde",
+ "thiserror 2.0.20",
+]
+
+[[package]]
+name = "hellas-kernel"
+version = "0.1.0"
+dependencies = [
+ "hellas-xet",
+ "k256",
+]
+
+[[package]]
+name = "hellas-presentation"
+version = "0.1.0"
+dependencies = [
+ "anyhow",
+ "hellas-rpc",
+ "tokenizers",
+]
+
+[[package]]
+name = "hellas-providers"
+version = "0.1.0"
+dependencies = [
+ "anyhow",
+ "async-stream",
+ "futures",
+ "hellas-adaptors",
+ "hellas-executor",
+ "hellas-rpc",
+ "reqwest",
+ "serde",
+ "serde_json",
+ "tokio",
+ "tracing",
+]
+
+[[package]]
+name = "hellas-rpc"
+version = "0.1.0"
+dependencies = [
+ "bytes",
+ "ed25519-dalek",
+ "futures-core",
+ "futures-util",
+ "getrandom 0.2.17",
+ "hellas-kernel",
+ "hellas-wire",
+ "hellas-xet",
+ "k256",
+ "p256",
+ "prettyplease",
+ "proc-macro2",
+ "prost",
+ "prost-build",
+ "prost-types",
+ "protox",
+ "quote",
+ "serde",
+ "serde_bytes",
+ "serde_ipld_dagcbor",
+ "serde_json",
+ "smol_str 0.3.6",
+ "syn 2.0.119",
+ "thiserror 2.0.20",
+ "tracing",
+ "web-time",
+]
+
+[[package]]
+name = "hellas-sdk"
+version = "0.1.0"
dependencies = [
- "hashbrown 0.16.0",
+ "anyhow",
+ "futures-core",
+ "hellas-attestation",
+ "hellas-client",
+ "hellas-executor",
+ "hellas-gateway",
+ "hellas-providers",
+ "hellas-rpc",
+ "hellas-wire",
+ "iroh",
+ "tempfile",
+ "tokio",
+ "tracing",
]
[[package]]
-name = "heapless"
-version = "0.7.17"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cdc6457c0eb62c71aac4bc17216026d8410337c4126773b9c5daba343f17964f"
+name = "hellas-wire"
+version = "0.1.0"
dependencies = [
- "atomic-polyfill",
- "hash32",
- "rustc_version",
+ "async-stream",
+ "bytes",
+ "data-encoding",
+ "futures",
+ "futures-core",
+ "hellas-xet",
+ "iroh",
+ "iroh-mdns-address-lookup",
+ "mainline",
+ "n0-future",
+ "portable-atomic",
+ "postcard",
+ "rustls",
"serde",
- "spin 0.9.8",
- "stable_deref_trait",
+ "sha2 0.11.0",
+ "smol_str 0.3.6",
+ "thiserror 2.0.20",
+ "tokio",
+ "tokio-stream",
+ "tokio-tungstenite",
+ "tracing",
+ "web-time",
]
[[package]]
-name = "heck"
-version = "0.4.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
+name = "hellas-work"
+version = "0.1.0"
+dependencies = [
+ "hellas-kernel",
+ "hellas-rpc",
+ "hellas-wire",
+ "hellas-xet",
+ "prost",
+ "thiserror 2.0.20",
+ "tracing",
+]
[[package]]
-name = "heck"
-version = "0.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
+name = "hellas-xet"
+version = "0.1.0"
+dependencies = [
+ "blake3",
+ "gearhash",
+ "serde",
+]
[[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"
@@ -3631,87 +2927,24 @@ version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
-[[package]]
-name = "hf-hub"
-version = "0.4.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "629d8f3bbeda9d148036d6b0de0a3ab947abd08ce90626327fc3547a49d59d97"
-dependencies = [
- "dirs",
- "http 1.5.0",
- "indicatif",
- "libc",
- "log",
- "rand 0.9.5",
- "serde",
- "serde_json",
- "thiserror 2.0.20",
- "ureq",
- "windows-sys 0.60.2",
-]
-
[[package]]
name = "hickory-proto"
-version = "0.25.2"
+version = "0.26.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f8a6fe56c0038198998a6f217ca4e7ef3a5e51f46163bd6dd60b5c71ca6c6502"
+checksum = "12b92608f679a6fa515dd1d15c1ff89443026e391200a2c840c7afcba482893d"
dependencies = [
- "async-trait",
- "bytes",
- "cfg-if",
"data-encoding",
- "enum-as-inner",
- "futures-channel",
- "futures-io",
- "futures-util",
- "h2",
- "http 1.5.0",
- "idna 1.1.0",
+ "idna",
"ipnet",
+ "jni 0.22.4",
"once_cell",
- "rand 0.9.5",
- "ring",
- "rustls",
+ "rand 0.10.2",
"thiserror 2.0.20",
"tinyvec",
- "tokio",
- "tokio-rustls",
"tracing",
"url",
]
-[[package]]
-name = "hickory-resolver"
-version = "0.25.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dc62a9a99b0bfb44d2ab95a7208ac952d31060efc16241c87eaf36406fecf87a"
-dependencies = [
- "cfg-if",
- "futures-util",
- "hickory-proto",
- "ipconfig",
- "moka",
- "once_cell",
- "parking_lot",
- "rand 0.9.5",
- "resolv-conf",
- "rustls",
- "smallvec",
- "thiserror 2.0.20",
- "tokio",
- "tokio-rustls",
- "tracing",
-]
-
-[[package]]
-name = "hkdf"
-version = "0.12.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7"
-dependencies = [
- "hmac",
-]
-
[[package]]
name = "hmac"
version = "0.12.1"
@@ -3722,12 +2955,12 @@ dependencies = [
]
[[package]]
-name = "home"
-version = "0.5.11"
+name = "hmac"
+version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "589533453244b0995c858700322199b2becb13b627df2851f64a2775d024abcf"
+checksum = "6303bc9732ae41b04cb554b844a762b4115a61bfaa81e3e83050991eeb56863f"
dependencies = [
- "windows-sys 0.59.0",
+ "digest 0.11.3",
]
[[package]]
@@ -3740,17 +2973,6 @@ dependencies = [
"markup5ever",
]
-[[package]]
-name = "http"
-version = "0.2.12"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1"
-dependencies = [
- "bytes",
- "fnv",
- "itoa",
-]
-
[[package]]
name = "http"
version = "1.5.0"
@@ -3763,12 +2985,12 @@ 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 1.5.0",
+ "http",
]
[[package]]
@@ -3779,17 +3001,11 @@ checksum = "23169fe34a5fbcdd3f3862e78fb9b6fccd5f02a6dc6f732547005d45631ce71c"
dependencies = [
"bytes",
"futures-core",
- "http 1.5.0",
+ "http",
"http-body",
"pin-project-lite",
]
-[[package]]
-name = "http-range-header"
-version = "0.4.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9171a2ea8a68358193d15dd5d70c1c10a2afc3e7e4c5bc92bc9f025cebd7359c"
-
[[package]]
name = "httparse"
version = "1.10.1"
@@ -3804,10 +3020,11 @@ checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9"
[[package]]
name = "hybrid-array"
-version = "0.4.5"
+version = "0.4.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f471e0a81b2f90ffc0cb2f951ae04da57de8baa46fa99112b062a5173a5088d0"
+checksum = "27f864f10dfb56725ce5ce5472bc52252c8f93a4ab86327122cebf62c5f59a17"
dependencies = [
+ "subtle",
"typenum",
"zeroize",
]
@@ -3823,7 +3040,7 @@ dependencies = [
"futures-channel",
"futures-core",
"h2",
- "http 1.5.0",
+ "http",
"http-body",
"httparse",
"httpdate",
@@ -3836,37 +3053,17 @@ dependencies = [
[[package]]
name = "hyper-rustls"
-version = "0.27.7"
+version = "0.27.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58"
+checksum = "33ca68d021ef39cf6463ab54c1d0f5daf03377b70561305bb89a8f83aab66e0f"
dependencies = [
- "http 1.5.0",
+ "http",
"hyper",
"hyper-util",
"rustls",
- "rustls-native-certs",
- "rustls-pki-types",
- "rustls-platform-verifier 0.6.1",
"tokio",
"tokio-rustls",
"tower-service",
- "webpki-roots 1.0.3",
-]
-
-[[package]]
-name = "hyper-tls"
-version = "0.6.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0"
-dependencies = [
- "bytes",
- "http-body-util",
- "hyper",
- "hyper-util",
- "native-tls",
- "tokio",
- "tokio-native-tls",
- "tower-service",
]
[[package]]
@@ -3879,26 +3076,24 @@ dependencies = [
"bytes",
"futures-channel",
"futures-util",
- "http 1.5.0",
+ "http",
"http-body",
"hyper",
"ipnet",
"libc",
"percent-encoding",
"pin-project-lite",
- "socket2 0.6.0",
- "system-configuration 0.7.0",
+ "socket2",
"tokio",
"tower-service",
"tracing",
- "windows-registry",
]
[[package]]
name = "iana-time-zone"
-version = "0.1.63"
+version = "0.1.65"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b0c919e5debc312ad217002b8048a17b7d83f80703865bbfcfebb0458b0b27d8"
+checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470"
dependencies = [
"android_system_properties",
"core-foundation-sys",
@@ -3906,7 +3101,7 @@ dependencies = [
"js-sys",
"log",
"wasm-bindgen",
- "windows-core 0.61.2",
+ "windows-core 0.62.2",
]
[[package]]
@@ -3930,12 +3125,13 @@ dependencies = [
[[package]]
name = "icu_collections"
-version = "2.0.0"
+version = "2.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "200072f5d0e3614556f94a9930d5dc3e0662a652823904c3a75dc3b0af7fee47"
+checksum = "fa68d21081c4a05d5a901a1c62add574c77048b6a1c67be3b50ce0b60d4ca513"
dependencies = [
"displaydoc",
"potential_utf",
+ "utf8_iter",
"yoke",
"zerofrom",
"zerovec",
@@ -3943,9 +3139,9 @@ dependencies = [
[[package]]
name = "icu_locale_core"
-version = "2.0.0"
+version = "2.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0cde2700ccaed3872079a65fb1a78f6c0a36c91570f28755dda67bc8f7d9f00a"
+checksum = "d56e28588da92eee5c3201a6eff33fabdd49b62269c8938d4ff050ce4d900deb"
dependencies = [
"displaydoc",
"litemap",
@@ -3956,11 +3152,10 @@ dependencies = [
[[package]]
name = "icu_normalizer"
-version = "2.0.0"
+version = "2.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "436880e8e18df4d7bbc06d58432329d6458cc84531f7ac5f024e93deadb37979"
+checksum = "12f9cf5f235641ed274641dd81c3f28d870e276763d0797aeeab72317b1c646f"
dependencies = [
- "displaydoc",
"icu_collections",
"icu_normalizer_data",
"icu_properties",
@@ -3971,42 +3166,39 @@ dependencies = [
[[package]]
name = "icu_normalizer_data"
-version = "2.0.0"
+version = "2.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3"
+checksum = "1563da1ed3e0b3bf3d74c9b85917ac9c56464d2f57242270c09c9e752f8021a0"
[[package]]
name = "icu_properties"
-version = "2.0.1"
+version = "2.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "016c619c1eeb94efb86809b015c58f479963de65bdb6253345c1a1276f22e32b"
+checksum = "7e7ca276ad3145661a65914e6daf131ca5120cd3dcee8f8f3214b8875184a148"
dependencies = [
"displaydoc",
"icu_collections",
"icu_locale_core",
"icu_properties_data",
"icu_provider",
- "potential_utf",
"zerotrie",
"zerovec",
]
[[package]]
name = "icu_properties_data"
-version = "2.0.1"
+version = "2.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "298459143998310acd25ffe6810ed544932242d3f07083eee1084d83a71bd632"
+checksum = "e590f038c1464a96894fd6d10127e90a8be4509f56ff7ecef851b15cee0b7caa"
[[package]]
name = "icu_provider"
-version = "2.0.0"
+version = "2.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "03c80da27b5f4187909049ee2d72f276f0d9f99a42c306bd0131ecfe04d8e5af"
+checksum = "d27bbb9d3abbefac45d55f647c9de1d44aafcd1186eb91879afef17c396c3e73"
dependencies = [
"displaydoc",
"icu_locale_core",
- "stable_deref_trait",
- "tinystr",
"writeable",
"yoke",
"zerofrom",
@@ -4021,14 +3213,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
[[package]]
-name = "idna"
-version = "0.4.0"
+name = "identity-hash"
+version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c"
-dependencies = [
- "unicode-bidi",
- "unicode-normalization",
-]
+checksum = "dfdd7caa900436d8f13b2346fe10257e0c05c1f1f9e351f4f5d57c03bd5f45da"
[[package]]
name = "idna"
@@ -4043,9 +3231,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",
@@ -4053,45 +3241,24 @@ dependencies = [
[[package]]
name = "igd-next"
-version = "0.16.2"
+version = "0.17.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "516893339c97f6011282d5825ac94fc1c7aad5cad26bdc2d0cee068c0bf97f97"
+checksum = "de7238d487a9aff61f81b5ab41c0a841532a115a398b5fa92a2fadd0885e2581"
dependencies = [
- "async-trait",
"attohttpc",
"bytes",
"futures",
- "http 1.5.0",
+ "http",
"http-body-util",
"hyper",
"hyper-util",
"log",
- "rand 0.9.5",
+ "rand 0.10.2",
"tokio",
"url",
"xmltree",
]
-[[package]]
-name = "implicit-clone"
-version = "0.5.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "88e4c5423e5b38b6f175b42561a08f6ddbc8ed3a3275f48eb350ba2dfe9a6b60"
-dependencies = [
- "implicit-clone-derive",
- "indexmap 2.12.0",
-]
-
-[[package]]
-name = "implicit-clone-derive"
-version = "0.1.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "699c1b6d335e63d0ba5c1e1c7f647371ce989c3bcbe1f7ed2b85fa56e3bd1a21"
-dependencies = [
- "quote",
- "syn 2.0.106",
-]
-
[[package]]
name = "indexmap"
version = "1.9.3"
@@ -4105,29 +3272,16 @@ dependencies = [
[[package]]
name = "indexmap"
-version = "2.12.0"
+version = "2.14.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6717a8d2a5a929a1a2eb43a12812498ed141a0bcfb7e8f7844fbdbe4303bba9f"
+checksum = "cc4e190f5d26ca7051642629da2c52fc03bde85a03197c99408dcd291734c855"
dependencies = [
"equivalent",
- "hashbrown 0.16.0",
+ "hashbrown 0.17.1",
"serde",
"serde_core",
]
-[[package]]
-name = "indicatif"
-version = "0.17.11"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "183b3088984b400f4cfac3620d5e076c84da5364016b4f49473de574b2586235"
-dependencies = [
- "console",
- "number_prefix",
- "portable-atomic",
- "unicode-width",
- "web-time",
-]
-
[[package]]
name = "infer"
version = "0.19.0"
@@ -4139,114 +3293,93 @@ dependencies = [
[[package]]
name = "inout"
-version = "0.2.1"
+version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c7357b6e7aa75618c7864ebd0634b115a7218b0615f4cb1df33ac3eca23943d4"
+checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01"
dependencies = [
- "hybrid-array",
+ "generic-array",
]
[[package]]
-name = "instant"
-version = "0.1.13"
+name = "inout"
+version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222"
+checksum = "4250ce6452e92010fdf7268ccc5d14faa80bb12fc741938534c58f16804e03c7"
dependencies = [
- "cfg-if",
- "js-sys",
- "wasm-bindgen",
- "web-sys",
+ "hybrid-array",
]
[[package]]
-name = "instant-acme"
-version = "0.8.5"
+name = "ipconfig"
+version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9f05ad37c421b962354c358d347d4a6130151df9407978372d3ad7f0c8f71a64"
+checksum = "4d40460c0ce33d6ce4b0630ad68ff63d6661961c48b6dba35e5a4d81cfb48222"
dependencies = [
- "async-trait",
- "base64 0.22.1",
- "bytes",
- "http 1.5.0",
- "http-body",
- "http-body-util",
- "httpdate",
- "hyper",
- "hyper-rustls",
- "hyper-util",
- "rcgen",
- "ring",
- "rustls",
- "rustls-pki-types",
- "serde",
- "serde_json",
- "thiserror 2.0.20",
- "tokio",
+ "socket2",
+ "widestring",
+ "windows-registry",
+ "windows-result 0.4.1",
+ "windows-sys 0.61.2",
]
[[package]]
-name = "ipconfig"
-version = "0.3.2"
+name = "ipld-core"
+version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b58db92f96b720de98181bbbe63c831e87005ab460c1bf306eb2622b4707997f"
+checksum = "090f624976d72f0b0bb71b86d58dc16c15e069193067cb3a3a09d655246cbbda"
dependencies = [
- "socket2 0.5.10",
- "widestring",
- "windows-sys 0.48.0",
- "winreg 0.50.0",
+ "cid",
+ "serde",
+ "serde_bytes",
]
[[package]]
name = "ipnet"
-version = "2.11.0"
+version = "2.12.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130"
+checksum = "791930b43c0d5973160d90a8f3894509f2b273430f5c5c73b668636d0287c5c0"
[[package]]
name = "iroh"
-version = "0.95.1"
+version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2374ba3cdaac152dc6ada92d971f7328e6408286faab3b7350842b2ebbed4789"
+checksum = "b2f8d1cfffc83efe39a1031aab423ce09cb8048071baba550508931e9a81ce46"
dependencies = [
- "aead",
"backon",
+ "blake3",
"bytes",
"cfg_aliases",
- "crypto_box",
+ "ctutils",
"data-encoding",
"derive_more",
"ed25519-dalek",
"futures-util",
- "getrandom 0.3.4",
- "hickory-resolver",
- "http 1.5.0",
- "igd-next",
- "instant",
+ "getrandom 0.4.3",
+ "http",
+ "ipnet",
"iroh-base",
+ "iroh-dns",
"iroh-metrics",
- "iroh-quinn",
- "iroh-quinn-proto",
- "iroh-quinn-udp",
"iroh-relay",
"n0-error",
"n0-future",
"n0-watcher",
- "netdev",
"netwatch",
+ "noq",
+ "noq-proto",
+ "noq-udp",
+ "papaya",
"pin-project",
- "pkarr",
- "pkcs8 0.11.0-rc.7",
+ "portable-atomic",
"portmapper",
- "rand 0.9.5",
- "reqwest 0.12.28",
+ "rand 0.10.2",
+ "reqwest",
+ "rustc-hash",
"rustls",
"rustls-pki-types",
- "rustls-platform-verifier 0.5.3",
- "rustls-webpki",
"serde",
"smallvec",
"strum",
- "swarm-discovery",
"time",
"tokio",
"tokio-stream",
@@ -4254,144 +3387,130 @@ dependencies = [
"tracing",
"url",
"wasm-bindgen-futures",
- "webpki-roots 1.0.3",
- "z32",
]
[[package]]
name = "iroh-base"
-version = "0.95.1"
+version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "25a8c5fb1cc65589f0d7ab44269a76f615a8c4458356952c9b0ef1c93ea45ff8"
+checksum = "ffd1efd1aaecd68d4d1b0727a30c5811f43fb822843e48f65f6e5db3b7256cc9"
dependencies = [
"curve25519-dalek",
"data-encoding",
+ "data-encoding-macro",
"derive_more",
"ed25519-dalek",
+ "getrandom 0.4.3",
"n0-error",
- "rand_core 0.9.3",
+ "rand 0.10.2",
"serde",
"url",
"zeroize",
- "zeroize_derive",
]
[[package]]
-name = "iroh-metrics"
-version = "0.37.0"
+name = "iroh-dns"
+version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "79e3381da7c93c12d353230c74bba26131d1c8bf3a4d8af0fec041546454582e"
+checksum = "80276761b56e904e26ea71d0863beef0bb8d5ab6b639cbd1338e4b615209e3a1"
dependencies = [
- "iroh-metrics-derive",
- "itoa",
+ "arc-swap",
+ "cfg_aliases",
+ "derive_more",
+ "iroh-base",
+ "n0-dns-resolver",
"n0-error",
- "postcard",
- "ryu",
- "serde",
+ "n0-future",
+ "portable-atomic",
+ "rand 0.10.2",
+ "rustls",
+ "simple-dns",
+ "strum",
+ "tokio",
"tracing",
+ "url",
]
[[package]]
-name = "iroh-metrics-derive"
-version = "0.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d4e12bd0763fd16062f5cc5e8db15dd52d26e75a8af4c7fb57ccee3589b344b8"
-dependencies = [
- "heck 0.5.0",
- "proc-macro2",
- "quote",
- "syn 2.0.106",
-]
-
-[[package]]
-name = "iroh-quinn"
-version = "0.14.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0cde160ebee7aabede6ae887460cd303c8b809054224815addf1469d54a6fcf7"
-dependencies = [
- "bytes",
- "cfg_aliases",
- "iroh-quinn-proto",
- "iroh-quinn-udp",
- "pin-project-lite",
- "rustc-hash",
- "rustls",
- "socket2 0.5.10",
- "thiserror 2.0.20",
+name = "iroh-mdns-address-lookup"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7c1f941695731bc3999d8c13d7e94d50e229427da81ac957eec3818264f17559"
+dependencies = [
+ "data-encoding",
+ "derive_more",
+ "futures-util",
+ "iroh",
+ "iroh-base",
+ "n0-error",
+ "n0-future",
+ "n0-watcher",
+ "swarm-discovery",
"tokio",
+ "tokio-stream",
"tracing",
- "web-time",
]
[[package]]
-name = "iroh-quinn-proto"
-version = "0.13.0"
+name = "iroh-metrics"
+version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "929d5d8fa77d5c304d3ee7cae9aede31f13908bd049f9de8c7c0094ad6f7c535"
+checksum = "291065721ad7c477b972e581bbc528df031dc8eb5e39fe1ff3300ae5dfb157ef"
dependencies = [
- "bytes",
- "getrandom 0.2.16",
- "rand 0.8.8",
- "ring",
- "rustc-hash",
- "rustls",
- "rustls-pki-types",
- "slab",
- "thiserror 2.0.20",
- "tinyvec",
+ "iroh-metrics-derive",
+ "itoa",
+ "n0-error",
+ "portable-atomic",
+ "ryu",
+ "serde",
"tracing",
- "web-time",
]
[[package]]
-name = "iroh-quinn-udp"
-version = "0.5.7"
+name = "iroh-metrics-derive"
+version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c53afaa1049f7c83ea1331f5ebb9e6ebc5fdd69c468b7a22dd598b02c9bcc973"
+checksum = "1ae5f0c4405d1fbc9fb16ff422ca40620e93dc36c30ecaba0c2aee3992b7bd48"
dependencies = [
- "cfg_aliases",
- "libc",
- "once_cell",
- "socket2 0.5.10",
- "tracing",
- "windows-sys 0.59.0",
+ "heck 0.5.0",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.119",
]
[[package]]
name = "iroh-relay"
-version = "0.95.1"
+version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "43fbdf2aeffa7d6ede1a31f6570866c2199b1cee96a0b563994623795d1bac2c"
+checksum = "beb2294a9749d6a25fd7cd8bcf0fccd932f20716d4f967d85d3f23c7135ae6a2"
dependencies = [
"blake3",
"bytes",
"cfg_aliases",
"data-encoding",
"derive_more",
- "getrandom 0.3.4",
- "hickory-resolver",
- "http 1.5.0",
+ "getrandom 0.4.3",
+ "http",
"http-body-util",
"hyper",
"hyper-util",
"iroh-base",
+ "iroh-dns",
"iroh-metrics",
- "iroh-quinn",
- "iroh-quinn-proto",
- "lru 0.16.2",
+ "lru 0.18.4",
"n0-error",
"n0-future",
+ "noq",
+ "noq-proto",
"num_enum",
"pin-project",
- "pkarr",
"postcard",
- "rand 0.9.5",
- "reqwest 0.12.28",
+ "rand 0.10.2",
+ "reqwest",
"rustls",
"rustls-pki-types",
"serde",
"serde_bytes",
- "sha1 0.11.0-rc.2",
"strum",
"tokio",
"tokio-rustls",
@@ -4399,36 +3518,10 @@ dependencies = [
"tokio-websockets",
"tracing",
"url",
- "webpki-roots 1.0.3",
+ "webpki-roots 1.0.9",
"ws_stream_wasm",
- "z32",
-]
-
-[[package]]
-name = "is-docker"
-version = "0.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "928bae27f42bc99b60d9ac7334e3a21d10ad8f1835a4e12ec3ec0464765ed1b3"
-dependencies = [
- "once_cell",
-]
-
-[[package]]
-name = "is-wsl"
-version = "0.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "173609498df190136aa7dea1a91db051746d339e18476eed5ca40521f02d7aa5"
-dependencies = [
- "is-docker",
- "once_cell",
]
-[[package]]
-name = "is_terminal_polyfill"
-version = "1.70.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
-
[[package]]
name = "itertools"
version = "0.14.0"
@@ -4440,9 +3533,9 @@ dependencies = [
[[package]]
name = "itoa"
-version = "1.0.15"
+version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
+checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682"
[[package]]
name = "javascriptcore-rs"
@@ -4467,6 +3560,60 @@ dependencies = [
"system-deps",
]
+[[package]]
+name = "jiff"
+version = "0.2.37"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0ab1baf72f08796de0260609515130699b890ac25f30e610ad894bc5856cafdb"
+dependencies = [
+ "defmt",
+ "jiff-core",
+ "jiff-static",
+ "jiff-tzdb-platform",
+ "log",
+ "portable-atomic",
+ "portable-atomic-util",
+ "serde_core",
+ "windows-link 0.2.1",
+]
+
+[[package]]
+name = "jiff-core"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5e52fe76043ccecc9005d2305ebaadf7d7fc0cc89ca6baa10a94d6bc68c7128c"
+dependencies = [
+ "defmt",
+ "log",
+]
+
+[[package]]
+name = "jiff-static"
+version = "0.2.37"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "378268a1116ad67ae6228701118ac9f491d78fda38a40a1f1a9e1348de6f7212"
+dependencies = [
+ "jiff-core",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.119",
+]
+
+[[package]]
+name = "jiff-tzdb"
+version = "0.1.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "142bd39932ad231f10513df9ab62661fead8719872150b7ad02a2df79f4e141e"
+
+[[package]]
+name = "jiff-tzdb-platform"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "875a5a69ac2bab1a891711cf5eccbec1ce0341ea805560dcd90b7a2e925132e8"
+dependencies = [
+ "jiff-tzdb",
+]
+
[[package]]
name = "jni"
version = "0.21.1"
@@ -4476,36 +3623,89 @@ 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.20",
+ "walkdir",
+ "windows-link 0.2.1",
+]
+
+[[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 = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130"
+checksum = "c6377a88cb3910bee9b0fa88d4f42e1d2da8e79915598f65fb0c7ee14c878af2"
+dependencies = [
+ "jni-sys-macros",
+]
+
+[[package]]
+name = "jni-sys-macros"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "38c0b942f458fe50cdac086d2f946512305e5631e720728f2a61aabcd47a6264"
+dependencies = [
+ "quote",
+ "syn 2.0.119",
+]
[[package]]
name = "jobserver"
-version = "0.1.34"
+version = "0.1.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33"
+checksum = "1c00acbd29eabad4a2392fa0e921c874934dbbf4194312ad20f04a0ed67a3cb3"
dependencies = [
- "getrandom 0.3.4",
+ "getrandom 0.4.3",
"libc",
]
[[package]]
name = "js-sys"
-version = "0.3.78"
+version = "0.3.105"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0c0b063578492ceec17683ef2f8c5e89121fbd0b172cbc280635ab7567db2738"
+checksum = "ce57d20d1ea864ce2ac172ab472d409214f4fd359f0b2a2775abdf522e2af99e"
dependencies = [
- "once_cell",
+ "cfg-if",
+ "futures-util",
"wasm-bindgen",
]
@@ -4521,17 +3721,6 @@ dependencies = [
"thiserror 1.0.69",
]
-[[package]]
-name = "json5"
-version = "0.4.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "96b0db21af676c1ce64250b5f40f3ce2cf27e4e47cb91ed91eb6fe9350b430c1"
-dependencies = [
- "pest",
- "pest_derive",
- "serde",
-]
-
[[package]]
name = "jsonptr"
version = "0.6.3"
@@ -4543,18 +3732,17 @@ dependencies = [
]
[[package]]
-name = "jsonwebtoken"
-version = "9.3.1"
+name = "k256"
+version = "0.13.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5a87cc7a48537badeae96744432de36f4be2b4a34a05a5ef32e9dd8a1c169dde"
+checksum = "f6e3919bbaa2945715f0bb6d3934a173d1e9a59ac23767fbaaef277265a7411b"
dependencies = [
- "base64 0.22.1",
- "js-sys",
- "pem 3.0.5",
- "ring",
- "serde",
- "serde_json",
- "simple_asn1",
+ "cfg-if",
+ "ecdsa 0.16.9",
+ "elliptic-curve 0.13.8",
+ "once_cell",
+ "sha2 0.10.9",
+ "signature 2.2.0",
]
[[package]]
@@ -4563,7 +3751,7 @@ version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b750dcadc39a09dbadd74e118f6dd6598df77fa01df0cfcdc52c28dece74528a"
dependencies = [
- "bitflags 2.9.4",
+ "bitflags 2.13.2",
"serde",
"unicode-segmentation",
]
@@ -4573,9 +3761,6 @@ name = "lazy_static"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
-dependencies = [
- "spin 0.9.8",
-]
[[package]]
name = "libappindicator"
@@ -4603,9 +3788,9 @@ dependencies = [
[[package]]
name = "libc"
-version = "0.2.182"
+version = "0.2.189"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6800badb6cb2082ffd7b6a67e6125bb39f18782f793520caee8cb8846be06112"
+checksum = "3eaf3ede3fee6db1a4c2ee091bf8a8b4dccdc6d17f656fb07896ee72867612f2"
[[package]]
name = "libdbus-sys"
@@ -4626,40 +3811,15 @@ dependencies = [
"winapi",
]
-[[package]]
-name = "libm"
-version = "0.2.15"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de"
-
[[package]]
name = "libredox"
-version = "0.1.9"
+version = "0.1.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "391290121bad3d37fbddad76d8f5d1c1c314cfc646d143d7e07a3086ddff0ce3"
+checksum = "6480ccc157a1389bb2e4891b24751b0f798ba640d22386f23143fbcc89da195a"
dependencies = [
- "bitflags 2.9.4",
"libc",
- "redox_syscall",
-]
-
-[[package]]
-name = "libsqlite3-sys"
-version = "0.30.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2e99fb7a497b1e3339bc746195567ed8d3e24945ecd636e3619d20b9de9e9149"
-dependencies = [
- "cc",
- "pkg-config",
- "vcpkg",
]
-[[package]]
-name = "linked-hash-map"
-version = "0.5.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f"
-
[[package]]
name = "linux-raw-sys"
version = "0.12.1"
@@ -4668,31 +3828,96 @@ checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53"
[[package]]
name = "litemap"
-version = "0.8.0"
+version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956"
+checksum = "47d9d19d1d6efa0109d2f65ff4c85cddd50bd572e5a00127ab10987290bcefae"
[[package]]
name = "litrs"
-version = "0.4.2"
+version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f5e54036fe321fd421e10d732f155734c4e4afd610dd556d9a82833ab3ee0bed"
+checksum = "11d3d7f243d5c5a8b9bb5d6dd2b1602c0cb0b9db1621bafc7ed66e35ff9fe092"
[[package]]
name = "lock_api"
-version = "0.4.13"
+version = "0.4.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765"
+checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965"
dependencies = [
- "autocfg",
"scopeguard",
]
[[package]]
name = "log"
-version = "0.4.28"
+version = "0.4.34"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f9f8bd3e56ce4dfc153cf470fffbfa98c7620958b312ca5c3a4b8d5181fd13c6"
+
+[[package]]
+name = "logos"
+version = "0.15.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ff472f899b4ec2d99161c51f60ff7075eeb3097069a36050d8037a6325eb8154"
+dependencies = [
+ "logos-derive 0.15.1",
+]
+
+[[package]]
+name = "logos"
+version = "0.16.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432"
+checksum = "eb2c55a318a87600ea870ff8c2012148b44bf18b74fad48d0f835c38c7d07c5f"
+dependencies = [
+ "logos-derive 0.16.1",
+]
+
+[[package]]
+name = "logos-codegen"
+version = "0.15.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "192a3a2b90b0c05b27a0b2c43eecdb7c415e29243acc3f89cc8247a5b693045c"
+dependencies = [
+ "beef",
+ "fnv",
+ "lazy_static",
+ "proc-macro2",
+ "quote",
+ "regex-syntax",
+ "rustc_version",
+ "syn 2.0.119",
+]
+
+[[package]]
+name = "logos-codegen"
+version = "0.16.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "58b3ffaa284e1350d017a57d04ada118c4583cf260c8fb01e0fe28a2e9cf8970"
+dependencies = [
+ "fnv",
+ "proc-macro2",
+ "quote",
+ "regex-automata",
+ "regex-syntax",
+ "syn 2.0.119",
+]
+
+[[package]]
+name = "logos-derive"
+version = "0.15.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "605d9697bcd5ef3a42d38efc51541aa3d6a4a25f7ab6d1ed0da5ac632a26b470"
+dependencies = [
+ "logos-codegen 0.15.1",
+]
+
+[[package]]
+name = "logos-derive"
+version = "0.16.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "52d3a9855747c17eaf4383823f135220716ab49bea5fbea7dd42cc9a92f8aa31"
+dependencies = [
+ "logos-codegen 0.16.1",
+]
[[package]]
name = "loom"
@@ -4709,50 +3934,69 @@ dependencies = [
[[package]]
name = "lru"
-version = "0.13.0"
+version = "0.16.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "227748d55f2f0ab4735d87fd623798cb6b664512fe979705f829c9f81c934465"
+checksum = "7f66e8d5d03f609abc3a39e6f08e4164ebf1447a732906d39eb9b99b7919ef39"
[[package]]
name = "lru"
-version = "0.16.2"
+version = "0.18.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "96051b46fc183dc9cd4a223960ef37b9af631b55191852a8274bfef064cda20f"
+checksum = "ff9840bcc50b71349309900da0ce7279aa336ae71d73250b07998932c7d97c25"
dependencies = [
- "hashbrown 0.16.0",
+ "hashbrown 0.17.1",
]
[[package]]
-name = "lru-cache"
-version = "0.1.2"
+name = "lru-slab"
+version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "31e24f1ad8321ca0e8a1e0ac13f23cb668e6f5466c2c57319f6a5cf1cc8e3b1c"
-dependencies = [
- "linked-hash-map",
-]
+checksum = "4050469837a6ff301cd14c1f8f24f88549e6d548f24f64e2148eb0f72cebc51f"
[[package]]
-name = "lru-slab"
-version = "0.1.2"
+name = "mac-addr"
+version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154"
+checksum = "d3d25b0e0b648a86960ac23b7ad4abb9717601dec6f66c165f5b037f3f03065f"
[[package]]
name = "macro_rules_attribute"
-version = "0.2.2"
+version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "65049d7923698040cd0b1ddcced9b0eb14dd22c5f86ae59c3740eab64a676520"
+checksum = "b3ae8f6d608c795738406608304d30a2dfbdc8e58e44f7ba43236da5208ded3c"
dependencies = [
"macro_rules_attribute-proc_macro",
- "paste",
+ "pastey",
+]
+
+[[package]]
+name = "macro_rules_attribute-proc_macro"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fc04a4c58212d57930a24bf47d3fa87485264a3a054e9c10e042eb373573ad3c"
+
+[[package]]
+name = "mainline"
+version = "7.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6dfad9601b9117218868271c05403853593d4817e7abeab5c95e11eee16382bb"
+dependencies = [
+ "crc",
+ "document-features",
+ "dyn-clone",
+ "ed25519-dalek",
+ "flume",
+ "futures-lite",
+ "getrandom 0.4.3",
+ "lru 0.16.4",
+ "serde",
+ "serde_bencode",
+ "serde_bytes",
+ "sha1_smol",
+ "thiserror 2.0.20",
+ "tracing",
]
-[[package]]
-name = "macro_rules_attribute-proc_macro"
-version = "0.2.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "670fdfda89751bc4a84ac13eaa63e205cf0fd22b4c9a5fbfa085b63c1f1d3a30"
-
[[package]]
name = "markup5ever"
version = "0.38.0"
@@ -4764,6 +4008,17 @@ dependencies = [
"web_atoms",
]
+[[package]]
+name = "match-lookup"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "549e39695cc0b640f3cb378053832db3d2133422d49e8dcae5c866a2aaf1f730"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.119",
+]
+
[[package]]
name = "matchers"
version = "0.2.0"
@@ -4773,42 +4028,17 @@ dependencies = [
"regex-automata",
]
-[[package]]
-name = "matchit"
-version = "0.7.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94"
-
[[package]]
name = "matchit"
version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "47e1ffaa40ddd1f3ed91f717a33c8c0ee23fff369e3aa8772b9605cc1d22f4c3"
-[[package]]
-name = "md-5"
-version = "0.10.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf"
-dependencies = [
- "cfg-if",
- "digest 0.10.7",
-]
-
[[package]]
name = "memchr"
-version = "2.7.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0"
-
-[[package]]
-name = "memmap2"
-version = "0.9.8"
+version = "2.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "843a98750cd611cc2965a8213b53b43e715f13c37a9e096c6408e69990961db7"
-dependencies = [
- "libc",
-]
+checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98"
[[package]]
name = "memoffset"
@@ -4820,49 +4050,32 @@ dependencies = [
]
[[package]]
-name = "mime"
-version = "0.3.17"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
-
-[[package]]
-name = "mime_guess"
-version = "2.0.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e"
-dependencies = [
- "mime",
- "unicase",
-]
-
-[[package]]
-name = "minicov"
-version = "0.3.7"
+name = "miette"
+version = "7.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f27fe9f1cc3c22e1687f9446c2083c4c5fc7f0bcf1c7a86bdbded14985895b4b"
+checksum = "5f98efec8807c63c752b5bd61f862c165c115b0a35685bdcfd9238c7aeb592b7"
dependencies = [
- "cc",
- "walkdir",
+ "cfg-if",
+ "miette-derive",
+ "unicode-width",
]
[[package]]
-name = "minijinja"
-version = "2.12.0"
+name = "miette-derive"
+version = "7.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a9f264d75233323f4b7d2f03aefe8a990690cdebfbfe26ea86bcbaec5e9ac990"
+checksum = "db5b29714e950dbb20d5e6f74f9dcec4edbcc1067bb7f8ed198c097b8c1a818b"
dependencies = [
- "serde",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.119",
]
[[package]]
-name = "minijinja-contrib"
-version = "2.12.0"
+name = "mime"
+version = "0.3.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "182ba1438db4679ddfa03792c183bdc2b9ce26b58e7d41a749e59b06497cf136"
-dependencies = [
- "minijinja",
- "serde",
-]
+checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
[[package]]
name = "minimal-lexical"
@@ -4881,124 +4094,142 @@ dependencies = [
]
[[package]]
-name = "mio"
-version = "1.0.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c"
-dependencies = [
- "libc",
- "wasi",
- "windows-sys 0.59.0",
-]
-
-[[package]]
-name = "mockall"
-version = "0.15.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1a6ceddfe3ce334925e96bf420fdb2dcee5bed6c632a168ece622676dadeaf8a"
-dependencies = [
- "cfg-if",
- "downcast",
- "fragile",
- "mockall_derive",
- "predicates",
- "predicates-tree",
-]
-
-[[package]]
-name = "mockall_derive"
-version = "0.15.0"
+name = "miniz_oxide"
+version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9cfe16fbe8a314aeec0b861ac24e60b1e123e97634bab045475b9d6a18416fd8"
+checksum = "b63fbc4a50860e98e7b2aa7804ded1db5cbc3aff9193adaff57a6931bf7c4b4c"
dependencies = [
- "cfg-if",
- "proc-macro2",
- "quote",
- "syn 2.0.106",
+ "adler2",
+ "simd-adler32",
]
[[package]]
-name = "moka"
-version = "0.12.10"
+name = "mio"
+version = "1.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a9321642ca94a4282428e6ea4af8cc2ca4eac48ac7a6a4ea8f33f76d0ce70926"
+checksum = "4b18443e9c262bfe8fa82f51666e2642c53393f7e5c27b3e1aeab922cff5b9d8"
dependencies = [
- "crossbeam-channel",
- "crossbeam-epoch",
- "crossbeam-utils",
- "loom",
- "parking_lot",
- "portable-atomic",
- "rustc_version",
- "smallvec",
- "tagptr",
- "thiserror 1.0.69",
- "uuid",
+ "libc",
+ "wasi",
+ "windows-sys 0.61.2",
]
[[package]]
name = "monostate"
-version = "0.1.14"
+version = "0.1.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "aafe1be9d0c75642e3e50fedc7ecadf1ef1cbce6eb66462153fc44245343fbee"
+checksum = "3341a273f6c9d5bef1908f17b7267bbab0e95c9bf69a0d4dcf8e9e1b2c76ef67"
dependencies = [
"monostate-impl",
"serde",
+ "serde_core",
]
[[package]]
name = "monostate-impl"
-version = "0.1.14"
+version = "0.1.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c402a4092d5e204f32c9e155431046831fa712637043c58cb73bc6bc6c9663b5"
+checksum = "e4db6d5580af57bf992f59068d4ea26fd518574ff48d7639b255a36f9de6e7e9"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.106",
+ "syn 2.0.119",
]
[[package]]
name = "muda"
-version = "0.19.1"
+version = "0.19.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0ae8844f63b5b118e334e205585b8c5c17b984121dbdb179d44aeb087ffad3cb"
+checksum = "1dd04e60bc0b07438a6771710ee1698f98f6ebbc7f89b61264af1563b8aeb878"
dependencies = [
"crossbeam-channel",
"dpi",
"gtk",
"keyboard-types",
- "objc2 0.6.4",
+ "objc2",
"objc2-app-kit",
"objc2-core-foundation",
- "objc2-foundation 0.3.1",
+ "objc2-foundation",
"once_cell",
"png 0.18.1",
"serde",
"thiserror 2.0.20",
- "windows-sys 0.61.0",
+ "windows-sys 0.61.2",
]
[[package]]
-name = "n0-error"
+name = "multibase"
+version = "0.9.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7e0e4a371cbf1dfd666b658ba137763edb23c45beb43cfe369b5593cd6b437b6"
+dependencies = [
+ "base-x",
+ "base256emoji",
+ "base45",
+ "data-encoding",
+ "data-encoding-macro",
+]
+
+[[package]]
+name = "multihash"
+version = "0.19.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "577c63b00ad74d57e8c9aa870b5fccebf2fd64a308a5aee9f1bb88e4aea19447"
+dependencies = [
+ "serde",
+ "unsigned-varint",
+]
+
+[[package]]
+name = "multimap"
+version = "0.10.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1d87ecb2933e8aeadb3e3a02b828fed80a7528047e68b4f424523a0981a3a084"
+
+[[package]]
+name = "n0-dns-resolver"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8a4839a11b62f1fdd75be912ee20634053c734c2240e867ded41c7f50822c549"
+checksum = "535c99c9a786bee714155d2ee4fc2477405c2c43536e1bc6a51de09a0d1448f7"
dependencies = [
"derive_more",
+ "ipconfig",
+ "jni 0.22.4",
+ "lru 0.18.4",
+ "n0-error",
+ "n0-future",
+ "ndk-context",
+ "rand 0.10.2",
+ "reqwest",
+ "rustc-hash",
+ "rustls",
+ "simple-dns",
+ "system-configuration",
+ "tokio",
+ "tokio-rustls",
+ "tracing",
+ "webpki-roots 1.0.9",
+]
+
+[[package]]
+name = "n0-error"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "26c59ea174675ce6bc196878851e5049e11b8b1f9af3ba87e4d6df8d828bb001"
+dependencies = [
"n0-error-macros",
"spez",
]
[[package]]
name = "n0-error-macros"
-version = "0.1.0"
+version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6ed2a7e5ca3cb5729d4a162d7bcab5b338bed299a2fee8457568d7e0a747ed89"
+checksum = "4412346410d6616f3668c40e53c298e5320c7b856f7a960e5914e442601be79f"
dependencies = [
- "heck 0.5.0",
"proc-macro2",
"quote",
- "syn 2.0.106",
+ "syn 2.0.119",
]
[[package]]
@@ -5024,40 +4255,23 @@ dependencies = [
[[package]]
name = "n0-watcher"
-version = "0.5.0"
+version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "38acf13c1ddafc60eb7316d52213467f8ccb70b6f02b65e7d97f7799b1f50be4"
+checksum = "bbc618745ad0b7414b149d0517ad8b5573b2fb4d4e2717add3d2446ce1fdd826"
dependencies = [
"derive_more",
"n0-error",
"n0-future",
]
-[[package]]
-name = "native-tls"
-version = "0.2.14"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "87de3442987e9dbec73158d5c715e7ad9072fda936bb03d19d7fa10e00520f0e"
-dependencies = [
- "libc",
- "log",
- "openssl",
- "openssl-probe",
- "openssl-sys",
- "schannel",
- "security-framework 2.11.1",
- "security-framework-sys",
- "tempfile",
-]
-
[[package]]
name = "ndk"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3f42e7bbe13d351b6bead8286a43aac9534b82bd3cc43e47037f012ebfd62d4"
dependencies = [
- "bitflags 2.9.4",
- "jni-sys",
+ "bitflags 2.13.2",
+ "jni-sys 0.3.1",
"log",
"ndk-sys",
"num_enum",
@@ -5065,104 +4279,179 @@ dependencies = [
"thiserror 1.0.69",
]
+[[package]]
+name = "ndk-context"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "27b02d87554356db9e9a873add8782d4ea6e3e58ea071a9adb9a2e8ddb884a8b"
+
[[package]]
name = "ndk-sys"
version = "0.6.0+11769913"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ee6cda3051665f1fb8d9e08fc35c96d5a244fb1be711a03b71118828afc9a873"
dependencies = [
- "jni-sys",
+ "jni-sys 0.3.1",
]
[[package]]
name = "netdev"
-version = "0.38.2"
+version = "0.45.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "67ab878b4c90faf36dab10ea51d48c69ae9019bcca47c048a7c9b273d5d7a823"
+checksum = "096c44b66a9b09b99b4dd36b1c295ff3a492039ccecaf55466bd6ddcdba59968"
dependencies = [
- "dlopen2 0.5.0",
+ "block2",
+ "dispatch2",
+ "dlopen2",
"ipnet",
+ "jni 0.21.1",
"libc",
- "netlink-packet-core",
- "netlink-packet-route",
- "netlink-sys",
+ "mac-addr",
+ "ndk-context",
+ "netlink-packet-core 0.8.2",
+ "netlink-packet-route 0.31.0",
+ "netlink-sys 0.8.8",
+ "objc2",
+ "objc2-core-foundation",
+ "objc2-core-wlan",
+ "objc2-foundation",
+ "objc2-system-configuration",
"once_cell",
- "system-configuration 0.6.1",
- "windows-sys 0.59.0",
+ "plist",
+ "windows-sys 0.61.2",
+]
+
+[[package]]
+name = "netdev"
+version = "0.46.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c3c52c2584961c68f5a6e3356797344061f818c93b8acc9cd6d7e284795e563e"
+dependencies = [
+ "block2",
+ "dispatch2",
+ "dlopen2",
+ "ipnet",
+ "jni 0.21.1",
+ "libc",
+ "mac-addr",
+ "ndk-context",
+ "netlink-packet-core 0.9.0",
+ "netlink-packet-route 0.33.0",
+ "netlink-sys 0.9.0",
+ "objc2-core-foundation",
+ "objc2-system-configuration",
+ "once_cell",
+ "plist",
+ "windows-sys 0.61.2",
]
[[package]]
name = "netlink-packet-core"
-version = "0.8.1"
+version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3463cbb78394cb0141e2c926b93fc2197e473394b761986eca3b9da2c63ae0f4"
+checksum = "b897d7bd4f0af82e68d40d0344cf37e97f9c97ddf74a098de3e4da05e96ca395"
dependencies = [
"paste",
]
+[[package]]
+name = "netlink-packet-core"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2d6e2daf9a8c2e21302714706860a0e6be02e03d17294ecc66b354ea7d4059dd"
+
[[package]]
name = "netlink-packet-route"
-version = "0.25.1"
+version = "0.31.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e2288fcb784eb3defd5fb16f4c4160d5f477de192eac730f43e1d11c24d9a007"
+dependencies = [
+ "bitflags 2.13.2",
+ "libc",
+ "log",
+ "netlink-packet-core 0.8.2",
+]
+
+[[package]]
+name = "netlink-packet-route"
+version = "0.33.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3ec2f5b6839be2a19d7fa5aab5bc444380f6311c2b693551cb80f45caaa7b5ef"
+checksum = "59d48ffc8b73a506e1ff0878528c72668f2bfbc3d875b6be890a96be5d0d5576"
dependencies = [
- "bitflags 2.9.4",
+ "bitflags 2.13.2",
"libc",
"log",
- "netlink-packet-core",
+ "netlink-packet-core 0.9.0",
+ "zerocopy",
]
[[package]]
name = "netlink-proto"
-version = "0.12.0"
+version = "0.12.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b65d130ee111430e47eed7896ea43ca693c387f097dd97376bffafbf25812128"
+checksum = "93af8261786086024cd5e96e0a991dd65ced07bbf7c233a487bbc96b971d5539"
dependencies = [
"bytes",
- "futures",
+ "futures-channel",
+ "futures-util",
"log",
- "netlink-packet-core",
- "netlink-sys",
+ "netlink-packet-core 0.8.2",
+ "netlink-sys 0.8.8",
"thiserror 2.0.20",
]
[[package]]
name = "netlink-sys"
-version = "0.8.7"
+version = "0.8.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "16c903aa70590cb93691bf97a767c8d1d6122d2cc9070433deb3bbf36ce8bd23"
+checksum = "cd6c30ed10fa69cc491d491b85cc971f6bdeb8e7367b7cde2ee6cc878d583fae"
dependencies = [
"bytes",
- "futures",
+ "futures-util",
"libc",
"log",
"tokio",
]
+[[package]]
+name = "netlink-sys"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c99d38e00b420df49e940fe0826e667c3dad82ac68eb4c2bbf754c1c14a83a10"
+dependencies = [
+ "bytes",
+ "libc",
+ "log",
+]
+
[[package]]
name = "netwatch"
-version = "0.12.0"
+version = "0.19.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "26f2acd376ef48b6c326abf3ba23c449e0cb8aa5c2511d189dd8a8a3bfac889b"
+checksum = "39da9cad5f23aa43401f09497d3b280e51b5feba115d9ffbf38ca35d6ff95e96"
dependencies = [
"atomic-waker",
"bytes",
"cfg_aliases",
"derive_more",
- "iroh-quinn-udp",
+ "ipnet",
"js-sys",
"libc",
"n0-error",
"n0-future",
"n0-watcher",
- "netdev",
- "netlink-packet-core",
- "netlink-packet-route",
+ "netdev 0.45.1",
+ "netdev 0.46.3",
+ "netlink-packet-core 0.8.2",
+ "netlink-packet-route 0.31.0",
"netlink-proto",
- "netlink-sys",
+ "netlink-sys 0.8.8",
+ "noq-udp",
+ "objc2-core-foundation",
+ "objc2-system-configuration",
"pin-project-lite",
"serde",
- "socket2 0.6.0",
+ "socket2",
"time",
"tokio",
"tokio-util",
@@ -5180,111 +4469,118 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086"
[[package]]
-name = "nix"
-version = "0.30.1"
+name = "nom"
+version = "7.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "74523f3a35e05aba87a1d978330aef40f67b0304ac79c1c00b294c9830543db6"
+checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
dependencies = [
- "bitflags 2.9.4",
- "cfg-if",
+ "memchr",
+ "minimal-lexical",
+]
+
+[[package]]
+name = "noq"
+version = "1.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b78be567e796cfa74bb9bdc4117790af2d505eb887019cf8803244353eb09d89"
+dependencies = [
+ "bytes",
"cfg_aliases",
- "libc",
- "memoffset",
+ "derive_more",
+ "noq-proto",
+ "noq-udp",
+ "pin-project-lite",
+ "rustc-hash",
+ "rustls",
+ "socket2",
+ "thiserror 2.0.20",
+ "tokio",
+ "tokio-stream",
+ "tracing",
+ "web-time",
]
[[package]]
-name = "nom"
-version = "7.1.3"
+name = "noq-proto"
+version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
+checksum = "7c1e5b6fe668491eca022f745a0a9402585626c73a7b839b3424ace15d6a9c8f"
dependencies = [
- "memchr",
- "minimal-lexical",
+ "aes-gcm",
+ "bytes",
+ "derive_more",
+ "enum-assoc",
+ "getrandom 0.4.3",
+ "identity-hash",
+ "lru-slab",
+ "rand 0.10.2",
+ "rand_pcg",
+ "ring",
+ "rustc-hash",
+ "rustls",
+ "rustls-pki-types",
+ "slab",
+ "sorted-index-buffer",
+ "thiserror 2.0.20",
+ "tinyvec",
+ "tracing",
+ "web-time",
]
[[package]]
-name = "ntimestamp"
-version = "1.0.0"
+name = "noq-udp"
+version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c50f94c405726d3e0095e89e72f75ce7f6587b94a8bd8dc8054b73f65c0fd68c"
+checksum = "4dc50afea61aff926e150a36c31f06094608848e114a3fe667d76ec233163b1c"
dependencies = [
- "base32",
- "document-features",
- "getrandom 0.2.16",
- "httpdate",
- "js-sys",
- "once_cell",
- "serde",
+ "cfg_aliases",
+ "libc",
+ "socket2",
+ "tracing",
+ "windows-sys 0.61.2",
]
[[package]]
name = "nu-ansi-term"
-version = "0.50.1"
+version = "0.50.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d4a28e057d01f97e61255210fcff094d74ed0466038633e95017f5beb68e4399"
+checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5"
dependencies = [
- "windows-sys 0.52.0",
+ "windows-sys 0.61.2",
]
[[package]]
name = "num-bigint"
-version = "0.4.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9"
-dependencies = [
- "num-integer",
- "num-traits",
-]
-
-[[package]]
-name = "num-bigint-dig"
-version = "0.8.4"
+version = "0.4.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dc84195820f291c7697304f3cbdadd1cb7199c0efc917ff5eafd71225c136151"
+checksum = "c89e69e7e0f03bea5ef08013795c25018e101932225a656383bd384495ecc367"
dependencies = [
- "byteorder",
- "lazy_static",
- "libm",
"num-integer",
- "num-iter",
- "num-traits",
- "rand 0.8.8",
- "smallvec",
- "zeroize",
-]
-
-[[package]]
-name = "num-complex"
-version = "0.4.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495"
-dependencies = [
- "bytemuck",
"num-traits",
]
[[package]]
name = "num-conv"
-version = "0.1.0"
+version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9"
+checksum = "521739c6d2bac4aa25192232afe6841231376b2b26d4d9fae5ecf8ca5772e441"
[[package]]
name = "num-integer"
-version = "0.1.46"
+version = "0.1.47"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f"
+checksum = "7ce2d95d4b3734dc35aa2f45e1aa22cd416814592a4f9d9205e11affd5b8e10b"
dependencies = [
"num-traits",
]
[[package]]
-name = "num-iter"
-version = "0.1.45"
+name = "num-rational"
+version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf"
+checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824"
dependencies = [
- "autocfg",
+ "num-bigint",
"num-integer",
"num-traits",
]
@@ -5296,7 +4592,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
dependencies = [
"autocfg",
- "libm",
]
[[package]]
@@ -5311,9 +4606,9 @@ dependencies = [
[[package]]
name = "num_enum"
-version = "0.7.4"
+version = "0.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a973b4e44ce6cad84ce69d797acf9a044532e4184c4f267913d1b546a0727b7a"
+checksum = "5d0bca838442ec211fa11de3a8b0e0e8f3a4522575b5c4c06ed722e005036f26"
dependencies = [
"num_enum_derive",
"rustversion",
@@ -5321,36 +4616,14 @@ dependencies = [
[[package]]
name = "num_enum_derive"
-version = "0.7.4"
+version = "0.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "77e878c846a8abae00dd069496dbe8751b16ac1c3d6bd2a7283a938e8228f90d"
+checksum = "680998035259dcfcafe653688bf2aa6d3e2dc05e98be6ab46afb089dc84f1df8"
dependencies = [
- "proc-macro-crate 3.3.0",
+ "proc-macro-crate 3.5.0",
"proc-macro2",
"quote",
- "syn 2.0.106",
-]
-
-[[package]]
-name = "number_prefix"
-version = "0.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3"
-
-[[package]]
-name = "objc-sys"
-version = "0.3.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cdb91bdd390c7ce1a8607f35f3ca7151b65afc0ff5ff3b34fa350f7d7c7e4310"
-
-[[package]]
-name = "objc2"
-version = "0.5.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "46a785d4eeff09c14c487497c162e92766fbb3e4059a71840cecc03d9a50b804"
-dependencies = [
- "objc-sys",
- "objc2-encode",
+ "syn 2.0.119",
]
[[package]]
@@ -5365,80 +4638,108 @@ dependencies = [
[[package]]
name = "objc2-app-kit"
-version = "0.3.1"
+version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e6f29f568bec459b0ddff777cec4fe3fd8666d82d5a40ebd0ff7e66134f89bcc"
+checksum = "d49e936b501e5c5bf01fda3a9452ff86dc3ea98ad5f283e1455153142d97518c"
dependencies = [
- "bitflags 2.9.4",
- "block2 0.6.1",
- "objc2 0.6.4",
+ "bitflags 2.13.2",
+ "block2",
+ "objc2",
"objc2-core-foundation",
- "objc2-foundation 0.3.1",
+ "objc2-foundation",
]
[[package]]
name = "objc2-cloud-kit"
-version = "0.3.1"
+version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "17614fdcd9b411e6ff1117dfb1d0150f908ba83a7df81b1f118005fe0a8ea15d"
+checksum = "73ad74d880bb43877038da939b7427bba67e9dd42004a18b809ba7d87cee241c"
dependencies = [
- "bitflags 2.9.4",
- "objc2 0.6.4",
- "objc2-foundation 0.3.1",
+ "bitflags 2.13.2",
+ "objc2",
+ "objc2-foundation",
]
[[package]]
name = "objc2-core-data"
-version = "0.3.1"
+version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "291fbbf7d29287518e8686417cf7239c74700fd4b607623140a7d4a3c834329d"
+checksum = "0b402a653efbb5e82ce4df10683b6b28027616a2715e90009947d50b8dd298fa"
dependencies = [
- "objc2 0.6.4",
- "objc2-foundation 0.3.1",
+ "objc2",
+ "objc2-foundation",
]
[[package]]
name = "objc2-core-foundation"
-version = "0.3.1"
+version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1c10c2894a6fed806ade6027bcd50662746363a9589d3ec9d9bef30a4e4bc166"
+checksum = "2a180dd8642fa45cdb7dd721cd4c11b1cadd4929ce112ebd8b9f5803cc79d536"
dependencies = [
- "bitflags 2.9.4",
+ "bitflags 2.13.2",
+ "block2",
"dispatch2",
- "objc2 0.6.4",
+ "libc",
+ "objc2",
]
[[package]]
name = "objc2-core-graphics"
-version = "0.3.1"
+version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "989c6c68c13021b5c2d6b71456ebb0f9dc78d752e86a98da7c716f4f9470f5a4"
+checksum = "e022c9d066895efa1345f8e33e584b9f958da2fd4cd116792e15e07e4720a807"
dependencies = [
- "bitflags 2.9.4",
+ "bitflags 2.13.2",
"dispatch2",
- "objc2 0.6.4",
+ "objc2",
"objc2-core-foundation",
"objc2-io-surface",
]
[[package]]
name = "objc2-core-image"
-version = "0.3.1"
+version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "79b3dc0cc4386b6ccf21c157591b34a7f44c8e75b064f85502901ab2188c007e"
+checksum = "e5d563b38d2b97209f8e861173de434bd0214cf020e3423a52624cd1d989f006"
dependencies = [
- "objc2 0.6.4",
- "objc2-foundation 0.3.1",
+ "objc2",
+ "objc2-foundation",
]
[[package]]
name = "objc2-core-location"
-version = "0.3.1"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ca347214e24bc973fc025fd0d36ebb179ff30536ed1f80252706db19ee452009"
+dependencies = [
+ "objc2",
+ "objc2-foundation",
+]
+
+[[package]]
+name = "objc2-core-text"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0cde0dfb48d25d2b4862161a4d5fcc0e3c24367869ad306b0c9ec0073bfed92d"
+dependencies = [
+ "bitflags 2.13.2",
+ "objc2",
+ "objc2-core-foundation",
+ "objc2-core-graphics",
+]
+
+[[package]]
+name = "objc2-core-wlan"
+version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ac0f75792558aa9d618443bbb5db7426a7a0b6fddf96903f86ef9ad02e135740"
+checksum = "c71e34919aba0d701380d911702455038a8a3587467fe0141d6a71501e7ffe48"
dependencies = [
- "objc2 0.6.4",
- "objc2-foundation 0.3.1",
+ "bitflags 2.13.2",
+ "objc2",
+ "objc2-core-foundation",
+ "objc2-foundation",
+ "objc2-security",
+ "objc2-security-foundation",
]
[[package]]
@@ -5458,136 +4759,118 @@ dependencies = [
[[package]]
name = "objc2-foundation"
-version = "0.2.2"
+version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0ee638a5da3799329310ad4cfa62fbf045d5f56e3ef5ba4149e7452dcf89d5a8"
+checksum = "e3e0adef53c21f888deb4fa59fc59f7eb17404926ee8a6f59f5df0fd7f9f3272"
dependencies = [
- "bitflags 2.9.4",
- "block2 0.5.1",
+ "bitflags 2.13.2",
+ "block2",
"libc",
- "objc2 0.5.2",
+ "objc2",
+ "objc2-core-foundation",
]
[[package]]
-name = "objc2-foundation"
-version = "0.3.1"
+name = "objc2-io-surface"
+version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "900831247d2fe1a09a683278e5384cfb8c80c79fe6b166f9d14bfdde0ea1b03c"
+checksum = "180788110936d59bab6bd83b6060ffdfffb3b922ba1396b312ae795e1de9d81d"
dependencies = [
- "bitflags 2.9.4",
- "block2 0.6.1",
- "objc2 0.6.4",
+ "bitflags 2.13.2",
+ "objc2",
"objc2-core-foundation",
]
[[package]]
-name = "objc2-io-surface"
-version = "0.3.1"
+name = "objc2-quartz-core"
+version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7282e9ac92529fa3457ce90ebb15f4ecbc383e8338060960760fa2cf75420c3c"
+checksum = "96c1358452b371bf9f104e21ec536d37a650eb10f7ee379fff67d2e08d537f1f"
dependencies = [
- "bitflags 2.9.4",
- "objc2 0.6.4",
+ "bitflags 2.13.2",
+ "objc2",
"objc2-core-foundation",
+ "objc2-foundation",
]
[[package]]
-name = "objc2-metal"
-version = "0.2.2"
+name = "objc2-security"
+version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dd0cba1276f6023976a406a14ffa85e1fdd19df6b0f737b063b95f6c8c7aadd6"
+checksum = "709fe137109bd1e8b5a99390f77a7d8b2961dafc1a1c5db8f2e60329ad6d895a"
dependencies = [
- "bitflags 2.9.4",
- "block2 0.5.1",
- "objc2 0.5.2",
- "objc2-foundation 0.2.2",
+ "bitflags 2.13.2",
+ "objc2",
+ "objc2-core-foundation",
]
[[package]]
-name = "objc2-quartz-core"
-version = "0.2.2"
+name = "objc2-security-foundation"
+version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e42bee7bff906b14b167da2bac5efe6b6a07e6f7c0a21a7308d40c960242dc7a"
+checksum = "ef76382e9cedd18123099f17638715cc3d81dba3637d4c0d39ab69df2ef345a5"
dependencies = [
- "bitflags 2.9.4",
- "block2 0.5.1",
- "objc2 0.5.2",
- "objc2-foundation 0.2.2",
- "objc2-metal",
+ "objc2",
+ "objc2-foundation",
]
[[package]]
-name = "objc2-quartz-core"
-version = "0.3.1"
+name = "objc2-system-configuration"
+version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "90ffb6a0cd5f182dc964334388560b12a57f7b74b3e2dec5e2722aa2dfb2ccd5"
+checksum = "7216bd11cbda54ccabcab84d523dc93b858ec75ecfb3a7d89513fa22464da396"
dependencies = [
- "bitflags 2.9.4",
- "objc2 0.6.4",
+ "bitflags 2.13.2",
+ "dispatch2",
+ "libc",
+ "objc2",
"objc2-core-foundation",
- "objc2-foundation 0.3.1",
+ "objc2-security",
]
[[package]]
name = "objc2-ui-kit"
-version = "0.3.1"
+version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "25b1312ad7bc8a0e92adae17aa10f90aae1fb618832f9b993b022b591027daed"
+checksum = "d87d638e33c06f577498cbcc50491496a3ed4246998a7fbba7ccb98b1e7eab22"
dependencies = [
- "bitflags 2.9.4",
- "block2 0.6.1",
- "objc2 0.6.4",
+ "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-foundation 0.3.1",
- "objc2-quartz-core 0.3.1",
+ "objc2-core-text",
+ "objc2-foundation",
+ "objc2-quartz-core",
"objc2-user-notifications",
]
[[package]]
name = "objc2-user-notifications"
-version = "0.3.1"
+version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2a3f5ec77a81d9e0c5a0b32159b0cb143d7086165e79708351e02bf37dfc65cd"
+checksum = "9df9128cbbfef73cda168416ccf7f837b62737d748333bfe9ab71c245d76613e"
dependencies = [
- "objc2 0.6.4",
- "objc2-foundation 0.3.1",
+ "objc2",
+ "objc2-foundation",
]
[[package]]
name = "objc2-web-kit"
-version = "0.3.1"
+version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "91672909de8b1ce1c2252e95bbee8c1649c9ad9d14b9248b3d7b4c47903c47ad"
+checksum = "b2e5aaab980c433cf470df9d7af96a7b46a9d892d521a2cbbb2f8a4c16751e7f"
dependencies = [
- "bitflags 2.9.4",
- "block2 0.6.1",
- "objc2 0.6.4",
+ "bitflags 2.13.2",
+ "block2",
+ "objc2",
"objc2-app-kit",
"objc2-core-foundation",
- "objc2-foundation 0.3.1",
-]
-
-[[package]]
-name = "oid-registry"
-version = "0.7.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a8d8034d9489cdaf79228eb9f6a3b8d7bb32ba00d6645ebd48eef4077ceb5bd9"
-dependencies = [
- "asn1-rs 0.6.2",
-]
-
-[[package]]
-name = "oid-registry"
-version = "0.8.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "12f40cff3dde1b6087cc5d5f5d4d65712f34016a03ed60e9c08dcc392736b5b7"
-dependencies = [
- "asn1-rs 0.7.1",
+ "objc2-foundation",
]
[[package]]
@@ -5600,19 +4883,13 @@ dependencies = [
"portable-atomic",
]
-[[package]]
-name = "once_cell_polyfill"
-version = "1.70.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad"
-
[[package]]
name = "onig"
-version = "6.5.1"
+version = "6.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "336b9c63443aceef14bea841b899035ae3abe89b7c486aaf4c5bd8aafedac3f0"
+checksum = "0cc3cbf698f9438986c11a880c90a6d04b9de27575afd28bbf45b154b6c709e2"
dependencies = [
- "bitflags 2.9.4",
+ "bitflags 2.13.2",
"libc",
"once_cell",
"onig_sys",
@@ -5620,148 +4897,25 @@ dependencies = [
[[package]]
name = "onig_sys"
-version = "69.9.1"
+version = "69.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c7f86c6eef3d6df15f23bcfb6af487cbd2fed4e5581d58d5bf1f5f8b7f6727dc"
+checksum = "1e68317604e77e53b85896388e1a803c1d21b74c899ec9e5e1112db90735edd7"
dependencies = [
"cc",
"pkg-config",
]
[[package]]
-name = "open"
-version = "5.3.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e2483562e62ea94312f3576a7aca397306df7990b8d89033e18766744377ef95"
-dependencies = [
- "dunce",
- "is-wsl",
- "libc",
- "pathdiff",
-]
-
-[[package]]
-name = "open-hypergraphs"
-version = "0.2.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b5bf4628a77ba91c60f7fc64bc08b80052f9517bcba48ba3aa71f10e7cb1bbe7"
-dependencies = [
- "num-traits",
-]
-
-[[package]]
-name = "openssl"
-version = "0.10.81"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "77823a27f0babb03091cb9ed9ef80af3b39dbc82f97e8fa530374b7dafd87a45"
-dependencies = [
- "bitflags 2.9.4",
- "cfg-if",
- "foreign-types 0.3.2",
- "libc",
- "openssl-macros",
- "openssl-sys",
-]
-
-[[package]]
-name = "openssl-macros"
-version = "0.1.1"
+name = "opaque-debug"
+version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn 2.0.106",
-]
+checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381"
[[package]]
name = "openssl-probe"
-version = "0.1.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e"
-
-[[package]]
-name = "openssl-sys"
-version = "0.9.117"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b47e7e6bb2c38cd930d25a23b40fa52e068c10e85f3e03a7f5ba5aaca5713695"
-dependencies = [
- "cc",
- "libc",
- "pkg-config",
- "vcpkg",
-]
-
-[[package]]
-name = "opentelemetry"
-version = "0.32.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b0142c63252a9e054e68a4c61a5778f7b14f576274d593f8ce883d191a099682"
-dependencies = [
- "futures-core",
- "futures-sink",
- "js-sys",
- "pin-project-lite",
- "thiserror 2.0.20",
-]
-
-[[package]]
-name = "opentelemetry-http"
-version = "0.32.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5683015d09e2df236ef005b17f6f196f0d5f6313c4fa43a7b6a53b52776e4331"
-dependencies = [
- "async-trait",
- "bytes",
- "http 1.5.0",
- "opentelemetry",
- "reqwest 0.13.1",
-]
-
-[[package]]
-name = "opentelemetry-otlp"
-version = "0.32.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9966929966d17620d7c316c643ba62631826e10021409357772d5eea84f62c35"
-dependencies = [
- "http 1.5.0",
- "opentelemetry",
- "opentelemetry-http",
- "opentelemetry-proto",
- "opentelemetry_sdk",
- "prost",
- "reqwest 0.13.1",
- "thiserror 2.0.20",
-]
-
-[[package]]
-name = "opentelemetry-proto"
-version = "0.32.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "56d658ba1faf63f7b9c492cfbe6e0ec365440a16132d3270c1065f7b33f1b638"
-dependencies = [
- "opentelemetry",
- "opentelemetry_sdk",
- "prost",
-]
-
-[[package]]
-name = "opentelemetry_sdk"
-version = "0.32.1"
+version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9b59f80e1ac4d5ff7a2db8fb6c80badb7f0f3f858211fba08dd9aaec750894f9"
-dependencies = [
- "futures-channel",
- "futures-executor",
- "futures-util",
- "opentelemetry",
- "percent-encoding",
- "portable-atomic",
- "rand 0.9.5",
- "thiserror 2.0.20",
- "tokio",
- "tokio-stream",
-]
+checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe"
[[package]]
name = "option-ext"
@@ -5770,23 +4924,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d"
[[package]]
-name = "ordered-multimap"
-version = "0.7.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "49203cdcae0030493bad186b28da2fa25645fa276a51b6fec8010d281e02ef79"
-dependencies = [
- "dlv-list",
- "hashbrown 0.14.5",
-]
-
-[[package]]
-name = "ordered-stream"
-version = "0.2.0"
+name = "p256"
+version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9aa2b01e1d916879f73a53d01d1d6cee68adbb31d6d9177a8cfce093cced1d50"
+checksum = "d2c9239b2dbc807adbbe147e8cf72ea7450c3a0aabe62cb8e75ff4ec22e1f72a"
dependencies = [
- "futures-core",
- "pin-project-lite",
+ "ecdsa 0.17.0",
+ "elliptic-curve 0.14.1",
+ "primefield",
+ "primeorder",
+ "sha2 0.11.0",
]
[[package]]
@@ -5814,6 +4961,16 @@ dependencies = [
"system-deps",
]
+[[package]]
+name = "papaya"
+version = "0.2.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "da2442474a9404698c42509b8967f437249dbc7b50493e83020333d3943ec0ae"
+dependencies = [
+ "equivalent",
+ "seize",
+]
+
[[package]]
name = "parking"
version = "2.2.1"
@@ -5822,9 +4979,9 @@ checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba"
[[package]]
name = "parking_lot"
-version = "0.12.4"
+version = "0.12.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "70d58bf43669b5795d1576d0641cfb6fbb2057bf629506267a92807158584a13"
+checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a"
dependencies = [
"lock_api",
"parking_lot_core",
@@ -5832,15 +4989,15 @@ dependencies = [
[[package]]
name = "parking_lot_core"
-version = "0.9.11"
+version = "0.9.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5"
+checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1"
dependencies = [
"cfg-if",
"libc",
"redox_syscall",
"smallvec",
- "windows-targets 0.52.6",
+ "windows-link 0.2.1",
]
[[package]]
@@ -5850,51 +5007,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
[[package]]
-name = "pastey"
-version = "0.1.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "35fb2e5f958ec131621fdd531e9fc186ed768cbe395337403ae56c17a74c68ec"
-
-[[package]]
-name = "pathdiff"
-version = "0.2.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "df94ce210e5bc13cb6651479fa48d14f601d9858cfe0467f43ae157023b938d3"
-
-[[package]]
-name = "pem"
-version = "3.0.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "38af38e8470ac9dee3ce1bae1af9c1671fffc44ddfd8bd1d0a3445bf349a8ef3"
-dependencies = [
- "base64 0.22.1",
- "serde",
-]
-
-[[package]]
-name = "pem"
-version = "4.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d354a98a3d1251555de99e8fdd8afda05573c31b82f59063a7b0a29b5527f120"
-dependencies = [
- "base64 0.23.1",
- "serde_core",
-]
-
-[[package]]
-name = "pem-rfc7468"
-version = "0.7.0"
+name = "pastey"
+version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412"
-dependencies = [
- "base64ct",
-]
+checksum = "2ee67f1008b1ba2321834326597b8e186293b049a023cdef258527550b9935b4"
[[package]]
name = "pem-rfc7468"
-version = "1.0.0-rc.3"
+version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a8e58fab693c712c0d4e88f8eb3087b6521d060bcaf76aeb20cb192d809115ba"
+checksum = "a6305423e0e7738146434843d1694d621cce767262b2a86910beab705e4493d9"
dependencies = [
"base64ct",
]
@@ -5906,47 +5028,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220"
[[package]]
-name = "pest"
-version = "2.8.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1db05f56d34358a8b1066f67cbb203ee3e7ed2ba674a6263a1d5ec6db2204323"
-dependencies = [
- "memchr",
- "thiserror 2.0.20",
- "ucd-trie",
-]
-
-[[package]]
-name = "pest_derive"
-version = "2.8.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bb056d9e8ea77922845ec74a1c4e8fb17e7c218cc4fc11a15c5d25e189aa40bc"
-dependencies = [
- "pest",
- "pest_generator",
-]
-
-[[package]]
-name = "pest_generator"
-version = "2.8.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "87e404e638f781eb3202dc82db6760c8ae8a1eeef7fb3fa8264b2ef280504966"
-dependencies = [
- "pest",
- "pest_meta",
- "proc-macro2",
- "quote",
- "syn 2.0.106",
-]
-
-[[package]]
-name = "pest_meta"
-version = "2.8.1"
+name = "petgraph"
+version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "edd1101f170f5903fde0914f899bb503d9ff5271d7ba76bbb70bea63690cc0d5"
+checksum = "8701b58ea97060d5e5b155d383a69952a60943f0e6dfe30b04c287beb0b27455"
dependencies = [
- "pest",
- "sha2 0.10.9",
+ "fixedbitset",
+ "hashbrown 0.15.5",
+ "indexmap 2.14.2",
]
[[package]]
@@ -6000,7 +5089,7 @@ dependencies = [
"phf_shared",
"proc-macro2",
"quote",
- "syn 2.0.106",
+ "syn 2.0.119",
]
[[package]]
@@ -6014,93 +5103,29 @@ dependencies = [
[[package]]
name = "pin-project"
-version = "1.1.10"
+version = "1.1.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "677f1add503faace112b9f1373e43e9e054bfdd22ff1a63c1bc485eaec6a6a8a"
+checksum = "2466b2336ed02bcdca6b294417127b90ec92038d1d5c4fbeac971a922e0e0924"
dependencies = [
"pin-project-internal",
]
[[package]]
name = "pin-project-internal"
-version = "1.1.10"
+version = "1.1.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861"
+checksum = "c96395f0a926bc13b1c17622aaddda1ecb55d49c8f1bf9777e4d877800a43f8b"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.106",
+ "syn 2.0.119",
]
[[package]]
name = "pin-project-lite"
-version = "0.2.16"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b"
-
-[[package]]
-name = "pinned"
-version = "0.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a829027bd95e54cfe13e3e258a1ae7b645960553fb82b75ff852c29688ee595b"
-dependencies = [
- "futures",
- "rustversion",
- "thiserror 1.0.69",
-]
-
-[[package]]
-name = "piper"
-version = "0.2.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "96c8c490f422ef9a4efd2cb5b42b76c8613d7e7dfc1caf667b8a3350a5acc066"
-dependencies = [
- "atomic-waker",
- "fastrand",
- "futures-io",
-]
-
-[[package]]
-name = "pkarr"
-version = "5.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "792c1328860f6874e90e3b387b4929819cc7783a6bd5a4728e918706eb436a48"
-dependencies = [
- "async-compat",
- "base32",
- "bytes",
- "cfg_aliases",
- "document-features",
- "dyn-clone",
- "ed25519-dalek",
- "futures-buffered",
- "futures-lite",
- "getrandom 0.3.4",
- "log",
- "lru 0.13.0",
- "ntimestamp",
- "reqwest 0.12.28",
- "self_cell",
- "serde",
- "sha1_smol",
- "simple-dns",
- "thiserror 2.0.20",
- "tokio",
- "tracing",
- "url",
- "wasm-bindgen-futures",
-]
-
-[[package]]
-name = "pkcs1"
-version = "0.7.5"
+version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c8ffb9f10fa047879315e6625af03c164b16962a5368d724ed16323b68ace47f"
-dependencies = [
- "der 0.7.10",
- "pkcs8 0.10.2",
- "spki 0.7.3",
-]
+checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd"
[[package]]
name = "pkcs8"
@@ -6114,28 +5139,28 @@ dependencies = [
[[package]]
name = "pkcs8"
-version = "0.11.0-rc.7"
+version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "93eac55f10aceed84769df670ea4a32d2ffad7399400d41ee1c13b1cd8e1b478"
+checksum = "451913da69c775a56034ea8d9003d27ee8948e12443eae7c038ba100a4f21cb7"
dependencies = [
- "der 0.8.0-rc.9",
- "spki 0.8.0-rc.4",
+ "der 0.8.2",
+ "spki 0.8.0",
]
[[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.7.4"
+version = "1.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3af6b589e163c5a788fab00ce0c0366f6efbb9959c2f9874b224936af7fce7e1"
+checksum = "2896bade328c13f7042a297ea5ac5b0951f6cf989dea5f32c2fd98da398195cb"
dependencies = [
- "base64 0.22.1",
- "indexmap 2.12.0",
+ "base64 0.23.1",
+ "indexmap 2.14.2",
"quick-xml",
"serde",
"time",
@@ -6151,7 +5176,7 @@ dependencies = [
"crc32fast",
"fdeflate",
"flate2",
- "miniz_oxide",
+ "miniz_oxide 0.8.9",
]
[[package]]
@@ -6160,65 +5185,74 @@ version = "0.18.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "60769b8b31b2a9f263dae2776c37b1b28ae246943cf719eb6946a1db05128a61"
dependencies = [
- "bitflags 2.9.4",
+ "bitflags 2.13.2",
"crc32fast",
"fdeflate",
"flate2",
- "miniz_oxide",
+ "miniz_oxide 0.8.9",
]
[[package]]
-name = "polling"
-version = "3.10.0"
+name = "poly1305"
+version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b5bd19146350fe804f7cb2669c851c03d69da628803dab0d98018142aaa5d829"
+checksum = "6e2d0073b297041425c7c3df6eb4792d598a15323fe63346852b092eca02904c"
dependencies = [
- "cfg-if",
- "concurrent-queue",
- "hermit-abi",
- "pin-project-lite",
- "rustix",
- "windows-sys 0.60.2",
+ "cpufeatures 0.3.1",
+ "universal-hash 0.6.1",
]
[[package]]
-name = "poly1305"
-version = "0.9.0-rc.2"
+name = "polyval"
+version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fb78a635f75d76d856374961deecf61031c0b6f928c83dc9c0924ab6c019c298"
+checksum = "9d1fe60d06143b2430aa532c94cfe9e29783047f06c0d7fd359a9a51b729fa25"
dependencies = [
- "cpufeatures",
- "universal-hash",
+ "cfg-if",
+ "cpufeatures 0.2.17",
+ "opaque-debug",
+ "universal-hash 0.5.1",
]
[[package]]
name = "portable-atomic"
-version = "1.11.1"
+version = "1.15.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "05c8b63e8d9609db387f0324918f81d68fe27748f084ef092fb35954d0539a85"
+dependencies = [
+ "serde",
+]
+
+[[package]]
+name = "portable-atomic-util"
+version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483"
+checksum = "10ab3eb7f3becc3a1cbc4f2c6f20267996cfc1a6467a873763411b136a122715"
+dependencies = [
+ "portable-atomic",
+]
[[package]]
name = "portmapper"
-version = "0.12.0"
+version = "0.19.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7b575f975dcf03e258b0c7ab3f81497d7124f508884c37da66a7314aa2a8d467"
+checksum = "ca97242f016e090a25330613bc2382aab65eb22f9149dbe84d8f8e711d49a530"
dependencies = [
"base64 0.22.1",
"bytes",
"derive_more",
- "futures-lite",
- "futures-util",
"hyper-util",
"igd-next",
"iroh-metrics",
"libc",
"n0-error",
+ "n0-future",
"netwatch",
"num_enum",
- "rand 0.9.5",
+ "rand 0.10.2",
"serde",
"smallvec",
- "socket2 0.6.0",
+ "socket2",
"time",
"tokio",
"tokio-util",
@@ -6236,7 +5270,6 @@ dependencies = [
"cobs",
"embedded-io 0.4.0",
"embedded-io 0.6.1",
- "heapless",
"postcard-derive",
"serde",
]
@@ -6249,14 +5282,14 @@ checksum = "e0232bd009a197ceec9cc881ba46f727fcd8060a2d8d6a9dde7a69030a6fe2bb"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.106",
+ "syn 2.0.119",
]
[[package]]
name = "potential_utf"
-version = "0.1.3"
+version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "84df19adbe5b5a0782edcab45899906947ab039ccf4573713735ee7de1e6b08a"
+checksum = "d83eb9bc6d8e5cf568e7a1101d60ee05e81ed50ea106026f3d18deeb046d7661"
dependencies = [
"zerovec",
]
@@ -6283,39 +5316,40 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c"
[[package]]
-name = "predicates"
-version = "3.1.3"
+name = "prettyplease"
+version = "0.2.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a5d19ee57562043d37e82899fade9a22ebab7be9cef5026b07fda9cdd4293573"
+checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b"
dependencies = [
- "anstyle",
- "predicates-core",
+ "proc-macro2",
+ "syn 2.0.119",
]
[[package]]
-name = "predicates-core"
-version = "1.0.9"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "727e462b119fe9c93fd0eb1429a5f7647394014cf3c04ab2c0350eeb09095ffa"
-
-[[package]]
-name = "predicates-tree"
-version = "1.0.12"
+name = "primefield"
+version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "72dd2d6d381dfb73a193c7fca536518d7caee39fc8503f74e7dc0be0531b425c"
+checksum = "c555a6e4eb7d4e158fcb028c835c3b8642206ddc279b5c6b202ef9a8bdb592f4"
dependencies = [
- "predicates-core",
- "termtree",
+ "crypto-bigint 0.7.5",
+ "crypto-common 0.2.2",
+ "ff 0.14.0",
+ "rand_core 0.10.1",
+ "subtle",
+ "zeroize",
]
[[package]]
-name = "prettyplease"
-version = "0.2.37"
+name = "primeorder"
+version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b"
+checksum = "5c9f42978c78a00e3d68f69fc03e57a234debae69da4020a4fb588fcdcd07b06"
dependencies = [
- "proc-macro2",
- "syn 2.0.106",
+ "elliptic-curve 0.14.1",
+ "once_cell",
+ "primefield",
+ "serdect",
+ "wnaf",
]
[[package]]
@@ -6330,20 +5364,21 @@ dependencies = [
[[package]]
name = "proc-macro-crate"
-version = "2.0.0"
+version = "2.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7e8366a6159044a37876a2b9817124296703c586a5c92e2c53751fa06d8d43e8"
+checksum = "b00f26d3400549137f92511a46ac1cd8ce37cb5598a96d382381458b992a5d24"
dependencies = [
- "toml_edit 0.20.7",
+ "toml_datetime 0.6.3",
+ "toml_edit 0.20.2",
]
[[package]]
name = "proc-macro-crate"
-version = "3.3.0"
+version = "3.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "edce586971a4dfaa28950c6f18ed55e0406c1ab88bbce2c6f6293a7aaba73d35"
+checksum = "e67ba7e9b2b56446f1d419b1d807906278ffa1a658a8a5d8a39dcb1f5a78614f"
dependencies = [
- "toml_edit 0.22.27",
+ "toml_edit 0.25.15+spec-1.1.0",
]
[[package]]
@@ -6379,57 +5414,148 @@ dependencies = [
"unicode-ident",
]
+[[package]]
+name = "prometheus-client"
+version = "0.25.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1784dc11a05f5a8f57c4a62915686be140f24f70301290b997e317241fa9ffc2"
+dependencies = [
+ "dtoa",
+ "itoa",
+ "parking_lot",
+ "prometheus-client-derive-encode",
+]
+
+[[package]]
+name = "prometheus-client-derive-encode"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "01e34894696ff94f64a20c2c373a6440903e9c2789a303d68ec6e6f953f890e4"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 3.0.5",
+]
+
+[[package]]
+name = "proptest"
+version = "1.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4b45fcc2344c680f5025fe57779faef368840d0bd1f42f216291f0dc4ace4744"
+dependencies = [
+ "bitflags 2.13.2",
+ "num-traits",
+ "rand 0.9.5",
+ "rand_chacha 0.9.0",
+ "rand_xorshift",
+ "regex-syntax",
+ "unarray",
+]
+
[[package]]
name = "prost"
-version = "0.14.1"
+version = "0.14.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7231bd9b3d3d33c86b58adbac74b5ec0ad9f496b19d22801d773636feaa95f3d"
+checksum = "528ac67416ff8646872a3c02cad9cc4ee5dc9f9540c9b10771855c95cb2e5ae1"
dependencies = [
"bytes",
"prost-derive",
]
+[[package]]
+name = "prost-build"
+version = "0.14.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "03da047801ff44bb6a4d407d4860c05fd70bb81714e6b2f3812603d5b145b042"
+dependencies = [
+ "heck 0.5.0",
+ "itertools",
+ "log",
+ "multimap",
+ "petgraph",
+ "prettyplease",
+ "prost",
+ "prost-types",
+ "regex",
+ "syn 2.0.119",
+ "tempfile",
+]
+
[[package]]
name = "prost-derive"
-version = "0.14.1"
+version = "0.14.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9120690fafc389a67ba3803df527d0ec9cbbc9cc45e4cc20b332996dfb672425"
+checksum = "b570b25f7617e43d59005d0990ccb79e950a423952cea19671b7a876da390adf"
dependencies = [
"anyhow",
"itertools",
"proc-macro2",
"quote",
- "syn 2.0.106",
+ "syn 2.0.119",
]
[[package]]
-name = "pulp"
-version = "0.21.5"
+name = "prost-reflect"
+version = "0.16.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "96b86df24f0a7ddd5e4b95c94fc9ed8a98f1ca94d3b01bdce2824097e7835907"
+checksum = "01b80ea363c31af2de2b92e3c07ed1156628f7838c4afb4df75ee78a37fedbd1"
dependencies = [
- "bytemuck",
- "cfg-if",
- "libm",
- "num-complex",
- "reborrow",
- "version_check",
+ "logos 0.16.1",
+ "miette",
+ "prost",
+ "prost-types",
+]
+
+[[package]]
+name = "prost-types"
+version = "0.14.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f94967dc7688f3054c7fac87473ffae4cc4c3904800e2d9f5b857246d8963b0a"
+dependencies = [
+ "prost",
+]
+
+[[package]]
+name = "protox"
+version = "0.9.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4f25a07a73c6717f0b9bbbd685918f5df9815f7efba450b83d9c9dea41f0e3a1"
+dependencies = [
+ "bytes",
+ "miette",
+ "prost",
+ "prost-reflect",
+ "prost-types",
+ "protox-parse",
+ "thiserror 2.0.20",
+]
+
+[[package]]
+name = "protox-parse"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "072eee358134396a4643dff81cfff1c255c9fbd3fb296be14bdb6a26f9156366"
+dependencies = [
+ "logos 0.15.1",
+ "miette",
+ "prost-types",
+ "thiserror 2.0.20",
]
[[package]]
name = "quick-xml"
-version = "0.38.3"
+version = "0.42.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "42a232e7487fc2ef313d96dde7948e7a3c05101870d8985e4fd8d26aedd27b89"
+checksum = "41b1177fdf999d2321d3fb46ff47159d9c1fb9ad66a4879f8c50a0b504615e9b"
dependencies = [
"memchr",
]
[[package]]
name = "quinn"
-version = "0.11.9"
+version = "0.11.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b9e20a958963c291dc322d98411f541009df2ced7b5a4f2bd52337638cfccf20"
+checksum = "4051e23e9185c255a7e33ef59cdbca87a22d359052eecd22fc6b901fb37d9d11"
dependencies = [
"bytes",
"cfg_aliases",
@@ -6438,7 +5564,7 @@ dependencies = [
"quinn-udp",
"rustc-hash",
"rustls",
- "socket2 0.6.0",
+ "socket2",
"thiserror 2.0.20",
"tokio",
"tracing",
@@ -6447,14 +5573,16 @@ dependencies = [
[[package]]
name = "quinn-proto"
-version = "0.11.13"
+version = "0.11.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f1906b49b0c3bc04b5fe5d86a77925ae6524a19b816ae38ce1e426255f1d8a31"
+checksum = "a9746dbde176634f4f2f1faf2404e30a31b2bc1e9cafb5329c95d8177a18c9fc"
dependencies = [
+ "aws-lc-rs",
"bytes",
- "getrandom 0.3.4",
+ "getrandom 0.4.3",
"lru-slab",
- "rand 0.9.5",
+ "rand 0.10.2",
+ "rand_pcg",
"ring",
"rustc-hash",
"rustls",
@@ -6468,16 +5596,16 @@ dependencies = [
[[package]]
name = "quinn-udp"
-version = "0.5.14"
+version = "0.5.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "addec6a0dcad8a8d96a771f815f0eaf55f9d1805756410b39f5fa81332574cbd"
+checksum = "35a133f956daabe89a61a685c2649f13d82d5aa4bd5d12d1277e1072a21c0694"
dependencies = [
"cfg_aliases",
"libc",
"once_cell",
- "socket2 0.6.0",
+ "socket2",
"tracing",
- "windows-sys 0.60.2",
+ "windows-sys 0.61.2",
]
[[package]]
@@ -6503,43 +5631,43 @@ checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf"
[[package]]
name = "rand"
-version = "0.8.8"
+version = "0.9.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e058c7de0b26af77780c769414d6257830bb240f3c38477dbc2c16e5f54d6d4c"
+checksum = "b9ef1d0d795eb7d84685bca4f72f3649f064e6641543d3a8c415898726a57b41"
dependencies = [
- "libc",
- "rand_chacha 0.3.1",
- "rand_core 0.6.4",
+ "rand_chacha 0.9.0",
+ "rand_core 0.9.5",
]
[[package]]
name = "rand"
-version = "0.9.5"
+version = "0.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b9ef1d0d795eb7d84685bca4f72f3649f064e6641543d3a8c415898726a57b41"
+checksum = "c7f5fa3a058cd35567ef9bfa5e75732bee0f9e4c55fa90477bef2dfcdbc4be80"
dependencies = [
- "rand_chacha 0.9.0",
- "rand_core 0.9.3",
+ "chacha20",
+ "getrandom 0.4.3",
+ "rand_core 0.10.1",
]
[[package]]
name = "rand_chacha"
-version = "0.3.1"
+version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
+checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb"
dependencies = [
"ppv-lite86",
- "rand_core 0.6.4",
+ "rand_core 0.9.5",
]
[[package]]
name = "rand_chacha"
-version = "0.9.0"
+version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb"
+checksum = "3e6af7f3e25ded52c41df4e0b1af2d047e45896c2f3281792ed68a1c243daedb"
dependencies = [
"ppv-lite86",
- "rand_core 0.9.3",
+ "rand_core 0.10.1",
]
[[package]]
@@ -6548,25 +5676,40 @@ version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
dependencies = [
- "getrandom 0.2.16",
+ "getrandom 0.2.17",
]
[[package]]
name = "rand_core"
-version = "0.9.3"
+version = "0.9.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38"
+checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c"
dependencies = [
"getrandom 0.3.4",
]
[[package]]
-name = "raw-cpuid"
-version = "11.6.0"
+name = "rand_core"
+version = "0.10.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69"
+
+[[package]]
+name = "rand_pcg"
+version = "0.10.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "caa0f4137e1c0a72f4c651489402276c8e8e1cf081f3b0ba156d2cbeef09e86a"
+dependencies = [
+ "rand_core 0.10.1",
+]
+
+[[package]]
+name = "rand_xorshift"
+version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "498cd0dc59d73224351ee52a95fee0f1a617a2eae0e7d9d720cc622c73a54186"
+checksum = "513962919efc330f829edb2535844d1b912b0fbe2ca165d613e4e8788bb05a5a"
dependencies = [
- "bitflags 2.9.4",
+ "rand_core 0.9.5",
]
[[package]]
@@ -6577,9 +5720,9 @@ checksum = "20675572f6f24e9e76ef639bc5552774ed45f1c30e2951e1e99c59888861c539"
[[package]]
name = "rayon"
-version = "1.11.0"
+version = "1.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "368f01d005bf8fd9b1206fb6fa653e6c4a81ceb1466406b81792d87c5677a58f"
+checksum = "fb39b166781f92d482534ef4b4b1b2568f42613b53e5b6c160e24cfbfa30926d"
dependencies = [
"either",
"rayon-core",
@@ -6602,37 +5745,17 @@ version = "1.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91"
dependencies = [
- "crossbeam-deque",
- "crossbeam-utils",
-]
-
-[[package]]
-name = "rcgen"
-version = "0.14.10"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8774e05a7d0de114588e6a28fe7e71694b82614ed569d86d8b389dfbc98b8ad8"
-dependencies = [
- "pem 4.0.0",
- "ring",
- "rustls-pki-types",
- "time",
- "x509-parser 0.18.1",
- "yasna",
-]
-
-[[package]]
-name = "reborrow"
-version = "0.5.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "03251193000f4bd3b042892be858ee50e8b3719f2b08e5833ac4353724632430"
+ "crossbeam-deque",
+ "crossbeam-utils",
+]
[[package]]
name = "redox_syscall"
-version = "0.5.17"
+version = "0.5.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5407465600fb0548f1442edf71dd20683c6ed326200ace4b1ef0763521bb3b77"
+checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d"
dependencies = [
- "bitflags 2.9.4",
+ "bitflags 2.13.2",
]
[[package]]
@@ -6641,36 +5764,36 @@ version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a4e608c6638b9c18977b00b475ac1f28d14e84b27d8d42f70e0bf1e3dec127ac"
dependencies = [
- "getrandom 0.2.16",
+ "getrandom 0.2.17",
"libredox",
"thiserror 2.0.20",
]
[[package]]
name = "ref-cast"
-version = "1.0.24"
+version = "1.0.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4a0ae411dbe946a674d89546582cea4ba2bb8defac896622d6496f14c23ba5cf"
+checksum = "7e440fb4e4b4147295338efb76001ab9e4efc0e5839df2c47fc5ac2381d365c3"
dependencies = [
"ref-cast-impl",
]
[[package]]
name = "ref-cast-impl"
-version = "1.0.24"
+version = "1.0.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1165225c21bff1f3bbce98f5a1f889949bc902d3575308cc7b0de30b4f6d27c7"
+checksum = "92ecd8964f8453721699a1ed72037b0db49ce2f5a5138486ee89bed6f67cdf3a"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.106",
+ "syn 3.0.5",
]
[[package]]
name = "regex"
-version = "1.11.2"
+version = "1.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "23d7fd106d8c02486a8d64e778353d1cffe08ce79ac2e82f540c86d0facf6912"
+checksum = "f020237b6c8eed93db2e2cb53c00c60a8e1bc73da7d073199a1180401450218d"
dependencies = [
"aho-corasick",
"memchr",
@@ -6680,9 +5803,9 @@ dependencies = [
[[package]]
name = "regex-automata"
-version = "0.4.10"
+version = "0.4.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6b9458fa0bfeeac22b5ca447c63aaf45f28439a709ccd244698632f9aa6394d6"
+checksum = "ad8553b9b26413251cbf30e620595c7a41b3887f03da04579c0e6b0d6a06b4b2"
dependencies = [
"aho-corasick",
"memchr",
@@ -6691,103 +5814,70 @@ dependencies = [
[[package]]
name = "regex-syntax"
-version = "0.8.6"
+version = "0.8.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "caf4aa5b0f434c91fe5c7f1ecb6a5ece2130b02ad2a590589dda5146df959001"
+checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4"
[[package]]
name = "reqwest"
-version = "0.12.28"
+version = "0.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "eddd3ca559203180a307f12d114c268abf583f59b03cb906fd0b3ff8646c1147"
+checksum = "04e9018c9d814e5f30cc16a0f03271aeab3571e609612d9fe78c1aa8d11c2f62"
dependencies = [
"base64 0.22.1",
"bytes",
- "encoding_rs",
"futures-core",
"futures-util",
- "h2",
- "http 1.5.0",
+ "http",
"http-body",
"http-body-util",
"hyper",
"hyper-rustls",
- "hyper-tls",
"hyper-util",
"js-sys",
"log",
- "mime",
- "mime_guess",
- "native-tls",
"percent-encoding",
"pin-project-lite",
"quinn",
"rustls",
"rustls-pki-types",
+ "rustls-platform-verifier",
"serde",
"serde_json",
- "serde_urlencoded",
"sync_wrapper",
"tokio",
- "tokio-native-tls",
"tokio-rustls",
"tokio-util",
"tower",
- "tower-http 0.6.11",
+ "tower-http",
"tower-service",
"url",
"wasm-bindgen",
"wasm-bindgen-futures",
"wasm-streams",
"web-sys",
- "webpki-roots 1.0.3",
+ "webpki-roots 1.0.9",
]
[[package]]
-name = "reqwest"
-version = "0.13.1"
+name = "rfc6979"
+version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "04e9018c9d814e5f30cc16a0f03271aeab3571e609612d9fe78c1aa8d11c2f62"
+checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2"
dependencies = [
- "base64 0.22.1",
- "bytes",
- "futures-channel",
- "futures-core",
- "futures-util",
- "http 1.5.0",
- "http-body",
- "http-body-util",
- "hyper",
- "hyper-rustls",
- "hyper-util",
- "js-sys",
- "log",
- "percent-encoding",
- "pin-project-lite",
- "rustls",
- "rustls-pki-types",
- "rustls-platform-verifier 0.6.1",
- "serde",
- "serde_json",
- "sync_wrapper",
- "tokio",
- "tokio-rustls",
- "tokio-util",
- "tower",
- "tower-http 0.6.11",
- "tower-service",
- "url",
- "wasm-bindgen",
- "wasm-bindgen-futures",
- "wasm-streams",
- "web-sys",
+ "hmac 0.12.1",
+ "subtle",
]
[[package]]
-name = "resolv-conf"
-version = "0.7.4"
+name = "rfc6979"
+version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "95325155c684b1c89f7765e30bc1c42e4a6da51ca513615660cb8a62ef9a88e3"
+checksum = "b4a459cddafb3fe76b31fd8f1108007566c40301feb64dc7b54656eb7388172b"
+dependencies = [
+ "crypto-bigint 0.7.5",
+ "hmac 0.13.0",
+]
[[package]]
name = "ring"
@@ -6797,84 +5887,17 @@ checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7"
dependencies = [
"cc",
"cfg-if",
- "getrandom 0.2.16",
+ "getrandom 0.2.17",
"libc",
- "untrusted",
+ "untrusted 0.9.0",
"windows-sys 0.52.0",
]
-[[package]]
-name = "ron"
-version = "0.12.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "81116b9531d61eabc41aeb228e4b6b2435bcca3233b98cf3b3077d4e6e9debb3"
-dependencies = [
- "bitflags 2.9.4",
- "once_cell",
- "serde",
- "serde_derive",
- "typeid",
- "unicode-ident",
-]
-
-[[package]]
-name = "route-recognizer"
-version = "0.3.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "afab94fb28594581f62d981211a9a4d53cc8130bbcbbb89a0440d9b8e81a7746"
-
-[[package]]
-name = "rsa"
-version = "0.9.8"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "78928ac1ed176a5ca1d17e578a1825f3d81ca54cf41053a592584b020cfd691b"
-dependencies = [
- "const-oid 0.9.6",
- "digest 0.10.7",
- "num-bigint-dig",
- "num-integer",
- "num-traits",
- "pkcs1",
- "pkcs8 0.10.2",
- "rand_core 0.6.4",
- "signature 2.2.0",
- "spki 0.7.3",
- "subtle",
- "zeroize",
-]
-
-[[package]]
-name = "rust-ini"
-version = "0.21.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "796e8d2b6696392a43bea58116b667fb4c29727dc5abd27d6acf338bb4f688c7"
-dependencies = [
- "cfg-if",
- "ordered-multimap",
-]
-
-[[package]]
-name = "rust_decimal"
-version = "1.43.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7653272e75dcac41dc199fbea6f5797633994fafd339943c06c9af16bf29cd3a"
-dependencies = [
- "arrayvec",
- "borsh",
- "bytes",
- "num-traits",
- "rand 0.8.8",
- "rand 0.9.5",
- "serde",
- "serde_json",
- "wasm-bindgen",
-]
-
[[package]]
name = "rustc-hash"
-version = "2.1.1"
+version = "2.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d"
+checksum = "6b1e7f9a428571be2dc5bc0505c13fb6bf936822b894ec87abf8a08a4e51742d"
[[package]]
name = "rustc_version"
@@ -6885,33 +5908,24 @@ dependencies = [
"semver",
]
-[[package]]
-name = "rusticata-macros"
-version = "4.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "faf0c4a6ece9950b9abdb62b1cfcf2a68b3b67a10ba445b3bb85be2a293d0632"
-dependencies = [
- "nom",
-]
-
[[package]]
name = "rustix"
version = "1.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190"
dependencies = [
- "bitflags 2.9.4",
+ "bitflags 2.13.2",
"errno",
"libc",
"linux-raw-sys",
- "windows-sys 0.61.0",
+ "windows-sys 0.61.2",
]
[[package]]
name = "rustls"
-version = "0.23.44"
+version = "0.23.45"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6725596c3f2c3a0aef021139e145d4eafe314a6623e4680ca83852b2c67ab2ba"
+checksum = "0d41d731c7d2f962d1ccc364cec258de3c0e93b38c2fb3ba97ac74513048d634"
dependencies = [
"aws-lc-rs",
"log",
@@ -6925,30 +5939,21 @@ dependencies = [
[[package]]
name = "rustls-native-certs"
-version = "0.8.1"
+version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7fcff2dd52b58a8d98a70243663a0d234c4e2b79235637849d15913394a247d3"
+checksum = "dab5152771c58876a2146916e53e35057e1a4dfa2b9df0f0305b07f611fdea4d"
dependencies = [
"openssl-probe",
"rustls-pki-types",
"schannel",
- "security-framework 3.4.0",
-]
-
-[[package]]
-name = "rustls-pemfile"
-version = "2.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50"
-dependencies = [
- "rustls-pki-types",
+ "security-framework",
]
[[package]]
name = "rustls-pki-types"
-version = "1.12.0"
+version = "1.15.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "229a4a4c221013e7e1f1a043678c5cc39fe5171437c88fb47151a21e6f5b5c79"
+checksum = "2f4925028c7eb5d1fcdaf196971378ed9d2c1c4efc7dc5d011256f76c99c0a96"
dependencies = [
"web-time",
"zeroize",
@@ -6956,44 +5961,23 @@ dependencies = [
[[package]]
name = "rustls-platform-verifier"
-version = "0.5.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "19787cda76408ec5404443dc8b31795c87cd8fec49762dc75fa727740d34acc1"
-dependencies = [
- "core-foundation 0.10.1",
- "core-foundation-sys",
- "jni",
- "log",
- "once_cell",
- "rustls",
- "rustls-native-certs",
- "rustls-platform-verifier-android",
- "rustls-webpki",
- "security-framework 3.4.0",
- "security-framework-sys",
- "webpki-root-certs 0.26.11",
- "windows-sys 0.59.0",
-]
-
-[[package]]
-name = "rustls-platform-verifier"
-version = "0.6.1"
+version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "be59af91596cac372a6942530653ad0c3a246cdd491aaa9dcaee47f88d67d5a0"
+checksum = "1d99feebc72bae7ab76ba994bb5e121b8d83d910ca40b36e0921f53becc41784"
dependencies = [
- "core-foundation 0.10.1",
+ "core-foundation",
"core-foundation-sys",
- "jni",
+ "jni 0.21.1",
"log",
"once_cell",
"rustls",
"rustls-native-certs",
"rustls-platform-verifier-android",
"rustls-webpki",
- "security-framework 3.4.0",
+ "security-framework",
"security-framework-sys",
- "webpki-root-certs 1.0.2",
- "windows-sys 0.59.0",
+ "webpki-root-certs",
+ "windows-sys 0.61.2",
]
[[package]]
@@ -7011,40 +5995,20 @@ dependencies = [
"aws-lc-rs",
"ring",
"rustls-pki-types",
- "untrusted",
+ "untrusted 0.9.0",
]
[[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 = "ryu"
-version = "1.0.20"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f"
-
-[[package]]
-name = "safetensors"
-version = "0.6.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "172dd94c5a87b5c79f945c863da53b2ebc7ccef4eca24ac63cca66a41aab2178"
-dependencies = [
- "serde",
- "serde_json",
-]
-
-[[package]]
-name = "salsa20"
-version = "0.11.0-rc.1"
+version = "1.0.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d3ff3b81c8a6e381bc1673768141383f9328048a60edddcfc752a8291a138443"
-dependencies = [
- "cfg-if",
- "cipher",
-]
+checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f"
[[package]]
name = "same-file"
@@ -7057,11 +6021,11 @@ dependencies = [
[[package]]
name = "schannel"
-version = "0.1.28"
+version = "0.1.29"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "891d81b926048e76efe18581bf793546b4c0eaf8448d72be8de2bbee5fd166e1"
+checksum = "91c1b7e4904c873ef0710c1f407dde2e6287de2bebc1bbbf7d430bb7cbffd939"
dependencies = [
- "windows-sys 0.61.0",
+ "windows-sys 0.61.2",
]
[[package]]
@@ -7093,9 +6057,9 @@ dependencies = [
[[package]]
name = "schemars"
-version = "1.0.4"
+version = "1.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "82d20c4491bc164fa2f6c5d44565947a52ad80b9505d8e36f8d54c27c739fcd0"
+checksum = "687274d293b6cdc6e73e0fee520bf2049650090d7164f87672d212a3c530cf4a"
dependencies = [
"dyn-clone",
"ref-cast",
@@ -7112,7 +6076,7 @@ dependencies = [
"proc-macro2",
"quote",
"serde_derive_internals",
- "syn 2.0.106",
+ "syn 2.0.119",
]
[[package]]
@@ -7128,26 +6092,41 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
[[package]]
-name = "security-framework"
-version = "2.11.1"
+name = "sec1"
+version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02"
+checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc"
dependencies = [
- "bitflags 2.9.4",
- "core-foundation 0.9.4",
- "core-foundation-sys",
- "libc",
- "security-framework-sys",
+ "base16ct 0.2.0",
+ "der 0.7.10",
+ "generic-array",
+ "pkcs8 0.10.2",
+ "subtle",
+ "zeroize",
+]
+
+[[package]]
+name = "sec1"
+version = "0.8.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d56d437c2f19203ce5f7122e507831de96f3d2d4d3be5af44a0b0a09d8a80e4d"
+dependencies = [
+ "base16ct 1.0.0",
+ "ctutils",
+ "der 0.8.2",
+ "hybrid-array",
+ "subtle",
+ "zeroize",
]
[[package]]
name = "security-framework"
-version = "3.4.0"
+version = "3.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "60b369d18893388b345804dc0007963c99b7d665ae71d275812d828c6f089640"
+checksum = "b7f4bc775c73d9a02cde8bf7b2ec4c9d12743edf609006c7facc23998404cd1d"
dependencies = [
- "bitflags 2.9.4",
- "core-foundation 0.10.1",
+ "bitflags 2.13.2",
+ "core-foundation",
"core-foundation-sys",
"libc",
"security-framework-sys",
@@ -7155,21 +6134,27 @@ dependencies = [
[[package]]
name = "security-framework-sys"
-version = "2.15.0"
+version = "2.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cc1f0cbffaac4852523ce30d8bd3c5cdc873501d96ff467ca09b6767bb8cd5c0"
+checksum = "6ce2691df843ecc5d231c0b14ece2acc3efb62c0a398c7e1d875f3983ce020e3"
dependencies = [
"core-foundation-sys",
"libc",
]
+[[package]]
+name = "seize"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5b55fb86dfd3a2f5f76ea78310a88f96c4ea21a3031f8d212443d56123fd0521"
+
[[package]]
name = "selectors"
version = "0.36.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c5d9c0c92a92d33f08817311cf3f2c29a3538a8240e94a6a3c622ce652d7e00c"
dependencies = [
- "bitflags 2.9.4",
+ "bitflags 2.13.2",
"cssparser",
"derive_more",
"log",
@@ -7182,19 +6167,14 @@ dependencies = [
"smallvec",
]
-[[package]]
-name = "self_cell"
-version = "1.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0f7d95a54511e0c7be3f51e8867aa8cf35148d7b9445d44de2f943e2b206e749"
-
[[package]]
name = "semver"
-version = "1.0.26"
+version = "1.0.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0"
+checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd"
dependencies = [
"serde",
+ "serde_core",
]
[[package]]
@@ -7203,12 +6183,6 @@ version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cd0b0ec5f1c1ca621c432a25813d8d60c88abe6d3e08a3eb9cf37d97a0fe3d73"
-[[package]]
-name = "seq-macro"
-version = "0.3.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1bc711410fbe7399f390ca1c3b60ad0f53f80e95c5eb935e52268a0e2cd49acc"
-
[[package]]
name = "serde"
version = "1.0.229"
@@ -7232,33 +6206,23 @@ dependencies = [
]
[[package]]
-name = "serde-wasm-bindgen"
-version = "0.6.5"
+name = "serde_bencode"
+version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8302e169f0eddcc139c70f139d19d6467353af16f9fce27e8c30158036a1e16b"
+checksum = "a70dfc7b7438b99896e7f8992363ab8e2c4ba26aa5ec675d32d1c3c2c33d413e"
dependencies = [
- "js-sys",
"serde",
- "wasm-bindgen",
+ "serde_bytes",
]
[[package]]
name = "serde_bytes"
-version = "0.11.17"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8437fd221bde2d4ca316d61b90e337e9e702b3820b87d63caa9ba6c02bd06d96"
-dependencies = [
- "serde",
-]
-
-[[package]]
-name = "serde_cbor_2"
-version = "0.13.0"
+version = "0.11.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "34aec2709de9078e077090abd848e967abab63c9fb3fdb5d4799ad359d8d482c"
+checksum = "a5d440709e79d88e51ac01c4b72fc6cb7314017bb7da9eeff678aa94c10e3ea8"
dependencies = [
- "half",
"serde",
+ "serde_core",
]
[[package]]
@@ -7278,7 +6242,7 @@ checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348"
dependencies = [
"proc-macro2",
"quote",
- "syn 3.0.2",
+ "syn 3.0.5",
]
[[package]]
@@ -7289,7 +6253,19 @@ checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.106",
+ "syn 2.0.119",
+]
+
+[[package]]
+name = "serde_ipld_dagcbor"
+version = "0.6.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "46182f4f08349a02b45c998ba3215d3f9de826246ba02bb9dddfe9a2a2100778"
+dependencies = [
+ "cbor4ii",
+ "ipld-core",
+ "scopeguard",
+ "serde",
]
[[package]]
@@ -7307,23 +6283,24 @@ dependencies = [
[[package]]
name = "serde_path_to_error"
-version = "0.1.17"
+version = "0.1.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "59fab13f937fa393d08645bf3a84bdfe86e296747b506ada67bb15f10f218b2a"
+checksum = "10a9ff822e371bb5403e391ecd83e182e0e77ba7f6fe0160b795797109d1b457"
dependencies = [
"itoa",
"serde",
+ "serde_core",
]
[[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.106",
+ "syn 3.0.5",
]
[[package]]
@@ -7358,17 +6335,19 @@ dependencies = [
[[package]]
name = "serde_with"
-version = "3.17.0"
+version = "3.23.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "381b283ce7bc6b476d903296fb59d0d36633652b633b27f64db4fb46dcbfc3b9"
+checksum = "935177bb8c0cd8ca1a4e6d1a2ac8988bea69cab4f9d3a31311e012ad27868ea4"
dependencies = [
- "base64 0.22.1",
+ "base64 0.23.1",
+ "bs58",
"chrono",
"hex",
"indexmap 1.9.3",
- "indexmap 2.12.0",
+ "indexmap 2.14.2",
+ "jiff",
"schemars 0.9.0",
- "schemars 1.0.4",
+ "schemars 1.2.2",
"serde_core",
"serde_json",
"serde_with_macros",
@@ -7377,23 +6356,23 @@ dependencies = [
[[package]]
name = "serde_with_macros"
-version = "3.17.0"
+version = "3.23.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a6d4e30573c8cb306ed6ab1dca8423eec9a463ea0e155f45399455e0368b27e0"
+checksum = "1d607aa01a3cb0ad757d6fd216136910db3c97b102fe686585689615a02dbcdc"
dependencies = [
- "darling 0.21.3",
+ "darling 0.24.1",
"proc-macro2",
"quote",
- "syn 2.0.106",
+ "syn 3.0.5",
]
[[package]]
name = "serdect"
-version = "0.4.1"
+version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d3ef0e35b322ddfaecbc60f34ab448e157e48531288ee49fafbb053696b8ffe2"
+checksum = "66cf8fedced2fcf12406bcb34223dffb92eaf34908ede12fed414c82b7f00b3e"
dependencies = [
- "base16ct",
+ "base16ct 1.0.0",
"serde",
]
@@ -7416,7 +6395,7 @@ checksum = "772ee033c0916d670af7860b6e1ef7d658a4629a6d0b4c8c3e67f09b3765b75d"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.106",
+ "syn 2.0.119",
]
[[package]]
@@ -7430,26 +6409,15 @@ dependencies = [
[[package]]
name = "sha1"
-version = "0.10.6"
+version = "0.10.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba"
+checksum = "a978451301f4db1d02937a4ab3ccce137717b81826e79b7d49ffe3244a13c3b8"
dependencies = [
"cfg-if",
- "cpufeatures",
+ "cpufeatures 0.2.17",
"digest 0.10.7",
]
-[[package]]
-name = "sha1"
-version = "0.11.0-rc.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c5e046edf639aa2e7afb285589e5405de2ef7e61d4b0ac1e30256e3eab911af9"
-dependencies = [
- "cfg-if",
- "cpufeatures",
- "digest 0.11.0-rc.3",
-]
-
[[package]]
name = "sha1_smol"
version = "1.0.1"
@@ -7463,19 +6431,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283"
dependencies = [
"cfg-if",
- "cpufeatures",
+ "cpufeatures 0.2.17",
"digest 0.10.7",
]
[[package]]
name = "sha2"
-version = "0.11.0-rc.2"
+version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d1e3878ab0f98e35b2df35fe53201d088299b41a6bb63e3e34dada2ac4abd924"
+checksum = "446ba717509524cb3f22f17ecc096f10f4822d76ab5c0b9822c5f9c284e825f4"
dependencies = [
"cfg-if",
- "cpufeatures",
- "digest 0.11.0-rc.3",
+ "cpufeatures 0.3.1",
+ "digest 0.11.3",
]
[[package]]
@@ -7489,16 +6457,17 @@ dependencies = [
[[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"
-version = "1.4.6"
+version = "1.4.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b2a4719bff48cee6b39d12c020eeb490953ad2443b7055bd0b21fca26bd8c28b"
+checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b"
dependencies = [
+ "errno",
"libc",
]
@@ -7514,15 +6483,29 @@ dependencies = [
[[package]]
name = "signature"
-version = "3.0.0-rc.4"
+version = "3.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fc280a6ff65c79fbd6622f64d7127f32b85563bca8c53cd2e9141d6744a9056d"
+checksum = "28d567dcbaf0049cb8ac2608a76cd95ff9e4412e1899d389ee400918ca7537f5"
+dependencies = [
+ "digest 0.11.3",
+ "rand_core 0.10.1",
+]
[[package]]
name = "simd-adler32"
-version = "0.3.7"
+version = "0.3.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3a219298ac11a56ea9a6d2120044824d6f01aeb034955e7af7bc16858527deea"
+
+[[package]]
+name = "simd_cesu8"
+version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe"
+checksum = "11031e251abf8611c80f460e19dbdeb54a66db918e49c65a7065b46ac7aec520"
+dependencies = [
+ "rustc_version",
+ "simdutf8",
+]
[[package]]
name = "simdutf8"
@@ -7532,45 +6515,30 @@ checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e"
[[package]]
name = "simple-dns"
-version = "0.9.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dee851d0e5e7af3721faea1843e8015e820a234f81fda3dea9247e15bac9a86a"
-dependencies = [
- "bitflags 2.9.4",
-]
-
-[[package]]
-name = "simple_asn1"
-version = "0.6.3"
+version = "0.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "297f631f50729c8c99b84667867963997ec0b50f32b2a7dbcab828ef0541e8bb"
+checksum = "2b6f884fa9a8d48101774bfbd3aeb81e968dd22cffd19a372da69f183db22c1a"
dependencies = [
- "num-bigint",
- "num-traits",
- "thiserror 2.0.20",
- "time",
+ "bitflags 2.13.2",
]
[[package]]
name = "siphasher"
-version = "1.0.1"
+version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d"
+checksum = "8ee5873ec9cce0195efcb7a4e9507a04cd49aec9c83d0389df45b1ef7ba2e649"
[[package]]
name = "slab"
-version = "0.4.11"
+version = "0.4.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589"
+checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5"
[[package]]
name = "smallvec"
-version = "1.15.1"
+version = "1.16.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03"
-dependencies = [
- "serde",
-]
+checksum = "ba467056f1b547ed52077911161fc86985becbc60e8e1857c8a144dab0def891"
[[package]]
name = "smol_str"
@@ -7579,58 +6547,53 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fad6c857cbab2627dcf01ec85a623ca4e7dcb5691cbaa3d7fb7653671f0d09c9"
[[package]]
-name = "socket2"
-version = "0.5.10"
+name = "smol_str"
+version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678"
+checksum = "4aaa7368fcf4852a4c2dd92df0cace6a71f2091ca0a23391ce7f3a31833f1523"
dependencies = [
- "libc",
- "windows-sys 0.52.0",
+ "borsh",
+ "serde_core",
]
[[package]]
name = "socket2"
-version = "0.6.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "233504af464074f9d066d7b5416c5f9b894a5862a6506e306f7b816cdd6f1807"
-dependencies = [
- "libc",
- "windows-sys 0.59.0",
-]
-
-[[package]]
-name = "socks"
-version = "0.3.4"
+version = "0.6.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f0c3dbbd9ae980613c6dd8e28a9407b50509d3803b57624d5dfe8315218cd58b"
+checksum = "c3d1e2c7f27f8d4cb10542a02c49005dbd6e93095799d6f3be745fae9f8fedd4"
dependencies = [
- "byteorder",
"libc",
- "winapi",
+ "windows-sys 0.61.2",
]
[[package]]
name = "softbuffer"
-version = "0.4.6"
+version = "0.4.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "18051cdd562e792cad055119e0cdb2cfc137e44e3987532e0f9659a77931bb08"
+checksum = "aac18da81ebbf05109ab275b157c22a653bb3c12cf884450179942f81bcbf6c3"
dependencies = [
"bytemuck",
- "cfg_aliases",
- "core-graphics 0.24.0",
- "foreign-types 0.5.0",
"js-sys",
- "log",
- "objc2 0.5.2",
- "objc2-foundation 0.2.2",
- "objc2-quartz-core 0.2.2",
+ "ndk",
+ "objc2",
+ "objc2-core-foundation",
+ "objc2-core-graphics",
+ "objc2-foundation",
+ "objc2-quartz-core",
"raw-window-handle",
"redox_syscall",
+ "tracing",
"wasm-bindgen",
"web-sys",
- "windows-sys 0.59.0",
+ "windows-sys 0.61.2",
]
+[[package]]
+name = "sorted-index-buffer"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ea06cc588e43c632923a55450401b8f25e628131571d4e1baea1bdfdb2b5ed06"
+
[[package]]
name = "soup3"
version = "0.5.0"
@@ -7665,23 +6628,23 @@ checksum = "c87e960f4dca2788eeb86bbdde8dd246be8948790b7618d656e68f9b720a86e8"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.106",
+ "syn 2.0.119",
]
[[package]]
name = "spin"
-version = "0.9.8"
+version = "0.9.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67"
+checksum = "3763264f6b73151db08c50ff20d7d8a0b8796e021cdea7ceedad07b80155fa0e"
dependencies = [
"lock_api",
]
[[package]]
name = "spin"
-version = "0.10.0"
+version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d5fe4ccb98d9c292d56fec89a5e07da7fc4cf0dc11e156b41793132775d3e591"
+checksum = "023a211cb3138dbc438680b32560ad89f699977624c9f8dbb95a47d5b4c07dd3"
[[package]]
name = "spki"
@@ -7695,12 +6658,12 @@ dependencies = [
[[package]]
name = "spki"
-version = "0.8.0-rc.4"
+version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8baeff88f34ed0691978ec34440140e1572b68c7dd4a495fd14a3dc1944daa80"
+checksum = "1d9efca8738c78ee9484207732f728b1ef517bbb1833d6fc0879ca898a522f6f"
dependencies = [
"base64ct",
- "der 0.8.0-rc.9",
+ "der 0.8.2",
]
[[package]]
@@ -7715,234 +6678,11 @@ dependencies = [
"unicode-segmentation",
]
-[[package]]
-name = "sqlx"
-version = "0.8.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4410e73b3c0d8442c5f99b425d7a435b5ee0ae4167b3196771dd3f7a01be745f"
-dependencies = [
- "sqlx-core",
- "sqlx-macros",
- "sqlx-mysql",
- "sqlx-postgres",
- "sqlx-sqlite",
-]
-
-[[package]]
-name = "sqlx-core"
-version = "0.8.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6a007b6936676aa9ab40207cde35daab0a04b823be8ae004368c0793b96a61e0"
-dependencies = [
- "bytes",
- "chrono",
- "crc",
- "crossbeam-queue",
- "either",
- "event-listener",
- "futures-core",
- "futures-intrusive",
- "futures-io",
- "futures-util",
- "hashbrown 0.15.5",
- "hashlink 0.10.0",
- "indexmap 2.12.0",
- "log",
- "memchr",
- "once_cell",
- "percent-encoding",
- "rustls",
- "rustls-pemfile",
- "serde",
- "serde_json",
- "sha2 0.10.9",
- "smallvec",
- "thiserror 2.0.20",
- "tokio",
- "tokio-stream",
- "tracing",
- "url",
- "uuid",
- "webpki-roots 0.26.11",
-]
-
-[[package]]
-name = "sqlx-d1"
-version = "0.2.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1cdbc1b12713549997bb308b1d7b80375b5e261493fbb0d13adca78944c176de"
-dependencies = [
- "sqlx-d1-core",
-]
-
-[[package]]
-name = "sqlx-d1-core"
-version = "0.2.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c616de9b85649a1f1b8e18134a29be1d201d12316d33d41605b022886b8b3817"
-dependencies = [
- "futures-core",
- "futures-util",
- "log",
- "serde",
- "sqlx-core",
- "sqlx-sqlite",
- "worker",
- "worker-sys",
-]
-
-[[package]]
-name = "sqlx-macros"
-version = "0.8.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3112e2ad78643fef903618d78cf0aec1cb3134b019730edb039b69eaf531f310"
-dependencies = [
- "proc-macro2",
- "quote",
- "sqlx-core",
- "sqlx-macros-core",
- "syn 2.0.106",
-]
-
-[[package]]
-name = "sqlx-macros-core"
-version = "0.8.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4e9f90acc5ab146a99bf5061a7eb4976b573f560bc898ef3bf8435448dd5e7ad"
-dependencies = [
- "dotenvy",
- "either",
- "heck 0.5.0",
- "hex",
- "once_cell",
- "proc-macro2",
- "quote",
- "serde",
- "serde_json",
- "sha2 0.10.9",
- "sqlx-core",
- "sqlx-mysql",
- "sqlx-postgres",
- "sqlx-sqlite",
- "syn 2.0.106",
- "tempfile",
- "tokio",
- "url",
-]
-
-[[package]]
-name = "sqlx-mysql"
-version = "0.8.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4560278f0e00ce64938540546f59f590d60beee33fffbd3b9cd47851e5fff233"
-dependencies = [
- "atoi",
- "base64 0.22.1",
- "bitflags 2.9.4",
- "byteorder",
- "bytes",
- "chrono",
- "crc",
- "digest 0.10.7",
- "dotenvy",
- "either",
- "futures-channel",
- "futures-core",
- "futures-io",
- "futures-util",
- "generic-array",
- "hex",
- "hkdf",
- "hmac",
- "itoa",
- "log",
- "md-5",
- "memchr",
- "once_cell",
- "percent-encoding",
- "rand 0.8.8",
- "rsa",
- "serde",
- "sha1 0.10.6",
- "sha2 0.10.9",
- "smallvec",
- "sqlx-core",
- "stringprep",
- "thiserror 2.0.20",
- "tracing",
- "uuid",
- "whoami",
-]
-
-[[package]]
-name = "sqlx-postgres"
-version = "0.8.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c5b98a57f363ed6764d5b3a12bfedf62f07aa16e1856a7ddc2a0bb190a959613"
-dependencies = [
- "atoi",
- "base64 0.22.1",
- "bitflags 2.9.4",
- "byteorder",
- "chrono",
- "crc",
- "dotenvy",
- "etcetera",
- "futures-channel",
- "futures-core",
- "futures-util",
- "hex",
- "hkdf",
- "hmac",
- "home",
- "itoa",
- "log",
- "md-5",
- "memchr",
- "once_cell",
- "rand 0.8.8",
- "serde",
- "serde_json",
- "sha2 0.10.9",
- "smallvec",
- "sqlx-core",
- "stringprep",
- "thiserror 2.0.20",
- "tracing",
- "uuid",
- "whoami",
-]
-
-[[package]]
-name = "sqlx-sqlite"
-version = "0.8.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f85ca71d3a5b24e64e1d08dd8fe36c6c95c339a896cc33068148906784620540"
-dependencies = [
- "atoi",
- "chrono",
- "flume",
- "futures-channel",
- "futures-core",
- "futures-executor",
- "futures-intrusive",
- "futures-util",
- "libsqlite3-sys",
- "log",
- "percent-encoding",
- "serde",
- "serde_urlencoded",
- "sqlx-core",
- "tracing",
- "url",
- "uuid",
-]
-
[[package]]
name = "stable_deref_trait"
-version = "1.2.0"
+version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
+checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596"
[[package]]
name = "static_assertions"
@@ -7974,17 +6714,6 @@ dependencies = [
"quote",
]
-[[package]]
-name = "stringprep"
-version = "0.1.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7b4df3d392d81bd458a8a621b8bffbd2302a12ffe288a9d931670948749463b1"
-dependencies = [
- "unicode-bidi",
- "unicode-normalization",
- "unicode-properties",
-]
-
[[package]]
name = "strsim"
version = "0.11.1"
@@ -7993,23 +6722,23 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
[[package]]
name = "strum"
-version = "0.27.2"
+version = "0.28.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "af23d6f6c1a224baef9d3f61e287d2761385a5b88fdab4eb4c6f11aeb54c4bcf"
+checksum = "9628de9b8791db39ceda2b119bbe13134770b56c138ec1d3af810d045c04f9bd"
dependencies = [
"strum_macros",
]
[[package]]
name = "strum_macros"
-version = "0.27.2"
+version = "0.28.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7695ce3845ea4b33927c055a39dc438a45b059f7c1b3d91d38d10355fb8cbca7"
+checksum = "ab85eea0270ee17587ed4156089e10b9e6880ee688791d45a905f5b1ca36f664"
dependencies = [
"heck 0.5.0",
"proc-macro2",
"quote",
- "syn 2.0.106",
+ "syn 2.0.119",
]
[[package]]
@@ -8020,14 +6749,14 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
[[package]]
name = "swarm-discovery"
-version = "0.4.0"
+version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4eae338a4551897c6a50fa2c041c4b75f578962d9fca8adb828cf81f7158740f"
+checksum = "1b4877f20f064de34b77d79237c9caa37c393590af8ef5a2f3253d59be5a338b"
dependencies = [
"acto",
"hickory-proto",
- "rand 0.9.5",
- "socket2 0.5.10",
+ "rand 0.10.2",
+ "socket2",
"thiserror 2.0.20",
"tokio",
"tracing",
@@ -8035,9 +6764,9 @@ dependencies = [
[[package]]
name = "swift-rs"
-version = "1.0.7"
+version = "1.0.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4057c98e2e852d51fdcfca832aac7b571f6b351ad159f9eda5db1655f8d0c4d7"
+checksum = "e45c444e496845d3f2a351146bff59aae4975b2280238df1dfaa0c7d1846f38e"
dependencies = [
"base64 0.21.7",
"serde",
@@ -8056,9 +6785,9 @@ dependencies = [
[[package]]
name = "syn"
-version = "2.0.106"
+version = "2.0.119"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6"
+checksum = "872831b642d1a07999a962a351ed35b955ea2cfc8f3862091e2a240a84f17297"
dependencies = [
"proc-macro2",
"quote",
@@ -8067,9 +6796,9 @@ dependencies = [
[[package]]
name = "syn"
-version = "3.0.2"
+version = "3.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a207d6d6a2b7fc470b80443726053f18a2481b7e1eee970597051596567987a3"
+checksum = "12df2e0110f65b775f769bb17ef989067a1d931b2eb822bd4346631eeada89f9"
dependencies = [
"proc-macro2",
"quote",
@@ -8087,48 +6816,23 @@ 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.106",
-]
-
-[[package]]
-name = "sysctl"
-version = "0.6.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "01198a2debb237c62b6826ec7081082d951f46dbb64b0e8c7649a452230d1dfc"
-dependencies = [
- "bitflags 2.9.4",
- "byteorder",
- "enum-as-inner",
- "libc",
- "thiserror 1.0.69",
- "walkdir",
-]
-
-[[package]]
-name = "system-configuration"
-version = "0.6.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b"
-dependencies = [
- "bitflags 2.9.4",
- "core-foundation 0.9.4",
- "system-configuration-sys",
+ "syn 3.0.5",
]
[[package]]
name = "system-configuration"
-version = "0.7.0"
+version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a13f3d0daba03132c0aa9767f98351b3488edc2c100cda2d2ec2b04f3d8d3c8b"
+checksum = "501336eb7ba9e417300a6a0fa985721065467aa83a6dcf0422a8e43e4c0328fa"
dependencies = [
- "bitflags 2.9.4",
- "core-foundation 0.9.4",
+ "bitflags 2.13.2",
+ "core-foundation",
"system-configuration-sys",
]
@@ -8151,42 +6855,36 @@ dependencies = [
"cfg-expr",
"heck 0.5.0",
"pkg-config",
- "toml 0.8.23",
+ "toml 0.8.2",
"version-compare",
]
-[[package]]
-name = "tagptr"
-version = "0.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7b2093cf4c8eb1e67749a6762251bc9cd836b6fc171623bd0a9d324d37af2417"
-
[[package]]
name = "tao"
-version = "0.35.0"
+version = "0.35.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1cf65722394c2ac443e80120064987f8914ee1d4e4e36e63cdf10f2990f01159"
+checksum = "d1c93047acf68669466a34690ac58cca7010bd1b201e1ec86f1fd0a75d3dd4a9"
dependencies = [
- "bitflags 2.9.4",
- "block2 0.6.1",
- "core-foundation 0.10.1",
- "core-graphics 0.25.0",
+ "bitflags 2.13.2",
+ "block2",
+ "core-foundation",
+ "core-graphics",
"crossbeam-channel",
"dbus",
"dispatch2",
- "dlopen2 0.8.0",
+ "dlopen2",
"dpi",
"gdkwayland-sys",
"gdkx11-sys",
"gtk",
- "jni",
+ "jni 0.21.1",
"libc",
"log",
"ndk",
"ndk-sys",
- "objc2 0.6.4",
+ "objc2",
"objc2-app-kit",
- "objc2-foundation 0.3.1",
+ "objc2-foundation",
"objc2-ui-kit",
"once_cell",
"parking_lot",
@@ -8203,13 +6901,13 @@ dependencies = [
[[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.106",
+ "syn 2.0.119",
]
[[package]]
@@ -8234,22 +6932,21 @@ dependencies = [
"glob",
"gtk",
"heck 0.5.0",
- "http 1.5.0",
- "jni",
+ "http",
+ "jni 0.21.1",
"libc",
"log",
"mime",
"muda",
- "objc2 0.6.4",
+ "objc2",
"objc2-app-kit",
- "objc2-foundation 0.3.1",
+ "objc2-foundation",
"objc2-ui-kit",
"objc2-web-kit",
"percent-encoding",
"plist",
"raw-window-handle",
- "reqwest 0.13.1",
- "rustls",
+ "reqwest",
"serde",
"serde_json",
"serde_repr",
@@ -8309,7 +7006,7 @@ dependencies = [
"serde",
"serde_json",
"sha2 0.10.9",
- "syn 2.0.106",
+ "syn 2.0.119",
"tauri-utils",
"thiserror 2.0.20",
"time",
@@ -8319,55 +7016,17 @@ dependencies = [
]
[[package]]
-name = "tauri-macros"
-version = "2.6.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e8b394794f399a421811d06966343e7933fcae92d59f5180b9388d1174497a45"
-dependencies = [
- "heck 0.5.0",
- "proc-macro2",
- "quote",
- "syn 2.0.106",
- "tauri-codegen",
- "tauri-utils",
-]
-
-[[package]]
-name = "tauri-plugin"
-version = "2.6.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f8d5f58bfd0cdcfdbc0a68dc08b354eea2afc551b421de91b07b69e0dd769d57"
-dependencies = [
- "anyhow",
- "glob",
- "plist",
- "schemars 0.8.22",
- "serde",
- "serde_json",
- "tauri-utils",
- "walkdir",
-]
-
-[[package]]
-name = "tauri-plugin-opener"
-version = "2.5.5"
+name = "tauri-macros"
+version = "2.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "60d60366174b745b4ef5824b8bbc1c457fd08f0ce101ff643c0a49181a9f4e91"
+checksum = "e8b394794f399a421811d06966343e7933fcae92d59f5180b9388d1174497a45"
dependencies = [
- "dunce",
- "glob",
- "objc2-app-kit",
- "objc2-foundation 0.3.1",
- "open",
- "schemars 0.8.22",
- "serde",
- "serde_json",
- "tauri",
- "tauri-plugin",
- "thiserror 2.0.20",
- "url",
- "windows 0.61.3",
- "zbus",
+ "heck 0.5.0",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.119",
+ "tauri-codegen",
+ "tauri-utils",
]
[[package]]
@@ -8379,9 +7038,9 @@ dependencies = [
"cookie",
"dpi",
"gtk",
- "http 1.5.0",
- "jni",
- "objc2 0.6.4",
+ "http",
+ "jni 0.21.1",
+ "objc2",
"objc2-ui-kit",
"objc2-web-kit",
"raw-window-handle",
@@ -8402,10 +7061,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4e6fac707727b7a2f48e4ded90976324267371073edbb415ffb73bb0458d203f"
dependencies = [
"gtk",
- "http 1.5.0",
- "jni",
+ "http",
+ "jni 0.21.1",
"log",
- "objc2 0.6.4",
+ "objc2",
"objc2-app-kit",
"once_cell",
"percent-encoding",
@@ -8434,7 +7093,7 @@ dependencies = [
"dom_query",
"dunce",
"glob",
- "http 1.5.0",
+ "http",
"infer",
"json-patch",
"log",
@@ -8452,7 +7111,7 @@ dependencies = [
"serde_with",
"swift-rs",
"thiserror 2.0.20",
- "toml 0.9.12+spec-1.1.0",
+ "toml 1.1.6+spec-1.1.0",
"url",
"urlpattern",
"uuid",
@@ -8461,12 +7120,13 @@ dependencies = [
[[package]]
name = "tauri-winres"
-version = "0.3.3"
+version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fd21509dd1fa9bd355dc29894a6ff10635880732396aa38c0066c1e6c1ab8074"
+checksum = "cc65d45c68858bfe420dd29e834b5d15dbecf8a07a8a16cf4d532c7b1f69d4b6"
dependencies = [
+ "dunce",
"embed-resource",
- "toml 0.9.12+spec-1.1.0",
+ "toml 1.1.6+spec-1.1.0",
]
[[package]]
@@ -8479,45 +7139,25 @@ dependencies = [
"getrandom 0.4.3",
"once_cell",
"rustix",
- "windows-sys 0.61.0",
+ "windows-sys 0.61.2",
]
[[package]]
name = "tendril"
-version = "0.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c4790fc369d5a530f4b544b094e31388b9b3a37c0f4652ade4505945f5660d24"
-dependencies = [
- "new_debug_unreachable",
- "utf-8",
-]
-
-[[package]]
-name = "termtree"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8f50febec83f5ee1df3015341d8bd429f2d1cc62bcba7ea2076759d315084683"
-
-[[package]]
-name = "test-log"
-version = "0.2.18"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1e33b98a582ea0be1168eba097538ee8dd4bbe0f2b01b22ac92ea30054e5be7b"
+checksum = "5fed54709c5b3a53d09bb1c113ea4f5ceafd1e772ddcb0030a82e1d56c087b08"
dependencies = [
- "env_logger",
- "test-log-macros",
- "tracing-subscriber",
+ "new_debug_unreachable",
]
[[package]]
-name = "test-log-macros"
-version = "0.2.18"
+name = "termcolor"
+version = "1.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "451b374529930d7601b1eef8d32bc79ae870b6079b069401709c2a8bf9e75f36"
+checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755"
dependencies = [
- "proc-macro2",
- "quote",
- "syn 2.0.106",
+ "winapi-util",
]
[[package]]
@@ -8546,7 +7186,7 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.106",
+ "syn 2.0.119",
]
[[package]]
@@ -8557,63 +7197,63 @@ checksum = "bc04cd3e1236dd4a98afca4569f2deb3f120e5422a4023be2cb683f8486292af"
dependencies = [
"proc-macro2",
"quote",
- "syn 3.0.2",
+ "syn 3.0.5",
]
[[package]]
name = "thread_local"
-version = "1.1.9"
+version = "1.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185"
+checksum = "1ad99c4c6d32803332c548b1af0540b357b3f5fc0be8f6c6bfe8b2e6ae784070"
dependencies = [
"cfg-if",
]
+[[package]]
+name = "threadpool"
+version = "1.8.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d050e60b33d41c19108b32cea32164033a9013fe3b46cbd4457559bfbf77afaa"
+dependencies = [
+ "num_cpus",
+]
+
[[package]]
name = "time"
-version = "0.3.43"
+version = "0.3.55"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "83bde6f1ec10e72d583d91623c939f623002284ef622b87de38cfd546cbf2031"
+checksum = "cdb87b95ec50ddfa440816d227a17b2ccbdda963a316a727fda0fc4334f7d134"
dependencies = [
"deranged",
"js-sys",
"num-conv",
"powerfmt",
- "serde",
+ "serde_core",
"time-core",
"time-macros",
]
[[package]]
name = "time-core"
-version = "0.1.6"
+version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "40868e7c1d2f0b8d73e4a8c7f0ff63af4f6d19be117e90bd73eb1d62cf831c6b"
+checksum = "9e1c906769ad99c88eaa54e728060edef082f8e358ff32030cb7c7d315e81109"
[[package]]
name = "time-macros"
-version = "0.2.24"
+version = "0.2.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "30cfb0125f12d9c277f35663a0a33f8c30190f4e4574868a330595412d34ebf3"
+checksum = "7e689342a48d2ea927c87ea50cabf8594854bf940e9310208848d680d668ed85"
dependencies = [
"num-conv",
"time-core",
]
-[[package]]
-name = "tiny-keccak"
-version = "2.0.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237"
-dependencies = [
- "crunchy",
-]
-
[[package]]
name = "tinystr"
-version = "0.8.1"
+version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5d4f6d1145dcb577acf783d4e601bc1d76a13337bb54e6233add580b07344c8b"
+checksum = "b1e27c91459209c2986af3dcf603a5a74a4368754ce37414f59acc971167f643"
dependencies = [
"displaydoc",
"zerovec",
@@ -8621,24 +7261,15 @@ 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 = "tokenizers"
-version = "0.21.4"
+version = "0.22.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a620b996116a59e184c2fa2dfd8251ea34a36d0a514758c6f966386bd2e03476"
+checksum = "b238e22d44a15349529690fb07bd645cf58149a1b1e44d6cb5bd1641ff1a6223"
dependencies = [
"ahash",
"aho-corasick",
@@ -8647,8 +7278,6 @@ dependencies = [
"derive_builder",
"esaxx-rs",
"getrandom 0.3.4",
- "hf-hub",
- "indicatif",
"itertools",
"log",
"macro_rules_attribute",
@@ -8671,40 +7300,29 @@ dependencies = [
[[package]]
name = "tokio"
-version = "1.50.0"
+version = "1.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "27ad5e34374e03cfffefc301becb44e9dc3c17584f414349ebe29ed26661822d"
+checksum = "202caea871b69668250d242070849eb495be178ed697a3e98aebce5bc81a0bed"
dependencies = [
"bytes",
"libc",
"mio",
- "parking_lot",
"pin-project-lite",
"signal-hook-registry",
- "socket2 0.6.0",
+ "socket2",
"tokio-macros",
- "windows-sys 0.61.0",
+ "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.106",
-]
-
-[[package]]
-name = "tokio-native-tls"
-version = "0.3.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2"
-dependencies = [
- "native-tls",
- "tokio",
+ "syn 3.0.5",
]
[[package]]
@@ -8719,9 +7337,9 @@ dependencies = [
[[package]]
name = "tokio-stream"
-version = "0.1.17"
+version = "0.1.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "eca58d7bba4a75707817a2c44174253f9236b2d5fbd055602e9d5c07c139a047"
+checksum = "a3d06f0b082ba57c26b79407372e57cf2a1e28124f78e9479fe80322cf53420b"
dependencies = [
"futures-core",
"pin-project-lite",
@@ -8730,14 +7348,19 @@ dependencies = [
]
[[package]]
-name = "tokio-test"
-version = "0.4.5"
+name = "tokio-tungstenite"
+version = "0.29.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3f6d24790a10a7af737693a3e8f1d03faef7e6ca0cc99aae5066f533766de545"
+checksum = "8f72a05e828585856dacd553fba484c242c46e391fb0e58917c942ee9202915c"
dependencies = [
- "futures-core",
+ "futures-util",
+ "log",
+ "rustls",
+ "rustls-pki-types",
"tokio",
- "tokio-stream",
+ "tokio-rustls",
+ "tungstenite",
+ "webpki-roots 0.26.11",
]
[[package]]
@@ -8757,53 +7380,37 @@ dependencies = [
[[package]]
name = "tokio-websockets"
-version = "0.12.1"
+version = "0.13.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5190767f03b86528ab9f4f6a9158072a6d0ef240d9a9591772eb411f315920f4"
+checksum = "d52efb639344a7c6adb8e62c6f3d2c19c001ff1b79a5041ba1c6ed42e19c6aa5"
dependencies = [
"base64 0.22.1",
"bytes",
"futures-core",
"futures-sink",
- "getrandom 0.3.4",
- "http 1.5.0",
+ "getrandom 0.4.3",
+ "http",
"httparse",
- "rand 0.9.5",
+ "rand 0.10.2",
"ring",
"rustls-pki-types",
+ "sha1_smol",
"simdutf8",
"tokio",
"tokio-rustls",
"tokio-util",
]
-[[package]]
-name = "tokise"
-version = "0.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "decf97738ce15b9e9cc1671ea29b0f6c56538719e1a092d19cc2134bf144e40e"
-dependencies = [
- "futures",
- "gloo",
- "num_cpus",
- "once_cell",
- "pin-project",
- "pinned",
- "tokio",
- "tokio-stream",
- "wasm-bindgen-futures",
-]
-
[[package]]
name = "toml"
-version = "0.8.23"
+version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362"
+checksum = "185d8ab0dfbb35cf1399a6344d8484209c088f75f8f68230da55d48d95d43e3d"
dependencies = [
"serde",
"serde_spanned 0.6.9",
- "toml_datetime 0.6.11",
- "toml_edit 0.22.27",
+ "toml_datetime 0.6.3",
+ "toml_edit 0.20.2",
]
[[package]]
@@ -8812,33 +7419,35 @@ version = "0.9.12+spec-1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf92845e79fc2e2def6a5d828f0801e29a2f8acc037becc5ab08595c7d5e9863"
dependencies = [
- "indexmap 2.12.0",
+ "indexmap 2.14.2",
"serde_core",
"serde_spanned 1.1.1",
"toml_datetime 0.7.5+spec-1.1.0",
"toml_parser",
"toml_writer",
- "winnow 0.7.13",
+ "winnow 0.7.15",
]
[[package]]
name = "toml"
-version = "1.1.5+spec-1.1.0"
+version = "1.1.6+spec-1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "12c0ba9680044b4ce98d391a62094047eada0d64860b80166c39f4a6b5640785"
+checksum = "920602543f0911ab71da12c50d59701da54c196d1a2bf5cb4b75667f137a406a"
dependencies = [
+ "indexmap 2.14.2",
"serde_core",
"serde_spanned 1.1.1",
"toml_datetime 1.1.1+spec-1.1.0",
"toml_parser",
+ "toml_writer",
"winnow 1.0.4",
]
[[package]]
name = "toml_datetime"
-version = "0.6.11"
+version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c"
+checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b"
dependencies = [
"serde",
]
@@ -8867,33 +7476,34 @@ version = "0.19.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421"
dependencies = [
- "indexmap 2.12.0",
- "toml_datetime 0.6.11",
+ "indexmap 2.14.2",
+ "toml_datetime 0.6.3",
"winnow 0.5.40",
]
[[package]]
name = "toml_edit"
-version = "0.20.7"
+version = "0.20.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "70f427fce4d84c72b5b732388bf4a9f4531b53f74e2887e3ecb2481f68f66d81"
+checksum = "396e4d48bbb2b7554c944bde63101b5ae446cff6ec4a24227428f15eb72ef338"
dependencies = [
- "indexmap 2.12.0",
- "toml_datetime 0.6.11",
+ "indexmap 2.14.2",
+ "serde",
+ "serde_spanned 0.6.9",
+ "toml_datetime 0.6.3",
"winnow 0.5.40",
]
[[package]]
name = "toml_edit"
-version = "0.22.27"
+version = "0.25.15+spec-1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a"
+checksum = "1340ea94a5856333492c9064b02c778b191dd2c853778d9609debdcdfea3a614"
dependencies = [
- "indexmap 2.12.0",
- "serde",
- "serde_spanned 0.6.9",
- "toml_datetime 0.6.11",
- "winnow 0.7.13",
+ "indexmap 2.14.2",
+ "toml_datetime 1.1.1+spec-1.1.0",
+ "toml_parser",
+ "winnow 1.0.4",
]
[[package]]
@@ -8907,9 +7517,9 @@ dependencies = [
[[package]]
name = "toml_writer"
-version = "1.0.6+spec-1.1.0"
+version = "1.1.2+spec-1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ab16f14aed21ee8bfd8ec22513f7287cd4a91aa92e44edfe2c17ddd004e92607"
+checksum = "7d56353a2a665ad0f41a421187180aab746c8c325620617ad883a99a1cbe66d2"
[[package]]
name = "tower"
@@ -8924,6 +7534,7 @@ dependencies = [
"tokio",
"tower-layer",
"tower-service",
+ "tracing",
]
[[package]]
@@ -8932,49 +7543,18 @@ version = "0.6.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4cfcf7e2740e6fc6d4d688b4ef00650406bb94adf4731e43c096c3a19fe40840"
dependencies = [
- "async-compression",
- "bitflags 2.9.4",
+ "bitflags 2.13.2",
"bytes",
- "futures-core",
"futures-util",
- "http 1.5.0",
+ "http",
"http-body",
- "http-body-util",
"pin-project-lite",
- "tokio",
- "tokio-util",
"tower",
"tower-layer",
"tower-service",
"url",
]
-[[package]]
-name = "tower-http"
-version = "0.7.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "08a05a66a4fdd61cbbe0a1d755ffe0ca6aba159dd4820936a0ff8a8278245b9c"
-dependencies = [
- "bitflags 2.9.4",
- "bytes",
- "futures-core",
- "futures-util",
- "http 1.5.0",
- "http-body",
- "http-body-util",
- "http-range-header",
- "httpdate",
- "mime",
- "mime_guess",
- "percent-encoding",
- "pin-project-lite",
- "tokio",
- "tokio-util",
- "tower-layer",
- "tower-service",
- "tracing",
-]
-
[[package]]
name = "tower-layer"
version = "0.3.3"
@@ -9007,7 +7587,7 @@ checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.106",
+ "syn 2.0.119",
]
[[package]]
@@ -9031,30 +7611,6 @@ dependencies = [
"tracing-core",
]
-[[package]]
-name = "tracing-opentelemetry"
-version = "0.33.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "adbc64cba7137545b8044cb1fe9814f7aacf3c6b5f9b45be8bb5db538befdb26"
-dependencies = [
- "js-sys",
- "opentelemetry",
- "tracing",
- "tracing-core",
- "tracing-subscriber",
- "web-time",
-]
-
-[[package]]
-name = "tracing-serde"
-version = "0.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "704b1aeb7be0d0a84fc9828cae51dab5970fee5088f83d1dd7ee6f6246fc6ff1"
-dependencies = [
- "serde",
- "tracing-core",
-]
-
[[package]]
name = "tracing-subscriber"
version = "0.3.23"
@@ -9065,117 +7621,81 @@ dependencies = [
"nu-ansi-term",
"once_cell",
"regex-automata",
- "serde",
- "serde_json",
"sharded-slab",
"smallvec",
"thread_local",
"tracing",
"tracing-core",
"tracing-log",
- "tracing-serde",
-]
-
-[[package]]
-name = "tracing-web"
-version = "0.1.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b9e6a141feebd51f8d91ebfd785af50fca223c570b86852166caa3b141defe7c"
-dependencies = [
- "js-sys",
- "tracing-core",
- "tracing-subscriber",
- "wasm-bindgen",
- "web-sys",
]
[[package]]
name = "tray-icon"
-version = "0.24.1"
+version = "0.24.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "65ba1e5f6b9ef9fd87e21b9c6f351554dbd717960089168fcfdef854686961dc"
+checksum = "045979e3f037cd18ad1cb2a419dfda133c5c29c9f3453370079f2255d46c257e"
dependencies = [
"crossbeam-channel",
"dirs",
"libappindicator",
"muda",
- "objc2 0.6.4",
+ "objc2",
"objc2-app-kit",
"objc2-core-foundation",
"objc2-core-graphics",
- "objc2-foundation 0.3.1",
+ "objc2-foundation",
"once_cell",
"png 0.18.1",
"serde",
"thiserror 2.0.20",
- "windows-sys 0.61.0",
+ "windows-sys 0.61.2",
]
[[package]]
-name = "trunk-demo"
-version = "0.1.0"
-dependencies = [
- "console_error_panic_hook",
- "gate-chat-ui",
- "gloo-net 0.6.0",
- "serde_json",
- "wasm-bindgen",
- "wasm-bindgen-futures",
- "web-sys",
- "yew",
-]
+name = "try-lock"
+version = "0.2.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b"
[[package]]
-name = "trust-dns-proto"
-version = "0.23.2"
+name = "ts-rs"
+version = "12.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3119112651c157f4488931a01e586aa459736e9d6046d3bd9105ffb69352d374"
+checksum = "756050066659291d47a554a9f558125db17428b073c5ffce1daf5dcb0f7231d8"
dependencies = [
- "async-trait",
- "cfg-if",
- "data-encoding",
- "enum-as-inner",
- "futures-channel",
- "futures-io",
- "futures-util",
- "idna 0.4.0",
- "ipnet",
- "once_cell",
- "rand 0.8.8",
- "smallvec",
- "thiserror 1.0.69",
- "tinyvec",
- "tokio",
- "tracing",
- "url",
+ "thiserror 2.0.20",
+ "ts-rs-macros",
]
[[package]]
-name = "trust-dns-resolver"
-version = "0.23.2"
+name = "ts-rs-macros"
+version = "12.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "10a3e6c3aff1718b3c73e395d1f35202ba2ffa847c6a62eea0db8fb4cfe30be6"
+checksum = "38d90eea51bc7988ef9e674bf80a85ba6804739e535e9cab48e4bb34a8b652aa"
dependencies = [
- "cfg-if",
- "futures-util",
- "ipconfig",
- "lru-cache",
- "once_cell",
- "parking_lot",
- "rand 0.8.8",
- "resolv-conf",
- "smallvec",
- "thiserror 1.0.69",
- "tokio",
- "tracing",
- "trust-dns-proto",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.119",
+ "termcolor",
]
[[package]]
-name = "try-lock"
-version = "0.2.5"
+name = "tungstenite"
+version = "0.29.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b"
+checksum = "6c01152af293afb9c7c2a57e4b559c5620b421f6d133261c60dd2d0cdb38e6b8"
+dependencies = [
+ "bytes",
+ "data-encoding",
+ "http",
+ "httparse",
+ "log",
+ "rand 0.9.5",
+ "rustls",
+ "rustls-pki-types",
+ "sha1",
+ "thiserror 2.0.20",
+]
[[package]]
name = "typeid"
@@ -9185,26 +7705,15 @@ checksum = "bc7d623258602320d5c55d1bc22793b57daff0ec7efc270ea7d55ce1d5f5471c"
[[package]]
name = "typenum"
-version = "1.18.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f"
-
-[[package]]
-name = "ucd-trie"
-version = "0.1.7"
+version = "1.20.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971"
+checksum = "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20"
[[package]]
-name = "uds_windows"
-version = "1.1.0"
+name = "unarray"
+version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "89daebc3e6fd160ac4aa9fc8b3bf71e1f74fbf92367ae71fb83a037e8bf164b9"
-dependencies = [
- "memoffset",
- "tempfile",
- "winapi",
-]
+checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94"
[[package]]
name = "unic-char-property"
@@ -9247,32 +7756,11 @@ dependencies = [
"unic-common",
]
-[[package]]
-name = "unicase"
-version = "2.8.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "75b844d17643ee918803943289730bec8aac480150456169e647ed0b576ba539"
-
-[[package]]
-name = "unicode-bidi"
-version = "0.3.18"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5c1cb5db39152898a79168971543b1cb5020dff7fe43c8dc468b0885f5e29df5"
-
[[package]]
name = "unicode-ident"
-version = "1.0.19"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d"
-
-[[package]]
-name = "unicode-normalization"
-version = "0.1.24"
+version = "1.0.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5033c97c4262335cded6d6fc3e5c18ab755e1a3dc96376350f3d8e9f009ad956"
-dependencies = [
- "tinyvec",
-]
+checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
[[package]]
name = "unicode-normalization-alignments"
@@ -9283,23 +7771,17 @@ dependencies = [
"smallvec",
]
-[[package]]
-name = "unicode-properties"
-version = "0.1.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e70f2a8b45122e719eb623c01822704c4e0907e7e426a05927e1a1cfff5b75d0"
-
[[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-width"
-version = "0.2.1"
+version = "0.1.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4a1a07cc7db3810833284e8d372ccdc6da29741639ecc70c9ec107df0fa6154c"
+checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af"
[[package]]
name = "unicode-xid"
@@ -9315,38 +7797,41 @@ checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e"
[[package]]
name = "universal-hash"
-version = "0.6.0-rc.2"
+version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a55be643b40a21558f44806b53ee9319595bc7ca6896372e4e08e5d7d83c9cd6"
+checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea"
dependencies = [
- "crypto-common 0.2.0-rc.4",
+ "crypto-common 0.1.6",
"subtle",
]
+[[package]]
+name = "universal-hash"
+version = "0.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f4987bdc12753382e0bec4a65c50738ffaabc998b9cdd1f952fb5f39b0048a96"
+dependencies = [
+ "crypto-common 0.2.2",
+ "ctutils",
+]
+
+[[package]]
+name = "unsigned-varint"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "eb066959b24b5196ae73cb057f45598450d2c5f71460e98c49b738086eff9c06"
+
[[package]]
name = "untrusted"
-version = "0.9.0"
+version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1"
+checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a"
[[package]]
-name = "ureq"
-version = "2.12.1"
+name = "untrusted"
+version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "02d1a66277ed75f640d608235660df48c8e3c19f3b4edb6a263315626cc3c01d"
-dependencies = [
- "base64 0.22.1",
- "flate2",
- "log",
- "once_cell",
- "rustls",
- "rustls-pki-types",
- "serde",
- "serde_json",
- "socks",
- "url",
- "webpki-roots 0.26.11",
-]
+checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1"
[[package]]
name = "url"
@@ -9355,18 +7840,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed"
dependencies = [
"form_urlencoded",
- "idna 1.1.0",
+ "idna",
"percent-encoding",
"serde",
"serde_derive",
]
-[[package]]
-name = "urlencoding"
-version = "2.1.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da"
-
[[package]]
name = "urlpattern"
version = "0.3.0"
@@ -9379,24 +7858,12 @@ dependencies = [
"url",
]
-[[package]]
-name = "utf-8"
-version = "0.7.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9"
-
[[package]]
name = "utf8_iter"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be"
-[[package]]
-name = "utf8parse"
-version = "0.2.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
-
[[package]]
name = "uuid"
version = "1.26.1"
@@ -9415,17 +7882,11 @@ version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65"
-[[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.0"
+version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "852e951cb7832cb45cb1169900d19760cfa39b82bc0ea9c0e5a14ae88411c98b"
+checksum = "03c2856837ef78f57382f06b2b8563a2f512f7185d732608fd9176cb3b8edf0e"
[[package]]
name = "version_check"
@@ -9480,66 +7941,41 @@ checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
[[package]]
name = "wasip2"
-version = "1.0.0+wasi-0.2.4"
+version = "1.0.4+wasi-0.2.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "03fa2761397e5bd52002cd7e73110c71af2109aca4e521a9f40473fe685b0a24"
+checksum = "b67efb37e106e55ce722a510d6b5f9c17f083e5fc79afc2badeb12cc313d9487"
dependencies = [
"wit-bindgen",
]
-[[package]]
-name = "wasite"
-version = "0.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b"
-
[[package]]
name = "wasm-bindgen"
-version = "0.2.101"
+version = "0.2.128"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7e14915cadd45b529bb8d1f343c4ed0ac1de926144b746e2710f9cd05df6603b"
+checksum = "aecb87a33d3b0c5e3b7aa46336eaf486cffafbd281b195e4c8b80d50df2351bf"
dependencies = [
"cfg-if",
"once_cell",
"rustversion",
- "serde",
- "serde_json",
"wasm-bindgen-macro",
"wasm-bindgen-shared",
]
-[[package]]
-name = "wasm-bindgen-backend"
-version = "0.2.101"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e28d1ba982ca7923fd01448d5c30c6864d0a14109560296a162f80f305fb93bb"
-dependencies = [
- "bumpalo",
- "log",
- "proc-macro2",
- "quote",
- "syn 2.0.106",
- "wasm-bindgen-shared",
-]
-
[[package]]
name = "wasm-bindgen-futures"
-version = "0.4.51"
+version = "0.4.78"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0ca85039a9b469b38336411d6d6ced91f3fc87109a2a27b0c197663f5144dffe"
+checksum = "6ef4c5d3d2cdf5c54f4231181768f5510842e350db025faf1f7163b1030ed928"
dependencies = [
- "cfg-if",
"js-sys",
- "once_cell",
"wasm-bindgen",
- "web-sys",
]
[[package]]
name = "wasm-bindgen-macro"
-version = "0.2.101"
+version = "0.2.128"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7c3d463ae3eff775b0c45df9da45d68837702ac35af998361e2c84e7c5ec1b0d"
+checksum = "a690d511e3c1a8b3a55e33511e3c2c00c78415cd23650f32b808627f5696b9ed"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
@@ -9547,61 +7983,26 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro-support"
-version = "0.2.101"
+version = "0.2.128"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7bb4ce89b08211f923caf51d527662b75bdc9c9c7aab40f86dcb9fb85ac552aa"
+checksum = "411e4887f0071ef2d2164a9d5fdf2d20efbef78fccd3a78b0c10a1dc5295e48a"
dependencies = [
+ "bumpalo",
"proc-macro2",
"quote",
- "syn 2.0.106",
- "wasm-bindgen-backend",
+ "syn 3.0.5",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-shared"
-version = "0.2.101"
+version = "0.2.128"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f143854a3b13752c6950862c906306adb27c7e839f7414cec8fea35beab624c1"
+checksum = "81941cd78d0c92026c33e5e01312845a4cb1e9af3407f9134b100dd03144103e"
dependencies = [
"unicode-ident",
]
-[[package]]
-name = "wasm-bindgen-test"
-version = "0.3.51"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "80cc7f8a4114fdaa0c58383caf973fc126cf004eba25c9dc639bccd3880d55ad"
-dependencies = [
- "js-sys",
- "minicov",
- "wasm-bindgen",
- "wasm-bindgen-futures",
- "wasm-bindgen-test-macro",
-]
-
-[[package]]
-name = "wasm-bindgen-test-macro"
-version = "0.3.51"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c5ada2ab788d46d4bda04c9d567702a79c8ced14f51f221646a16ed39d0e6a5d"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn 2.0.106",
-]
-
-[[package]]
-name = "wasm-logger"
-version = "0.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "074649a66bb306c8f2068c9016395fa65d8e08d2affcbf95acf3c24c3ab19718"
-dependencies = [
- "log",
- "wasm-bindgen",
- "web-sys",
-]
-
[[package]]
name = "wasm-streams"
version = "0.4.2"
@@ -9617,9 +8018,9 @@ dependencies = [
[[package]]
name = "web-sys"
-version = "0.3.78"
+version = "0.3.105"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "77e4b637749ff0d92b8fad63aa1f7cff3cbe125fd49c175cd6345e7272638b12"
+checksum = "9fbddc4a036f00ec4f18c83445bd3115cb306a91da554919a099d9222fe4a7f8"
dependencies = [
"js-sys",
"wasm-bindgen",
@@ -9637,9 +8038,9 @@ dependencies = [
[[package]]
name = "web_atoms"
-version = "0.2.4"
+version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d7cff6eef815df1834fd250e3a2ff436044d82a9f1bc1980ca1dbdf07effc538"
+checksum = "ba8b815c1b593dc0baf78dd0f4fc8fdb2de53198fb1163738093e9a311c33fb3"
dependencies = [
"phf",
"phf_codegen",
@@ -9647,74 +8048,6 @@ dependencies = [
"string_cache_codegen",
]
-[[package]]
-name = "webauthn-attestation-ca"
-version = "0.5.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6475c0bbd1a3f04afaa3e98880408c5be61680c5e6bd3c6f8c250990d5d3e18e"
-dependencies = [
- "base64urlsafedata",
- "openssl",
- "openssl-sys",
- "serde",
- "tracing",
- "uuid",
-]
-
-[[package]]
-name = "webauthn-rs"
-version = "0.5.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6c548915e0e92ee946bbf2aecf01ea21bef53d974b0793cc6732ba81a03fc422"
-dependencies = [
- "base64urlsafedata",
- "serde",
- "tracing",
- "url",
- "uuid",
- "webauthn-rs-core",
-]
-
-[[package]]
-name = "webauthn-rs-core"
-version = "0.5.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "296d2d501feb715d80b8e186fb88bab1073bca17f460303a1013d17b673bea6a"
-dependencies = [
- "base64 0.21.7",
- "base64urlsafedata",
- "der-parser 9.0.0",
- "hex",
- "nom",
- "openssl",
- "openssl-sys",
- "rand 0.9.5",
- "rand_chacha 0.9.0",
- "serde",
- "serde_cbor_2",
- "serde_json",
- "thiserror 1.0.69",
- "tracing",
- "url",
- "uuid",
- "webauthn-attestation-ca",
- "webauthn-rs-proto",
- "x509-parser 0.16.0",
-]
-
-[[package]]
-name = "webauthn-rs-proto"
-version = "0.5.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c37393beac9c1ed1ca6dbb30b1e01783fb316ab3a45d90ecd48c99052dd7ef1e"
-dependencies = [
- "base64 0.21.7",
- "base64urlsafedata",
- "serde",
- "serde_json",
- "url",
-]
-
[[package]]
name = "webkit2gtk"
version = "2.0.2"
@@ -9761,18 +8094,9 @@ dependencies = [
[[package]]
name = "webpki-root-certs"
-version = "0.26.11"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "75c7f0ef91146ebfb530314f5f1d24528d7f0767efbfd31dce919275413e393e"
-dependencies = [
- "webpki-root-certs 1.0.2",
-]
-
-[[package]]
-name = "webpki-root-certs"
-version = "1.0.2"
+version = "1.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4e4ffd8df1c57e87c325000a3d6ef93db75279dc3a231125aac571650f22b12a"
+checksum = "b96554aa2acc8ccdb7e1c9a58a7a68dd5d13bccc69cd124cb09406db612a1c9b"
dependencies = [
"rustls-pki-types",
]
@@ -9783,23 +8107,23 @@ version = "0.26.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "521bc38abb08001b01866da9f51eb7c5d647a19260e00054a8c7fd5f9e57f7a9"
dependencies = [
- "webpki-roots 1.0.3",
+ "webpki-roots 1.0.9",
]
[[package]]
name = "webpki-roots"
-version = "1.0.3"
+version = "1.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "32b130c0d2d49f8b6889abc456e795e82525204f27c42cf767cf0d7734e089b8"
+checksum = "7dcd9d09a39985f5344844e66b0c530a33843579125f23e21e9f0f220850f22a"
dependencies = [
"rustls-pki-types",
]
[[package]]
name = "webview2-com"
-version = "0.38.0"
+version = "0.38.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d4ba622a989277ef3886dd5afb3e280e3dd6d974b766118950a08f8f678ad6a4"
+checksum = "7130243a7a5b33c54a444e54842e6a9e133de08b5ad7b5861cd8ed9a6a5bc96a"
dependencies = [
"webview2-com-macros",
"webview2-com-sys",
@@ -9811,41 +8135,31 @@ dependencies = [
[[package]]
name = "webview2-com-macros"
-version = "0.8.0"
+version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1d228f15bba3b9d56dde8bddbee66fa24545bd17b48d5128ccf4a8742b18e431"
+checksum = "67a921c1b6914c367b2b823cd4cde6f96beec77d30a939c8199bb377cf9b9b54"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.106",
+ "syn 2.0.119",
]
[[package]]
name = "webview2-com-sys"
-version = "0.38.0"
+version = "0.38.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "36695906a1b53a3bf5c4289621efedac12b73eeb0b89e7e1a89b517302d5d75c"
+checksum = "381336cfffd772377d291702245447a5251a2ffa5bad679c99e61bc48bacbf9c"
dependencies = [
"thiserror 2.0.20",
"windows 0.61.3",
"windows-core 0.61.2",
]
-[[package]]
-name = "whoami"
-version = "1.6.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5d4a4db5077702ca3015d3d02d74974948aba2ad9e12ab7df718ee64ccd7e97d"
-dependencies = [
- "libredox",
- "wasite",
-]
-
[[package]]
name = "widestring"
-version = "1.2.0"
+version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dd7cf3379ca1aac9eea11fba24fd7e315d621f8dfe35c8d7d2be8b793726e07d"
+checksum = "72069c3113ab32ab29e5584db3c6ec55d416895e60715417b5b883a357c3e471"
[[package]]
name = "winapi"
@@ -9869,7 +8183,7 @@ version = "0.1.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22"
dependencies = [
- "windows-sys 0.61.0",
+ "windows-sys 0.61.2",
]
[[package]]
@@ -9884,10 +8198,10 @@ version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9bec5a31f3f9362f2258fd0e9c9dd61a9ca432e7306cc78c444258f0dce9a9c"
dependencies = [
- "objc2 0.6.4",
+ "objc2",
"objc2-app-kit",
"objc2-core-foundation",
- "objc2-foundation 0.3.1",
+ "objc2-foundation",
"raw-window-handle",
"windows-sys 0.59.0",
"windows-version",
@@ -9992,7 +8306,7 @@ checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.106",
+ "syn 2.0.119",
]
[[package]]
@@ -10003,7 +8317,7 @@ checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.106",
+ "syn 2.0.119",
]
[[package]]
@@ -10040,13 +8354,13 @@ dependencies = [
[[package]]
name = "windows-registry"
-version = "0.5.3"
+version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5b8a9ed28765efc97bbc954883f4e6796c33a06546ebafacbabee9696967499e"
+checksum = "02752bf7fbdcce7f2a27a742f798510f3e5ad88dbe84871e5168e2120c3d5720"
dependencies = [
- "windows-link 0.1.3",
- "windows-result 0.3.4",
- "windows-strings 0.4.2",
+ "windows-link 0.2.1",
+ "windows-result 0.4.1",
+ "windows-strings 0.5.1",
]
[[package]]
@@ -10094,15 +8408,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"
@@ -10123,18 +8428,9 @@ dependencies = [
[[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.3",
-]
-
-[[package]]
-name = "windows-sys"
-version = "0.61.0"
+version = "0.61.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e201184e40b2ede64bc2ea34968b28e33622acdbbf37104f0e4a33f7abe657aa"
+checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc"
dependencies = [
"windows-link 0.2.1",
]
@@ -10154,21 +8450,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"
@@ -10178,30 +8459,13 @@ 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.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d5fe6031c4041849d7c496a8ded650796e7b6ecc19df1a431c1a363342e5dc91"
-dependencies = [
- "windows-link 0.1.3",
- "windows_aarch64_gnullvm 0.53.0",
- "windows_aarch64_msvc 0.53.0",
- "windows_i686_gnu 0.53.0",
- "windows_i686_gnullvm 0.53.0",
- "windows_i686_msvc 0.53.0",
- "windows_x86_64_gnu 0.53.0",
- "windows_x86_64_gnullvm 0.53.0",
- "windows_x86_64_msvc 0.53.0",
-]
-
[[package]]
name = "windows-threading"
version = "0.1.0"
@@ -10222,9 +8486,9 @@ dependencies = [
[[package]]
name = "windows-version"
-version = "0.1.5"
+version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "69e061eb0a22b4a1d778ad70f7575ec7845490abb35b08fa320df7895882cacb"
+checksum = "e4060a1da109b9d0326b7262c8e12c84df67cc0dbc9e33cf49e01ccc2eb63631"
dependencies = [
"windows-link 0.2.1",
]
@@ -10235,132 +8499,66 @@ 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.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764"
-
[[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.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c"
-
[[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.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3"
-
[[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.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11"
-
[[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.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d"
-
[[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.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba"
-
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.42.2"
@@ -10369,21 +8567,9 @@ 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.0"
+version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57"
+checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
[[package]]
name = "windows_x86_64_msvc"
@@ -10391,24 +8577,12 @@ 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.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486"
-
[[package]]
name = "winnow"
version = "0.5.40"
@@ -10420,12 +8594,9 @@ dependencies = [
[[package]]
name = "winnow"
-version = "0.7.13"
+version = "0.7.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "21a0236b59786fed61e2a80582dd500fe61f18b5dca67a4a067d0bc9039339cf"
-dependencies = [
- "memchr",
-]
+checksum = "df79d97927682d2fd8adb29682d1140b343be4ac0f08fd68b7765d9c059d3945"
[[package]]
name = "winnow"
@@ -10436,16 +8607,6 @@ 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"
@@ -10456,138 +8617,53 @@ dependencies = [
"windows-sys 0.59.0",
]
-[[package]]
-name = "wiremock"
-version = "0.6.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "08db1edfb05d9b3c1542e521aea074442088292f00b5f28e435c714a98f85031"
-dependencies = [
- "assert-json-diff",
- "base64 0.22.1",
- "deadpool 0.12.3",
- "futures",
- "http 1.5.0",
- "http-body-util",
- "hyper",
- "hyper-util",
- "log",
- "once_cell",
- "regex",
- "serde",
- "serde_json",
- "tokio",
- "url",
-]
-
[[package]]
name = "wit-bindgen"
-version = "0.45.1"
+version = "0.57.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5c573471f125075647d03df72e026074b7203790d41351cd6edc96f46bcccd36"
+checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e"
[[package]]
name = "wmi"
-version = "0.17.2"
+version = "0.18.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3d3de777dce4cbcdc661d5d18e78ce4b46a37adc2bb7c0078a556c7f07bcce2f"
+checksum = "7c81b85c57a57500e56669586496bf2abd5cf082b9d32995251185d105208b64"
dependencies = [
"chrono",
"futures",
"log",
"serde",
"thiserror 2.0.20",
- "windows 0.61.3",
- "windows-core 0.61.2",
-]
-
-[[package]]
-name = "worker"
-version = "0.6.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "52e04233d0395832db635283594103c453dab95ec6e33d6897135ff7881479de"
-dependencies = [
- "async-trait",
- "bytes",
- "chrono",
- "futures-channel",
- "futures-util",
- "http 1.5.0",
- "http-body",
- "js-sys",
- "matchit 0.7.3",
- "pin-project",
- "serde",
- "serde-wasm-bindgen",
- "serde_json",
- "serde_urlencoded",
- "tokio",
- "url",
- "wasm-bindgen",
- "wasm-bindgen-futures",
- "wasm-streams",
- "web-sys",
- "worker-kv",
- "worker-macros",
- "worker-sys",
-]
-
-[[package]]
-name = "worker-kv"
-version = "0.9.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b0d30eb90e8db0657414129624c0d12c6cb480574bc2ddd584822db196cb9a52"
-dependencies = [
- "js-sys",
- "serde",
- "serde-wasm-bindgen",
- "serde_json",
- "thiserror 2.0.20",
- "wasm-bindgen",
- "wasm-bindgen-futures",
-]
-
-[[package]]
-name = "worker-macros"
-version = "0.6.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3dc794c1a9509cbf9df713944227a1097f4bd70d8fed8f4866cb1c1c81eca48d"
-dependencies = [
- "async-trait",
- "proc-macro2",
- "quote",
- "syn 2.0.106",
- "wasm-bindgen",
- "wasm-bindgen-futures",
- "wasm-bindgen-macro-support",
- "worker-sys",
+ "windows 0.62.2",
+ "windows-core 0.62.2",
]
[[package]]
-name = "worker-sys"
-version = "0.6.1"
+name = "wnaf"
+version = "0.14.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "622487961193b4421cc0b1eee3a158164c958a1bd0731ff535e2c4a5dd2af30f"
+checksum = "795ca18b3fdb5e62bf982199278341ddcf7ebf7d32e25e212ad05d496e95f6fa"
dependencies = [
- "cfg-if",
- "js-sys",
- "wasm-bindgen",
- "web-sys",
+ "ff 0.14.0",
+ "group 0.14.0",
+ "hybrid-array",
+ "primefield",
]
[[package]]
name = "writeable"
-version = "0.6.1"
+version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb"
+checksum = "3ad82d2a33cdc9674dc7465672f271e096168fcdbe0f799d9e6db8c5892679dc"
[[package]]
name = "wry"
-version = "0.55.0"
+version = "0.55.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3013fd6116aac351dd2e18f349b28b2cfef3a5ff3253a9d0ce2d7193bb1b4429"
+checksum = "186f9871daa55fd9c016578b810d149de58367113db7fb72b462d2323ce19514"
dependencies = [
"base64 0.22.1",
- "block2 0.6.1",
+ "block2",
"cookie",
"crossbeam-channel",
"dirs",
@@ -10596,15 +8672,15 @@ dependencies = [
"dunce",
"gdkx11",
"gtk",
- "http 1.5.0",
+ "http",
"javascriptcore-rs",
- "jni",
+ "jni 0.21.1",
"libc",
"ndk",
- "objc2 0.6.4",
+ "objc2",
"objc2-app-kit",
"objc2-core-foundation",
- "objc2-foundation 0.3.1",
+ "objc2-foundation",
"objc2-ui-kit",
"objc2-web-kit",
"once_cell",
@@ -10665,45 +8741,32 @@ dependencies = [
]
[[package]]
-name = "x509-parser"
-version = "0.16.0"
+name = "x25519-dalek"
+version = "3.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fcbc162f30700d6f3f82a24bf7cc62ffe7caea42c0b2cba8bf7f3ae50cf51f69"
+checksum = "e7e8131a03190127fb2263afc72b322ecadae46b6ff8c6f399ff5d02f5559af6"
dependencies = [
- "asn1-rs 0.6.2",
- "data-encoding",
- "der-parser 9.0.0",
- "lazy_static",
- "nom",
- "oid-registry 0.7.1",
- "rusticata-macros",
- "thiserror 1.0.69",
- "time",
+ "curve25519-dalek",
+ "rand_core 0.10.1",
+ "zeroize",
]
[[package]]
-name = "x509-parser"
-version = "0.18.1"
+name = "x509-cert"
+version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d43b0f71ce057da06bc0851b23ee24f3f86190b07203dd8f567d0b706a185202"
+checksum = "1301e935010a701ae5f8655edc0ad17c44bad3ac5ce8c39185f75453b720ae94"
dependencies = [
- "asn1-rs 0.7.1",
- "data-encoding",
- "der-parser 10.0.0",
- "lazy_static",
- "nom",
- "oid-registry 0.8.1",
- "ring",
- "rusticata-macros",
- "thiserror 2.0.20",
- "time",
+ "const-oid 0.9.6",
+ "der 0.7.10",
+ "spki 0.7.3",
]
[[package]]
name = "xml-rs"
-version = "0.8.27"
+version = "0.8.29"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6fd8403733700263c6eb89f192880191f1b83e332f7a20371ddcf421c4a337c7"
+checksum = "e450f9b2ed1dff33c94c12589a87338689467b9c4f5d8a5710bd09a847d2c8a7"
[[package]]
name = "xmltree"
@@ -10714,100 +8777,12 @@ dependencies = [
"xml-rs",
]
-[[package]]
-name = "yaml-rust2"
-version = "0.11.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b36710ce3a279cfce8465dbab826f161675a262950b922cb2c3663852dfe9eb0"
-dependencies = [
- "arraydeque",
- "encoding_rs",
- "hashlink 0.11.1",
-]
-
-[[package]]
-name = "yasna"
-version = "0.6.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b5f6765e852b9b4dc8e2a76843e4d64d1cea8e79bcde0b6901aea8e7c7f08282"
-dependencies = [
- "bit-vec 0.9.1",
- "time",
-]
-
-[[package]]
-name = "yew"
-version = "0.21.0"
-source = "git+https://github.com/yewstack/yew#b7a599b9e4879fce18d0a3f3cbbe7c0d526e9f2d"
-dependencies = [
- "console_error_panic_hook",
- "futures",
- "gloo",
- "implicit-clone",
- "indexmap 2.12.0",
- "js-sys",
- "rustversion",
- "serde",
- "slab",
- "thiserror 2.0.20",
- "tokio",
- "tokise",
- "tracing",
- "wasm-bindgen",
- "wasm-bindgen-futures",
- "web-sys",
- "yew-macro",
-]
-
-[[package]]
-name = "yew-macro"
-version = "0.21.0"
-source = "git+https://github.com/yewstack/yew#b7a599b9e4879fce18d0a3f3cbbe7c0d526e9f2d"
-dependencies = [
- "once_cell",
- "prettyplease",
- "proc-macro-error",
- "proc-macro2",
- "quote",
- "rustversion",
- "syn 2.0.106",
-]
-
-[[package]]
-name = "yew-router"
-version = "0.18.0"
-source = "git+https://github.com/yewstack/yew#b7a599b9e4879fce18d0a3f3cbbe7c0d526e9f2d"
-dependencies = [
- "gloo",
- "js-sys",
- "route-recognizer",
- "serde",
- "serde_urlencoded",
- "tracing",
- "urlencoding",
- "wasm-bindgen",
- "web-sys",
- "yew",
- "yew-router-macro",
-]
-
-[[package]]
-name = "yew-router-macro"
-version = "0.18.0"
-source = "git+https://github.com/yewstack/yew#b7a599b9e4879fce18d0a3f3cbbe7c0d526e9f2d"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn 2.0.106",
-]
-
[[package]]
name = "yoke"
-version = "0.8.0"
+version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5f41bb01b8226ef4bfd589436a297c53d118f65921786300e427be8d487695cc"
+checksum = "709fe23a0424b6a435d82152b1bd3fdfb0833487d5fa90d05d42762a9891fef5"
dependencies = [
- "serde",
"stable_deref_trait",
"yoke-derive",
"zerofrom",
@@ -10815,148 +8790,82 @@ dependencies = [
[[package]]
name = "yoke-derive"
-version = "0.8.0"
+version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6"
+checksum = "33811428bee40dbceb6d545e95754741d17a6aef9a4849f0fd62e2ba4f412a78"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.106",
+ "syn 3.0.5",
"synstructure",
]
-[[package]]
-name = "z32"
-version = "1.3.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2164e798d9e3d84ee2c91139ace54638059a3b23e361f5c11781c2c6459bde0f"
-
-[[package]]
-name = "zbus"
-version = "5.11.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2d07e46d035fb8e375b2ce63ba4e4ff90a7f73cf2ffb0138b29e1158d2eaadf7"
-dependencies = [
- "async-broadcast",
- "async-executor",
- "async-io",
- "async-lock",
- "async-process",
- "async-recursion",
- "async-task",
- "async-trait",
- "blocking",
- "enumflags2",
- "event-listener",
- "futures-core",
- "futures-lite",
- "hex",
- "nix",
- "ordered-stream",
- "serde",
- "serde_repr",
- "tracing",
- "uds_windows",
- "windows-sys 0.60.2",
- "winnow 0.7.13",
- "zbus_macros",
- "zbus_names",
- "zvariant",
-]
-
-[[package]]
-name = "zbus_macros"
-version = "5.11.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "57e797a9c847ed3ccc5b6254e8bcce056494b375b511b3d6edcec0aeb4defaca"
-dependencies = [
- "proc-macro-crate 3.3.0",
- "proc-macro2",
- "quote",
- "syn 2.0.106",
- "zbus_names",
- "zvariant",
- "zvariant_utils",
-]
-
-[[package]]
-name = "zbus_names"
-version = "4.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7be68e64bf6ce8db94f63e72f0c7eb9a60d733f7e0499e628dfab0f84d6bcb97"
-dependencies = [
- "serde",
- "static_assertions",
- "winnow 0.7.13",
- "zvariant",
-]
-
[[package]]
name = "zerocopy"
-version = "0.8.27"
+version = "0.8.57"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0894878a5fa3edfd6da3f88c4805f4c8558e2b996227a3d864f47fe11e38282c"
+checksum = "d35102a9f36d089ccae9e4c6802bc118be4487b80aaffc0ab4e0cf5ce92d2873"
dependencies = [
"zerocopy-derive",
]
[[package]]
name = "zerocopy-derive"
-version = "0.8.27"
+version = "0.8.57"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "88d2b8d9c68ad2b9e4340d7832716a4d21a22a1154777ad56ea55c51a9cf3831"
+checksum = "146c01f5ab44258da43cf276c74a2763db2ff3969c9c652c3f2de07041d0b2bc"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.106",
+ "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.106",
+ "syn 3.0.5",
"synstructure",
]
[[package]]
name = "zeroize"
-version = "1.8.2"
+version = "1.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0"
+checksum = "e13c156562582aa81c60cb29407084cdb54c4164760106ab78e6c5b0858cf64e"
dependencies = [
"zeroize_derive",
]
[[package]]
name = "zeroize_derive"
-version = "1.4.2"
+version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69"
+checksum = "3c50655cbb0fe3fc43170059e702f1ce5e19b84cec58dc87b037a09935c2f328"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.106",
+ "syn 2.0.119",
]
[[package]]
name = "zerotrie"
-version = "0.2.2"
+version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "36f0bbd478583f79edad978b407914f61b2972f5af6fa089686016be8f9af595"
+checksum = "4ea269c3bd32f0a32c321907a2ae912ba6f4649bb0fc764a15627e99a7095a3f"
dependencies = [
"displaydoc",
"yoke",
@@ -10965,9 +8874,9 @@ dependencies = [
[[package]]
name = "zerovec"
-version = "0.11.4"
+version = "0.11.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e7aa2bd55086f1ab526693ecbe444205da57e25f4489879da80635a46d90e73b"
+checksum = "bb0464e17806c1d976d5cba29399c7f08e516e279e2ba493f63123b5fca67dd8"
dependencies = [
"yoke",
"zerofrom",
@@ -10976,85 +8885,23 @@ dependencies = [
[[package]]
name = "zerovec-derive"
-version = "0.11.1"
+version = "0.11.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f"
+checksum = "34df6fc39dbd26ddc9c10e6a2984476e13acce22e64e4487636ef494369225da"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.106",
-]
-
-[[package]]
-name = "zmij"
-version = "1.0.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0f4a4e8e9dc5c62d159f04fcdbe07f4c3fb710415aab4754bf11505501e3251d"
-
-[[package]]
-name = "zstd"
-version = "0.13.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e91ee311a569c327171651566e07972200e76fcfe2242a4fa446149a3881c08a"
-dependencies = [
- "zstd-safe",
-]
-
-[[package]]
-name = "zstd-safe"
-version = "7.2.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8f49c4d5f0abb602a93fb8736af2a4f4dd9512e36f7f570d66e65ff867ed3b9d"
-dependencies = [
- "zstd-sys",
-]
-
-[[package]]
-name = "zstd-sys"
-version = "2.0.16+zstd.1.5.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "91e19ebc2adc8f83e43039e79776e3fda8ca919132d68a1fed6a5faca2683748"
-dependencies = [
- "cc",
- "pkg-config",
+ "syn 3.0.5",
]
[[package]]
-name = "zvariant"
-version = "5.7.0"
+name = "zlib-rs"
+version = "0.6.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "999dd3be73c52b1fccd109a4a81e4fcd20fab1d3599c8121b38d04e1419498db"
-dependencies = [
- "endi",
- "enumflags2",
- "serde",
- "winnow 0.7.13",
- "zvariant_derive",
- "zvariant_utils",
-]
-
-[[package]]
-name = "zvariant_derive"
-version = "5.7.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6643fd0b26a46d226bd90d3f07c1b5321fe9bb7f04673cb37ac6d6883885b68e"
-dependencies = [
- "proc-macro-crate 3.3.0",
- "proc-macro2",
- "quote",
- "syn 2.0.106",
- "zvariant_utils",
-]
+checksum = "b268e58e7c693d7c271f93ffc4ba3b380412554231c85bf61ca7af91042a4112"
[[package]]
-name = "zvariant_utils"
-version = "3.2.1"
+name = "zmij"
+version = "1.0.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c6949d142f89f6916deca2232cf26a8afacf2b9fdc35ce766105e104478be599"
-dependencies = [
- "proc-macro2",
- "quote",
- "serde",
- "syn 2.0.106",
- "winnow 0.7.13",
-]
+checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b"
diff --git a/Cargo.toml b/Cargo.toml
index f825042d..f4a19bf2 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,22 +1,7 @@
[workspace]
resolver = "2"
-members = [
- "crates/chat-ui",
- "crates/chat-ui/examples/trunk-demo",
- "crates/core",
- "crates/daemon",
- "crates/fixtures",
- "crates/frontend-common",
- "crates/frontend-daemon",
- "crates/frontend-relay",
- "crates/frontend-tauri",
- "crates/gui",
- "crates/http",
- "crates/p2p",
- "crates/tlsforward",
- "crates/sqlx",
-]
-default-members = ["crates/daemon"]
+members = ["src-tauri"]
+default-members = ["src-tauri"]
[workspace.package]
version = "0.1.0"
@@ -24,125 +9,9 @@ edition = "2024"
authors = ["Hellas AI "]
license = "MIT OR Apache-2.0"
repository = "https://github.com/hellas-ai/gate"
-keywords = ["ai", "gateway", "inference", "llm", "api"]
-categories = ["network-programming", "web-programming"]
-
-[workspace.dependencies]
-openssl = { version = "0.10", features = ["vendored"] }
-anyhow = "1.0"
-arc-swap = "1.7"
-async-trait = "0.1"
-
-# Web framework
-axum = { version = "0.8", default-features = false, features = ["json", "macros", "matched-path", "query", "tokio", "http1", "http2"] }
-base64 = "0.23"
-bytes = "1.11"
-chrono = { version = "0.4", features = ["serde"] }
-
-# CLI parsing
-clap = { version = "4", features = ["derive"] }
-
-# Configuration
-config = { version = "0.15", features = ["yaml", "toml"] }
-directories = "6"
-futures = "0.3"
-
-# Internal crates
-gate-core = { path = "crates/core" }
-gate-frontend-common = { path = "crates/frontend-common" }
-gate-frontend-daemon = { path = "crates/frontend-daemon" }
-gate-frontend-relay = { path = "crates/frontend-relay" }
-gate-frontend-tauri = { path = "crates/frontend-tauri" }
-gate-http = { path = "crates/http" }
-gate-p2p = { path = "crates/p2p" }
-gate-tlsforward = { path = "crates/tlsforward" }
-gate-sqlx = { path = "crates/sqlx" }
-hex = "0.4"
-http = "1.4"
-hyper = "1.10"
-hyper-util = { version = "*", default-features = false }
-iroh = { version = "0.95", default-features = false, features = ["discovery-local-network"] }
-
-# Testing
-mockall = "0.15"
-
-# Platform-specific (file watching)
-notify = "6.1"
-
-# Random
-getrandom = { version = "0.4", default-features=false, features = ["wasm_js"] }
-rand = { version = "0.9", features = ["std", "std_rng"] }
-rust_decimal = { version = "1.42", features = ["serde"] }
-
-# Serialization
-serde = { version = "1.0", features = ["derive"] }
-serde_json = "1.0"
-serde_with = "3.17"
-sha2 = "0.10"
-
-# Error handling
-thiserror = "2.0"
-
-# Core async runtime
-tokio = { version = "1", default-features = false, features = ["sync", "time", "macros"] }
-tokio-util = "0.7"
-toml = "0.9"
-tower = { version = "0.5", features = ["util"] }
-tower-http = { version = "0.7", features = ["trace", "cors", "timeout"] }
-tower-service = "0.3"
-
-# Logging and tracing
-tracing = "0.1"
-tracing-subscriber = { version = "0.3", features = ["env-filter", "json"] }
-
-url = { version = "2.5", features = ["serde"] }
-
-# Frontend
-yew = { git = "https://github.com/yewstack/yew", default-features = false }
-yew-router = { git = "https://github.com/yewstack/yew", default-features = false }
-wasm-bindgen = { version = "0.2", default-features = false }
-wasm-bindgen-futures = { version = "0.4", default-features = false }
-web-sys = { version = "0.3", default-features = false }
-js-sys = { version = "0.3", default-features = false }
-gloo = { version = "0.11", default-features = false }
-gloo-timers = { version = "0.3", default-features = false }
-gloo-utils = { version = "0.2", default-features = false }
-gloo-events = { version = "0.2", default-features = false }
-gloo-net = { version = "0.6", default-features = false }
-wasm-logger = { version = "0.2", default-features = false }
-tracing-web = { version = "0.1", default-features = false }
-serde-wasm-bindgen = { version = "0.6", default-features = false }
-
-# Utilities
-uuid = { version = "1.23", features = ["v4", "serde", "js"] }
-webauthn-rs = { version = "0.5" }
-wiremock = "0.6"
-wasm-bindgen-test = { version = "0.3", default-features = false }
-console_error_panic_hook = { version = "0.1", default-features = false }
-
-[workspace.lints.rust]
-unsafe_code = "warn"
-unused_imports = "warn"
-unused_variables = "warn"
-dead_code = "warn"
-
-[workspace.lints.clippy]
-all = "warn"
-pedantic = "warn"
-nursery = "warn"
[profile.release]
-lto = "fat" # Enable full link-time optimization for maximum performance
-codegen-units = 1 # Use single codegen unit for better optimization (slower compile)
-strip = true # Strip debug symbols for smaller binaries
-panic = "abort" # Use abort instead of unwind for smaller binaries
-opt-level = 3 # Maximum optimization level
-overflow-checks = false # Disable overflow checks in release for performance
-debug = false # Ensure no debug info (strip should handle this too)
-
-# Optional: Create a profile for maximum size optimization (useful for WASM)
-[profile.release-min-size]
-inherits = "release"
-opt-level = "z" # Optimize for size instead of speed
-lto = "fat" # Still use LTO for size reduction
-strip = true # Strip all symbols
+lto = "thin"
+codegen-units = 1
+strip = true
+panic = "abort"
diff --git a/Makefile b/Makefile
index 41098a9e..2d522385 100644
--- a/Makefile
+++ b/Makefile
@@ -1,270 +1,20 @@
-# Gate Project Makefile
-# Comprehensive build, test, and development commands
+.PHONY: bindings check dev ui-check ui-build
-# Variables
-CARGO = cargo
-TRUNK = trunk
-TAURI = cargo tauri
-RUST_LOG ?= info
-RUST_BACKTRACE ?= 1
+export CARGO_TARGET_DIR ?= /tmp/hellas-gate-target
-# Detect OS
-UNAME_S := $(shell uname -s)
-ifeq ($(UNAME_S),Darwin)
- OPEN_CMD = open
-else
- OPEN_CMD = xdg-open
-endif
+bindings:
+ cargo test --locked -p hellas-gate --lib export_bindings
-# Colors for output
-RED = \033[0;31m
-GREEN = \033[0;32m
-YELLOW = \033[0;33m
-BLUE = \033[0;34m
-NC = \033[0m # No Color
+check: bindings ui-build
+ cargo fmt --all -- --check
+ cargo clippy --locked --workspace --all-targets -- -D warnings
+ cargo test --locked --workspace
-# Default target
-.DEFAULT_GOAL := help
+ui-check:
+ tsc --noEmit -p ui/tsconfig.json
-# Phony targets
-.PHONY: help build dev run clean test test-unit test-integration lint fmt fmt-check check audit \
- frontend-build-dev frontend-build frontend-clean frontend-dev \
- frontend-daemon-dev frontend-daemon-build \
- frontend-tauri-dev frontend-tauri-build frontend-relay-dev frontend-relay-build \
- gui-dev gui-build gui-build-dev gui-build-dmg \
- docs docs-deps ci pre-commit db-migrate db-reset server p2p tlsforward all-services
+dev:
+ cargo tauri dev
-## Help
-help: ## Show this help message
- @echo "$(BLUE)Gate Project Makefile$(NC)"
- @echo "$(YELLOW)Usage:$(NC) make [target]"
- @echo ""
- @echo "$(GREEN)Available targets:$(NC)"
- @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf " $(BLUE)%-20s$(NC) %s\n", $$1, $$2}'
- @echo ""
- @echo "$(YELLOW)Examples:$(NC)"
- @echo " make build # Build all crates in release mode"
- @echo " make test # Run all tests"
- @echo " make frontend-dev # Start frontend development server"
- @echo " make gui-build # Build native desktop app"
-
-## Building
-build: ## Build all crates in release mode
- @echo "$(GREEN)Building all crates in release mode...$(NC)"
- $(CARGO) build --release --all
-
-dev: ## Build all crates in debug mode
- @echo "$(GREEN)Building all crates in debug mode...$(NC)"
- $(CARGO) build --all
-
-run: ## Run the Gate server
- @echo "$(GREEN)Starting Gate server...$(NC)"
- RUST_LOG=$(RUST_LOG) $(CARGO) run --bin gate
-
-clean: ## Clean all build artifacts
- @echo "$(RED)Cleaning build artifacts...$(NC)"
- $(CARGO) clean
- rm -rf crates/frontend-daemon/dist/*
- rm -rf crates/frontend-tauri/dist/*
- rm -rf crates/frontend-relay/dist/*
- rm -f crates/frontend-daemon/assets/tailwind.output.css
- rm -f crates/frontend-tauri/assets/tailwind.output.css
- rm -f crates/frontend-relay/assets/tailwind.output.css
-
-## Testing & Quality
-test: ## Run all tests
- @echo "$(GREEN)Running all tests...$(NC)"
- $(CARGO) test --all --all-features
-
-test-unit: ## Run unit tests only
- @echo "$(GREEN)Running unit tests...$(NC)"
- $(CARGO) test --lib --all
-
-test-integration: ## Run integration tests only
- @echo "$(GREEN)Running integration tests...$(NC)"
- $(CARGO) test --test '*' --all
-
-lint: ## Run clippy on all crates
- @echo "$(YELLOW)Running clippy...$(NC)"
- $(CARGO) clippy --all --all-targets --all-features -- -D warnings
-
-fmt: ## Format all code with rustfmt
- @echo "$(GREEN)Formatting code...$(NC)"
- $(CARGO) fmt --all
-
-fmt-check: ## Check formatting without making changes
- @echo "$(YELLOW)Checking code formatting...$(NC)"
- $(CARGO) fmt --all -- --check
-
-check: ## Run cargo check on all crates
- @echo "$(YELLOW)Running cargo check...$(NC)"
- $(CARGO) check --all --all-features
-
-audit: ## Security audit of dependencies
- @echo "$(YELLOW)Running security audit...$(NC)"
- $(CARGO) audit
-
-
-## Frontend (alias for frontend-daemon)
-frontend-dev: frontend-daemon-dev ## Run frontend development server (alias for frontend-daemon-dev)
-
-frontend-build: frontend-daemon-build ## Build frontend for production (alias for frontend-daemon-build)
-
-frontend-build-dev: ## Build frontend for development
- @echo "$(GREEN)Building frontend for development...$(NC)"
- cd crates/frontend-daemon && $(TRUNK) build
-
-frontend-clean: ## Clean frontend build artifacts
- @echo "$(RED)Cleaning frontend artifacts...$(NC)"
- rm -rf crates/frontend-daemon/dist/*
- rm -f crates/frontend-daemon/assets/tailwind.output.css
-
-## Frontend - Daemon
-frontend-daemon-dev: ## Run daemon frontend development server
- @echo "$(GREEN)Starting daemon frontend dev server on http://localhost:8081...$(NC)"
- cd crates/frontend-daemon && $(TRUNK) serve
-
-frontend-daemon-build: ## Build daemon frontend for production
- @echo "$(GREEN)Building daemon frontend for production...$(NC)"
- cd crates/frontend-daemon && $(TRUNK) build --release
-
-## Frontend - Tauri
-frontend-tauri-dev: ## Run Tauri frontend development server
- @echo "$(GREEN)Starting Tauri frontend dev server on http://localhost:8081...$(NC)"
- cd crates/frontend-tauri && $(TRUNK) serve
-
-frontend-tauri-build: ## Build Tauri frontend for production
- @echo "$(GREEN)Building Tauri frontend for production...$(NC)"
- cd crates/frontend-tauri && $(TRUNK) build --release
-
-## Frontend - Relay
-frontend-relay-dev: ## Run relay frontend development server
- @echo "$(GREEN)Starting relay frontend dev server on http://localhost:8081...$(NC)"
- cd crates/frontend-relay && $(TRUNK) serve
-
-frontend-relay-build: ## Build relay frontend for production
- @echo "$(GREEN)Building relay frontend for production...$(NC)"
- cd crates/frontend-relay && $(TRUNK) build --release
-
-## GUI/Tauri
-gui-dev: ## Run Tauri in development mode
- @echo "$(GREEN)Starting Tauri development mode...$(NC)"
- cd crates/gui && $(TAURI) dev
-
-gui-build: ## Build native desktop app
- @echo "$(GREEN)Building native desktop app...$(NC)"
- cd crates/gui && $(TAURI) build
-
-gui-build-dev: ## Build native desktop app in debug mode (faster)
- @echo "$(GREEN)Building native desktop app (debug mode)...$(NC)"
- cd crates/gui && $(TAURI) build --debug
-
-gui-build-dmg: ## Build macOS DMG installer (macOS only)
-ifeq ($(UNAME_S),Darwin)
- @echo "$(GREEN)Building macOS DMG installer...$(NC)"
- cd crates/gui && $(TAURI) build --bundles dmg
-else
- @echo "$(RED)DMG building is only available on macOS$(NC)"
- @exit 1
-endif
-
-## Documentation
-docs: ## Generate and open documentation
- @echo "$(GREEN)Generating documentation...$(NC)"
- $(CARGO) doc --all --no-deps --open
-
-docs-deps: ## Generate dependency graph
- @echo "$(GREEN)Generating dependency graph...$(NC)"
- $(CARGO) depgraph --all-deps | dot -Tpng > target/dependencies.png
- @echo "$(GREEN)Dependency graph saved to target/dependencies.png$(NC)"
- $(OPEN_CMD) target/dependencies.png
-
-## CI/CD
-ci: fmt-check lint test ## Run all CI checks
- @echo "$(GREEN)All CI checks passed!$(NC)"
-
-pre-commit: fmt lint test-unit ## Run checks before committing
- @echo "$(GREEN)Pre-commit checks passed!$(NC)"
-
-## Database
-db-migrate: ## Run database migrations
- @echo "$(GREEN)Running database migrations...$(NC)"
- cd crates/sqlx && sqlx migrate run
-
-db-reset: ## Reset database
- @echo "$(RED)Resetting database...$(NC)"
- rm -f gate.db gate.db-shm gate.db-wal
- @echo "$(GREEN)Database reset. Run 'make db-migrate' to recreate.$(NC)"
-
-## Services
-server: ## Run the main server
- @echo "$(GREEN)Starting Gate server...$(NC)"
- RUST_LOG=$(RUST_LOG) $(CARGO) run --bin gate
-
-p2p: ## Run P2P service (if available)
- @echo "$(YELLOW)P2P service is a library, not a binary. Use it as a dependency.$(NC)"
-
-tlsforward: ## Run TLS forward service
- @echo "$(GREEN)Starting TLS forward service...$(NC)"
- RUST_LOG=$(RUST_LOG) $(CARGO) run --bin gate-tlsforward
-
-all-services: ## Run all services (requires multiple terminals)
- @echo "$(YELLOW)Starting all services...$(NC)"
- @echo "$(YELLOW)This requires multiple terminal windows.$(NC)"
- @echo ""
- @echo "Run these commands in separate terminals:"
- @echo " 1. make server"
- @echo " 2. make frontend-dev"
- @echo " 3. make tlsforward (if needed)"
-
-## Workspace Management
-workspace-check: ## Check workspace configuration
- @echo "$(YELLOW)Checking workspace configuration...$(NC)"
- @echo "Workspace members:"
- @grep -A20 "members = \[" Cargo.toml | grep -E '^\s*"' | sed 's/[",]//g' | sed 's/^/ /'
- @echo ""
- @echo "Default members:"
- @grep "default-members" Cargo.toml | sed 's/.*= //'
-
-## Advanced
-bench: ## Run benchmarks
- @echo "$(GREEN)Running benchmarks...$(NC)"
- $(CARGO) bench --all
-
-coverage: ## Generate test coverage report
- @echo "$(GREEN)Generating test coverage...$(NC)"
- $(CARGO) tarpaulin --all --out Html
- $(OPEN_CMD) tarpaulin-report.html
-
-update-deps: ## Update dependencies
- @echo "$(YELLOW)Updating dependencies...$(NC)"
- $(CARGO) update
- cd crates/frontend && npm update
-
-check-updates: ## Check for outdated dependencies
- @echo "$(YELLOW)Checking for outdated dependencies...$(NC)"
- $(CARGO) outdated
-
-## Quick Commands
-quick: dev ## Quick build for development
- @echo "$(GREEN)Quick build complete!$(NC)"
-
-watch: ## Watch for changes and rebuild
- @echo "$(GREEN)Watching for changes...$(NC)"
- cargo watch -x check -x test -x run
-
-## Release
-release-patch: ## Create a patch release
- @echo "$(YELLOW)Creating patch release...$(NC)"
- cargo release patch
-
-release-minor: ## Create a minor release
- @echo "$(YELLOW)Creating minor release...$(NC)"
- cargo release minor
-
-release-major: ## Create a major release
- @echo "$(YELLOW)Creating major release...$(NC)"
- cargo release major
-
-docker-ci:
- act -j gui-build -P ubuntu-latest=catthehacker/ubuntu:act-latest --matrix os:ubuntu-latest
+ui-build: ui-check
+ node ui/build.mjs
diff --git a/README.md b/README.md
index 32768aba..24aca725 100644
--- a/README.md
+++ b/README.md
@@ -1,31 +1,80 @@
-
-
gate
+# Hellas Gate
-
-[![License][license_img]][license_file]
-
+Gate is the small native desktop host for Hellas. It is one Tauri process and
+one vanilla TypeScript UI. There is no companion daemon, internal HTTP control
+plane, browser-side Rust, or second implementation of the Hellas protocol.
-
+The native process wires together the reusable pieces in `../hellas`:
+- a verified sealed-Fetch client with a stable caller and transport identity;
+- an Apple App Attest OpenAI Responses provider;
+- a bearer-protected `/v1/responses` gateway bound to loopback;
+- private SQLite execution history; and
+- a same-user Unix control socket carrying the existing Hellas mux and the
+ `HostControl` protobuf service.
-_Hellas Gate_ is a user-aligned llm inference server/proxy/router
+The only platform-specific protocol producer is the DeviceCheck bridge in
+`src-tauri/src/apple_app_attest.m`. The generic attestation boundary and the
+portable Apple verifier live in `hellas-attestation`. Provider and gateway
+runtimes live behind `hellas-sdk`; Gate contains only lifecycle and UI policy.
-# in-progress
-some of most of this exists, read as a wishlist rather than supported though
+The Rust/TypeScript seam is deliberately local and narrow. Rust DTOs derive
+TypeScript definitions with `ts-rs`, while `ui/src/api.ts` is the sole module
+allowed to invoke Tauri commands. The reusable non-UI seam is the `HostControl`
+protobuf service over any Hellas transport, including the local Unix transport.
+There is no npm package and no package publication in this repository.
-- Private local inference via built-in [`catgrad`](https://github.com/hellas-ai/catgrad) engine
-- End-to-end encrypted peer-to-peer mesh overlay to aggregate capacity across networked nodes
-- Use [LetsEncrypt](https://letsencrypt.org/) to generate a private cert for a public `https://.private.hellas.ai` endpoint, Hellas will relay it over p2p
-- Upstream support for any openai/anthropic-compatible providers, openrouter, vllm, ollama etc
-- Supports [Cursor](https://cursor.ai), [Codex](https://github.com/openai/codex) and [Claude-Code](http://rickroll.com), open-webui, charm, etc via local http server
-- API key management, cost-tracking, rate-limiting, quotas, permissions, etc
-- Smart router can optimize routing for cost, latency, etc via 'virtual models'
-- Capture/Log/Export all requests, responses, metadata through the gateway
+## Local development
-# future
-- Once [`catgrad`](https://github.com/hellas-ai/catgrad) ZK backend is implemented, we can support _verifying responses_- check request was serviced correctly without quantization, context injection, tampered weights, etc
-- Once [`protoproto`](https://github.com/hellas-ai/protoproto) consensus protocol is implemented, we can support settlement and thus create _decentralized_, _trustless and permissionless_ markets for llm inference
+The flake is the canonical environment. It supplies Rust, Tauri, TypeScript,
+esbuild, and Node directly; there is no npm manifest, `npm install`, or
+`node_modules` directory. Rust 1.96.1 is shared with the pinned Hellas workspace.
+Rust and frontend build output both stay under `/tmp`, off this shared checkout.
+Set `CARGO_TARGET_DIR` to override the Rust output location; the flake, Makefile,
+and CI all respect it.
-[license_file]: https://github.com/hellas-ai/gate/blob/master/LICENSE "Project license"
-[license_img]: https://img.shields.io/crates/l/gate.svg?style=for-the-badge "License badge"
+Gate uses local path dependencies from a sibling Hellas checkout. From a fresh
+Gate clone, prepare the exact published revision recorded in `.hellas-revision`:
+```sh
+git clone https://github.com/hellas-ai/hellas.git ../hellas
+git -C ../hellas checkout --detach "$(cat .hellas-revision)"
+```
+
+If `../hellas` already contains your work, keep it intact and create a separate
+parent directory with sibling `gate` and `hellas` checkouts for the pinned build.
+CI uses the same revision and layout. To update Hellas deliberately, change
+`.hellas-revision`, reconcile the desktop SDK calls, and regenerate `Cargo.lock`
+against that checkout.
+
+Then run:
+
+```sh
+nix develop
+make check
+make dev
+```
+
+`make check` runs binding generation, frontend typechecking and production
+bundling, Rust formatting, warnings-as-errors Clippy, and Rust tests with the
+checked-in lockfile. Gate's old router, daemon, relay, TLS forwarder, and
+Rust/Wasm frontend have intentionally been removed; equivalent protocol
+behavior must be added to Hellas rather than copied back into this app.
+
+## Local data and secrets
+
+Gate stores its stable identity, App Attest enrollment, assertion counters,
+provider quota/transcript state, and history below Tauri's private application
+data directory. Identity files and the Unix socket are owner-only. The OpenAI
+API key crosses the typed Tauri IPC seam once and is retained only in native
+memory for the active provider run. The loopback gateway generates a fresh
+bearer whenever it starts.
+
+## Apple App Attest
+
+The ordinary desktop build carries no restricted entitlement, so it launches
+without an Apple provisioning profile and reports App Attest as unavailable.
+An attested provider requires a separately provisioned and signed build whose
+profile matches the app bundle identifier and grants the App Attest `CDhash`
+entitlement. Gate never substitutes software assurance. See
+`docs/SIGNING.md` for the two build modes and their provisioning boundary.
diff --git a/crates/chat-ui/Cargo.toml b/crates/chat-ui/Cargo.toml
deleted file mode 100644
index be7e3b5d..00000000
--- a/crates/chat-ui/Cargo.toml
+++ /dev/null
@@ -1,49 +0,0 @@
-[package]
-name = "gate-chat-ui"
-version.workspace = true
-edition.workspace = true
-authors.workspace = true
-license.workspace = true
-
-[dependencies]
-anyhow = { workspace = true }
-base64.workspace = true
-gloo-timers = { workspace = true }
-js-sys = { workspace = true }
-# Use workspace dependencies where available
-serde = { workspace = true }
-serde_json = { workspace = true }
-
-wasm-bindgen = { workspace = true, features = ["serde-serialize"] }
-wasm-bindgen-futures = { workspace = true }
-web-sys = { workspace = true, features = [
- "console",
- "HtmlElement",
- "Element",
- "DomRect",
- "CssStyleDeclaration",
- "HtmlTextAreaElement",
- "KeyboardEvent",
- "File",
- "FileList",
- "FileReader",
- "HtmlInputElement",
- "Event",
- "ProgressEvent",
- "Blob",
- "HtmlSelectElement",
- "DomTokenList"
-] }
-
-# Frontend dependencies (matching gate-frontend-daemon versions)
-yew = { workspace = true, features = ["csr"] }
-
-[dev-dependencies]
-tokio-test = "0.4"
-wasm-bindgen-test = { workspace = true }
-gloo-net = { workspace = true, features = ["http"] }
-console_error_panic_hook = { workspace = true }
-
-[[example]]
-name = "trunk-demo"
-path = "examples/trunk-demo/main.rs"
diff --git a/crates/chat-ui/README.md b/crates/chat-ui/README.md
deleted file mode 100644
index 325d3c6a..00000000
--- a/crates/chat-ui/README.md
+++ /dev/null
@@ -1,73 +0,0 @@
-# gate-chat-ui
-
-Reusable chat interface component for Yew applications. Used by gate-frontend-daemon and other frontends to provide the chat testing interface.
-
-## Responsibilities
-
-- **Chat Component**: Standalone Yew component for AI chat
-- **Message Rendering**: Markdown support with syntax highlighting
-- **Streaming Support**: Real-time token streaming display
-- **Auto-resize**: Smart textarea that grows with content
-- **Keyboard Shortcuts**: Enter to send, Shift+Enter for newline
-
-## Usage
-
-```rust
-use gate_chat_ui::ChatInterface;
-use yew::prelude::*;
-
-#[function_component(App)]
-fn app() -> Html {
- let on_send = Callback::from(|message: String| {
- // Handle message sending
- });
-
- html! {
-
- }
-}
-```
-
-## Features
-
-- Message history with sender attribution
-- Loading states during inference
-- Error message display
-- Copy code blocks to clipboard
-- Auto-scroll to latest message
-- Mobile-responsive design
-
-## Component Props
-
-- `on_send`: Callback when user sends message
-- `placeholder`: Input field placeholder text
-- `initial_messages`: Pre-populate chat history
-- `disabled`: Disable input during processing
-
-## Dependencies
-
-Minimal WASM-compatible:
-- `yew`: Component framework
-- `web-sys`: DOM manipulation
-- `gloo-timers`: Async timeouts
-- `js-sys`: JavaScript interop
-
-## Styling
-
-Uses Tailwind CSS classes. Expects Tailwind to be available in parent application.
-
-## Browser Requirements
-
-- Modern browsers with ES2015+ support
-- ResizeObserver API for auto-resize
-- Clipboard API for copy functionality
-
-## Risks
-
-- **Parent Styling**: Requires Tailwind CSS in parent app
-- **Browser APIs**: Some features need polyfills for older browsers
-- **Memory**: Long conversations increase memory usage
\ No newline at end of file
diff --git a/crates/chat-ui/examples/trunk-demo/.cargo/config.toml b/crates/chat-ui/examples/trunk-demo/.cargo/config.toml
deleted file mode 100644
index 8afa7b6c..00000000
--- a/crates/chat-ui/examples/trunk-demo/.cargo/config.toml
+++ /dev/null
@@ -1,7 +0,0 @@
-[target.x86_64-unknown-linux-gnu]
-linker = "clang"
-rustflags = ["-C", "link-arg=-fuse-ld=/nix/store/pqwiwgf6vsqa6gwslam239zjdsc82293-mold-2.40.1/bin/mold"]
-
-[target.aarch64-unknown-linux-gnu]
-linker = "clang"
-rustflags = ["-C", "link-arg=-fuse-ld=/nix/store/pqwiwgf6vsqa6gwslam239zjdsc82293-mold-2.40.1/bin/mold"]
diff --git a/crates/chat-ui/examples/trunk-demo/.gitignore b/crates/chat-ui/examples/trunk-demo/.gitignore
deleted file mode 100644
index 3ce56b85..00000000
--- a/crates/chat-ui/examples/trunk-demo/.gitignore
+++ /dev/null
@@ -1,4 +0,0 @@
-/dist/
-/target/
-/cassettes
-Cargo.lock
\ No newline at end of file
diff --git a/crates/chat-ui/examples/trunk-demo/Cargo.toml b/crates/chat-ui/examples/trunk-demo/Cargo.toml
deleted file mode 100644
index 24b639cb..00000000
--- a/crates/chat-ui/examples/trunk-demo/Cargo.toml
+++ /dev/null
@@ -1,19 +0,0 @@
-[package]
-name = "trunk-demo"
-version = "0.1.0"
-edition = "2021"
-
-[lib]
-crate-type = ["cdylib"]
-path = "main.rs"
-
-[dependencies]
-gate-chat-ui = { path = "../.." }
-wasm-bindgen = { workspace = true }
-web-sys = { workspace = true, features = ["Window", "Document", "Element", "HtmlElement", "DomTokenList", "HtmlSelectElement", "Request", "RequestInit", "Response"] }
-yew = { workspace = true, features = ["csr"] }
-console_error_panic_hook = { workspace = true }
-serde_json = { workspace = true }
-wasm-bindgen-futures = { workspace = true }
-gloo-net = { workspace = true, features = ["http"] }
-
diff --git a/crates/chat-ui/examples/trunk-demo/README.md b/crates/chat-ui/examples/trunk-demo/README.md
deleted file mode 100644
index 0cf7a1e4..00000000
--- a/crates/chat-ui/examples/trunk-demo/README.md
+++ /dev/null
@@ -1,30 +0,0 @@
-# Gate Chat UI Demo
-
-This demo showcases the Gate Chat UI component with support for loading real API conversation cassettes.
-
-## Running the Demo
-
-```bash
-trunk serve
-```
-
-This will start the demo app on http://localhost:8081.
-
-## Features
-
-- **Cassette Loading**: Load real API conversations from test cassettes
-- **Dark Mode**: Toggle between light and dark themes
-- **Multimodal Support**: Send messages with images and file attachments
-- **Streaming Display**: View streaming responses from cassettes
-
-## Available Cassettes
-
-The demo includes example cassettes from:
-- OpenAI Chat Completions API (basic, streaming, multi-turn)
-- Anthropic Messages API (basic, streaming, vision)
-
-Select a cassette from the dropdown in the header to load and view the conversation.
-
-## How it Works
-
-The cassettes are symlinked from the fixtures directory and served as static files by trunk. This keeps the WASM bundle small while still providing access to all test data.
\ No newline at end of file
diff --git a/crates/chat-ui/examples/trunk-demo/Trunk.cassette.toml b/crates/chat-ui/examples/trunk-demo/Trunk.cassette.toml
deleted file mode 100644
index 888ee0f6..00000000
--- a/crates/chat-ui/examples/trunk-demo/Trunk.cassette.toml
+++ /dev/null
@@ -1,15 +0,0 @@
-[build]
-target = "cassette.html"
-dist = "dist-cassette"
-
-[watch]
-watch = [
- "../../src",
- "Cargo.toml",
- "cassette.html",
- "cassette_demo.rs",
- "tailwind.config.js"
-]
-
-[serve]
-port = 8081
\ No newline at end of file
diff --git a/crates/chat-ui/examples/trunk-demo/Trunk.toml b/crates/chat-ui/examples/trunk-demo/Trunk.toml
deleted file mode 100644
index f0de831b..00000000
--- a/crates/chat-ui/examples/trunk-demo/Trunk.toml
+++ /dev/null
@@ -1,15 +0,0 @@
-[build]
-target = "index.html"
-dist = "dist"
-
-[[hooks]]
-stage = "post_build"
-command = "sh"
-command_arguments = ["-c", "pwd && cp -rv ../../../fixtures/data/cassettes"]
-
-[serve]
-port = 8081
-open = false
-
-[watch]
-watch = ["../../src", "main.rs", "index.html"]
\ No newline at end of file
diff --git a/crates/chat-ui/examples/trunk-demo/cassette.html b/crates/chat-ui/examples/trunk-demo/cassette.html
deleted file mode 100644
index 8769bde8..00000000
--- a/crates/chat-ui/examples/trunk-demo/cassette.html
+++ /dev/null
@@ -1,14 +0,0 @@
-
-
-
-
-
- Gate Chat UI - Cassette Demo
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/crates/chat-ui/examples/trunk-demo/cassette_demo.rs b/crates/chat-ui/examples/trunk-demo/cassette_demo.rs
deleted file mode 100644
index a2ce2fed..00000000
--- a/crates/chat-ui/examples/trunk-demo/cassette_demo.rs
+++ /dev/null
@@ -1,228 +0,0 @@
-use gate_chat_ui::{ChatContainer, ChatMessage, ChatResponse, Provider};
-use gate_chat_ui::utils::simple_cassette_parser::parse_cassette;
-use gate_fixtures::{list_all_cassettes, get_cassette};
-use wasm_bindgen::prelude::*;
-use web_sys::window;
-use yew::prelude::*;
-
-#[derive(Clone, PartialEq)]
-struct CassetteInfo {
- provider: String,
- name: String,
- display_name: String,
-}
-
-#[function_component(App)]
-fn app() -> Html {
- let dark_mode = use_state(|| {
- window()
- .and_then(|w| w.document())
- .and_then(|d| d.document_element())
- .map(|e| e.class_list().contains("dark"))
- .unwrap_or(false)
- });
-
- let toggle_dark_mode = {
- let dark_mode = dark_mode.clone();
- Callback::from(move |_| {
- let new_state = !*dark_mode;
- dark_mode.set(new_state);
-
- if let Some(window) = window() {
- if let Some(document) = window.document() {
- if let Some(element) = document.document_element() {
- let class_list = element.class_list();
- if new_state {
- let _ = class_list.add_1("dark");
- } else {
- let _ = class_list.remove_1("dark");
- }
- }
- }
- }
- })
- };
-
- // Get available cassettes
- let available_cassettes = use_memo((), |_| {
- let mut cassettes = Vec::new();
- let all = list_all_cassettes();
-
- for (provider, names) in all {
- for name in names {
- let display_name = name
- .replace("_", " ")
- .split_whitespace()
- .map(|word| {
- let mut chars = word.chars();
- match chars.next() {
- None => String::new(),
- Some(f) => f.to_uppercase().collect::() + chars.as_str(),
- }
- })
- .collect::>()
- .join(" ");
-
- cassettes.push(CassetteInfo {
- provider: provider.to_string(),
- name: name.to_string(),
- display_name,
- });
- }
- }
-
- cassettes.sort_by(|a, b| a.provider.cmp(&b.provider).then(a.name.cmp(&b.name)));
- cassettes
- });
-
- let selected_cassette = use_state(|| None::);
- let loading_error = use_state(|| None::);
-
- let chat_response = use_state(|| ChatResponse {
- id: "demo-1".to_string(),
- model: "demo-model".to_string(),
- messages: vec![
- ChatMessage::system("Welcome to the Gate Chat UI Cassette Demo!\\n\\nThis demo allows you to load real API conversation cassettes and view them in the chat interface. Select a cassette from the dropdown above to see a real conversation."),
- ],
- provider: Provider::Unknown("demo".to_string()),
- usage: None,
- metadata: Default::default(),
- });
-
- let on_cassette_select = {
- let selected_cassette = selected_cassette.clone();
- let chat_response = chat_response.clone();
- let loading_error = loading_error.clone();
-
- Callback::from(move |e: Event| {
- loading_error.set(None);
-
- let target = e.target().unwrap();
- let select = target.dyn_into::().unwrap();
- let value = select.value();
-
- if value.is_empty() {
- selected_cassette.set(None);
- // Reset to welcome message
- chat_response.set(ChatResponse {
- id: "demo-1".to_string(),
- model: "demo-model".to_string(),
- messages: vec![
- ChatMessage::system("Welcome to the Gate Chat UI Cassette Demo!\\n\\nThis demo allows you to load real API conversation cassettes and view them in the chat interface. Select a cassette from the dropdown above to see a real conversation."),
- ],
- provider: Provider::Unknown("demo".to_string()),
- usage: None,
- metadata: Default::default(),
- });
- return;
- }
-
- // Parse provider:name format
- if let Some((provider, name)) = value.split_once(':') {
- let cassette_info = CassetteInfo {
- provider: provider.to_string(),
- name: name.to_string(),
- display_name: name.replace("_", " "),
- };
-
- selected_cassette.set(Some(cassette_info.clone()));
-
- // Load the cassette
- if let Some(cassette_content) = get_cassette(provider, name) {
- match parse_cassette(cassette_content) {
- Ok(mut parsed_response) => {
- // Add a header message explaining what cassette is loaded
- let header = ChatMessage::system(format!(
- "Loaded cassette: {} - {}\\n\\nThis is a real API conversation captured for testing.",
- provider.to_uppercase(),
- cassette_info.display_name
- ));
- parsed_response.messages.insert(0, header);
-
- chat_response.set(parsed_response);
- }
- Err(e) => {
- loading_error.set(Some(format!("Failed to parse cassette: {}", e)));
- }
- }
- } else {
- loading_error.set(Some("Failed to load cassette content".to_string()));
- }
- }
- })
- };
-
- html! {
-
-
-
-
{"Gate Chat UI - Cassette Demo"}
-
- if *dark_mode {
- // Sun icon for light mode
-
-
-
- } else {
- // Moon icon for dark mode
-
-
-
- }
-
-
-
- {"Load Cassette:"}
-
- {"Select a cassette..."}
- {
- available_cassettes.iter().map(|cassette| {
- let value = format!("{}:{}", cassette.provider, cassette.name);
- let label = format!("{} - {}",
- cassette.provider.to_uppercase(),
- cassette.display_name
- );
- html! {
- {label}
- }
- }).collect::()
- }
-
-
- if let Some(error) = &*loading_error {
-
- {error}
-
- }
-
-
-
-
-
- }
-}
-
-#[wasm_bindgen(start)]
-pub fn start() {
- console_error_panic_hook::set_once();
- yew::Renderer::::new().render();
-}
-
-fn main() {
- // Empty main for wasm32 target
-}
\ No newline at end of file
diff --git a/crates/chat-ui/examples/trunk-demo/index.html b/crates/chat-ui/examples/trunk-demo/index.html
deleted file mode 100644
index bf2570cd..00000000
--- a/crates/chat-ui/examples/trunk-demo/index.html
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
-
-
-
- Gate Chat UI Demo
-
-
-
-
-
-
\ No newline at end of file
diff --git a/crates/chat-ui/examples/trunk-demo/main.rs b/crates/chat-ui/examples/trunk-demo/main.rs
deleted file mode 100644
index c70f44ea..00000000
--- a/crates/chat-ui/examples/trunk-demo/main.rs
+++ /dev/null
@@ -1,337 +0,0 @@
-use gate_chat_ui::utils::simple_cassette_parser::parse_cassette;
-use gate_chat_ui::{ChatContainer, ChatMessage, ChatResponse, MultimodalMessage, Provider};
-use gloo_net::http::Request;
-use serde_json::json;
-use wasm_bindgen::prelude::*;
-use web_sys::window;
-use yew::prelude::*;
-
-#[derive(Clone, PartialEq)]
-struct CassetteInfo {
- provider: String,
- name: String,
- display_name: String,
- path: String,
-}
-
-#[function_component(App)]
-fn app() -> Html {
- let dark_mode = use_state(|| {
- // Check if dark mode is already set
- window()
- .and_then(|w| w.document())
- .and_then(|d| d.document_element())
- .map(|e| e.class_list().contains("dark"))
- .unwrap_or(false)
- });
-
- let toggle_dark_mode = {
- let dark_mode = dark_mode.clone();
- Callback::from(move |_| {
- let new_state = !*dark_mode;
- dark_mode.set(new_state);
-
- // Update the document element class
- #[allow(clippy::collapsible_if)]
- if let Some(window) = window() {
- if let Some(document) = window.document() {
- if let Some(element) = document.document_element() {
- let class_list = element.class_list();
- if new_state {
- let _ = class_list.add_1("dark");
- } else {
- let _ = class_list.remove_1("dark");
- }
- }
- }
- }
- })
- };
-
- let chat_response = use_state(|| ChatResponse {
- id: "demo-1".to_string(),
- model: "demo-model".to_string(),
- messages: vec![
- ChatMessage::system("You are a helpful assistant."),
- ChatMessage::user("Hello! Can you help me understand how this chat UI works?"),
- ChatMessage::assistant(
- "Of course! This is a demo of the Gate Chat UI component. It provides a clean interface for displaying chat messages between users and AI assistants. The UI supports various message types including system messages, user messages, and assistant responses.",
- ),
- ],
- provider: Provider::Unknown("demo".to_string()),
- usage: None,
- metadata: Default::default(),
- });
-
- let loading_cassette = use_state(|| false);
- let cassette_error = use_state(|| None::);
-
- // Hardcoded list of available cassettes
- // In production, this could be fetched from an API endpoint
- let available_cassettes = vec![
- // OpenAI Chat Completions
- CassetteInfo {
- provider: "openai".to_string(),
- name: "basic_chat_completion".to_string(),
- display_name: "Basic Chat Completion".to_string(),
- path: "/cassettes/openai/chat_completions/basic_chat_completion.json".to_string(),
- },
- CassetteInfo {
- provider: "openai".to_string(),
- name: "streaming_chat_completion".to_string(),
- display_name: "Streaming Chat Completion".to_string(),
- path: "/cassettes/openai/chat_completions/streaming_chat_completion.json".to_string(),
- },
- CassetteInfo {
- provider: "openai".to_string(),
- name: "multi_turn_conversation".to_string(),
- display_name: "Multi-turn Conversation".to_string(),
- path: "/cassettes/openai/chat_completions/multi_turn_conversation.json".to_string(),
- },
- CassetteInfo {
- provider: "openai".to_string(),
- name: "function_calling".to_string(),
- display_name: "Function Calling".to_string(),
- path: "/cassettes/openai/chat_completions/function_calling.json".to_string(),
- },
- CassetteInfo {
- provider: "openai".to_string(),
- name: "json_mode".to_string(),
- display_name: "JSON Mode".to_string(),
- path: "/cassettes/openai/chat_completions/json_mode.json".to_string(),
- },
- CassetteInfo {
- provider: "openai".to_string(),
- name: "system_message_instructions".to_string(),
- display_name: "System Message Instructions".to_string(),
- path: "/cassettes/openai/chat_completions/system_message_instructions.json".to_string(),
- },
- // Anthropic Messages
- CassetteInfo {
- provider: "anthropic".to_string(),
- name: "basic_message".to_string(),
- display_name: "Basic Message".to_string(),
- path: "/cassettes/anthropic/messages/basic_message.json".to_string(),
- },
- CassetteInfo {
- provider: "anthropic".to_string(),
- name: "streaming_basic".to_string(),
- display_name: "Streaming Basic".to_string(),
- path: "/cassettes/anthropic/messages/streaming_basic.json".to_string(),
- },
- CassetteInfo {
- provider: "anthropic".to_string(),
- name: "vision_image_analysis".to_string(),
- display_name: "Vision Image Analysis".to_string(),
- path: "/cassettes/anthropic/messages/vision_image_analysis.json".to_string(),
- },
- CassetteInfo {
- provider: "anthropic".to_string(),
- name: "multi_turn_conversation".to_string(),
- display_name: "Multi-turn Conversation".to_string(),
- path: "/cassettes/anthropic/messages/multi_turn_conversation.json".to_string(),
- },
- CassetteInfo {
- provider: "anthropic".to_string(),
- name: "tool_use_multi_turn".to_string(),
- display_name: "Tool Use Multi-turn".to_string(),
- path: "/cassettes/anthropic/messages/tool_use_multi_turn.json".to_string(),
- },
- CassetteInfo {
- provider: "anthropic".to_string(),
- name: "system_prompt".to_string(),
- display_name: "System Prompt".to_string(),
- path: "/cassettes/anthropic/messages/system_prompt.json".to_string(),
- },
- // OpenAI Responses
- CassetteInfo {
- provider: "openai".to_string(),
- name: "basic_response".to_string(),
- display_name: "Basic Response".to_string(),
- path: "/cassettes/openai/responses/basic_response.json".to_string(),
- },
- CassetteInfo {
- provider: "openai".to_string(),
- name: "basic_streaming".to_string(),
- display_name: "Basic Streaming Response".to_string(),
- path: "/cassettes/openai/responses/basic_streaming.json".to_string(),
- },
- CassetteInfo {
- provider: "openai".to_string(),
- name: "conversation_with_context".to_string(),
- display_name: "Conversation with Context".to_string(),
- path: "/cassettes/openai/responses/conversation_with_context.json".to_string(),
- },
- ];
-
- let on_cassette_select = {
- let chat_response = chat_response.clone();
- let loading_cassette = loading_cassette.clone();
- let cassette_error = cassette_error.clone();
- let available_cassettes = available_cassettes.clone();
-
- Callback::from(move |e: Event| {
- let target = e.target().unwrap();
- let select = target.dyn_into::().unwrap();
- let value = select.value();
-
- if value.is_empty() {
- return;
- }
-
- // Find the selected cassette
- let cassette = available_cassettes
- .iter()
- .find(|c| format!("{}:{}", c.provider, c.name) == value);
-
- if let Some(cassette_info) = cassette {
- loading_cassette.set(true);
- cassette_error.set(None);
-
- let chat_response = chat_response.clone();
- let loading_cassette = loading_cassette.clone();
- let cassette_error = cassette_error.clone();
- let path = cassette_info.path.clone();
-
- wasm_bindgen_futures::spawn_local(async move {
- match Request::get(&path).send().await {
- Ok(resp) => match resp.text().await {
- Ok(text) => match parse_cassette(&text) {
- Ok(parsed) => {
- chat_response.set(parsed);
- }
- Err(e) => {
- cassette_error
- .set(Some(format!("Failed to parse cassette: {e}")));
- }
- },
- Err(e) => {
- cassette_error.set(Some(format!("Failed to read response: {e}")));
- }
- },
- Err(e) => {
- cassette_error.set(Some(format!("Failed to load cassette: {e}")));
- }
- }
- loading_cassette.set(false);
- });
- }
-
- // Reset select to placeholder
- select.set_value("");
- })
- };
-
- let on_send_multimodal = {
- let chat_response = chat_response.clone();
- Callback::from(move |message: MultimodalMessage| {
- let mut updated = (*chat_response).clone();
-
- // Convert multimodal message to chat message with proper content blocks
- let content_blocks = message.to_content_blocks();
-
- if !content_blocks.is_empty() {
- let user_message = ChatMessage {
- role: "user".to_string(),
- content: Some(json!(content_blocks)),
- tool_calls: None,
- name: None,
- metadata: Default::default(),
- };
- updated.messages.push(user_message);
-
- // Simulate assistant response
- let response_text = if message.attachments.iter().any(|a| a.is_image()) {
- "I can see the image(s) you've uploaded. This is a simulated response - in a real implementation, I would analyze the image content.".to_string()
- } else if !message.attachments.is_empty() {
- format!(
- "I received {} file(s). This is a simulated response.",
- message.attachments.len()
- )
- } else {
- "I received your message! This is a simulated response.".to_string()
- };
-
- updated.messages.push(ChatMessage::assistant(response_text));
- }
-
- chat_response.set(updated);
- })
- };
-
- html! {
-
-
-
-
{"Gate Chat UI Demo"}
-
-
- {"Load example..."}
- {
- available_cassettes.iter().map(|cassette| {
- let value = format!("{}:{}", cassette.provider, cassette.name);
- let label = format!("{} - {}",
- cassette.provider.to_uppercase(),
- cassette.display_name
- );
- html! {
- {label}
- }
- }).collect::()
- }
-
-
- if *dark_mode {
- // Sun icon for light mode
-
-
-
- } else {
- // Moon icon for dark mode
-
-
-
- }
-
-
-
- if let Some(error) = &*cassette_error {
-
- {error}
-
- }
- if *loading_cassette {
-
- {"Loading cassette..."}
-
- }
-
-
-
-
-
- }
-}
-
-#[wasm_bindgen(start)]
-#[allow(clippy::main_recursion)]
-pub fn main() {
- console_error_panic_hook::set_once();
- yew::Renderer::::new().render();
-}
diff --git a/crates/chat-ui/examples/trunk-demo/style.css b/crates/chat-ui/examples/trunk-demo/style.css
deleted file mode 100644
index bd6213e1..00000000
--- a/crates/chat-ui/examples/trunk-demo/style.css
+++ /dev/null
@@ -1,3 +0,0 @@
-@tailwind base;
-@tailwind components;
-@tailwind utilities;
\ No newline at end of file
diff --git a/crates/chat-ui/examples/trunk-demo/tailwind.config.js b/crates/chat-ui/examples/trunk-demo/tailwind.config.js
deleted file mode 100644
index 9d6ac3f7..00000000
--- a/crates/chat-ui/examples/trunk-demo/tailwind.config.js
+++ /dev/null
@@ -1,29 +0,0 @@
-module.exports = {
- darkMode: 'class',
- content: [
- "./index.html",
- "./main.rs",
- "../../src/**/*.rs",
- ],
- theme: {
- extend: {
- animation: {
- 'spin': 'spin 1s linear infinite',
- 'pulse-dot': 'pulse-dot 1.4s ease-in-out infinite',
- },
- keyframes: {
- 'pulse-dot': {
- '0%, 80%, 100%': {
- opacity: '0.3',
- transform: 'scale(0.8)',
- },
- '40%': {
- opacity: '1',
- transform: 'scale(1)',
- },
- },
- },
- },
- },
- plugins: [],
-}
\ No newline at end of file
diff --git a/crates/chat-ui/src/components/chat_container.rs b/crates/chat-ui/src/components/chat_container.rs
deleted file mode 100644
index 3ac1f70e..00000000
--- a/crates/chat-ui/src/components/chat_container.rs
+++ /dev/null
@@ -1,95 +0,0 @@
-use crate::components::{ChatInput, MessageList, StreamingIndicator};
-use crate::styles::{
- CARD_BG, CONTAINER_BG, FLEX_BETWEEN, FLEX_CENTER_GAP_2, FLEX_COL, HEADER_PADDING,
- PRIMARY_BORDER, ROUNDED_STANDARD, SECONDARY_TEXT, TERTIARY_TEXT, combine_styles,
-};
-use crate::types::ChatResponse;
-use crate::types::MultimodalMessage;
-use yew::prelude::*;
-
-#[derive(Properties, Clone, PartialEq)]
-pub struct ChatContainerProps {
- pub chat_response: ChatResponse,
- #[prop_or_default]
- pub show_metadata: bool,
- #[prop_or_default]
- pub show_input: bool,
- #[prop_or_default]
- pub on_send_message: Option>,
- #[prop_or_default]
- pub on_send_multimodal: Option>,
- #[prop_or_default]
- pub input_disabled: bool,
- #[prop_or_default]
- pub allow_images: bool,
- #[prop_or_default]
- pub allow_files: bool,
- #[prop_or_default]
- pub class: Classes,
-}
-
-#[function_component(ChatContainer)]
-pub fn chat_container(props: &ChatContainerProps) -> Html {
- let ChatContainerProps {
- chat_response,
- show_metadata,
- show_input,
- on_send_message,
- on_send_multimodal,
- input_disabled,
- allow_images,
- allow_files,
- class,
- } = props;
-
- let is_streaming = chat_response
- .messages
- .last()
- .map(|m| m.is_streaming())
- .unwrap_or(false);
-
- html! {
-
- if *show_metadata {
-
-
- {format!("{:?}", chat_response.provider)}
- {&chat_response.model}
-
- if let Some(usage) = &chat_response.usage {
-
- if let Some(prompt) = usage.prompt_tokens {
- {format!("Prompt: {} tokens", prompt)}
- }
- if let Some(completion) = usage.completion_tokens {
- {format!("Completion: {} tokens", completion)}
- }
-
- }
-
- }
-
-
-
-
-
- if is_streaming {
-
- }
-
- if *show_input {
- if on_send_message.is_some() || on_send_multimodal.is_some() {
-
-
-
- }
- }
-
- }
-}
diff --git a/crates/chat-ui/src/components/chat_input.rs b/crates/chat-ui/src/components/chat_input.rs
deleted file mode 100644
index 0bb973a1..00000000
--- a/crates/chat-ui/src/components/chat_input.rs
+++ /dev/null
@@ -1,499 +0,0 @@
-use crate::styles::{
- CARD_BG, ERROR_TEXT, FLEX_CENTER, FLEX_COL, INPUT_COLORS, PRIMARY_BORDER, PRIMARY_TEXT,
- STANDARD_PADDING, TRANSITION_COLORS, combine_styles,
-};
-use crate::types::{Attachment, MultimodalMessage};
-use gloo_timers::callback::Timeout;
-use wasm_bindgen::{JsCast, closure::Closure};
-use wasm_bindgen_futures::JsFuture;
-use web_sys::{
- Event, File, FileReader, HtmlElement, HtmlInputElement, HtmlTextAreaElement, MouseEvent,
- ProgressEvent,
-};
-use yew::prelude::*;
-
-#[derive(Properties, PartialEq)]
-pub struct ChatInputProps {
- /// Callback for simple text messages (backward compatibility)
- #[prop_or_default]
- pub on_send: Option>,
- /// Callback for multimodal messages (text + attachments)
- #[prop_or_default]
- pub on_send_multimodal: Option>,
- #[prop_or_default]
- pub placeholder: Option,
- #[prop_or_default]
- pub disabled: bool,
- #[prop_or_default]
- pub allow_images: bool,
- #[prop_or_default]
- pub allow_files: bool,
- /// Maximum file size in bytes (default: 10MB)
- #[prop_or(10 * 1024 * 1024)]
- pub max_file_size: usize,
-}
-
-#[hook]
-fn use_auto_resize_textarea() -> (NodeRef, Callback<()>) {
- let text_area_ref = use_node_ref();
-
- let resize_textarea = {
- let text_area_ref = text_area_ref.clone();
- Callback::from(move |_| {
- if let Some(text_area) = text_area_ref.cast::()
- && let Some(element) = text_area.dyn_ref::()
- {
- let _ = element.style().set_property("height", "auto");
- let _ = element.style().set_property("overflow-y", "hidden");
- let scroll_height = text_area.scroll_height();
- let new_height = scroll_height.min(200);
- let _ = element
- .style()
- .set_property("height", &format!("{new_height}px"));
- if new_height >= 200 {
- let _ = element.style().set_property("overflow-y", "auto");
- }
- }
- })
- };
-
- (text_area_ref, resize_textarea)
-}
-
-fn clear_input_and_reset(input_value: &UseStateHandle, text_area_ref: &NodeRef) {
- input_value.set(String::new());
- if let Some(text_area) = text_area_ref.cast::() {
- text_area.set_value("");
- if let Some(element) = text_area.dyn_ref::() {
- let _ = element.style().set_property("height", "auto");
- }
- }
-}
-
-async fn read_file(file: File) -> Result, String> {
- let file_reader = FileReader::new().map_err(|_| "Failed to create FileReader")?;
-
- let (promise, resolve, reject) = {
- let mut resolve = None;
- let mut reject = None;
- let promise = js_sys::Promise::new(&mut |res, rej| {
- resolve = Some(res);
- reject = Some(rej);
- });
- (promise, resolve.unwrap(), reject.unwrap())
- };
-
- {
- let reader_clone = file_reader.clone();
- let onload = Closure::::new(move |_: ProgressEvent| {
- if let Ok(result) = reader_clone.result() {
- let _ = resolve.call1(&wasm_bindgen::JsValue::NULL, &result);
- }
- });
- file_reader.set_onload(Some(onload.as_ref().unchecked_ref()));
- onload.forget();
-
- let onerror = Closure::::new(move |_: ProgressEvent| {
- let _ = reject.call1(
- &wasm_bindgen::JsValue::NULL,
- &wasm_bindgen::JsValue::from_str("Failed to read file"),
- );
- });
- file_reader.set_onerror(Some(onerror.as_ref().unchecked_ref()));
- onerror.forget();
- }
-
- file_reader
- .read_as_array_buffer(&file)
- .map_err(|_| "Failed to read file")?;
-
- let result = JsFuture::from(promise)
- .await
- .map_err(|_| "Failed to read file")?;
- let array_buffer = result
- .dyn_into::()
- .map_err(|_| "Invalid ArrayBuffer")?;
- let array = js_sys::Uint8Array::new(&array_buffer);
- Ok(array.to_vec())
-}
-
-#[function_component(ChatInput)]
-pub fn chat_input(props: &ChatInputProps) -> Html {
- let input_value = use_state(String::new);
- let attachments = use_state(Vec::::new);
- let error_message = use_state(|| Option::::None);
- let is_loading = use_state(|| false);
- let file_input_ref = use_node_ref();
- let (text_area_ref, resize_textarea) = use_auto_resize_textarea();
-
- let _clear_error = {
- let error_message = error_message.clone();
- Callback::from(move |_: ()| {
- error_message.set(None);
- })
- };
-
- let handle_input = {
- let input_value = input_value.clone();
- let text_area_ref = text_area_ref.clone();
- let resize_textarea = resize_textarea.clone();
- Callback::from(move |_| {
- if let Some(text_area) = text_area_ref.cast::() {
- input_value.set(text_area.value());
- resize_textarea.emit(());
- }
- })
- };
-
- let handle_file_select = {
- let attachments = attachments.clone();
- let error_message = error_message.clone();
- let is_loading = is_loading.clone();
- let max_file_size = props.max_file_size;
- let file_input_ref = file_input_ref.clone();
-
- Callback::from(move |e: Event| {
- let input = e.target_unchecked_into::();
- if let Some(files) = input.files() {
- let files_len = files.length();
- if files_len > 0 {
- is_loading.set(true);
- error_message.set(None);
-
- let attachments = attachments.clone();
- let error_message = error_message.clone();
- let is_loading = is_loading.clone();
- let file_input_ref = file_input_ref.clone();
-
- wasm_bindgen_futures::spawn_local(async move {
- let mut new_attachments = (*attachments).clone();
- let mut has_error = false;
-
- for i in 0..files_len {
- if let Some(file) = files.item(i) {
- let size = file.size() as usize;
- if size > max_file_size {
- error_message.set(Some(format!(
- "{} is too large. Maximum size is {}",
- file.name(),
- format_file_size(max_file_size)
- )));
- has_error = true;
- break;
- }
-
- match read_file(file.clone()).await {
- Ok(data) => {
- new_attachments.push(Attachment {
- name: file.name(),
- mime_type: file.type_(),
- data,
- size,
- });
- }
- Err(err) => {
- error_message.set(Some(err));
- has_error = true;
- break;
- }
- }
- }
- }
-
- if !has_error {
- attachments.set(new_attachments);
- }
- is_loading.set(false);
-
- // Clear the file input
- if let Some(input) = file_input_ref.cast::() {
- input.set_value("");
- }
- });
- }
- }
- })
- };
-
- let remove_attachment = {
- let attachments = attachments.clone();
- Callback::from(move |index: usize| {
- let mut new_attachments = (*attachments).clone();
- new_attachments.remove(index);
- attachments.set(new_attachments);
- })
- };
-
- let send_message = {
- let input_value = input_value.clone();
- let attachments = attachments.clone();
- let on_send = props.on_send.clone();
- let on_send_multimodal = props.on_send_multimodal.clone();
- let text_area_ref = text_area_ref.clone();
-
- Callback::from(move |_| {
- let text = (*input_value).clone();
- let has_text = !text.trim().is_empty();
- let has_attachments = !attachments.is_empty();
-
- if has_text || has_attachments {
- if has_attachments || on_send_multimodal.is_some() {
- // Send as multimodal message
- if let Some(callback) = &on_send_multimodal {
- let message = MultimodalMessage::with_attachments(
- if has_text { Some(text) } else { None },
- (*attachments).clone(),
- );
- callback.emit(message);
- } else if has_text {
- // Fallback to text-only if no multimodal callback
- if let Some(callback) = on_send.as_ref() {
- callback.emit(text);
- }
- }
- } else if has_text {
- // Send as text-only message
- if let Some(callback) = on_send.as_ref() {
- callback.emit(text);
- }
- }
-
- // Clear everything
- clear_input_and_reset(&input_value, &text_area_ref);
- attachments.set(Vec::new());
- }
- })
- };
-
- let handle_keydown = {
- let send_message = send_message.clone();
- Callback::from(move |e: KeyboardEvent| {
- if e.key() == "Enter" && !e.shift_key() {
- e.prevent_default();
- send_message.emit(());
- }
- })
- };
-
- let handle_attachment_click = {
- let file_input_ref = file_input_ref.clone();
- Callback::from(move |_| {
- if let Some(input) = file_input_ref.cast::() {
- input.click();
- }
- })
- };
-
- // Auto-clear error after 5 seconds
- {
- let error_message = error_message.clone();
- use_effect_with((*error_message).clone(), move |err| {
- if err.is_some() {
- let error_message = error_message.clone();
- let timeout = Timeout::new(5000, move || {
- error_message.set(None);
- });
- timeout.forget();
- }
- || ()
- });
- }
-
- let is_empty = input_value.trim().is_empty() && attachments.is_empty();
- let placeholder = props
- .placeholder
- .clone()
- .unwrap_or_else(|| "Type a message...".to_string());
-
- let show_attachments = props.allow_images || props.allow_files;
- let accept = match (props.allow_images, props.allow_files) {
- (true, true) => "*/*",
- (true, false) => "image/*",
- (false, true) => "*/*",
- (false, false) => "",
- };
-
- html! {
-
- // Error message
- if let Some(error) = &*error_message {
-
- {error}
-
- }
-
- // Attachment previews
- if !attachments.is_empty() {
-
- {for attachments.iter().enumerate().map(|(i, attachment)| {
- html! {
-
- }
- })}
-
- }
-
- // Input area
-
- // Hidden file input
- if show_attachments {
-
- }
-
- // Attachment button
- if show_attachments {
-
-
-
-
-
- }
-
- // Text input
-
-
-
-
- // Send button
-
-
-
- }
-}
-
-#[derive(Properties, PartialEq)]
-struct AttachmentPreviewProps {
- pub attachment: Attachment,
- pub on_remove: Callback,
-}
-
-#[function_component(AttachmentPreview)]
-fn attachment_preview(props: &AttachmentPreviewProps) -> Html {
- let attachment = &props.attachment;
-
- html! {
-
- if attachment.is_image() {
- // Image preview
-
-
-
-
- } else {
- // File preview
-
-
-
-
-
-
- {&attachment.name}
-
-
- {attachment.size_string()}
-
-
-
-
-
-
-
-
- }
-
- }
-}
-
-#[derive(Properties, PartialEq)]
-struct SendButtonProps {
- pub onclick: Callback<()>,
- pub disabled: bool,
-}
-
-#[function_component(SendButton)]
-fn send_button(props: &SendButtonProps) -> Html {
- let handle_click = {
- let onclick = props.onclick.clone();
- Callback::from(move |_| onclick.emit(()))
- };
-
- html! {
-
-
-
-
-
-
- }
-}
-
-fn format_file_size(size: usize) -> String {
- if size < 1024 {
- format!("{size} B")
- } else if size < 1024 * 1024 {
- format!("{:.1} KB", size as f64 / 1024.0)
- } else {
- format!("{:.1} MB", size as f64 / (1024.0 * 1024.0))
- }
-}
diff --git a/crates/chat-ui/src/components/message.rs b/crates/chat-ui/src/components/message.rs
deleted file mode 100644
index 54ac17f1..00000000
--- a/crates/chat-ui/src/components/message.rs
+++ /dev/null
@@ -1,353 +0,0 @@
-use crate::components::StreamingText;
-use crate::styles::{
- ASSISTANT_BUBBLE_COLORS, DEFAULT_BUBBLE_COLORS, SYSTEM_BUBBLE_COLORS, TOOL_BUBBLE_COLORS,
- USER_BUBBLE_COLORS,
-};
-use crate::types::ChatMessage;
-use crate::utils::markdown::render_markdown;
-use serde_json::Value;
-use web_sys::MouseEvent;
-use yew::prelude::*;
-
-#[derive(Properties, Clone, PartialEq)]
-pub struct MessageProps {
- pub message: ChatMessage,
- #[prop_or_default]
- pub is_last: bool,
- #[prop_or_default]
- pub class: Classes,
-}
-
-#[function_component(Message)]
-pub fn message(props: &MessageProps) -> Html {
- let MessageProps {
- message,
- is_last,
- class,
- } = props;
-
- let expanded_tools = use_state(|| true); // Default to expanded for better visibility
-
- let role_class = match message.role.as_str() {
- "system" => "system",
- "user" => "user",
- "assistant" => "assistant",
- "tool" | "function" => "tool",
- _ => "unknown",
- };
-
- let role_label = match message.role.as_str() {
- "system" => "System",
- "user" => "User",
- "assistant" => "Assistant",
- "tool" => "Tool",
- "function" => "Function",
- _ => &message.role,
- };
-
- let toggle_tools = {
- let expanded_tools = expanded_tools.clone();
- Callback::from(move |_| {
- expanded_tools.set(!*expanded_tools);
- })
- };
-
- // Extract refusal from metadata
- let refusal = message
- .metadata
- .get("refusal")
- .and_then(|v| v.as_str())
- .map(|s| s.to_string());
-
- // Extract finish_reason from metadata
- let finish_reason = message.finish_reason();
-
- let message_class = match role_class {
- "user" => USER_BUBBLE_COLORS,
- "assistant" => ASSISTANT_BUBBLE_COLORS,
- "system" => SYSTEM_BUBBLE_COLORS,
- "tool" => TOOL_BUBBLE_COLORS,
- _ => DEFAULT_BUBBLE_COLORS,
- };
-
- html! {
-
-
- {role_label}
- if message.name.is_some() {
- {message.name.as_ref().unwrap()}
- }
-
-
-
- {render_message_content(&message.content, message.is_streaming(), *is_last)}
-
- if let Some(refusal_text) = refusal {
-
- {"Refusal:"}
- {refusal_text}
-
- }
-
- if let Some(tool_calls) = &message.tool_calls {
-
-
- {if *expanded_tools { "▼" } else { "▶" }}
- {"🔧"}
- {format!(" {} tool call{}", tool_calls.len(), if tool_calls.len() == 1 { "" } else { "s" })}
-
-
- if *expanded_tools {
-
- {for tool_calls.iter().map(|tool_call| {
- render_tool_call(tool_call)
- })}
-
- }
-
- }
-
-
- if let Some(reason) = finish_reason {
-
- {format!("Finish reason: {}", reason)}
-
- }
-
- // Display any extra metadata that might be interesting
- {render_extra_metadata(&message.metadata)}
-
-
- }
-}
-
-fn render_message_content(content: &Option, is_streaming: bool, is_last: bool) -> Html {
- match content {
- None => html! { {"(empty)"} },
- Some(Value::String(text)) => {
- if is_streaming && is_last {
- html! {
-
- }
- } else {
- render_markdown(text)
- }
- }
- Some(Value::Array(parts)) => {
- html! {
- <>
- {for parts.iter().map(|part| {
- if let Some(text) = part.get("text").and_then(|t| t.as_str()) {
- if is_streaming && is_last {
- html! {
-
- }
- } else {
- render_markdown(text)
- }
- } else if let Some(image_url) = part.get("image_url") {
- // OpenAI format
- if let Some(url) = image_url.get("url").and_then(|u| u.as_str()) {
- html! {
-
- }
- } else {
- html! {}
- }
- } else if part.get("type").and_then(|t| t.as_str()) == Some("image") {
- // Anthropic format
- if let Some(source) = part.get("source") {
- if let Some(data) = source.get("data").and_then(|d| d.as_str()) {
- if let Some(media_type) = source.get("media_type").and_then(|m| m.as_str()) {
- let url = format!("data:{media_type};base64,{data}");
- html! {
-
- }
- } else {
- html! {}
- }
- } else {
- html! {}
- }
- } else {
- html! {}
- }
- } else {
- // For other content types, show as JSON
- html! {
-
- {serde_json::to_string_pretty(part).unwrap_or_default()}
-
- }
- }
- })}
- >
- }
- }
- Some(Value::Object(obj)) => {
- // Try to extract text content
- if let Some(text) = obj.get("text").and_then(|t| t.as_str()) {
- if is_streaming && is_last {
- html! {
-
- }
- } else {
- render_markdown(text)
- }
- } else {
- // Show as formatted JSON
- html! {
-
- {serde_json::to_string_pretty(obj).unwrap_or_default()}
-
- }
- }
- }
- Some(other) => {
- // For other types, show as JSON
- html! {
-
- {serde_json::to_string_pretty(other).unwrap_or_default()}
-
- }
- }
- }
-}
-
-fn render_tool_call(tool_call: &Value) -> Html {
- let id = tool_call
- .get("id")
- .and_then(|v| v.as_str())
- .unwrap_or("unknown");
-
- let function_name = tool_call
- .get("function")
- .and_then(|f| f.get("name"))
- .and_then(|n| n.as_str())
- .unwrap_or("unknown");
-
- let args = tool_call
- .get("function")
- .and_then(|f| f.get("arguments"))
- .and_then(|a| a.as_str())
- .and_then(|args_str| serde_json::from_str::(args_str).ok())
- .and_then(|v| serde_json::to_string_pretty(&v).ok())
- .unwrap_or_else(|| {
- tool_call
- .get("function")
- .and_then(|f| f.get("arguments"))
- .and_then(|a| a.as_str())
- .unwrap_or("")
- .to_string()
- });
-
- html! {
-
-
- {format!("{} ({})", function_name, id)}
-
-
- {args}
-
-
- }
-}
-
-fn render_extra_metadata(metadata: &std::collections::HashMap) -> Html {
- // Filter out known fields that are already displayed
- let skip_fields = ["finish_reason", "refusal", "is_streaming"];
- let extra_fields: Vec<_> = metadata
- .iter()
- .filter(|(key, _)| !skip_fields.contains(&key.as_str()))
- .collect();
-
- if extra_fields.is_empty() {
- return html! {};
- }
-
- html! {
-
- {for extra_fields.iter().map(|(key, value)| {
- html! {
-
- {format!("{}: ", key)}
- {format_metadata_value(value)}
-
- }
- })}
-
- }
-}
-
-fn format_metadata_value(value: &Value) -> String {
- match value {
- Value::String(s) => s.clone(),
- Value::Number(n) => n.to_string(),
- Value::Bool(b) => b.to_string(),
- Value::Null => "null".to_string(),
- _ => serde_json::to_string(value).unwrap_or_default(),
- }
-}
-
-#[derive(Properties, Clone, PartialEq)]
-struct ImageDisplayProps {
- pub url: String,
-}
-
-#[function_component(ImageDisplay)]
-fn image_display(props: &ImageDisplayProps) -> Html {
- let expanded = use_state(|| false);
-
- let toggle_expanded = {
- let expanded = expanded.clone();
- Callback::from(move |_: MouseEvent| {
- expanded.set(!*expanded);
- })
- };
-
- if *expanded {
- // Full screen overlay
- html! {
- <>
-
-
-
-
-
-
-
-
-
-
-
- >
- }
- } else {
- // Thumbnail view
- html! {
-
-
-
- }
- }
-}
diff --git a/crates/chat-ui/src/components/message_list.rs b/crates/chat-ui/src/components/message_list.rs
deleted file mode 100644
index faa9350d..00000000
--- a/crates/chat-ui/src/components/message_list.rs
+++ /dev/null
@@ -1,43 +0,0 @@
-use crate::components::Message;
-use crate::styles::{FLEX_COL_GAP_4, STANDARD_PADDING};
-use crate::types::ChatMessage;
-use web_sys::Element;
-use yew::prelude::*;
-
-#[derive(Properties, Clone, PartialEq)]
-pub struct MessageListProps {
- pub messages: Vec,
- #[prop_or_default]
- pub class: Classes,
-}
-
-#[function_component(MessageList)]
-pub fn message_list(props: &MessageListProps) -> Html {
- let MessageListProps { messages, class } = props;
-
- let container_ref = use_node_ref();
-
- // Auto-scroll to bottom when new messages arrive
- use_effect_with(messages.len(), {
- let container_ref = container_ref.clone();
- move |_| {
- if let Some(element) = container_ref.cast::() {
- element.set_scroll_top(element.scroll_height());
- }
- }
- });
-
- html! {
-
- {for messages.iter().enumerate().map(|(index, message)| {
- html! {
-
- }
- })}
-
- }
-}
diff --git a/crates/chat-ui/src/components/mod.rs b/crates/chat-ui/src/components/mod.rs
deleted file mode 100644
index e8a7142c..00000000
--- a/crates/chat-ui/src/components/mod.rs
+++ /dev/null
@@ -1,13 +0,0 @@
-mod chat_container;
-mod chat_input;
-mod message;
-mod message_list;
-mod streaming_indicator;
-mod streaming_text;
-
-pub use chat_container::ChatContainer;
-pub use chat_input::ChatInput;
-pub use message::Message;
-pub use message_list::MessageList;
-pub use streaming_indicator::StreamingIndicator;
-pub use streaming_text::StreamingText;
diff --git a/crates/chat-ui/src/components/streaming_indicator.rs b/crates/chat-ui/src/components/streaming_indicator.rs
deleted file mode 100644
index 4026d551..00000000
--- a/crates/chat-ui/src/components/streaming_indicator.rs
+++ /dev/null
@@ -1,23 +0,0 @@
-use crate::styles::FLEX_CENTER;
-use yew::prelude::*;
-
-#[derive(Properties, Clone, PartialEq)]
-pub struct StreamingIndicatorProps {
- #[prop_or_default]
- pub class: Classes,
-}
-
-#[function_component(StreamingIndicator)]
-pub fn streaming_indicator(props: &StreamingIndicatorProps) -> Html {
- let StreamingIndicatorProps { class } = props;
-
- html! {
-
- }
-}
diff --git a/crates/chat-ui/src/components/streaming_text.rs b/crates/chat-ui/src/components/streaming_text.rs
deleted file mode 100644
index 36bcf042..00000000
--- a/crates/chat-ui/src/components/streaming_text.rs
+++ /dev/null
@@ -1,202 +0,0 @@
-use crate::utils::markdown::render_markdown;
-use gloo_timers::callback::{Interval, Timeout};
-use std::cell::RefCell;
-use std::rc::Rc;
-use yew::prelude::*;
-
-#[derive(Properties, Clone, PartialEq)]
-pub struct StreamingTextProps {
- pub text: String,
- pub streaming: bool,
- #[prop_or(25)]
- pub initial_delay_ms: u32,
- #[prop_or(5)]
- pub final_delay_ms: u32,
- #[prop_or_default]
- pub class: Classes,
-}
-
-#[derive(Clone, PartialEq)]
-struct StreamingState {
- current_text: String,
- current_index: usize,
- start_time: f64,
-}
-
-enum StreamingAction {
- Reset,
- Advance(String, usize), // text, index
- SetComplete(String),
-}
-
-impl Reducible for StreamingState {
- type Action = StreamingAction;
-
- fn reduce(self: Rc, action: Self::Action) -> Rc {
- let now = js_sys::Date::now();
- match action {
- StreamingAction::Reset => Rc::new(StreamingState {
- current_text: String::new(),
- current_index: 0,
- start_time: now,
- }),
- StreamingAction::Advance(text, index) => Rc::new(StreamingState {
- current_text: text,
- current_index: index,
- start_time: self.start_time,
- }),
- StreamingAction::SetComplete(text) => Rc::new(StreamingState {
- current_text: text.clone(),
- current_index: text.len(),
- start_time: self.start_time,
- }),
- }
- }
-}
-
-#[function_component(StreamingText)]
-pub fn streaming_text(props: &StreamingTextProps) -> Html {
- let StreamingTextProps {
- text,
- streaming,
- initial_delay_ms,
- final_delay_ms,
- class,
- } = props;
-
- let state = use_reducer(|| StreamingState {
- current_text: String::new(),
- current_index: 0,
- start_time: js_sys::Date::now(),
- });
- let interval_handle = use_state(|| None::);
-
- // Reset when text changes
- use_effect_with(text.clone(), {
- let state = state.clone();
- let interval_handle = interval_handle.clone();
- move |_| {
- interval_handle.set(None); // Clear interval
- state.dispatch(StreamingAction::Reset);
- }
- });
-
- // Streaming effect
- use_effect_with(
- (text.clone(), *streaming, *initial_delay_ms, *final_delay_ms),
- {
- let state = state.clone();
- let interval_handle = interval_handle.clone();
-
- move |(text, streaming, initial_delay, final_delay)| {
- // Clone values to avoid lifetime issues
- let text = text.clone();
- let streaming = *streaming;
- let initial_delay = *initial_delay;
- let final_delay = *final_delay;
-
- // Clear any existing interval
- interval_handle.set(None);
-
- if !streaming {
- // If not streaming, show all text immediately
- state.dispatch(StreamingAction::SetComplete(text));
- return;
- }
-
- // Start with empty text
- state.dispatch(StreamingAction::Reset);
-
- // Create interval for streaming animation
- let current_idx = Rc::new(RefCell::new(0usize));
- let _start_time = js_sys::Date::now();
-
- let setup_next_interval = Rc::new(RefCell::new(None::>));
- let setup_next_interval_clone = setup_next_interval.clone();
-
- *setup_next_interval.borrow_mut() = Some(Box::new({
- let state = state.clone();
- let interval_handle = interval_handle.clone();
- let text = text.clone();
- let current_idx = current_idx.clone();
- let setup_next_interval = setup_next_interval_clone.clone();
-
- move || {
- let idx = *current_idx.borrow();
-
- if idx >= text.len() {
- // Done streaming, clear interval
- interval_handle.set(None);
- return;
- }
-
- // Find next character boundary to avoid splitting UTF-8
- let mut next_idx = idx + 1;
- while next_idx < text.len() && !text.is_char_boundary(next_idx) {
- next_idx += 1;
- }
-
- // Calculate progress and delay with aggressive acceleration
- let progress = next_idx as f64 / text.len() as f64;
- let normalized = progress.clamp(0.0, 1.0);
- // Much more aggressive exponential curve: -8.0 instead of -3.0
- let factor = 1.0 - (-8.0 * normalized).exp();
- let delay =
- initial_delay as f64 - (initial_delay - final_delay) as f64 * factor;
- let delay = delay.max(final_delay as f64) as u32;
-
- // Update displayed text
- let new_text = text[..next_idx].to_string();
-
- // Update both the display state and our local index
- state.dispatch(StreamingAction::Advance(new_text, next_idx));
- *current_idx.borrow_mut() = next_idx;
-
- // Schedule next update with dynamic delay
- if next_idx < text.len() {
- let setup_clone = setup_next_interval.clone();
- let timeout = Timeout::new(delay, move || {
- if let Some(ref setup_fn) = *setup_clone.borrow() {
- setup_fn();
- }
- });
- timeout.forget();
- }
- }
- }));
-
- // Start the first interval
- if let Some(ref setup_fn) = *setup_next_interval.borrow() {
- setup_fn();
- }
- }
- },
- );
-
- // Cleanup interval on unmount
- use_effect_with((), {
- let interval_handle = interval_handle.clone();
- move |_| {
- move || {
- interval_handle.set(None);
- }
- }
- });
-
- // Simple, clean rendering without character-level spans
- let displayed_text = if *streaming {
- &state.current_text
- } else {
- text
- };
-
- html! {
-
- {render_markdown(displayed_text)}
-
- if *streaming && state.current_index < text.len() {
- {"▋"}
- }
-
- }
-}
diff --git a/crates/chat-ui/src/lib.rs b/crates/chat-ui/src/lib.rs
deleted file mode 100644
index 75b93e17..00000000
--- a/crates/chat-ui/src/lib.rs
+++ /dev/null
@@ -1,13 +0,0 @@
-pub mod components;
-pub mod parsers;
-pub mod styles;
-pub mod types;
-pub mod utils;
-
-// Re-export main components
-pub use components::{ChatContainer, Message, MessageList, StreamingIndicator};
-pub use types::{
- Attachment, ChatMessage, ChatResponse, ContentBlock, MessageContent, MessageRole,
- MultimodalMessage, Provider, ToolCall, ToolResponse, Usage,
-};
-pub use utils::flexible_parser::parse_cassette;
diff --git a/crates/chat-ui/src/parsers/anthropic.rs b/crates/chat-ui/src/parsers/anthropic.rs
deleted file mode 100644
index b6e9fd85..00000000
--- a/crates/chat-ui/src/parsers/anthropic.rs
+++ /dev/null
@@ -1,138 +0,0 @@
-use crate::types::{ChatMessage, ChatResponse, Provider, Usage};
-use anyhow::Result;
-use serde_json::{Value, json};
-use std::collections::HashMap;
-
-/// Parse Anthropic API response
-pub fn parse_response(response: Value, request: Value) -> Result {
- // Extract messages from request
- let mut messages = parse_request_messages(&request);
-
- // Parse the response content
- if let Some(content_array) = response.get("content").and_then(|c| c.as_array()) {
- let mut combined_content = Vec::new();
- let mut tool_calls = Vec::new();
-
- for content in content_array {
- let content_type = content.get("type").and_then(|t| t.as_str()).unwrap_or("");
-
- match content_type {
- "text" => {
- if let Some(text) = content.get("text") {
- combined_content.push(json!({
- "type": "text",
- "text": text
- }));
- }
- }
- "tool_use" => {
- // Anthropic's tool format
- tool_calls.push(content.clone());
- }
- _ => {
- // Other content types (images, etc.)
- combined_content.push(content.clone());
- }
- }
- }
-
- // Create assistant message
- let mut assistant_msg = ChatMessage {
- role: "assistant".to_string(),
- content: if combined_content.is_empty() {
- None
- } else if combined_content.len() == 1
- && combined_content[0].get("type").and_then(|t| t.as_str()) == Some("text")
- {
- combined_content[0].get("text").cloned()
- } else {
- Some(Value::Array(combined_content))
- },
- tool_calls: if tool_calls.is_empty() {
- None
- } else {
- Some(tool_calls)
- },
- name: None,
- metadata: HashMap::new(),
- };
-
- // Add stop_reason as metadata
- if let Some(stop_reason) = response.get("stop_reason") {
- assistant_msg
- .metadata
- .insert("finish_reason".to_string(), stop_reason.clone());
- }
-
- messages.push(assistant_msg);
- }
-
- // Parse usage with field aliasing
- let usage = response.get("usage").map(|usage_obj| Usage {
- prompt_tokens: usage_obj
- .get("input_tokens")
- .and_then(|v| v.as_i64())
- .map(|v| v as i32),
- completion_tokens: usage_obj
- .get("output_tokens")
- .and_then(|v| v.as_i64())
- .map(|v| v as i32),
- total_tokens: None, // Anthropic doesn't provide total_tokens
- metadata: serde_json::from_value(usage_obj.clone()).unwrap_or_default(),
- });
-
- // Build response with all metadata captured
- let mut metadata: HashMap = serde_json::from_value(response.clone())?;
- // Remove fields we've explicitly handled
- metadata.remove("content");
- metadata.remove("usage");
- metadata.remove("id");
- metadata.remove("model");
-
- Ok(ChatResponse {
- id: response
- .get("id")
- .and_then(|v| v.as_str())
- .unwrap_or("")
- .to_string(),
- model: response
- .get("model")
- .and_then(|v| v.as_str())
- .unwrap_or("")
- .to_string(),
- messages,
- provider: Provider::Anthropic,
- usage,
- metadata,
- })
-}
-
-fn parse_request_messages(request: &Value) -> Vec {
- let mut messages = Vec::new();
-
- // Add system message if present
- if let Some(system) = request.get("system").and_then(|s| s.as_str()) {
- messages.push(ChatMessage {
- role: "system".to_string(),
- content: Some(Value::String(system.to_string())),
- tool_calls: None,
- name: None,
- metadata: Default::default(),
- });
- }
-
- // Add user/assistant messages
- if let Some(msgs) = request.get("messages").and_then(|m| m.as_array()) {
- for msg in msgs {
- if let Ok(mut message) = serde_json::from_value::(msg.clone()) {
- // Anthropic uses "content" field which can be string or array
- if let Some(content) = msg.get("content") {
- message.content = Some(content.clone());
- }
- messages.push(message);
- }
- }
- }
-
- messages
-}
diff --git a/crates/chat-ui/src/parsers/google.rs b/crates/chat-ui/src/parsers/google.rs
deleted file mode 100644
index 360d7abb..00000000
--- a/crates/chat-ui/src/parsers/google.rs
+++ /dev/null
@@ -1,194 +0,0 @@
-use crate::types::{ChatMessage, ChatResponse, Provider, Usage};
-use anyhow::Result;
-use serde_json::Value;
-use std::collections::HashMap;
-
-/// Parse Google API response
-pub fn parse_response(response: Value, request: Value) -> Result {
- // Extract messages from request
- let mut messages = parse_request_messages(&request);
-
- // Parse candidates (Google's equivalent of choices)
- if let Some(candidates) = response.get("candidates").and_then(|c| c.as_array()) {
- for candidate in candidates {
- if let Some(content) = candidate.get("content")
- && let Some(parts) = content.get("parts").and_then(|p| p.as_array())
- {
- let role = content
- .get("role")
- .and_then(|r| r.as_str())
- .unwrap_or("model") // Google uses "model" instead of "assistant"
- .to_string();
-
- // Extract function calls and regular content separately
- let mut text_parts = Vec::new();
- let mut function_calls = Vec::new();
-
- for part in parts {
- if let Some(function_call) = part.get("functionCall") {
- // Convert Google functionCall to OpenAI-style tool call
- let tool_call =
- convert_google_function_call(function_call, function_calls.len());
- function_calls.push(tool_call);
- } else if let Some(text) = part.get("text") {
- text_parts.push(text.clone());
- } else {
- // For other content types, add to text parts as JSON
- text_parts.push(part.clone());
- }
- }
-
- // Build content from non-function parts
- let content_value = if text_parts.is_empty() {
- None
- } else if text_parts.len() == 1 {
- Some(text_parts[0].clone())
- } else {
- Some(Value::Array(text_parts))
- };
-
- let mut message = ChatMessage {
- role: if role == "model" {
- "assistant".to_string()
- } else {
- role
- },
- content: content_value,
- tool_calls: if function_calls.is_empty() {
- None
- } else {
- Some(function_calls)
- },
- name: None,
- metadata: HashMap::new(),
- };
-
- // Add finish reason as metadata
- if let Some(finish_reason) = candidate.get("finishReason") {
- message
- .metadata
- .insert("finish_reason".to_string(), finish_reason.clone());
- }
-
- messages.push(message);
- }
- }
- }
-
- // Parse usage metadata
- let usage = response.get("usageMetadata").map(|usage_metadata| Usage {
- prompt_tokens: usage_metadata
- .get("promptTokenCount")
- .and_then(|v| v.as_i64())
- .map(|v| v as i32),
- completion_tokens: usage_metadata
- .get("candidatesTokenCount")
- .and_then(|v| v.as_i64())
- .map(|v| v as i32),
- total_tokens: usage_metadata
- .get("totalTokenCount")
- .and_then(|v| v.as_i64())
- .map(|v| v as i32),
- metadata: serde_json::from_value(usage_metadata.clone()).unwrap_or_default(),
- });
-
- // Build response with all metadata
- let mut metadata: HashMap = serde_json::from_value(response.clone())?;
- metadata.remove("candidates");
- metadata.remove("usageMetadata");
-
- Ok(ChatResponse {
- id: response
- .get("id")
- .and_then(|v| v.as_str())
- .unwrap_or("")
- .to_string(),
- model: response
- .get("modelVersion")
- .or_else(|| response.get("model"))
- .and_then(|v| v.as_str())
- .unwrap_or("")
- .to_string(),
- messages,
- provider: Provider::Google,
- usage,
- metadata,
- })
-}
-
-fn parse_request_messages(request: &Value) -> Vec {
- let mut messages = Vec::new();
-
- // Add system instruction if present
- if let Some(system_instruction) = request.get("systemInstruction")
- && let Some(parts) = system_instruction.get("parts").and_then(|p| p.as_array())
- {
- let content = if parts.len() == 1 && parts[0].get("text").is_some() {
- parts[0].get("text").cloned()
- } else {
- Some(Value::Array(parts.to_vec()))
- };
-
- messages.push(ChatMessage {
- role: "system".to_string(),
- content,
- tool_calls: None,
- name: None,
- metadata: Default::default(),
- });
- }
-
- // Add conversation contents
- if let Some(contents) = request.get("contents").and_then(|c| c.as_array()) {
- for content in contents {
- let role = content
- .get("role")
- .and_then(|r| r.as_str())
- .unwrap_or("user")
- .to_string();
-
- if let Some(parts) = content.get("parts").and_then(|p| p.as_array()) {
- let content_value = if parts.len() == 1 && parts[0].get("text").is_some() {
- parts[0].get("text").cloned()
- } else {
- Some(Value::Array(parts.to_vec()))
- };
-
- messages.push(ChatMessage {
- role: if role == "model" {
- "assistant".to_string()
- } else {
- role
- },
- content: content_value,
- tool_calls: None,
- name: None,
- metadata: Default::default(),
- });
- }
- }
- }
-
- messages
-}
-
-/// Convert Google functionCall format to OpenAI tool call format
-fn convert_google_function_call(function_call: &Value, index: usize) -> Value {
- let function_name = function_call
- .get("name")
- .and_then(|n| n.as_str())
- .unwrap_or("unknown");
-
- let empty_args = Value::Object(serde_json::Map::new());
- let args = function_call.get("args").unwrap_or(&empty_args);
-
- // Convert to OpenAI format
- serde_json::json!({
- "id": format!("call_{}", index),
- "type": "function",
- "function": {
- "name": function_name,
- "arguments": serde_json::to_string(args).unwrap_or_default()
- }
- })
-}
diff --git a/crates/chat-ui/src/parsers/mod.rs b/crates/chat-ui/src/parsers/mod.rs
deleted file mode 100644
index 42a38aea..00000000
--- a/crates/chat-ui/src/parsers/mod.rs
+++ /dev/null
@@ -1,65 +0,0 @@
-pub mod anthropic;
-pub mod google;
-pub mod openai;
-pub mod streaming;
-
-use crate::types::{ChatResponse, Provider};
-use crate::utils::cassette_loader::CassetteInteraction;
-use anyhow::Result;
-use serde_json::Value;
-
-/// Decompress gzip data if needed
-fn decompress_response_body(
- body: &str,
- headers: &std::collections::HashMap>,
-) -> Result {
- // Check if the response is gzip-compressed
- let is_gzipped = headers
- .get("Content-Encoding")
- .or_else(|| headers.get("content-encoding"))
- .map(|values| values.iter().any(|v| v.to_lowercase().contains("gzip")))
- .unwrap_or(false);
-
- if !is_gzipped {
- return Ok(body.to_string());
- }
-
- // Try to decode base64 first (for binary YAML data)
- // Since we decompress when capturing, just return the body as-is
- Ok(body.to_string())
-}
-
-/// Parse a cassette interaction into a flexible chat response
-pub fn parse_interaction(interaction: &CassetteInteraction) -> Result {
- let provider = Provider::from_uri(&interaction.request.uri);
- let request_body: Value = serde_json::from_str(&interaction.request.body)?;
-
- // Decompress response body if needed
- let response_body = decompress_response_body(
- &interaction.response.body.string,
- &interaction.response.headers,
- )?;
-
- // Check if this is a streaming response (SSE format)
- if response_body.starts_with("data: ")
- || response_body.starts_with("event: ")
- || response_body.contains("\ndata: ")
- {
- streaming::parse_streaming_response(&response_body, provider, request_body)
- } else {
- // Parse as regular JSON response
- let response_json: Value = serde_json::from_str(&response_body)?;
-
- match provider {
- Provider::OpenAI => openai::parse_response(response_json, request_body),
- Provider::Anthropic => anthropic::parse_response(response_json, request_body),
- Provider::Google => google::parse_response(response_json, request_body),
- Provider::Unknown(_) => {
- // Generic parsing - just try to deserialize directly
- let mut response: ChatResponse = serde_json::from_value(response_json)?;
- response.provider = provider;
- Ok(response)
- }
- }
- }
-}
diff --git a/crates/chat-ui/src/parsers/openai.rs b/crates/chat-ui/src/parsers/openai.rs
deleted file mode 100644
index f7b08b5b..00000000
--- a/crates/chat-ui/src/parsers/openai.rs
+++ /dev/null
@@ -1,187 +0,0 @@
-use crate::types::{ChatMessage, ChatResponse, Provider};
-use anyhow::Result;
-use serde_json::Value;
-
-/// Parse OpenAI API response
-pub fn parse_response(response: Value, request: Value) -> Result {
- // Extract messages from request
- let messages = parse_request_messages(&request);
-
- // Check if this is an error response first
- if let Some(_error) = response.get("error") {
- return parse_error_response(response, messages, &request);
- }
-
- // Handle different OpenAI response formats
- if response.get("choices").is_some() {
- // Chat Completions API
- parse_chat_completion_response(response, messages)
- } else if response.get("output").is_some() {
- // Responses API (/v1/responses)
- parse_responses_api_response(response, messages)
- } else {
- // Unknown format - try generic parsing
- let mut chat_response: ChatResponse = match serde_json::from_value(response.clone()) {
- Ok(resp) => resp,
- Err(_) => {
- // If parsing fails, create a basic response with the raw data
- ChatResponse {
- id: response
- .get("id")
- .and_then(|v| v.as_str())
- .unwrap_or("unknown")
- .to_string(),
- model: response
- .get("model")
- .and_then(|v| v.as_str())
- .unwrap_or("unknown")
- .to_string(),
- messages,
- provider: Provider::OpenAI,
- usage: None,
- metadata: serde_json::from_value(response).unwrap_or_default(),
- }
- }
- };
- chat_response.provider = Provider::OpenAI;
- Ok(chat_response)
- }
-}
-
-fn parse_request_messages(request: &Value) -> Vec {
- let mut messages = Vec::new();
-
- // Try to extract messages from request
- if let Some(msgs) = request.get("messages").and_then(|m| m.as_array()) {
- for msg in msgs {
- // Parse each message more carefully to handle multipart content
- let role = msg
- .get("role")
- .and_then(|r| r.as_str())
- .unwrap_or("user")
- .to_string();
-
- let content = msg.get("content").cloned();
- let name = msg
- .get("name")
- .and_then(|n| n.as_str())
- .map(|s| s.to_string());
-
- messages.push(ChatMessage {
- role,
- content,
- tool_calls: None,
- name,
- metadata: Default::default(),
- });
- }
- } else if let Some(input) = request.get("input").and_then(|i| i.as_str()) {
- // Responses API format
- messages.push(ChatMessage {
- role: "user".to_string(),
- content: Some(Value::String(input.to_string())),
- tool_calls: None,
- name: None,
- metadata: Default::default(),
- });
- }
-
- messages
-}
-
-fn parse_chat_completion_response(
- response: Value,
- mut messages: Vec,
-) -> Result {
- // Add assistant messages from choices
- if let Some(choices) = response.get("choices").and_then(|c| c.as_array()) {
- for choice in choices {
- if let Some(message) = choice.get("message")
- && let Ok(msg) = serde_json::from_value::(message.clone())
- {
- messages.push(msg);
- }
- }
- }
-
- // Create the response with all fields captured
- let mut chat_response: ChatResponse = serde_json::from_value(response)?;
- chat_response.provider = Provider::OpenAI;
- chat_response.messages = messages;
-
- Ok(chat_response)
-}
-
-fn parse_responses_api_response(
- response: Value,
- mut messages: Vec,
-) -> Result {
- // Extract output messages
- if let Some(outputs) = response.get("output").and_then(|o| o.as_array()) {
- for output in outputs {
- let role = output
- .get("role")
- .and_then(|r| r.as_str())
- .unwrap_or("assistant")
- .to_string();
-
- let content = output
- .get("content")
- .cloned()
- .or_else(|| Some(Value::Array(vec![])));
-
- messages.push(ChatMessage {
- role,
- content,
- tool_calls: None,
- name: None,
- metadata: Default::default(),
- });
- }
- }
-
- let mut chat_response: ChatResponse = serde_json::from_value(response)?;
- chat_response.provider = Provider::OpenAI;
- chat_response.messages = messages;
-
- Ok(chat_response)
-}
-
-fn parse_error_response(
- response: Value,
- mut messages: Vec,
- request: &Value,
-) -> Result {
- // Add error as a system message
- if let Some(error) = response.get("error") {
- let error_message = error
- .get("message")
- .and_then(|m| m.as_str())
- .unwrap_or("Unknown error")
- .to_string();
-
- messages.push(ChatMessage {
- role: "system".to_string(),
- content: Some(Value::String(error_message)),
- tool_calls: None,
- name: None,
- metadata: Default::default(),
- });
- }
-
- // Extract model from request instead of hardcoding "error"
- let model = request
- .get("model")
- .and_then(|m| m.as_str())
- .unwrap_or("unknown")
- .to_string();
-
- Ok(ChatResponse {
- id: "error".to_string(),
- model,
- messages,
- provider: Provider::OpenAI,
- usage: None,
- metadata: Default::default(),
- })
-}
diff --git a/crates/chat-ui/src/parsers/streaming.rs b/crates/chat-ui/src/parsers/streaming.rs
deleted file mode 100644
index 1288e2b8..00000000
--- a/crates/chat-ui/src/parsers/streaming.rs
+++ /dev/null
@@ -1,290 +0,0 @@
-use crate::types::{ChatMessage, ChatResponse, Provider};
-use anyhow::Result;
-use serde_json::{Value, json};
-use std::collections::HashMap;
-
-/// Parse SSE streaming response data
-pub fn parse_streaming_response(
- sse_data: &str,
- provider: Provider,
- request: Value,
-) -> Result {
- match provider {
- Provider::OpenAI => parse_openai_streaming(sse_data, request),
- Provider::Anthropic => parse_anthropic_streaming(sse_data, request),
- Provider::Google => parse_google_streaming(sse_data, request),
- Provider::Unknown(_) => {
- // Generic streaming - just create a message with the content
- Ok(ChatResponse {
- id: "streaming".to_string(),
- model: "unknown".to_string(),
- messages: vec![ChatMessage {
- role: "assistant".to_string(),
- content: Some(Value::String(sse_data.to_string())),
- tool_calls: None,
- name: None,
- metadata: Default::default(),
- }],
- provider,
- usage: None,
- metadata: Default::default(),
- })
- }
- }
-}
-
-fn parse_openai_streaming(sse_data: &str, request: Value) -> Result {
- let mut messages = extract_request_messages(&request);
- let mut combined_content = String::new();
- let mut model = String::new();
- let mut id = String::new();
- let mut metadata = HashMap::new();
- let mut tool_calls: Vec = Vec::new();
-
- // Parse each SSE chunk
- for line in sse_data.lines() {
- if let Some(data) = line.strip_prefix("data: ") {
- let data = data.trim();
-
- // Skip empty data lines
- if data.is_empty() {
- continue;
- }
-
- if data == "[DONE]" {
- break;
- }
-
- match serde_json::from_str::(data) {
- Ok(chunk) => {
- // Extract model and id from first chunk
- if model.is_empty() {
- if let Some(m) = chunk.get("model").and_then(|v| v.as_str()) {
- model = m.to_string();
- }
- if let Some(i) = chunk.get("id").and_then(|v| v.as_str()) {
- id = i.to_string();
- }
-
- // Store system_fingerprint and service_tier if present
- if let Some(sf) = chunk.get("system_fingerprint") {
- metadata.insert("system_fingerprint".to_string(), sf.clone());
- }
- if let Some(st) = chunk.get("service_tier") {
- metadata.insert("service_tier".to_string(), st.clone());
- }
- }
-
- // Extract content from choices
- if let Some(choices) = chunk.get("choices").and_then(|c| c.as_array()) {
- for choice in choices {
- if let Some(delta) = choice.get("delta") {
- // Handle text content
- if let Some(content) = delta.get("content").and_then(|c| c.as_str())
- {
- combined_content.push_str(content);
- }
-
- // Handle tool calls
- if let Some(tcs) =
- delta.get("tool_calls").and_then(|t| t.as_array())
- {
- for tc in tcs {
- tool_calls.push(tc.clone());
- }
- }
- }
- }
- }
- }
- Err(e) => {
- // Log parsing error but continue processing
- eprintln!("Warning: Failed to parse OpenAI SSE data '{data}': {e}");
- continue;
- }
- }
- }
- }
-
- // Create assistant message
- let mut assistant_msg = ChatMessage {
- role: "assistant".to_string(),
- content: if combined_content.is_empty() {
- None
- } else {
- Some(Value::String(combined_content))
- },
- tool_calls: if tool_calls.is_empty() {
- None
- } else {
- Some(tool_calls)
- },
- name: None,
- metadata: HashMap::new(),
- };
-
- // Mark as streaming if content is substantial
- if assistant_msg.content.is_some() {
- assistant_msg
- .metadata
- .insert("is_streaming".to_string(), json!(true));
- }
-
- messages.push(assistant_msg);
-
- Ok(ChatResponse {
- id,
- model,
- messages,
- provider: Provider::OpenAI,
- usage: None,
- metadata,
- })
-}
-
-fn parse_anthropic_streaming(sse_data: &str, request: Value) -> Result {
- let mut messages = extract_request_messages(&request);
- let mut combined_content = String::new();
- let mut model = String::new();
- let mut id = String::new();
- let mut metadata = HashMap::new();
-
- // Parse SSE events
- for line in sse_data.lines() {
- if let Some(data) = line.strip_prefix("data: ") {
- let data = data.trim();
-
- // Skip empty data lines
- if data.is_empty() {
- continue;
- }
-
- // Handle special termination markers
- if data == "[DONE]" {
- break;
- }
-
- match serde_json::from_str::(data) {
- Ok(event) => {
- let event_type = event.get("type").and_then(|t| t.as_str()).unwrap_or("");
-
- match event_type {
- "message_start" => {
- if let Some(message) = event.get("message") {
- if let Some(m) = message.get("model").and_then(|v| v.as_str()) {
- model = m.to_string();
- }
- if let Some(i) = message.get("id").and_then(|v| v.as_str()) {
- id = i.to_string();
- }
- }
- }
- "content_block_delta" => {
- if let Some(delta) = event.get("delta")
- && let Some(text) = delta.get("text").and_then(|t| t.as_str())
- {
- combined_content.push_str(text);
- }
- }
- "message_delta" => {
- if let Some(delta) = event.get("delta")
- && let Some(stop_reason) = delta.get("stop_reason")
- {
- metadata.insert("stop_reason".to_string(), stop_reason.clone());
- }
- }
- _ => {}
- }
- }
- Err(e) => {
- // Log parsing error but continue processing
- eprintln!("Warning: Failed to parse SSE data '{data}': {e}");
- continue;
- }
- }
- }
- }
-
- let mut assistant_msg = ChatMessage {
- role: "assistant".to_string(),
- content: if combined_content.is_empty() {
- None
- } else {
- Some(Value::String(combined_content))
- },
- tool_calls: None,
- name: None,
- metadata: HashMap::new(),
- };
-
- if assistant_msg.content.is_some() {
- assistant_msg
- .metadata
- .insert("is_streaming".to_string(), json!(true));
- }
-
- messages.push(assistant_msg);
-
- Ok(ChatResponse {
- id,
- model,
- messages,
- provider: Provider::Anthropic,
- usage: None,
- metadata,
- })
-}
-
-fn parse_google_streaming(_sse_data: &str, request: Value) -> Result {
- // Google uses a different streaming format (not SSE)
- // For now, treat it as a single response
- let messages = extract_request_messages(&request);
-
- Ok(ChatResponse {
- id: "streaming".to_string(),
- model: "google".to_string(),
- messages,
- provider: Provider::Google,
- usage: None,
- metadata: Default::default(),
- })
-}
-
-/// Extract messages from request regardless of provider format
-fn extract_request_messages(request: &Value) -> Vec {
- let mut messages = Vec::new();
-
- // Common message extraction patterns
- if let Some(msgs) = request.get("messages").and_then(|m| m.as_array()) {
- for msg in msgs {
- if let Ok(message) = serde_json::from_value::(msg.clone()) {
- messages.push(message);
- }
- }
- }
-
- // System message (Anthropic style)
- if let Some(system) = request.get("system").and_then(|s| s.as_str()) {
- messages.insert(
- 0,
- ChatMessage {
- role: "system".to_string(),
- content: Some(Value::String(system.to_string())),
- tool_calls: None,
- name: None,
- metadata: Default::default(),
- },
- );
- }
-
- // Google contents format
- if let Some(contents) = request.get("contents").and_then(|c| c.as_array()) {
- for content in contents {
- if let Ok(message) = serde_json::from_value::(content.clone()) {
- messages.push(message);
- }
- }
- }
-
- messages
-}
diff --git a/crates/chat-ui/src/styles.rs b/crates/chat-ui/src/styles.rs
deleted file mode 100644
index d2b46070..00000000
--- a/crates/chat-ui/src/styles.rs
+++ /dev/null
@@ -1,87 +0,0 @@
-//! Centralized style constants for consistent theming across the chat UI components
-
-// Background colors with dark mode support
-pub const CONTAINER_BG: &str = "bg-gray-50 dark:bg-gray-900";
-pub const CARD_BG: &str = "bg-white dark:bg-gray-800";
-pub const SECONDARY_BG: &str = "bg-gray-50 dark:bg-gray-700";
-pub const TERTIARY_BG: &str = "bg-gray-100 dark:bg-gray-700";
-
-// Text colors with dark mode support
-pub const PRIMARY_TEXT: &str = "text-gray-900 dark:text-gray-100";
-pub const SECONDARY_TEXT: &str = "text-gray-700 dark:text-gray-300";
-pub const TERTIARY_TEXT: &str = "text-gray-600 dark:text-gray-400";
-pub const MUTED_TEXT: &str = "text-gray-500 dark:text-gray-400";
-
-// Border colors with dark mode support
-pub const PRIMARY_BORDER: &str = "border-gray-200 dark:border-gray-700";
-pub const SECONDARY_BORDER: &str = "border-gray-300 dark:border-gray-600";
-
-// Status color pairs (background + text)
-pub const ERROR_BG: &str = "bg-red-50 dark:bg-red-900";
-pub const ERROR_TEXT: &str = "text-red-700 dark:text-red-300";
-pub const ERROR_BORDER: &str = "border-red-200 dark:border-red-700";
-
-pub const SUCCESS_BG: &str = "bg-green-50 dark:bg-green-900";
-pub const SUCCESS_TEXT: &str = "text-green-800 dark:text-green-200";
-
-pub const INFO_BG: &str = "bg-blue-50 dark:bg-blue-900";
-pub const INFO_TEXT: &str = "text-blue-800 dark:text-blue-200";
-
-pub const WARNING_BG: &str = "bg-orange-50 dark:bg-orange-900";
-pub const WARNING_TEXT: &str = "text-orange-800 dark:text-orange-200";
-
-// Message bubble styles (moved from message.rs)
-pub const USER_BUBBLE_COLORS: &str =
- "bg-blue-100 dark:bg-blue-900 ml-10 md:ml-20 border border-blue-200 dark:border-blue-800";
-pub const ASSISTANT_BUBBLE_COLORS: &str =
- "bg-white dark:bg-gray-700 mr-10 md:mr-20 border border-gray-200 dark:border-gray-600";
-pub const SYSTEM_BUBBLE_COLORS: &str =
- "bg-orange-100 dark:bg-orange-900 italic border border-orange-200 dark:border-orange-800";
-pub const TOOL_BUBBLE_COLORS: &str =
- "bg-blue-50 dark:bg-blue-900 font-mono text-sm border border-blue-200 dark:border-blue-800";
-pub const DEFAULT_BUBBLE_COLORS: &str = "bg-white border border-gray-200 dark:border-gray-700";
-
-// Button styles
-pub const PRIMARY_BUTTON: &str = "px-4 py-2 bg-blue-500 hover:bg-blue-600 text-white rounded-md transition-colors disabled:bg-gray-300 dark:disabled:bg-gray-600 disabled:cursor-not-allowed";
-pub const SECONDARY_BUTTON: &str = "px-4 py-2 bg-gray-200 hover:bg-gray-300 dark:bg-gray-700 dark:hover:bg-gray-600 text-gray-700 dark:text-gray-300 rounded-md transition-colors";
-pub const DANGER_BUTTON: &str =
- "px-4 py-2 bg-red-500 hover:bg-red-600 text-white rounded-md transition-colors";
-
-// Input styles
-pub const INPUT_BASE: &str = "w-full px-3 py-2 border rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500";
-pub const INPUT_COLORS: &str =
- "border-gray-300 dark:border-gray-600 dark:bg-gray-700 dark:text-gray-200";
-pub const TEXTAREA_BASE: &str = "w-full px-3 py-2 border rounded-md resize-none focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500";
-
-// Code block styles
-pub const CODE_BLOCK: &str = "bg-gray-50 dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded p-2 font-mono text-xs overflow-x-auto whitespace-pre-wrap";
-pub const INLINE_CODE: &str = "bg-gray-100 dark:bg-gray-700 px-1 py-0.5 rounded text-sm font-mono";
-
-// Common layout patterns
-pub const FLEX_COL: &str = "flex flex-col";
-pub const FLEX_COL_GAP_2: &str = "flex flex-col gap-2";
-pub const FLEX_COL_GAP_4: &str = "flex flex-col gap-4";
-pub const FLEX_CENTER: &str = "flex items-center";
-pub const FLEX_CENTER_GAP_2: &str = "flex items-center gap-2";
-pub const FLEX_BETWEEN: &str = "flex justify-between items-center";
-
-// Common spacing
-pub const CARD_PADDING: &str = "p-6";
-pub const STANDARD_PADDING: &str = "p-4";
-pub const HEADER_PADDING: &str = "px-4 py-3";
-pub const BUTTON_PADDING: &str = "px-3 py-2";
-
-// Shadows and rounded corners
-pub const CARD_SHADOW: &str = "shadow-md";
-pub const LIGHT_SHADOW: &str = "shadow-sm";
-pub const ROUNDED_STANDARD: &str = "rounded-lg";
-pub const ROUNDED_SMALL: &str = "rounded-md";
-
-// Transitions
-pub const TRANSITION_COLORS: &str = "transition-colors duration-200";
-pub const TRANSITION_ALL: &str = "transition-all duration-200";
-
-// Utility function to combine multiple style constants
-pub fn combine_styles(styles: &[&str]) -> String {
- styles.join(" ")
-}
diff --git a/crates/chat-ui/src/types/mod.rs b/crates/chat-ui/src/types/mod.rs
deleted file mode 100644
index fabdd1f4..00000000
--- a/crates/chat-ui/src/types/mod.rs
+++ /dev/null
@@ -1,187 +0,0 @@
-mod multimodal;
-
-pub use multimodal::{Attachment, ContentBlock, ImageData, ImageSource, MultimodalMessage};
-
-use serde::{Deserialize, Serialize};
-use serde_json::Value;
-use std::collections::HashMap;
-
-/// Chat response that captures both typed and dynamic fields
-#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
-pub struct ChatResponse {
- // Core fields the UI needs
- #[serde(default)]
- pub id: String,
-
- #[serde(default)]
- pub model: String,
-
- #[serde(default)]
- pub messages: Vec,
-
- // Provider is determined from URI, not from response
- #[serde(skip)]
- pub provider: Provider,
-
- // Usage is common enough to deserve its own field
- #[serde(default)]
- pub usage: Option,
-
- // Everything else (service_tier, system_fingerprint, created, annotations, etc.)
- #[serde(flatten)]
- pub metadata: HashMap,
-}
-
-/// Message that captures both typed and dynamic fields
-#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
-pub struct ChatMessage {
- pub role: String,
-
- #[serde(default)]
- pub content: Option, // Can be string, array, or object
-
- // Common fields
- #[serde(default)]
- pub tool_calls: Option>,
-
- #[serde(default)]
- pub name: Option,
-
- // Everything else (refusal, function_call, tool_call_id, etc.)
- #[serde(flatten)]
- pub metadata: HashMap,
-}
-
-/// Usage information
-#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
-pub struct Usage {
- // Common fields across providers
- #[serde(alias = "prompt_tokens", alias = "input_tokens")]
- pub prompt_tokens: Option,
-
- #[serde(alias = "completion_tokens", alias = "output_tokens")]
- pub completion_tokens: Option,
-
- #[serde(default)]
- pub total_tokens: Option,
-
- // Everything else (cache info, token details, etc.)
- #[serde(flatten)]
- pub metadata: HashMap,
-}
-
-/// Provider types
-#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
-pub enum Provider {
- OpenAI,
- Anthropic,
- Google,
- Unknown(String),
-}
-
-impl Default for Provider {
- fn default() -> Self {
- Provider::Unknown("unknown".to_string())
- }
-}
-
-impl Provider {
- pub fn from_uri(uri: &str) -> Self {
- if uri.contains("openai.com") {
- Provider::OpenAI
- } else if uri.contains("anthropic.com") {
- Provider::Anthropic
- } else if uri.contains("googleapis.com") || uri.contains("google.com") {
- Provider::Google
- } else {
- Provider::Unknown(uri.to_string())
- }
- }
-}
-
-/// Helper methods for ChatMessage
-impl ChatMessage {
- /// Create a new message with role and content
- pub fn new(role: impl Into, content: impl Into) -> Self {
- Self {
- role: role.into(),
- content: Some(Value::String(content.into())),
- tool_calls: None,
- name: None,
- metadata: HashMap::new(),
- }
- }
-
- /// Create a system message
- pub fn system(content: impl Into) -> Self {
- Self::new("system", content)
- }
-
- /// Create a user message
- pub fn user(content: impl Into) -> Self {
- Self::new("user", content)
- }
-
- /// Create an assistant message
- pub fn assistant(content: impl Into) -> Self {
- Self::new("assistant", content)
- }
-
- /// Extract text content from various message formats
- pub fn get_text_content(&self) -> Option {
- match &self.content {
- Some(Value::String(s)) => Some(s.clone()),
- Some(Value::Array(parts)) => {
- // Handle multipart content
- let texts: Vec = parts
- .iter()
- .filter_map(|part| {
- if let Some(text) = part.get("text").and_then(|t| t.as_str()) {
- Some(text.to_string())
- } else {
- part.get("content")
- .and_then(|t| t.as_str())
- .map(|text| text.to_string())
- }
- })
- .collect();
-
- if texts.is_empty() {
- None
- } else {
- Some(texts.join(" "))
- }
- }
- Some(Value::Object(obj)) => {
- // Handle object with text field
- obj.get("text")
- .or_else(|| obj.get("content"))
- .and_then(|v| v.as_str())
- .map(|s| s.to_string())
- }
- _ => None,
- }
- }
-
- /// Check if this message indicates streaming
- pub fn is_streaming(&self) -> bool {
- self.metadata
- .get("is_streaming")
- .and_then(|v| v.as_bool())
- .unwrap_or(false)
- }
-
- /// Get finish reason if available
- pub fn finish_reason(&self) -> Option {
- self.metadata
- .get("finish_reason")
- .and_then(|v| v.as_str())
- .map(|s| s.to_string())
- }
-}
-
-// Legacy type aliases for compatibility
-pub type MessageRole = String;
-pub type MessageContent = Value;
-pub type ToolCall = Value;
-pub type ToolResponse = Value;
diff --git a/crates/chat-ui/src/types/multimodal.rs b/crates/chat-ui/src/types/multimodal.rs
deleted file mode 100644
index 63ed3899..00000000
--- a/crates/chat-ui/src/types/multimodal.rs
+++ /dev/null
@@ -1,115 +0,0 @@
-//! Types for multimodal message content (text, images, files)
-
-use serde::{Deserialize, Serialize};
-
-/// Represents different types of content that can be sent in a message
-#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
-#[serde(tag = "type", rename_all = "snake_case")]
-pub enum ContentBlock {
- /// Plain text content
- Text { text: String },
- /// Image content (base64 encoded or URL)
- #[serde(rename = "image_url")]
- ImageUrl { image_url: ImageData },
- /// Image content for Anthropic format
- Image { source: ImageSource },
-}
-
-/// Image data that can be either a URL or base64 encoded
-#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
-pub struct ImageData {
- pub url: String, // Can be a URL or data:image/jpeg;base64,... format
- #[serde(skip_serializing_if = "Option::is_none")]
- pub detail: Option, // OpenAI specific: "low", "high", "auto"
-}
-
-/// Anthropic-style image source
-#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
-pub struct ImageSource {
- #[serde(rename = "type")]
- pub source_type: String, // "base64"
- pub media_type: String, // "image/jpeg", "image/png", etc.
- pub data: String, // base64 encoded image data
-}
-
-/// Represents an attachment that can be added to a message
-#[derive(Clone, Debug, PartialEq)]
-pub struct Attachment {
- pub name: String,
- pub mime_type: String,
- pub data: Vec, // Raw file data before encoding
- pub size: usize,
-}
-
-impl Attachment {
- /// Convert to base64 data URL format
- pub fn to_data_url(&self) -> String {
- use base64::Engine;
- let base64_data = base64::engine::general_purpose::STANDARD.encode(&self.data);
- format!("data:{};base64,{}", self.mime_type, base64_data)
- }
-
- /// Check if this attachment is an image
- pub fn is_image(&self) -> bool {
- self.mime_type.starts_with("image/")
- }
-
- /// Get a human-readable size string
- pub fn size_string(&self) -> String {
- if self.size < 1024 {
- format!("{} B", self.size)
- } else if self.size < 1024 * 1024 {
- format!("{:.1} KB", self.size as f64 / 1024.0)
- } else {
- format!("{:.1} MB", self.size as f64 / (1024.0 * 1024.0))
- }
- }
-}
-
-/// Message content that can include text and attachments
-#[derive(Clone, Debug, PartialEq)]
-pub struct MultimodalMessage {
- pub text: Option,
- pub attachments: Vec,
-}
-
-impl MultimodalMessage {
- /// Create a text-only message
- pub fn text(text: String) -> Self {
- Self {
- text: Some(text),
- attachments: Vec::new(),
- }
- }
-
- /// Create a message with attachments
- pub fn with_attachments(text: Option, attachments: Vec) -> Self {
- Self { text, attachments }
- }
-
- /// Convert to content blocks for API submission
- pub fn to_content_blocks(&self) -> Vec {
- let mut blocks = Vec::new();
-
- // Add images first (following best practices)
- for attachment in &self.attachments {
- if attachment.is_image() {
- blocks.push(ContentBlock::ImageUrl {
- image_url: ImageData {
- url: attachment.to_data_url(),
- detail: None,
- },
- });
- }
- }
-
- // Add text content after images
- if let Some(text) = &self.text
- && !text.trim().is_empty()
- {
- blocks.push(ContentBlock::Text { text: text.clone() });
- }
-
- blocks
- }
-}
diff --git a/crates/chat-ui/src/utils/cassette_loader.rs b/crates/chat-ui/src/utils/cassette_loader.rs
deleted file mode 100644
index ee551cfd..00000000
--- a/crates/chat-ui/src/utils/cassette_loader.rs
+++ /dev/null
@@ -1,111 +0,0 @@
-use anyhow::Result;
-use serde::{Deserialize, Deserializer, Serialize};
-use std::collections::HashMap;
-
-/// Raw HTTP request data from cassette
-#[derive(Debug, Clone, Serialize, Deserialize)]
-pub struct RawRequest {
- pub uri: String,
- pub method: String,
- #[serde(default)]
- pub headers: HashMap>,
- pub body: String,
-}
-
-/// Raw HTTP response data from cassette
-#[derive(Debug, Clone, Serialize, Deserialize)]
-pub struct RawResponse {
- #[serde(default = "default_status", deserialize_with = "deserialize_status")]
- pub status: u16,
- #[serde(default)]
- pub headers: HashMap>,
- pub body: ResponseBody,
-}
-
-fn default_status() -> u16 {
- 200
-}
-
-/// Deserialize status from either a number or an object with a "code" field
-fn deserialize_status<'de, D>(deserializer: D) -> Result
-where
- D: Deserializer<'de>,
-{
- use serde::de::{self, Visitor};
- use serde_json::Value;
-
- struct StatusVisitor;
-
- impl<'de> Visitor<'de> for StatusVisitor {
- type Value = u16;
-
- fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
- formatter.write_str("a u16 or an object with a 'code' field")
- }
-
- fn visit_u64(self, value: u64) -> Result
- where
- E: de::Error,
- {
- Ok(value as u16)
- }
-
- fn visit_map(self, mut map: M) -> Result
- where
- M: de::MapAccess<'de>,
- {
- let mut code = None;
-
- while let Some(key) = map.next_key::()? {
- if key == "code" {
- code = Some(map.next_value::()?);
- } else {
- // Skip other fields like "message"
- map.next_value::()?;
- }
- }
-
- code.ok_or_else(|| de::Error::missing_field("code"))
- }
- }
-
- deserializer.deserialize_any(StatusVisitor)
-}
-
-#[derive(Debug, Clone, Serialize, Deserialize)]
-pub struct ResponseBody {
- pub string: String,
-}
-
-/// A single HTTP interaction from a cassette
-#[derive(Debug, Clone, Serialize, Deserialize)]
-pub struct CassetteInteraction {
- pub request: RawRequest,
- pub response: RawResponse,
-}
-
-/// Root structure of a cassette file
-#[derive(Debug, Clone, Serialize, Deserialize)]
-struct CassetteFile {
- interactions: Vec,
-}
-
-/// Load a cassette file and return the first interaction
-///
-/// This is a simple, dumb loader that just parses the JSON
-/// and returns the raw HTTP data without any interpretation
-pub fn load_cassette(json_content: &str) -> Result {
- let cassette: CassetteFile = serde_json::from_str(json_content)?;
-
- cassette
- .interactions
- .into_iter()
- .next()
- .ok_or_else(|| anyhow::anyhow!("No interactions found in cassette"))
-}
-
-/// Load all interactions from a cassette file
-pub fn load_all_interactions(json_content: &str) -> Result> {
- let cassette: CassetteFile = serde_json::from_str(json_content)?;
- Ok(cassette.interactions)
-}
diff --git a/crates/chat-ui/src/utils/cassette_parser.rs b/crates/chat-ui/src/utils/cassette_parser.rs
deleted file mode 100644
index a32980d5..00000000
--- a/crates/chat-ui/src/utils/cassette_parser.rs
+++ /dev/null
@@ -1,1084 +0,0 @@
-use crate::types::{ChatMessage, ChatResponse, MessageRole, Provider, ToolCall, Usage};
-use anyhow::{Context, Result};
-use serde::Deserialize;
-use serde_json::Value;
-
-// Helper macro for console logging that works in both WASM and non-WASM environments
-macro_rules! console_warn {
- ($($arg:tt)*) => {
- #[cfg(target_arch = "wasm32")]
- web_sys::console::warn_1(&format!($($arg)*).into());
- #[cfg(not(target_arch = "wasm32"))]
- eprintln!("WARN: {}", format!($($arg)*));
- };
-}
-
-macro_rules! console_error {
- ($($arg:tt)*) => {
- #[cfg(target_arch = "wasm32")]
- web_sys::console::error_1(&format!($($arg)*).into());
- #[cfg(not(target_arch = "wasm32"))]
- eprintln!("ERROR: {}", format!($($arg)*));
- };
-}
-
-#[derive(Debug, Deserialize)]
-struct CassetteFile {
- interactions: Vec,
-}
-
-#[derive(Debug, Deserialize)]
-struct Interaction {
- request: Request,
- response: Response,
-}
-
-#[derive(Debug, Deserialize)]
-struct Request {
- body: String,
- uri: String,
-}
-
-#[derive(Debug, Deserialize)]
-struct Response {
- body: ResponseBody,
-}
-
-#[derive(Debug, Deserialize)]
-struct ResponseBody {
- string: String,
-}
-
-// OpenAI response structures
-#[derive(Debug, Deserialize)]
-struct OpenAIResponse {
- id: String,
- model: String,
- choices: Vec,
- usage: Option,
- created: Option,
-}
-
-// OpenAI error response structure
-#[derive(Debug, Deserialize)]
-struct OpenAIErrorResponse {
- error: OpenAIError,
-}
-
-#[derive(Debug, Deserialize)]
-#[allow(dead_code)]
-struct OpenAIError {
- message: String,
- #[serde(rename = "type")]
- error_type: String,
- param: Option,
- code: Option,
-}
-
-// OpenAI Responses API structure (/v1/responses)
-#[derive(Debug, Deserialize)]
-struct OpenAIResponsesResponse {
- id: String,
- model: String,
- output: Vec,
- usage: Option,
- created_at: Option,
-}
-
-#[derive(Debug, Deserialize)]
-#[allow(dead_code)]
-struct OpenAIOutput {
- id: String,
- #[serde(rename = "type")]
- output_type: String,
- content: Vec,
- role: String,
-}
-
-#[derive(Debug, Deserialize)]
-#[allow(dead_code)]
-struct OpenAIOutputContent {
- #[serde(rename = "type")]
- content_type: String,
- text: Option,
- image_url: Option, // For image content
-}
-
-#[derive(Debug, Deserialize)]
-struct OpenAIResponsesUsage {
- input_tokens: Option,
- output_tokens: Option,
- total_tokens: Option,
-}
-
-#[derive(Debug, Deserialize)]
-struct OpenAIChoice {
- message: OpenAIMessage,
- finish_reason: Option,
-}
-
-#[derive(Debug, Deserialize)]
-struct OpenAIMessage {
- role: String,
- #[serde(skip_serializing_if = "Option::is_none")]
- content: Option, // Can be string or array
- tool_calls: Option>,
- refusal: Option,
-}
-
-#[derive(Debug, Deserialize)]
-struct OpenAIToolCall {
- id: String,
- #[serde(rename = "type")]
- tool_type: String,
- function: OpenAIFunction,
-}
-
-#[derive(Debug, Deserialize)]
-struct OpenAIFunction {
- name: String,
- arguments: String,
-}
-
-#[derive(Debug, Deserialize)]
-struct OpenAIUsage {
- prompt_tokens: Option,
- completion_tokens: Option,
- total_tokens: Option,
-}
-
-// Anthropic response structures
-#[derive(Debug, Deserialize)]
-struct AnthropicResponse {
- id: String,
- model: String,
- content: Vec,
- usage: Option,
- stop_reason: Option,
- stop_sequence: Option,
-}
-
-#[derive(Debug, Deserialize)]
-#[allow(dead_code)]
-struct AnthropicContent {
- #[serde(rename = "type")]
- content_type: String,
- text: Option,
- // Tool use fields
- id: Option,
- name: Option,
- input: Option,
-}
-
-#[derive(Debug, Deserialize)]
-struct AnthropicUsage {
- input_tokens: Option,
- output_tokens: Option,
-}
-
-pub fn parse_cassette(json_content: &str) -> Result {
- let cassette: CassetteFile = serde_json::from_str(json_content)
- .map_err(|e| {
- console_error!("Failed to parse cassette JSON: {}", e);
- e
- })
- .context("Failed to parse cassette JSON")?;
-
- if cassette.interactions.is_empty() {
- anyhow::bail!("No interactions found in cassette");
- }
-
- let interaction = &cassette.interactions[0];
- let provider = detect_provider(&interaction.request.uri);
-
- // Parse request to get the messages
- let request_body: Value = serde_json::from_str(&interaction.request.body)
- .context("Failed to parse request body")?;
-
- let mut messages = parse_request_messages(&request_body, &provider)?;
-
- // Parse response based on provider
- let chat_response = match &provider {
- Provider::OpenAI => {
- parse_openai_response(&interaction.response.body.string, &mut messages)
- .map_err(|e| {
- console_error!("Failed to parse OpenAI response: {}", e);
- e
- })
- }
- Provider::Anthropic => {
- parse_anthropic_response(&interaction.response.body.string, &mut messages)
- .map_err(|e| {
- console_error!("Failed to parse Anthropic response: {}", e);
- e
- })
- }
- Provider::Google => {
- parse_google_response(&interaction.response.body.string, &mut messages)
- .map_err(|e| {
- console_error!("Failed to parse Google response: {}", e);
- e
- })
- }
- Provider::Unknown(uri) => {
- console_warn!("Unknown provider for URI: {}. Attempting generic parsing.", uri);
- // Create a basic response with the raw messages
- Ok(ChatResponse {
- id: "unknown".to_string(),
- model: "unknown".to_string(),
- messages: messages.clone(),
- usage: None,
- created: None,
- provider: provider.clone(),
- })
- }
- }?;
-
- // Don't automatically mark messages as streaming - only use actual streaming data from cassettes
- // This was causing all assistant messages to appear as "streaming" and disabling the input
- // apply_smart_streaming(&mut chat_response.messages);
-
- Ok(chat_response)
-}
-
-
-fn detect_provider(uri: &str) -> Provider {
- if uri.contains("openai.com") {
- Provider::OpenAI
- } else if uri.contains("anthropic.com") {
- Provider::Anthropic
- } else if uri.contains("google") || uri.contains("generativelanguage") {
- Provider::Google
- } else {
- Provider::Unknown(uri.to_string())
- }
-}
-
-fn parse_request_messages(request_body: &Value, provider: &Provider) -> Result> {
- let mut messages = Vec::new();
-
- match provider {
- Provider::OpenAI => {
- // Handle both Chat Completions API (messages) and Responses API (input)
- if let Some(msgs) = request_body["messages"].as_array() {
- // Chat Completions API format
- for msg in msgs {
- let role = msg["role"].as_str().unwrap_or("user");
-
- // Handle different content formats
- let message = if let Some(content_str) = msg["content"].as_str() {
- // Simple string content
- ChatMessage::new(parse_role(role), content_str.to_string())
- } else if let Some(content_array) = msg["content"].as_array() {
- // Array of content parts (multimodal)
- let mut parts = Vec::new();
- for part in content_array {
- if let Some(part_type) = part["type"].as_str() {
- match part_type {
- "text" => {
- if let Some(text) = part["text"].as_str() {
- parts.push(crate::types::MessagePart::Text {
- part_type: "text".to_string(),
- text: text.to_string(),
- });
- }
- }
- "image_url" => {
- if let Some(image_obj) = part["image_url"].as_object() {
- if let Some(url) = image_obj.get("url").and_then(|v| v.as_str()) {
- parts.push(crate::types::MessagePart::Image {
- part_type: "image_url".to_string(),
- image_url: crate::types::ImageContent {
- url: url.to_string(),
- detail: image_obj.get("detail").and_then(|v| v.as_str()).map(|s| s.to_string()),
- },
- });
- }
- }
- }
- unknown_type => {
- console_warn!("Unknown OpenAI content part type in request: {}", unknown_type);
- }
- }
- }
- }
- let msg = ChatMessage {
- role: parse_role(role),
- content: Some(crate::types::MessageContent::Parts(parts)),
- name: None,
- tool_calls: None,
- tool_call_id: None,
- refusal: None,
- is_streaming: false,
- finish_reason: None,
- metadata: Default::default(),
- };
- msg
- } else {
- // Empty content
- ChatMessage::new(parse_role(role), String::new())
- };
-
- messages.push(message);
- }
- } else if let Some(input) = request_body["input"].as_str() {
- // Responses API format
- messages.push(ChatMessage::new(
- MessageRole::User,
- input.to_string(),
- ));
- }
- }
- Provider::Anthropic => {
- if let Some(msgs) = request_body["messages"].as_array() {
- for msg in msgs {
- let role = msg["role"].as_str().unwrap_or("user");
-
- // Handle different content formats for Anthropic
- let message = if let Some(content_str) = msg["content"].as_str() {
- // Simple string content
- ChatMessage::new(parse_role(role), content_str.to_string())
- } else if let Some(content_array) = msg["content"].as_array() {
- // Array of content parts (multimodal)
- let mut parts = Vec::new();
- for part in content_array {
- if let Some(part_type) = part["type"].as_str() {
- match part_type {
- "text" => {
- if let Some(text) = part["text"].as_str() {
- parts.push(crate::types::MessagePart::Text {
- part_type: "text".to_string(),
- text: text.to_string(),
- });
- }
- }
- "image" => {
- // Anthropic uses a different format for images
- if let Some(source) = part["source"].as_object() {
- if let Some(data) = source["data"].as_str() {
- let media_type = source["media_type"].as_str().unwrap_or("image/jpeg");
- let url = format!("data:{};base64,{}", media_type, data);
- parts.push(crate::types::MessagePart::Image {
- part_type: "image".to_string(),
- image_url: crate::types::ImageContent {
- url,
- detail: None,
- },
- });
- }
- }
- }
- unknown_type => {
- console_warn!("Unknown Anthropic content part type in request: {}", unknown_type);
- }
- }
- }
- }
- let msg = ChatMessage {
- role: parse_role(role),
- content: Some(crate::types::MessageContent::Parts(parts)),
- name: None,
- tool_calls: None,
- tool_call_id: None,
- refusal: None,
- is_streaming: false,
- finish_reason: None,
- metadata: Default::default(),
- };
- msg
- } else {
- // Empty content
- ChatMessage::new(parse_role(role), String::new())
- };
-
- messages.push(message);
- }
- }
- }
- Provider::Google => {
- if let Some(contents) = request_body["contents"].as_array() {
- for content in contents {
- let role = content["role"].as_str().unwrap_or("user");
- if let Some(parts) = content["parts"].as_array() {
- for part in parts {
- if let Some(text) = part["text"].as_str() {
- messages.push(ChatMessage::new(
- parse_role(role),
- text.to_string(),
- ));
- }
- }
- }
- }
- }
- }
- _ => {
- console_warn!("Unsupported provider in request parsing: {:?}", provider);
- }
- }
-
- Ok(messages)
-}
-
-fn parse_role(role: &str) -> MessageRole {
- match role.to_lowercase().as_str() {
- "system" => MessageRole::System,
- "user" => MessageRole::User,
- "assistant" | "model" => MessageRole::Assistant,
- "tool" | "function" => MessageRole::Tool,
- _ => MessageRole::User,
- }
-}
-
-fn parse_openai_response(response_str: &str, messages: &mut Vec) -> Result {
- // Handle streaming responses
- if response_str.starts_with("data:") {
- return parse_openai_streaming_response(response_str, messages);
- }
-
- // Check for error responses first
- if let Ok(error_response) = serde_json::from_str::(response_str) {
- let error_message = format!("OpenAI Error ({}): {}",
- error_response.error.error_type,
- error_response.error.message
- );
-
- // Add error as a system message
- messages.push(ChatMessage::new(
- crate::types::MessageRole::System,
- error_message.clone(),
- ));
-
- return Ok(ChatResponse {
- id: "error".to_string(),
- model: "error".to_string(),
- messages: messages.clone(),
- usage: None,
- created: None,
- provider: crate::types::Provider::OpenAI,
- });
- }
-
- // Try parsing as Responses API first (has "output" field)
- if let Ok(responses_response) = serde_json::from_str::(response_str) {
- return parse_openai_responses_api(responses_response, messages);
- }
-
- // Fall back to Chat Completions API (has "choices" field)
- let response: OpenAIResponse = serde_json::from_str(response_str)
- .context("Failed to parse OpenAI response")?;
-
- for choice in response.choices {
- // Parse content which can be either a string or array of parts
- let message_content = if let Some(content_value) = &choice.message.content {
- match content_value {
- serde_json::Value::String(s) => Some(crate::types::MessageContent::Text(s.clone())),
- serde_json::Value::Array(parts) => {
- let mut parsed_parts = Vec::new();
- for part in parts {
- if let Some(part_type) = part["type"].as_str() {
- match part_type {
- "text" => {
- if let Some(text) = part["text"].as_str() {
- parsed_parts.push(crate::types::MessagePart::Text {
- part_type: "text".to_string(),
- text: text.to_string(),
- });
- }
- }
- "image_url" => {
- if let Some(image_obj) = part["image_url"].as_object() {
- if let Some(url) = image_obj.get("url").and_then(|v| v.as_str()) {
- parsed_parts.push(crate::types::MessagePart::Image {
- part_type: "image_url".to_string(),
- image_url: crate::types::ImageContent {
- url: url.to_string(),
- detail: image_obj.get("detail").and_then(|v| v.as_str()).map(|s| s.to_string()),
- },
- });
- }
- }
- }
- unknown_type => {
- console_warn!("Unknown OpenAI content part type in response: {}", unknown_type);
- }
- }
- }
- }
- Some(crate::types::MessageContent::Parts(parsed_parts))
- }
- _ => None
- }
- } else {
- None
- };
-
- let mut message = ChatMessage {
- role: parse_role(&choice.message.role),
- content: message_content,
- name: None,
- tool_calls: None,
- tool_call_id: None,
- refusal: choice.message.refusal.clone(),
- is_streaming: false,
- finish_reason: choice.finish_reason.clone(),
- metadata: Default::default(),
- };
-
- if let Some(tool_calls) = choice.message.tool_calls {
- message.tool_calls = Some(tool_calls.into_iter().map(|tc| ToolCall {
- id: tc.id,
- tool_type: tc.tool_type,
- function: crate::types::FunctionCall {
- name: tc.function.name,
- arguments: tc.function.arguments,
- },
- }).collect());
- }
-
- message.refusal = choice.message.refusal;
- message.finish_reason = choice.finish_reason;
-
- // is_streaming is set to false by default
-
- messages.push(message);
- }
-
- Ok(ChatResponse {
- id: response.id,
- model: response.model,
- messages: messages.clone(),
- usage: response.usage.map(|u| Usage {
- prompt_tokens: u.prompt_tokens,
- completion_tokens: u.completion_tokens,
- total_tokens: u.total_tokens,
- }),
- created: response.created,
- provider: Provider::OpenAI,
- })
-}
-
-fn parse_openai_responses_api(response: OpenAIResponsesResponse, messages: &mut Vec) -> Result {
- for output in response.output {
- // Parse content parts (could include text and images)
- let mut parts = Vec::new();
-
- for content_part in &output.content {
- match content_part.content_type.as_str() {
- "text" | "input_text" | "output_text" => {
- if let Some(text) = &content_part.text {
- parts.push(crate::types::MessagePart::Text {
- part_type: "text".to_string(),
- text: text.clone(),
- });
- }
- }
- "image_url" => {
- if let Some(image_value) = &content_part.image_url {
- if let Some(image_obj) = image_value.as_object() {
- if let Some(url) = image_obj.get("url").and_then(|v| v.as_str()) {
- parts.push(crate::types::MessagePart::Image {
- part_type: "image_url".to_string(),
- image_url: crate::types::ImageContent {
- url: url.to_string(),
- detail: image_obj.get("detail").and_then(|v| v.as_str()).map(|s| s.to_string()),
- },
- });
- }
- }
- }
- }
- unknown_type => {
- console_warn!("Unknown OpenAI Responses API content type: {}", unknown_type);
- }
- }
- }
-
- let message_content = if parts.is_empty() {
- None
- } else if parts.len() == 1 && matches!(&parts[0], crate::types::MessagePart::Text { .. }) {
- // Single text part - use simple text content
- if let crate::types::MessagePart::Text { text, .. } = &parts[0] {
- Some(crate::types::MessageContent::Text(text.clone()))
- } else {
- None
- }
- } else {
- // Multiple parts or contains images
- Some(crate::types::MessageContent::Parts(parts))
- };
-
- let message = ChatMessage {
- role: parse_role(&output.role),
- content: message_content,
- name: None,
- tool_calls: None,
- tool_call_id: None,
- refusal: None,
- is_streaming: false,
- finish_reason: None,
- metadata: Default::default(),
- };
-
- messages.push(message);
- }
-
- Ok(ChatResponse {
- id: response.id,
- model: response.model,
- messages: messages.clone(),
- usage: response.usage.map(|u| Usage {
- prompt_tokens: u.input_tokens,
- completion_tokens: u.output_tokens,
- total_tokens: u.total_tokens,
- }),
- created: response.created_at,
- provider: Provider::OpenAI,
- })
-}
-
-fn parse_openai_streaming_response(response_str: &str, messages: &mut Vec) -> Result {
- let mut combined_content = String::new();
- let mut model = String::new();
- let mut id = String::new();
-
- for line in response_str.lines() {
- if line.starts_with("data: ") {
- let data_str = &line[6..];
- if data_str == "[DONE]" {
- break;
- }
-
- if let Ok(chunk) = serde_json::from_str::(data_str) {
- if id.is_empty() {
- id = chunk["id"].as_str().unwrap_or("").to_string();
- model = chunk["model"].as_str().unwrap_or("").to_string();
- }
-
- if let Some(choices) = chunk["choices"].as_array() {
- for choice in choices {
- if let Some(delta) = choice.get("delta") {
- if let Some(content) = delta["content"].as_str() {
- combined_content.push_str(content);
- }
- }
- }
- }
- }
- }
- }
-
- // Only stream if content is substantial
- let should_stream = !combined_content.trim().is_empty() && combined_content.len() > 10;
- let mut message = ChatMessage::assistant(combined_content);
- message.is_streaming = should_stream;
- messages.push(message);
-
- Ok(ChatResponse {
- id,
- model,
- messages: messages.clone(),
- usage: None,
- created: None,
- provider: Provider::OpenAI,
- })
-}
-
-fn parse_anthropic_response(response_str: &str, messages: &mut Vec) -> Result {
- // Check if this is a streaming response (SSE format)
- if response_str.starts_with("event:") {
- return parse_anthropic_streaming_response(response_str, messages);
- }
-
- let response: AnthropicResponse = serde_json::from_str(response_str)
- .with_context(|| format!("Failed to parse Anthropic response. Response preview: {}",
- &response_str[..response_str.len().min(200)]))?;
-
- // Collect text content
- let text_content = response.content
- .iter()
- .filter_map(|c| c.text.as_ref())
- .map(|s| s.as_str())
- .collect::>()
- .join("");
-
- // Collect tool calls
- let tool_calls: Vec = response.content
- .iter()
- .filter(|c| c.content_type == "tool_use")
- .filter_map(|c| {
- match (c.id.as_ref(), c.name.as_ref(), c.input.as_ref()) {
- (Some(id), Some(name), Some(input)) => {
- Some(ToolCall {
- id: id.clone(),
- tool_type: "function".to_string(),
- function: crate::types::FunctionCall {
- name: name.clone(),
- arguments: serde_json::to_string(input).unwrap_or_default(),
- },
- })
- }
- _ => None
- }
- })
- .collect();
-
- let mut message = ChatMessage::assistant(text_content);
- if !tool_calls.is_empty() {
- message.tool_calls = Some(tool_calls);
- }
-
- // Set finish reason from stop_reason
- message.finish_reason = response.stop_reason.clone();
-
- messages.push(message);
-
- Ok(ChatResponse {
- id: response.id,
- model: response.model,
- messages: messages.clone(),
- usage: response.usage.map(|u| Usage {
- prompt_tokens: u.input_tokens,
- completion_tokens: u.output_tokens,
- total_tokens: u.input_tokens.zip(u.output_tokens).map(|(i, o)| i + o),
- }),
- created: None,
- provider: Provider::Anthropic,
- })
-}
-
-fn parse_anthropic_streaming_response(response_str: &str, messages: &mut Vec) -> Result {
- let mut combined_content = String::new();
- let mut model = String::new();
- let mut id = String::new();
- let mut input_tokens = None;
- let mut output_tokens = None;
-
- // Parse SSE format
- for line in response_str.lines() {
- if line.starts_with("data: ") {
- let data_str = &line[6..];
- if let Ok(data) = serde_json::from_str::(data_str) {
- // Extract model and ID from message_start
- if data["type"] == "message_start" {
- if let Some(message) = data.get("message") {
- id = message["id"].as_str().unwrap_or("").to_string();
- model = message["model"].as_str().unwrap_or("").to_string();
- if let Some(usage) = message.get("usage") {
- input_tokens = usage["input_tokens"].as_i64().map(|x| x as i32);
- output_tokens = usage["output_tokens"].as_i64().map(|x| x as i32);
- }
- }
- }
- // Extract text from content_block_delta events
- else if data["type"] == "content_block_delta" {
- if let Some(delta) = data.get("delta") {
- if let Some(text) = delta["text"].as_str() {
- combined_content.push_str(text);
- }
- }
- }
- // Extract final usage from message_delta
- else if data["type"] == "message_delta" {
- if let Some(usage) = data.get("usage") {
- if let Some(output) = usage["output_tokens"].as_i64() {
- output_tokens = Some(output as i32);
- }
- }
- }
- }
- }
- }
-
- // Only stream if content is substantial
- let should_stream = !combined_content.trim().is_empty() && combined_content.len() > 10;
- let mut message = ChatMessage::assistant(combined_content);
- message.is_streaming = should_stream;
- messages.push(message);
-
- Ok(ChatResponse {
- id,
- model,
- messages: messages.clone(),
- usage: if input_tokens.is_some() || output_tokens.is_some() {
- Some(Usage {
- prompt_tokens: input_tokens,
- completion_tokens: output_tokens,
- total_tokens: input_tokens.zip(output_tokens).map(|(i, o)| i + o),
- })
- } else {
- None
- },
- created: None,
- provider: Provider::Anthropic,
- })
-}
-
-fn parse_google_response(response_str: &str, messages: &mut Vec) -> Result {
- let response: Value = serde_json::from_str(response_str)
- .context("Failed to parse Google response")?;
-
- if let Some(candidates) = response["candidates"].as_array() {
- for candidate in candidates {
- if let Some(content) = candidate.get("content") {
- if let Some(parts) = content["parts"].as_array() {
- for part in parts {
- if let Some(text) = part["text"].as_str() {
- let message = ChatMessage::assistant(text.to_string());
- // is_streaming is set to false by default
- messages.push(message);
- }
- }
- }
- }
- }
- }
-
- Ok(ChatResponse {
- id: response["id"].as_str().unwrap_or("").to_string(),
- model: response["model"].as_str().unwrap_or("").to_string(),
- messages: messages.clone(),
- usage: None,
- created: None,
- provider: Provider::Google,
- })
-}
-
-#[cfg(test)]
-mod tests {
- use super::*;
-
- #[test]
- fn test_multi_turn_cassette_parsing() {
- let cassette_content = r#"interactions:
-- request:
- body: '{"messages":[{"role":"user","content":"What is machine learning?"},{"role":"assistant","content":"Machine learning is a subset of artificial intelligence..."},{"role":"user","content":"Can you give me an example?"}],"model":"gpt-4o","max_completion_tokens":200}'
- uri: https://api.openai.com/v1/chat/completions
- response:
- body:
- string: '{"id": "chatcmpl-test", "object": "chat.completion", "created": 1750105908, "model": "gpt-4o-2024-08-06", "choices": [{"index": 0, "message": {"role": "assistant", "content": "Certainly! One common example...", "refusal": null}, "finish_reason": "length"}], "usage": {"prompt_tokens": 36, "completion_tokens": 200, "total_tokens": 236}}'
-"#;
-
- let result = parse_cassette(cassette_content).unwrap();
-
- println!("Parsed {} messages", result.messages.len());
- for (i, msg) in result.messages.iter().enumerate() {
- println!("Message {}: {:?} - {:?}", i, msg.role, msg.get_text_content());
- }
-
- // Check we have all messages: 2 from request + 1 from response
- assert_eq!(result.messages.len(), 4, "Should have 4 messages total: 3 from request + 1 from response");
-
- assert_eq!(result.messages[0].role, crate::types::MessageRole::User);
- assert_eq!(result.messages[1].role, crate::types::MessageRole::Assistant);
- assert_eq!(result.messages[2].role, crate::types::MessageRole::User);
- assert_eq!(result.messages[3].role, crate::types::MessageRole::Assistant);
- }
-
- #[test]
- fn test_openai_responses_api_parsing() {
- // Test parsing an OpenAI Responses API cassette (uses /v1/responses endpoint)
- let responses_cassette = r#"interactions:
-- request:
- body: '{"input":"Hello, how are you?","model":"gpt-4o"}'
- uri: https://api.openai.com/v1/responses
- response:
- body:
- string: '{"id": "resp_123", "model": "gpt-4o-2024-08-06", "output": [{"id": "msg_456", "type": "message", "content": [{"type": "output_text", "text": "Hello! I am just a program, so I do not have feelings, but I am here and ready to help."}], "role": "assistant"}], "usage": {"input_tokens": 13, "output_tokens": 29, "total_tokens": 42}}'
-"#;
-
- let result = parse_cassette(responses_cassette).unwrap();
-
- println!("OpenAI Responses API parsed {} messages", result.messages.len());
- for (i, msg) in result.messages.iter().enumerate() {
- println!("Message {}: {:?} - {:?}", i, msg.role, msg.get_text_content());
- }
-
- // Should have 1 message from request input + 1 from response output
- assert_eq!(result.messages.len(), 2, "Should have 2 messages total");
-
- assert_eq!(result.messages[0].role, crate::types::MessageRole::User);
- assert_eq!(result.messages[1].role, crate::types::MessageRole::Assistant);
-
- // Verify content is parsed correctly
- assert_eq!(result.messages[0].get_text_content().unwrap(), "Hello, how are you?");
- assert!(result.messages[1].get_text_content().unwrap().contains("Hello! I am just a program"));
-
- // Verify provider detection
- assert_eq!(result.provider, crate::types::Provider::OpenAI);
-
- // Verify usage parsing
- assert!(result.usage.is_some());
- let usage = result.usage.unwrap();
- assert_eq!(usage.prompt_tokens, Some(13));
- assert_eq!(usage.completion_tokens, Some(29));
- assert_eq!(usage.total_tokens, Some(42));
- }
-
- #[test]
- fn test_real_multi_turn_cassette_file() {
- let cassette_content = include_str!("../../samples/cassettes/openai_chat_completions/test_multi_turn_conversation.yaml");
-
- let result = parse_cassette(cassette_content).unwrap();
-
- println!("Real cassette parsed {} messages", result.messages.len());
- for (i, msg) in result.messages.iter().enumerate() {
- println!("Message {}: {:?} - {:?}", i, msg.role, msg.get_text_content().map(|s| s.chars().take(100).collect::()));
- }
-
- // Check we have all messages: 3 from request + 1 from response
- assert_eq!(result.messages.len(), 4, "Should have 4 messages total: 3 from request + 1 from response");
-
- assert_eq!(result.messages[0].role, crate::types::MessageRole::User);
- assert_eq!(result.messages[1].role, crate::types::MessageRole::Assistant);
- assert_eq!(result.messages[2].role, crate::types::MessageRole::User);
- assert_eq!(result.messages[3].role, crate::types::MessageRole::Assistant);
-
- // Verify content is parsed correctly
- assert!(result.messages[0].get_text_content().unwrap().contains("What is machine learning?"));
- assert!(result.messages[2].get_text_content().unwrap().contains("Can you give me an example?"));
- }
-
- #[test]
- fn test_unknown_provider_handling() {
- let cassette_content = r#"interactions:
-- request:
- body: '{"messages":[{"role":"user","content":"Hello"}]}'
- uri: https://unknown-llm-provider.com/v1/chat
- response:
- body:
- string: '{"id": "test", "message": "Response from unknown provider"}'
-"#;
-
- let result = parse_cassette(cassette_content).unwrap();
-
- // Should handle unknown provider gracefully
- assert!(matches!(result.provider, crate::types::Provider::Unknown(_)));
- // Unknown providers don't parse messages from the request body by default
- assert_eq!(result.messages.len(), 0);
- }
-
- #[test]
- fn test_unknown_content_types() {
- // Test OpenAI with unknown content type
- let cassette_content = r#"interactions:
-- request:
- body: '{"messages":[{"role":"user","content":[{"type":"text","text":"Hello"},{"type":"audio","audio_url":"http://example.com/audio.mp3"}]}]}'
- uri: https://api.openai.com/v1/chat/completions
- response:
- body:
- string: '{"id": "test", "model": "gpt-4", "choices": [{"message": {"role": "assistant", "content": "Hi there!"}}]}'
-"#;
-
- let result = parse_cassette(cassette_content).unwrap();
-
- // Should parse successfully, ignoring unknown content type
- assert_eq!(result.provider, crate::types::Provider::OpenAI);
- assert_eq!(result.messages.len(), 2);
-
- // Check that the text part was parsed correctly
- if let Some(crate::types::MessageContent::Parts(parts)) = &result.messages[0].content {
- assert_eq!(parts.len(), 1); // Only text part should be parsed
- assert!(matches!(&parts[0], crate::types::MessagePart::Text { text, .. } if text == "Hello"));
- } else {
- panic!("Expected Parts content");
- }
- }
-
- #[test]
- fn test_malformed_multimodal_content() {
- // Test with malformed image content
- let cassette_content = r#"interactions:
-- request:
- body: '{"messages":[{"role":"user","content":[{"type":"text","text":"Look at this"},{"type":"image_url","image_url":{"bad_field":"no_url"}}]}]}'
- uri: https://api.openai.com/v1/chat/completions
- response:
- body:
- string: '{"id": "test", "model": "gpt-4", "choices": [{"message": {"role": "assistant", "content": "I cannot see the image"}}]}'
-"#;
-
- let result = parse_cassette(cassette_content).unwrap();
-
- // Should handle malformed image gracefully
- assert_eq!(result.messages.len(), 2);
-
- // Only text should be parsed from the malformed multimodal content
- if let Some(crate::types::MessageContent::Parts(parts)) = &result.messages[0].content {
- assert_eq!(parts.len(), 1); // Only text part
- assert!(matches!(&parts[0], crate::types::MessagePart::Text { text, .. } if text == "Look at this"));
- } else {
- panic!("Expected Parts content");
- }
- }
-
- #[test]
- fn test_empty_content_array() {
- let cassette_content = r#"interactions:
-- request:
- body: '{"messages":[{"role":"user","content":[]}]}'
- uri: https://api.openai.com/v1/chat/completions
- response:
- body:
- string: '{"id": "test", "model": "gpt-4", "choices": [{"message": {"role": "assistant", "content": "Empty content?"}}]}'
-"#;
-
- let result = parse_cassette(cassette_content).unwrap();
-
- // Should handle empty content array
- assert_eq!(result.messages.len(), 2);
-
- // First message should have empty Parts
- if let Some(crate::types::MessageContent::Parts(parts)) = &result.messages[0].content {
- assert_eq!(parts.len(), 0);
- } else {
- panic!("Expected Parts content");
- }
- }
-
- #[test]
- fn test_openai_error_response() {
- let cassette_content = r#"interactions:
-- request:
- body: '{"messages":[{"role":"user","content":"Hello"}]}'
- uri: https://api.openai.com/v1/chat/completions
- response:
- body:
- string: '{"error": {"message": "Invalid API key", "type": "invalid_request_error", "param": null, "code": "invalid_api_key"}}'
-"#;
-
- let result = parse_cassette(cassette_content).unwrap();
-
- // Should handle error response
- assert_eq!(result.messages.len(), 2); // Request + error message
- assert_eq!(result.messages[1].role, crate::types::MessageRole::System);
- assert!(result.messages[1].get_text_content().unwrap().contains("Invalid API key"));
- }
-
- #[test]
- fn test_anthropic_tool_use_parsing() {
- let cassette_content = r#"interactions:
-- request:
- body: '{"messages":[{"role":"user","content":"What is the weather in Tokyo?"}],"tools":[{"name":"get_weather","input_schema":{"type":"object"}}]}'
- uri: https://api.anthropic.com/v1/messages
- response:
- body:
- string: '{"id":"msg_123","type":"message","role":"assistant","model":"claude-3-sonnet-20240229","content":[{"type":"text","text":"I will check the weather for you."},{"type":"tool_use","id":"tool_123","name":"get_weather","input":{"location":"Tokyo"}}],"usage":{"input_tokens":100,"output_tokens":50}}'
-"#;
-
- let result = parse_cassette(cassette_content).unwrap();
-
- // Should parse tool use correctly
- assert_eq!(result.messages.len(), 2);
- let assistant_msg = &result.messages[1];
- assert_eq!(assistant_msg.role, crate::types::MessageRole::Assistant);
- assert_eq!(assistant_msg.get_text_content().unwrap(), "I will check the weather for you.");
-
- // Check tool calls
- assert!(assistant_msg.tool_calls.is_some());
- let tool_calls = assistant_msg.tool_calls.as_ref().unwrap();
- assert_eq!(tool_calls.len(), 1);
- assert_eq!(tool_calls[0].id, "tool_123");
- assert_eq!(tool_calls[0].function.name, "get_weather");
- assert!(tool_calls[0].function.arguments.contains("Tokyo"));
- }
-}
\ No newline at end of file
diff --git a/crates/chat-ui/src/utils/flexible_parser.rs b/crates/chat-ui/src/utils/flexible_parser.rs
deleted file mode 100644
index 071e9cfe..00000000
--- a/crates/chat-ui/src/utils/flexible_parser.rs
+++ /dev/null
@@ -1,13 +0,0 @@
-use crate::parsers;
-use crate::types::ChatResponse;
-use crate::utils::cassette_loader;
-use anyhow::Result;
-
-/// Parse a cassette file using the new parsing architecture
-pub fn parse_cassette(json_content: &str) -> Result {
- // Load the cassette as raw HTTP data
- let interaction = cassette_loader::load_cassette(json_content)?;
-
- // Parse the interaction into a chat response
- parsers::parse_interaction(&interaction)
-}
diff --git a/crates/chat-ui/src/utils/markdown.rs b/crates/chat-ui/src/utils/markdown.rs
deleted file mode 100644
index 2652733a..00000000
--- a/crates/chat-ui/src/utils/markdown.rs
+++ /dev/null
@@ -1,136 +0,0 @@
-use yew::prelude::*;
-
-pub fn render_markdown(content: &str) -> Html {
- // For now, let's do basic markdown rendering without the pulldown-cmark dependency
- // to avoid version conflicts. We can enhance this later.
- let mut html_output = String::new();
- let mut in_code_block = false;
- let mut code_content = String::new();
-
- for line in content.lines() {
- if line.starts_with("```") {
- if in_code_block {
- // End code block
- html_output.push_str("");
- html_output.push_str(&html_escape(&code_content));
- html_output.push_str(" ");
- code_content.clear();
- in_code_block = false;
- } else {
- // Start code block
- in_code_block = true;
- }
- } else if in_code_block {
- if !code_content.is_empty() {
- code_content.push('\n');
- }
- code_content.push_str(line);
- } else {
- // Simple replacements for basic markdown
- let mut processed_line = line.to_string();
-
- // Headers
- if let Some(rest) = processed_line.strip_prefix("### ") {
- html_output.push_str(&format!("{} ", html_escape(rest)));
- } else if let Some(rest) = processed_line.strip_prefix("## ") {
- html_output.push_str(&format!("{} ", html_escape(rest)));
- } else if let Some(rest) = processed_line.strip_prefix("# ") {
- html_output.push_str(&format!("{} ", html_escape(rest)));
- } else if processed_line.trim().is_empty() {
- // Empty line
- if !html_output.ends_with(" ") && !html_output.ends_with("") {
- html_output.push_str(" ");
- }
- } else {
- // Regular paragraph
- html_output.push_str("");
-
- // Bold text
- processed_line = replace_pattern(&processed_line, "**", "", " ");
-
- // Italic text
- processed_line = replace_pattern(&processed_line, "*", "", " ");
-
- // Inline code
- processed_line = replace_inline_code(&processed_line);
-
- html_output.push_str(&processed_line);
- html_output.push_str("
");
- }
- }
- }
-
- // Handle unclosed code block
- if in_code_block {
- html_output.push_str("");
- html_output.push_str(&html_escape(&code_content));
- html_output.push_str(" ");
- }
-
- Html::from_html_unchecked(AttrValue::from(html_output))
-}
-
-fn replace_pattern(text: &str, delimiter: &str, open_tag: &str, close_tag: &str) -> String {
- let parts: Vec<&str> = text.split(delimiter).collect();
- if parts.len() < 3 {
- return text.to_string();
- }
-
- let mut result = String::new();
- let mut in_delimiter = false;
-
- for (i, part) in parts.iter().enumerate() {
- if i == 0 {
- result.push_str(part);
- } else if in_delimiter {
- result.push_str(close_tag);
- result.push_str(part);
- in_delimiter = false;
- } else {
- result.push_str(open_tag);
- result.push_str(part);
- in_delimiter = true;
- }
- }
-
- result
-}
-
-fn replace_inline_code(text: &str) -> String {
- let parts: Vec<&str> = text.split('`').collect();
- if parts.len() < 3 {
- return text.to_string();
- }
-
- let mut result = String::new();
- let mut in_code = false;
-
- for (i, part) in parts.iter().enumerate() {
- if i == 0 {
- result.push_str(part);
- } else if in_code {
- result.push_str("");
- result.push_str(part);
- in_code = false;
- } else {
- result.push_str("");
- result.push_str(&html_escape(part));
- in_code = true;
- }
- }
-
- result
-}
-
-fn html_escape(s: &str) -> String {
- s.chars()
- .map(|c| match c {
- '&' => "&".to_string(),
- '<' => "<".to_string(),
- '>' => ">".to_string(),
- '"' => """.to_string(),
- '\'' => "'".to_string(),
- _ => c.to_string(),
- })
- .collect()
-}
diff --git a/crates/chat-ui/src/utils/mod.rs b/crates/chat-ui/src/utils/mod.rs
deleted file mode 100644
index c1ef0aac..00000000
--- a/crates/chat-ui/src/utils/mod.rs
+++ /dev/null
@@ -1,4 +0,0 @@
-pub mod cassette_loader;
-pub mod flexible_parser;
-pub mod markdown;
-pub mod simple_cassette_parser;
diff --git a/crates/chat-ui/src/utils/simple_cassette_parser.rs b/crates/chat-ui/src/utils/simple_cassette_parser.rs
deleted file mode 100644
index fee1bb1e..00000000
--- a/crates/chat-ui/src/utils/simple_cassette_parser.rs
+++ /dev/null
@@ -1,371 +0,0 @@
-use crate::types::{ChatMessage, ChatResponse, Provider};
-use anyhow::{Context, Result};
-use serde::Deserialize;
-use serde_json::{Value, json};
-use std::collections::HashMap;
-
-#[derive(Debug, Deserialize)]
-struct CassetteFile {
- interactions: Vec,
-}
-
-#[derive(Debug, Deserialize)]
-struct Interaction {
- request: Request,
- response: Response,
-}
-
-#[derive(Debug, Deserialize)]
-struct Request {
- body: String,
- uri: String,
-}
-
-#[derive(Debug, Deserialize)]
-struct Response {
- body: ResponseBody,
-}
-
-#[derive(Debug, Deserialize)]
-struct ResponseBody {
- string: String,
-}
-
-/// Parse a cassette file into a ChatResponse
-pub fn parse_cassette(json_content: &str) -> Result {
- let cassette: CassetteFile =
- serde_json::from_str(json_content).context("Failed to parse cassette JSON")?;
-
- if cassette.interactions.is_empty() {
- anyhow::bail!("No interactions found in cassette");
- }
-
- let interaction = &cassette.interactions[0];
- let provider = Provider::from_uri(&interaction.request.uri);
-
- // Parse request to get the messages
- let request_body: Value =
- serde_json::from_str(&interaction.request.body).context("Failed to parse request body")?;
-
- let mut messages = extract_request_messages(&request_body, &provider)?;
-
- // Parse response and determine if it's streaming
- let is_streaming = interaction.response.body.string.starts_with("data:")
- || interaction.response.body.string.starts_with("event:");
-
- // Parse response and add assistant message
- if is_streaming {
- parse_streaming_response(&interaction.response.body.string, &mut messages)?;
- } else {
- parse_json_response(&interaction.response.body.string, &mut messages, &provider)?;
- }
-
- // Extract model and id from response if available
- let (id, model) = if !is_streaming {
- if let Ok(resp) = serde_json::from_str::(&interaction.response.body.string) {
- (
- resp.get("id")
- .and_then(|v| v.as_str())
- .unwrap_or("unknown")
- .to_string(),
- resp.get("model")
- .and_then(|v| v.as_str())
- .unwrap_or("unknown")
- .to_string(),
- )
- } else {
- ("unknown".to_string(), "unknown".to_string())
- }
- } else {
- // For streaming, extract from first data chunk
- extract_streaming_metadata(&interaction.response.body.string)
- .unwrap_or(("unknown".to_string(), "unknown".to_string()))
- };
-
- Ok(ChatResponse {
- id,
- model,
- messages,
- provider,
- usage: None,
- metadata: Default::default(),
- })
-}
-
-/// Extract messages from request body
-fn extract_request_messages(
- request_body: &Value,
- _provider: &Provider,
-) -> Result> {
- let mut messages = Vec::new();
-
- // Handle different request formats
- if let Some(msgs_array) = request_body.get("messages").and_then(|v| v.as_array()) {
- // Standard messages array format (OpenAI, Anthropic)
- for msg in msgs_array {
- let role = msg
- .get("role")
- .and_then(|v| v.as_str())
- .unwrap_or("user")
- .to_string();
-
- let content = msg.get("content").cloned();
-
- let mut metadata = HashMap::new();
-
- // Store other fields in metadata
- if let Some(name) = msg.get("name") {
- metadata.insert("name".to_string(), name.clone());
- }
- if let Some(tool_calls) = msg.get("tool_calls") {
- metadata.insert("tool_calls".to_string(), tool_calls.clone());
- }
-
- messages.push(ChatMessage {
- role,
- content,
- tool_calls: None,
- name: None,
- metadata,
- });
- }
- } else if let Some(input) = request_body.get("input").and_then(|v| v.as_str()) {
- // OpenAI Responses API format
- messages.push(ChatMessage {
- role: "user".to_string(),
- content: Some(Value::String(input.to_string())),
- tool_calls: None,
- name: None,
- metadata: Default::default(),
- });
- } else if let Some(contents) = request_body.get("contents").and_then(|v| v.as_array()) {
- // Google format
- for content in contents {
- let role = content
- .get("role")
- .and_then(|v| v.as_str())
- .unwrap_or("user")
- .to_string();
-
- if let Some(parts) = content.get("parts").and_then(|v| v.as_array()) {
- for part in parts {
- if let Some(text) = part.get("text").and_then(|v| v.as_str()) {
- messages.push(ChatMessage {
- role: role.clone(),
- content: Some(Value::String(text.to_string())),
- tool_calls: None,
- name: None,
- metadata: Default::default(),
- });
- }
- }
- }
- }
- }
-
- Ok(messages)
-}
-
-/// Parse streaming response (SSE format)
-fn parse_streaming_response(response_str: &str, messages: &mut Vec) -> Result<()> {
- let mut combined_content = String::new();
- let mut role = "assistant".to_string();
-
- for line in response_str.lines() {
- if let Some(data_str) = line.strip_prefix("data: ") {
- if data_str == "[DONE]" {
- break;
- }
-
- if let Ok(chunk) = serde_json::from_str::(data_str) {
- // Extract role if present
- if let Some(choices) = chunk.get("choices").and_then(|v| v.as_array())
- && let Some(choice) = choices.first()
- && let Some(delta) = choice.get("delta")
- {
- if let Some(r) = delta.get("role").and_then(|v| v.as_str()) {
- role = r.to_string();
- }
- if let Some(content) = delta.get("content").and_then(|v| v.as_str()) {
- combined_content.push_str(content);
- }
- }
-
- // Handle Anthropic streaming format
- if chunk.get("type").and_then(|v| v.as_str()) == Some("content_block_delta")
- && let Some(text) = chunk
- .get("delta")
- .and_then(|d| d.get("text"))
- .and_then(|t| t.as_str())
- {
- combined_content.push_str(text);
- }
- }
- }
- }
-
- if !combined_content.is_empty() {
- let mut metadata = HashMap::new();
- metadata.insert("is_streaming".to_string(), json!(true));
-
- messages.push(ChatMessage {
- role,
- content: Some(Value::String(combined_content)),
- tool_calls: None,
- name: None,
- metadata,
- });
- }
-
- Ok(())
-}
-
-/// Parse JSON response
-fn parse_json_response(
- response_str: &str,
- messages: &mut Vec,
- provider: &Provider,
-) -> Result<()> {
- let response: Value =
- serde_json::from_str(response_str).context("Failed to parse response JSON")?;
-
- match provider {
- Provider::OpenAI => {
- // Handle both Chat Completions and Responses API
- if let Some(choices) = response.get("choices").and_then(|v| v.as_array()) {
- // Chat Completions API
- for choice in choices {
- if let Some(message) = choice.get("message") {
- parse_message_object(message, messages)?;
- }
- }
- } else if let Some(outputs) = response.get("output").and_then(|v| v.as_array()) {
- // Responses API
- for output in outputs {
- parse_message_object(output, messages)?;
- }
- }
- }
- Provider::Anthropic => {
- // Anthropic messages API
- if let Some(content_array) = response.get("content").and_then(|v| v.as_array()) {
- let mut text_parts = Vec::new();
- let mut metadata = HashMap::new();
-
- for content in content_array {
- if let Some(content_type) = content.get("type").and_then(|v| v.as_str()) {
- match content_type {
- "text" => {
- if let Some(text) = content.get("text").and_then(|v| v.as_str()) {
- text_parts.push(text);
- }
- }
- "tool_use" => {
- // Store tool use in metadata
- metadata.insert("tool_use".to_string(), content.clone());
- }
- _ => {}
- }
- }
- }
-
- if !text_parts.is_empty() || !metadata.is_empty() {
- messages.push(ChatMessage {
- role: "assistant".to_string(),
- content: Some(Value::String(text_parts.join(""))),
- tool_calls: None,
- name: None,
- metadata,
- });
- }
- }
- }
- Provider::Google => {
- // Google Gemini API
- if let Some(candidates) = response.get("candidates").and_then(|v| v.as_array()) {
- for candidate in candidates {
- if let Some(content) = candidate.get("content")
- && let Some(parts) = content.get("parts").and_then(|v| v.as_array())
- {
- for part in parts {
- if let Some(text) = part.get("text").and_then(|v| v.as_str()) {
- messages.push(ChatMessage {
- role: "assistant".to_string(),
- content: Some(Value::String(text.to_string())),
- tool_calls: None,
- name: None,
- metadata: Default::default(),
- });
- }
- }
- }
- }
- }
- }
- _ => {
- // Unknown provider - try to extract a reasonable response
- if let Some(text) = response.get("text").and_then(|v| v.as_str()) {
- messages.push(ChatMessage::assistant(text));
- }
- }
- }
-
- Ok(())
-}
-
-/// Parse a message object into a ChatMessage
-fn parse_message_object(message: &Value, messages: &mut Vec) -> Result<()> {
- let role = message
- .get("role")
- .and_then(|v| v.as_str())
- .unwrap_or("assistant")
- .to_string();
-
- let content = message.get("content").cloned();
-
- let mut metadata = HashMap::new();
-
- // Store additional fields in metadata
- if let Some(refusal) = message.get("refusal") {
- metadata.insert("refusal".to_string(), refusal.clone());
- }
- if let Some(finish_reason) = message.get("finish_reason") {
- metadata.insert("finish_reason".to_string(), finish_reason.clone());
- }
- if let Some(tool_calls) = message.get("tool_calls") {
- metadata.insert("tool_calls".to_string(), tool_calls.clone());
- }
-
- messages.push(ChatMessage {
- role,
- content,
- tool_calls: None,
- name: None,
- metadata,
- });
-
- Ok(())
-}
-
-/// Extract metadata from streaming response
-fn extract_streaming_metadata(response_str: &str) -> Option<(String, String)> {
- for line in response_str.lines() {
- if let Some(data_str) = line.strip_prefix("data: ")
- && data_str != "[DONE]"
- && let Ok(chunk) = serde_json::from_str::(data_str)
- {
- let id = chunk
- .get("id")
- .and_then(|v| v.as_str())
- .unwrap_or("unknown")
- .to_string();
- let model = chunk
- .get("model")
- .and_then(|v| v.as_str())
- .unwrap_or("unknown")
- .to_string();
- return Some((id, model));
- }
- }
- None
-}
diff --git a/crates/core/Cargo.toml b/crates/core/Cargo.toml
deleted file mode 100644
index 8d464f23..00000000
--- a/crates/core/Cargo.toml
+++ /dev/null
@@ -1,60 +0,0 @@
-[package]
-name = "gate-core"
-version.workspace = true
-edition.workspace = true
-authors.workspace = true
-license.workspace = true
-repository.workspace = true
-keywords.workspace = true
-categories.workspace = true
-
-[features]
-default = ["router"]
-cloudflare = ["dep:worker", "dep:sqlx-d1"]
-tests = ["dep:uuid"]
-router = ["dep:uuid", "dep:async-stream", "dep:rand", "dep:js-sys", "tracing"]
-tracing = ["dep:tracing", "dep:hex", "dep:getrandom", "dep:rand"]
-tracing-otlp = ["tracing", "dep:opentelemetry", "dep:opentelemetry-otlp", "dep:opentelemetry_sdk", "dep:tracing-opentelemetry", "dep:tracing-subscriber"]
-tracing-prometheus = ["tracing"]
-
-[dependencies]
-anyhow.workspace = true
-async-stream = { version = "0.3", optional = true }
-async-trait.workspace = true
-chrono.workspace = true
-config.workspace = true
-futures.workspace = true
-http.workspace = true
-rand = { version = "0.9", optional = true }
-rust_decimal = { version = "1.42", features = ["serde"] }
-serde.workspace = true
-serde_json.workspace = true
-sqlx-d1 = { version = "0.2.1", optional = true }
-thiserror.workspace = true
-tokio = { workspace = true, features = ["sync", "time"] }
-url.workspace = true
-uuid = { workspace = true, features = ["v4", "serde"], optional = true }
-
-# Optional dependencies for cloudflare feature
-worker = { version = "0.6", optional = true }
-
-# Optional dependencies for tracing feature
-tracing = { workspace = true, optional = true }
-hex = { workspace = true, optional = true }
-
-[target.'cfg(target_arch = "wasm32")'.dependencies]
-getrandom = { workspace = true, features = ["wasm_js"], optional = true }
-js-sys = { version = "0.3", optional = true }
-
-# Optional dependencies for tracing-otlp feature (native only)
-[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
-opentelemetry = { version = "0.32", default-features = false, features = ["trace"], optional = true }
-opentelemetry-otlp = { version = "0.32", default-features = false, features = ["trace", "http-proto", "reqwest-blocking-client"], optional = true }
-opentelemetry_sdk = { version = "0.32", default-features = false, features = ["trace", "rt-tokio"], optional = true }
-tracing-opentelemetry = { version = "0.33", default-features = false, optional = true }
-tracing-subscriber = { workspace = true, optional = true }
-
-[dev-dependencies]
-mockall.workspace = true
-tokio = { workspace = true, features = ["test-util", "macros", "rt-multi-thread"] }
-uuid = { workspace = true, features = ["v4"] }
diff --git a/crates/core/README.md b/crates/core/README.md
deleted file mode 100644
index 21afa66f..00000000
--- a/crates/core/README.md
+++ /dev/null
@@ -1,63 +0,0 @@
-# gate-core
-
-Core abstractions and types for Gate. Defines the trait-based architecture that enables Gate's extensibility across native and WASM environments.
-
-## Responsibilities
-
-- **StateBackend trait**: Abstraction for persistent storage (users, API keys, usage tracking)
-- **Plugin system**: `GatePlugin` trait and hook registry for extending functionality
-- **Common types**: Shared data structures (User, ApiKey, Provider, Model, etc.)
-- **Error handling**: Unified error type with proper `#[from]` conversions
-- **WebAuthn**: Hardware authentication support
-
-## Key Traits
-
-### StateBackend
-```rust
-#[async_trait]
-pub trait StateBackend: Send + Sync {
- async fn get_api_key(&self, key_hash: &str) -> Result>;
- async fn record_usage(&self, usage: &UsageRecord) -> Result<()>;
- // User, organization, provider, model management
-}
-```
-
-### GatePlugin
-```rust
-#[async_trait]
-pub trait GatePlugin: Send + Sync {
- fn name(&self) -> &str;
- async fn init(&mut self, context: PluginContext) -> Result<()>;
-}
-```
-
-## Features
-
-- `default`: Core functionality only
-- `cloudflare`: Adds `worker` and `sqlx-d1` for Cloudflare Workers
-- `tests`: Exposes test utilities and mocks
-
-## Usage
-
-Implement `StateBackend` for custom storage:
-```rust
-#[async_trait]
-impl StateBackend for MyStorage {
- // Required method implementations
-}
-```
-
-Create plugins by implementing `GatePlugin` and registering hooks during `init()`.
-
-## Dependencies
-
-Minimal set:
-- `async-trait`, `thiserror` (required for trait system)
-- `serde`, `chrono`, `http` (data types)
-- `tokio` (sync primitives only, no runtime)
-
-## Risks
-
-- **WASM compatibility**: All code must work in both native and WASM targets
-- **No panics**: Never use `unwrap()` or `expect()` - this is library code
-- **Trait changes**: Breaking changes here affect entire ecosystem
\ No newline at end of file
diff --git a/crates/core/src/access/identity.rs b/crates/core/src/access/identity.rs
deleted file mode 100644
index 94371d0a..00000000
--- a/crates/core/src/access/identity.rs
+++ /dev/null
@@ -1,230 +0,0 @@
-use async_trait::async_trait;
-use serde::{Deserialize, Serialize};
-use std::collections::HashMap;
-use std::fmt::{self, Display};
-use std::ops::Deref;
-use thiserror::Error;
-
-/// Identity of the subject performing an action
-#[derive(Debug, Clone)]
-pub struct SubjectIdentity {
- pub id: String,
- pub source: String,
- pub context: C,
-}
-
-impl SubjectIdentity {
- pub fn new(id: impl Into, source: impl Into, context: C) -> Self {
- Self {
- id: id.into(),
- source: source.into(),
- context,
- }
- }
-}
-
-/// Context information for an identity
-pub trait IdentityContext: Send + Sync + Clone + std::fmt::Debug {
- /// Serialize context to key-value pairs
- fn to_attributes(&self) -> HashMap;
-
- /// Get a specific attribute value
- fn get(&self, key: &str) -> Option<&str>;
-}
-
-/// Namespace for target objects
-#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
-pub enum TargetNamespace {
- System,
- Local,
- Organization(String),
- Node(String),
-}
-
-impl Display for TargetNamespace {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- match self {
- Self::System => write!(f, "system"),
- Self::Local => write!(f, "local"),
- Self::Organization(org) => write!(f, "org:{org}"),
- Self::Node(node) => write!(f, "node:{node}"),
- }
- }
-}
-
-/// Type of object being accessed
-#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
-pub enum ObjectKind {
- Model,
- Provider,
- User,
- Users,
- Config,
- Billing,
- System,
- Quota,
-}
-
-impl Display for ObjectKind {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- write!(f, "{self:?}")
- }
-}
-
-/// Unique identifier for an object
-#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
-pub struct ObjectId(String);
-
-impl ObjectId {
- pub fn new(id: impl Into) -> Self {
- Self(id.into())
- }
-}
-
-impl Deref for ObjectId {
- type Target = str;
-
- fn deref(&self) -> &Self::Target {
- &self.0
- }
-}
-
-impl From<&str> for ObjectId {
- fn from(s: &str) -> Self {
- Self(s.to_string())
- }
-}
-
-impl From for ObjectId {
- fn from(s: String) -> Self {
- Self(s)
- }
-}
-
-impl Display for ObjectId {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- write!(f, "{}", self.0)
- }
-}
-
-/// Identity of the object being accessed
-#[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct ObjectIdentity {
- pub namespace: TargetNamespace,
- pub kind: ObjectKind,
- pub id: ObjectId,
-}
-
-impl ObjectIdentity {
- pub fn local_model(model_id: impl Into) -> Self {
- Self {
- namespace: TargetNamespace::Local,
- kind: ObjectKind::Model,
- id: ObjectId::new(model_id),
- }
- }
-
- pub fn org_model(org: impl Into, model_id: impl Into) -> Self {
- Self {
- namespace: TargetNamespace::Organization(org.into()),
- kind: ObjectKind::Model,
- id: ObjectId::new(model_id),
- }
- }
-
- pub fn local_provider(provider_id: impl Into) -> Self {
- Self {
- namespace: TargetNamespace::Local,
- kind: ObjectKind::Provider,
- id: ObjectId::new(provider_id),
- }
- }
-
- pub fn quota(user_id: impl Into) -> Self {
- Self {
- namespace: TargetNamespace::Local,
- kind: ObjectKind::Quota,
- id: ObjectId::new(user_id),
- }
- }
-
- pub fn wildcard() -> Self {
- Self {
- namespace: TargetNamespace::Local,
- kind: ObjectKind::System,
- id: ObjectId::new("*"),
- }
- }
-
- /// Parse an object identity from a string format "namespace/kind/id"
- pub fn from_string(s: &str) -> Result {
- let parts: Vec<&str> = s.split('/').collect();
- if parts.len() != 3 {
- return Err(format!(
- "Invalid object format: expected namespace/kind/id, got {s}"
- ));
- }
-
- let namespace = match parts[0] {
- "system" => TargetNamespace::System,
- "local" => TargetNamespace::Local,
- ns if ns.starts_with("org:") => {
- TargetNamespace::Organization(ns.strip_prefix("org:").unwrap().to_string())
- }
- ns if ns.starts_with("node:") => {
- TargetNamespace::Node(ns.strip_prefix("node:").unwrap().to_string())
- }
- _ => return Err(format!("Invalid namespace: {}", parts[0])),
- };
-
- let kind = match parts[1] {
- "Model" => ObjectKind::Model,
- "Provider" => ObjectKind::Provider,
- "User" => ObjectKind::User,
- "Users" => ObjectKind::Users,
- "Config" => ObjectKind::Config,
- "Billing" => ObjectKind::Billing,
- "System" => ObjectKind::System,
- "Quota" => ObjectKind::Quota,
- _ => return Err(format!("Invalid object kind: {}", parts[1])),
- };
-
- Ok(Self {
- namespace,
- kind,
- id: ObjectId::new(parts[2]),
- })
- }
-}
-
-impl Display for ObjectIdentity {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- write!(f, "{}/{}/{}", self.namespace, self.kind, self.id)
- }
-}
-
-#[derive(Debug, Error)]
-pub enum AuthenticationError {
- #[error("Invalid credentials")]
- InvalidCredentials,
-
- #[error("Authentication failed: {0}")]
- Failed(String),
-
- #[error("Token expired")]
- TokenExpired,
-
- #[error("Internal error: {0}")]
- Internal(String),
-}
-
-/// Establishes identity from credentials
-#[async_trait]
-pub trait Authentication: Send + Sync {
- type Context: IdentityContext;
-
- async fn authenticate(
- &self,
- credentials: &serde_json::Value,
- ) -> Result, AuthenticationError>;
-}
diff --git a/crates/core/src/access/mod.rs b/crates/core/src/access/mod.rs
deleted file mode 100644
index 5177a31b..00000000
--- a/crates/core/src/access/mod.rs
+++ /dev/null
@@ -1,10 +0,0 @@
-pub mod identity;
-pub mod permissions;
-pub mod policies;
-
-pub use identity::{
- Authentication, AuthenticationError, IdentityContext, ObjectId, ObjectIdentity, ObjectKind,
- SubjectIdentity, TargetNamespace,
-};
-pub use permissions::{Action, PermissionDenied, PermissionManager, PermissionResult, Permissions};
-pub use policies::{PolicyDecision, PolicyLimit};
diff --git a/crates/core/src/access/permissions.rs b/crates/core/src/access/permissions.rs
deleted file mode 100644
index d1536476..00000000
--- a/crates/core/src/access/permissions.rs
+++ /dev/null
@@ -1,86 +0,0 @@
-use super::identity::{IdentityContext, ObjectIdentity, SubjectIdentity};
-use async_trait::async_trait;
-use serde::{Deserialize, Serialize};
-use std::time::Duration;
-use thiserror::Error;
-
-/// Actions that can be performed on objects
-#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
-pub enum Action {
- Read,
- Write,
- Delete,
- Execute,
- Manage,
- GrantPermission,
- RevokePermission,
- ViewPermissions,
- ViewQuota,
- UpdateQuota,
- ConsumeQuota,
-}
-
-/// Reasons for permission denial
-#[derive(Debug, Clone, Error)]
-pub enum PermissionDenied {
- #[error("Not authorized")]
- NotAuthorized,
-
- #[error("Permission expired")]
- Expired,
-
- #[error("Rate limited, retry after {retry_after:?}")]
- RateLimited { retry_after: Duration },
-
- #[error("Quota exceeded for {resource}")]
- QuotaExceeded { resource: String },
-
- #[error("Account suspended: {reason}")]
- Suspended { reason: String },
-
- #[error("Permission denied: {0}")]
- Custom(String),
-}
-
-pub type PermissionResult = Result<(), PermissionDenied>;
-
-/// Checks if a subject can perform an action on an object
-#[async_trait]
-pub trait Permissions: Send + Sync {
- async fn check(
- &self,
- subject: &SubjectIdentity,
- action: Action,
- object: &ObjectIdentity,
- ) -> PermissionResult;
-}
-
-/// Manages permission grants and revocations
-#[async_trait]
-pub trait PermissionManager: Permissions {
- /// Grant a permission to a subject
- async fn grant(
- &self,
- granter: &SubjectIdentity,
- grantee: &SubjectIdentity,
- action: Action,
- object: &ObjectIdentity,
- ) -> PermissionResult;
-
- /// Revoke a permission from a subject
- async fn revoke(
- &self,
- revoker: &SubjectIdentity,
- subject: &SubjectIdentity,
- action: Action,
- object: &ObjectIdentity,
- ) -> PermissionResult;
-
- /// Store a permission without checking granter's permissions
- async fn store_permission_unchecked(
- &self,
- subject_id: &str,
- action: Action,
- object: &ObjectIdentity,
- ) -> Result<(), PermissionDenied>;
-}
diff --git a/crates/core/src/access/policies.rs b/crates/core/src/access/policies.rs
deleted file mode 100644
index 59e6e301..00000000
--- a/crates/core/src/access/policies.rs
+++ /dev/null
@@ -1,51 +0,0 @@
-use super::identity::{IdentityContext, ObjectIdentity, SubjectIdentity};
-use async_trait::async_trait;
-use rust_decimal::Decimal;
-use serde::{Deserialize, Serialize};
-use thiserror::Error;
-
-/// Limits that can be applied to allowed actions
-#[derive(Debug, Clone, Serialize, Deserialize)]
-pub enum PolicyLimit {
- TokenLimit(usize),
- RateLimit { per_minute: u32 },
- CreditCost(Decimal),
- Custom(String, serde_json::Value),
-}
-
-/// Result of a policy evaluation
-#[derive(Debug, Clone)]
-pub enum PolicyDecision {
- Allow(Vec),
- Deny(String),
-}
-
-#[derive(Debug, Error)]
-pub enum PolicyError {
- #[error("Policy evaluation failed: {0}")]
- EvaluationFailed(String),
-
- #[error("Internal error: {0}")]
- Internal(String),
-}
-
-/// Generic inference request for policy checking
-#[derive(Debug, Clone, Serialize, Deserialize)]
-pub struct InferenceRequest {
- pub model: String,
- pub prompt: String,
- pub max_tokens: Option,
- pub temperature: Option,
- pub has_images: bool,
-}
-
-/// Policy for inference operations
-#[async_trait]
-pub trait InferencePolicy: Send + Sync {
- async fn check_inference(
- &self,
- subject: &SubjectIdentity,
- object: &ObjectIdentity,
- request: &InferenceRequest,
- ) -> Result;
-}
diff --git a/crates/core/src/context.rs b/crates/core/src/context.rs
deleted file mode 100644
index e10519d5..00000000
--- a/crates/core/src/context.rs
+++ /dev/null
@@ -1,30 +0,0 @@
-use async_trait::async_trait;
-use std::collections::HashMap;
-
-/// Platform-agnostic request context trait
-///
-/// This trait abstracts away platform-specific details like Cloudflare's worker::Env
-/// to allow the same business logic to run on different platforms.
-#[async_trait]
-pub trait RequestContext: Send + Sync {
- /// Get an environment variable
- async fn get_env_var(&self, key: &str) -> Option;
-
- /// Get a secret value
- async fn get_secret(&self, key: &str) -> Option;
-
- /// Get request headers
- fn get_headers(&self) -> &HashMap;
-
- /// Get the request URL
- fn get_url(&self) -> &str;
-
- /// Get the request method
- fn get_method(&self) -> &str;
-
- /// Get the request body as bytes
- async fn get_body(&self) -> Result, Box>;
-
- /// Get client IP address
- fn get_client_ip(&self) -> Option;
-}
diff --git a/crates/core/src/errors.rs b/crates/core/src/errors.rs
deleted file mode 100644
index f7de6201..00000000
--- a/crates/core/src/errors.rs
+++ /dev/null
@@ -1,103 +0,0 @@
-use thiserror::Error;
-
-#[derive(Error, Debug)]
-pub enum Error {
- #[error("User not found: {0}")]
- UserNotFound(String),
-
- #[error("API key not found")]
- ApiKeyNotFound,
-
- #[error("Invalid API key")]
- InvalidApiKey,
-
- #[error("Provider not found: {0}")]
- ProviderNotFound(String),
-
- #[error("Model not found: {0}")]
- ModelNotFound(String),
-
- #[error("Insufficient permissions")]
- Unauthorized,
-
- #[error("Request rejected: {0}")]
- Rejected(http::StatusCode, String),
-
- #[error("Redirect required: {0}")]
- Redirect(String),
-
- #[error("State backend error: {0}")]
- StateError(String),
-
- #[error("Plugin error: {0}")]
- PluginError(String),
-
- #[error("Serialization error: {0}")]
- SerializationError(#[from] serde_json::Error),
-
- #[error("IO error: {0}")]
- IoError(#[from] std::io::Error),
-
- #[error("Internal error: {0}")]
- Internal(String),
-
- // Router-specific errors
- #[error("No sinks available for routing")]
- NoSinksAvailable,
-
- #[error("Protocol conversion not supported: {0} to {1}")]
- UnsupportedConversion(String, String),
-
- #[error("Quota exceeded: {0}")]
- QuotaExceeded(String),
-
- #[error("All routes failed")]
- AllRoutesFailed,
-
- #[error("Model not supported by any sink: {0}")]
- ModelNotSupported(String),
-
- #[error("Invalid routing configuration: {0}")]
- InvalidRoutingConfig(String),
-
- #[error("Invalid request: {0}")]
- InvalidRequest(String),
-
- #[error("Service unavailable: {0}")]
- ServiceUnavailable(String),
-
- #[error("Invalid configuration: {0}")]
- InvalidConfig(String),
-}
-
-pub type Result = std::result::Result;
-
-// Cloudflare-specific error conversions
-#[cfg(feature = "cloudflare")]
-mod cloudflare_impls {
- use super::Error;
-
- impl From for Error {
- fn from(err: worker::Error) -> Self {
- Error::StateError(format!("Worker error: {err}"))
- }
- }
-
- impl From for Error {
- fn from(err: worker::kv::KvError) -> Self {
- Error::StateError(format!("KV error: {err}"))
- }
- }
-
- impl From for Error {
- fn from(err: worker::d1::D1Error) -> Self {
- Error::StateError(format!("D1 error: {err}"))
- }
- }
-
- impl From for Error {
- fn from(err: sqlx_d1::Error) -> Self {
- Error::StateError(format!("D1 error: {err}"))
- }
- }
-}
diff --git a/crates/core/src/inference.rs b/crates/core/src/inference.rs
deleted file mode 100644
index 26a9af64..00000000
--- a/crates/core/src/inference.rs
+++ /dev/null
@@ -1,159 +0,0 @@
-use crate::Result;
-use async_trait::async_trait;
-use futures::stream::Stream;
-use serde::{Deserialize, Serialize};
-use serde_json::Value;
-use std::pin::Pin;
-
-#[derive(Debug, Clone, Serialize, Deserialize)]
-pub struct ChatCompletionRequest {
- pub model: String,
- pub messages: Vec,
- pub max_tokens: Option,
- pub temperature: Option,
- pub top_p: Option,
- pub stream: Option,
- pub stop: Option>,
- pub presence_penalty: Option,
- pub frequency_penalty: Option,
- pub logit_bias: Option,
- pub user: Option,
-}
-
-#[derive(Debug, Clone, Serialize, Deserialize)]
-pub struct ChatMessage {
- pub role: String,
- pub content: String,
- pub name: Option,
-}
-
-#[derive(Debug, Clone, Serialize, Deserialize)]
-pub struct ChatCompletionResponse {
- pub id: String,
- pub object: String,
- pub created: i64,
- pub model: String,
- pub choices: Vec,
- pub usage: Option,
-}
-
-#[derive(Debug, Clone, Serialize, Deserialize)]
-pub struct ChatChoice {
- pub index: u32,
- pub message: ChatMessage,
- pub finish_reason: Option,
-}
-
-#[derive(Debug, Clone, Serialize, Deserialize)]
-pub struct Usage {
- pub prompt_tokens: u32,
- pub completion_tokens: u32,
- pub total_tokens: u32,
-}
-
-#[derive(Debug, Clone, Serialize, Deserialize)]
-pub struct ChatCompletionChunk {
- pub id: String,
- pub object: String,
- pub created: i64,
- pub model: String,
- pub choices: Vec,
-}
-
-#[derive(Debug, Clone, Serialize, Deserialize)]
-pub struct ChatChunkChoice {
- pub index: u32,
- pub delta: ChatDelta,
- pub finish_reason: Option,
-}
-
-#[derive(Debug, Clone, Serialize, Deserialize)]
-pub struct ChatDelta {
- pub content: Option,
- pub role: Option,
-}
-
-#[derive(Debug, Clone, Serialize, Deserialize)]
-pub struct AnthropicMessageRequest {
- pub model: String,
- pub messages: Vec,
- pub max_tokens: u32,
- pub temperature: Option,
- pub top_p: Option,
- pub top_k: Option,
- pub stream: Option,
- pub stop_sequences: Option>,
- pub system: Option,
-}
-
-#[derive(Debug, Clone, Serialize, Deserialize)]
-pub struct AnthropicMessage {
- pub role: String,
- pub content: String,
-}
-
-#[derive(Debug, Clone, Serialize, Deserialize)]
-pub struct AnthropicMessageResponse {
- pub id: String,
- pub model: String,
- pub role: String,
- pub content: Vec,
- pub stop_reason: Option,
- pub stop_sequence: Option,
- pub usage: AnthropicUsage,
-}
-
-#[derive(Debug, Clone, Serialize, Deserialize)]
-pub struct AnthropicContent {
- #[serde(rename = "type")]
- pub content_type: String,
- pub text: String,
-}
-
-#[derive(Debug, Clone, Serialize, Deserialize)]
-pub struct AnthropicUsage {
- pub input_tokens: u32,
- pub output_tokens: u32,
-}
-
-#[derive(Debug, Clone, Serialize, Deserialize)]
-pub struct LocalModel {
- pub id: String,
- pub name: String,
- pub provider: String,
- pub path: Option,
- pub context_length: u32,
- pub supports_chat: bool,
- pub supports_completion: bool,
-}
-
-pub type ChatCompletionStream = Pin> + Send>>;
-pub type AnthropicMessageStream = Pin> + Send>>;
-
-#[async_trait]
-pub trait InferenceBackend: Send + Sync {
- async fn chat_completions(
- &self,
- request: ChatCompletionRequest,
- ) -> Result;
-
- async fn chat_completions_stream(
- &self,
- request: ChatCompletionRequest,
- ) -> Result;
-
- async fn messages(&self, request: AnthropicMessageRequest) -> Result;
-
- async fn messages_stream(
- &self,
- request: AnthropicMessageRequest,
- ) -> Result;
-
- async fn list_models(&self) -> Result>;
-
- async fn get_model(&self, model_id: &str) -> Result>;
-
- async fn health_check(&self) -> Result {
- Ok(true)
- }
-}
diff --git a/crates/core/src/lib.rs b/crates/core/src/lib.rs
deleted file mode 100644
index bae58604..00000000
--- a/crates/core/src/lib.rs
+++ /dev/null
@@ -1,29 +0,0 @@
-pub mod access;
-pub mod context;
-pub mod errors;
-pub mod inference;
-pub mod router;
-pub mod state;
-pub mod types;
-
-#[cfg(feature = "tracing")]
-#[macro_use]
-extern crate tracing as tracing_crate;
-
-#[cfg(feature = "tracing")]
-#[macro_use]
-pub mod tracing;
-
-#[cfg(any(test, feature = "tests"))]
-pub mod tests;
-
-pub use context::RequestContext;
-pub use errors::{Error, Result};
-pub use inference::InferenceBackend;
-pub use state::StateBackend;
-
-// Re-export types for convenience
-pub use types::{
- ApiKey, Error as ProtoError, HookAction, HookResponse, Model, ModelType, Organization,
- Provider, ProviderType, RequestHookContext, ResponseHookContext, TimeRange, UsageRecord, User,
-};
diff --git a/crates/core/src/router/executor.rs b/crates/core/src/router/executor.rs
deleted file mode 100644
index 4b58116d..00000000
--- a/crates/core/src/router/executor.rs
+++ /dev/null
@@ -1,86 +0,0 @@
-use super::plan::{Route, RoutingPlan};
-use super::registry::SinkRegistry;
-use super::sink::{RequestContext, Sink};
-use super::types::{RequestStream, ResponseChunk, StopReason};
-use crate::Result;
-use std::sync::Arc;
-use std::time::Duration;
-
-pub struct PlanExecutor {
- sink_registry: Arc,
-}
-
-impl PlanExecutor {
- pub fn new(sink_registry: Arc) -> Self {
- Self { sink_registry }
- }
-
- pub async fn execute(
- &self,
- plan: RoutingPlan,
- request: RequestStream,
- ) -> Result {
- let result = self
- .execute_route(&plan.context, request, &plan.primary_route)
- .await;
- match result {
- Ok(stream) => Ok(stream),
- Err(primary_err) => {
- #[cfg(feature = "tracing")]
- {
- warn!(
- "Primary route failed: {} - {}",
- plan.primary_route.sink_id, primary_err
- );
- }
- Err(primary_err)
- }
- }
- }
-
- async fn execute_route(
- &self,
- ctx: &RequestContext,
- request: RequestStream,
- route: &Route,
- ) -> Result {
- let sink = self
- .sink_registry
- .get(&route.sink_id)
- .await
- .ok_or_else(|| crate::Error::Internal(format!("Sink not found: {}", route.sink_id)))?;
-
- if route.protocol_conversion.is_some() {
- return Err(crate::Error::UnsupportedConversion(
- "from".into(),
- "to".into(),
- ));
- }
-
- self.execute_with_retries(ctx, sink, request, &route.retry_config, route.timeout)
- .await
- }
-
- async fn execute_with_retries(
- &self,
- ctx: &RequestContext,
- sink: Arc,
- request: RequestStream,
- _retry_config: &super::types::RetryConfig,
- timeout: Duration,
- ) -> Result {
- match tokio::time::timeout(timeout, sink.execute(ctx, request)).await {
- Ok(Ok(stream)) => Ok(stream),
- Ok(Err(err)) => Err(err),
- Err(_) => {
- let chunk = ResponseChunk::Stop {
- reason: StopReason::Timeout,
- error: Some("Request timed out".to_string()),
- cost: None,
- };
- let stream = futures::stream::once(async move { Ok(chunk) });
- Ok(Box::pin(stream))
- }
- }
- }
-}
diff --git a/crates/core/src/router/index.rs b/crates/core/src/router/index.rs
deleted file mode 100644
index a1ec49e3..00000000
--- a/crates/core/src/router/index.rs
+++ /dev/null
@@ -1,91 +0,0 @@
-//! SinkIndex: caller-managed snapshots of sink descriptions and health
-
-use tokio::sync::RwLock;
-
-use super::registry::SinkRegistry;
-use super::sink::SinkDescription;
-use super::types::SinkHealth;
-use std::collections::HashMap;
-use std::sync::Arc;
-
-/// Snapshot of a sink's description and health
-#[derive(Clone, Debug)]
-pub struct SinkSnapshot {
- pub description: SinkDescription,
- pub health: SinkHealth,
- pub updated_at: chrono::DateTime,
-}
-
-/// Caller-managed index of sink snapshots for fast routing
-#[derive(Default, Debug, Clone)]
-pub struct SinkIndex {
- inner: Arc>>,
-}
-
-impl SinkIndex {
- pub fn new() -> Self {
- Self {
- inner: Arc::new(RwLock::new(HashMap::new())),
- }
- }
-
- /// Set or update a snapshot for a sink ID (URL)
- pub async fn set_snapshot(
- &self,
- sink_id: String,
- description: SinkDescription,
- health: SinkHealth,
- ) {
- let mut guard = self.inner.write().await;
- guard.insert(
- sink_id,
- SinkSnapshot {
- description,
- health,
- updated_at: chrono::Utc::now(),
- },
- );
- }
-
- /// Remove a snapshot
- pub async fn remove(&self, sink_id: &str) {
- let mut guard = self.inner.write().await;
- guard.remove(sink_id);
- }
-
- /// Get a snapshot by sink ID
- pub async fn get(&self, sink_id: &str) -> Option {
- let guard = self.inner.read().await;
- guard.get(sink_id).cloned()
- }
-
- /// List all snapshots
- pub async fn list(&self) -> Vec<(String, SinkSnapshot)> {
- let guard = self.inner.read().await;
- guard.iter().map(|(k, v)| (k.clone(), v.clone())).collect()
- }
-
- /// Refresh snapshots from the given registry (all sinks)
- pub async fn refresh_from_registry(&self, registry: &SinkRegistry) -> usize {
- let ids = registry.list_ids().await;
- self.refresh_subset_from_registry(registry, &ids).await
- }
-
- /// Refresh a subset of sink IDs from the registry
- pub async fn refresh_subset_from_registry(
- &self,
- registry: &SinkRegistry,
- ids: &[String],
- ) -> usize {
- let mut count = 0usize;
- for id in ids {
- if let Some(sink) = registry.get(id).await {
- let desc = sink.describe().await;
- let health = sink.probe().await;
- self.set_snapshot(id.clone(), desc, health).await;
- count += 1;
- }
- }
- count
- }
-}
diff --git a/crates/core/src/router/middleware/cost_tracker.rs b/crates/core/src/router/middleware/cost_tracker.rs
deleted file mode 100644
index 00e93bd1..00000000
--- a/crates/core/src/router/middleware/cost_tracker.rs
+++ /dev/null
@@ -1,101 +0,0 @@
-//! Cost tracking middleware
-
-use super::{Middleware, Next, RequestStream, ResponseStream};
-use crate::router::sink::RequestContext;
-use crate::router::types::{ActualCost, ResponseChunk};
-use crate::state::StateBackend;
-use crate::{Result, UsageRecord};
-use async_trait::async_trait;
-use futures::StreamExt;
-use std::sync::Arc;
-
-/// Cost tracking middleware
-pub struct CostTrackerMiddleware {
- state_backend: Arc,
-}
-
-impl CostTrackerMiddleware {
- /// Create a new cost tracker middleware
- pub fn new(state_backend: Arc) -> Self {
- Self { state_backend }
- }
-}
-
-#[async_trait]
-impl Middleware for CostTrackerMiddleware {
- async fn process(
- &self,
- ctx: &mut RequestContext,
- request: RequestStream,
- next: Next,
- ) -> Result {
- // Forward the request
- let mut response_stream = next(request).await?;
-
- // Create a new stream that intercepts cost information
- let state_backend = self.state_backend.clone();
- let ctx_clone = ctx.clone();
-
- let intercepted_stream = async_stream::stream! {
- let mut total_cost: Option = None;
- let mut model = String::new();
- let mut provider = String::new();
-
- while let Some(chunk_result) = response_stream.next().await {
- match chunk_result {
- Ok(chunk) => {
- // Intercept metadata for model/provider
- // Extract metadata
- if let ResponseChunk::Metadata(ref metadata) = chunk {
- if let Some(m) = metadata.get("model").and_then(|v| v.as_str()) {
- model = m.to_string();
- }
- if let Some(p) = metadata.get("provider").and_then(|v| v.as_str()) {
- provider = p.to_string();
- }
- }
-
- // Intercept final cost on Stop
- if let ResponseChunk::Stop { cost: Some(ref c), .. } = chunk {
- total_cost = Some(c.clone());
- }
-
- yield Ok(chunk);
- }
- Err(e) => {
- yield Err(e);
- }
- }
- }
-
- // Record usage if we have cost information
- if let Some(cost) = total_cost {
- let usage = UsageRecord {
- id: uuid::Uuid::new_v4().to_string(),
- org_id: ctx_clone.identity.context.org_id.clone().unwrap_or_default(),
- user_id: ctx_clone.identity.context.user_id.clone().unwrap_or_default(),
- api_key_hash: ctx_clone.identity.context.api_key_hash.clone().unwrap_or_default(),
- request_id: ctx_clone.trace_id.clone().unwrap_or_default(),
- provider_id: provider,
- model_id: model,
- input_tokens: cost.input_tokens as u64,
- output_tokens: cost.output_tokens as u64,
- total_tokens: (cost.input_tokens + cost.output_tokens) as u64,
- cost: cost.total_cost_usd.to_string().parse().unwrap_or(0.0),
- timestamp: chrono::Utc::now(),
- metadata: std::collections::HashMap::new(),
- };
-
- if let Err(e) = state_backend.record_usage(&usage).await {
- #[cfg(feature = "tracing")]
- {
- error!("Failed to record usage: {}", e);
- }
- let _ = e; // Suppress unused warning when tracing is disabled
- }
- }
- };
-
- Ok(Box::pin(intercepted_stream))
- }
-}
diff --git a/crates/core/src/router/middleware/key_capture.rs b/crates/core/src/router/middleware/key_capture.rs
deleted file mode 100644
index e73acff9..00000000
--- a/crates/core/src/router/middleware/key_capture.rs
+++ /dev/null
@@ -1,84 +0,0 @@
-use super::{Middleware, Next, RequestStream, ResponseStream};
-use crate::Result;
-use crate::router::sink::RequestContext;
-use crate::router::types::{Protocol, ResponseChunk, StopReason};
-use async_trait::async_trait;
-use futures::StreamExt;
-use http::header::AUTHORIZATION;
-use std::sync::Arc;
-
-/// Hook for registering providers on successful responses
-#[async_trait]
-pub trait KeyCaptureRegistrar: Send + Sync {
- async fn register_anthropic_key(&self, key: &str) -> Result<()>;
-}
-
-/// Middleware that captures Anthropic API keys on successful requests
-pub struct KeyCaptureMiddleware {
- registrar: Arc,
-}
-
-impl KeyCaptureMiddleware {
- pub fn new(registrar: Arc) -> Self {
- Self { registrar }
- }
-
- fn extract_anthropic_key(ctx: &RequestContext) -> Option {
- if let Some(val) = ctx.headers.get("x-api-key")
- && let Ok(key) = val.to_str()
- && key.starts_with("sk-ant-")
- {
- return Some(key.to_string());
- }
- if let Some(val) = ctx.headers.get(AUTHORIZATION)
- && let Ok(auth) = val.to_str()
- && let Some(token) = auth.strip_prefix("Bearer ")
- && token.starts_with("sk-ant-")
- {
- return Some(token.to_string());
- }
- None
- }
-}
-
-#[async_trait]
-impl Middleware for KeyCaptureMiddleware {
- async fn process(
- &self,
- ctx: &mut RequestContext,
- request: RequestStream,
- next: Next,
- ) -> Result {
- // Only attempt capture for Anthropic protocol
- let protocol = request.protocol();
- let maybe_key = if protocol == Protocol::Anthropic {
- Self::extract_anthropic_key(ctx)
- } else {
- None
- };
-
- // Forward
- let mut response_stream = next(request).await?;
-
- if maybe_key.is_none() {
- return Ok(response_stream);
- }
-
- let key = maybe_key.unwrap();
- let registrar = self.registrar.clone();
-
- let intercepted = async_stream::stream! {
- let mut captured = false;
- while let Some(item) = response_stream.next().await {
- if let Ok(ResponseChunk::Stop { reason, error, .. }) = &item && !captured && matches!(reason, StopReason::Complete) && error.is_none() {
- // Best-effort capture, ignore errors
- let _ = registrar.register_anthropic_key(&key).await;
- captured = true;
- }
- yield item;
- }
- };
-
- Ok(Box::pin(intercepted))
- }
-}
diff --git a/crates/core/src/router/middleware/mod.rs b/crates/core/src/router/middleware/mod.rs
deleted file mode 100644
index 15344bc2..00000000
--- a/crates/core/src/router/middleware/mod.rs
+++ /dev/null
@@ -1,38 +0,0 @@
-//! Middleware system for request/response processing
-
-mod cost_tracker;
-mod key_capture;
-mod monitor;
-mod rate_limit;
-
-pub use cost_tracker::CostTrackerMiddleware;
-pub use key_capture::{KeyCaptureMiddleware, KeyCaptureRegistrar};
-pub use monitor::MonitoringMiddleware;
-pub use rate_limit::RateLimitMiddleware;
-
-use crate::Result;
-use async_trait::async_trait;
-use futures::Stream;
-use futures::future::BoxFuture;
-use std::pin::Pin;
-
-/// Stream of request data
-pub type RequestStream = super::types::RequestStream;
-
-/// Stream of response data
-pub type ResponseStream = Pin> + Send>>;
-
-/// Next middleware in the chain
-pub type Next = Box BoxFuture<'static, Result> + Send>;
-
-/// Middleware trait for processing requests and responses
-#[async_trait]
-pub trait Middleware: Send + Sync {
- /// Process the request/response through this middleware
- async fn process(
- &self,
- ctx: &mut super::sink::RequestContext,
- request: RequestStream,
- next: Next,
- ) -> Result;
-}
diff --git a/crates/core/src/router/middleware/monitor.rs b/crates/core/src/router/middleware/monitor.rs
deleted file mode 100644
index 7f03862d..00000000
--- a/crates/core/src/router/middleware/monitor.rs
+++ /dev/null
@@ -1,166 +0,0 @@
-//! Monitoring middleware for observability
-
-use super::{Middleware, Next, RequestStream, ResponseStream};
-use crate::Result;
-use crate::router::sink::RequestContext;
-use crate::router::types::ResponseChunk;
-use async_trait::async_trait;
-use futures::StreamExt;
-use std::time::Instant;
-
-/// Monitoring middleware for metrics and tracing
-pub struct MonitoringMiddleware {
- service_name: String,
-}
-
-impl MonitoringMiddleware {
- /// Create a new monitoring middleware
- pub fn new(service_name: String) -> Self {
- Self { service_name }
- }
-}
-
-impl Default for MonitoringMiddleware {
- fn default() -> Self {
- Self::new("gate-router".to_string())
- }
-}
-
-#[async_trait]
-impl Middleware for MonitoringMiddleware {
- async fn process(
- &self,
- ctx: &mut RequestContext,
- request: RequestStream,
- next: Next,
- ) -> Result {
- let start_time = Instant::now();
- let trace_id = ctx
- .trace_id
- .clone()
- .unwrap_or_else(|| "unknown".to_string());
-
- // Log request start
- #[cfg(feature = "tracing")]
- {
- info!(
- service = %self.service_name,
- trace_id = %trace_id,
- user_id = ?ctx.identity.context.user_id,
- "Processing request"
- );
- }
-
- // Process the request
- let result = next(request).await;
-
- match &result {
- Ok(_) => {
- let duration = start_time.elapsed();
- #[cfg(feature = "tracing")]
- {
- info!(
- service = %self.service_name,
- trace_id = %trace_id,
- duration_ms = %duration.as_millis(),
- "Request completed successfully"
- );
- }
-
- // Wrap the stream to monitor chunks
- let mut stream = result?;
- let service_name = self.service_name.clone();
- let trace_id_clone = trace_id.clone();
-
- let monitored_stream = async_stream::stream! {
- let mut chunk_count = 0;
- let mut total_tokens = 0u32;
- let mut has_error = false;
-
- while let Some(chunk_result) = stream.next().await {
- match chunk_result {
- Ok(chunk) => {
- chunk_count += 1;
-
- // Track token usage
- if let ResponseChunk::Usage { prompt_tokens, completion_tokens } = &chunk {
- total_tokens = prompt_tokens + completion_tokens;
- #[cfg(feature = "tracing")]
- {
- debug!(
- service = %service_name,
- trace_id = %trace_id_clone,
- prompt_tokens = %prompt_tokens,
- completion_tokens = %completion_tokens,
- "Token usage"
- );
- }
- }
-
- // Track errors
- if let ResponseChunk::Stop { error: Some(err), .. } = &chunk {
- has_error = true;
- #[cfg(feature = "tracing")]
- {
- error!(
- service = %service_name,
- trace_id = %trace_id_clone,
- error = %err,
- "Stream error"
- );
- }
- }
-
- yield Ok(chunk);
- }
- Err(e) => {
- has_error = true;
- #[cfg(feature = "tracing")]
- {
- error!(
- service = %service_name,
- trace_id = %trace_id_clone,
- error = %e,
- "Stream processing error"
- );
- }
- yield Err(e);
- }
- }
- }
-
- // Log stream completion
- let total_duration = start_time.elapsed();
- #[cfg(feature = "tracing")]
- {
- info!(
- service = %service_name,
- trace_id = %trace_id_clone,
- chunks = %chunk_count,
- total_tokens = %total_tokens,
- duration_ms = %total_duration.as_millis(),
- success = %!has_error,
- "Stream completed"
- );
- }
- };
-
- Ok(Box::pin(monitored_stream))
- }
- Err(e) => {
- let duration = start_time.elapsed();
- #[cfg(feature = "tracing")]
- {
- error!(
- service = %self.service_name,
- trace_id = %trace_id,
- duration_ms = %duration.as_millis(),
- error = %e,
- "Request failed"
- );
- }
- result
- }
- }
- }
-}
diff --git a/crates/core/src/router/middleware/rate_limit.rs b/crates/core/src/router/middleware/rate_limit.rs
deleted file mode 100644
index 01aa99e0..00000000
--- a/crates/core/src/router/middleware/rate_limit.rs
+++ /dev/null
@@ -1,177 +0,0 @@
-//! Rate limiting middleware
-
-use super::{Middleware, Next, RequestStream, ResponseStream};
-use crate::Result;
-use crate::router::sink::RequestContext;
-use crate::router::types::QuotaBehavior;
-use async_trait::async_trait;
-use std::collections::HashMap;
-use std::sync::Arc;
-use tokio::sync::RwLock;
-use tokio::time::{Duration, Instant};
-
-/// Trait for pluggable rate limit queue backends
-#[async_trait]
-pub trait RateLimitQueue: Send + Sync {
- async fn enqueue(&self, key: &str, timeout: Duration) -> Result<()>;
- async fn release(&self, key: &str);
-}
-
-/// Rate limit configuration
-#[derive(Debug, Clone)]
-pub struct RateLimitConfig {
- pub requests_per_minute: u32,
- pub tokens_per_minute: Option,
- pub behavior: QuotaBehavior,
-}
-
-impl Default for RateLimitConfig {
- fn default() -> Self {
- Self {
- requests_per_minute: 60,
- tokens_per_minute: Some(100_000),
- behavior: QuotaBehavior::Reject,
- }
- }
-}
-
-/// Rate limiter state for a single key
-#[derive(Debug)]
-struct RateLimitState {
- request_count: u32,
- token_count: u32,
- window_start: Instant,
-}
-
-impl RateLimitState {
- fn new() -> Self {
- Self {
- request_count: 0,
- token_count: 0,
- window_start: Instant::now(),
- }
- }
-
- fn reset_if_needed(&mut self, window_duration: Duration) {
- if self.window_start.elapsed() >= window_duration {
- self.request_count = 0;
- self.token_count = 0;
- self.window_start = Instant::now();
- }
- }
-}
-
-/// Rate limiting middleware
-pub struct RateLimitMiddleware {
- config: RateLimitConfig,
- states: Arc>>,
- queue: Option>, // optional external queue implementation
-}
-
-impl RateLimitMiddleware {
- /// Create a new rate limit middleware
- pub fn new(config: RateLimitConfig) -> Self {
- Self {
- config,
- states: Arc::new(RwLock::new(HashMap::new())),
- queue: None,
- }
- }
-
- /// Set a pluggable queue implementation
- pub fn with_queue(mut self, queue: Arc) -> Self {
- self.queue = Some(queue);
- self
- }
-
- /// Get the rate limit key from the context
- fn get_rate_limit_key(ctx: &RequestContext) -> String {
- // Use user ID if available, otherwise use org ID, otherwise use a default
- ctx.identity
- .context
- .user_id
- .clone()
- .or_else(|| ctx.identity.context.org_id.clone())
- .unwrap_or_else(|| "default".to_string())
- }
-
- /// Check if the request is within rate limits
- async fn check_rate_limit(&self, key: &str) -> Result {
- let mut states = self.states.write().await;
- let state = states
- .entry(key.to_string())
- .or_insert_with(RateLimitState::new);
-
- // Reset window if needed
- state.reset_if_needed(Duration::from_secs(60));
-
- // Check request limit
- if state.request_count >= self.config.requests_per_minute {
- return match self.config.behavior {
- QuotaBehavior::Reject => Err(crate::Error::QuotaExceeded(format!(
- "Request rate limit exceeded: {} requests per minute",
- self.config.requests_per_minute
- ))),
- QuotaBehavior::WarnOnly => {
- #[cfg(feature = "tracing")]
- {
- warn!(
- "Request rate limit exceeded for {}: {} requests",
- key, state.request_count
- );
- }
- Ok(true)
- }
- QuotaBehavior::TrackOverage => {
- #[cfg(feature = "tracing")]
- {
- info!(
- "Tracking overage for {}: {} requests over limit",
- key,
- state.request_count - self.config.requests_per_minute
- );
- }
- Ok(true)
- }
- };
- }
-
- // Increment request count
- state.request_count += 1;
- Ok(true)
- }
-}
-
-#[async_trait]
-impl Middleware for RateLimitMiddleware {
- async fn process(
- &self,
- ctx: &mut RequestContext,
- request: RequestStream,
- next: Next,
- ) -> Result {
- let key = Self::get_rate_limit_key(ctx);
-
- // Check rate limit
- // If over limits and behavior is Queue, optionally enqueue
- match self.check_rate_limit(&key).await {
- Ok(_) => {}
- Err(e) => {
- if let QuotaBehavior::Reject = self.config.behavior {
- return Err(e);
- }
- if let QuotaBehavior::TrackOverage | QuotaBehavior::WarnOnly = self.config.behavior
- {
- // pass through
- }
- }
- }
-
- // Process the request
- let response = next(request).await?;
-
- // TODO: Token usage tracking could be added by inspecting the response stream
-
- Ok(response)
- }
-}
diff --git a/crates/core/src/router/mod.rs b/crates/core/src/router/mod.rs
deleted file mode 100644
index 4413ccf5..00000000
--- a/crates/core/src/router/mod.rs
+++ /dev/null
@@ -1,35 +0,0 @@
-//! Smart routing module for LLM inference requests
-//!
-//! This module provides intelligent routing of inference requests across multiple
-//! providers, protocols, and deployment contexts (WASM, local daemon, Cloudflare Workers).
-
-pub mod executor;
-pub mod index;
-pub mod middleware;
-pub mod plan;
-pub mod prelude;
-pub mod protocols;
-pub mod record;
-pub mod registry;
-pub mod routing;
-pub mod service;
-pub mod signals;
-pub mod sink;
-pub mod sinks;
-pub mod strategy;
-pub mod types;
-
-#[cfg(test)]
-mod tests;
-
-// Re-export main types
-pub use index::{SinkIndex, SinkSnapshot};
-pub use plan::{Route, RoutingPlan};
-pub use registry::SinkRegistry;
-pub use routing::Router;
-pub use sink::RequestContext;
-pub use sink::{ResponseStream, Sink, SinkDescription};
-pub use types::{
- ActualCost, ModelCapabilities, Protocol, ResponseChunk, SinkCapabilities, SinkHealth,
- StopReason, VirtualModel,
-};
diff --git a/crates/core/src/router/plan.rs b/crates/core/src/router/plan.rs
deleted file mode 100644
index 23c90ca9..00000000
--- a/crates/core/src/router/plan.rs
+++ /dev/null
@@ -1,47 +0,0 @@
-//! Routing plan definition
-use super::protocols::ProtocolConversion;
-use super::sink::RequestContext;
-use super::types::RetryConfig;
-use rust_decimal::Decimal;
-use serde::{Deserialize, Serialize};
-use std::time::Duration;
-
-/// Executable routing plan
-#[derive(Debug, Clone)]
-pub struct RoutingPlan {
- pub id: uuid::Uuid,
- pub created_at: chrono::DateTime,
- pub context: RequestContext,
- pub primary_route: Route,
- pub fallback_routes: Vec,
- pub estimated_cost: Option,
-}
-
-/// A single route in the plan
-#[derive(Debug, Clone, Serialize, Deserialize)]
-pub struct Route {
- pub sink_id: String,
- pub protocol_conversion: Option,
- pub timeout: Duration,
- pub retry_config: RetryConfig,
-}
-
-impl RoutingPlan {
- /// Create a new routing plan
- pub fn new(context: RequestContext, primary_route: Route, fallback_routes: Vec) -> Self {
- Self {
- id: uuid::Uuid::new_v4(),
- created_at: chrono::Utc::now(),
- context,
- primary_route,
- fallback_routes,
- estimated_cost: None,
- }
- }
-
- /// Set estimated cost
- pub fn with_estimated_cost(mut self, cost: Decimal) -> Self {
- self.estimated_cost = Some(cost);
- self
- }
-}
diff --git a/crates/core/src/router/prelude.rs b/crates/core/src/router/prelude.rs
deleted file mode 100644
index 880ffdd8..00000000
--- a/crates/core/src/router/prelude.rs
+++ /dev/null
@@ -1,12 +0,0 @@
-pub use super::executor::PlanExecutor;
-pub use super::plan::{Route, RoutingPlan};
-pub use super::registry::SinkRegistry;
-pub use super::routing::Router;
-pub use super::service::route_and_execute_json_with_protocol;
-pub use super::sink::{
- RequestContext, ResponseStream, RouterIdentityContext, Sink, SinkDescription,
-};
-pub use super::types::{
- ModelList, Protocol, RequestDescriptor, RequestStream, ResponseChunk, SinkCapabilities,
- SinkHealth, StopReason,
-};
diff --git a/crates/core/src/router/protocols/capabilities.rs b/crates/core/src/router/protocols/capabilities.rs
deleted file mode 100644
index d1cad273..00000000
--- a/crates/core/src/router/protocols/capabilities.rs
+++ /dev/null
@@ -1,94 +0,0 @@
-//! Request capability extraction
-
-use super::Protocol;
-use crate::router::types::RequestCapabilities;
-use serde_json::Value as JsonValue;
-
-/// Extract required capabilities from request
-pub fn extract_capabilities(request: &JsonValue, protocol: Protocol) -> RequestCapabilities {
- RequestCapabilities {
- needs_tools: detect_tools(request, protocol),
- needs_vision: detect_vision(request, protocol),
- needs_streaming: request
- .get("stream")
- .and_then(|v| v.as_bool())
- .unwrap_or(false),
- max_tokens: request
- .get("max_tokens")
- .and_then(|v| v.as_u64())
- .map(|v| v as u32),
- modalities: detect_modalities(request, protocol),
- }
-}
-
-/// Detect if request needs tool/function support
-fn detect_tools(request: &JsonValue, _protocol: Protocol) -> bool {
- request.get("tools").is_some()
- || request.get("functions").is_some()
- || request.get("tool_choice").is_some()
- || request.get("function_call").is_some()
-}
-
-/// Detect if request contains image content
-fn detect_vision(request: &JsonValue, protocol: Protocol) -> bool {
- match protocol {
- Protocol::OpenAIChat => detect_vision_openai(request),
- Protocol::Anthropic => detect_vision_anthropic(request),
- _ => false,
- }
-}
-
-/// Detect vision in OpenAI format
-fn detect_vision_openai(request: &JsonValue) -> bool {
- if let Some(messages) = request.get("messages").and_then(|m| m.as_array()) {
- for message in messages {
- if let Some(content) = message.get("content") {
- // Check if content is an array (multi-modal)
- if let Some(content_array) = content.as_array() {
- for item in content_array {
- if let Some(item_type) = item.get("type").and_then(|t| t.as_str())
- && (item_type == "image_url" || item_type == "image")
- {
- return true;
- }
- }
- }
- }
- }
- }
- false
-}
-
-/// Detect vision in Anthropic format
-fn detect_vision_anthropic(request: &JsonValue) -> bool {
- if let Some(messages) = request.get("messages").and_then(|m| m.as_array()) {
- for message in messages {
- if let Some(content) = message.get("content").and_then(|c| c.as_array()) {
- for block in content {
- if let Some(block_type) = block.get("type").and_then(|t| t.as_str())
- && block_type == "image"
- {
- return true;
- }
- }
- }
- }
- }
- false
-}
-
-/// Detect modalities in the request
-fn detect_modalities(request: &JsonValue, protocol: Protocol) -> Vec {
- let mut modalities = vec!["text".to_string()];
-
- if detect_vision(request, protocol) {
- modalities.push("vision".to_string());
- }
-
- // Check for audio (future support)
- if request.get("audio").is_some() {
- modalities.push("audio".to_string());
- }
-
- modalities
-}
diff --git a/crates/core/src/router/protocols/convert.rs b/crates/core/src/router/protocols/convert.rs
deleted file mode 100644
index 7df2881a..00000000
--- a/crates/core/src/router/protocols/convert.rs
+++ /dev/null
@@ -1,465 +0,0 @@
-//! Protocol conversion implementations
-
-use super::Protocol;
-use crate::Result;
-use serde_json::{Value as JsonValue, json};
-
-/// Check if conversion between protocols is possible
-pub fn can_convert(from: Protocol, to: Protocol) -> bool {
- match (from, to) {
- (Protocol::Anthropic, Protocol::OpenAIChat) => true,
- (Protocol::OpenAIChat, Protocol::Anthropic) => true,
- (Protocol::OpenAICompletions, Protocol::OpenAIChat) => true,
- (a, b) if a == b => true,
- _ => false,
- }
-}
-
-/// Get expected information loss for a conversion
-pub fn conversion_loss(from: Protocol, to: Protocol) -> Vec {
- match (from, to) {
- (Protocol::Anthropic, Protocol::OpenAIChat) => vec![
- "system prompts handled differently".to_string(),
- "cache_control not supported".to_string(),
- ],
- (Protocol::OpenAIChat, Protocol::Anthropic) => vec![
- "function_call becomes tool_use".to_string(),
- "logprobs not supported".to_string(),
- ],
- (Protocol::OpenAICompletions, Protocol::OpenAIChat) => {
- vec!["completion context becomes single user message".to_string()]
- }
- _ => vec![],
- }
-}
-
-/// Convert request between protocols
-pub fn convert_request(
- from: Protocol,
- to: Protocol,
- json: &JsonValue,
-) -> Result<(JsonValue, Vec)> {
- match (from, to) {
- (Protocol::Anthropic, Protocol::OpenAIChat) => anthropic_to_openai_chat(json),
- (Protocol::OpenAIChat, Protocol::Anthropic) => openai_chat_to_anthropic(json),
- (Protocol::OpenAICompletions, Protocol::OpenAIChat) => completions_to_chat(json),
- (a, b) if a == b => Ok((json.clone(), vec![])),
- _ => Err(crate::Error::UnsupportedConversion(
- format!("{from:?}"),
- format!("{to:?}"),
- )),
- }
-}
-
-/// Convert response between protocols
-pub fn convert_response(
- from: Protocol,
- to: Protocol,
- json: &JsonValue,
-) -> Result<(JsonValue, Vec)> {
- match (from, to) {
- (Protocol::OpenAIChat, Protocol::Anthropic) => openai_chat_response_to_anthropic(json),
- (Protocol::Anthropic, Protocol::OpenAIChat) => anthropic_response_to_openai_chat(json),
- (a, b) if a == b => Ok((json.clone(), vec![])),
- _ => Err(crate::Error::UnsupportedConversion(
- format!("{from:?}"),
- format!("{to:?}"),
- )),
- }
-}
-
-/// Convert Anthropic request to OpenAI chat format
-fn anthropic_to_openai_chat(json: &JsonValue) -> Result<(JsonValue, Vec)> {
- let mut warnings = Vec::new();
- let mut result = json!({});
-
- // Copy model
- if let Some(model) = json.get("model") {
- result["model"] = model.clone();
- }
-
- // Convert messages
- if let Some(messages) = json.get("messages") {
- let mut converted_messages = Vec::new();
-
- // Add system message if present
- if let Some(system) = json.get("system") {
- converted_messages.push(json!({
- "role": "system",
- "content": system
- }));
- }
-
- // Convert each message
- if let Some(msg_array) = messages.as_array() {
- for msg in msg_array {
- let role = msg.get("role").and_then(|r| r.as_str()).unwrap_or("user");
- let content = msg.get("content");
-
- // Handle content blocks (Anthropic can have multiple content blocks)
- if let Some(content_array) = content.and_then(|c| c.as_array()) {
- let mut text_parts = Vec::new();
- for block in content_array {
- if let Some(block_type) = block.get("type").and_then(|t| t.as_str()) {
- match block_type {
- "text" => {
- if let Some(text) = block.get("text").and_then(|t| t.as_str()) {
- text_parts.push(text.to_string());
- }
- }
- "image" => {
- warnings.push("Image content not fully supported".to_string());
- }
- _ => {
- warnings
- .push(format!("Content type {block_type} not supported"));
- }
- }
- }
- }
- converted_messages.push(json!({
- "role": role,
- "content": text_parts.join("\n")
- }));
- } else if let Some(content_str) = content.and_then(|c| c.as_str()) {
- converted_messages.push(json!({
- "role": role,
- "content": content_str
- }));
- }
- }
- }
-
- result["messages"] = json!(converted_messages);
- }
-
- // Copy common parameters
- for field in &["temperature", "max_tokens", "top_p", "stream", "stop"] {
- if let Some(value) = json.get(*field) {
- result[*field] = value.clone();
- }
- }
-
- // Handle tools
- if let Some(tools) = json.get("tools") {
- result["tools"] = tools.clone();
- if let Some(tool_choice) = json.get("tool_choice") {
- result["tool_choice"] = tool_choice.clone();
- }
- }
-
- // Warn about unsupported fields
- if json.get("cache_control").is_some() {
- warnings.push("cache_control not supported in OpenAI format".to_string());
- }
-
- Ok((result, warnings))
-}
-
-/// Convert OpenAI chat to Anthropic format
-fn openai_chat_to_anthropic(json: &JsonValue) -> Result<(JsonValue, Vec)> {
- let mut warnings = Vec::new();
- let mut result = json!({
- "anthropic_version": "2024-10-22"
- });
-
- // Copy model
- if let Some(model) = json.get("model") {
- result["model"] = model.clone();
- }
-
- // Convert messages
- if let Some(messages) = json.get("messages").and_then(|m| m.as_array()) {
- let mut system_content = None;
- let mut converted_messages = Vec::new();
-
- for msg in messages {
- let role = msg.get("role").and_then(|r| r.as_str()).unwrap_or("user");
- let content = msg.get("content");
-
- match role {
- "system" => {
- // Anthropic uses a separate system field
- if let Some(content_str) = content.and_then(|c| c.as_str()) {
- system_content = Some(content_str.to_string());
- }
- }
- "assistant" => {
- if let Some(content_str) = content.and_then(|c| c.as_str()) {
- converted_messages.push(json!({
- "role": "assistant",
- "content": [{
- "type": "text",
- "text": content_str
- }]
- }));
- }
- }
- "user" => {
- if let Some(content_str) = content.and_then(|c| c.as_str()) {
- converted_messages.push(json!({
- "role": "user",
- "content": [{
- "type": "text",
- "text": content_str
- }]
- }));
- }
- }
- _ => {
- warnings.push(format!("Unknown role: {role}"));
- }
- }
- }
-
- if let Some(system) = system_content {
- result["system"] = json!(system);
- }
- result["messages"] = json!(converted_messages);
- }
-
- // Copy common parameters
- for field in &[
- "temperature",
- "max_tokens",
- "top_p",
- "stream",
- "stop_sequences",
- ] {
- if let Some(value) = json.get(*field) {
- result[*field] = value.clone();
- }
- }
-
- // Handle tools/functions
- if let Some(tools) = json.get("tools") {
- result["tools"] = tools.clone();
- if let Some(tool_choice) = json.get("tool_choice") {
- result["tool_choice"] = tool_choice.clone();
- }
- } else if let Some(functions) = json.get("functions") {
- // Convert functions to tools format
- warnings.push("functions converted to tools format".to_string());
- let mut tools = Vec::new();
- if let Some(func_array) = functions.as_array() {
- for func in func_array {
- tools.push(json!({
- "type": "function",
- "function": func
- }));
- }
- }
- result["tools"] = json!(tools);
- }
-
- // Warn about unsupported fields
- if json.get("logprobs").is_some() {
- warnings.push("logprobs not supported in Anthropic format".to_string());
- }
- if json.get("n").is_some() && json.get("n") != Some(&json!(1)) {
- warnings.push("n>1 not supported in Anthropic format".to_string());
- }
-
- Ok((result, warnings))
-}
-
-/// Convert OpenAI completions to chat format
-fn completions_to_chat(json: &JsonValue) -> Result<(JsonValue, Vec)> {
- let mut warnings = Vec::new();
- let mut result = json!({});
-
- // Copy model
- if let Some(model) = json.get("model") {
- result["model"] = model.clone();
- }
-
- // Convert prompt to messages
- if let Some(prompt) = json.get("prompt") {
- let content = if let Some(prompt_str) = prompt.as_str() {
- prompt_str.to_string()
- } else if let Some(prompt_array) = prompt.as_array() {
- prompt_array
- .iter()
- .filter_map(|p| p.as_str())
- .collect::>()
- .join("\n")
- } else {
- warnings.push("Complex prompt format not fully supported".to_string());
- "".to_string()
- };
-
- result["messages"] = json!([{
- "role": "user",
- "content": content
- }]);
- }
-
- // Copy common parameters
- for field in &[
- "temperature",
- "max_tokens",
- "top_p",
- "stream",
- "stop",
- "presence_penalty",
- "frequency_penalty",
- ] {
- if let Some(value) = json.get(*field) {
- result[*field] = value.clone();
- }
- }
-
- // Warn about completion-specific fields
- if json.get("suffix").is_some() {
- warnings.push("suffix not supported in chat format".to_string());
- }
- if json.get("echo").is_some() {
- warnings.push("echo not supported in chat format".to_string());
- }
-
- Ok((result, warnings))
-}
-
-/// Convert OpenAI chat response to Anthropic format
-fn openai_chat_response_to_anthropic(json: &JsonValue) -> Result<(JsonValue, Vec)> {
- let mut warnings = Vec::new();
- let mut result = json!({
- "type": "message"
- });
-
- // Copy ID
- if let Some(id) = json.get("id") {
- result["id"] = id.clone();
- }
-
- // Copy model
- if let Some(model) = json.get("model") {
- result["model"] = model.clone();
- }
-
- // Convert choices to content
- if let Some(choices) = json.get("choices").and_then(|c| c.as_array()) {
- if let Some(first_choice) = choices.first() {
- if let Some(message) = first_choice.get("message") {
- let role = message
- .get("role")
- .and_then(|r| r.as_str())
- .unwrap_or("assistant");
- result["role"] = json!(role);
-
- if let Some(content) = message.get("content").and_then(|c| c.as_str()) {
- result["content"] = json!([{
- "type": "text",
- "text": content
- }]);
- }
-
- // Handle tool calls
- if let Some(tool_calls) = message.get("tool_calls") {
- result["tool_calls"] = tool_calls.clone();
- }
- }
-
- // Copy finish reason
- if let Some(finish_reason) = first_choice.get("finish_reason") {
- result["stop_reason"] = match finish_reason.as_str() {
- Some("stop") => json!("end_turn"),
- Some("length") => json!("max_tokens"),
- Some("tool_calls") => json!("tool_use"),
- _ => finish_reason.clone(),
- };
- }
- }
-
- if choices.len() > 1 {
- warnings.push("Multiple choices not supported in Anthropic format".to_string());
- }
- }
-
- // Convert usage
- if let Some(usage) = json.get("usage") {
- result["usage"] = json!({
- "input_tokens": usage.get("prompt_tokens"),
- "output_tokens": usage.get("completion_tokens")
- });
- }
-
- Ok((result, warnings))
-}
-
-/// Convert Anthropic response to OpenAI chat format
-fn anthropic_response_to_openai_chat(json: &JsonValue) -> Result<(JsonValue, Vec)> {
- let warnings = Vec::new();
- let mut result = json!({
- "object": "chat.completion",
- "created": chrono::Utc::now().timestamp()
- });
-
- // Copy ID
- if let Some(id) = json.get("id") {
- result["id"] = id.clone();
- } else {
- result["id"] = json!(format!("chatcmpl-{}", uuid::Uuid::new_v4()));
- }
-
- // Copy model
- if let Some(model) = json.get("model") {
- result["model"] = model.clone();
- }
-
- // Convert content to choices
- let mut message = json!({
- "role": json.get("role").unwrap_or(&json!("assistant"))
- });
-
- if let Some(content) = json.get("content").and_then(|c| c.as_array()) {
- let mut text_parts = Vec::new();
- for block in content {
- if let Some(block_type) = block.get("type").and_then(|t| t.as_str())
- && block_type == "text"
- && let Some(text) = block.get("text").and_then(|t| t.as_str())
- {
- text_parts.push(text.to_string());
- }
- }
- message["content"] = json!(text_parts.join("\n"));
- } else if let Some(content_str) = json.get("content").and_then(|c| c.as_str()) {
- message["content"] = json!(content_str);
- }
-
- // Handle tool use
- if let Some(tool_calls) = json.get("tool_calls") {
- message["tool_calls"] = tool_calls.clone();
- }
-
- // Convert stop reason to finish reason
- let finish_reason = if let Some(stop_reason) = json.get("stop_reason").and_then(|s| s.as_str())
- {
- match stop_reason {
- "end_turn" => "stop",
- "max_tokens" => "length",
- "tool_use" => "tool_calls",
- _ => stop_reason,
- }
- } else {
- "stop"
- };
-
- result["choices"] = json!([{
- "index": 0,
- "message": message,
- "finish_reason": finish_reason
- }]);
-
- // Convert usage
- if let Some(usage) = json.get("usage") {
- result["usage"] = json!({
- "prompt_tokens": usage.get("input_tokens"),
- "completion_tokens": usage.get("output_tokens"),
- "total_tokens": usage.get("input_tokens").and_then(|i| i.as_u64()).unwrap_or(0)
- + usage.get("output_tokens").and_then(|o| o.as_u64()).unwrap_or(0)
- });
- }
-
- Ok((result, warnings))
-}
diff --git a/crates/core/src/router/protocols/mod.rs b/crates/core/src/router/protocols/mod.rs
deleted file mode 100644
index 78df9372..00000000
--- a/crates/core/src/router/protocols/mod.rs
+++ /dev/null
@@ -1,28 +0,0 @@
-//! Protocol conversion and capabilities
-
-mod capabilities;
-mod convert;
-
-pub use crate::router::types::RequestCapabilities;
-pub use capabilities::extract_capabilities;
-pub use convert::{can_convert, conversion_loss, convert_request, convert_response};
-
-use super::types::Protocol;
-use serde::{Deserialize, Serialize};
-use serde_json::Value as JsonValue;
-
-/// Protocol conversion information
-#[derive(Debug, Clone, Serialize, Deserialize)]
-pub struct ProtocolConversion {
- pub from: Protocol,
- pub to: Protocol,
- pub expected_loss: Vec,
-}
-
-/// Extract model from request
-pub fn extract_model(request: &JsonValue) -> Option {
- request
- .get("model")
- .and_then(|v| v.as_str())
- .map(|s| s.to_string())
-}
diff --git a/crates/core/src/router/record.rs b/crates/core/src/router/record.rs
deleted file mode 100644
index 4c4aef5a..00000000
--- a/crates/core/src/router/record.rs
+++ /dev/null
@@ -1,42 +0,0 @@
-//! Recording interfaces for request/response replay
-
-use crate::Result;
-use crate::router::sink::RequestContext;
-use crate::router::types::ResponseChunk;
-use async_trait::async_trait;
-use std::collections::HashMap;
-
-/// A recorded event in a request/response trace
-#[derive(Debug, Clone)]
-pub enum RecordEvent {
- RequestHeaders(HashMap),
- RequestChunk(serde_json::Value),
- RouteSelected { sink_url: String, rationale: String },
- ResponseHeaders(HashMap),
- ResponseChunk(ResponseChunk),
- Error(String),
-}
-
-/// Recorder trait for capturing request/response traces
-#[async_trait]
-pub trait Recorder: Send + Sync {
- async fn begin(&self, ctx: &RequestContext) -> Result; // returns a trace id
- async fn record(&self, trace_id: &str, event: RecordEvent) -> Result<()>;
- async fn end(&self, trace_id: &str) -> Result<()>;
-}
-
-/// A no-op recorder implementation
-pub struct NoopRecorder;
-
-#[async_trait]
-impl Recorder for NoopRecorder {
- async fn begin(&self, _ctx: &RequestContext) -> Result {
- Ok(uuid::Uuid::new_v4().to_string())
- }
- async fn record(&self, _trace_id: &str, _event: RecordEvent) -> Result<()> {
- Ok(())
- }
- async fn end(&self, _trace_id: &str) -> Result<()> {
- Ok(())
- }
-}
diff --git a/crates/core/src/router/registry.rs b/crates/core/src/router/registry.rs
deleted file mode 100644
index a7d6a768..00000000
--- a/crates/core/src/router/registry.rs
+++ /dev/null
@@ -1,42 +0,0 @@
-use super::sink::Sink;
-use std::collections::HashMap;
-use std::sync::Arc;
-
-/// Registry for managing sinks
-pub struct SinkRegistry {
- sinks: Arc>>>,
-}
-
-impl SinkRegistry {
- pub fn new() -> Self {
- Self {
- sinks: Arc::new(tokio::sync::RwLock::new(HashMap::new())),
- }
- }
- pub async fn register(&self, id: String, sink: Arc) {
- let mut sinks = self.sinks.write().await;
- sinks.insert(id, sink);
- }
- pub async fn get(&self, id: &str) -> Option> {
- let sinks = self.sinks.read().await;
- sinks.get(id).cloned()
- }
- pub async fn remove(&self, id: &str) {
- let mut sinks = self.sinks.write().await;
- sinks.remove(id);
- }
- pub async fn list_ids(&self) -> Vec {
- let sinks = self.sinks.read().await;
- sinks.keys().cloned().collect()
- }
- pub async fn get_all(&self) -> Vec> {
- let sinks = self.sinks.read().await;
- sinks.values().cloned().collect()
- }
-}
-
-impl Default for SinkRegistry {
- fn default() -> Self {
- Self::new()
- }
-}
diff --git a/crates/core/src/router/routing.rs b/crates/core/src/router/routing.rs
deleted file mode 100644
index 2e0304a7..00000000
--- a/crates/core/src/router/routing.rs
+++ /dev/null
@@ -1,469 +0,0 @@
-//! Router implementation for intelligent request routing
-
-use super::executor::PlanExecutor;
-use super::index::SinkIndex;
-use super::middleware::Middleware;
-use super::plan::{Route, RoutingPlan};
-use super::registry::SinkRegistry;
-use super::sink::{RequestContext, ResponseStream, Sink, SinkDescription};
-use super::strategy::{RoutingStrategy, ScoredRoute, SimpleStrategy, SinkCandidate};
-use super::types::{Protocol, RequestCapabilities, RequestDescriptor, RequestStream, RetryConfig};
-use super::{SinkHealth, SinkSnapshot};
-use crate::Result;
-use crate::router::SinkCapabilities;
-use crate::router::types::ModelList;
-use crate::state::StateBackend;
-use async_trait::async_trait;
-use chrono::Utc;
-use futures::future::BoxFuture;
-use std::cmp::Ordering;
-use std::collections::HashSet;
-use std::sync::Arc;
-use std::time::Duration;
-
-/// Router - makes routing decisions
-pub struct Router {
- state_backend: Arc,
- sink_registry: Arc,
- strategy: Box,
- middleware: Vec>,
- sink_index: Option>, // Optional fast-path index
-}
-
-impl Router {
- /// Create a new router builder
- pub fn builder() -> RouterBuilder {
- RouterBuilder::new()
- }
-
- /// Route a request to create a plan
- pub async fn route(
- &self,
- ctx: &RequestContext,
- desc: &RequestDescriptor,
- ) -> Result {
- // Resolve aliases for model
- let concrete_models = self.resolve_model(&desc.model).await?;
-
- // Find eligible sinks (no protocol conversion in v2)
- let candidates = self
- .find_eligible_sinks(
- &concrete_models,
- desc.protocol,
- &desc.capabilities,
- desc.context_length_hint,
- self.sink_index.as_deref(),
- )
- .await?;
-
- if candidates.is_empty() {
- return Err(crate::Error::NoSinksAvailable);
- }
-
- // Apply routing strategy
- let scored_routes = self.strategy.evaluate(ctx, desc, candidates).await?;
- if scored_routes.is_empty() {
- return Err(crate::Error::NoSinksAvailable);
- }
-
- // Convert to routes
- let (primary, fallbacks) = self.create_routes(scored_routes)?;
-
- // Create plan
- Ok(RoutingPlan::new(ctx.clone(), primary, fallbacks))
- }
-
- /// Execute a routing plan
- pub async fn execute(
- &self,
- plan: RoutingPlan,
- request: RequestStream,
- ) -> Result {
- debug!("Executing routing plan: {:?}", self.sink_index);
-
- let executor = PlanExecutor::new(self.sink_registry.clone());
-
- // Build middleware pipeline around the executor
- let middlewares = self.middleware.clone();
- let ctx_arc = Arc::new(plan.context.clone());
-
- // Terminal handler
- let terminal = move |req: RequestStream| {
- let executor = executor;
- let plan = plan;
- Box::pin(async move { executor.execute(plan, req).await })
- as BoxFuture<'static, Result>
- };
-
- // Build chain from back to front
- let mut next: super::middleware::Next = Box::new(terminal);
- for mw in middlewares.into_iter().rev() {
- let prev_next = next;
- let ctx_iter = ctx_arc.clone();
- next = Box::new(move |req_stream| {
- let mw = mw.clone();
- Box::pin(async move {
- let mut ctx_clone = (*ctx_iter).clone();
- mw.process(&mut ctx_clone, req_stream, prev_next).await
- })
- });
- }
-
- // Kick off the chain
- next(request).await
- }
- /// Refresh the attached sink index from the current registry. Returns number of refreshed sinks.
- pub async fn refresh_index(&self) -> Result {
- if let Some(index) = &self.sink_index {
- let n = index.refresh_from_registry(&self.sink_registry).await;
- Ok(n)
- } else {
- Ok(0)
- }
- }
-
- /// Resolve model aliases to concrete models
- async fn resolve_model(&self, model: &str) -> Result> {
- // First check if it's an alias
- match self.state_backend.resolve_model_alias(model).await {
- Ok(models) if !models.is_empty() => Ok(models),
- _ => Ok(vec![model.to_string()]), // Use as-is if not an alias
- }
- }
-
- /// Find eligible sinks for the given models and protocol
- async fn find_eligible_sinks(
- &self,
- models: &[String],
- protocol: Protocol,
- req_caps: &RequestCapabilities,
- context_hint: Option,
- index: Option<&SinkIndex>,
- ) -> Result> {
- let mut candidates = Vec::new();
-
- if let Some(index) = index {
- // Use snapshots for hot path
- let snapshots = index.list().await;
- for (
- sink_id,
- SinkSnapshot {
- description,
- health,
- ..
- },
- ) in snapshots
- {
- let Some(sink) = self.sink_registry.get(&sink_id).await else {
- continue;
- };
-
- // Check if sink is healthy
- if !health.healthy {
- continue;
- }
-
- // Check if sink supports any of the models
- let supports_model = models.iter().any(|model| description.supports_model(model));
- if !supports_model {
- continue;
- }
-
- // Check protocol support (no conversion in v2)
- if !description.accepts_protocol(protocol) {
- continue;
- }
-
- // Check capability support
- if req_caps.needs_streaming && !description.capabilities.supports_streaming {
- continue;
- }
-
- if req_caps.needs_tools && !description.capabilities.supports_tools {
- continue;
- }
-
- // Modalities (must include all requested)
- let sink_modalities: HashSet<_> = description
- .capabilities
- .modalities
- .iter()
- .cloned()
- .collect();
-
- let req_modalities: HashSet<_> = req_caps.modalities.iter().cloned().collect();
- if !req_modalities.is_subset(&sink_modalities) {
- continue;
- }
-
- // Context length best-effort check
- if let (Some(max_ctx), Some(input_hint)) =
- (description.capabilities.max_context_length, context_hint)
- {
- let want_out = req_caps.max_tokens.unwrap_or(0) as usize;
- if input_hint + want_out > max_ctx {
- continue;
- }
- }
-
- candidates.push(SinkCandidate {
- sink: sink.clone(),
- description,
- health,
- needs_conversion: None,
- });
- }
- } else {
- // Fallback: query sinks directly (slower)
- let sinks = self.sink_registry.get_all().await;
-
- for sink in sinks {
- let description = sink.describe().await;
- let health = sink.probe().await;
-
- if !health.healthy {
- continue;
- }
-
- let supports_model = models.iter().any(|model| description.supports_model(model));
- if !supports_model {
- continue;
- }
-
- if !description.accepts_protocol(protocol) {
- continue;
- }
-
- if req_caps.needs_streaming && !description.capabilities.supports_streaming {
- continue;
- }
- if req_caps.needs_tools && !description.capabilities.supports_tools {
- continue;
- }
- let sink_modalities: HashSet<_> = description
- .capabilities
- .modalities
- .iter()
- .cloned()
- .collect();
- let req_modalities: HashSet<_> = req_caps.modalities.iter().cloned().collect();
- if !req_modalities.is_subset(&sink_modalities) {
- continue;
- }
- if let (Some(max_ctx), Some(input_hint)) =
- (description.capabilities.max_context_length, context_hint)
- {
- let want_out = req_caps.max_tokens.unwrap_or(0) as usize;
- if input_hint + want_out > max_ctx {
- continue;
- }
- }
-
- candidates.push(SinkCandidate {
- sink: sink.clone(),
- description,
- health,
- needs_conversion: None,
- });
- }
- }
-
- Ok(candidates)
- }
-
- /// Create routes from scored routes
- fn create_routes(&self, mut scored: Vec) -> Result<(Route, Vec)> {
- if scored.is_empty() {
- return Err(crate::Error::NoSinksAvailable);
- }
-
- // Sort by score (highest first)
- scored.sort_by(|a, b| b.score.partial_cmp(&a.score).unwrap_or(Ordering::Equal));
-
- let primary = scored.remove(0);
- let primary_route = Route {
- sink_id: primary.sink_id,
- protocol_conversion: primary.conversion_needed,
- timeout: Duration::from_secs(300),
- retry_config: RetryConfig::default(),
- };
-
- let fallback_routes = scored
- .into_iter()
- .take(2) // Limit fallbacks
- .map(|s| Route {
- sink_id: s.sink_id,
- protocol_conversion: s.conversion_needed,
- timeout: Duration::from_secs(30),
- retry_config: RetryConfig::default(),
- })
- .collect();
-
- Ok((primary_route, fallback_routes))
- }
-}
-
-// Router also implements Sink for composability
-#[async_trait]
-impl Sink for Router {
- async fn describe(&self) -> SinkDescription {
- // Aggregate descriptions from all sinks
- let sinks = self.sink_registry.get_all().await;
- let mut all_protocols = Vec::new();
- let mut all_models = Vec::new();
- let mut supports_streaming = false;
- let mut supports_tools = false;
- let mut max_context = 0usize;
-
- for sink in sinks {
- let desc = sink.describe().await;
- for proto in desc.accepted_protocols {
- if !all_protocols.contains(&proto) {
- all_protocols.push(proto);
- }
- }
- if let ModelList::Static(models) = desc.models {
- for model in models {
- if !all_models.contains(&model) {
- all_models.push(model);
- }
- }
- }
- supports_streaming |= desc.capabilities.supports_streaming;
- supports_tools |= desc.capabilities.supports_tools;
- if let Some(ctx_len) = desc.capabilities.max_context_length {
- max_context = max_context.max(ctx_len);
- }
- }
-
- SinkDescription {
- id: "router".to_string(),
- accepted_protocols: all_protocols,
- models: if all_models.is_empty() {
- ModelList::Dynamic
- } else {
- ModelList::Static(all_models)
- },
- capabilities: SinkCapabilities {
- supports_streaming,
- supports_batching: false,
- supports_tools,
- max_context_length: Some(max_context),
- modalities: vec!["text".to_string()],
- },
- cost_structure: None,
- }
- }
-
- async fn probe(&self) -> SinkHealth {
- // Aggregate health from all sinks
- let sinks = self.sink_registry.get_all().await;
- let mut healthy_count = 0;
- let mut total_count = 0;
-
- for sink in sinks {
- let health = sink.probe().await;
- total_count += 1;
- if health.healthy {
- healthy_count += 1;
- }
- }
-
- SinkHealth {
- healthy: healthy_count > 0,
- latency_ms: None,
- error_rate: if total_count > 0 {
- 1.0 - (healthy_count as f32 / total_count as f32)
- } else {
- 1.0
- },
- last_error: None,
- last_check: Utc::now(),
- }
- }
-
- async fn execute(
- &self,
- _ctx: &RequestContext,
- _request: RequestStream,
- ) -> Result {
- // Router-as-sink execution path requires request peeking to build a descriptor.
- // Not yet implemented in v2 core.
- Err(crate::Error::Internal(
- "Router used as a sink: not implemented".into(),
- ))
- }
-}
-
-/// Builder for Router
-pub struct RouterBuilder {
- state_backend: Option>,
- sink_registry: Option>,
- strategy: Option>,
- middleware: Vec>,
- sink_index: Option>,
-}
-
-impl RouterBuilder {
- /// Create a new router builder
- pub fn new() -> Self {
- Self {
- state_backend: None,
- sink_registry: None,
- strategy: None,
- middleware: Vec::new(),
- sink_index: None,
- }
- }
-
- /// Set the state backend
- pub fn state_backend(mut self, backend: Arc) -> Self {
- self.state_backend = Some(backend);
- self
- }
-
- /// Set the sink registry
- pub fn sink_registry(mut self, registry: Arc) -> Self {
- self.sink_registry = Some(registry);
- self
- }
-
- /// Set the routing strategy
- pub fn strategy(mut self, strategy: Box) -> Self {
- self.strategy = Some(strategy);
- self
- }
-
- /// Add middleware
- pub fn middleware(mut self, middleware: Arc) -> Self {
- self.middleware.push(middleware);
- self
- }
-
- /// Set an optional sink index to use for fast routing
- pub fn sink_index(mut self, index: Arc) -> Self {
- self.sink_index = Some(index);
- self
- }
-
- /// Build the router
- pub fn build(self) -> Router {
- Router {
- state_backend: self.state_backend.expect("state_backend is required"),
- sink_registry: self
- .sink_registry
- .unwrap_or_else(|| Arc::new(SinkRegistry::new())),
- strategy: self
- .strategy
- .unwrap_or_else(|| Box::new(SimpleStrategy::new())),
- middleware: self.middleware,
- sink_index: self.sink_index,
- }
- }
-}
-
-impl Default for RouterBuilder {
- fn default() -> Self {
- Self::new()
- }
-}
diff --git a/crates/core/src/router/service.rs b/crates/core/src/router/service.rs
deleted file mode 100644
index 35324daf..00000000
--- a/crates/core/src/router/service.rs
+++ /dev/null
@@ -1,50 +0,0 @@
-//! Helper service for routing from JSON requests
-
-use crate::Result;
-use crate::router::middleware::ResponseStream as MwResponseStream;
-use crate::router::protocols;
-use crate::router::routing::Router;
-use crate::router::sink::RequestContext;
-use crate::router::types::Protocol;
-use crate::router::types::{RequestDescriptor, RequestStream};
-use serde_json::Value as JsonValue;
-
-/// Build a RequestDescriptor from a single JSON request body for a known protocol
-pub fn descriptor_from_json_with_protocol(
- json: &JsonValue,
- protocol: Protocol,
-) -> Result {
- let model = protocols::extract_model(json).unwrap_or_else(|| "unknown".to_string());
- let capabilities = protocols::extract_capabilities(json, protocol);
-
- // Best-effort context length hint: rough token estimate by chars/4
- let context_length_hint = Some(json.to_string().len() / 4);
-
- Ok(RequestDescriptor {
- model,
- protocol,
- capabilities,
- context_length_hint,
- })
-}
-
-/// Build a one-off RequestStream from a single JSON payload
-pub fn one_shot_stream(protocol: Protocol, json: JsonValue) -> RequestStream {
- RequestStream::new(
- protocol,
- Box::pin(futures::stream::once(async move { Ok(json) })),
- )
-}
-
-/// Route and execute for a single JSON request with a known protocol
-pub async fn route_and_execute_json_with_protocol(
- router: &Router,
- ctx: &RequestContext,
- protocol: Protocol,
- json: JsonValue,
-) -> Result {
- let desc = descriptor_from_json_with_protocol(&json, protocol)?;
- let plan = router.route(ctx, &desc).await?;
- let stream = one_shot_stream(protocol, json);
- router.execute(plan, stream).await
-}
diff --git a/crates/core/src/router/signals.rs b/crates/core/src/router/signals.rs
deleted file mode 100644
index 0ddce80b..00000000
--- a/crates/core/src/router/signals.rs
+++ /dev/null
@@ -1,41 +0,0 @@
-use http::header::{AUTHORIZATION, HeaderName};
-
-/// Return Anthropic API key from headers, if present (either `x-api-key` or `Authorization: Bearer sk-ant-*`).
-pub fn anthropic_key_from(headers: &http::HeaderMap) -> Option<&str> {
- let x_api_key = HeaderName::from_static("x-api-key");
- if let Some(val) = headers.get(&x_api_key).and_then(|v| v.to_str().ok())
- && val.starts_with("sk-ant-")
- {
- return Some(val);
- }
- if let Some(auth) = headers.get(AUTHORIZATION).and_then(|v| v.to_str().ok())
- && let Some(token) = auth.strip_prefix("Bearer ")
- && token.starts_with("sk-ant-")
- {
- return Some(token);
- }
- None
-}
-
-/// Return OpenAI bearer token from headers, if present (`Authorization: Bearer `).
-pub fn openai_bearer_from(headers: &http::HeaderMap) -> Option<&str> {
- if let Some(auth) = headers.get(AUTHORIZATION).and_then(|v| v.to_str().ok())
- && let Some(token) = auth.strip_prefix("Bearer ")
- && !token.is_empty()
- {
- return Some(token);
- }
- None
-}
-
-/// Whether headers contain Anthropic-specific signals (version header or key).
-pub fn has_anthropic_signal(headers: &http::HeaderMap) -> bool {
- let anth_version = HeaderName::from_static("anthropic-version");
- headers.contains_key(&anth_version) || anthropic_key_from(headers).is_some()
-}
-
-/// Whether headers contain OpenAI-specific signals (beta header or Authorization Bearer).
-pub fn has_openai_signal(headers: &http::HeaderMap) -> bool {
- let openai_beta = HeaderName::from_static("openai-beta");
- headers.contains_key(&openai_beta) || openai_bearer_from(headers).is_some()
-}
diff --git a/crates/core/src/router/sink.rs b/crates/core/src/router/sink.rs
deleted file mode 100644
index 3b074c0c..00000000
--- a/crates/core/src/router/sink.rs
+++ /dev/null
@@ -1,106 +0,0 @@
-//! Sink trait and core implementations
-
-use super::types::{
- CostStructure, ModelList, Protocol, ResponseChunk, SinkCapabilities, SinkHealth,
-};
-use crate::{
- Result,
- access::{IdentityContext, SubjectIdentity},
- tracing::CorrelationId,
-};
-use async_trait::async_trait;
-use futures::Stream;
-use http::HeaderMap;
-use serde::{Deserialize, Serialize};
-use std::pin::Pin;
-
-/// Stream of response chunks
-pub type ResponseStream = Pin> + Send>>;
-
-/// Request context for request execution
-#[derive(Debug, Clone)]
-pub struct RequestContext {
- pub identity: SubjectIdentity,
- pub correlation_id: CorrelationId,
- /// Request headers supplied by the caller (not credentials)
- pub headers: HeaderMap,
- /// Raw query string from the incoming HTTP request (without leading '?')
- pub query: Option,
- pub trace_id: Option,
- pub metadata: std::collections::HashMap,
-}
-
-/// Identity context specific to router
-#[derive(Debug, Clone, Default, Serialize, Deserialize)]
-pub struct RouterIdentityContext {
- pub org_id: Option,
- pub user_id: Option,
- pub api_key_hash: Option,
-}
-
-impl IdentityContext for RouterIdentityContext {
- fn to_attributes(&self) -> std::collections::HashMap {
- let mut attrs = std::collections::HashMap::new();
- if let Some(ref org_id) = self.org_id {
- attrs.insert("org_id".to_string(), org_id.clone());
- }
- if let Some(ref user_id) = self.user_id {
- attrs.insert("user_id".to_string(), user_id.clone());
- }
- if let Some(ref api_key_hash) = self.api_key_hash {
- attrs.insert("api_key_hash".to_string(), api_key_hash.clone());
- }
- attrs
- }
-
- fn get(&self, key: &str) -> Option<&str> {
- match key {
- "org_id" => self.org_id.as_deref(),
- "user_id" => self.user_id.as_deref(),
- "api_key_hash" => self.api_key_hash.as_deref(),
- _ => None,
- }
- }
-}
-
-/// Sink trait - anything that can receive and process requests
-#[async_trait]
-pub trait Sink: Send + Sync {
- /// Describe sink capabilities
- async fn describe(&self) -> SinkDescription;
-
- /// Check sink health
- async fn probe(&self) -> SinkHealth;
-
- /// Execute request
- async fn execute(
- &self,
- ctx: &RequestContext,
- request: super::types::RequestStream,
- ) -> Result;
-}
-
-/// Description of a sink's capabilities
-#[derive(Debug, Clone)]
-pub struct SinkDescription {
- pub id: String,
- pub accepted_protocols: Vec,
- pub models: ModelList,
- pub capabilities: SinkCapabilities,
- pub cost_structure: Option,
-}
-
-impl SinkDescription {
- /// Check if this sink supports the given model
- pub fn supports_model(&self, model: &str) -> bool {
- match &self.models {
- ModelList::Static(models) => models.iter().any(|m| m == model),
- ModelList::Dynamic | ModelList::Infinite => true,
- }
- }
-
- /// Check if this sink accepts the given protocol
- pub fn accepts_protocol(&self, protocol: Protocol) -> bool {
- self.accepted_protocols.contains(&protocol)
- }
-}
diff --git a/crates/core/src/router/sinks/mock.rs b/crates/core/src/router/sinks/mock.rs
deleted file mode 100644
index 38496faf..00000000
--- a/crates/core/src/router/sinks/mock.rs
+++ /dev/null
@@ -1,85 +0,0 @@
-//! Mock sink implementations for testing
-
-use crate::Result;
-use crate::router::sink::{RequestContext, Sink, SinkDescription};
-use crate::router::types::RequestStream;
-use crate::router::types::{ModelList, Protocol, ResponseChunk, SinkCapabilities, SinkHealth};
-use async_trait::async_trait;
-use futures::StreamExt;
-use serde_json::json;
-use std::pin::Pin;
-
-pub struct MockSink {
- pub id: String,
- pub accepted_protocols: Vec,
- pub models: ModelList,
- pub capabilities: SinkCapabilities,
- pub healthy: bool,
-}
-
-impl MockSink {
- pub fn success(id: &str) -> Self {
- Self {
- id: id.to_string(),
- accepted_protocols: vec![Protocol::OpenAIChat, Protocol::Anthropic],
- models: ModelList::Dynamic,
- capabilities: SinkCapabilities {
- supports_streaming: true,
- supports_batching: false,
- supports_tools: true,
- max_context_length: Some(128_000),
- modalities: vec!["text".into()],
- },
- healthy: true,
- }
- }
-
- pub fn unhealthy(id: &str) -> Self {
- let mut s = Self::success(id);
- s.healthy = false;
- s
- }
-}
-
-#[async_trait]
-impl Sink for MockSink {
- async fn describe(&self) -> SinkDescription {
- SinkDescription {
- id: self.id.clone(),
- accepted_protocols: self.accepted_protocols.clone(),
- models: self.models.clone(),
- capabilities: self.capabilities.clone(),
- cost_structure: None,
- }
- }
-
- async fn probe(&self) -> SinkHealth {
- SinkHealth {
- healthy: self.healthy,
- latency_ms: Some(50),
- error_rate: if self.healthy { 0.0 } else { 1.0 },
- last_error: None,
- last_check: chrono::Utc::now(),
- }
- }
-
- async fn execute(
- &self,
- _ctx: &RequestContext,
- mut request: RequestStream,
- ) -> Result> + Send>>> {
- // Consume the request and echo a simple response
- let mut messages = Vec::new();
- while let Some(item) = request.next().await {
- let v = item?;
- messages.push(v);
- }
-
- let stream = async_stream::stream! {
- yield Ok(ResponseChunk::Headers(Default::default()));
- yield Ok(ResponseChunk::Content(json!({"ok": true, "echo": messages })));
- yield Ok(ResponseChunk::Stop { reason: crate::router::types::StopReason::Complete, error: None, cost: None });
- };
- Ok(Box::pin(stream))
- }
-}
diff --git a/crates/core/src/router/sinks/mod.rs b/crates/core/src/router/sinks/mod.rs
deleted file mode 100644
index 68109d17..00000000
--- a/crates/core/src/router/sinks/mod.rs
+++ /dev/null
@@ -1,3 +0,0 @@
-//! Sink implementations
-
-pub mod mock;
diff --git a/crates/core/src/router/strategy/best_of_n.rs b/crates/core/src/router/strategy/best_of_n.rs
deleted file mode 100644
index 0a8d22dd..00000000
--- a/crates/core/src/router/strategy/best_of_n.rs
+++ /dev/null
@@ -1,115 +0,0 @@
-//! Best-of-N sampling strategy
-
-use super::{RoutingStrategy, ScoredRoute, SinkCandidate};
-use crate::Result;
-use crate::router::sink::RequestContext;
-use crate::router::types::RequestDescriptor;
-use async_trait::async_trait;
-
-/// Selection method for best-of-N
-#[derive(Debug, Clone)]
-pub enum SelectionMethod {
- /// Return the first complete response
- FirstComplete,
- /// Return the most common response (majority vote)
- MajorityVote,
- /// Return the response with highest confidence
- HighestConfidence,
- /// Use a judge model to select the best
- JudgeModel(String),
-}
-
-/// Best-of-N sampling strategy
-pub struct BestOfNStrategy {
- n: usize,
- selection: SelectionMethod,
-}
-
-impl BestOfNStrategy {
- /// Create a new best-of-N strategy
- pub fn new(n: usize, selection: SelectionMethod) -> Self {
- Self {
- n: n.max(1),
- selection,
- }
- }
-
- /// Create a first-complete strategy
- pub fn first_complete(n: usize) -> Self {
- Self::new(n, SelectionMethod::FirstComplete)
- }
-
- /// Create a majority vote strategy
- pub fn majority_vote(n: usize) -> Self {
- Self::new(n, SelectionMethod::MajorityVote)
- }
-
- /// Create a judge-based strategy
- pub fn with_judge(n: usize, judge_model: String) -> Self {
- Self::new(n, SelectionMethod::JudgeModel(judge_model))
- }
-}
-
-#[async_trait]
-impl RoutingStrategy for BestOfNStrategy {
- async fn evaluate(
- &self,
- _ctx: &RequestContext,
- _request: &RequestDescriptor,
- mut candidates: Vec,
- ) -> Result> {
- // For best-of-N, we want to select N candidates that will all be executed
- // Score them equally high so they're all selected
-
- // Filter to healthy candidates only
- candidates.retain(|c| c.health.healthy);
-
- if candidates.is_empty() {
- return Ok(vec![]);
- }
-
- // Take up to N candidates
- let n_candidates = candidates.len().min(self.n);
- let selected = candidates.into_iter().take(n_candidates);
-
- let mut scored = Vec::new();
- for (i, candidate) in selected.enumerate() {
- // Give all selected candidates the same high score
- // They will all be executed in parallel
- let score = 1.0;
-
- let rationale = match &self.selection {
- SelectionMethod::FirstComplete => {
- format!("Best-of-{}: candidate {} (first-complete)", self.n, i + 1)
- }
- SelectionMethod::MajorityVote => {
- format!("Best-of-{}: candidate {} (majority-vote)", self.n, i + 1)
- }
- SelectionMethod::HighestConfidence => {
- format!(
- "Best-of-{}: candidate {} (highest-confidence)",
- self.n,
- i + 1
- )
- }
- SelectionMethod::JudgeModel(model) => {
- format!("Best-of-{}: candidate {} (judge: {})", self.n, i + 1, model)
- }
- };
-
- scored.push(ScoredRoute {
- sink_id: candidate.description.id.clone(),
- score,
- estimated_cost: None,
- estimated_latency: candidate
- .health
- .latency_ms
- .map(std::time::Duration::from_millis),
- conversion_needed: candidate.needs_conversion.clone(),
- rationale,
- });
- }
-
- Ok(scored)
- }
-}
diff --git a/crates/core/src/router/strategy/cost.rs b/crates/core/src/router/strategy/cost.rs
deleted file mode 100644
index fc3a329f..00000000
--- a/crates/core/src/router/strategy/cost.rs
+++ /dev/null
@@ -1,137 +0,0 @@
-//! Cost-optimized routing strategy
-
-use super::{RoutingStrategy, ScoredRoute, SinkCandidate};
-use crate::Result;
-use crate::router::sink::RequestContext;
-use crate::router::types::RequestDescriptor;
-use async_trait::async_trait;
-use rust_decimal::Decimal;
-
-/// Cost-optimized routing strategy
-pub struct CostOptimizedStrategy {
- budget: Option,
- prefer_cached: bool,
-}
-
-impl CostOptimizedStrategy {
- /// Create a new cost-optimized strategy
- pub fn new() -> Self {
- Self {
- budget: None,
- prefer_cached: true,
- }
- }
-
- /// Create with a budget limit
- pub fn with_budget(budget: Decimal) -> Self {
- Self {
- budget: Some(budget),
- prefer_cached: true,
- }
- }
-
- /// Estimate cost for a request
- fn estimate_cost(
- &self,
- candidate: &SinkCandidate,
- request: &RequestDescriptor,
- ) -> Option {
- let cost_structure = candidate.description.cost_structure.as_ref()?;
- // Estimate tokens (rough): use context_length_hint and max_tokens if available
- let estimated_input_tokens = request.context_length_hint.unwrap_or(0) as u32;
- let max_tokens = request.capabilities.max_tokens.unwrap_or(512);
- let estimated_output_tokens = (max_tokens / 2).max(1);
-
- let input_cost =
- cost_structure.input_cost_per_token * Decimal::from(estimated_input_tokens);
- let output_cost =
- cost_structure.output_cost_per_token * Decimal::from(estimated_output_tokens);
-
- Some(input_cost + output_cost)
- }
-}
-
-impl Default for CostOptimizedStrategy {
- fn default() -> Self {
- Self::new()
- }
-}
-
-#[async_trait]
-impl RoutingStrategy for CostOptimizedStrategy {
- async fn evaluate(
- &self,
- _ctx: &RequestContext,
- request: &RequestDescriptor,
- candidates: Vec,
- ) -> Result> {
- let mut scored = Vec::new();
-
- for candidate in candidates {
- let estimated_cost = self.estimate_cost(&candidate, request);
-
- // Skip if over budget
- if let (Some(budget), Some(cost)) = (self.budget, estimated_cost)
- && cost > budget
- {
- continue;
- }
-
- // Calculate score based on cost (lower cost = higher score)
- let cost_score = if let Some(cost) = estimated_cost {
- // Normalize cost to 0-1 range (assuming max cost of $1)
- let max_cost = Decimal::from(1);
- let normalized = (max_cost - cost.min(max_cost)) / max_cost;
- normalized.to_string().parse::().unwrap_or(0.5)
- } else {
- 0.5 // Neutral score if cost unknown
- };
-
- // Boost score if sink supports caching and we prefer cached
- let cache_boost = if self.prefer_cached
- && candidate
- .description
- .cost_structure
- .as_ref()
- .and_then(|cs| cs.cached_input_cost_per_token)
- .is_some()
- {
- 0.1
- } else {
- 0.0
- };
-
- // Penalize unhealthy sinks
- let health_penalty = if !candidate.health.healthy {
- 0.5
- } else {
- candidate.health.error_rate as f64
- };
-
- let final_score = (cost_score + cache_boost) * (1.0 - health_penalty);
-
- scored.push(ScoredRoute {
- sink_id: candidate.description.id.clone(),
- score: final_score,
- estimated_cost,
- estimated_latency: candidate
- .health
- .latency_ms
- .map(std::time::Duration::from_millis),
- conversion_needed: candidate.needs_conversion.clone(),
- rationale: format!(
- "Cost-optimized: estimated_cost={estimated_cost:?}, score={final_score:.3}"
- ),
- });
- }
-
- // Sort by score (highest first)
- scored.sort_by(|a, b| {
- b.score
- .partial_cmp(&a.score)
- .unwrap_or(std::cmp::Ordering::Equal)
- });
-
- Ok(scored)
- }
-}
diff --git a/crates/core/src/router/strategy/latency.rs b/crates/core/src/router/strategy/latency.rs
deleted file mode 100644
index bed4070c..00000000
--- a/crates/core/src/router/strategy/latency.rs
+++ /dev/null
@@ -1,123 +0,0 @@
-//! Latency-optimized routing strategy
-
-use super::{RoutingStrategy, ScoredRoute, SinkCandidate};
-use crate::Result;
-use crate::router::sink::RequestContext;
-use crate::router::types::RequestDescriptor;
-use async_trait::async_trait;
-use std::time::Duration;
-
-/// Latency-optimized routing strategy
-pub struct LatencyOptimizedStrategy {
- max_latency: Option,
- percentile: f64, // e.g., 0.95 for p95
-}
-
-impl LatencyOptimizedStrategy {
- /// Create a new latency-optimized strategy
- pub fn new() -> Self {
- Self {
- max_latency: None,
- percentile: 0.95,
- }
- }
-
- /// Create with a maximum latency threshold
- pub fn with_max_latency(max_latency: Duration) -> Self {
- Self {
- max_latency: Some(max_latency),
- percentile: 0.95,
- }
- }
-
- /// Set the percentile to optimize for (e.g., 0.99 for p99)
- pub fn with_percentile(mut self, percentile: f64) -> Self {
- self.percentile = percentile.clamp(0.0, 1.0);
- self
- }
-}
-
-impl Default for LatencyOptimizedStrategy {
- fn default() -> Self {
- Self::new()
- }
-}
-
-#[async_trait]
-impl RoutingStrategy for LatencyOptimizedStrategy {
- async fn evaluate(
- &self,
- _ctx: &RequestContext,
- _request: &RequestDescriptor,
- candidates: Vec,
- ) -> Result> {
- let mut scored = Vec::new();
-
- // Find the minimum latency for normalization
- let min_latency = candidates
- .iter()
- .filter_map(|c| c.health.latency_ms)
- .min()
- .unwrap_or(0);
-
- for candidate in candidates {
- let latency_ms = candidate.health.latency_ms.unwrap_or(1000); // Default to 1s if unknown
- let latency = Duration::from_millis(latency_ms);
-
- // Skip if over max latency threshold
- if let Some(max) = self.max_latency
- && latency > max
- {
- continue;
- }
-
- // Calculate latency score (lower latency = higher score)
- let latency_score = if latency_ms > 0 {
- // Normalize to 0-1 range, with exponential decay
- let normalized = (min_latency as f64) / (latency_ms as f64);
- normalized.powf(2.0) // Square to heavily favor lower latencies
- } else {
- 1.0
- };
-
- // Factor in health
- let health_factor = if candidate.health.healthy {
- 1.0 - (candidate.health.error_rate as f64 * 0.5) // Error rate impacts score
- } else {
- 0.1 // Severely penalize unhealthy sinks
- };
-
- // Consider protocol conversion overhead
- let conversion_penalty = if candidate.needs_conversion.is_some() {
- 0.95 // 5% penalty for needing conversion
- } else {
- 1.0
- };
-
- let final_score = latency_score * health_factor * conversion_penalty;
-
- scored.push(ScoredRoute {
- sink_id: candidate.description.id.clone(),
- score: final_score,
- estimated_cost: None,
- estimated_latency: Some(latency),
- conversion_needed: candidate.needs_conversion.clone(),
- rationale: format!(
- "Latency-optimized: {}ms (p{:.0}), score={:.3}",
- latency_ms,
- self.percentile * 100.0,
- final_score
- ),
- });
- }
-
- // Sort by score (highest first)
- scored.sort_by(|a, b| {
- b.score
- .partial_cmp(&a.score)
- .unwrap_or(std::cmp::Ordering::Equal)
- });
-
- Ok(scored)
- }
-}
diff --git a/crates/core/src/router/strategy/mod.rs b/crates/core/src/router/strategy/mod.rs
deleted file mode 100644
index 0cfbf62e..00000000
--- a/crates/core/src/router/strategy/mod.rs
+++ /dev/null
@@ -1,163 +0,0 @@
-//! Routing strategy implementations
-
-mod best_of_n;
-mod cost;
-mod latency;
-mod provider_affinity;
-mod weighted;
-
-pub use best_of_n::{BestOfNStrategy, SelectionMethod};
-pub use cost::CostOptimizedStrategy;
-pub use latency::LatencyOptimizedStrategy;
-pub use provider_affinity::ProviderAffinityStrategy;
-pub use weighted::WeightedStrategy;
-
-use super::protocols::ProtocolConversion;
-use super::sink::{RequestContext, Sink, SinkDescription};
-use super::types::{RequestDescriptor, SinkHealth};
-use crate::Result;
-use async_trait::async_trait;
-use rust_decimal::Decimal;
-use std::sync::Arc;
-use std::time::Duration;
-
-/// Candidate sink for routing
-#[derive(Clone)]
-pub struct SinkCandidate {
- pub sink: Arc,
- pub description: SinkDescription,
- pub health: SinkHealth,
- pub needs_conversion: Option,
-}
-
-/// Scored route after strategy evaluation
-pub struct ScoredRoute {
- pub sink_id: String,
- pub score: f64,
- pub estimated_cost: Option,
- pub estimated_latency: Option,
- pub conversion_needed: Option,
- pub rationale: String,
-}
-
-/// Trait for routing strategies
-#[async_trait]
-pub trait RoutingStrategy: Send + Sync {
- /// Evaluate candidates and return scored routes
- async fn evaluate(
- &self,
- ctx: &RequestContext,
- request: &RequestDescriptor,
- candidates: Vec,
- ) -> Result>;
-}
-
-/// Simple strategy that returns candidates in order
-pub struct SimpleStrategy;
-
-impl SimpleStrategy {
- pub fn new() -> Self {
- Self
- }
-}
-
-#[async_trait]
-impl RoutingStrategy for SimpleStrategy {
- async fn evaluate(
- &self,
- _ctx: &RequestContext,
- _request: &RequestDescriptor,
- candidates: Vec,
- ) -> Result> {
- Ok(candidates
- .into_iter()
- .enumerate()
- .map(|(i, candidate)| ScoredRoute {
- sink_id: candidate.description.id,
- score: 1.0 / (i as f64 + 1.0), // Decreasing scores
- estimated_cost: None,
- estimated_latency: None,
- conversion_needed: candidate.needs_conversion,
- rationale: "Simple ordered routing".to_string(),
- })
- .collect())
- }
-}
-
-impl Default for SimpleStrategy {
- fn default() -> Self {
- Self::new()
- }
-}
-
-/// Composite strategy that combines multiple strategies
-pub struct CompositeStrategy {
- strategies: Vec<(Box, f64)>, // Strategy and weight
-}
-
-impl CompositeStrategy {
- pub fn new(strategies: Vec<(Box, f64)>) -> Self {
- Self { strategies }
- }
-}
-
-#[async_trait]
-impl RoutingStrategy for CompositeStrategy {
- async fn evaluate(
- &self,
- ctx: &RequestContext,
- request: &RequestDescriptor,
- candidates: Vec,
- ) -> Result> {
- if self.strategies.is_empty() {
- return Ok(vec![]);
- }
-
- // Collect scores from all strategies
- let mut all_scores: std::collections::HashMap> =
- std::collections::HashMap::new();
- let mut final_routes: std::collections::HashMap =
- std::collections::HashMap::new();
-
- for (strategy, weight) in &self.strategies {
- let scored = strategy.evaluate(ctx, request, candidates.clone()).await?;
- for route in scored {
- all_scores
- .entry(route.sink_id.clone())
- .or_default()
- .push((route.score, *weight));
-
- // Store the route details (will be overwritten by last strategy)
- final_routes.insert(route.sink_id.clone(), route);
- }
- }
-
- // Calculate weighted average scores
- let mut result = Vec::new();
- for (sink_id, scores) in all_scores {
- let total_weight: f64 = scores.iter().map(|(_, w)| w).sum();
- let weighted_sum: f64 = scores.iter().map(|(s, w)| s * w).sum();
- let final_score = if total_weight > 0.0 {
- weighted_sum / total_weight
- } else {
- 0.0
- };
-
- if let Some(mut route) = final_routes.remove(&sink_id) {
- route.score = final_score;
- route.rationale =
- format!("Composite score from {} strategies", self.strategies.len());
- result.push(route);
- }
- }
-
- // Sort by score (highest first)
- result.sort_by(|a, b| {
- b.score
- .partial_cmp(&a.score)
- .unwrap_or(std::cmp::Ordering::Equal)
- });
-
- Ok(result)
- }
-}
diff --git a/crates/core/src/router/strategy/provider_affinity.rs b/crates/core/src/router/strategy/provider_affinity.rs
deleted file mode 100644
index d0afb0a6..00000000
--- a/crates/core/src/router/strategy/provider_affinity.rs
+++ /dev/null
@@ -1,127 +0,0 @@
-use super::{RoutingStrategy, ScoredRoute, SinkCandidate};
-use crate::Result;
-use crate::router::signals::{has_anthropic_signal, has_openai_signal};
-use crate::router::sink::RequestContext;
-use crate::router::types::{Protocol, RequestDescriptor};
-use async_trait::async_trait;
-use http::header::AUTHORIZATION;
-
-pub struct ProviderAffinityStrategy;
-
-impl Default for ProviderAffinityStrategy {
- fn default() -> Self {
- Self::new()
- }
-}
-
-impl ProviderAffinityStrategy {
- pub fn new() -> Self {
- Self
- }
-
- fn provider_prefix_for_model(model: &str) -> Option<&'static str> {
- let m = model.to_lowercase();
- if m.starts_with("claude") {
- Some("provider://anthropic")
- } else if m.starts_with("gpt-") || m.starts_with("o1-") || m.starts_with("o3-") {
- Some("provider://openai")
- } else {
- None
- }
- }
-
- fn provider_prefix_for_protocol(proto: Protocol) -> Option<&'static str> {
- match proto {
- Protocol::Anthropic => Some("provider://anthropic"),
- Protocol::OpenAIChat
- | Protocol::OpenAIMessages
- | Protocol::OpenAICompletions
- | Protocol::OpenAIResponses => Some("provider://openai"),
- _ => None,
- }
- }
-
- fn provider_prefix_from_headers(headers: &http::HeaderMap) -> Option<&'static str> {
- if has_anthropic_signal(headers) {
- return Some("provider://anthropic");
- }
- if has_openai_signal(headers) {
- return Some("provider://openai");
- }
-
- None
- }
-}
-
-#[async_trait]
-impl RoutingStrategy for ProviderAffinityStrategy {
- async fn evaluate(
- &self,
- _ctx: &RequestContext,
- request: &RequestDescriptor,
- candidates: Vec,
- ) -> Result> {
- // Derive intent from protocol, headers, then model prefix as weak hint
- let protocol_intent = Self::provider_prefix_for_protocol(request.protocol);
- let header_intent = Self::provider_prefix_from_headers(&_ctx.headers);
- let model_hint = Self::provider_prefix_for_model(&request.model);
-
- let mut routes = Vec::with_capacity(candidates.len());
- for (i, c) in candidates.into_iter().enumerate() {
- let mut score = 0.0;
- if let Some(p) = protocol_intent
- && c.description.id.starts_with(p)
- {
- score += 1.0;
- }
- if let Some(h) = header_intent
- && c.description.id.starts_with(h)
- {
- score += 0.6;
- }
- if let Some(m) = model_hint
- && c.description.id.starts_with(m)
- {
- score += 0.3;
- }
- // Prefer Codex backend for OpenAI Responses when using OAuth (non sk- token)
- if request.protocol == Protocol::OpenAIResponses
- && let Some(auth) = _ctx
- .headers
- .get(AUTHORIZATION)
- .and_then(|v| v.to_str().ok())
- && let Some(token) = auth.strip_prefix("Bearer ")
- && !token.starts_with("sk-")
- && c.description.id.starts_with("provider://openai/codex")
- {
- score += 0.5;
- }
- // Slight preference for configured/self sinks when otherwise tied
- if c.description.id.starts_with("self://") {
- score += 0.1;
- }
- // Ensure stable ordering when all signals are absent
- if score == 0.0 {
- score = 1.0 / (i as f64 + 1.0);
- }
-
- routes.push(ScoredRoute {
- sink_id: c.description.id.clone(),
- score,
- estimated_cost: None,
- estimated_latency: None,
- conversion_needed: c.needs_conversion,
- rationale: "Provider affinity".into(),
- });
- }
-
- // Sort by score (highest first)
- routes.sort_by(|a, b| {
- b.score
- .partial_cmp(&a.score)
- .unwrap_or(std::cmp::Ordering::Equal)
- });
-
- Ok(routes)
- }
-}
diff --git a/crates/core/src/router/strategy/weighted.rs b/crates/core/src/router/strategy/weighted.rs
deleted file mode 100644
index 5930c0da..00000000
--- a/crates/core/src/router/strategy/weighted.rs
+++ /dev/null
@@ -1,124 +0,0 @@
-//! Weighted routing strategy
-
-use super::{RoutingStrategy, ScoredRoute, SinkCandidate};
-use crate::Result;
-use crate::router::sink::RequestContext;
-use crate::router::types::RequestDescriptor;
-use async_trait::async_trait;
-use std::collections::HashMap;
-
-/// Weighted routing strategy
-pub struct WeightedStrategy {
- weights: HashMap,
- randomize: bool,
-}
-
-impl WeightedStrategy {
- /// Create a new weighted strategy
- pub fn new(weights: HashMap) -> Self {
- Self {
- weights,
- randomize: true,
- }
- }
-
- /// Create a deterministic weighted strategy (no randomization)
- pub fn deterministic(weights: HashMap) -> Self {
- Self {
- weights,
- randomize: false,
- }
- }
-}
-
-#[async_trait]
-impl RoutingStrategy for WeightedStrategy {
- async fn evaluate(
- &self,
- _ctx: &RequestContext,
- _request: &RequestDescriptor,
- candidates: Vec,
- ) -> Result> {
- let mut scored = Vec::new();
-
- for candidate in candidates {
- let sink_id = &candidate.description.id;
- let base_weight = self.weights.get(sink_id).copied().unwrap_or(1.0);
-
- // Adjust weight based on health
- let health_factor = if candidate.health.healthy {
- 1.0 - candidate.health.error_rate as f64
- } else {
- 0.1 // Severely penalize unhealthy sinks
- };
-
- let score = if self.randomize {
- // Add some randomization for load balancing
- let random_factor = 0.8 + (rand::random::() * 0.4);
- base_weight * health_factor * random_factor
- } else {
- base_weight * health_factor
- };
-
- scored.push(ScoredRoute {
- sink_id: sink_id.clone(),
- score,
- estimated_cost: None,
- estimated_latency: candidate.health.latency_ms.map(Duration::from_millis),
- conversion_needed: candidate.needs_conversion.clone(),
- rationale: format!(
- "Weighted routing: base_weight={base_weight:.2}, health_factor={health_factor:.2}"
- ),
- });
- }
-
- // Sort by score (highest first)
- scored.sort_by(|a, b| {
- b.score
- .partial_cmp(&a.score)
- .unwrap_or(std::cmp::Ordering::Equal)
- });
-
- Ok(scored)
- }
-}
-
-// Helper for random number generation in WASM
-#[cfg(target_arch = "wasm32")]
-mod rand {
- pub fn random() -> T
- where
- T: RandomValue,
- {
- T::random()
- }
-
- pub trait RandomValue {
- fn random() -> Self;
- }
-
- impl RandomValue for f64 {
- fn random() -> Self {
- // Simple pseudo-random for WASM
- let timestamp = js_sys::Date::now();
- ((timestamp as u64 * 1103515245 + 12345) % (1 << 31)) as f64 / (1 << 31) as f64
- }
- }
-}
-
-#[cfg(not(target_arch = "wasm32"))]
-mod rand {
- use rand::{
- Rng,
- distributions::{Distribution, Standard},
- };
-
- pub fn random() -> T
- where
- Standard: Distribution,
- {
- rand::thread_rng().r#gen::()
- }
-}
-
-use std::time::Duration;
diff --git a/crates/core/src/router/tests.rs b/crates/core/src/router/tests.rs
deleted file mode 100644
index 23f932c5..00000000
--- a/crates/core/src/router/tests.rs
+++ /dev/null
@@ -1,445 +0,0 @@
-//! Tests for the router module
-
-use super::*;
-use crate::Result;
-use crate::state::StateBackend;
-use async_trait::async_trait;
-
-// Mock state backend for testing
-struct MockStateBackend;
-
-#[async_trait]
-impl StateBackend for MockStateBackend {
- async fn get_user(&self, _user_id: &str) -> Result> {
- Ok(None)
- }
-
- async fn get_user_by_id(&self, _user_id: &str) -> Result > {
- Ok(None)
- }
-
- async fn create_user(&self, _user: &crate::User) -> Result<()> {
- Ok(())
- }
-
- async fn update_user(&self, _user: &crate::User) -> Result<()> {
- Ok(())
- }
-
- async fn delete_user(&self, _user_id: &str) -> Result<()> {
- Ok(())
- }
-
- async fn list_users(&self) -> Result> {
- Ok(vec![])
- }
-
- async fn get_api_key(&self, _key_hash: &str) -> Result> {
- Ok(None)
- }
-
- async fn create_api_key(&self, _key: &crate::ApiKey, _raw_key: &str) -> Result<()> {
- Ok(())
- }
-
- async fn list_api_keys(&self, _org_id: &str) -> Result> {
- Ok(vec![])
- }
-
- async fn delete_api_key(&self, _key_hash: &str) -> Result<()> {
- Ok(())
- }
-
- async fn record_usage(&self, _usage: &crate::UsageRecord) -> Result<()> {
- Ok(())
- }
-
- async fn get_usage(
- &self,
- _org_id: &str,
- _range: &crate::TimeRange,
- ) -> Result> {
- Ok(vec![])
- }
-
- async fn get_provider(&self, _id: &str) -> Result> {
- Ok(None)
- }
-
- async fn list_providers(&self) -> Result> {
- Ok(vec![])
- }
-
- async fn get_model(&self, _id: &str) -> Result> {
- Ok(None)
- }
-
- async fn list_models(&self) -> Result> {
- Ok(vec![])
- }
-
- async fn get_organization(&self, _id: &str) -> Result> {
- Ok(None)
- }
-
- async fn create_organization(&self, _org: &crate::Organization) -> Result<()> {
- Ok(())
- }
-
- async fn has_permission(
- &self,
- _subject_id: &str,
- _action: &crate::access::Action,
- _object: &crate::access::ObjectIdentity,
- ) -> Result {
- Ok(true)
- }
-
- async fn grant_permission(
- &self,
- _subject_id: &str,
- _action: &crate::access::Action,
- _object: &crate::access::ObjectIdentity,
- ) -> Result<()> {
- Ok(())
- }
-
- async fn remove_permission(
- &self,
- _subject_id: &str,
- _action: &crate::access::Action,
- _object: &crate::access::ObjectIdentity,
- ) -> Result<()> {
- Ok(())
- }
-
- async fn list_user_permissions(
- &self,
- _user_id: &str,
- ) -> Result)>> {
- Ok(vec![])
- }
-}
-
-#[tokio::test]
-async fn test_router_creation() {
- let backend = std::sync::Arc::new(MockStateBackend);
- let registry = std::sync::Arc::new(super::registry::SinkRegistry::new());
-
- let router = routing::Router::builder()
- .state_backend(backend as std::sync::Arc)
- .sink_registry(registry)
- .build();
-
- // Test that router implements Sink
- let _sink: &dyn Sink = &router;
-}
-
-#[test]
-fn test_protocol_conversion() {
- use serde_json::json;
-
- let openai_request = json!({
- "model": "gpt-4",
- "messages": [
- {"role": "system", "content": "You are helpful"},
- {"role": "user", "content": "Hello"}
- ],
- "temperature": 0.7
- });
-
- let (converted, warnings) =
- protocols::convert_request(Protocol::OpenAIChat, Protocol::Anthropic, &openai_request)
- .unwrap();
-
- assert!(converted.get("messages").is_some());
- assert!(converted.get("system").is_some());
- assert_eq!(converted["system"], "You are helpful");
- assert!(warnings.is_empty() || !warnings.is_empty()); // Either case is fine for now
-}
-
-#[tokio::test]
-async fn test_route_and_execute_with_mock_sink() {
- use crate::access::SubjectIdentity;
- use crate::router::index::SinkIndex;
- use crate::router::sink::RouterIdentityContext;
- use crate::router::sinks::mock::MockSink;
- use crate::router::types::{RequestCapabilities, RequestDescriptor};
- use futures::StreamExt;
- use serde_json::json;
-
- // Backend and registry
- let backend = std::sync::Arc::new(MockStateBackend);
- let registry = std::sync::Arc::new(super::registry::SinkRegistry::new());
- registry
- .register(
- "self://mock".to_string(),
- std::sync::Arc::new(MockSink::success("self://mock")),
- )
- .await;
-
- // Prepare sink index snapshot for fast routing
- let index = std::sync::Arc::new(SinkIndex::new());
- let sink = registry.get("self://mock").await.unwrap();
- let desc = sink.describe().await;
- let health = sink.probe().await;
- index
- .set_snapshot("self://mock".to_string(), desc, health)
- .await;
-
- // Router
- let router = routing::Router::builder()
- .state_backend(backend as std::sync::Arc)
- .sink_registry(registry)
- .sink_index(index)
- .build();
-
- // Context and descriptor
- let ctx = sink::RequestContext {
- identity: SubjectIdentity::new(
- "user-1",
- "test",
- RouterIdentityContext {
- org_id: Some("org-1".into()),
- user_id: Some("user-1".into()),
- api_key_hash: None,
- },
- ),
- correlation_id: crate::tracing::CorrelationId::new(),
- headers: Default::default(),
- query: None,
- trace_id: None,
- metadata: Default::default(),
- };
-
- let desc = RequestDescriptor {
- model: "test-model".into(),
- protocol: Protocol::OpenAIChat,
- capabilities: RequestCapabilities {
- needs_tools: false,
- needs_vision: false,
- needs_streaming: false,
- max_tokens: Some(64),
- modalities: vec!["text".into()],
- },
- context_length_hint: Some(100),
- };
-
- // Request stream (single event)
- let request_json = json!({
- "model": "test-model",
- "messages": [{"role":"user","content":"hello"}],
- "stream": false
- });
- let request_stream: types::RequestStream = types::RequestStream::new(
- Protocol::OpenAIChat,
- Box::pin(futures::stream::once(
- async move { Ok(request_json.clone()) },
- )),
- );
-
- // Route and execute
- let plan = router.route(&ctx, &desc).await.expect("route ok");
- let mut response = router
- .execute(plan, request_stream)
- .await
- .expect("execute ok");
-
- // Collect chunks
- let mut chunks = Vec::new();
- while let Some(item) = response.next().await {
- chunks.push(item.expect("chunk ok"));
- }
-
- assert!(matches!(chunks.first(), Some(ResponseChunk::Headers(_))));
- match chunks.get(1) {
- Some(ResponseChunk::Content(v)) => {
- assert_eq!(v["ok"], json!(true));
- assert!(v["echo"].is_array());
- }
- other => panic!("unexpected content chunk: {other:?}"),
- }
- assert!(matches!(
- chunks.last(),
- Some(ResponseChunk::Stop {
- reason: StopReason::Complete,
- ..
- })
- ));
-}
-
-#[tokio::test]
-async fn test_service_route_and_execute_json() {
- use crate::access::SubjectIdentity;
- use crate::router::index::SinkIndex;
- use crate::router::service::route_and_execute_json_with_protocol;
- use crate::router::sink::RouterIdentityContext;
- use crate::router::sinks::mock::MockSink;
- use crate::router::types::Protocol;
- use futures::StreamExt;
- use serde_json::json;
-
- let backend = std::sync::Arc::new(MockStateBackend);
- let registry = std::sync::Arc::new(super::registry::SinkRegistry::new());
- registry
- .register(
- "self://mock".into(),
- std::sync::Arc::new(MockSink::success("self://mock")),
- )
- .await;
-
- let index = std::sync::Arc::new(SinkIndex::new());
- index.refresh_from_registry(®istry).await;
-
- let router = routing::Router::builder()
- .state_backend(backend as std::sync::Arc)
- .sink_registry(registry)
- .sink_index(index)
- .build();
-
- let ctx = sink::RequestContext {
- identity: SubjectIdentity::new(
- "user-1",
- "test",
- RouterIdentityContext {
- org_id: None,
- user_id: None,
- api_key_hash: None,
- },
- ),
- correlation_id: crate::tracing::CorrelationId::new(),
- headers: Default::default(),
- query: None,
- trace_id: None,
- metadata: Default::default(),
- };
-
- let json_req = json!({
- "model": "m",
- "messages": [{"role":"user","content":"hi"}],
- "stream": false
- });
-
- let mut resp =
- route_and_execute_json_with_protocol(&router, &ctx, Protocol::OpenAIChat, json_req)
- .await
- .expect("exec");
- let mut chunks = Vec::new();
- while let Some(item) = resp.next().await {
- chunks.push(item.expect("ok"));
- }
- assert!(matches!(chunks.first(), Some(ResponseChunk::Headers(_))));
- assert!(matches!(chunks.last(), Some(ResponseChunk::Stop { .. })));
-}
-
-#[tokio::test]
-async fn test_sink_index_selects_healthy_candidate() {
- use crate::access::SubjectIdentity;
- use crate::router::index::SinkIndex;
- use crate::router::sink::RouterIdentityContext;
- use crate::router::sinks::mock::MockSink;
- use crate::router::types::{RequestCapabilities, RequestDescriptor};
-
- let backend = std::sync::Arc::new(MockStateBackend);
- let registry = std::sync::Arc::new(super::registry::SinkRegistry::new());
-
- // Two sinks: A healthy, B unhealthy
- let sink_a_id = "self://a";
- let sink_b_id = "self://b";
- registry
- .register(
- sink_a_id.to_string(),
- std::sync::Arc::new(MockSink::success(sink_a_id)),
- )
- .await;
- registry
- .register(
- sink_b_id.to_string(),
- std::sync::Arc::new(MockSink::unhealthy(sink_b_id)),
- )
- .await;
-
- // Build index snapshots
- let index = std::sync::Arc::new(SinkIndex::new());
- // Refresh from registry to populate index for all sinks
- let refreshed = index.refresh_from_registry(®istry).await;
- assert_eq!(refreshed, 2);
-
- // Router with index and deterministic weighted strategy
- use crate::router::strategy::WeightedStrategy;
- let weights = std::collections::HashMap::new();
- let strategy = Box::new(WeightedStrategy::deterministic(weights));
- let router = routing::Router::builder()
- .state_backend(backend as std::sync::Arc)
- .sink_registry(registry)
- .sink_index(index)
- .strategy(strategy)
- .build();
-
- let ctx = sink::RequestContext {
- identity: SubjectIdentity::new(
- "user-1",
- "test",
- RouterIdentityContext {
- org_id: None,
- user_id: None,
- api_key_hash: None,
- },
- ),
- correlation_id: crate::tracing::CorrelationId::new(),
- headers: Default::default(),
- query: None,
- trace_id: None,
- metadata: Default::default(),
- };
-
- let desc = RequestDescriptor {
- model: "test".into(),
- protocol: Protocol::OpenAIChat,
- capabilities: RequestCapabilities {
- needs_tools: false,
- needs_vision: false,
- needs_streaming: false,
- max_tokens: Some(32),
- modalities: vec!["text".into()],
- },
- context_length_hint: Some(64),
- };
-
- let plan = router.route(&ctx, &desc).await.expect("route ok");
- assert_eq!(plan.primary_route.sink_id, sink_a_id);
-}
-
-#[tokio::test]
-async fn test_sink_index_refresher_lists_all_sinks() {
- use crate::router::index::SinkIndex;
- use crate::router::sinks::mock::MockSink;
-
- let registry = std::sync::Arc::new(super::registry::SinkRegistry::new());
- registry
- .register(
- "self://one".into(),
- std::sync::Arc::new(MockSink::success("self://one")),
- )
- .await;
- registry
- .register(
- "self://two".into(),
- std::sync::Arc::new(MockSink::unhealthy("self://two")),
- )
- .await;
-
- let index = SinkIndex::new();
- let n = index.refresh_from_registry(®istry).await;
- assert_eq!(n, 2);
-
- let items = index.list().await;
- assert_eq!(items.len(), 2);
- // Confirm that both sink_ids are present and snapshot health matches probes
- let mut map = std::collections::HashMap::new();
- for (id, snap) in items {
- map.insert(id, snap);
- }
- assert!(map.get("self://one").unwrap().health.healthy);
- assert!(!map.get("self://two").unwrap().health.healthy);
-}
diff --git a/crates/core/src/router/types.rs b/crates/core/src/router/types.rs
deleted file mode 100644
index 2da66d52..00000000
--- a/crates/core/src/router/types.rs
+++ /dev/null
@@ -1,254 +0,0 @@
-//! Core types for the router module
-
-use futures::Stream;
-use rust_decimal::Decimal;
-use serde::{Deserialize, Serialize};
-use serde_json::Value as JsonValue;
-use std::collections::HashMap;
-use std::pin::Pin;
-use std::time::Duration;
-
-/// Protocol identifier for different LLM APIs
-#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
-pub enum Protocol {
- OpenAIMessages, // v1/chat/messages
- OpenAIChat, // v1/chat/completions
- OpenAICompletions, // v1/completions
- OpenAIResponses, // v1/responses
- Anthropic, // v1/messages
- Unknown, // Escape hatch
-}
-
-impl std::fmt::Display for Protocol {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- match self {
- Protocol::OpenAIMessages => write!(f, "OpenAI Messages"),
- Protocol::OpenAIChat => write!(f, "OpenAI Chat"),
- Protocol::OpenAICompletions => write!(f, "OpenAI Completions"),
- Protocol::OpenAIResponses => write!(f, "OpenAI Responses"),
- Protocol::Anthropic => write!(f, "Anthropic"),
- Protocol::Unknown => write!(f, "Unknown"),
- }
- }
-}
-
-/// Sink health information
-#[derive(Debug, Clone, Serialize, Deserialize)]
-pub struct SinkHealth {
- pub healthy: bool,
- pub latency_ms: Option,
- pub error_rate: f32,
- pub last_error: Option,
- pub last_check: chrono::DateTime,
-}
-
-/// Virtual model definition for user-defined routing
-#[derive(Debug, Clone, Serialize, Deserialize)]
-pub struct VirtualModel {
- pub name: String,
- pub version: String,
- pub owner: String,
- pub routing_rules: RoutingRules,
- pub visibility: Visibility,
-}
-
-/// Routing rules for virtual models
-#[derive(Debug, Clone, Serialize, Deserialize)]
-pub struct RoutingRules {
- pub strategy: String,
- pub targets: Vec,
- pub fallback: Option