@jaypie/constructs 1.1.34 → 1.1.36-beta.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.
@@ -35,11 +35,12 @@ export interface JaypieLambdaProps {
35
35
  }
36
36
  export declare class JaypieLambda extends Construct implements lambda.IFunction {
37
37
  private readonly _lambda;
38
- private readonly _alias?;
38
+ private readonly _provisioned?;
39
39
  private readonly _code;
40
+ private readonly _reference;
40
41
  constructor(scope: Construct, id: string, props: JaypieLambdaProps);
41
42
  get lambda(): lambda.Function;
42
- get alias(): lambda.Alias | undefined;
43
+ get provisioned(): lambda.Alias | undefined;
43
44
  get code(): lambda.Code;
44
45
  get functionArn(): string;
45
46
  get functionName(): string;
@@ -7,12 +7,12 @@ var apiGateway = require('aws-cdk-lib/aws-apigateway');
7
7
  var route53 = require('aws-cdk-lib/aws-route53');
8
8
  var route53Targets = require('aws-cdk-lib/aws-route53-targets');
9
9
  var cdk = require('@jaypie/cdk');
10
+ var lambda = require('aws-cdk-lib/aws-lambda');
11
+ var secretsmanager = require('aws-cdk-lib/aws-secretsmanager');
10
12
  var s3 = require('aws-cdk-lib/aws-s3');
11
13
  var s3n = require('aws-cdk-lib/aws-s3-notifications');
12
- var lambda = require('aws-cdk-lib/aws-lambda');
13
14
  var sqs = require('aws-cdk-lib/aws-sqs');
14
15
  var lambdaEventSources = require('aws-cdk-lib/aws-lambda-event-sources');
15
- var secretsmanager = require('aws-cdk-lib/aws-secretsmanager');
16
16
  var awsIam = require('aws-cdk-lib/aws-iam');
17
17
  var awsLogs = require('aws-cdk-lib/aws-logs');
18
18
  var sso = require('aws-cdk-lib/aws-sso');
@@ -41,12 +41,12 @@ var acm__namespace = /*#__PURE__*/_interopNamespaceDefault(acm);
41
41
  var apiGateway__namespace = /*#__PURE__*/_interopNamespaceDefault(apiGateway);
42
42
  var route53__namespace = /*#__PURE__*/_interopNamespaceDefault(route53);
43
43
  var route53Targets__namespace = /*#__PURE__*/_interopNamespaceDefault(route53Targets);
44
+ var lambda__namespace = /*#__PURE__*/_interopNamespaceDefault(lambda);
45
+ var secretsmanager__namespace = /*#__PURE__*/_interopNamespaceDefault(secretsmanager);
44
46
  var s3__namespace = /*#__PURE__*/_interopNamespaceDefault(s3);
45
47
  var s3n__namespace = /*#__PURE__*/_interopNamespaceDefault(s3n);
46
- var lambda__namespace = /*#__PURE__*/_interopNamespaceDefault(lambda);
47
48
  var sqs__namespace = /*#__PURE__*/_interopNamespaceDefault(sqs);
48
49
  var lambdaEventSources__namespace = /*#__PURE__*/_interopNamespaceDefault(lambdaEventSources);
49
- var secretsmanager__namespace = /*#__PURE__*/_interopNamespaceDefault(secretsmanager);
50
50
  var sso__namespace = /*#__PURE__*/_interopNamespaceDefault(sso);
51
51
  var cloudfront__namespace = /*#__PURE__*/_interopNamespaceDefault(cloudfront);
52
52
  var origins__namespace = /*#__PURE__*/_interopNamespaceDefault(origins);
@@ -138,186 +138,6 @@ function stackTagger(stack, { name } = {}) {
138
138
  return true;
139
139
  }
140
140
 
141
- class JaypieApiGateway extends constructs.Construct {
142
- constructor(scope, id, props) {
143
- super(scope, id);
144
- const { certificate = true, handler, host: propsHost, name, roleTag = cdk.CDK.ROLE.API, zone: propsZone, } = props;
145
- // Determine zone from props or environment
146
- let zone = propsZone;
147
- if (!zone && process.env.CDK_ENV_API_HOSTED_ZONE) {
148
- zone = process.env.CDK_ENV_API_HOSTED_ZONE;
149
- }
150
- // Determine host from props or environment
151
- let host = propsHost;
152
- if (!host) {
153
- if (process.env.CDK_ENV_API_HOST_NAME) {
154
- host = process.env.CDK_ENV_API_HOST_NAME;
155
- }
156
- else if (process.env.CDK_ENV_API_SUBDOMAIN &&
157
- process.env.CDK_ENV_API_HOSTED_ZONE) {
158
- host = cdk.mergeDomain(process.env.CDK_ENV_API_SUBDOMAIN, process.env.CDK_ENV_API_HOSTED_ZONE);
159
- }
160
- }
161
- const apiGatewayName = name || constructEnvName("ApiGateway");
162
- const certificateName = constructEnvName("Certificate");
163
- const apiDomainName = constructEnvName("ApiDomainName");
164
- let hostedZone;
165
- let certificateToUse;
166
- if (host && zone) {
167
- if (typeof zone === "string") {
168
- hostedZone = route53__namespace.HostedZone.fromLookup(this, "HostedZone", {
169
- domainName: zone,
170
- });
171
- }
172
- else {
173
- hostedZone = zone;
174
- }
175
- if (certificate === true) {
176
- certificateToUse = new acm__namespace.Certificate(this, certificateName, {
177
- domainName: host,
178
- validation: acm__namespace.CertificateValidation.fromDns(hostedZone),
179
- });
180
- cdk$1.Tags.of(certificateToUse).add(cdk.CDK.TAG.ROLE, cdk.CDK.ROLE.HOSTING);
181
- }
182
- else if (typeof certificate === "object") {
183
- certificateToUse = certificate;
184
- }
185
- this._certificate = certificateToUse;
186
- this._host = host;
187
- }
188
- const {
189
- // * `...lambdaRestApiProps` cannot be moved to the first const destructuring because it needs to exclude the custom properties first.
190
- // Ignore the variables we already assigned to other properties
191
- /* eslint-disable @typescript-eslint/no-unused-vars */
192
- certificate: _certificate, host: _host, name: _name, roleTag: _roleTag, zone: _zone, handler: _handler,
193
- /* eslint-enable @typescript-eslint/no-unused-vars */
194
- ...lambdaRestApiProps } = props;
195
- this._api = new apiGateway__namespace.LambdaRestApi(this, apiGatewayName, {
196
- handler,
197
- ...lambdaRestApiProps,
198
- });
199
- cdk$1.Tags.of(this._api).add(cdk.CDK.TAG.ROLE, roleTag);
200
- if (host && certificateToUse && hostedZone) {
201
- this._domainName = this._api.addDomainName(apiDomainName, {
202
- domainName: host,
203
- certificate: certificateToUse,
204
- });
205
- cdk$1.Tags.of(this._domainName).add(cdk.CDK.TAG.ROLE, roleTag);
206
- const record = new route53__namespace.ARecord(this, "AliasRecord", {
207
- recordName: host,
208
- target: route53__namespace.RecordTarget.fromAlias(new route53Targets__namespace.ApiGatewayDomain(this._domainName)),
209
- zone: hostedZone,
210
- });
211
- cdk$1.Tags.of(record).add(cdk.CDK.TAG.ROLE, cdk.CDK.ROLE.NETWORKING);
212
- }
213
- }
214
- get api() {
215
- return this._api;
216
- }
217
- get url() {
218
- return this._api.url;
219
- }
220
- get certificateArn() {
221
- return this._certificate?.certificateArn;
222
- }
223
- get domainName() {
224
- return this._domainName?.domainName;
225
- }
226
- get host() {
227
- return this._host;
228
- }
229
- get restApiId() {
230
- return this._api.restApiId;
231
- }
232
- get restApiName() {
233
- return this._api.restApiName;
234
- }
235
- get restApiRootResourceId() {
236
- return this._api.restApiRootResourceId;
237
- }
238
- get deploymentStage() {
239
- return this._api.deploymentStage;
240
- }
241
- get domainNameAliasDomainName() {
242
- return this._domainName?.domainNameAliasDomainName;
243
- }
244
- get domainNameAliasHostedZoneId() {
245
- return this._domainName?.domainNameAliasHostedZoneId;
246
- }
247
- get root() {
248
- return this._api.root;
249
- }
250
- get env() {
251
- return {
252
- account: cdk$1.Stack.of(this).account,
253
- region: cdk$1.Stack.of(this).region,
254
- };
255
- }
256
- get stack() {
257
- return this._api.stack;
258
- }
259
- arnForExecuteApi(method, path, stage) {
260
- return this._api.arnForExecuteApi(method, path, stage);
261
- }
262
- metric(metricName, props) {
263
- return this._api.metric(metricName, props);
264
- }
265
- metricCacheHitCount(props) {
266
- return this._api.metricCacheHitCount(props);
267
- }
268
- metricCacheMissCount(props) {
269
- return this._api.metricCacheMissCount(props);
270
- }
271
- metricClientError(props) {
272
- return this._api.metricClientError(props);
273
- }
274
- metricCount(props) {
275
- return this._api.metricCount(props);
276
- }
277
- metricIntegrationLatency(props) {
278
- return this._api.metricIntegrationLatency(props);
279
- }
280
- metricLatency(props) {
281
- return this._api.metricLatency(props);
282
- }
283
- metricServerError(props) {
284
- return this._api.metricServerError(props);
285
- }
286
- applyRemovalPolicy(policy) {
287
- this._api.applyRemovalPolicy(policy);
288
- }
289
- }
290
-
291
- class JaypieStack extends cdk$1.Stack {
292
- constructor(scope, id, props = {}) {
293
- const { key, ...stackProps } = props;
294
- // Handle stackName
295
- if (!stackProps.stackName) {
296
- stackProps.stackName = constructStackName(key);
297
- }
298
- // Handle env
299
- stackProps.env = {
300
- account: process.env.CDK_DEFAULT_ACCOUNT,
301
- region: process.env.CDK_DEFAULT_REGION,
302
- ...stackProps.env,
303
- };
304
- super(scope, id, stackProps);
305
- // Apply tags
306
- stackTagger(this, { name: stackProps.stackName });
307
- }
308
- }
309
-
310
- class JaypieAppStack extends JaypieStack {
311
- constructor(scope, id, props = {}) {
312
- const { key = "app", ...stackProps } = props;
313
- // Handle stackName
314
- if (!stackProps.stackName) {
315
- stackProps.stackName = constructStackName(key);
316
- }
317
- super(scope, id, { key, ...stackProps });
318
- }
319
- }
320
-
321
141
  class JaypieLambda extends constructs.Construct {
322
142
  constructor(scope, id, props) {
323
143
  super(scope, id);
@@ -460,7 +280,6 @@ class JaypieLambda extends constructs.Construct {
460
280
  });
461
281
  // Grant read permissions for JaypieEnvSecrets
462
282
  secrets.forEach((secret) => {
463
- secret.grantRead(this);
464
283
  secret.grantRead(this._lambda);
465
284
  });
466
285
  // Grant Datadog API key read permission if applicable
@@ -473,13 +292,13 @@ class JaypieLambda extends constructs.Construct {
473
292
  // Use currentVersion which is auto-published with proper configuration
474
293
  const version = this._lambda.currentVersion;
475
294
  // Create alias for provisioned concurrency
476
- this._alias = new lambda__namespace.Alias(this, "ProvisionedAlias", {
295
+ this._provisioned = new lambda__namespace.Alias(this, "ProvisionedAlias", {
477
296
  aliasName: "provisioned",
478
297
  version,
479
298
  provisionedConcurrentExecutions,
480
299
  });
481
300
  // Add explicit dependencies to ensure proper creation order
482
- this._alias.node.addDependency(version);
301
+ this._provisioned.node.addDependency(version);
483
302
  }
484
303
  if (roleTag) {
485
304
  cdk$1.Tags.of(this._lambda).add(cdk.CDK.TAG.ROLE, roleTag);
@@ -487,100 +306,230 @@ class JaypieLambda extends constructs.Construct {
487
306
  if (vendorTag) {
488
307
  cdk$1.Tags.of(this._lambda).add(cdk.CDK.TAG.VENDOR, vendorTag);
489
308
  }
309
+ // Assign _reference based on provisioned state
310
+ this._reference =
311
+ this._provisioned !== undefined ? this._provisioned : this._lambda;
490
312
  }
491
313
  // Public accessors
492
314
  get lambda() {
493
315
  return this._lambda;
494
316
  }
495
- get alias() {
496
- return this._alias;
317
+ get provisioned() {
318
+ return this._provisioned;
497
319
  }
498
320
  get code() {
499
321
  return this._code;
500
322
  }
501
323
  // IFunction implementation
502
324
  get functionArn() {
503
- return this._alias?.functionArn ?? this._lambda.functionArn;
325
+ return this._reference.functionArn;
504
326
  }
505
327
  get functionName() {
506
- return this._alias?.functionName ?? this._lambda.functionName;
328
+ return this._reference.functionName;
507
329
  }
508
330
  get grantPrincipal() {
509
- return this._lambda.grantPrincipal;
331
+ return this._reference.grantPrincipal;
510
332
  }
511
333
  get role() {
512
- return this._lambda.role;
334
+ return this._reference.role;
513
335
  }
514
336
  get architecture() {
515
- return this._lambda.architecture;
337
+ return this._reference.architecture;
516
338
  }
517
339
  get connections() {
518
- return this._lambda.connections;
340
+ return this._reference.connections;
519
341
  }
520
342
  get isBoundToVpc() {
521
- return this._lambda.isBoundToVpc;
343
+ return this._reference.isBoundToVpc;
522
344
  }
523
345
  get latestVersion() {
524
- return this._lambda.latestVersion;
346
+ return this._reference.latestVersion;
525
347
  }
526
348
  get permissionsNode() {
527
- return this._lambda.permissionsNode;
349
+ return this._reference.permissionsNode;
528
350
  }
529
351
  get resourceArnsForGrantInvoke() {
530
- return (this._alias?.resourceArnsForGrantInvoke ??
531
- this._lambda.resourceArnsForGrantInvoke);
352
+ return this._reference.resourceArnsForGrantInvoke;
532
353
  }
533
354
  addEventSource(source) {
534
- this._lambda.addEventSource(source);
355
+ this._reference.addEventSource(source);
535
356
  }
536
357
  addEventSourceMapping(id, options) {
537
- return this._lambda.addEventSourceMapping(id, options);
358
+ return this._reference.addEventSourceMapping(id, options);
538
359
  }
539
360
  addFunctionUrl(options) {
540
- return this._lambda.addFunctionUrl(options);
361
+ return this._reference.addFunctionUrl(options);
541
362
  }
542
363
  addPermission(id, permission) {
543
- this._lambda.addPermission(id, permission);
364
+ this._reference.addPermission(id, permission);
544
365
  }
545
366
  addToRolePolicy(statement) {
546
- this._lambda.addToRolePolicy(statement);
367
+ this._reference.addToRolePolicy(statement);
547
368
  }
548
369
  addEnvironment(key, value, options) {
549
370
  return this._lambda.addEnvironment(key, value, options);
550
371
  }
551
372
  configureAsyncInvoke(options) {
552
- this._lambda.configureAsyncInvoke(options);
373
+ this._reference.configureAsyncInvoke(options);
553
374
  }
554
375
  grantInvoke(grantee) {
555
- return (this._alias?.grantInvoke(grantee) ?? this._lambda.grantInvoke(grantee));
376
+ return this._reference.grantInvoke(grantee);
556
377
  }
557
378
  grantInvokeCompositePrincipal(compositePrincipal) {
558
- return this._lambda.grantInvokeCompositePrincipal(compositePrincipal);
379
+ return this._reference.grantInvokeCompositePrincipal(compositePrincipal);
559
380
  }
560
381
  grantInvokeUrl(grantee) {
561
- return this._lambda.grantInvokeUrl(grantee);
382
+ return this._reference.grantInvokeUrl(grantee);
562
383
  }
563
384
  metric(metricName, props) {
564
- return this._lambda.metric(metricName, props);
385
+ return this._reference.metric(metricName, props);
565
386
  }
566
387
  metricDuration(props) {
567
- return this._lambda.metricDuration(props);
388
+ return this._reference.metricDuration(props);
568
389
  }
569
390
  metricErrors(props) {
570
- return this._lambda.metricErrors(props);
391
+ return this._reference.metricErrors(props);
571
392
  }
572
393
  metricInvocations(props) {
573
- return this._lambda.metricInvocations(props);
394
+ return this._reference.metricInvocations(props);
574
395
  }
575
396
  metricThrottles(props) {
576
- return this._lambda.metricThrottles(props);
397
+ return this._reference.metricThrottles(props);
577
398
  }
578
399
  // Additional IFunction implementation
579
400
  grantInvokeLatestVersion(grantee) {
580
- return this._lambda.grantInvokeLatestVersion(grantee);
401
+ return this._reference.grantInvokeLatestVersion(grantee);
581
402
  }
582
403
  grantInvokeVersion(grantee, version) {
583
- return this._lambda.grantInvokeVersion(grantee, version);
404
+ return this._reference.grantInvokeVersion(grantee, version);
405
+ }
406
+ get env() {
407
+ return {
408
+ account: cdk$1.Stack.of(this).account,
409
+ region: cdk$1.Stack.of(this).region,
410
+ };
411
+ }
412
+ get stack() {
413
+ return this._reference.stack;
414
+ }
415
+ applyRemovalPolicy(policy) {
416
+ this._reference.applyRemovalPolicy(policy);
417
+ }
418
+ }
419
+
420
+ class JaypieApiGateway extends constructs.Construct {
421
+ constructor(scope, id, props) {
422
+ super(scope, id);
423
+ const { certificate = true, handler, host: propsHost, name, roleTag = cdk.CDK.ROLE.API, zone: propsZone, } = props;
424
+ // Determine zone from props or environment
425
+ let zone = propsZone;
426
+ if (!zone && process.env.CDK_ENV_API_HOSTED_ZONE) {
427
+ zone = process.env.CDK_ENV_API_HOSTED_ZONE;
428
+ }
429
+ // Determine host from props or environment
430
+ let host = propsHost;
431
+ if (!host) {
432
+ if (process.env.CDK_ENV_API_HOST_NAME) {
433
+ host = process.env.CDK_ENV_API_HOST_NAME;
434
+ }
435
+ else if (process.env.CDK_ENV_API_SUBDOMAIN &&
436
+ process.env.CDK_ENV_API_HOSTED_ZONE) {
437
+ host = cdk.mergeDomain(process.env.CDK_ENV_API_SUBDOMAIN, process.env.CDK_ENV_API_HOSTED_ZONE);
438
+ }
439
+ }
440
+ const apiGatewayName = name || constructEnvName("ApiGateway");
441
+ const certificateName = constructEnvName("Certificate");
442
+ const apiDomainName = constructEnvName("ApiDomainName");
443
+ let hostedZone;
444
+ let certificateToUse;
445
+ if (host && zone) {
446
+ if (typeof zone === "string") {
447
+ hostedZone = route53__namespace.HostedZone.fromLookup(this, "HostedZone", {
448
+ domainName: zone,
449
+ });
450
+ }
451
+ else {
452
+ hostedZone = zone;
453
+ }
454
+ if (certificate === true) {
455
+ certificateToUse = new acm__namespace.Certificate(this, certificateName, {
456
+ domainName: host,
457
+ validation: acm__namespace.CertificateValidation.fromDns(hostedZone),
458
+ });
459
+ cdk$1.Tags.of(certificateToUse).add(cdk.CDK.TAG.ROLE, cdk.CDK.ROLE.HOSTING);
460
+ }
461
+ else if (typeof certificate === "object") {
462
+ certificateToUse = certificate;
463
+ }
464
+ this._certificate = certificateToUse;
465
+ this._host = host;
466
+ }
467
+ const {
468
+ // * `...lambdaRestApiProps` cannot be moved to the first const destructuring because it needs to exclude the custom properties first.
469
+ // Ignore the variables we already assigned to other properties
470
+ /* eslint-disable @typescript-eslint/no-unused-vars */
471
+ certificate: _certificate, host: _host, name: _name, roleTag: _roleTag, zone: _zone, handler: _handler,
472
+ /* eslint-enable @typescript-eslint/no-unused-vars */
473
+ ...lambdaRestApiProps } = props;
474
+ // Check if handler is a JaypieLambda instance and use provisioned alias if available
475
+ let handlerToUse = handler;
476
+ if (handler instanceof JaypieLambda && handler.provisioned) {
477
+ handlerToUse = handler.provisioned;
478
+ }
479
+ this._api = new apiGateway__namespace.LambdaRestApi(this, apiGatewayName, {
480
+ handler: handlerToUse,
481
+ ...lambdaRestApiProps,
482
+ });
483
+ cdk$1.Tags.of(this._api).add(cdk.CDK.TAG.ROLE, roleTag);
484
+ if (host && certificateToUse && hostedZone) {
485
+ this._domainName = this._api.addDomainName(apiDomainName, {
486
+ domainName: host,
487
+ certificate: certificateToUse,
488
+ });
489
+ cdk$1.Tags.of(this._domainName).add(cdk.CDK.TAG.ROLE, roleTag);
490
+ const record = new route53__namespace.ARecord(this, "AliasRecord", {
491
+ recordName: host,
492
+ target: route53__namespace.RecordTarget.fromAlias(new route53Targets__namespace.ApiGatewayDomain(this._domainName)),
493
+ zone: hostedZone,
494
+ });
495
+ cdk$1.Tags.of(record).add(cdk.CDK.TAG.ROLE, cdk.CDK.ROLE.NETWORKING);
496
+ }
497
+ }
498
+ get api() {
499
+ return this._api;
500
+ }
501
+ get url() {
502
+ return this._api.url;
503
+ }
504
+ get certificateArn() {
505
+ return this._certificate?.certificateArn;
506
+ }
507
+ get domainName() {
508
+ return this._domainName?.domainName;
509
+ }
510
+ get host() {
511
+ return this._host;
512
+ }
513
+ get restApiId() {
514
+ return this._api.restApiId;
515
+ }
516
+ get restApiName() {
517
+ return this._api.restApiName;
518
+ }
519
+ get restApiRootResourceId() {
520
+ return this._api.restApiRootResourceId;
521
+ }
522
+ get deploymentStage() {
523
+ return this._api.deploymentStage;
524
+ }
525
+ get domainNameAliasDomainName() {
526
+ return this._domainName?.domainNameAliasDomainName;
527
+ }
528
+ get domainNameAliasHostedZoneId() {
529
+ return this._domainName?.domainNameAliasHostedZoneId;
530
+ }
531
+ get root() {
532
+ return this._api.root;
584
533
  }
585
534
  get env() {
586
535
  return {
@@ -589,10 +538,67 @@ class JaypieLambda extends constructs.Construct {
589
538
  };
590
539
  }
591
540
  get stack() {
592
- return this._lambda.stack;
541
+ return this._api.stack;
542
+ }
543
+ arnForExecuteApi(method, path, stage) {
544
+ return this._api.arnForExecuteApi(method, path, stage);
545
+ }
546
+ metric(metricName, props) {
547
+ return this._api.metric(metricName, props);
548
+ }
549
+ metricCacheHitCount(props) {
550
+ return this._api.metricCacheHitCount(props);
551
+ }
552
+ metricCacheMissCount(props) {
553
+ return this._api.metricCacheMissCount(props);
554
+ }
555
+ metricClientError(props) {
556
+ return this._api.metricClientError(props);
557
+ }
558
+ metricCount(props) {
559
+ return this._api.metricCount(props);
560
+ }
561
+ metricIntegrationLatency(props) {
562
+ return this._api.metricIntegrationLatency(props);
563
+ }
564
+ metricLatency(props) {
565
+ return this._api.metricLatency(props);
566
+ }
567
+ metricServerError(props) {
568
+ return this._api.metricServerError(props);
593
569
  }
594
570
  applyRemovalPolicy(policy) {
595
- this._lambda.applyRemovalPolicy(policy);
571
+ this._api.applyRemovalPolicy(policy);
572
+ }
573
+ }
574
+
575
+ class JaypieStack extends cdk$1.Stack {
576
+ constructor(scope, id, props = {}) {
577
+ const { key, ...stackProps } = props;
578
+ // Handle stackName
579
+ if (!stackProps.stackName) {
580
+ stackProps.stackName = constructStackName(key);
581
+ }
582
+ // Handle env
583
+ stackProps.env = {
584
+ account: process.env.CDK_DEFAULT_ACCOUNT,
585
+ region: process.env.CDK_DEFAULT_REGION,
586
+ ...stackProps.env,
587
+ };
588
+ super(scope, id, stackProps);
589
+ // Apply tags
590
+ stackTagger(this, { name: stackProps.stackName });
591
+ }
592
+ }
593
+
594
+ class JaypieAppStack extends JaypieStack {
595
+ constructor(scope, id, props = {}) {
596
+ const { key = "app", ...stackProps } = props;
597
+ // Handle stackName
598
+ if (!stackProps.stackName) {
599
+ stackProps.stackName = constructStackName(key);
600
+ }
601
+ super(scope, id, { key, ...stackProps });
596
602
  }
597
603
  }
598
604