import { RelayClientInstallProgressStageSchema, type RelayClientInstallProgressEvent, type RelayClientInstallProgressStage, } from "@t3tools/contracts"; import * as Schema from "effect/Schema"; export class RelayClientInstallConfirmationConflictError extends Schema.TaggedError()( "RelayClientInstallConfirmationConflictError", { requestedVersion: Schema.String, activeVersion: Schema.String, activeDialogStatus: Schema.Literals(["confirming", "installing", "closing"]), activeInstallStage: Schema.optional(RelayClientInstallProgressStageSchema), }, ) { override get message(): string { return `Cannot confirm relay client installation ${this.requestedVersion}; installation ${this.activeVersion} has dialog status ${this.activeDialogStatus}.`; } } export type RelayClientInstallDialogState = | { readonly status: "idle" } | { readonly status: "confirming"; readonly version: string } | { readonly status: "installing"; readonly version: string; readonly stage: RelayClientInstallProgressStage; } | { readonly status: "closing"; readonly view: | { readonly status: "confirming"; readonly version: string } | { readonly status: "installing"; readonly version: string; readonly stage: RelayClientInstallProgressStage; }; }; const idleState: RelayClientInstallDialogState = { status: "idle" }; let state: RelayClientInstallDialogState = idleState; let resolveConfirmation: ((confirmed: boolean) => void) | null = null; const listeners = new Set<() => void>(); function publish(next: RelayClientInstallDialogState) { state = next; for (const listener of listeners) { listener(); } } export function readRelayClientInstallDialogState(): RelayClientInstallDialogState { return state; } export function subscribeRelayClientInstallDialog(listener: () => void): () => void { listeners.add(listener); return () => { listeners.delete(listener); }; } export function requestRelayClientInstallConfirmation(version: string): Promise { if (state.status !== "idle") { const activeInstall = state.status === "closing" ? state.view : state; return Promise.reject( new RelayClientInstallConfirmationConflictError({ requestedVersion: version, activeVersion: activeInstall.version, activeDialogStatus: state.status, ...(activeInstall.status === "installing" ? { activeInstallStage: activeInstall.stage } : {}), }), ); } publish({ status: "confirming", version }); return new Promise((resolve) => { resolveConfirmation = resolve; }); } export function respondToRelayClientInstallConfirmation(confirmed: boolean): void { if (state.status !== "confirming" || !resolveConfirmation) { return; } const resolve = resolveConfirmation; resolveConfirmation = null; publish( confirmed ? { status: "installing", version: state.version, stage: "checking" } : { status: "closing", view: state }, ); resolve(confirmed); } export function reportRelayClientInstallProgress(event: RelayClientInstallProgressEvent): void { if (state.status !== "installing" || event.type !== "progress") { return; } publish({ ...state, stage: event.stage }); } export function finishRelayClientInstall(): void { resolveConfirmation?.(false); resolveConfirmation = null; if (state.status === "confirming" || state.status === "installing") { publish({ status: "closing", view: state }); } } export function completeRelayClientInstallDialogClose(): void { if (state.status === "closing") { publish(idleState); } } export function resetRelayClientInstallDialogForTests(): void { resolveConfirmation?.(false); resolveConfirmation = null; publish(idleState); listeners.clear(); }