@agenticmail/api 0.9.9 → 0.9.11
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 +19 -4
- package/package.json +1 -1
- package/public/js/list-view.js +21 -2
package/dist/index.js
CHANGED
|
@@ -1861,7 +1861,19 @@ function normalizeWakeList(value) {
|
|
|
1861
1861
|
if (value === "all" || value === WAKE_ALL_SENTINEL) return void 0;
|
|
1862
1862
|
const strip = (s) => s.trim().replace(/@localhost$/i, "").toLowerCase();
|
|
1863
1863
|
if (Array.isArray(value)) return value.map((v) => strip(String(v))).filter(Boolean);
|
|
1864
|
-
if (typeof value === "string")
|
|
1864
|
+
if (typeof value === "string") {
|
|
1865
|
+
const trimmed = value.trim();
|
|
1866
|
+
if (trimmed.startsWith("[") && trimmed.endsWith("]")) {
|
|
1867
|
+
try {
|
|
1868
|
+
const parsed = JSON.parse(trimmed);
|
|
1869
|
+
if (Array.isArray(parsed)) {
|
|
1870
|
+
return parsed.map((v) => strip(String(v))).filter(Boolean);
|
|
1871
|
+
}
|
|
1872
|
+
} catch {
|
|
1873
|
+
}
|
|
1874
|
+
}
|
|
1875
|
+
return value.split(",").map(strip).filter(Boolean);
|
|
1876
|
+
}
|
|
1865
1877
|
return void 0;
|
|
1866
1878
|
}
|
|
1867
1879
|
function deriveDefaultWakeList(toField) {
|
|
@@ -2560,19 +2572,22 @@ function createMailRoutes(accountManager, config, db, gatewayManager) {
|
|
|
2560
2572
|
router.post("/mail/batch/move", requireAgent, async (req, res, next) => {
|
|
2561
2573
|
try {
|
|
2562
2574
|
const agent = req.agent;
|
|
2563
|
-
const
|
|
2564
|
-
const uids = validateUids(
|
|
2575
|
+
const body = req.body || {};
|
|
2576
|
+
const uids = validateUids(body.uids);
|
|
2565
2577
|
if (!uids) {
|
|
2566
2578
|
res.status(400).json({ error: "uids must be a non-empty array of positive integers (max 1000)" });
|
|
2567
2579
|
return;
|
|
2568
2580
|
}
|
|
2581
|
+
const fromFolder = body.from ?? body.folder;
|
|
2582
|
+
const toFolder = body.to ?? body.toFolder;
|
|
2569
2583
|
if (!toFolder) {
|
|
2570
|
-
res.status(400).json({ error: "
|
|
2584
|
+
res.status(400).json({ error: "destination folder is required (pass as `to` or `toFolder`)" });
|
|
2571
2585
|
return;
|
|
2572
2586
|
}
|
|
2573
2587
|
const password = getAgentPassword(agent);
|
|
2574
2588
|
const receiver = await getReceiver(agent.stalwartPrincipal, password, config);
|
|
2575
2589
|
await receiver.batchMove(uids, fromFolder || "INBOX", toFolder);
|
|
2590
|
+
for (const uid of uids) invalidateParsedMessage(agent.id, uid);
|
|
2576
2591
|
res.json({ ok: true, moved: uids.length });
|
|
2577
2592
|
} catch (err) {
|
|
2578
2593
|
next(err);
|
package/package.json
CHANGED
package/public/js/list-view.js
CHANGED
|
@@ -107,7 +107,7 @@ export async function loadList(agent, folder) {
|
|
|
107
107
|
</div>
|
|
108
108
|
<div class="list-toolbar-spacer"></div>
|
|
109
109
|
<span class="count-text" id="list-count"></span>
|
|
110
|
-
<button class="icon-btn pager-btn" id="pager-prev" title="Newer"
|
|
110
|
+
<button class="icon-btn pager-btn" id="pager-prev" title="Newer"></button>
|
|
111
111
|
<button class="icon-btn pager-btn" id="pager-next" title="Older"></button>
|
|
112
112
|
</div>
|
|
113
113
|
<div class="list-rows" id="list-rows"><div class="empty">Loading…</div></div>
|
|
@@ -116,6 +116,14 @@ export async function loadList(agent, folder) {
|
|
|
116
116
|
// the head of the inbox); "Older" advances to higher offsets.
|
|
117
117
|
// Each handler clamps to valid bounds and refetches via loadList
|
|
118
118
|
// with the new offset preserved in state.pagination.
|
|
119
|
+
//
|
|
120
|
+
// Both buttons share the same `back` chevron glyph — Prev is the
|
|
121
|
+
// glyph as-is (points left), Next rotates it 180° to point right.
|
|
122
|
+
// Previously Prev had only a `data-icon="back"` attribute (no
|
|
123
|
+
// innerHTML assignment), which left it visually empty — the user
|
|
124
|
+
// could click it but couldn't see it, so on page 2+ the back
|
|
125
|
+
// button looked entirely missing.
|
|
126
|
+
document.getElementById('pager-prev').innerHTML = icon('back', { size: 18 });
|
|
119
127
|
document.getElementById('pager-next').innerHTML = icon('back', { size: 18 });
|
|
120
128
|
document.getElementById('pager-next').style.transform = 'rotate(180deg)';
|
|
121
129
|
document.getElementById('pager-prev')?.addEventListener('click', () => goToPage(agent, folder, -1));
|
|
@@ -149,7 +157,18 @@ export async function loadList(agent, folder) {
|
|
|
149
157
|
// side flag filter (Gmail convention); other folders need a real
|
|
150
158
|
// mailbox name from the discovery cache.
|
|
151
159
|
const isStarred = folder === 'starred';
|
|
152
|
-
|
|
160
|
+
let imap = isStarred ? 'INBOX' : imapNameFor(folder);
|
|
161
|
+
if (!imap) {
|
|
162
|
+
// The cache was populated at agent-switch time; some folders are
|
|
163
|
+
// created LATER on demand (the API auto-creates Archive on first
|
|
164
|
+
// archive, Spam on first report-as-spam). If we don't see the
|
|
165
|
+
// requested folder in the cache, force a fresh discovery once
|
|
166
|
+
// before declaring "no such folder" — covers the "moved to
|
|
167
|
+
// Archive but Archive tab is empty" report.
|
|
168
|
+
state.folderNames = {};
|
|
169
|
+
await ensureFolderCache(agent);
|
|
170
|
+
imap = imapNameFor(folder);
|
|
171
|
+
}
|
|
153
172
|
if (!imap) {
|
|
154
173
|
document.getElementById('list-rows').innerHTML =
|
|
155
174
|
`<div class="empty"><div class="big">📭</div>No ${escapeHtml(folderTitle(folder))} folder on this server.</div>`;
|