@jaypie/constructs 1.1.39 → 1.1.41

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.
@@ -62,6 +62,7 @@ export declare class JaypieWebDeploymentBucket extends Construct implements s3.I
62
62
  grantRead(identity: any, objectsKeyPattern?: any): any;
63
63
  grantReadWrite(identity: any, objectsKeyPattern?: any): any;
64
64
  grantWrite(identity: any, objectsKeyPattern?: any): any;
65
+ grantReplicationPermission(identity: any, props: any): any;
65
66
  s3UrlForObject(key?: string): string;
66
67
  urlForObject(key?: string): string;
67
68
  virtualHostedUrlForObject(key?: string, options?: s3.VirtualHostedStyleUrlOptions): string;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,5 @@
1
+ import * as lambda from "aws-cdk-lib/aws-lambda";
2
+ export interface AddDatadogLayerOptions {
3
+ datadogApiKeyArn?: string;
4
+ }
5
+ export declare function addDatadogLayer(lambdaFunction: lambda.Function, options?: AddDatadogLayerOptions): boolean;
@@ -0,0 +1,11 @@
1
+ import * as lambda from "aws-cdk-lib/aws-lambda";
2
+ export interface AddParamsAndSecretsOptions {
3
+ paramsAndSecrets?: lambda.ParamsAndSecretsLayerVersion | boolean;
4
+ paramsAndSecretsOptions?: {
5
+ cacheSize?: number;
6
+ logLevel?: lambda.ParamsAndSecretsLogLevel;
7
+ parameterStoreTtl?: number;
8
+ secretsManagerTtl?: number;
9
+ };
10
+ }
11
+ export declare function addParamsAndSecrets(lambdaFunction: lambda.Function, options?: AddParamsAndSecretsOptions): boolean;
@@ -0,0 +1,4 @@
1
+ import { Construct } from "constructs";
2
+ export declare function constructTagger(construct: Construct, { name }?: {
3
+ name?: string;
4
+ }): boolean;
@@ -0,0 +1,6 @@
1
+ export declare function envHostname({ component, domain, env, subdomain, }: {
2
+ component?: string;
3
+ domain?: string;
4
+ env?: string;
5
+ subdomain?: string;
6
+ }): string;
@@ -1,4 +1,9 @@
1
+ export { addDatadogLayer } from "./addDatadogLayer";
2
+ export { addParamsAndSecrets } from "./addParamsAndSecrets";
1
3
  export { constructEnvName } from "./constructEnvName";
2
4
  export { constructStackName } from "./constructStackName";
5
+ export { constructTagger } from "./constructTagger";
6
+ export { envHostname } from "./envHostname";
3
7
  export { isEnv, isProductionEnv, isSandboxEnv } from "./isEnv";
4
- export { stackTagger } from "./stackTagger";
8
+ export { jaypieLambdaEnv } from "./jaypieLambdaEnv";
9
+ export { resolveHostedZone } from "./resolveHostedZone";
@@ -0,0 +1,8 @@
1
+ export interface JaypieLambdaEnvOptions {
2
+ initialEnvironment?: {
3
+ [key: string]: string;
4
+ };
5
+ }
6
+ export declare function jaypieLambdaEnv(options?: JaypieLambdaEnvOptions): {
7
+ [key: string]: string;
8
+ };
@@ -0,0 +1,6 @@
1
+ import { Construct } from "constructs";
2
+ import * as route53 from "aws-cdk-lib/aws-route53";
3
+ export declare function resolveHostedZone(scope: Construct, { name, zone, }: {
4
+ name?: string;
5
+ zone?: string | route53.IHostedZone;
6
+ }): route53.IHostedZone;
package/dist/esm/index.js CHANGED
@@ -1,28 +1,121 @@
1
1
  import { Construct } from 'constructs';
2
2
  import * as cdk from 'aws-cdk-lib';
3
- import { Tags, Stack, Duration, RemovalPolicy, Fn, CfnOutput, SecretValue } from 'aws-cdk-lib';
3
+ import { Stack, Tags, Duration, RemovalPolicy, Fn, CfnOutput, SecretValue } from 'aws-cdk-lib';
4
4
  import * as acm from 'aws-cdk-lib/aws-certificatemanager';
5
5
  import * as apiGateway from 'aws-cdk-lib/aws-apigateway';
