sst 2.0.0-rc.9 → 2.0.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.
Files changed (242) hide show
  1. package/bootstrap.d.ts +2 -4
  2. package/bootstrap.js +208 -61
  3. package/bus.d.ts +3 -3
  4. package/bus.js +1 -1
  5. package/cache.js +1 -1
  6. package/cdk/cloudformation-deployments-wrapper.d.ts +3 -0
  7. package/cdk/cloudformation-deployments-wrapper.js +117 -0
  8. package/cdk/cloudformation-deployments.d.ts +19 -4
  9. package/cdk/deploy-stack.d.ts +17 -2
  10. package/cdk/deploy-stack.js +6 -1
  11. package/cli/colors.d.ts +28 -0
  12. package/cli/colors.js +27 -0
  13. package/cli/commands/bind.d.ts +4 -0
  14. package/cli/commands/bind.js +10 -7
  15. package/cli/commands/bootstrap.d.ts +13 -0
  16. package/cli/commands/bootstrap.js +11 -0
  17. package/cli/commands/build.d.ts +6 -2
  18. package/cli/commands/build.js +13 -8
  19. package/cli/commands/console.d.ts +5 -1
  20. package/cli/commands/console.js +8 -6
  21. package/cli/commands/deploy.d.ts +4 -2
  22. package/cli/commands/deploy.js +69 -29
  23. package/cli/commands/dev.d.ts +5 -1
  24. package/cli/commands/dev.js +157 -79
  25. package/cli/commands/diff.d.ts +15 -0
  26. package/cli/commands/diff.js +61 -0
  27. package/cli/commands/env.d.ts +5 -1
  28. package/cli/commands/env.js +14 -15
  29. package/cli/commands/plugins/kysely.js +13 -5
  30. package/cli/commands/plugins/pothos.js +9 -4
  31. package/cli/commands/remove.d.ts +4 -0
  32. package/cli/commands/remove.js +26 -18
  33. package/cli/commands/secrets/get.d.ts +7 -3
  34. package/cli/commands/secrets/get.js +11 -24
  35. package/cli/commands/secrets/list.d.ts +6 -2
  36. package/cli/commands/secrets/list.js +15 -7
  37. package/cli/commands/secrets/remove.d.ts +8 -4
  38. package/cli/commands/secrets/remove.js +18 -16
  39. package/cli/commands/secrets/secrets.js +3 -3
  40. package/cli/commands/secrets/set.d.ts +8 -6
  41. package/cli/commands/secrets/set.js +16 -33
  42. package/cli/commands/telemetry.d.ts +15 -0
  43. package/cli/commands/telemetry.js +17 -0
  44. package/cli/commands/transform.d.ts +15 -0
  45. package/cli/commands/transform.js +55 -0
  46. package/cli/commands/update.d.ts +6 -2
  47. package/cli/commands/update.js +41 -33
  48. package/cli/commands/version.d.ts +13 -0
  49. package/cli/commands/version.js +7 -0
  50. package/cli/local/router.d.ts +6 -6
  51. package/cli/local/router.js +3 -3
  52. package/cli/local/server.d.ts +5 -3
  53. package/cli/local/server.js +21 -14
  54. package/cli/program.d.ts +5 -1
  55. package/cli/program.js +29 -5
  56. package/cli/spinner.js +2 -0
  57. package/cli/sst.js +35 -23
  58. package/cli/telemetry/environment.d.ts +1 -1
  59. package/cli/telemetry/environment.js +1 -1
  60. package/cli/terminal.d.ts +1 -0
  61. package/cli/terminal.js +8 -0
  62. package/cli/ui/deploy.d.ts +3 -2
  63. package/cli/ui/deploy.js +106 -106
  64. package/cli/ui/functions.d.ts +2 -0
  65. package/cli/ui/functions.js +132 -0
  66. package/cli/ui/header.d.ts +5 -0
  67. package/cli/ui/header.js +16 -0
  68. package/cli/ui/stack.d.ts +1 -0
  69. package/cli/ui/stack.js +6 -0
  70. package/config.d.ts +1 -1
  71. package/config.js +8 -8
  72. package/constructs/Api.d.ts +3 -71
  73. package/constructs/Api.js +3 -42
  74. package/constructs/ApiGatewayV1Api.d.ts +3 -3
  75. package/constructs/ApiGatewayV1Api.js +4 -3
  76. package/constructs/App.d.ts +2 -22
  77. package/constructs/App.js +12 -25
  78. package/constructs/AppSyncApi.d.ts +4 -5
  79. package/constructs/AppSyncApi.js +8 -5
  80. package/constructs/AstroSite.d.ts +2 -3
  81. package/constructs/AstroSite.js +43 -53
  82. package/constructs/Auth.js +27 -16
  83. package/constructs/BaseSite.d.ts +10 -10
  84. package/constructs/BaseSite.js +2 -2
  85. package/constructs/Cognito.js +28 -28
  86. package/constructs/EdgeFunction.d.ts +6 -4
  87. package/constructs/EdgeFunction.js +56 -59
  88. package/constructs/EventBus.js +1 -1
  89. package/constructs/Function.d.ts +4 -44
  90. package/constructs/Function.js +14 -50
  91. package/constructs/FunctionalStack.d.ts +2 -2
  92. package/constructs/Job.d.ts +23 -63
  93. package/constructs/Job.js +11 -32
  94. package/constructs/Metadata.d.ts +18 -20
  95. package/constructs/NextjsSite.d.ts +21 -5
  96. package/constructs/NextjsSite.js +67 -101
  97. package/constructs/Queue.js +10 -10
  98. package/constructs/RDS.d.ts +1 -1
  99. package/constructs/RDS.js +1 -1
  100. package/constructs/RemixSite.d.ts +0 -2
  101. package/constructs/RemixSite.js +20 -20
  102. package/constructs/Script.js +1 -1
  103. package/constructs/Secret.js +5 -3
  104. package/constructs/SolidStartSite.d.ts +2 -3
  105. package/constructs/SolidStartSite.js +42 -52
  106. package/constructs/SsrFunction.d.ts +22 -0
  107. package/constructs/SsrFunction.js +113 -0
  108. package/constructs/SsrSite.d.ts +104 -104
  109. package/constructs/SsrSite.js +196 -217
  110. package/constructs/Stack.d.ts +1 -20
  111. package/constructs/Stack.js +3 -65
  112. package/constructs/StaticSite.d.ts +33 -53
  113. package/constructs/StaticSite.js +92 -118
  114. package/constructs/Table.d.ts +1 -1
  115. package/constructs/Table.js +4 -4
  116. package/constructs/Topic.js +1 -1
  117. package/constructs/cdk/certificate-base.d.ts +18 -0
  118. package/constructs/cdk/certificate-base.js +26 -0
  119. package/constructs/cdk/dns-validated-certificate.d.ts +77 -0
  120. package/constructs/cdk/dns-validated-certificate.js +125 -0
  121. package/constructs/cdk/website-redirect.d.ts +53 -0
  122. package/constructs/cdk/website-redirect.js +77 -0
  123. package/constructs/deferred_task.d.ts +1 -1
  124. package/constructs/deprecated/NextjsSite.js +8 -6
  125. package/constructs/index.d.ts +0 -6
  126. package/constructs/index.js +0 -6
  127. package/constructs/util/apiGatewayV1AccessLog.d.ts +1 -1
  128. package/constructs/util/apiGatewayV2AccessLog.js +4 -4
  129. package/constructs/util/apiGatewayV2Domain.js +9 -2
  130. package/constructs/util/appSyncApiDomain.d.ts +1 -1
  131. package/constructs/util/appSyncApiDomain.js +9 -15
  132. package/constructs/util/duration.d.ts +1 -1
  133. package/constructs/util/functionBinding.js +1 -1
  134. package/constructs/util/permission.d.ts +3 -3
  135. package/constructs/util/permission.js +16 -18
  136. package/constructs/util/size.d.ts +1 -1
  137. package/constructs/util/warning.js +2 -2
  138. package/context/context.d.ts +2 -2
  139. package/context/context.js +4 -4
  140. package/context/handler.d.ts +1 -1
  141. package/credentials.d.ts +1 -1
  142. package/credentials.js +42 -6
  143. package/index.d.ts +1 -0
  144. package/index.js +1 -0
  145. package/iot.js +6 -2
  146. package/logger.js +3 -1
  147. package/node/api/index.d.ts +2 -3
  148. package/node/api/index.js +8 -2
  149. package/node/auth/adapter/adapter.d.ts +1 -1
  150. package/node/auth/adapter/facebook.js +1 -1
  151. package/node/auth/adapter/github.js +4 -4
  152. package/node/auth/adapter/google.d.ts +1 -1
  153. package/node/auth/adapter/google.js +2 -2
  154. package/node/auth/adapter/twitch.js +1 -1
  155. package/node/auth/session.d.ts +1 -1
  156. package/node/config/index.d.ts +2 -2
  157. package/node/config/index.js +3 -8
  158. package/node/job/index.d.ts +2 -2
  159. package/node/site/index.js +3 -5
  160. package/package.json +26 -21
  161. package/pothos.js +1 -0
  162. package/project.d.ts +47 -0
  163. package/{app.js → project.js} +60 -53
  164. package/runtime/handlers/dotnet.d.ts +1 -1
  165. package/runtime/handlers/dotnet.js +4 -4
  166. package/runtime/handlers/go.d.ts +1 -1
  167. package/runtime/handlers/go.js +3 -3
  168. package/runtime/handlers/java.d.ts +1 -1
  169. package/runtime/handlers/java.js +4 -4
  170. package/runtime/handlers/node.d.ts +1 -1
  171. package/runtime/handlers/node.js +60 -39
  172. package/runtime/handlers/python.d.ts +1 -1
  173. package/runtime/handlers/python.js +3 -3
  174. package/runtime/handlers.js +15 -12
  175. package/runtime/iot.js +3 -0
  176. package/runtime/runtime.d.ts +4 -0
  177. package/runtime/server.d.ts +3 -3
  178. package/runtime/server.js +11 -5
  179. package/runtime/workers.d.ts +4 -2
  180. package/runtime/workers.js +13 -3
  181. package/site-env.js +2 -1
  182. package/sst.mjs +6357 -20848
  183. package/stacks/app-metadata.d.ts +7 -0
  184. package/stacks/app-metadata.js +78 -0
  185. package/stacks/assembly.d.ts +1 -0
  186. package/stacks/assembly.js +4 -0
  187. package/stacks/build.d.ts +1 -1
  188. package/stacks/build.js +41 -48
  189. package/stacks/deploy.d.ts +1 -0
  190. package/stacks/deploy.js +128 -7
  191. package/stacks/diff.d.ts +8 -0
  192. package/stacks/diff.js +62 -0
  193. package/stacks/index.d.ts +3 -0
  194. package/stacks/index.js +3 -0
  195. package/stacks/metadata.d.ts +2 -0
  196. package/stacks/metadata.js +14 -12
  197. package/stacks/monitor.d.ts +8 -3
  198. package/stacks/monitor.js +38 -4
  199. package/stacks/remove.js +0 -4
  200. package/stacks/synth.d.ts +1 -0
  201. package/stacks/synth.js +27 -13
  202. package/support/base-site-archiver.mjs +1 -1
  203. package/support/bootstrap-metadata-function/index.mjs +68740 -0
  204. package/support/bridge/bridge.mjs +28 -28
  205. package/support/certificate-requestor/index.js +549 -0
  206. package/support/custom-resources/index.mjs +3824 -26567
  207. package/support/dotnet6-bootstrap/release/dotnet-bootstrap.deps.json +1 -1
  208. package/support/dotnet6-bootstrap/release/dotnet-bootstrap.runtimeconfig.json +1 -1
  209. package/support/edge-function/edge-lambda.mjs +2 -2
  210. package/support/job-invoker/index.mjs +26 -0
  211. package/support/nodejs-runtime/index.mjs +75 -72
  212. package/support/rds-migrator/index.mjs +22 -23
  213. package/support/remix-site-function/edge-server.js +1 -1
  214. package/support/script-function/index.mjs +30485 -0
  215. package/support/{edge-function-code-replacer → sls-nextjs-site-function-code-replacer}/lambda-code-updater.py +0 -0
  216. package/support/ssr-site-function-archiver.mjs +96 -0
  217. package/watcher.js +1 -1
  218. package/app.d.ts +0 -36
  219. package/constructs/DebugApp.d.ts +0 -49
  220. package/constructs/DebugApp.js +0 -63
  221. package/constructs/DebugStack.d.ts +0 -34
  222. package/constructs/DebugStack.js +0 -132
  223. package/constructs/GraphQLApi.d.ts +0 -98
  224. package/constructs/GraphQLApi.js +0 -80
  225. package/constructs/ReactStaticSite.d.ts +0 -20
  226. package/constructs/ReactStaticSite.js +0 -54
  227. package/constructs/Script/cfn-response.d.ts +0 -19
  228. package/constructs/Script/cfn-response.js +0 -77
  229. package/constructs/Script/index.d.ts +0 -1
  230. package/constructs/Script/index.js +0 -78
  231. package/constructs/Script/outbound.d.ts +0 -10
  232. package/constructs/Script/outbound.js +0 -42
  233. package/constructs/Script/util.d.ts +0 -2
  234. package/constructs/Script/util.js +0 -11
  235. package/constructs/ViteStaticSite.d.ts +0 -32
  236. package/constructs/ViteStaticSite.js +0 -66
  237. package/support/astro-site-html-stub/index.html +0 -99
  238. package/support/base-site-archiver.cjs +0 -116
  239. package/support/nextjs-site-html-stub/index.html +0 -99
  240. package/support/remix-site-html-stub/index.html +0 -99
  241. package/support/solid-start-site-html-stub/index.html +0 -99
  242. package/support/static-site-stub/index.html +0 -90
