@stacksjs/cloud 0.67.0 → 0.68.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.
Files changed (45) hide show
  1. package/dist/ai.d.ts +20 -0
  2. package/dist/cdn.d.ts +271 -0
  3. package/dist/cli.d.ts +12 -0
  4. package/dist/compute.d.ts +221 -0
  5. package/dist/database.d.ts +29 -0
  6. package/dist/deployment.d.ts +60 -0
  7. package/dist/dns.d.ts +34 -0
  8. package/dist/docs.d.ts +34 -0
  9. package/dist/email.d.ts +336 -0
  10. package/dist/file-system.d.ts +32 -0
  11. package/dist/helpers.d.ts +50 -50
  12. package/dist/index.d.ts +2 -2
  13. package/dist/index.js +19 -28
  14. package/dist/jump-box.d.ts +42 -0
  15. package/dist/network.d.ts +29 -0
  16. package/dist/origin-request.d.ts +5 -0
  17. package/dist/permissions.d.ts +25 -0
  18. package/dist/queue.d.ts +144 -0
  19. package/dist/redirects.d.ts +45 -0
  20. package/dist/security.d.ts +149 -0
  21. package/dist/storage.d.ts +189 -0
  22. package/dist/types.d.ts +26 -25
  23. package/package.json +18 -18
  24. package/dist/cloud/ai.d.ts +0 -6
  25. package/dist/cloud/cache.d.ts +0 -0
  26. package/dist/cloud/cdn.d.ts +0 -34
  27. package/dist/cloud/cli.d.ts +0 -6
  28. package/dist/cloud/compute.d.ts +0 -17
  29. package/dist/cloud/dashboard.d.ts +0 -0
  30. package/dist/cloud/database.d.ts +0 -11
  31. package/dist/cloud/deployment.d.ts +0 -17
  32. package/dist/cloud/dns.d.ts +0 -7
  33. package/dist/cloud/docs.d.ts +0 -8
  34. package/dist/cloud/email.d.ts +0 -10
  35. package/dist/cloud/file-system.d.ts +0 -12
  36. package/dist/cloud/index.d.ts +0 -42
  37. package/dist/cloud/jump-box.d.ts +0 -12
  38. package/dist/cloud/network.d.ts +0 -8
  39. package/dist/cloud/permissions.d.ts +0 -6
  40. package/dist/cloud/queue.d.ts +0 -22
  41. package/dist/cloud/redirects.d.ts +0 -8
  42. package/dist/cloud/search-engine.d.ts +0 -0
  43. package/dist/cloud/security.d.ts +0 -15
  44. package/dist/cloud/storage.d.ts +0 -21
  45. package/dist/edge/origin-request.d.ts +0 -1
