├── .gitignore ├── crates ├── server │ ├── .env.example │ ├── orbit.example.toml │ ├── src │ │ ├── routes │ │ │ ├── mod.rs │ │ │ ├── docs.rs │ │ │ ├── system.rs │ │ │ └── sites.rs │ │ ├── main.rs │ │ ├── server.rs │ │ ├── config.rs │ │ ├── misc.rs │ │ └── deploy.rs │ ├── build.rs │ └── Cargo.toml ├── types │ ├── Cargo.toml │ └── src │ │ └── lib.rs ├── client │ ├── Cargo.toml │ └── src │ │ └── lib.rs └── cli │ ├── Cargo.toml │ └── src │ ├── utils.rs │ └── main.rs ├── .dockerignore ├── rustfmt.toml ├── Cargo.toml ├── Dockerfile.cli ├── Dockerfile.server ├── .github └── workflows │ ├── ci.yaml │ ├── build.yaml │ └── release.yaml ├── action.yml ├── LICENSE ├── README.md └── Cargo.lock /.gitignore: -------------------------------------------------------------------------------- 1 | tmp 2 | .env 3 | /target 4 | orbit.toml 5 | -------------------------------------------------------------------------------- /crates/server/.env.example: -------------------------------------------------------------------------------- 1 | RUST_LOG="orbit=debug" 2 | ORBIT_CONFIG="./orbit.toml" 3 | GITHUB_TOKEN="" 4 | -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | tmp 2 | .env 3 | target 4 | .github 5 | README.md 6 | orbit.toml 7 | Dockerfile.cli 8 | Dockerfile.server 9 | -------------------------------------------------------------------------------- /crates/server/orbit.example.toml: -------------------------------------------------------------------------------- 1 | version = 1 2 | token = "" # Use `openssl rand -base64 32` to generate a random token 3 | 4 | [[sites]] 5 | name = "Test Site" 6 | path = "/var/www/test-site" 7 | github_repo = "m1guelpf/laravel-test" 8 | -------------------------------------------------------------------------------- /rustfmt.toml: -------------------------------------------------------------------------------- 1 | tab_spaces = 4 2 | hard_tabs = true 3 | edition = "2021" 4 | use_try_shorthand = true 5 | imports_granularity = "Crate" 6 | use_field_init_shorthand = true 7 | condense_wildcard_suffixes = true 8 | match_block_trailing_comma = true 9 | -------------------------------------------------------------------------------- /crates/server/src/routes/mod.rs: -------------------------------------------------------------------------------- 1 | use aide::axum::ApiRouter; 2 | 3 | mod docs; 4 | mod sites; 5 | mod system; 6 | 7 | pub fn handler() -> ApiRouter { 8 | ApiRouter::new() 9 | .merge(docs::handler()) 10 | .merge(sites::handler()) 11 | .merge(system::handler()) 12 | } 13 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | resolver = "2" 3 | members = ["crates/*"] 4 | 5 | [workspace.package] 6 | license = "MIT" 7 | edition = "2021" 8 | readme = "README.md" 9 | repository = "https://github.com/m1guelpf/orbit" 10 | authors = ["Miguel Piedrafita "] 11 | 12 | [profile.release] 13 | lto = true 14 | strip = true 15 | opt-level = 3 16 | panic = "abort" 17 | -------------------------------------------------------------------------------- /Dockerfile.cli: -------------------------------------------------------------------------------- 1 | FROM --platform=linux/amd64 clux/muslrust AS builder 2 | WORKDIR /orbit-cli 3 | COPY . . 4 | RUN cargo build --release --bin orbit-cli 5 | 6 | FROM --platform=linux/amd64 alpine AS runtime 7 | WORKDIR /orbit-cli 8 | COPY --from=builder /orbit-cli/target/x86_64-unknown-linux-musl/release/orbit-cli /usr/local/bin/orbit 9 | 10 | ENTRYPOINT ["/usr/local/bin/orbit"] 11 | -------------------------------------------------------------------------------- /crates/types/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | version = "0.1.0" 3 | name = "orbit-types" 4 | description = "Shared types for Orbit." 5 | 6 | 7 | readme.workspace = true 8 | license.workspace = true 9 | edition.workspace = true 10 | authors.workspace = true 11 | repository.workspace = true 12 | 13 | [dependencies] 14 | thiserror = "1.0.63" 15 | serde = { version = "1.0.204", features = ["derive"] } 16 | -------------------------------------------------------------------------------- /Dockerfile.server: -------------------------------------------------------------------------------- 1 | FROM --platform=linux/amd64 clux/muslrust AS builder 2 | WORKDIR /orbit 3 | COPY . . 4 | RUN cargo build --release --bin orbit-server 5 | 6 | FROM --platform=linux/amd64 alpine AS runtime 7 | WORKDIR /orbit 8 | COPY --from=builder /orbit/target/x86_64-unknown-linux-musl/release/orbit-server /usr/local/bin 9 | 10 | EXPOSE 8000 11 | ENTRYPOINT ["/usr/local/bin/orbit-server"] 12 | 13 | HEALTHCHECK --interval=5m \ 14 | CMD curl -f http://localhost:8000/ || exit 1 15 | -------------------------------------------------------------------------------- /crates/server/src/routes/docs.rs: -------------------------------------------------------------------------------- 1 | use aide::{axum::ApiRouter, openapi::OpenApi, scalar::Scalar}; 2 | use axum::{routing::get, Extension, Json}; 3 | 4 | pub fn handler() -> ApiRouter { 5 | let scalar = Scalar::new("/openapi.json").with_title("Orbit Docs"); 6 | 7 | ApiRouter::new() 8 | .route("/docs", scalar.axum_route()) 9 | .route("/openapi.json", get(openapi_schema)) 10 | } 11 | 12 | #[allow(clippy::unused_async)] 13 | async fn openapi_schema(Extension(openapi): Extension) -> Json { 14 | Json(openapi) 15 | } 16 | -------------------------------------------------------------------------------- /crates/client/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | version = "0.1.0" 3 | name = "orbit-client" 4 | description = "An API client for the Orbit Server API" 5 | 6 | readme.workspace = true 7 | edition.workspace = true 8 | license.workspace = true 9 | authors.workspace = true 10 | repository.workspace = true 11 | 12 | [dependencies] 13 | url = "2.5.2" 14 | futures = "0.3.30" 15 | reqwest = "0.12.5" 16 | thiserror = "1.0.63" 17 | serde_json = "1.0.120" 18 | async-fn-stream = "0.2.2" 19 | reqwest-eventsource = "0.6.0" 20 | orbit-types = { version = "0.1.0", path = "../types" } 21 | -------------------------------------------------------------------------------- /crates/server/build.rs: -------------------------------------------------------------------------------- 1 | use chrono::prelude::{DateTime, Utc}; 2 | use std::process::Command; 3 | 4 | fn get_git_rev() -> Option { 5 | let output = Command::new("git") 6 | .args(["rev-parse", "--short", "HEAD"]) 7 | .output() 8 | .ok()?; 9 | 10 | if output.status.success() { 11 | String::from_utf8(output.stdout).ok() 12 | } else { 13 | None 14 | } 15 | } 16 | 17 | fn get_compile_date() -> String { 18 | let system_time = std::time::SystemTime::now(); 19 | let date_time: DateTime = system_time.into(); 20 | format!("{}", date_time.format("%+")) 21 | } 22 | 23 | fn main() { 24 | println!("cargo:rustc-env=STATIC_BUILD_DATE={}", get_compile_date()); 25 | 26 | if let Some(rev) = get_git_rev() { 27 | println!("cargo:rustc-env=GIT_REV={}", rev); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /crates/cli/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | version = "0.1.0" 3 | name = "orbit-cli" 4 | categories = ["command-line-utilities"] 5 | description = "Command-line tool to easily deploy Laravel sites using Orbit." 6 | 7 | readme.workspace = true 8 | edition.workspace = true 9 | license.workspace = true 10 | authors.workspace = true 11 | repository.workspace = true 12 | 13 | [dependencies] 14 | url = "2.5.2" 15 | log = "0.4.22" 16 | anyhow = "1.0.86" 17 | console = "0.15.8" 18 | pin-utils = "0.1.0" 19 | futures-util = "0.3.30" 20 | tokio = { version = "=1.29", features = ["full"] } 21 | fern = { version = "0.6.2", features = ["colored"] } 22 | orbit-types = { version = "0.1.0", path = "../types" } 23 | orbit-client = { version = "0.1.0", path = "../client" } 24 | clap = { version = "4.5.9", features = ["derive", "env"] } 25 | -------------------------------------------------------------------------------- /.github/workflows/ci.yaml: -------------------------------------------------------------------------------- 1 | on: [push, pull_request] 2 | 3 | name: CI 4 | 5 | jobs: 6 | check: 7 | name: Lint 8 | runs-on: ubuntu-latest 9 | steps: 10 | - name: Checkout repository 11 | uses: actions/checkout@v4 12 | 13 | - uses: dtolnay/rust-toolchain@nightly 14 | with: 15 | components: rustfmt, clippy 16 | 17 | - name: Cache build 18 | uses: Swatinem/rust-cache@v2 19 | with: 20 | key: cache 21 | 22 | - name: Check formatting 23 | run: cargo fmt --all -- --check 24 | 25 | - name: Clippy 26 | uses: clechasseur/rs-clippy-check@v3 27 | with: 28 | args: --all-features --all-targets 29 | -------------------------------------------------------------------------------- /crates/server/src/main.rs: -------------------------------------------------------------------------------- 1 | #![warn(clippy::all, clippy::pedantic, clippy::nursery)] 2 | 3 | use std::env; 4 | 5 | use anyhow::Result; 6 | use config::Config; 7 | use dotenvy::dotenv; 8 | use tracing_subscriber::{ 9 | prelude::__tracing_subscriber_SubscriberExt, util::SubscriberInitExt, EnvFilter, Layer, 10 | }; 11 | 12 | mod config; 13 | mod deploy; 14 | mod misc; 15 | mod routes; 16 | mod server; 17 | 18 | #[tokio::main] 19 | async fn main() -> Result<()> { 20 | dotenv().ok(); 21 | 22 | tracing_subscriber::registry() 23 | .with(tracing_subscriber::fmt::layer().with_filter( 24 | EnvFilter::try_from_default_env().unwrap_or_else(|_| "orbit_server=info".into()), 25 | )) 26 | .init(); 27 | 28 | let config = 29 | Config::load(env::var("ORBIT_CONFIG").expect("$ORBIT_CONFIG not found"))?.validate()?; 30 | 31 | server::start(config).await 32 | } 33 | -------------------------------------------------------------------------------- /action.yml: -------------------------------------------------------------------------------- 1 | name: Orbit Deploy 2 | author: Miguel Piedrafita 3 | description: Deploy an Orbit application 4 | branding: 5 | icon: upload-cloud 6 | color: purple 7 | inputs: 8 | orbit-url: 9 | required: true 10 | description: URL to your Orbit instance 11 | orbit-token: 12 | required: true 13 | description: Authentication token for your Orbit instance 14 | site: 15 | required: true 16 | description: Name of the site to deploy 17 | ref: 18 | required: false 19 | description: The git ref to deploy 20 | outputs: 21 | results: 22 | description: The results from calling `myapp` 23 | runs: 24 | using: docker 25 | image: docker://ghcr.io/m1guelpf/orbit-cli:edge 26 | env: 27 | DEPLOY_REF: ${{ inputs.ref }} 28 | ORBIT_URL: ${{ inputs.orbit-url }} 29 | ORBIT_TOKEN: ${{ inputs.orbit-token }} 30 | args: 31 | - deploy 32 | - ${{ inputs.site }} 33 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) Miguel Piedrafita 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /crates/server/src/routes/system.rs: -------------------------------------------------------------------------------- 1 | use aide::axum::{routing::get, ApiRouter}; 2 | use axum_jsonschema::Json; 3 | use schemars::JsonSchema; 4 | 5 | pub fn handler() -> ApiRouter { 6 | ApiRouter::new().api_route("/", get(root)) 7 | } 8 | 9 | #[derive(Debug, serde::Serialize, JsonSchema)] 10 | pub struct AppVersion { 11 | /// Current version of the application 12 | semver: String, 13 | /// Commit hash of the current build (if available) 14 | rev: Option, 15 | /// The time the application was compiled at 16 | compile_time: String, 17 | } 18 | 19 | #[derive(Debug, serde::Serialize, JsonSchema)] 20 | pub struct RootResponse { 21 | /// Relative URL to Swagger UI 22 | pub docs_url: String, 23 | /// Relative URL to `OpenAPI` specification 24 | pub openapi_url: String, 25 | /// Application version 26 | pub version: AppVersion, 27 | } 28 | 29 | #[allow(clippy::unused_async)] 30 | pub async fn root() -> Json { 31 | Json(RootResponse { 32 | docs_url: "/docs".to_string(), 33 | openapi_url: "/openapi.json".to_string(), 34 | version: AppVersion { 35 | semver: env!("CARGO_PKG_VERSION").to_string(), 36 | compile_time: env!("STATIC_BUILD_DATE").to_string(), 37 | rev: option_env!("GIT_REV").map(ToString::to_string), 38 | }, 39 | }) 40 | } 41 | -------------------------------------------------------------------------------- /crates/server/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | version = "0.1.0" 3 | name = "orbit-server" 4 | description = "Orbit enables simple & secure zero-downtime deployments for your Laravel apps." 5 | 6 | readme.workspace = true 7 | license.workspace = true 8 | edition.workspace = true 9 | authors.workspace = true 10 | repository.workspace = true 11 | 12 | [dependencies] 13 | axum = "0.7.5" 14 | http = "1.1.0" 15 | tar = "0.4.41" 16 | slug = "0.1.5" 17 | toml = "0.8.15" 18 | shlex = "1.3.0" 19 | anyhow = "1.0.71" 20 | symlink = "0.1.0" 21 | serde = "1.0.165" 22 | flate2 = "1.0.30" 23 | indexmap = "2.2.6" 24 | dotenvy = "0.15.7" 25 | tracing = "0.1.37" 26 | reqwest = "0.12.5" 27 | schemars = "0.8.12" 28 | thiserror = "1.0.63" 29 | serde_json = "1.0.99" 30 | futures-util = "0.3.30" 31 | async-fn-stream = "0.2.2" 32 | uuid = { version = "1.10.0", features = ["v7"] } 33 | tokio = { version = "1.29.1", features = ["full"] } 34 | orbit-types = { version = "0.1.0", path = "../types" } 35 | axum-jsonschema = { version = "0.8.0", features = ["aide"] } 36 | axum-extra = { version = "0.9.3", features = ["typed-header"] } 37 | tracing-subscriber = { version = "0.3.17", features = ["env-filter"] } 38 | aide = { version = "0.13.4", features = ["axum", "axum-headers", "scalar"] } 39 | 40 | [build-dependencies] 41 | chrono = "0.4.26" 42 | -------------------------------------------------------------------------------- /crates/server/src/server.rs: -------------------------------------------------------------------------------- 1 | use aide::openapi::{self, OpenApi}; 2 | use anyhow::Result; 3 | use axum::Extension; 4 | use std::{env, net::SocketAddr}; 5 | use tokio::{net::TcpListener, signal}; 6 | 7 | use crate::{config::Config, routes}; 8 | 9 | #[allow(clippy::redundant_pub_crate)] 10 | pub(crate) async fn start(config: Config) -> Result<()> { 11 | let mut openapi = OpenApi { 12 | info: openapi::Info { 13 | title: "Orbit".to_string(), 14 | version: env!("CARGO_PKG_VERSION").to_string(), 15 | ..openapi::Info::default() 16 | }, 17 | ..OpenApi::default() 18 | }; 19 | 20 | let router = routes::handler().finish_api(&mut openapi); 21 | 22 | let router = router.layer(config.extension()).layer(Extension(openapi)); 23 | 24 | let addr = SocketAddr::from(( 25 | [0, 0, 0, 0], 26 | env::var("PORT").map_or(Ok(8000), |p| p.parse())?, 27 | )); 28 | let listener = TcpListener::bind(&addr).await?; 29 | 30 | tracing::info!("Starting server on {addr}..."); 31 | 32 | axum::serve(listener, router.into_make_service()) 33 | .with_graceful_shutdown(shutdown_signal()) 34 | .await?; 35 | 36 | Ok(()) 37 | } 38 | 39 | async fn shutdown_signal() { 40 | let ctrl_c = async { 41 | signal::ctrl_c() 42 | .await 43 | .expect("failed to install Ctrl+C handler"); 44 | }; 45 | 46 | #[cfg(unix)] 47 | let terminate = async { 48 | signal::unix::signal(signal::unix::SignalKind::terminate()) 49 | .expect("failed to install signal handler") 50 | .recv() 51 | .await; 52 | }; 53 | 54 | #[cfg(not(unix))] 55 | let terminate = std::future::pending::<()>(); 56 | 57 | tokio::select! { 58 | () = ctrl_c => {}, 59 | () = terminate => {}, 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /crates/server/src/routes/sites.rs: -------------------------------------------------------------------------------- 1 | use std::{convert::Infallible, sync::Arc}; 2 | 3 | use aide::axum::{routing::post, ApiRouter}; 4 | use axum::{ 5 | extract::{Path, Query}, 6 | http::StatusCode, 7 | response::sse::{Event, KeepAlive}, 8 | Extension, 9 | }; 10 | use axum_extra::{ 11 | headers::{authorization::Bearer, Authorization}, 12 | TypedHeader, 13 | }; 14 | use futures_util::{stream::Stream, StreamExt}; 15 | use orbit_types::{ErrorResponse, Progress}; 16 | use schemars::JsonSchema; 17 | use serde::Deserialize; 18 | 19 | use crate::{ 20 | config::{Config, SiteCollectionExt}, 21 | misc::Sse, 22 | }; 23 | 24 | pub fn handler() -> ApiRouter { 25 | ApiRouter::new().api_route("/sites/:site/deploy", post(deploy_site)) 26 | } 27 | 28 | #[derive(Debug, Deserialize, JsonSchema)] 29 | pub struct DeployConfig { 30 | /// The Git reference to deploy. If not provided, the default branch will be used. 31 | r#ref: Option, 32 | } 33 | 34 | pub async fn deploy_site( 35 | Path(site_id): Path, 36 | Query(params): Query, 37 | Extension(config): Extension>, 38 | TypedHeader(authorization): TypedHeader>, 39 | ) -> Result>>, StatusCode> { 40 | if authorization.token() != config.token { 41 | return Err(StatusCode::UNAUTHORIZED); 42 | } 43 | 44 | let Some(site) = config.sites.find(&site_id) else { 45 | return Err(StatusCode::NOT_FOUND); 46 | }; 47 | 48 | let stream = site 49 | .deploy(params.r#ref) 50 | .stream() 51 | .map(|result| match result { 52 | Ok(Progress::Log(log)) => Event::default().id("log").json_data(log).unwrap(), 53 | Ok(Progress::Stage(stage)) => Event::default().id("stage").json_data(stage).unwrap(), 54 | Err(e) => { 55 | tracing::error!(e = ?e); 56 | 57 | Event::default() 58 | .id("error") 59 | .json_data(ErrorResponse::from(e)) 60 | .unwrap() 61 | }, 62 | }) 63 | .map(Ok); 64 | 65 | Ok(Sse::new(stream).keep_alive(KeepAlive::default())) 66 | } 67 | -------------------------------------------------------------------------------- /crates/cli/src/utils.rs: -------------------------------------------------------------------------------- 1 | use fern::colors::{Color, ColoredLevelConfig}; 2 | use log::{Level, LevelFilter}; 3 | 4 | pub fn set_hook() { 5 | // setup a panic hook to easily exit the program on panic 6 | std::panic::set_hook(Box::new(|panic_info| { 7 | // print the panic message 8 | let message = panic_info.payload().downcast_ref::().map_or_else( 9 | || { 10 | panic_info.payload().downcast_ref::<&str>().map_or_else( 11 | || format!("{panic_info:?}"), 12 | |message| (*message).to_string(), 13 | ) 14 | }, 15 | Clone::clone, 16 | ); 17 | 18 | // add some color 19 | log::error!("{message}"); 20 | 21 | #[cfg(debug_assertions)] 22 | log::debug!("{panic_info}"); 23 | 24 | std::process::exit(1); 25 | })); 26 | } 27 | 28 | pub fn logs(verbose: bool) { 29 | let colors = ColoredLevelConfig::new() 30 | .info(Color::BrightCyan) 31 | .error(Color::BrightRed) 32 | .warn(Color::BrightYellow) 33 | .debug(Color::BrightWhite); 34 | 35 | fern::Dispatch::new() 36 | .format(move |out, message, record| { 37 | let level = record.level(); 38 | 39 | match level { 40 | Level::Debug => out.finish(format_args!( 41 | "{} [{}]: {}", 42 | colors.color(Level::Debug).to_string().to_lowercase(), 43 | record.target(), 44 | message 45 | )), 46 | 47 | level => out.finish(format_args!( 48 | "{}: {}", 49 | colors.color(level).to_string().to_lowercase(), 50 | message 51 | )), 52 | } 53 | }) 54 | .level(if verbose { 55 | LevelFilter::Debug 56 | } else { 57 | LevelFilter::Info 58 | }) 59 | .chain( 60 | fern::Dispatch::new() 61 | .filter(|metadata| !matches!(metadata.level(), Level::Error | Level::Warn)) 62 | .chain(std::io::stdout()), 63 | ) 64 | .chain( 65 | fern::Dispatch::new() 66 | .level(log::LevelFilter::Error) 67 | .level(log::LevelFilter::Warn) 68 | .chain(std::io::stderr()), 69 | ) 70 | .apply() 71 | .ok(); 72 | } 73 | 74 | pub fn clean_term() { 75 | let term = console::Term::stdout(); 76 | 77 | // if the terminal is a tty, clear the screen and reset the cursor 78 | if term.is_term() { 79 | term.show_cursor().ok(); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /crates/server/src/config.rs: -------------------------------------------------------------------------------- 1 | use anyhow::{bail, Result}; 2 | use axum::Extension; 3 | use serde::{Deserialize, Serialize}; 4 | use slug::slugify; 5 | use std::{ 6 | path::{Path, PathBuf}, 7 | sync::Arc, 8 | }; 9 | 10 | use crate::deploy::Deployer; 11 | 12 | #[derive(Debug, Serialize, Deserialize)] 13 | pub struct Config { 14 | version: usize, 15 | pub token: String, 16 | pub sites: Vec, 17 | } 18 | 19 | impl Config { 20 | /// Load the config from a TOML file at the given path. 21 | pub fn load>(path: P) -> Result { 22 | if !path.as_ref().exists() { 23 | return Err(anyhow::anyhow!( 24 | "Could not locate Orbit config file at path {}", 25 | path.as_ref().display() 26 | )); 27 | } 28 | 29 | let file = std::fs::read_to_string(path)?; 30 | let config: Self = toml::from_str(&file)?; 31 | 32 | if config.version != 1 { 33 | return Err(anyhow::anyhow!("Unsupported version: {}", config.version)); 34 | } 35 | 36 | Ok(config) 37 | } 38 | 39 | pub fn validate(self) -> Result { 40 | if std::env::var("GITHUB_TOKEN").is_err() { 41 | bail!("$GITHUB_TOKEN is not set"); 42 | } 43 | 44 | if self.token.len() < 32 { 45 | bail!("Orbit token is too short. Must be at least 32 characters long."); 46 | } 47 | 48 | self.sites.iter().try_for_each(|site| { 49 | if !site.github_repo.contains('/') { 50 | bail!( 51 | "Invalid github_repo for site {}. Must be in the format of owner/repo", 52 | site.name 53 | ); 54 | } 55 | 56 | Ok(()) 57 | })?; 58 | 59 | Ok(self) 60 | } 61 | 62 | pub fn extension(self) -> Extension> { 63 | Extension(Arc::new(self)) 64 | } 65 | } 66 | 67 | pub trait SiteCollectionExt { 68 | fn find(&self, slug: &str) -> Option; 69 | } 70 | 71 | impl SiteCollectionExt for Vec { 72 | fn find(&self, slug: &str) -> Option { 73 | self.iter() 74 | .find(|site| slugify(&site.name) == slug) 75 | .cloned() 76 | } 77 | } 78 | 79 | #[allow(clippy::unsafe_derive_deserialize)] 80 | #[derive(Clone, Debug, Serialize, Deserialize)] 81 | pub struct Site { 82 | pub name: String, 83 | pub path: PathBuf, 84 | pub github_repo: String, 85 | #[serde(default)] 86 | pub commands: Vec, 87 | } 88 | 89 | impl Site { 90 | pub fn deploy(self, r#ref: Option) -> Deployer { 91 | Deployer::from_site(self, r#ref) 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /crates/types/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![warn(clippy::all, clippy::pedantic, clippy::nursery)] 2 | 3 | use serde::{Deserialize, Serialize}; 4 | 5 | /// A progress update for a deployment. 6 | pub enum Progress { 7 | Log(Log), 8 | Stage(Stage), 9 | } 10 | 11 | /// A log message. 12 | #[derive(Debug, Serialize, Deserialize)] 13 | #[serde(tag = "type", content = "log")] 14 | pub enum Log { 15 | Info(String), 16 | Error(String), 17 | } 18 | 19 | /// The stage of the deployment. 20 | #[derive(Debug, Serialize, Deserialize)] 21 | #[serde(rename_all = "snake_case")] 22 | pub enum Stage { 23 | /// The deployment has been started. 24 | Starting, 25 | /// The current deployment has been downloaded. 26 | Downloaded, 27 | /// Dependencies for the current deployment have been installed. 28 | DepsInstalled, 29 | /// The current deployment has been migrated. 30 | Migrated, 31 | /// The current deployment has been optimized. 32 | Optimized, 33 | /// The deployment is now live. 34 | Deployed, 35 | } 36 | 37 | #[derive(Debug, thiserror::Error, Serialize, Deserialize)] 38 | #[serde(rename_all = "snake_case")] 39 | pub enum Error { 40 | /// Failed to boorstrap the project. 41 | #[error("Failed to bootstrap the project.")] 42 | Bootstrap, 43 | 44 | /// Failed to clone the repository. 45 | #[error("Failed to clone the repository.")] 46 | Download, 47 | 48 | /// Failed to extract the repository contents. 49 | #[error("Failed to extract the repository contents.")] 50 | Extraction, 51 | 52 | /// Failed to configure the deployment. 53 | #[error("Failed to configure the deployment.")] 54 | Configure, 55 | 56 | /// Failed to install dependencies. 57 | #[error("Failed to install dependencies.")] 58 | InstallDeps, 59 | 60 | /// Failed to run definded commands. 61 | #[error("Failed to run defined commands.")] 62 | RunCommands, 63 | 64 | #[error("Failed to optimize the deployment.")] 65 | Optimize, 66 | 67 | /// Failed to build the deployment. 68 | #[error("Failed to cleanup old deployments.")] 69 | Cleanup, 70 | 71 | /// Failed to build the deployment. 72 | #[error("Failed to publish the new deployment.")] 73 | Publish, 74 | } 75 | 76 | #[derive(Debug, Serialize, Deserialize)] 77 | pub struct ErrorResponse { 78 | pub error: Error, 79 | pub message: String, 80 | } 81 | 82 | impl From for ErrorResponse { 83 | fn from(error: Error) -> Self { 84 | Self { 85 | message: error.to_string(), 86 | error, 87 | } 88 | } 89 | } 90 | 91 | impl From for Progress { 92 | fn from(value: Stage) -> Self { 93 | Self::Stage(value) 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 🛰️ Put your Laravel sites in Orbit. 2 | 3 | > Orbit provides a simple way to deploy your Laravel sites to your server in a few seconds. 4 | 5 | ## Get Started 6 | 7 | 1. Get the Orbit server up and running on your VPS. You'll need a [GitHub token](https://github.com/settings/personal-access-tokens/new) and the [server binary](https://github.com/m1guelpf/orbit/releases/latest) (there's a [Docker image](https://github.com/m1guelpf/orbit/pkgs/container/orbit-server) too!). 8 | > The Orbit server exposes an HTTP API, which you'll need to make accessible to the outside world. 9 | 2. Create an `Orbit.toml` config file and add your sites to it, like so: 10 | 11 | ```toml 12 | version = 1 13 | token = "" # Use `openssl rand -base64 32` to generate a random token 14 | 15 | [[sites]] 16 | name = "Test Site" 17 | path = "/var/www/test-site" 18 | github_repo = "m1guelpf/laravel-test" 19 | commands = [ # Extra commands to run during the deployment (optional) 20 | "php horizon:terminate" 21 | ] 22 | ``` 23 | 24 | 3. Create a `.github/workflows/deploy.yaml` GitHub action, like so: 25 | 26 | ```yaml 27 | name: Deploy to prod 28 | on: 29 | push: 30 | branches: [main] 31 | 32 | jobs: 33 | deploy: 34 | runs-on: ubuntu-latest 35 | steps: 36 | - name: Deploy to prod 37 | uses: m1guelpf/orbit@main 38 | with: 39 | site: alexandria # slug of your site, generated from the name above 40 | orbit-url: ${{ secrets.ORBIT_URL }} # URL to your Orbit instance 41 | orbit-token: ${{ secrets.ORBIT_TOKEN }} # The token you generated on your Orbit config 42 | ``` 43 | 44 | 4. That's it! Pushing to `main` will now deploy your site, with no downtime for your users 🎉 45 | 46 | ## Architecture 47 | 48 | ### 🌐 Orbit Server 49 | 50 | The Orbit Server is the main component of the system. It exposes an HTTP API that lets you trigger deployments and streams the results back in real time. It's the module that actually contains the logic for deploying the sites. 51 | 52 | ### 🌠 Orbit Client 53 | 54 | To make interacting with the Server easier, the Orbit Client provides a simple Rust interface for calling the API, dealing with serialization and such. If you want to write your own Orbit integration, it'll let you interact with the Server as if it was just another crate. 55 | 56 | ### 🐙 Orbit CLI & GitHub Action 57 | 58 | To make deployments easier for end users, Orbit also includes a CLI that provides user-friendly live output for deployments. And, if you want to run it from GitHub Actions, it comes packaged into its own GitHub Action, making zero-downtime deployments a one-line change. 59 | 60 | ## License 61 | 62 | This project is licensed under the MIT License - see the [LICENSE file](LICENSE) for details. 63 | -------------------------------------------------------------------------------- /.github/workflows/build.yaml: -------------------------------------------------------------------------------- 1 | name: Build 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | 8 | permissions: 9 | contents: read 10 | packages: write 11 | 12 | jobs: 13 | docker: 14 | runs-on: ubuntu-latest 15 | strategy: 16 | matrix: 17 | include: 18 | - image: orbit-server 19 | dockerfile: ./Dockerfile.server 20 | - image: orbit-cli 21 | dockerfile: ./Dockerfile.cli 22 | steps: 23 | - uses: actions/checkout@v4 24 | 25 | - name: Set up Docker Buildx 26 | uses: docker/setup-buildx-action@v3 27 | 28 | - name: Docker meta 29 | id: meta 30 | uses: docker/metadata-action@v5 31 | with: 32 | images: | 33 | ghcr.io/m1guelpf/${{ matrix.image }} 34 | tags: | 35 | type=sha 36 | type=edge 37 | 38 | - name: Login to GitHub Container Registry 39 | uses: docker/login-action@v3 40 | with: 41 | registry: ghcr.io 42 | username: '${{ github.actor }}' 43 | password: '${{ secrets.GITHUB_TOKEN }}' 44 | 45 | - name: Build and push 46 | id: docker_build 47 | uses: docker/build-push-action@v6 48 | with: 49 | push: true 50 | context: . 51 | cache-from: type=gha 52 | cache-to: 'type=gha,mode=max' 53 | file: '${{ matrix.dockerfile }}' 54 | tags: '${{ steps.meta.outputs.tags }}' 55 | labels: '${{ steps.meta.outputs.labels }}' 56 | env: 57 | DOCKER_BUILD_SUMMARY: false 58 | DOCKER_BUILD_RECORD_UPLOAD: false 59 | 60 | binaries: 61 | runs-on: ubuntu-latest 62 | steps: 63 | - uses: actions/checkout@v4 64 | 65 | - name: Install Rust 66 | uses: dtolnay/rust-toolchain@stable 67 | with: 68 | toolchain: stable 69 | target: x86_64-unknown-linux-musl 70 | 71 | - name: Build 72 | run: cargo build --release --bins 73 | 74 | - name: Upload orbit-server binary 75 | uses: actions/upload-artifact@v4 76 | with: 77 | name: orbit-server 78 | path: target/release/orbit-server 79 | 80 | - name: Upload orbit-cli binary 81 | uses: actions/upload-artifact@v4 82 | with: 83 | name: orbit-cli 84 | path: target/release/orbit-cli 85 | -------------------------------------------------------------------------------- /crates/cli/src/main.rs: -------------------------------------------------------------------------------- 1 | #![warn(clippy::all, clippy::pedantic, clippy::nursery)] 2 | 3 | use anyhow::Result; 4 | use clap::{Parser, Subcommand}; 5 | use futures_util::StreamExt; 6 | use orbit_client::Client; 7 | use orbit_types::{Log, Progress, Stage}; 8 | use pin_utils::pin_mut; 9 | use url::Url; 10 | 11 | mod utils; 12 | 13 | #[derive(Debug, Parser)] 14 | #[clap( 15 | name = "orbit", 16 | about = "🪐 Trigger Orbit deploys from the command line.", 17 | version, 18 | author 19 | )] 20 | struct Cli { 21 | /// URL to the Orbit instance. 22 | #[arg(short, long, env = "ORBIT_URL")] 23 | url: Url, 24 | 25 | /// Orbit authenticaton token. 26 | #[arg(short, long, env = "ORBIT_TOKEN")] 27 | token: String, 28 | 29 | /// Enable debug mode 30 | #[clap(short = 'D', long)] 31 | pub debug: bool, 32 | 33 | #[clap(subcommand)] 34 | command: Commands, 35 | } 36 | 37 | #[derive(Debug, Subcommand)] 38 | enum Commands { 39 | /// Trigger a deploy for an Orbit site. 40 | Deploy { 41 | /// The name of the site to deploy. 42 | slug: String, 43 | 44 | /// The git ref to deploy. If not provided, the default branch will be used. 45 | #[arg(long, env = "DEPLOY_REF")] 46 | r#ref: Option, 47 | }, 48 | } 49 | 50 | #[tokio::main] 51 | async fn main() -> Result<()> { 52 | let cli = Cli::parse(); 53 | 54 | // setup panic hook 55 | utils::set_hook(); 56 | utils::logs(cli.debug); 57 | 58 | let client = Client::new(cli.url, cli.token); 59 | 60 | if let Err(error) = handle_command(cli.command, &client).await { 61 | log::error!("{error}"); 62 | log::debug!("{error:#?}"); 63 | std::process::exit(1); 64 | } 65 | 66 | utils::clean_term(); 67 | 68 | Ok(()) 69 | } 70 | 71 | async fn handle_command(commands: Commands, client: &Client) -> Result<()> { 72 | match commands { 73 | Commands::Deploy { slug, r#ref } => { 74 | run_deploy(slug, r#ref.filter(|s| !s.is_empty()), client).await 75 | }, 76 | } 77 | } 78 | 79 | async fn run_deploy(slug: String, r#ref: Option, client: &Client) -> Result<()> { 80 | let stream = client.deploy(&slug, r#ref.as_deref()); 81 | pin_mut!(stream); 82 | 83 | while let Some(event) = stream.next().await { 84 | match event? { 85 | Ok(Progress::Log(log)) => match log { 86 | Log::Info(message) => println!("{message}"), 87 | Log::Error(message) => eprintln!("{message}"), 88 | }, 89 | Ok(Progress::Stage(stage)) => match stage { 90 | Stage::Deployed => log::info!("Deployed site"), 91 | Stage::Migrated => log::info!("Migrated database"), 92 | Stage::Starting => log::info!("Starting deployment"), 93 | Stage::Optimized => log::info!("Optimized deployment"), 94 | Stage::Downloaded => log::info!("Downloaded repository"), 95 | Stage::DepsInstalled => log::info!("Installed dependencies"), 96 | }, 97 | Err(error) => return Err(error.into()), 98 | } 99 | } 100 | 101 | Ok(()) 102 | } 103 | -------------------------------------------------------------------------------- /.github/workflows/release.yaml: -------------------------------------------------------------------------------- 1 | name: Release 2 | 3 | on: 4 | release: 5 | types: [published] 6 | 7 | permissions: 8 | contents: write 9 | packages: write 10 | 11 | jobs: 12 | docker: 13 | runs-on: ubuntu-latest 14 | strategy: 15 | matrix: 16 | include: 17 | - image: orbit-server 18 | dockerfile: ./Dockerfile.server 19 | - image: orbit-cli 20 | dockerfile: ./Dockerfile.cli 21 | steps: 22 | - uses: actions/checkout@v4 23 | 24 | - name: Set up Docker Buildx 25 | uses: docker/setup-buildx-action@v3 26 | 27 | - name: Docker meta 28 | id: meta 29 | uses: docker/metadata-action@v5 30 | with: 31 | images: | 32 | ghcr.io/m1guelpf/${{ matrix.image }} 33 | tags: | 34 | type=semver,pattern={{major}} 35 | type=semver,pattern={{version}} 36 | type=semver,pattern={{major}}.{{minor}} 37 | 38 | - name: Login to GitHub Container Registry 39 | uses: docker/login-action@v3 40 | with: 41 | registry: ghcr.io 42 | username: '${{ github.actor }}' 43 | password: '${{ secrets.GITHUB_TOKEN }}' 44 | 45 | - name: Build and push 46 | id: docker_build 47 | uses: docker/build-push-action@v6 48 | with: 49 | push: true 50 | context: . 51 | cache-from: type=gha 52 | cache-to: 'type=gha,mode=max' 53 | file: '${{ matrix.dockerfile }}' 54 | tags: '${{ steps.meta.outputs.tags }}' 55 | labels: '${{ steps.meta.outputs.labels }}' 56 | env: 57 | DOCKER_BUILD_SUMMARY: false 58 | DOCKER_BUILD_RECORD_UPLOAD: false 59 | 60 | binaries: 61 | runs-on: ubuntu-latest 62 | steps: 63 | - uses: actions/checkout@v4 64 | 65 | - name: Install Rust 66 | uses: dtolnay/rust-toolchain@stable 67 | with: 68 | toolchain: stable 69 | target: x86_64-unknown-linux-musl 70 | 71 | - name: Build 72 | run: cargo build --release --bins 73 | 74 | - name: Upload orbit-server binary 75 | uses: shogo82148/actions-upload-release-asset@v1 76 | with: 77 | asset_path: target/release/orbit-server 78 | upload_url: ${{ github.event.release.upload_url }} 79 | 80 | - name: Upload orbit-cli binary 81 | uses: shogo82148/actions-upload-release-asset@v1 82 | with: 83 | asset_path: target/release/orbit-cli 84 | upload_url: ${{ github.event.release.upload_url }} 85 | -------------------------------------------------------------------------------- /crates/client/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![warn(clippy::all, clippy::pedantic, clippy::nursery)] 2 | 3 | use async_fn_stream::try_fn_stream; 4 | use futures::{stream::StreamExt, Stream}; 5 | use orbit_types::{ErrorResponse, Progress}; 6 | use reqwest::{header, Response, StatusCode}; 7 | use reqwest_eventsource::{Event, RequestBuilderExt}; 8 | use url::Url; 9 | 10 | pub struct Client { 11 | base_url: Url, 12 | token: String, 13 | client: reqwest::Client, 14 | } 15 | 16 | #[derive(Debug, thiserror::Error)] 17 | pub enum Error { 18 | #[error(transparent)] 19 | Stream(#[from] reqwest_eventsource::Error), 20 | 21 | #[error("{0}")] 22 | Transport(#[from] reqwest::Error), 23 | 24 | #[error("Invalid authentication token")] 25 | Unauthorized, 26 | 27 | #[error("Could not find the requested site")] 28 | SiteNotFound, 29 | 30 | #[error("The server returned an invalid response.")] 31 | InvalidResponse(StatusCode, Response), 32 | 33 | #[error("The server returned an invalid event: {0}")] 34 | InvalidEvent(String), 35 | 36 | #[error("Could not decode the event data")] 37 | Decoding(#[from] serde_json::Error), 38 | } 39 | 40 | impl Client { 41 | /// Create a new client. 42 | #[must_use] 43 | pub fn new(base_url: Url, token: String) -> Self { 44 | Self { 45 | token, 46 | base_url, 47 | client: reqwest::Client::new(), 48 | } 49 | } 50 | 51 | /// Deploy a site. 52 | #[allow(clippy::missing_panics_doc)] 53 | pub fn deploy( 54 | &self, 55 | name: &str, 56 | r#ref: Option<&str>, 57 | ) -> impl Stream, Error>> { 58 | let mut stream = self 59 | .client 60 | .post( 61 | self.base_url 62 | .join(&format!("/sites/{name}/deploy")) 63 | .unwrap(), 64 | ) 65 | .query(&[("ref", r#ref)]) 66 | .header(header::AUTHORIZATION, format!("Bearer {}", self.token)) 67 | .eventsource() 68 | .unwrap(); 69 | 70 | try_fn_stream(|emitter| async move { 71 | while let Some(event) = stream.next().await { 72 | let event = match event { 73 | Ok(Event::Open) => continue, 74 | Ok(Event::Message(message)) => message, 75 | Err(reqwest_eventsource::Error::InvalidStatusCode(status_code, response)) => { 76 | match status_code { 77 | StatusCode::NOT_FOUND => return Err(Error::SiteNotFound), 78 | StatusCode::UNAUTHORIZED => return Err(Error::Unauthorized), 79 | _ => return Err(Error::InvalidResponse(status_code, response)), 80 | } 81 | }, 82 | Err(reqwest_eventsource::Error::StreamEnded) => return Ok(()), 83 | Err(reqwest_eventsource::Error::Transport(err)) => return Err(err.into()), 84 | Err(err) => return Err(err.into()), 85 | }; 86 | 87 | let response = match event.id.as_ref() { 88 | "log" => Ok(Progress::Log(serde_json::from_str(&event.data)?)), 89 | "stage" => Ok(Progress::Stage(serde_json::from_str(&event.data)?)), 90 | "error" => Err(serde_json::from_str::(&event.data)?.error), 91 | _ => return Err(Error::InvalidEvent(format!("{}: {}", event.id, event.data))), 92 | }; 93 | 94 | emitter.emit(response).await; 95 | } 96 | 97 | unreachable!("The stream should not end without a StreamEnded error"); 98 | }) 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /crates/server/src/misc.rs: -------------------------------------------------------------------------------- 1 | use aide::{ 2 | openapi::{MediaType, Operation, Response, SchemaObject}, 3 | r#gen::GenContext, 4 | }; 5 | use async_fn_stream::try_fn_stream; 6 | use axum::response::{ 7 | sse::{Event, KeepAlive}, 8 | IntoResponse, 9 | }; 10 | use futures_util::Stream; 11 | use indexmap::IndexMap; 12 | use orbit_types::Log; 13 | use schemars::JsonSchema; 14 | use std::{ 15 | fs, 16 | io::{self, Read}, 17 | path::Path, 18 | process::Stdio, 19 | rc::Rc, 20 | }; 21 | use tokio::{ 22 | io::{AsyncBufReadExt, BufReader}, 23 | process::Command, 24 | }; 25 | 26 | #[derive(Debug)] 27 | #[repr(transparent)] 28 | pub struct Sse(axum::response::Sse); 29 | 30 | impl Sse { 31 | /// Create a new [`Sse`] response that will respond with the given stream of 32 | /// [`Event`]s. 33 | /// 34 | /// See the [module docs](self) for more details. 35 | pub fn new(stream: S) -> Self 36 | where 37 | S: futures_util::TryStream + Send + 'static, 38 | S::Error: Into, 39 | { 40 | Self(axum::response::sse::Sse::new(stream)) 41 | } 42 | 43 | /// Configure the interval between keep-alive messages. 44 | /// 45 | /// Defaults to no keep-alive messages. 46 | pub fn keep_alive(mut self, keep_alive: KeepAlive) -> Self { 47 | self.0 = self.0.keep_alive(keep_alive); 48 | 49 | self 50 | } 51 | } 52 | 53 | impl IntoResponse for Sse 54 | where 55 | S: Stream> + Send + 'static, 56 | E: Into, 57 | { 58 | fn into_response(self) -> axum::response::Response { 59 | self.0.into_response() 60 | } 61 | } 62 | 63 | impl aide::OperationOutput for Sse 64 | where 65 | S: Stream> + Send + 'static, 66 | E: Into, 67 | { 68 | type Inner = String; 69 | 70 | fn operation_response(ctx: &mut GenContext, _operation: &mut Operation) -> Option { 71 | Some(Response { 72 | description: "An SSE event stream".into(), 73 | content: IndexMap::from_iter([( 74 | "text/event-stream".into(), 75 | MediaType { 76 | schema: Some(SchemaObject { 77 | json_schema: String::json_schema(&mut ctx.schema), 78 | example: None, 79 | external_docs: None, 80 | }), 81 | ..Default::default() 82 | }, 83 | )]), 84 | ..Default::default() 85 | }) 86 | } 87 | 88 | fn inferred_responses( 89 | ctx: &mut aide::gen::GenContext, 90 | operation: &mut Operation, 91 | ) -> Vec<(Option, Response)> { 92 | Self::operation_response(ctx, operation).map_or_else(Vec::new, |res| vec![(Some(200), res)]) 93 | } 94 | } 95 | 96 | pub fn untar_to(mut tar: tar::Archive, path: &Path) -> io::Result<()> { 97 | for entry in tar.entries()? { 98 | let mut file = entry?; 99 | let file_path = file.path()?.into_owned(); 100 | let file_path = file_path 101 | .strip_prefix(file_path.components().next().unwrap()) 102 | .unwrap() 103 | .to_owned(); 104 | 105 | if file_path.to_str() == Some("") { 106 | continue; 107 | } 108 | 109 | if !file.header().entry_type().is_dir() { 110 | fs::create_dir_all(path.join(&file_path).parent().unwrap())?; 111 | file.unpack(path.join(file_path))?; 112 | } 113 | } 114 | 115 | Ok(()) 116 | } 117 | 118 | pub fn spawn_with_logs(cmd: &mut Command) -> impl Stream> { 119 | let process = cmd.stdout(Stdio::piped()).stderr(Stdio::piped()).spawn(); 120 | let pretty_cmd = pretty_cmd(cmd.as_std()); 121 | 122 | try_fn_stream(|stream| async move { 123 | if let Some(pretty_cmd) = pretty_cmd { 124 | stream.emit(Log::Info(pretty_cmd)).await; 125 | } 126 | 127 | let mut process = process?; 128 | 129 | let mut stdout = BufReader::new(process.stdout.as_mut().unwrap()).lines(); 130 | let mut stderr = BufReader::new(process.stderr.as_mut().unwrap()).lines(); 131 | 132 | loop { 133 | tokio::select! { 134 | line = stdout.next_line() => { 135 | if let Some(line) = line? { 136 | stream.emit(Log::Info(line)).await; 137 | } else { 138 | break; 139 | } 140 | } 141 | line = stderr.next_line() => { 142 | if let Some(line) = line? { 143 | stream.emit(Log::Error(line)).await; 144 | } else { 145 | break; 146 | } 147 | } 148 | } 149 | } 150 | 151 | let status = process.wait().await?; 152 | if !status.success() { 153 | return Err(io::Error::new( 154 | io::ErrorKind::Other, 155 | format!("Command failed with status: {status}"), 156 | )); 157 | } 158 | 159 | Ok(()) 160 | }) 161 | } 162 | 163 | fn pretty_cmd(cmd: &std::process::Command) -> Option { 164 | let bin = cmd.get_program().to_str()?; 165 | let args = cmd 166 | .get_args() 167 | .map(|s| s.to_str()) 168 | .collect::>>()? 169 | .join(" "); 170 | 171 | Some(format!("$ {bin} {args}")) 172 | } 173 | -------------------------------------------------------------------------------- /crates/server/src/deploy.rs: -------------------------------------------------------------------------------- 1 | use async_fn_stream::try_fn_stream; 2 | use flate2::read::GzDecoder; 3 | use futures_util::{Stream, StreamExt, TryStreamExt}; 4 | use http::header; 5 | use orbit_types::{Log, Progress, Stage}; 6 | use shlex::Shlex; 7 | use std::{env, fs, path::PathBuf}; 8 | use tokio::process::Command; 9 | use uuid::Uuid; 10 | 11 | use crate::{ 12 | config::Site, 13 | misc::{spawn_with_logs, untar_to}, 14 | }; 15 | 16 | #[derive(Debug, thiserror::Error)] 17 | pub enum Error { 18 | #[error("Failed to bootstrap the project.")] 19 | Bootstrap(std::io::Error), 20 | 21 | #[error("Failed to clone the repository.")] 22 | Download(#[from] reqwest::Error), 23 | 24 | #[error("Failed to extract the repository contents.")] 25 | Extraction(std::io::Error), 26 | 27 | #[error("Failed to configure the deployment.")] 28 | Configure(std::io::Error), 29 | 30 | #[error("Failed to install dependencies.")] 31 | InstallDeps(std::io::Error), 32 | 33 | #[error("Failed to run defined commands.")] 34 | RunCommands(std::io::Error), 35 | 36 | #[error("Failed to optimize the deployment.")] 37 | Optimize(std::io::Error), 38 | 39 | #[error("Failed to cleanup old deployments.")] 40 | Cleanup(std::io::Error), 41 | 42 | #[error("Failed to publish the new deployment.")] 43 | Publish(std::io::Error), 44 | } 45 | 46 | impl From for orbit_types::Error { 47 | fn from(value: Error) -> Self { 48 | match value { 49 | Error::Cleanup(_) => Self::Cleanup, 50 | Error::Publish(_) => Self::Publish, 51 | Error::Download(_) => Self::Download, 52 | Error::Optimize(_) => Self::Optimize, 53 | Error::Bootstrap(_) => Self::Bootstrap, 54 | Error::Configure(_) => Self::Configure, 55 | Error::Extraction(_) => Self::Extraction, 56 | Error::InstallDeps(_) => Self::InstallDeps, 57 | Error::RunCommands(_) => Self::RunCommands, 58 | } 59 | } 60 | } 61 | 62 | impl From for orbit_types::ErrorResponse { 63 | fn from(value: Error) -> Self { 64 | Self::from(orbit_types::Error::from(value)) 65 | } 66 | } 67 | 68 | pub struct Deployer { 69 | site: Site, 70 | deployment_id: Uuid, 71 | github_token: String, 72 | r#ref: Option, 73 | client: reqwest::Client, 74 | } 75 | 76 | impl Deployer { 77 | pub fn from_site(site: Site, r#ref: Option) -> Self { 78 | // we unwrap here since Config::validate errors ealier if GITHUB_TOKEN is not set 79 | let github_token = env::var("GITHUB_TOKEN").expect("GITHUB_TOKEN is not set"); 80 | 81 | Self { 82 | site, 83 | r#ref, 84 | github_token, 85 | deployment_id: Uuid::now_v7(), 86 | client: reqwest::Client::builder() 87 | .user_agent("orbit-deployer") 88 | .build() 89 | .unwrap(), 90 | } 91 | } 92 | 93 | pub fn stream(self) -> impl Stream> { 94 | try_fn_stream(|stream| async move { 95 | stream.emit(Stage::Starting.into()).await; 96 | 97 | self.bootstrap_site()?; 98 | self.download_repo().await?; 99 | 100 | stream.emit(Stage::Downloaded.into()).await; 101 | 102 | self.configure_deployment()?; 103 | 104 | if self.should_install_deps() { 105 | self.install_deps() 106 | .try_for_each(|log| async { 107 | stream.emit(Progress::Log(log)).await; 108 | Ok(()) 109 | }) 110 | .await?; 111 | 112 | stream.emit(Stage::DepsInstalled.into()).await; 113 | } 114 | 115 | self.run_commands() 116 | .try_for_each(|log| async { 117 | stream.emit(Progress::Log(log)).await; 118 | Ok(()) 119 | }) 120 | .await?; 121 | 122 | self.optimize_deployment() 123 | .try_for_each(|log| async { 124 | stream.emit(Progress::Log(log)).await; 125 | Ok(()) 126 | }) 127 | .await?; 128 | 129 | stream.emit(Stage::Optimized.into()).await; 130 | 131 | self.migrate() 132 | .try_for_each(|log| async { 133 | stream.emit(Progress::Log(log)).await; 134 | Ok(()) 135 | }) 136 | .await?; 137 | 138 | stream.emit(Stage::Migrated.into()).await; 139 | 140 | self.set_live()?; 141 | stream.emit(Stage::Deployed.into()).await; 142 | 143 | self.clear_old_deployments()?; 144 | 145 | Ok(()) 146 | }) 147 | } 148 | 149 | fn bootstrap_site(&self) -> Result<(), Error> { 150 | fs::create_dir_all(self.get_path()).map_err(Error::Bootstrap)?; 151 | 152 | let current_path = self.site.path.join("current"); 153 | if current_path.exists() && !current_path.is_symlink() { 154 | fs::remove_dir_all(current_path).map_err(Error::Bootstrap)?; 155 | } 156 | 157 | let storage_path = self.site.path.join("storage"); 158 | if !storage_path.exists() { 159 | fs::create_dir_all(storage_path.join("logs")).map_err(Error::Bootstrap)?; 160 | fs::create_dir_all(storage_path.join("app/public")).map_err(Error::Bootstrap)?; 161 | fs::create_dir_all(storage_path.join("framework/cache")).map_err(Error::Bootstrap)?; 162 | fs::create_dir_all(storage_path.join("framework/views")).map_err(Error::Bootstrap)?; 163 | fs::create_dir_all(storage_path.join("framework/sessions")) 164 | .map_err(Error::Bootstrap)?; 165 | } 166 | 167 | Ok(()) 168 | } 169 | 170 | async fn download_repo(&self) -> Result<(), Error> { 171 | // we unwrap here since Config::validate errors ealier if `github_repo` does not cointain a `/` 172 | let (owner, repo) = self.site.github_repo.split_once('/').unwrap(); 173 | 174 | let tarball = self 175 | .client 176 | .get(format!( 177 | "https://api.github.com/repos/{owner}/{repo}/tarball/{}", 178 | self.r#ref 179 | .as_ref() 180 | .map_or(String::new(), |r#ref| format!("/{ref}")) 181 | )) 182 | .header( 183 | header::AUTHORIZATION, 184 | format!("Bearer {}", self.github_token), 185 | ) 186 | .send() 187 | .await? 188 | .error_for_status()? 189 | .bytes() 190 | .await?; 191 | 192 | untar_to( 193 | tar::Archive::new(GzDecoder::new(tarball.as_ref())), 194 | &self.get_path(), 195 | ) 196 | .map_err(Error::Extraction)?; 197 | 198 | Ok(()) 199 | } 200 | 201 | fn configure_deployment(&self) -> Result<(), Error> { 202 | let env_path = self.site.path.join(".env"); 203 | if env_path.exists() { 204 | symlink::symlink_dir(env_path, self.get_path().join(".env")) 205 | .map_err(Error::Configure)?; 206 | } 207 | 208 | let storage_path = self.get_path().join("storage"); 209 | if storage_path.exists() { 210 | fs::remove_dir_all(&storage_path).map_err(Error::Configure)?; 211 | } 212 | symlink::symlink_dir(self.site.path.join("storage"), storage_path) 213 | .map_err(Error::Configure)?; 214 | 215 | Ok(()) 216 | } 217 | 218 | fn install_deps(&self) -> impl Stream> { 219 | spawn_with_logs( 220 | Command::new("composer") 221 | .arg("install") 222 | .arg("--no-dev") 223 | .arg("--prefer-dist") 224 | .arg("--no-interaction") 225 | .arg("--optimize-autoloader") 226 | .current_dir(self.get_path()), 227 | ) 228 | .map_err(Error::InstallDeps) 229 | } 230 | 231 | fn run_commands(&self) -> impl Stream> { 232 | let mut streams = vec![]; 233 | 234 | for command in &self.site.commands { 235 | let mut argv = Shlex::new(command); 236 | 237 | streams.push(spawn_with_logs( 238 | Command::new(argv.next().unwrap()) 239 | .args(argv) 240 | .current_dir(self.get_path()), 241 | )); 242 | } 243 | 244 | futures_util::stream::iter(streams) 245 | .flatten() 246 | .map_err(Error::RunCommands) 247 | } 248 | 249 | fn migrate(&self) -> impl Stream> { 250 | spawn_with_logs( 251 | Command::new("php") 252 | .arg("artisan") 253 | .arg("migrate") 254 | .arg("--force") 255 | .current_dir(self.get_path()), 256 | ) 257 | .map_err(Error::InstallDeps) 258 | } 259 | 260 | fn optimize_deployment(&self) -> impl Stream> { 261 | spawn_with_logs( 262 | Command::new("php") 263 | .arg("artisan") 264 | .arg("optimize") 265 | .current_dir(self.get_path()), 266 | ) 267 | .map_err(Error::Optimize) 268 | } 269 | 270 | fn set_live(&self) -> Result<(), Error> { 271 | let current_deployment = self.site.path.join("current"); 272 | if current_deployment.exists() { 273 | fs::remove_file(¤t_deployment).map_err(Error::Publish)?; 274 | } 275 | 276 | symlink::symlink_dir( 277 | format!("deployments/{}", self.deployment_id), 278 | current_deployment, 279 | ) 280 | .map_err(Error::Publish)?; 281 | 282 | Ok(()) 283 | } 284 | 285 | fn clear_old_deployments(&self) -> Result<(), Error> { 286 | let deployments = 287 | fs::read_dir(self.site.path.join("deployments")).map_err(Error::Cleanup)?; 288 | 289 | let mut deployments: Vec<_> = deployments 290 | .map(|entry| { 291 | entry 292 | .and_then(|e| { 293 | let metadata = e.metadata()?; 294 | Ok((e.path(), metadata.modified()?)) 295 | }) 296 | .map_err(Error::Cleanup) 297 | }) 298 | .collect::>()?; 299 | 300 | deployments.sort_by_key(|(_, modified)| *modified); 301 | deployments 302 | .into_iter() 303 | .filter(|(path, _)| path.is_dir() && path != &self.get_path()) 304 | .rev() 305 | .skip(2) 306 | .try_for_each(|(path, _)| fs::remove_dir_all(path)) 307 | .map_err(Error::Cleanup)?; 308 | 309 | Ok(()) 310 | } 311 | 312 | fn get_path(&self) -> PathBuf { 313 | self.site 314 | .path 315 | .join(format!("deployments/{}", self.deployment_id)) 316 | } 317 | 318 | fn should_install_deps(&self) -> bool { 319 | let path = self.get_path(); 320 | 321 | path.join("composer.json").exists() && !path.join("vendor").exists() 322 | } 323 | } 324 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "addr2line" 7 | version = "0.22.0" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678" 10 | dependencies = [ 11 | "gimli", 12 | ] 13 | 14 | [[package]] 15 | name = "adler" 16 | version = "1.0.2" 17 | source = "registry+https://github.com/rust-lang/crates.io-index" 18 | checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" 19 | 20 | [[package]] 21 | name = "ahash" 22 | version = "0.8.11" 23 | source = "registry+https://github.com/rust-lang/crates.io-index" 24 | checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" 25 | dependencies = [ 26 | "cfg-if", 27 | "getrandom", 28 | "once_cell", 29 | "serde", 30 | "version_check", 31 | "zerocopy", 32 | ] 33 | 34 | [[package]] 35 | name = "aho-corasick" 36 | version = "1.1.3" 37 | source = "registry+https://github.com/rust-lang/crates.io-index" 38 | checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" 39 | dependencies = [ 40 | "memchr", 41 | ] 42 | 43 | [[package]] 44 | name = "aide" 45 | version = "0.13.4" 46 | source = "registry+https://github.com/rust-lang/crates.io-index" 47 | checksum = "7b0e3b97a21e41ec5c19bfd9b4fc1f7086be104f8b988681230247ffc91cc8ed" 48 | dependencies = [ 49 | "axum", 50 | "axum-extra", 51 | "bytes", 52 | "cfg-if", 53 | "http", 54 | "indexmap", 55 | "schemars", 56 | "serde", 57 | "serde_json", 58 | "serde_qs", 59 | "thiserror", 60 | "tower-layer", 61 | "tower-service", 62 | "tracing", 63 | ] 64 | 65 | [[package]] 66 | name = "android-tzdata" 67 | version = "0.1.1" 68 | source = "registry+https://github.com/rust-lang/crates.io-index" 69 | checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" 70 | 71 | [[package]] 72 | name = "android_system_properties" 73 | version = "0.1.5" 74 | source = "registry+https://github.com/rust-lang/crates.io-index" 75 | checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" 76 | dependencies = [ 77 | "libc", 78 | ] 79 | 80 | [[package]] 81 | name = "anstream" 82 | version = "0.6.14" 83 | source = "registry+https://github.com/rust-lang/crates.io-index" 84 | checksum = "418c75fa768af9c03be99d17643f93f79bbba589895012a80e3452a19ddda15b" 85 | dependencies = [ 86 | "anstyle", 87 | "anstyle-parse", 88 | "anstyle-query", 89 | "anstyle-wincon", 90 | "colorchoice", 91 | "is_terminal_polyfill", 92 | "utf8parse", 93 | ] 94 | 95 | [[package]] 96 | name = "anstyle" 97 | version = "1.0.7" 98 | source = "registry+https://github.com/rust-lang/crates.io-index" 99 | checksum = "038dfcf04a5feb68e9c60b21c9625a54c2c0616e79b72b0fd87075a056ae1d1b" 100 | 101 | [[package]] 102 | name = "anstyle-parse" 103 | version = "0.2.4" 104 | source = "registry+https://github.com/rust-lang/crates.io-index" 105 | checksum = "c03a11a9034d92058ceb6ee011ce58af4a9bf61491aa7e1e59ecd24bd40d22d4" 106 | dependencies = [ 107 | "utf8parse", 108 | ] 109 | 110 | [[package]] 111 | name = "anstyle-query" 112 | version = "1.1.0" 113 | source = "registry+https://github.com/rust-lang/crates.io-index" 114 | checksum = "ad186efb764318d35165f1758e7dcef3b10628e26d41a44bc5550652e6804391" 115 | dependencies = [ 116 | "windows-sys 0.52.0", 117 | ] 118 | 119 | [[package]] 120 | name = "anstyle-wincon" 121 | version = "3.0.3" 122 | source = "registry+https://github.com/rust-lang/crates.io-index" 123 | checksum = "61a38449feb7068f52bb06c12759005cf459ee52bb4adc1d5a7c4322d716fb19" 124 | dependencies = [ 125 | "anstyle", 126 | "windows-sys 0.52.0", 127 | ] 128 | 129 | [[package]] 130 | name = "anyhow" 131 | version = "1.0.86" 132 | source = "registry+https://github.com/rust-lang/crates.io-index" 133 | checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" 134 | 135 | [[package]] 136 | name = "async-fn-stream" 137 | version = "0.2.2" 138 | source = "registry+https://github.com/rust-lang/crates.io-index" 139 | checksum = "e71711442f1016c768c259bec59300a10efe753bc3e686ec19e2c6a54a97c29b" 140 | dependencies = [ 141 | "futures-util", 142 | "pin-project-lite", 143 | ] 144 | 145 | [[package]] 146 | name = "async-trait" 147 | version = "0.1.81" 148 | source = "registry+https://github.com/rust-lang/crates.io-index" 149 | checksum = "6e0c28dcc82d7c8ead5cb13beb15405b57b8546e93215673ff8ca0349a028107" 150 | dependencies = [ 151 | "proc-macro2", 152 | "quote", 153 | "syn", 154 | ] 155 | 156 | [[package]] 157 | name = "atomic-waker" 158 | version = "1.1.2" 159 | source = "registry+https://github.com/rust-lang/crates.io-index" 160 | checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" 161 | 162 | [[package]] 163 | name = "autocfg" 164 | version = "1.3.0" 165 | source = "registry+https://github.com/rust-lang/crates.io-index" 166 | checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" 167 | 168 | [[package]] 169 | name = "axum" 170 | version = "0.7.5" 171 | source = "registry+https://github.com/rust-lang/crates.io-index" 172 | checksum = "3a6c9af12842a67734c9a2e355436e5d03b22383ed60cf13cd0c18fbfe3dcbcf" 173 | dependencies = [ 174 | "async-trait", 175 | "axum-core", 176 | "bytes", 177 | "futures-util", 178 | "http", 179 | "http-body", 180 | "http-body-util", 181 | "hyper", 182 | "hyper-util", 183 | "itoa", 184 | "matchit", 185 | "memchr", 186 | "mime", 187 | "percent-encoding", 188 | "pin-project-lite", 189 | "rustversion", 190 | "serde", 191 | "serde_json", 192 | "serde_path_to_error", 193 | "serde_urlencoded", 194 | "sync_wrapper 1.0.1", 195 | "tokio", 196 | "tower", 197 | "tower-layer", 198 | "tower-service", 199 | "tracing", 200 | ] 201 | 202 | [[package]] 203 | name = "axum-core" 204 | version = "0.4.3" 205 | source = "registry+https://github.com/rust-lang/crates.io-index" 206 | checksum = "a15c63fd72d41492dc4f497196f5da1fb04fb7529e631d73630d1b491e47a2e3" 207 | dependencies = [ 208 | "async-trait", 209 | "bytes", 210 | "futures-util", 211 | "http", 212 | "http-body", 213 | "http-body-util", 214 | "mime", 215 | "pin-project-lite", 216 | "rustversion", 217 | "sync_wrapper 0.1.2", 218 | "tower-layer", 219 | "tower-service", 220 | "tracing", 221 | ] 222 | 223 | [[package]] 224 | name = "axum-extra" 225 | version = "0.9.3" 226 | source = "registry+https://github.com/rust-lang/crates.io-index" 227 | checksum = "0be6ea09c9b96cb5076af0de2e383bd2bc0c18f827cf1967bdd353e0b910d733" 228 | dependencies = [ 229 | "axum", 230 | "axum-core", 231 | "bytes", 232 | "futures-util", 233 | "headers", 234 | "http", 235 | "http-body", 236 | "http-body-util", 237 | "mime", 238 | "pin-project-lite", 239 | "serde", 240 | "tower", 241 | "tower-layer", 242 | "tower-service", 243 | "tracing", 244 | ] 245 | 246 | [[package]] 247 | name = "axum-jsonschema" 248 | version = "0.8.0" 249 | source = "registry+https://github.com/rust-lang/crates.io-index" 250 | checksum = "fcffe29ca1b60172349fea781ec34441d598809bd227ccbb5bf5dc2879cd9c78" 251 | dependencies = [ 252 | "aide", 253 | "async-trait", 254 | "axum", 255 | "http", 256 | "http-body", 257 | "itertools", 258 | "jsonschema", 259 | "schemars", 260 | "serde", 261 | "serde_json", 262 | "serde_path_to_error", 263 | "tracing", 264 | ] 265 | 266 | [[package]] 267 | name = "backtrace" 268 | version = "0.3.73" 269 | source = "registry+https://github.com/rust-lang/crates.io-index" 270 | checksum = "5cc23269a4f8976d0a4d2e7109211a419fe30e8d88d677cd60b6bc79c5732e0a" 271 | dependencies = [ 272 | "addr2line", 273 | "cc", 274 | "cfg-if", 275 | "libc", 276 | "miniz_oxide", 277 | "object", 278 | "rustc-demangle", 279 | ] 280 | 281 | [[package]] 282 | name = "base64" 283 | version = "0.21.7" 284 | source = "registry+https://github.com/rust-lang/crates.io-index" 285 | checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" 286 | 287 | [[package]] 288 | name = "base64" 289 | version = "0.22.1" 290 | source = "registry+https://github.com/rust-lang/crates.io-index" 291 | checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" 292 | 293 | [[package]] 294 | name = "bit-set" 295 | version = "0.5.3" 296 | source = "registry+https://github.com/rust-lang/crates.io-index" 297 | checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1" 298 | dependencies = [ 299 | "bit-vec", 300 | ] 301 | 302 | [[package]] 303 | name = "bit-vec" 304 | version = "0.6.3" 305 | source = "registry+https://github.com/rust-lang/crates.io-index" 306 | checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" 307 | 308 | [[package]] 309 | name = "bitflags" 310 | version = "1.3.2" 311 | source = "registry+https://github.com/rust-lang/crates.io-index" 312 | checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" 313 | 314 | [[package]] 315 | name = "bitflags" 316 | version = "2.6.0" 317 | source = "registry+https://github.com/rust-lang/crates.io-index" 318 | checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" 319 | 320 | [[package]] 321 | name = "block-buffer" 322 | version = "0.10.4" 323 | source = "registry+https://github.com/rust-lang/crates.io-index" 324 | checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" 325 | dependencies = [ 326 | "generic-array", 327 | ] 328 | 329 | [[package]] 330 | name = "bumpalo" 331 | version = "3.16.0" 332 | source = "registry+https://github.com/rust-lang/crates.io-index" 333 | checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" 334 | 335 | [[package]] 336 | name = "bytecount" 337 | version = "0.6.8" 338 | source = "registry+https://github.com/rust-lang/crates.io-index" 339 | checksum = "5ce89b21cab1437276d2650d57e971f9d548a2d9037cc231abdc0562b97498ce" 340 | 341 | [[package]] 342 | name = "bytes" 343 | version = "1.6.1" 344 | source = "registry+https://github.com/rust-lang/crates.io-index" 345 | checksum = "a12916984aab3fa6e39d655a33e09c0071eb36d6ab3aea5c2d78551f1df6d952" 346 | 347 | [[package]] 348 | name = "cc" 349 | version = "1.1.6" 350 | source = "registry+https://github.com/rust-lang/crates.io-index" 351 | checksum = "2aba8f4e9906c7ce3c73463f62a7f0c65183ada1a2d47e397cc8810827f9694f" 352 | 353 | [[package]] 354 | name = "cfg-if" 355 | version = "1.0.0" 356 | source = "registry+https://github.com/rust-lang/crates.io-index" 357 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 358 | 359 | [[package]] 360 | name = "chrono" 361 | version = "0.4.38" 362 | source = "registry+https://github.com/rust-lang/crates.io-index" 363 | checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" 364 | dependencies = [ 365 | "android-tzdata", 366 | "iana-time-zone", 367 | "js-sys", 368 | "num-traits", 369 | "wasm-bindgen", 370 | "windows-targets 0.52.6", 371 | ] 372 | 373 | [[package]] 374 | name = "clap" 375 | version = "4.5.9" 376 | source = "registry+https://github.com/rust-lang/crates.io-index" 377 | checksum = "64acc1846d54c1fe936a78dc189c34e28d3f5afc348403f28ecf53660b9b8462" 378 | dependencies = [ 379 | "clap_builder", 380 | "clap_derive", 381 | ] 382 | 383 | [[package]] 384 | name = "clap_builder" 385 | version = "4.5.9" 386 | source = "registry+https://github.com/rust-lang/crates.io-index" 387 | checksum = "6fb8393d67ba2e7bfaf28a23458e4e2b543cc73a99595511eb207fdb8aede942" 388 | dependencies = [ 389 | "anstream", 390 | "anstyle", 391 | "clap_lex", 392 | "strsim", 393 | ] 394 | 395 | [[package]] 396 | name = "clap_derive" 397 | version = "4.5.8" 398 | source = "registry+https://github.com/rust-lang/crates.io-index" 399 | checksum = "2bac35c6dafb060fd4d275d9a4ffae97917c13a6327903a8be2153cd964f7085" 400 | dependencies = [ 401 | "heck", 402 | "proc-macro2", 403 | "quote", 404 | "syn", 405 | ] 406 | 407 | [[package]] 408 | name = "clap_lex" 409 | version = "0.7.1" 410 | source = "registry+https://github.com/rust-lang/crates.io-index" 411 | checksum = "4b82cf0babdbd58558212896d1a4272303a57bdb245c2bf1147185fb45640e70" 412 | 413 | [[package]] 414 | name = "colorchoice" 415 | version = "1.0.1" 416 | source = "registry+https://github.com/rust-lang/crates.io-index" 417 | checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422" 418 | 419 | [[package]] 420 | name = "colored" 421 | version = "1.9.4" 422 | source = "registry+https://github.com/rust-lang/crates.io-index" 423 | checksum = "5a5f741c91823341bebf717d4c71bda820630ce065443b58bd1b7451af008355" 424 | dependencies = [ 425 | "is-terminal", 426 | "lazy_static", 427 | "winapi", 428 | ] 429 | 430 | [[package]] 431 | name = "console" 432 | version = "0.15.8" 433 | source = "registry+https://github.com/rust-lang/crates.io-index" 434 | checksum = "0e1f83fc076bd6dd27517eacdf25fef6c4dfe5f1d7448bafaaf3a26f13b5e4eb" 435 | dependencies = [ 436 | "encode_unicode", 437 | "lazy_static", 438 | "libc", 439 | "unicode-width", 440 | "windows-sys 0.52.0", 441 | ] 442 | 443 | [[package]] 444 | name = "core-foundation" 445 | version = "0.9.4" 446 | source = "registry+https://github.com/rust-lang/crates.io-index" 447 | checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" 448 | dependencies = [ 449 | "core-foundation-sys", 450 | "libc", 451 | ] 452 | 453 | [[package]] 454 | name = "core-foundation-sys" 455 | version = "0.8.6" 456 | source = "registry+https://github.com/rust-lang/crates.io-index" 457 | checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" 458 | 459 | [[package]] 460 | name = "cpufeatures" 461 | version = "0.2.12" 462 | source = "registry+https://github.com/rust-lang/crates.io-index" 463 | checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" 464 | dependencies = [ 465 | "libc", 466 | ] 467 | 468 | [[package]] 469 | name = "crc32fast" 470 | version = "1.4.2" 471 | source = "registry+https://github.com/rust-lang/crates.io-index" 472 | checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" 473 | dependencies = [ 474 | "cfg-if", 475 | ] 476 | 477 | [[package]] 478 | name = "crypto-common" 479 | version = "0.1.6" 480 | source = "registry+https://github.com/rust-lang/crates.io-index" 481 | checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" 482 | dependencies = [ 483 | "generic-array", 484 | "typenum", 485 | ] 486 | 487 | [[package]] 488 | name = "deranged" 489 | version = "0.3.11" 490 | source = "registry+https://github.com/rust-lang/crates.io-index" 491 | checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" 492 | dependencies = [ 493 | "powerfmt", 494 | ] 495 | 496 | [[package]] 497 | name = "deunicode" 498 | version = "1.6.0" 499 | source = "registry+https://github.com/rust-lang/crates.io-index" 500 | checksum = "339544cc9e2c4dc3fc7149fd630c5f22263a4fdf18a98afd0075784968b5cf00" 501 | 502 | [[package]] 503 | name = "digest" 504 | version = "0.10.7" 505 | source = "registry+https://github.com/rust-lang/crates.io-index" 506 | checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" 507 | dependencies = [ 508 | "block-buffer", 509 | "crypto-common", 510 | ] 511 | 512 | [[package]] 513 | name = "dotenvy" 514 | version = "0.15.7" 515 | source = "registry+https://github.com/rust-lang/crates.io-index" 516 | checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" 517 | 518 | [[package]] 519 | name = "dyn-clone" 520 | version = "1.0.17" 521 | source = "registry+https://github.com/rust-lang/crates.io-index" 522 | checksum = "0d6ef0072f8a535281e4876be788938b528e9a1d43900b82c2569af7da799125" 523 | 524 | [[package]] 525 | name = "either" 526 | version = "1.13.0" 527 | source = "registry+https://github.com/rust-lang/crates.io-index" 528 | checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" 529 | 530 | [[package]] 531 | name = "encode_unicode" 532 | version = "0.3.6" 533 | source = "registry+https://github.com/rust-lang/crates.io-index" 534 | checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" 535 | 536 | [[package]] 537 | name = "encoding_rs" 538 | version = "0.8.34" 539 | source = "registry+https://github.com/rust-lang/crates.io-index" 540 | checksum = "b45de904aa0b010bce2ab45264d0631681847fa7b6f2eaa7dab7619943bc4f59" 541 | dependencies = [ 542 | "cfg-if", 543 | ] 544 | 545 | [[package]] 546 | name = "equivalent" 547 | version = "1.0.1" 548 | source = "registry+https://github.com/rust-lang/crates.io-index" 549 | checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" 550 | 551 | [[package]] 552 | name = "errno" 553 | version = "0.3.9" 554 | source = "registry+https://github.com/rust-lang/crates.io-index" 555 | checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" 556 | dependencies = [ 557 | "libc", 558 | "windows-sys 0.52.0", 559 | ] 560 | 561 | [[package]] 562 | name = "eventsource-stream" 563 | version = "0.2.3" 564 | source = "registry+https://github.com/rust-lang/crates.io-index" 565 | checksum = "74fef4569247a5f429d9156b9d0a2599914385dd189c539334c625d8099d90ab" 566 | dependencies = [ 567 | "futures-core", 568 | "nom", 569 | "pin-project-lite", 570 | ] 571 | 572 | [[package]] 573 | name = "fancy-regex" 574 | version = "0.11.0" 575 | source = "registry+https://github.com/rust-lang/crates.io-index" 576 | checksum = "b95f7c0680e4142284cf8b22c14a476e87d61b004a3a0861872b32ef7ead40a2" 577 | dependencies = [ 578 | "bit-set", 579 | "regex", 580 | ] 581 | 582 | [[package]] 583 | name = "fastrand" 584 | version = "2.1.0" 585 | source = "registry+https://github.com/rust-lang/crates.io-index" 586 | checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" 587 | 588 | [[package]] 589 | name = "fern" 590 | version = "0.6.2" 591 | source = "registry+https://github.com/rust-lang/crates.io-index" 592 | checksum = "d9f0c14694cbd524c8720dd69b0e3179344f04ebb5f90f2e4a440c6ea3b2f1ee" 593 | dependencies = [ 594 | "colored", 595 | "log", 596 | ] 597 | 598 | [[package]] 599 | name = "filetime" 600 | version = "0.2.23" 601 | source = "registry+https://github.com/rust-lang/crates.io-index" 602 | checksum = "1ee447700ac8aa0b2f2bd7bc4462ad686ba06baa6727ac149a2d6277f0d240fd" 603 | dependencies = [ 604 | "cfg-if", 605 | "libc", 606 | "redox_syscall 0.4.1", 607 | "windows-sys 0.52.0", 608 | ] 609 | 610 | [[package]] 611 | name = "flate2" 612 | version = "1.0.30" 613 | source = "registry+https://github.com/rust-lang/crates.io-index" 614 | checksum = "5f54427cfd1c7829e2a139fcefea601bf088ebca651d2bf53ebc600eac295dae" 615 | dependencies = [ 616 | "crc32fast", 617 | "miniz_oxide", 618 | ] 619 | 620 | [[package]] 621 | name = "fnv" 622 | version = "1.0.7" 623 | source = "registry+https://github.com/rust-lang/crates.io-index" 624 | checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" 625 | 626 | [[package]] 627 | name = "foreign-types" 628 | version = "0.3.2" 629 | source = "registry+https://github.com/rust-lang/crates.io-index" 630 | checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" 631 | dependencies = [ 632 | "foreign-types-shared", 633 | ] 634 | 635 | [[package]] 636 | name = "foreign-types-shared" 637 | version = "0.1.1" 638 | source = "registry+https://github.com/rust-lang/crates.io-index" 639 | checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" 640 | 641 | [[package]] 642 | name = "form_urlencoded" 643 | version = "1.2.1" 644 | source = "registry+https://github.com/rust-lang/crates.io-index" 645 | checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" 646 | dependencies = [ 647 | "percent-encoding", 648 | ] 649 | 650 | [[package]] 651 | name = "fraction" 652 | version = "0.13.1" 653 | source = "registry+https://github.com/rust-lang/crates.io-index" 654 | checksum = "3027ae1df8d41b4bed2241c8fdad4acc1e7af60c8e17743534b545e77182d678" 655 | dependencies = [ 656 | "lazy_static", 657 | "num", 658 | ] 659 | 660 | [[package]] 661 | name = "futures" 662 | version = "0.3.30" 663 | source = "registry+https://github.com/rust-lang/crates.io-index" 664 | checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" 665 | dependencies = [ 666 | "futures-channel", 667 | "futures-core", 668 | "futures-executor", 669 | "futures-io", 670 | "futures-sink", 671 | "futures-task", 672 | "futures-util", 673 | ] 674 | 675 | [[package]] 676 | name = "futures-channel" 677 | version = "0.3.30" 678 | source = "registry+https://github.com/rust-lang/crates.io-index" 679 | checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" 680 | dependencies = [ 681 | "futures-core", 682 | "futures-sink", 683 | ] 684 | 685 | [[package]] 686 | name = "futures-core" 687 | version = "0.3.30" 688 | source = "registry+https://github.com/rust-lang/crates.io-index" 689 | checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" 690 | 691 | [[package]] 692 | name = "futures-executor" 693 | version = "0.3.30" 694 | source = "registry+https://github.com/rust-lang/crates.io-index" 695 | checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" 696 | dependencies = [ 697 | "futures-core", 698 | "futures-task", 699 | "futures-util", 700 | ] 701 | 702 | [[package]] 703 | name = "futures-io" 704 | version = "0.3.30" 705 | source = "registry+https://github.com/rust-lang/crates.io-index" 706 | checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" 707 | 708 | [[package]] 709 | name = "futures-macro" 710 | version = "0.3.30" 711 | source = "registry+https://github.com/rust-lang/crates.io-index" 712 | checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" 713 | dependencies = [ 714 | "proc-macro2", 715 | "quote", 716 | "syn", 717 | ] 718 | 719 | [[package]] 720 | name = "futures-sink" 721 | version = "0.3.30" 722 | source = "registry+https://github.com/rust-lang/crates.io-index" 723 | checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" 724 | 725 | [[package]] 726 | name = "futures-task" 727 | version = "0.3.30" 728 | source = "registry+https://github.com/rust-lang/crates.io-index" 729 | checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" 730 | 731 | [[package]] 732 | name = "futures-timer" 733 | version = "3.0.3" 734 | source = "registry+https://github.com/rust-lang/crates.io-index" 735 | checksum = "f288b0a4f20f9a56b5d1da57e2227c661b7b16168e2f72365f57b63326e29b24" 736 | 737 | [[package]] 738 | name = "futures-util" 739 | version = "0.3.30" 740 | source = "registry+https://github.com/rust-lang/crates.io-index" 741 | checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" 742 | dependencies = [ 743 | "futures-channel", 744 | "futures-core", 745 | "futures-io", 746 | "futures-macro", 747 | "futures-sink", 748 | "futures-task", 749 | "memchr", 750 | "pin-project-lite", 751 | "pin-utils", 752 | "slab", 753 | ] 754 | 755 | [[package]] 756 | name = "generic-array" 757 | version = "0.14.7" 758 | source = "registry+https://github.com/rust-lang/crates.io-index" 759 | checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" 760 | dependencies = [ 761 | "typenum", 762 | "version_check", 763 | ] 764 | 765 | [[package]] 766 | name = "getrandom" 767 | version = "0.2.15" 768 | source = "registry+https://github.com/rust-lang/crates.io-index" 769 | checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" 770 | dependencies = [ 771 | "cfg-if", 772 | "js-sys", 773 | "libc", 774 | "wasi", 775 | "wasm-bindgen", 776 | ] 777 | 778 | [[package]] 779 | name = "gimli" 780 | version = "0.29.0" 781 | source = "registry+https://github.com/rust-lang/crates.io-index" 782 | checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" 783 | 784 | [[package]] 785 | name = "h2" 786 | version = "0.4.5" 787 | source = "registry+https://github.com/rust-lang/crates.io-index" 788 | checksum = "fa82e28a107a8cc405f0839610bdc9b15f1e25ec7d696aa5cf173edbcb1486ab" 789 | dependencies = [ 790 | "atomic-waker", 791 | "bytes", 792 | "fnv", 793 | "futures-core", 794 | "futures-sink", 795 | "http", 796 | "indexmap", 797 | "slab", 798 | "tokio", 799 | "tokio-util", 800 | "tracing", 801 | ] 802 | 803 | [[package]] 804 | name = "hashbrown" 805 | version = "0.14.5" 806 | source = "registry+https://github.com/rust-lang/crates.io-index" 807 | checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" 808 | 809 | [[package]] 810 | name = "headers" 811 | version = "0.4.0" 812 | source = "registry+https://github.com/rust-lang/crates.io-index" 813 | checksum = "322106e6bd0cba2d5ead589ddb8150a13d7c4217cf80d7c4f682ca994ccc6aa9" 814 | dependencies = [ 815 | "base64 0.21.7", 816 | "bytes", 817 | "headers-core", 818 | "http", 819 | "httpdate", 820 | "mime", 821 | "sha1", 822 | ] 823 | 824 | [[package]] 825 | name = "headers-core" 826 | version = "0.3.0" 827 | source = "registry+https://github.com/rust-lang/crates.io-index" 828 | checksum = "54b4a22553d4242c49fddb9ba998a99962b5cc6f22cb5a3482bec22522403ce4" 829 | dependencies = [ 830 | "http", 831 | ] 832 | 833 | [[package]] 834 | name = "heck" 835 | version = "0.5.0" 836 | source = "registry+https://github.com/rust-lang/crates.io-index" 837 | checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" 838 | 839 | [[package]] 840 | name = "hermit-abi" 841 | version = "0.3.9" 842 | source = "registry+https://github.com/rust-lang/crates.io-index" 843 | checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" 844 | 845 | [[package]] 846 | name = "http" 847 | version = "1.1.0" 848 | source = "registry+https://github.com/rust-lang/crates.io-index" 849 | checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258" 850 | dependencies = [ 851 | "bytes", 852 | "fnv", 853 | "itoa", 854 | ] 855 | 856 | [[package]] 857 | name = "http-body" 858 | version = "1.0.1" 859 | source = "registry+https://github.com/rust-lang/crates.io-index" 860 | checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" 861 | dependencies = [ 862 | "bytes", 863 | "http", 864 | ] 865 | 866 | [[package]] 867 | name = "http-body-util" 868 | version = "0.1.2" 869 | source = "registry+https://github.com/rust-lang/crates.io-index" 870 | checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f" 871 | dependencies = [ 872 | "bytes", 873 | "futures-util", 874 | "http", 875 | "http-body", 876 | "pin-project-lite", 877 | ] 878 | 879 | [[package]] 880 | name = "httparse" 881 | version = "1.9.4" 882 | source = "registry+https://github.com/rust-lang/crates.io-index" 883 | checksum = "0fcc0b4a115bf80b728eb8ea024ad5bd707b615bfed49e0665b6e0f86fd082d9" 884 | 885 | [[package]] 886 | name = "httpdate" 887 | version = "1.0.3" 888 | source = "registry+https://github.com/rust-lang/crates.io-index" 889 | checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" 890 | 891 | [[package]] 892 | name = "hyper" 893 | version = "1.4.1" 894 | source = "registry+https://github.com/rust-lang/crates.io-index" 895 | checksum = "50dfd22e0e76d0f662d429a5f80fcaf3855009297eab6a0a9f8543834744ba05" 896 | dependencies = [ 897 | "bytes", 898 | "futures-channel", 899 | "futures-util", 900 | "h2", 901 | "http", 902 | "http-body", 903 | "httparse", 904 | "httpdate", 905 | "itoa", 906 | "pin-project-lite", 907 | "smallvec", 908 | "tokio", 909 | "want", 910 | ] 911 | 912 | [[package]] 913 | name = "hyper-rustls" 914 | version = "0.27.2" 915 | source = "registry+https://github.com/rust-lang/crates.io-index" 916 | checksum = "5ee4be2c948921a1a5320b629c4193916ed787a7f7f293fd3f7f5a6c9de74155" 917 | dependencies = [ 918 | "futures-util", 919 | "http", 920 | "hyper", 921 | "hyper-util", 922 | "rustls", 923 | "rustls-pki-types", 924 | "tokio", 925 | "tokio-rustls", 926 | "tower-service", 927 | ] 928 | 929 | [[package]] 930 | name = "hyper-tls" 931 | version = "0.6.0" 932 | source = "registry+https://github.com/rust-lang/crates.io-index" 933 | checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" 934 | dependencies = [ 935 | "bytes", 936 | "http-body-util", 937 | "hyper", 938 | "hyper-util", 939 | "native-tls", 940 | "tokio", 941 | "tokio-native-tls", 942 | "tower-service", 943 | ] 944 | 945 | [[package]] 946 | name = "hyper-util" 947 | version = "0.1.6" 948 | source = "registry+https://github.com/rust-lang/crates.io-index" 949 | checksum = "3ab92f4f49ee4fb4f997c784b7a2e0fa70050211e0b6a287f898c3c9785ca956" 950 | dependencies = [ 951 | "bytes", 952 | "futures-channel", 953 | "futures-util", 954 | "http", 955 | "http-body", 956 | "hyper", 957 | "pin-project-lite", 958 | "socket2 0.5.7", 959 | "tokio", 960 | "tower", 961 | "tower-service", 962 | "tracing", 963 | ] 964 | 965 | [[package]] 966 | name = "iana-time-zone" 967 | version = "0.1.60" 968 | source = "registry+https://github.com/rust-lang/crates.io-index" 969 | checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" 970 | dependencies = [ 971 | "android_system_properties", 972 | "core-foundation-sys", 973 | "iana-time-zone-haiku", 974 | "js-sys", 975 | "wasm-bindgen", 976 | "windows-core", 977 | ] 978 | 979 | [[package]] 980 | name = "iana-time-zone-haiku" 981 | version = "0.1.2" 982 | source = "registry+https://github.com/rust-lang/crates.io-index" 983 | checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" 984 | dependencies = [ 985 | "cc", 986 | ] 987 | 988 | [[package]] 989 | name = "idna" 990 | version = "0.5.0" 991 | source = "registry+https://github.com/rust-lang/crates.io-index" 992 | checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" 993 | dependencies = [ 994 | "unicode-bidi", 995 | "unicode-normalization", 996 | ] 997 | 998 | [[package]] 999 | name = "indexmap" 1000 | version = "2.2.6" 1001 | source = "registry+https://github.com/rust-lang/crates.io-index" 1002 | checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" 1003 | dependencies = [ 1004 | "equivalent", 1005 | "hashbrown", 1006 | "serde", 1007 | ] 1008 | 1009 | [[package]] 1010 | name = "ipnet" 1011 | version = "2.9.0" 1012 | source = "registry+https://github.com/rust-lang/crates.io-index" 1013 | checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" 1014 | 1015 | [[package]] 1016 | name = "is-terminal" 1017 | version = "0.4.12" 1018 | source = "registry+https://github.com/rust-lang/crates.io-index" 1019 | checksum = "f23ff5ef2b80d608d61efee834934d862cd92461afc0560dedf493e4c033738b" 1020 | dependencies = [ 1021 | "hermit-abi", 1022 | "libc", 1023 | "windows-sys 0.52.0", 1024 | ] 1025 | 1026 | [[package]] 1027 | name = "is_terminal_polyfill" 1028 | version = "1.70.0" 1029 | source = "registry+https://github.com/rust-lang/crates.io-index" 1030 | checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800" 1031 | 1032 | [[package]] 1033 | name = "iso8601" 1034 | version = "0.6.1" 1035 | source = "registry+https://github.com/rust-lang/crates.io-index" 1036 | checksum = "924e5d73ea28f59011fec52a0d12185d496a9b075d360657aed2a5707f701153" 1037 | dependencies = [ 1038 | "nom", 1039 | ] 1040 | 1041 | [[package]] 1042 | name = "itertools" 1043 | version = "0.12.1" 1044 | source = "registry+https://github.com/rust-lang/crates.io-index" 1045 | checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" 1046 | dependencies = [ 1047 | "either", 1048 | ] 1049 | 1050 | [[package]] 1051 | name = "itoa" 1052 | version = "1.0.11" 1053 | source = "registry+https://github.com/rust-lang/crates.io-index" 1054 | checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" 1055 | 1056 | [[package]] 1057 | name = "js-sys" 1058 | version = "0.3.69" 1059 | source = "registry+https://github.com/rust-lang/crates.io-index" 1060 | checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" 1061 | dependencies = [ 1062 | "wasm-bindgen", 1063 | ] 1064 | 1065 | [[package]] 1066 | name = "jsonschema" 1067 | version = "0.17.1" 1068 | source = "registry+https://github.com/rust-lang/crates.io-index" 1069 | checksum = "2a071f4f7efc9a9118dfb627a0a94ef247986e1ab8606a4c806ae2b3aa3b6978" 1070 | dependencies = [ 1071 | "ahash", 1072 | "anyhow", 1073 | "base64 0.21.7", 1074 | "bytecount", 1075 | "fancy-regex", 1076 | "fraction", 1077 | "getrandom", 1078 | "iso8601", 1079 | "itoa", 1080 | "memchr", 1081 | "num-cmp", 1082 | "once_cell", 1083 | "parking_lot", 1084 | "percent-encoding", 1085 | "regex", 1086 | "serde", 1087 | "serde_json", 1088 | "time", 1089 | "url", 1090 | "uuid", 1091 | ] 1092 | 1093 | [[package]] 1094 | name = "lazy_static" 1095 | version = "1.5.0" 1096 | source = "registry+https://github.com/rust-lang/crates.io-index" 1097 | checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" 1098 | 1099 | [[package]] 1100 | name = "libc" 1101 | version = "0.2.155" 1102 | source = "registry+https://github.com/rust-lang/crates.io-index" 1103 | checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" 1104 | 1105 | [[package]] 1106 | name = "linux-raw-sys" 1107 | version = "0.4.14" 1108 | source = "registry+https://github.com/rust-lang/crates.io-index" 1109 | checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" 1110 | 1111 | [[package]] 1112 | name = "lock_api" 1113 | version = "0.4.12" 1114 | source = "registry+https://github.com/rust-lang/crates.io-index" 1115 | checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" 1116 | dependencies = [ 1117 | "autocfg", 1118 | "scopeguard", 1119 | ] 1120 | 1121 | [[package]] 1122 | name = "log" 1123 | version = "0.4.22" 1124 | source = "registry+https://github.com/rust-lang/crates.io-index" 1125 | checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" 1126 | 1127 | [[package]] 1128 | name = "matchers" 1129 | version = "0.1.0" 1130 | source = "registry+https://github.com/rust-lang/crates.io-index" 1131 | checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" 1132 | dependencies = [ 1133 | "regex-automata 0.1.10", 1134 | ] 1135 | 1136 | [[package]] 1137 | name = "matchit" 1138 | version = "0.7.3" 1139 | source = "registry+https://github.com/rust-lang/crates.io-index" 1140 | checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94" 1141 | 1142 | [[package]] 1143 | name = "memchr" 1144 | version = "2.7.4" 1145 | source = "registry+https://github.com/rust-lang/crates.io-index" 1146 | checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" 1147 | 1148 | [[package]] 1149 | name = "mime" 1150 | version = "0.3.17" 1151 | source = "registry+https://github.com/rust-lang/crates.io-index" 1152 | checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" 1153 | 1154 | [[package]] 1155 | name = "minimal-lexical" 1156 | version = "0.2.1" 1157 | source = "registry+https://github.com/rust-lang/crates.io-index" 1158 | checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" 1159 | 1160 | [[package]] 1161 | name = "miniz_oxide" 1162 | version = "0.7.4" 1163 | source = "registry+https://github.com/rust-lang/crates.io-index" 1164 | checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" 1165 | dependencies = [ 1166 | "adler", 1167 | ] 1168 | 1169 | [[package]] 1170 | name = "mio" 1171 | version = "0.8.11" 1172 | source = "registry+https://github.com/rust-lang/crates.io-index" 1173 | checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" 1174 | dependencies = [ 1175 | "libc", 1176 | "wasi", 1177 | "windows-sys 0.48.0", 1178 | ] 1179 | 1180 | [[package]] 1181 | name = "native-tls" 1182 | version = "0.2.12" 1183 | source = "registry+https://github.com/rust-lang/crates.io-index" 1184 | checksum = "a8614eb2c83d59d1c8cc974dd3f920198647674a0a035e1af1fa58707e317466" 1185 | dependencies = [ 1186 | "libc", 1187 | "log", 1188 | "openssl", 1189 | "openssl-probe", 1190 | "openssl-sys", 1191 | "schannel", 1192 | "security-framework", 1193 | "security-framework-sys", 1194 | "tempfile", 1195 | ] 1196 | 1197 | [[package]] 1198 | name = "nom" 1199 | version = "7.1.3" 1200 | source = "registry+https://github.com/rust-lang/crates.io-index" 1201 | checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" 1202 | dependencies = [ 1203 | "memchr", 1204 | "minimal-lexical", 1205 | ] 1206 | 1207 | [[package]] 1208 | name = "nu-ansi-term" 1209 | version = "0.46.0" 1210 | source = "registry+https://github.com/rust-lang/crates.io-index" 1211 | checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" 1212 | dependencies = [ 1213 | "overload", 1214 | "winapi", 1215 | ] 1216 | 1217 | [[package]] 1218 | name = "num" 1219 | version = "0.4.3" 1220 | source = "registry+https://github.com/rust-lang/crates.io-index" 1221 | checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23" 1222 | dependencies = [ 1223 | "num-bigint", 1224 | "num-complex", 1225 | "num-integer", 1226 | "num-iter", 1227 | "num-rational", 1228 | "num-traits", 1229 | ] 1230 | 1231 | [[package]] 1232 | name = "num-bigint" 1233 | version = "0.4.6" 1234 | source = "registry+https://github.com/rust-lang/crates.io-index" 1235 | checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" 1236 | dependencies = [ 1237 | "num-integer", 1238 | "num-traits", 1239 | ] 1240 | 1241 | [[package]] 1242 | name = "num-cmp" 1243 | version = "0.1.0" 1244 | source = "registry+https://github.com/rust-lang/crates.io-index" 1245 | checksum = "63335b2e2c34fae2fb0aa2cecfd9f0832a1e24b3b32ecec612c3426d46dc8aaa" 1246 | 1247 | [[package]] 1248 | name = "num-complex" 1249 | version = "0.4.6" 1250 | source = "registry+https://github.com/rust-lang/crates.io-index" 1251 | checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" 1252 | dependencies = [ 1253 | "num-traits", 1254 | ] 1255 | 1256 | [[package]] 1257 | name = "num-conv" 1258 | version = "0.1.0" 1259 | source = "registry+https://github.com/rust-lang/crates.io-index" 1260 | checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" 1261 | 1262 | [[package]] 1263 | name = "num-integer" 1264 | version = "0.1.46" 1265 | source = "registry+https://github.com/rust-lang/crates.io-index" 1266 | checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" 1267 | dependencies = [ 1268 | "num-traits", 1269 | ] 1270 | 1271 | [[package]] 1272 | name = "num-iter" 1273 | version = "0.1.45" 1274 | source = "registry+https://github.com/rust-lang/crates.io-index" 1275 | checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" 1276 | dependencies = [ 1277 | "autocfg", 1278 | "num-integer", 1279 | "num-traits", 1280 | ] 1281 | 1282 | [[package]] 1283 | name = "num-rational" 1284 | version = "0.4.2" 1285 | source = "registry+https://github.com/rust-lang/crates.io-index" 1286 | checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" 1287 | dependencies = [ 1288 | "num-bigint", 1289 | "num-integer", 1290 | "num-traits", 1291 | ] 1292 | 1293 | [[package]] 1294 | name = "num-traits" 1295 | version = "0.2.19" 1296 | source = "registry+https://github.com/rust-lang/crates.io-index" 1297 | checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" 1298 | dependencies = [ 1299 | "autocfg", 1300 | ] 1301 | 1302 | [[package]] 1303 | name = "num_cpus" 1304 | version = "1.16.0" 1305 | source = "registry+https://github.com/rust-lang/crates.io-index" 1306 | checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" 1307 | dependencies = [ 1308 | "hermit-abi", 1309 | "libc", 1310 | ] 1311 | 1312 | [[package]] 1313 | name = "object" 1314 | version = "0.36.1" 1315 | source = "registry+https://github.com/rust-lang/crates.io-index" 1316 | checksum = "081b846d1d56ddfc18fdf1a922e4f6e07a11768ea1b92dec44e42b72712ccfce" 1317 | dependencies = [ 1318 | "memchr", 1319 | ] 1320 | 1321 | [[package]] 1322 | name = "once_cell" 1323 | version = "1.19.0" 1324 | source = "registry+https://github.com/rust-lang/crates.io-index" 1325 | checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" 1326 | 1327 | [[package]] 1328 | name = "openssl" 1329 | version = "0.10.65" 1330 | source = "registry+https://github.com/rust-lang/crates.io-index" 1331 | checksum = "c2823eb4c6453ed64055057ea8bd416eda38c71018723869dd043a3b1186115e" 1332 | dependencies = [ 1333 | "bitflags 2.6.0", 1334 | "cfg-if", 1335 | "foreign-types", 1336 | "libc", 1337 | "once_cell", 1338 | "openssl-macros", 1339 | "openssl-sys", 1340 | ] 1341 | 1342 | [[package]] 1343 | name = "openssl-macros" 1344 | version = "0.1.1" 1345 | source = "registry+https://github.com/rust-lang/crates.io-index" 1346 | checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" 1347 | dependencies = [ 1348 | "proc-macro2", 1349 | "quote", 1350 | "syn", 1351 | ] 1352 | 1353 | [[package]] 1354 | name = "openssl-probe" 1355 | version = "0.1.5" 1356 | source = "registry+https://github.com/rust-lang/crates.io-index" 1357 | checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" 1358 | 1359 | [[package]] 1360 | name = "openssl-sys" 1361 | version = "0.9.103" 1362 | source = "registry+https://github.com/rust-lang/crates.io-index" 1363 | checksum = "7f9e8deee91df40a943c71b917e5874b951d32a802526c85721ce3b776c929d6" 1364 | dependencies = [ 1365 | "cc", 1366 | "libc", 1367 | "pkg-config", 1368 | "vcpkg", 1369 | ] 1370 | 1371 | [[package]] 1372 | name = "orbit-cli" 1373 | version = "0.1.0" 1374 | dependencies = [ 1375 | "anyhow", 1376 | "clap", 1377 | "console", 1378 | "fern", 1379 | "futures-util", 1380 | "log", 1381 | "orbit-client", 1382 | "orbit-types", 1383 | "pin-utils", 1384 | "tokio", 1385 | "url", 1386 | ] 1387 | 1388 | [[package]] 1389 | name = "orbit-client" 1390 | version = "0.1.0" 1391 | dependencies = [ 1392 | "async-fn-stream", 1393 | "futures", 1394 | "orbit-types", 1395 | "reqwest", 1396 | "reqwest-eventsource", 1397 | "serde_json", 1398 | "thiserror", 1399 | "url", 1400 | ] 1401 | 1402 | [[package]] 1403 | name = "orbit-server" 1404 | version = "0.1.0" 1405 | dependencies = [ 1406 | "aide", 1407 | "anyhow", 1408 | "async-fn-stream", 1409 | "axum", 1410 | "axum-extra", 1411 | "axum-jsonschema", 1412 | "chrono", 1413 | "dotenvy", 1414 | "flate2", 1415 | "futures-util", 1416 | "http", 1417 | "indexmap", 1418 | "orbit-types", 1419 | "reqwest", 1420 | "schemars", 1421 | "serde", 1422 | "serde_json", 1423 | "shlex", 1424 | "slug", 1425 | "symlink", 1426 | "tar", 1427 | "thiserror", 1428 | "tokio", 1429 | "toml", 1430 | "tracing", 1431 | "tracing-subscriber", 1432 | "uuid", 1433 | ] 1434 | 1435 | [[package]] 1436 | name = "orbit-types" 1437 | version = "0.1.0" 1438 | dependencies = [ 1439 | "serde", 1440 | "thiserror", 1441 | ] 1442 | 1443 | [[package]] 1444 | name = "overload" 1445 | version = "0.1.1" 1446 | source = "registry+https://github.com/rust-lang/crates.io-index" 1447 | checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" 1448 | 1449 | [[package]] 1450 | name = "parking_lot" 1451 | version = "0.12.3" 1452 | source = "registry+https://github.com/rust-lang/crates.io-index" 1453 | checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" 1454 | dependencies = [ 1455 | "lock_api", 1456 | "parking_lot_core", 1457 | ] 1458 | 1459 | [[package]] 1460 | name = "parking_lot_core" 1461 | version = "0.9.10" 1462 | source = "registry+https://github.com/rust-lang/crates.io-index" 1463 | checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" 1464 | dependencies = [ 1465 | "cfg-if", 1466 | "libc", 1467 | "redox_syscall 0.5.3", 1468 | "smallvec", 1469 | "windows-targets 0.52.6", 1470 | ] 1471 | 1472 | [[package]] 1473 | name = "percent-encoding" 1474 | version = "2.3.1" 1475 | source = "registry+https://github.com/rust-lang/crates.io-index" 1476 | checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" 1477 | 1478 | [[package]] 1479 | name = "pin-project" 1480 | version = "1.1.5" 1481 | source = "registry+https://github.com/rust-lang/crates.io-index" 1482 | checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3" 1483 | dependencies = [ 1484 | "pin-project-internal", 1485 | ] 1486 | 1487 | [[package]] 1488 | name = "pin-project-internal" 1489 | version = "1.1.5" 1490 | source = "registry+https://github.com/rust-lang/crates.io-index" 1491 | checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" 1492 | dependencies = [ 1493 | "proc-macro2", 1494 | "quote", 1495 | "syn", 1496 | ] 1497 | 1498 | [[package]] 1499 | name = "pin-project-lite" 1500 | version = "0.2.14" 1501 | source = "registry+https://github.com/rust-lang/crates.io-index" 1502 | checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" 1503 | 1504 | [[package]] 1505 | name = "pin-utils" 1506 | version = "0.1.0" 1507 | source = "registry+https://github.com/rust-lang/crates.io-index" 1508 | checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" 1509 | 1510 | [[package]] 1511 | name = "pkg-config" 1512 | version = "0.3.30" 1513 | source = "registry+https://github.com/rust-lang/crates.io-index" 1514 | checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" 1515 | 1516 | [[package]] 1517 | name = "powerfmt" 1518 | version = "0.2.0" 1519 | source = "registry+https://github.com/rust-lang/crates.io-index" 1520 | checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" 1521 | 1522 | [[package]] 1523 | name = "proc-macro2" 1524 | version = "1.0.86" 1525 | source = "registry+https://github.com/rust-lang/crates.io-index" 1526 | checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" 1527 | dependencies = [ 1528 | "unicode-ident", 1529 | ] 1530 | 1531 | [[package]] 1532 | name = "quote" 1533 | version = "1.0.36" 1534 | source = "registry+https://github.com/rust-lang/crates.io-index" 1535 | checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" 1536 | dependencies = [ 1537 | "proc-macro2", 1538 | ] 1539 | 1540 | [[package]] 1541 | name = "redox_syscall" 1542 | version = "0.4.1" 1543 | source = "registry+https://github.com/rust-lang/crates.io-index" 1544 | checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" 1545 | dependencies = [ 1546 | "bitflags 1.3.2", 1547 | ] 1548 | 1549 | [[package]] 1550 | name = "redox_syscall" 1551 | version = "0.5.3" 1552 | source = "registry+https://github.com/rust-lang/crates.io-index" 1553 | checksum = "2a908a6e00f1fdd0dfd9c0eb08ce85126f6d8bbda50017e74bc4a4b7d4a926a4" 1554 | dependencies = [ 1555 | "bitflags 2.6.0", 1556 | ] 1557 | 1558 | [[package]] 1559 | name = "regex" 1560 | version = "1.10.5" 1561 | source = "registry+https://github.com/rust-lang/crates.io-index" 1562 | checksum = "b91213439dad192326a0d7c6ee3955910425f441d7038e0d6933b0aec5c4517f" 1563 | dependencies = [ 1564 | "aho-corasick", 1565 | "memchr", 1566 | "regex-automata 0.4.7", 1567 | "regex-syntax 0.8.4", 1568 | ] 1569 | 1570 | [[package]] 1571 | name = "regex-automata" 1572 | version = "0.1.10" 1573 | source = "registry+https://github.com/rust-lang/crates.io-index" 1574 | checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" 1575 | dependencies = [ 1576 | "regex-syntax 0.6.29", 1577 | ] 1578 | 1579 | [[package]] 1580 | name = "regex-automata" 1581 | version = "0.4.7" 1582 | source = "registry+https://github.com/rust-lang/crates.io-index" 1583 | checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" 1584 | dependencies = [ 1585 | "aho-corasick", 1586 | "memchr", 1587 | "regex-syntax 0.8.4", 1588 | ] 1589 | 1590 | [[package]] 1591 | name = "regex-syntax" 1592 | version = "0.6.29" 1593 | source = "registry+https://github.com/rust-lang/crates.io-index" 1594 | checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" 1595 | 1596 | [[package]] 1597 | name = "regex-syntax" 1598 | version = "0.8.4" 1599 | source = "registry+https://github.com/rust-lang/crates.io-index" 1600 | checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" 1601 | 1602 | [[package]] 1603 | name = "reqwest" 1604 | version = "0.12.5" 1605 | source = "registry+https://github.com/rust-lang/crates.io-index" 1606 | checksum = "c7d6d2a27d57148378eb5e111173f4276ad26340ecc5c49a4a2152167a2d6a37" 1607 | dependencies = [ 1608 | "base64 0.22.1", 1609 | "bytes", 1610 | "encoding_rs", 1611 | "futures-core", 1612 | "futures-util", 1613 | "h2", 1614 | "http", 1615 | "http-body", 1616 | "http-body-util", 1617 | "hyper", 1618 | "hyper-rustls", 1619 | "hyper-tls", 1620 | "hyper-util", 1621 | "ipnet", 1622 | "js-sys", 1623 | "log", 1624 | "mime", 1625 | "native-tls", 1626 | "once_cell", 1627 | "percent-encoding", 1628 | "pin-project-lite", 1629 | "rustls-pemfile", 1630 | "serde", 1631 | "serde_json", 1632 | "serde_urlencoded", 1633 | "sync_wrapper 1.0.1", 1634 | "system-configuration", 1635 | "tokio", 1636 | "tokio-native-tls", 1637 | "tokio-util", 1638 | "tower-service", 1639 | "url", 1640 | "wasm-bindgen", 1641 | "wasm-bindgen-futures", 1642 | "wasm-streams", 1643 | "web-sys", 1644 | "winreg", 1645 | ] 1646 | 1647 | [[package]] 1648 | name = "reqwest-eventsource" 1649 | version = "0.6.0" 1650 | source = "registry+https://github.com/rust-lang/crates.io-index" 1651 | checksum = "632c55746dbb44275691640e7b40c907c16a2dc1a5842aa98aaec90da6ec6bde" 1652 | dependencies = [ 1653 | "eventsource-stream", 1654 | "futures-core", 1655 | "futures-timer", 1656 | "mime", 1657 | "nom", 1658 | "pin-project-lite", 1659 | "reqwest", 1660 | "thiserror", 1661 | ] 1662 | 1663 | [[package]] 1664 | name = "ring" 1665 | version = "0.17.8" 1666 | source = "registry+https://github.com/rust-lang/crates.io-index" 1667 | checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" 1668 | dependencies = [ 1669 | "cc", 1670 | "cfg-if", 1671 | "getrandom", 1672 | "libc", 1673 | "spin", 1674 | "untrusted", 1675 | "windows-sys 0.52.0", 1676 | ] 1677 | 1678 | [[package]] 1679 | name = "rustc-demangle" 1680 | version = "0.1.24" 1681 | source = "registry+https://github.com/rust-lang/crates.io-index" 1682 | checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" 1683 | 1684 | [[package]] 1685 | name = "rustix" 1686 | version = "0.38.34" 1687 | source = "registry+https://github.com/rust-lang/crates.io-index" 1688 | checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" 1689 | dependencies = [ 1690 | "bitflags 2.6.0", 1691 | "errno", 1692 | "libc", 1693 | "linux-raw-sys", 1694 | "windows-sys 0.52.0", 1695 | ] 1696 | 1697 | [[package]] 1698 | name = "rustls" 1699 | version = "0.23.11" 1700 | source = "registry+https://github.com/rust-lang/crates.io-index" 1701 | checksum = "4828ea528154ae444e5a642dbb7d5623354030dc9822b83fd9bb79683c7399d0" 1702 | dependencies = [ 1703 | "once_cell", 1704 | "rustls-pki-types", 1705 | "rustls-webpki", 1706 | "subtle", 1707 | "zeroize", 1708 | ] 1709 | 1710 | [[package]] 1711 | name = "rustls-pemfile" 1712 | version = "2.1.2" 1713 | source = "registry+https://github.com/rust-lang/crates.io-index" 1714 | checksum = "29993a25686778eb88d4189742cd713c9bce943bc54251a33509dc63cbacf73d" 1715 | dependencies = [ 1716 | "base64 0.22.1", 1717 | "rustls-pki-types", 1718 | ] 1719 | 1720 | [[package]] 1721 | name = "rustls-pki-types" 1722 | version = "1.7.0" 1723 | source = "registry+https://github.com/rust-lang/crates.io-index" 1724 | checksum = "976295e77ce332211c0d24d92c0e83e50f5c5f046d11082cea19f3df13a3562d" 1725 | 1726 | [[package]] 1727 | name = "rustls-webpki" 1728 | version = "0.102.5" 1729 | source = "registry+https://github.com/rust-lang/crates.io-index" 1730 | checksum = "f9a6fccd794a42c2c105b513a2f62bc3fd8f3ba57a4593677ceb0bd035164d78" 1731 | dependencies = [ 1732 | "ring", 1733 | "rustls-pki-types", 1734 | "untrusted", 1735 | ] 1736 | 1737 | [[package]] 1738 | name = "rustversion" 1739 | version = "1.0.17" 1740 | source = "registry+https://github.com/rust-lang/crates.io-index" 1741 | checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" 1742 | 1743 | [[package]] 1744 | name = "ryu" 1745 | version = "1.0.18" 1746 | source = "registry+https://github.com/rust-lang/crates.io-index" 1747 | checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" 1748 | 1749 | [[package]] 1750 | name = "schannel" 1751 | version = "0.1.23" 1752 | source = "registry+https://github.com/rust-lang/crates.io-index" 1753 | checksum = "fbc91545643bcf3a0bbb6569265615222618bdf33ce4ffbbd13c4bbd4c093534" 1754 | dependencies = [ 1755 | "windows-sys 0.52.0", 1756 | ] 1757 | 1758 | [[package]] 1759 | name = "schemars" 1760 | version = "0.8.21" 1761 | source = "registry+https://github.com/rust-lang/crates.io-index" 1762 | checksum = "09c024468a378b7e36765cd36702b7a90cc3cba11654f6685c8f233408e89e92" 1763 | dependencies = [ 1764 | "dyn-clone", 1765 | "indexmap", 1766 | "schemars_derive", 1767 | "serde", 1768 | "serde_json", 1769 | ] 1770 | 1771 | [[package]] 1772 | name = "schemars_derive" 1773 | version = "0.8.21" 1774 | source = "registry+https://github.com/rust-lang/crates.io-index" 1775 | checksum = "b1eee588578aff73f856ab961cd2f79e36bc45d7ded33a7562adba4667aecc0e" 1776 | dependencies = [ 1777 | "proc-macro2", 1778 | "quote", 1779 | "serde_derive_internals", 1780 | "syn", 1781 | ] 1782 | 1783 | [[package]] 1784 | name = "scopeguard" 1785 | version = "1.2.0" 1786 | source = "registry+https://github.com/rust-lang/crates.io-index" 1787 | checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" 1788 | 1789 | [[package]] 1790 | name = "security-framework" 1791 | version = "2.11.1" 1792 | source = "registry+https://github.com/rust-lang/crates.io-index" 1793 | checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" 1794 | dependencies = [ 1795 | "bitflags 2.6.0", 1796 | "core-foundation", 1797 | "core-foundation-sys", 1798 | "libc", 1799 | "security-framework-sys", 1800 | ] 1801 | 1802 | [[package]] 1803 | name = "security-framework-sys" 1804 | version = "2.11.1" 1805 | source = "registry+https://github.com/rust-lang/crates.io-index" 1806 | checksum = "75da29fe9b9b08fe9d6b22b5b4bcbc75d8db3aa31e639aa56bb62e9d46bfceaf" 1807 | dependencies = [ 1808 | "core-foundation-sys", 1809 | "libc", 1810 | ] 1811 | 1812 | [[package]] 1813 | name = "serde" 1814 | version = "1.0.204" 1815 | source = "registry+https://github.com/rust-lang/crates.io-index" 1816 | checksum = "bc76f558e0cbb2a839d37354c575f1dc3fdc6546b5be373ba43d95f231bf7c12" 1817 | dependencies = [ 1818 | "serde_derive", 1819 | ] 1820 | 1821 | [[package]] 1822 | name = "serde_derive" 1823 | version = "1.0.204" 1824 | source = "registry+https://github.com/rust-lang/crates.io-index" 1825 | checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222" 1826 | dependencies = [ 1827 | "proc-macro2", 1828 | "quote", 1829 | "syn", 1830 | ] 1831 | 1832 | [[package]] 1833 | name = "serde_derive_internals" 1834 | version = "0.29.1" 1835 | source = "registry+https://github.com/rust-lang/crates.io-index" 1836 | checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" 1837 | dependencies = [ 1838 | "proc-macro2", 1839 | "quote", 1840 | "syn", 1841 | ] 1842 | 1843 | [[package]] 1844 | name = "serde_json" 1845 | version = "1.0.120" 1846 | source = "registry+https://github.com/rust-lang/crates.io-index" 1847 | checksum = "4e0d21c9a8cae1235ad58a00c11cb40d4b1e5c784f1ef2c537876ed6ffd8b7c5" 1848 | dependencies = [ 1849 | "itoa", 1850 | "ryu", 1851 | "serde", 1852 | ] 1853 | 1854 | [[package]] 1855 | name = "serde_path_to_error" 1856 | version = "0.1.16" 1857 | source = "registry+https://github.com/rust-lang/crates.io-index" 1858 | checksum = "af99884400da37c88f5e9146b7f1fd0fbcae8f6eec4e9da38b67d05486f814a6" 1859 | dependencies = [ 1860 | "itoa", 1861 | "serde", 1862 | ] 1863 | 1864 | [[package]] 1865 | name = "serde_qs" 1866 | version = "0.13.0" 1867 | source = "registry+https://github.com/rust-lang/crates.io-index" 1868 | checksum = "cd34f36fe4c5ba9654417139a9b3a20d2e1de6012ee678ad14d240c22c78d8d6" 1869 | dependencies = [ 1870 | "axum", 1871 | "futures", 1872 | "percent-encoding", 1873 | "serde", 1874 | "thiserror", 1875 | ] 1876 | 1877 | [[package]] 1878 | name = "serde_spanned" 1879 | version = "0.6.6" 1880 | source = "registry+https://github.com/rust-lang/crates.io-index" 1881 | checksum = "79e674e01f999af37c49f70a6ede167a8a60b2503e56c5599532a65baa5969a0" 1882 | dependencies = [ 1883 | "serde", 1884 | ] 1885 | 1886 | [[package]] 1887 | name = "serde_urlencoded" 1888 | version = "0.7.1" 1889 | source = "registry+https://github.com/rust-lang/crates.io-index" 1890 | checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" 1891 | dependencies = [ 1892 | "form_urlencoded", 1893 | "itoa", 1894 | "ryu", 1895 | "serde", 1896 | ] 1897 | 1898 | [[package]] 1899 | name = "sha1" 1900 | version = "0.10.6" 1901 | source = "registry+https://github.com/rust-lang/crates.io-index" 1902 | checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" 1903 | dependencies = [ 1904 | "cfg-if", 1905 | "cpufeatures", 1906 | "digest", 1907 | ] 1908 | 1909 | [[package]] 1910 | name = "sharded-slab" 1911 | version = "0.1.7" 1912 | source = "registry+https://github.com/rust-lang/crates.io-index" 1913 | checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" 1914 | dependencies = [ 1915 | "lazy_static", 1916 | ] 1917 | 1918 | [[package]] 1919 | name = "shlex" 1920 | version = "1.3.0" 1921 | source = "registry+https://github.com/rust-lang/crates.io-index" 1922 | checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" 1923 | 1924 | [[package]] 1925 | name = "signal-hook-registry" 1926 | version = "1.4.2" 1927 | source = "registry+https://github.com/rust-lang/crates.io-index" 1928 | checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" 1929 | dependencies = [ 1930 | "libc", 1931 | ] 1932 | 1933 | [[package]] 1934 | name = "slab" 1935 | version = "0.4.9" 1936 | source = "registry+https://github.com/rust-lang/crates.io-index" 1937 | checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" 1938 | dependencies = [ 1939 | "autocfg", 1940 | ] 1941 | 1942 | [[package]] 1943 | name = "slug" 1944 | version = "0.1.5" 1945 | source = "registry+https://github.com/rust-lang/crates.io-index" 1946 | checksum = "3bd94acec9c8da640005f8e135a39fc0372e74535e6b368b7a04b875f784c8c4" 1947 | dependencies = [ 1948 | "deunicode", 1949 | "wasm-bindgen", 1950 | ] 1951 | 1952 | [[package]] 1953 | name = "smallvec" 1954 | version = "1.13.2" 1955 | source = "registry+https://github.com/rust-lang/crates.io-index" 1956 | checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" 1957 | 1958 | [[package]] 1959 | name = "socket2" 1960 | version = "0.4.10" 1961 | source = "registry+https://github.com/rust-lang/crates.io-index" 1962 | checksum = "9f7916fc008ca5542385b89a3d3ce689953c143e9304a9bf8beec1de48994c0d" 1963 | dependencies = [ 1964 | "libc", 1965 | "winapi", 1966 | ] 1967 | 1968 | [[package]] 1969 | name = "socket2" 1970 | version = "0.5.7" 1971 | source = "registry+https://github.com/rust-lang/crates.io-index" 1972 | checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" 1973 | dependencies = [ 1974 | "libc", 1975 | "windows-sys 0.52.0", 1976 | ] 1977 | 1978 | [[package]] 1979 | name = "spin" 1980 | version = "0.9.8" 1981 | source = "registry+https://github.com/rust-lang/crates.io-index" 1982 | checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" 1983 | 1984 | [[package]] 1985 | name = "strsim" 1986 | version = "0.11.1" 1987 | source = "registry+https://github.com/rust-lang/crates.io-index" 1988 | checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" 1989 | 1990 | [[package]] 1991 | name = "subtle" 1992 | version = "2.6.1" 1993 | source = "registry+https://github.com/rust-lang/crates.io-index" 1994 | checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" 1995 | 1996 | [[package]] 1997 | name = "symlink" 1998 | version = "0.1.0" 1999 | source = "registry+https://github.com/rust-lang/crates.io-index" 2000 | checksum = "a7973cce6668464ea31f176d85b13c7ab3bba2cb3b77a2ed26abd7801688010a" 2001 | 2002 | [[package]] 2003 | name = "syn" 2004 | version = "2.0.71" 2005 | source = "registry+https://github.com/rust-lang/crates.io-index" 2006 | checksum = "b146dcf730474b4bcd16c311627b31ede9ab149045db4d6088b3becaea046462" 2007 | dependencies = [ 2008 | "proc-macro2", 2009 | "quote", 2010 | "unicode-ident", 2011 | ] 2012 | 2013 | [[package]] 2014 | name = "sync_wrapper" 2015 | version = "0.1.2" 2016 | source = "registry+https://github.com/rust-lang/crates.io-index" 2017 | checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" 2018 | 2019 | [[package]] 2020 | name = "sync_wrapper" 2021 | version = "1.0.1" 2022 | source = "registry+https://github.com/rust-lang/crates.io-index" 2023 | checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394" 2024 | 2025 | [[package]] 2026 | name = "system-configuration" 2027 | version = "0.5.1" 2028 | source = "registry+https://github.com/rust-lang/crates.io-index" 2029 | checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" 2030 | dependencies = [ 2031 | "bitflags 1.3.2", 2032 | "core-foundation", 2033 | "system-configuration-sys", 2034 | ] 2035 | 2036 | [[package]] 2037 | name = "system-configuration-sys" 2038 | version = "0.5.0" 2039 | source = "registry+https://github.com/rust-lang/crates.io-index" 2040 | checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9" 2041 | dependencies = [ 2042 | "core-foundation-sys", 2043 | "libc", 2044 | ] 2045 | 2046 | [[package]] 2047 | name = "tar" 2048 | version = "0.4.41" 2049 | source = "registry+https://github.com/rust-lang/crates.io-index" 2050 | checksum = "cb797dad5fb5b76fcf519e702f4a589483b5ef06567f160c392832c1f5e44909" 2051 | dependencies = [ 2052 | "filetime", 2053 | "libc", 2054 | "xattr", 2055 | ] 2056 | 2057 | [[package]] 2058 | name = "tempfile" 2059 | version = "3.10.1" 2060 | source = "registry+https://github.com/rust-lang/crates.io-index" 2061 | checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" 2062 | dependencies = [ 2063 | "cfg-if", 2064 | "fastrand", 2065 | "rustix", 2066 | "windows-sys 0.52.0", 2067 | ] 2068 | 2069 | [[package]] 2070 | name = "thiserror" 2071 | version = "1.0.63" 2072 | source = "registry+https://github.com/rust-lang/crates.io-index" 2073 | checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724" 2074 | dependencies = [ 2075 | "thiserror-impl", 2076 | ] 2077 | 2078 | [[package]] 2079 | name = "thiserror-impl" 2080 | version = "1.0.63" 2081 | source = "registry+https://github.com/rust-lang/crates.io-index" 2082 | checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" 2083 | dependencies = [ 2084 | "proc-macro2", 2085 | "quote", 2086 | "syn", 2087 | ] 2088 | 2089 | [[package]] 2090 | name = "thread_local" 2091 | version = "1.1.8" 2092 | source = "registry+https://github.com/rust-lang/crates.io-index" 2093 | checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" 2094 | dependencies = [ 2095 | "cfg-if", 2096 | "once_cell", 2097 | ] 2098 | 2099 | [[package]] 2100 | name = "time" 2101 | version = "0.3.36" 2102 | source = "registry+https://github.com/rust-lang/crates.io-index" 2103 | checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" 2104 | dependencies = [ 2105 | "deranged", 2106 | "num-conv", 2107 | "powerfmt", 2108 | "serde", 2109 | "time-core", 2110 | "time-macros", 2111 | ] 2112 | 2113 | [[package]] 2114 | name = "time-core" 2115 | version = "0.1.2" 2116 | source = "registry+https://github.com/rust-lang/crates.io-index" 2117 | checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" 2118 | 2119 | [[package]] 2120 | name = "time-macros" 2121 | version = "0.2.18" 2122 | source = "registry+https://github.com/rust-lang/crates.io-index" 2123 | checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf" 2124 | dependencies = [ 2125 | "num-conv", 2126 | "time-core", 2127 | ] 2128 | 2129 | [[package]] 2130 | name = "tinyvec" 2131 | version = "1.8.0" 2132 | source = "registry+https://github.com/rust-lang/crates.io-index" 2133 | checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938" 2134 | dependencies = [ 2135 | "tinyvec_macros", 2136 | ] 2137 | 2138 | [[package]] 2139 | name = "tinyvec_macros" 2140 | version = "0.1.1" 2141 | source = "registry+https://github.com/rust-lang/crates.io-index" 2142 | checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" 2143 | 2144 | [[package]] 2145 | name = "tokio" 2146 | version = "1.29.1" 2147 | source = "registry+https://github.com/rust-lang/crates.io-index" 2148 | checksum = "532826ff75199d5833b9d2c5fe410f29235e25704ee5f0ef599fb51c21f4a4da" 2149 | dependencies = [ 2150 | "autocfg", 2151 | "backtrace", 2152 | "bytes", 2153 | "libc", 2154 | "mio", 2155 | "num_cpus", 2156 | "parking_lot", 2157 | "pin-project-lite", 2158 | "signal-hook-registry", 2159 | "socket2 0.4.10", 2160 | "tokio-macros", 2161 | "windows-sys 0.48.0", 2162 | ] 2163 | 2164 | [[package]] 2165 | name = "tokio-macros" 2166 | version = "2.1.0" 2167 | source = "registry+https://github.com/rust-lang/crates.io-index" 2168 | checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" 2169 | dependencies = [ 2170 | "proc-macro2", 2171 | "quote", 2172 | "syn", 2173 | ] 2174 | 2175 | [[package]] 2176 | name = "tokio-native-tls" 2177 | version = "0.3.1" 2178 | source = "registry+https://github.com/rust-lang/crates.io-index" 2179 | checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" 2180 | dependencies = [ 2181 | "native-tls", 2182 | "tokio", 2183 | ] 2184 | 2185 | [[package]] 2186 | name = "tokio-rustls" 2187 | version = "0.26.0" 2188 | source = "registry+https://github.com/rust-lang/crates.io-index" 2189 | checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4" 2190 | dependencies = [ 2191 | "rustls", 2192 | "rustls-pki-types", 2193 | "tokio", 2194 | ] 2195 | 2196 | [[package]] 2197 | name = "tokio-util" 2198 | version = "0.7.11" 2199 | source = "registry+https://github.com/rust-lang/crates.io-index" 2200 | checksum = "9cf6b47b3771c49ac75ad09a6162f53ad4b8088b76ac60e8ec1455b31a189fe1" 2201 | dependencies = [ 2202 | "bytes", 2203 | "futures-core", 2204 | "futures-sink", 2205 | "pin-project-lite", 2206 | "tokio", 2207 | ] 2208 | 2209 | [[package]] 2210 | name = "toml" 2211 | version = "0.8.15" 2212 | source = "registry+https://github.com/rust-lang/crates.io-index" 2213 | checksum = "ac2caab0bf757388c6c0ae23b3293fdb463fee59434529014f85e3263b995c28" 2214 | dependencies = [ 2215 | "serde", 2216 | "serde_spanned", 2217 | "toml_datetime", 2218 | "toml_edit", 2219 | ] 2220 | 2221 | [[package]] 2222 | name = "toml_datetime" 2223 | version = "0.6.6" 2224 | source = "registry+https://github.com/rust-lang/crates.io-index" 2225 | checksum = "4badfd56924ae69bcc9039335b2e017639ce3f9b001c393c1b2d1ef846ce2cbf" 2226 | dependencies = [ 2227 | "serde", 2228 | ] 2229 | 2230 | [[package]] 2231 | name = "toml_edit" 2232 | version = "0.22.16" 2233 | source = "registry+https://github.com/rust-lang/crates.io-index" 2234 | checksum = "278f3d518e152219c994ce877758516bca5e118eaed6996192a774fb9fbf0788" 2235 | dependencies = [ 2236 | "indexmap", 2237 | "serde", 2238 | "serde_spanned", 2239 | "toml_datetime", 2240 | "winnow", 2241 | ] 2242 | 2243 | [[package]] 2244 | name = "tower" 2245 | version = "0.4.13" 2246 | source = "registry+https://github.com/rust-lang/crates.io-index" 2247 | checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" 2248 | dependencies = [ 2249 | "futures-core", 2250 | "futures-util", 2251 | "pin-project", 2252 | "pin-project-lite", 2253 | "tokio", 2254 | "tower-layer", 2255 | "tower-service", 2256 | "tracing", 2257 | ] 2258 | 2259 | [[package]] 2260 | name = "tower-layer" 2261 | version = "0.3.2" 2262 | source = "registry+https://github.com/rust-lang/crates.io-index" 2263 | checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0" 2264 | 2265 | [[package]] 2266 | name = "tower-service" 2267 | version = "0.3.2" 2268 | source = "registry+https://github.com/rust-lang/crates.io-index" 2269 | checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" 2270 | 2271 | [[package]] 2272 | name = "tracing" 2273 | version = "0.1.40" 2274 | source = "registry+https://github.com/rust-lang/crates.io-index" 2275 | checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" 2276 | dependencies = [ 2277 | "log", 2278 | "pin-project-lite", 2279 | "tracing-attributes", 2280 | "tracing-core", 2281 | ] 2282 | 2283 | [[package]] 2284 | name = "tracing-attributes" 2285 | version = "0.1.27" 2286 | source = "registry+https://github.com/rust-lang/crates.io-index" 2287 | checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" 2288 | dependencies = [ 2289 | "proc-macro2", 2290 | "quote", 2291 | "syn", 2292 | ] 2293 | 2294 | [[package]] 2295 | name = "tracing-core" 2296 | version = "0.1.32" 2297 | source = "registry+https://github.com/rust-lang/crates.io-index" 2298 | checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" 2299 | dependencies = [ 2300 | "once_cell", 2301 | "valuable", 2302 | ] 2303 | 2304 | [[package]] 2305 | name = "tracing-log" 2306 | version = "0.2.0" 2307 | source = "registry+https://github.com/rust-lang/crates.io-index" 2308 | checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" 2309 | dependencies = [ 2310 | "log", 2311 | "once_cell", 2312 | "tracing-core", 2313 | ] 2314 | 2315 | [[package]] 2316 | name = "tracing-subscriber" 2317 | version = "0.3.18" 2318 | source = "registry+https://github.com/rust-lang/crates.io-index" 2319 | checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" 2320 | dependencies = [ 2321 | "matchers", 2322 | "nu-ansi-term", 2323 | "once_cell", 2324 | "regex", 2325 | "sharded-slab", 2326 | "smallvec", 2327 | "thread_local", 2328 | "tracing", 2329 | "tracing-core", 2330 | "tracing-log", 2331 | ] 2332 | 2333 | [[package]] 2334 | name = "try-lock" 2335 | version = "0.2.5" 2336 | source = "registry+https://github.com/rust-lang/crates.io-index" 2337 | checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" 2338 | 2339 | [[package]] 2340 | name = "typenum" 2341 | version = "1.17.0" 2342 | source = "registry+https://github.com/rust-lang/crates.io-index" 2343 | checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" 2344 | 2345 | [[package]] 2346 | name = "unicode-bidi" 2347 | version = "0.3.15" 2348 | source = "registry+https://github.com/rust-lang/crates.io-index" 2349 | checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" 2350 | 2351 | [[package]] 2352 | name = "unicode-ident" 2353 | version = "1.0.12" 2354 | source = "registry+https://github.com/rust-lang/crates.io-index" 2355 | checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" 2356 | 2357 | [[package]] 2358 | name = "unicode-normalization" 2359 | version = "0.1.23" 2360 | source = "registry+https://github.com/rust-lang/crates.io-index" 2361 | checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" 2362 | dependencies = [ 2363 | "tinyvec", 2364 | ] 2365 | 2366 | [[package]] 2367 | name = "unicode-width" 2368 | version = "0.1.13" 2369 | source = "registry+https://github.com/rust-lang/crates.io-index" 2370 | checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d" 2371 | 2372 | [[package]] 2373 | name = "untrusted" 2374 | version = "0.9.0" 2375 | source = "registry+https://github.com/rust-lang/crates.io-index" 2376 | checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" 2377 | 2378 | [[package]] 2379 | name = "url" 2380 | version = "2.5.2" 2381 | source = "registry+https://github.com/rust-lang/crates.io-index" 2382 | checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c" 2383 | dependencies = [ 2384 | "form_urlencoded", 2385 | "idna", 2386 | "percent-encoding", 2387 | ] 2388 | 2389 | [[package]] 2390 | name = "utf8parse" 2391 | version = "0.2.2" 2392 | source = "registry+https://github.com/rust-lang/crates.io-index" 2393 | checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" 2394 | 2395 | [[package]] 2396 | name = "uuid" 2397 | version = "1.10.0" 2398 | source = "registry+https://github.com/rust-lang/crates.io-index" 2399 | checksum = "81dfa00651efa65069b0b6b651f4aaa31ba9e3c3ce0137aaad053604ee7e0314" 2400 | dependencies = [ 2401 | "getrandom", 2402 | ] 2403 | 2404 | [[package]] 2405 | name = "valuable" 2406 | version = "0.1.0" 2407 | source = "registry+https://github.com/rust-lang/crates.io-index" 2408 | checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" 2409 | 2410 | [[package]] 2411 | name = "vcpkg" 2412 | version = "0.2.15" 2413 | source = "registry+https://github.com/rust-lang/crates.io-index" 2414 | checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" 2415 | 2416 | [[package]] 2417 | name = "version_check" 2418 | version = "0.9.4" 2419 | source = "registry+https://github.com/rust-lang/crates.io-index" 2420 | checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" 2421 | 2422 | [[package]] 2423 | name = "want" 2424 | version = "0.3.1" 2425 | source = "registry+https://github.com/rust-lang/crates.io-index" 2426 | checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" 2427 | dependencies = [ 2428 | "try-lock", 2429 | ] 2430 | 2431 | [[package]] 2432 | name = "wasi" 2433 | version = "0.11.0+wasi-snapshot-preview1" 2434 | source = "registry+https://github.com/rust-lang/crates.io-index" 2435 | checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" 2436 | 2437 | [[package]] 2438 | name = "wasm-bindgen" 2439 | version = "0.2.92" 2440 | source = "registry+https://github.com/rust-lang/crates.io-index" 2441 | checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" 2442 | dependencies = [ 2443 | "cfg-if", 2444 | "wasm-bindgen-macro", 2445 | ] 2446 | 2447 | [[package]] 2448 | name = "wasm-bindgen-backend" 2449 | version = "0.2.92" 2450 | source = "registry+https://github.com/rust-lang/crates.io-index" 2451 | checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" 2452 | dependencies = [ 2453 | "bumpalo", 2454 | "log", 2455 | "once_cell", 2456 | "proc-macro2", 2457 | "quote", 2458 | "syn", 2459 | "wasm-bindgen-shared", 2460 | ] 2461 | 2462 | [[package]] 2463 | name = "wasm-bindgen-futures" 2464 | version = "0.4.42" 2465 | source = "registry+https://github.com/rust-lang/crates.io-index" 2466 | checksum = "76bc14366121efc8dbb487ab05bcc9d346b3b5ec0eaa76e46594cabbe51762c0" 2467 | dependencies = [ 2468 | "cfg-if", 2469 | "js-sys", 2470 | "wasm-bindgen", 2471 | "web-sys", 2472 | ] 2473 | 2474 | [[package]] 2475 | name = "wasm-bindgen-macro" 2476 | version = "0.2.92" 2477 | source = "registry+https://github.com/rust-lang/crates.io-index" 2478 | checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" 2479 | dependencies = [ 2480 | "quote", 2481 | "wasm-bindgen-macro-support", 2482 | ] 2483 | 2484 | [[package]] 2485 | name = "wasm-bindgen-macro-support" 2486 | version = "0.2.92" 2487 | source = "registry+https://github.com/rust-lang/crates.io-index" 2488 | checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" 2489 | dependencies = [ 2490 | "proc-macro2", 2491 | "quote", 2492 | "syn", 2493 | "wasm-bindgen-backend", 2494 | "wasm-bindgen-shared", 2495 | ] 2496 | 2497 | [[package]] 2498 | name = "wasm-bindgen-shared" 2499 | version = "0.2.92" 2500 | source = "registry+https://github.com/rust-lang/crates.io-index" 2501 | checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" 2502 | 2503 | [[package]] 2504 | name = "wasm-streams" 2505 | version = "0.4.0" 2506 | source = "registry+https://github.com/rust-lang/crates.io-index" 2507 | checksum = "b65dc4c90b63b118468cf747d8bf3566c1913ef60be765b5730ead9e0a3ba129" 2508 | dependencies = [ 2509 | "futures-util", 2510 | "js-sys", 2511 | "wasm-bindgen", 2512 | "wasm-bindgen-futures", 2513 | "web-sys", 2514 | ] 2515 | 2516 | [[package]] 2517 | name = "web-sys" 2518 | version = "0.3.69" 2519 | source = "registry+https://github.com/rust-lang/crates.io-index" 2520 | checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" 2521 | dependencies = [ 2522 | "js-sys", 2523 | "wasm-bindgen", 2524 | ] 2525 | 2526 | [[package]] 2527 | name = "winapi" 2528 | version = "0.3.9" 2529 | source = "registry+https://github.com/rust-lang/crates.io-index" 2530 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 2531 | dependencies = [ 2532 | "winapi-i686-pc-windows-gnu", 2533 | "winapi-x86_64-pc-windows-gnu", 2534 | ] 2535 | 2536 | [[package]] 2537 | name = "winapi-i686-pc-windows-gnu" 2538 | version = "0.4.0" 2539 | source = "registry+https://github.com/rust-lang/crates.io-index" 2540 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 2541 | 2542 | [[package]] 2543 | name = "winapi-x86_64-pc-windows-gnu" 2544 | version = "0.4.0" 2545 | source = "registry+https://github.com/rust-lang/crates.io-index" 2546 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 2547 | 2548 | [[package]] 2549 | name = "windows-core" 2550 | version = "0.52.0" 2551 | source = "registry+https://github.com/rust-lang/crates.io-index" 2552 | checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" 2553 | dependencies = [ 2554 | "windows-targets 0.52.6", 2555 | ] 2556 | 2557 | [[package]] 2558 | name = "windows-sys" 2559 | version = "0.48.0" 2560 | source = "registry+https://github.com/rust-lang/crates.io-index" 2561 | checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" 2562 | dependencies = [ 2563 | "windows-targets 0.48.5", 2564 | ] 2565 | 2566 | [[package]] 2567 | name = "windows-sys" 2568 | version = "0.52.0" 2569 | source = "registry+https://github.com/rust-lang/crates.io-index" 2570 | checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" 2571 | dependencies = [ 2572 | "windows-targets 0.52.6", 2573 | ] 2574 | 2575 | [[package]] 2576 | name = "windows-targets" 2577 | version = "0.48.5" 2578 | source = "registry+https://github.com/rust-lang/crates.io-index" 2579 | checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" 2580 | dependencies = [ 2581 | "windows_aarch64_gnullvm 0.48.5", 2582 | "windows_aarch64_msvc 0.48.5", 2583 | "windows_i686_gnu 0.48.5", 2584 | "windows_i686_msvc 0.48.5", 2585 | "windows_x86_64_gnu 0.48.5", 2586 | "windows_x86_64_gnullvm 0.48.5", 2587 | "windows_x86_64_msvc 0.48.5", 2588 | ] 2589 | 2590 | [[package]] 2591 | name = "windows-targets" 2592 | version = "0.52.6" 2593 | source = "registry+https://github.com/rust-lang/crates.io-index" 2594 | checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" 2595 | dependencies = [ 2596 | "windows_aarch64_gnullvm 0.52.6", 2597 | "windows_aarch64_msvc 0.52.6", 2598 | "windows_i686_gnu 0.52.6", 2599 | "windows_i686_gnullvm", 2600 | "windows_i686_msvc 0.52.6", 2601 | "windows_x86_64_gnu 0.52.6", 2602 | "windows_x86_64_gnullvm 0.52.6", 2603 | "windows_x86_64_msvc 0.52.6", 2604 | ] 2605 | 2606 | [[package]] 2607 | name = "windows_aarch64_gnullvm" 2608 | version = "0.48.5" 2609 | source = "registry+https://github.com/rust-lang/crates.io-index" 2610 | checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" 2611 | 2612 | [[package]] 2613 | name = "windows_aarch64_gnullvm" 2614 | version = "0.52.6" 2615 | source = "registry+https://github.com/rust-lang/crates.io-index" 2616 | checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" 2617 | 2618 | [[package]] 2619 | name = "windows_aarch64_msvc" 2620 | version = "0.48.5" 2621 | source = "registry+https://github.com/rust-lang/crates.io-index" 2622 | checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" 2623 | 2624 | [[package]] 2625 | name = "windows_aarch64_msvc" 2626 | version = "0.52.6" 2627 | source = "registry+https://github.com/rust-lang/crates.io-index" 2628 | checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" 2629 | 2630 | [[package]] 2631 | name = "windows_i686_gnu" 2632 | version = "0.48.5" 2633 | source = "registry+https://github.com/rust-lang/crates.io-index" 2634 | checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" 2635 | 2636 | [[package]] 2637 | name = "windows_i686_gnu" 2638 | version = "0.52.6" 2639 | source = "registry+https://github.com/rust-lang/crates.io-index" 2640 | checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" 2641 | 2642 | [[package]] 2643 | name = "windows_i686_gnullvm" 2644 | version = "0.52.6" 2645 | source = "registry+https://github.com/rust-lang/crates.io-index" 2646 | checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" 2647 | 2648 | [[package]] 2649 | name = "windows_i686_msvc" 2650 | version = "0.48.5" 2651 | source = "registry+https://github.com/rust-lang/crates.io-index" 2652 | checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" 2653 | 2654 | [[package]] 2655 | name = "windows_i686_msvc" 2656 | version = "0.52.6" 2657 | source = "registry+https://github.com/rust-lang/crates.io-index" 2658 | checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" 2659 | 2660 | [[package]] 2661 | name = "windows_x86_64_gnu" 2662 | version = "0.48.5" 2663 | source = "registry+https://github.com/rust-lang/crates.io-index" 2664 | checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" 2665 | 2666 | [[package]] 2667 | name = "windows_x86_64_gnu" 2668 | version = "0.52.6" 2669 | source = "registry+https://github.com/rust-lang/crates.io-index" 2670 | checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" 2671 | 2672 | [[package]] 2673 | name = "windows_x86_64_gnullvm" 2674 | version = "0.48.5" 2675 | source = "registry+https://github.com/rust-lang/crates.io-index" 2676 | checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" 2677 | 2678 | [[package]] 2679 | name = "windows_x86_64_gnullvm" 2680 | version = "0.52.6" 2681 | source = "registry+https://github.com/rust-lang/crates.io-index" 2682 | checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" 2683 | 2684 | [[package]] 2685 | name = "windows_x86_64_msvc" 2686 | version = "0.48.5" 2687 | source = "registry+https://github.com/rust-lang/crates.io-index" 2688 | checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" 2689 | 2690 | [[package]] 2691 | name = "windows_x86_64_msvc" 2692 | version = "0.52.6" 2693 | source = "registry+https://github.com/rust-lang/crates.io-index" 2694 | checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" 2695 | 2696 | [[package]] 2697 | name = "winnow" 2698 | version = "0.6.14" 2699 | source = "registry+https://github.com/rust-lang/crates.io-index" 2700 | checksum = "374ec40a2d767a3c1b4972d9475ecd557356637be906f2cb3f7fe17a6eb5e22f" 2701 | dependencies = [ 2702 | "memchr", 2703 | ] 2704 | 2705 | [[package]] 2706 | name = "winreg" 2707 | version = "0.52.0" 2708 | source = "registry+https://github.com/rust-lang/crates.io-index" 2709 | checksum = "a277a57398d4bfa075df44f501a17cfdf8542d224f0d36095a2adc7aee4ef0a5" 2710 | dependencies = [ 2711 | "cfg-if", 2712 | "windows-sys 0.48.0", 2713 | ] 2714 | 2715 | [[package]] 2716 | name = "xattr" 2717 | version = "1.3.1" 2718 | source = "registry+https://github.com/rust-lang/crates.io-index" 2719 | checksum = "8da84f1a25939b27f6820d92aed108f83ff920fdf11a7b19366c27c4cda81d4f" 2720 | dependencies = [ 2721 | "libc", 2722 | "linux-raw-sys", 2723 | "rustix", 2724 | ] 2725 | 2726 | [[package]] 2727 | name = "zerocopy" 2728 | version = "0.7.35" 2729 | source = "registry+https://github.com/rust-lang/crates.io-index" 2730 | checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" 2731 | dependencies = [ 2732 | "zerocopy-derive", 2733 | ] 2734 | 2735 | [[package]] 2736 | name = "zerocopy-derive" 2737 | version = "0.7.35" 2738 | source = "registry+https://github.com/rust-lang/crates.io-index" 2739 | checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" 2740 | dependencies = [ 2741 | "proc-macro2", 2742 | "quote", 2743 | "syn", 2744 | ] 2745 | 2746 | [[package]] 2747 | name = "zeroize" 2748 | version = "1.8.1" 2749 | source = "registry+https://github.com/rust-lang/crates.io-index" 2750 | checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" 2751 | --------------------------------------------------------------------------------