@jaypie/constructs 1.2.32 → 1.2.34

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.
@@ -7,7 +7,7 @@ export { JaypieCertificate, JaypieCertificateProps } from "./JaypieCertificate";
7
7
  export { JaypieDatadogBucket, JaypieDatadogBucketProps, } from "./JaypieDatadogBucket";
8
8
  export { JaypieDatadogForwarder, JaypieDatadogForwarderProps, } from "./JaypieDatadogForwarder";
9
9
  export { JaypieDatadogSecret } from "./JaypieDatadogSecret";
10
- export { JaypieDistribution, JaypieDistributionProps, SecurityHeadersOverrides, } from "./JaypieDistribution";
10
+ export { JaypieDistribution, JaypieDistributionProps, JaypieWafConfig, SecurityHeadersOverrides, } from "./JaypieDistribution";
11
11
  export { JaypieDnsRecord, JaypieDnsRecordProps } from "./JaypieDnsRecord";
12
12
  export { JaypieDynamoDb, JaypieDynamoDbProps } from "./JaypieDynamoDb";
13
13
  export type { IndexDefinition } from "@jaypie/fabric";
@@ -18,6 +18,7 @@ export { JaypieGitHubDeployRole, JaypieGitHubDeployRoleProps, } from "./JaypieGi
18
18
  export { JaypieHostedZone, JaypieHostedZoneRecordProps, } from "./JaypieHostedZone";
19
19
  export { JaypieInfrastructureStack } from "./JaypieInfrastructureStack";
20
20
  export { JaypieLambda, JaypieLambdaProps } from "./JaypieLambda";
21
+ export { JaypieMigration, JaypieMigrationProps } from "./JaypieMigration";
21
22
  export { JaypieMongoDbSecret } from "./JaypieMongoDbSecret";
22
23
  export { DomainNameConfig, JaypieNextJs, JaypieNextjsProps, } from "./JaypieNextJs";
23
24
  export { JaypieOpenAiSecret } from "./JaypieOpenAiSecret";
@@ -5,8 +5,38 @@ import * as lambda from "aws-cdk-lib/aws-lambda";
5
5
  import * as route53 from "aws-cdk-lib/aws-route53";
6
6
  import * as s3 from "aws-cdk-lib/aws-s3";
7
7
  import { LambdaDestination } from "aws-cdk-lib/aws-s3-notifications";
8
+ import * as wafv2 from "aws-cdk-lib/aws-wafv2";
8
9
  import { Construct } from "constructs";
9
10
  import { HostConfig } from "./helpers";
