sst 2.0.0-rc.26 → 2.0.0-rc.28

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/bootstrap.d.ts CHANGED
@@ -1,4 +1,4 @@
1
1
  export declare const useBootstrap: () => Promise<{
2
- version: undefined;
3
- bucket: undefined;
2
+ version: never;
3
+ bucket: never;
4
4
  }>;
package/bootstrap.js CHANGED
@@ -23,10 +23,8 @@ const LATEST_VERSION = "4";
23
23
  const __dirname = url.fileURLToPath(new URL(".", import.meta.url));
24
24
  export const useBootstrap = Context.memo(async () => {
25
25
  Logger.debug("Initializing bootstrap context");
26
- const ret = await loadBootstrapStatus();
27
- if (!ret.version ||
28
- !ret.bucket ||
29
- ret.version !== LATEST_VERSION) {
26
+ let status = await loadBootstrapStatus();
27
+ if (!status || status.version !== LATEST_VERSION) {
30
28
  const project = useProject();
31
29
  const spinner = createSpinner("Deploying bootstrap stack, this only needs to happen once").start();
32
30
  // Create bootstrap stack
@@ -89,22 +87,39 @@ export const useBootstrap = Context.memo(async () => {
89
87
  // Create stack outputs to store bootstrap stack info
90
88
  new CfnOutput(stack, OUTPUT_VERSION, { value: LATEST_VERSION });
91
89
  new CfnOutput(stack, OUTPUT_BUCKET, { value: bucket.bucketName });
90
+ // Deploy bootstrap stack
92
91
  const asm = app.synth();
93
92
  const result = await Stacks.deploy(asm.stacks[0]);
94
93
  if (Stacks.isFailed(result.status)) {
95
94
  throw new VisibleError(`Failed to deploy bootstrap stack:\n${JSON.stringify(result.errors, null, 4)}`);
96
95
  }
97
96
  spinner.succeed();
98
- return loadBootstrapStatus();
97
+ // Fetch bootstrap status
98
+ status = await loadBootstrapStatus();
99
+ if (!status) {
100
+ throw new VisibleError("Failed to deploy bootstrap stack");
101
+ }
99
102
  }
100
- Logger.debug("Loaded bootstrap info: ", JSON.stringify(ret));
101
- return ret;
103
+ Logger.debug("Loaded bootstrap info: ", JSON.stringify(status));
104
+ return status;
102
105
  });
103
106
  async function loadBootstrapStatus() {
107
+ // Get bootstrap CloudFormation stack
104
108
  const cf = useAWSClient(CloudFormationClient);
105
- const result = await cf.send(new DescribeStacksCommand({
106
- StackName: STACK_NAME,
107
- }));
109
+ let result;
110
+ try {
111
+ result = await cf.send(new DescribeStacksCommand({
112
+ StackName: STACK_NAME,
113
+ }));
114
+ }
115
+ catch (e) {
116
+ if (e.Code === "ValidationError"
117
+ && e.message === `Stack with id ${STACK_NAME} does not exist`) {
118
+ return null;
119
+ }
120
+ throw e;
121
+ }
122
+ // Parse stack outputs
108
123
  let version, bucket;
109
124
  (result.Stacks[0].Outputs || []).forEach((o) => {
110
125
  if (o.OutputKey === OUTPUT_VERSION) {
@@ -114,5 +129,8 @@ async function loadBootstrapStatus() {
114
129
  bucket = o.OutputValue;
115
130
  }
116
131
  });
132
+ if (!version || !bucket) {
133
+ return null;
134
+ }
117
135
  return { version, bucket };
118
136
  }
@@ -37,15 +37,20 @@ export const deploy = (program) => program.command("deploy [filter]", "Work on y
37
37
  return;
38
38
  }
39
39
  console.log(`Deploying ${bold(target.length + " stacks")} for stage ${blue(project.config.stage)}...`);
40
- let component = undefined;
41
- if (args.fullscreen) {
42
- process.stdout.write("\x1b[?1049h");
43
- component = render(React.createElement(DeploymentUI, { stacks: assembly.stacks.map((s) => s.stackName) }));
44
- }
40
+ const cleanup = (() => {
41
+ if (args.fullscreen) {
42
+ process.stdout.write("\x1b[?1049h");
43
+ const component = render(React.createElement(DeploymentUI, { stacks: assembly.stacks.map((s) => s.stackName) }));
44
+ return () => {
45
+ component.unmount();
46
+ process.stdout.write("\x1b[?1049l");
47
+ };
48
+ }
49
+ const spinner = createSpinner("Deploying stacks");
50
+ return () => spinner.succeed();
51
+ })();
45
52
  const results = await Stacks.deployMany(target);
46
- if (component)
47
- component.unmount();
48
- process.stdout.write("\x1b[?1049l");
53
+ cleanup();
49
54
  printDeploymentResults(results);
50
55
  if (Object.values(results).some((stack) => Stacks.isFailed(stack.status)))
51
56
  process.exit(1);
@@ -108,15 +108,20 @@ export const dev = (program) => program.command(["start", "dev"], "Work on your
108
108
  const assembly = pending;
109
109
  const nextChecksum = await checksum(assembly.directory);
110
110
  pending = undefined;
111
- let component = undefined;
112
- if (args.fullscreen) {
113
- process.stdout.write("\x1b[?1049h");
114
- component = render(React.createElement(DeploymentUI, { stacks: assembly.stacks.map((s) => s.stackName) }));
115
- }
111
+ const cleanup = (() => {
112
+ if (args.fullscreen) {
113
+ process.stdout.write("\x1b[?1049h");
114
+ const component = render(React.createElement(DeploymentUI, { stacks: assembly.stacks.map((s) => s.stackName) }));
115
+ return () => {
116
+ component.unmount();
117
+ process.stdout.write("\x1b[?1049l");
118
+ };
119
+ }
120
+ const spinner = createSpinner("Deploying stacks");
121
+ return () => spinner.succeed();
122
+ })();
116
123
  const results = await Stacks.deployMany(assembly.stacks);
117
- if (component)
118
- component.unmount();
119
- process.stdout.write("\x1b[?1049l");
124
+ cleanup();
120
125
  lastDeployed = nextChecksum;
121
126
  printDeploymentResults(results);
122
127
  const keys = await SiteEnv.keys();
@@ -8,6 +8,8 @@ export declare const remove: (program: Program) => import("yargs").Argv<{
8
8
  region: string | undefined;
9
9
  } & {
10
10
  from: string | undefined;
11
+ } & {
12
+ fullscreen: boolean;
11
13
  } & {
12
14
  filter: string | undefined;
13
15
  }>;
@@ -1,6 +1,12 @@
1
+ import { createSpinner } from "../spinner.js";
1
2
  import { printDeploymentResults } from "../ui/deploy.js";
2
3
  export const remove = (program) => program.command("remove [filter]", "Remove all stacks for this app", (yargs) => yargs
3
4
  .option("from", { type: "string" })
5
+ .option("fullscreen", {
6
+ type: "boolean",
7
+ describe: "Disable full screen UI",
8
+ default: true,
9
+ })
4
10
  .positional("filter", { type: "string" }), async (args) => {
5
11
  const React = await import("react");
6
12
  const { CloudAssembly } = await import("aws-cdk-lib/cx-api");
@@ -28,11 +34,22 @@ export const remove = (program) => program.command("remove [filter]", "Remove al
28
34
  process.exit(1);
29
35
  }
30
36
  console.log(`Removing ${bold(target.length + " stacks")} for stage ${blue(project.config.stage)}...`);
31
- process.stdout.write("\x1b[?1049h");
32
- const component = render(React.createElement(DeploymentUI, { stacks: target.map((s) => s.stackName) }));
37
+ const cleanup = (() => {
38
+ if (args.fullscreen) {
39
+ process.stdout.write("\x1b[?1049h");
40
+ const component = render(React.createElement(DeploymentUI, { stacks: assembly.stacks.map((s) => s.stackName) }));
41
+ return () => {
42
+ component.unmount();
43
+ process.stdout.write("\x1b[?1049l");
44
+ };
45
+ }
46
+ const spinner = createSpinner("Removing stacks");
47
+ return () => spinner.succeed();
48
+ })();
33
49
  const results = await Stacks.removeMany(target);
34
- component.unmount();
35
- process.stdout.write("\x1b[?1049l");
50
+ cleanup();
36
51
  printDeploymentResults(results);
52
+ if (Object.values(results).some((stack) => Stacks.isFailed(stack.status)))
53
+ process.exit(1);
37
54
  process.exit(0);
38
55
  });
package/cli/ui/deploy.js CHANGED
@@ -76,7 +76,10 @@ export const DeploymentUI = (props) => {
76
76
  React.createElement(Text, null,
77
77
  "Deploying ",
78
78
  React.createElement(Text, { color: "bold" }, props.stacks.length),
79
- " stacks for stage ",
79
+ " stack",
80
+ props.stacks.length > 1 && "s",
81
+ " for stage",
82
+ " ",
80
83
  React.createElement(Text, { color: "blue" }, useProject().config.stage)),
81
84
  Object.entries(stacks).map(([stackID, status]) => {
82
85
  return (React.createElement(React.Fragment, { key: stackID },
@@ -106,9 +109,9 @@ export const DeploymentUI = (props) => {
106
109
  };
107
110
  export function printDeploymentResults(results) {
108
111
  console.log();
109
- console.log(`----------------------------`);
110
- console.log(`| Stack deployment results |`);
111
- console.log(`----------------------------`);
112
+ console.log(`-----------`);
113
+ console.log(`| Summary |`);
114
+ console.log(`-----------`);
112
115
  for (const [stack, result] of Object.entries(results)) {
113
116
  const icon = (() => {
114
117
  if (Stacks.isSuccess(result.status))
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sst",
3
- "version": "2.0.0-rc.26",
3
+ "version": "2.0.0-rc.28",
4
4
  "bin": {
5
5
  "sst": "cli/sst.js"
6
6
  },
package/sst.mjs CHANGED
@@ -1135,7 +1135,9 @@ async function monitor(stack) {
1135
1135
  resources: resources.StackResources
1136
1136
  });
1137
1137
  for (const resource of resources.StackResources || []) {
1138
- if (resource.ResourceStatusReason?.includes("Resource creation cancelled"))
1138
+ if (resource.ResourceStatusReason?.includes(
1139
+ "Resource creation cancelled"
1140
+ ) || resource.ResourceStatusReason?.includes("Resource updated cancelled"))
1139
1141
  continue;
1140
1142
  if (resource.ResourceStatusReason)
1141
1143
  errors[resource.LogicalResourceId] = resource.ResourceStatusReason;
@@ -2213,11 +2215,19 @@ import {
2213
2215
  } from "aws-cdk-lib/aws-s3";
2214
2216
  async function loadBootstrapStatus() {
2215
2217
  const cf = useAWSClient(CloudFormationClient2);
2216
- const result = await cf.send(
2217
- new DescribeStacksCommand2({
2218
- StackName: STACK_NAME
2219
- })
2220
- );
2218
+ let result;
2219
+ try {
2220
+ result = await cf.send(
2221
+ new DescribeStacksCommand2({
2222
+ StackName: STACK_NAME
2223
+ })
2224
+ );
2225
+ } catch (e) {
2226
+ if (e.Code === "ValidationError" && e.message === `Stack with id ${STACK_NAME} does not exist`) {
2227
+ return null;
2228
+ }
2229
+ throw e;
2230
+ }
2221
2231
  let version, bucket;
2222
2232
  (result.Stacks[0].Outputs || []).forEach((o) => {
2223
2233
  if (o.OutputKey === OUTPUT_VERSION) {
@@ -2226,6 +2236,9 @@ async function loadBootstrapStatus() {
2226
2236
  bucket = o.OutputValue;
2227
2237
  }
2228
2238
  });
2239
+ if (!version || !bucket) {
2240
+ return null;
2241
+ }
2229
2242
  return { version, bucket };
2230
2243
  }
2231
2244
  var STACK_NAME, OUTPUT_VERSION, OUTPUT_BUCKET, LATEST_VERSION, __dirname, useBootstrap;
@@ -2246,8 +2259,8 @@ var init_bootstrap = __esm({
2246
2259
  __dirname = url2.fileURLToPath(new URL(".", import.meta.url));
2247
2260
  useBootstrap = Context.memo(async () => {
2248
2261
  Logger.debug("Initializing bootstrap context");
2249
- const ret = await loadBootstrapStatus();
2250
- if (!ret.version || !ret.bucket || ret.version !== LATEST_VERSION) {
2262
+ let status = await loadBootstrapStatus();
2263
+ if (!status || status.version !== LATEST_VERSION) {
2251
2264
  const project = useProject();
2252
2265
  const spinner = createSpinner(
2253
2266
  "Deploying bootstrap stack, this only needs to happen once"
@@ -2320,10 +2333,13 @@ ${JSON.stringify(
2320
2333
  );
2321
2334
  }
2322
2335
  spinner.succeed();
2323
- return loadBootstrapStatus();
2336
+ status = await loadBootstrapStatus();
2337
+ if (!status) {
2338
+ throw new VisibleError("Failed to deploy bootstrap stack");
2339
+ }
2324
2340
  }
2325
- Logger.debug("Loaded bootstrap info: ", JSON.stringify(ret));
2326
- return ret;
2341
+ Logger.debug("Loaded bootstrap info: ", JSON.stringify(status));
2342
+ return status;
2327
2343
  });
2328
2344
  }
2329
2345
  });
@@ -4188,9 +4204,9 @@ import inkSpinner from "ink-spinner";
4188
4204
  import { blue as blue4, bold, green as green2, red as red2 } from "colorette";
4189
4205
  function printDeploymentResults(results) {
4190
4206
  console.log();
4191
- console.log(`----------------------------`);
4192
- console.log(`| Stack deployment results |`);
4193
- console.log(`----------------------------`);
4207
+ console.log(`-----------`);
4208
+ console.log(`| Summary |`);
4209
+ console.log(`-----------`);
4194
4210
  for (const [stack, result] of Object.entries(results)) {
4195
4211
  const icon = (() => {
4196
4212
  if (stacks_exports.isSuccess(result.status))
@@ -4301,7 +4317,7 @@ var init_deploy2 = __esm({
4301
4317
  return "green";
4302
4318
  return "yellow";
4303
4319
  }
4304
- return /* @__PURE__ */ React.createElement(FullScreen, null, /* @__PURE__ */ React.createElement(Text, null, "Deploying ", /* @__PURE__ */ React.createElement(Text, { color: "bold" }, props.stacks.length), " stacks for stage ", /* @__PURE__ */ React.createElement(Text, { color: "blue" }, useProject().config.stage)), Object.entries(stacks).map(([stackID, status]) => {
4320
+ return /* @__PURE__ */ React.createElement(FullScreen, null, /* @__PURE__ */ React.createElement(Text, null, "Deploying ", /* @__PURE__ */ React.createElement(Text, { color: "bold" }, props.stacks.length), " stack", props.stacks.length > 1 && "s", " for stage", " ", /* @__PURE__ */ React.createElement(Text, { color: "blue" }, useProject().config.stage)), Object.entries(stacks).map(([stackID, status]) => {
4305
4321
  return /* @__PURE__ */ React.createElement(React.Fragment, { key: stackID }, /* @__PURE__ */ React.createElement(Text, null, !stacks_exports.isFinal(status) && /* @__PURE__ */ React.createElement(Spinner, null), stacks_exports.isSuccess(status) && /* @__PURE__ */ React.createElement(Text, { color: color(status) }, "\u2714"), stacks_exports.isFailed(status) && /* @__PURE__ */ React.createElement(Text, { color: color(status) }, "\u2716"), /* @__PURE__ */ React.createElement(Text, null, " " + stackID), status && /* @__PURE__ */ React.createElement(Text, { color: color(status) }, " ", status)), resources[stackID]?.map((resource) => /* @__PURE__ */ React.createElement(Box, { key: resource.LogicalResourceId }, /* @__PURE__ */ React.createElement(Text, null, " ", !stacks_exports.isFinal(resource.ResourceStatus || "") && /* @__PURE__ */ React.createElement(Spinner, null), stacks_exports.isSuccess(resource.ResourceStatus || "") && /* @__PURE__ */ React.createElement(Text, { color: "green" }, "\u2714"), stacks_exports.isFailed(resource.ResourceStatus || "") && /* @__PURE__ */ React.createElement(Text, { color: "red" }, "\u2716"), " ", resource.ResourceType, " ", resource.LogicalResourceId, " ", resource.ResourceStatusReason, " "), /* @__PURE__ */ React.createElement(Text, { color: color(resource.ResourceStatus || "") }, resource.ResourceStatus))));
4306
4322
  }));
4307
4323
  };
@@ -5735,17 +5751,27 @@ var dev = (program2) => program2.command(
5735
5751
  const assembly = pending;
5736
5752
  const nextChecksum = await checksum(assembly.directory);
5737
5753
  pending = void 0;
5738
- let component = void 0;
5739
- if (args.fullscreen) {
5740
- process.stdout.write("\x1B[?1049h");
5741
- component = render(
5742
- /* @__PURE__ */ React2.createElement(DeploymentUI2, { stacks: assembly.stacks.map((s) => s.stackName) })
5743
- );
5744
- }
5754
+ const cleanup = (() => {
5755
+ if (args.fullscreen) {
5756
+ process.stdout.write("\x1B[?1049h");
5757
+ const component = render(
5758
+ /* @__PURE__ */ React2.createElement(
5759
+ DeploymentUI2,
5760
+ {
5761
+ stacks: assembly.stacks.map((s) => s.stackName)
5762
+ }
5763
+ )
5764
+ );
5765
+ return () => {
5766
+ component.unmount();
5767
+ process.stdout.write("\x1B[?1049l");
5768
+ };
5769
+ }
5770
+ const spinner = createSpinner2("Deploying stacks");
5771
+ return () => spinner.succeed();
5772
+ })();
5745
5773
  const results = await Stacks.deployMany(assembly.stacks);
5746
- if (component)
5747
- component.unmount();
5748
- process.stdout.write("\x1B[?1049l");
5774
+ cleanup();
5749
5775
  lastDeployed = nextChecksum;
5750
5776
  printDeploymentResults(results);
5751
5777
  const keys2 = await site_env_exports.keys();
@@ -5918,17 +5944,22 @@ var deploy2 = (program2) => program2.command(
5918
5944
  project.config.stage
5919
5945
  )}...`
5920
5946
  );
5921
- let component = void 0;
5922
- if (args.fullscreen) {
5923
- process.stdout.write("\x1B[?1049h");
5924
- component = render(
5925
- /* @__PURE__ */ React2.createElement(DeploymentUI2, { stacks: assembly.stacks.map((s) => s.stackName) })
5926
- );
5927
- }
5947
+ const cleanup = (() => {
5948
+ if (args.fullscreen) {
5949
+ process.stdout.write("\x1B[?1049h");
5950
+ const component = render(
5951
+ /* @__PURE__ */ React2.createElement(DeploymentUI2, { stacks: assembly.stacks.map((s) => s.stackName) })
5952
+ );
5953
+ return () => {
5954
+ component.unmount();
5955
+ process.stdout.write("\x1B[?1049l");
5956
+ };
5957
+ }
5958
+ const spinner = createSpinner("Deploying stacks");
5959
+ return () => spinner.succeed();
5960
+ })();
5928
5961
  const results = await Stacks.deployMany(target);
5929
- if (component)
5930
- component.unmount();
5931
- process.stdout.write("\x1B[?1049l");
5962
+ cleanup();
5932
5963
  printDeploymentResults(results);
5933
5964
  if (Object.values(results).some((stack) => Stacks.isFailed(stack.status)))
5934
5965
  process.exit(1);
@@ -5937,11 +5968,16 @@ var deploy2 = (program2) => program2.command(
5937
5968
  );
5938
5969
 
5939
5970
  // src/cli/commands/remove.tsx
5971
+ init_spinner();
5940
5972
  init_deploy2();
5941
5973
  var remove3 = (program2) => program2.command(
5942
5974
  "remove [filter]",
5943
5975
  "Remove all stacks for this app",
5944
- (yargs2) => yargs2.option("from", { type: "string" }).positional("filter", { type: "string" }),
5976
+ (yargs2) => yargs2.option("from", { type: "string" }).option("fullscreen", {
5977
+ type: "boolean",
5978
+ describe: "Disable full screen UI",
5979
+ default: true
5980
+ }).positional("filter", { type: "string" }),
5945
5981
  async (args) => {
5946
5982
  const React2 = await import("react");
5947
5983
  const { CloudAssembly } = await import("aws-cdk-lib/cx-api");
@@ -5974,14 +6010,25 @@ var remove3 = (program2) => program2.command(
5974
6010
  project.config.stage
5975
6011
  )}...`
5976
6012
  );
5977
- process.stdout.write("\x1B[?1049h");
5978
- const component = render(
5979
- /* @__PURE__ */ React2.createElement(DeploymentUI2, { stacks: target.map((s) => s.stackName) })
5980
- );
6013
+ const cleanup = (() => {
6014
+ if (args.fullscreen) {
6015
+ process.stdout.write("\x1B[?1049h");
6016
+ const component = render(
6017
+ /* @__PURE__ */ React2.createElement(DeploymentUI2, { stacks: assembly.stacks.map((s) => s.stackName) })
6018
+ );
6019
+ return () => {
6020
+ component.unmount();
6021
+ process.stdout.write("\x1B[?1049l");
6022
+ };
6023
+ }
6024
+ const spinner = createSpinner("Removing stacks");
6025
+ return () => spinner.succeed();
6026
+ })();
5981
6027
  const results = await Stacks.removeMany(target);
5982
- component.unmount();
5983
- process.stdout.write("\x1B[?1049l");
6028
+ cleanup();
5984
6029
  printDeploymentResults(results);
6030
+ if (Object.values(results).some((stack) => Stacks.isFailed(stack.status)))
6031
+ process.exit(1);
5985
6032
  process.exit(0);
5986
6033
  }
5987
6034
  );
package/stacks/monitor.js CHANGED
@@ -69,7 +69,8 @@ export async function monitor(stack) {
69
69
  resources: resources.StackResources,
70
70
  });
71
71
  for (const resource of resources.StackResources || []) {
72
- if (resource.ResourceStatusReason?.includes("Resource creation cancelled"))
72
+ if (resource.ResourceStatusReason?.includes("Resource creation cancelled") ||
73
+ resource.ResourceStatusReason?.includes("Resource updated cancelled"))
73
74
  continue;
74
75
  if (resource.ResourceStatusReason)
75
76
  errors[resource.LogicalResourceId] = resource.ResourceStatusReason;