sst 2.22.10 → 2.23.0
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 +21 -16
- package/cli/commands/bind.d.ts +0 -2
- package/cli/commands/bind.js +175 -103
- package/cli/ui/deploy.js +32 -3
- package/constructs/AstroSite.d.ts +1 -0
- package/constructs/AstroSite.js +3 -0
- package/constructs/BaseSite.d.ts +0 -71
- package/constructs/Distribution.d.ts +143 -0
- package/constructs/Distribution.js +260 -0
- package/constructs/Function.js +1 -1
- package/constructs/Metadata.d.ts +3 -1
- package/constructs/NextjsSite.d.ts +3 -1
- package/constructs/NextjsSite.js +53 -48
- package/constructs/Service.d.ts +398 -0
- package/constructs/Service.js +584 -0
- package/constructs/SsrSite.d.ts +10 -18
- package/constructs/SsrSite.js +53 -239
- package/constructs/StaticSite.d.ts +20 -16
- package/constructs/StaticSite.js +40 -224
- package/constructs/deprecated/NextjsSite.d.ts +11 -2
- package/constructs/deprecated/NextjsSite.js +13 -0
- package/constructs/index.d.ts +1 -0
- package/constructs/index.js +1 -0
- package/node/event-bus/index.d.ts +4 -1
- package/node/event-bus/index.js +1 -0
- package/package.json +2 -1
- package/project.d.ts +1 -0
- package/runtime/handlers/node.js +3 -0
- package/sst.mjs +243 -107
- package/stacks/deploy.js +4 -0
- package/stacks/metadata.d.ts +1 -0
- package/stacks/metadata.js +17 -0
- package/stacks/monitor.d.ts +1 -1
- package/stacks/monitor.js +1 -0
- package/support/nixpacks/Dockerfile +6 -0
- package/support/service-dev-function/index.js +1 -0
package/bootstrap.js
CHANGED
|
@@ -157,22 +157,27 @@ export async function bootstrapSST() {
|
|
|
157
157
|
Tags.of(app).add(key, value);
|
|
158
158
|
}
|
|
159
159
|
// Create S3 bucket to store stacks metadata
|
|
160
|
-
const bucket =
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
160
|
+
const bucket = bootstrap?.useExistingBucket
|
|
161
|
+
? {
|
|
162
|
+
bucketName: bootstrap.useExistingBucket,
|
|
163
|
+
bucketArn: `arn:${stack.partition}:s3:::${bootstrap.useExistingBucket}`,
|
|
164
|
+
}
|
|
165
|
+
: new Bucket(stack, region, {
|
|
166
|
+
encryption: BucketEncryption.S3_MANAGED,
|
|
167
|
+
removalPolicy: RemovalPolicy.DESTROY,
|
|
168
|
+
autoDeleteObjects: true,
|
|
169
|
+
enforceSSL: true,
|
|
170
|
+
lifecycleRules: [
|
|
171
|
+
{
|
|
172
|
+
id: "Remove partial uploads after 3 days",
|
|
173
|
+
enabled: true,
|
|
174
|
+
abortIncompleteMultipartUploadAfter: Duration.days(3),
|
|
175
|
+
},
|
|
176
|
+
],
|
|
177
|
+
blockPublicAccess: cdk?.publicAccessBlockConfiguration !== false
|
|
178
|
+
? BlockPublicAccess.BLOCK_ALL
|
|
179
|
+
: undefined,
|
|
180
|
+
});
|
|
176
181
|
// Create Function and subscribe to CloudFormation events
|
|
177
182
|
const fn = new Function(stack, "MetadataHandler", {
|
|
178
183
|
code: Code.fromAsset(path.resolve(__dirname, "support/bootstrap-metadata-function")),
|
package/cli/commands/bind.d.ts
CHANGED
package/cli/commands/bind.js
CHANGED
|
@@ -6,10 +6,6 @@ class MetadataOutdatedError extends Error {
|
|
|
6
6
|
}
|
|
7
7
|
export const bind = (program) => program
|
|
8
8
|
.command(["bind <command..>", "env <command..>"], "Bind your app's resources to a command", (yargs) => yargs
|
|
9
|
-
.option("site", {
|
|
10
|
-
type: "boolean",
|
|
11
|
-
describe: "Run in site mode",
|
|
12
|
-
})
|
|
13
9
|
.option("script", {
|
|
14
10
|
type: "boolean",
|
|
15
11
|
describe: "Run in script mode",
|
|
@@ -18,103 +14,110 @@ export const bind = (program) => program
|
|
|
18
14
|
.example(`sst bind vitest run`, "Bind resources to your tests")
|
|
19
15
|
.example(`sst bind next dev`, "Bind resources to your site")
|
|
20
16
|
.example(`sst bind --script next build`, "Bind resources to your site before deployment"), async (args) => {
|
|
17
|
+
const { Token } = await import("aws-cdk-lib");
|
|
21
18
|
const { spawn } = await import("child_process");
|
|
22
19
|
const kill = await import("tree-kill");
|
|
23
20
|
const { useProject } = await import("../../project.js");
|
|
21
|
+
const { Stacks } = await import("../../stacks/index.js");
|
|
24
22
|
const { useBus } = await import("../../bus.js");
|
|
25
23
|
const { useIOT } = await import("../../iot.js");
|
|
26
24
|
const { Colors } = await import("../colors.js");
|
|
27
25
|
const { Logger } = await import("../../logger.js");
|
|
26
|
+
const [{ useServices }, { useSites: useSsrSites }, { useSites: useStaticSites }, { useSites: useSlsNextjsSites }, { Parameter }, { getEnvironmentKey },] = await Promise.all([
|
|
27
|
+
import("../../constructs/Service.js"),
|
|
28
|
+
import("../../constructs/SsrSite.js"),
|
|
29
|
+
import("../../constructs/StaticSite.js"),
|
|
30
|
+
import("../../constructs/deprecated/NextjsSite.js"),
|
|
31
|
+
import("../../constructs/Config.js"),
|
|
32
|
+
import("../../constructs/util/functionBinding.js"),
|
|
33
|
+
]);
|
|
34
|
+
// Handle deprecated "env" command
|
|
28
35
|
if (args._[0] === "env") {
|
|
29
36
|
Colors.line(Colors.warning(`Warning: ${Colors.bold(`sst env`)} has been renamed to ${Colors.bold(`sst bind`)}`));
|
|
30
37
|
}
|
|
38
|
+
// Handle missing command
|
|
39
|
+
const command = args.command?.join(" ");
|
|
40
|
+
if (!command) {
|
|
41
|
+
throw new VisibleError("Command is required, e.g. sst bind npm run script");
|
|
42
|
+
}
|
|
31
43
|
await useIOT();
|
|
32
44
|
const bus = useBus();
|
|
33
45
|
const project = useProject();
|
|
34
|
-
const command = args.command?.join(" ");
|
|
35
|
-
const isSite = await isRunningInSite();
|
|
36
|
-
const mode = args.site ? "site" : args.script ? "script" : "auto";
|
|
37
46
|
let p;
|
|
38
47
|
let timer;
|
|
39
48
|
let siteConfigCache;
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
49
|
+
await buildApp();
|
|
50
|
+
const ssrSite = isInSsrSite();
|
|
51
|
+
const staticSite = isInStaticSite();
|
|
52
|
+
const service = isInService();
|
|
53
|
+
// Run the script
|
|
54
|
+
if (args.script || (!ssrSite && !staticSite && !service)) {
|
|
55
|
+
return await runScript();
|
|
56
|
+
}
|
|
57
|
+
// Run the app
|
|
58
|
+
try {
|
|
59
|
+
await runSite("init");
|
|
43
60
|
}
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
61
|
+
catch (e) {
|
|
62
|
+
if (!(e instanceof MetadataOutdatedError) &&
|
|
63
|
+
!(e instanceof MetadataNotFoundError)) {
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
Colors.line(Colors.warning(e instanceof MetadataOutdatedError
|
|
67
|
+
? "Warning: This was deployed with an old version of SST. Run `sst dev` or `sst deploy` to update."
|
|
68
|
+
: "Warning: The site has not been deployed. Some resources might not be available."));
|
|
69
|
+
return await runSiteUndeployed();
|
|
48
70
|
}
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
bus.subscribe("stacks.metadata.updated", () => bindSite("metadata_updated"));
|
|
52
|
-
bus.subscribe("stacks.metadata.deleted", () => bindSite("metadata_updated"));
|
|
71
|
+
bus.subscribe("stacks.metadata.updated", () => runSite("metadata_updated"));
|
|
72
|
+
bus.subscribe("stacks.metadata.deleted", () => runSite("metadata_updated"));
|
|
53
73
|
bus.subscribe("config.secret.updated", (payload) => {
|
|
54
74
|
const secretName = payload.properties.name;
|
|
55
|
-
if (!
|
|
75
|
+
if (!siteConfigCache.secrets.includes(secretName))
|
|
56
76
|
return;
|
|
57
77
|
Colors.line(`\n`, `SST secrets have been updated. Restarting \`${command}\`...`);
|
|
58
|
-
|
|
78
|
+
runSite("secrets_updated");
|
|
59
79
|
});
|
|
60
|
-
async function
|
|
61
|
-
const
|
|
62
|
-
const
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
{ file: "angular.json" },
|
|
70
|
-
{ file: "ember-cli-build.js" },
|
|
71
|
-
{
|
|
72
|
-
file: "vite.config",
|
|
73
|
-
multiExtension: true,
|
|
74
|
-
match: /solid-start|plugin-vue|plugin-react|@preact\/preset-vite/,
|
|
75
|
-
},
|
|
76
|
-
{ file: "package.json", match: /react-scripts/ },
|
|
77
|
-
{ file: "index.html" }, // plain HTML
|
|
78
|
-
];
|
|
79
|
-
const results = await Promise.all(SITE_CONFIGS.map((site) => {
|
|
80
|
-
const files = site.multiExtension
|
|
81
|
-
? [".js", ".cjs", ".mjs", ".ts"].map((ext) => `${site.file}${ext}`)
|
|
82
|
-
: [site.file];
|
|
83
|
-
return files.map(async (file) => {
|
|
84
|
-
const exists = await existsAsync(file);
|
|
85
|
-
if (!exists)
|
|
86
|
-
return false;
|
|
87
|
-
if (site.match) {
|
|
88
|
-
const content = await readFile(file);
|
|
89
|
-
return content.toString().match(site.match);
|
|
90
|
-
}
|
|
91
|
-
return true;
|
|
92
|
-
});
|
|
93
|
-
}).flat());
|
|
94
|
-
return results.some(Boolean);
|
|
80
|
+
async function buildApp() {
|
|
81
|
+
const [_metafile, sstConfig] = await Stacks.load(project.paths.config);
|
|
82
|
+
const cwd = process.cwd();
|
|
83
|
+
process.chdir(project.paths.root);
|
|
84
|
+
await Stacks.synth({
|
|
85
|
+
fn: sstConfig.stacks,
|
|
86
|
+
mode: "remove",
|
|
87
|
+
});
|
|
88
|
+
process.chdir(cwd);
|
|
95
89
|
}
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
}
|
|
117
|
-
|
|
90
|
+
function isInSsrSite() {
|
|
91
|
+
const cwd = process.cwd();
|
|
92
|
+
return useSsrSites().all.find(({ props }) => {
|
|
93
|
+
console.log(path.resolve(project.paths.root, props.path));
|
|
94
|
+
return path.resolve(project.paths.root, props.path) === cwd;
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
function isInStaticSite() {
|
|
98
|
+
const cwd = process.cwd();
|
|
99
|
+
return (useStaticSites().all.find(({ props }) => {
|
|
100
|
+
console.log(path.resolve(project.paths.root, props.path));
|
|
101
|
+
return path.resolve(project.paths.root, props.path) === cwd;
|
|
102
|
+
}) ||
|
|
103
|
+
useSlsNextjsSites().all.find(({ props }) => {
|
|
104
|
+
console.log(path.resolve(project.paths.root, props.path));
|
|
105
|
+
return path.resolve(project.paths.root, props.path) === cwd;
|
|
106
|
+
}));
|
|
107
|
+
}
|
|
108
|
+
function isInService() {
|
|
109
|
+
const cwd = process.cwd();
|
|
110
|
+
return useServices().all.find(({ props }) => {
|
|
111
|
+
console.log(path.resolve(project.paths.root, props.path));
|
|
112
|
+
return path.resolve(project.paths.root, props.path) === cwd;
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
async function runSite(reason) {
|
|
116
|
+
const siteConfig = ssrSite
|
|
117
|
+
? await getSsrSiteMetadata()
|
|
118
|
+
: staticSite
|
|
119
|
+
? await getStaticSiteMetadata()
|
|
120
|
+
: await getServiceMetadata();
|
|
118
121
|
// Handle rebind due to metadata updated
|
|
119
122
|
if (reason === "metadata_updated") {
|
|
120
123
|
if (areEnvsSame(siteConfig.envs, siteConfigCache?.envs || {}))
|
|
@@ -132,54 +135,123 @@ export const bind = (program) => program
|
|
|
132
135
|
...credentials,
|
|
133
136
|
});
|
|
134
137
|
}
|
|
135
|
-
async function
|
|
138
|
+
async function runSiteUndeployed() {
|
|
139
|
+
// Note: when the site is undeployed:
|
|
140
|
+
// - bind all resources
|
|
141
|
+
// - bind resources that are constant (ie. Config.Parameter)
|
|
142
|
+
// - set environment variables that are constant
|
|
143
|
+
const constructEnvs = {};
|
|
144
|
+
Object.entries((ssrSite || staticSite || service)?.props.environment || {})
|
|
145
|
+
.filter(([key, value]) => !Token.isUnresolved(value))
|
|
146
|
+
.forEach(([key, value]) => (constructEnvs[key] = value));
|
|
147
|
+
((ssrSite || service)?.props.bind || []).forEach((b) => {
|
|
148
|
+
if (b instanceof Parameter && !Token.isUnresolved(b.value)) {
|
|
149
|
+
constructEnvs[getEnvironmentKey(b, "name")] = b.value;
|
|
150
|
+
}
|
|
151
|
+
});
|
|
136
152
|
const { Config } = await import("../../config.js");
|
|
137
153
|
await runCommand({
|
|
154
|
+
...constructEnvs,
|
|
138
155
|
...(await Config.env()),
|
|
139
156
|
...(await getLocalIamCredentials()),
|
|
140
157
|
});
|
|
141
158
|
}
|
|
142
|
-
async function
|
|
143
|
-
const {
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
159
|
+
async function runScript() {
|
|
160
|
+
const { Config } = await import("../../config.js");
|
|
161
|
+
await runCommand({
|
|
162
|
+
...(await Config.env()),
|
|
163
|
+
...(await getLocalIamCredentials()),
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
async function getSsrSiteMetadata() {
|
|
167
|
+
const [{ metadataForStack }, { LambdaClient, GetFunctionCommand }, { useAWSClient },] = await Promise.all([
|
|
168
|
+
import("../../stacks/metadata.js"),
|
|
169
|
+
import("@aws-sdk/client-lambda"),
|
|
170
|
+
import("../../credentials.js"),
|
|
171
|
+
]);
|
|
172
|
+
const metadataData = await metadataForStack(ssrSite.stack);
|
|
173
|
+
const metadata = metadataData
|
|
147
174
|
.filter((c) => [
|
|
148
|
-
"StaticSite",
|
|
149
175
|
"NextjsSite",
|
|
150
176
|
"AstroSite",
|
|
151
177
|
"RemixSite",
|
|
152
178
|
"SolidStartSite",
|
|
153
179
|
"SvelteKitSite",
|
|
154
|
-
"SlsNextjsSite",
|
|
155
180
|
].includes(c.type))
|
|
156
181
|
.find((c) => {
|
|
157
|
-
//
|
|
158
|
-
|
|
159
|
-
if (!c.data.path ||
|
|
160
|
-
(isSsr && !c.data.server) ||
|
|
161
|
-
(!isSsr && !c.data.environment)) {
|
|
182
|
+
// metadata prior to SST v2.3.0 doesn't have path
|
|
183
|
+
if (!c.data.path || !c.data.server) {
|
|
162
184
|
throw new MetadataOutdatedError();
|
|
163
185
|
}
|
|
164
186
|
return (path.resolve(project.paths.root, c.data.path) === process.cwd());
|
|
165
187
|
});
|
|
166
|
-
if (!
|
|
188
|
+
if (!metadata)
|
|
167
189
|
throw new MetadataNotFoundError();
|
|
168
|
-
|
|
169
|
-
|
|
190
|
+
// Parse metadata
|
|
191
|
+
const lambda = useAWSClient(LambdaClient);
|
|
192
|
+
const { Configuration: functionConfig } = await lambda.send(new GetFunctionCommand({
|
|
193
|
+
FunctionName: metadata.data.server,
|
|
194
|
+
}));
|
|
195
|
+
return {
|
|
196
|
+
role: functionConfig?.Role,
|
|
197
|
+
envs: functionConfig?.Environment?.Variables || {},
|
|
198
|
+
secrets: metadata.data.secrets,
|
|
199
|
+
};
|
|
170
200
|
}
|
|
171
|
-
async function
|
|
172
|
-
const {
|
|
173
|
-
const
|
|
174
|
-
const
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
201
|
+
async function getStaticSiteMetadata() {
|
|
202
|
+
const { metadataForStack } = await import("../../stacks/metadata.js");
|
|
203
|
+
const metadataData = await metadataForStack(staticSite.stack);
|
|
204
|
+
const metadata = metadataData
|
|
205
|
+
.filter((c) => ["StaticSite", "SlsNextjsSite"].includes(c.type))
|
|
206
|
+
.find((c) => {
|
|
207
|
+
// metadata prior to SST v2.3.0 doesn't have path
|
|
208
|
+
if (!c.data.path || !c.data.environment) {
|
|
209
|
+
throw new MetadataOutdatedError();
|
|
210
|
+
}
|
|
211
|
+
return (path.resolve(project.paths.root, c.data.path) === process.cwd());
|
|
212
|
+
});
|
|
213
|
+
if (!metadata)
|
|
214
|
+
throw new MetadataNotFoundError();
|
|
215
|
+
return {
|
|
216
|
+
envs: metadata.data.environment,
|
|
217
|
+
role: undefined,
|
|
218
|
+
secrets: [],
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
async function getServiceMetadata() {
|
|
222
|
+
const [{ metadataForStack }, { LambdaClient, GetFunctionCommand }, { ECSClient, DescribeTaskDefinitionCommand }, { useAWSClient },] = await Promise.all([
|
|
223
|
+
import("../../stacks/metadata.js"),
|
|
224
|
+
import("@aws-sdk/client-lambda"),
|
|
225
|
+
import("@aws-sdk/client-ecs"),
|
|
226
|
+
import("../../credentials.js"),
|
|
227
|
+
]);
|
|
228
|
+
// Get metadata
|
|
229
|
+
const metadataData = await metadataForStack(service.stack);
|
|
230
|
+
const metadata = metadataData
|
|
231
|
+
.filter((c) => ["Service"].includes(c.type))
|
|
232
|
+
.find((c) => {
|
|
233
|
+
return (path.resolve(project.paths.root, c.data.path) === process.cwd());
|
|
234
|
+
});
|
|
235
|
+
if (!metadata)
|
|
236
|
+
throw new MetadataNotFoundError();
|
|
237
|
+
// Parse metadata for "sst deploy"
|
|
238
|
+
if (metadata.data.mode === "deployed") {
|
|
239
|
+
const ecs = useAWSClient(ECSClient);
|
|
240
|
+
const task = await ecs.send(new DescribeTaskDefinitionCommand({
|
|
241
|
+
taskDefinition: metadata.data.task,
|
|
242
|
+
}));
|
|
243
|
+
const envs = {};
|
|
244
|
+
(task?.taskDefinition?.containerDefinitions[0].environment || []).forEach(({ name, value }) => (envs[name] = value));
|
|
245
|
+
return {
|
|
246
|
+
role: task?.taskDefinition?.taskRoleArn,
|
|
247
|
+
envs,
|
|
248
|
+
secrets: metadata.data.secrets,
|
|
249
|
+
};
|
|
178
250
|
}
|
|
179
|
-
//
|
|
251
|
+
// Parse metadata for "sst dev"
|
|
180
252
|
const lambda = useAWSClient(LambdaClient);
|
|
181
253
|
const { Configuration: functionConfig } = await lambda.send(new GetFunctionCommand({
|
|
182
|
-
FunctionName: metadata.data.
|
|
254
|
+
FunctionName: metadata.data.devFunction,
|
|
183
255
|
}));
|
|
184
256
|
return {
|
|
185
257
|
role: functionConfig?.Role,
|
|
@@ -196,7 +268,7 @@ export const bind = (program) => program
|
|
|
196
268
|
clearTimeout(timer);
|
|
197
269
|
timer = setTimeout(() => {
|
|
198
270
|
Colors.line(`\n`, `Your AWS session is about to expire. Creating a new session and restarting \`${command}\`...`);
|
|
199
|
-
|
|
271
|
+
runSite("iam_expired");
|
|
200
272
|
}, expireAt - Date.now());
|
|
201
273
|
return {
|
|
202
274
|
AWS_ACCESS_KEY_ID: credentials.AccessKeyId,
|
package/cli/ui/deploy.js
CHANGED
|
@@ -6,13 +6,29 @@ import Spinner from "ink-spinner";
|
|
|
6
6
|
import { Colors } from "../colors.js";
|
|
7
7
|
import { useProject } from "../../project.js";
|
|
8
8
|
export const DeploymentUI = (props) => {
|
|
9
|
+
const [statuses, setStatuses] = useState({});
|
|
9
10
|
const [resources, setResources] = useState({});
|
|
10
11
|
useEffect(() => {
|
|
11
12
|
Colors.gap();
|
|
12
13
|
const bus = useBus();
|
|
14
|
+
const status = bus.subscribe("stack.status", (payload) => {
|
|
15
|
+
const { stackID, status } = payload.properties;
|
|
16
|
+
setStatuses((previous) => {
|
|
17
|
+
if (status !== "PUBLISH_ASSETS_IN_PROGRESS") {
|
|
18
|
+
if (previous[stackID]) {
|
|
19
|
+
Colors.line(Colors.warning(Colors.prefix), Colors.dim(stackNameToId(stackID)), Colors.dim("PUBLISH_ASSETS_COMPLETE"), "");
|
|
20
|
+
}
|
|
21
|
+
const { [stackID]: _, ...next } = previous;
|
|
22
|
+
return next;
|
|
23
|
+
}
|
|
24
|
+
return {
|
|
25
|
+
...previous,
|
|
26
|
+
[stackID]: status,
|
|
27
|
+
};
|
|
28
|
+
});
|
|
29
|
+
});
|
|
13
30
|
const event = bus.subscribe("stack.event", (payload) => {
|
|
14
31
|
const { event } = payload.properties;
|
|
15
|
-
// if (event.ResourceType === "AWS::CloudFormation::Stack") return;
|
|
16
32
|
setResources((previous) => {
|
|
17
33
|
if (Stacks.isFinal(event.ResourceStatus)) {
|
|
18
34
|
const readable = logicalIdToCdkPath(props.assembly, event.StackName, event.LogicalResourceId);
|
|
@@ -34,6 +50,7 @@ export const DeploymentUI = (props) => {
|
|
|
34
50
|
});
|
|
35
51
|
return () => {
|
|
36
52
|
bus.unsubscribe(event);
|
|
53
|
+
bus.unsubscribe(status);
|
|
37
54
|
};
|
|
38
55
|
}, []);
|
|
39
56
|
function color(status) {
|
|
@@ -44,8 +61,19 @@ export const DeploymentUI = (props) => {
|
|
|
44
61
|
return "yellow";
|
|
45
62
|
}
|
|
46
63
|
return (React.createElement(Box, { flexDirection: "column" },
|
|
47
|
-
Object.entries(
|
|
64
|
+
Object.entries(statuses)
|
|
48
65
|
.slice(0, process.stdout.rows - 2)
|
|
66
|
+
.map(([stack, status], index) => {
|
|
67
|
+
return (React.createElement(Box, { key: index },
|
|
68
|
+
React.createElement(Text, null,
|
|
69
|
+
React.createElement(Spinner, null),
|
|
70
|
+
" ",
|
|
71
|
+
stackNameToId(stack),
|
|
72
|
+
" "),
|
|
73
|
+
React.createElement(Text, { color: color(status) }, status)));
|
|
74
|
+
}),
|
|
75
|
+
Object.entries(resources)
|
|
76
|
+
.slice(0, Math.max(0, process.stdout.rows - Object.entries(statuses).length - 2))
|
|
49
77
|
.map(([_, evt], index) => {
|
|
50
78
|
const readable = logicalIdToCdkPath(props.assembly, evt.StackName, evt.LogicalResourceId);
|
|
51
79
|
return (React.createElement(Box, { key: index },
|
|
@@ -58,7 +86,8 @@ export const DeploymentUI = (props) => {
|
|
|
58
86
|
" "),
|
|
59
87
|
React.createElement(Text, { color: color(evt.ResourceStatus || "") }, evt.ResourceStatus)));
|
|
60
88
|
}),
|
|
61
|
-
Object.entries(resources).length === 0 &&
|
|
89
|
+
Object.entries(resources).length === 0 &&
|
|
90
|
+
Object.entries(statuses).length === 0 && (React.createElement(Box, null,
|
|
62
91
|
React.createElement(Text, null,
|
|
63
92
|
React.createElement(Spinner, null),
|
|
64
93
|
" ",
|
package/constructs/AstroSite.js
CHANGED
package/constructs/BaseSite.d.ts
CHANGED
|
@@ -1,81 +1,10 @@
|
|
|
1
|
-
import { IHostedZone } from "aws-cdk-lib/aws-route53";
|
|
2
1
|
import { ErrorResponse, DistributionProps, BehaviorOptions, IOrigin } from "aws-cdk-lib/aws-cloudfront";
|
|
3
|
-
import { ICertificate } from "aws-cdk-lib/aws-certificatemanager";
|
|
4
2
|
export interface BaseSiteFileOptions {
|
|
5
3
|
exclude: string | string[];
|
|
6
4
|
include: string | string[];
|
|
7
5
|
cacheControl: string;
|
|
8
6
|
contentType?: string;
|
|
9
7
|
}
|
|
10
|
-
/**
|
|
11
|
-
* The customDomain for this website. SST supports domains that are hosted either on [Route 53](https://aws.amazon.com/route53/) or externally.
|
|
12
|
-
*
|
|
13
|
-
* Note that you can also migrate externally hosted domains to Route 53 by [following this guide](https://docs.aws.amazon.com/Route53/latest/DeveloperGuide/MigratingDNS.html).
|
|
14
|
-
*
|
|
15
|
-
* @example
|
|
16
|
-
* ```js
|
|
17
|
-
* new StaticSite(this, "Site", {
|
|
18
|
-
* path: "path/to/src",
|
|
19
|
-
* customDomain: "domain.com",
|
|
20
|
-
* });
|
|
21
|
-
* ```
|
|
22
|
-
*
|
|
23
|
-
* @example
|
|
24
|
-
* ```js
|
|
25
|
-
* new StaticSite(this, "Site", {
|
|
26
|
-
* path: "path/to/src",
|
|
27
|
-
* customDomain: {
|
|
28
|
-
* domainName: "domain.com",
|
|
29
|
-
* domainAlias: "www.domain.com",
|
|
30
|
-
* hostedZone: "domain.com",
|
|
31
|
-
* }
|
|
32
|
-
* });
|
|
33
|
-
* ```
|
|
34
|
-
*/
|
|
35
|
-
export interface BaseSiteDomainProps {
|
|
36
|
-
/**
|
|
37
|
-
* The domain to be assigned to the website URL (ie. domain.com).
|
|
38
|
-
*
|
|
39
|
-
* Supports domains that are hosted either on [Route 53](https://aws.amazon.com/route53/) or externally.
|
|
40
|
-
*/
|
|
41
|
-
domainName: string;
|
|
42
|
-
/**
|
|
43
|
-
* An alternative domain to be assigned to the website URL. Visitors to the alias will be redirected to the main domain. (ie. `www.domain.com`).
|
|
44
|
-
*
|
|
45
|
-
* Use this to create a `www.` version of your domain and redirect visitors to the root domain.
|
|
46
|
-
* @default no alias configured
|
|
47
|
-
*/
|
|
48
|
-
domainAlias?: string;
|
|
49
|
-
/**
|
|
50
|
-
* The hosted zone in Route 53 that contains the domain. By default, SST will look for a hosted zone matching the domainName that's passed in.
|
|
51
|
-
*
|
|
52
|
-
* Set this option if SST cannot find the hosted zone in Route 53.
|
|
53
|
-
* @default same as the `domainName`
|
|
54
|
-
*/
|
|
55
|
-
hostedZone?: string;
|
|
56
|
-
/**
|
|
57
|
-
* Specify additional names that should route to the Cloudfront Distribution. Note, certificates for these names will not be automatically generated so the `certificate` option must be specified.
|
|
58
|
-
* @default `[]`
|
|
59
|
-
*/
|
|
60
|
-
alternateNames?: string[];
|
|
61
|
-
/**
|
|
62
|
-
* Set this option if the domain is not hosted on Amazon Route 53.
|
|
63
|
-
* @default `false`
|
|
64
|
-
*/
|
|
65
|
-
isExternalDomain?: boolean;
|
|
66
|
-
cdk?: {
|
|
67
|
-
/**
|
|
68
|
-
* Import the underlying Route 53 hosted zone.
|
|
69
|
-
*/
|
|
70
|
-
hostedZone?: IHostedZone;
|
|
71
|
-
/**
|
|
72
|
-
* Import the certificate for the domain. By default, SST will create a certificate with the domain name. The certificate will be created in the `us-east-1`(N. Virginia) region as required by AWS CloudFront.
|
|
73
|
-
*
|
|
74
|
-
* Set this option if you have an existing certificate in the `us-east-1` region in AWS Certificate Manager you want to use.
|
|
75
|
-
*/
|
|
76
|
-
certificate?: ICertificate;
|
|
77
|
-
};
|
|
78
|
-
}
|
|
79
8
|
export interface BaseSiteEnvironmentOutputsInfo {
|
|
80
9
|
path: string;
|
|
81
10
|
stack: string;
|