sst 2.0.12 → 2.0.14

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.
@@ -140,7 +140,6 @@ export declare class Job extends Construct implements SSTConstruct {
140
140
  private readonly localId;
141
141
  private readonly props;
142
142
  private readonly job;
143
- private readonly isLiveDevEnabled;
144
143
  readonly _jobInvoker: Function;
145
144
  constructor(scope: Construct, id: string, props: JobProps);
146
145
  getConstructMetadata(): {
package/constructs/Job.js CHANGED
@@ -3,9 +3,9 @@ import url from "url";
3
3
  import path from "path";
4
4
  import fs from "fs/promises";
5
5
  import { Construct } from "constructs";
6
- import * as iam from "aws-cdk-lib/aws-iam";
7
- import * as lambda from "aws-cdk-lib/aws-lambda";
8
- import * as codebuild from "aws-cdk-lib/aws-codebuild";
6
+ import { PolicyStatement, Effect } from "aws-cdk-lib/aws-iam";
7
+ import { AssetCode } from "aws-cdk-lib/aws-lambda";
8
+ import { Project, LinuxBuildImage, BuildSpec, ComputeType, } from "aws-cdk-lib/aws-codebuild";
9
9
  import { Stack } from "./Stack.js";
10
10
  import { Function, useFunctions } from "./Function.js";
11
11
  import { toCdkDuration } from "./util/duration.js";
@@ -37,7 +37,6 @@ export class Job extends Construct {
37
37
  localId;
38
38
  props;
39
39
  job;
40
- isLiveDevEnabled;
41
40
  _jobInvoker;
42
41
  constructor(scope, id, props) {
43
42
  super(scope, props.cdk?.id || id);
@@ -53,9 +52,9 @@ export class Job extends Construct {
53
52
  .replace(/\$/g, "-")
54
53
  .replace(/\//g, "-")
55
54
  .replace(/\./g, "-");
56
- this.isLiveDevEnabled = this.props.enableLiveDev === false ? false : true;
55
+ const isLiveDevEnabled = app.local && (this.props.enableLiveDev === false ? false : true);
57
56
  this.job = this.createCodeBuildProject();
58
- if (app.local && this.isLiveDevEnabled) {
57
+ if (isLiveDevEnabled) {
59
58
  this._jobInvoker = this.createLocalInvoker();
60
59
  }
61
60
  else {
@@ -129,7 +128,7 @@ export class Job extends Construct {
129
128
  }
130
129
  createCodeBuildProject() {
131
130
  const app = this.node.root;
132
- return new codebuild.Project(this, "JobProject", {
131
+ return new Project(this, "JobProject", {
133
132
  vpc: this.props.cdk?.vpc,
134
133
  projectName: app.logicalPrefixedName(this.node.id),
135
134
  environment: {
@@ -139,7 +138,7 @@ export class Job extends Construct {
139
138
  // purpose of this demo, I use STANDARD_5_0. It takes 30s to boot.
140
139
  //buildImage: codebuild.LinuxBuildImage.STANDARD_6_0,
141
140
  //buildImage: codebuild.LinuxBuildImage.STANDARD_5_0,
142
- buildImage: codebuild.LinuxBuildImage.fromDockerRegistry("amazon/aws-lambda-nodejs:16"),
141
+ buildImage: LinuxBuildImage.fromDockerRegistry("amazon/aws-lambda-nodejs:16"),
143
142
  computeType: this.normalizeMemorySize(this.props.memorySize || "3 GB"),
144
143
  },
145
144
  environmentVariables: {
@@ -148,7 +147,7 @@ export class Job extends Construct {
148
147
  SST_SSM_PREFIX: { value: useProject().config.ssmPrefix },
149
148
  },
150
149
  timeout: this.normalizeTimeout(this.props.timeout || "8 hours"),
151
- buildSpec: codebuild.BuildSpec.fromObject({
150
+ buildSpec: BuildSpec.fromObject({
152
151
  version: "0.2",
153
152
  phases: {
154
153
  build: {
@@ -163,54 +162,40 @@ export class Job extends Construct {
163
162
  buildCodeBuildProjectCode() {
164
163
  const app = this.node.root;
165
164
  // Handle remove (ie. sst remove)
166
- if (app.mode !== "deploy") {
167
- // do nothing
168
- }
169
- // Handle build
170
- else {
171
- useDeferredTasks().add(async () => {
172
- // Build function
173
- /*
174
- const bundled = await Runtime.Handler.bundle({
175
- id: this.localId,
176
- root: app.appPath,
177
- handler,
178
- runtime: "nodejs16.x",
179
- srcPath,
180
- bundle
181
- })!;
182
- */
183
- // TODO: Fix
184
- const bundle = await useRuntimeHandlers().build(this.node.addr, "deploy");
185
- // handle copy files
186
- // create wrapper that calls the handler
187
- if (bundle.type === "error")
188
- throw new Error(`Failed to build job "${this.props.handler}"`);
189
- const parsed = path.parse(bundle.handler);
190
- await fs.writeFile(path.join(bundle.out, "handler-wrapper.js"), [
191
- `console.log("")`,
192
- `console.log("//////////////////////")`,
193
- `console.log("// Start of the job //")`,
194
- `console.log("//////////////////////")`,
195
- `console.log("")`,
196
- `import { ${parsed.ext.substring(1)} } from "./${path.join(parsed.dir, parsed.name)}.mjs";`,
197
- `const event = JSON.parse(process.env.SST_PAYLOAD);`,
198
- `const result = await ${parsed.name}(event);`,
199
- `console.log("")`,
200
- `console.log("----------------------")`,
201
- `console.log("")`,
202
- `console.log("Result:", result);`,
203
- `console.log("")`,
204
- `console.log("//////////////////////")`,
205
- `console.log("// End of the job //")`,
206
- `console.log("//////////////////////")`,
207
- `console.log("")`,
208
- ].join("\n"));
209
- const code = lambda.AssetCode.fromAsset(bundle.out);
210
- this.updateCodeBuildProjectCode(code, "handler-wrapper.js");
211
- // This should always be true b/c runtime is always Node.js
212
- });
213
- }
165
+ if (app.mode === "remove")
166
+ return;
167
+ useDeferredTasks().add(async () => {
168
+ // Build function
169
+ const bundle = await useRuntimeHandlers().build(this.node.addr, "deploy");
170
+ // create wrapper that calls the handler
171
+ if (bundle.type === "error")
172
+ throw new Error(`Failed to build job "${this.props.handler}"`);
173
+ const parsed = path.parse(bundle.handler);
174
+ const importName = parsed.ext.substring(1);
175
+ const importPath = `./${path.join(parsed.dir, parsed.name)}.mjs`;
176
+ await fs.writeFile(path.join(bundle.out, "handler-wrapper.mjs"), [
177
+ `console.log("")`,
178
+ `console.log("//////////////////////")`,
179
+ `console.log("// Start of the job //")`,
180
+ `console.log("//////////////////////")`,
181
+ `console.log("")`,
182
+ `import { ${importName} } from "${importPath}";`,
183
+ `const event = JSON.parse(process.env.SST_PAYLOAD);`,
184
+ `const result = await ${importName}(event);`,
185
+ `console.log("")`,
186
+ `console.log("----------------------")`,
187
+ `console.log("")`,
188
+ `console.log("Result:", result);`,
189
+ `console.log("")`,
190
+ `console.log("//////////////////////")`,
191
+ `console.log("// End of the job //")`,
192
+ `console.log("//////////////////////")`,
193
+ `console.log("")`,
194
+ ].join("\n"));
195
+ const code = AssetCode.fromAsset(bundle.out);
196
+ this.updateCodeBuildProjectCode(code, "handler-wrapper.mjs");
197
+ // This should always be true b/c runtime is always Node.js
198
+ });
214
199
  }
215
200
  updateCodeBuildProjectCode(code, script) {
216
201
  // Update job's commands
@@ -228,9 +213,9 @@ export class Job extends Construct {
228
213
  ].join("\n"),
229
214
  };
230
215
  this.attachPermissions([
231
- new iam.PolicyStatement({
216
+ new PolicyStatement({
232
217
  actions: ["s3:*"],
233
- effect: iam.Effect.ALLOW,
218
+ effect: Effect.ALLOW,
234
219
  resources: [
235
220
  `arn:${Stack.of(this).partition}:s3:::${codeConfig.s3Location?.bucketName}/${codeConfig.s3Location?.objectKey}`,
236
221
  ],
@@ -259,15 +244,15 @@ export class Job extends Construct {
259
244
  createCodeBuildInvoker() {
260
245
  const fn = new Function(this, this.node.id, {
261
246
  handler: path.join(__dirname, "../support/job-invoker/index.main"),
262
- runtime: "nodejs16.x",
247
+ runtime: "nodejs18.x",
263
248
  timeout: 10,
264
249
  memorySize: 1024,
265
250
  environment: {
266
251
  PROJECT_NAME: this.job.projectName,
267
252
  },
268
253
  permissions: [
269
- new iam.PolicyStatement({
270
- effect: iam.Effect.ALLOW,
254
+ new PolicyStatement({
255
+ effect: Effect.ALLOW,
271
256
  actions: ["codebuild:StartBuild"],
272
257
  resources: [this.job.projectArn],
273
258
  }),
@@ -289,9 +274,9 @@ export class Job extends Construct {
289
274
  // Bind permissions
290
275
  const permissions = bindPermissions(c);
291
276
  Object.entries(permissions).forEach(([action, resources]) => this.attachPermissionsForCodeBuild([
292
- new iam.PolicyStatement({
277
+ new PolicyStatement({
293
278
  actions: [action],
294
- effect: iam.Effect.ALLOW,
279
+ effect: Effect.ALLOW,
295
280
  resources,
296
281
  }),
297
282
  ]));
@@ -308,16 +293,16 @@ export class Job extends Construct {
308
293
  }
309
294
  normalizeMemorySize(memorySize) {
310
295
  if (memorySize === "3 GB") {
311
- return codebuild.ComputeType.SMALL;
296
+ return ComputeType.SMALL;
312
297
  }
313
298
  else if (memorySize === "7 GB") {
314
- return codebuild.ComputeType.MEDIUM;
299
+ return ComputeType.MEDIUM;
315
300
  }
316
301
  else if (memorySize === "15 GB") {
317
- return codebuild.ComputeType.LARGE;
302
+ return ComputeType.LARGE;
318
303
  }
319
304
  else if (memorySize === "145 GB") {
320
- return codebuild.ComputeType.X2_LARGE;
305
+ return ComputeType.X2_LARGE;
321
306
  }
322
307
  throw new Error(`Invalid memory size value for the ${this.node.id} Job.`);
323
308
  }
@@ -100,7 +100,7 @@ export class SsrSite extends Construct {
100
100
  : this.createCloudFrontDistributionForRegional();
101
101
  this.distribution.node.addDependency(s3deployCR);
102
102
  // Invalidate CloudFront
103
- const invalidationCR = this.createCloudFrontInvalidation(cliLayer);
103
+ const invalidationCR = this.createCloudFrontInvalidation();
104
104
  invalidationCR.node.addDependency(this.distribution);
105
105
  // Connect Custom Domain to CloudFront Distribution
106
106
  this.createRoute53Records();
@@ -551,36 +551,29 @@ export class SsrSite extends Construct {
551
551
  comment: "SST server response cache policy",
552
552
  });
553
553
  }
554
- createCloudFrontInvalidation(cliLayer) {
555
- // Create a Lambda function that will be doing the invalidation
556
- const invalidator = new Function(this, "CloudFrontInvalidator", {
557
- code: Code.fromAsset(path.join(__dirname, "../support/base-site-custom-resource")),
558
- layers: [cliLayer],
559
- runtime: Runtime.PYTHON_3_7,
560
- handler: "cf-invalidate.handler",
561
- timeout: CdkDuration.minutes(15),
562
- memorySize: 1024,
554
+ createCloudFrontInvalidation() {
555
+ const stack = Stack.of(this);
556
+ const resource = new CustomResource(this, "CloudFrontInvalidator", {
557
+ serviceToken: stack.customResourceHandler.functionArn,
558
+ resourceType: "Custom::CloudFrontInvalidator",
559
+ properties: {
560
+ buildId: this.generateBuildId(),
561
+ distributionId: this.distribution.distributionId,
562
+ paths: ["/*"],
563
+ waitForInvalidation: this.props.waitForInvalidation,
564
+ },
563
565
  });
564
- // Grant permissions to invalidate CF Distribution
565
- invalidator.addToRolePolicy(new PolicyStatement({
566
+ stack.customResourceHandler.role?.addToPrincipalPolicy(new PolicyStatement({
566
567
  effect: Effect.ALLOW,
567
568
  actions: [
568
569
  "cloudfront:GetInvalidation",
569
570
  "cloudfront:CreateInvalidation",
570
571
  ],
571
- resources: ["*"],
572
+ resources: [
573
+ `arn:${stack.partition}:cloudfront::${stack.account}:distribution/${this.distribution.distributionId}`,
574
+ ],
572
575
  }));
573
- return new CustomResource(this, "CloudFrontInvalidation", {
574
- serviceToken: invalidator.functionArn,
575
- resourceType: "Custom::SSTCloudFrontInvalidation",
576
- properties: {
577
- BuildId: this.generateBuildId(),
578
- DistributionId: this.distribution.distributionId,
579
- // TODO: Ignore the browser build path as it may speed up invalidation
580
- DistributionPaths: ["/*"],
581
- WaitForInvalidation: this.props.waitForInvalidation,
582
- },
583
- });
576
+ return resource;
584
577
  }
585
578
  /////////////////////
586
579
  // Custom Domain
@@ -1,3 +1,4 @@
1
+ import fs from "fs";
1
2
  import url from "url";
2
3
  import * as path from "path";
3
4
  import * as cdk from "aws-cdk-lib";
@@ -172,9 +173,11 @@ export class Stack extends cdk.Stack {
172
173
  });
173
174
  }
174
175
  createCustomResourceHandler() {
176
+ const dir = path.join(__dirname, "../support/custom-resources/");
175
177
  return new lambda.Function(this, "CustomResourceHandler", {
176
- code: lambda.Code.fromAsset(path.join(__dirname, "../support/custom-resources/"), {
177
- assetHash: this.stackName + "-custom-resources-20230130",
178
+ code: lambda.Code.fromAsset(dir, {
179
+ //assetHash: this.stackName + "-custom-resources-20230130",
180
+ assetHash: this.stackName + fs.readFileSync(dir + "/index.mjs").toString(),
178
181
  }),
179
182
  handler: "index.handler",
180
183
  runtime: lambda.Runtime.NODEJS_16_X,
@@ -7,7 +7,7 @@ import { Construct } from "constructs";
7
7
  import { Token, Duration, CfnOutput, RemovalPolicy, CustomResource, } from "aws-cdk-lib";
8
8
  import * as s3 from "aws-cdk-lib/aws-s3";
9
9
  import * as s3Assets from "aws-cdk-lib/aws-s3-assets";
10
- import * as iam from "aws-cdk-lib/aws-iam";
10
+ import { Effect, PolicyStatement } from "aws-cdk-lib/aws-iam";
11
11
  import * as lambda from "aws-cdk-lib/aws-lambda";
12
12
  import * as route53 from "aws-cdk-lib/aws-route53";
13
13
  import * as route53Targets from "aws-cdk-lib/aws-route53-targets";
@@ -91,7 +91,7 @@ export class StaticSite extends Construct {
91
91
  this.distribution = this.createCfDistribution();
92
92
  this.distribution.node.addDependency(s3deployCR);
93
93
  // Invalidate CloudFront
94
- const invalidationCR = this.createCloudFrontInvalidation(cliLayer, assets);
94
+ const invalidationCR = this.createCloudFrontInvalidation(assets);
95
95
  invalidationCR.node.addDependency(this.distribution);
96
96
  // Connect Custom Domain to CloudFront Distribution
97
97
  this.createRoute53Records();
@@ -420,41 +420,34 @@ interface ImportMeta {
420
420
  },
421
421
  });
422
422
  }
423
- createCloudFrontInvalidation(cliLayer, assets) {
424
- // Create a Lambda function that will be doing the invalidation
425
- const invalidator = new lambda.Function(this, "CloudFrontInvalidator", {
426
- code: lambda.Code.fromAsset(path.join(__dirname, "../support/base-site-custom-resource")),
427
- layers: [cliLayer],
428
- runtime: lambda.Runtime.PYTHON_3_7,
429
- handler: "cf-invalidate.handler",
430
- timeout: Duration.minutes(15),
431
- memorySize: 1024,
432
- });
433
- // Grant permissions to invalidate CF Distribution
434
- invalidator.addToRolePolicy(new iam.PolicyStatement({
435
- effect: iam.Effect.ALLOW,
436
- actions: [
437
- "cloudfront:GetInvalidation",
438
- "cloudfront:CreateInvalidation",
439
- ],
440
- resources: ["*"],
441
- }));
423
+ createCloudFrontInvalidation(assets) {
424
+ const stack = Stack.of(this);
442
425
  // Need the AssetHash field so the CR gets updated on each deploy
443
426
  const assetsHash = crypto
444
427
  .createHash("md5")
445
428
  .update(assets.map(({ assetHash }) => assetHash).join(""))
446
429
  .digest("hex");
447
- // Create custom resource
448
- return new CustomResource(this, "CloudFrontInvalidation", {
449
- serviceToken: invalidator.functionArn,
450
- resourceType: "Custom::SSTCloudFrontInvalidation",
430
+ const resource = new CustomResource(this, "CloudFrontInvalidator", {
431
+ serviceToken: stack.customResourceHandler.functionArn,
432
+ resourceType: "Custom::CloudFrontInvalidator",
451
433
  properties: {
452
- AssetsHash: assetsHash,
453
- DistributionId: this.distribution.distributionId,
454
- DistributionPaths: ["/*"],
455
- WaitForInvalidation: this.props.waitForInvalidation,
434
+ assetsHash,
435
+ distributionId: this.distribution.distributionId,
436
+ paths: ["/*"],
437
+ waitForInvalidation: this.props.waitForInvalidation,
456
438
  },
457
439
  });
440
+ stack.customResourceHandler.role?.addToPrincipalPolicy(new PolicyStatement({
441
+ effect: Effect.ALLOW,
442
+ actions: [
443
+ "cloudfront:GetInvalidation",
444
+ "cloudfront:CreateInvalidation",
445
+ ],
446
+ resources: [
447
+ `arn:${stack.partition}:cloudfront::${stack.account}:distribution/${this.distribution.distributionId}`,
448
+ ],
449
+ }));
450
+ return resource;
458
451
  }
459
452
  /////////////////////
460
453
  // Custom Domain
@@ -6,7 +6,7 @@ import { execSync } from "child_process";
6
6
  import { Construct } from "constructs";
7
7
  import { Token, Duration, CfnOutput, RemovalPolicy, CustomResource, } from "aws-cdk-lib";
8
8
  import * as s3 from "aws-cdk-lib/aws-s3";
9
- import * as iam from "aws-cdk-lib/aws-iam";
9
+ import { Role, Effect, PolicyStatement, CompositePrincipal, ServicePrincipal, ManagedPolicy, } from "aws-cdk-lib/aws-iam";
10
10
  import * as sqs from "aws-cdk-lib/aws-sqs";
11
11
  import * as logs from "aws-cdk-lib/aws-logs";
12
12
  import * as lambda from "aws-cdk-lib/aws-lambda";
@@ -388,10 +388,10 @@ export class NextjsSite extends Construct {
388
388
  createEdgeFunctionRole() {
389
389
  const { defaults } = this.props;
390
390
  // Create function role
391
- const role = new iam.Role(this, `EdgeLambdaRole`, {
392
- assumedBy: new iam.CompositePrincipal(new iam.ServicePrincipal("lambda.amazonaws.com"), new iam.ServicePrincipal("edgelambda.amazonaws.com")),
391
+ const role = new Role(this, `EdgeLambdaRole`, {
392
+ assumedBy: new CompositePrincipal(new ServicePrincipal("lambda.amazonaws.com"), new ServicePrincipal("edgelambda.amazonaws.com")),
393
393
  managedPolicies: [
394
- iam.ManagedPolicy.fromManagedPolicyArn(this, "EdgeLambdaPolicy", `arn:${Stack.of(this).partition}:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole`),
394
+ ManagedPolicy.fromManagedPolicyArn(this, "EdgeLambdaPolicy", `arn:${Stack.of(this).partition}:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole`),
395
395
  ],
396
396
  });
397
397
  // Attach permission
@@ -470,8 +470,8 @@ export class NextjsSite extends Construct {
470
470
  });
471
471
  }
472
472
  // Allow provider to perform search/replace on the asset
473
- provider.role?.addToPrincipalPolicy(new iam.PolicyStatement({
474
- effect: iam.Effect.ALLOW,
473
+ provider.role?.addToPrincipalPolicy(new PolicyStatement({
474
+ effect: Effect.ALLOW,
475
475
  actions: ["s3:*"],
476
476
  resources: [
477
477
  `arn:${Stack.of(this).partition}:s3:::${asset.s3BucketName}/${asset.s3ObjectKey}`,
@@ -813,24 +813,7 @@ export class NextjsSite extends Construct {
813
813
  return new cloudfront.OriginRequestPolicy(this, "ImageOriginRequest", NextjsSite.imageOriginRequestPolicyProps);
814
814
  }
815
815
  createCloudFrontInvalidation() {
816
- // Create a Lambda function that will be doing the invalidation
817
- const invalidator = new lambda.Function(this, "CloudFrontInvalidator", {
818
- code: lambda.Code.fromAsset(path.join(__dirname, "../../support/base-site-custom-resource")),
819
- layers: [this.awsCliLayer],
820
- runtime: lambda.Runtime.PYTHON_3_7,
821
- handler: "cf-invalidate.handler",
822
- timeout: Duration.minutes(15),
823
- memorySize: 1024,
824
- });
825
- // Grant permissions to invalidate CF Distribution
826
- invalidator.addToRolePolicy(new iam.PolicyStatement({
827
- effect: iam.Effect.ALLOW,
828
- actions: [
829
- "cloudfront:GetInvalidation",
830
- "cloudfront:CreateInvalidation",
831
- ],
832
- resources: ["*"],
833
- }));
816
+ const stack = Stack.of(this);
834
817
  // need the BuildId field so this CR gets updated on each deploy
835
818
  let buildId;
836
819
  if (this.isPlaceholder) {
@@ -846,16 +829,27 @@ export class NextjsSite extends Construct {
846
829
  : this.props.waitForInvalidation === false
847
830
  ? false
848
831
  : true;
849
- return new CustomResource(this, "CloudFrontInvalidation", {
850
- serviceToken: invalidator.functionArn,
851
- resourceType: "Custom::SSTCloudFrontInvalidation",
832
+ const resource = new CustomResource(this, "CloudFrontInvalidator", {
833
+ serviceToken: stack.customResourceHandler.functionArn,
834
+ resourceType: "Custom::CloudFrontInvalidator",
852
835
  properties: {
853
- BuildId: buildId,
854
- DistributionId: this.cdk.distribution.distributionId,
855
- DistributionPaths: ["/*"],
856
- WaitForInvalidation: waitForInvalidation,
836
+ buildId,
837
+ distributionId: this.cdk.distribution.distributionId,
838
+ paths: ["/*"],
839
+ waitForInvalidation,
857
840
  },
858
841
  });
842
+ stack.customResourceHandler.role?.addToPrincipalPolicy(new PolicyStatement({
843
+ effect: Effect.ALLOW,
844
+ actions: [
845
+ "cloudfront:GetInvalidation",
846
+ "cloudfront:CreateInvalidation",
847
+ ],
848
+ resources: [
849
+ `arn:${stack.partition}:cloudfront::${stack.account}:distribution/${this.cdk.distribution.distributionId}`,
850
+ ],
851
+ }));
852
+ return resource;
859
853
  }
860
854
  /////////////////////
861
855
  // Custom Domain
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sst",
3
- "version": "2.0.12",
3
+ "version": "2.0.14",
4
4
  "bin": {
5
5
  "sst": "cli/sst.js"
6
6
  },
@@ -30,6 +30,7 @@
30
30
  "@aws-cdk/cx-api": "2.62.2",
31
31
  "@aws-cdk/region-info": "2.62.2",
32
32
  "@aws-sdk/client-cloudformation": "3.208.0",
33
+ "@aws-sdk/client-cloudfront": "3.208.0",
33
34
  "@aws-sdk/client-iot": "3.208.0",
34
35
  "@aws-sdk/client-iot-data-plane": "3.208.0",
35
36
  "@aws-sdk/client-lambda": "3.208.0",
package/sst.mjs CHANGED
@@ -4228,11 +4228,16 @@ async function deploy(stack) {
4228
4228
  const deployment = new CloudFormationDeployments2({
4229
4229
  sdkProvider: provider
4230
4230
  });
4231
+ const stackTags = Object.entries(stack.tags ?? {}).map(([Key, Value]) => ({
4232
+ Key,
4233
+ Value
4234
+ }));
4231
4235
  try {
4232
4236
  await addInUseExports(stack);
4233
4237
  const result = await deployment.deployStack({
4234
4238
  stack,
4235
4239
  quiet: true,
4240
+ tags: stackTags,
4236
4241
  deploymentMethod: {
4237
4242
  method: "direct"
4238
4243
  }
package/stacks/deploy.js CHANGED
@@ -74,11 +74,16 @@ export async function deploy(stack) {
74
74
  const deployment = new CloudFormationDeployments({
75
75
  sdkProvider: provider,
76
76
  });
77
+ const stackTags = Object.entries(stack.tags ?? {}).map(([Key, Value]) => ({
78
+ Key,
79
+ Value,
80
+ }));
77
81
  try {
78
82
  await addInUseExports(stack);
79
83
  const result = await deployment.deployStack({
80
84
  stack: stack,
81
85
  quiet: true,
86
+ tags: stackTags,
82
87
  deploymentMethod: {
83
88
  method: "direct",
84
89
  },