sst 2.0.0-rc.36 → 2.0.0-rc.38

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.d.ts CHANGED
@@ -1,4 +1,5 @@
1
- export declare const useBootstrap: () => Promise<{
2
- version: never;
3
- bucket: never;
4
- }>;
1
+ export declare const useBootstrap: () => {
2
+ version: string;
3
+ bucket: string;
4
+ };
5
+ export declare function initBootstrap(): Promise<void>;
package/bootstrap.js CHANGED
@@ -12,19 +12,25 @@ import { BlockPublicAccess, Bucket, BucketEncryption, } from "aws-cdk-lib/aws-s3
12
12
  import { useProject } from "./project.js";
13
13
  import { createSpinner } from "./cli/spinner.js";
14
14
  import { Context } from "./context/context.js";
15
- import { useAWSClient } from "./credentials.js";
15
+ import { useAWSClient, useAWSCredentials, useSTSIdentity, } from "./credentials.js";
16
16
  import { VisibleError } from "./error.js";
17
17
  import { Logger } from "./logger.js";
18
18
  import { Stacks } from "./stacks/index.js";
19
+ import { spawnSync } from "child_process";
19
20
  const STACK_NAME = "SSTBootstrap";
20
21
  const OUTPUT_VERSION = "Version";
21
22
  const OUTPUT_BUCKET = "BucketName";
22
23
  const LATEST_VERSION = "5";
23
24
  const __dirname = url.fileURLToPath(new URL(".", import.meta.url));
24
- export const useBootstrap = Context.memo(async () => {
25
+ const BootstrapContext = Context.create();
26
+ export const useBootstrap = BootstrapContext.use;
27
+ export async function initBootstrap() {
25
28
  Logger.debug("Initializing bootstrap context");
26
- let status = await loadBootstrapStatus();
27
- if (!status || status.version !== LATEST_VERSION) {
29
+ await assertCDKToolkit();
30
+ const status = await (async () => {
31
+ const status = await load();
32
+ if (status && status.version === LATEST_VERSION)
33
+ return status;
28
34
  const project = useProject();
29
35
  const spinner = createSpinner("Deploying bootstrap stack, this only needs to happen once").start();
30
36
  // Create bootstrap stack
@@ -62,7 +68,9 @@ export const useBootstrap = Context.memo(async () => {
62
68
  }),
63
69
  new PolicyStatement({
64
70
  actions: ["iot:Publish"],
65
- resources: [`arn:${stack.partition}:iot:${stack.region}:${stack.account}:topic//sst/*`],
71
+ resources: [
72
+ `arn:${stack.partition}:iot:${stack.region}:${stack.account}:topic//sst/*`,
73
+ ],
66
74
  }),
67
75
  ],
68
76
  });
@@ -81,9 +89,9 @@ export const useBootstrap = Context.memo(async () => {
81
89
  "ROLLBACK_COMPLETE",
82
90
  "DELETE_COMPLETE",
83
91
  ],
84
- }
85
- }
86
- }
92
+ },
93
+ },
94
+ },
87
95
  });
