Initial Commit
This commit is contained in:
292
src/controllers/invitation-controller.ts
Normal file
292
src/controllers/invitation-controller.ts
Normal file
@@ -0,0 +1,292 @@
|
||||
/**
|
||||
* Invitation Controller - High-level interface for invitation management.
|
||||
*
|
||||
* Provides a simplified API for the TUI to interact with invitations,
|
||||
* wrapping the InvitationFlowManager and coordinating with the WalletController.
|
||||
*/
|
||||
|
||||
import { EventEmitter } from 'events';
|
||||
import type { XOInvitation } from '@xo-cash/types';
|
||||
import { InvitationFlowManager, type TrackedInvitation, type InvitationState } from '../services/invitation-flow.js';
|
||||
import type { WalletController } from './wallet-controller.js';
|
||||
import type { SyncClient } from '../services/sync-client.js';
|
||||
|
||||
/**
|
||||
* Events emitted by the invitation controller.
|
||||
*/
|
||||
export interface InvitationControllerEvents {
|
||||
'invitation-created': (invitationId: string) => void;
|
||||
'invitation-updated': (invitationId: string) => void;
|
||||
'invitation-state-changed': (invitationId: string, state: InvitationState) => void;
|
||||
'error': (error: Error) => void;
|
||||
}
|
||||
|
||||
/**
|
||||
* Controller for managing invitations in the TUI.
|
||||
*/
|
||||
export class InvitationController extends EventEmitter {
|
||||
/** Flow manager for invitation lifecycle */
|
||||
private flowManager: InvitationFlowManager;
|
||||
|
||||
/** Wallet controller reference */
|
||||
private walletController: WalletController;
|
||||
|
||||
/** Sync client reference */
|
||||
private syncClient: SyncClient;
|
||||
|
||||
/**
|
||||
* Creates a new invitation controller.
|
||||
* @param walletController - Wallet controller instance
|
||||
* @param syncClient - Sync client instance
|
||||
*/
|
||||
constructor(walletController: WalletController, syncClient: SyncClient) {
|
||||
super();
|
||||
|
||||
this.walletController = walletController;
|
||||
this.syncClient = syncClient;
|
||||
this.flowManager = new InvitationFlowManager(walletController, syncClient);
|
||||
|
||||
// Forward events from flow manager
|
||||
this.flowManager.on('invitation-created', (invitation: XOInvitation) => {
|
||||
this.emit('invitation-created', invitation.invitationIdentifier);
|
||||
});
|
||||
|
||||
this.flowManager.on('invitation-updated', (invitationId: string) => {
|
||||
this.emit('invitation-updated', invitationId);
|
||||
});
|
||||
|
||||
this.flowManager.on('invitation-state-changed', (invitationId: string, state: InvitationState) => {
|
||||
this.emit('invitation-state-changed', invitationId, state);
|
||||
});
|
||||
|
||||
this.flowManager.on('error', (_invitationId: string, error: Error) => {
|
||||
this.emit('error', error);
|
||||
});
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Invitation Creation Flow
|
||||
// ============================================================================
|
||||
|
||||
/**
|
||||
* Creates a new invitation from a template action.
|
||||
* @param templateIdentifier - Template ID
|
||||
* @param actionIdentifier - Action ID
|
||||
* @returns Created tracked invitation
|
||||
*/
|
||||
async createInvitation(
|
||||
templateIdentifier: string,
|
||||
actionIdentifier: string,
|
||||
): Promise<TrackedInvitation> {
|
||||
return this.flowManager.createInvitation(templateIdentifier, actionIdentifier);
|
||||
}
|
||||
|
||||
/**
|
||||
* Publishes an invitation to the sync server and starts listening for updates.
|
||||
* @param invitationId - Invitation ID to publish
|
||||
* @returns The invitation ID for sharing
|
||||
*/
|
||||
async publishAndSubscribe(invitationId: string): Promise<string> {
|
||||
// Publish to sync server
|
||||
await this.flowManager.publishInvitation(invitationId);
|
||||
|
||||
// Subscribe to SSE updates
|
||||
await this.flowManager.subscribeToUpdates(invitationId);
|
||||
|
||||
return invitationId;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Invitation Import Flow
|
||||
// ============================================================================
|
||||
|
||||
/**
|
||||
* Imports an invitation by ID from the sync server.
|
||||
* @param invitationId - Invitation ID to import
|
||||
* @returns Imported tracked invitation
|
||||
*/
|
||||
async importInvitation(invitationId: string): Promise<TrackedInvitation> {
|
||||
return this.flowManager.importInvitation(invitationId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Accepts an imported invitation (joins as participant).
|
||||
* @param invitationId - Invitation ID to accept
|
||||
* @returns Updated tracked invitation
|
||||
*/
|
||||
async acceptInvitation(invitationId: string): Promise<TrackedInvitation> {
|
||||
return this.flowManager.acceptInvitation(invitationId);
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Invitation Data Operations
|
||||
// ============================================================================
|
||||
|
||||
/**
|
||||
* Appends inputs to an invitation.
|
||||
* @param invitationId - Invitation ID
|
||||
* @param inputs - Inputs to add
|
||||
*/
|
||||
async addInputs(
|
||||
invitationId: string,
|
||||
inputs: Array<{
|
||||
outpointTransactionHash: string;
|
||||
outpointIndex: number;
|
||||
sequenceNumber?: number;
|
||||
}>,
|
||||
): Promise<TrackedInvitation> {
|
||||
return this.flowManager.appendToInvitation(invitationId, { inputs });
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends outputs to an invitation.
|
||||
* @param invitationId - Invitation ID
|
||||
* @param outputs - Outputs to add
|
||||
*/
|
||||
async addOutputs(
|
||||
invitationId: string,
|
||||
outputs: Array<{
|
||||
valueSatoshis?: bigint;
|
||||
lockingBytecode?: Uint8Array;
|
||||
outputIdentifier?: string;
|
||||
roleIdentifier?: string;
|
||||
}>,
|
||||
): Promise<TrackedInvitation> {
|
||||
return this.flowManager.appendToInvitation(invitationId, { outputs });
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends variables to an invitation.
|
||||
* @param invitationId - Invitation ID
|
||||
* @param variables - Variables to add
|
||||
*/
|
||||
async addVariables(
|
||||
invitationId: string,
|
||||
variables: Array<{
|
||||
variableIdentifier: string;
|
||||
value: bigint | boolean | number | string;
|
||||
roleIdentifier?: string;
|
||||
}>,
|
||||
): Promise<TrackedInvitation> {
|
||||
return this.flowManager.appendToInvitation(invitationId, { variables });
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Signing & Broadcasting
|
||||
// ============================================================================
|
||||
|
||||
/**
|
||||
* Signs an invitation.
|
||||
* @param invitationId - Invitation ID to sign
|
||||
* @returns Updated tracked invitation
|
||||
*/
|
||||
async signInvitation(invitationId: string): Promise<TrackedInvitation> {
|
||||
return this.flowManager.signInvitation(invitationId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Broadcasts the transaction for an invitation.
|
||||
* @param invitationId - Invitation ID
|
||||
* @returns Transaction hash
|
||||
*/
|
||||
async broadcastTransaction(invitationId: string): Promise<string> {
|
||||
return this.flowManager.broadcastTransaction(invitationId);
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Queries
|
||||
// ============================================================================
|
||||
|
||||
/**
|
||||
* Gets a tracked invitation by ID.
|
||||
* @param invitationId - Invitation ID
|
||||
* @returns Tracked invitation or undefined
|
||||
*/
|
||||
getInvitation(invitationId: string): TrackedInvitation | undefined {
|
||||
return this.flowManager.get(invitationId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all tracked invitations.
|
||||
* @returns Array of tracked invitations
|
||||
*/
|
||||
getAllInvitations(): TrackedInvitation[] {
|
||||
return this.flowManager.getAll();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the invitation data.
|
||||
* @param invitationId - Invitation ID
|
||||
* @returns The XOInvitation or undefined
|
||||
*/
|
||||
getInvitationData(invitationId: string): XOInvitation | undefined {
|
||||
return this.flowManager.get(invitationId)?.invitation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the state of an invitation.
|
||||
* @param invitationId - Invitation ID
|
||||
* @returns Invitation state or undefined
|
||||
*/
|
||||
getInvitationState(invitationId: string): InvitationState | undefined {
|
||||
return this.flowManager.get(invitationId)?.state;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets available roles for an invitation.
|
||||
* @param invitationId - Invitation ID
|
||||
* @returns Array of available role identifiers
|
||||
*/
|
||||
async getAvailableRoles(invitationId: string): Promise<string[]> {
|
||||
const tracked = this.flowManager.get(invitationId);
|
||||
if (!tracked) {
|
||||
throw new Error(`Invitation not found: ${invitationId}`);
|
||||
}
|
||||
return this.walletController.getAvailableRoles(tracked.invitation);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets missing requirements for an invitation.
|
||||
* @param invitationId - Invitation ID
|
||||
* @returns Missing requirements
|
||||
*/
|
||||
async getMissingRequirements(invitationId: string) {
|
||||
const tracked = this.flowManager.get(invitationId);
|
||||
if (!tracked) {
|
||||
throw new Error(`Invitation not found: ${invitationId}`);
|
||||
}
|
||||
return this.walletController.getMissingRequirements(tracked.invitation);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets requirements for an invitation.
|
||||
* @param invitationId - Invitation ID
|
||||
* @returns Requirements
|
||||
*/
|
||||
async getRequirements(invitationId: string) {
|
||||
const tracked = this.flowManager.get(invitationId);
|
||||
if (!tracked) {
|
||||
throw new Error(`Invitation not found: ${invitationId}`);
|
||||
}
|
||||
return this.walletController.getRequirements(tracked.invitation);
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Cleanup
|
||||
// ============================================================================
|
||||
|
||||
/**
|
||||
* Stops tracking an invitation.
|
||||
* @param invitationId - Invitation ID to stop tracking
|
||||
*/
|
||||
stopTracking(invitationId: string): void {
|
||||
this.flowManager.untrack(invitationId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleans up all resources.
|
||||
*/
|
||||
destroy(): void {
|
||||
this.flowManager.destroy();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user