sst 2.0.0-rc.40 → 2.0.0-rc.42

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.js CHANGED
@@ -31,6 +31,7 @@ export async function initBootstrap() {
31
31
  loadCDKStatus(),
32
32
  loadSSTStatus(),
33
33
  ]);
34
+ Logger.debug("Loaded bootstrap status");
34
35
  const needToBootstrapCDK = !cdkStatus;
35
36
  const needToBootstrapSST = !sstStatus || sstStatus.version !== LATEST_VERSION;
36
37
  if (needToBootstrapCDK || needToBootstrapSST) {
@@ -56,16 +57,15 @@ async function loadCDKStatus() {
56
57
  const { Stacks: stacks } = await client.send(new DescribeStacksCommand({
57
58
  StackName: "CDKToolkit",
58
59
  }));
59
- if (stacks && stacks.length > 0 && [
60
- "CREATE_COMPLETE",
61
- "UPDATE_COMPLETE",
62
- ].includes(stacks[0].StackStatus)) {
60
+ if (stacks &&
61
+ stacks.length > 0 &&
62
+ ["CREATE_COMPLETE", "UPDATE_COMPLETE"].includes(stacks[0].StackStatus)) {
63
63
  return true;
64
64
  }
65
65
  }
66
66
  catch (e) {
67
- if (e.name === "ValidationError"
68
- && e.message === "Stack with id CDKToolkit does not exist") {
67
+ if (e.name === "ValidationError" &&
68
+ e.message === "Stack with id CDKToolkit does not exist") {
69
69
  return false;
70
70
  }
71
71
  else {
package/cli/colors.d.ts CHANGED
@@ -1,7 +1,28 @@
1
1
  import chalk from "chalk";
2
+ declare let last: "line" | "gap";
2
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;
3
8
  primary: chalk.Chalk;
4
9
  link: chalk.Chalk;
5
10
  success: chalk.Chalk;
6
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;
7
27
  };
28
+ export {};
package/cli/colors.js CHANGED
@@ -1,7 +1,27 @@
1
1
  import chalk from "chalk";
2
+ let last = "gap";
2
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,
3
18
  primary: chalk.hex("#E27152"),
4
19
  link: chalk.cyan,
5
20
  success: chalk.green,
6
21
  danger: chalk.red,
22
+ warning: chalk.yellow,
23
+ dim: chalk.dim,
24
+ bold: chalk.bold,
25
+ all: chalk,
26
+ prefix: chalk.bold("| "),
7
27
  };
@@ -1,8 +1,9 @@
1
+ import { useLocalServerConfig } from "../local/server.js";
1
2
  export const consoleCommand = async (program) => program.command("console", "Start the SST Console", (yargs) => yargs, async () => {
2
3
  const { blue } = await import("colorette");
3
4
  const { useRuntimeServer } = await import("../../runtime/server.js");
4
5
  const { useLocalServer } = await import("../local/server.js");
5
- const [_, local] = await Promise.all([
6
+ await Promise.all([
6
7
  useRuntimeServer(),
7
8
  useLocalServer({
8
9
  key: "",
@@ -10,5 +11,6 @@ export const consoleCommand = async (program) => program.command("console", "Sta
10
11
  live: false,
11
12
  }),
12
13
  ]);
13
- console.log(`Console started: ${blue(local.url)}`);
14
+ const local = await useLocalServerConfig();
15
+ console.log(`Console started: ${local.url}`);
14
16
  });
@@ -1,3 +1,5 @@
1
+ import { Colors } from "../colors.js";
2
+ import { printHeader } from "../ui/header.js";
1
3
  export const deploy = (program) => program.command("deploy [filter]", "Deploy your app to AWS", (yargs) => yargs
2
4
  .option("from", {
3
5
  type: "string",
@@ -15,13 +17,8 @@ export const deploy = (program) => program.command("deploy [filter]", "Deploy yo
15
17
  const { loadAssembly, Stacks } = await import("../../stacks/index.js");
16
18
  const { render } = await import("ink");
17
19
  const { DeploymentUI } = await import("../ui/deploy.js");
18
- const { Colors } = await import("../colors.js");
19
20
  const project = useProject();
20
- console.log();
21
- console.log(` ${Colors.primary(`${bold(`SST`)} v${project.version}`)}`);
22
- console.log();
23
- console.log(` ${Colors.primary(`➜`)} ${bold(`Stage:`)} ${dim(project.config.stage)}`);
24
- console.log();
21
+ printHeader({});
25
22
  // Generate cloud assembly
26
23
  // - if --from is specified, we will use the existing cloud assembly
27
24
  // - if --from is not specified, we will call synth to generate
@@ -32,7 +29,6 @@ export const deploy = (program) => program.command("deploy [filter]", "Deploy yo
32
29
  }
33
30
  const spinner = createSpinner({
34
31
  text: " Building stacks",
35
- indent: 2,
36
32
  });
37
33
  const result = await Stacks.synth({
38
34
  fn: project.stacks,
@@ -45,7 +41,7 @@ export const deploy = (program) => program.command("deploy [filter]", "Deploy yo
45
41
  const target = assembly.stacks.filter((s) => !args.filter ||
46
42
  s.stackName.toLowerCase().includes(args.filter.toLowerCase()));
47
43
  if (!target.length) {
48
- console.log(`No stacks found matching ${blue(args.filter)}`);
44
+ Colors.line(`No stacks found matching ${blue(args.filter)}`);
49
45
  process.exit(1);
50
46
  }
51
47
  const component = render(React.createElement(DeploymentUI, { stacks: assembly.stacks.map((s) => s.stackName) }));
@@ -10,4 +10,6 @@ export declare const dev: (program: Program) => import("yargs").Argv<{
10
10
  verbose: boolean | undefined;
11
11
  } & {
12
12
  role: string | undefined;
13
+ } & {
14
+ "increase-timeout": boolean | undefined;
13
15
  }>;
@@ -1,6 +1,10 @@
1
1
  import chalk from "chalk";
2
2
  import { Colors } from "../colors.js";
3
- export const dev = (program) => program.command(["dev", "start"], "Work on your app locally", (yargs) => yargs, async (args) => {
3
+ import { printHeader } from "../ui/header.js";
4
+ export const dev = (program) => program.command(["dev", "start"], "Work on your app locally", (yargs) => yargs.option("increase-timeout", {
5
+ type: "boolean",
6
+ description: "Increase function timeout",
7
+ }), async (args) => {
4
8
  const { useRuntimeWorkers } = await import("../../runtime/workers.js");
5
9
  const { useIOTBridge } = await import("../../runtime/iot.js");
6
10
  const { useRuntimeServer } = await import("../../runtime/server.js");
@@ -27,70 +31,68 @@ export const dev = (program) => program.command(["dev", "start"], "Work on your
27
31
  const { useRDSWarmer } = await import("./plugins/warmer.js");
28
32
  const { useProject } = await import("../../project.js");
29
33
  const { useMetadata } = await import("../../stacks/metadata.js");
30
- const { Functions } = await import("../ui/functions.js");
31
34
  if (args._[0] === "start") {
32
35
  console.log(yellow(`Warning: ${bold(`sst start`)} has been renamed to ${bold(`sst dev`)}`));
33
36
  }
34
37
  const useFunctionLogger = Context.memo(async () => {
35
- const component = render(React.createElement(Functions, null));
36
38
  const bus = useBus();
37
- /*
39
+ const colors = ["#01cdfe", "#ff71ce", "#05ffa1", "#b967ff"];
40
+ let index = 0;
41
+ const pending = new Map();
42
+ function start(requestID) {
43
+ pending.set(requestID, {
44
+ requestID,
45
+ started: Date.now(),
46
+ color: colors[index % colors.length],
47
+ });
48
+ index++;
49
+ }
50
+ function prefix(requestID) {
51
+ return Colors.hex(pending.get(requestID).color)(Colors.prefix);
52
+ }
53
+ function end(requestID) {
54
+ // index--;
55
+ // if (index < 0) index = colors.length - 1;
56
+ pending.delete(requestID);
57
+ }
38
58
  bus.subscribe("function.invoked", async (evt) => {
39
- console.log(
40
- bold(magenta(` ➜ `)),
41
- useFunctions().fromID(evt.properties.functionID).handler!
42
- );
59
+ start(evt.properties.requestID);
60
+ Colors.line(prefix(evt.properties.requestID), Colors.dim.bold("Invoked"), Colors.dim(useFunctions().fromID(evt.properties.functionID).handler));
61
+ });
62
+ bus.subscribe("worker.stdout", async (evt) => {
63
+ const { started } = pending.get(evt.properties.requestID);
64
+ for (let line of evt.properties.message.split("\n")) {
65
+ Colors.line(prefix(evt.properties.requestID), Colors.dim(("+" + (Date.now() - started) + "ms").padEnd(7)), Colors.dim(line));
66
+ }
43
67
  });
44
-
45
68
  bus.subscribe("function.build.success", async (evt) => {
46
- console.log(
47
- bold(gray(`Built `)),
48
- useFunctions().fromID(evt.properties.functionID).handler!
49
- );
69
+ Colors.line(Colors.dim(Colors.prefix, "Built", useFunctions().fromID(evt.properties.functionID).handler));
50
70
  });
51
71
  bus.subscribe("function.build.failed", async (evt) => {
52
- console.log(
53
- bold(red(`Build failed `)),
54
- useFunctions().fromID(evt.properties.functionID).handler!
55
- );
56
- console.log(dim(evt.properties.errors.join("\n")));
57
- });
58
-
59
- bus.subscribe("worker.stdout", async (evt) => {
60
- const { message } = evt.properties;
61
- const lines = message.split("\n");
62
- for (let i = 0; i < lines.length; i++) {
63
- const line = lines[i];
64
- lines[i] = " " + line;
65
- }
66
- console.log(
67
- bold(blue(` ➜ `)),
68
- useFunctions().fromID(evt.properties.functionID).handler!
69
- );
70
- console.log(dim(lines.join("\n")));
72
+ Colors.gap();
73
+ Colors.line(Colors.danger("✖ "), "Build failed", useFunctions().fromID(evt.properties.functionID).handler);
74
+ for (const line of evt.properties.errors) {
75
+ Colors.line(" ", line);
76
+ }
77
+ Colors.gap();
71
78
  });
72
- */
73
- /*
74
79
  bus.subscribe("function.success", async (evt) => {
75
- console.log(
76
- bold(green(` ✔ `)),
77
- useFunctions().fromID(evt.properties.functionID).handler!
78
- );
79
- console.log();
80
+ // stdout logs sometimes come in after
81
+ const req = pending.get(evt.properties.requestID);
82
+ setTimeout(() => {
83
+ Colors.line(prefix(evt.properties.requestID), Colors.dim(`Done in ${Date.now() - req.started - 100}ms`));
84
+ end(evt.properties.requestID);
85
+ }, 100);
80
86
  });
81
- */
82
- /*
83
87
  bus.subscribe("function.error", async (evt) => {
84
- console.log(
85
- bold(red(` ✖ `)),
86
- useFunctions().fromID(evt.properties.functionID).handler!
87
- );
88
- console.log(` ${Colors.danger(evt.properties.errorMessage)}`);
89
- for (const line of evt.properties.trace || []) {
90
- console.log(` ${dim(line)}`);
91
- }
88
+ setTimeout(() => {
89
+ Colors.line(prefix(evt.properties.requestID), Colors.danger.bold("Error:"), Colors.danger.bold(evt.properties.errorMessage));
90
+ for (const line of evt.properties.trace || []) {
91
+ Colors.line(" ", `${dim(line)}`);
92
+ }
93
+ end(evt.properties.requestID);
94
+ }, 100);
92
95
  });
93
- */
94
96
  });
95
97
  const useStackBuilder = Context.memo(async () => {
96
98
  const watcher = useWatcher();
@@ -100,8 +102,8 @@ export const dev = (program) => program.command(["dev", "start"], "Work on your
100
102
  let pending;
101
103
  let isDeploying = false;
102
104
  async function build() {
105
+ Colors.gap();
103
106
  const spinner = createSpinner({
104
- indent: 2,
105
107
  color: "gray",
106
108
  text: lastDeployed
107
109
  ? ` Building stacks`
@@ -121,15 +123,17 @@ export const dev = (program) => program.command(["dev", "start"], "Work on your
121
123
  Logger.debug("Checksum", "next", next, "old", lastDeployed);
122
124
  if (next === lastDeployed) {
123
125
  spinner.succeed(" No changes");
124
- console.log();
126
+ Colors.gap();
125
127
  return;
126
128
  }
127
129
  if (!lastDeployed) {
128
130
  spinner.stop();
129
131
  spinner.clear();
132
+ Colors.mode("gap");
130
133
  }
131
134
  else {
132
135
  spinner.succeed(` Stacks built!`);
136
+ Colors.mode("gap");
133
137
  }
134
138
  pending = assembly;
135
139
  if (lastDeployed)
@@ -137,10 +141,11 @@ export const dev = (program) => program.command(["dev", "start"], "Work on your
137
141
  }
138
142
  catch (ex) {
139
143
  spinner.fail();
140
- console.log(ex.stack
144
+ Colors.line(ex.stack
141
145
  .split("\n")
142
- .map((line) => " " + line)
146
+ .map((line) => " " + line)
143
147
  .join("\n"));
148
+ Colors.gap();
144
149
  }
145
150
  }
146
151
  async function deploy() {
@@ -152,12 +157,12 @@ export const dev = (program) => program.command(["dev", "start"], "Work on your
152
157
  const assembly = pending;
153
158
  const nextChecksum = await checksum(assembly.directory);
154
159
  pending = undefined;
155
- console.log();
160
+ if (lastDeployed)
161
+ console.log();
156
162
  const component = render(React.createElement(DeploymentUI, { stacks: assembly.stacks.map((s) => s.stackName) }));
157
163
  const results = await Stacks.deployMany(assembly.stacks);
158
164
  component.clear();
159
165
  component.unmount();
160
- render(React.createElement(Functions, null));
161
166
  lastDeployed = nextChecksum;
162
167
  printDeploymentResults(assembly, results);
163
168
  const keys = await SiteEnv.keys();
@@ -208,17 +213,13 @@ export const dev = (program) => program.command(["dev", "start"], "Work on your
208
213
  const project = useProject();
209
214
  const primary = chalk.hex("#E27152");
210
215
  const link = chalk.cyan;
211
- const local = await useLocalServer({
216
+ await useLocalServer({
212
217
  key: "",
213
218
  cert: "",
214
219
  live: true,
215
220
  });
216
221
  console.clear();
217
- console.log();
218
- console.log(` ${Colors.primary(`${bold(`SST`)} v${project.version}`)} ${dim(`ready!`)}`);
219
- console.log();
220
- console.log(` ${primary(`➜`)} ${bold(`Stage:`)} ${dim(project.config.stage)}`);
221
- console.log(` ${primary(`➜`)} ${bold(`Console:`)} ${link(local.url)}`);
222
+ await printHeader({ console: true });
222
223
  /*
223
224
  console.log(` ${primary(`➜`)} ${bold(dim(`Outputs:`))}`);
224
225
  for (let i = 0; i < 3; i++) {
@@ -2,12 +2,13 @@ export const diff = (program) => program.command("diff", "Compare your app with
2
2
  type: "boolean",
3
3
  describe: "Compare in dev mode",
4
4
  }), async (args) => {
5
- const { printStackDiff } = await import("aws-cdk/lib/diff.js");
6
5
  const { useProject } = await import("../../project.js");
7
6
  const { Stacks } = await import("../../stacks/index.js");
8
7
  const { useAWSClient } = await import("../../credentials.js");
9
8
  const { CloudFormationClient, GetTemplateCommand } = await import("@aws-sdk/client-cloudformation");
10
9
  const { createSpinner } = await import("../spinner.js");
10
+ const { green } = await import("colorette");
11
+ // Build app
11
12
  const spinner = createSpinner("Building stacks");
12
13
  const project = useProject();
13
14
  const assembly = await Stacks.synth({
@@ -15,12 +16,51 @@ export const diff = (program) => program.command("diff", "Compare your app with
15
16
  mode: args.dev ? "dev" : "deploy",
16
17
  });
17
18
  spinner.succeed();
19
+ console.log("");
20
+ // Diff each stack
21
+ let changesAcc = 0;
22
+ let changedStacks = 0;
18
23
  const cfn = useAWSClient(CloudFormationClient);
19
24
  for (const stack of assembly.stacks) {
25
+ const spinner = createSpinner(`${stack.stackName}: Checking for changes...`);
26
+ // get old template
20
27
  const response = await cfn.send(new GetTemplateCommand({
21
28
  StackName: stack.stackName,
22
29
  }));
23
- printStackDiff(JSON.parse(response.TemplateBody), stack, true, 3);
30
+ const oldTemplate = JSON.parse(response.TemplateBody);
31
+ // generate diff
32
+ const { count, diff } = await Stacks.diff(stack, oldTemplate);
33
+ spinner.clear();
34
+ // print diff result
35
+ if (count === 0) {
36
+ console.log(`➜ ${stack.stackName}: No changes`);
37
+ console.log("");
38
+ }
39
+ else if (count === 1) {
40
+ console.log(`➜ ${stack.stackName}: ${count} change`);
41
+ console.log("");
42
+ console.log(diff);
43
+ changesAcc += count;
44
+ changedStacks++;
45
+ }
46
+ else {
47
+ console.log(`➜ ${stack.stackName}: ${count} changes`);
48
+ console.log("");
49
+ console.log(diff);
50
+ changesAcc += count;
51
+ changedStacks++;
52
+ }
53
+ }
54
+ // Handle no changes
55
+ if (changedStacks === 0) {
56
+ console.log(green("✔"), " There were no changes");
57
+ }
58
+ else {
59
+ console.log(green("✔"), changesAcc === 1
60
+ ? "1 change found in"
61
+ : `${changesAcc} changes found in`, changedStacks === 1
62
+ ? "1 stack"
63
+ : `${changedStacks} stacks`);
24
64
  }
25
65
  process.exit(0);
26
66
  });
@@ -17,7 +17,7 @@ export const env = (program) => program.command("env <command>", "Load environme
17
17
  .then(() => true)
18
18
  .catch(() => false);
19
19
  if (!exists) {
20
- spinner = createSpinner("Waiting for SST to start").start();
20
+ spinner = createSpinner("Cannot find SST environment variables. Waiting for SST to start...").start();
21
21
  await new Promise((resolve) => setTimeout(resolve, 1000));
22
22
  continue;
23
23
  }
@@ -6,6 +6,7 @@ import { exec } from "child_process";
6
6
  import { promisify } from "util";
7
7
  const execAsync = promisify(exec);
8
8
  import path from "path";
9
+ import { Colors } from "../../colors.js";
9
10
  export const usePothosBuilder = Context.memo(() => {
10
11
  let routes = [];
11
12
  const bus = useBus();
@@ -17,11 +18,14 @@ export const usePothosBuilder = Context.memo(() => {
17
18
  await fs.writeFile(route.output, schema);
18
19
  // bus.publish("pothos.extracted", { file: route.output });
19
20
  await Promise.all(route.commands.map((cmd) => execAsync(cmd)));
20
- console.log("Done building pothos schema");
21
+ Colors.line(Colors.prefix);
22
+ Colors.line(Colors.success(`✔`), " Extracted pothos schema");
21
23
  }
22
24
  catch (ex) {
23
- console.error("Failed to extract schema from pothos");
24
- console.error(ex);
25
+ Colors.line(Colors.danger(`✖`), " Failed to extract schema from pothos:");
26
+ for (let line of ex.message.split("\n")) {
27
+ console.log(` `, line);
28
+ }
25
29
  }
26
30
  }
27
31
  bus.subscribe("file.changed", async (evt) => {
@@ -0,0 +1,15 @@
1
+ /// <reference types="yargs" />
2
+ import type { Program } from "../program.js";
3
+ export declare const updateMod: (program: Program) => import("yargs").Argv<{
4
+ stage: string | undefined;
5
+ } & {
6
+ profile: string | undefined;
7
+ } & {
8
+ region: string | undefined;
9
+ } & {
10
+ verbose: boolean | undefined;
11
+ } & {
12
+ role: string | undefined;
13
+ } & {
14
+ transform: string;
15
+ }>;
@@ -0,0 +1,53 @@
1
+ export const updateMod = (program) => program.command("update-mod <transform>", "Transforms your SST app", (yargs) => yargs.positional("transform", {
2
+ type: "string",
3
+ describe: "Name of the transform",
4
+ demandOption: true,
5
+ }), async (args) => {
6
+ const { green } = await import("colorette");
7
+ if (args.transform === "resource-binding-secrets") {
8
+ await handleSecretsMigration();
9
+ }
10
+ console.log(green(`Update transform "${args.transform}" has been applied successfully!`));
11
+ });
12
+ async function handleSecretsMigration() {
13
+ const { useProject } = await import("../../project.js");
14
+ const { useAWSClient } = await import("../../credentials.js");
15
+ const { SSMClient, GetParametersByPathCommand, PutParameterCommand } = await import("@aws-sdk/client-ssm");
16
+ const project = useProject();
17
+ const { name: app, stage } = project.config;
18
+ const ssm = useAWSClient(SSMClient);
19
+ async function* getAllPrametersByPath(prefix) {
20
+ let token;
21
+ while (true) {
22
+ const results = await ssm.send(new GetParametersByPathCommand({
23
+ Path: prefix,
24
+ WithDecryption: true,
25
+ Recursive: true,
26
+ NextToken: token,
27
+ }));
28
+ yield* results.Parameters || [];
29
+ if (!results.NextToken)
30
+ break;
31
+ token = results.NextToken;
32
+ }
33
+ }
34
+ async function migrateSecretsSSMPath(stage) {
35
+ const oldPrefix = `/sst/${app}/${stage}/secrets/`;
36
+ const newPrefix = `/sst/${app}/${stage}/Secret/`;
37
+ for await (const secret of getAllPrametersByPath(oldPrefix)) {
38
+ const name = secret.Name.split("/")[5];
39
+ // Do not migrate SST Auth secrets b/c they are no longer secrets in v1.16.
40
+ if (name === "SST_AUTH_PRIVATE" || name === "SST_AUTH_PUBLIC") {
41
+ continue;
42
+ }
43
+ await ssm.send(new PutParameterCommand({
44
+ Name: `${newPrefix}${name}/value`,
45
+ Value: secret.Value,
46
+ Type: secret.Type,
47
+ Overwrite: true,
48
+ }));
49
+ }
50
+ }
51
+ await migrateSecretsSSMPath(stage);
52
+ await migrateSecretsSSMPath(".fallback");
53
+ }
@@ -11,9 +11,11 @@ declare module "../../bus.js" {
11
11
  "local.patches": DendriformPatch[];
12
12
  }
13
13
  }
14
- export declare function useLocalServer(opts: Opts): Promise<{
14
+ export declare const useLocalServerConfig: () => Promise<{
15
15
  port: number;
16
16
  url: string;
17
+ }>;
18
+ export declare function useLocalServer(opts: Opts): Promise<{
17
19
  updateState: (cb: (draft: WritableDraft<State>) => void) => void;
18
20
  updateFunction: (id: string, cb: (draft: WritableDraft<FunctionState>) => void) => void;
19
21
  }>;
@@ -12,11 +12,20 @@ import { sync } from "cross-spawn";
12
12
  import { useProject } from "../../project.js";
13
13
  import { useBus } from "../../bus.js";
14
14
  import getPort from "get-port";
15
- export async function useLocalServer(opts) {
15
+ import { Context } from "../../context/context.js";
16
+ export const useLocalServerConfig = Context.memo(async () => {
16
17
  const project = useProject();
17
18
  const port = await getPort({
18
19
  port: 13557,
19
20
  });
21
+ return {
22
+ port,
23
+ url: `https://console.sst.dev/${project.config.name}/${project.config.stage}${port !== 13557 ? `?port=${port}` : ""}`,
24
+ };
25
+ });
26
+ export async function useLocalServer(opts) {
27
+ const cfg = await useLocalServerConfig();
28
+ const project = useProject();
20
29
  let state = {
21
30
  app: project.config.name,
22
31
  stage: project.config.stage,
@@ -106,7 +115,7 @@ export async function useLocalServer(opts) {
106
115
  console.log("Rejecting unauthorized connection from " + req.headers.origin);
107
116
  socket.terminate();
108
117
  });
109
- server.listen(port);
118
+ server.listen(cfg.port);
110
119
  const handler = applyWSSHandler({
111
120
  wss,
112
121
  router,
@@ -203,8 +212,6 @@ export async function useLocalServer(opts) {
203
212
  });
204
213
  });
205
214
  const result = {
206
- port,
207
- url: `https://console.sst.dev/${project.config.name}/${project.config.stage}${port !== 13557 ? `?port=${port}` : ""}`,
208
215
  updateState,
209
216
  updateFunction,
210
217
  };
package/cli/program.js CHANGED
@@ -42,7 +42,7 @@ export const program = yargs(hideBin(process.argv))
42
42
  .fail((_, error, yargs) => {
43
43
  if (!error) {
44
44
  yargs.showHelp();
45
- return;
45
+ process.exit(1);
46
46
  }
47
47
  throw error;
48
48
  });
package/cli/spinner.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import { Context } from "../context/context.js";
2
2
  import ora from "ora";
3
+ import { Colors } from "./colors.js";
3
4
  export const useSpinners = Context.memo(() => {
4
5
  const spinners = [];
5
6
  return spinners;
@@ -8,5 +9,6 @@ export function createSpinner(options) {
8
9
  const spinners = useSpinners();
9
10
  const next = ora(options);
10
11
  spinners.push(next);
12
+ Colors.mode("line");
11
13
  return next;
12
14
  }
package/cli/sst.js CHANGED
@@ -15,6 +15,7 @@ import { remove } from "./commands/remove.js";
15
15
  import { consoleCommand } from "./commands/console.js";
16
16
  import { secrets } from "./commands/secrets/secrets.js";
17
17
  import { update } from "./commands/update.js";
18
+ import { updateMod } from "./commands/update-mod.js";
18
19
  import { diff } from "./commands/diff.js";
19
20
  dev(program);
20
21
  deploy(program);
@@ -24,6 +25,7 @@ env(program);
24
25
  secrets(program);
25
26
  remove(program);
26
27
  update(program);
28
+ updateMod(program);
27
29
  consoleCommand(program);
28
30
  diff(program);
29
31
  process.removeAllListeners("uncaughtException");