sst 2.0.0-rc.9 → 2.0.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.
Files changed (242) hide show
  1. package/bootstrap.d.ts +2 -4
  2. package/bootstrap.js +208 -61
  3. package/bus.d.ts +3 -3
  4. package/bus.js +1 -1
  5. package/cache.js +1 -1
  6. package/cdk/cloudformation-deployments-wrapper.d.ts +3 -0
  7. package/cdk/cloudformation-deployments-wrapper.js +117 -0
  8. package/cdk/cloudformation-deployments.d.ts +19 -4
  9. package/cdk/deploy-stack.d.ts +17 -2
  10. package/cdk/deploy-stack.js +6 -1
  11. package/cli/colors.d.ts +28 -0
  12. package/cli/colors.js +27 -0
  13. package/cli/commands/bind.d.ts +4 -0
  14. package/cli/commands/bind.js +10 -7
  15. package/cli/commands/bootstrap.d.ts +13 -0
  16. package/cli/commands/bootstrap.js +11 -0
  17. package/cli/commands/build.d.ts +6 -2
  18. package/cli/commands/build.js +13 -8
  19. package/cli/commands/console.d.ts +5 -1
  20. package/cli/commands/console.js +8 -6
  21. package/cli/commands/deploy.d.ts +4 -2
  22. package/cli/commands/deploy.js +69 -29
  23. package/cli/commands/dev.d.ts +5 -1
  24. package/cli/commands/dev.js +157 -79
  25. package/cli/commands/diff.d.ts +15 -0
  26. package/cli/commands/diff.js +61 -0
  27. package/cli/commands/env.d.ts +5 -1
  28. package/cli/commands/env.js +14 -15
  29. package/cli/commands/plugins/kysely.js +13 -5
  30. package/cli/commands/plugins/pothos.js +9 -4
  31. package/cli/commands/remove.d.ts +4 -0
  32. package/cli/commands/remove.js +26 -18
  33. package/cli/commands/secrets/get.d.ts +7 -3
  34. package/cli/commands/secrets/get.js +11 -24
  35. package/cli/commands/secrets/list.d.ts +6 -2
  36. package/cli/commands/secrets/list.js +15 -7
  37. package/cli/commands/secrets/remove.d.ts +8 -4
  38. package/cli/commands/secrets/remove.js +18 -16
  39. package/cli/commands/secrets/secrets.js +3 -3
  40. package/cli/commands/secrets/set.d.ts +8 -6
  41. package/cli/commands/secrets/set.js +16 -33
  42. package/cli/commands/telemetry.d.ts +15 -0
  43. package/cli/commands/telemetry.js +17 -0
  44. package/cli/commands/transform.d.ts +15 -0
  45. package/cli/commands/transform.js +55 -0
  46. package/cli/commands/update.d.ts +6 -2
  47. package/cli/commands/update.js +41 -33
  48. package/cli/commands/version.d.ts +13 -0
  49. package/cli/commands/version.js +7 -0
  50. package/cli/local/router.d.ts +6 -6
  51. package/cli/local/router.js +3 -3
  52. package/cli/local/server.d.ts +5 -3
  53. package/cli/local/server.js +21 -14
  54. package/cli/program.d.ts +5 -1
  55. package/cli/program.js +29 -5
  56. package/cli/spinner.js +2 -0
  57. package/cli/sst.js +35 -23
  58. package/cli/telemetry/environment.d.ts +1 -1
  59. package/cli/telemetry/environment.js +1 -1
  60. package/cli/terminal.d.ts +1 -0
  61. package/cli/terminal.js +8 -0
  62. package/cli/ui/deploy.d.ts +3 -2
  63. package/cli/ui/deploy.js +106 -106
  64. package/cli/ui/functions.d.ts +2 -0
  65. package/cli/ui/functions.js +132 -0
  66. package/cli/ui/header.d.ts +5 -0
  67. package/cli/ui/header.js +16 -0
  68. package/cli/ui/stack.d.ts +1 -0
  69. package/cli/ui/stack.js +6 -0
  70. package/config.d.ts +1 -1
  71. package/config.js +8 -8
  72. package/constructs/Api.d.ts +3 -71
  73. package/constructs/Api.js +3 -42
  74. package/constructs/ApiGatewayV1Api.d.ts +3 -3
  75. package/constructs/ApiGatewayV1Api.js +4 -3
  76. package/constructs/App.d.ts +2 -22
  77. package/constructs/App.js +12 -25
  78. package/constructs/AppSyncApi.d.ts +4 -5
  79. package/constructs/AppSyncApi.js +8 -5
  80. package/constructs/AstroSite.d.ts +2 -3
  81. package/constructs/AstroSite.js +43 -53
  82. package/constructs/Auth.js +27 -16
  83. package/constructs/BaseSite.d.ts +10 -10
  84. package/constructs/BaseSite.js +2 -2
  85. package/constructs/Cognito.js +28 -28
  86. package/constructs/EdgeFunction.d.ts +6 -4
  87. package/constructs/EdgeFunction.js +56 -59
  88. package/constructs/EventBus.js +1 -1
  89. package/constructs/Function.d.ts +4 -44
  90. package/constructs/Function.js +14 -50
  91. package/constructs/FunctionalStack.d.ts +2 -2
  92. package/constructs/Job.d.ts +23 -63
  93. package/constructs/Job.js +11 -32
  94. package/constructs/Metadata.d.ts +18 -20
  95. package/constructs/NextjsSite.d.ts +21 -5
  96. package/constructs/NextjsSite.js +67 -101
  97. package/constructs/Queue.js +10 -10
  98. package/constructs/RDS.d.ts +1 -1
  99. package/constructs/RDS.js +1 -1
  100. package/constructs/RemixSite.d.ts +0 -2
  101. package/constructs/RemixSite.js +20 -20
  102. package/constructs/Script.js +1 -1
  103. package/constructs/Secret.js +5 -3
  104. package/constructs/SolidStartSite.d.ts +2 -3
  105. package/constructs/SolidStartSite.js +42 -52
  106. package/constructs/SsrFunction.d.ts +22 -0
  107. package/constructs/SsrFunction.js +113 -0
  108. package/constructs/SsrSite.d.ts +104 -104
  109. package/constructs/SsrSite.js +196 -217
  110. package/constructs/Stack.d.ts +1 -20
  111. package/constructs/Stack.js +3 -65
  112. package/constructs/StaticSite.d.ts +33 -53
  113. package/constructs/StaticSite.js +92 -118
  114. package/constructs/Table.d.ts +1 -1
  115. package/constructs/Table.js +4 -4
  116. package/constructs/Topic.js +1 -1
  117. package/constructs/cdk/certificate-base.d.ts +18 -0
  118. package/constructs/cdk/certificate-base.js +26 -0
  119. package/constructs/cdk/dns-validated-certificate.d.ts +77 -0
  120. package/constructs/cdk/dns-validated-certificate.js +125 -0
  121. package/constructs/cdk/website-redirect.d.ts +53 -0
  122. package/constructs/cdk/website-redirect.js +77 -0
  123. package/constructs/deferred_task.d.ts +1 -1
  124. package/constructs/deprecated/NextjsSite.js +8 -6
  125. package/constructs/index.d.ts +0 -6
  126. package/constructs/index.js +0 -6
  127. package/constructs/util/apiGatewayV1AccessLog.d.ts +1 -1
  128. package/constructs/util/apiGatewayV2AccessLog.js +4 -4
  129. package/constructs/util/apiGatewayV2Domain.js +9 -2
  130. package/constructs/util/appSyncApiDomain.d.ts +1 -1
  131. package/constructs/util/appSyncApiDomain.js +9 -15
  132. package/constructs/util/duration.d.ts +1 -1
  133. package/constructs/util/functionBinding.js +1 -1
  134. package/constructs/util/permission.d.ts +3 -3
  135. package/constructs/util/permission.js +16 -18
  136. package/constructs/util/size.d.ts +1 -1
  137. package/constructs/util/warning.js +2 -2
  138. package/context/context.d.ts +2 -2
  139. package/context/context.js +4 -4
  140. package/context/handler.d.ts +1 -1
  141. package/credentials.d.ts +1 -1
  142. package/credentials.js +42 -6
  143. package/index.d.ts +1 -0
  144. package/index.js +1 -0
  145. package/iot.js +6 -2
  146. package/logger.js +3 -1
  147. package/node/api/index.d.ts +2 -3
  148. package/node/api/index.js +8 -2
  149. package/node/auth/adapter/adapter.d.ts +1 -1
  150. package/node/auth/adapter/facebook.js +1 -1
  151. package/node/auth/adapter/github.js +4 -4
  152. package/node/auth/adapter/google.d.ts +1 -1
  153. package/node/auth/adapter/google.js +2 -2
  154. package/node/auth/adapter/twitch.js +1 -1
  155. package/node/auth/session.d.ts +1 -1
  156. package/node/config/index.d.ts +2 -2
  157. package/node/config/index.js +3 -8
  158. package/node/job/index.d.ts +2 -2
  159. package/node/site/index.js +3 -5
  160. package/package.json +26 -21
  161. package/pothos.js +1 -0
  162. package/project.d.ts +47 -0
  163. package/{app.js → project.js} +60 -53
  164. package/runtime/handlers/dotnet.d.ts +1 -1
  165. package/runtime/handlers/dotnet.js +4 -4
  166. package/runtime/handlers/go.d.ts +1 -1
  167. package/runtime/handlers/go.js +3 -3
  168. package/runtime/handlers/java.d.ts +1 -1
  169. package/runtime/handlers/java.js +4 -4
  170. package/runtime/handlers/node.d.ts +1 -1
  171. package/runtime/handlers/node.js +60 -39
  172. package/runtime/handlers/python.d.ts +1 -1
  173. package/runtime/handlers/python.js +3 -3
  174. package/runtime/handlers.js +15 -12
  175. package/runtime/iot.js +3 -0
  176. package/runtime/runtime.d.ts +4 -0
  177. package/runtime/server.d.ts +3 -3
  178. package/runtime/server.js +11 -5
  179. package/runtime/workers.d.ts +4 -2
  180. package/runtime/workers.js +13 -3
  181. package/site-env.js +2 -1
  182. package/sst.mjs +6357 -20848
  183. package/stacks/app-metadata.d.ts +7 -0
  184. package/stacks/app-metadata.js +78 -0
  185. package/stacks/assembly.d.ts +1 -0
  186. package/stacks/assembly.js +4 -0
  187. package/stacks/build.d.ts +1 -1
  188. package/stacks/build.js +41 -48
  189. package/stacks/deploy.d.ts +1 -0
  190. package/stacks/deploy.js +128 -7
  191. package/stacks/diff.d.ts +8 -0
  192. package/stacks/diff.js +62 -0
  193. package/stacks/index.d.ts +3 -0
  194. package/stacks/index.js +3 -0
  195. package/stacks/metadata.d.ts +2 -0
  196. package/stacks/metadata.js +14 -12
  197. package/stacks/monitor.d.ts +8 -3
  198. package/stacks/monitor.js +38 -4
  199. package/stacks/remove.js +0 -4
  200. package/stacks/synth.d.ts +1 -0
  201. package/stacks/synth.js +27 -13
  202. package/support/base-site-archiver.mjs +1 -1
  203. package/support/bootstrap-metadata-function/index.mjs +68740 -0
  204. package/support/bridge/bridge.mjs +28 -28
  205. package/support/certificate-requestor/index.js +549 -0
  206. package/support/custom-resources/index.mjs +3824 -26567
  207. package/support/dotnet6-bootstrap/release/dotnet-bootstrap.deps.json +1 -1
  208. package/support/dotnet6-bootstrap/release/dotnet-bootstrap.runtimeconfig.json +1 -1
  209. package/support/edge-function/edge-lambda.mjs +2 -2
  210. package/support/job-invoker/index.mjs +26 -0
  211. package/support/nodejs-runtime/index.mjs +75 -72
  212. package/support/rds-migrator/index.mjs +22 -23
  213. package/support/remix-site-function/edge-server.js +1 -1
  214. package/support/script-function/index.mjs +30485 -0
  215. package/support/{edge-function-code-replacer → sls-nextjs-site-function-code-replacer}/lambda-code-updater.py +0 -0
  216. package/support/ssr-site-function-archiver.mjs +96 -0
  217. package/watcher.js +1 -1
  218. package/app.d.ts +0 -36
  219. package/constructs/DebugApp.d.ts +0 -49
  220. package/constructs/DebugApp.js +0 -63
  221. package/constructs/DebugStack.d.ts +0 -34
  222. package/constructs/DebugStack.js +0 -132
  223. package/constructs/GraphQLApi.d.ts +0 -98
  224. package/constructs/GraphQLApi.js +0 -80
  225. package/constructs/ReactStaticSite.d.ts +0 -20
  226. package/constructs/ReactStaticSite.js +0 -54
  227. package/constructs/Script/cfn-response.d.ts +0 -19
  228. package/constructs/Script/cfn-response.js +0 -77
  229. package/constructs/Script/index.d.ts +0 -1
  230. package/constructs/Script/index.js +0 -78
  231. package/constructs/Script/outbound.d.ts +0 -10
  232. package/constructs/Script/outbound.js +0 -42
  233. package/constructs/Script/util.d.ts +0 -2
  234. package/constructs/Script/util.js +0 -11
  235. package/constructs/ViteStaticSite.d.ts +0 -32
  236. package/constructs/ViteStaticSite.js +0 -66
  237. package/support/astro-site-html-stub/index.html +0 -99
  238. package/support/base-site-archiver.cjs +0 -116
  239. package/support/nextjs-site-html-stub/index.html +0 -99
  240. package/support/remix-site-html-stub/index.html +0 -99
  241. package/support/solid-start-site-html-stub/index.html +0 -99
  242. package/support/static-site-stub/index.html +0 -90