6
6
  import * as route53 from 'aws-cdk-lib/aws-route53';
7
7
  import { HostedZone } from 'aws-cdk-lib/aws-route53';
8
8
  import * as route53Targets from 'aws-cdk-lib/aws-route53-targets';
9
- import { CDK as CDK$2, mergeDomain, isValidSubdomain, ConfigurationError, isValidHostname } from '@jaypie/cdk';
9
+ import { CDK as CDK$2, ConfigurationError, mergeDomain, isValidSubdomain, isValidHostname } from '@jaypie/cdk';
10
+ import * as lambda from 'aws-cdk-lib/aws-lambda';
11
+ import * as secretsmanager from 'aws-cdk-lib/aws-secretsmanager';
10
12
  import * as s3 from 'aws-cdk-lib/aws-s3';
11
13
  import * as s3n from 'aws-cdk-lib/aws-s3-notifications';
12
- import * as lambda from 'aws-cdk-lib/aws-lambda';
13
14
  import * as sqs from 'aws-cdk-lib/aws-sqs';
14
15
  import * as lambdaEventSources from 'aws-cdk-lib/aws-lambda-event-sources';
15
- import * as secretsmanager from 'aws-cdk-lib/aws-secretsmanager';
16
16
  import { ServicePrincipal, Role, FederatedPrincipal, PolicyStatement, Effect } from 'aws-cdk-lib/aws-iam';
17
17
  import { LogGroup, RetentionDays, FilterPattern } from 'aws-cdk-lib/aws-logs';
18
18
  import * as sso from 'aws-cdk-lib/aws-sso';
19
19
  import * as cloudfront from 'aws-cdk-lib/aws-cloudfront';
20
20
  import * as origins from 'aws-cdk-lib/aws-cloudfront-origins';
21
21
 
