import * as plugins from '../plugins.js'; import type * as servezoneInterfaces from '@serve.zone/interfaces'; import * as interfaces from '../../ts_interfaces/index.js'; import { appState } from './shared.js'; import { getActionContext } from './login.js'; import { captureRealtimeTicket, isRealtimeTicketCurrent } from './realtime.js'; export interface ICertificateState { certificates: interfaces.requests.ICertificateInfo[]; summary: { total: number; valid: number; expiring: number; expired: number; failed: number; unknown: number }; isLoading: boolean; error: string | null; lastUpdated: number; } export const certificateStatePart = await appState.getStatePart( 'certificates', { certificates: [], summary: { total: 0, valid: 0, expiring: 0, expired: 0, failed: 0, unknown: 0 }, isLoading: false, error: null, lastUpdated: 0, }, 'soft' ); // Certificate Actions // ============================================================================ export const fetchCertificateOverviewAction = certificateStatePart.createAction(async (statePartArg): Promise => { const context = getActionContext(); const currentState = statePartArg.getState()!; if (!context.identity) return currentState; const ticket = captureRealtimeTicket('certificates'); try { const request = new plugins.domtools.plugins.typedrequest.TypedRequest< interfaces.requests.IReq_GetCertificateOverview >('/typedrequest', 'getCertificateOverview'); const response = await request.fire({ identity: context.identity, }); if (!isRealtimeTicketCurrent(ticket)) return statePartArg.getState()!; return { ...statePartArg.getState()!, certificates: response.certificates, summary: response.summary, isLoading: false, error: null, lastUpdated: Date.now(), }; } catch (error) { if (!isRealtimeTicketCurrent(ticket)) return statePartArg.getState()!; return { ...statePartArg.getState()!, isLoading: false, error: error instanceof Error ? error.message : 'Failed to fetch certificate overview', }; } }); export async function requestCertificateReprovision(domain: string, forceRenew?: boolean) { const context = getActionContext(); const request = new plugins.domtools.plugins.typedrequest.TypedRequest< interfaces.requests.IReq_ReprovisionCertificateDomain >('/typedrequest', 'reprovisionCertificateDomain'); return request.fire({ identity: context.identity!, domain, forceRenew, }); } export const deleteCertificateAction = certificateStatePart.createAction( async (statePartArg, domain, actionContext): Promise => { const context = getActionContext(); const currentState = statePartArg.getState()!; try { const request = new plugins.domtools.plugins.typedrequest.TypedRequest< interfaces.requests.IReq_DeleteCertificate >('/typedrequest', 'deleteCertificate'); await request.fire({ identity: context.identity!, domain, }); // Re-fetch overview after deletion return await actionContext!.dispatch(fetchCertificateOverviewAction, null); } catch (error: unknown) { return { ...currentState, error: error instanceof Error ? error.message : 'Failed to delete certificate', }; } } ); export const importCertificateAction = certificateStatePart.createAction<{ id: string; domainName: string; created: number; validUntil: number; privateKey: string; publicKey: string; csr: string; }>( async (statePartArg, cert, actionContext): Promise => { const context = getActionContext(); const currentState = statePartArg.getState()!; try { const request = new plugins.domtools.plugins.typedrequest.TypedRequest< servezoneInterfaces.requests.gateway.IReq_ImportCertificate >('/typedrequest', 'importCertificate'); await request.fire({ identity: context.identity!, cert, }); // Re-fetch overview after import return await actionContext!.dispatch(fetchCertificateOverviewAction, null); } catch (error: unknown) { return { ...currentState, error: error instanceof Error ? error.message : 'Failed to import certificate', }; } } ); export async function fetchCertificateExport(domain: string) { const context = getActionContext(); const request = new plugins.domtools.plugins.typedrequest.TypedRequest< servezoneInterfaces.requests.gateway.IReq_ExportCertificate >('/typedrequest', 'exportCertificate'); return request.fire({ identity: context.identity!, domain, }); } // ============================================================================