From b9d977237e3f0a962ea0a2f17ad595d7e7f759d8 Mon Sep 17 00:00:00 2001 From: Jost Schulte Date: Tue, 12 Nov 2024 14:42:23 -0600 Subject: [PATCH] feat(app-ws): add call PublishCountersigningSession --- src/api/app/types.ts | 12 +++++++++ src/api/app/websocket.ts | 53 +++++++++++++++++++++++++++++++++++++++ test/e2e/app-websocket.ts | 11 ++++++++ 3 files changed, 76 insertions(+) diff --git a/src/api/app/types.ts b/src/api/app/types.ts index 1bdf141c..c0446c8e 100644 --- a/src/api/app/types.ts +++ b/src/api/app/types.ts @@ -264,6 +264,18 @@ export type AbandonCountersigningSessionStateRequest = CellId; */ export type AbandonCountersigningSessionStateResponse = null; +/** + * Cell id for which the countersigning session should be published. + * + * @public + */ +export type PublishCountersigningSessionStateRequest = CellId; + +/** + * @public + */ +export type PublishCountersigningSessionStateResponse = null; + export enum CountersigningSessionStateType { Accepted = "Accepted", SignaturesCollected = "SignaturesCollected", diff --git a/src/api/app/websocket.ts b/src/api/app/websocket.ts index cd61be30..27721e36 100644 --- a/src/api/app/websocket.ts +++ b/src/api/app/websocket.ts @@ -52,6 +52,8 @@ import { GetCountersigningSessionStateResponse, AbandonCountersigningSessionStateRequest, AbandonCountersigningSessionStateResponse, + PublishCountersigningSessionStateRequest, + PublishCountersigningSessionStateResponse, } from "./types.js"; import { getHostZomeCallSigner, @@ -123,6 +125,10 @@ export class AppWebsocket implements AppClient { AbandonCountersigningSessionStateRequest, AbandonCountersigningSessionStateResponse >; + private readonly publishCountersigningSessionRequester: Requester< + PublishCountersigningSessionStateRequest, + PublishCountersigningSessionStateResponse + >; private constructor( client: WsClient, @@ -189,6 +195,11 @@ export class AppWebsocket implements AppClient { "abandon_countersigning_session", this.defaultTimeout ); + this.publishCountersigningSessionRequester = AppWebsocket.requester( + this.client, + "publish_countersigning_session", + this.defaultTimeout + ); // Ensure all super methods are bound to this instance because Emittery relies on `this` being the instance. // Please retain until the upstream is fixed https://github.com/sindresorhus/emittery/issues/86. @@ -481,6 +492,48 @@ export class AppWebsocket implements AppClient { return this.abandonCountersigningSessionRequester(args); } + /** + * Publish an unresolved countersigning session. + * + * If the current session has not been resolved automatically, it can be forcefully published. + * A condition for this call to succeed is that at least one attempt has been made to resolve + * it automatically. + * + * # Returns + * + * [`AppResponse::PublishCountersigningSessionTriggered`] + * + * The session is marked for publishing and the countersigning workflow was triggered. The session + * has not been published yet. + * + * Upon successful publishing the system signal [`SystemSignal::SuccessfulCountersigning`] will + * be emitted and the session removed from state, so that [`AppRequest::GetCountersigningSessionState`] + * would return `None`. + * + * In the countersigning workflow it will first be attempted to resolve the session with incoming + * signatures of the countersigned entries, before force-publishing the session. In a very rare event + * it could happen that in just the moment where the [`AppRequest::PublishCountersigningSession`] + * is made, signatures for this session come in. If they are valid, the session will be resolved and + * published as usual. Should they be invalid, however, the flag to publish the session is erased. + * In such cases this request can be retried until the session has been published successfully. + * + * # Errors + * + * [`CountersigningError::WorkspaceDoesNotExist`] likely indicates that an invalid cell id was + * passed in to the call. + * + * [`CountersigningError::SessionNotFound`] when no ongoing session could be found for the provided + * cell id. + * + * [`CountersigningError::SessionNotUnresolved`] when an attempt to resolve the session + * automatically has not been made. + */ + async publishCountersigningSession( + args: PublishCountersigningSessionStateRequest + ) { + return this.publishCountersigningSessionRequester(args); + } + /** * Register an event listener for signals. * diff --git a/test/e2e/app-websocket.ts b/test/e2e/app-websocket.ts index 621fe03f..c9519d63 100644 --- a/test/e2e/app-websocket.ts +++ b/test/e2e/app-websocket.ts @@ -336,5 +336,16 @@ test.only( "there should not be a countersigning session" ); } + + try { + await appWs.publishCountersigningSession(cell_id); + t.fail("there should not be a countersigning session to be published"); + } catch (error) { + assert(error instanceof Error); + t.assert( + error.message.includes("SessionNotFound"), + "there should not be a countersigning session" + ); + } }) );