cli

Command-line interface for Radroots
git clone https://radroots.dev/git/cli.git
Log | Files | Refs | README | LICENSE

commit 284c74df8dd1e6a4dd5b0b8a17a8f65c0d4ece9b
parent 4e6b4cb2328e14e63e0feb223ef96543e89a22db
Author: triesap <tyson@radroots.org>
Date:   Wed,  8 Apr 2026 19:21:49 +0000

surface signer session in cli write and job output

Diffstat:
Msrc/domain/runtime.rs | 22++++++++++++++++++++++
Msrc/render/mod.rs | 34+++++++++++++++++++++++++++++-----
Msrc/runtime/daemon.rs | 8++++++++
Msrc/runtime/job.rs | 2++
Msrc/runtime/listing.rs | 10++++++++++
Msrc/runtime/order.rs | 36++++++++++++++++++++++++++++++++++++
Mtests/job_rpc.rs | 10+++++++++-
Mtests/listing.rs | 37+++++++++++++++++++++++++++++++++----
Mtests/order.rs | 11++++++++++-
9 files changed, 159 insertions(+), 11 deletions(-)

diff --git a/src/domain/runtime.rs b/src/domain/runtime.rs @@ -453,6 +453,8 @@ pub struct JobSummaryView { pub state: String, pub terminal: bool, pub signer: String, + #[serde(skip_serializing_if = "Option::is_none")] + pub signer_session_id: Option<String>, pub requested_at_unix: u64, #[serde(skip_serializing_if = "Option::is_none")] pub completed_at_unix: Option<u64>, @@ -466,6 +468,8 @@ pub struct JobDetailView { pub state: String, pub terminal: bool, pub signer: String, + #[serde(skip_serializing_if = "Option::is_none")] + pub signer_session_id: Option<String>, pub requested_at_unix: u64, #[serde(skip_serializing_if = "Option::is_none")] pub completed_at_unix: Option<u64>, @@ -492,6 +496,9 @@ pub struct JobWatchFrameView { pub observed_at_unix: u64, pub state: String, pub terminal: bool, + pub signer: String, + #[serde(skip_serializing_if = "Option::is_none")] + pub signer_session_id: Option<String>, pub summary: String, } @@ -615,6 +622,10 @@ pub struct OrderSubmitView { #[serde(skip_serializing_if = "Option::is_none")] pub idempotency_key: Option<String>, #[serde(skip_serializing_if = "Option::is_none")] + pub signer_mode: Option<String>, + #[serde(skip_serializing_if = "Option::is_none")] + pub signer_session_id: Option<String>, + #[serde(skip_serializing_if = "Option::is_none")] pub requested_signer_session_id: Option<String>, #[serde(skip_serializing_if = "Option::is_none")] pub reason: Option<String>, @@ -670,6 +681,9 @@ pub struct OrderWatchFrameView { pub observed_at_unix: u64, pub state: String, pub terminal: bool, + pub signer_mode: String, + #[serde(skip_serializing_if = "Option::is_none")] + pub signer_session_id: Option<String>, pub summary: String, } @@ -779,6 +793,10 @@ pub struct OrderJobView { #[serde(skip_serializing_if = "Option::is_none")] pub command: Option<String>, #[serde(skip_serializing_if = "Option::is_none")] + pub signer_mode: Option<String>, + #[serde(skip_serializing_if = "Option::is_none")] + pub signer_session_id: Option<String>, + #[serde(skip_serializing_if = "Option::is_none")] pub requested_signer_session_id: Option<String>, #[serde(skip_serializing_if = "Option::is_none")] pub event_id: Option<String>, @@ -894,6 +912,8 @@ pub struct ListingMutationView { #[serde(skip_serializing_if = "Option::is_none")] pub idempotency_key: Option<String>, #[serde(skip_serializing_if = "Option::is_none")] + pub signer_session_id: Option<String>, + #[serde(skip_serializing_if = "Option::is_none")] pub requested_signer_session_id: Option<String>, #[serde(skip_serializing_if = "Option::is_none")] pub reason: Option<String>, @@ -928,6 +948,8 @@ pub struct ListingMutationJobView { pub requested_signer_session_id: Option<String>, #[serde(skip_serializing_if = "Option::is_none")] pub signer_mode: Option<String>, + #[serde(skip_serializing_if = "Option::is_none")] + pub signer_session_id: Option<String>, } #[derive(Debug, Clone, Serialize)] diff --git a/src/render/mod.rs b/src/render/mod.rs @@ -739,7 +739,7 @@ fn render_job_list(stdout: &mut dyn Write, view: &JobListView) -> Result<(), Run } } else { let table = Table { - headers: &["job", "type", "state", "signer", "updated"], + headers: &["job", "type", "state", "signer", "session", "updated"], rows: view .jobs .iter() @@ -750,6 +750,7 @@ fn render_job_list(stdout: &mut dyn Write, view: &JobListView) -> Result<(), Run job.command.clone(), job.state.clone(), job.signer.clone(), + job.signer_session_id.clone().unwrap_or_default(), crate::runtime::job::format_timestamp(updated_at), ] }) @@ -774,7 +775,11 @@ fn render_job_get(stdout: &mut dyn Write, view: &JobGetView) -> Result<(), Runti ("id", job.id.clone()), ("type", job.command.clone()), ("state", job.state.clone()), - ("signer", job.signer.clone()), + ("signer mode", job.signer.clone()), + ( + "signer session", + job.signer_session_id.clone().unwrap_or_else(|| "-".to_owned()), + ), ( "requested", crate::runtime::job::format_timestamp(job.requested_at_unix), @@ -823,7 +828,7 @@ fn render_job_watch(stdout: &mut dyn Write, view: &JobWatchView) -> Result<(), R } } else { let table = Table { - headers: &["frame", "time", "state", "terminal", "summary"], + headers: &["frame", "time", "state", "signer", "session", "terminal", "summary"], rows: view .frames .iter() @@ -832,6 +837,8 @@ fn render_job_watch(stdout: &mut dyn Write, view: &JobWatchView) -> Result<(), R frame.sequence.to_string(), crate::runtime::job::format_clock(frame.observed_at_unix), frame.state.clone(), + frame.signer.clone(), + frame.signer_session_id.clone().unwrap_or_default(), yes_no(frame.terminal).to_owned(), frame.summary.clone(), ] @@ -1035,6 +1042,12 @@ fn render_order_submit(stdout: &mut dyn Write, view: &OrderSubmitView) -> Result if let Some(idempotency_key) = &view.idempotency_key { rows.push(("idempotency key", idempotency_key.as_str())); } + if let Some(signer_mode) = &view.signer_mode { + rows.push(("signer mode", signer_mode.as_str())); + } + if let Some(signer_session_id) = &view.signer_session_id { + rows.push(("signer session", signer_session_id.as_str())); + } if let Some(requested_signer_session_id) = &view.requested_signer_session_id { rows.push(( "requested signer session", @@ -1074,7 +1087,7 @@ fn render_order_watch(stdout: &mut dyn Write, view: &OrderWatchView) -> Result<( render_owned_pairs(stdout, "watch", rows.as_slice())?; if !view.frames.is_empty() { let table = Table { - headers: &["frame", "time", "state", "terminal", "summary"], + headers: &["frame", "time", "state", "signer", "session", "terminal", "summary"], rows: view .frames .iter() @@ -1083,6 +1096,8 @@ fn render_order_watch(stdout: &mut dyn Write, view: &OrderWatchView) -> Result<( frame.sequence.to_string(), crate::runtime::job::format_clock(frame.observed_at_unix), frame.state.clone(), + frame.signer_mode.clone(), + frame.signer_session_id.clone().unwrap_or_default(), yes_no(frame.terminal).to_owned(), frame.summary.clone(), ] @@ -1214,6 +1229,12 @@ fn render_order_job(stdout: &mut dyn Write, job: &OrderJobView) -> Result<(), Ru if let Some(command) = &job.command { rows.push(("command", command.as_str())); } + if let Some(signer_mode) = &job.signer_mode { + rows.push(("signer mode", signer_mode.as_str())); + } + if let Some(signer_session_id) = &job.signer_session_id { + rows.push(("signer session", signer_session_id.as_str())); + } if let Some(requested_signer_session_id) = &job.requested_signer_session_id { rows.push(( "requested signer session", @@ -1429,7 +1450,10 @@ fn render_listing_mutation( rows.push(("event id", event_id.as_str())); } if let Some(signer_mode) = &view.signer_mode { - rows.push(("signer", signer_mode.as_str())); + rows.push(("signer mode", signer_mode.as_str())); + } + if let Some(signer_session_id) = &view.signer_session_id { + rows.push(("signer session", signer_session_id.as_str())); } if let Some(requested_signer_session_id) = &view.requested_signer_session_id { rows.push(( diff --git a/src/runtime/daemon.rs b/src/runtime/daemon.rs @@ -89,6 +89,8 @@ struct BridgeJobRemote { completed_at_unix: Option<u64>, signer_mode: String, #[serde(default)] + signer_session_id: Option<String>, + #[serde(default)] event_kind: Option<u32>, event_id: Option<String>, event_addr: Option<String>, @@ -132,6 +134,7 @@ pub struct BridgeListingPublishResult { pub idempotency_key: Option<String>, pub status: String, pub signer_mode: String, + pub signer_session_id: Option<String>, pub event_kind: Option<u32>, pub event_id: Option<String>, pub event_addr: Option<String>, @@ -144,6 +147,7 @@ pub struct BridgeOrderRequestResult { pub idempotency_key: Option<String>, pub status: String, pub signer_mode: String, + pub signer_session_id: Option<String>, pub event_id: Option<String>, pub event_addr: Option<String>, } @@ -393,6 +397,7 @@ pub fn bridge_listing_publish( idempotency_key: response.job.idempotency_key, status: response.job.status, signer_mode: response.job.signer_mode, + signer_session_id: response.job.signer_session_id, event_kind: response.job.event_kind, event_id: response.job.event_id, event_addr: response.job.event_addr, @@ -421,6 +426,7 @@ pub fn bridge_order_request( idempotency_key: response.job.idempotency_key, status: response.job.status, signer_mode: response.job.signer_mode, + signer_session_id: response.job.signer_session_id, event_id: response.job.event_id, event_addr: response.job.event_addr, }) @@ -624,6 +630,7 @@ fn map_job_summary_view(job: BridgeJobRemote) -> JobSummaryView { state: job.status, terminal: job.terminal, signer: job.signer_mode, + signer_session_id: job.signer_session_id, requested_at_unix: job.requested_at_unix, completed_at_unix: job.completed_at_unix, recovered_after_restart: job.recovered_after_restart, @@ -637,6 +644,7 @@ fn map_job_detail_view(job: BridgeJobRemote) -> JobDetailView { state: job.status, terminal: job.terminal, signer: job.signer_mode, + signer_session_id: job.signer_session_id, requested_at_unix: job.requested_at_unix, completed_at_unix: job.completed_at_unix, recovered_after_restart: job.recovered_after_restart, diff --git a/src/runtime/job.rs b/src/runtime/job.rs @@ -71,6 +71,8 @@ pub fn watch(config: &RuntimeConfig, args: &JobWatchArgs) -> Result<CommandOutpu observed_at_unix: job.completed_at_unix.unwrap_or(job.requested_at_unix), state: job.state.clone(), terminal: job.terminal, + signer: job.signer.clone(), + signer_session_id: job.signer_session_id.clone(), summary: job.relay_outcome_summary.clone(), }); if job.terminal || frames.len() >= max_frames { diff --git a/src/runtime/listing.rs b/src/runtime/listing.rs @@ -522,6 +522,7 @@ fn mutate( event_id: None, event_addr: Some(listing_addr.clone()), idempotency_key: args.idempotency_key.clone(), + signer_session_id: None, requested_signer_session_id: args.signer_session_id.clone(), reason: Some("dry run requested; daemon publish skipped".to_owned()), job: args.print_job.then(|| ListingMutationJobView { @@ -531,6 +532,7 @@ fn mutate( idempotency_key: args.idempotency_key.clone(), requested_signer_session_id: args.signer_session_id.clone(), signer_mode: Some(config.signer.backend.as_str().to_owned()), + signer_session_id: None, }), event: args.print_event.then_some(event_preview), actions: vec![format!( @@ -602,6 +604,7 @@ fn mutate( job_id: Some(result.job_id.clone()), job_status: Some(result.status.clone()), signer_mode: Some(result.signer_mode.clone()), + signer_session_id: result.signer_session_id.clone(), event_id: result.event_id.clone(), event_addr: result .event_addr @@ -619,6 +622,7 @@ fn mutate( idempotency_key: result.idempotency_key, requested_signer_session_id: args.signer_session_id.clone(), signer_mode: Some(result.signer_mode), + signer_session_id: result.signer_session_id, }), event: args.print_event.then(|| ListingMutationEventView { event_id: result.event_id, @@ -997,6 +1001,7 @@ fn daemon_error_view( job_id: None, job_status: None, signer_mode: None, + signer_session_id: None, event_id: None, event_addr: None, idempotency_key: args.idempotency_key.clone(), @@ -1009,6 +1014,7 @@ fn daemon_error_view( idempotency_key: args.idempotency_key.clone(), requested_signer_session_id: args.signer_session_id.clone(), signer_mode: Some(config.signer.backend.as_str().to_owned()), + signer_session_id: None, }), event: args.print_event.then_some(event_preview), actions: vec![ @@ -1030,6 +1036,7 @@ fn daemon_error_view( job_id: None, job_status: None, signer_mode: None, + signer_session_id: None, event_id: None, event_addr: None, idempotency_key: args.idempotency_key.clone(), @@ -1042,6 +1049,7 @@ fn daemon_error_view( idempotency_key: args.idempotency_key.clone(), requested_signer_session_id: args.signer_session_id.clone(), signer_mode: Some(config.signer.backend.as_str().to_owned()), + signer_session_id: None, }), event: args.print_event.then_some(event_preview), actions: vec!["start radrootsd and verify the rpc url".to_owned()], @@ -1062,6 +1070,7 @@ fn daemon_error_view( job_id: None, job_status: None, signer_mode: None, + signer_session_id: None, event_id: None, event_addr: None, idempotency_key: args.idempotency_key.clone(), @@ -1074,6 +1083,7 @@ fn daemon_error_view( idempotency_key: args.idempotency_key.clone(), requested_signer_session_id: args.signer_session_id.clone(), signer_mode: Some(config.signer.backend.as_str().to_owned()), + signer_session_id: None, }), event: args.print_event.then_some(event_preview), actions: vec!["inspect the daemon rpc response contract".to_owned()], diff --git a/src/runtime/order.rs b/src/runtime/order.rs @@ -74,6 +74,8 @@ struct OrderDraftSubmission { #[serde(default, skip_serializing_if = "Option::is_none")] signer_mode: Option<String>, #[serde(default, skip_serializing_if = "Option::is_none")] + signer_session_id: Option<String>, + #[serde(default, skip_serializing_if = "Option::is_none")] command: Option<String>, #[serde(default, skip_serializing_if = "Option::is_none")] event_id: Option<String>, @@ -280,6 +282,8 @@ pub fn submit( dry_run: false, deduplicated: false, idempotency_key: args.idempotency_key.clone(), + signer_mode: None, + signer_session_id: None, requested_signer_session_id: args.signer_session_id.clone(), reason: Some(format!("order draft `{}` was not found", args.key)), job: None, @@ -307,6 +311,8 @@ pub fn submit( dry_run: false, deduplicated: false, idempotency_key: args.idempotency_key.clone(), + signer_mode: None, + signer_session_id: None, requested_signer_session_id: args.signer_session_id.clone(), reason: Some(reason), job: None, @@ -335,6 +341,8 @@ pub fn submit( dry_run: false, deduplicated: false, idempotency_key: args.idempotency_key.clone(), + signer_mode: job.signer_mode.clone(), + signer_session_id: job.signer_session_id.clone(), requested_signer_session_id: args.signer_session_id.clone(), reason: Some("order draft already has a recorded submission job".to_owned()), job: Some(job), @@ -363,6 +371,8 @@ pub fn submit( dry_run: false, deduplicated: false, idempotency_key: args.idempotency_key.clone(), + signer_mode: None, + signer_session_id: None, requested_signer_session_id: args.signer_session_id.clone(), reason: Some("order draft is not ready for durable submit".to_owned()), job: None, @@ -385,12 +395,16 @@ pub fn submit( dry_run: true, deduplicated: false, idempotency_key: args.idempotency_key.clone(), + signer_mode: None, + signer_session_id: None, requested_signer_session_id: args.signer_session_id.clone(), reason: Some("dry run requested; daemon order submission skipped".to_owned()), job: Some(OrderJobView { job_id: "not_submitted".to_owned(), state: "not_submitted".to_owned(), command: Some("order.submit".to_owned()), + signer_mode: Some(config.signer.backend.as_str().to_owned()), + signer_session_id: None, requested_signer_session_id: args.signer_session_id.clone(), event_id: None, event_addr: None, @@ -428,6 +442,7 @@ pub fn submit( job_id: result.job_id.clone(), state: Some(result.status.clone()), signer_mode: Some(result.signer_mode.clone()), + signer_session_id: result.signer_session_id.clone(), command: Some("order.submit".to_owned()), event_id: result.event_id.clone(), event_addr: result.event_addr.clone(), @@ -466,6 +481,8 @@ pub fn submit( dry_run: false, deduplicated: result.deduplicated, idempotency_key: result.idempotency_key.clone(), + signer_mode: Some(result.signer_mode.clone()), + signer_session_id: result.signer_session_id.clone(), requested_signer_session_id: args.signer_session_id.clone(), reason: failed.then(|| { "daemon order request failed before relay delivery completed".to_owned() @@ -474,6 +491,8 @@ pub fn submit( job_id: result.job_id, state: result.status, command: Some("order.submit".to_owned()), + signer_mode: Some(result.signer_mode), + signer_session_id: result.signer_session_id, requested_signer_session_id: args.signer_session_id.clone(), event_id: result.event_id, event_addr: result.event_addr, @@ -554,6 +573,8 @@ pub fn watch( observed_at_unix: job.completed_at_unix.unwrap_or(job.requested_at_unix), state: job.state.clone(), terminal: job.terminal, + signer_mode: job.signer.clone(), + signer_session_id: job.signer_session_id.clone(), summary: job.relay_outcome_summary.clone(), }); if job.terminal || frames.len() >= max_frames { @@ -1031,6 +1052,8 @@ fn submission_job_view( job_id, state: job.state, command: Some(job.command), + signer_mode: Some(job.signer.clone()), + signer_session_id: job.signer_session_id, requested_signer_session_id: None, event_id: job.event_id, event_addr: job.event_addr, @@ -1040,6 +1063,8 @@ fn submission_job_view( job_id, state: "missing".to_owned(), command: submission.command.clone(), + signer_mode: submission.signer_mode.clone(), + signer_session_id: submission.signer_session_id.clone(), requested_signer_session_id: None, event_id: submission.event_id.clone(), event_addr: submission.event_addr.clone(), @@ -1057,6 +1082,8 @@ fn recorded_job_view(submission: &OrderDraftSubmission, job_id: String) -> Order .clone() .unwrap_or_else(|| "recorded".to_owned()), command: submission.command.clone(), + signer_mode: submission.signer_mode.clone(), + signer_session_id: submission.signer_session_id.clone(), requested_signer_session_id: None, event_id: submission.event_id.clone(), event_addr: submission.event_addr.clone(), @@ -1072,6 +1099,8 @@ fn job_view_from_error(job_id: String, error: DaemonRpcError) -> OrderJobView { job_id, state: "unconfigured".to_owned(), command: None, + signer_mode: None, + signer_session_id: None, requested_signer_session_id: None, event_id: None, event_addr: None, @@ -1081,6 +1110,8 @@ fn job_view_from_error(job_id: String, error: DaemonRpcError) -> OrderJobView { job_id, state: "unavailable".to_owned(), command: None, + signer_mode: None, + signer_session_id: None, requested_signer_session_id: None, event_id: None, event_addr: None, @@ -1092,6 +1123,8 @@ fn job_view_from_error(job_id: String, error: DaemonRpcError) -> OrderJobView { job_id, state: "error".to_owned(), command: None, + signer_mode: None, + signer_session_id: None, requested_signer_session_id: None, event_id: None, event_addr: None, @@ -1143,6 +1176,8 @@ fn order_submit_error_view( dry_run: false, deduplicated: false, idempotency_key: args.idempotency_key.clone(), + signer_mode: None, + signer_session_id: None, requested_signer_session_id: args.signer_session_id.clone(), reason: Some(reason), job: None, @@ -1415,6 +1450,7 @@ mod tests { job_id: "job_01".to_owned(), state: Some("accepted".to_owned()), signer_mode: Some("embedded_service_identity".to_owned()), + signer_session_id: None, command: Some("order.submit".to_owned()), event_id: None, event_addr: None, diff --git a/tests/job_rpc.rs b/tests/job_rpc.rs @@ -289,7 +289,8 @@ fn sample_job(job_id: &str, state: &str, terminal: bool, completed_at_unix: Opti "recovered_after_restart": false, "requested_at_unix": 1_712_720_000, "completed_at_unix": completed_at_unix, - "signer_mode": "embedded_service_identity", + "signer_mode": "nip46_session", + "signer_session_id": "session-1", "event_id": "event-123", "event_addr": "30023:npub1seller:listing-123", "delivery_policy": "best_effort", @@ -487,6 +488,8 @@ fn job_ls_and_get_report_retained_bridge_jobs() { assert_eq!(list_json["count"], 1); assert_eq!(list_json["jobs"][0]["id"], "job-123"); assert_eq!(list_json["jobs"][0]["command"], "listing.publish"); + assert_eq!(list_json["jobs"][0]["signer"], "nip46_session"); + assert_eq!(list_json["jobs"][0]["signer_session_id"], "session-1"); let get = job_rpc_command_in(dir.path()) .env("RADROOTS_RPC_URL", server.url()) @@ -498,6 +501,8 @@ fn job_ls_and_get_report_retained_bridge_jobs() { let get_json: Value = serde_json::from_slice(get.stdout.as_slice()).expect("get json"); assert_eq!(get_json["state"], "ready"); assert_eq!(get_json["job"]["id"], "job-123"); + assert_eq!(get_json["job"]["signer"], "nip46_session"); + assert_eq!(get_json["job"]["signer_session_id"], "session-1"); assert_eq!( get_json["job"]["relay_outcome_summary"], "published to 2 relays" @@ -569,6 +574,9 @@ fn job_watch_ndjson_emits_one_frame_per_poll_until_terminal() { assert_eq!(lines.len(), 2); assert!(lines[0].contains("\"sequence\":1")); assert!(lines[0].contains("\"state\":\"publishing\"")); + assert!(lines[0].contains("\"signer\":\"nip46_session\"")); + assert!(lines[0].contains("\"signer_session_id\":\"session-1\"")); assert!(lines[1].contains("\"sequence\":2")); assert!(lines[1].contains("\"terminal\":true")); + assert!(lines[1].contains("\"signer_session_id\":\"session-1\"")); } diff --git a/tests/listing.rs b/tests/listing.rs @@ -331,7 +331,13 @@ fn listing_publish_and_update_use_durable_bridge_publish() { assert_eq!(auth_header.as_deref(), Some("Bearer bridge-secret")); MockRpcResponse::success(json!({ "deduplicated": false, - "job": sample_listing_job("job_listing_01", "published", "event_listing_01", "30402:deadbeef:AAAAAAAAAAAAAAAAAAAAAg") + "job": sample_listing_job( + "job_listing_01", + "published", + "event_listing_01", + "30402:deadbeef:AAAAAAAAAAAAAAAAAAAAAg", + "sess_publish_01" + ) })) } other => MockRpcResponse::rpc_error(-32601, &format!("unexpected method: {other}")), @@ -363,7 +369,11 @@ fn listing_publish_and_update_use_durable_bridge_publish() { assert_eq!(publish_json["job_status"], "published"); assert_eq!(publish_json["event_id"], "event_listing_01"); assert_eq!(publish_json["event"]["kind"], 30402); + assert_eq!(publish_json["signer_mode"], "nip46_session"); + assert_eq!(publish_json["signer_session_id"], "sess_publish_01"); assert_eq!(publish_json["job"]["rpc_method"], "bridge.listing.publish"); + assert_eq!(publish_json["job"]["signer_mode"], "nip46_session"); + assert_eq!(publish_json["job"]["signer_session_id"], "sess_publish_01"); assert_eq!( publish_json["requested_signer_session_id"], "sess_publish_01" @@ -471,7 +481,13 @@ fn listing_archive_and_dry_run_are_truthful() { )])), "bridge.listing.publish" => MockRpcResponse::success(json!({ "deduplicated": false, - "job": sample_listing_job("job_listing_archive", "published", "event_listing_archive", "30402:deadbeef:AAAAAAAAAAAAAAAAAAAAAg") + "job": sample_listing_job( + "job_listing_archive", + "published", + "event_listing_archive", + "30402:deadbeef:AAAAAAAAAAAAAAAAAAAAAg", + "sess_archive_01" + ) })), other => MockRpcResponse::rpc_error(-32601, &format!("unexpected method: {other}")), } @@ -495,6 +511,8 @@ fn listing_archive_and_dry_run_are_truthful() { serde_json::from_slice(archive_output.stdout.as_slice()).expect("archive json"); assert_eq!(archive_json["operation"], "archive"); assert_eq!(archive_json["job_status"], "published"); + assert_eq!(archive_json["signer_mode"], "nip46_session"); + assert_eq!(archive_json["signer_session_id"], "sess_archive_01"); assert_eq!( archive_json["requested_signer_session_id"], "sess_archive_01" @@ -520,6 +538,10 @@ fn listing_archive_and_dry_run_are_truthful() { assert_eq!(dry_run_json["state"], "dry_run"); assert_eq!(dry_run_json["dry_run"], true); assert_eq!(dry_run_json["job"]["state"], "not_submitted"); + assert!(dry_run_json["signer_mode"].is_null()); + assert!(dry_run_json["signer_session_id"].is_null()); + assert_eq!(dry_run_json["job"]["signer_mode"], "local"); + assert!(dry_run_json["job"]["signer_session_id"].is_null()); assert_eq!(dry_run_json["event"]["kind"], 30402); assert!(dry_run_json["event"]["event_id"].is_null()); assert_eq!( @@ -944,7 +966,13 @@ fn write_response(stream: &mut TcpStream, response: &MockRpcResponse) -> Result< .map_err(|error| format!("flush mock rpc response: {error}")) } -fn sample_listing_job(job_id: &str, status: &str, event_id: &str, event_addr: &str) -> Value { +fn sample_listing_job( + job_id: &str, + status: &str, + event_id: &str, + event_addr: &str, + signer_session_id: &str, +) -> Value { json!({ "job_id": job_id, "command": "bridge.listing.publish", @@ -954,7 +982,8 @@ fn sample_listing_job(job_id: &str, status: &str, event_id: &str, event_addr: &s "recovered_after_restart": false, "requested_at_unix": 1_712_720_000, "completed_at_unix": 1_712_720_010, - "signer_mode": "local", + "signer_mode": "nip46_session", + "signer_session_id": signer_session_id, "event_kind": 30402, "event_id": event_id, "event_addr": event_addr, diff --git a/tests/order.rs b/tests/order.rs @@ -256,7 +256,8 @@ fn sample_bridge_job(job_id: &str, state: &str, terminal: bool) -> Value { "recovered_after_restart": false, "requested_at_unix": 1_712_720_000, "completed_at_unix": terminal.then_some(1_712_720_030), - "signer_mode": "embedded_service_identity", + "signer_mode": "nip46_session", + "signer_session_id": "sess_order_01", "event_kind": 30420, "event_id": "evt_order_01", "event_addr": "30402:deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef:AAAAAAAAAAAAAAAAAAAAAg", @@ -529,8 +530,12 @@ fn order_submit_persists_submission_metadata_and_reports_job() { let submit_json: Value = serde_json::from_slice(submit_output.stdout.as_slice()).expect("submit json"); assert_eq!(submit_json["state"], "accepted"); + assert_eq!(submit_json["signer_mode"], "nip46_session"); + assert_eq!(submit_json["signer_session_id"], "sess_order_01"); assert_eq!(submit_json["job"]["job_id"], "job_order_01"); assert_eq!(submit_json["job"]["command"], "order.submit"); + assert_eq!(submit_json["job"]["signer_mode"], "nip46_session"); + assert_eq!(submit_json["job"]["signer_session_id"], "sess_order_01"); assert_eq!(submit_json["requested_signer_session_id"], "sess_order_01"); assert_eq!( submit_json["job"]["requested_signer_session_id"], @@ -632,6 +637,10 @@ job_id = "job_watch_01" assert_eq!(json["frames"].as_array().map(Vec::len), Some(2)); assert_eq!(json["frames"][0]["state"], "accepted"); assert_eq!(json["frames"][1]["state"], "completed"); + assert_eq!(json["frames"][0]["signer_mode"], "nip46_session"); + assert_eq!(json["frames"][0]["signer_session_id"], "sess_order_01"); + assert_eq!(json["frames"][1]["signer_mode"], "nip46_session"); + assert_eq!(json["frames"][1]["signer_session_id"], "sess_order_01"); } #[test]