@stacksjs/cloud 0.70.22 → 0.70.25

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/email.d.ts DELETED
@@ -1,336 +0,0 @@
1
- import type { Construct } from 'constructs';
2
- import type { NestedCloudProps } from '../types';
3
-
4
- export declare interface EmailStackProps extends NestedCloudProps {
5
- zone: route53.IHostedZone
6
- }
7
- export declare class EmailStack {
8
- emailBucket: s3.Bucket
9
-
10
- constructor(scope: Construct, props: EmailStackProps) {
11
- const bucketPrefix = `${props.slug}-${props.appEnv}`
12
- this.emailBucket = new s3.Bucket(scope, 'EmailBucket', {
13
- bucketName: `${bucketPrefix}-email-${props.timestamp}`,
14
- versioned: true,
15
- removalPolicy: RemovalPolicy.DESTROY,
16
- autoDeleteObjects: true,
17
- encryption: s3.BucketEncryption.S3_MANAGED,
18
- lifecycleRules: [
19
- {
20
- id: '24h',
21
- enabled: true,
22
- expiration: Duration.days(1),
23
- noncurrentVersionExpiration: Duration.days(1),
24
- prefix: 'today/',
25
- },
26
- {
27
- id: 'Intelligent transition for Inbox',
28
- enabled: true,
29
- prefix: 'inbox/',
30
- transitions: [
31
- {
32
- storageClass: s3.StorageClass.INTELLIGENT_TIERING,
33
- transitionAfter: Duration.days(0),
34
- },
35
- ],
36
- },
37
- {
38
- id: 'Intelligent transition for Sent',
39
- enabled: true,
40
- prefix: 'sent/',
41
- transitions: [
42
- {
43
- storageClass: s3.StorageClass.INTELLIGENT_TIERING,
44
- transitionAfter: Duration.days(0),
45
- },
46
- ],
47
- },
48
- ],
49
- })
50
-
51
- Tags.of(this.emailBucket).add('daily-backup', 'true')
52
-
53
- const sesPrincipal = new iam.ServicePrincipal('ses.amazonaws.com')
54
- const ruleSetName = `${props.slug}-${props.appEnv}-email-receipt-rule-set`
55
- const receiptRuleName = `${props.slug}-${props.appEnv}-email-receipt-rule`
56
-
57
- const ruleSet = new ses.CfnReceiptRuleSet(scope, 'SESReceiptRuleSet', {
58
- ruleSetName,
59
- })
60
-
61
- this.emailBucket.addToResourcePolicy(
62
- new iam.PolicyStatement({
63
- sid: 'AllowSESPuts',
64
- effect: iam.Effect.ALLOW,
65
- principals: [sesPrincipal],
66
- actions: ['s3:PutObject'],
67
- resources: [`${this.emailBucket.bucketArn}/*`],
68
- conditions: {
69
- StringEquals: {
70
- 'aws:SourceAccount': Stack.of(scope).account,
71
- },
72
- ArnLike: {
73
- 'aws:SourceArn': `arn:aws:ses:${Stack.of(scope).region}:${
74
- Stack.of(scope).account
75
- }:receipt-rule-set/${ruleSetName}:receipt-rule/${receiptRuleName}`,
76
- },
77
- },
78
- }),
79
- )
80
-
81
- const receiptRule = new ses.CfnReceiptRule(scope, 'SESReceiptRule', {
82
- ruleSetName: ruleSet.ref,
83
- rule: {
84
- name: receiptRuleName,
85
- enabled: true,
86
- actions: [
87
- {
88
- s3Action: {
89
- bucketName: this.emailBucket.bucketName,
90
- objectKeyPrefix: 'tmp/email_in/',
91
- },
92
- },
93
- ],
94
- recipients: config.email.mailboxes || [],
95
- scanEnabled: config.email.server?.scan || true,
96
- tlsPolicy: 'Require',
97
- },
98
- })
99
-
100
- receiptRule.node.addDependency(this.emailBucket)
101
-
102
- const iamGroup = new iam.Group(scope, 'IAMGroup', {
103
- groupName: `${props.slug}-${props.appEnv}-email-management-s3-group`,
104
- })
105
-
106
- const listBucketsPolicyStatement = new iam.PolicyStatement({
107
- effect: iam.Effect.ALLOW,
108
- actions: ['s3:ListAllMyBuckets'],
109
- resources: ['*'],
110
- })
111
-
112
- const policyStatement = new iam.PolicyStatement({
113
- effect: iam.Effect.ALLOW,
114
- actions: [
115
- 's3:ListBucket',
116
- 's3:GetObject',
117
- 's3:PutObject',
118
- 's3:DeleteObject',
119
- 's3:GetObjectAcl',
120
- 's3:GetObjectVersionAcl',
121
- 's3:PutObjectAcl',
122
- 's3:PutObjectVersionAcl',
123
- ],
124
- resources: [this.emailBucket.bucketArn, `${this.emailBucket.bucketArn}/*`],
125
- })
126
-
127
- const policy = new iam.Policy(scope, 'EmailAccessPolicy', {
128
- policyName: `${props.slug}-${props.appEnv}-email-management-s3-policy`,
129
- statements: [policyStatement, listBucketsPolicyStatement],
130
- })
131
-
132
- iamGroup.attachInlinePolicy(policy)
133
-
134
- const sesIdentity = new ses.CfnEmailIdentity(scope, 'DomainIdentity', {
135
- emailIdentity: props.domain,
136
-
137
- dkimSigningAttributes: {
138
- nextSigningKeyLength: 'RSA_2048_BIT',
139
- },
140
-
141
- dkimAttributes: {
142
- signingEnabled: true,
143
- },
144
-
145
- mailFromAttributes: {
146
- behaviorOnMxFailure: 'USE_DEFAULT_VALUE',
147
- mailFromDomain: `mail.${props.domain}`,
148
- },
149
-
150
- feedbackAttributes: {
151
- emailForwardingEnabled: true,
152
- },
153
- })
154
-
155
- new route53.CfnRecordSet(scope, 'DkimRecord1', {
156
- hostedZoneName: `${props.zone.zoneName}.`,
157
- name: sesIdentity.attrDkimDnsTokenName1,
158
- type: 'CNAME',
159
- resourceRecords: [sesIdentity.attrDkimDnsTokenValue1],
160
- ttl: '1800',
161
- })
162
-
163
- new route53.CfnRecordSet(scope, 'DkimRecord2', {
164
- hostedZoneName: `${props.zone.zoneName}.`,
165
- name: sesIdentity.attrDkimDnsTokenName2,
166
- type: 'CNAME',
167
- resourceRecords: [sesIdentity.attrDkimDnsTokenValue2],
168
- ttl: '1800',
169
- })
170
-
171
- new route53.CfnRecordSet(scope, 'DkimRecord3', {
172
- hostedZoneName: `${props.zone.zoneName}.`,
173
- name: sesIdentity.attrDkimDnsTokenName3,
174
- type: 'CNAME',
175
- resourceRecords: [sesIdentity.attrDkimDnsTokenValue3],
176
- ttl: '1800',
177
- })
178
-
179
- new route53.MxRecord(scope, 'MxRecord', {
180
- zone: props.zone,
181
- recordName: 'mail',
182
- values: [
183
- {
184
- priority: 10,
185
- hostName: 'feedback-smtp.us-east-1.amazonses.com',
186
- },
187
- ],
188
- })
189
-
190
- new route53.TxtRecord(scope, 'TxtSpfRecord', {
191
- zone: props.zone,
192
- recordName: 'mail',
193
- values: ['v=spf1 include:amazonses.com ~all'],
194
- })
195
-
196
- new route53.TxtRecord(scope, 'TxtDmarcRecord', {
197
- zone: props.zone,
198
- recordName: '_dmarc',
199
- values: [`v=DMARC1;p=quarantine;pct=25;rua=mailto:dmarcreports@${props.domain}`],
200
- })
201
-
202
- const lambdaEmailOutboundRole = new iam.Role(scope, 'LambdaEmailOutboundRole', {
203
- roleName: `${props.slug}-${props.appEnv}-email-outbound`,
204
- assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'),
205
- managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')],
206
- })
207
-
208
- const lambdaEmailOutbound = new lambda.Function(scope, 'LambdaEmailOutbound', {
209
- functionName: `${props.slug}-${props.appEnv}-email-outbound`,
210
- description: 'Take the JSON and convert it in to an raw email.',
211
- code: lambda.Code.fromInline('exports.handler = async (event) => {return true;};'),
212
- handler: 'index.handler',
213
- memorySize: 256,
214
- runtime: lambda.Runtime.NODEJS_18_X,
215
- timeout: Duration.seconds(60),
216
- environment: {
217
- BUCKET: this.emailBucket.bucketName,
218
- },
219
- role: lambdaEmailOutboundRole,
220
- })
221
-
222
- lambdaEmailOutboundRole.addToPolicy(policyStatement)
223
-
224
- const sesPolicyStatement = new iam.PolicyStatement({
225
- effect: iam.Effect.ALLOW,
226
- actions: ['ses:SendRawEmail'],
227
- resources: ['*'],
228
- })
229
-
230
- lambdaEmailOutboundRole.addToPolicy(sesPolicyStatement)
231
-
232
- const lambdaEmailInboundRole = new iam.Role(scope, 'LambdaEmailInboundRole', {
233
- roleName: `${props.slug}-${props.appEnv}-email-inbound`,
234
- assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'),
235
- managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')],
236
- })
237
-
238
- const lambdaEmailInbound = new lambda.Function(scope, 'LambdaEmailInbound', {
239
- functionName: `${props.slug}-${props.appEnv}-email-inbound`,
240
- description: 'This Lambda organizes all the incoming emails based on the From and To field.',
241
- code: lambda.Code.fromInline('exports.handler = async (event) => {return true;};'),
242
- handler: 'index.handler',
243
- memorySize: 256,
244
- role: lambdaEmailInboundRole,
245
- runtime: lambda.Runtime.NODEJS_18_X,
246
- timeout: Duration.seconds(60),
247
- environment: {
248
- BUCKET: this.emailBucket.bucketName,
249
- },
250
- })
251
-
252
- new lambda.CfnPermission(scope, 'S3InboundPermission', {
253
- action: 'lambda:InvokeFunction',
254
- functionName: lambdaEmailInbound.functionName,
255
- principal: 's3.amazonaws.com',
256
- })
257
-
258
- const inboundS3PolicyStatement = new iam.PolicyStatement({
259
- effect: iam.Effect.ALLOW,
260
- actions: ['s3:*'],
261
- resources: [this.emailBucket.bucketArn, `${this.emailBucket.bucketArn}/*`],
262
- })
263
-
264
- lambdaEmailInboundRole.addToPolicy(inboundS3PolicyStatement)
265
-
266
- const sesInboundPolicyStatement = new iam.PolicyStatement({
267
- effect: iam.Effect.ALLOW,
268
- actions: ['ses:ListIdentities'],
269
- resources: ['*'],
270
- })
271
-
272
- lambdaEmailInboundRole.addToPolicy(sesInboundPolicyStatement)
273
-
274
- const lambdaEmailConverterRole = new iam.Role(scope, 'LambdaEmailConverterRole', {
275
- roleName: `${props.slug}-${props.appEnv}-email-converter`,
276
- assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'),
277
- managedPolicies: [iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')],
278
- })
279
-
280
- const lambdaEmailConverter = new lambda.Function(scope, 'LambdaEmailConverter', {
281
- functionName: `${props.slug}-${props.appEnv}-email-converter`,
282
- description: 'This Lambda converts raw emails files in to HTML and text.',
283
- code: lambda.Code.fromInline(
284
- 'exports.handler = async (event) => {console.log("hello world email converter");return true;};',
285
- ),
286
- handler: 'index.handler',
287
- memorySize: 256,
288
- role: lambdaEmailConverterRole,
289
- runtime: lambda.Runtime.NODEJS_18_X,
290
- timeout: Duration.seconds(60),
291
- environment: {
292
- BUCKET: this.emailBucket.bucketName,
293
- },
294
- })
295
-
296
- const converterS3PolicyStatement = new iam.PolicyStatement({
297
- effect: iam.Effect.ALLOW,
298
- actions: ['s3:*'],
299
- resources: [this.emailBucket.bucketArn, `${this.emailBucket.bucketArn}/*`],
300
- })
301
-
302
- new lambda.CfnPermission(scope, 'S3ConverterPermission', {
303
- action: 'lambda:InvokeFunction',
304
- functionName: lambdaEmailConverter.functionName,
305
- principal: 's3.amazonaws.com',
306
- })
307
-
308
- lambdaEmailConverterRole.addToPolicy(converterS3PolicyStatement)
309
-
310
- this.emailBucket.addEventNotification(
311
- s3.EventType.OBJECT_CREATED_PUT,
312
- new s3n.LambdaDestination(lambdaEmailInbound),
313
- { prefix: 'tmp/email_in/' },
314
- )
315
- this.emailBucket.addEventNotification(
316
- s3.EventType.OBJECT_CREATED_PUT,
317
- new s3n.LambdaDestination(lambdaEmailOutbound),
318
- { prefix: 'tmp/email_out/json/' },
319
- )
320
- this.emailBucket.addEventNotification(
321
- s3.EventType.OBJECT_CREATED_COPY,
322
- new s3n.LambdaDestination(lambdaEmailConverter),
323
- { prefix: 'sent/' },
324
- )
325
- this.emailBucket.addEventNotification(
326
- s3.EventType.OBJECT_CREATED_COPY,
327
- new s3n.LambdaDestination(lambdaEmailConverter),
328
- { prefix: 'inbox/' },
329
- )
330
- this.emailBucket.addEventNotification(
331
- s3.EventType.OBJECT_CREATED_COPY,
332
- new s3n.LambdaDestination(lambdaEmailConverter),
333
- { prefix: 'today/' },
334
- )
335
- }
336
- }
@@ -1,32 +0,0 @@
1
- import type { Construct } from 'constructs';
2
- import type { NestedCloudProps } from '../types';
3
-
4
- export declare interface FileSystemStackProps extends NestedCloudProps {
5
- vpc: ec2.Vpc
6
- }
7
- export declare class FileSystemStack {
8
- fileSystem: efs.FileSystem
9
- accessPoint: efs.AccessPoint
10
-
11
- constructor(scope: Construct, props: FileSystemStackProps) {
12
- this.fileSystem = new efs.FileSystem(scope, 'FileSystem', {
13
- fileSystemName: `${props.slug}-${props.appEnv}-efs`,
14
- vpc: props.vpc,
15
- removalPolicy: RemovalPolicy.DESTROY,
16
- lifecyclePolicy: efs.LifecyclePolicy.AFTER_7_DAYS,
17
- performanceMode: efs.PerformanceMode.GENERAL_PURPOSE,
18
- throughputMode: efs.ThroughputMode.BURSTING,
19
- enableAutomaticBackups: true,
20
- encrypted: true,
21
- })
22
-
23
- this.accessPoint = new efs.AccessPoint(scope, 'FileSystemAccessPoint', {
24
- fileSystem: this.fileSystem,
25
- path: '/',
26
- posixUser: {
27
- uid: '1000',
28
- gid: '1000',
29
- },
30
- })
31
- }
32
- }
package/dist/index.d.ts DELETED
@@ -1,118 +0,0 @@
1
- import type { CloudOptions } from '../types';
2
- import type { Construct } from 'constructs';
3
-
4
- export declare class Cloud extends Stack {
5
- dns: DnsStack
6
- security: SecurityStack
7
- storage: StorageStack
8
- network: NetworkStack
9
- fileSystem: FileSystemStack
10
- jumpBox: JumpBoxStack
11
- docs: DocsStack
12
- email: EmailStack
13
- redirects: RedirectsStack
14
- permissions: PermissionsStack
15
- ai: AiStack
16
- cli: CliStack
17
- api?: ComputeStack
18
- cdn!: CdnStack
19
- queue?: QueueStack
20
- deployment!: DeploymentStack
21
- scope: Construct
22
- props: CloudOptions
23
-
24
- constructor(scope: Construct, id: string, props: CloudOptions) {
25
- super(scope, id, props)
26
- this.scope = scope
27
- this.props = props
28
-
29
- this.dns = new DnsStack(this, props)
30
- this.security = new SecurityStack(this, {
31
- ...props,
32
- zone: this.dns.zone,
33
- })
34
-
35
- this.storage = new StorageStack(this, {
36
- ...props,
37
- kmsKey: this.security.kmsKey,
38
- originAccessIdentity: this.security.originAccessIdentity,
39
- })
40
-
41
- this.network = new NetworkStack(this, props)
42
-
43
- this.fileSystem = new FileSystemStack(this, {
44
- ...props,
45
- vpc: this.network.vpc,
46
- })
47
-
48
- this.jumpBox = new JumpBoxStack(this, {
49
- ...props,
50
- vpc: this.network.vpc,
51
- fileSystem: this.fileSystem.fileSystem,
52
- })
53
-
54
- this.docs = new DocsStack(this, props)
55
-
56
- this.email = new EmailStack(this, {
57
- ...props,
58
- zone: this.dns.zone,
59
- })
60
-
61
- this.redirects = new RedirectsStack(this, props)
62
-
63
- this.permissions = new PermissionsStack(this)
64
-
65
-
66
- this.ai = new AiStack(this, props)
67
-
68
- this.cli = new CliStack(this, props)
69
- }
70
-
71
-
72
- async init(): Promise<void> {
73
- const props = this.props
74
-
75
- if (this.shouldDeployApi()) {
76
- this.api = new ComputeStack(this, {
77
- ...props,
78
- vpc: this.network.vpc,
79
- fileSystem: this.fileSystem.fileSystem,
80
- zone: this.dns.zone,
81
- certificate: this.security.certificate,
82
- })
83
-
84
- this.queue = new QueueStack(this, {
85
- ...props,
86
- cluster: this.api.cluster,
87
- taskDefinition: this.api.taskDefinition,
88
- })
89
-
90
- await this.queue.init()
91
- }
92
-
93
- this.cdn = new CdnStack(this, {
94
- ...props,
95
- publicBucket: this.storage.publicBucket,
96
- docsBucket: this.storage.docsBucket,
97
- logBucket: this.storage.logBucket,
98
- certificate: this.security.certificate,
99
- firewall: this.security.firewall,
100
- originRequestFunction: this.docs.originRequestFunction,
101
- zone: this.dns.zone,
102
- lb: this.api?.lb,
103
- })
104
-
105
- this.deployment = new DeploymentStack(this, {
106
- ...props,
107
- publicBucket: this.storage.publicBucket,
108
- privateBucket: this.storage.privateBucket,
109
- docsBucket: this.storage.docsBucket,
110
- mainDistribution: this.cdn.mainDistribution,
111
- docsDistribution: this.cdn.docsDistribution,
112
- })
113
- }
114
-
115
- shouldDeployApi(): boolean {
116
- return config.cloud.api?.deploy ?? false
117
- }
118
- }
@@ -1,42 +0,0 @@
1
- import type { Construct } from 'constructs';
2
- import type { NestedCloudProps } from '../types';
3
-
4
- export declare interface JumpBoxStackProps extends NestedCloudProps {
5
- vpc: ec2.Vpc
6
- fileSystem: efs.FileSystem
7
- }
8
- export declare class JumpBoxStack {
9
- jumpBox?: ec2.Instance
10
-
11
- constructor(scope: Construct, props: JumpBoxStackProps) {
12
- const role = new iam.Role(scope, 'JumpBoxInstanceRole', {
13
- assumedBy: new iam.ServicePrincipal('ec2.amazonaws.com'),
14
- managedPolicies: [
15
- iam.ManagedPolicy.fromAwsManagedPolicyName('AmazonSSMManagedInstanceCore'),
16
- iam.ManagedPolicy.fromAwsManagedPolicyName('CloudWatchAgentServerPolicy'),
17
- ],
18
- })
19
-
20
- this.jumpBox = new ec2.Instance(scope, 'JumpBox', {
21
- vpc: props.vpc,
22
- instanceType: ec2.InstanceType.of(ec2.InstanceClass.T2, ec2.InstanceSize.MICRO),
23
- machineImage: new ec2.AmazonLinuxImage(),
24
- role,
25
- userData: ec2.UserData.custom(`
26
- #!/bin/bash
27
- yum update -y
28
- yum install -y amazon-efs-utils
29
- yum install -y git
30
- yum install -y https:
31
- mkdir /mnt/efs
32
- mount -t efs ${props.fileSystem.fileSystemId}:/ /mnt/efs
33
- git clone https:
34
- `),
35
- })
36
-
37
- new Output(scope, 'JumpBoxInstanceId', {
38
- value: this.jumpBox.instanceId,
39
- description: 'The ID of the EC2 instance that can be used to SSH into the Stacks Cloud.',
40
- })
41
- }
42
- }
package/dist/network.d.ts DELETED
@@ -1,29 +0,0 @@
1
- import type { Construct } from 'constructs';
2
- import type { NestedCloudProps } from '../types';
3
-
4
- export declare interface NetworkStackProps extends NestedCloudProps {
5
- }
6
- export declare class NetworkStack {
7
- vpc: ec2.Vpc
8
-
9
- constructor(scope: Construct, props: NetworkStackProps) {
10
- this.vpc = new ec2.Vpc(scope, 'Network', {
11
- vpcName: `${props.slug}-${props.appEnv}-vpc`,
12
- ipAddresses: ec2.IpAddresses.cidr('10.0.0.0/16'),
13
- maxAzs: 3,
14
- natGateways: 0,
15
- subnetConfiguration: [
16
- {
17
- name: 'public-subnet-1',
18
- subnetType: ec2.SubnetType.PUBLIC,
19
- cidrMask: 24,
20
- },
21
- {
22
- name: 'private-subnet-1',
23
- subnetType: ec2.SubnetType.PRIVATE_ISOLATED,
24
- cidrMask: 28,
25
- },
26
- ],
27
- })
28
- }
29
- }
@@ -1,5 +0,0 @@
1
- declare const config: {
2
- suffix: '.html';
3
- removeTrailingSlash: false
4
- };
5
- export declare function handler(event: any, context: any, callback: any): void;
@@ -1,31 +0,0 @@
1
- // src/edge/origin-request.ts
2
- var config = {
3
- suffix: ".html",
4
- removeTrailingSlash: false
5
- };
6
- var regexSuffixless = /\/[^/.]+$/;
7
- var regexTrailingSlash = /.+\/$/;
8
- function handler(event, context, callback) {
9
- const { request } = event.Records[0].cf;
10
- const { uri } = request;
11
- const { suffix } = config;
12
- if (uri === "/") {
13
- request.uri = "/index.html";
14
- callback(null, request);
15
- return;
16
- }
17
- if (uri.match(regexSuffixless)) {
18
- request.uri = uri + suffix;
19
- callback(null, request);
20
- return;
21
- }
22
- if (uri.match(regexTrailingSlash)) {
23
- request.uri = `${uri.slice(0, -1)}.html`;
24
- callback(null, request);
25
- return;
26
- }
27
- callback(null, request);
28
- }
29
- export {
30
- handler
31
- };
@@ -1,25 +0,0 @@
1
- import type { Construct } from 'constructs';
2
- import type { NestedCloudProps } from '../types';
3
-
4
- export declare interface PermissionsStackProps extends NestedCloudProps {
5
- }
6
- export declare class PermissionsStack {
7
- constructor(scope: Construct) {
8
- const teamName = config.team.name
9
- const users = config.team.members
10
- const password = env.AWS_DEFAULT_PASSWORD || string.random()
11
-
12
- for (const name in users) {
13
- const id = `User${string.pascalCase(teamName)}${string.pascalCase(name)}`
14
- const userName = string.slug(`${teamName}-${name}`)
15
- const user = new iam.User(scope, id, {
16
- userName,
17
- password: SecretValue.unsafePlainText(password),
18
- passwordResetRequired: true,
19
- })
20
-
21
- user.addManagedPolicy(iam.ManagedPolicy.fromAwsManagedPolicyName('AdministratorAccess'))
22
-
23
- }
24
- }
25
- }