proton-mail-bridge-client 2.1.4 → 2.1.5

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 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;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
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,EAChB,cAAc,EAGf,MAAM,kBAAkB,CAAC;AAmB1B,OAAO,EAAE,cAAc,EAAE,KAAK,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAorDnF,eAAO,MAAM,eAAe,aAyB1B,CAAC;AAgGH,wBAAsB,SAAS,CAAC,CAAC,EAC/B,YAAY,EAAE,YAAY,EAC1B,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9B,SAAS,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAC1B,OAAO,CAAC,CAAC,CAAC,CAwBZ;AAmED,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAK3G;AAKD,wBAAgB,0BAA0B,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAI1G;AASD,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAa9E;AAED,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,WAAW,GAAG;IAAE,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,CAS7F;AAuLD,wBAAgB,cAAc,CAAC,MAAM,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAW5E;AAED,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,WAAW,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAe/E;AAWD,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,WAAW,EACnB,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,OAAO,GAChB;IAAE,EAAE,EAAE,MAAM,EAAE,CAAC;IAAC,EAAE,EAAE,MAAM,EAAE,CAAA;CAAE,CAyBhC;AA6ED,wBAAgB,aAAa,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,GAAG,SAAS,EAAE,KAAK,EAAE,CAAC,GAAG,CAAC,CA4CtE;AAcD,wBAAgB,gCAAgC,CAAC,KAAK,EAAE,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAYlE;AAQD,wBAAgB,4BAA4B,CAAC,CAAC,SAAS;IAAE,OAAO,EAAE,cAAc,CAAA;CAAE,EAAE,MAAM,EAAE,CAAC,KAmB5F;AA8WD,wBAAgB,4BAA4B,CAAC,CAAC,EAAE,YAAY,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG;IAAE,IAAI,EAAE,CAAC,EAAE,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,CAKjI;AA8PD,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAEzE;AAED,wBAAgB,mBAAmB,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI,CAOzE;AAED,UAAU,mBAAmB;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;CACf;AASD,wBAAgB,uBAAuB,CACrC,QAAQ,EAAE,MAAM,EAAE,GAAG,SAAS,EAC9B,MAAM,EAAE,MAAM,EACd,kBAAkB,CAAC,EAAE,MAAM,GAC1B,mBAAmB,EAAE,CA8CvB;AAED,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,mBAAmB,EAC3B,gBAAgB,EAAE,mBAAmB,EAAE,GACtC,mBAAmB,CAmBrB;AAWD,wBAAgB,sBAAsB,CACpC,cAAc,EAAE,cAAc,EAC9B,QAAQ,EAAE,MAAM,EAAE,GACjB,GAAG,CAAC,MAAM,GAAG,SAAS,EAAE;IAAE,MAAM,EAAE,aAAa,CAAC;IAAC,OAAO,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC,CAYvE;AAOD,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,mBAAmB,EAAE,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,mBAAmB,CAQ3G;AAED,wBAAgB,cAAc,CAAC,QAAQ,EAAE,mBAAmB,EAAE,EAAE,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,mBAAmB,EAAE,CAK/G;AAID,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,mBAAmB,EAAE,GAAG,mBAAmB,CASpF;AAsQD,wBAAgB,kBAAkB,IAAI,gBAAgB,CAkGrD;AAED,wBAAgB,YAAY,CAC1B,MAAM,EAAE,gBAAgB,EACxB,OAAO,GAAE;IACP,mBAAmB,CAAC,EAAE,OAAO,CAAC;CAC1B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAysIP;AAED,wBAAsB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAmE1C"}
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
- return createTextResult(result, false, [
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
  ? [
@@ -4067,7 +4117,8 @@ export function createServer(config, options = {}) {
4067
4117
  : undefined);
4068
4118
  return presentDraft(createReplyDraftBundle, remoteSync ? { ...synced.draft, remoteSync } : synced.draft);
4069
4119
  });
4070
- return createTextResult(result, false, [
4120
+ // Same fix as create_draft/update_draft's identical bloat — see their comments.
4121
+ return createTextResult(redactDraftAttachmentsForListing(result), false, [
4071
4122
  draftSource(result),
4072
4123
  emailSource(detail),
4073
4124
  ...(result.remoteDraft?.emailId
@@ -4139,7 +4190,8 @@ export function createServer(config, options = {}) {
4139
4190
  : undefined);
4140
4191
  return presentDraft(createForwardDraftBundle, remoteSync ? { ...synced.draft, remoteSync } : synced.draft);
4141
4192
  });
4142
- return createTextResult(result, false, [
4193
+ // Same fix as create_draft/update_draft's identical bloat — see their comments.
4194
+ return createTextResult(redactDraftAttachmentsForListing(result), false, [
4143
4195
  draftSource(result),
4144
4196
  emailSource(detail),
4145
4197
  ...(result.remoteDraft?.emailId
@@ -4172,7 +4224,16 @@ export function createServer(config, options = {}) {
4172
4224
  case "get_draft": {
4173
4225
  const { bundle: getDraftBundle, rest: getDraftIdRest } = resolveAccountForDraftId(requireString(args, "draftId"));
4174
4226
  const draft = presentDraft(getDraftBundle, await getDraftBundle.draftStore.getDraft(getDraftIdRest));
4175
- return createTextResult(draft, false, [
4227
+ // Found live (external review): this always echoed every attachment's
4228
+ // full base64 content — ~955k tokens for a single 1 MiB attachment,
4229
+ // serialized twice by createTextResult on top of that. Metadata only by
4230
+ // default now (same redaction as list_drafts/update_draft/create_draft),
4231
+ // with an explicit opt-in for the rare case the caller actually needs
4232
+ // the raw bytes back.
4233
+ const draftResponse = normalizeBoolean(args.includeAttachmentContent, false)
4234
+ ? draft
4235
+ : redactDraftAttachmentsForListing(draft);
4236
+ return createTextResult(draftResponse, false, [
4176
4237
  draftSource(draft),
4177
4238
  ...(draft.remoteDraft?.emailId
4178
4239
  ? [
@@ -4265,7 +4326,8 @@ export function createServer(config, options = {}) {
4265
4326
  const draft = await syncDraftBundle.draftStore.getDraft(syncDraftIdRest);
4266
4327
  const synced = await withAudit(auditService, name, args, async () => syncDraftToRemote(syncDraftBundle.draftStore, syncDraftBundle.smtpService, syncDraftBundle.imapService, draft));
4267
4328
  const presentedSynced = presentDraft(syncDraftBundle, synced.draft);
4268
- return createTextResult({ ...presentedSynced, remoteSync: synced.remoteSync }, false, [
4329
+ // Same fix as create_draft/update_draft's identical bloat — see their comments.
4330
+ return createTextResult({ ...redactDraftAttachmentsForListing(presentedSynced), remoteSync: synced.remoteSync }, false, [
4269
4331
  draftSource(presentedSynced),
4270
4332
  ...(presentedSynced.remoteDraft?.emailId
4271
4333
  ? [
@@ -6452,7 +6514,8 @@ export function createServer(config, options = {}) {
6452
6514
  const presented = presentDraft(createThreadReplyDraftBundle, remoteSync ? { ...synced.draft, remoteSync } : synced.draft);
6453
6515
  return { ...presented, threadId: thread.id };
6454
6516
  });
6455
- return createTextResult(result, false, [
6517
+ // Same fix as create_draft/update_draft's identical bloat — see their comments.
6518
+ return createTextResult(redactDraftAttachmentsForListing(result), false, [
6456
6519
  draftSource(result),
6457
6520
  threadSource(thread),
6458
6521
  emailSource(detail),