88
96
  rule.addTarget(new SqsQueue(queue, {
89
97
  retryAttempts: 10,
@@ -99,15 +107,43 @@ export const useBootstrap = Context.memo(async () => {
99
107
  }
100
108
  spinner.succeed();
101
109
  // Fetch bootstrap status
102
- status = await loadBootstrapStatus();
103
- if (!status) {
104
- throw new VisibleError("Failed to deploy bootstrap stack");
105
- }
110
+ const ret = await load();
111
+ if (!ret)
112
+ throw new VisibleError("Failed to load bootstrap stack status");
113
+ return ret;
114
+ })();
115
+ BootstrapContext.provide(status);
116
+ Logger.debug("Bootstrap context initialized", status);
117
+ }
118
+ async function assertCDKToolkit() {
119
+ const client = useAWSClient(CloudFormationClient);
120
+ const { Stacks: stacks } = await client.send(new DescribeStacksCommand({
121
+ StackName: "CDKToolkit",
122
+ }));
123
+ if (!stacks || stacks.length === 0) {
124
+ const identity = await useSTSIdentity();
125
+ const credentials = await useAWSCredentials();
126
+ const project = useProject();
127
+ spawnSync([
128
+ "npx",
129
+ "cdk",
130
+ "bootstrap",
131
+ `aws://${identity.Account}/${useProject().config.region}`,
132
+ ].join(" "), {
133
+ env: {
134
+ ...process.env,
135
+ AWS_ACCESS_KEY_ID: credentials.accessKeyId,
136
+ AWS_SECRET_ACCESS_KEY: credentials.secretAccessKey,
137
+ AWS_SESSION_TOKEN: credentials.sessionToken,
138
+ AWS_REGION: project.config.region,
139
+ AWS_PROFILE: project.config.profile,
140
+ },
141
+ stdio: "inherit",
142
+ shell: process.env.SHELL || true,
143
+ });
106
144
  }
107
- Logger.debug("Loaded bootstrap info: ", JSON.stringify(status));
108
- return status;
109
- });
110
- async function loadBootstrapStatus() {
145
+ }
146
+ async function load() {
111
147
  // Get bootstrap CloudFormation stack
112
148
  const cf = useAWSClient(CloudFormationClient);
113
149
  let result;
@@ -117,8 +153,8 @@ async function loadBootstrapStatus() {
117
153
  }));
118
154
  }
