@wraps.dev/cli 1.1.3 → 1.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +436 -194
- package/dist/cli.js.map +1 -1
- package/dist/lambda/event-processor/.bundled +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -77,6 +77,7 @@ async function createDNSRecords(hostedZoneId, domain, dkimTokens, region, custom
|
|
|
77
77
|
ResourceRecords: [{ Value: '"v=spf1 include:amazonses.com ~all"' }]
|
|
78
78
|
}
|
|
79
79
|
});
|
|
80
|
+
const dmarcReportEmail = mailFromDomain ? `postmaster@${mailFromDomain}` : `postmaster@${domain}`;
|
|
80
81
|
changes.push({
|
|
81
82
|
Action: "UPSERT",
|
|
82
83
|
ResourceRecordSet: {
|
|
@@ -84,7 +85,7 @@ async function createDNSRecords(hostedZoneId, domain, dkimTokens, region, custom
|
|
|
84
85
|
Type: "TXT",
|
|
85
86
|
TTL: 1800,
|
|
86
87
|
ResourceRecords: [
|
|
87
|
-
{ Value: `"v=DMARC1; p=quarantine; rua=mailto
|
|
88
|
+
{ Value: `"v=DMARC1; p=quarantine; rua=mailto:${dmarcReportEmail}"` }
|
|
88
89
|
]
|
|
89
90
|
}
|
|
90
91
|
});
|
|
@@ -755,6 +756,312 @@ var init_aws = __esm({
|
|
|
755
756
|
}
|
|
756
757
|
});
|
|
757
758
|
|
|
759
|
+
// src/utils/shared/fs.ts
|
|
760
|
+
import { existsSync as existsSync2 } from "fs";
|
|
761
|
+
import { mkdir } from "fs/promises";
|
|
762
|
+
import { homedir } from "os";
|
|
763
|
+
import { join as join2 } from "path";
|
|
764
|
+
function getWrapsDir() {
|
|
765
|
+
return join2(homedir(), ".wraps");
|
|
766
|
+
}
|
|
767
|
+
function getPulumiWorkDir() {
|
|
768
|
+
return join2(getWrapsDir(), "pulumi");
|
|
769
|
+
}
|
|
770
|
+
async function ensureWrapsDir() {
|
|
771
|
+
const wrapsDir = getWrapsDir();
|
|
772
|
+
if (!existsSync2(wrapsDir)) {
|
|
773
|
+
await mkdir(wrapsDir, { recursive: true });
|
|
774
|
+
}
|
|
775
|
+
}
|
|
776
|
+
async function ensurePulumiWorkDir() {
|
|
777
|
+
await ensureWrapsDir();
|
|
778
|
+
const pulumiDir = getPulumiWorkDir();
|
|
779
|
+
if (!existsSync2(pulumiDir)) {
|
|
780
|
+
await mkdir(pulumiDir, { recursive: true });
|
|
781
|
+
}
|
|
782
|
+
process.env.PULUMI_BACKEND_URL = `file://${pulumiDir}`;
|
|
783
|
+
process.env.PULUMI_CONFIG_PASSPHRASE = "";
|
|
784
|
+
}
|
|
785
|
+
var init_fs = __esm({
|
|
786
|
+
"src/utils/shared/fs.ts"() {
|
|
787
|
+
"use strict";
|
|
788
|
+
init_esm_shims();
|
|
789
|
+
}
|
|
790
|
+
});
|
|
791
|
+
|
|
792
|
+
// src/utils/shared/metadata.ts
|
|
793
|
+
var metadata_exports = {};
|
|
794
|
+
__export(metadata_exports, {
|
|
795
|
+
addServiceToConnection: () => addServiceToConnection,
|
|
796
|
+
applyConfigUpdates: () => applyConfigUpdates,
|
|
797
|
+
connectionExists: () => connectionExists,
|
|
798
|
+
createConnectionMetadata: () => createConnectionMetadata,
|
|
799
|
+
deleteConnectionMetadata: () => deleteConnectionMetadata,
|
|
800
|
+
getConfiguredServices: () => getConfiguredServices,
|
|
801
|
+
hasService: () => hasService,
|
|
802
|
+
listConnections: () => listConnections,
|
|
803
|
+
loadConnectionMetadata: () => loadConnectionMetadata,
|
|
804
|
+
removeServiceFromConnection: () => removeServiceFromConnection,
|
|
805
|
+
saveConnectionMetadata: () => saveConnectionMetadata,
|
|
806
|
+
updateEmailConfig: () => updateEmailConfig,
|
|
807
|
+
updateServiceConfig: () => updateServiceConfig
|
|
808
|
+
});
|
|
809
|
+
import { existsSync as existsSync3 } from "fs";
|
|
810
|
+
import { readFile, writeFile } from "fs/promises";
|
|
811
|
+
import { join as join3 } from "path";
|
|
812
|
+
function getConnectionsDir() {
|
|
813
|
+
return join3(getWrapsDir(), "connections");
|
|
814
|
+
}
|
|
815
|
+
function getMetadataPath(accountId, region) {
|
|
816
|
+
return join3(getConnectionsDir(), `${accountId}-${region}.json`);
|
|
817
|
+
}
|
|
818
|
+
async function ensureConnectionsDir() {
|
|
819
|
+
await ensureWrapsDir();
|
|
820
|
+
const connectionsDir = getConnectionsDir();
|
|
821
|
+
if (!existsSync3(connectionsDir)) {
|
|
822
|
+
const { mkdir: mkdir2 } = await import("fs/promises");
|
|
823
|
+
await mkdir2(connectionsDir, { recursive: true });
|
|
824
|
+
}
|
|
825
|
+
}
|
|
826
|
+
function migrateLegacyMetadata(legacy) {
|
|
827
|
+
return {
|
|
828
|
+
version: "1.0.0",
|
|
829
|
+
accountId: legacy.accountId,
|
|
830
|
+
region: legacy.region,
|
|
831
|
+
provider: legacy.provider,
|
|
832
|
+
timestamp: legacy.timestamp,
|
|
833
|
+
vercel: legacy.vercel,
|
|
834
|
+
services: {
|
|
835
|
+
email: {
|
|
836
|
+
preset: legacy.preset,
|
|
837
|
+
config: legacy.emailConfig,
|
|
838
|
+
pulumiStackName: legacy.pulumiStackName,
|
|
839
|
+
deployedAt: legacy.timestamp
|
|
840
|
+
}
|
|
841
|
+
}
|
|
842
|
+
};
|
|
843
|
+
}
|
|
844
|
+
function isLegacyMetadata(data) {
|
|
845
|
+
return "emailConfig" in data && !("services" in data) && typeof data.emailConfig === "object";
|
|
846
|
+
}
|
|
847
|
+
async function loadConnectionMetadata(accountId, region) {
|
|
848
|
+
const metadataPath = getMetadataPath(accountId, region);
|
|
849
|
+
if (!existsSync3(metadataPath)) {
|
|
850
|
+
return null;
|
|
851
|
+
}
|
|
852
|
+
try {
|
|
853
|
+
const content = await readFile(metadataPath, "utf-8");
|
|
854
|
+
const data = JSON.parse(content);
|
|
855
|
+
if (isLegacyMetadata(data)) {
|
|
856
|
+
const migrated = migrateLegacyMetadata(data);
|
|
857
|
+
await saveConnectionMetadata(migrated);
|
|
858
|
+
return migrated;
|
|
859
|
+
}
|
|
860
|
+
if (!data.version) {
|
|
861
|
+
data.version = "1.0.0";
|
|
862
|
+
await saveConnectionMetadata(data);
|
|
863
|
+
}
|
|
864
|
+
return data;
|
|
865
|
+
} catch (error) {
|
|
866
|
+
console.error("Error loading connection metadata:", error.message);
|
|
867
|
+
return null;
|
|
868
|
+
}
|
|
869
|
+
}
|
|
870
|
+
async function saveConnectionMetadata(metadata) {
|
|
871
|
+
await ensureConnectionsDir();
|
|
872
|
+
const metadataPath = getMetadataPath(metadata.accountId, metadata.region);
|
|
873
|
+
try {
|
|
874
|
+
const content = JSON.stringify(metadata, null, 2);
|
|
875
|
+
await writeFile(metadataPath, content, "utf-8");
|
|
876
|
+
} catch (error) {
|
|
877
|
+
console.error("Error saving connection metadata:", error.message);
|
|
878
|
+
throw error;
|
|
879
|
+
}
|
|
880
|
+
}
|
|
881
|
+
async function deleteConnectionMetadata(accountId, region) {
|
|
882
|
+
const metadataPath = getMetadataPath(accountId, region);
|
|
883
|
+
if (existsSync3(metadataPath)) {
|
|
884
|
+
const { unlink } = await import("fs/promises");
|
|
885
|
+
await unlink(metadataPath);
|
|
886
|
+
}
|
|
887
|
+
}
|
|
888
|
+
async function listConnections() {
|
|
889
|
+
const connectionsDir = getConnectionsDir();
|
|
890
|
+
if (!existsSync3(connectionsDir)) {
|
|
891
|
+
return [];
|
|
892
|
+
}
|
|
893
|
+
try {
|
|
894
|
+
const { readdir } = await import("fs/promises");
|
|
895
|
+
const files = await readdir(connectionsDir);
|
|
896
|
+
const connections = [];
|
|
897
|
+
for (const file of files) {
|
|
898
|
+
if (file.endsWith(".json")) {
|
|
899
|
+
const content = await readFile(join3(connectionsDir, file), "utf-8");
|
|
900
|
+
try {
|
|
901
|
+
const metadata = JSON.parse(content);
|
|
902
|
+
connections.push(metadata);
|
|
903
|
+
} catch (error) {
|
|
904
|
+
console.error(`Error parsing ${file}:`, error);
|
|
905
|
+
}
|
|
906
|
+
}
|
|
907
|
+
}
|
|
908
|
+
return connections;
|
|
909
|
+
} catch (error) {
|
|
910
|
+
console.error("Error listing connections:", error.message);
|
|
911
|
+
return [];
|
|
912
|
+
}
|
|
913
|
+
}
|
|
914
|
+
async function connectionExists(accountId, region) {
|
|
915
|
+
const metadataPath = getMetadataPath(accountId, region);
|
|
916
|
+
return existsSync3(metadataPath);
|
|
917
|
+
}
|
|
918
|
+
function createConnectionMetadata(accountId, region, provider, emailConfig, preset) {
|
|
919
|
+
return {
|
|
920
|
+
version: "1.0.0",
|
|
921
|
+
accountId,
|
|
922
|
+
region,
|
|
923
|
+
provider,
|
|
924
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
925
|
+
services: {
|
|
926
|
+
email: {
|
|
927
|
+
preset,
|
|
928
|
+
config: emailConfig,
|
|
929
|
+
deployedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
930
|
+
}
|
|
931
|
+
}
|
|
932
|
+
};
|
|
933
|
+
}
|
|
934
|
+
function applyConfigUpdates(existingConfig, updates) {
|
|
935
|
+
const result = { ...existingConfig };
|
|
936
|
+
for (const [key, value] of Object.entries(updates)) {
|
|
937
|
+
if (value === void 0) continue;
|
|
938
|
+
if (key === "tracking" && typeof value === "object") {
|
|
939
|
+
const trackingUpdate = value;
|
|
940
|
+
result.tracking = {
|
|
941
|
+
...result.tracking,
|
|
942
|
+
...trackingUpdate,
|
|
943
|
+
// Always preserve these if they exist in original
|
|
944
|
+
customRedirectDomain: result.tracking?.customRedirectDomain || trackingUpdate.customRedirectDomain,
|
|
945
|
+
httpsEnabled: result.tracking?.httpsEnabled ?? trackingUpdate.httpsEnabled
|
|
946
|
+
};
|
|
947
|
+
} else if (key === "eventTracking" && typeof value === "object") {
|
|
948
|
+
result.eventTracking = {
|
|
949
|
+
...result.eventTracking,
|
|
950
|
+
...value
|
|
951
|
+
};
|
|
952
|
+
} else if (key === "suppressionList" && typeof value === "object") {
|
|
953
|
+
result.suppressionList = {
|
|
954
|
+
...result.suppressionList,
|
|
955
|
+
...value
|
|
956
|
+
};
|
|
957
|
+
} else if (key === "emailArchiving" && typeof value === "object") {
|
|
958
|
+
result.emailArchiving = {
|
|
959
|
+
...result.emailArchiving,
|
|
960
|
+
...value
|
|
961
|
+
};
|
|
962
|
+
} else {
|
|
963
|
+
result[key] = value;
|
|
964
|
+
}
|
|
965
|
+
}
|
|
966
|
+
return result;
|
|
967
|
+
}
|
|
968
|
+
function updateEmailConfig(metadata, emailConfig) {
|
|
969
|
+
if (!metadata.services.email) {
|
|
970
|
+
throw new Error("Email service not configured in metadata");
|
|
971
|
+
}
|
|
972
|
+
metadata.services.email.config = applyConfigUpdates(
|
|
973
|
+
metadata.services.email.config,
|
|
974
|
+
emailConfig
|
|
975
|
+
);
|
|
976
|
+
metadata.timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
977
|
+
}
|
|
978
|
+
function addServiceToConnection(accountId, region, provider, service, config2, preset, existingMetadata) {
|
|
979
|
+
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
980
|
+
if (existingMetadata) {
|
|
981
|
+
if (service === "email") {
|
|
982
|
+
existingMetadata.services.email = {
|
|
983
|
+
preset,
|
|
984
|
+
config: config2,
|
|
985
|
+
deployedAt: timestamp
|
|
986
|
+
};
|
|
987
|
+
} else if (service === "sms") {
|
|
988
|
+
existingMetadata.services.sms = {
|
|
989
|
+
preset,
|
|
990
|
+
config: config2,
|
|
991
|
+
deployedAt: timestamp
|
|
992
|
+
};
|
|
993
|
+
}
|
|
994
|
+
existingMetadata.timestamp = timestamp;
|
|
995
|
+
return existingMetadata;
|
|
996
|
+
}
|
|
997
|
+
const metadata = {
|
|
998
|
+
version: "1.0.0",
|
|
999
|
+
accountId,
|
|
1000
|
+
region,
|
|
1001
|
+
provider,
|
|
1002
|
+
timestamp,
|
|
1003
|
+
services: {}
|
|
1004
|
+
};
|
|
1005
|
+
if (service === "email") {
|
|
1006
|
+
metadata.services.email = {
|
|
1007
|
+
preset,
|
|
1008
|
+
config: config2,
|
|
1009
|
+
deployedAt: timestamp
|
|
1010
|
+
};
|
|
1011
|
+
} else if (service === "sms") {
|
|
1012
|
+
metadata.services.sms = {
|
|
1013
|
+
preset,
|
|
1014
|
+
config: config2,
|
|
1015
|
+
deployedAt: timestamp
|
|
1016
|
+
};
|
|
1017
|
+
}
|
|
1018
|
+
return metadata;
|
|
1019
|
+
}
|
|
1020
|
+
function updateServiceConfig(metadata, service, config2) {
|
|
1021
|
+
if (service === "email" && metadata.services.email) {
|
|
1022
|
+
metadata.services.email.config = {
|
|
1023
|
+
...metadata.services.email.config,
|
|
1024
|
+
...config2
|
|
1025
|
+
};
|
|
1026
|
+
} else if (service === "sms" && metadata.services.sms) {
|
|
1027
|
+
metadata.services.sms.config = {
|
|
1028
|
+
...metadata.services.sms.config,
|
|
1029
|
+
...config2
|
|
1030
|
+
};
|
|
1031
|
+
} else {
|
|
1032
|
+
throw new Error(`${service} service not configured in metadata`);
|
|
1033
|
+
}
|
|
1034
|
+
metadata.timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
1035
|
+
}
|
|
1036
|
+
function removeServiceFromConnection(metadata, service) {
|
|
1037
|
+
if (service === "email") {
|
|
1038
|
+
const { email, ...rest } = metadata.services;
|
|
1039
|
+
metadata.services = rest;
|
|
1040
|
+
} else if (service === "sms") {
|
|
1041
|
+
const { sms, ...rest } = metadata.services;
|
|
1042
|
+
metadata.services = rest;
|
|
1043
|
+
}
|
|
1044
|
+
metadata.timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
1045
|
+
}
|
|
1046
|
+
function hasService(metadata, service) {
|
|
1047
|
+
if (service === "email") return metadata.services.email !== void 0;
|
|
1048
|
+
if (service === "sms") return metadata.services.sms !== void 0;
|
|
1049
|
+
return false;
|
|
1050
|
+
}
|
|
1051
|
+
function getConfiguredServices(metadata) {
|
|
1052
|
+
const services = [];
|
|
1053
|
+
if (metadata.services.email) services.push("email");
|
|
1054
|
+
if (metadata.services.sms) services.push("sms");
|
|
1055
|
+
return services;
|
|
1056
|
+
}
|
|
1057
|
+
var init_metadata = __esm({
|
|
1058
|
+
"src/utils/shared/metadata.ts"() {
|
|
1059
|
+
"use strict";
|
|
1060
|
+
init_esm_shims();
|
|
1061
|
+
init_fs();
|
|
1062
|
+
}
|
|
1063
|
+
});
|
|
1064
|
+
|
|
758
1065
|
// src/utils/email/costs.ts
|
|
759
1066
|
function estimateStorageSize(emailsPerMonth, retention, numEventTypes = 8) {
|
|
760
1067
|
const avgRecordSizeKB = 2;
|
|
@@ -1712,12 +2019,12 @@ async function promptEmailArchiving() {
|
|
|
1712
2019
|
retention
|
|
1713
2020
|
};
|
|
1714
2021
|
}
|
|
1715
|
-
async function promptCustomConfig() {
|
|
2022
|
+
async function promptCustomConfig(existingConfig) {
|
|
1716
2023
|
clack4.log.info("Custom configuration builder");
|
|
1717
2024
|
clack4.log.info("Configure each feature individually");
|
|
1718
2025
|
const trackingEnabled = await clack4.confirm({
|
|
1719
2026
|
message: "Enable open & click tracking?",
|
|
1720
|
-
initialValue: true
|
|
2027
|
+
initialValue: existingConfig?.tracking?.enabled ?? true
|
|
1721
2028
|
});
|
|
1722
2029
|
if (clack4.isCancel(trackingEnabled)) {
|
|
1723
2030
|
clack4.cancel("Operation cancelled.");
|
|
@@ -1725,7 +2032,7 @@ async function promptCustomConfig() {
|
|
|
1725
2032
|
}
|
|
1726
2033
|
const eventTrackingEnabled = await clack4.confirm({
|
|
1727
2034
|
message: "Enable real-time event tracking (EventBridge)?",
|
|
1728
|
-
initialValue: true
|
|
2035
|
+
initialValue: existingConfig?.eventTracking?.enabled ?? true
|
|
1729
2036
|
});
|
|
1730
2037
|
if (clack4.isCancel(eventTrackingEnabled)) {
|
|
1731
2038
|
clack4.cancel("Operation cancelled.");
|
|
@@ -1736,7 +2043,7 @@ async function promptCustomConfig() {
|
|
|
1736
2043
|
if (eventTrackingEnabled) {
|
|
1737
2044
|
dynamoDBHistory = await clack4.confirm({
|
|
1738
2045
|
message: "Store email history in DynamoDB?",
|
|
1739
|
-
initialValue: true
|
|
2046
|
+
initialValue: existingConfig?.eventTracking?.dynamoDBHistory ?? true
|
|
1740
2047
|
});
|
|
1741
2048
|
if (clack4.isCancel(dynamoDBHistory)) {
|
|
1742
2049
|
clack4.cancel("Operation cancelled.");
|
|
@@ -1759,7 +2066,8 @@ async function promptCustomConfig() {
|
|
|
1759
2066
|
label: "Indefinite",
|
|
1760
2067
|
hint: "Higher storage cost"
|
|
1761
2068
|
}
|
|
1762
|
-
]
|
|
2069
|
+
],
|
|
2070
|
+
initialValue: existingConfig?.eventTracking?.archiveRetention || "90days"
|
|
1763
2071
|
});
|
|
1764
2072
|
if (clack4.isCancel(archiveRetention)) {
|
|
1765
2073
|
clack4.cancel("Operation cancelled.");
|
|
@@ -1769,7 +2077,7 @@ async function promptCustomConfig() {
|
|
|
1769
2077
|
}
|
|
1770
2078
|
const tlsRequired = await clack4.confirm({
|
|
1771
2079
|
message: "Require TLS encryption for all emails?",
|
|
1772
|
-
initialValue: true
|
|
2080
|
+
initialValue: existingConfig?.tlsRequired ?? true
|
|
1773
2081
|
});
|
|
1774
2082
|
if (clack4.isCancel(tlsRequired)) {
|
|
1775
2083
|
clack4.cancel("Operation cancelled.");
|
|
@@ -1777,7 +2085,7 @@ async function promptCustomConfig() {
|
|
|
1777
2085
|
}
|
|
1778
2086
|
const reputationMetrics = await clack4.confirm({
|
|
1779
2087
|
message: "Enable reputation metrics dashboard?",
|
|
1780
|
-
initialValue: true
|
|
2088
|
+
initialValue: existingConfig?.reputationMetrics ?? true
|
|
1781
2089
|
});
|
|
1782
2090
|
if (clack4.isCancel(reputationMetrics)) {
|
|
1783
2091
|
clack4.cancel("Operation cancelled.");
|
|
@@ -1785,7 +2093,7 @@ async function promptCustomConfig() {
|
|
|
1785
2093
|
}
|
|
1786
2094
|
const dedicatedIp = await clack4.confirm({
|
|
1787
2095
|
message: "Request dedicated IP address? (requires 100k+ emails/day)",
|
|
1788
|
-
initialValue: false
|
|
2096
|
+
initialValue: existingConfig?.dedicatedIp ?? false
|
|
1789
2097
|
});
|
|
1790
2098
|
if (clack4.isCancel(dedicatedIp)) {
|
|
1791
2099
|
clack4.cancel("Operation cancelled.");
|
|
@@ -1793,7 +2101,7 @@ async function promptCustomConfig() {
|
|
|
1793
2101
|
}
|
|
1794
2102
|
const emailArchivingEnabled = await clack4.confirm({
|
|
1795
2103
|
message: "Enable email archiving? (Store full email content with HTML for viewing)",
|
|
1796
|
-
initialValue: false
|
|
2104
|
+
initialValue: existingConfig?.emailArchiving?.enabled ?? false
|
|
1797
2105
|
});
|
|
1798
2106
|
if (clack4.isCancel(emailArchivingEnabled)) {
|
|
1799
2107
|
clack4.cancel("Operation cancelled.");
|
|
@@ -1823,7 +2131,7 @@ async function promptCustomConfig() {
|
|
|
1823
2131
|
hint: "~$35-60/mo for 10k emails"
|
|
1824
2132
|
}
|
|
1825
2133
|
],
|
|
1826
|
-
initialValue: "90days"
|
|
2134
|
+
initialValue: existingConfig?.emailArchiving?.retention || "90days"
|
|
1827
2135
|
});
|
|
1828
2136
|
if (clack4.isCancel(emailArchiveRetention)) {
|
|
1829
2137
|
clack4.cancel("Operation cancelled.");
|
|
@@ -2225,7 +2533,9 @@ import * as aws from "@pulumi/aws";
|
|
|
2225
2533
|
async function tableExists(tableName) {
|
|
2226
2534
|
try {
|
|
2227
2535
|
const { DynamoDBClient: DynamoDBClient4, DescribeTableCommand: DescribeTableCommand2 } = await import("@aws-sdk/client-dynamodb");
|
|
2228
|
-
const dynamodb2 = new DynamoDBClient4({
|
|
2536
|
+
const dynamodb2 = new DynamoDBClient4({
|
|
2537
|
+
region: process.env.AWS_REGION || "us-east-1"
|
|
2538
|
+
});
|
|
2229
2539
|
await dynamodb2.send(new DescribeTableCommand2({ TableName: tableName }));
|
|
2230
2540
|
return true;
|
|
2231
2541
|
} catch (error) {
|
|
@@ -2362,7 +2672,9 @@ import * as pulumi2 from "@pulumi/pulumi";
|
|
|
2362
2672
|
async function roleExists(roleName) {
|
|
2363
2673
|
try {
|
|
2364
2674
|
const { IAMClient: IAMClient2, GetRoleCommand } = await import("@aws-sdk/client-iam");
|
|
2365
|
-
const iam4 = new IAMClient2({
|
|
2675
|
+
const iam4 = new IAMClient2({
|
|
2676
|
+
region: process.env.AWS_REGION || "us-east-1"
|
|
2677
|
+
});
|
|
2366
2678
|
await iam4.send(new GetRoleCommand({ RoleName: roleName }));
|
|
2367
2679
|
return true;
|
|
2368
2680
|
} catch (error) {
|
|
@@ -2545,7 +2857,9 @@ function getPackageRoot() {
|
|
|
2545
2857
|
async function lambdaFunctionExists(functionName) {
|
|
2546
2858
|
try {
|
|
2547
2859
|
const { LambdaClient: LambdaClient2, GetFunctionCommand } = await import("@aws-sdk/client-lambda");
|
|
2548
|
-
const lambda2 = new LambdaClient2({
|
|
2860
|
+
const lambda2 = new LambdaClient2({
|
|
2861
|
+
region: process.env.AWS_REGION || "us-east-1"
|
|
2862
|
+
});
|
|
2549
2863
|
await lambda2.send(new GetFunctionCommand({ FunctionName: functionName }));
|
|
2550
2864
|
return true;
|
|
2551
2865
|
} catch (error) {
|
|
@@ -2559,7 +2873,9 @@ async function lambdaFunctionExists(functionName) {
|
|
|
2559
2873
|
async function findEventSourceMapping(functionName, queueArn) {
|
|
2560
2874
|
try {
|
|
2561
2875
|
const { LambdaClient: LambdaClient2, ListEventSourceMappingsCommand } = await import("@aws-sdk/client-lambda");
|
|
2562
|
-
const lambda2 = new LambdaClient2({
|
|
2876
|
+
const lambda2 = new LambdaClient2({
|
|
2877
|
+
region: process.env.AWS_REGION || "us-east-1"
|
|
2878
|
+
});
|
|
2563
2879
|
const response = await lambda2.send(
|
|
2564
2880
|
new ListEventSourceMappingsCommand({
|
|
2565
2881
|
FunctionName: functionName,
|
|
@@ -2782,27 +3098,13 @@ async function emailIdentityExists(emailIdentity, region) {
|
|
|
2782
3098
|
return false;
|
|
2783
3099
|
}
|
|
2784
3100
|
}
|
|
2785
|
-
async function eventDestinationExists(configSetName, eventDestName, region) {
|
|
2786
|
-
try {
|
|
2787
|
-
const { SESv2Client: SESv2Client5, GetConfigurationSetEventDestinationsCommand } = await import("@aws-sdk/client-sesv2");
|
|
2788
|
-
const ses = new SESv2Client5({ region });
|
|
2789
|
-
const response = await ses.send(
|
|
2790
|
-
new GetConfigurationSetEventDestinationsCommand({
|
|
2791
|
-
ConfigurationSetName: configSetName
|
|
2792
|
-
})
|
|
2793
|
-
);
|
|
2794
|
-
return response.EventDestinations?.some((dest) => dest.Name === eventDestName) ?? false;
|
|
2795
|
-
} catch (error) {
|
|
2796
|
-
if (error.name === "NotFoundException") {
|
|
2797
|
-
return false;
|
|
2798
|
-
}
|
|
2799
|
-
console.error("Error checking for existing event destination:", error);
|
|
2800
|
-
return false;
|
|
2801
|
-
}
|
|
2802
|
-
}
|
|
2803
3101
|
async function createSESResources(config2) {
|
|
2804
3102
|
const configSetOptions = {
|
|
2805
3103
|
configurationSetName: "wraps-email-tracking",
|
|
3104
|
+
deliveryOptions: config2.tlsRequired ? {
|
|
3105
|
+
tlsPolicy: "REQUIRE"
|
|
3106
|
+
// Require TLS 1.2+ for all emails
|
|
3107
|
+
} : void 0,
|
|
2806
3108
|
tags: {
|
|
2807
3109
|
ManagedBy: "wraps-cli",
|
|
2808
3110
|
Description: "Wraps email tracking configuration set"
|
|
@@ -2826,13 +3128,8 @@ async function createSESResources(config2) {
|
|
|
2826
3128
|
const defaultEventBus = aws5.cloudwatch.getEventBusOutput({
|
|
2827
3129
|
name: "default"
|
|
2828
3130
|
});
|
|
2829
|
-
|
|
2830
|
-
|
|
2831
|
-
configSetName,
|
|
2832
|
-
eventDestName,
|
|
2833
|
-
config2.region
|
|
2834
|
-
);
|
|
2835
|
-
if (!eventDestExists) {
|
|
3131
|
+
if (config2.eventTrackingEnabled) {
|
|
3132
|
+
const eventDestName = "wraps-email-eventbridge";
|
|
2836
3133
|
new aws5.sesv2.ConfigurationSetEventDestination("wraps-email-all-events", {
|
|
2837
3134
|
configurationSetName: configSet.configurationSetName,
|
|
2838
3135
|
eventDestinationName: eventDestName,
|
|
@@ -2969,7 +3266,9 @@ import * as aws7 from "@pulumi/aws";
|
|
|
2969
3266
|
async function getExistingOIDCProviderArn(url) {
|
|
2970
3267
|
try {
|
|
2971
3268
|
const { IAMClient: IAMClient2, ListOpenIDConnectProvidersCommand } = await import("@aws-sdk/client-iam");
|
|
2972
|
-
const iam4 = new IAMClient2({
|
|
3269
|
+
const iam4 = new IAMClient2({
|
|
3270
|
+
region: process.env.AWS_REGION || "us-east-1"
|
|
3271
|
+
});
|
|
2973
3272
|
const response = await iam4.send(new ListOpenIDConnectProvidersCommand({}));
|
|
2974
3273
|
const expectedArnSuffix = url.replace("https://", "");
|
|
2975
3274
|
const provider = response.OpenIDConnectProviderList?.find(
|
|
@@ -3058,7 +3357,9 @@ async function deployEmailStack(config2) {
|
|
|
3058
3357
|
cloudFrontResources = await createCloudFrontTracking2({
|
|
3059
3358
|
customTrackingDomain: emailConfig.tracking.customRedirectDomain,
|
|
3060
3359
|
region: config2.region,
|
|
3061
|
-
certificateArn
|
|
3360
|
+
certificateArn,
|
|
3361
|
+
hostedZoneId: hostedZone?.id
|
|
3362
|
+
// Pass hosted zone ID for automatic DNS record creation
|
|
3062
3363
|
});
|
|
3063
3364
|
}
|
|
3064
3365
|
let sesResources;
|
|
@@ -3068,7 +3369,11 @@ async function deployEmailStack(config2) {
|
|
|
3068
3369
|
mailFromDomain: emailConfig.mailFromDomain,
|
|
3069
3370
|
region: config2.region,
|
|
3070
3371
|
trackingConfig: emailConfig.tracking,
|
|
3071
|
-
eventTypes: emailConfig.eventTracking?.events
|
|
3372
|
+
eventTypes: emailConfig.eventTracking?.events,
|
|
3373
|
+
eventTrackingEnabled: emailConfig.eventTracking?.enabled,
|
|
3374
|
+
// Pass flag to create EventBridge destination
|
|
3375
|
+
tlsRequired: emailConfig.tlsRequired
|
|
3376
|
+
// Require TLS encryption for all emails
|
|
3072
3377
|
});
|
|
3073
3378
|
}
|
|
3074
3379
|
let dynamoTables;
|
|
@@ -3133,142 +3438,8 @@ async function deployEmailStack(config2) {
|
|
|
3133
3438
|
|
|
3134
3439
|
// src/commands/email/config.ts
|
|
3135
3440
|
init_aws();
|
|
3136
|
-
|
|
3137
|
-
|
|
3138
|
-
init_esm_shims();
|
|
3139
|
-
import { existsSync as existsSync2 } from "fs";
|
|
3140
|
-
import { mkdir } from "fs/promises";
|
|
3141
|
-
import { homedir } from "os";
|
|
3142
|
-
import { join as join2 } from "path";
|
|
3143
|
-
function getWrapsDir() {
|
|
3144
|
-
return join2(homedir(), ".wraps");
|
|
3145
|
-
}
|
|
3146
|
-
function getPulumiWorkDir() {
|
|
3147
|
-
return join2(getWrapsDir(), "pulumi");
|
|
3148
|
-
}
|
|
3149
|
-
async function ensureWrapsDir() {
|
|
3150
|
-
const wrapsDir = getWrapsDir();
|
|
3151
|
-
if (!existsSync2(wrapsDir)) {
|
|
3152
|
-
await mkdir(wrapsDir, { recursive: true });
|
|
3153
|
-
}
|
|
3154
|
-
}
|
|
3155
|
-
async function ensurePulumiWorkDir() {
|
|
3156
|
-
await ensureWrapsDir();
|
|
3157
|
-
const pulumiDir = getPulumiWorkDir();
|
|
3158
|
-
if (!existsSync2(pulumiDir)) {
|
|
3159
|
-
await mkdir(pulumiDir, { recursive: true });
|
|
3160
|
-
}
|
|
3161
|
-
process.env.PULUMI_BACKEND_URL = `file://${pulumiDir}`;
|
|
3162
|
-
process.env.PULUMI_CONFIG_PASSPHRASE = "";
|
|
3163
|
-
}
|
|
3164
|
-
|
|
3165
|
-
// src/utils/shared/metadata.ts
|
|
3166
|
-
init_esm_shims();
|
|
3167
|
-
import { existsSync as existsSync3 } from "fs";
|
|
3168
|
-
import { readFile, writeFile } from "fs/promises";
|
|
3169
|
-
import { join as join3 } from "path";
|
|
3170
|
-
function getConnectionsDir() {
|
|
3171
|
-
return join3(getWrapsDir(), "connections");
|
|
3172
|
-
}
|
|
3173
|
-
function getMetadataPath(accountId, region) {
|
|
3174
|
-
return join3(getConnectionsDir(), `${accountId}-${region}.json`);
|
|
3175
|
-
}
|
|
3176
|
-
async function ensureConnectionsDir() {
|
|
3177
|
-
await ensureWrapsDir();
|
|
3178
|
-
const connectionsDir = getConnectionsDir();
|
|
3179
|
-
if (!existsSync3(connectionsDir)) {
|
|
3180
|
-
const { mkdir: mkdir2 } = await import("fs/promises");
|
|
3181
|
-
await mkdir2(connectionsDir, { recursive: true });
|
|
3182
|
-
}
|
|
3183
|
-
}
|
|
3184
|
-
function migrateLegacyMetadata(legacy) {
|
|
3185
|
-
return {
|
|
3186
|
-
version: "1.0.0",
|
|
3187
|
-
accountId: legacy.accountId,
|
|
3188
|
-
region: legacy.region,
|
|
3189
|
-
provider: legacy.provider,
|
|
3190
|
-
timestamp: legacy.timestamp,
|
|
3191
|
-
vercel: legacy.vercel,
|
|
3192
|
-
services: {
|
|
3193
|
-
email: {
|
|
3194
|
-
preset: legacy.preset,
|
|
3195
|
-
config: legacy.emailConfig,
|
|
3196
|
-
pulumiStackName: legacy.pulumiStackName,
|
|
3197
|
-
deployedAt: legacy.timestamp
|
|
3198
|
-
}
|
|
3199
|
-
}
|
|
3200
|
-
};
|
|
3201
|
-
}
|
|
3202
|
-
function isLegacyMetadata(data) {
|
|
3203
|
-
return "emailConfig" in data && !("services" in data) && typeof data.emailConfig === "object";
|
|
3204
|
-
}
|
|
3205
|
-
async function loadConnectionMetadata(accountId, region) {
|
|
3206
|
-
const metadataPath = getMetadataPath(accountId, region);
|
|
3207
|
-
if (!existsSync3(metadataPath)) {
|
|
3208
|
-
return null;
|
|
3209
|
-
}
|
|
3210
|
-
try {
|
|
3211
|
-
const content = await readFile(metadataPath, "utf-8");
|
|
3212
|
-
const data = JSON.parse(content);
|
|
3213
|
-
if (isLegacyMetadata(data)) {
|
|
3214
|
-
const migrated = migrateLegacyMetadata(data);
|
|
3215
|
-
await saveConnectionMetadata(migrated);
|
|
3216
|
-
return migrated;
|
|
3217
|
-
}
|
|
3218
|
-
if (!data.version) {
|
|
3219
|
-
data.version = "1.0.0";
|
|
3220
|
-
await saveConnectionMetadata(data);
|
|
3221
|
-
}
|
|
3222
|
-
return data;
|
|
3223
|
-
} catch (error) {
|
|
3224
|
-
console.error("Error loading connection metadata:", error.message);
|
|
3225
|
-
return null;
|
|
3226
|
-
}
|
|
3227
|
-
}
|
|
3228
|
-
async function saveConnectionMetadata(metadata) {
|
|
3229
|
-
await ensureConnectionsDir();
|
|
3230
|
-
const metadataPath = getMetadataPath(metadata.accountId, metadata.region);
|
|
3231
|
-
try {
|
|
3232
|
-
const content = JSON.stringify(metadata, null, 2);
|
|
3233
|
-
await writeFile(metadataPath, content, "utf-8");
|
|
3234
|
-
} catch (error) {
|
|
3235
|
-
console.error("Error saving connection metadata:", error.message);
|
|
3236
|
-
throw error;
|
|
3237
|
-
}
|
|
3238
|
-
}
|
|
3239
|
-
async function deleteConnectionMetadata(accountId, region) {
|
|
3240
|
-
const metadataPath = getMetadataPath(accountId, region);
|
|
3241
|
-
if (existsSync3(metadataPath)) {
|
|
3242
|
-
const { unlink } = await import("fs/promises");
|
|
3243
|
-
await unlink(metadataPath);
|
|
3244
|
-
}
|
|
3245
|
-
}
|
|
3246
|
-
function createConnectionMetadata(accountId, region, provider, emailConfig, preset) {
|
|
3247
|
-
return {
|
|
3248
|
-
version: "1.0.0",
|
|
3249
|
-
accountId,
|
|
3250
|
-
region,
|
|
3251
|
-
provider,
|
|
3252
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3253
|
-
services: {
|
|
3254
|
-
email: {
|
|
3255
|
-
preset,
|
|
3256
|
-
config: emailConfig,
|
|
3257
|
-
deployedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
3258
|
-
}
|
|
3259
|
-
}
|
|
3260
|
-
};
|
|
3261
|
-
}
|
|
3262
|
-
function updateEmailConfig(metadata, emailConfig) {
|
|
3263
|
-
if (!metadata.services.email) {
|
|
3264
|
-
throw new Error("Email service not configured in metadata");
|
|
3265
|
-
}
|
|
3266
|
-
metadata.services.email.config = {
|
|
3267
|
-
...metadata.services.email.config,
|
|
3268
|
-
...emailConfig
|
|
3269
|
-
};
|
|
3270
|
-
metadata.timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
3271
|
-
}
|
|
3441
|
+
init_fs();
|
|
3442
|
+
init_metadata();
|
|
3272
3443
|
|
|
3273
3444
|
// src/utils/shared/output.ts
|
|
3274
3445
|
init_esm_shims();
|
|
@@ -3771,7 +3942,8 @@ ${pc3.bold("Current Configuration:")}
|
|
|
3771
3942
|
{
|
|
3772
3943
|
workDir: getPulumiWorkDir(),
|
|
3773
3944
|
envVars: {
|
|
3774
|
-
PULUMI_CONFIG_PASSPHRASE: ""
|
|
3945
|
+
PULUMI_CONFIG_PASSPHRASE: "",
|
|
3946
|
+
AWS_REGION: region
|
|
3775
3947
|
},
|
|
3776
3948
|
secretsProvider: "passphrase"
|
|
3777
3949
|
}
|
|
@@ -3842,6 +4014,8 @@ import * as pulumi6 from "@pulumi/pulumi";
|
|
|
3842
4014
|
import pc5 from "picocolors";
|
|
3843
4015
|
init_presets();
|
|
3844
4016
|
init_aws();
|
|
4017
|
+
init_fs();
|
|
4018
|
+
init_metadata();
|
|
3845
4019
|
init_prompts();
|
|
3846
4020
|
|
|
3847
4021
|
// src/utils/shared/scanner.ts
|
|
@@ -4146,6 +4320,10 @@ async function connect(options) {
|
|
|
4146
4320
|
const emailConfig = preset === "custom" ? await Promise.resolve().then(() => (init_prompts(), prompts_exports)).then(
|
|
4147
4321
|
(m) => m.promptCustomConfig()
|
|
4148
4322
|
) : getPreset(preset);
|
|
4323
|
+
const domainIdentities = selectedIdentities.filter((id) => !id.includes("@"));
|
|
4324
|
+
if (domainIdentities.length > 0) {
|
|
4325
|
+
emailConfig.domain = domainIdentities[0];
|
|
4326
|
+
}
|
|
4149
4327
|
if (!options.yes) {
|
|
4150
4328
|
const confirmed = await confirmConnect();
|
|
4151
4329
|
if (!confirmed) {
|
|
@@ -4186,7 +4364,8 @@ async function connect(options) {
|
|
|
4186
4364
|
{
|
|
4187
4365
|
workDir: getPulumiWorkDir(),
|
|
4188
4366
|
envVars: {
|
|
4189
|
-
PULUMI_CONFIG_PASSPHRASE: ""
|
|
4367
|
+
PULUMI_CONFIG_PASSPHRASE: "",
|
|
4368
|
+
AWS_REGION: region
|
|
4190
4369
|
},
|
|
4191
4370
|
secretsProvider: "passphrase"
|
|
4192
4371
|
}
|
|
@@ -4220,6 +4399,32 @@ async function connect(options) {
|
|
|
4220
4399
|
}
|
|
4221
4400
|
throw new Error(`Pulumi deployment failed: ${error.message}`);
|
|
4222
4401
|
}
|
|
4402
|
+
if (outputs.domain && outputs.dkimTokens && outputs.dkimTokens.length > 0) {
|
|
4403
|
+
const { findHostedZone: findHostedZone2, createDNSRecords: createDNSRecords2 } = await Promise.resolve().then(() => (init_route53(), route53_exports));
|
|
4404
|
+
const hostedZone = await findHostedZone2(outputs.domain, region);
|
|
4405
|
+
if (hostedZone) {
|
|
4406
|
+
try {
|
|
4407
|
+
progress.start("Creating DNS records in Route53");
|
|
4408
|
+
const mailFromDomain = emailConfig.mailFromDomain || `mail.${outputs.domain}`;
|
|
4409
|
+
await createDNSRecords2(
|
|
4410
|
+
hostedZone.id,
|
|
4411
|
+
outputs.domain,
|
|
4412
|
+
outputs.dkimTokens,
|
|
4413
|
+
region,
|
|
4414
|
+
outputs.customTrackingDomain,
|
|
4415
|
+
mailFromDomain
|
|
4416
|
+
);
|
|
4417
|
+
progress.succeed("DNS records created in Route53");
|
|
4418
|
+
} catch (error) {
|
|
4419
|
+
progress.fail(
|
|
4420
|
+
`Failed to create DNS records automatically: ${error.message}`
|
|
4421
|
+
);
|
|
4422
|
+
progress.info(
|
|
4423
|
+
"You can manually add the required DNS records shown below"
|
|
4424
|
+
);
|
|
4425
|
+
}
|
|
4426
|
+
}
|
|
4427
|
+
}
|
|
4223
4428
|
const metadata = createConnectionMetadata(
|
|
4224
4429
|
identity.accountId,
|
|
4225
4430
|
region,
|
|
@@ -4688,6 +4893,8 @@ import pc7 from "picocolors";
|
|
|
4688
4893
|
init_costs();
|
|
4689
4894
|
init_presets();
|
|
4690
4895
|
init_aws();
|
|
4896
|
+
init_fs();
|
|
4897
|
+
init_metadata();
|
|
4691
4898
|
init_prompts();
|
|
4692
4899
|
async function init(options) {
|
|
4693
4900
|
clack7.intro(pc7.bold("Wraps Email Infrastructure Setup"));
|
|
@@ -4818,8 +5025,9 @@ ${pc7.yellow(pc7.bold("Configuration Warnings:"))}`);
|
|
|
4818
5025
|
workDir: getPulumiWorkDir(),
|
|
4819
5026
|
// Use local file-based backend (no Pulumi Cloud login required)
|
|
4820
5027
|
envVars: {
|
|
4821
|
-
PULUMI_CONFIG_PASSPHRASE: ""
|
|
5028
|
+
PULUMI_CONFIG_PASSPHRASE: "",
|
|
4822
5029
|
// Use empty passphrase for local state
|
|
5030
|
+
AWS_REGION: region
|
|
4823
5031
|
},
|
|
4824
5032
|
secretsProvider: "passphrase"
|
|
4825
5033
|
}
|
|
@@ -4910,6 +5118,8 @@ ${pc7.yellow(pc7.bold("Configuration Warnings:"))}`);
|
|
|
4910
5118
|
// src/commands/email/restore.ts
|
|
4911
5119
|
init_esm_shims();
|
|
4912
5120
|
init_aws();
|
|
5121
|
+
init_fs();
|
|
5122
|
+
init_metadata();
|
|
4913
5123
|
import * as clack8 from "@clack/prompts";
|
|
4914
5124
|
import * as pulumi8 from "@pulumi/pulumi";
|
|
4915
5125
|
import pc8 from "picocolors";
|
|
@@ -4988,7 +5198,8 @@ ${pc8.bold("The following Wraps resources will be removed:")}
|
|
|
4988
5198
|
{
|
|
4989
5199
|
workDir: getPulumiWorkDir(),
|
|
4990
5200
|
envVars: {
|
|
4991
|
-
PULUMI_CONFIG_PASSPHRASE: ""
|
|
5201
|
+
PULUMI_CONFIG_PASSPHRASE: "",
|
|
5202
|
+
AWS_REGION: region
|
|
4992
5203
|
},
|
|
4993
5204
|
secretsProvider: "passphrase"
|
|
4994
5205
|
}
|
|
@@ -5025,6 +5236,8 @@ import pc9 from "picocolors";
|
|
|
5025
5236
|
init_costs();
|
|
5026
5237
|
init_presets();
|
|
5027
5238
|
init_aws();
|
|
5239
|
+
init_fs();
|
|
5240
|
+
init_metadata();
|
|
5028
5241
|
init_prompts();
|
|
5029
5242
|
async function upgrade(options) {
|
|
5030
5243
|
clack9.intro(pc9.bold("Wraps Upgrade - Enhance Your Email Infrastructure"));
|
|
@@ -5192,12 +5405,9 @@ ${pc9.bold("Current Configuration:")}
|
|
|
5192
5405
|
clack9.cancel("Upgrade cancelled.");
|
|
5193
5406
|
process.exit(0);
|
|
5194
5407
|
}
|
|
5408
|
+
const { applyConfigUpdates: applyConfigUpdates2 } = await Promise.resolve().then(() => (init_metadata(), metadata_exports));
|
|
5195
5409
|
const presetConfig = getPreset(selectedPreset);
|
|
5196
|
-
updatedConfig =
|
|
5197
|
-
...presetConfig,
|
|
5198
|
-
domain: config2.domain
|
|
5199
|
-
// Preserve original domain
|
|
5200
|
-
};
|
|
5410
|
+
updatedConfig = applyConfigUpdates2(config2, presetConfig);
|
|
5201
5411
|
newPreset = selectedPreset;
|
|
5202
5412
|
break;
|
|
5203
5413
|
}
|
|
@@ -5630,11 +5840,9 @@ ${pc9.bold("Current Configuration:")}
|
|
|
5630
5840
|
}
|
|
5631
5841
|
case "custom": {
|
|
5632
5842
|
const { promptCustomConfig: promptCustomConfig2 } = await Promise.resolve().then(() => (init_prompts(), prompts_exports));
|
|
5633
|
-
const
|
|
5634
|
-
|
|
5635
|
-
|
|
5636
|
-
domain: config2.domain
|
|
5637
|
-
};
|
|
5843
|
+
const { applyConfigUpdates: applyConfigUpdates2 } = await Promise.resolve().then(() => (init_metadata(), metadata_exports));
|
|
5844
|
+
const customConfig = await promptCustomConfig2(config2);
|
|
5845
|
+
updatedConfig = applyConfigUpdates2(config2, customConfig);
|
|
5638
5846
|
newPreset = void 0;
|
|
5639
5847
|
break;
|
|
5640
5848
|
}
|
|
@@ -5712,7 +5920,8 @@ ${pc9.bold("Cost Impact:")}`);
|
|
|
5712
5920
|
{
|
|
5713
5921
|
workDir: getPulumiWorkDir(),
|
|
5714
5922
|
envVars: {
|
|
5715
|
-
PULUMI_CONFIG_PASSPHRASE: ""
|
|
5923
|
+
PULUMI_CONFIG_PASSPHRASE: "",
|
|
5924
|
+
AWS_REGION: region
|
|
5716
5925
|
},
|
|
5717
5926
|
secretsProvider: "passphrase"
|
|
5718
5927
|
}
|
|
@@ -5754,6 +5963,33 @@ ${pc9.bold("Cost Impact:")}`);
|
|
|
5754
5963
|
}
|
|
5755
5964
|
throw new Error(`Pulumi upgrade failed: ${error.message}`);
|
|
5756
5965
|
}
|
|
5966
|
+
if (outputs.domain && outputs.dkimTokens && outputs.dkimTokens.length > 0) {
|
|
5967
|
+
const { findHostedZone: findHostedZone2, createDNSRecords: createDNSRecords2 } = await Promise.resolve().then(() => (init_route53(), route53_exports));
|
|
5968
|
+
const hostedZone = await findHostedZone2(outputs.domain, region);
|
|
5969
|
+
if (hostedZone) {
|
|
5970
|
+
try {
|
|
5971
|
+
progress.start("Creating DNS records in Route53");
|
|
5972
|
+
const mailFromDomain = updatedConfig.mailFromDomain || `mail.${outputs.domain}`;
|
|
5973
|
+
await createDNSRecords2(
|
|
5974
|
+
hostedZone.id,
|
|
5975
|
+
outputs.domain,
|
|
5976
|
+
outputs.dkimTokens,
|
|
5977
|
+
region,
|
|
5978
|
+
outputs.customTrackingDomain,
|
|
5979
|
+
mailFromDomain,
|
|
5980
|
+
outputs.cloudFrontDomain
|
|
5981
|
+
);
|
|
5982
|
+
progress.succeed("DNS records created in Route53");
|
|
5983
|
+
} catch (error) {
|
|
5984
|
+
progress.fail(
|
|
5985
|
+
`Failed to create DNS records automatically: ${error.message}`
|
|
5986
|
+
);
|
|
5987
|
+
progress.info(
|
|
5988
|
+
"You can manually add the required DNS records shown below"
|
|
5989
|
+
);
|
|
5990
|
+
}
|
|
5991
|
+
}
|
|
5992
|
+
}
|
|
5757
5993
|
updateEmailConfig(metadata, updatedConfig);
|
|
5758
5994
|
if (metadata.services.email) {
|
|
5759
5995
|
metadata.services.email.preset = newPreset;
|
|
@@ -6573,6 +6809,7 @@ function createMetricsRouter(config2) {
|
|
|
6573
6809
|
|
|
6574
6810
|
// src/console/routes/settings.ts
|
|
6575
6811
|
init_esm_shims();
|
|
6812
|
+
init_metadata();
|
|
6576
6813
|
import dns from "dns/promises";
|
|
6577
6814
|
import { Router as createRouter4 } from "express";
|
|
6578
6815
|
|
|
@@ -6915,6 +7152,7 @@ function createSettingsRouter(config2) {
|
|
|
6915
7152
|
|
|
6916
7153
|
// src/console/routes/user.ts
|
|
6917
7154
|
init_esm_shims();
|
|
7155
|
+
init_metadata();
|
|
6918
7156
|
import { Router as createRouter5 } from "express";
|
|
6919
7157
|
function createUserRouter(config2) {
|
|
6920
7158
|
const router = createRouter5();
|
|
@@ -7060,6 +7298,7 @@ async function startConsoleServer(config2) {
|
|
|
7060
7298
|
|
|
7061
7299
|
// src/commands/shared/dashboard.ts
|
|
7062
7300
|
init_aws();
|
|
7301
|
+
init_fs();
|
|
7063
7302
|
async function dashboard(options) {
|
|
7064
7303
|
clack10.intro(pc10.bold("Wraps Dashboard"));
|
|
7065
7304
|
const progress = new DeploymentProgress();
|
|
@@ -7116,6 +7355,8 @@ async function dashboard(options) {
|
|
|
7116
7355
|
// src/commands/shared/destroy.ts
|
|
7117
7356
|
init_esm_shims();
|
|
7118
7357
|
init_aws();
|
|
7358
|
+
init_fs();
|
|
7359
|
+
init_metadata();
|
|
7119
7360
|
import * as clack11 from "@clack/prompts";
|
|
7120
7361
|
import * as pulumi11 from "@pulumi/pulumi";
|
|
7121
7362
|
import pc11 from "picocolors";
|
|
@@ -7182,6 +7423,7 @@ Run ${pc11.cyan("wraps email init")} to deploy infrastructure again.
|
|
|
7182
7423
|
// src/commands/shared/status.ts
|
|
7183
7424
|
init_esm_shims();
|
|
7184
7425
|
init_aws();
|
|
7426
|
+
init_fs();
|
|
7185
7427
|
import * as clack12 from "@clack/prompts";
|
|
7186
7428
|
import * as pulumi12 from "@pulumi/pulumi";
|
|
7187
7429
|
import pc12 from "picocolors";
|