@wraps.dev/cli 2.18.5 → 2.18.7
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/cli.js +196 -25
- package/dist/cli.js.map +1 -1
- package/dist/console/assets/avif_enc-_C3kZEkJ.js +2 -0
- package/dist/console/assets/avif_enc_mt-CMxXiuUp.js +2 -0
- package/dist/console/assets/avif_enc_mt-CZ_pikvB.js +2 -0
- package/dist/console/assets/avif_enc_mt.worker-a9dNT6Io.js +1 -0
- package/dist/console/assets/index-BGDIROiI.css +1 -0
- package/dist/console/assets/{index-CNmw7YHP.js → index-C0zX5_O9.js} +1 -1
- package/dist/console/assets/{index-Ccg-KFP7.js → index-CRudvOG_.js} +1 -1
- package/dist/console/assets/index-Cto6vYr9.js +2 -0
- package/dist/console/assets/index-dD2Skj3E.js +127 -0
- package/dist/console/assets/{optimizer.worker-CeufIUo5.js → optimizer.worker-DZcD7Kza.js} +1 -1
- package/dist/console/index.html +2 -2
- package/dist/lambda/event-processor/.bundled +1 -1
- package/dist/lambda/inbound-processor/.bundled +1 -1
- package/dist/lambda/sms-event-processor/.bundled +1 -1
- package/package.json +1 -1
- package/dist/console/assets/avif_enc-GHSQWwbh.js +0 -2
- package/dist/console/assets/avif_enc_mt-BB9NYOXn.js +0 -2
- package/dist/console/assets/avif_enc_mt-DL2yi-mK.js +0 -2
- package/dist/console/assets/avif_enc_mt.worker-DASj3syc.js +0 -1
- package/dist/console/assets/index-41T2hONy.js +0 -497
- package/dist/console/assets/index-Cjum_-Wu.js +0 -2
- package/dist/console/assets/index-DF7apuYC.css +0 -1
package/dist/cli.js
CHANGED
|
@@ -1252,6 +1252,7 @@ var init_aws_detection = __esm({
|
|
|
1252
1252
|
var errors_exports = {};
|
|
1253
1253
|
__export(errors_exports, {
|
|
1254
1254
|
WrapsError: () => WrapsError,
|
|
1255
|
+
awsErrorToWrapsError: () => awsErrorToWrapsError,
|
|
1255
1256
|
classifyDNSError: () => classifyDNSError,
|
|
1256
1257
|
errors: () => errors,
|
|
1257
1258
|
handleCLIError: () => handleCLIError,
|
|
@@ -1408,7 +1409,7 @@ function handleCLIError(error, command) {
|
|
|
1408
1409
|
const parsed = parseAWSError(error);
|
|
1409
1410
|
code = `AWS_${parsed.code}`;
|
|
1410
1411
|
trackError(code, cmdContext, { action: parsed.action });
|
|
1411
|
-
const wrapsErr = awsErrorToWrapsError(parsed.code, parsed.action);
|
|
1412
|
+
const wrapsErr = awsErrorToWrapsError(parsed.code, parsed.action, error);
|
|
1412
1413
|
message = wrapsErr.message;
|
|
1413
1414
|
suggestion = wrapsErr.suggestion;
|
|
1414
1415
|
docsUrl = wrapsErr.docsUrl;
|
|
@@ -1463,7 +1464,7 @@ ${pc5.yellow("Suggestion:")}`);
|
|
|
1463
1464
|
if (isAWSError(error)) {
|
|
1464
1465
|
const { code, action } = parseAWSError(error);
|
|
1465
1466
|
trackError(`AWS_${code}`, cmdContext, { action });
|
|
1466
|
-
const wrapsError = awsErrorToWrapsError(code, action);
|
|
1467
|
+
const wrapsError = awsErrorToWrapsError(code, action, error);
|
|
1467
1468
|
clack4.log.error(wrapsError.message);
|
|
1468
1469
|
if (wrapsError.suggestion) {
|
|
1469
1470
|
console.log(`
|
|
@@ -1528,8 +1529,9 @@ ${pc5.dim("If this persists, please report at:")}`);
|
|
|
1528
1529
|
`);
|
|
1529
1530
|
process.exit(1);
|
|
1530
1531
|
}
|
|
1531
|
-
function awsErrorToWrapsError(code, action) {
|
|
1532
|
+
function awsErrorToWrapsError(code, action, originalError) {
|
|
1532
1533
|
switch (code) {
|
|
1534
|
+
// Credential / token errors — these mean the request never reached the API
|
|
1533
1535
|
case "ExpiredTokenException":
|
|
1534
1536
|
case "TokenRefreshRequired":
|
|
1535
1537
|
case "SSOTokenExpired":
|
|
@@ -1537,7 +1539,9 @@ function awsErrorToWrapsError(code, action) {
|
|
|
1537
1539
|
case "InvalidClientTokenId":
|
|
1538
1540
|
case "InvalidAccessKeyId":
|
|
1539
1541
|
case "SignatureDoesNotMatch":
|
|
1542
|
+
case "UnrecognizedClientException":
|
|
1540
1543
|
return errors.accessKeyInvalid();
|
|
1544
|
+
// IAM permission errors — request reached AWS but was denied
|
|
1541
1545
|
case "AccessDenied":
|
|
1542
1546
|
case "AccessDeniedException":
|
|
1543
1547
|
case "UnauthorizedAccess":
|
|
@@ -1546,8 +1550,35 @@ function awsErrorToWrapsError(code, action) {
|
|
|
1546
1550
|
"AWS resource",
|
|
1547
1551
|
"Ensure your IAM user/role has the required permissions."
|
|
1548
1552
|
);
|
|
1553
|
+
// SES SendEmail errors — request reached SES but was rejected
|
|
1554
|
+
case "MessageRejected":
|
|
1555
|
+
return errors.sesMessageRejected(sanitizeErrorMessage(originalError));
|
|
1556
|
+
case "MailFromDomainNotVerifiedException":
|
|
1557
|
+
return errors.sesMailFromNotVerified(sanitizeErrorMessage(originalError));
|
|
1558
|
+
case "AccountSendingPausedException":
|
|
1559
|
+
return errors.sesAccountSendingPaused();
|
|
1560
|
+
case "ConfigurationSetSendingPausedException":
|
|
1561
|
+
return errors.sesConfigSetSendingPaused();
|
|
1562
|
+
case "ConfigurationSetDoesNotExistException":
|
|
1563
|
+
return errors.sesConfigSetMissing(sanitizeErrorMessage(originalError));
|
|
1564
|
+
// Throughput / quota errors
|
|
1565
|
+
case "Throttling":
|
|
1566
|
+
case "ThrottlingException":
|
|
1567
|
+
case "TooManyRequestsException":
|
|
1568
|
+
return errors.awsThrottled(action);
|
|
1569
|
+
case "LimitExceededException":
|
|
1570
|
+
case "ServiceQuotaExceededException":
|
|
1571
|
+
return errors.awsLimitExceeded(
|
|
1572
|
+
action,
|
|
1573
|
+
sanitizeErrorMessage(originalError)
|
|
1574
|
+
);
|
|
1575
|
+
// Anything else — surface the real error instead of lying about credentials
|
|
1549
1576
|
default:
|
|
1550
|
-
return errors.
|
|
1577
|
+
return errors.awsUnknownError(
|
|
1578
|
+
code,
|
|
1579
|
+
action,
|
|
1580
|
+
sanitizeErrorMessage(originalError)
|
|
1581
|
+
);
|
|
1551
1582
|
}
|
|
1552
1583
|
}
|
|
1553
1584
|
function pulumiErrorToWrapsError(code, iamAction, service, resourceName, resourceType) {
|
|
@@ -1747,6 +1778,61 @@ View required SES permissions:
|
|
|
1747
1778
|
wraps permissions --service email --json`,
|
|
1748
1779
|
"https://wraps.dev/docs/guides/aws-setup/permissions"
|
|
1749
1780
|
),
|
|
1781
|
+
// SES SendEmail rejection errors — request reached SES but the send failed
|
|
1782
|
+
// for a reason unrelated to credentials.
|
|
1783
|
+
sesMessageRejected: (detail) => new WrapsError(
|
|
1784
|
+
`SES rejected the message: ${detail}`,
|
|
1785
|
+
"SES_MESSAGE_REJECTED",
|
|
1786
|
+
"Common causes:\n \u2022 Account is in the SES sandbox and the recipient is not a verified address\n \u2022 Sender identity (domain or email) is not verified for sending\n \u2022 The sender domain is verified for receiving but not for sending\n\nCheck status:\n wraps email status\n wraps email doctor\n\nRequest production access (exit sandbox):\n https://docs.aws.amazon.com/ses/latest/dg/request-production-access.html",
|
|
1787
|
+
"https://wraps.dev/docs/guides/email/troubleshooting"
|
|
1788
|
+
),
|
|
1789
|
+
sesMailFromNotVerified: (detail) => new WrapsError(
|
|
1790
|
+
`SES MAIL FROM domain is not verified: ${detail}`,
|
|
1791
|
+
"SES_MAIL_FROM_NOT_VERIFIED",
|
|
1792
|
+
"The custom MAIL FROM domain configured for this identity is not fully verified.\n\nCheck DNS records:\n wraps email verify\n\nOr remove the custom MAIL FROM domain in the SES console and retry.",
|
|
1793
|
+
"https://docs.aws.amazon.com/ses/latest/dg/mail-from.html"
|
|
1794
|
+
),
|
|
1795
|
+
sesAccountSendingPaused: () => new WrapsError(
|
|
1796
|
+
"SES account-level sending is paused",
|
|
1797
|
+
"SES_ACCOUNT_SENDING_PAUSED",
|
|
1798
|
+
"Your SES account is currently paused from sending email. This is usually caused by:\n \u2022 A high bounce or complaint rate\n \u2022 An AWS-initiated review\n\nCheck the SES console \u2192 Reputation Dashboard for details, then resume sending once the issue is resolved.",
|
|
1799
|
+
"https://docs.aws.amazon.com/ses/latest/dg/reputationdashboard.html"
|
|
1800
|
+
),
|
|
1801
|
+
sesConfigSetSendingPaused: () => new WrapsError(
|
|
1802
|
+
"SES configuration set sending is paused",
|
|
1803
|
+
"SES_CONFIG_SET_SENDING_PAUSED",
|
|
1804
|
+
"The configuration set used for this send has sending paused. Resume it in the SES console under Configuration Sets, or send without specifying the paused configuration set.",
|
|
1805
|
+
"https://docs.aws.amazon.com/ses/latest/dg/using-configuration-sets.html"
|
|
1806
|
+
),
|
|
1807
|
+
sesConfigSetMissing: (detail) => new WrapsError(
|
|
1808
|
+
`SES configuration set does not exist: ${detail}`,
|
|
1809
|
+
"SES_CONFIG_SET_MISSING",
|
|
1810
|
+
"The configuration set referenced by this send does not exist in the current region. Create it in the SES console, switch regions, or remove the ConfigurationSetName from the request.",
|
|
1811
|
+
"https://docs.aws.amazon.com/ses/latest/dg/using-configuration-sets.html"
|
|
1812
|
+
),
|
|
1813
|
+
// Generic AWS error fallbacks — used by awsErrorToWrapsError when no specific
|
|
1814
|
+
// mapping exists. These NEVER claim credentials are missing.
|
|
1815
|
+
awsThrottled: (action) => new WrapsError(
|
|
1816
|
+
`AWS request was throttled${action ? ` (${action})` : ""}`,
|
|
1817
|
+
"AWS_THROTTLED",
|
|
1818
|
+
"AWS is rate-limiting requests to this API. Wait a moment and retry.\n\nIf this happens repeatedly, request a service quota increase in the AWS console.",
|
|
1819
|
+
"https://docs.aws.amazon.com/general/latest/gr/api-retries.html"
|
|
1820
|
+
),
|
|
1821
|
+
awsLimitExceeded: (action, detail) => new WrapsError(
|
|
1822
|
+
`AWS service limit exceeded${action ? ` (${action})` : ""}${detail ? `: ${detail}` : ""}`,
|
|
1823
|
+
"AWS_LIMIT_EXCEEDED",
|
|
1824
|
+
"You've hit a service quota for this AWS API.\n\nRequest a quota increase in the AWS console:\n Service Quotas \u2192 AWS Services \u2192 (your service)",
|
|
1825
|
+
"https://docs.aws.amazon.com/general/latest/gr/aws_service_limits.html"
|
|
1826
|
+
),
|
|
1827
|
+
awsUnknownError: (code, action, detail) => new WrapsError(
|
|
1828
|
+
`AWS API error: ${code}${action ? ` (${action})` : ""}${detail ? ` \u2014 ${detail}` : ""}`,
|
|
1829
|
+
`AWS_${code}`,
|
|
1830
|
+
`This is an AWS API error, not a credentials problem. Look up "${code}" in the AWS documentation for the failing service.
|
|
1831
|
+
|
|
1832
|
+
If you believe this is a Wraps bug, report it at:
|
|
1833
|
+
https://github.com/wraps-team/wraps/issues`,
|
|
1834
|
+
"https://wraps.dev/docs/guides/aws-setup/troubleshooting"
|
|
1835
|
+
),
|
|
1750
1836
|
dynamoDBPermissionDenied: () => new WrapsError(
|
|
1751
1837
|
"DynamoDB permission denied",
|
|
1752
1838
|
"DYNAMODB_PERMISSION_DENIED",
|
|
@@ -18406,8 +18492,11 @@ async function connect2(options) {
|
|
|
18406
18492
|
try {
|
|
18407
18493
|
const ids = await scanSESIdentities(r);
|
|
18408
18494
|
return ids.length > 0 ? r : null;
|
|
18409
|
-
} catch {
|
|
18410
|
-
|
|
18495
|
+
} catch (error) {
|
|
18496
|
+
if (error instanceof Error && (error.name === "AccessDeniedException" || error.name === "UnrecognizedClientException" || error.message.includes("is not authorized"))) {
|
|
18497
|
+
return null;
|
|
18498
|
+
}
|
|
18499
|
+
throw error;
|
|
18411
18500
|
}
|
|
18412
18501
|
})
|
|
18413
18502
|
);
|
|
@@ -21086,6 +21175,77 @@ Enable it: ${pc24.cyan("wraps email inbound init")}
|
|
|
21086
21175
|
}
|
|
21087
21176
|
console.log();
|
|
21088
21177
|
}
|
|
21178
|
+
var NOT_VERIFIED_PATTERN = /not verified/i;
|
|
21179
|
+
function mapInboundTestSendError(error, ctx) {
|
|
21180
|
+
if (error instanceof WrapsError) {
|
|
21181
|
+
return error;
|
|
21182
|
+
}
|
|
21183
|
+
if (!(error instanceof Error)) {
|
|
21184
|
+
return new WrapsError(
|
|
21185
|
+
`Failed to send inbound test email to ${ctx.recipient}`,
|
|
21186
|
+
"INBOUND_TEST_SEND_FAILED",
|
|
21187
|
+
"An unexpected error occurred while sending the test email.\n\nCheck infrastructure status:\n wraps email status\n wraps email doctor",
|
|
21188
|
+
"https://wraps.dev/docs/guides/email/troubleshooting"
|
|
21189
|
+
);
|
|
21190
|
+
}
|
|
21191
|
+
const name = error.name;
|
|
21192
|
+
const message = error.message || "";
|
|
21193
|
+
if (name === "MailFromDomainNotVerifiedException") {
|
|
21194
|
+
return new WrapsError(
|
|
21195
|
+
`Custom MAIL FROM domain is not verified for ${ctx.domain}`,
|
|
21196
|
+
"INBOUND_TEST_MAIL_FROM_NOT_VERIFIED",
|
|
21197
|
+
`The MAIL FROM domain configured for "${ctx.domain}" is not fully verified.
|
|
21198
|
+
|
|
21199
|
+
Verify DNS records:
|
|
21200
|
+
wraps email verify
|
|
21201
|
+
|
|
21202
|
+
Or remove the custom MAIL FROM domain in the SES console and retry.`,
|
|
21203
|
+
"https://docs.aws.amazon.com/ses/latest/dg/mail-from.html"
|
|
21204
|
+
);
|
|
21205
|
+
}
|
|
21206
|
+
if (name === "MessageRejected" || name === "InvalidParameterValue" || NOT_VERIFIED_PATTERN.test(message)) {
|
|
21207
|
+
return new WrapsError(
|
|
21208
|
+
`SES rejected the inbound test send: ${message || name}`,
|
|
21209
|
+
"INBOUND_TEST_MESSAGE_REJECTED",
|
|
21210
|
+
[
|
|
21211
|
+
`Tried to send: ${ctx.source} \u2192 ${ctx.recipient} (region ${ctx.region})`,
|
|
21212
|
+
"",
|
|
21213
|
+
"Most likely causes:",
|
|
21214
|
+
` \u2022 Your SES account is in the sandbox and ${ctx.recipient} is not a verified address`,
|
|
21215
|
+
` \u2022 The sender domain "${ctx.domain}" is not verified for sending in ${ctx.region}`,
|
|
21216
|
+
` \u2022 The receiving domain "${ctx.receivingDomain}" is verified for receiving (MX) but not for sending`,
|
|
21217
|
+
"",
|
|
21218
|
+
"Check status:",
|
|
21219
|
+
" wraps email status",
|
|
21220
|
+
" wraps email doctor",
|
|
21221
|
+
"",
|
|
21222
|
+
"Exit the SES sandbox to send to any address:",
|
|
21223
|
+
" https://docs.aws.amazon.com/ses/latest/dg/request-production-access.html"
|
|
21224
|
+
].join("\n"),
|
|
21225
|
+
"https://wraps.dev/docs/guides/email/troubleshooting"
|
|
21226
|
+
);
|
|
21227
|
+
}
|
|
21228
|
+
if (name === "AccountSendingPausedException" || name === "ConfigurationSetSendingPausedException") {
|
|
21229
|
+
return new WrapsError(
|
|
21230
|
+
"SES sending is paused for this account",
|
|
21231
|
+
"INBOUND_TEST_SENDING_PAUSED",
|
|
21232
|
+
"Your SES account or configuration set has sending paused, usually due to a high bounce or complaint rate.\n\nCheck the SES Reputation Dashboard in the AWS console and resume sending once the issue is resolved.",
|
|
21233
|
+
"https://docs.aws.amazon.com/ses/latest/dg/reputationdashboard.html"
|
|
21234
|
+
);
|
|
21235
|
+
}
|
|
21236
|
+
if (name === "AccessDeniedException" || name === "AccessDenied") {
|
|
21237
|
+
return new WrapsError(
|
|
21238
|
+
`IAM permission denied: ses:SendEmail in ${ctx.region}`,
|
|
21239
|
+
"INBOUND_TEST_PERMISSION_DENIED",
|
|
21240
|
+
`Your AWS credentials lack the "ses:SendEmail" permission in region ${ctx.region}.
|
|
21241
|
+
|
|
21242
|
+
View required SES permissions:
|
|
21243
|
+
wraps permissions --service email --json`,
|
|
21244
|
+
"https://wraps.dev/docs/guides/aws-setup/permissions"
|
|
21245
|
+
);
|
|
21246
|
+
}
|
|
21247
|
+
return error;
|
|
21248
|
+
}
|
|
21089
21249
|
async function inboundTest(options) {
|
|
21090
21250
|
if (!isJsonMode()) {
|
|
21091
21251
|
clack22.intro(pc24.bold("Inbound Email Test"));
|
|
@@ -21109,34 +21269,45 @@ Enable it: ${pc24.cyan("wraps email inbound init")}
|
|
|
21109
21269
|
const receivingDomain = inbound.receivingDomain || (inbound.subdomain ? `${inbound.subdomain}.${emailConfig.domain}` : emailConfig.domain || "");
|
|
21110
21270
|
const bucketName = inbound.bucketName || `wraps-inbound-${identity.accountId}-${region}`;
|
|
21111
21271
|
const testRecipient = `test@${receivingDomain}`;
|
|
21272
|
+
const testSource = `test@${emailConfig.domain}`;
|
|
21112
21273
|
const testSubject = `Wraps Inbound Test - ${(/* @__PURE__ */ new Date()).toISOString()}`;
|
|
21113
21274
|
await progress.execute(`Sending test email to ${testRecipient}`, async () => {
|
|
21114
21275
|
const { SESClient: SESClient7, SendEmailCommand: SendEmailCommand2 } = await import("@aws-sdk/client-ses");
|
|
21115
21276
|
const ses = new SESClient7({ region });
|
|
21116
|
-
|
|
21117
|
-
|
|
21118
|
-
|
|
21119
|
-
|
|
21120
|
-
|
|
21121
|
-
|
|
21122
|
-
|
|
21123
|
-
|
|
21124
|
-
|
|
21125
|
-
|
|
21126
|
-
|
|
21127
|
-
|
|
21128
|
-
|
|
21129
|
-
|
|
21277
|
+
try {
|
|
21278
|
+
await ses.send(
|
|
21279
|
+
new SendEmailCommand2({
|
|
21280
|
+
Source: testSource,
|
|
21281
|
+
Destination: {
|
|
21282
|
+
ToAddresses: [testRecipient]
|
|
21283
|
+
},
|
|
21284
|
+
Message: {
|
|
21285
|
+
Subject: { Data: testSubject },
|
|
21286
|
+
Body: {
|
|
21287
|
+
Text: {
|
|
21288
|
+
Data: "This is a test email from Wraps CLI to verify inbound email processing."
|
|
21289
|
+
},
|
|
21290
|
+
Html: {
|
|
21291
|
+
Data: "<h1>Wraps Inbound Test</h1><p>This email was sent to verify inbound email processing is working correctly.</p>"
|
|
21292
|
+
}
|
|
21130
21293
|
}
|
|
21131
21294
|
}
|
|
21132
|
-
}
|
|
21133
|
-
|
|
21134
|
-
)
|
|
21295
|
+
})
|
|
21296
|
+
);
|
|
21297
|
+
} catch (error) {
|
|
21298
|
+
throw mapInboundTestSendError(error, {
|
|
21299
|
+
source: testSource,
|
|
21300
|
+
recipient: testRecipient,
|
|
21301
|
+
domain: emailConfig.domain || "",
|
|
21302
|
+
receivingDomain,
|
|
21303
|
+
region
|
|
21304
|
+
});
|
|
21305
|
+
}
|
|
21135
21306
|
});
|
|
21136
|
-
const spinner10 = clack22.spinner();
|
|
21137
|
-
spinner10.start("Waiting for email to be processed...");
|
|
21138
21307
|
const { S3Client: S3Client2, ListObjectsV2Command: ListObjectsV2Command2, GetObjectCommand: GetObjectCommand2 } = await import("@aws-sdk/client-s3");
|
|
21139
21308
|
const s34 = new S3Client2({ region });
|
|
21309
|
+
const spinner10 = clack22.spinner();
|
|
21310
|
+
spinner10.start("Waiting for email to be processed...");
|
|
21140
21311
|
let found = false;
|
|
21141
21312
|
const startTime = Date.now();
|
|
21142
21313
|
const timeout = 3e4;
|