1use std::io::Write;
7
8use clap::{ArgAction, CommandFactory, Parser, Subcommand};
9use clap_complete::Shell;
10
11use crate::commands;
12use crate::context::{Ctx, GlobalArgs};
13use crate::errors::CliError;
14use crate::output::Format;
15
16#[derive(Debug, Parser)]
18#[command(
19 name = "qn",
20 version,
21 about = "Command-line interface for the Quicknode API.",
22 long_about = "qn lets you manage Quicknode endpoints, streams, webhooks, and the KV store from the terminal.\n\n\
23 Use `qn <noun> --help` (e.g. `qn endpoint --help`) for command details.\n\n\
24 Authentication is resolved in this order: --api-key flag, QN_CLI__API_KEY env var,\n\
25 ~/.config/qn/config.toml. Run `qn auth login` to save a key the first time.",
26 propagate_version = true,
27 disable_help_subcommand = true
28)]
29pub struct Cli {
30 #[arg(long, global = true, env = "QN_CLI__API_KEY", hide_env_values = true)]
32 pub api_key: Option<String>,
33
34 #[arg(short = 'o', long = "format", global = true, value_enum)]
38 pub format: Option<Format>,
39
40 #[arg(long, global = true)]
42 pub no_color: bool,
43
44 #[arg(short, long, global = true)]
46 pub quiet: bool,
47
48 #[arg(short = 'w', long = "wide", global = true)]
52 pub wide: bool,
53
54 #[arg(short, long, global = true)]
56 pub verbose: bool,
57
58 #[arg(long, global = true)]
60 pub no_input: bool,
61
62 #[arg(short = 'y', long = "yes", global = true, action = ArgAction::Count)]
64 pub yes: u8,
65
66 #[arg(long, global = true, hide = true)]
69 pub base_url: Option<String>,
70
71 #[command(subcommand)]
72 pub command: Command,
73}
74
75#[derive(Debug, Subcommand)]
76pub enum Command {
77 Auth(commands::auth::Args),
79
80 #[command(visible_alias = "endpoints")]
82 Endpoint(commands::endpoint::Args),
83
84 #[command(visible_alias = "tags")]
86 Tag(commands::tag::Args),
87
88 #[command(visible_alias = "teams")]
90 Team(commands::team::Args),
91
92 Usage(commands::usage::Args),
94
95 Metrics(commands::metrics::Args),
97
98 #[command(visible_alias = "chains")]
100 Chain(commands::chain::Args),
101
102 Billing(commands::billing::Args),
104
105 Bulk(commands::bulk::Args),
107
108 #[command(visible_alias = "streams")]
110 Stream(commands::stream::Args),
111
112 #[command(visible_alias = "webhooks")]
114 Webhook(commands::webhook::Args),
115
116 Kv(commands::kv::Args),
118
119 Completions {
121 #[arg(value_enum)]
123 shell: Shell,
124 },
125}
126
127impl Cli {
128 pub fn global_args(&self) -> GlobalArgs {
130 GlobalArgs {
131 api_key: self.api_key.clone(),
132 format: self.format,
133 wide: self.wide,
134 no_color: self.no_color,
137 quiet: self.quiet,
138 verbose: self.verbose,
139 no_input: self.no_input,
140 yes_count: self.yes,
141 base_url: self.base_url.clone(),
142 }
143 }
144
145 pub async fn run(self) -> Result<(), CliError> {
151 let global = self.global_args();
152 match self.command {
153 Command::Completions { shell } => {
154 let mut cmd = <Self as CommandFactory>::command();
155 let bin_name = cmd.get_name().to_string();
156 let mut out = std::io::stdout().lock();
157 clap_complete::generate(shell, &mut cmd, bin_name, &mut out);
158 out.flush()?;
159 Ok(())
160 }
161 Command::Auth(args) => commands::auth::run(args, global).await,
162 Command::Endpoint(args) => {
163 commands::endpoint::run(args, Ctx::from_global(global)?).await
164 }
165 Command::Tag(args) => commands::tag::run(args, Ctx::from_global(global)?).await,
166 Command::Team(args) => commands::team::run(args, Ctx::from_global(global)?).await,
167 Command::Usage(args) => commands::usage::run(args, Ctx::from_global(global)?).await,
168 Command::Metrics(args) => commands::metrics::run(args, Ctx::from_global(global)?).await,
169 Command::Chain(args) => commands::chain::run(args, Ctx::from_global(global)?).await,
170 Command::Billing(args) => commands::billing::run(args, Ctx::from_global(global)?).await,
171 Command::Bulk(args) => commands::bulk::run(args, Ctx::from_global(global)?).await,
172 Command::Stream(args) => commands::stream::run(args, Ctx::from_global(global)?).await,
173 Command::Webhook(args) => commands::webhook::run(args, Ctx::from_global(global)?).await,
174 Command::Kv(args) => commands::kv::run(args, Ctx::from_global(global)?).await,
175 }
176 }
177}