proton-mail-bridge-client 2.1.4 → 2.1.6
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.d.ts +4 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +95 -10
- package/dist/index.js.map +1 -1
- package/dist/services/simple-imap-service.d.ts.map +1 -1
- package/dist/services/simple-imap-service.js +16 -4
- package/dist/services/simple-imap-service.js.map +1 -1
- package/dist/services/smtp-service.d.ts.map +1 -1
- package/dist/services/smtp-service.js +29 -0
- package/dist/services/smtp-service.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -8,7 +8,7 @@ import { LocalIndexService } from "./services/local-index-service.js";
|
|
|
8
8
|
import { SimpleIMAPService } from "./services/simple-imap-service.js";
|
|
9
9
|
import { SMTPService } from "./services/smtp-service.js";
|
|
10
10
|
import { SnoozeService } from "./services/snooze-service.js";
|
|
11
|
-
import type { BulkOperationResult, DraftRecord, EmailDetail, ProtonMailConfig } from "./types/index.js";
|
|
11
|
+
import type { BulkOperationResult, DraftRecord, EmailDetail, ProtonMailConfig, SendEmailInput } from "./types/index.js";
|
|
12
12
|
import { AccountManager, type AccountBundle } from "./services/account-manager.js";
|
|
13
13
|
export declare const CORE_TOOL_NAMES: Set<string>;
|
|
14
14
|
export declare function withAudit<T>(auditService: AuditService, tool: string, input: Record<string, unknown>, operation: () => Promise<T>): Promise<T>;
|
|
@@ -65,6 +65,9 @@ export declare function redactDraftAttachmentsForListing(draft: DraftRecord): {
|
|
|
65
65
|
remoteDraft?: import("./types/index.js").RemoteDraftRef;
|
|
66
66
|
lastSendResult?: import("./types/index.js").DraftSendResult;
|
|
67
67
|
};
|
|
68
|
+
export declare function redactQueueRecordAttachments<T extends {
|
|
69
|
+
payload: SendEmailInput;
|
|
70
|
+
}>(record: T): T;
|
|
68
71
|
export declare function paginateMergedAccountResults<T>(sortedMerged: T[], offset: number, limit: number): {
|
|
69
72
|
page: T[];
|
|
70
73
|
hasMore: boolean;
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AASA,OAAO,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AAYnE,OAAO,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAC3D,OAAO,EAAE,qBAAqB,EAAE,MAAM,uCAAuC,CAAC;AAC9E,OAAO,EAAE,oBAAoB,EAAE,MAAM,sCAAsC,CAAC;AAC5E,OAAO,EAAE,iBAAiB,EAAE,MAAM,mCAAmC,CAAC;AACtE,OAAO,EAAE,iBAAiB,EAAE,MAAM,mCAAmC,CAAC;AACtE,OAAO,EAA2H,iBAAiB,EAA+B,MAAM,mCAAmC,CAAC;AAC5N,OAAO,EAAmC,WAAW,EAAE,MAAM,4BAA4B,CAAC;AAC1F,OAAO,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAE7D,OAAO,KAAK,EAMV,mBAAmB,EAEnB,WAAW,EAIX,WAAW,EAIX,gBAAgB,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -408,12 +408,13 @@ const TOOLS = [
|
|
|
408
408
|
},
|
|
409
409
|
{
|
|
410
410
|
name: "get_draft",
|
|
411
|
-
description: "Fetch the full content of a single locally saved draft by its draftId. Use to read or verify a draft before sending or updating. Prefer list_drafts to discover draftIds first. Does NOT fetch drafts from the Proton server — use list_remote_drafts for those.",
|
|
411
|
+
description: "Fetch the full content of a single locally saved draft by its draftId. Use to read or verify a draft before sending or updating. Prefer list_drafts to discover draftIds first. Does NOT fetch drafts from the Proton server — use list_remote_drafts for those. Attachments are metadata only (filename/contentType/size, no base64 content) by default — set includeAttachmentContent:true if you actually need the raw bytes back (e.g. to re-attach them elsewhere); a large attachment's base64 content can be hundreds of thousands of tokens.",
|
|
412
412
|
annotations: { readOnlyHint: true },
|
|
413
413
|
inputSchema: {
|
|
414
414
|
type: "object",
|
|
415
415
|
properties: {
|
|
416
416
|
draftId: { type: "string", description: "Draft id returned by create_draft, list_drafts, or a create_*_draft call." },
|
|
417
|
+
includeAttachmentContent: { type: "boolean", description: "Return each attachment's full base64 content instead of just its metadata. Off by default — see the tool description.", default: false },
|
|
417
418
|
},
|
|
418
419
|
required: ["draftId"],
|
|
419
420
|
},
|
|
@@ -2276,6 +2277,32 @@ export function redactDraftAttachmentsForListing(draft) {
|
|
|
2276
2277
|
})),
|
|
2277
2278
|
};
|
|
2278
2279
|
}
|
|
2280
|
+
// Same fix as redactDraftAttachmentsForListing, for list_scheduled_sends — a
|
|
2281
|
+
// queued send's payload carries the same full base64 EmailAttachmentInput
|
|
2282
|
+
// content (found live: ~955k tokens for a single 1 MiB attachment on ONE
|
|
2283
|
+
// record, canceled records included, and list_scheduled_sends has no filter
|
|
2284
|
+
// or cap any more than list_drafts did). No explicit return-type annotation
|
|
2285
|
+
// for the same reason as the function above.
|
|
2286
|
+
export function redactQueueRecordAttachments(record) {
|
|
2287
|
+
const attachments = record.payload.attachments;
|
|
2288
|
+
if (!attachments || attachments.length === 0) {
|
|
2289
|
+
return record;
|
|
2290
|
+
}
|
|
2291
|
+
return {
|
|
2292
|
+
...record,
|
|
2293
|
+
payload: {
|
|
2294
|
+
...record.payload,
|
|
2295
|
+
attachments: attachments.map((attachment) => ({
|
|
2296
|
+
filename: attachment.filename,
|
|
2297
|
+
contentType: attachment.contentType,
|
|
2298
|
+
cid: attachment.cid,
|
|
2299
|
+
contentDisposition: attachment.contentDisposition,
|
|
2300
|
+
content: "",
|
|
2301
|
+
size: Buffer.byteLength(attachment.content, "base64"),
|
|
2302
|
+
})),
|
|
2303
|
+
},
|
|
2304
|
+
};
|
|
2305
|
+
}
|
|
2279
2306
|
function draftSource(draft) {
|
|
2280
2307
|
return {
|
|
2281
2308
|
uri: buildDraftResourceUri(draft.id),
|
|
@@ -2414,10 +2441,24 @@ async function syncDraftToRemote(draftStore, smtpService, imapService, draft) {
|
|
|
2414
2441
|
isHtml: draft.isHtml,
|
|
2415
2442
|
priority: draft.priority,
|
|
2416
2443
|
replyTo: draft.replyTo,
|
|
2444
|
+
// Found live (external review): this never passed draft.from, so a draft
|
|
2445
|
+
// saved under an alias (e.g. alias@example.com) previewed in the remote
|
|
2446
|
+
// Drafts mailbox under the primary address instead — the remote preview
|
|
2447
|
+
// and the eventual send_draft/schedule_draft sender didn't match.
|
|
2448
|
+
from: draft.from,
|
|
2417
2449
|
inReplyTo: draft.inReplyTo,
|
|
2418
2450
|
references: draft.references,
|
|
2419
2451
|
messageId: draft.draftMessageId,
|
|
2420
2452
|
attachments: draft.attachments,
|
|
2453
|
+
// Same reasoning as send_draft's identical appendSignature: false — draft
|
|
2454
|
+
// content is already finalized and reviewed by the time it's synced here.
|
|
2455
|
+
// Found live (external review): this used to omit appendSignature, so the
|
|
2456
|
+
// remote preview auto-added PROTONMAIL_SIGNATURE while send_draft/
|
|
2457
|
+
// schedule_draft never did — the actually-sent message either lacked the
|
|
2458
|
+
// signature the remote preview showed, or, if the caller had also typed a
|
|
2459
|
+
// signature into the draft body themselves, got it appended a second time
|
|
2460
|
+
// on every remote sync.
|
|
2461
|
+
appendSignature: false,
|
|
2421
2462
|
});
|
|
2422
2463
|
const remoteDraft = await imapService.upsertRemoteDraft({
|
|
2423
2464
|
raw,
|
|
@@ -3561,9 +3602,14 @@ export function createServer(config, options = {}) {
|
|
|
3561
3602
|
// item's id with its owning account's slug — mirrors the read-tool fan-out
|
|
3562
3603
|
// pattern (get_emails etc.). Single-account guard keeps byte-identical output
|
|
3563
3604
|
// for the common case.
|
|
3605
|
+
// Each record's payload carries the same full base64 attachment content as
|
|
3606
|
+
// a draft — see redactQueueRecordAttachments' comment. Redacted for every
|
|
3607
|
+
// record regardless of status (including canceled ones, which otherwise
|
|
3608
|
+
// stayed just as bloated once queued).
|
|
3564
3609
|
if (accountManager.all().length === 1) {
|
|
3565
3610
|
const all = await withAudit(auditService, name, args, async () => deliveryQueueService.list());
|
|
3566
|
-
const filtered = statusFilter ? all.filter((item) => item.status === statusFilter) : all
|
|
3611
|
+
const filtered = (statusFilter ? all.filter((item) => item.status === statusFilter) : all)
|
|
3612
|
+
.map(redactQueueRecordAttachments);
|
|
3567
3613
|
return createTextResult(filtered);
|
|
3568
3614
|
}
|
|
3569
3615
|
const perAccount = await withAudit(auditService, name, args, async () => Promise.all(accountManager.all().map(async (bundle) => ({
|
|
@@ -3571,7 +3617,8 @@ export function createServer(config, options = {}) {
|
|
|
3571
3617
|
items: await bundle.deliveryQueueService.list(),
|
|
3572
3618
|
}))));
|
|
3573
3619
|
const tagged = perAccount.flatMap(({ bundle, items }) => items.map((item) => ({ ...item, id: withAccountPrefix(responseSlug(bundle), item.id) })));
|
|
3574
|
-
const filtered = statusFilter ? tagged.filter((item) => item.status === statusFilter) : tagged
|
|
3620
|
+
const filtered = (statusFilter ? tagged.filter((item) => item.status === statusFilter) : tagged)
|
|
3621
|
+
.map(redactQueueRecordAttachments);
|
|
3575
3622
|
return createTextResult(filtered);
|
|
3576
3623
|
}
|
|
3577
3624
|
case "get_unsubscribe_info": {
|
|
@@ -3993,7 +4040,10 @@ export function createServer(config, options = {}) {
|
|
|
3993
4040
|
: undefined);
|
|
3994
4041
|
return presentDraft(createDraftBundle, remoteSync ? { ...synced.draft, remoteSync } : synced.draft);
|
|
3995
4042
|
});
|
|
3996
|
-
|
|
4043
|
+
// Same fix as update_draft's identical bloat — see its comment. The
|
|
4044
|
+
// caller already knows what it attached; get_draft is the "let me see
|
|
4045
|
+
// the full attachment content" call, not this one.
|
|
4046
|
+
return createTextResult(redactDraftAttachmentsForListing(result), false, [
|
|
3997
4047
|
draftSource(result),
|
|
3998
4048
|
...(result.remoteDraft?.emailId
|
|
3999
4049
|
? [
|
|
@@ -4046,6 +4096,14 @@ export function createServer(config, options = {}) {
|
|
|
4046
4096
|
subject: prefixedSubject(detail.subject, "Re:"),
|
|
4047
4097
|
body: buildReplyText(detail, body),
|
|
4048
4098
|
isHtml,
|
|
4099
|
+
// Found live (external review): a `from` naming a real alias NOT
|
|
4100
|
+
// itself a separately-configured account (e.g. a genuine alias
|
|
4101
|
+
// reachable only via header override, same as send_email's own
|
|
4102
|
+
// fallback) picked the right draftStore bundle above but never
|
|
4103
|
+
// actually stored the address on the draft — draft.from came back
|
|
4104
|
+
// undefined, so a later send_draft used the account's default
|
|
4105
|
+
// sender instead of the alias the caller asked for.
|
|
4106
|
+
from: optionalString(args, "from"),
|
|
4049
4107
|
inReplyTo: detail.messageId,
|
|
4050
4108
|
references: detail.messageId ? [detail.messageId] : undefined,
|
|
4051
4109
|
attachments,
|
|
@@ -4067,7 +4125,8 @@ export function createServer(config, options = {}) {
|
|
|
4067
4125
|
: undefined);
|
|
4068
4126
|
return presentDraft(createReplyDraftBundle, remoteSync ? { ...synced.draft, remoteSync } : synced.draft);
|
|
4069
4127
|
});
|
|
4070
|
-
|
|
4128
|
+
// Same fix as create_draft/update_draft's identical bloat — see their comments.
|
|
4129
|
+
return createTextResult(redactDraftAttachmentsForListing(result), false, [
|
|
4071
4130
|
draftSource(result),
|
|
4072
4131
|
emailSource(detail),
|
|
4073
4132
|
...(result.remoteDraft?.emailId
|
|
@@ -4120,6 +4179,8 @@ export function createServer(config, options = {}) {
|
|
|
4120
4179
|
subject: prefixedSubject(detail.subject, "Fwd:"),
|
|
4121
4180
|
body: buildForwardText(detail, optionalString(args, "body")),
|
|
4122
4181
|
isHtml: normalizeBoolean(args.isHtml, false),
|
|
4182
|
+
// Same fix as create_reply_draft — see its comment.
|
|
4183
|
+
from: optionalString(args, "from"),
|
|
4123
4184
|
attachments,
|
|
4124
4185
|
sourceEmailId: detail.id,
|
|
4125
4186
|
sourceMessageId: detail.messageId,
|
|
@@ -4139,7 +4200,8 @@ export function createServer(config, options = {}) {
|
|
|
4139
4200
|
: undefined);
|
|
4140
4201
|
return presentDraft(createForwardDraftBundle, remoteSync ? { ...synced.draft, remoteSync } : synced.draft);
|
|
4141
4202
|
});
|
|
4142
|
-
|
|
4203
|
+
// Same fix as create_draft/update_draft's identical bloat — see their comments.
|
|
4204
|
+
return createTextResult(redactDraftAttachmentsForListing(result), false, [
|
|
4143
4205
|
draftSource(result),
|
|
4144
4206
|
emailSource(detail),
|
|
4145
4207
|
...(result.remoteDraft?.emailId
|
|
@@ -4172,7 +4234,16 @@ export function createServer(config, options = {}) {
|
|
|
4172
4234
|
case "get_draft": {
|
|
4173
4235
|
const { bundle: getDraftBundle, rest: getDraftIdRest } = resolveAccountForDraftId(requireString(args, "draftId"));
|
|
4174
4236
|
const draft = presentDraft(getDraftBundle, await getDraftBundle.draftStore.getDraft(getDraftIdRest));
|
|
4175
|
-
|
|
4237
|
+
// Found live (external review): this always echoed every attachment's
|
|
4238
|
+
// full base64 content — ~955k tokens for a single 1 MiB attachment,
|
|
4239
|
+
// serialized twice by createTextResult on top of that. Metadata only by
|
|
4240
|
+
// default now (same redaction as list_drafts/update_draft/create_draft),
|
|
4241
|
+
// with an explicit opt-in for the rare case the caller actually needs
|
|
4242
|
+
// the raw bytes back.
|
|
4243
|
+
const draftResponse = normalizeBoolean(args.includeAttachmentContent, false)
|
|
4244
|
+
? draft
|
|
4245
|
+
: redactDraftAttachmentsForListing(draft);
|
|
4246
|
+
return createTextResult(draftResponse, false, [
|
|
4176
4247
|
draftSource(draft),
|
|
4177
4248
|
...(draft.remoteDraft?.emailId
|
|
4178
4249
|
? [
|
|
@@ -4265,7 +4336,8 @@ export function createServer(config, options = {}) {
|
|
|
4265
4336
|
const draft = await syncDraftBundle.draftStore.getDraft(syncDraftIdRest);
|
|
4266
4337
|
const synced = await withAudit(auditService, name, args, async () => syncDraftToRemote(syncDraftBundle.draftStore, syncDraftBundle.smtpService, syncDraftBundle.imapService, draft));
|
|
4267
4338
|
const presentedSynced = presentDraft(syncDraftBundle, synced.draft);
|
|
4268
|
-
|
|
4339
|
+
// Same fix as create_draft/update_draft's identical bloat — see their comments.
|
|
4340
|
+
return createTextResult({ ...redactDraftAttachmentsForListing(presentedSynced), remoteSync: synced.remoteSync }, false, [
|
|
4269
4341
|
draftSource(presentedSynced),
|
|
4270
4342
|
...(presentedSynced.remoteDraft?.emailId
|
|
4271
4343
|
? [
|
|
@@ -4592,8 +4664,18 @@ export function createServer(config, options = {}) {
|
|
|
4592
4664
|
}));
|
|
4593
4665
|
const taggedEmails = perAccount.flatMap(({ bundle, result }) => result.emails.map((email) => ({ ...email, id: withAccountPrefix(accountSlugForTag(bundle, primarySlug), email.id) })));
|
|
4594
4666
|
const mergedAll = sortByDateDesc(taggedEmails, (email) => email.internalDate || email.date);
|
|
4595
|
-
const { page: merged
|
|
4667
|
+
const { page: merged } = paginateMergedAccountResults(mergedAll, requestedOffset, effectiveLimit);
|
|
4596
4668
|
const total = perAccount.reduce((sum, { result }) => sum + result.total, 0);
|
|
4669
|
+
// Found live (external review): paginateMergedAccountResults' own hasMore
|
|
4670
|
+
// only looks at what was actually FETCHED (mergedAll.length, capped at
|
|
4671
|
+
// perAccountFetchLimit per account) — with a lopsided distribution (e.g.
|
|
4672
|
+
// 300 messages in one account, 0 in another) and a small page near the
|
|
4673
|
+
// start, mergedAll.length can equal requestedOffset+limit exactly even
|
|
4674
|
+
// though the account's real total is far larger, reporting hasMore:false
|
|
4675
|
+
// while 275 more messages exist. `total` above is each account's real,
|
|
4676
|
+
// authoritative IMAP mailbox count (not bounded by what we fetched), so
|
|
4677
|
+
// it's the correct source for this instead.
|
|
4678
|
+
const hasMore = total > requestedOffset + effectiveLimit;
|
|
4597
4679
|
return createTextResult({
|
|
4598
4680
|
folder: getEmailsInput.folder?.trim() || "INBOX",
|
|
4599
4681
|
total,
|
|
@@ -6430,6 +6512,8 @@ export function createServer(config, options = {}) {
|
|
|
6430
6512
|
subject: prefixedSubject(detail.subject, "Re:"),
|
|
6431
6513
|
body: buildReplyText(detail, body),
|
|
6432
6514
|
isHtml,
|
|
6515
|
+
// Same fix as create_reply_draft — see its comment.
|
|
6516
|
+
from: optionalString(args, "from"),
|
|
6433
6517
|
inReplyTo: detail.messageId,
|
|
6434
6518
|
references: detail.messageId ? [detail.messageId] : undefined,
|
|
6435
6519
|
attachments,
|
|
@@ -6452,7 +6536,8 @@ export function createServer(config, options = {}) {
|
|
|
6452
6536
|
const presented = presentDraft(createThreadReplyDraftBundle, remoteSync ? { ...synced.draft, remoteSync } : synced.draft);
|
|
6453
6537
|
return { ...presented, threadId: thread.id };
|
|
6454
6538
|
});
|
|
6455
|
-
|
|
6539
|
+
// Same fix as create_draft/update_draft's identical bloat — see their comments.
|
|
6540
|
+
return createTextResult(redactDraftAttachmentsForListing(result), false, [
|
|
6456
6541
|
draftSource(result),
|
|
6457
6542
|
threadSource(thread),
|
|
6458
6543
|
emailSource(detail),
|