Mail: instant first paint from the last saved accounts, folders and list; Outlook folders in one batched call; gzip for app files and large mail responses
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
fb7aabff61
commit
84a0ea10e9
6 files changed
+69
-17
No files matched your search
@@ -36,7 +36,13 @@ function secretStatus() {
|
||||
|
||||
const MAX_BODY = 6 * 1024 * 1024, MAX_ATTACH = 3 * 1024 * 1024;
|
||||
const readBody = req => new Promise((ok, no) => { const c = []; let n = 0; req.on('data', d => { n += d.length; if (n > MAX_BODY) { no(new Error('That is too large to send (attachments can total about 3 MB)')); req.destroy(); } else c.push(d); }); req.on('end', () => ok(Buffer.concat(c).toString())); req.on('error', no); });
|
||||
const json = (res, code, obj) => { res.writeHead(code, { 'content-type': 'application/json', 'cache-control': 'no-store' }); res.end(JSON.stringify(obj)); };
|
||||
const json = (res, code, obj) => {
|
||||
const body = Buffer.from(JSON.stringify(obj)), h = { 'content-type': 'application/json', 'cache-control': 'no-store' };
|
||||
if (body.length > 2048 && /\bgzip\b/.test((res.req && res.req.headers['accept-encoding']) || '')) { // message bodies are mostly HTML: gzip makes them several times smaller
|
||||
const z = require('zlib').gzipSync(body); res.writeHead(code, { ...h, 'content-encoding': 'gzip', vary: 'Accept-Encoding' }); return res.end(z);
|
||||
}
|
||||
res.writeHead(code, h); res.end(body);
|
||||
};
|
||||
const fail = (status, message) => Object.assign(new Error(message), { status });
|
||||
|
||||
// ---- each person's accounts (encrypted): [{ id, type: 'outlook' | 'gmail' | 'icloud', address, name, ...credentials }]
|
||||
@@ -155,10 +161,13 @@ const dropFolderCache = id => { if (id) { folderCache.delete(id); unreadCache.de
|
||||
const outlook = {
|
||||
async folders(a) {
|
||||
const c = folderCache.get(a.id); if (c && Date.now() - c.t < 15e3) return c.v;
|
||||
const sel = '?$select=id,displayName,unreadItemCount,totalItemCount';
|
||||
const wk = await Promise.all(Object.keys(WELL).map(k => graph(a, `/me/mailFolders/${k}${sel}`).then(f => ({ id: k, realId: f.id, name: WELL[k], unread: f.unreadItemCount || 0, total: f.totalItemCount || 0, well: true })).catch(() => null)));
|
||||
const sel = '?$select=id,displayName,unreadItemCount,totalItemCount', keys = Object.keys(WELL);
|
||||
// the usual six and the full list in ONE round trip (Graph's $batch), instead of seven
|
||||
const b = await graph(a, '/$batch', { method: 'POST', body: JSON.stringify({ requests: [...keys.map((k, i) => ({ id: String(i), method: 'GET', url: `/me/mailFolders/${k}${sel}` })), { id: 'all', method: 'GET', url: `/me/mailFolders${sel}&$top=100` }] }) });
|
||||
const by = Object.fromEntries((b.responses || []).map(r => [r.id, r]));
|
||||
const wk = keys.map((k, i) => { const r = by[String(i)]; return r && r.status === 200 ? { id: k, realId: r.body.id, name: WELL[k], unread: r.body.unreadItemCount || 0, total: r.body.totalItemCount || 0, well: true } : null; });
|
||||
const known = new Set(wk.filter(Boolean).map(f => f.realId));
|
||||
const rest = (await graph(a, `/me/mailFolders${sel}&$top=100`).catch(() => ({ value: [] }))).value || [];
|
||||
const rest = by.all && by.all.status === 200 ? by.all.body.value || [] : [];
|
||||
const v = [...wk.filter(Boolean).map(({ realId, ...f }) => f), ...rest.filter(f => !known.has(f.id) && !['Outbox', 'Conversation History', 'Sync Issues', 'RSS Feeds'].includes(f.displayName)).map(f => ({ id: f.id, name: f.displayName, unread: f.unreadItemCount || 0, total: f.totalItemCount || 0 }))];
|
||||
folderCache.set(a.id, { t: Date.now(), v }); return v;
|
||||
},
|
||||
|
||||
Reference in new issue
Block a user