sst 2.0.0-rc.5 → 2.0.0-rc.51

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 (186) hide show
  1. package/bootstrap.d.ts +5 -6
  2. package/bootstrap.js +208 -62
  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 +112 -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 +25 -17
  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/build.d.ts +6 -2
  16. package/cli/commands/build.js +13 -8
  17. package/cli/commands/console.d.ts +5 -1
  18. package/cli/commands/console.js +8 -6
  19. package/cli/commands/deploy.d.ts +4 -2
  20. package/cli/commands/deploy.js +47 -30
  21. package/cli/commands/dev.d.ts +5 -1
  22. package/cli/commands/dev.js +126 -65
  23. package/cli/commands/diff.d.ts +15 -0
  24. package/cli/commands/diff.js +61 -0
  25. package/cli/commands/env.d.ts +5 -1
  26. package/cli/commands/env.js +14 -15
  27. package/cli/commands/plugins/kysely.js +13 -5
  28. package/cli/commands/plugins/pothos.js +6 -3
  29. package/cli/commands/remove.d.ts +4 -0
  30. package/cli/commands/remove.js +25 -18
  31. package/cli/commands/secrets/get.d.ts +7 -3
  32. package/cli/commands/secrets/get.js +11 -24
  33. package/cli/commands/secrets/list.d.ts +6 -2
  34. package/cli/commands/secrets/list.js +15 -7
  35. package/cli/commands/secrets/remove.d.ts +8 -4
  36. package/cli/commands/secrets/remove.js +18 -16
  37. package/cli/commands/secrets/secrets.js +3 -3
  38. package/cli/commands/secrets/set.d.ts +8 -6
  39. package/cli/commands/secrets/set.js +16 -33
  40. package/cli/commands/transform.d.ts +15 -0
  41. package/cli/commands/transform.js +55 -0
  42. package/cli/commands/update.d.ts +6 -2
  43. package/cli/commands/update.js +41 -33
  44. package/cli/commands/version.d.ts +13 -0
  45. package/cli/commands/version.js +7 -0
  46. package/cli/local/router.d.ts +6 -6
  47. package/cli/local/router.js +3 -3
  48. package/cli/local/server.d.ts +5 -3
  49. package/cli/local/server.js +21 -14
  50. package/cli/program.d.ts +5 -1
  51. package/cli/program.js +29 -5
  52. package/cli/spinner.js +2 -0
  53. package/cli/sst.js +25 -23
  54. package/cli/telemetry/environment.d.ts +1 -1
  55. package/cli/telemetry/environment.js +1 -1
  56. package/cli/terminal.d.ts +1 -0
  57. package/cli/terminal.js +8 -0
  58. package/cli/ui/deploy.d.ts +3 -2
  59. package/cli/ui/deploy.js +104 -106
  60. package/cli/ui/functions.d.ts +2 -0
  61. package/cli/ui/functions.js +132 -0
  62. package/cli/ui/header.d.ts +5 -0
  63. package/cli/ui/header.js +16 -0
  64. package/cli/ui/stack.d.ts +1 -0
  65. package/cli/ui/stack.js +6 -0
  66. package/config.d.ts +1 -1
  67. package/config.js +8 -8
  68. package/constructs/Api.d.ts +3 -71
  69. package/constructs/Api.js +0 -36
  70. package/constructs/ApiGatewayV1Api.d.ts +2 -2
  71. package/constructs/App.d.ts +2 -22
  72. package/constructs/App.js +13 -24
  73. package/constructs/AppSyncApi.d.ts +1 -1
  74. package/constructs/AppSyncApi.js +1 -1
  75. package/constructs/AstroSite.js +5 -2
  76. package/constructs/Auth.js +2 -2
  77. package/constructs/EdgeFunction.js +2 -2
  78. package/constructs/Function.d.ts +4 -44
  79. package/constructs/Function.js +8 -48
  80. package/constructs/FunctionalStack.d.ts +2 -2
  81. package/constructs/Job.d.ts +2 -41
  82. package/constructs/Job.js +5 -30
  83. package/constructs/Metadata.d.ts +18 -20
  84. package/constructs/NextjsSite.d.ts +1 -1
  85. package/constructs/NextjsSite.js +21 -4
  86. package/constructs/RDS.d.ts +1 -1
  87. package/constructs/RDS.js +1 -1
  88. package/constructs/Script.js +1 -1
  89. package/constructs/Secret.js +4 -2
  90. package/constructs/SsrSite.d.ts +23 -6
  91. package/constructs/SsrSite.js +56 -41
  92. package/constructs/Stack.d.ts +1 -20
  93. package/constructs/Stack.js +2 -64
  94. package/constructs/StaticSite.d.ts +3 -3
  95. package/constructs/StaticSite.js +10 -10
  96. package/constructs/Table.d.ts +1 -1
  97. package/constructs/deferred_task.d.ts +1 -1
  98. package/constructs/deprecated/NextjsSite.js +4 -4
  99. package/constructs/index.d.ts +0 -3
  100. package/constructs/index.js +0 -3
  101. package/constructs/util/apiGatewayV1AccessLog.d.ts +1 -1
  102. package/constructs/util/apiGatewayV2Domain.js +11 -2
  103. package/constructs/util/duration.d.ts +1 -1
  104. package/constructs/util/permission.d.ts +3 -3
  105. package/constructs/util/permission.js +8 -8
  106. package/constructs/util/size.d.ts +1 -1
  107. package/context/handler.d.ts +1 -1
  108. package/credentials.d.ts +1 -1
  109. package/credentials.js +23 -6
  110. package/index.d.ts +1 -0
  111. package/index.js +1 -0
  112. package/iot.js +6 -2
  113. package/logger.js +3 -1
  114. package/node/api/index.d.ts +2 -0
  115. package/node/api/index.js +8 -0
  116. package/node/auth/adapter/adapter.d.ts +1 -1
  117. package/node/auth/adapter/github.js +4 -4
  118. package/node/auth/adapter/google.d.ts +1 -1
  119. package/node/auth/session.d.ts +1 -1
  120. package/node/config/index.d.ts +2 -2
  121. package/node/job/index.d.ts +2 -2
  122. package/package.json +10 -12
  123. package/project.d.ts +47 -0
  124. package/{app.js → project.js} +61 -52
  125. package/runtime/handlers/dotnet.d.ts +1 -1
  126. package/runtime/handlers/dotnet.js +4 -4
  127. package/runtime/handlers/go.d.ts +1 -1
  128. package/runtime/handlers/go.js +3 -3
  129. package/runtime/handlers/java.d.ts +1 -1
  130. package/runtime/handlers/java.js +4 -4
  131. package/runtime/handlers/node.d.ts +1 -1
  132. package/runtime/handlers/node.js +61 -42
  133. package/runtime/handlers/python.d.ts +1 -1
  134. package/runtime/handlers/python.js +3 -3
  135. package/runtime/handlers.js +14 -11
  136. package/runtime/iot.js +3 -0
  137. package/runtime/runtime.d.ts +4 -0
  138. package/runtime/server.d.ts +3 -3
  139. package/runtime/server.js +10 -5
  140. package/runtime/workers.d.ts +3 -2
  141. package/runtime/workers.js +9 -3
  142. package/site-env.js +2 -1
  143. package/sst.mjs +3248 -18082
  144. package/stacks/assembly.d.ts +1 -0
  145. package/stacks/assembly.js +4 -0
  146. package/stacks/build.d.ts +1 -1
  147. package/stacks/build.js +41 -48
  148. package/stacks/deploy.d.ts +1 -0
  149. package/stacks/deploy.js +19 -6
  150. package/stacks/diff.d.ts +8 -0
  151. package/stacks/diff.js +62 -0
  152. package/stacks/index.d.ts +2 -0
  153. package/stacks/index.js +2 -0
  154. package/stacks/metadata.d.ts +2 -0
  155. package/stacks/metadata.js +14 -12
  156. package/stacks/monitor.d.ts +8 -3
  157. package/stacks/monitor.js +32 -4
  158. package/stacks/remove.js +0 -4
  159. package/stacks/synth.d.ts +1 -0
  160. package/stacks/synth.js +27 -13
  161. package/support/base-site-archiver.mjs +79 -0
  162. package/support/bootstrap-metadata-function/index.mjs +68728 -0
  163. package/support/bridge/bridge.mjs +89 -28
  164. package/support/custom-resources/index.mjs +102 -59214
  165. package/support/edge-function/edge-lambda.mjs +2 -2
  166. package/support/nodejs-runtime/index.mjs +79 -72
  167. package/support/rds-migrator/index.mjs +27 -23
  168. package/support/script-function/index.mjs +30485 -0
  169. package/support/ssr-site-function-archiver.mjs +96 -0
  170. package/watcher.js +1 -1
  171. package/app.d.ts +0 -36
  172. package/constructs/GraphQLApi.d.ts +0 -98
  173. package/constructs/GraphQLApi.js +0 -80
  174. package/constructs/ReactStaticSite.d.ts +0 -20
  175. package/constructs/ReactStaticSite.js +0 -54
  176. package/constructs/Script/cfn-response.d.ts +0 -19
  177. package/constructs/Script/cfn-response.js +0 -77
  178. package/constructs/Script/index.d.ts +0 -1
  179. package/constructs/Script/index.js +0 -78
  180. package/constructs/Script/outbound.d.ts +0 -10
  181. package/constructs/Script/outbound.js +0 -42
  182. package/constructs/Script/util.d.ts +0 -2
  183. package/constructs/Script/util.js +0 -11
  184. package/constructs/ViteStaticSite.d.ts +0 -32
  185. package/constructs/ViteStaticSite.js +0 -66
  186. package/support/base-site-archiver.cjs +0 -116
