@wraps.dev/cli 2.12.3 → 2.12.4

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
@@ -29516,8 +29516,12 @@ async function findExistingPhoneNumber(phoneNumberType) {
29516
29516
  }
29517
29517
  }
29518
29518
  return null;
29519
- } catch {
29520
- return null;
29519
+ } catch (error) {
29520
+ const name = error instanceof Error ? error.name : "";
29521
+ if (name === "ResourceNotFoundException") {
29522
+ return null;
29523
+ }
29524
+ throw error;
29521
29525
  }
29522
29526
  }
29523
29527
  async function createSMSPhoneNumber(phoneNumberType, optOutList) {
@@ -29904,7 +29908,12 @@ async function createSMSPhonePoolWithSDK(phoneNumberArn, region) {
29904
29908
  }
29905
29909
  }
29906
29910
  }
29907
- } catch {
29911
+ } catch (error) {
29912
+ const name = error instanceof Error ? error.name : "";
29913
+ if (name === "ResourceNotFoundException") {
29914
+ } else {
29915
+ throw error;
29916
+ }
29908
29917
  }
29909
29918
  try {
29910
29919
  const response = await client.send(
@@ -29920,8 +29929,12 @@ async function createSMSPhonePoolWithSDK(phoneNumberArn, region) {
29920
29929
  })
29921
29930
  );
29922
29931
  return response.PoolId;
29923
- } catch {
29924
- return;
29932
+ } catch (error) {
29933
+ const name = error instanceof Error ? error.name : "";
29934
+ if (name === "ConflictException") {
29935
+ return;
29936
+ }
29937
+ throw error;
29925
29938
  }
29926
29939
  }
29927
29940
  async function createSMSEventDestinationWithSDK(configurationSetName, snsTopicArn, region) {
@@ -29947,7 +29960,12 @@ async function createSMSEventDestinationWithSDK(configurationSetName, snsTopicAr
29947
29960
  return existingDest.EventDestinationName;
29948
29961
  }
29949
29962
  }
29950
- } catch {
29963
+ } catch (error) {
29964
+ const name = error instanceof Error ? error.name : "";
29965
+ if (name === "ResourceNotFoundException") {
29966
+ } else {
29967
+ throw error;
29968
+ }
29951
29969
  }
29952
29970
  try {
29953
29971
  const response = await client.send(
@@ -29961,8 +29979,12 @@ async function createSMSEventDestinationWithSDK(configurationSetName, snsTopicAr
29961
29979
  })
29962
29980
  );
29963
29981
  return response.EventDestination?.EventDestinationName || eventDestinationName;
29964
- } catch {
29965
- return eventDestinationName;
29982
+ } catch (error) {
29983
+ const name = error instanceof Error ? error.name : "";
29984
+ if (name === "ConflictException") {
29985
+ return eventDestinationName;
29986
+ }
29987
+ throw error;
29966
29988
  }
29967
29989
  }
29968
29990
  async function deleteSMSPhonePoolWithSDK(region) {
@@ -29991,7 +30013,12 @@ async function deleteSMSPhonePoolWithSDK(region) {
29991
30013
  }
29992
30014
  }
29993
30015
  }
29994
- } catch {
30016
+ } catch (error) {
30017
+ const name = error instanceof Error ? error.name : "";
30018
+ if (name === "ResourceNotFoundException") {
30019
+ } else {
30020
+ throw error;
30021
+ }
29995
30022
  }
29996
30023
  }
29997
30024
  async function deleteSMSEventDestinationWithSDK(configurationSetName, region) {
@@ -30005,7 +30032,12 @@ async function deleteSMSEventDestinationWithSDK(configurationSetName, region) {
30005
30032
  EventDestinationName: eventDestinationName
30006
30033
  })
30007
30034
  );
30008
- } catch {
30035
+ } catch (error) {
30036
+ const name = error instanceof Error ? error.name : "";
30037
+ if (name === "ResourceNotFoundException") {
30038
+ } else {
30039
+ throw error;
30040
+ }
30009
30041
  }
30010
30042
  }
30011
30043
  async function createSMSProtectConfigurationWithSDK(configurationSetName, region, options) {
@@ -30040,7 +30072,12 @@ async function createSMSProtectConfigurationWithSDK(configurationSetName, region
30040
30072
  break;
30041
30073
  }
30042
30074
  }
