sst 2.2.8 → 2.3.0

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