@@ -1,23 +1,26 @@
1
- import { useProject } from "../../app.js";
2
- export const bind = (program) => program.command("bind <command>", "Binds blah", (yargs) => yargs.positional("command", {
1
+ export const bind = (program) => program.command("bind <command>", "Bind your app's resources to a command", (yargs) => yargs
2
+ .positional("command", {
3
3
  type: "string",
4
- describe: "Command to bind to",
4
+ describe: "The command to bind to",
5
5
  demandOption: true,
6
- }), async (args) => {
6
+ })
7
+ .example(`sst bind "vitest run"`, "Bind your resources to your tests")
8
+ .example(`sst bind "tsx scripts/myscript.ts"`, "Bind your resources to a script"), async (args) => {
7
9
  const { Config } = await import("../../config.js");
8
- const { spawnSync, spawn } = await import("child_process");
10
+ const { spawnSync } = await import("child_process");
9
11
  const { useAWSCredentials } = await import("../../credentials.js");
12
+ const { useProject } = await import("../../project.js");
10
13
  const env = await Config.env();
11
14
  const project = useProject();
12
15
  const credentials = await useAWSCredentials();
13
16
  const result = spawnSync(args.command, {
14
17
  env: {
18
+ ...process.env,
15
19
  ...env,
16
20
  AWS_ACCESS_KEY_ID: credentials.accessKeyId,
17
21
  AWS_SECRET_ACCESS_KEY: credentials.secretAccessKey,
18
22
  AWS_SESSION_TOKEN: credentials.sessionToken,
19
- AWS_REGION: project.region,
20
- PATH: process.env.PATH,
23
+ AWS_REGION: project.config.region,
21
24
  },
22
25
  stdio: "inherit",
23
26
  shell: process.env.SHELL || true,
@@ -0,0 +1,13 @@
1
+ /// <reference types="yargs" />
2
+ import type { Program } from "../program.js";
3
+ export declare const bootstrap: (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
+ }>;
@@ -0,0 +1,11 @@
1
+ export const bootstrap = (program) => program.command("bootstrap", "Create the SST bootstrap stack", (yargs) => yargs, async () => {
2
+ const { Colors } = await import("../colors.js");
3
+ const { useProject } = await import("../../project.js");
4
+ const { useBootstrap } = await import("../../bootstrap.js");
5
+ const { useSTSIdentity } = await import("../../credentials.js");
6
+ const project = useProject();
7
+ const identity = await useSTSIdentity();
8
+ await useBootstrap();
9
+ Colors.line(Colors.success(`✔`), Colors.bold(` Bootstrapped account ${identity.Account} in region ${project.config.region}`));
10
+ process.exit(0);
11
+ });
@@ -1,5 +1,5 @@
1
1
  /// <reference types="yargs" />
2
- import { Program } from "../program.js";
2
+ import type { Program } from "../program.js";
3
3
  export declare const build: (program: Program) => import("yargs").Argv<{
4
4
  stage: string | undefined;
5
5
  } & {
@@ -7,5 +7,9 @@ export declare const build: (program: Program) => import("yargs").Argv<{
7
7
  } & {
8
8
  region: string | undefined;
9
9
  } & {
10
- from: string | undefined;
10
+ verbose: boolean | undefined;
11
+ } & {
12
+ role: string | undefined;
13
+ } & {
14
+ to: string | undefined;
11
15
  }>;
@@ -1,12 +1,17 @@
1
- import { createSpinner } from "../spinner.js";
2
- export const build = (program) => program.command("build", "Build stacks code", yargs => yargs.option("from", { type: "string" }), async () => {
1
+ export const build = (program) => program.command("build", "Build your app", (yargs) => yargs.option("to", {
2
+ type: "string",
3
+ describe: "Output directory, defaults to .sst/dist",
4
+ }), async (args) => {
5
+ const { useProject } = await import("../../project.js");
3
6
  const { Stacks } = await import("../../stacks/index.js");
4
- const spinner = createSpinner("Building stacks").start();
5
- const fn = await Stacks.build();
6
- await Stacks.synth({
7
- fn,
8
- mode: "deploy"
7
+ const { Colors } = await import("../colors.js");
8
+ const path = await import("path");
9
+ const result = await Stacks.synth({
10
+ fn: useProject().stacks,
11
+ buildDir: args.to,
12
+ mode: "deploy",
9
13
  });
10
- spinner.succeed();
14
+ Colors.line("");
15
+ Colors.line(Colors.success(`✔`), Colors.bold(" Built:"), `${result.stacks.length} stack${result.stacks.length > 1 ? "s" : ""} to ${path.relative(process.cwd(), result.directory)}`);
11
16
  process.exit(0);
12
17
  });
@@ -1,9 +1,13 @@
1
1
  /// <reference types="yargs" />
2
- import { Program } from "../program.js";
2
+ import type { Program } from "../program.js";
3
3
  export declare const consoleCommand: (program: Program) => Promise<import("yargs").Argv<{
4
4
  stage: string | undefined;
5
5
  } & {
6
6
  profile: string | undefined;
7
7
  } & {
8
8
  region: string | undefined;
9
+ } & {
10
+ verbose: boolean | undefined;
11
+ } & {
12
+ role: string | undefined;
9
13
  }>>;
@@ -1,15 +1,17 @@
1
- import { blue } from "colorette";
2
- import { useRuntimeServer } from "../../runtime/server.js";
3
- import { useLocalServer } from "../local/server.js";
4
- export const consoleCommand = async (program) => program.command("console", "Start the sst console", (yargs) => yargs, async () => {
1
+ export const consoleCommand = async (program) => program.command("console", "Start the SST Console", (yargs) => yargs, async () => {
2
+ const { blue } = await import("colorette");
3
+ const { useRuntimeServer } = await import("../../runtime/server.js");
4
+ const { useLocalServer } = await import("../local/server.js");
5
+ const { printHeader } = await import("../ui/header.js");
6
+ const { clear } = await import("../terminal.js");
5
7
  await Promise.all([
6
8
  useRuntimeServer(),
7
9
  useLocalServer({
8
10
  key: "",
9
11
  cert: "",
10
12
  live: false,
11
- port: 13557,
12
13
  }),
13
14
  ]);
14
- console.log(`Console started: ${blue(`https://console.sst.dev`)}`);
15
+ clear();
16
+ printHeader({ console: true, hint: "ready!" });
15
17
  });
@@ -7,9 +7,11 @@ export declare const deploy: (program: Program) => import("yargs").Argv<{
7
7
  } & {
8
8
  region: string | undefined;
9
9
  } & {
10
- from: string | undefined;
10
+ verbose: boolean | undefined;
11
+ } & {
12
+ role: string | undefined;
11
13
  } & {
12
- fullscreen: boolean;
14
+ from: string | undefined;
13
15
  } & {
14
16
  filter: string | undefined;
15
17
  }>;
@@ -1,50 +1,90 @@
1
- import { printDeploymentResults } from "../ui/deploy.js";
2
- export const deploy = (program) => program.command("deploy [filter]", "Work on your SST app locally", (yargs) => yargs
3
- .option("from", { type: "string" })
4
- .option("fullscreen", {
5
- type: "boolean",
6
- describe: "Disable full screen UI",
7
- default: true,
1
+ import { useSTSIdentity } from "../../credentials.js";
2
+ import { Colors } from "../colors.js";
3
+ import fs from "fs/promises";
4
+ import path from "path";
5
+ export const deploy = (program) => program.command("deploy [filter]", "Deploy your app to AWS", (yargs) => yargs
6
+ .option("from", {
7
+ type: "string",
8
+ describe: "Deploy using previously built output",
8
9
  })
9
- .positional("filter", { type: "string" }), async (args) => {
10
+ .positional("filter", {
11
+ type: "string",
12
+ describe: "Optionally filter stacks to deploy",
13
+ }), async (args) => {
10
14
  const React = await import("react");
11
- const { CloudAssembly } = await import("aws-cdk-lib/cx-api");
12
- const { blue, bold } = await import("colorette");
13
- const { useProject } = await import("../../app.js");
14
- const { Stacks } = await import("../../stacks/index.js");
15
+ const { printDeploymentResults } = await import("../ui/deploy.js");
16
+ const { createSpinner } = await import("../spinner.js");
17
+ const { dim, blue, bold } = await import("colorette");
18
+ const { useProject } = await import("../../project.js");
19
+ const { loadAssembly, useAppMetadata, saveAppMetadata, Stacks } = await import("../../stacks/index.js");
15
20
  const { render } = await import("ink");
16
21
  const { DeploymentUI } = await import("../ui/deploy.js");
22
+ const { mapValues } = await import("remeda");
23
+ const project = useProject();
24
+ const [identity, appMetadata] = await Promise.all([
25
+ useSTSIdentity(),
26
+ useAppMetadata(),
27
+ ]);
28
+ // Check app mode changed
29
+ if (appMetadata && appMetadata.mode !== "deploy") {
30
+ if (!(await promptChangeMode())) {
31
+ process.exit(0);
32
+ }
33
+ }
34
+ Colors.line(`${Colors.primary.bold(`SST v${project.version}`)}`);
35
+ Colors.gap();
36
+ Colors.line(`${Colors.primary(`➜`)} ${Colors.bold("App:")} ${project.config.name}`);
37
+ Colors.line(` ${Colors.bold("Stage:")} ${project.config.stage}`);
38
+ Colors.line(` ${Colors.bold("Region:")} ${project.config.region}`);
39
+ Colors.line(` ${Colors.bold("Account:")} ${identity.Account}`);
40
+ Colors.gap();
41
+ // Generate cloud assembly
42
+ // - if --from is specified, we will use the existing cloud assembly
43
+ // - if --from is not specified, we will call synth to generate
17
44
  const assembly = await (async function () {
18
45
  if (args.from) {
19
- const result = new CloudAssembly(args.from);
46
+ const result = await loadAssembly(args.from);
20
47
  return result;
21
48
  }
22
- const fn = await Stacks.build();
23
- return await Stacks.synth({
24
- fn,
49
+ const spinner = createSpinner({
50
+ text: " Building...",
51
+ });
52
+ const result = await Stacks.synth({
53
+ fn: project.stacks,
25
54
  mode: "deploy",
26
55
  });
56
+ spinner.succeed();
57
+ return result;
27
58
  })();
28
- const project = useProject();
29
59
  const target = assembly.stacks.filter((s) => !args.filter ||
30
60
  s.stackName.toLowerCase().includes(args.filter.toLowerCase()));
31
61
  if (!target.length) {
32
- console.log(`No stacks found matching ${blue(args.filter)}`);
62
+ Colors.line(`No stacks found matching ${blue(args.filter)}`);
33
63
  process.exit(1);
34
- return;
35
- }
36
- console.log(`Deploying ${bold(target.length + " stacks")} for stage ${blue(project.stage)}...`);
37
- let component = undefined;
38
- if (args.fullscreen) {
39
- process.stdout.write("\x1b[?1049h");
40
- component = render(React.createElement(DeploymentUI, { stacks: assembly.stacks.map((s) => s.stackName) }));
41
64
  }
65
+ const component = render(React.createElement(DeploymentUI, { assembly: assembly }));
42
66
  const results = await Stacks.deployMany(target);
43
- if (component)
44
- component.unmount();
45
- process.stdout.write("\x1b[?1049l");
46
- printDeploymentResults(results);
67
+ component.clear();
68
+ component.unmount();
69
+ printDeploymentResults(assembly, results);
47
70
  if (Object.values(results).some((stack) => Stacks.isFailed(stack.status)))
48
71
  process.exit(1);
72
+ fs.writeFile(path.join(project.paths.out, "outputs.json"), JSON.stringify(mapValues(results, (val) => val.outputs), null, 2));
73
+ // Update app state
74
+ await saveAppMetadata({ mode: "deploy" });
49
75
  process.exit(0);
50
76
  });
77
+ async function promptChangeMode() {
78
+ const readline = await import("readline");
79
+ const rl = readline.createInterface({
80
+ input: process.stdin,
81
+ output: process.stdout,
82
+ });
83
+ return new Promise((resolve) => {
84
+ console.log("");
85
+ rl.question("You were previously running this stage in dev mode. It is recommended that you use a different stage for production. Read more here — https://docs.sst.dev/live-lambda-development\n\nAre you sure you want to deploy to this stage? (y/N) ", async (input) => {
86
+ rl.close();
87
+ resolve(input.trim() === "y");
88
+ });
89
+ });
90
+ }
@@ -7,5 +7,9 @@ export declare const dev: (program: Program) => import("yargs").Argv<{
7
7
  } & {
8
8
  region: string | undefined;
9
9
  } & {
10
- fullscreen: boolean;
10
+ verbose: boolean | undefined;
11
+ } & {
12
+ role: string | undefined;
13
+ } & {
14
+ "increase-timeout": boolean | undefined;
11
15
  }>;
@@ -1,81 +1,133 @@
1
- import path from "path";
2
- import fs from "fs/promises";
3
- import crypto from "crypto";
4
- import { printDeploymentResults } from "../ui/deploy.js";
5
- import { useFunctions } from "../../constructs/Function.js";
6
- import { dim, gray, yellow } from "colorette";
7
- import { useProject } from "../../app.js";
8
- import { SiteEnv } from "../../site-env.js";
9
- import { usePothosBuilder } from "./plugins/pothos.js";
10
- import { useKyselyTypeGenerator } from "./plugins/kysely.js";
11
- import { useRDSWarmer } from "./plugins/warmer.js";
12
- export const dev = (program) => program.command(["start", "dev"], "Work on your SST app locally", (yargs) => yargs.option("fullscreen", {
1
+ import { Colors } from "../colors.js";
2
+ import { printHeader } from "../ui/header.js";
3
+ import { mapValues, omitBy, pipe } from "remeda";
4
+ export const dev = (program) => program.command(["dev", "start"], "Work on your app locally", (yargs) => yargs.option("increase-timeout", {
13
5
  type: "boolean",
14
- describe: "Disable full screen UI",
15
- default: true,
6
+ description: "Increase function timeout",
16
7
  }), async (args) => {
17
8
  const { useRuntimeWorkers } = await import("../../runtime/workers.js");
18
9
  const { useIOTBridge } = await import("../../runtime/iot.js");
19
10
  const { useRuntimeServer } = await import("../../runtime/server.js");
20
11
  const { useBus } = await import("../../bus.js");
21
12
  const { useWatcher } = await import("../../watcher.js");
22
- const { Stacks } = await import("../../stacks/index.js");
13
+ const { useAppMetadata, saveAppMetadata, Stacks } = await import("../../stacks/index.js");
23
14
  const { Logger } = await import("../../logger.js");
24
15
  const { createSpinner } = await import("../spinner.js");
25
- const { bold, magenta, green, blue, red } = await import("colorette");
16
+ const { bold, dim, yellow } = await import("colorette");
26
17
  const { render } = await import("ink");
27
18
  const React = await import("react");
28
19
  const { Context } = await import("../../context/context.js");
29
- const { DeploymentUI } = await import("../ui/deploy.js");
20
+ const { printDeploymentResults, DeploymentUI } = await import("../ui/deploy.js");
30
21
  const { useLocalServer } = await import("../local/server.js");
22
+ const path = await import("path");
23
+ const fs = await import("fs/promises");
24
+ const crypto = await import("crypto");
25
+ const { useFunctions } = await import("../../constructs/Function.js");
26
+ const { SiteEnv } = await import("../../site-env.js");
27
+ const { usePothosBuilder } = await import("./plugins/pothos.js");
28
+ const { useKyselyTypeGenerator } = await import("./plugins/kysely.js");
29
+ const { useRDSWarmer } = await import("./plugins/warmer.js");
30
+ const { useProject } = await import("../../project.js");
31
+ const { useMetadata } = await import("../../stacks/metadata.js");
32
+ const { clear } = await import("../terminal.js");
31
33
  if (args._[0] === "start") {
32
34
  console.log(yellow(`Warning: ${bold(`sst start`)} has been renamed to ${bold(`sst dev`)}`));
33
35
  }
34
36
  const useFunctionLogger = Context.memo(async () => {
35
37
  const bus = useBus();
38
+ const colors = ["#01cdfe", "#ff71ce", "#05ffa1", "#b967ff"];
39
+ let index = 0;
40
+ const pending = new Map();
41
+ function prefix(requestID) {
42
+ const exists = pending.get(requestID);
43
+ if (exists) {
44
+ return Colors.hex(exists.color)(Colors.prefix);
45
+ }
46
+ pending.set(requestID, {
47
+ requestID,
48
+ started: Date.now(),
49
+ color: colors[index % colors.length],
50
+ });
51
+ index++;
52
+ return prefix(requestID);
53
+ }
54
+ function end(requestID) {
55
+ // index--;
56
+ // if (index < 0) index = colors.length - 1;
57
+ pending.delete(requestID);
58
+ }
36
59
  bus.subscribe("function.invoked", async (evt) => {
37
- console.log(bold(magenta(`Invoked `)), bold(useFunctions().fromID(evt.properties.functionID).handler));
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
+ prefix(evt.properties.requestID);
64
+ const { started } = pending.get(evt.properties.requestID);
65
+ for (let line of evt.properties.message.split("\n")) {
66
+ Colors.line(prefix(evt.properties.requestID), Colors.dim(("+" + (Date.now() - started) + "ms").padEnd(7)), Colors.dim(line));
67
+ }
38
68
  });
39
69
  bus.subscribe("function.build.success", async (evt) => {
40
- console.log(bold(gray(`Built `)), bold(useFunctions().fromID(evt.properties.functionID).handler));
70
+ const info = useFunctions().fromID(evt.properties.functionID);
71
+ if (!info.enableLiveDev)
72
+ return;
73
+ Colors.line(Colors.dim(Colors.prefix, "Built", info.handler));
41
74
  });
42
75
  bus.subscribe("function.build.failed", async (evt) => {
43
- console.log(bold(red(`Build failed `)), bold(useFunctions().fromID(evt.properties.functionID).handler));
44
- console.log(dim(evt.properties.errors.join("\n")));
45
- });
46
- bus.subscribe("worker.stdout", async (evt) => {
47
- const { message } = evt.properties;
48
- const lines = message.split("\n");
49
- for (let i = 0; i < lines.length; i++) {
50
- const line = lines[i];
51
- lines[i] = " " + line;
76
+ const info = useFunctions().fromID(evt.properties.functionID);
77
+ if (info.enableLiveDev === false)
78
+ return;
79
+ Colors.gap();
80
+ Colors.line(Colors.danger("✖ "), "Build failed", info.handler);
81
+ for (const line of evt.properties.errors) {
82
+ Colors.line(" ", line);
52
83
  }
53
- console.log(bold(blue(`Log `)), bold(useFunctions().fromID(evt.properties.functionID).handler));
54
- console.log(dim(lines.join("\n")));
84
+ Colors.gap();
55
85
  });
56
86
  bus.subscribe("function.success", async (evt) => {
57
- console.log(bold(green(`Success `)), bold(useFunctions().fromID(evt.properties.functionID).handler));
87
+ // stdout logs sometimes come in after
88
+ const p = prefix(evt.properties.requestID);
89
+ const req = pending.get(evt.properties.requestID);
90
+ setTimeout(() => {
91
+ Colors.line(p, Colors.dim(`Done in ${Date.now() - req.started - 100}ms`));
92
+ end(evt.properties.requestID);
93
+ }, 100);
58
94
  });
59
95
  bus.subscribe("function.error", async (evt) => {
60
- console.log(bold(red(`Error `)), bold(useFunctions().fromID(evt.properties.functionID).handler), evt.properties.errorMessage);
61
- for (const line of evt.properties.trace || []) {
62
- console.log(` ${dim(line)}`);
63
- }
96
+ setTimeout(() => {
97
+ Colors.line(prefix(evt.properties.requestID), Colors.danger.bold("Error:"), Colors.danger.bold(evt.properties.errorMessage));
98
+ for (const line of evt.properties.trace || []) {
99
+ Colors.line(" ", `${dim(line)}`);
100
+ }
101
+ end(evt.properties.requestID);
102
+ }, 100);
64
103
  });
65
104
  });
66
105
  const useStackBuilder = Context.memo(async () => {
67
106
  const watcher = useWatcher();
68
- const bus = useBus();
69
107
  const project = useProject();
108
+ const bus = useBus();
70
109
  let lastDeployed;
71
- let pending;
72
- let isDeploying = false;
110
+ let isWorking = false;
111
+ let isDirty = false;
73
112
  async function build() {
74
- const spinner = createSpinner("Building stacks").start();
113
+ if (isWorking) {
114
+ isDirty = true;
115
+ return;
116
+ }
117
+ isDirty = false;
118
+ isWorking = true;
119
+ Colors.gap();
120
+ const spinner = createSpinner({
121
+ color: "gray",
122
+ text: lastDeployed ? ` Building...` : dim(` Checking for changes`),
123
+ }).start();
75
124
  try {
76
- const fn = await Stacks.build();
125
+ const [metafile, sstConfig] = await Stacks.load(project.paths.config);
126
+ project.metafile = metafile;
127
+ project.stacks = sstConfig.stacks;
77
128
  const assembly = await Stacks.synth({
78
- fn,
129
+ increaseTimeout: args["increase-timeout"],
130
+ fn: project.stacks,
79
131
  outDir: `.sst/cdk.out`,
80
132
  mode: "dev",
81
133
  });
@@ -83,39 +135,46 @@ export const dev = (program) => program.command(["start", "dev"], "Work on your
83
135
  const next = await checksum(assembly.directory);
84
136
  Logger.debug("Checksum", "next", next, "old", lastDeployed);
85
137
  if (next === lastDeployed) {
86
- spinner.succeed("Stacks built! No changes");
138
+ spinner.succeed(Colors.dim(" Built with no changes"));
139
+ isWorking = false;
140
+ if (isDirty)
141
+ build();
87
142
  return;
88
143
  }
89
- spinner.succeed(lastDeployed ? `Stacks built!` : `Stacks built!`);
90
- pending = assembly;
91
- if (lastDeployed)
92
- deploy();
144
+ if (!lastDeployed) {
145
+ spinner.stop();
146
+ spinner.clear();
147
+ Colors.mode("gap");
148
+ }
149
+ else {
150
+ spinner.succeed(Colors.dim(` Built`));
151
+ Colors.gap();
152
+ }
153
+ deploy(assembly);
93
154
  }
94
155
  catch (ex) {
156
+ isWorking = false;
95
157
  spinner.fail();
96
- console.error(ex);
158
+ Colors.line(ex.stack
159
+ .split("\n")
160
+ .map((line) => " " + line)
161
+ .join("\n"));
162
+ Colors.gap();
97
163
  }
98
164
  }
99
- async function deploy() {
100
- if (!pending)
101
- return;
102
- if (isDeploying)
103
- return;
104
- isDeploying = true;
105
- const assembly = pending;
165
+ async function deploy(assembly) {
106
166
  const nextChecksum = await checksum(assembly.directory);
107
- pending = undefined;
108
- let component = undefined;
109
- if (args.fullscreen) {
110
- process.stdout.write("\x1b[?1049h");
111
- component = render(React.createElement(DeploymentUI, { stacks: assembly.stacks.map((s) => s.stackName) }));
112
- }
167
+ const component = render(React.createElement(DeploymentUI, { assembly: assembly }));
113
168
  const results = await Stacks.deployMany(assembly.stacks);
114
- if (component)
115
- component.unmount();
116
- process.stdout.write("\x1b[?1049l");
169
+ component.clear();
170
+ component.unmount();
171
+ printDeploymentResults(assembly, results);
172
+ // Update app state
173
+ if (!lastDeployed) {
174
+ await saveAppMetadata({ mode: "dev" });
175
+ }
117
176
  lastDeployed = nextChecksum;
118
- printDeploymentResults(results);
177
+ // Update site env
119
178
  const keys = await SiteEnv.keys();
120
179
  if (keys.length) {
121
180
  const result = {};
@@ -131,8 +190,11 @@ export const dev = (program) => program.command(["start", "dev"], "Work on your
131
190
  }
132
191
  await SiteEnv.writeValues(result);
133
192
  }
134
- isDeploying = false;
135
- deploy();
193
+ // Write outputs.json
194
+ fs.writeFile(path.join(project.paths.out, "outputs.json"), JSON.stringify(pipe(results, omitBy((_, key) => key.includes("SstSiteEnv")), mapValues((val) => val.outputs)), null, 2));
195
+ isWorking = false;
196
+ if (isDirty)
197
+ build();
136
198
  }
137
199
  async function checksum(cdkOutPath) {
138
200
  const manifestPath = path.join(cdkOutPath, "manifest.json");
@@ -151,38 +213,54 @@ export const dev = (program) => program.command(["start", "dev"], "Work on your
151
213
  .digest("hex");
152
214
  return hash;
153
215
  }
154
- let metafile;
155
- bus.subscribe("stack.built", async (evt) => {
156
- metafile = evt.properties.metafile;
157
- });
158
216
  watcher.subscribe("file.changed", async (evt) => {
159
- if (!metafile)
217
+ if (!project.metafile)
160
218
  return;
161
- if (!metafile.inputs[evt.properties.relative])
219
+ if (!project.metafile.inputs[evt.properties.relative])
162
220
  return;
163
221
  build();
164
222
  });
165
223
  await build();
166
- await deploy();
167
224
  });
168
- createSpinner("").start().succeed("Ready for function invocations");
169
- createSpinner("")
170
- .start()
171
- .succeed(`Console ready at https://console.sst.dev`);
172
- await Promise.all([
225
+ const [appMetadata] = await Promise.all([
226
+ useAppMetadata(),
173
227
  useLocalServer({
174
228
  key: "",
175
229
  cert: "",
176
230
  live: true,
177
- port: 13557,
178
231
  }),
232
+ ]);
233
+ // Check app mode changed
234
+ if (appMetadata && appMetadata.mode !== "dev") {
235
+ if (!(await promptChangeMode())) {
236
+ process.exit(0);
237
+ }
238
+ }
239
+ clear();
240
+ await printHeader({ console: true, hint: "ready!" });
241
+ await Promise.all([
179
242
  useRuntimeWorkers(),
180
243
  useIOTBridge(),
181
244
  useRuntimeServer(),
182
245
  usePothosBuilder(),
246
+ useMetadata(),
183
247
  useKyselyTypeGenerator(),
184
248
  useRDSWarmer(),
185
249
  useFunctionLogger(),
186
250
  useStackBuilder(),
187
251
  ]);
188
252
  });
253
+ async function promptChangeMode() {
254
+ const readline = await import("readline");
255
+ const rl = readline.createInterface({
256
+ input: process.stdin,
257
+ output: process.stdout,
258
+ });
259
+ return new Promise((resolve) => {
260
+ console.log("");
261
+ rl.question("You have previously deployed this stage in production. It is recommended that you use a different stage for development. Read more here — https://docs.sst.dev/live-lambda-development\n\nAre you sure you want to run this stage in dev mode? [y/N] ", async (input) => {
262
+ rl.close();
263
+ resolve(input.trim() === "y");
264
+ });
265
+ });
266
+ }
@@ -0,0 +1,15 @@
1
+ /// <reference types="yargs" />
2
+ import type { Program } from "../program.js";
3
+ export declare const diff: (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
+ dev: boolean | undefined;
15
+ }>;