30043
- } catch {
30075
+ } catch (error) {
30076
+ const name = error instanceof Error ? error.name : "";
30077
+ if (name === "ResourceNotFoundException") {
30078
+ } else {
30079
+ throw error;
30080
+ }
30044
30081
  }
30045
30082
  try {
30046
30083
  let protectConfigId = existingProtectConfigId;
@@ -30106,8 +30143,12 @@ async function createSMSProtectConfigurationWithSDK(configurationSetName, region
30106
30143
  );
30107
30144
  }
30108
30145
  return protectConfigId;
30109
- } catch {
30110
- return;
30146
+ } catch (error) {
30147
+ const name = error instanceof Error ? error.name : "";
30148
+ if (name === "ConflictException") {
30149
+ return;
30150
+ }
30151
+ throw error;
30111
30152
  }
30112
30153
  }
30113
30154
  async function deleteSMSProtectConfigurationWithSDK(region) {
@@ -30144,7 +30185,12 @@ async function deleteSMSProtectConfigurationWithSDK(region) {
30144
30185
  }
30145
30186
  }
30146
30187
  }
30147
- } catch {
30188
+ } catch (error) {
30189
+ const name = error instanceof Error ? error.name : "";
30190
+ if (name === "ResourceNotFoundException") {
30191
+ } else {
30192
+ throw error;
30193
+ }
30148
30194
  }
30149
30195
  }
30150
30196
 
@@ -30167,7 +30213,29 @@ async function smsDestroy(options) {
30167
30213
  "Validating AWS credentials",
30168
30214
  async () => validateAWSCredentials()
30169
30215
  );
30170
- const region = await getAWSRegion();
30216
+ let region = options.region || await getAWSRegion();
30217
+ if (!(options.region || process.env.AWS_REGION || process.env.AWS_DEFAULT_REGION)) {
30218
+ const smsConnections = await findConnectionsWithService(
30219
+ identity.accountId,
30220
+ "sms"
30221
+ );
30222
+ if (smsConnections.length === 1) {
30223
+ region = smsConnections[0].region;
30224
+ } else if (smsConnections.length > 1) {
30225
+ const selectedRegion = await clack38.select({
30226
+ message: "Multiple SMS deployments found. Which region to destroy?",
30227
+ options: smsConnections.map((conn) => ({
30228
+ value: conn.region,
30229
+ label: conn.region
30230
+ }))
30231
+ });
30232
+ if (clack38.isCancel(selectedRegion)) {
30233
+ clack38.cancel("Operation cancelled");
30234
+ process.exit(0);
30235
+ }
30236
+ region = selectedRegion;
30237
+ }
30238
+ }
30171
30239
  const metadata = await loadConnectionMetadata(identity.accountId, region);
30172
30240
  const smsService = metadata?.services?.sms;
30173
30241
  const storedStackName = smsService?.pulumiStackName;