@@ -0,0 +1,125 @@
1
+ import url from "url";
2
+ import * as path from "path";
3
+ import { Token, TagManager, TagType, Duration, Stack, CustomResource, Lazy, } from "aws-cdk-lib";
4
+ import * as iam from "aws-cdk-lib/aws-iam";
5
+ import * as lambda from "aws-cdk-lib/aws-lambda";
6
+ import { CertificateBase } from "./certificate-base.js";
7
+ const __dirname = url.fileURLToPath(new URL(".", import.meta.url));
8
+ /**
9
+ * A certificate managed by AWS Certificate Manager. Will be automatically
10
+ * validated using DNS validation against the specified Route 53 hosted zone.
11
+ *
12
+ * @resource AWS::CertificateManager::Certificate
13
+ */
14
+ export class DnsValidatedCertificate extends CertificateBase {
15
+ certificateArn;
16
+ /**
17
+ * Resource Tags.
18
+ * @see https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-certificatemanager-certificate.html#cfn-certificatemanager-certificate-tags
19
+ */
20
+ tags;
21
+ region;
22
+ normalizedZoneName;
23
+ hostedZoneId;
24
+ domainName;
25
+ _removalPolicy;
26
+ constructor(scope, id, props) {
27
+ super(scope, id);
28
+ this.region = props.region;
29
+ this.domainName = props.domainName;
30
+ // check if domain name is 64 characters or less
31
+ if (!Token.isUnresolved(props.domainName) && props.domainName.length > 64) {
32
+ throw new Error("Domain name must be 64 characters or less");
33
+ }
34
+ this.normalizedZoneName = props.hostedZone.zoneName;
35
+ // Remove trailing `.` from zone name
36
+ if (this.normalizedZoneName.endsWith(".")) {
37
+ this.normalizedZoneName = this.normalizedZoneName.substring(0, this.normalizedZoneName.length - 1);
38
+ }
39
+ // Remove any `/hostedzone/` prefix from the Hosted Zone ID
40
+ this.hostedZoneId = props.hostedZone.hostedZoneId.replace(/^\/hostedzone\//, "");
41
+ this.tags = new TagManager(TagType.MAP, "AWS::CertificateManager::Certificate");
42
+ let certificateTransparencyLoggingPreference;
43
+ if (props.transparencyLoggingEnabled !== undefined) {
44
+ certificateTransparencyLoggingPreference =
45
+ props.transparencyLoggingEnabled ? "ENABLED" : "DISABLED";
46
+ }
47
+ const requestorFunction = new lambda.Function(this, "CertificateRequestorFunction", {
48
+ code: lambda.Code.fromAsset(path.join(__dirname, "../../support/certificate-requestor")),
49
+ handler: "index.certificateRequestHandler",
50
+ runtime: lambda.Runtime.NODEJS_14_X,
51
+ timeout: Duration.minutes(15),
52
+ role: props.customResourceRole,
53
+ });
54
+ requestorFunction.addToRolePolicy(new iam.PolicyStatement({
55
+ actions: [
56
+ "acm:RequestCertificate",
57
+ "acm:DescribeCertificate",
58
+ "acm:DeleteCertificate",
59
+ "acm:AddTagsToCertificate",
60
+ ],
61
+ resources: ["*"],
62
+ }));
63
+ requestorFunction.addToRolePolicy(new iam.PolicyStatement({
64
+ actions: ["route53:GetChange"],
65
+ resources: ["*"],
66
+ }));
67
+ requestorFunction.addToRolePolicy(new iam.PolicyStatement({
68
+ actions: ["route53:changeResourceRecordSets"],
69
+ resources: [
70
+ `arn:${Stack.of(requestorFunction).partition}:route53:::hostedzone/${this.hostedZoneId}`,
71
+ ],
72
+ conditions: {
73
+ "ForAllValues:StringEquals": {
74
+ "route53:ChangeResourceRecordSetsRecordTypes": ["CNAME"],
75
+ "route53:ChangeResourceRecordSetsActions": props.cleanupRoute53Records ? ["UPSERT", "DELETE"] : ["UPSERT"],
76
+ },
77
+ "ForAllValues:StringLike": {
78
+ "route53:ChangeResourceRecordSetsNormalizedRecordNames": [
79
+ addWildcard(props.domainName),
80
+ ...(props.subjectAlternativeNames ?? []).map((d) => addWildcard(d)),
81
+ ],
82
+ },
83
+ },
84
+ }));
85
+ const certificate = new CustomResource(this, "CertificateRequestorResource", {
86
+ serviceToken: requestorFunction.functionArn,
87
+ properties: {
88
+ DomainName: props.domainName,
89
+ SubjectAlternativeNames: Lazy.list({ produce: () => props.subjectAlternativeNames }, { omitEmpty: true }),
90
+ CertificateTransparencyLoggingPreference: certificateTransparencyLoggingPreference,
91
+ HostedZoneId: this.hostedZoneId,
92
+ Region: props.region,
93
+ Route53Endpoint: props.route53Endpoint,
94
+ RemovalPolicy: Lazy.any({ produce: () => this._removalPolicy }),
95
+ // Custom resources properties are always converted to strings; might as well be explict here.
96
+ CleanupRecords: props.cleanupRoute53Records ? "true" : undefined,
97
+ Tags: Lazy.list({ produce: () => this.tags.renderTags() }),
98
+ },
99
+ });
100
+ this.certificateArn = certificate.getAtt("Arn").toString();
101
+ this.node.addValidation({
102
+ validate: () => this.validateDnsValidatedCertificate(),
103
+ });
104
+ }
105
+ applyRemovalPolicy(policy) {
106
+ this._removalPolicy = policy;
107
+ }
108
+ validateDnsValidatedCertificate() {
109
+ const errors = [];
110
+ // Ensure the zone name is a parent zone of the certificate domain name
111
+ if (!Token.isUnresolved(this.normalizedZoneName) &&
112
+ this.domainName !== this.normalizedZoneName &&
113
+ !this.domainName.endsWith("." + this.normalizedZoneName)) {
114
+ errors.push(`DNS zone ${this.normalizedZoneName} is not authoritative for certificate domain name ${this.domainName}`);
115
+ }
116
+ return errors;
117
+ }
118
+ }
119
+ // https://docs.aws.amazon.com/Route53/latest/DeveloperGuide/specifying-rrset-conditions.html
120
+ function addWildcard(domainName) {
121
+ if (domainName.startsWith("*.")) {
122
+ return domainName;
123
+ }
124
+ return `*.${domainName}`;
125
+ }
@@ -0,0 +1,53 @@
1
+ import { ICertificate } from "aws-cdk-lib/aws-certificatemanager";
2
+ import { IHostedZone } from "aws-cdk-lib/aws-route53";
3
+ import { Construct } from "constructs";
4
+ /**
5
+ * Properties to configure an HTTPS Redirect
6
+ */
7
+ export interface HttpsRedirectProps {
8
+ /**
9
+ * Hosted zone of the domain which will be used to create alias record(s) from
10
+ * domain names in the hosted zone to the target domain. The hosted zone must
11
+ * contain entries for the domain name(s) supplied through `recordNames` that
12
+ * will redirect to the target domain.
13
+ *
14
+ * Domain names in the hosted zone can include a specific domain (example.com)
15
+ * and its subdomains (acme.example.com, zenith.example.com).
16
+ *
17
+ */
18
+ readonly zone: IHostedZone;
19
+ /**
20
+ * The redirect target fully qualified domain name (FQDN). An alias record
21
+ * will be created that points to your CloudFront distribution. Root domain
22
+ * or sub-domain can be supplied.
23
+ */
24
+ readonly targetDomain: string;
25
+ /**
26
+ * The domain names that will redirect to `targetDomain`
27
+ *
28
+ * @default - the domain name of the hosted zone
29
+ */
30
+ readonly recordNames?: string[];
31
+ /**
32
+ * The AWS Certificate Manager (ACM) certificate that will be associated with
33
+ * the CloudFront distribution that will be created. If provided, the certificate must be
34
+ * stored in us-east-1 (N. Virginia)
35
+ *
36
+ * @default - A new certificate is created in us-east-1 (N. Virginia)
37
+ */
38
+ readonly certificate?: ICertificate;
39
+ }
40
+ /**
41
+ * Allows creating a domainA -> domainB redirect using CloudFront and S3.
42
+ * You can specify multiple domains to be redirected.
43
+ */
44
+ export declare class HttpsRedirect extends Construct {
45
+ constructor(scope: Construct, id: string, props: HttpsRedirectProps);
46
+ /**
47
+ * Creates a certificate.
48
+ *
49
+ * This is also safe to upgrade since the new certificate will be created and updated
50
+ * on the CloudFront distribution before the old one is deleted.
51
+ */
52
+ private createCertificate;
53
+ }
@@ -0,0 +1,77 @@
1
+ import { CloudFrontWebDistribution, OriginProtocolPolicy, PriceClass, ViewerCertificate, ViewerProtocolPolicy, } from "aws-cdk-lib/aws-cloudfront";
2
+ import { ARecord, AaaaRecord, RecordTarget, } from "aws-cdk-lib/aws-route53";
3
+ import { CloudFrontTarget } from "aws-cdk-lib/aws-route53-targets";
4
+ import { BlockPublicAccess, Bucket, RedirectProtocol, } from "aws-cdk-lib/aws-s3";
5
+ import { ArnFormat, RemovalPolicy, Stack, Token } from "aws-cdk-lib";
6
+ import cdkHelpers from "aws-cdk-lib/core/lib/helpers-internal";
7
+ import { Construct } from "constructs";
8
+ import { DnsValidatedCertificate } from "./dns-validated-certificate.js";
9
+ const { md5hash } = cdkHelpers;
10
+ /**
11
+ * Allows creating a domainA -> domainB redirect using CloudFront and S3.
12
+ * You can specify multiple domains to be redirected.
13
+ */
14
+ export class HttpsRedirect extends Construct {
15
+ constructor(scope, id, props) {
16
+ super(scope, id);
17
+ const domainNames = props.recordNames ?? [props.zone.zoneName];
18
+ if (props.certificate) {
19
+ const certificateRegion = Stack.of(this).splitArn(props.certificate.certificateArn, ArnFormat.SLASH_RESOURCE_NAME).region;
20
+ if (!Token.isUnresolved(certificateRegion) &&
21
+ certificateRegion !== "us-east-1") {
22
+ throw new Error(`The certificate must be in the us-east-1 region and the certificate you provided is in ${certificateRegion}.`);
23
+ }
24
+ }
25
+ const redirectCert = props.certificate ?? this.createCertificate(domainNames, props.zone);
26
+ const redirectBucket = new Bucket(this, "RedirectBucket", {
27
+ websiteRedirect: {
28
+ hostName: props.targetDomain,
29
+ protocol: RedirectProtocol.HTTPS,
30
+ },
31
+ removalPolicy: RemovalPolicy.DESTROY,
32
+ blockPublicAccess: BlockPublicAccess.BLOCK_ALL,
33
+ });
34
+ const redirectDist = new CloudFrontWebDistribution(this, "RedirectDistribution", {
35
+ defaultRootObject: "",
36
+ originConfigs: [
37
+ {
38
+ behaviors: [{ isDefaultBehavior: true }],
39
+ customOriginSource: {
40
+ domainName: redirectBucket.bucketWebsiteDomainName,
41
+ originProtocolPolicy: OriginProtocolPolicy.HTTP_ONLY,
42
+ },
43
+ },
44
+ ],
45
+ viewerCertificate: ViewerCertificate.fromAcmCertificate(redirectCert, {
46
+ aliases: domainNames,
47
+ }),
48
+ comment: `Redirect to ${props.targetDomain} from ${domainNames.join(", ")}`,
49
+ priceClass: PriceClass.PRICE_CLASS_ALL,
50
+ viewerProtocolPolicy: ViewerProtocolPolicy.REDIRECT_TO_HTTPS,
51
+ });
52
+ domainNames.forEach((domainName) => {
53
+ const hash = md5hash(domainName).slice(0, 6);
54
+ const aliasProps = {
55
+ recordName: domainName,
56
+ zone: props.zone,
57
+ target: RecordTarget.fromAlias(new CloudFrontTarget(redirectDist)),
58
+ };
59
+ new ARecord(this, `RedirectAliasRecord${hash}`, aliasProps);
60
+ new AaaaRecord(this, `RedirectAliasRecordSix${hash}`, aliasProps);
61
+ });
62
+ }
63
+ /**
64
+ * Creates a certificate.
65
+ *
66
+ * This is also safe to upgrade since the new certificate will be created and updated
67
+ * on the CloudFront distribution before the old one is deleted.
68
+ */
69
+ createCertificate(domainNames, zone) {
70
+ return new DnsValidatedCertificate(this, "RedirectCertificate", {
71
+ domainName: domainNames[0],
72
+ subjectAlternativeNames: domainNames,
73
+ hostedZone: zone,
74
+ region: "us-east-1",
75
+ });
76
+ }
77
+ }
@@ -1,4 +1,4 @@
1
- declare type Task = () => Promise<void>;
1
+ type Task = () => Promise<void>;
2
2
  export declare const useDeferredTasks: () => {
3
3
  add(task: Task): void;
4
4
  run(): Promise<unknown>;
@@ -28,7 +28,7 @@ import { ENVIRONMENT_PLACEHOLDER, getParameterPath, } from "../util/functionBind
28
28
  import * as crossRegionHelper from "./cross-region-helper.js";
29
29
  import { gray, red } from "colorette";
30
30
  import { SiteEnv } from "../../site-env.js";
31
- import { useProject } from "../../app.js";
31
+ import { useProject } from "../../project.js";
32
32
  const __dirname = url.fileURLToPath(new URL(".", import.meta.url));
33
33
  /////////////////////
34
34
  // Construct
@@ -253,7 +253,7 @@ export class NextjsSite extends Construct {
253
253
  },
254
254
  permissions: {
255
255
  "ssm:GetParameters": [
256
- `arn:aws:ssm:${app.region}:${app.account}:parameter${getParameterPath(this, "url")}`,
256
+ `arn:${Stack.of(this).partition}:ssm:${app.region}:${app.account}:parameter${getParameterPath(this, "url")}`,
257
257
  ],
258
258
  },
259
259
  };
@@ -265,7 +265,7 @@ export class NextjsSite extends Construct {
265
265
  throw new Error(`No build output found at "${siteOutputPath}" for the "${this.node.id}" NextjsSite.`);
266
266
  }
267
267
  // create zip files
268
- const script = path.join(__dirname, "../../support/base-site-archiver.cjs");
268
+ const script = path.join(__dirname, "../../support/base-site-archiver.mjs");
269
269
  const zipPath = path.resolve(path.join(this.sstBuildDir, `NextjsSite-${this.node.id}-${this.node.addr}`));
270
270
  // clear zip path to ensure no partX.zip remain from previous build
271
271
  fs.rmSync(zipPath, {
@@ -391,7 +391,7 @@ export class NextjsSite extends Construct {
391
391
  const role = new iam.Role(this, `EdgeLambdaRole`, {
392
392
  assumedBy: new iam.CompositePrincipal(new iam.ServicePrincipal("lambda.amazonaws.com"), new iam.ServicePrincipal("edgelambda.amazonaws.com")),
393
393
  managedPolicies: [
394
- iam.ManagedPolicy.fromManagedPolicyArn(this, "EdgeLambdaPolicy", "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"),
394
+ iam.ManagedPolicy.fromManagedPolicyArn(this, "EdgeLambdaPolicy", `arn:${Stack.of(this).partition}:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole`),
395
395
  ],
396
396
  });
397
397
  // Attach permission
@@ -461,7 +461,7 @@ export class NextjsSite extends Construct {
461
461
  // Create provider if not already created
462
462
  if (!provider) {
463
463
  provider = new lambda.Function(stack, providerId, {
464
- code: lambda.Code.fromAsset(path.join(__dirname, "../../support/edge-function-code-replacer")),
464
+ code: lambda.Code.fromAsset(path.join(__dirname, "../../support/sls-nextjs-site-function-code-replacer")),
465
465
  layers: [this.awsCliLayer],
466
466
  runtime: lambda.Runtime.PYTHON_3_7,
467
467
  handler: "lambda-code-updater.handler",
@@ -473,7 +473,9 @@ export class NextjsSite extends Construct {
473
473
  provider.role?.addToPrincipalPolicy(new iam.PolicyStatement({
474
474
  effect: iam.Effect.ALLOW,
475
475
  actions: ["s3:*"],
476
- resources: [`arn:aws:s3:::${asset.s3BucketName}/${asset.s3ObjectKey}`],
476
+ resources: [
477
+ `arn:${Stack.of(this).partition}:s3:::${asset.s3BucketName}/${asset.s3ObjectKey}`,
478
+ ],
477
479
  }));
478
480
  // Create custom resource
479
481
  const resource = new CustomResource(this, resId, {
@@ -14,9 +14,7 @@ export * from "./Bucket.js";
14
14
  export * from "./Script.js";
15
15
  export * from "./EventBus.js";
16
16
  export * from "./Function.js";
17
- export * from "./GraphQLApi.js";
18
17
  export * from "./AppSyncApi.js";
19
- export * from "./DebugStack.js";
20
18
  export * from "./WebSocketApi.js";
21
19
  export * from "./KinesisStream.js";
22
20
  export * from "./ApiGatewayV1Api.js";
@@ -24,13 +22,9 @@ export * from "./NextjsSite.js";
24
22
  export * from "./RemixSite.js";
25
23
  export * from "./SolidStartSite.js";
26
24
  export * from "./StaticSite.js";
27
- export * from "./ViteStaticSite.js";
28
- export * from "./ReactStaticSite.js";
29
25
  export * from "./util/size.js";
30
26
  export * from "./util/duration.js";
31
27
  export * from "./util/permission.js";
32
28
  export * as Config from "./Config.js";
33
29
  export * as Metadata from "./Metadata.js";
34
- export * from "./DebugApp.js";
35
- export * from "./DebugStack.js";
36
30
  export { use, dependsOn, getStack, StackContext } from "./FunctionalStack.js";
@@ -14,9 +14,7 @@ export * from "./Bucket.js";
14
14
  export * from "./Script.js";
15
15
  export * from "./EventBus.js";
16
16
  export * from "./Function.js";
17
- export * from "./GraphQLApi.js";
18
17
  export * from "./AppSyncApi.js";
19
- export * from "./DebugStack.js";
20
18
  export * from "./WebSocketApi.js";
21
19
  export * from "./KinesisStream.js";
22
20
  export * from "./ApiGatewayV1Api.js";
@@ -24,13 +22,9 @@ export * from "./NextjsSite.js";
24
22
  export * from "./RemixSite.js";
25
23
  export * from "./SolidStartSite.js";
26
24
  export * from "./StaticSite.js";
27
- export * from "./ViteStaticSite.js";
28
- export * from "./ReactStaticSite.js";
29
25
  export * from "./util/size.js";
30
26
  export * from "./util/duration.js";
31
27
  export * from "./util/permission.js";
32
28
  export * as Config from "./Config.js";
33
29
  export * as Metadata from "./Metadata.js";
34
- export * from "./DebugApp.js";
35
- export * from "./DebugStack.js";
36
30
  export { use, dependsOn, getStack } from "./FunctionalStack.js";
@@ -6,7 +6,7 @@ export interface AccessLogProps {
6
6
  destinationArn?: string;
7
7
  retention?: Lowercase<keyof typeof logs.RetentionDays>;
8
8
  }
9
- export declare type AccessLogData = {
9
+ export type AccessLogData = {
10
10
  logGroup: logs.LogGroup | undefined;
11
11
  format: apig.AccessLogFormat;
12
12
  destination: apig.LogGroupLogDestination;
@@ -17,7 +17,7 @@ const defaultHttpFields = [
17
17
  // caller info
18
18
  `"ip":"$context.identity.sourceIp"`,
19
19
  `"userAgent":"$context.identity.userAgent"`,
20
- `"cognitoIdentityId":"$context.identity.cognitoIdentityId"`
20
+ `"cognitoIdentityId":"$context.identity.cognitoIdentityId"`,
21
21
  ];
22
22
  const defaultWebSocketFields = [
23
23
  // request info
@@ -36,7 +36,7 @@ const defaultWebSocketFields = [
36
36
  `"userAgent":"$context.identity.userAgent"`,
37
37
  `"cognitoIdentityId":"$context.identity.cognitoIdentityId"`,
38
38
  `"connectedAt":"$context.connectedAt"`,
39
- `"connectionId":"$context.connectionId"`
39
+ `"connectionId":"$context.connectionId"`,
40
40
  ];
41
41
  export function buildAccessLogData(scope, accessLog, apiStage, isDefaultStage) {
42
42
  if (accessLog === false) {
@@ -60,9 +60,9 @@ export function buildAccessLogData(scope, accessLog, apiStage, isDefaultStage) {
60
60
  logGroupName: [
61
61
  `/aws/vendedlogs/apis`,
62
62
  `/${cleanupLogGroupName(apiName)}-${apiStage.api.apiId}`,
63
- `/${cleanupLogGroupName(apiStage.stageName)}`
63
+ `/${cleanupLogGroupName(apiStage.stageName)}`,
64
64
  ].join(""),
65
- retention: buildLogGroupRetention(accessLog)
65
+ retention: buildLogGroupRetention(accessLog),
66
66
  });
67
67
  destinationArn = logGroup.logGroupArn;
68
68
  }
@@ -32,7 +32,7 @@ function buildDataForStringInput(scope, customDomain) {
32
32
  }
33
33
  assertDomainNameIsLowerCase(customDomain);
34
34
  const domainName = customDomain;
35
- const hostedZoneDomain = domainName.split(".").slice(1).join(".");
35
+ const hostedZoneDomain = parseRoute53Domain(domainName);
36
36
  const hostedZone = lookupHostedZone(scope, hostedZoneDomain);
37
37
  const certificate = createCertificate(scope, domainName, hostedZone);
38
38
  const apigDomain = createApigDomain(scope, domainName, certificate);
@@ -71,7 +71,7 @@ function buildDataForInternalDomainInput(scope, customDomain) {
71
71
  hostedZone = customDomain.cdk.hostedZone;
72
72
  }
73
73
  else {
74
- const hostedZoneDomain = domainName.split(".").slice(1).join(".");
74
+ const hostedZoneDomain = parseRoute53Domain(domainName);
75
75
  hostedZone = lookupHostedZone(scope, hostedZoneDomain);
76
76
  }
77
77
  // Create certificate
@@ -199,3 +199,10 @@ function assertDomainNameIsLowerCase(domainName) {
199
199
  throw new Error(`The domain name needs to be in lowercase`);
200
200
  }
201
201
  }
202
+ function parseRoute53Domain(domainName) {
203
+ const parts = domainName.split(".");
204
+ // If the domain contains subdomain, ie. api.example.com,
205
+ // strip the subdomain and use the root domain, ie. example.com.
206
+ // Otherwise, use the domain as is.
207
+ return parts.length <= 2 ? domainName : parts.slice(1).join(".");
208
+ }
@@ -1,5 +1,5 @@
1
1
  import * as route53 from "aws-cdk-lib/aws-route53";
2
- import * as appsync from "@aws-cdk/aws-appsync-alpha";
2
+ import * as appsync from "aws-cdk-lib/aws-appsync";
3
3
  import * as acm from "aws-cdk-lib/aws-certificatemanager";
4
4
  import { AppSyncApi } from "../AppSyncApi.js";
5
5
  export interface CustomDomainProps {
@@ -26,16 +26,13 @@ function buildDataForStringInput(scope, customDomain) {
26
26
  }
27
27
  assertDomainNameIsLowerCase(customDomain);
28
28
  const domainName = customDomain;
29
- const hostedZoneDomain = domainName
30
- .split(".")
31
- .slice(1)
32
- .join(".");
29
+ const hostedZoneDomain = domainName.split(".").slice(1).join(".");
33
30
  const hostedZone = lookupHostedZone(scope, hostedZoneDomain);
34
31
  const certificate = createCertificate(scope, domainName, hostedZone);
35
32
  createRecord(scope, hostedZone, domainName);
36
33
  return {
37
34
  certificate,
38
- domainName
35
+ domainName,
39
36
  };
40
37
  }
41
38
  function buildDataForInternalDomainInput(scope, customDomain) {
@@ -63,10 +60,7 @@ function buildDataForInternalDomainInput(scope, customDomain) {
63
60
  hostedZone = customDomain.cdk.hostedZone;
64
61
  }
65
62
  else {
66
- const hostedZoneDomain = domainName
67
- .split(".")
68
- .slice(1)
69
- .join(".");
63
+ const hostedZoneDomain = domainName.split(".").slice(1).join(".");
70
64
  hostedZone = lookupHostedZone(scope, hostedZoneDomain);
71
65
  }
72
66
  // Create certificate
@@ -78,7 +72,7 @@ function buildDataForInternalDomainInput(scope, customDomain) {
78
72
  createRecord(scope, hostedZone, domainName);
79
73
  return {
80
74
  certificate,
81
- domainName
75
+ domainName,
82
76
  };
83
77
  }
84
78
  function buildDataForExternalDomainInput(scope, customDomain) {
@@ -95,18 +89,18 @@ function buildDataForExternalDomainInput(scope, customDomain) {
95
89
  const certificate = customDomain.cdk.certificate;
96
90
  return {
97
91
  certificate,
98
- domainName
92
+ domainName,
99
93
  };
100
94
  }
101
95
  function lookupHostedZone(scope, hostedZoneDomain) {
102
96
  return route53.HostedZone.fromLookup(scope, "HostedZone", {
103
- domainName: hostedZoneDomain
97
+ domainName: hostedZoneDomain,
104
98
  });
105
99
  }
106
100
  function createCertificate(scope, domainName, hostedZone) {
107
101
  return new acm.Certificate(scope, "Certificate", {
108
102
  domainName,
109
- validation: acm.CertificateValidation.fromDns(hostedZone)
103
+ validation: acm.CertificateValidation.fromDns(hostedZone),
110
104
  });
111
105
  }
112
106
  function createRecord(scope, hostedZone, domainName) {
@@ -117,8 +111,8 @@ function createRecord(scope, hostedZone, domainName) {
117
111
  domainName: Lazy.string({
118
112
  produce() {
119
113
  return scope._cfnDomainName.attrAppSyncDomainName;
120
- }
121
- })
114
+ },
115
+ }),
122
116
  });
123
117
  // note: If domainName is a TOKEN string ie. ${TOKEN..}, the route53.ARecord
124
118
  // construct will append ".${hostedZoneName}" to the end of the domain.
@@ -1,3 +1,3 @@
1
1
  import { Duration as CDKDuration } from "aws-cdk-lib";
2
- export declare type Duration = `${number} ${"second" | "seconds" | "minute" | "minutes" | "hour" | "hours" | "day" | "days"}`;
2
+ export type Duration = `${number} ${"second" | "seconds" | "minute" | "minutes" | "hour" | "hours" | "day" | "days"}`;
3
3
  export declare function toCdkDuration(duration: Duration): CDKDuration;
@@ -19,7 +19,7 @@ export function bindParameters(c) {
19
19
  }
20
20
  const app = c.node.root;
21
21
  Object.entries(binding.variables)
22
- .filter(([, variable]) => variable.parameter)
22
+ .filter(([, variable]) => variable.parameter !== undefined)
23
23
  .forEach(([prop, variable]) => {
24
24
  const resId = `Parameter_${prop}`;
25
25
  if (!c.node.tryFindChild(resId)) {
@@ -1,8 +1,8 @@
1
1
  import { IConstruct } from "constructs";
2
2
  import * as iam from "aws-cdk-lib/aws-iam";
3
- export declare type Permissions = "*" | Permission[];
4
- declare type SupportedPermissions = "execute-api" | "appsync" | "dynamodb" | "sns" | "sqs" | "events" | "kinesis" | "s3" | "rds-data" | "secretsmanager" | "lambda" | "ssm";
5
- declare type Permission = SupportedPermissions | Omit<string, SupportedPermissions> | IConstruct | [IConstruct, string] | iam.PolicyStatement;
3
+ export type Permissions = "*" | Permission[];
4
+ type SupportedPermissions = "execute-api" | "appsync" | "dynamodb" | "sns" | "sqs" | "events" | "kinesis" | "s3" | "rds-data" | "secretsmanager" | "lambda" | "ssm";
5
+ type Permission = SupportedPermissions | Omit<string, SupportedPermissions> | IConstruct | [IConstruct, string] | iam.PolicyStatement;
6
6
  export declare function attachPermissionsToRole(role: iam.Role, permissions: Permissions): void;
7
7
  export declare function attachPermissionsToPolicy(policy: iam.Policy, permissions: Permissions): void;
8
8
  export {};
@@ -1,7 +1,6 @@
1
1
  /* eslint-disable @typescript-eslint/ban-ts-comment*/
2
2
  import * as iam from "aws-cdk-lib/aws-iam";
3
3
  import { isCDKConstruct, isCDKConstructOf } from "../Construct.js";
4
- import { Logger } from "../../logger.js";
5
4
  import { Api } from "../Api.js";
6
5
  import { ApiGatewayV1Api } from "../ApiGatewayV1Api.js";
7
6
  import { Stack } from "../Stack.js";
@@ -18,8 +17,8 @@ import { RDS } from "../RDS.js";
18
17
  import { Job } from "../Job.js";
19
18
  export function attachPermissionsToRole(role, permissions) {
20
19
  const { statements, grants } = permissionsToStatementsAndGrants(permissions);
21
- statements.forEach(statement => role.addToPolicy(statement));
22
- grants.forEach(grant => {
20
+ statements.forEach((statement) => role.addToPolicy(statement));
21
+ grants.forEach((grant) => {
23
22
  const construct = grant[0];
24
23
  const methodName = grant[1];
25
24
  construct[methodName](role);
@@ -27,8 +26,8 @@ export function attachPermissionsToRole(role, permissions) {
27
26
  }
28
27
  export function attachPermissionsToPolicy(policy, permissions) {
29
28
  const { statements, grants } = permissionsToStatementsAndGrants(permissions);
30
- statements.forEach(statement => policy.addStatements(statement));
31
- grants.forEach(grant => {
29
+ statements.forEach((statement) => policy.addStatements(statement));
30
+ grants.forEach((grant) => {
32
31
  throw new Error(`Cannot attach the "${grant[1]}" permission to an IAM policy.`);
33
32
  });
34
33
  }
@@ -57,7 +56,7 @@ function permissionsToStatementsAndGrants(permissions) {
57
56
  if (permissions === "*") {
58
57
  return {
59
58
  statements: [buildPolicyStatement(permissions, ["*"])],
60
- grants: []
59
+ grants: [],
61
60
  };
62
61
  }
63
62
  if (!Array.isArray(permissions)) {
@@ -85,33 +84,33 @@ function permissionsToStatementsAndGrants(permissions) {
85
84
  ////////////////////////////////////
86
85
  else if (permission instanceof Api) {
87
86
  const httpApi = permission.cdk.httpApi;
88
- const { account, region } = Stack.of(httpApi);
87
+ const { account, region, partition } = Stack.of(httpApi);
89
88
  statements.push(buildPolicyStatement("execute-api:Invoke", [
90
- `arn:aws:execute-api:${region}:${account}:${httpApi.httpApiId}/*`
89
+ `arn:${partition}:execute-api:${region}:${account}:${httpApi.httpApiId}/*`,
91
90
  ]));
92
91
  }
93
92
  else if (permission instanceof ApiGatewayV1Api) {
94
93
  const restApi = permission.cdk.restApi;
95
- const { account, region } = Stack.of(restApi);
94
+ const { account, region, partition } = Stack.of(restApi);
96
95
  statements.push(buildPolicyStatement("execute-api:Invoke", [
97
- `arn:aws:execute-api:${region}:${account}:${restApi.restApiId}/*`
96
+ `arn:${partition}:execute-api:${region}:${account}:${restApi.restApiId}/*`,
98
97
  ]));
99
98
  }
100
99
  else if (permission instanceof WebSocketApi) {
101
100
  const webSocketApi = permission.cdk.webSocketApi;
102
- const { account, region } = Stack.of(webSocketApi);
101
+ const { account, region, partition } = Stack.of(webSocketApi);
103
102
  statements.push(buildPolicyStatement("execute-api:Invoke", [
104
- `arn:aws:execute-api:${region}:${account}:${webSocketApi.apiId}/*`
103
+ `arn:${partition}:execute-api:${region}:${account}:${webSocketApi.apiId}/*`,
105
104
  ]));
106
105
  statements.push(buildPolicyStatement("execute-api:ManageConnections", [
107
- permission._connectionsArn
106
+ permission._connectionsArn,
108
107
  ]));
109
108
  }
110
109
  else if (permission instanceof AppSyncApi) {
111
110
  const graphqlApi = permission.cdk.graphqlApi;
112
- const { account, region } = Stack.of(graphqlApi);
111
+ const { account, region, partition } = Stack.of(graphqlApi);
113
112
  statements.push(buildPolicyStatement("appsync:GraphQL", [
114
- `arn:aws:appsync:${region}:${account}:apis/${graphqlApi.apiId}/*`
113
+ `arn:${partition}:appsync:${region}:${account}:apis/${graphqlApi.apiId}/*`,
115
114
  ]));
116
115
  }
117
116
  else if (permission instanceof Table) {
@@ -177,7 +176,7 @@ function permissionsToStatementsAndGrants(permissions) {
177
176
  else if (permission.deliveryStreamArn &&
178
177
  permission.deliveryStreamName) {
179
178
  statements.push(buildPolicyStatement("firehose:*", [
180
- permission.deliveryStreamArn
179
+ permission.deliveryStreamArn,
181
180
  ]));
182
181
  }
183
182
  else if (permission.bucketArn &&
@@ -212,7 +211,6 @@ function permissionsToStatementsAndGrants(permissions) {
212
211
  grants.push(permission);
213
212
  }
214
213
  else {
215
- Logger.debug("permission object", permission);
216
214
  throw new Error(`The specified permissions are not supported.`);
217
215
  }
218
216
  });
@@ -222,6 +220,6 @@ function buildPolicyStatement(actions, resources) {
222
220
  return new iam.PolicyStatement({
223
221
  effect: iam.Effect.ALLOW,
224
222
  actions: typeof actions === "string" ? [actions] : actions,
225
- resources
223
+ resources,
226
224
  });
227
225
  }
@@ -1,3 +1,3 @@
1
1
  import * as cdk from "aws-cdk-lib";
2
- export declare type Size = `${number} ${"MB" | "GB"}`;
2
+ export type Size = `${number} ${"MB" | "GB"}`;
3
3
  export declare function toCdkSize(size: Size): cdk.Size;