22
+ function addDatadogLayer(lambdaFunction, options = {}) {
23
+ const { datadogApiKeyArn } = options;
24
+ // Resolve the Datadog API key ARN from multiple sources
25
+ const resolvedDatadogApiKeyArn = datadogApiKeyArn ||
26
+ process.env.DATADOG_API_KEY_ARN ||
27
+ process.env.CDK_ENV_DATADOG_API_KEY_ARN;
28
+ // Return false if no API key is found
29
+ if (!resolvedDatadogApiKeyArn) {
30
+ return false;
31
+ }
32
+ const stack = Stack.of(lambdaFunction);
33
+ // Create Datadog Node.js layer
34
+ const datadogNodeLayer = lambda.LayerVersion.fromLayerVersionArn(stack, `DatadogNodeLayer-${lambdaFunction.node.id}`, `arn:aws:lambda:${stack.region}:464622532012:layer:Datadog-Node20-x:${CDK$2.DATADOG.LAYER.NODE}`);
35
+ // Create Datadog Extension layer
36
+ const datadogExtensionLayer = lambda.LayerVersion.fromLayerVersionArn(stack, `DatadogExtensionLayer-${lambdaFunction.node.id}`, `arn:aws:lambda:${stack.region}:464622532012:layer:Datadog-Extension:${CDK$2.DATADOG.LAYER.EXTENSION}`);
37
+ // Add layers to the lambda function
38
+ lambdaFunction.addLayers(datadogNodeLayer, datadogExtensionLayer);
39
+ // Define Datadog environment variables
40
+ const datadogEnvVars = {
41
+ DD_API_KEY_SECRET_ARN: resolvedDatadogApiKeyArn,
42
+ DD_ENHANCED_METRICS: "true",
43
+ DD_ENV: process.env.PROJECT_ENV || "",
44
+ DD_PROFILING_ENABLED: "false",
45
+ DD_SERVERLESS_APPSEC_ENABLED: "false",
46
+ DD_SERVICE: process.env.PROJECT_SERVICE || "",
47
+ DD_SITE: CDK$2.DATADOG.SITE,
48
+ DD_TAGS: `${CDK$2.TAG.SPONSOR}:${process.env.PROJECT_SPONSOR || ""}`,
49
+ DD_TRACE_OTEL_ENABLED: "false",
50
+ };
51
+ // Add environment variables only if they don't already exist
52
+ Object.entries(datadogEnvVars).forEach(([key, value]) => {
53
+ if (lambdaFunction.environment[key] === undefined) {
54
+ lambdaFunction.addEnvironment(key, value);
55
+ }
56
+ });
57
+ // Grant Datadog API key read permission
58
+ const datadogApiKey = secretsmanager.Secret.fromSecretCompleteArn(stack, `DatadogApiKeyGrant-${lambdaFunction.node.id}`, resolvedDatadogApiKeyArn);
59
+ datadogApiKey.grantRead(lambdaFunction);
60
+ return true;
61
+ }
62
+
63
+ function addParamsAndSecrets(lambdaFunction, options = {}) {
64
+ const { paramsAndSecrets, paramsAndSecretsOptions } = options;
65
+ // Return false if explicitly disabled
66
+ if (paramsAndSecrets === false) {
67
+ return false;
68
+ }
69
+ const stack = Stack.of(lambdaFunction);
70
+ let resolvedLayer = undefined;
71
+ if (paramsAndSecrets instanceof lambda.ParamsAndSecretsLayerVersion) {
72
+ // For custom ParamsAndSecretsLayerVersion, we need to extract the ARN
73
+ // This is a workaround since ParamsAndSecretsLayerVersion doesn't implement ILayerVersion
74
+ const layerArn = `arn:aws:lambda:${stack.region}:017000801446:layer:AWSLambdaParametersAndSecrets:${lambda.ParamsAndSecretsVersions.V1_0_103}`;
75
+ resolvedLayer = lambda.LayerVersion.fromLayerVersionArn(stack, `ParamsAndSecretsLayer-${lambdaFunction.node.id}`, layerArn);
76
+ // Set environment variables for configuration
77
+ if (paramsAndSecretsOptions?.cacheSize) {
78
+ lambdaFunction.addEnvironment("PARAMETERS_SECRETS_EXTENSION_CACHE_SIZE", paramsAndSecretsOptions.cacheSize.toString());
79
+ }
80
+ if (paramsAndSecretsOptions?.logLevel) {
81
+ lambdaFunction.addEnvironment("PARAMETERS_SECRETS_EXTENSION_LOG_LEVEL", paramsAndSecretsOptions.logLevel);
82
+ }
83
+ if (paramsAndSecretsOptions?.parameterStoreTtl) {
84
+ lambdaFunction.addEnvironment("PARAMETERS_SECRETS_EXTENSION_PARAMETER_STORE_TTL", paramsAndSecretsOptions.parameterStoreTtl.toString());
85
+ }
86
+ if (paramsAndSecretsOptions?.secretsManagerTtl) {
87
+ lambdaFunction.addEnvironment("PARAMETERS_SECRETS_EXTENSION_SECRETS_MANAGER_TTL", paramsAndSecretsOptions.secretsManagerTtl.toString());
88
+ }
89
+ }
90
+ else {
91
+ // Create default ParamsAndSecrets layer using LayerVersion.fromLayerVersionArn
92
+ const layerArn = `arn:aws:lambda:${stack.region}:017000801446:layer:AWSLambdaParametersAndSecrets:${lambda.ParamsAndSecretsVersions.V1_0_103}`;
93
+ resolvedLayer = lambda.LayerVersion.fromLayerVersionArn(stack, `ParamsAndSecretsLayer-${lambdaFunction.node.id}`, layerArn);
94
+ // Set default environment variables
95
+ if (paramsAndSecretsOptions?.cacheSize) {
96
+ lambdaFunction.addEnvironment("PARAMETERS_SECRETS_EXTENSION_CACHE_SIZE", paramsAndSecretsOptions.cacheSize.toString());
97
+ }
98
+ const logLevel = paramsAndSecretsOptions?.logLevel || lambda.ParamsAndSecretsLogLevel.WARN;
99
+ lambdaFunction.addEnvironment("PARAMETERS_SECRETS_EXTENSION_LOG_LEVEL", logLevel);
100
+ if (paramsAndSecretsOptions?.parameterStoreTtl) {
101
+ lambdaFunction.addEnvironment("PARAMETERS_SECRETS_EXTENSION_PARAMETER_STORE_TTL", paramsAndSecretsOptions.parameterStoreTtl.toString());
102
+ }
103
+ if (paramsAndSecretsOptions?.secretsManagerTtl) {
104
+ lambdaFunction.addEnvironment("PARAMETERS_SECRETS_EXTENSION_SECRETS_MANAGER_TTL", paramsAndSecretsOptions.secretsManagerTtl.toString());
105
+ }
106
+ }
107
+ // Add the layer to the lambda function
108
+ if (resolvedLayer) {
109
+ lambdaFunction.addLayers(resolvedLayer);
110
+ return true;
111
+ }
112
+ return false;
113
+ }
114
+
22
115
  function constructEnvName(name, opts) {
23
116
  const env = opts?.env ?? process.env.PROJECT_ENV ?? "build";
24
117
  const key = opts?.key ?? process.env.PROJECT_KEY ?? "project";
25
- const nonce = opts?.nonce ?? process.env.PROJECT_NONCE ?? "cfe2";
118
+ const nonce = opts?.nonce ?? process.env.PROJECT_NONCE ?? "cfe2"; // This default is intentionally short. It is not a special value but should not be changed.
26
119
  return `${env}-${key}-${name}-${nonce}`;
27
120
  }