package/bootstrap.d.ts CHANGED
@@ -1,6 +1,5 @@
1
- export declare const LATEST_VERSION = "3";
2
- export declare const useBootstrap: () => Promise<{
3
- version: string | undefined;
4
- bucket: string | undefined;
5
- stack: string | undefined;
6
- }>;
1
+ export declare const useBootstrap: () => {
2
+ version: string;
3
+ bucket: string;
4
+ };
5
+ export declare function initBootstrap(): Promise<void>;
package/bootstrap.js CHANGED
@@ -1,79 +1,225 @@
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";
16
- export const useBootstrap = Context.memo(async () => {
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));
26
+ const BootstrapContext = Context.create();
27
+ export const useBootstrap = BootstrapContext.use;
28
+ export async function initBootstrap() {
17
29
  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();
30
+ let [cdkStatus, sstStatus] = await Promise.all([
31
+ loadCDKStatus(),
32
+ loadSSTStatus(),
33
+ ]);
34
+ Logger.debug("Loaded bootstrap status");
35
+ const needToBootstrapCDK = !cdkStatus;
36
+ const needToBootstrapSST = !sstStatus || sstStatus.version !== LATEST_VERSION;
37
+ if (needToBootstrapCDK || needToBootstrapSST) {
24
38
  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", {
39
+ if (needToBootstrapCDK) {
40
+ await bootstrapCDK();
41
+ }
42
+ if (needToBootstrapSST) {
43
+ await bootstrapSST();
44
+ // fetch bootstrap status
45
+ sstStatus = await loadSSTStatus();
46
+ if (!sstStatus)
47
+ throw new VisibleError("Failed to load bootstrap stack status");
48
+ }
49
+ spinner.succeed();
50
+ }
51
+ BootstrapContext.provide(sstStatus);
52
+ Logger.debug("Bootstrap context initialized", sstStatus);
53
+ }
54
+ async function loadCDKStatus() {
55
+ const client = useAWSClient(CloudFormationClient);
56
+ try {
57
+ const { Stacks: stacks } = await client.send(new DescribeStacksCommand({
58
+ StackName: "CDKToolkit",
59
+ }));
60
+ if (stacks &&
61
+ stacks.length > 0 &&
62
+ ["CREATE_COMPLETE", "UPDATE_COMPLETE"].includes(stacks[0].StackStatus)) {
63
+ return true;
64
+ }
65
+ }
66
+ catch (e) {
67
+ if (e.name === "ValidationError" &&
68
+ e.message === "Stack with id CDKToolkit does not exist") {
69
+ return false;
70
+ }
71
+ else {
72
+ throw e;
73
+ }
74
+ }
75
+ return false;
76
+ }
77
+ async function bootstrapSST() {
78
+ // Create bootstrap stack
79
+ const project = useProject();
80
+ const app = new App();
81
+ const stack = new Stack(app, STACK_NAME, {
82
+ env: {
83
+ region: project.config.region,
84
+ },
85
+ });
86
+ // Add tags to stack
87
+ const tags = {};
88
+ for (const [key, value] of Object.entries(tags)) {
89
+ Tags.of(app).add(key, value);
90
+ }
91
+ // Create S3 bucket to store stacks metadata
92
+ const bucket = new Bucket(stack, project.config.region, {
93
+ encryption: BucketEncryption.S3_MANAGED,
94
+ removalPolicy: RemovalPolicy.DESTROY,
95
+ autoDeleteObjects: true,
96
+ blockPublicAccess: BlockPublicAccess.BLOCK_ALL,
97
+ });
98
+ // Create Function and subscribe to CloudFormation events
99
+ const fn = new Function(stack, "MetadataHandler", {
100
+ code: Code.fromAsset(path.resolve(__dirname, "support/bootstrap-metadata-function")),
101
+ handler: "index.handler",
102
+ runtime: Runtime.NODEJS_18_X,
103
+ initialPolicy: [
104
+ new PolicyStatement({
105
+ actions: ["cloudformation:DescribeStacks"],
106
+ resources: ["*"],
107
+ }),
108
+ new PolicyStatement({
109
+ actions: ["s3:PutObject", "s3:DeleteObject"],
110
+ resources: [bucket.bucketArn + "/*"],
111
+ }),
112
+ new PolicyStatement({
113
+ actions: ["iot:Publish"],
114
+ resources: [
115
+ `arn:${stack.partition}:iot:${stack.region}:${stack.account}:topic//sst/*`,
116
+ ],
117
+ }),
118
+ ],
119
+ });
120
+ const queue = new Queue(stack, "MetadataQueue");
121
+ fn.addEventSource(new SqsEventSource(queue));
122
+ const rule = new Rule(stack, "MetadataRule", {
123
+ eventPattern: {
124
+ source: ["aws.cloudformation"],
125
+ detailType: ["CloudFormation Stack Status Change"],
126
+ detail: {
127
+ "status-details": {
128
+ status: [
129
+ "CREATE_COMPLETE",
130
+ "UPDATE_COMPLETE",
131
+ "UPDATE_ROLLBACK_COMPLETE",
132
+ "ROLLBACK_COMPLETE",
133
+ "DELETE_COMPLETE",
134
+ ],
135
+ },
136
+ },
137
+ },
138
+ });
139
+ rule.addTarget(new SqsQueue(queue, {
140
+ retryAttempts: 10,
141
+ }));
142
+ // Create stack outputs to store bootstrap stack info
143
+ new CfnOutput(stack, OUTPUT_VERSION, { value: LATEST_VERSION });
144
+ new CfnOutput(stack, OUTPUT_BUCKET, { value: bucket.bucketName });
145
+ // Deploy bootstrap stack
146
+ const asm = app.synth();
147
+ const result = await Stacks.deploy(asm.stacks[0]);
148
+ if (Stacks.isFailed(result.status)) {
149
+ throw new VisibleError(`Failed to deploy bootstrap stack:\n${JSON.stringify(result.errors, null, 4)}`);
150
+ }
151
+ }
152
+ async function bootstrapCDK() {
153
+ const identity = await useSTSIdentity();
154
+ const credentials = await useAWSCredentials();
155
+ const { region, profile } = useProject().config;
156
+ await new Promise((resolve, reject) => {
157
+ const proc = spawn([
158
+ "npx",
159
+ "cdk",
160
+ "bootstrap",
161
+ `aws://${identity.Account}/${region}`,
162
+ "--no-version-reporting",
163
+ ].join(" "), {
27
164
  env: {
28
- region: project.region,
165
+ ...process.env,
166
+ AWS_ACCESS_KEY_ID: credentials.accessKeyId,
167
+ AWS_SECRET_ACCESS_KEY: credentials.secretAccessKey,
168
+ AWS_SESSION_TOKEN: credentials.sessionToken,
169
+ AWS_REGION: region,
170
+ AWS_PROFILE: profile,
29
171
  },
172
+ stdio: "pipe",
173
+ shell: process.env.SHELL || true,
30
174
  });
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,
175
+ let stderr = "";
176
+ proc.stdout.on("data", (data) => {
177
+ Logger.debug(data.toString());
45
178
  });
46
- new StringParameter(stack, SSM_NAME_STACK_NAME, {
47
- parameterName: SSM_NAME_STACK_NAME,
48
- stringValue: stack.stackName,
49
- tier: ParameterTier.STANDARD,
179
+ proc.stderr.on("data", (data) => {
180
+ Logger.debug(data.toString());
181
+ stderr += data;
50
182
  });
51
- new StringParameter(stack, SSM_NAME_BUCKET_NAME, {
52
- parameterName: SSM_NAME_BUCKET_NAME,
53
- stringValue: bucket.bucketName,
54
- tier: ParameterTier.STANDARD,
183
+ proc.on("exit", (code) => {
184
+ Logger.debug("CDK bootstrap exited with code " + code);
185
+ if (code === 0) {
186
+ resolve();
187
+ }
188
+ else {
189
+ console.log(bold(dim(stderr)));
190
+ reject(new VisibleError(`Failed to bootstrap`));
191
+ }
55
192
  });
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)}`);
193
+ });
194
+ }
195
+ async function loadSSTStatus() {
196
+ // Get bootstrap CloudFormation stack
197
+ const cf = useAWSClient(CloudFormationClient);
198
+ let result;
199
+ try {
200
+ result = await cf.send(new DescribeStacksCommand({
201
+ StackName: STACK_NAME,
202
+ }));
203
+ }
204
+ catch (e) {
205
+ if (e.Code === "ValidationError" &&
206
+ e.message === `Stack with id ${STACK_NAME} does not exist`) {
207
+ return null;
60
208
  }
61
- spinner.succeed();
62
- return ssm();
209
+ throw e;
63
210
  }
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
- };
211
+ // Parse stack outputs
212
+ let version, bucket;
213
+ (result.Stacks[0].Outputs || []).forEach((o) => {
214
+ if (o.OutputKey === OUTPUT_VERSION) {
215
+ version = o.OutputValue;
216
+ }
217
+ else if (o.OutputKey === OUTPUT_BUCKET) {
218
+ bucket = o.OutputValue;
219
+ }
220
+ });
221
+ if (!version || !bucket) {
222
+ return null;
223
+ }
224
+ return { version, bucket };
79
225
  }
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,112 @@
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 && cloudFormationStack.stackStatus.name !== 'REVIEW_IN_PROGRESS',
103
+ params: {
104
+ StackName: deployName,
105
+ TemplateBody: bodyParameter.TemplateBody,
106
+ TemplateURL: bodyParameter.TemplateURL,
107
+ Parameters: stackParams.apiParameters,
108
+ Capabilities: ['CAPABILITY_IAM', 'CAPABILITY_NAMED_IAM', 'CAPABILITY_AUTO_EXPAND'],
109
+ Tags: options.tags,
110
+ },
111
+ };
112
+ }
@@ -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
  *
@@ -10,7 +10,6 @@ import { contentHash } from "aws-cdk/lib/util/content-hash.js";
10
10
  import { CfnEvaluationException } from "aws-cdk/lib/api/evaluate-cloudformation-template.js";
11
11
  import { tryHotswapDeployment } from "aws-cdk/lib/api/hotswap-deployments.js";
12
12
  import { changeSetHasNoChanges, CloudFormationStack, TemplateParameters, waitForChangeSet, waitForStackDeploy, waitForStackDelete, } from "aws-cdk/lib/api/util/cloudformation.js";
13
- import { StackActivityMonitor, } from "aws-cdk/lib/api/util/cloudformation/stack-activity-monitor.js";
14
13
  import { blue } from "colorette";
15
14
  const LARGE_TEMPLATE_SIZE_KB = 50;
16
15
  export async function deployStack(options) {
@@ -261,14 +260,19 @@ class FullCloudFormationDeployment {
261
260
  }
262
261
  }
263
262
  async monitorDeployment(startTime, expectedChanges) {
264
- const monitor = this.options.quiet
265
- ? undefined
266
- : StackActivityMonitor.withDefaultPrinter(this.cfn, this.stackName, this.stackArtifact, {
267
- resourcesTotal: expectedChanges,
268
- progress: this.options.progress,
269
- changeSetCreationTime: startTime,
270
- ci: this.options.ci,
271
- }).start();
263
+ // const monitor = this.options.quiet
264
+ // ? undefined
265
+ // : StackActivityMonitor.withDefaultPrinter(
266
+ // this.cfn,
267
+ // this.stackName,
268
+ // this.stackArtifact,
269
+ // {
270
+ // resourcesTotal: expectedChanges,
271
+ // progress: this.options.progress,
272
+ // changeSetCreationTime: startTime,
273
+ // ci: this.options.ci,
274
+ // }
275
+ // ).start();
272
276
  let finalState = this.cloudFormationStack;
273
277
  try {
274
278
  const successStack = await waitForStackDeploy(this.cfn, this.stackName);
@@ -279,10 +283,10 @@ class FullCloudFormationDeployment {
279
283
  finalState = successStack;
280
284
  }
281
285
  catch (e) {
282
- throw new Error(suffixWithErrors(e.message, monitor?.errors));
286
+ throw new Error(suffixWithErrors(e.message /*, monitor?.errors*/));
283
287
  }
284
288
  finally {
285
- await monitor?.stop();
289
+ // await monitor?.stop();
286
290
  }
287
291
  debug("Stack %s has completed updating", this.stackName);
288
292
  return {
@@ -336,7 +340,7 @@ class FullCloudFormationDeployment {
336
340
  * @param stack the synthesized stack that provides the CloudFormation template
337
341
  * @param toolkitInfo information about the toolkit stack
338
342
  */
339
- async function makeBodyParameter(stack, resolvedEnvironment, assetManifest, toolkitInfo, sdk, overrideTemplate) {
343
+ export async function makeBodyParameter(stack, resolvedEnvironment, assetManifest, toolkitInfo, sdk, overrideTemplate) {
340
344
  // If the template has already been uploaded to S3, just use it from there.
341
345
  if (stack.stackTemplateAssetObjectUrl && !overrideTemplate) {
342
346
  return {
@@ -399,11 +403,13 @@ export async function destroyStack(options) {
399
403
  if (!currentStack.exists) {
400
404
  return;
401
405
  }
406
+ /*
402
407
  const monitor = options.quiet
403
- ? undefined
404
- : StackActivityMonitor.withDefaultPrinter(cfn, deployName, options.stack, {
405
- ci: options.ci,
408
+ ? undefined
409
+ : StackActivityMonitor.withDefaultPrinter(cfn, deployName, options.stack, {
410
+ ci: options.ci,
406
411
  }).start();
412
+ */
407
413
  try {
408
414
  await cfn
409
415
  .deleteStack({ StackName: deployName, RoleARN: options.roleArn })
@@ -415,12 +421,14 @@ export async function destroyStack(options) {
415
421
  }
416
422
  }
417
423
  catch (e) {
418
- throw new Error(suffixWithErrors(e.message, monitor?.errors));
424
+ throw new Error(suffixWithErrors(e.message /* , monitor?.errors */));
419
425
  }
420
426
  finally {
427
+ /*
421
428
  if (monitor) {
422
- await monitor.stop();
429
+ await monitor.stop();
423
430
  }
431
+ */
424
432
  }
425
433
  }
426
434
  /**