From a030707cd6dc802acd5100d351ddffb20a10509c Mon Sep 17 00:00:00 2001 From: Matthieu MALVACHE Date: Mon, 23 Mar 2026 14:13:01 +0100 Subject: [PATCH] feat(jmap): add Mailbox/set methods for create, update, destroy (#44) --- lib/jmap/client.ts | 64 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/lib/jmap/client.ts b/lib/jmap/client.ts index 0c05634..03124e1 100644 --- a/lib/jmap/client.ts +++ b/lib/jmap/client.ts @@ -56,6 +56,17 @@ interface JMAPResponse { methodResponses: Array<[string, JMAPResponseResult, string]>; } +export class JMAPSetError extends Error { + type: string; + description?: string; + constructor(type: string, description?: string) { + super(description || `Mailbox/set error: ${type}`); + this.name = 'JMAPSetError'; + this.type = type; + this.description = description; + } +} + const DEFAULT_MAILBOX_RIGHTS = { mayReadItems: true, mayAddItems: true, @@ -762,6 +773,59 @@ export class JMAPClient { ]); } + async createMailbox(name: string, parentId?: string): Promise { + const create: Record = { name }; + if (parentId) create.parentId = parentId; + + const response = await this.request([ + ["Mailbox/set", { + accountId: this.accountId, + create: { "new-mailbox": create }, + }, "0"], + ]); + + const result = response.methodResponses?.[0]?.[1]; + if (result?.notCreated?.["new-mailbox"]) { + const err = result.notCreated["new-mailbox"]; + throw new JMAPSetError(err.type || "unknown", err.description); + } + + const realId = result?.created?.["new-mailbox"]?.id; + if (!realId) throw new JMAPSetError("unknown", "Server did not return created mailbox ID"); + return realId; + } + + async updateMailbox(id: string, changes: { name?: string; parentId?: string | null }): Promise { + const response = await this.request([ + ["Mailbox/set", { + accountId: this.accountId, + update: { [id]: changes }, + }, "0"], + ]); + + const result = response.methodResponses?.[0]?.[1]; + if (result?.notUpdated?.[id]) { + const err = result.notUpdated[id]; + throw new JMAPSetError(err.type || "unknown", err.description); + } + } + + async destroyMailbox(id: string): Promise { + const response = await this.request([ + ["Mailbox/set", { + accountId: this.accountId, + destroy: [id], + onDestroyRemoveEmails: false, + }, "0"], + ]); + + const result = response.methodResponses?.[0]?.[1]; + if (result?.notDestroyed?.[id]) { + const err = result.notDestroyed[id]; + throw new JMAPSetError(err.type || "unknown", err.description); + } + } + async moveEmail(emailId: string, toMailboxId: string, accountId?: string): Promise { const targetAccountId = accountId || this.accountId; const response = await this.request([