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 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 = new Bucket(stack, region, {
161
- encryption: BucketEncryption.S3_MANAGED,
162
- removalPolicy: RemovalPolicy.DESTROY,
163
- autoDeleteObjects: true,
164
- enforceSSL: true,
165
- lifecycleRules: [
166
- {
167
- id: "Remove partial uploads after 3 days",
168
- enabled: true,
169
- abortIncompleteMultipartUploadAfter: Duration.days(3),
170
- },
171
- ],
172
- blockPublicAccess: cdk?.publicAccessBlockConfiguration !== false
173
- ? BlockPublicAccess.BLOCK_ALL
174
- : undefined,
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")),
@@ -12,8 +12,6 @@ export declare const bind: (program: Program) => import("yargs").Argv<{
12
12
  role: string | undefined;
13
13
  } & {
14
14
  future: boolean | undefined;
15
- } & {
16
- site: boolean | undefined;
17
15
  } & {
18
16
  script: boolean | undefined;
19
17
  } & {
@@ -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
- // Handle missing command
41
- if (!command) {
42
- throw new VisibleError(`Command is required, e.g. sst bind ${isSite ? "next dev" : "vitest run"}`);
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
- // Bind script
45
- if (args.script || (!isSite && !args.site)) {
46
- Logger.debug("Running in script mode.");
47
- return await bindScript();
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
- // Bind site
50
- await bindSite("init");
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 (!(siteConfigCache?.secrets || []).includes(secretName))
75
+ if (!siteConfigCache.secrets.includes(secretName))
56
76
  return;
57
77
  Colors.line(`\n`, `SST secrets have been updated. Restarting \`${command}\`...`);
58
- bindSite("secrets_updated");
78
+ runSite("secrets_updated");
59
79
  });
60
- async function isRunningInSite() {
61
- const { existsAsync } = await import("../../util/fs.js");
62
- const { readFile } = await import("fs/promises");
63
- const SITE_CONFIGS = [
64
- { file: "next.config", multiExtension: true },
65
- { file: "astro.config", multiExtension: true },
66
- { file: "remix.config", multiExtension: true },
67
- { file: "svelte.config", multiExtension: true },
68
- { file: "gatsby-config", multiExtension: true },
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
- async function bindSite(reason) {
97
- // Get metadata
98
- let siteMetadata;
99
- try {
100
- siteMetadata = await getSiteMetadata();
101
- }
102
- catch (e) {
103
- // unhandled error
104
- if (!(e instanceof MetadataOutdatedError) &&
105
- !(e instanceof MetadataNotFoundError)) {
106
- throw e;
107
- }
108
- // ignore error if previously failed to fetch metadata
109
- if (reason !== "init")
110
- return;
111
- // run in script mode
112
- Colors.line(Colors.warning(e instanceof MetadataOutdatedError
113
- ? "Warning: This was deployed with an old version of SST. Run `sst dev` or `sst deploy` to update."
114
- : "Warning: The site has not been deployed. Some resources might not be available."));
115
- return await bindScript();
116
- }
117
- const siteConfig = await parseSiteMetadata(siteMetadata);
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 bindScript() {
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 getSiteMetadata() {
143
- const { metadata } = await import("../../stacks/metadata.js");
144
- const metadataData = await metadata();
145
- const data = Object.values(metadataData)
146
- .flat()
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
- // Handle metadata prior to SST v2.3.0 doesn't have path
158
- const isSsr = c.type !== "StaticSite" && c.type !== "SlsNextjsSite";
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 (!data) {
188
+ if (!metadata)
167
189
  throw new MetadataNotFoundError();
168
- }
169
- return data;
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 parseSiteMetadata(metadata) {
172
- const { LambdaClient, GetFunctionCommand } = await import("@aws-sdk/client-lambda");
173
- const { useAWSClient } = await import("../../credentials.js");
174
- const isBindSupported = metadata.type !== "StaticSite" && metadata.type !== "SlsNextjsSite";
175
- // Handle StaticSite
176
- if (!isBindSupported) {
177
- return { envs: metadata.data.environment };
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
- // Get function details
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.server,
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
- bindSite("iam_expired");
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(resources)
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 && (React.createElement(Box, null,
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
  " ",
@@ -34,4 +34,5 @@ export declare class AstroSite extends SsrSite {
34
34
  };
35
35
  type: "AstroSite";
36
36
  };
37
+ protected supportsStreaming(): boolean;
37
38
  }
@@ -72,4 +72,7 @@ export class AstroSite extends SsrSite {
72
72
  ...this.getConstructMetadataBase(),
73
73
  };
74
74
  }
75
+ supportsStreaming() {
76
+ return true;
77
+ }
75
78
  }
@@ -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;