@digitraffic/common 2023.1.18-2 → 2023.1.23-1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/dist/aws/infra/canaries/canary-alarm.js +11 -13
  2. package/dist/aws/infra/canaries/canary.js +2 -4
  3. package/dist/aws/infra/canaries/database-checker.js +4 -1
  4. package/dist/aws/infra/canaries/url-canary.js +1 -0
  5. package/dist/aws/infra/canaries/url-checker.d.ts +2 -2
  6. package/dist/aws/infra/canaries/url-checker.js +24 -5
  7. package/dist/aws/infra/sqs-integration.d.ts +1 -3
  8. package/dist/aws/infra/sqs-integration.js +28 -32
  9. package/dist/aws/infra/sqs-queue.d.ts +0 -2
  10. package/dist/aws/infra/sqs-queue.js +31 -24
  11. package/dist/aws/infra/stack/lambda-configs.d.ts +2 -31
  12. package/dist/aws/infra/stack/lambda-configs.js +5 -38
  13. package/dist/aws/infra/stack/monitoredfunction.js +3 -1
  14. package/dist/aws/infra/stacks/db-stack.js +1 -1
  15. package/dist/aws/infra/stacks/network-stack.d.ts +2 -1
  16. package/dist/aws/infra/stacks/network-stack.js +4 -2
  17. package/dist/aws/runtime/secrets/dbsecret.d.ts +0 -39
  18. package/dist/aws/runtime/secrets/dbsecret.js +1 -71
  19. package/dist/aws/runtime/secrets/proxy-holder.js +5 -4
  20. package/dist/aws/runtime/secrets/rds-holder.js +5 -4
  21. package/dist/aws/runtime/secrets/secret-holder.d.ts +0 -4
  22. package/dist/aws/runtime/secrets/secret-holder.js +6 -12
  23. package/dist/aws/runtime/secrets/secret.d.ts +0 -6
  24. package/dist/aws/runtime/secrets/secret.js +8 -17
  25. package/dist/database/database.d.ts +7 -0
  26. package/dist/database/database.js +19 -8
  27. package/dist/test/db-testutils.js +4 -5
  28. package/package.json +1 -1
  29. package/src/aws/infra/canaries/canary-alarm.ts +26 -24
  30. package/src/aws/infra/canaries/canary.ts +2 -4
  31. package/src/aws/infra/canaries/database-checker.ts +4 -1
  32. package/src/aws/infra/canaries/url-canary.ts +2 -1
  33. package/src/aws/infra/canaries/url-checker.ts +28 -11
  34. package/src/aws/infra/sqs-integration.ts +51 -47
  35. package/src/aws/infra/sqs-queue.ts +85 -53
  36. package/src/aws/infra/stack/lambda-configs.ts +6 -69
  37. package/src/aws/infra/stack/monitoredfunction.ts +2 -1
  38. package/src/aws/infra/stacks/db-stack.ts +1 -1
  39. package/src/aws/infra/stacks/network-stack.ts +7 -3
  40. package/src/aws/runtime/secrets/dbsecret.ts +1 -117
  41. package/src/aws/runtime/secrets/proxy-holder.ts +2 -5
  42. package/src/aws/runtime/secrets/rds-holder.ts +2 -1
  43. package/src/aws/runtime/secrets/secret-holder.ts +8 -20
  44. package/src/aws/runtime/secrets/secret.ts +17 -22
  45. package/src/database/database.ts +14 -3
  46. package/src/test/db-testutils.ts +5 -2
  47. package/dist/test/secret.d.ts +0 -3
  48. package/dist/test/secret.js +0 -25
  49. package/src/test/secret.ts +0 -23
@@ -1,7 +1,8 @@
1
1
  import { Stack } from "aws-cdk-lib";
2
2
  import { Construct } from "constructs";
3
- import { SubnetType, Vpc } from "aws-cdk-lib/aws-ec2";
3
+ import { IVpc, SubnetType, Vpc } from "aws-cdk-lib/aws-ec2";
4
4
  import { InfraStackConfiguration } from "./intra-stack-configuration";
5
+ import { exportValue } from "../import-util";
5
6
 
