@digitraffic/common 2026.9.4-1 → 2026.9.4-2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (30) hide show
  1. package/dist/__test__/imports.test.js +82 -304
  2. package/dist/__test__/infra/acl-builder.test.js +18 -0
  3. package/dist/__test__/infra/stack/dt-function.test.d.ts +1 -0
  4. package/dist/__test__/infra/stack/dt-function.test.js +70 -0
  5. package/dist/__test__/infra/stack/stack.test.d.ts +1 -0
  6. package/dist/__test__/infra/stack/stack.test.js +33 -0
  7. package/dist/__test__/stack/dt-function.test.js +3 -121
  8. package/dist/__test__/utils/lead-time-logging.test.d.ts +1 -0
  9. package/dist/__test__/utils/lead-time-logging.test.js +153 -0
  10. package/dist/aws/infra/acl-builder.d.ts +21 -2
  11. package/dist/aws/infra/acl-builder.js +54 -6
  12. package/dist/aws/infra/canaries/database-checker.js +2 -3
  13. package/dist/aws/infra/stack/dt-function.d.ts +19 -12
  14. package/dist/aws/infra/stack/dt-function.js +31 -48
  15. package/dist/aws/infra/stack/stack-checking-aspect.js +1 -2
  16. package/dist/aws/infra/stack/stack.d.ts +2 -0
  17. package/dist/aws/infra/stack/stack.js +9 -8
  18. package/dist/aws/runtime/dt-logger.d.ts +1 -0
  19. package/dist/aws/runtime/dt-logger.js +5 -0
  20. package/dist/aws/runtime/environment.d.ts +1 -0
  21. package/dist/aws/runtime/environment.js +1 -0
  22. package/dist/aws/runtime/secrets/proxy-holder.d.ts +6 -1
  23. package/dist/aws/runtime/secrets/proxy-holder.js +6 -4
  24. package/dist/aws/runtime/secrets/rds-holder.d.ts +4 -1
  25. package/dist/aws/runtime/secrets/rds-holder.js +6 -4
  26. package/dist/database/database.d.ts +1 -1
  27. package/dist/database/database.js +1 -1
  28. package/dist/utils/lead-time-logging.d.ts +10 -0
  29. package/dist/utils/lead-time-logging.js +33 -0
  30. package/package.json +1 -1
