@agenticmail/api 0.7.17 → 0.7.18

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -2167,9 +2167,23 @@ function createMailRoutes(accountManager2, config, db, gatewayManager) {
2167
2167
  res.status(400).json({ error: "Invalid UID" });
2168
2168
  return;
2169
2169
  }
2170
+ const permanent = req.query.permanent === "true" || req.query.permanent === "1";
2171
+ const sourceFolder = req.query.folder || "INBOX";
2170
2172
  const password = getAgentPassword(agent);
2171
2173
  const receiver = await getReceiver(agent.stalwartPrincipal, password, config);
2172
- await receiver.deleteMessage(uid);
2174
+ if (permanent) {
2175
+ await receiver.expungeMessage(uid, sourceFolder);
2176
+ res.status(204).send();
2177
+ return;
2178
+ }
2179
+ const folders = await receiver.listFolders();
2180
+ const trashRe = /^trash\b|deleted items|deleted messages|\[gmail\]\/trash|\[gmail\]\/bin/i;
2181
+ const trashFolder = folders.find((f) => trashRe.test(f.name) || trashRe.test(f.path))?.path ?? folders.find((f) => f.specialUse === "\\Trash")?.path;
2182
+ if (!trashFolder || trashFolder === sourceFolder) {
2183
+ await receiver.expungeMessage(uid, sourceFolder);
2184
+ } else {
2185
+ await receiver.moveToTrash(uid, sourceFolder, trashFolder);
2186
+ }
2173
2187
  res.status(204).send();
2174
2188
  } catch (err) {
2175
2189
  next(err);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agenticmail/api",
3
- "version": "0.7.17",
3
+ "version": "0.7.18",
4
4
  "description": "REST API server for AgenticMail — email and SMS endpoints for AI agents",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -247,15 +247,25 @@ async function markSpam() {
247
247
  async function deleteMessage() {
248
248
  if (!state.currentMessage || !state.selectedAgent) return;
249
249
  const subject = state.currentMessage.subject ?? '(no subject)';
250
+ // From Trash, delete is permanent (no further fallback). From
251
+ // every other folder it's a move-to-trash, recoverable.
252
+ const isTrash = state.selectedFolder === 'trash';
250
253
  const ok = await confirmModal({
251
- title: 'Delete this message?',
252
- body: `"${subject}" will be moved to Trash. This can't be undone from the web UI.`,
253
- confirm: 'Delete',
254
+ title: isTrash ? 'Delete this message forever?' : 'Delete this message?',
255
+ body: isTrash
256
+ ? `"${subject}" will be permanently removed. This can't be undone.`
257
+ : `"${subject}" will be moved to Trash. You can recover it from there.`,
258
+ confirm: isTrash ? 'Delete forever' : 'Move to Trash',
254
259
  danger: true,
255
260
  });
256
261
  if (!ok) return;
257
262
  try {
258
- await apiDelete(`/mail/messages/${state.selectedUid}`, { agentKey: state.selectedAgent.apiKey });
263
+ // Pass the real IMAP folder name + permanent flag. The API
264
+ // uses the folder for the IMAP source mailbox and decides
265
+ // move-to-trash vs expunge based on `permanent`.
266
+ const imap = state.folderNames?.[state.selectedFolder] ?? 'INBOX';
267
+ const qs = `?folder=${encodeURIComponent(imap)}${isTrash ? '&permanent=true' : ''}`;
268
+ await apiDelete(`/mail/messages/${state.selectedUid}${qs}`, { agentKey: state.selectedAgent.apiKey });
259
269
  toast('Deleted.');
260
270
  location.hash = `#/folder/${state.selectedFolder ?? 'inbox'}`;
261
271
  await loadList(state.selectedAgent, state.selectedFolder);