6
7
  export interface NetworkConfiguration {
7
8
  readonly vpcName: string;
@@ -9,6 +10,8 @@ export interface NetworkConfiguration {
9
10
  }
10
11
 
11
12
  export class NetworkStack extends Stack {
13
+ readonly vpc: IVpc;
14
+
12
15
  constructor(
13
16
  scope: Construct,
14
17
  id: string,
@@ -19,7 +22,8 @@ export class NetworkStack extends Stack {
19
22
  env: isc.env,
20
23
  });
21
24
 
22
- this.createVpc(configuration);
25
+ this.vpc = this.createVpc(configuration);
26
+ exportValue(this, isc.environmentName, "VPCID", this.vpc.vpcId);
23
27
  }
24
28
 
25
29
  createVpc(configuration: NetworkConfiguration): Vpc {
@@ -38,7 +42,7 @@ export class NetworkStack extends Stack {
38
42
  {
39
43
  name: "private",
40
44
  cidrMask: 24,
41
- subnetType: SubnetType.PRIVATE_WITH_NAT,
45
+ subnetType: SubnetType.PRIVATE_WITH_EGRESS,
42
46
  },
43
47
  ],
44
48
  });
@@ -1,11 +1,4 @@
1
- import { GenericSecret, withSecret, withSecretAndPrefix } from "./secret";
2
-
3
- export interface DbSecret {
4
- readonly username: string;
5
- readonly password: string;
6
- readonly host: string;
7
- readonly ro_host: string;
8
- }
1
+ import { GenericSecret } from "./secret";
9
2
 
