sst 2.5.4 → 2.5.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/cli/commands/bind.js +89 -64
  2. package/cli/commands/version.js +1 -0
  3. package/config.js +10 -10
  4. package/constructs/Api.d.ts +1 -1
  5. package/constructs/Api.js +1 -1
  6. package/constructs/ApiGatewayV1Api.d.ts +1 -1
  7. package/constructs/ApiGatewayV1Api.js +1 -1
  8. package/constructs/AppSyncApi.d.ts +1 -1
  9. package/constructs/AppSyncApi.js +1 -1
  10. package/constructs/Auth.d.ts +1 -1
  11. package/constructs/Auth.js +1 -1
  12. package/constructs/Bucket.d.ts +1 -1
  13. package/constructs/Bucket.js +1 -1
  14. package/constructs/Cognito.d.ts +1 -1
  15. package/constructs/Cognito.js +1 -1
  16. package/constructs/Cron.d.ts +1 -1
  17. package/constructs/Cron.js +1 -1
  18. package/constructs/EventBus.d.ts +1 -1
  19. package/constructs/EventBus.js +1 -1
  20. package/constructs/Function.d.ts +1 -1
  21. package/constructs/Function.js +1 -1
  22. package/constructs/Job.d.ts +38 -2
  23. package/constructs/Job.js +4 -2
  24. package/constructs/KinesisStream.d.ts +1 -1
  25. package/constructs/KinesisStream.js +1 -1
  26. package/constructs/Parameter.d.ts +1 -1
  27. package/constructs/Parameter.js +1 -1
  28. package/constructs/Queue.d.ts +1 -1
  29. package/constructs/Queue.js +1 -1
  30. package/constructs/RDS.d.ts +2 -2
  31. package/constructs/RDS.js +1 -1
  32. package/constructs/Script.d.ts +2 -2
  33. package/constructs/Script.js +1 -1
  34. package/constructs/Secret.d.ts +1 -1
  35. package/constructs/Secret.js +1 -1
  36. package/constructs/SsrSite.js +5 -1
  37. package/constructs/Stack.d.ts +1 -1
  38. package/constructs/Stack.js +1 -1
  39. package/constructs/StaticSite.d.ts +1 -1
  40. package/constructs/StaticSite.js +1 -1
  41. package/constructs/Table.d.ts +1 -1
  42. package/constructs/Table.js +1 -1
  43. package/constructs/Topic.d.ts +1 -1
  44. package/constructs/Topic.js +1 -1
  45. package/constructs/WebSocketApi.d.ts +1 -1
  46. package/constructs/WebSocketApi.js +1 -1
  47. package/constructs/future/Auth.d.ts +1 -1
  48. package/constructs/future/Auth.js +1 -1
  49. package/package.json +1 -1
  50. package/project.d.ts +7 -0
  51. package/project.js +35 -8
  52. package/sst.mjs +126 -82
  53. package/support/bootstrap-metadata-function/index.mjs +238 -238
  54. package/support/custom-resources/index.mjs +238 -238
