@stacksjs/cloud 0.61.24 → 0.63.0
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/index.js +170 -137
- package/dist/index.js.map +27 -0
- package/package.json +33 -34
- package/src/cloud/aws-sdk-layer/nodejs/package-lock.json +6 -6
- package/src/cloud/aws-sdk-layer/nodejs/package.json +2 -2
- package/src/cloud/cdn.ts +47 -47
- package/src/cloud/compute.ts +12 -3
- package/src/cloud/deployment.ts +34 -8
- package/src/cloud/docs.ts +2 -1
- package/src/cloud/index.ts +31 -24
- package/src/cloud/queue.ts +2 -4
- package/src/cloud/router-layer/nodejs/package.json +2 -2
- package/src/cloud/security.ts +4 -4
- package/src/cloud/storage.ts +19 -0
- package/src/helpers.ts +10 -4
package/dist/index.js
CHANGED
|
@@ -10,7 +10,7 @@ import {ContactType, Route53Domains} from "@aws-sdk/client-route-53-domains";
|
|
|
10
10
|
import {ListBucketsCommand, S3} from "@aws-sdk/client-s3";
|
|
11
11
|
import {SSM} from "@aws-sdk/client-ssm";
|
|
12
12
|
import {runCommand} from "@stacksjs/cli";
|
|
13
|
-
import {config as
|
|
13
|
+
import {config as config3} from "@stacksjs/config";
|
|
14
14
|
import {err, handleError, ok} from "@stacksjs/error-handling";
|
|
15
15
|
import {log} from "@stacksjs/logging";
|
|
16
16
|
import {path as p} from "@stacksjs/path";
|
|
@@ -97,7 +97,7 @@ async function getJumpBoxInstanceId(name) {
|
|
|
97
97
|
}
|
|
98
98
|
]
|
|
99
99
|
});
|
|
100
|
-
if (data.Reservations?.[0]
|
|
100
|
+
if (data.Reservations?.[0]?.Instances?.[0])
|
|
101
101
|
return data.Reservations[0].Instances[0].InstanceId;
|
|
102
102
|
return;
|
|
103
103
|
}
|
|
@@ -122,7 +122,7 @@ async function deleteJumpBox(stackName) {
|
|
|
122
122
|
async function deleteIamUsers() {
|
|
123
123
|
const iam = new IAM({ region: "us-east-1" });
|
|
124
124
|
const data = await iam.listUsers({});
|
|
125
|
-
const teamName = slug(
|
|
125
|
+
const teamName = slug(config3.team.name);
|
|
126
126
|
const users = data.Users?.filter((user) => {
|
|
127
127
|
const userNameLower = user.UserName?.toLowerCase();
|
|
128
128
|
return userNameLower !== "stacks" && userNameLower !== teamName.toLowerCase() && userNameLower?.includes(teamName.toLowerCase());
|
|
@@ -273,7 +273,7 @@ async function hasBeenDeployed() {
|
|
|
273
273
|
const s3 = new S3({ region: "us-east-1" });
|
|
274
274
|
try {
|
|
275
275
|
const response = await s3.send(new ListBucketsCommand({}));
|
|
276
|
-
return ok(response.Buckets?.some((bucket) => bucket.Name?.includes(
|
|
276
|
+
return ok(response.Buckets?.some((bucket) => bucket.Name?.includes(config3.app.name?.toLocaleLowerCase() || "stacks")) || false);
|
|
277
277
|
} catch (error) {
|
|
278
278
|
console.error(error);
|
|
279
279
|
return err(handleError("Error checking if the app has been deployed"));
|
|
@@ -307,7 +307,7 @@ async function addJumpBox(stackName) {
|
|
|
307
307
|
const client = new EFSClient({ region: "us-east-1" });
|
|
308
308
|
const command = new DescribeFileSystemsCommand({});
|
|
309
309
|
const data = await client.send(command);
|
|
310
|
-
const fileSystemName = `stacks-${
|
|
310
|
+
const fileSystemName = `stacks-${config3.app.env}-efs`;
|
|
311
311
|
const fileSystem = data.FileSystems?.find((fs) => fs.Name === fileSystemName);
|
|
312
312
|
const fileSystemId = fileSystem?.FileSystemId;
|
|
313
313
|
if (!fileSystem || !fileSystemId)
|
|
@@ -360,7 +360,7 @@ async function getJumpBoxSecurityGroupName() {
|
|
|
360
360
|
return err("Jump-box not found");
|
|
361
361
|
const ec2 = new EC2({ region: "us-east-1" });
|
|
362
362
|
const data = await ec2.describeInstances({ InstanceIds: [jumpBoxId] });
|
|
363
|
-
if (data.Reservations?.[0]
|
|
363
|
+
if (data.Reservations?.[0]?.Instances?.[0]) {
|
|
364
364
|
const instance = data.Reservations[0].Instances[0];
|
|
365
365
|
const securityGroups = instance.SecurityGroups;
|
|
366
366
|
if (securityGroups?.[0])
|
|
@@ -371,7 +371,7 @@ async function getJumpBoxSecurityGroupName() {
|
|
|
371
371
|
async function getSecurityGroupFromInstanceId(instanceId) {
|
|
372
372
|
const ec2 = new EC2({ region: "us-east-1" });
|
|
373
373
|
const data = await ec2.describeInstances({ InstanceIds: [instanceId] });
|
|
374
|
-
if (data.Reservations?.[0]
|
|
374
|
+
if (data.Reservations?.[0]?.Instances?.[0]) {
|
|
375
375
|
const instance = data.Reservations[0].Instances[0];
|
|
376
376
|
const securityGroups = instance.SecurityGroups;
|
|
377
377
|
if (securityGroups?.[0])
|
|
@@ -416,14 +416,17 @@ async function getOrCreateTimestamp() {
|
|
|
416
416
|
return timestamp;
|
|
417
417
|
}
|
|
418
418
|
}
|
|
419
|
-
|
|
419
|
+
async function getCloudFrontDistributionId() {
|
|
420
|
+
return "";
|
|
421
|
+
}
|
|
422
|
+
var appEnv = config3.app.env === "local" ? "dev" : config3.app.env;
|
|
420
423
|
var cloudName = `stacks-cloud-${appEnv}`;
|
|
421
424
|
// src/cloud/index.ts
|
|
422
|
-
import {config as
|
|
425
|
+
import {config as config21} from "@stacksjs/config";
|
|
423
426
|
import {Stack as Stack2} from "aws-cdk-lib";
|
|
424
427
|
|
|
425
428
|
// src/cloud/ai.ts
|
|
426
|
-
import {config as
|
|
429
|
+
import {config as config5} from "@stacksjs/config";
|
|
427
430
|
import {Duration, CfnOutput as Output, aws_iam as iam, aws_lambda as lambda} from "aws-cdk-lib";
|
|
428
431
|
|
|
429
432
|
class AiStack {
|
|
@@ -438,7 +441,7 @@ class AiStack {
|
|
|
438
441
|
const bedrockAccessPolicy = new iam.PolicyStatement({
|
|
439
442
|
effect: iam.Effect.ALLOW,
|
|
440
443
|
actions: ["bedrock:InvokeModel", "bedrock:InvokeModelWithResponseStream"],
|
|
441
|
-
resources:
|
|
444
|
+
resources: config5.ai.models?.map((model) => `arn:aws:bedrock:us-east-1::foundation-model/${model}`)
|
|
442
445
|
});
|
|
443
446
|
const bedrockAccessRole = new iam.Role(scope, "BedrockAccessRole", {
|
|
444
447
|
assumedBy: new iam.ServicePrincipal("lambda.amazonaws.com"),
|
|
@@ -495,7 +498,7 @@ class AiStack {
|
|
|
495
498
|
}
|
|
496
499
|
|
|
497
500
|
// src/cloud/cdn.ts
|
|
498
|
-
import {config as
|
|
501
|
+
import {config as config7} from "@stacksjs/config";
|
|
499
502
|
import {env as env2} from "@stacksjs/env";
|
|
500
503
|
import {path as p2} from "@stacksjs/path";
|
|
501
504
|
import {hasFiles} from "@stacksjs/storage";
|
|
@@ -508,7 +511,6 @@ aws_cloudfront_origins as origins,
|
|
|
508
511
|
aws_route53 as route53,
|
|
509
512
|
aws_route53_targets as targets
|
|
510
513
|
} from "aws-cdk-lib";
|
|
511
|
-
import * as kinesis from "aws-cdk-lib/aws-kinesis";
|
|
512
514
|
|
|
513
515
|
class CdnStack {
|
|
514
516
|
distribution;
|
|
@@ -524,35 +526,15 @@ class CdnStack {
|
|
|
524
526
|
this.cdnCachePolicy = new cloudfront.CachePolicy(scope, "CdnCachePolicy", {
|
|
525
527
|
comment: "Stacks CDN Cache Policy",
|
|
526
528
|
cachePolicyName: `${props.slug}-${props.appEnv}-cdn-cache-policy`,
|
|
527
|
-
minTtl:
|
|
528
|
-
defaultTtl:
|
|
529
|
-
maxTtl:
|
|
530
|
-
cookieBehavior: this.getCookieBehavior(
|
|
531
|
-
});
|
|
532
|
-
const logStream = new kinesis.Stream(scope, "StacksCdnRealtimeLogStream", {
|
|
533
|
-
streamName: "StacksCdnRealtimeLogStream",
|
|
534
|
-
retentionPeriod: Duration2.days(1),
|
|
535
|
-
shardCount: 1,
|
|
536
|
-
encryption: kinesis.StreamEncryption.UNENCRYPTED
|
|
537
|
-
});
|
|
538
|
-
this.realtimeLogConfig = new cloudfront.RealtimeLogConfig(scope, "StacksRealTimeLogConfig", {
|
|
539
|
-
endPoints: [cloudfront.Endpoint.fromKinesisStream(logStream)],
|
|
540
|
-
fields: [
|
|
541
|
-
"timestamp",
|
|
542
|
-
"c-ip",
|
|
543
|
-
"cs-method",
|
|
544
|
-
"cs-uri-stem",
|
|
545
|
-
"cs-uri-query",
|
|
546
|
-
"cs-referer",
|
|
547
|
-
"cs-user-agent",
|
|
548
|
-
"sc-status"
|
|
549
|
-
],
|
|
550
|
-
samplingRate: 100
|
|
529
|
+
minTtl: config7.cloud.cdn?.minTtl ? Duration2.seconds(config7.cloud.cdn.minTtl) : undefined,
|
|
530
|
+
defaultTtl: config7.cloud.cdn?.defaultTtl ? Duration2.seconds(config7.cloud.cdn.defaultTtl) : undefined,
|
|
531
|
+
maxTtl: config7.cloud.cdn?.maxTtl ? Duration2.seconds(config7.cloud.cdn.maxTtl) : undefined,
|
|
532
|
+
cookieBehavior: this.getCookieBehavior(config7.cloud.cdn?.cookieBehavior)
|
|
551
533
|
});
|
|
552
534
|
this.distribution = new cloudfront.Distribution(scope, "Cdn", {
|
|
553
535
|
domainNames: [props.domain],
|
|
554
536
|
defaultRootObject: "index.html",
|
|
555
|
-
comment: `CDN for ${
|
|
537
|
+
comment: `CDN for ${config7.app.url}`,
|
|
556
538
|
certificate: props.certificate,
|
|
557
539
|
enableLogging: true,
|
|
558
540
|
logBucket: props.logBucket,
|
|
@@ -563,7 +545,7 @@ class CdnStack {
|
|
|
563
545
|
webAclId: props.firewall.attrArn,
|
|
564
546
|
enableIpv6: true,
|
|
565
547
|
defaultBehavior: {
|
|
566
|
-
origin: new origins.S3Origin(props.publicBucket, {
|
|
548
|
+
origin: new origins.S3Origin(config7.app.docMode ? props.docsBucket : props.publicBucket, {
|
|
567
549
|
originAccessIdentity: this.originAccessIdentity
|
|
568
550
|
}),
|
|
569
551
|
edgeLambdas: [
|
|
@@ -572,12 +554,11 @@ class CdnStack {
|
|
|
572
554
|
functionVersion: props.originRequestFunction.currentVersion
|
|
573
555
|
}
|
|
574
556
|
],
|
|
575
|
-
compress:
|
|
557
|
+
compress: config7.cloud.cdn?.compress,
|
|
576
558
|
allowedMethods: this.allowedMethods(),
|
|
577
559
|
cachedMethods: this.cachedMethods(),
|
|
578
560
|
viewerProtocolPolicy: cloudfront.ViewerProtocolPolicy.REDIRECT_TO_HTTPS,
|
|
579
|
-
cachePolicy: this.cdnCachePolicy
|
|
580
|
-
realtimeLogConfig: this.realtimeLogConfig
|
|
561
|
+
cachePolicy: this.cdnCachePolicy
|
|
581
562
|
},
|
|
582
563
|
additionalBehaviors: this.additionalBehaviors(scope, props),
|
|
583
564
|
errorResponses: [
|
|
@@ -614,13 +595,13 @@ class CdnStack {
|
|
|
614
595
|
case "none":
|
|
615
596
|
return cloudfront.CacheCookieBehavior.none();
|
|
616
597
|
case "allowList":
|
|
617
|
-
return cloudfront.CacheCookieBehavior.allowList(...
|
|
598
|
+
return cloudfront.CacheCookieBehavior.allowList(...config7.cloud.cdn?.allowList.cookies || []);
|
|
618
599
|
default:
|
|
619
600
|
return;
|
|
620
601
|
}
|
|
621
602
|
}
|
|
622
603
|
allowedMethods() {
|
|
623
|
-
switch (
|
|
604
|
+
switch (config7.cloud.cdn?.allowedMethods) {
|
|
624
605
|
case "ALL":
|
|
625
606
|
return cloudfront.AllowedMethods.ALLOW_ALL;
|
|
626
607
|
case "GET_HEAD":
|
|
@@ -632,7 +613,7 @@ class CdnStack {
|
|
|
632
613
|
}
|
|
633
614
|
}
|
|
634
615
|
cachedMethods() {
|
|
635
|
-
switch (
|
|
616
|
+
switch (config7.cloud.cdn?.cachedMethods) {
|
|
636
617
|
case "GET_HEAD":
|
|
637
618
|
return cloudfront.CachedMethods.CACHE_GET_HEAD;
|
|
638
619
|
case "GET_HEAD_OPTIONS":
|
|
@@ -668,19 +649,17 @@ class CdnStack {
|
|
|
668
649
|
}
|
|
669
650
|
}
|
|
670
651
|
shouldDeployApi() {
|
|
671
|
-
return
|
|
652
|
+
return config7.cloud.api?.deploy;
|
|
672
653
|
}
|
|
673
654
|
apiBehaviorOptions(scope, props) {
|
|
674
655
|
const hostname = `api.${props.domain}`;
|
|
675
|
-
const origin = (
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
});
|
|
680
|
-
};
|
|
656
|
+
const origin = new origins.HttpOrigin(hostname, {
|
|
657
|
+
originPath: "/",
|
|
658
|
+
protocolPolicy: cloudfront.OriginProtocolPolicy.HTTPS_ONLY
|
|
659
|
+
});
|
|
681
660
|
return {
|
|
682
661
|
"/api": {
|
|
683
|
-
origin
|
|
662
|
+
origin,
|
|
684
663
|
compress: true,
|
|
685
664
|
allowedMethods: cloudfront.AllowedMethods.ALLOW_ALL,
|
|
686
665
|
cachedMethods: cloudfront.CachedMethods.CACHE_GET_HEAD_OPTIONS,
|
|
@@ -689,7 +668,7 @@ class CdnStack {
|
|
|
689
668
|
realtimeLogConfig: this.realtimeLogConfig
|
|
690
669
|
},
|
|
691
670
|
"/api/*": {
|
|
692
|
-
origin
|
|
671
|
+
origin,
|
|
693
672
|
compress: true,
|
|
694
673
|
allowedMethods: cloudfront.AllowedMethods.ALLOW_ALL,
|
|
695
674
|
cachedMethods: cloudfront.CachedMethods.CACHE_GET_HEAD_OPTIONS,
|
|
@@ -699,28 +678,28 @@ class CdnStack {
|
|
|
699
678
|
}
|
|
700
679
|
};
|
|
701
680
|
}
|
|
702
|
-
docsBehaviorOptions(
|
|
681
|
+
docsBehaviorOptions(docsBucket) {
|
|
682
|
+
if (!docsBucket)
|
|
683
|
+
return {};
|
|
684
|
+
const origin = new origins.S3Origin(docsBucket, {
|
|
685
|
+
originAccessIdentity: this.originAccessIdentity,
|
|
686
|
+
originPath: "/"
|
|
687
|
+
});
|
|
703
688
|
return {
|
|
704
689
|
"/docs": {
|
|
705
|
-
origin
|
|
706
|
-
originAccessIdentity: this.originAccessIdentity,
|
|
707
|
-
originPath: "/docs"
|
|
708
|
-
}),
|
|
690
|
+
origin,
|
|
709
691
|
compress: true,
|
|
710
|
-
allowedMethods: this.allowedMethodsFromString(
|
|
711
|
-
cachedMethods: this.cachedMethodsFromString(
|
|
692
|
+
allowedMethods: this.allowedMethodsFromString(config7.cloud.cdn?.allowedMethods),
|
|
693
|
+
cachedMethods: this.cachedMethodsFromString(config7.cloud.cdn?.cachedMethods),
|
|
712
694
|
viewerProtocolPolicy: cloudfront.ViewerProtocolPolicy.REDIRECT_TO_HTTPS,
|
|
713
695
|
cachePolicy: cloudfront.CachePolicy.CACHING_OPTIMIZED,
|
|
714
696
|
realtimeLogConfig: this.realtimeLogConfig
|
|
715
697
|
},
|
|
716
698
|
"/docs/*": {
|
|
717
|
-
origin
|
|
718
|
-
originAccessIdentity: this.originAccessIdentity,
|
|
719
|
-
originPath: "/docs"
|
|
720
|
-
}),
|
|
699
|
+
origin,
|
|
721
700
|
compress: true,
|
|
722
|
-
allowedMethods: this.allowedMethodsFromString(
|
|
723
|
-
cachedMethods: this.cachedMethodsFromString(
|
|
701
|
+
allowedMethods: this.allowedMethodsFromString(config7.cloud.cdn?.allowedMethods),
|
|
702
|
+
cachedMethods: this.cachedMethodsFromString(config7.cloud.cdn?.cachedMethods),
|
|
724
703
|
viewerProtocolPolicy: cloudfront.ViewerProtocolPolicy.REDIRECT_TO_HTTPS,
|
|
725
704
|
cachePolicy: cloudfront.CachePolicy.CACHING_OPTIMIZED,
|
|
726
705
|
realtimeLogConfig: this.realtimeLogConfig
|
|
@@ -787,13 +766,13 @@ class CdnStack {
|
|
|
787
766
|
};
|
|
788
767
|
}
|
|
789
768
|
shouldDeployAiEndpoints() {
|
|
790
|
-
return
|
|
769
|
+
return config7.cloud.ai;
|
|
791
770
|
}
|
|
792
771
|
shouldDeployCliSetup() {
|
|
793
|
-
return
|
|
772
|
+
return config7.cloud.cli;
|
|
794
773
|
}
|
|
795
774
|
shouldDeployDocs() {
|
|
796
|
-
return hasFiles(p2.projectPath("docs"));
|
|
775
|
+
return hasFiles(p2.projectPath("docs")) && !config7.app.docMode;
|
|
797
776
|
}
|
|
798
777
|
additionalBehaviors(scope, props) {
|
|
799
778
|
let behaviorOptions = {};
|
|
@@ -821,9 +800,9 @@ class CdnStack {
|
|
|
821
800
|
keysToRemove.forEach((key) => delete env2[key]);
|
|
822
801
|
behaviorOptions = this.apiBehaviorOptions(scope, props);
|
|
823
802
|
}
|
|
824
|
-
if (this.shouldDeployDocs()
|
|
803
|
+
if (this.shouldDeployDocs()) {
|
|
825
804
|
behaviorOptions = {
|
|
826
|
-
...this.docsBehaviorOptions(props),
|
|
805
|
+
...this.docsBehaviorOptions(props.docsBucket),
|
|
827
806
|
...behaviorOptions
|
|
828
807
|
};
|
|
829
808
|
}
|
|
@@ -926,7 +905,7 @@ class ComputeStack {
|
|
|
926
905
|
});
|
|
927
906
|
const container = this.taskDefinition.addContainer("WebServerContainer", {
|
|
928
907
|
containerName: `${props.appName}-${props.appEnv}-api`,
|
|
929
|
-
image: ecs.ContainerImage.fromAsset(p3.
|
|
908
|
+
image: ecs.ContainerImage.fromAsset(p3.frameworkCloudPath()),
|
|
930
909
|
logging: new ecs.AwsLogDriver({
|
|
931
910
|
streamPrefix: `${props.appName}-${props.appEnv}-web-server-logs`,
|
|
932
911
|
logGroup: new LogGroup(scope, "StacksApiLogs", {
|
|
@@ -1069,8 +1048,12 @@ class ComputeStack {
|
|
|
1069
1048
|
generateStringKey: Object.keys(env4).join(",").length.toString()
|
|
1070
1049
|
}
|
|
1071
1050
|
});
|
|
1072
|
-
|
|
1073
|
-
|
|
1051
|
+
if (service.taskDefinition.executionRole) {
|
|
1052
|
+
secrets.grantRead(service.taskDefinition.executionRole);
|
|
1053
|
+
container.addEnvironment("SECRETS_ARN", secrets.secretArn);
|
|
1054
|
+
} else {
|
|
1055
|
+
throw new Error("Service task execution role is undefined.");
|
|
1056
|
+
}
|
|
1074
1057
|
const apiPrefix = "api";
|
|
1075
1058
|
new Output4(scope, "ApiUrl", {
|
|
1076
1059
|
value: `https://${props.domain}/${apiPrefix}`,
|
|
@@ -1084,21 +1067,23 @@ class ComputeStack {
|
|
|
1084
1067
|
}
|
|
1085
1068
|
|
|
1086
1069
|
// src/cloud/deployment.ts
|
|
1087
|
-
import {config as
|
|
1088
|
-
import {
|
|
1070
|
+
import {config as config9} from "@stacksjs/config";
|
|
1071
|
+
import {path as p4} from "@stacksjs/path";
|
|
1072
|
+
import {hasFiles as hasFiles2} from "@stacksjs/storage";
|
|
1073
|
+
import {docsSourceHash, websiteSourceHash} from "@stacksjs/utils";
|
|
1089
1074
|
import {AssetHashType, aws_s3_deployment as s3deploy} from "aws-cdk-lib";
|
|
1090
1075
|
|
|
1091
1076
|
class DeploymentStack {
|
|
1092
1077
|
privateSource;
|
|
1093
1078
|
docsSource;
|
|
1094
|
-
|
|
1079
|
+
publicSource;
|
|
1095
1080
|
constructor(scope, props) {
|
|
1096
1081
|
this.privateSource = "../../private";
|
|
1097
1082
|
this.docsSource = "../docs/dist/";
|
|
1098
|
-
this.
|
|
1083
|
+
this.publicSource = config9.app.docMode === true ? this.docsSource : "../views/web/dist/";
|
|
1099
1084
|
new s3deploy.BucketDeployment(scope, "Website", {
|
|
1100
1085
|
sources: [
|
|
1101
|
-
s3deploy.Source.asset(this.
|
|
1086
|
+
s3deploy.Source.asset(this.publicSource, {
|
|
1102
1087
|
assetHash: websiteSourceHash(),
|
|
1103
1088
|
assetHashType: AssetHashType.CUSTOM
|
|
1104
1089
|
})
|
|
@@ -1107,10 +1092,30 @@ class DeploymentStack {
|
|
|
1107
1092
|
distribution: props.cdn,
|
|
1108
1093
|
distributionPaths: ["/*"]
|
|
1109
1094
|
});
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1095
|
+
if (this.shouldDeployDocs()) {
|
|
1096
|
+
new s3deploy.BucketDeployment(scope, "Docs", {
|
|
1097
|
+
sources: [
|
|
1098
|
+
s3deploy.Source.asset(this.docsSource, {
|
|
1099
|
+
assetHash: docsSourceHash(),
|
|
1100
|
+
assetHashType: AssetHashType.CUSTOM
|
|
1101
|
+
})
|
|
1102
|
+
],
|
|
1103
|
+
destinationBucket: props.docsBucket,
|
|
1104
|
+
distribution: props.cdn,
|
|
1105
|
+
distributionPaths: ["/docs/*"]
|
|
1106
|
+
});
|
|
1107
|
+
}
|
|
1108
|
+
if (hasFiles2(this.privateSource)) {
|
|
1109
|
+
new s3deploy.BucketDeployment(scope, "PrivateFiles", {
|
|
1110
|
+
sources: [s3deploy.Source.asset(this.privateSource)],
|
|
1111
|
+
destinationBucket: props.privateBucket
|
|
1112
|
+
});
|
|
1113
|
+
} else {
|
|
1114
|
+
console.error(`The path ${this.privateSource} does not have any files`);
|
|
1115
|
+
}
|
|
1116
|
+
}
|
|
1117
|
+
shouldDeployDocs() {
|
|
1118
|
+
return hasFiles2(p4.projectPath("docs")) && !config9.app.docMode;
|
|
1114
1119
|
}
|
|
1115
1120
|
}
|
|
1116
1121
|
|
|
@@ -1146,29 +1151,29 @@ class DnsStack {
|
|
|
1146
1151
|
}
|
|
1147
1152
|
|
|
1148
1153
|
// src/cloud/docs.ts
|
|
1149
|
-
import {config as
|
|
1150
|
-
import {path as
|
|
1151
|
-
import {storage as
|
|
1154
|
+
import {config as config11} from "@stacksjs/config";
|
|
1155
|
+
import {path as p5} from "@stacksjs/path";
|
|
1156
|
+
import {storage as storage4} from "@stacksjs/storage";
|
|
1152
1157
|
import {originRequestFunctionHash} from "@stacksjs/utils";
|
|
1153
1158
|
import {AssetHashType as AssetHashType2, CfnOutput as Output5, RemovalPolicy as RemovalPolicy3, aws_lambda as lambda3} from "aws-cdk-lib";
|
|
1154
1159
|
|
|
1155
1160
|
class DocsStack {
|
|
1156
1161
|
originRequestFunction;
|
|
1157
1162
|
constructor(scope, props) {
|
|
1158
|
-
const docsPrefix =
|
|
1163
|
+
const docsPrefix = "docs";
|
|
1159
1164
|
this.originRequestFunction = new lambda3.Function(scope, "OriginRequestFunction", {
|
|
1160
1165
|
functionName: `${props.slug}-${props.appEnv}-origin-request-${props.timestamp}`,
|
|
1161
1166
|
description: "The Stacks Origin Request function that prettifies URLs",
|
|
1162
1167
|
runtime: lambda3.Runtime.NODEJS_18_X,
|
|
1163
1168
|
handler: "dist/origin-request.handler",
|
|
1164
|
-
code: lambda3.Code.fromAsset(
|
|
1169
|
+
code: lambda3.Code.fromAsset(p5.frameworkCloudPath("dist.zip"), {
|
|
1165
1170
|
assetHash: originRequestFunctionHash(),
|
|
1166
1171
|
assetHashType: AssetHashType2.CUSTOM
|
|
1167
1172
|
})
|
|
1168
1173
|
});
|
|
1169
1174
|
const cfnOriginRequestFunction = this.originRequestFunction.node.defaultChild;
|
|
1170
1175
|
cfnOriginRequestFunction.applyRemovalPolicy(RemovalPolicy3.RETAIN);
|
|
1171
|
-
if (!
|
|
1176
|
+
if (!config11.app.docMode && storage4.hasFiles(p5.projectPath("docs"))) {
|
|
1172
1177
|
new Output5(scope, "DocsUrl", {
|
|
1173
1178
|
value: `https://${props.domain}/${docsPrefix}`,
|
|
1174
1179
|
description: "The URL of the deployed documentation"
|
|
@@ -1178,7 +1183,7 @@ class DocsStack {
|
|
|
1178
1183
|
}
|
|
1179
1184
|
|
|
1180
1185
|
// src/cloud/email.ts
|
|
1181
|
-
import {config as
|
|
1186
|
+
import {config as config13} from "@stacksjs/config";
|
|
1182
1187
|
import {
|
|
1183
1188
|
Duration as Duration5,
|
|
1184
1189
|
RemovalPolicy as RemovalPolicy4,
|
|
@@ -1269,8 +1274,8 @@ class EmailStack {
|
|
|
1269
1274
|
}
|
|
1270
1275
|
}
|
|
1271
1276
|
],
|
|
1272
|
-
recipients:
|
|
1273
|
-
scanEnabled:
|
|
1277
|
+
recipients: config13.email.mailboxes || [],
|
|
1278
|
+
scanEnabled: config13.email.server?.scan || true,
|
|
1274
1279
|
tlsPolicy: "Require"
|
|
1275
1280
|
}
|
|
1276
1281
|
});
|
|
@@ -1548,15 +1553,15 @@ class NetworkStack {
|
|
|
1548
1553
|
}
|
|
1549
1554
|
|
|
1550
1555
|
// src/cloud/permissions.ts
|
|
1551
|
-
import {config as
|
|
1556
|
+
import {config as config15} from "@stacksjs/config";
|
|
1552
1557
|
import {env as env6} from "@stacksjs/env";
|
|
1553
1558
|
import {string} from "@stacksjs/strings";
|
|
1554
1559
|
import {SecretValue, aws_iam as iam4} from "aws-cdk-lib";
|
|
1555
1560
|
|
|
1556
1561
|
class PermissionsStack {
|
|
1557
1562
|
constructor(scope) {
|
|
1558
|
-
const teamName =
|
|
1559
|
-
const users =
|
|
1563
|
+
const teamName = config15.team.name;
|
|
1564
|
+
const users = config15.team.members;
|
|
1560
1565
|
const password = env6.AWS_DEFAULT_PASSWORD || string.random();
|
|
1561
1566
|
for (const name in users) {
|
|
1562
1567
|
const id = `User${string.pascalCase(teamName)}${string.pascalCase(name)}`;
|
|
@@ -1572,7 +1577,7 @@ class PermissionsStack {
|
|
|
1572
1577
|
}
|
|
1573
1578
|
|
|
1574
1579
|
// src/cloud/queue.ts
|
|
1575
|
-
import {path as
|
|
1580
|
+
import {path as path7} from "@stacksjs/path";
|
|
1576
1581
|
import {fs} from "@stacksjs/storage";
|
|
1577
1582
|
import {pascalCase, slug as slug2} from "@stacksjs/strings";
|
|
1578
1583
|
import {aws_ec2 as ec24} from "aws-cdk-lib";
|
|
@@ -1587,9 +1592,9 @@ class QueueStack {
|
|
|
1587
1592
|
this.props = props;
|
|
1588
1593
|
}
|
|
1589
1594
|
async init() {
|
|
1590
|
-
const jobsDir =
|
|
1591
|
-
const actionsDir =
|
|
1592
|
-
const ormActionDir =
|
|
1595
|
+
const jobsDir = path7.jobsPath();
|
|
1596
|
+
const actionsDir = path7.appPath("Actions");
|
|
1597
|
+
const ormActionDir = path7.builtUserActionsPath("src");
|
|
1593
1598
|
const jobFiles = await fs.readdir(jobsDir);
|
|
1594
1599
|
const actionFiles = await fs.readdir(actionsDir);
|
|
1595
1600
|
const ormActionFiles = await fs.readdir(ormActionDir);
|
|
@@ -1597,7 +1602,7 @@ class QueueStack {
|
|
|
1597
1602
|
for (const file of jobFiles) {
|
|
1598
1603
|
if (!file.endsWith(".ts"))
|
|
1599
1604
|
continue;
|
|
1600
|
-
const jobPath =
|
|
1605
|
+
const jobPath = path7.jobsPath(file);
|
|
1601
1606
|
const job = await this.loadModule(jobPath);
|
|
1602
1607
|
this.createQueueRule(job, file);
|
|
1603
1608
|
jobs.push(job);
|
|
@@ -1605,7 +1610,7 @@ class QueueStack {
|
|
|
1605
1610
|
for (const ormFile of ormActionFiles) {
|
|
1606
1611
|
if (!ormFile.endsWith(".ts"))
|
|
1607
1612
|
continue;
|
|
1608
|
-
const ormActionPath =
|
|
1613
|
+
const ormActionPath = path7.builtUserActionsPath(ormFile);
|
|
1609
1614
|
const ormAction = await this.loadModule(ormActionPath);
|
|
1610
1615
|
this.createQueueRule(ormAction, ormFile);
|
|
1611
1616
|
jobs.push(ormAction);
|
|
@@ -1613,8 +1618,7 @@ class QueueStack {
|
|
|
1613
1618
|
for (const file of actionFiles) {
|
|
1614
1619
|
if (!file.endsWith(".ts"))
|
|
1615
1620
|
continue;
|
|
1616
|
-
const actionPath =
|
|
1617
|
-
console.log(actionPath);
|
|
1621
|
+
const actionPath = path7.appPath(`Actions/${file}`);
|
|
1618
1622
|
const action = await this.loadModule(actionPath);
|
|
1619
1623
|
this.createQueueRule(action, file);
|
|
1620
1624
|
jobs.push(action);
|
|
@@ -1687,13 +1691,13 @@ class QueueStack {
|
|
|
1687
1691
|
}
|
|
1688
1692
|
|
|
1689
1693
|
// src/cloud/redirects.ts
|
|
1690
|
-
import {config as
|
|
1694
|
+
import {config as config17} from "@stacksjs/config";
|
|
1691
1695
|
import {RemovalPolicy as RemovalPolicy6, aws_route53 as route535, aws_s3 as s33} from "aws-cdk-lib";
|
|
1692
1696
|
|
|
1693
1697
|
class RedirectsStack {
|
|
1694
1698
|
redirectZones = [];
|
|
1695
1699
|
constructor(scope, props) {
|
|
1696
|
-
|
|
1700
|
+
config17.dns.redirects?.forEach((redirect) => {
|
|
1697
1701
|
const slug3 = redirect.split(".").map((part, index) => index === 0 ? part : part.charAt(0).toUpperCase() + part.slice(1)).join("");
|
|
1698
1702
|
const hostedZone = route535.HostedZone.fromLookup(scope, "HostedZone", {
|
|
1699
1703
|
domainName: redirect
|
|
@@ -1713,7 +1717,7 @@ class RedirectsStack {
|
|
|
1713
1717
|
domainName: redirectBucket.bucketWebsiteDomainName
|
|
1714
1718
|
});
|
|
1715
1719
|
});
|
|
1716
|
-
|
|
1720
|
+
config17.dns.redirects?.forEach((redirect) => {
|
|
1717
1721
|
const slug3 = redirect.split(".").map((part, index) => index === 0 ? part : part.charAt(0).toUpperCase() + part.slice(1)).join("");
|
|
1718
1722
|
const hostedZone = route535.HostedZone.fromLookup(scope, `RedirectHostedZone${slug3}`, { domainName: redirect });
|
|
1719
1723
|
this.redirectZones.push(hostedZone);
|
|
@@ -1722,7 +1726,7 @@ class RedirectsStack {
|
|
|
1722
1726
|
}
|
|
1723
1727
|
|
|
1724
1728
|
// src/cloud/security.ts
|
|
1725
|
-
import {config as
|
|
1729
|
+
import {config as config19} from "@stacksjs/config";
|
|
1726
1730
|
import {
|
|
1727
1731
|
Duration as Duration6,
|
|
1728
1732
|
RemovalPolicy as RemovalPolicy7,
|
|
@@ -1737,7 +1741,7 @@ class SecurityStack {
|
|
|
1737
1741
|
kmsKey;
|
|
1738
1742
|
certificate;
|
|
1739
1743
|
constructor(scope, props) {
|
|
1740
|
-
const firewallOptions =
|
|
1744
|
+
const firewallOptions = config19.cloud.firewall;
|
|
1741
1745
|
if (!firewallOptions)
|
|
1742
1746
|
throw new Error("No firewall options found in config");
|
|
1743
1747
|
const options = {
|
|
@@ -1772,12 +1776,16 @@ class SecurityStack {
|
|
|
1772
1776
|
getFirewallRules(scope) {
|
|
1773
1777
|
const rules = [];
|
|
1774
1778
|
const priorities = [];
|
|
1775
|
-
if (
|
|
1779
|
+
if (config19.security.firewall?.countryCodes?.length) {
|
|
1776
1780
|
priorities.push(1);
|
|
1777
1781
|
rules.push({
|
|
1778
1782
|
name: "CountryRule",
|
|
1779
1783
|
priority: priorities.length,
|
|
1780
|
-
statement: {
|
|
1784
|
+
statement: {
|
|
1785
|
+
geoMatchStatement: {
|
|
1786
|
+
countryCodes: config19.security.firewall.countryCodes
|
|
1787
|
+
}
|
|
1788
|
+
},
|
|
1781
1789
|
action: {
|
|
1782
1790
|
block: {}
|
|
1783
1791
|
},
|
|
@@ -1788,12 +1796,12 @@ class SecurityStack {
|
|
|
1788
1796
|
}
|
|
1789
1797
|
});
|
|
1790
1798
|
}
|
|
1791
|
-
if (
|
|
1799
|
+
if (config19.security.firewall?.ipAddresses?.length) {
|
|
1792
1800
|
const ipSet = new wafv2.CfnIPSet(scope, "IpSet", {
|
|
1793
1801
|
name: "IpSet",
|
|
1794
1802
|
description: "IP Set",
|
|
1795
1803
|
scope: "CLOUDFRONT",
|
|
1796
|
-
addresses:
|
|
1804
|
+
addresses: config19.security.firewall.ipAddresses,
|
|
1797
1805
|
ipAddressVersion: "IPV4"
|
|
1798
1806
|
});
|
|
1799
1807
|
priorities.push(1);
|
|
@@ -1815,8 +1823,8 @@ class SecurityStack {
|
|
|
1815
1823
|
}
|
|
1816
1824
|
});
|
|
1817
1825
|
}
|
|
1818
|
-
if (
|
|
1819
|
-
|
|
1826
|
+
if (config19.security.firewall?.httpHeaders?.length) {
|
|
1827
|
+
config19.security.firewall.httpHeaders.forEach((header, index) => {
|
|
1820
1828
|
priorities.push(1);
|
|
1821
1829
|
rules.push({
|
|
1822
1830
|
name: `HttpHeaderRule${index}`,
|
|
@@ -1832,7 +1840,7 @@ class SecurityStack {
|
|
|
1832
1840
|
searchString: "true",
|
|
1833
1841
|
textTransformations: [
|
|
1834
1842
|
{
|
|
1835
|
-
priority:
|
|
1843
|
+
priority: 0,
|
|
1836
1844
|
type: "NONE"
|
|
1837
1845
|
}
|
|
1838
1846
|
]
|
|
@@ -1854,11 +1862,14 @@ class SecurityStack {
|
|
|
1854
1862
|
}
|
|
1855
1863
|
|
|
1856
1864
|
// src/cloud/storage.ts
|
|
1865
|
+
import {path as p6} from "@stacksjs/path";
|
|
1866
|
+
import {hasFiles as hasFiles3} from "@stacksjs/storage";
|
|
1857
1867
|
import {RemovalPolicy as RemovalPolicy8, Tags as Tags3, aws_backup as backup, aws_iam as iam5, aws_s3 as s34} from "aws-cdk-lib";
|
|
1858
1868
|
|
|
1859
1869
|
class StorageStack {
|
|
1860
1870
|
publicBucket;
|
|
1861
1871
|
privateBucket;
|
|
1872
|
+
docsBucket;
|
|
1862
1873
|
logBucket;
|
|
1863
1874
|
bucketPrefix;
|
|
1864
1875
|
vault;
|
|
@@ -1874,6 +1885,16 @@ class StorageStack {
|
|
|
1874
1885
|
encryption: s34.BucketEncryption.S3_MANAGED
|
|
1875
1886
|
});
|
|
1876
1887
|
Tags3.of(this.publicBucket).add("daily-backup", "true");
|
|
1888
|
+
if (this.shouldDeployDocs()) {
|
|
1889
|
+
this.docsBucket = new s34.Bucket(scope, "DocsBucket", {
|
|
1890
|
+
bucketName: `${this.bucketPrefix}-docs-${props.timestamp}`,
|
|
1891
|
+
versioned: true,
|
|
1892
|
+
autoDeleteObjects: true,
|
|
1893
|
+
removalPolicy: RemovalPolicy8.DESTROY,
|
|
1894
|
+
encryption: s34.BucketEncryption.S3_MANAGED
|
|
1895
|
+
});
|
|
1896
|
+
Tags3.of(this.docsBucket).add("weekly-backup", "true");
|
|
1897
|
+
}
|
|
1877
1898
|
this.privateBucket = new s34.Bucket(scope, "PrivateBucket", {
|
|
1878
1899
|
bucketName: `${this.bucketPrefix}-private-${props.timestamp}`,
|
|
1879
1900
|
versioned: true,
|
|
@@ -1981,6 +2002,9 @@ class StorageStack {
|
|
|
1981
2002
|
}));
|
|
1982
2003
|
return backupRole;
|
|
1983
2004
|
}
|
|
2005
|
+
shouldDeployDocs() {
|
|
2006
|
+
return hasFiles3(p6.projectPath("docs")) || config.app.docMode;
|
|
2007
|
+
}
|
|
1984
2008
|
}
|
|
1985
2009
|
|
|
1986
2010
|
// src/cloud/index.ts
|
|
@@ -2037,8 +2061,8 @@ class Cloud extends Stack2 {
|
|
|
2037
2061
|
this.cli = new CliStack(this, props);
|
|
2038
2062
|
}
|
|
2039
2063
|
async init() {
|
|
2040
|
-
|
|
2041
|
-
|
|
2064
|
+
const props = this.props;
|
|
2065
|
+
if (this.shouldDeployApi()) {
|
|
2042
2066
|
this.api = new ComputeStack(this, {
|
|
2043
2067
|
...props,
|
|
2044
2068
|
vpc: this.network.vpc,
|
|
@@ -2052,26 +2076,31 @@ class Cloud extends Stack2 {
|
|
|
2052
2076
|
taskDefinition: this.api.taskDefinition
|
|
2053
2077
|
});
|
|
2054
2078
|
await this.queue.init();
|
|
2055
|
-
this.cdn = new CdnStack(this, {
|
|
2056
|
-
...props,
|
|
2057
|
-
publicBucket: this.storage.publicBucket,
|
|
2058
|
-
logBucket: this.storage.logBucket,
|
|
2059
|
-
certificate: this.security.certificate,
|
|
2060
|
-
firewall: this.security.firewall,
|
|
2061
|
-
originRequestFunction: this.docs.originRequestFunction,
|
|
2062
|
-
zone: this.dns.zone,
|
|
2063
|
-
cliSetupUrl: this.cli.cliSetupUrl,
|
|
2064
|
-
askAiUrl: this.ai.askAiUrl,
|
|
2065
|
-
summarizeAiUrl: this.ai.summarizeAiUrl,
|
|
2066
|
-
lb: this.api?.lb
|
|
2067
|
-
});
|
|
2068
|
-
this.deployment = new DeploymentStack(this, {
|
|
2069
|
-
...props,
|
|
2070
|
-
publicBucket: this.storage.publicBucket,
|
|
2071
|
-
privateBucket: this.storage.privateBucket,
|
|
2072
|
-
cdn: this.cdn.distribution
|
|
2073
|
-
});
|
|
2074
2079
|
}
|
|
2080
|
+
this.cdn = new CdnStack(this, {
|
|
2081
|
+
...props,
|
|
2082
|
+
publicBucket: this.storage.publicBucket,
|
|
2083
|
+
docsBucket: this.storage.docsBucket,
|
|
2084
|
+
logBucket: this.storage.logBucket,
|
|
2085
|
+
certificate: this.security.certificate,
|
|
2086
|
+
firewall: this.security.firewall,
|
|
2087
|
+
originRequestFunction: this.docs.originRequestFunction,
|
|
2088
|
+
zone: this.dns.zone,
|
|
2089
|
+
cliSetupUrl: this.cli.cliSetupUrl,
|
|
2090
|
+
askAiUrl: this.ai.askAiUrl,
|
|
2091
|
+
summarizeAiUrl: this.ai.summarizeAiUrl,
|
|
2092
|
+
lb: this.api?.lb
|
|
2093
|
+
});
|
|
2094
|
+
this.deployment = new DeploymentStack(this, {
|
|
2095
|
+
...props,
|
|
2096
|
+
publicBucket: this.storage.publicBucket,
|
|
2097
|
+
privateBucket: this.storage.privateBucket,
|
|
2098
|
+
docsBucket: this.storage.docsBucket,
|
|
2099
|
+
cdn: this.cdn.distribution
|
|
2100
|
+
});
|
|
2101
|
+
}
|
|
2102
|
+
shouldDeployApi() {
|
|
2103
|
+
return config21.cloud.api?.deploy;
|
|
2075
2104
|
}
|
|
2076
2105
|
}
|
|
2077
2106
|
export {
|
|
@@ -2085,6 +2114,7 @@ export {
|
|
|
2085
2114
|
getJumpBoxSecurityGroupName,
|
|
2086
2115
|
getJumpBoxInstanceProfileName,
|
|
2087
2116
|
getJumpBoxInstanceId,
|
|
2117
|
+
getCloudFrontDistributionId,
|
|
2088
2118
|
deleteStacksFunctions,
|
|
2089
2119
|
deleteStacksBuckets,
|
|
2090
2120
|
deleteParameterStore,
|
|
@@ -2097,3 +2127,6 @@ export {
|
|
|
2097
2127
|
InstanceType,
|
|
2098
2128
|
Cloud
|
|
2099
2129
|
};
|
|
2130
|
+
|
|
2131
|
+
//# debugId=B17D4D8836F8DA4664756E2164756E21
|
|
2132
|
+
//# sourceMappingURL=index.js.map
|