11
+ export interface JaypieWafConfig {
12
+ /**
13
+ * Whether WAF is enabled
14
+ * @default true
15
+ */
16
+ enabled?: boolean;
17
+ /**
18
+ * WAF logging bucket.
19
+ * - true/undefined: create a logging bucket with Datadog forwarding (default)
20
+ * - false: disable WAF logging
21
+ * - IBucket: use an existing bucket (must have "aws-waf-logs-" prefix)
22
+ * @default true
23
+ */
24
+ logBucket?: boolean | s3.IBucket;
25
+ /**
26
+ * Managed rule group names to apply
27
+ * @default ["AWSManagedRulesCommonRuleSet", "AWSManagedRulesKnownBadInputsRuleSet"]
28
+ */
29
+ managedRules?: string[];
30
+ /**
31
+ * Rate limit per IP per 5-minute window
32
+ * @default 2000
33
+ */
34
+ rateLimitPerIp?: number;
35
+ /**
36
+ * Use an existing WebACL ARN instead of creating one
37
+ */
38
+ webAclArn?: string;
39
+ }
10
40
  export interface SecurityHeadersOverrides {
11
41
  contentSecurityPolicy?: string;
12
42
  frameOption?: cloudfront.HeadersFrameOption;
@@ -99,6 +129,14 @@ export interface JaypieDistributionProps extends Omit<cloudfront.DistributionPro
99
129
  * @default CDK.ROLE.HOSTING
100
130
  */
101
131
  roleTag?: string;
132
+ /**
133
+ * WAF WebACL configuration for the CloudFront distribution.
134
+ * - true/undefined: create and attach a WebACL with sensible defaults
135
+ * - false: disable WAF
136
+ * - JaypieWafConfig: customize WAF behavior
137
+ * @default true
138
+ */
139
+ waf?: boolean | JaypieWafConfig;
102
140
  /**
103
141
  * The hosted zone for DNS records
104
142
  * @default CDK_ENV_API_HOSTED_ZONE || CDK_ENV_HOSTED_ZONE
@@ -116,11 +154,14 @@ export declare class JaypieDistribution extends Construct implements cloudfront.
116
154
  readonly host?: string;
117
155
  readonly logBucket?: s3.IBucket;
118
156
  readonly responseHeadersPolicy?: cloudfront.IResponseHeadersPolicy;
157
+ readonly wafLogBucket?: s3.IBucket;
158
+ readonly webAcl?: wafv2.CfnWebACL;
119
159
  constructor(scope: Construct, id: string, props: JaypieDistributionProps);
120
160
  private isIOrigin;
121
161
  private isIFunctionUrl;
122
162
  private isIFunction;
123
163
  private isExportNameObject;
164
+ private resolveWafConfig;
124
165
  private resolveLogBucket;
125
166
  get env(): {
126
167
  account: string;
@@ -89,6 +89,7 @@ export declare class JaypieDynamoDb extends Construct implements dynamodb.ITable
89
89
  get tableRef(): dynamodb.TableReference;
90
90
  get tableStreamArn(): string | undefined;
91
91
  get encryptionKey(): import("aws-cdk-lib/aws-kms").IKey | undefined;
92
+ get grants(): dynamodb.TableGrants;
92
93
  applyRemovalPolicy(policy: RemovalPolicy): void;
93
94
  grant(grantee: import("aws-cdk-lib/aws-iam").IGrantable, ...actions: string[]): import("aws-cdk-lib/aws-iam").Grant;
94
95
  grantFullAccess(grantee: import("aws-cdk-lib/aws-iam").IGrantable): import("aws-cdk-lib/aws-iam").Grant;
@@ -0,0 +1,21 @@
1
+ import { Construct } from "constructs";
2
+ import * as dynamodb from "aws-cdk-lib/aws-dynamodb";
3
+ import * as lambda from "aws-cdk-lib/aws-lambda";
4
+ import { JaypieLambda } from "./JaypieLambda";
5
+ import type { SecretsArrayItem } from "./helpers/index.js";
6
+ export interface JaypieMigrationProps {
7
+ /** Path to the bundled migration code (esbuild output directory) */
8
+ code: lambda.Code | string;
9
+ /** Constructs that must be created before the migration runs */
10
+ dependencies?: Construct[];
11
+ /** Lambda handler entry point */
12
+ handler?: string;
13
+ /** Secrets to make available to the migration Lambda */
14
+ secrets?: SecretsArrayItem[];
15
+ /** DynamoDB tables to grant read/write access */
16
+ tables?: dynamodb.ITable[];
17
+ }
18
+ export declare class JaypieMigration extends Construct {
19
+ readonly lambda: JaypieLambda;
20
+ constructor(scope: Construct, id: string, props: JaypieMigrationProps);
21
+ }
@@ -1,4 +1,5 @@
1
1
  import { IBucket } from "aws-cdk-lib/aws-s3";
2
+ import { CfnAnalyzer } from "aws-cdk-lib/aws-accessanalyzer";
2
3
  import { Trail } from "aws-cdk-lib/aws-cloudtrail";
3
4
  import { Construct } from "constructs";
