From 43b2e44d95f2defc8699fe99d9bd8a26fe39c653 Mon Sep 17 00:00:00 2001 From: GW_MC <72297530+GWMCwing@users.noreply.github.com> Date: Tue, 3 Mar 2026 04:13:31 +0000 Subject: [PATCH] Add project structure and roadmap documentation - Created `project-structure.md` to outline the directory layout, crate dependencies, design principles, module guidelines, and naming conventions for the NxMesh codebase. - Introduced `roadmap.md` detailing the development phases, milestones, tasks, deliverables, and resource requirements for the NxMesh project, spanning from foundational setup to enterprise features. --- .devcontainer/Dockerfile | 1 + .devcontainer/docker-compose.yml | 2 +- AGENTS.md | 104 + Cargo.lock | 5552 ++++++++++++++++++++++++++++++ Cargo.toml | 77 +- README.md | 202 +- docs/api.md | 1107 ++++++ docs/architecture.md | 527 +++ docs/features.md | 814 +++++ docs/project-structure.md | 428 +++ docs/roadmap.md | 486 +++ 11 files changed, 9293 insertions(+), 7 deletions(-) create mode 100644 AGENTS.md create mode 100644 docs/api.md create mode 100644 docs/architecture.md create mode 100644 docs/features.md create mode 100644 docs/project-structure.md create mode 100644 docs/roadmap.md diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index c24f23c..2e7e7c0 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -8,6 +8,7 @@ RUN apt-get update && apt-get install -y \ pkg-config \ libssl-dev \ postgresql-client \ + protobuf-compiler \ && rm -rf /var/lib/apt/lists/* # Set working directory diff --git a/.devcontainer/docker-compose.yml b/.devcontainer/docker-compose.yml index c758e78..0cfa534 100644 --- a/.devcontainer/docker-compose.yml +++ b/.devcontainer/docker-compose.yml @@ -27,7 +27,7 @@ services: - docker pid: "service:nginx" - # Data Plane - Nginx (controlled by agent via Docker) + # Data Plane - Nginx (controlled by agent via PID namespace sharing) nginx: image: nginx:alpine container_name: nxmesh-nginx diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..36ed66e --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,104 @@ +# NxMesh - Agent Instructions + +This document provides context for AI agents working on the NxMesh project. + +## Project Overview + +**NxMesh** is a distributed nginx management system using a master-agent architecture: + +- **Master (Control Plane)**: Central API, embedded Web UI, configuration distribution, cluster management +- **Agent (Data Plane)**: Sidecar that manages local nginx instances +- **Web UI**: Vite React-based admin console, embedded and served by master + +## Quick Links to Documentation + +| Document | Purpose | +|----------|---------| +| [README.md](./README.md) | Project overview and quick start | +| [docs/architecture.md](./docs/architecture.md) | System design and data flow | +| [docs/features.md](./docs/features.md) | Detailed feature specifications | +| [docs/roadmap.md](./docs/roadmap.md) | Development phases and milestones | +| [docs/api.md](./docs/api.md) | REST and gRPC API specifications | + +| [docs/project-structure.md](./docs/project-structure.md) | Code organization | + +## Technology Stack + +| Component | Technology | +|-----------|------------| +| Backend | Rust (Axum, Tonic, SeaORM) | +| Frontend | React + TypeScript + Vite | +| Database | PostgreSQL 16+ | +| Cache | Redis | +| Message Format | Protocol Buffers (gRPC) | +| Container | Docker | +| Orchestration | Kubernetes (optional) | + +## Development Environment + +This project uses Dev Containers for consistent development: + +```bash +# All dependencies are pre-installed in the devcontainer +just setup # Initial setup +just dev # Start development +``` + +### Pre-configured Services + +The devcontainer includes: +- PostgreSQL database +- Redis cache +- Nginx instance +- Rust toolchain +- Node.js/Bun for frontend + +## Key Design Decisions + +1. **Master-Agent Protocol**: Bidirectional gRPC streaming for real-time communication +2. **Configuration Management**: Template-based (Handlebars) with versioning +3. **Security**: TLS + Shared Secret for agent connections, JWT for API auth +4. **Deployment**: Support for Docker sidecar, K8s sidecar, and standalone modes + +## Common Tasks + +### Adding a New API Endpoint + +1. Define route in `crates/nxmesh-master/src/api/v1/` +2. Add request/response types to shared models +3. Implement handler with proper error handling +4. Add tests +5. Update OpenAPI documentation + +### Adding a Database Entity + +1. Create migration with `sea-orm-cli migrate generate ` +2. Define entity in `crates/nxmesh-master/src/db/entities/` +3. Add repository in `crates/nxmesh-master/src/db/repositories/` +4. Update service layer + +### Adding Agent Functionality + +1. Add module in `crates/nxmesh-agent/src/` +2. Update gRPC protocol if needed (`crates/nxmesh-proto/proto/`) +3. Implement handler in agent +4. Add corresponding master service + +## Testing + +```bash +just test # All tests +just test-unit # Unit tests only +just test-integration # Integration tests +``` + +## Code Style + +- Follow Rust API Guidelines +- Use `cargo fmt` and `cargo clippy` +- All public APIs must have doc comments +- Error types should be descriptive and actionable + +## Questions? + +Refer to the documentation in `docs/` directory or ask the team. diff --git a/Cargo.lock b/Cargo.lock index 8e157bc..40c4050 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,3 +1,5555 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. version = 4 + +[[package]] +name = "adler2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" + +[[package]] +name = "ahash" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9" +dependencies = [ + "getrandom 0.2.17", + "once_cell", + "version_check", +] + +[[package]] +name = "ahash" +version = "0.8.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" +dependencies = [ + "cfg-if", + "const-random", + "getrandom 0.3.4", + "once_cell", + "version_check", + "zerocopy", +] + +[[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 = "anyhow" +version = "1.0.102" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" + +[[package]] +name = "argon2" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c3610892ee6e0cbce8ae2700349fcf8f98adb0dbfbee85aec3c9179d29cc072" +dependencies = [ + "base64ct", + "blake2", + "cpufeatures", + "password-hash", +] + +[[package]] +name = "arraydeque" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d902e3d592a523def97af8f317b08ce16b7ab854c1985a0c671e6f15cebc236" + +[[package]] +name = "arrayvec" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" + +[[package]] +name = "arrow" +version = "57.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4754a624e5ae42081f464514be454b39711daae0458906dacde5f4c632f33a8" +dependencies = [ + "arrow-arith", + "arrow-array", + "arrow-buffer", + "arrow-cast", + "arrow-data", + "arrow-ord", + "arrow-row", + "arrow-schema", + "arrow-select", + "arrow-string", +] + +[[package]] +name = "arrow-arith" +version = "57.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7b3141e0ec5145a22d8694ea8b6d6f69305971c4fa1c1a13ef0195aef2d678b" +dependencies = [ + "arrow-array", + "arrow-buffer", + "arrow-data", + "arrow-schema", + "chrono", + "num-traits", +] + +[[package]] +name = "arrow-array" +version = "57.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c8955af33b25f3b175ee10af580577280b4bd01f7e823d94c7cdef7cf8c9aef" +dependencies = [ + "ahash 0.8.12", + "arrow-buffer", + "arrow-data", + "arrow-schema", + "chrono", + "half", + "hashbrown 0.16.1", + "num-complex", + "num-integer", + "num-traits", +] + +[[package]] +name = "arrow-buffer" +version = "57.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c697ddca96183182f35b3a18e50b9110b11e916d7b7799cbfd4d34662f2c56c2" +dependencies = [ + "bytes", + "half", + "num-bigint", + "num-traits", +] + +[[package]] +name = "arrow-cast" +version = "57.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "646bbb821e86fd57189c10b4fcdaa941deaf4181924917b0daa92735baa6ada5" +dependencies = [ + "arrow-array", + "arrow-buffer", + "arrow-data", + "arrow-ord", + "arrow-schema", + "arrow-select", + "atoi", + "base64 0.22.1", + "chrono", + "half", + "lexical-core", + "num-traits", + "ryu", +] + +[[package]] +name = "arrow-data" +version = "57.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fdd994a9d28e6365aa78e15da3f3950c0fdcea6b963a12fa1c391afb637b304" +dependencies = [ + "arrow-buffer", + "arrow-schema", + "half", + "num-integer", + "num-traits", +] + +[[package]] +name = "arrow-ord" +version = "57.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7d8f1870e03d4cbed632959498bcc84083b5a24bded52905ae1695bd29da45b" +dependencies = [ + "arrow-array", + "arrow-buffer", + "arrow-data", + "arrow-schema", + "arrow-select", +] + +[[package]] +name = "arrow-row" +version = "57.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18228633bad92bff92a95746bbeb16e5fc318e8382b75619dec26db79e4de4c0" +dependencies = [ + "arrow-array", + "arrow-buffer", + "arrow-data", + "arrow-schema", + "half", +] + +[[package]] +name = "arrow-schema" +version = "57.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c872d36b7bf2a6a6a2b40de9156265f0242910791db366a2c17476ba8330d68" + +[[package]] +name = "arrow-select" +version = "57.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68bf3e3efbd1278f770d67e5dc410257300b161b93baedb3aae836144edcaf4b" +dependencies = [ + "ahash 0.8.12", + "arrow-array", + "arrow-buffer", + "arrow-data", + "arrow-schema", + "num-traits", +] + +[[package]] +name = "arrow-string" +version = "57.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85e968097061b3c0e9fe3079cf2e703e487890700546b5b0647f60fca1b5a8d8" +dependencies = [ + "arrow-array", + "arrow-buffer", + "arrow-data", + "arrow-schema", + "arrow-select", + "memchr", + "num-traits", + "regex", + "regex-syntax", +] + +[[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.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c96bf972d85afc50bf5ab8fe2d54d1586b4e0b46c97c50a0c9e71e2f7bcd812a" +dependencies = [ + "async-task", + "concurrent-queue", + "fastrand", + "futures-lite", + "pin-project-lite", + "slab", +] + +[[package]] +name = "async-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.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fd03604047cee9b6ce9de9f70c6cd540a0520c813cbd49bae61f33ab80ed1dc" +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.117", +] + +[[package]] +name = "async-task" +version = "4.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de" + +[[package]] +name = "async-trait" +version = "0.1.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "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 = "axum" +version = "0.6.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b829e4e32b91e643de6eafe82b1d90675f5874230191a4ffbc1b336dec4d6bf" +dependencies = [ + "async-trait", + "axum-core 0.3.4", + "bitflags 1.3.2", + "bytes", + "futures-util", + "http 0.2.12", + "http-body 0.4.6", + "hyper 0.14.32", + "itoa", + "matchit", + "memchr", + "mime", + "percent-encoding", + "pin-project-lite", + "rustversion", + "serde", + "sync_wrapper 0.1.2", + "tower 0.4.13", + "tower-layer", + "tower-service", +] + +[[package]] +name = "axum" +version = "0.7.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edca88bc138befd0323b20752846e6587272d3b03b0343c8ea28a6f819e6e71f" +dependencies = [ + "async-trait", + "axum-core 0.4.5", + "base64 0.22.1", + "bytes", + "futures-util", + "http 1.4.0", + "http-body 1.0.1", + "http-body-util", + "hyper 1.8.1", + "hyper-util", + "itoa", + "matchit", + "memchr", + "mime", + "percent-encoding", + "pin-project-lite", + "rustversion", + "serde", + "serde_json", + "serde_path_to_error", + "serde_urlencoded", + "sha1", + "sync_wrapper 1.0.2", + "tokio", + "tokio-tungstenite", + "tower 0.5.3", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "axum-core" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "759fa577a247914fd3f7f76d62972792636412fbfd634cd452f6a385a74d2d2c" +dependencies = [ + "async-trait", + "bytes", + "futures-util", + "http 0.2.12", + "http-body 0.4.6", + "mime", + "rustversion", + "tower-layer", + "tower-service", +] + +[[package]] +name = "axum-core" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09f2bd6146b97ae3359fa0cc6d6b376d9539582c7b4220f041a33ec24c226199" +dependencies = [ + "async-trait", + "bytes", + "futures-util", + "http 1.4.0", + "http-body 1.0.1", + "http-body-util", + "mime", + "pin-project-lite", + "rustversion", + "sync_wrapper 1.0.2", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "base64" +version = "0.21.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "base64ct" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" + +[[package]] +name = "bigdecimal" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d6867f1565b3aad85681f1015055b087fcfd840d6aeee6eee7f2da317603695" +dependencies = [ + "autocfg", + "libm", + "num-bigint", + "num-integer", + "num-traits", + "serde", +] + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af" +dependencies = [ + "serde_core", +] + +[[package]] +name = "bitvec" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" +dependencies = [ + "funty", + "radium", + "tap", + "wyz", +] + +[[package]] +name = "blake2" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe" +dependencies = [ + "digest", +] + +[[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 = "borsh" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1da5ab77c1437701eeff7c88d968729e7766172279eab0676857b3d63af7a6f" +dependencies = [ + "borsh-derive", + "cfg_aliases", +] + +[[package]] +name = "borsh-derive" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0686c856aa6aac0c4498f936d7d6a02df690f614c03e4d906d1018062b5c5e2c" +dependencies = [ + "once_cell", + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "bumpalo" +version = "3.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb" + +[[package]] +name = "bytecheck" +version = "0.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23cdc57ce23ac53c931e88a43d06d070a6fd142f2617be5855eb75efc9beb1c2" +dependencies = [ + "bytecheck_derive", + "ptr_meta", + "simdutf8", +] + +[[package]] +name = "bytecheck_derive" +version = "0.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3db406d29fbcd95542e92559bed4d8ad92636d1ca8b3b72ede10b4bcc010e659" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[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.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" + +[[package]] +name = "cc" +version = "1.2.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aebf35691d1bfb0ac386a69bac2fde4dd276fb618cf8bf4f5318fe285e821bb2" +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 = "cfg_aliases" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + +[[package]] +name = "chrono" +version = "0.4.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c673075a2e0e5f4a1dde27ce9dee1ea4558c7ffe648f576438a20ca1d2acc4b0" +dependencies = [ + "iana-time-zone", + "js-sys", + "num-traits", + "serde", + "wasm-bindgen", + "windows-link 0.2.1", +] + +[[package]] +name = "clap" +version = "4.5.60" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2797f34da339ce31042b27d23607e051786132987f595b02ba4f6a6dffb7030a" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.5.60" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24a241312cea5059b13574bb9b3861cabf758b879c15190b37b6d6fd63ab6876" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.5.55" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a92793da1a46a5f2a02a6f4c46c6496b28c43638adea8306fcb0caa1634f24e5" +dependencies = [ + "heck 0.5.0", + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "clap_lex" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a822ea5bc7590f9d40f1ba12c0dc3c2760f3482c6984db1573ad11031420831" + +[[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 = "config" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68578f196d2a33ff61b27fae256c3164f65e36382648e30666dde05b8cc9dfdf" +dependencies = [ + "async-trait", + "convert_case", + "json5", + "nom", + "pathdiff", + "ron", + "rust-ini", + "serde", + "serde_json", + "toml", + "yaml-rust2", +] + +[[package]] +name = "const-oid" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" + +[[package]] +name = "const-random" +version = "0.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87e00182fe74b066627d63b85fd550ac2998d4b0bd86bfed477a0ae4c7c71359" +dependencies = [ + "const-random-macro", +] + +[[package]] +name = "const-random-macro" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9d839f2a20b0aee515dc581a6172f2321f96cab76c1a38a4c584a194955390e" +dependencies = [ + "getrandom 0.2.17", + "once_cell", + "tiny-keccak", +] + +[[package]] +name = "convert_case" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec182b0ca2f35d8fc196cf3404988fd8b8c739a4d270ff118a398feb0cbec1ca" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "core-foundation" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + +[[package]] +name = "cpufeatures" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +dependencies = [ + "libc", +] + +[[package]] +name = "crc" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9710d3b3739c2e349eb44fe848ad0b7c8cb1e42bd87ee49371df2f7acaf3e675" +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 = "crc32fast" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" +dependencies = [ + "cfg-if", +] + +[[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 = "crunchy" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" + +[[package]] +name = "crypto-common" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "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", + "strsim", + "syn 2.0.117", +] + +[[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.117", +] + +[[package]] +name = "data-encoding" +version = "2.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7a1e2f27636f116493b8b860f5546edb47c8d8f8ea73e1d2a20be88e28d1fea" + +[[package]] +name = "der" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb" +dependencies = [ + "const-oid", + "pem-rfc7468", + "zeroize", +] + +[[package]] +name = "deranged" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c" +dependencies = [ + "powerfmt", + "serde_core", +] + +[[package]] +name = "derive_more" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "093242cf7570c207c83073cf82f79706fe7b8317e98620a47d5be7c3d8497678" +dependencies = [ + "derive_more-impl", +] + +[[package]] +name = "derive_more-impl" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bda628edc44c4bb645fbe0f758797143e4e07926f7ebf4e9bdfbd3d2ce621df3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", + "unicode-xid", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "const-oid", + "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.117", +] + +[[package]] +name = "dlv-list" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "442039f5147480ba31067cb00ada1adae6892028e40e45fc5de7b7df6dcc1b5f" +dependencies = [ + "const-random", +] + +[[package]] +name = "dotenvy" +version = "0.15.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" + +[[package]] +name = "downcast" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1435fa1053d8b2fbbe9be7e97eca7f33d37b28409959813daefc1446a14247f1" + +[[package]] +name = "either" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" +dependencies = [ + "serde", +] + +[[package]] +name = "encoding_rs" +version = "0.8.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "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.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" + +[[package]] +name = "fixedbitset" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" + +[[package]] +name = "flate2" +version = "1.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] +name = "flume" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da0e4dd2a88388a1f4ccc7c9ce104604dab68d9f408dc34cd45823d5a9069095" +dependencies = [ + "futures-core", + "futures-sink", + "spin", +] + +[[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 = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + +[[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 = "fragile" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28dd6caf6059519a65843af8fe2a3ae298b14b80179855aeb4adc2c1934ee619" + +[[package]] +name = "funty" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" + +[[package]] +name = "futures" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b147ee9d1f6d097cef9ce628cd2ee62288d963e16fb287bd9286455b241382d" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d" + +[[package]] +name = "futures-executor" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf29c38818342a3b26b5b923639e7b1f4a61fc5e76102d4b1981c6dc7a7579d" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-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.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718" + +[[package]] +name = "futures-lite" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f78e10609fe0e0b3f4157ffab1876319b5b0db102a2c60dc4626306dc46b44ad" +dependencies = [ + "fastrand", + "futures-core", + "futures-io", + "parking", + "pin-project-lite", +] + +[[package]] +name = "futures-macro" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e835b70203e41293343137df5c0664546da5745f82ec9b84d40be8336958447b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "futures-sink" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c39754e157331b013978ec91992bde1ac089843443c49cbc7f46150b0fad0893" + +[[package]] +name = "futures-task" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393" + +[[package]] +name = "futures-util" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "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.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "wasi", + "wasm-bindgen", +] + +[[package]] +name = "getrandom" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "r-efi", + "wasip2", + "wasm-bindgen", +] + +[[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 = "h2" +version = "0.3.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0beca50380b1fc32983fc1cb4587bfa4bb9e78fc259aad4a0032d2080309222d" +dependencies = [ + "bytes", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http 0.2.12", + "indexmap 2.11.4", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "half" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888" +dependencies = [ + "cfg-if", + "crunchy", + "num-traits", +] + +[[package]] +name = "handlebars" +version = "5.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d08485b96a0e6393e9e4d1b8d48cf74ad6c063cd905eb33f42c1ce3f0377539b" +dependencies = [ + "log", + "pest", + "pest_derive", + "serde", + "serde_json", + "thiserror 1.0.69", +] + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +dependencies = [ + "ahash 0.7.8", +] + +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" +dependencies = [ + "ahash 0.8.12", + "allocator-api2", +] + +[[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.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8094feaf31ff591f651a2664fb9cfd92bba7a60ce3197265e9482ebe753c8f7" +dependencies = [ + "hashbrown 0.14.5", +] + +[[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.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" +dependencies = [ + "windows-sys 0.52.0", +] + +[[package]] +name = "hostname" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "617aaa3557aef3810a6369d0a99fac8a080891b68bd9f9812a1eeda0c0730cbd" +dependencies = [ + "cfg-if", + "libc", + "windows-link 0.2.1", +] + +[[package]] +name = "http" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a" +dependencies = [ + "bytes", + "itoa", +] + +[[package]] +name = "http-body" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" +dependencies = [ + "bytes", + "http 0.2.12", + "pin-project-lite", +] + +[[package]] +name = "http-body" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" +dependencies = [ + "bytes", + "http 1.4.0", +] + +[[package]] +name = "http-body-util" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" +dependencies = [ + "bytes", + "futures-core", + "http 1.4.0", + "http-body 1.0.1", + "pin-project-lite", +] + +[[package]] +name = "http-range-header" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9171a2ea8a68358193d15dd5d70c1c10a2afc3e7e4c5bc92bc9f025cebd7359c" + +[[package]] +name = "httparse" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" + +[[package]] +name = "httpdate" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" + +[[package]] +name = "hyper" +version = "0.14.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41dfc780fdec9373c01bae43289ea34c972e40ee3c9f6b3c8801a35f35586ce7" +dependencies = [ + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "h2", + "http 0.2.12", + "http-body 0.4.6", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "socket2 0.5.10", + "tokio", + "tower-service", + "tracing", + "want", +] + +[[package]] +name = "hyper" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ab2d4f250c3d7b1c9fcdff1cece94ea4e2dfbec68614f7b87cb205f24ca9d11" +dependencies = [ + "atomic-waker", + "bytes", + "futures-channel", + "futures-core", + "http 1.4.0", + "http-body 1.0.1", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "pin-utils", + "smallvec", + "tokio", + "want", +] + +[[package]] +name = "hyper-rustls" +version = "0.27.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58" +dependencies = [ + "http 1.4.0", + "hyper 1.8.1", + "hyper-util", + "rustls", + "rustls-pki-types", + "tokio", + "tokio-rustls", + "tower-service", + "webpki-roots", +] + +[[package]] +name = "hyper-timeout" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbb958482e8c7be4bc3cf272a766a2b0bf1a6755e7a6ae777f017a31d11b13b1" +dependencies = [ + "hyper 0.14.32", + "pin-project-lite", + "tokio", + "tokio-io-timeout", +] + +[[package]] +name = "hyper-util" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96547c2556ec9d12fb1578c4eaf448b04993e7fb79cbaad930a656880a6bdfa0" +dependencies = [ + "base64 0.22.1", + "bytes", + "futures-channel", + "futures-util", + "http 1.4.0", + "http-body 1.0.1", + "hyper 1.8.1", + "ipnet", + "libc", + "percent-encoding", + "pin-project-lite", + "socket2 0.6.2", + "tokio", + "tower-service", + "tracing", +] + +[[package]] +name = "iana-time-zone" +version = "0.1.65" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "log", + "wasm-bindgen", + "windows-core", +] + +[[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 = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locid" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_locid_transform" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_locid_transform_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_locid_transform_data" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7515e6d781098bf9f7205ab3fc7e9709d34554ae0b21ddbcb5febfa4bc7df11d" + +[[package]] +name = "icu_normalizer" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "utf16_iter", + "utf8_iter", + "write16", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5e8338228bdc8ab83303f16b797e177953730f601a96c25d10cb3ab0daa0cb7" + +[[package]] +name = "icu_properties" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_locid_transform", + "icu_properties_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85fb8799753b75aee8d2a21d7c14d9f38921b54b3dbda10f5a3c7a7b82dba5e2" + +[[package]] +name = "icu_provider" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_provider_macros", + "stable_deref_trait", + "tinystr", + "writeable", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_provider_macros" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "idna" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + +[[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.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" +dependencies = [ + "icu_normalizer", + "icu_properties", +] + +[[package]] +name = "indexmap" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +dependencies = [ + "autocfg", + "hashbrown 0.12.3", +] + +[[package]] +name = "indexmap" +version = "2.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b0f83760fb341a774ed326568e19f5a863af4a952def8c39f9ab92fd95b88e5" +dependencies = [ + "equivalent", + "hashbrown 0.16.1", + "serde", + "serde_core", +] + +[[package]] +name = "indoc" +version = "2.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79cf5c93f93228cf8efb3ba362535fb11199ac548a09ce117c9b1adc3030d706" +dependencies = [ + "rustversion", +] + +[[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.117", +] + +[[package]] +name = "ipnet" +version = "2.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d98f6fed1fde3f8c21bc40a1abb88dd75e67924f9cffc3ef95607bad8017f8e2" + +[[package]] +name = "iri-string" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c91338f0783edbd6195decb37bae672fd3b165faffb89bf7b9e6942f8b1a731a" +dependencies = [ + "memchr", + "serde", +] + +[[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.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" +dependencies = [ + "either", +] + +[[package]] +name = "itertools" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" +dependencies = [ + "either", +] + +[[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.91" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b49715b7073f385ba4bc528e5747d02e66cb39c6146efb66b781f131f0fb399c" +dependencies = [ + "once_cell", + "wasm-bindgen", +] + +[[package]] +name = "json5" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96b0db21af676c1ce64250b5f40f3ce2cf27e4e47cb91ed91eb6fe9350b430c1" +dependencies = [ + "pest", + "pest_derive", + "serde", +] + +[[package]] +name = "jsonwebtoken" +version = "9.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a87cc7a48537badeae96744432de36f4be2b4a34a05a5ef32e9dd8a1c169dde" +dependencies = [ + "base64 0.22.1", + "js-sys", + "pem", + "ring", + "serde", + "serde_json", + "simple_asn1", +] + +[[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" +dependencies = [ + "spin", +] + +[[package]] +name = "lexical-core" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d8d125a277f807e55a77304455eb7b1cb52f2b18c143b60e766c120bd64a594" +dependencies = [ + "lexical-parse-float", + "lexical-parse-integer", + "lexical-util", + "lexical-write-float", + "lexical-write-integer", +] + +[[package]] +name = "lexical-parse-float" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52a9f232fbd6f550bc0137dcb5f99ab674071ac2d690ac69704593cb4abbea56" +dependencies = [ + "lexical-parse-integer", + "lexical-util", +] + +[[package]] +name = "lexical-parse-integer" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a7a039f8fb9c19c996cd7b2fcce303c1b2874fe1aca544edc85c4a5f8489b34" +dependencies = [ + "lexical-util", +] + +[[package]] +name = "lexical-util" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2604dd126bb14f13fb5d1bd6a66155079cb9fa655b37f875b3a742c705dbed17" + +[[package]] +name = "lexical-write-float" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50c438c87c013188d415fbabbb1dceb44249ab81664efbd31b14ae55dabb6361" +dependencies = [ + "lexical-util", + "lexical-write-integer", +] + +[[package]] +name = "lexical-write-integer" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "409851a618475d2d5796377cad353802345cba92c867d9fbcde9cf4eac4e14df" +dependencies = [ + "lexical-util", +] + +[[package]] +name = "libc" +version = "0.2.182" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6800badb6cb2082ffd7b6a67e6125bb39f18782f793520caee8cb8846be06112" + +[[package]] +name = "libm" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" + +[[package]] +name = "libredox" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1744e39d1d6a9948f4f388969627434e31128196de472883b39f148769bfe30a" +dependencies = [ + "bitflags 2.11.0", + "libc", + "plain", + "redox_syscall 0.7.3", +] + +[[package]] +name = "libsqlite3-sys" +version = "0.30.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e99fb7a497b1e3339bc746195567ed8d3e24945ecd636e3619d20b9de9e9149" +dependencies = [ + "pkg-config", + "vcpkg", +] + +[[package]] +name = "linux-raw-sys" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" + +[[package]] +name = "litemap" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ee93343901ab17bd981295f2cf0026d4ad018c7c31ba84549a4ddbb47a45104" + +[[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 = "lru-slab" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" + +[[package]] +name = "matchers" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1525a2a28c7f4fa0fc98bb91ae755d1e2d1505079e05539e35bc876b5d65ae9" +dependencies = [ + "regex-automata", +] + +[[package]] +name = "matchit" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94" + +[[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.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" + +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "mime_guess" +version = "2.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e" +dependencies = [ + "mime", + "unicase", +] + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "miniz_oxide" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" +dependencies = [ + "adler2", + "simd-adler32", +] + +[[package]] +name = "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 = "mockall" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43766c2b5203b10de348ffe19f7e54564b64f3d6018ff7648d1e2d6d3a0f0a48" +dependencies = [ + "cfg-if", + "downcast", + "fragile", + "lazy_static", + "mockall_derive", + "predicates", + "predicates-tree", +] + +[[package]] +name = "mockall_derive" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af7cbce79ec385a1d4f54baa90a76401eb15d9cab93685f62e7e9f942aa00ae2" +dependencies = [ + "cfg-if", + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "multimap" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d87ecb2933e8aeadb3e3a02b828fed80a7528047e68b4f424523a0981a3a084" + +[[package]] +name = "native-tls" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "465500e14ea162429d264d44189adc38b199b62b1c21eea9f69e4b73cb03bbf2" +dependencies = [ + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", +] + +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "nu-ansi-term" +version = "0.50.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "num-bigint" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] +name = "num-bigint-dig" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e661dda6640fad38e827a6d4a310ff4763082116fe217f279885c97f511bb0b7" +dependencies = [ + "lazy_static", + "libm", + "num-integer", + "num-iter", + "num-traits", + "rand 0.8.5", + "smallvec", + "zeroize", +] + +[[package]] +name = "num-complex" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-conv" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf97ec579c3c42f953ef76dbf8d55ac91fb219dde70e49aa4a6b7d74e9919050" + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-iter" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", + "libm", +] + +[[package]] +name = "nxmesh-agent" +version = "0.1.0" +dependencies = [ + "async-trait", + "axum 0.7.9", + "chrono", + "config", + "futures", + "handlebars", + "hex", + "hostname", + "mockall", + "nxmesh-core", + "nxmesh-proto", + "reqwest", + "serde", + "serde_json", + "sha2", + "thiserror 1.0.69", + "tokio", + "tokio-test", + "toml", + "tonic", + "tracing", + "tracing-subscriber", + "uuid", +] + +[[package]] +name = "nxmesh-cli" +version = "0.1.0" +dependencies = [ + "clap", + "config", + "nxmesh-core", + "reqwest", + "serde", + "serde_json", + "thiserror 1.0.69", + "tokio", + "tokio-test", + "tracing", + "tracing-subscriber", +] + +[[package]] +name = "nxmesh-core" +version = "0.1.0" +dependencies = [ + "chrono", + "serde", + "serde_json", + "thiserror 1.0.69", + "tokio-test", + "uuid", +] + +[[package]] +name = "nxmesh-master" +version = "0.1.0" +dependencies = [ + "argon2", + "async-stream", + "async-trait", + "axum 0.7.9", + "chrono", + "config", + "futures", + "handlebars", + "hex", + "jsonwebtoken", + "mockall", + "nxmesh-core", + "nxmesh-proto", + "sea-orm", + "sea-orm-migration 2.0.0-rc.35", + "serde", + "serde_json", + "sha2", + "thiserror 1.0.69", + "tokio", + "tokio-test", + "toml", + "tonic", + "tower 0.4.13", + "tower-http 0.5.2", + "tracing", + "tracing-subscriber", + "utoipa", + "utoipa-swagger-ui", + "uuid", + "validator", +] + +[[package]] +name = "nxmesh-proto" +version = "0.1.0" +dependencies = [ + "prost", + "tonic", + "tonic-build", +] + +[[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 = "openssl" +version = "0.10.75" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08838db121398ad17ab8531ce9de97b244589089e290a384c900cb9ff7434328" +dependencies = [ + "bitflags 2.11.0", + "cfg-if", + "foreign-types", + "libc", + "once_cell", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "openssl-probe" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe" + +[[package]] +name = "openssl-sys" +version = "0.9.111" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82cab2d520aa75e3c58898289429321eb788c3106963d0dc886ec7a5f4adc321" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + +[[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 = "ordered-multimap" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49203cdcae0030493bad186b28da2fa25645fa276a51b6fec8010d281e02ef79" +dependencies = [ + "dlv-list", + "hashbrown 0.14.5", +] + +[[package]] +name = "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.117", +] + +[[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 0.2.1", +] + +[[package]] +name = "password-hash" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "346f04948ba92c43e8469c1ee6736c7563d71012b17d40745260fe106aac2166" +dependencies = [ + "base64ct", + "rand_core 0.6.4", + "subtle", +] + +[[package]] +name = "pathdiff" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df94ce210e5bc13cb6651479fa48d14f601d9858cfe0467f43ae157023b938d3" + +[[package]] +name = "pem" +version = "3.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d30c53c26bc5b31a98cd02d20f25a7c8567146caf63ed593a9d87b2775291be" +dependencies = [ + "base64 0.22.1", + "serde_core", +] + +[[package]] +name = "pem-rfc7468" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412" +dependencies = [ + "base64ct", +] + +[[package]] +name = "percent-encoding" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" + +[[package]] +name = "pest" +version = "2.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21e0a3a33733faeaf8651dfee72dd0f388f0c8e5ad496a3478fa5a922f49cfa8" +dependencies = [ + "memchr", + "thiserror 2.0.18", + "ucd-trie", +] + +[[package]] +name = "pest_derive" +version = "2.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc58706f770acb1dbd0973e6530a3cff4746fb721207feb3a8a6064cd0b6c663" +dependencies = [ + "pest", + "pest_generator", +] + +[[package]] +name = "pest_generator" +version = "2.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d4f36811dfe07f7b8573462465d5cb8965fffc2e71ae377a33aecf14c2c9a2f" +dependencies = [ + "pest", + "pest_meta", + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "pest_meta" +version = "2.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42919b05089acbd0a5dcd5405fb304d17d1053847b81163d09c4ad18ce8e8420" +dependencies = [ + "pest", + "sha2", +] + +[[package]] +name = "petgraph" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db" +dependencies = [ + "fixedbitset", + "indexmap 2.11.4", +] + +[[package]] +name = "pgvector" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc58e2d255979a31caa7cabfa7aac654af0354220719ab7a68520ae7a91e8c0b" +dependencies = [ + "serde", +] + +[[package]] +name = "pin-project" +version = "1.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1749c7ed4bcaf4c3d0a3efc28538844fb29bcdd7d2b67b2be7e20ba861ff517" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b20ed30f105399776b9c883e68e536ef602a16ae6f596d2c473591d6ad64c6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "piper" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c835479a4443ded371d6c535cbfd8d31ad92c5d23ae9770a61bc155e4992a3c1" +dependencies = [ + "atomic-waker", + "fastrand", + "futures-io", +] + +[[package]] +name = "pkcs1" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8ffb9f10fa047879315e6625af03c164b16962a5368d724ed16323b68ace47f" +dependencies = [ + "der", + "pkcs8", + "spki", +] + +[[package]] +name = "pkcs8" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +dependencies = [ + "der", + "spki", +] + +[[package]] +name = "pkg-config" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" + +[[package]] +name = "plain" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" + +[[package]] +name = "pluralizer" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b3eba432a00a1f6c16f39147847a870e94e2e9b992759b503e330efec778cbe" +dependencies = [ + "once_cell", + "regex", +] + +[[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 = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + +[[package]] +name = "ppv-lite86" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "predicates" +version = "3.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ada8f2932f28a27ee7b70dd6c1c39ea0675c55a36879ab92f3a715eaa1e63cfe" +dependencies = [ + "anstyle", + "predicates-core", +] + +[[package]] +name = "predicates-core" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cad38746f3166b4031b1a0d39ad9f954dd291e7854fcc0eed52ee41a0b50d144" + +[[package]] +name = "predicates-tree" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0de1b847b39c8131db0467e9df1ff60e6d0562ab8e9a16e568ad0fdb372e2f2" +dependencies = [ + "predicates-core", + "termtree", +] + +[[package]] +name = "prettyplease" +version = "0.2.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" +dependencies = [ + "proc-macro2", + "syn 2.0.117", +] + +[[package]] +name = "proc-macro-crate" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "219cb19e96be00ab2e37d6e299658a0cfa83e52429179969b0f0121b4ac46983" +dependencies = [ + "toml_edit 0.23.10+spec-1.0.0", +] + +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn 1.0.109", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + +[[package]] +name = "proc-macro-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.117", +] + +[[package]] +name = "proc-macro2" +version = "1.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "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.117", + "version_check", + "yansi", +] + +[[package]] +name = "prost" +version = "0.12.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "deb1435c188b76130da55f17a466d252ff7b1418b2ad3e037d127b94e3411f29" +dependencies = [ + "bytes", + "prost-derive", +] + +[[package]] +name = "prost-build" +version = "0.12.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22505a5c94da8e3b7c2996394d1c933236c4d743e81a410bcca4e6989fc066a4" +dependencies = [ + "bytes", + "heck 0.5.0", + "itertools 0.12.1", + "log", + "multimap", + "once_cell", + "petgraph", + "prettyplease", + "prost", + "prost-types", + "regex", + "syn 2.0.117", + "tempfile", +] + +[[package]] +name = "prost-derive" +version = "0.12.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81bddcdb20abf9501610992b6759a4c888aef7d1a7247ef75e2404275ac24af1" +dependencies = [ + "anyhow", + "itertools 0.12.1", + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "prost-types" +version = "0.12.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9091c90b0a32608e984ff2fa4091273cbdd755d54935c51d520887f4a1dbd5b0" +dependencies = [ + "prost", +] + +[[package]] +name = "ptr_meta" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0738ccf7ea06b608c10564b31debd4f5bc5e197fc8bfe088f68ae5ce81e7a4f1" +dependencies = [ + "ptr_meta_derive", +] + +[[package]] +name = "ptr_meta_derive" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16b845dbfca988fa33db069c0e230574d15a3088f147a87b64c7589eb662c9ac" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "quinn" +version = "0.11.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e20a958963c291dc322d98411f541009df2ced7b5a4f2bd52337638cfccf20" +dependencies = [ + "bytes", + "cfg_aliases", + "pin-project-lite", + "quinn-proto", + "quinn-udp", + "rustc-hash", + "rustls", + "socket2 0.6.2", + "thiserror 2.0.18", + "tokio", + "tracing", + "web-time", +] + +[[package]] +name = "quinn-proto" +version = "0.11.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1906b49b0c3bc04b5fe5d86a77925ae6524a19b816ae38ce1e426255f1d8a31" +dependencies = [ + "bytes", + "getrandom 0.3.4", + "lru-slab", + "rand 0.9.2", + "ring", + "rustc-hash", + "rustls", + "rustls-pki-types", + "slab", + "thiserror 2.0.18", + "tinyvec", + "tracing", + "web-time", +] + +[[package]] +name = "quinn-udp" +version = "0.5.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "addec6a0dcad8a8d96a771f815f0eaf55f9d1805756410b39f5fa81332574cbd" +dependencies = [ + "cfg_aliases", + "libc", + "once_cell", + "socket2 0.6.2", + "tracing", + "windows-sys 0.60.2", +] + +[[package]] +name = "quote" +version = "1.0.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21b2ebcf727b7760c461f091f9f0f539b77b8e87f2fd88131e7f1b433b3cece4" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + +[[package]] +name = "radium" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha 0.3.1", + "rand_core 0.6.4", +] + +[[package]] +name = "rand" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" +dependencies = [ + "rand_chacha 0.9.0", + "rand_core 0.9.5", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_chacha" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" +dependencies = [ + "ppv-lite86", + "rand_core 0.9.5", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom 0.2.17", +] + +[[package]] +name = "rand_core" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" +dependencies = [ + "getrandom 0.3.4", +] + +[[package]] +name = "redox_syscall" +version = "0.5.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" +dependencies = [ + "bitflags 2.11.0", +] + +[[package]] +name = "redox_syscall" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce70a74e890531977d37e532c34d45e9055d2409ed08ddba14529471ed0be16" +dependencies = [ + "bitflags 2.11.0", +] + +[[package]] +name = "regex" +version = "1.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a" + +[[package]] +name = "rend" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71fe3824f5629716b1589be05dacd749f6aa084c87e00e016714a8cdfccc997c" +dependencies = [ + "bytecheck", +] + +[[package]] +name = "reqwest" +version = "0.12.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eddd3ca559203180a307f12d114c268abf583f59b03cb906fd0b3ff8646c1147" +dependencies = [ + "base64 0.22.1", + "bytes", + "futures-core", + "http 1.4.0", + "http-body 1.0.1", + "http-body-util", + "hyper 1.8.1", + "hyper-rustls", + "hyper-util", + "js-sys", + "log", + "percent-encoding", + "pin-project-lite", + "quinn", + "rustls", + "rustls-pki-types", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper 1.0.2", + "tokio", + "tokio-rustls", + "tower 0.5.3", + "tower-http 0.6.8", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "webpki-roots", +] + +[[package]] +name = "ring" +version = "0.17.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" +dependencies = [ + "cc", + "cfg-if", + "getrandom 0.2.17", + "libc", + "untrusted", + "windows-sys 0.52.0", +] + +[[package]] +name = "rkyv" +version = "0.7.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2297bf9c81a3f0dc96bc9521370b88f054168c29826a75e89c55ff196e7ed6a1" +dependencies = [ + "bitvec", + "bytecheck", + "bytes", + "hashbrown 0.12.3", + "ptr_meta", + "rend", + "rkyv_derive", + "seahash", + "tinyvec", + "uuid", +] + +[[package]] +name = "rkyv_derive" +version = "0.7.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84d7b42d4b8d06048d3ac8db0eb31bcb942cbeb709f0b5f2b2ebde398d3038f5" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ron" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b91f7eff05f748767f183df4320a63d6936e9c6107d97c9e6bdd9784f4289c94" +dependencies = [ + "base64 0.21.7", + "bitflags 2.11.0", + "serde", + "serde_derive", +] + +[[package]] +name = "rsa" +version = "0.9.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8573f03f5883dcaebdfcf4725caa1ecb9c15b2ef50c43a07b816e06799bb12d" +dependencies = [ + "const-oid", + "digest", + "num-bigint-dig", + "num-integer", + "num-traits", + "pkcs1", + "pkcs8", + "rand_core 0.6.4", + "signature", + "spki", + "subtle", + "zeroize", +] + +[[package]] +name = "rust-embed" +version = "8.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04113cb9355a377d83f06ef1f0a45b8ab8cd7d8b1288160717d66df5c7988d27" +dependencies = [ + "rust-embed-impl", + "rust-embed-utils", + "walkdir", +] + +[[package]] +name = "rust-embed-impl" +version = "8.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da0902e4c7c8e997159ab384e6d0fc91c221375f6894346ae107f47dd0f3ccaa" +dependencies = [ + "proc-macro2", + "quote", + "rust-embed-utils", + "syn 2.0.117", + "walkdir", +] + +[[package]] +name = "rust-embed-utils" +version = "8.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5bcdef0be6fe7f6fa333b1073c949729274b05f123a0ad7efcb8efd878e5c3b1" +dependencies = [ + "sha2", + "walkdir", +] + +[[package]] +name = "rust-ini" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e0698206bcb8882bf2a9ecb4c1e7785db57ff052297085a6efd4fe42302068a" +dependencies = [ + "cfg-if", + "ordered-multimap", +] + +[[package]] +name = "rust_decimal" +version = "1.40.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61f703d19852dbf87cbc513643fa81428361eb6940f1ac14fd58155d295a3eb0" +dependencies = [ + "arrayvec", + "borsh", + "bytes", + "num-traits", + "rand 0.8.5", + "rkyv", + "serde", + "serde_json", +] + +[[package]] +name = "rustc-hash" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" + +[[package]] +name = "rustix" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" +dependencies = [ + "bitflags 2.11.0", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.61.2", +] + +[[package]] +name = "rustls" +version = "0.23.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "758025cb5fccfd3bc2fd74708fd4682be41d99e5dff73c377c0646c6012c73a4" +dependencies = [ + "once_cell", + "ring", + "rustls-pki-types", + "rustls-webpki", + "subtle", + "zeroize", +] + +[[package]] +name = "rustls-pki-types" +version = "1.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be040f8b0a225e40375822a563fa9524378b9d63112f53e19ffff34df5d33fdd" +dependencies = [ + "web-time", + "zeroize", +] + +[[package]] +name = "rustls-webpki" +version = "0.103.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7df23109aa6c1567d1c575b9952556388da57401e4ace1d15f79eedad0d8f53" +dependencies = [ + "ring", + "rustls-pki-types", + "untrusted", +] + +[[package]] +name = "rustversion" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" + +[[package]] +name = "ryu" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "schannel" +version = "0.1.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "891d81b926048e76efe18581bf793546b4c0eaf8448d72be8de2bbee5fd166e1" +dependencies = [ + "windows-sys 0.61.2", +] + +[[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.117", +] + +[[package]] +name = "sea-orm" +version = "2.0.0-rc.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41c847ddcc05ba1c4a8ad6bf781ac8d3750123f6e95642c2268b0551101931de" +dependencies = [ + "async-stream", + "async-trait", + "bigdecimal", + "chrono", + "derive_more", + "futures-util", + "itertools 0.14.0", + "log", + "ouroboros", + "pgvector", + "rust_decimal", + "sea-orm-arrow", + "sea-orm-macros", + "sea-query", + "sea-query-sqlx", + "sea-schema", + "serde", + "serde_json", + "sqlx", + "strum", + "thiserror 2.0.18", + "time", + "tracing", + "url", + "uuid", +] + +[[package]] +name = "sea-orm-arrow" +version = "2.0.0-rc.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c2eee8405f16c1f337fe3a83389361caea83c928d14dbd666a480407072c365" +dependencies = [ + "arrow", + "sea-query", + "thiserror 2.0.18", +] + +[[package]] +name = "sea-orm-cli" +version = "2.0.0-rc.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19cac0ea172be551704a2c1dba1bea5a3057b2ed70b8a2819f965c501d1ffc07" +dependencies = [ + "chrono", + "clap", + "dotenvy", + "glob", + "indoc", + "regex", + "sea-schema", + "sqlx", + "tokio", + "tracing", + "tracing-subscriber", + "url", +] + +[[package]] +name = "sea-orm-macros" +version = "2.0.0-rc.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a172f9ceaceafa0fe40f6f15df0231750755284c80bd8ba98d10d5ae611ecaf0" +dependencies = [ + "heck 0.5.0", + "itertools 0.14.0", + "pluralizer", + "proc-macro2", + "quote", + "sea-bae", + "syn 2.0.117", + "unicode-ident", +] + +[[package]] +name = "sea-orm-migration" +version = "0.1.0" +dependencies = [ + "async-std", + "sea-orm", + "sea-orm-migration 2.0.0-rc.35", +] + +[[package]] +name = "sea-orm-migration" +version = "2.0.0-rc.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c011930d0cd0d0157d93ef9ad1fdd7a4002f28c082d0c49fabc5f0f445c8e925" +dependencies = [ + "async-trait", + "clap", + "dotenvy", + "sea-orm", + "sea-orm-cli", + "sea-schema", + "tracing", + "tracing-subscriber", +] + +[[package]] +name = "sea-query" +version = "1.0.0-rc.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58decdaaaf2a698170af2fa1b2e8f7b43a970e7768bf18aebaab113bada46354" +dependencies = [ + "chrono", + "inherent", + "ordered-float", + "rust_decimal", + "sea-query-derive", + "serde_json", + "time", + "uuid", +] + +[[package]] +name = "sea-query-derive" +version = "1.0.0-rc.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d88ad44b6ad9788c8b9476b6b91f94c7461d1e19d39cd8ea37838b1e6ff5aa8" +dependencies = [ + "darling", + "heck 0.4.1", + "proc-macro2", + "quote", + "syn 2.0.117", + "thiserror 2.0.18", +] + +[[package]] +name = "sea-query-sqlx" +version = "0.8.0-rc.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4377164b09a11bb692dec6966eb0e6908d63d768defef0be689b39e02cf8544" +dependencies = [ + "sea-query", + "sqlx", +] + +[[package]] +name = "sea-schema" +version = "0.17.0-rc.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b363dd21c20fe4d1488819cb2bc7f8d4696c62dd9f39554f97639f54d57dd0ab" +dependencies = [ + "async-trait", + "sea-query", + "sea-query-sqlx", + "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.117", +] + +[[package]] +name = "seahash" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b" + +[[package]] +name = "security-framework" +version = "3.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d17b898a6d6948c3a8ee4372c17cb384f90d2e6e912ef00895b14fd7ab54ec38" +dependencies = [ + "bitflags 2.11.0", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce2691df843ecc5d231c0b14ece2acc3efb62c0a398c7e1d875f3983ce020e3" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "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.117", +] + +[[package]] +name = "serde_json" +version = "1.0.149" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + +[[package]] +name = "serde_path_to_error" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10a9ff822e371bb5403e391ecd83e182e0e77ba7f6fe0160b795797109d1b457" +dependencies = [ + "itoa", + "serde", + "serde_core", +] + +[[package]] +name = "serde_spanned" +version = "0.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "sha1" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "sha2" +version = "0.10.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "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 = "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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" +dependencies = [ + "digest", + "rand_core 0.6.4", +] + +[[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.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d585997b0ac10be3c5ee635f1bab02d512760d14b7c468801ac8a01d9ae5f1d" +dependencies = [ + "num-bigint", + "num-traits", + "thiserror 2.0.18", + "time", +] + +[[package]] +name = "slab" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" + +[[package]] +name = "smallvec" +version = "1.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" +dependencies = [ + "serde", +] + +[[package]] +name = "socket2" +version = "0.5.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "socket2" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86f4aa3ad99f2088c990dfa82d367e19cb29268ed67c574d10d0a4bfe71f07e0" +dependencies = [ + "libc", + "windows-sys 0.60.2", +] + +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" +dependencies = [ + "lock_api", +] + +[[package]] +name = "spki" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" +dependencies = [ + "base64ct", + "der", +] + +[[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-mysql", + "sqlx-postgres", + "sqlx-sqlite", +] + +[[package]] +name = "sqlx-core" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee6798b1838b6a0f69c007c133b8df5866302197e404e8b6ee8ed3e3a5e68dc6" +dependencies = [ + "base64 0.22.1", + "bytes", + "chrono", + "crc", + "crossbeam-queue", + "either", + "event-listener 5.4.1", + "futures-core", + "futures-intrusive", + "futures-io", + "futures-util", + "hashbrown 0.15.5", + "hashlink 0.10.0", + "indexmap 2.11.4", + "log", + "memchr", + "native-tls", + "once_cell", + "percent-encoding", + "rust_decimal", + "serde", + "serde_json", + "sha2", + "smallvec", + "thiserror 2.0.18", + "time", + "tokio", + "tokio-stream", + "tracing", + "url", + "uuid", +] + +[[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.117", +] + +[[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-mysql", + "sqlx-postgres", + "sqlx-sqlite", + "syn 2.0.117", + "tokio", + "url", +] + +[[package]] +name = "sqlx-mysql" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa003f0038df784eb8fecbbac13affe3da23b45194bd57dba231c8f48199c526" +dependencies = [ + "atoi", + "base64 0.22.1", + "bitflags 2.11.0", + "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.18", + "time", + "tracing", + "uuid", + "whoami", +] + +[[package]] +name = "sqlx-postgres" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db58fcd5a53cf07c184b154801ff91347e4c30d17a3562a635ff028ad5deda46" +dependencies = [ + "atoi", + "base64 0.22.1", + "bitflags 2.11.0", + "byteorder", + "chrono", + "crc", + "dotenvy", + "etcetera", + "futures-channel", + "futures-core", + "futures-util", + "hex", + "hkdf", + "hmac", + "home", + "itoa", + "log", + "md-5", + "memchr", + "once_cell", + "rand 0.8.5", + "rust_decimal", + "serde", + "serde_json", + "sha2", + "smallvec", + "sqlx-core", + "stringprep", + "thiserror 2.0.18", + "time", + "tracing", + "uuid", + "whoami", +] + +[[package]] +name = "sqlx-sqlite" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2d12fe70b2c1b4401038055f90f151b78208de1f9f89a7dbfd41587a10c3eea" +dependencies = [ + "atoi", + "chrono", + "flume", + "futures-channel", + "futures-core", + "futures-executor", + "futures-intrusive", + "futures-util", + "libsqlite3-sys", + "log", + "percent-encoding", + "serde", + "serde_urlencoded", + "sqlx-core", + "thiserror 2.0.18", + "time", + "tracing", + "url", + "uuid", +] + +[[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.27.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af23d6f6c1a224baef9d3f61e287d2761385a5b88fdab4eb4c6f11aeb54c4bcf" + +[[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.117" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "sync_wrapper" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" + +[[package]] +name = "sync_wrapper" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" +dependencies = [ + "futures-core", +] + +[[package]] +name = "synstructure" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + +[[package]] +name = "tempfile" +version = "3.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82a72c767771b47409d2345987fda8628641887d5466101319899796367354a0" +dependencies = [ + "fastrand", + "getrandom 0.3.4", + "once_cell", + "rustix", + "windows-sys 0.61.2", +] + +[[package]] +name = "termtree" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f50febec83f5ee1df3015341d8bd429f2d1cc62bcba7ea2076759d315084683" + +[[package]] +name = "thiserror" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl 1.0.69", +] + +[[package]] +name = "thiserror" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" +dependencies = [ + "thiserror-impl 2.0.18", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "thread_local" +version = "1.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "time" +version = "0.3.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "743bd48c283afc0388f9b8827b976905fb217ad9e647fae3a379a9283c4def2c" +dependencies = [ + "deranged", + "itoa", + "num-conv", + "powerfmt", + "serde_core", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7694e1cfe791f8d31026952abf09c69ca6f6fa4e1a1229e18988f06a04a12dca" + +[[package]] +name = "time-macros" +version = "0.2.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e70e4c5a0e0a8a4823ad65dfe1a6930e4f4d756dcd9dd7939022b5e8c501215" +dependencies = [ + "num-conv", + "time-core", +] + +[[package]] +name = "tiny-keccak" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" +dependencies = [ + "crunchy", +] + +[[package]] +name = "tinystr" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" +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", + "parking_lot", + "pin-project-lite", + "signal-hook-registry", + "socket2 0.6.2", + "tokio-macros", + "windows-sys 0.61.2", +] + +[[package]] +name = "tokio-io-timeout" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bd86198d9ee903fedd2f9a2e72014287c0d9167e4ae43b5853007205dda1b76" +dependencies = [ + "pin-project-lite", + "tokio", +] + +[[package]] +name = "tokio-macros" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c55a2eff8b69ce66c84f85e1da1c233edc36ceb85a2058d11b0d6a3c7e7569c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "tokio-rustls" +version = "0.26.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61" +dependencies = [ + "rustls", + "tokio", +] + +[[package]] +name = "tokio-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-test" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f6d24790a10a7af737693a3e8f1d03faef7e6ca0cc99aae5066f533766de545" +dependencies = [ + "futures-core", + "tokio", + "tokio-stream", +] + +[[package]] +name = "tokio-tungstenite" +version = "0.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edc5f74e248dc973e0dbb7b74c7e0d6fcc301c694ff50049504004ef4d0cdcd9" +dependencies = [ + "futures-util", + "log", + "tokio", + "tungstenite", +] + +[[package]] +name = "tokio-util" +version = "0.7.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ae9cec805b01e8fc3fd2fe289f89149a9b66dd16786abd8b19cfa7b48cb0098" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "toml" +version = "0.8.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime 0.6.11", + "toml_edit 0.22.27", +] + +[[package]] +name = "toml_datetime" +version = "0.6.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_datetime" +version = "0.7.5+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92e1cfed4a3038bc5a127e35a2d360f145e1f4b971b551a2ba5fd7aedf7e1347" +dependencies = [ + "serde_core", +] + +[[package]] +name = "toml_edit" +version = "0.22.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" +dependencies = [ + "indexmap 2.11.4", + "serde", + "serde_spanned", + "toml_datetime 0.6.11", + "toml_write", + "winnow", +] + +[[package]] +name = "toml_edit" +version = "0.23.10+spec-1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84c8b9f757e028cee9fa244aea147aab2a9ec09d5325a9b01e0a49730c2b5269" +dependencies = [ + "indexmap 2.11.4", + "toml_datetime 0.7.5+spec-1.1.0", + "toml_parser", + "winnow", +] + +[[package]] +name = "toml_parser" +version = "1.0.9+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "702d4415e08923e7e1ef96cd5727c0dfed80b4d2fa25db9647fe5eb6f7c5a4c4" +dependencies = [ + "winnow", +] + +[[package]] +name = "toml_write" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801" + +[[package]] +name = "tonic" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76c4eb7a4e9ef9d4763600161f12f5070b92a578e1b634db88a6887844c91a13" +dependencies = [ + "async-stream", + "async-trait", + "axum 0.6.20", + "base64 0.21.7", + "bytes", + "h2", + "http 0.2.12", + "http-body 0.4.6", + "hyper 0.14.32", + "hyper-timeout", + "percent-encoding", + "pin-project", + "prost", + "tokio", + "tokio-stream", + "tower 0.4.13", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tonic-build" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4ef6dd70a610078cb4e338a0f79d06bc759ff1b22d2120c2ff02ae264ba9c2" +dependencies = [ + "prettyplease", + "proc-macro2", + "prost-build", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "tower" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" +dependencies = [ + "futures-core", + "futures-util", + "indexmap 1.9.3", + "pin-project", + "pin-project-lite", + "rand 0.8.5", + "slab", + "tokio", + "tokio-util", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebe5ef63511595f1344e2d5cfa636d973292adc0eec1f0ad45fae9f0851ab1d4" +dependencies = [ + "futures-core", + "futures-util", + "pin-project-lite", + "sync_wrapper 1.0.2", + "tokio", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower-http" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e9cd434a998747dd2c4276bc96ee2e0c7a2eadf3cae88e52be55a05fa9053f5" +dependencies = [ + "bitflags 2.11.0", + "bytes", + "futures-util", + "http 1.4.0", + "http-body 1.0.1", + "http-body-util", + "http-range-header", + "httpdate", + "mime", + "mime_guess", + "percent-encoding", + "pin-project-lite", + "tokio", + "tokio-util", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower-http" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4e6559d53cc268e5031cd8429d05415bc4cb4aefc4aa5d6cc35fbf5b924a1f8" +dependencies = [ + "bitflags 2.11.0", + "bytes", + "futures-util", + "http 1.4.0", + "http-body 1.0.1", + "iri-string", + "pin-project-lite", + "tower 0.5.3", + "tower-layer", + "tower-service", +] + +[[package]] +name = "tower-layer" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" + +[[package]] +name = "tower-service" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" + +[[package]] +name = "tracing" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" +dependencies = [ + "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.117", +] + +[[package]] +name = "tracing-core" +version = "0.1.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" +dependencies = [ + "once_cell", + "valuable", +] + +[[package]] +name = "tracing-log" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" +dependencies = [ + "log", + "once_cell", + "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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f30143827ddab0d256fd843b7a66d164e9f271cfa0dde49142c5ca0ca291f1e" +dependencies = [ + "matchers", + "nu-ansi-term", + "once_cell", + "regex-automata", + "serde", + "serde_json", + "sharded-slab", + "smallvec", + "thread_local", + "tracing", + "tracing-core", + "tracing-log", + "tracing-serde", +] + +[[package]] +name = "try-lock" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" + +[[package]] +name = "tungstenite" +version = "0.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18e5b8366ee7a95b16d32197d0b2604b43a0be89dc5fac9f8e96ccafbaedda8a" +dependencies = [ + "byteorder", + "bytes", + "data-encoding", + "http 1.4.0", + "httparse", + "log", + "rand 0.8.5", + "sha1", + "thiserror 1.0.69", + "utf-8", +] + +[[package]] +name = "typenum" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" + +[[package]] +name = "ucd-trie" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971" + +[[package]] +name = "unicase" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbc4bc3a9f746d862c45cb89d705aa10f187bb96c76001afab07a0d35ce60142" + +[[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.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" + +[[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-segmentation" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" + +[[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 1.1.0", + "percent-encoding", + "serde", +] + +[[package]] +name = "utf-8" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" + +[[package]] +name = "utf16_iter" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" + +[[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 = "utoipa" +version = "4.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5afb1a60e207dca502682537fefcfd9921e71d0b83e9576060f09abc6efab23" +dependencies = [ + "indexmap 2.11.4", + "serde", + "serde_json", + "utoipa-gen", +] + +[[package]] +name = "utoipa-gen" +version = "4.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20c24e8ab68ff9ee746aad22d39b5535601e6416d1b0feeabf78be986a5c4392" +dependencies = [ + "proc-macro-error", + "proc-macro2", + "quote", + "regex", + "syn 2.0.117", +] + +[[package]] +name = "utoipa-swagger-ui" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b39868d43c011961e04b41623e050aedf2cc93652562ff7935ce0f819aaf2da" +dependencies = [ + "axum 0.7.9", + "mime_guess", + "regex", + "rust-embed", + "serde", + "serde_json", + "utoipa", + "zip", +] + +[[package]] +name = "uuid" +version = "1.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee48d38b119b0cd71fe4141b30f5ba9c7c5d9f4e7a3a8b4a674e4b6ef789976f" +dependencies = [ + "getrandom 0.3.4", + "js-sys", + "serde_core", + "wasm-bindgen", +] + +[[package]] +name = "validator" +version = "0.18.1" +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", +] + +[[package]] +name = "validator_derive" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df0bcf92720c40105ac4b2dda2a4ea3aa717d4d6a862cc217da653a4bd5c6b10" +dependencies = [ + "darling", + "once_cell", + "proc-macro-error", + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "valuable" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" + +[[package]] +name = "value-bag" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ba6f5989077681266825251a52748b8c1d8a4ad098cc37e440103d0ea717fc0" + +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + +[[package]] +name = "want" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" +dependencies = [ + "try-lock", +] + +[[package]] +name = "wasi" +version = "0.11.1+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" + +[[package]] +name = "wasip2" +version = "1.0.2+wasi-0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5" +dependencies = [ + "wit-bindgen", +] + +[[package]] +name = "wasite" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b" + +[[package]] +name = "wasm-bindgen" +version = "0.2.114" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6532f9a5c1ece3798cb1c2cfdba640b9b3ba884f5db45973a6f442510a87d38e" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.64" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9c5522b3a28661442748e09d40924dfb9ca614b21c00d3fd135720e48b67db8" +dependencies = [ + "cfg-if", + "futures-util", + "js-sys", + "once_cell", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.114" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18a2d50fcf105fb33bb15f00e7a77b772945a2ee45dcf454961fd843e74c18e6" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.114" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03ce4caeaac547cdf713d280eda22a730824dd11e6b8c3ca9e42247b25c631e3" +dependencies = [ + "bumpalo", + "proc-macro2", + "quote", + "syn 2.0.117", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.114" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75a326b8c223ee17883a4251907455a2431acc2791c98c26279376490c378c16" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "web-sys" +version = "0.3.91" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "854ba17bb104abfb26ba36da9729addc7ce7f06f5c0f90f3c391f8461cca21f9" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "web-time" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "webpki-roots" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22cfaf3c063993ff62e73cb4311efde4db1efb31ab78a3e5c457939ad5cc0bed" +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 = "winapi-util" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "windows-core" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-link 0.1.3", + "windows-result", + "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.117", +] + +[[package]] +name = "windows-interface" +version = "0.59.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "windows-link" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-result" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6" +dependencies = [ + "windows-link 0.1.3", +] + +[[package]] +name = "windows-strings" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57" +dependencies = [ + "windows-link 0.1.3", +] + +[[package]] +name = "windows-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 0.2.1", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm 0.52.6", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", +] + +[[package]] +name = "windows-targets" +version = "0.53.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" +dependencies = [ + "windows-link 0.2.1", + "windows_aarch64_gnullvm 0.53.1", + "windows_aarch64_msvc 0.53.1", + "windows_i686_gnu 0.53.1", + "windows_i686_gnullvm 0.53.1", + "windows_i686_msvc 0.53.1", + "windows_x86_64_gnu 0.53.1", + "windows_x86_64_gnullvm 0.53.1", + "windows_x86_64_msvc 0.53.1", +] + +[[package]] +name = "windows_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 = "winnow" +version = "0.7.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a5364e9d77fcdeeaa6062ced926ee3381faa2ee02d3eb83a5c27a8825540829" +dependencies = [ + "memchr", +] + +[[package]] +name = "wit-bindgen" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" + +[[package]] +name = "write16" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" + +[[package]] +name = "writeable" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" + +[[package]] +name = "wyz" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" +dependencies = [ + "tap", +] + +[[package]] +name = "yaml-rust2" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8902160c4e6f2fb145dbe9d6760a75e3c9522d8bf796ed7047c85919ac7115f8" +dependencies = [ + "arraydeque", + "encoding_rs", + "hashlink 0.8.4", +] + +[[package]] +name = "yansi" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049" + +[[package]] +name = "yoke" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40" +dependencies = [ + "serde", + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", + "synstructure", +] + +[[package]] +name = "zerocopy" +version = "0.8.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a789c6e490b576db9f7e6b6d661bcc9799f7c0ac8352f56ea20193b2681532e5" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f65c489a7071a749c849713807783f70672b28094011623e200cb86dcb835953" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "zerofrom" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cff3ee08c995dee1859d998dea82f7374f2826091dd9cd47def953cae446cd2e" +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.117", + "synstructure", +] + +[[package]] +name = "zeroize" +version = "1.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" + +[[package]] +name = "zerovec" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "zip" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "760394e246e4c28189f19d488c058bf16f564016aefac5d32bb1f3b51d5e9261" +dependencies = [ + "byteorder", + "crc32fast", + "crossbeam-utils", + "flate2", +] + +[[package]] +name = "zmij" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" diff --git a/Cargo.toml b/Cargo.toml index bebdb23..a24a136 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,13 +1,80 @@ [workspace] members = [ + "crates/nxmesh-core", + "crates/nxmesh-proto", + "crates/nxmesh-master", + "crates/nxmesh-agent", + "crates/nxmesh-cli", + "migrations/sea-orm", ] - resolver = "3" -[workspace.lints.clippy] -module_inception = "allow" +[workspace.package] +version = "0.1.0" +edition = "2021" +authors = ["NxMesh Team"] +license = "GNU General Public License v3.0" +repository = "https://github.com/nxmesh/nxmesh" +rust-version = "1.80" [workspace.dependencies] -sea-orm = "2.0.0-rc" -sea-orm-cli = "2.0.0-rc" +# Core dependencies +tokio = { version = "1", features = ["full"] } +serde = { version = "1", features = ["derive"] } +serde_json = "1" +thiserror = "1" +tracing = "0.1" +tracing-subscriber = { version = "0.3", features = ["env-filter", "json"] } + +# Web framework +axum = "0.7" +tower = "0.4" +tower-http = { version = "0.5", features = ["trace", "cors", "fs"] } + +# gRPC +tonic = "0.11" +prost = "0.12" + +# Database +sea-orm = { version = "2.0.0-rc", features = ["sqlx-postgres", "runtime-tokio-native-tls"] } sea-orm-migration = "2.0.0-rc" + +# Async +async-trait = "0.1" +futures = "0.3" + +# Configuration +toml = "0.8" +config = "0.14" + +# HTTP client +reqwest = { version = "0.12", default-features = false, features = ["rustls-tls", "json"] } + +# Crypto +sha2 = "0.10" +hex = "0.4" +argon2 = "0.5" +jsonwebtoken = "9" + +# Validation +validator = { version = "0.18", features = ["derive"] } + +# Time +chrono = { version = "0.4", features = ["serde"] } + +# UUID +uuid = { version = "1", features = ["v4", "serde"] } + +# Templating +handlebars = "5" + +# CLI +clap = { version = "4", features = ["derive"] } + +# Testing +tokio-test = "0.4" +mockall = "0.12" + +# NxMesh internal +nxmesh-core = { path = "crates/nxmesh-core" } +nxmesh-proto = { path = "crates/nxmesh-proto" } diff --git a/README.md b/README.md index d148ba7..3d055ba 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,202 @@ -# NxMesh +# NxMesh - Distributed Nginx Management System +> **NxMesh** is a modern, scalable, distributed system for managing nginx instances across diverse infrastructure environments. Built with a master-agent architecture inspired by service mesh patterns, NxMesh provides centralized control with local intelligence. + +## 🎯 Project Vision + +NxMesh transforms nginx from a standalone reverse proxy into a **distributed, programmable edge layer**. By adopting a control plane (master) + data plane (agent/sidecar) architecture, NxMesh enables: + +- **Centralized Management**: Control thousands of nginx instances from a single control plane +- **Dynamic Configuration**: Real-time configuration updates without restarts or connection drops +- **Observability**: Unified metrics, logs, and health status across the entire fleet +- **Hybrid Deployment**: Support for Docker, Kubernetes, VMs, and bare metal environments +- **High Availability**: Fault-tolerant design with automatic failover and recovery + +## 🏗️ Architecture Overview + +``` +┌─────────────────────────────────────────────────────────────────────────────────┐ +│ CONTROL PLANE (Master) │ +│ ┌──────────────────────────────────────────────────────────────────────────┐ │ +│ │ NxMesh Master │ │ +│ │ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ │ +│ │ │ API │ │ Config │ │ Cluster │ │ Admin │ │ │ +│ │ │ Server │ │ Manager │ │ Coordinator │ │ Console │ │ │ +│ │ └──────┬───────┘ └──────┬───────┘ └──────┬───────┘ └──────┬───────┘ │ │ +│ │ └──────────────────┴──────────────────┴──────────────────┘ │ │ +│ │ │ │ │ +│ │ PostgreSQL (State) │ │ +│ └──────────────────────────────┼─────────────────────────────────────────────┘ │ +│ │ │ +│ gRPC/TLS │ WebSocket (Events) │ +│ ▼ │ +└─────────────────────────────────────────────────────────────────────────────────┘ + │ + ┌───────────────────────────┼───────────────────────────┐ + │ │ │ + ▼ ▼ ▼ +┌───────────────┐ ┌───────────────┐ ┌───────────────┐ +│ AGENT 1 │ │ AGENT 2 │ │ AGENT N │ +│ (Sidecar) │ │ (Standalone) │ │ (K8s Pod) │ +│ ┌───────────┐ │ │ ┌───────────┐ │ │ ┌───────────┐ │ +│ │ NxMesh │ │ │ │ NxMesh │ │ │ │ NxMesh │ │ +│ │ Agent │ │ │ │ Agent │ │ │ │ Agent │ │ +│ └─────┬─────┘ │ │ └─────┬─────┘ │ │ └─────┬─────┘ │ +│ │ │ │ │ │ │ │ │ +│ ┌────┴────┐ │ │ ┌────┴────┐ │ │ ┌────┴────┐ │ +│ │ Nginx │ │ │ │ Nginx │ │ │ │ Nginx │ │ +│ │ Instance│ │ │ │ Instance│ │ │ │ Instance│ │ +│ └─────────┘ │ │ └─────────┘ │ │ └─────────┘ │ +└───────────────┘ └───────────────┘ └───────────────┘ + Docker Compose VM/Bare Metal Kubernetes +``` + +### Core Components + +| Component | Description | Technology | +|-----------|-------------|------------| +| **Master** | Central control plane - API, embedded Web UI, config distribution | Rust (Axum/gRPC) + Embedded Vite React | +| **Agent** | Local nginx controller - configuration, health checks, metrics | Rust (Tokio) | +| **Database** | Persistent state storage | PostgreSQL | + +## 🚀 Key Features + +### Phase 1: Foundation +- [ ] **Master Control Plane** + - RESTful API for configuration management + - gRPC for agent communication + - PostgreSQL persistence + - JWT-based authentication + +- [ ] **Agent Sidecar** + - Docker deployment mode (sidecar pattern) + - Standalone deployment mode + - Automatic nginx lifecycle management + - Configuration hot-reloading + +- [ ] **Configuration Management** + - Virtual host (server block) templating + - Upstream pool management + - SSL/TLS certificate management + - Configuration versioning & rollback + +### Phase 2: Resilience +- [ ] **High Availability** + - Master clustering with Raft consensus + - Agent auto-reconnection with exponential backoff + - Configuration drift detection & auto-healing + +- [ ] **Observability** + - Real-time metrics collection (Prometheus) + - Structured logging (OpenTelemetry) + - Health check dashboards + - Alert management + +### Phase 3: Advanced +- [ ] **Traffic Management** + - Dynamic load balancing strategies + - Circuit breaker patterns + - Rate limiting & WAF rules + - A/B testing & canary deployments + +- [ ] **Multi-tenancy** + - Organization/workspace isolation + - RBAC (Role-Based Access Control) + - Resource quotas & limits + +## 📦 Deployment Modes + +### 1. Docker Sidecar (Recommended for Development) +```yaml +# docker-compose.yml +services: + nginx: + image: nginx:alpine + + nxmesh-agent: + image: nxmesh/agent:latest + environment: + - NXMESH_MASTER_URL=wss://master.nxmesh.io:8443 + - NXMESH_AGENT_TOKEN=${AGENT_TOKEN} + network_mode: service:nginx # Share network namespace + pid: service:nginx # Share PID namespace (for nginx reload) +``` + +### 2. Kubernetes Sidecar +```yaml +# deployment.yaml +spec: + containers: + - name: nginx + image: nginx:alpine + - name: nxmesh-agent + image: nxmesh/agent:latest + env: + - name: NXMESH_MASTER_URL + value: "wss://master.nxmesh.svc:8443" +``` + +### 3. Standalone (VM/Bare Metal) +```bash +# Install agent +curl -fsSL https://get.nxmesh.io | bash + +# Configure and start +nxmesh-agent --master-url wss://master.nxmesh.io:8443 --token ${AGENT_TOKEN} +``` + +## 📋 Quick Start + +### Prerequisites +- Docker & Docker Compose +- Rust 1.75+ (for development) +- PostgreSQL 16+ + +### Development Setup +```bash +# Clone and setup +git clone https://github.com/your-org/nxmesh.git +cd nxmesh +just setup + +# Start development environment +just dev + +# Access services +# - Web UI: http://localhost:3000 +# - API: http://localhost:8080 +# - Nginx: http://localhost:80 +``` + +### Production Deployment +```bash +# Deploy master +docker run -d \ + -p 8080:8080 \ + -p 8443:8443 \ + -e DATABASE_URL=postgres://... \ + nxmesh/master:latest + +# Deploy agent (on nginx host) +docker run -d \ + --network container:nginx \ + -e NXMESH_MASTER_URL=wss://master.example.com:8443 \ + -e NXMESH_AGENT_TOKEN= \ + nxmesh/agent:latest +``` + +## 📚 Documentation + +| Document | Description | +|----------|-------------| +| [Architecture](./docs/architecture.md) | System design, data flow, component interactions | +| [Features](./docs/features.md) | Detailed feature specifications | +| [Roadmap](./docs/roadmap.md) | Development phases and milestones | +| [API Reference](./docs/api.md) | REST API and gRPC specifications | +| [Deployment](./docs/deployment.md) | Production deployment guides | + +## 📄 License + +NxMesh is licensed under the Apache License 3.0. See [LICENSE](./LICENSE) for details. + +--- \ No newline at end of file diff --git a/docs/api.md b/docs/api.md new file mode 100644 index 0000000..541fe63 --- /dev/null +++ b/docs/api.md @@ -0,0 +1,1107 @@ +# NxMesh API Specification + +## Overview + +This document outlines the API structure for NxMesh. The system exposes: +- **REST API** for external integrations and Web UI +- **gRPC API** for master-agent communication +- **WebSocket API** for real-time events + +--- + +## REST API + +### Base Information + +| Property | Value | +|----------|-------| +| Base URL | `https://api.nxmesh.io/v1` | +| Content-Type | `application/json` | +| Authentication | Bearer Token (JWT) | +| Rate Limit | 1000 requests/minute | + +### Authentication + +#### Login +```http +POST /auth/login +Content-Type: application/json + +{ + "email": "user@example.com", + "password": "secure_password" +} +``` + +Response: +```json +{ + "access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...", + "refresh_token": "dGhpcyBpcyBhIHJlZnJlc2ggdG9rZW4...", + "expires_in": 3600, + "token_type": "Bearer" +} +``` + +#### Refresh Token +```http +POST /auth/refresh +Content-Type: application/json + +{ + "refresh_token": "dGhpcyBpcyBhIHJlZnJlc2ggdG9rZW4..." +} +``` + +--- + +### Organizations + +#### List Organizations +```http +GET /organizations?page=1&per_page=20 +Authorization: Bearer {token} +``` + +Response: +```json +{ + "data": [ + { + "id": "550e8400-e29b-41d4-a716-446655440000", + "name": "Acme Corp", + "slug": "acme-corp", + "created_at": "2026-01-15T10:30:00Z", + "updated_at": "2026-01-15T10:30:00Z" + } + ], + "meta": { + "page": 1, + "per_page": 20, + "total": 1 + } +} +``` + +#### Create Organization +```http +POST /organizations +Authorization: Bearer {token} +Content-Type: application/json + +{ + "name": "Acme Corp", + "slug": "acme-corp" +} +``` + +#### Get Organization +```http +GET /organizations/{organization_id} +Authorization: Bearer {token} +``` + +#### Update Organization +```http +PATCH /organizations/{organization_id} +Authorization: Bearer {token} +Content-Type: application/json + +{ + "name": "Acme Corporation" +} +``` + +#### Delete Organization +```http +DELETE /organizations/{organization_id} +Authorization: Bearer {token} +``` + +--- + +### Workspaces + +#### List Workspaces +```http +GET /organizations/{organization_id}/workspaces?page=1&per_page=20 +Authorization: Bearer {token} +``` + +Response: +```json +{ + "data": [ + { + "id": "660e8400-e29b-41d4-a716-446655440001", + "organization_id": "550e8400-e29b-41d4-a716-446655440000", + "name": "Production", + "slug": "production", + "created_at": "2026-01-15T10:30:00Z" + } + ], + "meta": { + "page": 1, + "per_page": 20, + "total": 3 + } +} +``` + +#### Create Workspace +```http +POST /organizations/{organization_id}/workspaces +Authorization: Bearer {token} +Content-Type: application/json + +{ + "name": "Staging", + "slug": "staging" +} +``` + +#### Get Workspace +```http +GET /workspaces/{workspace_id} +Authorization: Bearer {token} +``` + +#### Update Workspace +```http +PATCH /workspaces/{workspace_id} +Authorization: Bearer {token} +Content-Type: application/json + +{ + "name": "Staging Environment" +} +``` + +#### Delete Workspace +```http +DELETE /workspaces/{workspace_id} +Authorization: Bearer {token} +``` + +--- + +### Agents + +#### List Agents +```http +GET /workspaces/{workspace_id}/agents?page=1&per_page=20&state=online +Authorization: Bearer {token} +``` + +Query Parameters: +- `state` - Filter by state: `online`, `offline`, `degraded`, `all` +- `label_selector` - Filter by labels: `env=production,region=us-east` + +Response: +```json +{ + "data": [ + { + "id": "770e8400-e29b-41d4-a716-446655440002", + "workspace_id": "660e8400-e29b-41d4-a716-446655440001", + "name": "web-server-01", + "hostname": "web-01.internal", + "ip_address": "10.0.1.10", + "version": "0.1.0", + "state": "online", + "deployment_mode": "docker_sidecar", + "last_seen_at": "2026-03-02T12:00:00Z", + "capabilities": ["http2", "websocket"], + "labels": { + "env": "production", + "region": "us-east-1" + }, + "created_at": "2026-02-01T10:00:00Z" + } + ], + "meta": { + "page": 1, + "per_page": 20, + "total": 5 + } +} +``` + +#### Get Agent +```http +GET /agents/{agent_id} +Authorization: Bearer {token} +``` + +Response includes health details: +```json +{ + "id": "770e8400-e29b-41d4-a716-446655440002", + "workspace_id": "660e8400-e29b-41d4-a716-446655440001", + "name": "web-server-01", + "hostname": "web-01.internal", + "ip_address": "10.0.1.10", + "version": "0.1.0", + "state": "online", + "deployment_mode": "docker_sidecar", + "last_seen_at": "2026-03-02T12:00:00Z", + "capabilities": ["http2", "websocket"], + "labels": { + "env": "production", + "region": "us-east-1" + }, + "health": { + "nginx_status": "running", + "nginx_uptime_seconds": 86400, + "active_connections": 42, + "requests_per_second": 150.5, + "cpu_percent": 25.0, + "memory_used_mb": 512, + "config_version": 42 + }, + "created_at": "2026-02-01T10:00:00Z" +} +``` + +#### Create Agent Registration Token +```http +POST /workspaces/{workspace_id}/agents/tokens +Authorization: Bearer {token} +Content-Type: application/json + +{ + "name": "web-server-02", + "labels": { + "env": "production", + "region": "us-west-1" + }, + "expires_in_hours": 24 +} +``` + +Response: +```json +{ + "token": "nxmesh_agent_eyJhZ2VudF9pZCI6ICI3NzBlODQwMC1lMjliLTQxZDQtYTcxNi00NDY2NTU0NDAwMDMi...", + "agent_id": "770e8400-e29b-41d4-a716-446655440003", + "expires_at": "2026-03-03T12:00:00Z" +} +``` + +#### Update Agent +```http +PATCH /agents/{agent_id} +Authorization: Bearer {token} +Content-Type: application/json + +{ + "name": "web-server-01-renamed", + "labels": { + "env": "production", + "region": "us-east-1", + "tier": "web" + } +} +``` + +#### Delete Agent +```http +DELETE /agents/{agent_id} +Authorization: Bearer {token} +``` + +#### Reload Agent Nginx +```http +POST /agents/{agent_id}/reload +Authorization: Bearer {token} +``` + +Response: +```json +{ + "success": true, + "message": "Nginx reloaded successfully", + "timestamp": "2026-03-02T12:05:00Z" +} +``` + +--- + +### Virtual Hosts + +#### List Virtual Hosts +```http +GET /workspaces/{workspace_id}/virtual-hosts?page=1&per_page=20 +Authorization: Bearer {token} +``` + +Response: +```json +{ + "data": [ + { + "id": "880e8400-e29b-41d4-a716-446655440004", + "workspace_id": "660e8400-e29b-41d4-a716-446655440001", + "name": "Main Website", + "server_name": "example.com www.example.com", + "listen_port": 443, + "ssl_enabled": true, + "ssl_certificate_id": "990e8400-e29b-41d4-a716-446655440005", + "http2_enabled": true, + "target_agents": { + "type": "all" + }, + "created_at": "2026-02-01T10:00:00Z", + "updated_at": "2026-02-15T14:30:00Z" + } + ], + "meta": { + "page": 1, + "per_page": 20, + "total": 10 + } +} +``` + +#### Create Virtual Host +```http +POST /workspaces/{workspace_id}/virtual-hosts +Authorization: Bearer {token} +Content-Type: application/json + +{ + "name": "API Gateway", + "server_name": "api.example.com", + "listen_port": 443, + "ssl_enabled": true, + "ssl_certificate_id": "990e8400-e29b-41d4-a716-446655440005", + "http2_enabled": true, + "locations": [ + { + "path": "/api/v1", + "upstream_id": "aa0e8400-e29b-41d4-a716-446655440006", + "custom_headers": [ + { + "name": "X-Forwarded-Proto", + "value": "$scheme" + } + ] + }, + { + "path": "/health", + "proxy_pass": "http://localhost:8080/health" + } + ], + "target_agents": { + "type": "selector", + "label_selector": "env=production" + } +} +``` + +#### Get Virtual Host +```http +GET /virtual-hosts/{virtual_host_id} +Authorization: Bearer {token} +``` + +#### Update Virtual Host +```http +PATCH /virtual-hosts/{virtual_host_id} +Authorization: Bearer {token} +Content-Type: application/json + +{ + "name": "API Gateway v2", + "locations": [ + { + "path": "/api/v2", + "upstream_id": "aa0e8400-e29b-41d4-a716-446655440007" + } + ] +} +``` + +#### Delete Virtual Host +```http +DELETE /virtual-hosts/{virtual_host_id} +Authorization: Bearer {token} +``` + +--- + +### Upstreams + +#### List Upstreams +```http +GET /workspaces/{workspace_id}/upstreams?page=1&per_page=20 +Authorization: Bearer {token} +``` + +Response: +```json +{ + "data": [ + { + "id": "aa0e8400-e29b-41d4-a716-446655440006", + "workspace_id": "660e8400-e29b-41d4-a716-446655440001", + "name": "api-backend", + "algorithm": "round_robin", + "servers": [ + { + "address": "10.0.1.20:8080", + "weight": 1, + "backup": false, + "max_fails": 3, + "fail_timeout": 30 + }, + { + "address": "10.0.1.21:8080", + "weight": 1, + "backup": false, + "max_fails": 3, + "fail_timeout": 30 + } + ], + "health_check": { + "enabled": true, + "path": "/health", + "interval": 10, + "timeout": 5 + }, + "created_at": "2026-02-01T10:00:00Z", + "updated_at": "2026-02-15T14:30:00Z" + } + ], + "meta": { + "page": 1, + "per_page": 20, + "total": 5 + } +} +``` + +#### Create Upstream +```http +POST /workspaces/{workspace_id}/upstreams +Authorization: Bearer {token} +Content-Type: application/json + +{ + "name": "web-backend", + "algorithm": "least_connections", + "servers": [ + { + "address": "10.0.1.30:8080", + "weight": 2, + "backup": false + }, + { + "address": "10.0.1.31:8080", + "weight": 1, + "backup": false + }, + { + "address": "10.0.1.32:8080", + "weight": 1, + "backup": true + } + ], + "health_check": { + "enabled": true, + "path": "/health", + "interval": 10, + "timeout": 5 + } +} +``` + +#### Get Upstream +```http +GET /upstreams/{upstream_id} +Authorization: Bearer {token} +``` + +#### Update Upstream +```http +PATCH /upstreams/{upstream_id} +Authorization: Bearer {token} +Content-Type: application/json + +{ + "servers": [ + { + "address": "10.0.1.30:8080", + "weight": 3, + "backup": false + } + ] +} +``` + +#### Delete Upstream +```http +DELETE /upstreams/{upstream_id} +Authorization: Bearer {token} +``` + +--- + +### Certificates + +#### List Certificates +```http +GET /workspaces/{workspace_id}/certificates?page=1&per_page=20 +Authorization: Bearer {token} +``` + +Response: +```json +{ + "data": [ + { + "id": "990e8400-e29b-41d4-a716-446655440005", + "workspace_id": "660e8400-e29b-41d4-a716-446655440001", + "domain": "example.com", + "is_wildcard": false, + "provider": "letsencrypt", + "status": "active", + "issued_at": "2026-02-01T10:00:00Z", + "expires_at": "2026-05-01T10:00:00Z", + "auto_renew": true, + "created_at": "2026-02-01T10:00:00Z" + } + ], + "meta": { + "page": 1, + "per_page": 20, + "total": 3 + } +} +``` + +#### Request Certificate +```http +POST /workspaces/{workspace_id}/certificates +Authorization: Bearer {token} +Content-Type: application/json + +{ + "domain": "api.example.com", + "provider": "letsencrypt", + "auto_renew": true +} +``` + +#### Get Certificate +```http +GET /certificates/{certificate_id} +Authorization: Bearer {token} +``` + +#### Delete Certificate +```http +DELETE /certificates/{certificate_id} +Authorization: Bearer {token} +``` + +--- + +### Metrics + +#### Get Workspace Metrics +```http +GET /workspaces/{workspace_id}/metrics?from=2026-03-01T00:00:00Z&to=2026-03-02T00:00:00Z +Authorization: Bearer {token} +``` + +Response: +```json +{ + "requests_total": 1234567, + "requests_per_second": 150.5, + "error_rate": 0.001, + "active_connections": 42, + "bandwidth": { + "in_bytes": 1073741824, + "out_bytes": 5368709120 + }, + "status_codes": { + "2xx": 1230000, + "3xx": 4000, + "4xx": 500, + "5xx": 67 + } +} +``` + +#### Get Agent Metrics +```http +GET /agents/{agent_id}/metrics?from=2026-03-01T00:00:00Z&to=2026-03-02T00:00:00Z +Authorization: Bearer {token} +``` + +--- + +### Access Logs + +#### Query Access Logs +```http +GET /workspaces/{workspace_id}/access-logs?from=2026-03-01T00:00:00Z&to=2026-03-02T00:00:00Z&status_code=500&limit=100 +Authorization: Bearer {token} +``` + +Response: +```json +{ + "data": [ + { + "id": "bb0e8400-e29b-41d4-a716-446655440008", + "agent_id": "770e8400-e29b-41d4-a716-446655440002", + "timestamp": "2026-03-02T10:30:00Z", + "remote_addr": "192.168.1.100", + "method": "GET", + "uri": "/api/error", + "protocol": "HTTP/1.1", + "host": "api.example.com", + "status": 500, + "body_bytes_sent": 123, + "response_time_ms": 150.5, + "user_agent": "Mozilla/5.0...", + "referer": "https://example.com/", + "request_id": "req-123-456" + } + ], + "meta": { + "total": 67, + "limit": 100 + } +} +``` + +--- + +## Error Responses + +All errors follow this format: + +```json +{ + "error": { + "code": "VALIDATION_ERROR", + "message": "Request validation failed", + "request_id": "req-abc-123", + "details": [ + { + "field": "server_name", + "message": "Invalid domain format", + "code": "INVALID_FORMAT" + } + ] + } +} +``` + +### Error Codes + +| Code | HTTP Status | Description | +|------|-------------|-------------| +| `UNAUTHORIZED` | 401 | Authentication required or invalid credentials | +| `FORBIDDEN` | 403 | Insufficient permissions | +| `NOT_FOUND` | 404 | Resource not found | +| `VALIDATION_ERROR` | 422 | Request validation failed | +| `CONFLICT` | 409 | Resource conflict (e.g., duplicate slug) | +| `RATE_LIMITED` | 429 | Too many requests | +| `INTERNAL_ERROR` | 500 | Server internal error | +| `SERVICE_UNAVAILABLE` | 503 | Service temporarily unavailable | + +--- + +## gRPC API (Master-Agent) + +### Service Definition + +```protobuf +syntax = "proto3"; +package nxmesh.agent.v1; + +option go_package = "github.com/nxmesh/api/agent/v1"; + +// AgentService defines the bidirectional communication between master and agents +service AgentService { + // Stream establishes a persistent connection for real-time communication + rpc Stream(stream AgentMessage) returns (stream MasterMessage); + + // ReportHealth sends a health report to the master + rpc ReportHealth(HealthReport) returns (Ack); + + // ReportMetrics sends metrics batch to the master + rpc ReportMetrics(MetricsBatch) returns (Ack); +} + +// Messages sent from agent to master +message AgentMessage { + string agent_id = 1; + int64 timestamp = 2; + oneof payload { + RegistrationRequest registration = 3; + HealthReport health = 4; + ConfigStatus config_status = 5; + MetricsBatch metrics = 6; + LogBatch logs = 7; + Event event = 8; + } +} + +// Messages sent from master to agent +message MasterMessage { + int64 timestamp = 1; + oneof payload { + RegistrationResponse registration_response = 2; + ConfigUpdate config_update = 3; + Command command = 4; + Ack ack = 5; + Error error = 6; + } +} + +// Registration +message RegistrationRequest { + string token = 1; + string hostname = 2; + string ip_address = 3; + string version = 4; + repeated string capabilities = 5; + map labels = 6; + DeploymentMode deployment_mode = 7; +} + +message RegistrationResponse { + string agent_id = 1; + bool success = 2; + string error_message = 3; + int64 heartbeat_interval_seconds = 4; +} + +enum DeploymentMode { + DEPLOYMENT_MODE_UNSPECIFIED = 0; + DOCKER_SIDECAR = 1; + KUBERNETES_SIDECAR = 2; + STANDALONE = 3; +} + +// Health Reporting +message HealthReport { + NginxStatus nginx = 1; + SystemMetrics system = 2; + string config_checksum = 3; + int64 config_version = 4; + repeated Alert alerts = 5; +} + +message NginxStatus { + bool is_running = 1; + uint32 pid = 2; + uint64 uptime_seconds = 3; + uint32 active_connections = 4; + uint64 total_requests = 5; + float requests_per_second = 6; +} + +message SystemMetrics { + float cpu_percent = 1; + uint64 memory_used_bytes = 2; + uint64 memory_total_bytes = 3; + uint64 disk_used_bytes = 4; + uint64 disk_total_bytes = 5; + float load_average_1m = 6; +} + +message Alert { + string id = 1; + string severity = 2; // info, warning, error, critical + string message = 3; + int64 timestamp = 4; +} + +// Configuration +message ConfigUpdate { + string config_id = 1; + int64 version = 2; + repeated VirtualHost virtual_hosts = 3; + repeated Upstream upstreams = 4; + map certificates = 5; + GlobalSettings global_settings = 6; +} + +message VirtualHost { + string id = 1; + string name = 2; + string server_name = 3; + uint32 listen_port = 4; + bool ssl_enabled = 5; + string ssl_certificate_id = 6; + bool http2_enabled = 7; + bool http3_enabled = 8; + repeated Location locations = 9; + map custom_directives = 10; +} + +message Location { + string path = 1; + string proxy_pass = 2; + string upstream_id = 3; + string root = 4; + string index = 5; + repeated Header custom_headers = 6; + repeated RewriteRule rewrite_rules = 7; + map custom_directives = 8; +} + +message Header { + string name = 1; + string value = 2; + bool always = 3; +} + +message RewriteRule { + string pattern = 1; + string replacement = 2; + string flag = 3; +} + +message Upstream { + string id = 1; + string name = 2; + LoadBalanceAlgorithm algorithm = 3; + repeated UpstreamServer servers = 4; + HealthCheckConfig health_check = 5; + uint32 keepalive_connections = 6; +} + +enum LoadBalanceAlgorithm { + LOAD_BALANCE_ALGORITHM_UNSPECIFIED = 0; + ROUND_ROBIN = 1; + LEAST_CONNECTIONS = 2; + IP_HASH = 3; + WEIGHTED_ROUND_ROBIN = 4; +} + +message UpstreamServer { + string address = 1; + uint32 weight = 2; + bool backup = 3; + bool down = 4; + uint32 max_fails = 5; + uint32 fail_timeout_seconds = 6; +} + +message HealthCheckConfig { + bool enabled = 1; + string path = 2; + uint32 interval_seconds = 3; + uint32 timeout_seconds = 4; + uint32 healthy_threshold = 5; + uint32 unhealthy_threshold = 6; +} + +message Certificate { + string id = 1; + string domain = 2; + string certificate_pem = 3; + string private_key_pem = 4; + int64 expires_at = 5; +} + +message GlobalSettings { + map nginx_directives = 1; + map env_vars = 2; +} + +message ConfigStatus { + string config_id = 1; + int64 version = 2; + ConfigApplyStatus status = 3; + string error_message = 4; + int64 applied_at = 5; +} + +enum ConfigApplyStatus { + CONFIG_APPLY_STATUS_UNSPECIFIED = 0; + PENDING = 1; + VALIDATING = 2; + APPLYING = 3; + SUCCESS = 4; + FAILED = 5; + ROLLED_BACK = 6; +} + +// Metrics +message MetricsBatch { + int64 timestamp = 1; + repeated Metric metrics = 2; +} + +message Metric { + string name = 1; + double value = 2; + int64 timestamp = 3; + map labels = 4; + MetricType type = 5; +} + +enum MetricType { + METRIC_TYPE_UNSPECIFIED = 0; + GAUGE = 1; + COUNTER = 2; + HISTOGRAM = 3; +} + +// Logs +message LogBatch { + repeated LogEntry entries = 1; +} + +message LogEntry { + int64 timestamp = 1; + string level = 2; + string message = 3; + map fields = 4; +} + +// Commands +message Command { + string command_id = 1; + oneof command { + ReloadCommand reload = 2; + RestartCommand restart = 3; + StopCommand stop = 4; + GetStatusCommand get_status = 5; + ValidateConfigCommand validate_config = 6; + } +} + +message ReloadCommand { + bool graceful = 1; +} + +message RestartCommand { + bool force = 1; +} + +message StopCommand { + bool graceful = 1; + uint32 timeout_seconds = 2; +} + +message GetStatusCommand {} + +message ValidateConfigCommand { + string config_content = 1; +} + +// Events +message Event { + string event_id = 1; + string event_type = 2; + int64 timestamp = 3; + map data = 4; +} + +// Common messages +message Ack { + string message_id = 1; + bool success = 2; + string error_message = 3; +} + +message Error { + string code = 1; + string message = 2; + map details = 3; +} +``` + +--- + +## WebSocket API + +### Connection + +Connect to WebSocket endpoint with JWT token: + +```javascript +const ws = new WebSocket('wss://api.nxmesh.io/v1/events?token={jwt_token}'); +``` + +### Event Types + +#### Agent Connected +```json +{ + "type": "agent.connected", + "timestamp": "2026-03-02T12:00:00Z", + "data": { + "agent_id": "770e8400-e29b-41d4-a716-446655440002", + "hostname": "web-01.internal", + "ip_address": "10.0.1.10" + } +} +``` + +#### Agent Disconnected +```json +{ + "type": "agent.disconnected", + "timestamp": "2026-03-02T12:05:00Z", + "data": { + "agent_id": "770e8400-e29b-41d4-a716-446655440002", + "reason": "connection_timeout" + } +} +``` + +#### Config Applied +```json +{ + "type": "config.applied", + "timestamp": "2026-03-02T12:10:00Z", + "data": { + "agent_id": "770e8400-e29b-41d4-a716-446655440002", + "config_id": "config-123", + "version": 42, + "duration_ms": 150, + "success": true + } +} +``` + +#### Health Alert +```json +{ + "type": "health.alert", + "timestamp": "2026-03-02T12:15:00Z", + "data": { + "agent_id": "770e8400-e29b-41d4-a716-446655440002", + "alert_id": "alert-456", + "severity": "warning", + "message": "High CPU usage: 85%", + "metric": "cpu_percent", + "value": 85.0 + } +} +``` + +### Subscribing to Events + +Clients can subscribe to specific event types: + +```json +{ + "action": "subscribe", + "events": ["agent.*", "config.*"], + "filter": { + "workspace_id": "660e8400-e29b-41d4-a716-446655440001" + } +} +``` diff --git a/docs/architecture.md b/docs/architecture.md new file mode 100644 index 0000000..ff330e1 --- /dev/null +++ b/docs/architecture.md @@ -0,0 +1,527 @@ +# NxMesh Architecture + +## Table of Contents +1. [Overview](#overview) +2. [System Components](#system-components) +3. [Data Flow](#data-flow) +4. [Communication Protocols](#communication-protocols) +5. [Security Model](#security-model) +6. [Deployment Patterns](#deployment-patterns) +7. [Failure Handling](#failure-handling) + +--- + +## Overview + +NxMesh follows a **Control Plane / Data Plane** architecture pattern, similar to service meshes like Istio or Linkerd, but specifically optimized for nginx management. + +### Design Principles + +1. **Separation of Concerns**: Master handles policy and state; Agent handles execution +2. **Eventual Consistency**: Configuration changes propagate asynchronously +3. **Local Autonomy**: Agents can operate independently during master outages +4. **Zero-Downtime Updates**: Nginx reloads without dropping connections +5. **Observability First**: Every action is observable and traceable + +--- + +## System Components + +### 1. Master (Control Plane) + +The Master is the brain of the system. It maintains the desired state and coordinates all agents. + +``` +┌──────────────────────────────────────────────────────────────────┐ +│ MASTER │ +│ ┌──────────────┐ ┌──────────────┐ ┌─────────────────────────┐ │ +│ │ API │ │ Config │ │ Event & Agent │ │ +│ │ Layer │ │ Engine │ │ Coordination │ │ +│ │ │ │ │ │ │ │ +│ │ ┌─────────┐ │ │ ┌─────────┐ │ │ ┌───────────────────┐ │ │ +│ │ │ REST │ │ │ │ Template│ │ │ │ Agent Registry │ │ │ +│ │ │ Handler │ │ │ │ Engine │ │ │ │ (Connections) │ │ │ +│ │ └─────────┘ │ │ └─────────┘ │ │ └───────────────────┘ │ │ +│ │ ┌─────────┐ │ │ ┌─────────┐ │ │ ┌───────────────────┐ │ │ +│ │ │ gRPC │ │ │ │ Version │ │ │ │ Event Bus │ │ │ +│ │ │ Server │ │ │ │ Control │ │ │ │ (Config Dist.) │ │ │ +│ │ └─────────┘ │ │ └─────────┘ │ │ └───────────────────┘ │ │ +│ │ ┌──────────┐ │ │ ┌──────────┐ │ │ ┌───────────────────┐ │ │ +│ │ │ WebSocket│ │ │ │ Validator│ │ │ │ Broadcast │ │ │ +│ │ │ Handler │ │ │ │ │ │ │ │ (Agent Updates) │ │ │ +│ │ └──────────┘ │ │ └──────────┘ │ │ └───────────────────┘ │ │ +│ └──────────────┘ └──────────────┘ └─────────────────────────┘ │ +│ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────────┐ │ +│ │ Auth │ │ Storage │ │ Observability │ │ +│ │ Service │ │ Layer │ │ │ │ +│ │ │ │ │ │ ┌───────────────────┐ │ │ +│ │ ┌─────────┐ │ │ ┌─────────┐ │ │ │ Metrics │ │ │ +│ │ │ JWT │ │ │ │ Postgres│ │ │ │ (Prometheus) │ │ │ +│ │ │ OAuth2 │ │ │ │ (SeaORM)│ │ │ └───────────────────┘ │ │ +│ │ └─────────┘ │ │ └─────────┘ │ │ ┌───────────────────┐ │ │ +│ │ ┌─────────┐ │ │ ┌─────────┐ │ │ │ Tracing │ │ │ +│ │ │ Password│ │ │ │ Cache │ │ │ │ (OpenTelemetry) │ │ │ +│ │ │ Login │ │ │ │ (Redis) │ │ │ └───────────────────┘ │ │ +│ │ └─────────┘ │ │ └─────────┘ │ │ │ │ +│ │ ┌─────────┐ │ │ │ │ │ │ +│ │ │ RBAC │ │ │ │ │ │ │ +│ │ │ Engine │ │ │ │ │ │ │ +│ │ └─────────┘ │ │ │ │ │ │ +│ └─────────────┘ └─────────────┘ └─────────────────────────┘ │ +└──────────────────────────────────────────────────────────────────┘ +``` + +#### Master Responsibilities + +| Module | Responsibility | +|--------|----------------| +| API Layer | HTTP REST API for external clients (CLI, Web UI, external systems) | +| Config Engine | Template rendering, validation, versioning | +| Event & Agent Coordination | Agent connection management, config event broadcasting | +| Auth Service | Authentication (JWT/OAuth2, Password) and authorization (RBAC) | +| Storage Layer | PostgreSQL for persistent state, Redis for caching | +| Observability | Metrics collection, distributed tracing, structured logging | + +#### Future: High Availability Mode + +For large-scale deployments, the master can be extended with: +- **Raft Consensus** for leader election and state replication +- **Cluster Manager** for coordinating multiple master instances +- This is **not required** for single-organization, self-hosted deployments | + +### 2. Agent (Data Plane) + +The Agent is a lightweight sidecar that runs alongside each nginx instance. + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ AGENT │ +│ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────────┐ │ +│ │ Master │ │ Nginx │ │ Health Monitor │ │ +│ │ Client │ │ Controller │ │ │ │ +│ │ │ │ │ │ ┌───────────────────┐ │ │ +│ │ ┌─────────┐ │ │ ┌─────────┐ │ │ │ Nginx Health │ │ │ +│ │ │ gRPC │ │ │ │ Config │ │ │ │ (HTTP checks) │ │ │ +│ │ │ Client │ │ │ │ Renderer│ │ │ └───────────────────┘ │ │ +│ │ └─────────┘ │ │ └─────────┘ │ │ ┌───────────────────┐ │ │ +│ │ ┌─────────┐ │ │ ┌─────────┐ │ │ │ System Metrics │ │ │ +│ │ │ WebSocket│ │ │ │ Reload │ │ │ │ (CPU/Mem/IO) │ │ │ +│ │ │ Client │ │ │ │ Manager │ │ │ └───────────────────┘ │ │ +│ │ └─────────┘ │ │ └─────────┘ │ │ │ │ +│ │ ┌─────────┐ │ │ ┌─────────┐ │ │ ┌───────────────────┐ │ │ +│ │ │ Reconnect│ │ │ │ Process │ │ │ │ Self-Health │ │ │ +│ │ │ Handler │ │ │ │ Signal │ │ │ │ (Heartbeat) │ │ │ +│ │ └─────────┘ │ │ └─────────┘ │ │ └───────────────────┘ │ │ +│ └─────────────┘ └─────────────┘ └─────────────────────────┘ │ +│ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────────┐ │ +│ │ Metrics │ │ Local │ │ Watchdog │ │ +│ │ Exporter │ │ Cache │ │ │ │ +│ │ │ │ │ │ ┌───────────────────┐ │ │ +│ │ ┌─────────┐ │ │ ┌─────────┐ │ │ │ Config Drift │ │ │ +│ │ │Prometheus│ │ │ │ Config │ │ │ │ Detection │ │ │ +│ │ │Endpoint │ │ │ │ State │ │ │ └───────────────────┘ │ │ +│ │ └─────────┘ │ │ └─────────┘ │ │ ┌───────────────────┐ │ │ +│ │ ┌─────────┐ │ │ ┌─────────┐ │ │ │ Auto-Recovery │ │ │ +│ │ │Statsd │ │ │ │ Backup │ │ │ │ (Nginx restart) │ │ │ +│ │ │Client │ │ │ │ Files │ │ │ └───────────────────┘ │ │ +│ │ └─────────┘ │ │ └─────────┘ │ │ │ │ +│ └─────────────┘ └─────────────┘ └─────────────────────────┘ │ +└─────────────────────────────────────────────────────────────────┘ +``` + +#### Agent Responsibilities + +| Module | Responsibility | +|--------|----------------| +| Master Client | Maintains persistent connection to master (gRPC + WebSocket fallback) | +| Nginx Controller | Generates configs, manages reloads, handles lifecycle | +| Health Monitor | Monitors nginx health, system resources, reports status | +| Metrics Exporter | Prometheus endpoint, statsd client for metrics | +| Local Cache | Caches configs for offline operation, backup/restore | +| Watchdog | Detects config drift, auto-recovery from failures | + +--- + +## Data Flow + +### 1. Configuration Push Flow + +``` +┌────────┐ ┌────────┐ ┌────────┐ ┌────────┐ ┌────────┐ +│ User │────▶│ API │────▶│ Config │────▶│ Event │────▶│ Agents │ +│ Action │ │ Server │ │ Engine │ │ Bus │ │ │ +└────────┘ └────────┘ └────────┘ └────────┘ └────────┘ + │ + ▼ +┌────────┐ ┌────────┐ ┌────────┐ ┌────────┐ ┌────────┐ +│ Nginx │◀────│ Config │◀────│ Template│◀────│ gRPC │◀────│ Agent │ +│Reloaded│ │Applied │ │ Render │ │ Stream │ │Receive │ +└────────┘ └────────┘ └────────┘ └────────┘ └────────┘ +``` + +**Flow Description:** +1. User creates/updates configuration via API or Web UI +2. Master validates and stores configuration in database +3. Config Engine determines affected agents +4. Event Bus broadcasts configuration change event +5. Agents receive event via gRPC streaming +6. Agent renders local nginx configuration from templates +7. Agent validates new configuration (`nginx -t`) +8. Agent applies configuration via graceful reload +9. Agent reports status back to master + +### 2. Health Reporting Flow + +``` +┌────────┐ ┌────────┐ ┌────────┐ ┌────────┐ +│ Nginx │────▶│ Agent │────▶│ Master │────▶│ DB │ +│ Health │ │ Health │ │ API │ │ Store │ +└────────┘ └────────┘ └────────┘ └────────┘ + │ + ▼ + ┌────────┐ + │Prometheus│ + │ Server │ + └────────┘ +``` + +**Flow Description:** +1. Agent periodically checks nginx health (HTTP health endpoint) +2. Agent collects system metrics (CPU, memory, connections) +3. Agent sends health report to master via gRPC +4. Master aggregates and stores in database +5. Prometheus scrapes agent metrics endpoint + +### 3. Certificate Management Flow + +``` +┌────────┐ ┌────────┐ ┌────────┐ ┌────────┐ ┌────────┐ +│ Let's │◀────│ Master │────▶│ Agent │────▶│ Nginx │◀────│ Client │ +│Encrypt │ │ ACME │ │ Deploy │ │ Serve │ │Request │ +└────────┘ └────────┘ └────────┘ └────────┘ └────────┘ +``` + +**Flow Description:** +1. Master requests certificate from Let's Encrypt (ACME protocol) +2. Master distributes certificate to relevant agents +3. Agent stores certificate locally (encrypted at rest) +4. Agent updates nginx configuration with new certificate +5. Nginx serves HTTPS traffic with new certificate + +--- + +## Communication Protocols + +### Master-Agent Protocol + +NxMesh uses a **bidirectional gRPC stream** as the primary communication channel between master and agents. + +```protobuf +// agent.proto +syntax = "proto3"; +package nxmesh.agent; + +service AgentService { + // Bidirectional streaming for real-time communication + rpc Stream(stream AgentMessage) returns (stream MasterMessage); + + // Unary calls for specific operations + rpc ReportHealth(HealthReport) returns (Ack); + rpc ReportMetrics(MetricsBatch) returns (Ack); +} + +message AgentMessage { + string agent_id = 1; + uint64 timestamp = 2; + oneof payload { + RegistrationRequest register = 3; + HealthReport health = 4; + ConfigStatus config_status = 5; + MetricsBatch metrics = 6; + LogBatch logs = 7; + } +} + +message MasterMessage { + uint64 timestamp = 1; + oneof payload { + RegistrationResponse register_response = 2; + ConfigUpdate config_update = 3; + Command command = 4; + Ack ack = 5; + } +} + +message ConfigUpdate { + string config_id = 1; + uint64 version = 2; + repeated VirtualHost virtual_hosts = 3; + repeated Upstream upstreams = 4; + map ssl_certificates = 5; +} +``` + +### Connection Management + +``` +┌─────────────────────────────────────────────────────────────────────┐ +│ CONNECTION LIFECYCLE │ +│ │ +│ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ +│ │ INIT │───▶│ CONNECT │───▶│ STREAM │───▶│ READY │ │ +│ └─────────┘ └─────────┘ └─────────┘ └─────────┘ │ +│ │ │ │ │ +│ ▼ ▼ ▼ │ +│ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ +│ │ RETRY │ │RECONNECT│ │ ERROR │ │ +│ └─────────┘ └─────────┘ └─────────┘ │ +│ │ +│ Connection Parameters: │ +│ - Heartbeat interval: 30s │ +│ - Reconnect backoff: 1s, 2s, 4s, 8s... (max 60s) │ +│ - gRPC keepalive: 10s ping, 20s timeout │ +│ - TLS: Server-side TLS (auto-generated or custom) │ +│ - Agent auth: Bootstrap token → Shared secret (HMAC) │ +└─────────────────────────────────────────────────────────────────────┘ +``` + +--- + +## Security Model + +### Authentication + +| Component | Method | Details | +|-----------|--------|---------| +| Master API | JWT (RS256) | Short-lived access tokens, refresh tokens | +| Master WebSocket | JWT | Same tokens as API | +| Master-Agent gRPC | **TLS + Shared Secret** | Server TLS + bootstrap token → session HMAC | +| Agent Registration | One-time Bootstrap Token | Generated in Master UI, single-use, short expiry | + +### Agent Authentication Flow (TLS + Shared Secret) + +``` +┌─────────────┐ ┌──────────────┐ +│ Agent │ │ Master │ +└──────┬──────┘ └──────┬───────┘ + │ │ + │ 1. TLS Handshake (verify server certificate) │ + │◄───────────────────────────────────────────────►│ + │ │ + │ 2. Register with bootstrap_token │ + │ ── gRPC: RegisterAgent { token } ─────────────▶│ + │ │ + │ 3. Receive agent_id + session_key (+ key_id) │ + │◄────────────────────────────────────────────────│ + │ [Encrypted over TLS] │ + │ │ + │ 4. Subsequent requests: HMAC-signed │ + │ ── gRPC + Headers: │ + │ X-Agent-ID: │ + │ X-Key-ID: │ + │ X-Signature: HMAC(request_body, session_key)│ + │────────────────────────────────────────────────▶│ + │ │ + │ 5. Key Rotation (primary/secondary) │ + │◄═══════════════════════════════════════════════►│ +``` + +**Security Properties:** +- **TLS**: Encrypts channel, verifies master identity (server cert) +- **Bootstrap Token**: One-time use, time-limited, proves initial identity +- **Session Key**: Per-agent secret, used for HMAC request signing +- **Key Rotation**: Primary/secondary key design for seamless rotation + +### Authorization (RBAC) + +```yaml +# Example RBAC Configuration +roles: + admin: + permissions: + - "*:*" + + operator: + permissions: + - "config:read" + - "config:write" + - "agent:read" + - "agent:reload" + + viewer: + permissions: + - "config:read" + - "agent:read" + - "metrics:read" + +# Resource hierarchy +resources: + - organization + - workspace + - agent + - certificate + - config (virtual_host, upstream) +``` + +## Deployment Patterns + +### Pattern 1: Docker Sidecar (Development/Single Host) + +```yaml +# docker-compose.yml +version: '3.8' + +services: + nxmesh-master: + image: nxmesh/master:latest + ports: + - "8080:8080" # API + - "8443:8443" # gRPC + environment: + - DATABASE_URL=postgres://... + + nginx-site-a: + image: nginx:alpine + volumes: + - site-a-html:/usr/share/nginx/html + + nxmesh-agent-a: + image: nxmesh/agent:latest + network_mode: service:nginx-site-a # Share network namespace with nginx + pid: service:nginx-site-a # Share PID namespace (for nginx reload) + environment: + - NXMESH_MASTER_URL=wss://nxmesh-master:8443 + - NXMESH_AGENT_TOKEN=${AGENT_TOKEN_A} + - NXMESH_DEPLOYMENT_MODE=docker_sidecar + - NXMESH_NGINX_PID_FILE=/var/run/nginx.pid +``` + +**Pros:** Simple, isolated, good for development +**Cons:** Docker-only, single host limitation + +### Pattern 2: Kubernetes Sidecar + +```yaml +# deployment.yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: web-service +spec: + replicas: 3 + template: + spec: + containers: + - name: nginx + image: nginx:alpine + volumeMounts: + - name: nxmesh-config + mountPath: /etc/nginx/conf.d + + - name: nxmesh-agent + image: nxmesh/agent:latest + env: + - name: NXMESH_MASTER_URL + value: "wss://nxmesh-master.default.svc:8443" + - name: NXMESH_AGENT_TOKEN + valueFrom: + secretKeyRef: + name: nxmesh-agent-token + key: token + volumeMounts: + - name: nxmesh-config + mountPath: /etc/nginx/conf.d + volumes: + - name: nxmesh-config + emptyDir: {} +``` + +**Pros:** Native K8s integration, auto-scaling, health checks +**Cons:** K8s-only, more complex setup + +### Pattern 3: Standalone (VM/Bare Metal) + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ VM / Bare Metal │ +│ ┌───────────────────────────────────────────────────────────┐ │ +│ │ Systemd │ │ +│ │ ┌─────────────────────────────────────────────────────┐ │ │ +│ │ │ nxmesh-agent.service │ │ │ +│ │ │ ┌──────────────┐ ┌──────────────┐ ┌───────────┐ │ │ │ +│ │ │ │ Agent │ │ Nginx │ │ Config │ │ │ │ +│ │ │ │ Process │──│ Process │──│ Files │ │ │ │ +│ │ │ └──────────────┘ └──────────────┘ └───────────┘ │ │ │ +│ │ └─────────────────────────────────────────────────────┘ │ │ +│ └───────────────────────────────────────────────────────────┘ │ +└─────────────────────────────────────────────────────────────────┘ +``` + +**Pros:** Works anywhere, minimal dependencies +**Cons:** Manual setup, no container isolation + +--- + +## Failure Handling + +### Master Failure Scenarios + +| Scenario | Impact | Mitigation | +|----------|--------|------------| +| Master unreachable | Agents continue with cached config | Agents retry with exponential backoff | +| Master crashes | New connections fail, existing continue | External load balancer + health checks (HA: future) | +| Database down | Read-only mode for existing configs | Database replication, failover | + +### Agent Failure Scenarios + +| Scenario | Impact | Mitigation | +|----------|--------|------------| +| Agent crashes | Nginx continues running | Systemd restart, watchdog | +| Config validation fails | Previous config kept | Atomic config swap, rollback | +| Nginx crashes | Agent restarts nginx | Health checks, auto-restart | +| Network partition | Agent operates in "island mode" | Local cache, reconciliation on reconnect | + +### Recovery Procedures + +``` +┌─────────────────────────────────────────────────────────────────────┐ +│ FAILURE RECOVERY FLOW │ +│ │ +│ Agent Disconnect │ +│ │ │ +│ ▼ │ +│ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ +│ │ Retry │───▶│ Cache │───▶│ Alert │───▶│ Watch │ │ +│ │ Connect │ │ Config │ │ Master │ │ Dog │ │ +│ └─────────┘ └─────────┘ └─────────┘ └─────────┘ │ +│ │ │ │ +│ ▼ ▼ │ +│ ┌─────────┐ ┌─────────┐ │ +│ │Reconnected│ │ Restart │ │ +│ │ Sync │ │ Nginx │ │ +│ └─────────┘ └─────────┘ │ +│ │ +│ Recovery Strategies: │ +│ 1. Exponential backoff for reconnection │ +│ 2. Circuit breaker for failed operations │ +│ 3. Config checksum verification after reconnect │ +│ 4. Automatic nginx restart on health check failure │ +└─────────────────────────────────────────────────────────────────────┘ +``` + +--- + +## Technology Stack + +| Layer | Technology | Rationale | +|-------|------------|-----------| +| **Master Backend** | Rust (Axum) | Performance, safety, async ecosystem | +| **Agent** | Rust (Tokio) | Small binary, low memory, fast startup | +| **Database** | PostgreSQL | ACID, JSON support, reliability | +| **Cache** | Redis | Fast key-value, pub/sub for events | +| **Frontend** | React + Vite (embedded) | Static build served by master, fast HMR in dev | +| **gRPC** | Tonic | Native Rust implementation | +| **ORM** | SeaORM | Async, type-safe, migration support | +| **Config Template** | Handlebars | Logic-less, secure templating | +| **Metrics** | Prometheus | Industry standard, rich ecosystem | +| **Tracing** | OpenTelemetry | Vendor-neutral, future-proof | diff --git a/docs/features.md b/docs/features.md new file mode 100644 index 0000000..3596f19 --- /dev/null +++ b/docs/features.md @@ -0,0 +1,814 @@ +# NxMesh Feature Specification + +## Table of Contents +1. [Core Features](#core-features) +2. [Master Features](#master-features) +3. [Agent Features](#agent-features) +4. [Configuration Management](#configuration-management) +5. [Observability](#observability) +6. [Security Features](#security-features) + +--- + +## Core Features + +### CF-001: Multi-tenancy with Organizations and Workspaces + +**Description**: Support for multiple organizations with isolated workspaces within each organization. + +**Requirements**: +- Organizations are top-level resource containers +- Each organization can have multiple workspaces +- Resources (agents, configs, certificates) are scoped to a workspace +- Cross-workspace visibility is configurable + +**Data Model**: +```rust +struct Organization { + id: Uuid, + name: String, + slug: String, // URL-friendly identifier + created_at: DateTime, + settings: OrganizationSettings, +} + +struct Workspace { + id: Uuid, + organization_id: Uuid, + name: String, + slug: String, + created_at: DateTime, +} +``` + +**API Endpoints**: +- `GET /api/v1/organizations` - List organizations +- `POST /api/v1/organizations` - Create organization +- `GET /api/v1/organizations/{id}/workspaces` - List workspaces +- `POST /api/v1/organizations/{id}/workspaces` - Create workspace + +--- + +### CF-002: Agent Registration and Lifecycle Management + +**Description**: Agents must register with the master before receiving configurations. + +**Registration Flow**: +1. Administrator generates bootstrap token in Master UI +2. Token is provided to agent via environment variable or config file +3. Agent establishes TLS connection to master (verifies server certificate) +4. Agent sends bootstrap token for registration +5. Master validates token and establishes shared secret: + - Master generates session_key (per-agent) + key_id + - Session key used for HMAC request signing + - Primary/secondary key design for rotation + +**Agent States**: +```rust +enum AgentState { + Pending, // Registered but never connected + Online, // Connected and healthy + Offline, // Disconnected + Degraded, // Connected but health checks failing + Maintenance, // Manually placed in maintenance mode +} +``` + +**Agent Metadata**: +```rust +struct Agent { + id: Uuid, + workspace_id: Uuid, + name: String, + hostname: String, + ip_address: String, + version: String, + state: AgentState, + deployment_mode: DeploymentMode, // DockerSidecar, K8sSidecar, Standalone + last_seen_at: DateTime, + capabilities: Vec, // e.g., ["http3", "websocket", "rate_limiting"] + labels: HashMap, // e.g., {"env": "prod", "region": "us-east"} +} +``` + +**API Endpoints**: +- `POST /api/v1/agents/register` - Register new agent +- `GET /api/v1/agents` - List agents +- `GET /api/v1/agents/{id}` - Get agent details +- `POST /api/v1/agents/{id}/tokens` - Generate registration token +- `DELETE /api/v1/agents/{id}` - Deregister agent + +--- + +### CF-003: Real-time Configuration Distribution + +**Description**: Push configuration changes to agents in real-time with delivery guarantees. + +**Requirements**: +- Config changes propagate to all affected agents within 5 seconds +- Support for targeted updates (specific agents or groups) +- Config versioning with rollback capability +- Delivery confirmation from agents + +**Configuration Scope**: +```rust +enum ConfigScope { + Global, // All agents + Workspace, // All agents in workspace + AgentGroup(String), // Agents with specific label selector + Agent(Uuid), // Single agent +} +``` + +**Delivery Guarantees**: +- At-least-once delivery +- Automatic retry with exponential backoff +- Config checksum verification +- Offline agents receive updates on reconnection + +--- + +## Master Features + +### MF-001: RESTful API + +**Description**: Comprehensive REST API for all operations. + +**Base URL**: `/api/v1` + +**Resource Endpoints**: + +| Resource | Endpoints | +|----------|-----------| +| Organizations | GET, POST, PATCH, DELETE `/organizations` | +| Workspaces | GET, POST, PATCH, DELETE `/workspaces` | +| Agents | GET, POST, PATCH, DELETE `/agents` | +| VirtualHosts | GET, POST, PATCH, DELETE `/virtual-hosts` | +| Upstreams | GET, POST, PATCH, DELETE `/upstreams` | +| Certificates | GET, POST, DELETE `/certificates` | +| AccessLogs | GET `/access-logs` | +| Metrics | GET `/metrics` | + +**Response Format**: +```json +{ + "data": { ... }, + "meta": { + "page": 1, + "per_page": 20, + "total": 100 + }, + "links": { + "self": "/api/v1/agents?page=1", + "next": "/api/v1/agents?page=2", + "prev": null + } +} +``` + +**Error Format**: +```json +{ + "error": { + "code": "VALIDATION_ERROR", + "message": "Invalid configuration", + "details": [ + {"field": "server_name", "message": "Invalid domain format"} + ] + } +} +``` + +--- + +### MF-002: Web-based Admin Console (Embedded) + +**Description**: Modern web UI for managing the entire system. Built with React + Vite and served as static files embedded directly in the master binary. + +**Pages**: + +| Page | Features | +|------|----------| +| Dashboard | Agent status, recent events, traffic overview | +| Agents | List, detail view, logs, metrics graphs | +| Configurations | Virtual host editor, upstream management | +| Certificates | SSL certificate list, expiration alerts | +| Access Control | Users, roles, permissions management | +| Settings | Organization settings, integrations | + +**Key UI Features**: +- Real-time updates via WebSocket +- Monaco editor for nginx configuration +- Visual topology view (agent connections) +- Dark/light mode support +- Responsive design + +--- + +### MF-003: Configuration Template Engine + +**Description**: Templating system for generating nginx configurations. + +**Template Variables**: +```handlebars +# Example virtual host template +server { + listen {{port}} {{#if ssl}}ssl{{/if}} {{#if http2}}http2{{/if}}; + server_name {{server_name}}; + + {{#if ssl}} + ssl_certificate {{ssl_certificate_path}}; + ssl_certificate_key {{ssl_certificate_key_path}}; + {{/if}} + + location {{location_path}} { + proxy_pass http://{{upstream_name}}; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + + {{#each custom_headers}} + add_header {{name}} "{{value}}"; + {{/each}} + + {{#if rate_limiting}} + limit_req zone={{rate_limit_zone}} burst={{rate_limit_burst}}; + {{/if}} + } +} +``` + +**Built-in Templates**: +- `default` - Standard reverse proxy +- `spa` - Single Page Application (with fallback to index.html) +- `api` - API gateway with rate limiting +- `static` - Static file serving with caching +- `websocket` - WebSocket proxy with connection upgrades + +--- + +### MF-004: Certificate Management (ACME) + +**Description**: Automatic SSL/TLS certificate provisioning via Let's Encrypt. + +**Features**: +- ACME v2 protocol support +- HTTP-01 and DNS-01 challenges +- Automatic renewal (30 days before expiry) +- Wildcard certificate support (DNS-01) +- Certificate monitoring and alerts + +**Certificate Entity**: +```rust +struct Certificate { + id: Uuid, + workspace_id: Uuid, + domain: String, + is_wildcard: bool, + provider: CertificateProvider, // LetsEncrypt, Custom + status: CertificateStatus, // Pending, Active, Expired, Error + issued_at: DateTime, + expires_at: DateTime, + auto_renew: bool, + certificate_pem: Option, // Encrypted at rest + private_key_pem: Option, // Encrypted at rest +} +``` + +--- + +## Agent Features + +### AF-001: Nginx Lifecycle Management + +**Description**: Agent manages nginx process lifecycle based on deployment mode. + +**Docker Sidecar Mode**: +- Shares PID namespace with nginx container (via `pid: service:nginx`) +- Directly signals nginx process for reload/restart +- Monitors nginx via health checks + +**Standalone Mode**: +- Direct process management (signals to PID from file) +- systemd integration (optional, for service management) +- PID file monitoring + +**Lifecycle Actions**: +- `start` - Start nginx +- `stop` - Graceful shutdown +- `reload` - Hot reload configuration +- `restart` - Full restart +- `test` - Validate configuration + +--- + +### AF-002: Configuration Rendering and Application + +**Description**: Agent renders nginx configs from master templates and applies them using atomic symlink swaps for zero-downtime updates. + +**Config Directory Structure**: +``` +/etc/nginx/ +├── nginx.conf # Contains: include /etc/nginx/conf.d/current/*.conf +├── conf.d/ +│ ├── current -> ./20260302143000/ # Symlink to active deployment +│ ├── 20260302143000/ # Active config (timestamped) +│ │ ├── default.conf +│ │ └── upstream.conf +│ ├── 20260302141500/ # Previous deployment (for rollback) +│ │ ├── default.conf +│ │ └── upstream.conf +│ └── 20260302140000/ # Older deployment (cleanup candidate) +``` + +**Config Rendering Flow**: +1. Receive ConfigUpdate from master +2. Create new deployment folder: `./conf.d//` +3. Render nginx config files into timestamped folder +4. **Validate** new config: `nginx -t -c /etc/nginx/conf.d//nginx.conf` +5. If validation passes, **atomically update symlink**: `current` → `/` +6. Execute graceful nginx reload +7. Verify reload success (health check) +8. Report status to master +9. Cleanup old deployments (keep N recent versions) + +**Atomic Config Swap**: +```rust +async fn apply_config(&self, config: ConfigUpdate) -> Result<()> { + let timestamp = generate_timestamp(); + let deploy_dir = self.conf_d_path.join(×tamp); + let symlink_path = self.conf_d_path.join("current"); + + // 1. Render config to new timestamped directory + self.render_config(&config, &deploy_dir).await?; + + // 2. Validate BEFORE switching symlink (point to new folder directly) + self.validate_config(&deploy_dir).await?; + + // 3. Atomic symlink swap (Unix: symlink + rename) + let temp_link = self.conf_d_path.join("current.tmp"); + tokio::fs::symlink(&deploy_dir, &temp_link).await?; + tokio::fs::rename(&temp_link, &symlink_path).await?; // Atomic operation + + // 4. Reload nginx (picks up new symlink target) + self.reload_nginx().await?; + + // 5. Verify and cleanup + self.verify_health().await?; + self.cleanup_old_deployments(5).await?; // Keep last 5 versions + + self.report_success(config.id, timestamp).await; +} +``` + +**Rollback Strategy**: +```rust +async fn rollback(&self, target_timestamp: &str) -> Result<()> { + let target_dir = self.conf_d_path.join(target_timestamp); + let symlink_path = self.conf_d_path.join("current"); + + // Verify target exists + if !target_dir.exists() { + return Err(Error::RollbackTargetNotFound); + } + + // Atomic symlink swap back to previous deployment + let temp_link = self.conf_d_path.join("current.tmp"); + tokio::fs::symlink(&target_dir, &temp_link).await?; + tokio::fs::rename(&temp_link, &symlink_path).await?; + + // Reload nginx + self.reload_nginx().await?; +} +``` + +--- + +### AF-003: Health Monitoring and Reporting + +**Description**: Continuous health monitoring of nginx and the host system. + +**Health Checks**: +- **Nginx Health**: HTTP request to nginx health endpoint +- **Configuration Health**: Verify current config matches expected +- **Resource Health**: CPU, memory, disk usage +- **Connection Health**: Active connections, request rate + +**Health Report Structure**: +```rust +struct HealthReport { + agent_id: Uuid, + timestamp: DateTime, + nginx_status: NginxStatus, + system_metrics: SystemMetrics, + config_checksum: String, + alerts: Vec, +} + +struct NginxStatus { + is_running: bool, + pid: Option, + uptime_seconds: u64, + active_connections: u32, + requests_per_second: f64, +} + +struct SystemMetrics { + cpu_percent: f64, + memory_used_mb: u64, + memory_total_mb: u64, + disk_used_gb: u64, + disk_total_gb: u64, +} +``` + +**Reporting Interval**: Configurable (default: 30 seconds) + +--- + +### AF-004: Metrics Collection and Export + +**Description**: Collect and expose metrics in Prometheus format. + +**Metrics Endpoint**: `GET /metrics` (on agent) + +**Built-in Metrics**: +``` +# Nginx metrics (parsed from stub_status) +nxmesh_nginx_connections_active{agent_id="..."} 42 +nxmesh_nginx_connections_reading{agent_id="..."} 5 +nxmesh_nginx_connections_writing{agent_id="..."} 30 +nxmesh_nginx_connections_waiting{agent_id="..."} 7 +nxmesh_nginx_requests_total{agent_id="..."} 1234567 + +# Agent metrics +nxmesh_agent_uptime_seconds{agent_id="..."} 86400 +nxmesh_agent_master_connection_status{agent_id="..."} 1 +nxmesh_agent_config_version{agent_id="...",version="123"} 1 + +# System metrics +nxmesh_system_cpu_percent{agent_id="..."} 25.5 +nxmesh_system_memory_used_bytes{agent_id="..."} 1073741824 +nxmesh_system_disk_used_bytes{agent_id="..."} 53687091200 +``` + +**Custom Metrics**: Agents can collect custom metrics from nginx access logs + +--- + +### AF-005: Offline Operation and Recovery + +**Description**: Agent can operate independently when master is unreachable. + +**Offline Capabilities**: +- Continue serving traffic with cached configuration +- Local health monitoring continues +- Metrics are buffered for later transmission +- Automatic reconnection attempts + +**Recovery Flow**: +1. Detect disconnection from master +2. Enter "offline mode" +3. Continue operating with cached config +4. Buffer metrics and logs +5. Attempt reconnection with exponential backoff +6. On reconnection: + - Sync configuration (compare checksums) + - Transmit buffered metrics + - Resume normal operation + +--- + +## Configuration Management + +### CM-001: Virtual Host Configuration + +**Description**: Define nginx server blocks (virtual hosts) via API/UI. + +**VirtualHost Entity**: +```rust +struct VirtualHost { + id: Uuid, + workspace_id: Uuid, + name: String, // Human-readable name + server_name: String, // Domain name(s), comma-separated + listen_port: u16, // Usually 80 or 443 + ssl_enabled: bool, + ssl_certificate_id: Option, + + // Routing configuration + locations: Vec, + + // Advanced settings + http2_enabled: bool, + http3_enabled: bool, + gzip_enabled: bool, + rate_limiting: Option, + + // Target agents + target_agents: AgentSelector, +} + +struct Location { + path: String, // e.g., "/api" or "~ \.php$" + proxy_pass: Option, // e.g., "http://backend" + upstream_id: Option, + root: Option, // For static files + index: Option, // e.g., "index.html" + custom_headers: Vec
, + rewrite_rules: Vec, +} +``` + +**Validation Rules**: +- `server_name` must be valid domain(s) +- `listen_port` must be 1-65535 +- SSL certificate must exist if `ssl_enabled` is true +- At least one location must be defined + +--- + +### CM-002: Upstream Configuration + +**Description**: Define backend server pools for load balancing. + +**Upstream Entity**: +```rust +struct Upstream { + id: Uuid, + workspace_id: Uuid, + name: String, // Used as upstream identifier + + // Load balancing algorithm + algorithm: LoadBalanceAlgorithm, // RoundRobin, LeastConn, IPHash, etc. + + // Backend servers + servers: Vec, + + // Health check configuration + health_check: Option, + + // Connection settings + keepalive_connections: Option, + keepalive_timeout: Option, +} + +struct UpstreamServer { + address: String, // IP:port or hostname:port + weight: u32, // Default: 1 + backup: bool, // Backup server + down: bool, // Temporarily down + max_fails: u32, // Default: 1 + fail_timeout: u32, // Seconds, default: 10 +} + +enum LoadBalanceAlgorithm { + RoundRobin, + LeastConnections, + IPHash, + WeightedRoundRobin, +} +``` + +--- + +### CM-003: Configuration Versioning + +**Description**: Track all configuration changes with full history. + +**Versioning Features**: +- Every change creates a new version +- Versions are immutable +- Rollback to any previous version +- Diff between versions +- Audit log of who changed what + +**Version Entity**: +```rust +struct ConfigVersion { + id: Uuid, + resource_type: String, // "virtual_host", "upstream", etc. + resource_id: Uuid, + version_number: u64, // Auto-incrementing + data: Json, // Full configuration snapshot + checksum: String, // SHA-256 of data + created_by: Uuid, // User ID + created_at: DateTime, + change_summary: String, // Human-readable description +} +``` + +**API Endpoints**: +- `GET /api/v1/virtual-hosts/{id}/versions` - List versions +- `GET /api/v1/virtual-hosts/{id}/versions/{version}` - Get specific version +- `POST /api/v1/virtual-hosts/{id}/rollback` - Rollback to version +- `GET /api/v1/virtual-hosts/{id}/diff?from=v1&to=v2` - Compare versions + +--- + +## Observability + +### OB-001: Structured Logging + +**Description**: Comprehensive logging with structured format. + +**Log Levels**: ERROR, WARN, INFO, DEBUG, TRACE + +**Log Fields**: +```json +{ + "timestamp": "2026-03-02T10:30:00Z", + "level": "INFO", + "component": "agent", + "agent_id": "550e8400-e29b-41d4-a716-446655440000", + "trace_id": "abc123", + "span_id": "def456", + "message": "Configuration applied successfully", + "fields": { + "config_id": "config-123", + "version": 42, + "duration_ms": 150 + } +} +``` + +**Log Targets**: +- Master: systemd journal, file, or centralized (ELK/Loki) +- Agent: stdout (Docker), file (standalone), or remote + +--- + +### OB-002: Distributed Tracing + +**Description**: OpenTelemetry tracing for request flow visualization. + +**Traced Operations**: +- Configuration push (master → agent → nginx) +- Health check cycles +- Certificate issuance +- API requests + +**Span Attributes**: +- `nxmesh.agent_id` +- `nxmesh.config_id` +- `nxmesh.workspace_id` +- `nxmesh.organization_id` + +--- + +### OB-003: Access Log Aggregation + +**Description**: Collect and query nginx access logs from all agents. + +**Features**: +- Centralized access log storage +- Real-time log streaming +- SQL-like query interface +- Log retention policies + +**Access Log Schema**: +```rust +struct AccessLogEntry { + id: Uuid, + agent_id: Uuid, + timestamp: DateTime, + + // Request details + remote_addr: String, + method: String, + uri: String, + protocol: String, + host: String, + + // Response details + status: u16, + body_bytes_sent: u64, + response_time_ms: f64, + + // Additional fields + user_agent: Option, + referer: Option, + request_id: Option, +} +``` + +**Query API**: +```graphql +# Example query +query { + accessLogs( + filter: { + agentId: "...", + timeRange: { from: "2026-03-01", to: "2026-03-02" }, + statusCode: { gte: 500 } + }, + limit: 100 + ) { + timestamp + method + uri + status + responseTimeMs + } +} +``` + +--- + +## Security Features + +### SF-001: Authentication and Authorization + +**Description**: Multi-method authentication with fine-grained RBAC. + +**Authentication Methods**: +- JWT (for API/Web UI) +- Password-based login (local user accounts) +- OAuth2/OIDC (Google, GitHub, enterprise SSO) +- API Keys (for service accounts) +- **TLS + Shared Secret** (for agent communication) + - Server-side TLS (auto-generated self-signed or custom certificates) + - Bootstrap token for initial registration + - Session key with HMAC signing for ongoing requests + - Primary/secondary key rotation + +**RBAC Model**: +```rust +struct Role { + id: Uuid, + name: String, + permissions: Vec, +} + +enum Permission { + // Organization scope + OrganizationRead, + OrganizationWrite, + OrganizationDelete, + + // Workspace scope + WorkspaceRead, + WorkspaceWrite, + WorkspaceDelete, + + // Agent scope + AgentRead, + AgentWrite, + AgentReload, + AgentDelete, + + // Config scope + ConfigRead, + ConfigWrite, + ConfigDeploy, + ConfigDelete, + + // Certificate scope + CertificateRead, + CertificateWrite, + CertificateDelete, + + // User management + UserRead, + UserWrite, + UserDelete, +} +``` + +--- + +### SF-002: Secret Management + +**Description**: Secure storage and distribution of sensitive data. + +**Secrets**: +- SSL private keys +- API tokens +- Database passwords +- External service credentials + +**Security Measures**: +- Encryption at rest (AES-256-GCM) +- Encryption in transit (TLS 1.3) +- Automatic secret rotation +- Audit logging for secret access + +--- + +### SF-003: Network Security + +**Description**: Network-level security controls. + +**Features**: +- IP allowlisting for agent connections +- Rate limiting on API endpoints +- DDoS protection recommendations +- Security headers enforcement (HSTS, CSP, etc.) + +**Agent Connection Security**: +- **TLS Encryption**: Server-side TLS (auto-generated or custom certificates) + - Development: Self-signed certificates auto-generated on first start + - Production: Valid certificates (Let's Encrypt or corporate CA) +- **Bootstrap Authentication**: One-time token for initial registration +- **Session Authentication**: HMAC-signed requests with shared session key +- **Key Rotation**: Primary/secondary key design for seamless rotation +- **Certificate Pinning**: Optional fingerprint verification for additional security diff --git a/docs/project-structure.md b/docs/project-structure.md new file mode 100644 index 0000000..90b5f0c --- /dev/null +++ b/docs/project-structure.md @@ -0,0 +1,428 @@ +# NxMesh Project Structure + +This document outlines the recommended project structure for the NxMesh codebase. + +## Directory Layout + +``` +nxmesh/ +├── Cargo.toml # Workspace root +├── Cargo.lock +├── README.md +├── LICENSE +├── justfile # Task runner +├── AGENTS.md # AI agent context +├── +├── crates/ # Rust workspace crates +│ ├── nxmesh-core/ # Shared core library +│ │ ├── Cargo.toml +│ │ └── src/ +│ │ ├── lib.rs +│ │ ├── models/ # Shared data models +│ │ │ ├── mod.rs +│ │ │ ├── organization.rs +│ │ │ ├── workspace.rs +│ │ │ ├── agent.rs +│ │ │ ├── config.rs +│ │ │ └── certificate.rs +│ │ ├── crypto/ # Encryption, hashing +│ │ ├── validation/ # Input validation +│ │ └── error.rs # Common error types +│ │ +│ ├── nxmesh-proto/ # Protocol buffers +│ │ ├── Cargo.toml +│ │ ├── build.rs +│ │ └── proto/ +│ │ ├── agent.proto +│ │ ├── config.proto +│ │ └── common.proto +│ │ +│ ├── nxmesh-master/ # Control plane +│ │ ├── Cargo.toml +│ │ └── src/ +│ │ ├── main.rs +│ │ ├── lib.rs +│ │ ├── api/ # REST API handlers +│ │ │ ├── mod.rs +│ │ │ ├── routes.rs +│ │ │ ├── middleware/ +│ │ │ ├── v1/ # API version 1 +│ │ │ │ ├── mod.rs +│ │ │ │ ├── organizations.rs +│ │ │ │ ├── workspaces.rs +│ │ │ │ ├── agents.rs +│ │ │ │ ├── virtual_hosts.rs +│ │ │ │ ├── upstreams.rs +│ │ │ │ ├── certificates.rs +│ │ │ │ └── metrics.rs +│ │ │ └── websocket.rs +│ │ ├── grpc/ # gRPC service +│ │ │ ├── mod.rs +│ │ │ ├── server.rs +│ │ │ ├── agent_service.rs +│ │ │ └── interceptor.rs +│ │ ├── config/ # Configuration +│ │ │ ├── mod.rs +│ │ │ └── settings.rs +│ │ ├── db/ # Database layer +│ │ │ ├── mod.rs +│ │ │ ├── connection.rs +│ │ │ ├── migration.rs +│ │ │ └── repositories/ +│ │ ├── services/ # Business logic +│ │ │ ├── mod.rs +│ │ │ ├── organization_service.rs +│ │ │ ├── workspace_service.rs +│ │ │ ├── agent_service.rs +│ │ │ ├── config_service.rs +│ │ │ ├── certificate_service.rs +│ │ │ └── auth_service.rs +│ │ ├── domain/ # Domain entities +│ │ │ ├── mod.rs +│ │ │ ├── organization.rs +│ │ │ ├── agent.rs +│ │ │ └── config.rs +│ │ ├── infrastructure/ # External integrations +│ │ │ ├── mod.rs +│ │ │ ├── acme/ # Let's Encrypt +│ │ │ ├── storage/ # Object storage +│ │ │ └── notifier/ # Notifications +│ │ ├── events/ # Event bus +│ │ │ ├── mod.rs +│ │ │ ├── bus.rs +│ │ │ └── handlers.rs +│ │ └── cli.rs # CLI commands +│ │ +│ ├── nxmesh-agent/ # Data plane +│ │ ├── Cargo.toml +│ │ └── src/ +│ │ ├── main.rs +│ │ ├── lib.rs +│ │ ├── config/ # Agent configuration +│ │ │ ├── mod.rs +│ │ │ └── settings.rs +│ │ ├── master/ # Master communication +│ │ │ ├── mod.rs +│ │ │ ├── client.rs +│ │ │ ├── reconnect.rs +│ │ │ └── stream.rs +│ │ ├── nginx/ # Nginx management +│ │ │ ├── mod.rs +│ │ │ ├── controller.rs +│ │ │ ├── config_manager.rs # Symlink-based atomic deployment +│ │ │ ├── config_renderer.rs +│ │ │ ├── validator.rs +│ │ │ ├── docker_sidecar.rs # Docker sidecar (PID namespace sharing) +│ │ │ ├── systemd.rs # Standalone mode +│ │ │ └── parser.rs # Nginx config parser +│ │ ├── health/ # Health monitoring +│ │ │ ├── mod.rs +│ │ │ ├── monitor.rs +│ │ │ ├── nginx.rs +│ │ │ └── system.rs +│ │ ├── metrics/ # Metrics collection +│ │ │ ├── mod.rs +│ │ │ ├── collector.rs +│ │ │ └── exporter.rs +│ │ ├── cache/ # Local caching +│ │ │ ├── mod.rs +│ │ │ └── config_cache.rs +│ │ ├── watch/ # File watchers +│ │ │ ├── mod.rs +│ │ │ └── config_watch.rs +│ │ └── cli.rs # CLI commands +│ │ +│ └── nxmesh-cli/ # CLI tool +│ ├── Cargo.toml +│ └── src/ +│ ├── main.rs +│ ├── commands/ # CLI commands +│ │ ├── mod.rs +│ │ ├── login.rs +│ │ ├── agent.rs +│ │ ├── config.rs +│ │ └── deploy.rs +│ └── api/ # API client +│ +├── frontend/ # Web UI (embedded in master) +│ ├── package.json +│ ├── vite.config.ts +│ ├── tsconfig.json +│ ├── index.html +│ ├── src/ +│ │ ├── main.tsx +│ │ ├── App.tsx +│ │ ├── components/ # Reusable components +│ │ │ ├── common/ +│ │ │ ├── layout/ +│ │ │ └── forms/ +│ │ ├── pages/ # Page components +│ │ │ ├── Dashboard/ +│ │ │ ├── Agents/ +│ │ │ ├── Configurations/ +│ │ │ ├── Certificates/ +│ │ │ └── Settings/ +│ │ ├── hooks/ # React hooks +│ │ ├── stores/ # State management (Zustand) +│ │ ├── api/ # API client +│ │ ├── types/ # TypeScript types +│ │ ├── utils/ # Utilities +│ │ └── styles/ # CSS/Tailwind +│ └── public/ +│ +│ # Build output (dist/) is embedded into master binary +│ # Master serves static files at root path ("/") +│ +├── migrations/ # Database migrations +│ └── sea-orm/ +│ ├── Cargo.toml +│ └── src/ +│ +├── tests/ # Integration tests +│ ├── integration/ +│ │ ├── master_api_tests.rs +│ │ ├── agent_master_tests.rs +│ │ └── config_flow_tests.rs +│ └── fixtures/ +│ +├── scripts/ # Build/utility scripts +│ ├── build.sh +│ ├── test.sh +│ └── release.sh +│ +├── deploy/ # Deployment configs +│ ├── docker/ +│ │ ├── master.Dockerfile +│ │ ├── agent.Dockerfile +│ │ └── docker-compose.yml +│ ├── k8s/ +│ │ ├── namespace.yaml +│ │ ├── master/ +│ │ ├── agent/ +│ │ └── helm/ +│ └── terraform/ +│ +├── docs/ # Documentation +│ ├── architecture.md +│ ├── features.md +│ ├── roadmap.md +│ ├── api.md +│ ├── deployment.md +│ └── project-structure.md +│ +└── .devcontainer/ # Dev container + ├── devcontainer.json + ├── docker-compose.yml + ├── Dockerfile + └── nginx/ +``` + +## Crate Dependencies + +```mermaid +graph TB + subgraph "Workspace Crates" + CLI[nxmesh-cli] + AGENT[nxmesh-agent] + MASTER[nxmesh-master] + PROTO[nxmesh-proto] + CORE[nxmesh-core] + end + + CORE --> PROTO + AGENT --> CORE + AGENT --> PROTO + MASTER --> CORE + MASTER --> PROTO + CLI --> CORE +``` + +## Key Design Principles + +### 1. Separation of Concerns + +- **nxmesh-core**: Only shared types and utilities +- **nxmesh-master**: Only control plane logic +- **nxmesh-agent**: Only data plane logic +- **frontend**: Only UI logic + +### 2. Domain-Driven Design (in Master) + +``` +domain/ # Domain entities (pure logic) +services/ # Application services (orchestration) +repositories/ # Data access abstraction +api/ # Interface adapters (HTTP, gRPC) +infrastructure/ # External concerns +``` + +### 3. Agent Modularity + +Each major concern in the agent is a separate module: +- `nginx/`: All nginx-specific code +- `master/`: All master communication code +- `health/`: All health monitoring code +- `metrics/`: All metrics code + +### 4. Configuration Management + +Use hierarchical config: +1. Default values (in code) +2. Config file (`/etc/nxmesh/*.toml`) +3. Environment variables +4. Command-line arguments (highest priority) + +## Module Guidelines + +### API Versioning + +- Always version REST APIs: `/api/v1/...` +- Maintain backward compatibility within major versions +- Use feature flags for gradual rollouts + +### Error Handling + +- Use `thiserror` for error definitions +- Propagate errors with context +- Convert to user-friendly messages at API boundary + +### Testing Structure + +```rust +// In each module +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_feature() { + // unit tests + } +} +``` + +- Unit tests: In same file as code +- Integration tests: In `tests/` directory +- E2E tests: Separate crate or external repo + +### Documentation + +- All public APIs must have doc comments +- Include examples in doc comments +- Keep README files in each crate + +## Build Configuration + +### Workspace Cargo.toml + +```toml +[workspace] +members = [ + "crates/nxmesh-core", + "crates/nxmesh-proto", + "crates/nxmesh-master", + "crates/nxmesh-agent", + "crates/nxmesh-cli", +] +resolver = "3" + +[workspace.dependencies] +# Core dependencies +tokio = { version = "1", features = ["full"] } +serde = { version = "1", features = ["derive"] } +thiserror = "1" +tracing = "0.1" + +# Web framework +axum = "0.7" +tower = "0.4" +tower-http = "0.5" + +# gRPC +tonic = "0.11" +prost = "0.12" + +# Database +sea-orm = "2.0.0-rc" +sea-orm-migration = "2.0.0-rc" + +# Async +async-trait = "0.1" +futures = "0.3" + +# Serialization +serde_json = "1" +toml = "0.8" + +# HTTP +reqwest = { version = "0.12", default-features = false } + +# Crypto +sha2 = "0.10" +hex = "0.4" + +# Testing +tokio-test = "0.4" +mockall = "0.12" +``` + +## Naming Conventions + +### Files +- Use `snake_case` for file names +- Module entry point: `mod.rs` or `{module_name}.rs` + +### Types +- Structs/Enums: `PascalCase` +- Traits: `PascalCase` (often ending in `able` or with verb prefix) +- Functions/Methods: `snake_case` +- Constants: `SCREAMING_SNAKE_CASE` +- Generic parameters: Single uppercase letter (`T`, `K`, `V`) + +### Error Types +- Suffix with `Error`: `ConfigError`, `AgentError` +- Group in `error.rs` or `errors/` module + +### Feature Flags +- Use `kebab-case`: `postgres-native`, `tls-rustls` + +## CI/CD Structure + +```yaml +# .github/workflows/ +├── ci.yml # PR checks +├── test.yml # Test suite +├── release.yml # Release builds +├── docker.yml # Docker image builds +└── docs.yml # Documentation deploy +``` + +## Scripts + +Common operations should have just commands: + +```justfile +# Development +just dev # Start all services +just dev-backend # Start backend only +just dev-frontend # Start frontend only + +# Testing +just test # Run all tests +just test-unit # Unit tests only +just test-integration # Integration tests + +# Building +just build # Build all +just build-master # Build master only +just build-agent # Build agent only + +# Database +just db-migrate # Run migrations +just db-reset # Reset database +just db-console # Open psql + +# Deployment +just docker-build # Build Docker images +just k8s-deploy # Deploy to Kubernetes +``` diff --git a/docs/roadmap.md b/docs/roadmap.md new file mode 100644 index 0000000..be73762 --- /dev/null +++ b/docs/roadmap.md @@ -0,0 +1,486 @@ +# NxMesh Project Roadmap + +## Overview + +This document outlines the development phases and milestones for NxMesh. The project is divided into four major phases, each building upon the previous one. + +--- + +## Phase 1: Foundation (Months 1-3) + +**Goal**: Build a working MVP with basic master-agent communication and nginx configuration management. + +### Milestone 1.1: Project Setup and Core Infrastructure +**Target**: Week 2 + +| Task | Description | Status | +|------|-------------|--------| +| [ ] | Set up Rust workspace structure (master, agent, shared) | 🔲 | +| [ ] | Configure CI/CD pipeline (GitHub Actions) | 🔲 | +| [ ] | Set up database schema with SeaORM migrations | 🔲 | +| [ ] | Create development environment (devcontainer) | 🔲 | +| [ ] | Set up testing framework (unit, integration) | 🔲 | + +**Deliverables**: +- Working development environment +- Database schema for organizations, workspaces, agents +- CI pipeline with linting and testing + +--- + +### Milestone 1.2: Master - Core API +**Target**: Week 5 + +| Task | Description | Status | +|------|-------------|--------| +| [ ] | Implement Axum-based REST API server | 🔲 | +| [ ] | JWT authentication middleware | 🔲 | +| [ ] | CRUD endpoints for Organizations | 🔲 | +| [ ] | CRUD endpoints for Workspaces | 🔲 | +| [ ] | CRUD endpoints for Agents | 🔲 | +| [ ] | PostgreSQL persistence layer | 🔲 | + +**Deliverables**: +- REST API for basic resource management +- JWT authentication working +- API documentation (OpenAPI) + +--- + +### Milestone 1.3: Master - Agent Communication +**Target**: Week 7 + +| Task | Description | Status | +|------|-------------|--------| +| [ ] | gRPC server implementation (Tonic) | 🔲 | +| [ ] | Bidirectional streaming protocol | 🔲 | +| [ ] | Agent registration flow | 🔲 | +| [ ] | Token-based authentication for agents | 🔲 | +| [ ] | Agent heartbeat/health monitoring | 🔲 | +| [ ] | WebSocket fallback for events | 🔲 | + +**Deliverables**: +- Master can accept agent connections +- Agent registration and authentication works +- Health status tracking + +--- + +### Milestone 1.4: Agent - Core Functionality +**Target**: Week 9 + +| Task | Description | Status | +|------|-------------|--------| +| [ ] | Agent CLI and configuration | 🔲 | +| [ ] | gRPC client for master communication | 🔲 | +| [ ] | Automatic reconnection with backoff | 🔲 | +| [ ] | Nginx process management (Docker sidecar PID sharing) | 🔲 | +| [ ] | Health check reporting | 🔲 | +| [ ] | Local config caching | 🔲 | + +**Deliverables**: +- Agent binary that connects to master +- Nginx lifecycle management (Docker sidecar mode) +- Health reporting + +--- + +### Milestone 1.5: Configuration Management +**Target**: Week 11 + +| Task | Description | Status | +|------|-------------|--------| +| [ ] | VirtualHost CRUD API | 🔲 | +| [ ] | Upstream CRUD API | 🔲 | +| [ ] | Handlebars template engine integration | 🔲 | +| [ ] | Config rendering on agent | 🔲 | +| [ ] | Nginx config validation (`nginx -t`) | 🔲 | +| [ ] | Graceful reload on config change | 🔲 | + +**Deliverables**: +- End-to-end config push: Master → Agent → Nginx +- Basic virtual host and upstream management +- Template-based nginx config generation + +--- + +### Milestone 1.6: Web Admin Console - Foundation +**Target**: Week 13 + +| Task | Description | Status | +|------|-------------|--------| +| [ ] | React + Vite project setup | 🔲 | +| [ ] | Authentication UI (login/logout) | 🔲 | +| [ ] | Dashboard layout and navigation | 🔲 | +| [ ] | Agent list and detail views | 🔲 | +| [ ] | Basic virtual host form | 🔲 | +| [ ] | WebSocket integration for real-time updates | 🔲 | + +**Deliverables**: +- Functional Web UI +- Agent management via UI +- Basic configuration editing + +--- + +### Phase 1 Completion Criteria +- [ ] Master and Agent communicate via gRPC +- [ ] Nginx configs can be pushed from Master to Agent +- [ ] Web UI for basic management +- [ ] Docker sidecar deployment working +- [ ] Documentation complete + +**Estimated Effort**: 3 months +**Team Size**: 2-3 engineers + +--- + +## Phase 2: Resilience and Observability (Months 4-5) + +**Goal**: Make the system production-ready with HA, monitoring, and robust failure handling. + +### Milestone 2.1: High Availability - Master Clustering +**Target**: Week 15 + +| Task | Description | Status | +|------|-------------|--------| +| [ ] | Raft consensus integration (raft-rs) | 🔲 | +| [ ] | Leader election | 🔲 | +| [ ] | State replication across masters | 🔲 | +| [ ] | Agent connection failover | 🔲 | +| [ ] | Cluster health monitoring | 🔲 | + +**Deliverables**: +- Multiple master instances can form a cluster +- Automatic failover on master failure +- No single point of failure + +--- + +### Milestone 2.2: Certificate Management +**Target**: Week 17 + +| Task | Description | Status | +|------|-------------|--------| +| [ ] | ACME client integration (acme-rs) | 🔲 | +| [ ] | Let's Encrypt HTTP-01 challenge | 🔲 | +| [ ] | Certificate storage (encrypted) | 🔲 | +| [ ] | Automatic renewal | 🔲 | +| [ ] | Certificate distribution to agents | 🔲 | +| [ ] | Expiration monitoring and alerts | 🔲 | + +**Deliverables**: +- Automatic SSL certificate provisioning +- Certificate renewal before expiry +- UI for certificate management + +--- + +### Milestone 2.3: Observability Stack +**Target**: Week 19 + +| Task | Description | Status | +|------|-------------|--------| +| [ ] | OpenTelemetry integration | 🔲 | +| [ ] | Structured logging (tracing) | 🔲 | +| [ ] | Prometheus metrics endpoint (agent) | 🔲 | +| [ ] | Custom metrics collection | 🔲 | +| [ ] | Health check dashboard | 🔲 | +| [ ] | Alert configuration | 🔲 | + +**Deliverables**: +- Metrics visible in Prometheus +- Distributed traces for config pushes +- Health dashboard in Web UI + +--- + +### Milestone 2.4: Enhanced Failure Handling +**Target**: Week 21 + +| Task | Description | Status | +|------|-------------|--------| +| [ ] | Configuration drift detection | 🔲 | +| [ ] | Auto-healing (config sync) | 🔲 | +| [ ] | Circuit breaker for master connection | 🔲 | +| [ ] | Nginx crash detection and restart | 🔲 | +| [ ] | Config rollback on validation failure | 🔲 | +| [ ] | Bulk operations and queue management | 🔲 | + +**Deliverables**: +- System self-heals from common failures +- Config drift automatically corrected +- Robust reconnection logic + +--- + +### Phase 2 Completion Criteria +- [ ] Master clustering with Raft +- [ ] Automatic SSL certificates +- [ ] Full observability (metrics, logs, traces) +- [ ] Production-grade failure handling +- [ ] Performance benchmarks + +**Estimated Effort**: 2 months +**Team Size**: 2-3 engineers + +--- + +## Phase 3: Advanced Traffic Management (Months 6-7) + +**Goal**: Add enterprise-grade traffic management features. + +### Milestone 3.1: Advanced Load Balancing +**Target**: Week 23 + +| Task | Description | Status | +|------|-------------|--------| +| [ ] | Multiple load balancing algorithms | 🔲 | +| [ ] | Health checks for upstream servers | 🔲 | +| [ ] | Circuit breaker for upstreams | 🔲 | +| [ ] | Retry policies | 🔲 | +| [ ] | Connection pooling | 🔲 | +| [ ] | Upstream status dashboard | 🔲 | + +**Deliverables**: +- Advanced upstream configuration +- Health check visualization +- Circuit breaker metrics + +--- + +### Milestone 3.2: Rate Limiting and WAF +**Target**: Week 25 + +| Task | Description | Status | +|------|-------------|--------| +| [ ] | Rate limiting rules (IP, user, global) | 🔲 | +| [ ] | Rate limiting zones | 🔲 | +| [ ] | Basic WAF rules (ModSecurity integration) | 🔲 | +| [ ] | IP allowlist/blocklist | 🔲 | +| [ ] | Geo-blocking | 🔲 | +| [ ] | Rate limit analytics | 🔲 | + +**Deliverables**: +- Configurable rate limiting +- Basic WAF protection +- Security event dashboard + +--- + +### Milestone 3.3: Traffic Routing and Canary +**Target**: Week 27 + +| Task | Description | Status | +|------|-------------|--------| +| [ ] | Header-based routing | 🔲 | +| [ ] | Weight-based traffic splitting | 🔲 | +| [ ] | Canary deployment support | 🔲 | +| [ ] | A/B testing configuration | 🔲 | +| [ ] | Blue-green deployment | 🔲 | +| [ ] | Traffic analytics | 🔲 | + +**Deliverables**: +- Advanced traffic routing +- Canary deployment UI +- Traffic split visualization + +--- + +### Milestone 3.4: Access Log Aggregation +**Target**: Week 29 + +| Task | Description | Status | +|------|-------------|--------| +| [ ] | Nginx access log parsing | 🔲 | +| [ ] | Log streaming to master | 🔲 | +| [ ] | Log storage and indexing | 🔲 | +| [ ] | Log query interface | 🔲 | +| [ ] | Real-time log tailing | 🔲 | +| [ ] | Log-based alerting | 🔲 | + +**Deliverables**: +- Centralized access logs +- Log search and filtering +- Log-based metrics + +--- + +### Phase 3 Completion Criteria +- [ ] Advanced load balancing and health checks +- [ ] Rate limiting and basic WAF +- [ ] Canary and A/B testing +- [ ] Access log aggregation +- [ ] Traffic analytics dashboard + +**Estimated Effort**: 2 months +**Team Size**: 2-3 engineers + +--- + +## Phase 4: Enterprise Features (Months 8-10) + +**Goal**: Enterprise readiness with multi-tenancy, RBAC, and advanced integrations. + +### Milestone 4.1: Multi-tenancy and RBAC +**Target**: Week 31 + +| Task | Description | Status | +|------|-------------|--------| +| [ ] | Organization isolation | 🔲 | +| [ ] | Workspace-scoped resources | 🔲 | +| [ ] | Role-based access control | 🔲 | +| [ ] | User management API | 🔲 | +| [ ] | API key management | 🔲 | +| [ ] | Audit logging | 🔲 | + +**Deliverables**: +- Full multi-tenancy +- Granular permissions +- Audit trail + +--- + +### Milestone 4.2: Kubernetes Integration +**Target**: Week 33 + +| Task | Description | Status | +|------|-------------|--------| +| [ ] | Kubernetes operator | 🔲 | +| [ ] | CRD definitions | 🔲 | +| [ ] | Helm chart | 🔲 | +| [ ] | Service discovery integration | 🔲 | +| [ ] | Ingress controller mode | 🔲 | +| [ ] | K8s-native agent deployment | 🔲 | + +**Deliverables**: +- Kubernetes operator +- Helm chart for easy deployment +- Ingress controller functionality + +--- + +### Milestone 4.3: External Integrations +**Target**: Week 35 + +| Task | Description | Status | +|------|-------------|--------| +| [ ] | Terraform provider | 🔲 | +| [ ] | GitOps integration (Git sync) | 🔲 | +| [ ] | Webhook support | 🔲 | +| [ ] | Slack/Discord notifications | 🔲 | +| [ ] | PagerDuty/Opsgenie integration | 🔲 | +| [ ] | DNS provider integration (Route53, Cloudflare) | 🔲 | + +**Deliverables**: +- Infrastructure as Code support +- GitOps workflows +- Notification channels + +--- + +### Milestone 4.4: Performance and Scale +**Target**: Week 37 + +| Task | Description | Status | +|------|-------------|--------| +| [ ] | Connection pooling optimization | 🔲 | +| [ ] | Config caching improvements | 🔲 | +| [ ] | Database query optimization | 🔲 | +| [ ] | Horizontal scaling tests | 🔲 | +| [ ] | Load testing (10k+ agents) | 🔲 | +| [ ] | Performance tuning documentation | 🔲 | + +**Deliverables**: +- Performance benchmarks +- Scaling guidelines +- Optimization recommendations + +--- + +### Milestone 4.5: Enterprise Security +**Target**: Week 39 + +| Task | Description | Status | +|------|-------------|--------| +| [ ] | mTLS for all communications | 🔲 | +| [ ] | Secret encryption at rest | 🔲 | +| [ ] | HSM integration | 🔲 | +| [ ] | SSO/SAML integration | 🔲 | +| [ ] | Security scanning (SAST/DAST) | 🔲 | +| [ ] | Compliance documentation (SOC2) | 🔲 | + +**Deliverables**: +- Enterprise security features +- Compliance documentation +- Security audit + +--- + +### Phase 4 Completion Criteria +- [ ] Full RBAC and multi-tenancy +- [ ] Kubernetes operator +- [ ] External integrations (Terraform, GitOps) +- [ ] Proven scalability (10k+ agents) +- [ ] Enterprise security compliance + +**Estimated Effort**: 3 months +**Team Size**: 3-4 engineers + +--- + +## Timeline Summary + +``` +Month 1-3: ████████████████████████████████████████ Phase 1: Foundation +Month 4-5: ████████████████████ Phase 2: Resilience +Month 6-7: ████████████████████ Phase 3: Advanced +Month 8-10: ██████████████████████████ Phase 4: Enterprise + +Week: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 + |--M1--|--M2--|--M3--|--M4--|--M5--|--M6--| + +Week: 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 + |--M7--|--M8--|--M9--|--M10-|--M11-|--M12-|--M13-|--M14-| +``` + +--- + +## Resource Requirements + +### Phase 1 +- **Backend Engineers**: 2 +- **Frontend Engineer**: 1 +- **Total Person-Months**: 9 + +### Phase 2 +- **Backend Engineers**: 2 +- **Frontend Engineer**: 1 (part-time) +- **DevOps Engineer**: 1 (part-time) +- **Total Person-Months**: 7 + +### Phase 3 +- **Backend Engineers**: 2 +- **Frontend Engineer**: 1 +- **Total Person-Months**: 6 + +### Phase 4 +- **Backend Engineers**: 2 +- **Frontend Engineer**: 1 +- **DevOps Engineer**: 1 +- **Security Engineer**: 1 (part-time) +- **Total Person-Months**: 10 + +**Total Project**: ~32 person-months + +--- + +## Risk Assessment + +| Risk | Probability | Impact | Mitigation | +|------|-------------|--------|------------| +| Raft complexity delays HA | Medium | High | Start with single master, add HA later | +| gRPC performance issues | Low | Medium | Implement WebSocket fallback early | +| Nginx reload edge cases | Medium | High | Extensive testing, rollback capability | +| Team scaling challenges | Medium | Medium | Document architecture, modular design | +| Integration complexity | Medium | Medium | Clear APIs, contract testing |