@wraps.dev/cli 0.1.4 → 0.1.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 +313 -99
- package/dist/cli.js.map +1 -1
- package/dist/lambda/event-processor/.bundled +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -1348,9 +1348,12 @@ var init_route53 = __esm({
|
|
|
1348
1348
|
|
|
1349
1349
|
// src/cli.ts
|
|
1350
1350
|
init_esm_shims();
|
|
1351
|
-
import
|
|
1351
|
+
import { readFileSync } from "fs";
|
|
1352
|
+
import { dirname as dirname2, join as join4 } from "path";
|
|
1353
|
+
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
1354
|
+
import * as clack13 from "@clack/prompts";
|
|
1352
1355
|
import args from "args";
|
|
1353
|
-
import
|
|
1356
|
+
import pc13 from "picocolors";
|
|
1354
1357
|
|
|
1355
1358
|
// src/commands/connect.ts
|
|
1356
1359
|
init_esm_shims();
|
|
@@ -4369,17 +4372,14 @@ Run ${pc9.cyan("wraps init")} to deploy infrastructure.
|
|
|
4369
4372
|
});
|
|
4370
4373
|
}
|
|
4371
4374
|
|
|
4372
|
-
// src/commands/
|
|
4375
|
+
// src/commands/update.ts
|
|
4373
4376
|
init_esm_shims();
|
|
4374
4377
|
import * as clack10 from "@clack/prompts";
|
|
4375
4378
|
import * as pulumi11 from "@pulumi/pulumi";
|
|
4376
4379
|
import pc10 from "picocolors";
|
|
4377
4380
|
init_aws();
|
|
4378
|
-
|
|
4379
|
-
|
|
4380
|
-
init_prompts();
|
|
4381
|
-
async function upgrade(options) {
|
|
4382
|
-
clack10.intro(pc10.bold("Wraps Upgrade - Enhance Your Email Infrastructure"));
|
|
4381
|
+
async function update(options) {
|
|
4382
|
+
clack10.intro(pc10.bold("Wraps Update - Apply CLI Updates to Infrastructure"));
|
|
4383
4383
|
const progress = new DeploymentProgress();
|
|
4384
4384
|
const wasAutoInstalled = await progress.execute(
|
|
4385
4385
|
"Checking Pulumi CLI installation",
|
|
@@ -4423,33 +4423,224 @@ ${pc10.bold("Current Configuration:")}
|
|
|
4423
4423
|
}
|
|
4424
4424
|
if (config.tracking?.enabled) {
|
|
4425
4425
|
console.log(` ${pc10.green("\u2713")} Open & Click Tracking`);
|
|
4426
|
+
}
|
|
4427
|
+
if (config.suppressionList?.enabled) {
|
|
4428
|
+
console.log(` ${pc10.green("\u2713")} Bounce/Complaint Suppression`);
|
|
4429
|
+
}
|
|
4430
|
+
if (config.eventTracking?.enabled) {
|
|
4431
|
+
console.log(` ${pc10.green("\u2713")} Event Tracking (EventBridge)`);
|
|
4432
|
+
}
|
|
4433
|
+
if (config.dedicatedIp) {
|
|
4434
|
+
console.log(` ${pc10.green("\u2713")} Dedicated IP Address`);
|
|
4435
|
+
}
|
|
4436
|
+
console.log("");
|
|
4437
|
+
console.log(`${pc10.bold("What will be updated:")}
|
|
4438
|
+
`);
|
|
4439
|
+
console.log(
|
|
4440
|
+
` ${pc10.cyan("\u2022")} Lambda function code (if event tracking enabled)`
|
|
4441
|
+
);
|
|
4442
|
+
console.log(
|
|
4443
|
+
` ${pc10.cyan("\u2022")} EventBridge rules (if event tracking enabled)`
|
|
4444
|
+
);
|
|
4445
|
+
console.log(` ${pc10.cyan("\u2022")} IAM policies (security improvements)`);
|
|
4446
|
+
console.log(` ${pc10.cyan("\u2022")} SES configuration set (feature updates)`);
|
|
4447
|
+
console.log("");
|
|
4448
|
+
progress.info(
|
|
4449
|
+
"Your current configuration will be preserved - no features will be added or removed"
|
|
4450
|
+
);
|
|
4451
|
+
console.log("");
|
|
4452
|
+
if (!options.yes) {
|
|
4453
|
+
const confirmed = await clack10.confirm({
|
|
4454
|
+
message: "Proceed with update?",
|
|
4455
|
+
initialValue: true
|
|
4456
|
+
});
|
|
4457
|
+
if (clack10.isCancel(confirmed) || !confirmed) {
|
|
4458
|
+
clack10.cancel("Update cancelled.");
|
|
4459
|
+
process.exit(0);
|
|
4460
|
+
}
|
|
4461
|
+
}
|
|
4462
|
+
let vercelConfig;
|
|
4463
|
+
if (metadata.provider === "vercel" && metadata.vercel) {
|
|
4464
|
+
vercelConfig = metadata.vercel;
|
|
4465
|
+
}
|
|
4466
|
+
const stackConfig = {
|
|
4467
|
+
provider: metadata.provider,
|
|
4468
|
+
region,
|
|
4469
|
+
vercel: vercelConfig,
|
|
4470
|
+
emailConfig: config
|
|
4471
|
+
};
|
|
4472
|
+
let outputs;
|
|
4473
|
+
try {
|
|
4474
|
+
outputs = await progress.execute(
|
|
4475
|
+
"Updating Wraps infrastructure (this may take 2-3 minutes)",
|
|
4476
|
+
async () => {
|
|
4477
|
+
await ensurePulumiWorkDir();
|
|
4478
|
+
const stack = await pulumi11.automation.LocalWorkspace.createOrSelectStack(
|
|
4479
|
+
{
|
|
4480
|
+
stackName: metadata.pulumiStackName || `wraps-${identity.accountId}-${region}`,
|
|
4481
|
+
projectName: "wraps-email",
|
|
4482
|
+
program: async () => {
|
|
4483
|
+
const result = await deployEmailStack(stackConfig);
|
|
4484
|
+
return {
|
|
4485
|
+
roleArn: result.roleArn,
|
|
4486
|
+
configSetName: result.configSetName,
|
|
4487
|
+
tableName: result.tableName,
|
|
4488
|
+
region: result.region,
|
|
4489
|
+
lambdaFunctions: result.lambdaFunctions,
|
|
4490
|
+
domain: result.domain,
|
|
4491
|
+
dkimTokens: result.dkimTokens,
|
|
4492
|
+
customTrackingDomain: result.customTrackingDomain
|
|
4493
|
+
};
|
|
4494
|
+
}
|
|
4495
|
+
},
|
|
4496
|
+
{
|
|
4497
|
+
workDir: getPulumiWorkDir(),
|
|
4498
|
+
envVars: {
|
|
4499
|
+
PULUMI_CONFIG_PASSPHRASE: ""
|
|
4500
|
+
},
|
|
4501
|
+
secretsProvider: "passphrase"
|
|
4502
|
+
}
|
|
4503
|
+
);
|
|
4504
|
+
await stack.workspace.selectStack(
|
|
4505
|
+
metadata.pulumiStackName || `wraps-${identity.accountId}-${region}`
|
|
4506
|
+
);
|
|
4507
|
+
await stack.setConfig("aws:region", { value: region });
|
|
4508
|
+
const upResult = await stack.up({ onOutput: () => {
|
|
4509
|
+
} });
|
|
4510
|
+
const pulumiOutputs = upResult.outputs;
|
|
4511
|
+
return {
|
|
4512
|
+
roleArn: pulumiOutputs.roleArn?.value,
|
|
4513
|
+
configSetName: pulumiOutputs.configSetName?.value,
|
|
4514
|
+
tableName: pulumiOutputs.tableName?.value,
|
|
4515
|
+
region: pulumiOutputs.region?.value,
|
|
4516
|
+
lambdaFunctions: pulumiOutputs.lambdaFunctions?.value,
|
|
4517
|
+
domain: pulumiOutputs.domain?.value,
|
|
4518
|
+
dkimTokens: pulumiOutputs.dkimTokens?.value,
|
|
4519
|
+
customTrackingDomain: pulumiOutputs.customTrackingDomain?.value
|
|
4520
|
+
};
|
|
4521
|
+
}
|
|
4522
|
+
);
|
|
4523
|
+
} catch (error) {
|
|
4524
|
+
clack10.log.error("Infrastructure update failed");
|
|
4525
|
+
if (error.message?.includes("stack is currently locked")) {
|
|
4526
|
+
clack10.log.warn("\nThe Pulumi stack is locked from a previous run.");
|
|
4527
|
+
clack10.log.info("To fix this, run:");
|
|
4528
|
+
clack10.log.info(` ${pc10.cyan("rm -rf ~/.wraps/pulumi/.pulumi/locks")}`);
|
|
4529
|
+
clack10.log.info("\nThen try running wraps update again.");
|
|
4530
|
+
}
|
|
4531
|
+
throw new Error(`Pulumi update failed: ${error.message}`);
|
|
4532
|
+
}
|
|
4533
|
+
metadata.timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
4534
|
+
await saveConnectionMetadata(metadata);
|
|
4535
|
+
progress.info("Connection metadata updated");
|
|
4536
|
+
displaySuccess({
|
|
4537
|
+
roleArn: outputs.roleArn,
|
|
4538
|
+
configSetName: outputs.configSetName,
|
|
4539
|
+
region: outputs.region,
|
|
4540
|
+
tableName: outputs.tableName,
|
|
4541
|
+
customTrackingDomain: outputs.customTrackingDomain
|
|
4542
|
+
});
|
|
4543
|
+
console.log(`
|
|
4544
|
+
${pc10.green("\u2713")} ${pc10.bold("Update complete!")}
|
|
4545
|
+
`);
|
|
4546
|
+
console.log(
|
|
4547
|
+
"Infrastructure has been updated with the latest CLI improvements.\n"
|
|
4548
|
+
);
|
|
4549
|
+
console.log(`${pc10.bold("Next steps:")}
|
|
4550
|
+
`);
|
|
4551
|
+
console.log(
|
|
4552
|
+
` ${pc10.cyan("1.")} No code changes needed - your existing SDK integration continues to work`
|
|
4553
|
+
);
|
|
4554
|
+
console.log(
|
|
4555
|
+
` ${pc10.cyan("2.")} Check ${pc10.cyan("wraps status")} to verify all resources are healthy`
|
|
4556
|
+
);
|
|
4557
|
+
console.log(
|
|
4558
|
+
` ${pc10.cyan("3.")} View analytics at ${pc10.cyan("wraps console")}
|
|
4559
|
+
`
|
|
4560
|
+
);
|
|
4561
|
+
}
|
|
4562
|
+
|
|
4563
|
+
// src/commands/upgrade.ts
|
|
4564
|
+
init_esm_shims();
|
|
4565
|
+
import * as clack11 from "@clack/prompts";
|
|
4566
|
+
import * as pulumi12 from "@pulumi/pulumi";
|
|
4567
|
+
import pc11 from "picocolors";
|
|
4568
|
+
init_aws();
|
|
4569
|
+
init_costs();
|
|
4570
|
+
init_presets();
|
|
4571
|
+
init_prompts();
|
|
4572
|
+
async function upgrade(options) {
|
|
4573
|
+
clack11.intro(pc11.bold("Wraps Upgrade - Enhance Your Email Infrastructure"));
|
|
4574
|
+
const progress = new DeploymentProgress();
|
|
4575
|
+
const wasAutoInstalled = await progress.execute(
|
|
4576
|
+
"Checking Pulumi CLI installation",
|
|
4577
|
+
async () => await ensurePulumiInstalled()
|
|
4578
|
+
);
|
|
4579
|
+
if (wasAutoInstalled) {
|
|
4580
|
+
progress.info("Pulumi CLI was automatically installed");
|
|
4581
|
+
}
|
|
4582
|
+
const identity = await progress.execute(
|
|
4583
|
+
"Validating AWS credentials",
|
|
4584
|
+
async () => validateAWSCredentials()
|
|
4585
|
+
);
|
|
4586
|
+
progress.info(`Connected to AWS account: ${pc11.cyan(identity.accountId)}`);
|
|
4587
|
+
let region = options.region;
|
|
4588
|
+
if (!region) {
|
|
4589
|
+
const defaultRegion = await getAWSRegion();
|
|
4590
|
+
region = defaultRegion;
|
|
4591
|
+
}
|
|
4592
|
+
const metadata = await loadConnectionMetadata(identity.accountId, region);
|
|
4593
|
+
if (!metadata) {
|
|
4594
|
+
clack11.log.error(
|
|
4595
|
+
`No Wraps connection found for account ${pc11.cyan(identity.accountId)} in region ${pc11.cyan(region)}`
|
|
4596
|
+
);
|
|
4597
|
+
clack11.log.info(
|
|
4598
|
+
`Use ${pc11.cyan("wraps init")} to create new infrastructure or ${pc11.cyan("wraps connect")} to connect existing.`
|
|
4599
|
+
);
|
|
4600
|
+
process.exit(1);
|
|
4601
|
+
}
|
|
4602
|
+
progress.info(`Found existing connection created: ${metadata.timestamp}`);
|
|
4603
|
+
console.log(`
|
|
4604
|
+
${pc11.bold("Current Configuration:")}
|
|
4605
|
+
`);
|
|
4606
|
+
if (metadata.preset) {
|
|
4607
|
+
console.log(` Preset: ${pc11.cyan(metadata.preset)}`);
|
|
4608
|
+
} else {
|
|
4609
|
+
console.log(` Preset: ${pc11.cyan("custom")}`);
|
|
4610
|
+
}
|
|
4611
|
+
const config = metadata.emailConfig;
|
|
4612
|
+
if (config.domain) {
|
|
4613
|
+
console.log(` Sending Domain: ${pc11.cyan(config.domain)}`);
|
|
4614
|
+
}
|
|
4615
|
+
if (config.tracking?.enabled) {
|
|
4616
|
+
console.log(` ${pc11.green("\u2713")} Open & Click Tracking`);
|
|
4426
4617
|
if (config.tracking.customRedirectDomain) {
|
|
4427
4618
|
console.log(
|
|
4428
|
-
` ${
|
|
4619
|
+
` ${pc11.dim("\u2514\u2500")} Custom domain: ${pc11.cyan(config.tracking.customRedirectDomain)}`
|
|
4429
4620
|
);
|
|
4430
4621
|
}
|
|
4431
4622
|
}
|
|
4432
4623
|
if (config.suppressionList?.enabled) {
|
|
4433
|
-
console.log(` ${
|
|
4624
|
+
console.log(` ${pc11.green("\u2713")} Bounce/Complaint Suppression`);
|
|
4434
4625
|
}
|
|
4435
4626
|
if (config.eventTracking?.enabled) {
|
|
4436
|
-
console.log(` ${
|
|
4627
|
+
console.log(` ${pc11.green("\u2713")} Event Tracking (EventBridge)`);
|
|
4437
4628
|
if (config.eventTracking.dynamoDBHistory) {
|
|
4438
4629
|
console.log(
|
|
4439
|
-
` ${
|
|
4630
|
+
` ${pc11.dim("\u2514\u2500")} Email History: ${pc11.cyan(config.eventTracking.archiveRetention || "90days")}`
|
|
4440
4631
|
);
|
|
4441
4632
|
}
|
|
4442
4633
|
}
|
|
4443
4634
|
if (config.dedicatedIp) {
|
|
4444
|
-
console.log(` ${
|
|
4635
|
+
console.log(` ${pc11.green("\u2713")} Dedicated IP Address`);
|
|
4445
4636
|
}
|
|
4446
4637
|
const currentCostData = calculateCosts(config, 5e4);
|
|
4447
4638
|
console.log(
|
|
4448
4639
|
`
|
|
4449
|
-
Estimated Cost: ${
|
|
4640
|
+
Estimated Cost: ${pc11.cyan(`~${formatCost(currentCostData.total.monthly)}/mo`)}`
|
|
4450
4641
|
);
|
|
4451
4642
|
console.log("");
|
|
4452
|
-
const upgradeAction = await
|
|
4643
|
+
const upgradeAction = await clack11.select({
|
|
4453
4644
|
message: "What would you like to do?",
|
|
4454
4645
|
options: [
|
|
4455
4646
|
{
|
|
@@ -4484,8 +4675,8 @@ ${pc10.bold("Current Configuration:")}
|
|
|
4484
4675
|
}
|
|
4485
4676
|
]
|
|
4486
4677
|
});
|
|
4487
|
-
if (
|
|
4488
|
-
|
|
4678
|
+
if (clack11.isCancel(upgradeAction)) {
|
|
4679
|
+
clack11.cancel("Upgrade cancelled.");
|
|
4489
4680
|
process.exit(0);
|
|
4490
4681
|
}
|
|
4491
4682
|
let updatedConfig = { ...config };
|
|
@@ -4503,15 +4694,15 @@ ${pc10.bold("Current Configuration:")}
|
|
|
4503
4694
|
disabled: currentPresetIdx >= 0 && idx <= currentPresetIdx ? "Current or lower tier" : void 0
|
|
4504
4695
|
})).filter((p) => !p.disabled);
|
|
4505
4696
|
if (availablePresets.length === 0) {
|
|
4506
|
-
|
|
4697
|
+
clack11.log.warn("Already on highest preset (Enterprise)");
|
|
4507
4698
|
process.exit(0);
|
|
4508
4699
|
}
|
|
4509
|
-
const selectedPreset = await
|
|
4700
|
+
const selectedPreset = await clack11.select({
|
|
4510
4701
|
message: "Select new preset:",
|
|
4511
4702
|
options: availablePresets
|
|
4512
4703
|
});
|
|
4513
|
-
if (
|
|
4514
|
-
|
|
4704
|
+
if (clack11.isCancel(selectedPreset)) {
|
|
4705
|
+
clack11.cancel("Upgrade cancelled.");
|
|
4515
4706
|
process.exit(0);
|
|
4516
4707
|
}
|
|
4517
4708
|
const presetConfig = getPreset(selectedPreset);
|
|
@@ -4525,11 +4716,11 @@ ${pc10.bold("Current Configuration:")}
|
|
|
4525
4716
|
}
|
|
4526
4717
|
case "tracking-domain": {
|
|
4527
4718
|
if (!config.domain) {
|
|
4528
|
-
|
|
4719
|
+
clack11.log.error(
|
|
4529
4720
|
"No sending domain configured. You must configure a sending domain before adding a custom tracking domain."
|
|
4530
4721
|
);
|
|
4531
|
-
|
|
4532
|
-
`Use ${
|
|
4722
|
+
clack11.log.info(
|
|
4723
|
+
`Use ${pc11.cyan("wraps init")} to set up a sending domain first.`
|
|
4533
4724
|
);
|
|
4534
4725
|
process.exit(1);
|
|
4535
4726
|
}
|
|
@@ -4540,21 +4731,21 @@ ${pc10.bold("Current Configuration:")}
|
|
|
4540
4731
|
);
|
|
4541
4732
|
const sendingDomain = domains.find((d) => d.domain === config.domain);
|
|
4542
4733
|
if (!sendingDomain?.verified) {
|
|
4543
|
-
|
|
4544
|
-
`Sending domain ${
|
|
4734
|
+
clack11.log.error(
|
|
4735
|
+
`Sending domain ${pc11.cyan(config.domain)} is not verified.`
|
|
4545
4736
|
);
|
|
4546
|
-
|
|
4737
|
+
clack11.log.info(
|
|
4547
4738
|
"You must verify your sending domain before adding a custom tracking domain."
|
|
4548
4739
|
);
|
|
4549
|
-
|
|
4550
|
-
`Use ${
|
|
4740
|
+
clack11.log.info(
|
|
4741
|
+
`Use ${pc11.cyan("wraps verify")} to check DNS records and complete verification.`
|
|
4551
4742
|
);
|
|
4552
4743
|
process.exit(1);
|
|
4553
4744
|
}
|
|
4554
4745
|
progress.info(
|
|
4555
|
-
`Sending domain ${
|
|
4746
|
+
`Sending domain ${pc11.cyan(config.domain)} is verified ${pc11.green("\u2713")}`
|
|
4556
4747
|
);
|
|
4557
|
-
const trackingDomain = await
|
|
4748
|
+
const trackingDomain = await clack11.text({
|
|
4558
4749
|
message: "Custom tracking redirect domain:",
|
|
4559
4750
|
placeholder: "track.yourdomain.com",
|
|
4560
4751
|
initialValue: config.tracking?.customRedirectDomain || "",
|
|
@@ -4564,8 +4755,8 @@ ${pc10.bold("Current Configuration:")}
|
|
|
4564
4755
|
}
|
|
4565
4756
|
}
|
|
4566
4757
|
});
|
|
4567
|
-
if (
|
|
4568
|
-
|
|
4758
|
+
if (clack11.isCancel(trackingDomain)) {
|
|
4759
|
+
clack11.cancel("Upgrade cancelled.");
|
|
4569
4760
|
process.exit(0);
|
|
4570
4761
|
}
|
|
4571
4762
|
updatedConfig = {
|
|
@@ -4580,7 +4771,7 @@ ${pc10.bold("Current Configuration:")}
|
|
|
4580
4771
|
break;
|
|
4581
4772
|
}
|
|
4582
4773
|
case "retention": {
|
|
4583
|
-
const retention = await
|
|
4774
|
+
const retention = await clack11.select({
|
|
4584
4775
|
message: "Email history retention period:",
|
|
4585
4776
|
options: [
|
|
4586
4777
|
{ value: "7days", label: "7 days", hint: "Minimal storage cost" },
|
|
@@ -4599,8 +4790,8 @@ ${pc10.bold("Current Configuration:")}
|
|
|
4599
4790
|
],
|
|
4600
4791
|
initialValue: config.eventTracking?.archiveRetention || "90days"
|
|
4601
4792
|
});
|
|
4602
|
-
if (
|
|
4603
|
-
|
|
4793
|
+
if (clack11.isCancel(retention)) {
|
|
4794
|
+
clack11.cancel("Upgrade cancelled.");
|
|
4604
4795
|
process.exit(0);
|
|
4605
4796
|
}
|
|
4606
4797
|
updatedConfig = {
|
|
@@ -4616,7 +4807,7 @@ ${pc10.bold("Current Configuration:")}
|
|
|
4616
4807
|
break;
|
|
4617
4808
|
}
|
|
4618
4809
|
case "events": {
|
|
4619
|
-
const selectedEvents = await
|
|
4810
|
+
const selectedEvents = await clack11.multiselect({
|
|
4620
4811
|
message: "Select SES event types to track:",
|
|
4621
4812
|
options: [
|
|
4622
4813
|
{ value: "SEND", label: "Send", hint: "Email sent to SES" },
|
|
@@ -4660,8 +4851,8 @@ ${pc10.bold("Current Configuration:")}
|
|
|
4660
4851
|
],
|
|
4661
4852
|
required: true
|
|
4662
4853
|
});
|
|
4663
|
-
if (
|
|
4664
|
-
|
|
4854
|
+
if (clack11.isCancel(selectedEvents)) {
|
|
4855
|
+
clack11.cancel("Upgrade cancelled.");
|
|
4665
4856
|
process.exit(0);
|
|
4666
4857
|
}
|
|
4667
4858
|
updatedConfig = {
|
|
@@ -4676,16 +4867,16 @@ ${pc10.bold("Current Configuration:")}
|
|
|
4676
4867
|
break;
|
|
4677
4868
|
}
|
|
4678
4869
|
case "dedicated-ip": {
|
|
4679
|
-
const confirmed = await
|
|
4870
|
+
const confirmed = await clack11.confirm({
|
|
4680
4871
|
message: "Enable dedicated IP? (Requires 100k+ emails/day, adds ~$50-100/mo)",
|
|
4681
4872
|
initialValue: false
|
|
4682
4873
|
});
|
|
4683
|
-
if (
|
|
4684
|
-
|
|
4874
|
+
if (clack11.isCancel(confirmed)) {
|
|
4875
|
+
clack11.cancel("Upgrade cancelled.");
|
|
4685
4876
|
process.exit(0);
|
|
4686
4877
|
}
|
|
4687
4878
|
if (!confirmed) {
|
|
4688
|
-
|
|
4879
|
+
clack11.log.info("Dedicated IP not enabled.");
|
|
4689
4880
|
process.exit(0);
|
|
4690
4881
|
}
|
|
4691
4882
|
updatedConfig = {
|
|
@@ -4709,28 +4900,28 @@ ${pc10.bold("Current Configuration:")}
|
|
|
4709
4900
|
const newCostData = calculateCosts(updatedConfig, 5e4);
|
|
4710
4901
|
const costDiff = newCostData.total.monthly - currentCostData.total.monthly;
|
|
4711
4902
|
console.log(`
|
|
4712
|
-
${
|
|
4903
|
+
${pc11.bold("Cost Impact:")}`);
|
|
4713
4904
|
console.log(
|
|
4714
|
-
` Current: ${
|
|
4905
|
+
` Current: ${pc11.cyan(`${formatCost(currentCostData.total.monthly)}/mo`)}`
|
|
4715
4906
|
);
|
|
4716
4907
|
console.log(
|
|
4717
|
-
` New: ${
|
|
4908
|
+
` New: ${pc11.cyan(`${formatCost(newCostData.total.monthly)}/mo`)}`
|
|
4718
4909
|
);
|
|
4719
4910
|
if (costDiff > 0) {
|
|
4720
|
-
console.log(` Change: ${
|
|
4911
|
+
console.log(` Change: ${pc11.yellow(`+${formatCost(costDiff)}/mo`)}`);
|
|
4721
4912
|
} else if (costDiff < 0) {
|
|
4722
4913
|
console.log(
|
|
4723
|
-
` Change: ${
|
|
4914
|
+
` Change: ${pc11.green(`${formatCost(Math.abs(costDiff))}/mo`)}`
|
|
4724
4915
|
);
|
|
4725
4916
|
}
|
|
4726
4917
|
console.log("");
|
|
4727
4918
|
if (!options.yes) {
|
|
4728
|
-
const confirmed = await
|
|
4919
|
+
const confirmed = await clack11.confirm({
|
|
4729
4920
|
message: "Proceed with upgrade?",
|
|
4730
4921
|
initialValue: true
|
|
4731
4922
|
});
|
|
4732
|
-
if (
|
|
4733
|
-
|
|
4923
|
+
if (clack11.isCancel(confirmed) || !confirmed) {
|
|
4924
|
+
clack11.cancel("Upgrade cancelled.");
|
|
4734
4925
|
process.exit(0);
|
|
4735
4926
|
}
|
|
4736
4927
|
}
|
|
@@ -4752,7 +4943,7 @@ ${pc10.bold("Cost Impact:")}`);
|
|
|
4752
4943
|
"Updating Wraps infrastructure (this may take 2-3 minutes)",
|
|
4753
4944
|
async () => {
|
|
4754
4945
|
await ensurePulumiWorkDir();
|
|
4755
|
-
const stack = await
|
|
4946
|
+
const stack = await pulumi12.automation.LocalWorkspace.createOrSelectStack(
|
|
4756
4947
|
{
|
|
4757
4948
|
stackName: metadata.pulumiStackName || `wraps-${identity.accountId}-${region}`,
|
|
4758
4949
|
projectName: "wraps-email",
|
|
@@ -4798,12 +4989,12 @@ ${pc10.bold("Cost Impact:")}`);
|
|
|
4798
4989
|
}
|
|
4799
4990
|
);
|
|
4800
4991
|
} catch (error) {
|
|
4801
|
-
|
|
4992
|
+
clack11.log.error("Infrastructure upgrade failed");
|
|
4802
4993
|
if (error.message?.includes("stack is currently locked")) {
|
|
4803
|
-
|
|
4804
|
-
|
|
4805
|
-
|
|
4806
|
-
|
|
4994
|
+
clack11.log.warn("\nThe Pulumi stack is locked from a previous run.");
|
|
4995
|
+
clack11.log.info("To fix this, run:");
|
|
4996
|
+
clack11.log.info(` ${pc11.cyan("rm -rf ~/.wraps/pulumi/.pulumi/locks")}`);
|
|
4997
|
+
clack11.log.info("\nThen try running wraps upgrade again.");
|
|
4807
4998
|
}
|
|
4808
4999
|
throw new Error(`Pulumi upgrade failed: ${error.message}`);
|
|
4809
5000
|
}
|
|
@@ -4828,16 +5019,16 @@ ${pc10.bold("Cost Impact:")}`);
|
|
|
4828
5019
|
customTrackingDomain: outputs.customTrackingDomain
|
|
4829
5020
|
});
|
|
4830
5021
|
console.log(`
|
|
4831
|
-
${
|
|
5022
|
+
${pc11.green("\u2713")} ${pc11.bold("Upgrade complete!")}
|
|
4832
5023
|
`);
|
|
4833
5024
|
if (upgradeAction === "preset" && newPreset) {
|
|
4834
5025
|
console.log(
|
|
4835
|
-
`Upgraded to ${
|
|
5026
|
+
`Upgraded to ${pc11.cyan(newPreset)} preset (${pc11.green(formatCost(newCostData.total.monthly) + "/mo")})
|
|
4836
5027
|
`
|
|
4837
5028
|
);
|
|
4838
5029
|
} else {
|
|
4839
5030
|
console.log(
|
|
4840
|
-
`Updated configuration (${
|
|
5031
|
+
`Updated configuration (${pc11.green(formatCost(newCostData.total.monthly) + "/mo")})
|
|
4841
5032
|
`
|
|
4842
5033
|
);
|
|
4843
5034
|
}
|
|
@@ -4848,10 +5039,10 @@ init_esm_shims();
|
|
|
4848
5039
|
init_aws();
|
|
4849
5040
|
import { Resolver } from "dns/promises";
|
|
4850
5041
|
import { GetEmailIdentityCommand as GetEmailIdentityCommand3, SESv2Client as SESv2Client3 } from "@aws-sdk/client-sesv2";
|
|
4851
|
-
import * as
|
|
4852
|
-
import
|
|
5042
|
+
import * as clack12 from "@clack/prompts";
|
|
5043
|
+
import pc12 from "picocolors";
|
|
4853
5044
|
async function verify(options) {
|
|
4854
|
-
|
|
5045
|
+
clack12.intro(pc12.bold(`Verifying ${options.domain}`));
|
|
4855
5046
|
const progress = new DeploymentProgress();
|
|
4856
5047
|
const region = await getAWSRegion();
|
|
4857
5048
|
const sesClient = new SESv2Client3({ region });
|
|
@@ -4870,10 +5061,10 @@ async function verify(options) {
|
|
|
4870
5061
|
dkimTokens = identity.DkimAttributes?.Tokens || [];
|
|
4871
5062
|
} catch (_error) {
|
|
4872
5063
|
progress.stop();
|
|
4873
|
-
|
|
5064
|
+
clack12.log.error(`Domain ${options.domain} not found in SES`);
|
|
4874
5065
|
console.log(
|
|
4875
5066
|
`
|
|
4876
|
-
Run ${
|
|
5067
|
+
Run ${pc12.cyan(`wraps init --domain ${options.domain}`)} to add this domain.
|
|
4877
5068
|
`
|
|
4878
5069
|
);
|
|
4879
5070
|
process.exit(1);
|
|
@@ -4936,11 +5127,11 @@ Run ${pc11.cyan(`wraps init --domain ${options.domain}`)} to add this domain.
|
|
|
4936
5127
|
progress.stop();
|
|
4937
5128
|
const verificationStatus = identity.VerifiedForSendingStatus ? "verified" : "pending";
|
|
4938
5129
|
const dkimStatus = identity.DkimAttributes?.Status || "PENDING";
|
|
4939
|
-
|
|
5130
|
+
clack12.note(
|
|
4940
5131
|
[
|
|
4941
|
-
`${
|
|
4942
|
-
`${
|
|
4943
|
-
`${
|
|
5132
|
+
`${pc12.bold("Domain:")} ${options.domain}`,
|
|
5133
|
+
`${pc12.bold("Verification Status:")} ${verificationStatus === "verified" ? pc12.green("\u2713 Verified") : pc12.yellow("\u23F1 Pending")}`,
|
|
5134
|
+
`${pc12.bold("DKIM Status:")} ${dkimStatus === "SUCCESS" ? pc12.green("\u2713 Success") : pc12.yellow(`\u23F1 ${dkimStatus}`)}`
|
|
4944
5135
|
].join("\n"),
|
|
4945
5136
|
"SES Status"
|
|
4946
5137
|
);
|
|
@@ -4949,38 +5140,38 @@ Run ${pc11.cyan(`wraps init --domain ${options.domain}`)} to add this domain.
|
|
|
4949
5140
|
let statusColor;
|
|
4950
5141
|
if (record.status === "verified") {
|
|
4951
5142
|
statusIcon = "\u2713";
|
|
4952
|
-
statusColor =
|
|
5143
|
+
statusColor = pc12.green;
|
|
4953
5144
|
} else if (record.status === "incorrect") {
|
|
4954
5145
|
statusIcon = "\u2717";
|
|
4955
|
-
statusColor =
|
|
5146
|
+
statusColor = pc12.red;
|
|
4956
5147
|
} else {
|
|
4957
5148
|
statusIcon = "\u2717";
|
|
4958
|
-
statusColor =
|
|
5149
|
+
statusColor = pc12.red;
|
|
4959
5150
|
}
|
|
4960
5151
|
const recordInfo = record.records ? ` \u2192 ${record.records.join(", ")}` : "";
|
|
4961
5152
|
return ` ${statusColor(statusIcon)} ${record.name} (${record.type}) ${statusColor(
|
|
4962
5153
|
record.status
|
|
4963
5154
|
)}${recordInfo}`;
|
|
4964
5155
|
});
|
|
4965
|
-
|
|
5156
|
+
clack12.note(dnsLines.join("\n"), "DNS Records");
|
|
4966
5157
|
const allVerified = dnsResults.every((r) => r.status === "verified");
|
|
4967
5158
|
const someIncorrect = dnsResults.some((r) => r.status === "incorrect");
|
|
4968
5159
|
if (verificationStatus === "verified" && allVerified) {
|
|
4969
|
-
|
|
4970
|
-
|
|
5160
|
+
clack12.outro(
|
|
5161
|
+
pc12.green("\u2713 Domain is fully verified and ready to send emails!")
|
|
4971
5162
|
);
|
|
4972
5163
|
} else if (someIncorrect) {
|
|
4973
|
-
|
|
4974
|
-
|
|
5164
|
+
clack12.outro(
|
|
5165
|
+
pc12.red("\u2717 Some DNS records are incorrect. Please update them.")
|
|
4975
5166
|
);
|
|
4976
5167
|
console.log(
|
|
4977
5168
|
`
|
|
4978
|
-
Run ${
|
|
5169
|
+
Run ${pc12.cyan("wraps status")} to see the correct DNS records.
|
|
4979
5170
|
`
|
|
4980
5171
|
);
|
|
4981
5172
|
} else {
|
|
4982
|
-
|
|
4983
|
-
|
|
5173
|
+
clack12.outro(
|
|
5174
|
+
pc12.yellow("\u23F1 Waiting for DNS propagation and SES verification")
|
|
4984
5175
|
);
|
|
4985
5176
|
console.log("\nDNS records can take up to 48 hours to propagate.");
|
|
4986
5177
|
console.log(
|
|
@@ -5015,44 +5206,61 @@ function printCompletionScript() {
|
|
|
5015
5206
|
|
|
5016
5207
|
// src/cli.ts
|
|
5017
5208
|
init_errors();
|
|
5209
|
+
var __filename2 = fileURLToPath4(import.meta.url);
|
|
5210
|
+
var __dirname3 = dirname2(__filename2);
|
|
5211
|
+
var packageJson = JSON.parse(
|
|
5212
|
+
readFileSync(join4(__dirname3, "../package.json"), "utf-8")
|
|
5213
|
+
);
|
|
5214
|
+
var VERSION = packageJson.version;
|
|
5018
5215
|
setupTabCompletion();
|
|
5216
|
+
function showVersion() {
|
|
5217
|
+
console.log(`wraps v${VERSION}`);
|
|
5218
|
+
process.exit(0);
|
|
5219
|
+
}
|
|
5019
5220
|
function showHelp() {
|
|
5020
|
-
|
|
5221
|
+
clack13.intro(pc13.bold(`WRAPS CLI v${VERSION}`));
|
|
5021
5222
|
console.log("Deploy email infrastructure to your AWS account\n");
|
|
5022
5223
|
console.log("Usage: wraps <command> [options]\n");
|
|
5023
5224
|
console.log("Commands:");
|
|
5024
|
-
console.log(` ${
|
|
5225
|
+
console.log(` ${pc13.cyan("init")} Deploy new email infrastructure`);
|
|
5226
|
+
console.log(
|
|
5227
|
+
` ${pc13.cyan("connect")} Connect to existing AWS SES infrastructure`
|
|
5228
|
+
);
|
|
5025
5229
|
console.log(
|
|
5026
|
-
` ${
|
|
5230
|
+
` ${pc13.cyan("console")} Start local web dashboard for monitoring`
|
|
5027
5231
|
);
|
|
5028
5232
|
console.log(
|
|
5029
|
-
` ${
|
|
5233
|
+
` ${pc13.cyan("update")} Update infrastructure with latest CLI changes`
|
|
5030
5234
|
);
|
|
5031
5235
|
console.log(
|
|
5032
|
-
` ${
|
|
5236
|
+
` ${pc13.cyan("upgrade")} Add features to existing connection`
|
|
5033
5237
|
);
|
|
5034
|
-
console.log(` ${
|
|
5238
|
+
console.log(` ${pc13.cyan("status")} Show current infrastructure status`);
|
|
5035
5239
|
console.log(
|
|
5036
|
-
` ${
|
|
5240
|
+
` ${pc13.cyan("verify")} Verify domain DNS records and SES status`
|
|
5037
5241
|
);
|
|
5038
|
-
console.log(` ${
|
|
5039
|
-
console.log(` ${
|
|
5040
|
-
console.log(` ${
|
|
5242
|
+
console.log(` ${pc13.cyan("restore")} Restore original AWS configuration`);
|
|
5243
|
+
console.log(` ${pc13.cyan("destroy")} Remove all deployed infrastructure`);
|
|
5244
|
+
console.log(` ${pc13.cyan("completion")} Generate shell completion script
|
|
5041
5245
|
`);
|
|
5042
5246
|
console.log("Options:");
|
|
5043
5247
|
console.log(
|
|
5044
|
-
` ${
|
|
5248
|
+
` ${pc13.dim("--provider")} Hosting provider (vercel, aws, railway, other)`
|
|
5045
5249
|
);
|
|
5046
|
-
console.log(` ${
|
|
5047
|
-
console.log(` ${
|
|
5048
|
-
console.log(` ${
|
|
5250
|
+
console.log(` ${pc13.dim("--region")} AWS region`);
|
|
5251
|
+
console.log(` ${pc13.dim("--domain")} Domain to verify`);
|
|
5252
|
+
console.log(` ${pc13.dim("--account")} AWS account ID or alias`);
|
|
5253
|
+
console.log(` ${pc13.dim("--version, -v")} Show version number
|
|
5049
5254
|
`);
|
|
5050
5255
|
console.log(
|
|
5051
|
-
`Run ${
|
|
5256
|
+
`Run ${pc13.cyan("wraps <command> --help")} for more information on a command.
|
|
5052
5257
|
`
|
|
5053
5258
|
);
|
|
5054
5259
|
process.exit(0);
|
|
5055
5260
|
}
|
|
5261
|
+
if (process.argv.includes("--version") || process.argv.includes("-v")) {
|
|
5262
|
+
showVersion();
|
|
5263
|
+
}
|
|
5056
5264
|
if (process.argv.includes("--help") || process.argv.includes("-h")) {
|
|
5057
5265
|
showHelp();
|
|
5058
5266
|
}
|
|
@@ -5122,10 +5330,10 @@ async function run() {
|
|
|
5122
5330
|
break;
|
|
5123
5331
|
case "verify":
|
|
5124
5332
|
if (!flags.domain) {
|
|
5125
|
-
|
|
5333
|
+
clack13.log.error("--domain flag is required");
|
|
5126
5334
|
console.log(
|
|
5127
5335
|
`
|
|
5128
|
-
Usage: ${
|
|
5336
|
+
Usage: ${pc13.cyan("wraps verify --domain yourapp.com")}
|
|
5129
5337
|
`
|
|
5130
5338
|
);
|
|
5131
5339
|
process.exit(1);
|
|
@@ -5147,6 +5355,12 @@ Usage: ${pc12.cyan("wraps verify --domain yourapp.com")}
|
|
|
5147
5355
|
noOpen: flags.noOpen
|
|
5148
5356
|
});
|
|
5149
5357
|
break;
|
|
5358
|
+
case "update":
|
|
5359
|
+
await update({
|
|
5360
|
+
region: flags.region,
|
|
5361
|
+
yes: flags.yes
|
|
5362
|
+
});
|
|
5363
|
+
break;
|
|
5150
5364
|
case "upgrade":
|
|
5151
5365
|
await upgrade({
|
|
5152
5366
|
region: flags.region,
|
|
@@ -5168,10 +5382,10 @@ Usage: ${pc12.cyan("wraps verify --domain yourapp.com")}
|
|
|
5168
5382
|
printCompletionScript();
|
|
5169
5383
|
break;
|
|
5170
5384
|
default:
|
|
5171
|
-
|
|
5385
|
+
clack13.log.error(`Unknown command: ${command}`);
|
|
5172
5386
|
console.log(
|
|
5173
5387
|
`
|
|
5174
|
-
Run ${
|
|
5388
|
+
Run ${pc13.cyan("wraps --help")} for available commands.
|
|
5175
5389
|
`
|
|
5176
5390
|
);
|
|
5177
5391
|
process.exit(1);
|