apple-mail-mcp 2.10.26 → 2.10.28
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 +20 -1
- package/build/cli.js +24 -2
- package/build/index.js +77 -19
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -358,12 +358,19 @@ fallback.
|
|
|
358
358
|
Configure SMTP via environment variables on the MCP server. The password is
|
|
359
359
|
read from the macOS **Keychain** by default, so no secret goes in config:
|
|
360
360
|
|
|
361
|
+
Non-implicit-TLS SMTP connections fail closed if STARTTLS is unavailable.
|
|
362
|
+
`APPLE_MAIL_MCP_SMTP_ALLOW_PLAINTEXT=1` is a deliberate escape hatch for a
|
|
363
|
+
trusted isolated server or test fixture; it disables the upgrade requirement and
|
|
364
|
+
can expose credentials and message content. The server emits a warning when it
|
|
365
|
+
is used. Keep the default unset.
|
|
366
|
+
|
|
361
367
|
| Variable | Required | Default | Description |
|
|
362
368
|
|----------|----------|---------|-------------|
|
|
363
369
|
| `APPLE_MAIL_MCP_SMTP_HOST` | Yes | — | SMTP server hostname (e.g. `smtp.fastmail.com`) |
|
|
364
370
|
| `APPLE_MAIL_MCP_SMTP_USER` | Yes | — | SMTP username |
|
|
365
371
|
| `APPLE_MAIL_MCP_SMTP_PORT` | No | `465` if secure, else `587` | SMTP port |
|
|
366
372
|
| `APPLE_MAIL_MCP_SMTP_SECURE` | No | `false` | `true` for implicit TLS (port 465); otherwise STARTTLS |
|
|
373
|
+
| `APPLE_MAIL_MCP_SMTP_ALLOW_PLAINTEXT` | No | `0` | Set `1` only for an explicitly trusted plaintext test/server; otherwise STARTTLS is required |
|
|
367
374
|
| `APPLE_MAIL_MCP_SMTP_FROM` | No | = user | From address |
|
|
368
375
|
| `APPLE_MAIL_MCP_SMTP_ALLOWED_FROM` | No | — | Comma-separated sender aliases permitted as per-message From overrides |
|
|
369
376
|
| `APPLE_MAIL_MCP_SMTP_PASSWORD` | No | — | Password (if set, used instead of the Keychain) |
|
|
@@ -480,6 +487,7 @@ for an explicitly-named IMAP account, never on an omitted account.
|
|
|
480
487
|
| `APPLE_MAIL_MCP_IMAP_ACCOUNT` | No | = user | Mail account name to match for routing |
|
|
481
488
|
| `APPLE_MAIL_MCP_IMAP_HOST` | No | `imap.gmail.com` | IMAP server hostname |
|
|
482
489
|
| `APPLE_MAIL_MCP_IMAP_PORT` | No | `993` | IMAP port (993 = implicit TLS) |
|
|
490
|
+
| `APPLE_MAIL_MCP_IMAP_ALLOW_PLAINTEXT` | No | `0` | Set `1` only for an explicitly trusted plaintext test/server; otherwise STARTTLS is required |
|
|
483
491
|
| `APPLE_MAIL_MCP_IMAP_PASSWORD` | No | — | Password (if set, used instead of the Keychain) |
|
|
484
492
|
| `APPLE_MAIL_MCP_IMAP_KEYCHAIN_SERVICE` | No | — | Keychain item service/server name |
|
|
485
493
|
| `APPLE_MAIL_MCP_IMAP_KEYCHAIN_ACCOUNT` | No | = user | Keychain item account |
|
|
@@ -495,6 +503,12 @@ Each entry accepts `account`, `user`, `host`, `port`, `password`, `keychainServi
|
|
|
495
503
|
`keychainAccount`. Calls route to the account matching their `account` argument (or the
|
|
496
504
|
decoded `imap:` id), and each account keeps its own pooled connection.
|
|
497
505
|
|
|
506
|
+
Non-implicit-TLS IMAP connections require STARTTLS and fail closed when the server
|
|
507
|
+
does not offer a usable upgrade. `APPLE_MAIL_MCP_IMAP_ALLOW_PLAINTEXT=1` is a
|
|
508
|
+
deliberate escape hatch for a trusted isolated server or test fixture; it disables
|
|
509
|
+
the upgrade requirement and can expose credentials and message content. Keep the
|
|
510
|
+
default unset.
|
|
511
|
+
|
|
498
512
|
As with SMTP, the password is read from the macOS **Keychain** by default (use
|
|
499
513
|
an app-specific password for Gmail/Workspace/iCloud), so no secret goes in
|
|
500
514
|
config. Gmail label semantics: common names (`All Mail`, `Sent`, `Trash`,
|
|
@@ -1085,10 +1099,15 @@ Create a Mail rule with one or more conditions and actions.
|
|
|
1085
1099
|
| `conditions` | object[] | Yes | One or more `{field, operator, value}` (see below) |
|
|
1086
1100
|
| `actions` | object | Yes | At least one of `markRead`, `markFlagged`, `delete`, `moveTo` |
|
|
1087
1101
|
| `matchAll` | boolean | No | `true` (default) = all conditions must match; `false` = any |
|
|
1088
|
-
| `enabled` | boolean | No | Whether the rule is enabled on creation (default `
|
|
1102
|
+
| `enabled` | boolean | No | Whether the rule is enabled on creation (default `false`) |
|
|
1089
1103
|
|
|
1090
1104
|
Each condition is `{ field, operator, value }` where `field` is one of `from`, `to`, `cc`, `subject`, `content` and `operator` is one of `contains`, `notContains`, `equals`, `beginsWith`, `endsWith`. Actions: `markRead` / `markFlagged` / `delete` (booleans), `moveTo` (mailbox name) with optional `moveToAccount`.
|
|
1091
1105
|
|
|
1106
|
+
New rules are created **disabled by default**, including rules that delete or move
|
|
1107
|
+
messages. Review the conditions and actions with `list-rules` and in Mail.app,
|
|
1108
|
+
then call `enable-rule` explicitly when the rule is approved. Set
|
|
1109
|
+
`enabled: true` only when immediate activation is deliberate.
|
|
1110
|
+
|
|
1092
1111
|
**Example:**
|
|
1093
1112
|
```json
|
|
1094
1113
|
{
|
package/build/cli.js
CHANGED
|
@@ -11919,6 +11919,7 @@ var SMTP_ENV = {
|
|
|
11919
11919
|
host: "APPLE_MAIL_MCP_SMTP_HOST",
|
|
11920
11920
|
port: "APPLE_MAIL_MCP_SMTP_PORT",
|
|
11921
11921
|
secure: "APPLE_MAIL_MCP_SMTP_SECURE",
|
|
11922
|
+
allowPlaintext: "APPLE_MAIL_MCP_SMTP_ALLOW_PLAINTEXT",
|
|
11922
11923
|
user: "APPLE_MAIL_MCP_SMTP_USER",
|
|
11923
11924
|
from: "APPLE_MAIL_MCP_SMTP_FROM",
|
|
11924
11925
|
allowedFrom: "APPLE_MAIL_MCP_SMTP_ALLOWED_FROM",
|
|
@@ -11969,7 +11970,17 @@ function resolveSmtpConfig(env = process.env) {
|
|
|
11969
11970
|
`No SMTP password found. Set ${SMTP_ENV.password}, or store an internet password in the Keychain for service "${env[SMTP_ENV.keychainService]?.trim() || host}" / account "${env[SMTP_ENV.keychainAccount]?.trim() || user}". ` + SETUP_HINT
|
|
11970
11971
|
);
|
|
11971
11972
|
}
|
|
11972
|
-
|
|
11973
|
+
const allowPlaintext = /^(1|true|yes|on)$/i.test(env[SMTP_ENV.allowPlaintext]?.trim() ?? "");
|
|
11974
|
+
return {
|
|
11975
|
+
host,
|
|
11976
|
+
port,
|
|
11977
|
+
secure,
|
|
11978
|
+
allowPlaintext,
|
|
11979
|
+
user,
|
|
11980
|
+
pass,
|
|
11981
|
+
from,
|
|
11982
|
+
allowedFrom
|
|
11983
|
+
};
|
|
11973
11984
|
}
|
|
11974
11985
|
function buildAttachments(attachments) {
|
|
11975
11986
|
if (!attachments || attachments.length === 0) return void 0;
|
|
@@ -12008,10 +12019,19 @@ async function sendViaSmtp(opts, config, createTransport = import_nodemailer.def
|
|
|
12008
12019
|
} catch (error) {
|
|
12009
12020
|
return { success: false, error: error instanceof Error ? error.message : String(error) };
|
|
12010
12021
|
}
|
|
12022
|
+
const requireTLS = !cfg.secure && !cfg.allowPlaintext;
|
|
12023
|
+
if (!cfg.secure && cfg.allowPlaintext) {
|
|
12024
|
+
console.warn(
|
|
12025
|
+
`SMTP plaintext explicitly enabled via ${SMTP_ENV.allowPlaintext}; credentials and message content may be exposed.`
|
|
12026
|
+
);
|
|
12027
|
+
}
|
|
12011
12028
|
const transporter = createTransport({
|
|
12012
12029
|
host: cfg.host,
|
|
12013
12030
|
port: cfg.port,
|
|
12014
12031
|
secure: cfg.secure,
|
|
12032
|
+
// Port 587/143-style configurations must not silently downgrade to
|
|
12033
|
+
// plaintext when the server advertises no usable TLS upgrade.
|
|
12034
|
+
requireTLS,
|
|
12015
12035
|
auth: { user: cfg.user, pass: cfg.pass }
|
|
12016
12036
|
});
|
|
12017
12037
|
const html = opts.htmlBody?.trim() ? opts.htmlBody : void 0;
|
|
@@ -12032,9 +12052,11 @@ async function sendViaSmtp(opts, config, createTransport = import_nodemailer.def
|
|
|
12032
12052
|
});
|
|
12033
12053
|
return { success: true, messageId: info.messageId };
|
|
12034
12054
|
} catch (error) {
|
|
12055
|
+
const detail = error instanceof Error ? error.message : String(error);
|
|
12056
|
+
const tlsHint = requireTLS ? ` STARTTLS is required for non-implicit TLS; to explicitly allow plaintext (not recommended), set ${SMTP_ENV.allowPlaintext}=1.` : "";
|
|
12035
12057
|
return {
|
|
12036
12058
|
success: false,
|
|
12037
|
-
error: `SMTP send failed: ${
|
|
12059
|
+
error: `SMTP send failed: ${detail}.${tlsHint}`
|
|
12038
12060
|
};
|
|
12039
12061
|
} finally {
|
|
12040
12062
|
transporter.close();
|
package/build/index.js
CHANGED
|
@@ -82068,7 +82068,7 @@ end tell`;
|
|
|
82068
82068
|
if (!actionStmts.length) {
|
|
82069
82069
|
return { success: false, error: "A rule needs at least one action." };
|
|
82070
82070
|
}
|
|
82071
|
-
const enabled = opts.enabled
|
|
82071
|
+
const enabled = opts.enabled === true;
|
|
82072
82072
|
const matchAll = opts.matchAll !== false;
|
|
82073
82073
|
const script = buildAppLevelScript(`
|
|
82074
82074
|
try
|
|
@@ -82446,6 +82446,7 @@ var SMTP_ENV = {
|
|
|
82446
82446
|
host: "APPLE_MAIL_MCP_SMTP_HOST",
|
|
82447
82447
|
port: "APPLE_MAIL_MCP_SMTP_PORT",
|
|
82448
82448
|
secure: "APPLE_MAIL_MCP_SMTP_SECURE",
|
|
82449
|
+
allowPlaintext: "APPLE_MAIL_MCP_SMTP_ALLOW_PLAINTEXT",
|
|
82449
82450
|
user: "APPLE_MAIL_MCP_SMTP_USER",
|
|
82450
82451
|
from: "APPLE_MAIL_MCP_SMTP_FROM",
|
|
82451
82452
|
allowedFrom: "APPLE_MAIL_MCP_SMTP_ALLOWED_FROM",
|
|
@@ -82506,7 +82507,17 @@ function resolveSmtpConfig(env = process.env) {
|
|
|
82506
82507
|
`No SMTP password found. Set ${SMTP_ENV.password}, or store an internet password in the Keychain for service "${env[SMTP_ENV.keychainService]?.trim() || host}" / account "${env[SMTP_ENV.keychainAccount]?.trim() || user}". ` + SETUP_HINT
|
|
82507
82508
|
);
|
|
82508
82509
|
}
|
|
82509
|
-
|
|
82510
|
+
const allowPlaintext = /^(1|true|yes|on)$/i.test(env[SMTP_ENV.allowPlaintext]?.trim() ?? "");
|
|
82511
|
+
return {
|
|
82512
|
+
host,
|
|
82513
|
+
port,
|
|
82514
|
+
secure,
|
|
82515
|
+
allowPlaintext,
|
|
82516
|
+
user,
|
|
82517
|
+
pass,
|
|
82518
|
+
from,
|
|
82519
|
+
allowedFrom
|
|
82520
|
+
};
|
|
82510
82521
|
}
|
|
82511
82522
|
function buildAttachments(attachments) {
|
|
82512
82523
|
if (!attachments || attachments.length === 0) return void 0;
|
|
@@ -82545,10 +82556,19 @@ async function sendViaSmtp(opts, config2, createTransport = import_nodemailer.de
|
|
|
82545
82556
|
} catch (error2) {
|
|
82546
82557
|
return { success: false, error: error2 instanceof Error ? error2.message : String(error2) };
|
|
82547
82558
|
}
|
|
82559
|
+
const requireTLS = !cfg.secure && !cfg.allowPlaintext;
|
|
82560
|
+
if (!cfg.secure && cfg.allowPlaintext) {
|
|
82561
|
+
console.warn(
|
|
82562
|
+
`SMTP plaintext explicitly enabled via ${SMTP_ENV.allowPlaintext}; credentials and message content may be exposed.`
|
|
82563
|
+
);
|
|
82564
|
+
}
|
|
82548
82565
|
const transporter = createTransport({
|
|
82549
82566
|
host: cfg.host,
|
|
82550
82567
|
port: cfg.port,
|
|
82551
82568
|
secure: cfg.secure,
|
|
82569
|
+
// Port 587/143-style configurations must not silently downgrade to
|
|
82570
|
+
// plaintext when the server advertises no usable TLS upgrade.
|
|
82571
|
+
requireTLS,
|
|
82552
82572
|
auth: { user: cfg.user, pass: cfg.pass }
|
|
82553
82573
|
});
|
|
82554
82574
|
const html = opts.htmlBody?.trim() ? opts.htmlBody : void 0;
|
|
@@ -82569,9 +82589,11 @@ async function sendViaSmtp(opts, config2, createTransport = import_nodemailer.de
|
|
|
82569
82589
|
});
|
|
82570
82590
|
return { success: true, messageId: info.messageId };
|
|
82571
82591
|
} catch (error2) {
|
|
82592
|
+
const detail = error2 instanceof Error ? error2.message : String(error2);
|
|
82593
|
+
const tlsHint = requireTLS ? ` STARTTLS is required for non-implicit TLS; to explicitly allow plaintext (not recommended), set ${SMTP_ENV.allowPlaintext}=1.` : "";
|
|
82572
82594
|
return {
|
|
82573
82595
|
success: false,
|
|
82574
|
-
error: `SMTP send failed: ${
|
|
82596
|
+
error: `SMTP send failed: ${detail}.${tlsHint}`
|
|
82575
82597
|
};
|
|
82576
82598
|
} finally {
|
|
82577
82599
|
transporter.close();
|
|
@@ -82744,6 +82766,7 @@ var IMAP_ENV = {
|
|
|
82744
82766
|
password: "APPLE_MAIL_MCP_IMAP_PASSWORD",
|
|
82745
82767
|
keychainService: "APPLE_MAIL_MCP_IMAP_KEYCHAIN_SERVICE",
|
|
82746
82768
|
keychainAccount: "APPLE_MAIL_MCP_IMAP_KEYCHAIN_ACCOUNT",
|
|
82769
|
+
allowPlaintext: "APPLE_MAIL_MCP_IMAP_ALLOW_PLAINTEXT",
|
|
82747
82770
|
// C2 multi-account: JSON array of additional accounts, e.g.
|
|
82748
82771
|
// [{"account":"Work","user":"me@co.com","host":"imap.co.com","keychainService":"imap.co.com"}]
|
|
82749
82772
|
accounts: "APPLE_MAIL_MCP_IMAP_ACCOUNTS"
|
|
@@ -82784,6 +82807,9 @@ function depsForAccount(account, deps) {
|
|
|
82784
82807
|
function depsForMessageRef(ref, deps) {
|
|
82785
82808
|
return depsForAccount(ref.account, deps);
|
|
82786
82809
|
}
|
|
82810
|
+
function isTruthySetting(value) {
|
|
82811
|
+
return /^(1|true|yes|on)$/i.test(value?.trim() ?? "");
|
|
82812
|
+
}
|
|
82787
82813
|
function specMatchesSelector(spec, selector) {
|
|
82788
82814
|
return spec.accountLabel === selector || spec.user === selector || (spec.aliases?.includes(selector) ?? false);
|
|
82789
82815
|
}
|
|
@@ -82849,7 +82875,7 @@ function listImapAccountSpecs(env = process.env) {
|
|
|
82849
82875
|
}
|
|
82850
82876
|
return specs;
|
|
82851
82877
|
}
|
|
82852
|
-
function specToConfig(spec) {
|
|
82878
|
+
function specToConfig(spec, allowPlaintext = false) {
|
|
82853
82879
|
if (!Number.isInteger(spec.port) || spec.port <= 0) {
|
|
82854
82880
|
throw new Error(`Invalid IMAP port for account "${spec.accountLabel}": "${spec.port}".`);
|
|
82855
82881
|
}
|
|
@@ -82866,6 +82892,7 @@ function specToConfig(spec) {
|
|
|
82866
82892
|
host: spec.host,
|
|
82867
82893
|
port: spec.port,
|
|
82868
82894
|
secure: spec.port === 993,
|
|
82895
|
+
allowPlaintext,
|
|
82869
82896
|
user: spec.user,
|
|
82870
82897
|
pass,
|
|
82871
82898
|
accountLabel: spec.accountLabel
|
|
@@ -82883,9 +82910,10 @@ function listImapAccountLabels(env = process.env) {
|
|
|
82883
82910
|
}
|
|
82884
82911
|
function resolveImapConfigs(env = process.env) {
|
|
82885
82912
|
const out = [];
|
|
82913
|
+
const allowPlaintext = isTruthySetting(env[IMAP_ENV.allowPlaintext]);
|
|
82886
82914
|
for (const spec of listImapAccountSpecs(env)) {
|
|
82887
82915
|
try {
|
|
82888
|
-
out.push(specToConfig(spec));
|
|
82916
|
+
out.push(specToConfig(spec, allowPlaintext));
|
|
82889
82917
|
} catch (e) {
|
|
82890
82918
|
console.error(`Skipping IMAP account "${spec.accountLabel}": ${String(e)}`);
|
|
82891
82919
|
}
|
|
@@ -82910,19 +82938,45 @@ function resolveImapConfig(env = process.env, account) {
|
|
|
82910
82938
|
} else {
|
|
82911
82939
|
spec = specs[0];
|
|
82912
82940
|
}
|
|
82913
|
-
return specToConfig(spec);
|
|
82941
|
+
return specToConfig(spec, isTruthySetting(env[IMAP_ENV.allowPlaintext]));
|
|
82914
82942
|
}
|
|
82915
|
-
|
|
82916
|
-
|
|
82943
|
+
function buildImapConnectionOptions(cfg) {
|
|
82944
|
+
return {
|
|
82917
82945
|
host: cfg.host,
|
|
82918
82946
|
port: cfg.port,
|
|
82919
82947
|
secure: cfg.secure,
|
|
82948
|
+
// ImapFlow reads this as a tri-state, and the distinction matters:
|
|
82949
|
+
// true -> require STARTTLS; fail if the server does not offer it
|
|
82950
|
+
// false -> NEVER STARTTLS, even if the server advertises it
|
|
82951
|
+
// undefined -> opportunistic upgrade (ImapFlow's documented default)
|
|
82952
|
+
//
|
|
82953
|
+
// secure=true already has implicit TLS, so there is no upgrade to negotiate.
|
|
82954
|
+
// Without the escape hatch the upgrade is required. WITH it we must fall back
|
|
82955
|
+
// to `undefined`, not `false`: the escape hatch means "let me reach a server
|
|
82956
|
+
// that cannot do TLS", not "never encrypt". Sending `false` suppressed the
|
|
82957
|
+
// upgrade even against servers still offering it, so enabling the opt-out for
|
|
82958
|
+
// one broken account silently downgraded every other plaintext-port account
|
|
82959
|
+
// below what it already negotiated before this option existed.
|
|
82960
|
+
doSTARTTLS: cfg.secure || cfg.allowPlaintext ? void 0 : true,
|
|
82920
82961
|
auth: { user: cfg.user, pass: cfg.pass },
|
|
82921
82962
|
logger: false
|
|
82922
|
-
}
|
|
82963
|
+
};
|
|
82964
|
+
}
|
|
82965
|
+
var defaultConnect = async (cfg) => {
|
|
82966
|
+
const client = new import_imapflow.ImapFlow(buildImapConnectionOptions(cfg));
|
|
82923
82967
|
client.on("error", () => {
|
|
82924
82968
|
});
|
|
82925
|
-
|
|
82969
|
+
try {
|
|
82970
|
+
await client.connect();
|
|
82971
|
+
} catch (error2) {
|
|
82972
|
+
if (!cfg.secure && !cfg.allowPlaintext) {
|
|
82973
|
+
const detail = error2 instanceof Error ? error2.message : String(error2);
|
|
82974
|
+
throw new Error(
|
|
82975
|
+
`IMAP connection failed: ${detail}. STARTTLS is required for non-implicit TLS; to explicitly allow plaintext (not recommended), set ${IMAP_ENV.allowPlaintext}=1.`
|
|
82976
|
+
);
|
|
82977
|
+
}
|
|
82978
|
+
throw error2;
|
|
82979
|
+
}
|
|
82926
82980
|
return client;
|
|
82927
82981
|
};
|
|
82928
82982
|
function resolveMailboxPath(mailbox, mode) {
|
|
@@ -84214,16 +84268,20 @@ function subjectFromGetMessage(info) {
|
|
|
84214
84268
|
// src/services/imapIdle.ts
|
|
84215
84269
|
var import_imapflow2 = __toESM(require_imap_flow(), 1);
|
|
84216
84270
|
var defaultIdleConnect = async (cfg) => {
|
|
84217
|
-
const client = new import_imapflow2.ImapFlow(
|
|
84218
|
-
host: cfg.host,
|
|
84219
|
-
port: cfg.port,
|
|
84220
|
-
secure: cfg.secure,
|
|
84221
|
-
auth: { user: cfg.user, pass: cfg.pass },
|
|
84222
|
-
logger: false
|
|
84223
|
-
});
|
|
84271
|
+
const client = new import_imapflow2.ImapFlow(buildImapConnectionOptions(cfg));
|
|
84224
84272
|
client.on("error", () => {
|
|
84225
84273
|
});
|
|
84226
|
-
|
|
84274
|
+
try {
|
|
84275
|
+
await client.connect();
|
|
84276
|
+
} catch (error2) {
|
|
84277
|
+
if (!cfg.secure && !cfg.allowPlaintext) {
|
|
84278
|
+
const detail = error2 instanceof Error ? error2.message : String(error2);
|
|
84279
|
+
throw new Error(
|
|
84280
|
+
`IMAP IDLE connection failed: ${detail}. STARTTLS is required for non-implicit TLS; to explicitly allow plaintext (not recommended), set ${IMAP_ENV.allowPlaintext}=1.`
|
|
84281
|
+
);
|
|
84282
|
+
}
|
|
84283
|
+
throw error2;
|
|
84284
|
+
}
|
|
84227
84285
|
return client;
|
|
84228
84286
|
};
|
|
84229
84287
|
var ImapIdleWatcher = class {
|
|
@@ -86249,7 +86307,7 @@ registerTool(
|
|
|
86249
86307
|
"At least one action is required (markRead, markFlagged, delete, or moveTo)"
|
|
86250
86308
|
),
|
|
86251
86309
|
matchAll: external_exports.boolean().default(true),
|
|
86252
|
-
enabled: external_exports.boolean().default(
|
|
86310
|
+
enabled: external_exports.boolean().default(false).describe("Enable immediately; defaults to false so the rule must be reviewed first")
|
|
86253
86311
|
},
|
|
86254
86312
|
outputSchema: {
|
|
86255
86313
|
name: external_exports.string().optional(),
|
package/package.json
CHANGED