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.
package/sst.mjs CHANGED
@@ -177,6 +177,13 @@ var init_module = __esm({
177
177
  });
178
178
 
179
179
  // src/util/fs.ts
180
+ var fs_exports = {};
181
+ __export(fs_exports, {
182
+ existsAsync: () => existsAsync,
183
+ findAbove: () => findAbove,
184
+ findBelow: () => findBelow,
185
+ isChild: () => isChild
186
+ });
180
187
  import fs2 from "fs/promises";
181
188
  import path2 from "path";
182
189
  async function findAbove(dir, target) {
@@ -1980,6 +1987,7 @@ async function monitor(stack) {
1980
1987
  errors: {}
1981
1988
  };
1982
1989
  }
1990
+ throw ex;
1983
1991
  }
1984
1992
  await new Promise((resolve) => setTimeout(resolve, 1e3));
1985
1993
  }
@@ -3258,13 +3266,13 @@ async function listImports(exportName) {
3258
3266
  }
3259
3267
  }
3260
3268
  async function getLocalTemplate(stack) {
3261
- const fs19 = await import("fs/promises");
3262
- const fileContent = await fs19.readFile(stack.templateFullPath);
3269
+ const fs18 = await import("fs/promises");
3270
+ const fileContent = await fs18.readFile(stack.templateFullPath);
3263
3271
  return fileContent.toString();
3264
3272
  }
3265
3273
  async function saveLocalTemplate(stack, content) {
3266
- const fs19 = await import("fs/promises");
3267
- await fs19.writeFile(stack.templateFullPath, content);
3274
+ const fs18 = await import("fs/promises");
3275
+ await fs18.writeFile(stack.templateFullPath, content);
3268
3276
  }
