@wraps.dev/cli 3.1.0 → 3.2.1

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
@@ -14,12 +14,12 @@ var __export = (target, all6) => {
14
14
  __defProp(target, name, { get: all6[name], enumerable: true });
15
15
  };
16
16
 
17
- // ../../node_modules/.pnpm/tsup@8.5.1_jiti@2.7.0_postcss@8.5.23_supports-color@8.1.1_tsx@4.20.6_typescript@5.9.3_yaml@2.9.0/node_modules/tsup/assets/esm_shims.js
17
+ // ../../node_modules/.pnpm/tsup@8.5.1_jiti@2.7.0_postcss@8.5.26_supports-color@8.1.1_tsx@4.20.6_typescript@5.9.3_yaml@2.9.0/node_modules/tsup/assets/esm_shims.js
18
18
  import path from "path";
19
19
  import { fileURLToPath } from "url";
20
20
  var getFilename, getDirname, __dirname;
21
21
  var init_esm_shims = __esm({
22
- "../../node_modules/.pnpm/tsup@8.5.1_jiti@2.7.0_postcss@8.5.23_supports-color@8.1.1_tsx@4.20.6_typescript@5.9.3_yaml@2.9.0/node_modules/tsup/assets/esm_shims.js"() {
22
+ "../../node_modules/.pnpm/tsup@8.5.1_jiti@2.7.0_postcss@8.5.26_supports-color@8.1.1_tsx@4.20.6_typescript@5.9.3_yaml@2.9.0/node_modules/tsup/assets/esm_shims.js"() {
23
23
  "use strict";
24
24
  getFilename = () => fileURLToPath(import.meta.url);
25
25
  getDirname = () => path.dirname(getFilename());
@@ -1029,6 +1029,12 @@ To remove: wraps destroy --stack ${stackName}`,
1029
1029
  Saved regions: ${savedRegions.join(", ")}` : "Pass --region or set AWS_REGION.\nNo saved Wraps deployments found.",
1030
1030
  "https://wraps.dev/docs/cli-reference"
1031
1031
  ),
1032
+ nonInteractiveInput: (what, flagHint) => new WrapsError(
1033
+ `${what} is required in non-interactive mode`,
1034
+ "NON_INTERACTIVE_INPUT",
1035
+ `Pass ${flagHint} (or run in an interactive terminal).`,
1036
+ "https://wraps.dev/docs/reference/json-output"
1037
+ ),
1032
1038
  pulumiError: (message) => new WrapsError(
1033
1039
  `Infrastructure deployment failed: ${message}`,
1034
1040
  "PULUMI_ERROR",
@@ -1084,6 +1090,18 @@ Saved regions: ${savedRegions.join(", ")}` : "Pass --region or set AWS_REGION.\n
1084
1090
  "Phone numbers must be in E.164 format:\n Example: +14155551234 (US)\n Example: +447911123456 (UK)",
1085
1091
  "https://wraps.dev/docs/sms-sdk-reference"
1086
1092
  ),
1093
+ smsInvalidCountries: (raw) => new WrapsError(
1094
+ `Invalid --countries value: ${raw}`,
1095
+ "SMS_INVALID_COUNTRIES",
1096
+ "Pass a comma-separated list of ISO 3166-1 alpha-2 codes.\n Example: --countries US,CA,GB",
1097
+ "https://wraps.dev/docs/cli-reference"
1098
+ ),
1099
+ smsInvalidVolume: (raw) => new WrapsError(
1100
+ `Invalid --volume value: ${raw}`,
1101
+ "SMS_INVALID_VOLUME",
1102
+ "Pass a positive whole number of messages per month.\n Example: --volume 10000",
1103
+ "https://wraps.dev/docs/cli-reference"
1104
+ ),
1087
1105
  smsSimulatorLimit: () => new WrapsError(
1088
1106
  "Simulator daily message limit reached (100 messages)",
1089
1107
  "SMS_SIMULATOR_LIMIT",
@@ -26484,6 +26502,7 @@ __export(prompts_exports, {
26484
26502
  REQUIRED_SUPPRESSION_EVENT_TYPES: () => REQUIRED_SUPPRESSION_EVENT_TYPES,
26485
26503
  confirmConnect: () => confirmConnect,
26486
26504
  confirmDeploy: () => confirmDeploy,
26505
+ ensureInteractive: () => ensureInteractive,
26487
26506
  getAvailableFeatures: () => getAvailableFeatures,
26488
26507
  isInteractive: () => isInteractive,
26489
26508
  promptConfigPreset: () => promptConfigPreset,
@@ -26514,7 +26533,13 @@ import pc8 from "picocolors";
26514
26533
  function isInteractive() {
26515
26534
  return process.stdin.isTTY === true && process.stdout.isTTY === true && !process.env.CI;
26516
26535
  }
26536
+ function ensureInteractive(what, flagHint) {
26537
+ if (!isInteractive() || isJsonMode()) {
26538
+ throw errors.nonInteractiveInput(what, flagHint);
26539
+ }
26540
+ }
26517
26541
  async function promptProvider() {
26542
+ ensureInteractive("Provider", "--provider <vercel|aws|railway|other>");
26518
26543
  const provider = await clack6.select({
26519
26544
  message: "Where is your app hosted?",
26520
26545
  options: [
@@ -26547,6 +26572,7 @@ async function promptProvider() {
26547
26572
  return provider;
26548
26573
  }
26549
26574
  async function promptRegion(defaultRegion) {
26575
+ ensureInteractive("Region", "--region <aws-region>");
26550
26576
  const region = await clack6.select({
26551
26577
  message: "Select AWS region:",
26552
26578
  options: [
@@ -26634,6 +26660,7 @@ async function promptRegion(defaultRegion) {
26634
26660
  return region;
26635
26661
  }
26636
26662
  async function promptDomain() {
26663
+ ensureInteractive("Domain", "--domain <domain>");
26637
26664
  const domain = await clack6.text({
26638
26665
  message: "Domain to verify (optional):",
26639
26666
  placeholder: "myapp.com",
@@ -26653,6 +26680,10 @@ async function promptDomain() {
26653
26680
  return domain || "";
26654
26681
  }
26655
26682
  async function promptVercelConfig() {
26683
+ ensureInteractive(
26684
+ "Vercel configuration",
26685
+ "--provider aws (or interactive run)"
26686
+ );
26656
26687
  const config2 = await clack6.group(
26657
26688
  {
26658
26689
  teamSlug: () => clack6.text({
@@ -26684,6 +26715,7 @@ async function promptVercelConfig() {
26684
26715
  return config2;
26685
26716
  }
26686
26717
  async function promptIntegrationLevel() {
26718
+ ensureInteractive("Integration level", "run interactively");
26687
26719
  const level = await clack6.select({
26688
26720
  message: "Integration level:",
26689
26721
  options: [
@@ -26706,6 +26738,7 @@ async function promptIntegrationLevel() {
26706
26738
  return level;
26707
26739
  }
26708
26740
  async function confirmDeploy() {
26741
+ ensureInteractive("Deployment confirmation", "--yes");
26709
26742
  const confirmed = await clack6.confirm({
26710
26743
  message: "Deploy infrastructure to your AWS account?",
26711
26744
  initialValue: true
@@ -26751,6 +26784,7 @@ function getAvailableFeatures() {
26751
26784
  ];
26752
26785
  }
26753
26786
  async function promptFeatureSelection(preselected) {
26787
+ ensureInteractive("Feature selection", "run interactively");
26754
26788
  const features = getAvailableFeatures();
26755
26789
  const selected = await clack6.multiselect({
26756
26790
  message: "Select features to deploy:",
@@ -26770,6 +26804,7 @@ async function promptFeatureSelection(preselected) {
26770
26804
  return selected;
26771
26805
  }
26772
26806
  async function promptConflictResolution(resourceType, existingResourceName) {
26807
+ ensureInteractive("Conflict resolution", "run interactively");
26773
26808
  const action = await clack6.select({
26774
26809
  message: `Found existing ${resourceType}: ${pc8.cyan(existingResourceName)}. How should we handle this?`,
26775
26810
  options: [
@@ -26797,6 +26832,7 @@ async function promptConflictResolution(resourceType, existingResourceName) {
26797
26832
  return action;
26798
26833
  }
26799
26834
  async function promptSelectIdentities(identities) {
26835
+ ensureInteractive("Identity selection", "run interactively");
26800
26836
  const selected = await clack6.multiselect({
26801
26837
  message: "Select identities to connect with Wraps:",
26802
26838
  options: identities.map((id) => ({
@@ -26813,6 +26849,7 @@ async function promptSelectIdentities(identities) {
26813
26849
  return selected;
26814
26850
  }
26815
26851
  async function confirmConnect() {
26852
+ ensureInteractive("Connection confirmation", "--yes");
26816
26853
  const confirmed = await clack6.confirm({
26817
26854
  message: "Connect to existing AWS infrastructure?",
26818
26855
  initialValue: true
@@ -26824,6 +26861,7 @@ async function confirmConnect() {
26824
26861
  return confirmed;
26825
26862
  }
26826
26863
  async function promptConfigPreset() {
26864
+ ensureInteractive("Preset", "--preset <starter|production|enterprise>");
26827
26865
  const { getAllPresetInfo: getAllPresetInfo2 } = await Promise.resolve().then(() => (init_presets(), presets_exports));
26828
26866
  const presets = getAllPresetInfo2();
26829
26867
  const preset = await clack6.select({
@@ -26841,6 +26879,7 @@ async function promptConfigPreset() {
26841
26879
  return preset;
26842
26880
  }
26843
26881
  async function promptEstimatedVolume() {
26882
+ ensureInteractive("Estimated volume", "--quick");
26844
26883
  const volume = await clack6.select({
26845
26884
  message: "Estimated monthly email volume:",
26846
26885
  options: [
@@ -26866,6 +26905,7 @@ async function promptEstimatedVolume() {
26866
26905
  return volume;
26867
26906
  }
26868
26907
  async function promptEmailArchiving() {
26908
+ ensureInteractive("Email archiving", "--quick");
26869
26909
  const enabled = await clack6.confirm({
26870
26910
  message: "Enable email archiving? (Store full email content with HTML for viewing in dashboard)",
26871
26911
  initialValue: false
@@ -26919,6 +26959,10 @@ async function promptEmailArchiving() {
26919
26959
  };
26920
26960
  }
26921
26961
  async function promptCustomConfig(existingConfig) {
26962
+ ensureInteractive(
26963
+ "Custom configuration",
26964
+ "--preset starter|production|enterprise (custom requires an interactive terminal)"
26965
+ );
26922
26966
  clack6.log.info("Custom configuration builder");
26923
26967
  clack6.log.info("Configure each feature individually");
26924
26968
  const reputationMetrics = await clack6.confirm({
@@ -27176,6 +27220,7 @@ async function promptDNSConfirmation(preview) {
27176
27220
  clack6.log.success("All DNS records are already configured correctly.");
27177
27221
  return { shouldCreate: false, selectedCategories: /* @__PURE__ */ new Set() };
27178
27222
  }
27223
+ ensureInteractive("DNS record confirmation", "run interactively");
27179
27224
  const shouldCreate = await clack6.confirm({
27180
27225
  message: "Create DNS records in Route53?",
27181
27226
  initialValue: !preview.hasConflicts
@@ -27231,6 +27276,7 @@ async function promptDNSConfirmation(preview) {
27231
27276
  return { shouldCreate: true, selectedCategories: allCategories };
27232
27277
  }
27233
27278
  async function promptDNSManagement(domain) {
27279
+ ensureInteractive("DNS management confirmation", "run interactively");
27234
27280
  const manage = await clack6.confirm({
27235
27281
  message: `Manage DNS records for ${pc8.cyan(domain)} via Route53?`,
27236
27282
  initialValue: true
@@ -27242,6 +27288,7 @@ async function promptDNSManagement(domain) {
27242
27288
  return manage;
27243
27289
  }
27244
27290
  async function promptDNSProvider(domain, availableProviders) {
27291
+ ensureInteractive("DNS provider", "run interactively");
27245
27292
  const options = availableProviders.map((p3) => {
27246
27293
  let label;
27247
27294
  let hint;
@@ -27283,6 +27330,7 @@ async function promptDNSProvider(domain, availableProviders) {
27283
27330
  return provider;
27284
27331
  }
27285
27332
  async function promptInboundSubdomain(domain) {
27333
+ ensureInteractive("Inbound subdomain", "--subdomain <subdomain>");
27286
27334
  const choice = await clack6.select({
27287
27335
  message: `Where should ${pc8.cyan(domain)} receive inbound email?`,
27288
27336
  options: [
@@ -27327,6 +27375,7 @@ async function promptInboundSubdomain(domain) {
27327
27375
  return subdomain || "inbound";
27328
27376
  }
27329
27377
  async function promptWebhookUrl() {
27378
+ ensureInteractive("Webhook URL confirmation", "run interactively");
27330
27379
  const wantsWebhook = await clack6.confirm({
27331
27380
  message: "Send inbound email events to a webhook URL?",
27332
27381
  initialValue: false
@@ -27363,6 +27412,7 @@ async function promptWebhookUrl() {
27363
27412
  return url;
27364
27413
  }
27365
27414
  async function promptDNSRecordSelection(records, providerName) {
27415
+ ensureInteractive("DNS record selection", "run interactively");
27366
27416
  const { DNS_RECORD_DESCRIPTIONS: DNS_RECORD_DESCRIPTIONS2 } = await Promise.resolve().then(() => (init_create_records(), create_records_exports));
27367
27417
  const categories = /* @__PURE__ */ new Map();
27368
27418
  for (const record of records) {
@@ -27410,6 +27460,10 @@ async function promptDNSRecordSelection(records, providerName) {
27410
27460
  };
27411
27461
  }
27412
27462
  async function promptContinueManualDNS() {
27463
+ ensureInteractive(
27464
+ "Manual DNS continuation confirmation",
27465
+ "run interactively"
27466
+ );
27413
27467
  const continueManual = await clack6.confirm({
27414
27468
  message: "Continue with manual DNS setup?",
27415
27469
  initialValue: true
@@ -27421,6 +27475,7 @@ async function promptContinueManualDNS() {
27421
27475
  return continueManual;
27422
27476
  }
27423
27477
  async function promptSubdomainSuggestions(primaryDomain) {
27478
+ ensureInteractive("Subdomain suggestion", "--domain <subdomain.domain>");
27424
27479
  clack6.log.info(
27425
27480
  pc8.dim(
27426
27481
  "Using subdomains isolates sender reputation \u2014 a bounce spike on marketing won't affect transactional mail."
@@ -27475,6 +27530,7 @@ async function promptSubdomainSuggestions(primaryDomain) {
27475
27530
  return choice;
27476
27531
  }
27477
27532
  async function promptDomainPurpose() {
27533
+ ensureInteractive("Domain purpose", "--quick");
27478
27534
  const purpose = await clack6.select({
27479
27535
  message: "What will this domain be used for?",
27480
27536
  options: [
@@ -27507,6 +27563,7 @@ async function promptDomainPurpose() {
27507
27563
  return purpose;
27508
27564
  }
27509
27565
  async function promptMailFromSubdomain(domain) {
27566
+ ensureInteractive("MAIL FROM subdomain", "--preset (non-custom)");
27510
27567
  const subdomain = await clack6.text({
27511
27568
  message: `MAIL FROM subdomain for ${pc8.cyan(domain)}:`,
27512
27569
  placeholder: "mail",
@@ -27532,6 +27589,8 @@ var init_prompts = __esm({
27532
27589
  "use strict";
27533
27590
  init_esm_shims();
27534
27591
  init_dist();
27592
+ init_errors();
27593
+ init_json_output();
27535
27594
  REQUIRED_SUPPRESSION_EVENT_TYPES = [
27536
27595
  "BOUNCE",
27537
27596
  "COMPLAINT"
@@ -30536,7 +30595,7 @@ __export(preflight_exports, {
30536
30595
  });
30537
30596
  import * as clack25 from "@clack/prompts";
30538
30597
  import pc27 from "picocolors";
30539
- async function runPreflightScan(region, domain) {
30598
+ async function runPreflightScan(region, domain, opts) {
30540
30599
  const scan = await scanAWSResources(region);
30541
30600
  const filtered = filterWrapsResources(scan);
30542
30601
  const existing = checkWrapsResourcesExist(filtered);
@@ -30582,6 +30641,15 @@ async function runPreflightScan(region, domain) {
30582
30641
  }
30583
30642
  }
30584
30643
  if (hasConflicts) {
30644
+ if (!isInteractive() || isJsonMode()) {
30645
+ if (opts?.force) {
30646
+ clack25.log.warn("Conflicts detected \u2014 continuing due to --force.");
30647
+ return { shouldContinue: true, scan };
30648
+ }
30649
+ throw errors.resourceConflict(
30650
+ resourceTypes.length > 0 ? resourceTypes.join(", ") : domain ?? "domain"
30651
+ );
30652
+ }
30585
30653
  const shouldContinue = await clack25.confirm({
30586
30654
  message: "Continue anyway?",
30587
30655
  initialValue: false
@@ -30596,6 +30664,9 @@ var init_preflight = __esm({
30596
30664
  "src/utils/shared/preflight.ts"() {
30597
30665
  "use strict";
30598
30666
  init_esm_shims();
30667
+ init_errors();
30668
+ init_json_output();
30669
+ init_prompts();
30599
30670
  init_scanner();
30600
30671
  }
30601
30672
  });
@@ -32547,6 +32618,8 @@ async function doctor() {
32547
32618
  init_esm_shims();
32548
32619
  init_events();
32549
32620
  init_aws_detection();
32621
+ init_errors();
32622
+ init_json_output();
32550
32623
  init_prompts();
32551
32624
  import * as clack7 from "@clack/prompts";
32552
32625
  import pc9 from "picocolors";
@@ -33097,6 +33170,12 @@ function showNextSteps(_state) {
33097
33170
  console.log();
33098
33171
  }
33099
33172
  async function setup(_options = {}) {
33173
+ if (!isInteractive() || isJsonMode()) {
33174
+ throw errors.nonInteractiveInput(
33175
+ "AWS Setup Wizard",
33176
+ "manual setup \u2014 see https://wraps.dev/docs/guides/aws-setup"
33177
+ );
33178
+ }
33100
33179
  const startTime = Date.now();
33101
33180
  clack7.intro(pc9.bold("AWS Setup Wizard"));
33102
33181
  const spinner11 = clack7.spinner();
@@ -34318,6 +34397,7 @@ init_output();
34318
34397
  init_prompts();
34319
34398
  init_pulumi();
34320
34399
  async function promptCdnPreset() {
34400
+ ensureInteractive("Preset", "--preset <starter|production|custom>");
34321
34401
  const starterInfo = getPresetInfo2("starter");
34322
34402
  const productionInfo = getPresetInfo2("production");
34323
34403
  const customInfo = getPresetInfo2("custom");
@@ -34348,6 +34428,10 @@ async function promptCdnPreset() {
34348
34428
  return result;
34349
34429
  }
34350
34430
  async function promptCustomCdnConfig() {
34431
+ ensureInteractive(
34432
+ "Custom CDN configuration",
34433
+ "--preset starter|production (custom requires an interactive terminal)"
34434
+ );
34351
34435
  const cdnEnabled = await clack10.confirm({
34352
34436
  message: "Enable CloudFront CDN for fast global delivery?",
34353
34437
  initialValue: true
@@ -34470,6 +34554,7 @@ async function promptCustomCdnConfig() {
34470
34554
  };
34471
34555
  }
34472
34556
  async function promptCustomDomain() {
34557
+ ensureInteractive("Custom domain confirmation", "--domain <domain>");
34473
34558
  const wantCustomDomain = await clack10.confirm({
34474
34559
  message: "Configure a custom CDN domain? (e.g., cdn.yourapp.com)",
34475
34560
  initialValue: false
@@ -34503,6 +34588,10 @@ async function promptCustomDomain() {
34503
34588
  return domain;
34504
34589
  }
34505
34590
  async function promptEstimatedUsage() {
34591
+ ensureInteractive(
34592
+ "Estimated usage",
34593
+ "--preset <starter|production> (usage estimate requires an interactive terminal)"
34594
+ );
34506
34595
  const usage = await clack10.select({
34507
34596
  message: "Estimated monthly usage (for cost estimate):",
34508
34597
  options: [
@@ -34896,10 +34985,10 @@ ${pc12.yellow(pc12.bold("Configuration Notes:"))}`);
34896
34985
  )
34897
34986
  );
34898
34987
  }
