@rubytech/create-maxy-code 0.1.359 → 0.1.360

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.
Files changed (43) hide show
  1. package/package.json +1 -1
  2. package/payload/platform/plugins/browser/PLUGIN.md +1 -1
  3. package/payload/platform/plugins/email/mcp/dist/__tests__/source-fetch-efficiency.test.d.ts +2 -0
  4. package/payload/platform/plugins/email/mcp/dist/__tests__/source-fetch-efficiency.test.d.ts.map +1 -0
  5. package/payload/platform/plugins/email/mcp/dist/__tests__/source-fetch-efficiency.test.js +142 -0
  6. package/payload/platform/plugins/email/mcp/dist/__tests__/source-fetch-efficiency.test.js.map +1 -0
  7. package/payload/platform/plugins/email/mcp/dist/lib/imap.d.ts +0 -5
  8. package/payload/platform/plugins/email/mcp/dist/lib/imap.d.ts.map +1 -1
  9. package/payload/platform/plugins/email/mcp/dist/lib/imap.js +120 -94
  10. package/payload/platform/plugins/email/mcp/dist/lib/imap.js.map +1 -1
  11. package/payload/platform/scripts/__tests__/vnc-cdp-liveness.test.sh +222 -0
  12. package/payload/platform/scripts/rss-sampler.sh +16 -0
  13. package/payload/platform/scripts/vnc.sh +117 -3
  14. package/payload/platform/services/claude-session-manager/dist/systemd-scope.d.ts +0 -4
  15. package/payload/platform/services/claude-session-manager/dist/systemd-scope.d.ts.map +1 -1
  16. package/payload/platform/services/claude-session-manager/dist/systemd-scope.js +0 -15
  17. package/payload/platform/services/claude-session-manager/dist/systemd-scope.js.map +1 -1
  18. package/payload/server/public/assets/{AdminLoginScreens-tHyAPNnQ.js → AdminLoginScreens-FufN0KIm.js} +1 -1
  19. package/payload/server/public/assets/{AdminShell-Ce9izNVZ.js → AdminShell-CmFCbj38.js} +1 -1
  20. package/payload/server/public/assets/{Checkbox-Cq6SJJlX.js → Checkbox-njajXf-b.js} +1 -1
  21. package/payload/server/public/assets/OperatorConversations-BqudLZH5.css +1 -0
  22. package/payload/server/public/assets/{admin-D9iMgdbN.js → admin-DYOYaRcc.js} +1 -1
  23. package/payload/server/public/assets/{browser-CZWi0EAP.js → browser-CUwGN38H.js} +1 -1
  24. package/payload/server/public/assets/{calendar-DUAh-_kx.js → calendar-HonT_eBL.js} +1 -1
  25. package/payload/server/public/assets/chat-B-sCk0kO.js +1 -0
  26. package/payload/server/public/assets/{data-CoOcAR_2.js → data-vEYM-aPa.js} +1 -1
  27. package/payload/server/public/assets/{graph-Dc_votDd.js → graph-BLUtXXda.js} +1 -1
  28. package/payload/server/public/assets/{graph-labels-jqagxwhW.js → graph-labels-tUzvK8mv.js} +1 -1
  29. package/payload/server/public/assets/{operator-KYXcuQ4Y.js → operator-BLEBOkrQ.js} +1 -1
  30. package/payload/server/public/assets/{page-Cfsv97nq.js → page-CcnJY-yB.js} +1 -1
  31. package/payload/server/public/assets/{public-49guEjCh.js → public-B8GW-fZg.js} +1 -1
  32. package/payload/server/public/assets/{rotate-ccw-CyR5o3Nq.js → rotate-ccw-BA0MN5YR.js} +1 -1
  33. package/payload/server/public/browser.html +4 -4
  34. package/payload/server/public/calendar.html +4 -4
  35. package/payload/server/public/chat.html +6 -6
  36. package/payload/server/public/data.html +4 -4
  37. package/payload/server/public/graph.html +7 -7
  38. package/payload/server/public/index.html +6 -6
  39. package/payload/server/public/operator.html +8 -8
  40. package/payload/server/public/public.html +6 -6
  41. package/payload/server/public/assets/OperatorConversations-BERW_hUa.css +0 -1
  42. package/payload/server/public/assets/chat-DHuibPfc.js +0 -1
  43. /package/payload/server/public/assets/{OperatorConversations-m2lz6Ss7.js → OperatorConversations-B9Vx84BF.js} +0 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rubytech/create-maxy-code",
