sst 2.0.0-rc.7 → 2.0.0-rc.71

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 +4 -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 +71 -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 +27 -24
  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 +6350 -20851
  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 +80 -1
  203. package/support/bootstrap-metadata-function/index.mjs +68740 -0
  204. package/support/bridge/bridge.mjs +89 -28
  205. package/support/certificate-requestor/index.js +549 -0
  206. package/support/custom-resources/index.mjs +3843 -26565
  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 +80 -72
  212. package/support/rds-migrator/index.mjs +27 -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
package/bootstrap.d.ts CHANGED
@@ -1,6 +1,4 @@
1
- export declare const LATEST_VERSION = "3";
2
1
  export declare const useBootstrap: () => Promise<{
3
- version: string | undefined;
4
- bucket: string | undefined;
5
- stack: string | undefined;
2
+ version: string;
3
+ bucket: string;
6
4
  }>;
package/bootstrap.js CHANGED
@@ -1,79 +1,226 @@
1
- import { GetParametersCommand, SSMClient } from "@aws-sdk/client-ssm";
2
- import { Tags, Stack, RemovalPolicy, App } from "aws-cdk-lib";
1
+ import url from "url";
2
+ import path from "path";
3
+ import { bold, dim } from "colorette";
4
+ import { spawn } from "child_process";
5
+ import { DescribeStacksCommand, CloudFormationClient, } from "@aws-sdk/client-cloudformation";
6
+ import { Tags, Stack, RemovalPolicy, App, CfnOutput } from "aws-cdk-lib";
7
+ import { Function, Runtime, Code } from "aws-cdk-lib/aws-lambda";
8
+ import { SqsEventSource } from "aws-cdk-lib/aws-lambda-event-sources";
9
+ import { PolicyStatement } from "aws-cdk-lib/aws-iam";
10
+ import { Queue } from "aws-cdk-lib/aws-sqs";
11
+ import { Rule } from "aws-cdk-lib/aws-events";
12
+ import { SqsQueue } from "aws-cdk-lib/aws-events-targets";
3
13
  import { BlockPublicAccess, Bucket, BucketEncryption, } from "aws-cdk-lib/aws-s3";
4
- import { ParameterTier, StringParameter } from "aws-cdk-lib/aws-ssm";
5
- import { useProject } from "./app.js";
14
+ import { useProject } from "./project.js";
6
15
  import { createSpinner } from "./cli/spinner.js";
7
16
  import { Context } from "./context/context.js";
8
- import { useAWSClient } from "./credentials.js";
17
+ import { useAWSClient, useAWSCredentials, useSTSIdentity, } from "./credentials.js";
9
18
  import { VisibleError } from "./error.js";
10
19
  import { Logger } from "./logger.js";
11
20
  import { Stacks } from "./stacks/index.js";