4
5
  export interface JaypieOrganizationTrailProps {
@@ -26,11 +27,26 @@ export interface JaypieOrganizationTrailProps {
26
27
  * Optional project tag value
27
28
  */
28
29
  project?: string;
30
+ /**
31
+ * Whether to enable IAM Access Analyzer (organization-level)
32
+ * @default true
33
+ */
34
+ enableAccessAnalyzer?: boolean;
29
35
  /**
30
36
  * Whether to enable file validation for the trail
31
- * @default false
37
+ * @default true
32
38
  */
33
39
  enableFileValidation?: boolean;
40
+ /**
41
+ * Whether to enable Lambda data events in CloudTrail
42
+ * @default true
43
+ */
44
+ enableLambdaDataEvents?: boolean;
45
+ /**
46
+ * Whether to enable S3 data events in CloudTrail
47
+ * @default false (opt-in due to potential high volume/cost)
48
+ */
49
+ enableS3DataEvents?: boolean;
34
50
  /**
35
51
  * Number of days before logs expire
36
52
  * @default 365
@@ -53,6 +69,7 @@ export interface JaypieOrganizationTrailProps {
53
69
  enableDatadogNotifications?: boolean;
54
70
  }
55
71
  export declare class JaypieOrganizationTrail extends Construct {
72
+ readonly analyzer?: CfnAnalyzer;
56
73
  readonly bucket: IBucket;
57
74
  readonly trail: Trail;
58
75
  /**
@@ -0,0 +1 @@
1
+ export {};
@@ -7,7 +7,7 @@ export { JaypieCertificate, JaypieCertificateProps } from "./JaypieCertificate";
7
7
  export { JaypieDatadogBucket, JaypieDatadogBucketProps, } from "./JaypieDatadogBucket";
8
8
  export { JaypieDatadogForwarder, JaypieDatadogForwarderProps, } from "./JaypieDatadogForwarder";
9
9
  export { JaypieDatadogSecret } from "./JaypieDatadogSecret";
10
- export { JaypieDistribution, JaypieDistributionProps, SecurityHeadersOverrides, } from "./JaypieDistribution";
10
+ export { JaypieDistribution, JaypieDistributionProps, JaypieWafConfig, SecurityHeadersOverrides, } from "./JaypieDistribution";
11
11
  export { JaypieDnsRecord, JaypieDnsRecordProps } from "./JaypieDnsRecord";
12
12
  export { JaypieDynamoDb, JaypieDynamoDbProps } from "./JaypieDynamoDb";
13
13
  export type { IndexDefinition } from "@jaypie/fabric";
@@ -18,6 +18,7 @@ export { JaypieGitHubDeployRole, JaypieGitHubDeployRoleProps, } from "./JaypieGi
18
18
  export { JaypieHostedZone, JaypieHostedZoneRecordProps, } from "./JaypieHostedZone";
19
19
  export { JaypieInfrastructureStack } from "./JaypieInfrastructureStack";
20
20
  export { JaypieLambda, JaypieLambdaProps } from "./JaypieLambda";
21
+ export { JaypieMigration, JaypieMigrationProps } from "./JaypieMigration";
21
22
  export { JaypieMongoDbSecret } from "./JaypieMongoDbSecret";
22
23
  export { DomainNameConfig, JaypieNextJs, JaypieNextjsProps, } from "./JaypieNextJs";
23
24
  export { JaypieOpenAiSecret } from "./JaypieOpenAiSecret";
package/dist/esm/index.js CHANGED
@@ -24,10 +24,13 @@ import { Rule, RuleTargetInput } from 'aws-cdk-lib/aws-events';
24
24
  import { LambdaFunction } from 'aws-cdk-lib/aws-events-targets';
25
25
  import * as cloudfront from 'aws-cdk-lib/aws-cloudfront';
26
26
  import * as origins from 'aws-cdk-lib/aws-cloudfront-origins';
27
+ import * as wafv2 from 'aws-cdk-lib/aws-wafv2';
27
28
  import * as dynamodb from 'aws-cdk-lib/aws-dynamodb';
28
29
  import { generateIndexName, DEFAULT_SORT_KEY } from '@jaypie/fabric';
30
+ import * as cr from 'aws-cdk-lib/custom-resources';
29
31
  import { Nextjs } from 'cdk-nextjs-standalone';
30
32
  import * as path from 'path';
33
+ import { CfnAnalyzer } from 'aws-cdk-lib/aws-accessanalyzer';
31
34
  import { Trail, ReadWriteType } from 'aws-cdk-lib/aws-cloudtrail';
32
35
  import { CfnPermissionSet, CfnAssignment } from 'aws-cdk-lib/aws-sso';
33
36
  import { CfnApplication } from 'aws-cdk-lib/aws-sam';
@@ -2340,10 +2343,15 @@ class JaypieDatadogSecret extends JaypieEnvSecret {
2340
2343
  }
2341
2344
  }
2342
2345
 
2346
+ const DEFAULT_RATE_LIMIT = 2000;
2347
+ const DEFAULT_MANAGED_RULES = [
2348
+ "AWSManagedRulesCommonRuleSet",
2349
+ "AWSManagedRulesKnownBadInputsRuleSet",
2350
+ ];
2343
2351
  class JaypieDistribution extends Construct {
2344
2352
  constructor(scope, id, props) {
2345
2353
  super(scope, id);
2346
- const { certificate: certificateProp = true, defaultBehavior: propsDefaultBehavior, destination: destinationProp = true, handler, host: propsHost, logBucket: logBucketProp, originReadTimeout = Duration.seconds(CDK$2.DURATION.CLOUDFRONT_API), responseHeadersPolicy: responseHeadersPolicyProp, roleTag = CDK$2.ROLE.API, securityHeaders: securityHeadersProp, streaming = false, zone: propsZone, ...distributionProps } = props;
2354
+ const { certificate: certificateProp = true, defaultBehavior: propsDefaultBehavior, destination: destinationProp = true, handler, host: propsHost, logBucket: logBucketProp, originReadTimeout = Duration.seconds(CDK$2.DURATION.CLOUDFRONT_API), responseHeadersPolicy: responseHeadersPolicyProp, roleTag = CDK$2.ROLE.API, securityHeaders: securityHeadersProp, streaming = false, waf: wafProp = true, zone: propsZone, ...distributionProps } = props;
2347
2355
  // Validate environment variables
2348
2356
  if (process.env.CDK_ENV_API_SUBDOMAIN &&
2349
2357
  !isValidSubdomain(process.env.CDK_ENV_API_SUBDOMAIN)) {
@@ -2586,6 +2594,118 @@ class JaypieDistribution extends Construct {
2586
2594
  this.distributionDomainName = this.distribution.distributionDomainName;
2587
2595
  this.distributionId = this.distribution.distributionId;
2588
2596
  this.domainName = this.distribution.domainName;
2597
+ // Create and attach WAF WebACL
2598
+ let resolvedWebAclArn;
2599
+ const wafConfig = this.resolveWafConfig(wafProp);
2600
+ if (wafConfig) {
2601
+ if (wafConfig.webAclArn) {
2602
+ // Use existing WebACL
2603
+ resolvedWebAclArn = wafConfig.webAclArn;
2604
+ this.distribution.attachWebAclId(wafConfig.webAclArn);
2605
+ }
2606
+ else {
2607
+ // Create new WebACL
2608
+ const { managedRules = DEFAULT_MANAGED_RULES, rateLimitPerIp = DEFAULT_RATE_LIMIT, } = wafConfig;
2609
+ let priority = 0;
2610
+ const rules = [];
2611
+ // Add managed rule groups
2612
+ for (const ruleName of managedRules) {
2613
+ rules.push({
2614
+ name: ruleName,
2615
+ priority: priority++,
2616
+ overrideAction: { none: {} },
2617
+ statement: {
2618
+ managedRuleGroupStatement: {
2619
+ name: ruleName,
2620
+ vendorName: "AWS",
2621
+ },
2622
+ },
2623
+ visibilityConfig: {
2624
+ cloudWatchMetricsEnabled: true,
2625
+ metricName: ruleName,
2626
+ sampledRequestsEnabled: true,
2627
+ },
2628
+ });
2629
+ }
2630
+ // Add rate-based rule
2631
+ rules.push({
2632
+ name: "RateLimitPerIp",
2633
+ priority: priority++,
2634
+ action: { block: {} },
2635
+ statement: {
2636
+ rateBasedStatement: {
2637
+ aggregateKeyType: "IP",
2638
+ limit: rateLimitPerIp,
2639
+ },
2640
+ },
2641
+ visibilityConfig: {
2642
+ cloudWatchMetricsEnabled: true,
2643
+ metricName: "RateLimitPerIp",
2644
+ sampledRequestsEnabled: true,
2645
+ },
2646
+ });
2647
+ const webAcl = new wafv2.CfnWebACL(this, "WebAcl", {
2648
+ defaultAction: { allow: {} },
2649
+ name: constructEnvName("WebAcl"),
2650
+ rules,
2651
+ scope: "CLOUDFRONT",
2652
+ visibilityConfig: {
2653
+ cloudWatchMetricsEnabled: true,
2654
+ metricName: constructEnvName("WebAcl"),
2655
+ sampledRequestsEnabled: true,
2656
+ },
2657
+ });
2658
+ this.webAcl = webAcl;
2659
+ resolvedWebAclArn = webAcl.attrArn;
2660
+ this.distribution.attachWebAclId(webAcl.attrArn);
2661
+ Tags.of(webAcl).add(CDK$2.TAG.ROLE, roleTag);
2662
+ }
2663
+ }
2664
+ // Create WAF logging
2665
+ if (resolvedWebAclArn && wafConfig) {
2666
+ const { logBucket: wafLogBucketProp = true } = wafConfig;
2667
+ let wafLogBucket;
2668
+ if (wafLogBucketProp === true) {
2669
+ // Create inline WAF logging bucket with Datadog forwarding
2670
+ const createdBucket = new s3.Bucket(this, constructEnvName("WafLogBucket"), {
2671
+ bucketName: `aws-waf-logs-${constructEnvName("waf").toLowerCase()}`,
2672
+ lifecycleRules: [
2673
+ {
2674
+ expiration: Duration.days(90),
2675
+ transitions: [
2676
+ {
2677
+ storageClass: s3.StorageClass.INFREQUENT_ACCESS,
2678
+ transitionAfter: Duration.days(30),
2679
+ },
2680
+ ],
2681
+ },
2682
+ ],
2683
+ objectOwnership: s3.ObjectOwnership.OBJECT_WRITER,
2684
+ removalPolicy: RemovalPolicy.RETAIN,
2685
+ });
2686
+ Tags.of(createdBucket).add(CDK$2.TAG.ROLE, CDK$2.ROLE.MONITORING);
2687
+ // Add Datadog forwarder notification
2688
+ if (destinationProp !== false) {
2689
+ const lambdaDestination = destinationProp === true
2690
+ ? new LambdaDestination(resolveDatadogForwarderFunction(this))
2691
+ : destinationProp;
2692
+ createdBucket.addEventNotification(s3.EventType.OBJECT_CREATED, lambdaDestination);
2693
+ }
2694
+ wafLogBucket = createdBucket;
2695
+ }
2696
+ else if (typeof wafLogBucketProp === "object") {
2697
+ // Use provided IBucket
2698
+ wafLogBucket = wafLogBucketProp;
2699
+ }
2700
+ // wafLogBucketProp === false → no logging
2701
+ if (wafLogBucket) {
2702
+ this.wafLogBucket = wafLogBucket;
2703
+ new wafv2.CfnLoggingConfiguration(this, "WafLoggingConfig", {
2704
+ logDestinationConfigs: [wafLogBucket.bucketArn],
2705
+ resourceArn: resolvedWebAclArn,
2706
+ });
2707
+ }
2708
+ }
2589
2709
  // Create DNS records if we have host and zone
2590
2710
  if (host && hostedZone) {
2591
2711
  const aRecord = new route53.ARecord(this, "AliasRecord", {
@@ -2632,6 +2752,15 @@ class JaypieDistribution extends Construct {
2632
2752
  "exportName" in value &&
2633
2753
  typeof value.exportName === "string");
2634
2754
  }
2755
+ resolveWafConfig(wafProp) {
2756
+ if (wafProp === false)
2757
+ return undefined;
2758
+ if (wafProp === true)
2759
+ return {};
2760
+ if (wafProp.enabled === false)
2761
+ return undefined;
2762
+ return wafProp;
2763
+ }
2635
2764
  resolveLogBucket(logBucketProp) {
2636
2765
  // true = use account logging bucket
2637
2766
  if (logBucketProp === true) {
@@ -2895,6 +3024,9 @@ class JaypieDynamoDb extends Construct {
2895
3024
  get encryptionKey() {
2896
3025
  return this._table.encryptionKey;
2897
3026
  }
3027
+ get grants() {
3028
+ return this._table.grants;
3029
+ }
2898
3030
  applyRemovalPolicy(policy) {
2899
3031
  this._table.applyRemovalPolicy(policy);
2900
3032
  }
@@ -3253,6 +3385,35 @@ class JaypieInfrastructureStack extends JaypieStack {
3253
3385
  }
3254
3386
  }
3255
3387
 
3388
+ class JaypieMigration extends Construct {
3389
+ constructor(scope, id, props) {
3390
+ super(scope, id);
3391
+ const { code, dependencies = [], handler = "index.handler", secrets = [], tables = [], } = props;
3392
+ // Migration Lambda — 5 minute timeout for long-running migrations
3393
+ this.lambda = new JaypieLambda(this, "MigrationLambda", {
3394
+ code,
3395
+ description: "DynamoDB migration custom resource",
3396
+ handler,
3397
+ roleTag: CDK$2.ROLE.PROCESSING,
3398
+ secrets,
3399
+ tables,
3400
+ timeout: cdk.Duration.minutes(5),
3401
+ });
3402
+ // Custom Resource provider wrapping the Lambda
3403
+ const provider = new cr.Provider(this, "MigrationProvider", {
3404
+ onEventHandler: this.lambda,
3405
+ });
3406
+ // Custom Resource that triggers on every deploy
3407
+ const resource = new cdk.CustomResource(this, "MigrationResource", {
3408
+ serviceToken: provider.serviceToken,
3409
+ });
3410
+ // Ensure dependencies are created before the migration runs
3411
+ for (const dep of dependencies) {
3412
+ resource.node.addDependency(dep);
3413
+ }
3414
+ }
3415
+ }
3416
+
3256
3417
  class JaypieMongoDbSecret extends JaypieEnvSecret {
3257
3418
  constructor(scope, id = "MongoConnectionString", props) {
3258
3419
  const defaultProps = {
@@ -3471,7 +3632,7 @@ class JaypieOrganizationTrail extends Construct {
3471
3632
  // Resolve options with defaults
3472
3633
  const { bucketName = process.env.PROJECT_NONCE
3473
3634
  ? `organization-cloudtrail-${process.env.PROJECT_NONCE}`
3474
- : "organization-cloudtrail", enableDatadogNotifications = true, enableFileValidation = false, expirationDays = 365, glacierTransitionDays = 180, infrequentAccessTransitionDays = 30, project, service = CDK$2.SERVICE.INFRASTRUCTURE, trailName = process.env.PROJECT_NONCE
3635
+ : "organization-cloudtrail", enableAccessAnalyzer = true, enableDatadogNotifications = true, enableFileValidation = true, enableLambdaDataEvents = true, enableS3DataEvents = false, expirationDays = 365, glacierTransitionDays = 180, infrequentAccessTransitionDays = 30, project, service = CDK$2.SERVICE.INFRASTRUCTURE, trailName = process.env.PROJECT_NONCE
3475
3636
  ? `organization-cloudtrail-${process.env.PROJECT_NONCE}`
3476
3637
  : "organization-cloudtrail", } = props;
3477
3638
  // Create the S3 bucket for CloudTrail logs
@@ -3531,12 +3692,34 @@ class JaypieOrganizationTrail extends Construct {
3531
3692
  managementEvents: ReadWriteType.ALL,
3532
3693
  trailName,
3533
3694
  });
3695
+ // Add data event selectors
3696
+ if (enableLambdaDataEvents) {
3697
+ this.trail.logAllLambdaDataEvents();
3698
+ }
3699
+ if (enableS3DataEvents) {
3700
+ this.trail.logAllS3DataEvents();
3701
+ }
3534
3702
  // Add tags to trail
3535
3703
  cdk.Tags.of(this.trail).add(CDK$2.TAG.SERVICE, service);
3536
3704
  cdk.Tags.of(this.trail).add(CDK$2.TAG.ROLE, CDK$2.ROLE.MONITORING);
3537
3705
  if (project) {
3538
3706
  cdk.Tags.of(this.trail).add(CDK$2.TAG.PROJECT, project);
3539
3707
  }
3708
+ // Create IAM Access Analyzer
3709
+ if (enableAccessAnalyzer) {
3710
+ const analyzerName = process.env.PROJECT_NONCE
3711
+ ? `organization-access-analyzer-${process.env.PROJECT_NONCE}`
3712
+ : "organization-access-analyzer";
3713
+ this.analyzer = new CfnAnalyzer(this, "AccessAnalyzer", {
3714
+ analyzerName,
3715
+ type: "ORGANIZATION",
3716
+ });
3717
+ cdk.Tags.of(this.analyzer).add(CDK$2.TAG.SERVICE, service);
3718
+ cdk.Tags.of(this.analyzer).add(CDK$2.TAG.ROLE, CDK$2.ROLE.MONITORING);
3719
+ if (project) {
3720
+ cdk.Tags.of(this.analyzer).add(CDK$2.TAG.PROJECT, project);
3721
+ }
3722
+ }
3540
3723
  }
3541
3724
  }
3542
3725
 
@@ -4580,5 +4763,5 @@ class JaypieWebSocketTable extends Construct {
4580
4763
  }
4581
4764
  }
4582
4765
 
4583
- export { CDK$2 as CDK, JaypieAccountLoggingBucket, JaypieApiGateway, JaypieAppStack, JaypieBucketQueuedLambda, JaypieCertificate, JaypieDatadogBucket, JaypieDatadogForwarder, JaypieDatadogSecret, JaypieDistribution, JaypieDnsRecord, JaypieDynamoDb, JaypieEnvSecret, JaypieEventsRule, JaypieExpressLambda, JaypieGitHubDeployRole, JaypieHostedZone, JaypieInfrastructureStack, JaypieLambda, JaypieMongoDbSecret, JaypieNextJs, JaypieOpenAiSecret, JaypieOrganizationTrail, JaypieQueuedLambda, JaypieSsoPermissions, JaypieSsoSyncApplication, JaypieStack, JaypieStaticWebBucket, JaypieTraceSigningKeySecret, JaypieWebDeploymentBucket, JaypieWebSocket, JaypieWebSocketLambda, JaypieWebSocketTable, addDatadogLayers, clearAllCertificateCaches, clearAllSecretsCaches, clearCertificateCache, clearSecretsCache, constructEnvName, constructStackName, constructTagger, envHostname, extendDatadogRole, isEnv, isProductionEnv, isSandboxEnv, isValidHostname$1 as isValidHostname, isValidSubdomain, jaypieLambdaEnv, mergeDomain, resolveCertificate, resolveDatadogForwarderFunction, resolveDatadogLayers, resolveDatadogLoggingDestination, resolveEnvironment, resolveHostedZone, resolveParamsAndSecrets, resolveSecrets };
4766
+ export { CDK$2 as CDK, JaypieAccountLoggingBucket, JaypieApiGateway, JaypieAppStack, JaypieBucketQueuedLambda, JaypieCertificate, JaypieDatadogBucket, JaypieDatadogForwarder, JaypieDatadogSecret, JaypieDistribution, JaypieDnsRecord, JaypieDynamoDb, JaypieEnvSecret, JaypieEventsRule, JaypieExpressLambda, JaypieGitHubDeployRole, JaypieHostedZone, JaypieInfrastructureStack, JaypieLambda, JaypieMigration, JaypieMongoDbSecret, JaypieNextJs, JaypieOpenAiSecret, JaypieOrganizationTrail, JaypieQueuedLambda, JaypieSsoPermissions, JaypieSsoSyncApplication, JaypieStack, JaypieStaticWebBucket, JaypieTraceSigningKeySecret, JaypieWebDeploymentBucket, JaypieWebSocket, JaypieWebSocketLambda, JaypieWebSocketTable, addDatadogLayers, clearAllCertificateCaches, clearAllSecretsCaches, clearCertificateCache, clearSecretsCache, constructEnvName, constructStackName, constructTagger, envHostname, extendDatadogRole, isEnv, isProductionEnv, isSandboxEnv, isValidHostname$1 as isValidHostname, isValidSubdomain, jaypieLambdaEnv, mergeDomain, resolveCertificate, resolveDatadogForwarderFunction, resolveDatadogLayers, resolveDatadogLoggingDestination, resolveEnvironment, resolveHostedZone, resolveParamsAndSecrets, resolveSecrets };
4584
4767
  //# sourceMappingURL=index.js.map