import { jmapClient } from './jmap-client'; import { assertSetResult, requireMethodResult } from './jmap-result'; import { CAPABILITIES } from './types'; import type { Identity } from './types'; import { sanitizeDisplayName } from '../lib/rfc5322-mailbox'; const USING = [CAPABILITIES.CORE, CAPABILITIES.SUBMISSION]; // A display name that carries an address or a line break produces a malformed // `From:` on every message sent with the identity (#672); reduce it to the // bare name before it reaches the server. function sanitizeIdentityPatch(identity: Partial): Partial { if (typeof identity.name !== 'string') return identity; return { ...identity, name: sanitizeDisplayName(identity.name) }; } export async function getIdentities(accountIdOverride?: string): Promise { const accountId = accountIdOverride ?? jmapClient.accountId; const res = await jmapClient.request([['Identity/get', { accountId }, '0']], USING); const body = requireMethodResult<{ list?: Identity[] }>(res, '0', 'Identity/get'); return body.list ?? []; } export async function createIdentity( identity: Partial, ): Promise { const accountId = jmapClient.accountId; const cid = 'new-identity'; const res = await jmapClient.request( [['Identity/set', { accountId, create: { [cid]: sanitizeIdentityPatch(identity) } }, '0']], USING, ); const body = requireMethodResult(res, '0', 'Identity/set'); assertSetResult(body, [cid], 'identity'); const created = body.created?.[cid] as Partial | undefined; if (!created?.id) throw new Error('Identity/set returned no id'); // The create echo carries only server-set properties; re-read the full // object so the caller gets name/email/signature back. const all = await getIdentities(); return all.find((i) => i.id === created.id) ?? ({ ...identity, ...created } as Identity); } export async function updateIdentity( id: string, changes: Partial, ): Promise { const accountId = jmapClient.accountId; const res = await jmapClient.request( [['Identity/set', { accountId, update: { [id]: sanitizeIdentityPatch(changes) } }, '0']], USING, ); assertSetResult(requireMethodResult(res, '0', 'Identity/set'), [id], 'identity'); } export async function deleteIdentity(id: string): Promise { const accountId = jmapClient.accountId; const res = await jmapClient.request( [['Identity/set', { accountId, destroy: [id] }, '0']], USING, ); assertSetResult(requireMethodResult(res, '0', 'Identity/set'), [id], 'identity'); }