28
121
 
@@ -35,25 +128,6 @@ function constructStackName(key) {
35
128
  }
36
129
  }
37
130
 
38
- /**
39
- * Check if the current environment matches the given environment
40
- */
41
- function isEnv(env) {
42
- return process.env.PROJECT_ENV === env;
43
- }
44
- /**
45
- * Check if the current environment is production
46
- */
47
- function isProductionEnv() {
48
- return isEnv(CDK$2.ENV.PRODUCTION);
49
- }
50
- /**
51
- * Check if the current environment is sandbox
52
- */
53
- function isSandboxEnv() {
54
- return isEnv(CDK$2.ENV.SANDBOX);
55
- }
56
-
57
131
  const CDK$1 = {
58
132
  CREATION: {
59
133
  CDK: "cdk",
@@ -77,35 +151,137 @@ const CDK$1 = {
77
151
  VERSION: "version",
78
152
  },
79
153
  };
80
- function stackTagger(stack, { name } = {}) {
154
+ function constructTagger(construct, { name } = {}) {
81
155
  const stackName = name || constructStackName();
82
156
  const version = process.env.npm_package_version || process.env.PROJECT_VERSION || null;
83
157
  if (process.env.PROJECT_COMMIT && process.env.PROJECT_COMMIT.length > 8) {
84
- Tags.of(stack).add(CDK$1.TAG.BUILD_HEX, process.env.PROJECT_COMMIT.slice(0, 8));
158
+ Tags.of(construct).add(CDK$1.TAG.BUILD_HEX, process.env.PROJECT_COMMIT.slice(0, 8));
85
159
  }
86
- Tags.of(stack).add(CDK$1.TAG.BUILD_DATE, new Date().toISOString());
87
- Tags.of(stack).add(CDK$1.TAG.BUILD_TIME, Date.now().toString());
160
+ Tags.of(construct).add(CDK$1.TAG.BUILD_DATE, new Date().toISOString());
161
+ Tags.of(construct).add(CDK$1.TAG.BUILD_TIME, Date.now().toString());
88
162
  if (process.env.PROJECT_COMMIT)
89
- Tags.of(stack).add(CDK$1.TAG.COMMIT, process.env.PROJECT_COMMIT);
90
- Tags.of(stack).add(CDK$1.TAG.CREATION, CDK$1.CREATION.CDK);
163
+ Tags.of(construct).add(CDK$1.TAG.COMMIT, process.env.PROJECT_COMMIT);
164
+ Tags.of(construct).add(CDK$1.TAG.CREATION, CDK$1.CREATION.CDK);
91
165
  if (process.env.PROJECT_ENV)
92
- Tags.of(stack).add(CDK$1.TAG.ENV, process.env.PROJECT_ENV);
166
+ Tags.of(construct).add(CDK$1.TAG.ENV, process.env.PROJECT_ENV);
93
167
  if (process.env.PROJECT_NONCE)
94
- Tags.of(stack).add(CDK$1.TAG.NONCE, process.env.PROJECT_NONCE);
168
+ Tags.of(construct).add(CDK$1.TAG.NONCE, process.env.PROJECT_NONCE);
95
169
  if (process.env.PROJECT_KEY)
96
- Tags.of(stack).add(CDK$1.TAG.PROJECT, process.env.PROJECT_KEY);
97
- Tags.of(stack).add(CDK$1.TAG.ROLE, CDK$1.ROLE.STACK);
170
+ Tags.of(construct).add(CDK$1.TAG.PROJECT, process.env.PROJECT_KEY);
171
+ Tags.of(construct).add(CDK$1.TAG.ROLE, CDK$1.ROLE.STACK);
98
172
  if (process.env.PROJECT_SERVICE)
99
- Tags.of(stack).add(CDK$1.TAG.SERVICE, process.env.PROJECT_SERVICE);
173
+ Tags.of(construct).add(CDK$1.TAG.SERVICE, process.env.PROJECT_SERVICE);
100
174
  if (process.env.PROJECT_SPONSOR)
101
- Tags.of(stack).add(CDK$1.TAG.SPONSOR, process.env.PROJECT_SPONSOR);
175
+ Tags.of(construct).add(CDK$1.TAG.SPONSOR, process.env.PROJECT_SPONSOR);
102
176
  if (stackName)
103
- Tags.of(stack).add(CDK$1.TAG.STACK, stackName);
177
+ Tags.of(construct).add(CDK$1.TAG.STACK, stackName);
104
178
  if (version)
105
- Tags.of(stack).add(CDK$1.TAG.VERSION, version);
179
+ Tags.of(construct).add(CDK$1.TAG.VERSION, version);
106
180
  return true;
107
181
  }
108
182
 
183
+ function envHostname({ component, domain, env, subdomain, }) {
184
+ const resolvedDomain = domain || process.env.CDK_ENV_DOMAIN || process.env.CDK_ENV_HOSTED_ZONE;
185
+ if (!resolvedDomain) {
186
+ throw new ConfigurationError("No hostname `domain` provided. Set CDK_ENV_DOMAIN or CDK_ENV_HOSTED_ZONE to use environment domain");
187
+ }
188
+ const resolvedComponent = component === "@" || component === "" ? undefined : component;
189
+ const resolvedSubdomain = subdomain || process.env.CDK_ENV_SUBDOMAIN;
190
+ const resolvedEnv = env || process.env.PROJECT_ENV;
191
+ const parts = [
192
+ resolvedComponent,
193
+ resolvedSubdomain,
194
+ resolvedEnv,
195
+ resolvedDomain,
196
+ ].filter((part) => part);
197
+ return parts.join(".");
198
+ }
199
+
200
+ /**
201
+ * Check if the current environment matches the given environment
202
+ */
203
+ function isEnv(env) {
204
+ return process.env.PROJECT_ENV === env;
205
+ }
206
+ /**
207
+ * Check if the current environment is production
208
+ */
209
+ function isProductionEnv() {
210
+ return isEnv(CDK$2.ENV.PRODUCTION);
211
+ }
212
+ /**
213
+ * Check if the current environment is sandbox
214
+ */
215
+ function isSandboxEnv() {
216
+ return isEnv(CDK$2.ENV.SANDBOX);
217
+ }
218
+
219
+ function jaypieLambdaEnv(options = {}) {
220
+ const { initialEnvironment = {} } = options;
221
+ // Start with empty environment - we'll only add valid values
222
+ let environment = {};
223
+ // First, add all valid string values from initialEnvironment
224
+ Object.entries(initialEnvironment).forEach(([key, value]) => {
225
+ if (typeof value === "string") {
226
+ environment[key] = value;
227
+ }
228
+ });
229
+ // Default environment values
230
+ const defaultEnvValues = {
231
+ AWS_LAMBDA_NODEJS_DISABLE_CALLBACK_WARNING: "true",
232
+ };
233
+ // Apply default environment values with user overrides
234
+ Object.entries(defaultEnvValues).forEach(([key, defaultValue]) => {
235
+ if (key in initialEnvironment) {
236
+ const userValue = initialEnvironment[key];
237
+ // If user passes a string, it's already added above
238
+ // If user passes non-string falsy value, omit the key
239
+ if (!userValue) {
240
+ delete environment[key];
241
+ }
242
+ // Ignore non-string truthy values (key not added)
243
+ }
244
+ else {
245
+ // No user override, use default value
246
+ environment[key] = defaultValue;
247
+ }
248
+ });
249
+ // Default environment variables from process.env if present
250
+ const defaultEnvVars = [
251
+ "DATADOG_API_KEY_ARN",
252
+ "LOG_LEVEL",
253
+ "MODULE_LOGGER",
254
+ "MODULE_LOG_LEVEL",
255
+ "PROJECT_CHAOS",
256
+ "PROJECT_COMMIT",
257
+ "PROJECT_ENV",
258
+ "PROJECT_KEY",
259
+ "PROJECT_SECRET",
260
+ "PROJECT_SERVICE",
261
+ "PROJECT_SPONSOR",
262
+ "PROJECT_VERSION",
263
+ ];
264
+ // Add default environment variables if they exist in process.env
265
+ defaultEnvVars.forEach((envVar) => {
266
+ if (process.env[envVar] && !environment[envVar]) {
267
+ environment[envVar] = process.env[envVar];
268
+ }
269
+ });
270
+ return environment;
271
+ }
272
+
273
+ function resolveHostedZone(scope, { name = "HostedZone", zone = process.env.CDK_ENV_HOSTED_ZONE, }) {
274
+ if (!zone) {
275
+ throw new ConfigurationError("No `zone` provided. Set CDK_ENV_HOSTED_ZONE to use environment zone");
276
+ }
277
+ if (typeof zone === "string") {
278
+ return route53.HostedZone.fromLookup(scope, name, {
279
+ domainName: zone,
280
+ });
281
+ }
282
+ return zone;
283
+ }
284
+
109
285
  class JaypieApiGateway extends Construct {
110
286
  constructor(scope, id, props) {
111
287
  super(scope, id);
@@ -132,14 +308,7 @@ class JaypieApiGateway extends Construct {
132
308
  let hostedZone;
133
309
  let certificateToUse;
134
310
  if (host && zone) {
135
- if (typeof zone === "string") {
136
- hostedZone = route53.HostedZone.fromLookup(this, "HostedZone", {
137
- domainName: zone,
138
- });
139
- }
140
- else {
141
- hostedZone = zone;
142
- }
311
+ hostedZone = resolveHostedZone(this, { zone });
143
312
  if (certificate === true) {
144
313
  certificateToUse = new acm.Certificate(this, certificateName, {
145
314
  domainName: host,
@@ -271,7 +440,7 @@ class JaypieStack extends Stack {
271
440
  };
272
441
  super(scope, id, stackProps);
273
442
  // Apply tags
274
- stackTagger(this, { name: stackProps.stackName });
443
+ constructTagger(this, { name: stackProps.stackName });
275
444
  }
276
445
  }
277
446
 
@@ -290,102 +459,11 @@ class JaypieLambda extends Construct {
290
459
  constructor(scope, id, props) {
291
460
  super(scope, id);
292
461
  const { allowAllOutbound, allowPublicSubnet, architecture = lambda.Architecture.X86_64, code, codeSigningConfig, datadogApiKeyArn, deadLetterQueue, deadLetterQueueEnabled, deadLetterTopic, description, environment: initialEnvironment = {}, environmentEncryption, envSecrets = {}, ephemeralStorageSize, filesystem, handler = "index.handler", initialPolicy, layers = [], logRetention = CDK$2.LAMBDA.LOG_RETENTION, logRetentionRole, logRetentionRetryOptions, maxEventAge, memorySize = CDK$2.LAMBDA.MEMORY_SIZE, paramsAndSecrets, paramsAndSecretsOptions, profiling, profilingGroup, provisionedConcurrentExecutions, reservedConcurrentExecutions, retryAttempts, roleTag = CDK$2.ROLE.PROCESSING, runtime = lambda.Runtime.NODEJS_22_X, runtimeManagementMode, secrets = [], securityGroups, timeout = Duration.seconds(CDK$2.DURATION.LAMBDA_WORKER), tracing, vendorTag, vpc, vpcSubnets, } = props;
293
- // Create a mutable copy of the environment variables
294
- let environment = { ...initialEnvironment };
295
- // Default environment values
296
- const defaultEnvValues = {
297
- AWS_LAMBDA_NODEJS_DISABLE_CALLBACK_WARNING: "true",
298
- };
299
- // Apply default environment values with user overrides
300
- Object.entries(defaultEnvValues).forEach(([key, defaultValue]) => {
301
- if (key in initialEnvironment) {
302
- const userValue = initialEnvironment[key];
303
- // If user passes a string, use that value
304
- if (typeof userValue === "string") {
305
- environment[key] = userValue;
306
- }
307
- // If user passes non-string falsy value, omit the key
308
- else if (!userValue) {
309
- delete environment[key];
310
- }
311
- // Ignore non-string truthy values (key already not present)
312
- }
313
- else {
314
- // No user override, use default value
315
- environment[key] = defaultValue;
316
- }
317
- });
318
- // Default environment variables from process.env if present
319
- const defaultEnvVars = [
320
- "DATADOG_API_KEY_ARN",
321
- "LOG_LEVEL",
322
- "MODULE_LOGGER",
323
- "MODULE_LOG_LEVEL",
324
- "PROJECT_COMMIT",
325
- "PROJECT_ENV",
326
- "PROJECT_KEY",
327
- "PROJECT_SECRET",
328
- "PROJECT_SERVICE",
329
- "PROJECT_SPONSOR",
330
- "PROJECT_VERSION",
331
- ];
332
- // Add default environment variables if they exist in process.env
333
- defaultEnvVars.forEach((envVar) => {
334
- if (process.env[envVar] && !environment[envVar]) {
335
- environment[envVar] = process.env[envVar];
336
- }
337
- });
462
+ // Get base environment with defaults
463
+ const environment = jaypieLambdaEnv({ initialEnvironment });
338
464
  const codeAsset = typeof code === "string" ? lambda.Code.fromAsset(code) : code;
339
465
  // Create a working copy of layers
340
466
  const resolvedLayers = [...layers];
341
- // Determine if we should add Datadog integration
342
- // Check for datadog API key ARN in different sources
343
- const resolvedDatadogApiKeyArn = datadogApiKeyArn ||
344
- process.env.DATADOG_API_KEY_ARN ||
345
- process.env.CDK_ENV_DATADOG_API_KEY_ARN;
346
- // Add Datadog integration if API key is available
347
- if (resolvedDatadogApiKeyArn) {
348
- // Add Datadog Node.js layer
349
- const datadogNodeLayer = lambda.LayerVersion.fromLayerVersionArn(this, "DatadogNodeLayer", `arn:aws:lambda:${Stack.of(this).region}:464622532012:layer:Datadog-Node20-x:${CDK$2.DATADOG.LAYER.NODE}`);
350
- resolvedLayers.push(datadogNodeLayer);
351
- // Add Datadog Extension layer
352
- const datadogExtensionLayer = lambda.LayerVersion.fromLayerVersionArn(this, "DatadogExtensionLayer", `arn:aws:lambda:${Stack.of(this).region}:464622532012:layer:Datadog-Extension:${CDK$2.DATADOG.LAYER.EXTENSION}`);
353
- resolvedLayers.push(datadogExtensionLayer);
354
- // Set Datadog environment variables
355
- Object.assign(environment, {
356
- DD_API_KEY_SECRET_ARN: resolvedDatadogApiKeyArn,
357
- DD_ENHANCED_METRICS: "true",
358
- DD_ENV: process.env.PROJECT_ENV || "",
359
- DD_PROFILING_ENABLED: "false",
360
- DD_SERVERLESS_APPSEC_ENABLED: "false",
361
- DD_SERVICE: process.env.PROJECT_SERVICE || "",
362
- DD_SITE: CDK$2.DATADOG.SITE,
363
- DD_TAGS: `${CDK$2.TAG.SPONSOR}:${process.env.PROJECT_SPONSOR || ""}`,
364
- DD_TRACE_OTEL_ENABLED: "false",
365
- });
366
- }
367
- // Configure ParamsAndSecrets layer
368
- let resolvedParamsAndSecrets = undefined;
369
- if (paramsAndSecrets !== false) {
370
- if (paramsAndSecrets instanceof lambda.ParamsAndSecretsLayerVersion) {
371
- resolvedParamsAndSecrets = paramsAndSecrets;
372
- }
373
- else {
374
- // Create default ParamsAndSecrets layer
375
- resolvedParamsAndSecrets =
376
- lambda.ParamsAndSecretsLayerVersion.fromVersion(lambda.ParamsAndSecretsVersions.V1_0_103, {
377
- cacheSize: paramsAndSecretsOptions?.cacheSize,
378
- logLevel: paramsAndSecretsOptions?.logLevel ||
379
- lambda.ParamsAndSecretsLogLevel.WARN,
380
- parameterStoreTtl: paramsAndSecretsOptions?.parameterStoreTtl
381
- ? Duration.seconds(paramsAndSecretsOptions.parameterStoreTtl)
382
- : undefined,
383
- secretsManagerTtl: paramsAndSecretsOptions?.secretsManagerTtl
384
- ? Duration.seconds(paramsAndSecretsOptions.secretsManagerTtl)
385
- : undefined,
386
- });
387
- }
388
- }
389
467
  // Process secrets environment variables
390
468
  const secretsEnvironment = Object.entries(envSecrets).reduce((acc, [key, secret]) => ({
391
469
  ...acc,
@@ -428,7 +506,6 @@ class JaypieLambda extends Construct {
428
506
  logRetentionRetryOptions,
429
507
  maxEventAge,
430
508
  memorySize,
431
- paramsAndSecrets: resolvedParamsAndSecrets,
432
509
  profiling,
433
510
  profilingGroup,
434
511
  reservedConcurrentExecutions,
@@ -449,6 +526,13 @@ class JaypieLambda extends Construct {
449
526
  }
450
527
  : undefined,
451
528
  });
529
+ // Add ParamsAndSecrets layer if configured
530
+ addParamsAndSecrets(this._lambda, {
531
+ paramsAndSecrets,
532
+ paramsAndSecretsOptions,
533
+ });
534
+ // Add Datadog layers and environment variables if configured
535
+ addDatadogLayer(this._lambda, { datadogApiKeyArn });
452
536
  // Grant secret read permissions
453
537
  Object.values(envSecrets).forEach((secret) => {
454
538
  secret.grantRead(this._lambda);
@@ -457,11 +541,6 @@ class JaypieLambda extends Construct {
457
541
  secrets.forEach((secret) => {
458
542
  secret.grantRead(this._lambda);
459
543
  });
460
- // Grant Datadog API key read permission if applicable
461
- if (resolvedDatadogApiKeyArn) {
462
- const datadogApiKey = secretsmanager.Secret.fromSecretCompleteArn(this, "DatadogApiKeyGrant", resolvedDatadogApiKeyArn);
463
- datadogApiKey.grantRead(this._lambda);
464
- }
465
544
  // Configure provisioned concurrency if specified
466
545
  if (provisionedConcurrentExecutions !== undefined) {
467
546
  // Use currentVersion which is auto-published with proper configuration
@@ -1702,6 +1781,9 @@ class JaypieWebDeploymentBucket extends Construct {
1702
1781
  grantWrite(identity, objectsKeyPattern) {
1703
1782
  return this.bucket.grantWrite(identity, objectsKeyPattern);
1704
1783
  }
1784
+ grantReplicationPermission(identity, props) {
1785
+ return this.bucket.grantReplicationPermission(identity, props);
1786
+ }
1705
1787
  s3UrlForObject(key) {
1706
1788
  return this.bucket.s3UrlForObject(key);
1707
1789
  }
@@ -1752,5 +1834,5 @@ class JaypieWebDeploymentBucket extends Construct {
1752
1834
  }
1753
1835
  }
1754
1836
 
1755
- export { JaypieApiGateway, JaypieAppStack, JaypieBucketQueuedLambda, JaypieDatadogSecret, JaypieEnvSecret, JaypieExpressLambda, JaypieHostedZone, JaypieInfrastructureStack, JaypieLambda, JaypieMongoDbSecret, JaypieOpenAiSecret, JaypieQueuedLambda, JaypieSsoGroups, JaypieStack, JaypieTraceSigningKeySecret, JaypieWebDeploymentBucket, PermissionSetType, constructEnvName, constructStackName, isEnv, isProductionEnv, isSandboxEnv, stackTagger };
1837
+ export { JaypieApiGateway, JaypieAppStack, JaypieBucketQueuedLambda, JaypieDatadogSecret, JaypieEnvSecret, JaypieExpressLambda, JaypieHostedZone, JaypieInfrastructureStack, JaypieLambda, JaypieMongoDbSecret, JaypieOpenAiSecret, JaypieQueuedLambda, JaypieSsoGroups, JaypieStack, JaypieTraceSigningKeySecret, JaypieWebDeploymentBucket, PermissionSetType, addDatadogLayer, addParamsAndSecrets, constructEnvName, constructStackName, constructTagger, envHostname, isEnv, isProductionEnv, isSandboxEnv, jaypieLambdaEnv, resolveHostedZone };
1756
1838
  //# sourceMappingURL=index.js.map