-
1
-
2
-
3
-
4
-
5
-
6
-
7
-
8
-
9
-
10
-
11
-
12
-
13
-
14
-
15
-
16
-
17
-
18
-
19
-
20
-
21
-
22
-
23
-
24
-
25
-
26
-
27
-
28
-
29
-
30
-
31
-
32
-
33
-
34
-
35
-
36
-
37
-
38
-
39
-
40
-
41
-
42
-
43
-
44
-
45
-
46
-
47
-
48
-
49
-
50
-
51
-
52
-
53
-
54
-
55
-
56
-
57
-
58
-
59
-
60
-
61
-
62
-
63
-
64
-
65
-
66
-
67
-
68
-
69
-
70
-
71
-
72
-
73
-
74
-
75
-
76
-
77
-
78
-
79
-
80
-
81
-
82
-
83
-
84
// This script deploys website/dist to a AWS S3 Bucket.
// This script expects an environment to have non-empty variables
// AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, and AWS_DEFAULT_REGION.
import * as commander from "commander";
interface DeployOptions {
s3BucketName: string;
cfDistributionID: string;
}
function deploy({ s3BucketName, cfDistributionID }: DeployOptions) {
const sync = Bun.spawnSync(
[
"aws",
"s3",
"sync",
"--delete",
new URL("../../website/dist", import.meta.url).pathname,
`s3://${s3BucketName}`,
],
{
stdio: ["inherit", "inherit", "inherit"],
},
);
if (!sync.success) {
throw new Error("Failed to sync local contents to S3 bucket");
}
const invalidation = Bun.spawnSync(
[
"aws",
"cloudfront",
"create-invalidation",
"--distribution-id",
cfDistributionID,
"--paths",
"/*",
],
{
stdio: ["inherit", "inherit", "inherit"],
},
);
if (!invalidation.success) {
throw new Error("Failed to invalidate CloudFront cache");
}
}
if (import.meta.main) {
interface CLIOptions {
s3Bucket?: string;
cfDistId?: string;
}
const program = commander.program
.option("--s3-bucket", "S3 Bucket name to deploy ($S3_BUCKET_NAME)")
.option(
"--cf-dist-id",
"CloudFront distribution ID of the website CDN ($CF_DIST_ID)",
)
.action(
({
s3Bucket = Bun.env.S3_BUCKET,
cfDistId = Bun.env.CF_DIST_ID,
}: CLIOptions) => {
if (!s3Bucket) {
throw new Error("S3 Bucket name is required.");
}
if (!cfDistId) {
throw new Error("CloudFront distribution ID is required.");
}
deploy({
s3BucketName: s3Bucket,
cfDistributionID: cfDistId,
});
},
);
await program.parseAsync(Bun.argv);
}