@digitraffic/common 2026.3.17-1 → 2026.3.26-1-beta
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.
- package/README.md +18 -1
- package/dist/__test__/asserter.d.ts +13 -0
- package/dist/__test__/asserter.js +39 -0
- package/dist/__test__/db-testutils.d.ts +3 -0
- package/dist/__test__/db-testutils.js +38 -0
- package/dist/__test__/dependencies.test.d.ts +1 -0
- package/dist/__test__/dependencies.test.js +21 -0
- package/dist/__test__/imports.test.d.ts +1 -0
- package/dist/__test__/imports.test.js +318 -0
- package/dist/__test__/infra/acl-builder.test.d.ts +1 -0
- package/dist/__test__/infra/acl-builder.test.js +72 -0
- package/dist/__test__/infra/api/handler-factory.test.d.ts +1 -0
- package/dist/__test__/infra/api/handler-factory.test.js +42 -0
- package/dist/__test__/infra/api/integration.test.d.ts +1 -0
- package/dist/__test__/infra/api/integration.test.js +162 -0
- package/dist/__test__/infra/api/response.test.d.ts +1 -0
- package/dist/__test__/infra/api/response.test.js +77 -0
- package/dist/__test__/infra/api/static-integration.test.d.ts +1 -0
- package/dist/__test__/infra/api/static-integration.test.js +35 -0
- package/dist/__test__/infra/documentation.test.d.ts +1 -0
- package/dist/__test__/infra/documentation.test.js +38 -0
- package/dist/__test__/infra/scheduler.test.d.ts +1 -0
- package/dist/__test__/infra/scheduler.test.js +23 -0
- package/dist/__test__/infra/security-rule.test.d.ts +1 -0
- package/dist/__test__/infra/security-rule.test.js +21 -0
- package/dist/__test__/infra/stack/rest-apis.test.d.ts +1 -0
- package/dist/__test__/infra/stack/rest-apis.test.js +47 -0
- package/dist/__test__/marine/id_utils.test.d.ts +1 -0
- package/dist/__test__/marine/id_utils.test.js +45 -0
- package/dist/__test__/mock-ky.d.ts +2 -0
- package/dist/__test__/mock-ky.js +15 -0
- package/dist/__test__/promise/promise.test.d.ts +1 -0
- package/dist/__test__/promise/promise.test.js +126 -0
- package/dist/__test__/runtime/dt-logger.test.d.ts +1 -0
- package/dist/__test__/runtime/dt-logger.test.js +193 -0
- package/dist/__test__/secrets/secret-holder.test.d.ts +1 -0
- package/dist/__test__/secrets/secret-holder.test.js +96 -0
- package/dist/__test__/secrets/secret.test.d.ts +1 -0
- package/dist/__test__/secrets/secret.test.js +57 -0
- package/dist/__test__/stack/dt-function.test.d.ts +1 -0
- package/dist/__test__/stack/dt-function.test.js +340 -0
- package/dist/__test__/stack/rest-apis.test.d.ts +1 -0
- package/dist/__test__/stack/rest-apis.test.js +45 -0
- package/dist/__test__/test/mock-ky.test.d.ts +1 -0
- package/dist/__test__/test/mock-ky.test.js +46 -0
- package/dist/__test__/testutils.d.ts +12 -0
- package/dist/__test__/testutils.js +32 -0
- package/dist/__test__/types/lambda-proxy-types.test.d.ts +8 -0
- package/dist/__test__/types/lambda-proxy-types.test.js +155 -0
- package/dist/__test__/types/lambda-response-builder.test.d.ts +1 -0
- package/dist/__test__/types/lambda-response-builder.test.js +81 -0
- package/dist/__test__/types/lambda-response.test.d.ts +9 -0
- package/dist/__test__/types/lambda-response.test.js +73 -0
- package/dist/__test__/utils/base64.test.d.ts +1 -0
- package/dist/__test__/utils/base64.test.js +38 -0
- package/dist/__test__/utils/date-utils.test.d.ts +1 -0
- package/dist/__test__/utils/date-utils.test.js +32 -0
- package/dist/__test__/utils/geometry.test.d.ts +1 -0
- package/dist/__test__/utils/geometry.test.js +25 -0
- package/dist/__test__/utils/lambda-proxy-event.test.d.ts +1 -0
- package/dist/__test__/utils/lambda-proxy-event.test.js +45 -0
- package/dist/__test__/utils/logging.test.d.ts +1 -0
- package/dist/__test__/utils/logging.test.js +75 -0
- package/dist/__test__/utils/stop-watch.test.d.ts +1 -0
- package/dist/__test__/utils/stop-watch.test.js +118 -0
- package/dist/__test__/utils/utils.test.d.ts +1 -0
- package/dist/__test__/utils/utils.test.js +48 -0
- package/dist/aws/infra/acl-builder.d.ts +53 -0
- package/dist/aws/infra/acl-builder.js +407 -0
- package/dist/aws/infra/api/handler-factory.d.ts +22 -0
- package/dist/aws/infra/api/handler-factory.js +68 -0
- package/dist/aws/infra/api/integration.d.ts +49 -0
- package/dist/aws/infra/api/integration.js +162 -0
- package/dist/aws/infra/api/response.d.ts +62 -0
- package/dist/aws/infra/api/response.js +132 -0
- package/dist/aws/infra/api/responses.d.ts +60 -0
- package/dist/aws/infra/api/responses.js +90 -0
- package/dist/aws/infra/api/static-integration.d.ts +16 -0
- package/dist/aws/infra/api/static-integration.js +76 -0
- package/dist/aws/infra/bucket-policy.d.ts +38 -0
- package/dist/aws/infra/bucket-policy.js +30 -0
- package/dist/aws/infra/canaries/canary-alarm.d.ts +6 -0
- package/dist/aws/infra/canaries/canary-alarm.js +20 -0
- package/dist/aws/infra/canaries/canary-keys.d.ts +3 -0
- package/dist/aws/infra/canaries/canary-keys.js +4 -0
- package/dist/aws/infra/canaries/canary-parameters.d.ts +19 -0
- package/dist/aws/infra/canaries/canary-parameters.js +2 -0
- package/dist/aws/infra/canaries/canary-role.d.ts +14 -0
- package/dist/aws/infra/canaries/canary-role.js +51 -0
- package/dist/aws/infra/canaries/canary.d.ts +8 -0
- package/dist/aws/infra/canaries/canary.js +26 -0
- package/dist/aws/infra/canaries/database-canary.d.ts +17 -0
- package/dist/aws/infra/canaries/database-canary.js +65 -0
- package/dist/aws/infra/canaries/database-checker.d.ts +33 -0
- package/dist/aws/infra/canaries/database-checker.js +119 -0
- package/dist/aws/infra/canaries/url-canary.d.ts +16 -0
- package/dist/aws/infra/canaries/url-canary.js +55 -0
- package/dist/aws/infra/canaries/url-checker.d.ts +45 -0
- package/dist/aws/infra/canaries/url-checker.js +256 -0
- package/dist/aws/infra/documentation.d.ts +56 -0
- package/dist/aws/infra/documentation.js +90 -0
- package/dist/aws/infra/import-util.d.ts +17 -0
- package/dist/aws/infra/import-util.js +41 -0
- package/dist/aws/infra/scheduler.d.ts +12 -0
- package/dist/aws/infra/scheduler.js +27 -0
- package/dist/aws/infra/security-rule.d.ts +12 -0
- package/dist/aws/infra/security-rule.js +35 -0
- package/dist/aws/infra/sqs-integration.d.ts +4 -0
- package/dist/aws/infra/sqs-integration.js +85 -0
- package/dist/aws/infra/sqs-queue.d.ts +19 -0
- package/dist/aws/infra/sqs-queue.js +145 -0
- package/dist/aws/infra/stack/dt-function-alarms.d.ts +29 -0
- package/dist/aws/infra/stack/dt-function-alarms.js +54 -0
- package/dist/aws/infra/stack/dt-function.d.ts +124 -0
- package/dist/aws/infra/stack/dt-function.js +315 -0
- package/dist/aws/infra/stack/lambda-configs.d.ts +44 -0
- package/dist/aws/infra/stack/lambda-configs.js +71 -0
- package/dist/aws/infra/stack/lambda-log-group.d.ts +15 -0
- package/dist/aws/infra/stack/lambda-log-group.js +24 -0
- package/dist/aws/infra/stack/monitoredfunction.d.ts +85 -0
- package/dist/aws/infra/stack/monitoredfunction.js +147 -0
- package/dist/aws/infra/stack/parameters.d.ts +40 -0
- package/dist/aws/infra/stack/parameters.js +50 -0
- package/dist/aws/infra/stack/rest-api.d.ts +74 -0
- package/dist/aws/infra/stack/rest-api.js +235 -0
- package/dist/aws/infra/stack/stack-checking-aspect.d.ts +20 -0
- package/dist/aws/infra/stack/stack-checking-aspect.js +183 -0
- package/dist/aws/infra/stack/stack.d.ts +56 -0
- package/dist/aws/infra/stack/stack.js +71 -0
- package/dist/aws/infra/stack/subscription.d.ts +17 -0
- package/dist/aws/infra/stack/subscription.js +37 -0
- package/dist/aws/infra/stacks/db-dns-stack.d.ts +13 -0
- package/dist/aws/infra/stacks/db-dns-stack.js +60 -0
- package/dist/aws/infra/stacks/db-proxy-stack.d.ts +24 -0
- package/dist/aws/infra/stacks/db-proxy-stack.js +74 -0
- package/dist/aws/infra/stacks/db-stack.d.ts +65 -0
- package/dist/aws/infra/stacks/db-stack.js +189 -0
- package/dist/aws/infra/stacks/intra-stack-configuration.d.ts +5 -0
- package/dist/aws/infra/stacks/intra-stack-configuration.js +2 -0
- package/dist/aws/infra/stacks/network-stack.d.ts +14 -0
- package/dist/aws/infra/stacks/network-stack.js +45 -0
- package/dist/aws/infra/usage-plans.d.ts +16 -0
- package/dist/aws/infra/usage-plans.js +38 -0
- package/dist/aws/runtime/apikey.d.ts +2 -0
- package/dist/aws/runtime/apikey.js +13 -0
- package/dist/aws/runtime/digitraffic-integration-response.d.ts +8 -0
- package/dist/aws/runtime/digitraffic-integration-response.js +25 -0
- package/dist/aws/runtime/dt-logger-default.d.ts +9 -0
- package/dist/aws/runtime/dt-logger-default.js +6 -0
- package/dist/aws/runtime/dt-logger.d.ts +117 -0
- package/dist/aws/runtime/dt-logger.js +159 -0
- package/dist/aws/runtime/environment.d.ts +5 -0
- package/dist/aws/runtime/environment.js +7 -0
- package/dist/aws/runtime/s3.d.ts +3 -0
- package/dist/aws/runtime/s3.js +21 -0
- package/dist/aws/runtime/secrets/dbsecret.d.ts +16 -0
- package/dist/aws/runtime/secrets/dbsecret.js +26 -0
- package/dist/aws/runtime/secrets/proxy-holder.d.ts +9 -0
- package/dist/aws/runtime/secrets/proxy-holder.js +25 -0
- package/dist/aws/runtime/secrets/rds-holder.d.ts +9 -0
- package/dist/aws/runtime/secrets/rds-holder.js +25 -0
- package/dist/aws/runtime/secrets/secret-holder.d.ts +30 -0
- package/dist/aws/runtime/secrets/secret-holder.js +81 -0
- package/dist/aws/runtime/secrets/secret.d.ts +8 -0
- package/dist/aws/runtime/secrets/secret.js +61 -0
- package/dist/aws/types/errors.d.ts +8 -0
- package/dist/aws/types/errors.js +13 -0
- package/dist/aws/types/lambda-proxy-types.d.ts +59 -0
- package/dist/aws/types/lambda-proxy-types.js +210 -0
- package/dist/aws/types/lambda-response.d.ts +89 -0
- package/dist/aws/types/lambda-response.js +204 -0
- package/dist/aws/types/mediatypes.d.ts +11 -0
- package/dist/aws/types/mediatypes.js +14 -0
- package/dist/aws/types/model-with-reference.d.ts +7 -0
- package/dist/aws/types/model-with-reference.js +2 -0
- package/dist/aws/types/tags.d.ts +2 -0
- package/dist/aws/types/tags.js +4 -0
- package/dist/database/database.d.ts +27 -0
- package/dist/database/database.js +95 -0
- package/dist/database/last-updated.d.ts +15 -0
- package/dist/database/last-updated.js +46 -0
- package/dist/database/models.d.ts +6 -0
- package/dist/database/models.js +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/marine/id_utils.d.ts +3 -0
- package/dist/marine/id_utils.js +36 -0
- package/dist/marine/rtz.d.ts +48 -0
- package/dist/marine/rtz.js +2 -0
- package/dist/types/async-timeout-error.d.ts +3 -0
- package/dist/types/async-timeout-error.js +6 -0
- package/dist/types/either.d.ts +9 -0
- package/dist/types/either.js +2 -0
- package/dist/types/geojson.d.ts +47 -0
- package/dist/types/geojson.js +51 -0
- package/dist/types/http-error.d.ts +4 -0
- package/dist/types/http-error.js +8 -0
- package/dist/types/input-error.d.ts +2 -0
- package/dist/types/input-error.js +3 -0
- package/dist/types/language.d.ts +5 -0
- package/dist/types/language.js +7 -0
- package/dist/types/nullable.d.ts +24 -0
- package/dist/types/nullable.js +2 -0
- package/dist/types/openapi-schema.d.ts +932 -0
- package/dist/types/openapi-schema.js +151 -0
- package/dist/types/traffictype.d.ts +11 -0
- package/dist/types/traffictype.js +13 -0
- package/dist/types/urn.d.ts +1 -0
- package/dist/types/urn.js +2 -0
- package/dist/types/util-types.d.ts +11 -0
- package/dist/types/util-types.js +2 -0
- package/dist/types/validator.d.ts +4 -0
- package/dist/types/validator.js +9 -0
- package/dist/utils/api-model.d.ts +51 -0
- package/dist/utils/api-model.js +118 -0
- package/dist/utils/base64.d.ts +34 -0
- package/dist/utils/base64.js +53 -0
- package/dist/utils/date-utils.d.ts +27 -0
- package/dist/utils/date-utils.js +45 -0
- package/dist/utils/geojson-types.d.ts +14 -0
- package/dist/utils/geojson-types.js +15 -0
- package/dist/utils/geometry.d.ts +44 -0
- package/dist/utils/geometry.js +154 -0
- package/dist/utils/lambda-proxy-event.d.ts +9 -0
- package/dist/utils/lambda-proxy-event.js +31 -0
- package/dist/utils/logging.d.ts +40 -0
- package/dist/utils/logging.js +88 -0
- package/dist/utils/retry.d.ts +33 -0
- package/dist/utils/retry.js +135 -0
- package/dist/utils/slack.d.ts +5 -0
- package/dist/utils/slack.js +24 -0
- package/dist/utils/stop-watch.d.ts +46 -0
- package/dist/utils/stop-watch.js +114 -0
- package/dist/utils/utils.d.ts +95 -0
- package/dist/utils/utils.js +178 -0
- package/dist/utils/zod-utils.d.ts +27 -0
- package/dist/utils/zod-utils.js +57 -0
- package/package.json +30 -28
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { Alarm, ComparisonOperator } from "aws-cdk-lib/aws-cloudwatch";
|
|
2
|
+
import { SnsAction } from "aws-cdk-lib/aws-cloudwatch-actions";
|
|
3
|
+
import { Topic } from "aws-cdk-lib/aws-sns";
|
|
4
|
+
export class CanaryAlarm {
|
|
5
|
+
constructor(stack, canary, params) {
|
|
6
|
+
const alarmName = params.alarm?.alarmName ?? `${params.name}-alarm`;
|
|
7
|
+
const alarm = new Alarm(stack, alarmName, {
|
|
8
|
+
alarmName,
|
|
9
|
+
alarmDescription: params.alarm?.description ?? "",
|
|
10
|
+
metric: canary.metricSuccessPercent(),
|
|
11
|
+
evaluationPeriods: params.alarm?.evalutionPeriods ?? 1,
|
|
12
|
+
threshold: params.alarm?.threshold ?? 100,
|
|
13
|
+
comparisonOperator: ComparisonOperator.LESS_THAN_THRESHOLD,
|
|
14
|
+
});
|
|
15
|
+
if (params.alarm?.topicArn) {
|
|
16
|
+
alarm.addAlarmAction(new SnsAction(Topic.fromTopicArn(stack, `${alarmName}-action`, params.alarm.topicArn)));
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=canary-alarm.js.map
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { Runtime, Schedule } from "aws-cdk-lib/aws-synthetics";
|
|
2
|
+
/** Optional env parameters for canary */
|
|
3
|
+
type CanaryEnv = Record<string, string>;
|
|
4
|
+
export interface CanaryParameters {
|
|
5
|
+
readonly name: string;
|
|
6
|
+
readonly schedule?: Schedule;
|
|
7
|
+
readonly secret?: string;
|
|
8
|
+
readonly handler: string;
|
|
9
|
+
readonly alarm?: {
|
|
10
|
+
readonly alarmName?: string;
|
|
11
|
+
readonly description?: string;
|
|
12
|
+
readonly evalutionPeriods?: number;
|
|
13
|
+
readonly threshold?: number;
|
|
14
|
+
readonly topicArn?: string;
|
|
15
|
+
};
|
|
16
|
+
readonly canaryEnv?: CanaryEnv;
|
|
17
|
+
readonly runtime?: Runtime;
|
|
18
|
+
}
|
|
19
|
+
export {};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { Role } from "aws-cdk-lib/aws-iam";
|
|
2
|
+
import type { Construct } from "constructs";
|
|
3
|
+
export declare class DigitrafficCanaryRole extends Role {
|
|
4
|
+
constructor(stack: Construct, canaryName: string);
|
|
5
|
+
/**
|
|
6
|
+
* Provides permissions to access resources within a VPC.
|
|
7
|
+
*/
|
|
8
|
+
withDatabaseAccess(): this;
|
|
9
|
+
/**
|
|
10
|
+
* Same as withDatabaseAccess() - renamed to avoid confusion if used with UrlCanary.
|
|
11
|
+
* A UrlCanary needs these permissions to e.g. access a private API Gateway endpoint in a VPC.
|
|
12
|
+
*/
|
|
13
|
+
withVpcAccess(): this;
|
|
14
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { ManagedPolicy, PolicyStatement, Role, ServicePrincipal, } from "aws-cdk-lib/aws-iam";
|
|
2
|
+
const BASE_POLICY_STATEMENT_PROPS = {
|
|
3
|
+
actions: [
|
|
4
|
+
"logs:CreateLogStream",
|
|
5
|
+
"logs:PutLogEvents",
|
|
6
|
+
"logs:CreateLogGroup",
|
|
7
|
+
"logs:DescribeLogGroups",
|
|
8
|
+
"logs:DescribeLogStreams",
|
|
9
|
+
],
|
|
10
|
+
resources: ["*"],
|
|
11
|
+
};
|
|
12
|
+
const CLOUDWATCH_STATEMENT_PROPS = {
|
|
13
|
+
actions: ["cloudwatch:PutMetricData"],
|
|
14
|
+
resources: ["*"],
|
|
15
|
+
conditions: {
|
|
16
|
+
StringEquals: {
|
|
17
|
+
"cloudwatch:namespace": "CloudWatchSynthetics",
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
};
|
|
21
|
+
export class DigitrafficCanaryRole extends Role {
|
|
22
|
+
constructor(stack, canaryName) {
|
|
23
|
+
super(stack, `canary-role-${canaryName}`, {
|
|
24
|
+
assumedBy: new ServicePrincipal("lambda.amazonaws.com"),
|
|
25
|
+
managedPolicies: [
|
|
26
|
+
ManagedPolicy.fromAwsManagedPolicyName("CloudWatchSyntheticsFullAccess"),
|
|
27
|
+
],
|
|
28
|
+
});
|
|
29
|
+
this.addToPolicy(new PolicyStatement(BASE_POLICY_STATEMENT_PROPS));
|
|
30
|
+
this.addToPolicy(new PolicyStatement(CLOUDWATCH_STATEMENT_PROPS));
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Provides permissions to access resources within a VPC.
|
|
34
|
+
*/
|
|
35
|
+
withDatabaseAccess() {
|
|
36
|
+
// Won't work :(
|
|
37
|
+
// this.addToPolicy(new PolicyStatement(DB_STATEMENT_PROPS));
|
|
38
|
+
// Works
|
|
39
|
+
this.addManagedPolicy(ManagedPolicy.fromAwsManagedPolicyName("service-role/AWSLambdaVPCAccessExecutionRole"));
|
|
40
|
+
return this;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Same as withDatabaseAccess() - renamed to avoid confusion if used with UrlCanary.
|
|
44
|
+
* A UrlCanary needs these permissions to e.g. access a private API Gateway endpoint in a VPC.
|
|
45
|
+
*/
|
|
46
|
+
withVpcAccess() {
|
|
47
|
+
this.addManagedPolicy(ManagedPolicy.fromAwsManagedPolicyName("service-role/AWSLambdaVPCAccessExecutionRole"));
|
|
48
|
+
return this;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=canary-role.js.map
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { Role } from "aws-cdk-lib/aws-iam";
|
|
2
|
+
import { Canary } from "aws-cdk-lib/aws-synthetics";
|
|
3
|
+
import type { Construct } from "constructs";
|
|
4
|
+
import type { LambdaEnvironment } from "../stack/lambda-configs.js";
|
|
5
|
+
import type { CanaryParameters } from "./canary-parameters.js";
|
|
6
|
+
export declare class DigitrafficCanary extends Canary {
|
|
7
|
+
constructor(scope: Construct, canaryName: string, role: Role, params: CanaryParameters, environmentVariables: LambdaEnvironment);
|
|
8
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { Duration } from "aws-cdk-lib";
|
|
2
|
+
import { AssetCode, Canary, Runtime, Schedule, Test, } from "aws-cdk-lib/aws-synthetics";
|
|
3
|
+
import { CanaryAlarm } from "./canary-alarm.js";
|
|
4
|
+
export class DigitrafficCanary extends Canary {
|
|
5
|
+
constructor(scope, canaryName, role, params, environmentVariables) {
|
|
6
|
+
super(scope, canaryName, {
|
|
7
|
+
runtime: params.runtime ?? Runtime.SYNTHETICS_NODEJS_PUPPETEER_13_0,
|
|
8
|
+
role,
|
|
9
|
+
test: Test.custom({
|
|
10
|
+
code: new AssetCode("dist", {
|
|
11
|
+
exclude: ["lambda", "out", "canaries"],
|
|
12
|
+
}),
|
|
13
|
+
handler: params.handler,
|
|
14
|
+
}),
|
|
15
|
+
environmentVariables: {
|
|
16
|
+
...environmentVariables,
|
|
17
|
+
...params.canaryEnv,
|
|
18
|
+
},
|
|
19
|
+
canaryName,
|
|
20
|
+
schedule: params.schedule ?? Schedule.rate(Duration.minutes(15)),
|
|
21
|
+
});
|
|
22
|
+
this.artifactsBucket.grantWrite(role);
|
|
23
|
+
new CanaryAlarm(scope, this, params);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=canary.js.map
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { Role } from "aws-cdk-lib/aws-iam";
|
|
2
|
+
import type { ISecret } from "aws-cdk-lib/aws-secretsmanager";
|
|
3
|
+
import type { DigitrafficStack } from "../stack/stack.js";
|
|
4
|
+
import { DigitrafficCanary } from "./canary.js";
|
|
5
|
+
import type { CanaryParameters } from "./canary-parameters.js";
|
|
6
|
+
export declare class DatabaseCanary extends DigitrafficCanary {
|
|
7
|
+
constructor(stack: DigitrafficStack, role: Role, secret: ISecret, params: CanaryParameters);
|
|
8
|
+
static create(stack: DigitrafficStack, role: Role, params: CanaryParameters): DatabaseCanary;
|
|
9
|
+
/**
|
|
10
|
+
* @param stack
|
|
11
|
+
* @param role
|
|
12
|
+
* @param name name of the typescipt file without -db -suffix. Max len is 10 char if @param canaryName is not given.
|
|
13
|
+
* @param params
|
|
14
|
+
* @param canaryName Optional name for canary if multiple canaries is made from same ${name}-db.ts canary file.
|
|
15
|
+
*/
|
|
16
|
+
static createV2(stack: DigitrafficStack, role: Role, name: string, params?: Partial<CanaryParameters>, canaryName?: string): DatabaseCanary;
|
|
17
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { Duration } from "aws-cdk-lib";
|
|
2
|
+
import { Schedule } from "aws-cdk-lib/aws-events";
|
|
3
|
+
import { CfnCanary } from "aws-cdk-lib/aws-synthetics";
|
|
4
|
+
import { DigitrafficCanary } from "./canary.js";
|
|
5
|
+
export class DatabaseCanary extends DigitrafficCanary {
|
|
6
|
+
constructor(stack, role, secret, params) {
|
|
7
|
+
const canaryName = `${params.name}-db`;
|
|
8
|
+
const environmentVariables = stack.createDefaultLambdaEnvironment(`Synthetics-${canaryName}`);
|
|
9
|
+
// the handler code is defined at the actual project using this
|
|
10
|
+
super(stack, canaryName, role, params, environmentVariables);
|
|
11
|
+
this.artifactsBucket.grantWrite(this.role);
|
|
12
|
+
secret.grantRead(this.role);
|
|
13
|
+
// need to override vpc and security group, can't do this with cdk
|
|
14
|
+
if (this.node.defaultChild instanceof CfnCanary) {
|
|
15
|
+
const subnetIds = stack.vpc === undefined
|
|
16
|
+
? []
|
|
17
|
+
: stack.vpc.privateSubnets.map((subnet) => subnet.subnetId);
|
|
18
|
+
const securityGroupIds = stack.lambdaDbSg === undefined
|
|
19
|
+
? []
|
|
20
|
+
: [stack.lambdaDbSg.securityGroupId];
|
|
21
|
+
this.node.defaultChild.vpcConfig = {
|
|
22
|
+
vpcId: stack.vpc?.vpcId,
|
|
23
|
+
securityGroupIds,
|
|
24
|
+
subnetIds,
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
static create(stack, role, params) {
|
|
29
|
+
const secret = stack.getSecret();
|
|
30
|
+
return new DatabaseCanary(stack, role, secret, {
|
|
31
|
+
...{
|
|
32
|
+
secret: stack.configuration.secretId,
|
|
33
|
+
schedule: Schedule.rate(Duration.hours(1)),
|
|
34
|
+
handler: `${params.name}.handler`,
|
|
35
|
+
},
|
|
36
|
+
...params,
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* @param stack
|
|
41
|
+
* @param role
|
|
42
|
+
* @param name name of the typescipt file without -db -suffix. Max len is 10 char if @param canaryName is not given.
|
|
43
|
+
* @param params
|
|
44
|
+
* @param canaryName Optional name for canary if multiple canaries is made from same ${name}-db.ts canary file.
|
|
45
|
+
*/
|
|
46
|
+
static createV2(stack, role, name, params = {}, canaryName = name) {
|
|
47
|
+
const secret = stack.getSecret();
|
|
48
|
+
return new DatabaseCanary(stack, role, secret, {
|
|
49
|
+
...{
|
|
50
|
+
secret: stack.configuration.secretId,
|
|
51
|
+
schedule: Schedule.rate(Duration.hours(1)),
|
|
52
|
+
handler: `${name}-db.handler`,
|
|
53
|
+
name: canaryName,
|
|
54
|
+
alarm: {
|
|
55
|
+
alarmName: canaryName === name
|
|
56
|
+
? `${stack.configuration.shortName}-DB-Alarm`
|
|
57
|
+
: `${canaryName}-DB-Alarm`,
|
|
58
|
+
topicArn: stack.configuration.alarmTopicArn,
|
|
59
|
+
},
|
|
60
|
+
},
|
|
61
|
+
...params,
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
//# sourceMappingURL=database-canary.js.map
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { Countable } from "../../../database/models.js";
|
|
2
|
+
declare abstract class DatabaseCheck<T> {
|
|
3
|
+
readonly name: string;
|
|
4
|
+
readonly sql: string;
|
|
5
|
+
failed: boolean;
|
|
6
|
+
protected constructor(name: string, sql: string);
|
|
7
|
+
abstract check(value: T): void;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Checker for sql that checks the count. Meaning that the
|
|
11
|
+
* sql must be structured as "select count(*) from <table> where <something>".
|
|
12
|
+
*/
|
|
13
|
+
export declare class DatabaseCountChecker {
|
|
14
|
+
readonly credentialsFunction: () => Promise<void>;
|
|
15
|
+
readonly checks: DatabaseCheck<Countable>[];
|
|
16
|
+
private constructor();
|
|
17
|
+
static createForProxy(): DatabaseCountChecker;
|
|
18
|
+
static createForRds(): DatabaseCountChecker;
|
|
19
|
+
/**
|
|
20
|
+
* Expect that the count is 1
|
|
21
|
+
*/
|
|
22
|
+
expectOne(name: string, sql: string): DatabaseCountChecker;
|
|
23
|
+
/**
|
|
24
|
+
* Expect that the count is 0
|
|
25
|
+
*/
|
|
26
|
+
expectZero(name: string, sql: string): DatabaseCountChecker;
|
|
27
|
+
/**
|
|
28
|
+
* Expect that the count is 1 or more
|
|
29
|
+
*/
|
|
30
|
+
expectOneOrMore(name: string, sql: string): DatabaseCountChecker;
|
|
31
|
+
expect(): Promise<"OK">;
|
|
32
|
+
}
|
|
33
|
+
export {};
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import synthetics from "Synthetics";
|
|
2
|
+
import { inDatabaseReadonly } from "../../../database/database.js";
|
|
3
|
+
import { getEnvVariable } from "../../../utils/utils.js";
|
|
4
|
+
import { logger } from "../../runtime/dt-logger-default.js";
|
|
5
|
+
import { ProxyHolder } from "../../runtime/secrets/proxy-holder.js";
|
|
6
|
+
import { RdsHolder } from "../../runtime/secrets/rds-holder.js";
|
|
7
|
+
class DatabaseCheck {
|
|
8
|
+
name;
|
|
9
|
+
sql;
|
|
10
|
+
failed;
|
|
11
|
+
constructor(name, sql) {
|
|
12
|
+
this.name = name;
|
|
13
|
+
this.sql = sql;
|
|
14
|
+
this.failed = false;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
class CountDatabaseCheck extends DatabaseCheck {
|
|
18
|
+
minCount;
|
|
19
|
+
maxCount;
|
|
20
|
+
constructor(name, sql, minCount, maxCount) {
|
|
21
|
+
super(name, sql);
|
|
22
|
+
if (!sql.toLowerCase().includes("select") ||
|
|
23
|
+
!sql.toLowerCase().includes("count")) {
|
|
24
|
+
throw new Error("sql must contain select count(*)");
|
|
25
|
+
}
|
|
26
|
+
if ((minCount === null || minCount === undefined) &&
|
|
27
|
+
(maxCount === null || maxCount === undefined)) {
|
|
28
|
+
throw new Error("no max or min given");
|
|
29
|
+
}
|
|
30
|
+
this.minCount = minCount;
|
|
31
|
+
this.maxCount = maxCount;
|
|
32
|
+
}
|
|
33
|
+
check(value) {
|
|
34
|
+
if ("count" in value) {
|
|
35
|
+
if (this.minCount && value.count < this.minCount) {
|
|
36
|
+
this.failed = true;
|
|
37
|
+
throw new Error(`count was ${value.count}, minimum is ${this.minCount}`);
|
|
38
|
+
}
|
|
39
|
+
if (this.maxCount && value.count > this.maxCount) {
|
|
40
|
+
this.failed = true;
|
|
41
|
+
throw new Error(`count was ${value.count}, max is ${this.maxCount}`);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
this.failed = true;
|
|
46
|
+
throw new Error("no count available");
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
const stepConfig = {
|
|
51
|
+
continueOnStepFailure: true,
|
|
52
|
+
screenshotOnStepStart: false,
|
|
53
|
+
screenshotOnStepSuccess: false,
|
|
54
|
+
screenshotOnStepFailure: false,
|
|
55
|
+
};
|
|
56
|
+
/**
|
|
57
|
+
* Checker for sql that checks the count. Meaning that the
|
|
58
|
+
* sql must be structured as "select count(*) from <table> where <something>".
|
|
59
|
+
*/
|
|
60
|
+
export class DatabaseCountChecker {
|
|
61
|
+
credentialsFunction;
|
|
62
|
+
checks = [];
|
|
63
|
+
constructor(credentialsFunction) {
|
|
64
|
+
this.credentialsFunction = credentialsFunction;
|
|
65
|
+
synthetics.getConfiguration().disableRequestMetrics();
|
|
66
|
+
synthetics.getConfiguration().withFailedCanaryMetric(true);
|
|
67
|
+
}
|
|
68
|
+
static createForProxy() {
|
|
69
|
+
return new DatabaseCountChecker(() => new ProxyHolder(getEnvVariable("SECRET_ID")).setCredentials());
|
|
70
|
+
}
|
|
71
|
+
static createForRds() {
|
|
72
|
+
return new DatabaseCountChecker(() => new RdsHolder(getEnvVariable("SECRET_ID")).setCredentials());
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Expect that the count is 1
|
|
76
|
+
*/
|
|
77
|
+
expectOne(name, sql) {
|
|
78
|
+
this.checks.push(new CountDatabaseCheck(name, sql, 1, 1));
|
|
79
|
+
return this;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Expect that the count is 0
|
|
83
|
+
*/
|
|
84
|
+
expectZero(name, sql) {
|
|
85
|
+
this.checks.push(new CountDatabaseCheck(name, sql, null, 0));
|
|
86
|
+
return this;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Expect that the count is 1 or more
|
|
90
|
+
*/
|
|
91
|
+
expectOneOrMore(name, sql) {
|
|
92
|
+
this.checks.push(new CountDatabaseCheck(name, sql, 1, null));
|
|
93
|
+
return this;
|
|
94
|
+
}
|
|
95
|
+
async expect() {
|
|
96
|
+
if (!this.checks.length) {
|
|
97
|
+
throw new Error("No checks");
|
|
98
|
+
}
|
|
99
|
+
await this.credentialsFunction();
|
|
100
|
+
await inDatabaseReadonly(async (db) => {
|
|
101
|
+
for (const check of this.checks) {
|
|
102
|
+
logger.info({
|
|
103
|
+
method: "DatabaseCountChecker.expect",
|
|
104
|
+
message: `Running sql: ${check.sql}`,
|
|
105
|
+
});
|
|
106
|
+
const value = await db.one(check.sql);
|
|
107
|
+
const checkFunction = () => {
|
|
108
|
+
check.check(value);
|
|
109
|
+
};
|
|
110
|
+
synthetics.executeStep(check.name, checkFunction, stepConfig);
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
if (this.checks.some((check) => check.failed)) {
|
|
114
|
+
throw new Error("Failed");
|
|
115
|
+
}
|
|
116
|
+
return "OK";
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
//# sourceMappingURL=database-checker.js.map
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { Role } from "aws-cdk-lib/aws-iam";
|
|
2
|
+
import type { ISecret } from "aws-cdk-lib/aws-secretsmanager";
|
|
3
|
+
import type { DigitrafficRestApi } from "../stack/rest-api.js";
|
|
4
|
+
import type { DigitrafficStack } from "../stack/stack.js";
|
|
5
|
+
import { DigitrafficCanary } from "./canary.js";
|
|
6
|
+
import type { CanaryParameters } from "./canary-parameters.js";
|
|
7
|
+
export interface UrlCanaryParameters extends CanaryParameters {
|
|
8
|
+
readonly hostname: string;
|
|
9
|
+
readonly apiKeyId: string;
|
|
10
|
+
readonly inVpc?: boolean;
|
|
11
|
+
}
|
|
12
|
+
export declare class UrlCanary extends DigitrafficCanary {
|
|
13
|
+
constructor(stack: DigitrafficStack, role: Role, params: UrlCanaryParameters, secret?: ISecret);
|
|
14
|
+
static create(stack: DigitrafficStack, role: Role, publicApi: DigitrafficRestApi, params: Partial<UrlCanaryParameters>, secret?: ISecret): UrlCanary;
|
|
15
|
+
static getApiKey(publicApi: DigitrafficRestApi): string | undefined;
|
|
16
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { CfnCanary } from "aws-cdk-lib/aws-synthetics";
|
|
2
|
+
import { DigitrafficCanary } from "./canary.js";
|
|
3
|
+
import { ENV_API_KEY, ENV_HOSTNAME, ENV_SECRET } from "./canary-keys.js";
|
|
4
|
+
export class UrlCanary extends DigitrafficCanary {
|
|
5
|
+
constructor(stack, role, params, secret) {
|
|
6
|
+
const canaryName = `${params.name}-url`;
|
|
7
|
+
const environmentVariables = {};
|
|
8
|
+
environmentVariables[ENV_HOSTNAME] = params.hostname;
|
|
9
|
+
if (params.secret) {
|
|
10
|
+
environmentVariables[ENV_SECRET] = params.secret;
|
|
11
|
+
}
|
|
12
|
+
if (params.apiKeyId) {
|
|
13
|
+
environmentVariables[ENV_API_KEY] = params.apiKeyId;
|
|
14
|
+
}
|
|
15
|
+
if (secret) {
|
|
16
|
+
secret.grantRead(role);
|
|
17
|
+
}
|
|
18
|
+
// the handler code is defined at the actual project using this
|
|
19
|
+
super(stack, canaryName, role, params, environmentVariables);
|
|
20
|
+
if (params.inVpc && this.node.defaultChild instanceof CfnCanary) {
|
|
21
|
+
const subnetIds = stack.vpc === undefined
|
|
22
|
+
? []
|
|
23
|
+
: stack.vpc.privateSubnets.map((subnet) => subnet.subnetId);
|
|
24
|
+
const securityGroupIds = stack.lambdaDbSg === undefined
|
|
25
|
+
? []
|
|
26
|
+
: [stack.lambdaDbSg.securityGroupId];
|
|
27
|
+
this.node.defaultChild.vpcConfig = {
|
|
28
|
+
vpcId: stack.vpc?.vpcId,
|
|
29
|
+
securityGroupIds,
|
|
30
|
+
subnetIds,
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
static create(stack, role, publicApi, params, secret) {
|
|
35
|
+
return new UrlCanary(stack, role, {
|
|
36
|
+
handler: `${params.name ?? undefined}.handler`,
|
|
37
|
+
hostname: publicApi.hostname(),
|
|
38
|
+
apiKeyId: UrlCanary.getApiKey(publicApi),
|
|
39
|
+
...params,
|
|
40
|
+
}, secret);
|
|
41
|
+
}
|
|
42
|
+
static getApiKey(publicApi) {
|
|
43
|
+
const apiKeys = publicApi.apiKeyIds;
|
|
44
|
+
if (apiKeys.length > 1) {
|
|
45
|
+
console.info("rest api has more than one api key");
|
|
46
|
+
}
|
|
47
|
+
if (apiKeys.length === 0) {
|
|
48
|
+
console.info("rest api has no api keys");
|
|
49
|
+
return undefined;
|
|
50
|
+
}
|
|
51
|
+
// always use first api key
|
|
52
|
+
return publicApi.apiKeyIds[0];
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=url-canary.js.map
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type { IncomingMessage } from "node:http";
|
|
2
|
+
import type { FeatureCollection } from "geojson";
|
|
3
|
+
import { MediaType } from "../../types/mediatypes.js";
|
|
4
|
+
export declare const API_KEY_HEADER = "x-api-key";
|
|
5
|
+
type CheckerFunction = (Res: IncomingMessage) => Promise<void>;
|
|
6
|
+
type JsonCheckerFunction<T> = (json: T, body: string, message: IncomingMessage) => Promise<void>;
|
|
7
|
+
export declare class UrlChecker {
|
|
8
|
+
private readonly requestOptions;
|
|
9
|
+
constructor(hostname: string, apiKey?: string);
|
|
10
|
+
static create(hostname: string, apiKeyId: string): Promise<UrlChecker>;
|
|
11
|
+
static createV2(): Promise<UrlChecker>;
|
|
12
|
+
expectStatus<T>(statusCode: number, url: string, callback: JsonCheckerFunction<T>): Promise<void>;
|
|
13
|
+
expect200<T>(url: string, ...callbacks: JsonCheckerFunction<T>[]): Promise<void>;
|
|
14
|
+
expect404(url: string): Promise<void>;
|
|
15
|
+
expect400(url: string): Promise<void>;
|
|
16
|
+
expect403WithoutApiKey(url: string, mediaType?: MediaType): Promise<void>;
|
|
17
|
+
done(): string;
|
|
18
|
+
}
|
|
19
|
+
export declare class ResponseChecker {
|
|
20
|
+
private readonly contentType;
|
|
21
|
+
private checkCors;
|
|
22
|
+
constructor(contentType: string);
|
|
23
|
+
static forJson(): ResponseChecker;
|
|
24
|
+
static forCSV(): ResponseChecker;
|
|
25
|
+
static forGeojson(): ResponseChecker;
|
|
26
|
+
static forJpeg(): ResponseChecker;
|
|
27
|
+
check(): CheckerFunction;
|
|
28
|
+
checkJson<T>(fn: (json: T, body: string, res: IncomingMessage) => void): CheckerFunction;
|
|
29
|
+
responseChecker(fn: (body: string, res: IncomingMessage) => void): CheckerFunction;
|
|
30
|
+
}
|
|
31
|
+
export declare const ContentChecker: {
|
|
32
|
+
checkJson<T>(fn: (json: T, body: string, res: IncomingMessage) => void): CheckerFunction;
|
|
33
|
+
checkResponse(fn: (body: string, res: IncomingMessage) => void): CheckerFunction;
|
|
34
|
+
};
|
|
35
|
+
export declare const ContentTypeChecker: {
|
|
36
|
+
checkContentType(contentType: MediaType): CheckerFunction;
|
|
37
|
+
};
|
|
38
|
+
export declare const GeoJsonChecker: {
|
|
39
|
+
validFeatureCollection(fn?: (json: FeatureCollection) => void): CheckerFunction;
|
|
40
|
+
};
|
|
41
|
+
export declare const HeaderChecker: {
|
|
42
|
+
checkHeaderExists(headerName: string): CheckerFunction;
|
|
43
|
+
checkHeaderMissing(headerName: string): CheckerFunction;
|
|
44
|
+
};
|
|
45
|
+
export {};
|