apple-mail-mcp 2.19.14 → 2.19.15
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/README.md +9 -0
- package/build/cli.js +71 -18
- package/build/index.js +88 -29
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1077,6 +1077,15 @@ refused rather than guessed; pass the full path to disambiguate. This also
|
|
|
1077
1077
|
means Gmail's nested special mailboxes now report their real path, e.g.
|
|
1078
1078
|
`[Gmail]/All Mail` rather than `All Mail` — a visible change from before 2.17.0.
|
|
1079
1079
|
|
|
1080
|
+
Matching ignores letter case **and Unicode normalization form**: a typed
|
|
1081
|
+
precomposed `México` (NFC) finds a mailbox the server stores decomposed (NFD —
|
|
1082
|
+
common for folders created on a Mac, and what iCloud keeps), and the server's
|
|
1083
|
+
own stored spelling is what gets selected. Two mailboxes whose names differ
|
|
1084
|
+
*only* in case or normalization look identical in any listing, so a name that
|
|
1085
|
+
matches both is refused with an error saying so — rename one of them. For the
|
|
1086
|
+
same reason `create-mailbox` treats a normalization-equivalent existing name as
|
|
1087
|
+
already existing, and `rename-mailbox` refuses to create such a twin.
|
|
1088
|
+
|
|
1080
1089
|
**Mail's local "On My Mac" mailboxes** are not children of any account — they
|
|
1081
1090
|
hang off the application — so they are reported under the synthetic account label
|
|
1082
1091
|
**`On My Mac`**. An unscoped call includes them (listed last); `account="On My
|
package/build/cli.js
CHANGED
|
@@ -57647,6 +57647,19 @@ var require_imap_flow = __commonJS({
|
|
|
57647
57647
|
}
|
|
57648
57648
|
});
|
|
57649
57649
|
|
|
57650
|
+
// src/utils/mailboxName.ts
|
|
57651
|
+
function mailboxNameKey(name) {
|
|
57652
|
+
return name.trim().normalize("NFC").toLowerCase();
|
|
57653
|
+
}
|
|
57654
|
+
function nfc(name) {
|
|
57655
|
+
return name.trim().normalize("NFC");
|
|
57656
|
+
}
|
|
57657
|
+
var init_mailboxName = __esm({
|
|
57658
|
+
"src/utils/mailboxName.ts"() {
|
|
57659
|
+
"use strict";
|
|
57660
|
+
}
|
|
57661
|
+
});
|
|
57662
|
+
|
|
57650
57663
|
// src/utils/mimeParse.ts
|
|
57651
57664
|
function extractBoundary(source) {
|
|
57652
57665
|
const match = source.match(/boundary="?([^";\s\r\n]+)"?/i);
|
|
@@ -58076,6 +58089,7 @@ __export(imapClient_exports, {
|
|
|
58076
58089
|
listImapAccountLabels: () => listImapAccountLabels,
|
|
58077
58090
|
mailFlagBitsFor: () => mailFlagBitsFor,
|
|
58078
58091
|
mailFlagColorIndex: () => mailFlagColorIndex,
|
|
58092
|
+
matchMailbox: () => matchMailbox,
|
|
58079
58093
|
normalizeMessageId: () => normalizeMessageId,
|
|
58080
58094
|
resolveImapConfig: () => resolveImapConfig,
|
|
58081
58095
|
resolveImapConfigs: () => resolveImapConfigs,
|
|
@@ -58290,16 +58304,21 @@ function staticMailboxAlias(mailbox) {
|
|
|
58290
58304
|
}
|
|
58291
58305
|
async function resolveMailboxPath(client, mailbox, _mode) {
|
|
58292
58306
|
if (!mailbox) return "INBOX";
|
|
58307
|
+
let boxes;
|
|
58293
58308
|
try {
|
|
58294
|
-
|
|
58295
|
-
if (resolved.kind === "found") return resolved.path;
|
|
58296
|
-
const flag = SPECIAL_USE_ALIASES[mailbox.trim().toLowerCase()];
|
|
58297
|
-
if (flag) {
|
|
58298
|
-
const boxes = await client.list();
|
|
58299
|
-
const special = boxes.find((b) => b.specialUse?.toLowerCase() === flag);
|
|
58300
|
-
if (special) return special.path;
|
|
58301
|
-
}
|
|
58309
|
+
boxes = await client.list();
|
|
58302
58310
|
} catch {
|
|
58311
|
+
return staticMailboxAlias(mailbox);
|
|
58312
|
+
}
|
|
58313
|
+
const resolved = matchMailbox(boxes, mailbox);
|
|
58314
|
+
if (resolved.kind === "found") return resolved.path;
|
|
58315
|
+
const flag = SPECIAL_USE_ALIASES[mailbox.trim().toLowerCase()];
|
|
58316
|
+
if (flag) {
|
|
58317
|
+
const special = boxes.find((b) => b.specialUse?.toLowerCase() === flag);
|
|
58318
|
+
if (special) return special.path;
|
|
58319
|
+
}
|
|
58320
|
+
if (resolved.kind === "ambiguous") {
|
|
58321
|
+
throw new Error(ambiguousMailboxError(mailbox, resolved.candidates));
|
|
58303
58322
|
}
|
|
58304
58323
|
return staticMailboxAlias(mailbox);
|
|
58305
58324
|
}
|
|
@@ -58392,7 +58411,7 @@ function structuredRow(m, account, path) {
|
|
|
58392
58411
|
};
|
|
58393
58412
|
}
|
|
58394
58413
|
function describeMailboxFailure(error) {
|
|
58395
|
-
const raw =
|
|
58414
|
+
const raw = errText(error);
|
|
58396
58415
|
const oneLine = raw.split("\n")[0].trim();
|
|
58397
58416
|
const looksSensitive = /pass(word)?\s*[:=]|authorization:\s*\S|bearer\s+\S{10,}/i.test(oneLine);
|
|
58398
58417
|
const safe = looksSensitive ? "IMAP error (detail redacted \u2014 response text looked like it might contain a credential)" : oneLine || "unknown error";
|
|
@@ -58630,7 +58649,13 @@ function imapMailStats(deps = {}) {
|
|
|
58630
58649
|
);
|
|
58631
58650
|
}
|
|
58632
58651
|
function errText(e) {
|
|
58633
|
-
|
|
58652
|
+
if (!(e instanceof Error)) return String(e);
|
|
58653
|
+
const x = e;
|
|
58654
|
+
if (typeof x.responseStatus !== "string" || !x.responseStatus) return e.message;
|
|
58655
|
+
const code = typeof x.serverResponseCode === "string" && x.serverResponseCode;
|
|
58656
|
+
const text = typeof x.responseText === "string" ? x.responseText.trim() : "";
|
|
58657
|
+
const server = [x.responseStatus, code ? `[${code}]` : "", text].filter(Boolean).join(" ");
|
|
58658
|
+
return e.message && e.message !== "Command failed" ? `${e.message}: ${server}` : server;
|
|
58634
58659
|
}
|
|
58635
58660
|
function assertMutated(result, what) {
|
|
58636
58661
|
if (!result) throw new Error(`${what}: server rejected the command (IMAP NO/BAD)`);
|
|
@@ -58782,20 +58807,30 @@ function withClient(deps, fn) {
|
|
|
58782
58807
|
return useClient(deps, fn);
|
|
58783
58808
|
}
|
|
58784
58809
|
async function resolveMailbox(client, name) {
|
|
58785
|
-
const wanted = name.trim().toLowerCase();
|
|
58786
58810
|
const boxes = await client.list();
|
|
58787
|
-
|
|
58788
|
-
|
|
58789
|
-
|
|
58790
|
-
|
|
58791
|
-
if (
|
|
58792
|
-
|
|
58811
|
+
return matchMailbox(boxes, name);
|
|
58812
|
+
}
|
|
58813
|
+
function matchMailbox(boxes, name) {
|
|
58814
|
+
const exact = boxes.find((b) => b.path === name || b.path === name.trim());
|
|
58815
|
+
if (exact) return { kind: "found", path: exact.path };
|
|
58816
|
+
const wanted = mailboxNameKey(name);
|
|
58817
|
+
const tiers = [
|
|
58818
|
+
boxes.filter((b) => mailboxNameKey(b.path) === wanted),
|
|
58819
|
+
boxes.filter((b) => mailboxNameKey(b.name) === wanted)
|
|
58820
|
+
];
|
|
58821
|
+
for (const hits of tiers) {
|
|
58822
|
+
const paths = [...new Set(hits.map((b) => b.path))];
|
|
58823
|
+
if (paths.length === 1) return { kind: "found", path: paths[0] };
|
|
58824
|
+
if (paths.length > 1) return { kind: "ambiguous", candidates: paths.sort() };
|
|
58793
58825
|
}
|
|
58794
58826
|
return { kind: "none" };
|
|
58795
58827
|
}
|
|
58796
58828
|
function ambiguousMailboxError(name, candidates, accountLabel) {
|
|
58797
58829
|
const where = accountLabel ? ` on IMAP account ${accountLabel}` : "";
|
|
58798
|
-
|
|
58830
|
+
const listed = candidates.map((c) => `"${c}"`).join(" and ");
|
|
58831
|
+
const indistinguishable = new Set(candidates.map(mailboxNameKey)).size === 1;
|
|
58832
|
+
const hint = indistinguishable ? " They differ only in letter case or Unicode normalization (precomposed vs decomposed accents), so no typed name can tell them apart. Rename one of them." : " Pass the full path.";
|
|
58833
|
+
return `Mailbox "${name}" is ambiguous${where} \u2014 it matches ${listed}.${hint}`;
|
|
58799
58834
|
}
|
|
58800
58835
|
async function findMailboxPathOrThrow(client, name) {
|
|
58801
58836
|
const res = await resolveMailbox(client, name);
|
|
@@ -58804,6 +58839,15 @@ async function findMailboxPathOrThrow(client, name) {
|
|
|
58804
58839
|
}
|
|
58805
58840
|
function imapCreateMailbox(name, deps = {}) {
|
|
58806
58841
|
return withClient(deps, async (client) => {
|
|
58842
|
+
let twin;
|
|
58843
|
+
try {
|
|
58844
|
+
const wanted = nfc(name);
|
|
58845
|
+
twin = (await client.list()).find((b) => nfc(b.path) === wanted)?.path;
|
|
58846
|
+
} catch {
|
|
58847
|
+
}
|
|
58848
|
+
if (twin !== void 0) {
|
|
58849
|
+
return { success: true, info: `Mailbox "${twin}" already existed.` };
|
|
58850
|
+
}
|
|
58807
58851
|
try {
|
|
58808
58852
|
const res = await client.mailboxCreate(name);
|
|
58809
58853
|
return res.created ? { success: true, info: `Created mailbox "${res.path}".` } : { success: true, info: `Mailbox "${res.path}" already existed.` };
|
|
@@ -58855,6 +58899,14 @@ function imapRenameMailbox(oldName, newName, deps = {}) {
|
|
|
58855
58899
|
};
|
|
58856
58900
|
}
|
|
58857
58901
|
const path = found.path;
|
|
58902
|
+
const wantedNew = nfc(newName);
|
|
58903
|
+
const clash = (await client.list()).find((b) => b.path !== path && nfc(b.path) === wantedNew);
|
|
58904
|
+
if (clash) {
|
|
58905
|
+
return {
|
|
58906
|
+
success: false,
|
|
58907
|
+
error: `Cannot rename "${path}" to "${newName}": mailbox "${clash.path}" already exists on IMAP account ${cfg.accountLabel} (the same name, differing only in how its accents are encoded).`
|
|
58908
|
+
};
|
|
58909
|
+
}
|
|
58858
58910
|
try {
|
|
58859
58911
|
const res = await client.mailboxRename(path, newName);
|
|
58860
58912
|
return { success: true, info: `Renamed "${res.path}" to "${res.newPath}" via IMAP.` };
|
|
@@ -59509,6 +59561,7 @@ var init_imapClient = __esm({
|
|
|
59509
59561
|
import_imapflow = __toESM(require_imap_flow(), 1);
|
|
59510
59562
|
init_smtpMailer();
|
|
59511
59563
|
init_docsUrls();
|
|
59564
|
+
init_mailboxName();
|
|
59512
59565
|
init_mimeParse();
|
|
59513
59566
|
init_headers();
|
|
59514
59567
|
init_auditLog();
|
package/build/index.js
CHANGED
|
@@ -7681,6 +7681,19 @@ var init_headers = __esm({
|
|
|
7681
7681
|
}
|
|
7682
7682
|
});
|
|
7683
7683
|
|
|
7684
|
+
// src/utils/mailboxName.ts
|
|
7685
|
+
function mailboxNameKey(name) {
|
|
7686
|
+
return name.trim().normalize("NFC").toLowerCase();
|
|
7687
|
+
}
|
|
7688
|
+
function nfc(name) {
|
|
7689
|
+
return name.trim().normalize("NFC");
|
|
7690
|
+
}
|
|
7691
|
+
var init_mailboxName = __esm({
|
|
7692
|
+
"src/utils/mailboxName.ts"() {
|
|
7693
|
+
"use strict";
|
|
7694
|
+
}
|
|
7695
|
+
});
|
|
7696
|
+
|
|
7684
7697
|
// src/utils/attachmentLimits.ts
|
|
7685
7698
|
function isInlineAttachmentBase64WithinLimit(contentBase64) {
|
|
7686
7699
|
if (contentBase64.length > MAX_INLINE_ATTACHMENT_BASE64_INPUT_CHARS) return false;
|
|
@@ -65405,6 +65418,7 @@ __export(imapClient_exports, {
|
|
|
65405
65418
|
listImapAccountLabels: () => listImapAccountLabels,
|
|
65406
65419
|
mailFlagBitsFor: () => mailFlagBitsFor,
|
|
65407
65420
|
mailFlagColorIndex: () => mailFlagColorIndex,
|
|
65421
|
+
matchMailbox: () => matchMailbox,
|
|
65408
65422
|
normalizeMessageId: () => normalizeMessageId,
|
|
65409
65423
|
resolveImapConfig: () => resolveImapConfig,
|
|
65410
65424
|
resolveImapConfigs: () => resolveImapConfigs,
|
|
@@ -65619,16 +65633,21 @@ function staticMailboxAlias(mailbox) {
|
|
|
65619
65633
|
}
|
|
65620
65634
|
async function resolveMailboxPath(client, mailbox, _mode) {
|
|
65621
65635
|
if (!mailbox) return "INBOX";
|
|
65636
|
+
let boxes;
|
|
65622
65637
|
try {
|
|
65623
|
-
|
|
65624
|
-
if (resolved.kind === "found") return resolved.path;
|
|
65625
|
-
const flag = SPECIAL_USE_ALIASES[mailbox.trim().toLowerCase()];
|
|
65626
|
-
if (flag) {
|
|
65627
|
-
const boxes = await client.list();
|
|
65628
|
-
const special = boxes.find((b) => b.specialUse?.toLowerCase() === flag);
|
|
65629
|
-
if (special) return special.path;
|
|
65630
|
-
}
|
|
65638
|
+
boxes = await client.list();
|
|
65631
65639
|
} catch {
|
|
65640
|
+
return staticMailboxAlias(mailbox);
|
|
65641
|
+
}
|
|
65642
|
+
const resolved = matchMailbox(boxes, mailbox);
|
|
65643
|
+
if (resolved.kind === "found") return resolved.path;
|
|
65644
|
+
const flag = SPECIAL_USE_ALIASES[mailbox.trim().toLowerCase()];
|
|
65645
|
+
if (flag) {
|
|
65646
|
+
const special = boxes.find((b) => b.specialUse?.toLowerCase() === flag);
|
|
65647
|
+
if (special) return special.path;
|
|
65648
|
+
}
|
|
65649
|
+
if (resolved.kind === "ambiguous") {
|
|
65650
|
+
throw new Error(ambiguousMailboxError(mailbox, resolved.candidates));
|
|
65632
65651
|
}
|
|
65633
65652
|
return staticMailboxAlias(mailbox);
|
|
65634
65653
|
}
|
|
@@ -65721,7 +65740,7 @@ function structuredRow(m, account, path) {
|
|
|
65721
65740
|
};
|
|
65722
65741
|
}
|
|
65723
65742
|
function describeMailboxFailure(error2) {
|
|
65724
|
-
const raw =
|
|
65743
|
+
const raw = errText(error2);
|
|
65725
65744
|
const oneLine = raw.split("\n")[0].trim();
|
|
65726
65745
|
const looksSensitive = /pass(word)?\s*[:=]|authorization:\s*\S|bearer\s+\S{10,}/i.test(oneLine);
|
|
65727
65746
|
const safe = looksSensitive ? "IMAP error (detail redacted \u2014 response text looked like it might contain a credential)" : oneLine || "unknown error";
|
|
@@ -65959,7 +65978,13 @@ function imapMailStats(deps = {}) {
|
|
|
65959
65978
|
);
|
|
65960
65979
|
}
|
|
65961
65980
|
function errText(e) {
|
|
65962
|
-
|
|
65981
|
+
if (!(e instanceof Error)) return String(e);
|
|
65982
|
+
const x = e;
|
|
65983
|
+
if (typeof x.responseStatus !== "string" || !x.responseStatus) return e.message;
|
|
65984
|
+
const code = typeof x.serverResponseCode === "string" && x.serverResponseCode;
|
|
65985
|
+
const text = typeof x.responseText === "string" ? x.responseText.trim() : "";
|
|
65986
|
+
const server2 = [x.responseStatus, code ? `[${code}]` : "", text].filter(Boolean).join(" ");
|
|
65987
|
+
return e.message && e.message !== "Command failed" ? `${e.message}: ${server2}` : server2;
|
|
65963
65988
|
}
|
|
65964
65989
|
function assertMutated(result, what) {
|
|
65965
65990
|
if (!result) throw new Error(`${what}: server rejected the command (IMAP NO/BAD)`);
|
|
@@ -66111,20 +66136,30 @@ function withClient(deps, fn) {
|
|
|
66111
66136
|
return useClient(deps, fn);
|
|
66112
66137
|
}
|
|
66113
66138
|
async function resolveMailbox(client, name) {
|
|
66114
|
-
const wanted = name.trim().toLowerCase();
|
|
66115
66139
|
const boxes = await client.list();
|
|
66116
|
-
|
|
66117
|
-
|
|
66118
|
-
|
|
66119
|
-
|
|
66120
|
-
if (
|
|
66121
|
-
|
|
66140
|
+
return matchMailbox(boxes, name);
|
|
66141
|
+
}
|
|
66142
|
+
function matchMailbox(boxes, name) {
|
|
66143
|
+
const exact = boxes.find((b) => b.path === name || b.path === name.trim());
|
|
66144
|
+
if (exact) return { kind: "found", path: exact.path };
|
|
66145
|
+
const wanted = mailboxNameKey(name);
|
|
66146
|
+
const tiers = [
|
|
66147
|
+
boxes.filter((b) => mailboxNameKey(b.path) === wanted),
|
|
66148
|
+
boxes.filter((b) => mailboxNameKey(b.name) === wanted)
|
|
66149
|
+
];
|
|
66150
|
+
for (const hits of tiers) {
|
|
66151
|
+
const paths = [...new Set(hits.map((b) => b.path))];
|
|
66152
|
+
if (paths.length === 1) return { kind: "found", path: paths[0] };
|
|
66153
|
+
if (paths.length > 1) return { kind: "ambiguous", candidates: paths.sort() };
|
|
66122
66154
|
}
|
|
66123
66155
|
return { kind: "none" };
|
|
66124
66156
|
}
|
|
66125
66157
|
function ambiguousMailboxError(name, candidates, accountLabel) {
|
|
66126
66158
|
const where = accountLabel ? ` on IMAP account ${accountLabel}` : "";
|
|
66127
|
-
|
|
66159
|
+
const listed = candidates.map((c) => `"${c}"`).join(" and ");
|
|
66160
|
+
const indistinguishable = new Set(candidates.map(mailboxNameKey)).size === 1;
|
|
66161
|
+
const hint = indistinguishable ? " They differ only in letter case or Unicode normalization (precomposed vs decomposed accents), so no typed name can tell them apart. Rename one of them." : " Pass the full path.";
|
|
66162
|
+
return `Mailbox "${name}" is ambiguous${where} \u2014 it matches ${listed}.${hint}`;
|
|
66128
66163
|
}
|
|
66129
66164
|
async function findMailboxPathOrThrow(client, name) {
|
|
66130
66165
|
const res = await resolveMailbox(client, name);
|
|
@@ -66133,6 +66168,15 @@ async function findMailboxPathOrThrow(client, name) {
|
|
|
66133
66168
|
}
|
|
66134
66169
|
function imapCreateMailbox(name, deps = {}) {
|
|
66135
66170
|
return withClient(deps, async (client) => {
|
|
66171
|
+
let twin;
|
|
66172
|
+
try {
|
|
66173
|
+
const wanted = nfc(name);
|
|
66174
|
+
twin = (await client.list()).find((b) => nfc(b.path) === wanted)?.path;
|
|
66175
|
+
} catch {
|
|
66176
|
+
}
|
|
66177
|
+
if (twin !== void 0) {
|
|
66178
|
+
return { success: true, info: `Mailbox "${twin}" already existed.` };
|
|
66179
|
+
}
|
|
66136
66180
|
try {
|
|
66137
66181
|
const res = await client.mailboxCreate(name);
|
|
66138
66182
|
return res.created ? { success: true, info: `Created mailbox "${res.path}".` } : { success: true, info: `Mailbox "${res.path}" already existed.` };
|
|
@@ -66184,6 +66228,14 @@ function imapRenameMailbox(oldName, newName, deps = {}) {
|
|
|
66184
66228
|
};
|
|
66185
66229
|
}
|
|
66186
66230
|
const path = found.path;
|
|
66231
|
+
const wantedNew = nfc(newName);
|
|
66232
|
+
const clash = (await client.list()).find((b) => b.path !== path && nfc(b.path) === wantedNew);
|
|
66233
|
+
if (clash) {
|
|
66234
|
+
return {
|
|
66235
|
+
success: false,
|
|
66236
|
+
error: `Cannot rename "${path}" to "${newName}": mailbox "${clash.path}" already exists on IMAP account ${cfg.accountLabel} (the same name, differing only in how its accents are encoded).`
|
|
66237
|
+
};
|
|
66238
|
+
}
|
|
66187
66239
|
try {
|
|
66188
66240
|
const res = await client.mailboxRename(path, newName);
|
|
66189
66241
|
return { success: true, info: `Renamed "${res.path}" to "${res.newPath}" via IMAP.` };
|
|
@@ -66838,6 +66890,7 @@ var init_imapClient = __esm({
|
|
|
66838
66890
|
import_imapflow = __toESM(require_imap_flow(), 1);
|
|
66839
66891
|
init_smtpMailer();
|
|
66840
66892
|
init_docsUrls();
|
|
66893
|
+
init_mailboxName();
|
|
66841
66894
|
init_mimeParse();
|
|
66842
66895
|
init_headers();
|
|
66843
66896
|
init_auditLog();
|
|
@@ -81931,6 +81984,7 @@ function executeAppleScript(script, options = {}) {
|
|
|
81931
81984
|
init_docsUrls();
|
|
81932
81985
|
init_mimeParse();
|
|
81933
81986
|
init_headers();
|
|
81987
|
+
init_mailboxName();
|
|
81934
81988
|
|
|
81935
81989
|
// src/services/templateStore.ts
|
|
81936
81990
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
|
|
@@ -82566,23 +82620,28 @@ function mailboxLeaf(path) {
|
|
|
82566
82620
|
function resolveAppleMailboxPath(mailbox, actualPaths) {
|
|
82567
82621
|
if (actualPaths.length === 0) return mailbox;
|
|
82568
82622
|
const candidates = [mailbox, ...MAILBOX_ALIASES[mailbox.toLowerCase()] ?? []];
|
|
82623
|
+
const ambiguous = (matches) => {
|
|
82624
|
+
const sorted = [...new Set(matches)].sort();
|
|
82625
|
+
const paths = sorted.map((path) => `"${path}"`).join(" and ");
|
|
82626
|
+
const twins = new Set(sorted.map(mailboxNameKey)).size === 1;
|
|
82627
|
+
const hint = twins ? " They differ only in letter case or Unicode normalization (precomposed vs decomposed accents), so no typed name can tell them apart. Rename one of them." : " Pass the full path.";
|
|
82628
|
+
return new Error(`Mailbox "${mailbox}" is ambiguous \u2014 it matches ${paths}.${hint}`);
|
|
82629
|
+
};
|
|
82569
82630
|
for (const candidate of candidates) {
|
|
82570
82631
|
const exact = actualPaths.find((path) => path === candidate);
|
|
82571
82632
|
if (exact) return exact;
|
|
82572
|
-
const
|
|
82573
|
-
|
|
82633
|
+
const key = mailboxNameKey(candidate);
|
|
82634
|
+
const folded = [...new Set(actualPaths.filter((path) => mailboxNameKey(path) === key))];
|
|
82635
|
+
if (folded.length === 1) return folded[0];
|
|
82636
|
+
if (folded.length > 1) throw ambiguous(folded);
|
|
82574
82637
|
}
|
|
82575
82638
|
for (const candidate of candidates) {
|
|
82576
|
-
const
|
|
82577
|
-
|
|
82578
|
-
|
|
82639
|
+
const key = mailboxNameKey(candidate);
|
|
82640
|
+
const leafMatches = [
|
|
82641
|
+
...new Set(actualPaths.filter((path) => mailboxNameKey(mailboxLeaf(path)) === key))
|
|
82642
|
+
];
|
|
82579
82643
|
if (leafMatches.length === 1) return leafMatches[0];
|
|
82580
|
-
if (leafMatches.length > 1)
|
|
82581
|
-
const paths = [...leafMatches].sort().map((path) => `"${path}"`).join(" and ");
|
|
82582
|
-
throw new Error(
|
|
82583
|
-
`Mailbox "${mailbox}" is ambiguous \u2014 it matches ${paths}. Pass the full path.`
|
|
82584
|
-
);
|
|
82585
|
-
}
|
|
82644
|
+
if (leafMatches.length > 1) throw ambiguous(leafMatches);
|
|
82586
82645
|
}
|
|
82587
82646
|
return mailbox;
|
|
82588
82647
|
}
|
package/package.json
CHANGED