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