@@ -30246,6 +30314,7 @@ async function smsDestroy(options) {
30246
30314
  await progress.execute("Cleaning up protect configuration", async () => {
30247
30315
  await deleteSMSProtectConfigurationWithSDK(region);
30248
30316
  });
30317
+ let destroyFailed = false;
30249
30318
  try {
30250
30319
  await progress.execute(
30251
30320
  "Destroying SMS infrastructure (this may take 2-3 minutes)",
@@ -30261,8 +30330,14 @@ async function smsDestroy(options) {
30261
30330
  } catch (_error) {
30262
30331
  throw new Error("No SMS infrastructure found to destroy");
30263
30332
  }
30264
- await stack.destroy({ onOutput: () => {
30333
+ await stack.refresh({ onOutput: () => {
30265
30334
  } });
30335
+ await withTimeout(
30336
+ stack.destroy({ onOutput: () => {
30337
+ }, continueOnError: true }),
30338
+ DEFAULT_PULUMI_TIMEOUT_MS,
30339
+ "Pulumi destroy"
30340
+ );
30266
30341
  await stack.workspace.removeStack(stackName);
30267
30342
  }
30268
30343
  );
@@ -30282,21 +30357,29 @@ async function smsDestroy(options) {
30282
30357
  throw errors.stackLocked();
30283
30358
  }
30284
30359
  trackError("DESTROY_FAILED", "sms destroy", { step: "destroy" });
30285
- clack38.log.error("SMS infrastructure destruction failed");
30286
- throw new Error(`SMS destruction failed: ${errorMessage}`);
30360
+ destroyFailed = true;
30361
+ clack38.log.warn(
30362
+ "Some resources may not have been fully removed. You can re-run this command or clean up manually in the AWS console."
30363
+ );
30287
30364
  }
30288
30365
  if (metadata) {
30289
30366
  removeServiceFromConnection(metadata, "sms");
30290
30367
  await saveConnectionMetadata(metadata);
30291
30368
  }
30292
30369
  progress.stop();
30293
- clack38.outro(pc41.green("SMS infrastructure has been removed"));
30294
- console.log(`
30370
+ if (destroyFailed) {
30371
+ clack38.outro(
30372
+ pc41.yellow("SMS infrastructure partially removed. Metadata cleaned up.")
30373
+ );
30374
+ } else {
30375
+ clack38.outro(pc41.green("SMS infrastructure has been removed"));
30376
+ console.log(`
30295
30377
  ${pc41.bold("Cleaned up:")}`);
30296
- console.log(` ${pc41.green("\u2713")} Phone number released`);
30297
- console.log(` ${pc41.green("\u2713")} Configuration set deleted`);
30298
- console.log(` ${pc41.green("\u2713")} Event processing infrastructure removed`);
30299
- console.log(` ${pc41.green("\u2713")} IAM role deleted`);
30378
+ console.log(` ${pc41.green("\u2713")} Phone number released`);
30379
+ console.log(` ${pc41.green("\u2713")} Configuration set deleted`);
30380
+ console.log(` ${pc41.green("\u2713")} Event processing infrastructure removed`);
30381
+ console.log(` ${pc41.green("\u2713")} IAM role deleted`);
30382
+ }
30300
30383
  console.log(
30301
30384
  `
30302
30385
  Run ${pc41.cyan("wraps sms init")} to deploy infrastructure again.
@@ -30304,6 +30387,7 @@ Run ${pc41.cyan("wraps sms init")} to deploy infrastructure again.
30304
30387
  );
30305
30388
  trackServiceRemoved("sms", {
30306
30389
  reason: "user_initiated",
30390
+ partial_failure: destroyFailed,
30307
30391
  duration_ms: Date.now() - startTime
30308
30392
  });
30309
30393
  }
@@ -31007,31 +31091,64 @@ ${pc42.yellow(pc42.bold("Important Notes:"))}`);
31007
31091
  };
31008
31092
  }
31009
31093
  );
31094
+ let sdkResourceWarning = false;
31010
31095
  if (outputs.phoneNumberArn) {
31011
- await progress.execute("Creating phone pool", async () => {
31012
- await createSMSPhonePoolWithSDK(outputs.phoneNumberArn, region);
31013
- });
31096
+ try {
31097
+ await progress.execute("Creating phone pool", async () => {
31098
+ await createSMSPhonePoolWithSDK(outputs.phoneNumberArn, region);
31099
+ });
31100
+ } catch (sdkError) {
31101
+ sdkResourceWarning = true;
31102
+ const msg = sdkError instanceof Error ? sdkError.message : String(sdkError);
31103
+ clack39.log.warn(`Phone pool creation failed: ${msg}`);
31104
+ clack39.log.info(
31105
+ `Run ${pc42.cyan("wraps sms sync")} to retry SDK resource creation.`
31106
+ );
31107
+ }
31014
31108
  }
31015
31109
  if (smsConfig.eventTracking?.enabled && outputs.configSetName && outputs.snsTopicArn) {
31016
- await progress.execute("Configuring event destination", async () => {
31017
- await createSMSEventDestinationWithSDK(
31018
- outputs.configSetName,
31019
- outputs.snsTopicArn,
31020
- region
31110
+ try {
31111
+ await progress.execute("Configuring event destination", async () => {
31112
+ await createSMSEventDestinationWithSDK(
31113
+ outputs.configSetName,
31114
+ outputs.snsTopicArn,
31115
+ region
31116
+ );
31117
+ });
31118
+ } catch (sdkError) {
31119
+ sdkResourceWarning = true;
31120
+ const msg = sdkError instanceof Error ? sdkError.message : String(sdkError);
31121
+ clack39.log.warn(`Event destination creation failed: ${msg}`);
31122
+ clack39.log.info(
31123
+ `Run ${pc42.cyan("wraps sms sync")} to retry SDK resource creation.`
31021
31124
  );
31022
- });
31125
+ }
31023
31126
  }
31024
31127
  if (smsConfig.protectConfiguration?.enabled && outputs.configSetName) {
31025
- await progress.execute("Configuring fraud protection", async () => {
31026
- await createSMSProtectConfigurationWithSDK(
31027
- outputs.configSetName,
31028
- region,
31029
- {
31030
- allowedCountries: smsConfig.protectConfiguration?.allowedCountries,
31031
- aitFiltering: smsConfig.protectConfiguration?.aitFiltering
31032
- }
31128
+ try {
31129
+ await progress.execute("Configuring fraud protection", async () => {
31130
+ await createSMSProtectConfigurationWithSDK(
31131
+ outputs.configSetName,
31132
+ region,
31133
+ {
31134
+ allowedCountries: smsConfig.protectConfiguration?.allowedCountries,
31135
+ aitFiltering: smsConfig.protectConfiguration?.aitFiltering
31136
+ }
31137
+ );
31138
+ });
31139
+ } catch (sdkError) {
31140
+ sdkResourceWarning = true;
31141
+ const msg = sdkError instanceof Error ? sdkError.message : String(sdkError);
31142
+ clack39.log.warn(`Protect configuration creation failed: ${msg}`);
31143
+ clack39.log.info(
31144
+ `Run ${pc42.cyan("wraps sms sync")} to retry SDK resource creation.`
31033
31145
  );
31034
- });
31146
+ }
31147
+ }
31148
+ if (sdkResourceWarning) {
31149
+ clack39.log.warn(
31150
+ "Some SDK resources failed to create. Core infrastructure is deployed."
31151
+ );
31035
31152
  }
31036
31153
  } catch (error) {
31037
31154
  trackServiceInit("sms", false, {
@@ -31160,7 +31277,8 @@ async function getPhoneNumberDetails(region) {
31160
31277
  }
31161
31278
  return null;
31162
31279
  } catch (error) {
31163
- console.error("Error fetching phone number:", error);
31280
+ const errorMessage = error instanceof Error ? error.message : String(error);
31281
+ clack40.log.error(`Error fetching phone number: ${errorMessage}`);
31164
31282
  return null;
31165
31283
  }
31166
31284
  }
@@ -31554,7 +31672,7 @@ Run ${pc45.cyan("wraps sms init")} to deploy SMS infrastructure first.
31554
31672
  smsConfig.protectConfiguration = {
31555
31673
  enabled: true,
31556
31674
  allowedCountries: ["US"],
31557
- aitFiltering: true
31675
+ aitFiltering: false
31558
31676
  };
31559
31677
  }
31560
31678
  }
@@ -31604,9 +31722,14 @@ import {
31604
31722
  } from "@aws-sdk/client-pinpoint-sms-voice-v2";
31605
31723
  import * as clack43 from "@clack/prompts";
31606
31724
  import pc46 from "picocolors";
31725
+
31726
+ // src/utils/sms/validation.ts
31727
+ init_esm_shims();
31607
31728
  function isValidPhoneNumber(phone) {
31608
31729
  return /^\+[1-9]\d{1,14}$/.test(phone);
31609
31730
  }
31731
+
31732
+ // src/commands/sms/test.ts
31610
31733
  var SIMULATOR_DESTINATIONS = [
31611
31734
  { number: "+14254147755", country: "United States (US)" },
31612
31735
  { number: "+447860019066", country: "United Kingdom (GB)" },
@@ -31776,18 +31899,39 @@ Run ${pc46.cyan("wraps sms init")} to deploy SMS infrastructure.
31776
31899
  error: errorMessage,
31777
31900
  duration_ms: Date.now() - startTime
31778
31901
  });
31779
- if (errorMessage.includes("not verified")) {
31902
+ const errorName = error instanceof Error ? error.name : "";
31903
+ if (errorName === "ConflictException" || errorMessage.includes("opt-out")) {
31904
+ clack43.log.error("Destination number has opted out of messages");
31905
+ console.log(
31906
+ `
31907
+ The recipient has opted out of receiving SMS messages.
31908
+ `
31909
+ );
31910
+ } else if (errorName === "ThrottlingException" || errorMessage.includes("spending limit")) {
31911
+ clack43.log.error("SMS rate or spending limit reached");
31912
+ console.log(
31913
+ `
31914
+ Check your AWS account SMS spending limits in the console.
31915
+ `
31916
+ );
31917
+ } else if (errorName === "ValidationException") {
31918
+ clack43.log.error(`Invalid request: ${errorMessage}`);
31919
+ } else if (errorMessage.includes("not verified") || errorMessage.includes("not registered")) {
31780
31920
  clack43.log.error("Toll-free number registration is not complete");
31781
31921
  console.log(
31782
31922
  `
31783
- Run ${pc46.cyan("wraps sms register")} to complete registration.
31923
+ Run ${pc46.cyan("wraps sms register")} to check registration status.
31924
+ `
31925
+ );
31926
+ } else if (errorName === "AccessDeniedException") {
31927
+ clack43.log.error(
31928
+ "Permission denied \u2014 IAM role may be missing SMS send permissions"
31929
+ );
31930
+ console.log(
31931
+ `
31932
+ Run ${pc46.cyan("wraps sms upgrade")} to update IAM policies.
31784
31933
  `
31785
31934
  );
31786
- } else if (errorMessage.includes("opt-out")) {
31787
- clack43.log.error("Destination number has opted out of messages");
31788
- } else if (errorMessage.includes("spending limit")) {
31789
- clack43.log.error("AWS SMS spending limit reached");
31790
- console.log("\nVisit the AWS console to increase your spending limit.\n");
31791
31935
  } else {
31792
31936
  clack43.log.error(`Failed to send SMS: ${errorMessage}`);
31793
31937
  }
@@ -32740,9 +32884,6 @@ import {
32740
32884
  } from "@aws-sdk/client-pinpoint-sms-voice-v2";
32741
32885
  import * as clack45 from "@clack/prompts";
32742
32886
  import pc48 from "picocolors";
32743
- function isValidPhoneNumber2(phone) {
32744
- return /^\+[1-9]\d{1,14}$/.test(phone);
32745
- }
32746
32887
  async function smsVerifyNumber(options) {
32747
32888
  const startTime = Date.now();
32748
32889
  const progress = new DeploymentProgress();
@@ -32863,7 +33004,7 @@ Usage: ${pc48.cyan("wraps sms verify-number --delete --phone-number +14155551234
32863
33004
  if (!value) {
32864
33005
  return "Phone number is required";
32865
33006
  }
32866
- if (!isValidPhoneNumber2(value)) {
33007
+ if (!isValidPhoneNumber(value)) {
32867
33008
  return "Please enter a valid phone number in E.164 format (e.g., +14155551234)";
32868
33009
  }
32869
33010
  return;
@@ -32874,7 +33015,7 @@ Usage: ${pc48.cyan("wraps sms verify-number --delete --phone-number +14155551234
32874
33015
  process.exit(0);
32875
33016
  }
32876
33017
  phoneNumber = result;
32877
- } else if (!isValidPhoneNumber2(phoneNumber)) {
33018
+ } else if (!isValidPhoneNumber(phoneNumber)) {
32878
33019
  progress.stop();
32879
33020
  clack45.log.error(
32880
33021
  `Invalid phone number format: ${phoneNumber}. Use E.164 format (e.g., +14155551234)`
@@ -34140,7 +34281,8 @@ Run ${pc51.cyan("wraps --help")} for available commands.
34140
34281
  case "destroy":
34141
34282
  await smsDestroy({
34142
34283
  force: flags.force,
34143
- preview: flags.preview
34284
+ preview: flags.preview,
34285
+ region: flags.region
34144
34286
  });
34145
34287
  break;
34146
34288
  case "verify-number":