sst 2.2.8 → 2.3.1

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.
@@ -1,31 +1,203 @@
1
+ import path from "path";
1
2
  import { VisibleError } from "../../error.js";
3
+ const SITE_CONFIG = {
4
+ NextjsSite: "next.config",
5
+ AstroSite: "astro.config",
6
+ RemixSite: "remix.config",
7
+ SolidStartSite: "vite.config",
8
+ StaticSite: "vite.config",
9
+ SlsNextjsSite: "next.config",
10
+ };
2
11
  export const bind = (program) => program
3
- .command("bind <command..>", "Bind your app's resources to a command", (yargs) => yargs
12
+ .command(["bind <command..>", "env <command..>"], "Bind your app's resources to a command", (yargs) => yargs
4
13
  .array("command")
5
14
  .example(`sst bind "vitest run"`, "Bind your resources to your tests")
6
15
  .example(`sst bind "tsx scripts/myscript.ts"`, "Bind your resources to a script"), async (args) => {
7
- const { Config } = await import("../../config.js");
8
- const { spawnSync } = await import("child_process");
9
- const { useAWSCredentials } = await import("../../credentials.js");
16
+ const { spawn } = await import("child_process");
10
17
  const { useProject } = await import("../../project.js");
11
- const env = await Config.env();
18
+ const { useBus } = await import("../../bus.js");
19
+ const { useIOT } = await import("../../iot.js");
20
+ const { Colors } = await import("../colors.js");
21
+ if (args._[0] === "env") {
22
+ Colors.line(Colors.warning(`Warning: ${Colors.bold(`sst env`)} has been renamed to ${Colors.bold(`sst bind`)}`));
23
+ }
24
+ await useIOT();
25
+ const bus = useBus();
12
26
  const project = useProject();
13
- const credentials = await useAWSCredentials();
14
- const joined = args.command?.join(" ");
15
- if (!joined)
16
- throw new VisibleError("Command is required, e.g. sst bind env");
17
- const result = spawnSync(joined, {
18
- env: {
19
- ...process.env,
20
- ...env,
27
+ const command = args.command?.join(" ");
28
+ const isFrontend = await isRunningInFrontend();
29
+ let p;
30
+ let timer;
31
+ let metadataCache;
32
+ // Handle missing command
33
+ if (!command) {
34
+ throw new VisibleError(`Command is required, e.g. sst bind ${isFrontend ? "next dev" : "env"}`);
35
+ }
36
+ // Bind script
37
+ const initialMetadata = await getSiteMetadata();
38
+ if (!initialMetadata) {
39
+ return await bindScript();
40
+ }
41
+ // Bind site
42
+ await bindSite("init");
43
+ bus.subscribe("stacks.metadata.updated", () => bindSite("metadata_updated"));
44
+ bus.subscribe("stacks.metadata.deleted", () => bindSite("metadata_updated"));
45
+ bus.subscribe("config.secret.updated", (payload) => {
46
+ const secretName = payload.properties.name;
47
+ if (metadataCache?.secrets === undefined)
48
+ return;
49
+ if (!metadataCache.secrets.includes(secretName))
50
+ return;
51
+ Colors.line(`\n`, `SST secrets have been updated. Restarting \`${command}\`...`);
52
+ bindSite("secrets_updated");
53
+ });
54
+ async function isRunningInFrontend() {
55
+ const { existsAsync } = await import("../../util/fs.js");
56
+ const results = await Promise.all(Object.values(SITE_CONFIG)
57
+ .map((config) => [".js", ".cjs", ".mjs", ".ts"].map((ext) => existsAsync(`${config}${ext}`)))
58
+ .flat());
59
+ return results.some(Boolean);
60
+ }
61
+ async function bindSite(reason) {
62
+ // Get metadata
63
+ const metadata = (reason === "init" ? initialMetadata : await getSiteMetadata());
64
+ // Handle rebind due to metadata updated
65
+ if (reason === "metadata_updated") {
66
+ if (areEnvsSame(metadata.envs, metadataCache?.envs || {}))
67
+ return;
68
+ Colors.line(`\n`, `SST resources have been updated. Restarting \`${command}\`...`);
69
+ }
70
+ metadataCache = metadata;
71
+ // Assume function's role credentials
72
+ if (metadata.role) {
73
+ const credentials = await assumeSsrRole(metadata.role);
74
+ if (credentials) {
75
+ // refresh crecentials 1 minute before expiration
76
+ const expireAt = credentials.Expiration.getTime() - 60000;
77
+ clearTimeout(timer);
78
+ timer = setTimeout(() => {
79
+ Colors.line(`\n`, `Your AWS session is about to expire. Creating a new session and restarting \`${command}\`...`);
80
+ bindSite("iam_expired");
81
+ }, expireAt - Date.now());
82
+ runCommand({
83
+ ...metadata.envs,
84
+ AWS_ACCESS_KEY_ID: credentials.AccessKeyId,
85
+ AWS_SECRET_ACCESS_KEY: credentials.SecretAccessKey,
86
+ AWS_SESSION_TOKEN: credentials.SessionToken,
87
+ });
88
+ return;
89
+ }
90
+ }
91
+ // Fallback to use local IAM credentials
92
+ runCommand({
93
+ ...metadata.envs,
94
+ ...(await localIamCredentials()),
95
+ });
96
+ }
97
+ async function bindScript() {
98
+ const { Config } = await import("../../config.js");
99
+ runCommand({
100
+ ...(await Config.env()),
101
+ ...(await localIamCredentials()),
102
+ });
103
+ }
104
+ async function getSiteMetadata() {
105
+ const { metadata } = await import("../../stacks/metadata.js");
106
+ const { createSpinner } = await import("../spinner.js");
107
+ const { LambdaClient, GetFunctionCommand } = await import("@aws-sdk/client-lambda");
108
+ const { useAWSClient } = await import("../../credentials.js");
109
+ const spinner = createSpinner({});
110
+ while (true) {
111
+ const metadataData = await metadata();
112
+ const data = Object.values(metadataData)
113
+ .flat()
114
+ .filter((c) => Boolean(c))
115
+ .filter((c) => Boolean(SITE_CONFIG[c.type]))
116
+ .find((c) => path.resolve(project.paths.root, c.data.path) ===
117
+ process.cwd());
118
+ // Do not retry if not running in frontend
119
+ if (!data && !isFrontend) {
120
+ return;
121
+ }
122
+ // Handle site metadata not found
123
+ if (!data) {
124
+ spinner.start(
125
+ //"Waiting for SST to start for the first time. Run `sst dev`..."
126
+ //"Run `sst dev` for the first time. Waiting..."
127
+ "Make sure `sst dev` is running...");
128
+ await new Promise((resolve) => setTimeout(resolve, 1000));
129
+ continue;
130
+ }
131
+ // Handle site metadata is old
132
+ const isBindSupported = data.type !== "StaticSite" && data.type !== "SlsNextjsSite";
133
+ if ((isBindSupported && !data.data.server) ||
134
+ (!isBindSupported && !data.data.environment)) {
135
+ spinner.start("This was deployed with an old version of SST. Make sure to restart `sst dev`...");
136
+ await new Promise((resolve) => setTimeout(resolve, 1000));
137
+ continue;
138
+ }
139
+ spinner.isSpinning && spinner.stop().clear();
140
+ // Handle StaticSite
141
+ if (!isBindSupported) {
142
+ return { envs: data.data.environment };
143
+ }
144
+ // Get function details
145
+ const lambda = useAWSClient(LambdaClient);
146
+ const { Configuration: functionConfig } = await lambda.send(new GetFunctionCommand({
147
+ FunctionName: data.data.server,
148
+ }));
149
+ return {
150
+ role: functionConfig?.Role,
151
+ envs: functionConfig?.Environment?.Variables || {},
152
+ secrets: data.data.secrets,
153
+ };
154
+ }
155
+ }
156
+ async function assumeSsrRole(roleArn) {
157
+ const { STSClient, AssumeRoleCommand } = await import("@aws-sdk/client-sts");
158
+ const { Logger } = await import("../../logger.js");
159
+ const { useAWSClient } = await import("../../credentials.js");
160
+ const sts = useAWSClient(STSClient);
161
+ try {
162
+ const { Credentials: credentials } = await sts.send(new AssumeRoleCommand({
163
+ RoleArn: roleArn,
164
+ RoleSessionName: "dev-session",
165
+ DurationSeconds: 43200,
166
+ }));
167
+ return credentials;
168
+ }
169
+ catch (e) {
170
+ Colors.line(Colors.warning(`Failed to assume SSR role ${roleArn}. Falling back to using local IAM credentials.`));
171
+ Logger.debug(`Failed to assume ${roleArn}.`, e);
172
+ }
173
+ }
174
+ async function localIamCredentials() {
175
+ const { useAWSCredentials } = await import("../../credentials.js");
176
+ const credentials = await useAWSCredentials();
177
+ return {
21
178
  AWS_ACCESS_KEY_ID: credentials.accessKeyId,
22
179
  AWS_SECRET_ACCESS_KEY: credentials.secretAccessKey,
23
180
  AWS_SESSION_TOKEN: credentials.sessionToken,
24
- AWS_REGION: project.config.region,
25
- },
26
- stdio: "inherit",
27
- shell: true,
28
- });
29
- process.exitCode = result.status || undefined;
181
+ };
182
+ }
183
+ function runCommand(envs) {
184
+ Colors.gap();
185
+ if (p) {
186
+ p.kill();
187
+ }
188
+ p = spawn(command, {
189
+ env: {
190
+ ...process.env,
191
+ ...envs,
192
+ AWS_REGION: project.config.region,
193
+ },
194
+ stdio: "inherit",
195
+ shell: true,
196
+ });
197
+ }
198
+ function areEnvsSame(envs1, envs2) {
199
+ return (Object.keys(envs1).length === Object.keys(envs2).length &&
200
+ Object.keys(envs1).every((key) => envs1[key] === envs2[key]));
201
+ }
30
202
  })
31
203
  .strict(false);
@@ -4,7 +4,7 @@ export const dev = (program) => program.command(["dev", "start"], "Work on your
4
4
  }), async (args) => {
5
5
  const { Colors } = await import("../colors.js");
6
6
  const { printHeader } = await import("../ui/header.js");
7
- const { mapValues, omitBy, pipe } = await import("remeda");
7
+ const { mapValues } = await import("remeda");
8
8
  const path = await import("path");
9
9
  const { useRuntimeWorkers } = await import("../../runtime/workers.js");
10
10
  const { useIOTBridge } = await import("../../runtime/iot.js");
@@ -23,7 +23,6 @@ export const dev = (program) => program.command(["dev", "start"], "Work on your
23
23
  const fs = await import("fs/promises");
24
24
  const crypto = await import("crypto");
25
25
  const { useFunctions } = await import("../../constructs/Function.js");
26
- const { SiteEnv } = await import("../../site-env.js");
27
26
  const { usePothosBuilder } = await import("./plugins/pothos.js");
28
27
  const { useKyselyTypeGenerator } = await import("./plugins/kysely.js");
29
28
  const { useRDSWarmer } = await import("./plugins/warmer.js");
@@ -178,22 +177,8 @@ export const dev = (program) => program.command(["dev", "start"], "Work on your
178
177
  await saveAppMetadata({ mode: "dev" });
179
178
  }
180
179
  lastDeployed = nextChecksum;
181
- // Update site env
182
- const keys = await SiteEnv.keys();
183
- const result = {};
184
- for (const key of keys) {
185
- const stack = results[key.stack];
186
- const value = stack.outputs[key.output];
187
- let existing = result[key.path];
188
- if (!existing) {
189
- result[key.path] = existing;
190
- existing = result[key.path] = {};
191
- }
192
- existing[key.environment] = value;
193
- }
194
- await SiteEnv.writeValues(result);
195
180
  // Write outputs.json
196
- fs.writeFile(path.join(project.paths.out, "outputs.json"), JSON.stringify(pipe(results, omitBy((_, key) => key.includes("SstSiteEnv")), mapValues((val) => val.outputs)), null, 2));
181
+ fs.writeFile(path.join(project.paths.out, "outputs.json"), JSON.stringify(mapValues(results, (val) => val.outputs), null, 2));
197
182
  isWorking = false;
198
183
  if (isDirty)
199
184
  build();
@@ -14,8 +14,10 @@ export const set = (program) => program.command("set <name> <value>", "Set the v
14
14
  describe: "Set the fallback value",
15
15
  }), async (args) => {
16
16
  const { Config } = await import("../../../config.js");
17
+ const { Colors } = await import("../../colors.js");
17
18
  const { blue } = await import("colorette");
18
19
  const { createSpinner } = await import("../../spinner.js");
20
+ // Set secret value
19
21
  const setting = createSpinner(` Setting "${args.name}"`).start();
20
22
  await Config.setSecret({
21
23
  key: args.name,
@@ -23,9 +25,24 @@ export const set = (program) => program.command("set <name> <value>", "Set the v
23
25
  fallback: args.fallback === true,
24
26
  });
25
27
  setting.succeed();
26
- const restarting = createSpinner(` Restarting all functions using ${blue(args.name)}...`).start();
27
- const count = await Config.restart(args.name);
28
- restarting.succeed(count === 1
29
- ? ` Restarted ${count} function`
30
- : ` Restarted ${count} functions`);
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`);
37
+ }
38
+ const functionCount = functions.length;
39
+ if (functionCount > 0) {
40
+ Colors.line(Colors.success(`✔ `), functionCount === 1
41
+ ? `Reloaded ${functionCount} function`
42
+ : `Reloaded ${functionCount} functions`);
43
+ }
44
+ edgeSites.forEach(({ id, type }) => {
45
+ Colors.line(Colors.danger(`➜ `), `Redeploy the "${id}" ${type} to use the new secret`);
46
+ });
47
+ process.exit(0);
31
48
  });
package/cli/sst.js CHANGED
@@ -13,7 +13,6 @@ dotenv.config({
13
13
  override: true,
14
14
  });
15
15
  import { bootstrap } from "./commands/bootstrap.js";
16
- import { env } from "./commands/env.js";
17
16
  import { dev } from "./commands/dev.js";
18
17
  import { bind } from "./commands/bind.js";
19
18
  import { build } from "./commands/build.js";
@@ -31,7 +30,6 @@ dev(program);
31
30
  deploy(program);
32
31
  build(program);
33
32
  bind(program);
34
- env(program);
35
33
  secrets(program);
36
34
  remove(program);
37
35
  update(program);
@@ -1,4 +1,4 @@
1
- /// <reference types="react" />
1
+ /// <reference types="react" resolution-mode="require"/>
2
2
  import { Stacks } from "../../stacks/index.js";
3
3
  import type { CloudAssembly } from "aws-cdk-lib/cx-api";
4
4
  interface Props {
package/cli/ui/deploy.js CHANGED
@@ -71,13 +71,10 @@ export function printDeploymentResults(assembly, results, remove) {
71
71
  Colors.gap();
72
72
  Colors.line(Colors.success(`✔`), Colors.bold(remove ? ` Removed:` : ` Deployed:`));
73
73
  for (const [stack, result] of success) {
74
- const outputs = Object.entries(result.outputs).filter(([key, _]) => !key.includes("SstSiteEnv"));
75
74
  Colors.line(` ${Colors.dim(stackNameToId(stack))}`);
76
- if (outputs.length > 0) {
77
- for (const key of Object.keys(Object.fromEntries(outputs)).sort()) {
78
- const value = result.outputs[key];
79
- Colors.line(` ${Colors.bold.dim(key + ":")} ${value}`);
80
- }
75
+ for (const key of Object.keys(result.outputs).sort()) {
76
+ const value = result.outputs[key];
77
+ Colors.line(` ${Colors.bold.dim(key + ":")} ${value}`);
81
78
  }
82
79
  }
83
80
  Colors.gap();
@@ -1,2 +1,2 @@
1
- /// <reference types="react" />
1
+ /// <reference types="react" resolution-mode="require"/>
2
2
  export declare function Functions(): JSX.Element;
package/config.d.ts CHANGED
@@ -1,3 +1,11 @@
1
+ import { FunctionMetadata, SsrSiteMetadata } from "./constructs/Metadata.js";
2
+ declare module "./bus.js" {
3
+ interface Events {
4
+ "config.secret.updated": {
5
+ name: string;
6
+ };
7
+ }
8
+ }
1
9
  interface Secret {
2
10
  value?: string;
3
11
  fallback?: string;
@@ -38,6 +46,11 @@ export declare namespace Config {
38
46
  key: string;
39
47
  fallback?: boolean;
40
48
  }): Promise<void>;
41
- function restart(key: string): Promise<number>;
49
+ function restart(key: string): Promise<{
50
+ edgeSites: SsrSiteMetadata[];
51
+ sites: SsrSiteMetadata[];
52
+ placeholderSites: SsrSiteMetadata[];
53
+ functions: FunctionMetadata[];
54
+ }>;
42
55
  }
43
56
  export {};
package/config.js CHANGED
@@ -3,6 +3,7 @@ import { GetFunctionConfigurationCommand, LambdaClient, UpdateFunctionConfigurat
3
3
  import { pipe, map } from "remeda";
4
4
  import { useProject } from "./project.js";
5
5
  import { useAWSClient } from "./credentials.js";
6
+ import { useIOT } from "./iot.js";
6
7
  import { Stacks } from "./stacks/index.js";
7
8
  export var Config;
8
9
  (function (Config) {
@@ -71,7 +72,7 @@ export var Config;
71
72
  Config.env = env;
72
73
  async function setSecret(input) {
73
74
  const ssm = useAWSClient(SSMClient);
74
- const result = await ssm.send(new PutParameterCommand({
75
+ await ssm.send(new PutParameterCommand({
75
76
  Name: pathFor({
76
77
  id: input.key,
77
78
  type: "Secret",
@@ -82,6 +83,10 @@ export var Config;
82
83
  Type: "SecureString",
83
84
  Overwrite: true,
84
85
  }));
86
+ // Publish event
87
+ const iot = await useIOT();
88
+ const topic = `${iot.prefix}/events`;
89
+ await iot.publish(topic, "config.secret.updated", { name: input.key });
85
90
  }
86
91
  Config.setSecret = setSecret;
87
92
  async function getSecret(input) {
@@ -111,38 +116,44 @@ export var Config;
111
116
  }
112
117
  Config.removeSecret = removeSecret;
113
118
  async function restart(key) {
114
- const lambda = useAWSClient(LambdaClient);
115
119
  const metadata = await Stacks.metadata();
116
- const filtered = Object.values(metadata)
120
+ const siteData = Object.values(metadata)
117
121
  .flat()
118
- .filter((f) => f.type === "Function")
119
- .filter((f) => f.data.secrets.includes(key));
120
- const restarted = await Promise.all(filtered.map(async (f) => {
121
- // Note: in the case where the function is removed, but the metadata
122
- // is not updated, we ignore the Function not found error.
123
- try {
124
- const config = await lambda.send(new GetFunctionConfigurationCommand({
125
- FunctionName: f.data.arn,
126
- }));
127
- await lambda.send(new UpdateFunctionConfigurationCommand({
128
- FunctionName: f.data.arn,
129
- Environment: {
130
- Variables: {
131
- ...(config.Environment?.Variables || {}),
132
- [SECRET_UPDATED_AT_ENV]: Date.now().toString(),
133
- },
134
- },
135
- }));
136
- return true;
137
- }
138
- catch (e) {
139
- if (e.name === "ResourceNotFoundException" &&
140
- e.message.startsWith("Function not found")) {
141
- return;
142
- }
143
- }
144
- }));
145
- return restarted.filter(Boolean).length;
122
+ .filter((c) => c.type === "AstroSite" ||
123
+ c.type === "NextjsSite" ||
124
+ c.type === "RemixSite" ||
125
+ c.type === "SolidStartSite")
126
+ .filter((c) => c.data.secrets.includes(key));
127
+ const siteDataPlaceholder = siteData.filter((c) => c.data.mode === "placeholder");
128
+ const siteDataEdge = siteData
129
+ .filter((c) => c.data.mode === "deployed")
130
+ .filter((c) => c.data.edge);
131
+ const siteDataRegional = siteData
132
+ .filter((c) => c.data.mode === "deployed")
133
+ .filter((c) => !c.data.edge);
134
+ const regionalSiteArns = siteData.map((s) => s.data.server);
135
+ const functionData = Object.values(metadata)
136
+ .flat()
137
+ .filter((c) => c.type === "Function")
138
+ // filter out SSR functions for sites
139
+ .filter((c) => !regionalSiteArns.includes(c.data.arn))
140
+ .filter((c) => c.data.secrets.includes(key));
141
+ // Restart sites
142
+ const restartedSites = (await Promise.all(siteDataRegional.map(async (s) => {
143
+ const restarted = await restartFunction(s.data.server);
144
+ return restarted ? s : restarted;
145
+ }))).filter((c) => Boolean(c));
146
+ // Restart functions
147
+ const restartedFunctions = (await Promise.all(functionData.map(async (f) => {
148
+ const restarted = await restartFunction(f.data.arn);
149
+ return restarted ? f : restarted;
150
+ }))).filter((c) => Boolean(c));
151
+ return {
152
+ edgeSites: siteDataEdge,
153
+ sites: restartedSites,
154
+ placeholderSites: siteDataPlaceholder,
155
+ functions: restartedFunctions,
156
+ };
146
157
  }
147
158
  Config.restart = restart;
148
159
  })(Config || (Config = {}));
@@ -182,3 +193,29 @@ function parse(ssmName) {
182
193
  prop: parts.slice(6).join("/"),
183
194
  };
184
195
  }
196
+ async function restartFunction(arn) {
197
+ const lambda = useAWSClient(LambdaClient);
198
+ // Note: in the case where the function is removed, but the metadata
199
+ // is not updated, we ignore the Function not found error.
200
+ try {
201
+ const config = await lambda.send(new GetFunctionConfigurationCommand({
202
+ FunctionName: arn,
203
+ }));
204
+ await lambda.send(new UpdateFunctionConfigurationCommand({
205
+ FunctionName: arn,
206
+ Environment: {
207
+ Variables: {
208
+ ...(config.Environment?.Variables || {}),
209
+ [SECRET_UPDATED_AT_ENV]: Date.now().toString(),
210
+ },
211
+ },
212
+ }));
213
+ return true;
214
+ }
215
+ catch (e) {
216
+ if (e.name === "ResourceNotFoundException" &&
217
+ e.message.startsWith("Function not found")) {
218
+ return;
219
+ }
220
+ }
221
+ }
@@ -50,7 +50,7 @@ export declare class App extends CDKApp {
50
50
  */
51
51
  readonly mode: AppDeployProps["mode"];
52
52
  /**
53
- * The name of your app, comes from the `name` in your `sst.json`
53
+ * The name of your app, comes from the `name` in your `sst.config.ts`
54
54
  */
55
55
  readonly name: string;
56
56
  /**
@@ -58,7 +58,7 @@ export declare class App extends CDKApp {
58
58
  */
59
59
  readonly stage: string;
60
60
  /**
61
- * The region the app is being deployed to. If this is not specified as the --region option in the SST CLI, it'll default to the region in your sst.json.
61
+ * The region the app is being deployed to. If this is not specified as the --region option in the SST CLI, it'll default to the region in your sst.config.ts.
62
62
  */
63
63
  readonly region: string;
64
64
  /**
package/constructs/App.js CHANGED
@@ -11,7 +11,6 @@ import { useDeferredTasks } from "./deferred_task.js";
11
11
  import { AppContext } from "./context.js";
12
12
  import { useProject } from "../project.js";
13
13
  import { Logger } from "../logger.js";
14
- import { SiteEnv } from "../site-env.js";
15
14
  import { App as CDKApp, Tags, CfnResource, RemovalPolicy, CustomResourceProvider, CustomResourceProviderRuntime, CustomResource, Aspects, } from "aws-cdk-lib";
16
15
  import { CfnFunction } from "aws-cdk-lib/aws-lambda";
17
16
  import { Bucket } from "aws-cdk-lib/aws-s3";
@@ -35,7 +34,7 @@ export class App extends CDKApp {
35
34
  */
36
35
  mode;
37
36
  /**
38
- * The name of your app, comes from the `name` in your `sst.json`
37
+ * The name of your app, comes from the `name` in your `sst.config.ts`
39
38
  */
40
39
  name;
41
40
  /**
@@ -43,7 +42,7 @@ export class App extends CDKApp {
43
42
  */
44
43
  stage;
45
44
  /**
46
- * The region the app is being deployed to. If this is not specified as the --region option in the SST CLI, it'll default to the region in your sst.json.
45
+ * The region the app is being deployed to. If this is not specified as the --region option in the SST CLI, it'll default to the region in your sst.config.ts.
47
46
  */
48
47
  region;
49
48
  /**
@@ -71,7 +70,6 @@ export class App extends CDKApp {
71
70
  constructor(deployProps, props = {}) {
72
71
  super(props);
73
72
  AppContext.provide(this);
74
- SiteEnv.reset();
75
73
  this.appPath = process.cwd();
76
74
  this.mode = deployProps.mode;
77
75
  this.local = this.mode === "dev";
@@ -14,6 +14,7 @@ import { EdgeFunction } from "./EdgeFunction.js";
14
14
  */
15
15
  export declare class AstroSite extends SsrSite {
16
16
  protected initBuildConfig(): {
17
+ typesPath: string;
17
18
  serverBuildOutputFile: string;
18
19
  clientBuildOutputDir: string;
19
20
  clientBuildVersionedSubDir: string;
@@ -18,6 +18,7 @@ import { EdgeFunction } from "./EdgeFunction.js";
18
18
  export class AstroSite extends SsrSite {
19
19
  initBuildConfig() {
20
20
  return {
21
+ typesPath: "src",
21
22
  serverBuildOutputFile: "dist/server/entry.mjs",
22
23
  clientBuildOutputDir: "dist/client",
23
24
  clientBuildVersionedSubDir: "assets",
@@ -513,7 +513,7 @@ export interface JavaProps {
513
513
  */
514
514
  export interface FunctionCopyFilesProps {
515
515
  /**
516
- * Source path relative to sst.json
516
+ * Source path relative to sst.config.ts
517
517
  */
518
518
  from: string;
519
519
  /**
@@ -24,10 +24,14 @@ import type { KinesisStream } from "./KinesisStream.js";
24
24
  export type KinesisStreamMetadata = ExtractMetadata<KinesisStream>;
25
25
  import type { NextjsSite } from "./NextjsSite.js";
26
26
  export type NextjsMetadata = ExtractMetadata<NextjsSite>;
27
+ import type { NextjsSite as SlsNextjsSite } from "./deprecated/NextjsSite.js";
28
+ export type SlsNextjsMetadata = ExtractMetadata<SlsNextjsSite>;
27
29
  import type { Queue } from "./Queue.js";
28
30
  export type QueueMetadata = ExtractMetadata<Queue>;
29
31
  import type { StaticSite } from "./StaticSite.js";
30
32
  export type StaticSiteMetadata = ExtractMetadata<StaticSite>;
33
+ import type { SsrSite } from "./SsrSite.js";
34
+ export type SsrSiteMetadata = ExtractMetadata<SsrSite>;
31
35
  import type { Table } from "./Table.js";
32
36
  export type TableMetadata = ExtractMetadata<Table>;
33
37
  import type { Topic } from "./Topic.js";
@@ -36,5 +40,5 @@ import type { WebSocketApi } from "./WebSocketApi.js";
36
40
  export type WebSocketApiMetadata = ExtractMetadata<WebSocketApi>;
37
41
  import type { RDS } from "./RDS.js";
38
42
  export type RDSMetadata = ExtractMetadata<RDS>;
39
- export type Metadata = ApiMetadata | ApiGatewayV1ApiMetadata | AuthMetadata | AppSyncApiMetadata | BucketMetadata | CronMetadata | EventBusMetadata | FunctionMetadata | KinesisStreamMetadata | NextjsMetadata | QueueMetadata | StaticSiteMetadata | TableMetadata | TopicMetadata | WebSocketApiMetadata | RDSMetadata;
43
+ export type Metadata = ApiMetadata | ApiGatewayV1ApiMetadata | AuthMetadata | AppSyncApiMetadata | BucketMetadata | CronMetadata | EventBusMetadata | FunctionMetadata | KinesisStreamMetadata | NextjsMetadata | SlsNextjsMetadata | QueueMetadata | StaticSiteMetadata | SsrSiteMetadata | TableMetadata | TopicMetadata | WebSocketApiMetadata | RDSMetadata;
40
44
  export {};
@@ -37,6 +37,7 @@ export declare class NextjsSite extends SsrSite {
37
37
  };
38
38
  constructor(scope: Construct, id: string, props?: NextjsSiteProps);
39
39
  protected initBuildConfig(): {
40
+ typesPath: string;
40
41
  serverBuildOutputFile: string;
41
42
  clientBuildOutputDir: string;
42
43
  clientBuildVersionedSubDir: string;
@@ -32,6 +32,7 @@ export class NextjsSite extends SsrSite {
32
32
  }
33
33
  initBuildConfig() {
34
34
  return {
35
+ typesPath: ".",
35
36
  serverBuildOutputFile: ".open-next/server-function/index.mjs",
36
37
  clientBuildOutputDir: ".open-next/assets",
37
38
  clientBuildVersionedSubDir: "_next",
@@ -16,6 +16,7 @@ import { EdgeFunction } from "./EdgeFunction.js";
16
16
  */
17
17
  export declare class RemixSite extends SsrSite {
18
18
  protected initBuildConfig(): {
19
+ typesPath: string;
19
20
  serverBuildOutputFile: string;
20
21
  clientBuildOutputDir: string;
21
22
  clientBuildVersionedSubDir: string;
@@ -49,6 +49,7 @@ export class RemixSite extends SsrSite {
49
49
  }
50
50
  });
51
51
  return {
52
+ typesPath: ".",
52
53
  serverBuildOutputFile: "build/index.js",
53
54
  clientBuildOutputDir: "public",
54
55
  clientBuildVersionedSubDir: "build",