@wraps.dev/cli 2.18.4 → 2.18.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/cli.js CHANGED
@@ -1855,6 +1855,7 @@ You may need to merge your existing rules into the wraps rule set.`,
1855
1855
  // src/utils/shared/aws.ts
1856
1856
  var aws_exports = {};
1857
1857
  __export(aws_exports, {
1858
+ SES_REGIONS: () => SES_REGIONS,
1858
1859
  checkRegion: () => checkRegion,
1859
1860
  getACMCertificateStatus: () => getACMCertificateStatus,
1860
1861
  getAWSRegion: () => getAWSRegion,
@@ -1933,31 +1934,7 @@ async function validateAWSCredentialsWithDetails() {
1933
1934
  }
1934
1935
  }
1935
1936
  async function checkRegion(region) {
1936
- const validRegions = [
1937
- "us-east-1",
1938
- "us-east-2",
1939
- "us-west-1",
1940
- "us-west-2",
1941
- "af-south-1",
1942
- "ap-east-1",
1943
- "ap-south-1",
1944
- "ap-northeast-1",
1945
- "ap-northeast-2",
1946
- "ap-northeast-3",
1947
- "ap-southeast-1",
1948
- "ap-southeast-2",
1949
- "ap-southeast-3",
1950
- "ca-central-1",
1951
- "eu-central-1",
1952
- "eu-west-1",
1953
- "eu-west-2",
1954
- "eu-west-3",
1955
- "eu-south-1",
1956
- "eu-north-1",
1957
- "me-south-1",
1958
- "sa-east-1"
1959
- ];
1960
- return validRegions.includes(region);
1937
+ return SES_REGIONS.includes(region);
1961
1938
  }
1962
1939
  async function getAWSRegion() {
1963
1940
  if (process.env.AWS_REGION) {
@@ -2042,12 +2019,37 @@ async function getACMCertificateStatus(certificateArn) {
2042
2019
  return null;
2043
2020
  }
2044
2021
  }
2022
+ var SES_REGIONS;
2045
2023
  var init_aws = __esm({
2046
2024
  "src/utils/shared/aws.ts"() {
2047
2025
  "use strict";
2048
2026
  init_esm_shims();
2049
2027
  init_aws_detection();
2050
2028
  init_errors();
2029
+ SES_REGIONS = [
2030
+ "us-east-1",
2031
+ "us-east-2",
2032
+ "us-west-1",
2033
+ "us-west-2",
2034
+ "af-south-1",
2035
+ "ap-east-1",
2036
+ "ap-south-1",
2037
+ "ap-northeast-1",
2038
+ "ap-northeast-2",
2039
+ "ap-northeast-3",
2040
+ "ap-southeast-1",
2041
+ "ap-southeast-2",
2042
+ "ap-southeast-3",
2043
+ "ca-central-1",
2044
+ "eu-central-1",
2045
+ "eu-west-1",
2046
+ "eu-west-2",
2047
+ "eu-west-3",
2048
+ "eu-south-1",
2049
+ "eu-north-1",
2050
+ "me-south-1",
2051
+ "sa-east-1"
2052
+ ];
2051
2053
  }
2052
2054
  });
2053
2055
 
@@ -8123,6 +8125,9 @@ async function scanSESIdentities(region) {
8123
8125
  }
8124
8126
  return identities;
8125
8127
  } catch (error) {
8128
+ if (error instanceof Error && (error.name === "AccessDeniedException" || error.name === "AccessDenied")) {
8129
+ throw error;
8130
+ }
8126
8131
  console.error(
8127
8132
  "Error scanning SES identities:",
8128
8133
  error instanceof Error ? error.message : error
@@ -8303,27 +8308,37 @@ async function scanIAMRoles(region) {
8303
8308
  }
8304
8309
  async function scanAWSResources(region) {
8305
8310
  const [
8306
- identities,
8311
+ identityResult,
8307
8312
  configurationSets,
8308
8313
  snsTopics,
8309
8314
  dynamoTables,
8310
8315
  lambdaFunctions,
8311
8316
  iamRoles
8312
8317
  ] = await Promise.all([
8313
- scanSESIdentities(region),
8318
+ scanSESIdentities(region).catch(
8319
+ (error) => error instanceof Error ? error : new Error(String(error))
8320
+ ),
8314
8321
  scanSESConfigurationSets(region),
8315
8322
  scanSNSTopics(region),
8316
8323
  scanDynamoTables(region),
8317
8324
  scanLambdaFunctions(region),
8318
8325
  scanIAMRoles(region)
8319
8326
  ]);
8327
+ let identities = [];
8328
+ let scanErrors;
8329
+ if (identityResult instanceof Error) {
8330
+ scanErrors = { identities: identityResult.name };
8331
+ } else {
8332
+ identities = identityResult;
8333
+ }
8320
8334
  return {
8321
8335
  identities,
8322
8336
  configurationSets,
8323
8337
  snsTopics,
8324
8338
  dynamoTables,
8325
8339
  lambdaFunctions,
8326
- iamRoles
8340
+ iamRoles,
8341
+ scanErrors
8327
8342
  };
8328
8343
  }
8329
8344
  function filterWrapsResources(scan) {
@@ -18378,11 +18393,40 @@ async function connect2(options) {
18378
18393
  progress.info(
18379
18394
  `Found: ${scan.identities.length} identities, ${scan.configurationSets.length} config sets`
18380
18395
  );
18396
+ if (scan.scanErrors?.identities) {
18397
+ throw errors.sesPermissionDenied("ListIdentities");
18398
+ }
18381
18399
  if (scan.identities.length === 0) {
18382
- clack17.log.warn("No SES identities found in this region.");
18383
- clack17.log.info(
18384
- `Use ${pc19.cyan("wraps email init")} to create new email infrastructure instead.`
18400
+ const otherRegions = SES_REGIONS.filter((r) => r !== region);
18401
+ const regionHits = await progress.execute(
18402
+ "Checking other regions for SES identities",
18403
+ async () => {
18404
+ const results = await Promise.all(
18405
+ otherRegions.map(async (r) => {
18406
+ try {
18407
+ const ids = await scanSESIdentities(r);
18408
+ return ids.length > 0 ? r : null;
18409
+ } catch {
18410
+ return null;
18411
+ }
18412
+ })
18413
+ );
18414
+ return results.filter((r) => r !== null);
18415
+ }
18385
18416
  );
18417
+ if (regionHits.length > 0) {
18418
+ clack17.log.warn(
18419
+ `No SES identities found in ${pc19.cyan(region)}, but found identities in: ${regionHits.map((r) => pc19.cyan(r)).join(", ")}`
18420
+ );
18421
+ clack17.log.info(
18422
+ `Run ${pc19.cyan(`wraps email connect --region ${regionHits[0]}`)} to connect to your existing infrastructure.`
18423
+ );
18424
+ } else {
18425
+ clack17.log.warn("No SES identities found in any region.");
18426
+ clack17.log.info(
18427
+ `Use ${pc19.cyan("wraps email init")} to create new email infrastructure instead.`
18428
+ );
18429
+ }
18386
18430
  process.exit(0);
18387
18431
  }
18388
18432
  const verifiedIdentities = scan.identities.filter((id) => id.verified);
@@ -18409,6 +18453,15 @@ async function connect2(options) {
18409
18453
  clack17.log.warn("No identities selected. Nothing to connect.");
18410
18454
  process.exit(0);
18411
18455
  }
18456
+ const unverifiedSelected = selectedIdentities.filter((name) => {
18457
+ const identity2 = scan.identities.find((id) => id.name === name);
18458
+ return identity2 && !identity2.verified;
18459
+ });
18460
+ if (unverifiedSelected.length > 0) {
18461
+ clack17.log.warn(
18462
+ `${unverifiedSelected.map((id) => pc19.cyan(id)).join(", ")} not yet verified \u2014 SES will reject sends from unverified identities until verification is complete.`
18463
+ );
18464
+ }
18412
18465
  const preset = await promptConfigPreset();
18413
18466
  const emailConfig = preset === "custom" ? await Promise.resolve().then(() => (init_prompts(), prompts_exports)).then(
18414
18467
  (m) => m.promptCustomConfig()