diff --git a/apps/cli/Cargo.lock b/apps/cli/Cargo.lock index d79688a3..d1217387 100644 --- a/apps/cli/Cargo.lock +++ b/apps/cli/Cargo.lock @@ -84,9 +84,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.102" +version = "1.0.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" +checksum = "330a5ed07fa54e4702c9d6c4174f74427fc0ef6e214bbd677ae50a5099946470" [[package]] name = "arrayref" diff --git a/apps/cli/README.md b/apps/cli/README.md index 6381668a..1339305e 100644 --- a/apps/cli/README.md +++ b/apps/cli/README.md @@ -24,9 +24,16 @@ npx @onequery/cli --help onequery auth login onequery org use onequery source list +onequery source update sentry:// --input credentials-patch.json +onequery source delete sentry:// --yes onequery query exec --source postgres:// --sql "SELECT * FROM users LIMIT 10" ``` +Source updates accept a partial credential document such as +`{"credentials":{"organizationSlug":"wordbricks"}}`. OneQuery retains omitted +secrets, validates and tests the merged credentials, and persists them only when +the connection test succeeds. Source deletion requires `--yes`. + ## Profiles OneQuery stores the default CLI auth session and config in `~/.onequery/auth.json` diff --git a/apps/cli/crates/onequery-cli/src/cli/args.rs b/apps/cli/crates/onequery-cli/src/cli/args.rs index c62bcd4f..c14e0d18 100644 --- a/apps/cli/crates/onequery-cli/src/cli/args.rs +++ b/apps/cli/crates/onequery-cli/src/cli/args.rs @@ -179,6 +179,30 @@ pub(crate) enum SourceSubcommand { }, /// Show instructions or create a new source connection. Connect(SourceConnectArgs), + /// Update one source's credentials from a JSON patch. + Update(SourceUpdateArgs), + /// Permanently delete one source. + Delete(SourceDeleteArgs), +} + +#[derive(Debug, Clone, Args, Eq, PartialEq)] +pub(crate) struct SourceUpdateArgs { + /// Read {"credentials": {...}} from this file or stdin (`-`). + #[arg(long, value_hint = ValueHint::FilePath, value_name = "PATH|-")] + pub input: PathBuf, + /// Update this source. + #[arg(value_name = "SOURCE", value_parser = parse_source_reference)] + pub source: SourceReference, +} + +#[derive(Debug, Clone, Args, Eq, PartialEq)] +pub(crate) struct SourceDeleteArgs { + /// Delete this source. + #[arg(value_name = "SOURCE", value_parser = parse_source_reference)] + pub source: SourceReference, + /// Confirm permanent deletion. + #[arg(long)] + pub yes: bool, } #[derive(Debug, Clone, Args, Eq, PartialEq)] diff --git a/apps/cli/crates/onequery-cli/src/cli/mod.rs b/apps/cli/crates/onequery-cli/src/cli/mod.rs index 1a62e8e7..bf56eef7 100644 --- a/apps/cli/crates/onequery-cli/src/cli/mod.rs +++ b/apps/cli/crates/onequery-cli/src/cli/mod.rs @@ -31,7 +31,9 @@ pub(crate) use args::QueryValidateArgs; pub(crate) use args::ReadArgs; pub(crate) use args::RestoreArgs; pub(crate) use args::SourceConnectArgs; +pub(crate) use args::SourceDeleteArgs; pub(crate) use args::SourceSubcommand; +pub(crate) use args::SourceUpdateArgs; pub(crate) use args::UpgradeArgs; pub(crate) use model::Command; pub(crate) use model::ConfigCommand; diff --git a/apps/cli/crates/onequery-cli/src/cli/model.rs b/apps/cli/crates/onequery-cli/src/cli/model.rs index ca1078f9..d01cd6de 100644 --- a/apps/cli/crates/onequery-cli/src/cli/model.rs +++ b/apps/cli/crates/onequery-cli/src/cli/model.rs @@ -275,6 +275,8 @@ impl Command { Self::Source(SourceSubcommand::Show { .. }) => "source show", Self::Source(SourceSubcommand::Test { .. }) => "source test", Self::Source(SourceSubcommand::Connect(_)) => "source connect", + Self::Source(SourceSubcommand::Update(_)) => "source update", + Self::Source(SourceSubcommand::Delete(_)) => "source delete", Self::Query(QuerySubcommand::Execute(_)) => "query exec", Self::Query(QuerySubcommand::Validate(_)) => "query validate", Self::Restore(_) => "restore", diff --git a/apps/cli/crates/onequery-cli/src/cli_tests.rs b/apps/cli/crates/onequery-cli/src/cli_tests.rs index d250542f..cd1b16b4 100644 --- a/apps/cli/crates/onequery-cli/src/cli_tests.rs +++ b/apps/cli/crates/onequery-cli/src/cli_tests.rs @@ -965,6 +965,41 @@ fn parse_invocation_accepts_source_test_reference() { )); } +#[test] +fn parse_invocation_accepts_source_update_input() { + let invocation = parse_invocation(&[ + "onequery", + "source", + "update", + "sentry://errors", + "--input", + "patch.json", + ]); + + assert!(matches!( + invocation.command, + Command::Source(super::SourceSubcommand::Update(super::SourceUpdateArgs { + source, + input, + })) if source == test_source_reference("sentry://errors") + && input == *"patch.json" + )); +} + +#[test] +fn parse_invocation_accepts_confirmed_source_delete() { + let invocation = + parse_invocation(&["onequery", "source", "delete", "sentry://errors", "--yes"]); + + assert!(matches!( + invocation.command, + Command::Source(super::SourceSubcommand::Delete(super::SourceDeleteArgs { + source, + yes: true, + })) if source == test_source_reference("sentry://errors") + )); +} + #[test] fn parse_invocation_accepts_query_result_window_args() { let invocation = parse_invocation(&[ diff --git a/apps/cli/crates/onequery-cli/src/commands/mod.rs b/apps/cli/crates/onequery-cli/src/commands/mod.rs index bba6bc7d..9bec3b80 100644 --- a/apps/cli/crates/onequery-cli/src/commands/mod.rs +++ b/apps/cli/crates/onequery-cli/src/commands/mod.rs @@ -11,6 +11,7 @@ mod restore; mod source; mod source_api; mod source_connect; +mod source_mutation; mod source_providers; #[cfg(test)] pub(crate) mod test_support; diff --git a/apps/cli/crates/onequery-cli/src/commands/source.rs b/apps/cli/crates/onequery-cli/src/commands/source.rs index 18615ce4..de9a6b93 100644 --- a/apps/cli/crates/onequery-cli/src/commands/source.rs +++ b/apps/cli/crates/onequery-cli/src/commands/source.rs @@ -139,6 +139,14 @@ pub(super) async fn execute( return super::source_connect::execute(args, context, runtime).await; } + if let SourceSubcommand::Update(args) = command { + return super::source_mutation::execute_update(args, context, runtime).await; + } + + if let SourceSubcommand::Delete(args) = command { + return super::source_mutation::execute_delete(args, context, runtime).await; + } + let mode = match command { SourceSubcommand::List { read } => SourceMode::List { read: read.clone() }, SourceSubcommand::Show { source_key, read } => SourceMode::Show { @@ -150,6 +158,8 @@ pub(super) async fn execute( }, SourceSubcommand::Providers => unreachable!("source providers is delegated"), SourceSubcommand::Connect(_) => unreachable!("source connect is delegated"), + SourceSubcommand::Update(_) => unreachable!("source update is delegated"), + SourceSubcommand::Delete(_) => unreachable!("source delete is delegated"), }; let final_state = run_reducer_workflow( diff --git a/apps/cli/crates/onequery-cli/src/commands/source_mutation.rs b/apps/cli/crates/onequery-cli/src/commands/source_mutation.rs new file mode 100644 index 00000000..9c45af93 --- /dev/null +++ b/apps/cli/crates/onequery-cli/src/commands/source_mutation.rs @@ -0,0 +1,254 @@ +use std::io::IsTerminal; +use std::path::Path; + +use onequery_core::error::CliError; +use onequery_core::error::ErrorStage; +use tokio::fs; +use tokio::io::AsyncReadExt; + +use crate::cli::SourceDeleteArgs; +use crate::cli::SourceUpdateArgs; +use crate::output::CommandOutput; +use crate::output::serialize_command_data; +use crate::presentation::api_failure::ApiErrorPresentation; +use crate::presentation::api_failure::present_api_failure_with_context; +use crate::recovery::auth_login_then_retry_try_next; +use crate::recovery::auth_login_try_next; +use crate::transport::source::SourceTestOutcome; +use crate::transport::source::SourceTestSupportedResult; +use crate::transport::source_mutation; +use crate::transport::source_mutation::SourceDeletePayload; +use crate::transport::source_mutation::SourceUpdatePayload; +use crate::transport::source_mutation::SourceUpdateRequestPayload; + +use super::CommandContext; +use super::Runtime; +use super::auth_session::authenticated_api_client; +use super::auth_session::ensure_authenticated_org; + +pub(super) async fn execute_update( + args: &SourceUpdateArgs, + context: &CommandContext, + runtime: &mut Runtime, +) -> Result { + let request = read_update_request(args.input.as_path(), context).await?; + let org = ensure_authenticated_org(context, runtime).await?; + let client = authenticated_api_client(context, runtime)?; + let response = + source_mutation::update_source(&client, org.as_str(), args.source.as_str(), &request) + .await + .map_err(|failure| { + present_source_mutation_failure(failure, context, "source update failed") + })?; + + render_update_output(response.payload).map(|output| { + output + .with_command("source update") + .with_request_id(response.request_id) + }) +} + +pub(super) async fn execute_delete( + args: &SourceDeleteArgs, + context: &CommandContext, + runtime: &mut Runtime, +) -> Result { + if !args.yes { + return Err(CliError::new( + "source deletion requires confirmation", + context.command_line.clone(), + ErrorStage::ParseCommand, + format!( + "{} will be permanently deleted; pass --yes to confirm", + args.source + ), + vec![format!("onequery source delete {} --yes", args.source)], + )); + } + + let org = ensure_authenticated_org(context, runtime).await?; + let client = authenticated_api_client(context, runtime)?; + let response = source_mutation::delete_source(&client, org.as_str(), args.source.as_str()) + .await + .map_err(|failure| { + present_source_mutation_failure(failure, context, "source delete failed") + })?; + + render_delete_output(response.payload).map(|output| { + output + .with_command("source delete") + .with_request_id(response.request_id) + }) +} + +async fn read_update_request( + input_path: &Path, + context: &CommandContext, +) -> Result { + let raw = if input_path.as_os_str() == "-" { + if std::io::stdin().is_terminal() { + return Err(update_input_error( + context, + "no piped stdin input detected. --input - requires one UTF-8 JSON payload from stdin", + )); + } + + let mut buffer = String::new(); + tokio::io::stdin() + .read_to_string(&mut buffer) + .await + .map_err(|error| update_input_error(context, error.to_string()))?; + buffer + } else { + let metadata = fs::metadata(input_path).await.map_err(|error| { + update_input_error(context, format!("{error} ({})", input_path.display())) + })?; + if !metadata.is_file() { + return Err(update_input_error( + context, + format!("path is not a regular file ({})", input_path.display()), + )); + } + fs::read_to_string(input_path).await.map_err(|error| { + update_input_error(context, format!("{error} ({})", input_path.display())) + })? + }; + + let request = serde_json::from_str::(&raw) + .map_err(|error| update_input_error(context, format!("invalid JSON payload: {error}")))?; + if request.credentials.is_empty() { + return Err(update_input_error( + context, + "credentials must contain at least one field", + )); + } + Ok(request) +} + +fn update_input_error(context: &CommandContext, why: impl Into) -> CliError { + CliError::new( + "invalid source update input", + context.command_line.clone(), + ErrorStage::ReadQueryInput, + why, + vec![ + "create a JSON file such as {\"credentials\":{\"organizationSlug\":\"wordbricks\"}}" + .to_owned(), + "onequery source update sentry://source-key --input patch.json".to_owned(), + "printf '%s' '' | onequery source update sentry://source-key --input -" + .to_owned(), + ], + ) +} + +fn render_update_output(payload: SourceUpdatePayload) -> Result { + let (message, latency) = match &payload.outcome { + SourceTestOutcome::Supported { result, latency_ms } => { + let message = match result { + SourceTestSupportedResult::Passed { message } + | SourceTestSupportedResult::Failed { message, .. } => message.clone(), + }; + let latency = latency_ms.map_or_else(|| "-".to_owned(), |value| format!("{value} ms")); + (message, latency) + } + SourceTestOutcome::Unsupported { message, .. } => (message.clone(), "-".to_owned()), + }; + let lines = vec![ + format!("Updated source: {}", payload.source.reference()), + format!("Status: {}", payload.source.status), + format!("Connection test: {message}"), + format!("Test latency: {latency}"), + ]; + + Ok(CommandOutput::try_deferred(lines, move || { + serialize_command_data(&payload, "onequery source update") + })) +} + +fn render_delete_output(payload: SourceDeletePayload) -> Result { + let lines = vec![ + format!("Deleted source: {}", payload.source.reference()), + format!("Provider: {}", payload.source.provider), + ]; + Ok(CommandOutput::try_deferred(lines, move || { + serialize_command_data(&payload, "onequery source delete") + })) +} + +fn present_source_mutation_failure( + failure: crate::transport::api_failure::ApiFailure, + context: &CommandContext, + title: &'static str, +) -> CliError { + present_api_failure_with_context( + failure, + context, + ApiErrorPresentation { + command: &context.command_line, + title, + transport_why_prefix: "failed to reach source mutation endpoint", + decode_why_prefix: "failed to decode source mutation response", + fallback_try_next: auth_login_then_retry_try_next(&context.command_line), + unauthorized_try_next: Some(auth_login_try_next()), + }, + ) +} + +#[cfg(test)] +mod tests { + use insta::assert_snapshot; + + use crate::transport::source::SourceSummary; + use crate::transport::source::SourceTestOutcome; + use crate::transport::source::SourceTestSupportedResult; + use crate::transport::source_mutation::SourceDeletePayload; + use crate::transport::source_mutation::SourceUpdatePayload; + + use super::render_delete_output; + use super::render_update_output; + + fn source() -> SourceSummary { + SourceSummary { + source_key: "getgpt-sentry".to_owned(), + display_name: None, + provider: "sentry".to_owned(), + status: "active".to_owned(), + interfaces: vec!["api".to_owned()], + } + } + + #[test] + fn render_update_output_reports_connection_test() { + let output = render_update_output(SourceUpdatePayload { + source: source(), + outcome: SourceTestOutcome::Supported { + result: SourceTestSupportedResult::Passed { + message: "Connected to Sentry".to_owned(), + }, + latency_ms: Some(42), + }, + }) + .expect("update output should render"); + + assert_snapshot!(output.lines.join("\n"), @r###" + Updated source: sentry://getgpt-sentry + Status: active + Connection test: Connected to Sentry + Test latency: 42 ms + "###); + } + + #[test] + fn render_delete_output_identifies_deleted_source() { + let output = render_delete_output(SourceDeletePayload { + source: source(), + deleted: true, + }) + .expect("delete output should render"); + + assert_snapshot!(output.lines.join("\n"), @r###" + Deleted source: sentry://getgpt-sentry + Provider: sentry + "###); + } +} diff --git a/apps/cli/crates/onequery-cli/src/transport/mod.rs b/apps/cli/crates/onequery-cli/src/transport/mod.rs index bc841246..e42dbc5d 100644 --- a/apps/cli/crates/onequery-cli/src/transport/mod.rs +++ b/apps/cli/crates/onequery-cli/src/transport/mod.rs @@ -11,4 +11,5 @@ pub(crate) mod source; pub(crate) mod source_api; pub(crate) mod source_connect; pub(crate) mod source_connect_provider; +pub(crate) mod source_mutation; pub(crate) mod well_known; diff --git a/apps/cli/crates/onequery-cli/src/transport/org.rs b/apps/cli/crates/onequery-cli/src/transport/org.rs index 92783b21..63d3fab9 100644 --- a/apps/cli/crates/onequery-cli/src/transport/org.rs +++ b/apps/cli/crates/onequery-cli/src/transport/org.rs @@ -208,6 +208,7 @@ fn org_capability_from_generated( } Some(types::OrgCapability::ORG_CAPABILITY_SOURCE_LIST) => Ok("source.list".to_owned()), Some(types::OrgCapability::ORG_CAPABILITY_SOURCE_READ) => Ok("source.read".to_owned()), + Some(types::OrgCapability::ORG_CAPABILITY_SOURCE_WRITE) => Ok("source.write".to_owned()), Some(types::OrgCapability::ORG_CAPABILITY_QUERY_EXECUTE) => Ok("query.execute".to_owned()), Some(types::OrgCapability::ORG_CAPABILITY_SOURCE_API_DESCRIBE) => { Ok("source_api.describe".to_owned()) @@ -270,6 +271,7 @@ mod tests { types::OrgCapability::ORG_CAPABILITY_SOURCE_API_DESCRIBE.into(), types::OrgCapability::ORG_CAPABILITY_SOURCE_API_EXECUTE.into(), types::OrgCapability::ORG_CAPABILITY_ORG_READ.into(), + types::OrgCapability::ORG_CAPABILITY_SOURCE_WRITE.into(), ], ..Default::default() }, @@ -288,6 +290,7 @@ mod tests { "source_api.describe".to_owned(), "source_api.execute".to_owned(), "org.read".to_owned(), + "source.write".to_owned(), ]), } ); diff --git a/apps/cli/crates/onequery-cli/src/transport/source.rs b/apps/cli/crates/onequery-cli/src/transport/source.rs index f318fd68..5aba015c 100644 --- a/apps/cli/crates/onequery-cli/src/transport/source.rs +++ b/apps/cli/crates/onequery-cli/src/transport/source.rs @@ -406,7 +406,7 @@ pub(crate) async fn test_source( }) } -fn decode_required_source_summary( +pub(crate) fn decode_required_source_summary( summary: Option, stage: ErrorStage, message: &str, diff --git a/apps/cli/crates/onequery-cli/src/transport/source_mutation.rs b/apps/cli/crates/onequery-cli/src/transport/source_mutation.rs new file mode 100644 index 00000000..e461b81a --- /dev/null +++ b/apps/cli/crates/onequery-cli/src/transport/source_mutation.rs @@ -0,0 +1,215 @@ +use buffa::MessageField; +use onequery_core::error::ErrorStage; +use serde::Deserialize; +use serde::Serialize; +use serde_json::Map; +use serde_json::Value; + +use crate::transport::api_failure::ApiFailure; +use crate::transport::api_failure::ApiSuccess; +use crate::transport::api_failure::conversion_failure; +use crate::transport::api_failure::decode_failure; +use crate::transport::api_failure::failure_from_connect; +use crate::transport::api_failure::success_response_request_id; +use crate::transport::api_failure::try_into_value; +use crate::transport::client::AuthenticatedApiClient; +use crate::transport::generated::types; +use crate::transport::response_decode::require_non_empty_text; +use crate::transport::source::SourceSummary; +use crate::transport::source::SourceTestOutcome; +use crate::transport::source::SourceTestSupportedResult; +use crate::transport::source::decode_required_source_summary; +use crate::transport::source::source_selector_from_reference; +use crate::transport::well_known::required_duration_ms; + +#[derive(Debug, Clone, Deserialize, Serialize, Eq, PartialEq)] +#[serde(rename_all = "camelCase", deny_unknown_fields)] +pub(crate) struct SourceUpdatePayload { + pub(crate) source: SourceSummary, + pub(crate) outcome: SourceTestOutcome, +} + +#[derive(Debug, Clone, Deserialize, Serialize, Eq, PartialEq)] +#[serde(rename_all = "camelCase", deny_unknown_fields)] +pub(crate) struct SourceDeletePayload { + pub(crate) source: SourceSummary, + pub(crate) deleted: bool, +} + +#[derive(Debug, Clone, Deserialize, Serialize, PartialEq)] +#[serde(deny_unknown_fields)] +pub(crate) struct SourceUpdateRequestPayload { + pub(crate) credentials: Map, +} + +pub(crate) async fn update_source( + client: &AuthenticatedApiClient, + org: &str, + source: &str, + request: &SourceUpdateRequestPayload, +) -> Result, ApiFailure> { + let stage = ErrorStage::ResolveSource; + let credentials = serde_json::from_value::( + Value::Object(request.credentials.clone()), + ) + .map_err(|error| conversion_failure(stage, error.to_string()))?; + let response = client + .source() + .update_source(types::UpdateSourceRequest { + org_slug: Some(try_into_value(org, stage)?), + source: MessageField::some(source_selector_from_reference(source, stage)?), + credentials: MessageField::some(credentials), + ..Default::default() + }) + .await + .map_err(|error| failure_from_connect(error, stage))?; + let request_id = success_response_request_id(&response); + let payload = response.into_owned(); + let outcome = payload.outcome.ok_or_else(|| { + decode_failure( + stage, + "source update response missing test outcome", + request_id.clone(), + ) + })?; + let outcome = match outcome { + types::update_source_response::Outcome::Supported(supported) => { + decode_supported_test_outcome(*supported, request_id.clone())? + } + types::update_source_response::Outcome::Unsupported(unsupported) => { + decode_unsupported_test_outcome(*unsupported, request_id.clone())? + } + }; + + Ok(ApiSuccess { + payload: SourceUpdatePayload { + source: decode_required_source_summary( + payload.source.into_option(), + stage, + "source update response missing source", + request_id.clone(), + )?, + outcome, + }, + request_id, + }) +} + +pub(crate) async fn delete_source( + client: &AuthenticatedApiClient, + org: &str, + source: &str, +) -> Result, ApiFailure> { + let stage = ErrorStage::ResolveSource; + let response = client + .source() + .delete_source(types::DeleteSourceRequest { + org_slug: Some(try_into_value(org, stage)?), + source: MessageField::some(source_selector_from_reference(source, stage)?), + ..Default::default() + }) + .await + .map_err(|error| failure_from_connect(error, stage))?; + let request_id = success_response_request_id(&response); + let payload = response.into_owned(); + if payload.deleted != Some(true) { + return Err(decode_failure( + stage, + "source delete response did not confirm deletion", + request_id, + )); + } + + Ok(ApiSuccess { + payload: SourceDeletePayload { + source: decode_required_source_summary( + payload.source.into_option(), + stage, + "source delete response missing source", + request_id.clone(), + )?, + deleted: true, + }, + request_id, + }) +} + +fn decode_supported_test_outcome( + supported: types::TestSourceSupportedOutcome, + request_id: Option, +) -> Result { + let latency_ms = required_duration_ms( + supported.latency, + ErrorStage::ResolveSource, + "source update test response missing latency", + request_id.clone(), + )?; + let result = supported.result.ok_or_else(|| { + decode_failure( + ErrorStage::ResolveSource, + "source update test response missing result", + request_id.clone(), + ) + })?; + let result = match result { + types::test_source_supported_outcome::Result::Passed(passed) => { + SourceTestSupportedResult::Passed { + message: require_non_empty_text( + passed.message, + ErrorStage::ResolveSource, + "source update test response missing message", + request_id, + )?, + } + } + types::test_source_supported_outcome::Result::Failed(failed) => { + SourceTestSupportedResult::Failed { + message: require_non_empty_text( + failed.message, + ErrorStage::ResolveSource, + "source update test response missing message", + request_id.clone(), + )?, + error: require_non_empty_text( + failed.error, + ErrorStage::ResolveSource, + "source update test response missing error", + request_id, + )?, + } + } + }; + Ok(SourceTestOutcome::Supported { + result, + latency_ms: Some(latency_ms), + }) +} + +fn decode_unsupported_test_outcome( + unsupported: types::TestSourceUnsupportedOutcome, + request_id: Option, +) -> Result { + let reason = match unsupported.reason.and_then(|value| value.as_known()) { + Some(types::SourceTestUnsupportedReason::SOURCE_TEST_UNSUPPORTED_REASON_OAUTH) => "oauth", + Some( + types::SourceTestUnsupportedReason::SOURCE_TEST_UNSUPPORTED_REASON_NOT_IMPLEMENTED, + ) => "not_implemented", + Some(types::SourceTestUnsupportedReason::SOURCE_TEST_UNSUPPORTED_REASON_UNSPECIFIED) + | None => { + return Err(decode_failure( + ErrorStage::ResolveSource, + "source update test response has invalid unsupported reason", + request_id, + )); + } + }; + Ok(SourceTestOutcome::Unsupported { + message: require_non_empty_text( + unsupported.message, + ErrorStage::ResolveSource, + "source update test response missing message", + request_id, + )?, + reason: reason.to_owned(), + }) +} diff --git a/apps/cli/crates/proto-cli/src/generated/connect/onequery.cli.v1.cli.__connect.rs b/apps/cli/crates/proto-cli/src/generated/connect/onequery.cli.v1.cli.__connect.rs index d0734e92..fbaa3c3e 100644 --- a/apps/cli/crates/proto-cli/src/generated/connect/onequery.cli.v1.cli.__connect.rs +++ b/apps/cli/crates/proto-cli/src/generated/connect/onequery.cli.v1.cli.__connect.rs @@ -112,6 +112,22 @@ pub type OwnedTestSourceRequestView = ::buffa::view::OwnedView< pub type OwnedTestSourceResponseView = ::buffa::view::OwnedView< crate::proto::onequery::cli::v1::__buffa::view::TestSourceResponseView<'static>, >; +///Shorthand for `OwnedView>`. +pub type OwnedUpdateSourceRequestView = ::buffa::view::OwnedView< + crate::proto::onequery::cli::v1::__buffa::view::UpdateSourceRequestView<'static>, +>; +///Shorthand for `OwnedView>`. +pub type OwnedUpdateSourceResponseView = ::buffa::view::OwnedView< + crate::proto::onequery::cli::v1::__buffa::view::UpdateSourceResponseView<'static>, +>; +///Shorthand for `OwnedView>`. +pub type OwnedDeleteSourceRequestView = ::buffa::view::OwnedView< + crate::proto::onequery::cli::v1::__buffa::view::DeleteSourceRequestView<'static>, +>; +///Shorthand for `OwnedView>`. +pub type OwnedDeleteSourceResponseView = ::buffa::view::OwnedView< + crate::proto::onequery::cli::v1::__buffa::view::DeleteSourceResponseView<'static>, +>; ///Shorthand for `OwnedView>`. pub type OwnedDescribeSourceApiRequestView = ::buffa::view::OwnedView< crate::proto::onequery::cli::v1::__buffa::view::DescribeSourceApiRequestView<'static>, @@ -434,6 +450,46 @@ for ::buffa::view::OwnedView< ::connectrpc::__codegen::encode_view_body(&**self, codec) } } +impl ::connectrpc::Encodable +for crate::proto::onequery::cli::v1::__buffa::view::UpdateSourceResponseView<'_> { + fn encode( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::buffa::bytes::Bytes, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body(self, codec) + } +} +impl ::connectrpc::Encodable +for ::buffa::view::OwnedView< + crate::proto::onequery::cli::v1::__buffa::view::UpdateSourceResponseView<'static>, +> { + fn encode( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::buffa::bytes::Bytes, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body(&**self, codec) + } +} +impl ::connectrpc::Encodable +for crate::proto::onequery::cli::v1::__buffa::view::DeleteSourceResponseView<'_> { + fn encode( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::buffa::bytes::Bytes, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body(self, codec) + } +} +impl ::connectrpc::Encodable +for ::buffa::view::OwnedView< + crate::proto::onequery::cli::v1::__buffa::view::DeleteSourceResponseView<'static>, +> { + fn encode( + &self, + codec: ::connectrpc::CodecFormat, + ) -> ::std::result::Result<::buffa::bytes::Bytes, ::connectrpc::ConnectError> { + ::connectrpc::__codegen::encode_view_body(&**self, codec) + } +} impl ::connectrpc::Encodable for crate::proto::onequery::cli::v1::__buffa::view::DescribeSourceApiResponseView<'_> { fn encode( @@ -1745,6 +1801,24 @@ pub const CLI_SOURCE_SERVICE_TEST_SOURCE_SPEC: ::connectrpc::Spec = ::connectrpc ::connectrpc::StreamType::Unary, ) .with_idempotency_level(::connectrpc::IdempotencyLevel::Unknown); +/// Static [`Spec`](::connectrpc::Spec) for the server-side `UpdateSource` RPC. +/// +/// The dispatcher surfaces this on +/// [`RequestContext::spec`](::connectrpc::RequestContext::spec). +pub const CLI_SOURCE_SERVICE_UPDATE_SOURCE_SPEC: ::connectrpc::Spec = ::connectrpc::Spec::server( + "/onequery.cli.v1.CliSourceService/UpdateSource", + ::connectrpc::StreamType::Unary, + ) + .with_idempotency_level(::connectrpc::IdempotencyLevel::Unknown); +/// Static [`Spec`](::connectrpc::Spec) for the server-side `DeleteSource` RPC. +/// +/// The dispatcher surfaces this on +/// [`RequestContext::spec`](::connectrpc::RequestContext::spec). +pub const CLI_SOURCE_SERVICE_DELETE_SOURCE_SPEC: ::connectrpc::Spec = ::connectrpc::Spec::server( + "/onequery.cli.v1.CliSourceService/DeleteSource", + ::connectrpc::StreamType::Unary, + ) + .with_idempotency_level(::connectrpc::IdempotencyLevel::Unknown); /// Server trait for CliSourceService. /// /// # Implementing handlers @@ -1866,6 +1940,34 @@ pub trait CliSourceService: Send + Sync + 'static { > + Send + use<'a, Self>, >, > + Send; + /// Handle the UpdateSource RPC. + /// + /// `'a` lets the response body borrow from `&self` (e.g. server-resident state). + fn update_source<'a>( + &'a self, + ctx: ::connectrpc::RequestContext, + request: OwnedUpdateSourceRequestView, + ) -> impl ::std::future::Future< + Output = ::connectrpc::ServiceResult< + impl ::connectrpc::Encodable< + crate::proto::onequery::cli::v1::UpdateSourceResponse, + > + Send + use<'a, Self>, + >, + > + Send; + /// Handle the DeleteSource RPC. + /// + /// `'a` lets the response body borrow from `&self` (e.g. server-resident state). + fn delete_source<'a>( + &'a self, + ctx: ::connectrpc::RequestContext, + request: OwnedDeleteSourceRequestView, + ) -> impl ::std::future::Future< + Output = ::connectrpc::ServiceResult< + impl ::connectrpc::Encodable< + crate::proto::onequery::cli::v1::DeleteSourceResponse, + > + Send + use<'a, Self>, + >, + > + Send; } /// Extension trait for registering a service implementation with a Router. /// @@ -2003,6 +2105,42 @@ impl CliSourceServiceExt for S { }, ) .with_spec(CLI_SOURCE_SERVICE_TEST_SOURCE_SPEC) + .route_view( + CLI_SOURCE_SERVICE_SERVICE_NAME, + "UpdateSource", + { + let svc = ::std::sync::Arc::clone(&self); + ::connectrpc::view_handler_fn(move |ctx, req, format| { + let svc = ::std::sync::Arc::clone(&svc); + async move { + svc.update_source(ctx, req) + .await? + .encode::< + crate::proto::onequery::cli::v1::UpdateSourceResponse, + >(format) + } + }) + }, + ) + .with_spec(CLI_SOURCE_SERVICE_UPDATE_SOURCE_SPEC) + .route_view( + CLI_SOURCE_SERVICE_SERVICE_NAME, + "DeleteSource", + { + let svc = ::std::sync::Arc::clone(&self); + ::connectrpc::view_handler_fn(move |ctx, req, format| { + let svc = ::std::sync::Arc::clone(&svc); + async move { + svc.delete_source(ctx, req) + .await? + .encode::< + crate::proto::onequery::cli::v1::DeleteSourceResponse, + >(format) + } + }) + }, + ) + .with_spec(CLI_SOURCE_SERVICE_DELETE_SOURCE_SPEC) } } /// Monomorphic dispatcher for `CliSourceService`. @@ -2084,6 +2222,18 @@ impl ::connectrpc::Dispatcher for CliSourceServiceServer .with_spec(CLI_SOURCE_SERVICE_TEST_SOURCE_SPEC), ) } + "UpdateSource" => { + Some( + ::connectrpc::dispatcher::codegen::MethodDescriptor::unary(false) + .with_spec(CLI_SOURCE_SERVICE_UPDATE_SOURCE_SPEC), + ) + } + "DeleteSource" => { + Some( + ::connectrpc::dispatcher::codegen::MethodDescriptor::unary(false) + .with_spec(CLI_SOURCE_SERVICE_DELETE_SOURCE_SPEC), + ) + } _ => None, } } @@ -2177,6 +2327,32 @@ impl ::connectrpc::Dispatcher for CliSourceServiceServer >(format) }) } + "UpdateSource" => { + let svc = ::std::sync::Arc::clone(&self.inner); + Box::pin(async move { + let req = ::connectrpc::dispatcher::codegen::decode_request_view::< + crate::proto::onequery::cli::v1::__buffa::view::UpdateSourceRequestView, + >(request.encoded()?, format)?; + svc.update_source(ctx, req) + .await? + .encode::< + crate::proto::onequery::cli::v1::UpdateSourceResponse, + >(format) + }) + } + "DeleteSource" => { + let svc = ::std::sync::Arc::clone(&self.inner); + Box::pin(async move { + let req = ::connectrpc::dispatcher::codegen::decode_request_view::< + crate::proto::onequery::cli::v1::__buffa::view::DeleteSourceRequestView, + >(request.encoded()?, format)?; + svc.delete_source(ctx, req) + .await? + .encode::< + crate::proto::onequery::cli::v1::DeleteSourceResponse, + >(format) + }) + } _ => ::connectrpc::dispatcher::codegen::unimplemented_unary(path), } } @@ -2567,6 +2743,96 @@ where ) .await } + /// Call the UpdateSource RPC. Sends a request to /onequery.cli.v1.CliSourceService/UpdateSource. + pub async fn update_source( + &self, + request: crate::proto::onequery::cli::v1::UpdateSourceRequest, + ) -> Result< + ::connectrpc::client::UnaryResponse< + ::buffa::view::OwnedView< + crate::proto::onequery::cli::v1::__buffa::view::UpdateSourceResponseView< + 'static, + >, + >, + >, + ::connectrpc::ConnectError, + > { + self.update_source_with_options( + request, + ::connectrpc::client::CallOptions::default(), + ) + .await + } + /// Call the UpdateSource RPC with explicit per-call options. Options override [`ClientConfig`](::connectrpc::client::ClientConfig) defaults. + pub async fn update_source_with_options( + &self, + request: crate::proto::onequery::cli::v1::UpdateSourceRequest, + options: ::connectrpc::client::CallOptions, + ) -> Result< + ::connectrpc::client::UnaryResponse< + ::buffa::view::OwnedView< + crate::proto::onequery::cli::v1::__buffa::view::UpdateSourceResponseView< + 'static, + >, + >, + >, + ::connectrpc::ConnectError, + > { + ::connectrpc::client::call_unary( + &self.transport, + &self.config, + CLI_SOURCE_SERVICE_SERVICE_NAME, + "UpdateSource", + request, + options, + ) + .await + } + /// Call the DeleteSource RPC. Sends a request to /onequery.cli.v1.CliSourceService/DeleteSource. + pub async fn delete_source( + &self, + request: crate::proto::onequery::cli::v1::DeleteSourceRequest, + ) -> Result< + ::connectrpc::client::UnaryResponse< + ::buffa::view::OwnedView< + crate::proto::onequery::cli::v1::__buffa::view::DeleteSourceResponseView< + 'static, + >, + >, + >, + ::connectrpc::ConnectError, + > { + self.delete_source_with_options( + request, + ::connectrpc::client::CallOptions::default(), + ) + .await + } + /// Call the DeleteSource RPC with explicit per-call options. Options override [`ClientConfig`](::connectrpc::client::ClientConfig) defaults. + pub async fn delete_source_with_options( + &self, + request: crate::proto::onequery::cli::v1::DeleteSourceRequest, + options: ::connectrpc::client::CallOptions, + ) -> Result< + ::connectrpc::client::UnaryResponse< + ::buffa::view::OwnedView< + crate::proto::onequery::cli::v1::__buffa::view::DeleteSourceResponseView< + 'static, + >, + >, + >, + ::connectrpc::ConnectError, + > { + ::connectrpc::client::call_unary( + &self.transport, + &self.config, + CLI_SOURCE_SERVICE_SERVICE_NAME, + "DeleteSource", + request, + options, + ) + .await + } } /// Full service name for this service. pub const CLI_SOURCE_API_SERVICE_SERVICE_NAME: &str = "onequery.cli.v1.CliSourceApiService"; diff --git a/apps/cli/crates/proto-cli/src/generated/proto/onequery.cli.v1.mod.rs b/apps/cli/crates/proto-cli/src/generated/proto/onequery.cli.v1.mod.rs index ca74f7b0..27b9d8fc 100644 --- a/apps/cli/crates/proto-cli/src/generated/proto/onequery.cli.v1.mod.rs +++ b/apps/cli/crates/proto-cli/src/generated/proto/onequery.cli.v1.mod.rs @@ -116,6 +116,14 @@ pub use self::__buffa::view::TestSourceRequestView; #[doc(inline)] pub use self::__buffa::view::TestSourceResponseView; #[doc(inline)] +pub use self::__buffa::view::UpdateSourceRequestView; +#[doc(inline)] +pub use self::__buffa::view::UpdateSourceResponseView; +#[doc(inline)] +pub use self::__buffa::view::DeleteSourceRequestView; +#[doc(inline)] +pub use self::__buffa::view::DeleteSourceResponseView; +#[doc(inline)] pub use self::__buffa::view::TestSourceSupportedOutcomeView; #[doc(inline)] pub use self::__buffa::view::TestSourcePassedOutcomeView; diff --git a/apps/cli/crates/proto-cli/src/generated/proto/onequery.cli.v1.org.rs b/apps/cli/crates/proto-cli/src/generated/proto/onequery.cli.v1.org.rs index 2923f4ed..b8a9686a 100644 --- a/apps/cli/crates/proto-cli/src/generated/proto/onequery.cli.v1.org.rs +++ b/apps/cli/crates/proto-cli/src/generated/proto/onequery.cli.v1.org.rs @@ -13,6 +13,7 @@ pub enum OrgCapability { ORG_CAPABILITY_QUERY_EXECUTE = 6i32, ORG_CAPABILITY_SOURCE_API_DESCRIBE = 7i32, ORG_CAPABILITY_SOURCE_API_EXECUTE = 8i32, + ORG_CAPABILITY_SOURCE_WRITE = 9i32, } impl ::core::default::Default for OrgCapability { fn default() -> Self { @@ -119,6 +120,7 @@ impl ::buffa::Enumeration for OrgCapability { ::core::option::Option::Some(Self::ORG_CAPABILITY_SOURCE_API_DESCRIBE) } 8i32 => ::core::option::Option::Some(Self::ORG_CAPABILITY_SOURCE_API_EXECUTE), + 9i32 => ::core::option::Option::Some(Self::ORG_CAPABILITY_SOURCE_WRITE), _ => ::core::option::Option::None, } } @@ -140,6 +142,7 @@ impl ::buffa::Enumeration for OrgCapability { Self::ORG_CAPABILITY_SOURCE_API_EXECUTE => { "ORG_CAPABILITY_SOURCE_API_EXECUTE" } + Self::ORG_CAPABILITY_SOURCE_WRITE => "ORG_CAPABILITY_SOURCE_WRITE", } } fn from_proto_name(name: &str) -> ::core::option::Option { @@ -171,6 +174,9 @@ impl ::buffa::Enumeration for OrgCapability { "ORG_CAPABILITY_SOURCE_API_EXECUTE" => { ::core::option::Option::Some(Self::ORG_CAPABILITY_SOURCE_API_EXECUTE) } + "ORG_CAPABILITY_SOURCE_WRITE" => { + ::core::option::Option::Some(Self::ORG_CAPABILITY_SOURCE_WRITE) + } _ => ::core::option::Option::None, } } @@ -185,6 +191,7 @@ impl ::buffa::Enumeration for OrgCapability { Self::ORG_CAPABILITY_QUERY_EXECUTE, Self::ORG_CAPABILITY_SOURCE_API_DESCRIBE, Self::ORG_CAPABILITY_SOURCE_API_EXECUTE, + Self::ORG_CAPABILITY_SOURCE_WRITE, ] } } diff --git a/apps/cli/crates/proto-cli/src/generated/proto/onequery.cli.v1.source.__oneof.rs b/apps/cli/crates/proto-cli/src/generated/proto/onequery.cli.v1.source.__oneof.rs index c0edb2bf..7dce34fb 100644 --- a/apps/cli/crates/proto-cli/src/generated/proto/onequery.cli.v1.source.__oneof.rs +++ b/apps/cli/crates/proto-cli/src/generated/proto/onequery.cli.v1.source.__oneof.rs @@ -55,6 +55,60 @@ pub mod test_source_response { } } } +pub mod update_source_response { + #[allow(unused_imports)] + use super::*; + #[derive(Clone, PartialEq, Debug)] + pub enum Outcome { + Supported( + ::buffa::alloc::boxed::Box, + ), + Unsupported( + ::buffa::alloc::boxed::Box, + ), + } + impl ::buffa::Oneof for Outcome {} + impl From for Outcome { + fn from(v: super::super::super::TestSourceSupportedOutcome) -> Self { + Self::Supported(::buffa::alloc::boxed::Box::new(v)) + } + } + impl From + for ::core::option::Option { + fn from(v: super::super::super::TestSourceSupportedOutcome) -> Self { + Self::Some(Outcome::from(v)) + } + } + impl From for Outcome { + fn from(v: super::super::super::TestSourceUnsupportedOutcome) -> Self { + Self::Unsupported(::buffa::alloc::boxed::Box::new(v)) + } + } + impl From + for ::core::option::Option { + fn from(v: super::super::super::TestSourceUnsupportedOutcome) -> Self { + Self::Some(Outcome::from(v)) + } + } + impl serde::Serialize for Outcome { + fn serialize( + &self, + s: S, + ) -> ::core::result::Result { + use serde::ser::SerializeMap; + let mut map = s.serialize_map(Some(1))?; + match self { + Self::Supported(v) => { + map.serialize_entry("supported", v)?; + } + Self::Unsupported(v) => { + map.serialize_entry("unsupported", v)?; + } + } + map.end() + } + } +} pub mod test_source_supported_outcome { #[allow(unused_imports)] use super::*; diff --git a/apps/cli/crates/proto-cli/src/generated/proto/onequery.cli.v1.source.__view.rs b/apps/cli/crates/proto-cli/src/generated/proto/onequery.cli.v1.source.__view.rs index 03d1614f..cf989639 100644 --- a/apps/cli/crates/proto-cli/src/generated/proto/onequery.cli.v1.source.__view.rs +++ b/apps/cli/crates/proto-cli/src/generated/proto/onequery.cli.v1.source.__view.rs @@ -2848,6 +2848,1124 @@ impl ::buffa::ViewReborrow for TestSourceResponseView<'static> { } } #[derive(Clone, Debug, Default)] +pub struct UpdateSourceRequestView<'a> { + /// Field 1: `org_slug` + pub org_slug: ::core::option::Option<&'a str>, + /// Field 2: `source` + pub source: ::buffa::MessageFieldView< + super::super::__buffa::view::CliSourceSelectorView<'a>, + >, + /// Field 3: `credentials` + pub credentials: ::buffa::MessageFieldView< + ::buffa_types::google::protobuf::__buffa::view::StructView<'a>, + >, + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, +} +impl<'a> UpdateSourceRequestView<'a> { + /// Decode from `buf`, enforcing a recursion depth limit for nested messages. + /// + /// Called by [`::buffa::MessageView::decode_view`] with [`::buffa::RECURSION_LIMIT`] + /// and by generated sub-message decode arms with `depth - 1`. + /// + /// **Not part of the public API.** Named with a leading underscore to + /// signal that it is for generated-code use only. + #[doc(hidden)] + pub fn _decode_depth( + buf: &'a [u8], + depth: u32, + ) -> ::core::result::Result { + let mut view = Self::default(); + view._merge_into_view(buf, depth)?; + ::core::result::Result::Ok(view) + } + /// Merge fields from `buf` into this view (proto merge semantics). + /// + /// Repeated fields append; singular fields last-wins; singular + /// MESSAGE fields merge recursively. Used by sub-message decode + /// arms when the same field appears multiple times on the wire. + /// + /// **Not part of the public API.** + #[doc(hidden)] + pub fn _merge_into_view( + &mut self, + buf: &'a [u8], + depth: u32, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + let _ = depth; + #[allow(unused_variables)] + let view = self; + let mut cur: &'a [u8] = buf; + while !cur.is_empty() { + let before_tag = cur; + let tag = ::buffa::encoding::Tag::decode(&mut cur)?; + match tag.field_number() { + 1u32 => { + if tag.wire_type() != ::buffa::encoding::WireType::LengthDelimited { + return ::core::result::Result::Err(::buffa::DecodeError::WireTypeMismatch { + field_number: 1u32, + expected: 2u8, + actual: tag.wire_type() as u8, + }); + } + view.org_slug = Some(::buffa::types::borrow_str(&mut cur)?); + } + 2u32 => { + if tag.wire_type() != ::buffa::encoding::WireType::LengthDelimited { + return ::core::result::Result::Err(::buffa::DecodeError::WireTypeMismatch { + field_number: 2u32, + expected: 2u8, + actual: tag.wire_type() as u8, + }); + } + if depth == 0 { + return Err(::buffa::DecodeError::RecursionLimitExceeded); + } + let sub = ::buffa::types::borrow_bytes(&mut cur)?; + match view.source.as_mut() { + Some(existing) => existing._merge_into_view(sub, depth - 1)?, + None => { + view.source = ::buffa::MessageFieldView::set( + super::super::__buffa::view::CliSourceSelectorView::_decode_depth( + sub, + depth - 1, + )?, + ); + } + } + } + 3u32 => { + if tag.wire_type() != ::buffa::encoding::WireType::LengthDelimited { + return ::core::result::Result::Err(::buffa::DecodeError::WireTypeMismatch { + field_number: 3u32, + expected: 2u8, + actual: tag.wire_type() as u8, + }); + } + if depth == 0 { + return Err(::buffa::DecodeError::RecursionLimitExceeded); + } + let sub = ::buffa::types::borrow_bytes(&mut cur)?; + match view.credentials.as_mut() { + Some(existing) => existing._merge_into_view(sub, depth - 1)?, + None => { + view.credentials = ::buffa::MessageFieldView::set( + ::buffa_types::google::protobuf::__buffa::view::StructView::_decode_depth( + sub, + depth - 1, + )?, + ); + } + } + } + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, depth)?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields.push_raw(&before_tag[..span_len]); + } + } + } + ::core::result::Result::Ok(()) + } +} +impl<'a> ::buffa::MessageView<'a> for UpdateSourceRequestView<'a> { + type Owned = super::super::UpdateSourceRequest; + fn decode_view(buf: &'a [u8]) -> ::core::result::Result { + Self::_decode_depth(buf, ::buffa::RECURSION_LIMIT) + } + fn decode_view_with_limit( + buf: &'a [u8], + depth: u32, + ) -> ::core::result::Result { + Self::_decode_depth(buf, depth) + } + fn to_owned_message(&self) -> super::super::UpdateSourceRequest { + self.to_owned_from_source(None) + } + #[allow(clippy::useless_conversion, clippy::needless_update)] + fn to_owned_from_source( + &self, + __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, + ) -> super::super::UpdateSourceRequest { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + let _ = __buffa_src; + super::super::UpdateSourceRequest { + org_slug: self.org_slug.map(|s| s.to_string()), + source: match self.source.as_option() { + Some(v) => { + ::buffa::MessageField::< + super::super::CliSourceSelector, + >::some(v.to_owned_from_source(__buffa_src)) + } + None => ::buffa::MessageField::none(), + }, + credentials: match self.credentials.as_option() { + Some(v) => { + ::buffa::MessageField::< + ::buffa_types::google::protobuf::Struct, + >::some(v.to_owned_from_source(__buffa_src)) + } + None => ::buffa::MessageField::none(), + }, + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned() + .unwrap_or_default() + .into(), + ..::core::default::Default::default() + } + } +} +impl<'a> ::buffa::ViewEncode<'a> for UpdateSourceRequestView<'a> { + #[allow(clippy::needless_borrow, clippy::let_and_return)] + fn compute_size(&self, __cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u32; + if let Some(ref v) = self.org_slug { + size += 1u32 + ::buffa::types::string_encoded_len(v) as u32; + } + if self.source.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.source.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u32 + ::buffa::encoding::varint_len(inner_size as u64) as u32 + + inner_size; + } + if self.credentials.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.credentials.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u32 + ::buffa::encoding::varint_len(inner_size as u64) as u32 + + inner_size; + } + size += self.__buffa_unknown_fields.encoded_len() as u32; + size + } + #[allow(clippy::needless_borrow)] + fn write_to( + &self, + __cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::bytes::BufMut, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if let Some(ref v) = self.org_slug { + ::buffa::encoding::Tag::new( + 1u32, + ::buffa::encoding::WireType::LengthDelimited, + ) + .encode(buf); + ::buffa::types::encode_string(v, buf); + } + if self.source.is_set() { + ::buffa::encoding::Tag::new( + 2u32, + ::buffa::encoding::WireType::LengthDelimited, + ) + .encode(buf); + ::buffa::encoding::encode_varint(__cache.consume_next() as u64, buf); + self.source.write_to(__cache, buf); + } + if self.credentials.is_set() { + ::buffa::encoding::Tag::new( + 3u32, + ::buffa::encoding::WireType::LengthDelimited, + ) + .encode(buf); + ::buffa::encoding::encode_varint(__cache.consume_next() as u64, buf); + self.credentials.write_to(__cache, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } +} +/// Serializes this view as protobuf JSON. +/// +/// Implicit-presence fields with default values are omitted, `required` +/// fields are always emitted, explicit-presence (`optional`) fields are +/// emitted only when set, bytes fields are base64-encoded, and enum +/// values are their proto name strings. +/// +/// This impl uses `serialize_map(None)` because the number of emitted +/// fields depends on default-omission rules; serializers that require +/// known map lengths (e.g. `bincode`) will return a runtime error. +/// Use the owned message type for those formats. +impl<'__a> ::serde::Serialize for UpdateSourceRequestView<'__a> { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + use ::serde::ser::SerializeMap as _; + let mut __map = __s.serialize_map(::core::option::Option::None)?; + if let ::core::option::Option::Some(__v) = self.org_slug { + __map.serialize_entry("orgSlug", __v)?; + } + { + if let ::core::option::Option::Some(__v) = self.source.as_option() { + __map.serialize_entry("source", __v)?; + } + } + { + if let ::core::option::Option::Some(__v) = self.credentials.as_option() { + __map.serialize_entry("credentials", __v)?; + } + } + __map.end() + } +} +impl<'a> ::buffa::MessageName for UpdateSourceRequestView<'a> { + const PACKAGE: &'static str = "onequery.cli.v1"; + const NAME: &'static str = "UpdateSourceRequest"; + const FULL_NAME: &'static str = "onequery.cli.v1.UpdateSourceRequest"; + const TYPE_URL: &'static str = "type.googleapis.com/onequery.cli.v1.UpdateSourceRequest"; +} +impl<'v> ::buffa::DefaultViewInstance for UpdateSourceRequestView<'v> { + fn default_view_instance<'a>() -> &'a Self + where + Self: 'a, + { + static VALUE: ::buffa::__private::OnceBox> = ::buffa::__private::OnceBox::new(); + VALUE + .get_or_init(|| ::buffa::alloc::boxed::Box::new( + >::default(), + )) + } +} +impl ::buffa::ViewReborrow for UpdateSourceRequestView<'static> { + type Reborrowed<'b> = UpdateSourceRequestView<'b>; + fn reborrow<'b>(this: &'b Self) -> &'b Self::Reborrowed<'b> { + this + } +} +#[derive(Clone, Debug, Default)] +pub struct UpdateSourceResponseView<'a> { + /// Field 1: `source` + pub source: ::buffa::MessageFieldView< + super::super::__buffa::view::CliSourceView<'a>, + >, + pub outcome: ::core::option::Option< + super::super::__buffa::view::oneof::update_source_response::Outcome<'a>, + >, + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, +} +impl<'a> UpdateSourceResponseView<'a> { + /// Decode from `buf`, enforcing a recursion depth limit for nested messages. + /// + /// Called by [`::buffa::MessageView::decode_view`] with [`::buffa::RECURSION_LIMIT`] + /// and by generated sub-message decode arms with `depth - 1`. + /// + /// **Not part of the public API.** Named with a leading underscore to + /// signal that it is for generated-code use only. + #[doc(hidden)] + pub fn _decode_depth( + buf: &'a [u8], + depth: u32, + ) -> ::core::result::Result { + let mut view = Self::default(); + view._merge_into_view(buf, depth)?; + ::core::result::Result::Ok(view) + } + /// Merge fields from `buf` into this view (proto merge semantics). + /// + /// Repeated fields append; singular fields last-wins; singular + /// MESSAGE fields merge recursively. Used by sub-message decode + /// arms when the same field appears multiple times on the wire. + /// + /// **Not part of the public API.** + #[doc(hidden)] + pub fn _merge_into_view( + &mut self, + buf: &'a [u8], + depth: u32, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + let _ = depth; + #[allow(unused_variables)] + let view = self; + let mut cur: &'a [u8] = buf; + while !cur.is_empty() { + let before_tag = cur; + let tag = ::buffa::encoding::Tag::decode(&mut cur)?; + match tag.field_number() { + 1u32 => { + if tag.wire_type() != ::buffa::encoding::WireType::LengthDelimited { + return ::core::result::Result::Err(::buffa::DecodeError::WireTypeMismatch { + field_number: 1u32, + expected: 2u8, + actual: tag.wire_type() as u8, + }); + } + if depth == 0 { + return Err(::buffa::DecodeError::RecursionLimitExceeded); + } + let sub = ::buffa::types::borrow_bytes(&mut cur)?; + match view.source.as_mut() { + Some(existing) => existing._merge_into_view(sub, depth - 1)?, + None => { + view.source = ::buffa::MessageFieldView::set( + super::super::__buffa::view::CliSourceView::_decode_depth( + sub, + depth - 1, + )?, + ); + } + } + } + 2u32 => { + if tag.wire_type() != ::buffa::encoding::WireType::LengthDelimited { + return ::core::result::Result::Err(::buffa::DecodeError::WireTypeMismatch { + field_number: 2u32, + expected: 2u8, + actual: tag.wire_type() as u8, + }); + } + if depth == 0 { + return Err(::buffa::DecodeError::RecursionLimitExceeded); + } + let sub = ::buffa::types::borrow_bytes(&mut cur)?; + if let Some( + super::super::__buffa::view::oneof::update_source_response::Outcome::Supported( + ref mut existing, + ), + ) = view.outcome + { + existing._merge_into_view(sub, depth - 1)?; + } else { + view.outcome = Some( + super::super::__buffa::view::oneof::update_source_response::Outcome::Supported( + ::buffa::alloc::boxed::Box::new( + super::super::__buffa::view::TestSourceSupportedOutcomeView::_decode_depth( + sub, + depth - 1, + )?, + ), + ), + ); + } + } + 3u32 => { + if tag.wire_type() != ::buffa::encoding::WireType::LengthDelimited { + return ::core::result::Result::Err(::buffa::DecodeError::WireTypeMismatch { + field_number: 3u32, + expected: 2u8, + actual: tag.wire_type() as u8, + }); + } + if depth == 0 { + return Err(::buffa::DecodeError::RecursionLimitExceeded); + } + let sub = ::buffa::types::borrow_bytes(&mut cur)?; + if let Some( + super::super::__buffa::view::oneof::update_source_response::Outcome::Unsupported( + ref mut existing, + ), + ) = view.outcome + { + existing._merge_into_view(sub, depth - 1)?; + } else { + view.outcome = Some( + super::super::__buffa::view::oneof::update_source_response::Outcome::Unsupported( + ::buffa::alloc::boxed::Box::new( + super::super::__buffa::view::TestSourceUnsupportedOutcomeView::_decode_depth( + sub, + depth - 1, + )?, + ), + ), + ); + } + } + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, depth)?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields.push_raw(&before_tag[..span_len]); + } + } + } + ::core::result::Result::Ok(()) + } +} +impl<'a> ::buffa::MessageView<'a> for UpdateSourceResponseView<'a> { + type Owned = super::super::UpdateSourceResponse; + fn decode_view(buf: &'a [u8]) -> ::core::result::Result { + Self::_decode_depth(buf, ::buffa::RECURSION_LIMIT) + } + fn decode_view_with_limit( + buf: &'a [u8], + depth: u32, + ) -> ::core::result::Result { + Self::_decode_depth(buf, depth) + } + fn to_owned_message(&self) -> super::super::UpdateSourceResponse { + self.to_owned_from_source(None) + } + #[allow(clippy::useless_conversion, clippy::needless_update)] + fn to_owned_from_source( + &self, + __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, + ) -> super::super::UpdateSourceResponse { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + let _ = __buffa_src; + super::super::UpdateSourceResponse { + source: match self.source.as_option() { + Some(v) => { + ::buffa::MessageField::< + super::super::CliSource, + >::some(v.to_owned_from_source(__buffa_src)) + } + None => ::buffa::MessageField::none(), + }, + outcome: self + .outcome + .as_ref() + .map(|v| match v { + super::super::__buffa::view::oneof::update_source_response::Outcome::Supported( + v, + ) => { + super::super::__buffa::oneof::update_source_response::Outcome::Supported( + ::buffa::alloc::boxed::Box::new( + v.to_owned_from_source(__buffa_src), + ), + ) + } + super::super::__buffa::view::oneof::update_source_response::Outcome::Unsupported( + v, + ) => { + super::super::__buffa::oneof::update_source_response::Outcome::Unsupported( + ::buffa::alloc::boxed::Box::new( + v.to_owned_from_source(__buffa_src), + ), + ) + } + }), + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned() + .unwrap_or_default() + .into(), + ..::core::default::Default::default() + } + } +} +impl<'a> ::buffa::ViewEncode<'a> for UpdateSourceResponseView<'a> { + #[allow(clippy::needless_borrow, clippy::let_and_return)] + fn compute_size(&self, __cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u32; + if self.source.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.source.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u32 + ::buffa::encoding::varint_len(inner_size as u64) as u32 + + inner_size; + } + if let ::core::option::Option::Some(ref v) = self.outcome { + match v { + super::super::__buffa::view::oneof::update_source_response::Outcome::Supported( + x, + ) => { + let __slot = __cache.reserve(); + let inner = x.compute_size(__cache); + __cache.set(__slot, inner); + size + += 1u32 + ::buffa::encoding::varint_len(inner as u64) as u32 + + inner; + } + super::super::__buffa::view::oneof::update_source_response::Outcome::Unsupported( + x, + ) => { + let __slot = __cache.reserve(); + let inner = x.compute_size(__cache); + __cache.set(__slot, inner); + size + += 1u32 + ::buffa::encoding::varint_len(inner as u64) as u32 + + inner; + } + } + } + size += self.__buffa_unknown_fields.encoded_len() as u32; + size + } + #[allow(clippy::needless_borrow)] + fn write_to( + &self, + __cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::bytes::BufMut, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if self.source.is_set() { + ::buffa::encoding::Tag::new( + 1u32, + ::buffa::encoding::WireType::LengthDelimited, + ) + .encode(buf); + ::buffa::encoding::encode_varint(__cache.consume_next() as u64, buf); + self.source.write_to(__cache, buf); + } + if let ::core::option::Option::Some(ref v) = self.outcome { + match v { + super::super::__buffa::view::oneof::update_source_response::Outcome::Supported( + x, + ) => { + ::buffa::encoding::Tag::new( + 2u32, + ::buffa::encoding::WireType::LengthDelimited, + ) + .encode(buf); + ::buffa::encoding::encode_varint(__cache.consume_next() as u64, buf); + x.write_to(__cache, buf); + } + super::super::__buffa::view::oneof::update_source_response::Outcome::Unsupported( + x, + ) => { + ::buffa::encoding::Tag::new( + 3u32, + ::buffa::encoding::WireType::LengthDelimited, + ) + .encode(buf); + ::buffa::encoding::encode_varint(__cache.consume_next() as u64, buf); + x.write_to(__cache, buf); + } + } + } + self.__buffa_unknown_fields.write_to(buf); + } +} +/// Serializes this view as protobuf JSON. +/// +/// Implicit-presence fields with default values are omitted, `required` +/// fields are always emitted, explicit-presence (`optional`) fields are +/// emitted only when set, bytes fields are base64-encoded, and enum +/// values are their proto name strings. +/// +/// This impl uses `serialize_map(None)` because the number of emitted +/// fields depends on default-omission rules; serializers that require +/// known map lengths (e.g. `bincode`) will return a runtime error. +/// Use the owned message type for those formats. +impl<'__a> ::serde::Serialize for UpdateSourceResponseView<'__a> { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + use ::serde::ser::SerializeMap as _; + let mut __map = __s.serialize_map(::core::option::Option::None)?; + { + if let ::core::option::Option::Some(__v) = self.source.as_option() { + __map.serialize_entry("source", __v)?; + } + } + if let ::core::option::Option::Some(ref __ov) = self.outcome { + match __ov { + super::super::__buffa::view::oneof::update_source_response::Outcome::Supported( + v, + ) => { + __map.serialize_entry("supported", v)?; + } + super::super::__buffa::view::oneof::update_source_response::Outcome::Unsupported( + v, + ) => { + __map.serialize_entry("unsupported", v)?; + } + } + } + __map.end() + } +} +impl<'a> ::buffa::MessageName for UpdateSourceResponseView<'a> { + const PACKAGE: &'static str = "onequery.cli.v1"; + const NAME: &'static str = "UpdateSourceResponse"; + const FULL_NAME: &'static str = "onequery.cli.v1.UpdateSourceResponse"; + const TYPE_URL: &'static str = "type.googleapis.com/onequery.cli.v1.UpdateSourceResponse"; +} +impl<'v> ::buffa::DefaultViewInstance for UpdateSourceResponseView<'v> { + fn default_view_instance<'a>() -> &'a Self + where + Self: 'a, + { + static VALUE: ::buffa::__private::OnceBox> = ::buffa::__private::OnceBox::new(); + VALUE + .get_or_init(|| ::buffa::alloc::boxed::Box::new( + >::default(), + )) + } +} +impl ::buffa::ViewReborrow for UpdateSourceResponseView<'static> { + type Reborrowed<'b> = UpdateSourceResponseView<'b>; + fn reborrow<'b>(this: &'b Self) -> &'b Self::Reborrowed<'b> { + this + } +} +#[derive(Clone, Debug, Default)] +pub struct DeleteSourceRequestView<'a> { + /// Field 1: `org_slug` + pub org_slug: ::core::option::Option<&'a str>, + /// Field 2: `source` + pub source: ::buffa::MessageFieldView< + super::super::__buffa::view::CliSourceSelectorView<'a>, + >, + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, +} +impl<'a> DeleteSourceRequestView<'a> { + /// Decode from `buf`, enforcing a recursion depth limit for nested messages. + /// + /// Called by [`::buffa::MessageView::decode_view`] with [`::buffa::RECURSION_LIMIT`] + /// and by generated sub-message decode arms with `depth - 1`. + /// + /// **Not part of the public API.** Named with a leading underscore to + /// signal that it is for generated-code use only. + #[doc(hidden)] + pub fn _decode_depth( + buf: &'a [u8], + depth: u32, + ) -> ::core::result::Result { + let mut view = Self::default(); + view._merge_into_view(buf, depth)?; + ::core::result::Result::Ok(view) + } + /// Merge fields from `buf` into this view (proto merge semantics). + /// + /// Repeated fields append; singular fields last-wins; singular + /// MESSAGE fields merge recursively. Used by sub-message decode + /// arms when the same field appears multiple times on the wire. + /// + /// **Not part of the public API.** + #[doc(hidden)] + pub fn _merge_into_view( + &mut self, + buf: &'a [u8], + depth: u32, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + let _ = depth; + #[allow(unused_variables)] + let view = self; + let mut cur: &'a [u8] = buf; + while !cur.is_empty() { + let before_tag = cur; + let tag = ::buffa::encoding::Tag::decode(&mut cur)?; + match tag.field_number() { + 1u32 => { + if tag.wire_type() != ::buffa::encoding::WireType::LengthDelimited { + return ::core::result::Result::Err(::buffa::DecodeError::WireTypeMismatch { + field_number: 1u32, + expected: 2u8, + actual: tag.wire_type() as u8, + }); + } + view.org_slug = Some(::buffa::types::borrow_str(&mut cur)?); + } + 2u32 => { + if tag.wire_type() != ::buffa::encoding::WireType::LengthDelimited { + return ::core::result::Result::Err(::buffa::DecodeError::WireTypeMismatch { + field_number: 2u32, + expected: 2u8, + actual: tag.wire_type() as u8, + }); + } + if depth == 0 { + return Err(::buffa::DecodeError::RecursionLimitExceeded); + } + let sub = ::buffa::types::borrow_bytes(&mut cur)?; + match view.source.as_mut() { + Some(existing) => existing._merge_into_view(sub, depth - 1)?, + None => { + view.source = ::buffa::MessageFieldView::set( + super::super::__buffa::view::CliSourceSelectorView::_decode_depth( + sub, + depth - 1, + )?, + ); + } + } + } + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, depth)?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields.push_raw(&before_tag[..span_len]); + } + } + } + ::core::result::Result::Ok(()) + } +} +impl<'a> ::buffa::MessageView<'a> for DeleteSourceRequestView<'a> { + type Owned = super::super::DeleteSourceRequest; + fn decode_view(buf: &'a [u8]) -> ::core::result::Result { + Self::_decode_depth(buf, ::buffa::RECURSION_LIMIT) + } + fn decode_view_with_limit( + buf: &'a [u8], + depth: u32, + ) -> ::core::result::Result { + Self::_decode_depth(buf, depth) + } + fn to_owned_message(&self) -> super::super::DeleteSourceRequest { + self.to_owned_from_source(None) + } + #[allow(clippy::useless_conversion, clippy::needless_update)] + fn to_owned_from_source( + &self, + __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, + ) -> super::super::DeleteSourceRequest { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + let _ = __buffa_src; + super::super::DeleteSourceRequest { + org_slug: self.org_slug.map(|s| s.to_string()), + source: match self.source.as_option() { + Some(v) => { + ::buffa::MessageField::< + super::super::CliSourceSelector, + >::some(v.to_owned_from_source(__buffa_src)) + } + None => ::buffa::MessageField::none(), + }, + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned() + .unwrap_or_default() + .into(), + ..::core::default::Default::default() + } + } +} +impl<'a> ::buffa::ViewEncode<'a> for DeleteSourceRequestView<'a> { + #[allow(clippy::needless_borrow, clippy::let_and_return)] + fn compute_size(&self, __cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u32; + if let Some(ref v) = self.org_slug { + size += 1u32 + ::buffa::types::string_encoded_len(v) as u32; + } + if self.source.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.source.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u32 + ::buffa::encoding::varint_len(inner_size as u64) as u32 + + inner_size; + } + size += self.__buffa_unknown_fields.encoded_len() as u32; + size + } + #[allow(clippy::needless_borrow)] + fn write_to( + &self, + __cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::bytes::BufMut, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if let Some(ref v) = self.org_slug { + ::buffa::encoding::Tag::new( + 1u32, + ::buffa::encoding::WireType::LengthDelimited, + ) + .encode(buf); + ::buffa::types::encode_string(v, buf); + } + if self.source.is_set() { + ::buffa::encoding::Tag::new( + 2u32, + ::buffa::encoding::WireType::LengthDelimited, + ) + .encode(buf); + ::buffa::encoding::encode_varint(__cache.consume_next() as u64, buf); + self.source.write_to(__cache, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } +} +/// Serializes this view as protobuf JSON. +/// +/// Implicit-presence fields with default values are omitted, `required` +/// fields are always emitted, explicit-presence (`optional`) fields are +/// emitted only when set, bytes fields are base64-encoded, and enum +/// values are their proto name strings. +/// +/// This impl uses `serialize_map(None)` because the number of emitted +/// fields depends on default-omission rules; serializers that require +/// known map lengths (e.g. `bincode`) will return a runtime error. +/// Use the owned message type for those formats. +impl<'__a> ::serde::Serialize for DeleteSourceRequestView<'__a> { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + use ::serde::ser::SerializeMap as _; + let mut __map = __s.serialize_map(::core::option::Option::None)?; + if let ::core::option::Option::Some(__v) = self.org_slug { + __map.serialize_entry("orgSlug", __v)?; + } + { + if let ::core::option::Option::Some(__v) = self.source.as_option() { + __map.serialize_entry("source", __v)?; + } + } + __map.end() + } +} +impl<'a> ::buffa::MessageName for DeleteSourceRequestView<'a> { + const PACKAGE: &'static str = "onequery.cli.v1"; + const NAME: &'static str = "DeleteSourceRequest"; + const FULL_NAME: &'static str = "onequery.cli.v1.DeleteSourceRequest"; + const TYPE_URL: &'static str = "type.googleapis.com/onequery.cli.v1.DeleteSourceRequest"; +} +impl<'v> ::buffa::DefaultViewInstance for DeleteSourceRequestView<'v> { + fn default_view_instance<'a>() -> &'a Self + where + Self: 'a, + { + static VALUE: ::buffa::__private::OnceBox> = ::buffa::__private::OnceBox::new(); + VALUE + .get_or_init(|| ::buffa::alloc::boxed::Box::new( + >::default(), + )) + } +} +impl ::buffa::ViewReborrow for DeleteSourceRequestView<'static> { + type Reborrowed<'b> = DeleteSourceRequestView<'b>; + fn reborrow<'b>(this: &'b Self) -> &'b Self::Reborrowed<'b> { + this + } +} +#[derive(Clone, Debug, Default)] +pub struct DeleteSourceResponseView<'a> { + /// Field 1: `source` + pub source: ::buffa::MessageFieldView< + super::super::__buffa::view::CliSourceView<'a>, + >, + /// Field 2: `deleted` + pub deleted: ::core::option::Option, + pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, +} +impl<'a> DeleteSourceResponseView<'a> { + /// Decode from `buf`, enforcing a recursion depth limit for nested messages. + /// + /// Called by [`::buffa::MessageView::decode_view`] with [`::buffa::RECURSION_LIMIT`] + /// and by generated sub-message decode arms with `depth - 1`. + /// + /// **Not part of the public API.** Named with a leading underscore to + /// signal that it is for generated-code use only. + #[doc(hidden)] + pub fn _decode_depth( + buf: &'a [u8], + depth: u32, + ) -> ::core::result::Result { + let mut view = Self::default(); + view._merge_into_view(buf, depth)?; + ::core::result::Result::Ok(view) + } + /// Merge fields from `buf` into this view (proto merge semantics). + /// + /// Repeated fields append; singular fields last-wins; singular + /// MESSAGE fields merge recursively. Used by sub-message decode + /// arms when the same field appears multiple times on the wire. + /// + /// **Not part of the public API.** + #[doc(hidden)] + pub fn _merge_into_view( + &mut self, + buf: &'a [u8], + depth: u32, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + let _ = depth; + #[allow(unused_variables)] + let view = self; + let mut cur: &'a [u8] = buf; + while !cur.is_empty() { + let before_tag = cur; + let tag = ::buffa::encoding::Tag::decode(&mut cur)?; + match tag.field_number() { + 1u32 => { + if tag.wire_type() != ::buffa::encoding::WireType::LengthDelimited { + return ::core::result::Result::Err(::buffa::DecodeError::WireTypeMismatch { + field_number: 1u32, + expected: 2u8, + actual: tag.wire_type() as u8, + }); + } + if depth == 0 { + return Err(::buffa::DecodeError::RecursionLimitExceeded); + } + let sub = ::buffa::types::borrow_bytes(&mut cur)?; + match view.source.as_mut() { + Some(existing) => existing._merge_into_view(sub, depth - 1)?, + None => { + view.source = ::buffa::MessageFieldView::set( + super::super::__buffa::view::CliSourceView::_decode_depth( + sub, + depth - 1, + )?, + ); + } + } + } + 2u32 => { + if tag.wire_type() != ::buffa::encoding::WireType::Varint { + return ::core::result::Result::Err(::buffa::DecodeError::WireTypeMismatch { + field_number: 2u32, + expected: 0u8, + actual: tag.wire_type() as u8, + }); + } + view.deleted = Some(::buffa::types::decode_bool(&mut cur)?); + } + _ => { + ::buffa::encoding::skip_field_depth(tag, &mut cur, depth)?; + let span_len = before_tag.len() - cur.len(); + view.__buffa_unknown_fields.push_raw(&before_tag[..span_len]); + } + } + } + ::core::result::Result::Ok(()) + } +} +impl<'a> ::buffa::MessageView<'a> for DeleteSourceResponseView<'a> { + type Owned = super::super::DeleteSourceResponse; + fn decode_view(buf: &'a [u8]) -> ::core::result::Result { + Self::_decode_depth(buf, ::buffa::RECURSION_LIMIT) + } + fn decode_view_with_limit( + buf: &'a [u8], + depth: u32, + ) -> ::core::result::Result { + Self::_decode_depth(buf, depth) + } + fn to_owned_message(&self) -> super::super::DeleteSourceResponse { + self.to_owned_from_source(None) + } + #[allow(clippy::useless_conversion, clippy::needless_update)] + fn to_owned_from_source( + &self, + __buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>, + ) -> super::super::DeleteSourceResponse { + #[allow(unused_imports)] + use ::buffa::alloc::string::ToString as _; + let _ = __buffa_src; + super::super::DeleteSourceResponse { + source: match self.source.as_option() { + Some(v) => { + ::buffa::MessageField::< + super::super::CliSource, + >::some(v.to_owned_from_source(__buffa_src)) + } + None => ::buffa::MessageField::none(), + }, + deleted: self.deleted, + __buffa_unknown_fields: self + .__buffa_unknown_fields + .to_owned() + .unwrap_or_default() + .into(), + ..::core::default::Default::default() + } + } +} +impl<'a> ::buffa::ViewEncode<'a> for DeleteSourceResponseView<'a> { + #[allow(clippy::needless_borrow, clippy::let_and_return)] + fn compute_size(&self, __cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u32; + if self.source.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.source.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u32 + ::buffa::encoding::varint_len(inner_size as u64) as u32 + + inner_size; + } + if self.deleted.is_some() { + size += 1u32 + ::buffa::types::BOOL_ENCODED_LEN as u32; + } + size += self.__buffa_unknown_fields.encoded_len() as u32; + size + } + #[allow(clippy::needless_borrow)] + fn write_to( + &self, + __cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::bytes::BufMut, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if self.source.is_set() { + ::buffa::encoding::Tag::new( + 1u32, + ::buffa::encoding::WireType::LengthDelimited, + ) + .encode(buf); + ::buffa::encoding::encode_varint(__cache.consume_next() as u64, buf); + self.source.write_to(__cache, buf); + } + if let Some(v) = self.deleted { + ::buffa::encoding::Tag::new(2u32, ::buffa::encoding::WireType::Varint) + .encode(buf); + ::buffa::types::encode_bool(v, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } +} +/// Serializes this view as protobuf JSON. +/// +/// Implicit-presence fields with default values are omitted, `required` +/// fields are always emitted, explicit-presence (`optional`) fields are +/// emitted only when set, bytes fields are base64-encoded, and enum +/// values are their proto name strings. +/// +/// This impl uses `serialize_map(None)` because the number of emitted +/// fields depends on default-omission rules; serializers that require +/// known map lengths (e.g. `bincode`) will return a runtime error. +/// Use the owned message type for those formats. +impl<'__a> ::serde::Serialize for DeleteSourceResponseView<'__a> { + fn serialize<__S: ::serde::Serializer>( + &self, + __s: __S, + ) -> ::core::result::Result<__S::Ok, __S::Error> { + use ::serde::ser::SerializeMap as _; + let mut __map = __s.serialize_map(::core::option::Option::None)?; + { + if let ::core::option::Option::Some(__v) = self.source.as_option() { + __map.serialize_entry("source", __v)?; + } + } + if let ::core::option::Option::Some(__v) = self.deleted { + __map.serialize_entry("deleted", &__v)?; + } + __map.end() + } +} +impl<'a> ::buffa::MessageName for DeleteSourceResponseView<'a> { + const PACKAGE: &'static str = "onequery.cli.v1"; + const NAME: &'static str = "DeleteSourceResponse"; + const FULL_NAME: &'static str = "onequery.cli.v1.DeleteSourceResponse"; + const TYPE_URL: &'static str = "type.googleapis.com/onequery.cli.v1.DeleteSourceResponse"; +} +impl<'v> ::buffa::DefaultViewInstance for DeleteSourceResponseView<'v> { + fn default_view_instance<'a>() -> &'a Self + where + Self: 'a, + { + static VALUE: ::buffa::__private::OnceBox> = ::buffa::__private::OnceBox::new(); + VALUE + .get_or_init(|| ::buffa::alloc::boxed::Box::new( + >::default(), + )) + } +} +impl ::buffa::ViewReborrow for DeleteSourceResponseView<'static> { + type Reborrowed<'b> = DeleteSourceResponseView<'b>; + fn reborrow<'b>(this: &'b Self) -> &'b Self::Reborrowed<'b> { + this + } +} +#[derive(Clone, Debug, Default)] pub struct TestSourceSupportedOutcomeView<'a> { /// Field 3: `latency` pub latency: ::buffa::MessageFieldView< diff --git a/apps/cli/crates/proto-cli/src/generated/proto/onequery.cli.v1.source.__view_oneof.rs b/apps/cli/crates/proto-cli/src/generated/proto/onequery.cli.v1.source.__view_oneof.rs index bd91137e..bcceb076 100644 --- a/apps/cli/crates/proto-cli/src/generated/proto/onequery.cli.v1.source.__view_oneof.rs +++ b/apps/cli/crates/proto-cli/src/generated/proto/onequery.cli.v1.source.__view_oneof.rs @@ -22,6 +22,27 @@ pub mod test_source_response { ), } } +pub mod update_source_response { + #[allow(unused_imports)] + use super::*; + #[derive(Clone, Debug)] + pub enum Outcome<'a> { + Supported( + ::buffa::alloc::boxed::Box< + super::super::super::super::__buffa::view::TestSourceSupportedOutcomeView< + 'a, + >, + >, + ), + Unsupported( + ::buffa::alloc::boxed::Box< + super::super::super::super::__buffa::view::TestSourceUnsupportedOutcomeView< + 'a, + >, + >, + ), + } +} pub mod test_source_supported_outcome { #[allow(unused_imports)] use super::*; diff --git a/apps/cli/crates/proto-cli/src/generated/proto/onequery.cli.v1.source.rs b/apps/cli/crates/proto-cli/src/generated/proto/onequery.cli.v1.source.rs index 19e64b1f..434a6302 100644 --- a/apps/cli/crates/proto-cli/src/generated/proto/onequery.cli.v1.source.rs +++ b/apps/cli/crates/proto-cli/src/generated/proto/onequery.cli.v1.source.rs @@ -2980,6 +2980,963 @@ pub mod test_source_response { pub use super::__buffa::view::oneof::test_source_response::Outcome as OutcomeView; } #[derive(Clone, PartialEq, Default)] +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[serde(default)] +pub struct UpdateSourceRequest { + /// Field 1: `org_slug` + #[serde( + rename = "orgSlug", + alias = "org_slug", + skip_serializing_if = "::core::option::Option::is_none" + )] + pub org_slug: ::core::option::Option<::buffa::alloc::string::String>, + /// Field 2: `source` + #[serde( + rename = "source", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_unset_message_field" + )] + pub source: ::buffa::MessageField, + /// Field 3: `credentials` + #[serde( + rename = "credentials", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_unset_message_field" + )] + pub credentials: ::buffa::MessageField<::buffa_types::google::protobuf::Struct>, + #[serde(skip)] + #[doc(hidden)] + pub __buffa_unknown_fields: ::buffa::UnknownFields, +} +impl ::core::fmt::Debug for UpdateSourceRequest { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("UpdateSourceRequest") + .field("org_slug", &self.org_slug) + .field("source", &self.source) + .field("credentials", &self.credentials) + .finish() + } +} +impl UpdateSourceRequest { + /// Protobuf type URL for this message, for use with `Any::pack` and + /// `Any::unpack_if`. + /// + /// Format: `type.googleapis.com/` + pub const TYPE_URL: &'static str = "type.googleapis.com/onequery.cli.v1.UpdateSourceRequest"; +} +impl UpdateSourceRequest { + #[must_use = "with_* setters return `self` by value; assign or chain the result"] + #[inline] + ///Sets [`Self::org_slug`] to `Some(value)`, consuming and returning `self`. + pub fn with_org_slug( + mut self, + value: impl Into<::buffa::alloc::string::String>, + ) -> Self { + self.org_slug = Some(value.into()); + self + } +} +impl ::buffa::DefaultInstance for UpdateSourceRequest { + fn default_instance() -> &'static Self { + static VALUE: ::buffa::__private::OnceBox = ::buffa::__private::OnceBox::new(); + VALUE.get_or_init(|| ::buffa::alloc::boxed::Box::new(Self::default())) + } +} +impl ::buffa::MessageName for UpdateSourceRequest { + const PACKAGE: &'static str = "onequery.cli.v1"; + const NAME: &'static str = "UpdateSourceRequest"; + const FULL_NAME: &'static str = "onequery.cli.v1.UpdateSourceRequest"; + const TYPE_URL: &'static str = "type.googleapis.com/onequery.cli.v1.UpdateSourceRequest"; +} +impl ::buffa::Message for UpdateSourceRequest { + /// Returns the total encoded size in bytes. + /// + /// The result is a `u32`; the protobuf specification requires all + /// messages to fit within 2 GiB (2,147,483,647 bytes), so a + /// compliant message will never overflow this type. + #[allow(clippy::let_and_return)] + fn compute_size(&self, __cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u32; + if let Some(ref v) = self.org_slug { + size += 1u32 + ::buffa::types::string_encoded_len(v) as u32; + } + if self.source.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.source.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u32 + ::buffa::encoding::varint_len(inner_size as u64) as u32 + + inner_size; + } + if self.credentials.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.credentials.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u32 + ::buffa::encoding::varint_len(inner_size as u64) as u32 + + inner_size; + } + size += self.__buffa_unknown_fields.encoded_len() as u32; + size + } + fn write_to( + &self, + __cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::bytes::BufMut, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if let Some(ref v) = self.org_slug { + ::buffa::encoding::Tag::new( + 1u32, + ::buffa::encoding::WireType::LengthDelimited, + ) + .encode(buf); + ::buffa::types::encode_string(v, buf); + } + if self.source.is_set() { + ::buffa::encoding::Tag::new( + 2u32, + ::buffa::encoding::WireType::LengthDelimited, + ) + .encode(buf); + ::buffa::encoding::encode_varint(__cache.consume_next() as u64, buf); + self.source.write_to(__cache, buf); + } + if self.credentials.is_set() { + ::buffa::encoding::Tag::new( + 3u32, + ::buffa::encoding::WireType::LengthDelimited, + ) + .encode(buf); + ::buffa::encoding::encode_varint(__cache.consume_next() as u64, buf); + self.credentials.write_to(__cache, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + fn merge_field( + &mut self, + tag: ::buffa::encoding::Tag, + buf: &mut impl ::buffa::bytes::Buf, + depth: u32, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + #[allow(unused_imports)] + use ::buffa::bytes::Buf as _; + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + match tag.field_number() { + 1u32 => { + if tag.wire_type() != ::buffa::encoding::WireType::LengthDelimited { + return ::core::result::Result::Err(::buffa::DecodeError::WireTypeMismatch { + field_number: 1u32, + expected: 2u8, + actual: tag.wire_type() as u8, + }); + } + ::buffa::types::merge_string( + self + .org_slug + .get_or_insert_with(::buffa::alloc::string::String::new), + buf, + )?; + } + 2u32 => { + if tag.wire_type() != ::buffa::encoding::WireType::LengthDelimited { + return ::core::result::Result::Err(::buffa::DecodeError::WireTypeMismatch { + field_number: 2u32, + expected: 2u8, + actual: tag.wire_type() as u8, + }); + } + ::buffa::Message::merge_length_delimited( + self.source.get_or_insert_default(), + buf, + depth, + )?; + } + 3u32 => { + if tag.wire_type() != ::buffa::encoding::WireType::LengthDelimited { + return ::core::result::Result::Err(::buffa::DecodeError::WireTypeMismatch { + field_number: 3u32, + expected: 2u8, + actual: tag.wire_type() as u8, + }); + } + ::buffa::Message::merge_length_delimited( + self.credentials.get_or_insert_default(), + buf, + depth, + )?; + } + _ => { + self.__buffa_unknown_fields + .push(::buffa::encoding::decode_unknown_field(tag, buf, depth)?); + } + } + ::core::result::Result::Ok(()) + } + fn clear(&mut self) { + self.org_slug = ::core::option::Option::None; + self.source = ::buffa::MessageField::none(); + self.credentials = ::buffa::MessageField::none(); + self.__buffa_unknown_fields.clear(); + } +} +impl ::buffa::ExtensionSet for UpdateSourceRequest { + const PROTO_FQN: &'static str = "onequery.cli.v1.UpdateSourceRequest"; + fn unknown_fields(&self) -> &::buffa::UnknownFields { + &self.__buffa_unknown_fields + } + fn unknown_fields_mut(&mut self) -> &mut ::buffa::UnknownFields { + &mut self.__buffa_unknown_fields + } +} +impl ::buffa::json_helpers::ProtoElemJson for UpdateSourceRequest { + fn serialize_proto_json( + v: &Self, + s: S, + ) -> ::core::result::Result { + ::serde::Serialize::serialize(v, s) + } + fn deserialize_proto_json<'de, D: ::serde::Deserializer<'de>>( + d: D, + ) -> ::core::result::Result { + ::deserialize(d) + } +} +#[doc(hidden)] +pub const __UPDATE_SOURCE_REQUEST_JSON_ANY: ::buffa::type_registry::JsonAnyEntry = ::buffa::type_registry::JsonAnyEntry { + type_url: "type.googleapis.com/onequery.cli.v1.UpdateSourceRequest", + to_json: ::buffa::type_registry::any_to_json::, + from_json: ::buffa::type_registry::any_from_json::, + is_wkt: false, +}; +#[derive(Clone, PartialEq, Default)] +#[derive(::serde::Serialize)] +#[serde(default)] +pub struct UpdateSourceResponse { + /// Field 1: `source` + #[serde( + rename = "source", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_unset_message_field" + )] + pub source: ::buffa::MessageField, + #[serde(flatten)] + pub outcome: ::core::option::Option<__buffa::oneof::update_source_response::Outcome>, + #[serde(skip)] + #[doc(hidden)] + pub __buffa_unknown_fields: ::buffa::UnknownFields, +} +impl ::core::fmt::Debug for UpdateSourceResponse { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("UpdateSourceResponse") + .field("source", &self.source) + .field("outcome", &self.outcome) + .finish() + } +} +impl UpdateSourceResponse { + /// Protobuf type URL for this message, for use with `Any::pack` and + /// `Any::unpack_if`. + /// + /// Format: `type.googleapis.com/` + pub const TYPE_URL: &'static str = "type.googleapis.com/onequery.cli.v1.UpdateSourceResponse"; +} +impl ::buffa::DefaultInstance for UpdateSourceResponse { + fn default_instance() -> &'static Self { + static VALUE: ::buffa::__private::OnceBox = ::buffa::__private::OnceBox::new(); + VALUE.get_or_init(|| ::buffa::alloc::boxed::Box::new(Self::default())) + } +} +impl ::buffa::MessageName for UpdateSourceResponse { + const PACKAGE: &'static str = "onequery.cli.v1"; + const NAME: &'static str = "UpdateSourceResponse"; + const FULL_NAME: &'static str = "onequery.cli.v1.UpdateSourceResponse"; + const TYPE_URL: &'static str = "type.googleapis.com/onequery.cli.v1.UpdateSourceResponse"; +} +impl ::buffa::Message for UpdateSourceResponse { + /// Returns the total encoded size in bytes. + /// + /// The result is a `u32`; the protobuf specification requires all + /// messages to fit within 2 GiB (2,147,483,647 bytes), so a + /// compliant message will never overflow this type. + #[allow(clippy::let_and_return)] + fn compute_size(&self, __cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u32; + if self.source.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.source.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u32 + ::buffa::encoding::varint_len(inner_size as u64) as u32 + + inner_size; + } + if let ::core::option::Option::Some(ref v) = self.outcome { + match v { + __buffa::oneof::update_source_response::Outcome::Supported(x) => { + let __slot = __cache.reserve(); + let inner = x.compute_size(__cache); + __cache.set(__slot, inner); + size + += 1u32 + ::buffa::encoding::varint_len(inner as u64) as u32 + + inner; + } + __buffa::oneof::update_source_response::Outcome::Unsupported(x) => { + let __slot = __cache.reserve(); + let inner = x.compute_size(__cache); + __cache.set(__slot, inner); + size + += 1u32 + ::buffa::encoding::varint_len(inner as u64) as u32 + + inner; + } + } + } + size += self.__buffa_unknown_fields.encoded_len() as u32; + size + } + fn write_to( + &self, + __cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::bytes::BufMut, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if self.source.is_set() { + ::buffa::encoding::Tag::new( + 1u32, + ::buffa::encoding::WireType::LengthDelimited, + ) + .encode(buf); + ::buffa::encoding::encode_varint(__cache.consume_next() as u64, buf); + self.source.write_to(__cache, buf); + } + if let ::core::option::Option::Some(ref v) = self.outcome { + match v { + __buffa::oneof::update_source_response::Outcome::Supported(x) => { + ::buffa::encoding::Tag::new( + 2u32, + ::buffa::encoding::WireType::LengthDelimited, + ) + .encode(buf); + ::buffa::encoding::encode_varint(__cache.consume_next() as u64, buf); + x.write_to(__cache, buf); + } + __buffa::oneof::update_source_response::Outcome::Unsupported(x) => { + ::buffa::encoding::Tag::new( + 3u32, + ::buffa::encoding::WireType::LengthDelimited, + ) + .encode(buf); + ::buffa::encoding::encode_varint(__cache.consume_next() as u64, buf); + x.write_to(__cache, buf); + } + } + } + self.__buffa_unknown_fields.write_to(buf); + } + fn merge_field( + &mut self, + tag: ::buffa::encoding::Tag, + buf: &mut impl ::buffa::bytes::Buf, + depth: u32, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + #[allow(unused_imports)] + use ::buffa::bytes::Buf as _; + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + match tag.field_number() { + 1u32 => { + if tag.wire_type() != ::buffa::encoding::WireType::LengthDelimited { + return ::core::result::Result::Err(::buffa::DecodeError::WireTypeMismatch { + field_number: 1u32, + expected: 2u8, + actual: tag.wire_type() as u8, + }); + } + ::buffa::Message::merge_length_delimited( + self.source.get_or_insert_default(), + buf, + depth, + )?; + } + 2u32 => { + if tag.wire_type() != ::buffa::encoding::WireType::LengthDelimited { + return ::core::result::Result::Err(::buffa::DecodeError::WireTypeMismatch { + field_number: 2u32, + expected: 2u8, + actual: tag.wire_type() as u8, + }); + } + if let ::core::option::Option::Some( + __buffa::oneof::update_source_response::Outcome::Supported( + ref mut existing, + ), + ) = self.outcome + { + ::buffa::Message::merge_length_delimited( + &mut **existing, + buf, + depth, + )?; + } else { + let mut val = ::core::default::Default::default(); + ::buffa::Message::merge_length_delimited(&mut val, buf, depth)?; + self.outcome = ::core::option::Option::Some( + __buffa::oneof::update_source_response::Outcome::Supported( + ::buffa::alloc::boxed::Box::new(val), + ), + ); + } + } + 3u32 => { + if tag.wire_type() != ::buffa::encoding::WireType::LengthDelimited { + return ::core::result::Result::Err(::buffa::DecodeError::WireTypeMismatch { + field_number: 3u32, + expected: 2u8, + actual: tag.wire_type() as u8, + }); + } + if let ::core::option::Option::Some( + __buffa::oneof::update_source_response::Outcome::Unsupported( + ref mut existing, + ), + ) = self.outcome + { + ::buffa::Message::merge_length_delimited( + &mut **existing, + buf, + depth, + )?; + } else { + let mut val = ::core::default::Default::default(); + ::buffa::Message::merge_length_delimited(&mut val, buf, depth)?; + self.outcome = ::core::option::Option::Some( + __buffa::oneof::update_source_response::Outcome::Unsupported( + ::buffa::alloc::boxed::Box::new(val), + ), + ); + } + } + _ => { + self.__buffa_unknown_fields + .push(::buffa::encoding::decode_unknown_field(tag, buf, depth)?); + } + } + ::core::result::Result::Ok(()) + } + fn clear(&mut self) { + self.source = ::buffa::MessageField::none(); + self.outcome = ::core::option::Option::None; + self.__buffa_unknown_fields.clear(); + } +} +impl ::buffa::ExtensionSet for UpdateSourceResponse { + const PROTO_FQN: &'static str = "onequery.cli.v1.UpdateSourceResponse"; + fn unknown_fields(&self) -> &::buffa::UnknownFields { + &self.__buffa_unknown_fields + } + fn unknown_fields_mut(&mut self) -> &mut ::buffa::UnknownFields { + &mut self.__buffa_unknown_fields + } +} +impl<'de> serde::Deserialize<'de> for UpdateSourceResponse { + fn deserialize>( + d: D, + ) -> ::core::result::Result { + struct _V; + impl<'de> serde::de::Visitor<'de> for _V { + type Value = UpdateSourceResponse; + fn expecting(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + f.write_str("struct UpdateSourceResponse") + } + #[allow(clippy::field_reassign_with_default)] + fn visit_map>( + self, + mut map: A, + ) -> ::core::result::Result { + let mut __f_source: ::core::option::Option< + ::buffa::MessageField, + > = None; + let mut __oneof_outcome: ::core::option::Option< + __buffa::oneof::update_source_response::Outcome, + > = None; + while let Some(key) = map.next_key::<::buffa::alloc::string::String>()? { + match key.as_str() { + "source" => { + __f_source = Some( + map.next_value::<::buffa::MessageField>()?, + ); + } + "supported" => { + let v: ::core::option::Option = map + .next_value_seed( + ::buffa::json_helpers::NullableDeserializeSeed( + ::buffa::json_helpers::DefaultDeserializeSeed::< + TestSourceSupportedOutcome, + >::new(), + ), + )?; + if let Some(v) = v { + if __oneof_outcome.is_some() { + return Err( + serde::de::Error::custom( + "multiple oneof fields set for 'outcome'", + ), + ); + } + __oneof_outcome = Some( + __buffa::oneof::update_source_response::Outcome::Supported( + ::buffa::alloc::boxed::Box::new(v), + ), + ); + } + } + "unsupported" => { + let v: ::core::option::Option< + TestSourceUnsupportedOutcome, + > = map + .next_value_seed( + ::buffa::json_helpers::NullableDeserializeSeed( + ::buffa::json_helpers::DefaultDeserializeSeed::< + TestSourceUnsupportedOutcome, + >::new(), + ), + )?; + if let Some(v) = v { + if __oneof_outcome.is_some() { + return Err( + serde::de::Error::custom( + "multiple oneof fields set for 'outcome'", + ), + ); + } + __oneof_outcome = Some( + __buffa::oneof::update_source_response::Outcome::Unsupported( + ::buffa::alloc::boxed::Box::new(v), + ), + ); + } + } + _ => { + map.next_value::()?; + } + } + } + let mut __r = ::default(); + if let ::core::option::Option::Some(v) = __f_source { + __r.source = v; + } + __r.outcome = __oneof_outcome; + Ok(__r) + } + } + d.deserialize_map(_V) + } +} +impl ::buffa::json_helpers::ProtoElemJson for UpdateSourceResponse { + fn serialize_proto_json( + v: &Self, + s: S, + ) -> ::core::result::Result { + ::serde::Serialize::serialize(v, s) + } + fn deserialize_proto_json<'de, D: ::serde::Deserializer<'de>>( + d: D, + ) -> ::core::result::Result { + ::deserialize(d) + } +} +#[doc(hidden)] +pub const __UPDATE_SOURCE_RESPONSE_JSON_ANY: ::buffa::type_registry::JsonAnyEntry = ::buffa::type_registry::JsonAnyEntry { + type_url: "type.googleapis.com/onequery.cli.v1.UpdateSourceResponse", + to_json: ::buffa::type_registry::any_to_json::, + from_json: ::buffa::type_registry::any_from_json::, + is_wkt: false, +}; +pub mod update_source_response { + #[allow(unused_imports)] + use super::*; + #[doc(inline)] + pub use super::__buffa::oneof::update_source_response::Outcome; + #[doc(inline)] + pub use super::__buffa::view::oneof::update_source_response::Outcome as OutcomeView; +} +#[derive(Clone, PartialEq, Default)] +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[serde(default)] +pub struct DeleteSourceRequest { + /// Field 1: `org_slug` + #[serde( + rename = "orgSlug", + alias = "org_slug", + skip_serializing_if = "::core::option::Option::is_none" + )] + pub org_slug: ::core::option::Option<::buffa::alloc::string::String>, + /// Field 2: `source` + #[serde( + rename = "source", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_unset_message_field" + )] + pub source: ::buffa::MessageField, + #[serde(skip)] + #[doc(hidden)] + pub __buffa_unknown_fields: ::buffa::UnknownFields, +} +impl ::core::fmt::Debug for DeleteSourceRequest { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("DeleteSourceRequest") + .field("org_slug", &self.org_slug) + .field("source", &self.source) + .finish() + } +} +impl DeleteSourceRequest { + /// Protobuf type URL for this message, for use with `Any::pack` and + /// `Any::unpack_if`. + /// + /// Format: `type.googleapis.com/` + pub const TYPE_URL: &'static str = "type.googleapis.com/onequery.cli.v1.DeleteSourceRequest"; +} +impl DeleteSourceRequest { + #[must_use = "with_* setters return `self` by value; assign or chain the result"] + #[inline] + ///Sets [`Self::org_slug`] to `Some(value)`, consuming and returning `self`. + pub fn with_org_slug( + mut self, + value: impl Into<::buffa::alloc::string::String>, + ) -> Self { + self.org_slug = Some(value.into()); + self + } +} +impl ::buffa::DefaultInstance for DeleteSourceRequest { + fn default_instance() -> &'static Self { + static VALUE: ::buffa::__private::OnceBox = ::buffa::__private::OnceBox::new(); + VALUE.get_or_init(|| ::buffa::alloc::boxed::Box::new(Self::default())) + } +} +impl ::buffa::MessageName for DeleteSourceRequest { + const PACKAGE: &'static str = "onequery.cli.v1"; + const NAME: &'static str = "DeleteSourceRequest"; + const FULL_NAME: &'static str = "onequery.cli.v1.DeleteSourceRequest"; + const TYPE_URL: &'static str = "type.googleapis.com/onequery.cli.v1.DeleteSourceRequest"; +} +impl ::buffa::Message for DeleteSourceRequest { + /// Returns the total encoded size in bytes. + /// + /// The result is a `u32`; the protobuf specification requires all + /// messages to fit within 2 GiB (2,147,483,647 bytes), so a + /// compliant message will never overflow this type. + #[allow(clippy::let_and_return)] + fn compute_size(&self, __cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u32; + if let Some(ref v) = self.org_slug { + size += 1u32 + ::buffa::types::string_encoded_len(v) as u32; + } + if self.source.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.source.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u32 + ::buffa::encoding::varint_len(inner_size as u64) as u32 + + inner_size; + } + size += self.__buffa_unknown_fields.encoded_len() as u32; + size + } + fn write_to( + &self, + __cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::bytes::BufMut, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if let Some(ref v) = self.org_slug { + ::buffa::encoding::Tag::new( + 1u32, + ::buffa::encoding::WireType::LengthDelimited, + ) + .encode(buf); + ::buffa::types::encode_string(v, buf); + } + if self.source.is_set() { + ::buffa::encoding::Tag::new( + 2u32, + ::buffa::encoding::WireType::LengthDelimited, + ) + .encode(buf); + ::buffa::encoding::encode_varint(__cache.consume_next() as u64, buf); + self.source.write_to(__cache, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + fn merge_field( + &mut self, + tag: ::buffa::encoding::Tag, + buf: &mut impl ::buffa::bytes::Buf, + depth: u32, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + #[allow(unused_imports)] + use ::buffa::bytes::Buf as _; + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + match tag.field_number() { + 1u32 => { + if tag.wire_type() != ::buffa::encoding::WireType::LengthDelimited { + return ::core::result::Result::Err(::buffa::DecodeError::WireTypeMismatch { + field_number: 1u32, + expected: 2u8, + actual: tag.wire_type() as u8, + }); + } + ::buffa::types::merge_string( + self + .org_slug + .get_or_insert_with(::buffa::alloc::string::String::new), + buf, + )?; + } + 2u32 => { + if tag.wire_type() != ::buffa::encoding::WireType::LengthDelimited { + return ::core::result::Result::Err(::buffa::DecodeError::WireTypeMismatch { + field_number: 2u32, + expected: 2u8, + actual: tag.wire_type() as u8, + }); + } + ::buffa::Message::merge_length_delimited( + self.source.get_or_insert_default(), + buf, + depth, + )?; + } + _ => { + self.__buffa_unknown_fields + .push(::buffa::encoding::decode_unknown_field(tag, buf, depth)?); + } + } + ::core::result::Result::Ok(()) + } + fn clear(&mut self) { + self.org_slug = ::core::option::Option::None; + self.source = ::buffa::MessageField::none(); + self.__buffa_unknown_fields.clear(); + } +} +impl ::buffa::ExtensionSet for DeleteSourceRequest { + const PROTO_FQN: &'static str = "onequery.cli.v1.DeleteSourceRequest"; + fn unknown_fields(&self) -> &::buffa::UnknownFields { + &self.__buffa_unknown_fields + } + fn unknown_fields_mut(&mut self) -> &mut ::buffa::UnknownFields { + &mut self.__buffa_unknown_fields + } +} +impl ::buffa::json_helpers::ProtoElemJson for DeleteSourceRequest { + fn serialize_proto_json( + v: &Self, + s: S, + ) -> ::core::result::Result { + ::serde::Serialize::serialize(v, s) + } + fn deserialize_proto_json<'de, D: ::serde::Deserializer<'de>>( + d: D, + ) -> ::core::result::Result { + ::deserialize(d) + } +} +#[doc(hidden)] +pub const __DELETE_SOURCE_REQUEST_JSON_ANY: ::buffa::type_registry::JsonAnyEntry = ::buffa::type_registry::JsonAnyEntry { + type_url: "type.googleapis.com/onequery.cli.v1.DeleteSourceRequest", + to_json: ::buffa::type_registry::any_to_json::, + from_json: ::buffa::type_registry::any_from_json::, + is_wkt: false, +}; +#[derive(Clone, PartialEq, Default)] +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[serde(default)] +pub struct DeleteSourceResponse { + /// Field 1: `source` + #[serde( + rename = "source", + skip_serializing_if = "::buffa::json_helpers::skip_if::is_unset_message_field" + )] + pub source: ::buffa::MessageField, + /// Field 2: `deleted` + #[serde(rename = "deleted", skip_serializing_if = "::core::option::Option::is_none")] + pub deleted: ::core::option::Option, + #[serde(skip)] + #[doc(hidden)] + pub __buffa_unknown_fields: ::buffa::UnknownFields, +} +impl ::core::fmt::Debug for DeleteSourceResponse { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("DeleteSourceResponse") + .field("source", &self.source) + .field("deleted", &self.deleted) + .finish() + } +} +impl DeleteSourceResponse { + /// Protobuf type URL for this message, for use with `Any::pack` and + /// `Any::unpack_if`. + /// + /// Format: `type.googleapis.com/` + pub const TYPE_URL: &'static str = "type.googleapis.com/onequery.cli.v1.DeleteSourceResponse"; +} +impl DeleteSourceResponse { + #[must_use = "with_* setters return `self` by value; assign or chain the result"] + #[inline] + ///Sets [`Self::deleted`] to `Some(value)`, consuming and returning `self`. + pub fn with_deleted(mut self, value: bool) -> Self { + self.deleted = Some(value); + self + } +} +impl ::buffa::DefaultInstance for DeleteSourceResponse { + fn default_instance() -> &'static Self { + static VALUE: ::buffa::__private::OnceBox = ::buffa::__private::OnceBox::new(); + VALUE.get_or_init(|| ::buffa::alloc::boxed::Box::new(Self::default())) + } +} +impl ::buffa::MessageName for DeleteSourceResponse { + const PACKAGE: &'static str = "onequery.cli.v1"; + const NAME: &'static str = "DeleteSourceResponse"; + const FULL_NAME: &'static str = "onequery.cli.v1.DeleteSourceResponse"; + const TYPE_URL: &'static str = "type.googleapis.com/onequery.cli.v1.DeleteSourceResponse"; +} +impl ::buffa::Message for DeleteSourceResponse { + /// Returns the total encoded size in bytes. + /// + /// The result is a `u32`; the protobuf specification requires all + /// messages to fit within 2 GiB (2,147,483,647 bytes), so a + /// compliant message will never overflow this type. + #[allow(clippy::let_and_return)] + fn compute_size(&self, __cache: &mut ::buffa::SizeCache) -> u32 { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + let mut size = 0u32; + if self.source.is_set() { + let __slot = __cache.reserve(); + let inner_size = self.source.compute_size(__cache); + __cache.set(__slot, inner_size); + size + += 1u32 + ::buffa::encoding::varint_len(inner_size as u64) as u32 + + inner_size; + } + if self.deleted.is_some() { + size += 1u32 + ::buffa::types::BOOL_ENCODED_LEN as u32; + } + size += self.__buffa_unknown_fields.encoded_len() as u32; + size + } + fn write_to( + &self, + __cache: &mut ::buffa::SizeCache, + buf: &mut impl ::buffa::bytes::BufMut, + ) { + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + if self.source.is_set() { + ::buffa::encoding::Tag::new( + 1u32, + ::buffa::encoding::WireType::LengthDelimited, + ) + .encode(buf); + ::buffa::encoding::encode_varint(__cache.consume_next() as u64, buf); + self.source.write_to(__cache, buf); + } + if let Some(v) = self.deleted { + ::buffa::encoding::Tag::new(2u32, ::buffa::encoding::WireType::Varint) + .encode(buf); + ::buffa::types::encode_bool(v, buf); + } + self.__buffa_unknown_fields.write_to(buf); + } + fn merge_field( + &mut self, + tag: ::buffa::encoding::Tag, + buf: &mut impl ::buffa::bytes::Buf, + depth: u32, + ) -> ::core::result::Result<(), ::buffa::DecodeError> { + #[allow(unused_imports)] + use ::buffa::bytes::Buf as _; + #[allow(unused_imports)] + use ::buffa::Enumeration as _; + match tag.field_number() { + 1u32 => { + if tag.wire_type() != ::buffa::encoding::WireType::LengthDelimited { + return ::core::result::Result::Err(::buffa::DecodeError::WireTypeMismatch { + field_number: 1u32, + expected: 2u8, + actual: tag.wire_type() as u8, + }); + } + ::buffa::Message::merge_length_delimited( + self.source.get_or_insert_default(), + buf, + depth, + )?; + } + 2u32 => { + if tag.wire_type() != ::buffa::encoding::WireType::Varint { + return ::core::result::Result::Err(::buffa::DecodeError::WireTypeMismatch { + field_number: 2u32, + expected: 0u8, + actual: tag.wire_type() as u8, + }); + } + self.deleted = ::core::option::Option::Some( + ::buffa::types::decode_bool(buf)?, + ); + } + _ => { + self.__buffa_unknown_fields + .push(::buffa::encoding::decode_unknown_field(tag, buf, depth)?); + } + } + ::core::result::Result::Ok(()) + } + fn clear(&mut self) { + self.source = ::buffa::MessageField::none(); + self.deleted = ::core::option::Option::None; + self.__buffa_unknown_fields.clear(); + } +} +impl ::buffa::ExtensionSet for DeleteSourceResponse { + const PROTO_FQN: &'static str = "onequery.cli.v1.DeleteSourceResponse"; + fn unknown_fields(&self) -> &::buffa::UnknownFields { + &self.__buffa_unknown_fields + } + fn unknown_fields_mut(&mut self) -> &mut ::buffa::UnknownFields { + &mut self.__buffa_unknown_fields + } +} +impl ::buffa::json_helpers::ProtoElemJson for DeleteSourceResponse { + fn serialize_proto_json( + v: &Self, + s: S, + ) -> ::core::result::Result { + ::serde::Serialize::serialize(v, s) + } + fn deserialize_proto_json<'de, D: ::serde::Deserializer<'de>>( + d: D, + ) -> ::core::result::Result { + ::deserialize(d) + } +} +#[doc(hidden)] +pub const __DELETE_SOURCE_RESPONSE_JSON_ANY: ::buffa::type_registry::JsonAnyEntry = ::buffa::type_registry::JsonAnyEntry { + type_url: "type.googleapis.com/onequery.cli.v1.DeleteSourceResponse", + to_json: ::buffa::type_registry::any_to_json::, + from_json: ::buffa::type_registry::any_from_json::, + is_wkt: false, +}; +#[derive(Clone, PartialEq, Default)] #[derive(::serde::Serialize)] #[serde(default)] pub struct TestSourceSupportedOutcome { diff --git a/packages/cli-server/package.json b/packages/cli-server/package.json index a0272ac1..3e57ad28 100644 --- a/packages/cli-server/package.json +++ b/packages/cli-server/package.json @@ -8,7 +8,8 @@ "./connect/context": "./src/connect/context.ts", "./connect/service": "./src/connect/service/index.ts", "./query/effects": "./src/query/effects.ts", - "./source/effects": "./src/source/effects.ts" + "./source/effects": "./src/source/effects.ts", + "./source/mutations": "./src/source/mutations.ts" }, "scripts": { "typecheck": "tsgo --noEmit", diff --git a/packages/cli-server/src/authorization.test.ts b/packages/cli-server/src/authorization.test.ts index fc4eba50..a1645148 100644 --- a/packages/cli-server/src/authorization.test.ts +++ b/packages/cli-server/src/authorization.test.ts @@ -12,6 +12,7 @@ const FULL_CAPABILITIES = [ "source.connect", "source.list", "source.read", + "source.write", "source_api.describe", "source_api.execute", "query.execute", @@ -25,6 +26,7 @@ describe("cli authorization", () => { "source.connect", "source.list", "source.read", + "source.write", "source_api.describe", "source_api.execute", "query.execute", diff --git a/packages/cli-server/src/authorization.ts b/packages/cli-server/src/authorization.ts index 1cd50529..b456294b 100644 --- a/packages/cli-server/src/authorization.ts +++ b/packages/cli-server/src/authorization.ts @@ -13,6 +13,7 @@ export const CLI_ACTIONS = [ "source.connect", "source.list", "source.read", + "source.write", "source_api.describe", "source_api.execute", "query.execute", @@ -29,6 +30,7 @@ const CLI_ACTION_PERMISSIONS = { "source.connect": organizationPermissionChecks.cliSourceConnect, "source.list": organizationPermissionChecks.cliSourceList, "source.read": organizationPermissionChecks.cliSourceRead, + "source.write": organizationPermissionChecks.cliSourceWrite, "source_api.describe": organizationPermissionChecks.cliSourceApiDescribe, "source_api.execute": organizationPermissionChecks.cliSourceApiExecute, } as const; diff --git a/packages/cli-server/src/connect/node-adapter.ts b/packages/cli-server/src/connect/node-adapter.ts index 7b368476..a4c12eee 100644 --- a/packages/cli-server/src/connect/node-adapter.ts +++ b/packages/cli-server/src/connect/node-adapter.ts @@ -119,6 +119,8 @@ const CLI_VALIDATION_PROBLEM_KEYS_BY_METHOD_NAME = new Map< [CliSourceService.method.connectSource.name, "SOURCE_REQUEST_INVALID"], [CliSourceService.method.getSource.name, "SOURCE_REQUEST_INVALID"], [CliSourceService.method.testSource.name, "SOURCE_REQUEST_INVALID"], + [CliSourceService.method.updateSource.name, "SOURCE_REQUEST_INVALID"], + [CliSourceService.method.deleteSource.name, "SOURCE_REQUEST_INVALID"], [ CliSourceApiService.method.describeSourceApi.name, "SOURCE_API_REQUEST_INVALID", diff --git a/packages/cli-server/src/connect/rpc.ts b/packages/cli-server/src/connect/rpc.ts index 360b6b6c..b48dc37c 100644 --- a/packages/cli-server/src/connect/rpc.ts +++ b/packages/cli-server/src/connect/rpc.ts @@ -20,11 +20,13 @@ import { import { handleExecuteQuery, handleValidateQuery } from "./service/query"; import { handleConnectSource, + handleDeleteSource, handleGetSource, handleGetSourceConnectGuide, handleListSourceProviders, handleListSources, handleTestSource, + handleUpdateSource, } from "./service/source"; import { handleDescribeSourceApi, @@ -56,6 +58,8 @@ const cliSourceConnectImplementation: ServiceImpl = { testSource: handleTestSource, getSourceConnectGuide: handleGetSourceConnectGuide, connectSource: handleConnectSource, + updateSource: handleUpdateSource, + deleteSource: handleDeleteSource, }; const cliSourceApiConnectImplementation: ServiceImpl< diff --git a/packages/cli-server/src/connect/service/__snapshots__/source-api.test.ts.snap b/packages/cli-server/src/connect/service/__snapshots__/source-api.test.ts.snap index 7de9b829..99ae108d 100644 --- a/packages/cli-server/src/connect/service/__snapshots__/source-api.test.ts.snap +++ b/packages/cli-server/src/connect/service/__snapshots__/source-api.test.ts.snap @@ -55,6 +55,7 @@ exports[`source api connect service > binds continuation tokens to execution sta "source.connect", "source.list", "source.read", + "source.write", "source_api.describe", "source_api.execute", "query.execute", @@ -165,6 +166,7 @@ exports[`source api connect service > converts protobuf JSON draft bodies into c "source.connect", "source.list", "source.read", + "source.write", "source_api.describe", "source_api.execute", "query.execute", @@ -268,6 +270,7 @@ exports[`source api connect service > describes the source API through the Conne "source.connect", "source.list", "source.read", + "source.write", "source_api.describe", "source_api.execute", "query.execute", @@ -359,6 +362,7 @@ exports[`source api connect service > executes source API requests through the C "source.connect", "source.list", "source.read", + "source.write", "source_api.describe", "source_api.execute", "query.execute", @@ -529,6 +533,7 @@ exports[`source api connect service > previews source API execution through the "source.connect", "source.list", "source.read", + "source.write", "source_api.describe", "source_api.execute", "query.execute", diff --git a/packages/cli-server/src/connect/service/index.ts b/packages/cli-server/src/connect/service/index.ts index 49e9937c..d7aeb58d 100644 --- a/packages/cli-server/src/connect/service/index.ts +++ b/packages/cli-server/src/connect/service/index.ts @@ -17,10 +17,12 @@ export type { } from "./query"; export { handleConnectSource, + handleDeleteSource, handleGetSource, handleGetSourceConnectGuide, handleListSources, handleTestSource, + handleUpdateSource, } from "./source"; export { handleDescribeSourceApi, diff --git a/packages/cli-server/src/connect/service/organization.ts b/packages/cli-server/src/connect/service/organization.ts index a8c624de..8a2f345b 100644 --- a/packages/cli-server/src/connect/service/organization.ts +++ b/packages/cli-server/src/connect/service/organization.ts @@ -32,6 +32,8 @@ function toCliOrgCapability( return OrgCapability.SOURCE_LIST; case "source.read": return OrgCapability.SOURCE_READ; + case "source.write": + return OrgCapability.SOURCE_WRITE; case "source_api.describe": return OrgCapability.SOURCE_API_DESCRIBE; case "source_api.execute": diff --git a/packages/cli-server/src/connect/service/source/handlers.ts b/packages/cli-server/src/connect/service/source/handlers.ts index f5c16698..3240bd92 100644 --- a/packages/cli-server/src/connect/service/source/handlers.ts +++ b/packages/cli-server/src/connect/service/source/handlers.ts @@ -32,6 +32,7 @@ import { getCliSourceInterfaceTypes, sortCliSourceRecords, } from "../../../source/model"; +import { deleteCliSource, updateCliSource } from "../../../source/mutations"; import { parseCliSourceSelector } from "../../../source/reference"; import { requireCliConnectRequestContext } from "../../context"; import { @@ -48,13 +49,16 @@ import { buildCliSource, buildGetSourceResponse, buildTestSourceResponse, + buildUpdateSourceResponse, toCliContentFormat, toCliSourceInterface, } from "./response"; import type { ConnectSourceResponseInit, + DeleteSourceResponseInit, GetSourceConnectGuideResponseInit, TestSourceResponseInit, + UpdateSourceResponseInit, } from "./types"; const handleListSourcesImpl: CliResultServiceMethod<"listSources"> = async ( @@ -415,6 +419,137 @@ const handleConnectSourceImpl: CliResultServiceMethod<"connectSource"> = async ( } satisfies ConnectSourceResponseInit); }); +const handleUpdateSourceImpl: CliResultServiceMethod<"updateSource"> = async ( + request, + context +) => + Result.gen(async function* handleUpdateSourceFlow() { + const sourceSelector = parseCliSourceSelector(request.source); + if (!sourceSelector) { + return yield* cliServiceErr({ + detail: "source must include provider and sourceKey", + key: "SOURCE_REQUEST_INVALID", + }); + } + + const access = yield* Result.await( + resolveAuthorizedSourceRequestState( + "source.write", + request.orgSlug, + context + ) + ); + const provider = yield* fromCliSourceProvider( + sourceSelector.sourceProvider + ); + const result = await updateCliSource({ + credentialsPatch: request.credentials, + db: access.c.var.storage.db, + masterEncryptionKey: access.c.var.runtime.crypto.masterEncryptionKey, + organizationId: access.authorizedOrg.org.id, + sourceKey: sourceSelector.sourceKey, + sourceProvider: provider, + }); + + switch (result.kind) { + case "not_found": + return Result.err( + createCliSourceNotFoundFailure( + access.authorizedOrg.org.slug, + sourceSelector.sourceKey + ) + ); + case "invalid_credentials": + return yield* cliServiceErr({ + detail: result.detail, + key: "SOURCE_REQUEST_INVALID", + }); + case "connection_test_failed": + return yield* cliServiceErr({ + detail: result.detail, + errors: [ + { + code: "connection_test_failed", + field: "credentials", + message: result.message, + }, + ], + key: "SOURCE_REQUEST_INVALID", + }); + case "updated": + logCliEvent({ + details: buildCliRequestLogDetails(access.c, { + orgSlug: access.authorizedOrg.org.slug, + provider: result.source.provider, + roles: access.authorizedOrg.membershipRoles, + sourceKey: result.source.sourceKey, + }), + event: "source.update.completed", + level: "info", + }); + return Result.ok( + buildUpdateSourceResponse({ + outcome: result.test, + source: result.source, + }) satisfies UpdateSourceResponseInit + ); + } + }); + +const handleDeleteSourceImpl: CliResultServiceMethod<"deleteSource"> = async ( + request, + context +) => + Result.gen(async function* handleDeleteSourceFlow() { + const sourceSelector = parseCliSourceSelector(request.source); + if (!sourceSelector) { + return yield* cliServiceErr({ + detail: "source must include provider and sourceKey", + key: "SOURCE_REQUEST_INVALID", + }); + } + + const access = yield* Result.await( + resolveAuthorizedSourceRequestState( + "source.write", + request.orgSlug, + context + ) + ); + const provider = yield* fromCliSourceProvider( + sourceSelector.sourceProvider + ); + const result = await deleteCliSource({ + db: access.c.var.storage.db, + organizationId: access.authorizedOrg.org.id, + sourceKey: sourceSelector.sourceKey, + sourceProvider: provider, + }); + if (result.kind === "not_found") { + return Result.err( + createCliSourceNotFoundFailure( + access.authorizedOrg.org.slug, + sourceSelector.sourceKey + ) + ); + } + + logCliEvent({ + details: buildCliRequestLogDetails(access.c, { + orgSlug: access.authorizedOrg.org.slug, + provider: result.source.provider, + roles: access.authorizedOrg.membershipRoles, + sourceKey: result.source.sourceKey, + }), + event: "source.delete.completed", + level: "info", + }); + return Result.ok({ + deleted: true, + source: buildCliSource(result.source), + } satisfies DeleteSourceResponseInit); + }); + export const handleListSources = liftCliServiceMethod(handleListSourcesImpl); export const handleListSourceProviders = liftCliServiceMethod( @@ -433,6 +568,10 @@ export const handleConnectSource = liftCliServiceMethod( handleConnectSourceImpl ); +export const handleUpdateSource = liftCliServiceMethod(handleUpdateSourceImpl); + +export const handleDeleteSource = liftCliServiceMethod(handleDeleteSourceImpl); + async function resolveAuthorizedSourceRequestState( action: CliAction, orgSlug: string, diff --git a/packages/cli-server/src/connect/service/source/index.ts b/packages/cli-server/src/connect/service/source/index.ts index 1269ba77..c9f8f30c 100644 --- a/packages/cli-server/src/connect/service/source/index.ts +++ b/packages/cli-server/src/connect/service/source/index.ts @@ -1,8 +1,10 @@ export { handleConnectSource, + handleDeleteSource, handleGetSource, handleGetSourceConnectGuide, handleListSourceProviders, handleListSources, handleTestSource, + handleUpdateSource, } from "./handlers"; diff --git a/packages/cli-server/src/connect/service/source/response.ts b/packages/cli-server/src/connect/service/source/response.ts index afcb6ad0..bf06d638 100644 --- a/packages/cli-server/src/connect/service/source/response.ts +++ b/packages/cli-server/src/connect/service/source/response.ts @@ -13,6 +13,7 @@ import type { CliSourceInit, GetSourceResponseInit, TestSourceResponseInit, + UpdateSourceResponseInit, } from "./types"; export function toCliContentFormat(value: "markdown") { @@ -129,3 +130,25 @@ export function buildTestSourceResponse(input: { }; return response; } + +export function buildUpdateSourceResponse(input: { + source: BuildCliSourceInput; + outcome: + | { + kind: "supported"; + success: true; + message: string; + latencyMs: number; + } + | { + kind: "unsupported"; + reason: "oauth" | "not_implemented"; + message: string; + }; +}): UpdateSourceResponseInit { + const tested = buildTestSourceResponse(input); + return { + source: tested.source, + outcome: tested.outcome, + }; +} diff --git a/packages/cli-server/src/connect/service/source/types.ts b/packages/cli-server/src/connect/service/source/types.ts index 49a04c15..f336c7fa 100644 --- a/packages/cli-server/src/connect/service/source/types.ts +++ b/packages/cli-server/src/connect/service/source/types.ts @@ -10,6 +10,8 @@ import { GetSourceConnectGuideResponseSchema, GetSourceResponseSchema, TestSourceResponseSchema, + UpdateSourceResponseSchema, + DeleteSourceResponseSchema, } from "@onequery/proto-cli/cli/v1/source_pb"; export type GetSourceConnectGuideResponseInit = MessageInitShape< @@ -25,6 +27,12 @@ export type GetSourceResponseInit = MessageInitShape< export type TestSourceResponseInit = MessageInitShape< typeof TestSourceResponseSchema >; +export type UpdateSourceResponseInit = MessageInitShape< + typeof UpdateSourceResponseSchema +>; +export type DeleteSourceResponseInit = MessageInitShape< + typeof DeleteSourceResponseSchema +>; export type ParsedConnectSourceCredentials = { provider: ProviderType; diff --git a/packages/cli-server/src/source/credential-patch.test.ts b/packages/cli-server/src/source/credential-patch.test.ts new file mode 100644 index 00000000..3aacb46a --- /dev/null +++ b/packages/cli-server/src/source/credential-patch.test.ts @@ -0,0 +1,52 @@ +import { describe, expect, it } from "vitest"; + +import { mergeSourceCredentialPatch } from "./credential-patch"; + +describe("mergeSourceCredentialPatch", () => { + it("retains omitted secrets while replacing requested credential fields", () => { + expect( + mergeSourceCredentialPatch( + { + authToken: "secret-token", + organizationSlug: "getgpt", + type: "sentry", + }, + { organizationSlug: "wordbricks" } + ) + ).toEqual({ + ok: true, + value: { + authToken: "secret-token", + organizationSlug: "wordbricks", + type: "sentry", + }, + }); + }); + + it.each([null, [], {}, "credentials", 42])( + "rejects a non-object or empty credential patch: %j", + (patch) => { + expect( + mergeSourceCredentialPatch( + { authToken: "secret-token", type: "sentry" }, + patch + ) + ).toEqual({ + detail: "credentials must be a non-empty JSON object", + ok: false, + }); + } + ); + + it("rejects credential type changes", () => { + expect( + mergeSourceCredentialPatch( + { authToken: "secret-token", type: "sentry" }, + { type: "github" } + ) + ).toEqual({ + detail: 'credentials.type must remain "sentry"', + ok: false, + }); + }); +}); diff --git a/packages/cli-server/src/source/credential-patch.ts b/packages/cli-server/src/source/credential-patch.ts new file mode 100644 index 00000000..5a66abef --- /dev/null +++ b/packages/cli-server/src/source/credential-patch.ts @@ -0,0 +1,45 @@ +type CredentialPatchResult = + | { ok: true; value: Record } + | { ok: false; detail: string }; + +export function mergeSourceCredentialPatch( + current: Record, + patch: unknown +): CredentialPatchResult { + if (!isNonEmptyRecord(patch)) { + return { + detail: "credentials must be a non-empty JSON object", + ok: false, + }; + } + + const currentType = current.type; + if ( + typeof currentType === "string" && + patch.type !== undefined && + patch.type !== currentType + ) { + return { + detail: `credentials.type must remain "${currentType}"`, + ok: false, + }; + } + + return { + ok: true, + value: { + ...current, + ...patch, + ...(typeof currentType === "string" ? { type: currentType } : {}), + }, + }; +} + +function isNonEmptyRecord(value: unknown): value is Record { + return ( + typeof value === "object" && + value !== null && + !Array.isArray(value) && + Object.keys(value).length > 0 + ); +} diff --git a/packages/cli-server/src/source/mutations.test.ts b/packages/cli-server/src/source/mutations.test.ts new file mode 100644 index 00000000..629e41fe --- /dev/null +++ b/packages/cli-server/src/source/mutations.test.ts @@ -0,0 +1,188 @@ +import { Result } from "better-result"; +import { beforeEach, describe, expect, it, vi } from "vitest"; + +import { deleteCliSource, updateCliSource } from "./mutations"; + +describe("CLI source mutations", () => { + const loadSource = vi.fn(); + const decryptCredentials = vi.fn(); + const encryptCredentials = vi.fn(); + const testCredentials = vi.fn(); + + beforeEach(() => { + vi.clearAllMocks(); + loadSource.mockResolvedValue({ + kind: "found", + source: { + credentialsEncrypted: "encrypted-current", + credentialsIv: "iv-current", + displayName: null, + id: "source-1", + name: "getgpt-sentry", + organizationId: "org-1", + provider: "sentry", + sourceKey: "getgpt-sentry", + status: "error", + }, + }); + decryptCredentials.mockReturnValue( + Result.ok({ + authToken: "secret-token", + organizationSlug: "wrong-slug", + projectSlug: "frontend", + type: "sentry", + }) + ); + encryptCredentials.mockReturnValue({ + ciphertext: "encrypted-updated", + iv: "iv-updated", + }); + testCredentials.mockResolvedValue({ + kind: "supported", + result: { + latencyMs: 21, + message: "Connected to Sentry", + success: true, + }, + }); + }); + + const updateDependencies = { + decryptCredentials, + encryptCredentials, + loadSource, + testCredentials, + }; + + const deleteDependencies = { loadSource }; + + it("tests and persists a merged credential patch", async () => { + let persisted: Record | undefined; + const db = { + update: vi.fn(() => ({ + set: vi.fn((values: Record) => { + persisted = values; + return { + where: vi.fn(() => ({ + returning: vi.fn(async () => [ + { + id: "source-1", + name: "getgpt-sentry", + provider: "sentry", + status: "active", + }, + ]), + })), + }; + }), + })), + }; + + const result = await updateCliSource( + { + credentialsPatch: { organizationSlug: "wordbricks" }, + db: db as never, + masterEncryptionKey: new Uint8Array(32), + organizationId: "org-1", + sourceKey: "getgpt-sentry", + sourceProvider: "sentry", + }, + updateDependencies as never + ); + + expect(testCredentials).toHaveBeenCalledWith( + expect.objectContaining({ + credentials: expect.objectContaining({ + authToken: "secret-token", + organizationSlug: "wordbricks", + }), + organizationId: "org-1", + }) + ); + expect(persisted).toMatchObject({ + credentialsEncrypted: "encrypted-updated", + credentialsIv: "iv-updated", + errorMessage: null, + status: "active", + }); + expect(result).toMatchObject({ + kind: "updated", + source: { sourceKey: "getgpt-sentry", provider: "sentry" }, + test: { latencyMs: 21, kind: "supported" }, + }); + }); + + it("does not persist credentials when the connection test fails", async () => { + const update = vi.fn(); + testCredentials.mockResolvedValueOnce({ + kind: "supported", + result: { + error: "Organization not found", + latencyMs: 10, + message: "Invalid organization slug", + success: false, + }, + }); + + const result = await updateCliSource( + { + credentialsPatch: { organizationSlug: "still-wrong" }, + db: { update } as never, + masterEncryptionKey: new Uint8Array(32), + organizationId: "org-1", + sourceKey: "getgpt-sentry", + sourceProvider: "sentry", + }, + updateDependencies as never + ); + + expect(result).toEqual({ + detail: "Organization not found", + kind: "connection_test_failed", + message: "Invalid organization slug", + }); + expect(update).not.toHaveBeenCalled(); + }); + + it("rejects credential field typos instead of silently stripping them", async () => { + const result = await updateCliSource( + { + credentialsPatch: { organisationSlug: "wordbricks" }, + db: {} as never, + masterEncryptionKey: new Uint8Array(32), + organizationId: "org-1", + sourceKey: "getgpt-sentry", + sourceProvider: "sentry", + }, + updateDependencies as never + ); + + expect(result).toEqual({ + detail: "unsupported credential field: organisationSlug", + kind: "invalid_credentials", + }); + expect(testCredentials).not.toHaveBeenCalled(); + }); + + it("deletes only the loaded source in the authorized org", async () => { + const returning = vi.fn(async () => [{ id: "source-1" }]); + const where = vi.fn(() => ({ returning })); + const deleteRows = vi.fn(() => ({ where })); + + const result = await deleteCliSource( + { + db: { delete: deleteRows } as never, + organizationId: "org-1", + sourceKey: "getgpt-sentry", + sourceProvider: "sentry", + }, + deleteDependencies as never + ); + + expect(deleteRows).toHaveBeenCalledOnce(); + expect(result).toMatchObject({ + kind: "deleted", + source: { sourceKey: "getgpt-sentry", provider: "sentry" }, + }); + }); +}); diff --git a/packages/cli-server/src/source/mutations.ts b/packages/cli-server/src/source/mutations.ts new file mode 100644 index 00000000..37d4f28e --- /dev/null +++ b/packages/cli-server/src/source/mutations.ts @@ -0,0 +1,281 @@ +import { CredentialsSchema } from "@onequery/db"; +import type { Credentials } from "@onequery/db"; +import { and, dataSources, eq } from "@onequery/db/server"; +import type { Database, ProviderType } from "@onequery/db/server"; +import { safeParseSourceProviderCredentials } from "@onequery/db/source-providers"; +import type { SourceProviderCredentialsParseError } from "@onequery/db/source-providers"; +import { + decryptCredentialsObjectResult, + encryptCredentialsObject, +} from "@onequery/server/services/crypto/credential-encryption"; +import type { EncryptedCredentialsDecodeError } from "@onequery/server/services/crypto/credential-encryption"; +import { + serializeDataSourceTestOutcome, + testDataSource, +} from "@onequery/server/services/data-source-tester"; +import type { Result as ResultType } from "better-result"; + +import type { + CliQuerySourceRecord, + CliSourceRecord, +} from "../domain/workflows"; +import { mergeSourceCredentialPatch } from "./credential-patch"; +import { runCliLoadSourceEffect } from "./effects"; +import { createCliSourceRecord } from "./model"; + +type CliSourceUpdateDependencies = { + decryptCredentials(input: { + credentialsEncrypted: string; + credentialsIv: string; + masterEncryptionKey: Uint8Array; + }): ResultType; + encryptCredentials( + credentials: Credentials, + masterEncryptionKey: Uint8Array + ): ReturnType; + loadSource: typeof runCliLoadSourceEffect; + testCredentials(input: { + credentials: Credentials; + db: Database; + organizationId: string; + }): Promise>; +}; + +type CliSourceDeleteDependencies = Pick< + CliSourceUpdateDependencies, + "loadSource" +>; + +const defaultUpdateDependencies: CliSourceUpdateDependencies = { + decryptCredentials: (input) => + decryptCredentialsObjectResult( + input.credentialsEncrypted, + input.credentialsIv, + input.masterEncryptionKey, + CredentialsSchema + ), + encryptCredentials: encryptCredentialsObject, + loadSource: runCliLoadSourceEffect, + testCredentials: async (input) => + serializeDataSourceTestOutcome( + await testDataSource(input.credentials, { + db: input.db, + organizationId: input.organizationId, + }) + ), +}; + +const defaultDeleteDependencies: CliSourceDeleteDependencies = { + loadSource: runCliLoadSourceEffect, +}; + +export type CliSourceMutationTest = + | { + kind: "supported"; + success: true; + message: string; + latencyMs: number; + } + | { + kind: "unsupported"; + reason: "oauth" | "not_implemented"; + message: string; + }; + +export type CliSourceUpdateResult = + | { + kind: "updated"; + source: CliSourceRecord; + test: CliSourceMutationTest; + } + | { kind: "not_found" } + | { kind: "invalid_credentials"; detail: string } + | { kind: "connection_test_failed"; detail: string; message: string }; + +export type CliSourceDeleteResult = + | { kind: "deleted"; source: CliSourceRecord } + | { kind: "not_found" }; + +export async function updateCliSource( + input: { + db: Database; + organizationId: string; + sourceKey: string; + sourceProvider?: ProviderType; + credentialsPatch: unknown; + masterEncryptionKey: Uint8Array; + }, + dependencies = defaultUpdateDependencies +): Promise { + const loaded = await loadSource(input, dependencies); + if (!loaded) { + return { kind: "not_found" }; + } + + const currentCredentials = dependencies.decryptCredentials({ + credentialsEncrypted: loaded.credentialsEncrypted, + credentialsIv: loaded.credentialsIv, + masterEncryptionKey: input.masterEncryptionKey, + }); + if (currentCredentials.isErr()) { + return { + detail: currentCredentials.error.message, + kind: "invalid_credentials", + }; + } + + const merged = mergeSourceCredentialPatch( + currentCredentials.value, + input.credentialsPatch + ); + if (!merged.ok) { + return { detail: merged.detail, kind: "invalid_credentials" }; + } + + const parsed = safeParseSourceProviderCredentials({ + credentials: merged.value, + provider: loaded.provider, + }); + if (!parsed.success) { + return { + detail: sourceCredentialsErrorDetail(parsed.error), + kind: "invalid_credentials", + }; + } + + const unsupportedPatchFields = Object.keys( + input.credentialsPatch as Record + ).filter((field) => !(field in parsed.data.credentials)); + if (unsupportedPatchFields.length > 0) { + return { + detail: `unsupported credential field${unsupportedPatchFields.length === 1 ? "" : "s"}: ${unsupportedPatchFields.join(", ")}`, + kind: "invalid_credentials", + }; + } + + const test = await dependencies.testCredentials({ + credentials: parsed.data.credentials, + db: input.db, + organizationId: input.organizationId, + }); + if (test.kind === "supported" && !test.result.success) { + return { + detail: test.result.error, + kind: "connection_test_failed", + message: test.result.message, + }; + } + + const encrypted = dependencies.encryptCredentials( + parsed.data.credentials, + input.masterEncryptionKey + ); + const now = new Date(); + const [updated] = await input.db + .update(dataSources) + .set({ + credentialsEncrypted: encrypted.ciphertext, + credentialsIv: encrypted.iv, + errorMessage: null, + lastUsedAt: now, + status: "active", + updatedAt: now, + }) + .where( + and( + eq(dataSources.id, loaded.id), + eq(dataSources.organizationId, input.organizationId) + ) + ) + .returning({ + id: dataSources.id, + name: dataSources.name, + provider: dataSources.provider, + status: dataSources.status, + }); + const source = updated ? createCliSourceRecord(updated) : null; + if (!source) { + return { kind: "not_found" }; + } + + return { + kind: "updated", + source, + test: + test.kind === "supported" + ? { + kind: "supported", + latencyMs: test.result.latencyMs, + message: test.result.message, + success: true, + } + : test, + }; +} + +export async function deleteCliSource( + input: { + db: Database; + organizationId: string; + sourceKey: string; + sourceProvider?: ProviderType; + }, + dependencies = defaultDeleteDependencies +): Promise { + const loaded = await loadSource(input, dependencies); + if (!loaded) { + return { kind: "not_found" }; + } + + const source = createCliSourceRecord(loaded); + if (!source) { + return { kind: "not_found" }; + } + const deleted = await input.db + .delete(dataSources) + .where( + and( + eq(dataSources.id, loaded.id), + eq(dataSources.organizationId, input.organizationId) + ) + ) + .returning({ id: dataSources.id }); + + return deleted.length > 0 + ? { kind: "deleted", source } + : { kind: "not_found" }; +} + +async function loadSource( + input: { + db: Database; + organizationId: string; + sourceKey: string; + sourceProvider?: ProviderType; + }, + dependencies: CliSourceDeleteDependencies +): Promise { + const loaded = await dependencies.loadSource({ + db: input.db, + effect: { + kind: "load_source", + organizationId: input.organizationId, + sourceKey: input.sourceKey, + sourceProvider: input.sourceProvider, + }, + }); + return loaded.kind === "found" ? loaded.source : null; +} + +function sourceCredentialsErrorDetail( + error: SourceProviderCredentialsParseError +): string { + switch (error.code) { + case "invalid_credentials": + return error.error.issues[0]?.message ?? "invalid source credentials"; + case "provider_credentials_mismatch": + return `credentials type "${error.credentialsType}" does not match provider "${error.provider}"`; + case "unsupported_provider": + return `unsupported source provider "${error.provider}"`; + } +} diff --git a/packages/proto-cli/src/onequery/cli/v1/cli_pb.ts b/packages/proto-cli/src/onequery/cli/v1/cli_pb.ts index 098c3405..8f94e268 100644 --- a/packages/proto-cli/src/onequery/cli/v1/cli_pb.ts +++ b/packages/proto-cli/src/onequery/cli/v1/cli_pb.ts @@ -44,6 +44,8 @@ import { file_onequery_cli_v1_source_api } from "./source_api_pb.js"; import type { ConnectSourceRequestSchema, ConnectSourceResponseSchema, + DeleteSourceRequestSchema, + DeleteSourceResponseSchema, GetSourceConnectGuideRequestSchema, GetSourceConnectGuideResponseSchema, GetSourceRequestSchema, @@ -54,6 +56,8 @@ import type { ListSourcesResponseSchema, TestSourceRequestSchema, TestSourceResponseSchema, + UpdateSourceRequestSchema, + UpdateSourceResponseSchema, } from "./source_pb.js"; import { file_onequery_cli_v1_source } from "./source_pb.js"; @@ -61,7 +65,7 @@ import { file_onequery_cli_v1_source } from "./source_pb.js"; * Describes the file onequery/cli/v1/cli.proto. */ export const file_onequery_cli_v1_cli: GenFile /*@__PURE__*/ = fileDesc( - "ChlvbmVxdWVyeS9jbGkvdjEvY2xpLnByb3RvEg9vbmVxdWVyeS5jbGkudjEyzgMKDkNsaUF1dGhTZXJ2aWNlEloKCkdldFNlc3Npb24SIi5vbmVxdWVyeS5jbGkudjEuR2V0U2Vzc2lvblJlcXVlc3QaIy5vbmVxdWVyeS5jbGkudjEuR2V0U2Vzc2lvblJlc3BvbnNlIgOQAgESYQoOUmVmcmVzaFNlc3Npb24SJi5vbmVxdWVyeS5jbGkudjEuUmVmcmVzaFNlc3Npb25SZXF1ZXN0Gicub25lcXVlcnkuY2xpLnYxLlJlZnJlc2hTZXNzaW9uUmVzcG9uc2USfwoYU3RhcnREZXZpY2VBdXRob3JpemF0aW9uEjAub25lcXVlcnkuY2xpLnYxLlN0YXJ0RGV2aWNlQXV0aG9yaXphdGlvblJlcXVlc3QaMS5vbmVxdWVyeS5jbGkudjEuU3RhcnREZXZpY2VBdXRob3JpemF0aW9uUmVzcG9uc2USfAoXUG9sbERldmljZUF1dGhvcml6YXRpb24SLy5vbmVxdWVyeS5jbGkudjEuUG9sbERldmljZUF1dGhvcml6YXRpb25SZXF1ZXN0GjAub25lcXVlcnkuY2xpLnYxLlBvbGxEZXZpY2VBdXRob3JpemF0aW9uUmVzcG9uc2Uy9AEKFkNsaU9yZ2FuaXphdGlvblNlcnZpY2USbwoRTGlzdE9yZ2FuaXphdGlvbnMSKS5vbmVxdWVyeS5jbGkudjEuTGlzdE9yZ2FuaXphdGlvbnNSZXF1ZXN0Gioub25lcXVlcnkuY2xpLnYxLkxpc3RPcmdhbml6YXRpb25zUmVzcG9uc2UiA5ACARJpCg9HZXRPcmdhbml6YXRpb24SJy5vbmVxdWVyeS5jbGkudjEuR2V0T3JnYW5pemF0aW9uUmVxdWVzdBooLm9uZXF1ZXJ5LmNsaS52MS5HZXRPcmdhbml6YXRpb25SZXNwb25zZSIDkAIBMvUEChBDbGlTb3VyY2VTZXJ2aWNlEnUKE0xpc3RTb3VyY2VQcm92aWRlcnMSKy5vbmVxdWVyeS5jbGkudjEuTGlzdFNvdXJjZVByb3ZpZGVyc1JlcXVlc3QaLC5vbmVxdWVyeS5jbGkudjEuTGlzdFNvdXJjZVByb3ZpZGVyc1Jlc3BvbnNlIgOQAgESXQoLTGlzdFNvdXJjZXMSIy5vbmVxdWVyeS5jbGkudjEuTGlzdFNvdXJjZXNSZXF1ZXN0GiQub25lcXVlcnkuY2xpLnYxLkxpc3RTb3VyY2VzUmVzcG9uc2UiA5ACARJ7ChVHZXRTb3VyY2VDb25uZWN0R3VpZGUSLS5vbmVxdWVyeS5jbGkudjEuR2V0U291cmNlQ29ubmVjdEd1aWRlUmVxdWVzdBouLm9uZXF1ZXJ5LmNsaS52MS5HZXRTb3VyY2VDb25uZWN0R3VpZGVSZXNwb25zZSIDkAIBEl4KDUNvbm5lY3RTb3VyY2USJS5vbmVxdWVyeS5jbGkudjEuQ29ubmVjdFNvdXJjZVJlcXVlc3QaJi5vbmVxdWVyeS5jbGkudjEuQ29ubmVjdFNvdXJjZVJlc3BvbnNlElcKCUdldFNvdXJjZRIhLm9uZXF1ZXJ5LmNsaS52MS5HZXRTb3VyY2VSZXF1ZXN0GiIub25lcXVlcnkuY2xpLnYxLkdldFNvdXJjZVJlc3BvbnNlIgOQAgESVQoKVGVzdFNvdXJjZRIiLm9uZXF1ZXJ5LmNsaS52MS5UZXN0U291cmNlUmVxdWVzdBojLm9uZXF1ZXJ5LmNsaS52MS5UZXN0U291cmNlUmVzcG9uc2UyuQMKE0NsaVNvdXJjZUFwaVNlcnZpY2USagoRRGVzY3JpYmVTb3VyY2VBcGkSKS5vbmVxdWVyeS5jbGkudjEuRGVzY3JpYmVTb3VyY2VBcGlSZXF1ZXN0Gioub25lcXVlcnkuY2xpLnYxLkRlc2NyaWJlU291cmNlQXBpUmVzcG9uc2USZwoQUHJldmlld1NvdXJjZUFwaRIoLm9uZXF1ZXJ5LmNsaS52MS5QcmV2aWV3U291cmNlQXBpUmVxdWVzdBopLm9uZXF1ZXJ5LmNsaS52MS5QcmV2aWV3U291cmNlQXBpUmVzcG9uc2USZwoQRXhlY3V0ZVNvdXJjZUFwaRIoLm9uZXF1ZXJ5LmNsaS52MS5FeGVjdXRlU291cmNlQXBpUmVxdWVzdBopLm9uZXF1ZXJ5LmNsaS52MS5FeGVjdXRlU291cmNlQXBpUmVzcG9uc2USZAoPUmVzdW1lU291cmNlQXBpEicub25lcXVlcnkuY2xpLnYxLlJlc3VtZVNvdXJjZUFwaVJlcXVlc3QaKC5vbmVxdWVyeS5jbGkudjEuUmVzdW1lU291cmNlQXBpUmVzcG9uc2UyzgEKD0NsaVF1ZXJ5U2VydmljZRJeCg1WYWxpZGF0ZVF1ZXJ5EiUub25lcXVlcnkuY2xpLnYxLlZhbGlkYXRlUXVlcnlSZXF1ZXN0GiYub25lcXVlcnkuY2xpLnYxLlZhbGlkYXRlUXVlcnlSZXNwb25zZRJbCgxFeGVjdXRlUXVlcnkSJC5vbmVxdWVyeS5jbGkudjEuRXhlY3V0ZVF1ZXJ5UmVxdWVzdBolLm9uZXF1ZXJ5LmNsaS52MS5FeGVjdXRlUXVlcnlSZXNwb25zZWIIZWRpdGlvbnNw6Ac", + "ChlvbmVxdWVyeS9jbGkvdjEvY2xpLnByb3RvEg9vbmVxdWVyeS5jbGkudjEyzgMKDkNsaUF1dGhTZXJ2aWNlEloKCkdldFNlc3Npb24SIi5vbmVxdWVyeS5jbGkudjEuR2V0U2Vzc2lvblJlcXVlc3QaIy5vbmVxdWVyeS5jbGkudjEuR2V0U2Vzc2lvblJlc3BvbnNlIgOQAgESYQoOUmVmcmVzaFNlc3Npb24SJi5vbmVxdWVyeS5jbGkudjEuUmVmcmVzaFNlc3Npb25SZXF1ZXN0Gicub25lcXVlcnkuY2xpLnYxLlJlZnJlc2hTZXNzaW9uUmVzcG9uc2USfwoYU3RhcnREZXZpY2VBdXRob3JpemF0aW9uEjAub25lcXVlcnkuY2xpLnYxLlN0YXJ0RGV2aWNlQXV0aG9yaXphdGlvblJlcXVlc3QaMS5vbmVxdWVyeS5jbGkudjEuU3RhcnREZXZpY2VBdXRob3JpemF0aW9uUmVzcG9uc2USfAoXUG9sbERldmljZUF1dGhvcml6YXRpb24SLy5vbmVxdWVyeS5jbGkudjEuUG9sbERldmljZUF1dGhvcml6YXRpb25SZXF1ZXN0GjAub25lcXVlcnkuY2xpLnYxLlBvbGxEZXZpY2VBdXRob3JpemF0aW9uUmVzcG9uc2Uy9AEKFkNsaU9yZ2FuaXphdGlvblNlcnZpY2USbwoRTGlzdE9yZ2FuaXphdGlvbnMSKS5vbmVxdWVyeS5jbGkudjEuTGlzdE9yZ2FuaXphdGlvbnNSZXF1ZXN0Gioub25lcXVlcnkuY2xpLnYxLkxpc3RPcmdhbml6YXRpb25zUmVzcG9uc2UiA5ACARJpCg9HZXRPcmdhbml6YXRpb24SJy5vbmVxdWVyeS5jbGkudjEuR2V0T3JnYW5pemF0aW9uUmVxdWVzdBooLm9uZXF1ZXJ5LmNsaS52MS5HZXRPcmdhbml6YXRpb25SZXNwb25zZSIDkAIBMq8GChBDbGlTb3VyY2VTZXJ2aWNlEnUKE0xpc3RTb3VyY2VQcm92aWRlcnMSKy5vbmVxdWVyeS5jbGkudjEuTGlzdFNvdXJjZVByb3ZpZGVyc1JlcXVlc3QaLC5vbmVxdWVyeS5jbGkudjEuTGlzdFNvdXJjZVByb3ZpZGVyc1Jlc3BvbnNlIgOQAgESXQoLTGlzdFNvdXJjZXMSIy5vbmVxdWVyeS5jbGkudjEuTGlzdFNvdXJjZXNSZXF1ZXN0GiQub25lcXVlcnkuY2xpLnYxLkxpc3RTb3VyY2VzUmVzcG9uc2UiA5ACARJ7ChVHZXRTb3VyY2VDb25uZWN0R3VpZGUSLS5vbmVxdWVyeS5jbGkudjEuR2V0U291cmNlQ29ubmVjdEd1aWRlUmVxdWVzdBouLm9uZXF1ZXJ5LmNsaS52MS5HZXRTb3VyY2VDb25uZWN0R3VpZGVSZXNwb25zZSIDkAIBEl4KDUNvbm5lY3RTb3VyY2USJS5vbmVxdWVyeS5jbGkudjEuQ29ubmVjdFNvdXJjZVJlcXVlc3QaJi5vbmVxdWVyeS5jbGkudjEuQ29ubmVjdFNvdXJjZVJlc3BvbnNlElcKCUdldFNvdXJjZRIhLm9uZXF1ZXJ5LmNsaS52MS5HZXRTb3VyY2VSZXF1ZXN0GiIub25lcXVlcnkuY2xpLnYxLkdldFNvdXJjZVJlc3BvbnNlIgOQAgESVQoKVGVzdFNvdXJjZRIiLm9uZXF1ZXJ5LmNsaS52MS5UZXN0U291cmNlUmVxdWVzdBojLm9uZXF1ZXJ5LmNsaS52MS5UZXN0U291cmNlUmVzcG9uc2USWwoMVXBkYXRlU291cmNlEiQub25lcXVlcnkuY2xpLnYxLlVwZGF0ZVNvdXJjZVJlcXVlc3QaJS5vbmVxdWVyeS5jbGkudjEuVXBkYXRlU291cmNlUmVzcG9uc2USWwoMRGVsZXRlU291cmNlEiQub25lcXVlcnkuY2xpLnYxLkRlbGV0ZVNvdXJjZVJlcXVlc3QaJS5vbmVxdWVyeS5jbGkudjEuRGVsZXRlU291cmNlUmVzcG9uc2UyuQMKE0NsaVNvdXJjZUFwaVNlcnZpY2USagoRRGVzY3JpYmVTb3VyY2VBcGkSKS5vbmVxdWVyeS5jbGkudjEuRGVzY3JpYmVTb3VyY2VBcGlSZXF1ZXN0Gioub25lcXVlcnkuY2xpLnYxLkRlc2NyaWJlU291cmNlQXBpUmVzcG9uc2USZwoQUHJldmlld1NvdXJjZUFwaRIoLm9uZXF1ZXJ5LmNsaS52MS5QcmV2aWV3U291cmNlQXBpUmVxdWVzdBopLm9uZXF1ZXJ5LmNsaS52MS5QcmV2aWV3U291cmNlQXBpUmVzcG9uc2USZwoQRXhlY3V0ZVNvdXJjZUFwaRIoLm9uZXF1ZXJ5LmNsaS52MS5FeGVjdXRlU291cmNlQXBpUmVxdWVzdBopLm9uZXF1ZXJ5LmNsaS52MS5FeGVjdXRlU291cmNlQXBpUmVzcG9uc2USZAoPUmVzdW1lU291cmNlQXBpEicub25lcXVlcnkuY2xpLnYxLlJlc3VtZVNvdXJjZUFwaVJlcXVlc3QaKC5vbmVxdWVyeS5jbGkudjEuUmVzdW1lU291cmNlQXBpUmVzcG9uc2UyzgEKD0NsaVF1ZXJ5U2VydmljZRJeCg1WYWxpZGF0ZVF1ZXJ5EiUub25lcXVlcnkuY2xpLnYxLlZhbGlkYXRlUXVlcnlSZXF1ZXN0GiYub25lcXVlcnkuY2xpLnYxLlZhbGlkYXRlUXVlcnlSZXNwb25zZRJbCgxFeGVjdXRlUXVlcnkSJC5vbmVxdWVyeS5jbGkudjEuRXhlY3V0ZVF1ZXJ5UmVxdWVzdBolLm9uZXF1ZXJ5LmNsaS52MS5FeGVjdXRlUXVlcnlSZXNwb25zZWIIZWRpdGlvbnNw6Ac", [ file_onequery_cli_v1_auth, file_onequery_cli_v1_org, @@ -183,6 +187,22 @@ export const CliSourceService: GenService<{ input: typeof TestSourceRequestSchema; output: typeof TestSourceResponseSchema; }; + /** + * @generated from rpc onequery.cli.v1.CliSourceService.UpdateSource + */ + updateSource: { + methodKind: "unary"; + input: typeof UpdateSourceRequestSchema; + output: typeof UpdateSourceResponseSchema; + }; + /** + * @generated from rpc onequery.cli.v1.CliSourceService.DeleteSource + */ + deleteSource: { + methodKind: "unary"; + input: typeof DeleteSourceRequestSchema; + output: typeof DeleteSourceResponseSchema; + }; }> /*@__PURE__*/ = serviceDesc(file_onequery_cli_v1_cli, 2); /** diff --git a/packages/proto-cli/src/onequery/cli/v1/org_pb.ts b/packages/proto-cli/src/onequery/cli/v1/org_pb.ts index 9d0dff4f..3d445348 100644 --- a/packages/proto-cli/src/onequery/cli/v1/org_pb.ts +++ b/packages/proto-cli/src/onequery/cli/v1/org_pb.ts @@ -20,7 +20,7 @@ import { file_onequery_cli_v1_common } from "./common_pb.js"; * Describes the file onequery/cli/v1/org.proto. */ export const file_onequery_cli_v1_org: GenFile /*@__PURE__*/ = fileDesc( - "ChlvbmVxdWVyeS9jbGkvdjEvb3JnLnByb3RvEg9vbmVxdWVyeS5jbGkudjEiSQoYTGlzdE9yZ2FuaXphdGlvbnNSZXF1ZXN0Ei0KBHBhZ2UYASABKAsyHy5vbmVxdWVyeS5jbGkudjEuQ2xpUGFnZVJlcXVlc3QilQEKGUxpc3RPcmdhbml6YXRpb25zUmVzcG9uc2USSAoNb3JnYW5pemF0aW9ucxgBIAMoCzInLm9uZXF1ZXJ5LmNsaS52MS5DbGlPcmdhbml6YXRpb25TdW1tYXJ5Qgi6SAWSAQIQZBIuCgRwYWdlGAIgASgLMhgub25lcXVlcnkuY2xpLnYxLkNsaVBhZ2VCBrpIA8gBASJVChZHZXRPcmdhbml6YXRpb25SZXF1ZXN0EjsKCG9yZ19zbHVnGAEgASgJQim6SCbIAQFyIRABGP8BMhpeW2EtejAtOV0rKD86LVthLXowLTldKykqJCKBAgoXR2V0T3JnYW5pemF0aW9uUmVzcG9uc2USNwoEc2x1ZxgBIAEoCUIpukgmyAEBciEQARj/ATIaXlthLXowLTldKyg/Oi1bYS16MC05XSspKiQSGwoEbmFtZRgCIAEoCUINukgKyAEBcgUQARj/ARJFCgVyb2xlcxgDIAMoDjIhLm9uZXF1ZXJ5LmNsaS52MS5Pcmdhbml6YXRpb25Sb2xlQhO6SBCSAQ0QIBgBIgeCAQQQASAAEkkKDGNhcGFiaWxpdGllcxgEIAMoDjIeLm9uZXF1ZXJ5LmNsaS52MS5PcmdDYXBhYmlsaXR5QhO6SBCSAQ0QIBgBIgeCAQQQASAAIm4KFkNsaU9yZ2FuaXphdGlvblN1bW1hcnkSNwoEc2x1ZxgBIAEoCUIpukgmyAEBciEQARj/ATIaXlthLXowLTldKyg/Oi1bYS16MC05XSspKiQSGwoEbmFtZRgCIAEoCUINukgKyAEBcgUQARj/ASq9AgoNT3JnQ2FwYWJpbGl0eRIeChpPUkdfQ0FQQUJJTElUWV9VTlNQRUNJRklFRBAAEhsKF09SR19DQVBBQklMSVRZX09SR19MSVNUEAESGwoXT1JHX0NBUEFCSUxJVFlfT1JHX1JFQUQQAhIhCh1PUkdfQ0FQQUJJTElUWV9TT1VSQ0VfQ09OTkVDVBADEh4KGk9SR19DQVBBQklMSVRZX1NPVVJDRV9MSVNUEAQSHgoaT1JHX0NBUEFCSUxJVFlfU09VUkNFX1JFQUQQBRIgChxPUkdfQ0FQQUJJTElUWV9RVUVSWV9FWEVDVVRFEAYSJgoiT1JHX0NBUEFCSUxJVFlfU09VUkNFX0FQSV9ERVNDUklCRRAHEiUKIU9SR19DQVBBQklMSVRZX1NPVVJDRV9BUElfRVhFQ1VURRAIKo0BChBPcmdhbml6YXRpb25Sb2xlEiEKHU9SR0FOSVpBVElPTl9ST0xFX1VOU1BFQ0lGSUVEEAASGwoXT1JHQU5JWkFUSU9OX1JPTEVfT1dORVIQARIbChdPUkdBTklaQVRJT05fUk9MRV9BRE1JThACEhwKGE9SR0FOSVpBVElPTl9ST0xFX01FTUJFUhADYghlZGl0aW9uc3DoBw", + "ChlvbmVxdWVyeS9jbGkvdjEvb3JnLnByb3RvEg9vbmVxdWVyeS5jbGkudjEiSQoYTGlzdE9yZ2FuaXphdGlvbnNSZXF1ZXN0Ei0KBHBhZ2UYASABKAsyHy5vbmVxdWVyeS5jbGkudjEuQ2xpUGFnZVJlcXVlc3QilQEKGUxpc3RPcmdhbml6YXRpb25zUmVzcG9uc2USSAoNb3JnYW5pemF0aW9ucxgBIAMoCzInLm9uZXF1ZXJ5LmNsaS52MS5DbGlPcmdhbml6YXRpb25TdW1tYXJ5Qgi6SAWSAQIQZBIuCgRwYWdlGAIgASgLMhgub25lcXVlcnkuY2xpLnYxLkNsaVBhZ2VCBrpIA8gBASJVChZHZXRPcmdhbml6YXRpb25SZXF1ZXN0EjsKCG9yZ19zbHVnGAEgASgJQim6SCbIAQFyIRABGP8BMhpeW2EtejAtOV0rKD86LVthLXowLTldKykqJCKBAgoXR2V0T3JnYW5pemF0aW9uUmVzcG9uc2USNwoEc2x1ZxgBIAEoCUIpukgmyAEBciEQARj/ATIaXlthLXowLTldKyg/Oi1bYS16MC05XSspKiQSGwoEbmFtZRgCIAEoCUINukgKyAEBcgUQARj/ARJFCgVyb2xlcxgDIAMoDjIhLm9uZXF1ZXJ5LmNsaS52MS5Pcmdhbml6YXRpb25Sb2xlQhO6SBCSAQ0QIBgBIgeCAQQQASAAEkkKDGNhcGFiaWxpdGllcxgEIAMoDjIeLm9uZXF1ZXJ5LmNsaS52MS5PcmdDYXBhYmlsaXR5QhO6SBCSAQ0QIBgBIgeCAQQQASAAIm4KFkNsaU9yZ2FuaXphdGlvblN1bW1hcnkSNwoEc2x1ZxgBIAEoCUIpukgmyAEBciEQARj/ATIaXlthLXowLTldKyg/Oi1bYS16MC05XSspKiQSGwoEbmFtZRgCIAEoCUINukgKyAEBcgUQARj/ASreAgoNT3JnQ2FwYWJpbGl0eRIeChpPUkdfQ0FQQUJJTElUWV9VTlNQRUNJRklFRBAAEhsKF09SR19DQVBBQklMSVRZX09SR19MSVNUEAESGwoXT1JHX0NBUEFCSUxJVFlfT1JHX1JFQUQQAhIhCh1PUkdfQ0FQQUJJTElUWV9TT1VSQ0VfQ09OTkVDVBADEh4KGk9SR19DQVBBQklMSVRZX1NPVVJDRV9MSVNUEAQSHgoaT1JHX0NBUEFCSUxJVFlfU09VUkNFX1JFQUQQBRIgChxPUkdfQ0FQQUJJTElUWV9RVUVSWV9FWEVDVVRFEAYSJgoiT1JHX0NBUEFCSUxJVFlfU09VUkNFX0FQSV9ERVNDUklCRRAHEiUKIU9SR19DQVBBQklMSVRZX1NPVVJDRV9BUElfRVhFQ1VURRAIEh8KG09SR19DQVBBQklMSVRZX1NPVVJDRV9XUklURRAJKo0BChBPcmdhbml6YXRpb25Sb2xlEiEKHU9SR0FOSVpBVElPTl9ST0xFX1VOU1BFQ0lGSUVEEAASGwoXT1JHQU5JWkFUSU9OX1JPTEVfT1dORVIQARIbChdPUkdBTklaQVRJT05fUk9MRV9BRE1JThACEhwKGE9SR0FOSVpBVElPTl9ST0xFX01FTUJFUhADYghlZGl0aW9uc3DoBw", [file_buf_validate_validate, file_onequery_cli_v1_common] ); @@ -187,6 +187,11 @@ export enum OrgCapability { * @generated from enum value: ORG_CAPABILITY_SOURCE_API_EXECUTE = 8; */ SOURCE_API_EXECUTE = 8, + + /** + * @generated from enum value: ORG_CAPABILITY_SOURCE_WRITE = 9; + */ + SOURCE_WRITE = 9, } /** diff --git a/packages/proto-cli/src/onequery/cli/v1/source_pb.ts b/packages/proto-cli/src/onequery/cli/v1/source_pb.ts index 4ee87c7d..a6fce606 100644 --- a/packages/proto-cli/src/onequery/cli/v1/source_pb.ts +++ b/packages/proto-cli/src/onequery/cli/v1/source_pb.ts @@ -25,7 +25,7 @@ import { file_onequery_cli_v1_common } from "./common_pb.js"; * Describes the file onequery/cli/v1/source.proto. */ export const file_onequery_cli_v1_source: GenFile /*@__PURE__*/ = fileDesc( - "ChxvbmVxdWVyeS9jbGkvdjEvc291cmNlLnByb3RvEg9vbmVxdWVyeS5jbGkudjEigAEKEkxpc3RTb3VyY2VzUmVxdWVzdBI7Cghvcmdfc2x1ZxgBIAEoCUIpukgmyAEBciEQARj/ATIaXlthLXowLTldKyg/Oi1bYS16MC05XSspKiQSLQoEcGFnZRgCIAEoCzIfLm9uZXF1ZXJ5LmNsaS52MS5DbGlQYWdlUmVxdWVzdCJ8ChNMaXN0U291cmNlc1Jlc3BvbnNlEjUKB3NvdXJjZXMYASADKAsyGi5vbmVxdWVyeS5jbGkudjEuQ2xpU291cmNlQgi6SAWSAQIQZBIuCgRwYWdlGAIgASgLMhgub25lcXVlcnkuY2xpLnYxLkNsaVBhZ2VCBrpIA8gBASJZChpMaXN0U291cmNlUHJvdmlkZXJzUmVxdWVzdBI7Cghvcmdfc2x1ZxgBIAEoCUIpukgmyAEBciEQARj/ATIaXlthLXowLTldKyg/Oi1bYS16MC05XSspKiQiXgobTGlzdFNvdXJjZVByb3ZpZGVyc1Jlc3BvbnNlEj8KCXByb3ZpZGVycxgBIAMoCzIiLm9uZXF1ZXJ5LmNsaS52MS5DbGlTb3VyY2VQcm92aWRlckIIukgFkgECEGQi0wIKEUNsaVNvdXJjZVByb3ZpZGVyEjIKCHByb3ZpZGVyGAEgASgJQiC6SB3IAQFyGBABGIABMhFeW2Etel1bYS16MC05X10qJBIgCgVsYWJlbBgCIAEoCUIRukgOyAEBcgkQARiAATICXFMSEwoLY29ubmVjdGFibGUYAyABKAgSEAoIdGVzdGFibGUYBCABKAgSSQoKaW50ZXJmYWNlcxgFIAMoDjIgLm9uZXF1ZXJ5LmNsaS52MS5Tb3VyY2VJbnRlcmZhY2VCE7pIEJIBDRACGAEiB4IBBBABIAASOQoPY3JlZGVudGlhbF90eXBlGAYgASgJQiC6SB3IAQFyGBABGIABMhFeW2Etel1bYS16MC05X10qJBI7ChJjcmVkZW50aWFsX2V4YW1wbGUYByABKAsyFy5nb29nbGUucHJvdG9idWYuU3RydWN0Qga6SAPYAQMiiwEKEEdldFNvdXJjZVJlcXVlc3QSOwoIb3JnX3NsdWcYASABKAlCKbpIJsgBAXIhEAEY/wEyGl5bYS16MC05XSsoPzotW2EtejAtOV0rKSokEjoKBnNvdXJjZRgCIAEoCzIiLm9uZXF1ZXJ5LmNsaS52MS5DbGlTb3VyY2VTZWxlY3RvckIGukgDyAEBIpgBChFDbGlTb3VyY2VTZWxlY3RvchIyCghwcm92aWRlchgBIAEoCUIgukgdyAEBchgQARiAATIRXlthLXpdW2EtejAtOV9dKiQSTwoKc291cmNlX2tleRgCIAEoCUI7ukg4yAEBcjMQARj/ATIsXltBLVphLXowLTldKD86W0EtWmEtejAtOS5fLV0qW0EtWmEtejAtOV0pPyQivwIKCUNsaVNvdXJjZRJPCgpzb3VyY2Vfa2V5GAEgASgJQju6SDjIAQFyMxABGP8BMixeW0EtWmEtejAtOV0oPzpbQS1aYS16MC05Ll8tXSpbQS1aYS16MC05XSk/JBIkCgxkaXNwbGF5X25hbWUYAiABKAlCDrpIC3IJEAEY/wEyAlxTEjIKCHByb3ZpZGVyGAMgASgJQiC6SB3IAQFyGBABGIABMhFeW2Etel1bYS16MC05X10qJBJJCgppbnRlcmZhY2VzGAQgAygOMiAub25lcXVlcnkuY2xpLnYxLlNvdXJjZUludGVyZmFjZUITukgQkgENEAIYASIHggEEEAEgABI8CgZzdGF0dXMYBSABKA4yHS5vbmVxdWVyeS5jbGkudjEuU291cmNlU3RhdHVzQg26SArIAQGCAQQQASAAIkcKEUdldFNvdXJjZVJlc3BvbnNlEjIKBnNvdXJjZRgBIAEoCzIaLm9uZXF1ZXJ5LmNsaS52MS5DbGlTb3VyY2VCBrpIA8gBASKMAQoRVGVzdFNvdXJjZVJlcXVlc3QSOwoIb3JnX3NsdWcYASABKAlCKbpIJsgBAXIhEAEY/wEyGl5bYS16MC05XSsoPzotW2EtejAtOV0rKSokEjoKBnNvdXJjZRgCIAEoCzIiLm9uZXF1ZXJ5LmNsaS52MS5DbGlTb3VyY2VTZWxlY3RvckIGukgDyAEBIuIBChJUZXN0U291cmNlUmVzcG9uc2USMgoGc291cmNlGAEgASgLMhoub25lcXVlcnkuY2xpLnYxLkNsaVNvdXJjZUIGukgDyAEBEkAKCXN1cHBvcnRlZBgCIAEoCzIrLm9uZXF1ZXJ5LmNsaS52MS5UZXN0U291cmNlU3VwcG9ydGVkT3V0Y29tZUgAEkQKC3Vuc3VwcG9ydGVkGAMgASgLMi0ub25lcXVlcnkuY2xpLnYxLlRlc3RTb3VyY2VVbnN1cHBvcnRlZE91dGNvbWVIAEIQCgdvdXRjb21lEgW6SAIIASLeAQoaVGVzdFNvdXJjZVN1cHBvcnRlZE91dGNvbWUSOgoGcGFzc2VkGAEgASgLMigub25lcXVlcnkuY2xpLnYxLlRlc3RTb3VyY2VQYXNzZWRPdXRjb21lSAASOgoGZmFpbGVkGAIgASgLMigub25lcXVlcnkuY2xpLnYxLlRlc3RTb3VyY2VGYWlsZWRPdXRjb21lSAASNwoHbGF0ZW5jeRgDIAEoCzIZLmdvb2dsZS5wcm90b2J1Zi5EdXJhdGlvbkILukgIyAEBqgECMgBCDwoGcmVzdWx0EgW6SAIIASI5ChdUZXN0U291cmNlUGFzc2VkT3V0Y29tZRIeCgdtZXNzYWdlGAEgASgJQg26SArIAQFyBRABGIAEIlsKF1Rlc3RTb3VyY2VGYWlsZWRPdXRjb21lEh4KB21lc3NhZ2UYASABKAlCDbpICsgBAXIFEAEYgAQSIAoFZXJyb3IYAiABKAlCEbpIDsgBAXIJEAEYgBAyAlxTIosBChxUZXN0U291cmNlVW5zdXBwb3J0ZWRPdXRjb21lEksKBnJlYXNvbhgBIAEoDjIsLm9uZXF1ZXJ5LmNsaS52MS5Tb3VyY2VUZXN0VW5zdXBwb3J0ZWRSZWFzb25CDbpICsgBAYIBBBABIAASHgoHbWVzc2FnZRgCIAEoCUINukgKyAEBcgUQARiABCKPAQocR2V0U291cmNlQ29ubmVjdEd1aWRlUmVxdWVzdBI7Cghvcmdfc2x1ZxgBIAEoCUIpukgmyAEBciEQARj/ATIaXlthLXowLTldKyg/Oi1bYS16MC05XSspKiQSMgoIcHJvdmlkZXIYAiABKAlCILpIHcgBAXIYEAEYgAEyEV5bYS16XVthLXowLTlfXSokIuEBCh1HZXRTb3VyY2VDb25uZWN0R3VpZGVSZXNwb25zZRIcCgV0aXRsZRgBIAEoCUINukgKyAEBcgUQARigARIiCgtkZXNjcmlwdGlvbhgCIAEoCUINukgKyAEBcgUQARiACBI9CgZmb3JtYXQYAyABKA4yHi5vbmVxdWVyeS5jbGkudjEuQ29udGVudEZvcm1hdEINukgKyAEBggEEEAEgABIfCgdjb250ZW50GAQgASgJQg66SAvIAQFyBhABGICABBIeCgdjb21tYW5kGAUgASgJQg26SArIAQFyBRABGIBAIpcCChRDb25uZWN0U291cmNlUmVxdWVzdBI7Cghvcmdfc2x1ZxgBIAEoCUIpukgmyAEBciEQARj/ATIaXlthLXowLTldKyg/Oi1bYS16MC05XSspKiQSWAoKc291cmNlX2tleRgCIAEoCUJEukhByAEBcjwQARj/ATI1XltBLVphLXowLTldW0EtWmEtejAtOS5fLV0qW0EtWmEtejAtOV0kfF5bQS1aYS16MC05XSQSMgoIcHJvdmlkZXIYAyABKAlCILpIHcgBAXIYEAEYgAEyEV5bYS16XVthLXowLTlfXSokEjQKC2NyZWRlbnRpYWxzGAQgASgLMhcuZ29vZ2xlLnByb3RvYnVmLlN0cnVjdEIGukgD2AEDInAKFUNvbm5lY3RTb3VyY2VSZXNwb25zZRIyCgZzb3VyY2UYASABKAsyGi5vbmVxdWVyeS5jbGkudjEuQ2xpU291cmNlQga6SAPIAQESIwoMbmV4dF9jb21tYW5kGAIgASgJQg26SArIAQFyBRABGIBAKoABCgxTb3VyY2VTdGF0dXMSHQoZU09VUkNFX1NUQVRVU19VTlNQRUNJRklFRBAAEhgKFFNPVVJDRV9TVEFUVVNfQUNUSVZFEAESFwoTU09VUkNFX1NUQVRVU19FUlJPUhACEh4KGlNPVVJDRV9TVEFUVVNfRElTQ09OTkVDVEVEEAMqaQoPU291cmNlSW50ZXJmYWNlEiAKHFNPVVJDRV9JTlRFUkZBQ0VfVU5TUEVDSUZJRUQQABIaChZTT1VSQ0VfSU5URVJGQUNFX1FVRVJZEAESGAoUU09VUkNFX0lOVEVSRkFDRV9BUEkQAiqrAQobU291cmNlVGVzdFVuc3VwcG9ydGVkUmVhc29uEi4KKlNPVVJDRV9URVNUX1VOU1VQUE9SVEVEX1JFQVNPTl9VTlNQRUNJRklFRBAAEigKJFNPVVJDRV9URVNUX1VOU1VQUE9SVEVEX1JFQVNPTl9PQVVUSBABEjIKLlNPVVJDRV9URVNUX1VOU1VQUE9SVEVEX1JFQVNPTl9OT1RfSU1QTEVNRU5URUQQAmIIZWRpdGlvbnNw6Ac", + "ChxvbmVxdWVyeS9jbGkvdjEvc291cmNlLnByb3RvEg9vbmVxdWVyeS5jbGkudjEigAEKEkxpc3RTb3VyY2VzUmVxdWVzdBI7Cghvcmdfc2x1ZxgBIAEoCUIpukgmyAEBciEQARj/ATIaXlthLXowLTldKyg/Oi1bYS16MC05XSspKiQSLQoEcGFnZRgCIAEoCzIfLm9uZXF1ZXJ5LmNsaS52MS5DbGlQYWdlUmVxdWVzdCJ8ChNMaXN0U291cmNlc1Jlc3BvbnNlEjUKB3NvdXJjZXMYASADKAsyGi5vbmVxdWVyeS5jbGkudjEuQ2xpU291cmNlQgi6SAWSAQIQZBIuCgRwYWdlGAIgASgLMhgub25lcXVlcnkuY2xpLnYxLkNsaVBhZ2VCBrpIA8gBASJZChpMaXN0U291cmNlUHJvdmlkZXJzUmVxdWVzdBI7Cghvcmdfc2x1ZxgBIAEoCUIpukgmyAEBciEQARj/ATIaXlthLXowLTldKyg/Oi1bYS16MC05XSspKiQiXgobTGlzdFNvdXJjZVByb3ZpZGVyc1Jlc3BvbnNlEj8KCXByb3ZpZGVycxgBIAMoCzIiLm9uZXF1ZXJ5LmNsaS52MS5DbGlTb3VyY2VQcm92aWRlckIIukgFkgECEGQi0wIKEUNsaVNvdXJjZVByb3ZpZGVyEjIKCHByb3ZpZGVyGAEgASgJQiC6SB3IAQFyGBABGIABMhFeW2Etel1bYS16MC05X10qJBIgCgVsYWJlbBgCIAEoCUIRukgOyAEBcgkQARiAATICXFMSEwoLY29ubmVjdGFibGUYAyABKAgSEAoIdGVzdGFibGUYBCABKAgSSQoKaW50ZXJmYWNlcxgFIAMoDjIgLm9uZXF1ZXJ5LmNsaS52MS5Tb3VyY2VJbnRlcmZhY2VCE7pIEJIBDRACGAEiB4IBBBABIAASOQoPY3JlZGVudGlhbF90eXBlGAYgASgJQiC6SB3IAQFyGBABGIABMhFeW2Etel1bYS16MC05X10qJBI7ChJjcmVkZW50aWFsX2V4YW1wbGUYByABKAsyFy5nb29nbGUucHJvdG9idWYuU3RydWN0Qga6SAPYAQMiiwEKEEdldFNvdXJjZVJlcXVlc3QSOwoIb3JnX3NsdWcYASABKAlCKbpIJsgBAXIhEAEY/wEyGl5bYS16MC05XSsoPzotW2EtejAtOV0rKSokEjoKBnNvdXJjZRgCIAEoCzIiLm9uZXF1ZXJ5LmNsaS52MS5DbGlTb3VyY2VTZWxlY3RvckIGukgDyAEBIpgBChFDbGlTb3VyY2VTZWxlY3RvchIyCghwcm92aWRlchgBIAEoCUIgukgdyAEBchgQARiAATIRXlthLXpdW2EtejAtOV9dKiQSTwoKc291cmNlX2tleRgCIAEoCUI7ukg4yAEBcjMQARj/ATIsXltBLVphLXowLTldKD86W0EtWmEtejAtOS5fLV0qW0EtWmEtejAtOV0pPyQivwIKCUNsaVNvdXJjZRJPCgpzb3VyY2Vfa2V5GAEgASgJQju6SDjIAQFyMxABGP8BMixeW0EtWmEtejAtOV0oPzpbQS1aYS16MC05Ll8tXSpbQS1aYS16MC05XSk/JBIkCgxkaXNwbGF5X25hbWUYAiABKAlCDrpIC3IJEAEY/wEyAlxTEjIKCHByb3ZpZGVyGAMgASgJQiC6SB3IAQFyGBABGIABMhFeW2Etel1bYS16MC05X10qJBJJCgppbnRlcmZhY2VzGAQgAygOMiAub25lcXVlcnkuY2xpLnYxLlNvdXJjZUludGVyZmFjZUITukgQkgENEAIYASIHggEEEAEgABI8CgZzdGF0dXMYBSABKA4yHS5vbmVxdWVyeS5jbGkudjEuU291cmNlU3RhdHVzQg26SArIAQGCAQQQASAAIkcKEUdldFNvdXJjZVJlc3BvbnNlEjIKBnNvdXJjZRgBIAEoCzIaLm9uZXF1ZXJ5LmNsaS52MS5DbGlTb3VyY2VCBrpIA8gBASKMAQoRVGVzdFNvdXJjZVJlcXVlc3QSOwoIb3JnX3NsdWcYASABKAlCKbpIJsgBAXIhEAEY/wEyGl5bYS16MC05XSsoPzotW2EtejAtOV0rKSokEjoKBnNvdXJjZRgCIAEoCzIiLm9uZXF1ZXJ5LmNsaS52MS5DbGlTb3VyY2VTZWxlY3RvckIGukgDyAEBIuIBChJUZXN0U291cmNlUmVzcG9uc2USMgoGc291cmNlGAEgASgLMhoub25lcXVlcnkuY2xpLnYxLkNsaVNvdXJjZUIGukgDyAEBEkAKCXN1cHBvcnRlZBgCIAEoCzIrLm9uZXF1ZXJ5LmNsaS52MS5UZXN0U291cmNlU3VwcG9ydGVkT3V0Y29tZUgAEkQKC3Vuc3VwcG9ydGVkGAMgASgLMi0ub25lcXVlcnkuY2xpLnYxLlRlc3RTb3VyY2VVbnN1cHBvcnRlZE91dGNvbWVIAEIQCgdvdXRjb21lEgW6SAIIASLEAQoTVXBkYXRlU291cmNlUmVxdWVzdBI7Cghvcmdfc2x1ZxgBIAEoCUIpukgmyAEBciEQARj/ATIaXlthLXowLTldKyg/Oi1bYS16MC05XSspKiQSOgoGc291cmNlGAIgASgLMiIub25lcXVlcnkuY2xpLnYxLkNsaVNvdXJjZVNlbGVjdG9yQga6SAPIAQESNAoLY3JlZGVudGlhbHMYAyABKAsyFy5nb29nbGUucHJvdG9idWYuU3RydWN0Qga6SAPYAQMi5AEKFFVwZGF0ZVNvdXJjZVJlc3BvbnNlEjIKBnNvdXJjZRgBIAEoCzIaLm9uZXF1ZXJ5LmNsaS52MS5DbGlTb3VyY2VCBrpIA8gBARJACglzdXBwb3J0ZWQYAiABKAsyKy5vbmVxdWVyeS5jbGkudjEuVGVzdFNvdXJjZVN1cHBvcnRlZE91dGNvbWVIABJECgt1bnN1cHBvcnRlZBgDIAEoCzItLm9uZXF1ZXJ5LmNsaS52MS5UZXN0U291cmNlVW5zdXBwb3J0ZWRPdXRjb21lSABCEAoHb3V0Y29tZRIFukgCCAEijgEKE0RlbGV0ZVNvdXJjZVJlcXVlc3QSOwoIb3JnX3NsdWcYASABKAlCKbpIJsgBAXIhEAEY/wEyGl5bYS16MC05XSsoPzotW2EtejAtOV0rKSokEjoKBnNvdXJjZRgCIAEoCzIiLm9uZXF1ZXJ5LmNsaS52MS5DbGlTb3VyY2VTZWxlY3RvckIGukgDyAEBIlsKFERlbGV0ZVNvdXJjZVJlc3BvbnNlEjIKBnNvdXJjZRgBIAEoCzIaLm9uZXF1ZXJ5LmNsaS52MS5DbGlTb3VyY2VCBrpIA8gBARIPCgdkZWxldGVkGAIgASgIIt4BChpUZXN0U291cmNlU3VwcG9ydGVkT3V0Y29tZRI6CgZwYXNzZWQYASABKAsyKC5vbmVxdWVyeS5jbGkudjEuVGVzdFNvdXJjZVBhc3NlZE91dGNvbWVIABI6CgZmYWlsZWQYAiABKAsyKC5vbmVxdWVyeS5jbGkudjEuVGVzdFNvdXJjZUZhaWxlZE91dGNvbWVIABI3CgdsYXRlbmN5GAMgASgLMhkuZ29vZ2xlLnByb3RvYnVmLkR1cmF0aW9uQgu6SAjIAQGqAQIyAEIPCgZyZXN1bHQSBbpIAggBIjkKF1Rlc3RTb3VyY2VQYXNzZWRPdXRjb21lEh4KB21lc3NhZ2UYASABKAlCDbpICsgBAXIFEAEYgAQiWwoXVGVzdFNvdXJjZUZhaWxlZE91dGNvbWUSHgoHbWVzc2FnZRgBIAEoCUINukgKyAEBcgUQARiABBIgCgVlcnJvchgCIAEoCUIRukgOyAEBcgkQARiAEDICXFMiiwEKHFRlc3RTb3VyY2VVbnN1cHBvcnRlZE91dGNvbWUSSwoGcmVhc29uGAEgASgOMiwub25lcXVlcnkuY2xpLnYxLlNvdXJjZVRlc3RVbnN1cHBvcnRlZFJlYXNvbkINukgKyAEBggEEEAEgABIeCgdtZXNzYWdlGAIgASgJQg26SArIAQFyBRABGIAEIo8BChxHZXRTb3VyY2VDb25uZWN0R3VpZGVSZXF1ZXN0EjsKCG9yZ19zbHVnGAEgASgJQim6SCbIAQFyIRABGP8BMhpeW2EtejAtOV0rKD86LVthLXowLTldKykqJBIyCghwcm92aWRlchgCIAEoCUIgukgdyAEBchgQARiAATIRXlthLXpdW2EtejAtOV9dKiQi4QEKHUdldFNvdXJjZUNvbm5lY3RHdWlkZVJlc3BvbnNlEhwKBXRpdGxlGAEgASgJQg26SArIAQFyBRABGKABEiIKC2Rlc2NyaXB0aW9uGAIgASgJQg26SArIAQFyBRABGIAIEj0KBmZvcm1hdBgDIAEoDjIeLm9uZXF1ZXJ5LmNsaS52MS5Db250ZW50Rm9ybWF0Qg26SArIAQGCAQQQASAAEh8KB2NvbnRlbnQYBCABKAlCDrpIC8gBAXIGEAEYgIAEEh4KB2NvbW1hbmQYBSABKAlCDbpICsgBAXIFEAEYgEAilwIKFENvbm5lY3RTb3VyY2VSZXF1ZXN0EjsKCG9yZ19zbHVnGAEgASgJQim6SCbIAQFyIRABGP8BMhpeW2EtejAtOV0rKD86LVthLXowLTldKykqJBJYCgpzb3VyY2Vfa2V5GAIgASgJQkS6SEHIAQFyPBABGP8BMjVeW0EtWmEtejAtOV1bQS1aYS16MC05Ll8tXSpbQS1aYS16MC05XSR8XltBLVphLXowLTldJBIyCghwcm92aWRlchgDIAEoCUIgukgdyAEBchgQARiAATIRXlthLXpdW2EtejAtOV9dKiQSNAoLY3JlZGVudGlhbHMYBCABKAsyFy5nb29nbGUucHJvdG9idWYuU3RydWN0Qga6SAPYAQMicAoVQ29ubmVjdFNvdXJjZVJlc3BvbnNlEjIKBnNvdXJjZRgBIAEoCzIaLm9uZXF1ZXJ5LmNsaS52MS5DbGlTb3VyY2VCBrpIA8gBARIjCgxuZXh0X2NvbW1hbmQYAiABKAlCDbpICsgBAXIFEAEYgEAqgAEKDFNvdXJjZVN0YXR1cxIdChlTT1VSQ0VfU1RBVFVTX1VOU1BFQ0lGSUVEEAASGAoUU09VUkNFX1NUQVRVU19BQ1RJVkUQARIXChNTT1VSQ0VfU1RBVFVTX0VSUk9SEAISHgoaU09VUkNFX1NUQVRVU19ESVNDT05ORUNURUQQAyppCg9Tb3VyY2VJbnRlcmZhY2USIAocU09VUkNFX0lOVEVSRkFDRV9VTlNQRUNJRklFRBAAEhoKFlNPVVJDRV9JTlRFUkZBQ0VfUVVFUlkQARIYChRTT1VSQ0VfSU5URVJGQUNFX0FQSRACKqsBChtTb3VyY2VUZXN0VW5zdXBwb3J0ZWRSZWFzb24SLgoqU09VUkNFX1RFU1RfVU5TVVBQT1JURURfUkVBU09OX1VOU1BFQ0lGSUVEEAASKAokU09VUkNFX1RFU1RfVU5TVVBQT1JURURfUkVBU09OX09BVVRIEAESMgouU09VUkNFX1RFU1RfVU5TVVBQT1JURURfUkVBU09OX05PVF9JTVBMRU1FTlRFRBACYghlZGl0aW9uc3DoBw", [ file_buf_validate_validate, file_google_protobuf_duration, @@ -323,6 +323,118 @@ export type TestSourceResponse = export const TestSourceResponseSchema: GenMessage /*@__PURE__*/ = messageDesc(file_onequery_cli_v1_source, 10); +/** + * @generated from message onequery.cli.v1.UpdateSourceRequest + */ +export type UpdateSourceRequest = + Message<"onequery.cli.v1.UpdateSourceRequest"> & { + /** + * @generated from field: string org_slug = 1; + */ + orgSlug: string; + + /** + * @generated from field: onequery.cli.v1.CliSourceSelector source = 2; + */ + source?: CliSourceSelector; + + /** + * @generated from field: google.protobuf.Struct credentials = 3; + */ + credentials?: JsonObject; + }; + +/** + * Describes the message onequery.cli.v1.UpdateSourceRequest. + * Use `create(UpdateSourceRequestSchema)` to create a new message. + */ +export const UpdateSourceRequestSchema: GenMessage /*@__PURE__*/ = + messageDesc(file_onequery_cli_v1_source, 11); + +/** + * @generated from message onequery.cli.v1.UpdateSourceResponse + */ +export type UpdateSourceResponse = + Message<"onequery.cli.v1.UpdateSourceResponse"> & { + /** + * @generated from field: onequery.cli.v1.CliSource source = 1; + */ + source?: CliSource; + + /** + * @generated from oneof onequery.cli.v1.UpdateSourceResponse.outcome + */ + outcome: + | { + /** + * @generated from field: onequery.cli.v1.TestSourceSupportedOutcome supported = 2; + */ + value: TestSourceSupportedOutcome; + case: "supported"; + } + | { + /** + * @generated from field: onequery.cli.v1.TestSourceUnsupportedOutcome unsupported = 3; + */ + value: TestSourceUnsupportedOutcome; + case: "unsupported"; + } + | { case: undefined; value?: undefined }; + }; + +/** + * Describes the message onequery.cli.v1.UpdateSourceResponse. + * Use `create(UpdateSourceResponseSchema)` to create a new message. + */ +export const UpdateSourceResponseSchema: GenMessage /*@__PURE__*/ = + messageDesc(file_onequery_cli_v1_source, 12); + +/** + * @generated from message onequery.cli.v1.DeleteSourceRequest + */ +export type DeleteSourceRequest = + Message<"onequery.cli.v1.DeleteSourceRequest"> & { + /** + * @generated from field: string org_slug = 1; + */ + orgSlug: string; + + /** + * @generated from field: onequery.cli.v1.CliSourceSelector source = 2; + */ + source?: CliSourceSelector; + }; + +/** + * Describes the message onequery.cli.v1.DeleteSourceRequest. + * Use `create(DeleteSourceRequestSchema)` to create a new message. + */ +export const DeleteSourceRequestSchema: GenMessage /*@__PURE__*/ = + messageDesc(file_onequery_cli_v1_source, 13); + +/** + * @generated from message onequery.cli.v1.DeleteSourceResponse + */ +export type DeleteSourceResponse = + Message<"onequery.cli.v1.DeleteSourceResponse"> & { + /** + * @generated from field: onequery.cli.v1.CliSource source = 1; + */ + source?: CliSource; + + /** + * @generated from field: bool deleted = 2; + */ + deleted: boolean; + }; + +/** + * Describes the message onequery.cli.v1.DeleteSourceResponse. + * Use `create(DeleteSourceResponseSchema)` to create a new message. + */ +export const DeleteSourceResponseSchema: GenMessage /*@__PURE__*/ = + messageDesc(file_onequery_cli_v1_source, 14); + /** * @generated from message onequery.cli.v1.TestSourceSupportedOutcome */ @@ -359,7 +471,7 @@ export type TestSourceSupportedOutcome = * Use `create(TestSourceSupportedOutcomeSchema)` to create a new message. */ export const TestSourceSupportedOutcomeSchema: GenMessage /*@__PURE__*/ = - messageDesc(file_onequery_cli_v1_source, 11); + messageDesc(file_onequery_cli_v1_source, 15); /** * @generated from message onequery.cli.v1.TestSourcePassedOutcome @@ -377,7 +489,7 @@ export type TestSourcePassedOutcome = * Use `create(TestSourcePassedOutcomeSchema)` to create a new message. */ export const TestSourcePassedOutcomeSchema: GenMessage /*@__PURE__*/ = - messageDesc(file_onequery_cli_v1_source, 12); + messageDesc(file_onequery_cli_v1_source, 16); /** * @generated from message onequery.cli.v1.TestSourceFailedOutcome @@ -400,7 +512,7 @@ export type TestSourceFailedOutcome = * Use `create(TestSourceFailedOutcomeSchema)` to create a new message. */ export const TestSourceFailedOutcomeSchema: GenMessage /*@__PURE__*/ = - messageDesc(file_onequery_cli_v1_source, 13); + messageDesc(file_onequery_cli_v1_source, 17); /** * @generated from message onequery.cli.v1.TestSourceUnsupportedOutcome @@ -423,7 +535,7 @@ export type TestSourceUnsupportedOutcome = * Use `create(TestSourceUnsupportedOutcomeSchema)` to create a new message. */ export const TestSourceUnsupportedOutcomeSchema: GenMessage /*@__PURE__*/ = - messageDesc(file_onequery_cli_v1_source, 14); + messageDesc(file_onequery_cli_v1_source, 18); /** * @generated from message onequery.cli.v1.GetSourceConnectGuideRequest @@ -446,7 +558,7 @@ export type GetSourceConnectGuideRequest = * Use `create(GetSourceConnectGuideRequestSchema)` to create a new message. */ export const GetSourceConnectGuideRequestSchema: GenMessage /*@__PURE__*/ = - messageDesc(file_onequery_cli_v1_source, 15); + messageDesc(file_onequery_cli_v1_source, 19); /** * @generated from message onequery.cli.v1.GetSourceConnectGuideResponse @@ -484,7 +596,7 @@ export type GetSourceConnectGuideResponse = * Use `create(GetSourceConnectGuideResponseSchema)` to create a new message. */ export const GetSourceConnectGuideResponseSchema: GenMessage /*@__PURE__*/ = - messageDesc(file_onequery_cli_v1_source, 16); + messageDesc(file_onequery_cli_v1_source, 20); /** * @generated from message onequery.cli.v1.ConnectSourceRequest @@ -517,7 +629,7 @@ export type ConnectSourceRequest = * Use `create(ConnectSourceRequestSchema)` to create a new message. */ export const ConnectSourceRequestSchema: GenMessage /*@__PURE__*/ = - messageDesc(file_onequery_cli_v1_source, 17); + messageDesc(file_onequery_cli_v1_source, 21); /** * @generated from message onequery.cli.v1.ConnectSourceResponse @@ -540,7 +652,7 @@ export type ConnectSourceResponse = * Use `create(ConnectSourceResponseSchema)` to create a new message. */ export const ConnectSourceResponseSchema: GenMessage /*@__PURE__*/ = - messageDesc(file_onequery_cli_v1_source, 18); + messageDesc(file_onequery_cli_v1_source, 22); /** * @generated from enum onequery.cli.v1.SourceStatus diff --git a/packages/server/src/auth/organization-permissions.ts b/packages/server/src/auth/organization-permissions.ts index a7d205e4..d1c5142e 100644 --- a/packages/server/src/auth/organization-permissions.ts +++ b/packages/server/src/auth/organization-permissions.ts @@ -16,7 +16,7 @@ export const organizationPermissionStatements = { ...defaultStatements, cliOrg: ["list", "read"], cliQuery: ["execute"], - cliSource: ["connect", "list", "read"], + cliSource: ["connect", "list", "read", "write"], cliSourceApi: ["describe", "execute"], } as const; @@ -92,6 +92,9 @@ export const organizationPermissionChecks = { cliSourceRead: { cliSource: ["read"], }, + cliSourceWrite: { + cliSource: ["write"], + }, cliSourceApiDescribe: { cliSourceApi: ["describe"], }, @@ -119,6 +122,7 @@ export const organizationPermissionChecks = { | "cliSourceList" | "cliSourceConnect" | "cliSourceRead" + | "cliSourceWrite" | "cliSourceApiDescribe" | "cliSourceApiExecute", OrganizationPermissionCheck diff --git a/proto/onequery/cli/v1/cli.proto b/proto/onequery/cli/v1/cli.proto index 45e7a8a0..a9f0c952 100644 --- a/proto/onequery/cli/v1/cli.proto +++ b/proto/onequery/cli/v1/cli.proto @@ -41,6 +41,8 @@ service CliSourceService { option idempotency_level = NO_SIDE_EFFECTS; } rpc TestSource(TestSourceRequest) returns (TestSourceResponse); + rpc UpdateSource(UpdateSourceRequest) returns (UpdateSourceResponse); + rpc DeleteSource(DeleteSourceRequest) returns (DeleteSourceResponse); } service CliSourceApiService { diff --git a/proto/onequery/cli/v1/org.proto b/proto/onequery/cli/v1/org.proto index b424c182..27b451fc 100644 --- a/proto/onequery/cli/v1/org.proto +++ b/proto/onequery/cli/v1/org.proto @@ -74,6 +74,7 @@ enum OrgCapability { ORG_CAPABILITY_QUERY_EXECUTE = 6; ORG_CAPABILITY_SOURCE_API_DESCRIBE = 7; ORG_CAPABILITY_SOURCE_API_EXECUTE = 8; + ORG_CAPABILITY_SOURCE_WRITE = 9; } enum OrganizationRole { diff --git a/proto/onequery/cli/v1/source.proto b/proto/onequery/cli/v1/source.proto index f774ff40..6d18d05e 100644 --- a/proto/onequery/cli/v1/source.proto +++ b/proto/onequery/cli/v1/source.proto @@ -146,6 +146,42 @@ message TestSourceResponse { } } +message UpdateSourceRequest { + string org_slug = 1 [ + (buf.validate.field).required = true, + (buf.validate.field).string.min_len = 1, + (buf.validate.field).string.max_len = 255, + (buf.validate.field).string.pattern = "^[a-z0-9]+(?:-[a-z0-9]+)*$" + ]; + CliSourceSelector source = 2 [(buf.validate.field).required = true]; + google.protobuf.Struct credentials = 3 [(buf.validate.field).ignore = IGNORE_ALWAYS]; +} + +message UpdateSourceResponse { + CliSource source = 1 [(buf.validate.field).required = true]; + oneof outcome { + option (buf.validate.oneof).required = true; + + TestSourceSupportedOutcome supported = 2; + TestSourceUnsupportedOutcome unsupported = 3; + } +} + +message DeleteSourceRequest { + string org_slug = 1 [ + (buf.validate.field).required = true, + (buf.validate.field).string.min_len = 1, + (buf.validate.field).string.max_len = 255, + (buf.validate.field).string.pattern = "^[a-z0-9]+(?:-[a-z0-9]+)*$" + ]; + CliSourceSelector source = 2 [(buf.validate.field).required = true]; +} + +message DeleteSourceResponse { + CliSource source = 1 [(buf.validate.field).required = true]; + bool deleted = 2; +} + message TestSourceSupportedOutcome { oneof result { option (buf.validate.oneof).required = true;