@jait/gateway 0.1.497 → 0.1.499
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/db/migrations.d.ts.map +1 -1
- package/dist/db/migrations.js +22 -0
- package/dist/db/migrations.js.map +1 -1
- package/dist/db/schema.d.ts +178 -0
- package/dist/db/schema.d.ts.map +1 -1
- package/dist/db/schema.js +15 -0
- package/dist/db/schema.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -1
- package/dist/routes/chat.d.ts.map +1 -1
- package/dist/routes/chat.js +77 -7
- package/dist/routes/chat.js.map +1 -1
- package/dist/routes/email.d.ts +5 -0
- package/dist/routes/email.d.ts.map +1 -0
- package/dist/routes/email.js +202 -0
- package/dist/routes/email.js.map +1 -0
- package/dist/security/tool-profiles.d.ts.map +1 -1
- package/dist/security/tool-profiles.js +3 -0
- package/dist/security/tool-profiles.js.map +1 -1
- package/dist/server.d.ts +1 -0
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +4 -0
- package/dist/server.js.map +1 -1
- package/dist/services/email/gmail.d.ts +16 -0
- package/dist/services/email/gmail.d.ts.map +1 -0
- package/dist/services/email/gmail.js +170 -0
- package/dist/services/email/gmail.js.map +1 -0
- package/dist/services/email/index.d.ts +3 -0
- package/dist/services/email/index.d.ts.map +1 -0
- package/dist/services/email/index.js +2 -0
- package/dist/services/email/index.js.map +1 -0
- package/dist/services/email/oauth.d.ts +32 -0
- package/dist/services/email/oauth.d.ts.map +1 -0
- package/dist/services/email/oauth.js +105 -0
- package/dist/services/email/oauth.js.map +1 -0
- package/dist/services/email/outlook.d.ts +15 -0
- package/dist/services/email/outlook.d.ts.map +1 -0
- package/dist/services/email/outlook.js +142 -0
- package/dist/services/email/outlook.js.map +1 -0
- package/dist/services/email/service.d.ts +50 -0
- package/dist/services/email/service.d.ts.map +1 -0
- package/dist/services/email/service.js +277 -0
- package/dist/services/email/service.js.map +1 -0
- package/dist/services/email/types.d.ts +82 -0
- package/dist/services/email/types.d.ts.map +1 -0
- package/dist/services/email/types.js +3 -0
- package/dist/services/email/types.js.map +1 -0
- package/dist/tools/email-tools.d.ts +52 -0
- package/dist/tools/email-tools.d.ts.map +1 -0
- package/dist/tools/email-tools.js +237 -0
- package/dist/tools/email-tools.js.map +1 -0
- package/dist/tools/index.d.ts +3 -1
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +16 -2
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/project-tools.d.ts +6 -0
- package/dist/tools/project-tools.d.ts.map +1 -1
- package/dist/tools/project-tools.js +82 -0
- package/dist/tools/project-tools.js.map +1 -1
- package/dist/tools/tool-names.d.ts +1 -0
- package/dist/tools/tool-names.d.ts.map +1 -1
- package/dist/tools/tool-names.js +1 -0
- package/dist/tools/tool-names.js.map +1 -1
- package/package.json +2 -2
- package/web-dist/assets/{_basePickBy-1ypMBiW_.js → _basePickBy-CzT63eI9.js} +1 -1
- package/web-dist/assets/{_baseUniq-DvjcbfPq.js → _baseUniq-C9jker1F.js} +1 -1
- package/web-dist/assets/{arc-ErevYm19.js → arc-DljFfWWm.js} +1 -1
- package/web-dist/assets/{architectureDiagram-2XIMDMQ5-D_WVp0kY.js → architectureDiagram-2XIMDMQ5-pEbMBiw_.js} +1 -1
- package/web-dist/assets/{blockDiagram-WCTKOSBZ-Bo6-xom-.js → blockDiagram-WCTKOSBZ-A_4J6Sb-.js} +1 -1
- package/web-dist/assets/{c4Diagram-IC4MRINW-D9M8EKu_.js → c4Diagram-IC4MRINW-COgCzBlY.js} +1 -1
- package/web-dist/assets/channel-xM6w002v.js +1 -0
- package/web-dist/assets/{chunk-4BX2VUAB-WH1KAVAb.js → chunk-4BX2VUAB-Bfy5mnZM.js} +1 -1
- package/web-dist/assets/{chunk-55IACEB6-D2a2qrrp.js → chunk-55IACEB6-BHbwUxN1.js} +1 -1
- package/web-dist/assets/{chunk-FMBD7UC4-28DcGMIY.js → chunk-FMBD7UC4-oWbyVk_l.js} +1 -1
- package/web-dist/assets/{chunk-JSJVCQXG-C1uNGWZs.js → chunk-JSJVCQXG-DICPKbbU.js} +1 -1
- package/web-dist/assets/{chunk-KX2RTZJC-V1qtcDEn.js → chunk-KX2RTZJC-S1AI6fsb.js} +1 -1
- package/web-dist/assets/{chunk-NQ4KR5QH-cug-v0rY.js → chunk-NQ4KR5QH-CC2BDuwQ.js} +1 -1
- package/web-dist/assets/{chunk-QZHKN3VN-CM17QePX.js → chunk-QZHKN3VN-BU0b1vSt.js} +1 -1
- package/web-dist/assets/{chunk-WL4C6EOR-DlYbqSTG.js → chunk-WL4C6EOR-BxRy9Kn0.js} +1 -1
- package/web-dist/assets/classDiagram-VBA2DB6C-BwiCmurD.js +1 -0
- package/web-dist/assets/classDiagram-v2-RAHNMMFH-BwiCmurD.js +1 -0
- package/web-dist/assets/clone-BXkaMZnK.js +1 -0
- package/web-dist/assets/{cose-bilkent-S5V4N54A-CVsGoDQL.js → cose-bilkent-S5V4N54A-C0lXwD6L.js} +1 -1
- package/web-dist/assets/{dagre-KLK3FWXG-DLQZVyW4.js → dagre-KLK3FWXG-DsCVwtnr.js} +1 -1
- package/web-dist/assets/{diagram-E7M64L7V-BF0y78lG.js → diagram-E7M64L7V-CRFZjLO4.js} +1 -1
- package/web-dist/assets/{diagram-IFDJBPK2-MuDqalfZ.js → diagram-IFDJBPK2-CxxDuheX.js} +1 -1
- package/web-dist/assets/{diagram-P4PSJMXO-e36wc7XG.js → diagram-P4PSJMXO-DdN9wKJP.js} +1 -1
- package/web-dist/assets/{erDiagram-INFDFZHY-B_i7tPHh.js → erDiagram-INFDFZHY-BxRMeXZf.js} +1 -1
- package/web-dist/assets/{flowDiagram-PKNHOUZH-fPB07Diy.js → flowDiagram-PKNHOUZH--76cPw_T.js} +1 -1
- package/web-dist/assets/{ganttDiagram-A5KZAMGK-q8EsM9Gb.js → ganttDiagram-A5KZAMGK-D81XRpy6.js} +1 -1
- package/web-dist/assets/{gitGraphDiagram-K3NZZRJ6-BiAyblPL.js → gitGraphDiagram-K3NZZRJ6-BWTqK6Hq.js} +1 -1
- package/web-dist/assets/{graph-DnNeq8po.js → graph-e1i_2mNj.js} +1 -1
- package/web-dist/assets/index-BU0ZMPd5.css +32 -0
- package/web-dist/assets/{index-Bk_qadgU.js → index-C_vS46mJ.js} +1 -1
- package/web-dist/assets/{index-BbmkMmHZ.js → index-_OeJ0-l0.js} +1 -1
- package/web-dist/assets/{index-CzRne9la.js → index-oEvNrdmq.js} +395 -373
- package/web-dist/assets/{infoDiagram-LFFYTUFH-C3TzSSln.js → infoDiagram-LFFYTUFH-BAvnH6OJ.js} +1 -1
- package/web-dist/assets/{ishikawaDiagram-PHBUUO56-szGd8_KC.js → ishikawaDiagram-PHBUUO56-DaNqVDUe.js} +1 -1
- package/web-dist/assets/{journeyDiagram-4ABVD52K-ByTvobTa.js → journeyDiagram-4ABVD52K-BjDRRfop.js} +1 -1
- package/web-dist/assets/{kanban-definition-K7BYSVSG-DoUUzwjw.js → kanban-definition-K7BYSVSG-Qw6LXlh0.js} +1 -1
- package/web-dist/assets/{layout-BzJ0RrG1.js → layout-BhFuErQG.js} +1 -1
- package/web-dist/assets/{linear-B5XYxmuh.js → linear-CVpOVEfb.js} +1 -1
- package/web-dist/assets/{mindmap-definition-YRQLILUH-FaHbvuby.js → mindmap-definition-YRQLILUH-HX2oEkzo.js} +1 -1
- package/web-dist/assets/{pieDiagram-SKSYHLDU-F0mNDNRX.js → pieDiagram-SKSYHLDU-eoDXKsir.js} +1 -1
- package/web-dist/assets/{quadrantDiagram-337W2JSQ-CSy2sGI7.js → quadrantDiagram-337W2JSQ-BMuqPJ4T.js} +1 -1
- package/web-dist/assets/{requirementDiagram-Z7DCOOCP-iXp1hJSy.js → requirementDiagram-Z7DCOOCP-DortKE8d.js} +1 -1
- package/web-dist/assets/{sankeyDiagram-WA2Y5GQK-BUFT8Ncy.js → sankeyDiagram-WA2Y5GQK-BdCE80-q.js} +1 -1
- package/web-dist/assets/{sequenceDiagram-2WXFIKYE-iWc1z5r5.js → sequenceDiagram-2WXFIKYE-CcYDmGFB.js} +1 -1
- package/web-dist/assets/{stateDiagram-RAJIS63D-Dmla9JkM.js → stateDiagram-RAJIS63D-CSTfSkb3.js} +1 -1
- package/web-dist/assets/stateDiagram-v2-FVOUBMTO-DBn-vddG.js +1 -0
- package/web-dist/assets/{timeline-definition-YZTLITO2-4XUMaeyN.js → timeline-definition-YZTLITO2-CluVwYjy.js} +1 -1
- package/web-dist/assets/{treemap-KZPCXAKY-BiXISVos.js → treemap-KZPCXAKY-Ds4wGITO.js} +1 -1
- package/web-dist/assets/{vennDiagram-LZ73GAT5-BHzH1mWp.js → vennDiagram-LZ73GAT5-DDk9o8W5.js} +1 -1
- package/web-dist/assets/{xychartDiagram-JWTSCODW-C1rAefFy.js → xychartDiagram-JWTSCODW-BWpgTsfS.js} +1 -1
- package/web-dist/index.html +2 -2
- package/web-dist/assets/channel-CzVoFm04.js +0 -1
- package/web-dist/assets/classDiagram-VBA2DB6C-CkMkzWkJ.js +0 -1
- package/web-dist/assets/classDiagram-v2-RAHNMMFH-CkMkzWkJ.js +0 -1
- package/web-dist/assets/clone-BrtlKZXp.js +0 -1
- package/web-dist/assets/index-C-Ol-PwZ.css +0 -32
- package/web-dist/assets/stateDiagram-v2-FVOUBMTO-DrmN0_X9.js +0 -1
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
// Gmail mailbox client (Gmail REST API v1).
|
|
2
|
+
const BASE = "https://gmail.googleapis.com/gmail/v1/users/me";
|
|
3
|
+
// Map friendly folder names to Gmail system label ids; pass real label ids through.
|
|
4
|
+
const SYSTEM_LABELS = {
|
|
5
|
+
inbox: "INBOX", sent: "SENT", drafts: "DRAFT", draft: "DRAFT",
|
|
6
|
+
spam: "SPAM", trash: "TRASH", starred: "STARRED", important: "IMPORTANT", unread: "UNREAD",
|
|
7
|
+
};
|
|
8
|
+
function normalizeLabelId(folder) {
|
|
9
|
+
return SYSTEM_LABELS[folder.toLowerCase()] ?? folder;
|
|
10
|
+
}
|
|
11
|
+
function header(headers, name) {
|
|
12
|
+
return headers?.find((h) => h.name.toLowerCase() === name.toLowerCase())?.value ?? "";
|
|
13
|
+
}
|
|
14
|
+
function decodeBody(data) {
|
|
15
|
+
if (!data)
|
|
16
|
+
return "";
|
|
17
|
+
return Buffer.from(data.replace(/-/g, "+").replace(/_/g, "/"), "base64").toString("utf8");
|
|
18
|
+
}
|
|
19
|
+
/** Walk the MIME tree collecting the first text/plain and text/html bodies. */
|
|
20
|
+
function extractBodies(part, acc) {
|
|
21
|
+
if (!part)
|
|
22
|
+
return;
|
|
23
|
+
const mime = part.mimeType ?? "";
|
|
24
|
+
if (part.filename)
|
|
25
|
+
acc.attachments = true;
|
|
26
|
+
if (mime === "text/plain" && !acc.text)
|
|
27
|
+
acc.text = decodeBody(part.body?.data);
|
|
28
|
+
else if (mime === "text/html" && !acc.html)
|
|
29
|
+
acc.html = decodeBody(part.body?.data);
|
|
30
|
+
for (const child of part.parts ?? [])
|
|
31
|
+
extractBodies(child, acc);
|
|
32
|
+
}
|
|
33
|
+
export class GmailClient {
|
|
34
|
+
async gfetch(accessToken, path, init) {
|
|
35
|
+
const res = await fetch(`${BASE}${path}`, {
|
|
36
|
+
...init,
|
|
37
|
+
headers: {
|
|
38
|
+
Authorization: `Bearer ${accessToken}`,
|
|
39
|
+
...(init?.body ? { "Content-Type": "application/json" } : {}),
|
|
40
|
+
...(init?.headers ?? {}),
|
|
41
|
+
},
|
|
42
|
+
});
|
|
43
|
+
const text = await res.text();
|
|
44
|
+
const data = text ? JSON.parse(text) : {};
|
|
45
|
+
if (!res.ok) {
|
|
46
|
+
const msg = data?.error?.message ?? `HTTP ${res.status}`;
|
|
47
|
+
throw new Error(`Gmail API error: ${msg}`);
|
|
48
|
+
}
|
|
49
|
+
return data;
|
|
50
|
+
}
|
|
51
|
+
summarize(m, labelNames) {
|
|
52
|
+
const h = m.payload?.headers;
|
|
53
|
+
const labelIds = m.labelIds ?? [];
|
|
54
|
+
return {
|
|
55
|
+
id: m.id,
|
|
56
|
+
threadId: m.threadId,
|
|
57
|
+
from: header(h, "From"),
|
|
58
|
+
to: header(h, "To"),
|
|
59
|
+
subject: header(h, "Subject"),
|
|
60
|
+
snippet: m.snippet ?? "",
|
|
61
|
+
date: header(h, "Date"),
|
|
62
|
+
unread: labelIds.includes("UNREAD"),
|
|
63
|
+
labels: labelIds
|
|
64
|
+
.filter((id) => !id.startsWith("CATEGORY_"))
|
|
65
|
+
.map((id) => labelNames.get(id) ?? id),
|
|
66
|
+
hasAttachments: false,
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
async labelMaps(accessToken) {
|
|
70
|
+
const data = (await this.gfetch(accessToken, "/labels"));
|
|
71
|
+
const byId = new Map();
|
|
72
|
+
const byName = new Map();
|
|
73
|
+
for (const l of data.labels ?? []) {
|
|
74
|
+
byId.set(l.id, l.name);
|
|
75
|
+
byName.set(l.name.toLowerCase(), l.id);
|
|
76
|
+
}
|
|
77
|
+
return { byId, byName };
|
|
78
|
+
}
|
|
79
|
+
async listMessages(accessToken, opts) {
|
|
80
|
+
const limit = Math.min(Math.max(opts.limit ?? 25, 1), 50);
|
|
81
|
+
const params = new URLSearchParams({ maxResults: String(limit) });
|
|
82
|
+
if (opts.query)
|
|
83
|
+
params.set("q", opts.query);
|
|
84
|
+
if (opts.folder && opts.folder.toLowerCase() !== "all") {
|
|
85
|
+
params.set("labelIds", normalizeLabelId(opts.folder));
|
|
86
|
+
}
|
|
87
|
+
const list = (await this.gfetch(accessToken, `/messages?${params.toString()}`));
|
|
88
|
+
const ids = (list.messages ?? []).map((x) => x.id);
|
|
89
|
+
if (ids.length === 0)
|
|
90
|
+
return [];
|
|
91
|
+
const { byId } = await this.labelMaps(accessToken);
|
|
92
|
+
const metas = await Promise.all(ids.map((id) => this.gfetch(accessToken, `/messages/${id}?format=metadata&metadataHeaders=From&metadataHeaders=To&metadataHeaders=Subject&metadataHeaders=Date`)));
|
|
93
|
+
return metas.map((m) => this.summarize(m, byId));
|
|
94
|
+
}
|
|
95
|
+
async getMessage(accessToken, id) {
|
|
96
|
+
const m = (await this.gfetch(accessToken, `/messages/${id}?format=full`));
|
|
97
|
+
const { byId } = await this.labelMaps(accessToken);
|
|
98
|
+
const summary = this.summarize(m, byId);
|
|
99
|
+
const bodies = { text: "", html: "", attachments: false };
|
|
100
|
+
extractBodies(m.payload, bodies);
|
|
101
|
+
return {
|
|
102
|
+
...summary,
|
|
103
|
+
cc: header(m.payload?.headers, "Cc"),
|
|
104
|
+
bodyText: bodies.text,
|
|
105
|
+
bodyHtml: bodies.html,
|
|
106
|
+
hasAttachments: bodies.attachments,
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
async sendMessage(accessToken, input) {
|
|
110
|
+
const lines = [
|
|
111
|
+
`To: ${input.to}`,
|
|
112
|
+
input.cc ? `Cc: ${input.cc}` : "",
|
|
113
|
+
input.bcc ? `Bcc: ${input.bcc}` : "",
|
|
114
|
+
`Subject: ${input.subject}`,
|
|
115
|
+
"MIME-Version: 1.0",
|
|
116
|
+
`Content-Type: ${input.html ? "text/html" : "text/plain"}; charset=UTF-8`,
|
|
117
|
+
"",
|
|
118
|
+
input.body,
|
|
119
|
+
].filter(Boolean);
|
|
120
|
+
const raw = Buffer.from(lines.join("\r\n"), "utf8").toString("base64url");
|
|
121
|
+
const body = { raw };
|
|
122
|
+
if (input.replyToMessageId) {
|
|
123
|
+
const orig = (await this.gfetch(accessToken, `/messages/${input.replyToMessageId}?format=metadata`));
|
|
124
|
+
if (orig.threadId)
|
|
125
|
+
body.threadId = orig.threadId;
|
|
126
|
+
}
|
|
127
|
+
const sent = (await this.gfetch(accessToken, "/messages/send", {
|
|
128
|
+
method: "POST",
|
|
129
|
+
body: JSON.stringify(body),
|
|
130
|
+
}));
|
|
131
|
+
return { id: sent.id };
|
|
132
|
+
}
|
|
133
|
+
async tagMessage(accessToken, id, add, remove) {
|
|
134
|
+
const { byName } = await this.labelMaps(accessToken);
|
|
135
|
+
const resolve = async (name) => {
|
|
136
|
+
const builtin = name.toUpperCase();
|
|
137
|
+
if (["INBOX", "UNREAD", "STARRED", "IMPORTANT", "SPAM", "TRASH"].includes(builtin))
|
|
138
|
+
return builtin;
|
|
139
|
+
const existing = byName.get(name.toLowerCase());
|
|
140
|
+
if (existing)
|
|
141
|
+
return existing;
|
|
142
|
+
const created = (await this.gfetch(accessToken, "/labels", {
|
|
143
|
+
method: "POST",
|
|
144
|
+
body: JSON.stringify({ name, labelListVisibility: "labelShow", messageListVisibility: "show" }),
|
|
145
|
+
}));
|
|
146
|
+
byName.set(name.toLowerCase(), created.id);
|
|
147
|
+
return created.id;
|
|
148
|
+
};
|
|
149
|
+
const addLabelIds = await Promise.all(add.map(resolve));
|
|
150
|
+
const removeLabelIds = await Promise.all(remove.map(resolve));
|
|
151
|
+
await this.gfetch(accessToken, `/messages/${id}/modify`, {
|
|
152
|
+
method: "POST",
|
|
153
|
+
body: JSON.stringify({ addLabelIds, removeLabelIds }),
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
async deleteMessage(accessToken, id) {
|
|
157
|
+
await this.gfetch(accessToken, `/messages/${id}/trash`, { method: "POST" });
|
|
158
|
+
}
|
|
159
|
+
async listFolders(accessToken) {
|
|
160
|
+
const data = (await this.gfetch(accessToken, "/labels"));
|
|
161
|
+
return (data.labels ?? [])
|
|
162
|
+
.filter((l) => !l.id.startsWith("CATEGORY_"))
|
|
163
|
+
.map((l) => ({ id: l.id, name: l.name }));
|
|
164
|
+
}
|
|
165
|
+
async getProfileEmail(accessToken) {
|
|
166
|
+
const data = (await this.gfetch(accessToken, "/profile"));
|
|
167
|
+
return data.emailAddress ?? "";
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
//# sourceMappingURL=gmail.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gmail.js","sourceRoot":"","sources":["../../../src/services/email/gmail.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/services/email/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAC5C,YAAY,EACV,YAAY,EACZ,aAAa,EACb,mBAAmB,EACnB,gBAAgB,EAChB,WAAW,EACX,mBAAmB,EACnB,gBAAgB,GACjB,MAAM,YAAY,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/services/email/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { EmailProvider, EmailTokens } from "./types.js";
|
|
2
|
+
export interface OAuthClientCredentials {
|
|
3
|
+
clientId: string;
|
|
4
|
+
clientSecret: string;
|
|
5
|
+
}
|
|
6
|
+
export type ClientCredentialResolver = (provider: EmailProvider) => OAuthClientCredentials | null;
|
|
7
|
+
export declare function envClientCredentials(provider: EmailProvider): OAuthClientCredentials | null;
|
|
8
|
+
/** PKCE verifier/challenge pair (S256). */
|
|
9
|
+
export declare function createPkce(): {
|
|
10
|
+
verifier: string;
|
|
11
|
+
challenge: string;
|
|
12
|
+
};
|
|
13
|
+
export declare function buildAuthorizeUrl(params: {
|
|
14
|
+
provider: EmailProvider;
|
|
15
|
+
credentials: OAuthClientCredentials;
|
|
16
|
+
redirectUri: string;
|
|
17
|
+
state: string;
|
|
18
|
+
codeChallenge: string;
|
|
19
|
+
}): string;
|
|
20
|
+
export declare function exchangeCode(params: {
|
|
21
|
+
provider: EmailProvider;
|
|
22
|
+
credentials: OAuthClientCredentials;
|
|
23
|
+
redirectUri: string;
|
|
24
|
+
code: string;
|
|
25
|
+
codeVerifier: string;
|
|
26
|
+
}): Promise<EmailTokens>;
|
|
27
|
+
export declare function refreshTokens(params: {
|
|
28
|
+
provider: EmailProvider;
|
|
29
|
+
credentials: OAuthClientCredentials;
|
|
30
|
+
refreshToken: string;
|
|
31
|
+
}): Promise<EmailTokens>;
|
|
32
|
+
//# sourceMappingURL=oauth.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"oauth.d.ts","sourceRoot":"","sources":["../../../src/services/email/oauth.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAkC7D,MAAM,WAAW,sBAAsB;IACrC,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,MAAM,wBAAwB,GAAG,CACrC,QAAQ,EAAE,aAAa,KACpB,sBAAsB,GAAG,IAAI,CAAC;AAEnC,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,aAAa,GAAG,sBAAsB,GAAG,IAAI,CAM3F;AAED,2CAA2C;AAC3C,wBAAgB,UAAU,IAAI;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAIpE;AAED,wBAAgB,iBAAiB,CAAC,MAAM,EAAE;IACxC,QAAQ,EAAE,aAAa,CAAC;IACxB,WAAW,EAAE,sBAAsB,CAAC;IACpC,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,aAAa,EAAE,MAAM,CAAC;CACvB,GAAG,MAAM,CAcT;AA6BD,wBAAsB,YAAY,CAAC,MAAM,EAAE;IACzC,QAAQ,EAAE,aAAa,CAAC;IACxB,WAAW,EAAE,sBAAsB,CAAC;IACpC,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,CAAC;CACtB,GAAG,OAAO,CAAC,WAAW,CAAC,CAUvB;AAED,wBAAsB,aAAa,CAAC,MAAM,EAAE;IAC1C,QAAQ,EAAE,aAAa,CAAC;IACxB,WAAW,EAAE,sBAAsB,CAAC;IACpC,YAAY,EAAE,MAAM,CAAC;CACtB,GAAG,OAAO,CAAC,WAAW,CAAC,CAQvB"}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
// OAuth2 (authorization-code) helpers for Gmail and Outlook.
|
|
2
|
+
//
|
|
3
|
+
// Client credentials are resolved (in priority order) from:
|
|
4
|
+
// 1. Per-user secrets (type "email-oauth-app", keys "<provider>-client-id" /
|
|
5
|
+
// "<provider>-client-secret") — lets the user configure apps from the UI.
|
|
6
|
+
// 2. Gateway environment variables.
|
|
7
|
+
//
|
|
8
|
+
// Gmail: GMAIL_OAUTH_CLIENT_ID / GMAIL_OAUTH_CLIENT_SECRET
|
|
9
|
+
// Outlook: OUTLOOK_OAUTH_CLIENT_ID / OUTLOOK_OAUTH_CLIENT_SECRET
|
|
10
|
+
import { createHash, randomBytes } from "node:crypto";
|
|
11
|
+
const PROVIDERS = {
|
|
12
|
+
gmail: {
|
|
13
|
+
authorizeUrl: "https://accounts.google.com/o/oauth2/v2/auth",
|
|
14
|
+
tokenUrl: "https://oauth2.googleapis.com/token",
|
|
15
|
+
scopes: [
|
|
16
|
+
"https://www.googleapis.com/auth/gmail.modify",
|
|
17
|
+
"https://www.googleapis.com/auth/gmail.send",
|
|
18
|
+
],
|
|
19
|
+
// offline + consent are required to reliably receive a refresh token.
|
|
20
|
+
authorizeParams: { access_type: "offline", prompt: "consent" },
|
|
21
|
+
},
|
|
22
|
+
outlook: {
|
|
23
|
+
authorizeUrl: "https://login.microsoftonline.com/common/oauth2/v2.0/authorize",
|
|
24
|
+
tokenUrl: "https://login.microsoftonline.com/common/oauth2/v2.0/token",
|
|
25
|
+
scopes: [
|
|
26
|
+
"offline_access",
|
|
27
|
+
"https://graph.microsoft.com/Mail.ReadWrite",
|
|
28
|
+
"https://graph.microsoft.com/Mail.Send",
|
|
29
|
+
"https://graph.microsoft.com/User.Read",
|
|
30
|
+
],
|
|
31
|
+
authorizeParams: { response_mode: "query" },
|
|
32
|
+
},
|
|
33
|
+
};
|
|
34
|
+
export function envClientCredentials(provider) {
|
|
35
|
+
const prefix = provider === "gmail" ? "GMAIL" : "OUTLOOK";
|
|
36
|
+
const clientId = process.env[`${prefix}_OAUTH_CLIENT_ID`]?.trim();
|
|
37
|
+
const clientSecret = process.env[`${prefix}_OAUTH_CLIENT_SECRET`]?.trim();
|
|
38
|
+
if (!clientId || !clientSecret)
|
|
39
|
+
return null;
|
|
40
|
+
return { clientId, clientSecret };
|
|
41
|
+
}
|
|
42
|
+
/** PKCE verifier/challenge pair (S256). */
|
|
43
|
+
export function createPkce() {
|
|
44
|
+
const verifier = randomBytes(32).toString("base64url");
|
|
45
|
+
const challenge = createHash("sha256").update(verifier).digest("base64url");
|
|
46
|
+
return { verifier, challenge };
|
|
47
|
+
}
|
|
48
|
+
export function buildAuthorizeUrl(params) {
|
|
49
|
+
const cfg = PROVIDERS[params.provider];
|
|
50
|
+
const url = new URL(cfg.authorizeUrl);
|
|
51
|
+
url.searchParams.set("client_id", params.credentials.clientId);
|
|
52
|
+
url.searchParams.set("redirect_uri", params.redirectUri);
|
|
53
|
+
url.searchParams.set("response_type", "code");
|
|
54
|
+
url.searchParams.set("scope", cfg.scopes.join(" "));
|
|
55
|
+
url.searchParams.set("state", params.state);
|
|
56
|
+
url.searchParams.set("code_challenge", params.codeChallenge);
|
|
57
|
+
url.searchParams.set("code_challenge_method", "S256");
|
|
58
|
+
for (const [k, v] of Object.entries(cfg.authorizeParams)) {
|
|
59
|
+
url.searchParams.set(k, v);
|
|
60
|
+
}
|
|
61
|
+
return url.toString();
|
|
62
|
+
}
|
|
63
|
+
function tokensFromResponse(data, fallbackRefresh) {
|
|
64
|
+
const expiresIn = typeof data["expires_in"] === "number" ? data["expires_in"] : 3600;
|
|
65
|
+
return {
|
|
66
|
+
accessToken: String(data["access_token"] ?? ""),
|
|
67
|
+
refreshToken: data["refresh_token"] ?? fallbackRefresh ?? null,
|
|
68
|
+
expiresAt: Date.now() + expiresIn * 1000,
|
|
69
|
+
scope: data["scope"],
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
async function postToken(provider, body) {
|
|
73
|
+
const res = await fetch(PROVIDERS[provider].tokenUrl, {
|
|
74
|
+
method: "POST",
|
|
75
|
+
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
76
|
+
body: new URLSearchParams(body).toString(),
|
|
77
|
+
});
|
|
78
|
+
const data = (await res.json().catch(() => ({})));
|
|
79
|
+
if (!res.ok) {
|
|
80
|
+
const detail = data["error_description"] ?? data["error"] ?? `HTTP ${res.status}`;
|
|
81
|
+
throw new Error(`OAuth token request failed: ${detail}`);
|
|
82
|
+
}
|
|
83
|
+
return data;
|
|
84
|
+
}
|
|
85
|
+
export async function exchangeCode(params) {
|
|
86
|
+
const data = await postToken(params.provider, {
|
|
87
|
+
client_id: params.credentials.clientId,
|
|
88
|
+
client_secret: params.credentials.clientSecret,
|
|
89
|
+
code: params.code,
|
|
90
|
+
redirect_uri: params.redirectUri,
|
|
91
|
+
grant_type: "authorization_code",
|
|
92
|
+
code_verifier: params.codeVerifier,
|
|
93
|
+
});
|
|
94
|
+
return tokensFromResponse(data);
|
|
95
|
+
}
|
|
96
|
+
export async function refreshTokens(params) {
|
|
97
|
+
const data = await postToken(params.provider, {
|
|
98
|
+
client_id: params.credentials.clientId,
|
|
99
|
+
client_secret: params.credentials.clientSecret,
|
|
100
|
+
refresh_token: params.refreshToken,
|
|
101
|
+
grant_type: "refresh_token",
|
|
102
|
+
});
|
|
103
|
+
return tokensFromResponse(data, params.refreshToken);
|
|
104
|
+
}
|
|
105
|
+
//# sourceMappingURL=oauth.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"oauth.js","sourceRoot":"","sources":["../../../src/services/email/oauth.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { EmailFolder, EmailMessageFull, EmailMessageSummary, ListMessagesOptions, MailboxClient, SendMessageInput } from "./types.js";
|
|
2
|
+
export declare class OutlookClient implements MailboxClient {
|
|
3
|
+
private gfetch;
|
|
4
|
+
private summarize;
|
|
5
|
+
listMessages(accessToken: string, opts: ListMessagesOptions): Promise<EmailMessageSummary[]>;
|
|
6
|
+
getMessage(accessToken: string, id: string): Promise<EmailMessageFull>;
|
|
7
|
+
sendMessage(accessToken: string, input: SendMessageInput): Promise<{
|
|
8
|
+
id: string;
|
|
9
|
+
}>;
|
|
10
|
+
tagMessage(accessToken: string, id: string, add: string[], remove: string[]): Promise<void>;
|
|
11
|
+
deleteMessage(accessToken: string, id: string): Promise<void>;
|
|
12
|
+
listFolders(accessToken: string): Promise<EmailFolder[]>;
|
|
13
|
+
getProfileEmail(accessToken: string): Promise<string>;
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=outlook.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"outlook.d.ts","sourceRoot":"","sources":["../../../src/services/email/outlook.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,WAAW,EACX,gBAAgB,EAChB,mBAAmB,EACnB,mBAAmB,EACnB,aAAa,EACb,gBAAgB,EACjB,MAAM,YAAY,CAAC;AAuCpB,qBAAa,aAAc,YAAW,aAAa;YACnC,MAAM;IAmBpB,OAAO,CAAC,SAAS;IAeX,YAAY,CAAC,WAAW,EAAE,MAAM,EAAE,IAAI,EAAE,mBAAmB,GAAG,OAAO,CAAC,mBAAmB,EAAE,CAAC;IAsB5F,UAAU,CAAC,WAAW,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAYtE,WAAW,CAAC,WAAW,EAAE,MAAM,EAAE,KAAK,EAAE,gBAAgB,GAAG,OAAO,CAAC;QAAE,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC;IA8BlF,UAAU,CAAC,WAAW,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAW3F,aAAa,CAAC,WAAW,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAK7D,WAAW,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;IAOxD,eAAe,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;CAO5D"}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
// Outlook mailbox client (Microsoft Graph v1.0).
|
|
2
|
+
const BASE = "https://graph.microsoft.com/v1.0";
|
|
3
|
+
function fmtRecipient(r) {
|
|
4
|
+
const ea = r?.emailAddress;
|
|
5
|
+
if (!ea)
|
|
6
|
+
return "";
|
|
7
|
+
return ea.name ? `${ea.name} <${ea.address ?? ""}>` : ea.address ?? "";
|
|
8
|
+
}
|
|
9
|
+
function fmtRecipients(list) {
|
|
10
|
+
return (list ?? []).map(fmtRecipient).filter(Boolean).join(", ");
|
|
11
|
+
}
|
|
12
|
+
function toGraphRecipients(value) {
|
|
13
|
+
if (!value)
|
|
14
|
+
return [];
|
|
15
|
+
return value
|
|
16
|
+
.split(/[,;]/)
|
|
17
|
+
.map((s) => s.trim())
|
|
18
|
+
.filter(Boolean)
|
|
19
|
+
.map((address) => ({ emailAddress: { address } }));
|
|
20
|
+
}
|
|
21
|
+
export class OutlookClient {
|
|
22
|
+
async gfetch(accessToken, path, init) {
|
|
23
|
+
const res = await fetch(`${BASE}${path}`, {
|
|
24
|
+
...init,
|
|
25
|
+
headers: {
|
|
26
|
+
Authorization: `Bearer ${accessToken}`,
|
|
27
|
+
...(init?.body ? { "Content-Type": "application/json" } : {}),
|
|
28
|
+
...(init?.headers ?? {}),
|
|
29
|
+
},
|
|
30
|
+
});
|
|
31
|
+
if (res.status === 204)
|
|
32
|
+
return {};
|
|
33
|
+
const text = await res.text();
|
|
34
|
+
const data = text ? JSON.parse(text) : {};
|
|
35
|
+
if (!res.ok) {
|
|
36
|
+
const msg = data?.error?.message ?? `HTTP ${res.status}`;
|
|
37
|
+
throw new Error(`Microsoft Graph error: ${msg}`);
|
|
38
|
+
}
|
|
39
|
+
return data;
|
|
40
|
+
}
|
|
41
|
+
summarize(m) {
|
|
42
|
+
return {
|
|
43
|
+
id: m.id,
|
|
44
|
+
threadId: m.conversationId,
|
|
45
|
+
from: fmtRecipient(m.from),
|
|
46
|
+
to: fmtRecipients(m.toRecipients),
|
|
47
|
+
subject: m.subject ?? "",
|
|
48
|
+
snippet: m.bodyPreview ?? "",
|
|
49
|
+
date: m.receivedDateTime ?? "",
|
|
50
|
+
unread: m.isRead === false,
|
|
51
|
+
labels: m.categories ?? [],
|
|
52
|
+
hasAttachments: m.hasAttachments ?? false,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
async listMessages(accessToken, opts) {
|
|
56
|
+
const limit = Math.min(Math.max(opts.limit ?? 25, 1), 50);
|
|
57
|
+
const folder = opts.folder && opts.folder.toLowerCase() !== "all" ? opts.folder : "inbox";
|
|
58
|
+
const params = new URLSearchParams({
|
|
59
|
+
$top: String(limit),
|
|
60
|
+
$select: "id,conversationId,subject,bodyPreview,receivedDateTime,isRead,hasAttachments,categories,from,toRecipients",
|
|
61
|
+
});
|
|
62
|
+
let path;
|
|
63
|
+
if (opts.query) {
|
|
64
|
+
// $search cannot be combined with $orderby.
|
|
65
|
+
params.set("$search", `"${opts.query.replace(/"/g, "")}"`);
|
|
66
|
+
path = `/me/mailFolders/${folder}/messages?${params.toString()}`;
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
params.set("$orderby", "receivedDateTime desc");
|
|
70
|
+
path = `/me/mailFolders/${folder}/messages?${params.toString()}`;
|
|
71
|
+
}
|
|
72
|
+
const data = (await this.gfetch(accessToken, path, {
|
|
73
|
+
headers: { ConsistencyLevel: "eventual" },
|
|
74
|
+
}));
|
|
75
|
+
return (data.value ?? []).map((m) => this.summarize(m));
|
|
76
|
+
}
|
|
77
|
+
async getMessage(accessToken, id) {
|
|
78
|
+
const m = (await this.gfetch(accessToken, `/me/messages/${id}`));
|
|
79
|
+
const summary = this.summarize(m);
|
|
80
|
+
const isHtml = (m.body?.contentType ?? "").toLowerCase() === "html";
|
|
81
|
+
return {
|
|
82
|
+
...summary,
|
|
83
|
+
cc: fmtRecipients(m.ccRecipients),
|
|
84
|
+
bodyText: isHtml ? "" : m.body?.content ?? "",
|
|
85
|
+
bodyHtml: isHtml ? m.body?.content ?? "" : "",
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
async sendMessage(accessToken, input) {
|
|
89
|
+
if (input.replyToMessageId) {
|
|
90
|
+
await this.gfetch(accessToken, `/me/messages/${input.replyToMessageId}/reply`, {
|
|
91
|
+
method: "POST",
|
|
92
|
+
body: JSON.stringify({
|
|
93
|
+
message: {
|
|
94
|
+
toRecipients: input.to ? toGraphRecipients(input.to) : undefined,
|
|
95
|
+
ccRecipients: toGraphRecipients(input.cc),
|
|
96
|
+
},
|
|
97
|
+
comment: input.body,
|
|
98
|
+
}),
|
|
99
|
+
});
|
|
100
|
+
return { id: input.replyToMessageId };
|
|
101
|
+
}
|
|
102
|
+
await this.gfetch(accessToken, "/me/sendMail", {
|
|
103
|
+
method: "POST",
|
|
104
|
+
body: JSON.stringify({
|
|
105
|
+
message: {
|
|
106
|
+
subject: input.subject,
|
|
107
|
+
body: { contentType: input.html ? "HTML" : "Text", content: input.body },
|
|
108
|
+
toRecipients: toGraphRecipients(input.to),
|
|
109
|
+
ccRecipients: toGraphRecipients(input.cc),
|
|
110
|
+
bccRecipients: toGraphRecipients(input.bcc),
|
|
111
|
+
},
|
|
112
|
+
saveToSentItems: true,
|
|
113
|
+
}),
|
|
114
|
+
});
|
|
115
|
+
return { id: "" };
|
|
116
|
+
}
|
|
117
|
+
async tagMessage(accessToken, id, add, remove) {
|
|
118
|
+
const m = (await this.gfetch(accessToken, `/me/messages/${id}?$select=categories`));
|
|
119
|
+
const current = new Set(m.categories ?? []);
|
|
120
|
+
for (const c of add)
|
|
121
|
+
current.add(c);
|
|
122
|
+
for (const c of remove)
|
|
123
|
+
current.delete(c);
|
|
124
|
+
await this.gfetch(accessToken, `/me/messages/${id}`, {
|
|
125
|
+
method: "PATCH",
|
|
126
|
+
body: JSON.stringify({ categories: [...current] }),
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
async deleteMessage(accessToken, id) {
|
|
130
|
+
// DELETE moves the message to Deleted Items.
|
|
131
|
+
await this.gfetch(accessToken, `/me/messages/${id}`, { method: "DELETE" });
|
|
132
|
+
}
|
|
133
|
+
async listFolders(accessToken) {
|
|
134
|
+
const data = (await this.gfetch(accessToken, "/me/mailFolders?$top=50&$select=id,displayName,unreadItemCount"));
|
|
135
|
+
return (data.value ?? []).map((f) => ({ id: f.id, name: f.displayName, unreadCount: f.unreadItemCount }));
|
|
136
|
+
}
|
|
137
|
+
async getProfileEmail(accessToken) {
|
|
138
|
+
const data = (await this.gfetch(accessToken, "/me?$select=mail,userPrincipalName"));
|
|
139
|
+
return data.mail ?? data.userPrincipalName ?? "";
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
//# sourceMappingURL=outlook.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"outlook.js","sourceRoot":"","sources":["../../../src/services/email/outlook.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type { JaitDB } from "../../db/connection.js";
|
|
2
|
+
import type { UserSecretService } from "../user-secrets.js";
|
|
3
|
+
import { type OAuthClientCredentials } from "./oauth.js";
|
|
4
|
+
import type { EmailAccount, EmailFolder, EmailMessageFull, EmailMessageSummary, EmailProvider, ListMessagesOptions, SendMessageInput } from "./types.js";
|
|
5
|
+
export declare class EmailService {
|
|
6
|
+
private readonly db;
|
|
7
|
+
private readonly secrets;
|
|
8
|
+
private readonly clients;
|
|
9
|
+
private readonly pending;
|
|
10
|
+
constructor(db: JaitDB, secrets: UserSecretService);
|
|
11
|
+
/** Resolve OAuth app credentials: per-user secret first, then env. */
|
|
12
|
+
resolveCredentials(provider: EmailProvider, userId: string | null): OAuthClientCredentials | null;
|
|
13
|
+
/** Which providers are ready to connect (have OAuth app credentials). */
|
|
14
|
+
configuredProviders(userId: string | null): Record<EmailProvider, boolean>;
|
|
15
|
+
saveAppCredentials(userId: string | null, provider: EmailProvider, creds: OAuthClientCredentials): void;
|
|
16
|
+
startConnect(params: {
|
|
17
|
+
userId: string | null;
|
|
18
|
+
provider: EmailProvider;
|
|
19
|
+
redirectUri: string;
|
|
20
|
+
}): {
|
|
21
|
+
authUrl: string;
|
|
22
|
+
};
|
|
23
|
+
completeConnect(params: {
|
|
24
|
+
code: string;
|
|
25
|
+
state: string;
|
|
26
|
+
}): Promise<EmailAccount>;
|
|
27
|
+
listAccounts(userId: string | null): EmailAccount[];
|
|
28
|
+
getAccount(userId: string | null, accountId: string): EmailAccount | null;
|
|
29
|
+
/** Resolve an account by id, or fall back to the user's first account. */
|
|
30
|
+
resolveAccount(userId: string | null, accountId?: string): EmailAccount;
|
|
31
|
+
disconnect(userId: string | null, accountId: string): boolean;
|
|
32
|
+
private upsertAccount;
|
|
33
|
+
private storeTokens;
|
|
34
|
+
private loadTokens;
|
|
35
|
+
private findTokenSecretId;
|
|
36
|
+
private validAccessToken;
|
|
37
|
+
listMessages(userId: string | null, accountId: string | undefined, opts: ListMessagesOptions): Promise<{
|
|
38
|
+
account: EmailAccount;
|
|
39
|
+
messages: EmailMessageSummary[];
|
|
40
|
+
}>;
|
|
41
|
+
getMessage(userId: string | null, accountId: string | undefined, id: string): Promise<EmailMessageFull>;
|
|
42
|
+
sendMessage(userId: string | null, accountId: string | undefined, input: SendMessageInput): Promise<{
|
|
43
|
+
id: string;
|
|
44
|
+
}>;
|
|
45
|
+
tagMessage(userId: string | null, accountId: string | undefined, id: string, add: string[], remove: string[]): Promise<void>;
|
|
46
|
+
deleteMessage(userId: string | null, accountId: string | undefined, id: string): Promise<void>;
|
|
47
|
+
listFolders(userId: string | null, accountId: string | undefined): Promise<EmailFolder[]>;
|
|
48
|
+
private gcPending;
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../../src/services/email/service.ts"],"names":[],"mappings":"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"}
|