@wraps.dev/cli 2.2.0 → 2.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +372 -371
- package/dist/cli.js.map +1 -1
- package/dist/console/assets/index-Ddo3dMAv.css +1 -0
- package/dist/console/assets/index-Dpfyi8cC.js +471 -0
- package/dist/console/index.html +2 -2
- package/dist/lambda/event-processor/.bundled +1 -1
- package/dist/lambda/sms-event-processor/.bundled +1 -1
- package/package.json +1 -1
- package/dist/console/assets/index-C2_7RIq3.js +0 -471
- package/dist/console/assets/index-DpvjnbMd.css +0 -1
package/dist/cli.js
CHANGED
|
@@ -147,7 +147,7 @@ var require_package = __commonJS({
|
|
|
147
147
|
"package.json"(exports, module) {
|
|
148
148
|
module.exports = {
|
|
149
149
|
name: "@wraps.dev/cli",
|
|
150
|
-
version: "2.2.
|
|
150
|
+
version: "2.2.2",
|
|
151
151
|
description: "CLI for deploying Wraps email infrastructure to your AWS account",
|
|
152
152
|
type: "module",
|
|
153
153
|
main: "./dist/cli.js",
|
|
@@ -2382,8 +2382,8 @@ function addServiceToConnection(accountId, region, provider, service, config2, p
|
|
|
2382
2382
|
config: config2,
|
|
2383
2383
|
deployedAt: timestamp
|
|
2384
2384
|
};
|
|
2385
|
-
} else if (service === "
|
|
2386
|
-
existingMetadata.services.
|
|
2385
|
+
} else if (service === "cdn") {
|
|
2386
|
+
existingMetadata.services.cdn = {
|
|
2387
2387
|
preset,
|
|
2388
2388
|
config: config2,
|
|
2389
2389
|
deployedAt: timestamp
|
|
@@ -2412,8 +2412,8 @@ function addServiceToConnection(accountId, region, provider, service, config2, p
|
|
|
2412
2412
|
config: config2,
|
|
2413
2413
|
deployedAt: timestamp
|
|
2414
2414
|
};
|
|
2415
|
-
} else if (service === "
|
|
2416
|
-
metadata.services.
|
|
2415
|
+
} else if (service === "cdn") {
|
|
2416
|
+
metadata.services.cdn = {
|
|
2417
2417
|
preset,
|
|
2418
2418
|
config: config2,
|
|
2419
2419
|
deployedAt: timestamp
|
|
@@ -2432,9 +2432,9 @@ function updateServiceConfig(metadata, service, config2) {
|
|
|
2432
2432
|
...metadata.services.sms.config,
|
|
2433
2433
|
...config2
|
|
2434
2434
|
};
|
|
2435
|
-
} else if (service === "
|
|
2436
|
-
metadata.services.
|
|
2437
|
-
...metadata.services.
|
|
2435
|
+
} else if (service === "cdn" && metadata.services.cdn) {
|
|
2436
|
+
metadata.services.cdn.config = {
|
|
2437
|
+
...metadata.services.cdn.config,
|
|
2438
2438
|
...config2
|
|
2439
2439
|
};
|
|
2440
2440
|
} else {
|
|
@@ -2449,8 +2449,8 @@ function removeServiceFromConnection(metadata, service) {
|
|
|
2449
2449
|
} else if (service === "sms") {
|
|
2450
2450
|
const { sms, ...rest } = metadata.services;
|
|
2451
2451
|
metadata.services = rest;
|
|
2452
|
-
} else if (service === "
|
|
2453
|
-
const {
|
|
2452
|
+
} else if (service === "cdn") {
|
|
2453
|
+
const { cdn, ...rest } = metadata.services;
|
|
2454
2454
|
metadata.services = rest;
|
|
2455
2455
|
}
|
|
2456
2456
|
metadata.timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -2462,8 +2462,8 @@ function hasService(metadata, service) {
|
|
|
2462
2462
|
if (service === "sms") {
|
|
2463
2463
|
return metadata.services.sms !== void 0;
|
|
2464
2464
|
}
|
|
2465
|
-
if (service === "
|
|
2466
|
-
return metadata.services.
|
|
2465
|
+
if (service === "cdn") {
|
|
2466
|
+
return metadata.services.cdn !== void 0;
|
|
2467
2467
|
}
|
|
2468
2468
|
return false;
|
|
2469
2469
|
}
|
|
@@ -2475,8 +2475,8 @@ function getConfiguredServices(metadata) {
|
|
|
2475
2475
|
if (metadata.services.sms) {
|
|
2476
2476
|
services.push("sms");
|
|
2477
2477
|
}
|
|
2478
|
-
if (metadata.services.
|
|
2479
|
-
services.push("
|
|
2478
|
+
if (metadata.services.cdn) {
|
|
2479
|
+
services.push("cdn");
|
|
2480
2480
|
}
|
|
2481
2481
|
return services;
|
|
2482
2482
|
}
|
|
@@ -13737,6 +13737,7 @@ async function fetchEmailById(messageId, options) {
|
|
|
13737
13737
|
destination: sendEvent.destination,
|
|
13738
13738
|
availableKeys: Object.keys(sendEvent)
|
|
13739
13739
|
});
|
|
13740
|
+
const subjectFromEvents = events.find((e) => e.subject)?.subject;
|
|
13740
13741
|
let htmlBody;
|
|
13741
13742
|
let textBody;
|
|
13742
13743
|
if (sendEvent.eventData) {
|
|
@@ -13840,7 +13841,7 @@ async function fetchEmailById(messageId, options) {
|
|
|
13840
13841
|
from: sendEvent.from || "unknown",
|
|
13841
13842
|
to: toAddresses,
|
|
13842
13843
|
replyTo: sendEvent.replyTo,
|
|
13843
|
-
subject: sendEvent.subject || "(no subject)",
|
|
13844
|
+
subject: sendEvent.subject || subjectFromEvents || "(no subject)",
|
|
13844
13845
|
htmlBody: htmlBody || sendEvent.htmlBody,
|
|
13845
13846
|
textBody: textBody || sendEvent.textBody,
|
|
13846
13847
|
status: status2,
|
|
@@ -15376,11 +15377,11 @@ function createSMSRouter(config2) {
|
|
|
15376
15377
|
return router;
|
|
15377
15378
|
}
|
|
15378
15379
|
|
|
15379
|
-
// src/console/routes/
|
|
15380
|
+
// src/console/routes/cdn.ts
|
|
15380
15381
|
init_esm_shims();
|
|
15381
15382
|
init_metadata();
|
|
15382
15383
|
import { Router as createRouter6 } from "express";
|
|
15383
|
-
function
|
|
15384
|
+
function createCdnRouter(config2) {
|
|
15384
15385
|
const router = createRouter6();
|
|
15385
15386
|
router.get("/settings", async (_req, res) => {
|
|
15386
15387
|
try {
|
|
@@ -15388,36 +15389,36 @@ function createStorageRouter(config2) {
|
|
|
15388
15389
|
config2.accountId || "",
|
|
15389
15390
|
config2.region
|
|
15390
15391
|
);
|
|
15391
|
-
if (!metadata?.services.
|
|
15392
|
+
if (!metadata?.services.cdn) {
|
|
15392
15393
|
return res.status(404).json({
|
|
15393
|
-
error: "No
|
|
15394
|
+
error: "No CDN infrastructure found for this account and region"
|
|
15394
15395
|
});
|
|
15395
15396
|
}
|
|
15396
|
-
const
|
|
15397
|
-
const
|
|
15397
|
+
const cdnService = metadata.services.cdn;
|
|
15398
|
+
const cdnConfig = cdnService.config;
|
|
15398
15399
|
const settings = {
|
|
15399
|
-
bucketName: config2.
|
|
15400
|
-
bucketArn: `arn:aws:s3:::${config2.
|
|
15400
|
+
bucketName: config2.cdnBucketName || `wraps-cdn-${config2.accountId}`,
|
|
15401
|
+
bucketArn: `arn:aws:s3:::${config2.cdnBucketName || `wraps-cdn-${config2.accountId}`}`,
|
|
15401
15402
|
region: config2.region,
|
|
15402
|
-
roleArn: config2.
|
|
15403
|
+
roleArn: config2.cdnRoleArn || config2.roleArn,
|
|
15403
15404
|
cdn: {
|
|
15404
|
-
enabled:
|
|
15405
|
-
distributionId: config2.
|
|
15406
|
-
distributionDomain: config2.
|
|
15407
|
-
customDomain:
|
|
15408
|
-
status: config2.
|
|
15405
|
+
enabled: cdnConfig.cdn?.enabled ?? false,
|
|
15406
|
+
distributionId: config2.cdnDistributionId,
|
|
15407
|
+
distributionDomain: config2.cdnDistributionDomain,
|
|
15408
|
+
customDomain: cdnConfig.cdn?.customDomain,
|
|
15409
|
+
status: config2.cdnDistributionId ? "Deployed" : void 0
|
|
15409
15410
|
},
|
|
15410
|
-
certificate:
|
|
15411
|
-
arn: config2.
|
|
15412
|
-
status: config2.
|
|
15411
|
+
certificate: cdnConfig.cdn?.customDomain ? {
|
|
15412
|
+
arn: config2.cdnCertificateArn,
|
|
15413
|
+
status: config2.cdnCertificateArn ? "ISSUED" : "PENDING_VALIDATION"
|
|
15413
15414
|
} : void 0,
|
|
15414
|
-
versioning:
|
|
15415
|
-
retention:
|
|
15415
|
+
versioning: cdnConfig.versioning ?? false,
|
|
15416
|
+
retention: cdnConfig.retention
|
|
15416
15417
|
};
|
|
15417
15418
|
res.json(settings);
|
|
15418
15419
|
} catch (error) {
|
|
15419
15420
|
const errorMessage = error instanceof Error ? error.message : "Unknown error";
|
|
15420
|
-
console.error("[
|
|
15421
|
+
console.error("[CDN] Error fetching settings:", error);
|
|
15421
15422
|
res.status(500).json({ error: errorMessage });
|
|
15422
15423
|
}
|
|
15423
15424
|
});
|
|
@@ -15427,16 +15428,16 @@ function createStorageRouter(config2) {
|
|
|
15427
15428
|
config2.accountId || "",
|
|
15428
15429
|
config2.region
|
|
15429
15430
|
);
|
|
15430
|
-
if (!metadata?.services.
|
|
15431
|
+
if (!metadata?.services.cdn) {
|
|
15431
15432
|
return res.status(404).json({
|
|
15432
|
-
error: "No
|
|
15433
|
+
error: "No CDN infrastructure found for this account and region"
|
|
15433
15434
|
});
|
|
15434
15435
|
}
|
|
15435
|
-
const bucketName = config2.
|
|
15436
|
+
const bucketName = config2.cdnBucketName || `wraps-cdn-${config2.accountId}`;
|
|
15436
15437
|
const { S3Client, ListObjectsV2Command, GetObjectTaggingCommand } = await import("@aws-sdk/client-s3");
|
|
15437
15438
|
const { assumeRole: assumeRole2 } = await Promise.resolve().then(() => (init_assume_role(), assume_role_exports));
|
|
15438
|
-
const credentials = config2.
|
|
15439
|
-
config2.
|
|
15439
|
+
const credentials = config2.cdnRoleArn || config2.roleArn ? await assumeRole2(
|
|
15440
|
+
config2.cdnRoleArn || config2.roleArn,
|
|
15440
15441
|
config2.region
|
|
15441
15442
|
) : void 0;
|
|
15442
15443
|
const s3Client = new S3Client({ region: config2.region, credentials });
|
|
@@ -15446,7 +15447,7 @@ function createStorageRouter(config2) {
|
|
|
15446
15447
|
MaxKeys: 100
|
|
15447
15448
|
})
|
|
15448
15449
|
);
|
|
15449
|
-
const cdnUrl = config2.
|
|
15450
|
+
const cdnUrl = config2.cdnDistributionDomain ? `https://${metadata.services.cdn.config.cdn?.customDomain || config2.cdnDistributionDomain}` : null;
|
|
15450
15451
|
const getContentType = (key) => {
|
|
15451
15452
|
const ext = key.split(".").pop()?.toLowerCase();
|
|
15452
15453
|
const mimeTypes = {
|
|
@@ -15509,15 +15510,15 @@ function createStorageRouter(config2) {
|
|
|
15509
15510
|
res.json({
|
|
15510
15511
|
bucketName,
|
|
15511
15512
|
region: config2.region,
|
|
15512
|
-
cdnDomain: config2.
|
|
15513
|
-
customDomain: metadata.services.
|
|
15513
|
+
cdnDomain: config2.cdnDistributionDomain,
|
|
15514
|
+
customDomain: metadata.services.cdn.config.cdn?.customDomain,
|
|
15514
15515
|
files,
|
|
15515
15516
|
totalSize,
|
|
15516
15517
|
fileCount: files.length
|
|
15517
15518
|
});
|
|
15518
15519
|
} catch (error) {
|
|
15519
15520
|
const errorMessage = error instanceof Error ? error.message : "Unknown error";
|
|
15520
|
-
console.error("[
|
|
15521
|
+
console.error("[CDN] Error fetching files:", error);
|
|
15521
15522
|
res.status(500).json({ error: errorMessage });
|
|
15522
15523
|
}
|
|
15523
15524
|
});
|
|
@@ -15529,16 +15530,16 @@ function createStorageRouter(config2) {
|
|
|
15529
15530
|
config2.accountId || "",
|
|
15530
15531
|
config2.region
|
|
15531
15532
|
);
|
|
15532
|
-
if (!metadata?.services.
|
|
15533
|
+
if (!metadata?.services.cdn) {
|
|
15533
15534
|
return res.status(404).json({
|
|
15534
|
-
error: "No
|
|
15535
|
+
error: "No CDN infrastructure found for this account and region"
|
|
15535
15536
|
});
|
|
15536
15537
|
}
|
|
15537
|
-
const bucketName = config2.
|
|
15538
|
+
const bucketName = config2.cdnBucketName || `wraps-cdn-${config2.accountId}`;
|
|
15538
15539
|
const { CloudWatchClient: CloudWatchClient3, GetMetricStatisticsCommand } = await import("@aws-sdk/client-cloudwatch");
|
|
15539
15540
|
const { assumeRole: assumeRole2 } = await Promise.resolve().then(() => (init_assume_role(), assume_role_exports));
|
|
15540
|
-
const credentials = config2.
|
|
15541
|
-
config2.
|
|
15541
|
+
const credentials = config2.cdnRoleArn || config2.roleArn ? await assumeRole2(
|
|
15542
|
+
config2.cdnRoleArn || config2.roleArn,
|
|
15542
15543
|
config2.region
|
|
15543
15544
|
) : void 0;
|
|
15544
15545
|
const cloudWatchClient = new CloudWatchClient3({
|
|
@@ -15580,7 +15581,7 @@ function createStorageRouter(config2) {
|
|
|
15580
15581
|
);
|
|
15581
15582
|
numberOfObjects = objectsResponse.Datapoints?.[0]?.Average || 0;
|
|
15582
15583
|
} catch (err) {
|
|
15583
|
-
console.log("[
|
|
15584
|
+
console.log("[CDN] CloudWatch metrics not available yet");
|
|
15584
15585
|
}
|
|
15585
15586
|
const usage = [];
|
|
15586
15587
|
const bandwidth = [];
|
|
@@ -15616,7 +15617,7 @@ function createStorageRouter(config2) {
|
|
|
15616
15617
|
});
|
|
15617
15618
|
} catch (error) {
|
|
15618
15619
|
const errorMessage = error instanceof Error ? error.message : "Unknown error";
|
|
15619
|
-
console.error("[
|
|
15620
|
+
console.error("[CDN] Error fetching metrics:", error);
|
|
15620
15621
|
res.status(500).json({ error: errorMessage });
|
|
15621
15622
|
}
|
|
15622
15623
|
});
|
|
@@ -15630,17 +15631,17 @@ function createStorageRouter(config2) {
|
|
|
15630
15631
|
config2.accountId || "",
|
|
15631
15632
|
config2.region
|
|
15632
15633
|
);
|
|
15633
|
-
if (!metadata?.services.
|
|
15634
|
+
if (!metadata?.services.cdn) {
|
|
15634
15635
|
return res.status(404).json({
|
|
15635
|
-
error: "No
|
|
15636
|
+
error: "No CDN infrastructure found for this account and region"
|
|
15636
15637
|
});
|
|
15637
15638
|
}
|
|
15638
|
-
const bucketName = config2.
|
|
15639
|
+
const bucketName = config2.cdnBucketName || `wraps-cdn-${config2.accountId}`;
|
|
15639
15640
|
const { S3Client, PutObjectCommand } = await import("@aws-sdk/client-s3");
|
|
15640
15641
|
const { getSignedUrl } = await import("@aws-sdk/s3-request-presigner");
|
|
15641
15642
|
const { assumeRole: assumeRole2 } = await Promise.resolve().then(() => (init_assume_role(), assume_role_exports));
|
|
15642
|
-
const credentials = config2.
|
|
15643
|
-
config2.
|
|
15643
|
+
const credentials = config2.cdnRoleArn || config2.roleArn ? await assumeRole2(
|
|
15644
|
+
config2.cdnRoleArn || config2.roleArn,
|
|
15644
15645
|
config2.region
|
|
15645
15646
|
) : void 0;
|
|
15646
15647
|
const s3Client = new S3Client({ region: config2.region, credentials });
|
|
@@ -15653,7 +15654,7 @@ function createStorageRouter(config2) {
|
|
|
15653
15654
|
expiresIn: 3600
|
|
15654
15655
|
// 1 hour
|
|
15655
15656
|
});
|
|
15656
|
-
const cdnUrl = metadata.services.
|
|
15657
|
+
const cdnUrl = metadata.services.cdn.config.cdn?.customDomain ? `https://${metadata.services.cdn.config.cdn.customDomain}/${filename}` : config2.cdnDistributionDomain ? `https://${config2.cdnDistributionDomain}/${filename}` : `s3://${bucketName}/${filename}`;
|
|
15657
15658
|
res.json({
|
|
15658
15659
|
uploadUrl,
|
|
15659
15660
|
cdnUrl,
|
|
@@ -15662,7 +15663,7 @@ function createStorageRouter(config2) {
|
|
|
15662
15663
|
});
|
|
15663
15664
|
} catch (error) {
|
|
15664
15665
|
const errorMessage = error instanceof Error ? error.message : "Unknown error";
|
|
15665
|
-
console.error("[
|
|
15666
|
+
console.error("[CDN] Error generating upload URL:", error);
|
|
15666
15667
|
res.status(500).json({ error: errorMessage });
|
|
15667
15668
|
}
|
|
15668
15669
|
});
|
|
@@ -15680,16 +15681,16 @@ function createStorageRouter(config2) {
|
|
|
15680
15681
|
config2.accountId || "",
|
|
15681
15682
|
config2.region
|
|
15682
15683
|
);
|
|
15683
|
-
if (!metadata?.services.
|
|
15684
|
+
if (!metadata?.services.cdn) {
|
|
15684
15685
|
return res.status(404).json({
|
|
15685
|
-
error: "No
|
|
15686
|
+
error: "No CDN infrastructure found for this account and region"
|
|
15686
15687
|
});
|
|
15687
15688
|
}
|
|
15688
|
-
const bucketName = config2.
|
|
15689
|
+
const bucketName = config2.cdnBucketName || `wraps-cdn-${config2.accountId}`;
|
|
15689
15690
|
const { S3Client, GetObjectTaggingCommand, PutObjectTaggingCommand } = await import("@aws-sdk/client-s3");
|
|
15690
15691
|
const { assumeRole: assumeRole2 } = await Promise.resolve().then(() => (init_assume_role(), assume_role_exports));
|
|
15691
|
-
const credentials = config2.
|
|
15692
|
-
config2.
|
|
15692
|
+
const credentials = config2.cdnRoleArn || config2.roleArn ? await assumeRole2(
|
|
15693
|
+
config2.cdnRoleArn || config2.roleArn,
|
|
15693
15694
|
config2.region
|
|
15694
15695
|
) : void 0;
|
|
15695
15696
|
const s3Client = new S3Client({ region: config2.region, credentials });
|
|
@@ -15721,7 +15722,7 @@ function createStorageRouter(config2) {
|
|
|
15721
15722
|
res.json({ success: true, key, starred });
|
|
15722
15723
|
} catch (error) {
|
|
15723
15724
|
const errorMessage = error instanceof Error ? error.message : "Unknown error";
|
|
15724
|
-
console.error("[
|
|
15725
|
+
console.error("[CDN] Error toggling star:", error);
|
|
15725
15726
|
res.status(500).json({ error: errorMessage });
|
|
15726
15727
|
}
|
|
15727
15728
|
});
|
|
@@ -15735,16 +15736,16 @@ function createStorageRouter(config2) {
|
|
|
15735
15736
|
config2.accountId || "",
|
|
15736
15737
|
config2.region
|
|
15737
15738
|
);
|
|
15738
|
-
if (!metadata?.services.
|
|
15739
|
+
if (!metadata?.services.cdn) {
|
|
15739
15740
|
return res.status(404).json({
|
|
15740
|
-
error: "No
|
|
15741
|
+
error: "No CDN infrastructure found for this account and region"
|
|
15741
15742
|
});
|
|
15742
15743
|
}
|
|
15743
|
-
const bucketName = config2.
|
|
15744
|
+
const bucketName = config2.cdnBucketName || `wraps-cdn-${config2.accountId}`;
|
|
15744
15745
|
const { S3Client, DeleteObjectCommand } = await import("@aws-sdk/client-s3");
|
|
15745
15746
|
const { assumeRole: assumeRole2 } = await Promise.resolve().then(() => (init_assume_role(), assume_role_exports));
|
|
15746
|
-
const credentials = config2.
|
|
15747
|
-
config2.
|
|
15747
|
+
const credentials = config2.cdnRoleArn || config2.roleArn ? await assumeRole2(
|
|
15748
|
+
config2.cdnRoleArn || config2.roleArn,
|
|
15748
15749
|
config2.region
|
|
15749
15750
|
) : void 0;
|
|
15750
15751
|
const s3Client = new S3Client({ region: config2.region, credentials });
|
|
@@ -15757,7 +15758,7 @@ function createStorageRouter(config2) {
|
|
|
15757
15758
|
res.json({ success: true, key });
|
|
15758
15759
|
} catch (error) {
|
|
15759
15760
|
const errorMessage = error instanceof Error ? error.message : "Unknown error";
|
|
15760
|
-
console.error("[
|
|
15761
|
+
console.error("[CDN] Error deleting file:", error);
|
|
15761
15762
|
res.status(500).json({ error: errorMessage });
|
|
15762
15763
|
}
|
|
15763
15764
|
});
|
|
@@ -15774,16 +15775,16 @@ function createStorageRouter(config2) {
|
|
|
15774
15775
|
config2.accountId || "",
|
|
15775
15776
|
config2.region
|
|
15776
15777
|
);
|
|
15777
|
-
if (!metadata?.services.
|
|
15778
|
+
if (!metadata?.services.cdn) {
|
|
15778
15779
|
return res.status(404).json({
|
|
15779
|
-
error: "No
|
|
15780
|
+
error: "No CDN infrastructure found for this account and region"
|
|
15780
15781
|
});
|
|
15781
15782
|
}
|
|
15782
|
-
const bucketName = config2.
|
|
15783
|
+
const bucketName = config2.cdnBucketName || `wraps-cdn-${config2.accountId}`;
|
|
15783
15784
|
const { S3Client, CopyObjectCommand, DeleteObjectCommand } = await import("@aws-sdk/client-s3");
|
|
15784
15785
|
const { assumeRole: assumeRole2 } = await Promise.resolve().then(() => (init_assume_role(), assume_role_exports));
|
|
15785
|
-
const credentials = config2.
|
|
15786
|
-
config2.
|
|
15786
|
+
const credentials = config2.cdnRoleArn || config2.roleArn ? await assumeRole2(
|
|
15787
|
+
config2.cdnRoleArn || config2.roleArn,
|
|
15787
15788
|
config2.region
|
|
15788
15789
|
) : void 0;
|
|
15789
15790
|
const s3Client = new S3Client({ region: config2.region, credentials });
|
|
@@ -15800,11 +15801,11 @@ function createStorageRouter(config2) {
|
|
|
15800
15801
|
Key: oldKey
|
|
15801
15802
|
})
|
|
15802
15803
|
);
|
|
15803
|
-
const cdnUrl = metadata.services.
|
|
15804
|
+
const cdnUrl = metadata.services.cdn.config.cdn?.customDomain ? `https://${metadata.services.cdn.config.cdn.customDomain}/${newKey}` : config2.cdnDistributionDomain ? `https://${config2.cdnDistributionDomain}/${newKey}` : `s3://${bucketName}/${newKey}`;
|
|
15804
15805
|
res.json({ success: true, oldKey, newKey, cdnUrl });
|
|
15805
15806
|
} catch (error) {
|
|
15806
15807
|
const errorMessage = error instanceof Error ? error.message : "Unknown error";
|
|
15807
|
-
console.error("[
|
|
15808
|
+
console.error("[CDN] Error renaming file:", error);
|
|
15808
15809
|
res.status(500).json({ error: errorMessage });
|
|
15809
15810
|
}
|
|
15810
15811
|
});
|
|
@@ -15904,7 +15905,7 @@ async function startConsoleServer(config2) {
|
|
|
15904
15905
|
app.use((_req, res, next) => {
|
|
15905
15906
|
res.setHeader("X-Frame-Options", "DENY");
|
|
15906
15907
|
res.setHeader("X-Content-Type-Options", "nosniff");
|
|
15907
|
-
const customDomainSrc = config2.
|
|
15908
|
+
const customDomainSrc = config2.cdnCustomDomain ? ` https://${config2.cdnCustomDomain}` : "";
|
|
15908
15909
|
res.setHeader(
|
|
15909
15910
|
"Content-Security-Policy",
|
|
15910
15911
|
`default-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; font-src 'self' https://fonts.gstatic.com; img-src 'self' data: blob: https://*.amazonaws.com https://*.cloudfront.net${customDomainSrc}; connect-src 'self' https://*.amazonaws.com https://*.cloudfront.net${customDomainSrc}`
|
|
@@ -15938,9 +15939,9 @@ async function startConsoleServer(config2) {
|
|
|
15938
15939
|
app.use("/api/user", authenticateToken(authToken), createUserRouter(config2));
|
|
15939
15940
|
app.use("/api/sms", authenticateToken(authToken), createSMSRouter(config2));
|
|
15940
15941
|
app.use(
|
|
15941
|
-
"/api/
|
|
15942
|
+
"/api/cdn",
|
|
15942
15943
|
authenticateToken(authToken),
|
|
15943
|
-
|
|
15944
|
+
createCdnRouter(config2)
|
|
15944
15945
|
);
|
|
15945
15946
|
const staticDir = path2.join(__dirname2, "console");
|
|
15946
15947
|
app.use(express.static(staticDir));
|
|
@@ -16000,12 +16001,12 @@ async function dashboard(options) {
|
|
|
16000
16001
|
} catch (_smsError) {
|
|
16001
16002
|
}
|
|
16002
16003
|
try {
|
|
16003
|
-
const
|
|
16004
|
-
stackName: `wraps-
|
|
16004
|
+
const cdnStack = await pulumi12.automation.LocalWorkspace.selectStack({
|
|
16005
|
+
stackName: `wraps-cdn-${identity.accountId}-${region}`,
|
|
16005
16006
|
workDir: getPulumiWorkDir()
|
|
16006
16007
|
});
|
|
16007
|
-
storageStackOutputs = await
|
|
16008
|
-
} catch (
|
|
16008
|
+
storageStackOutputs = await cdnStack.outputs();
|
|
16009
|
+
} catch (_cdnError) {
|
|
16009
16010
|
}
|
|
16010
16011
|
if (Object.keys(emailStackOutputs).length === 0 && Object.keys(smsStackOutputs).length === 0 && Object.keys(storageStackOutputs).length === 0) {
|
|
16011
16012
|
throw new Error("No infrastructure found");
|
|
@@ -16026,15 +16027,15 @@ async function dashboard(options) {
|
|
|
16026
16027
|
const smsPhoneNumberArn = smsStackOutputs.phoneNumberArn?.value;
|
|
16027
16028
|
const smsPhoneNumberType = smsStackOutputs.phoneNumberType?.value;
|
|
16028
16029
|
const smsConfigSetName = smsStackOutputs.configSetName?.value;
|
|
16029
|
-
const
|
|
16030
|
-
const
|
|
16031
|
-
const
|
|
16032
|
-
const
|
|
16030
|
+
const cdnBucketName = storageStackOutputs.bucketName?.value;
|
|
16031
|
+
const cdnDistributionId = storageStackOutputs.distributionId?.value;
|
|
16032
|
+
const cdnDistributionDomain = storageStackOutputs.distributionDomain?.value;
|
|
16033
|
+
const cdnCertificateArn = storageStackOutputs.acmCertificateArn?.value;
|
|
16033
16034
|
let smsProtectEnabled = false;
|
|
16034
16035
|
let smsAllowedCountries;
|
|
16035
16036
|
let smsAitFiltering;
|
|
16036
16037
|
let smsArchiveRetention;
|
|
16037
|
-
let
|
|
16038
|
+
let cdnCustomDomain;
|
|
16038
16039
|
try {
|
|
16039
16040
|
const metadata = await loadConnectionMetadata(identity.accountId, region);
|
|
16040
16041
|
if (metadata?.services?.sms?.config) {
|
|
@@ -16048,8 +16049,8 @@ async function dashboard(options) {
|
|
|
16048
16049
|
smsArchiveRetention = smsConfig.eventTracking.archiveRetention;
|
|
16049
16050
|
}
|
|
16050
16051
|
}
|
|
16051
|
-
if (metadata?.services?.
|
|
16052
|
-
|
|
16052
|
+
if (metadata?.services?.cdn?.config?.cdn?.customDomain) {
|
|
16053
|
+
cdnCustomDomain = metadata.services.cdn.config.cdn.customDomain;
|
|
16053
16054
|
}
|
|
16054
16055
|
} catch {
|
|
16055
16056
|
}
|
|
@@ -16080,13 +16081,13 @@ async function dashboard(options) {
|
|
|
16080
16081
|
smsAitFiltering,
|
|
16081
16082
|
smsArchiveRetention,
|
|
16082
16083
|
// Storage config (don't pass roleArn - use current credentials like email)
|
|
16083
|
-
|
|
16084
|
-
|
|
16084
|
+
cdnBucketName,
|
|
16085
|
+
cdnRoleArn: void 0,
|
|
16085
16086
|
// Use current credentials instead of assuming role
|
|
16086
|
-
|
|
16087
|
-
|
|
16088
|
-
|
|
16089
|
-
|
|
16087
|
+
cdnDistributionId,
|
|
16088
|
+
cdnDistributionDomain,
|
|
16089
|
+
cdnCustomDomain,
|
|
16090
|
+
cdnCertificateArn
|
|
16090
16091
|
});
|
|
16091
16092
|
console.log(`\\n${pc19.bold("Dashboard:")} ${pc19.cyan(url)}`);
|
|
16092
16093
|
console.log(`${pc19.dim("Press Ctrl+C to stop")}\\n`);
|
|
@@ -20106,7 +20107,7 @@ Run ${pc29.cyan(`wraps sms verify-number --phone-number ${phoneNumber} --resend`
|
|
|
20106
20107
|
}
|
|
20107
20108
|
}
|
|
20108
20109
|
|
|
20109
|
-
// src/commands/
|
|
20110
|
+
// src/commands/cdn/destroy.ts
|
|
20110
20111
|
init_esm_shims();
|
|
20111
20112
|
init_events();
|
|
20112
20113
|
init_route53();
|
|
@@ -20117,11 +20118,11 @@ init_metadata();
|
|
|
20117
20118
|
import * as clack28 from "@clack/prompts";
|
|
20118
20119
|
import * as pulumi20 from "@pulumi/pulumi";
|
|
20119
20120
|
import pc30 from "picocolors";
|
|
20120
|
-
async function
|
|
20121
|
+
async function cdnDestroy(options) {
|
|
20121
20122
|
const startTime = Date.now();
|
|
20122
20123
|
clack28.intro(
|
|
20123
20124
|
pc30.bold(
|
|
20124
|
-
options.preview ? "
|
|
20125
|
+
options.preview ? "CDN Infrastructure Destruction Preview" : "CDN Infrastructure Teardown"
|
|
20125
20126
|
)
|
|
20126
20127
|
);
|
|
20127
20128
|
const progress = new DeploymentProgress();
|
|
@@ -20131,16 +20132,16 @@ async function storageDestroy(options) {
|
|
|
20131
20132
|
);
|
|
20132
20133
|
let region = options.region || await getAWSRegion();
|
|
20133
20134
|
if (!(options.region || process.env.AWS_REGION || process.env.AWS_DEFAULT_REGION)) {
|
|
20134
|
-
const
|
|
20135
|
+
const cdnConnections = await findConnectionsWithService(
|
|
20135
20136
|
identity.accountId,
|
|
20136
|
-
"
|
|
20137
|
+
"cdn"
|
|
20137
20138
|
);
|
|
20138
|
-
if (
|
|
20139
|
-
region =
|
|
20140
|
-
} else if (
|
|
20139
|
+
if (cdnConnections.length === 1) {
|
|
20140
|
+
region = cdnConnections[0].region;
|
|
20141
|
+
} else if (cdnConnections.length > 1) {
|
|
20141
20142
|
const selectedRegion = await clack28.select({
|
|
20142
|
-
message: "Multiple
|
|
20143
|
-
options:
|
|
20143
|
+
message: "Multiple CDN deployments found. Which region to destroy?",
|
|
20144
|
+
options: cdnConnections.map((conn) => ({
|
|
20144
20145
|
value: conn.region,
|
|
20145
20146
|
label: conn.region
|
|
20146
20147
|
}))
|
|
@@ -20153,17 +20154,17 @@ async function storageDestroy(options) {
|
|
|
20153
20154
|
}
|
|
20154
20155
|
}
|
|
20155
20156
|
const metadata = await loadConnectionMetadata(identity.accountId, region);
|
|
20156
|
-
const
|
|
20157
|
-
const
|
|
20158
|
-
const customDomain =
|
|
20159
|
-
const storedStackName =
|
|
20157
|
+
const cdnService = metadata?.services?.cdn;
|
|
20158
|
+
const cdnConfig = cdnService?.config;
|
|
20159
|
+
const customDomain = cdnConfig?.cdn?.customDomain;
|
|
20160
|
+
const storedStackName = cdnService?.pulumiStackName;
|
|
20160
20161
|
if (!(options.force || options.preview)) {
|
|
20161
20162
|
clack28.log.warn(
|
|
20162
20163
|
pc30.yellow("This will delete your S3 bucket and all files in it!")
|
|
20163
20164
|
);
|
|
20164
20165
|
const confirmed = await clack28.confirm({
|
|
20165
20166
|
message: pc30.red(
|
|
20166
|
-
"Are you sure you want to destroy all
|
|
20167
|
+
"Are you sure you want to destroy all CDN infrastructure?"
|
|
20167
20168
|
),
|
|
20168
20169
|
initialValue: false
|
|
20169
20170
|
});
|
|
@@ -20198,7 +20199,7 @@ async function storageDestroy(options) {
|
|
|
20198
20199
|
"Generating destruction preview",
|
|
20199
20200
|
async () => {
|
|
20200
20201
|
await ensurePulumiWorkDir();
|
|
20201
|
-
const stackName = storedStackName || `wraps-
|
|
20202
|
+
const stackName = storedStackName || `wraps-cdn-${identity.accountId}-${region}`;
|
|
20202
20203
|
let stack;
|
|
20203
20204
|
try {
|
|
20204
20205
|
stack = await pulumi20.automation.LocalWorkspace.selectStack({
|
|
@@ -20206,7 +20207,7 @@ async function storageDestroy(options) {
|
|
|
20206
20207
|
workDir: getPulumiWorkDir()
|
|
20207
20208
|
});
|
|
20208
20209
|
} catch (_error) {
|
|
20209
|
-
throw new Error("No
|
|
20210
|
+
throw new Error("No CDN infrastructure found to preview");
|
|
20210
20211
|
}
|
|
20211
20212
|
const result = await previewWithResourceChanges(stack, {
|
|
20212
20213
|
diff: true
|
|
@@ -20218,7 +20219,7 @@ async function storageDestroy(options) {
|
|
|
20218
20219
|
changeSummary: previewResult.changeSummary,
|
|
20219
20220
|
resourceChanges: previewResult.resourceChanges,
|
|
20220
20221
|
costEstimate: "Monthly cost after destruction: $0.00",
|
|
20221
|
-
commandName: "wraps
|
|
20222
|
+
commandName: "wraps cdn destroy"
|
|
20222
20223
|
});
|
|
20223
20224
|
if (customDomain) {
|
|
20224
20225
|
const previewHostedZone = await findHostedZone(customDomain, region);
|
|
@@ -20231,7 +20232,7 @@ async function storageDestroy(options) {
|
|
|
20231
20232
|
clack28.outro(
|
|
20232
20233
|
pc30.green("Preview complete. Run without --preview to destroy.")
|
|
20233
20234
|
);
|
|
20234
|
-
trackServiceRemoved("
|
|
20235
|
+
trackServiceRemoved("cdn", {
|
|
20235
20236
|
preview: true,
|
|
20236
20237
|
region,
|
|
20237
20238
|
duration_ms: Date.now() - startTime
|
|
@@ -20239,8 +20240,8 @@ async function storageDestroy(options) {
|
|
|
20239
20240
|
return;
|
|
20240
20241
|
} catch (error) {
|
|
20241
20242
|
progress.stop();
|
|
20242
|
-
if (error.message.includes("No
|
|
20243
|
-
clack28.log.warn("No
|
|
20243
|
+
if (error.message.includes("No CDN infrastructure found")) {
|
|
20244
|
+
clack28.log.warn("No CDN infrastructure found to preview");
|
|
20244
20245
|
process.exit(0);
|
|
20245
20246
|
}
|
|
20246
20247
|
trackError("PREVIEW_FAILED", "storage destroy", { step: "preview" });
|
|
@@ -20252,7 +20253,7 @@ async function storageDestroy(options) {
|
|
|
20252
20253
|
await progress.execute(
|
|
20253
20254
|
`Deleting DNS records for ${customDomain}`,
|
|
20254
20255
|
async () => {
|
|
20255
|
-
await
|
|
20256
|
+
await deleteCdnDNSRecords(hostedZone.id, customDomain);
|
|
20256
20257
|
}
|
|
20257
20258
|
);
|
|
20258
20259
|
} catch (error) {
|
|
@@ -20260,7 +20261,7 @@ async function storageDestroy(options) {
|
|
|
20260
20261
|
clack28.log.info("You may need to delete them manually from Route53");
|
|
20261
20262
|
}
|
|
20262
20263
|
}
|
|
20263
|
-
const bucketName = `wraps-
|
|
20264
|
+
const bucketName = `wraps-cdn-${identity.accountId}`;
|
|
20264
20265
|
try {
|
|
20265
20266
|
await progress.execute(
|
|
20266
20267
|
"Emptying S3 bucket (this may take a while for large buckets)",
|
|
@@ -20273,10 +20274,10 @@ async function storageDestroy(options) {
|
|
|
20273
20274
|
}
|
|
20274
20275
|
try {
|
|
20275
20276
|
await progress.execute(
|
|
20276
|
-
"Destroying
|
|
20277
|
+
"Destroying CDN infrastructure (this may take 2-3 minutes)",
|
|
20277
20278
|
async () => {
|
|
20278
20279
|
await ensurePulumiWorkDir();
|
|
20279
|
-
const stackName = storedStackName || `wraps-
|
|
20280
|
+
const stackName = storedStackName || `wraps-cdn-${identity.accountId}-${region}`;
|
|
20280
20281
|
let stack;
|
|
20281
20282
|
try {
|
|
20282
20283
|
stack = await pulumi20.automation.LocalWorkspace.selectStack({
|
|
@@ -20284,7 +20285,7 @@ async function storageDestroy(options) {
|
|
|
20284
20285
|
workDir: getPulumiWorkDir()
|
|
20285
20286
|
});
|
|
20286
20287
|
} catch (_error) {
|
|
20287
|
-
throw new Error("No
|
|
20288
|
+
throw new Error("No CDN infrastructure found to destroy");
|
|
20288
20289
|
}
|
|
20289
20290
|
await stack.destroy({ onOutput: () => {
|
|
20290
20291
|
} });
|
|
@@ -20293,10 +20294,10 @@ async function storageDestroy(options) {
|
|
|
20293
20294
|
);
|
|
20294
20295
|
} catch (error) {
|
|
20295
20296
|
progress.stop();
|
|
20296
|
-
if (error.message.includes("No
|
|
20297
|
-
clack28.log.warn("No
|
|
20297
|
+
if (error.message.includes("No CDN infrastructure found")) {
|
|
20298
|
+
clack28.log.warn("No CDN infrastructure found");
|
|
20298
20299
|
if (metadata) {
|
|
20299
|
-
removeServiceFromConnection(metadata, "
|
|
20300
|
+
removeServiceFromConnection(metadata, "cdn");
|
|
20300
20301
|
await saveConnectionMetadata(metadata);
|
|
20301
20302
|
}
|
|
20302
20303
|
process.exit(0);
|
|
@@ -20306,11 +20307,11 @@ async function storageDestroy(options) {
|
|
|
20306
20307
|
throw errors.stackLocked();
|
|
20307
20308
|
}
|
|
20308
20309
|
trackError("DESTROY_FAILED", "storage destroy", { step: "destroy" });
|
|
20309
|
-
clack28.log.error("
|
|
20310
|
+
clack28.log.error("CDN infrastructure destruction failed");
|
|
20310
20311
|
throw error;
|
|
20311
20312
|
}
|
|
20312
20313
|
if (metadata) {
|
|
20313
|
-
removeServiceFromConnection(metadata, "
|
|
20314
|
+
removeServiceFromConnection(metadata, "cdn");
|
|
20314
20315
|
const hasOtherServices = Object.keys(metadata.services).length > 0;
|
|
20315
20316
|
if (hasOtherServices) {
|
|
20316
20317
|
await saveConnectionMetadata(metadata);
|
|
@@ -20324,7 +20325,7 @@ async function storageDestroy(options) {
|
|
|
20324
20325
|
if (shouldCleanDNS && hostedZone) {
|
|
20325
20326
|
deletedItems.push("Route53 DNS records");
|
|
20326
20327
|
}
|
|
20327
|
-
clack28.outro(pc30.green("
|
|
20328
|
+
clack28.outro(pc30.green("CDN infrastructure has been removed"));
|
|
20328
20329
|
console.log(`
|
|
20329
20330
|
${pc30.bold("Cleaned up:")}`);
|
|
20330
20331
|
for (const item of deletedItems) {
|
|
@@ -20332,10 +20333,10 @@ ${pc30.bold("Cleaned up:")}`);
|
|
|
20332
20333
|
}
|
|
20333
20334
|
console.log(
|
|
20334
20335
|
`
|
|
20335
|
-
Run ${pc30.cyan("wraps
|
|
20336
|
+
Run ${pc30.cyan("wraps cdn init")} to deploy CDN infrastructure again.
|
|
20336
20337
|
`
|
|
20337
20338
|
);
|
|
20338
|
-
trackServiceRemoved("
|
|
20339
|
+
trackServiceRemoved("cdn", {
|
|
20339
20340
|
reason: "user_initiated",
|
|
20340
20341
|
region,
|
|
20341
20342
|
duration_ms: Date.now() - startTime,
|
|
@@ -20374,7 +20375,7 @@ async function emptyS3Bucket(bucketName, region) {
|
|
|
20374
20375
|
versionIdMarker = listResponse.NextVersionIdMarker;
|
|
20375
20376
|
} while (keyMarker);
|
|
20376
20377
|
}
|
|
20377
|
-
async function
|
|
20378
|
+
async function deleteCdnDNSRecords(hostedZoneId, customDomain) {
|
|
20378
20379
|
const {
|
|
20379
20380
|
Route53Client: Route53Client2,
|
|
20380
20381
|
ListResourceRecordSetsCommand: ListResourceRecordSetsCommand2,
|
|
@@ -20407,18 +20408,18 @@ async function deleteStorageDNSRecords(hostedZoneId, customDomain) {
|
|
|
20407
20408
|
);
|
|
20408
20409
|
}
|
|
20409
20410
|
|
|
20410
|
-
// src/commands/
|
|
20411
|
+
// src/commands/cdn/init.ts
|
|
20411
20412
|
init_esm_shims();
|
|
20412
20413
|
import * as clack29 from "@clack/prompts";
|
|
20413
20414
|
import * as pulumi23 from "@pulumi/pulumi";
|
|
20414
20415
|
import pc31 from "picocolors";
|
|
20415
20416
|
|
|
20416
|
-
// src/infrastructure/
|
|
20417
|
+
// src/infrastructure/cdn-stack.ts
|
|
20417
20418
|
init_esm_shims();
|
|
20418
20419
|
import * as aws14 from "@pulumi/aws";
|
|
20419
20420
|
import * as pulumi22 from "@pulumi/pulumi";
|
|
20420
20421
|
|
|
20421
|
-
// src/infrastructure/resources/s3-
|
|
20422
|
+
// src/infrastructure/resources/s3-cdn.ts
|
|
20422
20423
|
init_esm_shims();
|
|
20423
20424
|
import * as aws13 from "@pulumi/aws";
|
|
20424
20425
|
import * as pulumi21 from "@pulumi/pulumi";
|
|
@@ -20440,17 +20441,17 @@ function retentionToDays(retention) {
|
|
|
20440
20441
|
return null;
|
|
20441
20442
|
}
|
|
20442
20443
|
}
|
|
20443
|
-
async function
|
|
20444
|
-
const bucketName = config2.
|
|
20445
|
-
const bucket = new aws13.s3.BucketV2("wraps-
|
|
20444
|
+
async function createCdnBucket(config2) {
|
|
20445
|
+
const bucketName = config2.cdnConfig.bucketName || `wraps-cdn-${config2.accountId}`;
|
|
20446
|
+
const bucket = new aws13.s3.BucketV2("wraps-cdn-bucket", {
|
|
20446
20447
|
bucket: bucketName,
|
|
20447
20448
|
tags: {
|
|
20448
20449
|
ManagedBy: "wraps-cli",
|
|
20449
|
-
Service: "
|
|
20450
|
+
Service: "cdn"
|
|
20450
20451
|
}
|
|
20451
20452
|
});
|
|
20452
|
-
if (config2.
|
|
20453
|
-
new aws13.s3.BucketVersioningV2("wraps-
|
|
20453
|
+
if (config2.cdnConfig.versioning) {
|
|
20454
|
+
new aws13.s3.BucketVersioningV2("wraps-cdn-versioning", {
|
|
20454
20455
|
bucket: bucket.id,
|
|
20455
20456
|
versioningConfiguration: {
|
|
20456
20457
|
status: "Enabled"
|
|
@@ -20458,7 +20459,7 @@ async function createStorageBucket(config2) {
|
|
|
20458
20459
|
});
|
|
20459
20460
|
}
|
|
20460
20461
|
new aws13.s3.BucketServerSideEncryptionConfigurationV2(
|
|
20461
|
-
"wraps-
|
|
20462
|
+
"wraps-cdn-encryption",
|
|
20462
20463
|
{
|
|
20463
20464
|
bucket: bucket.id,
|
|
20464
20465
|
rules: [
|
|
@@ -20481,9 +20482,9 @@ async function createStorageBucket(config2) {
|
|
|
20481
20482
|
"http://localhost:5555",
|
|
20482
20483
|
"http://localhost:5556",
|
|
20483
20484
|
"http://localhost:8080",
|
|
20484
|
-
...config2.
|
|
20485
|
+
...config2.cdnConfig.additionalOrigins || []
|
|
20485
20486
|
];
|
|
20486
|
-
new aws13.s3.BucketCorsConfigurationV2("wraps-
|
|
20487
|
+
new aws13.s3.BucketCorsConfigurationV2("wraps-cdn-cors", {
|
|
20487
20488
|
bucket: bucket.id,
|
|
20488
20489
|
corsRules: [
|
|
20489
20490
|
{
|
|
@@ -20495,9 +20496,9 @@ async function createStorageBucket(config2) {
|
|
|
20495
20496
|
}
|
|
20496
20497
|
]
|
|
20497
20498
|
});
|
|
20498
|
-
const retentionDays = config2.
|
|
20499
|
+
const retentionDays = config2.cdnConfig.retention ? retentionToDays(config2.cdnConfig.retention) : null;
|
|
20499
20500
|
if (retentionDays) {
|
|
20500
|
-
new aws13.s3.BucketLifecycleConfigurationV2("wraps-
|
|
20501
|
+
new aws13.s3.BucketLifecycleConfigurationV2("wraps-cdn-lifecycle", {
|
|
20501
20502
|
bucket: bucket.id,
|
|
20502
20503
|
rules: [
|
|
20503
20504
|
{
|
|
@@ -20510,7 +20511,7 @@ async function createStorageBucket(config2) {
|
|
|
20510
20511
|
]
|
|
20511
20512
|
});
|
|
20512
20513
|
}
|
|
20513
|
-
new aws13.s3.BucketPublicAccessBlock("wraps-
|
|
20514
|
+
new aws13.s3.BucketPublicAccessBlock("wraps-cdn-public-access", {
|
|
20514
20515
|
bucket: bucket.id,
|
|
20515
20516
|
blockPublicAcls: true,
|
|
20516
20517
|
blockPublicPolicy: true,
|
|
@@ -20523,16 +20524,16 @@ async function createStorageBucket(config2) {
|
|
|
20523
20524
|
bucketArn: bucket.arn
|
|
20524
20525
|
};
|
|
20525
20526
|
}
|
|
20526
|
-
async function
|
|
20527
|
+
async function createCdnWAF() {
|
|
20527
20528
|
const usEast1Provider = new aws13.Provider("storage-waf-us-east-1", {
|
|
20528
20529
|
region: "us-east-1"
|
|
20529
20530
|
});
|
|
20530
20531
|
const webAcl = new aws13.wafv2.WebAcl(
|
|
20531
|
-
"wraps-
|
|
20532
|
+
"wraps-cdn-waf",
|
|
20532
20533
|
{
|
|
20533
20534
|
scope: "CLOUDFRONT",
|
|
20534
20535
|
// WAF for CloudFront must use CLOUDFRONT scope
|
|
20535
|
-
description: "Rate limiting protection for Wraps
|
|
20536
|
+
description: "Rate limiting protection for Wraps CDN",
|
|
20536
20537
|
defaultAction: {
|
|
20537
20538
|
allow: {}
|
|
20538
20539
|
// Allow by default
|
|
@@ -20555,20 +20556,20 @@ async function createStorageWAF() {
|
|
|
20555
20556
|
visibilityConfig: {
|
|
20556
20557
|
sampledRequestsEnabled: true,
|
|
20557
20558
|
cloudwatchMetricsEnabled: true,
|
|
20558
|
-
metricName: "
|
|
20559
|
+
metricName: "CdnRateLimitRule"
|
|
20559
20560
|
}
|
|
20560
20561
|
}
|
|
20561
20562
|
],
|
|
20562
20563
|
visibilityConfig: {
|
|
20563
20564
|
sampledRequestsEnabled: true,
|
|
20564
20565
|
cloudwatchMetricsEnabled: true,
|
|
20565
|
-
metricName: "wraps-
|
|
20566
|
+
metricName: "wraps-cdn-waf"
|
|
20566
20567
|
},
|
|
20567
20568
|
tags: {
|
|
20568
|
-
Name: "wraps-
|
|
20569
|
+
Name: "wraps-cdn-waf",
|
|
20569
20570
|
ManagedBy: "wraps-cli",
|
|
20570
|
-
Service: "
|
|
20571
|
-
Description: "WAF for Wraps
|
|
20571
|
+
Service: "cdn",
|
|
20572
|
+
Description: "WAF for Wraps CDN with rate limiting"
|
|
20572
20573
|
}
|
|
20573
20574
|
},
|
|
20574
20575
|
{
|
|
@@ -20577,11 +20578,11 @@ async function createStorageWAF() {
|
|
|
20577
20578
|
);
|
|
20578
20579
|
return webAcl;
|
|
20579
20580
|
}
|
|
20580
|
-
async function
|
|
20581
|
-
const webAcl = config2.wafEnabled ? await
|
|
20582
|
-
const oac = new aws13.cloudfront.OriginAccessControl("wraps-
|
|
20583
|
-
name: "wraps-
|
|
20584
|
-
description: "OAC for Wraps
|
|
20581
|
+
async function createCdnDistribution(config2) {
|
|
20582
|
+
const webAcl = config2.wafEnabled ? await createCdnWAF() : void 0;
|
|
20583
|
+
const oac = new aws13.cloudfront.OriginAccessControl("wraps-cdn-oac", {
|
|
20584
|
+
name: "wraps-cdn-oac",
|
|
20585
|
+
description: "OAC for Wraps CDN S3 bucket",
|
|
20585
20586
|
originAccessControlOriginType: "s3",
|
|
20586
20587
|
signingBehavior: "always",
|
|
20587
20588
|
signingProtocol: "sigv4"
|
|
@@ -20596,7 +20597,7 @@ async function createStorageCDN(config2) {
|
|
|
20596
20597
|
};
|
|
20597
20598
|
const originConfig = {
|
|
20598
20599
|
domainName: config2.bucket.bucketRegionalDomainName,
|
|
20599
|
-
originId: "s3-
|
|
20600
|
+
originId: "s3-cdn",
|
|
20600
20601
|
originAccessControlId: oac.id
|
|
20601
20602
|
};
|
|
20602
20603
|
if (config2.originShield) {
|
|
@@ -20614,9 +20615,9 @@ async function createStorageCDN(config2) {
|
|
|
20614
20615
|
} : {
|
|
20615
20616
|
restrictionType: "none"
|
|
20616
20617
|
};
|
|
20617
|
-
const distribution = new aws13.cloudfront.Distribution("wraps-
|
|
20618
|
+
const distribution = new aws13.cloudfront.Distribution("wraps-cdn-cdn", {
|
|
20618
20619
|
enabled: true,
|
|
20619
|
-
comment: "Wraps
|
|
20620
|
+
comment: "Wraps CDN",
|
|
20620
20621
|
aliases,
|
|
20621
20622
|
// Attach WAF Web ACL for rate limiting protection (only if enabled)
|
|
20622
20623
|
webAclId: webAcl?.arn,
|
|
@@ -20624,7 +20625,7 @@ async function createStorageCDN(config2) {
|
|
|
20624
20625
|
origins: [originConfig],
|
|
20625
20626
|
// Default cache behavior for static assets
|
|
20626
20627
|
defaultCacheBehavior: {
|
|
20627
|
-
targetOriginId: "s3-
|
|
20628
|
+
targetOriginId: "s3-cdn",
|
|
20628
20629
|
viewerProtocolPolicy: "redirect-to-https",
|
|
20629
20630
|
// Allow GET, HEAD, OPTIONS only (uploads go direct to S3 via presigned URLs)
|
|
20630
20631
|
allowedMethods: ["GET", "HEAD", "OPTIONS"],
|
|
@@ -20652,12 +20653,12 @@ async function createStorageCDN(config2) {
|
|
|
20652
20653
|
// SSL certificate
|
|
20653
20654
|
viewerCertificate,
|
|
20654
20655
|
tags: {
|
|
20655
|
-
Name: "wraps-
|
|
20656
|
+
Name: "wraps-cdn",
|
|
20656
20657
|
ManagedBy: "wraps-cli",
|
|
20657
|
-
Service: "
|
|
20658
|
+
Service: "cdn"
|
|
20658
20659
|
}
|
|
20659
20660
|
});
|
|
20660
|
-
new aws13.s3.BucketPolicy("wraps-
|
|
20661
|
+
new aws13.s3.BucketPolicy("wraps-cdn-bucket-policy", {
|
|
20661
20662
|
bucket: config2.bucket.id,
|
|
20662
20663
|
policy: pulumi21.interpolate`{
|
|
20663
20664
|
"Version": "2012-10-17",
|
|
@@ -20685,19 +20686,19 @@ async function createStorageCDN(config2) {
|
|
|
20685
20686
|
webAcl
|
|
20686
20687
|
};
|
|
20687
20688
|
}
|
|
20688
|
-
async function
|
|
20689
|
+
async function createCdnACMCertificate(config2) {
|
|
20689
20690
|
const usEast1Provider = new aws13.Provider("storage-acm-us-east-1", {
|
|
20690
20691
|
region: "us-east-1"
|
|
20691
20692
|
});
|
|
20692
20693
|
const certificate = new aws13.acm.Certificate(
|
|
20693
|
-
"wraps-
|
|
20694
|
+
"wraps-cdn-cert",
|
|
20694
20695
|
{
|
|
20695
20696
|
domainName: config2.domain,
|
|
20696
20697
|
validationMethod: "DNS",
|
|
20697
20698
|
tags: {
|
|
20698
20699
|
ManagedBy: "wraps-cli",
|
|
20699
|
-
Service: "
|
|
20700
|
-
Description: "SSL certificate for Wraps
|
|
20700
|
+
Service: "cdn",
|
|
20701
|
+
Description: "SSL certificate for Wraps CDN domain"
|
|
20701
20702
|
}
|
|
20702
20703
|
},
|
|
20703
20704
|
{
|
|
@@ -20714,7 +20715,7 @@ async function createStorageACMCertificate(config2) {
|
|
|
20714
20715
|
let certificateValidation;
|
|
20715
20716
|
if (config2.hostedZoneId) {
|
|
20716
20717
|
const validationRecord = new aws13.route53.Record(
|
|
20717
|
-
"wraps-
|
|
20718
|
+
"wraps-cdn-cert-validation",
|
|
20718
20719
|
{
|
|
20719
20720
|
zoneId: config2.hostedZoneId,
|
|
20720
20721
|
name: certificate.domainValidationOptions[0].resourceRecordName,
|
|
@@ -20724,7 +20725,7 @@ async function createStorageACMCertificate(config2) {
|
|
|
20724
20725
|
}
|
|
20725
20726
|
);
|
|
20726
20727
|
certificateValidation = new aws13.acm.CertificateValidation(
|
|
20727
|
-
"wraps-
|
|
20728
|
+
"wraps-cdn-cert-validation-waiter",
|
|
20728
20729
|
{
|
|
20729
20730
|
certificateArn: certificate.arn,
|
|
20730
20731
|
validationRecordFqdns: [validationRecord.fqdn]
|
|
@@ -20741,7 +20742,7 @@ async function createStorageACMCertificate(config2) {
|
|
|
20741
20742
|
};
|
|
20742
20743
|
}
|
|
20743
20744
|
|
|
20744
|
-
// src/infrastructure/
|
|
20745
|
+
// src/infrastructure/cdn-stack.ts
|
|
20745
20746
|
async function roleExists3(roleName) {
|
|
20746
20747
|
try {
|
|
20747
20748
|
const { IAMClient: IAMClient3, GetRoleCommand: GetRoleCommand2 } = await import("@aws-sdk/client-iam");
|
|
@@ -20758,7 +20759,7 @@ async function roleExists3(roleName) {
|
|
|
20758
20759
|
return false;
|
|
20759
20760
|
}
|
|
20760
20761
|
}
|
|
20761
|
-
async function
|
|
20762
|
+
async function createCdnIAMRole(config2) {
|
|
20762
20763
|
let assumeRolePolicy;
|
|
20763
20764
|
if (config2.provider === "vercel" && config2.oidcProvider) {
|
|
20764
20765
|
assumeRolePolicy = pulumi22.interpolate`{
|
|
@@ -20793,7 +20794,7 @@ async function createStorageIAMRole(config2) {
|
|
|
20793
20794
|
} else {
|
|
20794
20795
|
throw new Error("Other providers not yet implemented");
|
|
20795
20796
|
}
|
|
20796
|
-
const roleName = "wraps-
|
|
20797
|
+
const roleName = "wraps-cdn-role";
|
|
20797
20798
|
const exists = await roleExists3(roleName);
|
|
20798
20799
|
const role = exists ? new aws14.iam.Role(
|
|
20799
20800
|
roleName,
|
|
@@ -20802,7 +20803,7 @@ async function createStorageIAMRole(config2) {
|
|
|
20802
20803
|
assumeRolePolicy,
|
|
20803
20804
|
tags: {
|
|
20804
20805
|
ManagedBy: "wraps-cli",
|
|
20805
|
-
Service: "
|
|
20806
|
+
Service: "cdn",
|
|
20806
20807
|
Provider: config2.provider
|
|
20807
20808
|
}
|
|
20808
20809
|
},
|
|
@@ -20814,7 +20815,7 @@ async function createStorageIAMRole(config2) {
|
|
|
20814
20815
|
assumeRolePolicy,
|
|
20815
20816
|
tags: {
|
|
20816
20817
|
ManagedBy: "wraps-cli",
|
|
20817
|
-
Service: "
|
|
20818
|
+
Service: "cdn",
|
|
20818
20819
|
Provider: config2.provider
|
|
20819
20820
|
}
|
|
20820
20821
|
});
|
|
@@ -20847,7 +20848,7 @@ async function createStorageIAMRole(config2) {
|
|
|
20847
20848
|
Resource: config2.distributionArn
|
|
20848
20849
|
});
|
|
20849
20850
|
}
|
|
20850
|
-
new aws14.iam.RolePolicy("wraps-
|
|
20851
|
+
new aws14.iam.RolePolicy("wraps-cdn-policy", {
|
|
20851
20852
|
role: role.name,
|
|
20852
20853
|
policy: pulumi22.all([statements]).apply(
|
|
20853
20854
|
([stmts]) => JSON.stringify({
|
|
@@ -20858,7 +20859,7 @@ async function createStorageIAMRole(config2) {
|
|
|
20858
20859
|
});
|
|
20859
20860
|
return role;
|
|
20860
20861
|
}
|
|
20861
|
-
async function
|
|
20862
|
+
async function deployCdnStack(config2) {
|
|
20862
20863
|
const accountId = config2.accountId;
|
|
20863
20864
|
let oidcProvider;
|
|
20864
20865
|
if (config2.provider === "vercel" && config2.vercel) {
|
|
@@ -20867,42 +20868,42 @@ async function deployStorageStack(config2) {
|
|
|
20867
20868
|
accountId
|
|
20868
20869
|
});
|
|
20869
20870
|
}
|
|
20870
|
-
const bucketResources = await
|
|
20871
|
+
const bucketResources = await createCdnBucket({
|
|
20871
20872
|
accountId,
|
|
20872
20873
|
region: config2.region,
|
|
20873
|
-
|
|
20874
|
+
cdnConfig: config2.cdnConfig
|
|
20874
20875
|
});
|
|
20875
20876
|
let acmResources;
|
|
20876
20877
|
let hostedZone = null;
|
|
20877
|
-
if (config2.
|
|
20878
|
-
const domainParts = config2.
|
|
20879
|
-
const rootDomain = domainParts.length > 2 ? domainParts.slice(-2).join(".") : config2.
|
|
20878
|
+
if (config2.cdnConfig.cdn.customDomain) {
|
|
20879
|
+
const domainParts = config2.cdnConfig.cdn.customDomain.split(".");
|
|
20880
|
+
const rootDomain = domainParts.length > 2 ? domainParts.slice(-2).join(".") : config2.cdnConfig.cdn.customDomain;
|
|
20880
20881
|
const { findHostedZone: findHostedZone2 } = await Promise.resolve().then(() => (init_route53(), route53_exports));
|
|
20881
20882
|
hostedZone = await findHostedZone2(rootDomain, config2.region);
|
|
20882
|
-
acmResources = await
|
|
20883
|
-
domain: config2.
|
|
20883
|
+
acmResources = await createCdnACMCertificate({
|
|
20884
|
+
domain: config2.cdnConfig.cdn.customDomain,
|
|
20884
20885
|
hostedZoneId: hostedZone?.id
|
|
20885
20886
|
});
|
|
20886
20887
|
}
|
|
20887
20888
|
let cdnResources;
|
|
20888
|
-
if (config2.
|
|
20889
|
+
if (config2.cdnConfig.cdn.enabled) {
|
|
20889
20890
|
const hasAutoValidation2 = acmResources?.certificateValidation;
|
|
20890
20891
|
const useCertFromUpgrade = config2.certValidated && config2.existingCertArn;
|
|
20891
20892
|
const certificateArn = useCertFromUpgrade ? pulumi22.output(config2.existingCertArn) : hasAutoValidation2 ? acmResources?.certificateValidation?.certificateArn : void 0;
|
|
20892
|
-
const customDomainForCdn = useCertFromUpgrade || hasAutoValidation2 ? config2.
|
|
20893
|
-
cdnResources = await
|
|
20893
|
+
const customDomainForCdn = useCertFromUpgrade || hasAutoValidation2 ? config2.cdnConfig.cdn.customDomain : void 0;
|
|
20894
|
+
cdnResources = await createCdnDistribution({
|
|
20894
20895
|
bucket: bucketResources.bucket,
|
|
20895
20896
|
bucketRegion: config2.region,
|
|
20896
20897
|
// For Origin Shield
|
|
20897
20898
|
customDomain: customDomainForCdn,
|
|
20898
20899
|
certificateArn,
|
|
20899
|
-
priceClass: config2.
|
|
20900
|
-
originShield: config2.
|
|
20901
|
-
geoRestriction: config2.
|
|
20902
|
-
wafEnabled: config2.
|
|
20900
|
+
priceClass: config2.cdnConfig.cdn.priceClass,
|
|
20901
|
+
originShield: config2.cdnConfig.cdn.originShield,
|
|
20902
|
+
geoRestriction: config2.cdnConfig.cdn.geoRestriction,
|
|
20903
|
+
wafEnabled: config2.cdnConfig.cdn.wafEnabled
|
|
20903
20904
|
});
|
|
20904
20905
|
}
|
|
20905
|
-
const role = await
|
|
20906
|
+
const role = await createCdnIAMRole({
|
|
20906
20907
|
provider: config2.provider,
|
|
20907
20908
|
oidcProvider,
|
|
20908
20909
|
vercelTeamSlug: config2.vercel?.teamSlug,
|
|
@@ -20912,8 +20913,8 @@ async function deployStorageStack(config2) {
|
|
|
20912
20913
|
});
|
|
20913
20914
|
const hasAutoValidation = acmResources?.certificateValidation;
|
|
20914
20915
|
const hasCertFromUpgrade = config2.certValidated && config2.existingCertArn;
|
|
20915
|
-
const customDomainActive = config2.
|
|
20916
|
-
const customDomainPending = config2.
|
|
20916
|
+
const customDomainActive = config2.cdnConfig.cdn.customDomain && (hasAutoValidation || hasCertFromUpgrade);
|
|
20917
|
+
const customDomainPending = config2.cdnConfig.cdn.customDomain && !hasAutoValidation && !hasCertFromUpgrade;
|
|
20917
20918
|
return {
|
|
20918
20919
|
roleArn: role.arn,
|
|
20919
20920
|
bucketName: bucketResources.bucketName,
|
|
@@ -20922,17 +20923,17 @@ async function deployStorageStack(config2) {
|
|
|
20922
20923
|
distributionId: cdnResources?.distributionId,
|
|
20923
20924
|
distributionDomain: cdnResources?.domainName,
|
|
20924
20925
|
// Report custom domain if it's actually configured on CloudFront (auto or manual validation)
|
|
20925
|
-
customDomain: customDomainActive ? config2.
|
|
20926
|
+
customDomain: customDomainActive ? config2.cdnConfig.cdn.customDomain : void 0,
|
|
20926
20927
|
// Report pending custom domain that needs manual cert validation
|
|
20927
|
-
customDomainPending: customDomainPending ? config2.
|
|
20928
|
+
customDomainPending: customDomainPending ? config2.cdnConfig.cdn.customDomain : void 0,
|
|
20928
20929
|
acmCertificateArn: acmResources?.certificate.arn,
|
|
20929
20930
|
acmCertificateValidationRecords: acmResources?.validationRecords,
|
|
20930
|
-
versioning: config2.
|
|
20931
|
-
retention: config2.
|
|
20931
|
+
versioning: config2.cdnConfig.versioning ?? false,
|
|
20932
|
+
retention: config2.cdnConfig.retention
|
|
20932
20933
|
};
|
|
20933
20934
|
}
|
|
20934
20935
|
|
|
20935
|
-
// src/commands/
|
|
20936
|
+
// src/commands/cdn/init.ts
|
|
20936
20937
|
init_events();
|
|
20937
20938
|
init_aws();
|
|
20938
20939
|
init_errors();
|
|
@@ -20940,7 +20941,7 @@ init_fs();
|
|
|
20940
20941
|
init_metadata();
|
|
20941
20942
|
init_prompts();
|
|
20942
20943
|
|
|
20943
|
-
// src/utils/
|
|
20944
|
+
// src/utils/cdn/costs.ts
|
|
20944
20945
|
init_esm_shims();
|
|
20945
20946
|
var PRICING = {
|
|
20946
20947
|
// S3 Storage (per GB/month)
|
|
@@ -21026,7 +21027,7 @@ function getCostSummary2(config2, estimatedStorageGB = 10, estimatedBandwidthGB
|
|
|
21026
21027
|
return lines.join("\n");
|
|
21027
21028
|
}
|
|
21028
21029
|
|
|
21029
|
-
// src/utils/
|
|
21030
|
+
// src/utils/cdn/presets.ts
|
|
21030
21031
|
init_esm_shims();
|
|
21031
21032
|
var STARTER_PRESET2 = {
|
|
21032
21033
|
cdn: {
|
|
@@ -21141,13 +21142,13 @@ function validateConfig2(config2) {
|
|
|
21141
21142
|
return warnings;
|
|
21142
21143
|
}
|
|
21143
21144
|
|
|
21144
|
-
// src/commands/
|
|
21145
|
-
async function
|
|
21145
|
+
// src/commands/cdn/init.ts
|
|
21146
|
+
async function promptCdnPreset() {
|
|
21146
21147
|
const starterInfo = getPresetInfo2("starter");
|
|
21147
21148
|
const productionInfo = getPresetInfo2("production");
|
|
21148
21149
|
const customInfo = getPresetInfo2("custom");
|
|
21149
21150
|
const result = await clack29.select({
|
|
21150
|
-
message: "Select a
|
|
21151
|
+
message: "Select a CDN configuration preset:",
|
|
21151
21152
|
options: [
|
|
21152
21153
|
{
|
|
21153
21154
|
value: "production",
|
|
@@ -21172,7 +21173,7 @@ async function promptStoragePreset() {
|
|
|
21172
21173
|
}
|
|
21173
21174
|
return result;
|
|
21174
21175
|
}
|
|
21175
|
-
async function
|
|
21176
|
+
async function promptCustomCdnConfig() {
|
|
21176
21177
|
const cdnEnabled = await clack29.confirm({
|
|
21177
21178
|
message: "Enable CloudFront CDN for fast global delivery?",
|
|
21178
21179
|
initialValue: true
|
|
@@ -21367,7 +21368,7 @@ async function init3(options) {
|
|
|
21367
21368
|
const startTime = Date.now();
|
|
21368
21369
|
clack29.intro(
|
|
21369
21370
|
pc31.bold(
|
|
21370
|
-
options.preview ? "Wraps
|
|
21371
|
+
options.preview ? "Wraps CDN Infrastructure Preview" : "Wraps CDN Infrastructure Setup"
|
|
21371
21372
|
)
|
|
21372
21373
|
);
|
|
21373
21374
|
const progress = new DeploymentProgress();
|
|
@@ -21400,45 +21401,45 @@ async function init3(options) {
|
|
|
21400
21401
|
identity.accountId,
|
|
21401
21402
|
region
|
|
21402
21403
|
);
|
|
21403
|
-
if (existingConnection && hasService(existingConnection, "
|
|
21404
|
+
if (existingConnection && hasService(existingConnection, "cdn")) {
|
|
21404
21405
|
clack29.log.warn(
|
|
21405
|
-
`
|
|
21406
|
+
`CDN service already exists for account ${pc31.cyan(identity.accountId)} in region ${pc31.cyan(region)}`
|
|
21406
21407
|
);
|
|
21407
21408
|
clack29.log.info(
|
|
21408
|
-
`Created: ${existingConnection.services.
|
|
21409
|
+
`Created: ${existingConnection.services.cdn?.deployedAt}`
|
|
21409
21410
|
);
|
|
21410
21411
|
clack29.log.info(
|
|
21411
|
-
`Use ${pc31.cyan("wraps
|
|
21412
|
+
`Use ${pc31.cyan("wraps cdn status")} to view current setup`
|
|
21412
21413
|
);
|
|
21413
21414
|
process.exit(0);
|
|
21414
21415
|
}
|
|
21415
21416
|
let preset = options.preset;
|
|
21416
21417
|
if (!preset) {
|
|
21417
|
-
preset = await
|
|
21418
|
+
preset = await promptCdnPreset();
|
|
21418
21419
|
}
|
|
21419
|
-
let
|
|
21420
|
+
let cdnConfig;
|
|
21420
21421
|
if (preset === "custom") {
|
|
21421
|
-
|
|
21422
|
+
cdnConfig = await promptCustomCdnConfig();
|
|
21422
21423
|
} else {
|
|
21423
|
-
|
|
21424
|
+
cdnConfig = getPreset2(preset);
|
|
21424
21425
|
}
|
|
21425
21426
|
let customDomain = options.domain;
|
|
21426
|
-
if (!customDomain &&
|
|
21427
|
+
if (!customDomain && cdnConfig.cdn.enabled) {
|
|
21427
21428
|
customDomain = await promptCustomDomain();
|
|
21428
21429
|
}
|
|
21429
21430
|
if (customDomain) {
|
|
21430
|
-
|
|
21431
|
+
cdnConfig.cdn.customDomain = customDomain;
|
|
21431
21432
|
}
|
|
21432
21433
|
const estimatedUsage = await promptEstimatedUsage();
|
|
21433
21434
|
progress.info(`
|
|
21434
21435
|
${pc31.bold("Cost Estimate:")}`);
|
|
21435
21436
|
const costSummary = getCostSummary2(
|
|
21436
|
-
|
|
21437
|
+
cdnConfig,
|
|
21437
21438
|
estimatedUsage.storageGB,
|
|
21438
21439
|
estimatedUsage.bandwidthGB
|
|
21439
21440
|
);
|
|
21440
21441
|
clack29.log.info(costSummary);
|
|
21441
|
-
const warnings = validateConfig2(
|
|
21442
|
+
const warnings = validateConfig2(cdnConfig);
|
|
21442
21443
|
if (warnings.length > 0) {
|
|
21443
21444
|
progress.info(`
|
|
21444
21445
|
${pc31.yellow(pc31.bold("Configuration Notes:"))}`);
|
|
@@ -21450,8 +21451,8 @@ ${pc31.yellow(pc31.bold("Configuration Notes:"))}`);
|
|
|
21450
21451
|
identity.accountId,
|
|
21451
21452
|
region,
|
|
21452
21453
|
provider,
|
|
21453
|
-
"
|
|
21454
|
-
|
|
21454
|
+
"cdn",
|
|
21455
|
+
cdnConfig,
|
|
21455
21456
|
preset === "custom" ? void 0 : preset,
|
|
21456
21457
|
existingConnection || void 0
|
|
21457
21458
|
);
|
|
@@ -21470,7 +21471,7 @@ ${pc31.yellow(pc31.bold("Configuration Notes:"))}`);
|
|
|
21470
21471
|
region,
|
|
21471
21472
|
accountId: identity.accountId,
|
|
21472
21473
|
vercel: vercelConfig,
|
|
21473
|
-
|
|
21474
|
+
cdnConfig
|
|
21474
21475
|
};
|
|
21475
21476
|
if (options.preview) {
|
|
21476
21477
|
try {
|
|
@@ -21480,10 +21481,10 @@ ${pc31.yellow(pc31.bold("Configuration Notes:"))}`);
|
|
|
21480
21481
|
await ensurePulumiWorkDir();
|
|
21481
21482
|
const stack = await pulumi23.automation.LocalWorkspace.createOrSelectStack(
|
|
21482
21483
|
{
|
|
21483
|
-
stackName: `wraps-
|
|
21484
|
-
projectName: "wraps-
|
|
21484
|
+
stackName: `wraps-cdn-${identity.accountId}-${region}`,
|
|
21485
|
+
projectName: "wraps-cdn",
|
|
21485
21486
|
program: async () => {
|
|
21486
|
-
const result2 = await
|
|
21487
|
+
const result2 = await deployCdnStack(stackConfig);
|
|
21487
21488
|
return {
|
|
21488
21489
|
roleArn: result2.roleArn,
|
|
21489
21490
|
bucketName: result2.bucketName,
|
|
@@ -21515,12 +21516,12 @@ ${pc31.yellow(pc31.bold("Configuration Notes:"))}`);
|
|
|
21515
21516
|
changeSummary: previewResult.changeSummary,
|
|
21516
21517
|
resourceChanges: previewResult.resourceChanges,
|
|
21517
21518
|
costEstimate: costSummary,
|
|
21518
|
-
commandName: "wraps
|
|
21519
|
+
commandName: "wraps cdn init"
|
|
21519
21520
|
});
|
|
21520
21521
|
clack29.outro(
|
|
21521
21522
|
pc31.green("Preview complete. Run without --preview to deploy.")
|
|
21522
21523
|
);
|
|
21523
|
-
trackServiceInit("
|
|
21524
|
+
trackServiceInit("cdn", true, {
|
|
21524
21525
|
preset,
|
|
21525
21526
|
provider,
|
|
21526
21527
|
region,
|
|
@@ -21539,15 +21540,15 @@ ${pc31.yellow(pc31.bold("Configuration Notes:"))}`);
|
|
|
21539
21540
|
let outputs;
|
|
21540
21541
|
try {
|
|
21541
21542
|
outputs = await progress.execute(
|
|
21542
|
-
"Deploying
|
|
21543
|
+
"Deploying CDN infrastructure (this may take 2-3 minutes)",
|
|
21543
21544
|
async () => {
|
|
21544
21545
|
await ensurePulumiWorkDir();
|
|
21545
21546
|
const stack = await pulumi23.automation.LocalWorkspace.createOrSelectStack(
|
|
21546
21547
|
{
|
|
21547
|
-
stackName: `wraps-
|
|
21548
|
-
projectName: "wraps-
|
|
21548
|
+
stackName: `wraps-cdn-${identity.accountId}-${region}`,
|
|
21549
|
+
projectName: "wraps-cdn",
|
|
21549
21550
|
program: async () => {
|
|
21550
|
-
const result = await
|
|
21551
|
+
const result = await deployCdnStack(stackConfig);
|
|
21551
21552
|
return {
|
|
21552
21553
|
roleArn: result.roleArn,
|
|
21553
21554
|
bucketName: result.bucketName,
|
|
@@ -21574,7 +21575,7 @@ ${pc31.yellow(pc31.bold("Configuration Notes:"))}`);
|
|
|
21574
21575
|
}
|
|
21575
21576
|
);
|
|
21576
21577
|
await stack.workspace.selectStack(
|
|
21577
|
-
`wraps-
|
|
21578
|
+
`wraps-cdn-${identity.accountId}-${region}`
|
|
21578
21579
|
);
|
|
21579
21580
|
await stack.setConfig("aws:region", { value: region });
|
|
21580
21581
|
const upResult = await stack.up({ onOutput: () => {
|
|
@@ -21597,7 +21598,7 @@ ${pc31.yellow(pc31.bold("Configuration Notes:"))}`);
|
|
|
21597
21598
|
}
|
|
21598
21599
|
);
|
|
21599
21600
|
} catch (error) {
|
|
21600
|
-
trackServiceInit("
|
|
21601
|
+
trackServiceInit("cdn", false, {
|
|
21601
21602
|
preset,
|
|
21602
21603
|
provider,
|
|
21603
21604
|
region,
|
|
@@ -21610,8 +21611,8 @@ ${pc31.yellow(pc31.bold("Configuration Notes:"))}`);
|
|
|
21610
21611
|
trackError("DEPLOYMENT_FAILED", "storage:init", { step: "deploy" });
|
|
21611
21612
|
throw new Error(`Pulumi deployment failed: ${error.message}`);
|
|
21612
21613
|
}
|
|
21613
|
-
if (metadata.services.
|
|
21614
|
-
metadata.services.
|
|
21614
|
+
if (metadata.services.cdn) {
|
|
21615
|
+
metadata.services.cdn.pulumiStackName = `wraps-cdn-${identity.accountId}-${region}`;
|
|
21615
21616
|
}
|
|
21616
21617
|
await saveConnectionMetadata(metadata);
|
|
21617
21618
|
progress.info("Connection metadata saved");
|
|
@@ -21649,12 +21650,12 @@ ${pc31.yellow(pc31.bold("Configuration Notes:"))}`);
|
|
|
21649
21650
|
);
|
|
21650
21651
|
const dnsRecords = [];
|
|
21651
21652
|
const existingValue = existingCname?.ResourceRecords?.[0]?.Value || null;
|
|
21652
|
-
let
|
|
21653
|
+
let cdnStatus2 = "new";
|
|
21653
21654
|
let cdnConflictReason;
|
|
21654
21655
|
if (existingValue === outputs.distributionDomain) {
|
|
21655
|
-
|
|
21656
|
+
cdnStatus2 = "no_change";
|
|
21656
21657
|
} else if (existingValue) {
|
|
21657
|
-
|
|
21658
|
+
cdnStatus2 = "conflict";
|
|
21658
21659
|
cdnConflictReason = `Currently points to ${existingValue}`;
|
|
21659
21660
|
}
|
|
21660
21661
|
dnsRecords.push({
|
|
@@ -21662,7 +21663,7 @@ ${pc31.yellow(pc31.bold("Configuration Notes:"))}`);
|
|
|
21662
21663
|
type: "CNAME",
|
|
21663
21664
|
proposedValue: outputs.distributionDomain,
|
|
21664
21665
|
existingValue,
|
|
21665
|
-
status:
|
|
21666
|
+
status: cdnStatus2,
|
|
21666
21667
|
conflictReason: cdnConflictReason
|
|
21667
21668
|
});
|
|
21668
21669
|
console.log();
|
|
@@ -21742,7 +21743,7 @@ ${pc31.yellow(pc31.bold("Configuration Notes:"))}`);
|
|
|
21742
21743
|
}
|
|
21743
21744
|
}
|
|
21744
21745
|
}
|
|
21745
|
-
|
|
21746
|
+
displayCdnSuccess({
|
|
21746
21747
|
bucketName: outputs.bucketName,
|
|
21747
21748
|
region: outputs.region,
|
|
21748
21749
|
distributionDomain: outputs.distributionDomain,
|
|
@@ -21757,31 +21758,31 @@ ${pc31.yellow(pc31.bold("Configuration Notes:"))}`);
|
|
|
21757
21758
|
});
|
|
21758
21759
|
const duration = Date.now() - startTime;
|
|
21759
21760
|
const enabledFeatures = [];
|
|
21760
|
-
if (
|
|
21761
|
+
if (cdnConfig.cdn.enabled) {
|
|
21761
21762
|
enabledFeatures.push("cdn");
|
|
21762
21763
|
}
|
|
21763
|
-
if (
|
|
21764
|
+
if (cdnConfig.cdn.customDomain) {
|
|
21764
21765
|
enabledFeatures.push("custom_domain");
|
|
21765
21766
|
}
|
|
21766
|
-
if (
|
|
21767
|
+
if (cdnConfig.versioning) {
|
|
21767
21768
|
enabledFeatures.push("versioning");
|
|
21768
21769
|
}
|
|
21769
|
-
trackServiceInit("
|
|
21770
|
+
trackServiceInit("cdn", true, {
|
|
21770
21771
|
preset,
|
|
21771
21772
|
provider,
|
|
21772
21773
|
region,
|
|
21773
21774
|
features: enabledFeatures,
|
|
21774
21775
|
duration_ms: duration
|
|
21775
21776
|
});
|
|
21776
|
-
trackServiceDeployed("
|
|
21777
|
+
trackServiceDeployed("cdn", {
|
|
21777
21778
|
duration_ms: duration,
|
|
21778
21779
|
region,
|
|
21779
21780
|
features: enabledFeatures,
|
|
21780
21781
|
preset
|
|
21781
21782
|
});
|
|
21782
21783
|
}
|
|
21783
|
-
function
|
|
21784
|
-
clack29.log.success(pc31.green(pc31.bold("
|
|
21784
|
+
function displayCdnSuccess(options) {
|
|
21785
|
+
clack29.log.success(pc31.green(pc31.bold("CDN infrastructure deployed!")));
|
|
21785
21786
|
clack29.log.info(`
|
|
21786
21787
|
${pc31.bold("Infrastructure:")}`);
|
|
21787
21788
|
clack29.log.info(` S3 Bucket: ${pc31.cyan(options.bucketName)}`);
|
|
@@ -21821,7 +21822,7 @@ ${pc31.yellow(pc31.bold("DNS Records Required:"))}`);
|
|
|
21821
21822
|
`);
|
|
21822
21823
|
}
|
|
21823
21824
|
clack29.log.warn(
|
|
21824
|
-
"Custom domain requires manual setup:\n 1. Add the SSL certificate validation DNS record above\n 2. Wait for certificate to be validated (check AWS ACM console)\n 3. Run 'wraps
|
|
21825
|
+
"Custom domain requires manual setup:\n 1. Add the SSL certificate validation DNS record above\n 2. Wait for certificate to be validated (check AWS ACM console)\n 3. Run 'wraps cdn upgrade' to add custom domain to CloudFront\n 4. Add the CDN CNAME record to point your domain to CloudFront"
|
|
21825
21826
|
);
|
|
21826
21827
|
} else if (options.customDomain && !options.dnsAutoCreated && options.distributionDomain) {
|
|
21827
21828
|
clack29.log.info(`
|
|
@@ -21835,19 +21836,19 @@ ${pc31.yellow(pc31.bold("DNS Record Required:"))}`);
|
|
|
21835
21836
|
clack29.log.info(`
|
|
21836
21837
|
${pc31.bold("Next Steps:")}`);
|
|
21837
21838
|
clack29.log.info(
|
|
21838
|
-
` 1. ${pc31.cyan("wraps
|
|
21839
|
+
` 1. ${pc31.cyan("wraps cdn status")} - View your CDN setup`
|
|
21839
21840
|
);
|
|
21840
21841
|
if (options.customDomainPending) {
|
|
21841
21842
|
clack29.log.info(" 2. Add DNS records above and validate SSL certificate");
|
|
21842
21843
|
clack29.log.info(
|
|
21843
|
-
` 3. ${pc31.cyan("wraps
|
|
21844
|
+
` 3. ${pc31.cyan("wraps cdn upgrade")} - Add custom domain to CloudFront`
|
|
21844
21845
|
);
|
|
21845
21846
|
} else if (options.customDomain && !options.dnsAutoCreated) {
|
|
21846
21847
|
clack29.log.info(
|
|
21847
21848
|
" 2. Add DNS record above to point your domain to CloudFront"
|
|
21848
21849
|
);
|
|
21849
21850
|
clack29.log.info(
|
|
21850
|
-
` 3. ${pc31.cyan("wraps
|
|
21851
|
+
` 3. ${pc31.cyan("wraps cdn verify")} - Check DNS propagation`
|
|
21851
21852
|
);
|
|
21852
21853
|
}
|
|
21853
21854
|
const cdnUrl = options.customDomain ? `https://${options.customDomain}` : options.distributionDomain ? `https://${options.distributionDomain}` : null;
|
|
@@ -21859,15 +21860,15 @@ ${pc31.bold("CDN URL:")}`);
|
|
|
21859
21860
|
if (options.customDomainPending) {
|
|
21860
21861
|
clack29.outro(
|
|
21861
21862
|
pc31.yellow(
|
|
21862
|
-
"
|
|
21863
|
+
"CDN deployed! Custom domain pending certificate validation."
|
|
21863
21864
|
)
|
|
21864
21865
|
);
|
|
21865
21866
|
} else {
|
|
21866
|
-
clack29.outro(pc31.green("
|
|
21867
|
+
clack29.outro(pc31.green("CDN is ready!"));
|
|
21867
21868
|
}
|
|
21868
21869
|
}
|
|
21869
21870
|
|
|
21870
|
-
// src/commands/
|
|
21871
|
+
// src/commands/cdn/status.ts
|
|
21871
21872
|
init_esm_shims();
|
|
21872
21873
|
init_client();
|
|
21873
21874
|
init_events();
|
|
@@ -21877,26 +21878,26 @@ init_metadata();
|
|
|
21877
21878
|
import * as clack30 from "@clack/prompts";
|
|
21878
21879
|
import * as pulumi24 from "@pulumi/pulumi";
|
|
21879
21880
|
import pc32 from "picocolors";
|
|
21880
|
-
async function
|
|
21881
|
+
async function cdnStatus(options) {
|
|
21881
21882
|
const startTime = Date.now();
|
|
21882
21883
|
const progress = new DeploymentProgress();
|
|
21883
|
-
clack30.intro(pc32.bold("Wraps
|
|
21884
|
+
clack30.intro(pc32.bold("Wraps CDN Status"));
|
|
21884
21885
|
const identity = await progress.execute(
|
|
21885
|
-
"Loading
|
|
21886
|
+
"Loading CDN infrastructure status",
|
|
21886
21887
|
async () => validateAWSCredentials()
|
|
21887
21888
|
);
|
|
21888
21889
|
let region = options.region || await getAWSRegion();
|
|
21889
21890
|
if (!(options.region || process.env.AWS_REGION || process.env.AWS_DEFAULT_REGION)) {
|
|
21890
|
-
const
|
|
21891
|
+
const cdnConnections = await findConnectionsWithService(
|
|
21891
21892
|
identity.accountId,
|
|
21892
|
-
"
|
|
21893
|
+
"cdn"
|
|
21893
21894
|
);
|
|
21894
|
-
if (
|
|
21895
|
-
region =
|
|
21896
|
-
} else if (
|
|
21895
|
+
if (cdnConnections.length === 1) {
|
|
21896
|
+
region = cdnConnections[0].region;
|
|
21897
|
+
} else if (cdnConnections.length > 1) {
|
|
21897
21898
|
const selectedRegion = await clack30.select({
|
|
21898
|
-
message: "Multiple
|
|
21899
|
-
options:
|
|
21899
|
+
message: "Multiple CDN deployments found. Which region?",
|
|
21900
|
+
options: cdnConnections.map((conn) => ({
|
|
21900
21901
|
value: conn.region,
|
|
21901
21902
|
label: conn.region
|
|
21902
21903
|
}))
|
|
@@ -21912,22 +21913,22 @@ async function storageStatus(options) {
|
|
|
21912
21913
|
try {
|
|
21913
21914
|
await ensurePulumiWorkDir();
|
|
21914
21915
|
const stack = await pulumi24.automation.LocalWorkspace.selectStack({
|
|
21915
|
-
stackName: `wraps-
|
|
21916
|
+
stackName: `wraps-cdn-${identity.accountId}-${region}`,
|
|
21916
21917
|
workDir: getPulumiWorkDir()
|
|
21917
21918
|
});
|
|
21918
21919
|
stackOutputs = await stack.outputs();
|
|
21919
21920
|
} catch (_error) {
|
|
21920
21921
|
progress.stop();
|
|
21921
|
-
clack30.log.error("No
|
|
21922
|
+
clack30.log.error("No CDN infrastructure found");
|
|
21922
21923
|
console.log(
|
|
21923
21924
|
`
|
|
21924
|
-
Run ${pc32.cyan("wraps
|
|
21925
|
+
Run ${pc32.cyan("wraps cdn init")} to deploy CDN infrastructure.
|
|
21925
21926
|
`
|
|
21926
21927
|
);
|
|
21927
21928
|
process.exit(1);
|
|
21928
21929
|
}
|
|
21929
21930
|
progress.stop();
|
|
21930
|
-
|
|
21931
|
+
displayCdnStatus({
|
|
21931
21932
|
bucketName: stackOutputs.bucketName?.value,
|
|
21932
21933
|
region: stackOutputs.region?.value || region,
|
|
21933
21934
|
distributionId: stackOutputs.distributionId?.value,
|
|
@@ -21949,9 +21950,9 @@ Run ${pc32.cyan("wraps storage init")} to deploy storage infrastructure.
|
|
|
21949
21950
|
});
|
|
21950
21951
|
getTelemetryClient().showFooterOnce();
|
|
21951
21952
|
}
|
|
21952
|
-
function
|
|
21953
|
+
function displayCdnStatus(options) {
|
|
21953
21954
|
clack30.log.info(`
|
|
21954
|
-
${pc32.bold("
|
|
21955
|
+
${pc32.bold("CDN Infrastructure:")}`);
|
|
21955
21956
|
clack30.log.info(` S3 Bucket: ${pc32.cyan(options.bucketName)}`);
|
|
21956
21957
|
clack30.log.info(` Region: ${pc32.cyan(options.region)}`);
|
|
21957
21958
|
clack30.log.info(
|
|
@@ -22018,19 +22019,19 @@ ${pc32.bold("File URLs:")}`);
|
|
|
22018
22019
|
${pc32.bold("Commands:")}`);
|
|
22019
22020
|
if (hasPendingCert) {
|
|
22020
22021
|
clack30.log.info(
|
|
22021
|
-
` ${pc32.cyan("wraps
|
|
22022
|
+
` ${pc32.cyan("wraps cdn upgrade")} - Add custom domain after cert validation`
|
|
22022
22023
|
);
|
|
22023
22024
|
}
|
|
22024
22025
|
clack30.log.info(
|
|
22025
|
-
` ${pc32.cyan("wraps
|
|
22026
|
+
` ${pc32.cyan("wraps cdn verify")} - Check DNS and certificate status`
|
|
22026
22027
|
);
|
|
22027
22028
|
clack30.log.info(
|
|
22028
|
-
` ${pc32.cyan("wraps
|
|
22029
|
+
` ${pc32.cyan("wraps cdn destroy")} - Remove CDN infrastructure`
|
|
22029
22030
|
);
|
|
22030
22031
|
clack30.outro("");
|
|
22031
22032
|
}
|
|
22032
22033
|
|
|
22033
|
-
// src/commands/
|
|
22034
|
+
// src/commands/cdn/sync.ts
|
|
22034
22035
|
init_esm_shims();
|
|
22035
22036
|
import * as clack31 from "@clack/prompts";
|
|
22036
22037
|
import * as pulumi25 from "@pulumi/pulumi";
|
|
@@ -22040,26 +22041,26 @@ init_events();
|
|
|
22040
22041
|
init_aws();
|
|
22041
22042
|
init_fs();
|
|
22042
22043
|
init_metadata();
|
|
22043
|
-
async function
|
|
22044
|
+
async function cdnSync(options) {
|
|
22044
22045
|
const startTime = Date.now();
|
|
22045
22046
|
const progress = new DeploymentProgress();
|
|
22046
|
-
clack31.intro(pc33.bold("Wraps
|
|
22047
|
+
clack31.intro(pc33.bold("Wraps CDN Sync"));
|
|
22047
22048
|
const identity = await progress.execute(
|
|
22048
22049
|
"Validating AWS credentials",
|
|
22049
22050
|
async () => validateAWSCredentials()
|
|
22050
22051
|
);
|
|
22051
22052
|
let region = options.region || await getAWSRegion();
|
|
22052
22053
|
if (!(options.region || process.env.AWS_REGION || process.env.AWS_DEFAULT_REGION)) {
|
|
22053
|
-
const
|
|
22054
|
+
const cdnConnections = await findConnectionsWithService(
|
|
22054
22055
|
identity.accountId,
|
|
22055
|
-
"
|
|
22056
|
+
"cdn"
|
|
22056
22057
|
);
|
|
22057
|
-
if (
|
|
22058
|
-
region =
|
|
22059
|
-
} else if (
|
|
22058
|
+
if (cdnConnections.length === 1) {
|
|
22059
|
+
region = cdnConnections[0].region;
|
|
22060
|
+
} else if (cdnConnections.length > 1) {
|
|
22060
22061
|
const selectedRegion = await clack31.select({
|
|
22061
|
-
message: "Multiple
|
|
22062
|
-
options:
|
|
22062
|
+
message: "Multiple CDN deployments found. Which region?",
|
|
22063
|
+
options: cdnConnections.map((conn) => ({
|
|
22063
22064
|
value: conn.region,
|
|
22064
22065
|
label: conn.region
|
|
22065
22066
|
}))
|
|
@@ -22072,25 +22073,25 @@ async function storageSync(options) {
|
|
|
22072
22073
|
}
|
|
22073
22074
|
}
|
|
22074
22075
|
const metadata = await loadConnectionMetadata(identity.accountId, region);
|
|
22075
|
-
if (!metadata?.services.
|
|
22076
|
+
if (!metadata?.services.cdn) {
|
|
22076
22077
|
clack31.log.error(
|
|
22077
|
-
`No
|
|
22078
|
+
`No CDN infrastructure found for account ${pc33.cyan(identity.accountId)} in region ${pc33.cyan(region)}`
|
|
22078
22079
|
);
|
|
22079
22080
|
clack31.log.info(
|
|
22080
|
-
`Use ${pc33.cyan("wraps
|
|
22081
|
+
`Use ${pc33.cyan("wraps cdn init")} to deploy CDN infrastructure.`
|
|
22081
22082
|
);
|
|
22082
22083
|
process.exit(1);
|
|
22083
22084
|
}
|
|
22084
|
-
const
|
|
22085
|
-
const
|
|
22085
|
+
const cdnService = metadata.services.cdn;
|
|
22086
|
+
const cdnConfig = cdnService.config;
|
|
22086
22087
|
progress.info(`Found storage deployment in ${pc33.cyan(region)}`);
|
|
22087
22088
|
let certValidated = false;
|
|
22088
22089
|
let existingCertArn;
|
|
22089
|
-
if (
|
|
22090
|
+
if (cdnConfig.cdn.customDomain) {
|
|
22090
22091
|
try {
|
|
22091
22092
|
await ensurePulumiWorkDir();
|
|
22092
22093
|
const checkStack = await pulumi25.automation.LocalWorkspace.selectStack({
|
|
22093
|
-
stackName: `wraps-
|
|
22094
|
+
stackName: `wraps-cdn-${identity.accountId}-${region}`,
|
|
22094
22095
|
workDir: getPulumiWorkDir()
|
|
22095
22096
|
});
|
|
22096
22097
|
const stackOutputs = await checkStack.outputs();
|
|
@@ -22106,7 +22107,7 @@ async function storageSync(options) {
|
|
|
22106
22107
|
certValidated = true;
|
|
22107
22108
|
existingCertArn = stackOutputs.acmCertificateArn.value;
|
|
22108
22109
|
progress.info(
|
|
22109
|
-
`Certificate validated for ${pc33.cyan(
|
|
22110
|
+
`Certificate validated for ${pc33.cyan(cdnConfig.cdn.customDomain)}`
|
|
22110
22111
|
);
|
|
22111
22112
|
}
|
|
22112
22113
|
}
|
|
@@ -22118,20 +22119,20 @@ async function storageSync(options) {
|
|
|
22118
22119
|
region,
|
|
22119
22120
|
accountId: identity.accountId,
|
|
22120
22121
|
vercel: metadata.vercel,
|
|
22121
|
-
|
|
22122
|
+
cdnConfig,
|
|
22122
22123
|
// Pass cert validation flags if cert is validated externally
|
|
22123
22124
|
certValidated,
|
|
22124
22125
|
existingCertArn
|
|
22125
22126
|
};
|
|
22126
22127
|
try {
|
|
22127
|
-
await progress.execute("Syncing
|
|
22128
|
+
await progress.execute("Syncing CDN infrastructure", async () => {
|
|
22128
22129
|
await ensurePulumiWorkDir();
|
|
22129
22130
|
const stack = await pulumi25.automation.LocalWorkspace.createOrSelectStack(
|
|
22130
22131
|
{
|
|
22131
|
-
stackName: `wraps-
|
|
22132
|
-
projectName: "wraps-
|
|
22132
|
+
stackName: `wraps-cdn-${identity.accountId}-${region}`,
|
|
22133
|
+
projectName: "wraps-cdn",
|
|
22133
22134
|
program: async () => {
|
|
22134
|
-
const result2 = await
|
|
22135
|
+
const result2 = await deployCdnStack(stackConfig);
|
|
22135
22136
|
return {
|
|
22136
22137
|
roleArn: result2.roleArn,
|
|
22137
22138
|
bucketName: result2.bucketName,
|
|
@@ -22174,7 +22175,7 @@ async function storageSync(options) {
|
|
|
22174
22175
|
clack31.log.error(`Sync failed: ${error.message}`);
|
|
22175
22176
|
process.exit(1);
|
|
22176
22177
|
}
|
|
22177
|
-
clack31.log.success(pc33.green("
|
|
22178
|
+
clack31.log.success(pc33.green("CDN infrastructure synced!"));
|
|
22178
22179
|
trackCommand("storage:sync", {
|
|
22179
22180
|
success: true,
|
|
22180
22181
|
region,
|
|
@@ -22184,7 +22185,7 @@ async function storageSync(options) {
|
|
|
22184
22185
|
clack31.outro("");
|
|
22185
22186
|
}
|
|
22186
22187
|
|
|
22187
|
-
// src/commands/
|
|
22188
|
+
// src/commands/cdn/upgrade.ts
|
|
22188
22189
|
init_esm_shims();
|
|
22189
22190
|
import * as clack32 from "@clack/prompts";
|
|
22190
22191
|
import * as pulumi26 from "@pulumi/pulumi";
|
|
@@ -22194,12 +22195,12 @@ init_events();
|
|
|
22194
22195
|
init_aws();
|
|
22195
22196
|
init_fs();
|
|
22196
22197
|
init_metadata();
|
|
22197
|
-
async function
|
|
22198
|
+
async function cdnUpgrade(options) {
|
|
22198
22199
|
const startTime = Date.now();
|
|
22199
22200
|
const progress = new DeploymentProgress();
|
|
22200
22201
|
clack32.intro(
|
|
22201
22202
|
pc34.bold(
|
|
22202
|
-
options.preview ? "Wraps
|
|
22203
|
+
options.preview ? "Wraps CDN Upgrade Preview" : "Wraps CDN Upgrade"
|
|
22203
22204
|
)
|
|
22204
22205
|
);
|
|
22205
22206
|
const identity = await progress.execute(
|
|
@@ -22209,16 +22210,16 @@ async function storageUpgrade(options) {
|
|
|
22209
22210
|
progress.info(`Connected to AWS account: ${pc34.cyan(identity.accountId)}`);
|
|
22210
22211
|
let region = options.region || await getAWSRegion();
|
|
22211
22212
|
if (!(options.region || process.env.AWS_REGION || process.env.AWS_DEFAULT_REGION)) {
|
|
22212
|
-
const
|
|
22213
|
+
const cdnConnections = await findConnectionsWithService(
|
|
22213
22214
|
identity.accountId,
|
|
22214
|
-
"
|
|
22215
|
+
"cdn"
|
|
22215
22216
|
);
|
|
22216
|
-
if (
|
|
22217
|
-
region =
|
|
22218
|
-
} else if (
|
|
22217
|
+
if (cdnConnections.length === 1) {
|
|
22218
|
+
region = cdnConnections[0].region;
|
|
22219
|
+
} else if (cdnConnections.length > 1) {
|
|
22219
22220
|
const selectedRegion = await clack32.select({
|
|
22220
|
-
message: "Multiple
|
|
22221
|
-
options:
|
|
22221
|
+
message: "Multiple CDN deployments found. Which region?",
|
|
22222
|
+
options: cdnConnections.map((conn) => ({
|
|
22222
22223
|
value: conn.region,
|
|
22223
22224
|
label: conn.region
|
|
22224
22225
|
}))
|
|
@@ -22231,22 +22232,22 @@ async function storageUpgrade(options) {
|
|
|
22231
22232
|
}
|
|
22232
22233
|
}
|
|
22233
22234
|
const metadata = await loadConnectionMetadata(identity.accountId, region);
|
|
22234
|
-
if (!metadata?.services.
|
|
22235
|
+
if (!metadata?.services.cdn) {
|
|
22235
22236
|
clack32.log.error(
|
|
22236
|
-
`No
|
|
22237
|
+
`No CDN infrastructure found for account ${pc34.cyan(identity.accountId)} in region ${pc34.cyan(region)}`
|
|
22237
22238
|
);
|
|
22238
22239
|
clack32.log.info(
|
|
22239
|
-
`Use ${pc34.cyan("wraps
|
|
22240
|
+
`Use ${pc34.cyan("wraps cdn init")} to deploy CDN infrastructure.`
|
|
22240
22241
|
);
|
|
22241
22242
|
process.exit(1);
|
|
22242
22243
|
}
|
|
22243
|
-
const
|
|
22244
|
-
const
|
|
22244
|
+
const cdnService = metadata.services.cdn;
|
|
22245
|
+
const cdnConfig = cdnService.config;
|
|
22245
22246
|
let stackOutputs = {};
|
|
22246
22247
|
try {
|
|
22247
22248
|
await ensurePulumiWorkDir();
|
|
22248
22249
|
const stack = await pulumi26.automation.LocalWorkspace.selectStack({
|
|
22249
|
-
stackName: `wraps-
|
|
22250
|
+
stackName: `wraps-cdn-${identity.accountId}-${region}`,
|
|
22250
22251
|
workDir: getPulumiWorkDir()
|
|
22251
22252
|
});
|
|
22252
22253
|
stackOutputs = await stack.outputs();
|
|
@@ -22255,7 +22256,7 @@ async function storageUpgrade(options) {
|
|
|
22255
22256
|
process.exit(1);
|
|
22256
22257
|
}
|
|
22257
22258
|
let cloudFrontHasCustomDomain = false;
|
|
22258
|
-
if (stackOutputs.distributionId?.value &&
|
|
22259
|
+
if (stackOutputs.distributionId?.value && cdnConfig.cdn?.customDomain) {
|
|
22259
22260
|
try {
|
|
22260
22261
|
const { CloudFrontClient, GetDistributionCommand } = await import("@aws-sdk/client-cloudfront");
|
|
22261
22262
|
const cfClient = new CloudFrontClient({ region: "us-east-1" });
|
|
@@ -22266,16 +22267,16 @@ async function storageUpgrade(options) {
|
|
|
22266
22267
|
);
|
|
22267
22268
|
const aliases = cfResponse.Distribution?.DistributionConfig?.Aliases?.Items || [];
|
|
22268
22269
|
cloudFrontHasCustomDomain = aliases.includes(
|
|
22269
|
-
|
|
22270
|
+
cdnConfig.cdn.customDomain
|
|
22270
22271
|
);
|
|
22271
22272
|
} catch {
|
|
22272
22273
|
}
|
|
22273
22274
|
}
|
|
22274
22275
|
const hasPendingCert = stackOutputs.acmCertificateArn?.value && !stackOutputs.customDomain?.value && !cloudFrontHasCustomDomain;
|
|
22275
22276
|
const pendingDomain = stackOutputs.customDomainPending?.value || (hasPendingCert && stackOutputs.acmCertificateValidationRecords?.value?.[0]?.name ? stackOutputs.acmCertificateValidationRecords.value[0].name.replace(/^_[^.]+\./, "").replace(/\.$/, "") : void 0);
|
|
22276
|
-
const activeCustomDomain = cloudFrontHasCustomDomain ?
|
|
22277
|
+
const activeCustomDomain = cloudFrontHasCustomDomain ? cdnConfig.cdn?.customDomain : stackOutputs.customDomain?.value;
|
|
22277
22278
|
if (!hasPendingCert) {
|
|
22278
|
-
clack32.log.info("No pending upgrades found for
|
|
22279
|
+
clack32.log.info("No pending upgrades found for CDN infrastructure.");
|
|
22279
22280
|
clack32.log.info(
|
|
22280
22281
|
`
|
|
22281
22282
|
Current configuration:
|
|
@@ -22322,7 +22323,7 @@ Pending domain: ${pc34.cyan(pendingDomain)}`);
|
|
|
22322
22323
|
clack32.log.info(
|
|
22323
22324
|
"After adding the DNS record, wait for validation (typically 5-30 minutes)."
|
|
22324
22325
|
);
|
|
22325
|
-
clack32.log.info(`Then run ${pc34.cyan("wraps
|
|
22326
|
+
clack32.log.info(`Then run ${pc34.cyan("wraps cdn upgrade")} again.
|
|
22326
22327
|
`);
|
|
22327
22328
|
process.exit(0);
|
|
22328
22329
|
}
|
|
@@ -22344,9 +22345,9 @@ Ready to add custom domain: ${pc34.cyan(pendingDomain)}`);
|
|
|
22344
22345
|
}
|
|
22345
22346
|
}
|
|
22346
22347
|
const updatedConfig = {
|
|
22347
|
-
...
|
|
22348
|
+
...cdnConfig,
|
|
22348
22349
|
cdn: {
|
|
22349
|
-
...
|
|
22350
|
+
...cdnConfig.cdn,
|
|
22350
22351
|
customDomain: pendingDomain
|
|
22351
22352
|
}
|
|
22352
22353
|
};
|
|
@@ -22355,8 +22356,8 @@ Ready to add custom domain: ${pc34.cyan(pendingDomain)}`);
|
|
|
22355
22356
|
region,
|
|
22356
22357
|
accountId: identity.accountId,
|
|
22357
22358
|
vercel: metadata.vercel,
|
|
22358
|
-
|
|
22359
|
-
// Tell
|
|
22359
|
+
cdnConfig: updatedConfig,
|
|
22360
|
+
// Tell deployCdnStack that the cert is validated externally (manual DNS)
|
|
22360
22361
|
certValidated: true,
|
|
22361
22362
|
existingCertArn: stackOutputs.acmCertificateArn.value
|
|
22362
22363
|
};
|
|
@@ -22386,10 +22387,10 @@ Ready to add custom domain: ${pc34.cyan(pendingDomain)}`);
|
|
|
22386
22387
|
await ensurePulumiWorkDir();
|
|
22387
22388
|
const stack = await pulumi26.automation.LocalWorkspace.createOrSelectStack(
|
|
22388
22389
|
{
|
|
22389
|
-
stackName: `wraps-
|
|
22390
|
-
projectName: "wraps-
|
|
22390
|
+
stackName: `wraps-cdn-${identity.accountId}-${region}`,
|
|
22391
|
+
projectName: "wraps-cdn",
|
|
22391
22392
|
program: async () => {
|
|
22392
|
-
const result = await
|
|
22393
|
+
const result = await deployCdnStack(stackConfig);
|
|
22393
22394
|
return {
|
|
22394
22395
|
roleArn: result.roleArn,
|
|
22395
22396
|
bucketName: result.bucketName,
|
|
@@ -22432,8 +22433,8 @@ Ready to add custom domain: ${pc34.cyan(pendingDomain)}`);
|
|
|
22432
22433
|
clack32.log.error(`Upgrade failed: ${error.message}`);
|
|
22433
22434
|
process.exit(1);
|
|
22434
22435
|
}
|
|
22435
|
-
if (metadata.services.
|
|
22436
|
-
metadata.services.
|
|
22436
|
+
if (metadata.services.cdn) {
|
|
22437
|
+
metadata.services.cdn.config = updatedConfig;
|
|
22437
22438
|
await saveConnectionMetadata(metadata);
|
|
22438
22439
|
}
|
|
22439
22440
|
clack32.log.success(`
|
|
@@ -22464,7 +22465,7 @@ ${pc34.green("")} ${pc34.bold("Upgrade complete!")}
|
|
|
22464
22465
|
clack32.outro("");
|
|
22465
22466
|
}
|
|
22466
22467
|
|
|
22467
|
-
// src/commands/
|
|
22468
|
+
// src/commands/cdn/verify.ts
|
|
22468
22469
|
init_esm_shims();
|
|
22469
22470
|
init_events();
|
|
22470
22471
|
init_aws();
|
|
@@ -22520,26 +22521,26 @@ async function checkDistributionStatus(distributionId, region) {
|
|
|
22520
22521
|
return { status: "ERROR", enabled: false, aliases: [] };
|
|
22521
22522
|
}
|
|
22522
22523
|
}
|
|
22523
|
-
async function
|
|
22524
|
+
async function cdnVerify(options) {
|
|
22524
22525
|
const startTime = Date.now();
|
|
22525
22526
|
const progress = new DeploymentProgress();
|
|
22526
|
-
clack33.intro(pc35.bold("Wraps
|
|
22527
|
+
clack33.intro(pc35.bold("Wraps CDN Verification"));
|
|
22527
22528
|
const identity = await progress.execute(
|
|
22528
|
-
"Loading
|
|
22529
|
+
"Loading CDN infrastructure",
|
|
22529
22530
|
async () => validateAWSCredentials()
|
|
22530
22531
|
);
|
|
22531
22532
|
let region = options.region || await getAWSRegion();
|
|
22532
22533
|
if (!(options.region || process.env.AWS_REGION || process.env.AWS_DEFAULT_REGION)) {
|
|
22533
|
-
const
|
|
22534
|
+
const cdnConnections = await findConnectionsWithService(
|
|
22534
22535
|
identity.accountId,
|
|
22535
|
-
"
|
|
22536
|
+
"cdn"
|
|
22536
22537
|
);
|
|
22537
|
-
if (
|
|
22538
|
-
region =
|
|
22539
|
-
} else if (
|
|
22538
|
+
if (cdnConnections.length === 1) {
|
|
22539
|
+
region = cdnConnections[0].region;
|
|
22540
|
+
} else if (cdnConnections.length > 1) {
|
|
22540
22541
|
const selectedRegion = await clack33.select({
|
|
22541
|
-
message: "Multiple
|
|
22542
|
-
options:
|
|
22542
|
+
message: "Multiple CDN deployments found. Which region?",
|
|
22543
|
+
options: cdnConnections.map((conn) => ({
|
|
22543
22544
|
value: conn.region,
|
|
22544
22545
|
label: conn.region
|
|
22545
22546
|
}))
|
|
@@ -22555,16 +22556,16 @@ async function storageVerify(options) {
|
|
|
22555
22556
|
try {
|
|
22556
22557
|
await ensurePulumiWorkDir();
|
|
22557
22558
|
const stack = await pulumi27.automation.LocalWorkspace.selectStack({
|
|
22558
|
-
stackName: `wraps-
|
|
22559
|
+
stackName: `wraps-cdn-${identity.accountId}-${region}`,
|
|
22559
22560
|
workDir: getPulumiWorkDir()
|
|
22560
22561
|
});
|
|
22561
22562
|
stackOutputs = await stack.outputs();
|
|
22562
22563
|
} catch (_error) {
|
|
22563
22564
|
progress.stop();
|
|
22564
|
-
clack33.log.error("No
|
|
22565
|
+
clack33.log.error("No CDN infrastructure found");
|
|
22565
22566
|
console.log(
|
|
22566
22567
|
`
|
|
22567
|
-
Run ${pc35.cyan("wraps
|
|
22568
|
+
Run ${pc35.cyan("wraps cdn init")} to deploy CDN infrastructure.
|
|
22568
22569
|
`
|
|
22569
22570
|
);
|
|
22570
22571
|
process.exit(1);
|
|
@@ -22647,7 +22648,7 @@ ${pc35.bold("Custom Domain DNS:")}`);
|
|
|
22647
22648
|
` ${pc35.yellow("!")} CloudFront alias not configured for ${targetDomain}`
|
|
22648
22649
|
);
|
|
22649
22650
|
clack33.log.info(
|
|
22650
|
-
` Run ${pc35.cyan("wraps
|
|
22651
|
+
` Run ${pc35.cyan("wraps cdn upgrade")} to add the custom domain to CloudFront.`
|
|
22651
22652
|
);
|
|
22652
22653
|
allPassed = false;
|
|
22653
22654
|
}
|
|
@@ -22688,12 +22689,12 @@ ${pc35.bold("Certificate Validation DNS:")}`);
|
|
|
22688
22689
|
const cdnUrl = targetDomain ? `https://${targetDomain}` : distributionDomain ? `https://${distributionDomain}` : null;
|
|
22689
22690
|
if (cdnUrl) {
|
|
22690
22691
|
clack33.log.info(`
|
|
22691
|
-
Your
|
|
22692
|
+
Your CDN is accessible at: ${pc35.cyan(cdnUrl)}`);
|
|
22692
22693
|
}
|
|
22693
22694
|
if (stackOutputsStale) {
|
|
22694
22695
|
clack33.log.info(
|
|
22695
22696
|
`
|
|
22696
|
-
${pc35.dim("Tip:")} Run ${pc35.cyan("wraps
|
|
22697
|
+
${pc35.dim("Tip:")} Run ${pc35.cyan("wraps cdn sync")} to update infrastructure state.`
|
|
22697
22698
|
);
|
|
22698
22699
|
}
|
|
22699
22700
|
} else {
|
|
@@ -22701,7 +22702,7 @@ ${pc35.dim("Tip:")} Run ${pc35.cyan("wraps storage sync")} to update infrastruct
|
|
|
22701
22702
|
if (validationRecords && validationRecords.length > 0) {
|
|
22702
22703
|
clack33.log.info("\nDNS records may take up to 48 hours to propagate.");
|
|
22703
22704
|
clack33.log.info(
|
|
22704
|
-
`Run ${pc35.cyan("wraps
|
|
22705
|
+
`Run ${pc35.cyan("wraps cdn verify")} again to check status.`
|
|
22705
22706
|
);
|
|
22706
22707
|
}
|
|
22707
22708
|
}
|
|
@@ -22863,7 +22864,7 @@ function showHelp() {
|
|
|
22863
22864
|
` ${pc38.cyan("sms")} SMS infrastructure (AWS End User Messaging)`
|
|
22864
22865
|
);
|
|
22865
22866
|
console.log(
|
|
22866
|
-
` ${pc38.cyan("
|
|
22867
|
+
` ${pc38.cyan("cdn")} CDN infrastructure (AWS S3 + CloudFront)
|
|
22867
22868
|
`
|
|
22868
22869
|
);
|
|
22869
22870
|
console.log("Email Commands:");
|
|
@@ -22912,24 +22913,24 @@ function showHelp() {
|
|
|
22912
22913
|
` ${pc38.cyan("sms destroy")} Remove SMS infrastructure
|
|
22913
22914
|
`
|
|
22914
22915
|
);
|
|
22915
|
-
console.log("
|
|
22916
|
+
console.log("CDN Commands:");
|
|
22916
22917
|
console.log(
|
|
22917
|
-
` ${pc38.cyan("
|
|
22918
|
+
` ${pc38.cyan("cdn init")} Deploy CDN infrastructure (S3 + CloudFront)`
|
|
22918
22919
|
);
|
|
22919
22920
|
console.log(
|
|
22920
|
-
` ${pc38.cyan("
|
|
22921
|
+
` ${pc38.cyan("cdn status")} Show CDN infrastructure details`
|
|
22921
22922
|
);
|
|
22922
22923
|
console.log(
|
|
22923
|
-
` ${pc38.cyan("
|
|
22924
|
+
` ${pc38.cyan("cdn verify")} Check DNS and certificate status`
|
|
22924
22925
|
);
|
|
22925
22926
|
console.log(
|
|
22926
|
-
` ${pc38.cyan("
|
|
22927
|
+
` ${pc38.cyan("cdn upgrade")} Add custom domain after cert validation`
|
|
22927
22928
|
);
|
|
22928
22929
|
console.log(
|
|
22929
|
-
` ${pc38.cyan("
|
|
22930
|
+
` ${pc38.cyan("cdn sync")} Sync infrastructure with current config`
|
|
22930
22931
|
);
|
|
22931
22932
|
console.log(
|
|
22932
|
-
` ${pc38.cyan("
|
|
22933
|
+
` ${pc38.cyan("cdn destroy")} Remove CDN infrastructure
|
|
22933
22934
|
`
|
|
22934
22935
|
);
|
|
22935
22936
|
console.log("Local Development:");
|
|
@@ -23137,8 +23138,8 @@ if (!primaryCommand) {
|
|
|
23137
23138
|
hint: "AWS End User Messaging"
|
|
23138
23139
|
},
|
|
23139
23140
|
{
|
|
23140
|
-
value: "
|
|
23141
|
-
label: "Deploy
|
|
23141
|
+
value: "cdn-init",
|
|
23142
|
+
label: "Deploy CDN",
|
|
23142
23143
|
hint: "AWS S3 + CloudFront CDN"
|
|
23143
23144
|
},
|
|
23144
23145
|
{
|
|
@@ -23196,7 +23197,7 @@ if (!primaryCommand) {
|
|
|
23196
23197
|
yes: flags.yes
|
|
23197
23198
|
});
|
|
23198
23199
|
break;
|
|
23199
|
-
case "
|
|
23200
|
+
case "cdn-init":
|
|
23200
23201
|
await init3({
|
|
23201
23202
|
provider: flags.provider,
|
|
23202
23203
|
region: flags.region,
|
|
@@ -23496,7 +23497,7 @@ Run ${pc38.cyan("wraps --help")} for available commands.
|
|
|
23496
23497
|
});
|
|
23497
23498
|
return;
|
|
23498
23499
|
}
|
|
23499
|
-
if (primaryCommand === "
|
|
23500
|
+
if (primaryCommand === "cdn" && subCommand) {
|
|
23500
23501
|
switch (subCommand) {
|
|
23501
23502
|
case "init":
|
|
23502
23503
|
await init3({
|
|
@@ -23509,36 +23510,36 @@ Run ${pc38.cyan("wraps --help")} for available commands.
|
|
|
23509
23510
|
});
|
|
23510
23511
|
break;
|
|
23511
23512
|
case "status":
|
|
23512
|
-
await
|
|
23513
|
+
await cdnStatus({
|
|
23513
23514
|
region: flags.region
|
|
23514
23515
|
});
|
|
23515
23516
|
break;
|
|
23516
23517
|
case "verify":
|
|
23517
|
-
await
|
|
23518
|
+
await cdnVerify({
|
|
23518
23519
|
region: flags.region
|
|
23519
23520
|
});
|
|
23520
23521
|
break;
|
|
23521
23522
|
case "upgrade":
|
|
23522
|
-
await
|
|
23523
|
+
await cdnUpgrade({
|
|
23523
23524
|
region: flags.region,
|
|
23524
23525
|
yes: flags.yes,
|
|
23525
23526
|
preview: flags.preview
|
|
23526
23527
|
});
|
|
23527
23528
|
break;
|
|
23528
23529
|
case "sync":
|
|
23529
|
-
await
|
|
23530
|
+
await cdnSync({
|
|
23530
23531
|
region: flags.region
|
|
23531
23532
|
});
|
|
23532
23533
|
break;
|
|
23533
23534
|
case "destroy":
|
|
23534
|
-
await
|
|
23535
|
+
await cdnDestroy({
|
|
23535
23536
|
force: flags.force,
|
|
23536
23537
|
region: flags.region,
|
|
23537
23538
|
preview: flags.preview
|
|
23538
23539
|
});
|
|
23539
23540
|
break;
|
|
23540
23541
|
default:
|
|
23541
|
-
clack36.log.error(`Unknown
|
|
23542
|
+
clack36.log.error(`Unknown cdn command: ${subCommand}`);
|
|
23542
23543
|
console.log(
|
|
23543
23544
|
`
|
|
23544
23545
|
Run ${pc38.cyan("wraps --help")} for available commands.
|
|
@@ -23546,12 +23547,12 @@ Run ${pc38.cyan("wraps --help")} for available commands.
|
|
|
23546
23547
|
);
|
|
23547
23548
|
process.exit(1);
|
|
23548
23549
|
}
|
|
23549
|
-
const
|
|
23550
|
-
const
|
|
23551
|
-
trackCommand(
|
|
23550
|
+
const cdnDuration = Date.now() - startTime;
|
|
23551
|
+
const cdnCommandName = `cdn:${subCommand}`;
|
|
23552
|
+
trackCommand(cdnCommandName, {
|
|
23552
23553
|
success: true,
|
|
23553
|
-
duration_ms:
|
|
23554
|
-
service: "
|
|
23554
|
+
duration_ms: cdnDuration,
|
|
23555
|
+
service: "cdn"
|
|
23555
23556
|
});
|
|
23556
23557
|
return;
|
|
23557
23558
|
}
|
|
@@ -23674,7 +23675,7 @@ Available commands: ${pc38.cyan("enable")}, ${pc38.cyan("disable")}, ${pc38.cyan
|
|
|
23674
23675
|
// Show help for service without subcommand
|
|
23675
23676
|
case "email":
|
|
23676
23677
|
case "sms":
|
|
23677
|
-
case "
|
|
23678
|
+
case "cdn":
|
|
23678
23679
|
case "aws":
|
|
23679
23680
|
console.log(
|
|
23680
23681
|
`
|