Merge pull request #768 from paulhenry46/uploadBlob-plugin-api

feat(plugins): add jmap.uploadBlob to plugins api
This commit is contained in:
Linus Rath
2026-08-11 09:53:29 +02:00
committed by GitHub
3 changed files with 13 additions and 1 deletions
+10
View File
@@ -27,6 +27,7 @@ import { EncryptionAtRestConfig, PublicKeyInfo, PublicKeyInput, useAccountSecuri
*/
const PRIVILEGED_ONLY_METHODS = new Set<string>([
'jmap.fetchBlob',
'jmap.uploadBlob',
'jmap.sendRaw',
'jmap.submitRaw',
'jmap.importRaw',
@@ -66,6 +67,7 @@ const PERM_PER_METHOD: Record<string, Permission | null> = {
'http.fetch': 'http:fetch',
// jmap (privileged-tier only; see PRIVILEGED_ONLY_METHODS)
'jmap.fetchBlob': 'email:blob-read',
'jmap.uploadBlob': 'email:blob-write',
'jmap.sendRaw': 'email:raw-send',
'jmap.submitRaw': 'email:raw-send',
'jmap.importRaw': 'email:raw-send',
@@ -394,6 +396,13 @@ async function doJmapFetchBlob(blobId: string, opts?: { name?: string; type?: st
return new Uint8Array(buf);
}
async function doJmapUploadBlob(content: Uint8Array, name: string, type: string): Promise<{ blobId: string; size: number; type: string; }> {
const { client } = useAuthStore.getState();
if (!client) throw new Error('jmap.uploadBlob: no active session');
const file = new File([content as BlobPart], name, { type });
return await client.uploadBlob(file);
}
interface JmapSubmitRawOptions {
delayedUntil?: string;
envelopeRecipients?: string[];
@@ -860,6 +869,7 @@ export async function dispatchApiCall(
case 'http.fetch': return doHttpFetch(plugin, args[0] as string, args[1] as PluginFetchInit | undefined);
case 'jmap.fetchBlob': return doJmapFetchBlob(args[0] as string, args[1] as { name?: string; type?: string } | undefined);
case 'jmap.uploadBlob': return doJmapUploadBlob(args[0] as Uint8Array, args[1] as string, args[2] as string);
case 'jmap.sendRaw': return doJmapSendRaw(
args[0] as ArrayBuffer | ArrayBufferView,
args[1] as string,
+1 -1
View File
@@ -242,7 +242,7 @@ export const API_METHODS = [
'storage.get', 'storage.set', 'storage.remove', 'storage.keys',
'http.post', 'http.fetch',
'crypto.getOrCreateWebAuthn', 'crypto.getPublicKeys', 'crypto.createPublicKey', 'crypto.removePublicKey', 'crypto.getEncryptionAtRest', 'crypto.setEncryptionAtRest',
'jmap.fetchBlob', 'jmap.sendRaw',
'jmap.fetchBlob', 'jmap.uploadBlob', 'jmap.sendRaw',
'upfiles.get', 'upfiles.save',
'contact.get', 'contact.update', 'contact.create', 'contact.search',
'admin.getConfig', 'admin.getAllConfig', 'admin.setConfig', 'admin.deleteConfig',
+2
View File
@@ -206,6 +206,8 @@ function buildPluginApi(manifest: PluginManifest) {
/** Fetch a blob's raw bytes by id. Resolves to a Uint8Array. */
fetchBlob: (blobId: string, opts?: { name?: string; type?: string }) =>
callApi('jmap.fetchBlob', [blobId, opts]) as Promise<Uint8Array>,
uploadBlob: (content: Uint8Array, name: string, type: string) =>
callApi('jmap.uploadBlob', [content, name, type]) as Promise<{ blobId: string; size: number; type: string; }>,
/** Submit a fully-formed raw RFC822 message (already signed/encrypted). */
sendRaw: (
rawBytes: ArrayBuffer | ArrayBufferView,