package/sst.mjs CHANGED
@@ -317,6 +317,7 @@ var init_build = __esm({
317
317
  var project_exports = {};
318
318
  __export(project_exports, {
319
319
  ProjectContext: () => ProjectContext,
320
+ exportedForTesting: () => exportedForTesting,
320
321
  initProject: () => initProject,
321
322
  useProject: () => useProject
322
323
  });
@@ -353,14 +354,18 @@ async function initProject(globals) {
353
354
  }();
354
355
  const config = await Promise.resolve(sstConfig.config(globals));
355
356
  const stage = globals.stage || config.stage || await usePersonalStage(out) || await promptPersonalStage(out);
356
- const [version2, cdkVersion] = await (async () => {
357
+ const [version2, cdkVersion, constructsVersion] = await (async () => {
357
358
  try {
358
359
  const packageJson = JSON.parse(
359
360
  await fs4.readFile(
360
361
  url2.fileURLToPath(new URL("./package.json", import.meta.url))
361
362
  ).then((x) => x.toString())
362
363
  );
363
- return [packageJson.version, packageJson.dependencies["aws-cdk-lib"]];
364
+ return [
365
+ packageJson.version,
366
+ packageJson.dependencies["aws-cdk-lib"],
367
+ packageJson.dependencies["constructs"]
368
+ ];
364
369
  } catch {
365
370
  return ["unknown", "unknown"];
366
371
  }
@@ -368,6 +373,7 @@ async function initProject(globals) {
368
373
  const project = {
369
374
  version: version2,
370
375
  cdkVersion,
376
+ constructsVersion,
371
377
  config: {
372
378
  ...config,
373
379
  stage,
@@ -415,26 +421,29 @@ async function usePersonalStage(out) {
415
421
  return;
416
422
  }
417
423
  }
418
- async function promptPersonalStage(out) {
424
+ async function promptPersonalStage(out, isRetry) {
419
425
  const readline = await import("readline");
420
426
  const rl = readline.createInterface({
421
427
  input: process.stdin,
422
428
  output: process.stdout
423
429
  });
424
- return new Promise((resolve) => {
425
- const suggested = os.userInfo().username;
430
+ const stage = await new Promise((resolve) => {
431
+ const suggested = sanitizeStageName(os.userInfo().username) || "local";
432
+ const instruction = !isRetry ? `Please enter a name you\u2019d like to use for your personal stage.` : `Please enter a name that starts with a letter, followed by letters, numbers, or hyphens.`;
426
433
  rl.question(
427
- `Please enter a name you\u2019d like to use for your personal stage. Or hit enter to use ${blue(
428
- suggested
429
- )}: `,
434
+ `${instruction} Or hit enter to use ${blue(suggested)}: `,
430
435
  async (input) => {
431
436
  rl.close();
432
- const result = input || suggested;
433
- await fs4.writeFile(path4.join(out, "stage"), result);
437
+ const result = input === "" ? suggested : input;
434
438
  resolve(result);
435
439
  }
436
440
  );
437
441
  });
442
+ if (isValidStageName(stage)) {
443
+ await fs4.writeFile(path4.join(out, "stage"), stage);
444
+ return stage;
445
+ }
446
+ return await promptPersonalStage(out, true);
438
447
  }
439
448
  async function findRoot() {
440
449
  async function find2(dir) {
@@ -455,7 +464,13 @@ async function findRoot() {
455
464
  const result = await find2(process.cwd());
456
465
  return result;
457
466
  }
458
- var ProjectContext, CONFIG_EXTENSIONS;
467
+ function sanitizeStageName(stage) {
468
+ return stage.replace(/[^A-Za-z0-9-]/g, "-").replace(/--+/g, "-").replace(/^[^A-Za-z]/, "").replace(/-$/, "") || "local";
469
+ }
470
+ function isValidStageName(stage) {
471
+ return Boolean(stage.match(/^[A-Za-z][A-Za-z0-9-]*$/));
472
+ }
473
+ var ProjectContext, CONFIG_EXTENSIONS, exportedForTesting;
459
474
  var init_project = __esm({
460
475
  "src/project.ts"() {
461
476
  "use strict";
@@ -472,6 +487,10 @@ var init_project = __esm({
472
487
  ".config.mjs",
473
488
  ".config.js"
474
489
  ];
490
+ exportedForTesting = {
491
+ sanitizeStageName,
492
+ isValidStageName
493
+ };
475
494
  }
476
495
  });
477
496
 
@@ -6518,12 +6537,12 @@ async function* scan(prefix) {
6518
6537
  token = results.NextToken;
6519
6538
  }
6520
6539
  }
6521
- function parse(ssmName) {
6522
- const parts = ssmName.split("/");
6540
+ function parse(ssmName, prefix) {
6541
+ const parts = ssmName.substring(prefix.length).split("/");
6523
6542
  return {
6524
- type: parts[4],
6525
- id: parts[5],
6526
- prop: parts.slice(6).join("/")
6543
+ type: parts[0],
6544
+ id: parts[1],
6545
+ prop: parts.slice(2).join("/")
6527
6546
  };
6528
6547
  }
6529
6548
  async function restartFunction(arn) {
@@ -6564,7 +6583,7 @@ var init_config = __esm({
6564
6583
  async function parameters() {
6565
6584
  const result = [];
6566
6585
  for await (const p of scan(PREFIX.FALLBACK)) {
6567
- const parsed = parse(p.Name);
6586
+ const parsed = parse(p.Name, PREFIX.FALLBACK);
6568
6587
  if (parsed.type === "secrets")
6569
6588
  continue;
6570
6589
  result.push({
@@ -6573,7 +6592,7 @@ var init_config = __esm({
6573
6592
  });
6574
6593
  }
6575
6594
  for await (const p of scan(PREFIX.STAGE)) {
6576
- const parsed = parse(p.Name);
6595
+ const parsed = parse(p.Name, PREFIX.STAGE);
6577
6596
  if (parsed.type === "secrets")
6578
6597
  continue;
6579
6598
  result.push({
@@ -6599,13 +6618,13 @@ var init_config = __esm({
6599
6618
  async function secrets2() {
6600
6619
  const result = {};
6601
6620
  for await (const p of scan(PREFIX.STAGE + "Secret")) {
6602
- const parsed = parse(p.Name);
6621
+ const parsed = parse(p.Name, PREFIX.STAGE);
6603
6622
  if (!result[parsed.id])
6604
6623
  result[parsed.id] = {};
6605
6624
  result[parsed.id].value = p.Value;
6606
6625
  }
6607
6626
  for await (const p of scan(PREFIX.FALLBACK + "Secret")) {
6608
- const parsed = parse(p.Name);
6627
+ const parsed = parse(p.Name, PREFIX.FALLBACK);
6609
6628
  if (!result[parsed.id])
6610
6629
  result[parsed.id] = {};
6611
6630
  result[parsed.id].fallback = p.Value;
@@ -6716,7 +6735,7 @@ var init_config = __esm({
6716
6735
  PREFIX = {
6717
6736
  get STAGE() {
6718
6737
  const project = useProject();
6719
- return `/sst/${project.config.name}/${project.config.stage}/`;
6738
+ return project.config.ssmPrefix;
6720
6739
  },
6721
6740
  get FALLBACK() {
6722
6741
  const project = useProject();
@@ -7113,12 +7132,7 @@ Are you sure you want to run this stage in dev mode? [y/N] `,
7113
7132
  // src/cli/commands/bind.ts
7114
7133
  init_error();
7115
7134
  import path18 from "path";
7116
- var SSR_SITE_CONFIG = {
7117
- NextjsSite: "next.config",
7118
- AstroSite: "astro.config",
7119
- RemixSite: "remix.config",
7120
- SolidStartSite: "vite.config",
7121
- SlsNextjsSite: "next.config"
7135
+ var OutdatedMetadataError = class extends Error {
7122
7136
  };
7123
7137
  var bind = (program2) => program2.command(
7124
7138
  ["bind <command..>", "env <command..>"],
@@ -7147,21 +7161,32 @@ var bind = (program2) => program2.command(
7147
7161
  const bus = useBus2();
7148
7162
  const project = useProject2();
7149
7163
  const command = args.command?.join(" ");
7150
- const isSsrSite = await isRunningInSsrSite();
7164
+ const isSite = await isRunningInSite();
7151
7165
  let p;
7152
7166
  let timer;
7153
7167
  let siteConfigCache;
7154
7168
  if (!command) {
7155
7169
  throw new VisibleError(
7156
- `Command is required, e.g. sst bind ${isSsrSite ? "next dev" : "env"}`
7170
+ `Command is required, e.g. sst bind ${isSite ? "next dev" : "vitest run"}`
7157
7171
  );
7158
7172
  }
7159
- const initialMetadata = await getSiteMetadata();
7160
- if (!initialMetadata && !isSsrSite) {
7173
+ if (!isSite) {
7161
7174
  Logger2.debug("Running in script mode.");
7162
7175
  return await bindScript();
7163
7176
  }
7164
- await bindSite("init");
7177
+ try {
7178
+ await bindSite("init");
7179
+ } catch (e) {
7180
+ if (e instanceof OutdatedMetadataError) {
7181
+ Colors2.line(
7182
+ Colors2.warning(
7183
+ "Warning: This was deployed with an old version of SST. Run `sst dev` or `sst deploy` to update."
7184
+ )
7185
+ );
7186
+ return await bindScript();
7187
+ }
7188
+ throw e;
7189
+ }
7165
7190
  bus.subscribe(
7166
7191
  "stacks.metadata.updated",
7167
7192
  () => bindSite("metadata_updated")
@@ -7172,9 +7197,7 @@ var bind = (program2) => program2.command(
7172
7197
  );
7173
7198
  bus.subscribe("config.secret.updated", (payload) => {
7174
7199
  const secretName = payload.properties.name;
7175
- if (siteConfigCache?.secrets === void 0)
7176
- return;
7177
- if (!siteConfigCache.secrets.includes(secretName))
7200
+ if (!(siteConfigCache?.secrets || []).includes(secretName))
7178
7201
  return;
7179
7202
  Colors2.line(
7180
7203
  `
@@ -7183,26 +7206,47 @@ var bind = (program2) => program2.command(
7183
7206
  );
7184
7207
  bindSite("secrets_updated");
7185
7208
  });
7186
- async function isRunningInSsrSite() {
7209
+ async function isRunningInSite() {
7187
7210
  const { existsAsync: existsAsync3 } = await Promise.resolve().then(() => (init_fs(), fs_exports));
7188
7211
  const { readFile } = await import("fs/promises");
7212
+ const SITE_CONFIGS = [
7213
+ { file: "next.config", multiExtension: true },
7214
+ { file: "astro.config", multiExtension: true },
7215
+ { file: "remix.config", multiExtension: true },
7216
+ { file: "svelte.config", multiExtension: true },
7217
+ { file: "gatsby-config", multiExtension: true },
7218
+ { file: "angular.json" },
7219
+ { file: "ember-cli-build.js" },
7220
+ {
7221
+ file: "vite.config",
7222
+ multiExtension: true,
7223
+ match: /solid-start|plugin-vue|plugin-react|@preact\/preset-vite/
7224
+ },
7225
+ { file: "package.json", match: /react-scripts/ },
7226
+ { file: "index.html" }
7227
+ ];
7189
7228
  const results = await Promise.all(
7190
- Object.values(SSR_SITE_CONFIG).map(
7191
- (config) => [".js", ".cjs", ".mjs", ".ts"].map(async (ext) => {
7192
- const exists = await existsAsync3(`${config}${ext}`);
7193
- if (exists && config === "vite.config") {
7194
- const content = await readFile(`${config}${ext}`);
7195
- return content.includes("solid-start");
7229
+ SITE_CONFIGS.map((site) => {
7230
+ const files = site.multiExtension ? [".js", ".cjs", ".mjs", ".ts"].map(
7231
+ (ext) => `${site.file}${ext}`
7232
+ ) : [site.file];
7233
+ return files.map(async (file) => {
7234
+ const exists = await existsAsync3(file);
7235
+ if (!exists)
7236
+ return false;
7237
+ if (site.match) {
7238
+ const content = await readFile(file);
7239
+ return content.toString().match(site.match);
7196
7240
  }
7197
- return exists;
7198
- })
7199
- ).flat()
7241
+ return true;
7242
+ });
7243
+ }).flat()
7200
7244
  );
7201
7245
  return results.some(Boolean);
7202
7246
  }
7203
7247
  async function bindSite(reason) {
7204
- const siteMetadata = reason === "init" ? initialMetadata : await getSiteMetadataUntilAvailable();
7205
- const siteConfig = await parseSiteConfig(siteMetadata);
7248
+ const siteMetadata = await getSiteMetadataUntilAvailable();
7249
+ const siteConfig = await parseSiteMetadata(siteMetadata);
7206
7250
  if (reason === "metadata_updated") {
7207
7251
  if (areEnvsSame(siteConfig.envs, siteConfigCache?.envs || {}))
7208
7252
  return;
@@ -7247,42 +7291,13 @@ var bind = (program2) => program2.command(
7247
7291
  ...await localIamCredentials()
7248
7292
  });
7249
7293
  }
7250
- async function parseSiteConfig(metadata3) {
7251
- const { LambdaClient: LambdaClient2, GetFunctionCommand } = await import("@aws-sdk/client-lambda");
7252
- const { useAWSClient: useAWSClient2 } = await Promise.resolve().then(() => (init_credentials(), credentials_exports));
7253
- const isBindSupported = metadata3.type !== "StaticSite" && metadata3.type !== "SlsNextjsSite";
7254
- if (!isBindSupported) {
7255
- return { envs: metadata3.data.environment };
7256
- }
7257
- const lambda = useAWSClient2(LambdaClient2);
7258
- const { Configuration: functionConfig } = await lambda.send(
7259
- new GetFunctionCommand({
7260
- FunctionName: metadata3.data.server
7261
- })
7262
- );
7263
- return {
7264
- role: functionConfig?.Role,
7265
- envs: functionConfig?.Environment?.Variables || {},
7266
- secrets: metadata3.data.secrets
7267
- };
7268
- }
7269
7294
  async function getSiteMetadataUntilAvailable() {
7270
7295
  const { createSpinner: createSpinner2 } = await Promise.resolve().then(() => (init_spinner(), spinner_exports));
7271
7296
  const spinner = createSpinner2({});
7272
7297
  while (true) {
7273
7298
  const data2 = await getSiteMetadata();
7274
7299
  if (!data2) {
7275
- spinner.start(
7276
- "Make sure `sst dev` is running..."
7277
- );
7278
- await new Promise((resolve) => setTimeout(resolve, 1e3));
7279
- continue;
7280
- }
7281
- const isBindSupported = data2.type !== "StaticSite" && data2.type !== "SlsNextjsSite";
7282
- if (isBindSupported && !data2.data.server || !isBindSupported && !data2.data.environment) {
7283
- spinner.start(
7284
- "This was deployed with an old version of SST. Make sure to restart `sst dev`..."
7285
- );
7300
+ spinner.start("Make sure `sst dev` is running...");
7286
7301
  await new Promise((resolve) => setTimeout(resolve, 1e3));
7287
7302
  continue;
7288
7303
  }
@@ -7294,12 +7309,40 @@ var bind = (program2) => program2.command(
7294
7309
  const { metadata: metadata3 } = await Promise.resolve().then(() => (init_metadata(), metadata_exports));
7295
7310
  const metadataData = await metadata3();
7296
7311
  return Object.values(metadataData).flat().filter(
7297
- (c) => Boolean(c)
7298
- ).filter(
7299
- (c) => c.type === "StaticSite" || Boolean(SSR_SITE_CONFIG[c.type])
7300
- ).find(
7301
- (c) => path18.resolve(project.paths.root, c.data.path) === process.cwd()
7312
+ (c) => [
7313
+ "StaticSite",
7314
+ "NextjsSite",
7315
+ "AstroSite",
7316
+ "RemixSite",
7317
+ "SolidStartSite",
7318
+ "SlsNextjsSite"
7319
+ ].includes(c.type)
7320
+ ).find((c) => {
7321
+ const isSsr = c.type !== "StaticSite" && c.type !== "SlsNextjsSite";
7322
+ if (!c.data.path || isSsr && !c.data.server || !isSsr && !c.data.environment) {
7323
+ throw new OutdatedMetadataError();
7324
+ }
7325
+ return path18.resolve(project.paths.root, c.data.path) === process.cwd();
7326
+ });
7327
+ }
7328
+ async function parseSiteMetadata(metadata3) {
7329
+ const { LambdaClient: LambdaClient2, GetFunctionCommand } = await import("@aws-sdk/client-lambda");
7330
+ const { useAWSClient: useAWSClient2 } = await Promise.resolve().then(() => (init_credentials(), credentials_exports));
7331
+ const isBindSupported = metadata3.type !== "StaticSite" && metadata3.type !== "SlsNextjsSite";
7332
+ if (!isBindSupported) {
7333
+ return { envs: metadata3.data.environment };
7334
+ }
7335
+ const lambda = useAWSClient2(LambdaClient2);
7336
+ const { Configuration: functionConfig } = await lambda.send(
7337
+ new GetFunctionCommand({
7338
+ FunctionName: metadata3.data.server
7339
+ })
7302
7340
  );
7341
+ return {
7342
+ role: functionConfig?.Role,
7343
+ envs: functionConfig?.Environment?.Variables || {},
7344
+ secrets: metadata3.data.secrets
7345
+ };
7303
7346
  }
7304
7347
  async function assumeSsrRole(roleArn) {
7305
7348
  const { STSClient: STSClient2, AssumeRoleCommand } = await import("@aws-sdk/client-sts");
@@ -8034,6 +8077,7 @@ var version = (program2) => program2.command(
8034
8077
  const project = useProject2();
8035
8078
  Colors2.line(Colors2.bold(`SST:`), `v${project.version}`);
8036
8079
  Colors2.line(Colors2.bold(`CDK:`), `v${project.cdkVersion}`);
8080
+ Colors2.line(Colors2.bold(`Constructs:`), `v${project.constructsVersion}`);
8037
8081
  }
8038
8082
  );
8039
8083