feat: add contact methods in plugin API
This commit is contained in:
@@ -14,6 +14,7 @@ import { apiFetch } from '../browser-navigation';
|
|||||||
import { awaitDialog, awaitPrompt, type PromptField } from './host-dialog';
|
import { awaitDialog, awaitPrompt, type PromptField } from './host-dialog';
|
||||||
import { fileStorage } from '../plugin-storage';
|
import { fileStorage } from '../plugin-storage';
|
||||||
import { generateUUID } from '../utils';
|
import { generateUUID } from '../utils';
|
||||||
|
import { ContactCard } from '../jmap/types';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Methods only callable from the privileged (same-origin) tier. These expose
|
* Methods only callable from the privileged (same-origin) tier. These expose
|
||||||
@@ -56,6 +57,11 @@ const PERM_PER_METHOD: Record<string, Permission | null> = {
|
|||||||
'upfiles.get' : 'email:blob-write',
|
'upfiles.get' : 'email:blob-write',
|
||||||
'upfiles.save' : 'email:blob-write',
|
'upfiles.save' : 'email:blob-write',
|
||||||
'webauthn.getOrCreate': 'crypto:full',
|
'webauthn.getOrCreate': 'crypto:full',
|
||||||
|
// contact
|
||||||
|
'contact.get': 'contacts:read',
|
||||||
|
'contact.update': 'contacts:write',
|
||||||
|
'contact.create': 'contacts:write',
|
||||||
|
'contact.search': 'contacts:read',
|
||||||
// admin
|
// admin
|
||||||
'admin.getConfig': 'admin:config',
|
'admin.getConfig': 'admin:config',
|
||||||
'admin.getAllConfig': 'admin:config',
|
'admin.getAllConfig': 'admin:config',
|
||||||
@@ -388,6 +394,40 @@ async function doJmapImportRaw(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function doContactSearch(query: string): Promise<ContactCard[]> {
|
||||||
|
const { client } = useAuthStore.getState();
|
||||||
|
if (!client) {
|
||||||
|
throw new Error('jmap.importRaw: no active session');
|
||||||
|
}
|
||||||
|
return await client.searchContacts(query);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function doContactGet(contactId: string): Promise<ContactCard | null> {
|
||||||
|
const { client } = useAuthStore.getState();
|
||||||
|
if (!client) {
|
||||||
|
throw new Error('jmap.importRaw: no active session');
|
||||||
|
}
|
||||||
|
return await client.getContact(contactId);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function doContactUpdate(id: string, contact: Partial<ContactCard>): Promise<void> {
|
||||||
|
const { client } = useAuthStore.getState();
|
||||||
|
if (!client) {
|
||||||
|
throw new Error('jmap.importRaw: no active session');
|
||||||
|
}
|
||||||
|
|
||||||
|
await client.updateContact(id, contact);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function doContactCreate(contact: ContactCard): Promise<ContactCard> {
|
||||||
|
const { client } = useAuthStore.getState();
|
||||||
|
if (!client) {
|
||||||
|
throw new Error('jmap.importRaw: no active session');
|
||||||
|
}
|
||||||
|
|
||||||
|
return await client.createContact(contact);
|
||||||
|
}
|
||||||
|
|
||||||
// ─── WebAuthn (privileged tier) ─────────────────────────────────────────────
|
// ─── WebAuthn (privileged tier) ─────────────────────────────────────────────
|
||||||
|
|
||||||
// This salt acts as a constant context identifier for key derivation.
|
// This salt acts as a constant context identifier for key derivation.
|
||||||
@@ -699,6 +739,11 @@ export async function dispatchApiCall(
|
|||||||
case 'upfiles.get' : return getFile(args[0] as string);
|
case 'upfiles.get' : return getFile(args[0] as string);
|
||||||
case 'upfiles.save' : return saveFile(args[0] as string, args[1] as File);
|
case 'upfiles.save' : return saveFile(args[0] as string, args[1] as File);
|
||||||
case 'webauthn.getOrCreate': return doGetOrCreatePRF(args[0] as number[] | undefined, args[1] as string | undefined, args[2] as string | undefined);
|
case 'webauthn.getOrCreate': return doGetOrCreatePRF(args[0] as number[] | undefined, args[1] as string | undefined, args[2] as string | undefined);
|
||||||
|
|
||||||
|
case 'contact.get': return doContactGet(args[0] as string);
|
||||||
|
case 'contact.update': return doContactUpdate(args[0] as string, args[1] as Partial<ContactCard>);
|
||||||
|
case 'contact.create': return doContactCreate(args[0] as ContactCard);
|
||||||
|
case 'contact.search': return doContactSearch(args[0] as string);
|
||||||
|
|
||||||
case 'admin.getConfig': return adminGet(plugin.id, args[0] as string);
|
case 'admin.getConfig': return adminGet(plugin.id, args[0] as string);
|
||||||
case 'admin.getAllConfig': return adminGetAll(plugin.id);
|
case 'admin.getAllConfig': return adminGetAll(plugin.id);
|
||||||
|
|||||||
@@ -244,6 +244,7 @@ export const API_METHODS = [
|
|||||||
'webauthn.getOrCreate',
|
'webauthn.getOrCreate',
|
||||||
'jmap.fetchBlob', 'jmap.sendRaw',
|
'jmap.fetchBlob', 'jmap.sendRaw',
|
||||||
'upfiles.get', 'upfiles.save',
|
'upfiles.get', 'upfiles.save',
|
||||||
|
'contact.get', 'contact.update', 'contact.create', 'contact.search',
|
||||||
'admin.getConfig', 'admin.getAllConfig', 'admin.setConfig', 'admin.deleteConfig',
|
'admin.getConfig', 'admin.getAllConfig', 'admin.setConfig', 'admin.deleteConfig',
|
||||||
'toast.success', 'toast.error', 'toast.info', 'toast.warning',
|
'toast.success', 'toast.error', 'toast.info', 'toast.warning',
|
||||||
'ui.confirm', 'ui.alert', 'ui.prompt', 'ui.rerenderEmail', 'ui.rerenderFetchedEmails', 'ui.openExternalUrl', 'ui.downloadFile',
|
'ui.confirm', 'ui.alert', 'ui.prompt', 'ui.rerenderEmail', 'ui.rerenderFetchedEmails', 'ui.openExternalUrl', 'ui.downloadFile',
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ import type {
|
|||||||
} from './protocol';
|
} from './protocol';
|
||||||
import { themeSnapshotToCSS, type ThemeSnapshot } from './host-theme';
|
import { themeSnapshotToCSS, type ThemeSnapshot } from './host-theme';
|
||||||
import type { SlotName } from '../plugin-types';
|
import type { SlotName } from '../plugin-types';
|
||||||
|
import { ContactCard } from '../jmap/types';
|
||||||
|
|
||||||
// ─── Module-scope state ──────────────────────────────────────
|
// ─── Module-scope state ──────────────────────────────────────
|
||||||
|
|
||||||
@@ -204,6 +205,12 @@ function buildPluginApi(manifest: PluginManifest) {
|
|||||||
opts?: { keywords?: Record<string, boolean>; accountId?: string },
|
opts?: { keywords?: Record<string, boolean>; accountId?: string },
|
||||||
) => callApi('jmap.importRaw', [rawBytes, mailboxRoles, opts]),
|
) => callApi('jmap.importRaw', [rawBytes, mailboxRoles, opts]),
|
||||||
},
|
},
|
||||||
|
contacts: {
|
||||||
|
get: (contactId: string) => callApi('contact.get', [contactId]) as Promise<ContactCard>,
|
||||||
|
update: (contactId: string, updates: Partial<ContactCard>) => callApi('contact.update', [contactId, updates]),
|
||||||
|
create: (contact: ContactCard) => callApi('contact.create', [contact]) as Promise<string>,
|
||||||
|
search: (query: string) => callApi('contact.search', [query]) as Promise<ContactCard[]>,
|
||||||
|
},
|
||||||
/**
|
/**
|
||||||
* Used to alterate files before they are uploaded to server.
|
* Used to alterate files before they are uploaded to server.
|
||||||
* Edited files are saved on indexedDB and remove once the upload to server begins.
|
* Edited files are saved on indexedDB and remove once the upload to server begins.
|
||||||
|
|||||||
Reference in New Issue
Block a user