sst 2.24.15 → 2.24.17

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.
@@ -8,76 +8,82 @@ export const diff = (program) => program.command("diff", "Compare your app with
8
8
  type: "string",
9
9
  describe: "Output directory, defaults to .sst/dist",
10
10
  }), async (args) => {
11
+ const { exit, exitWithError } = await import("../program.js");
11
12
  const { useProject } = await import("../../project.js");
12
13
  const { Stacks } = await import("../../stacks/index.js");
13
14
  const { useAWSClient } = await import("../../credentials.js");
14
15
  const { CloudFormationClient, GetTemplateCommand } = await import("@aws-sdk/client-cloudformation");
15
16
  const { createSpinner } = await import("../spinner.js");
16
17
  const { Colors } = await import("../colors.js");
17
- // Build app
18
- const project = useProject();
19
- const [_metafile, sstConfig] = await Stacks.load(project.paths.config);
20
- const assembly = await Stacks.synth({
21
- fn: sstConfig.stacks,
22
- buildDir: args.to,
23
- mode: args.dev ? "dev" : "deploy",
24
- });
25
- // Diff each stack
26
- let changesAcc = 0;
27
- let changedStacks = 0;
28
- const cfn = useAWSClient(CloudFormationClient);
29
- for (const stack of assembly.stacks) {
30
- const spinner = createSpinner(`${stack.stackName}: Checking for changes...`);
31
- // get old template
32
- const oldTemplate = await getTemplate(stack.stackName);
33
- if (!oldTemplate) {
18
+ try {
19
+ // Build app
20
+ const project = useProject();
21
+ const [_metafile, sstConfig] = await Stacks.load(project.paths.config);
22
+ const assembly = await Stacks.synth({
23
+ fn: sstConfig.stacks,
24
+ buildDir: args.to,
25
+ mode: args.dev ? "dev" : "deploy",
26
+ });
27
+ // Diff each stack
28
+ let changesAcc = 0;
29
+ let changedStacks = 0;
30
+ const cfn = useAWSClient(CloudFormationClient);
31
+ for (const stack of assembly.stacks) {
32
+ const spinner = createSpinner(`${stack.stackName}: Checking for changes...`);
33
+ // get old template
34
+ const oldTemplate = await getTemplate(stack.stackName);
35
+ if (!oldTemplate) {
36
+ spinner.clear();
37
+ Colors.line(`➜ ${Colors.dim.bold(stackNameToId(stack.stackName) + ":")} New stack`);
38
+ Colors.gap();
39
+ continue;
40
+ }
41
+ // generate diff
42
+ const { count, diff } = await Stacks.diff(stack, oldTemplate);
34
43
  spinner.clear();
35
- Colors.line(`➜ ${Colors.dim.bold(stackNameToId(stack.stackName) + ":")} New stack`);
36
- Colors.gap();
37
- continue;
38
- }
39
- // generate diff
40
- const { count, diff } = await Stacks.diff(stack, oldTemplate);
41
- spinner.clear();
42
- // print diff result
43
- if (count === 0) {
44
- Colors.line(`➜ ${Colors.dim.bold(stackNameToId(stack.stackName) + ":")} No changes`);
45
- Colors.gap();
44
+ // print diff result
45
+ if (count === 0) {
46
+ Colors.line(`➜ ${Colors.dim.bold(stackNameToId(stack.stackName) + ":")} No changes`);
47
+ Colors.gap();
48
+ }
49
+ else if (count === 1) {
50
+ Colors.line(`➜ ${Colors.dim.bold(stackNameToId(stack.stackName) + ":")} ${count} change`);
51
+ Colors.gap();
52
+ console.log(diff);
53
+ changesAcc += count;
54
+ changedStacks++;
55
+ }
56
+ else {
57
+ Colors.line(`➜ ${Colors.dim.bold(stackNameToId(stack.stackName) + ":")} ${count} changes`);
58
+ Colors.gap();
59
+ console.log(diff);
60
+ changesAcc += count;
61
+ changedStacks++;
62
+ }
46
63
  }
47
- else if (count === 1) {
48
- Colors.line(`➜ ${Colors.dim.bold(stackNameToId(stack.stackName) + ":")} ${count} change`);
49
- Colors.gap();
50
- console.log(diff);
51
- changesAcc += count;
52
- changedStacks++;
64
+ // Handle no changes
65
+ if (changedStacks === 0) {
66
+ Colors.line(Colors.success(`✔`), Colors.bold(" Diff:"), "No changes");
53
67
  }
54
68
  else {
55
- Colors.line(`➜ ${Colors.dim.bold(stackNameToId(stack.stackName) + ":")} ${count} changes`);
56
- Colors.gap();
57
- console.log(diff);
58
- changesAcc += count;
59
- changedStacks++;
69
+ Colors.line(Colors.success(`✔`), Colors.bold(" Diff:"), changesAcc === 1 ? "1 change found in" : `${changesAcc} changes in`, changedStacks === 1 ? "1 stack" : `${changedStacks} stacks`);
60
70
  }
61
- }
62
- // Handle no changes
63
- if (changedStacks === 0) {
64
- Colors.line(Colors.success(`✔`), Colors.bold(" Diff:"), "No changes");
65
- }
66
- else {
67
- Colors.line(Colors.success(`✔`), Colors.bold(" Diff:"), changesAcc === 1 ? "1 change found in" : `${changesAcc} changes in`, changedStacks === 1 ? "1 stack" : `${changedStacks} stacks`);
68
- }
69
- process.exit(0);
70
- async function getTemplate(stackName) {
71
- try {
72
- const response = await cfn.send(new GetTemplateCommand({ StackName: stackName }));
73
- return JSON.parse(response.TemplateBody);
74
- }
75
- catch (e) {
76
- if (e.name === "ValidationError" &&
77
- e.message.includes("does not exist")) {
78
- return;
71
+ async function getTemplate(stackName) {
72
+ try {
73
+ const response = await cfn.send(new GetTemplateCommand({ StackName: stackName }));
74
+ return JSON.parse(response.TemplateBody);
75
+ }
76
+ catch (e) {
77
+ if (e.name === "ValidationError" &&
78
+ e.message.includes("does not exist")) {
79
+ return;
80
+ }
81
+ throw e;
79
82
  }
80
- throw e;
81
83
  }
84
+ await exit();
85
+ }
86
+ catch (e) {
87
+ await exitWithError(e);
82
88
  }
83
89
  });
@@ -4,49 +4,59 @@ export const remove = (program) => program.command("remove [filter]", "Remove yo
4
4
  }), async (args) => {
5
5
  const React = await import("react");
6
6
  const { dim, blue, bold } = await import("colorette");
7
+ const { exit, exitWithError } = await import("../program.js");
7
8
  const { useProject } = await import("../../project.js");
9
+ const { SilentError } = await import("../../error.js");
8
10
  const { loadAssembly, clearAppMetadata, Stacks } = await import("../../stacks/index.js");
9
11
  const { render } = await import("ink");
10
12
  const { DeploymentUI } = await import("../ui/deploy.js");
11
13
  const { printDeploymentResults } = await import("../ui/deploy.js");
12
14
  const { Colors } = await import("../colors.js");
13
15
  const { useSTSIdentity } = await import("../../credentials.js");
14
- const project = useProject();
15
- const identity = await useSTSIdentity();
16
- Colors.line(`${Colors.primary.bold(`SST v${project.version}`)}`);
17
- Colors.gap();
18
- Colors.line(`${Colors.primary(`➜`)} ${Colors.bold("App:")} ${project.config.name}`);
19
- Colors.line(` ${Colors.bold("Stage:")} ${project.config.stage}`);
20
- Colors.line(` ${Colors.bold("Region:")} ${project.config.region}`);
21
- Colors.line(` ${Colors.bold("Account:")} ${identity.Account}`);
22
- const assembly = await (async function () {
23
- if (args.from) {
24
- const result = await loadAssembly(args.from);
25
- return result;
16
+ try {
17
+ const project = useProject();
18
+ const identity = await useSTSIdentity();
19
+ Colors.line(`${Colors.primary.bold(`SST v${project.version}`)}`);
20
+ Colors.gap();
21
+ Colors.line(`${Colors.primary(`➜`)} ${Colors.bold("App:")} ${project.config.name}`);
22
+ Colors.line(` ${Colors.bold("Stage:")} ${project.config.stage}`);
23
+ Colors.line(` ${Colors.bold("Region:")} ${project.config.region}`);
24
+ Colors.line(` ${Colors.bold("Account:")} ${identity.Account}`);
25
+ const assembly = await (async function () {
26
+ if (args.from) {
27
+ const result = await loadAssembly(args.from);
28
+ return result;
29
+ }
30
+ const [_metafile, sstConfig] = await Stacks.load(project.paths.config);
31
+ return await Stacks.synth({
32
+ fn: sstConfig.stacks,
33
+ mode: "remove",
34
+ });
35
+ })();
36
+ const target = assembly.stacks.filter((s) => !args.filter ||
37
+ s.id
38
+ .toLowerCase()
39
+ .replace(project.config.name.toLowerCase(), "")
40
+ .replace(project.config.stage.toLowerCase(), "")
41
+ .includes(args.filter.toLowerCase()));
42
+ if (!target.length) {
43
+ console.log(`No stacks found matching ${blue(args.filter)}`);
44
+ throw new SilentError(`No stacks found matching ${args.filter}`);
26
45
  }
27
- const [_metafile, sstConfig] = await Stacks.load(project.paths.config);
28
- return await Stacks.synth({
29
- fn: sstConfig.stacks,
30
- mode: "remove",
31
- });
32
- })();
33
- const target = assembly.stacks.filter((s) => !args.filter ||
34
- s.id
35
- .toLowerCase()
36
- .replace(project.config.name.toLowerCase(), "")
37
- .replace(project.config.stage.toLowerCase(), "")
38
- .includes(args.filter.toLowerCase()));
39
- if (!target.length) {
40
- console.log(`No stacks found matching ${blue(args.filter)}`);
41
- process.exit(1);
46
+ const component = render(React.createElement(DeploymentUI, { assembly: assembly, remove: true }));
47
+ const results = await Stacks.removeMany(target);
48
+ component.clear();
49
+ component.unmount();
50
+ printDeploymentResults(assembly, results, true);
51
+ // Check failed stacks
52
+ const failed = Object.values(results).find((result) => Stacks.isFailed(result.status));
53
+ if (failed) {
54
+ throw new SilentError(`CloudFormation status ${failed.status}`);
55
+ }
56
+ await clearAppMetadata();
57
+ await exit();
58
+ }
59
+ catch (e) {
60
+ await exitWithError(e);
42
61
  }
43
- const component = render(React.createElement(DeploymentUI, { assembly: assembly, remove: true }));
44
- const results = await Stacks.removeMany(target);
45
- component.clear();
46
- component.unmount();
47
- printDeploymentResults(assembly, results, true);
48
- if (Object.values(results).some((stack) => Stacks.isFailed(stack.status)))
49
- process.exit(1);
50
- await clearAppMetadata();
51
- process.exit(0);
52
62
  });
@@ -1,5 +1,5 @@
1
1
  /// <reference types="yargs" />
2
- import { Program } from "../../program.js";
2
+ import type { Program } from "../../program.js";
3
3
  export declare const get: (program: Program) => import("yargs").Argv<{
4
4
  stage: string | undefined;
5
5
  } & {
@@ -8,8 +8,9 @@ export const get = (program) => program.command("get <name>", "Get the value of
8
8
  type: "boolean",
9
9
  describe: "Get the fallback value",
10
10
  }), async (args) => {
11
- const { red } = await import("colorette");
11
+ const { exit, exitWithError } = await import("../../program.js");
12
12
  const { Config } = await import("../../../config.js");
13
+ const { SilentError } = await import("../../../error.js");
13
14
  const { Colors } = await import("../../colors.js");
14
15
  try {
15
16
  const result = await Config.getSecret({
@@ -17,8 +18,10 @@ export const get = (program) => program.command("get <name>", "Get the value of
17
18
  fallback: args.fallback === true,
18
19
  });
19
20
  console.log(result);
21
+ await exit();
20
22
  }
21
23
  catch {
22
24
  Colors.line(Colors.danger(`✖ `), `"${args.name}" is not set`);
25
+ await exitWithError(new SilentError(`"${args.name}" is not set`));
23
26
  }
24
27
  });
@@ -4,59 +4,66 @@ export const list = (program) => program.command("list [format]", "Fetch all the
4
4
  choices: ["table", "env", "json"],
5
5
  })
6
6
  .boolean("fallback"), async (args) => {
7
- const { Config } = await import("../../../config.js");
8
7
  const { gray } = await import("colorette");
8
+ const { Config } = await import("../../../config.js");
9
+ const { exit, exitWithError } = await import("../../program.js");
9
10
  const { Colors } = await import("../../colors.js");
10
- const configSecrets = await Config.secrets();
11
- const secrets = !args.fallback
12
- ? configSecrets
13
- : Object.entries(configSecrets).reduce((carry, [key, value]) => ({
14
- ...carry,
15
- ...(!value.value && !!value.fallback ? { [key]: value } : {}),
16
- }), {});
17
- if (Object.entries(secrets).length === 0) {
18
- Colors.line("No secrets set");
19
- return;
11
+ try {
12
+ const configSecrets = await Config.secrets();
13
+ const secrets = !args.fallback
14
+ ? configSecrets
15
+ : Object.entries(configSecrets).reduce((carry, [key, value]) => ({
16
+ ...carry,
17
+ ...(!value.value && !!value.fallback ? { [key]: value } : {}),
18
+ }), {});
19
+ if (Object.entries(secrets).length === 0) {
20
+ Colors.line("No secrets set");
21
+ return;
22
+ }
23
+ switch (args.format || "table") {
24
+ case "json":
25
+ const env = Object.fromEntries(Object.entries(secrets).map(([key, { value, fallback }]) => [
26
+ key,
27
+ value || fallback,
28
+ ]));
29
+ console.log(JSON.stringify(env, null, 2));
30
+ break;
31
+ case "env":
32
+ for (const [key, value] of Object.entries(secrets)) {
33
+ console.log(`${key}=${value.value || `${value.fallback} #fallback`}`);
34
+ }
35
+ break;
36
+ case "table":
37
+ const keys = Object.keys(secrets);
38
+ const keyLen = Math.max("Secrets".length, ...keys.map((key) => key.length));
39
+ const valueLen = Math.max("Values".length, ...keys.map((key) => secrets[key].value
40
+ ? secrets[key].value.length
41
+ : `${secrets[key].fallback} (fallback)`.length));
42
+ console.log("┌".padEnd(keyLen + 3, "─") +
43
+ "┬" +
44
+ "".padEnd(valueLen + 2, "─") +
45
+ "┐");
46
+ console.log(`│ ${"Secrets".padEnd(keyLen)} │ ${"Values".padEnd(valueLen)} │`);
47
+ console.log("├".padEnd(keyLen + 3, "─") +
48
+ "┼" +
49
+ "".padEnd(valueLen + 2, "─") +
50
+ "┤");
51
+ keys.sort().forEach((key) => {
52
+ const value = secrets[key].value
53
+ ? secrets[key].value
54
+ : `${secrets[key].fallback} ${gray("(fallback)")}`;
55
+ const colourPadding = secrets[key].value ? 0 : gray("").length;
56
+ console.log(`│ ${key.padEnd(keyLen)} │ ${value.padEnd(valueLen + colourPadding)} │`);
57
+ });
58
+ console.log("└".padEnd(keyLen + 3, "─") +
59
+ "┴" +
60
+ "".padEnd(valueLen + 2, "─") +
61
+ "┘");
62
+ break;
63
+ }
64
+ await exit();
20
65
  }
21
- switch (args.format || "table") {
22
- case "json":
23
- const env = Object.fromEntries(Object.entries(secrets).map(([key, { value, fallback }]) => [
24
- key,
25
- value || fallback,
26
- ]));
27
- console.log(JSON.stringify(env, null, 2));
28
- break;
29
- case "env":
30
- for (const [key, value] of Object.entries(secrets)) {
31
- console.log(`${key}=${value.value || `${value.fallback} #fallback`}`);
32
- }
33
- break;
34
- case "table":
35
- const keys = Object.keys(secrets);
36
- const keyLen = Math.max("Secrets".length, ...keys.map((key) => key.length));
37
- const valueLen = Math.max("Values".length, ...keys.map((key) => secrets[key].value
38
- ? secrets[key].value.length
39
- : `${secrets[key].fallback} (fallback)`.length));
40
- console.log("┌".padEnd(keyLen + 3, "─") +
41
- "┬" +
42
- "".padEnd(valueLen + 2, "─") +
43
- "┐");
44
- console.log(`│ ${"Secrets".padEnd(keyLen)} │ ${"Values".padEnd(valueLen)} │`);
45
- console.log("├".padEnd(keyLen + 3, "─") +
46
- "┼" +
47
- "".padEnd(valueLen + 2, "─") +
48
- "┤");
49
- keys.sort().forEach((key) => {
50
- const value = secrets[key].value
51
- ? secrets[key].value
52
- : `${secrets[key].fallback} ${gray("(fallback)")}`;
53
- const colourPadding = secrets[key].value ? 0 : gray("").length;
54
- console.log(`│ ${key.padEnd(keyLen)} │ ${value.padEnd(valueLen + colourPadding)} │`);
55
- });
56
- console.log("└".padEnd(keyLen + 3, "─") +
57
- "┴" +
58
- "".padEnd(valueLen + 2, "─") +
59
- "┘");
60
- break;
66
+ catch (e) {
67
+ await exitWithError(e);
61
68
  }
62
69
  });
@@ -2,40 +2,46 @@ export const load = (program) => program.command("load <filename>", "Loads secre
2
2
  type: "string",
3
3
  demandOption: true,
4
4
  }), async (args) => {
5
+ const { exit, exitWithError } = await import("../../program.js");
5
6
  const { Config } = await import("../../../config.js");
6
7
  const { Colors } = await import("../../colors.js");
7
8
  const { blue } = await import("colorette");
8
9
  const { createSpinner } = await import("../../spinner.js");
9
10
  const { parse } = await import("dotenv");
10
11
  const fs = await import("fs/promises");
11
- // Parse .env file
12
- const fileContent = await fs.readFile(args.filename, "utf-8");
13
- const envVars = parse(fileContent);
14
- // Set secrets
15
- const setting = createSpinner(` Setting secrets from "${args.filename}"`).start();
16
- for (const [key, value] of Object.entries(envVars)) {
17
- await Config.setSecret({ key, value });
12
+ try {
13
+ // Parse .env file
14
+ const fileContent = await fs.readFile(args.filename, "utf-8");
15
+ const envVars = parse(fileContent);
16
+ // Set secrets
17
+ const setting = createSpinner(` Setting secrets from "${args.filename}"`).start();
18
+ for (const [key, value] of Object.entries(envVars)) {
19
+ await Config.setSecret({ key, value });
20
+ }
21
+ setting.succeed();
22
+ // Restart functions & sites
23
+ const envNames = Object.keys(envVars);
24
+ const restarting = createSpinner(` Restarting all resources using ${blue(envNames.join(", "))}...`).start();
25
+ const { edgeSites, sites, placeholderSites, functions } = await Config.restart(envNames);
26
+ restarting.stop().clear();
27
+ const siteCount = sites.length + placeholderSites.length;
28
+ if (siteCount > 0) {
29
+ Colors.line(Colors.success(`✔ `), siteCount === 1
30
+ ? `Reloaded ${siteCount} site`
31
+ : `Reloaded ${siteCount} sites`);
32
+ }
33
+ const functionCount = functions.length;
34
+ if (functionCount > 0) {
35
+ Colors.line(Colors.success(`✔ `), functionCount === 1
36
+ ? `Reloaded ${functionCount} function`
37
+ : `Reloaded ${functionCount} functions`);
38
+ }
39
+ edgeSites.forEach(({ id, type }) => {
40
+ Colors.line(Colors.primary(`➜ `), `Redeploy the "${id}" ${type} to use the new secret`);
41
+ });
42
+ await exit();
18
43
  }
19
- setting.succeed();
20
- // Restart functions & sites
21
- const envNames = Object.keys(envVars);
22
- const restarting = createSpinner(` Restarting all resources using ${blue(envNames.join(", "))}...`).start();
23
- const { edgeSites, sites, placeholderSites, functions } = await Config.restart(envNames);
24
- restarting.stop().clear();
25
- const siteCount = sites.length + placeholderSites.length;
26
- if (siteCount > 0) {
27
- Colors.line(Colors.success(`✔ `), siteCount === 1
28
- ? `Reloaded ${siteCount} site`
29
- : `Reloaded ${siteCount} sites`);
44
+ catch (e) {
45
+ await exitWithError(e);
30
46
  }
31
- const functionCount = functions.length;
32
- if (functionCount > 0) {
33
- Colors.line(Colors.success(`✔ `), functionCount === 1
34
- ? `Reloaded ${functionCount} function`
35
- : `Reloaded ${functionCount} functions`);
36
- }
37
- edgeSites.forEach(({ id, type }) => {
38
- Colors.line(Colors.primary(`➜ `), `Redeploy the "${id}" ${type} to use the new secret`);
39
- });
40
- process.exit(0);
41
47
  });
@@ -9,6 +9,8 @@ export const remove = (program) => program.command("remove <name>", "Remove a se
9
9
  describe: "Remove the fallback value",
10
10
  }), async (args) => {
11
11
  const { Config } = await import("../../../config.js");
12
+ const { exit, exitWithError } = await import("../../program.js");
13
+ const { SilentError } = await import("../../../error.js");
12
14
  const { Colors } = await import("../../colors.js");
13
15
  try {
14
16
  await Config.removeSecret({
@@ -16,8 +18,10 @@ export const remove = (program) => program.command("remove <name>", "Remove a se
16
18
  fallback: args.fallback === true,
17
19
  });
18
20
  Colors.line(Colors.success(`✔ `), `Removed "${args.name}"`);
21
+ await exit();
19
22
  }
20
23
  catch {
21
24
  Colors.line(Colors.danger(`✖ `), `"${args.name}" is not set`);
25
+ await exitWithError(new SilentError(`"${args.name}" is not set`));
22
26
  }
23
27
  });
@@ -1,2 +1,2 @@
1
- import { Program } from "../../program.js";
1
+ import type { Program } from "../../program.js";
2
2
  export declare function secrets(program: Program): void;
@@ -6,11 +6,11 @@ import { set } from "./set.js";
6
6
  export function secrets(program) {
7
7
  program.command("secrets", "Manage the secrets in your app", (yargs) => {
8
8
  yargs.demandCommand(1);
9
- set(yargs);
10
- get(yargs);
11
- load(yargs);
12
- list(yargs);
13
- remove(yargs);
9
+ set(program);
10
+ get(program);
11
+ load(program);
12
+ list(program);
13
+ remove(program);
14
14
  return yargs;
15
15
  });
16
16
  }
@@ -13,36 +13,42 @@ export const set = (program) => program.command("set <name> <value>", "Set the v
13
13
  type: "boolean",
14
14
  describe: "Set the fallback value",
15
15
  }), async (args) => {
16
+ const { exit, exitWithError } = await import("../../program.js");
16
17
  const { Config } = await import("../../../config.js");
17
18
  const { Colors } = await import("../../colors.js");
18
19
  const { blue } = await import("colorette");
19
20
  const { createSpinner } = await import("../../spinner.js");
20
- // Set secret value
21
- const setting = createSpinner(` Setting "${args.name}"`).start();
22
- await Config.setSecret({
23
- key: args.name,
24
- value: args.value,
25
- fallback: args.fallback === true,
26
- });
27
- setting.succeed();
28
- // Restart functions & sites
29
- const restarting = createSpinner(` Reloading all resources using ${blue(args.name)}...`).start();
30
- const { edgeSites, sites, placeholderSites, functions } = await Config.restart([args.name]);
31
- restarting.stop().clear();
32
- const siteCount = sites.length + placeholderSites.length;
33
- if (siteCount > 0) {
34
- Colors.line(Colors.success(`✔ `), siteCount === 1
35
- ? `Reloaded ${siteCount} site`
36
- : `Reloaded ${siteCount} sites`);
21
+ try {
22
+ // Set secret value
23
+ const setting = createSpinner(` Setting "${args.name}"`).start();
24
+ await Config.setSecret({
25
+ key: args.name,
26
+ value: args.value,
27
+ fallback: args.fallback === true,
28
+ });
29
+ setting.succeed();
30
+ // Restart functions & sites
31
+ const restarting = createSpinner(` Reloading all resources using ${blue(args.name)}...`).start();
32
+ const { edgeSites, sites, placeholderSites, functions } = await Config.restart([args.name]);
33
+ restarting.stop().clear();
34
+ const siteCount = sites.length + placeholderSites.length;
35
+ if (siteCount > 0) {
36
+ Colors.line(Colors.success(`✔ `), siteCount === 1
37
+ ? `Reloaded ${siteCount} site`
38
+ : `Reloaded ${siteCount} sites`);
39
+ }
40
+ const functionCount = functions.length;
41
+ if (functionCount > 0) {
42
+ Colors.line(Colors.success(`✔ `), functionCount === 1
43
+ ? `Reloaded ${functionCount} function`
44
+ : `Reloaded ${functionCount} functions`);
45
+ }
46
+ edgeSites.forEach(({ id, type }) => {
47
+ Colors.line(Colors.primary(`➜ `), `Redeploy the "${id}" ${type} to use the new secret`);
48
+ });
49
+ await exit();
37
50
  }
38
- const functionCount = functions.length;
39
- if (functionCount > 0) {
40
- Colors.line(Colors.success(`✔ `), functionCount === 1
41
- ? `Reloaded ${functionCount} function`
42
- : `Reloaded ${functionCount} functions`);
51
+ catch (e) {
52
+ await exitWithError(e);
43
53
  }
44
- edgeSites.forEach(({ id, type }) => {
45
- Colors.line(Colors.primary(`➜ `), `Redeploy the "${id}" ${type} to use the new secret`);
46
- });
47
- process.exit(0);
48
54
  });
@@ -6,12 +6,19 @@ export const telemetry = (program) => program.command("telemetry <action>", "Loa
6
6
  demandOption: true,
7
7
  }), async (args) => {
8
8
  const { enable, disable } = await import("../telemetry/telemetry.js");
9
- if (args.action === "enable") {
10
- enable();
11
- Colors.line(Colors.success(`✔ `), `Telemetry enabled`);
9
+ const { exit, exitWithError } = await import("../program.js");
10
+ try {
11
+ if (args.action === "enable") {
12
+ enable();
13
+ Colors.line(Colors.success(`✔ `), `Telemetry enabled`);
14
+ }
15
+ if (args.action === "disable") {
16
+ disable();
17
+ Colors.line(Colors.success(`✔ `), `Telemetry disabled`);
18
+ }
19
+ await exit();
12
20
  }
13
- if (args.action === "disable") {
14
- disable();
15
- Colors.line(Colors.success(`✔ `), `Telemetry disabled`);
21
+ catch (e) {
22
+ await exitWithError(e);
16
23
  }
17
24
  });
@@ -4,12 +4,19 @@ export const transform = (program) => program.command("transform <mod>", "Apply
4
4
  demandOption: true,
5
5
  }), async (args) => {
6
6
  const { Colors } = await import("../colors.js");
7
- if (args.mod === "resource-binding-secrets") {
8
- await handleSecretsMigration();
9
- Colors.line(Colors.success(`✔ `), `Transform "${args.mod}" applied successfully!`);
10
- return;
7
+ const { exit, exitWithError } = await import("../program.js");
8
+ try {
9
+ if (args.mod === "resource-binding-secrets") {
10
+ await handleSecretsMigration();
11
+ Colors.line(Colors.success(`✔ `), `Transform "${args.mod}" applied successfully!`);
12
+ return;
13
+ }
14
+ Colors.line(Colors.danger(`✖ `), `Transform "${args.mod}" not found`);
15
+ await exit();
16
+ }
17
+ catch (e) {
18
+ await exitWithError(e);
11
19
  }
12
- Colors.line(Colors.danger(`✖ `), `Transform "${args.mod}" not found`);
13
20
  });
14
21
  async function handleSecretsMigration() {
15
22
  const { useProject } = await import("../../project.js");