1
1
/* eslint-disable no-new */
2
- import type { CfnResource , NestedStackProps , aws_certificatemanager as acm , aws_wafv2 as wafv2 } from 'aws-cdk-lib'
2
+ import type { CfnResource } from 'aws-cdk-lib'
3
3
import {
4
4
AssetHashType ,
5
5
Duration ,
6
6
Fn ,
7
7
NestedStack ,
8
8
RemovalPolicy ,
9
+ Stack ,
10
+ aws_certificatemanager as acm ,
9
11
aws_cloudfront as cloudfront ,
10
12
aws_lambda as lambda ,
11
13
aws_cloudfront_origins as origins ,
@@ -18,43 +20,37 @@ import {
18
20
import type { Construct } from 'constructs'
19
21
import { hasFiles } from '@stacksjs/storage'
20
22
import { path as p } from '@stacksjs/path'
23
+ import type { NestedCloudProps } from '../types'
21
24
import type { EnvKey } from '~/storage/framework/stacks/env'
22
25
23
- interface ResourceNestedStackProps extends NestedStackProps {
24
- env : {
25
- account : string
26
- region : string
27
- }
28
- appName : string
29
- appEnv : string
30
- domain : string
31
- partialAppKey : string
32
- zone : route53 . HostedZone
33
- certificate : acm . Certificate
34
- logBucket : s3 . Bucket
35
- firewall : wafv2 . CfnWebACL
36
- storage : {
37
- publicBucket : s3 . Bucket
38
- accessPoint : s3 . CfnAccessPoint | undefined
39
- }
40
- }
41
-
42
26
export class CdnStack extends NestedStack {
43
- cdn ! : cloudfront . Distribution
44
- originAccessIdentity ! : cloudfront . OriginAccessIdentity
45
- cdnCachePolicy ! : cloudfront . CachePolicy
46
- apiCachePolicy : cloudfront . CachePolicy | undefined
47
- vanityUrl ! : string
48
- apiVanityUrl ! : string
49
- props : ResourceNestedStackProps
50
-
51
- constructor ( scope : Construct , props : ResourceNestedStackProps ) {
27
+ originAccessIdentity : cloudfront . OriginAccessIdentity
28
+ cdnCachePolicy : cloudfront . CachePolicy
29
+ zone : route53 . IHostedZone
30
+ certificateArn : string
31
+ certificate : acm . ICertificate
32
+ logBucket : s3 . IBucket
33
+
34
+ constructor ( scope : Construct , props : NestedCloudProps ) {
52
35
super ( scope , 'Cdn' , props )
53
- this . props = props
54
- // ...
55
- const originAccessIdentity = new cloudfront . OriginAccessIdentity ( this , 'OAI' )
56
36
57
- const cdnCachePolicy = new cloudfront . CachePolicy ( this , 'CdnCachePolicy' , {
37
+ // do lookups
38
+ this . zone = route53 . PublicHostedZone . fromLookup ( this , 'AppUrlHostedZone' , {
39
+ domainName : props . domain ,
40
+ } )
41
+ this . certificateArn = Stack . of ( this ) . formatArn ( {
42
+ service : 'acm' ,
43
+ resource : 'certificate' ,
44
+ resourceName : 'Certificate' , // replace with your actual certificate logical ID
45
+ } )
46
+ this . certificate = acm . Certificate . fromCertificateArn ( this , 'Certificate' , this . certificateArn )
47
+ const bucketPrefix = `${ props . appName } -${ props . appEnv } `
48
+ this . logBucket = s3 . Bucket . fromBucketName ( this , 'LogBucket' , `${ bucketPrefix } -logs-${ props . partialAppKey } ` )
49
+
50
+ // proceed with cdn logic
51
+ this . originAccessIdentity = new cloudfront . OriginAccessIdentity ( this , 'OAI' )
52
+
53
+ this . cdnCachePolicy = new cloudfront . CachePolicy ( this , 'CdnCachePolicy' , {
58
54
comment : 'Stacks CDN Cache Policy' ,
59
55
cachePolicyName : `${ props . appName } -${ props . appEnv } -cdn-cache-policy` ,
60
56
minTtl : config . cloud . cdn ?. minTtl ? Duration . seconds ( config . cloud . cdn . minTtl ) : undefined ,
@@ -63,11 +59,9 @@ export class CdnStack extends NestedStack {
63
59
cookieBehavior : this . getCookieBehavior ( config . cloud . cdn ?. cookieBehavior ) ,
64
60
} )
65
61
66
- // const timestamp = new Date().getTime()
67
-
68
62
// Fetch the timestamp from SSM Parameter Store
69
63
const timestampParam = ssm . StringParameter . fromSecureStringParameterAttributes ( this , 'TimestampParam' , {
70
- parameterName : `/${ this . props . appName . toLowerCase ( ) } /timestamp` ,
64
+ parameterName : `/${ props . appName . toLowerCase ( ) } /timestamp` ,
71
65
version : 1 ,
72
66
} )
73
67
@@ -77,24 +71,18 @@ export class CdnStack extends NestedStack {
77
71
if ( ! timestamp ) {
78
72
timestamp = new Date ( ) . getTime ( ) . toString ( )
79
73
new ssm . StringParameter ( this , 'TimestampParam' , {
80
- parameterName : `/${ this . props . appName . toLowerCase ( ) } /timestamp` ,
74
+ parameterName : `/${ props . appName . toLowerCase ( ) } /timestamp` ,
81
75
stringValue : timestamp ,
82
76
} )
83
77
}
84
78
85
- new route53 . ARecord ( this , 'AliasRecord' , {
86
- recordName : this . props . domain ,
87
- zone : this . props . zone ,
88
- target : route53 . RecordTarget . fromAlias ( new targets . CloudFrontTarget ( this . cdn ) ) ,
89
- } )
90
-
91
79
// this edge function ensures pretty docs urls
92
80
// soon to be reused for our Meema features
93
81
const originRequestFunction = new lambda . Function ( this , 'OriginRequestFunction' , {
94
82
// this needs to have partialAppKey & timestamp to ensure it is unique, because there is a chance that during testing, you deploy
95
83
// the same app many times using the same app key. Since Origin Request (Lambda@Edge) functions are replicated functions, the
96
84
// deletion process takes a long time. This is to ensure that the function is always unique in cases of quick recreations.
97
- functionName : `${ this . props . appName } -${ this . props . appEnv } -origin-request-${ this . props . partialAppKey } -${ timestamp } ` ,
85
+ functionName : `${ props . appName } -${ props . appEnv } -origin-request-${ props . partialAppKey } -${ timestamp } ` ,
98
86
description : 'The Stacks Origin Request function that prettifies URLs' ,
99
87
runtime : lambda . Runtime . NODEJS_18_X ,
100
88
handler : 'dist/origin-request.handler' ,
@@ -112,21 +100,21 @@ export class CdnStack extends NestedStack {
112
100
cfnOriginRequestFunction . applyRemovalPolicy ( RemovalPolicy . RETAIN )
113
101
114
102
const cdn = new cloudfront . Distribution ( this , 'Distribution' , {
115
- domainNames : [ this . props . domain ] ,
103
+ domainNames : [ props . domain ] ,
116
104
defaultRootObject : 'index.html' ,
117
105
comment : `CDN for ${ config . app . url } ` ,
118
- certificate : this . props . certificate ,
106
+ certificate,
119
107
enableLogging : true ,
120
- logBucket : this . props . logBucket ,
108
+ logBucket : props . logBucket ,
121
109
httpVersion : cloudfront . HttpVersion . HTTP2_AND_3 ,
122
110
priceClass : cloudfront . PriceClass . PRICE_CLASS_ALL ,
123
111
enabled : true ,
124
112
minimumProtocolVersion : cloudfront . SecurityPolicyProtocol . TLS_V1_2_2021 ,
125
- webAclId : this . props . firewall . attrArn ,
113
+ webAclId : props . firewall . attrArn ,
126
114
enableIpv6 : true ,
127
115
128
116
defaultBehavior : {
129
- origin : new origins . S3Origin ( this . props . storage . publicBucket , {
117
+ origin : new origins . S3Origin ( props . publicBucket , {
130
118
originAccessIdentity : this . originAccessIdentity ,
131
119
} ) ,
132
120
edgeLambdas : [
@@ -142,7 +130,7 @@ export class CdnStack extends NestedStack {
142
130
cachePolicy : this . cdnCachePolicy ,
143
131
} ,
144
132
145
- additionalBehaviors : this . additionalBehaviors ( ) ,
133
+ additionalBehaviors : this . additionalBehaviors ( props ) ,
146
134
147
135
// Add custom error responses
148
136
errorResponses : [
@@ -158,9 +146,9 @@ export class CdnStack extends NestedStack {
158
146
// setup the www redirect
159
147
// Create a bucket for www.yourdomain.com and configure it to redirect to yourdomain.com
160
148
const wwwBucket = new s3 . Bucket ( this , 'WwwBucket' , {
161
- bucketName : `www.${ this . props . domain } ` ,
149
+ bucketName : `www.${ props . domain } ` ,
162
150
websiteRedirect : {
163
- hostName : this . props . domain ,
151
+ hostName : props . domain ,
164
152
protocol : s3 . RedirectProtocol . HTTPS ,
165
153
} ,
166
154
removalPolicy : RemovalPolicy . DESTROY ,
@@ -169,15 +157,15 @@ export class CdnStack extends NestedStack {
169
157
170
158
// Create a Route53 record for www.yourdomain.com
171
159
new route53 . ARecord ( this , 'WwwAliasRecord' , {
172
- recordName : `www.${ this . props . domain } ` ,
173
- zone : this . props . zone ,
160
+ recordName : `www.${ props . domain } ` ,
161
+ zone : this . zone ,
174
162
target : route53 . RecordTarget . fromAlias ( new targets . BucketWebsiteTarget ( wwwBucket ) ) ,
175
163
} )
176
164
177
- this . cdn = cdn
178
- this . originAccessIdentity = originAccessIdentity
179
- this . cdnCachePolicy = cdnCachePolicy
180
- this . vanityUrl = `https://${ this . cdn . domainName } `
165
+ // this.cdn = cdn
166
+ // this.originAccessIdentity = originAccessIdentity
167
+ // this.cdnCachePolicy = cdnCachePolicy
168
+ // this.vanityUrl = `https://${this.cdn.domainName}`
181
169
}
182
170
183
171
getCookieBehavior ( behavior : string | undefined ) : cloudfront . CacheCookieBehavior | undefined {
@@ -252,20 +240,20 @@ export class CdnStack extends NestedStack {
252
240
return config . cloud . deploy ?. api
253
241
}
254
242
255
- deployApi ( ) {
243
+ deployApi ( props ) {
256
244
const keysToRemove = [ '_HANDLER' , '_X_AMZN_TRACE_ID' , 'AWS_REGION' , 'AWS_EXECUTION_ENV' , 'AWS_LAMBDA_FUNCTION_NAME' , 'AWS_LAMBDA_FUNCTION_MEMORY_SIZE' , 'AWS_LAMBDA_FUNCTION_VERSION' , 'AWS_LAMBDA_INITIALIZATION_TYPE' , 'AWS_LAMBDA_LOG_GROUP_NAME' , 'AWS_LAMBDA_LOG_STREAM_NAME' , 'AWS_ACCESS_KEY' , 'AWS_ACCESS_KEY_ID' , 'AWS_SECRET_ACCESS_KEY' , 'AWS_SESSION_TOKEN' , 'AWS_LAMBDA_RUNTIME_API' , 'LAMBDA_TASK_ROOT' , 'LAMBDA_RUNTIME_DIR' , '_' ]
257
245
keysToRemove . forEach ( key => delete env [ key as EnvKey ] )
258
246
259
247
const secrets = new secretsmanager . Secret ( this , 'StacksSecrets' , {
260
- secretName : `${ this . props . appName } -${ this . props . appEnv } -secrets` ,
248
+ secretName : `${ props . appName } -${ props . appEnv } -secrets` ,
261
249
description : 'Secrets for the Stacks application' ,
262
250
generateSecretString : {
263
251
secretStringTemplate : JSON . stringify ( env ) ,
264
252
generateStringKey : Object . keys ( env ) . join ( ',' ) . length . toString ( ) ,
265
253
} ,
266
254
} )
267
255
268
- const functionName = `${ this . props . appName } -${ this . props . appEnv } -server`
256
+ const functionName = `${ props . appName } -${ props . appEnv } -server`
269
257
270
258
// this.apiVanityUrl = api.url
271
259
}
@@ -327,11 +315,11 @@ export class CdnStack extends NestedStack {
327
315
return hasFiles ( p . projectPath ( 'docs' ) )
328
316
}
329
317
330
- additionalBehaviors ( ) : Record < string , cloudfront . BehaviorOptions > {
318
+ additionalBehaviors ( props ) : Record < string , cloudfront . BehaviorOptions > {
331
319
let behaviorOptions : Record < string , cloudfront . BehaviorOptions > = { }
332
320
333
321
if ( this . shouldDeployApi ( ) ) {
334
- this . deployApi ( )
322
+ this . deployApi ( props )
335
323
336
324
behaviorOptions = this . apiBehaviorOptions ( )
337
325
}
0 commit comments