@@ -61,6 +61,7 @@ describe("FunctionBuilder test", () => {
61
61
  template.hasResourceProperties("AWS::Lambda::Function", {
62
62
  Environment: {
63
63
  Variables: {
64
+ [EnvKeys.APP_NAME]: "road-test",
64
65
  [EnvKeys.SECRET_ID]: "testSecret",
65
66
  [TEST_ENV_VAR]: TEST_ENV_VALUE,
66
67
  },
@@ -139,11 +140,9 @@ describe("FunctionBuilder test", () => {
139
140
  });
140
141
  });
141
142
  test("Lambda handler module is resolved from path last element", () => {
142
- const template = createTemplate((_builder) => { }, false, "api/charging-network/v1/operators");
143
- // const lambdas = template.findResources("AWS::Lambda::Function");
144
- // console.debug(JSON.stringify(lambdas, null, 2));
143
+ const template = createTemplate((_builder) => { }, false, "api/feature/v1/get-items");
145
144
  template.hasResourceProperties("AWS::Lambda::Function", {
146
- Handler: "operators.handler",
145
+ Handler: "get-items.handler",
147
146
  });
148
147
  });
149
148
  test("Lambda handler module is same as lambda name", () => {
@@ -336,122 +335,5 @@ describe("FunctionBuilder test", () => {
336
335
  .build();
337
336
  }).toThrow('Lambda test-Test cannot use wildcard action "*" in withAllowedActions');
338
337
  });
339
- describe("withAdotTracing", () => {
340
- test("given withAdotTracing is called / when lambda is built / then AWS_LAMBDA_EXEC_WRAPPER is set", () => {
341
- // given/when
342
- const template = createTemplate((builder) => {
343
- builder.withAdotTracing();
344
- });
345
- // then
346
- expectEnvironmentValue(template, "AWS_LAMBDA_EXEC_WRAPPER", "/opt/otel-instrument");
347
- });
348
- test("given withAdotTracing is called / when lambda is built / then OTEL_AWS_APPLICATION_SIGNALS_ENABLED is false", () => {
349
- // given/when
350
- const template = createTemplate((builder) => {
351
- builder.withAdotTracing();
352
- });
353
- // then
354
- expectEnvironmentValue(template, "OTEL_AWS_APPLICATION_SIGNALS_ENABLED", "false");
355
- });
356
- test("given withAdotTracing is called / when lambda is built / then X-Ray active tracing is enabled", () => {
357
- // given/when
358
- const template = createTemplate((builder) => {
359
- builder.withAdotTracing();
360
- });
361
- // then
362
- template.hasResourceProperties("AWS::Lambda::Function", {
363
- TracingConfig: { Mode: "Active" },
364
- });
365
- });
366
- test("given withAdotTracing is called / when lambda is built / then CloudWatch Lambda Application Signals policy is attached", () => {
367
- // given/when
368
- const template = createTemplate((builder) => {
369
- builder.withAdotTracing();
370
- });
371
- // then — the managed policy ARN contains CloudWatchLambdaApplicationSignalsExecutionRolePolicy
372
- const roles = template.findResources("AWS::IAM::Role");
373
- const lambdaRoleKey = Object.keys(roles).find((key) => key.includes("ServiceRole"));
374
- expect(lambdaRoleKey).toBeDefined();
375
- const role = roles[lambdaRoleKey];
376
- const managedPolicyArns = JSON.stringify(role["Properties"]?.["ManagedPolicyArns"]);
377
- expect(managedPolicyArns).toContain("CloudWatchLambdaApplicationSignalsExecutionRolePolicy");
378
- });
379
- test("given withAdotTracing on Node.js runtime / when lambda is built / then JS ADOT layer is attached", () => {
380
- // given/when — default runtime is NODEJS_24_X
381
- const template = createTemplate((builder) => {
382
- builder.withAdotTracing();
383
- });
384
- // then
385
- template.hasResourceProperties("AWS::Lambda::Function", {
386
- Layers: Match.arrayWith([
387
- Match.stringLikeRegexp("AWSOpenTelemetryDistroJs"),
388
- ]),
389
- });
390
- });
391
- test("given withAdotTracing on Python runtime / when lambda is built / then Python ADOT layer is attached", () => {
392
- // given/when
393
- const template = createTemplate((builder) => {
394
- builder.withRuntime(Runtime.PYTHON_3_12).withAdotTracing();
395
- });
396
- // then
397
- template.hasResourceProperties("AWS::Lambda::Function", {
398
- Layers: Match.arrayWith([
399
- Match.stringLikeRegexp("AWSOpenTelemetryDistroPython"),
400
- ]),
401
- });
402
- });
403
- test("given withAdotTracing is NOT called / when lambda is built / then ADOT env vars are absent", () => {
404
- // given/when
405
- const template = createTemplate((_builder) => { });
406
- // then
407
- expectEnvironmentValueMissing(template, "AWS_LAMBDA_EXEC_WRAPPER");
408
- expectEnvironmentValueMissing(template, "OTEL_AWS_APPLICATION_SIGNALS_ENABLED");
409
- });
410
- test("given withAdotTracing is NOT called / when lambda is built / then tracing is not Active", () => {
411
- // given/when
412
- const template = createTemplate((_builder) => { });
413
- // then
414
- template.hasResourceProperties("AWS::Lambda::Function", {
415
- TracingConfig: Match.absent(),
416
- });
417
- });
418
- test("given withAdotTracing combined with other builder methods / when lambda is built / then all properties are present", () => {
419
- // given/when
420
- const template = createTemplate((builder) => {
421
- builder
422
- .withAdotTracing()
423
- .withMemorySize(512)
424
- .withTimeout(Duration.seconds(30))
425
- .withEnvironment({ CUSTOM_KEY: "custom_value" });
426
- });
427
- // then — ADOT config present
428
- expectEnvironmentValue(template, "AWS_LAMBDA_EXEC_WRAPPER", "/opt/otel-instrument");
429
- template.hasResourceProperties("AWS::Lambda::Function", {
430
- TracingConfig: { Mode: "Active" },
431
- });
432
- // then — other builder settings also present
433
- template.hasResourceProperties("AWS::Lambda::Function", {
434
- MemorySize: 512,
435
- Timeout: 30,
436
- });
437
- expectEnvironmentValue(template, "CUSTOM_KEY", "custom_value");
438
- });
439
- test("given withAdotTracing on plain builder / when lambda is built / then ADOT config is applied without database env vars", () => {
440
- // given/when
441
- const template = createTemplate((builder) => {
442
- builder.withAdotTracing();
443
- }, true);
444
- // then — ADOT config present
445
- expectEnvironmentValue(template, "AWS_LAMBDA_EXEC_WRAPPER", "/opt/otel-instrument");
446
- template.hasResourceProperties("AWS::Lambda::Function", {
447
- TracingConfig: { Mode: "Active" },
448
- Layers: Match.arrayWith([
449
- Match.stringLikeRegexp("AWSOpenTelemetryDistroJs"),
450
- ]),
451
- });
452
- // then — no database env vars
453
- expectEnvironmentValueMissing(template, "DB_APPLICATION");
454
- });
455
- });
456
338
  });
457
339
  //# sourceMappingURL=dt-function.test.js.map
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,153 @@
1
+ import { afterEach, describe, expect, test, vi } from "vitest";
2
+ import { logger } from "../../aws/runtime/dt-logger-default.js";
3
+ import { logLeadTime, logLeadTimes } from "../../utils/lead-time-logging.js";
4
+ describe("lead-time-logging", () => {
5
+ afterEach(() => {
6
+ vi.restoreAllMocks();
7
+ });
8
+ test("logLeadTime logs expected payload", () => {
9
+ const infoSpy = vi
10
+ .spyOn(logger, "info")
11
+ .mockImplementation(() => undefined);
12
+ const errorSpy = vi
13
+ .spyOn(logger, "error")
14
+ .mockImplementation(() => undefined);
15
+ logLeadTime("lead-time", "test-target", 123);
16
+ expect(infoSpy).toHaveBeenCalledTimes(1);
17
+ expect(infoSpy).toHaveBeenCalledWith({
18
+ method: "LeadTimeLogging.logLeadTime",
19
+ customLeadTime: true,
20
+ customName: "lead-time",
21
+ customTarget: "test-target",
22
+ tookMs: 123,
23
+ });
24
+ expect(errorSpy).toHaveBeenCalledTimes(0);
25
+ });
26
+ test("logLeadTime merges extra fields", () => {
27
+ const infoSpy = vi
28
+ .spyOn(logger, "info")
29
+ .mockImplementation(() => undefined);
30
+ logLeadTime("mqtt-time", "mqtt", 88, {
31
+ customSource: "mqtt",
32
+ customRetriesCount: 2,
33
+ });
34
+ expect(infoSpy).toHaveBeenCalledTimes(1);
35
+ expect(infoSpy).toHaveBeenCalledWith({
36
+ method: "LeadTimeLogging.logLeadTime",
37
+ customLeadTime: true,
38
+ customName: "mqtt-time",
39
+ customTarget: "mqtt",
40
+ tookMs: 88,
41
+ customSource: "mqtt",
42
+ customRetriesCount: 2,
43
+ });
44
+ });
45
+ test("logLeadTime logs error if logger.info throws", () => {
46
+ const infoError = new Error("boom");
47
+ vi.spyOn(logger, "info").mockImplementation(() => {
48
+ throw infoError;
49
+ });
50
+ const errorSpy = vi
51
+ .spyOn(logger, "error")
52
+ .mockImplementation(() => undefined);
53
+ logLeadTime("process-time", "target", 10);
54
+ expect(errorSpy).toHaveBeenCalledTimes(1);
55
+ expect(errorSpy).toHaveBeenCalledWith({
56
+ method: "LeadTimeLogging.logLeadTime",
57
+ message: "Error logging lead time",
58
+ error: infoError,
59
+ });
60
+ });
61
+ test("logLeadTimes logs only lead-time when only leadTimeMs is safe", () => {
62
+ const infoSpy = vi
63
+ .spyOn(logger, "info")
64
+ .mockImplementation(() => undefined);
65
+ logLeadTimes({ target: "x", leadTimeMs: 10 });
66
+ expect(infoSpy).toHaveBeenCalledTimes(1);
67
+ expect(infoSpy).toHaveBeenNthCalledWith(1, {
68
+ method: "LeadTimeLogging.logLeadTime",
69
+ customLeadTime: true,
70
+ customName: "lead-time",
71
+ customTarget: "x",
72
+ tookMs: 10,
73
+ });
74
+ });
75
+ test("logLeadTimes logs only process-time when only processTimeMs is safe", () => {
76
+ const infoSpy = vi
77
+ .spyOn(logger, "info")
78
+ .mockImplementation(() => undefined);
79
+ logLeadTimes({ target: "x", processTimeMs: 20 });
80
+ expect(infoSpy).toHaveBeenCalledTimes(1);
81
+ expect(infoSpy).toHaveBeenNthCalledWith(1, {
82
+ method: "LeadTimeLogging.logLeadTime",
83
+ customLeadTime: true,
84
+ customName: "process-time",
85
+ customTarget: "x",
86
+ tookMs: 20,
87
+ });
88
+ });
89
+ test("logLeadTimes logs both in order with extra fields", () => {
90
+ const infoSpy = vi
91
+ .spyOn(logger, "info")
92
+ .mockImplementation(() => undefined);
93
+ const input = {
94
+ target: "device",
95
+ leadTimeMs: 11,
96
+ processTimeMs: 22,
97
+ extraFields: { customSource: "mqtt", customPartition: 3 },
98
+ };
99
+ logLeadTimes(input);
100
+ expect(infoSpy).toHaveBeenCalledTimes(2);
101
+ expect(infoSpy).toHaveBeenNthCalledWith(1, {
102
+ method: "LeadTimeLogging.logLeadTime",
103
+ customLeadTime: true,
104
+ customName: "lead-time",
105
+ customTarget: "device",
106
+ tookMs: 11,
107
+ customSource: "mqtt",
108
+ customPartition: 3,
109
+ });
110
+ expect(infoSpy).toHaveBeenNthCalledWith(2, {
111
+ method: "LeadTimeLogging.logLeadTime",
112
+ customLeadTime: true,
113
+ customName: "process-time",
114
+ customTarget: "device",
115
+ tookMs: 22,
116
+ customSource: "mqtt",
117
+ customPartition: 3,
118
+ });
119
+ });
120
+ test("logLeadTimes ignores non-safe values", () => {
121
+ const infoSpy = vi
122
+ .spyOn(logger, "info")
123
+ .mockImplementation(() => undefined);
124
+ logLeadTimes({
125
+ target: "x",
126
+ leadTimeMs: 1.5,
127
+ processTimeMs: Number.MAX_SAFE_INTEGER + 1,
128
+ });
129
+ logLeadTimes({
130
+ target: "x",
131
+ leadTimeMs: Number.NaN,
132
+ processTimeMs: Infinity,
133
+ });
134
+ logLeadTimes({ target: "x" });
135
+ expect(infoSpy).toHaveBeenCalledTimes(0);
136
+ });
137
+ test("logLeadTimes logs negative safe integer values", () => {
138
+ const infoSpy = vi
139
+ .spyOn(logger, "info")
140
+ .mockImplementation(() => undefined);
141
+ logLeadTimes({ target: "x", leadTimeMs: -5 });
142
+ expect(infoSpy).toHaveBeenCalledTimes(1);
143
+ expect(infoSpy).toHaveBeenNthCalledWith(1, {
144
+ method: "LeadTimeLogging.logLeadTime",
145
+ customLeadTime: true,
146
+ customName: "lead-time",
147
+ customTarget: "x",
148
+ tookMs: -5,
149
+ });
150
+ });
151
+ });
152
+ // clean comment
153
+ //# sourceMappingURL=lead-time-logging.test.js.map
@@ -32,13 +32,32 @@ export declare class AclBuilder {
32
32
  * Allow access only from the given addresses
33
33
  */
34
34
  withIpWhitelistRule(addresses: string[]): this;
35
- withThrottleRule(name: string, limit: number, isHeaderRequired: boolean, isBasedOnIpAndUriPath: boolean, customResponseBodyKey?: string, path?: RegExp): this;
35
+ /**
36
+ * Adds a rate-based WAF rule for either blocking or counting requests.
37
+ *
38
+ * @param name WAF rule name and CloudWatch metric name.
39
+ * @param limit Maximum requests allowed in the WAF evaluation window.
40
+ * @param isHeaderRequired Whether the rule applies when the digitraffic-user header is present.
41
+ * @param isBasedOnIpAndUriPath Whether requests are aggregated by IP address and URI path.
42
+ * @param customResponseBodyKey Custom response body key; when provided, matching requests are blocked instead of counted.
43
+ * @param path Optional URI path pattern that limits which requests are included.
44
+ * @param excludedPath Optional URI path pattern that excludes matching requests from the rule.
45
+ */
46
+ withThrottleRule(name: string, limit: number, isHeaderRequired: boolean, isBasedOnIpAndUriPath: boolean, customResponseBodyKey?: string, path?: RegExp, excludedPath?: RegExp): this;
36
47
  withCustomResponseBody(key: string, customResponseBody: CfnWebACL.CustomResponseBodyProperty): this;
37
48
  withThrottleDigitrafficUserIp(limit: number | undefined): this;
38
49
  withThrottleDigitrafficUserIpAndUriPath(limit: number | undefined): this;
39
50
  withThrottleAnonymousUserIp(limit: number | undefined): AclBuilder;
40
51
  withThrottleAnonymousUserIpByUriPath(limit: number | undefined, path: RegExp | undefined): AclBuilder;
41
- withThrottleAnonymousUserIpAndUriPath(limit: number | undefined): this;
52
+ /**
53
+ * Throttles anonymous requests by IP address and URI path.
54
+ *
55
+ * Existing callers that omit `excludedPath` retain the previous behavior.
56
+ *
57
+ * @param limit Maximum requests allowed for each IP and URI path combination.
58
+ * @param excludedPath Optional URI path pattern excluded from this throttle rule.
59
+ */
60
+ withThrottleAnonymousUserIpAndUriPath(limit: number | undefined, excludedPath?: RegExp): this;
42
61
  withCountDigitrafficUserIp(limit: number | undefined): this;
43
62
  withCountDigitrafficUserIpAndUriPath(limit: number | undefined): this;
44
63
  withCountAnonymousUserIp(limit: number | undefined): this;
@@ -91,7 +91,18 @@ export class AclBuilder {
91
91
  });
92
92
  return this;
93
93
  }
