Files
webmail/lib/plugin-sandbox/assistant/c.runtime.ts
T
Linus Rath fd30fdcd27 feat: let plugins answer invitations, add filter rules, change many messages and change settings, with undo
The AI assistant's "more actions" need host calls today's plugin API
lacks. Area c of lib/plugin-sandbox/assistant adds them:

- `calendar.respond(emailId, status)`, new permission calendar:respond:
  answers an invitation of the user's own account through
  lib/calendar-rsvp.ts, like the reader's banner
- `calendar.deleteEvent` now returns an undo token for a single event;
  `calendar.undoDelete` creates it again from the host's copy
- `filters.list/create/undo` over Settings > Filters' model; forward,
  redirect, reject, discard and keep are refused, and so are folders
  that are shared or not the account's own
- `email.batch/undoBatch`: up to 200 messages through the store's
  batch functions, restore points first, one entry in the undo history
- `vacation.get` also says whether the out-of-office forwards mail
- `app.describeSettings`, `app.setSettings` and `app.undoSettings`, new
  permission settings:change, over the allow-list in
  lib/settings-schema.ts, refusing locked, hidden, restricted and gated
  settings when the change is made

Undo tokens stay in the host for 30 minutes, bound to the plugin and
the account. app.getSettings now shows every setting setSettings may
change. settings:write's text is reworded to what it gates (tags).
plugin-host-api-app-info gains a test; its other assertions are as
they were.
2026-11-02 23:14:23 +01:00

40 lines
2.0 KiB
TypeScript

// Area c of the assistant's host APIs, inside the plugin sandbox (see README.md).
import type { CallApi, RuntimeAdditions } from './runtime';
import type {
FilterRuleInput, InvitationAnswer, MailBatchInput, SettingValue,
} from './c.types';
/** The methods this area adds to the plugin's api, by namespace. */
export function runtime(callApi: CallApi): RuntimeAdditions {
return {
calendar: {
// Answer an invitation in a message of the user's own account, as the
// reader's banner does; the server sends the reply to the organiser
// (permission calendar:respond).
respond: (emailId: string, status: InvitationAnswer) => callApi('calendar.respond', [emailId, status]),
// Put back an event calendar.deleteEvent deleted, from its undo token (calendar:write).
undoDelete: (undoToken: string) => callApi('calendar.undoDelete', [undoToken]),
},
filters: {
// The account's filter rules (filters:read).
list: () => callApi('filters.list', []),
// Add a rule at the top; no forwarding, rejecting or deleting rules (filters:write).
create: (rule: FilterRuleInput) => callApi('filters.create', [rule]),
undo: (undoToken: string) => callApi('filters.undo', [undoToken]),
},
email: {
// One change to up to 200 messages of the account, with one Undo (email:write).
batch: (batch: MailBatchInput) => callApi('email.batch', [batch]),
undoBatch: (undoToken: string) => callApi('email.undoBatch', [undoToken]),
},
app: {
// Settings in the user's language: label, page, current and new value (settings:read).
describeSettings: (changes: Record<string, SettingValue> | string[]) => callApi('app.describeSettings', [changes]),
// Change settings on the allow-list (settings:change).
setSettings: (changes: Record<string, SettingValue>) => callApi('app.setSettings', [changes]),
undoSettings: (undoToken: string) => callApi('app.undoSettings', [undoToken]),
},
};
}