@agenticmail/api 0.7.4 → 0.7.7
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 +157 -56
- package/package.json +2 -1
- package/public/index.html +882 -0
package/dist/index.js
CHANGED
|
@@ -6,6 +6,9 @@ import { networkInterfaces } from "os";
|
|
|
6
6
|
import express from "express";
|
|
7
7
|
import cors from "cors";
|
|
8
8
|
import rateLimit from "express-rate-limit";
|
|
9
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
10
|
+
import { dirname as dirname2, join as join2 } from "path";
|
|
11
|
+
import { existsSync } from "fs";
|
|
9
12
|
import {
|
|
10
13
|
resolveConfig,
|
|
11
14
|
getDatabase,
|
|
@@ -35,7 +38,7 @@ function safeEqual(a, b) {
|
|
|
35
38
|
const hb = createHash("sha256").update(b).digest();
|
|
36
39
|
return timingSafeEqual(ha, hb);
|
|
37
40
|
}
|
|
38
|
-
function createAuthMiddleware(masterKey,
|
|
41
|
+
function createAuthMiddleware(masterKey, accountManager2, db) {
|
|
39
42
|
return async (req, res, next) => {
|
|
40
43
|
const authHeader = req.headers.authorization;
|
|
41
44
|
if (!authHeader?.startsWith("Bearer ")) {
|
|
@@ -53,7 +56,7 @@ function createAuthMiddleware(masterKey, accountManager, db) {
|
|
|
53
56
|
return;
|
|
54
57
|
}
|
|
55
58
|
try {
|
|
56
|
-
const agent = await
|
|
59
|
+
const agent = await accountManager2.getByApiKey(token);
|
|
57
60
|
if (agent) {
|
|
58
61
|
req.agent = agent;
|
|
59
62
|
if (db) {
|
|
@@ -324,9 +327,9 @@ function sanitizeAgent(agent) {
|
|
|
324
327
|
}
|
|
325
328
|
return agent;
|
|
326
329
|
}
|
|
327
|
-
function createAccountRoutes(
|
|
330
|
+
function createAccountRoutes(accountManager2, db, config) {
|
|
328
331
|
const router = Router3();
|
|
329
|
-
const deletionService = new AgentDeletionService(db,
|
|
332
|
+
const deletionService = new AgentDeletionService(db, accountManager2, config);
|
|
330
333
|
router.post("/accounts", requireMaster, async (req, res, next) => {
|
|
331
334
|
if (!req.body || typeof req.body !== "object") {
|
|
332
335
|
res.status(400).json({ error: "Request body must be JSON" });
|
|
@@ -357,7 +360,7 @@ function createAccountRoutes(accountManager, db, config) {
|
|
|
357
360
|
const cleanMeta = metadata ? Object.fromEntries(
|
|
358
361
|
Object.entries(metadata).filter(([k]) => !k.startsWith("_"))
|
|
359
362
|
) : void 0;
|
|
360
|
-
const agent = await
|
|
363
|
+
const agent = await accountManager2.create({ name: accountName, domain, password: password || void 0, metadata: cleanMeta, role });
|
|
361
364
|
try {
|
|
362
365
|
db.prepare("UPDATE agents SET last_activity_at = datetime('now') WHERE id = ?").run(agent.id);
|
|
363
366
|
} catch {
|
|
@@ -389,7 +392,7 @@ function createAccountRoutes(accountManager, db, config) {
|
|
|
389
392
|
});
|
|
390
393
|
router.get("/accounts", requireMaster, async (_req, res, next) => {
|
|
391
394
|
try {
|
|
392
|
-
const agents = await
|
|
395
|
+
const agents = await accountManager2.list();
|
|
393
396
|
res.json({ agents: agents.map(sanitizeAgent) });
|
|
394
397
|
} catch (err) {
|
|
395
398
|
next(err);
|
|
@@ -397,7 +400,7 @@ function createAccountRoutes(accountManager, db, config) {
|
|
|
397
400
|
});
|
|
398
401
|
router.get("/accounts/directory", requireAuth, async (_req, res, next) => {
|
|
399
402
|
try {
|
|
400
|
-
const agents = await
|
|
403
|
+
const agents = await accountManager2.list();
|
|
401
404
|
const directory = agents.map((a) => ({ name: a.name, email: a.email, role: a.role }));
|
|
402
405
|
res.json({ agents: directory });
|
|
403
406
|
} catch (err) {
|
|
@@ -406,7 +409,7 @@ function createAccountRoutes(accountManager, db, config) {
|
|
|
406
409
|
});
|
|
407
410
|
router.get("/accounts/directory/:name", requireAuth, async (req, res, next) => {
|
|
408
411
|
try {
|
|
409
|
-
const agent = await
|
|
412
|
+
const agent = await accountManager2.getByName(req.params.name);
|
|
410
413
|
if (!agent) {
|
|
411
414
|
res.status(404).json({ error: "Agent not found" });
|
|
412
415
|
return;
|
|
@@ -471,7 +474,7 @@ function createAccountRoutes(accountManager, db, config) {
|
|
|
471
474
|
const deleted = [];
|
|
472
475
|
for (const row of rows) {
|
|
473
476
|
try {
|
|
474
|
-
await
|
|
477
|
+
await accountManager2.delete(row.id);
|
|
475
478
|
deleted.push(row.name);
|
|
476
479
|
} catch {
|
|
477
480
|
}
|
|
@@ -483,7 +486,7 @@ function createAccountRoutes(accountManager, db, config) {
|
|
|
483
486
|
});
|
|
484
487
|
router.get("/accounts/:id", requireMaster, async (req, res, next) => {
|
|
485
488
|
try {
|
|
486
|
-
const agent = await
|
|
489
|
+
const agent = await accountManager2.getById(req.params.id);
|
|
487
490
|
if (!agent) {
|
|
488
491
|
res.status(404).json({ error: "Agent not found" });
|
|
489
492
|
return;
|
|
@@ -501,7 +504,7 @@ function createAccountRoutes(accountManager, db, config) {
|
|
|
501
504
|
res.status(400).json({ error: "metadata must be an object" });
|
|
502
505
|
return;
|
|
503
506
|
}
|
|
504
|
-
const updated = await
|
|
507
|
+
const updated = await accountManager2.updateMetadata(agent.id, metadata);
|
|
505
508
|
if (!updated) {
|
|
506
509
|
res.status(404).json({ error: "Agent not found" });
|
|
507
510
|
return;
|
|
@@ -526,7 +529,7 @@ function createAccountRoutes(accountManager, db, config) {
|
|
|
526
529
|
});
|
|
527
530
|
router.delete("/accounts/:id", requireMaster, async (req, res, next) => {
|
|
528
531
|
try {
|
|
529
|
-
const allAgents = await
|
|
532
|
+
const allAgents = await accountManager2.list();
|
|
530
533
|
if (allAgents.length <= 1) {
|
|
531
534
|
res.status(400).json({ error: "Cannot delete the last agent. At least one agent must remain." });
|
|
532
535
|
return;
|
|
@@ -544,7 +547,7 @@ function createAccountRoutes(accountManager, db, config) {
|
|
|
544
547
|
}
|
|
545
548
|
res.json(summary);
|
|
546
549
|
} else {
|
|
547
|
-
const deleted = await
|
|
550
|
+
const deleted = await accountManager2.delete(req.params.id);
|
|
548
551
|
if (!deleted) {
|
|
549
552
|
res.status(404).json({ error: "Agent not found" });
|
|
550
553
|
return;
|
|
@@ -828,6 +831,8 @@ function createFeatureRoutes(db, _accountManager, config, gatewayManager) {
|
|
|
828
831
|
return;
|
|
829
832
|
}
|
|
830
833
|
const agent = req.agent;
|
|
834
|
+
const wakeList = normalizeWakeList(req.body?.wake);
|
|
835
|
+
const customHeaders = wakeHeaders(wakeList);
|
|
831
836
|
const mailOpts = {
|
|
832
837
|
to: draft.to_addr,
|
|
833
838
|
subject: draft.subject || "(no subject)",
|
|
@@ -836,7 +841,8 @@ function createFeatureRoutes(db, _accountManager, config, gatewayManager) {
|
|
|
836
841
|
cc: draft.cc || void 0,
|
|
837
842
|
bcc: draft.bcc || void 0,
|
|
838
843
|
inReplyTo: draft.in_reply_to || void 0,
|
|
839
|
-
references: draft.refs ? JSON.parse(draft.refs) : void 0
|
|
844
|
+
references: draft.refs ? JSON.parse(draft.refs) : void 0,
|
|
845
|
+
...Object.keys(customHeaders).length > 0 ? { headers: customHeaders } : {}
|
|
840
846
|
};
|
|
841
847
|
if (gatewayManager) {
|
|
842
848
|
const gatewayResult = await gatewayManager.routeOutbound(agent.name, mailOpts);
|
|
@@ -857,6 +863,19 @@ function createFeatureRoutes(db, _accountManager, config, gatewayManager) {
|
|
|
857
863
|
try {
|
|
858
864
|
const result = await sender.send(mailOpts);
|
|
859
865
|
db.prepare("DELETE FROM drafts WHERE id = ?").run(draft.id);
|
|
866
|
+
notifyLocalRecipientsOfNewMail(
|
|
867
|
+
accountManager,
|
|
868
|
+
mailOpts.to,
|
|
869
|
+
mailOpts.cc,
|
|
870
|
+
mailOpts.bcc,
|
|
871
|
+
agent,
|
|
872
|
+
mailOpts.subject,
|
|
873
|
+
result.messageId,
|
|
874
|
+
config,
|
|
875
|
+
wakeList
|
|
876
|
+
).catch((err) => {
|
|
877
|
+
console.warn(`[drafts] SSE notify failed: ${err.message}`);
|
|
878
|
+
});
|
|
860
879
|
res.json(result);
|
|
861
880
|
} finally {
|
|
862
881
|
sender.close();
|
|
@@ -1078,20 +1097,24 @@ function createFeatureRoutes(db, _accountManager, config, gatewayManager) {
|
|
|
1078
1097
|
res.status(404).json({ error: "Template not found" });
|
|
1079
1098
|
return;
|
|
1080
1099
|
}
|
|
1081
|
-
const { to, variables, cc, bcc } = req.body || {};
|
|
1100
|
+
const { to, variables, cc, bcc, wake } = req.body || {};
|
|
1082
1101
|
if (!to) {
|
|
1083
1102
|
res.status(400).json({ error: "to is required" });
|
|
1084
1103
|
return;
|
|
1085
1104
|
}
|
|
1086
1105
|
const applyVars = (text, vars2) => text.replace(/\{\{(\w+)\}\}/g, (m, key) => vars2[key] ?? m);
|
|
1106
|
+
const wakeList = normalizeWakeList(wake);
|
|
1107
|
+
const customHeaders = wakeHeaders(wakeList);
|
|
1087
1108
|
const vars = variables && typeof variables === "object" ? variables : {};
|
|
1109
|
+
const renderedSubject = applyVars(template.subject || "(no subject)", vars);
|
|
1088
1110
|
const mailOpts = {
|
|
1089
1111
|
to,
|
|
1090
|
-
subject:
|
|
1112
|
+
subject: renderedSubject,
|
|
1091
1113
|
text: template.text_body ? applyVars(template.text_body, vars) : void 0,
|
|
1092
1114
|
html: template.html_body ? applyVars(template.html_body, vars) : void 0,
|
|
1093
1115
|
cc: cc || void 0,
|
|
1094
|
-
bcc: bcc || void 0
|
|
1116
|
+
bcc: bcc || void 0,
|
|
1117
|
+
...Object.keys(customHeaders).length > 0 ? { headers: customHeaders } : {}
|
|
1095
1118
|
};
|
|
1096
1119
|
const agent = req.agent;
|
|
1097
1120
|
if (gatewayManager) {
|
|
@@ -1111,6 +1134,19 @@ function createFeatureRoutes(db, _accountManager, config, gatewayManager) {
|
|
|
1111
1134
|
});
|
|
1112
1135
|
try {
|
|
1113
1136
|
const result = await sender.send(mailOpts);
|
|
1137
|
+
notifyLocalRecipientsOfNewMail(
|
|
1138
|
+
accountManager,
|
|
1139
|
+
to,
|
|
1140
|
+
cc,
|
|
1141
|
+
bcc,
|
|
1142
|
+
agent,
|
|
1143
|
+
renderedSubject,
|
|
1144
|
+
result.messageId,
|
|
1145
|
+
config,
|
|
1146
|
+
wakeList
|
|
1147
|
+
).catch((err) => {
|
|
1148
|
+
console.warn(`[templates] SSE notify failed: ${err.message}`);
|
|
1149
|
+
});
|
|
1114
1150
|
res.json(result);
|
|
1115
1151
|
} finally {
|
|
1116
1152
|
sender.close();
|
|
@@ -1181,7 +1217,7 @@ function evaluateRules(db, agentId, email) {
|
|
|
1181
1217
|
}
|
|
1182
1218
|
return null;
|
|
1183
1219
|
}
|
|
1184
|
-
function startScheduledSender(db,
|
|
1220
|
+
function startScheduledSender(db, accountManager2, config, gatewayManager) {
|
|
1185
1221
|
return setInterval(async () => {
|
|
1186
1222
|
try {
|
|
1187
1223
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -1190,7 +1226,7 @@ function startScheduledSender(db, accountManager, config, gatewayManager) {
|
|
|
1190
1226
|
).all(now);
|
|
1191
1227
|
for (const row of pending) {
|
|
1192
1228
|
try {
|
|
1193
|
-
const agent = await
|
|
1229
|
+
const agent = await accountManager2.getById(row.agent_id);
|
|
1194
1230
|
if (!agent) {
|
|
1195
1231
|
db.prepare("UPDATE scheduled_emails SET status = 'failed', error = ? WHERE id = ?").run("Agent not found", row.id);
|
|
1196
1232
|
continue;
|
|
@@ -1289,7 +1325,7 @@ async function closeAllWatchers() {
|
|
|
1289
1325
|
}
|
|
1290
1326
|
activeWatchers.clear();
|
|
1291
1327
|
}
|
|
1292
|
-
function createEventRoutes(
|
|
1328
|
+
function createEventRoutes(accountManager2, config, db) {
|
|
1293
1329
|
const router = Router5();
|
|
1294
1330
|
router.get("/events", requireAgent, async (req, res, next) => {
|
|
1295
1331
|
try {
|
|
@@ -1677,7 +1713,18 @@ function normalizeMessageId(id) {
|
|
|
1677
1713
|
if (!id) return "";
|
|
1678
1714
|
return id.trim().replace(/^<+|>+$/g, "").toLowerCase();
|
|
1679
1715
|
}
|
|
1680
|
-
|
|
1716
|
+
function normalizeWakeList(value) {
|
|
1717
|
+
if (value === void 0 || value === null) return void 0;
|
|
1718
|
+
const strip = (s) => s.trim().replace(/@localhost$/i, "").toLowerCase();
|
|
1719
|
+
if (Array.isArray(value)) return value.map((v) => strip(String(v))).filter(Boolean);
|
|
1720
|
+
if (typeof value === "string") return value.split(",").map(strip).filter(Boolean);
|
|
1721
|
+
return void 0;
|
|
1722
|
+
}
|
|
1723
|
+
function wakeHeaders(wakeList) {
|
|
1724
|
+
if (wakeList === void 0) return {};
|
|
1725
|
+
return { "X-AgenticMail-Wake": wakeList.join(", ") };
|
|
1726
|
+
}
|
|
1727
|
+
async function notifyLocalRecipientsOfNewMail(accountManager2, toField, ccField, bccField, fromAgent, subject, messageId, config, wakeList) {
|
|
1681
1728
|
const collected = [];
|
|
1682
1729
|
const push = (v) => {
|
|
1683
1730
|
if (!v) return;
|
|
@@ -1707,7 +1754,7 @@ async function notifyLocalRecipientsOfNewMail(accountManager, toField, ccField,
|
|
|
1707
1754
|
if (addr === fromAgent.email.toLowerCase()) continue;
|
|
1708
1755
|
let recipient = null;
|
|
1709
1756
|
try {
|
|
1710
|
-
recipient = await
|
|
1757
|
+
recipient = await accountManager2.getByName(localPart);
|
|
1711
1758
|
} catch {
|
|
1712
1759
|
}
|
|
1713
1760
|
if (!recipient || notified.has(recipient.id)) continue;
|
|
@@ -1738,7 +1785,12 @@ async function notifyLocalRecipientsOfNewMail(accountManager, toField, ccField,
|
|
|
1738
1785
|
internal: true,
|
|
1739
1786
|
from: { name: fromAgent.name, address: fromAgent.email },
|
|
1740
1787
|
subject,
|
|
1741
|
-
messageId
|
|
1788
|
+
messageId,
|
|
1789
|
+
// Wake gating signal. Present iff the sender opted in. The
|
|
1790
|
+
// dispatcher reads this and spawns a Claude worker only for
|
|
1791
|
+
// recipients whose name is on the list (or for everyone if the
|
|
1792
|
+
// field is absent, preserving the v0.8.x default).
|
|
1793
|
+
...wakeList !== void 0 ? { wakeAllowlist: wakeList } : {}
|
|
1742
1794
|
});
|
|
1743
1795
|
}
|
|
1744
1796
|
}
|
|
@@ -1752,7 +1804,7 @@ function saveSentCopy(authUser, password, config, raw) {
|
|
|
1752
1804
|
}
|
|
1753
1805
|
})();
|
|
1754
1806
|
}
|
|
1755
|
-
function createMailRoutes(
|
|
1807
|
+
function createMailRoutes(accountManager2, config, db, gatewayManager) {
|
|
1756
1808
|
const router = Router6();
|
|
1757
1809
|
router.post("/mail/send", requireAgent, async (req, res, next) => {
|
|
1758
1810
|
try {
|
|
@@ -1761,7 +1813,7 @@ function createMailRoutes(accountManager, config, db, gatewayManager) {
|
|
|
1761
1813
|
return;
|
|
1762
1814
|
}
|
|
1763
1815
|
const agent = req.agent;
|
|
1764
|
-
const { to, subject, text, html, cc, bcc, replyTo, inReplyTo, references, attachments, allowSensitive } = req.body;
|
|
1816
|
+
const { to, subject, text, html, cc, bcc, replyTo, inReplyTo, references, attachments, allowSensitive, wake } = req.body;
|
|
1765
1817
|
if (!to || !subject) {
|
|
1766
1818
|
res.status(400).json({ error: "to and subject are required" });
|
|
1767
1819
|
return;
|
|
@@ -1789,7 +1841,21 @@ function createMailRoutes(accountManager, config, db, gatewayManager) {
|
|
|
1789
1841
|
const pendingId = crypto.randomUUID();
|
|
1790
1842
|
const ownerName2 = agent.metadata?.ownerName;
|
|
1791
1843
|
const fromName2 = ownerName2 ? `${agent.name} from ${ownerName2}` : agent.name;
|
|
1792
|
-
const
|
|
1844
|
+
const wakeListForPersist = normalizeWakeList(wake);
|
|
1845
|
+
const mailOptions = {
|
|
1846
|
+
to,
|
|
1847
|
+
subject,
|
|
1848
|
+
text,
|
|
1849
|
+
html,
|
|
1850
|
+
cc,
|
|
1851
|
+
bcc,
|
|
1852
|
+
replyTo,
|
|
1853
|
+
inReplyTo,
|
|
1854
|
+
references,
|
|
1855
|
+
attachments,
|
|
1856
|
+
fromName: fromName2,
|
|
1857
|
+
...wakeListForPersist !== void 0 ? { wakeList: wakeListForPersist } : {}
|
|
1858
|
+
};
|
|
1793
1859
|
db.prepare(
|
|
1794
1860
|
`INSERT INTO pending_outbound (id, agent_id, mail_options, warnings, summary) VALUES (?, ?, ?, ?, ?)`
|
|
1795
1861
|
).run(pendingId, agent.id, JSON.stringify(mailOptions), JSON.stringify(scanResult.warnings), scanResult.summary);
|
|
@@ -1858,7 +1924,22 @@ function createMailRoutes(accountManager, config, db, gatewayManager) {
|
|
|
1858
1924
|
}
|
|
1859
1925
|
const ownerName = agent.metadata?.ownerName;
|
|
1860
1926
|
const fromName = ownerName ? `${agent.name} from ${ownerName}` : agent.name;
|
|
1861
|
-
const
|
|
1927
|
+
const wakeList = normalizeWakeList(wake);
|
|
1928
|
+
const customHeaders = wakeHeaders(wakeList);
|
|
1929
|
+
const mailOpts = {
|
|
1930
|
+
to,
|
|
1931
|
+
subject,
|
|
1932
|
+
text,
|
|
1933
|
+
html,
|
|
1934
|
+
cc,
|
|
1935
|
+
bcc,
|
|
1936
|
+
replyTo,
|
|
1937
|
+
inReplyTo,
|
|
1938
|
+
references,
|
|
1939
|
+
attachments,
|
|
1940
|
+
fromName,
|
|
1941
|
+
...Object.keys(customHeaders).length > 0 ? { headers: customHeaders } : {}
|
|
1942
|
+
};
|
|
1862
1943
|
const password = getAgentPassword(agent);
|
|
1863
1944
|
if (gatewayManager) {
|
|
1864
1945
|
const gatewayResult = await gatewayManager.routeOutbound(agent.name, mailOpts);
|
|
@@ -1875,14 +1956,15 @@ function createMailRoutes(accountManager, config, db, gatewayManager) {
|
|
|
1875
1956
|
const result = await sender.send(mailOpts);
|
|
1876
1957
|
saveSentCopy(agent.stalwartPrincipal, password, config, result.raw);
|
|
1877
1958
|
notifyLocalRecipientsOfNewMail(
|
|
1878
|
-
|
|
1959
|
+
accountManager2,
|
|
1879
1960
|
to,
|
|
1880
1961
|
cc,
|
|
1881
1962
|
bcc,
|
|
1882
1963
|
agent,
|
|
1883
1964
|
subject,
|
|
1884
1965
|
result.messageId,
|
|
1885
|
-
config
|
|
1966
|
+
config,
|
|
1967
|
+
wakeList
|
|
1886
1968
|
).catch((err) => {
|
|
1887
1969
|
console.warn(`[mail] Internal SSE notify failed: ${err.message}`);
|
|
1888
1970
|
});
|
|
@@ -2454,7 +2536,7 @@ function createMailRoutes(accountManager, config, db, gatewayManager) {
|
|
|
2454
2536
|
res.status(400).json({ error: `Email already ${row.status}` });
|
|
2455
2537
|
return;
|
|
2456
2538
|
}
|
|
2457
|
-
const agent = await
|
|
2539
|
+
const agent = await accountManager2.getById(row.agent_id);
|
|
2458
2540
|
if (!agent) {
|
|
2459
2541
|
res.status(404).json({ error: "Agent account no longer exists" });
|
|
2460
2542
|
return;
|
|
@@ -2469,6 +2551,11 @@ function createMailRoutes(accountManager, config, db, gatewayManager) {
|
|
|
2469
2551
|
}
|
|
2470
2552
|
}
|
|
2471
2553
|
}
|
|
2554
|
+
const persistedWakeList = Array.isArray(mailOpts.wakeList) ? mailOpts.wakeList : void 0;
|
|
2555
|
+
if (persistedWakeList !== void 0) {
|
|
2556
|
+
mailOpts.headers = { ...mailOpts.headers ?? {}, ...wakeHeaders(persistedWakeList) };
|
|
2557
|
+
delete mailOpts.wakeList;
|
|
2558
|
+
}
|
|
2472
2559
|
const password = getAgentPassword(agent);
|
|
2473
2560
|
let response;
|
|
2474
2561
|
if (gatewayManager) {
|
|
@@ -2486,14 +2573,15 @@ function createMailRoutes(accountManager, config, db, gatewayManager) {
|
|
|
2486
2573
|
const result = await sender.send(mailOpts);
|
|
2487
2574
|
saveSentCopy(agent.stalwartPrincipal, password, config, result.raw);
|
|
2488
2575
|
notifyLocalRecipientsOfNewMail(
|
|
2489
|
-
|
|
2576
|
+
accountManager2,
|
|
2490
2577
|
mailOpts.to,
|
|
2491
2578
|
mailOpts.cc,
|
|
2492
2579
|
mailOpts.bcc,
|
|
2493
2580
|
agent,
|
|
2494
2581
|
mailOpts.subject,
|
|
2495
2582
|
result.messageId,
|
|
2496
|
-
config
|
|
2583
|
+
config,
|
|
2584
|
+
persistedWakeList
|
|
2497
2585
|
).catch((err) => {
|
|
2498
2586
|
console.warn(`[mail] Internal SSE notify (approve) failed: ${err.message}`);
|
|
2499
2587
|
});
|
|
@@ -2542,7 +2630,7 @@ var INBOUND_SECRET = process.env.AGENTICMAIL_INBOUND_SECRET || (() => {
|
|
|
2542
2630
|
return generated;
|
|
2543
2631
|
})();
|
|
2544
2632
|
var DEBUG = () => !!process.env.AGENTICMAIL_DEBUG;
|
|
2545
|
-
function createInboundRoutes(
|
|
2633
|
+
function createInboundRoutes(accountManager2, config, gatewayManager) {
|
|
2546
2634
|
const router = Router7();
|
|
2547
2635
|
router.post("/mail/inbound", async (req, res, next) => {
|
|
2548
2636
|
try {
|
|
@@ -2558,7 +2646,7 @@ function createInboundRoutes(accountManager, config, gatewayManager) {
|
|
|
2558
2646
|
}
|
|
2559
2647
|
const recipientEmail = typeof to === "string" ? to : to[0];
|
|
2560
2648
|
const localPart = recipientEmail.split("@")[0];
|
|
2561
|
-
const agent = await
|
|
2649
|
+
const agent = await accountManager2.getByName(localPart);
|
|
2562
2650
|
if (!agent) {
|
|
2563
2651
|
console.warn(`[Inbound] No agent found for "${localPart}" (${recipientEmail})`);
|
|
2564
2652
|
res.status(404).json({ error: `No agent found for ${recipientEmail}` });
|
|
@@ -3042,7 +3130,7 @@ import { Router as Router10 } from "express";
|
|
|
3042
3130
|
import { v4 as uuidv43 } from "uuid";
|
|
3043
3131
|
import { MailSender as MailSender4 } from "@agenticmail/core";
|
|
3044
3132
|
var rpcResolvers = /* @__PURE__ */ new Map();
|
|
3045
|
-
function createTaskRoutes(db,
|
|
3133
|
+
function createTaskRoutes(db, accountManager2, config) {
|
|
3046
3134
|
const router = Router10();
|
|
3047
3135
|
router.post("/tasks/assign", requireAuth, async (req, res, next) => {
|
|
3048
3136
|
try {
|
|
@@ -3051,7 +3139,7 @@ function createTaskRoutes(db, accountManager, config) {
|
|
|
3051
3139
|
res.status(400).json({ error: "assignee (agent name) is required" });
|
|
3052
3140
|
return;
|
|
3053
3141
|
}
|
|
3054
|
-
const target = await
|
|
3142
|
+
const target = await accountManager2.getByName(assignee);
|
|
3055
3143
|
if (!target) {
|
|
3056
3144
|
res.status(404).json({ error: `Agent "${assignee}" not found` });
|
|
3057
3145
|
return;
|
|
@@ -3110,7 +3198,7 @@ Please check your pending tasks.`
|
|
|
3110
3198
|
let assigneeId = req.agent.id;
|
|
3111
3199
|
const assigneeName = req.query.assignee;
|
|
3112
3200
|
if (assigneeName) {
|
|
3113
|
-
const target = await
|
|
3201
|
+
const target = await accountManager2.getByName(assigneeName);
|
|
3114
3202
|
if (target) assigneeId = target.id;
|
|
3115
3203
|
}
|
|
3116
3204
|
const rows = db.prepare(
|
|
@@ -3238,7 +3326,7 @@ Please check your pending tasks.`
|
|
|
3238
3326
|
res.status(400).json({ error: "target (agent name) and task are required" });
|
|
3239
3327
|
return;
|
|
3240
3328
|
}
|
|
3241
|
-
const targetAgent = await
|
|
3329
|
+
const targetAgent = await accountManager2.getByName(target);
|
|
3242
3330
|
if (!targetAgent) {
|
|
3243
3331
|
res.status(404).json({ error: `Agent "${target}" not found` });
|
|
3244
3332
|
return;
|
|
@@ -3372,7 +3460,7 @@ import {
|
|
|
3372
3460
|
normalizePhoneNumber,
|
|
3373
3461
|
isValidPhoneNumber
|
|
3374
3462
|
} from "@agenticmail/core";
|
|
3375
|
-
function createSmsRoutes(db,
|
|
3463
|
+
function createSmsRoutes(db, accountManager2, config, gatewayManager) {
|
|
3376
3464
|
const router = Router11();
|
|
3377
3465
|
const smsManager = new SmsManager(db);
|
|
3378
3466
|
function getAgent(req, res) {
|
|
@@ -3760,7 +3848,7 @@ function adaptBetterSqlite(raw) {
|
|
|
3760
3848
|
}
|
|
3761
3849
|
};
|
|
3762
3850
|
}
|
|
3763
|
-
function createStorageRoutes(rawDb,
|
|
3851
|
+
function createStorageRoutes(rawDb, accountManager2, config, dialect = "sqlite") {
|
|
3764
3852
|
const db = adaptBetterSqlite(rawDb);
|
|
3765
3853
|
const router = Router12();
|
|
3766
3854
|
function getAgent(req, res) {
|
|
@@ -4730,12 +4818,12 @@ function createApp(configOverrides) {
|
|
|
4730
4818
|
adminUser: config.stalwart.adminUser,
|
|
4731
4819
|
adminPassword: config.stalwart.adminPassword
|
|
4732
4820
|
});
|
|
4733
|
-
const
|
|
4821
|
+
const accountManager2 = new AccountManager(db, stalwart);
|
|
4734
4822
|
const domainManager = new DomainManager(db, stalwart);
|
|
4735
4823
|
const gatewayManager = new GatewayManager2({
|
|
4736
4824
|
db,
|
|
4737
4825
|
stalwart,
|
|
4738
|
-
accountManager,
|
|
4826
|
+
accountManager: accountManager2,
|
|
4739
4827
|
localSmtp: {
|
|
4740
4828
|
host: config.smtp.host,
|
|
4741
4829
|
port: config.smtp.port,
|
|
@@ -4761,36 +4849,49 @@ function createApp(configOverrides) {
|
|
|
4761
4849
|
message: { error: "Too many requests, please try again later" }
|
|
4762
4850
|
})
|
|
4763
4851
|
);
|
|
4852
|
+
const staticDir = (() => {
|
|
4853
|
+
const here = dirname2(fileURLToPath2(import.meta.url));
|
|
4854
|
+
const candidates = [
|
|
4855
|
+
join2(here, "..", "public"),
|
|
4856
|
+
join2(here, "public")
|
|
4857
|
+
];
|
|
4858
|
+
for (const c of candidates) if (existsSync(c)) return c;
|
|
4859
|
+
return null;
|
|
4860
|
+
})();
|
|
4861
|
+
if (staticDir) {
|
|
4862
|
+
app2.use("/", express.static(staticDir, { index: "index.html", extensions: ["html"] }));
|
|
4863
|
+
app2.get("/ui", (_req, res) => res.sendFile(join2(staticDir, "index.html")));
|
|
4864
|
+
}
|
|
4764
4865
|
app2.use("/api/agenticmail", createHealthRoutes(stalwart));
|
|
4765
|
-
app2.use("/api/agenticmail", createInboundRoutes(
|
|
4866
|
+
app2.use("/api/agenticmail", createInboundRoutes(accountManager2, config, gatewayManager));
|
|
4766
4867
|
const integrationFactory = readResolvedFactory(integrationRouteFactoryPromise);
|
|
4767
4868
|
if (integrationFactory) {
|
|
4768
4869
|
app2.use("/api/agenticmail", integrationFactory());
|
|
4769
4870
|
}
|
|
4770
|
-
app2.use("/api/agenticmail", createAuthMiddleware(config.masterKey,
|
|
4771
|
-
app2.use("/api/agenticmail", createAccountRoutes(
|
|
4772
|
-
app2.use("/api/agenticmail", createMailRoutes(
|
|
4773
|
-
app2.use("/api/agenticmail", createEventRoutes(
|
|
4871
|
+
app2.use("/api/agenticmail", createAuthMiddleware(config.masterKey, accountManager2, db));
|
|
4872
|
+
app2.use("/api/agenticmail", createAccountRoutes(accountManager2, db, config));
|
|
4873
|
+
app2.use("/api/agenticmail", createMailRoutes(accountManager2, config, db, gatewayManager));
|
|
4874
|
+
app2.use("/api/agenticmail", createEventRoutes(accountManager2, config, db));
|
|
4774
4875
|
app2.use("/api/agenticmail", createDomainRoutes(domainManager));
|
|
4775
4876
|
app2.use("/api/agenticmail", createGatewayRoutes(gatewayManager));
|
|
4776
|
-
app2.use("/api/agenticmail", createFeatureRoutes(db,
|
|
4777
|
-
app2.use("/api/agenticmail", createTaskRoutes(db,
|
|
4778
|
-
app2.use("/api/agenticmail", createSmsRoutes(db,
|
|
4779
|
-
app2.use("/api/agenticmail", createStorageRoutes(db,
|
|
4877
|
+
app2.use("/api/agenticmail", createFeatureRoutes(db, accountManager2, config, gatewayManager));
|
|
4878
|
+
app2.use("/api/agenticmail", createTaskRoutes(db, accountManager2, config));
|
|
4879
|
+
app2.use("/api/agenticmail", createSmsRoutes(db, accountManager2, config, gatewayManager));
|
|
4880
|
+
app2.use("/api/agenticmail", createStorageRoutes(db, accountManager2, config));
|
|
4780
4881
|
app2.use("/api/agenticmail", createSystemEventRoutes());
|
|
4781
4882
|
app2.use("/api/agenticmail", createDispatcherActivityRoutes());
|
|
4782
4883
|
app2.use("/api/agenticmail", (_req, res) => {
|
|
4783
4884
|
res.status(404).json({ error: "Not found" });
|
|
4784
4885
|
});
|
|
4785
4886
|
app2.use(errorHandler);
|
|
4786
|
-
const context2 = { config, db, stalwart, accountManager, domainManager, gatewayManager };
|
|
4887
|
+
const context2 = { config, db, stalwart, accountManager: accountManager2, domainManager, gatewayManager };
|
|
4787
4888
|
return { app: app2, context: context2 };
|
|
4788
4889
|
}
|
|
4789
4890
|
|
|
4790
4891
|
// src/index.ts
|
|
4791
4892
|
import { readFileSync as readFileSync2 } from "fs";
|
|
4792
|
-
import { fileURLToPath as
|
|
4793
|
-
import { dirname as
|
|
4893
|
+
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
4894
|
+
import { dirname as dirname3, join as join3 } from "path";
|
|
4794
4895
|
await prepareIntegrations();
|
|
4795
4896
|
function getLocalIp() {
|
|
4796
4897
|
const nets = networkInterfaces();
|
|
@@ -4804,8 +4905,8 @@ function getLocalIp() {
|
|
|
4804
4905
|
}
|
|
4805
4906
|
var VERSION = (() => {
|
|
4806
4907
|
try {
|
|
4807
|
-
const __dirname =
|
|
4808
|
-
const pkg = JSON.parse(readFileSync2(
|
|
4908
|
+
const __dirname = dirname3(fileURLToPath3(import.meta.url));
|
|
4909
|
+
const pkg = JSON.parse(readFileSync2(join3(__dirname, "..", "package.json"), "utf-8"));
|
|
4809
4910
|
return pkg.version;
|
|
4810
4911
|
} catch {
|
|
4811
4912
|
return "0.5.31";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agenticmail/api",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.7",
|
|
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",
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
},
|
|
15
15
|
"files": [
|
|
16
16
|
"dist",
|
|
17
|
+
"public",
|
|
17
18
|
"README.md",
|
|
18
19
|
"REFERENCE.md",
|
|
19
20
|
"LICENSE"
|