import axios, { type AxiosInstance } from 'axios'; export class JMAPClient { private apiUrl: string = ''; private accountId: string = ''; private client: AxiosInstance; constructor( private baseUrl: string, private username: string, private appPassword: string ) { const auth = Buffer.from(`${this.username}:${this.appPassword}`).toString('base64'); this.client = axios.create({ headers: { 'Authorization': `Basic ${auth}`, 'Content-Type': 'application/json', 'Accept': 'application/json', } }); } async connect(): Promise { // Fetch session // Stalwart redirects /.well-known/jmap to /jmap/session const sessionUrl = this.baseUrl.endsWith('/') ? `${this.baseUrl}jmap/session` : `${this.baseUrl}/jmap/session`; try { const response = await this.client.get(sessionUrl); const session = response.data; // Fix for Stalwart behind proxy returning internal docker hostname in apiUrl const parsedApiUrl = new URL(session.apiUrl); const parsedBaseUrl = new URL(this.baseUrl); parsedApiUrl.protocol = parsedBaseUrl.protocol; parsedApiUrl.host = parsedBaseUrl.host; parsedApiUrl.port = parsedBaseUrl.port; this.apiUrl = parsedApiUrl.toString(); console.error("API URL set to:", this.apiUrl); // Get the primary account for mail this.accountId = session.primaryAccounts['urn:ietf:params:jmap:mail']; if (!this.accountId) { throw new Error("No primary mail account found in JMAP session."); } } catch (error) { console.error("Failed to connect to JMAP session:", error); throw error; } } async request(methodCalls: any[][]): Promise { if (!this.apiUrl) { await this.connect(); } const payload = { using: [ "urn:ietf:params:jmap:core", "urn:ietf:params:jmap:mail" ], methodCalls }; const response = await this.client.post(this.apiUrl, payload); return response.data; } getAccountId(): string { return this.accountId; } }