@wraps.dev/cli 2.15.0 → 2.16.0
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
|
@@ -65,6 +65,7 @@ var init_ci_detection = __esm({
|
|
|
65
65
|
// src/utils/shared/s3-state.ts
|
|
66
66
|
var s3_state_exports = {};
|
|
67
67
|
__export(s3_state_exports, {
|
|
68
|
+
clearS3StackLocks: () => clearS3StackLocks,
|
|
68
69
|
deleteMetadata: () => deleteMetadata,
|
|
69
70
|
downloadMetadata: () => downloadMetadata,
|
|
70
71
|
ensureStateBucket: () => ensureStateBucket,
|
|
@@ -196,6 +197,27 @@ async function deleteMetadata(bucketName, accountId, region) {
|
|
|
196
197
|
})
|
|
197
198
|
);
|
|
198
199
|
}
|
|
200
|
+
async function clearS3StackLocks(accountId, region) {
|
|
201
|
+
const { S3Client: S3Client2, ListObjectsV2Command: ListObjectsV2Command2, DeleteObjectCommand } = await import("@aws-sdk/client-s3");
|
|
202
|
+
const client = new S3Client2({ region });
|
|
203
|
+
const bucketName = getStateBucketName(accountId, region);
|
|
204
|
+
const prefix = ".pulumi/locks/";
|
|
205
|
+
const response = await client.send(
|
|
206
|
+
new ListObjectsV2Command2({ Bucket: bucketName, Prefix: prefix })
|
|
207
|
+
);
|
|
208
|
+
const lockObjects = response.Contents ?? [];
|
|
209
|
+
if (lockObjects.length === 0) {
|
|
210
|
+
return 0;
|
|
211
|
+
}
|
|
212
|
+
for (const obj of lockObjects) {
|
|
213
|
+
if (obj.Key) {
|
|
214
|
+
await client.send(
|
|
215
|
+
new DeleteObjectCommand({ Bucket: bucketName, Key: obj.Key })
|
|
216
|
+
);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
return lockObjects.length;
|
|
220
|
+
}
|
|
199
221
|
async function downloadMetadata(bucketName, accountId, region) {
|
|
200
222
|
const { S3Client: S3Client2, GetObjectCommand: GetObjectCommand2 } = await import("@aws-sdk/client-s3");
|
|
201
223
|
const client = new S3Client2({ region });
|
|
@@ -302,8 +324,16 @@ var init_s3_state = __esm({
|
|
|
302
324
|
});
|
|
303
325
|
|
|
304
326
|
// src/utils/shared/fs.ts
|
|
327
|
+
var fs_exports = {};
|
|
328
|
+
__export(fs_exports, {
|
|
329
|
+
clearLocalStackLocks: () => clearLocalStackLocks,
|
|
330
|
+
ensurePulumiWorkDir: () => ensurePulumiWorkDir,
|
|
331
|
+
ensureWrapsDir: () => ensureWrapsDir,
|
|
332
|
+
getPulumiWorkDir: () => getPulumiWorkDir,
|
|
333
|
+
getWrapsDir: () => getWrapsDir
|
|
334
|
+
});
|
|
305
335
|
import { existsSync as existsSync2 } from "fs";
|
|
306
|
-
import { mkdir } from "fs/promises";
|
|
336
|
+
import { mkdir, readdir as readdir2, rm } from "fs/promises";
|
|
307
337
|
import { homedir } from "os";
|
|
308
338
|
import { join as join2 } from "path";
|
|
309
339
|
function getWrapsDir() {
|
|
@@ -318,6 +348,27 @@ async function ensureWrapsDir() {
|
|
|
318
348
|
await mkdir(wrapsDir, { recursive: true });
|
|
319
349
|
}
|
|
320
350
|
}
|
|
351
|
+
async function clearLocalStackLocks() {
|
|
352
|
+
const locksDir = join2(getPulumiWorkDir(), ".pulumi", "locks");
|
|
353
|
+
if (!existsSync2(locksDir)) {
|
|
354
|
+
return 0;
|
|
355
|
+
}
|
|
356
|
+
let count = 0;
|
|
357
|
+
async function walkAndDelete(dir) {
|
|
358
|
+
const entries = await readdir2(dir, { withFileTypes: true });
|
|
359
|
+
for (const entry of entries) {
|
|
360
|
+
const fullPath = join2(dir, entry.name);
|
|
361
|
+
if (entry.isDirectory()) {
|
|
362
|
+
await walkAndDelete(fullPath);
|
|
363
|
+
} else if (entry.name.endsWith(".json")) {
|
|
364
|
+
await rm(fullPath);
|
|
365
|
+
count++;
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
await walkAndDelete(locksDir);
|
|
370
|
+
return count;
|
|
371
|
+
}
|
|
321
372
|
async function ensurePulumiWorkDir(options) {
|
|
322
373
|
await ensureWrapsDir();
|
|
323
374
|
const pulumiDir = getPulumiWorkDir();
|
|
@@ -4296,8 +4347,8 @@ async function listConnections() {
|
|
|
4296
4347
|
return [];
|
|
4297
4348
|
}
|
|
4298
4349
|
try {
|
|
4299
|
-
const { readdir:
|
|
4300
|
-
const files = await
|
|
4350
|
+
const { readdir: readdir5 } = await import("fs/promises");
|
|
4351
|
+
const files = await readdir5(connectionsDir);
|
|
4301
4352
|
const connections = [];
|
|
4302
4353
|
for (const file of files) {
|
|
4303
4354
|
if (file.endsWith(".json")) {
|
|
@@ -6728,7 +6779,7 @@ var init_cloudflare = __esm({
|
|
|
6728
6779
|
};
|
|
6729
6780
|
}
|
|
6730
6781
|
async createEmailRecords(data) {
|
|
6731
|
-
const { domain, dkimTokens, mailFromDomain, region } = data;
|
|
6782
|
+
const { domain, dkimTokens, mailFromDomain, customTrackingDomain, region } = data;
|
|
6732
6783
|
const errors2 = [];
|
|
6733
6784
|
let recordsCreated = 0;
|
|
6734
6785
|
try {
|
|
@@ -6765,6 +6816,20 @@ var init_cloudflare = __esm({
|
|
|
6765
6816
|
} else {
|
|
6766
6817
|
errors2.push(`Failed to create DMARC record for ${domain}`);
|
|
6767
6818
|
}
|
|
6819
|
+
if (customTrackingDomain) {
|
|
6820
|
+
const trackingSuccess = await this.createRecord(
|
|
6821
|
+
customTrackingDomain,
|
|
6822
|
+
"CNAME",
|
|
6823
|
+
`r.${region}.awstrack.me`
|
|
6824
|
+
);
|
|
6825
|
+
if (trackingSuccess) {
|
|
6826
|
+
recordsCreated++;
|
|
6827
|
+
} else {
|
|
6828
|
+
errors2.push(
|
|
6829
|
+
`Failed to create tracking CNAME for ${customTrackingDomain}`
|
|
6830
|
+
);
|
|
6831
|
+
}
|
|
6832
|
+
}
|
|
6768
6833
|
if (mailFromDomain) {
|
|
6769
6834
|
const mxSuccess = await this.createRecord(
|
|
6770
6835
|
mailFromDomain,
|
|
@@ -7096,7 +7161,7 @@ var init_vercel = __esm({
|
|
|
7096
7161
|
};
|
|
7097
7162
|
}
|
|
7098
7163
|
async createEmailRecords(data) {
|
|
7099
|
-
const { domain, dkimTokens, mailFromDomain, region } = data;
|
|
7164
|
+
const { domain, dkimTokens, mailFromDomain, customTrackingDomain, region } = data;
|
|
7100
7165
|
const errors2 = [];
|
|
7101
7166
|
let recordsCreated = 0;
|
|
7102
7167
|
try {
|
|
@@ -7133,6 +7198,20 @@ var init_vercel = __esm({
|
|
|
7133
7198
|
} else {
|
|
7134
7199
|
errors2.push(`Failed to create DMARC record for ${domain}`);
|
|
7135
7200
|
}
|
|
7201
|
+
if (customTrackingDomain) {
|
|
7202
|
+
const trackingSuccess = await this.createRecord(
|
|
7203
|
+
customTrackingDomain,
|
|
7204
|
+
"CNAME",
|
|
7205
|
+
`r.${region}.awstrack.me`
|
|
7206
|
+
);
|
|
7207
|
+
if (trackingSuccess) {
|
|
7208
|
+
recordsCreated++;
|
|
7209
|
+
} else {
|
|
7210
|
+
errors2.push(
|
|
7211
|
+
`Failed to create tracking CNAME for ${customTrackingDomain}`
|
|
7212
|
+
);
|
|
7213
|
+
}
|
|
7214
|
+
}
|
|
7136
7215
|
if (mailFromDomain) {
|
|
7137
7216
|
const mxSuccess = await this.createRecord(
|
|
7138
7217
|
mailFromDomain,
|
|
@@ -7348,7 +7427,7 @@ import {
|
|
|
7348
7427
|
Route53Client as Route53Client2
|
|
7349
7428
|
} from "@aws-sdk/client-route-53";
|
|
7350
7429
|
function buildEmailDNSRecords(data) {
|
|
7351
|
-
const { domain, dkimTokens, mailFromDomain, region } = data;
|
|
7430
|
+
const { domain, dkimTokens, mailFromDomain, customTrackingDomain, region } = data;
|
|
7352
7431
|
const records = [];
|
|
7353
7432
|
for (const token of dkimTokens) {
|
|
7354
7433
|
records.push({
|
|
@@ -7371,6 +7450,14 @@ function buildEmailDNSRecords(data) {
|
|
|
7371
7450
|
value: `v=DMARC1; p=quarantine; rua=mailto:postmaster@${dmarcRuaDomain}`,
|
|
7372
7451
|
category: "dmarc"
|
|
7373
7452
|
});
|
|
7453
|
+
if (customTrackingDomain) {
|
|
7454
|
+
records.push({
|
|
7455
|
+
name: customTrackingDomain,
|
|
7456
|
+
type: "CNAME",
|
|
7457
|
+
value: `r.${region}.awstrack.me`,
|
|
7458
|
+
category: "tracking"
|
|
7459
|
+
});
|
|
7460
|
+
}
|
|
7374
7461
|
if (mailFromDomain) {
|
|
7375
7462
|
records.push({
|
|
7376
7463
|
name: mailFromDomain,
|
|
@@ -7431,8 +7518,7 @@ async function createDNSRecordsForProvider(credentials, data, selectedCategories
|
|
|
7431
7518
|
data.dkimTokens,
|
|
7432
7519
|
data.region,
|
|
7433
7520
|
categories,
|
|
7434
|
-
|
|
7435
|
-
// customTrackingDomain - not used here
|
|
7521
|
+
data.customTrackingDomain,
|
|
7436
7522
|
data.mailFromDomain
|
|
7437
7523
|
);
|
|
7438
7524
|
let recordsCreated = 0;
|
|
@@ -10078,6 +10164,48 @@ async function previewWithResourceChanges(stack, options) {
|
|
|
10078
10164
|
resourceChanges
|
|
10079
10165
|
};
|
|
10080
10166
|
}
|
|
10167
|
+
async function clearStackLocks(accountId, region) {
|
|
10168
|
+
const backendUrl = process.env.PULUMI_BACKEND_URL || "";
|
|
10169
|
+
if (backendUrl.startsWith("s3://")) {
|
|
10170
|
+
const { clearS3StackLocks: clearS3StackLocks2 } = await Promise.resolve().then(() => (init_s3_state(), s3_state_exports));
|
|
10171
|
+
return clearS3StackLocks2(accountId, region);
|
|
10172
|
+
}
|
|
10173
|
+
const { clearLocalStackLocks: clearLocalStackLocks2 } = await Promise.resolve().then(() => (init_fs(), fs_exports));
|
|
10174
|
+
return clearLocalStackLocks2();
|
|
10175
|
+
}
|
|
10176
|
+
async function withLockRetry(fn, options) {
|
|
10177
|
+
try {
|
|
10178
|
+
return await fn();
|
|
10179
|
+
} catch (error) {
|
|
10180
|
+
if (!(error instanceof Error)) {
|
|
10181
|
+
throw error;
|
|
10182
|
+
}
|
|
10183
|
+
const parsed = parsePulumiError(error);
|
|
10184
|
+
if (parsed.code !== "STACK_LOCKED") {
|
|
10185
|
+
throw error;
|
|
10186
|
+
}
|
|
10187
|
+
const clack51 = await import("@clack/prompts");
|
|
10188
|
+
const pc54 = (await import("picocolors")).default;
|
|
10189
|
+
if (options.autoConfirm) {
|
|
10190
|
+
clack51.log.warn(
|
|
10191
|
+
"Stack is locked from a previous interrupted run. Auto-clearing..."
|
|
10192
|
+
);
|
|
10193
|
+
} else {
|
|
10194
|
+
const shouldClear = await clack51.confirm({
|
|
10195
|
+
message: `Stack is locked from a previous interrupted run. ${pc54.yellow("Clear the stale lock and retry?")}`,
|
|
10196
|
+
initialValue: true
|
|
10197
|
+
});
|
|
10198
|
+
if (clack51.isCancel(shouldClear) || !shouldClear) {
|
|
10199
|
+
throw errors.stackLocked();
|
|
10200
|
+
}
|
|
10201
|
+
}
|
|
10202
|
+
const cleared = await clearStackLocks(options.accountId, options.region);
|
|
10203
|
+
clack51.log.info(
|
|
10204
|
+
`Cleared ${cleared} lock file${cleared === 1 ? "" : "s"}. Retrying...`
|
|
10205
|
+
);
|
|
10206
|
+
return fn();
|
|
10207
|
+
}
|
|
10208
|
+
}
|
|
10081
10209
|
|
|
10082
10210
|
// src/commands/cdn/destroy.ts
|
|
10083
10211
|
async function cdnDestroy(options) {
|
|
@@ -10268,8 +10396,12 @@ async function cdnDestroy(options) {
|
|
|
10268
10396
|
} catch (_error) {
|
|
10269
10397
|
throw new Error("No CDN infrastructure found to destroy");
|
|
10270
10398
|
}
|
|
10271
|
-
await stack.destroy({ onOutput: () => {
|
|
10272
|
-
} })
|
|
10399
|
+
await withLockRetry(() => stack.destroy({ onOutput: () => {
|
|
10400
|
+
} }), {
|
|
10401
|
+
accountId: identity.accountId,
|
|
10402
|
+
region,
|
|
10403
|
+
autoConfirm: options.force
|
|
10404
|
+
});
|
|
10273
10405
|
await stack.workspace.removeStack(stackName);
|
|
10274
10406
|
}
|
|
10275
10407
|
);
|
|
@@ -10284,10 +10416,6 @@ async function cdnDestroy(options) {
|
|
|
10284
10416
|
}
|
|
10285
10417
|
process.exit(0);
|
|
10286
10418
|
}
|
|
10287
|
-
if (msg.includes("stack is currently locked")) {
|
|
10288
|
-
trackError("STACK_LOCKED", "storage destroy", { step: "destroy" });
|
|
10289
|
-
throw errors.stackLocked();
|
|
10290
|
-
}
|
|
10291
10419
|
trackError("DESTROY_FAILED", "storage destroy", { step: "destroy" });
|
|
10292
10420
|
clack9.log.error("CDN infrastructure destruction failed");
|
|
10293
10421
|
throw error;
|
|
@@ -11677,8 +11805,11 @@ ${pc11.yellow(pc11.bold("Configuration Notes:"))}`);
|
|
|
11677
11805
|
`wraps-cdn-${identity.accountId}-${region}`
|
|
11678
11806
|
);
|
|
11679
11807
|
await stack.setConfig("aws:region", { value: region });
|
|
11680
|
-
const upResult = await
|
|
11681
|
-
|
|
11808
|
+
const upResult = await withLockRetry(
|
|
11809
|
+
() => stack.up({ onOutput: () => {
|
|
11810
|
+
} }),
|
|
11811
|
+
{ accountId: identity.accountId, region, autoConfirm: options.yes }
|
|
11812
|
+
);
|
|
11682
11813
|
const pulumiOutputs = upResult.outputs;
|
|
11683
11814
|
return {
|
|
11684
11815
|
roleArn: pulumiOutputs.roleArn?.value,
|
|
@@ -11704,10 +11835,6 @@ ${pc11.yellow(pc11.bold("Configuration Notes:"))}`);
|
|
|
11704
11835
|
region,
|
|
11705
11836
|
duration_ms: Date.now() - startTime
|
|
11706
11837
|
});
|
|
11707
|
-
if (msg.includes("stack is currently locked")) {
|
|
11708
|
-
trackError("STACK_LOCKED", "storage:init", { step: "deploy" });
|
|
11709
|
-
throw errors.stackLocked();
|
|
11710
|
-
}
|
|
11711
11838
|
trackError("DEPLOYMENT_FAILED", "storage:init", { step: "deploy" });
|
|
11712
11839
|
throw new Error(`Pulumi deployment failed: ${msg}`);
|
|
11713
11840
|
}
|
|
@@ -18155,11 +18282,14 @@ async function emailDestroy(options) {
|
|
|
18155
18282
|
}
|
|
18156
18283
|
await stack.refresh({ onOutput: () => {
|
|
18157
18284
|
} });
|
|
18158
|
-
await
|
|
18159
|
-
|
|
18160
|
-
|
|
18161
|
-
|
|
18162
|
-
|
|
18285
|
+
await withLockRetry(
|
|
18286
|
+
() => withTimeout(
|
|
18287
|
+
stack.destroy({ onOutput: () => {
|
|
18288
|
+
}, continueOnError: true }),
|
|
18289
|
+
DEFAULT_PULUMI_TIMEOUT_MS,
|
|
18290
|
+
"Pulumi destroy"
|
|
18291
|
+
),
|
|
18292
|
+
{ accountId: identity.accountId, region, autoConfirm: options.force }
|
|
18163
18293
|
);
|
|
18164
18294
|
await stack.workspace.removeStack(stackName);
|
|
18165
18295
|
}
|
|
@@ -18172,10 +18302,6 @@ async function emailDestroy(options) {
|
|
|
18172
18302
|
await deleteConnectionMetadata(identity.accountId, region);
|
|
18173
18303
|
process.exit(0);
|
|
18174
18304
|
}
|
|
18175
|
-
if (msg.includes("stack is currently locked")) {
|
|
18176
|
-
trackError("STACK_LOCKED", "email destroy", { step: "destroy" });
|
|
18177
|
-
throw errors.stackLocked();
|
|
18178
|
-
}
|
|
18179
18305
|
trackError("DESTROY_FAILED", "email destroy", { step: "destroy" });
|
|
18180
18306
|
clack18.log.error("Email infrastructure destruction failed");
|
|
18181
18307
|
destroyFailed = true;
|
|
@@ -19425,8 +19551,8 @@ async function inboundInit(options) {
|
|
|
19425
19551
|
if (!domain) {
|
|
19426
19552
|
throw errors.inboundRequiresOutbound();
|
|
19427
19553
|
}
|
|
19428
|
-
const subdomain = options.subdomain
|
|
19429
|
-
const receivingDomain = `${subdomain}.${domain}
|
|
19554
|
+
const subdomain = options.root ? "" : options.subdomain ?? (options.yes ? "inbound" : await promptInboundSubdomain(domain));
|
|
19555
|
+
const receivingDomain = subdomain ? `${subdomain}.${domain}` : domain;
|
|
19430
19556
|
clack20.log.info(`Receiving domain: ${pc21.cyan(receivingDomain)}`);
|
|
19431
19557
|
const webhookUrl = options.webhookUrl || (options.yes ? void 0 : await promptWebhookUrl());
|
|
19432
19558
|
const webhookSecret = randomBytes3(32).toString("hex");
|
|
@@ -19490,22 +19616,25 @@ async function inboundInit(options) {
|
|
|
19490
19616
|
);
|
|
19491
19617
|
await stack.setConfig("aws:region", { value: region });
|
|
19492
19618
|
const pulumiOutput = [];
|
|
19493
|
-
await
|
|
19494
|
-
|
|
19495
|
-
|
|
19496
|
-
|
|
19619
|
+
await withLockRetry(
|
|
19620
|
+
() => withTimeout(
|
|
19621
|
+
stack.up({
|
|
19622
|
+
onOutput: (msg) => {
|
|
19623
|
+
pulumiOutput.push(msg);
|
|
19624
|
+
}
|
|
19625
|
+
}),
|
|
19626
|
+
DEFAULT_PULUMI_TIMEOUT_MS,
|
|
19627
|
+
"Pulumi deployment"
|
|
19628
|
+
).catch((error) => {
|
|
19629
|
+
if (pulumiOutput.length > 0) {
|
|
19630
|
+
const fullOutput = pulumiOutput.join("");
|
|
19631
|
+
clack20.log.error("Pulumi deployment output:");
|
|
19632
|
+
console.error(fullOutput);
|
|
19497
19633
|
}
|
|
19634
|
+
throw error;
|
|
19498
19635
|
}),
|
|
19499
|
-
|
|
19500
|
-
|
|
19501
|
-
).catch((error) => {
|
|
19502
|
-
if (pulumiOutput.length > 0) {
|
|
19503
|
-
const fullOutput = pulumiOutput.join("");
|
|
19504
|
-
clack20.log.error("Pulumi deployment output:");
|
|
19505
|
-
console.error(fullOutput);
|
|
19506
|
-
}
|
|
19507
|
-
throw error;
|
|
19508
|
-
});
|
|
19636
|
+
{ accountId: identity.accountId, region, autoConfirm: options.yes }
|
|
19637
|
+
);
|
|
19509
19638
|
});
|
|
19510
19639
|
await progress.execute("Creating SES receipt rules", async () => {
|
|
19511
19640
|
await createReceiptRuleSet(region);
|
|
@@ -19731,11 +19860,14 @@ Deploy first: ${pc21.cyan("wraps email inbound init")}
|
|
|
19731
19860
|
}
|
|
19732
19861
|
);
|
|
19733
19862
|
await stack.setConfig("aws:region", { value: region });
|
|
19734
|
-
await
|
|
19735
|
-
|
|
19736
|
-
|
|
19737
|
-
|
|
19738
|
-
|
|
19863
|
+
await withLockRetry(
|
|
19864
|
+
() => withTimeout(
|
|
19865
|
+
stack.up({ onOutput: () => {
|
|
19866
|
+
} }),
|
|
19867
|
+
DEFAULT_PULUMI_TIMEOUT_MS,
|
|
19868
|
+
"Pulumi deployment"
|
|
19869
|
+
),
|
|
19870
|
+
{ accountId: identity.accountId, region, autoConfirm: options.force }
|
|
19739
19871
|
);
|
|
19740
19872
|
});
|
|
19741
19873
|
await progress.execute("Saving configuration", async () => {
|
|
@@ -19785,7 +19917,7 @@ Enable it: ${pc21.cyan("wraps email inbound init")}
|
|
|
19785
19917
|
const inboundDomains = emailConfig.inboundDomains ?? [];
|
|
19786
19918
|
const activeRuleSet = await getActiveReceiptRuleSet(region);
|
|
19787
19919
|
const domainList = inboundDomains.length > 0 ? inboundDomains.map((d) => d.receivingDomain) : [
|
|
19788
|
-
inbound.receivingDomain || `${inbound.subdomain}.${emailConfig.domain}`
|
|
19920
|
+
inbound.receivingDomain || (inbound.subdomain ? `${inbound.subdomain}.${emailConfig.domain}` : emailConfig.domain || "")
|
|
19789
19921
|
];
|
|
19790
19922
|
if (isJsonMode()) {
|
|
19791
19923
|
jsonSuccess("email.inbound.status", {
|
|
@@ -19804,9 +19936,7 @@ Enable it: ${pc21.cyan("wraps email inbound init")}
|
|
|
19804
19936
|
console.log(pc21.bold(" Inbound Email Configuration"));
|
|
19805
19937
|
console.log();
|
|
19806
19938
|
if (domainList.length === 1) {
|
|
19807
|
-
console.log(
|
|
19808
|
-
` ${pc21.dim("Receiving domain:")} ${pc21.cyan(domainList[0])}`
|
|
19809
|
-
);
|
|
19939
|
+
console.log(` ${pc21.dim("Receiving domain:")} ${pc21.cyan(domainList[0])}`);
|
|
19810
19940
|
} else {
|
|
19811
19941
|
console.log(` ${pc21.dim("Receiving domains:")}`);
|
|
19812
19942
|
for (const d of domainList) {
|
|
@@ -19850,7 +19980,7 @@ Enable it: ${pc21.cyan("wraps email inbound init")}
|
|
|
19850
19980
|
const inbound = emailConfig.inbound;
|
|
19851
19981
|
const inboundDomains = emailConfig.inboundDomains ?? [];
|
|
19852
19982
|
const domainList = inboundDomains.length > 0 ? inboundDomains.map((d) => d.receivingDomain) : [
|
|
19853
|
-
inbound.receivingDomain || `${inbound.subdomain}.${emailConfig.domain}`
|
|
19983
|
+
inbound.receivingDomain || (inbound.subdomain ? `${inbound.subdomain}.${emailConfig.domain}` : emailConfig.domain || "")
|
|
19854
19984
|
];
|
|
19855
19985
|
let allPassed = true;
|
|
19856
19986
|
const domainChecks = {};
|
|
@@ -19965,7 +20095,7 @@ Enable it: ${pc21.cyan("wraps email inbound init")}
|
|
|
19965
20095
|
}
|
|
19966
20096
|
const emailConfig = metadata.services.email.config;
|
|
19967
20097
|
const inbound = emailConfig.inbound;
|
|
19968
|
-
const receivingDomain = inbound.receivingDomain || `${inbound.subdomain}.${emailConfig.domain}
|
|
20098
|
+
const receivingDomain = inbound.receivingDomain || (inbound.subdomain ? `${inbound.subdomain}.${emailConfig.domain}` : emailConfig.domain || "");
|
|
19969
20099
|
const bucketName = inbound.bucketName || `wraps-inbound-${identity.accountId}-${region}`;
|
|
19970
20100
|
const testRecipient = `test@${receivingDomain}`;
|
|
19971
20101
|
const testSubject = `Wraps Inbound Test - ${(/* @__PURE__ */ new Date()).toISOString()}`;
|
|
@@ -20108,11 +20238,9 @@ async function inboundAdd(options) {
|
|
|
20108
20238
|
const metadata = await loadConnectionMetadata(identity.accountId, region);
|
|
20109
20239
|
if (!metadata?.services?.email?.config?.inbound?.enabled) {
|
|
20110
20240
|
clack20.log.error("Inbound email infrastructure is not deployed.");
|
|
20111
|
-
console.log(
|
|
20112
|
-
`
|
|
20241
|
+
console.log(`
|
|
20113
20242
|
Deploy first: ${pc21.cyan("wraps email inbound init")}
|
|
20114
|
-
`
|
|
20115
|
-
);
|
|
20243
|
+
`);
|
|
20116
20244
|
process.exit(1);
|
|
20117
20245
|
}
|
|
20118
20246
|
const emailConfig = metadata.services.email.config;
|
|
@@ -20145,8 +20273,8 @@ Deploy first: ${pc21.cyan("wraps email inbound init")}
|
|
|
20145
20273
|
parentDomain = selected;
|
|
20146
20274
|
}
|
|
20147
20275
|
}
|
|
20148
|
-
const subdomain = options.subdomain
|
|
20149
|
-
const receivingDomain = `${subdomain}.${parentDomain}
|
|
20276
|
+
const subdomain = options.root ? "" : options.subdomain ?? (options.yes ? "inbound" : await promptInboundSubdomain(parentDomain));
|
|
20277
|
+
const receivingDomain = subdomain ? `${subdomain}.${parentDomain}` : parentDomain;
|
|
20150
20278
|
const existingDomains = emailConfig.inboundDomains ?? [];
|
|
20151
20279
|
if (existingDomains.some((d) => d.receivingDomain === receivingDomain)) {
|
|
20152
20280
|
clack20.log.warn(
|
|
@@ -20279,16 +20407,12 @@ Deploy first: ${pc21.cyan("wraps email inbound init")}
|
|
|
20279
20407
|
`${pc21.bold("Added inbound domain:")} ${pc21.cyan(receivingDomain)}`
|
|
20280
20408
|
);
|
|
20281
20409
|
console.log();
|
|
20282
|
-
if (
|
|
20283
|
-
console.log(
|
|
20284
|
-
` ${pc21.dim("1.")} Add DNS records above to your DNS provider`
|
|
20285
|
-
);
|
|
20286
|
-
console.log(
|
|
20287
|
-
` ${pc21.dim("2.")} Verify: ${pc21.cyan("wraps email inbound verify")}`
|
|
20288
|
-
);
|
|
20410
|
+
if (dnsAutoCreated) {
|
|
20411
|
+
console.log(` Verify: ${pc21.cyan("wraps email inbound verify")}`);
|
|
20289
20412
|
} else {
|
|
20413
|
+
console.log(` ${pc21.dim("1.")} Add DNS records above to your DNS provider`);
|
|
20290
20414
|
console.log(
|
|
20291
|
-
` Verify: ${pc21.cyan("wraps email inbound verify")}`
|
|
20415
|
+
` ${pc21.dim("2.")} Verify: ${pc21.cyan("wraps email inbound verify")}`
|
|
20292
20416
|
);
|
|
20293
20417
|
}
|
|
20294
20418
|
console.log();
|
|
@@ -20306,11 +20430,9 @@ async function inboundRemove(options) {
|
|
|
20306
20430
|
const metadata = await loadConnectionMetadata(identity.accountId, region);
|
|
20307
20431
|
if (!metadata?.services?.email?.config?.inbound?.enabled) {
|
|
20308
20432
|
clack20.log.error("Inbound email infrastructure is not deployed.");
|
|
20309
|
-
console.log(
|
|
20310
|
-
`
|
|
20433
|
+
console.log(`
|
|
20311
20434
|
Deploy first: ${pc21.cyan("wraps email inbound init")}
|
|
20312
|
-
`
|
|
20313
|
-
);
|
|
20435
|
+
`);
|
|
20314
20436
|
process.exit(1);
|
|
20315
20437
|
}
|
|
20316
20438
|
const emailConfig = metadata.services.email.config;
|
|
@@ -20803,12 +20925,19 @@ ${pc24.yellow(pc24.bold("Configuration Warnings:"))}`);
|
|
|
20803
20925
|
`wraps-${identity.accountId}-${region}`
|
|
20804
20926
|
);
|
|
20805
20927
|
await stack.setConfig("aws:region", { value: region });
|
|
20806
|
-
const upResult = await
|
|
20807
|
-
|
|
20808
|
-
|
|
20809
|
-
|
|
20810
|
-
|
|
20811
|
-
|
|
20928
|
+
const upResult = await withLockRetry(
|
|
20929
|
+
() => withTimeout(
|
|
20930
|
+
stack.up({ onOutput: () => {
|
|
20931
|
+
} }),
|
|
20932
|
+
// Suppress Pulumi output
|
|
20933
|
+
DEFAULT_PULUMI_TIMEOUT_MS,
|
|
20934
|
+
"Pulumi deployment"
|
|
20935
|
+
),
|
|
20936
|
+
{
|
|
20937
|
+
accountId: identity.accountId,
|
|
20938
|
+
region,
|
|
20939
|
+
autoConfirm: options.yes || options.quick
|
|
20940
|
+
}
|
|
20812
20941
|
);
|
|
20813
20942
|
const pulumiOutputs = upResult.outputs;
|
|
20814
20943
|
return {
|
|
@@ -20835,10 +20964,6 @@ ${pc24.yellow(pc24.bold("Configuration Warnings:"))}`);
|
|
|
20835
20964
|
region,
|
|
20836
20965
|
duration_ms: Date.now() - startTime
|
|
20837
20966
|
});
|
|
20838
|
-
if (msg.includes("stack is currently locked")) {
|
|
20839
|
-
trackError("STACK_LOCKED", "email:init", { step: "deploy" });
|
|
20840
|
-
throw errors.stackLocked();
|
|
20841
|
-
}
|
|
20842
20967
|
if (isPulumiError(error)) {
|
|
20843
20968
|
const { code, iamAction, service } = parsePulumiError(error);
|
|
20844
20969
|
trackError(`PULUMI_${code}`, "email:init", {
|
|
@@ -20956,6 +21081,7 @@ ${pc24.yellow(pc24.bold("Configuration Warnings:"))}`);
|
|
|
20956
21081
|
domain: outputs.domain,
|
|
20957
21082
|
dkimTokens: outputs.dkimTokens,
|
|
20958
21083
|
mailFromDomain: outputs.mailFromDomain,
|
|
21084
|
+
customTrackingDomain: outputs.customTrackingDomain,
|
|
20959
21085
|
region
|
|
20960
21086
|
},
|
|
20961
21087
|
selectedCategories
|
|
@@ -20988,6 +21114,7 @@ ${pc24.yellow(pc24.bold("Configuration Warnings:"))}`);
|
|
|
20988
21114
|
domain: outputs.domain,
|
|
20989
21115
|
dkimTokens: outputs.dkimTokens,
|
|
20990
21116
|
mailFromDomain: outputs.mailFromDomain,
|
|
21117
|
+
customTrackingDomain: outputs.customTrackingDomain,
|
|
20991
21118
|
region
|
|
20992
21119
|
};
|
|
20993
21120
|
const records = buildEmailDNSRecords2(recordData);
|
|
@@ -22001,8 +22128,8 @@ async function templatesInit(options) {
|
|
|
22001
22128
|
const { homedir: homedir3 } = await import("os");
|
|
22002
22129
|
const connectionsDir = join9(homedir3(), ".wraps", "connections");
|
|
22003
22130
|
if (existsSync8(connectionsDir)) {
|
|
22004
|
-
const { readdir:
|
|
22005
|
-
const files = await
|
|
22131
|
+
const { readdir: readdir5 } = await import("fs/promises");
|
|
22132
|
+
const files = await readdir5(connectionsDir);
|
|
22006
22133
|
if (files.length > 0) {
|
|
22007
22134
|
const firstFile = files[0];
|
|
22008
22135
|
const match = firstFile.match(/\d+-(.+)\.json$/);
|
|
@@ -22321,7 +22448,7 @@ import pc28 from "picocolors";
|
|
|
22321
22448
|
// src/utils/email/template-compiler.ts
|
|
22322
22449
|
init_esm_shims();
|
|
22323
22450
|
import { existsSync as existsSync9 } from "fs";
|
|
22324
|
-
import { mkdir as mkdir4, readdir as
|
|
22451
|
+
import { mkdir as mkdir4, readdir as readdir3, writeFile as writeFile6 } from "fs/promises";
|
|
22325
22452
|
import { join as join10 } from "path";
|
|
22326
22453
|
async function loadWrapsConfig(wrapsDir) {
|
|
22327
22454
|
const configPath = join10(wrapsDir, "wraps.config.ts");
|
|
@@ -22356,7 +22483,7 @@ async function loadWrapsConfig(wrapsDir) {
|
|
|
22356
22483
|
return config2;
|
|
22357
22484
|
}
|
|
22358
22485
|
async function discoverTemplates(dir, filter) {
|
|
22359
|
-
const entries = await
|
|
22486
|
+
const entries = await readdir3(dir);
|
|
22360
22487
|
const templates = entries.filter(
|
|
22361
22488
|
(f) => (f.endsWith(".tsx") || f.endsWith(".ts")) && !f.startsWith("_") && !f.endsWith(".d.ts")
|
|
22362
22489
|
);
|
|
@@ -24864,6 +24991,7 @@ ${pc30.bold("Cost Impact:")}`);
|
|
|
24864
24991
|
domain: outputs.domain,
|
|
24865
24992
|
dkimTokens: outputs.dkimTokens,
|
|
24866
24993
|
mailFromDomain,
|
|
24994
|
+
customTrackingDomain: outputs.customTrackingDomain,
|
|
24867
24995
|
region
|
|
24868
24996
|
};
|
|
24869
24997
|
try {
|
|
@@ -24914,6 +25042,7 @@ ${pc30.bold("Cost Impact:")}`);
|
|
|
24914
25042
|
domain: outputs.domain,
|
|
24915
25043
|
dkimTokens: outputs.dkimTokens,
|
|
24916
25044
|
mailFromDomain,
|
|
25045
|
+
customTrackingDomain: outputs.customTrackingDomain,
|
|
24917
25046
|
region
|
|
24918
25047
|
};
|
|
24919
25048
|
const dnsRecords = buildEmailDNSRecords(dnsData);
|
|
@@ -25630,8 +25759,8 @@ async function workflowsInit(options) {
|
|
|
25630
25759
|
}
|
|
25631
25760
|
const progress = new DeploymentProgress();
|
|
25632
25761
|
if (existsSync13(workflowsDir) && !options.force) {
|
|
25633
|
-
const { readdir:
|
|
25634
|
-
const files = await
|
|
25762
|
+
const { readdir: readdir5 } = await import("fs/promises");
|
|
25763
|
+
const files = await readdir5(workflowsDir);
|
|
25635
25764
|
const tsFiles = files.filter(
|
|
25636
25765
|
(f) => f.endsWith(".ts") && !f.startsWith("_")
|
|
25637
25766
|
);
|
|
@@ -25965,13 +26094,13 @@ function assignPositions(steps, transitions) {
|
|
|
25965
26094
|
init_esm_shims();
|
|
25966
26095
|
import { createHash as createHash2 } from "crypto";
|
|
25967
26096
|
import { existsSync as existsSync14 } from "fs";
|
|
25968
|
-
import { mkdir as mkdir8, readdir as
|
|
26097
|
+
import { mkdir as mkdir8, readdir as readdir4, readFile as readFile8, writeFile as writeFile10 } from "fs/promises";
|
|
25969
26098
|
import { basename, join as join15 } from "path";
|
|
25970
26099
|
async function discoverWorkflows(dir, filter) {
|
|
25971
26100
|
if (!existsSync14(dir)) {
|
|
25972
26101
|
return [];
|
|
25973
26102
|
}
|
|
25974
|
-
const entries = await
|
|
26103
|
+
const entries = await readdir4(dir);
|
|
25975
26104
|
const workflows = entries.filter(
|
|
25976
26105
|
(f) => (
|
|
25977
26106
|
// Include .ts files only (not .tsx for workflows)
|
|
@@ -32946,7 +33075,6 @@ import * as pulumi26 from "@pulumi/pulumi";
|
|
|
32946
33075
|
import pc43 from "picocolors";
|
|
32947
33076
|
init_events();
|
|
32948
33077
|
init_aws();
|
|
32949
|
-
init_errors();
|
|
32950
33078
|
init_fs();
|
|
32951
33079
|
init_json_output();
|
|
32952
33080
|
init_metadata();
|
|
@@ -33624,7 +33752,10 @@ ${pc43.yellow(pc43.bold("Important Notes:"))}`);
|
|
|
33624
33752
|
}
|
|
33625
33753
|
);
|
|
33626
33754
|
await stack.setConfig("aws:region", { value: region });
|
|
33627
|
-
const upResult = await
|
|
33755
|
+
const upResult = await withLockRetry(
|
|
33756
|
+
() => stack.up({ onOutput: console.log }),
|
|
33757
|
+
{ accountId: identity.accountId, region, autoConfirm: options.yes }
|
|
33758
|
+
);
|
|
33628
33759
|
const pulumiOutputs = upResult.outputs;
|
|
33629
33760
|
return {
|
|
33630
33761
|
roleArn: pulumiOutputs.roleArn?.value,
|
|
@@ -33707,10 +33838,6 @@ ${pc43.yellow(pc43.bold("Important Notes:"))}`);
|
|
|
33707
33838
|
duration_ms: Date.now() - startTime
|
|
33708
33839
|
});
|
|
33709
33840
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
33710
|
-
if (errorMessage.includes("stack is currently locked")) {
|
|
33711
|
-
trackError("STACK_LOCKED", "sms:init", { step: "deploy" });
|
|
33712
|
-
throw errors.stackLocked();
|
|
33713
|
-
}
|
|
33714
33841
|
trackError("DEPLOYMENT_FAILED", "sms:init", { step: "deploy" });
|
|
33715
33842
|
throw new Error(`SMS deployment failed: ${errorMessage}`);
|
|
33716
33843
|
}
|