94
- withThrottleRule(name, limit, isHeaderRequired, isBasedOnIpAndUriPath, customResponseBodyKey, path) {
94
+ /**
95
+ * Adds a rate-based WAF rule for either blocking or counting requests.
96
+ *
97
+ * @param name WAF rule name and CloudWatch metric name.
98
+ * @param limit Maximum requests allowed in the WAF evaluation window.
99
+ * @param isHeaderRequired Whether the rule applies when the digitraffic-user header is present.
100
+ * @param isBasedOnIpAndUriPath Whether requests are aggregated by IP address and URI path.
101
+ * @param customResponseBodyKey Custom response body key; when provided, matching requests are blocked instead of counted.
102
+ * @param path Optional URI path pattern that limits which requests are included.
103
+ * @param excludedPath Optional URI path pattern that excludes matching requests from the rule.
104
+ */
105
+ withThrottleRule(name, limit, isHeaderRequired, isBasedOnIpAndUriPath, customResponseBodyKey, path, excludedPath) {
95
106
  const isBlockRule = !!customResponseBodyKey;
96
107
  const rules = isBlockRule ? this._blockRules : this._countRules;
97
108
  const action = isBlockRule
@@ -114,7 +125,7 @@ export class AclBuilder {
114
125
  metricName: name,
115
126
  },
116
127
  action,
117
- statement: createThrottleStatement(limit, isHeaderRequired, isBasedOnIpAndUriPath, path),
128
+ statement: createThrottleStatement(limit, isHeaderRequired, isBasedOnIpAndUriPath, path, excludedPath),
118
129
  });