3269
3277
  var init_deploy = __esm({
3270
3278
  "src/stacks/deploy.ts"() {
@@ -3373,7 +3381,6 @@ var init_cache = __esm({
3373
3381
  var metadata_exports = {};
3374
3382
  __export(metadata_exports, {
3375
3383
  metadata: () => metadata2,
3376
- metadataForStack: () => metadataForStack,
3377
3384
  useMetadata: () => useMetadata
3378
3385
  });
3379
3386
  import {
@@ -3417,32 +3424,6 @@ async function metadata2() {
3417
3424
  Logger.debug("Fetched metadata from", list2.KeyCount, "stacks");
3418
3425
  return result;
3419
3426
  }
3420
- async function metadataForStack(stackID) {
3421
- const [project, credentials, bootstrap2] = await Promise.all([
3422
- useProject(),
3423
- useAWSCredentialsProvider(),
3424
- useBootstrap()
3425
- ]);
3426
- const s3 = new S3Client2({
3427
- region: project.config.region,
3428
- credentials
3429
- });
3430
- const key = `stackMetadata/app.${project.config.name}/stage.${project.config.stage}/stack.${stackID}.json`;
3431
- Logger.debug("Getting metadata", key, "from", bootstrap2.bucket);
3432
- try {
3433
- const result = await s3.send(
3434
- new GetObjectCommand2({
3435
- Key: key,
3436
- Bucket: bootstrap2.bucket
3437
- })
3438
- );
3439
- const body = await result.Body.transformToString();
3440
- return JSON.parse(body);
3441
- } catch (ex) {
3442
- console.error(ex);
3443
- return [];
3444
- }
3445
- }
3446
3427
  var MetadataContext2, useMetadata;
3447
3428
  var init_metadata = __esm({
3448
3429
  "src/stacks/metadata.ts"() {
@@ -5080,7 +5061,6 @@ __export(stacks_exports, {
5080
5061
  load: () => load,
5081
5062
  loadAssembly: () => loadAssembly,
5082
5063
  metadata: () => metadata2,
5083
- metadataForStack: () => metadataForStack,
5084
5064
  monitor: () => monitor,
5085
5065
  publishAssets: () => publishAssets4,
5086
5066
  remove: () => remove,
@@ -5384,65 +5364,6 @@ var init_bootstrap = __esm({
5384
5364
  }
5385
5365
  });
5386
5366
 
5387
- // src/site-env.ts
5388
- var site_env_exports = {};
5389
- __export(site_env_exports, {
5390
- SiteEnv: () => site_env_exports,
5391
- append: () => append,
5392
- keys: () => keys,
5393
- reset: () => reset2,
5394
- values: () => values,
5395
- valuesFile: () => valuesFile,
5396
- writeValues: () => writeValues
5397
- });
5398
- import fs13 from "fs";
5399
- import path16 from "path";
5400
- function keysFile() {
5401
- return path16.join(useProject().paths.out, "site-environment-keys.jsonl");
5402
- }
5403
- function valuesFile() {
5404
- return path16.join(useProject().paths.out, "site-environment-values.json");
5405
- }
5406
- async function keys() {
5407
- try {
5408
- const file = keysFile();
5409
- const data2 = await fs13.promises.readFile(file).then((x) => x.toString().split("\n"));
5410
- return data2.filter(Boolean).map((x) => JSON.parse(x));
5411
- } catch {
5412
- return [];
5413
- }
5414
- }
5415
- async function values() {
5416
- try {
5417
- const file = valuesFile();
5418
- const data2 = await fs13.promises.readFile(file).then((x) => JSON.parse(x.toString()));
5419
- return data2;
5420
- } catch {
5421
- return {};
5422
- }
5423
- }
5424
- async function writeValues(input) {
5425
- const file = valuesFile();
5426
- await fs13.promises.writeFile(file, JSON.stringify(input));
5427
- }
5428
- function append(input) {
5429
- input.path = path16.resolve(useProject().paths.root, input.path);
5430
- fs13.appendFileSync(keysFile(), JSON.stringify(input) + "\n");
5431
- }
5432
- function reset2() {
5433
- fs13.rmSync(keysFile(), {
5434
- force: true,
5435
- recursive: true
5436
- });
5437
- }
5438
- var init_site_env = __esm({
5439
- "src/site-env.ts"() {
5440
- "use strict";
5441
- init_site_env();
5442
- init_project();
5443
- }
5444
- });
5445
-
5446
5367
  // src/cli/local/router.ts
5447
5368
  import * as trpc from "@trpc/server";
5448
5369
  var router2;
@@ -5497,7 +5418,7 @@ __export(server_exports2, {
5497
5418
  });
5498
5419
  import { produceWithPatches, enablePatches } from "immer";
5499
5420
  import express2 from "express";
5500
- import fs14 from "fs/promises";
5421
+ import fs13 from "fs/promises";
5501
5422
  import { WebSocketServer } from "ws";
5502
5423
  import https3 from "https";
5503
5424
  import http from "http";
@@ -5578,15 +5499,15 @@ async function useLocalServer(opts) {
5578
5499
  const CERT_PATH = ".sst/localhost.pem";
5579
5500
  if (result2.status === 0) {
5580
5501
  try {
5581
- await Promise.all([fs14.access(KEY_PATH), fs14.access(CERT_PATH)]);
5502
+ await Promise.all([fs13.access(KEY_PATH), fs13.access(CERT_PATH)]);
5582
5503
  } catch (e) {
5583
5504
  sync("mkcert", ["localhost"], {
5584
5505
  cwd: ".sst"
5585
5506
  });
5586
5507
  }
5587
5508
  const [key, cert] = await Promise.all([
5588
- fs14.readFile(KEY_PATH),
5589
- fs14.readFile(CERT_PATH)
5509
+ fs13.readFile(KEY_PATH),
5510
+ fs13.readFile(CERT_PATH)
5590
5511
  ]);
5591
5512
  return https3.createServer(
5592
5513
  {
@@ -5995,15 +5916,10 @@ function printDeploymentResults(assembly, results, remove4) {
5995
5916
  Colors.bold(remove4 ? ` Removed:` : ` Deployed:`)
5996
5917
  );
5997
5918
  for (const [stack, result] of success) {
5998
- const outputs = Object.entries(result.outputs).filter(
5999
- ([key, _]) => !key.includes("SstSiteEnv")
6000
- );
6001
5919
  Colors.line(` ${Colors.dim(stackNameToId(stack))}`);
6002
- if (outputs.length > 0) {
6003
- for (const key of Object.keys(Object.fromEntries(outputs)).sort()) {
6004
- const value = result.outputs[key];
6005
- Colors.line(` ${Colors.bold.dim(key + ":")} ${value}`);
6006
- }
5920
+ for (const key of Object.keys(result.outputs).sort()) {
5921
+ const value = result.outputs[key];
5922
+ Colors.line(` ${Colors.bold.dim(key + ":")} ${value}`);
6007
5923
  }
6008
5924
  }
6009
5925
  Colors.gap();
@@ -6142,16 +6058,16 @@ __export(pothos_exports, {
6142
6058
  import babel from "@babel/core";
6143
6059
  import generator from "@babel/generator";
6144
6060
  import esbuild3 from "esbuild";
6145
- import fs15 from "fs/promises";
6146
- import path17 from "path";
6061
+ import fs14 from "fs/promises";
6062
+ import path16 from "path";
6147
6063
  import url9 from "url";
6148
6064
  async function generate(opts) {
6149
6065
  const { printSchema, lexicographicSortSchema } = await import("graphql");
6150
6066
  const contents = await extractSchema(opts);
6151
- const out = path17.join(path17.dirname(opts.schema), "out.mjs");
6152
- await fs15.writeFile(out, contents, "utf8");
6067
+ const out = path16.join(path16.dirname(opts.schema), "out.mjs");
6068
+ await fs14.writeFile(out, contents, "utf8");
6153
6069
  const { schema } = await import(url9.pathToFileURL(out).href + "?bust=" + Date.now());
6154
- await fs15.rm(out);
6070
+ await fs14.rm(out);
6155
6071
  const schemaAsString = printSchema(lexicographicSortSchema(schema));
6156
6072
  return schemaAsString;
6157
6073
  }
@@ -6299,10 +6215,10 @@ var pothos_exports2 = {};
6299
6215
  __export(pothos_exports2, {
6300
6216
  usePothosBuilder: () => usePothosBuilder
6301
6217
  });
6302
- import fs16 from "fs/promises";
6218
+ import fs15 from "fs/promises";
6303
6219
  import { exec as exec6 } from "child_process";
6304
6220
  import { promisify as promisify4 } from "util";
6305
- import path18 from "path";
6221
+ import path17 from "path";
6306
6222
  var execAsync4, usePothosBuilder;
6307
6223
  var init_pothos2 = __esm({
6308
6224
  "src/cli/commands/plugins/pothos.ts"() {
@@ -6320,7 +6236,7 @@ var init_pothos2 = __esm({
6320
6236
  const schema = await pothos_exports.generate({
6321
6237
  schema: route.schema
6322
6238
  });
6323
- await fs16.writeFile(route.output, schema);
6239
+ await fs15.writeFile(route.output, schema);
6324
6240
  if (Array.isArray(route.commands) && route.commands.length > 0) {
6325
6241
  await Promise.all(route.commands.map((cmd) => execAsync4(cmd)));
6326
6242
  }
@@ -6336,9 +6252,9 @@ var init_pothos2 = __esm({
6336
6252
  if (evt.properties.file.endsWith("out.mjs"))
6337
6253
  return;
6338
6254
  for (const route of routes) {
6339
- const dir = path18.dirname(route.schema);
6340
- const relative = path18.relative(dir, evt.properties.file);
6341
- if (relative && !relative.startsWith("..") && !path18.isAbsolute(relative))
6255
+ const dir = path17.dirname(route.schema);
6256
+ const relative = path17.relative(dir, evt.properties.file);
6257
+ if (relative && !relative.startsWith("..") && !path17.isAbsolute(relative))
6342
6258
  build2(route);
6343
6259
  }
6344
6260
  });
@@ -6364,7 +6280,7 @@ __export(kysely_exports, {
6364
6280
  import { Kysely } from "kysely";
6365
6281
  import { DataApiDialect } from "kysely-data-api";
6366
6282
  import { RDSData } from "@aws-sdk/client-rds-data";
6367
- import * as fs17 from "fs/promises";
6283
+ import * as fs16 from "fs/promises";
6368
6284
  import {
6369
6285
  DatabaseMetadata,
6370
6286
  EnumCollection,
@@ -6436,7 +6352,7 @@ var init_kysely = __esm({
6436
6352
  };
6437
6353
  const serializer = new Serializer();
6438
6354
  const data2 = serializer.serialize(nodes);
6439
- await fs17.writeFile(db.types.path, data2);
6355
+ await fs16.writeFile(db.types.path, data2);
6440
6356
  }
6441
6357
  bus.subscribe("stacks.metadata", (evt) => {
6442
6358
  const constructs = Object.values(evt.properties).flat();
@@ -6573,12 +6489,39 @@ function parse(ssmName) {
6573
6489
  prop: parts.slice(6).join("/")
6574
6490
  };
6575
6491
  }
6492
+ async function restartFunction(arn) {
6493
+ const lambda = useAWSClient(LambdaClient);
6494
+ try {
6495
+ const config = await lambda.send(
6496
+ new GetFunctionConfigurationCommand({
6497
+ FunctionName: arn
6498
+ })
6499
+ );
6500
+ await lambda.send(
6501
+ new UpdateFunctionConfigurationCommand({
6502
+ FunctionName: arn,
6503
+ Environment: {
6504
+ Variables: {
6505
+ ...config.Environment?.Variables || {},
6506
+ [SECRET_UPDATED_AT_ENV]: Date.now().toString()
6507
+ }
6508
+ }
6509
+ })
6510
+ );
6511
+ return true;
6512
+ } catch (e) {
6513
+ if (e.name === "ResourceNotFoundException" && e.message.startsWith("Function not found")) {
6514
+ return;
6515
+ }
6516
+ }
6517
+ }
6576
6518
  var Config, FALLBACK_STAGE, SECRET_UPDATED_AT_ENV, PREFIX;
6577
6519
  var init_config = __esm({
6578
6520
  "src/config.ts"() {
6579
6521
  "use strict";
6580
6522
  init_project();
6581
6523
  init_credentials();
6524
+ init_iot();
6582
6525
  init_stacks();
6583
6526
  ((Config2) => {
6584
6527
  async function parameters() {
@@ -6633,10 +6576,10 @@ var init_config = __esm({
6633
6576
  return result;
6634
6577
  }
6635
6578
  Config2.secrets = secrets2;
6636
- async function env2() {
6579
+ async function env() {
6637
6580
  const project = useProject();
6638
6581
  const parameters2 = await Config2.parameters();
6639
- const env3 = {
6582
+ const env2 = {
6640
6583
  SST_APP: project.config.name,
6641
6584
  SST_STAGE: project.config.stage,
6642
6585
  ...pipe2(
@@ -6645,12 +6588,12 @@ var init_config = __esm({
6645
6588
  Object.fromEntries
6646
6589
  )
6647
6590
  };
6648
- return env3;
6591
+ return env2;
6649
6592
  }
6650
- Config2.env = env2;
6593
+ Config2.env = env;
6651
6594
  async function setSecret(input) {
6652
6595
  const ssm = useAWSClient(SSMClient);
6653
- const result = await ssm.send(
6596
+ await ssm.send(
6654
6597
  new PutParameterCommand({
6655
6598
  Name: pathFor({
6656
6599
  id: input.key,
@@ -6663,6 +6606,9 @@ var init_config = __esm({
6663
6606
  Overwrite: true
6664
6607
  })
6665
6608
  );
6609
+ const iot2 = await useIOT();
6610
+ const topic = `${iot2.prefix}/events`;
6611
+ await iot2.publish(topic, "config.secret.updated", { name: input.key });
6666
6612
  }
6667
6613
  Config2.setSecret = setSecret;
6668
6614
  async function getSecret(input) {
@@ -6696,37 +6642,35 @@ var init_config = __esm({
6696
6642
  }
6697
6643
  Config2.removeSecret = removeSecret;
6698
6644
  async function restart(key) {
6699
- const lambda = useAWSClient(LambdaClient);
6700
6645
  const metadata3 = await stacks_exports.metadata();
6701
- const filtered = Object.values(metadata3).flat().filter((f) => f.type === "Function").filter((f) => f.data.secrets.includes(key));
6702
- const restarted = await Promise.all(
6703
- filtered.map(async (f) => {
6704
- try {
6705
- const config = await lambda.send(
6706
- new GetFunctionConfigurationCommand({
6707
- FunctionName: f.data.arn
6708
- })
6709
- );
6710
- await lambda.send(
6711
- new UpdateFunctionConfigurationCommand({
6712
- FunctionName: f.data.arn,
6713
- Environment: {
6714
- Variables: {
6715
- ...config.Environment?.Variables || {},
6716
- [SECRET_UPDATED_AT_ENV]: Date.now().toString()
6717
- }
6718
- }
6719
- })
6720
- );
6721
- return true;
6722
- } catch (e) {
6723
- if (e.name === "ResourceNotFoundException" && e.message.startsWith("Function not found")) {
6724
- return;
6725
- }
6726
- }
6727
- })
6646
+ const siteData = Object.values(metadata3).flat().filter(
6647
+ (c) => c.type === "AstroSite" || c.type === "NextjsSite" || c.type === "RemixSite" || c.type === "SolidStartSite"
6648
+ ).filter((c) => c.data.secrets.includes(key));
6649
+ const siteDataPlaceholder = siteData.filter(
6650
+ (c) => c.data.mode === "placeholder"
6728
6651
  );
6729
- return restarted.filter(Boolean).length;
6652
+ const siteDataEdge = siteData.filter((c) => c.data.mode === "deployed").filter((c) => c.data.edge);
6653
+ const siteDataRegional = siteData.filter((c) => c.data.mode === "deployed").filter((c) => !c.data.edge);
6654
+ const regionalSiteArns = siteData.map((s) => s.data.server);
6655
+ const functionData = Object.values(metadata3).flat().filter((c) => c.type === "Function").filter((c) => !regionalSiteArns.includes(c.data.arn)).filter((c) => c.data.secrets.includes(key));
6656
+ const restartedSites = (await Promise.all(
6657
+ siteDataRegional.map(async (s) => {
6658
+ const restarted = await restartFunction(s.data.server);
6659
+ return restarted ? s : restarted;
6660
+ })
6661
+ )).filter((c) => Boolean(c));
6662
+ const restartedFunctions = (await Promise.all(
6663
+ functionData.map(async (f) => {
6664
+ const restarted = await restartFunction(f.data.arn);
6665
+ return restarted ? f : restarted;
6666
+ })
6667
+ )).filter((c) => Boolean(c));
6668
+ return {
6669
+ edgeSites: siteDataEdge,
6670
+ sites: restartedSites,
6671
+ placeholderSites: siteDataPlaceholder,
6672
+ functions: restartedFunctions
6673
+ };
6730
6674
  }
6731
6675
  Config2.restart = restart;
6732
6676
  })(Config || (Config = {}));
@@ -6802,63 +6746,6 @@ var bootstrap = (program2) => program2.command(
6802
6746
  }
6803
6747
  );
6804
6748
 
6805
- // src/cli/commands/env.ts
6806
- init_error();
6807
- var env = (program2) => program2.command(
6808
- "env <command..>",
6809
- "Load environment variables and start your frontend",
6810
- (yargs2) => yargs2.array("command").example(
6811
- `sst env "next dev"`,
6812
- "Start Next.js with your environment variables"
6813
- ).example(
6814
- `sst env "vite dev"`,
6815
- "Start Vite with your environment variables"
6816
- ),
6817
- async (args) => {
6818
- const { createSpinner: createSpinner2 } = await Promise.resolve().then(() => (init_spinner(), spinner_exports));
6819
- const fs19 = await import("fs/promises");
6820
- const { SiteEnv } = await Promise.resolve().then(() => (init_site_env(), site_env_exports));
6821
- const { spawnSync } = await import("child_process");
6822
- const { useAWSCredentials: useAWSCredentials3 } = await Promise.resolve().then(() => (init_credentials(), credentials_exports));
6823
- const { useProject: useProject2 } = await Promise.resolve().then(() => (init_project(), project_exports));
6824
- let spinner;
6825
- while (true) {
6826
- const exists = await fs19.access(SiteEnv.valuesFile()).then(() => true).catch(() => false);
6827
- if (!exists) {
6828
- spinner = createSpinner2(
6829
- "Cannot find SST environment variables. Waiting for SST to start..."
6830
- ).start();
6831
- await new Promise((resolve) => setTimeout(resolve, 1e3));
6832
- continue;
6833
- }
6834
- spinner?.succeed();
6835
- const sites = await SiteEnv.values();
6836
- const env2 = sites[process.cwd()] || {};
6837
- const project = useProject2();
6838
- const credentials = await useAWSCredentials3();
6839
- const joined = args.command?.join(" ");
6840
- if (!joined)
6841
- throw new VisibleError(
6842
- "Command is required, e.g. sst env vite dev"
6843
- );
6844
- const result = spawnSync(joined, {
6845
- env: {
6846
- ...process.env,
6847
- ...env2,
6848
- AWS_ACCESS_KEY_ID: credentials.accessKeyId,
6849
- AWS_SECRET_ACCESS_KEY: credentials.secretAccessKey,
6850
- AWS_SESSION_TOKEN: credentials.sessionToken,
6851
- AWS_REGION: project.config.region
6852
- },
6853
- stdio: "inherit",
6854
- shell: true
6855
- });
6856
- process.exitCode = result.status || void 0;
6857
- break;
6858
- }
6859
- }
6860
- ).strict(false);
6861
-
6862
6749
  // src/cli/commands/dev.tsx
6863
6750
  var dev = (program2) => program2.command(
6864
6751
  ["dev", "start"],
@@ -6870,7 +6757,7 @@ var dev = (program2) => program2.command(
6870
6757
  async (args) => {
6871
6758
  const { Colors: Colors2 } = await Promise.resolve().then(() => (init_colors(), colors_exports));
6872
6759
  const { printHeader: printHeader2 } = await Promise.resolve().then(() => (init_header(), header_exports));
6873
- const { mapValues, omitBy: omitBy2, pipe: pipe3 } = await import("remeda");
6760
+ const { mapValues } = await import("remeda");
6874
6761
  const path20 = await import("path");
6875
6762
  const { useRuntimeWorkers: useRuntimeWorkers2 } = await Promise.resolve().then(() => (init_workers(), workers_exports));
6876
6763
  const { useIOTBridge: useIOTBridge2 } = await Promise.resolve().then(() => (init_iot2(), iot_exports2));
@@ -6886,10 +6773,9 @@ var dev = (program2) => program2.command(
6886
6773
  const { Context: Context2 } = await Promise.resolve().then(() => (init_context(), context_exports));
6887
6774
  const { printDeploymentResults: printDeploymentResults2, DeploymentUI: DeploymentUI2 } = await Promise.resolve().then(() => (init_deploy2(), deploy_exports));
6888
6775
  const { useLocalServer: useLocalServer2 } = await Promise.resolve().then(() => (init_server2(), server_exports2));
6889
- const fs19 = await import("fs/promises");
6776
+ const fs18 = await import("fs/promises");
6890
6777
  const crypto2 = await import("crypto");
6891
6778
  const { useFunctions: useFunctions3 } = await import("../src/constructs/Function.js");
6892
- const { SiteEnv } = await Promise.resolve().then(() => (init_site_env(), site_env_exports));
6893
6779
  const { usePothosBuilder: usePothosBuilder2 } = await Promise.resolve().then(() => (init_pothos2(), pothos_exports2));
6894
6780
  const { useKyselyTypeGenerator: useKyselyTypeGenerator2 } = await Promise.resolve().then(() => (init_kysely(), kysely_exports));
6895
6781
  const { useRDSWarmer: useRDSWarmer2 } = await Promise.resolve().then(() => (init_warmer(), warmer_exports));
@@ -7061,27 +6947,10 @@ var dev = (program2) => program2.command(
7061
6947
  await saveAppMetadata2({ mode: "dev" });
7062
6948
  }
7063
6949
  lastDeployed = nextChecksum;
7064
- const keys2 = await SiteEnv.keys();
7065
- const result = {};
7066
- for (const key of keys2) {
7067
- const stack = results[key.stack];
7068
- const value = stack.outputs[key.output];
7069
- let existing = result[key.path];
7070
- if (!existing) {
7071
- result[key.path] = existing;
7072
- existing = result[key.path] = {};
7073
- }
7074
- existing[key.environment] = value;
7075
- }
7076
- await SiteEnv.writeValues(result);
7077
- fs19.writeFile(
6950
+ fs18.writeFile(
7078
6951
  path20.join(project.paths.out, "outputs.json"),
7079
6952
  JSON.stringify(
7080
- pipe3(
7081
- results,
7082
- omitBy2((_, key) => key.includes("SstSiteEnv")),
7083
- mapValues((val) => val.outputs)
7084
- ),
6953
+ mapValues(results, (val) => val.outputs),
7085
6954
  null,
7086
6955
  2
7087
6956
  )
@@ -7093,7 +6962,7 @@ var dev = (program2) => program2.command(
7093
6962
  async function checksum(cdkOutPath) {
7094
6963
  const manifestPath = path20.join(cdkOutPath, "manifest.json");
7095
6964
  const cdkManifest = JSON.parse(
7096
- await fs19.readFile(manifestPath).then((x) => x.toString())
6965
+ await fs18.readFile(manifestPath).then((x) => x.toString())
7097
6966
  );
7098
6967
  const checksumData = await Promise.all(
7099
6968
  Object.keys(cdkManifest.artifacts).filter(
@@ -7101,7 +6970,7 @@ var dev = (program2) => program2.command(
7101
6970
  ).map(async (key) => {
7102
6971
  const { templateFile } = cdkManifest.artifacts[key].properties;
7103
6972
  const templatePath = path20.join(cdkOutPath, templateFile);
7104
- const templateContent = await fs19.readFile(templatePath);
6973
+ const templateContent = await fs18.readFile(templatePath);
7105
6974
  return templateContent;
7106
6975
  })
7107
6976
  ).then((x) => x.join("\n"));
@@ -7192,37 +7061,231 @@ Are you sure you want to run this stage in dev mode? [y/N] `,
7192
7061
 
7193
7062
  // src/cli/commands/bind.ts
7194
7063
  init_error();
7064
+ import path18 from "path";
7065
+ var SITE_CONFIG = {
7066
+ NextjsSite: "next.config",
7067
+ AstroSite: "astro.config",
7068
+ RemixSite: "remix.config",
7069
+ SolidStartSite: "vite.config",
7070
+ StaticSite: "vite.config",
7071
+ SlsNextjsSite: "next.config"
7072
+ };
7195
7073
  var bind = (program2) => program2.command(
7196
- "bind <command..>",
7074
+ ["bind <command..>", "env <command..>"],
7197
7075
  "Bind your app's resources to a command",
7198
7076
  (yargs2) => yargs2.array("command").example(`sst bind "vitest run"`, "Bind your resources to your tests").example(
7199
7077
  `sst bind "tsx scripts/myscript.ts"`,
7200
7078
  "Bind your resources to a script"
7201
7079
  ),
7202
7080
  async (args) => {
7203
- const { Config: Config2 } = await Promise.resolve().then(() => (init_config(), config_exports));
7204
- const { spawnSync } = await import("child_process");
7205
- const { useAWSCredentials: useAWSCredentials3 } = await Promise.resolve().then(() => (init_credentials(), credentials_exports));
7081
+ const { spawn: spawn7 } = await import("child_process");
7206
7082
  const { useProject: useProject2 } = await Promise.resolve().then(() => (init_project(), project_exports));
7207
- const env2 = await Config2.env();
7083
+ const { useBus: useBus2 } = await Promise.resolve().then(() => (init_bus(), bus_exports));
7084
+ const { useIOT: useIOT2 } = await Promise.resolve().then(() => (init_iot(), iot_exports));
7085
+ const { Colors: Colors2 } = await Promise.resolve().then(() => (init_colors(), colors_exports));
7086
+ if (args._[0] === "env") {
7087
+ Colors2.line(
7088
+ Colors2.warning(
7089
+ `Warning: ${Colors2.bold(
7090
+ `sst env`
7091
+ )} has been renamed to ${Colors2.bold(`sst bind`)}`
7092
+ )
7093
+ );
7094
+ }
7095
+ await useIOT2();
7096
+ const bus = useBus2();
7208
7097
  const project = useProject2();
7209
- const credentials = await useAWSCredentials3();
7210
- const joined = args.command?.join(" ");
7211
- if (!joined)
7212
- throw new VisibleError("Command is required, e.g. sst bind env");
7213
- const result = spawnSync(joined, {
7214
- env: {
7215
- ...process.env,
7216
- ...env2,
7098
+ const command = args.command?.join(" ");
7099
+ const isFrontend = await isRunningInFrontend();
7100
+ let p;
7101
+ let timer;
7102
+ let metadataCache;
7103
+ if (!command) {
7104
+ throw new VisibleError(
7105
+ `Command is required, e.g. sst bind ${isFrontend ? "next dev" : "env"}`
7106
+ );
7107
+ }
7108
+ const initialMetadata = await getSiteMetadata();
7109
+ if (!initialMetadata) {
7110
+ return await bindScript();
7111
+ }
7112
+ await bindSite("init");
7113
+ bus.subscribe(
7114
+ "stacks.metadata.updated",
7115
+ () => bindSite("metadata_updated")
7116
+ );
7117
+ bus.subscribe(
7118
+ "stacks.metadata.deleted",
7119
+ () => bindSite("metadata_updated")
7120
+ );
7121
+ bus.subscribe("config.secret.updated", (payload) => {
7122
+ const secretName = payload.properties.name;
7123
+ if (metadataCache?.secrets === void 0)
7124
+ return;
7125
+ if (!metadataCache.secrets.includes(secretName))
7126
+ return;
7127
+ Colors2.line(
7128
+ `
7129
+ `,
7130
+ `SST secrets have been updated. Restarting \`${command}\`...`
7131
+ );
7132
+ bindSite("secrets_updated");
7133
+ });
7134
+ async function isRunningInFrontend() {
7135
+ const { existsAsync: existsAsync3 } = await Promise.resolve().then(() => (init_fs(), fs_exports));
7136
+ const results = await Promise.all(
7137
+ Object.values(SITE_CONFIG).map(
7138
+ (config) => [".js", ".cjs", ".mjs", ".ts"].map(
7139
+ (ext) => existsAsync3(`${config}${ext}`)
7140
+ )
7141
+ ).flat()
7142
+ );
7143
+ return results.some(Boolean);
7144
+ }
7145
+ async function bindSite(reason) {
7146
+ const metadata3 = reason === "init" ? initialMetadata : await getSiteMetadata();
7147
+ if (reason === "metadata_updated") {
7148
+ if (areEnvsSame(metadata3.envs, metadataCache?.envs || {}))
7149
+ return;
7150
+ Colors2.line(
7151
+ `
7152
+ `,
7153
+ `SST resources have been updated. Restarting \`${command}\`...`
7154
+ );
7155
+ }
7156
+ metadataCache = metadata3;
7157
+ if (metadata3.role) {
7158
+ const credentials = await assumeSsrRole(metadata3.role);
7159
+ if (credentials) {
7160
+ const expireAt = credentials.Expiration.getTime() - 6e4;
7161
+ clearTimeout(timer);
7162
+ timer = setTimeout(() => {
7163
+ Colors2.line(
7164
+ `
7165
+ `,
7166
+ `Your AWS session is about to expire. Creating a new session and restarting \`${command}\`...`
7167
+ );
7168
+ bindSite("iam_expired");
7169
+ }, expireAt - Date.now());
7170
+ runCommand({
7171
+ ...metadata3.envs,
7172
+ AWS_ACCESS_KEY_ID: credentials.AccessKeyId,
7173
+ AWS_SECRET_ACCESS_KEY: credentials.SecretAccessKey,
7174
+ AWS_SESSION_TOKEN: credentials.SessionToken
7175
+ });
7176
+ return;
7177
+ }
7178
+ }
7179
+ runCommand({
7180
+ ...metadata3.envs,
7181
+ ...await localIamCredentials()
7182
+ });
7183
+ }
7184
+ async function bindScript() {
7185
+ const { Config: Config2 } = await Promise.resolve().then(() => (init_config(), config_exports));
7186
+ runCommand({
7187
+ ...await Config2.env(),
7188
+ ...await localIamCredentials()
7189
+ });
7190
+ }
7191
+ async function getSiteMetadata() {
7192
+ const { metadata: metadata3 } = await Promise.resolve().then(() => (init_metadata(), metadata_exports));
7193
+ const { createSpinner: createSpinner2 } = await Promise.resolve().then(() => (init_spinner(), spinner_exports));
7194
+ const { LambdaClient: LambdaClient2, GetFunctionCommand } = await import("@aws-sdk/client-lambda");
7195
+ const { useAWSClient: useAWSClient2 } = await Promise.resolve().then(() => (init_credentials(), credentials_exports));
7196
+ const spinner = createSpinner2({});
7197
+ while (true) {
7198
+ const metadataData = await metadata3();
7199
+ const data2 = Object.values(metadataData).flat().filter(
7200
+ (c) => Boolean(c)
7201
+ ).filter((c) => Boolean(SITE_CONFIG[c.type])).find(
7202
+ (c) => path18.resolve(project.paths.root, c.data.path) === process.cwd()
7203
+ );
7204
+ if (!data2 && !isFrontend) {
7205
+ return;
7206
+ }
7207
+ if (!data2) {
7208
+ spinner.start(
7209
+ "Make sure `sst dev` is running..."
7210
+ );
7211
+ await new Promise((resolve) => setTimeout(resolve, 1e3));
7212
+ continue;
7213
+ }
7214
+ const isBindSupported = data2.type !== "StaticSite" && data2.type !== "SlsNextjsSite";
7215
+ if (isBindSupported && !data2.data.server || !isBindSupported && !data2.data.environment) {
7216
+ spinner.start(
7217
+ "This was deployed with an old version of SST. Make sure to restart `sst dev`..."
7218
+ );
7219
+ await new Promise((resolve) => setTimeout(resolve, 1e3));
7220
+ continue;
7221
+ }
7222
+ spinner.isSpinning && spinner.stop().clear();
7223
+ if (!isBindSupported) {
7224
+ return { envs: data2.data.environment };
7225
+ }
7226
+ const lambda = useAWSClient2(LambdaClient2);
7227
+ const { Configuration: functionConfig } = await lambda.send(
7228
+ new GetFunctionCommand({
7229
+ FunctionName: data2.data.server
7230
+ })
7231
+ );
7232
+ return {
7233
+ role: functionConfig?.Role,
7234
+ envs: functionConfig?.Environment?.Variables || {},
7235
+ secrets: data2.data.secrets
7236
+ };
7237
+ }
7238
+ }
7239
+ async function assumeSsrRole(roleArn) {
7240
+ const { STSClient: STSClient2, AssumeRoleCommand } = await import("@aws-sdk/client-sts");
7241
+ const { Logger: Logger2 } = await Promise.resolve().then(() => (init_logger(), logger_exports));
7242
+ const { useAWSClient: useAWSClient2 } = await Promise.resolve().then(() => (init_credentials(), credentials_exports));
7243
+ const sts = useAWSClient2(STSClient2);
7244
+ try {
7245
+ const { Credentials: credentials } = await sts.send(
7246
+ new AssumeRoleCommand({
7247
+ RoleArn: roleArn,
7248
+ RoleSessionName: "dev-session",
7249
+ DurationSeconds: 43200
7250
+ })
7251
+ );
7252
+ return credentials;
7253
+ } catch (e) {
7254
+ Colors2.line(
7255
+ Colors2.warning(
7256
+ `Failed to assume SSR role ${roleArn}. Falling back to using local IAM credentials.`
7257
+ )
7258
+ );
7259
+ Logger2.debug(`Failed to assume ${roleArn}.`, e);
7260
+ }
7261
+ }
7262
+ async function localIamCredentials() {
7263
+ const { useAWSCredentials: useAWSCredentials3 } = await Promise.resolve().then(() => (init_credentials(), credentials_exports));
7264
+ const credentials = await useAWSCredentials3();
7265
+ return {
7217
7266
  AWS_ACCESS_KEY_ID: credentials.accessKeyId,
7218
7267
  AWS_SECRET_ACCESS_KEY: credentials.secretAccessKey,
7219
- AWS_SESSION_TOKEN: credentials.sessionToken,
7220
- AWS_REGION: project.config.region
7221
- },
7222
- stdio: "inherit",
7223
- shell: true
7224
- });
7225
- process.exitCode = result.status || void 0;
7268
+ AWS_SESSION_TOKEN: credentials.sessionToken
7269
+ };
7270
+ }
7271
+ function runCommand(envs) {
7272
+ Colors2.gap();
7273
+ if (p) {
7274
+ p.kill();
7275
+ }
7276
+ p = spawn7(command, {
7277
+ env: {
7278
+ ...process.env,
7279
+ ...envs,
7280
+ AWS_REGION: project.config.region
7281
+ },
7282
+ stdio: "inherit",
7283
+ shell: true
7284
+ });
7285
+ }
7286
+ function areEnvsSame(envs1, envs2) {
7287
+ return Object.keys(envs1).length === Object.keys(envs2).length && Object.keys(envs1).every((key) => envs1[key] === envs2[key]);
7288
+ }
7226
7289
  }
7227
7290
  ).strict(false);
7228
7291
 
@@ -7257,7 +7320,7 @@ var build = (program2) => program2.command(
7257
7320
  // src/cli/commands/deploy.tsx
7258
7321
  init_credentials();
7259
7322
  init_colors();
7260
- import fs18 from "fs/promises";
7323
+ import fs17 from "fs/promises";
7261
7324
  import path19 from "path";
7262
7325
  var deploy2 = (program2) => program2.command(
7263
7326
  "deploy [filter]",
@@ -7346,7 +7409,7 @@ Are you sure you want to deploy to this stage? (y/N) `,
7346
7409
  printDeploymentResults2(assembly, results);
7347
7410
  if (Object.values(results).some((stack) => Stacks.isFailed(stack.status)))
7348
7411
  process.exit(1);
7349
- fs18.writeFile(
7412
+ fs17.writeFile(
7350
7413
  path19.join(project.paths.out, "outputs.json"),
7351
7414
  JSON.stringify(
7352
7415
  mapValues(results, (val) => val.outputs),
@@ -7494,14 +7557,14 @@ var list = (program2) => program2.command(
7494
7557
  }
7495
7558
  break;
7496
7559
  case "table":
7497
- const keys2 = Object.keys(secrets2);
7560
+ const keys = Object.keys(secrets2);
7498
7561
  const keyLen = Math.max(
7499
7562
  "Secrets".length,
7500
- ...keys2.map((key) => key.length)
7563
+ ...keys.map((key) => key.length)
7501
7564
  );
7502
7565
  const valueLen = Math.max(
7503
7566
  "Values".length,
7504
- ...keys2.map(
7567
+ ...keys.map(
7505
7568
  (key) => secrets2[key].value ? secrets2[key].value.length : `${secrets2[key].fallback} (fallback)`.length
7506
7569
  )
7507
7570
  );
@@ -7514,7 +7577,7 @@ var list = (program2) => program2.command(
7514
7577
  console.log(
7515
7578
  "\u251C".padEnd(keyLen + 3, "\u2500") + "\u253C" + "".padEnd(valueLen + 2, "\u2500") + "\u2524"
7516
7579
  );
7517
- keys2.sort().forEach((key) => {
7580
+ keys.sort().forEach((key) => {
7518
7581
  const value = secrets2[key].value ? secrets2[key].value : `${secrets2[key].fallback} ${gray("(fallback)")}`;
7519
7582
  console.log(
7520
7583
  `\u2502 ${key.padEnd(keyLen)} \u2502 ${value.padEnd(valueLen)} \u2502`
@@ -7573,6 +7636,7 @@ var set = (program2) => program2.command(
7573
7636
  }),
7574
7637
  async (args) => {
7575
7638
  const { Config: Config2 } = await Promise.resolve().then(() => (init_config(), config_exports));
7639
+ const { Colors: Colors2 } = await Promise.resolve().then(() => (init_colors(), colors_exports));
7576
7640
  const { blue: blue4 } = await import("colorette");
7577
7641
  const { createSpinner: createSpinner2 } = await Promise.resolve().then(() => (init_spinner(), spinner_exports));
7578
7642
  const setting = createSpinner2(` Setting "${args.name}"`).start();
@@ -7583,12 +7647,31 @@ var set = (program2) => program2.command(
7583
7647
  });
7584
7648
  setting.succeed();
7585
7649
  const restarting = createSpinner2(
7586
- ` Restarting all functions using ${blue4(args.name)}...`
7650
+ ` Reloading all resources using ${blue4(args.name)}...`
7587
7651
  ).start();
7588
- const count = await Config2.restart(args.name);
7589
- restarting.succeed(
7590
- count === 1 ? ` Restarted ${count} function` : ` Restarted ${count} functions`
7591
- );
7652
+ const { edgeSites, sites, placeholderSites, functions } = await Config2.restart(args.name);
7653
+ restarting.stop().clear();
7654
+ const siteCount = sites.length + placeholderSites.length;
7655
+ if (siteCount > 0) {
7656
+ Colors2.line(
7657
+ Colors2.success(`\u2714 `),
7658
+ siteCount === 1 ? `Reloaded ${siteCount} site` : `Reloaded ${siteCount} sites`
7659
+ );
7660
+ }
7661
+ const functionCount = functions.length;
7662
+ if (functionCount > 0) {
7663
+ Colors2.line(
7664
+ Colors2.success(`\u2714 `),
7665
+ functionCount === 1 ? `Reloaded ${functionCount} function` : `Reloaded ${functionCount} functions`
7666
+ );
7667
+ }
7668
+ edgeSites.forEach(({ id, type }) => {
7669
+ Colors2.line(
7670
+ Colors2.danger(`\u279C `),
7671
+ `Redeploy the "${id}" ${type} to use the new secret`
7672
+ );
7673
+ });
7674
+ process.exit(0);
7592
7675
  }
7593
7676
  );
7594
7677
 
@@ -7616,13 +7699,13 @@ var update = (program2) => program2.command(
7616
7699
  }),
7617
7700
  async (args) => {
7618
7701
  const { green, yellow } = await import("colorette");
7619
- const fs19 = await import("fs/promises");
7702
+ const fs18 = await import("fs/promises");
7620
7703
  const path20 = await import("path");
7621
7704
  const { fetch } = await import("undici");
7622
7705
  const { useProject: useProject2 } = await Promise.resolve().then(() => (init_project(), project_exports));
7623
7706
  const { Colors: Colors2 } = await Promise.resolve().then(() => (init_colors(), colors_exports));
7624
7707
  async function find2(dir) {
7625
- const children = await fs19.readdir(dir);
7708
+ const children = await fs18.readdir(dir);
7626
7709
  const tasks2 = children.map(async (item) => {
7627
7710
  if (item === "node_modules")
7628
7711
  return [];
@@ -7631,7 +7714,7 @@ var update = (program2) => program2.command(
7631
7714
  const full = path20.join(dir, item);
7632
7715
  if (item === "package.json")
7633
7716
  return [full];
7634
- const stat = await fs19.stat(full);
7717
+ const stat = await fs18.stat(full);
7635
7718
  if (stat.isDirectory())
7636
7719
  return find2(full);
7637
7720
  return [];
@@ -7645,7 +7728,7 @@ var update = (program2) => program2.command(
7645
7728
  ).then((resp) => resp.json());
7646
7729
  const results = /* @__PURE__ */ new Map();
7647
7730
  const tasks = files.map(async (file) => {
7648
- const data2 = await fs19.readFile(file).then((x) => x.toString()).then(JSON.parse);
7731
+ const data2 = await fs18.readFile(file).then((x) => x.toString()).then(JSON.parse);
7649
7732
  for (const field of FIELDS) {
7650
7733
  const deps = data2[field];
7651
7734
  if (!deps)
@@ -7674,7 +7757,7 @@ var update = (program2) => program2.command(
7674
7757
  }
7675
7758
  }
7676
7759
  if (results.has(file)) {
7677
- await fs19.writeFile(file, JSON.stringify(data2, null, 2));
7760
+ await fs18.writeFile(file, JSON.stringify(data2, null, 2));
7678
7761
  }
7679
7762
  });
7680
7763
  await Promise.all(tasks);
@@ -7907,7 +7990,6 @@ dev(program);
7907
7990
  deploy2(program);
7908
7991
  build(program);
7909
7992
  bind(program);
7910
- env(program);
7911
7993
  secrets(program);
7912
7994
  remove2(program);
7913
7995
  update(program);