mod api;
mod cli;
mod config;
mod tui;
mod utils;
use clap::{Parser, Subcommand};
#[derive(Parser)]
#[command(
name = "flexprice",
version,
about = "⚡ FlexPrice CLI — Usage-based billing, from your terminal.",
long_about = None,
arg_required_else_help = true,
styles = get_styles(),
)]
struct Cli {
#[command(subcommand)]
command: Commands,
#[arg(long, global = true)]
api_url: Option<String>,
#[arg(long, global = true)]
api_key: Option<String>,
}
#[derive(Subcommand)]
enum Commands {
Auth {
#[command(subcommand)]
command: cli::auth::AuthCommands,
},
Customers {
#[command(subcommand)]
command: cli::customers::CustomerCommands,
},
Plans {
#[command(subcommand)]
command: cli::plans::PlanCommands,
},
Subscriptions {
#[command(subcommand)]
command: cli::subscriptions::SubscriptionCommands,
},
Invoices {
#[command(subcommand)]
command: cli::invoices::InvoiceCommands,
},
Meters {
#[command(subcommand)]
command: cli::meters::MeterCommands,
},
Events {
#[command(subcommand)]
command: cli::events::EventCommands,
},
Wallets {
#[command(subcommand)]
command: cli::wallets::WalletCommands,
},
Features {
#[command(subcommand)]
command: cli::features::FeatureCommands,
},
Entitlements {
#[command(subcommand)]
command: cli::entitlements::EntitlementCommands,
},
Config,
Dashboard,
}
fn get_styles() -> clap::builder::Styles {
clap::builder::Styles::styled()
.header(
clap::builder::styling::AnsiColor::Cyan
.on_default()
.bold(),
)
.usage(
clap::builder::styling::AnsiColor::Cyan
.on_default()
.bold(),
)
.literal(
clap::builder::styling::AnsiColor::Green.on_default().bold(),
)
.placeholder(clap::builder::styling::AnsiColor::BrightBlue.on_default())
}
#[tokio::main]
async fn main() {
let _ = dotenvy::dotenv();
let cli = Cli::parse();
let result = match cli.command {
Commands::Auth { command } => cli::auth::handle(command).await,
Commands::Customers { command } => cli::customers::handle(command).await,
Commands::Plans { command } => cli::plans::handle(command).await,
Commands::Subscriptions { command } => cli::subscriptions::handle(command).await,
Commands::Invoices { command } => cli::invoices::handle(command).await,
Commands::Meters { command } => cli::meters::handle(command).await,
Commands::Events { command } => cli::events::handle(command).await,
Commands::Wallets { command } => cli::wallets::handle(command).await,
Commands::Features { command } => cli::features::handle(command).await,
Commands::Entitlements { command } => cli::entitlements::handle(command).await,
Commands::Config => handle_config(),
Commands::Dashboard => handle_dashboard().await,
};
if let Err(e) = result {
utils::output::error(&format!("{:#}", e));
std::process::exit(1);
}
}
fn handle_config() -> anyhow::Result<()> {
let creds = config::Credentials::load(None, None)?;
println!();
utils::output::info(&format!("API URL: {}", if creds.api_url.is_empty() { "(not set)" } else { &creds.api_url }));
utils::output::info(&format!("API Key: {}", creds.masked_api_key()));
utils::output::info(&format!("Env ID: {}", creds.environment_id.as_deref().unwrap_or("(not set)")));
utils::output::info(&format!("Config path: {}", config::Credentials::credentials_path().display()));
println!();
Ok(())
}
async fn handle_dashboard() -> anyhow::Result<()> {
let creds = cli::auth::require_auth()?;
tui::dashboard::run(creds).await
}