@digitraffic/common 2023.1.18-2 → 2023.1.23-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 (58) hide show
  1. package/dist/aws/infra/api/integration.d.ts +2 -1
  2. package/dist/aws/infra/api/integration.js +3 -2
  3. package/dist/aws/infra/api/response.d.ts +2 -1
  4. package/dist/aws/infra/api/response.js +13 -7
  5. package/dist/aws/infra/canaries/canary-alarm.js +11 -13
  6. package/dist/aws/infra/canaries/canary.js +2 -4
  7. package/dist/aws/infra/canaries/database-checker.js +4 -1
  8. package/dist/aws/infra/canaries/url-canary.js +1 -0
  9. package/dist/aws/infra/canaries/url-checker.d.ts +2 -2
  10. package/dist/aws/infra/canaries/url-checker.js +24 -5
  11. package/dist/aws/infra/sqs-integration.d.ts +1 -3
  12. package/dist/aws/infra/sqs-integration.js +28 -32
  13. package/dist/aws/infra/sqs-queue.d.ts +0 -2
  14. package/dist/aws/infra/sqs-queue.js +31 -24
  15. package/dist/aws/infra/stack/lambda-configs.d.ts +2 -31
  16. package/dist/aws/infra/stack/lambda-configs.js +5 -38
  17. package/dist/aws/infra/stack/monitoredfunction.js +3 -1
  18. package/dist/aws/infra/stacks/db-stack.js +1 -1
  19. package/dist/aws/infra/stacks/network-stack.d.ts +2 -1
  20. package/dist/aws/infra/stacks/network-stack.js +4 -2
  21. package/dist/aws/runtime/digitraffic-integration-response.d.ts +2 -2
  22. package/dist/aws/runtime/digitraffic-integration-response.js +6 -4
  23. package/dist/aws/runtime/secrets/dbsecret.d.ts +0 -39
  24. package/dist/aws/runtime/secrets/dbsecret.js +1 -71
  25. package/dist/aws/runtime/secrets/proxy-holder.js +5 -4
  26. package/dist/aws/runtime/secrets/rds-holder.js +5 -4
  27. package/dist/aws/runtime/secrets/secret-holder.d.ts +0 -4
  28. package/dist/aws/runtime/secrets/secret-holder.js +6 -12
  29. package/dist/aws/runtime/secrets/secret.d.ts +0 -6
  30. package/dist/aws/runtime/secrets/secret.js +8 -17
  31. package/dist/database/database.d.ts +7 -0
  32. package/dist/database/database.js +19 -8
  33. package/dist/test/db-testutils.js +4 -5
  34. package/package.json +1 -1
  35. package/src/aws/infra/api/integration.ts +8 -3
  36. package/src/aws/infra/api/response.ts +16 -16
  37. package/src/aws/infra/canaries/canary-alarm.ts +26 -24
  38. package/src/aws/infra/canaries/canary.ts +2 -4
  39. package/src/aws/infra/canaries/database-checker.ts +4 -1
  40. package/src/aws/infra/canaries/url-canary.ts +2 -1
  41. package/src/aws/infra/canaries/url-checker.ts +28 -11
  42. package/src/aws/infra/sqs-integration.ts +51 -47
  43. package/src/aws/infra/sqs-queue.ts +85 -53
  44. package/src/aws/infra/stack/lambda-configs.ts +6 -69
  45. package/src/aws/infra/stack/monitoredfunction.ts +2 -1
  46. package/src/aws/infra/stacks/db-stack.ts +1 -1
  47. package/src/aws/infra/stacks/network-stack.ts +7 -3
  48. package/src/aws/runtime/digitraffic-integration-response.ts +16 -9
  49. package/src/aws/runtime/secrets/dbsecret.ts +1 -117
  50. package/src/aws/runtime/secrets/proxy-holder.ts +2 -5
  51. package/src/aws/runtime/secrets/rds-holder.ts +2 -1
  52. package/src/aws/runtime/secrets/secret-holder.ts +8 -20
  53. package/src/aws/runtime/secrets/secret.ts +17 -22
  54. package/src/database/database.ts +14 -3
  55. package/src/test/db-testutils.ts +5 -2
  56. package/dist/test/secret.d.ts +0 -3
  57. package/dist/test/secret.js +0 -25
  58. package/src/test/secret.ts +0 -23