119
155
  catch (e) {
120
- if (e.Code === "ValidationError"
121
- && e.message === `Stack with id ${STACK_NAME} does not exist`) {
156
+ if (e.Code === "ValidationError" &&
157
+ e.message === `Stack with id ${STACK_NAME} does not exist`) {
122
158
  return null;
123
159
  }
124
160
  throw e;
@@ -8,6 +8,8 @@ export declare const bind: (program: Program) => import("yargs").Argv<{
8
8
  region: string | undefined;
9
9
  } & {
10
10
  verbose: boolean | undefined;
11
+ } & {
12
+ role: string | undefined;
11
13
  } & {
12
14
  command: string;
13
15
  }>;
@@ -8,6 +8,8 @@ export declare const build: (program: Program) => import("yargs").Argv<{
8
8
  region: string | undefined;
9
9
  } & {
10
10
  verbose: boolean | undefined;
11
+ } & {
12
+ role: string | undefined;
11
13
  } & {
12
14
  to: string | undefined;
13
15
  }>;
@@ -8,4 +8,6 @@ export declare const consoleCommand: (program: Program) => Promise<import("yargs
8
8
  region: string | undefined;
9
9
  } & {
10
10
  verbose: boolean | undefined;
11
+ } & {
12
+ role: string | undefined;
11
13
  }>>;
@@ -8,6 +8,8 @@ export declare const deploy: (program: Program) => import("yargs").Argv<{
8
8
  region: string | undefined;
9
9
  } & {
10
10
  verbose: boolean | undefined;
11
+ } & {
12
+ role: string | undefined;
11
13
  } & {
12
14
  from: string | undefined;
13
15
  } & {
@@ -8,4 +8,6 @@ export declare const dev: (program: Program) => import("yargs").Argv<{
8
8
  region: string | undefined;
9
9
  } & {
10
10
  verbose: boolean | undefined;
11
+ } & {
12
+ role: string | undefined;
11
13
  }>;
@@ -1,6 +1,5 @@
1
1
  import chalk from "chalk";
2
2
  import { Colors } from "../colors.js";
3
- import { Functions } from "../ui/functions.js";
4
3
  export const dev = (program) => program.command(["dev", "start"], "Work on your app locally", (yargs) => yargs, async (args) => {
5
4
  const { useRuntimeWorkers } = await import("../../runtime/workers.js");
6
5
  const { useIOTBridge } = await import("../../runtime/iot.js");
@@ -28,6 +27,7 @@ export const dev = (program) => program.command(["dev", "start"], "Work on your
28
27
  const { useRDSWarmer } = await import("./plugins/warmer.js");
29
28
  const { useProject } = await import("../../project.js");
30
29
  const { useMetadata } = await import("../../stacks/metadata.js");
30
+ const { Functions } = await import("../ui/functions.js");
31
31
  if (args._[0] === "start") {
32
32
  console.log(yellow(`Warning: ${bold(`sst start`)} has been renamed to ${bold(`sst dev`)}`));
33
33
  }
@@ -8,6 +8,8 @@ export declare const diff: (program: Program) => import("yargs").Argv<{
8
8
  region: string | undefined;
9
9
  } & {
10
10
  verbose: boolean | undefined;
11
+ } & {
12
+ role: string | undefined;
11
13
  } & {
12
14
  dev: boolean | undefined;
13
15
  }>;
@@ -8,6 +8,8 @@ export declare const env: (program: Program) => import("yargs").Argv<{
8
8
  region: string | undefined;
9
9
  } & {
10
10
  verbose: boolean | undefined;
11
+ } & {
12
+ role: string | undefined;
11
13
  } & {
12
14
  command: string;
13
15
  }>;
@@ -8,6 +8,8 @@ export declare const remove: (program: Program) => import("yargs").Argv<{
8
8
  region: string | undefined;
9
9
  } & {
10
10
  verbose: boolean | undefined;
11
+ } & {
12
+ role: string | undefined;
11
13
  } & {
12
14
  from: string | undefined;
13
15
  } & {
@@ -8,6 +8,8 @@ export declare const get: (program: Program) => import("yargs").Argv<{
8
8
  region: string | undefined;
9
9
  } & {
10
10
  verbose: boolean | undefined;
11
+ } & {
12
+ role: string | undefined;
11
13
  } & {
12
14
  name: string;
13
15
  } & {
@@ -8,6 +8,8 @@ export declare const list: (program: Program) => import("yargs").Argv<{
8
8
  region: string | undefined;
9
9
  } & {
10
10
  verbose: boolean | undefined;
11
+ } & {
12
+ role: string | undefined;
11
13
  } & {
12
14
  format: string | undefined;
13
15
  }>;
@@ -8,6 +8,8 @@ export declare const remove: (program: Program) => import("yargs").Argv<{
8
8
  region: string | undefined;
9
9
  } & {
10
10
  verbose: boolean | undefined;
11
+ } & {
12
+ role: string | undefined;
11
13
  } & {
12
14
  name: string;
13
15
  } & {
@@ -1,11 +1,14 @@
1
+ import { get } from "./get.js";
2
+ import { list } from "./list.js";
3
+ import { remove } from "./remove.js";
1
4
  import { set } from "./set.js";
2
5
  export function secrets(program) {
3
6
  program.command("secrets", "Manage the secrets in your app", (yargs) => {
4
7
  yargs.demandCommand(1);
5
8
  set(yargs);
6
- // get(yargs);
7
- // list(yargs);
8
- // remove(yargs);
9
+ get(yargs);
10
+ list(yargs);
11
+ remove(yargs);
9
12
  return yargs;
10
13
  });
11
14
  }
@@ -8,6 +8,8 @@ export declare const set: (program: Program) => import("yargs").Argv<{
8
8
  region: string | undefined;
9
9
  } & {
10
10
  verbose: boolean | undefined;
11
+ } & {
12
+ role: string | undefined;
11
13
  } & {
12
14
  name: string;
13
15
  } & {
@@ -8,6 +8,8 @@ export declare const update: (program: Program) => import("yargs").Argv<{
8
8
  region: string | undefined;
9
9
  } & {
10
10
  verbose: boolean | undefined;
11
+ } & {
12
+ role: string | undefined;
11
13
  } & {
12
14
  version: string | undefined;
13
15
  }>;
@@ -8,6 +8,8 @@ export declare const env: (program: Program) => import("yargs").Argv<{
8
8
  region: string | undefined;
9
9
  } & {
10
10
  verbose: boolean | undefined;
11
+ } & {
12
+ role: string | undefined;
11
13
  } & {
12
14
  command: string;
13
15
  }>;
package/cli/program.d.ts CHANGED
@@ -7,5 +7,7 @@ export declare const program: import("yargs").Argv<{
7
7
  region: string | undefined;
8
8
  } & {
9
9
  verbose: boolean | undefined;
10
+ } & {
11
+ role: string | undefined;
10
12
  }>;
11
13
  export type Program = typeof program;
package/cli/program.js CHANGED
@@ -18,7 +18,11 @@ export const program = yargs(hideBin(process.argv))
18
18
  type: "boolean",
19
19
  describe: "Print verbose logs",
20
20
  })
21
- .group(["stage", "profile", "region", "help"], "Global:")
21
+ .option("role", {
22
+ type: "string",
23
+ describe: "ARN of the IAM role to use when invoking AWS",
24
+ })
25
+ .group(["stage", "profile", "region", "help", "verbose", "role"], "Global:")
22
26
  .middleware(async (argv) => {
23
27
  if (argv.verbose) {
24
28
  process.env.SST_VERBOSE = "1";
package/cli/sst.js CHANGED
@@ -3,8 +3,9 @@ import { blue, red } from "colorette";
3
3
  import { program } from "./program.js";
4
4
  import { VisibleError } from "../error.js";
5
5
  import { useSpinners } from "./spinner.js";
6
- import dotenv from "dotenv";
7
6
  import { Logger } from "../logger.js";
7
+ import dotenv from "dotenv";
8
+ dotenv.config();
8
9
  import { env } from "./commands/env.js";
9
10
  import { dev } from "./commands/dev.js";
10
11
  import { bind } from "./commands/bind.js";
@@ -15,7 +16,6 @@ import { consoleCommand } from "./commands/console.js";
15
16
  import { secrets } from "./commands/secrets/secrets.js";
16
17
  import { update } from "./commands/update.js";
17
18
  import { diff } from "./commands/diff.js";
18
- dotenv.config();
19
19
  dev(program);
20
20
  deploy(program);
21
21
  build(program);
@@ -60,6 +60,8 @@ export function Functions() {
60
60
  }
61
61
  setFunctions((functions) => {
62
62
  const { [evt.properties.requestID]: existing, ...next } = functions;
63
+ if (!existing)
64
+ return functions;
63
65
  const diff = Date.now() - existing.started;
64
66
  if (diff > 500 && diff < 1500) {
65
67
  setTimeout(() => {
@@ -91,6 +93,8 @@ export function Functions() {
91
93
  }
92
94
  setFunctions((functions) => {
93
95
  const { [evt.properties.requestID]: existing, ...next } = functions;
96
+ if (!existing)
97
+ return functions;
94
98
  const diff = Date.now() - existing.started;
95
99
  if (diff > 500 && diff < 1500) {
96
100
  setTimeout(() => {
@@ -7,7 +7,6 @@ import * as Config from "./Config.js";
7
7
  import { Permissions } from "./util/permission.js";
8
8
  import { StackProps } from "./Stack.js";
9
9
  import { FunctionalStack } from "./FunctionalStack.js";
10
- import { useBootstrap } from "../bootstrap.js";
11
10
  /**
12
11
  * @internal
13
12
  */
@@ -40,7 +39,6 @@ export interface AppDeployProps {
40
39
  readonly debugBridge?: string;
41
40
  readonly debugIncreaseTimeout?: boolean;
42
41
  readonly mode: "deploy" | "dev" | "remove";
43
- readonly bootstrap: Awaited<ReturnType<typeof useBootstrap>>;
44
42
  }
45
43
  type AppRemovalPolicy = Lowercase<keyof typeof cdk.RemovalPolicy>;
46
44
  export type AppProps = cdk.AppProps;
@@ -87,8 +85,6 @@ export declare class App extends cdk.App {
87
85
  /** @internal */
88
86
  readonly appPath: string;
89
87
  /** @internal */
90
- readonly bootstrap: AppDeployProps["bootstrap"];
91
- /** @internal */
92
88
  defaultFunctionProps: (FunctionProps | ((stack: cdk.Stack) => FunctionProps))[];
93
89
  private _defaultRemovalPolicy?;
94
90
  /** @internal */
package/constructs/App.js CHANGED
@@ -14,6 +14,7 @@ import { createRequire } from "module";
14
14
  import { Auth } from "./Auth.js";
15
15
  import { useDeferredTasks } from "./deferred_task.js";
16
16
  import { AppContext } from "./context.js";
17
+ import { useBootstrap } from "../bootstrap.js";
17
18
  import { useProject } from "../project.js";
18
19
  import { Logger } from "../logger.js";
19
20
  import { SiteEnv } from "../site-env.js";
@@ -65,8 +66,6 @@ export class App extends cdk.App {
65
66
  /** @internal */
66
67
  appPath;
67
68
  /** @internal */
68
- bootstrap;
69
- /** @internal */
70
69
  defaultFunctionProps;
71
70
  _defaultRemovalPolicy;
72
71
  /** @internal */
@@ -93,7 +92,6 @@ export class App extends cdk.App {
93
92
  super(props);
94
93
  AppContext.provide(this);
95
94
  SiteEnv.reset();
96
- this.bootstrap = deployProps.bootstrap;
97
95
  this.appPath = process.cwd();
98
96
  this.mode = deployProps.mode;
99
97
  this.local = this.mode === "dev";
@@ -309,7 +307,7 @@ export class App extends cdk.App {
309
307
  app: this.name,
310
308
  stage: this.stage,
311
309
  version: useProject().version,
312
- bootstrapBucket: this.bootstrap.bucket,
310
+ bootstrapBucket: useBootstrap().bucket,
313
311
  metadata: byStack[stackName] || [],
314
312
  }),
315
313
  });
package/credentials.js CHANGED
@@ -10,6 +10,7 @@ export const useAWSCredentialsProvider = Context.memo(() => {
10
10
  Logger.debug("Using AWS profile", project.config.profile);
11
11
  const provider = fromNodeProviderChain({
12
12
  profile: project.config.profile,
13
+ roleArn: project.config.role,
13
14
  });
14
15
  return provider;
15
16
  });
package/iot.js CHANGED
@@ -37,6 +37,10 @@ export const useIOT = Context.memo(async () => {
37
37
  });
38
38
  device.on("message", (_topic, buffer) => {
39
39
  const fragment = JSON.parse(buffer.toString());
40
+ if (!fragment.id) {
41
+ bus.publish(fragment.type, fragment.properties);
42
+ return;
43
+ }
40
44
  let pending = fragments.get(fragment.id);
41
45
  if (!pending) {
42
46
  pending = new Map();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sst",
3
- "version": "2.0.0-rc.36",
3
+ "version": "2.0.0-rc.38",
4
4
  "bin": {
5
5
  "sst": "cli/sst.js"
6
6
  },
package/project.d.ts CHANGED
@@ -9,6 +9,7 @@ export interface ConfigOptions {
9
9
  region?: string;
10
10
  stage?: string;
11
11
  profile?: string;
12
+ role?: string;
12
13
  ssmPrefix?: string;
13
14
  }
14
15
  declare const DEFAULTS: {
@@ -36,6 +37,7 @@ export declare const ProjectContext: {
36
37
  export declare function useProject(): Project;
37
38
  interface GlobalOptions {
38
39
  profile?: string;
40
+ role?: string;
39
41
  stage?: string;
40
42
  root?: string;
41
43
  region?: string;
package/project.js CHANGED
@@ -64,6 +64,7 @@ export async function initProject(globals) {
64
64
  stage,
65
65
  profile: config.profile || globals.profile,
66
66
  region: config.region || globals.region,
67
+ role: config.role || globals.role,
67
68
  ssmPrefix: config.ssmPrefix || `/sst/${config.name}/${stage}/`,
68
69
  },
69
70
  stacks: sstConfig.stacks,
@@ -76,6 +77,8 @@ export async function initProject(globals) {
76
77
  },
77
78
  };
78
79
  ProjectContext.provide(project);
80
+ const { initBootstrap } = await import("./bootstrap.js");
81
+ await initBootstrap();
79
82
  dotenv.config({
80
83
  path: path.join(project.paths.root, `.env.${project.config.stage}`),
81
84
  });