119
130
  return this;
120
131
  }
@@ -160,13 +171,21 @@ export class AclBuilder {
160
171
  this._addThrottleResponseBody(customResponseBodyKey, limit);
161
172
  return this.withThrottleRule("ThrottleRuleWithAnonymousUserByPath", limit, false, false, customResponseBodyKey, path);
162
173
  }
163
- withThrottleAnonymousUserIpAndUriPath(limit) {
174
+ /**
175
+ * Throttles anonymous requests by IP address and URI path.
176
+ *
177
+ * Existing callers that omit `excludedPath` retain the previous behavior.
178
+ *
179
+ * @param limit Maximum requests allowed for each IP and URI path combination.
180
+ * @param excludedPath Optional URI path pattern excluded from this throttle rule.
181
+ */
182
+ withThrottleAnonymousUserIpAndUriPath(limit, excludedPath) {
164
183
  if (limit === undefined) {
165
184
  return this;
166
185
  }
167
186
  const customResponseBodyKey = `IP_PATH_THROTTLE_ANONYMOUS_USER_${limit}`;
168
187
  this._addThrottleResponseBody(customResponseBodyKey, limit);
169
- return this.withThrottleRule("ThrottleRuleIPQueryWithAnonymousUser", limit, false, true, customResponseBodyKey);
188
+ return this.withThrottleRule("ThrottleRuleIPQueryWithAnonymousUser", limit, false, true, customResponseBodyKey, undefined, excludedPath);
170
189
  }
171
190
  withCountDigitrafficUserIp(limit) {
172
191
  if (limit === undefined) {
@@ -289,8 +308,18 @@ function notStatement(statement) {
289
308
  },
290
309
  };
291
310
  }
292
- function createThrottleStatement(limit, isHeaderRequired, isBasedOnIpAndUriPath, path) {
293
- // this statement matches empty digitraffic-user -header
311
+ /**
312
+ * Creates the scope-down and rate-based statement used by a throttle rule.
313
+ *
314
+ * @param limit Maximum requests allowed in the WAF evaluation window.
315
+ * @param isHeaderRequired Whether the statement matches requests with the digitraffic-user header.
316
+ * @param isBasedOnIpAndUriPath Whether requests are aggregated by IP address and URI path.
317
+ * @param path Optional URI path pattern that limits which requests are included.
318
+ * @param excludedPath Optional URI path pattern that is explicitly excluded from the statement.
319
+ */
320
+ function createThrottleStatement(limit, isHeaderRequired, isBasedOnIpAndUriPath, path, excludedPath) {
321
+ // Matches requests with a non-empty digitraffic-user header. For anonymous
322
+ // requests, the inverted statement matches requests without the header.
294
323
  const matchStatement = {
295
324
  sizeConstraintStatement: {
296
325
  comparisonOperator: isHeaderRequired ? "GT" : "GE",
@@ -324,6 +353,25 @@ function createThrottleStatement(limit, isHeaderRequired, isBasedOnIpAndUriPath,
324
353
  },
325
354
  };
326
355
  }
356
+ if (excludedPath) {
357
+ const excludedPathMatchStatement = {
358
+ regexMatchStatement: {
359
+ fieldToMatch: {
360
+ uriPath: {},
361
+ },
362
+ regexString: excludedPath.source,
363
+ textTransformations: [{ priority: 0, type: "NONE" }],
364
+ },
365
+ };
366
+ scopeDownStatement = {
367
+ andStatement: {
368
+ statements: [
369
+ scopeDownStatement,
370
+ notStatement(excludedPathMatchStatement),
371
+ ],
372
+ },
373
+ };
374
+ }
327
375
  if (isBasedOnIpAndUriPath) {
328
376
  return {
329
377
  rateBasedStatement: {
@@ -1,6 +1,5 @@
1
1
  import synthetics from "Synthetics";
2
2
  import { inDatabaseReadonly } from "../../../database/database.js";
3
- import { getEnvVariable } from "../../../utils/utils.js";
4
3
  import { logger } from "../../runtime/dt-logger-default.js";
5
4
  import { ProxyHolder } from "../../runtime/secrets/proxy-holder.js";
6
5
  import { RdsHolder } from "../../runtime/secrets/rds-holder.js";
@@ -66,10 +65,10 @@ export class DatabaseCountChecker {
66
65
  synthetics.getConfiguration().withFailedCanaryMetric(true);
67
66
  }
68
67
  static createForProxy() {
69
- return new DatabaseCountChecker(() => new ProxyHolder(getEnvVariable("SECRET_ID")).setCredentials());
68
+ return new DatabaseCountChecker(() => ProxyHolder.create().setCredentials());
70
69
  }
71
70
  static createForRds() {
72
- return new DatabaseCountChecker(() => new RdsHolder(getEnvVariable("SECRET_ID")).setCredentials());
71
+ return new DatabaseCountChecker(() => RdsHolder.create().setCredentials());
73
72
  }
74
73
  /**
75
74
  * Expect that the count is 1
@@ -1,4 +1,4 @@
1
- import type { Stack } from "aws-cdk-lib";
1
+ import type { Size, Stack } from "aws-cdk-lib";
2
2
  import { Duration } from "aws-cdk-lib";
3
3
  import type { ISecurityGroup } from "aws-cdk-lib/aws-ec2";
4
4
  import type { IRole } from "aws-cdk-lib/aws-iam";
@@ -21,6 +21,7 @@ export declare class FunctionBuilder {
21
21
  private functionName;
22
22
  private environment;
23
23
  private vpc?;
24
+ private storageSize?;
24
25
  private alarms;
25
26
  private code;
26
27
  private handler;
@@ -28,7 +29,6 @@ export declare class FunctionBuilder {
28
29
  private readonly securityGroups;
29
30
  private readonly policyStatements;
30
31
  private readonly allowedActions;
31
- private _adotTracing;
32
32
  private readonly _features;
33
33
  constructor(stack: Stack & DigitrafficStackInterface, lambdaName: string);
34
34
  /**
@@ -41,9 +41,19 @@ export declare class FunctionBuilder {
41
41
  */
42
42
  static plain(stack: Stack & DigitrafficStackInterface, lambdaName: string): FunctionBuilder;
43
43
  /**
44
- * Use AssetCode from given path(dist/lambda/${path}). Default path is lambdaName. Also calls withHandler with the same value.
45
- */
46
- withAssetCode(path?: string): this;
44
+ * Sets the Lambda deployment package to the directory `dist/lambda/${path}` and configures
45
+ * the handler to `basename(path).handler`.
46
+ * @param path - subdirectory under `dist/lambda/` that contains the compiled Lambda code.
47
+ * The handler module name is derived from `basename(path)` (e.g. `"locations.handler"`).
48
+ * Defaults to `lambdaName`.
49
+ * Example: `"dump/locations"` → asset dir `dist/lambda/dump/locations/`, handler `locations.handler`.
50
+ * @param exclude - optional glob patterns to exclude from the asset bundle.
51
+ * Patterns are relative to the asset root (`dist/lambda/${path}/`) — do NOT use a leading slash.
52
+ * Use `**` to match files recursively.
53
+ * Example: `["datex2-36", "datex2-37", "statuses"]` excludes sibling lambda subdirectories
54
+ * that would otherwise be bundled into this lambda's deployment package.
55
+ */
56
+ withAssetCode(path?: string, exclude?: string[]): this;
47
57
  withCode(code: Code): this;
48
58
  /**
49
59
  * Use given handler(${name}.handler) to run the lambda. Default value is lambdaName.
@@ -74,15 +84,13 @@ export declare class FunctionBuilder {
74
84
  */
75
85
  withRuntime(runtime: Runtime): this;
76
86
  /**
77
- * Add Lambda layers.
87
+ * Set storage size for the lambda. Defaults to AWS default (512MB).
78
88
  */
79
- withLayers(...layers: ILayerVersion[]): this;
89
+ withStorageSize(storageSize: Size): this;
80
90
  /**
81
- * Enable ADOT (AWS Distro for OpenTelemetry) tracing for this Lambda.
82
- * Adds the ADOT Lambda layer, enables X-Ray active tracing,
83
- * sets required environment variables, and attaches IAM permissions.
91
+ * Add Lambda layers.
84
92
  */
85
- withAdotTracing(): this;
93
+ withLayers(...layers: ILayerVersion[]): this;
86
94
  /**
87
95
  * Set architecture for the lambda. Default is Architecture.ARM_64.
88
96
  */
@@ -121,7 +129,6 @@ export declare class FunctionBuilder {
121
129
  build(): AwsFunction;
122
130
  private attachPolicies;
123
131
  private validateNoWildcardActions;
124
- private getLayers;
125
132
  private getEnvironment;
126
133
  private createAlarms;
127
134
  private createAlarm;