@@ -10,7 +10,8 @@ export declare class DigitrafficIntegration {
10
10
  readonly lambda: IFunction;
11
11
  readonly mediaType: MediaType;
12
12
  readonly parameters: ApiParameter[];
13
- constructor(lambda: IFunction, mediaType?: MediaType);
13
+ readonly sunset?: string;
14
+ constructor(lambda: IFunction, mediaType?: MediaType, sunset?: string);
14
15
  addPathParameter(...names: string[]): this;
15
16
  addQueryParameter(...names: string[]): this;
16
17
  build(): LambdaIntegration;
@@ -5,10 +5,11 @@ const aws_apigateway_1 = require("aws-cdk-lib/aws-apigateway");
5
5
  const mediatypes_1 = require("../../types/mediatypes");
6
6
  const digitraffic_integration_response_1 = require("../../runtime/digitraffic-integration-response");
7
7
  class DigitrafficIntegration {
8
- constructor(lambda, mediaType = mediatypes_1.MediaType.TEXT_PLAIN) {
8
+ constructor(lambda, mediaType = mediatypes_1.MediaType.TEXT_PLAIN, sunset) {
9
9
  this.parameters = [];
10
10
  this.lambda = lambda;
11
11
  this.mediaType = mediaType;
12
+ this.sunset = sunset;
12
13
  }
13
14
  addPathParameter(...names) {
14
15
  names.forEach((name) => this.parameters.push({ type: "path", name }));
@@ -49,7 +50,7 @@ class DigitrafficIntegration {
49
50
  };
50
51
  }
51
52
  createResponses() {
52
- return [digitraffic_integration_response_1.DigitrafficIntegrationResponse.ok(this.mediaType)];
53
+ return [digitraffic_integration_response_1.DigitrafficIntegrationResponse.ok(this.mediaType, this.sunset)];
53
54
  }
54
55
  }
55
56
  exports.DigitrafficIntegration = DigitrafficIntegration;
@@ -12,6 +12,7 @@ import { IModel } from "aws-cdk-lib/aws-apigateway/lib/model";
12
12
  * If fileName is set, then Content-Disposition-header will be set to use it
13
13
  */
14
14
  export declare const RESPONSE_DEFAULT_LAMBDA = "#set($inputRoot = $input.path('$'))\n$util.base64Decode($inputRoot.body)\n#if ($inputRoot.status != 200)\n#set ($context.responseOverride.status = $inputRoot.status)\n#set ($context.responseOverride.header.Content-Type = 'text/plain')\n#end\n#set ($context.responseOverride.header.Access-Control-Allow-Origin = '*')\n#if (\"$!inputRoot.fileName\" != \"\")\n#set ($disposition = 'attachment; filename=\"FN\"')\n#set ($context.responseOverride.header.Content-Disposition = $disposition.replaceAll('FN', $inputRoot.fileName))\n#end\n";
15
+ export declare const getDeprecatedDefaultLambdaResponse: (sunset: string) => string;
15
16
  export declare const MessageModel: {
16
17
  contentType: MediaType;
17
18
  modelName: string;
@@ -24,7 +25,7 @@ export declare const XmlResponseTemplate: Record<string, string>;
24
25
  export declare const InternalServerErrorResponseTemplate: Record<string, string>;
25
26
  export declare function createResponses<T>(key: MediaType, value: T): Record<string, T>;
26
27
  export declare class DigitrafficMethodResponse {
27
- static response(statusCode: string, model: IModel, mediaType: MediaType, disableCors?: boolean): MethodResponse;
28
+ static response(statusCode: string, model: IModel, mediaType: MediaType, disableCors?: boolean, deprecation?: boolean): MethodResponse;
28
29
  static response200(model: IModel, mediaType?: MediaType): MethodResponse;
29
30
  static response500(model?: IModel, mediaType?: MediaType): MethodResponse;
30
31
  static response400(model?: IModel, mediaType?: MediaType): MethodResponse;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.DigitrafficMethodResponse = exports.createResponses = exports.InternalServerErrorResponseTemplate = exports.XmlResponseTemplate = exports.NotFoundResponseTemplate = exports.BadRequestResponseTemplate = exports.NotFoundResponse = exports.MessageModel = exports.RESPONSE_DEFAULT_LAMBDA = void 0;
3
+ exports.DigitrafficMethodResponse = exports.createResponses = exports.InternalServerErrorResponseTemplate = exports.XmlResponseTemplate = exports.NotFoundResponseTemplate = exports.BadRequestResponseTemplate = exports.NotFoundResponse = exports.MessageModel = exports.getDeprecatedDefaultLambdaResponse = exports.RESPONSE_DEFAULT_LAMBDA = void 0;
4
4
  const mediatypes_1 = require("../../types/mediatypes");
5
5
  const aws_apigateway_1 = require("aws-cdk-lib/aws-apigateway");
6
6
  /**
@@ -25,6 +25,12 @@ $util.base64Decode($inputRoot.body)
25
25
  #set ($context.responseOverride.header.Content-Disposition = $disposition.replaceAll('FN', $inputRoot.fileName))
26
26
  #end
27
27
  `;
28
+ const getDeprecatedDefaultLambdaResponse = (sunset) => {
29
+ const setDeprecationHeaders = `#set ($context.responseOverride.header.Deprecation = 'true')
30
+ #set ($context.responseOverride.header.Sunset = '${sunset}')`;
31
+ return exports.RESPONSE_DEFAULT_LAMBDA.concat(setDeprecationHeaders);
32
+ };
33
+ exports.getDeprecatedDefaultLambdaResponse = getDeprecatedDefaultLambdaResponse;
28
34
  const BODY_FROM_INPUT_PATH = "$input.path('$').body";
29
35
  /// @deprecated
30
36
  const messageSchema = {
@@ -68,17 +74,17 @@ function createResponses(key, value) {
68
74
  }
69
75
  exports.createResponses = createResponses;
70
76
  class DigitrafficMethodResponse {
71
- static response(statusCode, model, mediaType, disableCors = false) {
77
+ static response(statusCode, model, mediaType, disableCors = false, deprecation = false) {
72
78
  return {
73
79
  statusCode,
74
80
  responseModels: {
75
81
  [mediaType]: model,
76
82
  },
77
- responseParameters: disableCors
78
- ? {}
79
- : {
80
- "method.response.header.Access-Control-Allow-Origin": true,
81
- },
83
+ responseParameters: {
84
+ "method.response.header.Access-Control-Allow-Origin": !disableCors,
85
+ "method.response.header.Deprecation": deprecation,
86
+ "method.response.header.Sunset": deprecation,
87
+ },
82
88
  };
83
89
  }
84
90
  static response200(model, mediaType = mediatypes_1.MediaType.APPLICATION_JSON) {
@@ -6,19 +6,17 @@ const aws_cloudwatch_actions_1 = require("aws-cdk-lib/aws-cloudwatch-actions");
6
6
  const aws_sns_1 = require("aws-cdk-lib/aws-sns");
7
7
  class CanaryAlarm {
8
8
  constructor(stack, canary, params) {
9
- if (params.alarm ?? true) {
10
- const alarmName = params.alarm?.alarmName ?? `${params.name}-alarm`;
11
- const alarm = new aws_cloudwatch_1.Alarm(stack, alarmName, {
12
- alarmName,
13
- alarmDescription: params.alarm?.description ?? '',
14
- metric: canary.metricSuccessPercent(),
15
- evaluationPeriods: params.alarm?.evalutionPeriods ?? 1,
16
- threshold: params.alarm?.threshold ?? 100,
17
- comparisonOperator: aws_cloudwatch_1.ComparisonOperator.LESS_THAN_THRESHOLD,
18
- });
19
- if (params.alarm?.topicArn) {
20
- alarm.addAlarmAction(new aws_cloudwatch_actions_1.SnsAction(aws_sns_1.Topic.fromTopicArn(stack, `${alarmName}-action`, params.alarm.topicArn)));
21
- }
9
+ const alarmName = params.alarm?.alarmName ?? `${params.name}-alarm`;
10
+ const alarm = new aws_cloudwatch_1.Alarm(stack, alarmName, {
11
+ alarmName,
12
+ alarmDescription: params.alarm?.description ?? "",
13
+ metric: canary.metricSuccessPercent(),
14
+ evaluationPeriods: params.alarm?.evalutionPeriods ?? 1,
15
+ threshold: params.alarm?.threshold ?? 100,
16
+ comparisonOperator: aws_cloudwatch_1.ComparisonOperator.LESS_THAN_THRESHOLD,
17
+ });
18
+ if (params.alarm?.topicArn) {
19
+ alarm.addAlarmAction(new aws_cloudwatch_actions_1.SnsAction(aws_sns_1.Topic.fromTopicArn(stack, `${alarmName}-action`, params.alarm.topicArn)));
22
20
  }
23
21
  }
24
22
  }
@@ -17,15 +17,13 @@ class DigitrafficCanary extends aws_synthetics_alpha_1.Canary {
17
17
  }),
18
18
  environmentVariables: {
19
19
  ...environmentVariables,
20
- ...params?.canaryEnv,
20
+ ...params.canaryEnv,
21
21
  },
22
22
  canaryName,
23
23
  schedule: params.schedule ?? aws_synthetics_alpha_1.Schedule.rate(aws_cdk_lib_1.Duration.minutes(15)),
24
24
  });
25
25
  this.artifactsBucket.grantWrite(role);
26
- if (params.alarm ?? true) {
27
- new canary_alarm_1.CanaryAlarm(scope, this, params);
28
- }
26
+ new canary_alarm_1.CanaryAlarm(scope, this, params);
29
27
  }
30
28
  }
31
29
  exports.DigitrafficCanary = DigitrafficCanary;
@@ -5,7 +5,7 @@ const database_1 = require("../../../database/database");
5
5
  const proxy_holder_1 = require("../../runtime/secrets/proxy-holder");
6
6
  const rds_holder_1 = require("../../runtime/secrets/rds-holder");
7
7
  const utils_1 = require("../../../utils/utils");
8
- // eslint-disable-next-line @typescript-eslint/no-var-requires
8
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-var-requires
9
9
  const synthetics = require("Synthetics");
10
10
  class DatabaseCheck {
11
11
  constructor(name, sql) {
@@ -58,7 +58,9 @@ class DatabaseCountChecker {
58
58
  constructor(credentialsFunction) {
59
59
  this.checks = [];
60
60
  this.credentialsFunction = credentialsFunction;
61
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call
61
62
  synthetics.getConfiguration().disableRequestMetrics();
63
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call
62
64
  synthetics.getConfiguration().withFailedCanaryMetric(true);
63
65
  }
64
66
  static createForProxy() {
@@ -100,6 +102,7 @@ class DatabaseCountChecker {
100
102
  const checkFunction = () => {
101
103
  check.check(value);
102
104
  };
105
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call
103
106
  synthetics.executeStep(check.name, checkFunction, stepConfig);
104
107
  }
105
108
  });
@@ -23,6 +23,7 @@ class UrlCanary extends canary_1.DigitrafficCanary {
23
23
  static create(stack, role, publicApi, params) {
24
24
  return new UrlCanary(stack, role, {
25
25
  ...{
26
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
26
27
  handler: `${params.name}.handler`,
27
28
  hostname: publicApi.hostname(),
28
29
  apiKeyId: this.getApiKey(publicApi),
@@ -3,8 +3,8 @@ import { IncomingMessage } from "http";
3
3
  import { MediaType } from "../../types/mediatypes";
4
4
  import { FeatureCollection } from "geojson";
5
5
  export declare const API_KEY_HEADER = "x-api-key";
6
- type CheckerFunction = (Res: IncomingMessage) => void;
7
- type JsonCheckerFunction<T> = (json: T, body: string, message: IncomingMessage) => void;
6
+ type CheckerFunction = (Res: IncomingMessage) => Promise<void>;
7
+ type JsonCheckerFunction<T> = (json: T, body: string, message: IncomingMessage) => Promise<void>;
8
8
  export declare class UrlChecker {
9
9
  private readonly requestOptions;
10
10
  constructor(hostname: string, apiKey?: string);
@@ -2,7 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.HeaderChecker = exports.GeoJsonChecker = exports.ContentTypeChecker = exports.ContentChecker = exports.ResponseChecker = exports.UrlChecker = exports.API_KEY_HEADER = void 0;
4
4
  const asserter_1 = require("../../../test/asserter");
5
- // eslint-disable-next-line @typescript-eslint/no-var-requires
5
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-var-requires
6
6
  const synthetics = require("Synthetics");
7
7
  const zlib = require("zlib");
8
8
  const mediatypes_1 = require("../../types/mediatypes");
@@ -28,7 +28,9 @@ class UrlChecker {
28
28
  protocol: "https:",
29
29
  headers,
30
30
  };
31
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call
31
32
  synthetics.getConfiguration().disableRequestMetrics();
33
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call
32
34
  synthetics
33
35
  .getConfiguration()
34
36
  .withIncludeRequestBody(false)
@@ -52,6 +54,7 @@ class UrlChecker {
52
54
  path: url,
53
55
  },
54
56
  };
57
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-return
55
58
  return synthetics.executeHttpStep(`Verify ${statusCode} for ${url.replace(/auth=.*/, "")}`, requestOptions, callback);
56
59
  }
57
60
  expect200(url, ...callbacks) {
@@ -67,6 +70,7 @@ class UrlChecker {
67
70
  path: url,
68
71
  },
69
72
  };
73
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-return
70
74
  return synthetics.executeHttpStep(`Verify 404 for ${url}`, requestOptions, validateStatusCodeAndContentType(404, mediatypes_1.MediaType.TEXT_PLAIN));
71
75
  }
72
76
  expect400(url) {
@@ -76,10 +80,13 @@ class UrlChecker {
76
80
  path: url,
77
81
  },
78
82
  };
83
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-return
79
84
  return synthetics.executeHttpStep(`Verify 400 for ${url}`, requestOptions, validateStatusCodeAndContentType(400, mediatypes_1.MediaType.TEXT_PLAIN));
80
85
  }
81
86
  expect403WithoutApiKey(url, mediaType) {
82
- if (!this.requestOptions.headers ||
87
+ if (
88
+ // eslint-disable-next-line @typescript-eslint/prefer-optional-chain
89
+ !this.requestOptions.headers ||
83
90
  !this.requestOptions.headers[exports.API_KEY_HEADER]) {
84
91
  console.error("No api key defined");
85
92
  }
@@ -90,6 +97,7 @@ class UrlChecker {
90
97
  headers: baseHeaders,
91
98
  },
92
99
  };
100
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-return
93
101
  return synthetics.executeHttpStep(`Verify 403 for ${url}`, requestOptions, validateStatusCodeAndContentType(403, mediaType ?? mediatypes_1.MediaType.APPLICATION_JSON));
94
102
  }
95
103
  done() {
@@ -129,10 +137,13 @@ function validateStatusCodeAndContentType(statusCode, contentType) {
129
137
  return (res) => {
130
138
  return new Promise((resolve) => {
131
139
  if (res.statusCode !== statusCode) {
140
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
132
141
  throw new Error(`${res.statusCode} ${res.statusMessage}`);
133
142
  }
134
143
  if (res.headers["content-type"] !== contentType) {
135
- throw new Error("Wrong content-type " + res.headers["content-type"]);
144
+ throw new Error(
145
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
146
+ `Wrong content-type ${res.headers["content-type"]}`);
136
147
  }
137
148
  resolve();
138
149
  });
@@ -172,13 +183,16 @@ class ResponseChecker {
172
183
  throw new Error("statusCode missing");
173
184
  }
174
185
  if (res.statusCode < 200 || res.statusCode > 299) {
186
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
175
187
  throw new Error(`${res.statusCode} ${res.statusMessage}`);
176
188
  }
177
189
  if (this.checkCors && !res.headers["access-control-allow-origin"]) {
178
190
  throw new Error("CORS missing");
179
191
  }
180
192
  if (res.headers["content-type"] !== this.contentType) {
181
- throw new Error("Wrong content-type " + res.headers["content-type"]);
193
+ throw new Error(
194
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
195
+ `Wrong content-type ${res.headers["content-type"]}`);
182
196
  }
183
197
  const body = await getResponseBody(res);
184
198
  fn(body, res);
@@ -208,13 +222,16 @@ class ContentTypeChecker {
208
222
  throw new Error("statusCode missing");
209
223
  }
210
224
  if (res.statusCode < 200 || res.statusCode > 299) {
225
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
211
226
  throw new Error(`${res.statusCode} ${res.statusMessage}`);
212
227
  }
213
228
  if (!res.headers["access-control-allow-origin"]) {
214
229
  throw new Error("CORS missing");
215
230
  }
216
231
  if (res.headers["content-type"] !== contentType) {
217
- throw new Error("Wrong content-type " + res.headers["content-type"]);
232
+ throw new Error(
233
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
234
+ `Wrong content-type ${res.headers["content-type"]}`);
218
235
  }
219
236
  };
220
237
  }
@@ -238,6 +255,7 @@ class HeaderChecker {
238
255
  if (!res.headers[headerName]) {
239
256
  throw new Error("Missing header: " + headerName);
240
257
  }
258
+ return Promise.resolve();
241
259
  };
242
260
  }
243
261
  static checkHeaderMissing(headerName) {
@@ -245,6 +263,7 @@ class HeaderChecker {
245
263
  if (res.headers[headerName]) {
246
264
  throw new Error("Header should not exist: " + headerName);
247
265
  }
266
+ return Promise.resolve();
248
267
  };
249
268
  }
250
269
  }
@@ -2,6 +2,4 @@ import { RequestValidator, Resource } from "aws-cdk-lib/aws-apigateway";
2
2
  import { Queue } from "aws-cdk-lib/aws-sqs";
3
3
  import { IModel } from "aws-cdk-lib/aws-apigateway/lib/model";
4
4
  import { Construct } from "constructs";
5
- export declare function attachQueueToApiGatewayResource(stack: Construct, queue: Queue, resource: Resource, requestValidator: RequestValidator, resourceName: string, apiKeyRequired: boolean, requestModels?: {
6
- [param: string]: IModel;
7
- }): void;
5
+ export declare function attachQueueToApiGatewayResource(stack: Construct, queue: Queue, resource: Resource, requestValidator: RequestValidator, resourceName: string, apiKeyRequired: boolean, requestModels?: Record<string, IModel>): void;
@@ -7,83 +7,79 @@ const aws_iam_1 = require("aws-cdk-lib/aws-iam");
7
7
  function attachQueueToApiGatewayResource(stack, queue, resource, requestValidator, resourceName, apiKeyRequired, requestModels) {
8
8
  // role for API Gateway
9
9
  const apiGwRole = new aws_iam_1.Role(stack, `${resourceName}APIGatewayToSQSRole`, {
10
- assumedBy: new aws_iam_1.ServicePrincipal('apigateway.amazonaws.com'),
10
+ assumedBy: new aws_iam_1.ServicePrincipal("apigateway.amazonaws.com"),
11
11
  });
12
12
  // grants API Gateway the right to send SQS messages
13
13
  apiGwRole.addToPolicy(new aws_iam_1.PolicyStatement({
14
- resources: [
15
- queue.queueArn,
16
- ],
17
- actions: [
18
- 'sqs:SendMessage',
19
- ],
14
+ resources: [queue.queueArn],
15
+ actions: ["sqs:SendMessage"],
20
16
  }));
21
17
  // grants API Gateway the right write CloudWatch Logs
22
18
  apiGwRole.addToPolicy(new aws_iam_1.PolicyStatement({
23
- resources: [
24
- '*',
25
- ],
19
+ resources: ["*"],
26
20
  actions: [
27
- 'logs:CreateLogGroup',
28
- 'logs:CreateLogStream',
29
- 'logs:DescribeLogGroups',
30
- 'logs:DescribeLogStreams',
31
- 'logs:PutLogEvents',
32
- 'logs:GetLogEvents',
33
- 'logs:FilterLogEvents',
21
+ "logs:CreateLogGroup",
22
+ "logs:CreateLogStream",
23
+ "logs:DescribeLogGroups",
24
+ "logs:DescribeLogStreams",
25
+ "logs:PutLogEvents",
26
+ "logs:GetLogEvents",
27
+ "logs:FilterLogEvents",
34
28
  ],
35
29
  }));
36
30
  // create an integration between API Gateway and an SQS queue
37
- const fifoMessageGroupId = queue.fifo ? '&MessageGroupId=AlwaysSameFifoGroup' : '';
31
+ const fifoMessageGroupId = queue.fifo
32
+ ? "&MessageGroupId=AlwaysSameFifoGroup"
33
+ : "";
38
34
  const sqsIntegration = new aws_apigateway_1.AwsIntegration({
39
- service: 'sqs',
40
- integrationHttpMethod: 'POST',
35
+ service: "sqs",
36
+ integrationHttpMethod: "POST",
41
37
  options: {
42
38
  passthroughBehavior: aws_apigateway_1.PassthroughBehavior.NEVER,
43
39
  credentialsRole: apiGwRole,
44
40
  requestParameters: {
45
41
  // SQS requires the Content-Type of the HTTP request to be application/x-www-form-urlencoded
46
- 'integration.request.header.Content-Type': "'application/x-www-form-urlencoded'",
42
+ "integration.request.header.Content-Type": "'application/x-www-form-urlencoded'",
47
43
  },
48
44
  requestTemplates: {
49
45
  // map the JSON request to a form parameter, FIFO needs also MessageGroupId
50
46
  // https://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_SendMessage.html
51
- 'application/json': `Action=SendMessage${fifoMessageGroupId}&MessageBody=$util.urlEncode($input.body)`,
47
+ "application/json": `Action=SendMessage${fifoMessageGroupId}&MessageBody=$util.urlEncode($input.body)`,
52
48
  },
53
49
  // these are required by SQS
54
50
  integrationResponses: [
55
51
  {
56
- statusCode: '200',
52
+ statusCode: "200",
57
53
  responseTemplates: {
58
- 'text/html': 'Success',
54
+ "text/html": "Success",
59
55
  },
60
56
  },
61
57
  {
62
- statusCode: '500',
58
+ statusCode: "500",
63
59
  responseTemplates: {
64
- 'text/html': 'Error',
60
+ "text/html": "Error",
65
61
  },
66
- selectionPattern: '500',
62
+ selectionPattern: "500",
67
63
  },
68
64
  ],
69
65
  },
70
66
  path: `${aws_cdk_lib_1.Aws.ACCOUNT_ID}/${queue.queueName}`,
71
67
  });
72
- resource.addMethod('POST', sqsIntegration, {
68
+ resource.addMethod("POST", sqsIntegration, {
73
69
  requestValidator,
74
70
  apiKeyRequired,
75
71
  requestModels: requestModels ?? {},
76
72
  methodResponses: [
77
73
  {
78
- statusCode: '200',
74
+ statusCode: "200",
79
75
  responseParameters: {
80
- 'method.response.header.Content-Type': true,
76
+ "method.response.header.Content-Type": true,
81
77
  },
82
78
  },
83
79
  {
84
- statusCode: '500',
80
+ statusCode: "500",
85
81
  responseParameters: {
86
- 'method.response.header.Content-Type': true,
82
+ "method.response.header.Content-Type": true,
87
83
  },
88
84
  },
89
85
  ],
@@ -1,5 +1,4 @@
1
1
  import { Queue, QueueProps } from "aws-cdk-lib/aws-sqs";
2
- import { Construct } from "constructs";
3
2
  import { DigitrafficStack } from "./stack/stack";
4
3
  /**
5
4
  * Construct for creating SQS-queues.
@@ -8,7 +7,6 @@ import { DigitrafficStack } from "./stack/stack";
8
7
  * and an alarm for the queue. Anything that goes to the dlq will be written into the bucket and the alarm is activated.
9
8
  */
10
9
  export declare class DigitrafficSqsQueue extends Queue {
11
- constructor(scope: Construct, name: string, props: QueueProps);
12
10
  static create(stack: DigitrafficStack, name: string, props: QueueProps): DigitrafficSqsQueue;
13
11
  }
14
12
  export declare class DigitrafficDLQueue {
@@ -18,19 +18,19 @@ const monitoredfunction_1 = require("./stack/monitoredfunction");
18
18
  * and an alarm for the queue. Anything that goes to the dlq will be written into the bucket and the alarm is activated.
19
19
  */
20
20
  class DigitrafficSqsQueue extends aws_sqs_1.Queue {
21
- constructor(scope, name, props) {
22
- super(scope, name, props);
23
- }
24
21
  static create(stack, name, props) {
25
22
  const queueName = `${stack.configuration.shortName}-${name}-Queue`;
26
- const queueProps = { ...props, ...{
23
+ const queueProps = {
24
+ ...props,
25
+ ...{
27
26
  encryption: aws_sqs_1.QueueEncryption.KMS_MANAGED,
28
27
  queueName,
29
- deadLetterQueue: props.deadLetterQueue || {
28
+ deadLetterQueue: props.deadLetterQueue ?? {
30
29
  maxReceiveCount: 2,
31
30
  queue: DigitrafficDLQueue.create(stack, name),
32
31
  },
33
- } };
32
+ },
33
+ };
34
34
  return new DigitrafficSqsQueue(stack, queueName, queueProps);
35
35
  }
36
36
  }
@@ -53,14 +53,14 @@ class DigitrafficDLQueue {
53
53
  functionName: dlqFunctionName,
54
54
  code: getDlqCode(dlqBucket.bucketName),
55
55
  timeout: aws_cdk_lib_1.Duration.seconds(10),
56
- handler: 'index.handler',
56
+ handler: "index.handler",
57
57
  memorySize: 128,
58
58
  reservedConcurrentExecutions: 1,
59
59
  });
60
60
  const statement = new aws_iam_1.PolicyStatement();
61
- statement.addActions('s3:PutObject');
62
- statement.addActions('s3:PutObjectAcl');
63
- statement.addResources(dlqBucket.bucketArn + '/*');
61
+ statement.addActions("s3:PutObject");
62
+ statement.addActions("s3:PutObjectAcl");
63
+ statement.addResources(dlqBucket.bucketArn + "/*");
64
64
  lambda.addToRolePolicy(statement);
65
65
  lambda.addEventSource(new aws_lambda_event_sources_1.SqsEventSource(dlq));
66
66
  addDLQAlarm(stack, dlqName, dlq);
@@ -72,17 +72,18 @@ function addDLQAlarm(stack, dlqName, dlq) {
72
72
  const alarmName = `${dlqName}-Alarm`;
73
73
  dlq.metricNumberOfMessagesReceived({
74
74
  period: aws_cdk_lib_1.Duration.minutes(5),
75
- }).createAlarm(stack, alarmName, {
75
+ })
76
+ .createAlarm(stack, alarmName, {
76
77
  alarmName,
77
78
  threshold: 0,
78
79
  evaluationPeriods: 1,
79
80
  treatMissingData: aws_cloudwatch_1.TreatMissingData.NOT_BREACHING,
80
81
  comparisonOperator: aws_cloudwatch_1.ComparisonOperator.GREATER_THAN_THRESHOLD,
81
- }).addAlarmAction(new aws_cloudwatch_actions_1.SnsAction(stack.warningTopic));
82
+ })
83
+ .addAlarmAction(new aws_cloudwatch_actions_1.SnsAction(stack.warningTopic));
82
84
  }
83
85
  function getDlqCode(bName) {
84
- const functionBody = DLQ_LAMBDA_CODE
85
- .replace("__bucketName__", bName)
86
+ const functionBody = DLQ_LAMBDA_CODE.replace("__bucketName__", bName)
86
87
  .replace("__upload__", uploadToS3.toString())
87
88
  .replace("__doUpload__", doUpload.toString())
88
89
  .replace("__handler__", createHandler().toString().substring(23)); // remove function handler() from signature
@@ -90,33 +91,39 @@ function getDlqCode(bName) {
90
91
  }
91
92
  async function uploadToS3(s3, bName, body, objectName) {
92
93
  try {
93
- console.info('writing %s to %s', objectName, bName);
94
+ console.info("writing %s to %s", objectName, bName);
94
95
  await doUpload(s3, bName, body, objectName);
95
96
  }
96
97
  catch (error) {
97
98
  console.warn(error);
98
- console.warn('method=uploadToS3 retrying upload to bucket %s', bName);
99
+ console.warn("method=uploadToS3 retrying upload to bucket %s", bName);
99
100
  try {
100
101
  await doUpload(s3, bName, body, objectName);
101
102
  }
102
103
  catch (e2) {
103
- console.error('method=uploadToS3 failed retrying upload to bucket %s', bName);
104
+ console.error("method=uploadToS3 failed retrying upload to bucket %s", bName);
104
105
  }
105
106
  }
106
107
  }
107
108
  function doUpload(s3, bName, Body, Key) {
108
- return s3.upload({
109
- Bucket: bName, Body, Key,
110
- }).promise();
109
+ return s3
110
+ .upload({
111
+ Bucket: bName,
112
+ Body,
113
+ Key,
114
+ })
115
+ .promise();
111
116
  }
112
117
  // bucketName is unused, will be overridden in the actual lambda code below
113
- const bucketName = '';
118
+ const bucketName = "";
114
119
  function createHandler() {
115
120
  return async function handler(event) {
116
- // eslint-disable-next-line @typescript-eslint/no-var-requires
117
- const AWS = require('aws-sdk');
121
+ // eslint-disable-next-line @typescript-eslint/no-var-requires, @typescript-eslint/no-unsafe-assignment
122
+ const AWS = require("aws-sdk");
118
123
  const millis = new Date().getTime();
119
- await Promise.all(event.Records.map((e, idx) => uploadToS3(new AWS.S3(), bucketName, e.body, `dlq-${millis}-${idx}.json`)));
124
+ await Promise.all(event.Records.map((e, idx) => uploadToS3(
125
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access
126
+ new AWS.S3(), bucketName, e.body, `dlq-${millis}-${idx}.json`)));
120
127
  };
121
128
  }
122
129
  const DLQ_LAMBDA_CODE = `const AWS = require('aws-sdk');
@@ -1,5 +1,5 @@
1
1
  import { Architecture, Code, FunctionProps, Runtime } from "aws-cdk-lib/aws-lambda";
2
- import { ISecurityGroup, IVpc, SubnetSelection } from "aws-cdk-lib/aws-ec2";
2
+ import { IVpc, SubnetSelection } from "aws-cdk-lib/aws-ec2";
3
3
  import { Role } from "aws-cdk-lib/aws-iam";
4
4
  import { DigitrafficStack } from "./stack";
5
5
  import { MonitoredFunctionAlarmProps } from "./monitoredfunction";
@@ -8,34 +8,8 @@ export type DBLambdaEnvironment = LambdaEnvironment & {
8
8
  SECRET_ID?: string;
9
9
  DB_APPLICATION: string;
10
10
  };
11
- export interface LambdaConfiguration {
12
- vpcId: string;
13
- allowFromIpAddresses?: string[];
14
- privateSubnetIds: string[];
15
- availabilityZones: string[];
16
- lambdaDbSgId: string;
17
- dbProps?: DbProps;
18
- defaultLambdaDurationSeconds?: number;
19
- logsDestinationArn: string;
20
- memorySize?: number;
21
- runtime?: Runtime;
22
- }
23
- declare interface DbProps {
24
- username: string;
25
- password: string;
26
- uri?: string;
27
- ro_uri?: string;
28
- }
29
11
  export declare function databaseFunctionProps(stack: DigitrafficStack, environment: LambdaEnvironment, lambdaName: string, simpleLambdaName: string, config?: Partial<FunctionParameters>): FunctionProps;
30
12
  export declare function lambdaFunctionProps(stack: DigitrafficStack, environment: LambdaEnvironment, lambdaName: string, simpleLambdaName: string, config?: Partial<FunctionParameters>): FunctionProps;
31
- /**
32
- * Creates a base configuration for a Lambda that uses an RDS database
33
- * @param vpc "Private" Lambdas are associated with a VPC
34
- * @param lambdaDbSg Security Group shared by Lambda and RDS
35
- * @param props Database connection properties for the Lambda
36
- * @param config Lambda configuration
37
- */
38
- export declare function dbLambdaConfiguration(vpc: IVpc, lambdaDbSg: ISecurityGroup, props: LambdaConfiguration, config: FunctionParameters): FunctionProps;
39
13
  export declare function defaultLambdaConfiguration(config: FunctionParameters): FunctionProps;
40
14
  export interface FunctionParameters {
41
15
  memorySize?: number;
@@ -44,9 +18,7 @@ export interface FunctionParameters {
44
18
  code: Code;
45
19
  handler: string;
46
20
  readOnly?: boolean;
47
- environment?: {
48
- [key: string]: string;
49
- };
21
+ environment?: Record<string, string>;
50
22
  reservedConcurrentExecutions?: number;
51
23
  role?: Role;
52
24
  vpc?: IVpc;
@@ -61,4 +33,3 @@ export type MonitoredFunctionParameters = FunctionParameters & {
61
33
  readonly errorAlarmProps?: MonitoredFunctionAlarmProps;
62
34
  readonly throttleAlarmProps?: MonitoredFunctionAlarmProps;
63
35
  };
64
- export {};