@wraps.dev/cli 2.19.0 → 2.19.2
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
|
@@ -820,6 +820,18 @@ To remove: wraps destroy --stack ${stackName}`,
|
|
|
820
820
|
"Use a valid AWS region like: us-east-1, eu-west-1, ap-southeast-1",
|
|
821
821
|
"https://docs.aws.amazon.com/general/latest/gr/rande.html"
|
|
822
822
|
),
|
|
823
|
+
// The accountId parameter is kept in the signature so callers don't
|
|
824
|
+
// have to change, but it is deliberately not included in the output —
|
|
825
|
+
// the user ran the command so they know their own account, and keeping
|
|
826
|
+
// IDs out of error text matches the `sanitizeErrorMessage` posture used
|
|
827
|
+
// elsewhere in the error system.
|
|
828
|
+
regionRequired: (_accountId, savedRegions) => new WrapsError(
|
|
829
|
+
"Region is required and could not be determined",
|
|
830
|
+
"REGION_REQUIRED",
|
|
831
|
+
savedRegions.length > 0 ? `Pass --region or set AWS_REGION.
|
|
832
|
+
Saved regions: ${savedRegions.join(", ")}` : "Pass --region or set AWS_REGION.\nNo saved Wraps deployments found.",
|
|
833
|
+
"https://wraps.dev/docs/cli-reference"
|
|
834
|
+
),
|
|
823
835
|
pulumiError: (message) => new WrapsError(
|
|
824
836
|
`Infrastructure deployment failed: ${message}`,
|
|
825
837
|
"PULUMI_ERROR",
|
|
@@ -842,7 +854,7 @@ To remove: wraps destroy --stack ${stackName}`,
|
|
|
842
854
|
"The Pulumi stack is locked from a previous run",
|
|
843
855
|
"STACK_LOCKED",
|
|
844
856
|
"This happens when a previous deployment was interrupted.\n\nFor local state, run:\n rm -rf ~/.wraps/pulumi/.pulumi/locks\n\nFor S3 state, delete the lock object in your wraps-state-* bucket under .pulumi/locks/\n\nThen try your command again.",
|
|
845
|
-
"https://wraps.dev/docs/guides/aws-setup/
|
|
857
|
+
"https://wraps.dev/docs/guides/aws-setup/troubleshooting"
|
|
846
858
|
),
|
|
847
859
|
// SMS-specific errors
|
|
848
860
|
smsNotConfigured: () => new WrapsError(
|
|
@@ -958,7 +970,7 @@ View required SES permissions:
|
|
|
958
970
|
`SES rejected the message: ${detail}`,
|
|
959
971
|
"SES_MESSAGE_REJECTED",
|
|
960
972
|
"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",
|
|
961
|
-
"https://wraps.dev/docs/guides/
|
|
973
|
+
"https://wraps.dev/docs/guides/aws-setup/troubleshooting"
|
|
962
974
|
),
|
|
963
975
|
sesMailFromNotVerified: (detail) => new WrapsError(
|
|
964
976
|
`SES MAIL FROM domain is not verified: ${detail}`,
|
|
@@ -1088,25 +1100,25 @@ You may need to merge your existing rules into the wraps rule set.`,
|
|
|
1088
1100
|
"wraps/wraps.config.ts not found",
|
|
1089
1101
|
"WRAPS_CONFIG_NOT_FOUND",
|
|
1090
1102
|
"Initialize templates first:\n wraps email templates init",
|
|
1091
|
-
"https://wraps.dev/docs/templates
|
|
1103
|
+
"https://wraps.dev/docs/guides/templates"
|
|
1092
1104
|
),
|
|
1093
1105
|
templateCompilationFailed: (name, error) => new WrapsError(
|
|
1094
1106
|
`Failed to compile template "${name}": ${error}`,
|
|
1095
1107
|
"TEMPLATE_COMPILATION_FAILED",
|
|
1096
1108
|
"Check your template for syntax errors and ensure all imports are valid.",
|
|
1097
|
-
"https://wraps.dev/docs/templates
|
|
1109
|
+
"https://wraps.dev/docs/guides/templates"
|
|
1098
1110
|
),
|
|
1099
1111
|
notAuthenticated: () => new WrapsError(
|
|
1100
1112
|
"Not authenticated to Wraps Platform",
|
|
1101
1113
|
"NOT_AUTHENTICATED",
|
|
1102
1114
|
"Sign in first:\n wraps auth login\n\nOr provide an API key:\n wraps push --token wraps_...\n WRAPS_API_KEY=wraps_... wraps push",
|
|
1103
|
-
"https://wraps.dev/docs/auth"
|
|
1115
|
+
"https://wraps.dev/docs/cli-reference/auth"
|
|
1104
1116
|
),
|
|
1105
1117
|
templatePushFailed: (name, error) => new WrapsError(
|
|
1106
1118
|
`Failed to push template "${name}": ${error}`,
|
|
1107
1119
|
"TEMPLATE_PUSH_FAILED",
|
|
1108
1120
|
"Check your API key and network connection.",
|
|
1109
|
-
"https://wraps.dev/docs/templates
|
|
1121
|
+
"https://wraps.dev/docs/guides/templates"
|
|
1110
1122
|
)
|
|
1111
1123
|
};
|
|
1112
1124
|
}
|
|
@@ -1195,8 +1207,8 @@ async function validateAWSCredentialsWithDetails() {
|
|
|
1195
1207
|
}
|
|
1196
1208
|
}
|
|
1197
1209
|
async function resolveAWSCredentialsToEnv() {
|
|
1198
|
-
delete process.env.AWS_PROFILE;
|
|
1199
1210
|
if (process.env.AWS_ACCESS_KEY_ID && process.env.AWS_SECRET_ACCESS_KEY) {
|
|
1211
|
+
delete process.env.AWS_PROFILE;
|
|
1200
1212
|
return;
|
|
1201
1213
|
}
|
|
1202
1214
|
const sts = new STSClient2({});
|
|
@@ -1223,6 +1235,7 @@ async function resolveAWSCredentialsToEnv() {
|
|
|
1223
1235
|
if (creds.sessionToken) {
|
|
1224
1236
|
process.env.AWS_SESSION_TOKEN = creds.sessionToken;
|
|
1225
1237
|
}
|
|
1238
|
+
delete process.env.AWS_PROFILE;
|
|
1226
1239
|
}
|
|
1227
1240
|
async function checkRegion(region) {
|
|
1228
1241
|
return SES_REGIONS.includes(region);
|
|
@@ -1702,8 +1715,8 @@ async function ensurePulumiWorkDir(options) {
|
|
|
1702
1715
|
);
|
|
1703
1716
|
return;
|
|
1704
1717
|
} catch (error) {
|
|
1705
|
-
const
|
|
1706
|
-
|
|
1718
|
+
const clack56 = await import("@clack/prompts");
|
|
1719
|
+
clack56.log.warn(
|
|
1707
1720
|
`S3 state backend unavailable (${error instanceof Error ? error.message : error}). Using local state.`
|
|
1708
1721
|
);
|
|
1709
1722
|
}
|
|
@@ -4423,6 +4436,7 @@ __export(prompts_exports, {
|
|
|
4423
4436
|
confirmConnect: () => confirmConnect,
|
|
4424
4437
|
confirmDeploy: () => confirmDeploy,
|
|
4425
4438
|
getAvailableFeatures: () => getAvailableFeatures,
|
|
4439
|
+
isInteractive: () => isInteractive,
|
|
4426
4440
|
promptConfigPreset: () => promptConfigPreset,
|
|
4427
4441
|
promptConflictResolution: () => promptConflictResolution,
|
|
4428
4442
|
promptContinueManualDNS: () => promptContinueManualDNS,
|
|
@@ -4448,6 +4462,9 @@ __export(prompts_exports, {
|
|
|
4448
4462
|
});
|
|
4449
4463
|
import * as clack6 from "@clack/prompts";
|
|
4450
4464
|
import pc8 from "picocolors";
|
|
4465
|
+
function isInteractive() {
|
|
4466
|
+
return process.stdin.isTTY === true && process.stdout.isTTY === true && !process.env.CI;
|
|
4467
|
+
}
|
|
4451
4468
|
async function promptProvider() {
|
|
4452
4469
|
const provider = await clack6.select({
|
|
4453
4470
|
message: "Where is your app hosted?",
|
|
@@ -6783,23 +6800,23 @@ async function withLockRetry(fn, options) {
|
|
|
6783
6800
|
if (parsed.code !== "STACK_LOCKED") {
|
|
6784
6801
|
throw error;
|
|
6785
6802
|
}
|
|
6786
|
-
const
|
|
6803
|
+
const clack56 = await import("@clack/prompts");
|
|
6787
6804
|
const pc60 = (await import("picocolors")).default;
|
|
6788
6805
|
if (options.autoConfirm) {
|
|
6789
|
-
|
|
6806
|
+
clack56.log.warn(
|
|
6790
6807
|
"Stack is locked from a previous interrupted run. Auto-clearing..."
|
|
6791
6808
|
);
|
|
6792
6809
|
} else {
|
|
6793
|
-
const shouldClear = await
|
|
6810
|
+
const shouldClear = await clack56.confirm({
|
|
6794
6811
|
message: `Stack is locked from a previous interrupted run. ${pc60.yellow("Clear the stale lock and retry?")}`,
|
|
6795
6812
|
initialValue: true
|
|
6796
6813
|
});
|
|
6797
|
-
if (
|
|
6814
|
+
if (clack56.isCancel(shouldClear) || !shouldClear) {
|
|
6798
6815
|
throw errors.stackLocked();
|
|
6799
6816
|
}
|
|
6800
6817
|
}
|
|
6801
6818
|
const cleared = await clearStackLocks(options.accountId, options.region);
|
|
6802
|
-
|
|
6819
|
+
clack56.log.info(
|
|
6803
6820
|
`Cleared ${cleared} lock file${cleared === 1 ? "" : "s"}. Retrying...`
|
|
6804
6821
|
);
|
|
6805
6822
|
return fn();
|
|
@@ -6815,26 +6832,11 @@ var init_pulumi = __esm({
|
|
|
6815
6832
|
}
|
|
6816
6833
|
});
|
|
6817
6834
|
|
|
6818
|
-
// src/constants.ts
|
|
6819
|
-
function getDefaultRegion() {
|
|
6820
|
-
return process.env.AWS_REGION || DEFAULT_AWS_REGION;
|
|
6821
|
-
}
|
|
6822
|
-
var DEFAULT_AWS_REGION;
|
|
6823
|
-
var init_constants = __esm({
|
|
6824
|
-
"src/constants.ts"() {
|
|
6825
|
-
"use strict";
|
|
6826
|
-
init_esm_shims();
|
|
6827
|
-
DEFAULT_AWS_REGION = "us-east-1";
|
|
6828
|
-
}
|
|
6829
|
-
});
|
|
6830
|
-
|
|
6831
6835
|
// src/infrastructure/shared/resource-checks.ts
|
|
6832
6836
|
async function roleExists(roleName) {
|
|
6833
6837
|
try {
|
|
6834
6838
|
const { IAMClient: IAMClient5, GetRoleCommand: GetRoleCommand3 } = await import("@aws-sdk/client-iam");
|
|
6835
|
-
const iam10 = new IAMClient5({
|
|
6836
|
-
region: getDefaultRegion()
|
|
6837
|
-
});
|
|
6839
|
+
const iam10 = new IAMClient5({ region: "us-east-1" });
|
|
6838
6840
|
await iam10.send(new GetRoleCommand3({ RoleName: roleName }));
|
|
6839
6841
|
return true;
|
|
6840
6842
|
} catch (error) {
|
|
@@ -6845,12 +6847,10 @@ async function roleExists(roleName) {
|
|
|
6845
6847
|
return false;
|
|
6846
6848
|
}
|
|
6847
6849
|
}
|
|
6848
|
-
async function tableExists(tableName) {
|
|
6850
|
+
async function tableExists(tableName, region) {
|
|
6849
6851
|
try {
|
|
6850
6852
|
const { DynamoDBClient: DynamoDBClient7, DescribeTableCommand: DescribeTableCommand2 } = await import("@aws-sdk/client-dynamodb");
|
|
6851
|
-
const dynamodb3 = new DynamoDBClient7({
|
|
6852
|
-
region: getDefaultRegion()
|
|
6853
|
-
});
|
|
6853
|
+
const dynamodb3 = new DynamoDBClient7({ region });
|
|
6854
6854
|
await dynamodb3.send(new DescribeTableCommand2({ TableName: tableName }));
|
|
6855
6855
|
return true;
|
|
6856
6856
|
} catch (error) {
|
|
@@ -6861,12 +6861,10 @@ async function tableExists(tableName) {
|
|
|
6861
6861
|
return false;
|
|
6862
6862
|
}
|
|
6863
6863
|
}
|
|
6864
|
-
async function sqsQueueExists(queueName) {
|
|
6864
|
+
async function sqsQueueExists(queueName, region) {
|
|
6865
6865
|
try {
|
|
6866
6866
|
const { SQSClient, GetQueueUrlCommand } = await import("@aws-sdk/client-sqs");
|
|
6867
|
-
const sqs5 = new SQSClient({
|
|
6868
|
-
region: getDefaultRegion()
|
|
6869
|
-
});
|
|
6867
|
+
const sqs5 = new SQSClient({ region });
|
|
6870
6868
|
const response = await sqs5.send(
|
|
6871
6869
|
new GetQueueUrlCommand({ QueueName: queueName })
|
|
6872
6870
|
);
|
|
@@ -6875,12 +6873,10 @@ async function sqsQueueExists(queueName) {
|
|
|
6875
6873
|
return null;
|
|
6876
6874
|
}
|
|
6877
6875
|
}
|
|
6878
|
-
async function snsTopicExists(topicName) {
|
|
6876
|
+
async function snsTopicExists(topicName, region) {
|
|
6879
6877
|
try {
|
|
6880
6878
|
const { SNSClient: SNSClient3, ListTopicsCommand: ListTopicsCommand2 } = await import("@aws-sdk/client-sns");
|
|
6881
|
-
const sns3 = new SNSClient3({
|
|
6882
|
-
region: getDefaultRegion()
|
|
6883
|
-
});
|
|
6879
|
+
const sns3 = new SNSClient3({ region });
|
|
6884
6880
|
let nextToken;
|
|
6885
6881
|
do {
|
|
6886
6882
|
const response = await sns3.send(
|
|
@@ -6899,12 +6895,10 @@ async function snsTopicExists(topicName) {
|
|
|
6899
6895
|
return null;
|
|
6900
6896
|
}
|
|
6901
6897
|
}
|
|
6902
|
-
async function lambdaFunctionExists(functionName) {
|
|
6898
|
+
async function lambdaFunctionExists(functionName, region) {
|
|
6903
6899
|
try {
|
|
6904
6900
|
const { LambdaClient: LambdaClient3, GetFunctionCommand } = await import("@aws-sdk/client-lambda");
|
|
6905
|
-
const lambda4 = new LambdaClient3({
|
|
6906
|
-
region: getDefaultRegion()
|
|
6907
|
-
});
|
|
6901
|
+
const lambda4 = new LambdaClient3({ region });
|
|
6908
6902
|
await lambda4.send(new GetFunctionCommand({ FunctionName: functionName }));
|
|
6909
6903
|
return true;
|
|
6910
6904
|
} catch (error) {
|
|
@@ -6919,7 +6913,6 @@ var init_resource_checks = __esm({
|
|
|
6919
6913
|
"src/infrastructure/shared/resource-checks.ts"() {
|
|
6920
6914
|
"use strict";
|
|
6921
6915
|
init_esm_shims();
|
|
6922
|
-
init_constants();
|
|
6923
6916
|
}
|
|
6924
6917
|
});
|
|
6925
6918
|
|
|
@@ -7350,12 +7343,10 @@ function getPackageRoot() {
|
|
|
7350
7343
|
}
|
|
7351
7344
|
throw new Error("Could not find package.json");
|
|
7352
7345
|
}
|
|
7353
|
-
async function findEventSourceMapping(functionName, queueArn) {
|
|
7346
|
+
async function findEventSourceMapping(functionName, queueArn, region) {
|
|
7354
7347
|
try {
|
|
7355
7348
|
const { LambdaClient: LambdaClient3, ListEventSourceMappingsCommand } = await import("@aws-sdk/client-lambda");
|
|
7356
|
-
const lambda4 = new LambdaClient3({
|
|
7357
|
-
region: getDefaultRegion()
|
|
7358
|
-
});
|
|
7349
|
+
const lambda4 = new LambdaClient3({ region });
|
|
7359
7350
|
const response = await lambda4.send(
|
|
7360
7351
|
new ListEventSourceMappingsCommand({
|
|
7361
7352
|
FunctionName: functionName,
|
|
@@ -7464,7 +7455,7 @@ async function deployLambdaFunctions(config2) {
|
|
|
7464
7455
|
)
|
|
7465
7456
|
});
|
|
7466
7457
|
const functionName = "wraps-email-event-processor";
|
|
7467
|
-
const exists = await lambdaFunctionExists(functionName);
|
|
7458
|
+
const exists = await lambdaFunctionExists(functionName, config2.region);
|
|
7468
7459
|
const lambdaEnvironment = {
|
|
7469
7460
|
variables: {
|
|
7470
7461
|
TABLE_NAME: config2.tableName,
|
|
@@ -7512,7 +7503,8 @@ async function deployLambdaFunctions(config2) {
|
|
|
7512
7503
|
const queueArnValue = `arn:aws:sqs:${config2.region}:${config2.accountId}:wraps-email-events`;
|
|
7513
7504
|
const existingMappingUuid = await findEventSourceMapping(
|
|
7514
7505
|
functionName,
|
|
7515
|
-
queueArnValue
|
|
7506
|
+
queueArnValue,
|
|
7507
|
+
config2.region
|
|
7516
7508
|
);
|
|
7517
7509
|
const mappingConfig = {
|
|
7518
7510
|
eventSourceArn: config2.queueArn,
|
|
@@ -7545,7 +7537,6 @@ var init_lambda = __esm({
|
|
|
7545
7537
|
"src/infrastructure/resources/lambda.ts"() {
|
|
7546
7538
|
"use strict";
|
|
7547
7539
|
init_esm_shims();
|
|
7548
|
-
init_constants();
|
|
7549
7540
|
init_resource_checks();
|
|
7550
7541
|
nodeBuiltins = builtinModules.flatMap((m) => [m, `node:${m}`]);
|
|
7551
7542
|
}
|
|
@@ -7893,7 +7884,7 @@ function retentionToAWSPeriod2(retention) {
|
|
|
7893
7884
|
}
|
|
7894
7885
|
}
|
|
7895
7886
|
async function createMailManagerArchive(config2) {
|
|
7896
|
-
const region = config2.region
|
|
7887
|
+
const region = config2.region;
|
|
7897
7888
|
const archiveName = `wraps-${config2.name}-archive`;
|
|
7898
7889
|
const mailManagerClient = new MailManagerClient({ region });
|
|
7899
7890
|
const sesClient = new SESv2Client3({ region });
|
|
@@ -7995,7 +7986,6 @@ var init_mail_manager = __esm({
|
|
|
7995
7986
|
"src/infrastructure/resources/mail-manager.ts"() {
|
|
7996
7987
|
"use strict";
|
|
7997
7988
|
init_esm_shims();
|
|
7998
|
-
init_constants();
|
|
7999
7989
|
}
|
|
8000
7990
|
});
|
|
8001
7991
|
|
|
@@ -9675,6 +9665,60 @@ var init_test = __esm({
|
|
|
9675
9665
|
}
|
|
9676
9666
|
});
|
|
9677
9667
|
|
|
9668
|
+
// src/utils/shared/region-resolver.ts
|
|
9669
|
+
var region_resolver_exports = {};
|
|
9670
|
+
__export(region_resolver_exports, {
|
|
9671
|
+
resolveRegionForCommand: () => resolveRegionForCommand
|
|
9672
|
+
});
|
|
9673
|
+
import * as clack28 from "@clack/prompts";
|
|
9674
|
+
async function resolveRegionForCommand(opts) {
|
|
9675
|
+
const { accountId, optionRegion, service, label = "deployment" } = opts;
|
|
9676
|
+
if (optionRegion) {
|
|
9677
|
+
return optionRegion;
|
|
9678
|
+
}
|
|
9679
|
+
const envRegion = process.env.AWS_REGION || process.env.AWS_DEFAULT_REGION;
|
|
9680
|
+
if (envRegion) {
|
|
9681
|
+
return envRegion;
|
|
9682
|
+
}
|
|
9683
|
+
const connections = (service ? await findConnectionsWithService(accountId, service) : await findConnectionsForAccount(accountId)) ?? [];
|
|
9684
|
+
if (connections.length === 1) {
|
|
9685
|
+
return connections[0].region;
|
|
9686
|
+
}
|
|
9687
|
+
const savedRegions = connections.map((c) => c.region);
|
|
9688
|
+
if (connections.length === 0) {
|
|
9689
|
+
return getAWSRegion();
|
|
9690
|
+
}
|
|
9691
|
+
if (!isInteractive() || isJsonMode()) {
|
|
9692
|
+
throw errors.regionRequired(accountId, savedRegions);
|
|
9693
|
+
}
|
|
9694
|
+
const selected = await clack28.select({
|
|
9695
|
+
message: `Multiple ${label}s found. Which region?`,
|
|
9696
|
+
options: connections.map((conn) => ({
|
|
9697
|
+
value: conn.region,
|
|
9698
|
+
label: conn.region
|
|
9699
|
+
}))
|
|
9700
|
+
});
|
|
9701
|
+
if (clack28.isCancel(selected)) {
|
|
9702
|
+
throw new WrapsError(
|
|
9703
|
+
"Operation cancelled",
|
|
9704
|
+
"OPERATION_CANCELLED",
|
|
9705
|
+
`Pass --region to skip the prompt. Saved regions: ${savedRegions.join(", ")}`
|
|
9706
|
+
);
|
|
9707
|
+
}
|
|
9708
|
+
return selected;
|
|
9709
|
+
}
|
|
9710
|
+
var init_region_resolver = __esm({
|
|
9711
|
+
"src/utils/shared/region-resolver.ts"() {
|
|
9712
|
+
"use strict";
|
|
9713
|
+
init_esm_shims();
|
|
9714
|
+
init_aws();
|
|
9715
|
+
init_errors();
|
|
9716
|
+
init_json_output();
|
|
9717
|
+
init_metadata();
|
|
9718
|
+
init_prompts();
|
|
9719
|
+
}
|
|
9720
|
+
});
|
|
9721
|
+
|
|
9678
9722
|
// src/utils/dns/caa.ts
|
|
9679
9723
|
var caa_exports = {};
|
|
9680
9724
|
__export(caa_exports, {
|
|
@@ -10080,7 +10124,7 @@ import { homedir as homedir4, tmpdir as tmpdir2 } from "os";
|
|
|
10080
10124
|
import { join as join21 } from "path";
|
|
10081
10125
|
import { Readable } from "stream";
|
|
10082
10126
|
import { pipeline } from "stream/promises";
|
|
10083
|
-
import { cancel as cancel31, confirm as confirm26, intro as intro51, isCancel as
|
|
10127
|
+
import { cancel as cancel31, confirm as confirm26, intro as intro51, isCancel as isCancel36, log as log50 } from "@clack/prompts";
|
|
10084
10128
|
import pc58 from "picocolors";
|
|
10085
10129
|
function isStandaloneInstall() {
|
|
10086
10130
|
return process.execPath.includes(".wraps/runtime");
|
|
@@ -10142,7 +10186,7 @@ async function update(currentVersion) {
|
|
|
10142
10186
|
const shouldUpdate = await confirm26({
|
|
10143
10187
|
message: `Update to v${latestVersion}?`
|
|
10144
10188
|
});
|
|
10145
|
-
if (
|
|
10189
|
+
if (isCancel36(shouldUpdate) || !shouldUpdate) {
|
|
10146
10190
|
cancel31("Update cancelled.");
|
|
10147
10191
|
return;
|
|
10148
10192
|
}
|
|
@@ -10233,7 +10277,7 @@ init_esm_shims();
|
|
|
10233
10277
|
import { readFileSync as readFileSync3 } from "fs";
|
|
10234
10278
|
import { dirname as dirname5, join as join22 } from "path";
|
|
10235
10279
|
import { fileURLToPath as fileURLToPath6 } from "url";
|
|
10236
|
-
import * as
|
|
10280
|
+
import * as clack55 from "@clack/prompts";
|
|
10237
10281
|
import pc59 from "picocolors";
|
|
10238
10282
|
|
|
10239
10283
|
// src/commands/auth/login.ts
|
|
@@ -10648,26 +10692,30 @@ async function runDiagnostics(state) {
|
|
|
10648
10692
|
}
|
|
10649
10693
|
}
|
|
10650
10694
|
if (state.credentialsConfigured) {
|
|
10695
|
+
const regionUsed = state.region || "us-east-1";
|
|
10696
|
+
const regionNote = state.region ? `Region: ${regionUsed}` : `No AWS_REGION set \u2014 defaulted to ${regionUsed}. Set AWS_REGION if your deployment lives elsewhere.`;
|
|
10651
10697
|
try {
|
|
10652
|
-
const
|
|
10653
|
-
const sandbox = await isSESSandbox(region);
|
|
10698
|
+
const sandbox = await isSESSandbox(regionUsed);
|
|
10654
10699
|
if (sandbox) {
|
|
10655
10700
|
results.push({
|
|
10656
10701
|
status: "warn",
|
|
10657
10702
|
message: "SES is in sandbox mode",
|
|
10658
|
-
details:
|
|
10703
|
+
details: `You can only send to verified emails. Request production access in AWS console.
|
|
10704
|
+
${regionNote}`
|
|
10659
10705
|
});
|
|
10660
10706
|
} else {
|
|
10661
10707
|
results.push({
|
|
10662
10708
|
status: "pass",
|
|
10663
|
-
message: "SES has production access"
|
|
10709
|
+
message: "SES has production access",
|
|
10710
|
+
details: regionNote
|
|
10664
10711
|
});
|
|
10665
10712
|
}
|
|
10666
10713
|
} catch {
|
|
10667
10714
|
results.push({
|
|
10668
10715
|
status: "info",
|
|
10669
10716
|
message: "Could not check SES status",
|
|
10670
|
-
details:
|
|
10717
|
+
details: `SES may not be enabled in this region.
|
|
10718
|
+
${regionNote}`
|
|
10671
10719
|
});
|
|
10672
10720
|
}
|
|
10673
10721
|
}
|
|
@@ -11812,6 +11860,7 @@ async function createCdnBucket(config2) {
|
|
|
11812
11860
|
const corsOrigins = [
|
|
11813
11861
|
"https://wraps.dev",
|
|
11814
11862
|
"https://*.wraps.dev",
|
|
11863
|
+
"https://*.wraps.localhost",
|
|
11815
11864
|
"http://localhost:3000",
|
|
11816
11865
|
"http://localhost:3001",
|
|
11817
11866
|
"http://localhost:3002",
|
|
@@ -12201,8 +12250,16 @@ async function createServiceIAMRole(config2) {
|
|
|
12201
12250
|
|
|
12202
12251
|
// src/infrastructure/vercel-oidc.ts
|
|
12203
12252
|
init_esm_shims();
|
|
12204
|
-
init_constants();
|
|
12205
12253
|
import * as aws3 from "@pulumi/aws";
|
|
12254
|
+
|
|
12255
|
+
// src/constants.ts
|
|
12256
|
+
init_esm_shims();
|
|
12257
|
+
var DEFAULT_AWS_REGION = "us-east-1";
|
|
12258
|
+
function getDefaultRegion() {
|
|
12259
|
+
return process.env.AWS_REGION || DEFAULT_AWS_REGION;
|
|
12260
|
+
}
|
|
12261
|
+
|
|
12262
|
+
// src/infrastructure/vercel-oidc.ts
|
|
12206
12263
|
async function getExistingOIDCProviderArn(url) {
|
|
12207
12264
|
try {
|
|
12208
12265
|
const { IAMClient: IAMClient5, ListOpenIDConnectProvidersCommand } = await import("@aws-sdk/client-iam");
|
|
@@ -17508,9 +17565,9 @@ async function createAlertingResources(config2) {
|
|
|
17508
17565
|
init_esm_shims();
|
|
17509
17566
|
init_resource_checks();
|
|
17510
17567
|
import * as aws5 from "@pulumi/aws";
|
|
17511
|
-
async function createDynamoDBTables(
|
|
17568
|
+
async function createDynamoDBTables(config2) {
|
|
17512
17569
|
const tableName = "wraps-email-history";
|
|
17513
|
-
const exists = await tableExists(tableName);
|
|
17570
|
+
const exists = await tableExists(tableName, config2.region);
|
|
17514
17571
|
const emailHistory = exists ? new aws5.dynamodb.Table(
|
|
17515
17572
|
tableName,
|
|
17516
17573
|
{
|
|
@@ -18048,7 +18105,6 @@ async function createSESResources(config2) {
|
|
|
18048
18105
|
|
|
18049
18106
|
// src/infrastructure/resources/smtp-credentials.ts
|
|
18050
18107
|
init_esm_shims();
|
|
18051
|
-
init_constants();
|
|
18052
18108
|
import { createHmac as createHmac3 } from "crypto";
|
|
18053
18109
|
import * as aws10 from "@pulumi/aws";
|
|
18054
18110
|
function convertToSMTPPassword2(secretAccessKey, region) {
|
|
@@ -18138,11 +18194,11 @@ import * as aws11 from "@pulumi/aws";
|
|
|
18138
18194
|
var SQS_TIMEOUTS = {
|
|
18139
18195
|
customTimeouts: { create: "2m", update: "2m", delete: "2m" }
|
|
18140
18196
|
};
|
|
18141
|
-
async function createSQSResources() {
|
|
18197
|
+
async function createSQSResources(config2) {
|
|
18142
18198
|
const dlqName = "wraps-email-events-dlq";
|
|
18143
18199
|
const queueName = "wraps-email-events";
|
|
18144
|
-
const dlqUrl = await sqsQueueExists(dlqName);
|
|
18145
|
-
const queueUrl = await sqsQueueExists(queueName);
|
|
18200
|
+
const dlqUrl = await sqsQueueExists(dlqName, config2.region);
|
|
18201
|
+
const queueUrl = await sqsQueueExists(queueName, config2.region);
|
|
18146
18202
|
const dlqConfig = {
|
|
18147
18203
|
name: dlqName,
|
|
18148
18204
|
messageRetentionSeconds: 1209600,
|
|
@@ -18281,12 +18337,13 @@ async function deployEmailStack(config2) {
|
|
|
18281
18337
|
let dynamoTables;
|
|
18282
18338
|
if (emailConfig.eventTracking?.dynamoDBHistory) {
|
|
18283
18339
|
dynamoTables = await createDynamoDBTables({
|
|
18340
|
+
region: config2.region,
|
|
18284
18341
|
retention: emailConfig.eventTracking.archiveRetention
|
|
18285
18342
|
});
|
|
18286
18343
|
}
|
|
18287
18344
|
let sqsResources;
|
|
18288
18345
|
if (emailConfig.eventTracking?.enabled) {
|
|
18289
|
-
sqsResources = await createSQSResources();
|
|
18346
|
+
sqsResources = await createSQSResources({ region: config2.region });
|
|
18290
18347
|
}
|
|
18291
18348
|
if (emailConfig.eventTracking?.enabled && sesResources && sqsResources) {
|
|
18292
18349
|
await createEventBridgeResources({
|
|
@@ -21245,6 +21302,8 @@ async function inboundInit(options) {
|
|
|
21245
21302
|
subdomain,
|
|
21246
21303
|
bucketName: `wraps-inbound-${identity.accountId}-${region}`,
|
|
21247
21304
|
webhookUrl: webhookUrl || null,
|
|
21305
|
+
webhookSecret: webhookUrl ? webhookSecret : null,
|
|
21306
|
+
webhookHeader: webhookUrl ? "X-Wraps-Inbound-Key" : null,
|
|
21248
21307
|
dnsAutoCreated,
|
|
21249
21308
|
region
|
|
21250
21309
|
});
|
|
@@ -21263,6 +21322,27 @@ async function inboundInit(options) {
|
|
|
21263
21322
|
if (dnsAutoCreated) {
|
|
21264
21323
|
console.log(` ${pc24.dim("DNS:")} ${pc24.green("Auto-created")}`);
|
|
21265
21324
|
}
|
|
21325
|
+
if (webhookUrl) {
|
|
21326
|
+
const setupLines = [
|
|
21327
|
+
`EventBridge will POST every ${pc24.cyan("email.received")} event to:`,
|
|
21328
|
+
` ${pc24.cyan(webhookUrl)}`,
|
|
21329
|
+
"",
|
|
21330
|
+
"Verify the request by checking this header on every POST:",
|
|
21331
|
+
` ${pc24.bold("X-Wraps-Inbound-Key")}: ${pc24.yellow(webhookSecret)}`,
|
|
21332
|
+
"",
|
|
21333
|
+
pc24.bold("Save this secret now \u2014 it is only shown once."),
|
|
21334
|
+
`Retrieve it later with: ${pc24.cyan("wraps email inbound status --reveal-secret")}`,
|
|
21335
|
+
"",
|
|
21336
|
+
"Body shape (JSON):",
|
|
21337
|
+
pc24.dim(
|
|
21338
|
+
' { "emailId", "from", "to", "subject", "html", "text", "attachments", "headers", ... }'
|
|
21339
|
+
),
|
|
21340
|
+
"",
|
|
21341
|
+
`Docs: ${pc24.cyan("https://wraps.dev/docs/quickstart/email/inbound")}`
|
|
21342
|
+
].join("\n");
|
|
21343
|
+
console.log();
|
|
21344
|
+
clack22.note(setupLines, "Webhook setup");
|
|
21345
|
+
}
|
|
21266
21346
|
console.log();
|
|
21267
21347
|
console.log(pc24.bold("Next steps:"));
|
|
21268
21348
|
if (dnsAutoCreated) {
|
|
@@ -21413,6 +21493,8 @@ Enable it: ${pc24.cyan("wraps email inbound init")}
|
|
|
21413
21493
|
bucketName: inbound.bucketName || "",
|
|
21414
21494
|
region,
|
|
21415
21495
|
webhookUrl: inbound.webhookUrl || null,
|
|
21496
|
+
webhookHeader: inbound.webhookUrl ? "X-Wraps-Inbound-Key" : null,
|
|
21497
|
+
webhookSecret: options.revealSecret && inbound.webhookUrl ? inbound.webhookSecret || null : null,
|
|
21416
21498
|
receiptRuleSetActive: activeRuleSet === RULE_SET_NAME,
|
|
21417
21499
|
retention: inbound.retention || null
|
|
21418
21500
|
});
|
|
@@ -21436,6 +21518,20 @@ Enable it: ${pc24.cyan("wraps email inbound init")}
|
|
|
21436
21518
|
console.log(
|
|
21437
21519
|
` ${pc24.dim("Webhook URL:")} ${inbound.webhookUrl ? pc24.cyan(inbound.webhookUrl) : pc24.dim("not configured")}`
|
|
21438
21520
|
);
|
|
21521
|
+
if (inbound.webhookUrl) {
|
|
21522
|
+
console.log(
|
|
21523
|
+
` ${pc24.dim("Webhook header:")} ${pc24.cyan("X-Wraps-Inbound-Key")}`
|
|
21524
|
+
);
|
|
21525
|
+
if (options.revealSecret) {
|
|
21526
|
+
console.log(
|
|
21527
|
+
` ${pc24.dim("Webhook secret:")} ${inbound.webhookSecret ? pc24.yellow(inbound.webhookSecret) : pc24.dim("not set")}`
|
|
21528
|
+
);
|
|
21529
|
+
} else {
|
|
21530
|
+
console.log(
|
|
21531
|
+
` ${pc24.dim("Webhook secret:")} ${pc24.dim("hidden \u2014 pass --reveal-secret to show")}`
|
|
21532
|
+
);
|
|
21533
|
+
}
|
|
21534
|
+
}
|
|
21439
21535
|
console.log(
|
|
21440
21536
|
` ${pc24.dim("Receipt rule set:")} ${activeRuleSet === RULE_SET_NAME ? pc24.green("active") : pc24.yellow("inactive")}`
|
|
21441
21537
|
);
|
|
@@ -21571,7 +21667,7 @@ function mapInboundTestSendError(error, ctx) {
|
|
|
21571
21667
|
`Failed to send inbound test email to ${ctx.recipient}`,
|
|
21572
21668
|
"INBOUND_TEST_SEND_FAILED",
|
|
21573
21669
|
"An unexpected error occurred while sending the test email.\n\nCheck infrastructure status:\n wraps email status\n wraps email doctor",
|
|
21574
|
-
"https://wraps.dev/docs/guides/
|
|
21670
|
+
"https://wraps.dev/docs/guides/aws-setup/troubleshooting"
|
|
21575
21671
|
);
|
|
21576
21672
|
}
|
|
21577
21673
|
const name = error.name;
|
|
@@ -21608,7 +21704,7 @@ Or remove the custom MAIL FROM domain in the SES console and retry.`,
|
|
|
21608
21704
|
"Exit the SES sandbox to send to any address:",
|
|
21609
21705
|
" https://docs.aws.amazon.com/ses/latest/dg/request-production-access.html"
|
|
21610
21706
|
].join("\n"),
|
|
21611
|
-
"https://wraps.dev/docs/guides/
|
|
21707
|
+
"https://wraps.dev/docs/guides/aws-setup/troubleshooting"
|
|
21612
21708
|
);
|
|
21613
21709
|
}
|
|
21614
21710
|
if (name === "AccountSendingPausedException" || name === "ConfigurationSetSendingPausedException") {
|
|
@@ -23049,7 +23145,7 @@ async function replyInitForSingleDomain(params) {
|
|
|
23049
23145
|
`The Pulumi deploy completed but the SSM parameter ${ssmParameterName(domain)} was not found. Run:
|
|
23050
23146
|
wraps email reply status
|
|
23051
23147
|
to diagnose, or retry the init.`,
|
|
23052
|
-
"https://wraps.dev/docs/guides/
|
|
23148
|
+
"https://wraps.dev/docs/guides/reply-threading"
|
|
23053
23149
|
);
|
|
23054
23150
|
}
|
|
23055
23151
|
const finalEntry = {
|
|
@@ -23162,7 +23258,7 @@ async function replyInit(options) {
|
|
|
23162
23258
|
"Reply threading requires inbound email infrastructure",
|
|
23163
23259
|
"REPLY_REQUIRES_INBOUND",
|
|
23164
23260
|
"Deploy inbound first:\n wraps email inbound init\n\nThen enable reply threading:\n wraps email reply init --domain yourapp.com",
|
|
23165
|
-
"https://wraps.dev/docs/guides/
|
|
23261
|
+
"https://wraps.dev/docs/guides/reply-threading"
|
|
23166
23262
|
);
|
|
23167
23263
|
}
|
|
23168
23264
|
const emailService = metadata.services.email;
|
|
@@ -23178,7 +23274,7 @@ async function replyInit(options) {
|
|
|
23178
23274
|
"No inbound domains configured",
|
|
23179
23275
|
"REPLY_NO_INBOUND_DOMAINS",
|
|
23180
23276
|
"Add an inbound domain first:\n wraps email inbound add --domain yourapp.com",
|
|
23181
|
-
"https://wraps.dev/docs/guides/
|
|
23277
|
+
"https://wraps.dev/docs/guides/reply-threading"
|
|
23182
23278
|
);
|
|
23183
23279
|
}
|
|
23184
23280
|
let targetDomains;
|
|
@@ -23207,7 +23303,7 @@ async function replyInit(options) {
|
|
|
23207
23303
|
"REPLY_INBOUND_DOMAIN_NOT_FOUND",
|
|
23208
23304
|
`Add it to inbound first:
|
|
23209
23305
|
wraps email inbound add ${target}`,
|
|
23210
|
-
"https://wraps.dev/docs/guides/
|
|
23306
|
+
"https://wraps.dev/docs/guides/reply-threading"
|
|
23211
23307
|
);
|
|
23212
23308
|
}
|
|
23213
23309
|
if (isReplyEnabledFor(metadata, target)) {
|
|
@@ -23216,7 +23312,7 @@ async function replyInit(options) {
|
|
|
23216
23312
|
"REPLY_ALREADY_ENABLED",
|
|
23217
23313
|
`To rotate the signing secret, run:
|
|
23218
23314
|
wraps email reply rotate --domain ${target}`,
|
|
23219
|
-
"https://wraps.dev/docs/guides/
|
|
23315
|
+
"https://wraps.dev/docs/guides/reply-threading"
|
|
23220
23316
|
);
|
|
23221
23317
|
}
|
|
23222
23318
|
targetDomains = [target];
|
|
@@ -23225,7 +23321,7 @@ async function replyInit(options) {
|
|
|
23225
23321
|
"Specify a domain or use --all",
|
|
23226
23322
|
"REPLY_MISSING_DOMAIN",
|
|
23227
23323
|
"Use one of:\n wraps email reply init --domain yourapp.com\n wraps email reply init --all",
|
|
23228
|
-
"https://wraps.dev/docs/guides/
|
|
23324
|
+
"https://wraps.dev/docs/guides/reply-threading"
|
|
23229
23325
|
);
|
|
23230
23326
|
}
|
|
23231
23327
|
const stackName = emailService.pulumiStackName || `wraps-${identity.accountId}-${region}`;
|
|
@@ -23277,7 +23373,7 @@ async function replyRotate(options) {
|
|
|
23277
23373
|
"--domain is required for rotate",
|
|
23278
23374
|
"REPLY_ROTATE_MISSING_DOMAIN",
|
|
23279
23375
|
"Usage:\n wraps email reply rotate --domain yourapp.com",
|
|
23280
|
-
"https://wraps.dev/docs/guides/
|
|
23376
|
+
"https://wraps.dev/docs/guides/reply-threading"
|
|
23281
23377
|
);
|
|
23282
23378
|
}
|
|
23283
23379
|
const identity = await progress.execute(
|
|
@@ -23291,7 +23387,7 @@ async function replyRotate(options) {
|
|
|
23291
23387
|
"Reply threading is not enabled",
|
|
23292
23388
|
"REPLY_NOT_ENABLED",
|
|
23293
23389
|
"Enable it first:\n wraps email reply init --domain yourapp.com",
|
|
23294
|
-
"https://wraps.dev/docs/guides/
|
|
23390
|
+
"https://wraps.dev/docs/guides/reply-threading"
|
|
23295
23391
|
);
|
|
23296
23392
|
}
|
|
23297
23393
|
const rt = metadata.services.email.config.replyThreading;
|
|
@@ -23302,7 +23398,7 @@ async function replyRotate(options) {
|
|
|
23302
23398
|
"REPLY_DOMAIN_NOT_ENABLED",
|
|
23303
23399
|
`Enable it first:
|
|
23304
23400
|
wraps email reply init --domain ${options.domain}`,
|
|
23305
|
-
"https://wraps.dev/docs/guides/
|
|
23401
|
+
"https://wraps.dev/docs/guides/reply-threading"
|
|
23306
23402
|
);
|
|
23307
23403
|
}
|
|
23308
23404
|
const parameterName = entry.parameterName || ssmParameterName(options.domain);
|
|
@@ -23327,7 +23423,7 @@ async function replyRotate(options) {
|
|
|
23327
23423
|
"REPLY_SECRET_PARAMETER_MISSING",
|
|
23328
23424
|
`The signing secret for ${options.domain} has not been created yet. Run:
|
|
23329
23425
|
wraps email reply init --domain ${options.domain}`,
|
|
23330
|
-
"https://wraps.dev/docs/guides/
|
|
23426
|
+
"https://wraps.dev/docs/guides/reply-threading"
|
|
23331
23427
|
);
|
|
23332
23428
|
}
|
|
23333
23429
|
throw error;
|
|
@@ -23567,7 +23663,7 @@ async function replyDestroy(options) {
|
|
|
23567
23663
|
"Specify a domain or use --all",
|
|
23568
23664
|
"REPLY_DESTROY_MISSING_DOMAIN",
|
|
23569
23665
|
"Usage:\n wraps email reply destroy --domain yourapp.com\n wraps email reply destroy --all",
|
|
23570
|
-
"https://wraps.dev/docs/guides/
|
|
23666
|
+
"https://wraps.dev/docs/guides/reply-threading"
|
|
23571
23667
|
);
|
|
23572
23668
|
}
|
|
23573
23669
|
if (!(options.force || isJsonMode())) {
|
|
@@ -23622,7 +23718,7 @@ async function replyDecode(addressInput, options) {
|
|
|
23622
23718
|
"Usage: wraps email reply decode <token>@r.mail.yourapp.com",
|
|
23623
23719
|
"REPLY_DECODE_MISSING_ADDRESS",
|
|
23624
23720
|
"Provide a signed reply address like:\n wraps email reply decode abcDEF123@r.mail.yourapp.com",
|
|
23625
|
-
"https://wraps.dev/docs/guides/
|
|
23721
|
+
"https://wraps.dev/docs/guides/reply-threading"
|
|
23626
23722
|
);
|
|
23627
23723
|
}
|
|
23628
23724
|
const at = addressInput.lastIndexOf("@");
|
|
@@ -23632,7 +23728,7 @@ async function replyDecode(addressInput, options) {
|
|
|
23632
23728
|
"Address must be in the form <token>@r.mail.example.com",
|
|
23633
23729
|
"REPLY_DECODE_MALFORMED_ADDRESS",
|
|
23634
23730
|
"Pass a full signed reply address:\n wraps email reply decode abcDEF123@r.mail.yourapp.com",
|
|
23635
|
-
"https://wraps.dev/docs/guides/
|
|
23731
|
+
"https://wraps.dev/docs/guides/reply-threading"
|
|
23636
23732
|
);
|
|
23637
23733
|
}
|
|
23638
23734
|
const local = addressInput.slice(0, at);
|
|
@@ -23683,7 +23779,8 @@ init_json_output();
|
|
|
23683
23779
|
init_metadata();
|
|
23684
23780
|
init_output();
|
|
23685
23781
|
init_pulumi();
|
|
23686
|
-
|
|
23782
|
+
init_region_resolver();
|
|
23783
|
+
import * as clack29 from "@clack/prompts";
|
|
23687
23784
|
import * as pulumi21 from "@pulumi/pulumi";
|
|
23688
23785
|
import pc30 from "picocolors";
|
|
23689
23786
|
async function restore(options) {
|
|
@@ -23696,15 +23793,15 @@ async function restore(options) {
|
|
|
23696
23793
|
);
|
|
23697
23794
|
}
|
|
23698
23795
|
if (!isJsonMode()) {
|
|
23699
|
-
|
|
23796
|
+
clack29.intro(
|
|
23700
23797
|
pc30.bold(
|
|
23701
23798
|
options.preview ? "Wraps Restore Preview" : "Wraps Restore - Remove Wraps Infrastructure"
|
|
23702
23799
|
)
|
|
23703
23800
|
);
|
|
23704
|
-
|
|
23801
|
+
clack29.log.info(
|
|
23705
23802
|
`${pc30.yellow("Note:")} This will remove all Wraps-managed infrastructure.`
|
|
23706
23803
|
);
|
|
23707
|
-
|
|
23804
|
+
clack29.log.info(
|
|
23708
23805
|
"Your original AWS resources remain untouched (Wraps never modifies them).\n"
|
|
23709
23806
|
);
|
|
23710
23807
|
}
|
|
@@ -23715,17 +23812,18 @@ async function restore(options) {
|
|
|
23715
23812
|
async () => validateAWSCredentials()
|
|
23716
23813
|
);
|
|
23717
23814
|
progress.info(`Connected to AWS account: ${pc30.cyan(identity.accountId)}`);
|
|
23718
|
-
|
|
23719
|
-
|
|
23720
|
-
|
|
23721
|
-
|
|
23722
|
-
|
|
23815
|
+
const region = await resolveRegionForCommand({
|
|
23816
|
+
accountId: identity.accountId,
|
|
23817
|
+
optionRegion: options.region,
|
|
23818
|
+
service: "email",
|
|
23819
|
+
label: "email deployment"
|
|
23820
|
+
});
|
|
23723
23821
|
const metadata = await loadConnectionMetadata(identity.accountId, region);
|
|
23724
23822
|
if (!metadata) {
|
|
23725
|
-
|
|
23823
|
+
clack29.log.error(
|
|
23726
23824
|
`No Wraps connection found for account ${pc30.cyan(identity.accountId)} in region ${pc30.cyan(region)}`
|
|
23727
23825
|
);
|
|
23728
|
-
|
|
23826
|
+
clack29.log.info(
|
|
23729
23827
|
`Use ${pc30.cyan("wraps email init")} or ${pc30.cyan("wraps email connect")} to create a connection first.`
|
|
23730
23828
|
);
|
|
23731
23829
|
process.exit(1);
|
|
@@ -23750,12 +23848,12 @@ ${pc30.bold("The following Wraps resources will be removed:")}
|
|
|
23750
23848
|
console.log(` ${pc30.cyan("\u2713")} IAM Role (wraps-email-role)`);
|
|
23751
23849
|
console.log("");
|
|
23752
23850
|
if (!(options.force || options.preview)) {
|
|
23753
|
-
const confirmed = await
|
|
23851
|
+
const confirmed = await clack29.confirm({
|
|
23754
23852
|
message: "Proceed with removal? This cannot be undone.",
|
|
23755
23853
|
initialValue: false
|
|
23756
23854
|
});
|
|
23757
|
-
if (
|
|
23758
|
-
|
|
23855
|
+
if (clack29.isCancel(confirmed) || !confirmed) {
|
|
23856
|
+
clack29.cancel("Removal cancelled.");
|
|
23759
23857
|
process.exit(0);
|
|
23760
23858
|
}
|
|
23761
23859
|
}
|
|
@@ -23795,7 +23893,7 @@ ${pc30.bold("The following Wraps resources will be removed:")}
|
|
|
23795
23893
|
costEstimate: "Monthly cost after removal: $0.00",
|
|
23796
23894
|
commandName: "wraps email restore"
|
|
23797
23895
|
});
|
|
23798
|
-
|
|
23896
|
+
clack29.outro(
|
|
23799
23897
|
pc30.green(
|
|
23800
23898
|
"Preview complete. Run without --preview to remove infrastructure."
|
|
23801
23899
|
)
|
|
@@ -23888,7 +23986,7 @@ init_json_output();
|
|
|
23888
23986
|
init_metadata();
|
|
23889
23987
|
init_output();
|
|
23890
23988
|
init_pulumi();
|
|
23891
|
-
import * as
|
|
23989
|
+
import * as clack30 from "@clack/prompts";
|
|
23892
23990
|
import * as pulumi22 from "@pulumi/pulumi";
|
|
23893
23991
|
import pc31 from "picocolors";
|
|
23894
23992
|
async function emailStatus(options) {
|
|
@@ -23896,7 +23994,7 @@ async function emailStatus(options) {
|
|
|
23896
23994
|
const startTime = Date.now();
|
|
23897
23995
|
const progress = new DeploymentProgress();
|
|
23898
23996
|
if (!isJsonMode()) {
|
|
23899
|
-
|
|
23997
|
+
clack30.intro(pc31.bold("Wraps Email Status"));
|
|
23900
23998
|
}
|
|
23901
23999
|
const identity = await progress.execute(
|
|
23902
24000
|
"Loading email infrastructure status",
|
|
@@ -23911,15 +24009,15 @@ async function emailStatus(options) {
|
|
|
23911
24009
|
if (emailConnections.length === 1) {
|
|
23912
24010
|
region = emailConnections[0].region;
|
|
23913
24011
|
} else if (emailConnections.length > 1) {
|
|
23914
|
-
const selectedRegion = await
|
|
24012
|
+
const selectedRegion = await clack30.select({
|
|
23915
24013
|
message: "Multiple email deployments found. Which region?",
|
|
23916
24014
|
options: emailConnections.map((conn) => ({
|
|
23917
24015
|
value: conn.region,
|
|
23918
24016
|
label: conn.region
|
|
23919
24017
|
}))
|
|
23920
24018
|
});
|
|
23921
|
-
if (
|
|
23922
|
-
|
|
24019
|
+
if (clack30.isCancel(selectedRegion)) {
|
|
24020
|
+
clack30.cancel("Operation cancelled");
|
|
23923
24021
|
process.exit(0);
|
|
23924
24022
|
}
|
|
23925
24023
|
region = selectedRegion;
|
|
@@ -23935,7 +24033,7 @@ async function emailStatus(options) {
|
|
|
23935
24033
|
stackOutputs = await stack.outputs();
|
|
23936
24034
|
} catch (_error) {
|
|
23937
24035
|
progress.stop();
|
|
23938
|
-
|
|
24036
|
+
clack30.log.error("No email infrastructure found");
|
|
23939
24037
|
console.log(
|
|
23940
24038
|
`
|
|
23941
24039
|
Run ${pc31.cyan("wraps email init")} to deploy email infrastructure.
|
|
@@ -24031,7 +24129,7 @@ init_output();
|
|
|
24031
24129
|
import { existsSync as existsSync9 } from "fs";
|
|
24032
24130
|
import { mkdir as mkdir3, readFile as readFile4, writeFile as writeFile5 } from "fs/promises";
|
|
24033
24131
|
import { join as join11 } from "path";
|
|
24034
|
-
import * as
|
|
24132
|
+
import * as clack31 from "@clack/prompts";
|
|
24035
24133
|
import pc32 from "picocolors";
|
|
24036
24134
|
|
|
24037
24135
|
// src/utils/shared/scaffold-claude.ts
|
|
@@ -24478,7 +24576,7 @@ async function templatesInit(options) {
|
|
|
24478
24576
|
const cwd = process.cwd();
|
|
24479
24577
|
const wrapsDir = join11(cwd, "wraps");
|
|
24480
24578
|
if (!isJsonMode()) {
|
|
24481
|
-
|
|
24579
|
+
clack31.intro(pc32.bold("Templates as Code"));
|
|
24482
24580
|
}
|
|
24483
24581
|
const progress = new DeploymentProgress();
|
|
24484
24582
|
if (existsSync9(wrapsDir) && !options.force) {
|
|
@@ -24495,12 +24593,12 @@ async function templatesInit(options) {
|
|
|
24495
24593
|
if (orgs?.length === 1) {
|
|
24496
24594
|
orgSlug = orgs[0].slug;
|
|
24497
24595
|
} else if (orgs && orgs.length > 1 && !isJsonMode()) {
|
|
24498
|
-
const selected = await
|
|
24596
|
+
const selected = await clack31.select({
|
|
24499
24597
|
message: "Which organization?",
|
|
24500
24598
|
options: orgs.map((o) => ({ value: o.slug, label: o.name }))
|
|
24501
24599
|
});
|
|
24502
|
-
if (
|
|
24503
|
-
|
|
24600
|
+
if (clack31.isCancel(selected)) {
|
|
24601
|
+
clack31.cancel("Operation cancelled.");
|
|
24504
24602
|
process.exit(0);
|
|
24505
24603
|
}
|
|
24506
24604
|
orgSlug = selected;
|
|
@@ -24634,7 +24732,7 @@ wraps/.wraps/
|
|
|
24634
24732
|
duration_ms: Date.now() - startTime
|
|
24635
24733
|
});
|
|
24636
24734
|
console.log();
|
|
24637
|
-
|
|
24735
|
+
clack31.log.success(pc32.green("Templates as Code initialized!"));
|
|
24638
24736
|
console.log();
|
|
24639
24737
|
console.log(` ${pc32.dim("Directory:")} ${pc32.cyan("wraps/")}`);
|
|
24640
24738
|
console.log(` ${pc32.dim("Config:")} ${pc32.cyan("wraps/wraps.config.ts")}`);
|
|
@@ -24847,7 +24945,7 @@ init_esm_shims();
|
|
|
24847
24945
|
init_events();
|
|
24848
24946
|
import { existsSync as existsSync11, watch } from "fs";
|
|
24849
24947
|
import { join as join13 } from "path";
|
|
24850
|
-
import * as
|
|
24948
|
+
import * as clack32 from "@clack/prompts";
|
|
24851
24949
|
import pc33 from "picocolors";
|
|
24852
24950
|
|
|
24853
24951
|
// src/utils/email/template-compiler.ts
|
|
@@ -24972,7 +25070,7 @@ async function templatesPreview(options) {
|
|
|
24972
25070
|
if (!existsSync11(configPath)) {
|
|
24973
25071
|
throw errors.wrapsConfigNotFound();
|
|
24974
25072
|
}
|
|
24975
|
-
|
|
25073
|
+
clack32.intro(pc33.bold("Preview Templates"));
|
|
24976
25074
|
const config2 = await loadWrapsConfig(wrapsDir);
|
|
24977
25075
|
const templatesDir = join13(wrapsDir, config2.templatesDir || "./templates");
|
|
24978
25076
|
if (!existsSync11(templatesDir)) {
|
|
@@ -24980,7 +25078,7 @@ async function templatesPreview(options) {
|
|
|
24980
25078
|
}
|
|
24981
25079
|
const templateFiles = await discoverTemplates(templatesDir, options.template);
|
|
24982
25080
|
if (templateFiles.length === 0) {
|
|
24983
|
-
|
|
25081
|
+
clack32.log.info("No templates found.");
|
|
24984
25082
|
return;
|
|
24985
25083
|
}
|
|
24986
25084
|
const cache = /* @__PURE__ */ new Map();
|
|
@@ -25095,11 +25193,11 @@ async function templatesPreview(options) {
|
|
|
25095
25193
|
success: true,
|
|
25096
25194
|
template_count: templateFiles.length
|
|
25097
25195
|
});
|
|
25098
|
-
|
|
25196
|
+
clack32.log.success(`Preview server running at ${pc33.cyan(url)}`);
|
|
25099
25197
|
if (options.template) {
|
|
25100
|
-
|
|
25198
|
+
clack32.log.info(`Previewing: ${pc33.cyan(options.template)}`);
|
|
25101
25199
|
} else {
|
|
25102
|
-
|
|
25200
|
+
clack32.log.info(
|
|
25103
25201
|
`${templateFiles.length} template${templateFiles.length === 1 ? "" : "s"} available`
|
|
25104
25202
|
);
|
|
25105
25203
|
}
|
|
@@ -25299,7 +25397,7 @@ import { createHash } from "crypto";
|
|
|
25299
25397
|
import { existsSync as existsSync13 } from "fs";
|
|
25300
25398
|
import { mkdir as mkdir6, readFile as readFile6, writeFile as writeFile8 } from "fs/promises";
|
|
25301
25399
|
import { join as join15 } from "path";
|
|
25302
|
-
import * as
|
|
25400
|
+
import * as clack33 from "@clack/prompts";
|
|
25303
25401
|
import pc34 from "picocolors";
|
|
25304
25402
|
|
|
25305
25403
|
// src/utils/email/template-render.ts
|
|
@@ -25420,7 +25518,7 @@ async function templatesPush(options) {
|
|
|
25420
25518
|
throw errors.wrapsConfigNotFound();
|
|
25421
25519
|
}
|
|
25422
25520
|
if (!isJsonMode()) {
|
|
25423
|
-
|
|
25521
|
+
clack33.intro(pc34.bold("Push Templates"));
|
|
25424
25522
|
}
|
|
25425
25523
|
const progress = new DeploymentProgress();
|
|
25426
25524
|
progress.start("Loading configuration");
|
|
@@ -25433,7 +25531,7 @@ async function templatesPush(options) {
|
|
|
25433
25531
|
const templateFiles = await discoverTemplates(templatesDir, options.template);
|
|
25434
25532
|
if (templateFiles.length === 0) {
|
|
25435
25533
|
if (!isJsonMode()) {
|
|
25436
|
-
|
|
25534
|
+
clack33.log.info("No templates found to push.");
|
|
25437
25535
|
}
|
|
25438
25536
|
return;
|
|
25439
25537
|
}
|
|
@@ -25479,7 +25577,7 @@ async function templatesPush(options) {
|
|
|
25479
25577
|
errors: []
|
|
25480
25578
|
});
|
|
25481
25579
|
} else {
|
|
25482
|
-
|
|
25580
|
+
clack33.log.info(
|
|
25483
25581
|
`${unchanged.length} template${unchanged.length === 1 ? "" : "s"} unchanged. Use --force to re-push.`
|
|
25484
25582
|
);
|
|
25485
25583
|
}
|
|
@@ -25500,7 +25598,7 @@ async function templatesPush(options) {
|
|
|
25500
25598
|
});
|
|
25501
25599
|
} else {
|
|
25502
25600
|
console.log();
|
|
25503
|
-
|
|
25601
|
+
clack33.log.info(pc34.bold("Dry run \u2014 no changes made"));
|
|
25504
25602
|
console.log();
|
|
25505
25603
|
for (const t of compiled) {
|
|
25506
25604
|
console.log(
|
|
@@ -25552,16 +25650,16 @@ async function templatesPush(options) {
|
|
|
25552
25650
|
});
|
|
25553
25651
|
} else {
|
|
25554
25652
|
console.log();
|
|
25555
|
-
|
|
25653
|
+
clack33.log.success(
|
|
25556
25654
|
pc34.green(
|
|
25557
25655
|
`${compiled.length} template${compiled.length === 1 ? "" : "s"} pushed`
|
|
25558
25656
|
)
|
|
25559
25657
|
);
|
|
25560
25658
|
if (unchanged.length > 0) {
|
|
25561
|
-
|
|
25659
|
+
clack33.log.info(`${unchanged.length} unchanged (use --force to re-push)`);
|
|
25562
25660
|
}
|
|
25563
25661
|
if (compileErrors.length > 0) {
|
|
25564
|
-
|
|
25662
|
+
clack33.log.error(`${compileErrors.length} failed to compile`);
|
|
25565
25663
|
}
|
|
25566
25664
|
console.log();
|
|
25567
25665
|
}
|
|
@@ -25696,20 +25794,21 @@ function transformVariablesForSes(content) {
|
|
|
25696
25794
|
}
|
|
25697
25795
|
async function pushToSES(templates, progress) {
|
|
25698
25796
|
const results = [];
|
|
25699
|
-
|
|
25700
|
-
let
|
|
25797
|
+
const { validateAWSCredentialsWithDetails: validateAWSCredentialsWithDetails2 } = await Promise.resolve().then(() => (init_aws(), aws_exports));
|
|
25798
|
+
let identity;
|
|
25701
25799
|
try {
|
|
25702
|
-
const
|
|
25703
|
-
|
|
25704
|
-
hasAWSCredentials = true;
|
|
25705
|
-
region = await getAWSRegion2();
|
|
25800
|
+
const result = await validateAWSCredentialsWithDetails2();
|
|
25801
|
+
identity = result.identity;
|
|
25706
25802
|
} catch {
|
|
25707
25803
|
progress.info("No AWS credentials \u2014 skipping SES push");
|
|
25708
25804
|
return templates.map((t) => ({ slug: t.slug, success: false }));
|
|
25709
25805
|
}
|
|
25710
|
-
|
|
25711
|
-
|
|
25712
|
-
|
|
25806
|
+
const { resolveRegionForCommand: resolveRegionForCommand2 } = await Promise.resolve().then(() => (init_region_resolver(), region_resolver_exports));
|
|
25807
|
+
const region = await resolveRegionForCommand2({
|
|
25808
|
+
accountId: identity.accountId,
|
|
25809
|
+
service: "email",
|
|
25810
|
+
label: "email deployment"
|
|
25811
|
+
});
|
|
25713
25812
|
const {
|
|
25714
25813
|
SESv2Client: SESv2Client9,
|
|
25715
25814
|
CreateEmailTemplateCommand,
|
|
@@ -25939,7 +26038,7 @@ init_test();
|
|
|
25939
26038
|
|
|
25940
26039
|
// src/commands/email/upgrade.ts
|
|
25941
26040
|
init_esm_shims();
|
|
25942
|
-
import * as
|
|
26041
|
+
import * as clack34 from "@clack/prompts";
|
|
25943
26042
|
import * as pulumi23 from "@pulumi/pulumi";
|
|
25944
26043
|
import pc35 from "picocolors";
|
|
25945
26044
|
init_events();
|
|
@@ -25955,11 +26054,12 @@ init_metadata();
|
|
|
25955
26054
|
init_output();
|
|
25956
26055
|
init_prompts();
|
|
25957
26056
|
init_pulumi();
|
|
26057
|
+
init_region_resolver();
|
|
25958
26058
|
async function upgrade(options) {
|
|
25959
26059
|
const startTime = Date.now();
|
|
25960
26060
|
let upgradeAction = "";
|
|
25961
26061
|
if (!isJsonMode()) {
|
|
25962
|
-
|
|
26062
|
+
clack34.intro(
|
|
25963
26063
|
pc35.bold(
|
|
25964
26064
|
options.preview ? "Wraps Upgrade Preview" : "Wraps Upgrade - Enhance Your Email Infrastructure"
|
|
25965
26065
|
)
|
|
@@ -25978,17 +26078,18 @@ async function upgrade(options) {
|
|
|
25978
26078
|
async () => validateAWSCredentials()
|
|
25979
26079
|
);
|
|
25980
26080
|
progress.info(`Connected to AWS account: ${pc35.cyan(identity.accountId)}`);
|
|
25981
|
-
|
|
25982
|
-
|
|
25983
|
-
|
|
25984
|
-
|
|
25985
|
-
|
|
26081
|
+
const region = await resolveRegionForCommand({
|
|
26082
|
+
accountId: identity.accountId,
|
|
26083
|
+
optionRegion: options.region,
|
|
26084
|
+
service: "email",
|
|
26085
|
+
label: "email deployment"
|
|
26086
|
+
});
|
|
25986
26087
|
const metadata = await loadConnectionMetadata(identity.accountId, region);
|
|
25987
26088
|
if (!metadata) {
|
|
25988
|
-
|
|
26089
|
+
clack34.log.error(
|
|
25989
26090
|
`No Wraps connection found for account ${pc35.cyan(identity.accountId)} in region ${pc35.cyan(region)}`
|
|
25990
26091
|
);
|
|
25991
|
-
|
|
26092
|
+
clack34.log.info(
|
|
25992
26093
|
`Use ${pc35.cyan("wraps email init")} to create new infrastructure or ${pc35.cyan("wraps email connect")} to connect existing.`
|
|
25993
26094
|
);
|
|
25994
26095
|
process.exit(1);
|
|
@@ -26004,8 +26105,8 @@ ${pc35.bold("Current Configuration:")}
|
|
|
26004
26105
|
}
|
|
26005
26106
|
const config2 = metadata.services.email?.config;
|
|
26006
26107
|
if (!config2) {
|
|
26007
|
-
|
|
26008
|
-
|
|
26108
|
+
clack34.log.error("No email configuration found in metadata");
|
|
26109
|
+
clack34.log.info(
|
|
26009
26110
|
`Use ${pc35.cyan("wraps email init")} to create new infrastructure.`
|
|
26010
26111
|
);
|
|
26011
26112
|
process.exit(1);
|
|
@@ -26158,12 +26259,12 @@ ${pc35.bold("Current Configuration:")}
|
|
|
26158
26259
|
if (options.action) {
|
|
26159
26260
|
upgradeAction = options.action;
|
|
26160
26261
|
} else {
|
|
26161
|
-
upgradeAction = await
|
|
26262
|
+
upgradeAction = await clack34.select({
|
|
26162
26263
|
message: "What would you like to do?",
|
|
26163
26264
|
options: upgradeOptions
|
|
26164
26265
|
});
|
|
26165
|
-
if (
|
|
26166
|
-
|
|
26266
|
+
if (clack34.isCancel(upgradeAction)) {
|
|
26267
|
+
clack34.cancel("Upgrade cancelled.");
|
|
26167
26268
|
process.exit(0);
|
|
26168
26269
|
}
|
|
26169
26270
|
}
|
|
@@ -26171,7 +26272,7 @@ ${pc35.bold("Current Configuration:")}
|
|
|
26171
26272
|
let newPreset = metadata.services.email?.preset;
|
|
26172
26273
|
switch (upgradeAction) {
|
|
26173
26274
|
case "finish-tracking-domain": {
|
|
26174
|
-
|
|
26275
|
+
clack34.log.info(
|
|
26175
26276
|
`Checking certificate status for ${pc35.cyan(config2.tracking?.customRedirectDomain ?? "")}...`
|
|
26176
26277
|
);
|
|
26177
26278
|
updatedConfig = { ...config2 };
|
|
@@ -26192,19 +26293,19 @@ ${pc35.bold("Current Configuration:")}
|
|
|
26192
26293
|
disabled: currentPresetIdx >= 0 && idx <= currentPresetIdx ? "Current or lower tier" : void 0
|
|
26193
26294
|
})).filter((p) => !p.disabled);
|
|
26194
26295
|
if (availablePresets.length === 0) {
|
|
26195
|
-
|
|
26296
|
+
clack34.log.warn("Already on highest preset (Enterprise)");
|
|
26196
26297
|
process.exit(0);
|
|
26197
26298
|
}
|
|
26198
26299
|
let selectedPreset;
|
|
26199
26300
|
if (options.preset) {
|
|
26200
26301
|
selectedPreset = options.preset;
|
|
26201
26302
|
} else {
|
|
26202
|
-
selectedPreset = await
|
|
26303
|
+
selectedPreset = await clack34.select({
|
|
26203
26304
|
message: "Select new preset:",
|
|
26204
26305
|
options: availablePresets
|
|
26205
26306
|
});
|
|
26206
|
-
if (
|
|
26207
|
-
|
|
26307
|
+
if (clack34.isCancel(selectedPreset)) {
|
|
26308
|
+
clack34.cancel("Upgrade cancelled.");
|
|
26208
26309
|
process.exit(0);
|
|
26209
26310
|
}
|
|
26210
26311
|
}
|
|
@@ -26215,7 +26316,7 @@ ${pc35.bold("Current Configuration:")}
|
|
|
26215
26316
|
}
|
|
26216
26317
|
case "archiving": {
|
|
26217
26318
|
if (config2.emailArchiving?.enabled) {
|
|
26218
|
-
const archivingAction = await
|
|
26319
|
+
const archivingAction = await clack34.select({
|
|
26219
26320
|
message: "What would you like to do with email archiving?",
|
|
26220
26321
|
options: [
|
|
26221
26322
|
{
|
|
@@ -26230,17 +26331,17 @@ ${pc35.bold("Current Configuration:")}
|
|
|
26230
26331
|
}
|
|
26231
26332
|
]
|
|
26232
26333
|
});
|
|
26233
|
-
if (
|
|
26234
|
-
|
|
26334
|
+
if (clack34.isCancel(archivingAction)) {
|
|
26335
|
+
clack34.cancel("Upgrade cancelled.");
|
|
26235
26336
|
process.exit(0);
|
|
26236
26337
|
}
|
|
26237
26338
|
if (archivingAction === "disable") {
|
|
26238
|
-
const confirmDisable = await
|
|
26339
|
+
const confirmDisable = await clack34.confirm({
|
|
26239
26340
|
message: "Are you sure? Existing archived emails will remain, but new emails won't be archived.",
|
|
26240
26341
|
initialValue: false
|
|
26241
26342
|
});
|
|
26242
|
-
if (
|
|
26243
|
-
|
|
26343
|
+
if (clack34.isCancel(confirmDisable) || !confirmDisable) {
|
|
26344
|
+
clack34.cancel("Archiving not disabled.");
|
|
26244
26345
|
process.exit(0);
|
|
26245
26346
|
}
|
|
26246
26347
|
updatedConfig = {
|
|
@@ -26251,7 +26352,7 @@ ${pc35.bold("Current Configuration:")}
|
|
|
26251
26352
|
}
|
|
26252
26353
|
};
|
|
26253
26354
|
} else {
|
|
26254
|
-
const retention = await
|
|
26355
|
+
const retention = await clack34.select({
|
|
26255
26356
|
message: "Email archive retention period:",
|
|
26256
26357
|
options: [
|
|
26257
26358
|
{
|
|
@@ -26287,8 +26388,8 @@ ${pc35.bold("Current Configuration:")}
|
|
|
26287
26388
|
],
|
|
26288
26389
|
initialValue: config2.emailArchiving.retention
|
|
26289
26390
|
});
|
|
26290
|
-
if (
|
|
26291
|
-
|
|
26391
|
+
if (clack34.isCancel(retention)) {
|
|
26392
|
+
clack34.cancel("Upgrade cancelled.");
|
|
26292
26393
|
process.exit(0);
|
|
26293
26394
|
}
|
|
26294
26395
|
updatedConfig = {
|
|
@@ -26300,19 +26401,19 @@ ${pc35.bold("Current Configuration:")}
|
|
|
26300
26401
|
};
|
|
26301
26402
|
}
|
|
26302
26403
|
} else {
|
|
26303
|
-
const enableArchiving = await
|
|
26404
|
+
const enableArchiving = await clack34.confirm({
|
|
26304
26405
|
message: "Enable email archiving? (Store full email content with HTML for viewing)",
|
|
26305
26406
|
initialValue: true
|
|
26306
26407
|
});
|
|
26307
|
-
if (
|
|
26308
|
-
|
|
26408
|
+
if (clack34.isCancel(enableArchiving)) {
|
|
26409
|
+
clack34.cancel("Upgrade cancelled.");
|
|
26309
26410
|
process.exit(0);
|
|
26310
26411
|
}
|
|
26311
26412
|
if (!enableArchiving) {
|
|
26312
|
-
|
|
26413
|
+
clack34.log.info("Email archiving not enabled.");
|
|
26313
26414
|
process.exit(0);
|
|
26314
26415
|
}
|
|
26315
|
-
const retention = await
|
|
26416
|
+
const retention = await clack34.select({
|
|
26316
26417
|
message: "Email archive retention period:",
|
|
26317
26418
|
options: [
|
|
26318
26419
|
{
|
|
@@ -26348,16 +26449,16 @@ ${pc35.bold("Current Configuration:")}
|
|
|
26348
26449
|
],
|
|
26349
26450
|
initialValue: "90days"
|
|
26350
26451
|
});
|
|
26351
|
-
if (
|
|
26352
|
-
|
|
26452
|
+
if (clack34.isCancel(retention)) {
|
|
26453
|
+
clack34.cancel("Upgrade cancelled.");
|
|
26353
26454
|
process.exit(0);
|
|
26354
26455
|
}
|
|
26355
|
-
|
|
26456
|
+
clack34.log.info(
|
|
26356
26457
|
pc35.dim(
|
|
26357
26458
|
"Archiving stores full RFC 822 emails with HTML, attachments, and headers"
|
|
26358
26459
|
)
|
|
26359
26460
|
);
|
|
26360
|
-
|
|
26461
|
+
clack34.log.info(
|
|
26361
26462
|
pc35.dim(
|
|
26362
26463
|
"Cost: $2/GB ingestion + $0.19/GB/month storage (~50KB per email)"
|
|
26363
26464
|
)
|
|
@@ -26375,10 +26476,10 @@ ${pc35.bold("Current Configuration:")}
|
|
|
26375
26476
|
}
|
|
26376
26477
|
case "tracking-domain": {
|
|
26377
26478
|
if (!config2.domain) {
|
|
26378
|
-
|
|
26479
|
+
clack34.log.error(
|
|
26379
26480
|
"No sending domain configured. You must configure a sending domain before adding a custom tracking domain."
|
|
26380
26481
|
);
|
|
26381
|
-
|
|
26482
|
+
clack34.log.info(
|
|
26382
26483
|
`Use ${pc35.cyan("wraps email init")} to set up a sending domain first.`
|
|
26383
26484
|
);
|
|
26384
26485
|
process.exit(1);
|
|
@@ -26390,13 +26491,13 @@ ${pc35.bold("Current Configuration:")}
|
|
|
26390
26491
|
);
|
|
26391
26492
|
const sendingDomain = domains.find((d) => d.domain === config2.domain);
|
|
26392
26493
|
if (!sendingDomain?.verified) {
|
|
26393
|
-
|
|
26494
|
+
clack34.log.error(
|
|
26394
26495
|
`Sending domain ${pc35.cyan(config2.domain)} is not verified.`
|
|
26395
26496
|
);
|
|
26396
|
-
|
|
26497
|
+
clack34.log.info(
|
|
26397
26498
|
"You must verify your sending domain before adding a custom tracking domain."
|
|
26398
26499
|
);
|
|
26399
|
-
|
|
26500
|
+
clack34.log.info(
|
|
26400
26501
|
`Use ${pc35.cyan("wraps email verify")} to check DNS records and complete verification.`
|
|
26401
26502
|
);
|
|
26402
26503
|
process.exit(1);
|
|
@@ -26404,7 +26505,7 @@ ${pc35.bold("Current Configuration:")}
|
|
|
26404
26505
|
progress.info(
|
|
26405
26506
|
`Sending domain ${pc35.cyan(config2.domain)} is verified ${pc35.green("\u2713")}`
|
|
26406
26507
|
);
|
|
26407
|
-
const trackingDomain = await
|
|
26508
|
+
const trackingDomain = await clack34.text({
|
|
26408
26509
|
message: "Custom tracking redirect domain:",
|
|
26409
26510
|
placeholder: "track.yourdomain.com",
|
|
26410
26511
|
initialValue: config2.tracking?.customRedirectDomain || "",
|
|
@@ -26414,25 +26515,25 @@ ${pc35.bold("Current Configuration:")}
|
|
|
26414
26515
|
}
|
|
26415
26516
|
}
|
|
26416
26517
|
});
|
|
26417
|
-
if (
|
|
26418
|
-
|
|
26518
|
+
if (clack34.isCancel(trackingDomain)) {
|
|
26519
|
+
clack34.cancel("Upgrade cancelled.");
|
|
26419
26520
|
process.exit(0);
|
|
26420
26521
|
}
|
|
26421
|
-
const enableHttps = await
|
|
26522
|
+
const enableHttps = await clack34.confirm({
|
|
26422
26523
|
message: "Enable HTTPS tracking with CloudFront + SSL certificate?",
|
|
26423
26524
|
initialValue: true
|
|
26424
26525
|
});
|
|
26425
|
-
if (
|
|
26426
|
-
|
|
26526
|
+
if (clack34.isCancel(enableHttps)) {
|
|
26527
|
+
clack34.cancel("Upgrade cancelled.");
|
|
26427
26528
|
process.exit(0);
|
|
26428
26529
|
}
|
|
26429
26530
|
if (enableHttps) {
|
|
26430
|
-
|
|
26531
|
+
clack34.log.info(
|
|
26431
26532
|
pc35.dim(
|
|
26432
26533
|
"HTTPS tracking creates a CloudFront distribution with an SSL certificate."
|
|
26433
26534
|
)
|
|
26434
26535
|
);
|
|
26435
|
-
|
|
26536
|
+
clack34.log.info(
|
|
26436
26537
|
pc35.dim(
|
|
26437
26538
|
"This ensures all tracking links use secure HTTPS connections."
|
|
26438
26539
|
)
|
|
@@ -26463,32 +26564,32 @@ ${pc35.bold("Current Configuration:")}
|
|
|
26463
26564
|
progress.info(
|
|
26464
26565
|
`Found ${pc35.cyan(getDNSProviderDisplayName(detectedProvider.provider))} ${pc35.green("\u2713")}`
|
|
26465
26566
|
);
|
|
26466
|
-
|
|
26567
|
+
clack34.log.info(
|
|
26467
26568
|
pc35.dim(
|
|
26468
26569
|
"DNS records (SSL certificate validation + CloudFront) will be created automatically."
|
|
26469
26570
|
)
|
|
26470
26571
|
);
|
|
26471
26572
|
} else {
|
|
26472
26573
|
canAutomateDNS = false;
|
|
26473
|
-
|
|
26574
|
+
clack34.log.warn(
|
|
26474
26575
|
`No automatic DNS provider detected for ${pc35.cyan(trackingDomain || config2.domain)}`
|
|
26475
26576
|
);
|
|
26476
|
-
|
|
26577
|
+
clack34.log.info(
|
|
26477
26578
|
pc35.dim(
|
|
26478
26579
|
"You'll need to manually create DNS records for SSL certificate validation and CloudFront."
|
|
26479
26580
|
)
|
|
26480
26581
|
);
|
|
26481
|
-
|
|
26582
|
+
clack34.log.info(
|
|
26482
26583
|
pc35.dim("DNS record details will be shown after deployment.")
|
|
26483
26584
|
);
|
|
26484
26585
|
}
|
|
26485
26586
|
}
|
|
26486
|
-
const confirmHttps = await
|
|
26587
|
+
const confirmHttps = await clack34.confirm({
|
|
26487
26588
|
message: canAutomateDNS ? "Proceed with automatic HTTPS setup?" : "Proceed with manual HTTPS setup (requires DNS configuration)?",
|
|
26488
26589
|
initialValue: true
|
|
26489
26590
|
});
|
|
26490
|
-
if (
|
|
26491
|
-
|
|
26591
|
+
if (clack34.isCancel(confirmHttps) || !confirmHttps) {
|
|
26592
|
+
clack34.log.info("HTTPS tracking not enabled. Using HTTP tracking.");
|
|
26492
26593
|
updatedConfig = {
|
|
26493
26594
|
...config2,
|
|
26494
26595
|
tracking: {
|
|
@@ -26510,7 +26611,7 @@ ${pc35.bold("Current Configuration:")}
|
|
|
26510
26611
|
};
|
|
26511
26612
|
}
|
|
26512
26613
|
} else {
|
|
26513
|
-
|
|
26614
|
+
clack34.log.info(
|
|
26514
26615
|
pc35.dim(
|
|
26515
26616
|
"Using HTTP tracking (standard). Links will use http:// protocol."
|
|
26516
26617
|
)
|
|
@@ -26529,7 +26630,7 @@ ${pc35.bold("Current Configuration:")}
|
|
|
26529
26630
|
break;
|
|
26530
26631
|
}
|
|
26531
26632
|
case "retention": {
|
|
26532
|
-
const retention = await
|
|
26633
|
+
const retention = await clack34.select({
|
|
26533
26634
|
message: "Email history retention period (event data in DynamoDB):",
|
|
26534
26635
|
options: [
|
|
26535
26636
|
{ value: "7days", label: "7 days", hint: "Minimal storage cost" },
|
|
@@ -26553,16 +26654,16 @@ ${pc35.bold("Current Configuration:")}
|
|
|
26553
26654
|
],
|
|
26554
26655
|
initialValue: config2.eventTracking?.archiveRetention || "90days"
|
|
26555
26656
|
});
|
|
26556
|
-
if (
|
|
26557
|
-
|
|
26657
|
+
if (clack34.isCancel(retention)) {
|
|
26658
|
+
clack34.cancel("Upgrade cancelled.");
|
|
26558
26659
|
process.exit(0);
|
|
26559
26660
|
}
|
|
26560
|
-
|
|
26661
|
+
clack34.log.info(
|
|
26561
26662
|
pc35.dim(
|
|
26562
26663
|
"Note: This is for event data (sent, delivered, opened, etc.) stored in DynamoDB."
|
|
26563
26664
|
)
|
|
26564
26665
|
);
|
|
26565
|
-
|
|
26666
|
+
clack34.log.info(
|
|
26566
26667
|
pc35.dim(
|
|
26567
26668
|
"For full email content storage, use 'Enable email archiving' option."
|
|
26568
26669
|
)
|
|
@@ -26580,7 +26681,7 @@ ${pc35.bold("Current Configuration:")}
|
|
|
26580
26681
|
break;
|
|
26581
26682
|
}
|
|
26582
26683
|
case "events": {
|
|
26583
|
-
const selectedEvents = await
|
|
26684
|
+
const selectedEvents = await clack34.multiselect({
|
|
26584
26685
|
message: "Select SES event types to track:",
|
|
26585
26686
|
options: [
|
|
26586
26687
|
{ value: "SEND", label: "Send", hint: "Email sent to SES" },
|
|
@@ -26624,8 +26725,8 @@ ${pc35.bold("Current Configuration:")}
|
|
|
26624
26725
|
],
|
|
26625
26726
|
required: true
|
|
26626
26727
|
});
|
|
26627
|
-
if (
|
|
26628
|
-
|
|
26728
|
+
if (clack34.isCancel(selectedEvents)) {
|
|
26729
|
+
clack34.cancel("Upgrade cancelled.");
|
|
26629
26730
|
process.exit(0);
|
|
26630
26731
|
}
|
|
26631
26732
|
updatedConfig = {
|
|
@@ -26640,16 +26741,16 @@ ${pc35.bold("Current Configuration:")}
|
|
|
26640
26741
|
break;
|
|
26641
26742
|
}
|
|
26642
26743
|
case "dedicated-ip": {
|
|
26643
|
-
const confirmed = await
|
|
26744
|
+
const confirmed = await clack34.confirm({
|
|
26644
26745
|
message: "Enable dedicated IP? (Requires 100k+ emails/day, adds ~$50-100/mo)",
|
|
26645
26746
|
initialValue: false
|
|
26646
26747
|
});
|
|
26647
|
-
if (
|
|
26648
|
-
|
|
26748
|
+
if (clack34.isCancel(confirmed)) {
|
|
26749
|
+
clack34.cancel("Upgrade cancelled.");
|
|
26649
26750
|
process.exit(0);
|
|
26650
26751
|
}
|
|
26651
26752
|
if (!confirmed) {
|
|
26652
|
-
|
|
26753
|
+
clack34.log.info("Dedicated IP not enabled.");
|
|
26653
26754
|
process.exit(0);
|
|
26654
26755
|
}
|
|
26655
26756
|
updatedConfig = {
|
|
@@ -26661,16 +26762,16 @@ ${pc35.bold("Current Configuration:")}
|
|
|
26661
26762
|
}
|
|
26662
26763
|
case "alerts": {
|
|
26663
26764
|
if (!config2.reputationMetrics) {
|
|
26664
|
-
|
|
26665
|
-
|
|
26765
|
+
clack34.log.warn("Reputation metrics must be enabled to use alerting.");
|
|
26766
|
+
clack34.log.info(
|
|
26666
26767
|
"This requires the Production or Enterprise preset, or enabling reputation metrics manually."
|
|
26667
26768
|
);
|
|
26668
|
-
const enableReputationMetrics = await
|
|
26769
|
+
const enableReputationMetrics = await clack34.confirm({
|
|
26669
26770
|
message: "Enable reputation metrics now?",
|
|
26670
26771
|
initialValue: true
|
|
26671
26772
|
});
|
|
26672
|
-
if (
|
|
26673
|
-
|
|
26773
|
+
if (clack34.isCancel(enableReputationMetrics) || !enableReputationMetrics) {
|
|
26774
|
+
clack34.cancel("Alerting not enabled.");
|
|
26674
26775
|
process.exit(0);
|
|
26675
26776
|
}
|
|
26676
26777
|
updatedConfig = {
|
|
@@ -26679,13 +26780,13 @@ ${pc35.bold("Current Configuration:")}
|
|
|
26679
26780
|
};
|
|
26680
26781
|
}
|
|
26681
26782
|
if (config2.alerts?.enabled) {
|
|
26682
|
-
|
|
26783
|
+
clack34.log.info(`Alerting is currently ${pc35.green("enabled")}`);
|
|
26683
26784
|
if (config2.alerts.notificationEmail) {
|
|
26684
|
-
|
|
26785
|
+
clack34.log.info(
|
|
26685
26786
|
` Notification email: ${pc35.cyan(config2.alerts.notificationEmail)}`
|
|
26686
26787
|
);
|
|
26687
26788
|
}
|
|
26688
|
-
const alertsAction = await
|
|
26789
|
+
const alertsAction = await clack34.select({
|
|
26689
26790
|
message: "What would you like to do?",
|
|
26690
26791
|
options: [
|
|
26691
26792
|
{
|
|
@@ -26705,17 +26806,17 @@ ${pc35.bold("Current Configuration:")}
|
|
|
26705
26806
|
}
|
|
26706
26807
|
]
|
|
26707
26808
|
});
|
|
26708
|
-
if (
|
|
26709
|
-
|
|
26809
|
+
if (clack34.isCancel(alertsAction)) {
|
|
26810
|
+
clack34.cancel("Upgrade cancelled.");
|
|
26710
26811
|
process.exit(0);
|
|
26711
26812
|
}
|
|
26712
26813
|
if (alertsAction === "disable") {
|
|
26713
|
-
const confirmDisable = await
|
|
26814
|
+
const confirmDisable = await clack34.confirm({
|
|
26714
26815
|
message: "Are you sure? You won't be notified if your reputation degrades.",
|
|
26715
26816
|
initialValue: false
|
|
26716
26817
|
});
|
|
26717
|
-
if (
|
|
26718
|
-
|
|
26818
|
+
if (clack34.isCancel(confirmDisable) || !confirmDisable) {
|
|
26819
|
+
clack34.log.info("Alerting not disabled.");
|
|
26719
26820
|
process.exit(0);
|
|
26720
26821
|
}
|
|
26721
26822
|
updatedConfig = {
|
|
@@ -26723,7 +26824,7 @@ ${pc35.bold("Current Configuration:")}
|
|
|
26723
26824
|
alerts: { enabled: false }
|
|
26724
26825
|
};
|
|
26725
26826
|
} else if (alertsAction === "change-email") {
|
|
26726
|
-
const notificationEmail = await
|
|
26827
|
+
const notificationEmail = await clack34.text({
|
|
26727
26828
|
message: "Notification email address:",
|
|
26728
26829
|
placeholder: "alerts@yourcompany.com",
|
|
26729
26830
|
initialValue: config2.alerts.notificationEmail || "",
|
|
@@ -26733,8 +26834,8 @@ ${pc35.bold("Current Configuration:")}
|
|
|
26733
26834
|
}
|
|
26734
26835
|
}
|
|
26735
26836
|
});
|
|
26736
|
-
if (
|
|
26737
|
-
|
|
26837
|
+
if (clack34.isCancel(notificationEmail)) {
|
|
26838
|
+
clack34.cancel("Upgrade cancelled.");
|
|
26738
26839
|
process.exit(0);
|
|
26739
26840
|
}
|
|
26740
26841
|
updatedConfig = {
|
|
@@ -26746,14 +26847,14 @@ ${pc35.bold("Current Configuration:")}
|
|
|
26746
26847
|
}
|
|
26747
26848
|
};
|
|
26748
26849
|
} else if (alertsAction === "change-thresholds") {
|
|
26749
|
-
|
|
26850
|
+
clack34.log.info(`
|
|
26750
26851
|
${pc35.bold("Alert Thresholds")}`);
|
|
26751
|
-
|
|
26852
|
+
clack34.log.info(
|
|
26752
26853
|
pc35.dim("These thresholds warn you BEFORE AWS takes action:")
|
|
26753
26854
|
);
|
|
26754
|
-
|
|
26755
|
-
|
|
26756
|
-
const thresholdPreset = await
|
|
26855
|
+
clack34.log.info(pc35.dim(" AWS warns at 5% bounce, 0.1% complaint"));
|
|
26856
|
+
clack34.log.info(pc35.dim(" Gmail blocks at 0.3% complaint rate\n"));
|
|
26857
|
+
const thresholdPreset = await clack34.select({
|
|
26757
26858
|
message: "Choose threshold sensitivity:",
|
|
26758
26859
|
options: [
|
|
26759
26860
|
{
|
|
@@ -26773,8 +26874,8 @@ ${pc35.bold("Alert Thresholds")}`);
|
|
|
26773
26874
|
}
|
|
26774
26875
|
]
|
|
26775
26876
|
});
|
|
26776
|
-
if (
|
|
26777
|
-
|
|
26877
|
+
if (clack34.isCancel(thresholdPreset)) {
|
|
26878
|
+
clack34.cancel("Upgrade cancelled.");
|
|
26778
26879
|
process.exit(0);
|
|
26779
26880
|
}
|
|
26780
26881
|
const thresholdConfigs = {
|
|
@@ -26807,27 +26908,27 @@ ${pc35.bold("Alert Thresholds")}`);
|
|
|
26807
26908
|
};
|
|
26808
26909
|
}
|
|
26809
26910
|
} else {
|
|
26810
|
-
|
|
26911
|
+
clack34.log.info(`
|
|
26811
26912
|
${pc35.bold("Reputation Alerts")}
|
|
26812
26913
|
`);
|
|
26813
|
-
|
|
26914
|
+
clack34.log.info(
|
|
26814
26915
|
pc35.dim("Get notified when your email reputation is at risk:")
|
|
26815
26916
|
);
|
|
26816
|
-
|
|
26817
|
-
|
|
26917
|
+
clack34.log.info(pc35.dim(" - Bounce rate warnings (before AWS review)"));
|
|
26918
|
+
clack34.log.info(
|
|
26818
26919
|
pc35.dim(" - Complaint rate warnings (before Gmail blocks you)")
|
|
26819
26920
|
);
|
|
26820
|
-
|
|
26821
|
-
|
|
26822
|
-
const enableAlerts = await
|
|
26921
|
+
clack34.log.info(pc35.dim(" - DLQ alerts (event processing failures)"));
|
|
26922
|
+
clack34.log.info(pc35.dim("\nCost: ~$0.50/mo (5 CloudWatch alarms)\n"));
|
|
26923
|
+
const enableAlerts = await clack34.confirm({
|
|
26823
26924
|
message: "Enable reputation alerts?",
|
|
26824
26925
|
initialValue: true
|
|
26825
26926
|
});
|
|
26826
|
-
if (
|
|
26827
|
-
|
|
26927
|
+
if (clack34.isCancel(enableAlerts) || !enableAlerts) {
|
|
26928
|
+
clack34.log.info("Alerting not enabled.");
|
|
26828
26929
|
process.exit(0);
|
|
26829
26930
|
}
|
|
26830
|
-
const notificationEmail = await
|
|
26931
|
+
const notificationEmail = await clack34.text({
|
|
26831
26932
|
message: "Notification email address:",
|
|
26832
26933
|
placeholder: "alerts@yourcompany.com",
|
|
26833
26934
|
validate: (value) => {
|
|
@@ -26839,11 +26940,11 @@ ${pc35.bold("Reputation Alerts")}
|
|
|
26839
26940
|
}
|
|
26840
26941
|
}
|
|
26841
26942
|
});
|
|
26842
|
-
if (
|
|
26843
|
-
|
|
26943
|
+
if (clack34.isCancel(notificationEmail)) {
|
|
26944
|
+
clack34.cancel("Upgrade cancelled.");
|
|
26844
26945
|
process.exit(0);
|
|
26845
26946
|
}
|
|
26846
|
-
|
|
26947
|
+
clack34.log.info(
|
|
26847
26948
|
pc35.dim("\nYou'll receive an email to confirm your subscription.")
|
|
26848
26949
|
);
|
|
26849
26950
|
updatedConfig = {
|
|
@@ -26870,18 +26971,18 @@ ${pc35.bold("Reputation Alerts")}
|
|
|
26870
26971
|
}
|
|
26871
26972
|
case "wraps-dashboard": {
|
|
26872
26973
|
if (!config2.eventTracking?.enabled) {
|
|
26873
|
-
|
|
26974
|
+
clack34.log.warn(
|
|
26874
26975
|
"Event tracking must be enabled to connect to Wraps Dashboard."
|
|
26875
26976
|
);
|
|
26876
|
-
|
|
26977
|
+
clack34.log.info(
|
|
26877
26978
|
"Enabling event tracking will allow SES events to be sent to the dashboard."
|
|
26878
26979
|
);
|
|
26879
|
-
const enableEventTracking = await
|
|
26980
|
+
const enableEventTracking = await clack34.confirm({
|
|
26880
26981
|
message: "Enable event tracking now?",
|
|
26881
26982
|
initialValue: true
|
|
26882
26983
|
});
|
|
26883
|
-
if (
|
|
26884
|
-
|
|
26984
|
+
if (clack34.isCancel(enableEventTracking) || !enableEventTracking) {
|
|
26985
|
+
clack34.cancel("Dashboard connection cancelled.");
|
|
26885
26986
|
process.exit(0);
|
|
26886
26987
|
}
|
|
26887
26988
|
updatedConfig = {
|
|
@@ -26904,10 +27005,10 @@ ${pc35.bold("Reputation Alerts")}
|
|
|
26904
27005
|
}
|
|
26905
27006
|
const existingSecret = metadata.services.email?.webhookSecret;
|
|
26906
27007
|
if (existingSecret) {
|
|
26907
|
-
|
|
27008
|
+
clack34.log.info(
|
|
26908
27009
|
`Currently connected to Wraps Dashboard (AWS Account: ${pc35.cyan(metadata.accountId)})`
|
|
26909
27010
|
);
|
|
26910
|
-
const action = await
|
|
27011
|
+
const action = await clack34.select({
|
|
26911
27012
|
message: "What would you like to do?",
|
|
26912
27013
|
options: [
|
|
26913
27014
|
{
|
|
@@ -26927,17 +27028,17 @@ ${pc35.bold("Reputation Alerts")}
|
|
|
26927
27028
|
}
|
|
26928
27029
|
]
|
|
26929
27030
|
});
|
|
26930
|
-
if (
|
|
26931
|
-
|
|
27031
|
+
if (clack34.isCancel(action) || action === "cancel") {
|
|
27032
|
+
clack34.log.info("No changes made.");
|
|
26932
27033
|
process.exit(0);
|
|
26933
27034
|
}
|
|
26934
27035
|
if (action === "disconnect") {
|
|
26935
|
-
const confirmDisconnect = await
|
|
27036
|
+
const confirmDisconnect = await clack34.confirm({
|
|
26936
27037
|
message: "Are you sure? Events will no longer be sent to the Wraps Dashboard.",
|
|
26937
27038
|
initialValue: false
|
|
26938
27039
|
});
|
|
26939
|
-
if (
|
|
26940
|
-
|
|
27040
|
+
if (clack34.isCancel(confirmDisconnect) || !confirmDisconnect) {
|
|
27041
|
+
clack34.log.info("Disconnect cancelled.");
|
|
26941
27042
|
process.exit(0);
|
|
26942
27043
|
}
|
|
26943
27044
|
if (metadata.services.email) {
|
|
@@ -26949,12 +27050,12 @@ ${pc35.bold("Reputation Alerts")}
|
|
|
26949
27050
|
}
|
|
26950
27051
|
}
|
|
26951
27052
|
const webhookSecret = generateWebhookSecret();
|
|
26952
|
-
|
|
27053
|
+
clack34.log.info(`
|
|
26953
27054
|
${pc35.bold("Webhook Configuration:")}`);
|
|
26954
|
-
|
|
27055
|
+
clack34.log.info(
|
|
26955
27056
|
pc35.dim("A secure webhook secret has been generated for authentication.")
|
|
26956
27057
|
);
|
|
26957
|
-
|
|
27058
|
+
clack34.log.info(
|
|
26958
27059
|
pc35.dim(
|
|
26959
27060
|
"After deployment, you'll need to register this secret in the dashboard.\n"
|
|
26960
27061
|
)
|
|
@@ -27000,18 +27101,18 @@ ${pc35.bold("Webhook Configuration:")}`);
|
|
|
27000
27101
|
}
|
|
27001
27102
|
};
|
|
27002
27103
|
if (!config2.eventTracking?.enabled) {
|
|
27003
|
-
|
|
27104
|
+
clack34.log.warn(
|
|
27004
27105
|
"Event tracking must be enabled to configure a webhook endpoint."
|
|
27005
27106
|
);
|
|
27006
|
-
|
|
27107
|
+
clack34.log.info(
|
|
27007
27108
|
"Enabling event tracking will allow SES events to be sent to your endpoint."
|
|
27008
27109
|
);
|
|
27009
|
-
const enableEventTracking = await
|
|
27110
|
+
const enableEventTracking = await clack34.confirm({
|
|
27010
27111
|
message: "Enable event tracking now?",
|
|
27011
27112
|
initialValue: true
|
|
27012
27113
|
});
|
|
27013
|
-
if (
|
|
27014
|
-
|
|
27114
|
+
if (clack34.isCancel(enableEventTracking) || !enableEventTracking) {
|
|
27115
|
+
clack34.cancel("Webhook configuration cancelled.");
|
|
27015
27116
|
process.exit(0);
|
|
27016
27117
|
}
|
|
27017
27118
|
updatedConfig = {
|
|
@@ -27033,10 +27134,10 @@ ${pc35.bold("Webhook Configuration:")}`);
|
|
|
27033
27134
|
};
|
|
27034
27135
|
}
|
|
27035
27136
|
if (config2.userWebhook?.enabled) {
|
|
27036
|
-
|
|
27137
|
+
clack34.log.info(
|
|
27037
27138
|
`Webhook endpoint currently sending events to: ${pc35.cyan(config2.userWebhook.url)}`
|
|
27038
27139
|
);
|
|
27039
|
-
const action = await
|
|
27140
|
+
const action = await clack34.select({
|
|
27040
27141
|
message: "What would you like to do?",
|
|
27041
27142
|
options: [
|
|
27042
27143
|
{
|
|
@@ -27061,17 +27162,17 @@ ${pc35.bold("Webhook Configuration:")}`);
|
|
|
27061
27162
|
}
|
|
27062
27163
|
]
|
|
27063
27164
|
});
|
|
27064
|
-
if (
|
|
27065
|
-
|
|
27165
|
+
if (clack34.isCancel(action) || action === "cancel") {
|
|
27166
|
+
clack34.log.info("No changes made.");
|
|
27066
27167
|
process.exit(0);
|
|
27067
27168
|
}
|
|
27068
27169
|
if (action === "disable") {
|
|
27069
|
-
const confirmDisable = await
|
|
27170
|
+
const confirmDisable = await clack34.confirm({
|
|
27070
27171
|
message: "Are you sure? Events will no longer be sent to your webhook endpoint.",
|
|
27071
27172
|
initialValue: false
|
|
27072
27173
|
});
|
|
27073
|
-
if (
|
|
27074
|
-
|
|
27174
|
+
if (clack34.isCancel(confirmDisable) || !confirmDisable) {
|
|
27175
|
+
clack34.log.info("Webhook not disabled.");
|
|
27075
27176
|
process.exit(0);
|
|
27076
27177
|
}
|
|
27077
27178
|
updatedConfig = {
|
|
@@ -27082,13 +27183,13 @@ ${pc35.bold("Webhook Configuration:")}`);
|
|
|
27082
27183
|
break;
|
|
27083
27184
|
}
|
|
27084
27185
|
if (action === "change-url") {
|
|
27085
|
-
const newUrl = await
|
|
27186
|
+
const newUrl = await clack34.text({
|
|
27086
27187
|
message: "New webhook URL:",
|
|
27087
27188
|
placeholder: "https://your-app.com/webhooks/email-events",
|
|
27088
27189
|
validate: validateWebhookUrl
|
|
27089
27190
|
});
|
|
27090
|
-
if (
|
|
27091
|
-
|
|
27191
|
+
if (clack34.isCancel(newUrl)) {
|
|
27192
|
+
clack34.cancel("Webhook configuration cancelled.");
|
|
27092
27193
|
process.exit(0);
|
|
27093
27194
|
}
|
|
27094
27195
|
updatedConfig = {
|
|
@@ -27116,20 +27217,20 @@ ${pc35.bold("Webhook Configuration:")}`);
|
|
|
27116
27217
|
break;
|
|
27117
27218
|
}
|
|
27118
27219
|
} else {
|
|
27119
|
-
|
|
27220
|
+
clack34.log.info(`
|
|
27120
27221
|
${pc35.bold("Webhook Endpoint")}
|
|
27121
27222
|
`);
|
|
27122
|
-
|
|
27223
|
+
clack34.log.info(
|
|
27123
27224
|
pc35.dim("Send SES events (send, delivery, open, click, bounce, etc.)")
|
|
27124
27225
|
);
|
|
27125
|
-
|
|
27126
|
-
const webhookUrl = await
|
|
27226
|
+
clack34.log.info(pc35.dim("to your own HTTP endpoint in real-time.\n"));
|
|
27227
|
+
const webhookUrl = await clack34.text({
|
|
27127
27228
|
message: "Webhook URL (must be HTTPS):",
|
|
27128
27229
|
placeholder: "https://your-app.com/webhooks/email-events",
|
|
27129
27230
|
validate: validateWebhookUrl
|
|
27130
27231
|
});
|
|
27131
|
-
if (
|
|
27132
|
-
|
|
27232
|
+
if (clack34.isCancel(webhookUrl)) {
|
|
27233
|
+
clack34.cancel("Webhook configuration cancelled.");
|
|
27133
27234
|
process.exit(0);
|
|
27134
27235
|
}
|
|
27135
27236
|
const secret2 = generateWebhookSecret();
|
|
@@ -27147,10 +27248,10 @@ ${pc35.bold("Webhook Endpoint")}
|
|
|
27147
27248
|
}
|
|
27148
27249
|
case "smtp-credentials": {
|
|
27149
27250
|
if (metadata.services.email?.smtpCredentials?.enabled) {
|
|
27150
|
-
|
|
27251
|
+
clack34.log.info(
|
|
27151
27252
|
`SMTP credentials are currently ${pc35.green("enabled")} (created ${metadata.services.email.smtpCredentials.createdAt})`
|
|
27152
27253
|
);
|
|
27153
|
-
const smtpAction = await
|
|
27254
|
+
const smtpAction = await clack34.select({
|
|
27154
27255
|
message: "What would you like to do?",
|
|
27155
27256
|
options: [
|
|
27156
27257
|
{
|
|
@@ -27170,17 +27271,17 @@ ${pc35.bold("Webhook Endpoint")}
|
|
|
27170
27271
|
}
|
|
27171
27272
|
]
|
|
27172
27273
|
});
|
|
27173
|
-
if (
|
|
27174
|
-
|
|
27274
|
+
if (clack34.isCancel(smtpAction) || smtpAction === "cancel") {
|
|
27275
|
+
clack34.log.info("No changes made.");
|
|
27175
27276
|
process.exit(0);
|
|
27176
27277
|
}
|
|
27177
27278
|
if (smtpAction === "disable") {
|
|
27178
|
-
const confirmDisable = await
|
|
27279
|
+
const confirmDisable = await clack34.confirm({
|
|
27179
27280
|
message: "Are you sure? Any systems using these credentials will stop working immediately.",
|
|
27180
27281
|
initialValue: false
|
|
27181
27282
|
});
|
|
27182
|
-
if (
|
|
27183
|
-
|
|
27283
|
+
if (clack34.isCancel(confirmDisable) || !confirmDisable) {
|
|
27284
|
+
clack34.log.info("SMTP credentials not disabled.");
|
|
27184
27285
|
process.exit(0);
|
|
27185
27286
|
}
|
|
27186
27287
|
updatedConfig = {
|
|
@@ -27193,43 +27294,43 @@ ${pc35.bold("Webhook Endpoint")}
|
|
|
27193
27294
|
newPreset = void 0;
|
|
27194
27295
|
break;
|
|
27195
27296
|
}
|
|
27196
|
-
|
|
27297
|
+
clack34.log.info(
|
|
27197
27298
|
"\nRotating credentials will invalidate your current SMTP password."
|
|
27198
27299
|
);
|
|
27199
|
-
|
|
27300
|
+
clack34.log.warn(
|
|
27200
27301
|
"You will need to update all systems using the old credentials."
|
|
27201
27302
|
);
|
|
27202
|
-
const confirmRotate = await
|
|
27303
|
+
const confirmRotate = await clack34.confirm({
|
|
27203
27304
|
message: "Generate new SMTP credentials?",
|
|
27204
27305
|
initialValue: false
|
|
27205
27306
|
});
|
|
27206
|
-
if (
|
|
27207
|
-
|
|
27307
|
+
if (clack34.isCancel(confirmRotate) || !confirmRotate) {
|
|
27308
|
+
clack34.log.info("Credential rotation cancelled.");
|
|
27208
27309
|
process.exit(0);
|
|
27209
27310
|
}
|
|
27210
27311
|
}
|
|
27211
|
-
|
|
27312
|
+
clack34.log.info(`
|
|
27212
27313
|
${pc35.bold("SMTP Credentials for Legacy Systems")}
|
|
27213
27314
|
`);
|
|
27214
|
-
|
|
27315
|
+
clack34.log.info(
|
|
27215
27316
|
pc35.dim("Generate SMTP username/password that works with:")
|
|
27216
27317
|
);
|
|
27217
|
-
|
|
27218
|
-
|
|
27219
|
-
|
|
27220
|
-
|
|
27318
|
+
clack34.log.info(pc35.dim(" - PHP mail() and PHPMailer"));
|
|
27319
|
+
clack34.log.info(pc35.dim(" - WordPress (WP Mail SMTP plugin)"));
|
|
27320
|
+
clack34.log.info(pc35.dim(" - Nodemailer and other SMTP libraries"));
|
|
27321
|
+
clack34.log.info(pc35.dim(" - Any SMTP-compatible email client"));
|
|
27221
27322
|
console.log("");
|
|
27222
|
-
|
|
27323
|
+
clack34.log.warn(
|
|
27223
27324
|
"Credentials will be shown ONCE after deployment - save them immediately!"
|
|
27224
27325
|
);
|
|
27225
27326
|
console.log("");
|
|
27226
27327
|
if (!options.yes) {
|
|
27227
|
-
const confirmCreate = await
|
|
27328
|
+
const confirmCreate = await clack34.confirm({
|
|
27228
27329
|
message: "Create SMTP credentials?",
|
|
27229
27330
|
initialValue: true
|
|
27230
27331
|
});
|
|
27231
|
-
if (
|
|
27232
|
-
|
|
27332
|
+
if (clack34.isCancel(confirmCreate) || !confirmCreate) {
|
|
27333
|
+
clack34.log.info("SMTP credentials not created.");
|
|
27233
27334
|
process.exit(0);
|
|
27234
27335
|
}
|
|
27235
27336
|
}
|
|
@@ -27244,7 +27345,7 @@ ${pc35.bold("SMTP Credentials for Legacy Systems")}
|
|
|
27244
27345
|
break;
|
|
27245
27346
|
}
|
|
27246
27347
|
case "hosting-provider": {
|
|
27247
|
-
const newProvider = await
|
|
27348
|
+
const newProvider = await clack34.select({
|
|
27248
27349
|
message: "Where is your app hosted?",
|
|
27249
27350
|
options: [
|
|
27250
27351
|
{
|
|
@@ -27269,12 +27370,12 @@ ${pc35.bold("SMTP Credentials for Legacy Systems")}
|
|
|
27269
27370
|
}
|
|
27270
27371
|
]
|
|
27271
27372
|
});
|
|
27272
|
-
if (
|
|
27273
|
-
|
|
27373
|
+
if (clack34.isCancel(newProvider)) {
|
|
27374
|
+
clack34.cancel("Upgrade cancelled.");
|
|
27274
27375
|
process.exit(0);
|
|
27275
27376
|
}
|
|
27276
27377
|
if (newProvider === metadata.provider) {
|
|
27277
|
-
|
|
27378
|
+
clack34.log.info("Provider unchanged \u2014 no changes needed.");
|
|
27278
27379
|
process.exit(0);
|
|
27279
27380
|
}
|
|
27280
27381
|
metadata.provider = newProvider;
|
|
@@ -27305,12 +27406,12 @@ ${pc35.bold("Cost Impact:")}`);
|
|
|
27305
27406
|
}
|
|
27306
27407
|
console.log("");
|
|
27307
27408
|
if (!(options.yes || options.preview)) {
|
|
27308
|
-
const confirmed = await
|
|
27409
|
+
const confirmed = await clack34.confirm({
|
|
27309
27410
|
message: "Proceed with upgrade?",
|
|
27310
27411
|
initialValue: true
|
|
27311
27412
|
});
|
|
27312
|
-
if (
|
|
27313
|
-
|
|
27413
|
+
if (clack34.isCancel(confirmed) || !confirmed) {
|
|
27414
|
+
clack34.cancel("Upgrade cancelled.");
|
|
27314
27415
|
process.exit(0);
|
|
27315
27416
|
}
|
|
27316
27417
|
}
|
|
@@ -27357,15 +27458,15 @@ ${pc35.bold("Cost Impact:")}`);
|
|
|
27357
27458
|
);
|
|
27358
27459
|
await new Promise((resolve) => setTimeout(resolve, 2e3));
|
|
27359
27460
|
} else if (!caaResult.success) {
|
|
27360
|
-
|
|
27461
|
+
clack34.log.warn(
|
|
27361
27462
|
`Could not verify CAA records: ${caaResult.error || "Unknown error"}`
|
|
27362
27463
|
);
|
|
27363
|
-
|
|
27464
|
+
clack34.log.info(
|
|
27364
27465
|
pc35.dim(
|
|
27365
27466
|
"If certificate issuance fails, you may need to add a CAA record manually:"
|
|
27366
27467
|
)
|
|
27367
27468
|
);
|
|
27368
|
-
|
|
27469
|
+
clack34.log.info(pc35.dim(` ${parentDomain} CAA 0 issue "amazon.com"`));
|
|
27369
27470
|
}
|
|
27370
27471
|
}
|
|
27371
27472
|
}
|
|
@@ -27429,7 +27530,7 @@ ${pc35.bold("Cost Impact:")}`);
|
|
|
27429
27530
|
costEstimate: costComparison,
|
|
27430
27531
|
commandName: "wraps email upgrade"
|
|
27431
27532
|
});
|
|
27432
|
-
|
|
27533
|
+
clack34.outro(
|
|
27433
27534
|
pc35.green("Preview complete. Run without --preview to upgrade.")
|
|
27434
27535
|
);
|
|
27435
27536
|
trackServiceUpgrade("email", {
|
|
@@ -27607,7 +27708,7 @@ ${pc35.bold("Cost Impact:")}`);
|
|
|
27607
27708
|
);
|
|
27608
27709
|
}
|
|
27609
27710
|
} else {
|
|
27610
|
-
|
|
27711
|
+
clack34.log.warn(
|
|
27611
27712
|
credResult.error || `Unable to validate ${getDNSProviderDisplayName(dnsProvider)} credentials`
|
|
27612
27713
|
);
|
|
27613
27714
|
}
|
|
@@ -27623,7 +27724,7 @@ ${pc35.bold("Cost Impact:")}`);
|
|
|
27623
27724
|
};
|
|
27624
27725
|
const dnsRecords = buildEmailDNSRecords(dnsData);
|
|
27625
27726
|
console.log();
|
|
27626
|
-
|
|
27727
|
+
clack34.note(
|
|
27627
27728
|
formatManualDNSInstructions(dnsRecords),
|
|
27628
27729
|
"DNS Records \u2014 Add these to your DNS provider"
|
|
27629
27730
|
);
|
|
@@ -27933,7 +28034,7 @@ init_output();
|
|
|
27933
28034
|
import { existsSync as existsSync14 } from "fs";
|
|
27934
28035
|
import { mkdir as mkdir7, readFile as readFile7, writeFile as writeFile9 } from "fs/promises";
|
|
27935
28036
|
import { join as join16 } from "path";
|
|
27936
|
-
import * as
|
|
28037
|
+
import * as clack35 from "@clack/prompts";
|
|
27937
28038
|
import pc36 from "picocolors";
|
|
27938
28039
|
|
|
27939
28040
|
// src/commands/email/workflows/claude-content.ts
|
|
@@ -28325,7 +28426,7 @@ async function workflowsInit(options) {
|
|
|
28325
28426
|
const cwd = process.cwd();
|
|
28326
28427
|
const workflowsDir = join16(cwd, "wraps", "workflows");
|
|
28327
28428
|
if (!isJsonMode()) {
|
|
28328
|
-
|
|
28429
|
+
clack35.intro(pc36.bold("Workflows as Code"));
|
|
28329
28430
|
}
|
|
28330
28431
|
const progress = new DeploymentProgress();
|
|
28331
28432
|
if (existsSync14(workflowsDir) && !options.force) {
|
|
@@ -28335,7 +28436,7 @@ async function workflowsInit(options) {
|
|
|
28335
28436
|
(f) => f.endsWith(".ts") && !f.startsWith("_")
|
|
28336
28437
|
);
|
|
28337
28438
|
if (tsFiles.length > 0 && !options.force && !isJsonMode()) {
|
|
28338
|
-
|
|
28439
|
+
clack35.log.warn(
|
|
28339
28440
|
`${pc36.cyan("wraps/workflows/")} already contains ${tsFiles.length} workflow file(s). Use ${pc36.bold("--force")} to overwrite.`
|
|
28340
28441
|
);
|
|
28341
28442
|
}
|
|
@@ -28402,7 +28503,7 @@ async function workflowsInit(options) {
|
|
|
28402
28503
|
return;
|
|
28403
28504
|
}
|
|
28404
28505
|
console.log();
|
|
28405
|
-
|
|
28506
|
+
clack35.log.success(pc36.green("Workflows as Code initialized!"));
|
|
28406
28507
|
console.log();
|
|
28407
28508
|
console.log(` ${pc36.dim("Directory:")} ${pc36.cyan("wraps/workflows/")}`);
|
|
28408
28509
|
if (!options.noExample) {
|
|
@@ -28445,7 +28546,7 @@ init_esm_shims();
|
|
|
28445
28546
|
init_events();
|
|
28446
28547
|
import { existsSync as existsSync16 } from "fs";
|
|
28447
28548
|
import { join as join18 } from "path";
|
|
28448
|
-
import * as
|
|
28549
|
+
import * as clack36 from "@clack/prompts";
|
|
28449
28550
|
import pc37 from "picocolors";
|
|
28450
28551
|
|
|
28451
28552
|
// src/utils/email/workflow-transform.ts
|
|
@@ -29296,7 +29397,7 @@ async function workflowsPush(options) {
|
|
|
29296
29397
|
throw errors.wrapsConfigNotFound();
|
|
29297
29398
|
}
|
|
29298
29399
|
if (!isJsonMode()) {
|
|
29299
|
-
|
|
29400
|
+
clack36.intro(pc37.bold("Push Workflows"));
|
|
29300
29401
|
}
|
|
29301
29402
|
const progress = new DeploymentProgress();
|
|
29302
29403
|
progress.start("Loading configuration");
|
|
@@ -29311,7 +29412,7 @@ async function workflowsPush(options) {
|
|
|
29311
29412
|
errors: []
|
|
29312
29413
|
});
|
|
29313
29414
|
} else {
|
|
29314
|
-
|
|
29415
|
+
clack36.log.info("No workflows/ directory found.");
|
|
29315
29416
|
}
|
|
29316
29417
|
return;
|
|
29317
29418
|
}
|
|
@@ -29324,7 +29425,7 @@ async function workflowsPush(options) {
|
|
|
29324
29425
|
errors: []
|
|
29325
29426
|
});
|
|
29326
29427
|
} else {
|
|
29327
|
-
|
|
29428
|
+
clack36.log.info("No workflows found to push.");
|
|
29328
29429
|
}
|
|
29329
29430
|
return;
|
|
29330
29431
|
}
|
|
@@ -29393,7 +29494,7 @@ async function workflowsPush(options) {
|
|
|
29393
29494
|
});
|
|
29394
29495
|
} else {
|
|
29395
29496
|
console.log();
|
|
29396
|
-
|
|
29497
|
+
clack36.log.error(
|
|
29397
29498
|
pc37.red("Cannot push due to validation errors. Fix errors and retry.")
|
|
29398
29499
|
);
|
|
29399
29500
|
console.log();
|
|
@@ -29408,7 +29509,7 @@ async function workflowsPush(options) {
|
|
|
29408
29509
|
errors: []
|
|
29409
29510
|
});
|
|
29410
29511
|
} else {
|
|
29411
|
-
|
|
29512
|
+
clack36.log.info(
|
|
29412
29513
|
`${unchanged.length} workflow(s) unchanged. Use --force to re-push.`
|
|
29413
29514
|
);
|
|
29414
29515
|
}
|
|
@@ -29429,7 +29530,7 @@ async function workflowsPush(options) {
|
|
|
29429
29530
|
});
|
|
29430
29531
|
} else {
|
|
29431
29532
|
console.log();
|
|
29432
|
-
|
|
29533
|
+
clack36.log.info(pc37.bold("Dry run \u2014 no changes made"));
|
|
29433
29534
|
console.log();
|
|
29434
29535
|
for (const w of toProcess) {
|
|
29435
29536
|
console.log(
|
|
@@ -29486,20 +29587,20 @@ async function workflowsPush(options) {
|
|
|
29486
29587
|
} else {
|
|
29487
29588
|
console.log();
|
|
29488
29589
|
if (enabled.length > 0) {
|
|
29489
|
-
|
|
29590
|
+
clack36.log.success(
|
|
29490
29591
|
pc37.green(`${enabled.length} workflow(s) pushed and enabled`)
|
|
29491
29592
|
);
|
|
29492
29593
|
}
|
|
29493
29594
|
if (drafts.length > 0) {
|
|
29494
|
-
|
|
29595
|
+
clack36.log.success(
|
|
29495
29596
|
pc37.green(`${drafts.length} workflow(s) pushed as draft`)
|
|
29496
29597
|
);
|
|
29497
29598
|
}
|
|
29498
29599
|
if (unchanged.length > 0) {
|
|
29499
|
-
|
|
29600
|
+
clack36.log.info(`${unchanged.length} unchanged (use --force to re-push)`);
|
|
29500
29601
|
}
|
|
29501
29602
|
if (conflicts.length > 0) {
|
|
29502
|
-
|
|
29603
|
+
clack36.log.error(
|
|
29503
29604
|
`${conflicts.length} workflow(s) skipped due to dashboard edits. Use --force to overwrite.`
|
|
29504
29605
|
);
|
|
29505
29606
|
for (const c of conflicts) {
|
|
@@ -29663,7 +29764,7 @@ init_esm_shims();
|
|
|
29663
29764
|
init_events();
|
|
29664
29765
|
import { existsSync as existsSync17 } from "fs";
|
|
29665
29766
|
import { join as join19 } from "path";
|
|
29666
|
-
import * as
|
|
29767
|
+
import * as clack37 from "@clack/prompts";
|
|
29667
29768
|
import pc38 from "picocolors";
|
|
29668
29769
|
init_errors();
|
|
29669
29770
|
init_json_output();
|
|
@@ -29677,7 +29778,7 @@ async function workflowsValidate(options) {
|
|
|
29677
29778
|
throw errors.wrapsConfigNotFound();
|
|
29678
29779
|
}
|
|
29679
29780
|
if (!isJsonMode()) {
|
|
29680
|
-
|
|
29781
|
+
clack37.intro(pc38.bold("Validate Workflows"));
|
|
29681
29782
|
}
|
|
29682
29783
|
const progress = new DeploymentProgress();
|
|
29683
29784
|
progress.start("Loading configuration");
|
|
@@ -29688,7 +29789,7 @@ async function workflowsValidate(options) {
|
|
|
29688
29789
|
if (isJsonMode()) {
|
|
29689
29790
|
jsonSuccess("email.workflows.validate", { workflows: [], errors: [] });
|
|
29690
29791
|
} else {
|
|
29691
|
-
|
|
29792
|
+
clack37.log.info("No workflows/ directory found.");
|
|
29692
29793
|
}
|
|
29693
29794
|
return;
|
|
29694
29795
|
}
|
|
@@ -29697,7 +29798,7 @@ async function workflowsValidate(options) {
|
|
|
29697
29798
|
if (isJsonMode()) {
|
|
29698
29799
|
jsonSuccess("email.workflows.validate", { workflows: [], errors: [] });
|
|
29699
29800
|
} else {
|
|
29700
|
-
|
|
29801
|
+
clack37.log.info("No workflows found to validate.");
|
|
29701
29802
|
}
|
|
29702
29803
|
return;
|
|
29703
29804
|
}
|
|
@@ -29774,18 +29875,18 @@ async function workflowsValidate(options) {
|
|
|
29774
29875
|
const invalidCount = validationResults.filter((r) => !r.valid).length;
|
|
29775
29876
|
const parseErrorCount = parseErrors.length;
|
|
29776
29877
|
if (parseErrorCount === 0 && invalidCount === 0) {
|
|
29777
|
-
|
|
29878
|
+
clack37.log.success(
|
|
29778
29879
|
pc38.green(`${validCount} workflow(s) validated successfully`)
|
|
29779
29880
|
);
|
|
29780
29881
|
} else {
|
|
29781
29882
|
if (validCount > 0) {
|
|
29782
|
-
|
|
29883
|
+
clack37.log.success(pc38.green(`${validCount} workflow(s) valid`));
|
|
29783
29884
|
}
|
|
29784
29885
|
if (invalidCount > 0) {
|
|
29785
|
-
|
|
29886
|
+
clack37.log.error(pc38.red(`${invalidCount} workflow(s) have errors`));
|
|
29786
29887
|
}
|
|
29787
29888
|
if (parseErrorCount > 0) {
|
|
29788
|
-
|
|
29889
|
+
clack37.log.error(
|
|
29789
29890
|
pc38.red(`${parseErrorCount} workflow(s) failed to parse`)
|
|
29790
29891
|
);
|
|
29791
29892
|
}
|
|
@@ -29819,11 +29920,11 @@ async function workflowsValidate(options) {
|
|
|
29819
29920
|
// src/commands/news.ts
|
|
29820
29921
|
init_esm_shims();
|
|
29821
29922
|
init_events();
|
|
29822
|
-
import * as
|
|
29923
|
+
import * as clack38 from "@clack/prompts";
|
|
29823
29924
|
import pc39 from "picocolors";
|
|
29824
29925
|
async function news() {
|
|
29825
29926
|
trackCommand("news", { success: true });
|
|
29826
|
-
|
|
29927
|
+
clack38.intro(pc39.bold("What's New in Wraps"));
|
|
29827
29928
|
console.log();
|
|
29828
29929
|
console.log(" See the latest updates, features, and improvements:");
|
|
29829
29930
|
console.log();
|
|
@@ -29839,7 +29940,7 @@ async function news() {
|
|
|
29839
29940
|
init_esm_shims();
|
|
29840
29941
|
init_events();
|
|
29841
29942
|
init_json_output();
|
|
29842
|
-
import * as
|
|
29943
|
+
import * as clack39 from "@clack/prompts";
|
|
29843
29944
|
import pc40 from "picocolors";
|
|
29844
29945
|
function getBaseStatements() {
|
|
29845
29946
|
return [
|
|
@@ -30231,7 +30332,7 @@ function buildPolicy(service, preset) {
|
|
|
30231
30332
|
};
|
|
30232
30333
|
}
|
|
30233
30334
|
function displaySummary(service, preset) {
|
|
30234
|
-
|
|
30335
|
+
clack39.intro(pc40.bold("Wraps Required AWS Permissions"));
|
|
30235
30336
|
const serviceLabel = service ? service.toUpperCase() : "All Services";
|
|
30236
30337
|
const presetLabel = preset ? preset.charAt(0).toUpperCase() + preset.slice(1) : "All Features";
|
|
30237
30338
|
console.log(`
|
|
@@ -30325,7 +30426,7 @@ async function permissions(options) {
|
|
|
30325
30426
|
console.log("2. Create the policy in AWS Console:");
|
|
30326
30427
|
console.log(" IAM > Policies > Create Policy > JSON\n");
|
|
30327
30428
|
console.log("3. Attach to your IAM user/role\n");
|
|
30328
|
-
|
|
30429
|
+
clack39.outro(
|
|
30329
30430
|
pc40.green("Run with --json to get the full IAM policy document")
|
|
30330
30431
|
);
|
|
30331
30432
|
}
|
|
@@ -30343,7 +30444,7 @@ import {
|
|
|
30343
30444
|
IAMClient as IAMClient3,
|
|
30344
30445
|
PutRolePolicyCommand
|
|
30345
30446
|
} from "@aws-sdk/client-iam";
|
|
30346
|
-
import { confirm as confirm18, intro as intro34, isCancel as
|
|
30447
|
+
import { confirm as confirm18, intro as intro34, isCancel as isCancel25, log as log36, outro as outro20, select as select17 } from "@clack/prompts";
|
|
30347
30448
|
import * as pulumi24 from "@pulumi/pulumi";
|
|
30348
30449
|
import pc41 from "picocolors";
|
|
30349
30450
|
init_events();
|
|
@@ -30356,6 +30457,7 @@ init_metadata();
|
|
|
30356
30457
|
init_output();
|
|
30357
30458
|
init_prompts();
|
|
30358
30459
|
init_pulumi();
|
|
30460
|
+
init_region_resolver();
|
|
30359
30461
|
function buildConsolePolicyDocument(emailConfig, smsConfig) {
|
|
30360
30462
|
const statements = [];
|
|
30361
30463
|
statements.push({
|
|
@@ -30532,10 +30634,11 @@ async function validateAndLoadMetadata(options, progress) {
|
|
|
30532
30634
|
async () => validateAWSCredentials()
|
|
30533
30635
|
);
|
|
30534
30636
|
progress.info(`Connected to AWS account: ${pc41.cyan(identity.accountId)}`);
|
|
30535
|
-
|
|
30536
|
-
|
|
30537
|
-
region
|
|
30538
|
-
|
|
30637
|
+
const region = await resolveRegionForCommand({
|
|
30638
|
+
accountId: identity.accountId,
|
|
30639
|
+
optionRegion: options.region,
|
|
30640
|
+
label: "connection"
|
|
30641
|
+
});
|
|
30539
30642
|
const metadata = await loadConnectionMetadata(identity.accountId, region);
|
|
30540
30643
|
if (!metadata) {
|
|
30541
30644
|
progress.stop();
|
|
@@ -30694,7 +30797,7 @@ async function resolveOrganization() {
|
|
|
30694
30797
|
if (orgs.length === 1) {
|
|
30695
30798
|
return orgs[0];
|
|
30696
30799
|
}
|
|
30697
|
-
const selected = await
|
|
30800
|
+
const selected = await select17({
|
|
30698
30801
|
message: "Which organization should this AWS account connect to?",
|
|
30699
30802
|
options: orgs.map((org) => ({
|
|
30700
30803
|
value: org.id,
|
|
@@ -30702,7 +30805,7 @@ async function resolveOrganization() {
|
|
|
30702
30805
|
hint: org.slug
|
|
30703
30806
|
}))
|
|
30704
30807
|
});
|
|
30705
|
-
if (
|
|
30808
|
+
if (isCancel25(selected)) {
|
|
30706
30809
|
outro20("Operation cancelled");
|
|
30707
30810
|
process.exit(0);
|
|
30708
30811
|
}
|
|
@@ -30768,7 +30871,7 @@ async function authenticatedConnect(token, options) {
|
|
|
30768
30871
|
message: "Enable event tracking now?",
|
|
30769
30872
|
initialValue: true
|
|
30770
30873
|
});
|
|
30771
|
-
if (
|
|
30874
|
+
if (isCancel25(enableTracking) || !enableTracking) {
|
|
30772
30875
|
outro20("Platform connection cancelled.");
|
|
30773
30876
|
process.exit(0);
|
|
30774
30877
|
}
|
|
@@ -30913,10 +31016,11 @@ async function connect3(options) {
|
|
|
30913
31016
|
async () => validateAWSCredentials()
|
|
30914
31017
|
);
|
|
30915
31018
|
progress.info(`Connected to AWS account: ${pc41.cyan(identity.accountId)}`);
|
|
30916
|
-
|
|
30917
|
-
|
|
30918
|
-
region
|
|
30919
|
-
|
|
31019
|
+
const region = await resolveRegionForCommand({
|
|
31020
|
+
accountId: identity.accountId,
|
|
31021
|
+
optionRegion: options.region,
|
|
31022
|
+
label: "connection"
|
|
31023
|
+
});
|
|
30920
31024
|
const metadata = await loadConnectionMetadata(identity.accountId, region);
|
|
30921
31025
|
if (!metadata) {
|
|
30922
31026
|
progress.stop();
|
|
@@ -30962,7 +31066,7 @@ Run ${pc41.cyan("wraps email init")} or ${pc41.cyan("wraps sms init")} first.
|
|
|
30962
31066
|
message: "Enable event tracking now?",
|
|
30963
31067
|
initialValue: true
|
|
30964
31068
|
});
|
|
30965
|
-
if (
|
|
31069
|
+
if (isCancel25(enableEventTracking) || !enableEventTracking) {
|
|
30966
31070
|
outro20("Platform connection cancelled.");
|
|
30967
31071
|
process.exit(0);
|
|
30968
31072
|
}
|
|
@@ -30990,7 +31094,7 @@ Run ${pc41.cyan("wraps email init")} or ${pc41.cyan("wraps sms init")} first.
|
|
|
30990
31094
|
log36.info(
|
|
30991
31095
|
`Already connected to Wraps Platform (AWS Account: ${pc41.cyan(metadata.accountId)})`
|
|
30992
31096
|
);
|
|
30993
|
-
const action = await
|
|
31097
|
+
const action = await select17({
|
|
30994
31098
|
message: "What would you like to do?",
|
|
30995
31099
|
options: [
|
|
30996
31100
|
{
|
|
@@ -31010,7 +31114,7 @@ Run ${pc41.cyan("wraps email init")} or ${pc41.cyan("wraps sms init")} first.
|
|
|
31010
31114
|
}
|
|
31011
31115
|
]
|
|
31012
31116
|
});
|
|
31013
|
-
if (
|
|
31117
|
+
if (isCancel25(action)) {
|
|
31014
31118
|
outro20("Operation cancelled");
|
|
31015
31119
|
process.exit(0);
|
|
31016
31120
|
}
|
|
@@ -31021,7 +31125,7 @@ Run ${pc41.cyan("wraps email init")} or ${pc41.cyan("wraps sms init")} first.
|
|
|
31021
31125
|
message: "Are you sure? Events will no longer be sent to the Wraps Platform.",
|
|
31022
31126
|
initialValue: false
|
|
31023
31127
|
});
|
|
31024
|
-
if (
|
|
31128
|
+
if (isCancel25(confirmDisconnect) || !confirmDisconnect) {
|
|
31025
31129
|
outro20("Disconnect cancelled");
|
|
31026
31130
|
process.exit(0);
|
|
31027
31131
|
}
|
|
@@ -31171,10 +31275,10 @@ ${pc41.bold("Next Steps:")}`);
|
|
|
31171
31275
|
|
|
31172
31276
|
// src/commands/platform/index.ts
|
|
31173
31277
|
init_esm_shims();
|
|
31174
|
-
import * as
|
|
31278
|
+
import * as clack40 from "@clack/prompts";
|
|
31175
31279
|
import pc42 from "picocolors";
|
|
31176
31280
|
async function platform() {
|
|
31177
|
-
|
|
31281
|
+
clack40.intro(pc42.bold("Wraps Platform"));
|
|
31178
31282
|
console.log();
|
|
31179
31283
|
console.log(
|
|
31180
31284
|
" The Wraps Platform extends the free CLI with hosted features:"
|
|
@@ -31227,12 +31331,13 @@ init_aws();
|
|
|
31227
31331
|
init_json_output();
|
|
31228
31332
|
init_metadata();
|
|
31229
31333
|
init_output();
|
|
31334
|
+
init_region_resolver();
|
|
31230
31335
|
import {
|
|
31231
31336
|
CreateRoleCommand as CreateRoleCommand2,
|
|
31232
31337
|
GetRoleCommand as GetRoleCommand2,
|
|
31233
31338
|
IAMClient as IAMClient4
|
|
31234
31339
|
} from "@aws-sdk/client-iam";
|
|
31235
|
-
import { confirm as confirm19, intro as intro36, isCancel as
|
|
31340
|
+
import { confirm as confirm19, intro as intro36, isCancel as isCancel26, log as log37, outro as outro21 } from "@clack/prompts";
|
|
31236
31341
|
import pc43 from "picocolors";
|
|
31237
31342
|
async function updateRole(options) {
|
|
31238
31343
|
const startTime = Date.now();
|
|
@@ -31244,7 +31349,11 @@ async function updateRole(options) {
|
|
|
31244
31349
|
"Validating AWS credentials",
|
|
31245
31350
|
async () => validateAWSCredentials()
|
|
31246
31351
|
);
|
|
31247
|
-
const region =
|
|
31352
|
+
const region = await resolveRegionForCommand({
|
|
31353
|
+
accountId: identity.accountId,
|
|
31354
|
+
optionRegion: options.region,
|
|
31355
|
+
label: "connection"
|
|
31356
|
+
});
|
|
31248
31357
|
const metadata = await loadConnectionMetadata(identity.accountId, region);
|
|
31249
31358
|
if (!metadata) {
|
|
31250
31359
|
progress.stop();
|
|
@@ -31297,7 +31406,7 @@ Run ${pc43.cyan("wraps email init")} to deploy infrastructure first.
|
|
|
31297
31406
|
message: `${actionLabel} IAM role ${pc43.cyan(roleName)} with latest permissions?`,
|
|
31298
31407
|
initialValue: true
|
|
31299
31408
|
});
|
|
31300
|
-
if (
|
|
31409
|
+
if (isCancel26(shouldContinue) || !shouldContinue) {
|
|
31301
31410
|
outro21(`${actionLabel} cancelled`);
|
|
31302
31411
|
process.exit(0);
|
|
31303
31412
|
}
|
|
@@ -31616,7 +31725,7 @@ function buildConsolePolicyDocument2(emailConfig, smsConfig) {
|
|
|
31616
31725
|
|
|
31617
31726
|
// src/commands/shared/dashboard.ts
|
|
31618
31727
|
init_esm_shims();
|
|
31619
|
-
import * as
|
|
31728
|
+
import * as clack41 from "@clack/prompts";
|
|
31620
31729
|
import * as pulumi25 from "@pulumi/pulumi";
|
|
31621
31730
|
import getPort from "get-port";
|
|
31622
31731
|
import open2 from "open";
|
|
@@ -34267,7 +34376,7 @@ init_output();
|
|
|
34267
34376
|
init_pulumi();
|
|
34268
34377
|
async function dashboard(options) {
|
|
34269
34378
|
await ensurePulumiInstalled();
|
|
34270
|
-
|
|
34379
|
+
clack41.intro(pc44.bold("Wraps Dashboard"));
|
|
34271
34380
|
const progress = new DeploymentProgress();
|
|
34272
34381
|
const identity = await progress.execute(
|
|
34273
34382
|
"Validating AWS credentials",
|
|
@@ -34308,7 +34417,7 @@ async function dashboard(options) {
|
|
|
34308
34417
|
}
|
|
34309
34418
|
} catch (_error) {
|
|
34310
34419
|
progress.stop();
|
|
34311
|
-
|
|
34420
|
+
clack41.log.error("No Wraps infrastructure found");
|
|
34312
34421
|
console.log(
|
|
34313
34422
|
`\\nRun ${pc44.cyan("wraps email init")}, ${pc44.cyan("wraps sms init")}, or ${pc44.cyan("wraps storage init")} to deploy infrastructure first.\\n`
|
|
34314
34423
|
);
|
|
@@ -34352,7 +34461,7 @@ async function dashboard(options) {
|
|
|
34352
34461
|
}
|
|
34353
34462
|
const port = options.port || await getPort({ port: [5555, 5556, 5557, 5558, 5559] });
|
|
34354
34463
|
progress.stop();
|
|
34355
|
-
|
|
34464
|
+
clack41.log.success("Starting dashboard server...");
|
|
34356
34465
|
console.log(
|
|
34357
34466
|
`${pc44.dim("Using current AWS credentials (no role assumption)")}\\n`
|
|
34358
34467
|
);
|
|
@@ -34409,7 +34518,7 @@ init_aws();
|
|
|
34409
34518
|
init_errors();
|
|
34410
34519
|
init_json_output();
|
|
34411
34520
|
init_metadata();
|
|
34412
|
-
import * as
|
|
34521
|
+
import * as clack42 from "@clack/prompts";
|
|
34413
34522
|
import pc45 from "picocolors";
|
|
34414
34523
|
async function destroy(options) {
|
|
34415
34524
|
trackCommand("destroy", { success: true });
|
|
@@ -34421,9 +34530,9 @@ async function destroy(options) {
|
|
|
34421
34530
|
);
|
|
34422
34531
|
}
|
|
34423
34532
|
if (!isJsonMode()) {
|
|
34424
|
-
|
|
34533
|
+
clack42.intro(pc45.bold("Wraps Infrastructure Teardown"));
|
|
34425
34534
|
}
|
|
34426
|
-
const spinner10 =
|
|
34535
|
+
const spinner10 = clack42.spinner();
|
|
34427
34536
|
spinner10.start("Validating AWS credentials");
|
|
34428
34537
|
let identity;
|
|
34429
34538
|
try {
|
|
@@ -34440,7 +34549,7 @@ async function destroy(options) {
|
|
|
34440
34549
|
deployedServices.push("email");
|
|
34441
34550
|
}
|
|
34442
34551
|
if (deployedServices.length === 0) {
|
|
34443
|
-
|
|
34552
|
+
clack42.log.warn("No Wraps services found in this region");
|
|
34444
34553
|
console.log(
|
|
34445
34554
|
`
|
|
34446
34555
|
Run ${pc45.cyan("wraps email init")} to deploy infrastructure.
|
|
@@ -34450,7 +34559,7 @@ Run ${pc45.cyan("wraps email init")} to deploy infrastructure.
|
|
|
34450
34559
|
}
|
|
34451
34560
|
if (deployedServices.length === 1) {
|
|
34452
34561
|
const service = deployedServices[0];
|
|
34453
|
-
|
|
34562
|
+
clack42.log.info(`Found ${pc45.cyan(service)} service deployed`);
|
|
34454
34563
|
if (service === "email") {
|
|
34455
34564
|
await emailDestroy(options);
|
|
34456
34565
|
return;
|
|
@@ -34465,7 +34574,7 @@ Run ${pc45.cyan("wraps email init")} to deploy infrastructure.
|
|
|
34465
34574
|
jsonSuccess("destroy", { destroyed: true });
|
|
34466
34575
|
return;
|
|
34467
34576
|
}
|
|
34468
|
-
const serviceToDestroy = await
|
|
34577
|
+
const serviceToDestroy = await clack42.select({
|
|
34469
34578
|
message: "Which service would you like to destroy?",
|
|
34470
34579
|
options: [
|
|
34471
34580
|
...deployedServices.map((s) => ({
|
|
@@ -34480,15 +34589,15 @@ Run ${pc45.cyan("wraps email init")} to deploy infrastructure.
|
|
|
34480
34589
|
}
|
|
34481
34590
|
]
|
|
34482
34591
|
});
|
|
34483
|
-
if (
|
|
34484
|
-
|
|
34592
|
+
if (clack42.isCancel(serviceToDestroy)) {
|
|
34593
|
+
clack42.cancel("Operation cancelled.");
|
|
34485
34594
|
process.exit(0);
|
|
34486
34595
|
}
|
|
34487
34596
|
if ((serviceToDestroy === "email" || serviceToDestroy === "all") && deployedServices.includes("email")) {
|
|
34488
34597
|
await emailDestroy(options);
|
|
34489
34598
|
}
|
|
34490
34599
|
if (serviceToDestroy === "all") {
|
|
34491
|
-
|
|
34600
|
+
clack42.outro(pc45.green("All Wraps infrastructure has been removed"));
|
|
34492
34601
|
}
|
|
34493
34602
|
}
|
|
34494
34603
|
|
|
@@ -34500,7 +34609,7 @@ init_fs();
|
|
|
34500
34609
|
init_json_output();
|
|
34501
34610
|
init_output();
|
|
34502
34611
|
init_pulumi();
|
|
34503
|
-
import * as
|
|
34612
|
+
import * as clack43 from "@clack/prompts";
|
|
34504
34613
|
import * as pulumi26 from "@pulumi/pulumi";
|
|
34505
34614
|
import pc46 from "picocolors";
|
|
34506
34615
|
async function status(_options) {
|
|
@@ -34508,7 +34617,7 @@ async function status(_options) {
|
|
|
34508
34617
|
const startTime = Date.now();
|
|
34509
34618
|
const progress = new DeploymentProgress();
|
|
34510
34619
|
if (!isJsonMode()) {
|
|
34511
|
-
|
|
34620
|
+
clack43.intro(pc46.bold("Wraps Infrastructure Status"));
|
|
34512
34621
|
}
|
|
34513
34622
|
const identity = await progress.execute(
|
|
34514
34623
|
"Loading infrastructure status",
|
|
@@ -34571,7 +34680,7 @@ async function status(_options) {
|
|
|
34571
34680
|
return;
|
|
34572
34681
|
}
|
|
34573
34682
|
console.log();
|
|
34574
|
-
|
|
34683
|
+
clack43.note(
|
|
34575
34684
|
services.map((s) => {
|
|
34576
34685
|
if (s.status === "deployed") {
|
|
34577
34686
|
const details = s.details ? pc46.dim(` (${s.details})`) : "";
|
|
@@ -34610,13 +34719,12 @@ ${pc46.bold("Dashboard:")} ${pc46.blue("https://app.wraps.dev")}`);
|
|
|
34610
34719
|
|
|
34611
34720
|
// src/commands/sms/destroy.ts
|
|
34612
34721
|
init_esm_shims();
|
|
34613
|
-
import * as
|
|
34722
|
+
import * as clack44 from "@clack/prompts";
|
|
34614
34723
|
import * as pulumi28 from "@pulumi/pulumi";
|
|
34615
34724
|
import pc47 from "picocolors";
|
|
34616
34725
|
|
|
34617
34726
|
// src/infrastructure/sms-stack.ts
|
|
34618
34727
|
init_esm_shims();
|
|
34619
|
-
init_constants();
|
|
34620
34728
|
import * as aws20 from "@pulumi/aws";
|
|
34621
34729
|
import * as pulumi27 from "@pulumi/pulumi";
|
|
34622
34730
|
init_resource_checks();
|
|
@@ -34732,12 +34840,10 @@ function createSMSOptOutList() {
|
|
|
34732
34840
|
}
|
|
34733
34841
|
});
|
|
34734
34842
|
}
|
|
34735
|
-
async function findExistingPhoneNumber(phoneNumberType) {
|
|
34843
|
+
async function findExistingPhoneNumber(phoneNumberType, region) {
|
|
34736
34844
|
try {
|
|
34737
34845
|
const { PinpointSMSVoiceV2Client: PinpointSMSVoiceV2Client5, DescribePhoneNumbersCommand: DescribePhoneNumbersCommand2 } = await import("@aws-sdk/client-pinpoint-sms-voice-v2");
|
|
34738
|
-
const client = new PinpointSMSVoiceV2Client5({
|
|
34739
|
-
region: getDefaultRegion()
|
|
34740
|
-
});
|
|
34846
|
+
const client = new PinpointSMSVoiceV2Client5({ region });
|
|
34741
34847
|
const numberTypeMap = {
|
|
34742
34848
|
simulator: "SIMULATOR",
|
|
34743
34849
|
"toll-free": "TOLL_FREE",
|
|
@@ -34771,14 +34877,14 @@ async function findExistingPhoneNumber(phoneNumberType) {
|
|
|
34771
34877
|
throw error;
|
|
34772
34878
|
}
|
|
34773
34879
|
}
|
|
34774
|
-
async function createSMSPhoneNumber(phoneNumberType, optOutList) {
|
|
34880
|
+
async function createSMSPhoneNumber(phoneNumberType, optOutList, region) {
|
|
34775
34881
|
const numberTypeMap = {
|
|
34776
34882
|
simulator: "SIMULATOR",
|
|
34777
34883
|
"toll-free": "TOLL_FREE",
|
|
34778
34884
|
"10dlc": "TEN_DLC",
|
|
34779
34885
|
"short-code": "SHORT_CODE"
|
|
34780
34886
|
};
|
|
34781
|
-
const existingArn = await findExistingPhoneNumber(phoneNumberType);
|
|
34887
|
+
const existingArn = await findExistingPhoneNumber(phoneNumberType, region);
|
|
34782
34888
|
const phoneConfig = {
|
|
34783
34889
|
isoCountryCode: "US",
|
|
34784
34890
|
messageType: "TRANSACTIONAL",
|
|
@@ -34815,11 +34921,11 @@ async function createSMSPhoneNumber(phoneNumberType, optOutList) {
|
|
|
34815
34921
|
}
|
|
34816
34922
|
);
|
|
34817
34923
|
}
|
|
34818
|
-
async function createSMSSQSResources() {
|
|
34924
|
+
async function createSMSSQSResources(config2) {
|
|
34819
34925
|
const dlqName = "wraps-sms-events-dlq";
|
|
34820
34926
|
const queueName = "wraps-sms-events";
|
|
34821
|
-
const dlqUrl = await sqsQueueExists(dlqName);
|
|
34822
|
-
const queueUrl = await sqsQueueExists(queueName);
|
|
34927
|
+
const dlqUrl = await sqsQueueExists(dlqName, config2.region);
|
|
34928
|
+
const queueUrl = await sqsQueueExists(queueName, config2.region);
|
|
34823
34929
|
const dlqConfig = {
|
|
34824
34930
|
name: dlqName,
|
|
34825
34931
|
messageRetentionSeconds: 1209600,
|
|
@@ -34866,7 +34972,7 @@ async function createSMSSQSResources() {
|
|
|
34866
34972
|
}
|
|
34867
34973
|
async function createSMSSNSResources(config2) {
|
|
34868
34974
|
const topicName = "wraps-sms-events";
|
|
34869
|
-
const topicArn = await snsTopicExists(topicName);
|
|
34975
|
+
const topicArn = await snsTopicExists(topicName, config2.region);
|
|
34870
34976
|
const topicConfig = {
|
|
34871
34977
|
name: topicName,
|
|
34872
34978
|
tags: {
|
|
@@ -34929,9 +35035,9 @@ async function createSMSSNSResources(config2) {
|
|
|
34929
35035
|
);
|
|
34930
35036
|
return { topic, subscription };
|
|
34931
35037
|
}
|
|
34932
|
-
async function createSMSDynamoDBTable() {
|
|
35038
|
+
async function createSMSDynamoDBTable(config2) {
|
|
34933
35039
|
const tableName = "wraps-sms-history";
|
|
34934
|
-
const exists = await tableExists(tableName);
|
|
35040
|
+
const exists = await tableExists(tableName, config2.region);
|
|
34935
35041
|
const tableConfig = {
|
|
34936
35042
|
name: tableName,
|
|
34937
35043
|
billingMode: "PAY_PER_REQUEST",
|
|
@@ -35096,23 +35202,25 @@ async function deploySMSStack(config2) {
|
|
|
35096
35202
|
if (smsConfig.phoneNumberType) {
|
|
35097
35203
|
phoneNumber = await createSMSPhoneNumber(
|
|
35098
35204
|
smsConfig.phoneNumberType,
|
|
35099
|
-
optOutList
|
|
35205
|
+
optOutList,
|
|
35206
|
+
config2.region
|
|
35100
35207
|
);
|
|
35101
35208
|
}
|
|
35102
35209
|
let sqsResources;
|
|
35103
35210
|
if (smsConfig.eventTracking?.enabled) {
|
|
35104
|
-
sqsResources = await createSMSSQSResources();
|
|
35211
|
+
sqsResources = await createSMSSQSResources({ region: config2.region });
|
|
35105
35212
|
}
|
|
35106
35213
|
let snsResources;
|
|
35107
35214
|
if (smsConfig.eventTracking?.enabled && sqsResources) {
|
|
35108
35215
|
snsResources = await createSMSSNSResources({
|
|
35109
35216
|
queueArn: sqsResources.queue.arn,
|
|
35110
|
-
queueUrl: sqsResources.queue.url
|
|
35217
|
+
queueUrl: sqsResources.queue.url,
|
|
35218
|
+
region: config2.region
|
|
35111
35219
|
});
|
|
35112
35220
|
}
|
|
35113
35221
|
let dynamoTable;
|
|
35114
35222
|
if (smsConfig.eventTracking?.dynamoDBHistory) {
|
|
35115
|
-
dynamoTable = await createSMSDynamoDBTable();
|
|
35223
|
+
dynamoTable = await createSMSDynamoDBTable({ region: config2.region });
|
|
35116
35224
|
}
|
|
35117
35225
|
let lambdaFunction;
|
|
35118
35226
|
if (smsConfig.eventTracking?.dynamoDBHistory && dynamoTable && sqsResources) {
|
|
@@ -35461,7 +35569,7 @@ async function smsDestroy(options) {
|
|
|
35461
35569
|
);
|
|
35462
35570
|
}
|
|
35463
35571
|
if (!isJsonMode()) {
|
|
35464
|
-
|
|
35572
|
+
clack44.intro(
|
|
35465
35573
|
pc47.bold(
|
|
35466
35574
|
options.preview ? "SMS Infrastructure Destruction Preview" : "SMS Infrastructure Teardown"
|
|
35467
35575
|
)
|
|
@@ -35488,15 +35596,15 @@ async function smsDestroy(options) {
|
|
|
35488
35596
|
`Available regions: ${smsConnections.map((c) => c.region).join(", ")}`
|
|
35489
35597
|
);
|
|
35490
35598
|
}
|
|
35491
|
-
const selectedRegion = await
|
|
35599
|
+
const selectedRegion = await clack44.select({
|
|
35492
35600
|
message: "Multiple SMS deployments found. Which region to destroy?",
|
|
35493
35601
|
options: smsConnections.map((conn) => ({
|
|
35494
35602
|
value: conn.region,
|
|
35495
35603
|
label: conn.region
|
|
35496
35604
|
}))
|
|
35497
35605
|
});
|
|
35498
|
-
if (
|
|
35499
|
-
|
|
35606
|
+
if (clack44.isCancel(selectedRegion)) {
|
|
35607
|
+
clack44.cancel("Operation cancelled");
|
|
35500
35608
|
process.exit(0);
|
|
35501
35609
|
}
|
|
35502
35610
|
region = selectedRegion;
|
|
@@ -35507,18 +35615,18 @@ async function smsDestroy(options) {
|
|
|
35507
35615
|
const storedStackName = smsService?.pulumiStackName;
|
|
35508
35616
|
if (!smsService) {
|
|
35509
35617
|
progress.stop();
|
|
35510
|
-
|
|
35618
|
+
clack44.log.warn("No SMS infrastructure found");
|
|
35511
35619
|
process.exit(0);
|
|
35512
35620
|
}
|
|
35513
35621
|
if (!(options.force || options.preview)) {
|
|
35514
|
-
const confirmed = await
|
|
35622
|
+
const confirmed = await clack44.confirm({
|
|
35515
35623
|
message: pc47.red(
|
|
35516
35624
|
"Are you sure you want to destroy all SMS infrastructure?"
|
|
35517
35625
|
),
|
|
35518
35626
|
initialValue: false
|
|
35519
35627
|
});
|
|
35520
|
-
if (
|
|
35521
|
-
|
|
35628
|
+
if (clack44.isCancel(confirmed) || !confirmed) {
|
|
35629
|
+
clack44.cancel("Destruction cancelled.");
|
|
35522
35630
|
process.exit(0);
|
|
35523
35631
|
}
|
|
35524
35632
|
}
|
|
@@ -35550,7 +35658,7 @@ async function smsDestroy(options) {
|
|
|
35550
35658
|
costEstimate: "Monthly cost after destruction: $0.00",
|
|
35551
35659
|
commandName: "wraps sms destroy"
|
|
35552
35660
|
});
|
|
35553
|
-
|
|
35661
|
+
clack44.outro(
|
|
35554
35662
|
pc47.green("Preview complete. Run without --preview to destroy.")
|
|
35555
35663
|
);
|
|
35556
35664
|
trackServiceRemoved("sms", {
|
|
@@ -35562,7 +35670,7 @@ async function smsDestroy(options) {
|
|
|
35562
35670
|
progress.stop();
|
|
35563
35671
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
35564
35672
|
if (errorMessage.includes("No SMS infrastructure found")) {
|
|
35565
|
-
|
|
35673
|
+
clack44.log.warn("No SMS infrastructure found to preview");
|
|
35566
35674
|
process.exit(0);
|
|
35567
35675
|
}
|
|
35568
35676
|
trackError("PREVIEW_FAILED", "sms destroy", { step: "preview" });
|
|
@@ -35611,7 +35719,7 @@ async function smsDestroy(options) {
|
|
|
35611
35719
|
progress.stop();
|
|
35612
35720
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
35613
35721
|
if (errorMessage.includes("No SMS infrastructure found")) {
|
|
35614
|
-
|
|
35722
|
+
clack44.log.warn("No SMS infrastructure found");
|
|
35615
35723
|
if (metadata) {
|
|
35616
35724
|
removeServiceFromConnection(metadata, "sms");
|
|
35617
35725
|
await saveConnectionMetadata(metadata);
|
|
@@ -35624,7 +35732,7 @@ async function smsDestroy(options) {
|
|
|
35624
35732
|
}
|
|
35625
35733
|
trackError("DESTROY_FAILED", "sms destroy", { step: "destroy" });
|
|
35626
35734
|
destroyFailed = true;
|
|
35627
|
-
|
|
35735
|
+
clack44.log.warn(
|
|
35628
35736
|
"Some resources may not have been fully removed. You can re-run this command or clean up manually in the AWS console."
|
|
35629
35737
|
);
|
|
35630
35738
|
}
|
|
@@ -35647,11 +35755,11 @@ async function smsDestroy(options) {
|
|
|
35647
35755
|
return;
|
|
35648
35756
|
}
|
|
35649
35757
|
if (destroyFailed) {
|
|
35650
|
-
|
|
35758
|
+
clack44.outro(
|
|
35651
35759
|
pc47.yellow("SMS infrastructure partially removed. Metadata cleaned up.")
|
|
35652
35760
|
);
|
|
35653
35761
|
} else {
|
|
35654
|
-
|
|
35762
|
+
clack44.outro(pc47.green("SMS infrastructure has been removed"));
|
|
35655
35763
|
console.log(`
|
|
35656
35764
|
${pc47.bold("Cleaned up:")}`);
|
|
35657
35765
|
console.log(` ${pc47.green("\u2713")} Phone number released`);
|
|
@@ -35673,7 +35781,7 @@ Run ${pc47.cyan("wraps sms init")} to deploy infrastructure again.
|
|
|
35673
35781
|
|
|
35674
35782
|
// src/commands/sms/init.ts
|
|
35675
35783
|
init_esm_shims();
|
|
35676
|
-
import * as
|
|
35784
|
+
import * as clack45 from "@clack/prompts";
|
|
35677
35785
|
import * as pulumi29 from "@pulumi/pulumi";
|
|
35678
35786
|
import pc48 from "picocolors";
|
|
35679
35787
|
init_events();
|
|
@@ -36094,7 +36202,7 @@ function validateSMSConfig(config2) {
|
|
|
36094
36202
|
|
|
36095
36203
|
// src/commands/sms/init.ts
|
|
36096
36204
|
async function promptPhoneNumberType() {
|
|
36097
|
-
const result = await
|
|
36205
|
+
const result = await clack45.select({
|
|
36098
36206
|
message: "Select phone number type:",
|
|
36099
36207
|
options: [
|
|
36100
36208
|
{
|
|
@@ -36114,14 +36222,14 @@ async function promptPhoneNumberType() {
|
|
|
36114
36222
|
}
|
|
36115
36223
|
]
|
|
36116
36224
|
});
|
|
36117
|
-
if (
|
|
36118
|
-
|
|
36225
|
+
if (clack45.isCancel(result)) {
|
|
36226
|
+
clack45.cancel("Operation cancelled.");
|
|
36119
36227
|
process.exit(0);
|
|
36120
36228
|
}
|
|
36121
36229
|
return result;
|
|
36122
36230
|
}
|
|
36123
36231
|
async function promptSMSPreset() {
|
|
36124
|
-
const result = await
|
|
36232
|
+
const result = await clack45.select({
|
|
36125
36233
|
message: "Choose configuration preset:",
|
|
36126
36234
|
options: [
|
|
36127
36235
|
{
|
|
@@ -36146,8 +36254,8 @@ async function promptSMSPreset() {
|
|
|
36146
36254
|
}
|
|
36147
36255
|
]
|
|
36148
36256
|
});
|
|
36149
|
-
if (
|
|
36150
|
-
|
|
36257
|
+
if (clack45.isCancel(result)) {
|
|
36258
|
+
clack45.cancel("Operation cancelled.");
|
|
36151
36259
|
process.exit(0);
|
|
36152
36260
|
}
|
|
36153
36261
|
return result;
|
|
@@ -36167,7 +36275,7 @@ var COMMON_COUNTRIES = [
|
|
|
36167
36275
|
{ code: "IN", name: "India" }
|
|
36168
36276
|
];
|
|
36169
36277
|
async function promptAllowedCountries() {
|
|
36170
|
-
const result = await
|
|
36278
|
+
const result = await clack45.multiselect({
|
|
36171
36279
|
message: "Select countries to allow SMS delivery (blocks all others):",
|
|
36172
36280
|
options: COMMON_COUNTRIES.map((c) => ({
|
|
36173
36281
|
value: c.code,
|
|
@@ -36176,14 +36284,14 @@ async function promptAllowedCountries() {
|
|
|
36176
36284
|
initialValues: ["US"],
|
|
36177
36285
|
required: true
|
|
36178
36286
|
});
|
|
36179
|
-
if (
|
|
36180
|
-
|
|
36287
|
+
if (clack45.isCancel(result)) {
|
|
36288
|
+
clack45.cancel("Operation cancelled.");
|
|
36181
36289
|
process.exit(0);
|
|
36182
36290
|
}
|
|
36183
36291
|
return result;
|
|
36184
36292
|
}
|
|
36185
36293
|
async function promptEstimatedSMSVolume() {
|
|
36186
|
-
const result = await
|
|
36294
|
+
const result = await clack45.select({
|
|
36187
36295
|
message: "Estimated messages per month:",
|
|
36188
36296
|
options: [
|
|
36189
36297
|
{ value: 100, label: "< 100 (Testing)" },
|
|
@@ -36193,8 +36301,8 @@ async function promptEstimatedSMSVolume() {
|
|
|
36193
36301
|
{ value: 1e5, label: "50,000+" }
|
|
36194
36302
|
]
|
|
36195
36303
|
});
|
|
36196
|
-
if (
|
|
36197
|
-
|
|
36304
|
+
if (clack45.isCancel(result)) {
|
|
36305
|
+
clack45.cancel("Operation cancelled.");
|
|
36198
36306
|
process.exit(0);
|
|
36199
36307
|
}
|
|
36200
36308
|
return result;
|
|
@@ -36202,7 +36310,7 @@ async function promptEstimatedSMSVolume() {
|
|
|
36202
36310
|
async function init3(options) {
|
|
36203
36311
|
const startTime = Date.now();
|
|
36204
36312
|
if (!isJsonMode()) {
|
|
36205
|
-
|
|
36313
|
+
clack45.intro(pc48.bold("Wraps SMS Infrastructure Setup"));
|
|
36206
36314
|
}
|
|
36207
36315
|
const progress = new DeploymentProgress();
|
|
36208
36316
|
const wasAutoInstalled = await progress.execute(
|
|
@@ -36228,10 +36336,10 @@ async function init3(options) {
|
|
|
36228
36336
|
region
|
|
36229
36337
|
);
|
|
36230
36338
|
if (existingConnection?.services?.sms) {
|
|
36231
|
-
|
|
36339
|
+
clack45.log.warn(
|
|
36232
36340
|
`SMS already configured for account ${pc48.cyan(identity.accountId)} in region ${pc48.cyan(region)}`
|
|
36233
36341
|
);
|
|
36234
|
-
|
|
36342
|
+
clack45.log.info(`Use ${pc48.cyan("wraps sms status")} to view current setup`);
|
|
36235
36343
|
process.exit(0);
|
|
36236
36344
|
}
|
|
36237
36345
|
let preset = options.preset;
|
|
@@ -36248,12 +36356,12 @@ async function init3(options) {
|
|
|
36248
36356
|
optOutManagement: true,
|
|
36249
36357
|
sendingEnabled: true
|
|
36250
36358
|
};
|
|
36251
|
-
const enableEventTracking = await
|
|
36359
|
+
const enableEventTracking = await clack45.confirm({
|
|
36252
36360
|
message: "Enable event tracking (EventBridge + DynamoDB)?",
|
|
36253
36361
|
initialValue: false
|
|
36254
36362
|
});
|
|
36255
|
-
if (
|
|
36256
|
-
|
|
36363
|
+
if (clack45.isCancel(enableEventTracking)) {
|
|
36364
|
+
clack45.cancel("Operation cancelled.");
|
|
36257
36365
|
process.exit(0);
|
|
36258
36366
|
}
|
|
36259
36367
|
if (enableEventTracking) {
|
|
@@ -36278,12 +36386,12 @@ ${pc48.bold("Fraud Protection")} - Block SMS to countries where you don't do bus
|
|
|
36278
36386
|
const allowedCountries = await promptAllowedCountries();
|
|
36279
36387
|
let aitFiltering = false;
|
|
36280
36388
|
if (smsConfig.phoneNumberType !== "simulator") {
|
|
36281
|
-
const enableAIT = await
|
|
36389
|
+
const enableAIT = await clack45.confirm({
|
|
36282
36390
|
message: "Enable AIT (Artificially Inflated Traffic) filtering? (adds per-message cost)",
|
|
36283
36391
|
initialValue: false
|
|
36284
36392
|
});
|
|
36285
|
-
if (
|
|
36286
|
-
|
|
36393
|
+
if (clack45.isCancel(enableAIT)) {
|
|
36394
|
+
clack45.cancel("Operation cancelled.");
|
|
36287
36395
|
process.exit(0);
|
|
36288
36396
|
}
|
|
36289
36397
|
aitFiltering = enableAIT;
|
|
@@ -36297,19 +36405,19 @@ ${pc48.bold("Fraud Protection")} - Block SMS to countries where you don't do bus
|
|
|
36297
36405
|
progress.info(`
|
|
36298
36406
|
${pc48.bold("Cost Estimate:")}`);
|
|
36299
36407
|
const costSummary = getSMSCostSummary(smsConfig, estimatedVolume);
|
|
36300
|
-
|
|
36408
|
+
clack45.log.info(costSummary);
|
|
36301
36409
|
const warnings = validateSMSConfig(smsConfig);
|
|
36302
36410
|
if (warnings.length > 0) {
|
|
36303
36411
|
progress.info(`
|
|
36304
36412
|
${pc48.yellow(pc48.bold("Important Notes:"))}`);
|
|
36305
36413
|
for (const warning of warnings) {
|
|
36306
|
-
|
|
36414
|
+
clack45.log.warn(warning);
|
|
36307
36415
|
}
|
|
36308
36416
|
}
|
|
36309
36417
|
if (!options.yes) {
|
|
36310
36418
|
const confirmed = await confirmDeploy();
|
|
36311
36419
|
if (!confirmed) {
|
|
36312
|
-
|
|
36420
|
+
clack45.cancel("Deployment cancelled.");
|
|
36313
36421
|
process.exit(0);
|
|
36314
36422
|
}
|
|
36315
36423
|
}
|
|
@@ -36385,8 +36493,8 @@ ${pc48.yellow(pc48.bold("Important Notes:"))}`);
|
|
|
36385
36493
|
} catch (sdkError) {
|
|
36386
36494
|
sdkResourceWarning = true;
|
|
36387
36495
|
const msg = sdkError instanceof Error ? sdkError.message : String(sdkError);
|
|
36388
|
-
|
|
36389
|
-
|
|
36496
|
+
clack45.log.warn(`Phone pool creation failed: ${msg}`);
|
|
36497
|
+
clack45.log.info(
|
|
36390
36498
|
`Run ${pc48.cyan("wraps sms sync")} to retry SDK resource creation.`
|
|
36391
36499
|
);
|
|
36392
36500
|
}
|
|
@@ -36403,8 +36511,8 @@ ${pc48.yellow(pc48.bold("Important Notes:"))}`);
|
|
|
36403
36511
|
} catch (sdkError) {
|
|
36404
36512
|
sdkResourceWarning = true;
|
|
36405
36513
|
const msg = sdkError instanceof Error ? sdkError.message : String(sdkError);
|
|
36406
|
-
|
|
36407
|
-
|
|
36514
|
+
clack45.log.warn(`Event destination creation failed: ${msg}`);
|
|
36515
|
+
clack45.log.info(
|
|
36408
36516
|
`Run ${pc48.cyan("wraps sms sync")} to retry SDK resource creation.`
|
|
36409
36517
|
);
|
|
36410
36518
|
}
|
|
@@ -36424,14 +36532,14 @@ ${pc48.yellow(pc48.bold("Important Notes:"))}`);
|
|
|
36424
36532
|
} catch (sdkError) {
|
|
36425
36533
|
sdkResourceWarning = true;
|
|
36426
36534
|
const msg = sdkError instanceof Error ? sdkError.message : String(sdkError);
|
|
36427
|
-
|
|
36428
|
-
|
|
36535
|
+
clack45.log.warn(`Protect configuration creation failed: ${msg}`);
|
|
36536
|
+
clack45.log.info(
|
|
36429
36537
|
`Run ${pc48.cyan("wraps sms sync")} to retry SDK resource creation.`
|
|
36430
36538
|
);
|
|
36431
36539
|
}
|
|
36432
36540
|
}
|
|
36433
36541
|
if (sdkResourceWarning) {
|
|
36434
|
-
|
|
36542
|
+
clack45.log.warn(
|
|
36435
36543
|
"Some SDK resources failed to create. Core infrastructure is deployed."
|
|
36436
36544
|
);
|
|
36437
36545
|
}
|
|
@@ -36476,9 +36584,9 @@ ${pc48.yellow(pc48.bold("Important Notes:"))}`);
|
|
|
36476
36584
|
return;
|
|
36477
36585
|
}
|
|
36478
36586
|
console.log("\n");
|
|
36479
|
-
|
|
36587
|
+
clack45.log.success(pc48.green(pc48.bold("SMS infrastructure deployed!")));
|
|
36480
36588
|
console.log("\n");
|
|
36481
|
-
|
|
36589
|
+
clack45.note(
|
|
36482
36590
|
[
|
|
36483
36591
|
`${pc48.bold("Phone Number:")} ${pc48.cyan(outputs.phoneNumber || "Provisioning...")}`,
|
|
36484
36592
|
`${pc48.bold("Phone Type:")} ${pc48.cyan(smsConfig.phoneNumberType || "simulator")}`,
|
|
@@ -36502,12 +36610,12 @@ ${pc48.yellow(pc48.bold("Important Notes:"))}`);
|
|
|
36502
36610
|
);
|
|
36503
36611
|
nextSteps.push(`${pc48.cyan("wraps sms status")} - View SMS configuration`);
|
|
36504
36612
|
console.log("\n");
|
|
36505
|
-
|
|
36613
|
+
clack45.log.info(pc48.bold("Next steps:"));
|
|
36506
36614
|
for (const step of nextSteps) {
|
|
36507
36615
|
console.log(` ${step}`);
|
|
36508
36616
|
}
|
|
36509
36617
|
console.log("\n");
|
|
36510
|
-
|
|
36618
|
+
clack45.log.info(pc48.bold("SDK Usage:"));
|
|
36511
36619
|
console.log(pc48.dim(" npm install @wraps.dev/sms"));
|
|
36512
36620
|
console.log("");
|
|
36513
36621
|
console.log(pc48.dim(" import { Wraps } from '@wraps.dev/sms';"));
|
|
@@ -36516,7 +36624,7 @@ ${pc48.yellow(pc48.bold("Important Notes:"))}`);
|
|
|
36516
36624
|
console.log(pc48.dim(" to: '+14155551234',"));
|
|
36517
36625
|
console.log(pc48.dim(" message: 'Your code is 123456',"));
|
|
36518
36626
|
console.log(pc48.dim(" });"));
|
|
36519
|
-
|
|
36627
|
+
clack45.outro(pc48.green("Setup complete!"));
|
|
36520
36628
|
const duration = Date.now() - startTime;
|
|
36521
36629
|
const enabledFeatures = [];
|
|
36522
36630
|
if (smsConfig.tracking?.enabled) {
|
|
@@ -36552,7 +36660,7 @@ init_aws();
|
|
|
36552
36660
|
init_json_output();
|
|
36553
36661
|
init_metadata();
|
|
36554
36662
|
init_output();
|
|
36555
|
-
import * as
|
|
36663
|
+
import * as clack46 from "@clack/prompts";
|
|
36556
36664
|
import pc49 from "picocolors";
|
|
36557
36665
|
async function getPhoneNumberDetails(region) {
|
|
36558
36666
|
const { PinpointSMSVoiceV2Client: PinpointSMSVoiceV2Client5, DescribePhoneNumbersCommand: DescribePhoneNumbersCommand2 } = await import("@aws-sdk/client-pinpoint-sms-voice-v2");
|
|
@@ -36573,7 +36681,7 @@ async function getPhoneNumberDetails(region) {
|
|
|
36573
36681
|
return null;
|
|
36574
36682
|
} catch (error) {
|
|
36575
36683
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
36576
|
-
|
|
36684
|
+
clack46.log.error(`Error fetching phone number: ${errorMessage}`);
|
|
36577
36685
|
return null;
|
|
36578
36686
|
}
|
|
36579
36687
|
}
|
|
@@ -36594,7 +36702,7 @@ async function getRegistrationStatus(region, registrationId) {
|
|
|
36594
36702
|
async function smsRegister(options) {
|
|
36595
36703
|
const startTime = Date.now();
|
|
36596
36704
|
if (!isJsonMode()) {
|
|
36597
|
-
|
|
36705
|
+
clack46.intro(pc49.bold("Wraps SMS - Toll-Free Registration"));
|
|
36598
36706
|
}
|
|
36599
36707
|
const progress = new DeploymentProgress();
|
|
36600
36708
|
const identity = await progress.execute(
|
|
@@ -36607,8 +36715,8 @@ async function smsRegister(options) {
|
|
|
36607
36715
|
}
|
|
36608
36716
|
const metadata = await loadConnectionMetadata(identity.accountId, region);
|
|
36609
36717
|
if (!metadata?.services?.sms) {
|
|
36610
|
-
|
|
36611
|
-
|
|
36718
|
+
clack46.log.error("No SMS infrastructure found.");
|
|
36719
|
+
clack46.log.info(`Run ${pc49.cyan("wraps sms init")} first.`);
|
|
36612
36720
|
process.exit(1);
|
|
36613
36721
|
}
|
|
36614
36722
|
const phoneDetails = await progress.execute(
|
|
@@ -36616,7 +36724,7 @@ async function smsRegister(options) {
|
|
|
36616
36724
|
async () => getPhoneNumberDetails(region)
|
|
36617
36725
|
);
|
|
36618
36726
|
if (!phoneDetails) {
|
|
36619
|
-
|
|
36727
|
+
clack46.log.error("No phone number found.");
|
|
36620
36728
|
process.exit(1);
|
|
36621
36729
|
}
|
|
36622
36730
|
let registrationStatus = null;
|
|
@@ -36653,18 +36761,18 @@ async function smsRegister(options) {
|
|
|
36653
36761
|
}
|
|
36654
36762
|
console.log("");
|
|
36655
36763
|
if (phoneDetails.status === "ACTIVE") {
|
|
36656
|
-
|
|
36764
|
+
clack46.log.success("Your phone number is already ACTIVE and ready to use!");
|
|
36657
36765
|
const { PinpointSMSVoiceV2Client: PinpointSMSVoiceV2Client5, DescribePoolsCommand } = await import("@aws-sdk/client-pinpoint-sms-voice-v2");
|
|
36658
36766
|
const client = new PinpointSMSVoiceV2Client5({ region });
|
|
36659
36767
|
const pools = await client.send(new DescribePoolsCommand({}));
|
|
36660
36768
|
if (!pools.Pools?.length) {
|
|
36661
|
-
|
|
36769
|
+
clack46.log.info("Run `wraps sms sync` to create the phone pool.");
|
|
36662
36770
|
}
|
|
36663
36771
|
process.exit(0);
|
|
36664
36772
|
}
|
|
36665
36773
|
if (phoneDetails.type !== "TOLL_FREE") {
|
|
36666
|
-
|
|
36667
|
-
|
|
36774
|
+
clack46.log.info("Only toll-free numbers require registration.");
|
|
36775
|
+
clack46.log.info(`Your ${phoneDetails.type} number should be ready to use.`);
|
|
36668
36776
|
process.exit(0);
|
|
36669
36777
|
}
|
|
36670
36778
|
console.log(pc49.bold("Toll-Free Registration Required"));
|
|
@@ -36683,12 +36791,12 @@ async function smsRegister(options) {
|
|
|
36683
36791
|
console.log(` ${pc49.dim("\u2022")} How users opt-in to receive messages`);
|
|
36684
36792
|
console.log(` ${pc49.dim("\u2022")} Expected monthly message volume`);
|
|
36685
36793
|
console.log("");
|
|
36686
|
-
const openConsole = await
|
|
36794
|
+
const openConsole = await clack46.confirm({
|
|
36687
36795
|
message: "Open AWS Console to start registration?",
|
|
36688
36796
|
initialValue: true
|
|
36689
36797
|
});
|
|
36690
|
-
if (
|
|
36691
|
-
|
|
36798
|
+
if (clack46.isCancel(openConsole)) {
|
|
36799
|
+
clack46.cancel("Registration cancelled.");
|
|
36692
36800
|
process.exit(0);
|
|
36693
36801
|
}
|
|
36694
36802
|
if (openConsole) {
|
|
@@ -36698,13 +36806,13 @@ async function smsRegister(options) {
|
|
|
36698
36806
|
const execAsync2 = promisify2(exec2);
|
|
36699
36807
|
try {
|
|
36700
36808
|
await execAsync2(`open "${consoleUrl}"`);
|
|
36701
|
-
|
|
36809
|
+
clack46.log.success("Opened AWS Console in your browser.");
|
|
36702
36810
|
} catch {
|
|
36703
36811
|
try {
|
|
36704
36812
|
await execAsync2(`xdg-open "${consoleUrl}"`);
|
|
36705
|
-
|
|
36813
|
+
clack46.log.success("Opened AWS Console in your browser.");
|
|
36706
36814
|
} catch {
|
|
36707
|
-
|
|
36815
|
+
clack46.log.info("Open this URL in your browser:");
|
|
36708
36816
|
console.log(`
|
|
36709
36817
|
${pc49.cyan(consoleUrl)}
|
|
36710
36818
|
`);
|
|
@@ -36732,7 +36840,7 @@ async function smsRegister(options) {
|
|
|
36732
36840
|
success: true,
|
|
36733
36841
|
duration_ms: Date.now() - startTime
|
|
36734
36842
|
});
|
|
36735
|
-
|
|
36843
|
+
clack46.outro(pc49.dim("Good luck with your registration!"));
|
|
36736
36844
|
}
|
|
36737
36845
|
|
|
36738
36846
|
// src/commands/sms/status.ts
|
|
@@ -36744,7 +36852,8 @@ init_json_output();
|
|
|
36744
36852
|
init_metadata();
|
|
36745
36853
|
init_output();
|
|
36746
36854
|
init_pulumi();
|
|
36747
|
-
|
|
36855
|
+
init_region_resolver();
|
|
36856
|
+
import * as clack47 from "@clack/prompts";
|
|
36748
36857
|
import * as pulumi30 from "@pulumi/pulumi";
|
|
36749
36858
|
import pc50 from "picocolors";
|
|
36750
36859
|
function displaySMSStatus(options) {
|
|
@@ -36784,24 +36893,29 @@ function displaySMSStatus(options) {
|
|
|
36784
36893
|
lines.push(pc50.bold("IAM Role"));
|
|
36785
36894
|
lines.push(` ${pc50.dim(options.roleArn)}`);
|
|
36786
36895
|
}
|
|
36787
|
-
|
|
36896
|
+
clack47.note(lines.join("\n"), "SMS Status");
|
|
36788
36897
|
}
|
|
36789
|
-
async function smsStatus(
|
|
36898
|
+
async function smsStatus(options) {
|
|
36790
36899
|
await ensurePulumiInstalled();
|
|
36791
36900
|
const startTime = Date.now();
|
|
36792
36901
|
const progress = new DeploymentProgress();
|
|
36793
36902
|
if (!isJsonMode()) {
|
|
36794
|
-
|
|
36903
|
+
clack47.intro(pc50.bold("Wraps SMS Status"));
|
|
36795
36904
|
}
|
|
36796
36905
|
const identity = await progress.execute(
|
|
36797
36906
|
"Loading SMS infrastructure status",
|
|
36798
36907
|
async () => validateAWSCredentials()
|
|
36799
36908
|
);
|
|
36800
|
-
const region = await
|
|
36909
|
+
const region = await resolveRegionForCommand({
|
|
36910
|
+
accountId: identity.accountId,
|
|
36911
|
+
optionRegion: options.region,
|
|
36912
|
+
service: "sms",
|
|
36913
|
+
label: "SMS deployment"
|
|
36914
|
+
});
|
|
36801
36915
|
const metadata = await loadConnectionMetadata(identity.accountId, region);
|
|
36802
36916
|
if (!metadata?.services?.sms) {
|
|
36803
36917
|
progress.stop();
|
|
36804
|
-
|
|
36918
|
+
clack47.log.error("No SMS infrastructure found");
|
|
36805
36919
|
console.log(
|
|
36806
36920
|
`
|
|
36807
36921
|
Run ${pc50.cyan("wraps sms init")} to deploy SMS infrastructure.
|
|
@@ -36840,7 +36954,7 @@ Run ${pc50.cyan("wraps sms init")} to deploy SMS infrastructure.
|
|
|
36840
36954
|
}
|
|
36841
36955
|
displaySMSStatus(smsStatusData);
|
|
36842
36956
|
console.log("");
|
|
36843
|
-
|
|
36957
|
+
clack47.log.info(pc50.bold("Commands:"));
|
|
36844
36958
|
console.log(
|
|
36845
36959
|
` ${pc50.cyan("wraps sms test --to +1234567890")} - Send a test message`
|
|
36846
36960
|
);
|
|
@@ -36851,12 +36965,12 @@ Run ${pc50.cyan("wraps sms init")} to deploy SMS infrastructure.
|
|
|
36851
36965
|
event_tracking: smsConfig?.eventTracking?.enabled,
|
|
36852
36966
|
duration_ms: Date.now() - startTime
|
|
36853
36967
|
});
|
|
36854
|
-
|
|
36968
|
+
clack47.outro(pc50.dim("SMS infrastructure is ready"));
|
|
36855
36969
|
}
|
|
36856
36970
|
|
|
36857
36971
|
// src/commands/sms/sync.ts
|
|
36858
36972
|
init_esm_shims();
|
|
36859
|
-
import * as
|
|
36973
|
+
import * as clack48 from "@clack/prompts";
|
|
36860
36974
|
import * as pulumi31 from "@pulumi/pulumi";
|
|
36861
36975
|
import pc51 from "picocolors";
|
|
36862
36976
|
init_events();
|
|
@@ -36871,7 +36985,7 @@ async function smsSync(options) {
|
|
|
36871
36985
|
await ensurePulumiInstalled();
|
|
36872
36986
|
const startTime = Date.now();
|
|
36873
36987
|
if (!isJsonMode()) {
|
|
36874
|
-
|
|
36988
|
+
clack48.intro(pc51.bold("Wraps SMS Infrastructure Sync"));
|
|
36875
36989
|
}
|
|
36876
36990
|
const progress = new DeploymentProgress();
|
|
36877
36991
|
const identity = await progress.execute(
|
|
@@ -36883,7 +36997,7 @@ async function smsSync(options) {
|
|
|
36883
36997
|
const smsService = metadata?.services?.sms;
|
|
36884
36998
|
if (!smsService?.config) {
|
|
36885
36999
|
progress.stop();
|
|
36886
|
-
|
|
37000
|
+
clack48.log.error("No SMS infrastructure found to sync");
|
|
36887
37001
|
console.log(
|
|
36888
37002
|
`
|
|
36889
37003
|
Run ${pc51.cyan("wraps sms init")} to deploy SMS infrastructure first.
|
|
@@ -36901,12 +37015,12 @@ Run ${pc51.cyan("wraps sms init")} to deploy SMS infrastructure first.
|
|
|
36901
37015
|
`Event tracking: ${pc51.cyan(smsConfig.eventTracking?.enabled ? "enabled" : "disabled")}`
|
|
36902
37016
|
);
|
|
36903
37017
|
if (!options.yes) {
|
|
36904
|
-
const confirmed = await
|
|
37018
|
+
const confirmed = await clack48.confirm({
|
|
36905
37019
|
message: "Sync SMS infrastructure? This will update Lambda code and recreate any missing resources.",
|
|
36906
37020
|
initialValue: true
|
|
36907
37021
|
});
|
|
36908
|
-
if (
|
|
36909
|
-
|
|
37022
|
+
if (clack48.isCancel(confirmed) || !confirmed) {
|
|
37023
|
+
clack48.cancel("Sync cancelled.");
|
|
36910
37024
|
process.exit(0);
|
|
36911
37025
|
}
|
|
36912
37026
|
}
|
|
@@ -37011,7 +37125,7 @@ Run ${pc51.cyan("wraps sms init")} to deploy SMS infrastructure first.
|
|
|
37011
37125
|
throw errors.stackLocked();
|
|
37012
37126
|
}
|
|
37013
37127
|
trackError("SYNC_FAILED", "sms:sync", { step: "sync" });
|
|
37014
|
-
|
|
37128
|
+
clack48.log.error(`SMS sync failed: ${errorMessage}`);
|
|
37015
37129
|
process.exit(1);
|
|
37016
37130
|
}
|
|
37017
37131
|
if (metadata && smsService) {
|
|
@@ -37031,7 +37145,7 @@ Run ${pc51.cyan("wraps sms init")} to deploy SMS infrastructure first.
|
|
|
37031
37145
|
return;
|
|
37032
37146
|
}
|
|
37033
37147
|
console.log("\n");
|
|
37034
|
-
|
|
37148
|
+
clack48.log.success(pc51.green("SMS infrastructure synced successfully!"));
|
|
37035
37149
|
const changes = [];
|
|
37036
37150
|
if (outputs.lambdaFunctions?.length) {
|
|
37037
37151
|
changes.push("Lambda functions updated");
|
|
@@ -37045,7 +37159,7 @@ Run ${pc51.cyan("wraps sms init")} to deploy SMS infrastructure first.
|
|
|
37045
37159
|
success: true,
|
|
37046
37160
|
duration_ms: Date.now() - startTime
|
|
37047
37161
|
});
|
|
37048
|
-
|
|
37162
|
+
clack48.outro(pc51.green("Sync complete!"));
|
|
37049
37163
|
}
|
|
37050
37164
|
|
|
37051
37165
|
// src/commands/sms/test.ts
|
|
@@ -37060,7 +37174,7 @@ import {
|
|
|
37060
37174
|
PinpointSMSVoiceV2Client as PinpointSMSVoiceV2Client3,
|
|
37061
37175
|
SendTextMessageCommand
|
|
37062
37176
|
} from "@aws-sdk/client-pinpoint-sms-voice-v2";
|
|
37063
|
-
import * as
|
|
37177
|
+
import * as clack49 from "@clack/prompts";
|
|
37064
37178
|
import pc52 from "picocolors";
|
|
37065
37179
|
|
|
37066
37180
|
// src/utils/sms/validation.ts
|
|
@@ -37084,7 +37198,7 @@ async function smsTest(options) {
|
|
|
37084
37198
|
const startTime = Date.now();
|
|
37085
37199
|
const progress = new DeploymentProgress();
|
|
37086
37200
|
if (!isJsonMode()) {
|
|
37087
|
-
|
|
37201
|
+
clack49.intro(pc52.bold("Wraps SMS Test"));
|
|
37088
37202
|
}
|
|
37089
37203
|
const identity = await progress.execute(
|
|
37090
37204
|
"Validating AWS credentials",
|
|
@@ -37094,7 +37208,7 @@ async function smsTest(options) {
|
|
|
37094
37208
|
const metadata = await loadConnectionMetadata(identity.accountId, region);
|
|
37095
37209
|
if (!metadata?.services?.sms) {
|
|
37096
37210
|
progress.stop();
|
|
37097
|
-
|
|
37211
|
+
clack49.log.error("No SMS infrastructure found");
|
|
37098
37212
|
console.log(
|
|
37099
37213
|
`
|
|
37100
37214
|
Run ${pc52.cyan("wraps sms init")} to deploy SMS infrastructure.
|
|
@@ -37111,7 +37225,7 @@ Run ${pc52.cyan("wraps sms init")} to deploy SMS infrastructure.
|
|
|
37111
37225
|
);
|
|
37112
37226
|
}
|
|
37113
37227
|
if (!toNumber) {
|
|
37114
|
-
const destinationType = await
|
|
37228
|
+
const destinationType = await clack49.select({
|
|
37115
37229
|
message: "Choose destination number:",
|
|
37116
37230
|
options: [
|
|
37117
37231
|
{
|
|
@@ -37126,25 +37240,25 @@ Run ${pc52.cyan("wraps sms init")} to deploy SMS infrastructure.
|
|
|
37126
37240
|
}
|
|
37127
37241
|
]
|
|
37128
37242
|
});
|
|
37129
|
-
if (
|
|
37130
|
-
|
|
37243
|
+
if (clack49.isCancel(destinationType)) {
|
|
37244
|
+
clack49.cancel("Operation cancelled.");
|
|
37131
37245
|
process.exit(0);
|
|
37132
37246
|
}
|
|
37133
37247
|
if (destinationType === "simulator") {
|
|
37134
|
-
const simResult = await
|
|
37248
|
+
const simResult = await clack49.select({
|
|
37135
37249
|
message: "Select simulator destination:",
|
|
37136
37250
|
options: SIMULATOR_DESTINATIONS.map((sim) => ({
|
|
37137
37251
|
value: sim.number,
|
|
37138
37252
|
label: `${sim.number} | ${sim.country}`
|
|
37139
37253
|
}))
|
|
37140
37254
|
});
|
|
37141
|
-
if (
|
|
37142
|
-
|
|
37255
|
+
if (clack49.isCancel(simResult)) {
|
|
37256
|
+
clack49.cancel("Operation cancelled.");
|
|
37143
37257
|
process.exit(0);
|
|
37144
37258
|
}
|
|
37145
37259
|
toNumber = simResult;
|
|
37146
37260
|
} else {
|
|
37147
|
-
const result = await
|
|
37261
|
+
const result = await clack49.text({
|
|
37148
37262
|
message: "Enter destination phone number (E.164 format):",
|
|
37149
37263
|
placeholder: "+14155551234",
|
|
37150
37264
|
validate: (value) => {
|
|
@@ -37157,22 +37271,22 @@ Run ${pc52.cyan("wraps sms init")} to deploy SMS infrastructure.
|
|
|
37157
37271
|
return;
|
|
37158
37272
|
}
|
|
37159
37273
|
});
|
|
37160
|
-
if (
|
|
37161
|
-
|
|
37274
|
+
if (clack49.isCancel(result)) {
|
|
37275
|
+
clack49.cancel("Operation cancelled.");
|
|
37162
37276
|
process.exit(0);
|
|
37163
37277
|
}
|
|
37164
37278
|
toNumber = result;
|
|
37165
37279
|
}
|
|
37166
37280
|
} else if (!isValidPhoneNumber(toNumber)) {
|
|
37167
37281
|
progress.stop();
|
|
37168
|
-
|
|
37282
|
+
clack49.log.error(
|
|
37169
37283
|
`Invalid phone number format: ${toNumber}. Use E.164 format (e.g., +14155551234)`
|
|
37170
37284
|
);
|
|
37171
37285
|
process.exit(1);
|
|
37172
37286
|
}
|
|
37173
37287
|
let message = options.message;
|
|
37174
37288
|
if (!message) {
|
|
37175
|
-
const result = await
|
|
37289
|
+
const result = await clack49.text({
|
|
37176
37290
|
message: "Enter test message:",
|
|
37177
37291
|
placeholder: "Hello from Wraps SMS!",
|
|
37178
37292
|
defaultValue: "Hello from Wraps SMS! This is a test message.",
|
|
@@ -37186,8 +37300,8 @@ Run ${pc52.cyan("wraps sms init")} to deploy SMS infrastructure.
|
|
|
37186
37300
|
return;
|
|
37187
37301
|
}
|
|
37188
37302
|
});
|
|
37189
|
-
if (
|
|
37190
|
-
|
|
37303
|
+
if (clack49.isCancel(result)) {
|
|
37304
|
+
clack49.cancel("Operation cancelled.");
|
|
37191
37305
|
process.exit(0);
|
|
37192
37306
|
}
|
|
37193
37307
|
message = result;
|
|
@@ -37226,9 +37340,9 @@ Run ${pc52.cyan("wraps sms init")} to deploy SMS infrastructure.
|
|
|
37226
37340
|
return;
|
|
37227
37341
|
}
|
|
37228
37342
|
console.log("\n");
|
|
37229
|
-
|
|
37343
|
+
clack49.log.success(pc52.green("Test SMS sent successfully!"));
|
|
37230
37344
|
console.log("");
|
|
37231
|
-
|
|
37345
|
+
clack49.note(
|
|
37232
37346
|
[
|
|
37233
37347
|
`${pc52.bold("Message ID:")} ${pc52.cyan(messageId || "unknown")}`,
|
|
37234
37348
|
`${pc52.bold("To:")} ${pc52.cyan(toNumber)}`,
|
|
@@ -37243,11 +37357,11 @@ Run ${pc52.cyan("wraps sms init")} to deploy SMS infrastructure.
|
|
|
37243
37357
|
);
|
|
37244
37358
|
if (smsConfig?.eventTracking?.enabled) {
|
|
37245
37359
|
console.log("");
|
|
37246
|
-
|
|
37360
|
+
clack49.log.info(
|
|
37247
37361
|
pc52.dim("Event tracking is enabled. Check DynamoDB for delivery status.")
|
|
37248
37362
|
);
|
|
37249
37363
|
}
|
|
37250
|
-
|
|
37364
|
+
clack49.outro(pc52.green("Test complete!"));
|
|
37251
37365
|
} catch (error) {
|
|
37252
37366
|
progress.stop();
|
|
37253
37367
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
@@ -37259,24 +37373,24 @@ Run ${pc52.cyan("wraps sms init")} to deploy SMS infrastructure.
|
|
|
37259
37373
|
});
|
|
37260
37374
|
const errorName = error instanceof Error ? error.name : "";
|
|
37261
37375
|
if (errorName === "ConflictException" || errorMessage.includes("opt-out")) {
|
|
37262
|
-
|
|
37376
|
+
clack49.log.error("Destination number has opted out of messages");
|
|
37263
37377
|
console.log("\nThe recipient has opted out of receiving SMS messages.\n");
|
|
37264
37378
|
} else if (errorName === "ThrottlingException" || errorMessage.includes("spending limit")) {
|
|
37265
|
-
|
|
37379
|
+
clack49.log.error("SMS rate or spending limit reached");
|
|
37266
37380
|
console.log(
|
|
37267
37381
|
"\nCheck your AWS account SMS spending limits in the console.\n"
|
|
37268
37382
|
);
|
|
37269
37383
|
} else if (errorName === "ValidationException") {
|
|
37270
|
-
|
|
37384
|
+
clack49.log.error(`Invalid request: ${errorMessage}`);
|
|
37271
37385
|
} else if (errorMessage.includes("not verified") || errorMessage.includes("not registered")) {
|
|
37272
|
-
|
|
37386
|
+
clack49.log.error("Toll-free number registration is not complete");
|
|
37273
37387
|
console.log(
|
|
37274
37388
|
`
|
|
37275
37389
|
Run ${pc52.cyan("wraps sms register")} to check registration status.
|
|
37276
37390
|
`
|
|
37277
37391
|
);
|
|
37278
37392
|
} else if (errorName === "AccessDeniedException") {
|
|
37279
|
-
|
|
37393
|
+
clack49.log.error(
|
|
37280
37394
|
"Permission denied \u2014 IAM role may be missing SMS send permissions"
|
|
37281
37395
|
);
|
|
37282
37396
|
console.log(
|
|
@@ -37285,7 +37399,7 @@ Run ${pc52.cyan("wraps sms upgrade")} to update IAM policies.
|
|
|
37285
37399
|
`
|
|
37286
37400
|
);
|
|
37287
37401
|
} else {
|
|
37288
|
-
|
|
37402
|
+
clack49.log.error(`Failed to send SMS: ${errorMessage}`);
|
|
37289
37403
|
}
|
|
37290
37404
|
process.exit(1);
|
|
37291
37405
|
}
|
|
@@ -37293,7 +37407,7 @@ Run ${pc52.cyan("wraps sms upgrade")} to update IAM policies.
|
|
|
37293
37407
|
|
|
37294
37408
|
// src/commands/sms/upgrade.ts
|
|
37295
37409
|
init_esm_shims();
|
|
37296
|
-
import * as
|
|
37410
|
+
import * as clack50 from "@clack/prompts";
|
|
37297
37411
|
import * as pulumi32 from "@pulumi/pulumi";
|
|
37298
37412
|
import pc53 from "picocolors";
|
|
37299
37413
|
init_events();
|
|
@@ -37305,11 +37419,12 @@ init_metadata();
|
|
|
37305
37419
|
init_output();
|
|
37306
37420
|
init_prompts();
|
|
37307
37421
|
init_pulumi();
|
|
37422
|
+
init_region_resolver();
|
|
37308
37423
|
async function smsUpgrade(options) {
|
|
37309
37424
|
const startTime = Date.now();
|
|
37310
37425
|
let upgradeAction = "";
|
|
37311
37426
|
if (!isJsonMode()) {
|
|
37312
|
-
|
|
37427
|
+
clack50.intro(pc53.bold("Wraps SMS Upgrade - Enhance Your SMS Infrastructure"));
|
|
37313
37428
|
}
|
|
37314
37429
|
const progress = new DeploymentProgress();
|
|
37315
37430
|
const wasAutoInstalled = await progress.execute(
|
|
@@ -37324,24 +37439,25 @@ async function smsUpgrade(options) {
|
|
|
37324
37439
|
async () => validateAWSCredentials()
|
|
37325
37440
|
);
|
|
37326
37441
|
progress.info(`Connected to AWS account: ${pc53.cyan(identity.accountId)}`);
|
|
37327
|
-
|
|
37328
|
-
|
|
37329
|
-
|
|
37330
|
-
|
|
37331
|
-
|
|
37442
|
+
const region = await resolveRegionForCommand({
|
|
37443
|
+
accountId: identity.accountId,
|
|
37444
|
+
optionRegion: options.region,
|
|
37445
|
+
service: "sms",
|
|
37446
|
+
label: "SMS deployment"
|
|
37447
|
+
});
|
|
37332
37448
|
const metadata = await loadConnectionMetadata(identity.accountId, region);
|
|
37333
37449
|
if (!metadata) {
|
|
37334
|
-
|
|
37450
|
+
clack50.log.error(
|
|
37335
37451
|
`No Wraps connection found for account ${pc53.cyan(identity.accountId)} in region ${pc53.cyan(region)}`
|
|
37336
37452
|
);
|
|
37337
|
-
|
|
37453
|
+
clack50.log.info(
|
|
37338
37454
|
`Use ${pc53.cyan("wraps sms init")} to create new infrastructure.`
|
|
37339
37455
|
);
|
|
37340
37456
|
process.exit(1);
|
|
37341
37457
|
}
|
|
37342
37458
|
if (!metadata.services.sms) {
|
|
37343
|
-
|
|
37344
|
-
|
|
37459
|
+
clack50.log.error("No SMS infrastructure found");
|
|
37460
|
+
clack50.log.info(
|
|
37345
37461
|
`Use ${pc53.cyan("wraps sms init")} to deploy SMS infrastructure.`
|
|
37346
37462
|
);
|
|
37347
37463
|
process.exit(1);
|
|
@@ -37357,8 +37473,8 @@ ${pc53.bold("Current Configuration:")}
|
|
|
37357
37473
|
}
|
|
37358
37474
|
const config2 = metadata.services.sms.config;
|
|
37359
37475
|
if (!config2) {
|
|
37360
|
-
|
|
37361
|
-
|
|
37476
|
+
clack50.log.error("No SMS configuration found in metadata");
|
|
37477
|
+
clack50.log.info(
|
|
37362
37478
|
`Use ${pc53.cyan("wraps sms init")} to create new infrastructure.`
|
|
37363
37479
|
);
|
|
37364
37480
|
process.exit(1);
|
|
@@ -37418,7 +37534,7 @@ ${pc53.bold("Current Configuration:")}
|
|
|
37418
37534
|
"10dlc": "10DLC",
|
|
37419
37535
|
"short-code": "Short code"
|
|
37420
37536
|
};
|
|
37421
|
-
upgradeAction = await
|
|
37537
|
+
upgradeAction = await clack50.select({
|
|
37422
37538
|
message: "What would you like to do?",
|
|
37423
37539
|
options: [
|
|
37424
37540
|
{
|
|
@@ -37458,8 +37574,8 @@ ${pc53.bold("Current Configuration:")}
|
|
|
37458
37574
|
}
|
|
37459
37575
|
]
|
|
37460
37576
|
});
|
|
37461
|
-
if (
|
|
37462
|
-
|
|
37577
|
+
if (clack50.isCancel(upgradeAction)) {
|
|
37578
|
+
clack50.cancel("Upgrade cancelled.");
|
|
37463
37579
|
process.exit(0);
|
|
37464
37580
|
}
|
|
37465
37581
|
let updatedConfig = { ...config2 };
|
|
@@ -37500,17 +37616,17 @@ ${pc53.bold("Current Configuration:")}
|
|
|
37500
37616
|
hint: p.hint
|
|
37501
37617
|
}));
|
|
37502
37618
|
if (availableTypes.length === 0) {
|
|
37503
|
-
|
|
37619
|
+
clack50.log.warn(
|
|
37504
37620
|
"Already on highest phone number tier. Contact AWS for dedicated short codes."
|
|
37505
37621
|
);
|
|
37506
37622
|
process.exit(0);
|
|
37507
37623
|
}
|
|
37508
|
-
const selectedType = await
|
|
37624
|
+
const selectedType = await clack50.select({
|
|
37509
37625
|
message: "Select new phone number type:",
|
|
37510
37626
|
options: availableTypes
|
|
37511
37627
|
});
|
|
37512
|
-
if (
|
|
37513
|
-
|
|
37628
|
+
if (clack50.isCancel(selectedType)) {
|
|
37629
|
+
clack50.cancel("Upgrade cancelled.");
|
|
37514
37630
|
process.exit(0);
|
|
37515
37631
|
}
|
|
37516
37632
|
if (selectedType === "toll-free") {
|
|
@@ -37533,12 +37649,12 @@ ${pc53.yellow("\u26A0")} ${pc53.bold("Toll-free Registration Required")}
|
|
|
37533
37649
|
console.log(
|
|
37534
37650
|
pc53.dim("\nUntil verified, sending is limited to low volume.\n")
|
|
37535
37651
|
);
|
|
37536
|
-
const confirmTollFree = await
|
|
37652
|
+
const confirmTollFree = await clack50.confirm({
|
|
37537
37653
|
message: "Continue with toll-free number request?",
|
|
37538
37654
|
initialValue: true
|
|
37539
37655
|
});
|
|
37540
|
-
if (
|
|
37541
|
-
|
|
37656
|
+
if (clack50.isCancel(confirmTollFree) || !confirmTollFree) {
|
|
37657
|
+
clack50.cancel("Upgrade cancelled.");
|
|
37542
37658
|
process.exit(0);
|
|
37543
37659
|
}
|
|
37544
37660
|
}
|
|
@@ -37553,12 +37669,12 @@ ${pc53.yellow("\u26A0")} ${pc53.bold("10DLC Campaign Registration Required")}
|
|
|
37553
37669
|
console.log(" \u2022 Campaign registration: $15/mo per campaign");
|
|
37554
37670
|
console.log(" \u2022 Verification takes 1-7 business days");
|
|
37555
37671
|
console.log("");
|
|
37556
|
-
const confirm10DLC = await
|
|
37672
|
+
const confirm10DLC = await clack50.confirm({
|
|
37557
37673
|
message: "Continue with 10DLC number request?",
|
|
37558
37674
|
initialValue: true
|
|
37559
37675
|
});
|
|
37560
|
-
if (
|
|
37561
|
-
|
|
37676
|
+
if (clack50.isCancel(confirm10DLC) || !confirm10DLC) {
|
|
37677
|
+
clack50.cancel("Upgrade cancelled.");
|
|
37562
37678
|
process.exit(0);
|
|
37563
37679
|
}
|
|
37564
37680
|
}
|
|
@@ -37583,15 +37699,15 @@ ${pc53.yellow("\u26A0")} ${pc53.bold("10DLC Campaign Registration Required")}
|
|
|
37583
37699
|
disabled: currentPresetIdx >= 0 && idx <= currentPresetIdx ? "Current or lower tier" : void 0
|
|
37584
37700
|
})).filter((p) => !p.disabled && p.value !== "custom");
|
|
37585
37701
|
if (availablePresets.length === 0) {
|
|
37586
|
-
|
|
37702
|
+
clack50.log.warn("Already on highest preset (Enterprise)");
|
|
37587
37703
|
process.exit(0);
|
|
37588
37704
|
}
|
|
37589
|
-
const selectedPreset = await
|
|
37705
|
+
const selectedPreset = await clack50.select({
|
|
37590
37706
|
message: "Select new preset:",
|
|
37591
37707
|
options: availablePresets
|
|
37592
37708
|
});
|
|
37593
|
-
if (
|
|
37594
|
-
|
|
37709
|
+
if (clack50.isCancel(selectedPreset)) {
|
|
37710
|
+
clack50.cancel("Upgrade cancelled.");
|
|
37595
37711
|
process.exit(0);
|
|
37596
37712
|
}
|
|
37597
37713
|
const presetConfig = getSMSPreset(selectedPreset);
|
|
@@ -37607,7 +37723,7 @@ ${pc53.yellow("\u26A0")} ${pc53.bold("10DLC Campaign Registration Required")}
|
|
|
37607
37723
|
}
|
|
37608
37724
|
case "event-tracking": {
|
|
37609
37725
|
if (config2.eventTracking?.enabled) {
|
|
37610
|
-
const eventAction = await
|
|
37726
|
+
const eventAction = await clack50.select({
|
|
37611
37727
|
message: "What would you like to do with event tracking?",
|
|
37612
37728
|
options: [
|
|
37613
37729
|
{
|
|
@@ -37622,17 +37738,17 @@ ${pc53.yellow("\u26A0")} ${pc53.bold("10DLC Campaign Registration Required")}
|
|
|
37622
37738
|
}
|
|
37623
37739
|
]
|
|
37624
37740
|
});
|
|
37625
|
-
if (
|
|
37626
|
-
|
|
37741
|
+
if (clack50.isCancel(eventAction)) {
|
|
37742
|
+
clack50.cancel("Upgrade cancelled.");
|
|
37627
37743
|
process.exit(0);
|
|
37628
37744
|
}
|
|
37629
37745
|
if (eventAction === "disable") {
|
|
37630
|
-
const confirmDisable = await
|
|
37746
|
+
const confirmDisable = await clack50.confirm({
|
|
37631
37747
|
message: "Are you sure? Existing history will remain, but new events won't be tracked.",
|
|
37632
37748
|
initialValue: false
|
|
37633
37749
|
});
|
|
37634
|
-
if (
|
|
37635
|
-
|
|
37750
|
+
if (clack50.isCancel(confirmDisable) || !confirmDisable) {
|
|
37751
|
+
clack50.cancel("Event tracking not disabled.");
|
|
37636
37752
|
process.exit(0);
|
|
37637
37753
|
}
|
|
37638
37754
|
updatedConfig = {
|
|
@@ -37642,7 +37758,7 @@ ${pc53.yellow("\u26A0")} ${pc53.bold("10DLC Campaign Registration Required")}
|
|
|
37642
37758
|
}
|
|
37643
37759
|
};
|
|
37644
37760
|
} else {
|
|
37645
|
-
const retention = await
|
|
37761
|
+
const retention = await clack50.select({
|
|
37646
37762
|
message: "Message history retention period:",
|
|
37647
37763
|
options: [
|
|
37648
37764
|
{ value: "7days", label: "7 days", hint: "Minimal storage cost" },
|
|
@@ -37669,8 +37785,8 @@ ${pc53.yellow("\u26A0")} ${pc53.bold("10DLC Campaign Registration Required")}
|
|
|
37669
37785
|
],
|
|
37670
37786
|
initialValue: config2.eventTracking.archiveRetention || "90days"
|
|
37671
37787
|
});
|
|
37672
|
-
if (
|
|
37673
|
-
|
|
37788
|
+
if (clack50.isCancel(retention)) {
|
|
37789
|
+
clack50.cancel("Upgrade cancelled.");
|
|
37674
37790
|
process.exit(0);
|
|
37675
37791
|
}
|
|
37676
37792
|
updatedConfig = {
|
|
@@ -37682,19 +37798,19 @@ ${pc53.yellow("\u26A0")} ${pc53.bold("10DLC Campaign Registration Required")}
|
|
|
37682
37798
|
};
|
|
37683
37799
|
}
|
|
37684
37800
|
} else {
|
|
37685
|
-
const enableTracking = await
|
|
37801
|
+
const enableTracking = await clack50.confirm({
|
|
37686
37802
|
message: "Enable event tracking? (Track SMS events with history)",
|
|
37687
37803
|
initialValue: true
|
|
37688
37804
|
});
|
|
37689
|
-
if (
|
|
37690
|
-
|
|
37805
|
+
if (clack50.isCancel(enableTracking)) {
|
|
37806
|
+
clack50.cancel("Upgrade cancelled.");
|
|
37691
37807
|
process.exit(0);
|
|
37692
37808
|
}
|
|
37693
37809
|
if (!enableTracking) {
|
|
37694
|
-
|
|
37810
|
+
clack50.log.info("Event tracking not enabled.");
|
|
37695
37811
|
process.exit(0);
|
|
37696
37812
|
}
|
|
37697
|
-
const retention = await
|
|
37813
|
+
const retention = await clack50.select({
|
|
37698
37814
|
message: "Message history retention period:",
|
|
37699
37815
|
options: [
|
|
37700
37816
|
{ value: "7days", label: "7 days", hint: "Minimal storage cost" },
|
|
@@ -37717,8 +37833,8 @@ ${pc53.yellow("\u26A0")} ${pc53.bold("10DLC Campaign Registration Required")}
|
|
|
37717
37833
|
],
|
|
37718
37834
|
initialValue: "90days"
|
|
37719
37835
|
});
|
|
37720
|
-
if (
|
|
37721
|
-
|
|
37836
|
+
if (clack50.isCancel(retention)) {
|
|
37837
|
+
clack50.cancel("Upgrade cancelled.");
|
|
37722
37838
|
process.exit(0);
|
|
37723
37839
|
}
|
|
37724
37840
|
updatedConfig = {
|
|
@@ -37737,12 +37853,12 @@ ${pc53.yellow("\u26A0")} ${pc53.bold("10DLC Campaign Registration Required")}
|
|
|
37737
37853
|
}
|
|
37738
37854
|
case "retention": {
|
|
37739
37855
|
if (!config2.eventTracking?.enabled) {
|
|
37740
|
-
|
|
37856
|
+
clack50.log.error(
|
|
37741
37857
|
"Event tracking is not enabled. Enable it first to change retention."
|
|
37742
37858
|
);
|
|
37743
37859
|
process.exit(1);
|
|
37744
37860
|
}
|
|
37745
|
-
const retention = await
|
|
37861
|
+
const retention = await clack50.select({
|
|
37746
37862
|
message: "Message history retention period (event data in DynamoDB):",
|
|
37747
37863
|
options: [
|
|
37748
37864
|
{ value: "7days", label: "7 days", hint: "Minimal storage cost" },
|
|
@@ -37761,8 +37877,8 @@ ${pc53.yellow("\u26A0")} ${pc53.bold("10DLC Campaign Registration Required")}
|
|
|
37761
37877
|
],
|
|
37762
37878
|
initialValue: config2.eventTracking.archiveRetention || "90days"
|
|
37763
37879
|
});
|
|
37764
|
-
if (
|
|
37765
|
-
|
|
37880
|
+
if (clack50.isCancel(retention)) {
|
|
37881
|
+
clack50.cancel("Upgrade cancelled.");
|
|
37766
37882
|
process.exit(0);
|
|
37767
37883
|
}
|
|
37768
37884
|
updatedConfig = {
|
|
@@ -37780,21 +37896,21 @@ ${pc53.yellow("\u26A0")} ${pc53.bold("10DLC Campaign Registration Required")}
|
|
|
37780
37896
|
case "link-tracking": {
|
|
37781
37897
|
const enableLinkTracking = !config2.tracking?.linkTracking;
|
|
37782
37898
|
if (enableLinkTracking) {
|
|
37783
|
-
|
|
37899
|
+
clack50.log.info(
|
|
37784
37900
|
pc53.dim(
|
|
37785
37901
|
"Link tracking will track clicks on URLs in your SMS messages."
|
|
37786
37902
|
)
|
|
37787
37903
|
);
|
|
37788
|
-
|
|
37904
|
+
clack50.log.info(
|
|
37789
37905
|
pc53.dim("URLs will be rewritten to go through a tracking endpoint.")
|
|
37790
37906
|
);
|
|
37791
37907
|
}
|
|
37792
|
-
const confirmed = await
|
|
37908
|
+
const confirmed = await clack50.confirm({
|
|
37793
37909
|
message: enableLinkTracking ? "Enable link click tracking?" : "Disable link click tracking?",
|
|
37794
37910
|
initialValue: enableLinkTracking
|
|
37795
37911
|
});
|
|
37796
|
-
if (
|
|
37797
|
-
|
|
37912
|
+
if (clack50.isCancel(confirmed) || !confirmed) {
|
|
37913
|
+
clack50.cancel("Upgrade cancelled.");
|
|
37798
37914
|
process.exit(0);
|
|
37799
37915
|
}
|
|
37800
37916
|
updatedConfig = {
|
|
@@ -37811,7 +37927,7 @@ ${pc53.yellow("\u26A0")} ${pc53.bold("10DLC Campaign Registration Required")}
|
|
|
37811
37927
|
}
|
|
37812
37928
|
case "archiving": {
|
|
37813
37929
|
if (config2.messageArchiving?.enabled) {
|
|
37814
|
-
const archivingAction = await
|
|
37930
|
+
const archivingAction = await clack50.select({
|
|
37815
37931
|
message: "What would you like to do with message archiving?",
|
|
37816
37932
|
options: [
|
|
37817
37933
|
{
|
|
@@ -37826,17 +37942,17 @@ ${pc53.yellow("\u26A0")} ${pc53.bold("10DLC Campaign Registration Required")}
|
|
|
37826
37942
|
}
|
|
37827
37943
|
]
|
|
37828
37944
|
});
|
|
37829
|
-
if (
|
|
37830
|
-
|
|
37945
|
+
if (clack50.isCancel(archivingAction)) {
|
|
37946
|
+
clack50.cancel("Upgrade cancelled.");
|
|
37831
37947
|
process.exit(0);
|
|
37832
37948
|
}
|
|
37833
37949
|
if (archivingAction === "disable") {
|
|
37834
|
-
const confirmDisable = await
|
|
37950
|
+
const confirmDisable = await clack50.confirm({
|
|
37835
37951
|
message: "Are you sure? Existing archived messages will remain, but new messages won't be archived.",
|
|
37836
37952
|
initialValue: false
|
|
37837
37953
|
});
|
|
37838
|
-
if (
|
|
37839
|
-
|
|
37954
|
+
if (clack50.isCancel(confirmDisable) || !confirmDisable) {
|
|
37955
|
+
clack50.cancel("Archiving not disabled.");
|
|
37840
37956
|
process.exit(0);
|
|
37841
37957
|
}
|
|
37842
37958
|
updatedConfig = {
|
|
@@ -37847,7 +37963,7 @@ ${pc53.yellow("\u26A0")} ${pc53.bold("10DLC Campaign Registration Required")}
|
|
|
37847
37963
|
}
|
|
37848
37964
|
};
|
|
37849
37965
|
} else {
|
|
37850
|
-
const retention = await
|
|
37966
|
+
const retention = await clack50.select({
|
|
37851
37967
|
message: "Message archive retention period:",
|
|
37852
37968
|
options: [
|
|
37853
37969
|
{
|
|
@@ -37878,8 +37994,8 @@ ${pc53.yellow("\u26A0")} ${pc53.bold("10DLC Campaign Registration Required")}
|
|
|
37878
37994
|
],
|
|
37879
37995
|
initialValue: config2.messageArchiving.retention
|
|
37880
37996
|
});
|
|
37881
|
-
if (
|
|
37882
|
-
|
|
37997
|
+
if (clack50.isCancel(retention)) {
|
|
37998
|
+
clack50.cancel("Upgrade cancelled.");
|
|
37883
37999
|
process.exit(0);
|
|
37884
38000
|
}
|
|
37885
38001
|
updatedConfig = {
|
|
@@ -37891,19 +38007,19 @@ ${pc53.yellow("\u26A0")} ${pc53.bold("10DLC Campaign Registration Required")}
|
|
|
37891
38007
|
};
|
|
37892
38008
|
}
|
|
37893
38009
|
} else {
|
|
37894
|
-
const enableArchiving = await
|
|
38010
|
+
const enableArchiving = await clack50.confirm({
|
|
37895
38011
|
message: "Enable message archiving? (Store full message content for viewing)",
|
|
37896
38012
|
initialValue: true
|
|
37897
38013
|
});
|
|
37898
|
-
if (
|
|
37899
|
-
|
|
38014
|
+
if (clack50.isCancel(enableArchiving)) {
|
|
38015
|
+
clack50.cancel("Upgrade cancelled.");
|
|
37900
38016
|
process.exit(0);
|
|
37901
38017
|
}
|
|
37902
38018
|
if (!enableArchiving) {
|
|
37903
|
-
|
|
38019
|
+
clack50.log.info("Message archiving not enabled.");
|
|
37904
38020
|
process.exit(0);
|
|
37905
38021
|
}
|
|
37906
|
-
const retention = await
|
|
38022
|
+
const retention = await clack50.select({
|
|
37907
38023
|
message: "Message archive retention period:",
|
|
37908
38024
|
options: [
|
|
37909
38025
|
{ value: "7days", label: "7 days", hint: "~$1-2/mo for 10k msgs" },
|
|
@@ -37930,8 +38046,8 @@ ${pc53.yellow("\u26A0")} ${pc53.bold("10DLC Campaign Registration Required")}
|
|
|
37930
38046
|
],
|
|
37931
38047
|
initialValue: "90days"
|
|
37932
38048
|
});
|
|
37933
|
-
if (
|
|
37934
|
-
|
|
38049
|
+
if (clack50.isCancel(retention)) {
|
|
38050
|
+
clack50.cancel("Upgrade cancelled.");
|
|
37935
38051
|
process.exit(0);
|
|
37936
38052
|
}
|
|
37937
38053
|
updatedConfig = {
|
|
@@ -37963,7 +38079,7 @@ ${pc53.yellow("\u26A0")} ${pc53.bold("10DLC Campaign Registration Required")}
|
|
|
37963
38079
|
const currentAllowed = config2.protectConfiguration?.allowedCountries || [
|
|
37964
38080
|
"US"
|
|
37965
38081
|
];
|
|
37966
|
-
const selectedCountries = await
|
|
38082
|
+
const selectedCountries = await clack50.multiselect({
|
|
37967
38083
|
message: "Select countries to allow SMS delivery (all others blocked):",
|
|
37968
38084
|
options: commonCountries.map((c) => ({
|
|
37969
38085
|
value: c.code,
|
|
@@ -37972,16 +38088,16 @@ ${pc53.yellow("\u26A0")} ${pc53.bold("10DLC Campaign Registration Required")}
|
|
|
37972
38088
|
initialValues: currentAllowed,
|
|
37973
38089
|
required: true
|
|
37974
38090
|
});
|
|
37975
|
-
if (
|
|
37976
|
-
|
|
38091
|
+
if (clack50.isCancel(selectedCountries)) {
|
|
38092
|
+
clack50.cancel("Upgrade cancelled.");
|
|
37977
38093
|
process.exit(0);
|
|
37978
38094
|
}
|
|
37979
|
-
const enableAIT = await
|
|
38095
|
+
const enableAIT = await clack50.confirm({
|
|
37980
38096
|
message: "Enable AIT (Artificially Inflated Traffic) filtering? (adds per-message cost)",
|
|
37981
38097
|
initialValue: config2.protectConfiguration?.aitFiltering ?? false
|
|
37982
38098
|
});
|
|
37983
|
-
if (
|
|
37984
|
-
|
|
38099
|
+
if (clack50.isCancel(enableAIT)) {
|
|
38100
|
+
clack50.cancel("Upgrade cancelled.");
|
|
37985
38101
|
process.exit(0);
|
|
37986
38102
|
}
|
|
37987
38103
|
updatedConfig = {
|
|
@@ -38015,12 +38131,12 @@ ${pc53.bold("Cost Impact:")}`);
|
|
|
38015
38131
|
}
|
|
38016
38132
|
console.log("");
|
|
38017
38133
|
if (!options.yes) {
|
|
38018
|
-
const confirmed = await
|
|
38134
|
+
const confirmed = await clack50.confirm({
|
|
38019
38135
|
message: "Proceed with upgrade?",
|
|
38020
38136
|
initialValue: true
|
|
38021
38137
|
});
|
|
38022
|
-
if (
|
|
38023
|
-
|
|
38138
|
+
if (clack50.isCancel(confirmed) || !confirmed) {
|
|
38139
|
+
clack50.cancel("Upgrade cancelled.");
|
|
38024
38140
|
process.exit(0);
|
|
38025
38141
|
}
|
|
38026
38142
|
}
|
|
@@ -38162,9 +38278,9 @@ ${pc53.bold("Cost Impact:")}`);
|
|
|
38162
38278
|
}
|
|
38163
38279
|
progress.info("Connection metadata updated");
|
|
38164
38280
|
console.log("\n");
|
|
38165
|
-
|
|
38281
|
+
clack50.log.success(pc53.green(pc53.bold("SMS infrastructure upgraded!")));
|
|
38166
38282
|
console.log("\n");
|
|
38167
|
-
|
|
38283
|
+
clack50.note(
|
|
38168
38284
|
[
|
|
38169
38285
|
`${pc53.bold("Phone Number:")} ${pc53.cyan(outputs.phoneNumber || "Provisioning...")}`,
|
|
38170
38286
|
`${pc53.bold("Phone Type:")} ${pc53.cyan(updatedConfig.phoneNumberType || "simulator")}`,
|
|
@@ -38239,7 +38355,7 @@ ${pc53.green("\u2713")} ${pc53.bold("Upgrade complete!")}
|
|
|
38239
38355
|
action: typeof upgradeAction === "string" ? upgradeAction : void 0,
|
|
38240
38356
|
duration_ms: Date.now() - startTime
|
|
38241
38357
|
});
|
|
38242
|
-
|
|
38358
|
+
clack50.outro(pc53.green("Upgrade complete!"));
|
|
38243
38359
|
}
|
|
38244
38360
|
|
|
38245
38361
|
// src/commands/sms/verify-number.ts
|
|
@@ -38258,13 +38374,13 @@ import {
|
|
|
38258
38374
|
SendDestinationNumberVerificationCodeCommand,
|
|
38259
38375
|
VerifyDestinationNumberCommand
|
|
38260
38376
|
} from "@aws-sdk/client-pinpoint-sms-voice-v2";
|
|
38261
|
-
import * as
|
|
38377
|
+
import * as clack51 from "@clack/prompts";
|
|
38262
38378
|
import pc54 from "picocolors";
|
|
38263
38379
|
async function smsVerifyNumber(options) {
|
|
38264
38380
|
const startTime = Date.now();
|
|
38265
38381
|
const progress = new DeploymentProgress();
|
|
38266
38382
|
if (!isJsonMode()) {
|
|
38267
|
-
|
|
38383
|
+
clack51.intro(pc54.bold("Wraps SMS - Verify Destination Number"));
|
|
38268
38384
|
}
|
|
38269
38385
|
const identity = await progress.execute(
|
|
38270
38386
|
"Validating AWS credentials",
|
|
@@ -38274,7 +38390,7 @@ async function smsVerifyNumber(options) {
|
|
|
38274
38390
|
const metadata = await loadConnectionMetadata(identity.accountId, region);
|
|
38275
38391
|
if (!metadata?.services?.sms) {
|
|
38276
38392
|
progress.stop();
|
|
38277
|
-
|
|
38393
|
+
clack51.log.error("No SMS infrastructure found");
|
|
38278
38394
|
console.log(
|
|
38279
38395
|
`
|
|
38280
38396
|
Run ${pc54.cyan("wraps sms init")} to deploy SMS infrastructure.
|
|
@@ -38291,7 +38407,7 @@ Run ${pc54.cyan("wraps sms init")} to deploy SMS infrastructure.
|
|
|
38291
38407
|
);
|
|
38292
38408
|
progress.stop();
|
|
38293
38409
|
if (!response.VerifiedDestinationNumbers || response.VerifiedDestinationNumbers.length === 0) {
|
|
38294
|
-
|
|
38410
|
+
clack51.log.info("No verified destination numbers found");
|
|
38295
38411
|
console.log(
|
|
38296
38412
|
`
|
|
38297
38413
|
Run ${pc54.cyan("wraps sms verify-number")} to verify a number.
|
|
@@ -38299,7 +38415,7 @@ Run ${pc54.cyan("wraps sms verify-number")} to verify a number.
|
|
|
38299
38415
|
);
|
|
38300
38416
|
} else {
|
|
38301
38417
|
console.log("\n");
|
|
38302
|
-
|
|
38418
|
+
clack51.log.info(pc54.bold("Verified Destination Numbers:"));
|
|
38303
38419
|
console.log("");
|
|
38304
38420
|
for (const num of response.VerifiedDestinationNumbers) {
|
|
38305
38421
|
const status2 = num.Status === "VERIFIED" ? pc54.green("\u2713 Verified") : pc54.yellow("\u29D6 Pending");
|
|
@@ -38321,7 +38437,7 @@ Run ${pc54.cyan("wraps sms verify-number")} to verify a number.
|
|
|
38321
38437
|
});
|
|
38322
38438
|
return;
|
|
38323
38439
|
}
|
|
38324
|
-
|
|
38440
|
+
clack51.outro(pc54.green("Done!"));
|
|
38325
38441
|
return;
|
|
38326
38442
|
} catch (error) {
|
|
38327
38443
|
progress.stop();
|
|
@@ -38329,7 +38445,7 @@ Run ${pc54.cyan("wraps sms verify-number")} to verify a number.
|
|
|
38329
38445
|
trackError("SMS_LIST_VERIFIED_FAILED", "sms:verify-number:list", {
|
|
38330
38446
|
error: errorMessage
|
|
38331
38447
|
});
|
|
38332
|
-
|
|
38448
|
+
clack51.log.error(`Failed to list verified numbers: ${errorMessage}`);
|
|
38333
38449
|
process.exit(1);
|
|
38334
38450
|
}
|
|
38335
38451
|
}
|
|
@@ -38337,7 +38453,7 @@ Run ${pc54.cyan("wraps sms verify-number")} to verify a number.
|
|
|
38337
38453
|
const phoneNumber2 = options.phoneNumber;
|
|
38338
38454
|
if (!phoneNumber2) {
|
|
38339
38455
|
progress.stop();
|
|
38340
|
-
|
|
38456
|
+
clack51.log.error("Phone number is required for deletion");
|
|
38341
38457
|
console.log(
|
|
38342
38458
|
`
|
|
38343
38459
|
Usage: ${pc54.cyan("wraps sms verify-number --delete --phone-number +14155551234")}
|
|
@@ -38354,7 +38470,7 @@ Usage: ${pc54.cyan("wraps sms verify-number --delete --phone-number +14155551234
|
|
|
38354
38470
|
const verifiedNumber = listResponse.VerifiedDestinationNumbers?.[0];
|
|
38355
38471
|
if (!verifiedNumber?.VerifiedDestinationNumberId) {
|
|
38356
38472
|
progress.stop();
|
|
38357
|
-
|
|
38473
|
+
clack51.log.error(`Number ${phoneNumber2} is not in verified list`);
|
|
38358
38474
|
process.exit(1);
|
|
38359
38475
|
}
|
|
38360
38476
|
await progress.execute(`Removing ${phoneNumber2}`, async () => {
|
|
@@ -38365,7 +38481,7 @@ Usage: ${pc54.cyan("wraps sms verify-number --delete --phone-number +14155551234
|
|
|
38365
38481
|
);
|
|
38366
38482
|
});
|
|
38367
38483
|
progress.stop();
|
|
38368
|
-
|
|
38484
|
+
clack51.log.success(`Removed ${pc54.cyan(phoneNumber2)} from verified list`);
|
|
38369
38485
|
trackCommand("sms:verify-number:delete", {
|
|
38370
38486
|
success: true,
|
|
38371
38487
|
duration_ms: Date.now() - startTime
|
|
@@ -38377,7 +38493,7 @@ Usage: ${pc54.cyan("wraps sms verify-number --delete --phone-number +14155551234
|
|
|
38377
38493
|
});
|
|
38378
38494
|
return;
|
|
38379
38495
|
}
|
|
38380
|
-
|
|
38496
|
+
clack51.outro(pc54.green("Done!"));
|
|
38381
38497
|
return;
|
|
38382
38498
|
} catch (error) {
|
|
38383
38499
|
progress.stop();
|
|
@@ -38385,7 +38501,7 @@ Usage: ${pc54.cyan("wraps sms verify-number --delete --phone-number +14155551234
|
|
|
38385
38501
|
trackError("SMS_DELETE_VERIFIED_FAILED", "sms:verify-number:delete", {
|
|
38386
38502
|
error: errorMessage
|
|
38387
38503
|
});
|
|
38388
|
-
|
|
38504
|
+
clack51.log.error(`Failed to delete verified number: ${errorMessage}`);
|
|
38389
38505
|
process.exit(1);
|
|
38390
38506
|
}
|
|
38391
38507
|
}
|
|
@@ -38398,7 +38514,7 @@ Usage: ${pc54.cyan("wraps sms verify-number --delete --phone-number +14155551234
|
|
|
38398
38514
|
);
|
|
38399
38515
|
}
|
|
38400
38516
|
if (!phoneNumber) {
|
|
38401
|
-
const result = await
|
|
38517
|
+
const result = await clack51.text({
|
|
38402
38518
|
message: "Enter phone number to verify (E.164 format):",
|
|
38403
38519
|
placeholder: "+14155551234",
|
|
38404
38520
|
validate: (value) => {
|
|
@@ -38411,14 +38527,14 @@ Usage: ${pc54.cyan("wraps sms verify-number --delete --phone-number +14155551234
|
|
|
38411
38527
|
return;
|
|
38412
38528
|
}
|
|
38413
38529
|
});
|
|
38414
|
-
if (
|
|
38415
|
-
|
|
38530
|
+
if (clack51.isCancel(result)) {
|
|
38531
|
+
clack51.cancel("Operation cancelled.");
|
|
38416
38532
|
process.exit(0);
|
|
38417
38533
|
}
|
|
38418
38534
|
phoneNumber = result;
|
|
38419
38535
|
} else if (!isValidPhoneNumber(phoneNumber)) {
|
|
38420
38536
|
progress.stop();
|
|
38421
|
-
|
|
38537
|
+
clack51.log.error(
|
|
38422
38538
|
`Invalid phone number format: ${phoneNumber}. Use E.164 format (e.g., +14155551234)`
|
|
38423
38539
|
);
|
|
38424
38540
|
process.exit(1);
|
|
@@ -38433,7 +38549,7 @@ Usage: ${pc54.cyan("wraps sms verify-number --delete --phone-number +14155551234
|
|
|
38433
38549
|
const verifiedNumber = listResponse.VerifiedDestinationNumbers?.[0];
|
|
38434
38550
|
if (!verifiedNumber?.VerifiedDestinationNumberId) {
|
|
38435
38551
|
progress.stop();
|
|
38436
|
-
|
|
38552
|
+
clack51.log.error(
|
|
38437
38553
|
`Number ${phoneNumber} not found. Run without --code first.`
|
|
38438
38554
|
);
|
|
38439
38555
|
process.exit(1);
|
|
@@ -38448,7 +38564,7 @@ Usage: ${pc54.cyan("wraps sms verify-number --delete --phone-number +14155551234
|
|
|
38448
38564
|
});
|
|
38449
38565
|
progress.stop();
|
|
38450
38566
|
console.log("\n");
|
|
38451
|
-
|
|
38567
|
+
clack51.log.success(
|
|
38452
38568
|
pc54.green(`Phone number ${pc54.cyan(phoneNumber)} verified!`)
|
|
38453
38569
|
);
|
|
38454
38570
|
console.log("");
|
|
@@ -38466,13 +38582,13 @@ Usage: ${pc54.cyan("wraps sms verify-number --delete --phone-number +14155551234
|
|
|
38466
38582
|
});
|
|
38467
38583
|
return;
|
|
38468
38584
|
}
|
|
38469
|
-
|
|
38585
|
+
clack51.outro(pc54.green("Verification complete!"));
|
|
38470
38586
|
return;
|
|
38471
38587
|
} catch (error) {
|
|
38472
38588
|
progress.stop();
|
|
38473
38589
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
38474
38590
|
if (errorMessage.includes("Invalid verification code")) {
|
|
38475
|
-
|
|
38591
|
+
clack51.log.error("Invalid verification code. Please try again.");
|
|
38476
38592
|
console.log(
|
|
38477
38593
|
`
|
|
38478
38594
|
Run ${pc54.cyan(`wraps sms verify-number --phone-number ${phoneNumber} --resend`)} to get a new code.
|
|
@@ -38482,7 +38598,7 @@ Run ${pc54.cyan(`wraps sms verify-number --phone-number ${phoneNumber} --resend`
|
|
|
38482
38598
|
trackError("SMS_VERIFY_CODE_FAILED", "sms:verify-number:confirm", {
|
|
38483
38599
|
error: errorMessage
|
|
38484
38600
|
});
|
|
38485
|
-
|
|
38601
|
+
clack51.log.error(`Verification failed: ${errorMessage}`);
|
|
38486
38602
|
}
|
|
38487
38603
|
process.exit(1);
|
|
38488
38604
|
}
|
|
@@ -38497,7 +38613,7 @@ Run ${pc54.cyan(`wraps sms verify-number --phone-number ${phoneNumber} --resend`
|
|
|
38497
38613
|
const verifiedNumber = listResponse.VerifiedDestinationNumbers?.[0];
|
|
38498
38614
|
if (!verifiedNumber?.VerifiedDestinationNumberId) {
|
|
38499
38615
|
progress.stop();
|
|
38500
|
-
|
|
38616
|
+
clack51.log.error(
|
|
38501
38617
|
`Number ${phoneNumber} not found. Run without --resend first.`
|
|
38502
38618
|
);
|
|
38503
38619
|
process.exit(1);
|
|
@@ -38511,7 +38627,7 @@ Run ${pc54.cyan(`wraps sms verify-number --phone-number ${phoneNumber} --resend`
|
|
|
38511
38627
|
);
|
|
38512
38628
|
});
|
|
38513
38629
|
progress.stop();
|
|
38514
|
-
|
|
38630
|
+
clack51.log.success(`Verification code resent to ${pc54.cyan(phoneNumber)}`);
|
|
38515
38631
|
console.log("");
|
|
38516
38632
|
console.log(
|
|
38517
38633
|
`Once you receive the code, run:
|
|
@@ -38528,7 +38644,7 @@ Run ${pc54.cyan(`wraps sms verify-number --phone-number ${phoneNumber} --resend`
|
|
|
38528
38644
|
});
|
|
38529
38645
|
return;
|
|
38530
38646
|
}
|
|
38531
|
-
|
|
38647
|
+
clack51.outro(pc54.green("Code sent!"));
|
|
38532
38648
|
return;
|
|
38533
38649
|
} catch (error) {
|
|
38534
38650
|
progress.stop();
|
|
@@ -38536,7 +38652,7 @@ Run ${pc54.cyan(`wraps sms verify-number --phone-number ${phoneNumber} --resend`
|
|
|
38536
38652
|
trackError("SMS_RESEND_CODE_FAILED", "sms:verify-number:resend", {
|
|
38537
38653
|
error: errorMessage
|
|
38538
38654
|
});
|
|
38539
|
-
|
|
38655
|
+
clack51.log.error(`Failed to resend code: ${errorMessage}`);
|
|
38540
38656
|
process.exit(1);
|
|
38541
38657
|
}
|
|
38542
38658
|
}
|
|
@@ -38556,10 +38672,10 @@ Run ${pc54.cyan(`wraps sms verify-number --phone-number ${phoneNumber} --resend`
|
|
|
38556
38672
|
});
|
|
38557
38673
|
return;
|
|
38558
38674
|
}
|
|
38559
|
-
|
|
38675
|
+
clack51.log.info(
|
|
38560
38676
|
`Number ${pc54.cyan(phoneNumber)} is already verified and ready to use!`
|
|
38561
38677
|
);
|
|
38562
|
-
|
|
38678
|
+
clack51.outro(pc54.green("Done!"));
|
|
38563
38679
|
return;
|
|
38564
38680
|
}
|
|
38565
38681
|
if (existingNumber?.Status === "PENDING") {
|
|
@@ -38583,7 +38699,7 @@ Run ${pc54.cyan(`wraps sms verify-number --phone-number ${phoneNumber} --resend`
|
|
|
38583
38699
|
});
|
|
38584
38700
|
return;
|
|
38585
38701
|
}
|
|
38586
|
-
|
|
38702
|
+
clack51.log.info(
|
|
38587
38703
|
`Verification already in progress. New code sent to ${pc54.cyan(phoneNumber)}`
|
|
38588
38704
|
);
|
|
38589
38705
|
console.log("");
|
|
@@ -38591,7 +38707,7 @@ Run ${pc54.cyan(`wraps sms verify-number --phone-number ${phoneNumber} --resend`
|
|
|
38591
38707
|
`Once you receive the code, run:
|
|
38592
38708
|
${pc54.cyan(`wraps sms verify-number --phone-number ${phoneNumber} --code YOUR_CODE`)}`
|
|
38593
38709
|
);
|
|
38594
|
-
|
|
38710
|
+
clack51.outro(pc54.green("Code sent!"));
|
|
38595
38711
|
return;
|
|
38596
38712
|
}
|
|
38597
38713
|
const createResponse = await progress.execute(
|
|
@@ -38612,11 +38728,11 @@ Run ${pc54.cyan(`wraps sms verify-number --phone-number ${phoneNumber} --resend`
|
|
|
38612
38728
|
});
|
|
38613
38729
|
progress.stop();
|
|
38614
38730
|
console.log("\n");
|
|
38615
|
-
|
|
38731
|
+
clack51.log.success(
|
|
38616
38732
|
`Verification code sent to ${pc54.cyan(phoneNumber)} via SMS`
|
|
38617
38733
|
);
|
|
38618
38734
|
console.log("");
|
|
38619
|
-
|
|
38735
|
+
clack51.note(
|
|
38620
38736
|
[
|
|
38621
38737
|
"1. Check your phone for the verification code",
|
|
38622
38738
|
"",
|
|
@@ -38639,12 +38755,12 @@ Run ${pc54.cyan(`wraps sms verify-number --phone-number ${phoneNumber} --resend`
|
|
|
38639
38755
|
});
|
|
38640
38756
|
return;
|
|
38641
38757
|
}
|
|
38642
|
-
|
|
38758
|
+
clack51.outro(pc54.green("Verification started!"));
|
|
38643
38759
|
} catch (error) {
|
|
38644
38760
|
progress.stop();
|
|
38645
38761
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
38646
38762
|
if (errorMessage.includes("already exists")) {
|
|
38647
|
-
|
|
38763
|
+
clack51.log.error("This number is already being verified");
|
|
38648
38764
|
console.log(
|
|
38649
38765
|
`
|
|
38650
38766
|
Run ${pc54.cyan(`wraps sms verify-number --phone-number ${phoneNumber} --resend`)} to get a new code.
|
|
@@ -38654,7 +38770,7 @@ Run ${pc54.cyan(`wraps sms verify-number --phone-number ${phoneNumber} --resend`
|
|
|
38654
38770
|
trackError("SMS_CREATE_VERIFIED_FAILED", "sms:verify-number:start", {
|
|
38655
38771
|
error: errorMessage
|
|
38656
38772
|
});
|
|
38657
|
-
|
|
38773
|
+
clack51.log.error(`Failed to start verification: ${errorMessage}`);
|
|
38658
38774
|
}
|
|
38659
38775
|
process.exit(1);
|
|
38660
38776
|
}
|
|
@@ -38663,11 +38779,11 @@ Run ${pc54.cyan(`wraps sms verify-number --phone-number ${phoneNumber} --resend`
|
|
|
38663
38779
|
// src/commands/support.ts
|
|
38664
38780
|
init_esm_shims();
|
|
38665
38781
|
init_events();
|
|
38666
|
-
import * as
|
|
38782
|
+
import * as clack52 from "@clack/prompts";
|
|
38667
38783
|
import pc55 from "picocolors";
|
|
38668
38784
|
async function support() {
|
|
38669
38785
|
trackCommand("support", { success: true });
|
|
38670
|
-
|
|
38786
|
+
clack52.intro(pc55.bold("Get Help with Wraps"));
|
|
38671
38787
|
console.log();
|
|
38672
38788
|
console.log(` ${pc55.bold("Email:")} ${pc55.cyan("hey@wraps.sh")}`);
|
|
38673
38789
|
console.log(
|
|
@@ -38682,20 +38798,20 @@ async function support() {
|
|
|
38682
38798
|
// src/commands/telemetry.ts
|
|
38683
38799
|
init_esm_shims();
|
|
38684
38800
|
init_client();
|
|
38685
|
-
import * as
|
|
38801
|
+
import * as clack53 from "@clack/prompts";
|
|
38686
38802
|
import pc56 from "picocolors";
|
|
38687
38803
|
async function telemetryEnable() {
|
|
38688
38804
|
const client = getTelemetryClient();
|
|
38689
38805
|
const override = client.enable();
|
|
38690
38806
|
if (override) {
|
|
38691
|
-
|
|
38807
|
+
clack53.log.warn(
|
|
38692
38808
|
"Telemetry enabled in config, but overridden by environment"
|
|
38693
38809
|
);
|
|
38694
38810
|
console.log(` Reason: ${pc56.yellow(override)}`);
|
|
38695
38811
|
console.log(` Config: ${pc56.dim(client.getConfigPath())}`);
|
|
38696
38812
|
console.log();
|
|
38697
38813
|
} else {
|
|
38698
|
-
|
|
38814
|
+
clack53.log.success(pc56.green("Telemetry enabled"));
|
|
38699
38815
|
console.log(` Config: ${pc56.dim(client.getConfigPath())}`);
|
|
38700
38816
|
console.log(`
|
|
38701
38817
|
${pc56.dim("Thank you for helping improve Wraps!")}
|
|
@@ -38705,7 +38821,7 @@ async function telemetryEnable() {
|
|
|
38705
38821
|
async function telemetryDisable() {
|
|
38706
38822
|
const client = getTelemetryClient();
|
|
38707
38823
|
client.disable();
|
|
38708
|
-
|
|
38824
|
+
clack53.log.success(pc56.green("Telemetry disabled"));
|
|
38709
38825
|
console.log(` Config: ${pc56.dim(client.getConfigPath())}`);
|
|
38710
38826
|
console.log(
|
|
38711
38827
|
`
|
|
@@ -38715,7 +38831,7 @@ async function telemetryDisable() {
|
|
|
38715
38831
|
}
|
|
38716
38832
|
async function telemetryStatus() {
|
|
38717
38833
|
const client = getTelemetryClient();
|
|
38718
|
-
|
|
38834
|
+
clack53.intro(pc56.bold("Telemetry Status"));
|
|
38719
38835
|
const override = client.getEnvOverride();
|
|
38720
38836
|
const status2 = client.isEnabled() ? pc56.green("Enabled") : pc56.red("Disabled");
|
|
38721
38837
|
console.log();
|
|
@@ -38753,7 +38869,7 @@ async function telemetryStatus() {
|
|
|
38753
38869
|
init_esm_shims();
|
|
38754
38870
|
import { existsSync as existsSync18, mkdirSync as mkdirSync2, writeFileSync } from "fs";
|
|
38755
38871
|
import { join as join20 } from "path";
|
|
38756
|
-
import * as
|
|
38872
|
+
import * as clack54 from "@clack/prompts";
|
|
38757
38873
|
import pc57 from "picocolors";
|
|
38758
38874
|
var EXAMPLE_CASCADE_WORKFLOW = `import {
|
|
38759
38875
|
defineWorkflow,
|
|
@@ -38849,30 +38965,30 @@ export default defineConfig({
|
|
|
38849
38965
|
});
|
|
38850
38966
|
`;
|
|
38851
38967
|
async function workflowInit(options = {}) {
|
|
38852
|
-
|
|
38968
|
+
clack54.intro(pc57.bgCyan(pc57.black(" wraps workflow init ")));
|
|
38853
38969
|
const wrapsDir = join20(process.cwd(), "wraps");
|
|
38854
38970
|
const workflowsDir = join20(wrapsDir, "workflows");
|
|
38855
38971
|
const configPath = join20(wrapsDir, "wraps.config.ts");
|
|
38856
38972
|
if (existsSync18(workflowsDir)) {
|
|
38857
|
-
|
|
38973
|
+
clack54.log.info(
|
|
38858
38974
|
`Workflows directory already exists at ${pc57.cyan("wraps/workflows/")}`
|
|
38859
38975
|
);
|
|
38860
38976
|
const files = existsSync18(join20(workflowsDir, "cart-recovery.ts")) || existsSync18(join20(workflowsDir, "welcome-sequence.ts"));
|
|
38861
38977
|
if (files && !options.yes) {
|
|
38862
|
-
const shouldContinue = await
|
|
38978
|
+
const shouldContinue = await clack54.confirm({
|
|
38863
38979
|
message: "Example files may already exist. Overwrite them?",
|
|
38864
38980
|
initialValue: false
|
|
38865
38981
|
});
|
|
38866
|
-
if (
|
|
38867
|
-
|
|
38982
|
+
if (clack54.isCancel(shouldContinue) || !shouldContinue) {
|
|
38983
|
+
clack54.log.info("Skipping file creation.");
|
|
38868
38984
|
showNextSteps2();
|
|
38869
|
-
|
|
38985
|
+
clack54.outro("Done!");
|
|
38870
38986
|
return;
|
|
38871
38987
|
}
|
|
38872
38988
|
}
|
|
38873
38989
|
}
|
|
38874
38990
|
try {
|
|
38875
|
-
const s =
|
|
38991
|
+
const s = clack54.spinner();
|
|
38876
38992
|
s.start("Creating workflows directory...");
|
|
38877
38993
|
mkdirSync2(workflowsDir, { recursive: true });
|
|
38878
38994
|
s.stop("Created wraps/workflows/");
|
|
@@ -38890,26 +39006,26 @@ async function workflowInit(options = {}) {
|
|
|
38890
39006
|
s.stop("Created 2 example workflows");
|
|
38891
39007
|
if (!existsSync18(configPath)) {
|
|
38892
39008
|
writeFileSync(configPath, EXAMPLE_CONFIG, "utf-8");
|
|
38893
|
-
|
|
39009
|
+
clack54.log.info(`Created ${pc57.cyan("wraps/wraps.config.ts")}`);
|
|
38894
39010
|
}
|
|
38895
|
-
|
|
39011
|
+
clack54.log.success(
|
|
38896
39012
|
`${pc57.bold("Workflows scaffolded!")} Created:
|
|
38897
39013
|
${pc57.cyan("wraps/wraps.config.ts")} \u2014 Project config
|
|
38898
39014
|
${pc57.cyan("wraps/workflows/cart-recovery.ts")} \u2014 Cross-channel cascade example
|
|
38899
39015
|
${pc57.cyan("wraps/workflows/welcome-sequence.ts")} \u2014 Welcome series example`
|
|
38900
39016
|
);
|
|
38901
39017
|
showNextSteps2();
|
|
38902
|
-
|
|
39018
|
+
clack54.outro(pc57.green("Happy orchestrating!"));
|
|
38903
39019
|
} catch (error) {
|
|
38904
|
-
|
|
39020
|
+
clack54.log.error(
|
|
38905
39021
|
`Failed to scaffold workflows: ${error instanceof Error ? error.message : String(error)}`
|
|
38906
39022
|
);
|
|
38907
|
-
|
|
39023
|
+
clack54.outro(pc57.red("Scaffolding failed."));
|
|
38908
39024
|
process.exitCode = 1;
|
|
38909
39025
|
}
|
|
38910
39026
|
}
|
|
38911
39027
|
function showNextSteps2() {
|
|
38912
|
-
|
|
39028
|
+
clack54.log.info(
|
|
38913
39029
|
`${pc57.bold("Next steps:")}
|
|
38914
39030
|
|
|
38915
39031
|
1. Edit ${pc57.cyan("wraps/wraps.config.ts")} with your org slug and domain
|
|
@@ -38968,6 +39084,7 @@ var BOOLEAN_FLAGS = [
|
|
|
38968
39084
|
"draft",
|
|
38969
39085
|
"root",
|
|
38970
39086
|
"cleanup",
|
|
39087
|
+
"reveal-secret",
|
|
38971
39088
|
"help",
|
|
38972
39089
|
"version"
|
|
38973
39090
|
];
|
|
@@ -39094,7 +39211,7 @@ function showVersion() {
|
|
|
39094
39211
|
process.exit(0);
|
|
39095
39212
|
}
|
|
39096
39213
|
function showHelp() {
|
|
39097
|
-
|
|
39214
|
+
clack55.intro(pc59.bold(`WRAPS CLI v${VERSION}`));
|
|
39098
39215
|
console.log("Deploy AWS infrastructure to your account\n");
|
|
39099
39216
|
console.log("Usage: wraps [service] <command> [options]\n");
|
|
39100
39217
|
console.log("Services:");
|
|
@@ -39300,7 +39417,7 @@ if (!primaryCommand) {
|
|
|
39300
39417
|
const telemetry = getTelemetryClient();
|
|
39301
39418
|
if (telemetry.shouldShowNotification()) {
|
|
39302
39419
|
console.log();
|
|
39303
|
-
|
|
39420
|
+
clack55.log.info(pc59.bold("Anonymous Telemetry"));
|
|
39304
39421
|
console.log(
|
|
39305
39422
|
` Wraps collects ${pc59.cyan("anonymous usage data")} to improve the CLI.`
|
|
39306
39423
|
);
|
|
@@ -39318,9 +39435,9 @@ if (!primaryCommand) {
|
|
|
39318
39435
|
telemetry.markNotificationShown();
|
|
39319
39436
|
}
|
|
39320
39437
|
trackCommand("interactive:menu", { success: true, duration_ms: 0 });
|
|
39321
|
-
|
|
39438
|
+
clack55.intro(pc59.bold(`WRAPS CLI v${VERSION}`));
|
|
39322
39439
|
console.log(" Deploy AWS infrastructure to your account.\n");
|
|
39323
|
-
const action = await
|
|
39440
|
+
const action = await clack55.select({
|
|
39324
39441
|
message: "What would you like to do?",
|
|
39325
39442
|
options: [
|
|
39326
39443
|
{
|
|
@@ -39370,13 +39487,13 @@ if (!primaryCommand) {
|
|
|
39370
39487
|
}
|
|
39371
39488
|
]
|
|
39372
39489
|
});
|
|
39373
|
-
if (
|
|
39490
|
+
if (clack55.isCancel(action)) {
|
|
39374
39491
|
trackCommand("interactive:cancel", {
|
|
39375
39492
|
success: true,
|
|
39376
39493
|
duration_ms: Date.now() - startTime
|
|
39377
39494
|
});
|
|
39378
39495
|
await telemetry.shutdown();
|
|
39379
|
-
|
|
39496
|
+
clack55.cancel("Operation cancelled.");
|
|
39380
39497
|
process.exit(0);
|
|
39381
39498
|
}
|
|
39382
39499
|
trackCommand(`interactive:${action}`, {
|
|
@@ -39455,7 +39572,7 @@ async function run() {
|
|
|
39455
39572
|
const telemetry = getTelemetryClient();
|
|
39456
39573
|
if (telemetry.shouldShowNotification()) {
|
|
39457
39574
|
console.log();
|
|
39458
|
-
|
|
39575
|
+
clack55.log.info(pc59.bold("Anonymous Telemetry"));
|
|
39459
39576
|
console.log(
|
|
39460
39577
|
` Wraps collects ${pc59.cyan("anonymous usage data")} to improve the CLI.`
|
|
39461
39578
|
);
|
|
@@ -39552,7 +39669,7 @@ async function run() {
|
|
|
39552
39669
|
break;
|
|
39553
39670
|
case "verify": {
|
|
39554
39671
|
if (!flags.domain) {
|
|
39555
|
-
|
|
39672
|
+
clack55.log.error("--domain flag is required");
|
|
39556
39673
|
console.log(
|
|
39557
39674
|
`
|
|
39558
39675
|
Usage: ${pc59.cyan("wraps email verify --domain yourapp.com")}
|
|
@@ -39591,7 +39708,8 @@ Usage: ${pc59.cyan("wraps email verify --domain yourapp.com")}
|
|
|
39591
39708
|
case "status":
|
|
39592
39709
|
await inboundStatus({
|
|
39593
39710
|
region: flags.region,
|
|
39594
|
-
json: flags.json
|
|
39711
|
+
json: flags.json,
|
|
39712
|
+
revealSecret: flags.revealSecret
|
|
39595
39713
|
});
|
|
39596
39714
|
break;
|
|
39597
39715
|
case "verify":
|
|
@@ -39625,7 +39743,7 @@ Usage: ${pc59.cyan("wraps email verify --domain yourapp.com")}
|
|
|
39625
39743
|
});
|
|
39626
39744
|
break;
|
|
39627
39745
|
default:
|
|
39628
|
-
|
|
39746
|
+
clack55.log.error(
|
|
39629
39747
|
`Unknown inbound command: ${inboundSubCommand || "(none)"}`
|
|
39630
39748
|
);
|
|
39631
39749
|
console.log(
|
|
@@ -39680,7 +39798,7 @@ Available commands: ${pc59.cyan("init")}, ${pc59.cyan("destroy")}, ${pc59.cyan("
|
|
|
39680
39798
|
break;
|
|
39681
39799
|
}
|
|
39682
39800
|
default:
|
|
39683
|
-
|
|
39801
|
+
clack55.log.error(
|
|
39684
39802
|
`Unknown reply command: ${replySubCommand || "(none)"}`
|
|
39685
39803
|
);
|
|
39686
39804
|
console.log(
|
|
@@ -39710,7 +39828,7 @@ Available commands: ${pc59.cyan("init")}, ${pc59.cyan("rotate")}, ${pc59.cyan("s
|
|
|
39710
39828
|
break;
|
|
39711
39829
|
case "verify": {
|
|
39712
39830
|
if (!flags.domain) {
|
|
39713
|
-
|
|
39831
|
+
clack55.log.error("--domain flag is required");
|
|
39714
39832
|
console.log(
|
|
39715
39833
|
`
|
|
39716
39834
|
Usage: ${pc59.cyan("wraps email domains verify --domain yourapp.com")}
|
|
@@ -39723,7 +39841,7 @@ Usage: ${pc59.cyan("wraps email domains verify --domain yourapp.com")}
|
|
|
39723
39841
|
}
|
|
39724
39842
|
case "get-dkim": {
|
|
39725
39843
|
if (!flags.domain) {
|
|
39726
|
-
|
|
39844
|
+
clack55.log.error("--domain flag is required");
|
|
39727
39845
|
console.log(
|
|
39728
39846
|
`
|
|
39729
39847
|
Usage: ${pc59.cyan("wraps email domains get-dkim --domain yourapp.com")}
|
|
@@ -39736,7 +39854,7 @@ Usage: ${pc59.cyan("wraps email domains get-dkim --domain yourapp.com")}
|
|
|
39736
39854
|
}
|
|
39737
39855
|
case "remove": {
|
|
39738
39856
|
if (!flags.domain) {
|
|
39739
|
-
|
|
39857
|
+
clack55.log.error("--domain flag is required");
|
|
39740
39858
|
console.log(
|
|
39741
39859
|
`
|
|
39742
39860
|
Usage: ${pc59.cyan("wraps email domains remove --domain yourapp.com --force")}
|
|
@@ -39751,7 +39869,7 @@ Usage: ${pc59.cyan("wraps email domains remove --domain yourapp.com --force")}
|
|
|
39751
39869
|
break;
|
|
39752
39870
|
}
|
|
39753
39871
|
default:
|
|
39754
|
-
|
|
39872
|
+
clack55.log.error(
|
|
39755
39873
|
`Unknown domains command: ${domainsSubCommand || "(none)"}`
|
|
39756
39874
|
);
|
|
39757
39875
|
console.log(
|
|
@@ -39798,7 +39916,7 @@ Available commands: ${pc59.cyan("add")}, ${pc59.cyan("list")}, ${pc59.cyan("veri
|
|
|
39798
39916
|
});
|
|
39799
39917
|
break;
|
|
39800
39918
|
default:
|
|
39801
|
-
|
|
39919
|
+
clack55.log.error(
|
|
39802
39920
|
`Unknown templates command: ${templatesSubCommand || "(none)"}`
|
|
39803
39921
|
);
|
|
39804
39922
|
console.log(
|
|
@@ -39842,7 +39960,7 @@ Available commands: ${pc59.cyan("init")}, ${pc59.cyan("push")}, ${pc59.cyan("pre
|
|
|
39842
39960
|
});
|
|
39843
39961
|
break;
|
|
39844
39962
|
default:
|
|
39845
|
-
|
|
39963
|
+
clack55.log.error(
|
|
39846
39964
|
`Unknown workflows command: ${workflowsSubCommand || "(none)"}`
|
|
39847
39965
|
);
|
|
39848
39966
|
console.log(
|
|
@@ -39872,7 +39990,7 @@ Available commands: ${pc59.cyan("init")}, ${pc59.cyan("validate")}, ${pc59.cyan(
|
|
|
39872
39990
|
});
|
|
39873
39991
|
break;
|
|
39874
39992
|
default:
|
|
39875
|
-
|
|
39993
|
+
clack55.log.error(`Unknown email command: ${subCommand}`);
|
|
39876
39994
|
console.log(
|
|
39877
39995
|
`
|
|
39878
39996
|
Run ${pc59.cyan("wraps --help")} for available commands.
|
|
@@ -39950,7 +40068,7 @@ Run ${pc59.cyan("wraps --help")} for available commands.
|
|
|
39950
40068
|
});
|
|
39951
40069
|
break;
|
|
39952
40070
|
default:
|
|
39953
|
-
|
|
40071
|
+
clack55.log.error(`Unknown sms command: ${subCommand}`);
|
|
39954
40072
|
console.log(
|
|
39955
40073
|
`
|
|
39956
40074
|
Run ${pc59.cyan("wraps --help")} for available commands.
|
|
@@ -40014,7 +40132,7 @@ Run ${pc59.cyan("wraps --help")} for available commands.
|
|
|
40014
40132
|
});
|
|
40015
40133
|
break;
|
|
40016
40134
|
default:
|
|
40017
|
-
|
|
40135
|
+
clack55.log.error(`Unknown cdn command: ${subCommand}`);
|
|
40018
40136
|
console.log(
|
|
40019
40137
|
`
|
|
40020
40138
|
Run ${pc59.cyan("wraps --help")} for available commands.
|
|
@@ -40039,7 +40157,7 @@ Run ${pc59.cyan("wraps --help")} for available commands.
|
|
|
40039
40157
|
});
|
|
40040
40158
|
break;
|
|
40041
40159
|
default:
|
|
40042
|
-
|
|
40160
|
+
clack55.log.error(
|
|
40043
40161
|
`Unknown workflow command: ${subCommand || "(none)"}`
|
|
40044
40162
|
);
|
|
40045
40163
|
console.log(`
|
|
@@ -40087,7 +40205,7 @@ Available commands: ${pc59.cyan("init")}
|
|
|
40087
40205
|
});
|
|
40088
40206
|
break;
|
|
40089
40207
|
default:
|
|
40090
|
-
|
|
40208
|
+
clack55.log.error(`Unknown platform command: ${subCommand}`);
|
|
40091
40209
|
console.log(
|
|
40092
40210
|
`
|
|
40093
40211
|
Available commands: ${pc59.cyan("connect")}, ${pc59.cyan("update-role")}
|
|
@@ -40119,7 +40237,7 @@ Available commands: ${pc59.cyan("connect")}, ${pc59.cyan("update-role")}
|
|
|
40119
40237
|
await logout();
|
|
40120
40238
|
break;
|
|
40121
40239
|
default:
|
|
40122
|
-
|
|
40240
|
+
clack55.log.error(`Unknown auth command: ${subCommand || "(none)"}`);
|
|
40123
40241
|
console.log(
|
|
40124
40242
|
`
|
|
40125
40243
|
Available commands: ${pc59.cyan("login")}, ${pc59.cyan("status")}, ${pc59.cyan("logout")}
|
|
@@ -40140,7 +40258,7 @@ Available commands: ${pc59.cyan("login")}, ${pc59.cyan("status")}, ${pc59.cyan("
|
|
|
40140
40258
|
await doctor();
|
|
40141
40259
|
break;
|
|
40142
40260
|
default:
|
|
40143
|
-
|
|
40261
|
+
clack55.log.error(`Unknown aws command: ${subCommand}`);
|
|
40144
40262
|
console.log(
|
|
40145
40263
|
`
|
|
40146
40264
|
Available commands: ${pc59.cyan("setup")}, ${pc59.cyan("doctor")}
|
|
@@ -40225,7 +40343,7 @@ Available commands: ${pc59.cyan("setup")}, ${pc59.cyan("doctor")}
|
|
|
40225
40343
|
await telemetryStatus();
|
|
40226
40344
|
break;
|
|
40227
40345
|
default:
|
|
40228
|
-
|
|
40346
|
+
clack55.log.error(`Unknown telemetry command: ${subCommand}`);
|
|
40229
40347
|
console.log(
|
|
40230
40348
|
`
|
|
40231
40349
|
Available commands: ${pc59.cyan("enable")}, ${pc59.cyan("disable")}, ${pc59.cyan("status")}
|
|
@@ -40252,7 +40370,7 @@ Please specify a command for ${primaryCommand} service.
|
|
|
40252
40370
|
showHelp();
|
|
40253
40371
|
break;
|
|
40254
40372
|
default:
|
|
40255
|
-
|
|
40373
|
+
clack55.log.error(`Unknown command: ${primaryCommand}`);
|
|
40256
40374
|
console.log(
|
|
40257
40375
|
`
|
|
40258
40376
|
Run ${pc59.cyan("wraps --help")} for available commands.
|