3
- "version": "0.1.359",
3
+ "version": "0.1.360",
4
4
  "description": "Install Maxy — AI for Productive People",
5
5
  "bin": {
6
6
  "create-maxy-code": "./dist/index.js"
@@ -111,4 +111,4 @@ All tools are admin-allowlisted; none are exposed to public chat.
111
111
 
112
112
  ## Observability
113
113
 
114
- A successful render emits `[browser-render] url=… rendered=true domBytes=…` on the server's stderr (captured by the mcp-spawn-tee log). Every other tool returns a structured outcome: `ok`, or one of `cdp-unreachable`, `session-lost`, `selector-not-found`, `option-not-found`, `wait-timeout`, `navigate-failed`, `load-timeout`, `evaluate-failed`, `command-timeout`, `pdf-failed`, `screenshot-failed`, `unsupported-key`. On a device with no running Chromium (e.g. a laptop native-display install with no VNC browser) the tools return `cdp-unreachable` rather than hanging.
114
+ A successful render emits `[browser-render] url=… rendered=true domBytes=…` on the server's stderr (captured by the mcp-spawn-tee log). Every other tool returns a structured outcome: `ok`, or one of `cdp-unreachable`, `session-lost`, `selector-not-found`, `option-not-found`, `wait-timeout`, `navigate-failed`, `load-timeout`, `evaluate-failed`, `command-timeout`, `pdf-failed`, `screenshot-failed`, `unsupported-key`. On a device with no running Chromium (e.g. a laptop native-display install with no VNC browser) the tools return `cdp-unreachable` rather than hanging. In virtual-display mode a Chromium that dies while the VNC display stays up is self-healing: the brand's standing CDP-liveness check (run each `rss-sampler` cycle via `vnc.sh cdp-liveness`) relaunches it and logs `[vnc] op=cdp-liveness … reachable=<bool>` plus `[vnc] op=chromium-respawn … outcome=<ready|failed>` to the service journal, so `cdp-unreachable` is transient (recovered within the check interval, bounded against hot-looping an unlaunchable browser) rather than dead-until-restart. Native-display installs launch Chromium on-demand, so a `cdp-unreachable` there clears on the next browser call.
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=source-fetch-efficiency.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"source-fetch-efficiency.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/source-fetch-efficiency.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,142 @@
1
+ import { beforeEach, describe, expect, it, vi } from "vitest";
2
+ const fetchCalls = [];
3
+ let connectCount = 0;
4
+ let inbox = [];
5
+ function envelopeOf(m) {
6
+ return {
7
+ from: [{ address: m.from, name: null }],
8
+ to: [{ address: m.to }],
9
+ cc: [],
10
+ subject: m.subject,
11
+ date: new Date("2026-01-01T00:00:00Z"),
12
+ messageId: `<${m.uid}@x>`,
13
+ inReplyTo: null,
14
+ };
15
+ }
16
+ function sourceOf(m) {
17
+ return Buffer.from([`From: ${m.from}`, `To: ${m.to}`, `Subject: ${m.subject}`, "", `body-${m.uid}`, ""].join("\r\n"));
18
+ }
19
+ function rowFor(uid, fields) {
20
+ const m = inbox.find((x) => x.uid === uid);
21
+ if (!m)
22
+ return null;
23
+ const row = { uid };
24
+ if (fields.envelope)
25
+ row.envelope = envelopeOf(m);
26
+ if (fields.bodyStructure)
27
+ row.bodyStructure = { type: "text/plain" };
28
+ if (fields.source)
29
+ row.source = sourceOf(m);
30
+ return row;
31
+ }
32
+ const mockClient = {
33
+ connect: vi.fn(async () => {
34
+ connectCount++;
35
+ }),
36
+ list: vi.fn(async () => [
37
+ { path: "INBOX" },
38
+ { path: "Sent", specialUse: "\\Sent" },
39
+ ]),
40
+ getMailboxLock: vi.fn(async () => ({ release: vi.fn() })),
41
+ search: vi.fn(async () => inbox.map((m) => m.uid)),
42
+ // async generator over the requested UID range, honouring the field set.
43
+ fetch: vi.fn(function (range, fields) {
44
+ fetchCalls.push({ range, fields });
45
+ const uids = range.split(",").map((s) => Number(s.trim()));
46
+ async function* gen() {
47
+ for (const uid of uids) {
48
+ const row = rowFor(uid, fields);
49
+ if (row)
50
+ yield row;
51
+ }
52
+ }
53
+ return gen();
54
+ }),
55
+ fetchOne: vi.fn(async (range, fields) => {
56
+ fetchCalls.push({ range, fields });
57
+ return rowFor(Number(range), fields);
58
+ }),
59
+ logout: vi.fn(async () => { }),
60
+ close: vi.fn(() => { }),
61
+ };
62
+ vi.mock("imapflow", () => ({
63
+ ImapFlow: function ImapFlow() {
64
+ return mockClient;
65
+ },
66
+ }));
67
+ import { fetchFullBody, fetchRecent, searchMessages } from "../lib/imap.js";
68
+ const config = {
69
+ email: "agent@example.com",
70
+ imapHost: "imap.example.com",
71
+ imapPort: 993,
72
+ imapSecurity: "tls",
73
+ };
74
+ beforeEach(() => {
75
+ vi.clearAllMocks();
76
+ fetchCalls.length = 0;
77
+ connectCount = 0;
78
+ inbox = [];
79
+ });
80
+ describe("Task 1180 — message_id full-body read uses one connection", () => {
81
+ it("opens a single IMAP connection for a message_id target", async () => {
82
+ inbox = [{ uid: 10, to: "agent@example.com", subject: "Hi", from: "a@x.com" }];
83
+ // search by message-id header returns the matching uid
84
+ mockClient.search.mockResolvedValue([10]);
85
+ const full = await fetchFullBody(config, "pw", { messageId: "<10@x>" });
86
+ expect(full?.body).toContain("body-10");
87
+ expect(connectCount).toBe(1);
88
+ });
89
+ });
90
+ describe("Task 1180 — list/search fetch source only for displayed messages", () => {
91
+ it("fetchRecent second-pass source fetch covers only the displayed UID set", async () => {
92
+ // 9 messages; recipient filter keeps only those addressed to keep@x.com.
93
+ // limit 2 + TO over-fetch ×3 => window of 6 newest UIDs (uids 4..9).
94
+ inbox = [
95
+ { uid: 1, to: "keep@x.com", subject: "s1", from: "a@x.com" },
96
+ { uid: 2, to: "other@x.com", subject: "s2", from: "a@x.com" },
97
+ { uid: 3, to: "keep@x.com", subject: "s3", from: "a@x.com" },
98
+ { uid: 4, to: "other@x.com", subject: "s4", from: "a@x.com" },
99
+ { uid: 5, to: "keep@x.com", subject: "s5", from: "a@x.com" },
100
+ { uid: 6, to: "other@x.com", subject: "s6", from: "a@x.com" },
101
+ { uid: 7, to: "keep@x.com", subject: "s7", from: "a@x.com" },
102
+ { uid: 8, to: "other@x.com", subject: "s8", from: "a@x.com" },
103
+ { uid: 9, to: "keep@x.com", subject: "s9", from: "a@x.com" },
104
+ ];
105
+ mockClient.search.mockResolvedValue(inbox.map((m) => m.uid));
106
+ const res = await fetchRecent(config, "pw", { limit: 2, to: "keep@x.com" });
107
+ // Window is the 6 newest UIDs (4..9). The display set is the FIRST two
108
+ // keep@ matches in ascending window order (5, 7), returned newest-first.
109
+ expect(res.messages.map((m) => m.uid)).toEqual([7, 5]);
110
+ expect(res.messages.every((m) => m.bodyPreview.length > 0)).toBe(true);
111
+ const sourceFetches = fetchCalls.filter((c) => c.fields.source);
112
+ expect(sourceFetches.length).toBe(1);
113
+ const fetchedUids = sourceFetches[0].range
114
+ .split(",")
115
+ .map((s) => Number(s.trim()))
116
+ .sort((a, b) => a - b);
117
+ expect(fetchedUids).toEqual([5, 7]);
118
+ });
119
+ it("searchMessages second-pass source fetch covers only the displayed UID set", async () => {
120
+ inbox = [
121
+ { uid: 1, to: "keep@x.com", subject: "s1", from: "a@x.com" },
122
+ { uid: 2, to: "other@x.com", subject: "s2", from: "a@x.com" },
123
+ { uid: 3, to: "keep@x.com", subject: "s3", from: "a@x.com" },
124
+ { uid: 4, to: "other@x.com", subject: "s4", from: "a@x.com" },
125
+ { uid: 5, to: "keep@x.com", subject: "s5", from: "a@x.com" },
126
+ { uid: 6, to: "other@x.com", subject: "s6", from: "a@x.com" },
127
+ ];
128
+ mockClient.search.mockResolvedValue(inbox.map((m) => m.uid));
129
+ const res = await searchMessages(config, "pw", { limit: 2, to: "keep@x.com" });
130
+ // Window is all 6 UIDs (1..6). Display set is the first two keep@ matches
131
+ // in ascending order (1, 3), returned newest-first.
132
+ expect(res.messages.map((m) => m.uid)).toEqual([3, 1]);
133
+ const sourceFetches = fetchCalls.filter((c) => c.fields.source);
134
+ expect(sourceFetches.length).toBe(1);
135
+ const fetchedUids = sourceFetches[0].range
136
+ .split(",")
137
+ .map((s) => Number(s.trim()))
138
+ .sort((a, b) => a - b);
139
+ expect(fetchedUids).toEqual([1, 3]);
140
+ });
141
+ });
142
+ //# sourceMappingURL=source-fetch-efficiency.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"source-fetch-efficiency.test.js","sourceRoot":"","sources":["../../src/__tests__/source-fetch-efficiency.test.ts"],"names":[],"mappings":"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"}
@@ -289,11 +289,6 @@ export declare function fetchSinceUid(config: EmailConfig, password: string, sin
289
289
  /**
290
290
  * Resolve an envelope by Message-ID via IMAP. Searches INBOX first, then
291
291
  * the \Sent special-use folder. Returns null when no folder yields a hit.
292
- *
293
- * Uses `header: { "message-id": ... }` IMAP SEARCH — sufficient on every
294
- * server that honours RFC 3501 header search. The Message-ID is sent with
295
- * angle brackets restored because some servers (notably Gmail) only match
296
- * the raw header value, not the bare identifier.
297
292
  */
298
293
  export declare function fetchEnvelopeByMessageId(config: EmailConfig, password: string, messageId: string): Promise<{
299
294
  uid: number;
@@ -1 +1 @@
1
- {"version":3,"file":"imap.d.ts","sourceRoot":"","sources":["../../src/lib/imap.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"imap.d.ts","sourceRoot":"","sources":["../../src/lib/imap.ts"],"names":[],"mappings":"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"}
@@ -564,15 +564,15 @@ export async function fetchRecent(config, password, options = {}) {
564
564
  let envelopeCount = 0;
565
565
  let recipientKept = 0;
566
566
  let recipientHidden = 0;
567
- // Body sources captured during streaming and parsed after the fetch
568
- // iterator closes running simpleParser inside the open fetch loop can
569
- // stall the IMAP socket. Aligned by index with `messages`.
570
- const bodySources = [];
567
+ // Pass 1: envelopes + structure only (no source) across the whole
568
+ // over-fetched window, so recipient kept/hidden accounting covers every
569
+ // UID while costing only envelope bytes. structureType is captured per
570
+ // displayed message (aligned by index with `messages`) for the diag.
571
+ const displayStructureTypes = [];
571
572
  for await (const msg of client.fetch(uidList, {
572
573
  envelope: true,
573
574
  uid: true,
574
575
  bodyStructure: true,
575
- source: true,
576
576
  }, { uid: true })) {
577
577
  envelopeCount++;
578
578
  diag("fetchRecent", `envelope #${envelopeCount}`, `uid=${msg.uid} from=${msg.envelope?.from?.[0]?.address ?? "?"} at ${Date.now() - t2}ms`);
@@ -593,14 +593,10 @@ export async function fetchRecent(config, password, options = {}) {
593
593
  continue;
594
594
  // Collect up to `limit` messages for display, but keep iterating past
595
595
  // that point so the recipient kept/hidden accounting covers the whole
596
- // fetched window. Body parsing is deferred until the iterator closes
597
- // (see bodySources) and only runs for the displayed messages.
596
+ // fetched window.
598
597
  if (messages.length < limit) {
599
598
  const attachments = walkAttachmentMetadata(msg.bodyStructure);
600
- bodySources.push({
601
- source: msg.source ?? Buffer.alloc(0),
602
- structureType: msg.bodyStructure?.type ?? "?",
603
- });
599
+ displayStructureTypes.push(msg.bodyStructure?.type ?? "?");
604
600
  messages.push({
605
601
  uid: msg.uid,
606
602
  messageId,
@@ -613,11 +609,20 @@ export async function fetchRecent(config, password, options = {}) {
613
609
  });
614
610
  }
615
611
  }
616
- // Parse the captured sources now that the fetch stream is closed.
617
- for (let i = 0; i < messages.length; i++) {
618
- const { body, kind } = await extractBody(bodySources[i].source);
619
- messages[i].bodyPreview = previewBody(body);
620
- diag("fetchRecent", `body #${i + 1}`, `uid=${messages[i].uid} preview=${messages[i].bodyPreview.length}chars type=${bodySources[i].structureType} bodySource=${kind}`);
612
+ // Pass 2: download full source ONLY for the messages we display, keyed by
613
+ // UID, then decode previews now that the stream is closed. A heavily
614
+ // filtered over-fetch no longer pulls source for the UIDs it dropped.
615
+ if (messages.length > 0) {
616
+ const displayUids = messages.map((m) => m.uid);
617
+ const sourceByUid = new Map();
618
+ for await (const msg of client.fetch(displayUids.map(String).join(","), { uid: true, source: true }, { uid: true })) {
619
+ sourceByUid.set(msg.uid, msg.source ?? Buffer.alloc(0));
620
+ }
621
+ for (let i = 0; i < messages.length; i++) {
622
+ const { body, kind } = await extractBody(sourceByUid.get(messages[i].uid) ?? Buffer.alloc(0));
623
+ messages[i].bodyPreview = previewBody(body);
624
+ diag("fetchRecent", `body #${i + 1}`, `uid=${messages[i].uid} preview=${messages[i].bodyPreview.length}chars type=${displayStructureTypes[i]} bodySource=${kind}`);
625
+ }
621
626
  }
622
627
  diag("fetchRecent", "fetch done", `${envelopeCount} envelopes, ${messages.length} messages in ${Date.now() - t2}ms (total ${Date.now() - t0}ms)`);
623
628
  if (clientSideRecipients) {
@@ -693,14 +698,14 @@ export async function searchMessages(config, password, query) {
693
698
  let envelopeCount = 0;
694
699
  let recipientKept = 0;
695
700
  let recipientHidden = 0;
696
- // Body sources captured during streaming and parsed after the fetch
697
- // iterator closes (see fetchRecent). Aligned by index with `messages`.
698
- const bodySources = [];
701
+ // Pass 1: envelopes + structure only (no source) across the whole
702
+ // over-fetched window (see fetchRecent). structureType is captured per
703
+ // displayed message, aligned by index with `messages`.
704
+ const displayStructureTypes = [];
699
705
  for await (const msg of client.fetch(recentUids.map(String).join(","), {
700
706
  envelope: true,
701
707
  uid: true,
702
708
  bodyStructure: true,
703
- source: true,
704
709
  }, { uid: true })) {
705
710
  envelopeCount++;
706
711
  // Client-side recipient filter (replaces IMAP SEARCH TO), with kept-vs-hidden accounting
@@ -718,13 +723,10 @@ export async function searchMessages(config, password, query) {
718
723
  const inReplyTo = msg.envelope?.inReplyTo ?? null;
719
724
  // Collect up to `limit` messages for display, but keep iterating past
720
725
  // that point so the recipient kept/hidden accounting covers the whole
721
- // fetched window. Body parsing is deferred until the iterator closes.
726
+ // fetched window.
722
727
  if (messages.length < limit) {
723
728
  const attachments = walkAttachmentMetadata(msg.bodyStructure);
724
- bodySources.push({
725
- source: msg.source ?? Buffer.alloc(0),
726
- structureType: msg.bodyStructure?.type ?? "?",
727
- });
729
+ displayStructureTypes.push(msg.bodyStructure?.type ?? "?");
728
730
  messages.push({
729
731
  uid: msg.uid,
730
732
  messageId,
@@ -737,11 +739,19 @@ export async function searchMessages(config, password, query) {
737
739
  });
738
740
  }
739
741
  }
740
- // Parse the captured sources now that the fetch stream is closed.
741
- for (let i = 0; i < messages.length; i++) {
742
- const { body, kind } = await extractBody(bodySources[i].source);
743
- messages[i].bodyPreview = previewBody(body);
744
- diag("searchMessages", `body #${i + 1}`, `uid=${messages[i].uid} preview=${messages[i].bodyPreview.length}chars type=${bodySources[i].structureType} bodySource=${kind}`);
742
+ // Pass 2: download full source ONLY for the displayed messages, keyed by
743
+ // UID, then decode previews (see fetchRecent).
744
+ if (messages.length > 0) {
745
+ const displayUids = messages.map((m) => m.uid);
746
+ const sourceByUid = new Map();
747
+ for await (const msg of client.fetch(displayUids.map(String).join(","), { uid: true, source: true }, { uid: true })) {
748
+ sourceByUid.set(msg.uid, msg.source ?? Buffer.alloc(0));
749
+ }
750
+ for (let i = 0; i < messages.length; i++) {
751
+ const { body, kind } = await extractBody(sourceByUid.get(messages[i].uid) ?? Buffer.alloc(0));
752
+ messages[i].bodyPreview = previewBody(body);
753
+ diag("searchMessages", `body #${i + 1}`, `uid=${messages[i].uid} preview=${messages[i].bodyPreview.length}chars type=${displayStructureTypes[i]} bodySource=${kind}`);
754
+ }
745
755
  }
746
756
  diag("searchMessages", "fetch done", `${envelopeCount} envelopes, ${messages.length} messages in ${Date.now() - t2}ms (total ${Date.now() - t0}ms)`);
747
757
  if (clientSideRecipients) {
@@ -881,67 +891,81 @@ export async function fetchSinceUid(config, password, sinceUid, recipients) {
881
891
  }
882
892
  }
883
893
  /**
884
- * Resolve an envelope by Message-ID via IMAP. Searches INBOX first, then
885
- * the \Sent special-use folder. Returns null when no folder yields a hit.
894
+ * Locate a message by Message-ID on an ALREADY-CONNECTED client. Searches
895
+ * INBOX first, then the \Sent special-use folder, returning the first hit
896
+ * whose envelope carries a From address. The caller owns connect/logout — this
897
+ * helper neither opens nor closes the connection, so one login can both resolve
898
+ * the message and fetch its source (see fetchFullBody's message_id path).
886
899
  *
887
- * Uses `header: { "message-id": ... }` IMAP SEARCH — sufficient on every
888
- * server that honours RFC 3501 header search. The Message-ID is sent with
889
- * angle brackets restored because some servers (notably Gmail) only match
890
- * the raw header value, not the bare identifier.
900
+ * Uses `header: { "message-id": ... }` IMAP SEARCH — sufficient on every server
901
+ * that honours RFC 3501 header search. The Message-ID is sent with angle
902
+ * brackets restored because some servers (notably Gmail) only match the raw
903
+ * header value, not the bare identifier.
891
904
  */
892
- export async function fetchEnvelopeByMessageId(config, password, messageId) {
905
+ async function locateByMessageId(client, messageId) {
893
906
  const cleanId = messageId.replace(/^<|>$/g, "");
894
907
  const needle = `<${cleanId}>`;
908
+ const folders = ["INBOX"];
909
+ try {
910
+ const sentPath = await resolveFolderName(client, "sent");
911
+ folders.push(sentPath);
912
+ }
913
+ catch {
914
+ // No \Sent folder advertised — only search INBOX.
915
+ }
916
+ for (const folderPath of folders) {
917
+ const lock = await client.getMailboxLock(folderPath);
918
+ try {
919
+ const uids = await client.search({ header: { "message-id": needle } }, { uid: true });
920
+ if (!uids || uids.length === 0)
921
+ continue;
922
+ const uid = uids[0];
923
+ for await (const msg of client.fetch(String(uid), { envelope: true, uid: true }, { uid: true })) {
924
+ const env = msg.envelope;
925
+ if (!env?.from?.[0]?.address)
926
+ continue;
927
+ return { uid: msg.uid, mailbox: folderPath, envelope: env };
928
+ }
929
+ }
930
+ finally {
931
+ lock.release();
932
+ }
933
+ }
934
+ return null;
935
+ }
936
+ /**
937
+ * Resolve an envelope by Message-ID via IMAP. Searches INBOX first, then
938
+ * the \Sent special-use folder. Returns null when no folder yields a hit.
939
+ */
940
+ export async function fetchEnvelopeByMessageId(config, password, messageId) {
895
941
  const client = createClient(config, password);
896
942
  const t0 = Date.now();
897
- diag("fetchEnvelopeByMessageId", "start", `messageId=${cleanId}`);
943
+ diag("fetchEnvelopeByMessageId", "start", `messageId=${messageId.replace(/^<|>$/g, "")}`);
898
944
  try {
899
945
  await client.connect();
900
946
  diag("fetchEnvelopeByMessageId", "connected", `${Date.now() - t0}ms`);
901
- const folders = ["INBOX"];
902
- try {
903
- const sentPath = await resolveFolderName(client, "sent");
904
- folders.push(sentPath);
905
- }
906
- catch {
907
- // No \Sent folder advertised — only search INBOX.
908
- }
909
- for (const folderPath of folders) {
910
- const lock = await client.getMailboxLock(folderPath);
911
- try {
912
- const uids = await client.search({ header: { "message-id": needle } }, { uid: true });
913
- if (!uids || uids.length === 0)
914
- continue;
915
- const uid = uids[0];
916
- for await (const msg of client.fetch(String(uid), { envelope: true, uid: true }, { uid: true })) {
917
- const env = msg.envelope ?? {};
918
- const fromAddr = env.from?.[0]?.address ?? "";
919
- if (!fromAddr)
920
- continue;
921
- diag("fetchEnvelopeByMessageId", "match", `folder=${folderPath} uid=${msg.uid} in ${Date.now() - t0}ms`);
922
- return {
923
- uid: msg.uid,
924
- mailbox: folderPath,
925
- messageId: env.messageId ?? messageId,
926
- fromAddress: fromAddr,
927
- fromName: env.from?.[0]?.name ?? null,
928
- toAddresses: (env.to ?? [])
929
- .map((a) => a.address)
930
- .filter((a) => !!a),
931
- ccAddresses: (env.cc ?? [])
932
- .map((a) => a.address)
933
- .filter((a) => !!a),
934
- subject: env.subject ?? "",
935
- date: env.date?.toISOString() ?? "",
936
- };
937
- }
938
- }
939
- finally {
940
- lock.release();
941
- }
947
+ const loc = await locateByMessageId(client, messageId);
948
+ if (!loc) {
949
+ diag("fetchEnvelopeByMessageId", "no-match", `in ${Date.now() - t0}ms`);
950
+ return null;
942
951
  }
943
- diag("fetchEnvelopeByMessageId", "no-match", `searched=${folders.join(",")} in ${Date.now() - t0}ms`);
944
- return null;
952
+ const env = loc.envelope;
953
+ diag("fetchEnvelopeByMessageId", "match", `folder=${loc.mailbox} uid=${loc.uid} in ${Date.now() - t0}ms`);
954
+ return {
955
+ uid: loc.uid,
956
+ mailbox: loc.mailbox,
957
+ messageId: env.messageId ?? messageId,
958
+ fromAddress: env.from?.[0]?.address ?? "",
959
+ fromName: env.from?.[0]?.name ?? null,
960
+ toAddresses: (env.to ?? [])
961
+ .map((a) => a.address)
962
+ .filter((a) => !!a),
963
+ ccAddresses: (env.cc ?? [])
964
+ .map((a) => a.address)
965
+ .filter((a) => !!a),
966
+ subject: env.subject ?? "",
967
+ date: env.date?.toISOString() ?? "",
968
+ };
945
969
  }
946
970
  catch (err) {
947
971
  diag("fetchEnvelopeByMessageId", "FAILED", `${err instanceof Error ? err.message : String(err)} after ${Date.now() - t0}ms`);
@@ -958,18 +982,6 @@ export async function fetchEnvelopeByMessageId(config, password, messageId) {
958
982
  * MIME-shape blind spot. Returns null when the message cannot be located.
959
983
  */
960
984
  export async function fetchFullBody(config, password, target) {
961
- let mailbox = "";
962
- let uid;
963
- if ("messageId" in target) {
964
- const env = await fetchEnvelopeByMessageId(config, password, target.messageId);
965
- if (!env)
966
- return null;
967
- mailbox = env.mailbox;
968
- uid = env.uid;
969
- }
970
- else {
971
- uid = target.uid;
972
- }
973
985
  const client = createClient(config, password);
974
986
  const t0 = Date.now();
975
987
  const label = "messageId" in target
@@ -978,8 +990,22 @@ export async function fetchFullBody(config, password, target) {
978
990
  diag("fetchFullBody", "start", label);
979
991
  try {
980
992
  await client.connect();
981
- if (!("messageId" in target)) {
993
+ // Resolve the message location on THIS connection — a message_id read no
994
+ // longer opens a second login just to learn its uid/mailbox.
995
+ let mailbox;
996
+ let uid;
997
+ if ("messageId" in target) {
998
+ const loc = await locateByMessageId(client, target.messageId);
999
+ if (!loc) {
1000
+ diag("fetchFullBody", "not-found", `messageId=${target.messageId} in ${Date.now() - t0}ms`);
1001
+ return null;
1002
+ }
1003
+ mailbox = loc.mailbox;
1004
+ uid = loc.uid;
1005
+ }
1006
+ else {
982
1007
  mailbox = await resolveFolderName(client, target.folder ?? "inbox");
1008
+ uid = target.uid;
983
1009
  }
984
1010
  const lock = await client.getMailboxLock(mailbox);
985
1011
  try {