@stacksjs/cloud 0.70.23 → 0.70.26

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/compute.d.ts DELETED
@@ -1,221 +0,0 @@
1
- import type { Construct } from 'constructs';
2
- import type { NestedCloudProps } from '../types';
3
-
4
- export declare interface ComputeStackProps extends NestedCloudProps {
5
- vpc: ec2.Vpc
6
- fileSystem: efs.FileSystem
7
- zone: route53.IHostedZone
8
- certificate: acm.Certificate
9
- }
10
- export declare class ComputeStack {
11
- lb: elbv2.ApplicationLoadBalancer
12
- cluster: ecs.Cluster
13
- taskDefinition: ecs.FargateTaskDefinition
14
-
15
- constructor(scope: Construct, props: ComputeStackProps) {
16
- const vpc = props.vpc
17
- const fileSystem = props.fileSystem
18
-
19
- if (!fileSystem)
20
- throw new Error('The file system is missing. Please make sure it was created properly.')
21
-
22
- this.cluster = new ecs.Cluster(scope, 'StacksCluster', {
23
- clusterName: `${props.slug}-${props.appEnv}-web-server-cluster`,
24
- vpc,
25
- })
26
-
27
- this.taskDefinition = new ecs.FargateTaskDefinition(scope, 'TaskDefinition', {
28
- family: `${props.appName}-${props.appEnv}-api`,
29
- memoryLimitMiB: 512,
30
- cpu: 256,
31
- runtimePlatform: {
32
- cpuArchitecture: ecs.CpuArchitecture.ARM64,
33
- },
34
- })
35
-
36
-
37
- const container = this.taskDefinition.addContainer('WebServerContainer', {
38
- containerName: `${props.appName}-${props.appEnv}-api`,
39
- image: ecs.ContainerImage.fromAsset(p.frameworkPath('server')),
40
- logging: new ecs.AwsLogDriver({
41
- streamPrefix: `${props.appName}-${props.appEnv}-web-server-logs`,
42
- logGroup: new LogGroup(scope, 'StacksApiLogs', {
43
- logGroupName: '/aws/ecs/stacks-api',
44
- removalPolicy: RemovalPolicy.DESTROY,
45
- }),
46
- }),
47
- healthCheck: {
48
- command: ['CMD-SHELL', 'curl -f http:
49
- interval: Duration.seconds(10),
50
- timeout: Duration.seconds(5),
51
- retries: 3,
52
- startPeriod: Duration.seconds(10),
53
- },
54
- })
55
-
56
- container.addPortMappings({
57
- containerPort: 3000,
58
- hostPort: 3000,
59
- })
60
-
61
- const serviceSecurityGroup = new ec2.SecurityGroup(scope, 'ServiceSecurityGroup', {
62
- securityGroupName: `${props.appName}-${props.appEnv}-api-service-sg`,
63
- vpc,
64
- description: 'Stacks Security Group for API Service',
65
- })
66
-
67
- const publicLoadBalancerSG = new ec2.SecurityGroup(scope, 'PublicLoadBalancerSG', {
68
- securityGroupName: `${props.appName}-${props.appEnv}-public-load-balancer-sg`,
69
- vpc,
70
- description: 'Access to the public facing load balancer',
71
- })
72
-
73
- serviceSecurityGroup.addIngressRule(publicLoadBalancerSG, ec2.Port.allTraffic(), 'Ingress from the public ALB')
74
-
75
- this.lb = new elbv2.ApplicationLoadBalancer(scope, 'ApplicationLoadBalancer', {
76
- http2Enabled: true,
77
- loadBalancerName: `${props.appName}-${props.appEnv}-alb`,
78
- vpc,
79
- vpcSubnets: {
80
- subnets: vpc.selectSubnets({
81
- subnetType: ec2.SubnetType.PUBLIC,
82
- onePerAz: true,
83
- }).subnets,
84
- },
85
- internetFacing: true,
86
- idleTimeout: Duration.seconds(30),
87
- securityGroup: publicLoadBalancerSG,
88
- })
89
-
90
- new route53.ARecord(scope, 'ApiDomainAliasRecord', {
91
- zone: props.zone,
92
- recordName: 'api',
93
- target: route53.RecordTarget.fromAlias(new route53Targets.LoadBalancerTarget(this.lb)),
94
- })
95
-
96
- const serviceTargetGroup = new elbv2.ApplicationTargetGroup(scope, 'ServiceTargetGroup', {
97
- targetGroupName: `${props.appName}-${props.appEnv}-api-tg`,
98
- vpc,
99
- targetType: elbv2.TargetType.IP,
100
- protocol: elbv2.ApplicationProtocol.HTTP,
101
- port: 3000,
102
- healthCheck: {
103
- interval: Duration.seconds(6),
104
- path: '/health',
105
- protocol: elbv2.Protocol.HTTP,
106
- timeout: Duration.seconds(5),
107
- healthyThresholdCount: 2,
108
- unhealthyThresholdCount: 10,
109
- },
110
- })
111
-
112
- const service = new ecs.FargateService(scope, 'StacksApiService', {
113
- serviceName: `${props.appName}-${props.appEnv}-api-service`,
114
- cluster: this.cluster,
115
- taskDefinition: this.taskDefinition,
116
- desiredCount: 1,
117
- assignPublicIp: true,
118
- maxHealthyPercent: 200,
119
- vpcSubnets: vpc.selectSubnets({
120
- subnetType: ec2.SubnetType.PUBLIC,
121
- onePerAz: true,
122
- }),
123
- minHealthyPercent: 75,
124
- securityGroups: [serviceSecurityGroup],
125
- })
126
-
127
- service.attachToApplicationTargetGroup(serviceTargetGroup)
128
- publicLoadBalancerSG.addIngressRule(ec2.Peer.anyIpv4(), ec2.Port.allTraffic())
129
-
130
- this.lb.addListener('HttpsListener', {
131
- port: 443,
132
- certificates: [props.certificate],
133
- defaultAction: elbv2.ListenerAction.forward([serviceTargetGroup]),
134
- })
135
-
136
- this.lb.addListener('HttpListener', {
137
- port: 80,
138
- defaultAction: elbv2.ListenerAction.forward([serviceTargetGroup]),
139
- })
140
-
141
- props.fileSystem.connections.allowFromAnyIpv4(ec2.Port.tcp(2049))
142
-
143
- const volumeName = `${props.slug}-${props.appEnv}-efs`
144
- this.taskDefinition.addVolume({
145
- name: volumeName,
146
- efsVolumeConfiguration: {
147
- fileSystemId: props.fileSystem.fileSystemId,
148
- },
149
- })
150
-
151
- container.addMountPoints({
152
- sourceVolume: volumeName,
153
- containerPath: '/mnt/efs',
154
- readOnly: false,
155
- })
156
-
157
- const scaling = service.autoScaleTaskCount({ maxCapacity: 2 })
158
-
159
- scaling.scaleOnCpuUtilization('CpuScaling', {
160
- targetUtilizationPercent: 50,
161
- scaleInCooldown: Duration.seconds(60),
162
- scaleOutCooldown: Duration.seconds(60),
163
- })
164
-
165
- scaling.scaleOnMemoryUtilization('MemoryScaling', {
166
- targetUtilizationPercent: 60,
167
- scaleInCooldown: Duration.seconds(60),
168
- scaleOutCooldown: Duration.seconds(60),
169
- })
170
-
171
- const keysToRemove = [
172
- '_HANDLER',
173
- '_X_AMZN_TRACE_ID',
174
- 'AWS_REGION',
175
- 'AWS_EXECUTION_ENV',
176
- 'AWS_LAMBDA_FUNCTION_NAME',
177
- 'AWS_LAMBDA_FUNCTION_MEMORY_SIZE',
178
- 'AWS_LAMBDA_FUNCTION_VERSION',
179
- 'AWS_LAMBDA_INITIALIZATION_TYPE',
180
- 'AWS_LAMBDA_LOG_GROUP_NAME',
181
- 'AWS_LAMBDA_LOG_STREAM_NAME',
182
- 'AWS_ACCESS_KEY',
183
- 'AWS_ACCESS_KEY_ID',
184
- 'AWS_SECRET_ACCESS_KEY',
185
- 'AWS_SESSION_TOKEN',
186
- 'AWS_LAMBDA_RUNTIME_API',
187
- 'LAMBDA_TASK_ROOT',
188
- 'LAMBDA_RUNTIME_DIR',
189
- '_',
190
- ]
191
- keysToRemove.forEach(key => delete env[key as EnvKey])
192
-
193
- const secrets = new secretsmanager.Secret(scope, 'StacksSecrets', {
194
- secretName: `${props.slug}-${props.appEnv}-secrets`,
195
- description: 'Secrets for the Stacks application',
196
- generateSecretString: {
197
- secretStringTemplate: JSON.stringify(env),
198
- generateStringKey: Object.keys(env).join(',').length.toString(),
199
- },
200
- })
201
-
202
- if (service.taskDefinition.executionRole) {
203
- secrets.grantRead(service.taskDefinition.executionRole)
204
- container.addEnvironment('SECRETS_ARN', secrets.secretArn)
205
- }
206
- else {
207
- throw new Error('Service task execution role is undefined.')
208
- }
209
-
210
- const apiPrefix = 'api'
211
- new Output(scope, 'ApiUrl', {
212
- value: `https:
213
- description: 'The URL of the deployed application',
214
- })
215
-
216
- new Output(scope, 'ApiVanityUrl', {
217
- value: `http:
218
- description: 'The Vanity URL / DNS name of the load balancer',
219
- })
220
- }
221
- }
@@ -1,29 +0,0 @@
1
- import type { Construct } from 'constructs';
2
- import type { NestedCloudProps } from '../types';
3
-
4
- export declare interface DatabaseStackProps extends NestedCloudProps {
5
- vpc: ec2.Vpc
6
- }
7
- export declare class DatabaseStack {
8
- database: dynamodb.Table
9
-
10
- constructor(scope: Construct, props: DatabaseStackProps) {
11
- this.database = new dynamodb.Table(scope, 'Database', {
12
- tableName: `${props.slug}-${props.appEnv}-database`,
13
- partitionKey: {
14
- name: 'id',
15
- type: dynamodb.AttributeType.STRING,
16
- },
17
- sortKey: {
18
- name: 'sort',
19
- type: dynamodb.AttributeType.STRING,
20
- },
21
- billingMode: dynamodb.BillingMode.PAY_PER_REQUEST,
22
- readCapacity: 5,
23
- writeCapacity: 5,
24
- pointInTimeRecovery: true,
25
- removalPolicy: RemovalPolicy.DESTROY,
26
- encryption: dynamodb.TableEncryption.AWS_MANAGED,
27
- })
28
- }
29
- }
@@ -1,60 +0,0 @@
1
- import type { Construct } from 'constructs';
2
- import type { NestedCloudProps } from '../types';
3
-
4
- export declare interface DeploymentStackProps extends NestedCloudProps {
5
- publicBucket: s3.Bucket
6
- docsBucket?: s3.Bucket
7
- privateBucket: s3.Bucket
8
- mainDistribution: cloudfront.Distribution
9
- docsDistribution?: cloudfront.Distribution
10
- }
11
- export declare class DeploymentStack {
12
- privateSource: string
13
- docsSource: string
14
- publicSource: string
15
-
16
- constructor(scope: Construct, props: DeploymentStackProps) {
17
- this.privateSource = '../../private'
18
- this.docsSource = '../docs/dist/'
19
- this.publicSource = config.app.docMode === true ? this.docsSource : '../views/web/dist/'
20
- const mainBucket = config.app.docMode === true ? props.docsBucket : props.publicBucket
21
-
22
- new s3deploy.BucketDeployment(scope, 'Website', {
23
- sources: [
24
- s3deploy.Source.asset(this.publicSource, {
25
- assetHash: websiteSourceHash(),
26
- assetHashType: AssetHashType.CUSTOM,
27
- }),
28
- ],
29
- destinationBucket: mainBucket as s3.Bucket,
30
- distribution: props.mainDistribution,
31
- })
32
-
33
- if (this.shouldDeployDocs()) {
34
- new s3deploy.BucketDeployment(scope, 'Docs', {
35
- sources: [
36
- s3deploy.Source.asset(this.docsSource, {
37
- assetHash: docsSourceHash(),
38
- assetHashType: AssetHashType.CUSTOM,
39
- }),
40
- ],
41
- destinationBucket: props.docsBucket as s3.Bucket,
42
- distribution: props.docsDistribution,
43
- })
44
- }
45
-
46
- if (hasFiles(this.privateSource)) {
47
- new s3deploy.BucketDeployment(scope, 'PrivateFiles', {
48
- sources: [s3deploy.Source.asset(this.privateSource)],
49
- destinationBucket: props.privateBucket,
50
- })
51
- }
52
- else {
53
- console.error(`The path ${this.privateSource} does not have any files`)
54
- }
55
- }
56
-
57
- shouldDeployDocs(): boolean {
58
- return hasFiles(p.projectPath('docs')) && !config.app.docMode
59
- }
60
- }
package/dist/dns.d.ts DELETED
@@ -1,34 +0,0 @@
1
- import type { Construct } from 'constructs';
2
- import type { NestedCloudProps } from '../types';
3
-
4
- export declare class DnsStack {
5
- zone: route53.IHostedZone
6
-
7
- constructor(scope: Construct, props: NestedCloudProps) {
8
- this.zone = route53.PublicHostedZone.fromLookup(scope, 'AppUrlHostedZone', {
9
- domainName: props.domain,
10
- })
11
-
12
- const wwwBucket = new s3.Bucket(scope, 'WwwBucket', {
13
- bucketName: `www.${props.domain}`,
14
- websiteRedirect: {
15
- hostName: props.domain,
16
- protocol: s3.RedirectProtocol.HTTPS,
17
- },
18
- removalPolicy: RemovalPolicy.DESTROY,
19
- autoDeleteObjects: true,
20
- })
21
-
22
- new route53.ARecord(scope, 'WwwAliasRecord', {
23
- recordName: `www.${props.domain}`,
24
- zone: this.zone,
25
- target: route53.RecordTarget.fromAlias(new targets.BucketWebsiteTarget(wwwBucket)),
26
- })
27
-
28
- new route53.ARecord(scope, 'StoreAliasRecord', {
29
- recordName: `store.${props.domain}`,
30
- zone: this.zone,
31
- target: route53.RecordTarget.fromIpAddresses('137.66.37.136'),
32
- })
33
- }
34
- }
package/dist/docs.d.ts DELETED
@@ -1,34 +0,0 @@
1
- import type { CfnResource } from 'aws-cdk-lib';
2
- import type { Construct } from 'constructs';
3
- import type { NestedCloudProps } from '../types';
4
-
5
- export declare interface DocsStackProps extends NestedCloudProps {
6
- }
7
- export declare class DocsStack {
8
- originRequestFunction: lambda.Function
9
-
10
- constructor(scope: Construct, props: DocsStackProps) {
11
- const docsPrefix = 'docs'
12
-
13
- this.originRequestFunction = new lambda.Function(scope, 'OriginRequestFunction', {
14
- functionName: `${props.slug}-${props.appEnv}-origin-request-${props.timestamp}`,
15
- description: 'The Stacks Origin Request function that prettifies URLs by removing the .html extension',
16
- runtime: lambda.Runtime.NODEJS_20_X,
17
- handler: 'dist/origin-request.handler',
18
- code: lambda.Code.fromAsset(p.cloudPath('dist.zip'), {
19
- assetHash: originRequestFunctionHash(),
20
- assetHashType: AssetHashType.CUSTOM,
21
- }),
22
- })
23
-
24
- const cfnOriginRequestFunction = this.originRequestFunction.node.defaultChild as CfnResource
25
- cfnOriginRequestFunction.applyRemovalPolicy(RemovalPolicy.RETAIN)
26
-
27
- if (!config.app.docMode && storage.hasFiles(p.projectPath('docs'))) {
28
- new Output(scope, 'DocsUrl', {
29
- value: `https:
30
- description: 'The URL of the deployed documentation',
31
- })
32
- }
33
- }
34
- }