@wraps.dev/cli 2.19.8 → 2.20.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js
CHANGED
|
@@ -6057,7 +6057,9 @@ function getAllTrackedDomains(metadata) {
|
|
|
6057
6057
|
managed: true,
|
|
6058
6058
|
purpose: d.purpose,
|
|
6059
6059
|
mailFromDomain: d.mailFromDomain,
|
|
6060
|
-
addedAt: d.addedAt
|
|
6060
|
+
addedAt: d.addedAt,
|
|
6061
|
+
configSetName: d.configSetName,
|
|
6062
|
+
trackingConfig: d.trackingConfig
|
|
6061
6063
|
});
|
|
6062
6064
|
}
|
|
6063
6065
|
return result;
|
|
@@ -7255,6 +7257,35 @@ var init_dist = __esm({
|
|
|
7255
7257
|
}
|
|
7256
7258
|
});
|
|
7257
7259
|
|
|
7260
|
+
// src/utils/email/config-set-slug.ts
|
|
7261
|
+
var config_set_slug_exports = {};
|
|
7262
|
+
__export(config_set_slug_exports, {
|
|
7263
|
+
domainToConfigSetName: () => domainToConfigSetName
|
|
7264
|
+
});
|
|
7265
|
+
import { createHash } from "crypto";
|
|
7266
|
+
function domainToConfigSetName(domain) {
|
|
7267
|
+
const slug = domain.toLowerCase().replace(/\./g, "-");
|
|
7268
|
+
const needsHash = domain.includes("-") || slug.length > MAX_SLUG;
|
|
7269
|
+
if (!needsHash) {
|
|
7270
|
+
return `${PREFIX}${slug}`;
|
|
7271
|
+
}
|
|
7272
|
+
const hash = createHash("sha256").update(domain).digest("hex").slice(0, 8);
|
|
7273
|
+
const rawSlugPart = slug.length > MAX_SLUG_WITH_HASH ? slug.slice(0, MAX_SLUG_WITH_HASH) : slug;
|
|
7274
|
+
const slugPart = rawSlugPart.replace(/-+$/, "");
|
|
7275
|
+
return `${PREFIX}${slugPart}-${hash}`;
|
|
7276
|
+
}
|
|
7277
|
+
var PREFIX, MAX_LENGTH, MAX_SLUG, MAX_SLUG_WITH_HASH;
|
|
7278
|
+
var init_config_set_slug = __esm({
|
|
7279
|
+
"src/utils/email/config-set-slug.ts"() {
|
|
7280
|
+
"use strict";
|
|
7281
|
+
init_esm_shims();
|
|
7282
|
+
PREFIX = "wraps-email-";
|
|
7283
|
+
MAX_LENGTH = 64;
|
|
7284
|
+
MAX_SLUG = MAX_LENGTH - PREFIX.length;
|
|
7285
|
+
MAX_SLUG_WITH_HASH = MAX_SLUG - 9;
|
|
7286
|
+
}
|
|
7287
|
+
});
|
|
7288
|
+
|
|
7258
7289
|
// src/infrastructure/resources/eventbridge-user-webhook.ts
|
|
7259
7290
|
var eventbridge_user_webhook_exports = {};
|
|
7260
7291
|
__export(eventbridge_user_webhook_exports, {
|
|
@@ -7929,20 +7960,20 @@ async function createMailManagerArchive(config2) {
|
|
|
7929
7960
|
let archiveId;
|
|
7930
7961
|
let archiveArn;
|
|
7931
7962
|
try {
|
|
7932
|
-
const listResult = await mailManagerClient.send(
|
|
7963
|
+
const listResult = await mailManagerClient.send(
|
|
7964
|
+
new ListArchivesCommand({})
|
|
7965
|
+
);
|
|
7933
7966
|
const existing = listResult.Archives?.find(
|
|
7934
7967
|
(a) => a.ArchiveState === ArchiveState.ACTIVE && a.ArchiveName !== void 0 && namePattern.test(a.ArchiveName)
|
|
7935
7968
|
);
|
|
7936
7969
|
if (existing?.ArchiveId) {
|
|
7937
|
-
console.log(`Using existing Mail Manager archive: ${existing.ArchiveName}`);
|
|
7938
7970
|
archiveId = existing.ArchiveId;
|
|
7939
7971
|
const getResult = await mailManagerClient.send(
|
|
7940
7972
|
new GetArchiveCommand({ ArchiveId: archiveId })
|
|
7941
7973
|
);
|
|
7942
7974
|
archiveArn = getResult.ArchiveArn;
|
|
7943
7975
|
}
|
|
7944
|
-
} catch
|
|
7945
|
-
console.log("Error checking for existing archive:", error);
|
|
7976
|
+
} catch {
|
|
7946
7977
|
}
|
|
7947
7978
|
if (!archiveId) {
|
|
7948
7979
|
for (let attempt = 1; attempt <= MAX_NAME_ATTEMPTS; attempt++) {
|
|
@@ -7966,13 +7997,9 @@ async function createMailManagerArchive(config2) {
|
|
|
7966
7997
|
"Failed to create Mail Manager Archive: No ArchiveId returned"
|
|
7967
7998
|
);
|
|
7968
7999
|
}
|
|
7969
|
-
console.log(`Created new Mail Manager archive: ${archiveName}`);
|
|
7970
8000
|
break;
|
|
7971
8001
|
} catch (error) {
|
|
7972
8002
|
if (error instanceof Error && error.name === "ConflictException" && attempt < MAX_NAME_ATTEMPTS) {
|
|
7973
|
-
console.log(
|
|
7974
|
-
`Archive '${archiveName}' is unavailable, trying '${baseArchiveName}-${attempt + 1}'...`
|
|
7975
|
-
);
|
|
7976
8003
|
continue;
|
|
7977
8004
|
}
|
|
7978
8005
|
throw error;
|
|
@@ -9572,7 +9599,7 @@ Run ${pc27.cyan(`wraps email domains verify --domain ${domain} --wait`)} to keep
|
|
|
9572
9599
|
}
|
|
9573
9600
|
}
|
|
9574
9601
|
},
|
|
9575
|
-
ConfigurationSetName:
|
|
9602
|
+
ConfigurationSetName: domainToConfigSetName(domain)
|
|
9576
9603
|
})
|
|
9577
9604
|
);
|
|
9578
9605
|
return response.MessageId;
|
|
@@ -9684,6 +9711,7 @@ var init_test = __esm({
|
|
|
9684
9711
|
"use strict";
|
|
9685
9712
|
init_esm_shims();
|
|
9686
9713
|
init_events();
|
|
9714
|
+
init_config_set_slug();
|
|
9687
9715
|
init_ses_simulator();
|
|
9688
9716
|
init_verification();
|
|
9689
9717
|
init_aws();
|
|
@@ -17403,6 +17431,7 @@ import pc18 from "picocolors";
|
|
|
17403
17431
|
// src/infrastructure/email-stack.ts
|
|
17404
17432
|
init_esm_shims();
|
|
17405
17433
|
init_dist();
|
|
17434
|
+
init_config_set_slug();
|
|
17406
17435
|
import * as aws19 from "@pulumi/aws";
|
|
17407
17436
|
|
|
17408
17437
|
// src/infrastructure/resources/alerting.ts
|
|
@@ -17963,6 +17992,7 @@ init_lambda();
|
|
|
17963
17992
|
|
|
17964
17993
|
// src/infrastructure/resources/ses.ts
|
|
17965
17994
|
init_esm_shims();
|
|
17995
|
+
init_config_set_slug();
|
|
17966
17996
|
import * as aws9 from "@pulumi/aws";
|
|
17967
17997
|
async function configurationSetExists(configSetName, region) {
|
|
17968
17998
|
try {
|
|
@@ -18014,8 +18044,9 @@ async function emailIdentityExists(emailIdentity, region) {
|
|
|
18014
18044
|
}
|
|
18015
18045
|
}
|
|
18016
18046
|
async function createSESResources(config2) {
|
|
18047
|
+
const configSetName = config2.domain ? domainToConfigSetName(config2.domain) : "wraps-email-tracking";
|
|
18017
18048
|
const configSetOptions = {
|
|
18018
|
-
configurationSetName:
|
|
18049
|
+
configurationSetName: configSetName,
|
|
18019
18050
|
deliveryOptions: config2.tlsRequired ? {
|
|
18020
18051
|
tlsPolicy: "REQUIRE"
|
|
18021
18052
|
// Require TLS 1.2+ for all emails
|
|
@@ -18040,7 +18071,6 @@ async function createSESResources(config2) {
|
|
|
18040
18071
|
httpsPolicy: config2.trackingConfig.httpsEnabled ? "REQUIRE" : "OPTIONAL"
|
|
18041
18072
|
};
|
|
18042
18073
|
}
|
|
18043
|
-
const configSetName = "wraps-email-tracking";
|
|
18044
18074
|
const exists = await configurationSetExists(configSetName, config2.region);
|
|
18045
18075
|
const configSet = exists && !config2.skipResourceImports ? new aws9.sesv2.ConfigurationSet(configSetName, configSetOptions, {
|
|
18046
18076
|
import: configSetName
|
|
@@ -18050,6 +18080,20 @@ async function createSESResources(config2) {
|
|
|
18050
18080
|
});
|
|
18051
18081
|
if (config2.eventTrackingEnabled) {
|
|
18052
18082
|
const eventDestName = "wraps-email-eventbridge";
|
|
18083
|
+
const opensEnabled = config2.trackingConfig?.opens ?? true;
|
|
18084
|
+
const clicksEnabled = config2.trackingConfig?.clicks ?? true;
|
|
18085
|
+
const matchingEventTypes = [
|
|
18086
|
+
"SEND",
|
|
18087
|
+
"DELIVERY",
|
|
18088
|
+
...opensEnabled ? ["OPEN"] : [],
|
|
18089
|
+
...clicksEnabled ? ["CLICK"] : [],
|
|
18090
|
+
"BOUNCE",
|
|
18091
|
+
"COMPLAINT",
|
|
18092
|
+
"REJECT",
|
|
18093
|
+
"RENDERING_FAILURE",
|
|
18094
|
+
"DELIVERY_DELAY",
|
|
18095
|
+
"SUBSCRIPTION"
|
|
18096
|
+
];
|
|
18053
18097
|
new aws9.sesv2.ConfigurationSetEventDestination(
|
|
18054
18098
|
"wraps-email-all-events",
|
|
18055
18099
|
{
|
|
@@ -18057,18 +18101,7 @@ async function createSESResources(config2) {
|
|
|
18057
18101
|
eventDestinationName: eventDestName,
|
|
18058
18102
|
eventDestination: {
|
|
18059
18103
|
enabled: true,
|
|
18060
|
-
matchingEventTypes
|
|
18061
|
-
"SEND",
|
|
18062
|
-
"DELIVERY",
|
|
18063
|
-
"OPEN",
|
|
18064
|
-
"CLICK",
|
|
18065
|
-
"BOUNCE",
|
|
18066
|
-
"COMPLAINT",
|
|
18067
|
-
"REJECT",
|
|
18068
|
-
"RENDERING_FAILURE",
|
|
18069
|
-
"DELIVERY_DELAY",
|
|
18070
|
-
"SUBSCRIPTION"
|
|
18071
|
-
],
|
|
18104
|
+
matchingEventTypes,
|
|
18072
18105
|
eventBridgeDestination: {
|
|
18073
18106
|
// SES requires default bus - cannot use custom bus
|
|
18074
18107
|
eventBusArn: defaultEventBus.arn
|
|
@@ -18078,7 +18111,7 @@ async function createSESResources(config2) {
|
|
|
18078
18111
|
{
|
|
18079
18112
|
// Import existing resource if it already exists in AWS but not in Pulumi state.
|
|
18080
18113
|
// Skip when skipResourceImports is true (resource already tracked in state).
|
|
18081
|
-
import: config2.importExistingEventDestination && !config2.skipResourceImports ?
|
|
18114
|
+
import: config2.importExistingEventDestination && !config2.skipResourceImports ? `${configSetName}|${eventDestName}` : void 0
|
|
18082
18115
|
}
|
|
18083
18116
|
);
|
|
18084
18117
|
}
|
|
@@ -18349,7 +18382,7 @@ async function deployEmailStack(config2) {
|
|
|
18349
18382
|
let sesResources;
|
|
18350
18383
|
if (emailConfig.tracking?.enabled || emailConfig.eventTracking?.enabled) {
|
|
18351
18384
|
const shouldImportEventDest = !config2.skipResourceImports && emailConfig.eventTracking?.enabled && await eventDestinationExists(
|
|
18352
|
-
"
|
|
18385
|
+
domainToConfigSetName(emailConfig.domain ?? ""),
|
|
18353
18386
|
"wraps-email-eventbridge",
|
|
18354
18387
|
config2.region
|
|
18355
18388
|
);
|
|
@@ -18433,7 +18466,7 @@ async function deployEmailStack(config2) {
|
|
|
18433
18466
|
let smtpResources;
|
|
18434
18467
|
if (emailConfig.smtpCredentials?.enabled && sesResources) {
|
|
18435
18468
|
smtpResources = await createSMTPCredentials({
|
|
18436
|
-
configSetName: "
|
|
18469
|
+
configSetName: domainToConfigSetName(emailConfig.domain ?? ""),
|
|
18437
18470
|
region: config2.region
|
|
18438
18471
|
});
|
|
18439
18472
|
}
|
|
@@ -19222,17 +19255,18 @@ ${pc19.dim("\u2500\u2500\u2500 end Pulumi output \u2500\u2500\u2500")}
|
|
|
19222
19255
|
tableName: outputs.tableName
|
|
19223
19256
|
});
|
|
19224
19257
|
if (selectedIdentities.length > 0 && emailConfig.tracking?.enabled) {
|
|
19258
|
+
const displayConfigSetName = outputs.configSetName ?? "wraps-email-<your-domain>";
|
|
19225
19259
|
console.log(`
|
|
19226
19260
|
${pc19.bold("Next Steps:")}
|
|
19227
19261
|
`);
|
|
19228
19262
|
console.log(
|
|
19229
|
-
`Update your code to use configuration set: ${pc19.cyan(
|
|
19263
|
+
`Update your code to use configuration set: ${pc19.cyan(displayConfigSetName)}`
|
|
19230
19264
|
);
|
|
19231
19265
|
console.log(`
|
|
19232
19266
|
${pc19.dim("Example:")}`);
|
|
19233
19267
|
console.log(
|
|
19234
19268
|
pc19.gray(` await ses.sendEmail({
|
|
19235
|
-
ConfigurationSetName: '
|
|
19269
|
+
ConfigurationSetName: '${displayConfigSetName}',
|
|
19236
19270
|
// ... other parameters
|
|
19237
19271
|
});`)
|
|
19238
19272
|
);
|
|
@@ -19550,6 +19584,42 @@ async function emailDestroy(options) {
|
|
|
19550
19584
|
"Some resources may not have been fully removed. You can re-run this command or clean up manually in the AWS console."
|
|
19551
19585
|
);
|
|
19552
19586
|
}
|
|
19587
|
+
if (destroyFailed) {
|
|
19588
|
+
try {
|
|
19589
|
+
const { SQSClient, GetQueueUrlCommand, DeleteQueueCommand } = await import("@aws-sdk/client-sqs");
|
|
19590
|
+
const sqsClient = new SQSClient({ region });
|
|
19591
|
+
for (const queueName of [
|
|
19592
|
+
"wraps-email-events",
|
|
19593
|
+
"wraps-email-events-dlq"
|
|
19594
|
+
]) {
|
|
19595
|
+
try {
|
|
19596
|
+
const { QueueUrl } = await sqsClient.send(
|
|
19597
|
+
new GetQueueUrlCommand({ QueueName: queueName })
|
|
19598
|
+
);
|
|
19599
|
+
if (QueueUrl) {
|
|
19600
|
+
await sqsClient.send(new DeleteQueueCommand({ QueueUrl }));
|
|
19601
|
+
}
|
|
19602
|
+
} catch {
|
|
19603
|
+
}
|
|
19604
|
+
}
|
|
19605
|
+
} catch {
|
|
19606
|
+
}
|
|
19607
|
+
}
|
|
19608
|
+
try {
|
|
19609
|
+
const { SESv2Client: SESv2Client9, DeleteConfigurationSetCommand: DeleteConfigSet } = await import("@aws-sdk/client-sesv2");
|
|
19610
|
+
const sesv22 = new SESv2Client9({ region });
|
|
19611
|
+
const additionalDomains = emailConfig?.additionalDomains ?? [];
|
|
19612
|
+
for (const d of additionalDomains) {
|
|
19613
|
+
if (!d.configSetName) continue;
|
|
19614
|
+
try {
|
|
19615
|
+
await sesv22.send(
|
|
19616
|
+
new DeleteConfigSet({ ConfigurationSetName: d.configSetName })
|
|
19617
|
+
);
|
|
19618
|
+
} catch {
|
|
19619
|
+
}
|
|
19620
|
+
}
|
|
19621
|
+
} catch {
|
|
19622
|
+
}
|
|
19553
19623
|
await deleteConnectionMetadata(identity.accountId, region);
|
|
19554
19624
|
progress.stop();
|
|
19555
19625
|
if (isJsonMode()) {
|
|
@@ -19917,6 +19987,7 @@ init_esm_shims();
|
|
|
19917
19987
|
init_client();
|
|
19918
19988
|
init_events();
|
|
19919
19989
|
init_dns();
|
|
19990
|
+
init_config_set_slug();
|
|
19920
19991
|
init_aws();
|
|
19921
19992
|
init_errors();
|
|
19922
19993
|
init_json_output();
|
|
@@ -19924,7 +19995,12 @@ init_metadata();
|
|
|
19924
19995
|
init_output();
|
|
19925
19996
|
init_prompts();
|
|
19926
19997
|
import { Resolver as Resolver2 } from "dns/promises";
|
|
19927
|
-
import {
|
|
19998
|
+
import {
|
|
19999
|
+
CreateConfigurationSetCommand,
|
|
20000
|
+
CreateConfigurationSetEventDestinationCommand,
|
|
20001
|
+
GetEmailIdentityCommand as GetEmailIdentityCommand2,
|
|
20002
|
+
SESv2Client as SESv2Client4
|
|
20003
|
+
} from "@aws-sdk/client-sesv2";
|
|
19928
20004
|
import * as clack21 from "@clack/prompts";
|
|
19929
20005
|
import pc23 from "picocolors";
|
|
19930
20006
|
async function checkVerification(domain, sesClient, region) {
|
|
@@ -20382,13 +20458,59 @@ Run ${pc23.cyan("wraps email init")} first to deploy email infrastructure.
|
|
|
20382
20458
|
if (!options.yes) {
|
|
20383
20459
|
purpose = await promptDomainPurpose();
|
|
20384
20460
|
}
|
|
20461
|
+
const configSetName = domainToConfigSetName(domain);
|
|
20462
|
+
const trackingConfig = {
|
|
20463
|
+
opens: purpose === "marketing" || purpose === "notifications",
|
|
20464
|
+
clicks: purpose === "marketing" || purpose === "notifications"
|
|
20465
|
+
};
|
|
20466
|
+
const baseEventTypes = [
|
|
20467
|
+
"SEND",
|
|
20468
|
+
"DELIVERY",
|
|
20469
|
+
"BOUNCE",
|
|
20470
|
+
"COMPLAINT",
|
|
20471
|
+
"REJECT",
|
|
20472
|
+
"RENDERING_FAILURE",
|
|
20473
|
+
"DELIVERY_DELAY",
|
|
20474
|
+
"SUBSCRIPTION"
|
|
20475
|
+
];
|
|
20476
|
+
const matchingEventTypes = trackingConfig.opens ? [...baseEventTypes, "OPEN", "CLICK"] : [...baseEventTypes];
|
|
20477
|
+
const eventBusArn = `arn:aws:events:${region}:${identity.accountId}:event-bus/default`;
|
|
20478
|
+
await progress.execute("Creating tracking configuration", async () => {
|
|
20479
|
+
try {
|
|
20480
|
+
await sesClient.send(
|
|
20481
|
+
new CreateConfigurationSetCommand({
|
|
20482
|
+
ConfigurationSetName: configSetName,
|
|
20483
|
+
SuppressionOptions: { SuppressedReasons: ["BOUNCE", "COMPLAINT"] }
|
|
20484
|
+
})
|
|
20485
|
+
);
|
|
20486
|
+
} catch (err) {
|
|
20487
|
+
if (err.name !== "AlreadyExistsException")
|
|
20488
|
+
throw err;
|
|
20489
|
+
}
|
|
20490
|
+
try {
|
|
20491
|
+
await sesClient.send(
|
|
20492
|
+
new CreateConfigurationSetEventDestinationCommand({
|
|
20493
|
+
ConfigurationSetName: configSetName,
|
|
20494
|
+
EventDestinationName: "wraps-email-eventbridge",
|
|
20495
|
+
EventDestination: {
|
|
20496
|
+
Enabled: true,
|
|
20497
|
+
MatchingEventTypes: matchingEventTypes,
|
|
20498
|
+
EventBridgeDestination: { EventBusArn: eventBusArn }
|
|
20499
|
+
}
|
|
20500
|
+
})
|
|
20501
|
+
);
|
|
20502
|
+
} catch (err) {
|
|
20503
|
+
if (err.name !== "AlreadyExistsException")
|
|
20504
|
+
throw err;
|
|
20505
|
+
}
|
|
20506
|
+
});
|
|
20385
20507
|
if (domainAlreadyExists) {
|
|
20386
20508
|
const { PutEmailIdentityConfigurationSetAttributesCommand } = await import("@aws-sdk/client-sesv2");
|
|
20387
20509
|
await progress.execute("Associating tracking configuration", async () => {
|
|
20388
20510
|
await sesClient.send(
|
|
20389
20511
|
new PutEmailIdentityConfigurationSetAttributesCommand({
|
|
20390
20512
|
EmailIdentity: domain,
|
|
20391
|
-
ConfigurationSetName:
|
|
20513
|
+
ConfigurationSetName: configSetName
|
|
20392
20514
|
})
|
|
20393
20515
|
);
|
|
20394
20516
|
});
|
|
@@ -20398,7 +20520,7 @@ Run ${pc23.cyan("wraps email init")} first to deploy email infrastructure.
|
|
|
20398
20520
|
await sesClient.send(
|
|
20399
20521
|
new CreateEmailIdentityCommand({
|
|
20400
20522
|
EmailIdentity: domain,
|
|
20401
|
-
ConfigurationSetName:
|
|
20523
|
+
ConfigurationSetName: configSetName,
|
|
20402
20524
|
DkimSigningAttributes: {
|
|
20403
20525
|
NextSigningKeyLength: "RSA_2048_BIT"
|
|
20404
20526
|
}
|
|
@@ -20511,6 +20633,8 @@ Run ${pc23.cyan("wraps email init")} first to deploy email infrastructure.
|
|
|
20511
20633
|
domain,
|
|
20512
20634
|
mailFromDomain,
|
|
20513
20635
|
purpose,
|
|
20636
|
+
configSetName,
|
|
20637
|
+
trackingConfig,
|
|
20514
20638
|
addedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
20515
20639
|
};
|
|
20516
20640
|
addDomainToMetadata(metadata, entry);
|
|
@@ -21424,7 +21548,7 @@ Deploy first: ${pc24.cyan("wraps email inbound init")}
|
|
|
21424
21548
|
}
|
|
21425
21549
|
const emailService = metadata.services.email;
|
|
21426
21550
|
const inboundConfig = emailService.config.inbound;
|
|
21427
|
-
if (!options.force) {
|
|
21551
|
+
if (!(options.force || options.preview)) {
|
|
21428
21552
|
clack22.log.warn(
|
|
21429
21553
|
`This will remove inbound email for ${pc24.cyan(inboundConfig.receivingDomain || "")}`
|
|
21430
21554
|
);
|
|
@@ -21437,17 +21561,6 @@ Deploy first: ${pc24.cyan("wraps email inbound init")}
|
|
|
21437
21561
|
process.exit(0);
|
|
21438
21562
|
}
|
|
21439
21563
|
}
|
|
21440
|
-
await progress.execute("Removing SES receipt rules", async () => {
|
|
21441
|
-
await deleteReceiptRule(region);
|
|
21442
|
-
await deleteReceiptRuleSet(region);
|
|
21443
|
-
});
|
|
21444
|
-
await progress.execute(
|
|
21445
|
-
"Preparing workspace",
|
|
21446
|
-
async () => ensurePulumiWorkDir({
|
|
21447
|
-
accountId: identity.accountId,
|
|
21448
|
-
region
|
|
21449
|
-
})
|
|
21450
|
-
);
|
|
21451
21564
|
const pulumiWorkDir = getPulumiWorkDir();
|
|
21452
21565
|
const stackName = emailService.pulumiStackName || `wraps-${identity.accountId}-${region}`;
|
|
21453
21566
|
const updatedEmailConfig = {
|
|
@@ -21458,7 +21571,8 @@ Deploy first: ${pc24.cyan("wraps email inbound init")}
|
|
|
21458
21571
|
const stackConfig = buildEmailStackConfig(metadata, region, {
|
|
21459
21572
|
emailConfig: updatedEmailConfig
|
|
21460
21573
|
});
|
|
21461
|
-
|
|
21574
|
+
const createStack = async () => {
|
|
21575
|
+
await ensurePulumiWorkDir({ accountId: identity.accountId, region });
|
|
21462
21576
|
const stack = await pulumi18.automation.LocalWorkspace.createOrSelectStack(
|
|
21463
21577
|
{
|
|
21464
21578
|
stackName,
|
|
@@ -21473,6 +21587,39 @@ Deploy first: ${pc24.cyan("wraps email inbound init")}
|
|
|
21473
21587
|
}
|
|
21474
21588
|
);
|
|
21475
21589
|
await stack.setConfig("aws:region", { value: region });
|
|
21590
|
+
return stack;
|
|
21591
|
+
};
|
|
21592
|
+
if (options.preview) {
|
|
21593
|
+
const previewResult = await progress.execute(
|
|
21594
|
+
"Generating infrastructure preview",
|
|
21595
|
+
async () => {
|
|
21596
|
+
const stack = await createStack();
|
|
21597
|
+
return previewWithResourceChanges(stack, { diff: true });
|
|
21598
|
+
}
|
|
21599
|
+
);
|
|
21600
|
+
displayPreview({
|
|
21601
|
+
changeSummary: previewResult.changeSummary,
|
|
21602
|
+
resourceChanges: previewResult.resourceChanges,
|
|
21603
|
+
commandName: "wraps email inbound destroy"
|
|
21604
|
+
});
|
|
21605
|
+
clack22.outro(
|
|
21606
|
+
pc24.green("Preview complete. Run without --preview to destroy.")
|
|
21607
|
+
);
|
|
21608
|
+
return;
|
|
21609
|
+
}
|
|
21610
|
+
await progress.execute("Removing SES receipt rules", async () => {
|
|
21611
|
+
await deleteReceiptRule(region);
|
|
21612
|
+
await deleteReceiptRuleSet(region);
|
|
21613
|
+
});
|
|
21614
|
+
await progress.execute(
|
|
21615
|
+
"Preparing workspace",
|
|
21616
|
+
async () => ensurePulumiWorkDir({
|
|
21617
|
+
accountId: identity.accountId,
|
|
21618
|
+
region
|
|
21619
|
+
})
|
|
21620
|
+
);
|
|
21621
|
+
await progress.execute("Removing inbound infrastructure", async () => {
|
|
21622
|
+
const stack = await createStack();
|
|
21476
21623
|
await withLockRetry(
|
|
21477
21624
|
() => withTimeout(
|
|
21478
21625
|
stack.up({ onOutput: () => {
|
|
@@ -22502,6 +22649,44 @@ async function init2(options) {
|
|
|
22502
22649
|
emailConfig.mailFromSubdomain = mailFromFull.endsWith(suffix) ? mailFromFull.slice(0, -suffix.length) || "mail" : "mail";
|
|
22503
22650
|
}
|
|
22504
22651
|
}
|
|
22652
|
+
if (!options.quick && preset !== "custom" && emailConfig.tracking?.enabled) {
|
|
22653
|
+
const purpose = await promptDomainPurpose();
|
|
22654
|
+
if (purpose === "transactional") {
|
|
22655
|
+
emailConfig.tracking = {
|
|
22656
|
+
...emailConfig.tracking,
|
|
22657
|
+
opens: false,
|
|
22658
|
+
clicks: false
|
|
22659
|
+
};
|
|
22660
|
+
} else if (purpose === "marketing" || purpose === "notifications") {
|
|
22661
|
+
emailConfig.tracking = {
|
|
22662
|
+
...emailConfig.tracking,
|
|
22663
|
+
opens: true,
|
|
22664
|
+
clicks: true
|
|
22665
|
+
};
|
|
22666
|
+
} else {
|
|
22667
|
+
const trackOpens = await clack26.confirm({
|
|
22668
|
+
message: "Track email opens?",
|
|
22669
|
+
initialValue: emailConfig.tracking.opens ?? true
|
|
22670
|
+
});
|
|
22671
|
+
if (clack26.isCancel(trackOpens)) {
|
|
22672
|
+
clack26.cancel("Operation cancelled.");
|
|
22673
|
+
process.exit(0);
|
|
22674
|
+
}
|
|
22675
|
+
const trackClicks = await clack26.confirm({
|
|
22676
|
+
message: "Track link clicks?",
|
|
22677
|
+
initialValue: emailConfig.tracking.clicks ?? true
|
|
22678
|
+
});
|
|
22679
|
+
if (clack26.isCancel(trackClicks)) {
|
|
22680
|
+
clack26.cancel("Operation cancelled.");
|
|
22681
|
+
process.exit(0);
|
|
22682
|
+
}
|
|
22683
|
+
emailConfig.tracking = {
|
|
22684
|
+
...emailConfig.tracking,
|
|
22685
|
+
opens: trackOpens,
|
|
22686
|
+
clicks: trackClicks
|
|
22687
|
+
};
|
|
22688
|
+
}
|
|
22689
|
+
}
|
|
22505
22690
|
let costSummary;
|
|
22506
22691
|
if (!options.quick) {
|
|
22507
22692
|
const estimatedVolume = await promptEstimatedVolume();
|
|
@@ -23372,6 +23557,59 @@ async function replyInit(options) {
|
|
|
23372
23557
|
);
|
|
23373
23558
|
}
|
|
23374
23559
|
const stackName = emailService.pulumiStackName || `wraps-${identity.accountId}-${region}`;
|
|
23560
|
+
if (options.preview) {
|
|
23561
|
+
const previewResult = await progress.execute(
|
|
23562
|
+
"Generating infrastructure preview",
|
|
23563
|
+
async () => {
|
|
23564
|
+
const previewMetadata = JSON.parse(
|
|
23565
|
+
JSON.stringify(metadata)
|
|
23566
|
+
);
|
|
23567
|
+
const previewEmailConfig = previewMetadata.services.email.config;
|
|
23568
|
+
const rt = previewEmailConfig.replyThreading ?? {
|
|
23569
|
+
enabled: false,
|
|
23570
|
+
domains: []
|
|
23571
|
+
};
|
|
23572
|
+
for (const domain of targetDomains) {
|
|
23573
|
+
const filtered = rt.domains.filter((d) => d.domain !== domain);
|
|
23574
|
+
filtered.push({
|
|
23575
|
+
domain,
|
|
23576
|
+
initialSecret: randomBytes5(32).toString("base64"),
|
|
23577
|
+
currentKid: 1,
|
|
23578
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
23579
|
+
});
|
|
23580
|
+
rt.domains = filtered;
|
|
23581
|
+
}
|
|
23582
|
+
previewEmailConfig.replyThreading = {
|
|
23583
|
+
enabled: true,
|
|
23584
|
+
domains: rt.domains
|
|
23585
|
+
};
|
|
23586
|
+
const stackConfig = buildEmailStackConfig(previewMetadata, region);
|
|
23587
|
+
await ensurePulumiWorkDir({ accountId: identity.accountId, region });
|
|
23588
|
+
const stack = await pulumi20.automation.LocalWorkspace.createOrSelectStack(
|
|
23589
|
+
{
|
|
23590
|
+
stackName,
|
|
23591
|
+
projectName: "wraps-email",
|
|
23592
|
+
program: async () => {
|
|
23593
|
+
const result = await deployEmailStack(stackConfig);
|
|
23594
|
+
return result;
|
|
23595
|
+
}
|
|
23596
|
+
},
|
|
23597
|
+
{
|
|
23598
|
+
workDir: getPulumiWorkDir()
|
|
23599
|
+
}
|
|
23600
|
+
);
|
|
23601
|
+
await stack.setConfig("aws:region", { value: region });
|
|
23602
|
+
return previewWithResourceChanges(stack, { diff: true });
|
|
23603
|
+
}
|
|
23604
|
+
);
|
|
23605
|
+
displayPreview({
|
|
23606
|
+
changeSummary: previewResult.changeSummary,
|
|
23607
|
+
resourceChanges: previewResult.resourceChanges,
|
|
23608
|
+
commandName: "wraps email reply init"
|
|
23609
|
+
});
|
|
23610
|
+
clack27.outro(pc29.green("Preview complete. Run without --preview to deploy."));
|
|
23611
|
+
return;
|
|
23612
|
+
}
|
|
23375
23613
|
const results = [];
|
|
23376
23614
|
for (const domain of targetDomains) {
|
|
23377
23615
|
const fresh = await loadConnectionMetadata(identity.accountId, region);
|
|
@@ -23713,7 +23951,7 @@ async function replyDestroy(options) {
|
|
|
23713
23951
|
"https://wraps.dev/docs/guides/reply-threading"
|
|
23714
23952
|
);
|
|
23715
23953
|
}
|
|
23716
|
-
if (!(options.force || isJsonMode())) {
|
|
23954
|
+
if (!(options.force || options.preview || isJsonMode())) {
|
|
23717
23955
|
const confirmed = await clack27.confirm({
|
|
23718
23956
|
message: `Remove reply threading for ${targets.join(", ")}?`,
|
|
23719
23957
|
initialValue: false
|
|
@@ -23723,10 +23961,55 @@ async function replyDestroy(options) {
|
|
|
23723
23961
|
return;
|
|
23724
23962
|
}
|
|
23725
23963
|
}
|
|
23964
|
+
const emailService = metadata.services.email;
|
|
23965
|
+
if (options.preview) {
|
|
23966
|
+
if (emailService) {
|
|
23967
|
+
const previewMetadata = JSON.parse(
|
|
23968
|
+
JSON.stringify(metadata)
|
|
23969
|
+
);
|
|
23970
|
+
for (const domain of targets) {
|
|
23971
|
+
stripDomainFromReplyThreadingMetadata({
|
|
23972
|
+
domain,
|
|
23973
|
+
metadata: previewMetadata
|
|
23974
|
+
});
|
|
23975
|
+
}
|
|
23976
|
+
const stackName = emailService.pulumiStackName || `wraps-${identity.accountId}-${region}`;
|
|
23977
|
+
const stackConfig = buildEmailStackConfig(previewMetadata, region);
|
|
23978
|
+
const previewResult = await progress.execute(
|
|
23979
|
+
"Generating infrastructure preview",
|
|
23980
|
+
async () => {
|
|
23981
|
+
await ensurePulumiWorkDir({ accountId: identity.accountId, region });
|
|
23982
|
+
const stack = await pulumi20.automation.LocalWorkspace.createOrSelectStack(
|
|
23983
|
+
{
|
|
23984
|
+
stackName,
|
|
23985
|
+
projectName: "wraps-email",
|
|
23986
|
+
program: async () => {
|
|
23987
|
+
const result = await deployEmailStack(stackConfig);
|
|
23988
|
+
return result;
|
|
23989
|
+
}
|
|
23990
|
+
},
|
|
23991
|
+
{
|
|
23992
|
+
workDir: getPulumiWorkDir()
|
|
23993
|
+
}
|
|
23994
|
+
);
|
|
23995
|
+
await stack.setConfig("aws:region", { value: region });
|
|
23996
|
+
return previewWithResourceChanges(stack, { diff: true });
|
|
23997
|
+
}
|
|
23998
|
+
);
|
|
23999
|
+
displayPreview({
|
|
24000
|
+
changeSummary: previewResult.changeSummary,
|
|
24001
|
+
resourceChanges: previewResult.resourceChanges,
|
|
24002
|
+
commandName: "wraps email reply destroy"
|
|
24003
|
+
});
|
|
24004
|
+
}
|
|
24005
|
+
clack27.outro(
|
|
24006
|
+
pc29.green("Preview complete. Run without --preview to destroy.")
|
|
24007
|
+
);
|
|
24008
|
+
return;
|
|
24009
|
+
}
|
|
23726
24010
|
for (const domain of targets) {
|
|
23727
24011
|
stripDomainFromReplyThreadingMetadata({ domain, metadata });
|
|
23728
24012
|
}
|
|
23729
|
-
const emailService = metadata.services.email;
|
|
23730
24013
|
if (emailService) {
|
|
23731
24014
|
const stackName = emailService.pulumiStackName || `wraps-${identity.accountId}-${region}`;
|
|
23732
24015
|
const stackConfig = buildEmailStackConfig(metadata, region);
|
|
@@ -23819,6 +24102,7 @@ async function replyDecode(addressInput, options) {
|
|
|
23819
24102
|
// src/commands/email/restore.ts
|
|
23820
24103
|
init_esm_shims();
|
|
23821
24104
|
init_events();
|
|
24105
|
+
init_config_set_slug();
|
|
23822
24106
|
init_aws();
|
|
23823
24107
|
init_errors();
|
|
23824
24108
|
init_fs();
|
|
@@ -23882,7 +24166,10 @@ ${pc30.bold("The following Wraps resources will be removed:")}
|
|
|
23882
24166
|
`
|
|
23883
24167
|
);
|
|
23884
24168
|
if (metadata.services.email?.config.tracking?.enabled) {
|
|
23885
|
-
|
|
24169
|
+
const configSetName = domainToConfigSetName(
|
|
24170
|
+
metadata.services.email.config.domain ?? ""
|
|
24171
|
+
);
|
|
24172
|
+
console.log(` ${pc30.cyan("\u2713")} Configuration Set (${configSetName})`);
|
|
23886
24173
|
}
|
|
23887
24174
|
if (metadata.services.email?.config.eventTracking?.dynamoDBHistory) {
|
|
23888
24175
|
console.log(` ${pc30.cyan("\u2713")} DynamoDB Table (wraps-email-history)`);
|
|
@@ -25440,7 +25727,7 @@ function renderErrorPage(err) {
|
|
|
25440
25727
|
// src/commands/email/templates/push.ts
|
|
25441
25728
|
init_esm_shims();
|
|
25442
25729
|
init_events();
|
|
25443
|
-
import { createHash } from "crypto";
|
|
25730
|
+
import { createHash as createHash2 } from "crypto";
|
|
25444
25731
|
import { existsSync as existsSync13 } from "fs";
|
|
25445
25732
|
import { mkdir as mkdir6, readFile as readFile6, writeFile as writeFile8 } from "fs/promises";
|
|
25446
25733
|
import { join as join15 } from "path";
|
|
@@ -26077,7 +26364,7 @@ async function pushToAPI(templates, token, progress, force) {
|
|
|
26077
26364
|
return results;
|
|
26078
26365
|
}
|
|
26079
26366
|
function sha256(content) {
|
|
26080
|
-
return
|
|
26367
|
+
return createHash2("sha256").update(content).digest("hex");
|
|
26081
26368
|
}
|
|
26082
26369
|
|
|
26083
26370
|
// src/cli.ts
|
|
@@ -26301,6 +26588,11 @@ ${pc35.bold("Current Configuration:")}
|
|
|
26301
26588
|
value: "hosting-provider",
|
|
26302
26589
|
label: "Change hosting provider",
|
|
26303
26590
|
hint: metadata.provider === "vercel" ? `Currently: Vercel (${metadata.vercel?.teamSlug || "configured"})` : `Currently: ${metadata.provider} \u2192 Switch to Vercel OIDC, etc.`
|
|
26591
|
+
},
|
|
26592
|
+
{
|
|
26593
|
+
value: "per-domain-config-sets",
|
|
26594
|
+
label: "Per-domain configuration sets",
|
|
26595
|
+
hint: "Create dedicated SES config sets for each additional domain"
|
|
26304
26596
|
}
|
|
26305
26597
|
);
|
|
26306
26598
|
if (options.action) {
|
|
@@ -27433,6 +27725,141 @@ ${pc35.bold("SMTP Credentials for Legacy Systems")}
|
|
|
27433
27725
|
}
|
|
27434
27726
|
break;
|
|
27435
27727
|
}
|
|
27728
|
+
case "per-domain-config-sets": {
|
|
27729
|
+
const {
|
|
27730
|
+
SESv2Client: SESv2Client9,
|
|
27731
|
+
CreateConfigurationSetCommand: CreateConfigurationSetCommand2,
|
|
27732
|
+
CreateConfigurationSetEventDestinationCommand: CreateConfigurationSetEventDestinationCommand2,
|
|
27733
|
+
PutEmailIdentityConfigurationSetAttributesCommand,
|
|
27734
|
+
EventType
|
|
27735
|
+
} = await import("@aws-sdk/client-sesv2");
|
|
27736
|
+
const { domainToConfigSetName: domainToConfigSetName2 } = await Promise.resolve().then(() => (init_config_set_slug(), config_set_slug_exports));
|
|
27737
|
+
const sesClient = new SESv2Client9({ region });
|
|
27738
|
+
const accountId = identity.accountId;
|
|
27739
|
+
const additionalDomains = metadata.services.email?.config.additionalDomains ?? [];
|
|
27740
|
+
const unmigratedDomains = additionalDomains.filter(
|
|
27741
|
+
(d) => !d.configSetName
|
|
27742
|
+
);
|
|
27743
|
+
if (unmigratedDomains.length === 0) {
|
|
27744
|
+
clack34.log.info(
|
|
27745
|
+
"All additional domains are already migrated to per-domain config sets."
|
|
27746
|
+
);
|
|
27747
|
+
clack34.outro(pc35.green("\u2713 Nothing to migrate"));
|
|
27748
|
+
trackServiceUpgrade("email", {
|
|
27749
|
+
action: "per-domain-config-sets",
|
|
27750
|
+
duration_ms: Date.now() - startTime
|
|
27751
|
+
});
|
|
27752
|
+
return;
|
|
27753
|
+
}
|
|
27754
|
+
clack34.log.info(
|
|
27755
|
+
`Migrating ${unmigratedDomains.length} domain(s) to per-domain configuration sets...`
|
|
27756
|
+
);
|
|
27757
|
+
const eventBusArn = `arn:aws:events:${region}:${accountId}:event-bus/default`;
|
|
27758
|
+
for (let i = 0; i < unmigratedDomains.length; i++) {
|
|
27759
|
+
const d = unmigratedDomains[i];
|
|
27760
|
+
const configSetName = domainToConfigSetName2(d.domain);
|
|
27761
|
+
clack34.log.step(
|
|
27762
|
+
`Migrating ${pc35.cyan(d.domain)} \u2192 ${pc35.dim(configSetName)}`
|
|
27763
|
+
);
|
|
27764
|
+
await progress.execute(
|
|
27765
|
+
`Creating config set for ${d.domain}`,
|
|
27766
|
+
async () => {
|
|
27767
|
+
try {
|
|
27768
|
+
await sesClient.send(
|
|
27769
|
+
new CreateConfigurationSetCommand2({
|
|
27770
|
+
ConfigurationSetName: configSetName,
|
|
27771
|
+
SuppressionOptions: {
|
|
27772
|
+
SuppressedReasons: ["BOUNCE", "COMPLAINT"]
|
|
27773
|
+
}
|
|
27774
|
+
})
|
|
27775
|
+
);
|
|
27776
|
+
} catch (err) {
|
|
27777
|
+
if (err.name !== "AlreadyExistsException")
|
|
27778
|
+
throw err;
|
|
27779
|
+
}
|
|
27780
|
+
}
|
|
27781
|
+
);
|
|
27782
|
+
const allEvents = [
|
|
27783
|
+
EventType.SEND,
|
|
27784
|
+
EventType.DELIVERY,
|
|
27785
|
+
EventType.OPEN,
|
|
27786
|
+
EventType.CLICK,
|
|
27787
|
+
EventType.BOUNCE,
|
|
27788
|
+
EventType.COMPLAINT,
|
|
27789
|
+
EventType.REJECT,
|
|
27790
|
+
EventType.RENDERING_FAILURE,
|
|
27791
|
+
EventType.DELIVERY_DELAY,
|
|
27792
|
+
EventType.SUBSCRIPTION
|
|
27793
|
+
];
|
|
27794
|
+
const matchingEventTypes = d.trackingConfig != null ? allEvents.filter((evt) => {
|
|
27795
|
+
if (evt === EventType.OPEN) return d.trackingConfig.opens;
|
|
27796
|
+
if (evt === EventType.CLICK) return d.trackingConfig.clicks;
|
|
27797
|
+
return true;
|
|
27798
|
+
}) : [...allEvents];
|
|
27799
|
+
await progress.execute(
|
|
27800
|
+
`Adding EventBridge destination for ${d.domain}`,
|
|
27801
|
+
async () => {
|
|
27802
|
+
try {
|
|
27803
|
+
await sesClient.send(
|
|
27804
|
+
new CreateConfigurationSetEventDestinationCommand2({
|
|
27805
|
+
ConfigurationSetName: configSetName,
|
|
27806
|
+
EventDestinationName: "wraps-email-eventbridge",
|
|
27807
|
+
EventDestination: {
|
|
27808
|
+
Enabled: true,
|
|
27809
|
+
MatchingEventTypes: matchingEventTypes,
|
|
27810
|
+
EventBridgeDestination: { EventBusArn: eventBusArn }
|
|
27811
|
+
}
|
|
27812
|
+
})
|
|
27813
|
+
);
|
|
27814
|
+
} catch (err) {
|
|
27815
|
+
if (err.name !== "AlreadyExistsException")
|
|
27816
|
+
throw err;
|
|
27817
|
+
}
|
|
27818
|
+
}
|
|
27819
|
+
);
|
|
27820
|
+
d.configSetName = configSetName;
|
|
27821
|
+
await saveConnectionMetadata(metadata);
|
|
27822
|
+
try {
|
|
27823
|
+
await progress.execute(
|
|
27824
|
+
`Reassigning identity ${d.domain}`,
|
|
27825
|
+
async () => {
|
|
27826
|
+
await sesClient.send(
|
|
27827
|
+
new PutEmailIdentityConfigurationSetAttributesCommand({
|
|
27828
|
+
EmailIdentity: d.domain,
|
|
27829
|
+
ConfigurationSetName: configSetName
|
|
27830
|
+
})
|
|
27831
|
+
);
|
|
27832
|
+
}
|
|
27833
|
+
);
|
|
27834
|
+
} catch (err) {
|
|
27835
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
27836
|
+
clack34.log.warn(
|
|
27837
|
+
`Failed to reassign identity for ${pc35.cyan(d.domain)}: ${msg}`
|
|
27838
|
+
);
|
|
27839
|
+
clack34.log.info(
|
|
27840
|
+
pc35.dim(
|
|
27841
|
+
`Config set was saved \u2014 re-run to retry identity reassignment for ${d.domain}`
|
|
27842
|
+
)
|
|
27843
|
+
);
|
|
27844
|
+
}
|
|
27845
|
+
if (i < unmigratedDomains.length - 1) {
|
|
27846
|
+
await new Promise((resolve) => setTimeout(resolve, 1e3));
|
|
27847
|
+
}
|
|
27848
|
+
}
|
|
27849
|
+
clack34.log.info(
|
|
27850
|
+
`For the primary domain (${pc35.cyan(config2.domain ?? "")}) config set rename: re-run ${pc35.cyan("wraps email upgrade")} with a Pulumi stack update.`
|
|
27851
|
+
);
|
|
27852
|
+
clack34.outro(
|
|
27853
|
+
pc35.green(
|
|
27854
|
+
`\u2713 Per-domain config sets migration complete (${unmigratedDomains.length} domain(s))`
|
|
27855
|
+
)
|
|
27856
|
+
);
|
|
27857
|
+
trackServiceUpgrade("email", {
|
|
27858
|
+
action: "per-domain-config-sets",
|
|
27859
|
+
duration_ms: Date.now() - startTime
|
|
27860
|
+
});
|
|
27861
|
+
return;
|
|
27862
|
+
}
|
|
27436
27863
|
}
|
|
27437
27864
|
const newCostData = calculateCosts(updatedConfig, 5e4);
|
|
27438
27865
|
const costDiff = newCostData.total.monthly - currentCostData.total.monthly;
|
|
@@ -28813,7 +29240,7 @@ function assignPositions(steps, transitions) {
|
|
|
28813
29240
|
|
|
28814
29241
|
// src/utils/email/workflow-ts.ts
|
|
28815
29242
|
init_esm_shims();
|
|
28816
|
-
import { createHash as
|
|
29243
|
+
import { createHash as createHash3 } from "crypto";
|
|
28817
29244
|
import { existsSync as existsSync15 } from "fs";
|
|
28818
29245
|
import { mkdir as mkdir8, readdir as readdir4, readFile as readFile8, writeFile as writeFile10 } from "fs/promises";
|
|
28819
29246
|
import { basename, join as join17 } from "path";
|
|
@@ -28839,7 +29266,7 @@ async function discoverWorkflows(dir, filter) {
|
|
|
28839
29266
|
async function parseWorkflowTs(filePath, wrapsDir) {
|
|
28840
29267
|
const { build: build2 } = await import("esbuild");
|
|
28841
29268
|
const source = await readFile8(filePath, "utf-8");
|
|
28842
|
-
const sourceHash =
|
|
29269
|
+
const sourceHash = createHash3("sha256").update(source).digest("hex");
|
|
28843
29270
|
const slug = basename(filePath, ".ts");
|
|
28844
29271
|
const shimDir = join17(wrapsDir, ".wraps", "_shims");
|
|
28845
29272
|
await mkdir8(shimDir, { recursive: true });
|
|
@@ -30494,7 +30921,7 @@ import {
|
|
|
30494
30921
|
IAMClient as IAMClient3,
|
|
30495
30922
|
PutRolePolicyCommand
|
|
30496
30923
|
} from "@aws-sdk/client-iam";
|
|
30497
|
-
import { confirm as confirm18, intro as intro34, isCancel as isCancel25, log as log36, outro as
|
|
30924
|
+
import { confirm as confirm18, intro as intro34, isCancel as isCancel25, log as log36, outro as outro22, select as select17 } from "@clack/prompts";
|
|
30498
30925
|
import * as pulumi24 from "@pulumi/pulumi";
|
|
30499
30926
|
import pc41 from "picocolors";
|
|
30500
30927
|
init_events();
|
|
@@ -30856,7 +31283,7 @@ async function resolveOrganization() {
|
|
|
30856
31283
|
}))
|
|
30857
31284
|
});
|
|
30858
31285
|
if (isCancel25(selected)) {
|
|
30859
|
-
|
|
31286
|
+
outro22("Operation cancelled");
|
|
30860
31287
|
process.exit(0);
|
|
30861
31288
|
}
|
|
30862
31289
|
return orgs.find((o) => o.id === selected) || null;
|
|
@@ -30922,7 +31349,7 @@ async function authenticatedConnect(token, options) {
|
|
|
30922
31349
|
initialValue: true
|
|
30923
31350
|
});
|
|
30924
31351
|
if (isCancel25(enableTracking) || !enableTracking) {
|
|
30925
|
-
|
|
31352
|
+
outro22("Platform connection cancelled.");
|
|
30926
31353
|
process.exit(0);
|
|
30927
31354
|
}
|
|
30928
31355
|
metadata.services.email.config = {
|
|
@@ -31013,7 +31440,7 @@ You can try the manual flow: ${pc41.cyan("wraps auth logout")} then ${pc41.cyan(
|
|
|
31013
31440
|
webhookConnected: true
|
|
31014
31441
|
});
|
|
31015
31442
|
} else {
|
|
31016
|
-
|
|
31443
|
+
outro22(pc41.green("Platform connection complete!"));
|
|
31017
31444
|
console.log();
|
|
31018
31445
|
console.log(
|
|
31019
31446
|
pc41.dim(
|
|
@@ -31117,7 +31544,7 @@ Run ${pc41.cyan("wraps email init")} or ${pc41.cyan("wraps sms init")} first.
|
|
|
31117
31544
|
initialValue: true
|
|
31118
31545
|
});
|
|
31119
31546
|
if (isCancel25(enableEventTracking) || !enableEventTracking) {
|
|
31120
|
-
|
|
31547
|
+
outro22("Platform connection cancelled.");
|
|
31121
31548
|
process.exit(0);
|
|
31122
31549
|
}
|
|
31123
31550
|
metadata.services.email.config = {
|
|
@@ -31165,7 +31592,7 @@ Run ${pc41.cyan("wraps email init")} or ${pc41.cyan("wraps sms init")} first.
|
|
|
31165
31592
|
]
|
|
31166
31593
|
});
|
|
31167
31594
|
if (isCancel25(action)) {
|
|
31168
|
-
|
|
31595
|
+
outro22("Operation cancelled");
|
|
31169
31596
|
process.exit(0);
|
|
31170
31597
|
}
|
|
31171
31598
|
if (action === "keep") {
|
|
@@ -31176,7 +31603,7 @@ Run ${pc41.cyan("wraps email init")} or ${pc41.cyan("wraps sms init")} first.
|
|
|
31176
31603
|
initialValue: false
|
|
31177
31604
|
});
|
|
31178
31605
|
if (isCancel25(confirmDisconnect) || !confirmDisconnect) {
|
|
31179
|
-
|
|
31606
|
+
outro22("Disconnect cancelled");
|
|
31180
31607
|
process.exit(0);
|
|
31181
31608
|
}
|
|
31182
31609
|
metadata.services.email.webhookSecret = void 0;
|
|
@@ -31274,7 +31701,7 @@ Run ${pc41.cyan("wraps email init")} or ${pc41.cyan("wraps sms init")} first.
|
|
|
31274
31701
|
}
|
|
31275
31702
|
await saveConnectionMetadata(metadata);
|
|
31276
31703
|
progress.stop();
|
|
31277
|
-
|
|
31704
|
+
outro22(pc41.green("Platform connection complete!"));
|
|
31278
31705
|
if (webhookSecret && needsDeployment) {
|
|
31279
31706
|
console.log(`
|
|
31280
31707
|
${pc41.bold("Webhook Secret")} ${pc41.dim("(save this!)")}`);
|
|
@@ -31387,7 +31814,7 @@ import {
|
|
|
31387
31814
|
GetRoleCommand as GetRoleCommand2,
|
|
31388
31815
|
IAMClient as IAMClient4
|
|
31389
31816
|
} from "@aws-sdk/client-iam";
|
|
31390
|
-
import { confirm as confirm19, intro as intro36, isCancel as isCancel26, log as log37, outro as
|
|
31817
|
+
import { confirm as confirm19, intro as intro36, isCancel as isCancel26, log as log37, outro as outro23 } from "@clack/prompts";
|
|
31391
31818
|
import pc43 from "picocolors";
|
|
31392
31819
|
async function updateRole(options) {
|
|
31393
31820
|
const startTime = Date.now();
|
|
@@ -31457,7 +31884,7 @@ Run ${pc43.cyan("wraps email init")} to deploy infrastructure first.
|
|
|
31457
31884
|
initialValue: true
|
|
31458
31885
|
});
|
|
31459
31886
|
if (isCancel26(shouldContinue) || !shouldContinue) {
|
|
31460
|
-
|
|
31887
|
+
outro23(`${actionLabel} cancelled`);
|
|
31461
31888
|
process.exit(0);
|
|
31462
31889
|
}
|
|
31463
31890
|
}
|
|
@@ -31537,7 +31964,7 @@ Run ${pc43.cyan("wraps email init")} to deploy infrastructure first.
|
|
|
31537
31964
|
});
|
|
31538
31965
|
return;
|
|
31539
31966
|
}
|
|
31540
|
-
|
|
31967
|
+
outro23(pc43.green(`\u2713 Platform access role ${actionVerb} successfully`));
|
|
31541
31968
|
console.log(`
|
|
31542
31969
|
${pc43.bold("Permissions:")}`);
|
|
31543
31970
|
console.log(`
|
|
@@ -33096,6 +33523,7 @@ function createMetricsRouter(config2) {
|
|
|
33096
33523
|
|
|
33097
33524
|
// src/console/routes/settings.ts
|
|
33098
33525
|
init_esm_shims();
|
|
33526
|
+
init_config_set_slug();
|
|
33099
33527
|
init_metadata();
|
|
33100
33528
|
import dns4 from "dns/promises";
|
|
33101
33529
|
import { Router as createRouter6 } from "express";
|
|
@@ -33232,8 +33660,8 @@ function createSettingsRouter(config2) {
|
|
|
33232
33660
|
error: "No Wraps infrastructure found for this account and region"
|
|
33233
33661
|
});
|
|
33234
33662
|
}
|
|
33235
|
-
const configSetName = "wraps-email-tracking";
|
|
33236
33663
|
const domain = metadata.services.email?.config.domain;
|
|
33664
|
+
const configSetName = domainToConfigSetName(domain ?? "");
|
|
33237
33665
|
const settings = await fetchEmailSettings(
|
|
33238
33666
|
config2.roleArn,
|
|
33239
33667
|
config2.region,
|
|
@@ -33335,7 +33763,9 @@ function createSettingsRouter(config2) {
|
|
|
33335
33763
|
error: "No Wraps infrastructure found for this account and region"
|
|
33336
33764
|
});
|
|
33337
33765
|
}
|
|
33338
|
-
const configSetName =
|
|
33766
|
+
const configSetName = domainToConfigSetName(
|
|
33767
|
+
metadata.services.email?.config.domain ?? ""
|
|
33768
|
+
);
|
|
33339
33769
|
console.log(
|
|
33340
33770
|
`[Settings] Updating sending options for ${configSetName}: ${enabled}`
|
|
33341
33771
|
);
|
|
@@ -33372,7 +33802,9 @@ function createSettingsRouter(config2) {
|
|
|
33372
33802
|
error: "No Wraps infrastructure found for this account and region"
|
|
33373
33803
|
});
|
|
33374
33804
|
}
|
|
33375
|
-
const configSetName =
|
|
33805
|
+
const configSetName = domainToConfigSetName(
|
|
33806
|
+
metadata.services.email?.config.domain ?? ""
|
|
33807
|
+
);
|
|
33376
33808
|
console.log(
|
|
33377
33809
|
`[Settings] Updating reputation options for ${configSetName}: ${enabled}`
|
|
33378
33810
|
);
|
|
@@ -33415,7 +33847,9 @@ function createSettingsRouter(config2) {
|
|
|
33415
33847
|
error: "No Wraps infrastructure found for this account and region"
|
|
33416
33848
|
});
|
|
33417
33849
|
}
|
|
33418
|
-
const configSetName =
|
|
33850
|
+
const configSetName = domainToConfigSetName(
|
|
33851
|
+
metadata.services.email?.config.domain ?? ""
|
|
33852
|
+
);
|
|
33419
33853
|
console.log(
|
|
33420
33854
|
`[Settings] Updating tracking domain for ${configSetName}: ${domain}`
|
|
33421
33855
|
);
|
|
@@ -36464,7 +36898,7 @@ ${pc48.yellow(pc48.bold("Important Notes:"))}`);
|
|
|
36464
36898
|
clack45.log.warn(warning);
|
|
36465
36899
|
}
|
|
36466
36900
|
}
|
|
36467
|
-
if (!options.yes) {
|
|
36901
|
+
if (!(options.yes || options.preview)) {
|
|
36468
36902
|
const confirmed = await confirmDeploy();
|
|
36469
36903
|
if (!confirmed) {
|
|
36470
36904
|
clack45.cancel("Deployment cancelled.");
|
|
@@ -36477,43 +36911,77 @@ ${pc48.yellow(pc48.bold("Important Notes:"))}`);
|
|
|
36477
36911
|
vercel: vercelConfig,
|
|
36478
36912
|
smsConfig
|
|
36479
36913
|
};
|
|
36914
|
+
const createStack = async () => {
|
|
36915
|
+
await ensurePulumiWorkDir({ accountId: identity.accountId, region });
|
|
36916
|
+
const stack = await pulumi29.automation.LocalWorkspace.createOrSelectStack(
|
|
36917
|
+
{
|
|
36918
|
+
stackName: `wraps-sms-${identity.accountId}-${region}`,
|
|
36919
|
+
projectName: "wraps-sms",
|
|
36920
|
+
program: async () => {
|
|
36921
|
+
const result = await deploySMSStack(stackConfig);
|
|
36922
|
+
return {
|
|
36923
|
+
roleArn: result.roleArn,
|
|
36924
|
+
phoneNumber: result.phoneNumber,
|
|
36925
|
+
phoneNumberArn: result.phoneNumberArn,
|
|
36926
|
+
configSetName: result.configSetName,
|
|
36927
|
+
tableName: result.tableName,
|
|
36928
|
+
region: result.region,
|
|
36929
|
+
lambdaFunctions: result.lambdaFunctions,
|
|
36930
|
+
snsTopicArn: result.snsTopicArn,
|
|
36931
|
+
queueUrl: result.queueUrl,
|
|
36932
|
+
dlqUrl: result.dlqUrl,
|
|
36933
|
+
optOutListArn: result.optOutListArn
|
|
36934
|
+
};
|
|
36935
|
+
}
|
|
36936
|
+
},
|
|
36937
|
+
{
|
|
36938
|
+
workDir: getPulumiWorkDir(),
|
|
36939
|
+
envVars: {
|
|
36940
|
+
PULUMI_CONFIG_PASSPHRASE: "",
|
|
36941
|
+
AWS_REGION: region
|
|
36942
|
+
},
|
|
36943
|
+
secretsProvider: "passphrase"
|
|
36944
|
+
}
|
|
36945
|
+
);
|
|
36946
|
+
await stack.setConfig("aws:region", { value: region });
|
|
36947
|
+
return stack;
|
|
36948
|
+
};
|
|
36949
|
+
if (options.preview) {
|
|
36950
|
+
try {
|
|
36951
|
+
const previewResult = await progress.execute(
|
|
36952
|
+
"Generating infrastructure preview",
|
|
36953
|
+
async () => {
|
|
36954
|
+
const stack = await createStack();
|
|
36955
|
+
return previewWithResourceChanges(stack, { diff: true });
|
|
36956
|
+
}
|
|
36957
|
+
);
|
|
36958
|
+
displayPreview({
|
|
36959
|
+
changeSummary: previewResult.changeSummary,
|
|
36960
|
+
resourceChanges: previewResult.resourceChanges,
|
|
36961
|
+
costEstimate: getSMSCostSummary(smsConfig, 0),
|
|
36962
|
+
commandName: "wraps sms init"
|
|
36963
|
+
});
|
|
36964
|
+
clack45.outro(
|
|
36965
|
+
pc48.green("Preview complete. Run without --preview to deploy.")
|
|
36966
|
+
);
|
|
36967
|
+
trackServiceInit("sms", true, {
|
|
36968
|
+
provider,
|
|
36969
|
+
region,
|
|
36970
|
+
preview: true,
|
|
36971
|
+
duration_ms: Date.now() - startTime
|
|
36972
|
+
});
|
|
36973
|
+
} catch (error) {
|
|
36974
|
+
trackError("PREVIEW_FAILED", "sms:init", { step: "preview" });
|
|
36975
|
+
throw error;
|
|
36976
|
+
}
|
|
36977
|
+
return;
|
|
36978
|
+
}
|
|
36480
36979
|
let outputs;
|
|
36481
36980
|
try {
|
|
36482
36981
|
outputs = await progress.execute(
|
|
36483
36982
|
"Deploying SMS infrastructure (this may take 2-3 minutes)",
|
|
36484
36983
|
async () => {
|
|
36485
|
-
|
|
36486
|
-
const stack = await pulumi29.automation.LocalWorkspace.createOrSelectStack(
|
|
36487
|
-
{
|
|
36488
|
-
stackName: `wraps-sms-${identity.accountId}-${region}`,
|
|
36489
|
-
projectName: "wraps-sms",
|
|
36490
|
-
program: async () => {
|
|
36491
|
-
const result = await deploySMSStack(stackConfig);
|
|
36492
|
-
return {
|
|
36493
|
-
roleArn: result.roleArn,
|
|
36494
|
-
phoneNumber: result.phoneNumber,
|
|
36495
|
-
phoneNumberArn: result.phoneNumberArn,
|
|
36496
|
-
configSetName: result.configSetName,
|
|
36497
|
-
tableName: result.tableName,
|
|
36498
|
-
region: result.region,
|
|
36499
|
-
lambdaFunctions: result.lambdaFunctions,
|
|
36500
|
-
snsTopicArn: result.snsTopicArn,
|
|
36501
|
-
queueUrl: result.queueUrl,
|
|
36502
|
-
dlqUrl: result.dlqUrl,
|
|
36503
|
-
optOutListArn: result.optOutListArn
|
|
36504
|
-
};
|
|
36505
|
-
}
|
|
36506
|
-
},
|
|
36507
|
-
{
|
|
36508
|
-
workDir: getPulumiWorkDir(),
|
|
36509
|
-
envVars: {
|
|
36510
|
-
PULUMI_CONFIG_PASSPHRASE: "",
|
|
36511
|
-
AWS_REGION: region
|
|
36512
|
-
},
|
|
36513
|
-
secretsProvider: "passphrase"
|
|
36514
|
-
}
|
|
36515
|
-
);
|
|
36516
|
-
await stack.setConfig("aws:region", { value: region });
|
|
36984
|
+
const stack = await createStack();
|
|
36517
36985
|
const upResult = await withLockRetry(
|
|
36518
36986
|
() => stack.up({ onOutput: console.log }),
|
|
36519
36987
|
{ accountId: identity.accountId, region, autoConfirm: options.yes }
|
|
@@ -38180,7 +38648,7 @@ ${pc53.bold("Cost Impact:")}`);
|
|
|
38180
38648
|
);
|
|
38181
38649
|
}
|
|
38182
38650
|
console.log("");
|
|
38183
|
-
if (!options.yes) {
|
|
38651
|
+
if (!(options.yes || options.preview)) {
|
|
38184
38652
|
const confirmed = await clack50.confirm({
|
|
38185
38653
|
message: "Proceed with upgrade?",
|
|
38186
38654
|
initialValue: true
|
|
@@ -38202,46 +38670,79 @@ ${pc53.bold("Cost Impact:")}`);
|
|
|
38202
38670
|
vercel: vercelConfig,
|
|
38203
38671
|
smsConfig: updatedConfig
|
|
38204
38672
|
};
|
|
38673
|
+
const stackName = metadata.services.sms?.pulumiStackName || `wraps-sms-${identity.accountId}-${region}`;
|
|
38674
|
+
const createStack = async () => {
|
|
38675
|
+
await ensurePulumiWorkDir({ accountId: identity.accountId, region });
|
|
38676
|
+
const stack = await pulumi32.automation.LocalWorkspace.createOrSelectStack(
|
|
38677
|
+
{
|
|
38678
|
+
stackName,
|
|
38679
|
+
projectName: "wraps-sms",
|
|
38680
|
+
program: async () => {
|
|
38681
|
+
const result = await deploySMSStack(stackConfig);
|
|
38682
|
+
return {
|
|
38683
|
+
roleArn: result.roleArn,
|
|
38684
|
+
phoneNumber: result.phoneNumber,
|
|
38685
|
+
phoneNumberArn: result.phoneNumberArn,
|
|
38686
|
+
configSetName: result.configSetName,
|
|
38687
|
+
tableName: result.tableName,
|
|
38688
|
+
region: result.region,
|
|
38689
|
+
lambdaFunctions: result.lambdaFunctions,
|
|
38690
|
+
snsTopicArn: result.snsTopicArn,
|
|
38691
|
+
queueUrl: result.queueUrl,
|
|
38692
|
+
dlqUrl: result.dlqUrl,
|
|
38693
|
+
optOutListArn: result.optOutListArn
|
|
38694
|
+
};
|
|
38695
|
+
}
|
|
38696
|
+
},
|
|
38697
|
+
{
|
|
38698
|
+
workDir: getPulumiWorkDir(),
|
|
38699
|
+
envVars: {
|
|
38700
|
+
PULUMI_CONFIG_PASSPHRASE: "",
|
|
38701
|
+
AWS_REGION: region
|
|
38702
|
+
},
|
|
38703
|
+
secretsProvider: "passphrase"
|
|
38704
|
+
}
|
|
38705
|
+
);
|
|
38706
|
+
await stack.workspace.selectStack(stackName);
|
|
38707
|
+
await stack.setConfig("aws:region", { value: region });
|
|
38708
|
+
return stack;
|
|
38709
|
+
};
|
|
38710
|
+
if (options.preview) {
|
|
38711
|
+
try {
|
|
38712
|
+
const previewResult = await progress.execute(
|
|
38713
|
+
"Generating infrastructure preview",
|
|
38714
|
+
async () => {
|
|
38715
|
+
const stack = await createStack();
|
|
38716
|
+
await stack.refresh({ onOutput: () => {
|
|
38717
|
+
} });
|
|
38718
|
+
return previewWithResourceChanges(stack, { diff: true });
|
|
38719
|
+
}
|
|
38720
|
+
);
|
|
38721
|
+
displayPreview({
|
|
38722
|
+
changeSummary: previewResult.changeSummary,
|
|
38723
|
+
resourceChanges: previewResult.resourceChanges,
|
|
38724
|
+
commandName: "wraps sms upgrade"
|
|
38725
|
+
});
|
|
38726
|
+
clack50.outro(
|
|
38727
|
+
pc53.green("Preview complete. Run without --preview to upgrade.")
|
|
38728
|
+
);
|
|
38729
|
+
trackServiceUpgrade("sms", {
|
|
38730
|
+
region,
|
|
38731
|
+
preview: true,
|
|
38732
|
+
duration_ms: Date.now() - startTime
|
|
38733
|
+
});
|
|
38734
|
+
} catch (error) {
|
|
38735
|
+
trackError("PREVIEW_FAILED", "sms:upgrade", { step: "preview" });
|
|
38736
|
+
throw error;
|
|
38737
|
+
}
|
|
38738
|
+
return;
|
|
38739
|
+
}
|
|
38205
38740
|
let outputs;
|
|
38206
38741
|
try {
|
|
38207
38742
|
outputs = await progress.execute(
|
|
38208
38743
|
"Updating SMS infrastructure (this may take 2-3 minutes)",
|
|
38209
38744
|
async () => {
|
|
38210
|
-
|
|
38211
|
-
const stack = await pulumi32.automation.LocalWorkspace.createOrSelectStack(
|
|
38212
|
-
{
|
|
38213
|
-
stackName: metadata.services.sms?.pulumiStackName || `wraps-sms-${identity.accountId}-${region}`,
|
|
38214
|
-
projectName: "wraps-sms",
|
|
38215
|
-
program: async () => {
|
|
38216
|
-
const result = await deploySMSStack(stackConfig);
|
|
38217
|
-
return {
|
|
38218
|
-
roleArn: result.roleArn,
|
|
38219
|
-
phoneNumber: result.phoneNumber,
|
|
38220
|
-
phoneNumberArn: result.phoneNumberArn,
|
|
38221
|
-
configSetName: result.configSetName,
|
|
38222
|
-
tableName: result.tableName,
|
|
38223
|
-
region: result.region,
|
|
38224
|
-
lambdaFunctions: result.lambdaFunctions,
|
|
38225
|
-
snsTopicArn: result.snsTopicArn,
|
|
38226
|
-
queueUrl: result.queueUrl,
|
|
38227
|
-
dlqUrl: result.dlqUrl,
|
|
38228
|
-
optOutListArn: result.optOutListArn
|
|
38229
|
-
};
|
|
38230
|
-
}
|
|
38231
|
-
},
|
|
38232
|
-
{
|
|
38233
|
-
workDir: getPulumiWorkDir(),
|
|
38234
|
-
envVars: {
|
|
38235
|
-
PULUMI_CONFIG_PASSPHRASE: "",
|
|
38236
|
-
AWS_REGION: region
|
|
38237
|
-
},
|
|
38238
|
-
secretsProvider: "passphrase"
|
|
38239
|
-
}
|
|
38240
|
-
);
|
|
38241
|
-
await stack.workspace.selectStack(
|
|
38242
|
-
metadata.services.sms?.pulumiStackName || `wraps-sms-${identity.accountId}-${region}`
|
|
38243
|
-
);
|
|
38244
|
-
await stack.setConfig("aws:region", { value: region });
|
|
38745
|
+
const stack = await createStack();
|
|
38245
38746
|
await stack.refresh({ onOutput: () => {
|
|
38246
38747
|
} });
|
|
38247
38748
|
const upResult = await stack.up({ onOutput: () => {
|
|
@@ -39567,7 +40068,8 @@ if (!primaryCommand) {
|
|
|
39567
40068
|
provider: flags.provider,
|
|
39568
40069
|
region: flags.region,
|
|
39569
40070
|
preset: flags.preset,
|
|
39570
|
-
yes: flags.yes
|
|
40071
|
+
yes: flags.yes,
|
|
40072
|
+
preview: flags.preview
|
|
39571
40073
|
});
|
|
39572
40074
|
break;
|
|
39573
40075
|
case "cdn-init":
|
|
@@ -39752,6 +40254,7 @@ Usage: ${pc59.cyan("wraps email verify --domain yourapp.com")}
|
|
|
39752
40254
|
await inboundDestroy({
|
|
39753
40255
|
region: flags.region,
|
|
39754
40256
|
force: flags.force,
|
|
40257
|
+
preview: flags.preview,
|
|
39755
40258
|
json: flags.json
|
|
39756
40259
|
});
|
|
39757
40260
|
break;
|
|
@@ -39816,6 +40319,7 @@ Available commands: ${pc59.cyan("init")}, ${pc59.cyan("destroy")}, ${pc59.cyan("
|
|
|
39816
40319
|
domain: flags.domain,
|
|
39817
40320
|
all: flags.all,
|
|
39818
40321
|
yes: flags.yes,
|
|
40322
|
+
preview: flags.preview,
|
|
39819
40323
|
json: flags.json
|
|
39820
40324
|
});
|
|
39821
40325
|
break;
|
|
@@ -39839,6 +40343,7 @@ Available commands: ${pc59.cyan("init")}, ${pc59.cyan("destroy")}, ${pc59.cyan("
|
|
|
39839
40343
|
domain: flags.domain,
|
|
39840
40344
|
all: flags.all,
|
|
39841
40345
|
force: flags.force,
|
|
40346
|
+
preview: flags.preview,
|
|
39842
40347
|
json: flags.json
|
|
39843
40348
|
});
|
|
39844
40349
|
break;
|
|
@@ -40065,6 +40570,7 @@ Run ${pc59.cyan("wraps --help")} for available commands.
|
|
|
40065
40570
|
region: flags.region,
|
|
40066
40571
|
preset: flags.preset,
|
|
40067
40572
|
yes: flags.yes,
|
|
40573
|
+
preview: flags.preview,
|
|
40068
40574
|
json: flags.json
|
|
40069
40575
|
});
|
|
40070
40576
|
break;
|
|
@@ -40087,6 +40593,7 @@ Run ${pc59.cyan("wraps --help")} for available commands.
|
|
|
40087
40593
|
await smsUpgrade({
|
|
40088
40594
|
region: flags.region,
|
|
40089
40595
|
yes: flags.yes,
|
|
40596
|
+
preview: flags.preview,
|
|
40090
40597
|
json: flags.json
|
|
40091
40598
|
});
|
|
40092
40599
|
break;
|