34899
- const shouldCreate = await clack10.confirm({
34988
+ const shouldCreate = isInteractive() && !isJsonMode() ? await clack10.confirm({
34900
34989
  message: conflictCount > 0 ? `Create ${newCount + conflictCount} DNS record(s)? (${conflictCount} will overwrite existing)` : `Create ${newCount} DNS record(s) in Route53?`,
34901
34990
  initialValue: true
34902
- });
34991
+ }) : false;
34903
34992
  if (!clack10.isCancel(shouldCreate) && shouldCreate) {
34904
34993
  progress.start("Creating DNS records in Route53");
34905
34994
  const changes = dnsRecords.filter((r6) => r6.status !== "no_change").map((record) => ({
@@ -46744,6 +46833,15 @@ async function init2(options) {
46744
46833
  region
46745
46834
  );
46746
46835
  if (existingConnection) {
46836
+ if (isJsonMode()) {
46837
+ jsonSuccess("email.init", {
46838
+ alreadyDeployed: true,
46839
+ accountId: identity.accountId,
46840
+ region,
46841
+ createdAt: existingConnection.timestamp
46842
+ });
46843
+ process.exit(0);
46844
+ }
46747
46845
  clack28.log.warn(
46748
46846
  `Connection already exists for account ${pc30.cyan(identity.accountId)} in region ${pc30.cyan(region)}`
46749
46847
  );
@@ -46892,7 +46990,7 @@ ${pc30.yellow(pc30.bold("Configuration Warnings:"))}`);
46892
46990
  const { runPreflightScan: runPreflightScan2 } = await Promise.resolve().then(() => (init_preflight(), preflight_exports));
46893
46991
  const preflight = await progress.execute(
46894
46992
  "Scanning for existing resources",
46895
- async () => runPreflightScan2(region, domain)
46993
+ async () => runPreflightScan2(region, domain, { force: options.force })
46896
46994
  );
46897
46995
  if (!preflight.shouldContinue) {
46898
46996
  clack28.cancel("Deployment cancelled.");
@@ -47327,7 +47425,7 @@ ${pc30.yellow(pc30.bold("Configuration Warnings:"))}`);
47327
47425
  }
47328
47426
  } catch {
47329
47427
  }
47330
- if (!options.preview) {
47428
+ if (!(options.preview || options.quick || options.yes) && isInteractive() && !isJsonMode()) {
47331
47429
  console.log("");
47332
47430
  const wantTest = await clack28.confirm({
47333
47431
  message: "Send a test email to verify everything works?",
@@ -62408,6 +62506,7 @@ import * as pulumi31 from "@pulumi/pulumi";
62408
62506
  import pc59 from "picocolors";
62409
62507
  init_events();
62410
62508
  init_aws();
62509
+ init_errors();
62411
62510
  init_fs();
62412
62511
  init_json_output();
62413
62512
  init_metadata();
@@ -62838,6 +62937,10 @@ function validateSMSConfig(config2) {
62838
62937
 
62839
62938
  // src/commands/sms/init.ts
62840
62939
  async function promptPhoneNumberType() {
62940
+ ensureInteractive(
62941
+ "Phone number type",
62942
+ "--preset starter|production|enterprise (custom requires an interactive terminal)"
62943
+ );
62841
62944
  const result = await clack55.select({
62842
62945
  message: "Select phone number type:",
62843
62946
  options: [
@@ -62865,6 +62968,10 @@ async function promptPhoneNumberType() {
62865
62968
  return result;
62866
62969
  }
62867
62970
  async function promptSMSPreset() {
62971
+ ensureInteractive(
62972
+ "Preset",
62973
+ "--preset <starter|production|enterprise|custom>"
62974
+ );
62868
62975
  const result = await clack55.select({
62869
62976
  message: "Choose configuration preset:",
62870
62977
  options: [
@@ -62943,6 +63050,25 @@ async function promptEstimatedSMSVolume() {
62943
63050
  }
62944
63051
  return result;
62945
63052
  }
63053
+ function parseCountries(raw) {
63054
+ const codes = raw.split(",").map((code) => code.trim().toUpperCase()).filter((code) => code.length > 0);
63055
+ if (codes.length === 0) {
63056
+ throw errors.smsInvalidCountries(raw);
63057
+ }
63058
+ for (const code of codes) {
63059
+ if (!/^[A-Z]{2}$/.test(code)) {
63060
+ throw errors.smsInvalidCountries(raw);
63061
+ }
63062
+ }
63063
+ return codes;
63064
+ }
63065
+ function parseVolume(raw) {
63066
+ const volume = Number.parseInt(raw, 10);
63067
+ if (Number.isNaN(volume) || volume <= 0) {
63068
+ throw errors.smsInvalidVolume(raw);
63069
+ }
63070
+ return volume;
63071
+ }
62946
63072
  async function init3(options) {
62947
63073
  const startTime = Date.now();
62948
63074
  if (!isJsonMode()) {
@@ -62980,7 +63106,7 @@ async function init3(options) {
62980
63106
  }
62981
63107
  let preset = options.preset;
62982
63108
  if (!preset) {
62983
- preset = await promptSMSPreset();
63109
+ preset = options.quick ? "starter" : await promptSMSPreset();
62984
63110
  }
62985
63111
  let smsConfig;
62986
63112
  if (preset === "custom") {
@@ -62992,6 +63118,10 @@ async function init3(options) {
62992
63118
  optOutManagement: true,
62993
63119
  sendingEnabled: true
62994
63120
  };
63121
+ ensureInteractive(
63122
+ "Event tracking confirmation",
63123
+ "--preset starter|production|enterprise (custom requires an interactive terminal)"
63124
+ );
62995
63125
  const enableEventTracking = await clack55.confirm({
62996
63126
  message: "Enable event tracking (EventBridge + DynamoDB)?",
62997
63127
  initialValue: false
@@ -63019,9 +63149,17 @@ async function init3(options) {
63019
63149
  `
63020
63150
  ${pc59.bold("Fraud Protection")} - Block SMS to countries where you don't do business`
63021
63151
  );
63022
- const allowedCountries = await promptAllowedCountries();
63152
+ let allowedCountries;
63153
+ if (options.countries) {
63154
+ allowedCountries = parseCountries(options.countries);
63155
+ } else if (options.quick) {
63156
+ allowedCountries = ["US"];
63157
+ } else {
63158
+ ensureInteractive("Allowed countries", "--countries <US,CA,\u2026>");
63159
+ allowedCountries = await promptAllowedCountries();
63160
+ }
63023
63161
  let aitFiltering = false;
63024
- if (smsConfig.phoneNumberType !== "simulator") {
63162
+ if (smsConfig.phoneNumberType !== "simulator" && isInteractive() && !isJsonMode() && !options.quick) {
63025
63163
  const enableAIT = await clack55.confirm({
63026
63164
  message: "Enable AIT (Artificially Inflated Traffic) filtering? (adds per-message cost)",
63027
63165
  initialValue: false
@@ -63037,7 +63175,15 @@ ${pc59.bold("Fraud Protection")} - Block SMS to countries where you don't do bus
63037
63175
  allowedCountries,
63038
63176
  aitFiltering
63039
63177
  };
63040
- const estimatedVolume = await promptEstimatedSMSVolume();
63178
+ let estimatedVolume;
63179
+ if (options.volume) {
63180
+ estimatedVolume = parseVolume(options.volume);
63181
+ } else if (options.quick) {
63182
+ estimatedVolume = 100;
63183
+ } else {
63184
+ ensureInteractive("Estimated volume", "--volume <messages-per-month>");
63185
+ estimatedVolume = await promptEstimatedSMSVolume();
63186
+ }
63041
63187
  progress.info(`
63042
63188
  ${pc59.bold("Cost Estimate:")}`);
63043
63189
  const costSummary = getSMSCostSummary(smsConfig, estimatedVolume);
@@ -65777,6 +65923,7 @@ var STRING_FLAGS = [
65777
65923
  "cursor",
65778
65924
  "set",
65779
65925
  "volume",
65926
+ "countries",
65780
65927
  "since",
65781
65928
  "filter",
65782
65929
  "source"
@@ -66187,7 +66334,7 @@ if (!primaryCommand) {
66187
66334
  async function interactiveMenu() {
66188
66335
  const startTime = Date.now();
66189
66336
  const telemetry = getTelemetryClient();
66190
- if (telemetry.shouldShowNotification()) {
66337
+ if (!isJsonMode() && telemetry.shouldShowNotification()) {
66191
66338
  console.log();
66192
66339
  clack65.log.info(pc70.bold("Anonymous Telemetry"));
66193
66340
  console.log(
@@ -66343,7 +66490,7 @@ if (!primaryCommand) {
66343
66490
  async function run() {
66344
66491
  const startTime = Date.now();
66345
66492
  const telemetry = getTelemetryClient();
66346
- if (telemetry.shouldShowNotification()) {
66493
+ if (!isJsonMode() && telemetry.shouldShowNotification()) {
66347
66494
  console.log();
66348
66495
  clack65.log.info(pc70.bold("Anonymous Telemetry"));
66349
66496
  console.log(
@@ -66374,7 +66521,8 @@ async function run() {
66374
66521
  yes: flags.yes,
66375
66522
  preview: flags.preview,
66376
66523
  quick: flags.quick,
66377
- json: flags.json
66524
+ json: flags.json,
66525
+ force: flags.force
66378
66526
  });
66379
66527
  break;
66380
66528
  case "test":
@@ -67006,7 +67154,10 @@ Run ${pc70.cyan("wraps --help")} for available commands.
67006
67154
  preset: flags.preset,
67007
67155
  yes: flags.yes,
67008
67156
  preview: flags.preview,
67009
- json: flags.json
67157
+ json: flags.json,
67158
+ quick: flags.quick,
67159
+ countries: flags.countries,
67160
+ volume: flags.volume
67010
67161
  });
67011
67162
  break;
67012
67163
  case "status":
@@ -67245,9 +67396,7 @@ Available commands: ${pc70.cyan("login")}, ${pc70.cyan("status")}, ${pc70.cyan("
67245
67396
  if (primaryCommand === "aws" && subCommand) {
67246
67397
  switch (subCommand) {
67247
67398
  case "setup":
67248
- await setup({
67249
- yes: flags.yes
67250
- });
67399
+ await setup({});
67251
67400
  break;
67252
67401
  case "doctor":
67253
67402
  await doctor();