@wraps.dev/cli 0.1.2 → 0.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +272 -151
- package/dist/cli.js.map +1 -1
- package/dist/lambda/event-processor/.bundled +1 -0
- package/dist/lambda/event-processor/index.mjs +1 -0
- package/package.json +4 -2
- package/dist/lambda/event-processor/__tests__/index.test.ts +0 -932
- package/dist/lambda/event-processor/index.ts +0 -165
- package/dist/lambda/event-processor/package.json +0 -13
package/dist/cli.js
CHANGED
|
@@ -9,15 +9,214 @@ var __export = (target, all3) => {
|
|
|
9
9
|
__defProp(target, name, { get: all3[name], enumerable: true });
|
|
10
10
|
};
|
|
11
11
|
|
|
12
|
-
// ../../node_modules/.pnpm/tsup@8.5.0_jiti@2.6.1_postcss@8.5.6_typescript@5.8.3/node_modules/tsup/assets/esm_shims.js
|
|
12
|
+
// ../../node_modules/.pnpm/tsup@8.5.0_jiti@2.6.1_postcss@8.5.6_tsx@4.20.6_typescript@5.8.3/node_modules/tsup/assets/esm_shims.js
|
|
13
13
|
import path from "path";
|
|
14
14
|
import { fileURLToPath } from "url";
|
|
15
15
|
var init_esm_shims = __esm({
|
|
16
|
-
"../../node_modules/.pnpm/tsup@8.5.0_jiti@2.6.1_postcss@8.5.6_typescript@5.8.3/node_modules/tsup/assets/esm_shims.js"() {
|
|
16
|
+
"../../node_modules/.pnpm/tsup@8.5.0_jiti@2.6.1_postcss@8.5.6_tsx@4.20.6_typescript@5.8.3/node_modules/tsup/assets/esm_shims.js"() {
|
|
17
17
|
"use strict";
|
|
18
18
|
}
|
|
19
19
|
});
|
|
20
20
|
|
|
21
|
+
// src/utils/errors.ts
|
|
22
|
+
import * as clack from "@clack/prompts";
|
|
23
|
+
import pc from "picocolors";
|
|
24
|
+
function handleCLIError(error) {
|
|
25
|
+
console.error("");
|
|
26
|
+
if (error instanceof WrapsError) {
|
|
27
|
+
clack.log.error(error.message);
|
|
28
|
+
if (error.suggestion) {
|
|
29
|
+
console.log(`
|
|
30
|
+
${pc.yellow("Suggestion:")}`);
|
|
31
|
+
console.log(` ${pc.white(error.suggestion)}
|
|
32
|
+
`);
|
|
33
|
+
}
|
|
34
|
+
if (error.docsUrl) {
|
|
35
|
+
console.log(`${pc.dim("Documentation:")}`);
|
|
36
|
+
console.log(` ${pc.blue(error.docsUrl)}
|
|
37
|
+
`);
|
|
38
|
+
}
|
|
39
|
+
process.exit(1);
|
|
40
|
+
}
|
|
41
|
+
clack.log.error("An unexpected error occurred");
|
|
42
|
+
console.error(error);
|
|
43
|
+
console.log(`
|
|
44
|
+
${pc.dim("If this persists, please report at:")}`);
|
|
45
|
+
console.log(` ${pc.blue("https://github.com/wraps-team/wraps/issues")}
|
|
46
|
+
`);
|
|
47
|
+
process.exit(1);
|
|
48
|
+
}
|
|
49
|
+
var WrapsError, errors;
|
|
50
|
+
var init_errors = __esm({
|
|
51
|
+
"src/utils/errors.ts"() {
|
|
52
|
+
"use strict";
|
|
53
|
+
init_esm_shims();
|
|
54
|
+
WrapsError = class extends Error {
|
|
55
|
+
constructor(message, code, suggestion, docsUrl) {
|
|
56
|
+
super(message);
|
|
57
|
+
this.code = code;
|
|
58
|
+
this.suggestion = suggestion;
|
|
59
|
+
this.docsUrl = docsUrl;
|
|
60
|
+
this.name = "WrapsError";
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
errors = {
|
|
64
|
+
noAWSCredentials: () => new WrapsError(
|
|
65
|
+
"AWS credentials not found",
|
|
66
|
+
"NO_AWS_CREDENTIALS",
|
|
67
|
+
"Run: aws configure\nOr set AWS_PROFILE environment variable",
|
|
68
|
+
"https://docs.wraps.dev/setup/aws-credentials"
|
|
69
|
+
),
|
|
70
|
+
stackExists: (stackName) => new WrapsError(
|
|
71
|
+
`Stack "${stackName}" already exists`,
|
|
72
|
+
"STACK_EXISTS",
|
|
73
|
+
`To update: wraps upgrade
|
|
74
|
+
To remove: wraps destroy --stack ${stackName}`,
|
|
75
|
+
"https://docs.wraps.dev/cli/upgrade"
|
|
76
|
+
),
|
|
77
|
+
invalidRegion: (region) => new WrapsError(
|
|
78
|
+
`Invalid AWS region: ${region}`,
|
|
79
|
+
"INVALID_REGION",
|
|
80
|
+
"Use a valid AWS region like: us-east-1, eu-west-1, ap-southeast-1",
|
|
81
|
+
"https://docs.aws.amazon.com/general/latest/gr/rande.html"
|
|
82
|
+
),
|
|
83
|
+
pulumiError: (message) => new WrapsError(
|
|
84
|
+
`Infrastructure deployment failed: ${message}`,
|
|
85
|
+
"PULUMI_ERROR",
|
|
86
|
+
"Check your AWS permissions and try again",
|
|
87
|
+
"https://docs.wraps.dev/troubleshooting"
|
|
88
|
+
),
|
|
89
|
+
noStack: () => new WrapsError(
|
|
90
|
+
"No Wraps infrastructure found in this AWS account",
|
|
91
|
+
"NO_STACK",
|
|
92
|
+
"Run: wraps init\nTo deploy new infrastructure",
|
|
93
|
+
"https://docs.wraps.dev/cli/init"
|
|
94
|
+
),
|
|
95
|
+
pulumiNotInstalled: () => new WrapsError(
|
|
96
|
+
"Pulumi CLI is not installed",
|
|
97
|
+
"PULUMI_NOT_INSTALLED",
|
|
98
|
+
"Install Pulumi:\n macOS: brew install pulumi/tap/pulumi\n Linux: curl -fsSL https://get.pulumi.com | sh\n Windows: choco install pulumi\n\nOr download from: https://www.pulumi.com/docs/install/",
|
|
99
|
+
"https://www.pulumi.com/docs/install/"
|
|
100
|
+
)
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
// src/utils/aws.ts
|
|
106
|
+
var aws_exports = {};
|
|
107
|
+
__export(aws_exports, {
|
|
108
|
+
checkRegion: () => checkRegion,
|
|
109
|
+
getAWSRegion: () => getAWSRegion,
|
|
110
|
+
isSESSandbox: () => isSESSandbox,
|
|
111
|
+
listSESDomains: () => listSESDomains,
|
|
112
|
+
validateAWSCredentials: () => validateAWSCredentials
|
|
113
|
+
});
|
|
114
|
+
import {
|
|
115
|
+
GetIdentityVerificationAttributesCommand,
|
|
116
|
+
ListIdentitiesCommand,
|
|
117
|
+
SESClient
|
|
118
|
+
} from "@aws-sdk/client-ses";
|
|
119
|
+
import { GetCallerIdentityCommand, STSClient } from "@aws-sdk/client-sts";
|
|
120
|
+
async function validateAWSCredentials() {
|
|
121
|
+
const sts = new STSClient({ region: "us-east-1" });
|
|
122
|
+
try {
|
|
123
|
+
const identity = await sts.send(new GetCallerIdentityCommand({}));
|
|
124
|
+
return {
|
|
125
|
+
accountId: identity.Account,
|
|
126
|
+
userId: identity.UserId,
|
|
127
|
+
arn: identity.Arn
|
|
128
|
+
};
|
|
129
|
+
} catch (_error) {
|
|
130
|
+
throw errors.noAWSCredentials();
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
async function checkRegion(region) {
|
|
134
|
+
const validRegions = [
|
|
135
|
+
"us-east-1",
|
|
136
|
+
"us-east-2",
|
|
137
|
+
"us-west-1",
|
|
138
|
+
"us-west-2",
|
|
139
|
+
"af-south-1",
|
|
140
|
+
"ap-east-1",
|
|
141
|
+
"ap-south-1",
|
|
142
|
+
"ap-northeast-1",
|
|
143
|
+
"ap-northeast-2",
|
|
144
|
+
"ap-northeast-3",
|
|
145
|
+
"ap-southeast-1",
|
|
146
|
+
"ap-southeast-2",
|
|
147
|
+
"ap-southeast-3",
|
|
148
|
+
"ca-central-1",
|
|
149
|
+
"eu-central-1",
|
|
150
|
+
"eu-west-1",
|
|
151
|
+
"eu-west-2",
|
|
152
|
+
"eu-west-3",
|
|
153
|
+
"eu-south-1",
|
|
154
|
+
"eu-north-1",
|
|
155
|
+
"me-south-1",
|
|
156
|
+
"sa-east-1"
|
|
157
|
+
];
|
|
158
|
+
return validRegions.includes(region);
|
|
159
|
+
}
|
|
160
|
+
async function getAWSRegion() {
|
|
161
|
+
if (process.env.AWS_REGION) {
|
|
162
|
+
return process.env.AWS_REGION;
|
|
163
|
+
}
|
|
164
|
+
if (process.env.AWS_DEFAULT_REGION) {
|
|
165
|
+
return process.env.AWS_DEFAULT_REGION;
|
|
166
|
+
}
|
|
167
|
+
return "us-east-1";
|
|
168
|
+
}
|
|
169
|
+
async function listSESDomains(region) {
|
|
170
|
+
const ses = new SESClient({ region });
|
|
171
|
+
try {
|
|
172
|
+
const identitiesResponse = await ses.send(
|
|
173
|
+
new ListIdentitiesCommand({
|
|
174
|
+
IdentityType: "Domain"
|
|
175
|
+
})
|
|
176
|
+
);
|
|
177
|
+
const identities = identitiesResponse.Identities || [];
|
|
178
|
+
if (identities.length === 0) {
|
|
179
|
+
return [];
|
|
180
|
+
}
|
|
181
|
+
const attributesResponse = await ses.send(
|
|
182
|
+
new GetIdentityVerificationAttributesCommand({
|
|
183
|
+
Identities: identities
|
|
184
|
+
})
|
|
185
|
+
);
|
|
186
|
+
const attributes = attributesResponse.VerificationAttributes || {};
|
|
187
|
+
return identities.map((domain) => ({
|
|
188
|
+
domain,
|
|
189
|
+
verified: attributes[domain]?.VerificationStatus === "Success"
|
|
190
|
+
}));
|
|
191
|
+
} catch (error) {
|
|
192
|
+
console.error("Error listing SES domains:", error);
|
|
193
|
+
return [];
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
async function isSESSandbox(region) {
|
|
197
|
+
const ses = new SESClient({ region });
|
|
198
|
+
try {
|
|
199
|
+
await ses.send(
|
|
200
|
+
new ListIdentitiesCommand({
|
|
201
|
+
MaxItems: 1
|
|
202
|
+
})
|
|
203
|
+
);
|
|
204
|
+
return false;
|
|
205
|
+
} catch (error) {
|
|
206
|
+
if (error.name === "InvalidParameterValue") {
|
|
207
|
+
return true;
|
|
208
|
+
}
|
|
209
|
+
throw error;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
var init_aws = __esm({
|
|
213
|
+
"src/utils/aws.ts"() {
|
|
214
|
+
"use strict";
|
|
215
|
+
init_esm_shims();
|
|
216
|
+
init_errors();
|
|
217
|
+
}
|
|
218
|
+
});
|
|
219
|
+
|
|
21
220
|
// src/utils/costs.ts
|
|
22
221
|
function estimateStorageSize(emailsPerMonth, retention, numEventTypes = 8) {
|
|
23
222
|
const avgRecordSizeKB = 2;
|
|
@@ -78,17 +277,16 @@ function calculateDynamoDBCost(config, emailsPerMonth) {
|
|
|
78
277
|
const storageCost = Math.max(0, storageGB - FREE_TIER.DYNAMODB_STORAGE_GB) * AWS_PRICING.DYNAMODB_STORAGE_PER_GB;
|
|
79
278
|
return {
|
|
80
279
|
monthly: writeCost + storageCost,
|
|
81
|
-
description: `Email history (${retention}, ~${storageGB.toFixed(
|
|
280
|
+
description: `Email history (${retention}, ~${storageGB.toFixed(2)} GB at steady-state, ${numEventTypes} event types)`
|
|
82
281
|
};
|
|
83
282
|
}
|
|
84
283
|
function calculateTrackingCost(config) {
|
|
85
284
|
if (!config.tracking?.enabled) {
|
|
86
285
|
return;
|
|
87
286
|
}
|
|
88
|
-
const cost = config.tracking.customRedirectDomain ? 0.5 : 0;
|
|
89
287
|
return {
|
|
90
|
-
monthly:
|
|
91
|
-
description:
|
|
288
|
+
monthly: 0,
|
|
289
|
+
description: "Open/click tracking (no additional cost)"
|
|
92
290
|
};
|
|
93
291
|
}
|
|
94
292
|
function calculateReputationMetricsCost(config) {
|
|
@@ -1334,7 +1532,10 @@ async function createIAMRole(config) {
|
|
|
1334
1532
|
"dynamodb:Scan",
|
|
1335
1533
|
"dynamodb:BatchGetItem"
|
|
1336
1534
|
],
|
|
1337
|
-
Resource:
|
|
1535
|
+
Resource: [
|
|
1536
|
+
"arn:aws:dynamodb:*:*:table/wraps-email-*",
|
|
1537
|
+
"arn:aws:dynamodb:*:*:table/wraps-email-*/index/*"
|
|
1538
|
+
]
|
|
1338
1539
|
});
|
|
1339
1540
|
}
|
|
1340
1541
|
if (config.emailConfig.eventTracking?.enabled) {
|
|
@@ -1387,14 +1588,33 @@ function getPackageRoot() {
|
|
|
1387
1588
|
}
|
|
1388
1589
|
throw new Error("Could not find package.json");
|
|
1389
1590
|
}
|
|
1390
|
-
async function
|
|
1591
|
+
async function getLambdaCode(functionName) {
|
|
1592
|
+
const packageRoot = getPackageRoot();
|
|
1593
|
+
const distLambdaPath = join(packageRoot, "dist", "lambda", functionName);
|
|
1594
|
+
const distBundleMarker = join(distLambdaPath, ".bundled");
|
|
1595
|
+
if (existsSync(distBundleMarker)) {
|
|
1596
|
+
return distLambdaPath;
|
|
1597
|
+
}
|
|
1598
|
+
const lambdaPath = join(packageRoot, "lambda", functionName);
|
|
1599
|
+
const lambdaBundleMarker = join(lambdaPath, ".bundled");
|
|
1600
|
+
if (existsSync(lambdaBundleMarker)) {
|
|
1601
|
+
return lambdaPath;
|
|
1602
|
+
}
|
|
1603
|
+
const sourcePath = join(lambdaPath, "index.ts");
|
|
1604
|
+
if (!existsSync(sourcePath)) {
|
|
1605
|
+
throw new Error(
|
|
1606
|
+
`Lambda source not found: ${sourcePath}
|
|
1607
|
+
This usually means the build process didn't complete successfully.
|
|
1608
|
+
Try running: pnpm build`
|
|
1609
|
+
);
|
|
1610
|
+
}
|
|
1391
1611
|
const buildId = randomBytes(8).toString("hex");
|
|
1392
1612
|
const outdir = join(tmpdir(), `wraps-lambda-${buildId}`);
|
|
1393
1613
|
if (!existsSync(outdir)) {
|
|
1394
1614
|
mkdirSync(outdir, { recursive: true });
|
|
1395
1615
|
}
|
|
1396
1616
|
await build({
|
|
1397
|
-
entryPoints: [
|
|
1617
|
+
entryPoints: [sourcePath],
|
|
1398
1618
|
bundle: true,
|
|
1399
1619
|
platform: "node",
|
|
1400
1620
|
target: "node20",
|
|
@@ -1408,10 +1628,7 @@ async function bundleLambda(functionPath) {
|
|
|
1408
1628
|
return outdir;
|
|
1409
1629
|
}
|
|
1410
1630
|
async function deployLambdaFunctions(config) {
|
|
1411
|
-
const
|
|
1412
|
-
const lambdaDir = join(packageRoot, "lambda");
|
|
1413
|
-
const eventProcessorPath = join(lambdaDir, "event-processor", "index.ts");
|
|
1414
|
-
const eventProcessorBundle = await bundleLambda(eventProcessorPath);
|
|
1631
|
+
const eventProcessorCode = await getLambdaCode("event-processor");
|
|
1415
1632
|
const lambdaRole = new aws4.iam.Role("wraps-email-lambda-role", {
|
|
1416
1633
|
assumeRolePolicy: JSON.stringify({
|
|
1417
1634
|
Version: "2012-10-17",
|
|
@@ -1473,7 +1690,7 @@ async function deployLambdaFunctions(config) {
|
|
|
1473
1690
|
runtime: aws4.lambda.Runtime.NodeJS20dX,
|
|
1474
1691
|
handler: "index.handler",
|
|
1475
1692
|
role: lambdaRole.arn,
|
|
1476
|
-
code: new pulumi3.asset.FileArchive(
|
|
1693
|
+
code: new pulumi3.asset.FileArchive(eventProcessorCode),
|
|
1477
1694
|
timeout: 300,
|
|
1478
1695
|
// 5 minutes (matches SQS visibility timeout)
|
|
1479
1696
|
memorySize: 512,
|
|
@@ -1714,143 +1931,8 @@ async function deployEmailStack(config) {
|
|
|
1714
1931
|
};
|
|
1715
1932
|
}
|
|
1716
1933
|
|
|
1717
|
-
// src/
|
|
1718
|
-
|
|
1719
|
-
import {
|
|
1720
|
-
GetIdentityVerificationAttributesCommand,
|
|
1721
|
-
ListIdentitiesCommand,
|
|
1722
|
-
SESClient
|
|
1723
|
-
} from "@aws-sdk/client-ses";
|
|
1724
|
-
import { GetCallerIdentityCommand, STSClient } from "@aws-sdk/client-sts";
|
|
1725
|
-
|
|
1726
|
-
// src/utils/errors.ts
|
|
1727
|
-
init_esm_shims();
|
|
1728
|
-
import * as clack from "@clack/prompts";
|
|
1729
|
-
import pc from "picocolors";
|
|
1730
|
-
var WrapsError = class extends Error {
|
|
1731
|
-
constructor(message, code, suggestion, docsUrl) {
|
|
1732
|
-
super(message);
|
|
1733
|
-
this.code = code;
|
|
1734
|
-
this.suggestion = suggestion;
|
|
1735
|
-
this.docsUrl = docsUrl;
|
|
1736
|
-
this.name = "WrapsError";
|
|
1737
|
-
}
|
|
1738
|
-
};
|
|
1739
|
-
function handleCLIError(error) {
|
|
1740
|
-
console.error("");
|
|
1741
|
-
if (error instanceof WrapsError) {
|
|
1742
|
-
clack.log.error(error.message);
|
|
1743
|
-
if (error.suggestion) {
|
|
1744
|
-
console.log(`
|
|
1745
|
-
${pc.yellow("Suggestion:")}`);
|
|
1746
|
-
console.log(` ${pc.white(error.suggestion)}
|
|
1747
|
-
`);
|
|
1748
|
-
}
|
|
1749
|
-
if (error.docsUrl) {
|
|
1750
|
-
console.log(`${pc.dim("Documentation:")}`);
|
|
1751
|
-
console.log(` ${pc.blue(error.docsUrl)}
|
|
1752
|
-
`);
|
|
1753
|
-
}
|
|
1754
|
-
process.exit(1);
|
|
1755
|
-
}
|
|
1756
|
-
clack.log.error("An unexpected error occurred");
|
|
1757
|
-
console.error(error);
|
|
1758
|
-
console.log(`
|
|
1759
|
-
${pc.dim("If this persists, please report at:")}`);
|
|
1760
|
-
console.log(` ${pc.blue("https://github.com/wraps-team/wraps/issues")}
|
|
1761
|
-
`);
|
|
1762
|
-
process.exit(1);
|
|
1763
|
-
}
|
|
1764
|
-
var errors = {
|
|
1765
|
-
noAWSCredentials: () => new WrapsError(
|
|
1766
|
-
"AWS credentials not found",
|
|
1767
|
-
"NO_AWS_CREDENTIALS",
|
|
1768
|
-
"Run: aws configure\nOr set AWS_PROFILE environment variable",
|
|
1769
|
-
"https://docs.wraps.dev/setup/aws-credentials"
|
|
1770
|
-
),
|
|
1771
|
-
stackExists: (stackName) => new WrapsError(
|
|
1772
|
-
`Stack "${stackName}" already exists`,
|
|
1773
|
-
"STACK_EXISTS",
|
|
1774
|
-
`To update: wraps upgrade
|
|
1775
|
-
To remove: wraps destroy --stack ${stackName}`,
|
|
1776
|
-
"https://docs.wraps.dev/cli/upgrade"
|
|
1777
|
-
),
|
|
1778
|
-
invalidRegion: (region) => new WrapsError(
|
|
1779
|
-
`Invalid AWS region: ${region}`,
|
|
1780
|
-
"INVALID_REGION",
|
|
1781
|
-
"Use a valid AWS region like: us-east-1, eu-west-1, ap-southeast-1",
|
|
1782
|
-
"https://docs.aws.amazon.com/general/latest/gr/rande.html"
|
|
1783
|
-
),
|
|
1784
|
-
pulumiError: (message) => new WrapsError(
|
|
1785
|
-
`Infrastructure deployment failed: ${message}`,
|
|
1786
|
-
"PULUMI_ERROR",
|
|
1787
|
-
"Check your AWS permissions and try again",
|
|
1788
|
-
"https://docs.wraps.dev/troubleshooting"
|
|
1789
|
-
),
|
|
1790
|
-
noStack: () => new WrapsError(
|
|
1791
|
-
"No Wraps infrastructure found in this AWS account",
|
|
1792
|
-
"NO_STACK",
|
|
1793
|
-
"Run: wraps init\nTo deploy new infrastructure",
|
|
1794
|
-
"https://docs.wraps.dev/cli/init"
|
|
1795
|
-
),
|
|
1796
|
-
pulumiNotInstalled: () => new WrapsError(
|
|
1797
|
-
"Pulumi CLI is not installed",
|
|
1798
|
-
"PULUMI_NOT_INSTALLED",
|
|
1799
|
-
"Install Pulumi:\n macOS: brew install pulumi/tap/pulumi\n Linux: curl -fsSL https://get.pulumi.com | sh\n Windows: choco install pulumi\n\nOr download from: https://www.pulumi.com/docs/install/",
|
|
1800
|
-
"https://www.pulumi.com/docs/install/"
|
|
1801
|
-
)
|
|
1802
|
-
};
|
|
1803
|
-
|
|
1804
|
-
// src/utils/aws.ts
|
|
1805
|
-
async function validateAWSCredentials() {
|
|
1806
|
-
const sts = new STSClient({ region: "us-east-1" });
|
|
1807
|
-
try {
|
|
1808
|
-
const identity = await sts.send(new GetCallerIdentityCommand({}));
|
|
1809
|
-
return {
|
|
1810
|
-
accountId: identity.Account,
|
|
1811
|
-
userId: identity.UserId,
|
|
1812
|
-
arn: identity.Arn
|
|
1813
|
-
};
|
|
1814
|
-
} catch (_error) {
|
|
1815
|
-
throw errors.noAWSCredentials();
|
|
1816
|
-
}
|
|
1817
|
-
}
|
|
1818
|
-
async function getAWSRegion() {
|
|
1819
|
-
if (process.env.AWS_REGION) {
|
|
1820
|
-
return process.env.AWS_REGION;
|
|
1821
|
-
}
|
|
1822
|
-
if (process.env.AWS_DEFAULT_REGION) {
|
|
1823
|
-
return process.env.AWS_DEFAULT_REGION;
|
|
1824
|
-
}
|
|
1825
|
-
return "us-east-1";
|
|
1826
|
-
}
|
|
1827
|
-
async function listSESDomains(region) {
|
|
1828
|
-
const ses = new SESClient({ region });
|
|
1829
|
-
try {
|
|
1830
|
-
const identitiesResponse = await ses.send(
|
|
1831
|
-
new ListIdentitiesCommand({
|
|
1832
|
-
IdentityType: "Domain"
|
|
1833
|
-
})
|
|
1834
|
-
);
|
|
1835
|
-
const identities = identitiesResponse.Identities || [];
|
|
1836
|
-
if (identities.length === 0) {
|
|
1837
|
-
return [];
|
|
1838
|
-
}
|
|
1839
|
-
const attributesResponse = await ses.send(
|
|
1840
|
-
new GetIdentityVerificationAttributesCommand({
|
|
1841
|
-
Identities: identities
|
|
1842
|
-
})
|
|
1843
|
-
);
|
|
1844
|
-
const attributes = attributesResponse.VerificationAttributes || {};
|
|
1845
|
-
return identities.map((domain) => ({
|
|
1846
|
-
domain,
|
|
1847
|
-
verified: attributes[domain]?.VerificationStatus === "Success"
|
|
1848
|
-
}));
|
|
1849
|
-
} catch (error) {
|
|
1850
|
-
console.error("Error listing SES domains:", error);
|
|
1851
|
-
return [];
|
|
1852
|
-
}
|
|
1853
|
-
}
|
|
1934
|
+
// src/commands/connect.ts
|
|
1935
|
+
init_aws();
|
|
1854
1936
|
|
|
1855
1937
|
// src/utils/fs.ts
|
|
1856
1938
|
init_esm_shims();
|
|
@@ -2219,6 +2301,7 @@ init_prompts();
|
|
|
2219
2301
|
|
|
2220
2302
|
// src/utils/pulumi.ts
|
|
2221
2303
|
init_esm_shims();
|
|
2304
|
+
init_errors();
|
|
2222
2305
|
import { exec } from "child_process";
|
|
2223
2306
|
import { promisify } from "util";
|
|
2224
2307
|
import * as automation2 from "@pulumi/pulumi/automation/index.js";
|
|
@@ -3787,6 +3870,7 @@ async function startConsoleServer(config) {
|
|
|
3787
3870
|
}
|
|
3788
3871
|
|
|
3789
3872
|
// src/commands/console.ts
|
|
3873
|
+
init_aws();
|
|
3790
3874
|
async function runConsole(options) {
|
|
3791
3875
|
clack5.intro(pc5.bold("Wraps Console"));
|
|
3792
3876
|
const progress = new DeploymentProgress();
|
|
@@ -3838,6 +3922,7 @@ async function runConsole(options) {
|
|
|
3838
3922
|
|
|
3839
3923
|
// src/commands/destroy.ts
|
|
3840
3924
|
init_esm_shims();
|
|
3925
|
+
init_aws();
|
|
3841
3926
|
import * as clack6 from "@clack/prompts";
|
|
3842
3927
|
import * as pulumi7 from "@pulumi/pulumi";
|
|
3843
3928
|
import pc6 from "picocolors";
|
|
@@ -3906,6 +3991,7 @@ init_esm_shims();
|
|
|
3906
3991
|
import * as clack7 from "@clack/prompts";
|
|
3907
3992
|
import * as pulumi8 from "@pulumi/pulumi";
|
|
3908
3993
|
import pc7 from "picocolors";
|
|
3994
|
+
init_aws();
|
|
3909
3995
|
init_costs();
|
|
3910
3996
|
init_presets();
|
|
3911
3997
|
init_prompts();
|
|
@@ -4112,6 +4198,7 @@ async function init(options) {
|
|
|
4112
4198
|
|
|
4113
4199
|
// src/commands/restore.ts
|
|
4114
4200
|
init_esm_shims();
|
|
4201
|
+
init_aws();
|
|
4115
4202
|
import * as clack8 from "@clack/prompts";
|
|
4116
4203
|
import * as pulumi9 from "@pulumi/pulumi";
|
|
4117
4204
|
import pc8 from "picocolors";
|
|
@@ -4216,6 +4303,7 @@ ${pc8.green("\u2713")} ${pc8.bold("Infrastructure removed successfully!")}
|
|
|
4216
4303
|
|
|
4217
4304
|
// src/commands/status.ts
|
|
4218
4305
|
init_esm_shims();
|
|
4306
|
+
init_aws();
|
|
4219
4307
|
import * as clack9 from "@clack/prompts";
|
|
4220
4308
|
import * as pulumi10 from "@pulumi/pulumi";
|
|
4221
4309
|
import pc9 from "picocolors";
|
|
@@ -4286,6 +4374,7 @@ init_esm_shims();
|
|
|
4286
4374
|
import * as clack10 from "@clack/prompts";
|
|
4287
4375
|
import * as pulumi11 from "@pulumi/pulumi";
|
|
4288
4376
|
import pc10 from "picocolors";
|
|
4377
|
+
init_aws();
|
|
4289
4378
|
init_costs();
|
|
4290
4379
|
init_presets();
|
|
4291
4380
|
init_prompts();
|
|
@@ -4435,6 +4524,36 @@ ${pc10.bold("Current Configuration:")}
|
|
|
4435
4524
|
break;
|
|
4436
4525
|
}
|
|
4437
4526
|
case "tracking-domain": {
|
|
4527
|
+
if (!config.domain) {
|
|
4528
|
+
clack10.log.error(
|
|
4529
|
+
"No sending domain configured. You must configure a sending domain before adding a custom tracking domain."
|
|
4530
|
+
);
|
|
4531
|
+
clack10.log.info(
|
|
4532
|
+
`Use ${pc10.cyan("wraps init")} to set up a sending domain first.`
|
|
4533
|
+
);
|
|
4534
|
+
process.exit(1);
|
|
4535
|
+
}
|
|
4536
|
+
const { listSESDomains: listSESDomains2 } = await Promise.resolve().then(() => (init_aws(), aws_exports));
|
|
4537
|
+
const domains = await progress.execute(
|
|
4538
|
+
"Checking domain verification status",
|
|
4539
|
+
async () => await listSESDomains2(region)
|
|
4540
|
+
);
|
|
4541
|
+
const sendingDomain = domains.find((d) => d.domain === config.domain);
|
|
4542
|
+
if (!sendingDomain?.verified) {
|
|
4543
|
+
clack10.log.error(
|
|
4544
|
+
`Sending domain ${pc10.cyan(config.domain)} is not verified.`
|
|
4545
|
+
);
|
|
4546
|
+
clack10.log.info(
|
|
4547
|
+
"You must verify your sending domain before adding a custom tracking domain."
|
|
4548
|
+
);
|
|
4549
|
+
clack10.log.info(
|
|
4550
|
+
`Use ${pc10.cyan("wraps verify")} to check DNS records and complete verification.`
|
|
4551
|
+
);
|
|
4552
|
+
process.exit(1);
|
|
4553
|
+
}
|
|
4554
|
+
progress.info(
|
|
4555
|
+
`Sending domain ${pc10.cyan(config.domain)} is verified ${pc10.green("\u2713")}`
|
|
4556
|
+
);
|
|
4438
4557
|
const trackingDomain = await clack10.text({
|
|
4439
4558
|
message: "Custom tracking redirect domain:",
|
|
4440
4559
|
placeholder: "track.yourdomain.com",
|
|
@@ -4726,6 +4845,7 @@ ${pc10.green("\u2713")} ${pc10.bold("Upgrade complete!")}
|
|
|
4726
4845
|
|
|
4727
4846
|
// src/commands/verify.ts
|
|
4728
4847
|
init_esm_shims();
|
|
4848
|
+
init_aws();
|
|
4729
4849
|
import { Resolver } from "dns/promises";
|
|
4730
4850
|
import { GetEmailIdentityCommand as GetEmailIdentityCommand3, SESv2Client as SESv2Client3 } from "@aws-sdk/client-sesv2";
|
|
4731
4851
|
import * as clack11 from "@clack/prompts";
|
|
@@ -4894,6 +5014,7 @@ function printCompletionScript() {
|
|
|
4894
5014
|
}
|
|
4895
5015
|
|
|
4896
5016
|
// src/cli.ts
|
|
5017
|
+
init_errors();
|
|
4897
5018
|
setupTabCompletion();
|
|
4898
5019
|
function showHelp() {
|
|
4899
5020
|
clack12.intro(pc12.bold("WRAPS CLI"));
|