diff --git a/.claude/scripts/enumerate-endpoints.sh b/.claude/scripts/enumerate-endpoints.sh deleted file mode 100755 index e1b018b..0000000 --- a/.claude/scripts/enumerate-endpoints.sh +++ /dev/null @@ -1,440 +0,0 @@ -#!/usr/bin/env bash -# -# enumerate-endpoints.sh -# -# Enumerates all API endpoints defined in the application by generating -# and parsing the OpenAPI specification. Outputs each endpoint as a pair of -# (HTTP METHOD, Path). -# -# This script builds the project if necessary, generates the OpenAPI document -# using the application's export-openapi command, and extracts endpoint -# information using jq. -# -# Usage: -# ./enumerate-endpoints.sh [OPTIONS] -# -# Options: -# --release Build and use release binary (default: debug) -# --skip-build Skip the cargo build step (assumes binary exists) -# --json Output as JSON array instead of plain text -# --dry-run Print commands without executing them -# --help Show this help message -# -# Output Format (default): -# (GET, /api/v1/workspaces/{workspace_id}/api-keys) -# (POST, /api/v1/workspaces/{workspace_id}/api-keys) -# ... -# -# Output Format (--json): -# [ -# {"method": "GET", "path": "/api/v1/workspaces/{workspace_id}/api-keys"}, -# ... -# ] -# - -set -euo pipefail - -# ============================================================================= -# CONSTANTS -# ============================================================================= - -# Color codes for output formatting. Using these consistently provides a -# unified visual experience and makes it easier to scan output for errors -# (red), warnings (yellow), successes (green), and informational messages (blue). -readonly COLOR_RED='\033[0;31m' -readonly COLOR_GREEN='\033[0;32m' -readonly COLOR_YELLOW='\033[0;33m' -readonly COLOR_BLUE='\033[0;34m' -readonly COLOR_RESET='\033[0m' - -# Script location for relative path resolution -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -readonly SCRIPT_DIR - -# Project root is two levels up from .claude/scripts/ -PROJECT_ROOT="$(cd "${SCRIPT_DIR}/../.." && pwd)" -readonly PROJECT_ROOT - -# ============================================================================= -# GLOBAL STATE -# ============================================================================= - -# These variables are set by parse_arguments() and used throughout the script. -RELEASE_BUILD=false -SKIP_BUILD=false -JSON_OUTPUT=false -DRY_RUN=false - -# ============================================================================= -# LOGGING FUNCTIONS -# -# These functions provide consistent, color-coded output. Each function adds -# a tag prefix ([INFO], [OK], [WARN], [ERROR]) to make it easy to scan logs -# and identify message severity at a glance. -# ============================================================================= - -####################################### -# Prints an informational message in blue. -# Use for general progress updates and status information. -# Arguments: -# $1 - The message to print -####################################### -info() { - local -r message="$1" - echo -e "${COLOR_BLUE}[INFO]${COLOR_RESET} ${message}" >&2 -} - -####################################### -# Prints a success message in green. -# Use when an operation completes successfully. -# Arguments: -# $1 - The message to print -####################################### -success() { - local -r message="$1" - echo -e "${COLOR_GREEN}[OK]${COLOR_RESET} ${message}" >&2 -} - -####################################### -# Prints a warning message in yellow. -# Use for non-fatal issues or important notices that don't stop execution. -# Arguments: -# $1 - The message to print -####################################### -warn() { - local -r message="$1" - echo -e "${COLOR_YELLOW}[WARN]${COLOR_RESET} ${message}" >&2 -} - -####################################### -# Prints an error message in red and exits with code 1. -# Use for fatal errors that prevent the script from continuing. -# The message is sent to stderr so it's visible even when stdout is redirected. -# Arguments: -# $1 - The error message to print -####################################### -error_exit() { - local -r message="$1" - echo -e "${COLOR_RED}[ERROR]${COLOR_RESET} ${message}" >&2 - exit 1 -} - -# ============================================================================= -# COMMAND EXECUTION -# ============================================================================= - -####################################### -# Executes a command, or prints it if in dry-run mode. -# This function checks the global DRY_RUN variable to determine behavior. -# In dry-run mode, the command is printed with a [DRY-RUN] prefix but not -# executed, and the function returns success (0). -# -# Arguments: -# $@ - The command and its arguments to execute -# Returns: -# The exit code of the command (0 in dry-run mode) -####################################### -run_cmd() { - if [[ "${DRY_RUN}" == true ]]; then - echo -e "${COLOR_YELLOW}[DRY-RUN]${COLOR_RESET} $*" >&2 - return 0 - else - "$@" - fi -} - -# ============================================================================= -# HELP AND USAGE -# ============================================================================= - -####################################### -# Prints the help message and exits. -####################################### -show_help() { - cat << 'EOF' -Usage: enumerate-endpoints.sh [OPTIONS] - -Enumerates all API endpoints defined in the application by generating -and parsing the OpenAPI specification. Outputs each endpoint as a pair of -(HTTP METHOD, Path). - -Options: - --release Build and use release binary (default: debug) - --skip-build Skip the cargo build step (assumes binary exists) - --json Output as JSON array instead of plain text - --dry-run Print commands without executing them - --help Show this help message - -Output Format (default): - (GET, /api/v1/workspaces/{workspace_id}/api-keys) - (POST, /api/v1/workspaces/{workspace_id}/api-keys) - ... - -Output Format (--json): - [ - {"method": "GET", "path": "/api/v1/workspaces/{workspace_id}/api-keys"}, - ... - ] - -Examples: - # Enumerate endpoints using debug build - ./enumerate-endpoints.sh - - # Use release build for faster execution - ./enumerate-endpoints.sh --release - - # Skip build if binary already exists - ./enumerate-endpoints.sh --release --skip-build - - # Output as JSON for programmatic use - ./enumerate-endpoints.sh --json - - # See what commands would be run - ./enumerate-endpoints.sh --dry-run -EOF - exit 0 -} - -# ============================================================================= -# ARGUMENT PARSING -# ============================================================================= - -####################################### -# Parses command-line arguments and sets global configuration variables. -# Arguments: -# $@ - All command-line arguments passed to the script -# Globals: -# RELEASE_BUILD - Set to true if --release is provided -# SKIP_BUILD - Set to true if --skip-build is provided -# JSON_OUTPUT - Set to true if --json is provided -# DRY_RUN - Set to true if --dry-run is provided -####################################### -parse_arguments() { - while [[ $# -gt 0 ]]; do - case "$1" in - --release) - RELEASE_BUILD=true - shift - ;; - --skip-build) - SKIP_BUILD=true - shift - ;; - --json) - JSON_OUTPUT=true - shift - ;; - --dry-run) - DRY_RUN=true - shift - ;; - --help|-h) - show_help - ;; - *) - error_exit "Unknown option: $1. Use --help for usage information." - ;; - esac - done -} - -# ============================================================================= -# PREREQUISITE CHECKS -# -# These checks verify that the local environment is properly configured. -# Failures here require manual intervention - the script cannot automatically -# recover from missing tools. -# ============================================================================= - -####################################### -# Verifies that cargo (Rust toolchain) is installed and available in PATH. -# cargo is required for building the application. -####################################### -check_cargo_available() { - info "Checking if cargo is available..." - - if ! command -v cargo &>/dev/null; then - error_exit "cargo is not installed. Please install the Rust toolchain and try again. -See: https://rustup.rs/" - fi - - success "cargo is available" -} - -####################################### -# Verifies that jq is installed and available in PATH. -# jq is required for parsing the OpenAPI JSON output. -####################################### -check_jq_available() { - info "Checking if jq is available..." - - if ! command -v jq &>/dev/null; then - error_exit "jq is not installed. Please install jq and try again. -See: https://jqlang.github.io/jq/download/" - fi - - success "jq is available" -} - -####################################### -# Runs all prerequisite checks. -####################################### -check_prerequisites() { - info "=== Checking Prerequisites ===" - - # Only check cargo if we're going to build - if [[ "${SKIP_BUILD}" == false ]]; then - check_cargo_available - fi - - check_jq_available - success "All prerequisites satisfied" - echo "" >&2 -} - -# ============================================================================= -# BUILD FUNCTIONS -# ============================================================================= - -####################################### -# Builds the application. -# Uses release or debug mode based on the RELEASE_BUILD flag. -####################################### -build_application() { - if [[ "${SKIP_BUILD}" == true ]]; then - info "Skipping build step (--skip-build specified)" - return 0 - fi - - info "=== Building Application ===" - - local build_args=("build" "-p" "__SERVICE_NAME__") - - if [[ "${RELEASE_BUILD}" == true ]]; then - build_args+=("--release") - info "Building in release mode..." - else - info "Building in debug mode..." - fi - - cd "${PROJECT_ROOT}" - run_cmd cargo "${build_args[@]}" - - success "Build completed" - echo "" >&2 -} - -# ============================================================================= -# OPENAPI EXPORT FUNCTIONS -# ============================================================================= - -####################################### -# Gets the path to the binary based on build mode. -# Outputs: -# The path to the binary -####################################### -get_binary_path() { - if [[ "${RELEASE_BUILD}" == true ]]; then - echo "${PROJECT_ROOT}/target/release/__service_name__" - else - echo "${PROJECT_ROOT}/target/debug/__service_name__" - fi -} - -####################################### -# Verifies the binary exists at the expected location. -# Skips verification in dry-run mode since the binary may not exist. -####################################### -verify_binary_exists() { - # Skip verification in dry-run mode - if [[ "${DRY_RUN}" == true ]]; then - return 0 - fi - - local binary_path - binary_path=$(get_binary_path) - - if [[ ! -x "${binary_path}" ]]; then - if [[ "${SKIP_BUILD}" == true ]]; then - error_exit "Binary not found at ${binary_path}. Remove --skip-build to build first." - else - error_exit "Binary not found at ${binary_path} after build. Check for build errors." - fi - fi -} - -####################################### -# Generates the OpenAPI specification and extracts endpoints. -# Outputs the endpoints to stdout in the requested format. -####################################### -export_and_parse_openapi() { - info "=== Exporting OpenAPI Specification ===" - - local binary_path - binary_path=$(get_binary_path) - - verify_binary_exists - - info "Generating OpenAPI document..." - - # In dry-run mode, show the command and output a sample - if [[ "${DRY_RUN}" == true ]]; then - run_cmd "${binary_path}" export-openapi - echo "" >&2 - info "Would parse OpenAPI JSON and extract endpoints" - if [[ "${JSON_OUTPUT}" == true ]]; then - echo '[{"method": "GET", "path": "/example"}]' - else - echo "(GET, /example)" - fi - return 0 - fi - - # Generate OpenAPI spec and parse it - local openapi_json - if ! openapi_json=$("${binary_path}" export-openapi 2>/dev/null); then - error_exit "Failed to generate OpenAPI specification. Ensure the application builds correctly." - fi - - success "OpenAPI document generated" - echo "" >&2 - - info "=== Extracting Endpoints ===" - - # Parse the OpenAPI JSON to extract (method, path) pairs - # The OpenAPI spec has a "paths" object where keys are paths and values - # contain HTTP method objects (get, post, put, delete, etc.) - local endpoints - if ! endpoints=$(echo "${openapi_json}" | jq -r ' - .paths | to_entries[] | .key as $path | - .value | to_entries[] | - select(.key | test("^(get|post|put|patch|delete|head|options|trace)$")) | - {method: .key | ascii_upcase, path: $path} - '); then - error_exit "Failed to parse OpenAPI specification. Ensure the JSON is valid." - fi - - # Output in the requested format - if [[ "${JSON_OUTPUT}" == true ]]; then - echo "${endpoints}" | jq -s '.' - else - echo "${endpoints}" | jq -r '"(\(.method), \(.path))"' - fi - - local count - count=$(echo "${endpoints}" | jq -s 'length') - success "Found ${count} endpoints" >&2 -} - -# ============================================================================= -# MAIN -# ============================================================================= - -main() { - parse_arguments "$@" - check_prerequisites - build_application - export_and_parse_openapi -} - -main "$@" diff --git a/.github/workflows/on-merge.yml b/.github/workflows/on-merge.yml index 9450055..6622c4f 100644 --- a/.github/workflows/on-merge.yml +++ b/.github/workflows/on-merge.yml @@ -1,346 +1,73 @@ -name: "On Merge | Validate Build" +name: "On Merge – Validate" on: - # Use a merge queue to gate the creation and storage - # of these Docker images. + # The merge queue validates each PR against the latest trunk before it lands. + # This fires only when a GitHub merge queue is enabled for the repo; with no + # queue configured it simply never runs. merge_group: - # Allow this job to be executed manually from the GH UI. - workflow_dispatch: + +# No cancel-in-progress here: merge-queue runs must not cancel each other. env: CARGO_TERM_COLOR: always - # Container registry - REGISTRY: ghcr.io - # The name of the Docker image - IMAGE_NAME: "__SERVICE_NAME__" jobs: + # Single required status check. Keep this job's name ("⚡ PR Ready") identical + # to the one in on-push.yml so the same branch-protection check is satisfied + # in both the push and merge-queue contexts. pr-ready: if: always() name: "⚡ PR Ready" - runs-on: ubuntu-22.04 + runs-on: ubuntu-latest needs: - - "format" - - "helm-lint" - - "build" - - "coverage" - - "docker" - - "helm" - - "manifest" + - validate + - cuda-build steps: - - if: ${{ contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled') || contains(needs.*.result, 'skipped') }} + - if: ${{ contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled') || contains(needs.*.result, 'skipped') }} run: | - echo "One or more dependent jobs failed, was skipped, or was cancelled. All jobs must pass for the PR to be ready." + echo "One or more dependent jobs failed, was skipped, or was cancelled. All jobs must pass to merge." exit 1 - run: echo "OK" - format: + validate: + name: fmt · clippy · build · test runs-on: ubuntu-latest - steps: - name: Checkout code uses: actions/checkout@v5 + # Reads the channel + components from rust-toolchain.toml and sets up + # caching for the workspace. - name: Install Rust toolchain uses: actions-rust-lang/setup-rust-toolchain@v1 with: - toolchain: stable - components: rustfmt - - - name: Configure private git dependencies - run: | - git config --global url."https://x-access-token:${{ secrets.CROSS_REPO_PAT }}@github.com/".insteadOf "https://github.com/" - git config --global --add url."https://x-access-token:${{ secrets.CROSS_REPO_PAT }}@github.com/".insteadOf "ssh://git@github.com/" - - - name: Install cargo-make - uses: taiki-e/install-action@v2 - with: - tool: cargo-make + components: rustfmt, clippy - name: Check formatting - run: cargo make check-format + run: cargo fmt --all --check - # Lint Helm chart early to fail fast on chart issues. - # This runs in parallel with format and before the longer build jobs. - helm-lint: - name: Lint Helm Chart - runs-on: ubuntu-latest - - steps: - - name: Checkout repository - uses: actions/checkout@v5 + - name: Clippy (deny warnings) + run: cargo clippy --all-targets --workspace --locked -- -D warnings - - name: Install Helm - uses: azure/setup-helm@v5 - with: - version: v3.14.0 + - name: Build + run: cargo build --workspace --locked - - name: Lint Helm chart - run: helm lint helm/chart + - name: Test + run: cargo test --workspace --locked - # This job installs Cargo Make and Cargo Nextest before running - # the CI workflow using Cargo Make. Most of the time, it should - # restore Cargo Make and other dependencies from cache. - build: - name: Validate Rust Build + # Compile-check the CUDA (CubeCL) backend. cudarc uses dynamic loading, so this + # builds with no GPU, driver, or CUDA toolkit present — it only validates that + # the `#[cfg(feature = "cuda")]` code still compiles. Actually running the CUDA + # backend needs a GPU runner, which is out of scope here. + cuda-build: + name: build (cuda, compile-only) runs-on: ubuntu-latest - steps: - - name: Checkout repository - uses: actions/checkout@v5 - - - name: Setup Rust - uses: "wack/gh-actions/setup-rust@trunk" - with: - shared-key: rust-ci - extra-tools: cargo-nextest - - - name: Configure private git dependencies - run: | - git config --global url."https://x-access-token:${{ secrets.CROSS_REPO_PAT }}@github.com/".insteadOf "https://github.com/" - git config --global --add url."https://x-access-token:${{ secrets.CROSS_REPO_PAT }}@github.com/".insteadOf "ssh://git@github.com/" - - - name: Cargo Make - run: cargo make ci-flow - - # Run the test suite under coverage. Shares the `rust-ci` cache namespace with - # the build job so the warmed cargo cache is reused. - coverage: - name: Coverage - runs-on: ubuntu-latest - - steps: - - name: Checkout repository - uses: actions/checkout@v5 - - - name: Setup Rust - uses: "wack/gh-actions/setup-rust@trunk" - with: - shared-key: rust-ci - extra-tools: cargo-nextest,cargo-llvm-cov - - - name: Configure private git dependencies - run: | - git config --global url."https://x-access-token:${{ secrets.CROSS_REPO_PAT }}@github.com/".insteadOf "https://github.com/" - git config --global --add url."https://x-access-token:${{ secrets.CROSS_REPO_PAT }}@github.com/".insteadOf "ssh://git@github.com/" - - - name: Coverage - run: cargo make coverage-flow - - # Build Docker images for multiple architectures - docker: - name: Build Docker (${{ matrix.arch }}) - runs-on: ${{ matrix.runner }} - needs: - - "build" - permissions: - contents: read - packages: write - - strategy: - fail-fast: false - matrix: - arch: - - amd64 - - arm64 - include: - - arch: amd64 - runner: ubuntu-24.04 - platform: linux/amd64 - - arch: arm64 - runner: ubuntu-24.04-arm - platform: linux/arm64 - - steps: - - name: Checkout repository - uses: actions/checkout@v5 - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v4 - - - name: Log in to Container Registry - uses: docker/login-action@v4 - with: - registry: ${{ env.REGISTRY }} - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} - - - name: Generate image tags - id: tags - run: | - IMAGE="${{ env.REGISTRY }}/${{ github.repository_owner }}/${{ env.IMAGE_NAME }}" - SHA_SHORT=$(echo "${{ github.sha }}" | cut -c1-7) - - # Architecture-specific tag (always set) - echo "arch_tag=${IMAGE}:${SHA_SHORT}-${{ matrix.arch }}" >> $GITHUB_OUTPUT - - # Clean SHA tag (without architecture suffix) for Helm chart reference - echo "sha_tag=${IMAGE}:${SHA_SHORT}" >> $GITHUB_OUTPUT - echo "sha_short=${SHA_SHORT}" >> $GITHUB_OUTPUT - - # For merge queue, use the head SHA for branch tagging - # Sanitize branch name: replace / with - for valid Docker tags - if [[ "${{ github.event_name }}" == "merge_group" ]]; then - BRANCH=$(echo "${{ github.base_ref }}" | sed 's/\//-/g') - elif [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then - BRANCH=$(echo "${{ github.ref_name }}" | sed 's/\//-/g') - fi - - # Only set branch_tag if BRANCH is non-empty - if [[ -n "$BRANCH" ]]; then - echo "branch_tag=${IMAGE}:${BRANCH}-${{ matrix.arch }}" >> $GITHUB_OUTPUT - fi - - - name: Build and push - uses: docker/build-push-action@v7 - with: - context: . - file: Dockerfile - platforms: ${{ matrix.platform }} - push: true - tags: | - ${{ steps.tags.outputs.arch_tag }} - ${{ steps.tags.outputs.branch_tag }} - # Build-time provenance plumbed into OpenTelemetry resource - # attributes by build.rs. Names match the OTel CI/CD + VCS - # semantic conventions. - build-args: | - VCS_REF_HEAD_REVISION=${{ github.sha }} - VCS_REF_HEAD_NAME=${{ github.base_ref || github.ref_name }} - VCS_REF_HEAD_TYPE=branch - VCS_REPOSITORY_URL_FULL=${{ github.server_url }}/${{ github.repository }} - CICD_PIPELINE_NAME=${{ github.workflow }} - CICD_PIPELINE_RUN_URL_FULL=${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} - cache-from: type=gha,scope=${{ env.IMAGE_NAME }}-${{ matrix.arch }} - cache-to: type=gha,mode=max,scope=${{ env.IMAGE_NAME }}-${{ matrix.arch }} - provenance: false - secrets: | - GITHUB_TOKEN=${{ secrets.CROSS_REPO_PAT }} - - # Create multi-arch manifest after all builds complete - manifest: - name: Create manifest - runs-on: ubuntu-latest - needs: docker - permissions: - contents: read - packages: write - - steps: - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v4 - - - name: Log in to Container Registry - uses: docker/login-action@v4 - with: - registry: ${{ env.REGISTRY }} - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} - - - name: Create and push manifest - run: | - IMAGE="${{ env.REGISTRY }}/${{ github.repository_owner }}/${{ env.IMAGE_NAME }}" - SHA_SHORT=$(echo "${{ github.sha }}" | cut -c1-7) - - # Create manifest for SHA tag - docker buildx imagetools create -t "${IMAGE}:${SHA_SHORT}" \ - "${IMAGE}:${SHA_SHORT}-amd64" \ - "${IMAGE}:${SHA_SHORT}-arm64" - - # Determine branch name and sanitize it (replace / with - for valid Docker tags) - if [[ "${{ github.event_name }}" == "merge_group" ]]; then - BRANCH=$(echo "${{ github.base_ref }}" | sed 's/\//-/g') - elif [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then - BRANCH=$(echo "${{ github.ref_name }}" | sed 's/\//-/g') - fi - - # Create manifest for branch tag only if BRANCH is non-empty - if [[ -n "$BRANCH" ]]; then - docker buildx imagetools create -t "${IMAGE}:${BRANCH}" \ - "${IMAGE}:${BRANCH}-amd64" \ - "${IMAGE}:${BRANCH}-arm64" - fi - - # Create 'latest' tag for trunk branch - if [[ "${{ github.base_ref }}" == "trunk" ]] || [[ "${{ github.ref_name }}" == "trunk" ]]; then - docker buildx imagetools create -t "${IMAGE}:latest" \ - "${IMAGE}:${SHA_SHORT}-amd64" \ - "${IMAGE}:${SHA_SHORT}-arm64" - fi - - # Publish Helm chart after Docker images are pushed. - # This job runs after the Docker job completes successfully, ensuring that - # the Docker image exists before we publish a Helm chart that references it. - # The chart's appVersion is dynamically set to match the Docker image tag (commit SHA), - # guaranteeing that `helm install` will pull the correct container image. - helm: - name: Publish Helm Chart - runs-on: ubuntu-latest - needs: docker - permissions: - contents: read # Required to checkout the repository - packages: write # Required to push to GitHub Container Registry - - steps: - # Checkout the repository to access the Helm chart source files. - - name: Checkout repository + - name: Checkout code uses: actions/checkout@v5 - # Install Helm CLI. We pin to a specific version for reproducibility. - - name: Install Helm - uses: azure/setup-helm@v5 - with: - version: v3.14.0 - - # Authenticate to GHCR using the GitHub token. - # This is required for pushing the packaged chart as an OCI artifact. - - name: Log in to Container Registry - uses: docker/login-action@v4 - with: - registry: ${{ env.REGISTRY }} - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} - - # Set the chart version using date and workflow run number for monotonic versioning. - # Format: YYYY.MM.DD- (e.g., 2026.02.04-42) - - name: Set chart version - run: | - VERSION="$(date -u +%Y.%m.%d)-${{ github.run_number }}" - sed -i "s/^version:.*/version: ${VERSION}/" helm/chart/Chart.yaml - echo "Set chart version to: ${VERSION}" - - # Update the chart's appVersion to match the Docker image tag. - # This ensures the Helm chart references the exact Docker image built in this workflow. - # The appVersion (commit SHA) becomes the default image tag when the chart is installed. - - name: Update Chart.yaml appVersion with commit SHA - run: | - SHA_SHORT=$(echo "${{ github.sha }}" | cut -c1-7) - sed -i "s/^appVersion:.*/appVersion: \"${SHA_SHORT}\"/" helm/chart/Chart.yaml - echo "Updated appVersion to: ${SHA_SHORT}" - cat helm/chart/Chart.yaml - - # Extract the chart version from Chart.yaml for use in subsequent steps. - # The chart version is set dynamically using date and run number (YYYY.MM.DD-). - - name: Get chart version - id: chart - run: | - VERSION=$(grep '^version:' helm/chart/Chart.yaml | awk '{print $2}') - echo "version=$VERSION" >> $GITHUB_OUTPUT - echo "Chart version: $VERSION" - - # Validate the Helm chart structure and templates. - # This catches syntax errors and misconfigurations before publishing. - - name: Lint Helm chart - run: helm lint helm/chart - - # Package the chart into a versioned .tgz archive. - # The output filename follows the pattern: -.tgz - - name: Package Helm chart - run: helm package helm/chart + - name: Install Rust toolchain + uses: actions-rust-lang/setup-rust-toolchain@v1 - # Push the packaged chart to GHCR as an OCI artifact. - # The chart will be available at: oci://ghcr.io//charts/__SERVICE_NAME__: - # Users can install with: helm install __SERVICE_NAME__ oci://ghcr.io//charts/__SERVICE_NAME__ --version - - name: Push Helm chart to GHCR - run: | - helm push __SERVICE_NAME__-${{ steps.chart.outputs.version }}.tgz oci://${{ env.REGISTRY }}/${{ github.repository_owner }}/charts + - name: Build (cuda feature) + run: cargo build -p wubbie --no-default-features --features cuda --locked diff --git a/.github/workflows/on-push.yml b/.github/workflows/on-push.yml index 27d9f19..3b9fada 100644 --- a/.github/workflows/on-push.yml +++ b/.github/workflows/on-push.yml @@ -1,17 +1,16 @@ -name: "On Push – Validate Build" +name: "On Push – Validate" on: + # PRs are validated by their branch pushes. The default branch and the merge + # queue's transient refs are excluded — on-merge.yml owns merge-queue runs. push: - # Skip running this on the default branch, since the merge queue - # takes care of validating the commit. branches: - '**' - - '!trunk' # excludes trunk - - '!gh-readonly-queue/**' # on-merge.yml owns merge-queue validation + - '!trunk' + - '!gh-readonly-queue/**' -# Cancel superseded push runs for the same ref. Safe here because this workflow -# only triggers on push (never on the merge queue), so it never cancels -# merge-queue validation owned by on-merge.yml. +# Cancel superseded runs for the same ref. Safe here because this workflow only +# triggers on push, never on the merge queue (which on-merge.yml owns). concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true @@ -20,125 +19,62 @@ env: CARGO_TERM_COLOR: always jobs: - # Do not change this job's name without also changing "pr-ready"'s - # job name in "on-merge.yml". These jobs must have the same name. - # See the README for more details. + # Single required status check. Keep this job's name ("⚡ PR Ready") identical + # to the one in on-merge.yml so the same branch-protection check is satisfied + # in both the push and merge-queue contexts. pr-ready: if: always() name: "⚡ PR Ready" - runs-on: ubuntu-22.04 + runs-on: ubuntu-latest needs: - - "format" - - "clippy" - - "generate-openapi" + - validate + - cuda-build steps: - - if: ${{ contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled') || contains(needs.*.result, 'skipped') }} + - if: ${{ contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled') || contains(needs.*.result, 'skipped') }} run: | echo "One or more dependent jobs failed, was skipped, or was cancelled. All jobs must pass for the PR to be ready." exit 1 - run: echo "OK" - # This job checks that the code is properly formatted using cargo-make. - # Full test suite runs only on merge via on-merge.yml. - format: - name: Check Formatting + validate: + name: fmt · clippy · build · test runs-on: ubuntu-latest - steps: - name: Checkout code uses: actions/checkout@v5 + # Reads the channel + components from rust-toolchain.toml and sets up + # caching for the workspace. - name: Install Rust toolchain uses: actions-rust-lang/setup-rust-toolchain@v1 with: - toolchain: stable - components: rustfmt - - - name: Configure private git dependencies - run: | - git config --global url."https://x-access-token:${{ secrets.CROSS_REPO_PAT }}@github.com/".insteadOf "https://github.com/" - git config --global --add url."https://x-access-token:${{ secrets.CROSS_REPO_PAT }}@github.com/".insteadOf "ssh://git@github.com/" - - - name: Install cargo-make - uses: taiki-e/install-action@v2 - with: - tool: cargo-make + components: rustfmt, clippy - name: Check formatting - run: cargo make check-format - - # Fast workspace-wide clippy feedback on PRs (the merge queue's ci-flow runs - # the same gate). cargo make clippy-flow runs `cargo clippy-strict`. - clippy: - name: Clippy (workspace) - runs-on: ubuntu-latest + run: cargo fmt --all --check - steps: - - name: Checkout code - uses: actions/checkout@v5 + - name: Clippy (deny warnings) + run: cargo clippy --all-targets --workspace --locked -- -D warnings - - name: Install Rust toolchain - uses: actions-rust-lang/setup-rust-toolchain@v1 - with: - toolchain: stable - components: clippy + - name: Build + run: cargo build --workspace --locked - - name: Configure private git dependencies - run: | - git config --global url."https://x-access-token:${{ secrets.CROSS_REPO_PAT }}@github.com/".insteadOf "https://github.com/" - git config --global --add url."https://x-access-token:${{ secrets.CROSS_REPO_PAT }}@github.com/".insteadOf "ssh://git@github.com/" + - name: Test + run: cargo test --workspace --locked - - name: Install cargo-make - uses: taiki-e/install-action@v2 - with: - tool: cargo-make - - - name: Run clippy - run: cargo make clippy-flow - - generate-openapi: - name: OpenAPI Validation + # Compile-check the CUDA (CubeCL) backend. cudarc uses dynamic loading, so this + # builds with no GPU, driver, or CUDA toolkit present — it only validates that + # the `#[cfg(feature = "cuda")]` code still compiles. Actually running the CUDA + # backend needs a GPU runner, which is out of scope here. + cuda-build: + name: build (cuda, compile-only) runs-on: ubuntu-latest - steps: - name: Checkout code uses: actions/checkout@v5 - name: Install Rust toolchain uses: actions-rust-lang/setup-rust-toolchain@v1 - with: - toolchain: stable - - - name: Configure private git dependencies - run: | - git config --global url."https://x-access-token:${{ secrets.CROSS_REPO_PAT }}@github.com/".insteadOf "https://github.com/" - git config --global --add url."https://x-access-token:${{ secrets.CROSS_REPO_PAT }}@github.com/".insteadOf "ssh://git@github.com/" - - - name: Cache Rust dependencies - uses: Swatinem/rust-cache@v2 - - - name: Build the application - run: cargo build --release -p __service_name__ - - name: Generate OpenAPI specification - run: | - ./target/release/__service_name__ export-openapi > openapi.json - - - name: Build client (validates OpenAPI generation) - run: | - echo "Building __SERVICE_NAME__-client to validate generated code..." - cargo build -p __SERVICE_NAME__-client - echo "__SERVICE_NAME__-client built successfully from generated OpenAPI spec" - - - name: Run clippy on client - run: cargo clippy -p __SERVICE_NAME__-client -- -D warnings - - - name: Check formatting of client - run: cargo fmt -p __SERVICE_NAME__-client -- --check - - - name: Upload OpenAPI Documentation - uses: actions/upload-artifact@v7 - with: - name: openapi-documentation - path: openapi.json - retention-days: 90 + - name: Build (cuda feature) + run: cargo build -p wubbie --no-default-features --features cuda --locked diff --git a/.gitignore b/.gitignore index ff84bd0..0728338 100644 --- a/.gitignore +++ b/.gitignore @@ -24,11 +24,3 @@ target # Added by cargo /target - -# Generated OpenAPI specification -# This file is generated by running: cargo make generate-openapi -# It is regenerated during CI and local builds -openapi.json - -# Skip storing cached state. -/.tern/state.json diff --git a/.tern/migrations/00001.json b/.tern/migrations/00001.json deleted file mode 100644 index c87deec..0000000 --- a/.tern/migrations/00001.json +++ /dev/null @@ -1,773 +0,0 @@ -{ - "id": "347e3956c742e19fa8ed8e1b316cdd4fd217655da0f11eb530fa4cd93243ce50", - "description": "Baseline migration from existing database", - "created_at": "2026-01-25T01:05:43.725134Z", - "up_operations": [ - { - "CreateSequence": { - "schema": "public", - "sequence": { - "oid": 16429, - "name": "api_keys_id_seq", - "data_type": { - "name": "int4", - "schema": "pg_catalog", - "formatted": "integer", - "is_array": false - }, - "start_value": 1, - "increment": 1, - "min_value": 1, - "max_value": 2147483647, - "cache_size": 1, - "is_cyclic": false, - "comment": null - } - } - }, - { - "CreateTable": { - "schema": "public", - "table": { - "oid": 16430, - "name": "api_keys", - "kind": "regular", - "columns": [ - { - "name": "id", - "position": 1, - "type_info": { - "name": "int4", - "schema": "pg_catalog", - "formatted": "integer", - "is_array": false - }, - "is_nullable": false, - "default": "nextval('api_keys_id_seq'::regclass)", - "generated": null, - "identity": null, - "collation": { - "schema": "pg_catalog", - "name": "default" - }, - "comment": null - }, - { - "name": "internal_id", - "position": 2, - "type_info": { - "name": "uuid", - "schema": "pg_catalog", - "formatted": "uuid", - "is_array": false - }, - "is_nullable": false, - "default": null, - "generated": null, - "identity": null, - "collation": { - "schema": "pg_catalog", - "name": "default" - }, - "comment": null - }, - { - "name": "workspace_id", - "position": 3, - "type_info": { - "name": "int4", - "schema": "pg_catalog", - "formatted": "integer", - "is_array": false - }, - "is_nullable": false, - "default": null, - "generated": null, - "identity": null, - "collation": { - "schema": "pg_catalog", - "name": "default" - }, - "comment": null - }, - { - "name": "display_name", - "position": 4, - "type_info": { - "name": "text", - "schema": "pg_catalog", - "formatted": "text", - "is_array": false - }, - "is_nullable": false, - "default": null, - "generated": null, - "identity": null, - "collation": { - "schema": "pg_catalog", - "name": "default" - }, - "comment": null - }, - { - "name": "version", - "position": 5, - "type_info": { - "name": "int2", - "schema": "pg_catalog", - "formatted": "smallint", - "is_array": false - }, - "is_nullable": false, - "default": null, - "generated": null, - "identity": null, - "collation": { - "schema": "pg_catalog", - "name": "default" - }, - "comment": null - }, - { - "name": "secret_hash", - "position": 6, - "type_info": { - "name": "bytea", - "schema": "pg_catalog", - "formatted": "bytea", - "is_array": false - }, - "is_nullable": false, - "default": null, - "generated": null, - "identity": null, - "collation": { - "schema": "pg_catalog", - "name": "default" - }, - "comment": null - }, - { - "name": "created_at", - "position": 7, - "type_info": { - "name": "timestamptz", - "schema": "pg_catalog", - "formatted": "timestamp with time zone", - "is_array": false - }, - "is_nullable": false, - "default": "CURRENT_TIMESTAMP", - "generated": null, - "identity": null, - "collation": { - "schema": "pg_catalog", - "name": "default" - }, - "comment": null - }, - { - "name": "updated_at", - "position": 8, - "type_info": { - "name": "timestamptz", - "schema": "pg_catalog", - "formatted": "timestamp with time zone", - "is_array": false - }, - "is_nullable": false, - "default": "CURRENT_TIMESTAMP", - "generated": null, - "identity": null, - "collation": { - "schema": "pg_catalog", - "name": "default" - }, - "comment": null - } - ], - "constraints": [ - { - "name": "api_keys_pkey", - "kind": { - "type": "primary_key", - "columns": [ - "id" - ], - "index_name": "api_keys_pkey" - }, - "comment": null - }, - { - "name": "api_keys_display_name_workspace_id_key", - "kind": { - "type": "unique", - "columns": [ - "display_name", - "workspace_id" - ], - "index_name": "api_keys_display_name_workspace_id_key", - "nulls_not_distinct": false - }, - "comment": null - }, - { - "name": "api_keys_display_name_check", - "kind": { - "type": "check", - "expression": "(char_length(display_name) > 0)", - "is_no_inherit": false - }, - "comment": null - }, - { - "name": "api_keys_secret_hash_check", - "kind": { - "type": "check", - "expression": "(octet_length(secret_hash) = 64)", - "is_no_inherit": false - }, - "comment": null - } - ], - "indexes": [ - { - "oid": 16450, - "name": "api_keys_display_name_workspace_id_key", - "method": "btree", - "is_unique": true, - "is_constraint_index": true, - "columns": [ - { - "column": "display_name", - "expression": "display_name", - "order": "ascending", - "nulls": "last" - }, - { - "column": "workspace_id", - "expression": "workspace_id", - "order": "ascending", - "nulls": "last" - } - ], - "predicate": null, - "comment": null - }, - { - "oid": 16453, - "name": "api_keys_internal_id_unique", - "method": "btree", - "is_unique": true, - "is_constraint_index": false, - "columns": [ - { - "column": "internal_id", - "expression": "internal_id", - "order": "ascending", - "nulls": "last" - } - ], - "predicate": null, - "comment": null - }, - { - "oid": 16452, - "name": "index_api_keys_on_workspace_id", - "method": "btree", - "is_unique": false, - "is_constraint_index": false, - "columns": [ - { - "column": "workspace_id", - "expression": "workspace_id", - "order": "ascending", - "nulls": "last" - } - ], - "predicate": null, - "comment": null - } - ], - "comment": null - } - } - }, - { - "CreateTable": { - "schema": "public", - "table": { - "oid": 16384, - "name": "seaql_migrations", - "kind": "regular", - "columns": [ - { - "name": "version", - "position": 1, - "type_info": { - "name": "varchar", - "schema": "pg_catalog", - "formatted": "character varying", - "is_array": false - }, - "is_nullable": false, - "default": null, - "generated": null, - "identity": null, - "collation": { - "schema": "pg_catalog", - "name": "default" - }, - "comment": null - }, - { - "name": "applied_at", - "position": 2, - "type_info": { - "name": "int8", - "schema": "pg_catalog", - "formatted": "bigint", - "is_array": false - }, - "is_nullable": false, - "default": null, - "generated": null, - "identity": null, - "collation": { - "schema": "pg_catalog", - "name": "default" - }, - "comment": null - } - ], - "constraints": [ - { - "name": "seaql_migrations_pkey", - "kind": { - "type": "primary_key", - "columns": [ - "version" - ], - "index_name": "seaql_migrations_pkey" - }, - "comment": null - } - ], - "indexes": [], - "comment": null - } - } - }, - { - "CreateIndex": { - "schema": "public", - "table": "api_keys", - "index": { - "oid": 16453, - "name": "api_keys_internal_id_unique", - "method": "btree", - "is_unique": true, - "is_constraint_index": false, - "columns": [ - { - "column": "internal_id", - "expression": "internal_id", - "order": "ascending", - "nulls": "last" - } - ], - "predicate": null, - "comment": null - }, - "concurrently": false - } - }, - { - "CreateIndex": { - "schema": "public", - "table": "api_keys", - "index": { - "oid": 16452, - "name": "index_api_keys_on_workspace_id", - "method": "btree", - "is_unique": false, - "is_constraint_index": false, - "columns": [ - { - "column": "workspace_id", - "expression": "workspace_id", - "order": "ascending", - "nulls": "last" - } - ], - "predicate": null, - "comment": null - }, - "concurrently": false - } - }, - { - "SetComment": { - "target": { - "Schema": "public" - }, - "comment": "standard public schema" - } - } - ], - "down_operations": [], - "parent_state_hash": "0000000000000000000000000000000000000000000000000000000000000000", - "resulting_state_hash": "2ced9310ca71d720c46fb6a474fbd12e408f69099eb714422256f0b6682a022c", - "breaking_changes": [], - "checkpoint_state": { - "oid": 2200, - "name": "public", - "tables": [ - { - "oid": 16430, - "name": "api_keys", - "kind": "regular", - "columns": [ - { - "name": "id", - "position": 1, - "type_info": { - "name": "int4", - "schema": "pg_catalog", - "formatted": "integer", - "is_array": false - }, - "is_nullable": false, - "default": "nextval('api_keys_id_seq'::regclass)", - "generated": null, - "identity": null, - "collation": { - "schema": "pg_catalog", - "name": "default" - }, - "comment": null - }, - { - "name": "internal_id", - "position": 2, - "type_info": { - "name": "uuid", - "schema": "pg_catalog", - "formatted": "uuid", - "is_array": false - }, - "is_nullable": false, - "default": null, - "generated": null, - "identity": null, - "collation": { - "schema": "pg_catalog", - "name": "default" - }, - "comment": null - }, - { - "name": "workspace_id", - "position": 3, - "type_info": { - "name": "int4", - "schema": "pg_catalog", - "formatted": "integer", - "is_array": false - }, - "is_nullable": false, - "default": null, - "generated": null, - "identity": null, - "collation": { - "schema": "pg_catalog", - "name": "default" - }, - "comment": null - }, - { - "name": "display_name", - "position": 4, - "type_info": { - "name": "text", - "schema": "pg_catalog", - "formatted": "text", - "is_array": false - }, - "is_nullable": false, - "default": null, - "generated": null, - "identity": null, - "collation": { - "schema": "pg_catalog", - "name": "default" - }, - "comment": null - }, - { - "name": "version", - "position": 5, - "type_info": { - "name": "int2", - "schema": "pg_catalog", - "formatted": "smallint", - "is_array": false - }, - "is_nullable": false, - "default": null, - "generated": null, - "identity": null, - "collation": { - "schema": "pg_catalog", - "name": "default" - }, - "comment": null - }, - { - "name": "secret_hash", - "position": 6, - "type_info": { - "name": "bytea", - "schema": "pg_catalog", - "formatted": "bytea", - "is_array": false - }, - "is_nullable": false, - "default": null, - "generated": null, - "identity": null, - "collation": { - "schema": "pg_catalog", - "name": "default" - }, - "comment": null - }, - { - "name": "created_at", - "position": 7, - "type_info": { - "name": "timestamptz", - "schema": "pg_catalog", - "formatted": "timestamp with time zone", - "is_array": false - }, - "is_nullable": false, - "default": "CURRENT_TIMESTAMP", - "generated": null, - "identity": null, - "collation": { - "schema": "pg_catalog", - "name": "default" - }, - "comment": null - }, - { - "name": "updated_at", - "position": 8, - "type_info": { - "name": "timestamptz", - "schema": "pg_catalog", - "formatted": "timestamp with time zone", - "is_array": false - }, - "is_nullable": false, - "default": "CURRENT_TIMESTAMP", - "generated": null, - "identity": null, - "collation": { - "schema": "pg_catalog", - "name": "default" - }, - "comment": null - } - ], - "constraints": [ - { - "name": "api_keys_pkey", - "kind": { - "type": "primary_key", - "columns": [ - "id" - ], - "index_name": "api_keys_pkey" - }, - "comment": null - }, - { - "name": "api_keys_display_name_workspace_id_key", - "kind": { - "type": "unique", - "columns": [ - "display_name", - "workspace_id" - ], - "index_name": "api_keys_display_name_workspace_id_key", - "nulls_not_distinct": false - }, - "comment": null - }, - { - "name": "api_keys_display_name_check", - "kind": { - "type": "check", - "expression": "(char_length(display_name) > 0)", - "is_no_inherit": false - }, - "comment": null - }, - { - "name": "api_keys_secret_hash_check", - "kind": { - "type": "check", - "expression": "(octet_length(secret_hash) = 64)", - "is_no_inherit": false - }, - "comment": null - } - ], - "indexes": [ - { - "oid": 16450, - "name": "api_keys_display_name_workspace_id_key", - "method": "btree", - "is_unique": true, - "is_constraint_index": true, - "columns": [ - { - "column": "display_name", - "expression": "display_name", - "order": "ascending", - "nulls": "last" - }, - { - "column": "workspace_id", - "expression": "workspace_id", - "order": "ascending", - "nulls": "last" - } - ], - "predicate": null, - "comment": null - }, - { - "oid": 16453, - "name": "api_keys_internal_id_unique", - "method": "btree", - "is_unique": true, - "is_constraint_index": false, - "columns": [ - { - "column": "internal_id", - "expression": "internal_id", - "order": "ascending", - "nulls": "last" - } - ], - "predicate": null, - "comment": null - }, - { - "oid": 16452, - "name": "index_api_keys_on_workspace_id", - "method": "btree", - "is_unique": false, - "is_constraint_index": false, - "columns": [ - { - "column": "workspace_id", - "expression": "workspace_id", - "order": "ascending", - "nulls": "last" - } - ], - "predicate": null, - "comment": null - } - ], - "comment": null - }, - { - "oid": 16384, - "name": "seaql_migrations", - "kind": "regular", - "columns": [ - { - "name": "version", - "position": 1, - "type_info": { - "name": "varchar", - "schema": "pg_catalog", - "formatted": "character varying", - "is_array": false - }, - "is_nullable": false, - "default": null, - "generated": null, - "identity": null, - "collation": { - "schema": "pg_catalog", - "name": "default" - }, - "comment": null - }, - { - "name": "applied_at", - "position": 2, - "type_info": { - "name": "int8", - "schema": "pg_catalog", - "formatted": "bigint", - "is_array": false - }, - "is_nullable": false, - "default": null, - "generated": null, - "identity": null, - "collation": { - "schema": "pg_catalog", - "name": "default" - }, - "comment": null - } - ], - "constraints": [ - { - "name": "seaql_migrations_pkey", - "kind": { - "type": "primary_key", - "columns": [ - "version" - ], - "index_name": "seaql_migrations_pkey" - }, - "comment": null - } - ], - "indexes": [], - "comment": null - } - ], - "views": [], - "sequences": [ - { - "oid": 16429, - "name": "api_keys_id_seq", - "data_type": { - "name": "int4", - "schema": "pg_catalog", - "formatted": "integer", - "is_array": false - }, - "start_value": 1, - "increment": 1, - "min_value": 1, - "max_value": 2147483647, - "cache_size": 1, - "is_cyclic": false, - "comment": null - } - ], - "enums": [], - "comment": "standard public schema" - } -} \ No newline at end of file diff --git a/.tern/migrations/index.json b/.tern/migrations/index.json deleted file mode 100644 index f10bfae..0000000 --- a/.tern/migrations/index.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "migrations": [ - "347e3956c742e19fa8ed8e1b316cdd4fd217655da0f11eb530fa4cd93243ce50" - ] -} \ No newline at end of file diff --git a/CLAUDE.md b/CLAUDE.md index d56bbc2..6ecd301 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1,165 +1,91 @@ # CLAUDE.md -This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. +This file provides guidance to Claude Code (claude.ai/code) when working with code in this +repository. -This repository is a production-ready Rust microservice **template** built on the Salvo web -framework, SeaORM, and PostgreSQL. It follows hexagonal (ports-and-adapters) architecture -with a Sans-I/O core, and ships Docker, Helm, and GitHub Actions CI. New services are created -by running `scripts/init-service.sh`, which substitutes the `__SERVICE_NAME__` (kebab) and -`__service_name__` (snake/crate) placeholders. +`wubbie` is the all-Rust pipeline repository for a fully-open small language model: the model +definition, the training loop, and the inference server live here. Trained weights do **not** +live here — they are published to a separate HuggingFace model repo. + +The stack is all-Rust: [Burn](https://burn.dev/docs/burn/) (CUDA via CubeCL) for the model +and training, the [`tokenizers`](https://github.com/huggingface/tokenizers) crate for the +tokenizer, and [`safetensors`](https://github.com/huggingface/safetensors) for weights. ## Build Commands ```bash -cargo make pg # Start a local PostgreSQL (postgres:18-alpine) in Docker -cargo make migrate # Apply SeaORM migrations (crates/migrations) -cargo run -- server # Run the web server (OpenAPI docs at /scalar) -cargo clippy-strict # Canonical lint gate — == CI and the bacon clippy job -cargo make test # Run the test suite (nextest) -cargo make bacon # Watch tests and rerun on change (bacon nextest) -cargo make monitor # Headless bacon for Claude Code's Monitor tool -cargo make coverage # Test suite under llvm-cov -cargo make generate-openapi # Build the server and write openapi.json -cargo make generate-entities # Generate SeaORM entities from the database -cargo make generate-schema # Dump the post-migration schema to tern/schema.sql -cargo make check-format # Formatting check (CI runs this) +cargo build # build (CPU/ndarray backend) +cargo test --workspace # run the test suite +cargo fmt --all # format +cargo clippy --all-targets --workspace -- -D warnings # lint (the CI gate) +cargo build --release --features cuda # build the CUDA backend (needs CUDA) +cargo run -p wubbie -- # run the CLI ``` -`cargo clippy-strict` is an alias (defined in `.cargo/config.toml`) for `cargo clippy ---all-targets --workspace -- -D warnings` — the single canonical lint surface shared -byte-for-byte by CI, the bacon clippy job, and local runs, so all three agree on pass/fail. -Lint levels live in `[workspace.lints]` (root `Cargo.toml`); `-D warnings` makes any -violation a hard failure. CI runs format, clippy, and OpenAPI generation on PR branches -(`on-push.yml`); the full build, tests, coverage, Docker, and Helm publish run in the merge -queue (`on-merge.yml`). - -## Story / Session Tracking - -This repo tracks tickets, issues, and handovers under `.story/` (storybloq). All -`.story/` changes for a unit of work belong in **the same commit as that work** — do -not split project-tracking state from the code it describes. - -- **Flip ticket status with the work, not after the PR lands.** When you finish a - ticket, set its status to `complete` in the final commit of that session. Do **not** - defer closure to a separate post-merge "Close T-XXX" commit, and do **not** leave a - ticket `inprogress` pending the PR merging. (This supersedes the older land-then-close - practice some prior handovers describe.) -- **Write the session handover before the final commit.** At the end of a session, - take a snapshot, write the handover, flip any ticket statuses, and stage all of it - together — then make the single final commit and open the PR. The handover and status - changes ship inside that commit / PR, not afterward. -- Only `.story/` files git already tracks are committed; `.story/sessions/`, - `.story/snapshots/`, and `.story/status.json` are gitignored (ephemeral local state). - -## Architecture - -Hexagonal (ports and adapters). Requests flow inward through thin adapters; the domain core -has no framework or I/O dependencies. - -| Layer | Directory | Responsibility | -|-------|-----------|----------------| -| Controllers | `src/controllers/` | Thin Salvo HTTP handlers: parse requests, call services, render responses. | -| Services | `src/services/` | Business logic and use cases; coordinate repositories. | -| Repositories | `src/repos/` | Data-access traits (ports) and their SeaORM implementations. | -| Domain | `src/domain/` | Business entities and domain errors. No framework/I/O dependencies. | -| Views | `src/views/` | Serializable HTTP request/response types. | -| Models | `src/models/` | SeaORM entity definitions. | -| Middleware | `src/middleware/` | Salvo middleware (CORS, OTel, metrics, store injection). | - -**Sans-I/O rule:** business logic never performs I/O directly. Every external dependency -(database, HTTP clients, message queues) sits behind an async trait (port). Production code -uses real implementations; tests inject mocks (`src/middleware/mocks.rs`), so integration -tests run fast and deterministically with no real I/O. - -Per-layer conventions are documented in the directory-local CLAUDE.md files: -`src/cli/CLAUDE.md`, `src/controllers/CLAUDE.md`, `src/views/CLAUDE.md`. - -## Adding a New Entity - -1. **Create a migration** in `crates/migrations/src/` (add it to the migrator's list). -2. **Apply it:** `cargo make migrate`. -3. **Generate entities:** `cargo make generate-entities` (writes to `src/models/`). -4. **Domain types** in `src/domain//` — value objects via `nutype`. -5. **Repository trait + impl** in `src/repos//` (port + SeaORM adapter). -6. **Service** in `src/services//` — business logic over the repo trait. -7. **Views** in `src/views//` — request/response types (see `src/views/CLAUDE.md`). -8. **Controller** in `src/controllers//` (see `src/controllers/CLAUDE.md`). -9. **Register routes** in `src/controllers/mod.rs`. - -Each REST resource gets its own directory; nested resources mirror the URL path hierarchy -(e.g. `workspaces/{id}/api-keys` → `controllers/workspaces/api_keys/`). - -## Telemetry - -OpenTelemetry tracing + HTTP metrics. See [OPENTELEMETRY.md](OPENTELEMETRY.md) for the -background reference. The router middleware order (`root()` in `src/controllers/mod.rs`), -outermost → innermost, is: - -1. `OtelHttpMiddleware` — custom OTel HTTP spans (replaces Salvo's `Logger`) -2. CORS — `create_cors_middleware` -3. `Metrics` — Salvo built-in metrics -4. `metrics_middleware` — custom HTTP status-code histogram -5. `transaction_middleware` — database transaction -6. `item_store_middleware` — store injection - -Telemetry is initialized in `src/utils/telemetry.rs`, called from `Server::dispatch` -(`src/cli/server/mod.rs`); the custom middleware lives in `src/middleware/`. - -## Configuration - -Most CLI flags have an environment-variable equivalent (clap `env`). The most common are -`HOST`/`PORT`, the `POSTGRES_*` connection settings, `TLS_CERT`/`TLS_KEY`, `LOG_LEVEL`, -`LOG_FORMAT`, and the `OTEL_*` exporter settings. README.md documents the common `server` -options; run `cargo run -- server --help` for the complete, authoritative list. - -## CI / Infrastructure - -- **`on-push.yml`** (PR branches; excludes `trunk` and `gh-readonly-queue/**`): `format`, - `clippy` (`cargo make clippy-flow`), and `generate-openapi` jobs, gated by `⚡ PR Ready`. - A concurrency block cancels superseded push runs. -- **`on-merge.yml`** (merge queue): `format`, `helm-lint`, `build` (`cargo make ci-flow`), - `coverage`, multi-arch `docker`, `manifest`, and Helm publish — all gated by `⚡ PR Ready`. - `build` and `coverage` share the `rust-ci` cargo cache key. -- **Docker:** multi-stage Alpine build, musl static linking, `distroless/static:nonroot` - runtime (`Dockerfile`). -- **Helm:** chart in `helm/chart/`; CI sets the chart version to `YYYY.MM.DD-` - and `appVersion` to the commit SHA. - -## Agent Guardrails - -- **Clippy ratchet:** `cargo clippy-strict` must stay green. Lint levels live in - `[workspace.lints]`; to adopt a stricter lint, fix the findings it surfaces and land that - as its own small diff — do not add blanket `allow`s without a rationale comment. -- **Sans-I/O:** never perform I/O in services/domain — depend on a trait (port) and inject - the implementation. -- **Resource-per-directory:** one directory per REST resource under - `controllers/`/`services/`/`repos/`/`views/`; nested resources mirror the URL path. -- **Story discipline:** flip ticket status in the same commit as the work; ship `.story/` - changes with the code they describe. - -## Project Structure +If [`cargo-make`](https://github.com/sagiegurari/cargo-make) is installed, `cargo make ci` +reproduces the full CI gate locally (format check → clippy → build → test). `cargo clippy-strict` +(alias in `.cargo/config.toml`) is the canonical lint surface — `clippy --all-targets --workspace +-- -D warnings`, identical to CI. + +## Workspace Layout + +This is a Cargo virtual workspace. All code lives in the single `wubbie` crate today; new crates +are added as members in the root `Cargo.toml`. ``` . -├── src/ -│ ├── bin/main.rs # Binary entry point -│ ├── lib.rs # Library root -│ ├── cli/ # clap subcommands (server, version, export-openapi) + config -│ ├── controllers/ # HTTP handlers (thin adapters) -│ ├── services/ # Business logic layer -│ ├── repos/ # Repository ports + SeaORM implementations -│ ├── domain/ # Business entities and domain errors -│ ├── views/ # HTTP request/response types -│ ├── models/ # SeaORM entities -│ ├── middleware/ # Salvo middleware (cors, otel_http, metrics, stores, mocks) -│ └── utils/ # db.rs (connection), telemetry.rs (OTel), mod.rs -├── crates/ -│ ├── migrations/ # SeaORM migrations (crate name: migration) -│ └── client/ # Generated OpenAPI client (__SERVICE_NAME__-client) -├── helm/chart/ # Helm deployment chart -├── .github/workflows/ # on-push.yml, on-merge.yml -├── Dockerfile # Multi-stage musl/distroless build -├── Makefile.toml # cargo-make task definitions -├── rust-toolchain.toml # Pinned Rust toolchain -└── Cargo.toml # Workspace manifest + [workspace.lints] +├── Cargo.toml # virtual workspace + [workspace.dependencies] (pinned) +└── crates/ + └── wubbie/ # pipeline crate: library + `wubbie` binary + └── src/ + ├── lib.rs # module roots + ├── main.rs # CLI entry point (clap) + ├── backend.rs # compile-time backend selection (ndarray / cuda) + ├── config.rs # ModelConfig + ├── model.rs # model definition + ├── tokenizer.rs# tokenizer loading (tokenizers crate) + ├── training.rs # training loop + ├── inference.rs# inference entry points + └── weights.rs # safetensors (de)serialization ``` + +## Dependency Policy + +The three pipeline-critical crates are **pinned to exact versions** (`=x.y.z`) in +`[workspace.dependencies]`; everything else is locked transitively via `Cargo.lock` (committed). +When bumping `burn`, `tokenizers`, or `safetensors`, update the exact pin and the README version +table together. + +- `burn` `=0.21.0`, `tokenizers` `=0.23.1`, `safetensors` `=0.8.0`. +- Member crates inherit deps with `{ workspace = true }` rather than redeclaring versions. + +## Backends + +Burn is backend-generic; the concrete backend is chosen at compile time in `backend.rs` via +crate features: + +- **`ndarray`** (default) — pure-Rust CPU backend, builds everywhere. This is what CI builds. +- **`cuda`** — NVIDIA CUDA backend via CubeCL. Requires the CUDA toolkit at build time, so it is + intentionally **excluded from the default build and CI**. Code touching the CUDA backend is + `#[cfg(feature = "cuda")]`-gated; it is not compiled by `cargo build`/CI, so verify it builds on + a CUDA host before relying on it. + +Training uses `backend::TrainBackend` (an `Autodiff`-wrapped backend); inference uses +`backend::Backend` directly. + +## CI / Agent Guardrails + +- **CI workflows are named after their trigger event.** `.github/workflows/on-push.yml` runs on + push (PR branches; excludes `trunk` and the merge queue) and `.github/workflows/on-merge.yml` + runs on `merge_group` (the GitHub merge queue, if enabled). Both run the same jobs: `validate` + (`cargo fmt --all --check`, `cargo clippy --all-targets --workspace --locked -- -D warnings`, + `cargo build --workspace --locked`, `cargo test --workspace --locked`) and `cuda-build`, which + compile-checks the `cuda` feature (`cargo build --no-default-features --features cuda`) — `cudarc` + uses dynamic loading so it builds with no GPU/toolkit, but running it needs a GPU host. Both + workflows expose a single gate job named **`⚡ PR Ready`**; keep that name identical across the two + files so one branch-protection check covers both contexts. It must stay green. +- **`--locked`:** CI builds/tests with `--locked`, so keep `Cargo.lock` committed and in sync. +- **Clippy is the ratchet:** the workspace lints (`[workspace.lints]`) deny `unsafe_code` and warn + on `clippy::all`, escalated to a hard failure by `-D warnings`. Fix findings rather than adding + blanket `allow`s. +- **Toolchain** is pinned in `rust-toolchain.toml`. diff --git a/Cargo.lock b/Cargo.lock index 5ebbc0f..867f871 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,60 +2,6 @@ # It is not intended for manual editing. version = 4 -[[package]] -name = "__SERVICE_NAME__-client" -version = "0.1.0" -dependencies = [ - "chrono", - "openapiv3", - "prettyplease", - "progenitor", - "progenitor-client", - "reqwest 0.12.28", - "serde", - "serde_json", - "syn 2.0.114", - "uuid", -] - -[[package]] -name = "__service_name__" -version = "0.1.0" -dependencies = [ - "anyhow", - "async-trait", - "blake3", - "bon", - "chrono", - "clap", - "cucumber", - "data-encoding", - "derive-getters", - "miette", - "mvc-helpers", - "nutype", - "opentelemetry", - "opentelemetry-otlp", - "opentelemetry_sdk", - "pretty_assertions", - "rand 0.9.2", - "salvo 0.88.0", - "sea-orm", - "serde", - "serde_json", - "static_assertions", - "subtle", - "thiserror 2.0.17", - "tokio", - "tracing", - "tracing-subscriber", - "ulid", - "uuid", - "validator", - "vergen-gitcl", - "zeroize", -] - [[package]] name = "addr2line" version = "0.25.1" @@ -71,16 +17,6 @@ version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" -[[package]] -name = "aead" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0" -dependencies = [ - "crypto-common", - "generic-array", -] - [[package]] name = "aes" version = "0.8.4" @@ -92,29 +28,18 @@ dependencies = [ "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", - "aes", - "cipher", - "ctr", - "ghash", - "subtle", -] - [[package]] name = "ahash" -version = "0.7.8" +version = "0.8.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9" +checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" dependencies = [ - "getrandom 0.2.16", + "cfg-if", + "getrandom 0.3.4", "once_cell", + "serde", "version_check", + "zerocopy", ] [[package]] @@ -127,24 +52,21 @@ dependencies = [ ] [[package]] -name = "aliasable" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "250f629c0161ad8107cf89319e990051fae62832fd343083bea452d93e2205fd" - -[[package]] -name = "alloc-no-stdlib" -version = "2.0.4" +name = "aligned" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc7bb162ec39d46ab1ca8c77bf72e890535becd1751bb45f64c597edb4c8c6b3" +checksum = "ee4508988c62edf04abd8d92897fca0c2995d907ce1dfeaf369dac3716a40685" +dependencies = [ + "as-slice", +] [[package]] -name = "alloc-stdlib" -version = "0.2.2" +name = "aligned-vec" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94fb8275041c72129eb51b7d0322c29b8387a0386127718b096429201a5d6ece" +checksum = "dc890384c8602f339876ded803c97ad529f3842aba97f6392b3dba0dd171769b" dependencies = [ - "alloc-no-stdlib", + "equator", ] [[package]] @@ -164,9 +86,9 @@ dependencies = [ [[package]] name = "anstream" -version = "0.6.21" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43d5b281e737544384e969a5ccad3f1cdd24b48086a0fc1b2a5262a26b8f4f4a" +checksum = "824a212faf96e9acacdbd09febd34438f8f711fb84e09a8916013cd7815ca28d" dependencies = [ "anstyle", "anstyle-parse", @@ -179,15 +101,15 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.13" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78" +checksum = "940b3a0ca603d1eade50a4846a2afffd5ef57a9feac2c0e2ec2e14f9ead76000" [[package]] name = "anstyle-parse" -version = "0.2.7" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2" +checksum = "52ce7f38b242319f7cabaa6813055467063ecdc9d355bbb4ce0c68908cd8130e" dependencies = [ "utf8parse", ] @@ -214,101 +136,61 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" - -[[package]] -name = "arrayref" -version = "0.3.9" +version = "1.0.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" +checksum = "2a4385e2e34eb35d6b3efe798b9eb88096925d87726c0798709bf56d9ed84af3" [[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.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56624a96882bb8c26d61312ae18cb45868e5a9992ea73c58e45c3101e56a1e60" -dependencies = [ - "asn1-rs-derive", - "asn1-rs-impl", - "displaydoc", - "nom", - "num-traits", - "rusticata-macros", - "thiserror 2.0.17", - "time", -] - -[[package]] -name = "asn1-rs-derive" -version = "0.6.0" +name = "arbitrary" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3109e49b1e4909e9db6515a30c633684d68cdeaa252f215214cb4fa1a5bfee2c" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.114", - "synstructure", -] +checksum = "c3d036a3c4ab069c7b410a2ce876bd74808d2d0888a82667669f8e783a898bf1" [[package]] -name = "asn1-rs-impl" -version = "0.2.0" +name = "arg_enum_proc_macro" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b18050c2cd6fe86c3a76584ef5e0baf286d038cda203eb6223df2cc413565f7" +checksum = "0ae92a5119aa49cdbcf6b9f893fe4e1d98b04ccbf82ee0584ad948a44a734dea" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn", ] [[package]] -name = "async-stream" -version = "0.3.6" +name = "arrayvec" +version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b5a71a6f37880a80d1d7f19efd781e4b5de42c88f0722cc13bcb6cc2cfe8476" -dependencies = [ - "async-stream-impl", - "futures-core", - "pin-project-lite", -] +checksum = "f02882884d3e1bc524fb12c79f107f6ad0e1cfd498c536ffb494301740995dfe" [[package]] -name = "async-stream-impl" -version = "0.3.6" +name = "as-slice" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" +checksum = "516b6b4f0e40d50dcda9365d53964ec74560ad4284da2e7fc97122cd83174516" dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.114", + "stable_deref_trait", ] [[package]] -name = "async-trait" -version = "0.1.89" +name = "ash" +version = "0.38.0+1.3.281" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" +checksum = "0bb44936d800fea8f016d7f2311c6a4f97aebd5dc86f09906139ec848cf3a46f" dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.114", + "libloading 0.8.9", ] [[package]] -name = "atoi" -version = "2.0.0" +name = "async-channel" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f28d99ec8bfea296261ca1af174f24225171fea9664ba9003cbebee704810528" +checksum = "924ed96dd52d1b75e9c1a3e6275715fd320f5f9439fb5a4a11fa51f4221158d2" dependencies = [ - "num-traits", + "concurrent-queue", + "event-listener-strategy", + "futures-core", + "pin-project-lite", ] [[package]] @@ -317,33 +199,59 @@ version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" +[[package]] +name = "atomic_float" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "628d228f918ac3b82fe590352cc719d30664a0c13ca3a60266fe02c7132d480a" + [[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" -version = "1.15.2" +name = "av-scenechange" +version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a88aab2464f1f25453baa7a07c84c5b7684e274054ba06817f382357f77a288" +checksum = "0f321d77c20e19b92c39e7471cf986812cbb46659d2af674adc4331ef3f18394" dependencies = [ - "aws-lc-sys", - "untrusted 0.7.1", - "zeroize", + "aligned", + "anyhow", + "arg_enum_proc_macro", + "arrayvec", + "log", + "num-rational", + "num-traits", + "pastey", + "rayon", + "thiserror 2.0.18", + "v_frame", + "y4m", ] [[package]] -name = "aws-lc-sys" -version = "0.35.0" +name = "av1-grain" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b45afffdee1e7c9126814751f88dddc747f41d91da16c9551a0f1e8a11e788a1" +checksum = "8cfddb07216410377231960af4fcab838eaa12e013417781b78bd95ee22077f8" dependencies = [ - "cc", - "cmake", - "dunce", - "fs_extra", + "anyhow", + "arrayvec", + "log", + "nom 8.0.0", + "num-rational", + "v_frame", +] + +[[package]] +name = "avif-serialize" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7178fe5f7d460b13895ebb9dcb28a3a6216d2df2574a0806cb51b555d297f38" +dependencies = [ + "arrayvec", ] [[package]] @@ -362,13 +270,10 @@ dependencies = [ ] [[package]] -name = "backtrace-ext" -version = "0.2.1" +name = "base64" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "537beee3be4a18fb023b570f80e3ae28003db9167a751266b259926e25539d50" -dependencies = [ - "backtrace", -] +checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" [[package]] name = "base64" @@ -378,57 +283,77 @@ checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" [[package]] name = "base64ct" -version = "1.8.2" +version = "1.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d809780667f4410e7c41b07f52439b94d2bdf8528eeedc287fa38d3b7f95d82" +checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06" [[package]] -name = "bigdecimal" -version = "0.4.10" +name = "bincode" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d6867f1565b3aad85681f1015055b087fcfd840d6aeee6eee7f2da317603695" +checksum = "36eaf5d7b090263e8150820482d5d93cd964a81e4019913c972f4edcc6edb740" dependencies = [ - "autocfg", - "libm", - "num-bigint", - "num-integer", - "num-traits", "serde", + "unty", ] [[package]] -name = "bitflags" -version = "2.10.0" +name = "bindgen" +version = "0.71.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" +checksum = "5f58bf3d7db68cfbac37cfc485a8d711e87e064c3d0fe0435b92f7a407f9d6b3" dependencies = [ - "serde_core", + "bitflags", + "cexpr", + "clang-sys", + "itertools 0.13.0", + "log", + "prettyplease", + "proc-macro2", + "quote", + "regex", + "rustc-hash 2.1.2", + "shlex 1.3.0", + "syn", ] [[package]] -name = "bitvec" -version = "1.0.1" +name = "bit-set" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" +checksum = "34ddef2995421ab6a5c779542c81ee77c115206f4ad9d5a8e05f4ff49716a3dd" dependencies = [ - "funty", - "radium", - "tap", - "wyz", + "bit-vec", ] [[package]] -name = "blake3" -version = "1.8.3" +name = "bit-vec" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b71798fca2c1fe1086445a7258a4bc81e6e49dcd24c8d0dd9a1e57395b603f51" + +[[package]] +name = "bit_field" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e4b40c7323adcfc0a41c4b88143ed58346ff65a288fc144329c5c45e05d70c6" + +[[package]] +name = "bitflags" +version = "2.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2468ef7d57b3fb7e16b576e8377cdbde2320c60e1491e961d11da40fc4f02a2d" +checksum = "b4388bee8683e3d04af747c73422af53102d2bd24d9eadb6cbc100baef4b43f8" dependencies = [ - "arrayref", - "arrayvec", - "cc", - "cfg-if", - "constant_time_eq", - "cpufeatures 0.2.17", + "serde_core", +] + +[[package]] +name = "bitstream-io" +version = "4.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7eff00be299a18769011411c9def0d827e8f2d7bf0c3dbf53633147a8867fd1f" +dependencies = [ + "no_std_io2", ] [[package]] @@ -440,11 +365,20 @@ dependencies = [ "generic-array", ] +[[package]] +name = "block2" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdeb9d870516001442e364c5220d3574d2da8dc765554b4a617230d33fa58ef5" +dependencies = [ + "objc2", +] + [[package]] name = "bon" -version = "3.8.1" +version = "3.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebeb9aaf9329dff6ceb65c689ca3db33dbf15f324909c60e4e5eef5701ce31b1" +checksum = "a602c73c7b0148ec6d12af6fd5cc7a46e2eacc8878271a999abac56eed12f561" dependencies = [ "bon-macros", "rustversion", @@ -452,4046 +386,4373 @@ dependencies = [ [[package]] name = "bon-macros" -version = "3.8.1" +version = "3.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77e9d642a7e3a318e37c2c9427b5a6a48aa1ad55dcd986f3034ab2239045a645" +checksum = "6dee98b0db6a962de883bf5d20362dee4d7ca0d12fe39a7c6c73c844e1cd7c1f" dependencies = [ - "darling 0.21.3", + "darling 0.23.0", "ident_case", "prettyplease", "proc-macro2", "quote", "rustversion", - "syn 2.0.114", + "syn", ] [[package]] -name = "borsh" -version = "1.6.0" +name = "built" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1da5ab77c1437701eeff7c88d968729e7766172279eab0676857b3d63af7a6f" -dependencies = [ - "borsh-derive", - "cfg_aliases", -] +checksum = "5c0e531d93d39c34eef561e929e8a7f86d77a5af08aac4f6d6e39976c51858e9" + +[[package]] +name = "bumpalo" +version = "3.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649" [[package]] -name = "borsh-derive" -version = "1.6.0" +name = "burn" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0686c856aa6aac0c4498f936d7d6a02df690f614c03e4d906d1018062b5c5e2c" +checksum = "39474be398d30e08681f1f6a8ff446b1e4f1403b5cf7749649a8871fd5945f3a" dependencies = [ - "once_cell", - "proc-macro-crate", - "proc-macro2", - "quote", - "syn 2.0.114", + "burn-autodiff", + "burn-candle", + "burn-core", + "burn-cpu", + "burn-cuda", + "burn-dispatch", + "burn-flex", + "burn-ir", + "burn-ndarray", + "burn-nn", + "burn-optim", + "burn-rocm", + "burn-router", + "burn-std", + "burn-store", + "burn-tch", + "burn-train", + "burn-vision", + "burn-wgpu", ] [[package]] -name = "brotli" -version = "8.0.2" +name = "burn-autodiff" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bd8b9603c7aa97359dbd97ecf258968c95f3adddd6db2f7e7a5bef101c84560" +checksum = "3b93a80e43bfab909399444b29ce3894ff51f7e879720bfc75b6007ae6a01c3d" dependencies = [ - "alloc-no-stdlib", - "alloc-stdlib", - "brotli-decompressor", + "burn-backend", + "burn-std", + "derive-new", + "hashbrown 0.16.1", + "log", + "num-traits", + "parking_lot", + "portable-atomic", + "spin", ] [[package]] -name = "brotli-decompressor" -version = "5.0.0" +name = "burn-backend" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "874bb8112abecc98cbd6d81ea4fa7e94fb9449648c93cc89aa40c81c24d7de03" +checksum = "64491519ac0867f550fa9c726cd443e5db94608c629050986cf2614c8c5ad39f" dependencies = [ - "alloc-no-stdlib", - "alloc-stdlib", + "burn-std", + "bytemuck", + "cubecl", + "derive-new", + "enumset", + "hashbrown 0.16.1", + "num-traits", + "portable-atomic-util", + "rand 0.10.1", + "rand_distr 0.6.0", + "serde", + "spin", + "thiserror 2.0.18", ] [[package]] -name = "bstr" -version = "1.12.3" +name = "burn-candle" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cee35f73844aa3014bb606320a6c1f010249dbdf43342fe54b5a4f6a8ed4b79" +checksum = "917fbbe1238d80ec1483c2c360ed9fa0146fdf57b2e66015c0824ccf5155276c" dependencies = [ - "memchr", - "serde_core", + "burn-backend", + "burn-std", + "candle-core", + "derive-new", ] [[package]] -name = "bumpalo" -version = "3.19.1" +name = "burn-core" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dd9dc738b7a8311c7ade152424974d8115f2cdad61e8dab8dac9f2362298510" +checksum = "5bde1e3b8e7e39b0aa71cd5905207ceea5c3478bec47bdb64acf72dcd0d6f978" +dependencies = [ + "ahash", + "bincode", + "burn-dataset", + "burn-derive", + "burn-std", + "burn-tensor", + "data-encoding", + "derive-new", + "flate2", + "half", + "hashbrown 0.16.1", + "log", + "num-traits", + "portable-atomic", + "portable-atomic-util", + "rand 0.10.1", + "regex", + "rmp-serde", + "serde", + "serde_json", + "spin", + "uuid", +] [[package]] -name = "bytecheck" -version = "0.6.12" +name = "burn-cpu" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23cdc57ce23ac53c931e88a43d06d070a6fd142f2617be5855eb75efc9beb1c2" +checksum = "681478c5438ab6c753a55b85f5b42e5bd4c1f69a8564f2afa2f698ac396ba556" dependencies = [ - "bytecheck_derive", - "ptr_meta", - "simdutf8", + "burn-backend", + "burn-cubecl", + "burn-fusion", + "cubecl", ] [[package]] -name = "bytecheck_derive" -version = "0.6.12" +name = "burn-cubecl" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3db406d29fbcd95542e92559bed4d8ad92636d1ca8b3b72ede10b4bcc010e659" +checksum = "26efbec96ca3f691593c966fa90f98ef8a72867f62627904920b619ba3a9e6b6" dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", + "burn-backend", + "burn-cubecl-fusion", + "burn-fusion", + "burn-ir", + "burn-std", + "cubecl", + "cubek", + "derive-new", + "futures-lite", + "log", + "serde", + "text_placeholder", ] [[package]] -name = "bytecount" -version = "0.6.9" +name = "burn-cubecl-fusion" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "175812e0be2bccb6abe50bb8d566126198344f707e304f45c648fd8f2cc0365e" +checksum = "6993d15b8ed588f55626e835ca768c1c3c7aa7a79d59beff4c987c40fc82d1f4" +dependencies = [ + "burn-backend", + "burn-fusion", + "burn-ir", + "burn-std", + "cubecl", + "cubek", + "derive-new", + "hashbrown 0.16.1", + "serde", + "spin", +] [[package]] -name = "byteorder" -version = "1.5.0" +name = "burn-cuda" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" +checksum = "a6c66b49136fc11f59773054358f401fbec7fa0d69615f55ef22c29cf241c9b7" +dependencies = [ + "burn-backend", + "burn-cubecl", + "burn-fusion", + "cubecl", +] [[package]] -name = "bytes" -version = "1.11.0" +name = "burn-dataset" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b35204fbdc0b3f4446b89fc1ac2cf84a8a68971995d0bf2e925ec7cd960f9cb3" +checksum = "ba469fba38357c8bb65458873ddfd82aa97534aec0b3bae93d4c44604fc63839" +dependencies = [ + "csv", + "derive-new", + "dirs", + "rand 0.10.1", + "rmp-serde", + "sanitize-filename", + "serde", + "serde_json", + "strum", + "tempfile", + "thiserror 2.0.18", +] [[package]] -name = "castaway" -version = "0.2.4" +name = "burn-derive" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dec551ab6e7578819132c713a93c022a05d60159dc86e7a7050223577484c55a" +checksum = "dce7be43cdfc9903c43dbaf3f4821543e0497d79047d8fc9ee9084e448844446" dependencies = [ - "rustversion", + "derive-new", + "proc-macro2", + "quote", + "syn", ] [[package]] -name = "cc" -version = "1.2.51" +name = "burn-dispatch" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a0aeaff4ff1a90589618835a598e545176939b97874f7abc7851caa0618f203" +checksum = "c2087b9e12323e0d25cc0ebdccfee40427dfdec4a23fa6d3f49ba2aa1f94ac17" dependencies = [ - "find-msvc-tools", - "jobserver", - "libc", - "shlex", + "burn-autodiff", + "burn-backend", + "burn-cpu", + "burn-cuda", + "burn-flex", + "burn-ndarray", + "burn-rocm", + "burn-tch", + "burn-wgpu", + "paste", ] [[package]] -name = "cesu8" -version = "1.1.0" +name = "burn-flex" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" +checksum = "0098bf6555c151517b4c98ca0e8ed1ab6a976e40f5f4e967c117b00eee21e192" +dependencies = [ + "aligned-vec", + "burn-backend", + "burn-ir", + "burn-std", + "bytemuck", + "gemm", + "half", + "libm", + "macerator", + "num-traits", + "rayon", +] [[package]] -name = "cfg-if" -version = "1.0.4" +name = "burn-fusion" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" +checksum = "95e58fcfd52a60cdf2f7da34fbebf0ed38f960fbd8675d384bacd5795cf2bdf2" +dependencies = [ + "burn-backend", + "burn-ir", + "burn-std", + "derive-new", + "hashbrown 0.16.1", + "log", + "serde", + "smallvec", + "spin", + "tracing", +] [[package]] -name = "cfg_aliases" -version = "0.2.1" +name = "burn-ir" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" +checksum = "a81a55c32f35c2265d9e15ba2e796013d9780d5a49f9e21ea0ac4d29609dbf13" +dependencies = [ + "burn-backend", + "hashbrown 0.16.1", + "serde", +] [[package]] -name = "chacha20" -version = "0.10.0" +name = "burn-ndarray" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f8d983286843e49675a4b7a2d174efe136dc93a18d69130dd18198a6c167601" +checksum = "dceb9692e292782bab7ad0259e8e8f5ee80ba2b0329a78f0ba589a26a9633dd6" dependencies = [ - "cfg-if", - "cpufeatures 0.3.0", - "rand_core 0.10.1", + "atomic_float", + "burn-autodiff", + "burn-backend", + "burn-ir", + "burn-std", + "const-random", + "libm", + "macerator", + "matrixmultiply", + "ndarray 0.17.2", + "num-traits", + "paste", + "portable-atomic", + "portable-atomic-util", + "rand 0.10.1", ] [[package]] -name = "chardetng" -version = "0.1.17" +name = "burn-nn" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14b8f0b65b7b08ae3c8187e8d77174de20cb6777864c6b832d8ad365999cf1ea" +checksum = "93e4acd90806fa8663610f1071f3a8992eb98637d2d0816ee3062b334f61af00" dependencies = [ - "cfg-if", - "encoding_rs", - "memchr", + "burn-core", + "num-traits", ] [[package]] -name = "chrono" -version = "0.4.42" +name = "burn-optim" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "145052bdd345b87320e369255277e3fb5152762ad123a901ef5c262dd38fe8d2" +checksum = "4c5ea466ae0b85bf18f7656cdc152050dc8c581057fbbe33bbed267e22600228" dependencies = [ - "iana-time-zone", - "js-sys", + "burn-core", + "derive-new", + "hashbrown 0.16.1", + "log", "num-traits", "serde", - "wasm-bindgen", - "windows-link", ] [[package]] -name = "cipher" -version = "0.4.4" +name = "burn-rocm" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" +checksum = "66af82fdaaf2ad0fa4b0dae90119aa94f333105d76d520e0eb48917717c06fde" dependencies = [ - "crypto-common", - "inout", + "burn-backend", + "burn-cubecl", + "burn-fusion", + "cubecl", ] [[package]] -name = "clap" -version = "4.5.54" +name = "burn-router" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6e6ff9dcd79cff5cd969a17a545d79e84ab086e444102a591e288a8aa3ce394" +checksum = "7960a5d43918c3158629da2bd7956e38dda16ef54de95cca83b4b7b1477e6185" dependencies = [ - "clap_builder", - "clap_derive", + "burn-backend", + "burn-ir", + "burn-std", + "hashbrown 0.16.1", + "log", + "spin", ] [[package]] -name = "clap_builder" -version = "4.5.54" +name = "burn-std" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa42cf4d2b7a41bc8f663a7cab4031ebafa1bf3875705bfaf8466dc60ab52c00" +checksum = "81c7eb60eb2c316854af5b214fd55f59fc7b0e25dfde7db671f09cc49f269048" dependencies = [ - "anstream", - "anstyle", - "clap_lex", - "strsim", - "terminal_size", + "bytemuck", + "bytes", + "cubecl", + "cubecl-common", + "cubecl-zspace", + "half", + "num-traits", + "serde", + "smallvec", + "spin", ] [[package]] -name = "clap_derive" -version = "4.5.49" +name = "burn-store" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a0b5487afeab2deb2ff4e03a807ad1a03ac532ff5a2cee5d86884440c7f7671" +checksum = "2f64a4fe2a0616d18f07d1d0d19c79e655e70e1828cbcb5e9df7b52211091023" dependencies = [ - "heck 0.5.0", - "proc-macro2", - "quote", - "syn 2.0.114", + "burn-core", + "burn-tensor", + "byteorder", + "bytes", + "half", + "hashbrown 0.16.1", + "memmap2", + "regex", + "safetensors 0.7.0", + "textdistance", ] [[package]] -name = "clap_lex" -version = "0.7.6" +name = "burn-tch" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1d728cc89cf3aee9ff92b05e62b19ee65a02b5702cff7d5a377e32c6ae29d8d" +checksum = "dfa36b630bd7a790395b4561f7d0e315c0d5e1c557db7dd4cf1b48d5c0d4aff2" +dependencies = [ + "burn-backend", + "cc", + "libc", + "log", + "tch", + "torch-sys", +] [[package]] -name = "cmake" -version = "0.1.57" +name = "burn-tensor" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75443c44cd6b379beb8c5b45d85d0773baf31cce901fe7bb252f4eff3008ef7d" +checksum = "223ed3804bb9436e401fc57b87e44c86267070b870813520ed9f706c80c81442" dependencies = [ - "cc", + "burn-backend", + "burn-std", + "colored", + "derive-new", + "num-traits", + "serde", ] [[package]] -name = "colorchoice" -version = "1.0.4" +name = "burn-train" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" +checksum = "fa65e2e569e571bb8dc9d37aa8fcf715f522f8159c6ee87f665c1961fee5259f" +dependencies = [ + "async-channel", + "burn-core", + "burn-flex", + "burn-optim", + "derive-new", + "log", + "rand 0.10.1", + "rstest", + "serde", + "thiserror 2.0.18", + "tracing-appender", + "tracing-core", + "tracing-subscriber", +] [[package]] -name = "combine" -version = "4.6.7" +name = "burn-vision" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd" +checksum = "38b5a3e9096977462cd22bf713087f9777e427f7693508871f86f5b1e8347a70" dependencies = [ - "bytes", - "memchr", + "aligned-vec", + "bon", + "burn-cubecl", + "burn-fusion", + "burn-ir", + "burn-tensor", + "bytemuck", + "cubecl", + "derive-new", + "half", + "image", + "macerator", + "ndarray 0.17.2", + "num-traits", + "paste", + "serde", ] [[package]] -name = "compact_str" -version = "0.9.0" +name = "burn-wgpu" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb1325a1cece981e8a296ab8f0f9b63ae357bd0784a9faaf548cc7b480707a" +checksum = "6eb009254af15922cb37814f3b3b61043046193ba2fde97c3879a25fbd51a92e" dependencies = [ - "castaway", - "cfg-if", - "itoa", - "rustversion", - "ryu", - "serde", - "static_assertions", + "burn-backend", + "burn-cubecl", + "burn-fusion", + "cubecl", ] [[package]] -name = "concurrent-queue" -version = "2.5.0" +name = "bytemuck" +version = "1.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" +checksum = "c8efb64bd706a16a1bdde310ae86b351e4d21550d98d056f22f8a7f7a2183fec" dependencies = [ - "crossbeam-utils", + "bytemuck_derive", ] [[package]] -name = "console" -version = "0.15.11" +name = "bytemuck_derive" +version = "1.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "054ccb5b10f9f2cbf51eb355ca1d05c2d279ce1804688d0db74b4733a5aeafd8" +checksum = "f9abbd1bc6865053c427f7198e6af43bfdedc55ab791faed4fbd361d789575ff" dependencies = [ - "encode_unicode", - "libc", - "once_cell", - "unicode-width 0.2.2", - "windows-sys 0.59.0", + "proc-macro2", + "quote", + "syn", ] [[package]] -name = "const-oid" -version = "0.9.6" +name = "byteorder" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] -name = "constant_time_eq" -version = "0.4.2" +name = "byteorder-lite" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d52eff69cd5e647efe296129160853a42795992097e8af39800e1060caeea9b" +checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495" [[package]] -name = "content_inspector" -version = "0.2.4" +name = "bytes" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7bda66e858c683005a53a9a60c69a4aca7eeaa45d124526e389f7aec8e62f38" +checksum = "8ae3f5d315924270530207e2a68396c3cc547f6dca3fbdca317cfb1a51edb593" dependencies = [ - "memchr", + "portable-atomic", ] [[package]] -name = "convert_case" -version = "0.6.0" +name = "bzip2" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec182b0ca2f35d8fc196cf3404988fd8b8c739a4d270ff118a398feb0cbec1ca" +checksum = "bdb116a6ef3f6c3698828873ad02c3014b3c85cadb88496095628e3ef1e347f8" dependencies = [ - "unicode-segmentation", + "bzip2-sys", + "libc", ] [[package]] -name = "cookie" -version = "0.18.1" +name = "bzip2-sys" +version = "0.1.13+1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ddef33a339a91ea89fb53151bd0a4689cfce27055c291dfa69945475d22c747" +checksum = "225bff33b2141874fe80d71e07d6eec4f85c5c216453dd96388240f96e1acc14" dependencies = [ - "aes-gcm", - "base64", - "hmac", - "percent-encoding", - "rand 0.8.5", - "sha2", - "subtle", - "time", - "version_check", + "cc", + "pkg-config", ] [[package]] -name = "core-foundation" -version = "0.10.1" +name = "candle-core" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6" +checksum = "6bd9895436c1ba5dc1037a19935d084b838db066ff4e15ef7dded020b7c12a4a" dependencies = [ - "core-foundation-sys", - "libc", + "byteorder", + "float8", + "gemm", + "half", + "libm", + "memmap2", + "num-traits", + "num_cpus", + "rand 0.9.4", + "rand_distr 0.5.1", + "rayon", + "safetensors 0.7.0", + "thiserror 2.0.18", + "tokenizers 0.22.2", + "yoke", + "zip 7.2.0", ] [[package]] -name = "core-foundation-sys" -version = "0.8.7" +name = "caseless" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" +checksum = "8b6fd507454086c8edfd769ca6ada439193cdb209c7681712ef6275cccbfe5d8" +dependencies = [ + "unicode-normalization", +] [[package]] -name = "cpufeatures" -version = "0.2.17" +name = "castaway" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +checksum = "dec551ab6e7578819132c713a93c022a05d60159dc86e7a7050223577484c55a" dependencies = [ - "libc", + "rustversion", ] [[package]] -name = "cpufeatures" -version = "0.3.0" +name = "cc" +version = "1.2.65" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b2a41393f66f16b0823bb79094d54ac5fbd34ab292ddafb9a0456ac9f87d201" +checksum = "e228eec9be7c17ccb640b59b36a5cd805ea2a564a4c5e162c2f659fea30d3b96" dependencies = [ + "find-msvc-tools", + "jobserver", "libc", + "shlex 2.0.1", ] [[package]] -name = "crc" -version = "3.4.0" +name = "cexpr" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5eb8a2a1cd12ab0d987a5d5e825195d372001a4094a0376319d5a0ad71c1ba0d" +checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" dependencies = [ - "crc-catalog", + "nom 7.1.3", ] [[package]] -name = "crc-catalog" -version = "2.4.0" +name = "cfg-if" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" [[package]] -name = "crc32fast" -version = "1.5.0" +name = "cfg_aliases" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + +[[package]] +name = "chacha20" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d524456ba66e72eb8b115ff89e01e497f8e6d11d78b70b1aa13c0fbd97540a81" dependencies = [ "cfg-if", + "cpufeatures 0.3.0", + "rand_core 0.10.1", ] [[package]] -name = "crossbeam-deque" -version = "0.8.6" +name = "ciborium" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" +checksum = "42e69ffd6f0917f5c029256a24d0161db17cea3997d185db0d35926308770f0e" dependencies = [ - "crossbeam-epoch", - "crossbeam-utils", + "ciborium-io", + "ciborium-ll", + "serde", ] [[package]] -name = "crossbeam-epoch" -version = "0.9.18" +name = "ciborium-io" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" -dependencies = [ - "crossbeam-utils", -] +checksum = "05afea1e0a06c9be33d539b876f1ce3692f4afea2cb41f740e7743225ed1c757" [[package]] -name = "crossbeam-queue" -version = "0.3.12" +name = "ciborium-ll" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f58bbc28f91df819d0aa2a2c00cd19754769c2fad90579b3592b1c9ba7a3115" +checksum = "57663b653d948a338bfb3eeba9bb2fd5fcfaecb9e199e87e1eda4d9e8b240fd9" dependencies = [ - "crossbeam-utils", + "ciborium-io", + "half", ] [[package]] -name = "crossbeam-utils" -version = "0.8.21" +name = "cipher" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" +dependencies = [ + "crypto-common", + "inout", +] [[package]] -name = "crypto-common" -version = "0.1.7" +name = "clang-sys" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" +checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" dependencies = [ - "generic-array", - "rand_core 0.6.4", - "typenum", + "glob", + "libc", + "libloading 0.8.9", ] [[package]] -name = "ctr" -version = "0.9.2" +name = "clap" +version = "4.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835" +checksum = "1ddb117e43bbf7dacf0a4190fef4d345b9bad68dfc649cb349e7d17d28428e51" dependencies = [ - "cipher", + "clap_builder", + "clap_derive", ] [[package]] -name = "cucumber" -version = "0.21.1" +name = "clap_builder" +version = "4.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6cd12917efc3a8b069a4975ef3cb2f2d835d42d04b3814d90838488f9dd9bf69" +checksum = "714a53001bf66416adb0e2ef5ac857140e7dc3a0c48fb28b2f10762fc4b5069f" dependencies = [ - "anyhow", - "clap", - "console", - "crossbeam-utils", - "cucumber-codegen", - "cucumber-expressions", - "derive_more 0.99.20", - "drain_filter_polyfill", - "either", - "futures", - "gherkin", - "globwalk", - "humantime", - "inventory", - "itertools 0.13.0", - "lazy-regex", - "linked-hash-map", - "once_cell", - "pin-project", - "regex", - "sealed", - "smart-default", - "tracing", - "tracing-subscriber", + "anstream", + "anstyle", + "clap_lex", + "strsim", ] [[package]] -name = "cucumber-codegen" -version = "0.21.1" +name = "clap_derive" +version = "4.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e19cd9e8e7cfd79fbf844eb6a7334117973c01f6bad35571262b00891e60f1c" +checksum = "f2ce8604710f6733aa641a2b3731eaa1e8b3d9973d5e3565da11800813f997a9" dependencies = [ - "cucumber-expressions", - "inflections", - "itertools 0.13.0", + "heck", "proc-macro2", "quote", - "regex", - "syn 2.0.114", - "synthez", + "syn", ] [[package]] -name = "cucumber-expressions" -version = "0.3.0" +name = "clap_lex" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d794fed319eea24246fb5f57632f7ae38d61195817b7eb659455aa5bdd7c1810" -dependencies = [ - "derive_more 0.99.20", - "either", - "nom", - "nom_locate", - "regex", - "regex-syntax 0.7.5", -] +checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9" [[package]] -name = "darling" -version = "0.20.11" +name = "codespan-reporting" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee" +checksum = "af491d569909a7e4dee0ad7db7f5341fef5c614d5b8ec8cf765732aba3cff681" dependencies = [ - "darling_core 0.20.11", - "darling_macro 0.20.11", + "serde", + "termcolor", + "unicode-width", ] [[package]] -name = "darling" -version = "0.21.3" +name = "color_quant" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cdf337090841a411e2a7f3deb9187445851f91b309c0c0a29e05f74a00a48c0" -dependencies = [ - "darling_core 0.21.3", - "darling_macro 0.21.3", -] +checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" [[package]] -name = "darling_core" -version = "0.20.11" +name = "colorchoice" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d00b9596d185e565c2207a0b01f8bd1a135483d02d9b7b0a54b11da8d53412e" -dependencies = [ - "fnv", - "ident_case", - "proc-macro2", - "quote", - "strsim", - "syn 2.0.114", -] +checksum = "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570" [[package]] -name = "darling_core" -version = "0.21.3" +name = "colored" +version = "3.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1247195ecd7e3c85f83c8d2a366e4210d588e802133e1e355180a9870b517ea4" +checksum = "faf9468729b8cbcea668e36183cb69d317348c2e08e994829fb56ebfdfbaac34" dependencies = [ - "fnv", - "ident_case", - "proc-macro2", - "quote", - "strsim", - "syn 2.0.114", + "windows-sys 0.61.2", ] [[package]] -name = "darling_macro" -version = "0.20.11" +name = "compact_str" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" +checksum = "9dfdd1c2274d9aa354115b09dc9a901d6c5576818cdf70d14cae2bdb47df00ab" dependencies = [ - "darling_core 0.20.11", - "quote", - "syn 2.0.114", + "castaway", + "cfg-if", + "itoa", + "rustversion", + "ryu", + "serde", + "static_assertions", ] [[package]] -name = "darling_macro" -version = "0.21.3" +name = "comrak" +version = "0.39.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d38308df82d1080de0afee5d069fa14b0326a88c14f15c5ccda35b4a6c414c81" +checksum = "2fefab951771fc3beeed0773ce66a4f7b706273fc6c4c95b08dd1615744abcf5" dependencies = [ - "darling_core 0.21.3", - "quote", - "syn 2.0.114", + "caseless", + "entities", + "memchr", + "slug", + "typed-arena", + "unicode_categories", ] [[package]] -name = "data-encoding" -version = "2.9.0" +name = "concurrent-queue" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a2330da5de22e8a3cb63252ce2abb30116bf5265e89c0e01bc17015ce30a476" +checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" +dependencies = [ + "crossbeam-utils", +] [[package]] -name = "der" -version = "0.7.10" +name = "console" +version = "0.16.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb" +checksum = "d64e8af5551369d19cf50138de61f1c42074ab970f74e99be916646777f8fc87" dependencies = [ - "const-oid", - "pem-rfc7468", - "zeroize", + "encode_unicode", + "libc", + "unicode-width", + "windows-sys 0.61.2", ] [[package]] -name = "der-parser" -version = "10.0.0" +name = "const-random" +version = "0.1.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07da5016415d5a3c4dd39b11ed26f915f52fc4e0dc197d87908bc916e51bc1a6" +checksum = "87e00182fe74b066627d63b85fd550ac2998d4b0bd86bfed477a0ae4c7c71359" dependencies = [ - "asn1-rs", - "displaydoc", - "nom", - "num-bigint", - "num-traits", - "rusticata-macros", + "const-random-macro", ] [[package]] -name = "deranged" -version = "0.5.5" +name = "const-random-macro" +version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ececcb659e7ba858fb4f10388c250a7252eb0a27373f1a72b8748afdd248e587" +checksum = "f9d839f2a20b0aee515dc581a6172f2321f96cab76c1a38a4c584a194955390e" dependencies = [ - "powerfmt", - "serde_core", + "getrandom 0.2.17", + "once_cell", + "tiny-keccak", ] [[package]] -name = "derive-getters" -version = "0.5.0" +name = "constant_time_eq" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74ef43543e701c01ad77d3a5922755c6a1d71b22d942cb8042be4994b380caff" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.114", -] +checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" [[package]] -name = "derive_builder" -version = "0.20.2" +name = "constcat" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "507dfb09ea8b7fa618fcf76e953f4f5e192547945816d5358edffe39f6f94947" -dependencies = [ - "derive_builder_macro", -] +checksum = "136d3e02915a2cea4d74caa8681e2d44b1c3254bdbf17d11d41d587ff858832c" [[package]] -name = "derive_builder_core" -version = "0.20.2" +name = "convert_case" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d5bcf7b024d6835cfb3d473887cd966994907effbe9227e8c8219824d06c4e8" +checksum = "baaaa0ecca5b51987b9423ccdc971514dd8b0bb7b4060b983d3664dad3f1f89f" dependencies = [ - "darling 0.20.11", - "proc-macro2", - "quote", - "syn 2.0.114", + "unicode-segmentation", ] [[package]] -name = "derive_builder_macro" -version = "0.20.2" +name = "convert_case" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab63b0e2bf4d5928aff72e83a7dace85d7bba5fe12dcc3c5a572d78caffd3f3c" +checksum = "633458d4ef8c78b72454de2d54fd6ab2e60f9e02be22f3c6104cdc8a4e0fceb9" dependencies = [ - "derive_builder_core", - "syn 2.0.114", + "unicode-segmentation", ] [[package]] -name = "derive_more" -version = "0.99.20" +name = "cpufeatures" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6edb4b64a43d977b8e99788fe3a04d483834fba1215a7e02caa415b626497f7f" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.114", + "libc", ] [[package]] -name = "derive_more" -version = "2.1.1" +name = "cpufeatures" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d751e9e49156b02b44f9c1815bcb94b984cdcc4396ecc32521c739452808b134" +checksum = "8b2a41393f66f16b0823bb79094d54ac5fbd34ab292ddafb9a0456ac9f87d201" dependencies = [ - "derive_more-impl", + "libc", ] [[package]] -name = "derive_more-impl" -version = "2.1.1" +name = "crc32fast" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "799a97264921d8623a957f6c3b9011f3b5492f557bbb7a5a19b7fa6d06ba8dcb" +checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" dependencies = [ - "proc-macro2", - "quote", - "rustc_version", - "syn 2.0.114", - "unicode-xid", + "cfg-if", ] [[package]] -name = "diff" -version = "0.1.13" +name = "critical-section" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" +checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b" [[package]] -name = "digest" -version = "0.10.7" +name = "crossbeam-channel" +version = "0.5.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2" dependencies = [ - "block-buffer", - "const-oid", - "crypto-common", - "subtle", + "crossbeam-utils", ] [[package]] -name = "displaydoc" -version = "0.2.5" +name = "crossbeam-deque" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.114", + "crossbeam-epoch", + "crossbeam-utils", ] [[package]] -name = "dotenvy" -version = "0.15.7" +name = "crossbeam-epoch" +version = "0.9.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] [[package]] -name = "drain_filter_polyfill" -version = "0.1.3" +name = "crossbeam-utils" +version = "0.8.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "669a445ee724c5c69b1b06fe0b63e70a1c84bc9bb7d9696cd4f4e3ec45050408" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" [[package]] -name = "dunce" -version = "1.0.5" +name = "crunchy" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" +checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" [[package]] -name = "dyn-clone" -version = "1.0.20" +name = "crypto-common" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555" +checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" +dependencies = [ + "generic-array", + "typenum", +] [[package]] -name = "either" -version = "1.15.0" +name = "csv" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" +checksum = "52cd9d68cf7efc6ddfaaee42e7288d3a99d613d4b50f76ce9827ae0c6e14f938" dependencies = [ - "serde", + "csv-core", + "itoa", + "ryu", + "serde_core", ] [[package]] -name = "encode_unicode" -version = "1.0.0" +name = "csv-core" +version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0" +checksum = "704a3c26996a80471189265814dbc2c257598b96b8a7feae2d31ace646bb9782" +dependencies = [ + "memchr", +] [[package]] -name = "encoding_rs" -version = "0.8.35" +name = "cubecl" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" +checksum = "fd203fef6e359472e4cb8f6c0ef3eca062815a1edd560eb6d6c1d5c1397838d9" dependencies = [ - "cfg-if", + "cubecl-core", + "cubecl-cpu", + "cubecl-cuda", + "cubecl-hip", + "cubecl-ir", + "cubecl-runtime", + "cubecl-std", + "cubecl-wgpu", + "half", ] [[package]] -name = "enumflags2" -version = "0.7.12" +name = "cubecl-common" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1027f7680c853e056ebcec683615fb6fbbc07dbaa13b4d5d9442b146ded4ecef" +checksum = "cc956c2dcc993f16f748d03bfdbd900f75cab4d469f4e5d8924f8ee128e861ad" dependencies = [ - "enumflags2_derive", + "backtrace", + "bytemuck", + "bytes", + "cfg-if", + "cfg_aliases", + "ciborium", + "derive-new", + "derive_more", + "dirs", + "embassy-futures", + "embassy-time", + "float4", + "float8", + "futures-lite", + "half", + "hashbrown 0.16.1", + "log", + "num-traits", + "oneshot", + "parking_lot", + "portable-atomic", + "portable-atomic-util", + "rand 0.10.1", + "sanitize-filename", + "serde", + "serde_bytes", + "serde_json", + "spin", + "toml", + "tracing", + "tynm", + "wasm-bindgen-futures", + "web-time", + "xxhash-rust", ] [[package]] -name = "enumflags2_derive" -version = "0.7.12" +name = "cubecl-core" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67c78a4d8fdf9953a5c9d458f9efe940fd97a0cab0941c075a813ac594733827" +checksum = "a7522e7acf25d7848032c7b5270780f9f2abe84e13c7ed6345aa27ba70c312ca" dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.114", + "bitflags", + "bytemuck", + "cubecl-common", + "cubecl-ir", + "cubecl-macros", + "cubecl-runtime", + "cubecl-zspace", + "derive-new", + "derive_more", + "enumset", + "float-ord", + "half", + "hashbrown 0.16.1", + "log", + "num-traits", + "paste", + "serde", + "serde_json", + "tracing", + "variadics_please", ] [[package]] -name = "equivalent" -version = "1.0.2" +name = "cubecl-cpp" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" +checksum = "411af04828cbf4583ecd388579fb30cd7a644eec19a334bb8f0d9d08522e1458" +dependencies = [ + "bytemuck", + "cubecl-common", + "cubecl-core", + "cubecl-opt", + "cubecl-runtime", + "derive-new", + "half", + "itertools 0.14.0", + "log", +] [[package]] -name = "errno" -version = "0.3.14" +name = "cubecl-cpu" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" +checksum = "f572143f54e42a49ee0635a4ec36005f639e62be029e4f49890c808985981b35" dependencies = [ - "libc", - "windows-sys 0.61.2", + "bytemuck", + "cubecl-common", + "cubecl-core", + "cubecl-opt", + "cubecl-runtime", + "cubecl-std", + "derive-new", + "half", + "log", + "paste", + "serde", + "sysinfo", + "tracel-llvm", + "tracel-llvm-bundler", ] [[package]] -name = "etcetera" -version = "0.8.0" +name = "cubecl-cuda" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "136d1b5283a1ab77bd9257427ffd09d8667ced0570b6f938942bc7568ed5b943" +checksum = "b6b0a69ff45688d322ad8e92c8bf645167b9ca490fa8fa087fc6adac8c5e46be" dependencies = [ - "cfg-if", - "home", - "windows-sys 0.48.0", + "bytemuck", + "cubecl-common", + "cubecl-core", + "cubecl-cpp", + "cubecl-runtime", + "cudarc", + "derive-new", + "half", + "log", + "serde", + "tracing", ] [[package]] -name = "event-listener" -version = "5.4.1" +name = "cubecl-hip" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e13b66accf52311f30a0db42147dadea9850cb48cd070028831ae5f5d4b856ab" +checksum = "3c6b510a9348f06ecd56b32cf10eb6241639e927a87f5c09ec61cc7a7610d5a3" dependencies = [ - "concurrent-queue", - "parking", - "pin-project-lite", + "bytemuck", + "cubecl-common", + "cubecl-core", + "cubecl-cpp", + "cubecl-hip-sys", + "cubecl-runtime", + "derive-new", + "half", + "log", + "paste", + "serde", + "tracing", ] [[package]] -name = "fastrand" -version = "2.3.0" +name = "cubecl-hip-sys" +version = "7.2.5321100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" +checksum = "58887c6d217859c2261a868a3a6b66aa8f44ea2f4bfa51d0dbe4dcb0d1f5768d" +dependencies = [ + "libc", + "regex", +] [[package]] -name = "find-msvc-tools" -version = "0.1.6" +name = "cubecl-ir" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "645cbb3a84e60b7531617d5ae4e57f7e27308f6445f5abf653209ea76dec8dff" +checksum = "d28a897a40c8ee6c57a8b8d76d8823ba2e97f4c2b83db9338f17a0752132d486" +dependencies = [ + "cubecl-common", + "cubecl-macros-internal", + "derive-new", + "derive_more", + "enumset", + "float-ord", + "fnv", + "foldhash 0.2.0", + "half", + "hashbrown 0.16.1", + "num-traits", + "portable-atomic", + "serde", + "variadics_please", +] [[package]] -name = "flate2" -version = "1.1.5" +name = "cubecl-macros" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfe33edd8e85a12a67454e37f8c75e730830d83e313556ab9ebf9ee7fbeb3bfb" +checksum = "77aa6df563e8e6a0926d2e9eeacb968737940a0e1ae9be819f6a65a341006e12" dependencies = [ - "crc32fast", - "miniz_oxide", + "cubecl-common", + "darling 0.23.0", + "derive-new", + "ident_case", + "inflections", + "prettyplease", + "proc-macro2", + "quote", + "syn", ] [[package]] -name = "flume" -version = "0.11.1" +name = "cubecl-macros-internal" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da0e4dd2a88388a1f4ccc7c9ce104604dab68d9f408dc34cd45823d5a9069095" +checksum = "a515651a5a91e25d87f71f311f80a088e6cf815798b9922560a97636da6b8740" dependencies = [ - "futures-core", - "futures-sink", - "spin", + "darling 0.23.0", + "proc-macro2", + "quote", + "syn", ] [[package]] -name = "fnv" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" - -[[package]] -name = "foldhash" -version = "0.1.5" +name = "cubecl-opt" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" +checksum = "0a599c6c3efefdcee8636994c90e58ef696c7efbed2d18b5b5ad8d5f29923abb" +dependencies = [ + "cubecl-common", + "cubecl-core", + "cubecl-ir", + "float-ord", + "log", + "num", + "petgraph", + "smallvec", + "stable-vec", + "type-map", +] [[package]] -name = "foldhash" -version = "0.2.0" +name = "cubecl-runtime" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" +checksum = "b68491bf5b3e997ae36bdc4e63b4ccd6d2f0e86b3b596a5d7a48d2b9e92622a0" +dependencies = [ + "ahash", + "async-channel", + "bytemuck", + "cfg-if", + "cfg_aliases", + "cubecl-common", + "cubecl-ir", + "cubecl-zspace", + "derive-new", + "derive_more", + "dirs", + "enumset", + "hashbrown 0.16.1", + "log", + "md5", + "serde", + "serde_json", + "spin", + "thiserror 2.0.18", + "toml", + "tracing", + "wasm-bindgen-futures", + "web-time", +] [[package]] -name = "form_urlencoded" -version = "1.2.2" +name = "cubecl-std" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" +checksum = "b391b584a4897683dd9fc0767f96337ac712b733126ce0f68a9ee8a2df073d2d" dependencies = [ - "percent-encoding", + "cubecl-common", + "cubecl-core", + "cubecl-runtime", + "half", + "num-traits", + "paste", + "serde", + "spin", + "variadics_please", ] [[package]] -name = "fs_extra" -version = "1.3.0" +name = "cubecl-wgpu" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" +checksum = "4d3663c6e1a86187172b2cee495b6b533e7d91a2cb37e26f421649e315fe4c3a" +dependencies = [ + "async-channel", + "bytemuck", + "cfg-if", + "cfg_aliases", + "cubecl-common", + "cubecl-core", + "cubecl-ir", + "cubecl-runtime", + "derive-new", + "derive_more", + "half", + "hashbrown 0.16.1", + "log", + "sanitize-filename", + "tracing", + "wasm-bindgen-futures", + "wgpu", +] [[package]] -name = "funty" -version = "2.0.0" +name = "cubecl-zspace" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" +checksum = "04054d95698afab785a4dda9f949e297831dd9e4cc6d036a93e6603f88e88b07" +dependencies = [ + "derive-new", + "serde", + "smallvec", +] [[package]] -name = "futures" -version = "0.3.31" +name = "cubek" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" +checksum = "ba62fb5043d5eb723017415eec57c541f41901beea984500e2e16b57d75fa717" dependencies = [ - "futures-channel", - "futures-core", - "futures-executor", - "futures-io", - "futures-sink", - "futures-task", - "futures-util", + "cubecl", + "cubek-attention", + "cubek-convolution", + "cubek-fft", + "cubek-matmul", + "cubek-quant", + "cubek-random", + "cubek-reduce", + "cubek-std", ] [[package]] -name = "futures-channel" -version = "0.3.31" +name = "cubek-attention" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" +checksum = "75ca5c363f05a9297b9d1c0e90959cc5f9fd90bc596e4e537f26f20602ec63a5" dependencies = [ - "futures-core", - "futures-sink", + "bytemuck", + "cubecl", + "cubecl-common", + "cubek-matmul", + "cubek-std", + "half", + "serde", ] [[package]] -name = "futures-core" -version = "0.3.31" +name = "cubek-convolution" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" +checksum = "70f2755a8eb9ea5509c17edac78e4a9dc4be89c433d8e2ee709703a93b96f749" +dependencies = [ + "bytemuck", + "cubecl", + "cubecl-common", + "cubek-matmul", + "cubek-std", + "derive-new", + "enumset", + "half", + "serde", +] [[package]] -name = "futures-executor" -version = "0.3.31" +name = "cubek-fft" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" +checksum = "8dd7c2972363332dc4609067a2ccc21856308d98089e676d3f0c52747ae61a5b" dependencies = [ - "futures-core", - "futures-task", - "futures-util", + "cubecl", ] [[package]] -name = "futures-intrusive" -version = "0.5.0" +name = "cubek-matmul" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d930c203dd0b6ff06e0201a4a2fe9149b43c684fd4420555b26d21b1a02956f" +checksum = "83a4cea5f0f439907dc953c7638a6204b3f055f1bcbd10db91dfc5faa030ac1c" dependencies = [ - "futures-core", - "lock_api", - "parking_lot", + "bytemuck", + "cubecl", + "cubecl-common", + "cubek-std", + "half", + "serde", ] [[package]] -name = "futures-io" -version = "0.3.31" +name = "cubek-quant" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" +checksum = "802ff1b5f19597a7b7cb308c7c69e9eef28b78d57dab7794c816bb8f7d3d1b85" +dependencies = [ + "cubecl", + "cubecl-common", + "half", + "serde", +] [[package]] -name = "futures-macro" -version = "0.3.31" +name = "cubek-random" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" +checksum = "8dfecce959bdbeb3b355120e586d1ea9e45a0fc7f2ca354f4260a571952551be" dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.114", + "cubecl", + "cubecl-common", + "half", + "num-traits", + "rand 0.10.1", + "serde", ] [[package]] -name = "futures-sink" -version = "0.3.31" +name = "cubek-reduce" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" +checksum = "86758b84452b06e9121f25200da13b4909ecd6235cefb5f33f459bea24dac41a" +dependencies = [ + "cubecl", + "cubek-std", + "half", + "num-traits", + "serde", + "thiserror 2.0.18", +] [[package]] -name = "futures-task" -version = "0.3.31" +name = "cubek-std" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" +checksum = "a587d0a44b6f14f4c3711ac10717179b48adb59203b2b2bffe334876bf713187" +dependencies = [ + "cubecl", + "cubecl-common", + "half", +] [[package]] -name = "futures-util" -version = "0.3.31" +name = "cudarc" +version = "0.19.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" +checksum = "42310153e06cf4cd532901f7096beb27504d681736a29ee90728ae4e2d93b2a8" dependencies = [ - "futures-channel", - "futures-core", - "futures-io", - "futures-macro", - "futures-sink", - "futures-task", - "memchr", - "pin-project-lite", - "pin-utils", - "slab", + "libloading 0.9.0", ] [[package]] -name = "generic-array" -version = "0.14.7" +name = "daachorse" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" -dependencies = [ - "typenum", - "version_check", -] +checksum = "6f55d7153ba3b507595872a3874803f07a8a81d1e888abed8e5db7da0597d6e2" [[package]] -name = "getrandom" -version = "0.2.16" +name = "darling" +version = "0.20.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" +checksum = "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee" dependencies = [ - "cfg-if", - "js-sys", - "libc", - "wasi", - "wasm-bindgen", + "darling_core 0.20.11", + "darling_macro 0.20.11", ] [[package]] -name = "getrandom" -version = "0.3.4" +name = "darling" +version = "0.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" +checksum = "9cdf337090841a411e2a7f3deb9187445851f91b309c0c0a29e05f74a00a48c0" dependencies = [ - "cfg-if", - "js-sys", - "libc", - "r-efi 5.3.0", - "wasip2", - "wasm-bindgen", + "darling_core 0.21.3", + "darling_macro 0.21.3", ] [[package]] -name = "getrandom" -version = "0.4.2" +name = "darling" +version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0de51e6874e94e7bf76d726fc5d13ba782deca734ff60d5bb2fb2607c7406555" +checksum = "25ae13da2f202d56bd7f91c25fba009e7717a1e4a1cc98a76d844b65ae912e9d" dependencies = [ - "cfg-if", - "libc", - "r-efi 6.0.0", - "rand_core 0.10.1", - "wasip2", - "wasip3", + "darling_core 0.23.0", + "darling_macro 0.23.0", ] [[package]] -name = "getset" -version = "0.1.6" +name = "darling_core" +version = "0.20.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cf0fc11e47561d47397154977bc219f4cf809b2974facc3ccb3b89e2436f912" +checksum = "0d00b9596d185e565c2207a0b01f8bd1a135483d02d9b7b0a54b11da8d53412e" dependencies = [ - "proc-macro-error2", + "fnv", + "ident_case", "proc-macro2", "quote", - "syn 2.0.114", + "strsim", + "syn", ] [[package]] -name = "ghash" -version = "0.5.1" +name = "darling_core" +version = "0.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0d8a4362ccb29cb0b265253fb0a2728f592895ee6854fd9bc13f2ffda266ff1" +checksum = "1247195ecd7e3c85f83c8d2a366e4210d588e802133e1e355180a9870b517ea4" dependencies = [ - "opaque-debug", - "polyval", + "fnv", + "ident_case", + "proc-macro2", + "quote", + "syn", ] [[package]] -name = "gherkin" -version = "0.14.0" +name = "darling_core" +version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20b79820c0df536d1f3a089a2fa958f61cb96ce9e0f3f8f507f5a31179567755" +checksum = "9865a50f7c335f53564bb694ef660825eb8610e0a53d3e11bf1b0d3df31e03b0" dependencies = [ - "heck 0.4.1", - "peg", + "ident_case", + "proc-macro2", "quote", - "serde", - "serde_json", - "syn 2.0.114", - "textwrap", - "thiserror 1.0.69", - "typed-builder", + "strsim", + "syn", ] [[package]] -name = "gimli" -version = "0.32.3" +name = "darling_macro" +version = "0.20.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e629b9b98ef3dd8afe6ca2bd0f89306cec16d43d907889945bc5d6687f2f13c7" +checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" +dependencies = [ + "darling_core 0.20.11", + "quote", + "syn", +] [[package]] -name = "glob" -version = "0.3.3" +name = "darling_macro" +version = "0.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" +checksum = "d38308df82d1080de0afee5d069fa14b0326a88c14f15c5ccda35b4a6c414c81" +dependencies = [ + "darling_core 0.21.3", + "quote", + "syn", +] [[package]] -name = "globset" -version = "0.4.18" +name = "darling_macro" +version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52dfc19153a48bde0cbd630453615c8151bce3a5adfac7a0aebfbf0a1e1f57e3" +checksum = "ac3984ec7bd6cfa798e62b4a642426a5be0e68f9401cfc2a01e3fa9ea2fcdb8d" dependencies = [ - "aho-corasick", - "bstr", - "log", - "regex-automata", - "regex-syntax 0.8.8", + "darling_core 0.23.0", + "quote", + "syn", ] [[package]] -name = "globwalk" -version = "0.9.1" +name = "dary_heap" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bf760ebf69878d9fd8f110c89703d90ce35095324d1f1edcb595c63945ee757" +checksum = "8b1e3a325bc115f096c8b77bbf027a7c2592230e70be2d985be950d3d5e60ebe" dependencies = [ - "bitflags", - "ignore", - "walkdir", + "serde", ] [[package]] -name = "h2" -version = "0.4.13" +name = "data-encoding" +version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f44da3a8150a6703ed5d34e164b875fd14c2cdab9af1252a9a1020bde2bdc54" -dependencies = [ - "atomic-waker", - "bytes", - "fnv", - "futures-core", - "futures-sink", - "http", - "indexmap", - "slab", - "tokio", - "tokio-util", - "tracing", -] +checksum = "a4ae5f15dda3c708c0ade84bfee31ccab44a3da4f88015ed22f63732abe300c8" [[package]] -name = "h3" -version = "0.0.8" +name = "deranged" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10872b55cfb02a821b69dc7cf8dc6a71d6af25eb9a79662bec4a9d016056b3be" -dependencies = [ - "bytes", - "fastrand", - "futures-util", - "http", - "pin-project-lite", - "tokio", -] +checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c" [[package]] -name = "h3-datagram" -version = "0.0.2" +name = "derive-new" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d2c9f77921668673721ae40f17c729fc48b9e38a663858097cea547484fdf0f" +checksum = "2cdc8d50f426189eef89dac62fabfa0abb27d5cc008f25bf4156a0203325becc" dependencies = [ - "bytes", - "h3", - "pin-project-lite", + "proc-macro2", + "quote", + "syn", ] [[package]] -name = "h3-quinn" -version = "0.0.10" +name = "derive_builder" +version = "0.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b2e732c8d91a74731663ac8479ab505042fbf547b9a207213ab7fbcbfc4f8b4" +checksum = "507dfb09ea8b7fa618fcf76e953f4f5e192547945816d5358edffe39f6f94947" dependencies = [ - "bytes", - "futures", - "h3", - "h3-datagram", - "quinn", - "tokio", - "tokio-util", + "derive_builder_macro", ] [[package]] -name = "hashbrown" -version = "0.12.3" +name = "derive_builder_core" +version = "0.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +checksum = "2d5bcf7b024d6835cfb3d473887cd966994907effbe9227e8c8219824d06c4e8" dependencies = [ - "ahash", + "darling 0.20.11", + "proc-macro2", + "quote", + "syn", ] [[package]] -name = "hashbrown" -version = "0.15.5" +name = "derive_builder_macro" +version = "0.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" +checksum = "ab63b0e2bf4d5928aff72e83a7dace85d7bba5fe12dcc3c5a572d78caffd3f3c" dependencies = [ - "allocator-api2", - "equivalent", - "foldhash 0.1.5", + "derive_builder_core", + "syn", ] [[package]] -name = "hashbrown" -version = "0.16.1" +name = "derive_more" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" +checksum = "d751e9e49156b02b44f9c1815bcb94b984cdcc4396ecc32521c739452808b134" dependencies = [ - "allocator-api2", - "equivalent", - "foldhash 0.2.0", + "derive_more-impl", ] [[package]] -name = "hashlink" -version = "0.10.0" +name = "derive_more-impl" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7382cf6263419f2d8df38c55d7da83da5c18aef87fc7a7fc1fb1e344edfe14c1" +checksum = "799a97264921d8623a957f6c3b9011f3b5492f557bbb7a5a19b7fa6d06ba8dcb" dependencies = [ - "hashbrown 0.15.5", + "convert_case 0.10.0", + "proc-macro2", + "quote", + "rustc_version", + "syn", + "unicode-xid", ] [[package]] -name = "headers" -version = "0.4.1" +name = "deunicode" +version = "1.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3314d5adb5d94bcdf56771f2e50dbbc80bb4bdf88967526706205ac9eff24eb" -dependencies = [ - "base64", - "bytes", - "headers-core", - "http", - "httpdate", - "mime", - "sha1", -] +checksum = "abd57806937c9cc163efc8ea3910e00a62e2aeb0b8119f1793a978088f8f6b04" [[package]] -name = "headers-core" -version = "0.3.0" +name = "digest" +version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54b4a22553d4242c49fddb9ba998a99962b5cc6f22cb5a3482bec22522403ce4" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ - "http", + "block-buffer", + "crypto-common", + "subtle", ] [[package]] -name = "heck" -version = "0.4.1" +name = "dirs" +version = "6.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" +checksum = "c3e8aa94d75141228480295a7d0e7feb620b1a5ad9f12bc40be62411e38cce4e" +dependencies = [ + "dirs-sys", +] [[package]] -name = "heck" +name = "dirs-sys" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" - -[[package]] -name = "hex" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" - -[[package]] -name = "hkdf" -version = "0.12.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7" +checksum = "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab" dependencies = [ - "hmac", + "libc", + "option-ext", + "redox_users", + "windows-sys 0.61.2", ] [[package]] -name = "hmac" -version = "0.12.1" +name = "dispatch2" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +checksum = "1e0e367e4e7da84520dedcac1901e4da967309406d1e51017ae1abfb97adbd38" dependencies = [ - "digest", + "bitflags", + "objc2", ] [[package]] -name = "home" -version = "0.5.12" +name = "displaydoc" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc627f471c528ff0c4a49e1d5e60450c8f6461dd6d10ba9dcd3a61d3dff7728d" +checksum = "1ac70aa55017e108007fbaf5aa0f54b021c98f92ff8af59d42eda9da96e3dd4f" dependencies = [ - "windows-sys 0.61.2", + "proc-macro2", + "quote", + "syn", ] [[package]] -name = "http" -version = "1.4.0" +name = "dlib" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a" +checksum = "ab8ecd87370524b461f8557c119c405552c396ed91fc0a8eec68679eab26f94a" dependencies = [ - "bytes", - "itoa", + "libloading 0.8.9", ] [[package]] -name = "http-body" -version = "1.0.1" +name = "document-features" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" +checksum = "d4b8a88685455ed29a21542a33abd9cb6510b6b129abadabdcef0f4c55bc8f61" dependencies = [ - "bytes", - "http", + "litrs", ] [[package]] -name = "http-body-util" -version = "0.1.3" +name = "dyn-stack" +version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" +checksum = "1c4713e43e2886ba72b8271aa66c93d722116acf7a75555cce11dcde84388fe8" dependencies = [ - "bytes", - "futures-core", - "http", - "http-body", - "pin-project-lite", + "bytemuck", + "dyn-stack-macros", ] [[package]] -name = "httparse" -version = "1.10.1" +name = "dyn-stack-macros" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" +checksum = "e1d926b4d407d372f141f93bb444696142c29d32962ccbd3531117cf3aa0bfa9" [[package]] -name = "httpdate" -version = "1.0.3" +name = "either" +version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" +checksum = "91622ff5e7162018101f2fea40d6ebf4a78bbe5a49736a2020649edf9693679e" [[package]] -name = "humantime" -version = "2.3.0" +name = "embassy-futures" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "135b12329e5e3ce057a9f972339ea52bc954fe1e9358ef27f95e89716fbc5424" +checksum = "dc2d050bdc5c21e0862a89256ed8029ae6c290a93aecefc73084b3002cdebb01" [[package]] -name = "hyper" -version = "1.8.1" +name = "embassy-time" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ab2d4f250c3d7b1c9fcdff1cece94ea4e2dfbec68614f7b87cb205f24ca9d11" +checksum = "592b0c143ec626e821d4d90da51a2bd91d559d6c442b7c74a47d368c9e23d97a" dependencies = [ - "atomic-waker", - "bytes", - "futures-channel", + "cfg-if", + "critical-section", + "document-features", + "embassy-time-driver", + "embedded-hal 0.2.7", + "embedded-hal 1.0.0", + "embedded-hal-async", "futures-core", - "h2", - "http", - "http-body", - "httparse", - "httpdate", - "itoa", - "pin-project-lite", - "pin-utils", - "smallvec", - "tokio", - "want", ] [[package]] -name = "hyper-rustls" -version = "0.27.7" +name = "embassy-time-driver" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58" +checksum = "6ee71af1b3a0deaa53eaf2d39252f83504c853646e472400b763060389b9fcc9" dependencies = [ - "http", - "hyper", - "hyper-util", - "log", - "rustls", - "rustls-native-certs", - "rustls-pki-types", - "tokio", - "tokio-rustls", - "tower-service", - "webpki-roots 1.0.5", + "document-features", ] [[package]] -name = "hyper-util" -version = "0.1.19" +name = "embedded-hal" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "727805d60e7938b76b826a6ef209eb70eaa1812794f9424d4a4e2d740662df5f" +checksum = "35949884794ad573cf46071e41c9b60efb0cb311e3ca01f7af807af1debc66ff" dependencies = [ - "base64", - "bytes", - "futures-channel", - "futures-core", - "futures-util", - "http", - "http-body", - "hyper", - "ipnet", - "libc", - "percent-encoding", - "pin-project-lite", - "socket2", - "tokio", - "tower-service", - "tracing", + "nb 0.1.3", + "void", ] [[package]] -name = "iana-time-zone" -version = "0.1.64" +name = "embedded-hal" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33e57f83510bb73707521ebaffa789ec8caf86f9657cad665b092b581d40e9fb" -dependencies = [ - "android_system_properties", - "core-foundation-sys", - "iana-time-zone-haiku", - "js-sys", - "log", - "wasm-bindgen", - "windows-core", -] +checksum = "361a90feb7004eca4019fb28352a9465666b24f840f5c3cddf0ff13920590b89" [[package]] -name = "iana-time-zone-haiku" -version = "0.1.2" +name = "embedded-hal-async" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +checksum = "0c4c685bbef7fe13c3c6dd4da26841ed3980ef33e841cddfa15ce8a8fb3f1884" dependencies = [ - "cc", + "embedded-hal 1.0.0", ] [[package]] -name = "icu_collections" -version = "2.1.1" +name = "encode_unicode" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0" + +[[package]] +name = "entities" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43" +checksum = "b5320ae4c3782150d900b79807611a59a99fc9a1d61d686faafc24b93fc8d7ca" + +[[package]] +name = "enum-as-inner" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1e6a265c649f3f5979b601d26f1d05ada116434c87741c9493cb56218f76cbc" dependencies = [ - "displaydoc", - "potential_utf", - "yoke", - "zerofrom", - "zerovec", + "heck", + "proc-macro2", + "quote", + "syn", ] [[package]] -name = "icu_locale_core" -version = "2.1.1" +name = "enumset" +version = "1.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6" +checksum = "839c4174b41e75c8f7306110b2c51996a293b8d1d850edd529011841d9fede7d" dependencies = [ - "displaydoc", - "litemap", - "tinystr", - "writeable", - "zerovec", + "enumset_derive", + "serde", ] [[package]] -name = "icu_normalizer" -version = "2.1.1" +name = "enumset_derive" +version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599" +checksum = "4bd536557b58c682b217b8fb199afdff47cd3eff260623f19e77074eb073d63a" dependencies = [ - "icu_collections", - "icu_normalizer_data", - "icu_properties", - "icu_provider", - "smallvec", - "zerovec", + "darling 0.21.3", + "proc-macro2", + "quote", + "syn", ] [[package]] -name = "icu_normalizer_data" -version = "2.1.1" +name = "equator" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a" +checksum = "4711b213838dfee0117e3be6ac926007d7f433d7bbe33595975d4190cb07e6fc" +dependencies = [ + "equator-macro", +] [[package]] -name = "icu_properties" -version = "2.1.2" +name = "equator-macro" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "020bfc02fe870ec3a66d93e677ccca0562506e5872c650f893269e08615d74ec" +checksum = "44f23cf4b44bfce11a86ace86f8a73ffdec849c9fd00a386a53d278bd9e81fb3" dependencies = [ - "icu_collections", - "icu_locale_core", - "icu_properties_data", - "icu_provider", - "zerotrie", - "zerovec", + "proc-macro2", + "quote", + "syn", ] [[package]] -name = "icu_properties_data" -version = "2.1.2" +name = "equivalent" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "616c294cf8d725c6afcd8f55abc17c56464ef6211f9ed59cccffe534129c77af" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] -name = "icu_provider" -version = "2.1.1" +name = "errno" +version = "0.3.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ - "displaydoc", - "icu_locale_core", - "writeable", - "yoke", - "zerofrom", - "zerotrie", - "zerovec", + "libc", + "windows-sys 0.61.2", ] [[package]] -name = "id-arena" -version = "2.3.0" +name = "esaxx-rs" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" +checksum = "d817e038c30374a4bcb22f94d0a8a0e216958d4c3dcde369b1439fec4bdda6e6" [[package]] -name = "ident_case" -version = "1.0.1" +name = "event-listener" +version = "5.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" +checksum = "e13b66accf52311f30a0db42147dadea9850cb48cd070028831ae5f5d4b856ab" +dependencies = [ + "concurrent-queue", + "parking", + "pin-project-lite", +] [[package]] -name = "idna" -version = "0.5.0" +name = "event-listener-strategy" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" +checksum = "8be9f3dfaaffdae2972880079a491a1a8bb7cbed0b8dd7a347f668b4150a3b93" dependencies = [ - "unicode-bidi", - "unicode-normalization", + "event-listener", + "pin-project-lite", ] [[package]] -name = "idna" -version = "1.1.0" +name = "exr" +version = "1.74.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" +checksum = "4300e043a56aa2cb633c01af81ca8f699a321879a7854d3896a0ba89056363be" dependencies = [ - "idna_adapter", + "bit_field", + "half", + "lebe", + "miniz_oxide", + "rayon-core", "smallvec", - "utf8_iter", + "zune-inflate", ] [[package]] -name = "idna_adapter" -version = "1.2.1" +name = "fastrand" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" -dependencies = [ - "icu_normalizer", - "icu_properties", -] +checksum = "9f1f227452a390804cdb637b74a86990f2a7d7ba4b7d5693aac9b4dd6defd8d6" [[package]] -name = "ignore" -version = "0.4.26" +name = "fax" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b915661dd01db3f05050265b2477bcc6527b3792388e2749b41623cc592be67d" -dependencies = [ - "crossbeam-deque", - "globset", - "log", - "memchr", - "regex-automata", - "same-file", - "walkdir", - "winapi-util", +checksum = "caf1079563223d5d59d83c85886a56e586cfd5c1a26292e971a0fa266531ac5a" + +[[package]] +name = "fdeflate" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e6853b52649d4ac5c0bd02320cddc5ba956bdb407c4b75a2c6b75bf51500f8c" +dependencies = [ + "simd-adler32", ] [[package]] -name = "indexmap" -version = "2.13.0" +name = "filetime" +version = "0.2.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017" +checksum = "5c287a33c7f0a620c38e641e7f60827713987b3c0f26e8ddc9462cc69cf75759" dependencies = [ - "equivalent", - "hashbrown 0.16.1", - "serde", - "serde_core", + "cfg-if", + "libc", ] [[package]] -name = "inflections" -version = "1.1.1" +name = "find-msvc-tools" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a257582fdcde896fd96463bf2d40eefea0580021c0712a0e2b028b60b47a837a" +checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" [[package]] -name = "inherent" -version = "1.0.13" +name = "fixedbitset" +version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c727f80bfa4a6c6e2508d2f05b6f4bfce242030bd88ed15ae5331c5b5d30fba7" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.114", -] +checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99" [[package]] -name = "inout" -version = "0.1.4" +name = "flate2" +version = "1.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01" +checksum = "843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c" dependencies = [ - "generic-array", + "crc32fast", + "miniz_oxide", ] [[package]] -name = "inventory" -version = "0.3.21" +name = "float-ord" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc61209c082fbeb19919bee74b176221b27223e27b65d781eb91af24eb1fb46e" -dependencies = [ - "rustversion", -] +checksum = "8ce81f49ae8a0482e4c55ea62ebbd7e5a686af544c00b9d090bba3ff9be97b3d" [[package]] -name = "ipnet" -version = "2.11.0" +name = "float4" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" +checksum = "9a5404bf31d22893d61cf24d4dda149d8e6b2ff07601c3cb3be651031f61a4ed" [[package]] -name = "iri-string" -version = "0.7.10" +name = "float8" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c91338f0783edbd6195decb37bae672fd3b165faffb89bf7b9e6942f8b1a731a" +checksum = "c2d1f04709a8ac06e8e8042875a3c466cc4832d3c1a18dbcb9dba3c6e83046bc" dependencies = [ - "memchr", - "serde", + "half", + "num-traits", + "rand 0.9.4", + "rand_distr 0.5.1", ] [[package]] -name = "is_ci" -version = "1.2.0" +name = "fnv" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7655c9839580ee829dfacba1d1278c2b7883e50a277ff7541299489d6bdfdc45" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] -name = "is_terminal_polyfill" -version = "1.70.2" +name = "foldhash" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" [[package]] -name = "itertools" -version = "0.13.0" +name = "foldhash" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" -dependencies = [ - "either", -] +checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" [[package]] -name = "itertools" -version = "0.14.0" +name = "form_urlencoded" +version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" +checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" dependencies = [ - "either", + "percent-encoding", ] [[package]] -name = "itoa" -version = "1.0.17" +name = "futures-channel" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2" +checksum = "07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d" +dependencies = [ + "futures-core", + "futures-sink", +] [[package]] -name = "jni" -version = "0.21.1" +name = "futures-core" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a87aa2bb7d2af34197c04845522473242e1aa17c12f4935d5856491a7fb8c97" -dependencies = [ - "cesu8", - "cfg-if", - "combine", - "jni-sys", - "log", - "thiserror 1.0.69", - "walkdir", - "windows-sys 0.45.0", -] +checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d" [[package]] -name = "jni-sys" -version = "0.3.0" +name = "futures-io" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" +checksum = "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718" [[package]] -name = "jobserver" -version = "0.1.34" +name = "futures-lite" +version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" +checksum = "f78e10609fe0e0b3f4157ffab1876319b5b0db102a2c60dc4626306dc46b44ad" dependencies = [ - "getrandom 0.3.4", - "libc", + "fastrand", + "futures-core", + "futures-io", + "parking", + "pin-project-lite", ] [[package]] -name = "js-sys" -version = "0.3.83" +name = "futures-macro" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "464a3709c7f55f1f721e5389aa6ea4e3bc6aba669353300af094b29ffbdde1d8" +checksum = "e835b70203e41293343137df5c0664546da5745f82ec9b84d40be8336958447b" dependencies = [ - "once_cell", - "wasm-bindgen", + "proc-macro2", + "quote", + "syn", ] [[package]] -name = "jsonwebtoken" -version = "9.3.1" +name = "futures-sink" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a87cc7a48537badeae96744432de36f4be2b4a34a05a5ef32e9dd8a1c169dde" -dependencies = [ - "base64", - "js-sys", - "pem", - "ring", - "serde", - "serde_json", - "simple_asn1", -] +checksum = "c39754e157331b013978ec91992bde1ac089843443c49cbc7f46150b0fad0893" [[package]] -name = "kinded" -version = "0.3.0" +name = "futures-task" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce4bdbb2f423660b19f0e9f7115182214732d8dd5f840cd0a3aee3e22562f34c" -dependencies = [ - "kinded_macros", -] +checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393" [[package]] -name = "kinded_macros" -version = "0.3.0" +name = "futures-timer" +version = "3.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a13b4ddc5dcb32f45dac3d6f606da2a52fdb9964a18427e63cd5ef6c0d13288d" -dependencies = [ - "convert_case", - "proc-macro2", - "quote", - "syn 2.0.114", -] +checksum = "af43fadb8a98512d547e37b4e92e0ced13e205c061b87b4623eff01d918d6968" [[package]] -name = "lazy-regex" -version = "3.6.0" +name = "futures-util" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6bae91019476d3ec7147de9aa291cadb6d870abf2f3015d2da73a90325ac1496" +checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6" dependencies = [ - "lazy-regex-proc_macros", - "once_cell", - "regex", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "slab", ] [[package]] -name = "lazy-regex-proc_macros" -version = "3.6.0" +name = "gemm" +version = "0.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4de9c1e1439d8b7b3061b2d209809f447ca33241733d9a3c01eabf2dc8d94358" +checksum = "aa0673db364b12263d103b68337a68fbecc541d6f6b61ba72fe438654709eacb" dependencies = [ - "proc-macro2", - "quote", - "regex", - "syn 2.0.114", + "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 = "lazy_static" -version = "1.5.0" +name = "gemm-c32" +version = "0.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" +checksum = "086936dbdcb99e37aad81d320f98f670e53c1e55a98bee70573e83f95beb128c" dependencies = [ - "spin", + "dyn-stack", + "gemm-common", + "num-complex", + "num-traits", + "paste", + "raw-cpuid", + "seq-macro", ] [[package]] -name = "leb128fmt" -version = "0.1.0" +name = "gemm-c64" +version = "0.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" +checksum = "20c8aeeeec425959bda4d9827664029ba1501a90a0d1e6228e48bef741db3a3f" +dependencies = [ + "dyn-stack", + "gemm-common", + "num-complex", + "num-traits", + "paste", + "raw-cpuid", + "seq-macro", +] [[package]] -name = "libc" -version = "0.2.179" +name = "gemm-common" +version = "0.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5a2d376baa530d1238d133232d15e239abad80d05838b4b59354e5268af431f" +checksum = "88027625910cc9b1085aaaa1c4bc46bb3a36aad323452b33c25b5e4e7c8e2a3e" +dependencies = [ + "bytemuck", + "dyn-stack", + "half", + "libm", + "num-complex", + "num-traits", + "once_cell", + "paste", + "pulp", + "raw-cpuid", + "rayon", + "seq-macro", + "sysctl", +] [[package]] -name = "libm" -version = "0.2.15" +name = "gemm-f16" +version = "0.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de" +checksum = "e3df7a55202e6cd6739d82ae3399c8e0c7e1402859b30e4cb780e61525d9486e" +dependencies = [ + "dyn-stack", + "gemm-common", + "gemm-f32", + "half", + "num-complex", + "num-traits", + "paste", + "raw-cpuid", + "rayon", + "seq-macro", +] [[package]] -name = "libredox" -version = "0.1.12" +name = "gemm-f32" +version = "0.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d0b95e02c851351f877147b7deea7b1afb1df71b63aa5f8270716e0c5720616" +checksum = "02e0b8c9da1fbec6e3e3ab2ce6bc259ef18eb5f6f0d3e4edf54b75f9fd41a81c" dependencies = [ - "bitflags", - "libc", - "redox_syscall 0.7.0", + "dyn-stack", + "gemm-common", + "num-complex", + "num-traits", + "paste", + "raw-cpuid", + "seq-macro", ] [[package]] -name = "libsqlite3-sys" -version = "0.30.1" +name = "gemm-f64" +version = "0.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e99fb7a497b1e3339bc746195567ed8d3e24945ecd636e3619d20b9de9e9149" +checksum = "056131e8f2a521bfab322f804ccd652520c79700d81209e9d9275bbdecaadc6a" dependencies = [ - "pkg-config", - "vcpkg", + "dyn-stack", + "gemm-common", + "num-complex", + "num-traits", + "paste", + "raw-cpuid", + "seq-macro", ] [[package]] -name = "linked-hash-map" -version = "0.5.6" +name = "generic-array" +version = "0.14.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] [[package]] -name = "linux-raw-sys" -version = "0.11.0" +name = "getrandom" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" +checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "wasi", + "wasm-bindgen", +] [[package]] -name = "litemap" -version = "0.8.1" +name = "getrandom" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "r-efi 5.3.0", + "wasip2", + "wasm-bindgen", +] [[package]] -name = "local-ip-address" -version = "0.6.8" +name = "getrandom" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a60bf300a990b2d1ebdde4228e873e8e4da40d834adbf5265f3da1457ede652" +checksum = "300e883d756b2e4ec94e02791f39b04b522276138852cfc41d9fb7e904106099" dependencies = [ + "cfg-if", "libc", - "neli", - "thiserror 2.0.17", - "windows-sys 0.61.2", + "r-efi 6.0.0", + "rand_core 0.10.1", ] [[package]] -name = "lock_api" -version = "0.4.14" +name = "gif" +version = "0.14.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" +checksum = "ee8cfcc411d9adbbaba82fb72661cc1bcca13e8bba98b364e62b2dba8f960159" dependencies = [ - "scopeguard", + "color_quant", + "weezl", ] [[package]] -name = "log" -version = "0.4.29" +name = "gimli" +version = "0.32.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" +checksum = "e629b9b98ef3dd8afe6ca2bd0f89306cec16d43d907889945bc5d6687f2f13c7" [[package]] -name = "lru-slab" -version = "0.1.2" +name = "gl_generator" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" +checksum = "1a95dfc23a2b4a9a2f5ab41d194f8bfda3cabec42af4e39f08c339eb2a0c124d" +dependencies = [ + "khronos_api", + "log", + "xml-rs", +] [[package]] -name = "matchers" -version = "0.2.0" +name = "glob" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1525a2a28c7f4fa0fc98bb91ae755d1e2d1505079e05539e35bc876b5d65ae9" -dependencies = [ - "regex-automata", -] +checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" [[package]] -name = "md-5" -version = "0.10.6" +name = "glow" +version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" +checksum = "29038e1c483364cc6bb3cf78feee1816002e127c331a1eec55a4d202b9e1adb5" dependencies = [ - "cfg-if", - "digest", + "js-sys", + "slotmap", + "wasm-bindgen", + "web-sys", ] [[package]] -name = "memchr" -version = "2.7.6" +name = "glutin_wgl_sys" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" +checksum = "2c4ee00b289aba7a9e5306d57c2d05499b2e5dc427f84ac708bd2c090212cf3e" +dependencies = [ + "gl_generator", +] [[package]] -name = "miette" -version = "7.6.0" +name = "gpu-allocator" +version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f98efec8807c63c752b5bd61f862c165c115b0a35685bdcfd9238c7aeb592b7" +checksum = "51255ea7cfaadb6c5f1528d43e92a82acb2b96c43365989a28b2d44ee38f8795" dependencies = [ - "backtrace", - "backtrace-ext", - "cfg-if", - "miette-derive", - "owo-colors", - "supports-color", - "supports-hyperlinks", - "supports-unicode", - "terminal_size", - "textwrap", - "unicode-width 0.1.14", + "ash", + "hashbrown 0.16.1", + "log", + "presser", + "thiserror 2.0.18", + "windows", ] [[package]] -name = "miette-derive" -version = "7.6.0" +name = "gpu-descriptor" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db5b29714e950dbb20d5e6f74f9dcec4edbcc1067bb7f8ed198c097b8c1a818b" +checksum = "b89c83349105e3732062a895becfc71a8f921bb71ecbbdd8ff99263e3b53a0ca" dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.114", + "bitflags", + "gpu-descriptor-types", + "hashbrown 0.15.5", ] [[package]] -name = "migration" -version = "0.1.0" +name = "gpu-descriptor-types" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdf242682df893b86f33a73828fb09ca4b2d3bb6cc95249707fc684d27484b91" dependencies = [ - "sea-orm", - "sea-orm-migration", - "tokio", + "bitflags", ] [[package]] -name = "mime" -version = "0.3.17" +name = "h2" +version = "0.4.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" +checksum = "6cb093c84e8bd9b188d4c4a8cb6579fc016968d14c99882163cd3ff402a4f155" +dependencies = [ + "atomic-waker", + "bytes", + "fnv", + "futures-core", + "futures-sink", + "http", + "indexmap", + "slab", + "tokio", + "tokio-util", + "tracing", +] [[package]] -name = "mime-infer" -version = "4.0.1" +name = "half" +version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a10bc91d55685b82739d1dc95ec6e40485695cfe07b0a3abc1a82df17c40a0e5" +checksum = "6ea2d84b969582b4b1864a92dc5d27cd2b77b622a8d79306834f1be5ba20d84b" dependencies = [ - "mime", - "unicase", + "bytemuck", + "cfg-if", + "crunchy", + "num-traits", + "rand 0.9.4", + "rand_distr 0.5.1", + "serde", + "zerocopy", ] [[package]] -name = "minimal-lexical" +name = "hashbrown" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" +dependencies = [ + "ahash", +] + +[[package]] +name = "hashbrown" +version = "0.15.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" +dependencies = [ + "foldhash 0.1.5", +] + +[[package]] +name = "hashbrown" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" +dependencies = [ + "allocator-api2", + "equivalent", + "foldhash 0.2.0", + "serde", + "serde_core", +] + +[[package]] +name = "hashbrown" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "hermit-abi" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" + +[[package]] +name = "hexf-parse" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" +checksum = "dfa686283ad6dd069f105e5ab091b04c62850d3e4cf5d67debad1933f55023df" [[package]] -name = "miniz_oxide" -version = "0.8.9" +name = "hmac" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" dependencies = [ - "adler2", - "simd-adler32", + "digest", ] [[package]] -name = "mio" -version = "1.1.1" +name = "http" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a69bcab0ad47271a0234d9422b131806bf3968021e5dc9328caf2d4cd58557fc" +checksum = "6970f50e31d6fc17d3fa27329444bfa74e196cf62e95052a3f6fee181dba6425" dependencies = [ - "libc", - "wasi", - "windows-sys 0.61.2", + "bytes", + "itoa", ] [[package]] -name = "multer" -version = "3.1.0" +name = "http-body" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83e87776546dc87511aa5ee218730c92b666d7264ab6ed41f9d215af9cd5224b" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" dependencies = [ "bytes", - "encoding_rs", - "futures-util", "http", - "httparse", - "memchr", - "mime", - "spin", - "version_check", ] [[package]] -name = "multimap" -version = "0.10.1" +name = "http-body-util" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d87ecb2933e8aeadb3e3a02b828fed80a7528047e68b4f424523a0981a3a084" +checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" dependencies = [ - "serde", + "bytes", + "futures-core", + "http", + "http-body", + "pin-project-lite", ] [[package]] -name = "mvc-helpers" -version = "0.1.0" -source = "git+ssh://git@github.com/wack/mvc-helpers.git?branch=trunk#018fbcffc61224b9689caac3ad13633f61e7bf04" +name = "httparse" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" + +[[package]] +name = "hyper" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55281c53a1894c864990125767da440a4e630446785086f52523b20033b74498" dependencies = [ - "chrono", - "clap", - "derive-getters", - "jsonwebtoken", - "mvc-helpers-macros", - "nutype", - "regex", - "salvo 0.89.3", - "serde", - "thiserror 2.0.17", - "tracing", - "uuid", + "atomic-waker", + "bytes", + "futures-channel", + "futures-core", + "h2", + "http", + "http-body", + "httparse", + "itoa", + "pin-project-lite", + "smallvec", + "tokio", + "want", ] [[package]] -name = "mvc-helpers-macros" -version = "0.1.0" -source = "git+ssh://git@github.com/wack/mvc-helpers.git?branch=trunk#018fbcffc61224b9689caac3ad13633f61e7bf04" +name = "hyper-rustls" +version = "0.27.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33ca68d021ef39cf6463ab54c1d0f5daf03377b70561305bb89a8f83aab66e0f" dependencies = [ - "nutype", - "proc-macro2", - "quote", - "syn 2.0.114", + "http", + "hyper", + "hyper-util", + "rustls", + "tokio", + "tokio-rustls", + "tower-service", + "webpki-roots 1.0.8", ] [[package]] -name = "neli" -version = "0.7.3" +name = "hyper-util" +version = "0.1.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e23bebbf3e157c402c4d5ee113233e5e0610cc27453b2f07eefce649c7365dcc" +checksum = "96547c2556ec9d12fb1578c4eaf448b04993e7fb79cbaad930a656880a6bdfa0" dependencies = [ - "bitflags", - "byteorder", - "derive_builder", - "getset", + "base64 0.22.1", + "bytes", + "futures-channel", + "futures-util", + "http", + "http-body", + "hyper", + "ipnet", "libc", - "log", - "neli-proc-macros", - "parking_lot", + "percent-encoding", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", ] [[package]] -name = "neli-proc-macros" -version = "0.2.2" +name = "icu_collections" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05d8d08c6e98f20a62417478ebf7be8e1425ec9acecc6f63e22da633f6b71609" +checksum = "2984d1cd16c883d7935b9e07e44071dca8d917fd52ecc02c04d5fa0b5a3f191c" dependencies = [ - "either", - "proc-macro2", - "quote", - "serde", - "syn 2.0.114", + "displaydoc", + "potential_utf", + "utf8_iter", + "yoke", + "zerofrom", + "zerovec", ] [[package]] -name = "nix" -version = "0.30.1" +name = "icu_locale_core" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74523f3a35e05aba87a1d978330aef40f67b0304ac79c1c00b294c9830543db6" +checksum = "92219b62b3e2b4d88ac5119f8904c10f8f61bf7e95b640d25ba3075e6cac2c29" dependencies = [ - "bitflags", - "cfg-if", - "cfg_aliases", - "libc", + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", ] [[package]] -name = "nom" -version = "7.1.3" +name = "icu_normalizer" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +checksum = "c56e5ee99d6e3d33bd91c5d85458b6005a22140021cc324cea84dd0e72cff3b4" dependencies = [ - "memchr", - "minimal-lexical", + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "zerovec", ] [[package]] -name = "nom_locate" -version = "4.2.0" +name = "icu_normalizer_data" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e3c83c053b0713da60c5b8de47fe8e494fe3ece5267b2f23090a07a053ba8f3" -dependencies = [ - "bytecount", - "memchr", - "nom", -] +checksum = "da3be0ae77ea334f4da67c12f149704f19f81d1adf7c51cf482943e84a2bad38" [[package]] -name = "nu-ansi-term" -version = "0.50.3" +name = "icu_properties" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" +checksum = "bee3b67d0ea5c2cca5003417989af8996f8604e34fb9ddf96208a033901e70de" dependencies = [ - "windows-sys 0.61.2", + "icu_collections", + "icu_locale_core", + "icu_properties_data", + "icu_provider", + "zerotrie", + "zerovec", ] [[package]] -name = "num-bigint" -version = "0.4.6" +name = "icu_properties_data" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +checksum = "8e2bbb201e0c04f7b4b3e14382af113e17ba4f63e2c9d2ee626b720cbce54a14" + +[[package]] +name = "icu_provider" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "139c4cf31c8b5f33d7e199446eff9c1e02decfc2f0eec2c8d71f65befa45b421" dependencies = [ - "num-integer", - "num-traits", + "displaydoc", + "icu_locale_core", + "writeable", + "yoke", + "zerofrom", + "zerotrie", + "zerovec", ] [[package]] -name = "num-bigint-dig" -version = "0.8.6" +name = "ident_case" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e661dda6640fad38e827a6d4a310ff4763082116fe217f279885c97f511bb0b7" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "idna" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" dependencies = [ - "lazy_static", - "libm", - "num-integer", - "num-iter", - "num-traits", - "rand 0.8.5", + "idna_adapter", "smallvec", - "zeroize", + "utf8_iter", ] [[package]] -name = "num-conv" -version = "0.2.2" +name = "idna_adapter" +version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "521739c6d2bac4aa25192232afe6841231376b2b26d4d9fae5ecf8ca5772e441" +checksum = "cb68373c0d6620ef8105e855e7745e18b0d00d3bdb07fb532e434244cdb9a714" +dependencies = [ + "icu_normalizer", + "icu_properties", +] [[package]] -name = "num-integer" -version = "0.1.46" +name = "image" +version = "0.25.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +checksum = "85ab80394333c02fe689eaf900ab500fbd0c2213da414687ebf995a65d5a6104" dependencies = [ + "bytemuck", + "byteorder-lite", + "color_quant", + "exr", + "gif", + "image-webp", + "moxcms", "num-traits", + "png", + "qoi", + "ravif", + "rayon", + "rgb", + "tiff", + "zune-core", + "zune-jpeg", ] [[package]] -name = "num-iter" -version = "0.1.45" +name = "image-webp" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" +checksum = "525e9ff3e1a4be2fbea1fdf0e98686a6d98b4d8f937e1bf7402245af1909e8c3" dependencies = [ - "autocfg", - "num-integer", - "num-traits", + "byteorder-lite", + "quick-error", ] [[package]] -name = "num-traits" -version = "0.2.19" +name = "imgref" +version = "1.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +checksum = "89194689a993ab15268672e99e7b0e19da2da3268ac682e8f02d29d4d1434cd7" + +[[package]] +name = "indexmap" +version = "2.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9" dependencies = [ - "autocfg", - "libm", + "equivalent", + "hashbrown 0.17.1", ] [[package]] -name = "num_threads" -version = "0.1.7" +name = "indicatif" +version = "0.18.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c7398b9c8b70908f6371f47ed36737907c87c52af34c268fed0bf0ceb92ead9" +checksum = "25470f23803092da7d239834776d653104d551bc4d7eacaf31e6837854b8e9eb" dependencies = [ - "libc", + "console", + "portable-atomic", + "unicode-width", + "unit-prefix", + "web-time", ] [[package]] -name = "nutype" -version = "0.6.2" +name = "inflections" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a257582fdcde896fd96463bf2d40eefea0580021c0712a0e2b028b60b47a837a" + +[[package]] +name = "inout" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70587a780088c67dad31bf722b875c5616096b4d8c0ded8b7de03294ffb9bbb5" +checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01" dependencies = [ - "nutype_macros", + "generic-array", ] [[package]] -name = "nutype_macros" -version = "0.6.2" +name = "interpolate_name" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "148934b975faeddd8f0679d7cf11280b50c4c5495d6fe72bdaf07c932874b404" +checksum = "c34819042dc3d3971c46c2190835914dfbe0c3c13f61449b2997f4e9722dfa60" dependencies = [ - "cfg-if", - "kinded", "proc-macro2", "quote", - "regex", - "rustc_version", - "syn 2.0.114", - "urlencoding", + "syn", ] [[package]] -name = "object" -version = "0.37.3" +name = "ipnet" +version = "2.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff76201f031d8863c38aa7f905eca4f53abbfa15f609db4277d44cd8938f33fe" +checksum = "d98f6fed1fde3f8c21bc40a1abb88dd75e67924f9cffc3ef95607bad8017f8e2" + +[[package]] +name = "is_terminal_polyfill" +version = "1.70.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" + +[[package]] +name = "itertools" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" dependencies = [ - "memchr", + "either", ] [[package]] -name = "oid-registry" -version = "0.8.1" +name = "itertools" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12f40cff3dde1b6087cc5d5f5d4d65712f34016a03ed60e9c08dcc392736b5b7" +checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" dependencies = [ - "asn1-rs", + "either", ] [[package]] -name = "once_cell" -version = "1.21.3" +name = "itoa" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" [[package]] -name = "once_cell_polyfill" -version = "1.70.2" +name = "jni-sys" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" +checksum = "41a652e1f9b6e0275df1f15b32661cf0d4b78d4d87ddec5e0c3c20f097433258" +dependencies = [ + "jni-sys 0.4.1", +] [[package]] -name = "opaque-debug" -version = "0.3.1" +name = "jni-sys" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" +checksum = "c6377a88cb3910bee9b0fa88d4f42e1d2da8e79915598f65fb0c7ee14c878af2" +dependencies = [ + "jni-sys-macros", +] [[package]] -name = "openapiv3" -version = "2.2.0" +name = "jni-sys-macros" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c8d427828b22ae1fff2833a03d8486c2c881367f1c336349f307f321e7f4d05" +checksum = "38c0b942f458fe50cdac086d2f946512305e5631e720728f2a61aabcd47a6264" dependencies = [ - "indexmap", - "serde", - "serde_json", + "quote", + "syn", +] + +[[package]] +name = "jobserver" +version = "0.1.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" +dependencies = [ + "getrandom 0.3.4", + "libc", ] [[package]] -name = "openssl-probe" -version = "0.2.0" +name = "js-sys" +version = "0.3.103" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53b44bfcdb3f8d5837a46dae1ca9660a837176eee74a28b229bc626816589102" +dependencies = [ + "cfg-if", + "futures-util", + "wasm-bindgen", +] + +[[package]] +name = "khronos-egl" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6aae1df220ece3c0ada96b8153459b67eebe9ae9212258bb0134ae60416fdf76" +dependencies = [ + "libc", + "libloading 0.8.9", + "pkg-config", +] + +[[package]] +name = "khronos_api" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2db585e1d738fc771bf08a151420d3ed193d9d895a36df7f6f8a9456b911ddc" + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "lebe" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f50d9b3dabb09ecd771ad0aa242ca6894994c130308ca3d7684634df8037391" +checksum = "7a79a3332a6609480d7d0c9eab957bca6b455b91bb84e66d19f5ff66294b85b8" [[package]] -name = "opentelemetry" -version = "0.31.0" +name = "libc" +version = "0.2.186" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b84bcd6ae87133e903af7ef497404dda70c60d0ea14895fc8a5e6722754fc2a0" -dependencies = [ - "futures-core", - "futures-sink", - "js-sys", - "pin-project-lite", - "thiserror 2.0.17", - "tracing", -] +checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66" [[package]] -name = "opentelemetry-http" -version = "0.31.0" +name = "libfuzzer-sys" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7a6d09a73194e6b66df7c8f1b680f156d916a1a942abf2de06823dd02b7855d" +checksum = "a9fd2f41a1cba099f79a0b6b6c35656cf7c03351a7bae8ff0f28f25270f929d2" dependencies = [ - "async-trait", - "bytes", - "http", - "opentelemetry", - "reqwest 0.12.28", + "arbitrary", + "cc", ] [[package]] -name = "opentelemetry-otlp" -version = "0.31.0" +name = "libloading" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a2366db2dca4d2ad033cad11e6ee42844fd727007af5ad04a1730f4cb8163bf" +checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55" dependencies = [ - "http", - "opentelemetry", - "opentelemetry-http", - "opentelemetry-proto", - "opentelemetry_sdk", - "prost", - "reqwest 0.12.28", - "thiserror 2.0.17", - "tonic", - "tracing", + "cfg-if", + "windows-link", ] [[package]] -name = "opentelemetry-proto" -version = "0.31.0" +name = "libloading" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7175df06de5eaee9909d4805a3d07e28bb752c34cab57fa9cff549da596b30f" +checksum = "754ca22de805bb5744484a5b151a9e1a8e837d5dc232c2d7d8c2e3492edc8b60" dependencies = [ - "opentelemetry", - "opentelemetry_sdk", - "prost", - "tonic", - "tonic-prost", + "cfg-if", + "windows-link", ] [[package]] -name = "opentelemetry-semantic-conventions" -version = "0.31.0" +name = "liblzma" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e62e29dfe041afb8ed2a6c9737ab57db4907285d999ef8ad3a59092a36bdc846" +checksum = "45aec2360b3933207e27908049d8e4df4e476b58180afb1e56b2a4fb72efe4ba" +dependencies = [ + "liblzma-sys", + "num_cpus", +] [[package]] -name = "opentelemetry_sdk" -version = "0.31.0" +name = "liblzma-sys" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e14ae4f5991976fd48df6d843de219ca6d31b01daaab2dad5af2badeded372bd" +checksum = "a046c7f353ba30f810545151e04f63545833803f5b86ee3ddf1517247fe560a5" dependencies = [ - "futures-channel", - "futures-executor", - "futures-util", - "opentelemetry", - "percent-encoding", - "rand 0.9.2", - "thiserror 2.0.17", - "tokio", - "tokio-stream", + "cc", + "libc", + "pkg-config", ] [[package]] -name = "ordered-float" -version = "4.6.0" +name = "libm" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7bb71e1b3fa6ca1c61f383464aaf2bb0e2f8e772a1f01d486832464de363b951" -dependencies = [ - "num-traits", -] +checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" [[package]] -name = "ouroboros" -version = "0.18.5" +name = "libredox" +version = "0.1.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e0f050db9c44b97a94723127e6be766ac5c340c48f2c4bb3ffa11713744be59" +checksum = "f02ab6bace2054fb888a3c16f990117b579d14a3088e472d63c6011fa185c9d3" dependencies = [ - "aliasable", - "ouroboros_macro", - "static_assertions", + "libc", ] [[package]] -name = "ouroboros_macro" -version = "0.18.5" +name = "linux-raw-sys" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c7028bdd3d43083f6d8d4d5187680d0d3560d54df4cc9d752005268b41e64d0" -dependencies = [ - "heck 0.4.1", - "proc-macro2", - "proc-macro2-diagnostics", - "quote", - "syn 2.0.114", -] +checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" [[package]] -name = "owo-colors" -version = "4.2.3" +name = "litemap" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c6901729fa79e91a0913333229e9ca5dc725089d1c363b2f4b4760709dc4a52" +checksum = "92daf443525c4cce67b150400bc2316076100ce0b3686209eb8cf3c31612e6f0" [[package]] -name = "parking" -version = "2.2.1" +name = "litrs" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" +checksum = "11d3d7f243d5c5a8b9bb5d6dd2b1602c0cb0b9db1621bafc7ed66e35ff9fe092" [[package]] -name = "parking_lot" -version = "0.12.5" +name = "lock_api" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" dependencies = [ - "lock_api", - "parking_lot_core", + "scopeguard", ] [[package]] -name = "parking_lot_core" -version = "0.9.12" +name = "log" +version = "0.4.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" -dependencies = [ - "cfg-if", - "libc", - "redox_syscall 0.5.18", - "smallvec", - "windows-link", -] +checksum = "0ceec5bc11778974d1bcb055b18002eba7f4b3518b6a0081b3af5f21666da9ad" [[package]] -name = "peg" -version = "0.6.3" +name = "loop9" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f76678828272f177ac33b7e2ac2e3e73cc6c1cd1e3e387928aa69562fa51367" +checksum = "0fae87c125b03c1d2c0150c90365d7d6bcc53fb73a9acaef207d2d065860f062" dependencies = [ - "peg-macros", - "peg-runtime", + "imgref", ] [[package]] -name = "peg-macros" -version = "0.6.3" +name = "lru-slab" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "636d60acf97633e48d266d7415a9355d4389cea327a193f87df395d88cd2b14d" -dependencies = [ - "peg-runtime", - "proc-macro2", - "quote", -] +checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" [[package]] -name = "peg-runtime" -version = "0.6.3" +name = "macerator" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9555b1514d2d99d78150d3c799d4c357a3e2c2a8062cd108e93a06d9057629c5" +checksum = "508a2f720538bb7e3ea3cb6d098615b107cb82ae387d77d906276905e9ec894b" +dependencies = [ + "bytemuck", + "cfg_aliases", + "half", + "macerator-macros", + "moddef", + "num-traits", + "paste", + "rustc_version", +] [[package]] -name = "pem" -version = "3.0.6" +name = "macerator-macros" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d30c53c26bc5b31a98cd02d20f25a7c8567146caf63ed593a9d87b2775291be" +checksum = "ed5ce85961d618ce9794bdf822bfe96fe9dd341aa5b033b454f7a8d96e79b9b1" dependencies = [ - "base64", - "serde_core", + "darling 0.20.11", + "proc-macro2", + "quote", + "syn", ] [[package]] -name = "pem-rfc7468" -version = "0.7.0" +name = "macro_rules_attribute" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412" +checksum = "65049d7923698040cd0b1ddcced9b0eb14dd22c5f86ae59c3740eab64a676520" dependencies = [ - "base64ct", + "macro_rules_attribute-proc_macro", + "paste", ] [[package]] -name = "percent-encoding" -version = "2.3.2" +name = "macro_rules_attribute-proc_macro" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" +checksum = "670fdfda89751bc4a84ac13eaa63e205cf0fd22b4c9a5fbfa085b63c1f1d3a30" [[package]] -name = "pgvector" -version = "0.4.1" +name = "matchers" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc58e2d255979a31caa7cabfa7aac654af0354220719ab7a68520ae7a91e8c0b" +checksum = "d1525a2a28c7f4fa0fc98bb91ae755d1e2d1505079e05539e35bc876b5d65ae9" dependencies = [ - "serde", + "regex-automata", ] [[package]] -name = "pin-project" -version = "1.1.10" +name = "matrixmultiply" +version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677f1add503faace112b9f1373e43e9e054bfdd22ff1a63c1bc485eaec6a6a8a" +checksum = "a06de3016e9fae57a36fd14dba131fccf49f74b40b7fbdb472f96e361ec71a08" dependencies = [ - "pin-project-internal", + "autocfg", + "rawpointer", ] [[package]] -name = "pin-project-internal" -version = "1.1.10" +name = "maybe-rayon" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861" +checksum = "8ea1f30cedd69f0a2954655f7188c6a834246d2bcf1e315e2ac40c4b24dc9519" dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.114", + "cfg-if", + "rayon", ] [[package]] -name = "pin-project-lite" -version = "0.2.16" +name = "md5" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" +checksum = "ae960838283323069879657ca3de837e9f7bbb4c7bf6ea7f1b290d5e9476d2e0" [[package]] -name = "pin-utils" -version = "0.1.0" +name = "memchr" +version = "2.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +checksum = "88904434abc2901f197fe8cc55f0445e7ded921dba5911dad2e2b39b48e663c4" [[package]] -name = "pkcs1" -version = "0.7.5" +name = "memmap2" +version = "0.9.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8ffb9f10fa047879315e6625af03c164b16962a5368d724ed16323b68ace47f" +checksum = "d1219ed1b7f229ee7104d281dd01d6802fe28bb6e95d292942c4daacdeb798c0" dependencies = [ - "der", - "pkcs8", - "spki", + "libc", + "stable_deref_trait", ] [[package]] -name = "pkcs8" -version = "0.10.2" +name = "minimal-lexical" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" -dependencies = [ - "der", - "spki", -] +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] -name = "pkg-config" -version = "0.3.32" +name = "miniz_oxide" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" +dependencies = [ + "adler2", + "simd-adler32", +] [[package]] -name = "polyval" -version = "0.6.2" +name = "mio" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d1fe60d06143b2430aa532c94cfe9e29783047f06c0d7fd359a9a51b729fa25" +checksum = "02bd0af71c67b473010cbbc60715ee815645a4dc942899111f494b4b737d6fda" dependencies = [ - "cfg-if", - "cpufeatures 0.2.17", - "opaque-debug", - "universal-hash", + "libc", + "wasi", + "windows-sys 0.61.2", ] [[package]] -name = "potential_utf" -version = "0.1.4" +name = "moddef" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a0b3262dc837d2513fe2ef31ff8461352ef932dcca31ba0c0abe33547cf6b9b" + +[[package]] +name = "monostate" +version = "0.1.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77" +checksum = "3341a273f6c9d5bef1908f17b7267bbab0e95c9bf69a0d4dcf8e9e1b2c76ef67" dependencies = [ - "zerovec", + "monostate-impl", + "serde", + "serde_core", ] [[package]] -name = "powerfmt" -version = "0.2.0" +name = "monostate-impl" +version = "0.1.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" +checksum = "e4db6d5580af57bf992f59068d4ea26fd518574ff48d7639b255a36f9de6e7e9" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] [[package]] -name = "ppv-lite86" -version = "0.2.21" +name = "moxcms" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +checksum = "bb85c154ba489f01b25c0d36ae69a87e4a1c73a72631fc6c0eb6dde34a73e44b" dependencies = [ - "zerocopy", + "num-traits", + "pxfm", ] [[package]] -name = "pretty_assertions" -version = "1.4.1" +name = "naga" +version = "29.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ae130e2f271fbc2ac3a40fb1d07180839cdbbe443c7a27e1e3c13c5cac0116d" +checksum = "0dd91265cc2454558f659b3b4b9640f0ddb8cc6521277f166b8a8c181c898079" dependencies = [ - "diff", - "yansi", + "arrayvec", + "bit-set", + "bitflags", + "cfg-if", + "cfg_aliases", + "codespan-reporting", + "half", + "hashbrown 0.16.1", + "hexf-parse", + "indexmap", + "libm", + "log", + "num-traits", + "once_cell", + "rustc-hash 1.1.0", + "spirv", + "thiserror 2.0.18", + "unicode-ident", ] [[package]] -name = "prettyplease" -version = "0.2.37" +name = "nb" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" +checksum = "801d31da0513b6ec5214e9bf433a77966320625a37860f910be265be6e18d06f" dependencies = [ - "proc-macro2", - "syn 2.0.114", + "nb 1.1.0", ] [[package]] -name = "proc-macro-crate" -version = "3.4.0" +name = "nb" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d5439c4ad607c3c23abf66de8c8bf57ba8adcd1f129e699851a6e43935d339d" + +[[package]] +name = "ndarray" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "219cb19e96be00ab2e37d6e299658a0cfa83e52429179969b0f0121b4ac46983" +checksum = "882ed72dce9365842bf196bdeedf5055305f11fc8c03dee7bb0194a6cad34841" dependencies = [ - "toml_edit", + "matrixmultiply", + "num-complex", + "num-integer", + "num-traits", + "portable-atomic", + "portable-atomic-util", + "rawpointer", ] [[package]] -name = "proc-macro-error" -version = "1.0.4" +name = "ndarray" +version = "0.17.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +checksum = "520080814a7a6b4a6e9070823bb24b4531daac8c4627e08ba5de8c5ef2f2752d" dependencies = [ - "proc-macro-error-attr", - "proc-macro2", - "quote", - "syn 1.0.109", - "version_check", + "matrixmultiply", + "num-complex", + "num-integer", + "num-traits", + "portable-atomic", + "portable-atomic-util", + "rawpointer", ] [[package]] -name = "proc-macro-error-attr" -version = "1.0.4" +name = "ndk-sys" +version = "0.6.0+11769913" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +checksum = "ee6cda3051665f1fb8d9e08fc35c96d5a244fb1be711a03b71118828afc9a873" dependencies = [ - "proc-macro2", - "quote", - "version_check", + "jni-sys 0.3.1", ] [[package]] -name = "proc-macro-error-attr2" -version = "2.0.0" +name = "new_debug_unreachable" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" + +[[package]] +name = "no_std_io2" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5" +checksum = "418abd1b6d34fbf6cae440dc874771b0525a604428704c76e48b29a5e67b8003" dependencies = [ - "proc-macro2", - "quote", + "memchr", ] [[package]] -name = "proc-macro-error2" -version = "2.0.1" +name = "nom" +version = "7.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" dependencies = [ - "proc-macro-error-attr2", - "proc-macro2", - "quote", - "syn 2.0.114", + "memchr", + "minimal-lexical", ] [[package]] -name = "proc-macro2" -version = "1.0.105" +name = "nom" +version = "8.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "535d180e0ecab6268a3e718bb9fd44db66bbbc256257165fc699dadf70d16fe7" +checksum = "df9761775871bdef83bee530e60050f7e54b1105350d6884eb0fb4f46c2f9405" dependencies = [ - "unicode-ident", + "memchr", ] [[package]] -name = "proc-macro2-diagnostics" -version = "0.10.1" +name = "noop_proc_macro" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0676bb32a98c1a483ce53e500a81ad9c3d5b3f7c920c28c24e9cb0980d0b5bc8" + +[[package]] +name = "ntapi" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af066a9c399a26e020ada66a034357a868728e72cd426f3adcd35f80d88d88c8" +checksum = "c3b335231dfd352ffb0f8017f3b6027a4917f7df785ea2143d8af2adc66980ae" dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.114", - "version_check", - "yansi", + "winapi", ] [[package]] -name = "progenitor" -version = "0.11.2" +name = "nu-ansi-term" +version = "0.50.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2326f73d5326257514712436680ef8da4543ee47c0e9e0d501545c8909ee12e4" +checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" dependencies = [ - "progenitor-client", - "progenitor-impl", - "progenitor-macro", + "windows-sys 0.61.2", ] [[package]] -name = "progenitor-client" -version = "0.11.2" +name = "num" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71a0beb939758f229cbae70a4889c7c76a4ac0e90f0b1e7ae9b4636a927d1018" +checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23" dependencies = [ - "bytes", - "futures-core", - "percent-encoding", - "reqwest 0.12.28", - "serde", - "serde_json", - "serde_urlencoded", + "num-bigint", + "num-complex", + "num-integer", + "num-iter", + "num-rational", + "num-traits", ] [[package]] -name = "progenitor-impl" -version = "0.11.2" +name = "num-bigint" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90f6d9109b04e005bbdec84cacec7e81cc15533f2b5dc505f0defc212d270c15" -dependencies = [ - "heck 0.5.0", - "http", - "indexmap", - "openapiv3", - "proc-macro2", - "quote", - "regex", - "schemars", - "serde", - "serde_json", - "syn 2.0.114", - "thiserror 2.0.17", - "typify", - "unicode-ident", +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +dependencies = [ + "num-integer", + "num-traits", ] [[package]] -name = "progenitor-macro" -version = "0.11.2" +name = "num-complex" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46596c574831739c661f22923fe587399c61f5e3e79b73cc9a93644c72248d84" +checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" dependencies = [ - "openapiv3", - "proc-macro2", - "progenitor-impl", - "quote", - "schemars", - "serde", - "serde_json", - "serde_tokenstream", - "serde_yaml", - "syn 2.0.114", + "bytemuck", + "num-traits", ] [[package]] -name = "prost" -version = "0.14.3" +name = "num-conv" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2ea70524a2f82d518bce41317d0fae74151505651af45faf1ffbd6fd33f0568" -dependencies = [ - "bytes", - "prost-derive", -] +checksum = "521739c6d2bac4aa25192232afe6841231376b2b26d4d9fae5ecf8ca5772e441" [[package]] -name = "prost-derive" -version = "0.14.3" +name = "num-derive" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27c6023962132f4b30eb4c172c91ce92d933da334c59c23cddee82358ddafb0b" +checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" dependencies = [ - "anyhow", - "itertools 0.14.0", "proc-macro2", "quote", - "syn 2.0.114", + "syn", ] [[package]] -name = "ptr_meta" -version = "0.1.4" +name = "num-integer" +version = "0.1.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0738ccf7ea06b608c10564b31debd4f5bc5e197fc8bfe088f68ae5ce81e7a4f1" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" dependencies = [ - "ptr_meta_derive", + "num-traits", ] [[package]] -name = "ptr_meta_derive" -version = "0.1.4" +name = "num-iter" +version = "0.1.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16b845dbfca988fa33db069c0e230574d15a3088f147a87b64c7589eb662c9ac" +checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", + "autocfg", + "num-integer", + "num-traits", ] [[package]] -name = "quinn" -version = "0.11.9" +name = "num-rational" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9e20a958963c291dc322d98411f541009df2ced7b5a4f2bd52337638cfccf20" +checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" dependencies = [ - "bytes", - "cfg_aliases", - "futures-io", - "pin-project-lite", - "quinn-proto", - "quinn-udp", - "rustc-hash", - "rustls", - "socket2", - "thiserror 2.0.17", - "tokio", - "tracing", - "web-time", + "num-bigint", + "num-integer", + "num-traits", ] [[package]] -name = "quinn-proto" -version = "0.11.13" +name = "num-traits" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1906b49b0c3bc04b5fe5d86a77925ae6524a19b816ae38ce1e426255f1d8a31" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ - "aws-lc-rs", - "bytes", - "getrandom 0.3.4", - "lru-slab", - "rand 0.9.2", - "ring", - "rustc-hash", - "rustls", - "rustls-pki-types", - "slab", - "thiserror 2.0.17", - "tinyvec", - "tracing", - "web-time", + "autocfg", + "libm", ] [[package]] -name = "quinn-udp" -version = "0.5.14" +name = "num_cpus" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "addec6a0dcad8a8d96a771f815f0eaf55f9d1805756410b39f5fa81332574cbd" +checksum = "91df4bbde75afed763b708b7eee1e8e7651e02d97f6d5dd763e89367e957b23b" dependencies = [ - "cfg_aliases", + "hermit-abi", "libc", - "once_cell", - "socket2", - "tracing", - "windows-sys 0.60.2", ] [[package]] -name = "quote" -version = "1.0.43" +name = "objc2" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc74d9a594b72ae6656596548f56f667211f8a97b3d4c3d467150794690dc40a" +checksum = "3a12a8ed07aefc768292f076dc3ac8c48f3781c8f2d5851dd3d98950e8c5a89f" dependencies = [ - "proc-macro2", + "objc2-encode", ] [[package]] -name = "r-efi" -version = "5.3.0" +name = "objc2-core-foundation" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" +checksum = "2a180dd8642fa45cdb7dd721cd4c11b1cadd4929ce112ebd8b9f5803cc79d536" +dependencies = [ + "bitflags", + "dispatch2", + "objc2", +] [[package]] -name = "r-efi" -version = "6.0.0" +name = "objc2-encode" +version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" +checksum = "ef25abbcd74fb2609453eb695bd2f860d389e457f67dc17cafc8b8cbc89d0c33" [[package]] -name = "radium" -version = "0.7.0" +name = "objc2-foundation" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" +checksum = "e3e0adef53c21f888deb4fa59fc59f7eb17404926ee8a6f59f5df0fd7f9f3272" +dependencies = [ + "bitflags", + "objc2", + "objc2-core-foundation", +] [[package]] -name = "rand" -version = "0.8.5" +name = "objc2-io-kit" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +checksum = "33fafba39597d6dc1fb709123dfa8289d39406734be322956a69f0931c73bb15" dependencies = [ "libc", - "rand_chacha 0.3.1", - "rand_core 0.6.4", + "objc2-core-foundation", ] [[package]] -name = "rand" -version = "0.9.2" +name = "objc2-metal" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" +checksum = "a0125f776a10d00af4152d74616409f0d4a2053a6f57fa5b7d6aa2854ac04794" dependencies = [ - "rand_chacha 0.9.0", - "rand_core 0.9.3", + "bitflags", + "block2", + "objc2", + "objc2-foundation", ] [[package]] -name = "rand" -version = "0.10.1" +name = "objc2-quartz-core" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2e8e8bcc7961af1fdac401278c6a831614941f6164ee3bf4ce61b7edb162207" +checksum = "96c1358452b371bf9f104e21ec536d37a650eb10f7ee379fff67d2e08d537f1f" dependencies = [ - "chacha20", - "getrandom 0.4.2", - "rand_core 0.10.1", + "bitflags", + "objc2", + "objc2-core-foundation", + "objc2-foundation", + "objc2-metal", ] [[package]] -name = "rand_chacha" -version = "0.3.1" +name = "object" +version = "0.37.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +checksum = "ff76201f031d8863c38aa7f905eca4f53abbfa15f609db4277d44cd8938f33fe" dependencies = [ - "ppv-lite86", - "rand_core 0.6.4", + "memchr", ] [[package]] -name = "rand_chacha" -version = "0.9.0" +name = "once_cell" +version = "1.21.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" -dependencies = [ - "ppv-lite86", - "rand_core 0.9.3", -] +checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" [[package]] -name = "rand_core" -version = "0.6.4" +name = "once_cell_polyfill" +version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" + +[[package]] +name = "oneshot" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfe21416a02c693fb9f980befcb230ecc70b0b3d1cc4abf88b9675c4c1457f0c" + +[[package]] +name = "onig" +version = "6.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cc3cbf698f9438986c11a880c90a6d04b9de27575afd28bbf45b154b6c709e2" dependencies = [ - "getrandom 0.2.16", + "bitflags", + "libc", + "once_cell", + "onig_sys", ] [[package]] -name = "rand_core" -version = "0.9.3" +name = "onig_sys" +version = "69.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" +checksum = "1e68317604e77e53b85896388e1a803c1d21b74c899ec9e5e1112db90735edd7" dependencies = [ - "getrandom 0.3.4", + "cc", + "pkg-config", ] [[package]] -name = "rand_core" -version = "0.10.1" +name = "option-ext" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69" +checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" [[package]] -name = "rcgen" -version = "0.14.6" +name = "ordered-float" +version = "5.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ec0a99f2de91c3cddc84b37e7db80e4d96b743e05607f647eb236fc0455907f" +checksum = "b7d950ca161dc355eaf28f82b11345ed76c6e1f6eb1f4f4479e0323b9e2fbd0e" dependencies = [ - "pem", - "ring", - "rustls-pki-types", - "time", - "x509-parser", - "yasna", + "num-traits", ] [[package]] -name = "redox_syscall" -version = "0.5.18" +name = "parking" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" -dependencies = [ - "bitflags", -] +checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" [[package]] -name = "redox_syscall" -version = "0.7.0" +name = "parking_lot" +version = "0.12.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49f3fe0889e69e2ae9e41f4d6c4c0181701d00e4697b356fb1f74173a5e0ee27" +checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" dependencies = [ - "bitflags", + "lock_api", + "parking_lot_core", ] [[package]] -name = "regex" -version = "1.12.2" +name = "parking_lot_core" +version = "0.9.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "843bc0191f75f3e22651ae5f1e72939ab2f72a4bc30fa80a066bd66edefc24d4" +checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" dependencies = [ - "aho-corasick", - "memchr", - "regex-automata", - "regex-syntax 0.8.8", + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-link", ] [[package]] -name = "regex-automata" -version = "0.4.13" +name = "password-hash" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c" +checksum = "7676374caaee8a325c9e7a2ae557f216c5563a171d6997b0ef8a65af35147700" dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax 0.8.8", + "base64ct", + "rand_core 0.6.4", + "subtle", ] [[package]] -name = "regex-syntax" -version = "0.7.5" +name = "paste" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" [[package]] -name = "regex-syntax" -version = "0.8.8" +name = "pastey" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58" +checksum = "35fb2e5f958ec131621fdd531e9fc186ed768cbe395337403ae56c17a74c68ec" [[package]] -name = "regress" -version = "0.10.5" +name = "pbkdf2" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2057b2325e68a893284d1538021ab90279adac1139957ca2a74426c6f118fb48" +checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917" dependencies = [ - "hashbrown 0.16.1", - "memchr", + "digest", + "hmac", + "password-hash", + "sha2", ] [[package]] -name = "rend" -version = "0.4.2" +name = "percent-encoding" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" + +[[package]] +name = "petgraph" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71fe3824f5629716b1589be05dacd749f6aa084c87e00e016714a8cdfccc997c" +checksum = "8701b58ea97060d5e5b155d383a69952a60943f0e6dfe30b04c287beb0b27455" dependencies = [ - "bytecheck", + "fixedbitset", + "hashbrown 0.15.5", + "indexmap", + "serde", ] [[package]] -name = "reqwest" -version = "0.12.28" +name = "pin-project-lite" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eddd3ca559203180a307f12d114c268abf583f59b03cb906fd0b3ff8646c1147" +checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" + +[[package]] +name = "pkg-config" +version = "0.3.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19f132c84eca552bf34cab8ec81f1c1dcc229b811638f9d283dceabe58c5569e" + +[[package]] +name = "png" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60769b8b31b2a9f263dae2776c37b1b28ae246943cf719eb6946a1db05128a61" dependencies = [ - "base64", - "bytes", - "futures-channel", - "futures-core", - "futures-util", - "http", - "http-body", - "http-body-util", - "hyper", - "hyper-rustls", - "hyper-util", - "js-sys", - "log", - "percent-encoding", - "pin-project-lite", - "quinn", - "rustls", - "rustls-native-certs", - "rustls-pki-types", - "serde", - "serde_json", - "serde_urlencoded", - "sync_wrapper", - "tokio", - "tokio-rustls", - "tokio-util", - "tower", - "tower-http", - "tower-service", - "url", - "wasm-bindgen", - "wasm-bindgen-futures", - "wasm-streams", - "web-sys", - "webpki-roots 1.0.5", + "bitflags", + "crc32fast", + "fdeflate", + "flate2", + "miniz_oxide", +] + +[[package]] +name = "portable-atomic" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49" +dependencies = [ + "serde", ] [[package]] -name = "reqwest" -version = "0.13.1" +name = "portable-atomic-util" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04e9018c9d814e5f30cc16a0f03271aeab3571e609612d9fe78c1aa8d11c2f62" +checksum = "c2a106d1259c23fac8e543272398ae0e3c0b8d33c88ed73d0cc71b0f1d902618" dependencies = [ - "base64", - "bytes", - "encoding_rs", - "futures-core", - "futures-util", - "h2", - "http", - "http-body", - "http-body-util", - "hyper", - "hyper-rustls", - "hyper-util", - "js-sys", - "log", - "mime", - "percent-encoding", - "pin-project-lite", - "quinn", - "rustls", - "rustls-pki-types", - "rustls-platform-verifier", - "sync_wrapper", - "tokio", - "tokio-rustls", - "tokio-util", - "tower", - "tower-http", - "tower-service", - "url", - "wasm-bindgen", - "wasm-bindgen-futures", - "wasm-streams", - "web-sys", + "portable-atomic", ] [[package]] -name = "ring" -version = "0.17.14" +name = "potential_utf" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" +checksum = "0103b1cef7ec0cf76490e969665504990193874ea05c85ff9bab8b911d0a0564" dependencies = [ - "cc", - "cfg-if", - "getrandom 0.2.16", - "libc", - "untrusted 0.9.0", - "windows-sys 0.52.0", + "zerovec", ] [[package]] -name = "rkyv" -version = "0.7.46" +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + +[[package]] +name = "ppv-lite86" +version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2297bf9c81a3f0dc96bc9521370b88f054168c29826a75e89c55ff196e7ed6a1" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" dependencies = [ - "bitvec", - "bytecheck", - "bytes", - "hashbrown 0.12.3", - "ptr_meta", - "rend", - "rkyv_derive", - "seahash", - "tinyvec", - "uuid", + "zerocopy", ] [[package]] -name = "rkyv_derive" -version = "0.7.46" +name = "presser" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8cf8e6a8aa66ce33f63993ffc4ea4271eb5b0530a9002db8455ea6050c77bfa" + +[[package]] +name = "prettyplease" +version = "0.2.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84d7b42d4b8d06048d3ac8db0eb31bcb942cbeb709f0b5f2b2ebde398d3038f5" +checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" dependencies = [ "proc-macro2", - "quote", - "syn 1.0.109", + "syn", ] [[package]] -name = "rsa" -version = "0.9.10" +name = "proc-macro-crate" +version = "3.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8573f03f5883dcaebdfcf4725caa1ecb9c15b2ef50c43a07b816e06799bb12d" +checksum = "e67ba7e9b2b56446f1d419b1d807906278ffa1a658a8a5d8a39dcb1f5a78614f" dependencies = [ - "const-oid", - "digest", - "num-bigint-dig", - "num-integer", - "num-traits", - "pkcs1", - "pkcs8", - "rand_core 0.6.4", - "signature", - "spki", - "subtle", - "zeroize", + "toml_edit", ] [[package]] -name = "rust-embed" -version = "8.9.0" +name = "proc-macro2" +version = "1.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "947d7f3fad52b283d261c4c99a084937e2fe492248cb9a68a8435a861b8798ca" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" dependencies = [ - "rust-embed-impl", - "rust-embed-utils", - "walkdir", + "unicode-ident", ] [[package]] -name = "rust-embed-impl" -version = "8.9.0" +name = "profiling" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fa2c8c9e8711e10f9c4fd2d64317ef13feaab820a4c51541f1a8c8e2e851ab2" +checksum = "3d595e54a326bc53c1c197b32d295e14b169e3cfeaa8dc82b529f947fba6bcf5" dependencies = [ - "proc-macro2", - "quote", - "rust-embed-utils", - "syn 2.0.114", - "walkdir", + "profiling-procmacros", ] [[package]] -name = "rust-embed-utils" -version = "8.9.0" +name = "profiling-procmacros" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60b161f275cb337fe0a44d924a5f4df0ed69c2c39519858f931ce61c779d3475" +checksum = "4488a4a36b9a4ba6b9334a32a39971f77c1436ec82c38707bce707699cc3bbcb" dependencies = [ - "sha2", - "walkdir", + "quote", + "syn", ] [[package]] -name = "rust_decimal" -version = "1.39.0" +name = "pulp" +version = "0.22.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35affe401787a9bd846712274d97654355d21b2a2c092a3139aabe31e9022282" +checksum = "046aa45b989642ec2e4717c8e72d677b13edd831a4d3b6cf37d9a3e54912496a" dependencies = [ - "arrayvec", - "borsh", - "bytes", - "num-traits", - "rand 0.8.5", - "rkyv", - "serde", - "serde_json", + "bytemuck", + "cfg-if", + "libm", + "num-complex", + "paste", + "pulp-wasm-simd-flag", + "raw-cpuid", + "reborrow", + "version_check", ] [[package]] -name = "rustc-demangle" -version = "0.1.26" +name = "pulp-wasm-simd-flag" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56f7d92ca342cea22a06f2121d944b4fd82af56988c270852495420f961d4ace" +checksum = "1d8f70e07b9c3962945a74e59ca1c511bba65b6419468acc217c457d93f3c740" [[package]] -name = "rustc-hash" -version = "2.1.1" +name = "pxfm" +version = "0.1.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" +checksum = "e0c5ccf5294c6ccd63a74f1565028353830a9c2f5eb0c682c355c471726a6e3f" [[package]] -name = "rustc_version" +name = "qoi" version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +checksum = "7f6d64c71eb498fe9eae14ce4ec935c555749aef511cca85b5568910d6e48001" dependencies = [ - "semver", + "bytemuck", ] [[package]] -name = "rusticata-macros" -version = "4.1.0" +name = "quick-error" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3" + +[[package]] +name = "quinn" +version = "0.11.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "faf0c4a6ece9950b9abdb62b1cfcf2a68b3b67a10ba445b3bb85be2a293d0632" +checksum = "0c1a41e437b6bbd489372cd4971de128e85c855f56c57f283d20ff016cf7c0a8" dependencies = [ - "nom", + "bytes", + "cfg_aliases", + "pin-project-lite", + "quinn-proto", + "quinn-udp", + "rustc-hash 2.1.2", + "rustls", + "socket2", + "thiserror 2.0.18", + "tokio", + "tracing", + "web-time", ] [[package]] -name = "rustix" -version = "1.1.3" +name = "quinn-proto" +version = "0.11.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "146c9e247ccc180c1f61615433868c99f3de3ae256a30a43b49f67c2d9171f34" +checksum = "4fcb935c5bec503c2f0e306bdd3e58bb9029dcb14fa8d9ac76e3a5256ac0763e" dependencies = [ - "bitflags", - "errno", - "libc", - "linux-raw-sys", - "windows-sys 0.61.2", + "bytes", + "getrandom 0.3.4", + "lru-slab", + "rand 0.9.4", + "ring", + "rustc-hash 2.1.2", + "rustls", + "rustls-pki-types", + "slab", + "thiserror 2.0.18", + "tinyvec", + "tracing", + "web-time", ] [[package]] -name = "rustls" -version = "0.23.36" +name = "quinn-udp" +version = "0.5.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c665f33d38cea657d9614f766881e4d510e0eda4239891eea56b4cadcf01801b" +checksum = "addec6a0dcad8a8d96a771f815f0eaf55f9d1805756410b39f5fa81332574cbd" dependencies = [ - "aws-lc-rs", - "log", + "cfg_aliases", + "libc", "once_cell", - "ring", - "rustls-pki-types", - "rustls-webpki", - "subtle", - "zeroize", + "socket2", + "tracing", + "windows-sys 0.60.2", ] [[package]] -name = "rustls-native-certs" -version = "0.8.3" +name = "quote" +version = "1.0.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "612460d5f7bea540c490b2b6395d8e34a953e52b491accd6c86c8164c5932a63" +checksum = "dfbc457d0c7a0759a614551b11a6409e5951f6c7537be1f1b7682b9ae9230368" dependencies = [ - "openssl-probe", - "rustls-pki-types", - "schannel", - "security-framework", + "proc-macro2", ] [[package]] -name = "rustls-pki-types" -version = "1.13.2" +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + +[[package]] +name = "r-efi" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" + +[[package]] +name = "rand" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21e6f2ab2928ca4291b86736a8bd920a277a399bba1589409d72154ff87c1282" +checksum = "5ca0ecfa931c29007047d1bc58e623ab12e5590e8c7cc53200d5202b69266d8a" dependencies = [ - "web-time", - "zeroize", + "libc", + "rand_chacha 0.3.1", + "rand_core 0.6.4", ] [[package]] -name = "rustls-platform-verifier" -version = "0.6.2" +name = "rand" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d99feebc72bae7ab76ba994bb5e121b8d83d910ca40b36e0921f53becc41784" +checksum = "44c5af06bb1b7d3216d91932aed5265164bf384dc89cd6ba05cf59a35f5f76ea" dependencies = [ - "core-foundation", - "core-foundation-sys", - "jni", - "log", - "once_cell", - "rustls", - "rustls-native-certs", - "rustls-platform-verifier-android", - "rustls-webpki", - "security-framework", - "security-framework-sys", - "webpki-root-certs", - "windows-sys 0.61.2", + "rand_chacha 0.9.0", + "rand_core 0.9.5", ] [[package]] -name = "rustls-platform-verifier-android" -version = "0.1.1" +name = "rand" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f87165f0995f63a9fbeea62b64d10b4d9d8e78ec6d7d51fb2125fda7bb36788f" +checksum = "d2e8e8bcc7961af1fdac401278c6a831614941f6164ee3bf4ce61b7edb162207" +dependencies = [ + "chacha20", + "getrandom 0.4.3", + "rand_core 0.10.1", +] [[package]] -name = "rustls-webpki" -version = "0.103.8" +name = "rand_chacha" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ffdfa2f5286e2247234e03f680868ac2815974dc39e00ea15adc445d0aafe52" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ - "aws-lc-rs", - "ring", - "rustls-pki-types", - "untrusted 0.9.0", + "ppv-lite86", + "rand_core 0.6.4", ] [[package]] -name = "rustversion" -version = "1.0.22" +name = "rand_chacha" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" +dependencies = [ + "ppv-lite86", + "rand_core 0.9.5", +] [[package]] -name = "ryu" -version = "1.0.22" +name = "rand_core" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a50f4cf475b65d88e057964e0e9bb1f0aa9bbb2036dc65c64596b42932536984" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom 0.2.17", +] [[package]] -name = "salvo" -version = "0.88.0" +name = "rand_core" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db4a293f575fba1e82c034e023438133f64cc367cb06e6c86ec8687badf89ba4" +checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" dependencies = [ - "salvo-acme 0.88.0", - "salvo-cors", - "salvo-oapi 0.88.0", - "salvo-otel", - "salvo-proxy 0.88.0", - "salvo_core 0.88.1", + "getrandom 0.3.4", ] [[package]] -name = "salvo" -version = "0.89.3" +name = "rand_core" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69" + +[[package]] +name = "rand_distr" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "997a9250e40b5c3122280212b03fa7579b548307a8239492eecc11d58da8a911" +checksum = "6a8615d50dcf34fa31f7ab52692afec947c4dd0ab803cc87cb3b0b4570ff7463" dependencies = [ - "salvo-acme 0.89.3", - "salvo-oapi 0.89.3", - "salvo-proxy 0.89.3", - "salvo_core 0.89.3", + "num-traits", + "rand 0.9.4", ] [[package]] -name = "salvo-acme" -version = "0.88.0" +name = "rand_distr" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95e33619166d9e41c2e5a5dc6161b17c50f306cc9a90beba830608db3f8ef1bb" +checksum = "4d431c2703ccf129de4d45253c03f49ebb22b97d6ad79ee3ecfc7e3f4862c1d8" dependencies = [ - "aws-lc-rs", - "base64", - "bytes", - "futures-util", - "http", - "http-body-util", - "hyper", - "hyper-rustls", - "hyper-util", - "parking_lot", - "quinn", - "rcgen", - "salvo_core 0.88.1", - "serde", - "serde_json", - "tokio", - "tokio-rustls", - "tracing", - "x509-parser", + "num-traits", + "rand 0.10.1", ] [[package]] -name = "salvo-acme" -version = "0.89.3" +name = "range-alloc" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca45419789ae5a7899559e9512e58ca889e41f04f1f2445e9f4b290ceccd1d08" + +[[package]] +name = "rav1e" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "214d2a135ac07303211f70b64d8d5039b7886884cb811281d646ff0891e49767" +checksum = "43b6dd56e85d9483277cde964fd1bdb0428de4fec5ebba7540995639a21cb32b" dependencies = [ - "aws-lc-rs", - "base64", - "bytes", - "futures-util", - "http", - "http-body-util", - "hyper", - "hyper-rustls", - "hyper-util", - "parking_lot", - "quinn", - "rcgen", - "salvo_core 0.89.3", - "serde", - "serde_json", - "tokio", - "tokio-rustls", - "tracing", - "x509-parser", + "aligned-vec", + "arbitrary", + "arg_enum_proc_macro", + "arrayvec", + "av-scenechange", + "av1-grain", + "bitstream-io", + "built", + "cfg-if", + "interpolate_name", + "itertools 0.14.0", + "libc", + "libfuzzer-sys", + "log", + "maybe-rayon", + "new_debug_unreachable", + "noop_proc_macro", + "num-derive", + "num-traits", + "paste", + "profiling", + "rand 0.9.4", + "rand_chacha 0.9.0", + "simd_helpers", + "thiserror 2.0.18", + "v_frame", + "wasm-bindgen", ] [[package]] -name = "salvo-cors" -version = "0.88.0" +name = "ravif" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "082b0023e3ba961a305a969fcc4bd50eadf92c5977d3857a67ed3257f08bca04" +checksum = "e52310197d971b0f5be7fe6b57530dcd27beb35c1b013f29d66c1ad73fbbcc45" dependencies = [ - "bytes", - "salvo_core 0.88.1", - "tracing", + "avif-serialize", + "imgref", + "loop9", + "quick-error", + "rav1e", + "rayon", + "rgb", ] [[package]] -name = "salvo-http3" -version = "0.7.0" +name = "raw-cpuid" +version = "11.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b796803406733fab6a126e75bffb29f9e5336e8d42d39ea679ae381922059ed7" +checksum = "498cd0dc59d73224351ee52a95fee0f1a617a2eae0e7d9d720cc622c73a54186" dependencies = [ - "bytes", - "futures-util", - "h3", - "h3-datagram", - "h3-quinn", - "http", - "pin-project-lite", - "tokio", - "tracing", + "bitflags", ] [[package]] -name = "salvo-oapi" -version = "0.88.0" +name = "raw-window-handle" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c82aa0643c13cedf4407d7325165aa5c231a215c936b1476eab6dd12a0f3349" -dependencies = [ - "anyhow", - "base64", - "bytes", - "chrono", - "compact_str", - "futures-util", - "http", - "indexmap", - "inventory", - "mime-infer", - "parking_lot", - "regex", - "rust-embed", - "rust_decimal", - "salvo-oapi-macros 0.88.0", - "salvo_core 0.88.1", - "serde", - "serde_json", - "serde_norway", - "smallvec", - "thiserror 2.0.17", - "time", - "tokio", - "tracing", - "ulid", - "url", - "uuid", -] +checksum = "20675572f6f24e9e76ef639bc5552774ed45f1c30e2951e1e99c59888861c539" [[package]] -name = "salvo-oapi" -version = "0.89.3" +name = "raw-window-metal" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e639ba263b1fafa79309c2262cca93612f6777c3559f7a121f367a1c3f36605b" +checksum = "40d213455a5f1dc59214213c7330e074ddf8114c9a42411eb890c767357ce135" dependencies = [ - "anyhow", - "base64", - "bytes", - "chrono", - "compact_str", - "futures-util", - "http", - "indexmap", - "inventory", - "mime-infer", - "parking_lot", - "regex", - "rust-embed", - "rust_decimal", - "salvo-oapi-macros 0.89.3", - "salvo_core 0.89.3", - "serde", - "serde_json", - "serde_norway", - "smallvec", - "thiserror 2.0.17", - "time", - "tokio", - "tracing", - "ulid", - "url", - "uuid", + "objc2", + "objc2-core-foundation", + "objc2-foundation", + "objc2-quartz-core", ] [[package]] -name = "salvo-oapi-macros" -version = "0.88.0" +name = "rawpointer" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01c3c3cae3e05b3dca650b7188f9ed839f27020019f9a20d22b4d4d51c2a05cb" -dependencies = [ - "proc-macro-crate", - "proc-macro2", - "proc-macro2-diagnostics", - "quote", - "regex", - "salvo-serde-util 0.88.1", - "syn 2.0.114", -] +checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3" [[package]] -name = "salvo-oapi-macros" -version = "0.89.3" +name = "rayon" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f8cfa5ba6f6ad5ce247cfe05a6570858f0967ef83aabf984f8c3ed7f6fa7ad3" +checksum = "fb39b166781f92d482534ef4b4b1b2568f42613b53e5b6c160e24cfbfa30926d" dependencies = [ - "proc-macro-crate", - "proc-macro2", - "proc-macro2-diagnostics", - "quote", - "regex", - "salvo-serde-util 0.89.3", - "syn 2.0.114", + "either", + "rayon-core", ] [[package]] -name = "salvo-otel" -version = "0.88.1" +name = "rayon-cond" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7882fccd3bf530977ccf9c3eeeb4d92e5996d76336edb38fd691b420d5e610d" +checksum = "2964d0cf57a3e7a06e8183d14a8b527195c706b7983549cd5462d5aa3747438f" dependencies = [ - "opentelemetry", - "opentelemetry-http", - "opentelemetry-semantic-conventions", - "salvo_core 0.88.1", - "tracing", + "either", + "itertools 0.14.0", + "rayon", ] [[package]] -name = "salvo-proxy" -version = "0.88.0" +name = "rayon-core" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f4eae17b3f6cb50f7a6054268bfdb504f73e5b86504f29480669bd5bbb4fc0b" +checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91" dependencies = [ - "fastrand", - "futures-util", - "hyper", - "hyper-rustls", - "hyper-util", - "local-ip-address", - "percent-encoding", - "reqwest 0.13.1", - "salvo_core 0.88.1", - "tokio", - "tracing", - "url", + "crossbeam-deque", + "crossbeam-utils", ] [[package]] -name = "salvo-proxy" -version = "0.89.3" +name = "reborrow" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03251193000f4bd3b042892be858ee50e8b3719f2b08e5833ac4353724632430" + +[[package]] +name = "redox_syscall" +version = "0.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1501355e3361174931a91cd8c4026061ffdebb1757aa2ed449d97d33a178ee92" +checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" dependencies = [ - "fastrand", - "futures-util", - "hyper", - "hyper-rustls", - "hyper-util", - "local-ip-address", - "percent-encoding", - "reqwest 0.13.1", - "salvo_core 0.89.3", - "tokio", - "tracing", + "bitflags", ] [[package]] -name = "salvo-serde-util" -version = "0.88.1" +name = "redox_users" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f547cdd125668176b68cd1039f6f632719b0c7f08d128fad0f7cf44bff03e232" +checksum = "a4e608c6638b9c18977b00b475ac1f28d14e84b27d8d42f70e0bf1e3dec127ac" dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.114", + "getrandom 0.2.17", + "libredox", + "thiserror 2.0.18", ] [[package]] -name = "salvo-serde-util" -version = "0.89.3" +name = "regex" +version = "1.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c513cc94967322fab6ac2f1b3e68d40e110971fd4924f4d48677ca6e7df41038" +checksum = "f1292b7759ae1cb9ec195452d1390a074f0cd8541ab7a5a8c31cd6db45d4a6ba" dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.114", + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", ] [[package]] -name = "salvo_core" -version = "0.88.1" +name = "regex-automata" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5aca4ca8588eff4dcff1c06d227630a034b824804d01e2398184f7b74656e79" +checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" dependencies = [ - "anyhow", - "async-trait", - "base64", - "brotli", - "bytes", - "chardetng", - "content_inspector", - "cookie", - "encoding_rs", - "enumflags2", - "flate2", - "form_urlencoded", - "futures-channel", - "futures-util", - "h3-datagram", - "headers", - "http", - "http-body-util", - "hyper", - "hyper-util", - "indexmap", - "mime", - "mime-infer", - "multer", - "multimap", - "nix", - "parking_lot", - "percent-encoding", - "pin-project", - "quinn", - "rand 0.9.2", - "regex", - "salvo-http3", - "salvo_macros 0.88.1", - "serde", - "serde-xml-rs", - "serde_json", - "serde_urlencoded", - "sync_wrapper", - "tempfile", - "thiserror 2.0.17", - "tokio", - "tokio-rustls", - "tokio-util", - "tracing", - "url", - "zstd", + "aho-corasick", + "memchr", + "regex-syntax", ] [[package]] -name = "salvo_core" -version = "0.89.3" +name = "regex-syntax" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4" + +[[package]] +name = "relative-path" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba39f3699c378cd8970968dcbff9c43159ea4cfbd88d43c00b22f2ef10a435d2" + +[[package]] +name = "renderdoc-sys" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19b30a45b0cd0bcca8037f3d0dc3421eaf95327a17cad11964fb8179b4fc4832" + +[[package]] +name = "reqwest" +version = "0.12.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6b94eccfe18383d4db6dbc6a0462f1be4160467e8d42506db8e46932b8fd5a3" +checksum = "eddd3ca559203180a307f12d114c268abf583f59b03cb906fd0b3ff8646c1147" dependencies = [ - "async-trait", - "base64", - "brotli", + "base64 0.22.1", "bytes", - "chardetng", - "content_inspector", - "cookie", - "encoding_rs", - "enumflags2", - "flate2", - "form_urlencoded", "futures-channel", + "futures-core", "futures-util", - "h3-datagram", - "headers", + "h2", "http", + "http-body", "http-body-util", "hyper", + "hyper-rustls", "hyper-util", - "indexmap", - "mime", - "mime-infer", - "multer", - "multimap", - "parking_lot", + "js-sys", + "log", "percent-encoding", - "pin-project", + "pin-project-lite", "quinn", - "rand 0.10.1", - "regex", - "salvo-http3", - "salvo_macros 0.89.3", + "rustls", + "rustls-pki-types", "serde", - "serde-xml-rs", "serde_json", "serde_urlencoded", "sync_wrapper", - "tempfile", - "thiserror 2.0.17", "tokio", "tokio-rustls", - "tokio-util", - "tracing", + "tower", + "tower-http", + "tower-service", "url", - "zstd", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "webpki-roots 1.0.8", ] [[package]] -name = "salvo_macros" -version = "0.88.1" +name = "rgb" +version = "0.8.53" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "740c3979d3f2864f831bdb96520ddb9285275836c006542afdc284ece24294db" -dependencies = [ - "proc-macro-crate", - "proc-macro2", - "quote", - "regex", - "salvo-serde-util 0.88.1", - "syn 2.0.114", -] +checksum = "47b34b781b31e5d73e9fbc8689c70551fd1ade9a19e3e28cfec8580a79290cc4" [[package]] -name = "salvo_macros" -version = "0.89.3" +name = "ring" +version = "0.17.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a51d5f03526f7cc1cc38b60cc24c3cc5982516c8ad9c94ff27d7f82f3c9762fb" +checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" dependencies = [ - "proc-macro-crate", - "proc-macro2", - "quote", - "regex", - "salvo-serde-util 0.89.3", - "syn 2.0.114", + "cc", + "cfg-if", + "getrandom 0.2.17", + "libc", + "untrusted", + "windows-sys 0.52.0", ] [[package]] -name = "same-file" -version = "1.0.6" +name = "rmp" +version = "0.8.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +checksum = "4ba8be72d372b2c9b35542551678538b562e7cf86c3315773cae48dfbfe7790c" dependencies = [ - "winapi-util", + "num-traits", ] [[package]] -name = "schannel" -version = "0.1.28" +name = "rmp-serde" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "891d81b926048e76efe18581bf793546b4c0eaf8448d72be8de2bbee5fd166e1" +checksum = "72f81bee8c8ef9b577d1681a70ebbc962c232461e397b22c208c43c04b67a155" dependencies = [ - "windows-sys 0.61.2", + "rmp", + "serde", ] [[package]] -name = "schemars" -version = "0.8.22" +name = "rstest" +version = "0.26.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fbf2ae1b8bc8e02df939598064d22402220cd5bbcca1c76f7d6a310974d5615" +checksum = "f5a3193c063baaa2a95a33f03035c8a72b83d97a54916055ba22d35ed3839d49" dependencies = [ - "chrono", - "dyn-clone", - "schemars_derive", - "serde", - "serde_json", - "uuid", + "futures-timer", + "futures-util", + "rstest_macros", ] [[package]] -name = "schemars_derive" -version = "0.8.22" +name = "rstest_macros" +version = "0.26.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32e265784ad618884abaea0600a9adf15393368d840e0222d101a072f3f7534d" +checksum = "9c845311f0ff7951c5506121a9ad75aec44d083c31583b2ea5a30bcb0b0abba0" dependencies = [ + "cfg-if", + "glob", + "proc-macro-crate", "proc-macro2", "quote", - "serde_derive_internals", - "syn 2.0.114", + "regex", + "relative-path", + "rustc_version", + "syn", + "unicode-ident", ] [[package]] -name = "scopeguard" -version = "1.2.0" +name = "rustc-demangle" +version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +checksum = "b50b8869d9fc858ce7266cce0194bd74df58b9d0e3f6df3a9fc8eb470d95c09d" [[package]] -name = "sea-bae" -version = "0.2.1" +name = "rustc-hash" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f694a6ab48f14bc063cfadff30ab551d3c7e46d8f81836c51989d548f44a2a25" -dependencies = [ - "heck 0.4.1", - "proc-macro-error2", - "proc-macro2", - "quote", - "syn 2.0.114", -] +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" [[package]] -name = "sea-orm" -version = "1.1.19" +name = "rustc-hash" +version = "2.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d945f62558fac19e5988680d2fdf747b734c2dbc6ce2cb81ba33ed8dde5b103" -dependencies = [ - "async-stream", - "async-trait", - "bigdecimal", - "chrono", - "derive_more 2.1.1", - "futures-util", - "log", - "ouroboros", - "pgvector", - "rust_decimal", - "sea-orm-macros", - "sea-query", - "sea-query-binder", - "serde", - "serde_json", - "sqlx", - "strum", - "thiserror 2.0.17", - "time", - "tracing", - "url", - "uuid", -] +checksum = "94300abf3f1ae2e2b8ffb7b58043de3d399c73fa6f4b73826402a5c457614dbe" [[package]] -name = "sea-orm-cli" -version = "1.1.19" +name = "rustc_version" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c94492e2ab6c045b4cc38013809ce255d14c3d352c9f0d11e6b920e2adc948ad" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" dependencies = [ - "chrono", - "clap", - "dotenvy", - "glob", - "regex", - "sea-schema", - "sqlx", - "tokio", - "tracing", - "tracing-subscriber", - "url", + "semver", ] [[package]] -name = "sea-orm-macros" -version = "1.1.19" +name = "rustix" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84c2e64a50a9cc8339f10a27577e10062c7f995488e469f2c95762c5ee847832" +checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" dependencies = [ - "heck 0.5.0", - "proc-macro2", - "quote", - "sea-bae", - "syn 2.0.114", - "unicode-ident", + "bitflags", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.61.2", ] [[package]] -name = "sea-orm-migration" -version = "1.1.19" +name = "rustls" +version = "0.23.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7315c0cadb7e60fb17ee2bb282aa27d01911fc2a7e5836ec1d4ac37d19250bb4" +checksum = "6b92b125634d9b795e7beca796cc790df15a7fb38323bf3196fda83292d06b1f" dependencies = [ - "async-trait", - "clap", - "dotenvy", - "sea-orm", - "sea-orm-cli", - "sea-schema", - "tracing", - "tracing-subscriber", + "log", + "once_cell", + "ring", + "rustls-pki-types", + "rustls-webpki", + "subtle", + "zeroize", ] [[package]] -name = "sea-query" -version = "0.32.7" +name = "rustls-pki-types" +version = "1.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a5d1c518eaf5eda38e5773f902b26ab6d5e9e9e2bb2349ca6c64cf96f80448c" +checksum = "30a7197ae7eb376e574fe940d068c30fe0462554a3ddbe4eca7838e049c937a9" dependencies = [ - "bigdecimal", - "chrono", - "inherent", - "ordered-float", - "rust_decimal", - "sea-query-derive", - "serde_json", - "time", - "uuid", + "web-time", + "zeroize", ] [[package]] -name = "sea-query-binder" -version = "0.7.0" +name = "rustls-webpki" +version = "0.103.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0019f47430f7995af63deda77e238c17323359af241233ec768aba1faea7608" +checksum = "61c429a8649f110dddef65e2a5ad240f747e85f7758a6bccc7e5777bd33f756e" dependencies = [ - "bigdecimal", - "chrono", - "rust_decimal", - "sea-query", - "serde_json", - "sqlx", - "time", - "uuid", + "ring", + "rustls-pki-types", + "untrusted", ] [[package]] -name = "sea-query-derive" -version = "0.4.3" +name = "rustversion" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bae0cbad6ab996955664982739354128c58d16e126114fe88c2a493642502aab" -dependencies = [ - "darling 0.20.11", - "heck 0.4.1", - "proc-macro2", - "quote", - "syn 2.0.114", - "thiserror 2.0.17", -] +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" [[package]] -name = "sea-schema" -version = "0.16.2" +name = "ryu" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2239ff574c04858ca77485f112afea1a15e53135d3097d0c86509cef1def1338" -dependencies = [ - "futures", - "sea-query", - "sea-query-binder", - "sea-schema-derive", - "sqlx", -] +checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" [[package]] -name = "sea-schema-derive" -version = "0.3.0" +name = "safetensors" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "debdc8729c37fdbf88472f97fd470393089f997a909e535ff67c544d18cfccf0" +checksum = "d93279b86b3de76f820a8854dd06cbc33cfa57a417b19c47f6a25280112fb1df" dependencies = [ - "heck 0.4.1", - "proc-macro2", - "quote", - "syn 2.0.114", + "serde", + "serde_json", ] [[package]] -name = "seahash" -version = "4.1.0" +name = "safetensors" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b" +checksum = "675656c1eabb620b921efea4f9199f97fc86e36dd6ffd1fbbe48d0f59a4987f5" +dependencies = [ + "hashbrown 0.16.1", + "serde", + "serde_json", +] [[package]] -name = "sealed" -version = "0.5.0" +name = "safetensors" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4a8caec23b7800fb97971a1c6ae365b6239aaeddfb934d6265f8505e795699d" +checksum = "79b079b829cb27a1c3c374341345ed2e8b2c0c839034522cee576c140bd7f846" dependencies = [ - "heck 0.4.1", - "proc-macro2", - "quote", - "syn 2.0.114", + "hashbrown 0.16.1", + "libc", + "serde", + "serde_json", + "tempfile", ] [[package]] -name = "security-framework" -version = "3.5.1" +name = "same-file" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3297343eaf830f66ede390ea39da1d462b6b0c1b000f420d0a83f898bbbe6ef" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" dependencies = [ - "bitflags", - "core-foundation", - "core-foundation-sys", - "libc", - "security-framework-sys", + "winapi-util", ] [[package]] -name = "security-framework-sys" -version = "2.15.0" +name = "sanitize-filename" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc1f0cbffaac4852523ce30d8bd3c5cdc873501d96ff467ca09b6767bb8cd5c0" +checksum = "bc984f4f9ceb736a7bb755c3e3bd17dc56370af2600c9780dcc48c66453da34d" dependencies = [ - "core-foundation-sys", - "libc", + "regex", ] +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + [[package]] name = "semver" -version = "1.0.27" +version = "1.0.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" -dependencies = [ - "serde", - "serde_core", -] +checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd" + +[[package]] +name = "seq-macro" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bc711410fbe7399f390ca1c3b60ad0f53f80e95c5eb935e52268a0e2cd49acc" [[package]] name = "serde" @@ -4504,15 +4765,13 @@ dependencies = [ ] [[package]] -name = "serde-xml-rs" -version = "0.8.2" +name = "serde_bytes" +version = "0.11.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc2215ce3e6a77550b80a1c37251b7d294febaf42e36e21b7b411e0bf54d540d" +checksum = "a5d440709e79d88e51ac01c4b72fc6cb7314017bb7da9eeff678aa94c10e3ea8" dependencies = [ - "log", "serde", - "thiserror 2.0.17", - "xml", + "serde_core", ] [[package]] @@ -4532,25 +4791,14 @@ checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", -] - -[[package]] -name = "serde_derive_internals" -version = "0.29.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.114", + "syn", ] [[package]] name = "serde_json" -version = "1.0.149" +version = "1.0.150" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" +checksum = "e8014e44b4736ed0538adeecded0fce2a272f22dc9578a7eb6b2d9993c74cfb9" dependencies = [ "itoa", "memchr", @@ -4560,28 +4808,12 @@ dependencies = [ ] [[package]] -name = "serde_norway" -version = "0.9.42" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e408f29489b5fd500fab51ff1484fc859bb655f32c671f307dcd733b72e8168c" -dependencies = [ - "indexmap", - "itoa", - "ryu", - "serde", - "unsafe-libyaml-norway", -] - -[[package]] -name = "serde_tokenstream" -version = "0.2.2" +name = "serde_spanned" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64060d864397305347a78851c51588fd283767e7e7589829e8121d65512340f1" +checksum = "6662b5879511e06e8999a8a235d848113e942c9124f211511b16466ee2995f26" dependencies = [ - "proc-macro2", - "quote", - "serde", - "syn 2.0.114", + "serde_core", ] [[package]] @@ -4596,19 +4828,6 @@ dependencies = [ "serde", ] -[[package]] -name = "serde_yaml" -version = "0.9.34+deprecated" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" -dependencies = [ - "indexmap", - "itoa", - "ryu", - "serde", - "unsafe-libyaml", -] - [[package]] name = "sha1" version = "0.10.6" @@ -4647,319 +4866,107 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] -name = "signal-hook-registry" -version = "1.4.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b" -dependencies = [ - "errno", - "libc", -] - -[[package]] -name = "signature" -version = "2.2.0" +name = "shlex" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" -dependencies = [ - "digest", - "rand_core 0.6.4", -] +checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba" [[package]] name = "simd-adler32" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e320a6c5ad31d271ad523dcf3ad13e2767ad8b1cb8f047f75a8aeaf8da139da2" - -[[package]] -name = "simdutf8" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" - -[[package]] -name = "simple_asn1" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "297f631f50729c8c99b84667867963997ec0b50f32b2a7dbcab828ef0541e8bb" -dependencies = [ - "num-bigint", - "num-traits", - "thiserror 2.0.17", - "time", -] - -[[package]] -name = "slab" -version = "0.4.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589" - -[[package]] -name = "smallvec" -version = "1.15.1" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" -dependencies = [ - "serde", -] +checksum = "703d5c7ef118737c72f1af64ad2f6f8c5e1921f818cdcb97b8fe6fc69bf66214" [[package]] -name = "smart-default" -version = "0.7.1" +name = "simd_helpers" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0eb01866308440fc64d6c44d9e86c5cc17adfe33c4d6eed55da9145044d0ffc1" +checksum = "95890f873bec569a0362c235787f3aca6e1e887302ba4840839bcc6459c42da6" dependencies = [ - "proc-macro2", "quote", - "syn 2.0.114", -] - -[[package]] -name = "smawk" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8e2fb0f499abb4d162f2bedad68f5ef91a1682b5a03596ddb67efd37768d100" - -[[package]] -name = "socket2" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17129e116933cf371d018bb80ae557e889637989d8638274fb25622827b03881" -dependencies = [ - "libc", - "windows-sys 0.60.2", ] [[package]] -name = "spin" -version = "0.9.8" +name = "slab" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" -dependencies = [ - "lock_api", -] +checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" [[package]] -name = "spki" -version = "0.7.3" +name = "slotmap" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" +checksum = "bdd58c3c93c3d278ca835519292445cb4b0d4dc59ccfdf7ceadaab3f8aeb4038" dependencies = [ - "base64ct", - "der", + "version_check", ] [[package]] -name = "sqlx" -version = "0.8.6" +name = "slug" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fefb893899429669dcdd979aff487bd78f4064e5e7907e4269081e0ef7d97dc" +checksum = "882a80f72ee45de3cc9a5afeb2da0331d58df69e4e7d8eeb5d3c7784ae67e724" dependencies = [ - "sqlx-core", - "sqlx-macros", - "sqlx-mysql", - "sqlx-postgres", - "sqlx-sqlite", + "deunicode", + "wasm-bindgen", ] [[package]] -name = "sqlx-core" -version = "0.8.6" +name = "smallvec" +version = "1.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee6798b1838b6a0f69c007c133b8df5866302197e404e8b6ee8ed3e3a5e68dc6" +checksum = "8ed6a63f02c8539c91a8685a86f4099661ba3da017932f6ebbea6de3f0fa7c90" dependencies = [ - "base64", - "bigdecimal", - "bytes", - "chrono", - "crc", - "crossbeam-queue", - "either", - "event-listener", - "futures-core", - "futures-intrusive", - "futures-io", - "futures-util", - "hashbrown 0.15.5", - "hashlink", - "indexmap", - "log", - "memchr", - "once_cell", - "percent-encoding", - "rust_decimal", - "rustls", "serde", - "serde_json", - "sha2", - "smallvec", - "thiserror 2.0.17", - "time", - "tokio", - "tokio-stream", - "tracing", - "url", - "uuid", - "webpki-roots 0.26.11", -] - -[[package]] -name = "sqlx-macros" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2d452988ccaacfbf5e0bdbc348fb91d7c8af5bee192173ac3636b5fb6e6715d" -dependencies = [ - "proc-macro2", - "quote", - "sqlx-core", - "sqlx-macros-core", - "syn 2.0.114", ] [[package]] -name = "sqlx-macros-core" -version = "0.8.6" +name = "socket2" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19a9c1841124ac5a61741f96e1d9e2ec77424bf323962dd894bdb93f37d5219b" +checksum = "52d1cfed4120b4d927bf7c0f86d2087a4a7d6027c906d9f9d525a80573b9be51" dependencies = [ - "dotenvy", - "either", - "heck 0.5.0", - "hex", - "once_cell", - "proc-macro2", - "quote", - "serde", - "serde_json", - "sha2", - "sqlx-core", - "sqlx-mysql", - "sqlx-postgres", - "sqlx-sqlite", - "syn 2.0.114", - "tokio", - "url", + "libc", + "windows-sys 0.61.2", ] [[package]] -name = "sqlx-mysql" -version = "0.8.6" +name = "spin" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa003f0038df784eb8fecbbac13affe3da23b45194bd57dba231c8f48199c526" -dependencies = [ - "atoi", - "base64", - "bigdecimal", - "bitflags", - "byteorder", - "bytes", - "chrono", - "crc", - "digest", - "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.5", - "rsa", - "rust_decimal", - "serde", - "sha1", - "sha2", - "smallvec", - "sqlx-core", - "stringprep", - "thiserror 2.0.17", - "time", - "tracing", - "uuid", - "whoami", +checksum = "d5fe4ccb98d9c292d56fec89a5e07da7fc4cf0dc11e156b41793132775d3e591" +dependencies = [ + "lock_api", + "portable-atomic", ] [[package]] -name = "sqlx-postgres" -version = "0.8.6" +name = "spirv" +version = "0.4.0+sdk-1.4.341.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db58fcd5a53cf07c184b154801ff91347e4c30d17a3562a635ff028ad5deda46" +checksum = "d9571ea910ebd84c86af4b3ed27f9dbdc6ad06f17c5f96146b2b671e2976744f" dependencies = [ - "atoi", - "base64", - "bigdecimal", "bitflags", - "byteorder", - "chrono", - "crc", - "dotenvy", - "etcetera", - "futures-channel", - "futures-core", - "futures-util", - "hex", - "hkdf", - "hmac", - "home", - "itoa", - "log", - "md-5", - "memchr", - "num-bigint", - "once_cell", - "rand 0.8.5", - "rust_decimal", - "serde", - "serde_json", - "sha2", - "smallvec", - "sqlx-core", - "stringprep", - "thiserror 2.0.17", - "time", - "tracing", - "uuid", - "whoami", ] [[package]] -name = "sqlx-sqlite" -version = "0.8.6" +name = "spm_precompiled" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2d12fe70b2c1b4401038055f90f151b78208de1f9f89a7dbfd41587a10c3eea" +checksum = "5851699c4033c63636f7ea4cf7b7c1f1bf06d0cc03cfb42e711de5a5c46cf326" dependencies = [ - "atoi", - "chrono", - "flume", - "futures-channel", - "futures-core", - "futures-executor", - "futures-intrusive", - "futures-util", - "libsqlite3-sys", - "log", - "percent-encoding", + "base64 0.13.1", + "nom 7.1.3", "serde", - "serde_urlencoded", - "sqlx-core", - "thiserror 2.0.17", - "time", - "tracing", - "url", - "uuid", + "unicode-segmentation", ] +[[package]] +name = "stable-vec" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dac7bc0f7d0d44329b200020effbc25a534d89fa142af95e3ddf76113412a5e" + [[package]] name = "stable_deref_trait" version = "1.2.1" @@ -4972,17 +4979,6 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" -[[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" @@ -4991,53 +4987,42 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "strum" -version = "0.26.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06" - -[[package]] -name = "subtle" -version = "2.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" - -[[package]] -name = "supports-color" -version = "3.0.2" +version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c64fc7232dd8d2e4ac5ce4ef302b1d81e0b80d055b9d77c7c4f51f6aa4c867d6" +checksum = "9628de9b8791db39ceda2b119bbe13134770b56c138ec1d3af810d045c04f9bd" dependencies = [ - "is_ci", + "strum_macros", ] [[package]] -name = "supports-hyperlinks" -version = "3.2.0" +name = "strum_macros" +version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e396b6523b11ccb83120b115a0b7366de372751aa6edf19844dfb13a6af97e91" +checksum = "ab85eea0270ee17587ed4156089e10b9e6880ee688791d45a905f5b1ca36f664" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] [[package]] -name = "supports-unicode" -version = "3.0.0" +name = "subtle" +version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7401a30af6cb5818bb64852270bb722533397edcfc7344954a38f420819ece2" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] -name = "syn" -version = "1.0.109" +name = "symlink" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] +checksum = "a7973cce6668464ea31f176d85b13c7ab3bba2cb3b77a2ed26abd7801688010a" [[package]] name = "syn" -version = "2.0.114" +version = "2.0.118" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4d107df263a3013ef9b1879b0df87d706ff80f65a86ea879bd9c31f9b307c2a" +checksum = "1b9ae57f904213ebb649ce6895b8a66c66f0203b9319718f69a5612a065b1422" dependencies = [ "proc-macro2", "quote", @@ -5061,82 +5046,104 @@ checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn", ] [[package]] -name = "synthez" -version = "0.3.1" +name = "sysctl" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3d2c2202510a1e186e63e596d9318c91a8cbe85cd1a56a7be0c333e5f59ec8d" +checksum = "01198a2debb237c62b6826ec7081082d951f46dbb64b0e8c7649a452230d1dfc" dependencies = [ - "syn 2.0.114", - "synthez-codegen", - "synthez-core", + "bitflags", + "byteorder", + "enum-as-inner", + "libc", + "thiserror 1.0.69", + "walkdir", ] [[package]] -name = "synthez-codegen" -version = "0.3.1" +name = "sysinfo" +version = "0.38.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f724aa6d44b7162f3158a57bccd871a77b39a4aef737e01bcdff41f4772c7746" +checksum = "92ab6a2f8bfe508deb3c6406578252e491d299cbbf3bc0529ecc3313aee4a52f" dependencies = [ - "syn 2.0.114", - "synthez-core", + "libc", + "memchr", + "ntapi", + "objc2-core-foundation", + "objc2-io-kit", + "windows", ] [[package]] -name = "synthez-core" -version = "0.3.1" +name = "tar" +version = "0.4.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78bfa6ec52465e2425fd43ce5bbbe0f0b623964f7c63feb6b10980e816c654ea" +checksum = "3f6221d9a6003c78398e3b239969f352578258df48c8eb051caadae0015bc840" dependencies = [ - "proc-macro2", - "quote", - "sealed", - "syn 2.0.114", + "filetime", + "libc", + "xattr", ] [[package]] -name = "tap" -version = "1.0.1" +name = "tch" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" +checksum = "9e09b91610202dc4820c21eb474a42b386ef69f323b1c0902b5472ba7456ebb5" +dependencies = [ + "half", + "lazy_static", + "libc", + "ndarray 0.16.1", + "rand 0.8.6", + "safetensors 0.3.3", + "thiserror 1.0.69", + "torch-sys", + "zip 0.6.6", +] [[package]] name = "tempfile" -version = "3.24.0" +version = "3.27.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "655da9c7eb6305c55742045d5a8d2037996d61d8de95806335c7c86ce0f82e9c" +checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd" dependencies = [ "fastrand", - "getrandom 0.3.4", + "getrandom 0.4.3", "once_cell", "rustix", "windows-sys 0.61.2", ] [[package]] -name = "terminal_size" -version = "0.4.3" +name = "termcolor" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60b8cb979cb11c32ce1603f8137b22262a9d131aaa5c37b5678025f22b8becd0" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" dependencies = [ - "rustix", - "windows-sys 0.60.2", + "winapi-util", ] [[package]] -name = "textwrap" -version = "0.16.2" +name = "text_placeholder" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c13547615a44dc9c452a8a534638acdf07120d4b6847c8178705da06306a3057" +checksum = "dd5008f74a09742486ef0047596cf35df2b914e2a8dca5727fcb6ba6842a766b" dependencies = [ - "smawk", - "unicode-linebreak", - "unicode-width 0.2.2", + "hashbrown 0.13.2", + "serde", + "serde_json", ] +[[package]] +name = "textdistance" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa672c55ab69f787dbc9126cc387dbe57fdd595f585e4524cf89018fa44ab819" + [[package]] name = "thiserror" version = "1.0.69" @@ -5148,11 +5155,11 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.17" +version = "2.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8" +checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" dependencies = [ - "thiserror-impl 2.0.17", + "thiserror-impl 2.0.18", ] [[package]] @@ -5163,18 +5170,18 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn", ] [[package]] name = "thiserror-impl" -version = "2.0.17" +version = "2.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" +checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn", ] [[package]] @@ -5186,17 +5193,28 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "tiff" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b63feaf3343d35b6ca4d50483f94843803b0f51634937cc2ec519fc32232bc52" +dependencies = [ + "fax", + "flate2", + "half", + "quick-error", + "weezl", + "zune-jpeg", +] + [[package]] name = "time" -version = "0.3.47" +version = "0.3.51" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "743bd48c283afc0388f9b8827b976905fb217ad9e647fae3a379a9283c4def2c" +checksum = "85c17d80feb7334b40c484e45ed1a5273dfd8bfda537c3be2e74a06a6686f327" dependencies = [ "deranged", - "itoa", - "libc", "num-conv", - "num_threads", "powerfmt", "serde_core", "time-core", @@ -5205,25 +5223,34 @@ dependencies = [ [[package]] name = "time-core" -version = "0.1.8" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7694e1cfe791f8d31026952abf09c69ca6f6fa4e1a1229e18988f06a04a12dca" +checksum = "9e1c906769ad99c88eaa54e728060edef082f8e358ff32030cb7c7d315e81109" [[package]] name = "time-macros" -version = "0.2.27" +version = "0.2.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e70e4c5a0e0a8a4823ad65dfe1a6930e4f4d756dcd9dd7939022b5e8c501215" +checksum = "dcef1a61bdb119096e153208ec5cbec23944ce8bca13be5c7f60c634f7403935" 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.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869" +checksum = "c8323304221c2a851516f22236c5722a72eaa19749016521d6dff0824447d96d" dependencies = [ "displaydoc", "zerovec", @@ -5231,9 +5258,9 @@ dependencies = [ [[package]] name = "tinyvec" -version = "1.10.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa5fdc3bce6191a1dbc8c02d5c8bffcf557bafa17c124c5264a458f1b0613fa" +checksum = "3e61e67053d25a4e82c844e8424039d9745781b3fc4f32b8d55ed50f5f667ef3" dependencies = [ "tinyvec_macros", ] @@ -5244,34 +5271,87 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" +[[package]] +name = "tokenizers" +version = "0.22.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b238e22d44a15349529690fb07bd645cf58149a1b1e44d6cb5bd1641ff1a6223" +dependencies = [ + "ahash", + "aho-corasick", + "compact_str", + "dary_heap", + "derive_builder", + "esaxx-rs", + "getrandom 0.3.4", + "itertools 0.14.0", + "log", + "macro_rules_attribute", + "monostate", + "onig", + "paste", + "rand 0.9.4", + "rayon", + "rayon-cond", + "regex", + "regex-syntax", + "serde", + "serde_json", + "spm_precompiled", + "thiserror 2.0.18", + "unicode-normalization-alignments", + "unicode-segmentation", + "unicode_categories", +] + +[[package]] +name = "tokenizers" +version = "0.23.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44e5bea67576e04b6ff8564c5d9e09c2ef0cf476502245f2f120e497769d3112" +dependencies = [ + "ahash", + "compact_str", + "daachorse", + "dary_heap", + "derive_builder", + "esaxx-rs", + "getrandom 0.3.4", + "indicatif", + "itertools 0.14.0", + "log", + "macro_rules_attribute", + "monostate", + "onig", + "paste", + "rand 0.9.4", + "rayon", + "rayon-cond", + "regex", + "regex-syntax", + "serde", + "serde_json", + "spm_precompiled", + "thiserror 2.0.18", + "unicode-normalization-alignments", + "unicode-segmentation", + "unicode_categories", +] + [[package]] name = "tokio" -version = "1.49.0" +version = "1.52.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72a2903cd7736441aac9df9d7688bd0ce48edccaadf181c3b90be801e81d3d86" +checksum = "8fc7f01b389ac15039e4dc9531aa973a135d7a4135281b12d7c1bc79fd57fffe" dependencies = [ "bytes", "libc", "mio", - "parking_lot", "pin-project-lite", - "signal-hook-registry", "socket2", - "tokio-macros", "windows-sys 0.61.2", ] -[[package]] -name = "tokio-macros" -version = "2.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.114", -] - [[package]] name = "tokio-rustls" version = "0.26.4" @@ -5282,17 +5362,6 @@ dependencies = [ "tokio", ] -[[package]] -name = "tokio-stream" -version = "0.1.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32da49809aab5c3bc678af03902d4ccddea2a87d028d86392a4b1560c6906c70" -dependencies = [ - "futures-core", - "pin-project-lite", - "tokio", -] - [[package]] name = "tokio-util" version = "0.7.18" @@ -5306,20 +5375,35 @@ dependencies = [ "tokio", ] +[[package]] +name = "toml" +version = "1.1.2+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81f3d15e84cbcd896376e6730314d59fb5a87f31e4b038454184435cd57defee" +dependencies = [ + "indexmap", + "serde_core", + "serde_spanned", + "toml_datetime", + "toml_parser", + "toml_writer", + "winnow", +] + [[package]] name = "toml_datetime" -version = "0.7.5+spec-1.1.0" +version = "1.1.1+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92e1cfed4a3038bc5a127e35a2d360f145e1f4b971b551a2ba5fd7aedf7e1347" +checksum = "3165f65f62e28e0115a00b2ebdd37eb6f3b641855f9d636d3cd4103767159ad7" dependencies = [ "serde_core", ] [[package]] name = "toml_edit" -version = "0.23.10+spec-1.0.0" +version = "0.25.12+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84c8b9f757e028cee9fa244aea147aab2a9ec09d5325a9b01e0a49730c2b5269" +checksum = "d2153edc6955a6c354fad8f5efd38b6a8769bdccf9fe50f8e1329f81b0baa5d7" dependencies = [ "indexmap", "toml_datetime", @@ -5329,50 +5413,39 @@ dependencies = [ [[package]] name = "toml_parser" -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 = "a3198b4b0a8e11f09dd03e133c0280504d0801269e9afa46362ffde1cbeebf44" +checksum = "a2abe9b86193656635d2411dc43050282ca48aa31c2451210f4202550afb7526" dependencies = [ "winnow", ] [[package]] -name = "tonic" -version = "0.14.2" +name = "toml_writer" +version = "1.1.1+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb7613188ce9f7df5bfe185db26c5814347d110db17920415cf2fbcad85e7203" -dependencies = [ - "async-trait", - "base64", - "bytes", - "http", - "http-body", - "http-body-util", - "percent-encoding", - "pin-project", - "sync_wrapper", - "tokio-stream", - "tower-layer", - "tower-service", - "tracing", -] +checksum = "756daf9b1013ebe47a8776667b466417e2d4c5679d441c26230efd9ef78692db" [[package]] -name = "tonic-prost" -version = "0.14.2" +name = "torch-sys" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66bd50ad6ce1252d87ef024b3d64fe4c3cf54a86fb9ef4c631fdd0ded7aeaa67" +checksum = "aef40c585e342df95b66a1fa7c923188623999c2b657227befb481dfb03a6a42" dependencies = [ - "bytes", - "prost", - "tonic", + "anyhow", + "cc", + "libc", + "serde", + "serde_json", + "ureq", + "zip 0.6.6", ] [[package]] name = "tower" -version = "0.5.2" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9" +checksum = "ebe5ef63511595f1344e2d5cfa636d973292adc0eec1f0ad45fae9f0851ab1d4" dependencies = [ "futures-core", "futures-util", @@ -5385,20 +5458,20 @@ dependencies = [ [[package]] name = "tower-http" -version = "0.6.8" +version = "0.6.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4e6559d53cc268e5031cd8429d05415bc4cb4aefc4aa5d6cc35fbf5b924a1f8" +checksum = "4cfcf7e2740e6fc6d4d688b4ef00650406bb94adf4731e43c096c3a19fe40840" dependencies = [ "bitflags", "bytes", "futures-util", "http", "http-body", - "iri-string", "pin-project-lite", "tower", "tower-layer", "tower-service", + "url", ] [[package]] @@ -5413,18 +5486,109 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" +[[package]] +name = "tracel-llvm" +version = "20.1.4-7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "982535db9eb1a30ac0f2c50239a0eec3e5cf50993a88e92b04747bd2f4d365b2" +dependencies = [ + "tracel-mlir-rs", + "tracel-mlir-sys", +] + +[[package]] +name = "tracel-llvm-bundler" +version = "20.1.4-7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c75b8e477cb8d49d907afab029ca74d48459f5b88c27bdb4c6cd6acb5e61977" +dependencies = [ + "anyhow", + "bytes", + "constcat", + "dirs", + "liblzma", + "regex", + "reqwest", + "serde", + "serde_json", + "sha2", + "tar", + "walkdir", +] + +[[package]] +name = "tracel-mlir-rs" +version = "20.1.4-7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a478a35efd68d0ba73f747adfb7923b121c64e7f5be9cd8364ca1dcb772d5c" +dependencies = [ + "tracel-mlir-rs-macros", + "tracel-mlir-sys", +] + +[[package]] +name = "tracel-mlir-rs-macros" +version = "20.1.4-7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a94f36868c3b10b1825945223d99d106c73f4d249f063caa4651deeb9379344" +dependencies = [ + "comrak", + "convert_case 0.8.0", + "proc-macro2", + "quote", + "regex", + "syn", + "tracel-llvm-bundler", + "tracel-tblgen-rs", + "unindent", +] + +[[package]] +name = "tracel-mlir-sys" +version = "20.1.4-7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02f26d31af0c225a6d2e3d65d012fd6de848c9fc776897b152ee83b7d1bd15c4" +dependencies = [ + "tracel-llvm-bundler", +] + +[[package]] +name = "tracel-tblgen-rs" +version = "20.1.4-7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00d2581070380418ccc33b500f3739e4d4869421fdb477fcea51ff97c6253a52" +dependencies = [ + "bindgen", + "cc", + "paste", + "thiserror 2.0.18", + "tracel-llvm-bundler", +] + [[package]] name = "tracing" version = "0.1.44" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" dependencies = [ - "log", "pin-project-lite", "tracing-attributes", "tracing-core", ] +[[package]] +name = "tracing-appender" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "050686193eb999b4bb3bc2acfa891a13da00f79734704c4b8b4ef1a10b368a3c" +dependencies = [ + "crossbeam-channel", + "symlink", + "thiserror 2.0.18", + "time", + "tracing-subscriber", +] + [[package]] name = "tracing-attributes" version = "0.1.31" @@ -5433,7 +5597,7 @@ checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn", ] [[package]] @@ -5457,37 +5621,22 @@ dependencies = [ "tracing-core", ] -[[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.22" +version = "0.3.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f30143827ddab0d256fd843b7a66d164e9f271cfa0dde49142c5ca0ca291f1e" +checksum = "cb7f578e5945fb242538965c2d0b04418d38ec25c79d160cd279bf0731c8d319" dependencies = [ - "chrono", "matchers", "nu-ansi-term", "once_cell", "regex-automata", - "serde", - "serde_json", "sharded-slab", "smallvec", "thread_local", - "time", "tracing", "tracing-core", "tracing-log", - "tracing-serde", ] [[package]] @@ -5497,111 +5646,46 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" [[package]] -name = "typed-builder" -version = "0.15.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fe83c85a85875e8c4cb9ce4a890f05b23d38cd0d47647db7895d3d2a79566d2" -dependencies = [ - "typed-builder-macro", -] - -[[package]] -name = "typed-builder-macro" -version = "0.15.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29a3151c41d0b13e3d011f98adc24434560ef06673a155a6c7f66b9879eecce2" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.114", -] - -[[package]] -name = "typenum" -version = "1.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" - -[[package]] -name = "typify" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7144144e97e987c94758a3017c920a027feac0799df325d6df4fc8f08d02068e" -dependencies = [ - "typify-impl", - "typify-macro", -] - -[[package]] -name = "typify-impl" -version = "0.4.3" +name = "tynm" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "062879d46aa4c9dfe0d33b035bbaf512da192131645d05deacb7033ec8581a09" +checksum = "a21cdb0fc8f85c98b1ec812bc4cd69faf6c0fa2fc17d44ea3c2cdd38dc08e999" dependencies = [ - "heck 0.5.0", - "log", - "proc-macro2", - "quote", - "regress", - "schemars", - "semver", - "serde", - "serde_json", - "syn 2.0.114", - "thiserror 2.0.17", - "unicode-ident", + "nom 8.0.0", ] [[package]] -name = "typify-macro" -version = "0.4.3" +name = "type-map" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9708a3ceb6660ba3f8d2b8f0567e7d4b8b198e2b94d093b8a6077a751425de9e" +checksum = "cb30dbbd9036155e74adad6812e9898d03ec374946234fbcebd5dfc7b9187b90" dependencies = [ - "proc-macro2", - "quote", - "schemars", - "semver", - "serde", - "serde_json", - "serde_tokenstream", - "syn 2.0.114", - "typify-impl", + "rustc-hash 2.1.2", ] [[package]] -name = "ulid" -version = "1.2.1" +name = "typed-arena" +version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "470dbf6591da1b39d43c14523b2b469c86879a53e8b758c8e090a470fe7b1fbe" -dependencies = [ - "rand 0.9.2", - "web-time", -] +checksum = "6af6ae20167a9ece4bcb41af5b80f8a1f1df981f6391189ce00fd257af04126a" [[package]] -name = "unicase" -version = "2.9.0" +name = "typed-path" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbc4bc3a9f746d862c45cb89d705aa10f187bb96c76001afab07a0d35ce60142" +checksum = "8e28f89b80c87b8fb0cf04ab448d5dd0dd0ade2f8891bae878de66a75a28600e" [[package]] -name = "unicode-bidi" -version = "0.3.18" +name = "typenum" +version = "1.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c1cb5db39152898a79168971543b1cb5020dff7fe43c8dc468b0885f5e29df5" +checksum = "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20" [[package]] name = "unicode-ident" -version = "1.0.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" - -[[package]] -name = "unicode-linebreak" -version = "0.1.5" +version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b09c83c3c29d37506a3e260c08c03743a6bb66a9cd432c6934ab501a190571f" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" [[package]] name = "unicode-normalization" @@ -5613,22 +5697,19 @@ dependencies = [ ] [[package]] -name = "unicode-properties" -version = "0.1.4" +name = "unicode-normalization-alignments" +version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7df058c713841ad818f1dc5d3fd88063241cc61f49f5fbea4b951e8cf5a8d71d" +checksum = "43f613e4fa046e69818dd287fdc4bc78175ff20331479dab6e1b0f98d57062de" +dependencies = [ + "smallvec", +] [[package]] name = "unicode-segmentation" -version = "1.12.0" +version = "1.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" - -[[package]] -name = "unicode-width" -version = "0.1.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" +checksum = "c6f5d3c3b1bf09027a88a6bc961fc00497d651009560b5463668dc81b0fa87a8" [[package]] name = "unicode-width" @@ -5643,38 +5724,52 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" [[package]] -name = "universal-hash" -version = "0.5.1" +name = "unicode_categories" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea" -dependencies = [ - "crypto-common", - "subtle", -] +checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e" [[package]] -name = "unsafe-libyaml" -version = "0.2.11" +name = "unindent" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" +checksum = "7264e107f553ccae879d21fbea1d6724ac785e8c3bfc762137959b5802826ef3" [[package]] -name = "unsafe-libyaml-norway" -version = "0.2.15" +name = "unit-prefix" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b39abd59bf32521c7f2301b52d05a6a2c975b6003521cbd0c6dc1582f0a22104" +checksum = "81e544489bf3d8ef66c953931f56617f423cd4b5494be343d9b9d3dda037b9a3" [[package]] name = "untrusted" -version = "0.7.1" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] -name = "untrusted" -version = "0.9.0" +name = "unty" +version = "0.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" +checksum = "6d49784317cd0d1ee7ec5c716dd598ec5b4483ea832a2dced265471cc0f690ae" + +[[package]] +name = "ureq" +version = "2.12.1" +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", + "url", + "webpki-roots 0.26.11", +] [[package]] name = "url" @@ -5683,17 +5778,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed" dependencies = [ "form_urlencoded", - "idna 1.1.0", + "idna", "percent-encoding", "serde", ] -[[package]] -name = "urlencoding" -version = "2.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" - [[package]] name = "utf8_iter" version = "1.0.4" @@ -5708,44 +5797,19 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "uuid" -version = "1.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2e054861b4bd027cd373e18e8d8d8e6548085000e41290d95ce0c373a654b4a" -dependencies = [ - "getrandom 0.3.4", - "js-sys", - "serde_core", - "wasm-bindgen", -] - -[[package]] -name = "validator" -version = "0.18.1" +version = "1.23.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db79c75af171630a3148bd3e6d7c4f42b6a9a014c2945bc5ed0020cbb8d9478e" -dependencies = [ - "idna 0.5.0", - "once_cell", - "regex", - "serde", - "serde_derive", - "serde_json", - "url", - "validator_derive", -] +checksum = "bf80a72845275afea99e7f2b434723d3bc7e38470fcd1c7ed39a599c73319a53" [[package]] -name = "validator_derive" -version = "0.18.2" +name = "v_frame" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df0bcf92720c40105ac4b2dda2a4ea3aa717d4d6a862cc217da653a4bd5c6b10" +checksum = "666b7727c8875d6ab5db9533418d7c764233ac9c0cff1d469aec8fa127597be2" dependencies = [ - "darling 0.20.11", - "once_cell", - "proc-macro-error", - "proc-macro2", - "quote", - "syn 2.0.114", + "aligned-vec", + "num-traits", + "wasm-bindgen", ] [[package]] @@ -5755,46 +5819,14 @@ 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 = "vergen" -version = "9.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b849a1f6d8639e8de261e81ee0fc881e3e3620db1af9f2e0da015d4382ceaf75" -dependencies = [ - "anyhow", - "derive_builder", - "rustversion", - "vergen-lib", -] - -[[package]] -name = "vergen-gitcl" -version = "9.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77ff3b5300a085d6bcd8fc96a507f706a28ae3814693236c9b409db71a1d15b9" -dependencies = [ - "anyhow", - "derive_builder", - "rustversion", - "time", - "vergen", - "vergen-lib", -] - -[[package]] -name = "vergen-lib" -version = "9.1.0" +name = "variadics_please" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b34a29ba7e9c59e62f229ae1932fb1b8fb8a6fdcc99215a641913f5f5a59a569" +checksum = "41b6d82be61465f97d42bd1d15bf20f3b0a3a0905018f38f9d6f6962055b0b5c" dependencies = [ - "anyhow", - "derive_builder", - "rustversion", + "proc-macro2", + "quote", + "syn", ] [[package]] @@ -5803,6 +5835,12 @@ version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" +[[package]] +name = "void" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" + [[package]] name = "walkdir" version = "2.5.0" @@ -5830,33 +5868,18 @@ checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] name = "wasip2" -version = "1.0.1+wasi-0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7" -dependencies = [ - "wit-bindgen 0.46.0", -] - -[[package]] -name = "wasip3" -version = "0.4.0+wasi-0.3.0-rc-2026-01-06" +version = "1.0.4+wasi-0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5" +checksum = "b67efb37e106e55ce722a510d6b5f9c17f083e5fc79afc2badeb12cc313d9487" dependencies = [ - "wit-bindgen 0.51.0", + "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.106" +version = "0.2.126" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d759f433fa64a2d763d1340820e46e111a7a5ab75f993d1852d70b03dbb80fd" +checksum = "4b067c0c11094aef6b7a801c1e34a26affafdf3d051dba08456b868789aaf9a4" dependencies = [ "cfg-if", "once_cell", @@ -5867,22 +5890,19 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.56" +version = "0.4.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "836d9622d604feee9e5de25ac10e3ea5f2d65b41eac0d9ce72eb5deae707ce7c" +checksum = "c62df1340f32221cb9c54d6a27b030e3dba64361d4a95bed55f9aacb44da291d" dependencies = [ - "cfg-if", "js-sys", - "once_cell", "wasm-bindgen", - "web-sys", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.106" +version = "0.2.126" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48cb0d2638f8baedbc542ed444afc0644a29166f1595371af4fecf8ce1e7eeb3" +checksum = "167ce5e579f6bcf889c4f7175a8a5a585de84e8ff93976ce393efa5f2837aab1" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -5890,137 +5910,300 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.106" +version = "0.2.126" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cefb59d5cd5f92d9dcf80e4683949f15ca4b511f4ac0a6e14d4e1ac60c6ecd40" +checksum = "f3997c7839262f4ef12cf90b818d6340c18e80f263f1a94bf157d0ec4420380e" dependencies = [ "bumpalo", "proc-macro2", "quote", - "syn 2.0.114", + "syn", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.106" +version = "0.2.126" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbc538057e648b67f72a982e708d485b2efa771e1ac05fec311f9f63e5800db4" +checksum = "dc1b4cb0cc549fcf58d7dfc081778139b3d283a081644e833e84682ad71cea24" dependencies = [ "unicode-ident", ] [[package]] -name = "wasm-encoder" -version = "0.244.0" +name = "wayland-sys" +version = "0.31.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8eab23fefc9e41f8e841df4a9c707e8a8c4ed26e944ef69297184de2785e3be" +dependencies = [ + "dlib", + "log", + "once_cell", + "pkg-config", +] + +[[package]] +name = "web-sys" +version = "0.3.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319" +checksum = "8622dcb61c0bcc9fffa6938bed81210af2da9a7e4a1a834b2e37a59b6dfb6141" dependencies = [ - "leb128fmt", - "wasmparser", + "js-sys", + "wasm-bindgen", ] [[package]] -name = "wasm-metadata" -version = "0.244.0" +name = "web-time" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909" +checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" dependencies = [ - "anyhow", - "indexmap", - "wasm-encoder", - "wasmparser", + "js-sys", + "wasm-bindgen", ] [[package]] -name = "wasm-streams" -version = "0.4.2" +name = "webpki-roots" +version = "0.26.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15053d8d85c7eccdbefef60f06769760a563c7f0a9d6902a13d35c7800b0ad65" +checksum = "521bc38abb08001b01866da9f51eb7c5d647a19260e00054a8c7fd5f9e57f7a9" dependencies = [ - "futures-util", + "webpki-roots 1.0.8", +] + +[[package]] +name = "webpki-roots" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf85cb06032201fa7c6f829d7db5a7e5aa45bcc0655327713065f6f0576731bf" +dependencies = [ + "rustls-pki-types", +] + +[[package]] +name = "weezl" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a28ac98ddc8b9274cb41bb4d9d4d5c425b6020c50c46f25559911905610b4a88" + +[[package]] +name = "wgpu" +version = "29.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb3feacc458f7bee8bc1737149b42b6c731aa461039a4264a67bb6681646b250" +dependencies = [ + "arrayvec", + "bitflags", + "bytemuck", + "cfg-if", + "cfg_aliases", + "document-features", + "hashbrown 0.16.1", "js-sys", + "log", + "naga", + "parking_lot", + "portable-atomic", + "profiling", + "raw-window-handle", + "smallvec", + "static_assertions", "wasm-bindgen", "wasm-bindgen-futures", "web-sys", + "wgpu-core", + "wgpu-hal", + "wgpu-types", ] [[package]] -name = "wasmparser" -version = "0.244.0" +name = "wgpu-core" +version = "29.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" +checksum = "02da3ad1b568337f25513b317870960ef87073ea0945502e44b864b67a8c77b7" dependencies = [ + "arrayvec", + "bit-set", + "bit-vec", "bitflags", - "hashbrown 0.15.5", + "bytemuck", + "cfg_aliases", + "document-features", + "hashbrown 0.16.1", "indexmap", - "semver", + "log", + "naga", + "once_cell", + "parking_lot", + "portable-atomic", + "profiling", + "raw-window-handle", + "rustc-hash 1.1.0", + "smallvec", + "thiserror 2.0.18", + "wgpu-core-deps-apple", + "wgpu-core-deps-emscripten", + "wgpu-core-deps-windows-linux-android", + "wgpu-hal", + "wgpu-naga-bridge", + "wgpu-types", ] [[package]] -name = "web-sys" -version = "0.3.83" +name = "wgpu-core-deps-apple" +version = "29.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62e51b5447e144b3dbba4feb01f80f4fa21696fa0cd99afb2c3df1affd6fdb28" +dependencies = [ + "wgpu-hal", +] + +[[package]] +name = "wgpu-core-deps-emscripten" +version = "29.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3487cd6293a963bc5c0c0396f6a2192043c50003c07f4efdccbad3d90ec9d819" +dependencies = [ + "wgpu-hal", +] + +[[package]] +name = "wgpu-core-deps-windows-linux-android" +version = "29.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb01076d0aa08b0ba9bd741e178b5cc440f5abe99d9581323a4c8b5d1a1916" +dependencies = [ + "wgpu-hal", +] + +[[package]] +name = "wgpu-hal" +version = "29.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b32828d774c412041098d182a8b38b16ea816958e07cf40eec2bc080ae137ac" +checksum = "31f8e1a9e7a8512f276f7c62e018c7fa8d60954303fed2e5750114332049193f" dependencies = [ + "android_system_properties", + "arrayvec", + "ash", + "bit-set", + "bitflags", + "block2", + "bytemuck", + "cfg-if", + "cfg_aliases", + "glow", + "glutin_wgl_sys", + "gpu-allocator", + "gpu-descriptor", + "hashbrown 0.16.1", "js-sys", + "khronos-egl", + "libc", + "libloading 0.8.9", + "log", + "naga", + "ndk-sys", + "objc2", + "objc2-core-foundation", + "objc2-foundation", + "objc2-metal", + "objc2-quartz-core", + "once_cell", + "ordered-float", + "parking_lot", + "portable-atomic", + "portable-atomic-util", + "profiling", + "range-alloc", + "raw-window-handle", + "raw-window-metal", + "renderdoc-sys", + "smallvec", + "thiserror 2.0.18", "wasm-bindgen", + "wayland-sys", + "web-sys", + "wgpu-naga-bridge", + "wgpu-types", + "windows", + "windows-core", + "windows-result", ] [[package]] -name = "web-time" -version = "1.1.0" +name = "wgpu-naga-bridge" +version = "29.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" +checksum = "59c654c483f058800972c3645e95388a7eca31bf9fe1933bc20e036588a0be02" +dependencies = [ + "naga", + "wgpu-types", +] + +[[package]] +name = "wgpu-types" +version = "29.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9bcc31518a0e9735aefebedb5f7a9ef3ed1c42549c9f4c882fa9060ceaac639" dependencies = [ + "bitflags", + "bytemuck", "js-sys", - "wasm-bindgen", + "log", + "raw-window-handle", + "web-sys", ] [[package]] -name = "webpki-root-certs" -version = "1.0.5" +name = "winapi" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36a29fc0408b113f68cf32637857ab740edfafdf460c326cd2afaa2d84cc05dc" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" dependencies = [ - "rustls-pki-types", + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", ] [[package]] -name = "webpki-roots" -version = "0.26.11" +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "521bc38abb08001b01866da9f51eb7c5d647a19260e00054a8c7fd5f9e57f7a9" -dependencies = [ - "webpki-roots 1.0.5", -] +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] -name = "webpki-roots" -version = "1.0.5" +name = "winapi-util" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12bed680863276c63889429bfd6cab3b99943659923822de1c8a39c49e4d722c" +checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ - "rustls-pki-types", + "windows-sys 0.61.2", ] [[package]] -name = "whoami" -version = "1.6.1" +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows" +version = "0.62.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d4a4db5077702ca3015d3d02d74974948aba2ad9e12ab7df718ee64ccd7e97d" +checksum = "527fadee13e0c05939a6a05d5bd6eec6cd2e3dbd648b9f8e447c6518133d8580" dependencies = [ - "libredox", - "wasite", + "windows-collections", + "windows-core", + "windows-future", + "windows-numerics", ] [[package]] -name = "winapi-util" -version = "0.1.11" +name = "windows-collections" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" +checksum = "23b2d95af1a8a14a3c7367e1ed4fc9c20e0a26e79551b1454d72583c97cc6610" dependencies = [ - "windows-sys 0.61.2", + "windows-core", ] [[package]] @@ -6036,6 +6219,17 @@ dependencies = [ "windows-strings", ] +[[package]] +name = "windows-future" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1d6f90251fe18a279739e78025bd6ddc52a7e22f921070ccdc67dde84c605cb" +dependencies = [ + "windows-core", + "windows-link", + "windows-threading", +] + [[package]] name = "windows-implement" version = "0.60.2" @@ -6044,7 +6238,7 @@ checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn", ] [[package]] @@ -6055,7 +6249,7 @@ checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn", ] [[package]] @@ -6064,6 +6258,16 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" +[[package]] +name = "windows-numerics" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e2e40844ac143cdb44aead537bbf727de9b044e107a0f1220392177d15b0f26" +dependencies = [ + "windows-core", + "windows-link", +] + [[package]] name = "windows-result" version = "0.4.1" @@ -6082,24 +6286,6 @@ dependencies = [ "windows-link", ] -[[package]] -name = "windows-sys" -version = "0.45.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" -dependencies = [ - "windows-targets 0.42.2", -] - -[[package]] -name = "windows-sys" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" -dependencies = [ - "windows-targets 0.48.5", -] - [[package]] name = "windows-sys" version = "0.52.0" @@ -6109,15 +6295,6 @@ dependencies = [ "windows-targets 0.52.6", ] -[[package]] -name = "windows-sys" -version = "0.59.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" -dependencies = [ - "windows-targets 0.52.6", -] - [[package]] name = "windows-sys" version = "0.60.2" @@ -6136,36 +6313,6 @@ dependencies = [ "windows-link", ] -[[package]] -name = "windows-targets" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" -dependencies = [ - "windows_aarch64_gnullvm 0.42.2", - "windows_aarch64_msvc 0.42.2", - "windows_i686_gnu 0.42.2", - "windows_i686_msvc 0.42.2", - "windows_x86_64_gnu 0.42.2", - "windows_x86_64_gnullvm 0.42.2", - "windows_x86_64_msvc 0.42.2", -] - -[[package]] -name = "windows-targets" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" -dependencies = [ - "windows_aarch64_gnullvm 0.48.5", - "windows_aarch64_msvc 0.48.5", - "windows_i686_gnu 0.48.5", - "windows_i686_msvc 0.48.5", - "windows_x86_64_gnu 0.48.5", - "windows_x86_64_gnullvm 0.48.5", - "windows_x86_64_msvc 0.48.5", -] - [[package]] name = "windows-targets" version = "0.52.6" @@ -6200,16 +6347,13 @@ dependencies = [ ] [[package]] -name = "windows_aarch64_gnullvm" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.48.5" +name = "windows-threading" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" +checksum = "3949bd5b99cafdf1c7ca86b43ca564028dfe27d66958f2470940f73d86d75b37" +dependencies = [ + "windows-link", +] [[package]] name = "windows_aarch64_gnullvm" @@ -6223,18 +6367,6 @@ version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" -[[package]] -name = "windows_aarch64_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" - [[package]] name = "windows_aarch64_msvc" version = "0.52.6" @@ -6247,18 +6379,6 @@ version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" -[[package]] -name = "windows_i686_gnu" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" - -[[package]] -name = "windows_i686_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" - [[package]] name = "windows_i686_gnu" version = "0.52.6" @@ -6283,18 +6403,6 @@ version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" -[[package]] -name = "windows_i686_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" - -[[package]] -name = "windows_i686_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" - [[package]] name = "windows_i686_msvc" version = "0.52.6" @@ -6307,18 +6415,6 @@ version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" -[[package]] -name = "windows_x86_64_gnu" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" - [[package]] name = "windows_x86_64_gnu" version = "0.52.6" @@ -6331,18 +6427,6 @@ version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" - [[package]] name = "windows_x86_64_gnullvm" version = "0.52.6" @@ -6355,18 +6439,6 @@ version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" -[[package]] -name = "windows_x86_64_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" - [[package]] name = "windows_x86_64_msvc" version = "0.52.6" @@ -6381,166 +6453,73 @@ checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" [[package]] name = "winnow" -version = "0.7.14" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a5364e9d77fcdeeaa6062ced926ee3381faa2ee02d3eb83a5c27a8825540829" +checksum = "0592e1c9d151f854e6fd382574c3a0855250e1d9b2f99d9281c6e6391af352f1" dependencies = [ "memchr", ] [[package]] name = "wit-bindgen" -version = "0.46.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" - -[[package]] -name = "wit-bindgen" -version = "0.51.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" -dependencies = [ - "wit-bindgen-rust-macro", -] - -[[package]] -name = "wit-bindgen-core" -version = "0.51.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc" -dependencies = [ - "anyhow", - "heck 0.5.0", - "wit-parser", -] - -[[package]] -name = "wit-bindgen-rust" -version = "0.51.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21" -dependencies = [ - "anyhow", - "heck 0.5.0", - "indexmap", - "prettyplease", - "syn 2.0.114", - "wasm-metadata", - "wit-bindgen-core", - "wit-component", -] - -[[package]] -name = "wit-bindgen-rust-macro" -version = "0.51.0" +version = "0.57.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a" -dependencies = [ - "anyhow", - "prettyplease", - "proc-macro2", - "quote", - "syn 2.0.114", - "wit-bindgen-core", - "wit-bindgen-rust", -] +checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e" [[package]] -name = "wit-component" -version = "0.244.0" +name = "writeable" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2" -dependencies = [ - "anyhow", - "bitflags", - "indexmap", - "log", - "serde", - "serde_derive", - "serde_json", - "wasm-encoder", - "wasm-metadata", - "wasmparser", - "wit-parser", -] +checksum = "1ffae5123b2d3fc086436f8834ae3ab053a283cfac8fe0a0b8eaae044768a4c4" [[package]] -name = "wit-parser" -version = "0.244.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736" +name = "wubbie" +version = "0.1.0" dependencies = [ "anyhow", - "id-arena", - "indexmap", - "log", - "semver", + "burn", + "clap", + "safetensors 0.8.0", "serde", - "serde_derive", "serde_json", - "unicode-xid", - "wasmparser", -] - -[[package]] -name = "writeable" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9" - -[[package]] -name = "wyz" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" -dependencies = [ - "tap", + "tokenizers 0.23.1", + "tracing", + "tracing-subscriber", ] [[package]] -name = "x509-parser" -version = "0.18.0" +name = "xattr" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb3e137310115a65136898d2079f003ce33331a6c4b0d51f1531d1be082b6425" +checksum = "32e45ad4206f6d2479085147f02bc2ef834ac85886624a23575ae137c8aa8156" dependencies = [ - "asn1-rs", - "data-encoding", - "der-parser", - "lazy_static", - "nom", - "oid-registry", - "ring", - "rusticata-macros", - "thiserror 2.0.17", - "time", + "libc", + "rustix", ] [[package]] -name = "xml" -version = "1.2.0" +name = "xml-rs" +version = "0.8.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2df5825faced2427b2da74d9100f1e2e93c533fff063506a81ede1cf517b2e7e" +checksum = "3ae8337f8a065cfc972643663ea4279e04e7256de865aa66fe25cec5fb912d3f" [[package]] -name = "yansi" -version = "1.0.1" +name = "xxhash-rust" +version = "0.8.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049" +checksum = "fdd20c5420375476fbd4394763288da7eb0cc0b8c11deed431a91562af7335d3" [[package]] -name = "yasna" -version = "0.5.2" +name = "y4m" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e17bb3549cc1321ae1296b9cdc2698e2b6cb1992adfa19a8c72e5b7a738f44cd" -dependencies = [ - "time", -] +checksum = "7a5a4b21e1a62b67a2970e6831bc091d7b87e119e7f9791aef9702e3bef04448" [[package]] name = "yoke" -version = "0.8.1" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72d6e5c6afb84d73944e5cedb052c4680d5657337201555f9f2a16b7406d4954" +checksum = "709fe23a0424b6a435d82152b1bd3fdfb0833487d5fa90d05d42762a9891fef5" dependencies = [ "stable_deref_trait", "yoke-derive", @@ -6549,68 +6528,68 @@ dependencies = [ [[package]] name = "yoke-derive" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" +checksum = "de844c262c8848816172cef550288e7dc6c7b7814b4ee56b3e1553f275f1858e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn", "synstructure", ] [[package]] name = "zerocopy" -version = "0.8.33" +version = "0.8.52" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "668f5168d10b9ee831de31933dc111a459c97ec93225beb307aed970d1372dfd" +checksum = "ce1022995ff5ff5d841ad7d994facc23098cd40152f2c1d11cd607c6f530653f" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.33" +version = "0.8.52" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c7962b26b0a8685668b671ee4b54d007a67d4eaf05fda79ac0ecf41e32270f1" +checksum = "1ae7f38b72ec2a254e2b87ef277cf2cd4fb97cbebf944faa6f33354da0867930" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn", ] [[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.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" +checksum = "11532158c46691caf0f2593ea8358fed6bbf68a0315e80aae9bd41fbade684a1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn", "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" [[package]] name = "zerotrie" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a59c17a5562d507e4b54960e8569ebee33bee890c70aa3fe7b97e85a9fd7851" +checksum = "0f9152d31db0792fa83f70fb2f83148effb5c1f5b8c7686c3459e361d9bc20bf" dependencies = [ "displaydoc", "yoke", @@ -6619,9 +6598,9 @@ dependencies = [ [[package]] name = "zerovec" -version = "0.11.5" +version = "0.11.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002" +checksum = "90f911cbc359ab6af17377d242225f4d75119aec87ea711a880987b18cd7b239" dependencies = [ "yoke", "zerofrom", @@ -6630,36 +6609,69 @@ dependencies = [ [[package]] name = "zerovec-derive" -version = "0.11.2" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" +checksum = "625dc425cab0dca6dc3c3319506e6593dcb08a9f387ea3b284dbd52a92c40555" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn", +] + +[[package]] +name = "zip" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "760394e246e4c28189f19d488c058bf16f564016aefac5d32bb1f3b51d5e9261" +dependencies = [ + "aes", + "byteorder", + "bzip2", + "constant_time_eq", + "crc32fast", + "crossbeam-utils", + "flate2", + "hmac", + "pbkdf2", + "sha1", + "time", + "zstd", +] + +[[package]] +name = "zip" +version = "7.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c42e33efc22a0650c311c2ef19115ce232583abbe80850bc8b66509ebef02de0" +dependencies = [ + "crc32fast", + "indexmap", + "memchr", + "typed-path", ] [[package]] name = "zmij" -version = "1.0.12" +version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fc5a66a20078bf1251bde995aa2fdcc4b800c70b5d92dd2c62abc5c60f679f8" +checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" [[package]] name = "zstd" -version = "0.13.3" +version = "0.11.2+zstd.1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e91ee311a569c327171651566e07972200e76fcfe2242a4fa446149a3881c08a" +checksum = "20cc960326ece64f010d2d2107537f26dc589a6573a316bd5b1dba685fa5fde4" dependencies = [ "zstd-safe", ] [[package]] name = "zstd-safe" -version = "7.2.4" +version = "5.0.2+zstd.1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f49c4d5f0abb602a93fb8736af2a4f4dd9512e36f7f570d66e65ff867ed3b9d" +checksum = "1d2a5585e04f9eea4b2a3d1eca508c4dee9592a89ef6f450c11719da0726f4db" dependencies = [ + "libc", "zstd-sys", ] @@ -6672,3 +6684,27 @@ dependencies = [ "cc", "pkg-config", ] + +[[package]] +name = "zune-core" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb8a0807f7c01457d0379ba880ba6322660448ddebc890ce29bb64da71fb40f9" + +[[package]] +name = "zune-inflate" +version = "0.2.54" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73ab332fe2f6680068f3582b16a24f90ad7096d5d39b974d1c0aff0125116f02" +dependencies = [ + "simd-adler32", +] + +[[package]] +name = "zune-jpeg" +version = "0.5.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27bc9d5b815bc103f142aa054f561d9187d191692ec7c2d1e2b4737f8dbd7296" +dependencies = [ + "zune-core", +] diff --git a/Cargo.toml b/Cargo.toml index f7f75e3..503d79f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,133 +1,42 @@ [workspace] -members = [".", "crates/migrations", "crates/client"] +resolver = "2" +members = ["crates/wubbie"] +[workspace.package] +version = "0.1.0" +edition = "2024" +rust-version = "1.92" +license = "Apache-2.0" +repository = "https://github.com/wack/wubbie" + +# --- Pinned dependencies (MULTI-1372) --------------------------------------- +# The three pipeline-critical crates are pinned to exact versions (`=`) so a +# clean checkout always resolves the same toolchain of model / tokenizer / +# weight code. Everything else is locked transitively via Cargo.lock. [workspace.dependencies] -tokio = { version = "1.48.0", features = ["full"] } -chrono = { version = "0.4.42", default-features = false, features = ["serde"] } -opentelemetry = "0.31" -sea-orm-migration = { version = "1.1.7", features = [ - "runtime-tokio-rustls", - "sqlx-postgres", +# Burn deep-learning framework. The CPU (`ndarray`) backend is the default and +# is what CI builds; the NVIDIA CUDA backend (CubeCL) is wired behind the +# `cuda` feature on the `wubbie` crate (see crates/wubbie/Cargo.toml). +burn = { version = "=0.21.0", default-features = false } +# HuggingFace tokenizers. Used to train and load the byte-level BPE tokenizer. +tokenizers = { version = "=0.23.1", default-features = false, features = [ + "onig", + "progressbar", ] } -serde = { version = "1.0.228", features = ["derive"] } +# safetensors weight (de)serialization. Trained weights live in a separate HF +# model repo; this crate reads/writes the on-disk format. +safetensors = "=0.8.0" + +anyhow = "1.0" +clap = { version = "4.5", features = ["derive", "env"] } +serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" -tracing = "0.1.43" -uuid = { version = "1.0", features = ["serde"] } +thiserror = "2.0" +tracing = "0.1" +tracing-subscriber = { version = "0.3", features = ["env-filter"] } -# Shared lint policy. Members opt in via `[lints] workspace = true`. Advisory at -# `warn`; the canonical surfaces (`cargo clippy-strict`, the bacon clippy job, CI) -# run `-D warnings`, so any clippy::all violation is blocking there while plain -# `cargo build` stays non-fatal. [workspace.lints.rust] unsafe_code = "deny" [workspace.lints.clippy] all = "warn" - -[package] -name = "__service_name__" -version = "0.1.0" -edition = "2024" -rust-version = "1.92" -readme = "./README.md" -default-run = "__service_name__" - -[lints] -workspace = true - -[dev-dependencies] -cucumber = { version = "0.21", features = ["tracing"] } - -[[test]] -name = "cucumber" -harness = false - -[[bin]] -name = "__service_name__" -path = "src/bin/main.rs" - -[dependencies] -anyhow = "1.0" -async-trait = "0.1.89" -blake3 = "1.5" -bon = "3.8.1" -chrono = { workspace = true, features = ["clock"] } -clap = { version = "4.5.53", features = ["derive", "env"] } -data-encoding = "2.6" -miette = { version = "7.6.0", features = ["fancy"] } -nutype = { version = "0.6.2", features = ["serde", "new_unchecked"] } -pretty_assertions = "1.4.1" -rand = "0.9.2" -salvo = { version = "0.88.0", features = [ - "anyhow", - "cors", - "oapi", - "rustls", - "test", - "otel", -] } -sea-orm = { version = "1.1.19", features = [ - "runtime-tokio-rustls", - "sqlx-postgres", -] } -serde = { workspace = true } -serde_json = { workspace = true } -static_assertions = "1.1.0" -thiserror = "2.0.17" -tokio = { workspace = true } -tracing = { workspace = true, features = ["attributes"] } -tracing-subscriber = { version = "0.3.22", features = [ - "chrono", - "env-filter", - "fmt", - "json", - "local-time", -] } -ulid = "1.1" -uuid = { workspace = true, features = ["v4", "v7"] } -zeroize = "1.8" -validator = { version = "0.18", features = ["derive"] } -derive-getters = "0.5.0" -subtle = "2.6.1" -mvc-helpers = { git = "ssh://git@github.com/wack/mvc-helpers.git", branch = "trunk" } -opentelemetry = { workspace = true } -opentelemetry_sdk = { version = "0.31", features = ["experimental_async_runtime", "rt-tokio"] } -opentelemetry-otlp = { version = "0.31", features = ["tonic", "default", "reqwest-rustls"] } - -[build-dependencies] -vergen-gitcl = "9" - -# Bacon configuration. `cargo make monitor` (or running bacon directly) uses -# `default_job` below. The chain fmt-check -> check -> clippy surfaces the -# first failure that would block CI's `ci-flow`, in the order CI runs them. -# Use `nextest` interactively via the `t` keybinding. -[package.metadata.bacon] -default_job = "fmt-check" -env.CARGO_TERM_COLOR = "always" - -[package.metadata.bacon.jobs.fmt-check] -command = ["cargo", "fmt", "--all", "--", "--check"] -need_stdout = false -on_success = "job:check" - -[package.metadata.bacon.jobs.check] -command = ["cargo", "check", "--all-targets", "--workspace"] -need_stdout = false -on_success = "job:clippy" - -[package.metadata.bacon.jobs.clippy] -command = ["cargo", "clippy-strict"] -need_stdout = false - -[package.metadata.bacon.jobs.nextest] -command = [ - "cargo", - "nextest", - "run", - "--workspace", - "--hide-progress-bar", - "--failure-output", - "final", -] -need_stdout = true -analyzer = "nextest" diff --git a/Dockerfile b/Dockerfile index 86fdd59..5441fe0 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,92 +1,23 @@ -# Build stage -FROM rust:1.92-alpine AS builder +# Multi-stage build for the wubbie CLI (CPU / ndarray backend). +# +# This builds the default (CPU) backend so the image runs anywhere. A CUDA image +# (built with `--features cuda` on an NVIDIA base) is a follow-up; see the +# project README. -# Install build dependencies (no OpenSSL since we use rustls) -# git is required for git-fetch-with-cli (private GitHub dependencies) -RUN apk add --no-cache \ - musl-dev \ - pkgconfig \ - git +FROM rust:1.96-bookworm AS builder +WORKDIR /build -# Add the musl target for static compilation (native architecture) -RUN rustup target add $(uname -m)-unknown-linux-musl +# `tokenizers` pulls in the `onig` regex backend, whose build script needs a C +# toolchain and libclang for bindgen. +RUN apt-get update \ + && apt-get install -y --no-install-recommends clang libclang-dev \ + && rm -rf /var/lib/apt/lists/* -# Set the working directory -WORKDIR /app - -# Build-time provenance for OpenTelemetry resource attributes. Defaults are -# empty so local `docker build` (without --build-arg) falls through to the -# "unknown" branch in build.rs and the image still builds. CI is expected -# to pass real values via `docker/build-push-action`'s `build-args` input. -ARG VCS_REF_HEAD_REVISION="" -ARG VCS_REF_HEAD_NAME="" -ARG VCS_REF_HEAD_TYPE="" -ARG VCS_REPOSITORY_URL_FULL="" -ARG CICD_PIPELINE_NAME="" -ARG CICD_PIPELINE_RUN_URL_FULL="" -ENV VCS_REF_HEAD_REVISION=${VCS_REF_HEAD_REVISION} \ - VCS_REF_HEAD_NAME=${VCS_REF_HEAD_NAME} \ - VCS_REF_HEAD_TYPE=${VCS_REF_HEAD_TYPE} \ - VCS_REPOSITORY_URL_FULL=${VCS_REPOSITORY_URL_FULL} \ - CICD_PIPELINE_NAME=${CICD_PIPELINE_NAME} \ - CICD_PIPELINE_RUN_URL_FULL=${CICD_PIPELINE_RUN_URL_FULL} - -# Copy cargo config early (needed for git-fetch-with-cli setting) -COPY .cargo/config.toml .cargo/config.toml - -# Copy manifests -COPY Cargo.toml Cargo.lock ./ -COPY crates/migrations/Cargo.toml ./crates/migrations/ -COPY crates/client/Cargo.toml ./crates/client/ - -# Create dummy source files to cache dependencies -# Uses BuildKit secret mount for private GitHub dependency authentication. -# The git config is written and cleaned up within the same layer to avoid leaking the token. -RUN --mount=type=secret,id=GITHUB_TOKEN \ - if [ -f /run/secrets/GITHUB_TOKEN ]; then \ - git config --global url."https://x-access-token:$(cat /run/secrets/GITHUB_TOKEN)@github.com/".insteadOf "https://github.com/"; \ - git config --global --add url."https://x-access-token:$(cat /run/secrets/GITHUB_TOKEN)@github.com/".insteadOf "ssh://git@github.com/"; \ - fi && \ - mkdir src && \ - echo "fn main() {}" > src/main.rs && \ - mkdir -p src/bin && \ - echo "fn main() {}" > src/bin/main.rs && \ - mkdir -p crates/migrations/src && \ - echo "use sea_orm_migration::prelude::*; #[derive(DeriveMigrationName)] pub struct Migration; #[async_trait::async_trait] impl MigrationTrait for Migration { async fn up(&self, _: &SchemaManager) -> Result<(), DbErr> { Ok(()) } async fn down(&self, _: &SchemaManager) -> Result<(), DbErr> { Ok(()) } }" > crates/migrations/src/lib.rs && \ - echo "fn main() {}" > crates/migrations/src/main.rs && \ - mkdir -p crates/client/src && \ - echo "fn main() {}" > crates/client/build.rs && \ - echo "" > crates/client/src/lib.rs && \ - cargo build --release --target $(uname -m)-unknown-linux-musl && \ - rm -rf src crates && \ - rm -f /root/.gitconfig - -# Copy actual source code COPY . . +RUN cargo build --release --locked -p wubbie -# Build the application statically -# Touch source files to ensure they rebuild after the dummy -RUN touch src/bin/main.rs crates/migrations/src/lib.rs && \ - cargo build --release --target $(uname -m)-unknown-linux-musl && \ - cp /app/target/$(uname -m)-unknown-linux-musl/release/__SERVICE_NAME__ /app-binary - -# Runtime stage -FROM gcr.io/distroless/static:nonroot - -# Copy the binary from builder -COPY --from=builder /app-binary /__SERVICE_NAME__ - -# Set the working directory -WORKDIR / - -# Production defaults for logging and telemetry -ENV LOG_FORMAT=json -ENV LOG_LEVEL=info -ENV OTEL_DEPLOYMENT_ENVIRONMENT=production - -# Expose the port the server listens on -EXPOSE 8080 - -# Run the binary with the server subcommand by default -ENTRYPOINT ["/__SERVICE_NAME__"] -CMD ["server"] +FROM debian:bookworm-slim AS runtime +RUN useradd --create-home --user-group --uid 10001 wubbie +COPY --from=builder /build/target/release/wubbie /usr/local/bin/wubbie +USER wubbie +ENTRYPOINT ["wubbie"] diff --git a/Makefile.toml b/Makefile.toml index aadb61e..dd126ef 100644 --- a/Makefile.toml +++ b/Makefile.toml @@ -1,267 +1,42 @@ +# cargo-make tasks for local development. These mirror the CI gates in +# .github/workflows/ci.yml so `cargo make ci` reproduces CI locally. [config] default_to_workspace = false [env] -CARGO_MAKE_CLIPPY_ARGS = "-- --no-deps" -CARGO_MAKE_COVERAGE_PROVIDER = "llvm-cov" -CARGO_MAKE_CARGO_BUILD_TEST_FLAGS = "" -# This is the directory where we generate the CLI's reference -# documentation. -CLI_REFERENCE_DIR = "target/debug/" -# This is the name of the file containing the CLI's reference -# documentation. -CLI_REFERENCE_FILE_NAME = "reference.md" -# CORS configuration for local development -# Allows common localhost ports for frontend development -# In production, set CORS_ALLOWED_ORIGINS to your specific domain(s) -CORS_ALLOWED_ORIGINS = "http://localhost:3000,http://localhost:8080,http://127.0.0.1:3000,http://127.0.0.1:8080" -# Credentials disabled by default for security -CORS_ALLOW_CREDENTIALS = "false" - -[env.development] -CARGO_MAKE_EXTEND_WORKSPACE_MAKEFILE = true - -[tasks.dev-test-flow] -dependencies = [ - "pre-build", - "format-flow", - "clippy-flow", - "build", - "post-build", - "pre-docs", - "docs", - "post-docs", - "test-flow", -] - -[tasks.pre-build] -dependencies = ["format-toml-conditioned-flow", "unused-dependencies-flow"] - -[tasks.ci-flow] -dependencies = [ - "pre-ci-flow", - "print-env-flow", - "pre-build", - "check-format-flow", - "clippy-flow", - "build", - "post-build", - "pre-docs", - "docs", - "post-docs", - "test-flow", - "post-ci-flow", -] - -[tasks.generate-openapi] -description = "Generate OpenAPI specification from the server" -category = "Code Generation" -workspace = false -script_runner = "@shell" -script = ''' -cargo build --release -p __service_name__ -${CARGO_MAKE_WORKSPACE_WORKING_DIRECTORY}/target/release/__service_name__ export-openapi > ${CARGO_MAKE_WORKSPACE_WORKING_DIRECTORY}/openapi.json -''' - -[tasks.test] -workspace = true -description = "Run our test suite" -dependencies = ["generate-openapi"] -command = "cargo" -args = [ - "nextest", - "run", - "--locked", - "--no-tests=pass", - "--workspace", - "@@remove-empty(CARGO_MAKE_CARGO_VERBOSE_FLAGS)", - "@@split(CARGO_MAKE_CARGO_BUILD_TEST_FLAGS, )", -] - -[tasks.help] -command = "cargo" -description = "List help text for wack executable" -category = "Development" -args = [ - "run", - "@@remove-empty(CARGO_MAKE_CARGO_VERBOSE_FLAGS)", - "@@split(CARGO_MAKE_CARGO_BUILD_TEST_FLAGS, )", - "--", - "--help", -] - -[tasks.outdated] -workspace = true -description = "List dependencies with newer released versions" -args = ["outdated", "--root-deps-only", "--exit-code", "1"] +CARGO_TERM_COLOR = "always" [tasks.fmt] -workspace = true -alias = "format" +description = "Format the workspace." +command = "cargo" +args = ["fmt", "--all"] [tasks.check-format] -workspace = true - -[tasks.wc] -description = "Calculate the LoC in src." -category = "Development" -command = "tokei" -args = ["."] - -[tasks.gen-cli-reference] -description = "Generate the CLI's reference documentation in Markdown format" -category = "Development" -script_runner = "@shell" -script = ''' - mkdir -p $CLI_REFERENCE_DIR || true - cargo run --bin mkdown-docs --features=markdown > $CLI_REFERENCE_DIR/$CLI_REFERENCE_FILE_NAME -''' - -[tasks.integ] -description = "Run the BDD / cucumber integration suite (spec/**)." -category = "Test" -workspace = false +description = "Check formatting (CI gate)." command = "cargo" -args = ["test", "--test", "cucumber"] +args = ["fmt", "--all", "--", "--check"] -[tasks.bacon] -description = "Watch tests and rerun on file change." -category = "Development" -command = "bacon" -args = [ - "nextest", - "--", - "--workspace", - "@@split(CARGO_MAKE_CARGO_BUILD_TEST_FLAGS, )", -] - -[tasks.migrate] -description = "Run SeaORM migrations" -category = "Development" -command = "sea-orm-cli" -args = ["migrate", "up", "-d", "./crates/migrations"] - -[tasks.migrate-up] -alias = "migrate" - -[tasks.migrate-down] -description = "Revert SeaORM migrations" -category = "Development" -command = "sea-orm-cli" -args = ["migrate", "down", "-d", "./crates/migrations"] - -[tasks.generate-entities] -description = "Generate SeaORM entities from database" -category = "Development" -command = "sea-orm-cli" -args = [ - "generate", - "entity", - "-u", - "postgresql://postgres:postgres@localhost/__SERVICE_NAME__", - "--impl-active-model-behavior=false", - "-o", - "src/models", -] - -[tasks.pg] -description = "Run PostgreSQL in Docker for local development" -category = "Development" -script = [''' -docker run --rm \ - --name '__SERVICE_NAME__-pg' \ - -e POSTGRES_USER=${POSTGRES_USER:-postgres} \ - -e POSTGRES_PASSWORD=${POSTGRES_PASSWORD:-postgres} \ - -e POSTGRES_DB=${POSTGRES_DATABASE:-__SERVICE_NAME__} \ - -p 5432:5432 \ - postgres:18-alpine -'''] - -[tasks.monitor] -description = "Run bacon headless for Claude Code's Monitor tool (no TTY, summary output on each change)." -category = "Development" -command = "bacon" -args = ["--headless", "--summary", "--no-help-line"] - -# Canonical clippy gate. Overrides the cargo-make built-in clippy-flow (which is -# non-blocking) so `cargo make` (ci-flow / dev-test-flow) and the bacon clippy job -# both run the identical `clippy-strict` alias defined in .cargo/config.toml. -[tasks.clippy-flow] -description = "Run clippy over the whole workspace, denying warnings (overrides the cargo-make built-in clippy flow)." -category = "Test" -dependencies = ["install-clippy"] +[tasks.clippy] +description = "Lint the workspace, denying warnings (CI gate)." command = "cargo" -args = ["clippy-strict"] - -[tasks.coverage] -alias = "coverage-llvm-cov" +args = ["clippy", "--all-targets", "--workspace", "--", "-D", "warnings"] -[tasks.coverage-llvm-cov] -description = "Run the test suite under llvm-cov and report coverage." -category = "Test" -workspace = false -dependencies = ["generate-openapi"] +[tasks.build] +description = "Build the workspace." command = "cargo" -args = [ - "llvm-cov", - "nextest", - "--locked", - "--no-tests=pass", - "--workspace", - "@@remove-empty(CARGO_MAKE_CARGO_VERBOSE_FLAGS)", - "@@split(CARGO_MAKE_CARGO_BUILD_TEST_FLAGS, )", -] +args = ["build", "--workspace"] -[tasks.generate-schema] -description = "Generate tern/schema.sql from the post-migration database schema" -category = "Code Generation" -workspace = false -script_runner = "@shell" -# Spins up a throwaway, version-pinned PostgreSQL 18 instance, applies the -# SeaORM migrations against it, then dumps the resulting schema. The output is -# normalized so it is byte-for-byte reproducible: pg_dump emits a random -# \restrict/\unrestrict token and version-specific header comments, both of -# which we strip so the file can be diff-checked in CI. PostgreSQL is pinned to -# 18 (matching the `pg` task image) so the DDL formatting never drifts; pg_dump -# runs inside the container so its client version always matches the server. -# -# NOTE: the matching "generate-schema" CI check that diffs this file is added by -# TPL-015 (schema snapshot). When it lands, keep the normalization here in sync -# with that workflow. -script = ''' -set -e -CONTAINER=__SERVICE_NAME__-schema-pg -DB_PORT=54329 -DATABASE_URL="postgres://postgres:postgres@localhost:${DB_PORT}/__SERVICE_NAME__" -export DATABASE_URL - -cleanup() { docker rm -f "${CONTAINER}" >/dev/null 2>&1 || true; } -trap cleanup EXIT -cleanup - -docker run -d --name "${CONTAINER}" \ - -e POSTGRES_USER=postgres \ - -e POSTGRES_PASSWORD=postgres \ - -e POSTGRES_DB=__SERVICE_NAME__ \ - -p ${DB_PORT}:5432 \ - postgres:18-alpine >/dev/null - -echo "Waiting for PostgreSQL to become ready..." -for i in $(seq 1 30); do - if docker exec "${CONTAINER}" pg_isready -U postgres >/dev/null 2>&1; then - break - fi - sleep 1 -done - -cargo run -p migration -- up +[tasks.test] +description = "Run the test suite." +command = "cargo" +args = ["test", "--workspace"] -mkdir -p ${CARGO_MAKE_WORKSPACE_WORKING_DIRECTORY}/tern -docker exec -e PGPASSWORD=postgres "${CONTAINER}" \ - pg_dump --schema-only --no-owner --no-privileges -U postgres __SERVICE_NAME__ \ - | grep -v -E '^\\(un)?restrict ' \ - | grep -v -E '^-- Dumped (from database|by pg_dump) version ' \ - > ${CARGO_MAKE_WORKSPACE_WORKING_DIRECTORY}/tern/schema.sql +[tasks.run] +description = "Run the wubbie CLI (pass args after --)." +command = "cargo" +args = ["run", "-p", "wubbie", "--", "${@}"] -echo "Wrote ${CARGO_MAKE_WORKSPACE_WORKING_DIRECTORY}/tern/schema.sql" -''' +# Full local CI reproduction: format check -> clippy -> build -> test. +[tasks.ci] +description = "Run the full CI gate locally." +dependencies = ["check-format", "clippy", "build", "test"] diff --git a/OPENTELEMETRY.md b/OPENTELEMETRY.md deleted file mode 100644 index 755eeb0..0000000 --- a/OPENTELEMETRY.md +++ /dev/null @@ -1,83 +0,0 @@ -# OpenTelemetry Integration - -This project includes OpenTelemetry tracing and custom HTTP metrics collection. - -## Features - -### 1. Distributed Tracing - -OpenTelemetry tracing is automatically initialized when the server starts. The tracer is configured to: -- Export traces via OTLP HTTP protocol -- Use trace context propagation for distributed tracing -- Include all HTTP requests in traces via the Salvo `Tracing` middleware - -The tracer is available in request handlers through the depot: -```rust -#[handler] -async fn my_handler(depot: &mut Depot) -> String { - let tracer = depot.obtain::>().unwrap(); - // Use tracer for custom spans -} -``` - -### 2. HTTP Status Code Metrics - -A custom metrics middleware collects HTTP status codes and emits them as histograms every minute. - -**Implementation Details:** -- **RwLock-based synchronization**: Uses a single `HashMap` wrapped in `Arc>` for thread-safe access -- **Concurrent reads**: Multiple requests can read concurrently; writes acquire exclusive lock briefly -- **Delta temporality**: Emits count deltas every 60 seconds, then resets the histogram -- **Automatic background task**: Spawns a tokio task that runs for the lifetime of the application - -**Metrics Output:** -Every minute, the middleware logs: -``` -INFO HTTP Status Code Metrics (delta): {200: 1523, 404: 42, 500: 3} -INFO status_code=200 count=1523 "HTTP status code count" -INFO status_code=404 count=42 "HTTP status code count" -INFO status_code=500 count=3 "HTTP status code count" -``` - -## Configuration - -### OTLP Endpoint - -By default, the OTLP exporter sends traces to `http://localhost:4318` (HTTP). To customize: - -Set the `OTEL_EXPORTER_OTLP_ENDPOINT` environment variable: -```bash -export OTEL_EXPORTER_OTLP_ENDPOINT=http://my-collector:4318 -``` - -### Service Name - -The service name is automatically set from the Cargo package name. You can customize it by modifying `src/utils/telemetry.rs`. - -## Middleware Order - -The middleware is applied in this order (from outermost to innermost): -1. `Logger` - Request logging -2. `affix_state::inject` - Inject tracer into depot -3. `Metrics` - Salvo built-in metrics -4. `Tracing` - OpenTelemetry tracing -5. `metrics_middleware` - Custom HTTP status code collection -6. `transaction_middleware` - Database transaction management -7. `api_key_store_middleware` - API key store injection - -This ensures that all requests are traced and metrics are collected before database transactions begin. - -## Dependencies - -The following OpenTelemetry dependencies are included: -- `opentelemetry` (0.31) -- `opentelemetry_sdk` (0.31) with features: `experimental_async_runtime`, `rt-tokio` -- `opentelemetry-otlp` (0.31) with features: `tonic`, `default` -- `opentelemetry-http` (0.31) - -## Files - -- `src/utils/telemetry.rs` - OpenTelemetry initialization -- `src/middleware/metrics.rs` - HTTP status code metrics middleware -- `src/controllers/mod.rs` - Router setup with tracing middleware -- `src/bin/main.rs` - Tracer initialization in main function diff --git a/README.md b/README.md index a8439a8..9a6817f 100644 --- a/README.md +++ b/README.md @@ -1,141 +1,105 @@ -# __SERVICE_NAME__ +# wubbie -A Wack microservice built from [`rust-service-template`](https://github.com/wack/rust-service-template). +> A fully-open SLM, from corpus to inference. -## Overview +`wubbie` is the all-Rust pipeline repository for a small language model: the +model definition, the training loop, and the inference server all live here. +It is built on an all-Rust stack: -`__SERVICE_NAME__` is a Rust web service using the [Salvo](https://salvo.rs) framework, -[SeaORM](https://www.sea-orm.org) for PostgreSQL persistence, and OpenTelemetry for -observability. It follows a hexagonal (ports-and-adapters) architecture so that business -logic stays free of I/O concerns and integration tests can run against in-memory mocks. +| Concern | Crate | +| ---------- | ------------------------------------------------------ | +| Framework | [`burn`](https://burn.dev/docs/burn/) (CUDA via CubeCL)| +| Tokenizer | [`tokenizers`](https://github.com/huggingface/tokenizers) | +| Weights | [`safetensors`](https://github.com/huggingface/safetensors) | -The crate ships: +Trained weights do **not** live in this repository — they are published to a +separate HuggingFace model repo. This repo holds the code that produces and +serves them. -- An HTTP server exposing the service's REST API plus interactive OpenAPI docs at `/scalar`. -- A code-generated, strongly-typed HTTP client (`__SERVICE_NAME__-client`) derived from - the service's own OpenAPI specification. -- Database migrations managed with SeaORM. +## Layout -## Architecture - -The codebase is organized into hexagonal layers. Requests flow inward through thin -adapters; the domain core has no framework or I/O dependencies. - -| Layer | Directory | Responsibility | -|-------|-----------|----------------| -| Controllers | `src/controllers/` | Thin Salvo HTTP handlers: parse requests, call services, render responses. | -| Services | `src/services/` | Business logic and use cases; coordinate repositories. | -| Repositories | `src/repos/` | Data-access traits (ports) and their SeaORM implementations. | -| Domain | `src/domain/` | Business entities and domain errors. No framework or I/O dependencies. | -| Views | `src/views/` | Serializable HTTP request/response types. | -| Models | `src/models/` | SeaORM entity definitions. | -| Middleware | `src/middleware/` | Salvo middleware (e.g. the JSON error catcher). | - -Supporting crates: - -- `crates/migrations/` — SeaORM migration definitions. -- `crates/client/` — the generated OpenAPI client (built and validated in CI). +``` +. +├── Cargo.toml # virtual workspace + pinned dependencies +├── crates/ +│ └── wubbie/ # the pipeline crate (library + `wubbie` CLI) +│ └── src/ +│ ├── lib.rs +│ ├── main.rs # CLI entry point (train / generate / serve) +│ ├── backend.rs # compile-time backend selection (CPU / CUDA) +│ ├── config.rs # model configuration +│ ├── model.rs # model definition +│ ├── tokenizer.rs# tokenizer loading +│ ├── training.rs # training loop +│ ├── inference.rs# inference entry points +│ └── weights.rs # safetensors (de)serialization +├── Dockerfile # CPU inference image +└── .github/workflows/on-push.yml +``` -All external I/O sits behind async traits, so production code uses real implementations -while tests inject mocks (see `CLAUDE.md` for the full Sans-I/O design notes). +## Dependencies -## Usage +The three pipeline-critical crates are **pinned to exact versions** in the +workspace `[workspace.dependencies]` table, and everything else is locked via +`Cargo.lock`: -The binary is `__service_name__` and exposes three subcommands: +- `burn` `=0.21.0` +- `tokenizers` `=0.23.1` +- `safetensors` `=0.8.0` -```bash -# Run the web server -cargo run -- server +## Backends -# Print the CLI version and exit -cargo run -- version +Burn is generic over its compute backend; wubbie selects one at compile time +via crate features: -# Export the OpenAPI specification to stdout -cargo run -- export-openapi > openapi.json -``` +- **`ndarray`** (default) — a pure-Rust CPU backend that builds everywhere. This + is what CI builds and the default for `cargo build`. +- **`cuda`** — the NVIDIA CUDA backend via CubeCL, for GPU training/inference. + It requires the CUDA toolkit at build time and is therefore not part of the + default build or CI: -Once the server is running, interactive API documentation is available at -`http://127.0.0.1:8080/scalar` (or `https://…` when TLS is configured). - -## Configuration - -Most flags have an environment-variable equivalent (clap `env`). Common `server` options: - -| Flag | Env var | Default | Description | -|------|---------|---------|-------------| -| `--host` | `HOST` | `127.0.0.1` | Bind address. | -| `--port` | `PORT` | `8080` | Bind port. | -| `--pg-host` | `POSTGRES_HOST` | `localhost` | PostgreSQL host. | -| `--postgres-port` | `POSTGRES_PORT` | `5432` | PostgreSQL port. | -| `--database` | `POSTGRES_DATABASE` | `postgres` | Database name. | -| `--username` | `POSTGRES_USER` | _(empty)_ | Database user. | -| `--password` | `POSTGRES_PASSWORD` | _(empty)_ | Database password. | -| `--tls-cert` | `TLS_CERT` | _(none)_ | Path to TLS certificate (requires `--tls-key`). | -| `--tls-key` | `TLS_KEY` | _(none)_ | Path to TLS key (requires `--tls-cert`). | -| `--log-level` | `LOG_LEVEL` | `info` | Tracing level filter. | -| `--log-format` | `LOG_FORMAT` | `text` | `text` or `json` log output. | -| `--deployment-environment` | `OTEL_DEPLOYMENT_ENVIRONMENT` | `local` | OTel resource environment (`development`, `production`, `stable`, `local`). | -| `--otel-exporter-api-key` | `OTEL_EXPORTER_API_KEY` | _(none)_ | OTLP collector API key (`X-API-KEY`). | -| `--service-version` | `SERVICE_VERSION` | crate version | Service version reported to OTel. | - -CORS options are also exposed via `--cors-*` flags. Run `cargo run -- server --help` for -the complete, authoritative list. + ```bash + cargo build --release --features cuda + ``` ## Development -Prerequisites: the toolchain is pinned via `rust-toolchain.toml` (Rust 1.96.0); `rustup` -installs it automatically. Most workflows go through [`cargo-make`](https://github.com/sagiegurari/cargo-make). - ```bash -# Start a local PostgreSQL instance -cargo make pg +cargo build # build (CPU backend) +cargo test # run the test suite +cargo fmt --all # format +cargo clippy --all-targets --workspace -- -D warnings # lint (CI gate) +``` -# Apply database migrations -cargo make migrate +If you have [`cargo-make`](https://github.com/sagiegurari/cargo-make) +installed, `cargo make ci` runs the full CI gate (format check → clippy → +build → test) locally. -# Build the server and write the OpenAPI spec to openapi.json. -# (The __SERVICE_NAME__-client crate is regenerated from openapi.json on the -# next `cargo build` by its build script.) -cargo make generate-openapi +The `wubbie` CLI scaffolds three subcommands; they are wired up but not yet +implemented: -# Watch tests and rerun on change (runs `bacon nextest`) -cargo make bacon +```bash +cargo run -p wubbie -- train +cargo run -p wubbie -- generate +cargo run -p wubbie -- serve +``` -# Or run bare `bacon` for the default fmt-check -> check -> clippy watch chain -bacon +## CI -# Strict clippy — the canonical lint command shared by the bacon clippy job and CI. -# (`clippy-strict` is a cargo alias defined in .cargo/config.toml.) -cargo clippy-strict +Workflows are named after their trigger event: -# Run the test suite -cargo make test +- `.github/workflows/on-push.yml` runs on push (PR branches). +- `.github/workflows/on-merge.yml` runs on the GitHub merge queue + (`merge_group`), if one is enabled. -# Check formatting -cargo make check-format -``` +Both run the same gate: -## Project Structure +1. `cargo fmt --all --check` +2. `cargo clippy --all-targets --workspace --locked -- -D warnings` +3. `cargo build --workspace --locked` +4. `cargo test --workspace --locked` -``` -. -├── src/ -│ ├── bin/main.rs # Binary entry point -│ ├── lib.rs # Library root (shared by binary and tests) -│ ├── cli/ # clap subcommands (server, version, export-openapi) -│ ├── controllers/ # HTTP handlers (thin adapters) -│ ├── services/ # Business logic layer -│ ├── repos/ # Repository ports + SeaORM implementations -│ ├── domain/ # Business entities and domain errors -│ ├── views/ # HTTP request/response types -│ ├── models/ # SeaORM entities -│ ├── middleware/ # Salvo middleware -│ └── utils/ # Database, telemetry, and shared helpers -├── crates/ -│ ├── migrations/ # SeaORM migrations -│ └── client/ # Generated OpenAPI client (__SERVICE_NAME__-client) -├── helm/chart/ # Helm deployment chart -├── Makefile.toml # cargo-make task definitions -├── rust-toolchain.toml # Pinned Rust toolchain -└── Cargo.toml # Workspace manifest -``` +A separate `cuda-build` job compile-checks the CUDA backend +(`cargo build --no-default-features --features cuda`). `cudarc` uses dynamic +loading, so this builds with no GPU, driver, or CUDA toolkit present — it only +validates that the `cuda`-gated code compiles; running it needs a GPU host. diff --git a/TEMPLATE.md b/TEMPLATE.md deleted file mode 100644 index 75c777c..0000000 --- a/TEMPLATE.md +++ /dev/null @@ -1,189 +0,0 @@ -# Service Template - -This is a production-ready Rust microservice template built with the Salvo web framework, SeaORM, and PostgreSQL. It follows hexagonal architecture principles and includes everything needed to build, test, and deploy a microservice. - -## Quick Start - -### 1. Initialize Your Service - -Run the initialization script to replace placeholders with your service name: - -```bash -./scripts/init-service.sh my-service -``` - -Or run interactively: - -```bash -./scripts/init-service.sh -``` - -The script will: -- Replace `__SERVICE_NAME__` with your service name (e.g., `my-service`) -- Replace `__service_name__` with the Rust crate name (e.g., `my_service`) -- Update all configuration files, Helm charts, and source code - -### 2. Start Development Database - -```bash -cargo make pg -``` - -### 3. Run Migrations - -```bash -cargo make migrate -``` - -### 4. Build and Run - -```bash -cargo run -- server -``` - -The server will start at `http://127.0.0.1:8080` with OpenAPI docs at `/scalar`. - -## What's Included - -### Project Structure - -``` -├── src/ -│ ├── bin/main.rs # Application entry point -│ ├── lib.rs # Library exports -│ ├── cli/ # CLI configuration (clap) -│ ├── controllers/ # HTTP handlers (thin adapters) -│ ├── services/ # Business logic layer -│ ├── repos/ # Repository abstractions -│ ├── domain/ # Domain entities and logic -│ ├── views/ # HTTP request/response types -│ ├── models/ # SeaORM entities -│ ├── middleware/ # Salvo middleware -│ ├── db/ # Database connection pool -│ └── utils/ # Utilities (telemetry, etc.) -├── crates/ -│ ├── migrations/ # SeaORM database migrations -│ └── client/ # Generated API client (optional) -├── helm/ -│ └── chart/ # Kubernetes Helm chart -├── .github/workflows/ # CI/CD pipelines -├── Dockerfile # Multi-stage Docker build -└── Makefile.toml # Development tasks -``` - -### Architecture - -This template follows **hexagonal architecture** (ports and adapters): - -1. **Domain Layer** (`src/domain/`) - Business entities with no external dependencies -2. **Service Layer** (`src/services/`) - Business logic and use cases -3. **Repository Layer** (`src/repos/`) - Data access abstraction -4. **View Layer** (`src/views/`) - HTTP request/response types -5. **Controller Layer** (`src/controllers/`) - Thin HTTP adapters - -### Features - -- **Web Framework**: Salvo with OpenAPI/Swagger support -- **Database**: PostgreSQL with SeaORM async ORM -- **Observability**: OpenTelemetry tracing, structured logging -- **Security**: TLS support, non-root containers, security contexts -- **Deployment**: Docker, Helm charts, GitHub Actions CI/CD -- **Developer Experience**: cargo-make tasks, hot reload ready - -### Available Commands - -| Command | Description | -|---------|-------------| -| `cargo make pg` | Start PostgreSQL in Docker | -| `cargo make migrate` | Run database migrations | -| `cargo make migrate-down` | Rollback migrations | -| `cargo make generate-entities` | Generate SeaORM entities from DB | -| `cargo make generate-openapi` | Export OpenAPI spec | -| `cargo make test` | Run test suite | -| `cargo make ci-flow` | Run full CI pipeline | -| `cargo make bacon` | Watch mode testing | - -### CLI Commands - -```bash -# Run the server -cargo run -- server - -# Print version -cargo run -- version - -# Export OpenAPI spec -cargo run -- export-openapi > openapi.json -``` - -## Customization Guide - -### Adding a New Entity - -1. **Create migration** in `crates/migrations/src/` -2. **Run migration**: `cargo make migrate` -3. **Generate entities**: `cargo make generate-entities` -4. **Create domain types** in `src/domain/` -5. **Create repository trait** in `src/repos/` -6. **Implement service** in `src/services/` -7. **Create views** in `src/views/` -8. **Add controller** in `src/controllers/` -9. **Register routes** in `src/controllers/mod.rs` - -### Environment Variables - -| Variable | Description | Default | -|----------|-------------|---------| -| `HOST` | Server host | `127.0.0.1` | -| `PORT` | Server port | `8080` | -| `DATABASE_URL` | Full PostgreSQL URL | - | -| `POSTGRES_HOST` | Database host | - | -| `POSTGRES_PORT` | Database port | `5432` | -| `POSTGRES_USER` | Database user | - | -| `POSTGRES_PASSWORD` | Database password | - | -| `POSTGRES_DATABASE` | Database name | - | -| `LOG_LEVEL` | Log level | `info` | -| `LOG_FORMAT` | `text` or `json` | `text` | -| `TLS_CERT` | TLS certificate path | - | -| `TLS_KEY` | TLS key path | - | -| `CORS_ALLOWED_ORIGINS` | Comma-separated origins | - | - -### Helm Deployment - -```bash -# Install -helm install my-service helm/chart \ - --set database.host=postgres.example.com \ - --set database.user=myuser \ - --set database.password=mypassword \ - --set database.name=mydb - -# Upgrade -helm upgrade my-service helm/chart -f values-prod.yaml -``` - -## CI/CD Pipeline - -The GitHub Actions workflows provide: - -1. **on-push.yml** - Format check on feature branches -2. **on-merge.yml** - Full validation on merge queue: - - Rust formatting and linting - - Build and test with nextest - - Docker image build and push to GHCR - - Helm chart validation and publish - -Images are tagged with the commit SHA and pushed to: -- `ghcr.io//:` - -## Removing Template Files - -After initialization, you can remove template-specific files: -- `TEMPLATE.md` (this file) -- `scripts/init-service.sh` - -The initialization script offers to remove these automatically. - -## License - -This template is provided under the MIT License. diff --git a/build.rs b/build.rs deleted file mode 100644 index 4b83358..0000000 --- a/build.rs +++ /dev/null @@ -1,103 +0,0 @@ -// Build-time provenance for OpenTelemetry resource attributes. -// -// Emits the canonical VCS_* and CICD_* compile-time env vars consumed by -// `src/utils/telemetry.rs` to populate OTel resource attributes following -// the CI/CD + VCS semantic conventions: -// https://opentelemetry.io/docs/specs/semconv/resource/cicd/ -// https://opentelemetry.io/docs/specs/semconv/attributes-registry/vcs/ -// -// Resolution priority for each value: -// 1. Explicit env var (set by Docker ARG -> ENV from CI), e.g. VCS_REF_HEAD_REVISION. -// 2. Local git shell-out (works for `cargo build` outside Docker). -// 3. "unknown" + cargo:warning so misconfigured builds are visible. - -use std::env; -use std::process::Command; - -const ATTRS: &[&str] = &[ - "VCS_REF_HEAD_REVISION", - "VCS_REF_HEAD_NAME", - "VCS_REF_HEAD_TYPE", - "VCS_REPOSITORY_URL_FULL", - "CICD_PIPELINE_NAME", - "CICD_PIPELINE_RUN_URL_FULL", -]; - -fn main() { - // Best-effort: emit VERGEN_GIT_* and other vergen env vars for future use. - // Failure (e.g. no .git in a Docker builder) is non-fatal because the - // canonical VCS_* vars below have their own resolution chain. - let _ = run_vergen(); - - resolve("VCS_REF_HEAD_REVISION", || git(&["rev-parse", "HEAD"])); - resolve("VCS_REF_HEAD_NAME", || { - git(&["rev-parse", "--abbrev-ref", "HEAD"]) - }); - resolve("VCS_REF_HEAD_TYPE", || Some("branch".to_string())); - resolve("VCS_REPOSITORY_URL_FULL", || { - git(&["config", "--get", "remote.origin.url"]).map(normalize_repo_url) - }); - resolve("CICD_PIPELINE_NAME", || None); - resolve("CICD_PIPELINE_RUN_URL_FULL", || None); - - for name in ATTRS { - println!("cargo:rerun-if-env-changed={name}"); - } - // Re-run when CI toggles so the warning appears/disappears accordingly. - println!("cargo:rerun-if-env-changed=CI"); -} - -fn run_vergen() -> Result<(), Box> { - let gitcl = vergen_gitcl::GitclBuilder::all_git()?; - vergen_gitcl::Emitter::default() - .add_instructions(&gitcl)? - .emit()?; - Ok(()) -} - -fn resolve(name: &str, fallback: impl FnOnce() -> Option) { - if let Ok(value) = env::var(name) - && !value.is_empty() - { - println!("cargo:rustc-env={name}={value}"); - return; - } - if let Some(value) = fallback() - && !value.is_empty() - { - println!("cargo:rustc-env={name}={value}"); - return; - } - // Only nag in CI; a missing provenance var is normal for local dev builds. - if env::var_os("CI").is_some() { - println!("cargo:warning=No build-time value for {name}; stamping \"unknown\""); - } - println!("cargo:rustc-env={name}=unknown"); -} - -fn git(args: &[&str]) -> Option { - let output = Command::new("git").args(args).output().ok()?; - if !output.status.success() { - return None; - } - let value = String::from_utf8(output.stdout).ok()?.trim().to_string(); - (!value.is_empty()).then_some(value) -} - -// git remote URLs come in several forms: -// https://github.com/wack/aviary.git -// git@github.com:wack/aviary.git -// ssh://git@github.com/wack/aviary.git -// Normalize to the canonical `https://github.com//` form so the -// resource attribute matches what `${{ github.server_url }}/${{ github.repository }}` -// produces in CI. -fn normalize_repo_url(raw: String) -> String { - let trimmed = raw.trim().trim_end_matches(".git"); - if let Some(rest) = trimmed.strip_prefix("git@github.com:") { - return format!("https://github.com/{rest}"); - } - if let Some(rest) = trimmed.strip_prefix("ssh://git@github.com/") { - return format!("https://github.com/{rest}"); - } - trimmed.to_string() -} diff --git a/crates/client/Cargo.toml b/crates/client/Cargo.toml deleted file mode 100644 index 838a36f..0000000 --- a/crates/client/Cargo.toml +++ /dev/null @@ -1,24 +0,0 @@ -[package] -name = "__SERVICE_NAME__-client" -version = "0.1.0" -edition = "2024" -rust-version = "1.92" -description = "HTTP client for the __SERVICE_NAME__ API, generated from OpenAPI specification" - -[dependencies] -chrono = { version = "0.4", default-features = false, features = ["serde"] } -progenitor-client = "0.11" -reqwest = { version = "0.12", default-features = false, features = ["json", "rustls-tls"] } -serde = { version = "1.0", features = ["derive"] } -serde_json = "1.0" -uuid = { version = "1.0", features = ["serde"] } - -[build-dependencies] -openapiv3 = "2.0" -progenitor = "0.11" -prettyplease = "0.2" -serde_json = "1.0" -syn = "2.0" - -[lints] -workspace = true diff --git a/crates/client/Makefile.toml b/crates/client/Makefile.toml deleted file mode 100644 index 765c3fd..0000000 --- a/crates/client/Makefile.toml +++ /dev/null @@ -1,64 +0,0 @@ -# Makefile.toml for __SERVICE_NAME__-client crate -# This file extends the workspace Makefile.toml - -[config] -default_to_workspace = false - -[env] -CARGO_MAKE_EXTEND_WORKSPACE_MAKEFILE = true - -[tasks.generate-openapi] -description = "Generate OpenAPI specification from the server" -category = "Code Generation" -workspace = false -script_runner = "@shell" -script = ''' -echo "Building server..." -cargo build --release -p __service_name__ -echo "Exporting OpenAPI specification..." -${CARGO_MAKE_WORKSPACE_WORKING_DIRECTORY}/target/release/__service_name__ export-openapi > ${CARGO_MAKE_WORKSPACE_WORKING_DIRECTORY}/openapi.json -echo "OpenAPI specification generated at ${CARGO_MAKE_WORKSPACE_WORKING_DIRECTORY}/openapi.json" -''' - -[tasks.pre-build] -description = "Ensure OpenAPI spec exists before building client" -category = "Build" -script_runner = "@shell" -script = ''' -if [ ! -f "${CARGO_MAKE_WORKSPACE_WORKING_DIRECTORY}/openapi.json" ]; then - echo "OpenAPI specification not found. Generating..." - cargo build --release -p __service_name__ - ${CARGO_MAKE_WORKSPACE_WORKING_DIRECTORY}/target/release/__service_name__ export-openapi > ${CARGO_MAKE_WORKSPACE_WORKING_DIRECTORY}/openapi.json -fi -''' - -[tasks.build] -description = "Build the __SERVICE_NAME__-client crate" -category = "Build" -dependencies = ["pre-build"] -command = "cargo" -args = ["build", "-p", "__SERVICE_NAME__-client"] - -[tasks.check] -description = "Check the __SERVICE_NAME__-client crate" -category = "Build" -command = "cargo" -args = ["check", "-p", "__SERVICE_NAME__-client"] - -[tasks.fmt] -description = "Format the __SERVICE_NAME__-client crate" -category = "Development" -command = "cargo" -args = ["fmt", "-p", "__SERVICE_NAME__-client"] - -[tasks.check-format] -description = "Check formatting of the __SERVICE_NAME__-client crate" -category = "Development" -command = "cargo" -args = ["fmt", "-p", "__SERVICE_NAME__-client", "--", "--check"] - -[tasks.clippy] -description = "Run clippy on the __SERVICE_NAME__-client crate" -category = "Development" -command = "cargo" -args = ["clippy", "-p", "__SERVICE_NAME__-client", "--", "-D", "warnings"] diff --git a/crates/client/build.rs b/crates/client/build.rs deleted file mode 100644 index 7655dc2..0000000 --- a/crates/client/build.rs +++ /dev/null @@ -1,114 +0,0 @@ -use std::env; -use std::fs; -use std::path::PathBuf; - -fn main() { - // Build scripts run with the crate directory as CWD, so reach two levels up - // (crates/-client -> workspace root) for the generated spec, which - // `cargo make generate-openapi`, CI, and `export-openapi` all write to the root. - let openapi_path = "../../openapi.json"; - - // Tell Cargo to rerun this build script if the OpenAPI spec changes - println!("cargo:rerun-if-changed={}", openapi_path); - - // Read the OpenAPI specification - let spec_content = fs::read_to_string(openapi_path).unwrap_or_else(|e| { - panic!( - "Failed to read OpenAPI spec at '{}': {}. \ - Make sure to run 'cargo make generate-openapi' first.", - openapi_path, e - ) - }); - - // Parse as JSON Value to transform the spec - let mut spec: serde_json::Value = - serde_json::from_str(&spec_content).expect("Failed to parse OpenAPI spec as JSON"); - - // Convert OpenAPI 3.1.0 to 3.0.3 for progenitor compatibility - // Progenitor uses openapiv3 which only supports OpenAPI 3.0.x - if spec - .get("openapi") - .and_then(|v| v.as_str()) - .is_some_and(|version| version.starts_with("3.1")) - { - spec["openapi"] = serde_json::json!("3.0.3"); - - // Convert JSON Schema 2020-12 constructs to OpenAPI 3.0 compatible ones - transform_schemas_recursive(&mut spec); - } - - // Parse as OpenAPI struct - let spec: openapiv3::OpenAPI = - serde_json::from_value(spec).expect("Failed to parse transformed OpenAPI spec"); - - // Configure the generator - let mut settings = progenitor::GenerationSettings::new(); - settings.with_interface(progenitor::InterfaceStyle::Builder); - settings.with_tag(progenitor::TagStyle::Merged); - - // Generate the client code - let mut generator = progenitor::Generator::new(&settings); - - let tokens = generator - .generate_tokens(&spec) - .expect("Failed to generate client code from OpenAPI spec"); - - // Parse and format the generated code - let ast = syn::parse2(tokens).expect("Failed to parse generated code"); - let content = prettyplease::unparse(&ast); - - // Write to OUT_DIR - let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap()); - let dest_path = out_dir.join("codegen.rs"); - fs::write(&dest_path, content).expect("Failed to write generated code"); -} - -/// Recursively transform schemas from OpenAPI 3.1.0/JSON Schema 2020-12 to 3.0.3 compatible format -fn transform_schemas_recursive(value: &mut serde_json::Value) { - match value { - serde_json::Value::Object(map) => { - // Transform 'type' arrays to use 'nullable' (3.1.0 -> 3.0.x conversion) - // e.g., {"type": ["string", "null"]} -> {"type": "string", "nullable": true} - if let Some(type_val) = map.get("type").cloned() - && let Some(types) = type_val.as_array() - { - let non_null_types: Vec<&serde_json::Value> = types - .iter() - .filter(|t| t.as_str() != Some("null")) - .collect(); - let has_null = types.iter().any(|t| t.as_str() == Some("null")); - - if non_null_types.len() == 1 { - map.insert("type".to_string(), non_null_types[0].clone()); - if has_null { - map.insert("nullable".to_string(), serde_json::json!(true)); - } - } - } - - // Convert 'const' to 'enum' with single value (3.1.0 feature) - if let Some(const_val) = map.remove("const") { - map.insert("enum".to_string(), serde_json::json!([const_val])); - } - - // Convert 'examples' array to single 'example' (3.1.0 -> 3.0.x) - if let Some(examples) = map.remove("examples") - && let Some(arr) = examples.as_array() - && let Some(first) = arr.first() - { - map.insert("example".to_string(), first.clone()); - } - - // Recursively process all nested values - for (_, v) in map.iter_mut() { - transform_schemas_recursive(v); - } - } - serde_json::Value::Array(arr) => { - for item in arr.iter_mut() { - transform_schemas_recursive(item); - } - } - _ => {} - } -} diff --git a/crates/client/src/lib.rs b/crates/client/src/lib.rs deleted file mode 100644 index 2cba0e1..0000000 --- a/crates/client/src/lib.rs +++ /dev/null @@ -1,21 +0,0 @@ -//! HTTP client for the API. -//! -//! This crate provides a type-safe HTTP client generated from the API's -//! OpenAPI specification using [progenitor](https://github.com/oxidecomputer/progenitor). -//! -//! # Example -//! -//! ```no_run -//! use __service_name___client::Client; -//! -//! # async fn example() -> Result<(), Box> { -//! let client = Client::new("http://localhost:8080"); -//! -//! // Use the generated methods to interact with the API -//! let response = client.heartbeat().send().await?; -//! # Ok(()) -//! # } -//! ``` - -// Include the generated client code from the build script -include!(concat!(env!("OUT_DIR"), "/codegen.rs")); diff --git a/crates/migrations/Cargo.lock b/crates/migrations/Cargo.lock deleted file mode 100644 index bc64ff9..0000000 --- a/crates/migrations/Cargo.lock +++ /dev/null @@ -1,2640 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 4 - -[[package]] -name = "aho-corasick" -version = "1.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" -dependencies = [ - "memchr", -] - -[[package]] -name = "aliasable" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "250f629c0161ad8107cf89319e990051fae62832fd343083bea452d93e2205fd" - -[[package]] -name = "allocator-api2" -version = "0.2.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" - -[[package]] -name = "android_system_properties" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" -dependencies = [ - "libc", -] - -[[package]] -name = "anstream" -version = "0.6.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43d5b281e737544384e969a5ccad3f1cdd24b48086a0fc1b2a5262a26b8f4f4a" -dependencies = [ - "anstyle", - "anstyle-parse", - "anstyle-query", - "anstyle-wincon", - "colorchoice", - "is_terminal_polyfill", - "utf8parse", -] - -[[package]] -name = "anstyle" -version = "1.0.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78" - -[[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-query" -version = "1.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc" -dependencies = [ - "windows-sys 0.61.2", -] - -[[package]] -name = "anstyle-wincon" -version = "3.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d" -dependencies = [ - "anstyle", - "once_cell_polyfill", - "windows-sys 0.61.2", -] - -[[package]] -name = "async-attributes" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3203e79f4dd9bdda415ed03cf14dae5a2bf775c683a00f94e9cd1faf0f596e5" -dependencies = [ - "quote", - "syn 1.0.109", -] - -[[package]] -name = "async-channel" -version = "1.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81953c529336010edd6d8e358f886d9581267795c61b19475b71314bffa46d35" -dependencies = [ - "concurrent-queue", - "event-listener 2.5.3", - "futures-core", -] - -[[package]] -name = "async-channel" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "924ed96dd52d1b75e9c1a3e6275715fd320f5f9439fb5a4a11fa51f4221158d2" -dependencies = [ - "concurrent-queue", - "event-listener-strategy", - "futures-core", - "pin-project-lite", -] - -[[package]] -name = "async-executor" -version = "1.13.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "497c00e0fd83a72a79a39fcbd8e3e2f055d6f6c7e025f3b3d91f4f8e76527fb8" -dependencies = [ - "async-task", - "concurrent-queue", - "fastrand", - "futures-lite", - "pin-project-lite", - "slab", -] - -[[package]] -name = "async-global-executor" -version = "2.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05b1b633a2115cd122d73b955eadd9916c18c8f510ec9cd1686404c60ad1c29c" -dependencies = [ - "async-channel 2.5.0", - "async-executor", - "async-io", - "async-lock", - "blocking", - "futures-lite", - "once_cell", - "tokio", -] - -[[package]] -name = "async-io" -version = "2.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "456b8a8feb6f42d237746d4b3e9a178494627745c3c56c6ea55d92ba50d026fc" -dependencies = [ - "autocfg", - "cfg-if", - "concurrent-queue", - "futures-io", - "futures-lite", - "parking", - "polling", - "rustix", - "slab", - "windows-sys 0.61.2", -] - -[[package]] -name = "async-lock" -version = "3.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "290f7f2596bd5b78a9fec8088ccd89180d7f9f55b94b0576823bbbdc72ee8311" -dependencies = [ - "event-listener 5.4.1", - "event-listener-strategy", - "pin-project-lite", -] - -[[package]] -name = "async-std" -version = "1.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c8e079a4ab67ae52b7403632e4618815d6db36d2a010cfe41b02c1b1578f93b" -dependencies = [ - "async-attributes", - "async-channel 1.9.0", - "async-global-executor", - "async-io", - "async-lock", - "crossbeam-utils", - "futures-channel", - "futures-core", - "futures-io", - "futures-lite", - "gloo-timers", - "kv-log-macro", - "log", - "memchr", - "once_cell", - "pin-project-lite", - "pin-utils", - "slab", - "wasm-bindgen-futures", -] - -[[package]] -name = "async-stream" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b5a71a6f37880a80d1d7f19efd781e4b5de42c88f0722cc13bcb6cc2cfe8476" -dependencies = [ - "async-stream-impl", - "futures-core", - "pin-project-lite", -] - -[[package]] -name = "async-stream-impl" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.114", -] - -[[package]] -name = "async-task" -version = "4.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de" - -[[package]] -name = "async-trait" -version = "0.1.89" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.114", -] - -[[package]] -name = "atoi" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f28d99ec8bfea296261ca1af174f24225171fea9664ba9003cbebee704810528" -dependencies = [ - "num-traits", -] - -[[package]] -name = "atomic-waker" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" - -[[package]] -name = "autocfg" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" - -[[package]] -name = "base64" -version = "0.22.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" - -[[package]] -name = "bitflags" -version = "2.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" - -[[package]] -name = "block-buffer" -version = "0.10.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" -dependencies = [ - "generic-array", -] - -[[package]] -name = "blocking" -version = "1.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e83f8d02be6967315521be875afa792a316e28d57b5a2d401897e2a7921b7f21" -dependencies = [ - "async-channel 2.5.0", - "async-task", - "futures-io", - "futures-lite", - "piper", -] - -[[package]] -name = "bumpalo" -version = "3.19.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dd9dc738b7a8311c7ade152424974d8115f2cdad61e8dab8dac9f2362298510" - -[[package]] -name = "byteorder" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" - -[[package]] -name = "bytes" -version = "1.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b35204fbdc0b3f4446b89fc1ac2cf84a8a68971995d0bf2e925ec7cd960f9cb3" - -[[package]] -name = "cc" -version = "1.2.51" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a0aeaff4ff1a90589618835a598e545176939b97874f7abc7851caa0618f203" -dependencies = [ - "find-msvc-tools", - "shlex", -] - -[[package]] -name = "cfg-if" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" - -[[package]] -name = "chrono" -version = "0.4.42" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "145052bdd345b87320e369255277e3fb5152762ad123a901ef5c262dd38fe8d2" -dependencies = [ - "iana-time-zone", - "num-traits", - "windows-link", -] - -[[package]] -name = "clap" -version = "4.5.54" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6e6ff9dcd79cff5cd969a17a545d79e84ab086e444102a591e288a8aa3ce394" -dependencies = [ - "clap_builder", - "clap_derive", -] - -[[package]] -name = "clap_builder" -version = "4.5.54" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa42cf4d2b7a41bc8f663a7cab4031ebafa1bf3875705bfaf8466dc60ab52c00" -dependencies = [ - "anstream", - "anstyle", - "clap_lex", - "strsim", -] - -[[package]] -name = "clap_derive" -version = "4.5.49" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a0b5487afeab2deb2ff4e03a807ad1a03ac532ff5a2cee5d86884440c7f7671" -dependencies = [ - "heck 0.5.0", - "proc-macro2", - "quote", - "syn 2.0.114", -] - -[[package]] -name = "clap_lex" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1d728cc89cf3aee9ff92b05e62b19ee65a02b5702cff7d5a377e32c6ae29d8d" - -[[package]] -name = "colorchoice" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" - -[[package]] -name = "concurrent-queue" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" -dependencies = [ - "crossbeam-utils", -] - -[[package]] -name = "core-foundation-sys" -version = "0.8.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" - -[[package]] -name = "cpufeatures" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" -dependencies = [ - "libc", -] - -[[package]] -name = "crc" -version = "3.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5eb8a2a1cd12ab0d987a5d5e825195d372001a4094a0376319d5a0ad71c1ba0d" -dependencies = [ - "crc-catalog", -] - -[[package]] -name = "crc-catalog" -version = "2.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" - -[[package]] -name = "crossbeam-queue" -version = "0.3.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f58bbc28f91df819d0aa2a2c00cd19754769c2fad90579b3592b1c9ba7a3115" -dependencies = [ - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-utils" -version = "0.8.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" - -[[package]] -name = "crypto-common" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" -dependencies = [ - "generic-array", - "typenum", -] - -[[package]] -name = "darling" -version = "0.20.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee" -dependencies = [ - "darling_core", - "darling_macro", -] - -[[package]] -name = "darling_core" -version = "0.20.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d00b9596d185e565c2207a0b01f8bd1a135483d02d9b7b0a54b11da8d53412e" -dependencies = [ - "fnv", - "ident_case", - "proc-macro2", - "quote", - "syn 2.0.114", -] - -[[package]] -name = "darling_macro" -version = "0.20.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" -dependencies = [ - "darling_core", - "quote", - "syn 2.0.114", -] - -[[package]] -name = "derive_more" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d751e9e49156b02b44f9c1815bcb94b984cdcc4396ecc32521c739452808b134" -dependencies = [ - "derive_more-impl", -] - -[[package]] -name = "derive_more-impl" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "799a97264921d8623a957f6c3b9011f3b5492f557bbb7a5a19b7fa6d06ba8dcb" -dependencies = [ - "proc-macro2", - "quote", - "rustc_version", - "syn 2.0.114", - "unicode-xid", -] - -[[package]] -name = "digest" -version = "0.10.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" -dependencies = [ - "block-buffer", - "crypto-common", - "subtle", -] - -[[package]] -name = "displaydoc" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.114", -] - -[[package]] -name = "dotenvy" -version = "0.15.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" - -[[package]] -name = "either" -version = "1.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" -dependencies = [ - "serde", -] - -[[package]] -name = "equivalent" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" - -[[package]] -name = "errno" -version = "0.3.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" -dependencies = [ - "libc", - "windows-sys 0.61.2", -] - -[[package]] -name = "etcetera" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "136d1b5283a1ab77bd9257427ffd09d8667ced0570b6f938942bc7568ed5b943" -dependencies = [ - "cfg-if", - "home", - "windows-sys 0.48.0", -] - -[[package]] -name = "event-listener" -version = "2.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" - -[[package]] -name = "event-listener" -version = "5.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e13b66accf52311f30a0db42147dadea9850cb48cd070028831ae5f5d4b856ab" -dependencies = [ - "concurrent-queue", - "parking", - "pin-project-lite", -] - -[[package]] -name = "event-listener-strategy" -version = "0.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8be9f3dfaaffdae2972880079a491a1a8bb7cbed0b8dd7a347f668b4150a3b93" -dependencies = [ - "event-listener 5.4.1", - "pin-project-lite", -] - -[[package]] -name = "fastrand" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" - -[[package]] -name = "find-msvc-tools" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "645cbb3a84e60b7531617d5ae4e57f7e27308f6445f5abf653209ea76dec8dff" - -[[package]] -name = "fnv" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" - -[[package]] -name = "foldhash" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" - -[[package]] -name = "form_urlencoded" -version = "1.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" -dependencies = [ - "percent-encoding", -] - -[[package]] -name = "futures" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" -dependencies = [ - "futures-channel", - "futures-core", - "futures-io", - "futures-sink", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-channel" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" -dependencies = [ - "futures-core", - "futures-sink", -] - -[[package]] -name = "futures-core" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" - -[[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.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" - -[[package]] -name = "futures-lite" -version = "2.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f78e10609fe0e0b3f4157ffab1876319b5b0db102a2c60dc4626306dc46b44ad" -dependencies = [ - "fastrand", - "futures-core", - "futures-io", - "parking", - "pin-project-lite", -] - -[[package]] -name = "futures-sink" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" - -[[package]] -name = "futures-task" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" - -[[package]] -name = "futures-util" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" -dependencies = [ - "futures-core", - "futures-io", - "futures-sink", - "futures-task", - "memchr", - "pin-project-lite", - "pin-utils", - "slab", -] - -[[package]] -name = "generic-array" -version = "0.14.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" -dependencies = [ - "typenum", - "version_check", -] - -[[package]] -name = "getrandom" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" -dependencies = [ - "cfg-if", - "libc", - "wasi", -] - -[[package]] -name = "glob" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" - -[[package]] -name = "gloo-timers" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbb143cf96099802033e0d4f4963b19fd2e0b728bcf076cd9cf7f6634f092994" -dependencies = [ - "futures-channel", - "futures-core", - "js-sys", - "wasm-bindgen", -] - -[[package]] -name = "hashbrown" -version = "0.15.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" -dependencies = [ - "allocator-api2", - "equivalent", - "foldhash", -] - -[[package]] -name = "hashbrown" -version = "0.16.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" - -[[package]] -name = "hashlink" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7382cf6263419f2d8df38c55d7da83da5c18aef87fc7a7fc1fb1e344edfe14c1" -dependencies = [ - "hashbrown 0.15.5", -] - -[[package]] -name = "heck" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" - -[[package]] -name = "heck" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" - -[[package]] -name = "hermit-abi" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" - -[[package]] -name = "hex" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" - -[[package]] -name = "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" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" -dependencies = [ - "digest", -] - -[[package]] -name = "home" -version = "0.5.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc627f471c528ff0c4a49e1d5e60450c8f6461dd6d10ba9dcd3a61d3dff7728d" -dependencies = [ - "windows-sys 0.61.2", -] - -[[package]] -name = "iana-time-zone" -version = "0.1.64" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33e57f83510bb73707521ebaffa789ec8caf86f9657cad665b092b581d40e9fb" -dependencies = [ - "android_system_properties", - "core-foundation-sys", - "iana-time-zone-haiku", - "js-sys", - "log", - "wasm-bindgen", - "windows-core", -] - -[[package]] -name = "iana-time-zone-haiku" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" -dependencies = [ - "cc", -] - -[[package]] -name = "icu_collections" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43" -dependencies = [ - "displaydoc", - "potential_utf", - "yoke", - "zerofrom", - "zerovec", -] - -[[package]] -name = "icu_locale_core" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6" -dependencies = [ - "displaydoc", - "litemap", - "tinystr", - "writeable", - "zerovec", -] - -[[package]] -name = "icu_normalizer" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599" -dependencies = [ - "icu_collections", - "icu_normalizer_data", - "icu_properties", - "icu_provider", - "smallvec", - "zerovec", -] - -[[package]] -name = "icu_normalizer_data" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a" - -[[package]] -name = "icu_properties" -version = "2.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "020bfc02fe870ec3a66d93e677ccca0562506e5872c650f893269e08615d74ec" -dependencies = [ - "icu_collections", - "icu_locale_core", - "icu_properties_data", - "icu_provider", - "zerotrie", - "zerovec", -] - -[[package]] -name = "icu_properties_data" -version = "2.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "616c294cf8d725c6afcd8f55abc17c56464ef6211f9ed59cccffe534129c77af" - -[[package]] -name = "icu_provider" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614" -dependencies = [ - "displaydoc", - "icu_locale_core", - "writeable", - "yoke", - "zerofrom", - "zerotrie", - "zerovec", -] - -[[package]] -name = "ident_case" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" - -[[package]] -name = "idna" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" -dependencies = [ - "idna_adapter", - "smallvec", - "utf8_iter", -] - -[[package]] -name = "idna_adapter" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" -dependencies = [ - "icu_normalizer", - "icu_properties", -] - -[[package]] -name = "indexmap" -version = "2.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017" -dependencies = [ - "equivalent", - "hashbrown 0.16.1", -] - -[[package]] -name = "inherent" -version = "1.0.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c727f80bfa4a6c6e2508d2f05b6f4bfce242030bd88ed15ae5331c5b5d30fba7" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.114", -] - -[[package]] -name = "is_terminal_polyfill" -version = "1.70.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" - -[[package]] -name = "itoa" -version = "1.0.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2" - -[[package]] -name = "js-sys" -version = "0.3.83" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "464a3709c7f55f1f721e5389aa6ea4e3bc6aba669353300af094b29ffbdde1d8" -dependencies = [ - "once_cell", - "wasm-bindgen", -] - -[[package]] -name = "kv-log-macro" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0de8b303297635ad57c9f5059fd9cee7a47f8e8daa09df0fcd07dd39fb22977f" -dependencies = [ - "log", -] - -[[package]] -name = "lazy_static" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" - -[[package]] -name = "libc" -version = "0.2.179" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5a2d376baa530d1238d133232d15e239abad80d05838b4b59354e5268af431f" - -[[package]] -name = "libredox" -version = "0.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d0b95e02c851351f877147b7deea7b1afb1df71b63aa5f8270716e0c5720616" -dependencies = [ - "bitflags", - "libc", - "redox_syscall 0.7.0", -] - -[[package]] -name = "linux-raw-sys" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" - -[[package]] -name = "litemap" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77" - -[[package]] -name = "lock_api" -version = "0.4.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" -dependencies = [ - "scopeguard", -] - -[[package]] -name = "log" -version = "0.4.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" -dependencies = [ - "value-bag", -] - -[[package]] -name = "matchers" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1525a2a28c7f4fa0fc98bb91ae755d1e2d1505079e05539e35bc876b5d65ae9" -dependencies = [ - "regex-automata", -] - -[[package]] -name = "md-5" -version = "0.10.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" -dependencies = [ - "cfg-if", - "digest", -] - -[[package]] -name = "memchr" -version = "2.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" - -[[package]] -name = "migration" -version = "0.1.0" -dependencies = [ - "async-std", - "sea-orm-migration", -] - -[[package]] -name = "mio" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a69bcab0ad47271a0234d9422b131806bf3968021e5dc9328caf2d4cd58557fc" -dependencies = [ - "libc", - "wasi", - "windows-sys 0.61.2", -] - -[[package]] -name = "num-traits" -version = "0.2.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" -dependencies = [ - "autocfg", -] - -[[package]] -name = "once_cell" -version = "1.21.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" - -[[package]] -name = "once_cell_polyfill" -version = "1.70.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" - -[[package]] -name = "ordered-float" -version = "4.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7bb71e1b3fa6ca1c61f383464aaf2bb0e2f8e772a1f01d486832464de363b951" -dependencies = [ - "num-traits", -] - -[[package]] -name = "ouroboros" -version = "0.18.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e0f050db9c44b97a94723127e6be766ac5c340c48f2c4bb3ffa11713744be59" -dependencies = [ - "aliasable", - "ouroboros_macro", - "static_assertions", -] - -[[package]] -name = "ouroboros_macro" -version = "0.18.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c7028bdd3d43083f6d8d4d5187680d0d3560d54df4cc9d752005268b41e64d0" -dependencies = [ - "heck 0.4.1", - "proc-macro2", - "proc-macro2-diagnostics", - "quote", - "syn 2.0.114", -] - -[[package]] -name = "parking" -version = "2.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" - -[[package]] -name = "parking_lot" -version = "0.12.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" -dependencies = [ - "lock_api", - "parking_lot_core", -] - -[[package]] -name = "parking_lot_core" -version = "0.9.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" -dependencies = [ - "cfg-if", - "libc", - "redox_syscall 0.5.18", - "smallvec", - "windows-link", -] - -[[package]] -name = "percent-encoding" -version = "2.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" - -[[package]] -name = "pin-project-lite" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" - -[[package]] -name = "pin-utils" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" - -[[package]] -name = "piper" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96c8c490f422ef9a4efd2cb5b42b76c8613d7e7dfc1caf667b8a3350a5acc066" -dependencies = [ - "atomic-waker", - "fastrand", - "futures-io", -] - -[[package]] -name = "polling" -version = "3.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d0e4f59085d47d8241c88ead0f274e8a0cb551f3625263c05eb8dd897c34218" -dependencies = [ - "cfg-if", - "concurrent-queue", - "hermit-abi", - "pin-project-lite", - "rustix", - "windows-sys 0.61.2", -] - -[[package]] -name = "potential_utf" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77" -dependencies = [ - "zerovec", -] - -[[package]] -name = "ppv-lite86" -version = "0.2.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" -dependencies = [ - "zerocopy", -] - -[[package]] -name = "proc-macro-error-attr2" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5" -dependencies = [ - "proc-macro2", - "quote", -] - -[[package]] -name = "proc-macro-error2" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802" -dependencies = [ - "proc-macro-error-attr2", - "proc-macro2", - "quote", - "syn 2.0.114", -] - -[[package]] -name = "proc-macro2" -version = "1.0.105" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "535d180e0ecab6268a3e718bb9fd44db66bbbc256257165fc699dadf70d16fe7" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "proc-macro2-diagnostics" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af066a9c399a26e020ada66a034357a868728e72cd426f3adcd35f80d88d88c8" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.114", - "version_check", - "yansi", -] - -[[package]] -name = "quote" -version = "1.0.43" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc74d9a594b72ae6656596548f56f667211f8a97b3d4c3d467150794690dc40a" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "rand" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" -dependencies = [ - "libc", - "rand_chacha", - "rand_core", -] - -[[package]] -name = "rand_chacha" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" -dependencies = [ - "ppv-lite86", - "rand_core", -] - -[[package]] -name = "rand_core" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" -dependencies = [ - "getrandom", -] - -[[package]] -name = "redox_syscall" -version = "0.5.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" -dependencies = [ - "bitflags", -] - -[[package]] -name = "redox_syscall" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49f3fe0889e69e2ae9e41f4d6c4c0181701d00e4697b356fb1f74173a5e0ee27" -dependencies = [ - "bitflags", -] - -[[package]] -name = "regex" -version = "1.12.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "843bc0191f75f3e22651ae5f1e72939ab2f72a4bc30fa80a066bd66edefc24d4" -dependencies = [ - "aho-corasick", - "memchr", - "regex-automata", - "regex-syntax", -] - -[[package]] -name = "regex-automata" -version = "0.4.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", -] - -[[package]] -name = "regex-syntax" -version = "0.8.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58" - -[[package]] -name = "ring" -version = "0.17.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" -dependencies = [ - "cc", - "cfg-if", - "getrandom", - "libc", - "untrusted", - "windows-sys 0.52.0", -] - -[[package]] -name = "rustc_version" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" -dependencies = [ - "semver", -] - -[[package]] -name = "rustix" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "146c9e247ccc180c1f61615433868c99f3de3ae256a30a43b49f67c2d9171f34" -dependencies = [ - "bitflags", - "errno", - "libc", - "linux-raw-sys", - "windows-sys 0.61.2", -] - -[[package]] -name = "rustls" -version = "0.23.36" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c665f33d38cea657d9614f766881e4d510e0eda4239891eea56b4cadcf01801b" -dependencies = [ - "once_cell", - "ring", - "rustls-pki-types", - "rustls-webpki", - "subtle", - "zeroize", -] - -[[package]] -name = "rustls-pki-types" -version = "1.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21e6f2ab2928ca4291b86736a8bd920a277a399bba1589409d72154ff87c1282" -dependencies = [ - "zeroize", -] - -[[package]] -name = "rustls-webpki" -version = "0.103.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ffdfa2f5286e2247234e03f680868ac2815974dc39e00ea15adc445d0aafe52" -dependencies = [ - "ring", - "rustls-pki-types", - "untrusted", -] - -[[package]] -name = "rustversion" -version = "1.0.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" - -[[package]] -name = "scopeguard" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" - -[[package]] -name = "sea-bae" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f694a6ab48f14bc063cfadff30ab551d3c7e46d8f81836c51989d548f44a2a25" -dependencies = [ - "heck 0.4.1", - "proc-macro-error2", - "proc-macro2", - "quote", - "syn 2.0.114", -] - -[[package]] -name = "sea-orm" -version = "1.1.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d945f62558fac19e5988680d2fdf747b734c2dbc6ce2cb81ba33ed8dde5b103" -dependencies = [ - "async-stream", - "async-trait", - "derive_more", - "futures-util", - "log", - "ouroboros", - "sea-orm-macros", - "sea-query", - "sea-query-binder", - "serde", - "sqlx", - "strum", - "thiserror", - "tracing", - "url", -] - -[[package]] -name = "sea-orm-cli" -version = "1.1.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c94492e2ab6c045b4cc38013809ce255d14c3d352c9f0d11e6b920e2adc948ad" -dependencies = [ - "chrono", - "clap", - "dotenvy", - "glob", - "regex", - "sea-schema", - "sqlx", - "tokio", - "tracing", - "tracing-subscriber", - "url", -] - -[[package]] -name = "sea-orm-macros" -version = "1.1.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84c2e64a50a9cc8339f10a27577e10062c7f995488e469f2c95762c5ee847832" -dependencies = [ - "heck 0.5.0", - "proc-macro2", - "quote", - "sea-bae", - "syn 2.0.114", - "unicode-ident", -] - -[[package]] -name = "sea-orm-migration" -version = "1.1.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7315c0cadb7e60fb17ee2bb282aa27d01911fc2a7e5836ec1d4ac37d19250bb4" -dependencies = [ - "async-trait", - "clap", - "dotenvy", - "sea-orm", - "sea-orm-cli", - "sea-schema", - "tracing", - "tracing-subscriber", -] - -[[package]] -name = "sea-query" -version = "0.32.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a5d1c518eaf5eda38e5773f902b26ab6d5e9e9e2bb2349ca6c64cf96f80448c" -dependencies = [ - "inherent", - "ordered-float", - "sea-query-derive", -] - -[[package]] -name = "sea-query-binder" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0019f47430f7995af63deda77e238c17323359af241233ec768aba1faea7608" -dependencies = [ - "sea-query", - "sqlx", -] - -[[package]] -name = "sea-query-derive" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bae0cbad6ab996955664982739354128c58d16e126114fe88c2a493642502aab" -dependencies = [ - "darling", - "heck 0.4.1", - "proc-macro2", - "quote", - "syn 2.0.114", - "thiserror", -] - -[[package]] -name = "sea-schema" -version = "0.16.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2239ff574c04858ca77485f112afea1a15e53135d3097d0c86509cef1def1338" -dependencies = [ - "futures", - "sea-query", - "sea-query-binder", - "sea-schema-derive", - "sqlx", -] - -[[package]] -name = "sea-schema-derive" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "debdc8729c37fdbf88472f97fd470393089f997a909e535ff67c544d18cfccf0" -dependencies = [ - "heck 0.4.1", - "proc-macro2", - "quote", - "syn 2.0.114", -] - -[[package]] -name = "semver" -version = "1.0.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" - -[[package]] -name = "serde" -version = "1.0.228" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" -dependencies = [ - "serde_core", - "serde_derive", -] - -[[package]] -name = "serde_core" -version = "1.0.228" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.228" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.114", -] - -[[package]] -name = "serde_json" -version = "1.0.149" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" -dependencies = [ - "itoa", - "memchr", - "serde", - "serde_core", - "zmij", -] - -[[package]] -name = "sha2" -version = "0.10.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest", -] - -[[package]] -name = "sharded-slab" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" -dependencies = [ - "lazy_static", -] - -[[package]] -name = "shlex" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" - -[[package]] -name = "slab" -version = "0.4.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589" - -[[package]] -name = "smallvec" -version = "1.15.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" -dependencies = [ - "serde", -] - -[[package]] -name = "socket2" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17129e116933cf371d018bb80ae557e889637989d8638274fb25622827b03881" -dependencies = [ - "libc", - "windows-sys 0.60.2", -] - -[[package]] -name = "sqlx" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fefb893899429669dcdd979aff487bd78f4064e5e7907e4269081e0ef7d97dc" -dependencies = [ - "sqlx-core", - "sqlx-macros", - "sqlx-postgres", -] - -[[package]] -name = "sqlx-core" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee6798b1838b6a0f69c007c133b8df5866302197e404e8b6ee8ed3e3a5e68dc6" -dependencies = [ - "base64", - "bytes", - "crc", - "crossbeam-queue", - "either", - "event-listener 5.4.1", - "futures-core", - "futures-intrusive", - "futures-io", - "futures-util", - "hashbrown 0.15.5", - "hashlink", - "indexmap", - "log", - "memchr", - "once_cell", - "percent-encoding", - "rustls", - "serde", - "serde_json", - "sha2", - "smallvec", - "thiserror", - "tokio", - "tokio-stream", - "tracing", - "url", - "webpki-roots 0.26.11", -] - -[[package]] -name = "sqlx-macros" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2d452988ccaacfbf5e0bdbc348fb91d7c8af5bee192173ac3636b5fb6e6715d" -dependencies = [ - "proc-macro2", - "quote", - "sqlx-core", - "sqlx-macros-core", - "syn 2.0.114", -] - -[[package]] -name = "sqlx-macros-core" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19a9c1841124ac5a61741f96e1d9e2ec77424bf323962dd894bdb93f37d5219b" -dependencies = [ - "dotenvy", - "either", - "heck 0.5.0", - "hex", - "once_cell", - "proc-macro2", - "quote", - "serde", - "serde_json", - "sha2", - "sqlx-core", - "sqlx-postgres", - "syn 2.0.114", - "tokio", - "url", -] - -[[package]] -name = "sqlx-postgres" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db58fcd5a53cf07c184b154801ff91347e4c30d17a3562a635ff028ad5deda46" -dependencies = [ - "atoi", - "base64", - "bitflags", - "byteorder", - "crc", - "dotenvy", - "etcetera", - "futures-channel", - "futures-core", - "futures-util", - "hex", - "hkdf", - "hmac", - "home", - "itoa", - "log", - "md-5", - "memchr", - "once_cell", - "rand", - "serde", - "serde_json", - "sha2", - "smallvec", - "sqlx-core", - "stringprep", - "thiserror", - "tracing", - "whoami", -] - -[[package]] -name = "stable_deref_trait" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" - -[[package]] -name = "static_assertions" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" - -[[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" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" - -[[package]] -name = "strum" -version = "0.26.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06" - -[[package]] -name = "subtle" -version = "2.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" - -[[package]] -name = "syn" -version = "1.0.109" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "syn" -version = "2.0.114" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4d107df263a3013ef9b1879b0df87d706ff80f65a86ea879bd9c31f9b307c2a" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "synstructure" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.114", -] - -[[package]] -name = "thiserror" -version = "2.0.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8" -dependencies = [ - "thiserror-impl", -] - -[[package]] -name = "thiserror-impl" -version = "2.0.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.114", -] - -[[package]] -name = "thread_local" -version = "1.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "tinystr" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869" -dependencies = [ - "displaydoc", - "zerovec", -] - -[[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" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" - -[[package]] -name = "tokio" -version = "1.49.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72a2903cd7736441aac9df9d7688bd0ce48edccaadf181c3b90be801e81d3d86" -dependencies = [ - "bytes", - "libc", - "mio", - "pin-project-lite", - "socket2", - "tokio-macros", - "windows-sys 0.61.2", -] - -[[package]] -name = "tokio-macros" -version = "2.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.114", -] - -[[package]] -name = "tokio-stream" -version = "0.1.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32da49809aab5c3bc678af03902d4ccddea2a87d028d86392a4b1560c6906c70" -dependencies = [ - "futures-core", - "pin-project-lite", - "tokio", -] - -[[package]] -name = "tracing" -version = "0.1.44" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" -dependencies = [ - "log", - "pin-project-lite", - "tracing-attributes", - "tracing-core", -] - -[[package]] -name = "tracing-attributes" -version = "0.1.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.114", -] - -[[package]] -name = "tracing-core" -version = "0.1.36" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" -dependencies = [ - "once_cell", -] - -[[package]] -name = "tracing-subscriber" -version = "0.3.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f30143827ddab0d256fd843b7a66d164e9f271cfa0dde49142c5ca0ca291f1e" -dependencies = [ - "matchers", - "once_cell", - "regex-automata", - "sharded-slab", - "thread_local", - "tracing", - "tracing-core", -] - -[[package]] -name = "typenum" -version = "1.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" - -[[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.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" - -[[package]] -name = "unicode-normalization" -version = "0.1.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fd4f6878c9cb28d874b009da9e8d183b5abc80117c40bbd187a1fde336be6e8" -dependencies = [ - "tinyvec", -] - -[[package]] -name = "unicode-properties" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7df058c713841ad818f1dc5d3fd88063241cc61f49f5fbea4b951e8cf5a8d71d" - -[[package]] -name = "unicode-xid" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" - -[[package]] -name = "untrusted" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" - -[[package]] -name = "url" -version = "2.5.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed" -dependencies = [ - "form_urlencoded", - "idna", - "percent-encoding", - "serde", -] - -[[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 = "value-bag" -version = "1.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ba6f5989077681266825251a52748b8c1d8a4ad098cc37e440103d0ea717fc0" - -[[package]] -name = "version_check" -version = "0.9.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" - -[[package]] -name = "wasi" -version = "0.11.1+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" - -[[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.106" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d759f433fa64a2d763d1340820e46e111a7a5ab75f993d1852d70b03dbb80fd" -dependencies = [ - "cfg-if", - "once_cell", - "rustversion", - "wasm-bindgen-macro", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-futures" -version = "0.4.56" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "836d9622d604feee9e5de25ac10e3ea5f2d65b41eac0d9ce72eb5deae707ce7c" -dependencies = [ - "cfg-if", - "js-sys", - "once_cell", - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "wasm-bindgen-macro" -version = "0.2.106" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48cb0d2638f8baedbc542ed444afc0644a29166f1595371af4fecf8ce1e7eeb3" -dependencies = [ - "quote", - "wasm-bindgen-macro-support", -] - -[[package]] -name = "wasm-bindgen-macro-support" -version = "0.2.106" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cefb59d5cd5f92d9dcf80e4683949f15ca4b511f4ac0a6e14d4e1ac60c6ecd40" -dependencies = [ - "bumpalo", - "proc-macro2", - "quote", - "syn 2.0.114", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-shared" -version = "0.2.106" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbc538057e648b67f72a982e708d485b2efa771e1ac05fec311f9f63e5800db4" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "web-sys" -version = "0.3.83" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b32828d774c412041098d182a8b38b16ea816958e07cf40eec2bc080ae137ac" -dependencies = [ - "js-sys", - "wasm-bindgen", -] - -[[package]] -name = "webpki-roots" -version = "0.26.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "521bc38abb08001b01866da9f51eb7c5d647a19260e00054a8c7fd5f9e57f7a9" -dependencies = [ - "webpki-roots 1.0.5", -] - -[[package]] -name = "webpki-roots" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12bed680863276c63889429bfd6cab3b99943659923822de1c8a39c49e4d722c" -dependencies = [ - "rustls-pki-types", -] - -[[package]] -name = "whoami" -version = "1.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d4a4db5077702ca3015d3d02d74974948aba2ad9e12ab7df718ee64ccd7e97d" -dependencies = [ - "libredox", - "wasite", -] - -[[package]] -name = "windows-core" -version = "0.62.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" -dependencies = [ - "windows-implement", - "windows-interface", - "windows-link", - "windows-result", - "windows-strings", -] - -[[package]] -name = "windows-implement" -version = "0.60.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.114", -] - -[[package]] -name = "windows-interface" -version = "0.59.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.114", -] - -[[package]] -name = "windows-link" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" - -[[package]] -name = "windows-result" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" -dependencies = [ - "windows-link", -] - -[[package]] -name = "windows-strings" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" -dependencies = [ - "windows-link", -] - -[[package]] -name = "windows-sys" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" -dependencies = [ - "windows-targets 0.48.5", -] - -[[package]] -name = "windows-sys" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" -dependencies = [ - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-sys" -version = "0.60.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" -dependencies = [ - "windows-targets 0.53.5", -] - -[[package]] -name = "windows-sys" -version = "0.61.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" -dependencies = [ - "windows-link", -] - -[[package]] -name = "windows-targets" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" -dependencies = [ - "windows_aarch64_gnullvm 0.48.5", - "windows_aarch64_msvc 0.48.5", - "windows_i686_gnu 0.48.5", - "windows_i686_msvc 0.48.5", - "windows_x86_64_gnu 0.48.5", - "windows_x86_64_gnullvm 0.48.5", - "windows_x86_64_msvc 0.48.5", -] - -[[package]] -name = "windows-targets" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" -dependencies = [ - "windows_aarch64_gnullvm 0.52.6", - "windows_aarch64_msvc 0.52.6", - "windows_i686_gnu 0.52.6", - "windows_i686_gnullvm 0.52.6", - "windows_i686_msvc 0.52.6", - "windows_x86_64_gnu 0.52.6", - "windows_x86_64_gnullvm 0.52.6", - "windows_x86_64_msvc 0.52.6", -] - -[[package]] -name = "windows-targets" -version = "0.53.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" -dependencies = [ - "windows-link", - "windows_aarch64_gnullvm 0.53.1", - "windows_aarch64_msvc 0.53.1", - "windows_i686_gnu 0.53.1", - "windows_i686_gnullvm 0.53.1", - "windows_i686_msvc 0.53.1", - "windows_x86_64_gnu 0.53.1", - "windows_x86_64_gnullvm 0.53.1", - "windows_x86_64_msvc 0.53.1", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" - -[[package]] -name = "windows_i686_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" - -[[package]] -name = "windows_i686_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" - -[[package]] -name = "windows_i686_gnu" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" - -[[package]] -name = "windows_i686_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" - -[[package]] -name = "windows_i686_gnullvm" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" - -[[package]] -name = "windows_i686_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" - -[[package]] -name = "windows_i686_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" - -[[package]] -name = "windows_i686_msvc" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" - -[[package]] -name = "writeable" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9" - -[[package]] -name = "yansi" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049" - -[[package]] -name = "yoke" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72d6e5c6afb84d73944e5cedb052c4680d5657337201555f9f2a16b7406d4954" -dependencies = [ - "stable_deref_trait", - "yoke-derive", - "zerofrom", -] - -[[package]] -name = "yoke-derive" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.114", - "synstructure", -] - -[[package]] -name = "zerocopy" -version = "0.8.33" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "668f5168d10b9ee831de31933dc111a459c97ec93225beb307aed970d1372dfd" -dependencies = [ - "zerocopy-derive", -] - -[[package]] -name = "zerocopy-derive" -version = "0.8.33" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c7962b26b0a8685668b671ee4b54d007a67d4eaf05fda79ac0ecf41e32270f1" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.114", -] - -[[package]] -name = "zerofrom" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" -dependencies = [ - "zerofrom-derive", -] - -[[package]] -name = "zerofrom-derive" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.114", - "synstructure", -] - -[[package]] -name = "zeroize" -version = "1.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" - -[[package]] -name = "zerotrie" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a59c17a5562d507e4b54960e8569ebee33bee890c70aa3fe7b97e85a9fd7851" -dependencies = [ - "displaydoc", - "yoke", - "zerofrom", -] - -[[package]] -name = "zerovec" -version = "0.11.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002" -dependencies = [ - "yoke", - "zerofrom", - "zerovec-derive", -] - -[[package]] -name = "zerovec-derive" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.114", -] - -[[package]] -name = "zmij" -version = "1.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fc5a66a20078bf1251bde995aa2fdcc4b800c70b5d92dd2c62abc5c60f679f8" diff --git a/crates/migrations/Cargo.toml b/crates/migrations/Cargo.toml deleted file mode 100644 index 9cfb991..0000000 --- a/crates/migrations/Cargo.toml +++ /dev/null @@ -1,26 +0,0 @@ -[package] -name = "migration" -version = "0.1.0" -edition = "2024" -rust-version = "1.92" -publish = false - -[lib] -name = "migration" -path = "src/lib.rs" - -[dependencies] -tokio = { workspace = true } -sea-orm-migration = { version = "1.1.7", features = [ - "runtime-tokio-rustls", # `ASYNC_RUNTIME` feature - "sqlx-postgres" # `DATABASE_DRIVER` feature -] } - -[dev-dependencies] -sea-orm = { version = "1.1.19", features = [ - "runtime-tokio-rustls", - "sqlx-postgres", -] } - -[lints] -workspace = true \ No newline at end of file diff --git a/crates/migrations/README.md b/crates/migrations/README.md deleted file mode 100644 index b3ea53e..0000000 --- a/crates/migrations/README.md +++ /dev/null @@ -1,41 +0,0 @@ -# Running Migrator CLI - -- Generate a new migration file - ```sh - cargo run -- migrate generate MIGRATION_NAME - ``` -- Apply all pending migrations - ```sh - cargo run - ``` - ```sh - cargo run -- up - ``` -- Apply first 10 pending migrations - ```sh - cargo run -- up -n 10 - ``` -- Rollback last applied migrations - ```sh - cargo run -- down - ``` -- Rollback last 10 applied migrations - ```sh - cargo run -- down -n 10 - ``` -- Drop all tables from the database, then reapply all migrations - ```sh - cargo run -- fresh - ``` -- Rollback all applied migrations, then reapply all migrations - ```sh - cargo run -- refresh - ``` -- Rollback all applied migrations - ```sh - cargo run -- reset - ``` -- Check the status of all migrations - ```sh - cargo run -- status - ``` diff --git a/crates/migrations/src/0001_items.rs b/crates/migrations/src/0001_items.rs deleted file mode 100644 index 84b44b7..0000000 --- a/crates/migrations/src/0001_items.rs +++ /dev/null @@ -1,54 +0,0 @@ -use sea_orm_migration::{prelude::*, schema::*}; - -#[derive(DeriveMigrationName)] -pub struct Migration; - -#[async_trait::async_trait] -impl MigrationTrait for Migration { - async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> { - manager - .create_table( - Table::create() - .table(Items::Table) - .if_not_exists() - .col(pk_auto(Items::Id)) - .col(uuid_uniq(Items::InternalId)) - .col(string(Items::Name)) - .col(string_null(Items::Description)) - .col(timestamp_with_time_zone(Items::CreatedAt)) - .col(timestamp_with_time_zone(Items::UpdatedAt)) - .to_owned(), - ) - .await?; - - // Create index on internal_id for faster lookups - manager - .create_index( - Index::create() - .name("idx_items_internal_id") - .table(Items::Table) - .col(Items::InternalId) - .to_owned(), - ) - .await?; - - Ok(()) - } - - async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> { - manager - .drop_table(Table::drop().table(Items::Table).to_owned()) - .await - } -} - -#[derive(DeriveIden)] -enum Items { - Table, - Id, - InternalId, - Name, - Description, - CreatedAt, - UpdatedAt, -} diff --git a/crates/migrations/src/lib.rs b/crates/migrations/src/lib.rs deleted file mode 100644 index 3bd98fb..0000000 --- a/crates/migrations/src/lib.rs +++ /dev/null @@ -1,13 +0,0 @@ -pub use sea_orm_migration::prelude::*; - -#[path = "0001_items.rs"] -mod m0001_items; - -pub struct Migrator; - -#[async_trait::async_trait] -impl MigratorTrait for Migrator { - fn migrations() -> Vec> { - vec![Box::new(m0001_items::Migration)] - } -} diff --git a/crates/migrations/src/main.rs b/crates/migrations/src/main.rs deleted file mode 100644 index f054dea..0000000 --- a/crates/migrations/src/main.rs +++ /dev/null @@ -1,6 +0,0 @@ -use sea_orm_migration::prelude::*; - -#[tokio::main] -async fn main() { - cli::run_cli(migration::Migrator).await; -} diff --git a/crates/migrations/tests/round_trip.rs b/crates/migrations/tests/round_trip.rs deleted file mode 100644 index a1ef047..0000000 --- a/crates/migrations/tests/round_trip.rs +++ /dev/null @@ -1,94 +0,0 @@ -//! Migration round-trip integration test. -//! -//! Applies every migration (`up`), asserts the schema is present, then rolls the -//! whole chain back (`down`) and asserts it is gone — proving each migration's -//! `up`/`down` are inverses. -//! -//! This test needs a throwaway Postgres. It **skips green** when -//! `MIGRATION_TEST_DATABASE_URL` is unset, so `cargo test -p migration` passes -//! with or without a database (CI/local stay green; the real round-trip is -//! opt-in). -//! -//! # Running the real round-trip -//! -//! ```bash -//! cargo make pg # or any throwaway Postgres -//! MIGRATION_TEST_DATABASE_URL=postgres://postgres:postgres@localhost/migration_test \ -//! cargo test -p migration --test round_trip -//! ``` - -use std::env; - -use migration::Migrator; -use sea_orm::{ConnectionTrait, Database, DatabaseConnection, DbBackend, Statement}; -use sea_orm_migration::MigratorTrait; - -const ENV_VAR: &str = "MIGRATION_TEST_DATABASE_URL"; - -/// Returns whether the `public.items` table exists in the connected database. -async fn items_table_exists(conn: &DatabaseConnection) -> bool { - let stmt = Statement::from_string( - DbBackend::Postgres, - "SELECT to_regclass('public.items') IS NOT NULL AS present", - ); - let row = conn - .query_one(stmt) - .await - .expect("query items table existence") - .expect("existence query returns a row"); - row.try_get::("", "present") - .expect("read `present` column as bool") -} - -#[tokio::test] -async fn migrations_apply_and_roll_back() { - let url = match env::var(ENV_VAR) { - Ok(url) if !url.is_empty() => url, - _ => { - eprintln!( - "skipping migration round-trip test: set {ENV_VAR} \ - (e.g. postgres://postgres:postgres@localhost/migration_test) to run" - ); - return; - } - }; - - // Safety: the schema reset below is destructive (`DROP SCHEMA ... CASCADE`). - // Refuse to run unless the target database name looks like a throwaway test - // DB, so a typo or a reused production URL cannot wipe real data. - let db_name = url - .rsplit('/') - .next() - .and_then(|tail| tail.split(['?', '#']).next()) - .unwrap_or(""); - assert!( - db_name.contains("test"), - "refusing to reset schema: {ENV_VAR} database name {db_name:?} must contain \ - \"test\" (point it at a throwaway DB, e.g. .../migration_test)" - ); - - let conn = Database::connect(&url) - .await - .expect("connect to test database"); - - // Start from a clean schema so the round-trip is deterministic. - conn.execute_unprepared("DROP SCHEMA IF EXISTS public CASCADE; CREATE SCHEMA public;") - .await - .expect("reset public schema"); - - // Apply every migration, then confirm the schema is present. - Migrator::up(&conn, None).await.expect("apply migrations"); - assert!( - items_table_exists(&conn).await, - "items table should exist after `up`" - ); - - // Roll the whole chain back, then confirm the schema is gone. - Migrator::down(&conn, None) - .await - .expect("roll back migrations"); - assert!( - !items_table_exists(&conn).await, - "items table should be gone after `down`" - ); -} diff --git a/crates/wubbie/Cargo.toml b/crates/wubbie/Cargo.toml new file mode 100644 index 0000000..5ed637e --- /dev/null +++ b/crates/wubbie/Cargo.toml @@ -0,0 +1,43 @@ +[package] +name = "wubbie" +description = "A fully-open SLM, from corpus to inference — model, training, and inference pipeline." +version.workspace = true +edition.workspace = true +rust-version.workspace = true +license.workspace = true +repository.workspace = true +readme = "../../README.md" +default-run = "wubbie" + +[lints] +workspace = true + +[features] +default = ["ndarray"] +# CPU backend (pure Rust, builds everywhere — this is what CI uses). +ndarray = ["burn/ndarray"] +# NVIDIA CUDA backend via CubeCL. Requires the CUDA toolkit at build time, so it +# is intentionally not part of the default build or CI. Build it explicitly with +# `cargo build --features cuda` on a CUDA-capable host. +cuda = ["burn/cuda", "burn/fusion"] + +[dependencies] +burn = { workspace = true, features = ["std", "autodiff", "train"] } +tokenizers = { workspace = true } +safetensors = { workspace = true } +anyhow = { workspace = true } +clap = { workspace = true } +serde = { workspace = true } +tracing = { workspace = true } +tracing-subscriber = { workspace = true } + +[dev-dependencies] +serde_json = { workspace = true } + +[[bin]] +name = "wubbie" +path = "src/main.rs" + +[lib] +name = "wubbie" +path = "src/lib.rs" diff --git a/crates/wubbie/src/backend.rs b/crates/wubbie/src/backend.rs new file mode 100644 index 0000000..029d587 --- /dev/null +++ b/crates/wubbie/src/backend.rs @@ -0,0 +1,25 @@ +//! Backend selection for the wubbie pipeline. +//! +//! Burn is generic over its compute backend. We pick the concrete backend at +//! compile time from the crate features: +//! +//! * `ndarray` (default) — a pure-Rust CPU backend that builds anywhere, used +//! by CI and for small local runs. +//! * `cuda` — the NVIDIA CUDA backend via CubeCL, for GPU training/inference. +//! +//! Training wraps the backend in [`burn::backend::Autodiff`] to enable reverse- +//! mode autodiff; inference uses the inner [`Backend`] directly. + +#[cfg(not(any(feature = "ndarray", feature = "cuda")))] +compile_error!("wubbie requires a backend feature: enable `ndarray` (default) or `cuda`."); + +/// The compute backend used for inference. +#[cfg(feature = "cuda")] +pub type Backend = burn::backend::Cuda; + +/// The compute backend used for inference. +#[cfg(all(feature = "ndarray", not(feature = "cuda")))] +pub type Backend = burn::backend::NdArray; + +/// The autodiff-enabled backend used for training. +pub type TrainBackend = burn::backend::Autodiff; diff --git a/crates/wubbie/src/config.rs b/crates/wubbie/src/config.rs new file mode 100644 index 0000000..bbdea96 --- /dev/null +++ b/crates/wubbie/src/config.rs @@ -0,0 +1,47 @@ +//! Model configuration types. +//! +//! This is a baseline, serde-serializable description of the model +//! architecture. The full configuration system (and the CLI layout convention +//! that loads it) is tracked in MULTI-1382. + +use serde::{Deserialize, Serialize}; + +/// Hyperparameters describing the model architecture. +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub struct ModelConfig { + /// Number of tokens in the tokenizer vocabulary. + pub vocab_size: usize, + /// Maximum sequence length the model attends over. + pub context_length: usize, + /// Hidden dimension of the residual stream. + pub d_model: usize, + /// Number of transformer blocks. + pub num_layers: usize, + /// Number of attention heads per block. + pub num_heads: usize, +} + +impl Default for ModelConfig { + fn default() -> Self { + Self { + vocab_size: 32_000, + context_length: 1_024, + d_model: 512, + num_layers: 8, + num_heads: 8, + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn round_trips_through_json() { + let config = ModelConfig::default(); + let json = serde_json::to_string(&config).expect("serialize"); + let parsed: ModelConfig = serde_json::from_str(&json).expect("deserialize"); + assert_eq!(config, parsed); + } +} diff --git a/crates/wubbie/src/inference.rs b/crates/wubbie/src/inference.rs new file mode 100644 index 0000000..818e3a8 --- /dev/null +++ b/crates/wubbie/src/inference.rs @@ -0,0 +1,4 @@ +//! Inference entry points. +//! +//! The inference server and text-generation loop are implemented in a follow-up +//! ticket. They will run on [`Backend`](crate::backend::Backend). diff --git a/crates/wubbie/src/lib.rs b/crates/wubbie/src/lib.rs new file mode 100644 index 0000000..84b259b --- /dev/null +++ b/crates/wubbie/src/lib.rs @@ -0,0 +1,18 @@ +//! wubbie — a fully-open small language model pipeline, from corpus to inference. +//! +//! This crate hosts the model definition, training loop, and inference entry +//! points for an all-Rust SLM pipeline built on [`burn`]. It is generic over +//! the Burn backend: the CPU (`ndarray`) backend is the default, and the NVIDIA +//! CUDA backend (CubeCL) is available via the `cuda` crate feature. +//! +//! Trained weights are **not** stored in this repository; they live in a +//! separate HuggingFace model repo. The [`weights`] module reads and writes the +//! on-disk [`safetensors`] format used to move them around. + +pub mod backend; +pub mod config; +pub mod inference; +pub mod model; +pub mod tokenizer; +pub mod training; +pub mod weights; diff --git a/crates/wubbie/src/main.rs b/crates/wubbie/src/main.rs new file mode 100644 index 0000000..218cdf2 --- /dev/null +++ b/crates/wubbie/src/main.rs @@ -0,0 +1,41 @@ +//! `wubbie` command-line entry point. +//! +//! This is a thin CLI scaffold. The subcommands are wired up but not yet +//! implemented; the layout convention they follow is tracked in MULTI-1382. + +use clap::{Parser, Subcommand}; +use tracing_subscriber::EnvFilter; + +#[derive(Debug, Parser)] +#[command( + name = "wubbie", + version, + about = "A fully-open SLM, from corpus to inference" +)] +struct Cli { + #[command(subcommand)] + command: Command, +} + +#[derive(Debug, Subcommand)] +enum Command { + /// Train the model from a corpus. + Train, + /// Generate text from a trained model. + Generate, + /// Serve the model for inference. + Serve, +} + +fn main() -> anyhow::Result<()> { + tracing_subscriber::fmt() + .with_env_filter(EnvFilter::from_default_env()) + .init(); + + let cli = Cli::parse(); + match cli.command { + Command::Train => anyhow::bail!("`wubbie train` is not implemented yet"), + Command::Generate => anyhow::bail!("`wubbie generate` is not implemented yet"), + Command::Serve => anyhow::bail!("`wubbie serve` is not implemented yet"), + } +} diff --git a/crates/wubbie/src/model.rs b/crates/wubbie/src/model.rs new file mode 100644 index 0000000..4ed6c81 --- /dev/null +++ b/crates/wubbie/src/model.rs @@ -0,0 +1,7 @@ +//! Model definition. +//! +//! The transformer architecture is implemented in a follow-up ticket. For now +//! this module re-exports [`ModelConfig`](crate::config::ModelConfig) so +//! downstream code has a stable path to the architecture description. + +pub use crate::config::ModelConfig; diff --git a/crates/wubbie/src/tokenizer.rs b/crates/wubbie/src/tokenizer.rs new file mode 100644 index 0000000..aec9f87 --- /dev/null +++ b/crates/wubbie/src/tokenizer.rs @@ -0,0 +1,16 @@ +//! Tokenizer loading helpers. +//! +//! wubbie uses the HuggingFace [`tokenizers`] crate. Training the byte-level BPE +//! tokenizer is tracked in MULTI-1379; this module currently loads an already +//! serialized `tokenizer.json`. + +use std::path::Path; + +use anyhow::Result; +use tokenizers::Tokenizer; + +/// Load a serialized tokenizer from a `tokenizer.json` file. +pub fn load(path: impl AsRef) -> Result { + Tokenizer::from_file(path.as_ref()) + .map_err(|err| anyhow::anyhow!("failed to load tokenizer: {err}")) +} diff --git a/crates/wubbie/src/training.rs b/crates/wubbie/src/training.rs new file mode 100644 index 0000000..2cbf3db --- /dev/null +++ b/crates/wubbie/src/training.rs @@ -0,0 +1,5 @@ +//! Training loop. +//! +//! The training pipeline (data loading, the Burn `Learner`, checkpointing) is +//! implemented in a follow-up ticket. It will run on +//! [`TrainBackend`](crate::backend::TrainBackend). diff --git a/crates/wubbie/src/weights.rs b/crates/wubbie/src/weights.rs new file mode 100644 index 0000000..c3827f1 --- /dev/null +++ b/crates/wubbie/src/weights.rs @@ -0,0 +1,34 @@ +//! safetensors weight (de)serialization helpers. +//! +//! Trained weights live in a separate HuggingFace model repo; this module reads +//! the on-disk [`safetensors`] format used to transport them. + +use anyhow::Result; +use safetensors::SafeTensors; + +/// Return the names of every tensor stored in a serialized safetensors buffer. +pub fn tensor_names(buffer: &[u8]) -> Result> { + let tensors = SafeTensors::deserialize(buffer)?; + Ok(tensors.names().into_iter().map(str::to_string).collect()) +} + +#[cfg(test)] +mod tests { + use super::*; + use safetensors::Dtype; + use safetensors::serialize; + use safetensors::tensor::TensorView; + + #[test] + fn round_trips_tensor_names() { + let data: Vec = [0.0f32, 1.0f32] + .iter() + .flat_map(|value| value.to_le_bytes()) + .collect(); + let view = TensorView::new(Dtype::F32, vec![2], &data).expect("view"); + let bytes = serialize(vec![("weight", view)], None).expect("serialize"); + + let names = tensor_names(&bytes).expect("read names"); + assert_eq!(names, vec!["weight".to_string()]); + } +} diff --git a/helm/chart/.helmignore b/helm/chart/.helmignore deleted file mode 100644 index 414bb6e..0000000 --- a/helm/chart/.helmignore +++ /dev/null @@ -1,18 +0,0 @@ -# Patterns to ignore when building packages. -.DS_Store -.git/ -.gitignore -.bzr/ -.bzrignore -.hg/ -.hgignore -.svn/ -*.swp -*.bak -*.tmp -*.orig -*~ -.project -.idea/ -*.tmproj -.vscode/ diff --git a/helm/chart/Chart.yaml b/helm/chart/Chart.yaml deleted file mode 100644 index fce1e50..0000000 --- a/helm/chart/Chart.yaml +++ /dev/null @@ -1,15 +0,0 @@ -apiVersion: v2 -name: __SERVICE_NAME__ -description: A Helm chart for the __SERVICE_NAME__ API service -type: application -version: 0.1.0 -# appVersion is automatically updated during CI to match the Docker image SHA. -# The value below is a placeholder for local development. -appVersion: "0.1.0" -maintainers: - - name: wack -keywords: - - __SERVICE_NAME__ - - api - - rust - - salvo diff --git a/helm/chart/templates/NOTES.txt b/helm/chart/templates/NOTES.txt deleted file mode 100644 index 18e42bc..0000000 --- a/helm/chart/templates/NOTES.txt +++ /dev/null @@ -1,20 +0,0 @@ -1. Get the application URL by running these commands: -{{- if .Values.gateway.enabled }} -{{- range .Values.gateway.hostnames }} - http://{{ . }} -{{- end }} -{{- else if contains "NodePort" .Values.service.type }} - export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "__SERVICE_NAME__.fullname" . }}) - export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}") - echo http://$NODE_IP:$NODE_PORT -{{- else if contains "LoadBalancer" .Values.service.type }} - NOTE: It may take a few minutes for the LoadBalancer IP to be available. - You can watch the status of by running 'kubectl get --namespace {{ .Release.Namespace }} svc -w {{ include "__SERVICE_NAME__.fullname" . }}' - export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "__SERVICE_NAME__.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}") - echo http://$SERVICE_IP:{{ .Values.service.port }} -{{- else if contains "ClusterIP" .Values.service.type }} - export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "__SERVICE_NAME__.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}") - export CONTAINER_PORT=$(kubectl get pod --namespace {{ .Release.Namespace }} $POD_NAME -o jsonpath="{.spec.containers[0].ports[0].containerPort}") - echo "Visit http://127.0.0.1:8080 to use your application" - kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 8080:$CONTAINER_PORT -{{- end }} diff --git a/helm/chart/templates/_helpers.tpl b/helm/chart/templates/_helpers.tpl deleted file mode 100644 index 6a01dc9..0000000 --- a/helm/chart/templates/_helpers.tpl +++ /dev/null @@ -1,62 +0,0 @@ -{{/* -Expand the name of the chart. -*/}} -{{- define "__SERVICE_NAME__.name" -}} -{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} -{{- end }} - -{{/* -Create a default fully qualified app name. -We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). -If release name contains chart name it will be used as a full name. -*/}} -{{- define "__SERVICE_NAME__.fullname" -}} -{{- if .Values.fullnameOverride }} -{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} -{{- else }} -{{- $name := default .Chart.Name .Values.nameOverride }} -{{- if contains $name .Release.Name }} -{{- .Release.Name | trunc 63 | trimSuffix "-" }} -{{- else }} -{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} -{{- end }} -{{- end }} -{{- end }} - -{{/* -Create chart name and version as used by the chart label. -*/}} -{{- define "__SERVICE_NAME__.chart" -}} -{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} -{{- end }} - -{{/* -Common labels -*/}} -{{- define "__SERVICE_NAME__.labels" -}} -helm.sh/chart: {{ include "__SERVICE_NAME__.chart" . }} -{{ include "__SERVICE_NAME__.selectorLabels" . }} -{{- if .Chart.AppVersion }} -app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} -{{- end }} -app.kubernetes.io/managed-by: {{ .Release.Service }} -{{- end }} - -{{/* -Selector labels -*/}} -{{- define "__SERVICE_NAME__.selectorLabels" -}} -app.kubernetes.io/name: {{ include "__SERVICE_NAME__.name" . }} -app.kubernetes.io/instance: {{ .Release.Name }} -{{- end }} - -{{/* -Create the name of the service account to use -*/}} -{{- define "__SERVICE_NAME__.serviceAccountName" -}} -{{- if .Values.serviceAccount.create }} -{{- default (include "__SERVICE_NAME__.fullname" .) .Values.serviceAccount.name }} -{{- else }} -{{- default "default" .Values.serviceAccount.name }} -{{- end }} -{{- end }} diff --git a/helm/chart/templates/deployment.yaml b/helm/chart/templates/deployment.yaml deleted file mode 100644 index 083cf9d..0000000 --- a/helm/chart/templates/deployment.yaml +++ /dev/null @@ -1,112 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - name: {{ include "__SERVICE_NAME__.fullname" . }} - labels: - {{- include "__SERVICE_NAME__.labels" . | nindent 4 }} -spec: - {{- if not .Values.autoscaling.enabled }} - replicas: {{ .Values.replicaCount }} - {{- end }} - selector: - matchLabels: - {{- include "__SERVICE_NAME__.selectorLabels" . | nindent 6 }} - template: - metadata: - {{- with .Values.podAnnotations }} - annotations: - {{- toYaml . | nindent 8 }} - {{- end }} - labels: - {{- include "__SERVICE_NAME__.selectorLabels" . | nindent 8 }} - spec: - {{- with .Values.imagePullSecrets }} - imagePullSecrets: - {{- toYaml . | nindent 8 }} - {{- end }} - serviceAccountName: {{ include "__SERVICE_NAME__.serviceAccountName" . }} - securityContext: - {{- toYaml .Values.podSecurityContext | nindent 8 }} - containers: - - name: {{ .Chart.Name }} - securityContext: - {{- toYaml .Values.securityContext | nindent 12 }} - image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" - imagePullPolicy: {{ .Values.image.pullPolicy }} - ports: - - name: http - containerPort: {{ .Values.service.targetPort }} - protocol: TCP - env: - - name: POSTGRES_HOST - valueFrom: - secretKeyRef: - name: {{ include "__SERVICE_NAME__.fullname" . }} - key: POSTGRES_HOST - - name: POSTGRES_PORT - valueFrom: - secretKeyRef: - name: {{ include "__SERVICE_NAME__.fullname" . }} - key: POSTGRES_PORT - - name: POSTGRES_DATABASE - valueFrom: - secretKeyRef: - name: {{ include "__SERVICE_NAME__.fullname" . }} - key: POSTGRES_DATABASE - - name: POSTGRES_USER - valueFrom: - secretKeyRef: - name: {{ include "__SERVICE_NAME__.fullname" . }} - key: POSTGRES_USER - - name: POSTGRES_PASSWORD - valueFrom: - secretKeyRef: - name: {{ include "__SERVICE_NAME__.fullname" . }} - key: POSTGRES_PASSWORD - - name: DATABASE_URL - valueFrom: - secretKeyRef: - name: {{ include "__SERVICE_NAME__.fullname" . }} - key: DATABASE_URL - {{- if .Values.database.acquireTimeout }} - - name: POSTGRES_ACQUIRE_TIMEOUT - value: {{ .Values.database.acquireTimeout | quote }} - {{- end }} - # OpenTelemetry configuration - - name: OTEL_DEPLOYMENT_ENVIRONMENT - value: {{ .Values.opentelemetry.environment | quote }} - {{- if .Values.opentelemetry.endpoint }} - - name: OTEL_EXPORTER_OTLP_ENDPOINT - value: {{ .Values.opentelemetry.endpoint | quote }} - {{- end }} - {{- if .Values.opentelemetry.apiKey }} - - name: OTEL_EXPORTER_API_KEY - value: {{ .Values.opentelemetry.apiKey | quote }} - {{- end }} - - name: SERVICE_VERSION - value: {{ .Chart.Version | quote }} - {{- with .Values.env }} - {{- toYaml . | nindent 12 }} - {{- end }} - {{- with .Values.envFrom }} - envFrom: - {{- toYaml . | nindent 12 }} - {{- end }} - livenessProbe: - {{- toYaml .Values.livenessProbe | nindent 12 }} - readinessProbe: - {{- toYaml .Values.readinessProbe | nindent 12 }} - resources: - {{- toYaml .Values.resources | nindent 12 }} - {{- with .Values.nodeSelector }} - nodeSelector: - {{- toYaml . | nindent 8 }} - {{- end }} - {{- with .Values.affinity }} - affinity: - {{- toYaml . | nindent 8 }} - {{- end }} - {{- with .Values.tolerations }} - tolerations: - {{- toYaml . | nindent 8 }} - {{- end }} diff --git a/helm/chart/templates/hpa.yaml b/helm/chart/templates/hpa.yaml deleted file mode 100644 index 99d86cf..0000000 --- a/helm/chart/templates/hpa.yaml +++ /dev/null @@ -1,32 +0,0 @@ -{{- if .Values.autoscaling.enabled }} -apiVersion: autoscaling/v2 -kind: HorizontalPodAutoscaler -metadata: - name: {{ include "__SERVICE_NAME__.fullname" . }} - labels: - {{- include "__SERVICE_NAME__.labels" . | nindent 4 }} -spec: - scaleTargetRef: - apiVersion: apps/v1 - kind: Deployment - name: {{ include "__SERVICE_NAME__.fullname" . }} - minReplicas: {{ .Values.autoscaling.minReplicas }} - maxReplicas: {{ .Values.autoscaling.maxReplicas }} - metrics: - {{- if .Values.autoscaling.targetCPUUtilizationPercentage }} - - type: Resource - resource: - name: cpu - target: - type: Utilization - averageUtilization: {{ .Values.autoscaling.targetCPUUtilizationPercentage }} - {{- end }} - {{- if .Values.autoscaling.targetMemoryUtilizationPercentage }} - - type: Resource - resource: - name: memory - target: - type: Utilization - averageUtilization: {{ .Values.autoscaling.targetMemoryUtilizationPercentage }} - {{- end }} -{{- end }} diff --git a/helm/chart/templates/httproute.yaml b/helm/chart/templates/httproute.yaml deleted file mode 100644 index 4c84bfc..0000000 --- a/helm/chart/templates/httproute.yaml +++ /dev/null @@ -1,55 +0,0 @@ -{{- if .Values.gateway.enabled -}} -apiVersion: gateway.networking.k8s.io/v1 -kind: HTTPRoute -metadata: - name: {{ include "__SERVICE_NAME__.fullname" . }} - labels: - {{- include "__SERVICE_NAME__.labels" . | nindent 4 }} - {{- with .Values.gateway.annotations }} - annotations: - {{- toYaml . | nindent 4 }} - {{- end }} -spec: - parentRefs: - {{- range .Values.gateway.parentRefs }} - - name: {{ .name }} - {{- if .namespace }} - namespace: {{ .namespace }} - {{- end }} - {{- if .sectionName }} - sectionName: {{ .sectionName }} - {{- end }} - {{- end }} - {{- if .Values.gateway.hostnames }} - hostnames: - {{- range .Values.gateway.hostnames }} - - {{ . | quote }} - {{- end }} - {{- end }} - rules: - {{- range .Values.gateway.rules }} - - matches: - {{- range .matches }} - - path: - type: {{ .path.type | default "PathPrefix" }} - value: {{ .path.value | default "/" }} - {{- if .method }} - method: {{ .method }} - {{- end }} - {{- if .headers }} - headers: - {{- toYaml .headers | nindent 12 }} - {{- end }} - {{- end }} - backendRefs: - - name: {{ include "__SERVICE_NAME__.fullname" $ }} - port: {{ $.Values.service.port }} - {{- if .weight }} - weight: {{ .weight }} - {{- end }} - {{- if .filters }} - filters: - {{- toYaml .filters | nindent 8 }} - {{- end }} - {{- end }} -{{- end }} diff --git a/helm/chart/templates/secret.yaml b/helm/chart/templates/secret.yaml deleted file mode 100644 index 0845872..0000000 --- a/helm/chart/templates/secret.yaml +++ /dev/null @@ -1,14 +0,0 @@ -apiVersion: v1 -kind: Secret -metadata: - name: {{ include "__SERVICE_NAME__.fullname" . }} - labels: - {{- include "__SERVICE_NAME__.labels" . | nindent 4 }} -type: Opaque -stringData: - POSTGRES_HOST: {{ .Values.database.host | quote }} - POSTGRES_PORT: {{ .Values.database.port | quote }} - POSTGRES_DATABASE: {{ .Values.database.name | quote }} - POSTGRES_USER: {{ .Values.database.user | quote }} - POSTGRES_PASSWORD: {{ .Values.database.password | quote }} - DATABASE_URL: {{ printf "postgres://%s:%s@%s:%v/%s" .Values.database.user .Values.database.password .Values.database.host (.Values.database.port | default 5432) (.Values.database.name | default "postgres") | quote }} diff --git a/helm/chart/templates/service.yaml b/helm/chart/templates/service.yaml deleted file mode 100644 index 20f1617..0000000 --- a/helm/chart/templates/service.yaml +++ /dev/null @@ -1,15 +0,0 @@ -apiVersion: v1 -kind: Service -metadata: - name: {{ include "__SERVICE_NAME__.fullname" . }} - labels: - {{- include "__SERVICE_NAME__.labels" . | nindent 4 }} -spec: - type: {{ .Values.service.type }} - ports: - - port: {{ .Values.service.port }} - targetPort: http - protocol: TCP - name: http - selector: - {{- include "__SERVICE_NAME__.selectorLabels" . | nindent 4 }} diff --git a/helm/chart/templates/serviceaccount.yaml b/helm/chart/templates/serviceaccount.yaml deleted file mode 100644 index 12f4dae..0000000 --- a/helm/chart/templates/serviceaccount.yaml +++ /dev/null @@ -1,12 +0,0 @@ -{{- if .Values.serviceAccount.create -}} -apiVersion: v1 -kind: ServiceAccount -metadata: - name: {{ include "__SERVICE_NAME__.serviceAccountName" . }} - labels: - {{- include "__SERVICE_NAME__.labels" . | nindent 4 }} - {{- with .Values.serviceAccount.annotations }} - annotations: - {{- toYaml . | nindent 4 }} - {{- end }} -{{- end }} diff --git a/helm/chart/values.yaml b/helm/chart/values.yaml deleted file mode 100644 index 212828a..0000000 --- a/helm/chart/values.yaml +++ /dev/null @@ -1,155 +0,0 @@ -# Default values for __SERVICE_NAME__. - -replicaCount: 1 - -image: - repository: ghcr.io/wack/__SERVICE_NAME__ - pullPolicy: Always - # Overrides the image tag whose default is the chart appVersion. - # The appVersion is automatically set to the commit SHA during CI, - # matching the Docker image tag pushed in the same workflow. - tag: "" - -imagePullSecrets: [] -nameOverride: "" -fullnameOverride: "" - -serviceAccount: - # Specifies whether a service account should be created - create: true - # Annotations to add to the service account - annotations: {} - # The name of the service account to use. - # If not set and create is true, a name is generated using the fullname template - name: "" - -podAnnotations: {} - -podSecurityContext: - runAsNonRoot: true - runAsUser: 65532 - runAsGroup: 65532 - fsGroup: 65532 - -securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - runAsNonRoot: true - runAsUser: 65532 - capabilities: - drop: - - ALL - -service: - type: ClusterIP - port: 80 - targetPort: 8080 - -# Gateway API HTTPRoute configuration -# For DigitalOcean Kubernetes (DOKS), Cilium is the default CNI with Gateway API support. -# The GatewayClass is "cilium" (controller: io.cilium/gateway-controller). -# Create a Gateway with gatewayClassName: cilium, then reference it here. -gateway: - enabled: false - annotations: {} - # Parent Gateway references (the Gateway must use gatewayClassName: cilium on DOKS) - parentRefs: - - name: cilium-gateway - # namespace: default - # sectionName: https - # Hostnames to match - hostnames: - - __SERVICE_NAME__.local - # Routing rules - rules: - - matches: - - path: - type: PathPrefix - value: /api/v1 - filters: - - type: URLRewrite - urlRewrite: - path: - type: ReplacePrefixMatch - replacePrefixMatch: / - -resources: - limits: - cpu: 500m - memory: 256Mi - requests: - cpu: 100m - memory: 128Mi - -autoscaling: - enabled: false - minReplicas: 1 - maxReplicas: 10 - targetCPUUtilizationPercentage: 80 - # targetMemoryUtilizationPercentage: 80 - -nodeSelector: {} - -tolerations: [] - -affinity: {} - -# Database configuration -database: - # PostgreSQL host (hostname or IP) - host: "" - # PostgreSQL port - port: 5432 - # PostgreSQL database name - name: "postgres" - # PostgreSQL username - user: "" - # PostgreSQL password - password: "" - # Connection acquire timeout in seconds (optional) - acquireTimeout: "" - -# OpenTelemetry configuration -# These fields are REQUIRED for proper observability in production -opentelemetry: - # OTLP exporter endpoint (e.g., "http://vector:4318" or "http://otel-collector:4318") - # Leave empty to use the default (http://localhost:4318) - endpoint: "" - # Deployment environment (REQUIRED) - # Valid values: "production", "development", "local" - environment: "production" - # API key for authenticating with the OTLP collector - # Sent as the X-API-KEY header on exporter requests - # Leave empty to disable API key authentication - apiKey: "" - -# Environment variables -env: [] - # - name: RUST_LOG - # value: "info" - -# Extra environment variables from secrets/configmaps -envFrom: [] - # - secretRef: - # name: my-secret - # - configMapRef: - # name: my-configmap - -# Liveness and readiness probes -livenessProbe: - httpGet: - path: /heartbeat - port: http - initialDelaySeconds: 5 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - -readinessProbe: - httpGet: - path: /heartbeat - port: http - initialDelaySeconds: 5 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 diff --git a/scripts/init-service.sh b/scripts/init-service.sh deleted file mode 100755 index a4af704..0000000 --- a/scripts/init-service.sh +++ /dev/null @@ -1,263 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -# Service Template Initialization Script -# This script replaces placeholder values with your service name. - -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -PROJECT_ROOT="$(dirname "$SCRIPT_DIR")" - -# Colors for output -RED='\033[0;31m' -GREEN='\033[0;32m' -YELLOW='\033[1;33m' -BLUE='\033[0;34m' -NC='\033[0m' # No Color - -print_header() { - echo -e "${BLUE}╔════════════════════════════════════════════════════════════╗${NC}" - echo -e "${BLUE}║${NC} Service Template Initialization Script ${BLUE}║${NC}" - echo -e "${BLUE}╚════════════════════════════════════════════════════════════╝${NC}" - echo "" -} - -print_success() { - echo -e "${GREEN}✓${NC} $1" -} - -print_warning() { - echo -e "${YELLOW}!${NC} $1" -} - -print_error() { - echo -e "${RED}✗${NC} $1" -} - -print_info() { - echo -e "${BLUE}→${NC} $1" -} - -# Validate service name: lowercase alphanumeric and hyphens only, must start with letter -validate_service_name() { - local name="$1" - - if [[ -z "$name" ]]; then - print_error "Service name cannot be empty" - return 1 - fi - - if [[ ! "$name" =~ ^[a-z][a-z0-9-]*$ ]]; then - print_error "Service name must start with a lowercase letter and contain only lowercase letters, numbers, and hyphens" - return 1 - fi - - if [[ "$name" =~ --|-$ ]]; then - print_error "Service name cannot have consecutive hyphens or end with a hyphen" - return 1 - fi - - if [[ ${#name} -gt 63 ]]; then - print_error "Service name must be 63 characters or less (Kubernetes DNS naming limit)" - return 1 - fi - - return 0 -} - -# Convert kebab-case to snake_case for Rust identifiers -to_snake_case() { - echo "$1" | tr '-' '_' -} - -# Replace placeholders in files -replace_in_file() { - local file="$1" - local search="$2" - local replace="$3" - - if [[ -f "$file" ]]; then - if grep -q "$search" "$file" 2>/dev/null; then - if [[ "$OSTYPE" == "darwin"* ]]; then - sed -i '' "s|$search|$replace|g" "$file" - else - sed -i "s|$search|$replace|g" "$file" - fi - return 0 - fi - fi - return 1 -} - -# Main replacement function -perform_replacements() { - local service_name="$1" - local snake_case_name="$2" - local files_modified=0 - - print_info "Replacing __SERVICE_NAME__ with ${service_name}" - print_info "Replacing __service_name__ with ${snake_case_name}" - echo "" - - # Find all files that need replacement (excluding .git, target, node_modules) - while IFS= read -r -d '' file; do - local modified=false - - if replace_in_file "$file" "__SERVICE_NAME__" "$service_name"; then - modified=true - fi - - if replace_in_file "$file" "__service_name__" "$snake_case_name"; then - modified=true - fi - - if [[ "$modified" == true ]]; then - local relative_path="${file#$PROJECT_ROOT/}" - print_success "Updated: $relative_path" - ((files_modified++)) || true - fi - done < <(find "$PROJECT_ROOT" \ - -type f \ - ! -path "*/.git/*" \ - ! -path "*/target/*" \ - ! -path "*/node_modules/*" \ - ! -name "init-service.sh" \ - -print0) - - echo "" - print_success "Modified $files_modified files" -} - -# Rename helm chart directory name in Chart.yaml -rename_chart() { - local service_name="$1" - local chart_yaml="$PROJECT_ROOT/helm/chart/Chart.yaml" - - if [[ -f "$chart_yaml" ]]; then - print_info "Helm chart configured with name: ${service_name}" - fi -} - -# Rename crates/client -> crates/-client so the directory matches the -# client package name (__SERVICE_NAME__-client), and fix the workspace members -# path. Matches the keystore-client / metricstore-client convention. -rename_client_crate() { - local service_name="$1" - local old_dir="$PROJECT_ROOT/crates/client" - local new_dir="$PROJECT_ROOT/crates/${service_name}-client" - - if [[ ! -d "$old_dir" ]]; then - print_info "No crates/client directory to rename" - return 0 - fi - if [[ -e "$new_dir" ]]; then - print_warning "crates/${service_name}-client already exists; skipping client rename" - return 0 - fi - - mv "$old_dir" "$new_dir" - replace_in_file "$PROJECT_ROOT/Cargo.toml" "crates/client" "crates/${service_name}-client" - print_success "Renamed client crate -> crates/${service_name}-client" -} - -# Self-destruct option -cleanup_template_files() { - local response - echo "" - read -p "Remove template initialization files? (y/N) " response - - if [[ "$response" =~ ^[Yy]$ ]]; then - rm -f "$PROJECT_ROOT/TEMPLATE.md" - rm -f "$PROJECT_ROOT/scripts/init-service.sh" - rmdir "$PROJECT_ROOT/scripts" 2>/dev/null || true - print_success "Template files removed" - else - print_info "Template files kept (you can delete them manually later)" - fi -} - -# Display next steps -print_next_steps() { - local service_name="$1" - - echo "" - echo -e "${BLUE}╔════════════════════════════════════════════════════════════╗${NC}" - echo -e "${BLUE}║${NC} Next Steps ${BLUE}║${NC}" - echo -e "${BLUE}╚════════════════════════════════════════════════════════════╝${NC}" - echo "" - echo " 1. Review the changes made to the repository" - echo "" - echo " 2. Update CLAUDE.md with your service-specific guidelines" - echo "" - echo " 3. Start the development database:" - echo " cargo make pg" - echo "" - echo " 4. Run migrations:" - echo " cargo make migrate" - echo "" - echo " 5. Build and run the server:" - echo " cargo run -- server" - echo "" - echo " 6. Replace example business logic in:" - echo " - src/domain/ (domain entities)" - echo " - src/services/ (business logic)" - echo " - src/repos/ (data access)" - echo " - src/controllers/ (HTTP handlers)" - echo " - src/views/ (request/response types)" - echo " - crates/migrations/ (database schema)" - echo "" -} - -# Main entry point -main() { - print_header - - local service_name="${1:-}" - - # Prompt for service name if not provided - if [[ -z "$service_name" ]]; then - echo "Enter your service name (lowercase, alphanumeric, hyphens allowed):" - echo "Example: user-service, auth-api, payment-gateway" - echo "" - read -p "Service name: " service_name - fi - - echo "" - - # Validate - if ! validate_service_name "$service_name"; then - exit 1 - fi - - local snake_case_name - snake_case_name=$(to_snake_case "$service_name") - - print_info "Service name: ${service_name}" - print_info "Rust crate name: ${snake_case_name}" - echo "" - - # Confirm before proceeding - read -p "Proceed with initialization? (Y/n) " confirm - if [[ "$confirm" =~ ^[Nn]$ ]]; then - print_warning "Initialization cancelled" - exit 0 - fi - - echo "" - - # Perform replacements - perform_replacements "$service_name" "$snake_case_name" - - # Update configurations - rename_chart "$service_name" - rename_client_crate "$service_name" - - # Optional cleanup - cleanup_template_files - - # Print next steps - print_next_steps "$service_name" - - print_success "Service template initialized successfully!" -} - -main "$@" diff --git a/spec/items/list.feature b/spec/items/list.feature deleted file mode 100644 index f21d422..0000000 --- a/spec/items/list.feature +++ /dev/null @@ -1,7 +0,0 @@ -Feature: Listing items. - - Rule: The items list endpoint should respond successfully. - - Example: Listing items against the mock-backed app succeeds. - When the client lists items - Then the response should be successful diff --git a/spec/monitoring/heartbeat.feature b/spec/monitoring/heartbeat.feature deleted file mode 100644 index 3d15a32..0000000 --- a/spec/monitoring/heartbeat.feature +++ /dev/null @@ -1,7 +0,0 @@ -Feature: The monitoring routes should be responsive. - - Rule: The heartbeat route should always succeed. - - Example: Requesting the heartbeat route should succeed. - Given a request is sent to the heartbeat route - Then the request should succeed diff --git a/src/bin/main.rs b/src/bin/main.rs deleted file mode 100644 index c1c4edd..0000000 --- a/src/bin/main.rs +++ /dev/null @@ -1,19 +0,0 @@ -use __service_name__::cli::Cli; -use clap::{CommandFactory, Parser}; - -#[tokio::main] -async fn main() -> miette::Result<()> { - let cli = Cli::parse(); - - match cli.cmd { - None => empty_command(), - Some(cmd) => cmd.dispatch().await, - } -} - -fn empty_command() -> miette::Result<()> { - Cli::command() - .print_long_help() - .expect("unable to print help message"); - Ok(()) -} diff --git a/src/cli/CLAUDE.md b/src/cli/CLAUDE.md deleted file mode 100644 index 2444b85..0000000 --- a/src/cli/CLAUDE.md +++ /dev/null @@ -1,281 +0,0 @@ -# CLI Command Organization Pattern - -This document describes the organizational pattern for CLI commands in this application. - -## Overview - -All CLI commands follow a consistent modular structure that separates command definitions from their implementation logic. This pattern promotes: -- Clear separation of concerns -- Easy testability -- Consistent code organization -- Simple addition of new commands - -## Pattern Structure - -### 1. Command Enum (`src/cli/mod.rs`) - -Each top-level CLI command must be represented as a variant in the `CliCommand` enum: - -```rust -#[derive(Debug, Subcommand, Clone)] -pub enum CliCommand { - /// Print the CLI version and exit - Version(version::Version), - /// Run the web server - Serve(serve::Serve), - /// Export OpenAPI specification to stdout - ExportOpenapi(export_openapi::ExportOpenapi), -} -``` - -**Requirements:** -- Each variant MUST have exactly one field -- The field must be a struct or enum with the same name as the variant (e.g., `Version(version::Version)`) -- The type can be a unit struct if the command has no arguments -- The type must implement clap's `Args` trait - -### 2. Command Module Directory - -Each command must have its own directory under `src/cli/`: -- `src/cli/version/` for the `Version` command -- `src/cli/serve/` for the `Serve` command -- `src/cli/export_openapi/` for the `ExportOpenapi` command - -### 3. Command Module (`src/cli//mod.rs`) - -Each command directory must contain a `mod.rs` file that: -- Defines the command struct -- Derives `Debug`, `Clone`, and clap's `Args` -- Implements a `dispatch` method that contains the business logic - -**Example (unit struct with no arguments):** -```rust -use clap::Args; - -#[derive(Debug, Clone, Args)] -pub struct Version; - -impl Version { - pub fn dispatch(self) -> miette::Result<()> { - println!("{} v{}", env!("CARGO_PKG_NAME"), env!("CARGO_PKG_VERSION")); - Ok(()) - } -} -``` - -**Example (command with its own configuration):** -```rust -use crate::cli::{CorsConfig, JwtConfig, PostgresConfig, TlsConfig}; -use clap::Args; - -#[derive(Debug, Clone, Args)] -pub struct Serve { - /// Server hostname - #[arg(long = "host", env = "HOST", default_value = "127.0.0.1")] - pub host: String, - - /// Server port - #[arg(long = "port", env = "PORT", default_value = "8080")] - pub port: u16, - - /// PostgreSQL database configuration - #[command(flatten)] - pub pg: PostgresConfig, - - /// JWT configuration - #[command(flatten)] - pub jwt: JwtConfig, - - /// TLS configuration - #[command(flatten)] - pub tls: TlsConfig, - - /// CORS configuration - #[command(flatten)] - pub cors: CorsConfig, -} - -impl Serve { - pub async fn dispatch(self) -> miette::Result<()> { - // Implementation using self.host, self.port, self.pg, etc. - Ok(()) - } -} -``` - -### 4. Central Dispatch (`src/cli/mod.rs`) - -The `CliCommand` enum implements an async `dispatch` method that delegates to each command's implementation: - -```rust -impl CliCommand { - pub async fn dispatch(self) -> miette::Result<()> { - match self { - CliCommand::Version(version) => version.dispatch(), - CliCommand::Serve(serve) => serve.dispatch().await, - CliCommand::ExportOpenapi(export_openapi) => export_openapi.dispatch(), - } - } -} -``` - -**Key Points:** -- The method is async to support commands that need async operations -- Each command is self-contained with its own configuration -- Commands that need async can await, synchronous commands return immediately - -### 5. Main Entry Point (`src/bin/main.rs`) - -The main function parses the CLI and calls the central dispatch: - -```rust -let cli = Cli::parse(); - -match cli.cmd { - None => empty_command(), - Some(cmd) => cmd.dispatch().await, -} -``` - -### 6. Global vs Command-Specific Configuration - -**Global Configuration** (in `Cli` struct): -- Options that apply to all commands (e.g., `log_level`, `log_format`, `enable_colors`) -- Must be marked with `global = true` in clap attributes -- Available to all commands regardless of which subcommand is executed - -**Command-Specific Configuration** (in command structs): -- Options that only apply to a specific command (e.g., `host`, `port` for `Serve`) -- Defined as fields in the command's struct -- Only required when that specific command is executed -- Can use `#[command(flatten)]` to include shared configuration types - -**Example:** -```rust -// Global configuration - applies to all commands -#[derive(Debug, Parser, Clone)] -pub struct Cli { - #[arg(long, env = "LOG_LEVEL", default_value = "info", global = true)] - pub log_level: LevelFilter, - - #[command(subcommand)] - pub cmd: Option, -} - -// Command-specific configuration - only for the Serve command -#[derive(Debug, Clone, Args)] -pub struct Serve { - #[arg(long = "host", env = "HOST", default_value = "127.0.0.1")] - pub host: String, - - #[arg(long = "port", env = "PORT", default_value = "8080")] - pub port: u16, -} -``` - -This separation ensures that: -- Commands like `version` don't require unnecessary configuration -- Configuration validation only happens for the commands that use it -- The CLI is more user-friendly (fewer required arguments for simple commands) - -## Adding a New Command - -To add a new CLI command: - -1. **Create the command directory:** - ```bash - mkdir src/cli/my_command - ``` - -2. **Create `src/cli/my_command/mod.rs`:** - ```rust - use clap::Args; - - #[derive(Debug, Clone, Args)] - pub struct MyCommand { - // Add command-specific arguments here if needed - } - - impl MyCommand { - pub fn dispatch(self) -> miette::Result<()> { - // Implement your command logic here - Ok(()) - } - } - ``` - -3. **Register the module in `src/cli/mod.rs`:** - ```rust - pub mod my_command; - ``` - -4. **Add the variant to `CliCommand` enum:** - ```rust - #[derive(Debug, Subcommand, Clone)] - pub enum CliCommand { - // ... existing commands - /// Description of my command - MyCommand(my_command::MyCommand), - } - ``` - -5. **Add the dispatch case:** - ```rust - impl CliCommand { - pub async fn dispatch(self) -> miette::Result<()> { - match self { - // ... existing commands - CliCommand::MyCommand(my_command) => my_command.dispatch(), - } - } - } - ``` - -6. **If your command needs configuration, add it as fields:** - ```rust - use clap::Args; - - #[derive(Debug, Clone, Args)] - pub struct MyCommand { - /// Command-specific argument - #[arg(long, env = "MY_ARG")] - pub my_arg: String, - - /// Command-specific flag - #[arg(long)] - pub my_flag: bool, - } - - impl MyCommand { - pub fn dispatch(self) -> miette::Result<()> { - // Use self.my_arg, self.my_flag, etc. - Ok(()) - } - } - ``` - -## Design Principles - -- **Single Responsibility**: Each command module is responsible for one command's logic -- **Consistency**: All commands follow the same organizational pattern -- **Testability**: Command logic is isolated in testable functions -- **Modularity**: Commands can be added, removed, or modified without affecting others -- **Type Safety**: clap's derive macros provide compile-time validation of command structure - -## Dispatch Method Signatures - -All dispatch methods follow the pattern `dispatch(self)` and return `miette::Result<()>`: - -- **Synchronous command:** - ```rust - pub fn dispatch(self) -> miette::Result<()> - ``` - -- **Asynchronous command:** - ```rust - pub async fn dispatch(self) -> miette::Result<()> - ``` - -Commands are self-contained and access their configuration through `self` fields. There is no need to pass the `Cli` struct to dispatch methods because: -- Global configuration is accessed through clap's global args mechanism if needed -- Command-specific configuration is defined as fields in the command struct diff --git a/src/cli/colors.rs b/src/cli/colors.rs deleted file mode 100644 index d0b7f26..0000000 --- a/src/cli/colors.rs +++ /dev/null @@ -1,9 +0,0 @@ -use clap::ValueEnum; - -#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, ValueEnum, Default)] -pub enum EnableColors { - Always, - Never, - #[default] - Auto, -} diff --git a/src/cli/cors.rs b/src/cli/cors.rs deleted file mode 100644 index d916d69..0000000 --- a/src/cli/cors.rs +++ /dev/null @@ -1,120 +0,0 @@ -use clap::Args; - -#[derive(Debug, Clone, Args)] -pub struct CorsConfig { - /// Allowed CORS origins (comma-separated). - /// For local development, localhost and 127.0.0.1 are always allowed. - /// Use specific origins in production (e.g., "https://example.com,https://app.example.com"). - /// IMPORTANT: Never use "*" wildcard in production. - #[arg( - long = "cors-origins", - env = "CORS_ALLOWED_ORIGINS", - value_delimiter = ',', - default_value = "" - )] - pub allowed_origins: Vec, - - /// Allow credentials (cookies, authorization headers) in CORS requests. - /// Disabled by default for security. Only enable if you need authenticated cross-origin requests. - #[arg( - long = "cors-allow-credentials", - env = "CORS_ALLOW_CREDENTIALS", - default_value = "false" - )] - pub allow_credentials: bool, - - /// Maximum age (in seconds) for CORS preflight cache. - /// Default is 3600 seconds (1 hour). - #[arg(long = "cors-max-age", env = "CORS_MAX_AGE", default_value = "3600")] - pub max_age: u64, -} - -impl CorsConfig { - /// Returns the list of allowed origins, including developer-friendly defaults. - /// If no origins are configured, returns localhost variants for local development. - pub fn get_allowed_origins(&self) -> Vec { - let mut origins = self.allowed_origins.clone(); - - // Remove any empty strings that might come from parsing - origins.retain(|s| !s.is_empty()); - - // If no origins specified, use developer-friendly defaults - if origins.is_empty() { - origins = vec![ - "http://localhost:3000".to_string(), - "http://localhost:8080".to_string(), - "http://127.0.0.1:3000".to_string(), - "http://127.0.0.1:8080".to_string(), - ]; - } - - origins - } - - /// Validates that the configuration doesn't use wildcard in what appears to be production. - /// Returns true if the configuration looks safe. - pub fn is_safe(&self) -> bool { - // Check if any origin is a wildcard - !self.allowed_origins.iter().any(|origin| origin == "*") - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_default_origins_when_empty() { - let config = CorsConfig { - allowed_origins: vec![], - allow_credentials: false, - max_age: 3600, - }; - - let origins = config.get_allowed_origins(); - assert_eq!(origins.len(), 4); - assert!(origins.contains(&"http://localhost:3000".to_string())); - assert!(origins.contains(&"http://localhost:8080".to_string())); - assert!(origins.contains(&"http://127.0.0.1:3000".to_string())); - assert!(origins.contains(&"http://127.0.0.1:8080".to_string())); - } - - #[test] - fn test_custom_origins() { - let config = CorsConfig { - allowed_origins: vec![ - "https://example.com".to_string(), - "https://app.example.com".to_string(), - ], - allow_credentials: false, - max_age: 3600, - }; - - let origins = config.get_allowed_origins(); - assert_eq!(origins.len(), 2); - assert!(origins.contains(&"https://example.com".to_string())); - assert!(origins.contains(&"https://app.example.com".to_string())); - } - - #[test] - fn test_wildcard_is_unsafe() { - let config = CorsConfig { - allowed_origins: vec!["*".to_string()], - allow_credentials: false, - max_age: 3600, - }; - - assert!(!config.is_safe()); - } - - #[test] - fn test_safe_origins() { - let config = CorsConfig { - allowed_origins: vec!["https://example.com".to_string()], - allow_credentials: false, - max_age: 3600, - }; - - assert!(config.is_safe()); - } -} diff --git a/src/cli/db.rs b/src/cli/db.rs deleted file mode 100644 index 6176d53..0000000 --- a/src/cli/db.rs +++ /dev/null @@ -1,52 +0,0 @@ -use clap::Args; - -#[derive(Debug, Clone, Args)] -pub struct DbConfig { - /// Database URL for the primary database - #[arg( - long = "db-url", - env = "DATABASE_URL", - help = "Settings for the primary database. This is usually writeable, but will be read-only in some configurations." - )] - pub url: String, - - /// Minimum number of database connections - #[arg( - long = "db-min-connections", - env = "DB_MIN_CONNECTIONS", - default_value = "5" - )] - pub min_connections: u32, - - /// Maximum number of database connections - #[arg( - long = "db-max-connections", - env = "DB_MAX_CONNECTIONS", - default_value = "100" - )] - pub max_connections: u32, - - /// Database connection idle timeout in seconds - #[arg( - long = "db-idle-timeout", - env = "DB_IDLE_TIMEOUT", - default_value = "8" - )] - pub idle_timeout: u32, - - /// Database connection timeout in seconds - #[arg( - long = "db-connect-timeout", - env = "DB_CONNECT_TIMEOUT", - default_value = "8" - )] - pub connect_timeout: u32, - - /// Enable SQLx logging - #[arg( - long = "db-sqlx-logging", - env = "DB_SQLX_LOGGING", - default_value = "false" - )] - pub sqlx_logging: bool, -} diff --git a/src/cli/export_openapi/mod.rs b/src/cli/export_openapi/mod.rs deleted file mode 100644 index 5f12f44..0000000 --- a/src/cli/export_openapi/mod.rs +++ /dev/null @@ -1,30 +0,0 @@ -use clap::Args; -use salvo::oapi::OpenApi; -use std::io::Write; - -#[derive(Debug, Clone, Args)] -pub struct ExportOpenapi; - -impl ExportOpenapi { - pub fn dispatch(self) -> miette::Result<()> { - // Create a minimal router without database-dependent middleware - let router = crate::controllers::schema_router(); - - // Generate OpenAPI spec with the same metadata as the running server - let mut doc = OpenApi::new(env!("CARGO_PKG_NAME"), env!("CARGO_PKG_VERSION")); - doc.info.description = Some("API service".to_string()); - doc.info.license = Some(salvo::oapi::License::new("MIT")); - doc = doc.merge_router(&router); - - // Serialize the OpenAPI document to JSON - let spec_json = serde_json::to_string_pretty(&doc) - .map_err(|e| miette::miette!("Failed to serialize OpenAPI spec: {}", e))?; - - // Output to stdout - std::io::stdout() - .write_all(spec_json.as_bytes()) - .map_err(|e| miette::miette!("Failed to write OpenAPI spec to stdout: {}", e))?; - - Ok(()) - } -} diff --git a/src/cli/mod.rs b/src/cli/mod.rs deleted file mode 100644 index 62440b6..0000000 --- a/src/cli/mod.rs +++ /dev/null @@ -1,60 +0,0 @@ -pub use colors::EnableColors; -pub use cors::CorsConfig; -pub use pg::PostgresConfig; - -use clap::{Parser, Subcommand}; - -mod colors; -mod cors; -pub mod export_openapi; -mod pg; -pub mod server; -pub mod version; - -#[derive(Debug, Clone, clap::ValueEnum, Default)] -pub enum LogFormat { - #[default] - Text, - JSON, -} - -#[derive(Debug, Clone, clap::Args)] -pub struct TlsConfig { - /// Path to TLS certificate file - #[arg(long = "tls-cert", env = "TLS_CERT", requires = "key")] - pub cert: Option, - - /// Path to TLS key file - #[arg(long = "tls-key", env = "TLS_KEY", requires = "cert")] - pub key: Option, -} - -#[derive(Debug, Parser, Clone)] -pub struct Cli { - #[command(subcommand)] - pub cmd: Option, -} - -// `CliCommand` is parsed exactly once at process startup, so the size delta -// between the small `Version`/`ExportOpenapi` variants and the larger `Server` -// variant is irrelevant — boxing it would only add churn to the dispatch match. -#[allow(clippy::large_enum_variant)] -#[derive(Debug, Subcommand, Clone)] -pub enum CliCommand { - /// Print the CLI version and exit - Version(version::Version), - /// Run the web server - Server(server::Server), - /// Export OpenAPI specification to stdout - ExportOpenapi(export_openapi::ExportOpenapi), -} - -impl CliCommand { - pub async fn dispatch(self) -> miette::Result<()> { - match self { - CliCommand::Version(version) => version.dispatch(), - CliCommand::Server(server) => server.dispatch().await, - CliCommand::ExportOpenapi(export_openapi) => export_openapi.dispatch(), - } - } -} diff --git a/src/cli/pg.rs b/src/cli/pg.rs deleted file mode 100644 index 9fcb1e5..0000000 --- a/src/cli/pg.rs +++ /dev/null @@ -1,53 +0,0 @@ -use std::time::Duration; - -use clap::Parser; - -/// `PostgresConfig` enables a connection to a Postgres database, -/// and is required under almost all circumstances. -#[derive(Debug, Parser, Clone)] -pub struct PostgresConfig { - /// Postgres host (url or unix socket, localhost while running locally) - #[arg(long, env = "POSTGRES_HOST", default_value = "localhost")] - pub pg_host: String, - /// Postgres database port - #[arg(long = "postgres-port", env = "POSTGRES_PORT", default_value_t = 5432)] - pub pg_port: u16, - /// Postgres database - #[arg(long, env = "POSTGRES_DATABASE", default_value = "postgres")] - pub database: String, - /// Postgres username - #[arg(long, env = "POSTGRES_USER", default_value = "")] - pub username: String, - /// Postgres password - #[arg(long, env = "POSTGRES_PASSWORD", default_value = "")] - pub password: String, - - // default_value_t=chrono::Duration::from_millis(2500))] - // The maximum amount of time spent waiting to acquire a connection to the DB. - // See - // [this link](https://docs.rs/sqlx/latest/sqlx/pool/struct.PoolOptions.html#method.acquire_timeout) - #[arg(env = "POSTGRES_ACQUIRE_TIMEOUT", value_parser=parse_duration)] - pub acquire_timeout: Option, -} - -fn parse_duration(arg: &str) -> Result { - let seconds = arg.parse()?; - Ok(std::time::Duration::from_secs(seconds)) -} - -impl PostgresConfig { - /// Compose a PostgreSQL connection string from the configuration - pub fn connection_string(&self) -> String { - if self.password.is_empty() { - format!( - "postgres://{}@{}:{}/{}", - self.username, self.pg_host, self.pg_port, self.database - ) - } else { - format!( - "postgres://{}:{}@{}:{}/{}", - self.username, self.password, self.pg_host, self.pg_port, self.database - ) - } - } -} diff --git a/src/cli/server/mod.rs b/src/cli/server/mod.rs deleted file mode 100644 index 29695e0..0000000 --- a/src/cli/server/mod.rs +++ /dev/null @@ -1,165 +0,0 @@ -use crate::cli::{CorsConfig, EnableColors, LogFormat, PostgresConfig, TlsConfig}; -use crate::middleware::JsonErrorCatcher; -use clap::Args; -use mvc_helpers::DeploymentEnvironment; -use salvo::catcher::Catcher; -use salvo::conn::rustls::{Keycert, RustlsConfig}; -use salvo::prelude::*; -use salvo::server::ServerHandle; -use tokio::signal; -use tracing::{info, level_filters::LevelFilter}; - -#[derive(Debug, Clone, Args)] -pub struct Server { - /// Server hostname - #[arg(long = "host", env = "HOST", default_value = "127.0.0.1")] - pub host: String, - - /// Server port - #[arg(long = "port", env = "PORT", default_value = "8080")] - pub port: u16, - - /// PostgreSQL database configuration - #[command(flatten)] - pub pg: PostgresConfig, - - /// TLS configuration - #[command(flatten)] - pub tls: TlsConfig, - - /// CORS configuration - #[command(flatten)] - pub cors: CorsConfig, - - #[arg(long, env = "LOG_LEVEL", default_value = "info")] - pub log_level: LevelFilter, - - #[arg(long, env = "LOG_FORMAT", default_value = "text")] - pub log_format: LogFormat, - - #[arg(long, default_value = "auto")] - pub enable_colors: EnableColors, - - /// Deployment environment for OpenTelemetry resource attributes - #[arg(long, env = "OTEL_DEPLOYMENT_ENVIRONMENT", default_value_t)] - pub deployment_environment: DeploymentEnvironment, - - /// API key for authenticating with the OTLP collector (sent as X-API-KEY header) - #[arg(long = "otel-exporter-api-key", env = "OTEL_EXPORTER_API_KEY")] - pub otel_exporter_api_key: Option, - - /// Service version for OpenTelemetry (e.g. Helm chart calver tag). Falls back to crate version. - #[arg(long, env = "SERVICE_VERSION")] - pub service_version: Option, -} - -impl Server { - pub async fn dispatch(self) -> miette::Result<()> { - // Initialize OpenTelemetry tracing and logging subscriber - // The guard ensures spans are flushed on shutdown when dropped - let _telemetry_guard = - crate::utils::telemetry::init_telemetry(crate::utils::telemetry::TelemetryConfig { - log_level: self.log_level, - log_format: self.log_format.clone(), - enable_colors: self.enable_colors, - deployment_environment: self.deployment_environment, - otel_exporter_api_key: self.otel_exporter_api_key, - service_version: self.service_version, - }); - - info!("Initializing database connection"); - - // Initialize database - crate::utils::db::init(&self.pg).await; - - // Build the listen address from host and port - let listen_addr = format!("{}:{}", self.host, self.port); - - // Create the service with controllers, CORS, and tracing middleware. - // Attach a catcher that rewrites framework-level error responses - // (e.g. `PathParam` / `JsonBody` extractor failures) as our JSON - // error envelope. - let service = Service::new(crate::controllers::root(&self.cors)) - .catcher(Catcher::default().hoop(JsonErrorCatcher)); - - info!(address = %listen_addr, "Starting server"); - - // Check if TLS is configured - if let (Some(cert), Some(key)) = (self.tls.cert, self.tls.key) { - info!( - url = format!( - "https://{}/scalar", - listen_addr.replace("0.0.0.0", "127.0.0.1") - ), - "OpenAPI documentation available" - ); - - let config = RustlsConfig::new(Keycert::new().cert(cert).key(key)); - let acceptor = TcpListener::new(listen_addr.clone()) - .rustls(config) - .bind() - .await; - let salvo_server = salvo::Server::new(acceptor); - - // Spawn signal handler for graceful shutdown - tokio::spawn(shutdown_signal(salvo_server.handle())); - - // Start the server - salvo_server.serve(service).await; - } else { - info!( - url = format!( - "http://{}/scalar", - listen_addr.replace("0.0.0.0", "127.0.0.1") - ), - "OpenAPI documentation available" - ); - - let acceptor = TcpListener::new(listen_addr).bind().await; - let salvo_server = salvo::Server::new(acceptor); - - // Spawn signal handler for graceful shutdown - tokio::spawn(shutdown_signal(salvo_server.handle())); - - // Start the server - salvo_server.serve(service).await; - } - - // When we reach here, the server has stopped. - // The _telemetry_guard will be dropped, flushing any pending spans. - info!("Server shutdown complete, flushing telemetry..."); - - Ok(()) - } -} - -async fn shutdown_signal(handle: ServerHandle) { - let ctrl_c = async { - signal::ctrl_c() - .await - .expect("failed to install Ctrl+C handler"); - }; - - #[cfg(unix)] - let terminate = async { - signal::unix::signal(signal::unix::SignalKind::terminate()) - .expect("failed to install signal handler") - .recv() - .await; - }; - - #[cfg(not(unix))] - let terminate = std::future::pending::<()>(); - - tokio::select! { - _ = ctrl_c => { - info!("Ctrl+C signal received, shutting down gracefully..."); - }, - _ = terminate => { - info!("Terminate signal received, shutting down gracefully..."); - }, - } - - info!("Initiating graceful shutdown with 60 second timeout..."); - handle.stop_graceful(Some(std::time::Duration::from_secs(60))); -} diff --git a/src/cli/version/mod.rs b/src/cli/version/mod.rs deleted file mode 100644 index 7f6ce86..0000000 --- a/src/cli/version/mod.rs +++ /dev/null @@ -1,11 +0,0 @@ -use clap::Args; - -#[derive(Debug, Clone, Args)] -pub struct Version; - -impl Version { - pub fn dispatch(self) -> miette::Result<()> { - println!("{} v{}", env!("CARGO_PKG_NAME"), env!("CARGO_PKG_VERSION")); - Ok(()) - } -} diff --git a/src/controllers/CLAUDE.md b/src/controllers/CLAUDE.md deleted file mode 100644 index 318a584..0000000 --- a/src/controllers/CLAUDE.md +++ /dev/null @@ -1 +0,0 @@ -Each REST API resource must have its own directory under `controllers/`. Top-level resources get a folder directly in `controllers/` (e.g. `controllers/users/`, `controllers/workspaces/`). Nested resources mirror the URL path hierarchy — for example, a resource at `workspaces/{id}/api-keys` lives at `controllers/workspaces/api_keys/`. diff --git a/src/controllers/items/create.rs b/src/controllers/items/create.rs deleted file mode 100644 index 2cc3fe0..0000000 --- a/src/controllers/items/create.rs +++ /dev/null @@ -1,53 +0,0 @@ -use std::sync::Arc; - -use salvo::oapi::extract::JsonBody; -use salvo::prelude::*; - -use crate::domain::ItemName; -use crate::repos::ItemStore; -use crate::services::{ItemService, create_item_service}; -use crate::views::{CreateItemFailure, CreateItemRequest, CreateItemResponse}; - -/// Create a new item -#[endpoint( - tags("Items"), - summary = "Create a new item", - responses( - (status_code = 200, description = "Item created successfully", body = CreateItemResponse), - (status_code = 400, description = "Invalid request", body = CreateItemFailure), - (status_code = 500, description = "Internal server error", body = CreateItemFailure), - ) -)] -pub async fn create_item( - depot: &mut Depot, - body: JsonBody, -) -> Json> { - // Get the store from depot (injected by ItemStoreMiddleware) - let store = match depot.obtain::>() { - Ok(store) => store.clone(), - Err(_) => { - return Json(Err(CreateItemFailure::Internal( - "Store not available".to_string(), - ))); - } - }; - - // Validate and create the name - let name = match ItemName::try_new(&body.name) { - Ok(name) => name, - Err(_) => { - return Json(Err(CreateItemFailure::InvalidRequest( - "Invalid name: must be 1-255 characters".to_string(), - ))); - } - }; - - // Create the item using the service - let service = create_item_service(store); - match service.create_item(name, body.description.clone()).await { - Ok(metadata) => Json(Ok(CreateItemResponse::from(metadata))), - Err(_) => Json(Err(CreateItemFailure::Internal( - "Failed to create item".to_string(), - ))), - } -} diff --git a/src/controllers/items/delete.rs b/src/controllers/items/delete.rs deleted file mode 100644 index e039383..0000000 --- a/src/controllers/items/delete.rs +++ /dev/null @@ -1,62 +0,0 @@ -use std::sync::Arc; - -use salvo::prelude::*; - -use crate::domain::ItemId; -use crate::repos::ItemStore; -use crate::services::{ItemService, create_item_service}; -use crate::views::{DeleteItemFailure, DeleteItemResponse}; - -/// Delete an item -#[endpoint( - tags("Items"), - summary = "Delete an item", - parameters( - ("item_id" = String, Path, description = "The item's unique identifier (UUID)") - ), - responses( - (status_code = 200, description = "Item deleted successfully", body = DeleteItemResponse), - (status_code = 400, description = "Invalid item ID", body = DeleteItemFailure), - (status_code = 500, description = "Internal server error", body = DeleteItemFailure), - ) -)] -pub async fn delete_item( - req: &mut Request, - depot: &mut Depot, -) -> Json> { - // Parse the item_id from path - let item_id: ItemId = match req.param::("item_id") { - Some(id_str) => match id_str.parse() { - Ok(id) => id, - Err(_) => { - return Json(Err(DeleteItemFailure::InvalidParameter( - "Invalid item ID format".to_string(), - ))); - } - }, - None => { - return Json(Err(DeleteItemFailure::InvalidParameter( - "Missing item ID".to_string(), - ))); - } - }; - - // Get the store from depot (injected by ItemStoreMiddleware) - let store = match depot.obtain::>() { - Ok(store) => store.clone(), - Err(_) => { - return Json(Err(DeleteItemFailure::Internal( - "Store not available".to_string(), - ))); - } - }; - - // Delete the item using the service - let service = create_item_service(store); - match service.delete_item(item_id).await { - Ok(()) => Json(Ok(DeleteItemResponse::new())), - Err(_) => Json(Err(DeleteItemFailure::Internal( - "Failed to delete item".to_string(), - ))), - } -} diff --git a/src/controllers/items/list.rs b/src/controllers/items/list.rs deleted file mode 100644 index e52c073..0000000 --- a/src/controllers/items/list.rs +++ /dev/null @@ -1,37 +0,0 @@ -use std::sync::Arc; - -use salvo::prelude::*; - -use crate::repos::ItemStore; -use crate::services::{ItemService, create_item_service}; -use crate::views::{ListItemsFailure, ListItemsResponse}; - -/// List all items -#[endpoint( - tags("Items"), - summary = "List all items", - responses( - (status_code = 200, description = "List of items", body = ListItemsResponse), - (status_code = 500, description = "Internal server error", body = ListItemsFailure), - ) -)] -pub async fn list_items(depot: &mut Depot) -> Json> { - // Get the store from depot (injected by ItemStoreMiddleware) - let store = match depot.obtain::>() { - Ok(store) => store.clone(), - Err(_) => { - return Json(Err(ListItemsFailure::Internal( - "Store not available".to_string(), - ))); - } - }; - - // List items using the service - let service = create_item_service(store); - match service.list_items().await { - Ok(items) => Json(Ok(ListItemsResponse::new(items))), - Err(_) => Json(Err(ListItemsFailure::Internal( - "Failed to list items".to_string(), - ))), - } -} diff --git a/src/controllers/items/mod.rs b/src/controllers/items/mod.rs deleted file mode 100644 index 5fc22c1..0000000 --- a/src/controllers/items/mod.rs +++ /dev/null @@ -1,26 +0,0 @@ -use salvo::prelude::*; - -pub use create::create_item; -pub use delete::delete_item; -pub use list::list_items; -pub use read::get_item; -pub use update::update_item; - -mod create; -mod delete; -mod list; -mod read; -mod update; - -/// Items controller - provides CRUD operations for items -pub fn items_controller() -> Router { - Router::with_path("items") - .get(list_items) - .post(create_item) - .push( - Router::with_path("{item_id}") - .get(get_item) - .patch(update_item) - .delete(delete_item), - ) -} diff --git a/src/controllers/items/read.rs b/src/controllers/items/read.rs deleted file mode 100644 index 38a4a27..0000000 --- a/src/controllers/items/read.rs +++ /dev/null @@ -1,66 +0,0 @@ -use std::sync::Arc; - -use salvo::prelude::*; - -use crate::domain::ItemId; -use crate::repos::ItemStore; -use crate::services::{ItemService, create_item_service, items::ServiceError}; -use crate::views::{ReadItemFailure, ReadItemResponse}; - -/// Get a single item by ID -#[endpoint( - tags("Items"), - summary = "Get an item by ID", - parameters( - ("item_id" = String, Path, description = "The item's unique identifier (UUID)") - ), - responses( - (status_code = 200, description = "Item details", body = ReadItemResponse), - (status_code = 400, description = "Invalid item ID", body = ReadItemFailure), - (status_code = 404, description = "Item not found", body = ReadItemFailure), - (status_code = 500, description = "Internal server error", body = ReadItemFailure), - ) -)] -pub async fn get_item( - req: &mut Request, - depot: &mut Depot, -) -> Json> { - // Parse the item_id from path - let item_id: ItemId = match req.param::("item_id") { - Some(id_str) => match id_str.parse() { - Ok(id) => id, - Err(_) => { - return Json(Err(ReadItemFailure::InvalidParameter( - "Invalid item ID format".to_string(), - ))); - } - }, - None => { - return Json(Err(ReadItemFailure::InvalidParameter( - "Missing item ID".to_string(), - ))); - } - }; - - // Get the store from depot (injected by ItemStoreMiddleware) - let store = match depot.obtain::>() { - Ok(store) => store.clone(), - Err(_) => { - return Json(Err(ReadItemFailure::Internal( - "Store not available".to_string(), - ))); - } - }; - - // Get the item using the service - let service = create_item_service(store); - match service.get_item(item_id).await { - Ok(metadata) => Json(Ok(ReadItemResponse::from(metadata))), - Err(ServiceError::NotFound) => { - Json(Err(ReadItemFailure::NotFound("Item not found".to_string()))) - } - Err(_) => Json(Err(ReadItemFailure::Internal( - "Failed to get item".to_string(), - ))), - } -} diff --git a/src/controllers/items/update.rs b/src/controllers/items/update.rs deleted file mode 100644 index 38d58e6..0000000 --- a/src/controllers/items/update.rs +++ /dev/null @@ -1,84 +0,0 @@ -use std::sync::Arc; - -use salvo::oapi::extract::JsonBody; -use salvo::prelude::*; - -use crate::domain::{ItemId, ItemName}; -use crate::repos::ItemStore; -use crate::services::{ItemService, create_item_service, items::ServiceError}; -use crate::views::{UpdateItemFailure, UpdateItemRequest, UpdateItemResponse}; - -/// Update an item -#[endpoint( - tags("Items"), - summary = "Update an item", - parameters( - ("item_id" = String, Path, description = "The item's unique identifier (UUID)") - ), - responses( - (status_code = 200, description = "Item updated successfully", body = UpdateItemResponse), - (status_code = 400, description = "Invalid request", body = UpdateItemFailure), - (status_code = 404, description = "Item not found", body = UpdateItemFailure), - (status_code = 500, description = "Internal server error", body = UpdateItemFailure), - ) -)] -pub async fn update_item( - req: &mut Request, - depot: &mut Depot, - body: JsonBody, -) -> Json> { - // Parse the item_id from path - let item_id: ItemId = match req.param::("item_id") { - Some(id_str) => match id_str.parse() { - Ok(id) => id, - Err(_) => { - return Json(Err(UpdateItemFailure::InvalidParameter( - "Invalid item ID format".to_string(), - ))); - } - }, - None => { - return Json(Err(UpdateItemFailure::InvalidParameter( - "Missing item ID".to_string(), - ))); - } - }; - - // Validate name if provided - let name = match &body.name { - Some(name_str) => match ItemName::try_new(name_str) { - Ok(name) => Some(name), - Err(_) => { - return Json(Err(UpdateItemFailure::InvalidRequest( - "Invalid name: must be 1-255 characters".to_string(), - ))); - } - }, - None => None, - }; - - // Get the store from depot (injected by ItemStoreMiddleware) - let store = match depot.obtain::>() { - Ok(store) => store.clone(), - Err(_) => { - return Json(Err(UpdateItemFailure::Internal( - "Store not available".to_string(), - ))); - } - }; - - // Update the item using the service - let service = create_item_service(store); - match service - .update_item(item_id, name, body.description.clone()) - .await - { - Ok(metadata) => Json(Ok(UpdateItemResponse::from(metadata))), - Err(ServiceError::NotFound) => Json(Err(UpdateItemFailure::NotFound( - "Item not found".to_string(), - ))), - Err(_) => Json(Err(UpdateItemFailure::Internal( - "Failed to update item".to_string(), - ))), - } -} diff --git a/src/controllers/mod.rs b/src/controllers/mod.rs deleted file mode 100644 index c92f9e0..0000000 --- a/src/controllers/mod.rs +++ /dev/null @@ -1,93 +0,0 @@ -use salvo::cors::{AllowHeaders, AllowMethods, Cors}; -use salvo::http::Method; -use salvo::otel::Metrics; -use salvo::prelude::*; -use serde::Serialize; - -use crate::cli::CorsConfig; -use crate::middleware::{ - metrics::metrics_middleware, otel_http::OtelHttpMiddleware, stores::item_store_middleware, - transaction_middleware, -}; - -pub mod items; - -#[derive(Serialize, salvo::oapi::ToSchema)] -struct HeartbeatResponse { - ok: String, -} - -#[endpoint(tags("Health"), summary = "Health check endpoint")] -async fn heartbeat() -> Json { - Json(HeartbeatResponse { - ok: "true".to_string(), - }) -} - -/// Creates CORS middleware from configuration. -/// Allows all standard HTTP methods used by REST APIs. -/// For local development, automatically includes localhost origins. -fn create_cors_middleware(config: &CorsConfig) -> impl salvo::Handler { - let origins = config.get_allowed_origins(); - - tracing::info!("Configuring CORS with allowed origins: {:?}", origins); - - if !config.is_safe() { - tracing::warn!( - "UNSAFE CORS CONFIGURATION: Wildcard '*' origin detected. \ - This should NEVER be used in production as it exposes the API to CSRF attacks." - ); - } - - // Convert Vec to Vec<&str> for Salvo API - let origin_refs: Vec<&str> = origins.iter().map(|s| s.as_str()).collect(); - - let mut cors = Cors::new() - .allow_origin(origin_refs) - .allow_methods(AllowMethods::list([ - Method::GET, - Method::POST, - Method::PUT, - Method::PATCH, - Method::DELETE, - Method::OPTIONS, - ])) - .allow_headers(AllowHeaders::any()) - .max_age(config.max_age); - - if config.allow_credentials { - tracing::info!("CORS: Allowing credentials (cookies, authorization headers)"); - cors = cors.allow_credentials(true); - } - - cors.into_handler() -} - -/// Creates a minimal router for OpenAPI schema generation only. -/// Does not include middleware that requires database connections or tracing. -pub fn schema_router() -> Router { - Router::new() - .push(Router::with_path("heartbeat").get(heartbeat)) - .push(items::items_controller()) -} - -pub fn root(cors_config: &CorsConfig) -> Router { - let router = Router::new() - .hoop(OtelHttpMiddleware::new()) - .hoop(create_cors_middleware(cors_config)) - .hoop(Metrics::new()) - .hoop(metrics_middleware()) - .hoop(transaction_middleware()) - .hoop(item_store_middleware()) - .push(Router::with_path("heartbeat").get(heartbeat)) - .push(items::items_controller()); - - let mut doc = OpenApi::new(env!("CARGO_PKG_NAME"), env!("CARGO_PKG_VERSION")); - doc.info.description = Some("API service".to_string()); - doc.info.license = Some(salvo::oapi::License::new("MIT")); - doc = doc.merge_router(&router); - - router - .unshift(doc.into_router("/api-doc/openapi.json")) - .unshift(Scalar::new("/api-doc/openapi.json").into_router("scalar")) -} diff --git a/src/domain/errors/db.rs b/src/domain/errors/db.rs deleted file mode 100644 index a0757e4..0000000 --- a/src/domain/errors/db.rs +++ /dev/null @@ -1,32 +0,0 @@ -use super::{InternalError, NotFound}; -use sea_orm::DbErr; - -/// Certain database errors are expected, while -/// others are not. Namely, sometimes you can query for an -/// object without knowing if it exists. But most other errors -/// are unexpected, and should probably result in a 500. -#[derive(Debug, thiserror::Error)] -pub enum DatabaseError { - #[error("The requested object was not found.")] - NotFound(NotFound), - #[error("An unexpected error occurred when querying the database: {0}")] - Unexpected(DbErr), -} - -impl From for DatabaseError { - fn from(err: DbErr) -> Self { - match err { - DbErr::RecordNotFound(_) => Self::NotFound(NotFound::new(err.into())), - e => Self::Unexpected(e), - } - } -} - -/// DatabaseErrors can be converted into InternalErrors. -/// This is useful when _any_ error returned from the database -/// is unexpected. -impl From for InternalError { - fn from(value: DatabaseError) -> Self { - Self::new(value.into()) - } -} diff --git a/src/domain/errors/forbidden.rs b/src/domain/errors/forbidden.rs deleted file mode 100644 index a2b3c4c..0000000 --- a/src/domain/errors/forbidden.rs +++ /dev/null @@ -1,43 +0,0 @@ -use std::fmt::Debug; -use thiserror::Error; - -#[derive(Error)] -#[error("The user is forbidden from performing this action")] -pub struct Forbidden(#[from] anyhow::Error); - -impl Debug for Forbidden { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}: {}", self, self.0) - } -} - -impl Forbidden { - pub fn new(err: anyhow::Error) -> Self { - Self(err) - } -} - -#[cfg(test)] -mod tests { - use super::Forbidden; - use anyhow::anyhow; - use pretty_assertions::assert_str_eq; - - /// Demonstrate the Forbidden error renders in display format correctly. - #[test] - fn forbidden_renders_fmt() { - let err = Forbidden::new(anyhow!("bad token")); - let expected = "The user is forbidden from performing this action"; - let observed = err.to_string(); - assert_str_eq!(expected, observed); - } - - /// Demonstrate the Forbidden error renders in debug format correctly. - #[test] - fn forbidden_renders_debug() { - let err = Forbidden::new(anyhow!("bad token")); - let expected = "The user is forbidden from performing this action: bad token"; - let observed = format!("{err:?}"); - assert_str_eq!(expected, observed); - } -} diff --git a/src/domain/errors/internal.rs b/src/domain/errors/internal.rs deleted file mode 100644 index e83d5d1..0000000 --- a/src/domain/errors/internal.rs +++ /dev/null @@ -1,49 +0,0 @@ -use std::fmt::Debug; -use thiserror::Error; - -#[derive(Error)] -#[error("An internal server error has occurred")] -pub struct InternalError(#[from] anyhow::Error); - -impl Debug for InternalError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}: {}", self, self.0) - } -} - -impl InternalError { - pub fn new(err: anyhow::Error) -> Self { - Self(err) - } -} - -impl Drop for InternalError { - fn drop(&mut self) { - tracing::error!(msg = %self.0, "internal error"); - } -} - -#[cfg(test)] -mod tests { - use crate::domain::InternalError; - use anyhow::anyhow; - use pretty_assertions::assert_str_eq; - - /// Demonstrate the Forbidden error renders in display format correctly. - #[test] - fn internal_error_renders_fmt() { - let err = InternalError::new(anyhow!("bad token")); - let expected = "An internal server error has occurred"; - let observed = err.to_string(); - assert_str_eq!(expected, observed); - } - - /// Demonstrate the Forbidden error renders in debug format correctly. - #[test] - fn internal_error_renders_debug() { - let err = InternalError::new(anyhow!("bad token")); - let expected = "An internal server error has occurred: bad token"; - let observed = format!("{err:?}"); - assert_str_eq!(expected, observed); - } -} diff --git a/src/domain/errors/mod.rs b/src/domain/errors/mod.rs deleted file mode 100644 index 85e3dfe..0000000 --- a/src/domain/errors/mod.rs +++ /dev/null @@ -1,10 +0,0 @@ -pub use db::DatabaseError; -pub use forbidden::Forbidden; -pub use internal::InternalError; -pub use not_found::NotFound; - -mod db; -mod forbidden; -mod internal; -mod not_found; -mod unauthorized; diff --git a/src/domain/errors/not_found.rs b/src/domain/errors/not_found.rs deleted file mode 100644 index b10e989..0000000 --- a/src/domain/errors/not_found.rs +++ /dev/null @@ -1,61 +0,0 @@ -use std::fmt::Debug; - -#[allow(deprecated)] -use super::forbidden::Forbidden; - -#[derive(thiserror::Error)] -#[error("The requested object or path was not found")] -pub struct NotFound(#[from] anyhow::Error); - -impl Debug for NotFound { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}: {}", self, self.0) - } -} - -/// When users aren't authorized to perform an action, we create -/// a Forbidden error, per HTTP's specification. However, we usually -/// want to return a 404 instead so as not to leak private information -/// about a resource this user doesn't have access to. This type -/// convertion makes it easy to return a 404 while still -/// tracking the providence of errors. -#[allow(deprecated)] -impl From for NotFound { - fn from(err: Forbidden) -> Self { - Self::from(anyhow::Error::from(err)) - } -} - -impl NotFound { - pub fn new(err: anyhow::Error) -> Self { - Self(err) - } -} - -#[cfg(test)] -mod tests { - use super::NotFound; - use anyhow::anyhow; - use pretty_assertions::assert_str_eq; - - /// Demonstrate the Forbidden error renders in display format correctly. - #[test] - fn not_found_renders_fmt() { - let err = NotFound::new(anyhow!("no such user")); - let expected = "The requested object or path was not found"; - let observed = err.to_string(); - assert_str_eq!(expected, observed); - } - - /// Demonstrate the Forbidden error renders in debug format correctly. - #[test] - fn not_found_renders_debug() { - let err = NotFound::new(anyhow!("no such user")); - println!("What the fuck is happening"); - let expected = "The requested object or path was not found: no such user"; - let observed = format!("{err:?}"); - println!("Here's my observed error:"); - println!("{observed:?}"); - assert_str_eq!(expected, observed); - } -} diff --git a/src/domain/errors/unauthorized.rs b/src/domain/errors/unauthorized.rs deleted file mode 100644 index 666a6a6..0000000 --- a/src/domain/errors/unauthorized.rs +++ /dev/null @@ -1,47 +0,0 @@ -#![allow(deprecated)] - -use std::fmt::Debug; - -#[allow(unused)] -#[deprecated = "Only the middleware should return this status code."] -#[derive(thiserror::Error)] -#[error("The user is not authorized to perform this action")] -pub struct NotAuthorized(#[from] anyhow::Error); - -impl NotAuthorized { - #[cfg(test)] - pub fn new(err: anyhow::Error) -> Self { - Self(err) - } -} - -impl Debug for NotAuthorized { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}: {}", self, self.0) - } -} - -#[cfg(test)] -mod tests { - use super::NotAuthorized; - use anyhow::anyhow; - use pretty_assertions::assert_str_eq; - - /// Demonstrate the Forbidden error renders in display format correctly. - #[test] - fn not_authorized_renders_fmt() { - let err = NotAuthorized::new(anyhow!("bad token")); - let expected = "The user is not authorized to perform this action"; - let observed = err.to_string(); - assert_str_eq!(expected, observed); - } - - /// Demonstrate the Forbidden error renders in debug format correctly. - #[test] - fn not_authorized_renders_debug() { - let err = NotAuthorized::new(anyhow!("bad token")); - let expected = "The user is not authorized to perform this action: bad token"; - let observed = format!("{err:?}"); - assert_str_eq!(expected, observed); - } -} diff --git a/src/domain/items/id.rs b/src/domain/items/id.rs deleted file mode 100644 index 6b7d5bb..0000000 --- a/src/domain/items/id.rs +++ /dev/null @@ -1,55 +0,0 @@ -use nutype::nutype; -use uuid::Uuid; - -/// Unique identifier for an Item. -/// -/// This is the public-facing ID (UUID) used in API responses. -#[nutype( - derive( - Clone, - Copy, - Debug, - PartialEq, - Eq, - Hash, - Serialize, - Deserialize, - Display, - FromStr, - AsRef - ), - new_unchecked -)] -pub struct ItemId(Uuid); - -impl ItemId { - /// Creates a new random ItemId - pub fn random() -> Self { - Self::new(Uuid::new_v4()) - } -} - -impl Default for ItemId { - fn default() -> Self { - Self::random() - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_item_id_creation() { - let id = ItemId::random(); - let id_str = id.to_string(); - assert!(!id_str.is_empty()); - } - - #[test] - fn test_item_id_from_str() { - let uuid_str = "550e8400-e29b-41d4-a716-446655440000"; - let id: ItemId = uuid_str.parse().unwrap(); - assert_eq!(id.to_string(), uuid_str); - } -} diff --git a/src/domain/items/metadata.rs b/src/domain/items/metadata.rs deleted file mode 100644 index 84577b4..0000000 --- a/src/domain/items/metadata.rs +++ /dev/null @@ -1,61 +0,0 @@ -use chrono::{DateTime, Utc}; -use serde::Serialize; - -use super::{ItemId, ItemName}; - -/// Public metadata for an Item. -/// -/// This struct contains all the information about an item that can be -/// safely exposed through the API. -#[derive(Clone, Debug, Serialize)] -pub struct ItemMetadata { - /// The unique identifier for the item - pub id: ItemId, - /// The display name of the item - pub name: ItemName, - /// Optional description of the item - pub description: Option, - /// When the item was created - pub created_at: DateTime, - /// When the item was last updated - pub updated_at: DateTime, -} - -impl ItemMetadata { - /// Creates a new ItemMetadata instance - pub fn new( - id: ItemId, - name: ItemName, - description: Option, - created_at: DateTime, - updated_at: DateTime, - ) -> Self { - Self { - id, - name, - description, - created_at, - updated_at, - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_metadata_creation() { - let now = Utc::now(); - let metadata = ItemMetadata::new( - ItemId::random(), - ItemName::try_new("Test Item").unwrap(), - Some("A test description".to_string()), - now, - now, - ); - - assert_eq!(metadata.name.as_ref(), "Test Item"); - assert_eq!(metadata.description, Some("A test description".to_string())); - } -} diff --git a/src/domain/items/mod.rs b/src/domain/items/mod.rs deleted file mode 100644 index 8993c22..0000000 --- a/src/domain/items/mod.rs +++ /dev/null @@ -1,7 +0,0 @@ -pub use id::ItemId; -pub use metadata::ItemMetadata; -pub use name::ItemName; - -mod id; -mod metadata; -mod name; diff --git a/src/domain/items/name.rs b/src/domain/items/name.rs deleted file mode 100644 index f2337f1..0000000 --- a/src/domain/items/name.rs +++ /dev/null @@ -1,57 +0,0 @@ -use nutype::nutype; - -/// Display name for an Item. -/// -/// Must be between 1 and 255 characters, trimmed of whitespace. -#[nutype( - sanitize(trim), - validate(not_empty, len_char_max = 255), - derive( - Clone, - Debug, - PartialEq, - Eq, - Hash, - Serialize, - Deserialize, - Display, - AsRef - ) -)] -pub struct ItemName(String); - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_valid_name() { - let name = ItemName::try_new("My Item").unwrap(); - assert_eq!(name.as_ref(), "My Item"); - } - - #[test] - fn test_trimmed_name() { - let name = ItemName::try_new(" My Item ").unwrap(); - assert_eq!(name.as_ref(), "My Item"); - } - - #[test] - fn test_empty_name_rejected() { - let result = ItemName::try_new(""); - assert!(result.is_err()); - } - - #[test] - fn test_whitespace_only_rejected() { - let result = ItemName::try_new(" "); - assert!(result.is_err()); - } - - #[test] - fn test_too_long_name_rejected() { - let long_name = "a".repeat(256); - let result = ItemName::try_new(long_name); - assert!(result.is_err()); - } -} diff --git a/src/domain/mod.rs b/src/domain/mod.rs deleted file mode 100644 index 769ed03..0000000 --- a/src/domain/mod.rs +++ /dev/null @@ -1,5 +0,0 @@ -pub use errors::*; -pub use items::*; - -mod errors; -mod items; diff --git a/src/lib.rs b/src/lib.rs deleted file mode 100644 index a2cfeff..0000000 --- a/src/lib.rs +++ /dev/null @@ -1,9 +0,0 @@ -pub mod cli; -pub mod controllers; -pub mod domain; -pub mod middleware; -pub mod models; -pub mod repos; -pub mod services; -pub mod utils; -pub mod views; diff --git a/src/middleware/error_catcher.rs b/src/middleware/error_catcher.rs deleted file mode 100644 index b7ea7f2..0000000 --- a/src/middleware/error_catcher.rs +++ /dev/null @@ -1,109 +0,0 @@ -//! JSON error catcher for framework-level error responses. -//! -//! Salvo's default `DefaultGoal` produces HTML (or JSON / XML / plain text, -//! depending on the `Accept` header) when an extractor fails or when no -//! handler writes a body for an error status. Our API clients expect a -//! consistent JSON envelope, so this catcher hoop intercepts error responses -//! and rewrites them as: -//! -//! ```json -//! { "error": "BadRequest", "message": "Invalid request parameters" } -//! ``` -//! -//! To use it, register it on the `Service`: -//! -//! ```ignore -//! Service::new(router).catcher(Catcher::default().hoop(JsonErrorCatcher)); -//! ``` - -use salvo::async_trait; -use salvo::http::{ResBody, header}; -use salvo::prelude::*; -use serde::Serialize; - -/// A `Catcher` hoop that serializes framework-level error responses as JSON. -/// -/// Runs before Salvo's `DefaultGoal` so that any `ResBody::Error(StatusError)` -/// (produced, for example, by `PathParam` or `JsonBody` extractors) is -/// replaced with a flat JSON envelope and the content-type is set to -/// `application/json`. -pub struct JsonErrorCatcher; - -#[derive(Serialize)] -struct JsonErrorEnvelope<'a> { - error: &'a str, - message: String, -} - -#[async_trait] -impl Handler for JsonErrorCatcher { - async fn handle( - &self, - _req: &mut Request, - _depot: &mut Depot, - res: &mut Response, - ctrl: &mut FlowCtrl, - ) { - let Some(status) = res.status_code else { - return; - }; - if !(status.is_client_error() || status.is_server_error()) { - return; - } - - // Only rewrite when Salvo has produced an error body. Handlers that - // write their own response bodies (e.g. `Json>` from our - // view layer) are left alone. - let ResBody::Error(status_error) = &res.body else { - return; - }; - - let envelope = JsonErrorEnvelope { - error: status_name_to_code(status), - message: message_for(status, &status_error.brief), - }; - - let Ok(body) = serde_json::to_string(&envelope) else { - return; - }; - - res.headers_mut().insert( - header::CONTENT_TYPE, - "application/json" - .parse() - .expect("content-type header value should parse"), - ); - let _ = res.write_body(body); - ctrl.skip_rest(); - } -} - -/// Maps an HTTP status code to the PascalCase `error` tag used in our -/// JSON error envelope. Kept in sync with the variants produced by our -/// view-layer `*Failure` enums. -fn status_name_to_code(status: StatusCode) -> &'static str { - match status { - StatusCode::BAD_REQUEST => "BadRequest", - StatusCode::UNAUTHORIZED => "Unauthorized", - StatusCode::FORBIDDEN => "Forbidden", - StatusCode::NOT_FOUND => "NotFound", - StatusCode::CONFLICT => "Conflict", - StatusCode::UNPROCESSABLE_ENTITY => "UnprocessableEntity", - StatusCode::INTERNAL_SERVER_ERROR => "InternalServerError", - _ => "Error", - } -} - -/// Customize the human-readable message that accompanies a framework-level -/// error. Salvo's extractors emit `brief = "parse http data failed."` for -/// any parse failure, which is too generic for API clients; we rewrite it -/// to `"Invalid request parameters"`. Edit this function to add more -/// mappings as needed. -fn message_for(status: StatusCode, brief: &str) -> String { - match status { - StatusCode::BAD_REQUEST if brief == "parse http data failed." => { - "Invalid request parameters".to_string() - } - _ => brief.to_string(), - } -} diff --git a/src/middleware/metrics.rs b/src/middleware/metrics.rs deleted file mode 100644 index 7283f4b..0000000 --- a/src/middleware/metrics.rs +++ /dev/null @@ -1,104 +0,0 @@ -use salvo::prelude::*; -use std::collections::HashMap; -use std::sync::Arc; -use std::time::Duration; -use tokio::sync::RwLock; - -/// Histogram for collecting HTTP status codes -#[derive(Clone)] -pub struct StatusCodeHistogram { - /// The histogram data - data: Arc>>, -} - -impl Default for StatusCodeHistogram { - fn default() -> Self { - Self::new() - } -} - -impl StatusCodeHistogram { - pub fn new() -> Self { - Self { - data: Arc::new(RwLock::new(HashMap::new())), - } - } - - /// Increment the count for a given status code - pub async fn increment(&self, status_code: u16) { - let mut data = self.data.write().await; - *data.entry(status_code).or_insert(0) += 1; - } - - /// Take the current histogram data and reset it (delta temporality) - pub async fn take_snapshot(&self) -> HashMap { - let mut data = self.data.write().await; - std::mem::take(&mut *data) - } -} - -/// Middleware for collecting HTTP status code metrics -pub struct MetricsMiddleware { - histogram: StatusCodeHistogram, -} - -impl Default for MetricsMiddleware { - fn default() -> Self { - Self::new() - } -} - -impl MetricsMiddleware { - pub fn new() -> Self { - let histogram = StatusCodeHistogram::new(); - - // Spawn a background task to emit metrics every minute - let histogram_clone = histogram.clone(); - tokio::spawn(async move { - let mut interval = tokio::time::interval(Duration::from_secs(60)); - loop { - interval.tick().await; - let snapshot = histogram_clone.take_snapshot().await; - - if !snapshot.is_empty() { - tracing::info!("HTTP Status Code Metrics (delta): {:?}", snapshot); - - // Emit individual metrics for each status code - for (status_code, count) in snapshot { - tracing::info!( - status_code = status_code, - count = count, - "HTTP status code count" - ); - } - } - } - }); - - Self { histogram } - } -} - -#[async_trait] -impl Handler for MetricsMiddleware { - async fn handle( - &self, - req: &mut Request, - depot: &mut Depot, - res: &mut Response, - ctrl: &mut FlowCtrl, - ) { - // Continue processing the request - ctrl.call_next(req, depot, res).await; - - // After the request is processed, collect the status code - if let Some(status_code) = res.status_code { - self.histogram.increment(status_code.as_u16()).await; - } - } -} - -/// Create a new metrics middleware instance -pub fn metrics_middleware() -> MetricsMiddleware { - MetricsMiddleware::new() -} diff --git a/src/middleware/mocks.rs b/src/middleware/mocks.rs deleted file mode 100644 index 210e580..0000000 --- a/src/middleware/mocks.rs +++ /dev/null @@ -1,30 +0,0 @@ -use std::sync::Arc; - -use salvo::prelude::*; - -use crate::repos::{ItemStore, items::mocks::MockItemStore}; - -pub struct ItemStoreMockMiddleware; - -#[async_trait] -impl Handler for ItemStoreMockMiddleware { - async fn handle( - &self, - req: &mut Request, - depot: &mut Depot, - res: &mut Response, - ctrl: &mut FlowCtrl, - ) { - // Inject as Arc to match what the items controllers obtain - // (depot.obtain::>()) and the production - // ItemStoreMiddleware. Injecting a Box here would not be found by the - // controllers' Arc lookup, leaving routes unable to resolve the store. - let store: Arc = Arc::new(MockItemStore::new()); - depot.inject(store); - ctrl.call_next(req, depot, res).await; - } -} - -pub fn item_store_mock_middleware() -> ItemStoreMockMiddleware { - ItemStoreMockMiddleware -} diff --git a/src/middleware/mod.rs b/src/middleware/mod.rs deleted file mode 100644 index 30af254..0000000 --- a/src/middleware/mod.rs +++ /dev/null @@ -1,85 +0,0 @@ -use salvo::prelude::*; -use sea_orm::TransactionTrait; - -use crate::repos::{Transaction, TransactionError}; - -pub mod error_catcher; -pub mod metrics; -pub mod mocks; -pub mod otel_http; -pub mod stores; - -pub use error_catcher::JsonErrorCatcher; - -pub struct TransactionMiddleware; - -#[async_trait] -impl Handler for TransactionMiddleware { - async fn handle( - &self, - req: &mut Request, - depot: &mut Depot, - res: &mut Response, - ctrl: &mut FlowCtrl, - ) { - let pool = crate::utils::db::pool(); - - match pool.begin().await { - Ok(db_txn) => { - let transaction = Transaction::new(db_txn); - depot.inject(transaction.clone()); - - ctrl.call_next(req, depot, res).await; - - // Retrieve the transaction and attempt to commit or rollback - if let Ok(txn_wrapper) = depot.obtain::() { - // Check if transaction is still available (not consumed by handlers) - if txn_wrapper.is_available().await { - // Consume the transaction to get the underlying DatabaseTransaction - match txn_wrapper.clone().into_inner().await { - Ok(db_txn) => { - if res - .status_code - .unwrap_or(StatusCode::INTERNAL_SERVER_ERROR) - .is_success() - { - if let Err(e) = db_txn.commit().await { - tracing::error!("Failed to commit transaction: {}", e); - res.status_code(StatusCode::INTERNAL_SERVER_ERROR); - } - } else { - if let Err(e) = db_txn.rollback().await { - tracing::error!("Failed to rollback transaction: {}", e); - } - } - } - Err(TransactionError::TransactionConsumed) => { - tracing::warn!("Transaction was already consumed by handlers"); - // This is actually fine - handlers may have committed/rolled back manually - } - Err(e) => { - tracing::error!("Failed to extract transaction: {:?}", e); - res.status_code(StatusCode::INTERNAL_SERVER_ERROR); - } - } - } else { - tracing::debug!("Transaction was consumed during request processing"); - } - } else { - tracing::warn!("Transaction not found in depot"); - } - } - Err(e) => { - tracing::error!("Failed to begin transaction: {}", e); - res.status_code(StatusCode::INTERNAL_SERVER_ERROR); - } - } - } -} - -pub fn transaction_middleware() -> TransactionMiddleware { - TransactionMiddleware -} - -// Services will be created on-demand from the Transaction in the depot -// Controllers will create their own service instances as needed diff --git a/src/middleware/otel_http.rs b/src/middleware/otel_http.rs deleted file mode 100644 index 55f73ac..0000000 --- a/src/middleware/otel_http.rs +++ /dev/null @@ -1,122 +0,0 @@ -use std::time::Instant; - -use opentelemetry::trace::{Span, SpanKind, Status, Tracer}; -use opentelemetry::{KeyValue, global}; -use salvo::prelude::*; - -/// Custom OpenTelemetry HTTP middleware that produces spans conforming to the -/// [OTel HTTP Semantic Conventions](https://opentelemetry.io/docs/specs/semconv/http/http-spans/). -/// -/// This replaces Salvo's built-in `Logger` middleware which produces non-compliant spans: -/// - Uses `SPAN_KIND_SERVER` (kind=2) instead of `SPAN_KIND_INTERNAL` -/// - Sets `http.response.status_code` as an integer attribute instead of event string -/// - Uses namespaced attribute keys (`http.request.method`, `url.full`, etc.) -pub struct OtelHttpMiddleware; - -impl Default for OtelHttpMiddleware { - fn default() -> Self { - Self::new() - } -} - -impl OtelHttpMiddleware { - pub fn new() -> Self { - Self - } -} - -/// Extract the peer IP address from Salvo's remote address. -/// -/// Salvo formats remote addresses as `socket://IP:PORT`. This extracts just the IP portion -/// to conform to the `network.peer.address` semantic convention. -fn extract_peer_address(req: &Request) -> String { - let s = req.remote_addr().to_string(); - // Format is typically "socket://IP:PORT" - let without_prefix = s.strip_prefix("socket://").unwrap_or(&s); - without_prefix - .rsplit_once(':') - .map(|(ip, _port): (&str, &str)| ip.to_string()) - .unwrap_or_else(|| without_prefix.to_string()) -} - -/// Map HTTP version to the OTel `network.protocol.version` format. -fn format_protocol_version(version: salvo::http::Version) -> &'static str { - match version { - salvo::http::Version::HTTP_09 => "0.9", - salvo::http::Version::HTTP_10 => "1.0", - salvo::http::Version::HTTP_11 => "1.1", - salvo::http::Version::HTTP_2 => "2", - salvo::http::Version::HTTP_3 => "3", - _ => "unknown", - } -} - -#[async_trait] -impl Handler for OtelHttpMiddleware { - async fn handle( - &self, - req: &mut Request, - depot: &mut Depot, - res: &mut Response, - ctrl: &mut FlowCtrl, - ) { - let tracer = global::tracer(env!("CARGO_PKG_NAME")); - - let method = req.method().as_str().to_owned(); - let path = req.uri().path().to_owned(); - let full_url = req.uri().to_string(); - let peer_address = extract_peer_address(req); - let protocol_version = format_protocol_version(req.version()); - - // OTel convention: span name is "METHOD /route" - let span_name = format!("{} {}", method, path); - - let mut span = tracer - .span_builder(span_name) - .with_kind(SpanKind::Server) - .with_attributes(vec![ - KeyValue::new("http.request.method", method.clone()), - KeyValue::new("url.full", full_url), - KeyValue::new("http.route", path.clone()), - KeyValue::new("network.peer.address", peer_address.clone()), - KeyValue::new("network.protocol.version", protocol_version), - ]) - .start(&tracer); - - tracing::info!( - method = %method, - path = %path, - peer = %peer_address, - "Request received" - ); - - let start = Instant::now(); - - // Process the request through the rest of the middleware chain - ctrl.call_next(req, depot, res).await; - - // Set response status code as an integer attribute (OTel convention) - let status_code = res.status_code.unwrap_or(StatusCode::OK).as_u16(); - let latency_ms = start.elapsed().as_millis(); - - span.set_attribute(KeyValue::new( - "http.response.status_code", - i64::from(status_code), - )); - - // OTel convention: set span status to Error for 5xx responses - if status_code >= 500 { - span.set_status(Status::error(format!("HTTP {status_code}"))); - } - - tracing::info!( - method = %method, - path = %path, - status = status_code, - latency_ms = latency_ms, - "Response sent" - ); - - span.end(); - } -} diff --git a/src/middleware/stores.rs b/src/middleware/stores.rs deleted file mode 100644 index 9745ad7..0000000 --- a/src/middleware/stores.rs +++ /dev/null @@ -1,41 +0,0 @@ -use std::sync::Arc; - -use salvo::prelude::*; - -use crate::repos::{ItemStore, Transaction}; - -pub struct ItemStoreMiddleware; - -#[async_trait] -impl Handler for ItemStoreMiddleware { - async fn handle( - &self, - req: &mut Request, - depot: &mut Depot, - res: &mut Response, - ctrl: &mut FlowCtrl, - ) { - // Get the injected Transaction from the depot - let transaction = match depot.obtain::() { - Ok(txn) => txn.clone(), - Err(_) => { - tracing::error!( - "Transaction not found in depot - ensure TransactionMiddleware runs before ItemStoreMiddleware" - ); - res.status_code(StatusCode::INTERNAL_SERVER_ERROR); - return; - } - }; - - // Create a concrete database-backed ItemStore using the transaction - // Using Arc allows the store to be cloned cheaply by controllers - let store: Arc = Arc::new(transaction); - depot.inject(store); - - ctrl.call_next(req, depot, res).await; - } -} - -pub fn item_store_middleware() -> ItemStoreMiddleware { - ItemStoreMiddleware -} diff --git a/src/models/items.rs b/src/models/items.rs deleted file mode 100644 index 725d711..0000000 --- a/src/models/items.rs +++ /dev/null @@ -1,23 +0,0 @@ -//! `SeaORM` Entity for items table - -use sea_orm::entity::prelude::*; - -#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] -#[sea_orm(table_name = "items")] -pub struct Model { - #[sea_orm(primary_key)] - pub id: i32, - #[sea_orm(unique)] - pub internal_id: Uuid, - #[sea_orm(column_type = "Text")] - pub name: String, - #[sea_orm(column_type = "Text", nullable)] - pub description: Option, - pub created_at: DateTimeWithTimeZone, - pub updated_at: DateTimeWithTimeZone, -} - -#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] -pub enum Relation {} - -impl ActiveModelBehavior for ActiveModel {} diff --git a/src/models/mod.rs b/src/models/mod.rs deleted file mode 100644 index 0f25c0a..0000000 --- a/src/models/mod.rs +++ /dev/null @@ -1,5 +0,0 @@ -//! SeaORM Entities - -pub mod prelude; - -pub mod items; diff --git a/src/models/prelude.rs b/src/models/prelude.rs deleted file mode 100644 index 0bfc528..0000000 --- a/src/models/prelude.rs +++ /dev/null @@ -1,3 +0,0 @@ -//! SeaORM Entity prelude - -pub use super::items::Entity as Items; diff --git a/src/repos/items/mocks.rs b/src/repos/items/mocks.rs deleted file mode 100644 index 51aa77d..0000000 --- a/src/repos/items/mocks.rs +++ /dev/null @@ -1,175 +0,0 @@ -use std::collections::HashMap; -use std::sync::Arc; - -use chrono::Utc; -use salvo::async_trait; -use tokio::sync::RwLock; - -use super::{DatabaseError, ItemStore}; -use crate::domain::{ItemId, ItemMetadata, ItemName}; - -/// In-memory mock implementation of ItemStore for testing. -pub struct MockItemStore { - items: Arc>>, -} - -impl MockItemStore { - /// Creates a new empty mock store - pub fn new() -> Self { - Self { - items: Arc::new(RwLock::new(HashMap::new())), - } - } - - /// Creates a mock store pre-populated with items - pub fn with_items(items: Vec) -> Self { - let map: HashMap = items.into_iter().map(|i| (i.id, i)).collect(); - Self { - items: Arc::new(RwLock::new(map)), - } - } -} - -impl Default for MockItemStore { - fn default() -> Self { - Self::new() - } -} - -#[async_trait] -impl ItemStore for MockItemStore { - async fn create( - &self, - name: ItemName, - description: Option, - ) -> Result { - let now = Utc::now(); - let metadata = ItemMetadata::new(ItemId::random(), name, description, now, now); - - let mut items = self.items.write().await; - items.insert(metadata.id, metadata.clone()); - - Ok(metadata) - } - - async fn list(&self) -> Result, DatabaseError> { - let items = self.items.read().await; - Ok(items.values().cloned().collect()) - } - - async fn read(&self, id: ItemId) -> Result { - let items = self.items.read().await; - items.get(&id).cloned().ok_or(()) - } - - async fn update( - &self, - id: ItemId, - name: Option, - description: Option>, - ) -> Result { - let mut items = self.items.write().await; - - let item = items.get_mut(&id).ok_or(())?; - - if let Some(new_name) = name { - item.name = new_name; - } - - if let Some(new_description) = description { - item.description = new_description; - } - - item.updated_at = Utc::now(); - - Ok(item.clone()) - } - - async fn delete(&self, id: ItemId) -> Result<(), DatabaseError> { - let mut items = self.items.write().await; - items.remove(&id); - Ok(()) - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[tokio::test] - async fn test_create_and_read() { - let store = MockItemStore::new(); - let name = ItemName::try_new("Test Item").unwrap(); - - let created = store - .create(name.clone(), Some("A description".to_string())) - .await - .unwrap(); - - assert_eq!(created.name.as_ref(), "Test Item"); - assert_eq!(created.description, Some("A description".to_string())); - - let read = store.read(created.id).await.unwrap(); - assert_eq!(read.id, created.id); - assert_eq!(read.name.as_ref(), "Test Item"); - } - - #[tokio::test] - async fn test_list() { - let store = MockItemStore::new(); - - store - .create(ItemName::try_new("Item 1").unwrap(), None) - .await - .unwrap(); - store - .create(ItemName::try_new("Item 2").unwrap(), None) - .await - .unwrap(); - - let items = store.list().await.unwrap(); - assert_eq!(items.len(), 2); - } - - #[tokio::test] - async fn test_update() { - let store = MockItemStore::new(); - let created = store - .create(ItemName::try_new("Original").unwrap(), None) - .await - .unwrap(); - - let updated = store - .update( - created.id, - Some(ItemName::try_new("Updated").unwrap()), - Some(Some("New description".to_string())), - ) - .await - .unwrap(); - - assert_eq!(updated.name.as_ref(), "Updated"); - assert_eq!(updated.description, Some("New description".to_string())); - } - - #[tokio::test] - async fn test_delete() { - let store = MockItemStore::new(); - let created = store - .create(ItemName::try_new("To Delete").unwrap(), None) - .await - .unwrap(); - - store.delete(created.id).await.unwrap(); - - let result = store.read(created.id).await; - assert!(result.is_err()); - } - - #[tokio::test] - async fn test_read_not_found() { - let store = MockItemStore::new(); - let result = store.read(ItemId::random()).await; - assert!(result.is_err()); - } -} diff --git a/src/repos/items/mod.rs b/src/repos/items/mod.rs deleted file mode 100644 index 713ac40..0000000 --- a/src/repos/items/mod.rs +++ /dev/null @@ -1,88 +0,0 @@ -use crate::domain::{ItemId, ItemMetadata, ItemName}; -use salvo::async_trait; - -pub mod mocks; -pub mod seaorm; - -/// Error type for database operations -pub type DatabaseError = (); - -/// Repository trait for Item persistence operations. -/// -/// This trait defines the contract for item storage, allowing for -/// different implementations (e.g., SeaORM, mocks for testing). -#[async_trait] -pub trait ItemStore: Send + Sync { - /// Creates a new item and returns its metadata. - async fn create( - &self, - name: ItemName, - description: Option, - ) -> Result; - - /// Lists all items. - async fn list(&self) -> Result, DatabaseError>; - - /// Reads a single item by its ID. - /// - /// Returns `Ok(metadata)` if found, `Err(())` if not found. - async fn read(&self, id: ItemId) -> Result; - - /// Updates an item's name and/or description. - /// - /// Returns the updated metadata. - async fn update( - &self, - id: ItemId, - name: Option, - description: Option>, - ) -> Result; - - /// Deletes an item by its ID. - /// - /// This operation is idempotent - deleting a non-existent item returns success. - async fn delete(&self, id: ItemId) -> Result<(), DatabaseError>; -} - -/// Blanket implementation for Arc-wrapped ItemStore. -/// This allows `Arc` to implement `ItemStore`, enabling -/// services to work with cheaply cloneable trait objects that satisfy `'static`. -#[async_trait] -impl ItemStore for std::sync::Arc { - async fn create( - &self, - name: ItemName, - description: Option, - ) -> Result { - (**self).create(name, description).await - } - - async fn list(&self) -> Result, DatabaseError> { - (**self).list().await - } - - async fn read(&self, id: ItemId) -> Result { - (**self).read(id).await - } - - async fn update( - &self, - id: ItemId, - name: Option, - description: Option>, - ) -> Result { - (**self).update(id, name, description).await - } - - async fn delete(&self, id: ItemId) -> Result<(), DatabaseError> { - (**self).delete(id).await - } -} - -#[cfg(test)] -mod tests { - use super::ItemStore; - use static_assertions::assert_obj_safe; - - assert_obj_safe!(ItemStore); -} diff --git a/src/repos/items/seaorm.rs b/src/repos/items/seaorm.rs deleted file mode 100644 index 8a10ce0..0000000 --- a/src/repos/items/seaorm.rs +++ /dev/null @@ -1,153 +0,0 @@ -use chrono::Utc; -use salvo::async_trait; -use sea_orm::{ActiveModelTrait, ColumnTrait, EntityTrait, QueryFilter, Set}; -use uuid::Uuid; - -use super::{DatabaseError, ItemStore}; -use crate::domain::{ItemId, ItemMetadata, ItemName}; -use crate::models::items::{ActiveModel, Column, Entity as ItemEntity}; -use crate::repos::{Transaction, TransactionError}; - -#[async_trait] -impl ItemStore for Transaction { - async fn create( - &self, - name: ItemName, - description: Option, - ) -> Result { - let internal_id = Uuid::new_v4(); - let now = Utc::now(); - - let model = ActiveModel { - internal_id: Set(internal_id), - name: Set(name.to_string()), - description: Set(description.clone()), - created_at: Set(now.into()), - updated_at: Set(now.into()), - ..Default::default() - }; - - self.with_transaction_async(|txn| async move { - let _result = model.insert(&txn).await.map_err(|_| ())?; - Ok(((), txn)) - }) - .await - .map_err(|_: TransactionError<()>| ())?; - - Ok(ItemMetadata::new( - ItemId::new(internal_id), - name, - description, - now, - now, - )) - } - - async fn list(&self) -> Result, DatabaseError> { - self.with_transaction_async(|txn| async move { - let items = ItemEntity::find().all(&txn).await.map_err(|_| ())?; - - let metadata: Vec = items - .into_iter() - .map(|m| { - ItemMetadata::new( - ItemId::new(m.internal_id), - ItemName::try_new(m.name).unwrap(), - m.description, - m.created_at.into(), - m.updated_at.into(), - ) - }) - .collect(); - - Ok((metadata, txn)) - }) - .await - .map_err(|_: TransactionError<()>| ()) - } - - async fn read(&self, id: ItemId) -> Result { - let uuid: Uuid = *id.as_ref(); - - self.with_transaction_async(|txn| async move { - let item = ItemEntity::find() - .filter(Column::InternalId.eq(uuid)) - .one(&txn) - .await - .map_err(|_| ())? - .ok_or(())?; - - let metadata = ItemMetadata::new( - ItemId::new(item.internal_id), - ItemName::try_new(item.name).unwrap(), - item.description, - item.created_at.into(), - item.updated_at.into(), - ); - - Ok((metadata, txn)) - }) - .await - .map_err(|_: TransactionError<()>| ()) - } - - async fn update( - &self, - id: ItemId, - name: Option, - description: Option>, - ) -> Result { - let uuid: Uuid = *id.as_ref(); - - self.with_transaction_async(|txn| async move { - let item = ItemEntity::find() - .filter(Column::InternalId.eq(uuid)) - .one(&txn) - .await - .map_err(|_| ())? - .ok_or(())?; - - let mut active: ActiveModel = item.into(); - - if let Some(new_name) = name { - active.name = Set(new_name.to_string()); - } - - if let Some(new_description) = description { - active.description = Set(new_description); - } - - active.updated_at = Set(Utc::now().into()); - - let updated = active.update(&txn).await.map_err(|_| ())?; - - let metadata = ItemMetadata::new( - ItemId::new(updated.internal_id), - ItemName::try_new(updated.name).unwrap(), - updated.description, - updated.created_at.into(), - updated.updated_at.into(), - ); - - Ok((metadata, txn)) - }) - .await - .map_err(|_: TransactionError<()>| ()) - } - - async fn delete(&self, id: ItemId) -> Result<(), DatabaseError> { - let uuid: Uuid = *id.as_ref(); - - self.with_transaction_async(|txn| async move { - ItemEntity::delete_many() - .filter(Column::InternalId.eq(uuid)) - .exec(&txn) - .await - .map_err(|_| ())?; - - Ok(((), txn)) - }) - .await - .map_err(|_: TransactionError<()>| ()) - } -} diff --git a/src/repos/mod.rs b/src/repos/mod.rs deleted file mode 100644 index 7b26502..0000000 --- a/src/repos/mod.rs +++ /dev/null @@ -1,128 +0,0 @@ -use sea_orm::DatabaseTransaction; -use std::sync::Arc; -use tokio::sync::Mutex; - -pub use items::ItemStore; - -pub mod items; - -/// A thread-safe wrapper around SeaORM's DatabaseTransaction that allows -/// multiple stores to share and access the same transaction. -/// -/// This struct uses Arc> to provide shared ownership and mutability, -/// allowing multiple stores to obtain mutable references to the underlying -/// transaction safely across thread boundaries. -#[derive(Clone)] -pub struct Transaction { - inner: Arc>>, -} - -impl Transaction { - /// Creates a new Transaction wrapping the given DatabaseTransaction - pub fn new(txn: DatabaseTransaction) -> Self { - Self { - inner: Arc::new(Mutex::new(Some(txn))), - } - } - - /// Executes a closure with mutable access to the underlying transaction. - /// Returns an error if the transaction has already been consumed. - pub async fn with_transaction(&self, f: F) -> Result> - where - F: FnOnce(&mut DatabaseTransaction) -> Result, - { - let mut guard = self.inner.lock().await; - - match guard.as_mut() { - Some(txn) => f(txn).map_err(TransactionError::UserError), - None => Err(TransactionError::TransactionConsumed), - } - } - - /// Executes an async closure with access to the underlying transaction. - /// This version temporarily takes ownership of the transaction for the duration of the operation. - pub async fn with_transaction_async(&self, f: F) -> Result> - where - F: FnOnce(DatabaseTransaction) -> Fut + Send, - Fut: std::future::Future> + Send, - R: Send, - E: Send, - { - let mut guard = self.inner.lock().await; - - match guard.take() { - Some(txn) => match f(txn).await { - Ok((result, returned_txn)) => { - *guard = Some(returned_txn); - Ok(result) - } - Err(e) => { - // Transaction is lost on error - Err(TransactionError::UserError(e)) - } - }, - None => Err(TransactionError::TransactionConsumed), - } - } - - /// Consumes the transaction, returning the underlying DatabaseTransaction. - /// After this call, the Transaction wrapper becomes unusable. - pub async fn into_inner(self) -> Result> { - let mut guard = self.inner.lock().await; - guard.take().ok_or(TransactionError::TransactionConsumed) - } - - /// Checks if the transaction is still available (not consumed) - pub async fn is_available(&self) -> bool { - self.inner.lock().await.is_some() - } -} - -#[derive(Debug, thiserror::Error)] -pub enum TransactionError { - #[error("Transaction lock error - mutex was poisoned")] - LockError, - #[error("Transaction has already been consumed")] - TransactionConsumed, - #[error("User operation failed: {0}")] - UserError(E), -} - -impl TransactionError { - /// Maps the user error type to a different type - pub fn map_user_error(self, f: impl FnOnce(E) -> F) -> TransactionError { - match self { - TransactionError::LockError => TransactionError::LockError, - TransactionError::TransactionConsumed => TransactionError::TransactionConsumed, - TransactionError::UserError(e) => TransactionError::UserError(f(e)), - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_transaction_error_mapping() { - let error: TransactionError = TransactionError::UserError("test error".to_string()); - let mapped = error.map_user_error(|s| s.len()); - - match mapped { - TransactionError::UserError(len) => assert_eq!(len, 10), - _ => panic!("Expected UserError"), - } - - // Test other error types - let lock_error: TransactionError = TransactionError::LockError; - let mapped_lock = lock_error.map_user_error(|x| x.to_string()); - assert!(matches!(mapped_lock, TransactionError::LockError)); - - let consumed_error: TransactionError = TransactionError::TransactionConsumed; - let mapped_consumed = consumed_error.map_user_error(|x| x.to_string()); - assert!(matches!( - mapped_consumed, - TransactionError::TransactionConsumed - )); - } -} diff --git a/src/services/items/mod.rs b/src/services/items/mod.rs deleted file mode 100644 index 37d2a68..0000000 --- a/src/services/items/mod.rs +++ /dev/null @@ -1,3 +0,0 @@ -pub use service::{ItemService, Service, ServiceError}; - -mod service; diff --git a/src/services/items/service.rs b/src/services/items/service.rs deleted file mode 100644 index d86e5d3..0000000 --- a/src/services/items/service.rs +++ /dev/null @@ -1,156 +0,0 @@ -use salvo::async_trait; - -use crate::domain::{ItemId, ItemMetadata, ItemName}; -use crate::repos::items::ItemStore; - -/// Service trait for Item business logic. -/// -/// This trait defines the business operations for items, providing -/// a layer of abstraction between controllers and repositories. -#[async_trait] -pub trait ItemService: Send + Sync + 'static { - /// Creates a new item with the given name and optional description. - async fn create_item( - &self, - name: ItemName, - description: Option, - ) -> Result; - - /// Lists all items. - async fn list_items(&self) -> Result, ServiceError>; - - /// Retrieves a single item by ID. - async fn get_item(&self, id: ItemId) -> Result; - - /// Updates an item's name and/or description. - async fn update_item( - &self, - id: ItemId, - name: Option, - description: Option>, - ) -> Result; - - /// Deletes an item by ID. - async fn delete_item(&self, id: ItemId) -> Result<(), ServiceError>; -} - -/// Error type for service operations -#[derive(Debug, thiserror::Error)] -pub enum ServiceError { - #[error("Item not found")] - NotFound, - #[error("Internal error")] - Internal, -} - -/// Concrete implementation of ItemService -pub struct Service -where - R: ItemStore, -{ - repo: R, -} - -impl Service -where - R: ItemStore, -{ - /// Creates a new Service with the given repository - pub fn new(repo: R) -> Self { - Self { repo } - } -} - -#[async_trait] -impl ItemService for Service -where - R: ItemStore + 'static, -{ - async fn create_item( - &self, - name: ItemName, - description: Option, - ) -> Result { - self.repo - .create(name, description) - .await - .map_err(|_| ServiceError::Internal) - } - - async fn list_items(&self) -> Result, ServiceError> { - self.repo.list().await.map_err(|_| ServiceError::Internal) - } - - async fn get_item(&self, id: ItemId) -> Result { - self.repo.read(id).await.map_err(|_| ServiceError::NotFound) - } - - async fn update_item( - &self, - id: ItemId, - name: Option, - description: Option>, - ) -> Result { - self.repo - .update(id, name, description) - .await - .map_err(|_| ServiceError::NotFound) - } - - async fn delete_item(&self, id: ItemId) -> Result<(), ServiceError> { - self.repo - .delete(id) - .await - .map_err(|_| ServiceError::Internal) - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::repos::items::mocks::MockItemStore; - - #[tokio::test] - async fn test_create_and_get_item() { - let store = MockItemStore::new(); - let service = Service::new(store); - - let name = ItemName::try_new("Test Item").unwrap(); - let created = service - .create_item(name, Some("Description".to_string())) - .await - .unwrap(); - - assert_eq!(created.name.as_ref(), "Test Item"); - - let fetched = service.get_item(created.id).await.unwrap(); - assert_eq!(fetched.id, created.id); - } - - #[tokio::test] - async fn test_get_nonexistent_item() { - let store = MockItemStore::new(); - let service = Service::new(store); - - let result = service.get_item(ItemId::random()).await; - assert!(matches!(result, Err(ServiceError::NotFound))); - } - - #[tokio::test] - async fn test_list_items() { - let store = MockItemStore::new(); - let service = Service::new(store); - - service - .create_item(ItemName::try_new("Item 1").unwrap(), None) - .await - .unwrap(); - service - .create_item(ItemName::try_new("Item 2").unwrap(), None) - .await - .unwrap(); - - let items = service.list_items().await.unwrap(); - assert_eq!(items.len(), 2); - } -} diff --git a/src/services/mod.rs b/src/services/mod.rs deleted file mode 100644 index df625ab..0000000 --- a/src/services/mod.rs +++ /dev/null @@ -1,16 +0,0 @@ -pub mod items; - -pub use items::{ItemService, Service as ItemServiceImpl}; - -use crate::repos::items::ItemStore; - -/// Factory function to create an ItemService implementation with dependencies. -/// -/// This function provides dependency injection for the service layer, -/// taking repository implementations and returning a concrete service. -pub fn create_item_service(repo: R) -> impl ItemService -where - R: ItemStore + 'static, -{ - ItemServiceImpl::new(repo) -} diff --git a/src/utils/db.rs b/src/utils/db.rs deleted file mode 100644 index db652e8..0000000 --- a/src/utils/db.rs +++ /dev/null @@ -1,30 +0,0 @@ -use std::sync::OnceLock; -use std::time::Duration; - -use sea_orm::entity::prelude::DatabaseConnection; -use sea_orm::{ConnectOptions, Database}; - -use crate::cli::PostgresConfig; - -pub static SEAORM_POOL: OnceLock = OnceLock::new(); - -pub async fn init(config: &PostgresConfig) { - // Get the PostgreSQL connection string from the configuration - let database_url = config.connection_string(); - - let mut opt = ConnectOptions::new(database_url); - opt.max_connections(20) // Using the same DEFAULT_MAX_CONNECTIONS from pg.rs - .min_connections(5) - .connect_timeout(config.acquire_timeout.unwrap_or(Duration::from_secs(3))) - .idle_timeout(Duration::from_secs(8)) - .sqlx_logging(false); - - let pool = Database::connect(opt) - .await - .expect("db connection should connect"); - SEAORM_POOL.set(pool).expect("seaorm pool should be set"); -} - -pub fn pool() -> &'static DatabaseConnection { - SEAORM_POOL.get().expect("seaorm pool should set") -} diff --git a/src/utils/mod.rs b/src/utils/mod.rs deleted file mode 100644 index fa5cea3..0000000 --- a/src/utils/mod.rs +++ /dev/null @@ -1,6 +0,0 @@ -use chrono::{DateTime, Utc}; - -pub mod db; -pub mod telemetry; - -pub type Time = DateTime; diff --git a/src/utils/telemetry.rs b/src/utils/telemetry.rs deleted file mode 100644 index 0caf7f9..0000000 --- a/src/utils/telemetry.rs +++ /dev/null @@ -1,163 +0,0 @@ -use mvc_helpers::DeploymentEnvironment; -use opentelemetry::KeyValue; -use opentelemetry::global; -use opentelemetry_otlp::WithHttpConfig; -use opentelemetry_sdk::Resource; -use opentelemetry_sdk::propagation::TraceContextPropagator; -use opentelemetry_sdk::trace::SdkTracerProvider; -use tracing::level_filters::LevelFilter; -use tracing_subscriber::fmt::format::FmtSpan; -use tracing_subscriber::layer::SubscriberExt; -use tracing_subscriber::util::SubscriberInitExt; - -use crate::cli::{EnableColors, LogFormat}; - -/// Service name for OpenTelemetry semantic conventions -const SERVICE_NAME: &str = env!("CARGO_PKG_NAME"); - -/// Service version from Cargo.toml -const SERVICE_VERSION: &str = env!("CARGO_PKG_VERSION"); - -/// Header name for authenticating with the OTLP collector -const API_KEY_HEADER: &str = "X-API-KEY"; - -// Build-time provenance attributes, populated by `build.rs` from CI env vars -// (preferred) or local git shell-out. Missing values are stamped "unknown". -// Names follow the OpenTelemetry CI/CD + VCS semantic conventions. -const VCS_REF_HEAD_REVISION: &str = env!("VCS_REF_HEAD_REVISION"); -const VCS_REF_HEAD_NAME: &str = env!("VCS_REF_HEAD_NAME"); -const VCS_REF_HEAD_TYPE: &str = env!("VCS_REF_HEAD_TYPE"); -const VCS_REPOSITORY_URL_FULL: &str = env!("VCS_REPOSITORY_URL_FULL"); -const VCS_PROVIDER_NAME: &str = "github"; -const CICD_PIPELINE_NAME: &str = env!("CICD_PIPELINE_NAME"); -const CICD_PIPELINE_RUN_URL_FULL: &str = env!("CICD_PIPELINE_RUN_URL_FULL"); - -/// Guard that ensures OpenTelemetry resources are properly flushed on shutdown. -/// When dropped, this will flush any pending spans to the collector. -pub struct TelemetryGuard { - provider: SdkTracerProvider, -} - -impl Drop for TelemetryGuard { - fn drop(&mut self) { - if let Err(e) = self.provider.shutdown() { - eprintln!("Failed to shutdown tracer provider: {e}"); - } - } -} - -/// Configuration for initializing telemetry. -pub struct TelemetryConfig { - pub log_level: LevelFilter, - pub log_format: LogFormat, - pub enable_colors: EnableColors, - pub deployment_environment: DeploymentEnvironment, - pub otel_exporter_api_key: Option, - pub service_version: Option, -} - -/// Initialize the OpenTelemetry tracer provider and tracing subscriber. -/// -/// This sets up: -/// - A tracing-subscriber with either text (colored) or JSON formatting -/// - A global OTel TracerProvider for OTel-compliant span export via OTLP -/// - W3C Trace Context propagation for distributed tracing -/// - OTel semantic convention resource attributes (service.name, service.version, deployment.environment.name) -/// -/// Returns a TelemetryGuard. The guard must be held for the lifetime of the -/// application to ensure spans are flushed on shutdown. -pub fn init_telemetry(config: TelemetryConfig) -> TelemetryGuard { - // Set up W3C Trace Context propagation for distributed tracing - global::set_text_map_propagator(TraceContextPropagator::new()); - - // Use runtime service version if provided, otherwise fall back to compile-time crate version - let version = config.service_version.as_deref().unwrap_or(SERVICE_VERSION); - - // Build resource with OTel semantic convention attributes - let attributes = vec![ - KeyValue::new("service.name", SERVICE_NAME), - KeyValue::new("service.version", version.to_owned()), - KeyValue::new( - "deployment.environment.name", - config.deployment_environment.to_string(), - ), - KeyValue::new("vcs.ref.head.revision", VCS_REF_HEAD_REVISION), - KeyValue::new("vcs.ref.head.name", VCS_REF_HEAD_NAME), - KeyValue::new("vcs.ref.head.type", VCS_REF_HEAD_TYPE), - KeyValue::new("vcs.repository.url.full", VCS_REPOSITORY_URL_FULL), - KeyValue::new("vcs.provider.name", VCS_PROVIDER_NAME), - KeyValue::new("cicd.pipeline.name", CICD_PIPELINE_NAME), - KeyValue::new("cicd.pipeline.run.url.full", CICD_PIPELINE_RUN_URL_FULL), - ]; - let resource = Resource::builder().with_attributes(attributes).build(); - - // Build custom headers for OTLP exporter - let mut headers = std::collections::HashMap::new(); - - // Attach API key via X-API-KEY header if configured - if let Some(api_key) = config.otel_exporter_api_key { - headers.insert(API_KEY_HEADER.to_string(), api_key); - } - - // Create the OTLP exporter for sending spans to a collector (e.g., Vector) - let exporter = opentelemetry_otlp::SpanExporter::builder() - .with_http() - .with_headers(headers) - .build() - .expect("failed to create OTLP exporter"); - - // Build the tracer provider with batch export and resource attributes - let provider = SdkTracerProvider::builder() - .with_batch_exporter(exporter) - .with_resource(resource) - .build(); - - // Register the provider globally so it can be accessed from anywhere - // The OtelHttpMiddleware uses global::tracer() to create OTel-compliant spans - global::set_tracer_provider(provider.clone()); - - // Configure and initialize the appropriate formatting layer - match config.log_format { - LogFormat::Text => init_text_subscriber(config.log_level, config.enable_colors), - LogFormat::JSON => init_json_subscriber(config.log_level), - } - - TelemetryGuard { provider } -} - -/// Initialize the tracing subscriber with a human-readable text formatter. -fn init_text_subscriber(log_level: LevelFilter, enable_colors: EnableColors) { - let ansi = match enable_colors { - EnableColors::Always => true, - EnableColors::Never => false, - EnableColors::Auto => std::io::IsTerminal::is_terminal(&std::io::stderr()), - }; - - let fmt_layer = tracing_subscriber::fmt::layer() - .with_ansi(ansi) - .with_span_events(FmtSpan::CLOSE) - .with_target(true) - .with_thread_ids(false) - .with_file(false) - .with_line_number(false); - - tracing_subscriber::registry() - .with(log_level) - .with(fmt_layer) - .init(); -} - -/// Initialize the tracing subscriber with a JSON formatter. -fn init_json_subscriber(log_level: LevelFilter) { - let fmt_layer = tracing_subscriber::fmt::layer() - .json() - .with_span_events(FmtSpan::CLOSE) - .with_current_span(true) - .with_span_list(false) - .flatten_event(true); - - tracing_subscriber::registry() - .with(log_level) - .with(fmt_layer) - .init(); -} diff --git a/src/views/CLAUDE.md b/src/views/CLAUDE.md deleted file mode 100644 index 4ff4606..0000000 --- a/src/views/CLAUDE.md +++ /dev/null @@ -1,5 +0,0 @@ -Each REST API resource must have its own directory under `views/`. Top-level resources get a folder directly in `views/` (e.g. `views/users/`, `views/workspaces/`). Nested resources mirror the URL path hierarchy — for example, a resource at `workspaces/{id}/applications` lives at `views/workspaces/applications/`. - -Views which declare an id (like `views/workspaces/api_keys/id.rs`) must place the `Id` declaration in a file named `id.rs`. The newtype pattern must be used for these views, using either the `view_id!` macro (preferred) or the `nutype` library. - -Views which have a `display_name` string field must place the `DisplayName` type in a file named `display_name.rs` (like `views/workspaces/api_keys/display_name.rs`). The newtype pattern must be used for these views as well, wrapping the `String` type in a new type. The type name must be prefixed with the resource name (e.g., `WorkspaceDisplayName` for workspaces, `ApiKeyDisplayName` for api_keys). diff --git a/src/views/items/create.rs b/src/views/items/create.rs deleted file mode 100644 index f45f14b..0000000 --- a/src/views/items/create.rs +++ /dev/null @@ -1,50 +0,0 @@ -use salvo::oapi::ToSchema; -use serde::{Deserialize, Serialize}; - -use crate::domain::ItemMetadata; - -/// Request body for creating a new item -#[derive(Debug, Deserialize, ToSchema)] -pub struct CreateItemRequest { - /// The name of the item (1-255 characters) - pub name: String, - /// Optional description for the item - pub description: Option, -} - -/// Response for a successfully created item -#[derive(Debug, Serialize, ToSchema)] -pub struct CreateItemResponse { - /// The unique identifier for the created item - pub id: String, - /// The name of the item - pub name: String, - /// The description of the item - pub description: Option, - /// When the item was created (ISO 8601) - pub created_at: String, - /// When the item was last updated (ISO 8601) - pub updated_at: String, -} - -impl From for CreateItemResponse { - fn from(metadata: ItemMetadata) -> Self { - Self { - id: metadata.id.to_string(), - name: metadata.name.to_string(), - description: metadata.description, - created_at: metadata.created_at.to_rfc3339(), - updated_at: metadata.updated_at.to_rfc3339(), - } - } -} - -/// Error response for create operation -#[derive(Debug, Serialize, ToSchema)] -#[serde(tag = "error", content = "message")] -pub enum CreateItemFailure { - /// Invalid request parameters - InvalidRequest(String), - /// Internal server error - Internal(String), -} diff --git a/src/views/items/delete.rs b/src/views/items/delete.rs deleted file mode 100644 index 8324419..0000000 --- a/src/views/items/delete.rs +++ /dev/null @@ -1,33 +0,0 @@ -use salvo::oapi::ToSchema; -use serde::Serialize; - -/// Response for a successful delete operation -#[derive(Debug, Serialize, ToSchema)] -pub struct DeleteItemResponse { - /// Confirmation message - pub message: String, -} - -impl DeleteItemResponse { - pub fn new() -> Self { - Self { - message: "Item deleted successfully".to_string(), - } - } -} - -impl Default for DeleteItemResponse { - fn default() -> Self { - Self::new() - } -} - -/// Error response for delete operation -#[derive(Debug, Serialize, ToSchema)] -#[serde(tag = "error", content = "message")] -pub enum DeleteItemFailure { - /// Invalid item ID format - InvalidParameter(String), - /// Internal server error - Internal(String), -} diff --git a/src/views/items/list.rs b/src/views/items/list.rs deleted file mode 100644 index 0604b3b..0000000 --- a/src/views/items/list.rs +++ /dev/null @@ -1,54 +0,0 @@ -use salvo::oapi::ToSchema; -use serde::Serialize; - -use crate::domain::ItemMetadata; - -/// Single item in the list response -#[derive(Debug, Serialize, ToSchema)] -pub struct ItemSummary { - /// The unique identifier for the item - pub id: String, - /// The name of the item - pub name: String, - /// The description of the item - pub description: Option, - /// When the item was created (ISO 8601) - pub created_at: String, - /// When the item was last updated (ISO 8601) - pub updated_at: String, -} - -impl From for ItemSummary { - fn from(metadata: ItemMetadata) -> Self { - Self { - id: metadata.id.to_string(), - name: metadata.name.to_string(), - description: metadata.description, - created_at: metadata.created_at.to_rfc3339(), - updated_at: metadata.updated_at.to_rfc3339(), - } - } -} - -/// Response containing a list of items -#[derive(Debug, Serialize, ToSchema)] -pub struct ListItemsResponse { - /// The list of items - pub items: Vec, -} - -impl ListItemsResponse { - pub fn new(items: Vec) -> Self { - Self { - items: items.into_iter().map(ItemSummary::from).collect(), - } - } -} - -/// Error response for list operation -#[derive(Debug, Serialize, ToSchema)] -#[serde(tag = "error", content = "message")] -pub enum ListItemsFailure { - /// Internal server error - Internal(String), -} diff --git a/src/views/items/mod.rs b/src/views/items/mod.rs deleted file mode 100644 index 90b27be..0000000 --- a/src/views/items/mod.rs +++ /dev/null @@ -1,11 +0,0 @@ -pub use create::{CreateItemFailure, CreateItemRequest, CreateItemResponse}; -pub use delete::{DeleteItemFailure, DeleteItemResponse}; -pub use list::{ListItemsFailure, ListItemsResponse}; -pub use read::{ReadItemFailure, ReadItemResponse}; -pub use update::{UpdateItemFailure, UpdateItemRequest, UpdateItemResponse}; - -mod create; -mod delete; -mod list; -mod read; -mod update; diff --git a/src/views/items/read.rs b/src/views/items/read.rs deleted file mode 100644 index 4fa2bb9..0000000 --- a/src/views/items/read.rs +++ /dev/null @@ -1,43 +0,0 @@ -use salvo::oapi::ToSchema; -use serde::Serialize; - -use crate::domain::ItemMetadata; - -/// Response for reading a single item -#[derive(Debug, Serialize, ToSchema)] -pub struct ReadItemResponse { - /// The unique identifier for the item - pub id: String, - /// The name of the item - pub name: String, - /// The description of the item - pub description: Option, - /// When the item was created (ISO 8601) - pub created_at: String, - /// When the item was last updated (ISO 8601) - pub updated_at: String, -} - -impl From for ReadItemResponse { - fn from(metadata: ItemMetadata) -> Self { - Self { - id: metadata.id.to_string(), - name: metadata.name.to_string(), - description: metadata.description, - created_at: metadata.created_at.to_rfc3339(), - updated_at: metadata.updated_at.to_rfc3339(), - } - } -} - -/// Error response for read operation -#[derive(Debug, Serialize, ToSchema)] -#[serde(tag = "error", content = "message")] -pub enum ReadItemFailure { - /// Item not found - NotFound(String), - /// Invalid item ID format - InvalidParameter(String), - /// Internal server error - Internal(String), -} diff --git a/src/views/items/update.rs b/src/views/items/update.rs deleted file mode 100644 index a0d0a01..0000000 --- a/src/views/items/update.rs +++ /dev/null @@ -1,54 +0,0 @@ -use salvo::oapi::ToSchema; -use serde::{Deserialize, Serialize}; - -use crate::domain::ItemMetadata; - -/// Request body for updating an item -#[derive(Debug, Deserialize, ToSchema)] -pub struct UpdateItemRequest { - /// New name for the item (1-255 characters) - pub name: Option, - /// New description for the item (null to clear) - pub description: Option>, -} - -/// Response for a successfully updated item -#[derive(Debug, Serialize, ToSchema)] -pub struct UpdateItemResponse { - /// The unique identifier for the item - pub id: String, - /// The name of the item - pub name: String, - /// The description of the item - pub description: Option, - /// When the item was created (ISO 8601) - pub created_at: String, - /// When the item was last updated (ISO 8601) - pub updated_at: String, -} - -impl From for UpdateItemResponse { - fn from(metadata: ItemMetadata) -> Self { - Self { - id: metadata.id.to_string(), - name: metadata.name.to_string(), - description: metadata.description, - created_at: metadata.created_at.to_rfc3339(), - updated_at: metadata.updated_at.to_rfc3339(), - } - } -} - -/// Error response for update operation -#[derive(Debug, Serialize, ToSchema)] -#[serde(tag = "error", content = "message")] -pub enum UpdateItemFailure { - /// Item not found - NotFound(String), - /// Invalid request parameters - InvalidRequest(String), - /// Invalid item ID format - InvalidParameter(String), - /// Internal server error - Internal(String), -} diff --git a/src/views/mod.rs b/src/views/mod.rs deleted file mode 100644 index 6eb4f75..0000000 --- a/src/views/mod.rs +++ /dev/null @@ -1,3 +0,0 @@ -pub use items::*; - -pub mod items; diff --git a/tern/schema.sql b/tern/schema.sql deleted file mode 100644 index 0acbcfe..0000000 --- a/tern/schema.sql +++ /dev/null @@ -1,109 +0,0 @@ --- --- PostgreSQL database dump --- - - - -SET statement_timeout = 0; -SET lock_timeout = 0; -SET idle_in_transaction_session_timeout = 0; -SET transaction_timeout = 0; -SET client_encoding = 'UTF8'; -SET standard_conforming_strings = on; -SELECT pg_catalog.set_config('search_path', '', false); -SET check_function_bodies = false; -SET xmloption = content; -SET client_min_messages = warning; -SET row_security = off; - -SET default_tablespace = ''; - -SET default_table_access_method = heap; - --- --- Name: items; Type: TABLE; Schema: public; Owner: - --- - -CREATE TABLE public.items ( - id integer NOT NULL, - internal_id uuid NOT NULL, - name character varying NOT NULL, - description character varying, - created_at timestamp with time zone NOT NULL, - updated_at timestamp with time zone NOT NULL -); - - --- --- Name: items_id_seq; Type: SEQUENCE; Schema: public; Owner: - --- - -CREATE SEQUENCE public.items_id_seq - AS integer - START WITH 1 - INCREMENT BY 1 - NO MINVALUE - NO MAXVALUE - CACHE 1; - - --- --- Name: items_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - --- - -ALTER SEQUENCE public.items_id_seq OWNED BY public.items.id; - - --- --- Name: seaql_migrations; Type: TABLE; Schema: public; Owner: - --- - -CREATE TABLE public.seaql_migrations ( - version character varying NOT NULL, - applied_at bigint NOT NULL -); - - --- --- Name: items id; Type: DEFAULT; Schema: public; Owner: - --- - -ALTER TABLE ONLY public.items ALTER COLUMN id SET DEFAULT nextval('public.items_id_seq'::regclass); - - --- --- Name: items items_internal_id_key; Type: CONSTRAINT; Schema: public; Owner: - --- - -ALTER TABLE ONLY public.items - ADD CONSTRAINT items_internal_id_key UNIQUE (internal_id); - - --- --- Name: items items_pkey; Type: CONSTRAINT; Schema: public; Owner: - --- - -ALTER TABLE ONLY public.items - ADD CONSTRAINT items_pkey PRIMARY KEY (id); - - --- --- Name: seaql_migrations seaql_migrations_pkey; Type: CONSTRAINT; Schema: public; Owner: - --- - -ALTER TABLE ONLY public.seaql_migrations - ADD CONSTRAINT seaql_migrations_pkey PRIMARY KEY (version); - - --- --- Name: idx_items_internal_id; Type: INDEX; Schema: public; Owner: - --- - -CREATE INDEX idx_items_internal_id ON public.items USING btree (internal_id); - - --- --- PostgreSQL database dump complete --- - - diff --git a/tests/common/mod.rs b/tests/common/mod.rs deleted file mode 100644 index 07760ba..0000000 --- a/tests/common/mod.rs +++ /dev/null @@ -1,10 +0,0 @@ -//! Shared test helpers for BDD and integration tests. -//! -//! - [`test_app`] — builds a Salvo `Service` from the real controllers with -//! in-memory mock repositories (never a real database). -//! - [`test_client`] — an ergonomic wrapper over Salvo's test client. - -#![allow(dead_code)] - -pub mod test_app; -pub mod test_client; diff --git a/tests/common/test_app.rs b/tests/common/test_app.rs deleted file mode 100644 index f42a321..0000000 --- a/tests/common/test_app.rs +++ /dev/null @@ -1,53 +0,0 @@ -//! Test application wiring for BDD / integration tests. -//! -//! Builds a Salvo `Service` from the real controllers but with **in-memory mock -//! repositories** injected — BDD tests never touch a real database. - -#![allow(dead_code)] - -use std::sync::Arc; - -use salvo::prelude::*; - -use __service_name__::controllers::items::items_controller; -use __service_name__::repos::ItemStore; -use __service_name__::repos::items::mocks::MockItemStore; - -/// A test application wrapping a Salvo `Service`. -pub struct TestApp { - service: Service, -} - -impl TestApp { - /// Wraps a router in a `Service`. - #[must_use] - pub fn new(router: Router) -> Self { - Self { - service: Service::new(router), - } - } - - /// The underlying Salvo service (pass to `TestClient::send`). - #[must_use] - pub fn service(&self) -> &Service { - &self.service - } -} - -/// Middleware that injects a fresh in-memory `MockItemStore` as the -/// `Arc` the controllers expect — no database, no I/O. -#[handler] -async fn inject_mock_item_store(depot: &mut Depot) { - let store: Arc = Arc::new(MockItemStore::new()); - depot.inject(store); -} - -/// Builds a test app that serves the real items controller backed by the -/// in-memory mock store. -#[must_use] -pub fn create_test_app() -> TestApp { - let router = Router::new() - .hoop(inject_mock_item_store) - .push(items_controller()); - TestApp::new(router) -} diff --git a/tests/common/test_client.rs b/tests/common/test_client.rs deleted file mode 100644 index d65fd0f..0000000 --- a/tests/common/test_client.rs +++ /dev/null @@ -1,158 +0,0 @@ -//! Ergonomic HTTP test client wrapping Salvo's test client. -//! -//! `send` eagerly captures the status and full body so callers (and the BDD -//! `TestWorld`) can inspect the response without `&mut` plumbing. - -#![allow(dead_code)] - -use salvo::http::StatusCode; -use salvo::prelude::*; -use salvo::test::{ResponseExt, TestClient as SalvoTestClient}; -use serde::Serialize; - -/// A small wrapper around Salvo's test client. -#[derive(Debug)] -pub struct TestClient { - base_url: String, -} - -impl Default for TestClient { - fn default() -> Self { - Self::new() - } -} - -impl TestClient { - /// Creates a client with the default in-process base URL. - #[must_use] - pub fn new() -> Self { - Self { - base_url: "http://127.0.0.1:5800".to_string(), - } - } - - /// GET request builder for `path`. - #[must_use] - pub fn get(&self, path: &str) -> RequestBuilder { - RequestBuilder::new(Method::Get, self.build_url(path)) - } - - /// POST request builder for `path`. - #[must_use] - pub fn post(&self, path: &str) -> RequestBuilder { - RequestBuilder::new(Method::Post, self.build_url(path)) - } - - /// PUT request builder for `path`. - #[must_use] - pub fn put(&self, path: &str) -> RequestBuilder { - RequestBuilder::new(Method::Put, self.build_url(path)) - } - - /// PATCH request builder for `path`. - #[must_use] - pub fn patch(&self, path: &str) -> RequestBuilder { - RequestBuilder::new(Method::Patch, self.build_url(path)) - } - - /// DELETE request builder for `path`. - #[must_use] - pub fn delete(&self, path: &str) -> RequestBuilder { - RequestBuilder::new(Method::Delete, self.build_url(path)) - } - - fn build_url(&self, path: &str) -> String { - if path.starts_with('/') { - format!("{}{}", self.base_url, path) - } else { - format!("{}/{}", self.base_url, path) - } - } -} - -/// HTTP methods supported by the test client. -#[derive(Debug, Clone, Copy)] -enum Method { - Get, - Post, - Put, - Patch, - Delete, -} - -/// Builder for a single test request. -#[derive(Debug)] -pub struct RequestBuilder { - method: Method, - url: String, - body: Option>, - content_type: Option, -} - -impl RequestBuilder { - fn new(method: Method, url: String) -> Self { - Self { - method, - url, - body: None, - content_type: None, - } - } - - /// Sets a JSON request body. - #[must_use] - pub fn json(mut self, body: &T) -> Self { - self.body = Some(serde_json::to_vec(body).expect("failed to serialize JSON body")); - self.content_type = Some("application/json".to_string()); - self - } - - /// Sends the request to `service` and captures the response. - pub async fn send(self, service: &Service) -> TestResponse { - let mut client = match self.method { - Method::Get => SalvoTestClient::get(&self.url), - Method::Post => SalvoTestClient::post(&self.url), - Method::Put => SalvoTestClient::put(&self.url), - Method::Patch => SalvoTestClient::patch(&self.url), - Method::Delete => SalvoTestClient::delete(&self.url), - }; - - if let Some(content_type) = self.content_type { - client = client.add_header(salvo::http::header::CONTENT_TYPE, content_type, true); - } - if let Some(body) = self.body { - client = client.bytes(body); - } - - let mut response = client.send(service).await; - let status = response - .status_code - .unwrap_or(StatusCode::INTERNAL_SERVER_ERROR); - let body = response.take_bytes(None).await.unwrap_or_default().to_vec(); - - TestResponse { status, body } - } -} - -/// A captured test response (status + full body). -#[derive(Debug)] -pub struct TestResponse { - /// HTTP status code. - pub status: StatusCode, - /// Full response body bytes. - pub body: Vec, -} - -impl TestResponse { - /// True if the status is 2xx. - #[must_use] - pub fn is_success(&self) -> bool { - self.status.is_success() - } - - /// True if the status is 4xx. - #[must_use] - pub fn is_client_error(&self) -> bool { - self.status.is_client_error() - } -} diff --git a/tests/cucumber/main.rs b/tests/cucumber/main.rs deleted file mode 100644 index 6ee49c4..0000000 --- a/tests/cucumber/main.rs +++ /dev/null @@ -1,72 +0,0 @@ -//! Cucumber BDD test runner. -//! -//! Entry point for the BDD suite. Runs every `.feature` file under `spec/`. -//! -//! # Running -//! -//! ```bash -//! cargo test --test cucumber # or: cargo make integ -//! ``` -//! -//! # Layout -//! -//! - `spec/` — Gherkin feature files, organized by domain -//! - `tests/cucumber/world.rs` — `TestWorld` state shared across steps -//! - `tests/cucumber/steps/` — step definitions by domain -//! - `tests/common/` — shared test helpers (`TestApp`, `TestClient`) - -use clap::Parser; -use cucumber::{StatsWriter, World}; - -// Shared test utilities (also used by unit/integration tests). -#[path = "../common/mod.rs"] -mod common; - -mod steps; -mod world; - -use world::TestWorld; - -#[tokio::main] -async fn main() -> Result<(), ()> { - let args = Cli::parse(); - - // Support IDE test-inspector calls (list/ignored) without running anything. - if args.list || args.ignored { - return Ok(()); - } - - // Run every feature under spec/, skipping scenarios tagged @skip. - let results = TestWorld::cucumber() - .fail_on_skipped() - .filter_run("spec/", |_feature, _rule, scenario| { - !scenario.tags.iter().any(|t| t == "skip") - }) - .await; - - if results.execution_has_failed() { - eprintln!("Cucumber tests have failed."); - return Err(()); - } - - println!("Cucumber tests completed successfully."); - Ok(()) -} - -/// Command-line arguments for the cucumber runner (supports IDE integration). -#[derive(Debug, Parser)] -#[command(name = "cucumber")] -#[command(about = "BDD test runner")] -pub struct Cli { - /// List all available tests without running them. - #[arg(long, default_value_t = false)] - list: bool, - - /// Output format for test results. - #[arg(long, default_value_t = String::new())] - format: String, - - /// Run only ignored tests. - #[arg(long, default_value_t = false)] - ignored: bool, -} diff --git a/tests/cucumber/steps/items.rs b/tests/cucumber/steps/items.rs deleted file mode 100644 index af9eeac..0000000 --- a/tests/cucumber/steps/items.rs +++ /dev/null @@ -1,30 +0,0 @@ -//! Step definitions for the items features. -//! -//! These exercise the real items controller backed by an in-memory mock store -//! (see `tests/common/test_app.rs`) — no database, no I/O. - -use cucumber::{then, when}; - -use crate::common::test_app::create_test_app; -use crate::common::test_client::TestClient; -use crate::world::TestWorld; - -/// Lists items via `GET /items` against the mock-backed test app. -#[when("the client lists items")] -async fn list_items(world: &mut TestWorld) { - let app = create_test_app(); - let client = TestClient::new(); - - let response = client.get("/items").send(app.service()).await; - world.set_response(response.status, &response.body); -} - -/// Asserts the most recent response was a success. -#[then("the response should be successful")] -async fn response_should_be_successful(world: &mut TestWorld) { - assert!( - world.last_response_was_success(), - "expected a 2xx response, got: {:?}", - world.last_status - ); -} diff --git a/tests/cucumber/steps/mod.rs b/tests/cucumber/steps/mod.rs deleted file mode 100644 index 5e3fb3f..0000000 --- a/tests/cucumber/steps/mod.rs +++ /dev/null @@ -1,7 +0,0 @@ -//! Step definitions, organized by domain. -//! -//! Add a module per resource as features are written. Step functions use the -//! `#[given]` / `#[when]` / `#[then]` macros and operate on `TestWorld`. - -pub mod items; -pub mod monitoring; diff --git a/tests/cucumber/steps/monitoring.rs b/tests/cucumber/steps/monitoring.rs deleted file mode 100644 index 007dcbf..0000000 --- a/tests/cucumber/steps/monitoring.rs +++ /dev/null @@ -1,32 +0,0 @@ -//! Step definitions for the monitoring features (heartbeat). - -use cucumber::{given, then}; -use salvo::prelude::*; - -use __service_name__::controllers::schema_router; - -use crate::common::test_client::TestClient; -use crate::world::TestWorld; - -/// Sends a request to the real `heartbeat` route and records the response. -/// -/// Uses the production `schema_router()` (the heartbeat route needs no database -/// middleware), so a regression in the real route fails this scenario. -#[given("a request is sent to the heartbeat route")] -async fn request_heartbeat(world: &mut TestWorld) { - let service = Service::new(schema_router()); - let client = TestClient::new(); - - let response = client.get("/heartbeat").send(&service).await; - world.set_response(response.status, &response.body); -} - -/// Asserts the most recent response was a success. -#[then("the request should succeed")] -async fn request_should_succeed(world: &mut TestWorld) { - assert!( - world.last_response_was_success(), - "expected a 2xx response, got: {:?}", - world.last_status - ); -} diff --git a/tests/cucumber/world.rs b/tests/cucumber/world.rs deleted file mode 100644 index 07693e8..0000000 --- a/tests/cucumber/world.rs +++ /dev/null @@ -1,59 +0,0 @@ -//! Shared state for cucumber BDD steps. -//! -//! `TestWorld` carries the most recent HTTP response across step definitions. -//! Keep it small — add domain state only as real features need it. - -#![allow(dead_code)] - -use cucumber::World; -use salvo::http::StatusCode; - -/// State shared across cucumber steps within a scenario. -#[derive(Debug, World)] -#[world(init = Self::new)] -pub struct TestWorld { - /// Status code from the most recent response. - pub last_status: Option, - /// Parsed JSON body from the most recent response (the `data` envelope is - /// unwrapped when present). - pub last_body: Option, -} - -impl TestWorld { - /// Creates an empty `TestWorld`. - fn new() -> Self { - Self { - last_status: None, - last_body: None, - } - } - - /// Records a response: stores its status and (best-effort) parsed JSON body. - pub fn set_response(&mut self, status: StatusCode, body: &[u8]) { - self.last_status = Some(status); - self.last_body = serde_json::from_slice::(body) - .ok() - .map(|parsed| parsed.get("data").cloned().unwrap_or(parsed)); - } - - /// True if the last response was a 2xx success. - pub fn last_response_was_success(&self) -> bool { - self.last_status.is_some_and(|status| status.is_success()) - } - - /// True if the last response was a 4xx client error. - pub fn last_response_was_client_error(&self) -> bool { - self.last_status - .is_some_and(|status| status.is_client_error()) - } -} - -impl Default for TestWorld { - fn default() -> Self { - Self::new() - } -} - -// NOTE: plain `#[test]` fns do not run in this target (`harness = false` — -// `main.rs` owns the runner), so unit tests for helpers live in `src/` modules, -// not here. This file holds only the cucumber `World` and its helpers. diff --git a/tests/fixtures/.gitkeep b/tests/fixtures/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/tests/path_parameter_validation.rs b/tests/path_parameter_validation.rs deleted file mode 100644 index 0ef7f96..0000000 --- a/tests/path_parameter_validation.rs +++ /dev/null @@ -1,82 +0,0 @@ -use salvo::prelude::*; -use salvo::test::{ResponseExt, TestClient}; - -#[tokio::test] -async fn test_get_item_with_invalid_id() { - use __service_name__::controllers::items::get_item; - - let router = Router::new().path("items/{item_id}").get(get_item); - - let service = Service::new(router); - - // Test with invalid UUID format - let mut response = TestClient::get("http://127.0.0.1:5800/items/invalid_id") - .send(&service) - .await; - - // Verify error response - let json = response.take_json::().await.unwrap(); - assert!(json.get("Err").is_some(), "Expected Err response"); - assert_eq!(json["Err"]["error"], "InvalidParameter"); -} - -#[tokio::test] -async fn test_get_item_with_missing_id() { - use __service_name__::controllers::items::get_item; - - let router = Router::new().path("items/{item_id}").get(get_item); - - let service = Service::new(router); - - // Test with missing item_id (trailing slash) - let response = TestClient::get("http://127.0.0.1:5800/items/") - .send(&service) - .await; - - // Should return 404 Not Found (no route match) - assert_eq!(response.status_code, Some(StatusCode::NOT_FOUND)); -} - -#[tokio::test] -async fn test_update_item_with_invalid_id() { - use __service_name__::controllers::items::update_item; - - let router = Router::new().path("items/{item_id}").patch(update_item); - - let service = Service::new(router); - - // Test with invalid UUID (must include JSON body for PATCH requests) - let mut response = TestClient::patch("http://127.0.0.1:5800/items/not-a-uuid") - .json(&serde_json::json!({})) - .send(&service) - .await; - - // Verify error response - let json = response.take_json::().await.unwrap(); - assert!(json.get("Err").is_some(), "Expected Err response"); - assert_eq!(json["Err"]["error"], "InvalidParameter"); -} - -#[tokio::test] -async fn test_delete_item_with_invalid_id() { - use __service_name__::controllers::items::delete_item; - - let router = Router::new().path("items/{item_id}").delete(delete_item); - - let service = Service::new(router); - - // Test with invalid UUID - let mut response = TestClient::delete("http://127.0.0.1:5800/items/bad-id") - .send(&service) - .await; - - // Verify error response - let json = response.take_json::().await.unwrap(); - assert!(json.get("Err").is_some(), "Expected Err response"); - assert_eq!(json["Err"]["error"], "InvalidParameter"); -} - -// Note: We don't test valid path parameters here because they would pass validation -// and then fail when trying to access the ItemStore from the depot (which doesn't exist in tests). -// The tests above sufficiently demonstrate that invalid parameters are caught and return -// InvalidParameter errors, which implicitly proves that valid parameters pass validation.