12
- const SSM_NAME_VERSION = `/sst/bootstrap/version`;
13
- const SSM_NAME_STACK_NAME = `/sst/bootstrap/stack-name`;
14
- const SSM_NAME_BUCKET_NAME = `/sst/bootstrap/bucket-name`;
15
- export const LATEST_VERSION = "3";
21
+ const STACK_NAME = "SSTBootstrap";
22
+ const OUTPUT_VERSION = "Version";
23
+ const OUTPUT_BUCKET = "BucketName";
24
+ const LATEST_VERSION = "6";
25
+ const __dirname = url.fileURLToPath(new URL(".", import.meta.url));
16
26
  export const useBootstrap = Context.memo(async () => {
17
27
  Logger.debug("Initializing bootstrap context");
18
- const ret = await ssm();
19
- if (!ret.version ||
20
- !ret.bucket ||
21
- !ret.stack ||
22
- ret.version !== LATEST_VERSION) {
23
- const project = useProject();
28
+ let [cdkStatus, sstStatus] = await Promise.all([
29
+ loadCDKStatus(),
30
+ loadSSTStatus(),
31
+ ]);
32
+ Logger.debug("Loaded bootstrap status");
33
+ const needToBootstrapCDK = !cdkStatus;
34
+ const needToBootstrapSST = !sstStatus || sstStatus.version !== LATEST_VERSION;
35
+ if (needToBootstrapCDK || needToBootstrapSST) {
24
36
  const spinner = createSpinner("Deploying bootstrap stack, this only needs to happen once").start();
25
- const app = new App();
26
- const stack = new Stack(app, "SSTBootstrap", {
37
+ if (needToBootstrapCDK) {
38
+ await bootstrapCDK();
39
+ }
40
+ if (needToBootstrapSST) {
41
+ await bootstrapSST();
42
+ // fetch bootstrap status
43
+ sstStatus = await loadSSTStatus();
44
+ if (!sstStatus)
45
+ throw new VisibleError("Failed to load bootstrap stack status");
46
+ }
47
+ spinner.succeed();
48
+ }
49
+ Logger.debug("Bootstrap context initialized", sstStatus);
50
+ return sstStatus;
51
+ }, "Bootstrap");
52
+ async function loadCDKStatus() {
53
+ const client = useAWSClient(CloudFormationClient);
54
+ try {
55
+ const { Stacks: stacks } = await client.send(new DescribeStacksCommand({
56
+ StackName: "CDKToolkit",
57
+ }));
58
+ if (stacks &&
59
+ stacks.length > 0 &&
60
+ ["CREATE_COMPLETE", "UPDATE_COMPLETE"].includes(stacks[0].StackStatus)) {
61
+ return true;
62
+ }
63
+ }
64
+ catch (e) {
65
+ if (e.name === "ValidationError" &&
66
+ e.message === "Stack with id CDKToolkit does not exist") {
67
+ return false;
68
+ }
69
+ else {
70
+ throw e;
71
+ }
72
+ }
73
+ return false;
74
+ }
75
+ async function bootstrapSST() {
76
+ // Create bootstrap stack
77
+ const project = useProject();
78
+ const app = new App();
79
+ const stack = new Stack(app, STACK_NAME, {
80
+ env: {
81
+ region: project.config.region,
82
+ },
83
+ });
84
+ // Add tags to stack
85
+ const tags = {};
86
+ for (const [key, value] of Object.entries(tags)) {
87
+ Tags.of(app).add(key, value);
88
+ }
89
+ // Create S3 bucket to store stacks metadata
90
+ const bucket = new Bucket(stack, project.config.region, {
91
+ encryption: BucketEncryption.S3_MANAGED,
92
+ removalPolicy: RemovalPolicy.DESTROY,
93
+ autoDeleteObjects: true,
94
+ blockPublicAccess: BlockPublicAccess.BLOCK_ALL,
95
+ });
96
+ // Create Function and subscribe to CloudFormation events
97
+ const fn = new Function(stack, "MetadataHandler", {
98
+ code: Code.fromAsset(path.resolve(__dirname, "support/bootstrap-metadata-function")),
99
+ handler: "index.handler",
100
+ runtime: Runtime.NODEJS_18_X,
101
+ environment: {
102
+ BUCKET_NAME: bucket.bucketName,
103
+ },
104
+ initialPolicy: [
105
+ new PolicyStatement({
106
+ actions: ["cloudformation:DescribeStacks"],
107
+ resources: ["*"],
108
+ }),
109
+ new PolicyStatement({
110
+ actions: ["s3:PutObject", "s3:DeleteObject"],
111
+ resources: [bucket.bucketArn + "/*"],
112
+ }),
113
+ new PolicyStatement({
114
+ actions: ["iot:Publish"],
115
+ resources: [
116
+ `arn:${stack.partition}:iot:${stack.region}:${stack.account}:topic//sst/*`,
117
+ ],
118
+ }),
119
+ ],
120
+ });
121
+ const queue = new Queue(stack, "MetadataQueue");
122
+ fn.addEventSource(new SqsEventSource(queue));
123
+ const rule = new Rule(stack, "MetadataRule", {
124
+ eventPattern: {
125
+ source: ["aws.cloudformation"],
126
+ detailType: ["CloudFormation Stack Status Change"],
127
+ detail: {
128
+ "status-details": {
129
+ status: [
130
+ "CREATE_COMPLETE",
131
+ "UPDATE_COMPLETE",
132
+ "UPDATE_ROLLBACK_COMPLETE",
133
+ "ROLLBACK_COMPLETE",
134
+ "DELETE_COMPLETE",
135
+ ],
136
+ },
137
+ },
138
+ },
139
+ });
140
+ rule.addTarget(new SqsQueue(queue, {
141
+ retryAttempts: 10,
142
+ }));
143
+ // Create stack outputs to store bootstrap stack info
144
+ new CfnOutput(stack, OUTPUT_VERSION, { value: LATEST_VERSION });
145
+ new CfnOutput(stack, OUTPUT_BUCKET, { value: bucket.bucketName });
146
+ // Deploy bootstrap stack
147
+ const asm = app.synth();
148
+ const result = await Stacks.deploy(asm.stacks[0]);
149
+ if (Stacks.isFailed(result.status)) {
150
+ throw new VisibleError(`Failed to deploy bootstrap stack:\n${JSON.stringify(result.errors, null, 4)}`);
151
+ }
152
+ }
153
+ async function bootstrapCDK() {
154
+ const identity = await useSTSIdentity();
155
+ const credentials = await useAWSCredentials();
156
+ const { region, profile } = useProject().config;
157
+ await new Promise((resolve, reject) => {
158
+ const proc = spawn([
159
+ "npx",
160
+ "cdk",
161
+ "bootstrap",
162
+ `aws://${identity.Account}/${region}`,
163
+ "--no-version-reporting",
164
+ ].join(" "), {
27
165
  env: {
28
- region: project.region,
166
+ ...process.env,
167
+ AWS_ACCESS_KEY_ID: credentials.accessKeyId,
168
+ AWS_SECRET_ACCESS_KEY: credentials.secretAccessKey,
169
+ AWS_SESSION_TOKEN: credentials.sessionToken,
170
+ AWS_REGION: region,
171
+ AWS_PROFILE: profile,
29
172
  },
173
+ stdio: "pipe",
174
+ shell: process.env.SHELL || true,
30
175
  });
31
- const tags = {};
32
- for (const [key, value] of Object.entries(tags)) {
33
- Tags.of(app).add(key, value);
34
- }
35
- const bucket = new Bucket(stack, project.region, {
36
- encryption: BucketEncryption.S3_MANAGED,
37
- removalPolicy: RemovalPolicy.DESTROY,
38
- autoDeleteObjects: true,
39
- blockPublicAccess: BlockPublicAccess.BLOCK_ALL,
40
- });
41
- new StringParameter(stack, SSM_NAME_VERSION, {
42
- parameterName: SSM_NAME_VERSION,
43
- stringValue: LATEST_VERSION,
44
- tier: ParameterTier.STANDARD,
176
+ let stderr = "";
177
+ proc.stdout.on("data", (data) => {
178
+ Logger.debug(data.toString());
45
179
  });
46
- new StringParameter(stack, SSM_NAME_STACK_NAME, {
47
- parameterName: SSM_NAME_STACK_NAME,
48
- stringValue: stack.stackName,
49
- tier: ParameterTier.STANDARD,
180
+ proc.stderr.on("data", (data) => {
181
+ Logger.debug(data.toString());
182
+ stderr += data;
50
183
  });
51
- new StringParameter(stack, SSM_NAME_BUCKET_NAME, {
52
- parameterName: SSM_NAME_BUCKET_NAME,
53
- stringValue: bucket.bucketName,
54
- tier: ParameterTier.STANDARD,
184
+ proc.on("exit", (code) => {
185
+ Logger.debug("CDK bootstrap exited with code " + code);
186
+ if (code === 0) {
187
+ resolve();
188
+ }
189
+ else {
190
+ console.log(bold(dim(stderr)));
191
+ reject(new VisibleError(`Failed to bootstrap`));
192
+ }
55
193
  });
56
- const asm = app.synth();
57
- const result = await Stacks.deploy(asm.stacks[0]);
58
- if (Stacks.isFailed(result.status)) {
59
- throw new VisibleError(`Failed to deploy bootstrap stack:\n${JSON.stringify(result.errors, null, 4)}`);
194
+ });
195
+ }
196
+ async function loadSSTStatus() {
197
+ // Get bootstrap CloudFormation stack
198
+ const cf = useAWSClient(CloudFormationClient);
199
+ let result;
200
+ try {
201
+ result = await cf.send(new DescribeStacksCommand({
202
+ StackName: STACK_NAME,
203
+ }));
204
+ }
205
+ catch (e) {
206
+ if (e.Code === "ValidationError" &&
207
+ e.message === `Stack with id ${STACK_NAME} does not exist`) {
208
+ return null;
60
209
  }
61
- spinner.succeed();
62
- return ssm();
210
+ throw e;
63
211
  }
64
- Logger.debug("Loaded bootstrap info: ", JSON.stringify(ret));
65
- return ret;
66
- });
67
- async function ssm() {
68
- const ssm = useAWSClient(SSMClient);
69
- const result = await ssm.send(new GetParametersCommand({
70
- Names: [SSM_NAME_VERSION, SSM_NAME_STACK_NAME, SSM_NAME_BUCKET_NAME],
71
- }));
72
- return {
73
- version: result.Parameters.find((p) => p.Name === SSM_NAME_VERSION)?.Value,
74
- bucket: result.Parameters.find((p) => p.Name === SSM_NAME_BUCKET_NAME)
75
- ?.Value,
76
- stack: result.Parameters.find((p) => p.Name === SSM_NAME_STACK_NAME)
77
- ?.Value,
78
- };
212
+ // Parse stack outputs
213
+ let version, bucket;
214
+ (result.Stacks[0].Outputs || []).forEach((o) => {
215
+ if (o.OutputKey === OUTPUT_VERSION) {
216
+ version = o.OutputValue;
217
+ }
218
+ else if (o.OutputKey === OUTPUT_BUCKET) {
219
+ bucket = o.OutputValue;
220
+ }
221
+ });
222
+ if (!version || !bucket) {
223
+ return null;
224
+ }
225
+ return { version, bucket };
79
226
  }
package/bus.d.ts CHANGED
@@ -1,12 +1,12 @@
1
1
  export interface Events {
2
2
  }
3
- export declare type EventTypes = keyof Events;
4
- export declare type EventPayload<Type extends EventTypes = EventTypes> = {
3
+ export type EventTypes = keyof Events;
4
+ export type EventPayload<Type extends EventTypes = EventTypes> = {
5
5
  type: Type;
6
6
  sourceID: string;
7
7
  properties: Events[Type];
8
8
  };
9
- declare type Subscription = {
9
+ type Subscription = {
10
10
  type: EventTypes;
11
11
  cb: (payload: any) => void;
12
12
  };
package/bus.js CHANGED
@@ -30,7 +30,7 @@ export const useBus = Context.memo(() => {
30
30
  unsubscribe(sub) {
31
31
  const arr = subscribers(sub.type);
32
32
  const index = arr.indexOf(sub);
33
- if (!index)
33
+ if (index < 0)
34
34
  return;
35
35
  arr.splice(index, 1);
36
36
  },
package/cache.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import path from "path";
2
2
  import fs from "fs/promises";
3
- import { useProject } from "./app.js";
3
+ import { useProject } from "./project.js";
4
4
  import { Logger } from "./logger.js";
5
5
  import { Context } from "./context/context.js";
6
6
  export const useCache = Context.memo(async () => {
@@ -0,0 +1,3 @@
1
+ import { SdkProvider } from "aws-cdk/lib/api/aws-auth/sdk-provider.js";
2
+ import { DeployStackOptions as PublishStackAssetsOptions } from "./cloudformation-deployments.js";
3
+ export declare function publishDeployAssets(sdkProvider: SdkProvider, options: PublishStackAssetsOptions): Promise<any>;
@@ -0,0 +1,117 @@
1
+ import { debug } from "aws-cdk/lib/logging.js";
2
+ import { CloudFormationStack, TemplateParameters, waitForStackDelete, } from "aws-cdk/lib/api/util/cloudformation.js";
3
+ import { ToolkitInfo } from "aws-cdk/lib/api/toolkit-info.js";
4
+ import { addMetadataAssetsToManifest } from "aws-cdk/lib/assets.js";
5
+ import { publishAssets } from "aws-cdk/lib/util/asset-publishing.js";
6
+ import { AssetManifestBuilder } from "aws-cdk/lib/util/asset-manifest-builder.js";
7
+ import { CloudFormationDeployments, } from "./cloudformation-deployments.js";
8
+ import { makeBodyParameter } from "./deploy-stack.js";
9
+ import { Context } from "../context/context.js";
10
+ export async function publishDeployAssets(sdkProvider, options) {
11
+ const { deployment, toolkitInfo, stackSdk, resolvedEnvironment, cloudFormationRoleArn, } = await useDeployment().get(sdkProvider, options);
12
+ await deployment.publishStackAssets(options.stack, toolkitInfo, {
13
+ buildAssets: options.buildAssets ?? true,
14
+ publishOptions: {
15
+ quiet: options.quiet,
16
+ parallel: options.assetParallelism,
17
+ },
18
+ });
19
+ return deployStack({
20
+ stack: options.stack,
21
+ noMonitor: true,
22
+ resolvedEnvironment,
23
+ deployName: options.deployName,
24
+ notificationArns: options.notificationArns,
25
+ quiet: options.quiet,
26
+ sdk: stackSdk,
27
+ sdkProvider,
28
+ roleArn: cloudFormationRoleArn,
29
+ reuseAssets: options.reuseAssets,
30
+ toolkitInfo,
31
+ tags: options.tags,
32
+ deploymentMethod: options.deploymentMethod,
33
+ force: options.force,
34
+ parameters: options.parameters,
35
+ usePreviousParameters: options.usePreviousParameters,
36
+ progress: options.progress,
37
+ ci: options.ci,
38
+ rollback: options.rollback,
39
+ hotswap: options.hotswap,
40
+ extraUserAgent: options.extraUserAgent,
41
+ resourcesToImport: options.resourcesToImport,
42
+ overrideTemplate: options.overrideTemplate,
43
+ assetParallelism: options.assetParallelism,
44
+ });
45
+ }
46
+ const useDeployment = Context.memo(() => {
47
+ const state = new Map();
48
+ return {
49
+ async get(sdkProvider, options) {
50
+ if (!state.has(sdkProvider)) {
51
+ const deployment = new CloudFormationDeployments({ sdkProvider });
52
+ const { stackSdk, resolvedEnvironment, cloudFormationRoleArn } = await deployment.prepareSdkFor(options.stack, options.roleArn);
53
+ const toolkitInfo = await ToolkitInfo.lookup(resolvedEnvironment, stackSdk, options.toolkitStackName);
54
+ // Do a verification of the bootstrap stack version
55
+ await deployment.validateBootstrapStackVersion(options.stack.stackName, options.stack.requiresBootstrapStackVersion, options.stack.bootstrapStackVersionSsmParameter, toolkitInfo);
56
+ state.set(sdkProvider, {
57
+ deployment,
58
+ toolkitInfo,
59
+ stackSdk,
60
+ resolvedEnvironment,
61
+ cloudFormationRoleArn,
62
+ });
63
+ }
64
+ return state.get(sdkProvider);
65
+ },
66
+ };
67
+ });
68
+ async function deployStack(options) {
69
+ const stackArtifact = options.stack;
70
+ const stackEnv = options.resolvedEnvironment;
71
+ options.sdk.appendCustomUserAgent(options.extraUserAgent);
72
+ const cfn = options.sdk.cloudFormation();
73
+ const deployName = options.deployName || stackArtifact.stackName;
74
+ let cloudFormationStack = await CloudFormationStack.lookup(cfn, deployName);
75
+ if (cloudFormationStack.stackStatus.isCreationFailure) {
76
+ debug(`Found existing stack ${deployName} that had previously failed creation. Deleting it before attempting to re-create it.`);
77
+ await cfn.deleteStack({ StackName: deployName }).promise();
78
+ const deletedStack = await waitForStackDelete(cfn, deployName);
79
+ if (deletedStack && deletedStack.stackStatus.name !== "DELETE_COMPLETE") {
80
+ throw new Error(`Failed deleting stack ${deployName} that had previously failed creation (current state: ${deletedStack.stackStatus})`);
81
+ }
82
+ // Update variable to mark that the stack does not exist anymore, but avoid
83
+ // doing an actual lookup in CloudFormation (which would be silly to do if
84
+ // we just deleted it).
85
+ cloudFormationStack = CloudFormationStack.doesNotExist(cfn, deployName);
86
+ }
87
+ // Detect "legacy" assets (which remain in the metadata) and publish them via
88
+ // an ad-hoc asset manifest, while passing their locations via template
89
+ // parameters.
90
+ const legacyAssets = new AssetManifestBuilder();
91
+ const assetParams = await addMetadataAssetsToManifest(stackArtifact, legacyAssets, options.toolkitInfo, options.reuseAssets);
92
+ const finalParameterValues = { ...options.parameters, ...assetParams };
93
+ const templateParams = TemplateParameters.fromTemplate(stackArtifact.template);
94
+ const stackParams = options.usePreviousParameters
95
+ ? templateParams.updateExisting(finalParameterValues, cloudFormationStack.parameters)
96
+ : templateParams.supplyAll(finalParameterValues);
97
+ const bodyParameter = await makeBodyParameter(stackArtifact, options.resolvedEnvironment, legacyAssets, options.toolkitInfo, options.sdk, options.overrideTemplate);
98
+ await publishAssets(legacyAssets.toManifest(stackArtifact.assembly.directory), options.sdkProvider, stackEnv, {
99
+ parallel: options.assetParallelism,
100
+ });
101
+ return {
102
+ isUpdate: cloudFormationStack.exists &&
103
+ cloudFormationStack.stackStatus.name !== "REVIEW_IN_PROGRESS",
104
+ params: {
105
+ StackName: deployName,
106
+ TemplateBody: bodyParameter.TemplateBody,
107
+ TemplateURL: bodyParameter.TemplateURL,
108
+ Parameters: stackParams.apiParameters,
109
+ Capabilities: [
110
+ "CAPABILITY_IAM",
111
+ "CAPABILITY_NAMED_IAM",
112
+ "CAPABILITY_AUTO_EXPAND",
113
+ ],
114
+ Tags: options.tags,
115
+ },
116
+ };
117
+ }
@@ -1,9 +1,11 @@
1
1
  import * as cxapi from "@aws-cdk/cx-api";
2
2
  import { Tag } from "aws-cdk/lib/cdk-toolkit.js";
3
- import { BuildAssetsOptions } from "aws-cdk/lib/util/asset-publishing.js";
3
+ import { BuildAssetsOptions, PublishAssetsOptions } from "aws-cdk/lib/util/asset-publishing.js";
4
+ import { Mode } from "aws-cdk/lib/api/aws-auth/credentials.js";
4
5
  import { ISDK } from "aws-cdk/lib/api/aws-auth/sdk.js";
5
6
  import { SdkProvider } from "aws-cdk/lib/api/aws-auth/sdk-provider.js";
6
7
  import { DeployStackResult, DeploymentMethod } from "./deploy-stack.js";
8
+ import { ToolkitInfo } from "aws-cdk/lib/api/toolkit-info.js";
7
9
  import { Template, ResourcesToImport, ResourceIdentifierSummaries } from "aws-cdk/lib/api/util/cloudformation.js";
8
10
  import { StackActivityProgress } from "aws-cdk/lib/api/util/cloudformation/stack-activity-monitor.js";
9
11
  /**
@@ -203,6 +205,18 @@ export interface BuildStackAssetsOptions {
203
205
  */
204
206
  readonly buildOptions?: BuildAssetsOptions;
205
207
  }
208
+ interface PublishStackAssetsOptions {
209
+ /**
210
+ * Whether to build assets before publishing.
211
+ *
212
+ * @default true To remain backward compatible.
213
+ */
214
+ readonly buildAssets?: boolean;
215
+ /**
216
+ * Options to pass on to `publishAsests()` function
217
+ */
218
+ readonly publishOptions?: Omit<PublishAssetsOptions, "buildAssets">;
219
+ }
206
220
  export interface DestroyStackOptions {
207
221
  stack: cxapi.CloudFormationStackArtifact;
208
222
  deployName?: string;
@@ -264,7 +278,7 @@ export declare class CloudFormationDeployments {
264
278
  * - SDK loaded with the right credentials for calling `CreateChangeSet`.
265
279
  * - The Execution Role that should be passed to CloudFormation.
266
280
  */
267
- private prepareSdkFor;
281
+ prepareSdkFor(stack: cxapi.CloudFormationStackArtifact, roleArn?: string, mode?: Mode): Promise<PreparedSdkForEnvironment>;
268
282
  /**
269
283
  * Build a stack's assets.
270
284
  */
@@ -272,9 +286,10 @@ export declare class CloudFormationDeployments {
272
286
  /**
273
287
  * Publish all asset manifests that are referenced by the given stack
274
288
  */
275
- private publishStackAssets;
289
+ publishStackAssets(stack: cxapi.CloudFormationStackArtifact, toolkitInfo: ToolkitInfo, options?: PublishStackAssetsOptions): Promise<void>;
276
290
  /**
277
291
  * Validate that the bootstrap stack has the right version for this stack
278
292
  */
279
- private validateBootstrapStackVersion;
293
+ validateBootstrapStackVersion(stackName: string, requiresBootstrapStackVersion: number | undefined, bootstrapStackVersionSsmParameter: string | undefined, toolkitInfo: ToolkitInfo): Promise<void>;
280
294
  }
295
+ export {};
@@ -1,10 +1,11 @@
1
1
  import * as cxapi from "@aws-cdk/cx-api";
2
2
  import { Tag } from "aws-cdk/lib/cdk-toolkit.js";
3
+ import { AssetManifestBuilder } from "aws-cdk/lib/util/asset-manifest-builder.js";
3
4
  import { ISDK, SdkProvider } from "aws-cdk/lib/api/aws-auth/index.js";
4
5
  import { ToolkitInfo } from "aws-cdk/lib/api/toolkit-info.js";
5
6
  import { ResourcesToImport } from "aws-cdk/lib/api/util/cloudformation.js";
6
7
  import { StackActivityProgress } from "aws-cdk/lib/api/util/cloudformation/stack-activity-monitor.js";
7
- declare type TemplateBodyParameter = {
8
+ type TemplateBodyParameter = {
8
9
  TemplateBody?: string;
9
10
  TemplateURL?: string;
10
11
  };
@@ -166,7 +167,7 @@ export interface DeployStackOptions {
166
167
  */
167
168
  readonly assetParallelism?: boolean;
168
169
  }
169
- export declare type DeploymentMethod = DirectDeploymentMethod | ChangeSetDeploymentMethod;
170
+ export type DeploymentMethod = DirectDeploymentMethod | ChangeSetDeploymentMethod;
170
171
  export interface DirectDeploymentMethod {
171
172
  readonly method: "direct";
172
173
  }
@@ -185,6 +186,20 @@ export interface ChangeSetDeploymentMethod {
185
186
  readonly changeSetName?: string;
186
187
  }
187
188
  export declare function deployStack(options: DeployStackOptions): Promise<DeployStackResult | undefined>;
189
+ /**
190
+ * Prepares the body parameter for +CreateChangeSet+.
191
+ *
192
+ * If the template is small enough to be inlined into the API call, just return
193
+ * it immediately.
194
+ *
195
+ * Otherwise, add it to the asset manifest to get uploaded to the staging
196
+ * bucket and return its coordinates. If there is no staging bucket, an error
197
+ * is thrown.
198
+ *
199
+ * @param stack the synthesized stack that provides the CloudFormation template
200
+ * @param toolkitInfo information about the toolkit stack
201
+ */
202
+ export declare function makeBodyParameter(stack: cxapi.CloudFormationStackArtifact, resolvedEnvironment: cxapi.Environment, assetManifest: AssetManifestBuilder, toolkitInfo: ToolkitInfo, sdk: ISDK, overrideTemplate?: any): Promise<TemplateBodyParameter>;
188
203
  /**
189
204
  * Prepare a body parameter for CFN, performing the upload
190
205
  *
@@ -340,7 +340,7 @@ class FullCloudFormationDeployment {
340
340
  * @param stack the synthesized stack that provides the CloudFormation template
341
341
  * @param toolkitInfo information about the toolkit stack
342
342
  */
343
- async function makeBodyParameter(stack, resolvedEnvironment, assetManifest, toolkitInfo, sdk, overrideTemplate) {
343
+ export async function makeBodyParameter(stack, resolvedEnvironment, assetManifest, toolkitInfo, sdk, overrideTemplate) {
344
344
  // If the template has already been uploaded to S3, just use it from there.
345
345
  if (stack.stackTemplateAssetObjectUrl && !overrideTemplate) {
346
346
  return {
@@ -459,6 +459,11 @@ async function canSkipDeploy(deployStackOptions, cloudFormationStack, parameterC
459
459
  debug(`${deployName}: no existing stack`);
460
460
  return false;
461
461
  }
462
+ // SST check: stack is not busy
463
+ if (cloudFormationStack.stackStatus.isInProgress) {
464
+ debug(`${deployName}: stack is busy`);
465
+ return false;
466
+ }
462
467
  // Template has changed (assets taken into account here)
463
468
  if (JSON.stringify(deployStackOptions.stack.template) !==
464
469
  JSON.stringify(await cloudFormationStack.template())) {
@@ -0,0 +1,28 @@
1
+ import chalk from "chalk";
2
+ declare let last: "line" | "gap";
3
+ export declare const Colors: {
4
+ line: (message?: any, ...optionalParams: any[]) => void;
5
+ mode(input: typeof last): void;
6
+ gap(): void;
7
+ hex: (color: string) => chalk.Chalk;
8
+ primary: chalk.Chalk;
9
+ link: chalk.Chalk;
10
+ success: chalk.Chalk;
11
+ danger: chalk.Chalk;
12
+ warning: chalk.Chalk;
13
+ dim: chalk.Chalk;
14
+ bold: chalk.Chalk;
15
+ all: chalk.Chalk & chalk.ChalkFunction & {
16
+ supportsColor: false | chalk.ColorSupport;
17
+ Level: chalk.Level;
18
+ Color: ("red" | "green" | "yellow" | "black" | "blue" | "magenta" | "cyan" | "white" | "gray" | "grey" | "blackBright" | "redBright" | "greenBright" | "yellowBright" | "blueBright" | "magentaBright" | "cyanBright" | "whiteBright") | ("bgBlack" | "bgRed" | "bgGreen" | "bgYellow" | "bgBlue" | "bgMagenta" | "bgCyan" | "bgWhite" | "bgGray" | "bgGrey" | "bgBlackBright" | "bgRedBright" | "bgGreenBright" | "bgYellowBright" | "bgBlueBright" | "bgMagentaBright" | "bgCyanBright" | "bgWhiteBright");
19
+ ForegroundColor: "red" | "green" | "yellow" | "black" | "blue" | "magenta" | "cyan" | "white" | "gray" | "grey" | "blackBright" | "redBright" | "greenBright" | "yellowBright" | "blueBright" | "magentaBright" | "cyanBright" | "whiteBright";
20
+ BackgroundColor: "bgBlack" | "bgRed" | "bgGreen" | "bgYellow" | "bgBlue" | "bgMagenta" | "bgCyan" | "bgWhite" | "bgGray" | "bgGrey" | "bgBlackBright" | "bgRedBright" | "bgGreenBright" | "bgYellowBright" | "bgBlueBright" | "bgMagentaBright" | "bgCyanBright" | "bgWhiteBright";
21
+ Modifiers: "bold" | "dim" | "reset" | "italic" | "underline" | "inverse" | "hidden" | "strikethrough" | "visible";
22
+ stderr: chalk.Chalk & {
23
+ supportsColor: false | chalk.ColorSupport;
24
+ };
25
+ };
26
+ prefix: string;
27
+ };
28
+ export {};
package/cli/colors.js ADDED
@@ -0,0 +1,27 @@
1
+ import chalk from "chalk";
2
+ let last = "gap";
3
+ export const Colors = {
4
+ line: (message, ...optionalParams) => {
5
+ last = "line";
6
+ console.log(message, ...optionalParams);
7
+ },
8
+ mode(input) {
9
+ last = input;
10
+ },
11
+ gap() {
12
+ if (last === "line") {
13
+ last = "gap";
14
+ console.log();
15
+ }
16
+ },
17
+ hex: chalk.hex,
18
+ primary: chalk.hex("#E27152"),
19
+ link: chalk.cyan,
20
+ success: chalk.green,
21
+ danger: chalk.red,
22
+ warning: chalk.yellow,
23
+ dim: chalk.dim,
24
+ bold: chalk.bold,
25
+ all: chalk,
26
+ prefix: chalk.bold("| "),
27
+ };
@@ -6,6 +6,10 @@ export declare const bind: (program: Program) => import("yargs").Argv<{
6
6
  profile: string | undefined;
7
7
  } & {
8
8
  region: string | undefined;
9
+ } & {
10
+ verbose: boolean | undefined;
11
+ } & {
12
+ role: string | undefined;
9
13
  } & {
10
14
  command: string;
11
15
  }>;