@@ -0,0 +1,42 @@
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
+ }
@@ -0,0 +1,29 @@
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
+ }
@@ -0,0 +1,5 @@
1
+ declare const config: {
2
+ suffix: '.html';
3
+ removeTrailingSlash: false
4
+ };
5
+ export declare function handler(event: any, context: any, callback: any): void;
@@ -0,0 +1,25 @@
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
+ }
@@ -0,0 +1,144 @@
1
+ import type { Cluster, TaskDefinition } from 'aws-cdk-lib/aws-ecs';
2
+ import type { Construct } from 'constructs';
3
+ import type { NestedCloudProps } from '../types';
4
+
5
+ export declare interface QueueStackProps extends NestedCloudProps {
6
+ cluster: Cluster
7
+ taskDefinition: TaskDefinition
8
+ }
9
+ export declare class QueueStack {
10
+ scope: Construct
11
+ props: QueueStackProps
12
+
13
+ constructor(scope: Construct, props: QueueStackProps) {
14
+ this.scope = scope
15
+ this.props = props
16
+ }
17
+
18
+ async init(): Promise<void> {
19
+ const jobsDir = path.jobsPath()
20
+ const actionsDir = path.appPath('Actions')
21
+ const ormActionDir = path.builtUserActionsPath('src')
22
+
23
+ const jobFiles = await fs.readdir(jobsDir)
24
+ const actionFiles = await fs.readdir(actionsDir)
25
+ const ormActionFiles = await fs.readdir(ormActionDir)
26
+ const jobs = []
27
+
28
+ for (const file of jobFiles) {
29
+ if (!file.endsWith('.ts'))
30
+ continue
31
+
32
+ const jobPath = path.jobsPath(file)
33
+
34
+ const job = await this.loadModule(jobPath)
35
+ this.createQueueRule(job, file)
36
+ jobs.push(job)
37
+ }
38
+
39
+ for (const ormFile of ormActionFiles) {
40
+ if (!ormFile.endsWith('.ts'))
41
+ continue
42
+
43
+ const ormActionPath = path.builtUserActionsPath(`src/${ormFile}`)
44
+
45
+ const ormAction = await this.loadModule(ormActionPath)
46
+ this.createQueueRule(ormAction, ormFile)
47
+ jobs.push(ormAction)
48
+ }
49
+
50
+ for (const file of actionFiles) {
51
+ if (!file.endsWith('.ts'))
52
+ continue
53
+
54
+ const actionPath = path.appPath(`Actions/${file}`)
55
+
56
+ const action = await this.loadModule(actionPath)
57
+ this.createQueueRule(action, file)
58
+ jobs.push(action)
59
+ }
60
+ }
61
+
62
+ cronScheduleFromRate(rate: string): {
63
+ minute?: string
64
+ hour?: string
65
+ month?: string
66
+ weekDay?: string
67
+ year?: string
68
+ } {
69
+ const parts = rate.split(' ')
70
+ return {
71
+ minute: parts[0],
72
+ hour: parts[1],
73
+ month: parts[2],
74
+ weekDay: parts[3],
75
+ year: parts[4],
76
+ }
77
+ }
78
+
79
+ async loadModule(filePath: string): Promise<{ default: any }> {
80
+ const jobModule = await import(filePath)
81
+
82
+ return jobModule
83
+ }
84
+
85
+ createQueueRule(module: { default: any }, file: string): void {
86
+ const rate = module.default?.rate
87
+
88
+ if (!rate || module.default?.enabled === false)
89
+ return
90
+
91
+ const schedule = Schedule.cron(this.cronScheduleFromRate(rate))
92
+
93
+ const id = `QueueRule${pascalCase(file.replace('.ts', ''))}`
94
+
95
+ const rule = new Rule(this.scope, id, {
96
+ ruleName: `${this.props.appName}-${this.props.appEnv}-queue-rule-${slug(file.replace('.ts', ''))}`,
97
+ schedule,
98
+ })
99
+
100
+ rule.addTarget(
101
+ new EcsTask({
102
+ cluster: this.props.cluster,
103
+ taskDefinition: this.props.taskDefinition,
104
+ containerOverrides: [
105
+ {
106
+ containerName: `${this.props.appName}-${this.props.appEnv}-api`,
107
+ environment: [
108
+ {
109
+ name: 'QUEUE_WORKER',
110
+ value: 'true',
111
+ },
112
+ {
113
+ name: 'JOB',
114
+ value: file,
115
+ },
116
+ {
117
+ name: 'JOB_BACKOFF_FACTOR',
118
+ value: module.default?.backoffFactor,
119
+ },
120
+ {
121
+ name: 'JOB_RETRIES',
122
+ value: module.default?.tries,
123
+ },
124
+ {
125
+ name: 'JOB_INITIAL_DELAY',
126
+ value: module.default?.initialDelay,
127
+ },
128
+ {
129
+ name: 'JOB_JITTER',
130
+ value: module.default?.jitter,
131
+ },
132
+ ],
133
+ },
134
+ ],
135
+
136
+ retryAttempts: 1,
137
+
138
+ subnetSelection: {
139
+ subnetType: ec2.SubnetType.PUBLIC,
140
+ },
141
+ }),
142
+ )
143
+ }
144
+ }
@@ -0,0 +1,45 @@
1
+ import type { Construct } from 'constructs';
2
+ import type { NestedCloudProps } from '../types';
3
+
4
+ export declare interface RedirectsStackProps extends NestedCloudProps {
5
+ }
6
+ export declare class RedirectsStack {
7
+ redirectZones: route53.IHostedZone[] = []
8
+
9
+ constructor(scope: Construct, props: RedirectsStackProps) {
10
+ config.dns.redirects?.forEach((redirect: string) => {
11
+ const slug = redirect
12
+ .split('.')
13
+ .map((part: string, index: number) => (index === 0 ? part : part.charAt(0).toUpperCase() + part.slice(1)))
14
+ .join('')
15
+ const hostedZone = route53.HostedZone.fromLookup(scope, 'HostedZone', {
16
+ domainName: redirect,
17
+ })
18
+
19
+ const redirectBucket = new s3.Bucket(scope, `RedirectBucket${slug}`, {
20
+ bucketName: `${redirect}-redirect`,
21
+ websiteRedirect: {
22
+ hostName: props.domain,
23
+ protocol: s3.RedirectProtocol.HTTPS,
24
+ },
25
+ removalPolicy: RemovalPolicy.DESTROY,
26
+ autoDeleteObjects: true,
27
+ })
28
+
29
+ new route53.CnameRecord(scope, `RedirectRecord${slug}`, {
30
+ zone: hostedZone,
31
+ recordName: 'redirect',
32
+ domainName: redirectBucket.bucketWebsiteDomainName,
33
+ })
34
+ })
35
+
36
+ config.dns.redirects?.forEach((redirect: string) => {
37
+ const slug = redirect
38
+ .split('.')
39
+ .map((part: string, index: number) => (index === 0 ? part : part.charAt(0).toUpperCase() + part.slice(1)))
40
+ .join('')
41
+ const hostedZone = route53.HostedZone.fromLookup(scope, `RedirectHostedZone${slug}`, { domainName: redirect })
42
+ this.redirectZones.push(hostedZone)
43
+ })
44
+ }
45
+ }
@@ -0,0 +1,149 @@
1
+ import type { Construct } from 'constructs';
2
+ import type { NestedCloudProps } from '../types';
3
+
4
+ export declare interface StorageStackProps extends NestedCloudProps {
5
+ zone: route53.IHostedZone
6
+ }
7
+ export declare class SecurityStack {
8
+ firewall: wafv2.CfnWebACL
9
+ kmsKey: kms.Key
10
+ certificate: acm.Certificate
11
+ originAccessIdentity: cloudfront.OriginAccessIdentity
12
+
13
+ constructor(scope: Construct, props: StorageStackProps) {
14
+ const firewallOptions = config.cloud.firewall
15
+
16
+ if (!firewallOptions)
17
+ throw new Error('No firewall options found in config')
18
+
19
+ const options = {
20
+ defaultAction: { allow: {} },
21
+ scope: 'CLOUDFRONT',
22
+ visibilityConfig: {
23
+ sampledRequestsEnabled: true,
24
+ cloudWatchMetricsEnabled: true,
25
+ metricName: 'firewallMetric',
26
+ },
27
+ rules: this.getFirewallRules(scope),
28
+ }
29
+
30
+ this.firewall = new wafv2.CfnWebACL(scope, 'StacksWebFirewall', options)
31
+ Tags.of(this.firewall).add('Name', 'waf-cloudfront', { priority: 300 })
32
+ Tags.of(this.firewall).add('Purpose', 'CloudFront', { priority: 300 })
33
+ Tags.of(this.firewall).add('CreatedBy', 'CloudFormation', {
34
+ priority: 300,
35
+ })
36
+
37
+ this.kmsKey = new kms.Key(scope, 'EncryptionKey', {
38
+ alias: 'stacks-encryption-key',
39
+ description: 'KMS key for Stacks Cloud',
40
+ enableKeyRotation: true,
41
+ removalPolicy: RemovalPolicy.DESTROY,
42
+ pendingWindow: Duration.days(30),
43
+ })
44
+
45
+ this.certificate = new acm.Certificate(scope, 'Certificate', {
46
+ domainName: props.domain,
47
+ validation: acm.CertificateValidation.fromDns(props.zone),
48
+ subjectAlternativeNames: [`www.${props.domain}`, `api.${props.domain}`, `docs.${props.domain}`],
49
+ })
50
+
51
+ this.originAccessIdentity = new cloudfront.OriginAccessIdentity(scope, 'OAI')
52
+ }
53
+
54
+ getFirewallRules(scope: Construct): wafv2.CfnWebACL.RuleProperty[] {
55
+ const rules: wafv2.CfnWebACL.RuleProperty[] = []
56
+ const priorities = []
57
+
58
+ if (config.security.firewall?.countryCodes?.length) {
59
+ priorities.push(1)
60
+ rules.push({
61
+ name: 'CountryRule',
62
+ priority: priorities.length,
63
+ statement: {
64
+ geoMatchStatement: {
65
+ countryCodes: config.security.firewall.countryCodes as string[],
66
+ },
67
+ },
68
+ action: {
69
+ block: {},
70
+ },
71
+ visibilityConfig: {
72
+ sampledRequestsEnabled: true,
73
+ cloudWatchMetricsEnabled: true,
74
+ metricName: 'CountryRule',
75
+ },
76
+ })
77
+ }
78
+
79
+ if (config.security.firewall?.ipAddresses?.length) {
80
+ const ipSet = new wafv2.CfnIPSet(scope, 'IpSet', {
81
+ name: 'IpSet',
82
+ description: 'IP Set',
83
+ scope: 'CLOUDFRONT',
84
+ addresses: config.security.firewall.ipAddresses as string[],
85
+ ipAddressVersion: 'IPV4',
86
+ })
87
+
88
+ priorities.push(1)
89
+ rules.push({
90
+ name: 'IpAddressRule',
91
+ priority: priorities.length,
92
+ statement: {
93
+ ipSetReferenceStatement: {
94
+ arn: ipSet.attrArn,
95
+ },
96
+ },
97
+ action: {
98
+ block: {},
99
+ },
100
+ visibilityConfig: {
101
+ sampledRequestsEnabled: true,
102
+ cloudWatchMetricsEnabled: true,
103
+ metricName: 'IpAddressRule',
104
+ },
105
+ })
106
+ }
107
+
108
+ if (config.security.firewall?.httpHeaders?.length) {
109
+ config.security.firewall.httpHeaders.forEach((header: string | undefined, index: number) => {
110
+ priorities.push(1)
111
+ rules.push({
112
+ name: `HttpHeaderRule${index}`,
113
+ priority: priorities.length,
114
+ statement: {
115
+ byteMatchStatement: {
116
+ fieldToMatch: {
117
+ singleHeader: {
118
+ name: header,
119
+ },
120
+ },
121
+ positionalConstraint: 'EXACTLY',
122
+ searchString: 'true',
123
+ textTransformations: [
124
+ {
125
+ priority: 0,
126
+ type: 'NONE',
127
+ },
128
+ ],
129
+ },
130
+ },
131
+ action: {
132
+ block: {},
133
+ },
134
+ visibilityConfig: {
135
+ sampledRequestsEnabled: true,
136
+ cloudWatchMetricsEnabled: true,
137
+ metricName: `HttpHeaderRule${index}`,
138
+ },
139
+ })
140
+ })
141
+ }
142
+
143
+
144
+
145
+
146
+
147
+ return rules
148
+ }
149
+ }
@@ -0,0 +1,189 @@
1
+ import type { Construct } from 'constructs';
2
+ import type { NestedCloudProps } from '../types';
3
+
4
+ export declare interface StorageStackProps extends NestedCloudProps {
5
+ kmsKey: kms.Key
6
+ originAccessIdentity: cloudfront.OriginAccessIdentity
7
+ }
8
+ export declare class StorageStack {
9
+ publicBucket: s3.Bucket
10
+ privateBucket: s3.Bucket
11
+ docsBucket?: s3.Bucket
12
+ logBucket: s3.Bucket
13
+ bucketPrefix: string
14
+ vault: backup.BackupVault
15
+ backupPlan: backup.BackupPlan
16
+ backupRole: iam.Role
17
+
18
+ constructor(scope: Construct, props: StorageStackProps) {
19
+ this.bucketPrefix = `${props.slug}-${props.appEnv}`
20
+
21
+ this.publicBucket = new s3.Bucket(scope, 'PublicBucket', {
22
+ bucketName: `${this.bucketPrefix}-public-${props.timestamp}`,
23
+ versioned: true,
24
+ autoDeleteObjects: true,
25
+ removalPolicy: RemovalPolicy.DESTROY,
26
+ encryption: s3.BucketEncryption.S3_MANAGED,
27
+ websiteIndexDocument: 'index.html',
28
+ websiteErrorDocument: 'index.html',
29
+ publicReadAccess: true,
30
+ blockPublicAccess: s3.BlockPublicAccess.BLOCK_ACLS,
31
+ })
32
+
33
+ Tags.of(this.publicBucket).add('daily-backup', 'true')
34
+
35
+ if (this.shouldDeployDocs()) {
36
+ this.docsBucket = new s3.Bucket(scope, 'DocsBucket', {
37
+ bucketName: `${this.bucketPrefix}-docs-${props.timestamp}`,
38
+ versioned: true,
39
+ autoDeleteObjects: true,
40
+ removalPolicy: RemovalPolicy.DESTROY,
41
+ encryption: s3.BucketEncryption.S3_MANAGED,
42
+ websiteIndexDocument: 'index.html',
43
+ websiteErrorDocument: 'index.html',
44
+ publicReadAccess: true,
45
+ blockPublicAccess: s3.BlockPublicAccess.BLOCK_ACLS,
46
+ })
47
+
48
+ Tags.of(this.docsBucket).add('weekly-backup', 'true')
49
+ }
50
+
51
+ this.privateBucket = new s3.Bucket(scope, 'PrivateBucket', {
52
+ bucketName: `${this.bucketPrefix}-private-${props.timestamp}`,
53
+ versioned: true,
54
+ removalPolicy: RemovalPolicy.DESTROY,
55
+ autoDeleteObjects: true,
56
+ encryption: s3.BucketEncryption.S3_MANAGED,
57
+ enforceSSL: true,
58
+ publicReadAccess: false,
59
+ blockPublicAccess: {
60
+ blockPublicAcls: true,
61
+ blockPublicPolicy: true,
62
+ ignorePublicAcls: true,
63
+ restrictPublicBuckets: true,
64
+ },
65
+ })
66
+
67
+ Tags.of(this.privateBucket).add('daily-backup', 'true')
68
+
69
+ this.logBucket = new s3.Bucket(scope, 'LogsBucket', {
70
+ bucketName: `${this.bucketPrefix}-logs-${props.timestamp}`,
71
+ removalPolicy: RemovalPolicy.RETAIN,
72
+ blockPublicAccess: new s3.BlockPublicAccess({
73
+ blockPublicAcls: false,
74
+ ignorePublicAcls: true,
75
+ blockPublicPolicy: true,
76
+ restrictPublicBuckets: true,
77
+ }),
78
+ objectOwnership: s3.ObjectOwnership.BUCKET_OWNER_PREFERRED,
79
+ })
80
+
81
+ Tags.of(this.logBucket).add('daily-backup', 'true')
82
+
83
+ this.backupRole = this.createBackupRole(scope)
84
+
85
+ this.vault = new backup.BackupVault(scope, 'BackupVault', {
86
+ backupVaultName: `${props.slug}-${props.appEnv}-daily-backup-vault`,
87
+ encryptionKey: props.kmsKey,
88
+ removalPolicy: RemovalPolicy.DESTROY,
89
+ })
90
+
91
+ this.backupPlan = backup.BackupPlan.daily35DayRetention(scope, 'BackupPlan', this.vault)
92
+
93
+ this.backupPlan.addSelection('Selection', {
94
+ role: this.backupRole,
95
+ resources: [backup.BackupResource.fromTag('daily-backup', 'true')],
96
+ })
97
+ }
98
+
99
+ createBackupRole(scope: Construct): iam.Role {
100
+ const backupRole = new iam.Role(scope, 'BackupRole', {
101
+ assumedBy: new iam.ServicePrincipal('backup.amazonaws.com'),
102
+ })
103
+
104
+ backupRole.addToPolicy(
105
+ new iam.PolicyStatement({
106
+ actions: [
107
+ 's3:GetInventoryConfiguration',
108
+ 's3:PutInventoryConfiguration',
109
+ 's3:ListBucketVersions',
110
+ 's3:ListBucket',
111
+ 's3:GetBucketVersioning',
112
+ 's3:GetBucketNotification',
113
+ 's3:PutBucketNotification',
114
+ 's3:GetBucketLocation',
115
+ 's3:GetBucketTagging',
116
+ ],
117
+ resources: ['arn:aws:s3:::*'],
118
+ sid: 'S3BucketBackupPermissions',
119
+ }),
120
+ )
121
+
122
+ backupRole.addToPolicy(
123
+ new iam.PolicyStatement({
124
+ actions: [
125
+ 's3:GetObjectAcl',
126
+ 's3:GetObject',
127
+ 's3:GetObjectVersionTagging',
128
+ 's3:GetObjectVersionAcl',
129
+ 's3:GetObjectTagging',
130
+ 's3:GetObjectVersion',
131
+ ],
132
+ resources: ['arn:aws:s3:::*/*'],
133
+ sid: 'S3ObjectBackupPermissions',
134
+ }),
135
+ )
136
+
137
+ backupRole.addToPolicy(
138
+ new iam.PolicyStatement({
139
+ actions: ['s3:ListAllMyBuckets'],
140
+ resources: ['*'],
141
+ sid: 'S3GlobalPermissions',
142
+ }),
143
+ )
144
+
145
+ backupRole.addToPolicy(
146
+ new iam.PolicyStatement({
147
+ actions: ['kms:Decrypt', 'kms:DescribeKey'],
148
+ resources: ['*'],
149
+ sid: 'KMSBackupPermissions',
150
+ conditions: {
151
+ StringLike: {
152
+ 'kms:ViaService': 's3.*.amazonaws.com',
153
+ },
154
+ },
155
+ }),
156
+ )
157
+
158
+ backupRole.addToPolicy(
159
+ new iam.PolicyStatement({
160
+ actions: [
161
+ 'events:DescribeRule',
162
+ 'events:EnableRule',
163
+ 'events:PutRule',
164
+ 'events:DeleteRule',
165
+ 'events:PutTargets',
166
+ 'events:RemoveTargets',
167
+ 'events:ListTargetsByRule',
168
+ 'events:DisableRule',
169
+ ],
170
+ resources: ['arn:aws:events:*:*:rule/AwsBackupManagedRule*'],
171
+ sid: 'EventsPermissions',
172
+ }),
173
+ )
174
+
175
+ backupRole.addToPolicy(
176
+ new iam.PolicyStatement({
177
+ actions: ['cloudwatch:GetMetricData', 'events:ListRules'],
178
+ resources: ['*'],
179
+ sid: 'EventsMetricsGlobalPermissions',
180
+ }),
181
+ )
182
+
183
+ return backupRole
184
+ }
185
+
186
+ shouldDeployDocs(): boolean {
187
+ return (hasFiles(p.projectPath('docs')) || config.app.docMode) ?? false
188
+ }
189
+ }
package/dist/types.d.ts CHANGED
@@ -1,26 +1,27 @@
1
- import type { AppEnvType } from "@stacksjs/types";
2
- import type { StackProps } from "aws-cdk-lib";
3
- export interface CloudOptions extends StackProps {
4
- name: string;
5
- env: {
6
- account: string;
7
- region: string;
8
- };
9
- slug: string;
10
- appEnv: AppEnvType;
11
- appName: string;
12
- domain: string;
13
- timestamp: string;
14
- }
15
- export interface NestedCloudProps {
16
- name: string;
17
- env: {
18
- account: string;
19
- region: string;
20
- };
21
- slug: string;
22
- appEnv: AppEnvType;
23
- appName: string;
24
- domain: string;
25
- timestamp: string;
1
+ import type { AppEnvType } from '@stacksjs/types';
2
+ import type { StackProps } from 'aws-cdk-lib';
3
+
4
+ export declare interface CloudOptions extends StackProps {
5
+ name: string
6
+ env: {
7
+ account: string
8
+ region: string
9
+ }
10
+ slug: string
11
+ appEnv: AppEnvType
12
+ appName: string
13
+ domain: string
14
+ timestamp: string
26
15
  }
16
+ export declare interface NestedCloudProps {
17
+ name: string
18
+ env: {
19
+ account: string
20
+ region: string
21
+ }
22
+ slug: string
23
+ appEnv: AppEnvType
24
+ appName: string
25
+ domain: string
26
+ timestamp: string
27
+ }