@diskd-ai/email-client-mcp 0.1.0
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/LICENSE +155 -0
- package/README.md +110 -0
- package/dist/config/loader.d.ts +12 -0
- package/dist/config/loader.js +42 -0
- package/dist/config/loader.js.map +1 -0
- package/dist/config/schema.d.ts +512 -0
- package/dist/config/schema.js +66 -0
- package/dist/config/schema.js.map +1 -0
- package/dist/domain/errors.d.ts +40 -0
- package/dist/domain/errors.js +46 -0
- package/dist/domain/errors.js.map +1 -0
- package/dist/domain/result.d.ts +30 -0
- package/dist/domain/result.js +12 -0
- package/dist/domain/result.js.map +1 -0
- package/dist/imap/fetch.d.ts +44 -0
- package/dist/imap/fetch.js +127 -0
- package/dist/imap/fetch.js.map +1 -0
- package/dist/imap/mapper.d.ts +70 -0
- package/dist/imap/mapper.js +140 -0
- package/dist/imap/mapper.js.map +1 -0
- package/dist/imap/pool.d.ts +26 -0
- package/dist/imap/pool.js +92 -0
- package/dist/imap/pool.js.map +1 -0
- package/dist/imap/virtualFolders.d.ts +11 -0
- package/dist/imap/virtualFolders.js +20 -0
- package/dist/imap/virtualFolders.js.map +1 -0
- package/dist/sdk/diskdClient.d.ts +21 -0
- package/dist/sdk/diskdClient.js +39 -0
- package/dist/sdk/diskdClient.js.map +1 -0
- package/dist/server.d.ts +17 -0
- package/dist/server.js +180 -0
- package/dist/server.js.map +1 -0
- package/dist/store/conventions.d.ts +31 -0
- package/dist/store/conventions.js +53 -0
- package/dist/store/conventions.js.map +1 -0
- package/dist/store/driveStore.d.ts +36 -0
- package/dist/store/driveStore.js +95 -0
- package/dist/store/driveStore.js.map +1 -0
- package/dist/store/payloadTypes.d.ts +62 -0
- package/dist/store/payloadTypes.js +11 -0
- package/dist/store/payloadTypes.js.map +1 -0
- package/dist/sync/backoff.d.ts +18 -0
- package/dist/sync/backoff.js +24 -0
- package/dist/sync/backoff.js.map +1 -0
- package/dist/sync/sync.d.ts +85 -0
- package/dist/sync/sync.js +383 -0
- package/dist/sync/sync.js.map +1 -0
- package/dist/sync/watcher.d.ts +43 -0
- package/dist/sync/watcher.js +141 -0
- package/dist/sync/watcher.js.map +1 -0
- package/dist/tools/bulkAction.d.ts +41 -0
- package/dist/tools/bulkAction.js +82 -0
- package/dist/tools/bulkAction.js.map +1 -0
- package/dist/tools/findMailboxFolder.d.ts +33 -0
- package/dist/tools/findMailboxFolder.js +45 -0
- package/dist/tools/findMailboxFolder.js.map +1 -0
- package/dist/tools/getEmail.d.ts +41 -0
- package/dist/tools/getEmail.js +74 -0
- package/dist/tools/getEmail.js.map +1 -0
- package/dist/tools/getEmails.d.ts +38 -0
- package/dist/tools/getEmails.js +72 -0
- package/dist/tools/getEmails.js.map +1 -0
- package/dist/tools/getWatcherStatus.d.ts +9 -0
- package/dist/tools/getWatcherStatus.js +8 -0
- package/dist/tools/getWatcherStatus.js.map +1 -0
- package/dist/tools/listAccounts.d.ts +19 -0
- package/dist/tools/listAccounts.js +18 -0
- package/dist/tools/listAccounts.js.map +1 -0
- package/dist/tools/listEmails.d.ts +70 -0
- package/dist/tools/listEmails.js +101 -0
- package/dist/tools/listEmails.js.map +1 -0
- package/dist/tools/listMailboxFolder.d.ts +33 -0
- package/dist/tools/listMailboxFolder.js +60 -0
- package/dist/tools/listMailboxFolder.js.map +1 -0
- package/dist/tools/moveEmail.d.ts +36 -0
- package/dist/tools/moveEmail.js +52 -0
- package/dist/tools/moveEmail.js.map +1 -0
- package/dist/tools/registry.d.ts +17 -0
- package/dist/tools/registry.js +64 -0
- package/dist/tools/registry.js.map +1 -0
- package/package.json +46 -0
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP tool: bulk_action -- batch operation on a UID list (max 100).
|
|
3
|
+
*
|
|
4
|
+
* Actions:
|
|
5
|
+
* - mark_read / mark_unread: STORE +/-FLAGS \\Seen
|
|
6
|
+
* - flag / unflag: STORE +/-FLAGS \\Flagged
|
|
7
|
+
* - move: MOVE to targetMailbox (refuses virtual sources)
|
|
8
|
+
* - delete: EXPUNGE-style delete
|
|
9
|
+
*
|
|
10
|
+
* Returns per-UID success/failure detail so callers can recover.
|
|
11
|
+
*/
|
|
12
|
+
import { z } from "zod";
|
|
13
|
+
import { imapError, notFound, virtualFolderRefused } from "../domain/errors.js";
|
|
14
|
+
import { Err, Ok } from "../domain/result.js";
|
|
15
|
+
import { withMailboxLock } from "../imap/fetch.js";
|
|
16
|
+
import { isVirtualFolderPath } from "../imap/virtualFolders.js";
|
|
17
|
+
const bulkActionEnum = z.enum(["mark_read", "mark_unread", "flag", "unflag", "move", "delete"]);
|
|
18
|
+
export const bulkActionInput = z
|
|
19
|
+
.object({
|
|
20
|
+
account: z.string().min(1),
|
|
21
|
+
sourceMailbox: z.string().min(1),
|
|
22
|
+
uids: z.array(z.number().int().positive()).min(1).max(100),
|
|
23
|
+
action: bulkActionEnum,
|
|
24
|
+
targetMailbox: z.string().optional(),
|
|
25
|
+
})
|
|
26
|
+
.strict();
|
|
27
|
+
export const bulkAction = async (pool, input) => {
|
|
28
|
+
if (!pool.accountIds.includes(input.account))
|
|
29
|
+
return Err(notFound(`account '${input.account}'`));
|
|
30
|
+
if (input.action === "move" &&
|
|
31
|
+
(input.targetMailbox === undefined || input.targetMailbox.length === 0)) {
|
|
32
|
+
return Err(imapError(input.account, "bulk_action(move) requires targetMailbox"));
|
|
33
|
+
}
|
|
34
|
+
if (input.action === "move" && isVirtualFolderPath(input.sourceMailbox)) {
|
|
35
|
+
return Err(virtualFolderRefused(input.sourceMailbox));
|
|
36
|
+
}
|
|
37
|
+
const clientR = await pool.forAccount(input.account);
|
|
38
|
+
if (clientR.tag === "Err")
|
|
39
|
+
return clientR;
|
|
40
|
+
const client = clientR.value;
|
|
41
|
+
try {
|
|
42
|
+
return await withMailboxLock(client, input.sourceMailbox, async () => {
|
|
43
|
+
let ok = false;
|
|
44
|
+
switch (input.action) {
|
|
45
|
+
case "mark_read":
|
|
46
|
+
ok = await client.messageFlagsAdd(input.uids, ["\\Seen"], { uid: true });
|
|
47
|
+
break;
|
|
48
|
+
case "mark_unread":
|
|
49
|
+
ok = await client.messageFlagsRemove(input.uids, ["\\Seen"], { uid: true });
|
|
50
|
+
break;
|
|
51
|
+
case "flag":
|
|
52
|
+
ok = await client.messageFlagsAdd(input.uids, ["\\Flagged"], { uid: true });
|
|
53
|
+
break;
|
|
54
|
+
case "unflag":
|
|
55
|
+
ok = await client.messageFlagsRemove(input.uids, ["\\Flagged"], { uid: true });
|
|
56
|
+
break;
|
|
57
|
+
case "move": {
|
|
58
|
+
const r = await client.messageMove(input.uids, input.targetMailbox, {
|
|
59
|
+
uid: true,
|
|
60
|
+
});
|
|
61
|
+
ok = r !== false;
|
|
62
|
+
break;
|
|
63
|
+
}
|
|
64
|
+
case "delete":
|
|
65
|
+
ok = await client.messageDelete(input.uids, { uid: true });
|
|
66
|
+
break;
|
|
67
|
+
}
|
|
68
|
+
// imapflow STORE/MOVE/DELETE is all-or-nothing per call; we cannot
|
|
69
|
+
// partition success across UIDs without a per-UID retry. If the
|
|
70
|
+
// server rejected the whole batch, surface every UID as failed.
|
|
71
|
+
return Ok({
|
|
72
|
+
action: input.action,
|
|
73
|
+
succeeded: ok ? input.uids.length : 0,
|
|
74
|
+
failedUids: ok ? [] : [...input.uids],
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
catch (cause) {
|
|
79
|
+
return Err(imapError(input.account, `bulk_action(${input.action}) failed`, cause));
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
//# sourceMappingURL=bulkAction.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bulkAction.js","sourceRoot":"","sources":["../../src/tools/bulkAction.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAiB,SAAS,EAAE,QAAQ,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAC/F,OAAO,EAAE,GAAG,EAAE,EAAE,EAAe,MAAM,qBAAqB,CAAC;AAC3D,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAEnD,OAAO,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AAEhE,MAAM,cAAc,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE,aAAa,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC;AAEhG,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC;KAC7B,MAAM,CAAC;IACN,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IAC1B,aAAa,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IAChC,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC;IAC1D,MAAM,EAAE,cAAc;IACtB,aAAa,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;CACrC,CAAC;KACD,MAAM,EAAE,CAAC;AASZ,MAAM,CAAC,MAAM,UAAU,GAAG,KAAK,EAC7B,IAAc,EACd,KAAsB,EACuB,EAAE;IAC/C,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC;QAAE,OAAO,GAAG,CAAC,QAAQ,CAAC,YAAY,KAAK,CAAC,OAAO,GAAG,CAAC,CAAC,CAAC;IACjG,IACE,KAAK,CAAC,MAAM,KAAK,MAAM;QACvB,CAAC,KAAK,CAAC,aAAa,KAAK,SAAS,IAAI,KAAK,CAAC,aAAa,CAAC,MAAM,KAAK,CAAC,CAAC,EACvE,CAAC;QACD,OAAO,GAAG,CAAC,SAAS,CAAC,KAAK,CAAC,OAAO,EAAE,0CAA0C,CAAC,CAAC,CAAC;IACnF,CAAC;IACD,IAAI,KAAK,CAAC,MAAM,KAAK,MAAM,IAAI,mBAAmB,CAAC,KAAK,CAAC,aAAa,CAAC,EAAE,CAAC;QACxE,OAAO,GAAG,CAAC,oBAAoB,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC,CAAC;IACxD,CAAC;IACD,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IACrD,IAAI,OAAO,CAAC,GAAG,KAAK,KAAK;QAAE,OAAO,OAAO,CAAC;IAC1C,MAAM,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC;IAC7B,IAAI,CAAC;QACH,OAAO,MAAM,eAAe,CAAC,MAAM,EAAE,KAAK,CAAC,aAAa,EAAE,KAAK,IAAI,EAAE;YACnE,IAAI,EAAE,GAAG,KAAK,CAAC;YACf,QAAQ,KAAK,CAAC,MAAM,EAAE,CAAC;gBACrB,KAAK,WAAW;oBACd,EAAE,GAAG,MAAM,MAAM,CAAC,eAAe,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,QAAQ,CAAC,EAAE,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC;oBACzE,MAAM;gBACR,KAAK,aAAa;oBAChB,EAAE,GAAG,MAAM,MAAM,CAAC,kBAAkB,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,QAAQ,CAAC,EAAE,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC;oBAC5E,MAAM;gBACR,KAAK,MAAM;oBACT,EAAE,GAAG,MAAM,MAAM,CAAC,eAAe,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,WAAW,CAAC,EAAE,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC;oBAC5E,MAAM;gBACR,KAAK,QAAQ;oBACX,EAAE,GAAG,MAAM,MAAM,CAAC,kBAAkB,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,WAAW,CAAC,EAAE,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC;oBAC/E,MAAM;gBACR,KAAK,MAAM,CAAC,CAAC,CAAC;oBACZ,MAAM,CAAC,GAAG,MAAM,MAAM,CAAC,WAAW,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,aAAuB,EAAE;wBAC5E,GAAG,EAAE,IAAI;qBACV,CAAC,CAAC;oBACH,EAAE,GAAG,CAAC,KAAK,KAAK,CAAC;oBACjB,MAAM;gBACR,CAAC;gBACD,KAAK,QAAQ;oBACX,EAAE,GAAG,MAAM,MAAM,CAAC,aAAa,CAAC,KAAK,CAAC,IAAI,EAAE,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC;oBAC3D,MAAM;YACV,CAAC;YACD,mEAAmE;YACnE,gEAAgE;YAChE,gEAAgE;YAChE,OAAO,EAAE,CAAC;gBACR,MAAM,EAAE,KAAK,CAAC,MAAM;gBACpB,SAAS,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;gBACrC,UAAU,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,IAAI,CAAC;aACtC,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;IACL,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,GAAG,CAAC,SAAS,CAAC,KAAK,CAAC,OAAO,EAAE,eAAe,KAAK,CAAC,MAAM,UAAU,EAAE,KAAK,CAAC,CAAC,CAAC;IACrF,CAAC;AACH,CAAC,CAAC"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP tool: find_mailbox_folder -- given a Message-Id, list all real
|
|
3
|
+
* folders that contain a copy of that message. Required pre-step for
|
|
4
|
+
* `move_email` when the message was discovered via a virtual folder
|
|
5
|
+
* (e.g. Gmail "[Gmail]/All Mail").
|
|
6
|
+
*
|
|
7
|
+
* Strategy: list folders, skip virtuals, run UID SEARCH HEADER
|
|
8
|
+
* Message-Id on each, collect the hits.
|
|
9
|
+
*/
|
|
10
|
+
import { z } from "zod";
|
|
11
|
+
import { type AppError } from "../domain/errors.js";
|
|
12
|
+
import { type Result } from "../domain/result.js";
|
|
13
|
+
import type { ImapPool } from "../imap/pool.js";
|
|
14
|
+
export declare const findMailboxFolderInput: z.ZodObject<{
|
|
15
|
+
account: z.ZodString;
|
|
16
|
+
messageId: z.ZodString;
|
|
17
|
+
}, "strict", z.ZodTypeAny, {
|
|
18
|
+
account: string;
|
|
19
|
+
messageId: string;
|
|
20
|
+
}, {
|
|
21
|
+
account: string;
|
|
22
|
+
messageId: string;
|
|
23
|
+
}>;
|
|
24
|
+
export type FindMailboxFolderInput = z.infer<typeof findMailboxFolderInput>;
|
|
25
|
+
export type FindMailboxFolderResult = {
|
|
26
|
+
readonly account: string;
|
|
27
|
+
readonly messageId: string;
|
|
28
|
+
readonly folders: ReadonlyArray<{
|
|
29
|
+
readonly path: string;
|
|
30
|
+
readonly uids: readonly number[];
|
|
31
|
+
}>;
|
|
32
|
+
};
|
|
33
|
+
export declare const findMailboxFolder: (pool: ImapPool, input: FindMailboxFolderInput) => Promise<Result<AppError, FindMailboxFolderResult>>;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP tool: find_mailbox_folder -- given a Message-Id, list all real
|
|
3
|
+
* folders that contain a copy of that message. Required pre-step for
|
|
4
|
+
* `move_email` when the message was discovered via a virtual folder
|
|
5
|
+
* (e.g. Gmail "[Gmail]/All Mail").
|
|
6
|
+
*
|
|
7
|
+
* Strategy: list folders, skip virtuals, run UID SEARCH HEADER
|
|
8
|
+
* Message-Id on each, collect the hits.
|
|
9
|
+
*/
|
|
10
|
+
import { z } from "zod";
|
|
11
|
+
import { imapError, notFound } from "../domain/errors.js";
|
|
12
|
+
import { Err, Ok } from "../domain/result.js";
|
|
13
|
+
import { withMailboxLock } from "../imap/fetch.js";
|
|
14
|
+
import { isVirtualFolderPath, isVirtualSpecialUse } from "../imap/virtualFolders.js";
|
|
15
|
+
export const findMailboxFolderInput = z
|
|
16
|
+
.object({
|
|
17
|
+
account: z.string().min(1),
|
|
18
|
+
messageId: z.string().min(1),
|
|
19
|
+
})
|
|
20
|
+
.strict();
|
|
21
|
+
export const findMailboxFolder = async (pool, input) => {
|
|
22
|
+
if (!pool.accountIds.includes(input.account))
|
|
23
|
+
return Err(notFound(`account '${input.account}'`));
|
|
24
|
+
const clientR = await pool.forAccount(input.account);
|
|
25
|
+
if (clientR.tag === "Err")
|
|
26
|
+
return clientR;
|
|
27
|
+
const client = clientR.value;
|
|
28
|
+
try {
|
|
29
|
+
const folders = await client.list();
|
|
30
|
+
const hits = [];
|
|
31
|
+
for (const f of folders) {
|
|
32
|
+
const specialUse = (f.specialUse ?? null);
|
|
33
|
+
if (isVirtualFolderPath(f.path) || isVirtualSpecialUse(specialUse))
|
|
34
|
+
continue;
|
|
35
|
+
const uids = await withMailboxLock(client, f.path, () => client.search({ header: { "message-id": input.messageId } }, { uid: true }));
|
|
36
|
+
if (Array.isArray(uids) && uids.length > 0)
|
|
37
|
+
hits.push({ path: f.path, uids });
|
|
38
|
+
}
|
|
39
|
+
return Ok({ account: input.account, messageId: input.messageId, folders: hits });
|
|
40
|
+
}
|
|
41
|
+
catch (cause) {
|
|
42
|
+
return Err(imapError(input.account, "find_mailbox_folder failed", cause));
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
//# sourceMappingURL=findMailboxFolder.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"findMailboxFolder.js","sourceRoot":"","sources":["../../src/tools/findMailboxFolder.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAiB,SAAS,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AACzE,OAAO,EAAE,GAAG,EAAE,EAAE,EAAe,MAAM,qBAAqB,CAAC;AAC3D,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAEnD,OAAO,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AAErF,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC;KACpC,MAAM,CAAC;IACN,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IAC1B,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;CAC7B,CAAC;KACD,MAAM,EAAE,CAAC;AASZ,MAAM,CAAC,MAAM,iBAAiB,GAAG,KAAK,EACpC,IAAc,EACd,KAA6B,EACuB,EAAE;IACtD,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC;QAAE,OAAO,GAAG,CAAC,QAAQ,CAAC,YAAY,KAAK,CAAC,OAAO,GAAG,CAAC,CAAC,CAAC;IACjG,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IACrD,IAAI,OAAO,CAAC,GAAG,KAAK,KAAK;QAAE,OAAO,OAAO,CAAC;IAC1C,MAAM,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC;IAC7B,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,MAAM,MAAM,CAAC,IAAI,EAAE,CAAC;QACpC,MAAM,IAAI,GAAuC,EAAE,CAAC;QACpD,KAAK,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC;YACxB,MAAM,UAAU,GAAG,CAAC,CAAC,CAAC,UAAU,IAAI,IAAI,CAAkB,CAAC;YAC3D,IAAI,mBAAmB,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,mBAAmB,CAAC,UAAU,CAAC;gBAAE,SAAS;YAC7E,MAAM,IAAI,GAAG,MAAM,eAAe,CAAC,MAAM,EAAE,CAAC,CAAC,IAAI,EAAE,GAAG,EAAE,CACtD,MAAM,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,EAAE,YAAY,EAAE,KAAK,CAAC,SAAS,EAAE,EAAE,EAAE,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC,CAC5E,CAAC;YACF,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC;gBAAE,IAAI,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;QAChF,CAAC;QACD,OAAO,EAAE,CAAC,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,EAAE,SAAS,EAAE,KAAK,CAAC,SAAS,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;IACnF,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,GAAG,CAAC,SAAS,CAAC,KAAK,CAAC,OAAO,EAAE,4BAA4B,EAAE,KAAK,CAAC,CAAC,CAAC;IAC5E,CAAC;AACH,CAAC,CAAC"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP tool: get_email -- fetch one email by UID with BODY.PEEK.
|
|
3
|
+
*
|
|
4
|
+
* Live-IMAP. Defaults `markRead=false` so the IMAP `\Seen` flag is not
|
|
5
|
+
* touched. Format: "raw" returns the structured payload; "text" strips
|
|
6
|
+
* HTML; "stripped" additionally drops quoted replies and signatures.
|
|
7
|
+
*/
|
|
8
|
+
import { z } from "zod";
|
|
9
|
+
import { type AppError } from "../domain/errors.js";
|
|
10
|
+
import { type Result } from "../domain/result.js";
|
|
11
|
+
import type { ImapPool } from "../imap/pool.js";
|
|
12
|
+
import type { StoredEmailPayload } from "../store/payloadTypes.js";
|
|
13
|
+
export declare const getEmailInput: z.ZodObject<{
|
|
14
|
+
account: z.ZodString;
|
|
15
|
+
mailbox: z.ZodString;
|
|
16
|
+
uid: z.ZodNumber;
|
|
17
|
+
format: z.ZodDefault<z.ZodEnum<["raw", "text", "stripped"]>>;
|
|
18
|
+
maxLength: z.ZodOptional<z.ZodNumber>;
|
|
19
|
+
markRead: z.ZodDefault<z.ZodBoolean>;
|
|
20
|
+
}, "strict", z.ZodTypeAny, {
|
|
21
|
+
uid: number;
|
|
22
|
+
mailbox: string;
|
|
23
|
+
account: string;
|
|
24
|
+
format: "text" | "raw" | "stripped";
|
|
25
|
+
markRead: boolean;
|
|
26
|
+
maxLength?: number | undefined;
|
|
27
|
+
}, {
|
|
28
|
+
uid: number;
|
|
29
|
+
mailbox: string;
|
|
30
|
+
account: string;
|
|
31
|
+
format?: "text" | "raw" | "stripped" | undefined;
|
|
32
|
+
maxLength?: number | undefined;
|
|
33
|
+
markRead?: boolean | undefined;
|
|
34
|
+
}>;
|
|
35
|
+
export type GetEmailInput = z.infer<typeof getEmailInput>;
|
|
36
|
+
export type GetEmailResult = {
|
|
37
|
+
readonly email: StoredEmailPayload;
|
|
38
|
+
readonly bodyForDisplay: string | null;
|
|
39
|
+
readonly markedRead: boolean;
|
|
40
|
+
};
|
|
41
|
+
export declare const getEmail: (pool: ImapPool, input: GetEmailInput) => Promise<Result<AppError, GetEmailResult>>;
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP tool: get_email -- fetch one email by UID with BODY.PEEK.
|
|
3
|
+
*
|
|
4
|
+
* Live-IMAP. Defaults `markRead=false` so the IMAP `\Seen` flag is not
|
|
5
|
+
* touched. Format: "raw" returns the structured payload; "text" strips
|
|
6
|
+
* HTML; "stripped" additionally drops quoted replies and signatures.
|
|
7
|
+
*/
|
|
8
|
+
import { z } from "zod";
|
|
9
|
+
import { imapError, notFound } from "../domain/errors.js";
|
|
10
|
+
import { Err, Ok } from "../domain/result.js";
|
|
11
|
+
import { fetchOneByUid, withMailboxLock } from "../imap/fetch.js";
|
|
12
|
+
import { htmlToText, stripQuotedAndSignature, toStoredPayload } from "../imap/mapper.js";
|
|
13
|
+
export const getEmailInput = z
|
|
14
|
+
.object({
|
|
15
|
+
account: z.string().min(1),
|
|
16
|
+
mailbox: z.string().min(1),
|
|
17
|
+
uid: z.number().int().positive(),
|
|
18
|
+
format: z.enum(["raw", "text", "stripped"]).default("raw"),
|
|
19
|
+
maxLength: z.number().int().positive().optional(),
|
|
20
|
+
markRead: z.boolean().default(false),
|
|
21
|
+
})
|
|
22
|
+
.strict();
|
|
23
|
+
const buildDisplayBody = (payload, format, maxLength) => {
|
|
24
|
+
let text = payload.bodyText;
|
|
25
|
+
if (text === null && payload.bodyHtml !== null)
|
|
26
|
+
text = htmlToText(payload.bodyHtml);
|
|
27
|
+
if (text === null)
|
|
28
|
+
return null;
|
|
29
|
+
if (format === "stripped")
|
|
30
|
+
text = stripQuotedAndSignature(text);
|
|
31
|
+
if (maxLength !== undefined && text.length > maxLength)
|
|
32
|
+
text = text.slice(0, maxLength);
|
|
33
|
+
return text;
|
|
34
|
+
};
|
|
35
|
+
export const getEmail = async (pool, input) => {
|
|
36
|
+
if (!pool.accountIds.includes(input.account))
|
|
37
|
+
return Err(notFound(`account '${input.account}'`));
|
|
38
|
+
const clientR = await pool.forAccount(input.account);
|
|
39
|
+
if (clientR.tag === "Err")
|
|
40
|
+
return clientR;
|
|
41
|
+
const client = clientR.value;
|
|
42
|
+
try {
|
|
43
|
+
return await withMailboxLock(client, input.mailbox, async () => {
|
|
44
|
+
// Capture UIDVALIDITY so the produced payload has a stable externalId.
|
|
45
|
+
const status = await client.status(input.mailbox, { uidValidity: true });
|
|
46
|
+
const bundle = await fetchOneByUid(client, input.uid);
|
|
47
|
+
if (bundle === null) {
|
|
48
|
+
return Err(notFound(`message UID ${input.uid} in ${input.mailbox}`));
|
|
49
|
+
}
|
|
50
|
+
const payload = toStoredPayload(bundle.imapMessage, {
|
|
51
|
+
accountId: input.account,
|
|
52
|
+
mailbox: input.mailbox,
|
|
53
|
+
uidValidity: Number(status.uidValidity ?? 0),
|
|
54
|
+
fetchedAt: new Date(),
|
|
55
|
+
bodyText: bundle.bodyText,
|
|
56
|
+
bodyHtml: bundle.bodyHtml,
|
|
57
|
+
truncated: false,
|
|
58
|
+
});
|
|
59
|
+
const display = input.format === "raw"
|
|
60
|
+
? (payload.bodyText ?? (payload.bodyHtml !== null ? htmlToText(payload.bodyHtml) : null))
|
|
61
|
+
: buildDisplayBody(payload, input.format, input.maxLength);
|
|
62
|
+
let markedRead = false;
|
|
63
|
+
if (input.markRead === true) {
|
|
64
|
+
const ok = await client.messageFlagsAdd([input.uid], ["\\Seen"], { uid: true });
|
|
65
|
+
markedRead = ok === true;
|
|
66
|
+
}
|
|
67
|
+
return Ok({ email: payload, bodyForDisplay: display, markedRead });
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
catch (cause) {
|
|
71
|
+
return Err(imapError(input.account, "get_email failed", cause));
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
//# sourceMappingURL=getEmail.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"getEmail.js","sourceRoot":"","sources":["../../src/tools/getEmail.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP tool: get_emails -- bulk variant of get_email (max 20). One IMAP
|
|
3
|
+
* lock + one FETCH for the UID set. BODY.PEEK; never sets `\Seen`.
|
|
4
|
+
*/
|
|
5
|
+
import { z } from "zod";
|
|
6
|
+
import { type AppError } from "../domain/errors.js";
|
|
7
|
+
import { type Result } from "../domain/result.js";
|
|
8
|
+
import type { ImapPool } from "../imap/pool.js";
|
|
9
|
+
import type { StoredEmailPayload } from "../store/payloadTypes.js";
|
|
10
|
+
export declare const getEmailsInput: z.ZodObject<{
|
|
11
|
+
account: z.ZodString;
|
|
12
|
+
mailbox: z.ZodString;
|
|
13
|
+
uids: z.ZodArray<z.ZodNumber, "many">;
|
|
14
|
+
format: z.ZodDefault<z.ZodEnum<["raw", "text", "stripped"]>>;
|
|
15
|
+
maxLength: z.ZodOptional<z.ZodNumber>;
|
|
16
|
+
}, "strict", z.ZodTypeAny, {
|
|
17
|
+
mailbox: string;
|
|
18
|
+
account: string;
|
|
19
|
+
uids: number[];
|
|
20
|
+
format: "text" | "raw" | "stripped";
|
|
21
|
+
maxLength?: number | undefined;
|
|
22
|
+
}, {
|
|
23
|
+
mailbox: string;
|
|
24
|
+
account: string;
|
|
25
|
+
uids: number[];
|
|
26
|
+
format?: "text" | "raw" | "stripped" | undefined;
|
|
27
|
+
maxLength?: number | undefined;
|
|
28
|
+
}>;
|
|
29
|
+
export type GetEmailsInput = z.infer<typeof getEmailsInput>;
|
|
30
|
+
export type GetEmailsItem = {
|
|
31
|
+
readonly email: StoredEmailPayload;
|
|
32
|
+
readonly bodyForDisplay: string | null;
|
|
33
|
+
};
|
|
34
|
+
export type GetEmailsResult = {
|
|
35
|
+
readonly items: readonly GetEmailsItem[];
|
|
36
|
+
readonly missing: readonly number[];
|
|
37
|
+
};
|
|
38
|
+
export declare const getEmails: (pool: ImapPool, input: GetEmailsInput) => Promise<Result<AppError, GetEmailsResult>>;
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP tool: get_emails -- bulk variant of get_email (max 20). One IMAP
|
|
3
|
+
* lock + one FETCH for the UID set. BODY.PEEK; never sets `\Seen`.
|
|
4
|
+
*/
|
|
5
|
+
import { z } from "zod";
|
|
6
|
+
import { imapError, notFound } from "../domain/errors.js";
|
|
7
|
+
import { Err, Ok } from "../domain/result.js";
|
|
8
|
+
import { fetchEnvelopesUidRange, withMailboxLock } from "../imap/fetch.js";
|
|
9
|
+
import { htmlToText, stripQuotedAndSignature, toStoredPayload } from "../imap/mapper.js";
|
|
10
|
+
export const getEmailsInput = z
|
|
11
|
+
.object({
|
|
12
|
+
account: z.string().min(1),
|
|
13
|
+
mailbox: z.string().min(1),
|
|
14
|
+
uids: z.array(z.number().int().positive()).min(1).max(20),
|
|
15
|
+
format: z.enum(["raw", "text", "stripped"]).default("text"),
|
|
16
|
+
maxLength: z.number().int().positive().optional(),
|
|
17
|
+
})
|
|
18
|
+
.strict();
|
|
19
|
+
const display = (p, fmt, cap) => {
|
|
20
|
+
let txt = p.bodyText;
|
|
21
|
+
if (txt === null && p.bodyHtml !== null)
|
|
22
|
+
txt = htmlToText(p.bodyHtml);
|
|
23
|
+
if (txt === null)
|
|
24
|
+
return null;
|
|
25
|
+
if (fmt === "stripped")
|
|
26
|
+
txt = stripQuotedAndSignature(txt);
|
|
27
|
+
if (cap !== undefined && txt.length > cap)
|
|
28
|
+
txt = txt.slice(0, cap);
|
|
29
|
+
return txt;
|
|
30
|
+
};
|
|
31
|
+
export const getEmails = async (pool, input) => {
|
|
32
|
+
if (!pool.accountIds.includes(input.account))
|
|
33
|
+
return Err(notFound(`account '${input.account}'`));
|
|
34
|
+
const clientR = await pool.forAccount(input.account);
|
|
35
|
+
if (clientR.tag === "Err")
|
|
36
|
+
return clientR;
|
|
37
|
+
const client = clientR.value;
|
|
38
|
+
try {
|
|
39
|
+
return await withMailboxLock(client, input.mailbox, async () => {
|
|
40
|
+
const status = await client.status(input.mailbox, { uidValidity: true });
|
|
41
|
+
const wanted = new Set(input.uids);
|
|
42
|
+
const items = [];
|
|
43
|
+
const seen = new Set();
|
|
44
|
+
const minUid = Math.min(...input.uids);
|
|
45
|
+
const maxUid = Math.max(...input.uids);
|
|
46
|
+
for await (const env of fetchEnvelopesUidRange(client, minUid, maxUid)) {
|
|
47
|
+
if (!wanted.has(env.uid))
|
|
48
|
+
continue;
|
|
49
|
+
const payload = toStoredPayload(env, {
|
|
50
|
+
accountId: input.account,
|
|
51
|
+
mailbox: input.mailbox,
|
|
52
|
+
uidValidity: Number(status.uidValidity ?? 0),
|
|
53
|
+
fetchedAt: new Date(),
|
|
54
|
+
bodyText: null,
|
|
55
|
+
bodyHtml: null,
|
|
56
|
+
truncated: false,
|
|
57
|
+
});
|
|
58
|
+
items.push({
|
|
59
|
+
email: payload,
|
|
60
|
+
bodyForDisplay: display(payload, input.format, input.maxLength),
|
|
61
|
+
});
|
|
62
|
+
seen.add(env.uid);
|
|
63
|
+
}
|
|
64
|
+
const missing = input.uids.filter((u) => !seen.has(u));
|
|
65
|
+
return Ok({ items, missing });
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
catch (cause) {
|
|
69
|
+
return Err(imapError(input.account, "get_emails failed", cause));
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
//# sourceMappingURL=getEmails.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"getEmails.js","sourceRoot":"","sources":["../../src/tools/getEmails.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP tool: get_watcher_status -- in-memory status snapshot from the
|
|
3
|
+
* sync watcher. Read-only; no IMAP / Drive contact.
|
|
4
|
+
*/
|
|
5
|
+
import { z } from "zod";
|
|
6
|
+
import type { Watcher, WatcherStatus } from "../sync/watcher.js";
|
|
7
|
+
export declare const getWatcherStatusInput: z.ZodObject<{}, "strict", z.ZodTypeAny, {}, {}>;
|
|
8
|
+
export type GetWatcherStatusInput = z.infer<typeof getWatcherStatusInput>;
|
|
9
|
+
export declare const getWatcherStatus: (watcher: Watcher) => WatcherStatus;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP tool: get_watcher_status -- in-memory status snapshot from the
|
|
3
|
+
* sync watcher. Read-only; no IMAP / Drive contact.
|
|
4
|
+
*/
|
|
5
|
+
import { z } from "zod";
|
|
6
|
+
export const getWatcherStatusInput = z.object({}).strict();
|
|
7
|
+
export const getWatcherStatus = (watcher) => watcher.status();
|
|
8
|
+
//# sourceMappingURL=getWatcherStatus.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"getWatcherStatus.js","sourceRoot":"","sources":["../../src/tools/getWatcherStatus.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC;AAG3D,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,OAAgB,EAAiB,EAAE,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP tool: list_accounts -- enumerate the configured email accounts.
|
|
3
|
+
*
|
|
4
|
+
* Read-only and config-driven; does not contact IMAP. Always call this
|
|
5
|
+
* first to discover available account names for use with other tools.
|
|
6
|
+
*/
|
|
7
|
+
import { z } from "zod";
|
|
8
|
+
import type { Account } from "../config/schema.js";
|
|
9
|
+
export declare const listAccountsInput: z.ZodObject<{}, "strict", z.ZodTypeAny, {}, {}>;
|
|
10
|
+
export type ListAccountsInput = z.infer<typeof listAccountsInput>;
|
|
11
|
+
export type ListAccountsResult = {
|
|
12
|
+
readonly accounts: ReadonlyArray<{
|
|
13
|
+
readonly name: string;
|
|
14
|
+
readonly email: string;
|
|
15
|
+
readonly authType: "password" | "oauth";
|
|
16
|
+
readonly fullName: string;
|
|
17
|
+
}>;
|
|
18
|
+
};
|
|
19
|
+
export declare const listAccounts: (accounts: readonly Account[]) => ListAccountsResult;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP tool: list_accounts -- enumerate the configured email accounts.
|
|
3
|
+
*
|
|
4
|
+
* Read-only and config-driven; does not contact IMAP. Always call this
|
|
5
|
+
* first to discover available account names for use with other tools.
|
|
6
|
+
*/
|
|
7
|
+
import { z } from "zod";
|
|
8
|
+
import { isOAuthAccount } from "../config/schema.js";
|
|
9
|
+
export const listAccountsInput = z.object({}).strict();
|
|
10
|
+
export const listAccounts = (accounts) => ({
|
|
11
|
+
accounts: accounts.map((a) => ({
|
|
12
|
+
name: a.name,
|
|
13
|
+
email: a.email,
|
|
14
|
+
authType: isOAuthAccount(a) ? "oauth" : "password",
|
|
15
|
+
fullName: a.full_name ?? a.email,
|
|
16
|
+
})),
|
|
17
|
+
});
|
|
18
|
+
//# sourceMappingURL=listAccounts.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"listAccounts.js","sourceRoot":"","sources":["../../src/tools/listAccounts.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAErD,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC;AAYvD,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,QAA4B,EAAsB,EAAE,CAAC,CAAC;IACjF,QAAQ,EAAE,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QAC7B,IAAI,EAAE,CAAC,CAAC,IAAI;QACZ,KAAK,EAAE,CAAC,CAAC,KAAK;QACd,QAAQ,EAAE,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,UAAU;QAClD,QAAQ,EAAE,CAAC,CAAC,SAAS,IAAI,CAAC,CAAC,KAAK;KACjC,CAAC,CAAC;CACJ,CAAC,CAAC"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP tool: list_emails -- paginated metadata listing of a mailbox.
|
|
3
|
+
*
|
|
4
|
+
* Live-IMAP. Combines IMAP UID SEARCH (with optional filters) and
|
|
5
|
+
* envelope-only FETCH for matched UIDs. Pagination is offset-based:
|
|
6
|
+
* the first call returns the highest-UID page, subsequent calls pass
|
|
7
|
+
* the previous page's `nextCursor` (a UID).
|
|
8
|
+
*/
|
|
9
|
+
import { z } from "zod";
|
|
10
|
+
import { type AppError } from "../domain/errors.js";
|
|
11
|
+
import { type Result } from "../domain/result.js";
|
|
12
|
+
import type { ImapPool } from "../imap/pool.js";
|
|
13
|
+
export declare const listEmailsInput: z.ZodObject<{
|
|
14
|
+
account: z.ZodString;
|
|
15
|
+
mailbox: z.ZodString;
|
|
16
|
+
pageSize: z.ZodDefault<z.ZodNumber>;
|
|
17
|
+
cursor: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
|
|
18
|
+
unread: z.ZodOptional<z.ZodBoolean>;
|
|
19
|
+
flagged: z.ZodOptional<z.ZodBoolean>;
|
|
20
|
+
from: z.ZodOptional<z.ZodString>;
|
|
21
|
+
to: z.ZodOptional<z.ZodString>;
|
|
22
|
+
subject: z.ZodOptional<z.ZodString>;
|
|
23
|
+
since: z.ZodOptional<z.ZodString>;
|
|
24
|
+
}, "strict", z.ZodTypeAny, {
|
|
25
|
+
mailbox: string;
|
|
26
|
+
account: string;
|
|
27
|
+
pageSize: number;
|
|
28
|
+
cursor?: number | null | undefined;
|
|
29
|
+
unread?: boolean | undefined;
|
|
30
|
+
flagged?: boolean | undefined;
|
|
31
|
+
from?: string | undefined;
|
|
32
|
+
to?: string | undefined;
|
|
33
|
+
subject?: string | undefined;
|
|
34
|
+
since?: string | undefined;
|
|
35
|
+
}, {
|
|
36
|
+
mailbox: string;
|
|
37
|
+
account: string;
|
|
38
|
+
pageSize?: number | undefined;
|
|
39
|
+
cursor?: number | null | undefined;
|
|
40
|
+
unread?: boolean | undefined;
|
|
41
|
+
flagged?: boolean | undefined;
|
|
42
|
+
from?: string | undefined;
|
|
43
|
+
to?: string | undefined;
|
|
44
|
+
subject?: string | undefined;
|
|
45
|
+
since?: string | undefined;
|
|
46
|
+
}>;
|
|
47
|
+
export type ListEmailsInput = z.infer<typeof listEmailsInput>;
|
|
48
|
+
export type ListedEmail = {
|
|
49
|
+
readonly uid: number;
|
|
50
|
+
readonly messageId: string | null;
|
|
51
|
+
readonly subject: string;
|
|
52
|
+
readonly from: {
|
|
53
|
+
readonly name: string | null;
|
|
54
|
+
readonly address: string;
|
|
55
|
+
} | null;
|
|
56
|
+
readonly to: ReadonlyArray<{
|
|
57
|
+
readonly name: string | null;
|
|
58
|
+
readonly address: string;
|
|
59
|
+
}>;
|
|
60
|
+
readonly date: string;
|
|
61
|
+
readonly flags: readonly string[];
|
|
62
|
+
readonly hasAttachments: boolean;
|
|
63
|
+
};
|
|
64
|
+
export type ListEmailsResult = {
|
|
65
|
+
readonly account: string;
|
|
66
|
+
readonly mailbox: string;
|
|
67
|
+
readonly items: readonly ListedEmail[];
|
|
68
|
+
readonly nextCursor: number | null;
|
|
69
|
+
};
|
|
70
|
+
export declare const listEmails: (pool: ImapPool, input: ListEmailsInput) => Promise<Result<AppError, ListEmailsResult>>;
|