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 +6 -6
- package/cli/colors.d.ts +21 -0
- package/cli/colors.js +20 -0
- package/cli/commands/console.js +4 -2
- package/cli/commands/deploy.js +4 -8
- package/cli/commands/dev.d.ts +2 -0
- package/cli/commands/dev.js +63 -62
- package/cli/commands/diff.js +42 -2
- package/cli/commands/env.js +1 -1
- package/cli/commands/plugins/pothos.js +7 -3
- package/cli/commands/update-mod.d.ts +15 -0
- package/cli/commands/update-mod.js +53 -0
- package/cli/local/server.d.ts +3 -1
- package/cli/local/server.js +11 -4
- package/cli/program.js +1 -1
- package/cli/spinner.js +2 -0
- package/cli/sst.js +2 -0
- package/cli/ui/deploy.js +23 -33
- package/cli/ui/header.d.ts +4 -0
- package/cli/ui/header.js +12 -0
- package/constructs/Stack.d.ts +0 -1
- package/constructs/Stack.js +0 -24
- package/package.json +1 -1
- package/runtime/handlers/node.js +52 -37
- package/sst.mjs +749 -627
- package/stacks/build.js +31 -30
- package/stacks/diff.d.ts +8 -0
- package/stacks/diff.js +62 -0
- package/stacks/index.d.ts +1 -0
- package/stacks/index.js +1 -0
- package/stacks/metadata.js +1 -0
- package/stacks/synth.d.ts +1 -0
- package/stacks/synth.js +1 -0
- package/support/custom-resources/index.mjs +45 -25735
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 &&
|
|
60
|
-
|
|
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
|
-
|
|
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
|
};
|
package/cli/commands/console.js
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
14
|
+
const local = await useLocalServerConfig();
|
|
15
|
+
console.log(`Console started: ${local.url}`);
|
|
14
16
|
});
|
package/cli/commands/deploy.js
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
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) }));
|
package/cli/commands/dev.d.ts
CHANGED
package/cli/commands/dev.js
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import chalk from "chalk";
|
|
2
2
|
import { Colors } from "../colors.js";
|
|
3
|
-
|
|
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
|
-
|
|
40
|
-
|
|
41
|
-
|
|
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
|
-
|
|
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
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
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
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
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
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
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
|
-
|
|
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
|
-
|
|
144
|
+
Colors.line(ex.stack
|
|
141
145
|
.split("\n")
|
|
142
|
-
.map((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
|
-
|
|
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
|
-
|
|
216
|
+
await useLocalServer({
|
|
212
217
|
key: "",
|
|
213
218
|
cert: "",
|
|
214
219
|
live: true,
|
|
215
220
|
});
|
|
216
221
|
console.clear();
|
|
217
|
-
console
|
|
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++) {
|
package/cli/commands/diff.js
CHANGED
|
@@ -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
|
-
|
|
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
|
});
|
package/cli/commands/env.js
CHANGED
|
@@ -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
|
-
|
|
21
|
+
Colors.line(Colors.prefix);
|
|
22
|
+
Colors.line(Colors.success(`✔`), " Extracted pothos schema");
|
|
21
23
|
}
|
|
22
24
|
catch (ex) {
|
|
23
|
-
|
|
24
|
-
|
|
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
|
+
}
|
package/cli/local/server.d.ts
CHANGED
|
@@ -11,9 +11,11 @@ declare module "../../bus.js" {
|
|
|
11
11
|
"local.patches": DendriformPatch[];
|
|
12
12
|
}
|
|
13
13
|
}
|
|
14
|
-
export declare
|
|
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
|
}>;
|
package/cli/local/server.js
CHANGED
|
@@ -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
|
-
|
|
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
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");
|