10
3
  export enum RdsProxySecretKey {
11
4
  username = "username",
@@ -24,115 +17,6 @@ export enum RdsSecretKey {
24
17
  export type RdsProxySecret = Record<RdsProxySecretKey, string>;
25
18
  export type RdsSecret = Record<RdsSecretKey, string>;
26
19
 
27
- export enum DatabaseEnvironmentKeys {
28
- DB_USER = "DB_USER",
29
- DB_PASS = "DB_PASS",
30
- DB_URI = "DB_URI",
31
- DB_RO_URI = "DB_RO_URI",
32
- DB_APPLICATION = "DB_APPLICATION",
33
- }
34
-
35
- function setDbSecret(secret: DbSecret) {
36
- process.env[DatabaseEnvironmentKeys.DB_USER] = secret.username;
37
- process.env[DatabaseEnvironmentKeys.DB_PASS] = secret.password;
38
- process.env[DatabaseEnvironmentKeys.DB_URI] = secret.host;
39
- process.env[DatabaseEnvironmentKeys.DB_RO_URI] = secret.ro_host;
40
- }
41
-
42
- // cached at Lambda container level
43
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
44
- let cachedSecret: any;
45
-
46
- const missingSecretErrorText = "Missing or empty secretId";
47
-
48
- /**
49
- * You can give the following options for retrieving a secret:
50
- *
51
- * expectedKeys: the list of keys the secret must include. If not, an error will be thrown.
52
- * prefix: a prefix that's included in retrieved secret's keys. Only keys begining with the prefix will be included.
53
- * The secret that is passed to the given function will not include the prefix in it's keys.
54
-
55
- */
56
- export interface SecretOptions {
57
- readonly expectedKeys?: string[];
58
- readonly prefix?: string;
59
- }
60
-
61
- export type SecretToPromiseFunction<Secret, Response = void> = (
62
- secret: Secret
63
- ) => Promise<Response> | void;
64
- export type SecretFunction<Secret, Response = void> = (
65
- secretId: string,
66
- fn: SecretToPromiseFunction<Secret, Response>,
67
- options?: SecretOptions
68
- ) => Promise<Response | void>;
69
- export type EmptySecretFunction<Response = void> = SecretFunction<
70
- DbSecret,
71
- Response
72
- >;
73
-
74
- /**
75
- * Run the given function with secret retrieved from Secrets Manager. Also injects database-credentials into environment.
76
- *
77
- * @deprecated use SecretHolder & ProxyHolder
78
- * @see SecretOptions
79
- *
80
- * @param {string} secretId
81
- * @param {function} fn
82
- * @param {SecretOptions} options
83
- */
84
- export async function withDbSecret<Secret, Response>(
85
- secretId: string,
86
- fn: SecretToPromiseFunction<Secret, Response>,
87
- options?: SecretOptions
88
- ): Promise<Response | void> {
89
- if (!secretId) {
90
- console.error(missingSecretErrorText);
91
- return Promise.reject(missingSecretErrorText);
92
- }
93
-
94
- if (!cachedSecret) {
95
- // if prefix is given, first set db values and then fetch secret
96
- if (options?.prefix) {
97
- // first set db values
98
- await withSecret(secretId, (fetchedSecret: DbSecret) => {
99
- setDbSecret(fetchedSecret);
100
- });
101
-
102
- // then actual secret
103
- await withSecretAndPrefix(
104
- secretId,
105
- options.prefix,
106
- (fetchedSecret: Secret) => {
107
- cachedSecret = fetchedSecret;
108
- }
109
- );
110
- } else {
111
- await withSecret(secretId, (fetchedSecret: DbSecret) => {
112
- setDbSecret(fetchedSecret);
113
- cachedSecret = fetchedSecret;
114
- });
115
- }
116
- }
117
- try {
118
- if (options?.expectedKeys?.length) {
119
- checkExpectedSecretKeys(options.expectedKeys, cachedSecret);
120
- }
121
- return fn(cachedSecret);
122
- } catch (error) {
123
- console.error(
124
- "method=withDbSecret Caught an error, refreshing secret",
125
- error
126
- );
127
- // try to refetch secret in case it has changed
128
- await withSecret(secretId, (fetchedSecret: DbSecret) => {
129
- setDbSecret(fetchedSecret);
130
- cachedSecret = fetchedSecret;
131
- });
132
- return fn(cachedSecret);
133
- }
134
- }
135
-
136
20
  export function checkExpectedSecretKeys<Secret extends GenericSecret>(
137
21
  keys: string[],
138
22
  secret: Secret
@@ -1,10 +1,7 @@
1
1
  import { SecretHolder } from "./secret-holder";
2
- import {
3
- DatabaseEnvironmentKeys,
4
- RdsProxySecretKey,
5
- RdsProxySecret,
6
- } from "./dbsecret";
2
+ import { RdsProxySecretKey, RdsProxySecret } from "./dbsecret";
7
3
  import { getEnvVariable } from "../../../utils/utils";
4
+ import { DatabaseEnvironmentKeys } from "../../../database/database";
8
5
 
9
6
  const RDS_PROXY_SECRET_KEYS = Object.values(RdsProxySecretKey);
10
7
 
@@ -1,6 +1,7 @@
1
1
  import { SecretHolder } from "./secret-holder";
2
- import { DatabaseEnvironmentKeys, RdsSecret, RdsSecretKey } from "./dbsecret";
2
+ import { RdsSecret, RdsSecretKey } from "./dbsecret";
3
3
  import { getEnvVariable } from "../../../utils/utils";
4
+ import { DatabaseEnvironmentKeys } from "../../../database/database";
4
5
 
5
6
  const RDS_SECRET_KEYS = Object.values(RdsSecretKey);
6
7
 
@@ -1,12 +1,8 @@
1
1
  import { GenericSecret, getSecret } from "./secret";
2
- import {
3
- checkExpectedSecretKeys,
4
- DatabaseEnvironmentKeys,
5
- DbSecret,
6
- } from "./dbsecret";
2
+ import { checkExpectedSecretKeys } from "./dbsecret";
7
3
  import { getEnvVariable } from "../../../utils/utils";
8
4
 
9
- // eslint-disable-next-line @typescript-eslint/no-var-requires
5
+ // eslint-disable-next-line @typescript-eslint/no-var-requires, @typescript-eslint/no-unsafe-assignment
10
6
  const NodeTtl = require("node-ttl");
11
7
 
12
8
  const DEFAULT_PREFIX = "";
@@ -40,6 +36,7 @@ export class SecretHolder<Secret extends GenericSecret> {
40
36
  this.prefix = prefix;
41
37
  this.expectedKeys = expectedKeys;
42
38
 
39
+ // eslint-disable-next-line @typescript-eslint/no-var-requires, @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-call
43
40
  this.secretCache = new NodeTtl(configuration);
44
41
  }
45
42
 
@@ -48,6 +45,7 @@ export class SecretHolder<Secret extends GenericSecret> {
48
45
 
49
46
  console.info("refreshing secret " + this.secretId);
50
47
 
48
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access
51
49
  this.secretCache.push(DEFAULT_SECRET_KEY, secretValue);
52
50
  }
53
51
 
@@ -90,24 +88,14 @@ export class SecretHolder<Secret extends GenericSecret> {
90
88
  }
91
89
 
92
90
  private async getSecret<S>(): Promise<S> {
93
- const secret = this.secretCache.get(DEFAULT_SECRET_KEY);
91
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call
92
+ const secret: S | undefined = this.secretCache.get(DEFAULT_SECRET_KEY);
94
93
 
95
94
  if (!secret) {
96
95
  await this.initSecret();
97
96
  }
98
97
 
99
- return secret || this.secretCache.get(DEFAULT_SECRET_KEY);
100
- }
101
-
102
- /**
103
- * @deprecated Use ProxyHolder
104
- */
105
- public async setDatabaseCredentials() {
106
- const secret = await this.getSecret<DbSecret>();
107
-
108
- process.env[DatabaseEnvironmentKeys.DB_USER] = secret.username;
109
- process.env[DatabaseEnvironmentKeys.DB_PASS] = secret.password;
110
- process.env[DatabaseEnvironmentKeys.DB_URI] = secret.host;
111
- process.env[DatabaseEnvironmentKeys.DB_RO_URI] = secret.ro_host;
98
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call
99
+ return secret ?? (this.secretCache.get(DEFAULT_SECRET_KEY) as S);
112
100
  }
113
101
  }
@@ -1,5 +1,4 @@
1
- import {SecretsManager} from 'aws-sdk';
2
- import {SecretToPromiseFunction} from "./dbsecret";
1
+ import { SecretsManager } from "aws-sdk";
3
2
 
4
3
  const smClient = new SecretsManager({
5
4
  region: process.env.AWS_REGION,
@@ -7,29 +6,29 @@ const smClient = new SecretsManager({
7
6
 
8
7
  export type GenericSecret = Record<string, string>;
9
8
 
10
- /**
11
- @deprecated use SecretHolder & ProxyHolder
12
- */
13
- export async function withSecret<Secret, Response>(secretId: string, fn: SecretToPromiseFunction<Secret, Response>): Promise<Response | void> {
14
- return fn(await getSecret(secretId));
15
- }
16
-
17
- export async function getSecret<Secret>(secretId: string, prefix = ''): Promise<Secret> {
18
- const secretObj = await smClient.getSecretValue({
19
- SecretId: secretId,
20
- }).promise();
9
+ export async function getSecret<Secret>(
10
+ secretId: string,
11
+ prefix = ""
12
+ ): Promise<Secret> {
13
+ const secretObj = await smClient
14
+ .getSecretValue({
15
+ SecretId: secretId,
16
+ })
17
+ .promise();
21
18
 
22
19
  if (!secretObj.SecretString) {
23
- throw new Error('No secret found!');
20
+ throw new Error("No secret found!");
24
21
  }
25
22
 
26
- const secret = JSON.parse(secretObj.SecretString);
23
+ const secret: GenericSecret | Secret = JSON.parse(
24
+ secretObj.SecretString
25
+ ) as unknown as GenericSecret | Secret;
27
26
 
28
- if (prefix === '') {
29
- return secret;
27
+ if (!prefix) {
28
+ return secret as Secret;
30
29
  }
31
30
 
32
- return parseSecret(secret, `${prefix}.`);
31
+ return parseSecret(secret as GenericSecret, `${prefix}.`);
33
32
  }
34
33
 
35
34
  function parseSecret<Secret>(secret: GenericSecret, prefix: string): Secret {
@@ -44,7 +43,3 @@ function parseSecret<Secret>(secret: GenericSecret, prefix: string): Secret {
44
43
 
45
44
  return parsed as unknown as Secret;
46
45
  }
47
-
48
- export async function withSecretAndPrefix<Secret, Response>(secretId: string, prefix: string, fn: SecretToPromiseFunction<Secret, Response>): Promise<Response | void> {
49
- return fn(await getSecret(secretId, prefix));
50
- }
@@ -1,20 +1,30 @@
1
1
  import { IDatabase, ITask } from "pg-promise";
2
- import { DatabaseEnvironmentKeys } from "../aws/runtime/secrets/dbsecret";
3
2
  import { getEnvVariable } from "../utils/utils";
4
3
  import { envValue } from "../aws/runtime/environment";
5
4
 
6
- // eslint-disable-next-line @typescript-eslint/no-var-requires
5
+ export enum DatabaseEnvironmentKeys {
6
+ DB_USER = "DB_USER",
7
+ DB_PASS = "DB_PASS",
8
+ DB_URI = "DB_URI",
9
+ DB_RO_URI = "DB_RO_URI",
10
+ DB_APPLICATION = "DB_APPLICATION",
11
+ }
12
+
13
+ // eslint-disable-next-line @typescript-eslint/no-var-requires, @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-call
7
14
  const pgp = require("pg-promise")();
8
15
 
9
16
  // convert numeric types to number instead of string
17
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call
10
18
  pgp.pg.types.setTypeParser(pgp.pg.types.builtins.INT8, (value: string) => {
11
19
  return parseInt(value);
12
20
  });
13
21
 
22
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call
14
23
  pgp.pg.types.setTypeParser(pgp.pg.types.builtins.FLOAT8, (value: string) => {
15
24
  return parseFloat(value);
16
25
  });
17
26
 
27
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call
18
28
  pgp.pg.types.setTypeParser(pgp.pg.types.builtins.NUMERIC, (value: string) => {
19
29
  return parseFloat(value);
20
30
  });
@@ -44,6 +54,7 @@ export function initDbConnection(
44
54
  ): DTDatabase {
45
55
  const finalUrl = `postgresql://${username}:${password}@${url}?application_name=${applicationName}`;
46
56
 
57
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-return, @typescript-eslint/no-unsafe-call
47
58
  return pgp(finalUrl, options);
48
59
  }
49
60
 
@@ -90,6 +101,6 @@ async function doInDatabase<T>(
90
101
  console.error("Error in db:", e);
91
102
  throw e;
92
103
  } finally {
93
- db.$pool.end();
104
+ await db.$pool.end();
94
105
  }
95
106
  }
@@ -1,5 +1,8 @@
1
- import { DTDatabase, initDbConnection } from "../database/database";
2
- import { DatabaseEnvironmentKeys } from "../aws/runtime/secrets/dbsecret";
1
+ import {
2
+ DatabaseEnvironmentKeys,
3
+ DTDatabase,
4
+ initDbConnection,
5
+ } from "../database/database";
3
6
  import { Countable } from "../database/models";
4
7
 
5
8
  export async function assertCount(db: DTDatabase, sql: string, count: number) {
@@ -1,3 +0,0 @@
1
- import { EmptySecretFunction, SecretFunction } from "../aws/runtime/secrets/dbsecret";
2
- export declare function createSecretFunction<Secret, Response>(secret: Secret): SecretFunction<Secret, Response>;
3
- export declare function createEmptySecretFunction<Response>(): EmptySecretFunction<Response>;
@@ -1,25 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.createEmptySecretFunction = exports.createSecretFunction = void 0;
4
- const EMPTY_DB_SECRET = {
5
- username: '',
6
- password: '',
7
- host: '',
8
- // eslint-disable-next-line camelcase
9
- ro_host: '',
10
- };
11
- function createSecretFunction(secret) {
12
- // eslint-disable-next-line require-await
13
- return async (secretId, fn) => {
14
- return fn(secret);
15
- };
16
- }
17
- exports.createSecretFunction = createSecretFunction;
18
- function createEmptySecretFunction() {
19
- // eslint-disable-next-line require-await
20
- return async (secretId, fn) => {
21
- return fn(EMPTY_DB_SECRET);
22
- };
23
- }
24
- exports.createEmptySecretFunction = createEmptySecretFunction;
25
- //# sourceMappingURL=secret.js.map
@@ -1,23 +0,0 @@
1
- import {DbSecret, EmptySecretFunction, SecretFunction, SecretToPromiseFunction} from "../aws/runtime/secrets/dbsecret";
2
-
3
- const EMPTY_DB_SECRET: DbSecret = {
4
- username: '',
5
- password: '',
6
- host: '',
7
- // eslint-disable-next-line camelcase
8
- ro_host: '',
9
- };
10
-
11
- export function createSecretFunction<Secret, Response>(secret: Secret): SecretFunction<Secret, Response> {
12
- // eslint-disable-next-line require-await
13
- return async (secretId: string, fn: SecretToPromiseFunction<Secret, Response>) => {
14
- return fn(secret);
15
- };
16
- }
17
-
18
- export function createEmptySecretFunction<Response>(): EmptySecretFunction<Response> {
19
- // eslint-disable-next-line require-await
20
- return async (secretId: string, fn: SecretToPromiseFunction<DbSecret, Response>) => {
21
- return fn(EMPTY_DB_SECRET);
22
- };
23
- }