From 9c1e7d1857c76bc5284b84bfebc8f589f4b7e4d6 Mon Sep 17 00:00:00 2001 From: Joshua Send Date: Fri, 18 Jul 2025 19:50:46 +0100 Subject: [PATCH 01/10] Create specific exit error codes (#300) ## Usage and product changes We generate specific error codes to check when executing commands and scripts programmatically. We now have the following exit codes: ``` Success = 0, GeneralError = 1, CommandError = 2, ConnectionError = 3, UserInputError = 4, QueryError = 5, ``` --- src/main.rs | 104 ++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 73 insertions(+), 31 deletions(-) diff --git a/src/main.rs b/src/main.rs index a5ee07b..353535a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -57,6 +57,36 @@ const TRANSACTION_REPL_HISTORY: &'static str = "typedb_console_transaction_repl_ const DIAGNOSTICS_REPORTING_URI: &'static str = "https://7f0ccb67b03abfccbacd7369d1f4ac6b@o4506315929812992.ingest.sentry.io/4506355433537536"; +#[derive(Debug, Copy, Clone)] +enum ExitCode { + Success = 0, + GeneralError = 1, + CommandError = 2, + ConnectionError = 3, + UserInputError = 4, + QueryError = 5, +} + +fn exit_with_error(err: &(dyn std::error::Error + 'static)) -> ! { + use crate::repl::command::ReplError; + if let Some(repl_err) = err.downcast_ref::() { + eprintln!("Error: {}", repl_err); + exit(ExitCode::UserInputError as i32); + } else if let Some(io_err) = err.downcast_ref::() { + eprintln!("I/O Error: {}", io_err); + exit(ExitCode::GeneralError as i32); + } else if let Some(driver_err) = err.downcast_ref::() { + eprintln!("TypeDB Error: {}", driver_err); + exit(ExitCode::QueryError as i32); + } else if let Some(command_error) = err.downcast_ref::() { + eprintln!("Command Error: {}", command_error); + exit(ExitCode::CommandError as i32); + } else { + eprintln!("Error: {}", err); + exit(ExitCode::GeneralError as i32); + } +} + struct ConsoleContext { invocation_dir: PathBuf, repl_stack: Vec>>, @@ -94,7 +124,7 @@ fn main() { let mut args = Args::parse(); if args.version { println!("{}", VERSION); - exit(0); + exit(ExitCode::Success as i32); } if args.password.is_none() { args.password = Some(LineReaderHidden::new().readline(&format!("password for '{}': ", args.username))); @@ -103,13 +133,13 @@ fn main() { init_diagnostics() } if !args.tls_disabled && !args.address.starts_with("https:") { - println!( + eprintln!( "\ TLS connections can only be enabled when connecting to HTTPS endpoints, for example using 'https://:port'. \ Please modify the address, or disable TLS (--tls-disabled). WARNING: this will send passwords over plaintext!\ " ); - exit(1); + exit(ExitCode::UserInputError as i32); } let runtime = BackgroundRuntime::new(); let tls_root_ca_path = args.tls_root_ca.as_ref().map(|value| Path::new(value)); @@ -120,11 +150,11 @@ fn main() { )) { Ok(driver) => Arc::new(driver), Err(err) => { - println!("Failed to create driver connection to server. {}", err); + eprintln!("Failed to create driver connection to server. {}", err); if !args.tls_disabled { - println!("Verify that the server is also configured with TLS encryption."); + eprintln!("Verify that the server is also configured with TLS encryption."); } - exit(1); + exit(ExitCode::ConnectionError as i32); } }; @@ -140,27 +170,34 @@ fn main() { }; if !args.command.is_empty() && !args.script.is_empty() { - println!("Error: Cannot specify both commands and files"); - exit(1); + eprintln!("Error: Cannot specify both commands and files"); + exit(ExitCode::UserInputError as i32); } else if !args.command.is_empty() { - execute_command_list(&mut context, &args.command); + if let Err(err) = execute_command_list(&mut context, &args.command) { + exit_with_error(&*err); + } } else if !args.script.is_empty() { - execute_scripts(&mut context, &args.script); + if let Err(err) = execute_scripts(&mut context, &args.script) { + exit_with_error(&*err); + } } else { execute_interactive(&mut context); } } -fn execute_scripts(context: &mut ConsoleContext, files: &[String]) { +fn execute_scripts(context: &mut ConsoleContext, files: &[String]) -> Result<(), Box> { for file_path in files { let path = context.convert_path(file_path); if let Ok(file) = File::open(&file_path) { execute_script(context, path, io::BufReader::new(file).lines()) } else { - println!("Error opening file: {}", path.to_string_lossy()); - exit(1); + return Err(Box::new(io::Error::new( + io::ErrorKind::NotFound, + format!("Error opening file: {}", path.to_string_lossy()), + ))); } } + Ok(()) } fn execute_script( @@ -187,13 +224,14 @@ fn execute_script( context.script_dir = None; } -fn execute_command_list(context: &mut ConsoleContext, commands: &[String]) { +fn execute_command_list(context: &mut ConsoleContext, commands: &[String]) -> Result<(), Box> { for command in commands { - if let Err(_) = execute_commands(context, command, true, true) { - println!("### Stopped executing at command: {}", command); - exit(1); + if let Err(err) = execute_commands(context, command, true, true) { + eprintln!("### Stopped executing at command: {}", command); + return Err(Box::new(err)); } } + Ok(()) } fn execute_interactive(context: &mut ConsoleContext) { @@ -221,7 +259,7 @@ fn execute_interactive(context: &mut ConsoleContext) { // do nothing } else { // this is unexpected... quit - exit(1) + exit(ExitCode::GeneralError as i32); } } Err(err) => { @@ -236,7 +274,7 @@ fn execute_commands( mut input: &str, coerce_each_command_to_one_line: bool, must_log_command: bool, -) -> Result<(), EmptyError> { +) -> Result<(), CommandError> { let mut multiple_commands = None; while !context.repl_stack.is_empty() && !input.trim().is_empty() { let repl_index = context.repl_stack.len() - 1; @@ -244,8 +282,9 @@ fn execute_commands( input = match current_repl.match_first_command(input, coerce_each_command_to_one_line) { Ok(None) => { - println!("Unrecognised command: {}", input); - return Err(EmptyError {}); + let message = format!("Unrecognised command: {}", input); + eprintln!("{}", message); + return Err(CommandError { message }); } Ok(Some((command, arguments, next_command_index))) => { let command_string = &input[0..next_command_index]; @@ -254,19 +293,20 @@ fn execute_commands( } if must_log_command || multiple_commands.is_some_and(|b| b) { - println!("{} {}", "+".repeat(repl_index + 1), command_string.trim()); + eprintln!("{} {}", "+".repeat(repl_index + 1), command_string.trim()); } match command.execute(context, arguments) { Ok(_) => &input[next_command_index..], Err(err) => { - println!("Error executing command: '{}'\n{}", command_string.trim(), err); - return Err(EmptyError {}); + let message = format!("Error executing command: '{}'\n{}", command_string.trim(), err); + eprintln!("{}", message); + return Err(CommandError { message }); } } } Err(err) => { - println!("{}", err); - return Err(EmptyError {}); + eprintln!("{}", err); + return Err(CommandError { message: err.to_string() }); } }; input = input.trim_start(); @@ -432,18 +472,20 @@ fn init_diagnostics() { )); } -struct EmptyError {} +struct CommandError { + message: String, +} -impl Debug for EmptyError { +impl Debug for CommandError { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { Display::fmt(self, f) } } -impl Display for EmptyError { +impl Display for CommandError { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - write!(f, "") + write!(f, "{}", self.message) } } -impl Error for EmptyError {} +impl Error for CommandError {} From 8372f8ba55bba8634065b8c80a28a58514b683cb Mon Sep 17 00:00:00 2001 From: Georgii Novoselov Date: Tue, 5 Aug 2025 10:03:18 +0100 Subject: [PATCH 02/10] Prepare for release 3.4.4 (#301) ## Usage and product changes Update version, release notes, and dependencies. ## Implementation --- Cargo.lock | 4 +-- Cargo.toml | 2 +- RELEASE_NOTES_LATEST.md | 42 +++++++++++----------------- VERSION | 2 +- dependencies/typedb/repositories.bzl | 2 +- 5 files changed, 22 insertions(+), 30 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0892c88..39f661d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2456,7 +2456,7 @@ dependencies = [ [[package]] name = "typedb-driver" version = "0.0.0" -source = "git+https://github.com/typedb/typedb-driver?rev=3b171274a42751376b2a480baa40315ebbf80fce#3b171274a42751376b2a480baa40315ebbf80fce" +source = "git+https://github.com/typedb/typedb-driver?tag=3.4.4#ca07f77759f7b5ca4044429f112f3866e7115424" dependencies = [ "chrono", "chrono-tz", @@ -2478,7 +2478,7 @@ dependencies = [ [[package]] name = "typedb-protocol" version = "0.0.0" -source = "git+https://github.com/typedb/typedb-protocol?rev=38f66a1cc4db3b7a301676f50800e9530ac5c8a3#38f66a1cc4db3b7a301676f50800e9530ac5c8a3" +source = "git+https://github.com/typedb/typedb-protocol?tag=3.4.0#3fc4c0fe0ac37c517af0e31415347299cff0307c" dependencies = [ "prost", "tonic", diff --git a/Cargo.toml b/Cargo.toml index 8c5bf21..e30e0dc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -47,7 +47,7 @@ features = {} [dependencies.typedb-driver] features = [] git = "https://github.com/typedb/typedb-driver" - tag = "3.4.0" + tag = "3.4.4" default-features = false [dependencies.futures] diff --git a/RELEASE_NOTES_LATEST.md b/RELEASE_NOTES_LATEST.md index 7827908..a625a7b 100644 --- a/RELEASE_NOTES_LATEST.md +++ b/RELEASE_NOTES_LATEST.md @@ -1,30 +1,9 @@ ## Distribution -Download from TypeDB Package Repository: https://cloudsmith.io/~typedb/repos/public-release/packages/?q=name:^typedb-console+version:3.4.0 +Download from TypeDB Package Repository: https://cloudsmith.io/~typedb/repos/public-release/packages/?q=name:^typedb-console+version:3.4.4 ## New Features -- **Introduce database export and import** - Add database export and database import operations. - - Database export saves the database information (its schema and data) on the client machine as two files at provided locations: - ``` - # database export - database export my-database export/my-database.typeql export/my-database.typedb - ``` - - Database import uses the exported files to create a new database with equivalent schema and data: - ``` - # database export - database import their-database export/my-database.typeql export/my-database.typedb - ``` - -- **Support relative script and source commands** - - We support using relative paths for the `--script` command (relative to the current directory), as well as relative paths for the REPL `source` command. - - When `source` is invoked _from_ a script, the sourced file is relativised to the script, rather than the current working directory. - ## Bugs Fixed @@ -34,6 +13,19 @@ Download from TypeDB Package Repository: https://cloudsmith.io/~typedb/repos/pub ## Other Improvements -- **Update zlib dependency** - Support build on Apple Clang 17+ by updating dependencies (details: https://github.com/typedb/typedb-dependencies/pull/577). - +- **Create specific exit error codes** + + We generate specific error codes to check when executing commands and scripts programmatically. + We now have the following exit codes: + ``` + Success = 0, + GeneralError = 1, + CommandError = 2, + ConnectionError = 3, + UserInputError = 4, + QueryError = 5, + ``` + + + + diff --git a/VERSION b/VERSION index fbcbf73..5141b61 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -3.4.0 \ No newline at end of file +3.4.4 \ No newline at end of file diff --git a/dependencies/typedb/repositories.bzl b/dependencies/typedb/repositories.bzl index c98c0a9..21da494 100644 --- a/dependencies/typedb/repositories.bzl +++ b/dependencies/typedb/repositories.bzl @@ -15,7 +15,7 @@ def typedb_driver(): git_repository( name = "typedb_driver", remote = "https://github.com/typedb/typedb-driver", - tag = "3.4.0", # sync-marker: do not remove this comment, this is used for sync-dependencies by @typedb_driver + tag = "3.4.4", # sync-marker: do not remove this comment, this is used for sync-dependencies by @typedb_driver ) def typeql(): From b84751373100b1f1ae8c51d57cc6e1a23200e8f5 Mon Sep 17 00:00:00 2001 From: Georgii Novoselov Date: Wed, 6 Aug 2025 17:56:57 +0100 Subject: [PATCH 03/10] Make version argument not require other fields and unify error messaging (#302) ## Usage and product changes Fix an incorrect requirement of `username` and `address` when executing `console --version`. Additionally, unify the format of error messages and add colors (e.g., the "error" header is printed in bold red and argument references are printed in yellow, similar to some of the existing parsing errors). ## Implementation ### --version Make all CLI arguments optional. This requires handling `username` and `address` manually, but it's the most scalable solution (in case we have more arguments like `--version` that differ from the standard Console flow). Considered alternatives: * use the standard Clap `--version` (not available for us because of the version overriding mechanism, same as in `typedb` core); * split CLI into subcommands to have a distinct difference between the standard execution flow and other commands (I don't like it). ### Error messages With this change, error messages became more random - some are colored, while others are not. And this problem extended for specifically parsing errors. A less important loss: if both `username` and `address` are missing, we will only notify about `username` first, and the `address` will be mentioned only after the initial issue is fixed. To compensate the stylistic mismatch, we introduce a better user-friendly error messaging with coloring. Instead of manual coloring with styling codes, we reuse [clap structs](https://github.com/clap-rs/clap/blob/4c6fd932cb1860fac450dc7992918a5bde0c6a2b/clap_builder/src/builder/styling.rs#L62) and formatting approach to make sure that it works consistently for all error messages, for all operating systems, for all terminal operations (e.g., redirecting output to a file). --- src/cli.rs | 11 +++++--- src/main.rs | 70 ++++++++++++++++++++++++++++++++------------------ src/printer.rs | 49 +++++++++++++++++++++++++++++++++++ 3 files changed, 101 insertions(+), 29 deletions(-) diff --git a/src/cli.rs b/src/cli.rs index ecc2769..f0276b2 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -6,6 +6,9 @@ use clap::Parser; +pub const ADDRESS_VALUE_NAME: &str = "host:port"; +pub const USERNAME_VALUE_NAME: &str = "username"; + #[derive(Parser, Debug)] #[command(author, about)] pub struct Args { @@ -22,12 +25,12 @@ pub struct Args { pub script: Vec, /// TypeDB address to connect to. If using TLS encryption, this must start with "https://" - #[arg(long, value_name = "host:port")] - pub address: String, + #[arg(long, value_name = ADDRESS_VALUE_NAME)] + pub address: Option, /// Username for authentication - #[arg(long, value_name = "username")] - pub username: String, + #[arg(long, value_name = USERNAME_VALUE_NAME)] + pub username: Option, /// Password for authentication. Will be requested safely by default. #[arg(long, value_name = "password")] diff --git a/src/main.rs b/src/main.rs index 353535a..cab4755 100644 --- a/src/main.rs +++ b/src/main.rs @@ -25,7 +25,7 @@ use sentry::ClientOptions; use typedb_driver::{Credentials, DriverOptions, Transaction, TransactionType, TypeDBDriver}; use crate::{ - cli::Args, + cli::{Args, ADDRESS_VALUE_NAME, USERNAME_VALUE_NAME}, completions::{database_name_completer_fn, file_completer}, operations::{ database_create, database_delete, database_export, database_import, database_list, database_schema, @@ -70,19 +70,19 @@ enum ExitCode { fn exit_with_error(err: &(dyn std::error::Error + 'static)) -> ! { use crate::repl::command::ReplError; if let Some(repl_err) = err.downcast_ref::() { - eprintln!("Error: {}", repl_err); + println_error!("Error: {}", repl_err); exit(ExitCode::UserInputError as i32); } else if let Some(io_err) = err.downcast_ref::() { - eprintln!("I/O Error: {}", io_err); + println_error!("I/O Error: {}", io_err); exit(ExitCode::GeneralError as i32); } else if let Some(driver_err) = err.downcast_ref::() { - eprintln!("TypeDB Error: {}", driver_err); + println_error!("TypeDB Error: {}", driver_err); exit(ExitCode::QueryError as i32); } else if let Some(command_error) = err.downcast_ref::() { - eprintln!("Command Error: {}", command_error); + println_error!("Command Error: {}", command_error); exit(ExitCode::CommandError as i32); } else { - eprintln!("Error: {}", err); + println_error!("Error: {}", err); exit(ExitCode::GeneralError as i32); } } @@ -126,34 +126,54 @@ fn main() { println!("{}", VERSION); exit(ExitCode::Success as i32); } + let address = match args.address { + Some(address) => address, + None => { + println_error!("missing server address ('{}').", format_argument!("--address <{ADDRESS_VALUE_NAME}>")); + exit(ExitCode::UserInputError as i32); + } + }; + let username = match args.username { + Some(username) => username, + None => { + println_error!( + "username is required for connection authentication ('{}').", + format_argument!("--username <{USERNAME_VALUE_NAME}>") + ); + exit(ExitCode::UserInputError as i32); + } + }; if args.password.is_none() { - args.password = Some(LineReaderHidden::new().readline(&format!("password for '{}': ", args.username))); + args.password = Some(LineReaderHidden::new().readline(&format!("password for '{username}': "))); } if !args.diagnostics_disable { init_diagnostics() } - if !args.tls_disabled && !args.address.starts_with("https:") { - eprintln!( + if !args.tls_disabled && !address.starts_with("https:") { + println_error!( "\ - TLS connections can only be enabled when connecting to HTTPS endpoints, for example using 'https://:port'. \ - Please modify the address, or disable TLS (--tls-disabled). WARNING: this will send passwords over plaintext!\ - " + TLS connections can only be enabled when connecting to HTTPS endpoints. \ + For example, using 'https://:port'.\n\ + Please modify the address or disable TLS ('{}'). {}\ + ", + format_argument!("--tls-disabled"), + format_warning!("WARNING: this will send passwords over plaintext!"), ); exit(ExitCode::UserInputError as i32); } - let runtime = BackgroundRuntime::new(); let tls_root_ca_path = args.tls_root_ca.as_ref().map(|value| Path::new(value)); + + let runtime = BackgroundRuntime::new(); let driver = match runtime.run(TypeDBDriver::new( - args.address, - Credentials::new(&args.username, args.password.as_ref().unwrap()), + address, + Credentials::new(&username, args.password.as_ref().unwrap()), DriverOptions::new(!args.tls_disabled, tls_root_ca_path).unwrap(), )) { Ok(driver) => Arc::new(driver), Err(err) => { - eprintln!("Failed to create driver connection to server. {}", err); - if !args.tls_disabled { - eprintln!("Verify that the server is also configured with TLS encryption."); - } + let tls_error = + if args.tls_disabled { "" } else { "\nVerify that the server is also configured with TLS encryption." }; + println_error!("Failed to create driver connection to server. {err}{tls_error}"); exit(ExitCode::ConnectionError as i32); } }; @@ -170,7 +190,7 @@ fn main() { }; if !args.command.is_empty() && !args.script.is_empty() { - eprintln!("Error: Cannot specify both commands and files"); + println_error!("cannot specify both commands and files"); exit(ExitCode::UserInputError as i32); } else if !args.command.is_empty() { if let Err(err) = execute_command_list(&mut context, &args.command) { @@ -227,7 +247,7 @@ fn execute_script( fn execute_command_list(context: &mut ConsoleContext, commands: &[String]) -> Result<(), Box> { for command in commands { if let Err(err) = execute_commands(context, command, true, true) { - eprintln!("### Stopped executing at command: {}", command); + println_error!("### Stopped executing at command: {}", command); return Err(Box::new(err)); } } @@ -283,7 +303,7 @@ fn execute_commands( input = match current_repl.match_first_command(input, coerce_each_command_to_one_line) { Ok(None) => { let message = format!("Unrecognised command: {}", input); - eprintln!("{}", message); + println_error!("{}", message); return Err(CommandError { message }); } Ok(Some((command, arguments, next_command_index))) => { @@ -293,19 +313,19 @@ fn execute_commands( } if must_log_command || multiple_commands.is_some_and(|b| b) { - eprintln!("{} {}", "+".repeat(repl_index + 1), command_string.trim()); + println_error!("{} {}", "+".repeat(repl_index + 1), command_string.trim()); } match command.execute(context, arguments) { Ok(_) => &input[next_command_index..], Err(err) => { let message = format!("Error executing command: '{}'\n{}", command_string.trim(), err); - eprintln!("{}", message); + println_error!("{}", message); return Err(CommandError { message }); } } } Err(err) => { - eprintln!("{}", err); + println_error!("{}", err); return Err(CommandError { message: err.to_string() }); } }; diff --git a/src/printer.rs b/src/printer.rs index eddb758..b26bb57 100644 --- a/src/printer.rs +++ b/src/printer.rs @@ -4,6 +4,7 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ +use clap::builder::styling::{AnsiColor, Color, Style}; use typedb_driver::{ answer::{ConceptDocument, ConceptRow}, concept::{Concept, Value}, @@ -14,6 +15,54 @@ const TABLE_INDENT: &'static str = " "; const CONTENT_INDENT: &'static str = " "; const TABLE_DASHES: usize = 7; +pub const ERROR_STYLE: Style = Style::new().fg_color(Some(Color::Ansi(AnsiColor::Red))).bold(); +pub const WARNING_STYLE: Style = Style::new().fg_color(Some(Color::Ansi(AnsiColor::Yellow))).bold(); +pub const ARGUMENT_STYLE: Style = Style::new().fg_color(Some(Color::Ansi(AnsiColor::Yellow))); + +#[macro_export] +macro_rules! format_error { + ($($arg:tt)*) => { + $crate::format_colored!($crate::printer::ERROR_STYLE, $($arg)*) + }; +} + +#[macro_export] +macro_rules! format_warning { + ($($arg:tt)*) => { + $crate::format_colored!($crate::printer::WARNING_STYLE, $($arg)*) + }; +} + +#[macro_export] +macro_rules! format_argument { + ($($arg:tt)*) => { + $crate::format_colored!($crate::printer::ARGUMENT_STYLE, $($arg)*) + }; +} + +#[macro_export] +macro_rules! format_colored { + ($style:expr, $($arg:tt)*) => { + format!( + "{}{}{}", + $style.render(), + format!($($arg)*), + $style.render_reset() + ) + }; +} + +#[macro_export] +macro_rules! println_error { + ($($arg:tt)*) => { + eprintln!( + "{} {}", + $crate::format_error!("error:"), + format!($($arg)*) + ); + } +} + fn println(string: &str) { println!("{}", string) } From 2367e593bc665d4aea528fccec8c697a8bf33a27 Mon Sep 17 00:00:00 2001 From: Georgii Novoselov Date: Fri, 27 Jun 2025 16:07:09 +0100 Subject: [PATCH 04/10] Support cluster-based driver updates --- Cargo.toml | 2 +- dependencies/typedb/repositories.bzl | 5 +++-- src/constants.rs | 2 +- src/main.rs | 6 +++--- src/operations.rs | 6 +++--- 5 files changed, 11 insertions(+), 10 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index e30e0dc..f9cbf13 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -46,8 +46,8 @@ features = {} [dependencies.typedb-driver] features = [] + rev = "d2ce9ab4f85f8316a9087c130a20c7b1e731e8c4" git = "https://github.com/typedb/typedb-driver" - tag = "3.4.4" default-features = false [dependencies.futures] diff --git a/dependencies/typedb/repositories.bzl b/dependencies/typedb/repositories.bzl index 21da494..7c031c8 100644 --- a/dependencies/typedb/repositories.bzl +++ b/dependencies/typedb/repositories.bzl @@ -12,10 +12,11 @@ def typedb_dependencies(): ) def typedb_driver(): + # TODO: Return typedb git_repository( name = "typedb_driver", - remote = "https://github.com/typedb/typedb-driver", - tag = "3.4.4", # sync-marker: do not remove this comment, this is used for sync-dependencies by @typedb_driver + remote = "https://github.com/farost/typedb-driver", + commit = "d2ce9ab4f85f8316a9087c130a20c7b1e731e8c4", # sync-marker: do not remove this comment, this is used for sync-dependencies by @typedb_driver ) def typeql(): diff --git a/src/constants.rs b/src/constants.rs index 8abbb18..63ecdc4 100644 --- a/src/constants.rs +++ b/src/constants.rs @@ -14,4 +14,4 @@ pub mod common { pub const SECONDS_IN_HOUR: u64 = SECONDS_IN_MINUTE * MINUTES_IN_HOUR; } -pub const DEFAULT_TRANSACTION_TIMEOUT: Duration = Duration::from_secs(1 * SECONDS_IN_HOUR); +pub const DEFAULT_TRANSACTION_TIMEOUT: Duration = Duration::from_secs(10); diff --git a/src/main.rs b/src/main.rs index cab4755..e8c9415 100644 --- a/src/main.rs +++ b/src/main.rs @@ -22,7 +22,7 @@ use clap::Parser; use home::home_dir; use rustyline::error::ReadlineError; use sentry::ClientOptions; -use typedb_driver::{Credentials, DriverOptions, Transaction, TransactionType, TypeDBDriver}; +use typedb_driver::{Addresses, Credentials, DriverOptions, Transaction, TransactionType, TypeDBDriver}; use crate::{ cli::{Args, ADDRESS_VALUE_NAME, USERNAME_VALUE_NAME}, @@ -165,9 +165,9 @@ fn main() { let runtime = BackgroundRuntime::new(); let driver = match runtime.run(TypeDBDriver::new( - address, + Addresses::try_from_address_str(&address).unwrap(), Credentials::new(&username, args.password.as_ref().unwrap()), - DriverOptions::new(!args.tls_disabled, tls_root_ca_path).unwrap(), + DriverOptions::new().tls_enabled(!args.tls_disabled).tls_root_ca(tls_root_ca_path).unwrap(), )) { Ok(driver) => Arc::new(driver), Err(err) => { diff --git a/src/operations.rs b/src/operations.rs index 3fc9710..b970e81 100644 --- a/src/operations.rs +++ b/src/operations.rs @@ -117,7 +117,7 @@ pub(crate) fn user_list(context: &mut ConsoleContext, _input: &[String]) -> Comm println!("No users are present."); } else { for user in users { - println!("{}", user.name); + println!("{}", user.name()); } } Ok(()) @@ -169,13 +169,13 @@ pub(crate) fn user_update_password(context: &mut ConsoleContext, input: &[String }; let current_user = driver .users() - .get_current_user() + .get_current() .await .map_err(|err| Box::new(err) as Box)? .expect("Could not fetch currently logged in user."); user.update_password(new_password).await.map_err(|err| Box::new(err) as Box)?; - Ok(current_user.name == username) + Ok(current_user.name() == username) })?; if updated_current_user { println!("Successfully updated current user's password, exiting console. Please log in with the updated credentials."); From 91cc1777fd130bbd4a9a84c6e5fbc6a392f314ce Mon Sep 17 00:00:00 2001 From: Georgii Novoselov Date: Fri, 27 Jun 2025 16:19:17 +0100 Subject: [PATCH 05/10] Roll back default tx timeout --- src/constants.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/constants.rs b/src/constants.rs index 63ecdc4..8abbb18 100644 --- a/src/constants.rs +++ b/src/constants.rs @@ -14,4 +14,4 @@ pub mod common { pub const SECONDS_IN_HOUR: u64 = SECONDS_IN_MINUTE * MINUTES_IN_HOUR; } -pub const DEFAULT_TRANSACTION_TIMEOUT: Duration = Duration::from_secs(10); +pub const DEFAULT_TRANSACTION_TIMEOUT: Duration = Duration::from_secs(1 * SECONDS_IN_HOUR); From c2d0771adcd46c3c74b6fe356f0ad390ec78887e Mon Sep 17 00:00:00 2001 From: Georgii Novoselov Date: Fri, 4 Jul 2025 11:33:14 +0100 Subject: [PATCH 06/10] Introduce multiple addresses for connection --- src/cli.rs | 26 +++++++++++++++--- src/main.rs | 76 ++++++++++++++++++++++++++++++++++++----------------- 2 files changed, 74 insertions(+), 28 deletions(-) diff --git a/src/cli.rs b/src/cli.rs index f0276b2..6f735ce 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -24,10 +24,28 @@ pub struct Args { #[arg(long, value_name = "path to script file")] pub script: Vec, - /// TypeDB address to connect to. If using TLS encryption, this must start with "https://" - #[arg(long, value_name = ADDRESS_VALUE_NAME)] + /// TypeDB address to connect to (host:port). If using TLS encryption, this must start with "https://". + #[arg(long, value_name = ADDRESS_VALUE_NAME, conflicts_with_all = ["addresses", "address_translation"])] pub address: Option, + /// A comma-separated list of TypeDB replica addresses of a single cluster to connect to. + #[arg(long, value_name = "host1:port1,host2:port2", conflicts_with_all = ["address", "address_translation"])] + pub addresses: Option, + + /// A comma-separated list of public=private address pairs. Public addresses are the user-facing + /// addresses of the replicas, and private addresses are the addresses used for the server-side + /// connection between replicas. + #[arg(long, value_name = "public=private,...", conflicts_with_all = ["address", "addresses"])] + pub address_translation: Option, + + /// If used in a cluster environment, disables attempts to redirect requests to server replicas, + /// limiting Console to communicate only with the single address specified in the `address` + /// argument. + /// Use for administrative / debug purposes to test a specific replica only: this option will + /// lower the success rate of Console's operations in production. + #[arg(long = "replication-disabled", default_value = "false")] + pub replication_disabled: bool, + /// Username for authentication #[arg(long, value_name = USERNAME_VALUE_NAME)] pub username: Option, @@ -48,8 +66,8 @@ pub struct Args { /// Disable error reporting. Error reporting helps TypeDB improve by reporting /// errors and crashes to the development team. - #[arg(long = "diagnostics-disable", default_value = "false")] - pub diagnostics_disable: bool, + #[arg(long = "diagnostics-disabled", default_value = "false")] + pub diagnostics_disabled: bool, /// Print the Console binary version #[arg(long = "version")] diff --git a/src/main.rs b/src/main.rs index e8c9415..f201245 100644 --- a/src/main.rs +++ b/src/main.rs @@ -17,7 +17,7 @@ use std::{ rc::Rc, sync::Arc, }; - +use std::collections::HashMap; use clap::Parser; use home::home_dir; use rustyline::error::ReadlineError; @@ -126,13 +126,19 @@ fn main() { println!("{}", VERSION); exit(ExitCode::Success as i32); } - let address = match args.address { - Some(address) => address, - None => { - println_error!("missing server address ('{}').", format_argument!("--address <{ADDRESS_VALUE_NAME}>")); - exit(ExitCode::UserInputError as i32); - } - }; + let address_info = parse_addresses(&args); + if !args.tls_disabled && !address_info.only_https { + println_error!( + "\ + TLS connections can only be enabled when connecting to HTTPS endpoints. \ + For example, using 'https://:port'.\n\ + Please modify the address or disable TLS ('{}'). {}\ + ", + format_argument!("--tls-disabled"), + format_warning!("WARNING: this will send passwords over plaintext!"), + ); + exit(ExitCode::UserInputError as i32); + } let username = match args.username { Some(username) => username, None => { @@ -146,28 +152,16 @@ fn main() { if args.password.is_none() { args.password = Some(LineReaderHidden::new().readline(&format!("password for '{username}': "))); } - if !args.diagnostics_disable { + if !args.diagnostics_disabled { init_diagnostics() } - if !args.tls_disabled && !address.starts_with("https:") { - println_error!( - "\ - TLS connections can only be enabled when connecting to HTTPS endpoints. \ - For example, using 'https://:port'.\n\ - Please modify the address or disable TLS ('{}'). {}\ - ", - format_argument!("--tls-disabled"), - format_warning!("WARNING: this will send passwords over plaintext!"), - ); - exit(ExitCode::UserInputError as i32); - } let tls_root_ca_path = args.tls_root_ca.as_ref().map(|value| Path::new(value)); - let runtime = BackgroundRuntime::new(); + let driver_options = DriverOptions::new().use_replication(!args.replication_disabled).tls_enabled(!args.tls_disabled).tls_root_ca(tls_root_ca_path).unwrap(); let driver = match runtime.run(TypeDBDriver::new( - Addresses::try_from_address_str(&address).unwrap(), + address_info.addresses, Credentials::new(&username, args.password.as_ref().unwrap()), - DriverOptions::new().tls_enabled(!args.tls_disabled).tls_root_ca(tls_root_ca_path).unwrap(), + driver_options, )) { Ok(driver) => Arc::new(driver), Err(err) => { @@ -485,6 +479,40 @@ fn transaction_type_str(transaction_type: TransactionType) -> &'static str { } } +struct AddressInfo { + only_https: bool, + addresses: Addresses, +} + +fn parse_addresses(args: &Args) -> AddressInfo { + if let Some(address) = &args.address { + AddressInfo {only_https: is_https_address(address), addresses: Addresses::try_from_address_str(address).unwrap() } + } else if let Some(addresses) = &args.addresses { + let split = addresses.split(',').map(str::to_string).collect::>(); + println!("Split: {split:?}"); + let only_https = split.iter().all(|address| is_https_address(address)); + AddressInfo {only_https, addresses: Addresses::try_from_addresses_str(split).unwrap() } + } else if let Some(translation) = &args.address_translation { + let mut map = HashMap::new(); + let mut only_https = true; + for pair in translation.split(',') { + let (public_address, private_address) = pair + .split_once('=') + .unwrap_or_else(|| panic!("Invalid address pair: {pair}. Must be of form public=private")); + only_https = only_https && is_https_address(public_address); + map.insert(public_address.to_string(), private_address.to_string()); + } + println!("Translation map:: {map:?}"); + AddressInfo {only_https, addresses: Addresses::try_from_translation_str(map).unwrap() } + } else { + panic!("At least one of --address, --addresses, or --address-translation must be provided."); + } +} + +fn is_https_address(address: &str) -> bool { + address.starts_with("https:") +} + fn init_diagnostics() { let _ = sentry::init(( DIAGNOSTICS_REPORTING_URI, From fcf7ec5a0128694d43713255bcac2864b79617e7 Mon Sep 17 00:00:00 2001 From: Georgii Novoselov Date: Tue, 8 Jul 2025 09:43:50 +0100 Subject: [PATCH 07/10] Add replica management --- src/main.rs | 25 ++++++++++++++++++++ src/operations.rs | 59 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 84 insertions(+) diff --git a/src/main.rs b/src/main.rs index f201245..beaac3e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -40,6 +40,7 @@ use crate::{ }, runtime::BackgroundRuntime, }; +use crate::operations::{replica_deregister, replica_list, replica_primary, replica_register, server_version}; mod cli; mod completions; @@ -329,6 +330,9 @@ fn execute_commands( } fn entry_repl(driver: Arc, runtime: BackgroundRuntime) -> Repl { + let server_commands = Subcommand::new("server") + .add(CommandLeaf::new("version", "Retrieve server version.", server_version)); + let database_commands = Subcommand::new("database") .add(CommandLeaf::new("list", "List databases on the server.", database_list)) .add(CommandLeaf::new_with_input( @@ -402,6 +406,25 @@ fn entry_repl(driver: Arc, runtime: BackgroundRuntime) -> Repl, runtime: BackgroundRuntime) -> Repl CommandResult { + let driver = context.driver.clone(); + let server_version = context + .background_runtime + .run(async move { driver.server_version().await }) + .map_err(|err| Box::new(err) as Box)?; + println!("{}", server_version); + Ok(()) +} + pub(crate) fn database_list(context: &mut ConsoleContext, _input: &[String]) -> CommandResult { let driver = context.driver.clone(); let databases = context @@ -186,6 +196,55 @@ pub(crate) fn user_update_password(context: &mut ConsoleContext, input: &[String Ok(()) } +pub(crate) fn replica_list(context: &mut ConsoleContext, _input: &[String]) -> CommandResult { + let driver = context.driver.clone(); + let replicas = driver.replicas(); + if replicas.is_empty() { + println!("No replicas are present."); + } else { + for replica in replicas { + println!("{}", replica.address()); + } + } + Ok(()) +} + +pub(crate) fn replica_primary(context: &mut ConsoleContext, _input: &[String]) -> CommandResult { + let driver = context.driver.clone(); + let primary_replica = driver.primary_replica(); + if let Some(primary_replica) = primary_replica { + println!("{}", primary_replica.address()); + } else { + println!("No primary replica is present."); + } + Ok(()) +} + +pub(crate) fn replica_register(context: &mut ConsoleContext, input: &[String]) -> CommandResult { + let driver = context.driver.clone(); + let replica_id: u64 = input[0].parse().map_err(|_| Box::new(ReplError { message: format!("Replica id '{}' must be a number.", input[0]) }) + as Box)?; + let address = input[1].clone(); + context + .background_runtime + .run(async move { driver.register_replica(replica_id, address).await }) + .map_err(|err| Box::new(err) as Box)?; + println!("Successfully registered replica."); + Ok(()) +} + +pub(crate) fn replica_deregister(context: &mut ConsoleContext, input: &[String]) -> CommandResult { + let driver = context.driver.clone(); + let replica_id: u64 = input[0].parse().map_err(|_| Box::new(ReplError { message: format!("Replica id '{}' must be a number.", input[0]) }) + as Box)?; + context + .background_runtime + .run(async move { driver.deregister_replica(replica_id).await }) + .map_err(|err| Box::new(err) as Box)?; + println!("Successfully deregistered replica."); + Ok(()) +} + pub(crate) fn transaction_read(context: &mut ConsoleContext, input: &[String]) -> CommandResult { let driver = context.driver.clone(); let db_name = &input[0]; From c0657f62359fa22d8527f89ec8ad443dc3de4c55 Mon Sep 17 00:00:00 2001 From: Georgii Novoselov Date: Mon, 4 Aug 2025 18:48:48 +0100 Subject: [PATCH 08/10] Progress with todos, review me --- src/cli.rs | 2 ++ src/main.rs | 43 +++++++++++++++++++++---------------------- src/operations.rs | 18 ++++++++++-------- 3 files changed, 33 insertions(+), 30 deletions(-) diff --git a/src/cli.rs b/src/cli.rs index 6f735ce..da4f272 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -46,6 +46,8 @@ pub struct Args { #[arg(long = "replication-disabled", default_value = "false")] pub replication_disabled: bool, + // TODO: Add cluster-related retries/attempts flags from Driver Options? + /// Username for authentication #[arg(long, value_name = USERNAME_VALUE_NAME)] pub username: Option, diff --git a/src/main.rs b/src/main.rs index beaac3e..26bec0c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -332,7 +332,26 @@ fn execute_commands( fn entry_repl(driver: Arc, runtime: BackgroundRuntime) -> Repl { let server_commands = Subcommand::new("server") .add(CommandLeaf::new("version", "Retrieve server version.", server_version)); - + + let replica_commands = Subcommand::new("replica") + .add(CommandLeaf::new("list", "List replicas.", replica_list)) + .add(CommandLeaf::new("primary", "Get current primary replica.", replica_primary)) + .add(CommandLeaf::new_with_inputs( + "register", + "Register new replica. Requires a clustering address, not a connection address.", + vec![ + CommandInput::new("replica id", get_word, None, None), + CommandInput::new("clustering address", get_word, None, None), + ], + replica_register, + )) + .add(CommandLeaf::new_with_input( + "deregister", + "Deregister existing replica.", + CommandInput::new("replica id", get_word, None, None), + replica_deregister, + )); + let database_commands = Subcommand::new("database") .add(CommandLeaf::new("list", "List databases on the server.", database_list)) .add(CommandLeaf::new_with_input( @@ -406,25 +425,6 @@ fn entry_repl(driver: Arc, runtime: BackgroundRuntime) -> Repl AddressInfo { AddressInfo {only_https: is_https_address(address), addresses: Addresses::try_from_address_str(address).unwrap() } } else if let Some(addresses) = &args.addresses { let split = addresses.split(',').map(str::to_string).collect::>(); - println!("Split: {split:?}"); let only_https = split.iter().all(|address| is_https_address(address)); AddressInfo {only_https, addresses: Addresses::try_from_addresses_str(split).unwrap() } } else if let Some(translation) = &args.address_translation { @@ -527,7 +526,7 @@ fn parse_addresses(args: &Args) -> AddressInfo { only_https = only_https && is_https_address(public_address); map.insert(public_address.to_string(), private_address.to_string()); } - println!("Translation map:: {map:?}"); + println!("Translation map:: {map:?}"); // TODO: Remove AddressInfo {only_https, addresses: Addresses::try_from_translation_str(map).unwrap() } } else { panic!("At least one of --address, --addresses, or --address-translation must be provided."); diff --git a/src/operations.rs b/src/operations.rs index c78565b..a57216f 100644 --- a/src/operations.rs +++ b/src/operations.rs @@ -198,15 +198,17 @@ pub(crate) fn user_update_password(context: &mut ConsoleContext, input: &[String pub(crate) fn replica_list(context: &mut ConsoleContext, _input: &[String]) -> CommandResult { let driver = context.driver.clone(); - let replicas = driver.replicas(); - if replicas.is_empty() { - println!("No replicas are present."); - } else { - for replica in replicas { - println!("{}", replica.address()); + context.background_runtime.run(async move { + let replicas = driver.replicas().await.map_err(|err| Box::new(err) as Box)?; + if replicas.is_empty() { + println!("No replicas are present."); + } else { + for replica in replicas { + println!("{}", replica.address()); + } } - } - Ok(()) + Ok(()) + }) } pub(crate) fn replica_primary(context: &mut ConsoleContext, _input: &[String]) -> CommandResult { From 6d84373eaf6529340ff62af61707e3c77a94b837 Mon Sep 17 00:00:00 2001 From: Georgii Novoselov Date: Mon, 11 Aug 2025 11:25:09 +0100 Subject: [PATCH 09/10] Update dependencies --- dependencies/typedb/repositories.bzl | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/dependencies/typedb/repositories.bzl b/dependencies/typedb/repositories.bzl index 7c031c8..bdc69ba 100644 --- a/dependencies/typedb/repositories.bzl +++ b/dependencies/typedb/repositories.bzl @@ -5,11 +5,12 @@ load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository") def typedb_dependencies(): - git_repository( - name = "typedb_dependencies", - remote = "https://github.com/typedb/typedb-dependencies", - commit = "fac1121c903b0c9e5924d391a883e4a0749a82a2", # sync-marker: do not remove this comment, this is used for sync-dependencies by @typedb_dependencies - ) + # TODO: Return ref after merge to master, currently points to 'raft-dependencies-addition' + git_repository( + name = "typedb_dependencies", + remote = "https://github.com/typedb/typedb-dependencies", + commit = "a7f714591ac8da4e8a281ebd1542190346a56da1", # sync-marker: do not remove this comment, this is used for sync-dependencies by @typedb_dependencies + ) def typedb_driver(): # TODO: Return typedb From 38573ff2a51eafc741750668bd1c2f7f1ce2fdb1 Mon Sep 17 00:00:00 2001 From: Georgii Novoselov Date: Mon, 11 Aug 2025 12:36:11 +0100 Subject: [PATCH 10/10] Update cargo files after rebase --- Cargo.lock | 61 +++++++++++++++++++++++++++++------------- Cargo.toml | 4 +-- tool/runner/Cargo.toml | 2 +- 3 files changed, 46 insertions(+), 21 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 39f661d..3283d32 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -305,9 +305,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.39" +version = "4.5.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd60e63e9be68e5fb56422e397cf9baddded06dae1d2e523401542383bc72a9f" +checksum = "50fd97c9dc2399518aa331917ac6f274280ec5eb34e555dd291899745c48ec6f" dependencies = [ "clap_builder", "clap_derive", @@ -315,9 +315,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.39" +version = "4.5.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89cc6392a1f72bbeb820d71f32108f61fdaf18bc526e1d23954168a67759ef51" +checksum = "c35b5830294e1fa0462034af85cc95225a4cb07092c088c55bda3147cfcd8f65" dependencies = [ "anstream", "anstyle", @@ -328,9 +328,9 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.32" +version = "4.5.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09176aae279615badda0765c0c0b3f6ed53f4709118af73cf4655d85d1530cd7" +checksum = "ef4f52386a59ca4c860f7393bcf8abd8dfd91ecccc0f774635ff68e92eeef491" dependencies = [ "heck", "proc-macro2", @@ -865,7 +865,7 @@ dependencies = [ "http-body", "hyper", "pin-project-lite", - "socket2", + "socket2 0.5.8", "tokio", "tower-service", "tracing", @@ -1053,6 +1053,17 @@ dependencies = [ "hashbrown 0.15.2", ] +[[package]] +name = "io-uring" +version = "0.7.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d93587f37623a1a17d94ef2bc9ada592f5465fe7732084ab7beefabe5c77c0c4" +dependencies = [ + "bitflags", + "cfg-if", + "libc", +] + [[package]] name = "is_terminal_polyfill" version = "1.70.1" @@ -1095,9 +1106,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.169" +version = "0.2.175" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" +checksum = "6a82ae493e598baaea5209805c49bbf2ea7de956d50d7da0da1164f9c6d28543" [[package]] name = "linux-raw-sys" @@ -2054,6 +2065,16 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "socket2" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "233504af464074f9d066d7b5416c5f9b894a5862a6506e306f7b816cdd6f1807" +dependencies = [ + "libc", + "windows-sys 0.59.0", +] + [[package]] name = "spin" version = "0.9.8" @@ -2223,20 +2244,22 @@ dependencies = [ [[package]] name = "tokio" -version = "1.45.1" +version = "1.47.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75ef51a33ef1da925cea3e4eb122833cb377c61439ca401b770f54902b806779" +checksum = "89e49afdadebb872d3145a5638b59eb0691ea23e46ca484037cfab3b76b95038" dependencies = [ "backtrace", "bytes", + "io-uring", "libc", "mio", "parking_lot", "pin-project-lite", "signal-hook-registry", - "socket2", + "slab", + "socket2 0.6.0", "tokio-macros", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -2307,7 +2330,7 @@ dependencies = [ "prost", "rustls-native-certs", "rustls-pemfile", - "socket2", + "socket2 0.5.8", "tokio", "tokio-rustls", "tokio-stream", @@ -2456,7 +2479,7 @@ dependencies = [ [[package]] name = "typedb-driver" version = "0.0.0" -source = "git+https://github.com/typedb/typedb-driver?tag=3.4.4#ca07f77759f7b5ca4044429f112f3866e7115424" +source = "git+https://github.com/typedb/typedb-driver?rev=d2ce9ab4f85f8316a9087c130a20c7b1e731e8c4#d2ce9ab4f85f8316a9087c130a20c7b1e731e8c4" dependencies = [ "chrono", "chrono-tz", @@ -2478,7 +2501,7 @@ dependencies = [ [[package]] name = "typedb-protocol" version = "0.0.0" -source = "git+https://github.com/typedb/typedb-protocol?tag=3.4.0#3fc4c0fe0ac37c517af0e31415347299cff0307c" +source = "git+https://github.com/typedb/typedb-protocol?rev=bac73842bb0f6e4a93ae42d3421f474c75f9be1b#bac73842bb0f6e4a93ae42d3421f474c75f9be1b" dependencies = [ "prost", "tonic", @@ -2603,13 +2626,15 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "uuid" -version = "1.16.0" +version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "458f7a779bf54acc9f347480ac654f68407d3aab21269a6e3c9f922acd9e2da9" +checksum = "f33196643e165781c20a5ead5582283a7dacbb87855d867fbc2df3f81eddc1be" dependencies = [ "getrandom 0.3.1", + "js-sys", "rand 0.9.0", "serde", + "wasm-bindgen", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index f9cbf13..bf64cf8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,7 +20,7 @@ features = {} [dependencies.tokio] features = ["bytes", "default", "fs", "full", "io-std", "io-util", "libc", "macros", "mio", "net", "parking_lot", "process", "rt", "rt-multi-thread", "signal", "signal-hook-registry", "socket2", "sync", "time", "tokio-macros"] - version = "1.45.0" + version = "1.46.0" default-features = false [dependencies.rustyline] @@ -30,7 +30,7 @@ features = {} [dependencies.clap] features = ["color", "default", "derive", "error-context", "help", "std", "suggestions", "usage", "wrap_help"] - version = "4.5.38" + version = "4.5.40" default-features = false [dependencies.glob] diff --git a/tool/runner/Cargo.toml b/tool/runner/Cargo.toml index a7ab45f..193b708 100644 --- a/tool/runner/Cargo.toml +++ b/tool/runner/Cargo.toml @@ -16,7 +16,7 @@ features = {} [dependencies.clap] features = ["color", "default", "derive", "error-context", "help", "std", "suggestions", "usage", "wrap_help"] - version = "4.5.38" + version = "4.5.40" default-features = false [dependencies.tempdir]