From c8f10a1a19cd52b64ec6a9cf1a622a98d7dadd97 Mon Sep 17 00:00:00 2001 From: Eoin Shanaghy Date: Fri, 1 Dec 2023 15:04:05 +0000 Subject: [PATCH 01/35] chore: use real serverless.yml in snapshot tests --- ...rverless-test-project-alb-snapshot.test.ts | 7 +- ...less-test-project-appsync-snapshot.test.ts | 6 +- .../serverless-test-project-snapshot.test.ts | 6 +- ...test-project-alb-snapshot.test.ts.test.cjs | 150 ++ ...ess-test-project-snapshot.test.ts.test.cjs | 1361 +++++++++++++++-- test-utils/sls-test-utils.ts | 6 +- 6 files changed, 1437 insertions(+), 99 deletions(-) diff --git a/serverless-test-project-alb/tests/snapshot/serverless-test-project-alb-snapshot.test.ts b/serverless-test-project-alb/tests/snapshot/serverless-test-project-alb-snapshot.test.ts index d367a71e..fb9b2872 100644 --- a/serverless-test-project-alb/tests/snapshot/serverless-test-project-alb-snapshot.test.ts +++ b/serverless-test-project-alb/tests/snapshot/serverless-test-project-alb-snapshot.test.ts @@ -1,6 +1,10 @@ import { test } from 'tap' +import path from 'node:path' +import { readFileSync } from 'node:fs' import { type Template } from 'cloudform-types' +import { parse } from 'yaml' + import ServerlessPlugin from 'serverless-slic-watch-plugin/serverless-plugin' import inputTemplate from './fixtures/cloudformation-template-update-stack.json' @@ -13,7 +17,8 @@ const pluginUtils = { log: logger } test('the plugin adds SLIC Watch dashboards and alarms to a serverless-generated CloudFormation template with ALB resources', (t) => { setUpSnapshotDefaults(t) - const mockServerless = createMockServerless(inputTemplate as Template) + const slsConfig = readFileSync(path.join(__dirname, '..', '..', 'serverless.yml')).toString() + const mockServerless = createMockServerless(inputTemplate as Template, parse(slsConfig)) const plugin = new ServerlessPlugin(mockServerless, null, pluginUtils) plugin.createSlicWatchResources() const generatedTemplate = mockServerless.service.provider.compiledCloudFormationTemplate diff --git a/serverless-test-project-appsync/tests/snapshot/serverless-test-project-appsync-snapshot.test.ts b/serverless-test-project-appsync/tests/snapshot/serverless-test-project-appsync-snapshot.test.ts index 832d6f00..01227dc1 100644 --- a/serverless-test-project-appsync/tests/snapshot/serverless-test-project-appsync-snapshot.test.ts +++ b/serverless-test-project-appsync/tests/snapshot/serverless-test-project-appsync-snapshot.test.ts @@ -1,4 +1,7 @@ import { test } from 'tap' +import path from 'node:path' +import { readFileSync } from 'node:fs' +import { parse } from 'yaml' import { type Template } from 'cloudform-types' import ServerlessPlugin from 'serverless-slic-watch-plugin/serverless-plugin' @@ -13,7 +16,8 @@ const pluginUtils = { log: logger } test('the plugin adds SLIC Watch dashboards and alarms to a serverless-generated CloudFormation template with AppSync resources', (t) => { setUpSnapshotDefaults(t) - const mockServerless = createMockServerless(inputTemplate as unknown as Template) + const slsConfig = readFileSync(path.join(__dirname, '..', '..', 'serverless.yml')).toString() + const mockServerless = createMockServerless(inputTemplate as unknown as Template, parse(slsConfig)) const plugin = new ServerlessPlugin(mockServerless, null, pluginUtils) plugin.createSlicWatchResources() const generatedTemplate = mockServerless.service.provider.compiledCloudFormationTemplate diff --git a/serverless-test-project/tests/snapshot/serverless-test-project-snapshot.test.ts b/serverless-test-project/tests/snapshot/serverless-test-project-snapshot.test.ts index 1f78568d..37666701 100644 --- a/serverless-test-project/tests/snapshot/serverless-test-project-snapshot.test.ts +++ b/serverless-test-project/tests/snapshot/serverless-test-project-snapshot.test.ts @@ -1,4 +1,7 @@ import { test } from 'tap' +import path from 'node:path' +import { readFileSync } from 'node:fs' +import { parse } from 'yaml' import { type Template } from 'cloudform-types' import ServerlessPlugin from 'serverless-slic-watch-plugin/serverless-plugin' @@ -13,7 +16,8 @@ const pluginUtils = { log: logger } test('the plugin adds SLIC Watch dashboards and alarms to a serverless-generated CloudFormation template', (t) => { setUpSnapshotDefaults(t) - const mockServerless = createMockServerless(inputTemplate as Template) + const slsConfig = readFileSync(path.join(__dirname, '..', '..', 'serverless.yml')).toString() + const mockServerless = createMockServerless(inputTemplate as Template, parse(slsConfig)) const plugin = new ServerlessPlugin(mockServerless, null, pluginUtils) plugin.createSlicWatchResources() const generatedTemplate = mockServerless.service.provider.compiledCloudFormationTemplate diff --git a/tap-snapshots/serverless-test-project-alb/tests/snapshot/serverless-test-project-alb-snapshot.test.ts.test.cjs b/tap-snapshots/serverless-test-project-alb/tests/snapshot/serverless-test-project-alb-snapshot.test.ts.test.cjs index 49b277fb..6ac1b7e9 100644 --- a/tap-snapshots/serverless-test-project-alb/tests/snapshot/serverless-test-project-alb-snapshot.test.ts.test.cjs +++ b/tap-snapshots/serverless-test-project-alb/tests/snapshot/serverless-test-project-alb-snapshot.test.ts.test.cjs @@ -767,6 +767,156 @@ exports[`serverless-test-project-alb/tests/snapshot/serverless-test-project-alb- }, "Type": "AWS::CloudWatch::Dashboard" }, + "slicWatchLambdaDurationAlarmAlbEventLambdaFunction": { + "Properties": { + "ActionsEnabled": true, + "AlarmActions": [ + "test-topic" + ], + "AlarmDescription": { + "Fn::Sub": [ + "Max duration for \${AlbEventLambdaFunction} breaches 95% of timeout (6)", + {} + ] + }, + "AlarmName": { + "Fn::Sub": [ + "Lambda_Duration_\${AlbEventLambdaFunction}", + {} + ] + }, + "ComparisonOperator": "GreaterThanThreshold", + "Dimensions": [ + { + "Name": "FunctionName", + "Value": { + "Ref": "AlbEventLambdaFunction" + } + } + ], + "EvaluationPeriods": 1, + "MetricName": "Duration", + "Namespace": "AWS/Lambda", + "OKActions": [], + "Period": 60, + "Statistic": "Maximum", + "Threshold": 5700, + "TreatMissingData": "notBreaching" + }, + "Type": "AWS::CloudWatch::Alarm" + }, + "slicWatchLambdaErrorsAlarmAlbEventLambdaFunction": { + "Properties": { + "ActionsEnabled": true, + "AlarmActions": [ + "test-topic" + ], + "AlarmDescription": { + "Fn::Sub": [ + "Error count for \${AlbEventLambdaFunction} breaches 0", + {} + ] + }, + "AlarmName": { + "Fn::Sub": [ + "Lambda_Errors_\${AlbEventLambdaFunction}", + {} + ] + }, + "ComparisonOperator": "GreaterThanThreshold", + "Dimensions": [ + { + "Name": "FunctionName", + "Value": { + "Ref": "AlbEventLambdaFunction" + } + } + ], + "EvaluationPeriods": 1, + "MetricName": "Errors", + "Namespace": "AWS/Lambda", + "OKActions": [], + "Period": 60, + "Statistic": "Sum", + "Threshold": 0, + "TreatMissingData": "notBreaching" + }, + "Type": "AWS::CloudWatch::Alarm" + }, + "slicWatchLambdaThrottlesAlarmAlbEventLambdaFunction": { + "Properties": { + "ActionsEnabled": true, + "AlarmActions": [ + "test-topic" + ], + "AlarmDescription": { + "Fn::Sub": [ + "Throttles % for \${AlbEventLambdaFunction} breaches 0", + {} + ] + }, + "AlarmName": { + "Fn::Sub": [ + "Lambda_Throttles_\${AlbEventLambdaFunction}", + {} + ] + }, + "ComparisonOperator": "GreaterThanThreshold", + "EvaluationPeriods": 1, + "Metrics": [ + { + "Id": "throttles_pc", + "Expression": "(throttles / ( throttles + invocations )) * 100", + "Label": "% Throttles", + "ReturnData": true + }, + { + "Id": "throttles", + "MetricStat": { + "Metric": { + "Namespace": "AWS/Lambda", + "MetricName": "Throttles", + "Dimensions": [ + { + "Name": "FunctionName", + "Value": { + "Ref": "AlbEventLambdaFunction" + } + } + ] + }, + "Period": 60, + "Stat": "Sum" + }, + "ReturnData": false + }, + { + "Id": "invocations", + "MetricStat": { + "Metric": { + "Namespace": "AWS/Lambda", + "MetricName": "Invocations", + "Dimensions": [ + { + "Name": "FunctionName", + "Value": { + "Ref": "AlbEventLambdaFunction" + } + } + ] + }, + "Period": 60, + "Stat": "Sum" + }, + "ReturnData": false + } + ], + "OKActions": [], + "Threshold": 0, + "TreatMissingData": "notBreaching" + }, + "Type": "AWS::CloudWatch::Alarm" + }, "slicWatchLoadBalancerHTTPCodeELB5XXCountAlarmAlb": { "Properties": { "ActionsEnabled": true, diff --git a/tap-snapshots/serverless-test-project/tests/snapshot/serverless-test-project-snapshot.test.ts.test.cjs b/tap-snapshots/serverless-test-project/tests/snapshot/serverless-test-project-snapshot.test.ts.test.cjs index f83a4b33..c9ed6ceb 100644 --- a/tap-snapshots/serverless-test-project/tests/snapshot/serverless-test-project-snapshot.test.ts.test.cjs +++ b/tap-snapshots/serverless-test-project/tests/snapshot/serverless-test-project-snapshot.test.ts.test.cjs @@ -1702,15 +1702,6 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "stat": "Sum" } ], - [ - "AWS/Lambda", - "Errors", - "FunctionName", - "\${PingLambdaFunction}", - { - "stat": "Sum" - } - ], [ "AWS/Lambda", "Errors", @@ -1807,15 +1798,6 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "stat": "Sum" } ], - [ - "AWS/Lambda", - "Throttles", - "FunctionName", - "\${PingLambdaFunction}", - { - "stat": "Sum" - } - ], [ "AWS/Lambda", "Throttles", @@ -1912,15 +1894,6 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "stat": "Average" } ], - [ - "AWS/Lambda", - "Duration", - "FunctionName", - "\${PingLambdaFunction}", - { - "stat": "Average" - } - ], [ "AWS/Lambda", "Duration", @@ -2017,15 +1990,6 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "stat": "p95" } ], - [ - "AWS/Lambda", - "Duration", - "FunctionName", - "\${PingLambdaFunction}", - { - "stat": "p95" - } - ], [ "AWS/Lambda", "Duration", @@ -2122,15 +2086,6 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "stat": "Maximum" } ], - [ - "AWS/Lambda", - "Duration", - "FunctionName", - "\${PingLambdaFunction}", - { - "stat": "Maximum" - } - ], [ "AWS/Lambda", "Duration", @@ -2227,15 +2182,6 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "stat": "Sum" } ], - [ - "AWS/Lambda", - "Invocations", - "FunctionName", - "\${PingLambdaFunction}", - { - "stat": "Sum" - } - ], [ "AWS/Lambda", "Invocations", @@ -2332,15 +2278,6 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "stat": "Maximum" } ], - [ - "AWS/Lambda", - "ConcurrentExecutions", - "FunctionName", - "\${PingLambdaFunction}", - { - "stat": "Maximum" - } - ], [ "AWS/Lambda", "ConcurrentExecutions", @@ -3327,6 +3264,120 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot }, "Type": "AWS::CloudWatch::Alarm" }, + "slicWatchLambdaDurationAlarmDriveQueueLambdaFunction": { + "Properties": { + "ActionsEnabled": true, + "AlarmActions": [ + "test-topic" + ], + "AlarmDescription": { + "Fn::Sub": [ + "Max duration for \${DriveQueueLambdaFunction} breaches 95% of timeout (6)", + {} + ] + }, + "AlarmName": { + "Fn::Sub": [ + "Lambda_Duration_\${DriveQueueLambdaFunction}", + {} + ] + }, + "ComparisonOperator": "GreaterThanThreshold", + "Dimensions": [ + { + "Name": "FunctionName", + "Value": { + "Ref": "DriveQueueLambdaFunction" + } + } + ], + "EvaluationPeriods": 1, + "MetricName": "Duration", + "Namespace": "AWS/Lambda", + "OKActions": [], + "Period": 60, + "Statistic": "Maximum", + "Threshold": 5700, + "TreatMissingData": "notBreaching" + }, + "Type": "AWS::CloudWatch::Alarm" + }, + "slicWatchLambdaDurationAlarmDriveStreamLambdaFunction": { + "Properties": { + "ActionsEnabled": true, + "AlarmActions": [ + "test-topic" + ], + "AlarmDescription": { + "Fn::Sub": [ + "Max duration for \${DriveStreamLambdaFunction} breaches 95% of timeout (6)", + {} + ] + }, + "AlarmName": { + "Fn::Sub": [ + "Lambda_Duration_\${DriveStreamLambdaFunction}", + {} + ] + }, + "ComparisonOperator": "GreaterThanThreshold", + "Dimensions": [ + { + "Name": "FunctionName", + "Value": { + "Ref": "DriveStreamLambdaFunction" + } + } + ], + "EvaluationPeriods": 1, + "MetricName": "Duration", + "Namespace": "AWS/Lambda", + "OKActions": [], + "Period": 60, + "Statistic": "Maximum", + "Threshold": 5700, + "TreatMissingData": "notBreaching" + }, + "Type": "AWS::CloudWatch::Alarm" + }, + "slicWatchLambdaDurationAlarmDriveTableLambdaFunction": { + "Properties": { + "ActionsEnabled": true, + "AlarmActions": [ + "test-topic" + ], + "AlarmDescription": { + "Fn::Sub": [ + "Max duration for \${DriveTableLambdaFunction} breaches 95% of timeout (6)", + {} + ] + }, + "AlarmName": { + "Fn::Sub": [ + "Lambda_Duration_\${DriveTableLambdaFunction}", + {} + ] + }, + "ComparisonOperator": "GreaterThanThreshold", + "Dimensions": [ + { + "Name": "FunctionName", + "Value": { + "Ref": "DriveTableLambdaFunction" + } + } + ], + "EvaluationPeriods": 1, + "MetricName": "Duration", + "Namespace": "AWS/Lambda", + "OKActions": [], + "Period": 60, + "Statistic": "Maximum", + "Threshold": 5700, + "TreatMissingData": "notBreaching" + }, + "Type": "AWS::CloudWatch::Alarm" + }, "slicWatchLambdaDurationAlarmHelloLambdaFunction": { "Properties": { "ActionsEnabled": true, @@ -3365,7 +3416,7 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot }, "Type": "AWS::CloudWatch::Alarm" }, - "slicWatchLambdaErrorsAlarmHelloLambdaFunction": { + "slicWatchLambdaDurationAlarmHttpGetterLambdaFunction": { "Properties": { "ActionsEnabled": true, "AlarmActions": [ @@ -3373,13 +3424,13 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot ], "AlarmDescription": { "Fn::Sub": [ - "Error count for \${HelloLambdaFunction} breaches 0", + "Max duration for \${HttpGetterLambdaFunction} breaches 95% of timeout (30)", {} ] }, "AlarmName": { "Fn::Sub": [ - "Lambda_Errors_\${HelloLambdaFunction}", + "Lambda_Duration_\${HttpGetterLambdaFunction}", {} ] }, @@ -3388,22 +3439,22 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot { "Name": "FunctionName", "Value": { - "Ref": "HelloLambdaFunction" + "Ref": "HttpGetterLambdaFunction" } } ], "EvaluationPeriods": 1, - "MetricName": "Errors", + "MetricName": "Duration", "Namespace": "AWS/Lambda", "OKActions": [], "Period": 60, - "Statistic": "Sum", - "Threshold": 0, + "Statistic": "Maximum", + "Threshold": 28500, "TreatMissingData": "notBreaching" }, "Type": "AWS::CloudWatch::Alarm" }, - "slicWatchLambdaThrottlesAlarmHelloLambdaFunction": { + "slicWatchLambdaDurationAlarmPingLambdaFunction": { "Properties": { "ActionsEnabled": true, "AlarmActions": [ @@ -3411,39 +3462,941 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot ], "AlarmDescription": { "Fn::Sub": [ - "Throttles % for \${HelloLambdaFunction} breaches 0", + "Max duration for \${PingLambdaFunction} breaches 95% of timeout (6)", {} ] }, "AlarmName": { "Fn::Sub": [ - "Lambda_Throttles_\${HelloLambdaFunction}", + "Lambda_Duration_\${PingLambdaFunction}", {} ] }, "ComparisonOperator": "GreaterThanThreshold", + "Dimensions": [ + { + "Name": "FunctionName", + "Value": { + "Ref": "PingLambdaFunction" + } + } + ], "EvaluationPeriods": 1, - "Metrics": [ + "MetricName": "Duration", + "Namespace": "AWS/Lambda", + "OKActions": [], + "Period": 60, + "Statistic": "Maximum", + "Threshold": 5700, + "TreatMissingData": "notBreaching" + }, + "Type": "AWS::CloudWatch::Alarm" + }, + "slicWatchLambdaDurationAlarmStreamProcessorLambdaFunction": { + "Properties": { + "ActionsEnabled": true, + "AlarmActions": [ + "test-topic" + ], + "AlarmDescription": { + "Fn::Sub": [ + "Max duration for \${StreamProcessorLambdaFunction} breaches 95% of timeout (6)", + {} + ] + }, + "AlarmName": { + "Fn::Sub": [ + "Lambda_Duration_\${StreamProcessorLambdaFunction}", + {} + ] + }, + "ComparisonOperator": "GreaterThanThreshold", + "Dimensions": [ { - "Id": "throttles_pc", - "Expression": "(throttles / ( throttles + invocations )) * 100", - "Label": "% Throttles", - "ReturnData": true - }, + "Name": "FunctionName", + "Value": { + "Ref": "StreamProcessorLambdaFunction" + } + } + ], + "EvaluationPeriods": 1, + "MetricName": "Duration", + "Namespace": "AWS/Lambda", + "OKActions": [], + "Period": 60, + "Statistic": "Maximum", + "Threshold": 5700, + "TreatMissingData": "notBreaching" + }, + "Type": "AWS::CloudWatch::Alarm" + }, + "slicWatchLambdaDurationAlarmSubscriptionHandlerLambdaFunction": { + "Properties": { + "ActionsEnabled": true, + "AlarmActions": [ + "test-topic" + ], + "AlarmDescription": { + "Fn::Sub": [ + "Max duration for \${SubscriptionHandlerLambdaFunction} breaches 95% of timeout (30)", + {} + ] + }, + "AlarmName": { + "Fn::Sub": [ + "Lambda_Duration_\${SubscriptionHandlerLambdaFunction}", + {} + ] + }, + "ComparisonOperator": "GreaterThanThreshold", + "Dimensions": [ { - "Id": "throttles", - "MetricStat": { - "Metric": { - "Namespace": "AWS/Lambda", - "MetricName": "Throttles", - "Dimensions": [ - { - "Name": "FunctionName", - "Value": { - "Ref": "HelloLambdaFunction" - } - } - ] + "Name": "FunctionName", + "Value": { + "Ref": "SubscriptionHandlerLambdaFunction" + } + } + ], + "EvaluationPeriods": 1, + "MetricName": "Duration", + "Namespace": "AWS/Lambda", + "OKActions": [], + "Period": 60, + "Statistic": "Maximum", + "Threshold": 28500, + "TreatMissingData": "notBreaching" + }, + "Type": "AWS::CloudWatch::Alarm" + }, + "slicWatchLambdaDurationAlarmThrottlerLambdaFunction": { + "Properties": { + "ActionsEnabled": true, + "AlarmActions": [ + "test-topic" + ], + "AlarmDescription": { + "Fn::Sub": [ + "Max duration for \${ThrottlerLambdaFunction} breaches 95% of timeout (6)", + {} + ] + }, + "AlarmName": { + "Fn::Sub": [ + "Lambda_Duration_\${ThrottlerLambdaFunction}", + {} + ] + }, + "ComparisonOperator": "GreaterThanThreshold", + "Dimensions": [ + { + "Name": "FunctionName", + "Value": { + "Ref": "ThrottlerLambdaFunction" + } + } + ], + "EvaluationPeriods": 1, + "MetricName": "Duration", + "Namespace": "AWS/Lambda", + "OKActions": [], + "Period": 60, + "Statistic": "Maximum", + "Threshold": 5700, + "TreatMissingData": "notBreaching" + }, + "Type": "AWS::CloudWatch::Alarm" + }, + "slicWatchLambdaErrorsAlarmDriveQueueLambdaFunction": { + "Properties": { + "ActionsEnabled": true, + "AlarmActions": [ + "test-topic" + ], + "AlarmDescription": { + "Fn::Sub": [ + "Error count for \${DriveQueueLambdaFunction} breaches 0", + {} + ] + }, + "AlarmName": { + "Fn::Sub": [ + "Lambda_Errors_\${DriveQueueLambdaFunction}", + {} + ] + }, + "ComparisonOperator": "GreaterThanThreshold", + "Dimensions": [ + { + "Name": "FunctionName", + "Value": { + "Ref": "DriveQueueLambdaFunction" + } + } + ], + "EvaluationPeriods": 1, + "MetricName": "Errors", + "Namespace": "AWS/Lambda", + "OKActions": [], + "Period": 60, + "Statistic": "Sum", + "Threshold": 0, + "TreatMissingData": "notBreaching" + }, + "Type": "AWS::CloudWatch::Alarm" + }, + "slicWatchLambdaErrorsAlarmDriveStreamLambdaFunction": { + "Properties": { + "ActionsEnabled": true, + "AlarmActions": [ + "test-topic" + ], + "AlarmDescription": { + "Fn::Sub": [ + "Error count for \${DriveStreamLambdaFunction} breaches 0", + {} + ] + }, + "AlarmName": { + "Fn::Sub": [ + "Lambda_Errors_\${DriveStreamLambdaFunction}", + {} + ] + }, + "ComparisonOperator": "GreaterThanThreshold", + "Dimensions": [ + { + "Name": "FunctionName", + "Value": { + "Ref": "DriveStreamLambdaFunction" + } + } + ], + "EvaluationPeriods": 1, + "MetricName": "Errors", + "Namespace": "AWS/Lambda", + "OKActions": [], + "Period": 60, + "Statistic": "Sum", + "Threshold": 0, + "TreatMissingData": "notBreaching" + }, + "Type": "AWS::CloudWatch::Alarm" + }, + "slicWatchLambdaErrorsAlarmDriveTableLambdaFunction": { + "Properties": { + "ActionsEnabled": true, + "AlarmActions": [ + "test-topic" + ], + "AlarmDescription": { + "Fn::Sub": [ + "Error count for \${DriveTableLambdaFunction} breaches 0", + {} + ] + }, + "AlarmName": { + "Fn::Sub": [ + "Lambda_Errors_\${DriveTableLambdaFunction}", + {} + ] + }, + "ComparisonOperator": "GreaterThanThreshold", + "Dimensions": [ + { + "Name": "FunctionName", + "Value": { + "Ref": "DriveTableLambdaFunction" + } + } + ], + "EvaluationPeriods": 1, + "MetricName": "Errors", + "Namespace": "AWS/Lambda", + "OKActions": [], + "Period": 60, + "Statistic": "Sum", + "Threshold": 0, + "TreatMissingData": "notBreaching" + }, + "Type": "AWS::CloudWatch::Alarm" + }, + "slicWatchLambdaErrorsAlarmHelloLambdaFunction": { + "Properties": { + "ActionsEnabled": true, + "AlarmActions": [ + "test-topic" + ], + "AlarmDescription": { + "Fn::Sub": [ + "Error count for \${HelloLambdaFunction} breaches 0", + {} + ] + }, + "AlarmName": { + "Fn::Sub": [ + "Lambda_Errors_\${HelloLambdaFunction}", + {} + ] + }, + "ComparisonOperator": "GreaterThanThreshold", + "Dimensions": [ + { + "Name": "FunctionName", + "Value": { + "Ref": "HelloLambdaFunction" + } + } + ], + "EvaluationPeriods": 1, + "MetricName": "Errors", + "Namespace": "AWS/Lambda", + "OKActions": [], + "Period": 60, + "Statistic": "Sum", + "Threshold": 0, + "TreatMissingData": "notBreaching" + }, + "Type": "AWS::CloudWatch::Alarm" + }, + "slicWatchLambdaErrorsAlarmHttpGetterLambdaFunction": { + "Properties": { + "ActionsEnabled": true, + "AlarmActions": [ + "test-topic" + ], + "AlarmDescription": { + "Fn::Sub": [ + "Error count for \${HttpGetterLambdaFunction} breaches 0", + {} + ] + }, + "AlarmName": { + "Fn::Sub": [ + "Lambda_Errors_\${HttpGetterLambdaFunction}", + {} + ] + }, + "ComparisonOperator": "GreaterThanThreshold", + "Dimensions": [ + { + "Name": "FunctionName", + "Value": { + "Ref": "HttpGetterLambdaFunction" + } + } + ], + "EvaluationPeriods": 1, + "MetricName": "Errors", + "Namespace": "AWS/Lambda", + "OKActions": [], + "Period": 60, + "Statistic": "Sum", + "Threshold": 0, + "TreatMissingData": "notBreaching" + }, + "Type": "AWS::CloudWatch::Alarm" + }, + "slicWatchLambdaErrorsAlarmPingLambdaFunction": { + "Properties": { + "ActionsEnabled": true, + "AlarmActions": [ + "test-topic" + ], + "AlarmDescription": { + "Fn::Sub": [ + "Error count for \${PingLambdaFunction} breaches 0", + {} + ] + }, + "AlarmName": { + "Fn::Sub": [ + "Lambda_Errors_\${PingLambdaFunction}", + {} + ] + }, + "ComparisonOperator": "GreaterThanThreshold", + "Dimensions": [ + { + "Name": "FunctionName", + "Value": { + "Ref": "PingLambdaFunction" + } + } + ], + "EvaluationPeriods": 1, + "MetricName": "Errors", + "Namespace": "AWS/Lambda", + "OKActions": [], + "Period": 60, + "Statistic": "Sum", + "Threshold": 0, + "TreatMissingData": "notBreaching" + }, + "Type": "AWS::CloudWatch::Alarm" + }, + "slicWatchLambdaErrorsAlarmStreamProcessorLambdaFunction": { + "Properties": { + "ActionsEnabled": true, + "AlarmActions": [ + "test-topic" + ], + "AlarmDescription": { + "Fn::Sub": [ + "Error count for \${StreamProcessorLambdaFunction} breaches 0", + {} + ] + }, + "AlarmName": { + "Fn::Sub": [ + "Lambda_Errors_\${StreamProcessorLambdaFunction}", + {} + ] + }, + "ComparisonOperator": "GreaterThanThreshold", + "Dimensions": [ + { + "Name": "FunctionName", + "Value": { + "Ref": "StreamProcessorLambdaFunction" + } + } + ], + "EvaluationPeriods": 1, + "MetricName": "Errors", + "Namespace": "AWS/Lambda", + "OKActions": [], + "Period": 60, + "Statistic": "Sum", + "Threshold": 0, + "TreatMissingData": "notBreaching" + }, + "Type": "AWS::CloudWatch::Alarm" + }, + "slicWatchLambdaErrorsAlarmSubscriptionHandlerLambdaFunction": { + "Properties": { + "ActionsEnabled": true, + "AlarmActions": [ + "test-topic" + ], + "AlarmDescription": { + "Fn::Sub": [ + "Error count for \${SubscriptionHandlerLambdaFunction} breaches 0", + {} + ] + }, + "AlarmName": { + "Fn::Sub": [ + "Lambda_Errors_\${SubscriptionHandlerLambdaFunction}", + {} + ] + }, + "ComparisonOperator": "GreaterThanThreshold", + "Dimensions": [ + { + "Name": "FunctionName", + "Value": { + "Ref": "SubscriptionHandlerLambdaFunction" + } + } + ], + "EvaluationPeriods": 1, + "MetricName": "Errors", + "Namespace": "AWS/Lambda", + "OKActions": [], + "Period": 60, + "Statistic": "Sum", + "Threshold": 0, + "TreatMissingData": "notBreaching" + }, + "Type": "AWS::CloudWatch::Alarm" + }, + "slicWatchLambdaErrorsAlarmThrottlerLambdaFunction": { + "Properties": { + "ActionsEnabled": true, + "AlarmActions": [ + "test-topic" + ], + "AlarmDescription": { + "Fn::Sub": [ + "Error count for \${ThrottlerLambdaFunction} breaches 0", + {} + ] + }, + "AlarmName": { + "Fn::Sub": [ + "Lambda_Errors_\${ThrottlerLambdaFunction}", + {} + ] + }, + "ComparisonOperator": "GreaterThanThreshold", + "Dimensions": [ + { + "Name": "FunctionName", + "Value": { + "Ref": "ThrottlerLambdaFunction" + } + } + ], + "EvaluationPeriods": 1, + "MetricName": "Errors", + "Namespace": "AWS/Lambda", + "OKActions": [], + "Period": 60, + "Statistic": "Sum", + "Threshold": 0, + "TreatMissingData": "notBreaching" + }, + "Type": "AWS::CloudWatch::Alarm" + }, + "slicWatchLambdaIteratorAgeAlarmStreamProcessorLambdaFunction": { + "Properties": { + "ActionsEnabled": true, + "AlarmActions": [ + "test-topic" + ], + "AlarmDescription": { + "Fn::Sub": [ + "IteratorAge for \${StreamProcessorLambdaFunction} breaches 10000", + {} + ] + }, + "AlarmName": { + "Fn::Sub": [ + "Lambda_IteratorAge_\${StreamProcessorLambdaFunction}", + {} + ] + }, + "ComparisonOperator": "GreaterThanThreshold", + "Dimensions": [ + { + "Name": "FunctionName", + "Value": { + "Ref": "StreamProcessorLambdaFunction" + } + } + ], + "EvaluationPeriods": 1, + "MetricName": "IteratorAge", + "Namespace": "AWS/Lambda", + "OKActions": [], + "Period": 60, + "Statistic": "Maximum", + "Threshold": 10000, + "TreatMissingData": "notBreaching" + }, + "Type": "AWS::CloudWatch::Alarm" + }, + "slicWatchLambdaThrottlesAlarmDriveQueueLambdaFunction": { + "Properties": { + "ActionsEnabled": true, + "AlarmActions": [ + "test-topic" + ], + "AlarmDescription": { + "Fn::Sub": [ + "Throttles % for \${DriveQueueLambdaFunction} breaches 0", + {} + ] + }, + "AlarmName": { + "Fn::Sub": [ + "Lambda_Throttles_\${DriveQueueLambdaFunction}", + {} + ] + }, + "ComparisonOperator": "GreaterThanThreshold", + "EvaluationPeriods": 1, + "Metrics": [ + { + "Id": "throttles_pc", + "Expression": "(throttles / ( throttles + invocations )) * 100", + "Label": "% Throttles", + "ReturnData": true + }, + { + "Id": "throttles", + "MetricStat": { + "Metric": { + "Namespace": "AWS/Lambda", + "MetricName": "Throttles", + "Dimensions": [ + { + "Name": "FunctionName", + "Value": { + "Ref": "DriveQueueLambdaFunction" + } + } + ] + }, + "Period": 60, + "Stat": "Sum" + }, + "ReturnData": false + }, + { + "Id": "invocations", + "MetricStat": { + "Metric": { + "Namespace": "AWS/Lambda", + "MetricName": "Invocations", + "Dimensions": [ + { + "Name": "FunctionName", + "Value": { + "Ref": "DriveQueueLambdaFunction" + } + } + ] + }, + "Period": 60, + "Stat": "Sum" + }, + "ReturnData": false + } + ], + "OKActions": [], + "Threshold": 0, + "TreatMissingData": "notBreaching" + }, + "Type": "AWS::CloudWatch::Alarm" + }, + "slicWatchLambdaThrottlesAlarmDriveStreamLambdaFunction": { + "Properties": { + "ActionsEnabled": true, + "AlarmActions": [ + "test-topic" + ], + "AlarmDescription": { + "Fn::Sub": [ + "Throttles % for \${DriveStreamLambdaFunction} breaches 0", + {} + ] + }, + "AlarmName": { + "Fn::Sub": [ + "Lambda_Throttles_\${DriveStreamLambdaFunction}", + {} + ] + }, + "ComparisonOperator": "GreaterThanThreshold", + "EvaluationPeriods": 1, + "Metrics": [ + { + "Id": "throttles_pc", + "Expression": "(throttles / ( throttles + invocations )) * 100", + "Label": "% Throttles", + "ReturnData": true + }, + { + "Id": "throttles", + "MetricStat": { + "Metric": { + "Namespace": "AWS/Lambda", + "MetricName": "Throttles", + "Dimensions": [ + { + "Name": "FunctionName", + "Value": { + "Ref": "DriveStreamLambdaFunction" + } + } + ] + }, + "Period": 60, + "Stat": "Sum" + }, + "ReturnData": false + }, + { + "Id": "invocations", + "MetricStat": { + "Metric": { + "Namespace": "AWS/Lambda", + "MetricName": "Invocations", + "Dimensions": [ + { + "Name": "FunctionName", + "Value": { + "Ref": "DriveStreamLambdaFunction" + } + } + ] + }, + "Period": 60, + "Stat": "Sum" + }, + "ReturnData": false + } + ], + "OKActions": [], + "Threshold": 0, + "TreatMissingData": "notBreaching" + }, + "Type": "AWS::CloudWatch::Alarm" + }, + "slicWatchLambdaThrottlesAlarmDriveTableLambdaFunction": { + "Properties": { + "ActionsEnabled": true, + "AlarmActions": [ + "test-topic" + ], + "AlarmDescription": { + "Fn::Sub": [ + "Throttles % for \${DriveTableLambdaFunction} breaches 0", + {} + ] + }, + "AlarmName": { + "Fn::Sub": [ + "Lambda_Throttles_\${DriveTableLambdaFunction}", + {} + ] + }, + "ComparisonOperator": "GreaterThanThreshold", + "EvaluationPeriods": 1, + "Metrics": [ + { + "Id": "throttles_pc", + "Expression": "(throttles / ( throttles + invocations )) * 100", + "Label": "% Throttles", + "ReturnData": true + }, + { + "Id": "throttles", + "MetricStat": { + "Metric": { + "Namespace": "AWS/Lambda", + "MetricName": "Throttles", + "Dimensions": [ + { + "Name": "FunctionName", + "Value": { + "Ref": "DriveTableLambdaFunction" + } + } + ] + }, + "Period": 60, + "Stat": "Sum" + }, + "ReturnData": false + }, + { + "Id": "invocations", + "MetricStat": { + "Metric": { + "Namespace": "AWS/Lambda", + "MetricName": "Invocations", + "Dimensions": [ + { + "Name": "FunctionName", + "Value": { + "Ref": "DriveTableLambdaFunction" + } + } + ] + }, + "Period": 60, + "Stat": "Sum" + }, + "ReturnData": false + } + ], + "OKActions": [], + "Threshold": 0, + "TreatMissingData": "notBreaching" + }, + "Type": "AWS::CloudWatch::Alarm" + }, + "slicWatchLambdaThrottlesAlarmHelloLambdaFunction": { + "Properties": { + "ActionsEnabled": true, + "AlarmActions": [ + "test-topic" + ], + "AlarmDescription": { + "Fn::Sub": [ + "Throttles % for \${HelloLambdaFunction} breaches 0", + {} + ] + }, + "AlarmName": { + "Fn::Sub": [ + "Lambda_Throttles_\${HelloLambdaFunction}", + {} + ] + }, + "ComparisonOperator": "GreaterThanThreshold", + "EvaluationPeriods": 1, + "Metrics": [ + { + "Id": "throttles_pc", + "Expression": "(throttles / ( throttles + invocations )) * 100", + "Label": "% Throttles", + "ReturnData": true + }, + { + "Id": "throttles", + "MetricStat": { + "Metric": { + "Namespace": "AWS/Lambda", + "MetricName": "Throttles", + "Dimensions": [ + { + "Name": "FunctionName", + "Value": { + "Ref": "HelloLambdaFunction" + } + } + ] + }, + "Period": 60, + "Stat": "Sum" + }, + "ReturnData": false + }, + { + "Id": "invocations", + "MetricStat": { + "Metric": { + "Namespace": "AWS/Lambda", + "MetricName": "Invocations", + "Dimensions": [ + { + "Name": "FunctionName", + "Value": { + "Ref": "HelloLambdaFunction" + } + } + ] + }, + "Period": 60, + "Stat": "Sum" + }, + "ReturnData": false + } + ], + "OKActions": [], + "Threshold": 0, + "TreatMissingData": "notBreaching" + }, + "Type": "AWS::CloudWatch::Alarm" + }, + "slicWatchLambdaThrottlesAlarmHttpGetterLambdaFunction": { + "Properties": { + "ActionsEnabled": true, + "AlarmActions": [ + "test-topic" + ], + "AlarmDescription": { + "Fn::Sub": [ + "Throttles % for \${HttpGetterLambdaFunction} breaches 0", + {} + ] + }, + "AlarmName": { + "Fn::Sub": [ + "Lambda_Throttles_\${HttpGetterLambdaFunction}", + {} + ] + }, + "ComparisonOperator": "GreaterThanThreshold", + "EvaluationPeriods": 1, + "Metrics": [ + { + "Id": "throttles_pc", + "Expression": "(throttles / ( throttles + invocations )) * 100", + "Label": "% Throttles", + "ReturnData": true + }, + { + "Id": "throttles", + "MetricStat": { + "Metric": { + "Namespace": "AWS/Lambda", + "MetricName": "Throttles", + "Dimensions": [ + { + "Name": "FunctionName", + "Value": { + "Ref": "HttpGetterLambdaFunction" + } + } + ] + }, + "Period": 60, + "Stat": "Sum" + }, + "ReturnData": false + }, + { + "Id": "invocations", + "MetricStat": { + "Metric": { + "Namespace": "AWS/Lambda", + "MetricName": "Invocations", + "Dimensions": [ + { + "Name": "FunctionName", + "Value": { + "Ref": "HttpGetterLambdaFunction" + } + } + ] + }, + "Period": 60, + "Stat": "Sum" + }, + "ReturnData": false + } + ], + "OKActions": [], + "Threshold": 0, + "TreatMissingData": "notBreaching" + }, + "Type": "AWS::CloudWatch::Alarm" + }, + "slicWatchLambdaThrottlesAlarmPingLambdaFunction": { + "Properties": { + "ActionsEnabled": true, + "AlarmActions": [ + "test-topic" + ], + "AlarmDescription": { + "Fn::Sub": [ + "Throttles % for \${PingLambdaFunction} breaches 0", + {} + ] + }, + "AlarmName": { + "Fn::Sub": [ + "Lambda_Throttles_\${PingLambdaFunction}", + {} + ] + }, + "ComparisonOperator": "GreaterThanThreshold", + "EvaluationPeriods": 1, + "Metrics": [ + { + "Id": "throttles_pc", + "Expression": "(throttles / ( throttles + invocations )) * 100", + "Label": "% Throttles", + "ReturnData": true + }, + { + "Id": "throttles", + "MetricStat": { + "Metric": { + "Namespace": "AWS/Lambda", + "MetricName": "Throttles", + "Dimensions": [ + { + "Name": "FunctionName", + "Value": { + "Ref": "PingLambdaFunction" + } + } + ] }, "Period": 60, "Stat": "Sum" @@ -3460,7 +4413,229 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot { "Name": "FunctionName", "Value": { - "Ref": "HelloLambdaFunction" + "Ref": "PingLambdaFunction" + } + } + ] + }, + "Period": 60, + "Stat": "Sum" + }, + "ReturnData": false + } + ], + "OKActions": [], + "Threshold": 0, + "TreatMissingData": "notBreaching" + }, + "Type": "AWS::CloudWatch::Alarm" + }, + "slicWatchLambdaThrottlesAlarmStreamProcessorLambdaFunction": { + "Properties": { + "ActionsEnabled": true, + "AlarmActions": [ + "test-topic" + ], + "AlarmDescription": { + "Fn::Sub": [ + "Throttles % for \${StreamProcessorLambdaFunction} breaches 0", + {} + ] + }, + "AlarmName": { + "Fn::Sub": [ + "Lambda_Throttles_\${StreamProcessorLambdaFunction}", + {} + ] + }, + "ComparisonOperator": "GreaterThanThreshold", + "EvaluationPeriods": 1, + "Metrics": [ + { + "Id": "throttles_pc", + "Expression": "(throttles / ( throttles + invocations )) * 100", + "Label": "% Throttles", + "ReturnData": true + }, + { + "Id": "throttles", + "MetricStat": { + "Metric": { + "Namespace": "AWS/Lambda", + "MetricName": "Throttles", + "Dimensions": [ + { + "Name": "FunctionName", + "Value": { + "Ref": "StreamProcessorLambdaFunction" + } + } + ] + }, + "Period": 60, + "Stat": "Sum" + }, + "ReturnData": false + }, + { + "Id": "invocations", + "MetricStat": { + "Metric": { + "Namespace": "AWS/Lambda", + "MetricName": "Invocations", + "Dimensions": [ + { + "Name": "FunctionName", + "Value": { + "Ref": "StreamProcessorLambdaFunction" + } + } + ] + }, + "Period": 60, + "Stat": "Sum" + }, + "ReturnData": false + } + ], + "OKActions": [], + "Threshold": 0, + "TreatMissingData": "notBreaching" + }, + "Type": "AWS::CloudWatch::Alarm" + }, + "slicWatchLambdaThrottlesAlarmSubscriptionHandlerLambdaFunction": { + "Properties": { + "ActionsEnabled": true, + "AlarmActions": [ + "test-topic" + ], + "AlarmDescription": { + "Fn::Sub": [ + "Throttles % for \${SubscriptionHandlerLambdaFunction} breaches 0", + {} + ] + }, + "AlarmName": { + "Fn::Sub": [ + "Lambda_Throttles_\${SubscriptionHandlerLambdaFunction}", + {} + ] + }, + "ComparisonOperator": "GreaterThanThreshold", + "EvaluationPeriods": 1, + "Metrics": [ + { + "Id": "throttles_pc", + "Expression": "(throttles / ( throttles + invocations )) * 100", + "Label": "% Throttles", + "ReturnData": true + }, + { + "Id": "throttles", + "MetricStat": { + "Metric": { + "Namespace": "AWS/Lambda", + "MetricName": "Throttles", + "Dimensions": [ + { + "Name": "FunctionName", + "Value": { + "Ref": "SubscriptionHandlerLambdaFunction" + } + } + ] + }, + "Period": 60, + "Stat": "Sum" + }, + "ReturnData": false + }, + { + "Id": "invocations", + "MetricStat": { + "Metric": { + "Namespace": "AWS/Lambda", + "MetricName": "Invocations", + "Dimensions": [ + { + "Name": "FunctionName", + "Value": { + "Ref": "SubscriptionHandlerLambdaFunction" + } + } + ] + }, + "Period": 60, + "Stat": "Sum" + }, + "ReturnData": false + } + ], + "OKActions": [], + "Threshold": 0, + "TreatMissingData": "notBreaching" + }, + "Type": "AWS::CloudWatch::Alarm" + }, + "slicWatchLambdaThrottlesAlarmThrottlerLambdaFunction": { + "Properties": { + "ActionsEnabled": true, + "AlarmActions": [ + "test-topic" + ], + "AlarmDescription": { + "Fn::Sub": [ + "Throttles % for \${ThrottlerLambdaFunction} breaches 0", + {} + ] + }, + "AlarmName": { + "Fn::Sub": [ + "Lambda_Throttles_\${ThrottlerLambdaFunction}", + {} + ] + }, + "ComparisonOperator": "GreaterThanThreshold", + "EvaluationPeriods": 1, + "Metrics": [ + { + "Id": "throttles_pc", + "Expression": "(throttles / ( throttles + invocations )) * 100", + "Label": "% Throttles", + "ReturnData": true + }, + { + "Id": "throttles", + "MetricStat": { + "Metric": { + "Namespace": "AWS/Lambda", + "MetricName": "Throttles", + "Dimensions": [ + { + "Name": "FunctionName", + "Value": { + "Ref": "ThrottlerLambdaFunction" + } + } + ] + }, + "Period": 60, + "Stat": "Sum" + }, + "ReturnData": false + }, + { + "Id": "invocations", + "MetricStat": { + "Metric": { + "Namespace": "AWS/Lambda", + "MetricName": "Invocations", + "Dimensions": [ + { + "Name": "FunctionName", + "Value": { + "Ref": "ThrottlerLambdaFunction" } } ] diff --git a/test-utils/sls-test-utils.ts b/test-utils/sls-test-utils.ts index a6a7c237..4c8311e4 100644 --- a/test-utils/sls-test-utils.ts +++ b/test-utils/sls-test-utils.ts @@ -28,7 +28,7 @@ export const slsYaml: SlsYaml = { } } -export function createMockServerless (compiledTemplate: Template) { +export function createMockServerless (compiledTemplate: Template, slsConfig = slsYaml) { return { cli: { log: () => { '' } @@ -52,8 +52,8 @@ export function createMockServerless (compiledTemplate: Template) { topicArn: 'test-topic' } }, - getAllFunctions: () => Object.keys(slsYaml.functions), - getFunction: (funcRef) => slsYaml.functions[funcRef] + getAllFunctions: () => Object.keys(slsConfig.functions ?? {}), + getFunction: (funcRef) => slsConfig.functions[funcRef] } } } From 34ea56eb7f38a52299d2dd92a816947c82161c0b Mon Sep 17 00:00:00 2001 From: Eoin Shanaghy Date: Fri, 1 Dec 2023 13:55:47 +0000 Subject: [PATCH 02/35] chore: sort snapshots by key --- test-utils/snapshot-utils.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/test-utils/snapshot-utils.ts b/test-utils/snapshot-utils.ts index defd3520..9a8a6e83 100644 --- a/test-utils/snapshot-utils.ts +++ b/test-utils/snapshot-utils.ts @@ -3,6 +3,7 @@ import type { Template } from 'cloudform' import type { DashboardProperties } from 'cloudform-types/types/cloudWatch/dashboard' import { type ResourceType } from 'slic-watch-core/cf-template' import { type Test } from 'tap' + /** * node-tap snapshots are usually persisted in tcompare format. We replace this with JSON * so we can clean them and deal with JSON-within-JSON cases. From 8ee908fd1580064156c1cf2f8f63164d2f21b63f Mon Sep 17 00:00:00 2001 From: Eoin Shanaghy Date: Sat, 4 Nov 2023 09:22:49 +0000 Subject: [PATCH 03/35] chore: use latest GitHub actions --- .github/workflows/build.yml | 4 ++-- .github/workflows/release.yml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index c750080a..23194045 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -17,8 +17,8 @@ jobs: node-version: [18, 20] steps: - - uses: actions/checkout@v3 - - uses: actions/setup-node@v3 + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 with: node-version: ${{ matrix.node-version }}.x cache: 'npm' diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index eec73f97..32254522 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -19,9 +19,9 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout repository - uses: actions/checkout@master + uses: actions/checkout@v4 - name: Set up Node.js - uses: actions/setup-node@v2 + uses: actions/setup-node@v4 with: node-version: 18.x registry-url: "https://registry.npmjs.org" From 49acf73bcb2f762a85981ae7e649ee941337f966 Mon Sep 17 00:00:00 2001 From: Eoin Shanaghy Date: Mon, 6 Nov 2023 13:32:58 +0000 Subject: [PATCH 04/35] chore: use metadata for function alarm config --- cf-macro/index.ts | 6 +- core/alarms/alarm-types.ts | 6 + core/alarms/alarms.ts | 16 +-- core/alarms/dynamodb.ts | 4 +- core/alarms/lambda.ts | 155 +++++++++++-------------- core/alarms/tests/alarms.test.ts | 18 +-- core/inputs/function-config.ts | 35 ------ core/inputs/general-config.ts | 6 +- serverless-plugin/serverless-plugin.ts | 30 +++-- 9 files changed, 113 insertions(+), 163 deletions(-) delete mode 100644 core/inputs/function-config.ts diff --git a/cf-macro/index.ts b/cf-macro/index.ts index 265af8aa..b09b44be 100644 --- a/cf-macro/index.ts +++ b/cf-macro/index.ts @@ -1,10 +1,10 @@ import _ from 'lodash' +import { type Template } from 'cloudform-types' import pino from 'pino' -import { addAlarms, addDashboard, getResourcesByType } from '../core/index' +import { addAlarms, addDashboard, getResourcesByType } from 'slic-watch-core/index' import { setLogger } from 'slic-watch-core/logging' import { type SlicWatchConfig, resolveSlicWatchConfig } from 'slic-watch-core/inputs/general-config' -import { type Template } from 'cloudform-types' const logger = pino({ name: 'macroHandler', level: process.env.DEBUG_LEVEL ?? 'debug' }) @@ -54,7 +54,7 @@ export async function handler (event: Event): Promise { addDashboard(config.dashboard, functionDashboardConfigs, transformedTemplate) outputFragment = transformedTemplate } catch (err) { - logger.error(err) + logger.error({ err }) errorMessage = (err as Error).message status = 'fail' } diff --git a/core/alarms/alarm-types.ts b/core/alarms/alarm-types.ts index 2a7b4b94..87257580 100644 --- a/core/alarms/alarm-types.ts +++ b/core/alarms/alarm-types.ts @@ -23,11 +23,17 @@ export interface AlarmTemplate { Properties: AlarmProperties } +/** + * Alarm configuration type used *before* all mandatory fields have been applied + */ export interface SlicWatchAlarmConfig extends Omit { ComparisonOperator?: string enabled?: boolean } +/** + * Alarm configuration type used *after* all mandatory fields have been applied + */ export interface SlicWatchMergedConfig extends AlarmProperties { enabled: boolean } diff --git a/core/alarms/alarms.ts b/core/alarms/alarms.ts index dcfd4798..b98e5146 100644 --- a/core/alarms/alarms.ts +++ b/core/alarms/alarms.ts @@ -2,14 +2,12 @@ import type Resource from 'cloudform-types/types/resource' import type Template from 'cloudform-types/types/template' import { cascade } from '../inputs/cascading-config' -import { applyAlarmConfig } from '../inputs/function-config' import type { - AlarmActionsConfig, InputOutput, + AlarmActionsConfig, SlicWatchAlarmConfig, SlicWatchCascadedAlarmsConfig, SlicWatchMergedConfig } from './alarm-types' -import type { FunctionAlarmProperties } from './lambda' import createLambdaAlarms from './lambda' import createApiGatewayAlarms from './api-gateway' import createStatesAlarms from './step-functions' @@ -34,7 +32,6 @@ import { addResource } from '../cf-template' */ export default function addAlarms ( alarmProperties: SlicWatchCascadedAlarmsConfig, - functionAlarmProperties: FunctionAlarmProperties, alarmActionsConfig: AlarmActionsConfig, compiledTemplate: Template ) { @@ -50,11 +47,10 @@ export default function addAlarms ( Events: ruleConfig, ApplicationELB: albConfig, ApplicationELBTarget: albTargetConfig, - AppSync: appSyncConfig + AppSync: appSyncConfig, + enabled } = cascade(alarmProperties) as SlicWatchCascadedAlarmsConfig - const cascadedFunctionAlarmProperties = applyAlarmConfig(lambdaConfig, functionAlarmProperties) - const funcsWithConfig: Array<{ config: SlicWatchAlarmConfig, alarmFunc: any }> = [ { config: apiGwConfig, alarmFunc: createApiGatewayAlarms }, { config: sfConfig, alarmFunc: createStatesAlarms }, @@ -66,12 +62,12 @@ export default function addAlarms ( { config: ruleConfig, alarmFunc: createRuleAlarms }, { config: albConfig, alarmFunc: createAlbAlarms }, { config: albTargetConfig, alarmFunc: createAlbTargetAlarms }, - { config: appSyncConfig, alarmFunc: createAppSyncAlarms } + { config: appSyncConfig, alarmFunc: createAppSyncAlarms }, + { config: lambdaConfig, alarmFunc: createLambdaAlarms } ] const resources = {} - if (alarmProperties.enabled) { - Object.assign(resources, createLambdaAlarms(cascadedFunctionAlarmProperties, alarmActionsConfig, compiledTemplate)) + if (enabled) { for (const { config, alarmFunc } of funcsWithConfig) { Object.assign(resources, alarmFunc(config, alarmActionsConfig, compiledTemplate)) } diff --git a/core/alarms/dynamodb.ts b/core/alarms/dynamodb.ts index 3a64c1f0..fa74fe2a 100644 --- a/core/alarms/dynamodb.ts +++ b/core/alarms/dynamodb.ts @@ -27,7 +27,9 @@ const dynamoDbGsiMetrics = ['ReadThrottleEvents', 'WriteThrottleEvents'] * @returns DynamoDB-specific CloudFormation Alarm resources */ export default function createDynamoDbAlarms ( - dynamoDbAlarmsConfig: SlicWatchDynamoDbAlarmsConfig, alarmActionsConfig: AlarmActionsConfig, compiledTemplate: Template + dynamoDbAlarmsConfig: SlicWatchDynamoDbAlarmsConfig, + alarmActionsConfig: AlarmActionsConfig, + compiledTemplate: Template ): CloudFormationResources { const resources: CloudFormationResources = {} const tableResources = getResourcesByType('AWS::DynamoDB::Table', compiledTemplate) diff --git a/core/alarms/lambda.ts b/core/alarms/lambda.ts index 14c59f15..bbc552f0 100644 --- a/core/alarms/lambda.ts +++ b/core/alarms/lambda.ts @@ -5,6 +5,7 @@ import { Fn } from 'cloudform' import { getEventSourceMappingFunctions, getResourcesByType } from '../cf-template' import type { AlarmActionsConfig, InputOutput, Value, SlicWatchMergedConfig, SlicWatchAlarmConfig } from './alarm-types' import { createAlarm } from './alarm-utils' +import { cascade } from '../inputs/cascading-config' export interface SlicWatchLambdaAlarmsConfig extends SlicWatchAlarmConfig { Errors: T @@ -14,18 +15,7 @@ export interface SlicWatchLambdaAlarmsConfig extends Slic IteratorAge: T } -export interface FunctionAlarmProperties { - HelloLambdaFunction?: SlicWatchLambdaAlarmsConfig - ThrottlerLambdaFunction?: SlicWatchLambdaAlarmsConfig - DriveStreamLambdaFunction?: SlicWatchLambdaAlarmsConfig - DriveQueueLambdaFunction?: SlicWatchLambdaAlarmsConfig - DriveTableLambdaFunction?: SlicWatchLambdaAlarmsConfig - StreamProcessorLambdaFunction?: SlicWatchLambdaAlarmsConfig - HttpGetterLambdaFunction?: SlicWatchLambdaAlarmsConfig - SubscriptionHandlerLambdaFunction?: SlicWatchLambdaAlarmsConfig - EventsRuleLambdaFunction?: SlicWatchLambdaAlarmsConfig - AlbEventLambdaFunction?: SlicWatchLambdaAlarmsConfig -} +export type FunctionAlarmProperties = Record> const lambdaMetrics = ['Errors', 'ThrottlesPc', 'DurationPc', 'Invocations'] @@ -38,91 +28,88 @@ const lambdaMetrics = ['Errors', 'ThrottlesPc', 'DurationPc', 'Invocations'] * * @returns Lambda-specific CloudFormation Alarm resources */ -export default function createLambdaAlarms (functionAlarmProperties: SlicWatchLambdaAlarmsConfig, alarmActionsConfig: AlarmActionsConfig, compiledTemplate: Template) { +export default function createLambdaAlarms (lambdaAlarmConfig: SlicWatchLambdaAlarmsConfig, alarmActionsConfig: AlarmActionsConfig, compiledTemplate: Template) { const resources = {} const lambdaResources = getResourcesByType('AWS::Lambda::Function', compiledTemplate) + const configPerFunctionResource: Record> = {} for (const [funcLogicalId, funcResource] of Object.entries(lambdaResources)) { - const config: SlicWatchLambdaAlarmsConfig = functionAlarmProperties[funcLogicalId] + const resourceConfig = cascade(funcResource?.Metadata?.slicWatch?.alarms ?? {}) as SlicWatchLambdaAlarmsConfig + configPerFunctionResource[funcLogicalId] = resourceConfig + const config: SlicWatchLambdaAlarmsConfig = Object.assign(lambdaAlarmConfig, resourceConfig) - if (config === undefined) { - console.warn(`${funcLogicalId} is not found in the template. Alarms will not be created for this function.`) - } else { - for (const metric of lambdaMetrics) { - if (config.enabled === false || config[metric].enabled === false) { - continue - } - if (metric === 'ThrottlesPc') { - const properties = config.ThrottlesPc - properties.Metrics = [ - { - Id: 'throttles_pc', - Expression: '(throttles / ( throttles + invocations )) * 100', - Label: '% Throttles', - ReturnData: true - }, - { - Id: 'throttles', - MetricStat: { - Metric: { - Namespace: 'AWS/Lambda', - MetricName: 'Throttles', - Dimensions: [{ Name: 'FunctionName', Value: Fn.Ref(funcLogicalId) }] - }, - Period: properties.Period as Value, - Stat: properties.Statistic as Value + for (const metric of lambdaMetrics) { + if (config.enabled === false || config[metric].enabled === false) { + continue + } + if (metric === 'ThrottlesPc') { + const properties = config.ThrottlesPc + properties.Metrics = [ + { + Id: 'throttles_pc', + Expression: '(throttles / ( throttles + invocations )) * 100', + Label: '% Throttles', + ReturnData: true + }, + { + Id: 'throttles', + MetricStat: { + Metric: { + Namespace: 'AWS/Lambda', + MetricName: 'Throttles', + Dimensions: [{ Name: 'FunctionName', Value: Fn.Ref(funcLogicalId) }] }, - ReturnData: false + Period: properties.Period as Value, + Stat: properties.Statistic as Value }, - { - Id: 'invocations', - MetricStat: { - Metric: { - Namespace: 'AWS/Lambda', - MetricName: 'Invocations', - Dimensions: [{ Name: 'FunctionName', Value: Fn.Ref(funcLogicalId) }] - }, - Period: properties.Period as Value, - Stat: properties.Statistic as Value + ReturnData: false + }, + { + Id: 'invocations', + MetricStat: { + Metric: { + Namespace: 'AWS/Lambda', + MetricName: 'Invocations', + Dimensions: [{ Name: 'FunctionName', Value: Fn.Ref(funcLogicalId) }] }, - ReturnData: false - } - ] - } - if (metric === 'DurationPc') { - const properties = config.DurationPc - const funcTimeout: number = funcResource.Properties?.Timeout ?? 3 - const threshold: Value = properties.Threshold as number - const alarmDescription = Fn.Sub(`Max duration for \${${funcLogicalId}} breaches ${properties.Threshold}% of timeout (${funcTimeout})`, {}) - properties.AlarmDescription = alarmDescription - properties.Threshold = (threshold * funcTimeout * 1000) / 100 - } - if (metric === 'Errors') { - const properties = config.Errors - const alarmDescription = Fn.Sub(`Error count for \${${funcLogicalId}} breaches ${properties.Threshold}`, {}) - properties.AlarmDescription = alarmDescription - } - - if (metric === 'ThrottlesPc') { - const properties = config.ThrottlesPc - const alarmDescription = Fn.Sub(`Throttles % for \${${funcLogicalId}} breaches ${properties.Threshold}`, {}) - properties.AlarmDescription = alarmDescription - } + Period: properties.Period as Value, + Stat: properties.Statistic as Value + }, + ReturnData: false + } + ] + } + if (metric === 'DurationPc') { + const properties = config.DurationPc + const funcTimeout: number = funcResource.Properties?.Timeout ?? 3 + const threshold: Value = properties.Threshold as number + const alarmDescription = Fn.Sub(`Max duration for \${${funcLogicalId}} breaches ${properties.Threshold}% of timeout (${funcTimeout})`, {}) + properties.AlarmDescription = alarmDescription + properties.Threshold = (threshold * funcTimeout * 1000) / 100 + } + if (metric === 'Errors') { + const properties = config.Errors + const alarmDescription = Fn.Sub(`Error count for \${${funcLogicalId}} breaches ${properties.Threshold}`, {}) + properties.AlarmDescription = alarmDescription + } - if (metric === 'Invocations') { - const properties = config.Invocations - const alarmDescription = Fn.Sub(`Total invocations for \${${funcLogicalId}} breaches ${properties.Threshold}`, {}) - properties.AlarmDescription = alarmDescription - } + if (metric === 'ThrottlesPc') { + const properties = config.ThrottlesPc + const alarmDescription = Fn.Sub(`Throttles % for \${${funcLogicalId}} breaches ${properties.Threshold}`, {}) + properties.AlarmDescription = alarmDescription + } - Object.assign(resources, createLambdaCfAlarm(config[metric], metric, funcLogicalId, compiledTemplate, alarmActionsConfig)) + if (metric === 'Invocations') { + const properties = config.Invocations + const alarmDescription = Fn.Sub(`Total invocations for \${${funcLogicalId}} breaches ${properties.Threshold}`, {}) + properties.AlarmDescription = alarmDescription } + + Object.assign(resources, createLambdaCfAlarm(config[metric], metric, funcLogicalId, compiledTemplate, alarmActionsConfig)) } for (const funcLogicalId of Object.keys(getEventSourceMappingFunctions(compiledTemplate))) { - const config = functionAlarmProperties[funcLogicalId] - if (config === undefined) { - console.warn(`${funcLogicalId} is not found in the template. Alarms will not be created for this function.`) - } else if (config.enabled !== false && config.IteratorAge.enabled !== false) { + const config = configPerFunctionResource[funcLogicalId] + if (config.enabled !== false && config.IteratorAge.enabled) { Object.assign(resources, createLambdaCfAlarm(config.IteratorAge, 'IteratorAge', funcLogicalId, compiledTemplate, alarmActionsConfig)) } } diff --git a/core/alarms/tests/alarms.test.ts b/core/alarms/tests/alarms.test.ts index 00660688..e44f54dd 100644 --- a/core/alarms/tests/alarms.test.ts +++ b/core/alarms/tests/alarms.test.ts @@ -7,11 +7,7 @@ import { getResourcesByType } from '../../cf-template' test('Alarms create all service alarms', (t) => { const compiledTemplate = createTestCloudFormationTemplate() - const funcAlarmPropertiess = {} - for (const funcLogicalId of Object.keys(getResourcesByType('AWS::Lambda::Function', compiledTemplate))) { - funcAlarmPropertiess[funcLogicalId] = {} - } - addAlarms(defaultConfig.alarms, funcAlarmPropertiess, testAlarmActionsConfig, compiledTemplate) + addAlarms(defaultConfig.alarms, testAlarmActionsConfig, compiledTemplate) const namespaces = new Set() for (const resource of Object.values( getResourcesByType('AWS::CloudWatch::Alarm', compiledTemplate) @@ -26,11 +22,7 @@ test('Alarms create all service alarms', (t) => { test('Alarms create all ALB service alarms', (t) => { const compiledTemplate = createTestCloudFormationTemplate(albCfTemplate) - const funcAlarmPropertiess = {} - for (const funcLogicalId of Object.keys(getResourcesByType('AWS::Lambda::Function', compiledTemplate))) { - funcAlarmPropertiess[funcLogicalId] = {} - } - addAlarms(defaultConfig.alarms, funcAlarmPropertiess, testAlarmActionsConfig, compiledTemplate) + addAlarms(defaultConfig.alarms, testAlarmActionsConfig, compiledTemplate) const namespaces = new Set() for (const resource of Object.values( getResourcesByType('AWS::CloudWatch::Alarm', compiledTemplate) @@ -51,11 +43,7 @@ test('Alarms are not created when disabled globally', (t) => { } ) const compiledTemplate = createTestCloudFormationTemplate() - const funcAlarmPropertiess = {} - for (const funcLogicalId of Object.keys(getResourcesByType('AWS::Lambda::Function', compiledTemplate))) { - funcAlarmPropertiess[funcLogicalId] = {} - } - addAlarms(config, funcAlarmPropertiess, testAlarmActionsConfig, compiledTemplate) + addAlarms(config, testAlarmActionsConfig, compiledTemplate) const alarmsCreated = getResourcesByType('AWS::CloudWatch::Alarm', compiledTemplate) diff --git a/core/inputs/function-config.ts b/core/inputs/function-config.ts deleted file mode 100644 index fb95c318..00000000 --- a/core/inputs/function-config.ts +++ /dev/null @@ -1,35 +0,0 @@ - -import { get, merge } from 'lodash' - -import { cascade } from './cascading-config' -import defaultConfig from './default-config' -import type { SlicWatchLambdaAlarmsConfig } from '../alarms/lambda' -import { type SlicWatchMergedConfig } from '../alarms/alarm-types' - -/** - * Merges the global Lambda alarm configuration with any function-specific overrides, ensuring - * that function overrides take precedence over any global configuration - * - * cascadedLambdaAlarmConfig - * functionAlarmConfig An object per function name specifying any function-specific alarm configuration overrides - * A per-function configuration consolidating all inputs - */ -function applyAlarmConfig (cascadedLambdaAlarmConfig, functionAlarmConfigs): SlicWatchLambdaAlarmsConfig { - // Add all alarm properties to functionAlarmConfig so we can cascade top-level configuration down - const mergedFuncAlarmConfigs = {} - for (const func of Object.keys(functionAlarmConfigs)) { - const funcConfig = { ...(functionAlarmConfigs[func].Lambda ?? {}) } - for (const metric of Object.keys({ ...defaultConfig.alarms.Lambda })) { - funcConfig[metric] = get(functionAlarmConfigs, [func, 'Lambda', metric], {}) - } - mergedFuncAlarmConfigs[func] = merge({}, cascadedLambdaAlarmConfig, cascade(funcConfig)) - } - return mergedFuncAlarmConfigs as SlicWatchLambdaAlarmsConfig -} - -/** - * Support for function-specific configuration for AWS Lambda overrides at a function level - */ -export { - applyAlarmConfig -} diff --git a/core/inputs/general-config.ts b/core/inputs/general-config.ts index 0150192a..12866628 100644 --- a/core/inputs/general-config.ts +++ b/core/inputs/general-config.ts @@ -28,9 +28,9 @@ export class ConfigError extends Error { } /** - * Validates and transforms the user-provided top-configuration for SLIC Watch. The configuration - * is validated accoring to the config schema. Defaults are applied where not provided by the user. - * Finally, the alarm actions are addded. + * Validates and transforms the user-provided top-level configuration for SLIC Watch. + * The configuration is validated accoring to the config schema. Defaults are applied + * where not provided by the user. Finally, the alarm actions are addded. * * @param slicWatchConfig The user-provided configuration * @returns Resolved configuration diff --git a/serverless-plugin/serverless-plugin.ts b/serverless-plugin/serverless-plugin.ts index 455cc9c1..fe095c14 100644 --- a/serverless-plugin/serverless-plugin.ts +++ b/serverless-plugin/serverless-plugin.ts @@ -2,7 +2,8 @@ import { merge } from 'lodash' import type Serverless from 'serverless' import ServerlessError from 'serverless/lib/serverless-error' import type Hooks from 'serverless-hooks-plugin' - +import { type Template } from 'cloudform-types' +import type Resource from 'cloudform-types/types/resource' import { type ResourceType } from '../core/index' import { addAlarms, addDashboard, pluginConfigSchema, functionConfigSchema } from '../core/index' import { resolveSlicWatchConfig, type ResolvedConfiguration, type SlicWatchConfig } from '../core/inputs/general-config' @@ -56,22 +57,27 @@ class ServerlessPlugin { if (config.enabled) { const awsProvider = this.serverless.getProvider('aws') - const functionAlarmConfigs = {} - const functionDashboardConfigs = {} + const compiledTemplate = this.serverless.service.provider.compiledCloudFormationTemplate as Template + const additionalResources = this.serverless.service.resources as ResourceType + + // Each Lambda Function declared in serverless.yml may have a slicWatch configuration + // to set configuration overrides for the specific function. We transform those into + // CloudFormation Metadata on the generate AWS::Lambda::Function resource for (const funcName of this.serverless.service.getAllFunctions()) { - const func = this.serverless.service.getFunction(funcName) as any // check why they don't return slicWatch - const functionResName = awsProvider.naming.getLambdaLogicalId(funcName) + const func = this.serverless.service.getFunction(funcName) as any const funcConfig = func.slicWatch ?? {} - functionAlarmConfigs[functionResName] = funcConfig.alarms ?? {} - functionDashboardConfigs[functionResName] = funcConfig.dashboard - } + const functionLogicalId = awsProvider.naming.getLambdaLogicalId(funcName) - const compiledTemplate = this.serverless.service.provider.compiledCloudFormationTemplate - const additionalResources = this.serverless.service.resources as ResourceType + const templateResources = compiledTemplate.Resources as Record + templateResources[functionLogicalId].Metadata = { + ...templateResources[functionLogicalId].Metadata ?? {}, + slicWatch: funcConfig + } + } merge(compiledTemplate, additionalResources) - addDashboard(config.dashboard, functionDashboardConfigs, compiledTemplate) - addAlarms(config.alarms, functionAlarmConfigs, config.alarmActionsConfig, compiledTemplate) + addDashboard(config.dashboard, compiledTemplate) + addAlarms(config.alarms, config.alarmActionsConfig, compiledTemplate) } } } From 9ea9ea6100010b40e3a68e86937767c6b428bd69 Mon Sep 17 00:00:00 2001 From: Eoin Shanaghy Date: Tue, 14 Nov 2023 10:00:02 +0000 Subject: [PATCH 05/35] use more specific types for dashboard --- cf-macro/index.ts | 19 +- cf-macro/tests/cdk-cf.test.ts | 8 +- core/alarms/lambda.ts | 16 +- core/alarms/tests/lambda.test.ts | 125 +++--------- core/dashboards/dashboard-types.ts | 225 ++++++++++------------ core/dashboards/dashboard.ts | 242 ++++++++++++------------ core/dashboards/tests/dashboard.test.ts | 79 +++++--- core/inputs/default-config.ts | 4 +- core/package.json | 1 + package-lock.json | 14 ++ serverless-plugin/tests/index.test.ts | 76 -------- 11 files changed, 343 insertions(+), 466 deletions(-) diff --git a/cf-macro/index.ts b/cf-macro/index.ts index b09b44be..629677b8 100644 --- a/cf-macro/index.ts +++ b/cf-macro/index.ts @@ -1,8 +1,7 @@ -import _ from 'lodash' import { type Template } from 'cloudform-types' import pino from 'pino' -import { addAlarms, addDashboard, getResourcesByType } from 'slic-watch-core/index' +import { addAlarms, addDashboard } from 'slic-watch-core/index' import { setLogger } from 'slic-watch-core/logging' import { type SlicWatchConfig, resolveSlicWatchConfig } from 'slic-watch-core/inputs/general-config' @@ -38,20 +37,8 @@ export async function handler (event: Event): Promise { const config = resolveSlicWatchConfig(slicWatchConfig) - const functionAlarmConfigs = {} - const functionDashboardConfigs = {} - - const lambdaResources = getResourcesByType('AWS::Lambda::Function', transformedTemplate) - - for (const [funcResourceName, funcResource] of Object.entries(lambdaResources)) { - const funcConfig = funcResource.Metadata?.slicWatch ?? {} - functionAlarmConfigs[funcResourceName] = funcConfig.alarms ?? {} - functionDashboardConfigs[funcResourceName] = funcConfig.dashboard - } - - _.merge(transformedTemplate) - addAlarms(config.alarms, functionAlarmConfigs, config.alarmActionsConfig, transformedTemplate) - addDashboard(config.dashboard, functionDashboardConfigs, transformedTemplate) + addAlarms(config.alarms, config.alarmActionsConfig, transformedTemplate) + addDashboard(config.dashboard, transformedTemplate) outputFragment = transformedTemplate } catch (err) { logger.error({ err }) diff --git a/cf-macro/tests/cdk-cf.test.ts b/cf-macro/tests/cdk-cf.test.ts index fe493539..ea053b75 100644 --- a/cf-macro/tests/cdk-cf.test.ts +++ b/cf-macro/tests/cdk-cf.test.ts @@ -1,5 +1,5 @@ import { test } from 'tap' - +import type { Template } from 'cloudform-types' import { getResourcesByType } from 'slic-watch-core/cf-template' import { handler } from '../index' import cdkStack from './resources/cdk-ecs-cf.json' @@ -9,11 +9,13 @@ import cdkStack from './resources/cdk-ecs-cf.json' */ test('ECS CDK stack', async (t) => { const event = { - fragment: cdkStack + fragment: cdkStack as Template, + requestId: 'test' } + const handlerResponse = await handler(event) t.equal(handlerResponse.status, 'success') - const compiledTemplate = handlerResponse.fragment + const compiledTemplate = handlerResponse.fragment as Template test('alarms are generated', (t) => { const alarms = getResourcesByType('AWS::CloudWatch::Alarm', compiledTemplate) diff --git a/core/alarms/lambda.ts b/core/alarms/lambda.ts index bbc552f0..80342c4b 100644 --- a/core/alarms/lambda.ts +++ b/core/alarms/lambda.ts @@ -27,16 +27,18 @@ const lambdaMetrics = ['Errors', 'ThrottlesPc', 'DurationPc', 'Invocations'] * @compiledTemplate CloudFormation template object * * @returns Lambda-specific CloudFormation Alarm resources + * + * TODO - Fix the lambdaAlarmConfig type */ export default function createLambdaAlarms (lambdaAlarmConfig: SlicWatchLambdaAlarmsConfig, alarmActionsConfig: AlarmActionsConfig, compiledTemplate: Template) { const resources = {} const lambdaResources = getResourcesByType('AWS::Lambda::Function', compiledTemplate) - const configPerFunctionResource: Record> = {} + const mergedConfigPerFunction: Record> = {} for (const [funcLogicalId, funcResource] of Object.entries(lambdaResources)) { const resourceConfig = cascade(funcResource?.Metadata?.slicWatch?.alarms ?? {}) as SlicWatchLambdaAlarmsConfig - configPerFunctionResource[funcLogicalId] = resourceConfig const config: SlicWatchLambdaAlarmsConfig = Object.assign(lambdaAlarmConfig, resourceConfig) + mergedConfigPerFunction[funcLogicalId] = config for (const metric of lambdaMetrics) { if (config.enabled === false || config[metric].enabled === false) { @@ -107,11 +109,11 @@ export default function createLambdaAlarms (lambdaAlarmConfig: SlicWatchLambdaAl Object.assign(resources, createLambdaCfAlarm(config[metric], metric, funcLogicalId, compiledTemplate, alarmActionsConfig)) } - for (const funcLogicalId of Object.keys(getEventSourceMappingFunctions(compiledTemplate))) { - const config = configPerFunctionResource[funcLogicalId] - if (config.enabled !== false && config.IteratorAge.enabled) { - Object.assign(resources, createLambdaCfAlarm(config.IteratorAge, 'IteratorAge', funcLogicalId, compiledTemplate, alarmActionsConfig)) - } + } + for (const funcLogicalId of Object.keys(getEventSourceMappingFunctions(compiledTemplate))) { + const config = mergedConfigPerFunction[funcLogicalId] + if (config.enabled !== false && config.IteratorAge.enabled) { + Object.assign(resources, createLambdaCfAlarm(config.IteratorAge, 'IteratorAge', funcLogicalId, compiledTemplate, alarmActionsConfig)) } } return resources diff --git a/core/alarms/tests/lambda.test.ts b/core/alarms/tests/lambda.test.ts index 4cfbf29a..35b56479 100644 --- a/core/alarms/tests/lambda.test.ts +++ b/core/alarms/tests/lambda.test.ts @@ -1,4 +1,5 @@ import { test } from 'tap' +import type { AlarmProperties } from 'cloudform-types/types/cloudWatch/alarm' import createLambdaAlarms from '../lambda' import { getResourcesByType } from '../../cf-template' @@ -14,7 +15,6 @@ import { albCfTemplate, testAlarmActionsConfig } from '../../tests/testing-utils' -import { applyAlarmConfig } from '../../inputs/function-config' export interface AlarmsByType { Lambda_Duration? @@ -30,7 +30,7 @@ export interface MetricsById { } test('AWS Lambda alarms are created', (t) => { - const AlarmProperties = createTestConfig(defaultConfig.alarms, { + const alarmConfig = createTestConfig(defaultConfig.alarms, { Lambda: { Period: 120, EvaluationPeriods: 2, @@ -55,17 +55,12 @@ test('AWS Lambda alarms are created', (t) => { }) const compiledTemplate = createTestCloudFormationTemplate() - const FunctionAlarmProperties = AlarmProperties.Lambda - for (const funcLogicalId of Object.keys(getResourcesByType('AWS::Lambda::Function', compiledTemplate))) { - FunctionAlarmProperties[funcLogicalId] = AlarmProperties.Lambda - } - - const alarmResources: ResourceType = createLambdaAlarms(FunctionAlarmProperties, testAlarmActionsConfig, compiledTemplate) + const alarmResources: ResourceType = createLambdaAlarms(alarmConfig.Lambda, testAlarmActionsConfig, compiledTemplate) function getAlarmsByType (): AlarmsByType { const alarmsByType = {} for (const alarmResource of Object.values(alarmResources)) { - const al = alarmResource.Properties + const al = alarmResource.Properties as AlarmProperties assertCommonAlarmProperties(t, al) const alarmType = alarmNameToType(al?.AlarmName) alarmsByType[alarmType] = alarmsByType[alarmType] ?? new Set() @@ -86,7 +81,7 @@ test('AWS Lambda alarms are created', (t) => { for (const al of alarmsByType.Lambda_Errors) { t.equal(al.MetricName, 'Errors') t.equal(al.Statistic, 'Sum') - t.equal(al.Threshold, AlarmProperties.Lambda.Errors.Threshold) + t.equal(al.Threshold, alarmConfig.Lambda.Errors.Threshold) t.equal(al.EvaluationPeriods, 2) t.equal(al.TreatMissingData, 'breaching') t.equal(al.ComparisonOperator, 'GreaterThanOrEqualToThreshold') @@ -144,7 +139,7 @@ test('AWS Lambda alarms are created', (t) => { }) test('AWS Lambda alarms are created for ALB', (t) => { - const AlarmProperties = createTestConfig(defaultConfig.alarms, { + const alarmConfig = createTestConfig(defaultConfig.alarms, { Lambda: { Period: 120, EvaluationPeriods: 2, @@ -169,16 +164,12 @@ test('AWS Lambda alarms are created for ALB', (t) => { }) const compiledTemplate = createTestCloudFormationTemplate(albCfTemplate) - const albFunctionAlarmProperties = AlarmProperties.Lambda - for (const funcLogicalId of Object.keys(getResourcesByType('AWS::Lambda::Function', compiledTemplate))) { - albFunctionAlarmProperties[funcLogicalId] = AlarmProperties.Lambda - } - const albAlarmResources: ResourceType = createLambdaAlarms(albFunctionAlarmProperties, testAlarmActionsConfig, compiledTemplate) + const albAlarmResources: ResourceType = createLambdaAlarms(alarmConfig.Lambda, testAlarmActionsConfig, compiledTemplate) function getAlarmsByType (): AlarmsByType { const albAlarmsByType: AlarmsByType = {} for (const alarmResource of Object.values(albAlarmResources)) { - const al = alarmResource.Properties + const al = alarmResource.Properties as AlarmProperties assertCommonAlarmProperties(t, al) const alarmType: any = alarmNameToType(al?.AlarmName) albAlarmsByType[alarmType] = albAlarmsByType[alarmType] ?? new Set() @@ -196,7 +187,7 @@ test('AWS Lambda alarms are created for ALB', (t) => { for (const al of albAlarmsByType.Lambda_Errors) { t.equal(al.MetricName, 'Errors') t.equal(al.Statistic, 'Sum') - t.equal(al.Threshold, AlarmProperties.Lambda.Errors.Threshold) + t.equal(al.Threshold, alarmConfig.Lambda.Errors.Threshold) t.equal(al.EvaluationPeriods, 2) t.equal(al.TreatMissingData, 'breaching') t.equal(al.ComparisonOperator, 'GreaterThanOrEqualToThreshold') @@ -241,7 +232,7 @@ test('AWS Lambda alarms are created for ALB', (t) => { }) test('Invocation alarms are created if configured', (t) => { - const AlarmProperties = createTestConfig(defaultConfig.alarms, { + const alarmConfig = createTestConfig(defaultConfig.alarms, { Lambda: { Period: 60, Errors: { @@ -264,12 +255,7 @@ test('Invocation alarms are created if configured', (t) => { }) const compiledTemplate = createTestCloudFormationTemplate() - const FunctionAlarmProperties = AlarmProperties.Lambda - for (const funcLogicalId of Object.keys(getResourcesByType('AWS::Lambda::Function', compiledTemplate))) { - FunctionAlarmProperties[funcLogicalId] = AlarmProperties.Lambda - } - - const alarmResources = createLambdaAlarms(FunctionAlarmProperties, testAlarmActionsConfig, compiledTemplate) + const alarmResources = createLambdaAlarms(alarmConfig.Lambda, testAlarmActionsConfig, compiledTemplate) const invocAlarmResources: ResourceType = filterObject( alarmResources, (res) => res.Properties.AlarmName.payload[0].startsWith('Lambda_Invocations') @@ -282,13 +268,13 @@ test('Invocation alarms are created if configured', (t) => { t.equal(al?.Threshold, 900) t.equal(al?.EvaluationPeriods, 1) t.equal(al?.Namespace, 'AWS/Lambda') - t.equal(al?.Period, AlarmProperties.Lambda.Period) + t.equal(al?.Period, alarmConfig.Lambda.Period) } t.end() }) test('Invocation alarms throws if misconfigured (enabled but no threshold set)', (t) => { - const AlarmProperties = createTestConfig(defaultConfig.alarms, { + const alarmConfig = createTestConfig(defaultConfig.alarms, { Lambda: { Period: 60, Errors: { @@ -311,11 +297,7 @@ test('Invocation alarms throws if misconfigured (enabled but no threshold set)', }) const compiledTemplate = createTestCloudFormationTemplate() - const FunctionAlarmProperties = AlarmProperties - for (const funcLogicalId of Object.keys(getResourcesByType('AWS::Lambda::Function', compiledTemplate))) { - FunctionAlarmProperties[funcLogicalId] = AlarmProperties.Lambda - } - createLambdaAlarms(FunctionAlarmProperties, testAlarmActionsConfig, compiledTemplate) + createLambdaAlarms(alarmConfig.Lambda, testAlarmActionsConfig, compiledTemplate) t.end() }) @@ -333,7 +315,7 @@ test('Invocation alarms throws if misconfigured (enabled but no threshold set)', } ].forEach(({ functionName, reason }) => async () => { await test(`IteratorAge alarm is not created if function reference cannot be found due to ${reason}`, (t) => { - const AlarmProperties = createTestConfig(defaultConfig.alarms, { + const alarmConfig = createTestConfig(defaultConfig.alarms, { Lambda: { Period: 60, Errors: { @@ -367,11 +349,7 @@ test('Invocation alarms throws if misconfigured (enabled but no threshold set)', } ) - const FunctionAlarmProperties = AlarmProperties.Lambda - for (const funcLogicalId of Object.keys(getResourcesByType('AWS::Lambda::Function', compiledTemplate))) { - FunctionAlarmProperties[funcLogicalId] = AlarmProperties.Lambda - } - createLambdaAlarms(FunctionAlarmProperties, testAlarmActionsConfig, compiledTemplate) + createLambdaAlarms(alarmConfig.Lambda, testAlarmActionsConfig, compiledTemplate) const alarmResources = getResourcesByType('AWS::CloudWatch::Alarm', compiledTemplate) t.equal(Object.keys(alarmResources).length, 0) t.end() @@ -379,7 +357,7 @@ test('Invocation alarms throws if misconfigured (enabled but no threshold set)', }) test('Lambda alarms are not created when disabled globally', (t) => { - const AlarmProperties = createTestConfig(defaultConfig.alarms, { + const alarmConfig = createTestConfig(defaultConfig.alarms, { Lambda: { enabled: false, // disabled globally Period: 60, @@ -402,11 +380,7 @@ test('Lambda alarms are not created when disabled globally', (t) => { }) const compiledTemplate = createTestCloudFormationTemplate() - const FunctionAlarmProperties = AlarmProperties.Lambda - for (const funcLogicalId of Object.keys(getResourcesByType('AWS::Lambda::Function', compiledTemplate))) { - FunctionAlarmProperties[funcLogicalId] = AlarmProperties.Lambda - } - createLambdaAlarms(FunctionAlarmProperties, testAlarmActionsConfig, compiledTemplate) + createLambdaAlarms(alarmConfig.Lambda, testAlarmActionsConfig, compiledTemplate) const alarmResources = getResourcesByType('AWS::CloudWatch::Alarm', compiledTemplate) t.same({}, alarmResources) @@ -414,7 +388,7 @@ test('Lambda alarms are not created when disabled globally', (t) => { }) test('Lambda alarms are not created when disabled individually', (t) => { - const AlarmProperties = createTestConfig(defaultConfig.alarms, { + const alarmConfig = createTestConfig(defaultConfig.alarms, { Lambda: { enabled: true, // enabled globally Period: 60, @@ -442,11 +416,7 @@ test('Lambda alarms are not created when disabled individually', (t) => { }) const compiledTemplate = createTestCloudFormationTemplate() - const FunctionAlarmProperties = AlarmProperties - for (const funcLogicalId of Object.keys(getResourcesByType('AWS::Lambda::Function', compiledTemplate))) { - FunctionAlarmProperties[funcLogicalId] = AlarmProperties.Lambda - } - createLambdaAlarms(FunctionAlarmProperties, testAlarmActionsConfig, compiledTemplate) + createLambdaAlarms(alarmConfig.Lambda, testAlarmActionsConfig, compiledTemplate) const alarmResources = getResourcesByType('AWS::CloudWatch::Alarm', compiledTemplate) @@ -455,7 +425,7 @@ test('Lambda alarms are not created when disabled individually', (t) => { }) test('AWS Lambda alarms are not created if disabled at function level', (t) => { - const AlarmProperties = createTestConfig(defaultConfig.alarms, { + const alarmConfig = createTestConfig(defaultConfig.alarms, { Lambda: { Invocations: { enabled: true, @@ -469,6 +439,11 @@ test('AWS Lambda alarms are not created if disabled at function level', (t) => { Type: 'AWS::Lambda::Function', Properties: { FunctionName: 'serverless-test-project-dev-simpletest' + }, + Metadata: { + slicWatch: { + enabled: false + } } }, ESM: { @@ -479,34 +454,7 @@ test('AWS Lambda alarms are not created if disabled at function level', (t) => { } } }) - const disabledFunctionAlarmProperties = applyAlarmConfig( - AlarmProperties.Lambda, { - HelloLambdaFunction: { Lambda: { enabled: false } } - }) - createLambdaAlarms(disabledFunctionAlarmProperties, testAlarmActionsConfig, compiledTemplate) - - const alarmResources = getResourcesByType('AWS::CloudWatch::Alarm', compiledTemplate) - t.equal(Object.keys(alarmResources).length, 0) - t.end() -}) - -test('AWS Lambda alarms are not created if function configuration is not provided (e.g. Custom Resource injected functions)', (t) => { - const compiledTemplate = createTestCloudFormationTemplate({ - Resources: { - HelloLambdaFunction: { - Type: 'AWS::Lambda::Function', - Properties: { - FunctionName: 'serverless-test-project-dev-simpletest' - } - } - } - }) - const funcAlarmProperties = { Lambda: { enabled: false } } // No function configuration as in the case where functions are not defined in serverless.yml:functions - const disabledFunctionAlarmProperties = applyAlarmConfig( - funcAlarmProperties.Lambda, { - HelloLambdaFunction: { Lambda: { enabled: false } } - }) - createLambdaAlarms(disabledFunctionAlarmProperties, testAlarmActionsConfig, compiledTemplate) + createLambdaAlarms(alarmConfig.Lambda, testAlarmActionsConfig, compiledTemplate) const alarmResources = getResourcesByType('AWS::CloudWatch::Alarm', compiledTemplate) t.equal(Object.keys(alarmResources).length, 0) @@ -514,16 +462,14 @@ test('AWS Lambda alarms are not created if function configuration is not provide }) test('Duration alarms are created if no timeout is specified', (t) => { - const AlarmProperties = createTestConfig(defaultConfig.alarms, {}) + const alarmConfig = createTestConfig(defaultConfig.alarms, {}) const compiledTemplate = createTestCloudFormationTemplate() - const FunctionAlarmProperties = AlarmProperties.Lambda - for (const [funcLogicalId, resource] of Object.entries(getResourcesByType('AWS::Lambda::Function', compiledTemplate))) { - FunctionAlarmProperties[funcLogicalId] = AlarmProperties.Lambda + for (const resource of Object.values(getResourcesByType('AWS::Lambda::Function', compiledTemplate))) { delete resource.Properties?.Timeout } - const alarmResources = createLambdaAlarms(FunctionAlarmProperties, testAlarmActionsConfig, compiledTemplate) + const alarmResources = createLambdaAlarms(alarmConfig.Lambda, testAlarmActionsConfig, compiledTemplate) const invocAlarmResources = filterObject( alarmResources, (res) => res.Properties.AlarmName.payload[0].startsWith('Lambda_Duration') @@ -531,14 +477,3 @@ test('Duration alarms are created if no timeout is specified', (t) => { t.equal(Object.keys(invocAlarmResources).length, 8) t.end() }) - -test('Lambda alarms are not created if the slic watch config does not exist', (t) => { - const AlarmProperties = createTestConfig(defaultConfig.alarms, {}) - const compiledTemplate = createTestCloudFormationTemplate() - const perLambdaConfig = AlarmProperties - perLambdaConfig.HelloLambdaFunction = AlarmProperties.Lambda - const createdAlarms = createLambdaAlarms(perLambdaConfig, testAlarmActionsConfig, compiledTemplate) - - t.same(Object.keys(createdAlarms), ['slicWatchLambdaErrorsAlarmHelloLambdaFunction', 'slicWatchLambdaThrottlesAlarmHelloLambdaFunction', 'slicWatchLambdaDurationAlarmHelloLambdaFunction']) - t.end() -}) diff --git a/core/dashboards/dashboard-types.ts b/core/dashboards/dashboard-types.ts index 8d627b27..fa098fe6 100644 --- a/core/dashboards/dashboard-types.ts +++ b/core/dashboards/dashboard-types.ts @@ -1,6 +1,6 @@ -import type FunctionProperties from 'cloudform-types/types/lambda/function' +import type { Widget } from 'cloudwatch-dashboard-types' -export type YAxis = 'left' | 'right' +export type YAxisPos = 'left' | 'right' interface TimeRange { start: string @@ -10,171 +10,148 @@ interface TimeRange { export interface MetricDefs { namespace: string metric: string - dimensions: object + dimensions: Record stat: string - yAxis?: YAxis + yAxis?: YAxisPos } -export interface Properties { + +export interface WidgetWithSize extends Omit { + width: number + height: number +} + +export interface MetricProperties { metrics: any[][] title: string view: string region: string period?: number - yAxis?: YAxis + yAxis?: YAxisPos } export interface CreateMetricWidget { type: string - properties: Properties + properties: MetricProperties width: number height: number - yAxis?: YAxis -} - -export interface Widgets { - enabled?: boolean - metricPeriod?: number - width?: number - height?: number - yAxis?: YAxis - Statistic?: string[] - Lambda?: LambdaDashboardBodyProperties - ApiGateway?: ApiGwDashboardBodyProperties - States?: SfDashboardBodyProperties - DynamoDB?: DynamoDbDashboardBodyProperties - Kinesis?: KinesisDashboardBodyProperties - SQS?: SqsDashboardBodyProperties - ECS?: EcsDashboardBodyProperties - SNS?: SnsDashboardBodyProperties - Events?: RuleDashboardBodyProperties - ApplicationELB?: AlbDashboardBodyProperties - ApplicationELBTarget?: AlbTargetDashboardBodyProperties - AppSync?: AppSyncDashboardBodyProperties -} - -export interface SlicWatchDashboardConfig { - enabled?: boolean - timeRange?: TimeRange - widgets: Widgets + yAxis?: YAxisPos } -export interface DashboardBodyProperties { - enabled?: boolean - metricPeriod?: number - width?: number - height?: number - yAxis?: YAxis - Statistic?: string[] +export interface WidgetMetricProperties { + enabled: boolean + metricPeriod: number + width: number + height: number + yAxis: YAxisPos + Statistic: string[] } -export interface ServiceDashConfig { - DashboardBodyProperties?: DashboardBodyProperties - widgets?: Widgets +export interface Widgets extends WidgetMetricProperties { + Lambda: LambdaDashboardProperties + ApiGateway: ApiGwDashboardProperties + States: SfDashboardProperties + DynamoDB: DynamoDbDashboardProperties + Kinesis: KinesisDashboardProperties + SQS: SqsDashboardProperties + ECS: EcsDashboardProperties + SNS: SnsDashboardProperties + Events: RuleDashboardProperties + ApplicationELB: AlbDashboardProperties + ApplicationELBTarget: AlbTargetDashboardProperties + AppSync: AppSyncDashboardProperties } -export interface LambdaDashboardBodyProperties { - Errors: DashboardBodyProperties - Throttles: DashboardBodyProperties - Duration: DashboardBodyProperties - Invocations: DashboardBodyProperties - ConcurrentExecutions: DashboardBodyProperties - IteratorAge: DashboardBodyProperties +type NestedPartial = { + [K in keyof T]?: T[K] extends Array ? Array> : NestedPartial } -export interface ApiGwDashboardBodyProperties { - '5XXError': DashboardBodyProperties - '4XXError': DashboardBodyProperties - Latency: DashboardBodyProperties - Count: DashboardBodyProperties +export interface SlicWatchDashboardConfig extends WidgetMetricProperties { + timeRange: TimeRange + widgets: Widgets } -export interface SfDashboardBodyProperties { - ExecutionsFailed: DashboardBodyProperties - ExecutionThrottled: DashboardBodyProperties - ExecutionsTimedOut: DashboardBodyProperties -} +export type SlicWatchInputDashboardConfig = NestedPartial -export interface DynamoDbDashboardBodyProperties { - ReadThrottleEvents: DashboardBodyProperties - WriteThrottleEvents: DashboardBodyProperties +export interface LambdaDashboardProperties extends WidgetMetricProperties { + Errors: WidgetMetricProperties + Throttles: WidgetMetricProperties + Duration: WidgetMetricProperties + Invocations: WidgetMetricProperties + ConcurrentExecutions: WidgetMetricProperties + IteratorAge: WidgetMetricProperties } -export interface KinesisDashboardBodyProperties { - 'GetRecords.IteratorAgeMilliseconds': DashboardBodyProperties - ReadProvisionedThroughputExceeded: DashboardBodyProperties - WriteProvisionedThroughputExceeded: DashboardBodyProperties - 'PutRecord.Success': DashboardBodyProperties - 'PutRecords.Success': DashboardBodyProperties - 'GetRecords.Success': DashboardBodyProperties +export interface ApiGwDashboardProperties extends WidgetMetricProperties { + '5XXError': WidgetMetricProperties + '4XXError': WidgetMetricProperties + Latency: WidgetMetricProperties + Count: WidgetMetricProperties } -export interface SqsDashboardBodyProperties { - NumberOfMessagesSent: DashboardBodyProperties - NumberOfMessagesReceived: DashboardBodyProperties - NumberOfMessagesDeleted: DashboardBodyProperties - ApproximateAgeOfOldestMessage: DashboardBodyProperties - ApproximateNumberOfMessagesVisible: DashboardBodyProperties +export interface SfDashboardProperties extends WidgetMetricProperties { + ExecutionsFailed: WidgetMetricProperties + ExecutionThrottled: WidgetMetricProperties + ExecutionsTimedOut: WidgetMetricProperties } -export interface EcsDashboardBodyProperties { - enabled?: boolean - MemoryUtilization: DashboardBodyProperties - CPUUtilization: DashboardBodyProperties +export interface DynamoDbDashboardProperties extends WidgetMetricProperties { + ReadThrottleEvents: WidgetMetricProperties + WriteThrottleEvents: WidgetMetricProperties } -export interface SnsDashboardBodyProperties { - 'NumberOfNotificationsFilteredOut-InvalidAttributes': DashboardBodyProperties - NumberOfNotificationsFailed: DashboardBodyProperties +export interface KinesisDashboardProperties extends WidgetMetricProperties { + 'GetRecords.IteratorAgeMilliseconds': WidgetMetricProperties + ReadProvisionedThroughputExceeded: WidgetMetricProperties + WriteProvisionedThroughputExceeded: WidgetMetricProperties + 'PutRecord.Success': WidgetMetricProperties + 'PutRecords.Success': WidgetMetricProperties + 'GetRecords.Success': WidgetMetricProperties } -export interface RuleDashboardBodyProperties { - FailedInvocations: DashboardBodyProperties - ThrottledRules: DashboardBodyProperties - Invocations: DashboardBodyProperties +export interface SqsDashboardProperties extends WidgetMetricProperties { + NumberOfMessagesSent: WidgetMetricProperties + NumberOfMessagesReceived: WidgetMetricProperties + NumberOfMessagesDeleted: WidgetMetricProperties + ApproximateAgeOfOldestMessage: WidgetMetricProperties + ApproximateNumberOfMessagesVisible: WidgetMetricProperties } -export interface AlbDashboardBodyProperties { - HTTPCode_ELB_5XX_Count: DashboardBodyProperties - RejectedConnectionCount: DashboardBodyProperties +export interface EcsDashboardProperties extends WidgetMetricProperties { + MemoryUtilization: WidgetMetricProperties + CPUUtilization: WidgetMetricProperties } -export interface AlbTargetDashboardBodyProperties { - HTTPCode_Target_5XX_Count: DashboardBodyProperties - UnHealthyHostCount: DashboardBodyProperties - LambdaInternalError: DashboardBodyProperties - LambdaUserError: DashboardBodyProperties +export interface SnsDashboardProperties extends WidgetMetricProperties { + 'NumberOfNotificationsFilteredOut-InvalidAttributes': WidgetMetricProperties + NumberOfNotificationsFailed: WidgetMetricProperties } -export interface AppSyncDashboardBodyProperties { - '5XXError': DashboardBodyProperties - '4XXError': DashboardBodyProperties - Latency: DashboardBodyProperties - Requests: DashboardBodyProperties - ConnectServerError: DashboardBodyProperties - DisconnectServerError: DashboardBodyProperties - SubscribeServerError: DashboardBodyProperties - UnsubscribeServerError: DashboardBodyProperties - PublishDataMessageServerError: DashboardBodyProperties +export interface RuleDashboardProperties extends WidgetMetricProperties { + FailedInvocations: WidgetMetricProperties + ThrottledRules: WidgetMetricProperties + Invocations: WidgetMetricProperties } -// Lambda resources +export interface AlbDashboardProperties extends WidgetMetricProperties { + HTTPCode_ELB_5XX_Count: WidgetMetricProperties + RejectedConnectionCount: WidgetMetricProperties +} -export interface FunctionResources { - Type: string - Properties: FunctionProperties - DependsOn: string[] +export interface AlbTargetDashboardProperties extends WidgetMetricProperties { + HTTPCode_Target_5XX_Count: WidgetMetricProperties + UnHealthyHostCount: WidgetMetricProperties + LambdaInternalError: WidgetMetricProperties + LambdaUserError: WidgetMetricProperties } -export interface FunctionDashboardConfigs { - HelloLambdaFunction?: FunctionResources - PingLambdaFunction?: FunctionResources - ThrottlerLambdaFunction?: FunctionResources - DriveStreamLambdaFunction?: FunctionResources - DriveQueueLambdaFunction?: FunctionResources - DriveTableLambdaFunction?: FunctionResources - StreamProcessorLambdaFunction?: FunctionResources - HttpGetterLambdaFunction?: FunctionResources - SubscriptionHandlerLambdaFunction?: FunctionResources - EventsRuleLambdaFunction?: FunctionResources - AlbEventLambdaFunction?: FunctionResources +export interface AppSyncDashboardProperties extends WidgetMetricProperties { + '5XXError': WidgetMetricProperties + '4XXError': WidgetMetricProperties + Latency: WidgetMetricProperties + Requests: WidgetMetricProperties + ConnectServerError: WidgetMetricProperties + DisconnectServerError: WidgetMetricProperties + SubscribeServerError: WidgetMetricProperties + UnsubscribeServerError: WidgetMetricProperties + PublishDataMessageServerError: WidgetMetricProperties } diff --git a/core/dashboards/dashboard.ts b/core/dashboards/dashboard.ts index 204972c8..bc0abbfd 100644 --- a/core/dashboards/dashboard.ts +++ b/core/dashboards/dashboard.ts @@ -1,33 +1,31 @@ -import type { Entries } from 'type-fest' import type Template from 'cloudform-types/types/template' +import * as cwd from 'cloudwatch-dashboard-types' import { cascade } from '../inputs/cascading-config' import { getResourcesByType, getEventSourceMappingFunctions, addResource } from '../cf-template' import type { ResourceType } from '../cf-template' -import type { CreateMetricWidget, DashboardBodyProperties, FunctionDashboardConfigs, MetricDefs, ServiceDashConfig, SlicWatchDashboardConfig, Widgets } from './dashboard-types' +import type { + WidgetMetricProperties, MetricDefs, SlicWatchDashboardConfig, SlicWatchInputDashboardConfig, + Widgets, WidgetWithSize +} from './dashboard-types' import { findLoadBalancersForTargetGroup } from '../alarms/alb-target-group' import { resolveRestApiNameForSub } from '../alarms/api-gateway' -import { resolveEcsClusterNameForSub, resolveGraphQLId, resolveLoadBalancerFullNameForSub, resolveTargetGroupFullNameForSub } from './dashboard-utils' +import { + resolveEcsClusterNameForSub, resolveGraphQLId, + resolveLoadBalancerFullNameForSub, resolveTargetGroupFullNameForSub +} from './dashboard-utils' import { getLogger } from '../logging' -declare global { - interface ObjectConstructor { - // eslint-disable-next-line @typescript-eslint/method-signature-style - entries(obj: T): Entries - } -} - const MAX_WIDTH = 24 const logger = getLogger() /** * @param {*} dashboardConfig The global plugin dashboard configuration - * @param {*} functionDashboardConfigs The dashboard configuration override by function name * @param {*} compiledTemplate A CloudFormation template object */ -export default function addDashboard (dashboardConfig: SlicWatchDashboardConfig, functionDashboardConfigs: FunctionDashboardConfigs, compiledTemplate: Template) { +export default function addDashboard (dashboardConfig: SlicWatchInputDashboardConfig, compiledTemplate: Template) { const { timeRange, widgets: { @@ -96,7 +94,7 @@ export default function addDashboard (dashboardConfig: SlicWatchDashboardConfig, ]) if (positionedWidgets.length > 0) { - const dash = { start: timeRange?.start, end: timeRange?.end, widgets: positionedWidgets } + const dash: cwd.Dashboard = { start: timeRange?.start, end: timeRange?.end, widgets: positionedWidgets } const dashboardResource = { Type: 'AWS::CloudWatch::Dashboard', Properties: { @@ -116,8 +114,8 @@ export default function addDashboard (dashboardConfig: SlicWatchDashboardConfig, * @param {Array.} metricDefs The metric definitions to render * @param {Object} config Cascaded widget/metric configuration */ - function createMetricWidget (title: string, metricDefs: MetricDefs[], config: DashboardBodyProperties): CreateMetricWidget { - const metrics = metricDefs.map( + function createMetricWidget (title: string, metricDefs: MetricDefs[], config: WidgetMetricProperties): WidgetWithSize { + const metrics: cwd.WidgetMetric[] = metricDefs.map( ({ namespace, metric, dimensions, stat, yAxis }) => [ namespace, metric, @@ -125,20 +123,20 @@ export default function addDashboard (dashboardConfig: SlicWatchDashboardConfig, (acc: string[], [name, value]) => [...acc, name, value], [] ), - { stat, yAxis } + { stat: stat as cwd.Statistic, yAxis: yAxis as cwd.YAxisPosition } ] ) return { - type: 'metric', + type: cwd.WidgetType.Metric, properties: { metrics, title, - view: 'timeSeries', + view: cwd.MetricViewType.TimeSeries, region: '${AWS::Region}', period: config.metricPeriod }, - width: config.width as number, - height: config.height as number + width: config.width, + height: config.height } } @@ -149,56 +147,62 @@ export default function addDashboard (dashboardConfig: SlicWatchDashboardConfig, * Object with CloudFormation Lambda Function resources by resource name * eventSourceMappingFunctionResourceNames Names of Lambda function resources that are linked to EventSourceMappings */ - function createLambdaWidgets (functionResources: FunctionDashboardConfigs, eventSourceMappingFunctionResourceNames: string[]): CreateMetricWidget[] { + function createLambdaWidgets (functionResources: ResourceType, eventSourceMappingFunctionResourceNames: string[]): WidgetWithSize[] { const lambdaWidgets: any = [] + const configPerFunctionResource: Record = {} + for (const [logicalId, resource] of Object.entries(functionResources)) { + configPerFunctionResource[logicalId] = { + ...lambdaDashConfig, + ...cascade(resource?.Metadata?.slicWatch?.dashboard ?? {}) as SlicWatchDashboardConfig + } + } + if (Object.keys(functionResources).length > 0) { for (const [metric, metricConfig] of Object.entries(getConfiguredMetrics(lambdaDashConfig))) { - if (metricConfig?.enabled !== false) { - if (metric !== 'IteratorAge' as any) { - for (const stat of metricConfig?.Statistic ?? []) { - const metricDefs: MetricDefs[] = [] - for (const logicalId of Object.keys(functionResources)) { - const functionConfig = functionDashboardConfigs[logicalId] ?? {} - const functionMetricConfig = functionConfig[metric] ?? {} - if (functionConfig.enabled !== false && (functionMetricConfig.enabled !== false)) { - metricDefs.push({ - namespace: 'AWS/Lambda', - metric, - dimensions: { FunctionName: `\${${logicalId}}` }, - stat - }) - } + if (metric !== 'IteratorAge' as any) { + for (const stat of metricConfig?.Statistic ?? []) { + const metricDefs: MetricDefs[] = [] + for (const funcLogicalId of Object.keys(functionResources)) { + const funcConfig = configPerFunctionResource[funcLogicalId] + const metricConfig = funcConfig[metric] + if (metricConfig.enabled !== false) { + metricDefs.push({ + namespace: 'AWS/Lambda', + metric, + dimensions: { FunctionName: `\${${funcLogicalId}}` }, + stat: stat as cwd.Statistic + }) } + } - if (metricDefs.length > 0) { - const metricStatWidget = createMetricWidget( - `Lambda ${metric} ${stat} per Function`, - metricDefs, - metricConfig as Widgets - ) - lambdaWidgets.push(metricStatWidget) - } + if (metricDefs.length > 0) { + const metricStatWidget = createMetricWidget( + `Lambda ${metric} ${stat} per Function`, + metricDefs, + metricConfig as Widgets + ) + lambdaWidgets.push(metricStatWidget) } - } else { - for (const logicalId of eventSourceMappingFunctionResourceNames) { - // Add IteratorAge alarm if the Lambda function has an EventSourceMapping trigger - const functionConfig = functionDashboardConfigs[logicalId] ?? {} - const functionMetricConfig = functionConfig[metric] ?? {} - if (functionConfig.enabled !== false && (functionMetricConfig.enabled !== false)) { - const stats: string[] = [] - metricConfig?.Statistic?.forEach(a => stats.push(a)) - const iteratorAgeWidget = createMetricWidget( - `Lambda IteratorAge \${${logicalId}} ${stats?.join(',')}`, - stats.map(stat => ({ - namespace: 'AWS/Lambda', - metric: 'IteratorAge', - dimensions: { FunctionName: `\${${logicalId}}` }, - stat - })), - metricConfig as Widgets - ) - lambdaWidgets.push(iteratorAgeWidget) - } + } + } else { + for (const funcLogicalId of eventSourceMappingFunctionResourceNames) { + // Add IteratorAge alarm if the Lambda function has an EventSourceMapping trigger + const funcConfig = configPerFunctionResource[funcLogicalId] + const functionMetricConfig = funcConfig[metric] ?? {} + if (functionMetricConfig.enabled !== false) { + const stats: string[] = [] + metricConfig?.Statistic?.forEach(a => stats.push(a)) + const iteratorAgeWidget = createMetricWidget( + `Lambda IteratorAge \${${funcLogicalId}} ${stats?.join(',')}`, + stats.map(stat => ({ + namespace: 'AWS/Lambda', + metric: 'IteratorAge', + dimensions: { FunctionName: `\${${funcLogicalId}}` }, + stat: stat as cwd.Statistic + })), + metricConfig as Widgets + ) + lambdaWidgets.push(iteratorAgeWidget) } } } @@ -212,11 +216,13 @@ export default function addDashboard (dashboardConfig: SlicWatchDashboardConfig, * These config objects mix cascaded config literals (like `alarmPeriod: 300`) and metric * configurations (like `Errors: { Statistic: ['Sum'] }`) so here we extract the latter. * - * @param serviceDashConfig t The config object for a specific service within the dashboard - * @returns {Iterable} An iterable over the alarm-config Object entries + * @param serviceDashConfig The config object for a specific service within the dashboard + * @returns An object with the metric's properties by metric name */ - function getConfiguredMetrics (serviceDashConfig): ServiceDashConfig { - return Object.fromEntries(Object.entries(serviceDashConfig).filter((_, metricConfig) => typeof metricConfig !== 'object')) + function getConfiguredMetrics (serviceDashConfig: WidgetMetricProperties): Record { + return Object.fromEntries(Object.entries(serviceDashConfig).filter( + ([_, metricConfig]) => typeof metricConfig === 'object') + ) as unknown as Record } /** @@ -226,13 +232,13 @@ export default function addDashboard (dashboardConfig: SlicWatchDashboardConfig, * Object of CloudFormation RestApi resources by resource name */ - function createApiWidgets (apiResources: ResourceType): CreateMetricWidget[] { - const apiWidgets: CreateMetricWidget[] = [] + function createApiWidgets (apiResources: ResourceType): WidgetWithSize[] { + const apiWidgets: WidgetWithSize[] = [] for (const [resourceName, res] of Object.entries(apiResources)) { const apiName: string = resolveRestApiNameForSub(res, resourceName) // e.g., ${AWS::Stack} (Ref), ${OtherResource.Name} (GetAtt) const widgetMetrics: MetricDefs[] = [] for (const [metric, metricConfig] of Object.entries(getConfiguredMetrics(apiGwDashConfig))) { - if (metricConfig?.enabled !== false) { + if (metricConfig.enabled) { for (const stat of metricConfig?.Statistic ?? []) { widgetMetrics.push({ namespace: 'AWS/ApiGateway', @@ -248,7 +254,7 @@ export default function addDashboard (dashboardConfig: SlicWatchDashboardConfig, const metricStatWidget = createMetricWidget( `${metric} API ${apiName}`, widgetMetrics, - apiGwDashConfig as Widgets + apiGwDashConfig ) apiWidgets.push(metricStatWidget) } @@ -263,12 +269,12 @@ export default function addDashboard (dashboardConfig: SlicWatchDashboardConfig, * * Object of Step Function State Machine resources by resource name */ - function createStateMachineWidgets (smResources: ResourceType): CreateMetricWidget[] { - const smWidgets: CreateMetricWidget[] = [] + function createStateMachineWidgets (smResources: ResourceType): WidgetWithSize[] { + const smWidgets: WidgetWithSize[] = [] for (const [logicalId] of Object.entries(smResources)) { const widgetMetrics: MetricDefs[] = [] for (const [metric, metricConfig] of Object.entries(getConfiguredMetrics(sfDashConfig))) { - if (metricConfig?.enabled !== false) { + if (metricConfig.enabled) { for (const stat of metricConfig?.Statistic ?? []) { widgetMetrics.push({ namespace: 'AWS/States', @@ -285,7 +291,7 @@ export default function addDashboard (dashboardConfig: SlicWatchDashboardConfig, const metricStatWidget = createMetricWidget( `\${${logicalId}.Name} Step Function Executions`, widgetMetrics, - sfDashConfig as Widgets + sfDashConfig ) smWidgets.push(metricStatWidget) } @@ -298,12 +304,12 @@ export default function addDashboard (dashboardConfig: SlicWatchDashboardConfig, * * Object of DynamoDB table resources by resource name */ - function createDynamoDbWidgets (tableResources: ResourceType): CreateMetricWidget[] { - const ddbWidgets: CreateMetricWidget[] = [] + function createDynamoDbWidgets (tableResources: ResourceType): WidgetWithSize[] { + const ddbWidgets: WidgetWithSize[] = [] for (const [logicalId, res] of Object.entries(tableResources)) { const widgetMetrics: MetricDefs[] = [] for (const [metric, metricConfig] of Object.entries(getConfiguredMetrics(dynamoDbDashConfig))) { - if (metricConfig?.enabled !== false) { + if (metricConfig.enabled) { for (const stat of metricConfig?.Statistic ?? []) { widgetMetrics.push({ namespace: 'AWS/DynamoDB', @@ -318,7 +324,7 @@ export default function addDashboard (dashboardConfig: SlicWatchDashboardConfig, const metricStatWidget = createMetricWidget( `${metric} Table $\{${logicalId}}`, widgetMetrics, - dynamoDbDashConfig as Widgets + dynamoDbDashConfig ) ddbWidgets.push(metricStatWidget) } @@ -339,7 +345,7 @@ export default function addDashboard (dashboardConfig: SlicWatchDashboardConfig, const metricStatWidget = createMetricWidget( `${metric} GSI ${gsiName} in \${${logicalId}}`, widgetMetrics, - dynamoDbDashConfig as Widgets + dynamoDbDashConfig ) ddbWidgets.push(metricStatWidget) } @@ -355,8 +361,8 @@ export default function addDashboard (dashboardConfig: SlicWatchDashboardConfig, * * Object with CloudFormation Kinesis Data Stream resources by resource name */ - function createStreamWidgets (streamResources: ResourceType): CreateMetricWidget[] { - const streamWidgets: CreateMetricWidget[] = [] + function createStreamWidgets (streamResources: ResourceType): WidgetWithSize[] { + const streamWidgets: WidgetWithSize[] = [] const metricGroups = { IteratorAge: ['GetRecords.IteratorAgeMilliseconds'], @@ -370,7 +376,7 @@ export default function addDashboard (dashboardConfig: SlicWatchDashboardConfig, const widgetMetrics: MetricDefs[] = [] for (const metric of metrics) { const metricConfig = metricConfigs[metric] - if (metricConfig.enabled as boolean) { + if (metricConfig.enabled) { for (const stat of metricConfig.Statistic) { widgetMetrics.push({ namespace: 'AWS/Kinesis', @@ -385,7 +391,7 @@ export default function addDashboard (dashboardConfig: SlicWatchDashboardConfig, streamWidgets.push(createMetricWidget( `${group} $\{${logicalId}} Kinesis`, widgetMetrics, - kinesisDashConfig as Widgets + kinesisDashConfig )) } } @@ -397,8 +403,8 @@ export default function addDashboard (dashboardConfig: SlicWatchDashboardConfig, * Create a set of CloudWatch Dashboard widgets for the SQS resources provided * Object with CloudFormation SQS resources by resource name */ - function createQueueWidgets (queueResources: ResourceType): CreateMetricWidget[] { - const queueWidgets: CreateMetricWidget[] = [] + function createQueueWidgets (queueResources: ResourceType): WidgetWithSize[] { + const queueWidgets: WidgetWithSize[] = [] const metricGroups = { Messages: ['NumberOfMessagesSent', 'NumberOfMessagesReceived', 'NumberOfMessagesDeleted'], @@ -412,7 +418,7 @@ export default function addDashboard (dashboardConfig: SlicWatchDashboardConfig, const widgetMetrics: MetricDefs[] = [] for (const metric of metrics) { const metricConfig = metricConfigs[metric] - if (metricConfig.enabled !== false) { + if (metricConfig.enabled) { for (const stat of metricConfig.Statistic) { widgetMetrics.push({ namespace: 'AWS/SQS', @@ -429,7 +435,7 @@ export default function addDashboard (dashboardConfig: SlicWatchDashboardConfig, queueWidgets.push(createMetricWidget( `${group} \${${logicalId}.QueueName} SQS`, widgetMetrics, - sqsDashConfig as Widgets + sqsDashConfig )) } } @@ -443,15 +449,15 @@ export default function addDashboard (dashboardConfig: SlicWatchDashboardConfig, * * Object of ECS Service resources by resource name */ - function createEcsWidgets (ecsServiceResources: ResourceType): CreateMetricWidget[] { - const ecsWidgets: CreateMetricWidget[] = [] + function createEcsWidgets (ecsServiceResources: ResourceType): WidgetWithSize[] { + const ecsWidgets: WidgetWithSize[] = [] for (const [logicalId, res] of Object.entries(ecsServiceResources)) { const clusterName = resolveEcsClusterNameForSub(res.Properties?.Cluster) const widgetMetrics: MetricDefs[] = [] for (const [metric, metricConfig] of Object.entries(getConfiguredMetrics(ecsDashConfig))) { - if (metricConfig?.enabled !== false) { - for (const stat of metricConfig?.Statistic ?? []) { + if (metricConfig.enabled) { + for (const stat of metricConfig.Statistic) { widgetMetrics.push({ namespace: 'AWS/ECS', metric, @@ -468,7 +474,7 @@ export default function addDashboard (dashboardConfig: SlicWatchDashboardConfig, const metricStatWidget = createMetricWidget( `ECS Service \${${logicalId}.Name}`, widgetMetrics, - ecsDashConfig as Widgets + ecsDashConfig ) ecsWidgets.push(metricStatWidget) } @@ -481,12 +487,12 @@ export default function addDashboard (dashboardConfig: SlicWatchDashboardConfig, * * Object of SNS Service resources by resource name */ - function createTopicWidgets (topicResources: ResourceType): CreateMetricWidget[] { - const topicWidgets: CreateMetricWidget[] = [] + function createTopicWidgets (topicResources: ResourceType): WidgetWithSize[] { + const topicWidgets: WidgetWithSize[] = [] for (const logicalId of Object.keys(topicResources)) { const widgetMetrics: MetricDefs[] = [] for (const [metric, metricConfig] of Object.entries(getConfiguredMetrics(snsDashConfig))) { - if (metricConfig?.enabled !== false) { + if (metricConfig.enabled) { for (const stat of metricConfig?.Statistic ?? []) { widgetMetrics.push({ namespace: 'AWS/SNS', @@ -503,7 +509,7 @@ export default function addDashboard (dashboardConfig: SlicWatchDashboardConfig, const metricStatWidget = createMetricWidget( `SNS Topic \${${logicalId}.TopicName}`, widgetMetrics, - snsDashConfig as Widgets + snsDashConfig ) topicWidgets.push(metricStatWidget) } @@ -516,12 +522,12 @@ export default function addDashboard (dashboardConfig: SlicWatchDashboardConfig, * * Object of EventBridge Service resources by resource name */ - function createRuleWidgets (ruleResources: ResourceType): CreateMetricWidget[] { - const ruleWidgets: CreateMetricWidget[] = [] + function createRuleWidgets (ruleResources: ResourceType): WidgetWithSize[] { + const ruleWidgets: WidgetWithSize[] = [] for (const [logicalId] of Object.entries(ruleResources)) { const widgetMetrics: MetricDefs[] = [] for (const [metric, metricConfig] of Object.entries(getConfiguredMetrics(ruleDashConfig))) { - if (metricConfig?.enabled !== false) { + if (metricConfig.enabled) { for (const stat of metricConfig?.Statistic ?? []) { widgetMetrics.push({ namespace: 'AWS/Events', @@ -536,7 +542,7 @@ export default function addDashboard (dashboardConfig: SlicWatchDashboardConfig, const metricStatWidget = createMetricWidget( `EventBridge Rule \${${logicalId}}`, widgetMetrics, - ruleDashConfig as Widgets + ruleDashConfig ) ruleWidgets.push(metricStatWidget) } @@ -549,15 +555,15 @@ export default function addDashboard (dashboardConfig: SlicWatchDashboardConfig, * * Object of Application Load Balancer Service resources by resource name */ - function createLoadBalancerWidgets (loadBalancerResources: ResourceType): CreateMetricWidget[] { - const loadBalancerWidgets: CreateMetricWidget[] = [] + function createLoadBalancerWidgets (loadBalancerResources: ResourceType): WidgetWithSize[] { + const loadBalancerWidgets: WidgetWithSize[] = [] for (const [logicalId] of Object.entries(loadBalancerResources)) { const loadBalancerName = `\${${logicalId}.LoadBalancerName}` const loadBalancerFullName = resolveLoadBalancerFullNameForSub(logicalId) const widgetMetrics: MetricDefs[] = [] for (const [metric, metricConfig] of Object.entries(getConfiguredMetrics(albDashConfig))) { - if (metricConfig?.enabled !== false) { + if (metricConfig.enabled) { for (const stat of metricConfig?.Statistic ?? []) { widgetMetrics.push({ namespace: 'AWS/ApplicationELB', @@ -574,7 +580,7 @@ export default function addDashboard (dashboardConfig: SlicWatchDashboardConfig, const metricStatWidget = createMetricWidget( `ALB ${loadBalancerName}`, widgetMetrics, - albDashConfig as Widgets + albDashConfig ) loadBalancerWidgets.push(metricStatWidget) } @@ -588,8 +594,8 @@ export default function addDashboard (dashboardConfig: SlicWatchDashboardConfig, * Object of Application Load Balancer Service Target Group resources by resource name * The full CloudFormation template instance used to look up associated listener and ALB resources */ - function createTargetGroupWidgets (targetGroupResources: ResourceType, compiledTemplate: Template): CreateMetricWidget[] { - const targetGroupWidgets: CreateMetricWidget[] = [] + function createTargetGroupWidgets (targetGroupResources: ResourceType, compiledTemplate: Template): WidgetWithSize[] { + const targetGroupWidgets: WidgetWithSize[] = [] for (const [tgLogicalId, targetGroupResource] of Object.entries(targetGroupResources)) { const loadBalancerLogicalIds = findLoadBalancersForTargetGroup(tgLogicalId, compiledTemplate) for (const loadBalancerLogicalId of loadBalancerLogicalIds) { @@ -597,7 +603,7 @@ export default function addDashboard (dashboardConfig: SlicWatchDashboardConfig, const loadBalancerFullName = `\${${loadBalancerLogicalId}.LoadBalancerFullName}` const widgetMetrics: MetricDefs[] = [] for (const [metric, metricConfig] of Object.entries(getConfiguredMetrics(albTargetDashConfig))) { - if ((metricConfig?.enabled !== false) && + if (metricConfig.enabled && (targetGroupResource.Properties?.TargetType === 'lambda' || !['LambdaUserError', 'LambdaInternalError'].includes(metric)) ) { for (const stat of metricConfig?.Statistic ?? []) { @@ -617,7 +623,7 @@ export default function addDashboard (dashboardConfig: SlicWatchDashboardConfig, const metricStatWidget = createMetricWidget( `Target Group \${${loadBalancerLogicalId}.LoadBalancerName}/\${${tgLogicalId}.TargetGroupName}`, widgetMetrics, - albTargetDashConfig as Widgets + albTargetDashConfig ) targetGroupWidgets.push(metricStatWidget) } @@ -631,8 +637,8 @@ export default function addDashboard (dashboardConfig: SlicWatchDashboardConfig, * * Object of AppSync Service resources by resource name */ - function createAppSyncWidgets (appSyncResources: ResourceType): CreateMetricWidget[] { - const appSyncWidgets: CreateMetricWidget[] = [] + function createAppSyncWidgets (appSyncResources: ResourceType): WidgetWithSize[] { + const appSyncWidgets: WidgetWithSize[] = [] const metricGroups = { API: ['5XXError', '4XXError', 'Latency', 'Requests'], 'Real-time Subscriptions': ['ConnectServerError', 'DisconnectServerError', 'SubscribeServerError', 'UnsubscribeServerError', 'PublishDataMessageServerError'] @@ -645,8 +651,8 @@ export default function addDashboard (dashboardConfig: SlicWatchDashboardConfig, for (const [group, metrics] of Object.entries(metricGroups)) { const widgetMetrics: MetricDefs[] = [] for (const metric of metrics) { - const metricConfig: DashboardBodyProperties | Widgets = metricConfigs[metric] - if (metricConfig?.enabled !== false) { + const metricConfig: WidgetMetricProperties | Widgets = metricConfigs[metric] + if (metricConfig.enabled) { const stats: string[] = [] metricConfig?.Statistic?.forEach(stat => stats.push(stat)) for (const stat of stats) { @@ -654,8 +660,8 @@ export default function addDashboard (dashboardConfig: SlicWatchDashboardConfig, namespace: 'AWS/AppSync', metric, dimensions: { GraphQLAPIId: graphQLAPIId }, - stat, - yAxis: metricConfig.yAxis + stat: stat as cwd.Statistic, + yAxis: metricConfig.yAxis as cwd.YAxisPosition }) } } @@ -664,7 +670,7 @@ export default function addDashboard (dashboardConfig: SlicWatchDashboardConfig, appSyncWidgets.push(createMetricWidget( `AppSync ${group} ${appSyncResourceName}`, widgetMetrics, - sqsDashConfig as Widgets + sqsDashConfig )) } } @@ -679,7 +685,7 @@ export default function addDashboard (dashboardConfig: SlicWatchDashboardConfig, * A set of dashboard widgets * A set of dashboard widgets with layout properties set */ - function layOutWidgets (widgets: CreateMetricWidget[]) { + function layOutWidgets (widgets: WidgetWithSize[]) { let x = 0 let y = 0 diff --git a/core/dashboards/tests/dashboard.test.ts b/core/dashboards/tests/dashboard.test.ts index 42463429..900d5180 100644 --- a/core/dashboards/tests/dashboard.test.ts +++ b/core/dashboards/tests/dashboard.test.ts @@ -5,14 +5,13 @@ import addDashboard from '../dashboard' import defaultConfig from '../../inputs/default-config' import { createTestCloudFormationTemplate, defaultCfTemplate, albCfTemplate, appSyncCfTemplate } from '../../tests/testing-utils' -import { getResourcesByType } from '../../cf-template' +import { type ResourceType, getResourcesByType } from '../../cf-template' const lambdaMetrics = ['Errors', 'Duration', 'IteratorAge', 'Invocations', 'ConcurrentExecutions', 'Throttles'] -const emptyFuncConfigs = {} test('An empty template creates no dashboard', (t) => { const compiledTemplate = createTestCloudFormationTemplate({ Resources: {} }) - addDashboard(defaultConfig.dashboard, emptyFuncConfigs, compiledTemplate) + addDashboard(defaultConfig.dashboard, compiledTemplate) const dashResources = getResourcesByType('AWS::CloudWatch::Dashboard', compiledTemplate) t.equal(Object.keys(dashResources).length, 0) @@ -21,7 +20,7 @@ test('An empty template creates no dashboard', (t) => { test('A dashboard includes metrics', (t) => { const compiledTemplate = createTestCloudFormationTemplate() - addDashboard(defaultConfig.dashboard, emptyFuncConfigs, compiledTemplate) + addDashboard(defaultConfig.dashboard, compiledTemplate) const dashResources = getResourcesByType('AWS::CloudWatch::Dashboard', compiledTemplate) t.equal(Object.keys(dashResources).length, 1) const [, dashResource] = Object.entries(dashResources)[0] @@ -258,7 +257,7 @@ test('A dashboard includes metrics', (t) => { test('A dashboard includes metrics for ALB', (t) => { const compiledTemplate = createTestCloudFormationTemplate((albCfTemplate)) - addDashboard(defaultConfig.dashboard, emptyFuncConfigs, compiledTemplate) + addDashboard(defaultConfig.dashboard, compiledTemplate) const dashResources = getResourcesByType('AWS::CloudWatch::Dashboard', compiledTemplate) t.equal(Object.keys(dashResources).length, 1) const [, dashResource] = Object.entries(dashResources)[0] @@ -316,7 +315,7 @@ test('A dashboard includes metrics for ALB', (t) => { dashConfig.widgets[service].enabled = false } const compiledTemplate = createTestCloudFormationTemplate((appSyncCfTemplate)) - addDashboard(dashConfig, emptyFuncConfigs, compiledTemplate) + addDashboard(dashConfig, compiledTemplate) const dashResources = getResourcesByType('AWS::CloudWatch::Dashboard', compiledTemplate) t.same(dashResources, {}) t.end() @@ -329,7 +328,7 @@ test('A dashboard includes metrics for ALB', (t) => { dashConfig.widgets[service].enabled = false } const compiledTemplate = createTestCloudFormationTemplate((albCfTemplate)) - addDashboard(dashConfig, emptyFuncConfigs, compiledTemplate) + addDashboard(dashConfig, compiledTemplate) const dashResources = getResourcesByType('AWS::CloudWatch::Dashboard', compiledTemplate) t.same(dashResources, {}) t.end() @@ -361,7 +360,7 @@ test('A dashboard includes metrics for ALB', (t) => { } } }) - addDashboard(defaultConfig.dashboard, emptyFuncConfigs, compiledTemplate) + addDashboard(defaultConfig.dashboard, compiledTemplate) const tgDashResource = Object.values(getResourcesByType('AWS::CloudWatch::Dashboard', compiledTemplate))[0] const tgDashBody = JSON.parse(tgDashResource.Properties?.DashboardBody['Fn::Sub']) @@ -379,7 +378,7 @@ test('A dashboard includes metrics for ALB', (t) => { test('A dashboard includes metrics for AppSync', (t) => { const compiledTemplate = createTestCloudFormationTemplate((appSyncCfTemplate)) - addDashboard(defaultConfig.dashboard, emptyFuncConfigs, compiledTemplate) + addDashboard(defaultConfig.dashboard, compiledTemplate) const dashResources = getResourcesByType('AWS::CloudWatch::Dashboard', compiledTemplate) t.equal(Object.keys(dashResources).length, 1) const [, dashResource] = Object.entries(dashResources)[0] @@ -418,7 +417,7 @@ test('A dashboard includes metrics for ALB', (t) => { dashConfig.widgets[service].enabled = false } const compiledTemplate = createTestCloudFormationTemplate((appSyncCfTemplate)) - addDashboard(dashConfig, emptyFuncConfigs, compiledTemplate) + addDashboard(dashConfig, compiledTemplate) const dashResources = getResourcesByType('AWS::CloudWatch::Dashboard', compiledTemplate) t.same(dashResources, {}) t.end() @@ -440,7 +439,7 @@ test('DynamoDB widgets are created without GSIs', (t) => { } const compiledTemplate = createTestCloudFormationTemplate(compTemplates) - addDashboard(defaultConfig.dashboard, emptyFuncConfigs, compiledTemplate) + addDashboard(defaultConfig.dashboard, compiledTemplate) const dashResources = getResourcesByType('AWS::CloudWatch::Dashboard', compiledTemplate) const [, dashResource] = Object.entries(dashResources)[0] @@ -467,7 +466,7 @@ test('No dashboard is created if all widgets are disabled', (t) => { dashConfig.widgets[service].enabled = false } const compiledTemplate = createTestCloudFormationTemplate() - addDashboard(dashConfig, emptyFuncConfigs, compiledTemplate) + addDashboard(dashConfig, compiledTemplate) const dashResources = getResourcesByType('AWS::CloudWatch::Dashboard', compiledTemplate) t.same(dashResources, {}) t.end() @@ -480,22 +479,22 @@ test('No dashboard is created if all metrics are disabled', (t) => { dashConfig.widgets[service].enabled = false } const compiledTemplate = createTestCloudFormationTemplate() - addDashboard(dashConfig, emptyFuncConfigs, compiledTemplate) + addDashboard(dashConfig, compiledTemplate) const dashResources = getResourcesByType('AWS::CloudWatch::Dashboard', compiledTemplate) t.same(dashResources, {}) t.end() }) test('A widget is not created for Lambda if disabled at a function level', (t) => { - const disabledFunctionName = 'serverless-test-project-dev-hello' for (const metric of lambdaMetrics) { - const funcConfigs: any = { - [disabledFunctionName]: { - [metric]: { enabled: false } + const compiledTemplate = createTestCloudFormationTemplate(); + (compiledTemplate.Resources as ResourceType).HelloLambdaFunction.Metadata = { + slicWatch: { + dashboard: { enabled: false } } } - const compiledTemplate = createTestCloudFormationTemplate() - addDashboard(defaultConfig.dashboard, funcConfigs, compiledTemplate) + + addDashboard(defaultConfig.dashboard, compiledTemplate) const dashResources = getResourcesByType('AWS::CloudWatch::Dashboard', compiledTemplate) const [, dashResource] = Object.entries(dashResources)[0] const dashBody = JSON.parse(dashResource.Properties?.DashboardBody['Fn::Sub']) @@ -506,22 +505,52 @@ test('A widget is not created for Lambda if disabled at a function level', (t) = const widgetMetrics = widgets[0].properties.metrics const functionNames = widgetMetrics.map(widgetMetric => widgetMetric[3]) t.ok(functionNames.length > 0) - t.equal(functionNames.indexOf(disabledFunctionName), -1, `${metric} is disabled`) + t.equal(functionNames.indexOf('serverless-test-project-dev-hello'), -1, `${metric} is disabled`) + } + t.end() +}) + +test('A widget is not created for Lambda if disabled at a function level for each metric', (t) => { + for (const metric of lambdaMetrics) { + const compiledTemplate = createTestCloudFormationTemplate(); + (compiledTemplate.Resources as ResourceType).HelloLambdaFunction.Metadata = { + slicWatch: { + dashboard: Object.fromEntries(lambdaMetrics.map((metric) => ([ + metric, { enabled: false } + ]))) + } + } + + addDashboard(defaultConfig.dashboard, compiledTemplate) + const dashResources = getResourcesByType('AWS::CloudWatch::Dashboard', compiledTemplate) + const [, dashResource] = Object.entries(dashResources)[0] + const dashBody = JSON.parse(dashResource.Properties?.DashboardBody['Fn::Sub']) + + const widgets = dashBody.widgets.filter(({ properties: { title } }) => + title.startsWith(`Lambda ${metric}`) + ) + const widgetMetrics = widgets[0].properties.metrics + const functionNames = widgetMetrics.map(widgetMetric => widgetMetric[3]) + t.ok(functionNames.length > 0) + t.equal(functionNames.indexOf('serverless-test-project-dev-hello'), -1, `${metric} is disabled`) } t.end() }) test('No Lambda widgets are created if all metrics for functions are disabled', (t) => { - const funcConfigs = {} const compiledTemplate = createTestCloudFormationTemplate() const allFunctionLogicalIds = Object.keys(getResourcesByType('AWS::Lambda::Function', compiledTemplate)) for (const funcLogicalId of allFunctionLogicalIds) { - funcConfigs[funcLogicalId] = {} - for (const metric of lambdaMetrics) { - funcConfigs[funcLogicalId][metric] = { enabled: false } + (compiledTemplate.Resources as ResourceType)[funcLogicalId].Metadata = { + slicWatch: { + dashboard: Object.fromEntries(lambdaMetrics.map((metric) => ([ + metric, { enabled: false } + ]))) + } } } - addDashboard(defaultConfig.dashboard, funcConfigs, compiledTemplate) + + addDashboard(defaultConfig.dashboard, compiledTemplate) const dashResources = getResourcesByType('AWS::CloudWatch::Dashboard', compiledTemplate) const [, dashResource] = Object.entries(dashResources)[0] const dashBody = JSON.parse(dashResource.Properties?.DashboardBody['Fn::Sub']) diff --git a/core/inputs/default-config.ts b/core/inputs/default-config.ts index 2ee79443..bba15c5c 100644 --- a/core/inputs/default-config.ts +++ b/core/inputs/default-config.ts @@ -1,9 +1,9 @@ import type { SlicWatchCascadedAlarmsConfig, SlicWatchAlarmConfig } from '../alarms/alarm-types' -import type { SlicWatchDashboardConfig } from '../dashboards/dashboard-types' +import type { SlicWatchInputDashboardConfig } from '../dashboards/dashboard-types' export interface DefaultConfig { alarms: SlicWatchCascadedAlarmsConfig - dashboard: SlicWatchDashboardConfig + dashboard: SlicWatchInputDashboardConfig } /** diff --git a/core/package.json b/core/package.json index 2dceba1d..64c6a475 100644 --- a/core/package.json +++ b/core/package.json @@ -36,6 +36,7 @@ "yaml": "^1.10.2" }, "devDependencies": { + "cloudwatch-dashboard-types": "^1.0.0-rc1", "ts-node": "^10.9.1" } } diff --git a/package-lock.json b/package-lock.json index 00397c8f..f2b9d75a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -90,6 +90,7 @@ "yaml": "^1.10.2" }, "devDependencies": { + "cloudwatch-dashboard-types": "^1.0.0-rc1", "ts-node": "^10.9.1" } }, @@ -5532,6 +5533,12 @@ "node": ">=4.2.0" } }, + "node_modules/cloudwatch-dashboard-types": { + "version": "1.0.0-rc1", + "resolved": "https://registry.npmjs.org/cloudwatch-dashboard-types/-/cloudwatch-dashboard-types-1.0.0-rc1.tgz", + "integrity": "sha512-wmsDF8JQXR2JhTYBtDIPwVN4rNgsXMIRFE3hOefVFW0npqRDM0AWuWgHInfPnDyYb0kjIlsSnG7EsWV0BmiIew==", + "dev": true + }, "node_modules/co": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", @@ -17734,6 +17741,12 @@ "cloudform-types": { "version": "7.4.2" }, + "cloudwatch-dashboard-types": { + "version": "1.0.0-rc1", + "resolved": "https://registry.npmjs.org/cloudwatch-dashboard-types/-/cloudwatch-dashboard-types-1.0.0-rc1.tgz", + "integrity": "sha512-wmsDF8JQXR2JhTYBtDIPwVN4rNgsXMIRFE3hOefVFW0npqRDM0AWuWgHInfPnDyYb0kjIlsSnG7EsWV0BmiIew==", + "dev": true + }, "co": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", @@ -22174,6 +22187,7 @@ "ajv": "^8.11.0", "case": "^1.6.3", "cloudform": "^7.4.2", + "cloudwatch-dashboard-types": "^1.0.0-rc1", "lodash": "^4.17.21", "pino": "^8.4.2", "ts-node": "^10.9.1", diff --git a/serverless-plugin/tests/index.test.ts b/serverless-plugin/tests/index.test.ts index 9c08bc7a..34a4d6d2 100644 --- a/serverless-plugin/tests/index.test.ts +++ b/serverless-plugin/tests/index.test.ts @@ -23,23 +23,6 @@ const mockServerless = createMockServerless({ } }) -function compileServerlessFunctionsToCloudformation (functions: Record, provider: () => { - naming: { getLambdaLogicalId: (funcName: string) => string } -}) { - const compiledCloudFormationTemplate = Object.keys(functions).map(lambda => { - const compiledLambdaLogicalId = provider().naming.getLambdaLogicalId(lambda) - const result = {} - result[`${compiledLambdaLogicalId}`] = { - Type: 'AWS::Lambda::Function', - MemorySize: 256, - Runtime: 'nodejs12', - Timeout: 60 - } - return result - }).reduce((accum, currentValue) => ({ ...accum, ...currentValue })) - return { Resources: compiledCloudFormationTemplate } -} - test('index', t => { t.test('plugin uses v3 logger', t => { // Since v3, Serverless Framework provides a logger that we must use to log output @@ -169,64 +152,5 @@ test('index', t => { plugin.createSlicWatchResources() t.end() }) - - t.test('should create only the dashboard when a lambda is not referenced in the serverless functions config', t => { - const mockServerless = createMockServerless({ - Resources: { - HelloTestLambda: { - Type: 'AWS::Lambda::Function', - Properties: { - MemorySize: 256, - Runtime: 'nodejs12', - Timeout: 60 - } - } - } - }) - const plugin = new ServerlessPlugin(mockServerless, null, pluginUtils) - plugin.createSlicWatchResources() - t.same(Object.keys(mockServerless.service.provider.compiledCloudFormationTemplate.Resources as ResourceType), ['HelloTestLambda', 'slicWatchDashboard']) - t.end() - }) - - t.test('should create only the dashboard and lambda alarm when the lambda is referenced in the serverless functions config', t => { - const functions = { MyServerlessFunction: {} } - const provider = () => ({ - naming: { - getLambdaLogicalId: (funcName: string) => { - return funcName[0].toUpperCase() + funcName.slice(1) + 'LambdaFunction' - } - } - }) - const compiledCloudFormationTemplate = compileServerlessFunctionsToCloudformation(functions, provider) - - const mockServerless = { - getProvider: provider, - service: { - getAllFunctions: () => Object.keys(functions), - provider: { - name: 'aws', - compiledCloudFormationTemplate - }, - custom: { - slicWatch: { - enabled: true - } - }, - getFunction: (funcRef) => functions[funcRef] - } - } - const plugin = new ServerlessPlugin(mockServerless, null, pluginUtils) - plugin.createSlicWatchResources() - t.same(Object.keys(mockServerless.service.provider.compiledCloudFormationTemplate.Resources), - [ - 'MyServerlessFunctionLambdaFunction', - 'slicWatchDashboard', - 'slicWatchLambdaErrorsAlarmMyServerlessFunctionLambdaFunction', - 'slicWatchLambdaThrottlesAlarmMyServerlessFunctionLambdaFunction', - 'slicWatchLambdaDurationAlarmMyServerlessFunctionLambdaFunction' - ]) - t.end() - }) t.end() }) From c3a7db7573ae65f3dbc839a6b2436871b6794471 Mon Sep 17 00:00:00 2001 From: Eoin Shanaghy Date: Tue, 14 Nov 2023 10:27:11 +0000 Subject: [PATCH 06/35] chore: prune unused types --- core/alarms/alarm-types.ts | 5 ---- core/alarms/lambda.ts | 24 +++++++-------- core/dashboards/dashboard-types.ts | 17 ----------- core/dashboards/dashboard.ts | 40 ++++++++++++------------- core/dashboards/tests/dashboard.test.ts | 11 +++---- core/package.json | 2 +- package-lock.json | 16 +++++----- tsconfig.json | 2 +- 8 files changed, 48 insertions(+), 69 deletions(-) diff --git a/core/alarms/alarm-types.ts b/core/alarms/alarm-types.ts index 87257580..733d3e23 100644 --- a/core/alarms/alarm-types.ts +++ b/core/alarms/alarm-types.ts @@ -40,11 +40,6 @@ export interface SlicWatchMergedConfig extends AlarmProperties { export type InputOutput = SlicWatchAlarmConfig | SlicWatchMergedConfig -export interface ReturnAlarm { - resourceName: string - resource: Resource -} - export interface AlarmActionsConfig { actionsEnabled?: boolean okActions?: string[] diff --git a/core/alarms/lambda.ts b/core/alarms/lambda.ts index 80342c4b..a64d2e70 100644 --- a/core/alarms/lambda.ts +++ b/core/alarms/lambda.ts @@ -15,8 +15,6 @@ export interface SlicWatchLambdaAlarmsConfig extends Slic IteratorAge: T } -export type FunctionAlarmProperties = Record> - const lambdaMetrics = ['Errors', 'ThrottlesPc', 'DurationPc', 'Invocations'] /** @@ -30,22 +28,24 @@ const lambdaMetrics = ['Errors', 'ThrottlesPc', 'DurationPc', 'Invocations'] * * TODO - Fix the lambdaAlarmConfig type */ -export default function createLambdaAlarms (lambdaAlarmConfig: SlicWatchLambdaAlarmsConfig, alarmActionsConfig: AlarmActionsConfig, compiledTemplate: Template) { +export default function createLambdaAlarms ( + lambdaAlarmConfig: SlicWatchLambdaAlarmsConfig, alarmActionsConfig: AlarmActionsConfig, compiledTemplate: Template +) { const resources = {} const lambdaResources = getResourcesByType('AWS::Lambda::Function', compiledTemplate) const mergedConfigPerFunction: Record> = {} for (const [funcLogicalId, funcResource] of Object.entries(lambdaResources)) { const resourceConfig = cascade(funcResource?.Metadata?.slicWatch?.alarms ?? {}) as SlicWatchLambdaAlarmsConfig - const config: SlicWatchLambdaAlarmsConfig = Object.assign(lambdaAlarmConfig, resourceConfig) - mergedConfigPerFunction[funcLogicalId] = config + const mergedConfig: SlicWatchLambdaAlarmsConfig = Object.assign(lambdaAlarmConfig, resourceConfig) + mergedConfigPerFunction[funcLogicalId] = mergedConfig for (const metric of lambdaMetrics) { - if (config.enabled === false || config[metric].enabled === false) { + if (mergedConfig.enabled === false || mergedConfig[metric].enabled === false) { continue } if (metric === 'ThrottlesPc') { - const properties = config.ThrottlesPc + const properties = mergedConfig.ThrottlesPc properties.Metrics = [ { Id: 'throttles_pc', @@ -82,7 +82,7 @@ export default function createLambdaAlarms (lambdaAlarmConfig: SlicWatchLambdaAl ] } if (metric === 'DurationPc') { - const properties = config.DurationPc + const properties = mergedConfig.DurationPc const funcTimeout: number = funcResource.Properties?.Timeout ?? 3 const threshold: Value = properties.Threshold as number const alarmDescription = Fn.Sub(`Max duration for \${${funcLogicalId}} breaches ${properties.Threshold}% of timeout (${funcTimeout})`, {}) @@ -90,24 +90,24 @@ export default function createLambdaAlarms (lambdaAlarmConfig: SlicWatchLambdaAl properties.Threshold = (threshold * funcTimeout * 1000) / 100 } if (metric === 'Errors') { - const properties = config.Errors + const properties = mergedConfig.Errors const alarmDescription = Fn.Sub(`Error count for \${${funcLogicalId}} breaches ${properties.Threshold}`, {}) properties.AlarmDescription = alarmDescription } if (metric === 'ThrottlesPc') { - const properties = config.ThrottlesPc + const properties = mergedConfig.ThrottlesPc const alarmDescription = Fn.Sub(`Throttles % for \${${funcLogicalId}} breaches ${properties.Threshold}`, {}) properties.AlarmDescription = alarmDescription } if (metric === 'Invocations') { - const properties = config.Invocations + const properties = mergedConfig.Invocations const alarmDescription = Fn.Sub(`Total invocations for \${${funcLogicalId}} breaches ${properties.Threshold}`, {}) properties.AlarmDescription = alarmDescription } - Object.assign(resources, createLambdaCfAlarm(config[metric], metric, funcLogicalId, compiledTemplate, alarmActionsConfig)) + Object.assign(resources, createLambdaCfAlarm(mergedConfig[metric], metric, funcLogicalId, compiledTemplate, alarmActionsConfig)) } } for (const funcLogicalId of Object.keys(getEventSourceMappingFunctions(compiledTemplate))) { diff --git a/core/dashboards/dashboard-types.ts b/core/dashboards/dashboard-types.ts index fa098fe6..4a9454f5 100644 --- a/core/dashboards/dashboard-types.ts +++ b/core/dashboards/dashboard-types.ts @@ -20,23 +20,6 @@ export interface WidgetWithSize extends Omit { height: number } -export interface MetricProperties { - metrics: any[][] - title: string - view: string - region: string - period?: number - yAxis?: YAxisPos -} - -export interface CreateMetricWidget { - type: string - properties: MetricProperties - width: number - height: number - yAxis?: YAxisPos -} - export interface WidgetMetricProperties { enabled: boolean metricPeriod: number diff --git a/core/dashboards/dashboard.ts b/core/dashboards/dashboard.ts index bc0abbfd..bca8b561 100644 --- a/core/dashboards/dashboard.ts +++ b/core/dashboards/dashboard.ts @@ -1,5 +1,5 @@ import type Template from 'cloudform-types/types/template' -import * as cwd from 'cloudwatch-dashboard-types' +import { type Dashboard, type WidgetMetric, type Statistic, type YAxisPosition } from 'cloudwatch-dashboard-types' import { cascade } from '../inputs/cascading-config' import { getResourcesByType, getEventSourceMappingFunctions, addResource } from '../cf-template' @@ -94,7 +94,7 @@ export default function addDashboard (dashboardConfig: SlicWatchInputDashboardCo ]) if (positionedWidgets.length > 0) { - const dash: cwd.Dashboard = { start: timeRange?.start, end: timeRange?.end, widgets: positionedWidgets } + const dash: Dashboard = { start: timeRange?.start, end: timeRange?.end, widgets: positionedWidgets } const dashboardResource = { Type: 'AWS::CloudWatch::Dashboard', Properties: { @@ -115,7 +115,7 @@ export default function addDashboard (dashboardConfig: SlicWatchInputDashboardCo * @param {Object} config Cascaded widget/metric configuration */ function createMetricWidget (title: string, metricDefs: MetricDefs[], config: WidgetMetricProperties): WidgetWithSize { - const metrics: cwd.WidgetMetric[] = metricDefs.map( + const metrics: WidgetMetric[] = metricDefs.map( ({ namespace, metric, dimensions, stat, yAxis }) => [ namespace, metric, @@ -123,15 +123,15 @@ export default function addDashboard (dashboardConfig: SlicWatchInputDashboardCo (acc: string[], [name, value]) => [...acc, name, value], [] ), - { stat: stat as cwd.Statistic, yAxis: yAxis as cwd.YAxisPosition } + { stat: stat as Statistic, yAxis: yAxis as YAxisPosition } ] ) return { - type: cwd.WidgetType.Metric, + type: 'metric', properties: { metrics, title, - view: cwd.MetricViewType.TimeSeries, + view: 'timeSeries', region: '${AWS::Region}', period: config.metricPeriod }, @@ -160,7 +160,7 @@ export default function addDashboard (dashboardConfig: SlicWatchInputDashboardCo if (Object.keys(functionResources).length > 0) { for (const [metric, metricConfig] of Object.entries(getConfiguredMetrics(lambdaDashConfig))) { if (metric !== 'IteratorAge' as any) { - for (const stat of metricConfig?.Statistic ?? []) { + for (const stat of metricConfig.Statistic) { const metricDefs: MetricDefs[] = [] for (const funcLogicalId of Object.keys(functionResources)) { const funcConfig = configPerFunctionResource[funcLogicalId] @@ -170,7 +170,7 @@ export default function addDashboard (dashboardConfig: SlicWatchInputDashboardCo namespace: 'AWS/Lambda', metric, dimensions: { FunctionName: `\${${funcLogicalId}}` }, - stat: stat as cwd.Statistic + stat: stat as Statistic }) } } @@ -188,7 +188,7 @@ export default function addDashboard (dashboardConfig: SlicWatchInputDashboardCo for (const funcLogicalId of eventSourceMappingFunctionResourceNames) { // Add IteratorAge alarm if the Lambda function has an EventSourceMapping trigger const funcConfig = configPerFunctionResource[funcLogicalId] - const functionMetricConfig = funcConfig[metric] ?? {} + const functionMetricConfig = funcConfig[metric] if (functionMetricConfig.enabled !== false) { const stats: string[] = [] metricConfig?.Statistic?.forEach(a => stats.push(a)) @@ -198,7 +198,7 @@ export default function addDashboard (dashboardConfig: SlicWatchInputDashboardCo namespace: 'AWS/Lambda', metric: 'IteratorAge', dimensions: { FunctionName: `\${${funcLogicalId}}` }, - stat: stat as cwd.Statistic + stat: stat as Statistic })), metricConfig as Widgets ) @@ -239,7 +239,7 @@ export default function addDashboard (dashboardConfig: SlicWatchInputDashboardCo const widgetMetrics: MetricDefs[] = [] for (const [metric, metricConfig] of Object.entries(getConfiguredMetrics(apiGwDashConfig))) { if (metricConfig.enabled) { - for (const stat of metricConfig?.Statistic ?? []) { + for (const stat of metricConfig.Statistic) { widgetMetrics.push({ namespace: 'AWS/ApiGateway', metric, @@ -275,7 +275,7 @@ export default function addDashboard (dashboardConfig: SlicWatchInputDashboardCo const widgetMetrics: MetricDefs[] = [] for (const [metric, metricConfig] of Object.entries(getConfiguredMetrics(sfDashConfig))) { if (metricConfig.enabled) { - for (const stat of metricConfig?.Statistic ?? []) { + for (const stat of metricConfig.Statistic) { widgetMetrics.push({ namespace: 'AWS/States', metric, @@ -310,7 +310,7 @@ export default function addDashboard (dashboardConfig: SlicWatchInputDashboardCo const widgetMetrics: MetricDefs[] = [] for (const [metric, metricConfig] of Object.entries(getConfiguredMetrics(dynamoDbDashConfig))) { if (metricConfig.enabled) { - for (const stat of metricConfig?.Statistic ?? []) { + for (const stat of metricConfig.Statistic) { widgetMetrics.push({ namespace: 'AWS/DynamoDB', metric, @@ -330,7 +330,7 @@ export default function addDashboard (dashboardConfig: SlicWatchInputDashboardCo } for (const gsi of res.Properties?.GlobalSecondaryIndexes ?? []) { const gsiName: string = gsi.IndexName - for (const stat of metricConfig?.Statistic ?? []) { + for (const stat of metricConfig.Statistic) { widgetMetrics.push({ namespace: 'AWS/DynamoDB', metric, @@ -493,7 +493,7 @@ export default function addDashboard (dashboardConfig: SlicWatchInputDashboardCo const widgetMetrics: MetricDefs[] = [] for (const [metric, metricConfig] of Object.entries(getConfiguredMetrics(snsDashConfig))) { if (metricConfig.enabled) { - for (const stat of metricConfig?.Statistic ?? []) { + for (const stat of metricConfig.Statistic) { widgetMetrics.push({ namespace: 'AWS/SNS', metric, @@ -528,7 +528,7 @@ export default function addDashboard (dashboardConfig: SlicWatchInputDashboardCo const widgetMetrics: MetricDefs[] = [] for (const [metric, metricConfig] of Object.entries(getConfiguredMetrics(ruleDashConfig))) { if (metricConfig.enabled) { - for (const stat of metricConfig?.Statistic ?? []) { + for (const stat of metricConfig.Statistic) { widgetMetrics.push({ namespace: 'AWS/Events', metric, @@ -564,7 +564,7 @@ export default function addDashboard (dashboardConfig: SlicWatchInputDashboardCo const widgetMetrics: MetricDefs[] = [] for (const [metric, metricConfig] of Object.entries(getConfiguredMetrics(albDashConfig))) { if (metricConfig.enabled) { - for (const stat of metricConfig?.Statistic ?? []) { + for (const stat of metricConfig.Statistic) { widgetMetrics.push({ namespace: 'AWS/ApplicationELB', metric, @@ -606,7 +606,7 @@ export default function addDashboard (dashboardConfig: SlicWatchInputDashboardCo if (metricConfig.enabled && (targetGroupResource.Properties?.TargetType === 'lambda' || !['LambdaUserError', 'LambdaInternalError'].includes(metric)) ) { - for (const stat of metricConfig?.Statistic ?? []) { + for (const stat of metricConfig.Statistic) { widgetMetrics.push({ namespace: 'AWS/ApplicationELB', metric, @@ -660,8 +660,8 @@ export default function addDashboard (dashboardConfig: SlicWatchInputDashboardCo namespace: 'AWS/AppSync', metric, dimensions: { GraphQLAPIId: graphQLAPIId }, - stat: stat as cwd.Statistic, - yAxis: metricConfig.yAxis as cwd.YAxisPosition + stat: stat as Statistic, + yAxis: metricConfig.yAxis as YAxisPosition }) } } diff --git a/core/dashboards/tests/dashboard.test.ts b/core/dashboards/tests/dashboard.test.ts index 900d5180..2447d3b7 100644 --- a/core/dashboards/tests/dashboard.test.ts +++ b/core/dashboards/tests/dashboard.test.ts @@ -6,6 +6,7 @@ import defaultConfig from '../../inputs/default-config' import { createTestCloudFormationTemplate, defaultCfTemplate, albCfTemplate, appSyncCfTemplate } from '../../tests/testing-utils' import { type ResourceType, getResourcesByType } from '../../cf-template' +import { type Widgets } from '../dashboard-types' const lambdaMetrics = ['Errors', 'Duration', 'IteratorAge', 'Invocations', 'ConcurrentExecutions', 'Throttles'] @@ -312,7 +313,7 @@ test('A dashboard includes metrics for ALB', (t) => { const services = ['Lambda', 'ApiGateway', 'States', 'DynamoDB', 'SQS', 'Kinesis', 'ECS', 'SNS', 'Events', 'ApplicationELB', 'ApplicationELBTarget', 'AppSync'] const dashConfig = _.cloneDeep(defaultConfig.dashboard) for (const service of services) { - dashConfig.widgets[service].enabled = false + (dashConfig.widgets as Widgets)[service].enabled = false } const compiledTemplate = createTestCloudFormationTemplate((appSyncCfTemplate)) addDashboard(dashConfig, compiledTemplate) @@ -325,7 +326,7 @@ test('A dashboard includes metrics for ALB', (t) => { const services = ['Lambda', 'ApiGateway', 'States', 'DynamoDB', 'SQS', 'Kinesis', 'ECS', 'SNS', 'Events', 'ApplicationELB', 'ApplicationELBTarget', 'AppSync'] const dashConfig = _.cloneDeep(defaultConfig.dashboard) for (const service of services) { - dashConfig.widgets[service].enabled = false + (dashConfig.widgets as Widgets)[service].enabled = false } const compiledTemplate = createTestCloudFormationTemplate((albCfTemplate)) addDashboard(dashConfig, compiledTemplate) @@ -414,7 +415,7 @@ test('A dashboard includes metrics for ALB', (t) => { const services = ['Lambda', 'ApiGateway', 'States', 'DynamoDB', 'SQS', 'Kinesis', 'ECS', 'SNS', 'Events', 'ApplicationELB', 'ApplicationELBTarget', 'AppSync'] const dashConfig = _.cloneDeep(defaultConfig.dashboard) for (const service of services) { - dashConfig.widgets[service].enabled = false + (dashConfig.widgets as Widgets)[service].enabled = false } const compiledTemplate = createTestCloudFormationTemplate((appSyncCfTemplate)) addDashboard(dashConfig, compiledTemplate) @@ -463,7 +464,7 @@ test('No dashboard is created if all widgets are disabled', (t) => { const services = ['Lambda', 'ApiGateway', 'States', 'DynamoDB', 'SQS', 'Kinesis', 'ECS', 'SNS', 'Events', 'ApplicationELB', 'ApplicationELBTarget', 'AppSync'] const dashConfig = _.cloneDeep(defaultConfig.dashboard) for (const service of services) { - dashConfig.widgets[service].enabled = false + (dashConfig.widgets as Widgets)[service].enabled = false } const compiledTemplate = createTestCloudFormationTemplate() addDashboard(dashConfig, compiledTemplate) @@ -476,7 +477,7 @@ test('No dashboard is created if all metrics are disabled', (t) => { const services = ['Lambda', 'ApiGateway', 'States', 'DynamoDB', 'SQS', 'Kinesis', 'ECS', 'SNS', 'Events', 'ApplicationELB', 'ApplicationELBTarget', 'AppSync'] const dashConfig = _.cloneDeep(defaultConfig.dashboard) for (const service of services) { - dashConfig.widgets[service].enabled = false + (dashConfig.widgets as Widgets)[service].enabled = false } const compiledTemplate = createTestCloudFormationTemplate() addDashboard(dashConfig, compiledTemplate) diff --git a/core/package.json b/core/package.json index 64c6a475..ff856bd8 100644 --- a/core/package.json +++ b/core/package.json @@ -36,7 +36,7 @@ "yaml": "^1.10.2" }, "devDependencies": { - "cloudwatch-dashboard-types": "^1.0.0-rc1", + "cloudwatch-dashboard-types": "^1.0.1-rc2", "ts-node": "^10.9.1" } } diff --git a/package-lock.json b/package-lock.json index f2b9d75a..4dbf5657 100644 --- a/package-lock.json +++ b/package-lock.json @@ -90,7 +90,7 @@ "yaml": "^1.10.2" }, "devDependencies": { - "cloudwatch-dashboard-types": "^1.0.0-rc1", + "cloudwatch-dashboard-types": "^1.0.1-rc2", "ts-node": "^10.9.1" } }, @@ -5534,9 +5534,9 @@ } }, "node_modules/cloudwatch-dashboard-types": { - "version": "1.0.0-rc1", - "resolved": "https://registry.npmjs.org/cloudwatch-dashboard-types/-/cloudwatch-dashboard-types-1.0.0-rc1.tgz", - "integrity": "sha512-wmsDF8JQXR2JhTYBtDIPwVN4rNgsXMIRFE3hOefVFW0npqRDM0AWuWgHInfPnDyYb0kjIlsSnG7EsWV0BmiIew==", + "version": "1.0.1-rc2", + "resolved": "https://registry.npmjs.org/cloudwatch-dashboard-types/-/cloudwatch-dashboard-types-1.0.1-rc2.tgz", + "integrity": "sha512-8pdwBjVhaGFmEbqtfiqaZeUuf2yRb0oCaYOvHzea+0uFKH9nwVtXwB6R4GNffPk59zpZZ2kIrF9W/V581wnRjQ==", "dev": true }, "node_modules/co": { @@ -17742,9 +17742,9 @@ "version": "7.4.2" }, "cloudwatch-dashboard-types": { - "version": "1.0.0-rc1", - "resolved": "https://registry.npmjs.org/cloudwatch-dashboard-types/-/cloudwatch-dashboard-types-1.0.0-rc1.tgz", - "integrity": "sha512-wmsDF8JQXR2JhTYBtDIPwVN4rNgsXMIRFE3hOefVFW0npqRDM0AWuWgHInfPnDyYb0kjIlsSnG7EsWV0BmiIew==", + "version": "1.0.1-rc2", + "resolved": "https://registry.npmjs.org/cloudwatch-dashboard-types/-/cloudwatch-dashboard-types-1.0.1-rc2.tgz", + "integrity": "sha512-8pdwBjVhaGFmEbqtfiqaZeUuf2yRb0oCaYOvHzea+0uFKH9nwVtXwB6R4GNffPk59zpZZ2kIrF9W/V581wnRjQ==", "dev": true }, "co": { @@ -22187,7 +22187,7 @@ "ajv": "^8.11.0", "case": "^1.6.3", "cloudform": "^7.4.2", - "cloudwatch-dashboard-types": "^1.0.0-rc1", + "cloudwatch-dashboard-types": "^1.0.1-rc2", "lodash": "^4.17.21", "pino": "^8.4.2", "ts-node": "^10.9.1", diff --git a/tsconfig.json b/tsconfig.json index c907461d..c2aefed0 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -14,7 +14,7 @@ "resolveJsonModule": true, "target": "ESNext", "allowSyntheticDefaultImports": true, - "esModuleInterop": true + "esModuleInterop": true, }, "ts-node": { "swc": true, From af7a18c7b5b32534c959ffcd071b7a4d99d946c5 Mon Sep 17 00:00:00 2001 From: Eoin Shanaghy Date: Tue, 14 Nov 2023 13:49:44 +0000 Subject: [PATCH 07/35] feat: allow all resources to have configurable alarms --- core/alarms/alarm-utils.ts | 23 ++++++++------------ core/alarms/alb-target-group.ts | 17 ++++++++------- core/alarms/alb.ts | 4 ++-- core/alarms/api-gateway.ts | 18 ++++++++-------- core/alarms/appsync.ts | 12 +++++------ core/alarms/dynamodb.ts | 16 +++++++------- core/alarms/ecs.ts | 16 +++++++------- core/alarms/eventbridge.ts | 4 ++-- core/alarms/kinesis.ts | 16 +++++++------- core/alarms/lambda.ts | 24 ++++++++------------- core/alarms/sns.ts | 4 ++-- core/alarms/sqs.ts | 38 +++++++++++++++++---------------- core/alarms/step-functions.ts | 4 ++-- core/cf-template.ts | 32 +++++++++++++++++++++++++++ 14 files changed, 126 insertions(+), 102 deletions(-) diff --git a/core/alarms/alarm-utils.ts b/core/alarms/alarm-utils.ts index 44e787e4..c66c7d47 100644 --- a/core/alarms/alarm-utils.ts +++ b/core/alarms/alarm-utils.ts @@ -3,12 +3,7 @@ import type { AlarmProperties } from 'cloudform-types/types/cloudWatch/alarm' import { pascal } from 'case' import type { AlarmActionsConfig, AlarmTemplate, CloudFormationResources, OptionalAlarmProps, SlicWatchMergedConfig } from './alarm-types' -import { getResourcesByType } from '../cf-template' -import type { SlicWatchAlbAlarmsConfig } from './alb' -import type { SlicWatchDynamoDbAlarmsConfig } from './dynamodb' -import type { SlicWatchEventsAlarmsConfig } from './eventbridge' -import type { SlicWatchSnsAlarmsConfig } from './sns' -import type { SlicWatchSfAlarmsConfig } from './step-functions' +import { getResourceAlarmConfigurationsByType } from '../cf-template' /* * RegEx to filter out invalid CloudFormation Logical ID characters @@ -27,8 +22,6 @@ const LOGICAL_ID_FILTER_REGEX = /[^a-z0-9]/gi */ type SpecificAlarmPropertiesGeneratorFunction = (metric: string, resourceName: string, config: SlicWatchMergedConfig) => Omit -type CommonAlarmsConfigs = SlicWatchAlbAlarmsConfig | SlicWatchDynamoDbAlarmsConfig | SlicWatchEventsAlarmsConfig | SlicWatchSnsAlarmsConfig | SlicWatchSfAlarmsConfig - /** * Create CloudFormation 'AWS::CloudWatch::Alarm' resources based on metrics for a specfic resources type * @@ -43,17 +36,18 @@ type CommonAlarmsConfigs = SlicWatchAlbAlarmsConfig | Sli * @returns An object containing the alarm resources in CloudFormation syntax by logical ID */ export function createCfAlarms ( - type: string, service: string, metrics: string[], config: CommonAlarmsConfigs, alarmActionsConfig: AlarmActionsConfig, + type: string, service: string, metrics: string[], config: SlicWatchMergedConfig, alarmActionsConfig: AlarmActionsConfig, compiledTemplate: Template, genSpecificAlarmProps: SpecificAlarmPropertiesGeneratorFunction ): CloudFormationResources { const resources: CloudFormationResources = {} - const resourcesOfType = getResourcesByType(type, compiledTemplate) + const resourceConfigs = getResourceAlarmConfigurationsByType(type, compiledTemplate, config) - for (const resourceLogicalId of Object.keys(resourcesOfType)) { + for (const resourceLogicalId of Object.keys(resourceConfigs.resources)) { for (const metric of metrics) { - const { enabled, ...rest } = config[metric] - if (enabled !== false) { - const alarm = genSpecificAlarmProps(metric, resourceLogicalId, rest) + const mergedConfig = resourceConfigs.alarmConfigurations[resourceLogicalId][metric] as SlicWatchMergedConfig + const { enabled, ...rest } = mergedConfig + if (enabled) { + const alarm = genSpecificAlarmProps(metric, resourceLogicalId, mergedConfig) const alarmLogicalId = makeAlarmLogicalId(service, pascal(resourceLogicalId), metric) const resource = createAlarm({ MetricName: metric, @@ -66,6 +60,7 @@ export function createCfAlarms ( } return resources } + /** * Create a CloudFormation Alarm resourc * diff --git a/core/alarms/alb-target-group.ts b/core/alarms/alb-target-group.ts index 1031ed28..6f25d4fc 100644 --- a/core/alarms/alb-target-group.ts +++ b/core/alarms/alb-target-group.ts @@ -2,12 +2,12 @@ import type { AlarmProperties } from 'cloudform-types/types/cloudWatch/alarm' import type Template from 'cloudform-types/types/template' import { Fn } from 'cloudform' -import type { AlarmActionsConfig, CloudFormationResources, InputOutput, SlicWatchAlarmConfig, SlicWatchMergedConfig } from './alarm-types' +import type { AlarmActionsConfig, CloudFormationResources, InputOutput, SlicWatchMergedConfig } from './alarm-types' import { createAlarm, getStatisticName, makeAlarmLogicalId } from './alarm-utils' import type { ResourceType } from '../cf-template' -import { getResourcesByType } from '../cf-template' +import { getResourceAlarmConfigurationsByType, getResourcesByType } from '../cf-template' -export interface SlicWatchAlbTargetAlarmsConfig extends SlicWatchAlarmConfig { +export type SlicWatchAlbTargetAlarmsConfig = T & { HTTPCode_Target_5XX_Count: T UnHealthyHostCount: T LambdaInternalError: T @@ -128,15 +128,16 @@ function createAlbTargetCfAlarm ( export default function createAlbTargetAlarms ( albTargetAlarmsConfig: SlicWatchAlbTargetAlarmsConfig, alarmActionsConfig: AlarmActionsConfig, compiledTemplate: Template ): CloudFormationResources { - const targetGroupResources = getResourcesByType('AWS::ElasticLoadBalancingV2::TargetGroup', compiledTemplate) + const resourceConfigs = getResourceAlarmConfigurationsByType('AWS::ElasticLoadBalancingV2::TargetGroup', compiledTemplate, albTargetAlarmsConfig) const resources: CloudFormationResources = {} - for (const [targetGroupResourceName, targetGroupResource] of Object.entries(targetGroupResources)) { - const loadBalancerLogicalIds = findLoadBalancersForTargetGroup(targetGroupResourceName, compiledTemplate) - Object.assign(resources, createAlbTargetCfAlarm(targetGroupResourceName, executionMetrics, loadBalancerLogicalIds, albTargetAlarmsConfig, alarmActionsConfig)) + for (const [targetGroupLogicalId, targetGroupResource] of Object.entries(resourceConfigs.resources)) { + const mergedConfig = resourceConfigs.alarmConfigurations[targetGroupLogicalId] + const loadBalancerLogicalIds = findLoadBalancersForTargetGroup(targetGroupLogicalId, compiledTemplate) + Object.assign(resources, createAlbTargetCfAlarm(targetGroupLogicalId, executionMetrics, loadBalancerLogicalIds, mergedConfig, alarmActionsConfig)) if (targetGroupResource.Properties?.TargetType === 'lambda') { // Create additional alarms for Lambda-specific ALB metrics - Object.assign(resources, createAlbTargetCfAlarm(targetGroupResourceName, executionMetricsLambda, loadBalancerLogicalIds, albTargetAlarmsConfig, alarmActionsConfig)) + Object.assign(resources, createAlbTargetCfAlarm(targetGroupLogicalId, executionMetricsLambda, loadBalancerLogicalIds, mergedConfig, alarmActionsConfig)) } } return resources diff --git a/core/alarms/alb.ts b/core/alarms/alb.ts index a2c5be81..e5fefb47 100644 --- a/core/alarms/alb.ts +++ b/core/alarms/alb.ts @@ -2,10 +2,10 @@ import type { AlarmProperties } from 'cloudform-types/types/cloudWatch/alarm' import type Template from 'cloudform-types/types/template' import { Fn } from 'cloudform' -import type { AlarmActionsConfig, CloudFormationResources, InputOutput, SlicWatchAlarmConfig, SlicWatchMergedConfig } from './alarm-types' +import type { AlarmActionsConfig, CloudFormationResources, InputOutput, SlicWatchMergedConfig } from './alarm-types' import { createCfAlarms, getStatisticName } from './alarm-utils' -export interface SlicWatchAlbAlarmsConfig extends SlicWatchAlarmConfig { +export type SlicWatchAlbAlarmsConfig = T & { HTTPCode_ELB_5XX_Count: T RejectedConnectionCount: T } diff --git a/core/alarms/api-gateway.ts b/core/alarms/api-gateway.ts index 5d00ac19..592af135 100644 --- a/core/alarms/api-gateway.ts +++ b/core/alarms/api-gateway.ts @@ -3,11 +3,11 @@ import type Resource from 'cloudform-types/types/resource' import type Template from 'cloudform-types/types/template' import { Fn } from 'cloudform' -import type { AlarmActionsConfig, CloudFormationResources, InputOutput, SlicWatchAlarmConfig, SlicWatchMergedConfig } from './alarm-types' +import type { AlarmActionsConfig, CloudFormationResources, InputOutput, SlicWatchMergedConfig } from './alarm-types' import { createAlarm, getStatisticName, makeAlarmLogicalId } from './alarm-utils' -import { getResourcesByType } from '../cf-template' +import { getResourceAlarmConfigurationsByType } from '../cf-template' -export interface SlicWatchApiGwAlarmsConfig extends SlicWatchAlarmConfig { +export type SlicWatchApiGwAlarmsConfig = T & { '5XXError': T '4XXError': T Latency: T @@ -83,18 +83,18 @@ export default function createApiGatewayAlarms ( apiGwAlarmsConfig: SlicWatchApiGwAlarmsConfig, alarmActionsConfig: AlarmActionsConfig, compiledTemplate: Template ): CloudFormationResources { const resources: CloudFormationResources = {} - const apiResources = getResourcesByType('AWS::ApiGateway::RestApi', compiledTemplate) + const configuredResources = getResourceAlarmConfigurationsByType('AWS::ApiGateway::RestApi', compiledTemplate, apiGwAlarmsConfig) - for (const [apiLogicalId, apiResource] of Object.entries(apiResources)) { + for (const [apiLogicalId, apiResource] of Object.entries(configuredResources.resources)) { for (const metric of executionMetrics) { - const config: SlicWatchMergedConfig = apiGwAlarmsConfig[metric] - if (config.enabled) { - const { enabled, ...rest } = config + const mergedConfig: SlicWatchMergedConfig = configuredResources.alarmConfigurations[apiLogicalId][metric] + if (mergedConfig.enabled) { + const { enabled, ...rest } = mergedConfig const apiName = resolveRestApiNameAsCfn(apiResource, apiLogicalId) const apiNameForSub = resolveRestApiNameForSub(apiResource, apiLogicalId) const apiAlarmProperties: AlarmProperties = { AlarmName: Fn.Sub(`ApiGW_${metric}_${apiNameForSub}`, {}), - AlarmDescription: Fn.Sub(`API Gateway ${metric} ${getStatisticName(config)} for ${apiNameForSub} breaches ${config.Threshold}`, {}), + AlarmDescription: Fn.Sub(`API Gateway ${metric} ${getStatisticName(mergedConfig)} for ${apiNameForSub} breaches ${mergedConfig.Threshold}`, {}), MetricName: metric, Namespace: 'AWS/ApiGateway', Dimensions: [{ Name: 'ApiName', Value: apiName }], diff --git a/core/alarms/appsync.ts b/core/alarms/appsync.ts index c8b1d79e..3a8852ae 100644 --- a/core/alarms/appsync.ts +++ b/core/alarms/appsync.ts @@ -2,11 +2,11 @@ import type { AlarmProperties } from 'cloudform-types/types/cloudWatch/alarm' import type Template from 'cloudform-types/types/template' import { Fn } from 'cloudform' -import type { AlarmActionsConfig, CloudFormationResources, InputOutput, SlicWatchAlarmConfig, SlicWatchMergedConfig } from './alarm-types' +import type { AlarmActionsConfig, CloudFormationResources, InputOutput, SlicWatchMergedConfig } from './alarm-types' import { createAlarm, getStatisticName, makeAlarmLogicalId } from './alarm-utils' -import { getResourcesByType } from '../cf-template' +import { getResourceAlarmConfigurationsByType } from '../cf-template' -export interface SlicWatchAppSyncAlarmsConfig extends SlicWatchAlarmConfig { +export type SlicWatchAppSyncAlarmsConfig = T & { '5XXError': T Latency: T } @@ -27,11 +27,11 @@ export default function createAppSyncAlarms ( appSyncAlarmsConfig: SlicWatchAppSyncAlarmsConfig, alarmActionsConfig: AlarmActionsConfig, compiledTemplate: Template ): CloudFormationResources { const resources = {} - const appSyncResources = getResourcesByType('AWS::AppSync::GraphQLApi', compiledTemplate) + const configuredResources = getResourceAlarmConfigurationsByType('AWS::AppSync::GraphQLApi', compiledTemplate, appSyncAlarmsConfig) - for (const [appSyncLogicalId, appSyncResource] of Object.entries(appSyncResources)) { + for (const [appSyncLogicalId, appSyncResource] of Object.entries(configuredResources.resources)) { for (const metric of executionMetrics) { - const config: SlicWatchMergedConfig = appSyncAlarmsConfig[metric] + const config: SlicWatchMergedConfig = configuredResources.alarmConfigurations[appSyncLogicalId][metric] if (config.enabled) { const { enabled, ...rest } = config const graphQLName: string = appSyncResource.Properties?.Name diff --git a/core/alarms/dynamodb.ts b/core/alarms/dynamodb.ts index fa74fe2a..23642c4e 100644 --- a/core/alarms/dynamodb.ts +++ b/core/alarms/dynamodb.ts @@ -2,11 +2,11 @@ import type { AlarmProperties } from 'cloudform-types/types/cloudWatch/alarm' import type Template from 'cloudform-types/types/template' import { Fn } from 'cloudform' -import type { AlarmActionsConfig, CloudFormationResources, InputOutput, SlicWatchAlarmConfig, SlicWatchMergedConfig } from './alarm-types' +import type { AlarmActionsConfig, CloudFormationResources, InputOutput, SlicWatchMergedConfig } from './alarm-types' import { createAlarm, makeAlarmLogicalId } from './alarm-utils' -import { getResourcesByType } from '../cf-template' +import { getResourceAlarmConfigurationsByType } from '../cf-template' -export interface SlicWatchDynamoDbAlarmsConfig extends SlicWatchAlarmConfig { +export type SlicWatchDynamoDbAlarmsConfig = T & { ReadThrottleEvents: T WriteThrottleEvents: T UserErrors: T @@ -32,13 +32,13 @@ export default function createDynamoDbAlarms ( compiledTemplate: Template ): CloudFormationResources { const resources: CloudFormationResources = {} - const tableResources = getResourcesByType('AWS::DynamoDB::Table', compiledTemplate) + const configuredResources = getResourceAlarmConfigurationsByType('AWS::DynamoDB::Table', compiledTemplate, dynamoDbAlarmsConfig) - for (const [tableLogicalId, tableResource] of Object.entries(tableResources)) { + for (const [tableLogicalId, tableResource] of Object.entries(configuredResources.resources)) { for (const metric of dynamoDbMetrics) { - const config: SlicWatchMergedConfig = dynamoDbAlarmsConfig[metric] - if (config.enabled) { - const { enabled, ...rest } = config + const config: SlicWatchMergedConfig = configuredResources.alarmConfigurations[tableLogicalId][metric] + const { enabled, ...rest } = config + if (enabled) { const dynamoDbAlarmProperties: AlarmProperties = { AlarmName: Fn.Sub(`DDB_${metric}_Alarm_\${${tableLogicalId}}`, {}), AlarmDescription: Fn.Sub(`DynamoDB ${config.Statistic} for \${${tableLogicalId}} breaches ${config.Threshold}`, {}), diff --git a/core/alarms/ecs.ts b/core/alarms/ecs.ts index 95239fab..38bb8261 100644 --- a/core/alarms/ecs.ts +++ b/core/alarms/ecs.ts @@ -2,11 +2,11 @@ import type { AlarmProperties } from 'cloudform-types/types/cloudWatch/alarm' import type Template from 'cloudform-types/types/template' import { Fn } from 'cloudform' -import type { AlarmActionsConfig, CloudFormationResources, InputOutput, SlicWatchAlarmConfig, SlicWatchMergedConfig } from './alarm-types' +import type { AlarmActionsConfig, CloudFormationResources, InputOutput, SlicWatchMergedConfig } from './alarm-types' import { createAlarm } from './alarm-utils' -import { getResourcesByType } from '../cf-template' +import { getResourceAlarmConfigurationsByType } from '../cf-template' -export interface SlicWatchEcsAlarmsConfig extends SlicWatchAlarmConfig { +export type SlicWatchEcsAlarmsConfig = T & { MemoryUtilization: T CPUUtilization: T } @@ -49,15 +49,15 @@ export default function createECSAlarms ( ecsAlarmsConfig: SlicWatchEcsAlarmsConfig, alarmActionsConfig: AlarmActionsConfig, compiledTemplate: Template ): CloudFormationResources { const resources: CloudFormationResources = {} - const serviceResources = getResourcesByType('AWS::ECS::Service', compiledTemplate) + const configuredResources = getResourceAlarmConfigurationsByType('AWS::ECS::Service', compiledTemplate, ecsAlarmsConfig) - for (const [serviceLogicalId, serviceResource] of Object.entries(serviceResources)) { + for (const [serviceLogicalId, serviceResource] of Object.entries(configuredResources.resources)) { for (const metric of executionMetrics) { const cluster = serviceResource.Properties?.Cluster const clusterName = resolveEcsClusterNameAsCfn(cluster) - const config: SlicWatchMergedConfig = ecsAlarmsConfig[metric] - if (config.enabled) { - const { enabled, ...rest } = config + const config: SlicWatchMergedConfig = configuredResources.alarmConfigurations[serviceLogicalId][metric] + const { enabled, ...rest } = config + if (enabled) { const ecsAlarmProperties: AlarmProperties = { AlarmName: Fn.Sub(`ECS_${metric.replaceAll('Utilization', 'Alarm')}_\${${serviceLogicalId}.Name}`, {}), AlarmDescription: Fn.Sub(`ECS ${metric} for \${${serviceLogicalId}.Name} breaches ${config.Threshold}`, {}), diff --git a/core/alarms/eventbridge.ts b/core/alarms/eventbridge.ts index 91aab2e5..60e73e3e 100644 --- a/core/alarms/eventbridge.ts +++ b/core/alarms/eventbridge.ts @@ -1,10 +1,10 @@ import type Template from 'cloudform-types/types/template' import { Fn } from 'cloudform' -import type { AlarmActionsConfig, CloudFormationResources, InputOutput, SlicWatchAlarmConfig, SlicWatchMergedConfig } from './alarm-types' +import type { AlarmActionsConfig, CloudFormationResources, InputOutput, SlicWatchMergedConfig } from './alarm-types' import { createCfAlarms } from './alarm-utils' -export interface SlicWatchEventsAlarmsConfig extends SlicWatchAlarmConfig { +export type SlicWatchEventsAlarmsConfig = T & { FailedInvocations: T ThrottledRules: T } diff --git a/core/alarms/kinesis.ts b/core/alarms/kinesis.ts index 3e36b8f5..a2a6b427 100644 --- a/core/alarms/kinesis.ts +++ b/core/alarms/kinesis.ts @@ -3,11 +3,11 @@ import type Template from 'cloudform-types/types/template' import { Fn } from 'cloudform' import { pascal } from 'case' -import { getResourcesByType } from '../cf-template' -import type { AlarmActionsConfig, CloudFormationResources, InputOutput, SlicWatchAlarmConfig, SlicWatchMergedConfig } from './alarm-types' +import { getResourceAlarmConfigurationsByType } from '../cf-template' +import type { AlarmActionsConfig, CloudFormationResources, InputOutput, SlicWatchMergedConfig } from './alarm-types' import { createAlarm, getStatisticName, makeAlarmLogicalId } from './alarm-utils' -export interface SlicWatchKinesisAlarmsConfig extends SlicWatchAlarmConfig { +export type SlicWatchKinesisAlarmsConfig = T & { 'GetRecords.IteratorAgeMilliseconds': T ReadProvisionedThroughputExceeded: T WriteProvisionedThroughputExceeded: T @@ -39,13 +39,13 @@ export default function createKinesisAlarms ( kinesisAlarmsConfig: SlicWatchKinesisAlarmsConfig, alarmActionsConfig: AlarmActionsConfig, compiledTemplate: Template ): CloudFormationResources { const resources: CloudFormationResources = {} - const streamResources = getResourcesByType('AWS::Kinesis::Stream', compiledTemplate) + const configuredResources = getResourceAlarmConfigurationsByType('AWS::Kinesis::Stream', compiledTemplate, kinesisAlarmsConfig) - for (const [streamLogicalId] of Object.entries(streamResources)) { + for (const [streamLogicalId] of Object.entries(configuredResources.resources)) { for (const [type, metric] of Object.entries(kinesisAlarmTypes)) { - const config: SlicWatchMergedConfig = kinesisAlarmsConfig[metric] - if (config.enabled) { - const { enabled, ...rest } = config + const config: SlicWatchMergedConfig = configuredResources.alarmConfigurations[streamLogicalId][metric] + const { enabled, ...rest } = config + if (enabled) { const kinesisAlarmProperties: AlarmProperties = { AlarmName: Fn.Sub(`Kinesis_${type}_\${${streamLogicalId}}`, {}), AlarmDescription: Fn.Sub(`Kinesis ${getStatisticName(config)} ${metric} for \${${streamLogicalId}} breaches ${config.Threshold} milliseconds`, {}), diff --git a/core/alarms/lambda.ts b/core/alarms/lambda.ts index a64d2e70..08db913c 100644 --- a/core/alarms/lambda.ts +++ b/core/alarms/lambda.ts @@ -2,12 +2,11 @@ import type { AlarmProperties } from 'cloudform-types/types/cloudWatch/alarm' import type Template from 'cloudform-types/types/template' import { Fn } from 'cloudform' -import { getEventSourceMappingFunctions, getResourcesByType } from '../cf-template' -import type { AlarmActionsConfig, InputOutput, Value, SlicWatchMergedConfig, SlicWatchAlarmConfig } from './alarm-types' +import { getEventSourceMappingFunctions, getResourceAlarmConfigurationsByType } from '../cf-template' +import type { AlarmActionsConfig, InputOutput, Value, SlicWatchMergedConfig } from './alarm-types' import { createAlarm } from './alarm-utils' -import { cascade } from '../inputs/cascading-config' -export interface SlicWatchLambdaAlarmsConfig extends SlicWatchAlarmConfig { +export type SlicWatchLambdaAlarmsConfig = T & { Errors: T ThrottlesPc: T DurationPc: T @@ -25,23 +24,18 @@ const lambdaMetrics = ['Errors', 'ThrottlesPc', 'DurationPc', 'Invocations'] * @compiledTemplate CloudFormation template object * * @returns Lambda-specific CloudFormation Alarm resources - * - * TODO - Fix the lambdaAlarmConfig type */ export default function createLambdaAlarms ( lambdaAlarmConfig: SlicWatchLambdaAlarmsConfig, alarmActionsConfig: AlarmActionsConfig, compiledTemplate: Template ) { const resources = {} - const lambdaResources = getResourcesByType('AWS::Lambda::Function', compiledTemplate) - const mergedConfigPerFunction: Record> = {} - for (const [funcLogicalId, funcResource] of Object.entries(lambdaResources)) { - const resourceConfig = cascade(funcResource?.Metadata?.slicWatch?.alarms ?? {}) as SlicWatchLambdaAlarmsConfig - const mergedConfig: SlicWatchLambdaAlarmsConfig = Object.assign(lambdaAlarmConfig, resourceConfig) - mergedConfigPerFunction[funcLogicalId] = mergedConfig + const configuredLambdaResources = getResourceAlarmConfigurationsByType('AWS::Lambda::Function', compiledTemplate, lambdaAlarmConfig) + for (const [funcLogicalId, funcResource] of Object.entries(configuredLambdaResources.resources)) { + const mergedConfig = configuredLambdaResources.alarmConfigurations[funcLogicalId] for (const metric of lambdaMetrics) { - if (mergedConfig.enabled === false || mergedConfig[metric].enabled === false) { + if (!mergedConfig.enabled || mergedConfig[metric].enabled === false) { continue } if (metric === 'ThrottlesPc') { @@ -111,8 +105,8 @@ export default function createLambdaAlarms ( } } for (const funcLogicalId of Object.keys(getEventSourceMappingFunctions(compiledTemplate))) { - const config = mergedConfigPerFunction[funcLogicalId] - if (config.enabled !== false && config.IteratorAge.enabled) { + const config = configuredLambdaResources.alarmConfigurations[funcLogicalId] + if (config.enabled && config.IteratorAge.enabled) { Object.assign(resources, createLambdaCfAlarm(config.IteratorAge, 'IteratorAge', funcLogicalId, compiledTemplate, alarmActionsConfig)) } } diff --git a/core/alarms/sns.ts b/core/alarms/sns.ts index 1b38649e..4160a0af 100644 --- a/core/alarms/sns.ts +++ b/core/alarms/sns.ts @@ -1,10 +1,10 @@ import type Template from 'cloudform-types/types/template' import { Fn } from 'cloudform' -import type { AlarmActionsConfig, CloudFormationResources, InputOutput, SlicWatchAlarmConfig, SlicWatchMergedConfig } from './alarm-types' +import type { AlarmActionsConfig, CloudFormationResources, InputOutput, SlicWatchMergedConfig } from './alarm-types' import { createCfAlarms } from './alarm-utils' -export interface SlicWatchSnsAlarmsConfig extends SlicWatchAlarmConfig { +export type SlicWatchSnsAlarmsConfig = T & { 'NumberOfNotificationsFilteredOut-InvalidAttributes': T NumberOfNotificationsFailed: T } diff --git a/core/alarms/sqs.ts b/core/alarms/sqs.ts index 86adac6f..43937732 100644 --- a/core/alarms/sqs.ts +++ b/core/alarms/sqs.ts @@ -2,11 +2,11 @@ import type { AlarmProperties } from 'cloudform-types/types/cloudWatch/alarm' import type Template from 'cloudform-types/types/template' import { Fn } from 'cloudform' -import type { AlarmActionsConfig, CloudFormationResources, InputOutput, SlicWatchAlarmConfig, SlicWatchMergedConfig } from './alarm-types' +import type { AlarmActionsConfig, CloudFormationResources, InputOutput, SlicWatchMergedConfig } from './alarm-types' import { createAlarm } from './alarm-utils' -import { getResourcesByType } from '../cf-template' +import { getResourceAlarmConfigurationsByType } from '../cf-template' -export interface SlicWatchSqsAlarmsConfig extends SlicWatchAlarmConfig { +export type SlicWatchSqsAlarmsConfig = T & { InFlightMessagesPc: T AgeOfOldestMessage: T } @@ -25,20 +25,22 @@ export default function createSQSAlarms ( sqsAlarmsConfig: SlicWatchSqsAlarmsConfig, alarmActionsConfig: AlarmActionsConfig, compiledTemplate: Template ): CloudFormationResources { const resources: CloudFormationResources = {} - const queueResources = getResourcesByType('AWS::SQS::Queue', compiledTemplate) + const configuredResources = getResourceAlarmConfigurationsByType('AWS::SQS::Queue', compiledTemplate, sqsAlarmsConfig) - for (const [queueLogicalId, queueResource] of Object.entries(queueResources)) { - if (sqsAlarmsConfig.enabled === false) continue - if (sqsAlarmsConfig.InFlightMessagesPc.enabled) { - // TODO: verify if there is a way to reference these hard limits directly as variables in the alarm - // so that in case AWS changes them, the rule will still be valid - const config = sqsAlarmsConfig.InFlightMessagesPc - const { enabled, ...rest } = config + for (const [queueLogicalId, queueResource] of Object.entries(configuredResources.resources)) { + const mergedConfig = configuredResources.alarmConfigurations[queueLogicalId] + if (!mergedConfig.enabled) { + continue + } + + const inFlightMessagesPcConfig = mergedConfig.InFlightMessagesPc + if (inFlightMessagesPcConfig.enabled) { + const { enabled, ...rest } = inFlightMessagesPcConfig const hardLimit = (queueResource.Properties?.FifoQueue != null) ? 20000 : 120000 - const thresholdValue = Math.floor(hardLimit * (config.Threshold as any) / 100) + const thresholdValue = Math.floor(hardLimit * (inFlightMessagesPcConfig.Threshold as any) / 100) const sqsAlarmProperties: AlarmProperties = { AlarmName: Fn.Sub(`SQS_ApproximateNumberOfMessagesNotVisible_\${${queueLogicalId}.QueueName}`, {}), - AlarmDescription: Fn.Sub(`SQS in-flight messages for \${${queueLogicalId}.QueueName} breaches ${thresholdValue} (${config.Threshold}% of the hard limit of ${hardLimit})`, {}), + AlarmDescription: Fn.Sub(`SQS in-flight messages for \${${queueLogicalId}.QueueName} breaches ${thresholdValue} (${inFlightMessagesPcConfig.Threshold}% of the hard limit of ${hardLimit})`, {}), MetricName: 'ApproximateNumberOfMessagesNotVisible', Namespace: 'AWS/SQS', Dimensions: [{ Name: 'QueueName', Value: Fn.GetAtt(`${queueLogicalId}`, 'QueueName') }], @@ -50,16 +52,16 @@ export default function createSQSAlarms ( resources[resourceName] = resource } - if (sqsAlarmsConfig.AgeOfOldestMessage.enabled) { - if (sqsAlarmsConfig.AgeOfOldestMessage.Threshold == null) { + const ageOfOldestMessageConfig = sqsAlarmsConfig.AgeOfOldestMessage + if (ageOfOldestMessageConfig.enabled) { + if (ageOfOldestMessageConfig.Threshold == null) { throw new Error('SQS AgeOfOldestMessage alarm is enabled but `Threshold` is not specified. Please specify a threshold or disable the alarm.') } - const config = sqsAlarmsConfig.AgeOfOldestMessage - const { enabled, ...rest } = config + const { enabled, ...rest } = ageOfOldestMessageConfig const alarmProps = rest as AlarmProperties // All mandatory properties are set following cascading const sqsAlarmProperties: AlarmProperties = { AlarmName: Fn.Sub(`SQS_ApproximateAgeOfOldestMessage_\${${queueLogicalId}.QueueName}`, {}), - AlarmDescription: Fn.Sub(`SQS age of oldest message in the queue \${${queueLogicalId}.QueueName} breaches ${config.Threshold}`, {}), + AlarmDescription: Fn.Sub(`SQS age of oldest message in the queue \${${queueLogicalId}.QueueName} breaches ${ageOfOldestMessageConfig.Threshold as number}`, {}), MetricName: 'ApproximateAgeOfOldestMessage', Namespace: 'AWS/SQS', Dimensions: [{ Name: 'QueueName', Value: Fn.GetAtt(`${queueLogicalId}`, 'QueueName') }], diff --git a/core/alarms/step-functions.ts b/core/alarms/step-functions.ts index dae2b12c..1f775531 100644 --- a/core/alarms/step-functions.ts +++ b/core/alarms/step-functions.ts @@ -1,10 +1,10 @@ import type Template from 'cloudform-types/types/template' import { Fn } from 'cloudform' -import type { AlarmActionsConfig, CloudFormationResources, InputOutput, SlicWatchAlarmConfig, SlicWatchMergedConfig } from './alarm-types' +import type { AlarmActionsConfig, CloudFormationResources, InputOutput, SlicWatchMergedConfig } from './alarm-types' import { createCfAlarms } from './alarm-utils' -export interface SlicWatchSfAlarmsConfig extends SlicWatchAlarmConfig { +export type SlicWatchSfAlarmsConfig = T & { ExecutionThrottled: T ExecutionsFailed: T ExecutionsTimedOut: T diff --git a/core/cf-template.ts b/core/cf-template.ts index fcddf343..bdec82b1 100644 --- a/core/cf-template.ts +++ b/core/cf-template.ts @@ -3,6 +3,8 @@ import type Template from 'cloudform-types/types/template' import { filterObject } from './filter-object' import { getLogger } from './logging' +import { cascade } from './inputs/cascading-config' +import { type SlicWatchMergedConfig } from './alarms/alarm-types' const logger = getLogger() @@ -37,6 +39,36 @@ export function getResourcesByType (type: string, compiledTemplate: Template): R return filterObject(compiledTemplate.Resources ?? {}, (resource: { Type: string }) => resource.Type === type) } +export interface ResourceAlarmConfigurations { + resources: ResourceType + alarmConfigurations: Record +} + +/** + * Find all resources of a given type and merge any resource-specific SLIC Watch configuration with + * the global alarm configuration for resources of that type + * + * @param type The CloudFormation resource type + * @param template The CloudFormation template + * @param config The global alarm configuration for resources of this type + * @returns The resources along with the merged configuration for each resource by logical ID + */ +export function getResourceAlarmConfigurationsByType ( + type: string, template: Template, config: M +): ResourceAlarmConfigurations { + const alarmConfigurations: Record = {} + const resources = getResourcesByType(type, template) + for (const [funcLogicalId, resource] of Object.entries(resources)) { + const resourceConfig = cascade(resource?.Metadata?.slicWatch?.alarms ?? {}) as M + const mergedConfig: M = Object.assign(config, resourceConfig) + alarmConfigurations[funcLogicalId] = mergedConfig + } + return { + resources, + alarmConfigurations + } +} + export function getEventSourceMappingFunctions (compiledTemplate): ResourceType { const eventSourceMappings = getResourcesByType( 'AWS::Lambda::EventSourceMapping', compiledTemplate) From 41feffe776ecbd892c22ad964694f34b95043089 Mon Sep 17 00:00:00 2001 From: Eoin Shanaghy Date: Tue, 14 Nov 2023 15:25:33 +0000 Subject: [PATCH 08/35] feat: allow all resources to have configurable dashboards --- core/cf-template.ts | 32 +++++ core/dashboards/dashboard.ts | 237 +++++++++++++++++------------------ 2 files changed, 145 insertions(+), 124 deletions(-) diff --git a/core/cf-template.ts b/core/cf-template.ts index bdec82b1..1233591c 100644 --- a/core/cf-template.ts +++ b/core/cf-template.ts @@ -5,6 +5,7 @@ import { filterObject } from './filter-object' import { getLogger } from './logging' import { cascade } from './inputs/cascading-config' import { type SlicWatchMergedConfig } from './alarms/alarm-types' +import { type SlicWatchDashboardConfig, type WidgetMetricProperties } from './dashboards/dashboard-types' const logger = getLogger() @@ -44,6 +45,11 @@ export interface ResourceAlarmConfigurations { alarmConfigurations: Record } +export interface ResourceDashboardConfigurations { + resources: ResourceType + dashConfigurations: Record +} + /** * Find all resources of a given type and merge any resource-specific SLIC Watch configuration with * the global alarm configuration for resources of that type @@ -69,6 +75,32 @@ export function getResourceAlarmConfigurationsByType ( + type: string, template: Template, config: T +): ResourceDashboardConfigurations { + const dashConfigurations: Record = {} + const resources = getResourcesByType(type, template) + for (const [logicalId, resource] of Object.entries(resources)) { + dashConfigurations[logicalId] = { + ...config, + ...cascade(resource?.Metadata?.slicWatch?.dashboard ?? {}) as SlicWatchDashboardConfig + } + } + return { + resources, + dashConfigurations + } +} + export function getEventSourceMappingFunctions (compiledTemplate): ResourceType { const eventSourceMappings = getResourcesByType( 'AWS::Lambda::EventSourceMapping', compiledTemplate) diff --git a/core/dashboards/dashboard.ts b/core/dashboards/dashboard.ts index bca8b561..c3dd3703 100644 --- a/core/dashboards/dashboard.ts +++ b/core/dashboards/dashboard.ts @@ -2,8 +2,7 @@ import type Template from 'cloudform-types/types/template' import { type Dashboard, type WidgetMetric, type Statistic, type YAxisPosition } from 'cloudwatch-dashboard-types' import { cascade } from '../inputs/cascading-config' -import { getResourcesByType, getEventSourceMappingFunctions, addResource } from '../cf-template' -import type { ResourceType } from '../cf-template' +import { getEventSourceMappingFunctions, addResource, getResourceDashboardConfigurationsByType } from '../cf-template' import type { WidgetMetricProperties, MetricDefs, SlicWatchDashboardConfig, SlicWatchInputDashboardConfig, Widgets, WidgetWithSize @@ -22,6 +21,10 @@ const MAX_WIDTH = 24 const logger = getLogger() /** + * Adds a dashboard to the specified CloudFormation template based on the resources provided in the template. + * + * A CloudFormation template + * * @param {*} dashboardConfig The global plugin dashboard configuration * @param {*} compiledTemplate A CloudFormation template object */ @@ -44,39 +47,18 @@ export default function addDashboard (dashboardConfig: SlicWatchInputDashboardCo } } = cascade(dashboardConfig) as SlicWatchDashboardConfig - /** - * Adds a dashboard to the specified CloudFormation template - * based on the resources provided in the template. - * - * A CloudFormation template - */ - const apiResources = getResourcesByType('AWS::ApiGateway::RestApi', compiledTemplate) - const stateMachineResources = getResourcesByType('AWS::StepFunctions::StateMachine', compiledTemplate) - const lambdaResources = getResourcesByType('AWS::Lambda::Function', compiledTemplate) - const tableResources = getResourcesByType('AWS::DynamoDB::Table', compiledTemplate) - const streamResources = getResourcesByType('AWS::Kinesis::Stream', compiledTemplate) - const queueResources = getResourcesByType('AWS::SQS::Queue', compiledTemplate) - const ecsServiceResources = getResourcesByType('AWS::ECS::Service', compiledTemplate) - const topicResources = getResourcesByType('AWS::SNS::Topic', compiledTemplate) - const ruleResources = getResourcesByType('AWS::Events::Rule', compiledTemplate) - const loadBalancerResources = getResourcesByType('AWS::ElasticLoadBalancingV2::LoadBalancer', compiledTemplate) - const targetGroupResources = getResourcesByType('AWS::ElasticLoadBalancingV2::TargetGroup', compiledTemplate) - - const appSyncResources = getResourcesByType('AWS::AppSync::GraphQLApi', compiledTemplate) - - const eventSourceMappingFunctions = getEventSourceMappingFunctions(compiledTemplate) - const apiWidgets = createApiWidgets(apiResources) - const stateMachineWidgets = createStateMachineWidgets(stateMachineResources) - const dynamoDbWidgets = createDynamoDbWidgets(tableResources) - const lambdaWidgets = createLambdaWidgets(lambdaResources, Object.keys(eventSourceMappingFunctions)) - const streamWidgets = createStreamWidgets(streamResources) - const queueWidgets = createQueueWidgets(queueResources) - const ecsWidgets = createEcsWidgets(ecsServiceResources) - const topicWidgets = createTopicWidgets(topicResources) - const ruleWidgets = createRuleWidgets(ruleResources) - const loadBalancerWidgets = createLoadBalancerWidgets(loadBalancerResources) - const targetGroupWidgets = createTargetGroupWidgets(targetGroupResources, compiledTemplate) - const appSyncWidgets = createAppSyncWidgets(appSyncResources) + const apiWidgets = createApiWidgets() + const stateMachineWidgets = createStateMachineWidgets() + const dynamoDbWidgets = createDynamoDbWidgets() + const lambdaWidgets = createLambdaWidgets() + const streamWidgets = createStreamWidgets() + const queueWidgets = createQueueWidgets() + const ecsWidgets = createEcsWidgets() + const topicWidgets = createTopicWidgets() + const ruleWidgets = createRuleWidgets() + const loadBalancerWidgets = createLoadBalancerWidgets() + const targetGroupWidgets = createTargetGroupWidgets() + const appSyncWidgets = createAppSyncWidgets() const positionedWidgets = layOutWidgets([ ...apiWidgets, @@ -141,29 +123,23 @@ export default function addDashboard (dashboardConfig: SlicWatchInputDashboardCo } /** - * Create a set of CloudWatch Dashboard widgets for the Lambda - * CloudFormation resources provided + * Create a set of CloudWatch Dashboard widgets for the Lambda Functions in the specified template * - * Object with CloudFormation Lambda Function resources by resource name - * eventSourceMappingFunctionResourceNames Names of Lambda function resources that are linked to EventSourceMappings + * @return * Object with CloudFormation Lambda Function resources by resource name */ - function createLambdaWidgets (functionResources: ResourceType, eventSourceMappingFunctionResourceNames: string[]): WidgetWithSize[] { + function createLambdaWidgets (): WidgetWithSize[] { + const configuredResources = getResourceDashboardConfigurationsByType('AWS::Lambda::Function', compiledTemplate, lambdaDashConfig) + const eventSourceMappingFunctions = getEventSourceMappingFunctions(compiledTemplate) + const lambdaWidgets: any = [] - const configPerFunctionResource: Record = {} - for (const [logicalId, resource] of Object.entries(functionResources)) { - configPerFunctionResource[logicalId] = { - ...lambdaDashConfig, - ...cascade(resource?.Metadata?.slicWatch?.dashboard ?? {}) as SlicWatchDashboardConfig - } - } - if (Object.keys(functionResources).length > 0) { + if (Object.keys(configuredResources.resources).length > 0) { for (const [metric, metricConfig] of Object.entries(getConfiguredMetrics(lambdaDashConfig))) { if (metric !== 'IteratorAge' as any) { for (const stat of metricConfig.Statistic) { const metricDefs: MetricDefs[] = [] - for (const funcLogicalId of Object.keys(functionResources)) { - const funcConfig = configPerFunctionResource[funcLogicalId] + for (const funcLogicalId of Object.keys(configuredResources.resources)) { + const funcConfig = configuredResources.dashConfigurations[funcLogicalId] const metricConfig = funcConfig[metric] if (metricConfig.enabled !== false) { metricDefs.push({ @@ -185,9 +161,9 @@ export default function addDashboard (dashboardConfig: SlicWatchInputDashboardCo } } } else { - for (const funcLogicalId of eventSourceMappingFunctionResourceNames) { + for (const funcLogicalId of Object.keys(eventSourceMappingFunctions)) { // Add IteratorAge alarm if the Lambda function has an EventSourceMapping trigger - const funcConfig = configPerFunctionResource[funcLogicalId] + const funcConfig = configuredResources.dashConfigurations[funcLogicalId] const functionMetricConfig = funcConfig[metric] if (functionMetricConfig.enabled !== false) { const stats: string[] = [] @@ -232,12 +208,14 @@ export default function addDashboard (dashboardConfig: SlicWatchInputDashboardCo * Object of CloudFormation RestApi resources by resource name */ - function createApiWidgets (apiResources: ResourceType): WidgetWithSize[] { + function createApiWidgets (): WidgetWithSize[] { + const configuredResources = getResourceDashboardConfigurationsByType('AWS::ApiGateway::RestApi', compiledTemplate, apiGwDashConfig) const apiWidgets: WidgetWithSize[] = [] - for (const [resourceName, res] of Object.entries(apiResources)) { - const apiName: string = resolveRestApiNameForSub(res, resourceName) // e.g., ${AWS::Stack} (Ref), ${OtherResource.Name} (GetAtt) + for (const [logicalId, res] of Object.entries(configuredResources.resources)) { + const apiName: string = resolveRestApiNameForSub(res, logicalId) // e.g., ${AWS::Stack} (Ref), ${OtherResource.Name} (GetAtt) const widgetMetrics: MetricDefs[] = [] - for (const [metric, metricConfig] of Object.entries(getConfiguredMetrics(apiGwDashConfig))) { + const mergedConfig = configuredResources.dashConfigurations[logicalId] + for (const [metric, metricConfig] of Object.entries(getConfiguredMetrics(mergedConfig))) { if (metricConfig.enabled) { for (const stat of metricConfig.Statistic) { widgetMetrics.push({ @@ -269,11 +247,13 @@ export default function addDashboard (dashboardConfig: SlicWatchInputDashboardCo * * Object of Step Function State Machine resources by resource name */ - function createStateMachineWidgets (smResources: ResourceType): WidgetWithSize[] { + function createStateMachineWidgets (): WidgetWithSize[] { + const stateMachineResources = getResourceDashboardConfigurationsByType('AWS::StepFunctions::StateMachine', compiledTemplate, sfDashConfig) const smWidgets: WidgetWithSize[] = [] - for (const [logicalId] of Object.entries(smResources)) { + for (const [logicalId] of Object.entries(stateMachineResources.resources)) { + const mergedConfig = stateMachineResources.dashConfigurations[logicalId] const widgetMetrics: MetricDefs[] = [] - for (const [metric, metricConfig] of Object.entries(getConfiguredMetrics(sfDashConfig))) { + for (const [metric, metricConfig] of Object.entries(getConfiguredMetrics(mergedConfig))) { if (metricConfig.enabled) { for (const stat of metricConfig.Statistic) { widgetMetrics.push({ @@ -304,11 +284,13 @@ export default function addDashboard (dashboardConfig: SlicWatchInputDashboardCo * * Object of DynamoDB table resources by resource name */ - function createDynamoDbWidgets (tableResources: ResourceType): WidgetWithSize[] { + function createDynamoDbWidgets (): WidgetWithSize[] { + const configuredResources = getResourceDashboardConfigurationsByType('AWS::DynamoDB::Table', compiledTemplate, dynamoDbDashConfig) const ddbWidgets: WidgetWithSize[] = [] - for (const [logicalId, res] of Object.entries(tableResources)) { + for (const [logicalId, res] of Object.entries(configuredResources.resources)) { + const mergedConfig = configuredResources.dashConfigurations[logicalId] const widgetMetrics: MetricDefs[] = [] - for (const [metric, metricConfig] of Object.entries(getConfiguredMetrics(dynamoDbDashConfig))) { + for (const [metric, metricConfig] of Object.entries(getConfiguredMetrics(mergedConfig))) { if (metricConfig.enabled) { for (const stat of metricConfig.Statistic) { widgetMetrics.push({ @@ -361,7 +343,8 @@ export default function addDashboard (dashboardConfig: SlicWatchInputDashboardCo * * Object with CloudFormation Kinesis Data Stream resources by resource name */ - function createStreamWidgets (streamResources: ResourceType): WidgetWithSize[] { + function createStreamWidgets (): WidgetWithSize[] { + const configuredResources = getResourceDashboardConfigurationsByType('AWS::Kinesis::Stream', compiledTemplate, kinesisDashConfig) const streamWidgets: WidgetWithSize[] = [] const metricGroups = { @@ -369,14 +352,14 @@ export default function addDashboard (dashboardConfig: SlicWatchInputDashboardCo 'Get/Put Success': ['PutRecord.Success', 'PutRecords.Success', 'GetRecords.Success'], 'Provisioned Throughput': ['ReadProvisionedThroughputExceeded', 'WriteProvisionedThroughputExceeded'] } - const metricConfigs = getConfiguredMetrics(kinesisDashConfig) - for (const [logicalId] of Object.entries(streamResources)) { + for (const [logicalId] of Object.entries(configuredResources.resources)) { + const streamConfig = configuredResources.dashConfigurations[logicalId] for (const [group, metrics] of Object.entries(metricGroups)) { const widgetMetrics: MetricDefs[] = [] for (const metric of metrics) { - const metricConfig = metricConfigs[metric] - if (metricConfig.enabled) { + const metricConfig = streamConfig[metric] + if (metricConfig.enabled !== false) { for (const stat of metricConfig.Statistic) { widgetMetrics.push({ namespace: 'AWS/Kinesis', @@ -403,7 +386,8 @@ export default function addDashboard (dashboardConfig: SlicWatchInputDashboardCo * Create a set of CloudWatch Dashboard widgets for the SQS resources provided * Object with CloudFormation SQS resources by resource name */ - function createQueueWidgets (queueResources: ResourceType): WidgetWithSize[] { + function createQueueWidgets (): WidgetWithSize[] { + const configuredResources = getResourceDashboardConfigurationsByType('AWS::SQS::Queue', compiledTemplate, sqsDashConfig) const queueWidgets: WidgetWithSize[] = [] const metricGroups = { @@ -411,14 +395,13 @@ export default function addDashboard (dashboardConfig: SlicWatchInputDashboardCo 'Oldest Message age': ['ApproximateAgeOfOldestMessage'], 'Messages in queue': ['ApproximateNumberOfMessagesVisible'] } - const metricConfigs = getConfiguredMetrics(sqsDashConfig) - - for (const [logicalId] of Object.entries(queueResources)) { + for (const [logicalId] of Object.entries(configuredResources.resources)) { + const mergedConfig = configuredResources.dashConfigurations[logicalId] for (const [group, metrics] of Object.entries(metricGroups)) { const widgetMetrics: MetricDefs[] = [] for (const metric of metrics) { - const metricConfig = metricConfigs[metric] - if (metricConfig.enabled) { + const metricConfig = mergedConfig[metric] + if (metricConfig.enabled !== false) { for (const stat of metricConfig.Statistic) { widgetMetrics.push({ namespace: 'AWS/SQS', @@ -449,13 +432,14 @@ export default function addDashboard (dashboardConfig: SlicWatchInputDashboardCo * * Object of ECS Service resources by resource name */ - function createEcsWidgets (ecsServiceResources: ResourceType): WidgetWithSize[] { + function createEcsWidgets (): WidgetWithSize[] { + const configuredResources = getResourceDashboardConfigurationsByType('AWS::ECS::Service', compiledTemplate, ecsDashConfig) const ecsWidgets: WidgetWithSize[] = [] - for (const [logicalId, res] of Object.entries(ecsServiceResources)) { + for (const [logicalId, res] of Object.entries(configuredResources.resources)) { const clusterName = resolveEcsClusterNameForSub(res.Properties?.Cluster) - + const mergedConfig = configuredResources.dashConfigurations[logicalId] const widgetMetrics: MetricDefs[] = [] - for (const [metric, metricConfig] of Object.entries(getConfiguredMetrics(ecsDashConfig))) { + for (const [metric, metricConfig] of Object.entries(getConfiguredMetrics(mergedConfig))) { if (metricConfig.enabled) { for (const stat of metricConfig.Statistic) { widgetMetrics.push({ @@ -484,14 +468,14 @@ export default function addDashboard (dashboardConfig: SlicWatchInputDashboardCo /** * Create a set of CloudWatch Dashboard widgets for SNS services. - * - * Object of SNS Service resources by resource name */ - function createTopicWidgets (topicResources: ResourceType): WidgetWithSize[] { + function createTopicWidgets (): WidgetWithSize[] { + const configuredResources = getResourceDashboardConfigurationsByType('AWS::SNS::Topic', compiledTemplate, snsDashConfig) const topicWidgets: WidgetWithSize[] = [] - for (const logicalId of Object.keys(topicResources)) { + for (const logicalId of Object.keys(configuredResources.resources)) { const widgetMetrics: MetricDefs[] = [] - for (const [metric, metricConfig] of Object.entries(getConfiguredMetrics(snsDashConfig))) { + const mergedConfig = configuredResources.dashConfigurations[logicalId] + for (const [metric, metricConfig] of Object.entries(getConfiguredMetrics(mergedConfig))) { if (metricConfig.enabled) { for (const stat of metricConfig.Statistic) { widgetMetrics.push({ @@ -522,11 +506,13 @@ export default function addDashboard (dashboardConfig: SlicWatchInputDashboardCo * * Object of EventBridge Service resources by resource name */ - function createRuleWidgets (ruleResources: ResourceType): WidgetWithSize[] { + function createRuleWidgets (): WidgetWithSize[] { + const configuredResources = getResourceDashboardConfigurationsByType('AWS::Events::Rule', compiledTemplate, ruleDashConfig) const ruleWidgets: WidgetWithSize[] = [] - for (const [logicalId] of Object.entries(ruleResources)) { + for (const [logicalId] of Object.entries(configuredResources.resources)) { const widgetMetrics: MetricDefs[] = [] - for (const [metric, metricConfig] of Object.entries(getConfiguredMetrics(ruleDashConfig))) { + const mergedConfig = configuredResources.dashConfigurations[logicalId] + for (const [metric, metricConfig] of Object.entries(getConfiguredMetrics(mergedConfig))) { if (metricConfig.enabled) { for (const stat of metricConfig.Statistic) { widgetMetrics.push({ @@ -542,7 +528,7 @@ export default function addDashboard (dashboardConfig: SlicWatchInputDashboardCo const metricStatWidget = createMetricWidget( `EventBridge Rule \${${logicalId}}`, widgetMetrics, - ruleDashConfig + mergedConfig ) ruleWidgets.push(metricStatWidget) } @@ -552,17 +538,17 @@ export default function addDashboard (dashboardConfig: SlicWatchInputDashboardCo /** * Create a set of CloudWatch Dashboard widgets for Application Load Balancer services. - * - * Object of Application Load Balancer Service resources by resource name */ - function createLoadBalancerWidgets (loadBalancerResources: ResourceType): WidgetWithSize[] { + function createLoadBalancerWidgets (): WidgetWithSize[] { + const configuredResources = getResourceDashboardConfigurationsByType('AWS::ElasticLoadBalancingV2::LoadBalancer', compiledTemplate, albDashConfig) const loadBalancerWidgets: WidgetWithSize[] = [] - for (const [logicalId] of Object.entries(loadBalancerResources)) { + for (const [logicalId] of Object.entries(configuredResources.resources)) { const loadBalancerName = `\${${logicalId}.LoadBalancerName}` + const mergedConfig = configuredResources.dashConfigurations[logicalId] const loadBalancerFullName = resolveLoadBalancerFullNameForSub(logicalId) const widgetMetrics: MetricDefs[] = [] - for (const [metric, metricConfig] of Object.entries(getConfiguredMetrics(albDashConfig))) { + for (const [metric, metricConfig] of Object.entries(getConfiguredMetrics(mergedConfig))) { if (metricConfig.enabled) { for (const stat of metricConfig.Statistic) { widgetMetrics.push({ @@ -580,7 +566,7 @@ export default function addDashboard (dashboardConfig: SlicWatchInputDashboardCo const metricStatWidget = createMetricWidget( `ALB ${loadBalancerName}`, widgetMetrics, - albDashConfig + mergedConfig ) loadBalancerWidgets.push(metricStatWidget) } @@ -594,15 +580,18 @@ export default function addDashboard (dashboardConfig: SlicWatchInputDashboardCo * Object of Application Load Balancer Service Target Group resources by resource name * The full CloudFormation template instance used to look up associated listener and ALB resources */ - function createTargetGroupWidgets (targetGroupResources: ResourceType, compiledTemplate: Template): WidgetWithSize[] { + function createTargetGroupWidgets (): WidgetWithSize[] { + const configuredResources = getResourceDashboardConfigurationsByType('AWS::ElasticLoadBalancingV2::TargetGroup', compiledTemplate, albTargetDashConfig) + const targetGroupWidgets: WidgetWithSize[] = [] - for (const [tgLogicalId, targetGroupResource] of Object.entries(targetGroupResources)) { + for (const [tgLogicalId, targetGroupResource] of Object.entries(configuredResources.resources)) { + const mergedConfig = configuredResources.dashConfigurations[tgLogicalId] const loadBalancerLogicalIds = findLoadBalancersForTargetGroup(tgLogicalId, compiledTemplate) for (const loadBalancerLogicalId of loadBalancerLogicalIds) { const targetGroupFullName = resolveTargetGroupFullNameForSub(tgLogicalId) const loadBalancerFullName = `\${${loadBalancerLogicalId}.LoadBalancerFullName}` const widgetMetrics: MetricDefs[] = [] - for (const [metric, metricConfig] of Object.entries(getConfiguredMetrics(albTargetDashConfig))) { + for (const [metric, metricConfig] of Object.entries(getConfiguredMetrics(mergedConfig))) { if (metricConfig.enabled && (targetGroupResource.Properties?.TargetType === 'lambda' || !['LambdaUserError', 'LambdaInternalError'].includes(metric)) ) { @@ -623,7 +612,7 @@ export default function addDashboard (dashboardConfig: SlicWatchInputDashboardCo const metricStatWidget = createMetricWidget( `Target Group \${${loadBalancerLogicalId}.LoadBalancerName}/\${${tgLogicalId}.TargetGroupName}`, widgetMetrics, - albTargetDashConfig + mergedConfig ) targetGroupWidgets.push(metricStatWidget) } @@ -637,42 +626,42 @@ export default function addDashboard (dashboardConfig: SlicWatchInputDashboardCo * * Object of AppSync Service resources by resource name */ - function createAppSyncWidgets (appSyncResources: ResourceType): WidgetWithSize[] { + function createAppSyncWidgets (): WidgetWithSize[] { + const configuredResources = getResourceDashboardConfigurationsByType('AWS::AppSync::GraphQLApi', compiledTemplate, appSyncDashConfig) + const appSyncWidgets: WidgetWithSize[] = [] const metricGroups = { API: ['5XXError', '4XXError', 'Latency', 'Requests'], 'Real-time Subscriptions': ['ConnectServerError', 'DisconnectServerError', 'SubscribeServerError', 'UnsubscribeServerError', 'PublishDataMessageServerError'] } - const metricConfigs = getConfiguredMetrics(appSyncDashConfig) - for (const res of Object.values(appSyncResources)) { + for (const [logicalId, res] of Object.entries(configuredResources.resources)) { const appSyncResourceName: string = res.Properties?.Name - for (const [logicalId] of Object.entries(appSyncResources)) { - const graphQLAPIId = resolveGraphQLId(logicalId) - for (const [group, metrics] of Object.entries(metricGroups)) { - const widgetMetrics: MetricDefs[] = [] - for (const metric of metrics) { - const metricConfig: WidgetMetricProperties | Widgets = metricConfigs[metric] - if (metricConfig.enabled) { - const stats: string[] = [] - metricConfig?.Statistic?.forEach(stat => stats.push(stat)) - for (const stat of stats) { - widgetMetrics.push({ - namespace: 'AWS/AppSync', - metric, - dimensions: { GraphQLAPIId: graphQLAPIId }, - stat: stat as Statistic, - yAxis: metricConfig.yAxis as YAxisPosition - }) - } + const mergedConfig = configuredResources.dashConfigurations[logicalId] + const graphQLAPIId = resolveGraphQLId(logicalId) + for (const [group, metrics] of Object.entries(metricGroups)) { + const widgetMetrics: MetricDefs[] = [] + for (const metric of metrics) { + const metricConfig = mergedConfig[metric] + if (metricConfig.enabled !== false) { + const stats: string[] = [] + metricConfig?.Statistic?.forEach(stat => stats.push(stat)) + for (const stat of stats) { + widgetMetrics.push({ + namespace: 'AWS/AppSync', + metric, + dimensions: { GraphQLAPIId: graphQLAPIId }, + stat: stat as Statistic, + yAxis: metricConfig.yAxis as YAxisPosition + }) } } - if (widgetMetrics.length > 0) { - appSyncWidgets.push(createMetricWidget( - `AppSync ${group} ${appSyncResourceName}`, - widgetMetrics, - sqsDashConfig - )) - } + } + if (widgetMetrics.length > 0) { + appSyncWidgets.push(createMetricWidget( + `AppSync ${group} ${appSyncResourceName}`, + widgetMetrics, + mergedConfig + )) } } } From 6dad4224effb8509b84b548662dfe03af805a4c7 Mon Sep 17 00:00:00 2001 From: Eoin Shanaghy Date: Tue, 14 Nov 2023 22:17:03 +0000 Subject: [PATCH 09/35] chore: add unit tests for resource customised alarms --- cf-macro/tests/index.test.ts | 19 +++--- core/alarms/alarm-types.ts | 3 +- core/alarms/alarms.ts | 2 +- core/alarms/appsync.ts | 4 +- core/alarms/dynamodb.ts | 10 ++-- core/alarms/sqs.ts | 2 +- core/alarms/tests/alb-target-group.test.ts | 56 +++++++++++++++--- core/alarms/tests/alb.test.ts | 49 +++++++++++---- core/alarms/tests/api-gateway.test.ts | 66 ++++++++++++++++----- core/alarms/tests/appsync.test.ts | 56 ++++++++++++------ core/alarms/tests/dynamodb.test.ts | 69 ++++++++++++++++++---- core/alarms/tests/ecs.test.ts | 46 ++++++++++++--- core/alarms/tests/eventbridge.test.ts | 55 +++++++++++++---- core/alarms/tests/kinesis.test.ts | 50 +++++++++++++--- core/alarms/tests/sns.test.ts | 49 ++++++++++++--- core/alarms/tests/sqs.test.ts | 66 +++++++++++++++++---- core/alarms/tests/step-functions.test.ts | 59 ++++++++++++++---- core/cf-template.ts | 10 +--- core/tests/testing-utils.ts | 2 +- 19 files changed, 526 insertions(+), 147 deletions(-) diff --git a/cf-macro/tests/index.test.ts b/cf-macro/tests/index.test.ts index 163a3c7f..1490fb5e 100644 --- a/cf-macro/tests/index.test.ts +++ b/cf-macro/tests/index.test.ts @@ -1,13 +1,14 @@ import { test } from 'tap' import _ from 'lodash' -import type Template from 'cloudform-types/types/template' +import type { Template } from 'cloudform-types' +import type Resource from 'cloudform-types/types/resource' import { handler } from '../index' import _template from './event.json' const template = _template as Template -const event = { fragment: template } +const event = { fragment: template, requestId: 'test' } test('macro returns success', async t => { const result = await handler(event) @@ -37,7 +38,7 @@ test('macro uses topicArn if specified', async t => { const result = await handler(eventWithTopic) t.equal(result.status, 'success') t.notOk(result.errorMessage) - t.same(result.fragment.Resources.slicWatchLambdaDurationAlarmHelloLambdaFunction.Properties.AlarmActions, [topicArn]) + t.same(result?.fragment?.Resources?.slicWatchLambdaDurationAlarmHelloLambdaFunction?.Properties?.AlarmActions, [topicArn]) t.end() }) @@ -51,21 +52,23 @@ test('Macro skips SLIC Watch if top-level enabled==false', async t => { }) test('Macro adds dashboard and alarms if no function configuration is provided', async t => { + const functionResource: Resource = { + ...event.fragment.Resources?.HelloLambdaFunction, + Metadata: {} + } as unknown as Resource + const testEvent = { ...event, fragment: { ...event.fragment, Resources: { ...event.fragment.Resources, - HelloLambdaFunction: { - ...event.fragment.Resources?.HelloLambdaFunction, - Metadata: {} - } + HelloLambdaFunction: functionResource } } } const compiledTemplate = (await handler(testEvent)).fragment - t.same(compiledTemplate.Resources.Properties, template.Resources?.Properties) + t.same(compiledTemplate?.Resources?.Properties, template.Resources?.Properties) t.end() }) diff --git a/core/alarms/alarm-types.ts b/core/alarms/alarm-types.ts index 733d3e23..af224a36 100644 --- a/core/alarms/alarm-types.ts +++ b/core/alarms/alarm-types.ts @@ -28,6 +28,7 @@ export interface AlarmTemplate { */ export interface SlicWatchAlarmConfig extends Omit { ComparisonOperator?: string + EvaluationPeriods?: number enabled?: boolean } @@ -46,7 +47,7 @@ export interface AlarmActionsConfig { alarmActions?: string[] } -export interface SlicWatchCascadedAlarmsConfig extends AlarmProperties { +export type SlicWatchCascadedAlarmsConfig = T & { enabled: boolean Lambda: SlicWatchLambdaAlarmsConfig ApiGateway: SlicWatchApiGwAlarmsConfig diff --git a/core/alarms/alarms.ts b/core/alarms/alarms.ts index b98e5146..193990b2 100644 --- a/core/alarms/alarms.ts +++ b/core/alarms/alarms.ts @@ -51,7 +51,7 @@ export default function addAlarms ( enabled } = cascade(alarmProperties) as SlicWatchCascadedAlarmsConfig - const funcsWithConfig: Array<{ config: SlicWatchAlarmConfig, alarmFunc: any }> = [ + const funcsWithConfig: Array<{ config: SlicWatchMergedConfig, alarmFunc: any }> = [ { config: apiGwConfig, alarmFunc: createApiGatewayAlarms }, { config: sfConfig, alarmFunc: createStatesAlarms }, { config: dynamoDbConfig, alarmFunc: createDynamoDbAlarms }, diff --git a/core/alarms/appsync.ts b/core/alarms/appsync.ts index 3a8852ae..767141be 100644 --- a/core/alarms/appsync.ts +++ b/core/alarms/appsync.ts @@ -32,8 +32,8 @@ export default function createAppSyncAlarms ( for (const [appSyncLogicalId, appSyncResource] of Object.entries(configuredResources.resources)) { for (const metric of executionMetrics) { const config: SlicWatchMergedConfig = configuredResources.alarmConfigurations[appSyncLogicalId][metric] - if (config.enabled) { - const { enabled, ...rest } = config + const { enabled, ...rest } = config + if (enabled) { const graphQLName: string = appSyncResource.Properties?.Name const appSyncAlarmProperties: AlarmProperties = { AlarmName: `AppSync_${metric}Alarm_${graphQLName}`, diff --git a/core/alarms/dynamodb.ts b/core/alarms/dynamodb.ts index 23642c4e..682295f9 100644 --- a/core/alarms/dynamodb.ts +++ b/core/alarms/dynamodb.ts @@ -53,12 +53,12 @@ export default function createDynamoDbAlarms ( } } for (const metric of dynamoDbGsiMetrics) { - const config: SlicWatchMergedConfig = dynamoDbAlarmsConfig[metric] + const config: SlicWatchDynamoDbAlarmsConfig = configuredResources.alarmConfigurations[tableLogicalId][metric] for (const gsi of tableResource.Properties?.GlobalSecondaryIndexes ?? []) { - if (dynamoDbAlarmsConfig.ReadThrottleEvents.enabled && dynamoDbAlarmsConfig.WriteThrottleEvents.enabled) { - const { enabled, ...rest } = config - const gsiName: string = gsi.IndexName - const gsiIdentifierSub = `\${${tableLogicalId}}${gsiName}` + const gsiName: string = gsi.IndexName + const gsiIdentifierSub = `\${${tableLogicalId}}${gsiName}` + const { enabled, ...rest } = config + if (enabled) { const dynamoDbAlarmsConfig: AlarmProperties = { AlarmName: Fn.Sub(`DDB_${metric}_Alarm_${gsiIdentifierSub}`, {}), AlarmDescription: Fn.Sub(`DynamoDB ${config.Statistic} for ${gsiIdentifierSub} breaches ${config.Threshold}`, {}), diff --git a/core/alarms/sqs.ts b/core/alarms/sqs.ts index 43937732..c07e46a7 100644 --- a/core/alarms/sqs.ts +++ b/core/alarms/sqs.ts @@ -52,7 +52,7 @@ export default function createSQSAlarms ( resources[resourceName] = resource } - const ageOfOldestMessageConfig = sqsAlarmsConfig.AgeOfOldestMessage + const ageOfOldestMessageConfig = mergedConfig.AgeOfOldestMessage if (ageOfOldestMessageConfig.enabled) { if (ageOfOldestMessageConfig.Threshold == null) { throw new Error('SQS AgeOfOldestMessage alarm is enabled but `Threshold` is not specified. Please specify a threshold or disable the alarm.') diff --git a/core/alarms/tests/alb-target-group.test.ts b/core/alarms/tests/alb-target-group.test.ts index dc549bf7..7a081098 100644 --- a/core/alarms/tests/alb-target-group.test.ts +++ b/core/alarms/tests/alb-target-group.test.ts @@ -1,5 +1,7 @@ import { test } from 'tap' +import type { AlarmProperties } from 'cloudform-types/types/cloudWatch/alarm' + import createAlbTargetAlarms, { findLoadBalancersForTargetGroup } from '../alb-target-group' import { defaultConfig } from '../../inputs/default-config' import { @@ -188,7 +190,7 @@ test('findLoadBalancersForTargetGroup', (t) => { }) test('ALB Target Group alarms are created', (t) => { - const AlarmPropertiesTargetGroup = createTestConfig( + const testConfig = createTestConfig( defaultConfig.alarms, { Period: 120, @@ -210,13 +212,12 @@ test('ALB Target Group alarms are created', (t) => { } } } - ) - const albAlarmProperties = AlarmPropertiesTargetGroup.ApplicationELBTarget + const albAlarmConfig = testConfig.ApplicationELBTarget const compiledTemplate = createTestCloudFormationTemplate(albCfTemplate) - const targetGroupAlarmResources: ResourceType = createAlbTargetAlarms(albAlarmProperties, testAlarmActionsConfig, compiledTemplate) + const targetGroupAlarmResources: ResourceType = createAlbTargetAlarms(albAlarmConfig, testAlarmActionsConfig, compiledTemplate) const expectedTypesTargetGroup = { LoadBalancer_HTTPCodeTarget5XXCountAlarm: 'HTTPCode_Target_5XX_Count', @@ -227,13 +228,13 @@ test('ALB Target Group alarms are created', (t) => { t.equal(Object.keys(targetGroupAlarmResources).length, Object.keys(expectedTypesTargetGroup).length) for (const alarmResource of Object.values(targetGroupAlarmResources)) { - const al = alarmResource.Properties + const al = alarmResource.Properties as AlarmProperties assertCommonAlarmProperties(t, al) const alarmType = alarmNameToType(al?.AlarmName) const expectedMetric = expectedTypesTargetGroup[alarmType] t.equal(al?.MetricName, expectedMetric) t.ok(al?.Statistic) - t.equal(al?.Threshold, albAlarmProperties[expectedMetric].Threshold) + t.equal(al?.Threshold, albAlarmConfig[expectedMetric].Threshold) t.equal(al?.EvaluationPeriods, 2) t.equal(al?.TreatMissingData, 'breaching') t.equal(al?.ComparisonOperator, 'GreaterThanOrEqualToThreshold') @@ -266,8 +267,45 @@ test('ALB Target Group alarms are created', (t) => { t.end() }) +test('ALB resource configuration overrides take precedence', (t) => { + const testConfig = createTestConfig(defaultConfig.alarms) + const template = createTestCloudFormationTemplate(albCfTemplate); + (template.Resources as ResourceType).AlbEventAlbTargetGrouphttpListener.Metadata = { + slicWatch: { + alarms: { + Period: 900, + HTTPCode_Target_5XX_Count: { + Threshold: 55 + }, + UnHealthyHostCount: { + Threshold: 56 + }, + LambdaInternalError: { + Threshold: 57 + }, + LambdaUserError: { + Threshold: 58, + enabled: false + } + } + } + } + + const targetGroupAlarmResources = createAlbTargetAlarms(testConfig.ApplicationELBTarget, testAlarmActionsConfig, template) + t.same(Object.keys(targetGroupAlarmResources).length, 3) + + const code5xxAlarm = Object.values(targetGroupAlarmResources).filter(a => a?.Properties?.MetricName === 'HTTPCode_Target_5XX_Count')[0] + const unHealthyHostCountAlarm = Object.values(targetGroupAlarmResources).filter(a => a?.Properties?.MetricName === 'UnHealthyHostCount')[0] + const lambdaInternalErrorAlarm = Object.values(targetGroupAlarmResources).filter(a => a?.Properties?.MetricName === 'LambdaInternalError')[0] + + t.equal(code5xxAlarm?.Properties?.Threshold, 55) + t.equal(unHealthyHostCountAlarm?.Properties?.Threshold, 56) + t.equal(lambdaInternalErrorAlarm?.Properties?.Threshold, 57) + t.end() +}) + test('ALB alarms are not created when disabled globally', (t) => { - const AlarmPropertiesTargetGroup = createTestConfig( + const testConfig = createTestConfig( defaultConfig.alarms, { ApplicationELBTarget: { @@ -289,9 +327,9 @@ test('ALB alarms are not created when disabled globally', (t) => { } ) - const albAlarmProperties = AlarmPropertiesTargetGroup.ApplicationELBTarget + const albAlarmConfig = testConfig.ApplicationELBTarget const compiledTemplate = createTestCloudFormationTemplate(albCfTemplate) - const targetGroupAlarmResources = createAlbTargetAlarms(albAlarmProperties, testAlarmActionsConfig, compiledTemplate) + const targetGroupAlarmResources = createAlbTargetAlarms(albAlarmConfig, testAlarmActionsConfig, compiledTemplate) t.same({}, targetGroupAlarmResources) t.end() diff --git a/core/alarms/tests/alb.test.ts b/core/alarms/tests/alb.test.ts index 056b9e6e..68624339 100644 --- a/core/alarms/tests/alb.test.ts +++ b/core/alarms/tests/alb.test.ts @@ -1,7 +1,8 @@ import { test } from 'tap' +import type { AlarmProperties } from 'cloudform-types/types/cloudWatch/alarm' + import createAlbAlarms from '../alb' -import type { SlicWatchAlbAlarmsConfig } from '../alb' import defaultConfig from '../../inputs/default-config' import { assertCommonAlarmProperties, @@ -12,10 +13,9 @@ import { testAlarmActionsConfig } from '../../tests/testing-utils' import type { ResourceType } from '../../cf-template' -import type { SlicWatchMergedConfig } from '../alarm-types' test('ALB alarms are created', (t) => { - const AlarmPropertiesELB = createTestConfig( + const testConfig = createTestConfig( defaultConfig.alarms, { Period: 120, @@ -33,11 +33,8 @@ test('ALB alarms are created', (t) => { } ) - function createAlarmResources (elbAlarmProperties: SlicWatchAlbAlarmsConfig) { - const compiledTemplate = createTestCloudFormationTemplate(albCfTemplate) - return createAlbAlarms(elbAlarmProperties, testAlarmActionsConfig, compiledTemplate) - } - const albAlarmResources: ResourceType = createAlarmResources(AlarmPropertiesELB.ApplicationELB) + const compiledTemplate = createTestCloudFormationTemplate(albCfTemplate) + const albAlarmResources: ResourceType = createAlbAlarms(testConfig.ApplicationELB, testAlarmActionsConfig, compiledTemplate) const expectedTypesELB = { LoadBalancer_HTTPCodeELB5XXCountAlarm: 'HTTPCode_ELB_5XX_Count', @@ -46,13 +43,13 @@ test('ALB alarms are created', (t) => { t.equal(Object.keys(albAlarmResources).length, Object.keys(expectedTypesELB).length) for (const alarmResource of Object.values(albAlarmResources)) { - const al = alarmResource.Properties + const al = alarmResource.Properties as AlarmProperties assertCommonAlarmProperties(t, al) const alarmType = alarmNameToType(al?.AlarmName) const expectedMetric = expectedTypesELB[alarmType] t.equal(al?.MetricName, expectedMetric) t.ok(al?.Statistic) - t.equal(al?.Threshold, AlarmPropertiesELB.ApplicationELB[expectedMetric].Threshold) + t.equal(al?.Threshold, testConfig.ApplicationELB[expectedMetric].Threshold) t.equal(al?.EvaluationPeriods, 2) t.equal(al?.TreatMissingData, 'breaching') t.equal(al?.ComparisonOperator, 'GreaterThanOrEqualToThreshold') @@ -75,8 +72,36 @@ test('ALB alarms are created', (t) => { t.end() }) +test('ALB resource configuration overrides take precedence', (t) => { + const testConfig = createTestConfig(defaultConfig.alarms) + const template = createTestCloudFormationTemplate(albCfTemplate); + (template.Resources as ResourceType).alb.Metadata = { + slicWatch: { + alarms: { + Period: 900, + HTTPCode_ELB_5XX_Count: { + Threshold: 51, + enabled: false + }, + RejectedConnectionCount: { + Threshold: 52 + } + } + } + } + + const albAlarmResources: ResourceType = createAlbAlarms(testConfig.ApplicationELB, testAlarmActionsConfig, template) + + t.same(Object.keys(albAlarmResources).length, 1) + + const rejectedConnectionAlarm = Object.values(albAlarmResources).filter(a => a?.Properties?.MetricName === 'RejectedConnectionCount')[0] + + t.equal(rejectedConnectionAlarm?.Properties?.Threshold, 52) + t.end() +}) + test('ALB alarms are not created when disabled globally', (t) => { - const AlarmPropertiesELB = createTestConfig( + const testConfig = createTestConfig( defaultConfig.alarms, { ApplicationELB: { @@ -96,7 +121,7 @@ test('ALB alarms are not created when disabled globally', (t) => { const compiledTemplate = createTestCloudFormationTemplate(albCfTemplate) return createAlbAlarms(elbAlarmProperties, testAlarmActionsConfig, compiledTemplate) } - const albAlarmResources = createAlarmResources(AlarmPropertiesELB.ApplicationELB) + const albAlarmResources = createAlarmResources(testConfig.ApplicationELB) t.same({}, albAlarmResources) t.end() diff --git a/core/alarms/tests/api-gateway.test.ts b/core/alarms/tests/api-gateway.test.ts index bb349342..311beac7 100644 --- a/core/alarms/tests/api-gateway.test.ts +++ b/core/alarms/tests/api-gateway.test.ts @@ -1,5 +1,7 @@ import { test } from 'tap' +import type { AlarmProperties } from 'cloudform-types/types/cloudWatch/alarm' + import createApiGatewayAlarms, { resolveRestApiNameAsCfn, resolveRestApiNameForSub } from '../api-gateway' import defaultConfig from '../../inputs/default-config' import { @@ -90,7 +92,7 @@ test('resolveRestApiNameForSub', (t) => { }) test('API Gateway alarms are created', (t) => { - const AlarmProperties = createTestConfig( + const testConfig = createTestConfig( defaultConfig.alarms, { Period: 120, @@ -110,17 +112,17 @@ test('API Gateway alarms are created', (t) => { } } ) - const apiGwAlarmProperties = AlarmProperties.ApiGateway + const apiGwAlarmConfig = testConfig.ApiGateway t.test('with full template', (t) => { const compiledTemplate = createTestCloudFormationTemplate() - const alarmResources: ResourceType = createApiGatewayAlarms(apiGwAlarmProperties, testAlarmActionsConfig, compiledTemplate) + const alarmResources: ResourceType = createApiGatewayAlarms(apiGwAlarmConfig, testAlarmActionsConfig, compiledTemplate) const alarmsByType: AlarmsByType = {} t.equal(Object.keys(alarmResources).length, 3) for (const alarmResource of Object.values(alarmResources)) { - const al = alarmResource.Properties + const al = alarmResource.Properties as AlarmProperties assertCommonAlarmProperties(t, al) const alarmType = alarmNameToType(al?.AlarmName) alarmsByType[alarmType] = (alarmsByType[alarmType] === true) || new Set() @@ -136,7 +138,7 @@ test('API Gateway alarms are created', (t) => { for (const al of alarmsByType.ApiGW_5XXError) { t.equal(al.MetricName, '5XXError') t.equal(al.Statistic, 'Average') - t.equal(al.Threshold, apiGwAlarmProperties['5XXError'].Threshold) + t.equal(al.Threshold, apiGwAlarmConfig['5XXError'].Threshold) t.equal(al.EvaluationPeriods, 2) t.equal(al.TreatMissingData, 'breaching') t.equal(al.ComparisonOperator, 'GreaterThanOrEqualToThreshold') @@ -153,7 +155,7 @@ test('API Gateway alarms are created', (t) => { for (const al of alarmsByType.ApiGW_4XXError) { t.equal(al.MetricName, '4XXError') t.equal(al.Statistic, 'Average') - t.equal(al.Threshold, apiGwAlarmProperties['4XXError'].Threshold) + t.equal(al.Threshold, apiGwAlarmConfig['4XXError'].Threshold) t.equal(al.EvaluationPeriods, 2) t.equal(al.TreatMissingData, 'breaching') t.equal(al.ComparisonOperator, 'GreaterThanOrEqualToThreshold') @@ -170,7 +172,7 @@ test('API Gateway alarms are created', (t) => { for (const al of alarmsByType.ApiGW_Latency) { t.equal(al.MetricName, 'Latency') t.equal(al.ExtendedStatistic, 'p99') - t.equal(al.Threshold, apiGwAlarmProperties.Latency.Threshold) + t.equal(al.Threshold, apiGwAlarmConfig.Latency.Threshold) t.equal(al.EvaluationPeriods, 2) t.equal(al.TreatMissingData, 'breaching') t.equal(al.ComparisonOperator, 'GreaterThanOrEqualToThreshold') @@ -188,7 +190,7 @@ test('API Gateway alarms are created', (t) => { }) t.test('API Gateway alarms are not created when disabled globally', (t) => { - const AlarmProperties = createTestConfig( + const testConfig = createTestConfig( defaultConfig.alarms, { ApiGateway: { @@ -206,10 +208,10 @@ test('API Gateway alarms are created', (t) => { } } ) - const apiGwAlarmProperties = AlarmProperties.ApiGateway + const apiGwAlarmConfig = testConfig.ApiGateway const compiledTemplate = createTestCloudFormationTemplate() - const alarmResources = createApiGatewayAlarms(apiGwAlarmProperties, testAlarmActionsConfig, compiledTemplate) + const alarmResources = createApiGatewayAlarms(apiGwAlarmConfig, testAlarmActionsConfig, compiledTemplate) t.same({}, alarmResources) t.end() @@ -226,7 +228,7 @@ test('API Gateway alarms are created', (t) => { } } }) - const alarmResources: ResourceType = createApiGatewayAlarms(apiGwAlarmProperties, testAlarmActionsConfig, compiledTemplate) + const alarmResources: ResourceType = createApiGatewayAlarms(apiGwAlarmConfig, testAlarmActionsConfig, compiledTemplate) t.same(Object.keys(alarmResources).sort(), [ 'slicWatchApi4XXErrorAlarmAWSStackName', 'slicWatchApi5XXErrorAlarmAWSStackName', @@ -237,8 +239,44 @@ test('API Gateway alarms are created', (t) => { t.end() }) +test('API Gateway resource configuration overrides take precedence', (t) => { + const testConfig = createTestConfig(defaultConfig.alarms) + const template = createTestCloudFormationTemplate(); + + (template.Resources as ResourceType).ApiGatewayRestApi.Metadata = { + slicWatch: { + alarms: { + Period: 900, + '5XXError': { + enabled: true, + Threshold: 9.9 + }, + '4XXError': { + enabled: false, + Threshold: 0.05 + }, + Latency: { + Threshold: 4321 + } + } + } + } + + const alarmResources = createApiGatewayAlarms(testConfig.ApiGateway, testAlarmActionsConfig, template) + t.same(Object.keys(alarmResources).length, 2) + + const code5xxAlarm = Object.values(alarmResources).filter(a => a?.Properties?.MetricName === '5XXError')[0] + const latencyAlarm = Object.values(alarmResources).filter(a => a?.Properties?.MetricName === 'Latency')[0] + + t.equal(code5xxAlarm?.Properties?.Threshold, 9.9) + t.equal(code5xxAlarm?.Properties?.Period, 900) + t.equal(latencyAlarm?.Properties?.Threshold, 4321) + t.equal(latencyAlarm?.Properties?.Period, 900) + t.end() +}) + test('API Gateway alarms are not created when disabled individually', (t) => { - const AlarmProperties = createTestConfig( + const testConfig = createTestConfig( defaultConfig.alarms, { ApiGateway: { @@ -259,10 +297,10 @@ test('API Gateway alarms are not created when disabled individually', (t) => { } } ) - const apiGwAlarmProperties = AlarmProperties.ApiGateway + const apiGwAlarmConfig = testConfig.ApiGateway const compiledTemplate = createTestCloudFormationTemplate() - const alarmResources = createApiGatewayAlarms(apiGwAlarmProperties, testAlarmActionsConfig, compiledTemplate) + const alarmResources = createApiGatewayAlarms(apiGwAlarmConfig, testAlarmActionsConfig, compiledTemplate) t.same({}, alarmResources) t.end() }) diff --git a/core/alarms/tests/appsync.test.ts b/core/alarms/tests/appsync.test.ts index b0b99a83..7cead357 100644 --- a/core/alarms/tests/appsync.test.ts +++ b/core/alarms/tests/appsync.test.ts @@ -1,7 +1,7 @@ import { test } from 'tap' +import type { AlarmProperties } from 'cloudform-types/types/cloudWatch/alarm' import createAppSyncAlarms from '../appsync' -import type { SlicWatchAppSyncAlarmsConfig } from '../appsync' import defaultConfig from '../../inputs/default-config' import { assertCommonAlarmProperties, @@ -12,10 +12,9 @@ import { testAlarmActionsConfig } from '../../tests/testing-utils' import type { ResourceType } from '../../cf-template' -import type { SlicWatchMergedConfig } from '../alarm-types' test('AppSync alarms are created', (t) => { - const AlarmPropertiesAppSync = createTestConfig( + const testConfig = createTestConfig( defaultConfig.alarms, { Period: 120, @@ -31,13 +30,10 @@ test('AppSync alarms are created', (t) => { } } } - ) - function createAlarmResources (appSyncAlarmProperties: SlicWatchAppSyncAlarmsConfig) { - const compiledTemplate = createTestCloudFormationTemplate(appSyncCfTemplate) - return createAppSyncAlarms(appSyncAlarmProperties, testAlarmActionsConfig, compiledTemplate) - } - const appSyncAlarmResources: ResourceType = createAlarmResources(AlarmPropertiesAppSync.AppSync) + + const compiledTemplate = createTestCloudFormationTemplate(appSyncCfTemplate) + const appSyncAlarmResources: ResourceType = createAppSyncAlarms(testConfig.AppSync, testAlarmActionsConfig, compiledTemplate) const expectedTypesAppSync = { AppSync_5XXErrorAlarm: '5XXError', @@ -46,13 +42,13 @@ test('AppSync alarms are created', (t) => { t.equal(Object.keys(appSyncAlarmResources).length, Object.keys(expectedTypesAppSync).length) for (const alarmResource of Object.values(appSyncAlarmResources)) { - const al = alarmResource.Properties + const al = alarmResource.Properties as AlarmProperties assertCommonAlarmProperties(t, al) const alarmType = alarmNameToType(al?.AlarmName) const expectedMetric = expectedTypesAppSync[alarmType] t.equal(al?.MetricName, expectedMetric) t.ok(al?.Statistic) - t.equal(al?.Threshold, AlarmPropertiesAppSync.AppSync[expectedMetric].Threshold) + t.equal(al?.Threshold, testConfig.AppSync[expectedMetric].Threshold) t.equal(al?.EvaluationPeriods, 2) t.equal(al?.TreatMissingData, 'breaching') t.equal(al?.ComparisonOperator, 'GreaterThanOrEqualToThreshold') @@ -75,8 +71,37 @@ test('AppSync alarms are created', (t) => { t.end() }) +test('AppSync resource configuration overrides take precedence', (t) => { + const testConfig = createTestConfig(defaultConfig.alarms) + const template = createTestCloudFormationTemplate(appSyncCfTemplate); + + (template.Resources as ResourceType).AwesomeappsyncGraphQlApi.Metadata = { + slicWatch: { + alarms: { + Period: 900, + '5XXError': { + enabled: false, + Threshold: 9.9 + }, + Latency: { + Threshold: 4321 + } + } + } + } + + const alarmResources: ResourceType = createAppSyncAlarms(testConfig.AppSync, testAlarmActionsConfig, template) + t.same(Object.keys(alarmResources).length, 1) + + const latencyAlarm = Object.values(alarmResources).filter(a => a?.Properties?.MetricName === 'Latency')[0] + + t.equal(latencyAlarm?.Properties?.Threshold, 4321) + t.equal(latencyAlarm?.Properties?.Period, 900) + t.end() +}) + test('AppSync alarms are not created when disabled globally', (t) => { - const AlarmPropertiesAppSync = createTestConfig( + const testConfig = createTestConfig( defaultConfig.alarms, { AppSync: { @@ -92,11 +117,8 @@ test('AppSync alarms are not created when disabled globally', (t) => { } ) - function createAlarmResources (appSyncAlarmProperties) { - const compiledTemplate = createTestCloudFormationTemplate(appSyncCfTemplate) - return createAppSyncAlarms(appSyncAlarmProperties, testAlarmActionsConfig, compiledTemplate) - } - const appSyncAlarmResources = createAlarmResources(AlarmPropertiesAppSync.AppSync) + const compiledTemplate = createTestCloudFormationTemplate(appSyncCfTemplate) + const appSyncAlarmResources: ResourceType = createAppSyncAlarms(testConfig.AppSync, testAlarmActionsConfig, compiledTemplate) t.same({}, appSyncAlarmResources) t.end() diff --git a/core/alarms/tests/dynamodb.test.ts b/core/alarms/tests/dynamodb.test.ts index efae3ac6..c4631c9f 100644 --- a/core/alarms/tests/dynamodb.test.ts +++ b/core/alarms/tests/dynamodb.test.ts @@ -1,8 +1,9 @@ import { test } from 'tap' import _ from 'lodash' +import type { AlarmProperties } from 'cloudform-types/types/cloudWatch/alarm' import createDynamoDbAlarms from '../dynamodb' -import { addResource, getResourcesByType } from '../../cf-template' +import { type ResourceType, addResource, getResourcesByType } from '../../cf-template' import defaultConfig from '../../inputs/default-config' import { assertCommonAlarmProperties, @@ -13,7 +14,7 @@ import { defaultCfTemplate } from '../../tests/testing-utils' -const AlarmProperties = createTestConfig( +const testConfig = createTestConfig( defaultConfig.alarms, { Period: 120, EvaluationPeriods: 2, @@ -34,13 +35,15 @@ const AlarmProperties = createTestConfig( Threshold: 200 } } - }) -const dynamoDbAlarmProperties = AlarmProperties.DynamoDB + } +) + +const dynamoDbAlarmConfig = testConfig.DynamoDB ;[true, false].forEach(specifyTableName => { test(`DynamoDB alarms are created ${specifyTableName ? 'with' : 'without'} a table name property`, (t) => { const compiledTemplate = createTestCloudFormationTemplate() - const resources = createDynamoDbAlarms(dynamoDbAlarmProperties, testAlarmActionsConfig, compiledTemplate) + const resources = createDynamoDbAlarms(dynamoDbAlarmConfig, testAlarmActionsConfig, compiledTemplate) for (const resourceName in resources) { addResource(resourceName, resources[resourceName], compiledTemplate) @@ -55,7 +58,7 @@ const dynamoDbAlarmProperties = AlarmProperties.DynamoDB const alarmsByType = {} t.equal(Object.keys(alarmResources).length, 6) for (const alarmResource of Object.values(alarmResources)) { - const al = alarmResource.Properties + const al = alarmResource.Properties as AlarmProperties assertCommonAlarmProperties(t, al) const alarmType = alarmNameToType(al?.AlarmName) alarmsByType[alarmType] = alarmsByType[alarmType] ?? new Set() @@ -76,7 +79,7 @@ const dynamoDbAlarmProperties = AlarmProperties.DynamoDB for (const al of alarmsByType[type]) { t.equal(al.Statistic, 'Sum') const metric = type.split('_')[1] - t.equal(al.Threshold, dynamoDbAlarmProperties[metric].Threshold) + t.equal(al.Threshold, dynamoDbAlarmConfig[metric].Threshold) t.equal(al.EvaluationPeriods, 2) t.equal(al.TreatMissingData, 'breaching') t.equal(al.ComparisonOperator, 'GreaterThanOrEqualToThreshold') @@ -97,11 +100,55 @@ const dynamoDbAlarmProperties = AlarmProperties.DynamoDB }) }) +test('Table resource configuration overrides take precedence', (t) => { + const template = createTestCloudFormationTemplate(); + + (template.Resources as ResourceType).dataTable.Metadata = { + slicWatch: { + alarms: { + Period: 900, + ReadThrottleEvents: { + Threshold: 11 + }, + WriteThrottleEvents: { + Threshold: 12 + }, + UserErrors: { + Threshold: 13, + enabled: false + }, + SystemErrors: { + Threshold: 14 + } + } + } + } + + const alarmResources = createDynamoDbAlarms(dynamoDbAlarmConfig, testAlarmActionsConfig, template) + t.same(Object.keys(alarmResources).length, 5) // 3 for the table, 2 for the GSI + + const readThrottleAlarms = Object.values(alarmResources).filter(a => a?.Properties?.MetricName === 'ReadThrottleEvents') + const writeThrottleAlarms = Object.values(alarmResources).filter(a => a?.Properties?.MetricName === 'WriteThrottleEvents') + const systemErrorsAlarm = Object.values(alarmResources).filter(a => a?.Properties?.MetricName === 'SystemErrors')[0] + + for (const alarm of readThrottleAlarms) { + t.equal(alarm?.Properties?.Threshold, 11) + t.equal(alarm?.Properties?.Period, 900) + } + for (const alarm of writeThrottleAlarms) { + t.equal(alarm?.Properties?.Threshold, 12) + t.equal(alarm?.Properties?.Period, 900) + } + t.equal(systemErrorsAlarm?.Properties?.Threshold, 14) + t.equal(systemErrorsAlarm?.Properties?.Period, 900) + t.end() +}) + test('DynamoDB alarms are created without GSI', (t) => { const compiledTemplate = createTestCloudFormationTemplate() _.cloneDeep(defaultCfTemplate) delete compiledTemplate.Resources?.dataTable.Properties?.GlobalSecondaryIndexes - const resources = createDynamoDbAlarms(dynamoDbAlarmProperties, testAlarmActionsConfig, compiledTemplate) + const resources = createDynamoDbAlarms(dynamoDbAlarmConfig, testAlarmActionsConfig, compiledTemplate) for (const resourceName in resources) { addResource(resourceName, resources[resourceName], compiledTemplate) } @@ -112,15 +159,15 @@ test('DynamoDB alarms are created without GSI', (t) => { }) test('DynamoDB alarms are not created when disabled', (t) => { - const AlarmProperties = createTestConfig(defaultConfig.alarms, { + const testConfig = createTestConfig(defaultConfig.alarms, { DynamoDB: { enabled: false } }) - const dynamoDbAlarmProperties = AlarmProperties.DynamoDB + const dynamoDbAlarmConfig = testConfig.DynamoDB const compiledTemplate = createTestCloudFormationTemplate() - const alarmResources = createDynamoDbAlarms(dynamoDbAlarmProperties, testAlarmActionsConfig, compiledTemplate) + const alarmResources = createDynamoDbAlarms(dynamoDbAlarmConfig, testAlarmActionsConfig, compiledTemplate) t.same({}, alarmResources) t.end() diff --git a/core/alarms/tests/ecs.test.ts b/core/alarms/tests/ecs.test.ts index a5de1f81..98b23249 100644 --- a/core/alarms/tests/ecs.test.ts +++ b/core/alarms/tests/ecs.test.ts @@ -1,5 +1,7 @@ import { test } from 'tap' +import type { AlarmProperties } from 'cloudform-types/types/cloudWatch/alarm' + import createECSAlarms, { resolveEcsClusterNameAsCfn } from '../ecs' import defaultConfig from '../../inputs/default-config' import { @@ -31,7 +33,7 @@ test('resolveEcsClusterNameAsCfn', (t) => { }) test('ECS MemoryUtilization is created', (t) => { - const AlarmProperties = createTestConfig( + const testConfig = createTestConfig( defaultConfig.alarms, { Period: 120, @@ -48,10 +50,9 @@ test('ECS MemoryUtilization is created', (t) => { } } ) - const ecsAlarmProperties = AlarmProperties.ECS const compiledTemplate = createTestCloudFormationTemplate() - const alarmResources: ResourceType = createECSAlarms(ecsAlarmProperties, testAlarmActionsConfig, compiledTemplate) + const alarmResources: ResourceType = createECSAlarms(testConfig.ECS, testAlarmActionsConfig, compiledTemplate) const expectedTypes = { ECS_MemoryAlarm: 'MemoryUtilization', @@ -60,13 +61,13 @@ test('ECS MemoryUtilization is created', (t) => { t.equal(Object.keys(alarmResources).length, Object.keys(expectedTypes).length) for (const alarmResource of Object.values(alarmResources)) { - const al = alarmResource.Properties + const al = alarmResource.Properties as AlarmProperties assertCommonAlarmProperties(t, al) const alarmType = alarmNameToType(al?.AlarmName) const expectedMetric = expectedTypes[alarmType] t.equal(al?.MetricName, expectedMetric) t.ok(al?.Statistic) - t.equal(al?.Threshold, ecsAlarmProperties[expectedMetric].Threshold) + t.equal(al?.Threshold, testConfig.ECS[expectedMetric].Threshold) t.equal(al?.EvaluationPeriods, 2) t.equal(al?.TreatMissingData, 'breaching') t.equal(al?.ComparisonOperator, 'LessThanThreshold') @@ -93,8 +94,37 @@ test('ECS MemoryUtilization is created', (t) => { t.end() }) +test('ECS resource configuration overrides take precedence', (t) => { + const testConfig = createTestConfig(defaultConfig.alarms) + const template = createTestCloudFormationTemplate(); + + (template.Resources as ResourceType).ecsService.Metadata = { + slicWatch: { + alarms: { + Period: 900, + MemoryUtilization: { + Threshold: 51, + enabled: false + }, + CPUUtilization: { + Threshold: 52 + } + } + } + } + + const alarmResources: ResourceType = createECSAlarms(testConfig.ECS, testAlarmActionsConfig, template) + t.same(Object.keys(alarmResources).length, 1) + + const cpuAlarm = Object.values(alarmResources).filter(a => a?.Properties?.MetricName === 'CPUUtilization')[0] + + t.equal(cpuAlarm?.Properties?.Threshold, 52) + t.equal(cpuAlarm?.Properties?.Period, 900) + t.end() +}) + test('ECS alarms are not created when disabled globally', (t) => { - const AlarmProperties = createTestConfig( + const testConfig = createTestConfig( defaultConfig.alarms, { ECS: { @@ -109,10 +139,10 @@ test('ECS alarms are not created when disabled globally', (t) => { } } ) - const ecsAlarmProperties = AlarmProperties.ECS + const ecsAlarmConfig = testConfig.ECS const compiledTemplate = createTestCloudFormationTemplate() - const alarmResources = createECSAlarms(ecsAlarmProperties, testAlarmActionsConfig, compiledTemplate) + const alarmResources = createECSAlarms(ecsAlarmConfig, testAlarmActionsConfig, compiledTemplate) t.same({}, alarmResources) t.end() diff --git a/core/alarms/tests/eventbridge.test.ts b/core/alarms/tests/eventbridge.test.ts index 06f82bd9..38f8ee28 100644 --- a/core/alarms/tests/eventbridge.test.ts +++ b/core/alarms/tests/eventbridge.test.ts @@ -1,5 +1,7 @@ import { test } from 'tap' +import type { AlarmProperties, Dimension } from 'cloudform-types/types/cloudWatch/alarm' + import createRuleAlarms from '../eventbridge' import { getResourcesByType } from '../../cf-template' import type { ResourceType } from '../../cf-template' @@ -13,7 +15,7 @@ import { } from '../../tests/testing-utils' test('Events alarms are created', (t) => { - const AlarmProperties = createTestConfig( + const testConfig = createTestConfig( defaultConfig.alarms, { Period: 120, @@ -30,9 +32,9 @@ test('Events alarms are created', (t) => { } } ) - const ruleAlarmProperties = AlarmProperties.Events + const ruleAlarmConfig = testConfig.Events const compiledTemplate = createTestCloudFormationTemplate() - const alarmResources: ResourceType = createRuleAlarms(ruleAlarmProperties, testAlarmActionsConfig, compiledTemplate) + const alarmResources: ResourceType = createRuleAlarms(ruleAlarmConfig, testAlarmActionsConfig, compiledTemplate) const expectedTypes = { Events_FailedInvocations_Alarm: 'FailedInvocations', @@ -41,28 +43,59 @@ test('Events alarms are created', (t) => { t.equal(Object.keys(alarmResources).length, Object.keys(expectedTypes).length) for (const alarmResource of Object.values(alarmResources)) { - const al = alarmResource.Properties + const al = alarmResource.Properties as AlarmProperties assertCommonAlarmProperties(t, al) const alarmType = alarmNameToType(al?.AlarmName) const expectedMetric = expectedTypes[alarmType] t.equal(al?.MetricName, expectedMetric) t.ok(al?.Statistic) - t.equal(al?.Threshold, ruleAlarmProperties[expectedMetric].Threshold) + t.equal(al?.Threshold, ruleAlarmConfig[expectedMetric].Threshold) t.equal(al?.EvaluationPeriods, 2) t.equal(al?.TreatMissingData, 'breaching') t.equal(al?.ComparisonOperator, 'GreaterThanOrEqualToThreshold') t.equal(al?.Namespace, 'AWS/Events') t.equal(al?.Period, 120) - t.equal(al?.Dimensions.length, 1) - t.equal(al?.Dimensions[0].Name, 'RuleName') - t.ok(al?.Dimensions[0].Value) + const dims = al?.Dimensions as Dimension[] + t.equal(dims.length, 1) + const [dim] = dims + t.equal(dim.Name, 'RuleName') + t.ok(dim.Value) } t.end() }) +test('EventBridge Rule resource configuration overrides take precedence', (t) => { + const testConfig = createTestConfig(defaultConfig.alarms) + const template = createTestCloudFormationTemplate(); + + (template.Resources as ResourceType).ServerlesstestprojectdeveventsRulerule1EventBridgeRule.Metadata = { + slicWatch: { + alarms: { + Period: 900, + FailedInvocations: { + Threshold: 59 + }, + ThrottledRules: { + Threshold: 58, + enabled: false + } + } + } + } + + const alarmResources: ResourceType = createRuleAlarms(testConfig.Events, testAlarmActionsConfig, template) + t.same(Object.keys(alarmResources).length, 1) + + const failedInvocationsAlarm = Object.values(alarmResources).filter(a => a?.Properties?.MetricName === 'FailedInvocations')[0] + + t.equal(failedInvocationsAlarm?.Properties?.Threshold, 59) + t.equal(failedInvocationsAlarm?.Properties?.Period, 900) + t.end() +}) + test('Events alarms are not created when disabled globally', (t) => { - const AlarmProperties = createTestConfig( + const testConfig = createTestConfig( defaultConfig.alarms, { Events: { @@ -77,9 +110,9 @@ test('Events alarms are not created when disabled globally', (t) => { } } ) - const ruleAlarmProperties = AlarmProperties.Events + const ruleAlarmConfig = testConfig.Events const compiledTemplate = createTestCloudFormationTemplate() - createRuleAlarms(ruleAlarmProperties, testAlarmActionsConfig, compiledTemplate) + createRuleAlarms(ruleAlarmConfig, testAlarmActionsConfig, compiledTemplate) const alarmResources = getResourcesByType('AWS::CloudWatch::Alarm', compiledTemplate) diff --git a/core/alarms/tests/kinesis.test.ts b/core/alarms/tests/kinesis.test.ts index 0d2ca424..14a997e2 100644 --- a/core/alarms/tests/kinesis.test.ts +++ b/core/alarms/tests/kinesis.test.ts @@ -1,5 +1,8 @@ import { test } from 'tap' +import type { AlarmProperties } from 'cloudform-types/types/cloudWatch/alarm' +import { type Template } from 'cloudform' + import createKinesisAlarms from '../kinesis' import { getResourcesByType } from '../../cf-template' import type { ResourceType } from '../../cf-template' @@ -14,7 +17,7 @@ import { } from '../../tests/testing-utils' test('Kinesis data stream alarms are created', (t) => { - const AlarmProperties = createTestConfig( + const testConfig = createTestConfig( defaultConfig.alarms, { Period: 120, @@ -28,9 +31,9 @@ test('Kinesis data stream alarms are created', (t) => { } } ) - const kinesisAlarmProperties = AlarmProperties.Kinesis + const kinesisAlarmConfig = testConfig.Kinesis const compiledTemplate = createTestCloudFormationTemplate() - const alarmResources: ResourceType = createKinesisAlarms(kinesisAlarmProperties, testAlarmActionsConfig, compiledTemplate) + const alarmResources: ResourceType = createKinesisAlarms(kinesisAlarmConfig, testAlarmActionsConfig, compiledTemplate) const expectedTypes = { Kinesis_StreamIteratorAge: 'GetRecords.IteratorAgeMilliseconds', @@ -43,13 +46,13 @@ test('Kinesis data stream alarms are created', (t) => { t.equal(Object.keys(alarmResources).length, Object.keys(expectedTypes).length) for (const alarmResource of Object.values(alarmResources)) { - const al = alarmResource.Properties + const al = alarmResource.Properties as AlarmProperties assertCommonAlarmProperties(t, al) const alarmType = alarmNameToType(al?.AlarmName) const expectedMetric = expectedTypes[alarmType] t.equal(al?.MetricName, expectedMetric) t.ok(al?.Statistic) - t.equal(al?.Threshold, kinesisAlarmProperties[expectedMetric].Threshold) + t.equal(al?.Threshold, kinesisAlarmConfig[expectedMetric].Threshold) t.equal(al?.EvaluationPeriods, 2) t.equal(al?.TreatMissingData, 'breaching') t.equal(al?.ComparisonOperator, 'LessThanThreshold') @@ -70,7 +73,7 @@ test('Kinesis data stream alarms are created', (t) => { }) test('Kinesis data stream alarms are not created when disabled globally', (t) => { - const AlarmProperties = createTestConfig( + const testConfig = createTestConfig( defaultConfig.alarms, { Kinesis: { @@ -82,12 +85,43 @@ test('Kinesis data stream alarms are not created when disabled globally', (t) => } } ) - const kinesisAlarmProperties = AlarmProperties.Kinesis + const kinesisAlarmConfig = testConfig.Kinesis const compiledTemplate = createTestCloudFormationTemplate() - createKinesisAlarms(kinesisAlarmProperties, testAlarmActionsConfig, compiledTemplate) + createKinesisAlarms(kinesisAlarmConfig, testAlarmActionsConfig, compiledTemplate) const alarmResources = getResourcesByType('AWS::CloudWatch::Alarm', compiledTemplate) t.same({}, alarmResources) t.end() }) + +test('Kinesis data stream resource configuration overrides take precedence', (t) => { + const testConfig = createTestConfig(defaultConfig.alarms) + const template: Template = { + Resources: { + Stream: { + Type: 'AWS::Kinesis::Stream', + Properties: { + Name: 'test-stream' + }, + Metadata: { + slicWatch: { + alarms: { + Period: 900, + 'GetRecords.IteratorAgeMilliseconds': { + Threshold: 9999 + } + } + } + } + } + } + } + + const alarmResources: ResourceType = createKinesisAlarms(testConfig.Kinesis, testAlarmActionsConfig, template) + + const alarmResource = alarmResources.slicWatchKinesisStreamIteratorAgeAlarmStream + t.same(alarmResource.Properties?.Threshold, 9999) + t.same(alarmResource.Properties?.Period, 900) + t.end() +}) diff --git a/core/alarms/tests/sns.test.ts b/core/alarms/tests/sns.test.ts index c7329c7c..55185809 100644 --- a/core/alarms/tests/sns.test.ts +++ b/core/alarms/tests/sns.test.ts @@ -1,4 +1,5 @@ import { test } from 'tap' +import type { AlarmProperties } from 'cloudform-types/types/cloudWatch/alarm' import createSnsAlarms from '../sns' import { getResourcesByType } from '../../cf-template' @@ -13,7 +14,7 @@ import { } from '../../tests/testing-utils' test('SNS alarms are created', (t) => { - const AlarmProperties = createTestConfig( + const testConfig = createTestConfig( defaultConfig.alarms, { Period: 120, @@ -30,10 +31,10 @@ test('SNS alarms are created', (t) => { } } ) - const snsAlarmProperties = AlarmProperties.SNS + const snsAlarmConfig = testConfig.SNS const compiledTemplate = createTestCloudFormationTemplate() - const alarmResources: ResourceType = createSnsAlarms(snsAlarmProperties, testAlarmActionsConfig, compiledTemplate) + const alarmResources: ResourceType = createSnsAlarms(snsAlarmConfig, testAlarmActionsConfig, compiledTemplate) const expectedTypes = { SNS_NumberOfNotificationsFilteredOutInvalidAttributes_Alarm: 'NumberOfNotificationsFilteredOut-InvalidAttributes', SNS_NumberOfNotificationsFailed_Alarm: 'NumberOfNotificationsFailed' @@ -41,14 +42,14 @@ test('SNS alarms are created', (t) => { t.equal(Object.keys(alarmResources).length, Object.keys(expectedTypes).length) for (const alarmResource of Object.values(alarmResources)) { - const al = alarmResource.Properties + const al = alarmResource.Properties as AlarmProperties assertCommonAlarmProperties(t, al) const alarmType = alarmNameToType(al?.AlarmName) const expectedMetric = expectedTypes[alarmType] t.ok(expectedMetric) t.equal(al?.MetricName, expectedMetric) t.ok(al?.Statistic) - t.equal(al?.Threshold, snsAlarmProperties[expectedMetric].Threshold) + t.equal(al?.Threshold, snsAlarmConfig[expectedMetric].Threshold) t.equal(al?.EvaluationPeriods, 2) t.equal(al?.TreatMissingData, 'breaching') t.equal(al?.ComparisonOperator, 'GreaterThanOrEqualToThreshold') @@ -71,8 +72,40 @@ test('SNS alarms are created', (t) => { t.end() }) +test('topic resource configuration overrides take precedence', (t) => { + const testConfig = createTestConfig(defaultConfig.alarms) + const template = createTestCloudFormationTemplate(); + + (template.Resources as ResourceType).topic.Metadata = { + slicWatch: { + alarms: { + Period: 900, + 'NumberOfNotificationsFilteredOut-InvalidAttributes': { + Threshold: 51 + }, + NumberOfNotificationsFailed: { + Threshold: 52, + Period: 3600 + } + } + } + } + + const alarmResources: ResourceType = createSnsAlarms(testConfig.SNS, testAlarmActionsConfig, template) + t.same(Object.keys(alarmResources).length, 2) + + const invalidAttrsAlarm = Object.values(alarmResources).filter(a => a?.Properties?.MetricName === 'NumberOfNotificationsFilteredOut-InvalidAttributes')[0] + const failedAlarm = Object.values(alarmResources).filter(a => a?.Properties?.MetricName === 'NumberOfNotificationsFailed')[0] + t.equal(invalidAttrsAlarm?.Properties?.Threshold, 51) + t.equal(invalidAttrsAlarm?.Properties?.Period, 900) + t.equal(failedAlarm?.Properties?.Threshold, 52) + t.equal(failedAlarm?.Properties?.Period, 3600) + + t.end() +}) + test('SNS alarms are not created when disabled globally', (t) => { - const AlarmProperties = createTestConfig( + const testConfig = createTestConfig( defaultConfig.alarms, { SNS: { @@ -87,9 +120,9 @@ test('SNS alarms are not created when disabled globally', (t) => { } } ) - const snsAlarmProperties = AlarmProperties.SNS + const snsAlarmConfig = testConfig.SNS const compiledTemplate = createTestCloudFormationTemplate() - createSnsAlarms(snsAlarmProperties, testAlarmActionsConfig, compiledTemplate) + createSnsAlarms(snsAlarmConfig, testAlarmActionsConfig, compiledTemplate) const alarmResources = getResourcesByType('AWS::CloudWatch::Alarm', compiledTemplate) diff --git a/core/alarms/tests/sqs.test.ts b/core/alarms/tests/sqs.test.ts index 7b8ef9eb..c79e6d17 100644 --- a/core/alarms/tests/sqs.test.ts +++ b/core/alarms/tests/sqs.test.ts @@ -16,8 +16,9 @@ export interface AlarmsByType { SQS_ApproximateAgeOfOldestMessage SQS_ApproximateNumberOfMessagesNotVisible } + test('SQS alarms are created', (t) => { - const AlarmProperties = createTestConfig( + const testConfig = createTestConfig( defaultConfig.alarms, { Period: 120, @@ -36,10 +37,10 @@ test('SQS alarms are created', (t) => { } } }) - const sqsAlarmProperties = AlarmProperties.SQS + const sqsAlarmConfig = testConfig.SQS const compiledTemplate = createTestCloudFormationTemplate() - const alarmResources: ResourceType = createSQSAlarms(sqsAlarmProperties, testAlarmActionsConfig, compiledTemplate) + const alarmResources: ResourceType = createSQSAlarms(sqsAlarmConfig, testAlarmActionsConfig, compiledTemplate) // We have 2 queues (a regular one and a fifo one) in our test stack // we expect 2 alarms per queue @@ -71,7 +72,7 @@ test('SQS alarms are created', (t) => { // regular queue t.equal(approximateAgeOfOldMessageAlarms[0].MetricName, 'ApproximateAgeOfOldestMessage') t.equal(approximateAgeOfOldMessageAlarms[0].Statistic, 'Maximum') - t.equal(approximateAgeOfOldMessageAlarms[0].Threshold, sqsAlarmProperties.AgeOfOldestMessage.Threshold) + t.equal(approximateAgeOfOldMessageAlarms[0].Threshold, sqsAlarmConfig.AgeOfOldestMessage.Threshold) t.equal(approximateAgeOfOldMessageAlarms[0].EvaluationPeriods, 2) t.equal(approximateAgeOfOldMessageAlarms[0].TreatMissingData, 'breaching') t.equal(approximateAgeOfOldMessageAlarms[0].ComparisonOperator, 'GreaterThanOrEqualToThreshold') @@ -93,7 +94,7 @@ test('SQS alarms are created', (t) => { // fifo queue t.equal(approximateAgeOfOldMessageAlarms[1].MetricName, 'ApproximateAgeOfOldestMessage') t.equal(approximateAgeOfOldMessageAlarms[1].Statistic, 'Maximum') - t.equal(approximateAgeOfOldMessageAlarms[1].Threshold, sqsAlarmProperties.AgeOfOldestMessage.Threshold) + t.equal(approximateAgeOfOldMessageAlarms[1].Threshold, sqsAlarmConfig.AgeOfOldestMessage.Threshold) t.equal(approximateAgeOfOldMessageAlarms[1].EvaluationPeriods, 2) t.equal(approximateAgeOfOldMessageAlarms[1].TreatMissingData, 'breaching') t.equal(approximateAgeOfOldMessageAlarms[1].ComparisonOperator, 'GreaterThanOrEqualToThreshold') @@ -160,8 +161,49 @@ test('SQS alarms are created', (t) => { t.end() }) +test('queue resource configuration overrides take precedence', (t) => { + const testConfig = createTestConfig(defaultConfig.alarms) + const template = createTestCloudFormationTemplate(); + + (template.Resources as ResourceType).regularQueue.Metadata = { + slicWatch: { + alarms: { + Period: 900, + AgeOfOldestMessage: { + Statistic: 'P99', + Threshold: 51, + enabled: true // this one is disabled by default + }, + InFlightMessagesPc: { + Statistic: 'Average', + Threshold: 52, + Period: 60 + } + } + } + } + + const alarmResources: ResourceType = createSQSAlarms(testConfig.SQS, testAlarmActionsConfig, template) + t.same(Object.keys(alarmResources).length, 3) // Two for standard queue, two for the FIFO queue + + const ageOfOldestMessageAlarm = Object.entries(alarmResources).filter(([key, value]) => key.includes('regular') && value?.Properties?.MetricName === 'ApproximateAgeOfOldestMessage')[0][1] + const inFlightMessagesFifoAlarm = Object.entries(alarmResources).filter(([key, value]) => key.includes('fifo') && value?.Properties?.MetricName === 'ApproximateNumberOfMessagesNotVisible')[0][1] + const inFlightMessagesRegularAlarm = Object.entries(alarmResources).filter(([key, value]) => key.includes('regular') && value?.Properties?.MetricName === 'ApproximateNumberOfMessagesNotVisible')[0][1] + t.equal(ageOfOldestMessageAlarm?.Properties?.Threshold, 51) + t.equal(ageOfOldestMessageAlarm?.Properties?.Statistic, 'P99') + t.equal(ageOfOldestMessageAlarm?.Properties?.Period, 900) + t.equal(inFlightMessagesFifoAlarm?.Properties?.Period, 60) + t.equal(inFlightMessagesFifoAlarm?.Properties?.Threshold, Math.floor(0.8 * 20000)) + t.equal(inFlightMessagesFifoAlarm?.Properties?.Statistic, 'Maximum') + t.equal(inFlightMessagesRegularAlarm?.Properties?.Period, 60) + t.equal(inFlightMessagesRegularAlarm?.Properties?.Threshold, Math.floor(0.52 * 120000)) + t.equal(inFlightMessagesRegularAlarm?.Properties?.Statistic, 'Average') + + t.end() +}) + test('SQS alarms are not created when disabled globally', (t) => { - const AlarmProperties = createTestConfig( + const testConfig = createTestConfig( defaultConfig.alarms, { SQS: { @@ -176,7 +218,7 @@ test('SQS alarms are not created when disabled globally', (t) => { } } }) - const sqsAlarmProperties = AlarmProperties.SQS + const sqsAlarmProperties = testConfig.SQS const compiledTemplate = createTestCloudFormationTemplate() createSQSAlarms(sqsAlarmProperties, testAlarmActionsConfig, compiledTemplate) @@ -187,7 +229,7 @@ test('SQS alarms are not created when disabled globally', (t) => { }) test('SQS alarms are not created when disabled individually', (t) => { - const AlarmProperties = createTestConfig( + const testConfig = createTestConfig( defaultConfig.alarms, { SQS: { @@ -204,9 +246,9 @@ test('SQS alarms are not created when disabled individually', (t) => { } } }) - const sqsAlarmProperties = AlarmProperties.SQS + const sqsAlarmConfig = testConfig.SQS const compiledTemplate = createTestCloudFormationTemplate() - createSQSAlarms(sqsAlarmProperties, testAlarmActionsConfig, compiledTemplate) + createSQSAlarms(sqsAlarmConfig, testAlarmActionsConfig, compiledTemplate) const alarmResources = getResourcesByType('AWS::CloudWatch::Alarm', compiledTemplate) @@ -215,7 +257,7 @@ test('SQS alarms are not created when disabled individually', (t) => { }) test('SQS AgeOfOldestMessage alarms throws if misconfigured (enabled but no threshold set)', (t) => { - const AlarmProperties = createTestConfig( + const testConfig = createTestConfig( defaultConfig.alarms, { SQS: { @@ -231,7 +273,7 @@ test('SQS AgeOfOldestMessage alarms throws if misconfigured (enabled but no thre } } }) - const sqsAlarmProperties = AlarmProperties.SQS + const sqsAlarmProperties = testConfig.SQS const compiledTemplate = createTestCloudFormationTemplate() t.throws(() => { createSQSAlarms(sqsAlarmProperties, testAlarmActionsConfig, compiledTemplate) }, { message: 'SQS AgeOfOldestMessage alarm is enabled but `Threshold` is not specified. Please specify a threshold or disable the alarm.' }) t.end() diff --git a/core/alarms/tests/step-functions.test.ts b/core/alarms/tests/step-functions.test.ts index fdf4325c..afa3483e 100644 --- a/core/alarms/tests/step-functions.test.ts +++ b/core/alarms/tests/step-functions.test.ts @@ -1,9 +1,12 @@ import { test } from 'tap' +import type { AlarmProperties } from 'cloudform-types/types/cloudWatch/alarm' + import createStatesAlarms from '../step-functions' import { getResourcesByType } from '../../cf-template' import type { ResourceType } from '../../cf-template' import defaultConfig from '../../inputs/default-config' + import { assertCommonAlarmProperties, alarmNameToType, @@ -13,7 +16,7 @@ import { } from '../../tests/testing-utils' test('Step Function alarms are created', (t) => { - const AlarmProperties = createTestConfig( + const testConfig = createTestConfig( defaultConfig.alarms, { Period: 120, @@ -34,16 +37,16 @@ test('Step Function alarms are created', (t) => { } } ) - const sfAlarmProperties = AlarmProperties.States + const sfAlarmConfig = testConfig.States const compiledTemplate = createTestCloudFormationTemplate() - const alarmResources: ResourceType = createStatesAlarms(sfAlarmProperties, testAlarmActionsConfig, compiledTemplate) + const alarmResources: ResourceType = createStatesAlarms(sfAlarmConfig, testAlarmActionsConfig, compiledTemplate) const alarmsByType = {} t.equal(Object.keys(alarmResources).length, 6) for (const [resourceName, alarmResource] of Object.entries(alarmResources)) { // Just test the standard workflow alarms if (!resourceName.endsWith('ExpressWorkflow')) { - const al = alarmResource.Properties + const al = alarmResource.Properties as AlarmProperties assertCommonAlarmProperties(t, al) const alarmType = alarmNameToType(al?.AlarmName) alarmsByType[alarmType] = alarmsByType[alarmType] ?? new Set() @@ -64,7 +67,7 @@ test('Step Function alarms are created', (t) => { for (const al of alarmsByType[type]) { t.equal(al.Statistic, 'Sum') const metric = type.split('_')[1].replace(/Alarm$/g, '') - t.equal(al.Threshold, sfAlarmProperties[metric].Threshold) + t.equal(al.Threshold, sfAlarmConfig[metric].Threshold) t.equal(al.EvaluationPeriods, 2) t.equal(al.TreatMissingData, 'breaching') t.equal(al.ComparisonOperator, 'GreaterThanOrEqualToThreshold') @@ -85,8 +88,42 @@ test('Step Function alarms are created', (t) => { t.end() }) +test('step function resource configuration overrides take precedence', (t) => { + const testConfig = createTestConfig(defaultConfig.alarms) + const template = createTestCloudFormationTemplate(); + + (template.Resources as ResourceType).Workflow.Metadata = { + slicWatch: { + alarms: { + Period: 900, + ExecutionThrottled: { + Threshold: 1 + }, + ExecutionsFailed: { + Threshold: 2, + enabled: false + }, + ExecutionsTimedOut: { + Threshold: 3 + } + } + } + } + + const alarmResources: ResourceType = createStatesAlarms(testConfig.States, testAlarmActionsConfig, template) + t.same(Object.keys(alarmResources).length, 5) // Two for standard workflow, three for the express workflow + + const throttledAlarm = Object.entries(alarmResources).filter(([key, value]) => !key.includes('xpress') && value?.Properties?.MetricName === 'ExecutionThrottled')[0][1] + const timedOutAlarm = Object.entries(alarmResources).filter(([key, value]) => !key.includes('xpress') && value?.Properties?.MetricName === 'ExecutionsTimedOut')[0][1] + t.equal(throttledAlarm?.Properties?.Threshold, 1) + t.equal(throttledAlarm?.Properties?.Period, 900) + t.equal(timedOutAlarm?.Properties?.Threshold, 3) + t.equal(timedOutAlarm?.Properties?.Period, 900) + + t.end() +}) test('Step function alarms are not created when disabled globally', (t) => { - const AlarmProperties = createTestConfig( + const testConfig = createTestConfig( defaultConfig.alarms, { States: { @@ -104,9 +141,9 @@ test('Step function alarms are not created when disabled globally', (t) => { } } ) - const sfAlarmProperties = AlarmProperties.States + const sfAlarmConfig = testConfig.States const compiledTemplate = createTestCloudFormationTemplate() - createStatesAlarms(sfAlarmProperties, testAlarmActionsConfig, compiledTemplate) + createStatesAlarms(sfAlarmConfig, testAlarmActionsConfig, compiledTemplate) const alarmResources = getResourcesByType('AWS::CloudWatch::Alarm', compiledTemplate) @@ -115,7 +152,7 @@ test('Step function alarms are not created when disabled globally', (t) => { }) test('Step function alarms are not created when disabled individually', (t) => { - const AlarmProperties = createTestConfig( + const testConfig = createTestConfig( defaultConfig.alarms, { States: { @@ -136,9 +173,9 @@ test('Step function alarms are not created when disabled individually', (t) => { } } ) - const sfAlarmProperties = AlarmProperties.States + const sfAlarmConfig = testConfig.States const compiledTemplate = createTestCloudFormationTemplate() - createStatesAlarms(sfAlarmProperties, testAlarmActionsConfig, compiledTemplate) + createStatesAlarms(sfAlarmConfig, testAlarmActionsConfig, compiledTemplate) const alarmResources = getResourcesByType('AWS::CloudWatch::Alarm', compiledTemplate) diff --git a/core/cf-template.ts b/core/cf-template.ts index 1233591c..226b722d 100644 --- a/core/cf-template.ts +++ b/core/cf-template.ts @@ -6,6 +6,7 @@ import { getLogger } from './logging' import { cascade } from './inputs/cascading-config' import { type SlicWatchMergedConfig } from './alarms/alarm-types' import { type SlicWatchDashboardConfig, type WidgetMetricProperties } from './dashboards/dashboard-types' +import { merge } from 'lodash' const logger = getLogger() @@ -65,9 +66,7 @@ export function getResourceAlarmConfigurationsByType = {} const resources = getResourcesByType(type, template) for (const [funcLogicalId, resource] of Object.entries(resources)) { - const resourceConfig = cascade(resource?.Metadata?.slicWatch?.alarms ?? {}) as M - const mergedConfig: M = Object.assign(config, resourceConfig) - alarmConfigurations[funcLogicalId] = mergedConfig + alarmConfigurations[funcLogicalId] = merge({}, config, cascade(resource?.Metadata?.slicWatch?.alarms ?? {}) as M) } return { resources, @@ -90,10 +89,7 @@ export function getResourceDashboardConfigurationsByType = {} const resources = getResourcesByType(type, template) for (const [logicalId, resource] of Object.entries(resources)) { - dashConfigurations[logicalId] = { - ...config, - ...cascade(resource?.Metadata?.slicWatch?.dashboard ?? {}) as SlicWatchDashboardConfig - } + dashConfigurations[logicalId] = merge({}, config, cascade(resource?.Metadata?.slicWatch?.dashboard ?? {}) as SlicWatchDashboardConfig) } return { resources, diff --git a/core/tests/testing-utils.ts b/core/tests/testing-utils.ts index 24d2bf50..be159e87 100644 --- a/core/tests/testing-utils.ts +++ b/core/tests/testing-utils.ts @@ -35,7 +35,7 @@ function alarmNameToType (alarmName) { return components.join('_') } -function createTestConfig (from, cascadingChanges): any { +function createTestConfig (from, cascadingChanges = {}): any { return cascade( _.merge( {}, From b6d3605ae2adb154d8bdcb3cdc482b533f37158b Mon Sep 17 00:00:00 2001 From: Eoin Shanaghy Date: Tue, 14 Nov 2023 22:19:24 +0000 Subject: [PATCH 10/35] chore: update deps with npm audit --- package-lock.json | 5593 +++++++++++++++++++++++++-------------------- 1 file changed, 3119 insertions(+), 2474 deletions(-) diff --git a/package-lock.json b/package-lock.json index 4dbf5657..109b877b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -249,150 +249,152 @@ "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", "dev": true }, - "node_modules/@aws-sdk/abort-controller": { - "version": "3.347.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/abort-controller/-/abort-controller-3.347.0.tgz", - "integrity": "sha512-P/2qE6ntYEmYG4Ez535nJWZbXqgbkJx8CMz7ChEuEg3Gp3dvVYEKg+iEUEvlqQ2U5dWP5J3ehw5po9t86IsVPQ==", - "dev": true, - "dependencies": { - "@aws-sdk/types": "3.347.0", - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/client-cloudwatch": { - "version": "3.352.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-cloudwatch/-/client-cloudwatch-3.352.0.tgz", - "integrity": "sha512-TdPEpzoHBIme1hMtEv/01PGAZr89QzjXkFcX8II+FojDdHL6ojwPsx8MMD6F/jnzoxpU4nJ0go5uEUcpqOGbAw==", + "node_modules/@aws-sdk/client-cloudformation": { + "version": "3.451.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-cloudformation/-/client-cloudformation-3.451.0.tgz", + "integrity": "sha512-rc8MWRsWA1OgOq/hASLONtVTEbRggjf8VFYmW7UdL1g+oRQoDFWEWPv7kW5868UTpS6SmHdjCrXP8YREtR4ZSQ==", "dev": true, "dependencies": { "@aws-crypto/sha256-browser": "3.0.0", "@aws-crypto/sha256-js": "3.0.0", - "@aws-sdk/client-sts": "3.352.0", - "@aws-sdk/config-resolver": "3.347.0", - "@aws-sdk/credential-provider-node": "3.352.0", - "@aws-sdk/fetch-http-handler": "3.347.0", - "@aws-sdk/hash-node": "3.347.0", - "@aws-sdk/invalid-dependency": "3.347.0", - "@aws-sdk/middleware-content-length": "3.347.0", - "@aws-sdk/middleware-endpoint": "3.347.0", - "@aws-sdk/middleware-host-header": "3.347.0", - "@aws-sdk/middleware-logger": "3.347.0", - "@aws-sdk/middleware-recursion-detection": "3.347.0", - "@aws-sdk/middleware-retry": "3.347.0", - "@aws-sdk/middleware-serde": "3.347.0", - "@aws-sdk/middleware-signing": "3.347.0", - "@aws-sdk/middleware-stack": "3.347.0", - "@aws-sdk/middleware-user-agent": "3.352.0", - "@aws-sdk/node-config-provider": "3.347.0", - "@aws-sdk/node-http-handler": "3.350.0", - "@aws-sdk/smithy-client": "3.347.0", - "@aws-sdk/types": "3.347.0", - "@aws-sdk/url-parser": "3.347.0", - "@aws-sdk/util-base64": "3.310.0", - "@aws-sdk/util-body-length-browser": "3.310.0", - "@aws-sdk/util-body-length-node": "3.310.0", - "@aws-sdk/util-defaults-mode-browser": "3.347.0", - "@aws-sdk/util-defaults-mode-node": "3.347.0", - "@aws-sdk/util-endpoints": "3.352.0", - "@aws-sdk/util-retry": "3.347.0", - "@aws-sdk/util-user-agent-browser": "3.347.0", - "@aws-sdk/util-user-agent-node": "3.347.0", - "@aws-sdk/util-utf8": "3.310.0", - "@aws-sdk/util-waiter": "3.347.0", - "@smithy/protocol-http": "^1.0.1", - "@smithy/types": "^1.0.0", - "fast-xml-parser": "4.2.4", - "tslib": "^2.5.0" + "@aws-sdk/client-sts": "3.451.0", + "@aws-sdk/core": "3.451.0", + "@aws-sdk/credential-provider-node": "3.451.0", + "@aws-sdk/middleware-host-header": "3.451.0", + "@aws-sdk/middleware-logger": "3.451.0", + "@aws-sdk/middleware-recursion-detection": "3.451.0", + "@aws-sdk/middleware-signing": "3.451.0", + "@aws-sdk/middleware-user-agent": "3.451.0", + "@aws-sdk/region-config-resolver": "3.451.0", + "@aws-sdk/types": "3.451.0", + "@aws-sdk/util-endpoints": "3.451.0", + "@aws-sdk/util-user-agent-browser": "3.451.0", + "@aws-sdk/util-user-agent-node": "3.451.0", + "@smithy/config-resolver": "^2.0.18", + "@smithy/fetch-http-handler": "^2.2.6", + "@smithy/hash-node": "^2.0.15", + "@smithy/invalid-dependency": "^2.0.13", + "@smithy/middleware-content-length": "^2.0.15", + "@smithy/middleware-endpoint": "^2.2.0", + "@smithy/middleware-retry": "^2.0.20", + "@smithy/middleware-serde": "^2.0.13", + "@smithy/middleware-stack": "^2.0.7", + "@smithy/node-config-provider": "^2.1.5", + "@smithy/node-http-handler": "^2.1.9", + "@smithy/protocol-http": "^3.0.9", + "@smithy/smithy-client": "^2.1.15", + "@smithy/types": "^2.5.0", + "@smithy/url-parser": "^2.0.13", + "@smithy/util-base64": "^2.0.1", + "@smithy/util-body-length-browser": "^2.0.0", + "@smithy/util-body-length-node": "^2.1.0", + "@smithy/util-defaults-mode-browser": "^2.0.19", + "@smithy/util-defaults-mode-node": "^2.0.25", + "@smithy/util-endpoints": "^1.0.4", + "@smithy/util-retry": "^2.0.6", + "@smithy/util-utf8": "^2.0.2", + "@smithy/util-waiter": "^2.0.13", + "fast-xml-parser": "4.2.5", + "tslib": "^2.5.0", + "uuid": "^8.3.2" }, "engines": { "node": ">=14.0.0" } }, - "node_modules/@aws-sdk/client-sso": { - "version": "3.352.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.352.0.tgz", - "integrity": "sha512-oeO36rvRvYbUlsgzYtLI2/BPwXdUK4KtYw+OFmirYeONUyX5uYx8kWXD66r3oXViIYMqhyHKN3fhkiFmFcVluQ==", + "node_modules/@aws-sdk/client-cloudwatch": { + "version": "3.451.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-cloudwatch/-/client-cloudwatch-3.451.0.tgz", + "integrity": "sha512-qTOtdSRVdizBst94HK3ZAoCyi7gB7AFXZyHxu+acJwxFi28sAByPtwCVvmeTuFzivC+22JZs5mYRaXBWwL7USw==", "dev": true, "dependencies": { "@aws-crypto/sha256-browser": "3.0.0", "@aws-crypto/sha256-js": "3.0.0", - "@aws-sdk/config-resolver": "3.347.0", - "@aws-sdk/fetch-http-handler": "3.347.0", - "@aws-sdk/hash-node": "3.347.0", - "@aws-sdk/invalid-dependency": "3.347.0", - "@aws-sdk/middleware-content-length": "3.347.0", - "@aws-sdk/middleware-endpoint": "3.347.0", - "@aws-sdk/middleware-host-header": "3.347.0", - "@aws-sdk/middleware-logger": "3.347.0", - "@aws-sdk/middleware-recursion-detection": "3.347.0", - "@aws-sdk/middleware-retry": "3.347.0", - "@aws-sdk/middleware-serde": "3.347.0", - "@aws-sdk/middleware-stack": "3.347.0", - "@aws-sdk/middleware-user-agent": "3.352.0", - "@aws-sdk/node-config-provider": "3.347.0", - "@aws-sdk/node-http-handler": "3.350.0", - "@aws-sdk/smithy-client": "3.347.0", - "@aws-sdk/types": "3.347.0", - "@aws-sdk/url-parser": "3.347.0", - "@aws-sdk/util-base64": "3.310.0", - "@aws-sdk/util-body-length-browser": "3.310.0", - "@aws-sdk/util-body-length-node": "3.310.0", - "@aws-sdk/util-defaults-mode-browser": "3.347.0", - "@aws-sdk/util-defaults-mode-node": "3.347.0", - "@aws-sdk/util-endpoints": "3.352.0", - "@aws-sdk/util-retry": "3.347.0", - "@aws-sdk/util-user-agent-browser": "3.347.0", - "@aws-sdk/util-user-agent-node": "3.347.0", - "@aws-sdk/util-utf8": "3.310.0", - "@smithy/protocol-http": "^1.0.1", - "@smithy/types": "^1.0.0", + "@aws-sdk/client-sts": "3.451.0", + "@aws-sdk/core": "3.451.0", + "@aws-sdk/credential-provider-node": "3.451.0", + "@aws-sdk/middleware-host-header": "3.451.0", + "@aws-sdk/middleware-logger": "3.451.0", + "@aws-sdk/middleware-recursion-detection": "3.451.0", + "@aws-sdk/middleware-signing": "3.451.0", + "@aws-sdk/middleware-user-agent": "3.451.0", + "@aws-sdk/region-config-resolver": "3.451.0", + "@aws-sdk/types": "3.451.0", + "@aws-sdk/util-endpoints": "3.451.0", + "@aws-sdk/util-user-agent-browser": "3.451.0", + "@aws-sdk/util-user-agent-node": "3.451.0", + "@smithy/config-resolver": "^2.0.18", + "@smithy/fetch-http-handler": "^2.2.6", + "@smithy/hash-node": "^2.0.15", + "@smithy/invalid-dependency": "^2.0.13", + "@smithy/middleware-content-length": "^2.0.15", + "@smithy/middleware-endpoint": "^2.2.0", + "@smithy/middleware-retry": "^2.0.20", + "@smithy/middleware-serde": "^2.0.13", + "@smithy/middleware-stack": "^2.0.7", + "@smithy/node-config-provider": "^2.1.5", + "@smithy/node-http-handler": "^2.1.9", + "@smithy/protocol-http": "^3.0.9", + "@smithy/smithy-client": "^2.1.15", + "@smithy/types": "^2.5.0", + "@smithy/url-parser": "^2.0.13", + "@smithy/util-base64": "^2.0.1", + "@smithy/util-body-length-browser": "^2.0.0", + "@smithy/util-body-length-node": "^2.1.0", + "@smithy/util-defaults-mode-browser": "^2.0.19", + "@smithy/util-defaults-mode-node": "^2.0.25", + "@smithy/util-endpoints": "^1.0.4", + "@smithy/util-retry": "^2.0.6", + "@smithy/util-utf8": "^2.0.2", + "@smithy/util-waiter": "^2.0.13", + "fast-xml-parser": "4.2.5", "tslib": "^2.5.0" }, "engines": { "node": ">=14.0.0" } }, - "node_modules/@aws-sdk/client-sso-oidc": { - "version": "3.352.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso-oidc/-/client-sso-oidc-3.352.0.tgz", - "integrity": "sha512-PQdp0KOr478CaJNohASTgtt03W8Y/qINwsalLNguK01tWIGzellg2N3bA+IdyYXU8Oz3+Ab1oIJMKkUxtuNiGg==", + "node_modules/@aws-sdk/client-sso": { + "version": "3.451.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.451.0.tgz", + "integrity": "sha512-KkYSke3Pdv3MfVH/5fT528+MKjMyPKlcLcd4zQb0x6/7Bl7EHrPh1JZYjzPLHelb+UY5X0qN8+cb8iSu1eiwIQ==", "dev": true, "dependencies": { "@aws-crypto/sha256-browser": "3.0.0", "@aws-crypto/sha256-js": "3.0.0", - "@aws-sdk/config-resolver": "3.347.0", - "@aws-sdk/fetch-http-handler": "3.347.0", - "@aws-sdk/hash-node": "3.347.0", - "@aws-sdk/invalid-dependency": "3.347.0", - "@aws-sdk/middleware-content-length": "3.347.0", - "@aws-sdk/middleware-endpoint": "3.347.0", - "@aws-sdk/middleware-host-header": "3.347.0", - "@aws-sdk/middleware-logger": "3.347.0", - "@aws-sdk/middleware-recursion-detection": "3.347.0", - "@aws-sdk/middleware-retry": "3.347.0", - "@aws-sdk/middleware-serde": "3.347.0", - "@aws-sdk/middleware-stack": "3.347.0", - "@aws-sdk/middleware-user-agent": "3.352.0", - "@aws-sdk/node-config-provider": "3.347.0", - "@aws-sdk/node-http-handler": "3.350.0", - "@aws-sdk/smithy-client": "3.347.0", - "@aws-sdk/types": "3.347.0", - "@aws-sdk/url-parser": "3.347.0", - "@aws-sdk/util-base64": "3.310.0", - "@aws-sdk/util-body-length-browser": "3.310.0", - "@aws-sdk/util-body-length-node": "3.310.0", - "@aws-sdk/util-defaults-mode-browser": "3.347.0", - "@aws-sdk/util-defaults-mode-node": "3.347.0", - "@aws-sdk/util-endpoints": "3.352.0", - "@aws-sdk/util-retry": "3.347.0", - "@aws-sdk/util-user-agent-browser": "3.347.0", - "@aws-sdk/util-user-agent-node": "3.347.0", - "@aws-sdk/util-utf8": "3.310.0", - "@smithy/protocol-http": "^1.0.1", - "@smithy/types": "^1.0.0", + "@aws-sdk/core": "3.451.0", + "@aws-sdk/middleware-host-header": "3.451.0", + "@aws-sdk/middleware-logger": "3.451.0", + "@aws-sdk/middleware-recursion-detection": "3.451.0", + "@aws-sdk/middleware-user-agent": "3.451.0", + "@aws-sdk/region-config-resolver": "3.451.0", + "@aws-sdk/types": "3.451.0", + "@aws-sdk/util-endpoints": "3.451.0", + "@aws-sdk/util-user-agent-browser": "3.451.0", + "@aws-sdk/util-user-agent-node": "3.451.0", + "@smithy/config-resolver": "^2.0.18", + "@smithy/fetch-http-handler": "^2.2.6", + "@smithy/hash-node": "^2.0.15", + "@smithy/invalid-dependency": "^2.0.13", + "@smithy/middleware-content-length": "^2.0.15", + "@smithy/middleware-endpoint": "^2.2.0", + "@smithy/middleware-retry": "^2.0.20", + "@smithy/middleware-serde": "^2.0.13", + "@smithy/middleware-stack": "^2.0.7", + "@smithy/node-config-provider": "^2.1.5", + "@smithy/node-http-handler": "^2.1.9", + "@smithy/protocol-http": "^3.0.9", + "@smithy/smithy-client": "^2.1.15", + "@smithy/types": "^2.5.0", + "@smithy/url-parser": "^2.0.13", + "@smithy/util-base64": "^2.0.1", + "@smithy/util-body-length-browser": "^2.0.0", + "@smithy/util-body-length-node": "^2.1.0", + "@smithy/util-defaults-mode-browser": "^2.0.19", + "@smithy/util-defaults-mode-node": "^2.0.25", + "@smithy/util-endpoints": "^1.0.4", + "@smithy/util-retry": "^2.0.6", + "@smithy/util-utf8": "^2.0.2", "tslib": "^2.5.0" }, "engines": { @@ -400,62 +402,63 @@ } }, "node_modules/@aws-sdk/client-sts": { - "version": "3.352.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.352.0.tgz", - "integrity": "sha512-Lt7uSdwgOrwYx8S6Bhz76ewOeoJNFiPD+Q7v8S/mJK8T7HUE/houjomXC3UnFaJjcecjWv273zEqV67FgP5l5g==", + "version": "3.451.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.451.0.tgz", + "integrity": "sha512-48NcIRxWBdP1fom6RSjwn2R2u7SE7eeV3p+c4s7ukEOfrHhBxJfn3EpqBVQMGzdiU55qFImy+Fe81iA2lXq3Jw==", "dev": true, "dependencies": { "@aws-crypto/sha256-browser": "3.0.0", "@aws-crypto/sha256-js": "3.0.0", - "@aws-sdk/config-resolver": "3.347.0", - "@aws-sdk/credential-provider-node": "3.352.0", - "@aws-sdk/fetch-http-handler": "3.347.0", - "@aws-sdk/hash-node": "3.347.0", - "@aws-sdk/invalid-dependency": "3.347.0", - "@aws-sdk/middleware-content-length": "3.347.0", - "@aws-sdk/middleware-endpoint": "3.347.0", - "@aws-sdk/middleware-host-header": "3.347.0", - "@aws-sdk/middleware-logger": "3.347.0", - "@aws-sdk/middleware-recursion-detection": "3.347.0", - "@aws-sdk/middleware-retry": "3.347.0", - "@aws-sdk/middleware-sdk-sts": "3.347.0", - "@aws-sdk/middleware-serde": "3.347.0", - "@aws-sdk/middleware-signing": "3.347.0", - "@aws-sdk/middleware-stack": "3.347.0", - "@aws-sdk/middleware-user-agent": "3.352.0", - "@aws-sdk/node-config-provider": "3.347.0", - "@aws-sdk/node-http-handler": "3.350.0", - "@aws-sdk/smithy-client": "3.347.0", - "@aws-sdk/types": "3.347.0", - "@aws-sdk/url-parser": "3.347.0", - "@aws-sdk/util-base64": "3.310.0", - "@aws-sdk/util-body-length-browser": "3.310.0", - "@aws-sdk/util-body-length-node": "3.310.0", - "@aws-sdk/util-defaults-mode-browser": "3.347.0", - "@aws-sdk/util-defaults-mode-node": "3.347.0", - "@aws-sdk/util-endpoints": "3.352.0", - "@aws-sdk/util-retry": "3.347.0", - "@aws-sdk/util-user-agent-browser": "3.347.0", - "@aws-sdk/util-user-agent-node": "3.347.0", - "@aws-sdk/util-utf8": "3.310.0", - "@smithy/protocol-http": "^1.0.1", - "@smithy/types": "^1.0.0", - "fast-xml-parser": "4.2.4", + "@aws-sdk/core": "3.451.0", + "@aws-sdk/credential-provider-node": "3.451.0", + "@aws-sdk/middleware-host-header": "3.451.0", + "@aws-sdk/middleware-logger": "3.451.0", + "@aws-sdk/middleware-recursion-detection": "3.451.0", + "@aws-sdk/middleware-sdk-sts": "3.451.0", + "@aws-sdk/middleware-signing": "3.451.0", + "@aws-sdk/middleware-user-agent": "3.451.0", + "@aws-sdk/region-config-resolver": "3.451.0", + "@aws-sdk/types": "3.451.0", + "@aws-sdk/util-endpoints": "3.451.0", + "@aws-sdk/util-user-agent-browser": "3.451.0", + "@aws-sdk/util-user-agent-node": "3.451.0", + "@smithy/config-resolver": "^2.0.18", + "@smithy/fetch-http-handler": "^2.2.6", + "@smithy/hash-node": "^2.0.15", + "@smithy/invalid-dependency": "^2.0.13", + "@smithy/middleware-content-length": "^2.0.15", + "@smithy/middleware-endpoint": "^2.2.0", + "@smithy/middleware-retry": "^2.0.20", + "@smithy/middleware-serde": "^2.0.13", + "@smithy/middleware-stack": "^2.0.7", + "@smithy/node-config-provider": "^2.1.5", + "@smithy/node-http-handler": "^2.1.9", + "@smithy/protocol-http": "^3.0.9", + "@smithy/smithy-client": "^2.1.15", + "@smithy/types": "^2.5.0", + "@smithy/url-parser": "^2.0.13", + "@smithy/util-base64": "^2.0.1", + "@smithy/util-body-length-browser": "^2.0.0", + "@smithy/util-body-length-node": "^2.1.0", + "@smithy/util-defaults-mode-browser": "^2.0.19", + "@smithy/util-defaults-mode-node": "^2.0.25", + "@smithy/util-endpoints": "^1.0.4", + "@smithy/util-retry": "^2.0.6", + "@smithy/util-utf8": "^2.0.2", + "fast-xml-parser": "4.2.5", "tslib": "^2.5.0" }, "engines": { "node": ">=14.0.0" } }, - "node_modules/@aws-sdk/config-resolver": { - "version": "3.347.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/config-resolver/-/config-resolver-3.347.0.tgz", - "integrity": "sha512-2ja+Sf/VnUO7IQ3nKbDQ5aumYKKJUaTm/BuVJ29wNho8wYHfuf7wHZV0pDTkB8RF5SH7IpHap7zpZAj39Iq+EA==", + "node_modules/@aws-sdk/core": { + "version": "3.451.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.451.0.tgz", + "integrity": "sha512-SamWW2zHEf1ZKe3j1w0Piauryl8BQIlej0TBS18A4ACzhjhWXhCs13bO1S88LvPR5mBFXok3XOT6zPOnKDFktw==", "dev": true, "dependencies": { - "@aws-sdk/types": "3.347.0", - "@aws-sdk/util-config-provider": "3.310.0", - "@aws-sdk/util-middleware": "3.347.0", + "@smithy/smithy-client": "^2.1.15", "tslib": "^2.5.0" }, "engines": { @@ -463,29 +466,14 @@ } }, "node_modules/@aws-sdk/credential-provider-env": { - "version": "3.347.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.347.0.tgz", - "integrity": "sha512-UnEM+LKGpXKzw/1WvYEQsC6Wj9PupYZdQOE+e2Dgy2dqk/pVFy4WueRtFXYDT2B41ppv3drdXUuKZRIDVqIgNQ==", - "dev": true, - "dependencies": { - "@aws-sdk/property-provider": "3.347.0", - "@aws-sdk/types": "3.347.0", - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-imds": { - "version": "3.347.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-imds/-/credential-provider-imds-3.347.0.tgz", - "integrity": "sha512-7scCy/DCDRLIhlqTxff97LQWDnRwRXji3bxxMg+xWOTTaJe7PWx+etGSbBWaL42vsBHFShQjSLvJryEgoBktpw==", + "version": "3.451.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.451.0.tgz", + "integrity": "sha512-9dAav7DcRgaF7xCJEQR5ER9ErXxnu/tdnVJ+UPmb1NPeIZdESv1A3lxFDEq1Fs8c4/lzAj9BpshGyJVIZwZDKg==", "dev": true, "dependencies": { - "@aws-sdk/node-config-provider": "3.347.0", - "@aws-sdk/property-provider": "3.347.0", - "@aws-sdk/types": "3.347.0", - "@aws-sdk/url-parser": "3.347.0", + "@aws-sdk/types": "3.451.0", + "@smithy/property-provider": "^2.0.0", + "@smithy/types": "^2.5.0", "tslib": "^2.5.0" }, "engines": { @@ -493,19 +481,20 @@ } }, "node_modules/@aws-sdk/credential-provider-ini": { - "version": "3.352.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.352.0.tgz", - "integrity": "sha512-lnQUJznvOhI2er1u/OVf99/2JIyDH7W+6tfWNXEoVgEi4WXtdyZ+GpPNoZsmCtHB2Jwlsh51IxmYdCj6b6SdwQ==", - "dev": true, - "dependencies": { - "@aws-sdk/credential-provider-env": "3.347.0", - "@aws-sdk/credential-provider-imds": "3.347.0", - "@aws-sdk/credential-provider-process": "3.347.0", - "@aws-sdk/credential-provider-sso": "3.352.0", - "@aws-sdk/credential-provider-web-identity": "3.347.0", - "@aws-sdk/property-provider": "3.347.0", - "@aws-sdk/shared-ini-file-loader": "3.347.0", - "@aws-sdk/types": "3.347.0", + "version": "3.451.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.451.0.tgz", + "integrity": "sha512-TySt64Ci5/ZbqFw1F9Z0FIGvYx5JSC9e6gqDnizIYd8eMnn8wFRUscRrD7pIHKfrhvVKN5h0GdYovmMO/FMCBw==", + "dev": true, + "dependencies": { + "@aws-sdk/credential-provider-env": "3.451.0", + "@aws-sdk/credential-provider-process": "3.451.0", + "@aws-sdk/credential-provider-sso": "3.451.0", + "@aws-sdk/credential-provider-web-identity": "3.451.0", + "@aws-sdk/types": "3.451.0", + "@smithy/credential-provider-imds": "^2.0.0", + "@smithy/property-provider": "^2.0.0", + "@smithy/shared-ini-file-loader": "^2.0.6", + "@smithy/types": "^2.5.0", "tslib": "^2.5.0" }, "engines": { @@ -513,20 +502,21 @@ } }, "node_modules/@aws-sdk/credential-provider-node": { - "version": "3.352.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.352.0.tgz", - "integrity": "sha512-8UZ5EQpoqHCh+XSGq2CdhzHZyKLOwF1taDw5A/gmV4O5lAWL0AGs0cPIEUORJyggU6Hv43zZOpLgK6dMgWOLgA==", - "dev": true, - "dependencies": { - "@aws-sdk/credential-provider-env": "3.347.0", - "@aws-sdk/credential-provider-imds": "3.347.0", - "@aws-sdk/credential-provider-ini": "3.352.0", - "@aws-sdk/credential-provider-process": "3.347.0", - "@aws-sdk/credential-provider-sso": "3.352.0", - "@aws-sdk/credential-provider-web-identity": "3.347.0", - "@aws-sdk/property-provider": "3.347.0", - "@aws-sdk/shared-ini-file-loader": "3.347.0", - "@aws-sdk/types": "3.347.0", + "version": "3.451.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.451.0.tgz", + "integrity": "sha512-AEwM1WPyxUdKrKyUsKyFqqRFGU70e4qlDyrtBxJnSU9NRLZI8tfEZ67bN7fHSxBUBODgDXpMSlSvJiBLh5/3pw==", + "dev": true, + "dependencies": { + "@aws-sdk/credential-provider-env": "3.451.0", + "@aws-sdk/credential-provider-ini": "3.451.0", + "@aws-sdk/credential-provider-process": "3.451.0", + "@aws-sdk/credential-provider-sso": "3.451.0", + "@aws-sdk/credential-provider-web-identity": "3.451.0", + "@aws-sdk/types": "3.451.0", + "@smithy/credential-provider-imds": "^2.0.0", + "@smithy/property-provider": "^2.0.0", + "@smithy/shared-ini-file-loader": "^2.0.6", + "@smithy/types": "^2.5.0", "tslib": "^2.5.0" }, "engines": { @@ -534,14 +524,15 @@ } }, "node_modules/@aws-sdk/credential-provider-process": { - "version": "3.347.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.347.0.tgz", - "integrity": "sha512-yl1z4MsaBdXd4GQ2halIvYds23S67kElyOwz7g8kaQ4kHj+UoYWxz3JVW/DGusM6XmQ9/F67utBrUVA0uhQYyw==", + "version": "3.451.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.451.0.tgz", + "integrity": "sha512-HQywSdKeD5PErcLLnZfSyCJO+6T+ZyzF+Lm/QgscSC+CbSUSIPi//s15qhBRVely/3KBV6AywxwNH+5eYgt4lQ==", "dev": true, "dependencies": { - "@aws-sdk/property-provider": "3.347.0", - "@aws-sdk/shared-ini-file-loader": "3.347.0", - "@aws-sdk/types": "3.347.0", + "@aws-sdk/types": "3.451.0", + "@smithy/property-provider": "^2.0.0", + "@smithy/shared-ini-file-loader": "^2.0.6", + "@smithy/types": "^2.5.0", "tslib": "^2.5.0" }, "engines": { @@ -549,16 +540,17 @@ } }, "node_modules/@aws-sdk/credential-provider-sso": { - "version": "3.352.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.352.0.tgz", - "integrity": "sha512-YiooGNy9LYN1bFqKwO2wHC++1pYReiSqQDWBeluJfC3uZWpCyIUMdeYBR1X3XZDVtK6bl5KmhxldxJ3ntt/Q4w==", + "version": "3.451.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.451.0.tgz", + "integrity": "sha512-Usm/N51+unOt8ID4HnQzxIjUJDrkAQ1vyTOC0gSEEJ7h64NSSPGD5yhN7il5WcErtRd3EEtT1a8/GTC5TdBctg==", "dev": true, "dependencies": { - "@aws-sdk/client-sso": "3.352.0", - "@aws-sdk/property-provider": "3.347.0", - "@aws-sdk/shared-ini-file-loader": "3.347.0", - "@aws-sdk/token-providers": "3.352.0", - "@aws-sdk/types": "3.347.0", + "@aws-sdk/client-sso": "3.451.0", + "@aws-sdk/token-providers": "3.451.0", + "@aws-sdk/types": "3.451.0", + "@smithy/property-provider": "^2.0.0", + "@smithy/shared-ini-file-loader": "^2.0.6", + "@smithy/types": "^2.5.0", "tslib": "^2.5.0" }, "engines": { @@ -566,885 +558,492 @@ } }, "node_modules/@aws-sdk/credential-provider-web-identity": { - "version": "3.347.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.347.0.tgz", - "integrity": "sha512-DxoTlVK8lXjS1zVphtz/Ab+jkN/IZor9d6pP2GjJHNoAIIzXfRwwj5C8vr4eTayx/5VJ7GRP91J8GJ2cKly8Qw==", + "version": "3.451.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.451.0.tgz", + "integrity": "sha512-Xtg3Qw65EfDjWNG7o2xD6sEmumPfsy3WDGjk2phEzVg8s7hcZGxf5wYwe6UY7RJvlEKrU0rFA+AMn6Hfj5oOzg==", "dev": true, "dependencies": { - "@aws-sdk/property-provider": "3.347.0", - "@aws-sdk/types": "3.347.0", + "@aws-sdk/types": "3.451.0", + "@smithy/property-provider": "^2.0.0", + "@smithy/types": "^2.5.0", "tslib": "^2.5.0" }, "engines": { "node": ">=14.0.0" } }, - "node_modules/@aws-sdk/eventstream-codec": { - "version": "3.347.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/eventstream-codec/-/eventstream-codec-3.347.0.tgz", - "integrity": "sha512-61q+SyspjsaQ4sdgjizMyRgVph2CiW4aAtfpoH69EJFJfTxTR/OqnZ9Jx/3YiYi0ksrvDenJddYodfWWJqD8/w==", - "dev": true, - "dependencies": { - "@aws-crypto/crc32": "3.0.0", - "@aws-sdk/types": "3.347.0", - "@aws-sdk/util-hex-encoding": "3.310.0", - "tslib": "^2.5.0" - } - }, - "node_modules/@aws-sdk/fetch-http-handler": { - "version": "3.347.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/fetch-http-handler/-/fetch-http-handler-3.347.0.tgz", - "integrity": "sha512-sQ5P7ivY8//7wdxfA76LT1sF6V2Tyyz1qF6xXf9sihPN5Q1Y65c+SKpMzXyFSPqWZ82+SQQuDliYZouVyS6kQQ==", - "dev": true, - "dependencies": { - "@aws-sdk/protocol-http": "3.347.0", - "@aws-sdk/querystring-builder": "3.347.0", - "@aws-sdk/types": "3.347.0", - "@aws-sdk/util-base64": "3.310.0", - "tslib": "^2.5.0" - } - }, - "node_modules/@aws-sdk/hash-node": { - "version": "3.347.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/hash-node/-/hash-node-3.347.0.tgz", - "integrity": "sha512-96+ml/4EaUaVpzBdOLGOxdoXOjkPgkoJp/0i1fxOJEvl8wdAQSwc3IugVK9wZkCxy2DlENtgOe6DfIOhfffm/g==", + "node_modules/@aws-sdk/middleware-host-header": { + "version": "3.451.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.451.0.tgz", + "integrity": "sha512-j8a5jAfhWmsK99i2k8oR8zzQgXrsJtgrLxc3js6U+525mcZytoiDndkWTmD5fjJ1byU1U2E5TaPq+QJeDip05Q==", "dev": true, "dependencies": { - "@aws-sdk/types": "3.347.0", - "@aws-sdk/util-buffer-from": "3.310.0", - "@aws-sdk/util-utf8": "3.310.0", + "@aws-sdk/types": "3.451.0", + "@smithy/protocol-http": "^3.0.9", + "@smithy/types": "^2.5.0", "tslib": "^2.5.0" }, "engines": { "node": ">=14.0.0" } }, - "node_modules/@aws-sdk/invalid-dependency": { - "version": "3.347.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/invalid-dependency/-/invalid-dependency-3.347.0.tgz", - "integrity": "sha512-8imQcwLwqZ/wTJXZqzXT9pGLIksTRckhGLZaXT60tiBOPKuerTsus2L59UstLs5LP8TKaVZKFFSsjRIn9dQdmQ==", - "dev": true, - "dependencies": { - "@aws-sdk/types": "3.347.0", - "tslib": "^2.5.0" - } - }, - "node_modules/@aws-sdk/is-array-buffer": { - "version": "3.310.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/is-array-buffer/-/is-array-buffer-3.310.0.tgz", - "integrity": "sha512-urnbcCR+h9NWUnmOtet/s4ghvzsidFmspfhYaHAmSRdy9yDjdjBJMFjjsn85A1ODUktztm+cVncXjQ38WCMjMQ==", + "node_modules/@aws-sdk/middleware-logger": { + "version": "3.451.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.451.0.tgz", + "integrity": "sha512-0kHrYEyVeB2QBfP6TfbI240aRtatLZtcErJbhpiNUb+CQPgEL3crIjgVE8yYiJumZ7f0jyjo8HLPkwD1/2APaw==", "dev": true, "dependencies": { + "@aws-sdk/types": "3.451.0", + "@smithy/types": "^2.5.0", "tslib": "^2.5.0" }, "engines": { "node": ">=14.0.0" } }, - "node_modules/@aws-sdk/middleware-content-length": { - "version": "3.347.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-content-length/-/middleware-content-length-3.347.0.tgz", - "integrity": "sha512-i4qtWTDImMaDUtwKQPbaZpXsReiwiBomM1cWymCU4bhz81HL01oIxOxOBuiM+3NlDoCSPr3KI6txZSz/8cqXCQ==", + "node_modules/@aws-sdk/middleware-recursion-detection": { + "version": "3.451.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.451.0.tgz", + "integrity": "sha512-J6jL6gJ7orjHGM70KDRcCP7so/J2SnkN4vZ9YRLTeeZY6zvBuHDjX8GCIgSqPn/nXFXckZO8XSnA7u6+3TAT0w==", "dev": true, "dependencies": { - "@aws-sdk/protocol-http": "3.347.0", - "@aws-sdk/types": "3.347.0", + "@aws-sdk/types": "3.451.0", + "@smithy/protocol-http": "^3.0.9", + "@smithy/types": "^2.5.0", "tslib": "^2.5.0" }, "engines": { "node": ">=14.0.0" } }, - "node_modules/@aws-sdk/middleware-endpoint": { - "version": "3.347.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-endpoint/-/middleware-endpoint-3.347.0.tgz", - "integrity": "sha512-unF0c6dMaUL1ffU+37Ugty43DgMnzPWXr/Jup/8GbK5fzzWT5NQq6dj9KHPubMbWeEjQbmczvhv25JuJdK8gNQ==", + "node_modules/@aws-sdk/middleware-sdk-sts": { + "version": "3.451.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-sdk-sts/-/middleware-sdk-sts-3.451.0.tgz", + "integrity": "sha512-UJ6UfVUEgp0KIztxpAeelPXI5MLj9wUtUCqYeIMP7C1ZhoEMNm3G39VLkGN43dNhBf1LqjsV9jkKMZbVfYXuwg==", "dev": true, "dependencies": { - "@aws-sdk/middleware-serde": "3.347.0", - "@aws-sdk/types": "3.347.0", - "@aws-sdk/url-parser": "3.347.0", - "@aws-sdk/util-middleware": "3.347.0", + "@aws-sdk/middleware-signing": "3.451.0", + "@aws-sdk/types": "3.451.0", + "@smithy/types": "^2.5.0", "tslib": "^2.5.0" }, "engines": { "node": ">=14.0.0" } }, - "node_modules/@aws-sdk/middleware-host-header": { - "version": "3.347.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.347.0.tgz", - "integrity": "sha512-kpKmR9OvMlnReqp5sKcJkozbj1wmlblbVSbnQAIkzeQj2xD5dnVR3Nn2ogQKxSmU1Fv7dEroBtrruJ1o3fY38A==", + "node_modules/@aws-sdk/middleware-signing": { + "version": "3.451.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-signing/-/middleware-signing-3.451.0.tgz", + "integrity": "sha512-s5ZlcIoLNg1Huj4Qp06iKniE8nJt/Pj1B/fjhWc6cCPCM7XJYUCejCnRh6C5ZJoBEYodjuwZBejPc1Wh3j+znA==", "dev": true, "dependencies": { - "@aws-sdk/protocol-http": "3.347.0", - "@aws-sdk/types": "3.347.0", + "@aws-sdk/types": "3.451.0", + "@smithy/property-provider": "^2.0.0", + "@smithy/protocol-http": "^3.0.9", + "@smithy/signature-v4": "^2.0.0", + "@smithy/types": "^2.5.0", + "@smithy/util-middleware": "^2.0.6", "tslib": "^2.5.0" }, "engines": { "node": ">=14.0.0" } }, - "node_modules/@aws-sdk/middleware-logger": { - "version": "3.347.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.347.0.tgz", - "integrity": "sha512-NYC+Id5UCkVn+3P1t/YtmHt75uED06vwaKyxDy0UmB2K66PZLVtwWbLpVWrhbroaw1bvUHYcRyQ9NIfnVcXQjA==", + "node_modules/@aws-sdk/middleware-user-agent": { + "version": "3.451.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.451.0.tgz", + "integrity": "sha512-8NM/0JiKLNvT9wtAQVl1DFW0cEO7OvZyLSUBLNLTHqyvOZxKaZ8YFk7d8PL6l76LeUKRxq4NMxfZQlUIRe0eSA==", "dev": true, "dependencies": { - "@aws-sdk/types": "3.347.0", + "@aws-sdk/types": "3.451.0", + "@aws-sdk/util-endpoints": "3.451.0", + "@smithy/protocol-http": "^3.0.9", + "@smithy/types": "^2.5.0", "tslib": "^2.5.0" }, "engines": { "node": ">=14.0.0" } }, - "node_modules/@aws-sdk/middleware-recursion-detection": { - "version": "3.347.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.347.0.tgz", - "integrity": "sha512-qfnSvkFKCAMjMHR31NdsT0gv5Sq/ZHTUD4yQsSLpbVQ6iYAS834lrzXt41iyEHt57Y514uG7F/Xfvude3u4icQ==", + "node_modules/@aws-sdk/region-config-resolver": { + "version": "3.451.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.451.0.tgz", + "integrity": "sha512-3iMf4OwzrFb4tAAmoROXaiORUk2FvSejnHIw/XHvf/jjR4EqGGF95NZP/n/MeFZMizJWVssrwS412GmoEyoqhg==", "dev": true, "dependencies": { - "@aws-sdk/protocol-http": "3.347.0", - "@aws-sdk/types": "3.347.0", + "@smithy/node-config-provider": "^2.1.5", + "@smithy/types": "^2.5.0", + "@smithy/util-config-provider": "^2.0.0", + "@smithy/util-middleware": "^2.0.6", "tslib": "^2.5.0" }, "engines": { "node": ">=14.0.0" } }, - "node_modules/@aws-sdk/middleware-retry": { - "version": "3.347.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-retry/-/middleware-retry-3.347.0.tgz", - "integrity": "sha512-CpdM+8dCSbX96agy4FCzOfzDmhNnGBM/pxrgIVLm5nkYTLuXp/d7ubpFEUHULr+4hCd5wakHotMt7yO29NFaVw==", + "node_modules/@aws-sdk/token-providers": { + "version": "3.451.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.451.0.tgz", + "integrity": "sha512-ij1L5iUbn6CwxVOT1PG4NFjsrsKN9c4N1YEM0lkl6DwmaNOscjLKGSNyj9M118vSWsOs1ZDbTwtj++h0O/BWrQ==", "dev": true, "dependencies": { - "@aws-sdk/protocol-http": "3.347.0", - "@aws-sdk/service-error-classification": "3.347.0", - "@aws-sdk/types": "3.347.0", - "@aws-sdk/util-middleware": "3.347.0", - "@aws-sdk/util-retry": "3.347.0", - "tslib": "^2.5.0", - "uuid": "^8.3.2" + "@aws-crypto/sha256-browser": "3.0.0", + "@aws-crypto/sha256-js": "3.0.0", + "@aws-sdk/middleware-host-header": "3.451.0", + "@aws-sdk/middleware-logger": "3.451.0", + "@aws-sdk/middleware-recursion-detection": "3.451.0", + "@aws-sdk/middleware-user-agent": "3.451.0", + "@aws-sdk/region-config-resolver": "3.451.0", + "@aws-sdk/types": "3.451.0", + "@aws-sdk/util-endpoints": "3.451.0", + "@aws-sdk/util-user-agent-browser": "3.451.0", + "@aws-sdk/util-user-agent-node": "3.451.0", + "@smithy/config-resolver": "^2.0.18", + "@smithy/fetch-http-handler": "^2.2.6", + "@smithy/hash-node": "^2.0.15", + "@smithy/invalid-dependency": "^2.0.13", + "@smithy/middleware-content-length": "^2.0.15", + "@smithy/middleware-endpoint": "^2.2.0", + "@smithy/middleware-retry": "^2.0.20", + "@smithy/middleware-serde": "^2.0.13", + "@smithy/middleware-stack": "^2.0.7", + "@smithy/node-config-provider": "^2.1.5", + "@smithy/node-http-handler": "^2.1.9", + "@smithy/property-provider": "^2.0.0", + "@smithy/protocol-http": "^3.0.9", + "@smithy/shared-ini-file-loader": "^2.0.6", + "@smithy/smithy-client": "^2.1.15", + "@smithy/types": "^2.5.0", + "@smithy/url-parser": "^2.0.13", + "@smithy/util-base64": "^2.0.1", + "@smithy/util-body-length-browser": "^2.0.0", + "@smithy/util-body-length-node": "^2.1.0", + "@smithy/util-defaults-mode-browser": "^2.0.19", + "@smithy/util-defaults-mode-node": "^2.0.25", + "@smithy/util-endpoints": "^1.0.4", + "@smithy/util-retry": "^2.0.6", + "@smithy/util-utf8": "^2.0.2", + "tslib": "^2.5.0" }, "engines": { "node": ">=14.0.0" } }, - "node_modules/@aws-sdk/middleware-sdk-sts": { - "version": "3.347.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-sdk-sts/-/middleware-sdk-sts-3.347.0.tgz", - "integrity": "sha512-38LJ0bkIoVF3W97x6Jyyou72YV9Cfbml4OaDEdnrCOo0EssNZM5d7RhjMvQDwww7/3OBY/BzeOcZKfJlkYUXGw==", + "node_modules/@aws-sdk/types": { + "version": "3.451.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.451.0.tgz", + "integrity": "sha512-rhK+qeYwCIs+laJfWCcrYEjay2FR/9VABZJ2NRM89jV/fKqGVQR52E5DQqrI+oEIL5JHMhhnr4N4fyECMS35lw==", "dev": true, "dependencies": { - "@aws-sdk/middleware-signing": "3.347.0", - "@aws-sdk/types": "3.347.0", + "@smithy/types": "^2.5.0", "tslib": "^2.5.0" }, "engines": { "node": ">=14.0.0" } }, - "node_modules/@aws-sdk/middleware-serde": { - "version": "3.347.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-serde/-/middleware-serde-3.347.0.tgz", - "integrity": "sha512-x5Foi7jRbVJXDu9bHfyCbhYDH5pKK+31MmsSJ3k8rY8keXLBxm2XEEg/AIoV9/TUF9EeVvZ7F1/RmMpJnWQsEg==", + "node_modules/@aws-sdk/util-endpoints": { + "version": "3.451.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.451.0.tgz", + "integrity": "sha512-giqLGBTnRIcKkDqwU7+GQhKbtJ5Ku35cjGQIfMyOga6pwTBUbaK0xW1Sdd8sBQ1GhApscnChzI9o/R9x0368vw==", "dev": true, "dependencies": { - "@aws-sdk/types": "3.347.0", + "@aws-sdk/types": "3.451.0", + "@smithy/util-endpoints": "^1.0.4", "tslib": "^2.5.0" }, "engines": { "node": ">=14.0.0" } }, - "node_modules/@aws-sdk/middleware-signing": { - "version": "3.347.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-signing/-/middleware-signing-3.347.0.tgz", - "integrity": "sha512-zVBF/4MGKnvhAE/J+oAL/VAehiyv+trs2dqSQXwHou9j8eA8Vm8HS2NdOwpkZQchIxTuwFlqSusDuPEdYFbvGw==", + "node_modules/@aws-sdk/util-locate-window": { + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-locate-window/-/util-locate-window-3.310.0.tgz", + "integrity": "sha512-qo2t/vBTnoXpjKxlsC2e1gBrRm80M3bId27r0BRB2VniSSe7bL1mmzM+/HFtujm0iAxtPM+aLEflLJlJeDPg0w==", "dev": true, "dependencies": { - "@aws-sdk/property-provider": "3.347.0", - "@aws-sdk/protocol-http": "3.347.0", - "@aws-sdk/signature-v4": "3.347.0", - "@aws-sdk/types": "3.347.0", - "@aws-sdk/util-middleware": "3.347.0", "tslib": "^2.5.0" }, "engines": { "node": ">=14.0.0" } }, - "node_modules/@aws-sdk/middleware-stack": { - "version": "3.347.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-stack/-/middleware-stack-3.347.0.tgz", - "integrity": "sha512-Izidg4rqtYMcKuvn2UzgEpPLSmyd8ub9+LQ2oIzG3mpIzCBITq7wp40jN1iNkMg+X6KEnX9vdMJIYZsPYMCYuQ==", + "node_modules/@aws-sdk/util-user-agent-browser": { + "version": "3.451.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.451.0.tgz", + "integrity": "sha512-Ws5mG3J0TQifH7OTcMrCTexo7HeSAc3cBgjfhS/ofzPUzVCtsyg0G7I6T7wl7vJJETix2Kst2cpOsxygPgPD9w==", "dev": true, "dependencies": { + "@aws-sdk/types": "3.451.0", + "@smithy/types": "^2.5.0", + "bowser": "^2.11.0", "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" } }, - "node_modules/@aws-sdk/middleware-user-agent": { - "version": "3.352.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.352.0.tgz", - "integrity": "sha512-QGqblMTsVDqeomy22KPm9LUW8PHZXBA2Hjk9Hcw8U1uFS8IKYJrewInG3ae2+9FAcTyug4LFWDf8CRr9YH2B3Q==", + "node_modules/@aws-sdk/util-user-agent-node": { + "version": "3.451.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.451.0.tgz", + "integrity": "sha512-TBzm6P+ql4mkGFAjPlO1CI+w3yUT+NulaiALjl/jNX/nnUp6HsJsVxJf4nVFQTG5KRV0iqMypcs7I3KIhH+LmA==", "dev": true, "dependencies": { - "@aws-sdk/protocol-http": "3.347.0", - "@aws-sdk/types": "3.347.0", - "@aws-sdk/util-endpoints": "3.352.0", + "@aws-sdk/types": "3.451.0", + "@smithy/node-config-provider": "^2.1.5", + "@smithy/types": "^2.5.0", "tslib": "^2.5.0" }, "engines": { "node": ">=14.0.0" + }, + "peerDependencies": { + "aws-crt": ">=1.0.0" + }, + "peerDependenciesMeta": { + "aws-crt": { + "optional": true + } } }, - "node_modules/@aws-sdk/node-config-provider": { - "version": "3.347.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/node-config-provider/-/node-config-provider-3.347.0.tgz", - "integrity": "sha512-faU93d3+5uTTUcotGgMXF+sJVFjrKh+ufW+CzYKT4yUHammyaIab/IbTPWy2hIolcEGtuPeVoxXw8TXbkh/tuw==", + "node_modules/@aws-sdk/util-utf8-browser": { + "version": "3.259.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-utf8-browser/-/util-utf8-browser-3.259.0.tgz", + "integrity": "sha512-UvFa/vR+e19XookZF8RzFZBrw2EUkQWxiBW0yYQAhvk3C+QVGl0H3ouca8LDBlBfQKXwmW3huo/59H8rwb1wJw==", "dev": true, "dependencies": { - "@aws-sdk/property-provider": "3.347.0", - "@aws-sdk/shared-ini-file-loader": "3.347.0", - "@aws-sdk/types": "3.347.0", - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" + "tslib": "^2.3.1" } }, - "node_modules/@aws-sdk/node-http-handler": { - "version": "3.350.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/node-http-handler/-/node-http-handler-3.350.0.tgz", - "integrity": "sha512-oD96GAlmpzYilCdC8wwyURM5lNfNHZCjm/kxBkQulHKa2kRbIrnD9GfDqdCkWA5cTpjh1NzGLT4D6e6UFDjt9w==", + "node_modules/@base2/pretty-print-object": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@base2/pretty-print-object/-/pretty-print-object-1.0.1.tgz", + "integrity": "sha512-4iri8i1AqYHJE2DstZYkyEprg6Pq6sKx3xn5FpySk9sNhH7qN2LLlHJCfDTZRILNwQNPD7mATWM0TBui7uC1pA==", + "dev": true + }, + "node_modules/@bcoe/v8-coverage": { + "version": "0.2.3", "dev": true, - "dependencies": { - "@aws-sdk/abort-controller": "3.347.0", - "@aws-sdk/protocol-http": "3.347.0", - "@aws-sdk/querystring-builder": "3.347.0", - "@aws-sdk/types": "3.347.0", - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } + "license": "MIT" }, - "node_modules/@aws-sdk/property-provider": { - "version": "3.347.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/property-provider/-/property-provider-3.347.0.tgz", - "integrity": "sha512-t3nJ8CYPLKAF2v9nIHOHOlF0CviQbTvbFc2L4a+A+EVd/rM4PzL3+3n8ZJsr0h7f6uD04+b5YRFgKgnaqLXlEg==", + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", "dev": true, + "license": "MIT", "dependencies": { - "@aws-sdk/types": "3.347.0", - "tslib": "^2.5.0" + "@jridgewell/trace-mapping": "0.3.9" }, "engines": { - "node": ">=14.0.0" + "node": ">=12" } }, - "node_modules/@aws-sdk/protocol-http": { - "version": "3.347.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/protocol-http/-/protocol-http-3.347.0.tgz", - "integrity": "sha512-2YdBhc02Wvy03YjhGwUxF0UQgrPWEy8Iq75pfS42N+/0B/+eWX1aQgfjFxIpLg7YSjT5eKtYOQGlYd4MFTgj9g==", + "node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", "dev": true, + "license": "MIT", "dependencies": { - "@aws-sdk/types": "3.347.0", - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" } }, - "node_modules/@aws-sdk/querystring-builder": { - "version": "3.347.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/querystring-builder/-/querystring-builder-3.347.0.tgz", - "integrity": "sha512-phtKTe6FXoV02MoPkIVV6owXI8Mwr5IBN3bPoxhcPvJG2AjEmnetSIrhb8kwc4oNhlwfZwH6Jo5ARW/VEWbZtg==", - "dev": true, - "dependencies": { - "@aws-sdk/types": "3.347.0", - "@aws-sdk/util-uri-escape": "3.310.0", - "tslib": "^2.5.0" - }, + "node_modules/@esbuild/android-arm": { + "version": "0.17.16", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.17.16.tgz", + "integrity": "sha512-baLqRpLe4JnKrUXLJChoTN0iXZH7El/mu58GE3WIA6/H834k0XWvLRmGLG8y8arTRS9hJJibPnF0tiGhmWeZgw==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "android" + ], "engines": { - "node": ">=14.0.0" + "node": ">=12" } }, - "node_modules/@aws-sdk/querystring-parser": { - "version": "3.347.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/querystring-parser/-/querystring-parser-3.347.0.tgz", - "integrity": "sha512-5VXOhfZz78T2W7SuXf2avfjKglx1VZgZgp9Zfhrt/Rq+MTu2D+PZc5zmJHhYigD7x83jLSLogpuInQpFMA9LgA==", - "dev": true, - "dependencies": { - "@aws-sdk/types": "3.347.0", - "tslib": "^2.5.0" - }, + "node_modules/@esbuild/android-arm64": { + "version": "0.17.16", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.17.16.tgz", + "integrity": "sha512-QX48qmsEZW+gcHgTmAj+x21mwTz8MlYQBnzF6861cNdQGvj2jzzFjqH0EBabrIa/WVZ2CHolwMoqxVryqKt8+Q==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "android" + ], "engines": { - "node": ">=14.0.0" + "node": ">=12" } }, - "node_modules/@aws-sdk/service-error-classification": { - "version": "3.347.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/service-error-classification/-/service-error-classification-3.347.0.tgz", - "integrity": "sha512-xZ3MqSY81Oy2gh5g0fCtooAbahqh9VhsF8vcKjVX8+XPbGC8y+kej82+MsMg4gYL8gRFB9u4hgYbNgIS6JTAvg==", - "dev": true, + "node_modules/@esbuild/android-x64": { + "version": "0.17.16", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.17.16.tgz", + "integrity": "sha512-G4wfHhrrz99XJgHnzFvB4UwwPxAWZaZBOFXh+JH1Duf1I4vIVfuYY9uVLpx4eiV2D/Jix8LJY+TAdZ3i40tDow==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "android" + ], "engines": { - "node": ">=14.0.0" + "node": ">=12" } }, - "node_modules/@aws-sdk/shared-ini-file-loader": { - "version": "3.347.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/shared-ini-file-loader/-/shared-ini-file-loader-3.347.0.tgz", - "integrity": "sha512-Xw+zAZQVLb+xMNHChXQ29tzzLqm3AEHsD8JJnlkeFjeMnWQtXdUfOARl5s8NzAppcKQNlVe2gPzjaKjoy2jz1Q==", - "dev": true, - "dependencies": { - "@aws-sdk/types": "3.347.0", - "tslib": "^2.5.0" - }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.17.16", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.17.16.tgz", + "integrity": "sha512-/Ofw8UXZxuzTLsNFmz1+lmarQI6ztMZ9XktvXedTbt3SNWDn0+ODTwxExLYQ/Hod91EZB4vZPQJLoqLF0jvEzA==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">=14.0.0" + "node": ">=12" } }, - "node_modules/@aws-sdk/signature-v4": { - "version": "3.347.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/signature-v4/-/signature-v4-3.347.0.tgz", - "integrity": "sha512-58Uq1do+VsTHYkP11dTK+DF53fguoNNJL9rHRWhzP+OcYv3/mBMLoS2WPz/x9FO5mBg4ESFsug0I6mXbd36tjw==", - "dev": true, - "dependencies": { - "@aws-sdk/eventstream-codec": "3.347.0", - "@aws-sdk/is-array-buffer": "3.310.0", - "@aws-sdk/types": "3.347.0", - "@aws-sdk/util-hex-encoding": "3.310.0", - "@aws-sdk/util-middleware": "3.347.0", - "@aws-sdk/util-uri-escape": "3.310.0", - "@aws-sdk/util-utf8": "3.310.0", - "tslib": "^2.5.0" - }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.17.16", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.17.16.tgz", + "integrity": "sha512-SzBQtCV3Pdc9kyizh36Ol+dNVhkDyIrGb/JXZqFq8WL37LIyrXU0gUpADcNV311sCOhvY+f2ivMhb5Tuv8nMOQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">=14.0.0" + "node": ">=12" } }, - "node_modules/@aws-sdk/smithy-client": { - "version": "3.347.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/smithy-client/-/smithy-client-3.347.0.tgz", - "integrity": "sha512-PaGTDsJLGK0sTjA6YdYQzILRlPRN3uVFyqeBUkfltXssvUzkm8z2t1lz2H4VyJLAhwnG5ZuZTNEV/2mcWrU7JQ==", - "dev": true, - "dependencies": { - "@aws-sdk/middleware-stack": "3.347.0", - "@aws-sdk/types": "3.347.0", - "tslib": "^2.5.0" - }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.17.16", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.16.tgz", + "integrity": "sha512-ZqftdfS1UlLiH1DnS2u3It7l4Bc3AskKeu+paJSfk7RNOMrOxmeFDhLTMQqMxycP1C3oj8vgkAT6xfAuq7ZPRA==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "freebsd" + ], "engines": { - "node": ">=14.0.0" + "node": ">=12" } }, - "node_modules/@aws-sdk/token-providers": { - "version": "3.352.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.352.0.tgz", - "integrity": "sha512-cmmAgieLP/aAl9WdPiBoaC0Abd6KncSLig/ElLPoNsADR10l3QgxQcVF3YMtdX0U0d917+/SeE1PdrPD2x15cw==", - "dev": true, - "dependencies": { - "@aws-sdk/client-sso-oidc": "3.352.0", - "@aws-sdk/property-provider": "3.347.0", - "@aws-sdk/shared-ini-file-loader": "3.347.0", - "@aws-sdk/types": "3.347.0", - "tslib": "^2.5.0" - }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.17.16", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.17.16.tgz", + "integrity": "sha512-rHV6zNWW1tjgsu0dKQTX9L0ByiJHHLvQKrWtnz8r0YYJI27FU3Xu48gpK2IBj1uCSYhJ+pEk6Y0Um7U3rIvV8g==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "freebsd" + ], "engines": { - "node": ">=14.0.0" + "node": ">=12" } }, - "node_modules/@aws-sdk/types": { - "version": "3.347.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.347.0.tgz", - "integrity": "sha512-GkCMy79mdjU9OTIe5KT58fI/6uqdf8UmMdWqVHmFJ+UpEzOci7L/uw4sOXWo7xpPzLs6cJ7s5ouGZW4GRPmHFA==", - "dev": true, - "dependencies": { - "tslib": "^2.5.0" - }, + "node_modules/@esbuild/linux-arm": { + "version": "0.17.16", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.17.16.tgz", + "integrity": "sha512-n4O8oVxbn7nl4+m+ISb0a68/lcJClIbaGAoXwqeubj/D1/oMMuaAXmJVfFlRjJLu/ZvHkxoiFJnmbfp4n8cdSw==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=14.0.0" + "node": ">=12" } }, - "node_modules/@aws-sdk/url-parser": { - "version": "3.347.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/url-parser/-/url-parser-3.347.0.tgz", - "integrity": "sha512-lhrnVjxdV7hl+yCnJfDZOaVLSqKjxN20MIOiijRiqaWGLGEAiSqBreMhL89X1WKCifxAs4zZf9YB9SbdziRpAA==", - "dev": true, - "dependencies": { - "@aws-sdk/querystring-parser": "3.347.0", - "@aws-sdk/types": "3.347.0", - "tslib": "^2.5.0" - } - }, - "node_modules/@aws-sdk/util-base64": { - "version": "3.310.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-base64/-/util-base64-3.310.0.tgz", - "integrity": "sha512-v3+HBKQvqgdzcbL+pFswlx5HQsd9L6ZTlyPVL2LS9nNXnCcR3XgGz9jRskikRUuUvUXtkSG1J88GAOnJ/apTPg==", - "dev": true, - "dependencies": { - "@aws-sdk/util-buffer-from": "3.310.0", - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/util-body-length-browser": { - "version": "3.310.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-body-length-browser/-/util-body-length-browser-3.310.0.tgz", - "integrity": "sha512-sxsC3lPBGfpHtNTUoGXMQXLwjmR0zVpx0rSvzTPAuoVILVsp5AU/w5FphNPxD5OVIjNbZv9KsKTuvNTiZjDp9g==", - "dev": true, - "dependencies": { - "tslib": "^2.5.0" - } - }, - "node_modules/@aws-sdk/util-body-length-node": { - "version": "3.310.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-body-length-node/-/util-body-length-node-3.310.0.tgz", - "integrity": "sha512-2tqGXdyKhyA6w4zz7UPoS8Ip+7sayOg9BwHNidiGm2ikbDxm1YrCfYXvCBdwaJxa4hJfRVz+aL9e+d3GqPI9pQ==", - "dev": true, - "dependencies": { - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/util-buffer-from": { - "version": "3.310.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-buffer-from/-/util-buffer-from-3.310.0.tgz", - "integrity": "sha512-i6LVeXFtGih5Zs8enLrt+ExXY92QV25jtEnTKHsmlFqFAuL3VBeod6boeMXkN2p9lbSVVQ1sAOOYZOHYbYkntw==", - "dev": true, - "dependencies": { - "@aws-sdk/is-array-buffer": "3.310.0", - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/util-config-provider": { - "version": "3.310.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-config-provider/-/util-config-provider-3.310.0.tgz", - "integrity": "sha512-xIBaYo8dwiojCw8vnUcIL4Z5tyfb1v3yjqyJKJWV/dqKUFOOS0U591plmXbM+M/QkXyML3ypon1f8+BoaDExrg==", - "dev": true, - "dependencies": { - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/util-defaults-mode-browser": { - "version": "3.347.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-defaults-mode-browser/-/util-defaults-mode-browser-3.347.0.tgz", - "integrity": "sha512-+JHFA4reWnW/nMWwrLKqL2Lm/biw/Dzi/Ix54DAkRZ08C462jMKVnUlzAI+TfxQE3YLm99EIa0G7jiEA+p81Qw==", - "dev": true, - "dependencies": { - "@aws-sdk/property-provider": "3.347.0", - "@aws-sdk/types": "3.347.0", - "bowser": "^2.11.0", - "tslib": "^2.5.0" - }, - "engines": { - "node": ">= 10.0.0" - } - }, - "node_modules/@aws-sdk/util-defaults-mode-node": { - "version": "3.347.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-defaults-mode-node/-/util-defaults-mode-node-3.347.0.tgz", - "integrity": "sha512-A8BzIVhAAZE5WEukoAN2kYebzTc99ZgncbwOmgCCbvdaYlk5tzguR/s+uoT4G0JgQGol/4hAMuJEl7elNgU6RQ==", - "dev": true, - "dependencies": { - "@aws-sdk/config-resolver": "3.347.0", - "@aws-sdk/credential-provider-imds": "3.347.0", - "@aws-sdk/node-config-provider": "3.347.0", - "@aws-sdk/property-provider": "3.347.0", - "@aws-sdk/types": "3.347.0", - "tslib": "^2.5.0" - }, - "engines": { - "node": ">= 10.0.0" - } - }, - "node_modules/@aws-sdk/util-endpoints": { - "version": "3.352.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.352.0.tgz", - "integrity": "sha512-PjWMPdoIUWfBPgAWLyOrWFbdSS/3DJtc0OmFb/JrE8C8rKFYl+VGW5f1p0cVdRWiDR0xCGr0s67p8itAakVqjw==", - "dev": true, - "dependencies": { - "@aws-sdk/types": "3.347.0", - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/util-hex-encoding": { - "version": "3.310.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-hex-encoding/-/util-hex-encoding-3.310.0.tgz", - "integrity": "sha512-sVN7mcCCDSJ67pI1ZMtk84SKGqyix6/0A1Ab163YKn+lFBQRMKexleZzpYzNGxYzmQS6VanP/cfU7NiLQOaSfA==", - "dev": true, - "dependencies": { - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/util-locate-window": { - "version": "3.310.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-locate-window/-/util-locate-window-3.310.0.tgz", - "integrity": "sha512-qo2t/vBTnoXpjKxlsC2e1gBrRm80M3bId27r0BRB2VniSSe7bL1mmzM+/HFtujm0iAxtPM+aLEflLJlJeDPg0w==", - "dev": true, - "dependencies": { - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/util-middleware": { - "version": "3.347.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-middleware/-/util-middleware-3.347.0.tgz", - "integrity": "sha512-8owqUA3ePufeYTUvlzdJ7Z0miLorTwx+rNol5lourGQZ9JXsVMo23+yGA7nOlFuXSGkoKpMOtn6S0BT2bcfeiw==", - "dev": true, - "dependencies": { - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/util-retry": { - "version": "3.347.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-retry/-/util-retry-3.347.0.tgz", - "integrity": "sha512-NxnQA0/FHFxriQAeEgBonA43Q9/VPFQa8cfJDuT2A1YZruMasgjcltoZszi1dvoIRWSZsFTW42eY2gdOd0nffQ==", - "dev": true, - "dependencies": { - "@aws-sdk/service-error-classification": "3.347.0", - "tslib": "^2.5.0" - }, - "engines": { - "node": ">= 14.0.0" - } - }, - "node_modules/@aws-sdk/util-uri-escape": { - "version": "3.310.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-uri-escape/-/util-uri-escape-3.310.0.tgz", - "integrity": "sha512-drzt+aB2qo2LgtDoiy/3sVG8w63cgLkqFIa2NFlGpUgHFWTXkqtbgf4L5QdjRGKWhmZsnqkbtL7vkSWEcYDJ4Q==", - "dev": true, - "dependencies": { - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/util-user-agent-browser": { - "version": "3.347.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.347.0.tgz", - "integrity": "sha512-ydxtsKVtQefgbk1Dku1q7pMkjDYThauG9/8mQkZUAVik55OUZw71Zzr3XO8J8RKvQG8lmhPXuAQ0FKAyycc0RA==", - "dev": true, - "dependencies": { - "@aws-sdk/types": "3.347.0", - "bowser": "^2.11.0", - "tslib": "^2.5.0" - } - }, - "node_modules/@aws-sdk/util-user-agent-node": { - "version": "3.347.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.347.0.tgz", - "integrity": "sha512-6X0b9qGsbD1s80PmbaB6v1/ZtLfSx6fjRX8caM7NN0y/ObuLoX8LhYnW6WlB2f1+xb4EjaCNgpP/zCf98MXosw==", - "dev": true, - "dependencies": { - "@aws-sdk/node-config-provider": "3.347.0", - "@aws-sdk/types": "3.347.0", - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "aws-crt": ">=1.0.0" - }, - "peerDependenciesMeta": { - "aws-crt": { - "optional": true - } - } - }, - "node_modules/@aws-sdk/util-utf8": { - "version": "3.310.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-utf8/-/util-utf8-3.310.0.tgz", - "integrity": "sha512-DnLfFT8uCO22uOJc0pt0DsSNau1GTisngBCDw8jQuWT5CqogMJu4b/uXmwEqfj8B3GX6Xsz8zOd6JpRlPftQoA==", - "dev": true, - "dependencies": { - "@aws-sdk/util-buffer-from": "3.310.0", - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/util-utf8-browser": { - "version": "3.259.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-utf8-browser/-/util-utf8-browser-3.259.0.tgz", - "integrity": "sha512-UvFa/vR+e19XookZF8RzFZBrw2EUkQWxiBW0yYQAhvk3C+QVGl0H3ouca8LDBlBfQKXwmW3huo/59H8rwb1wJw==", - "dev": true, - "dependencies": { - "tslib": "^2.3.1" - } - }, - "node_modules/@aws-sdk/util-waiter": { - "version": "3.347.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-waiter/-/util-waiter-3.347.0.tgz", - "integrity": "sha512-3ze/0PkwkzUzLncukx93tZgGL0JX9NaP8DxTi6WzflnL/TEul5Z63PCruRNK0om17iZYAWKrf8q2mFoHYb4grA==", - "dev": true, - "dependencies": { - "@aws-sdk/abort-controller": "3.347.0", - "@aws-sdk/types": "3.347.0", - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@base2/pretty-print-object": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@base2/pretty-print-object/-/pretty-print-object-1.0.1.tgz", - "integrity": "sha512-4iri8i1AqYHJE2DstZYkyEprg6Pq6sKx3xn5FpySk9sNhH7qN2LLlHJCfDTZRILNwQNPD7mATWM0TBui7uC1pA==", - "dev": true - }, - "node_modules/@bcoe/v8-coverage": { - "version": "0.2.3", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspotcode/source-map-support": { - "version": "0.8.1", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/trace-mapping": "0.3.9" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": { - "version": "0.3.9", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" - } - }, - "node_modules/@esbuild/android-arm": { + "node_modules/@esbuild/linux-arm64": { "version": "0.17.16", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.17.16.tgz", - "integrity": "sha512-baLqRpLe4JnKrUXLJChoTN0iXZH7El/mu58GE3WIA6/H834k0XWvLRmGLG8y8arTRS9hJJibPnF0tiGhmWeZgw==", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.17.16.tgz", + "integrity": "sha512-8yoZhGkU6aHu38WpaM4HrRLTFc7/VVD9Q2SvPcmIQIipQt2I/GMTZNdEHXoypbbGao5kggLcxg0iBKjo0SQYKA==", "cpu": [ - "arm" + "arm64" ], "optional": true, "os": [ - "android" + "linux" ], "engines": { "node": ">=12" } }, - "node_modules/@esbuild/android-arm64": { + "node_modules/@esbuild/linux-ia32": { "version": "0.17.16", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.17.16.tgz", - "integrity": "sha512-QX48qmsEZW+gcHgTmAj+x21mwTz8MlYQBnzF6861cNdQGvj2jzzFjqH0EBabrIa/WVZ2CHolwMoqxVryqKt8+Q==", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.17.16.tgz", + "integrity": "sha512-9ZBjlkdaVYxPNO8a7OmzDbOH9FMQ1a58j7Xb21UfRU29KcEEU3VTHk+Cvrft/BNv0gpWJMiiZ/f4w0TqSP0gLA==", "cpu": [ - "arm64" + "ia32" ], "optional": true, "os": [ - "android" + "linux" ], "engines": { "node": ">=12" } }, - "node_modules/@esbuild/android-x64": { + "node_modules/@esbuild/linux-loong64": { "version": "0.17.16", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.17.16.tgz", - "integrity": "sha512-G4wfHhrrz99XJgHnzFvB4UwwPxAWZaZBOFXh+JH1Duf1I4vIVfuYY9uVLpx4eiV2D/Jix8LJY+TAdZ3i40tDow==", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.17.16.tgz", + "integrity": "sha512-TIZTRojVBBzdgChY3UOG7BlPhqJz08AL7jdgeeu+kiObWMFzGnQD7BgBBkWRwOtKR1i2TNlO7YK6m4zxVjjPRQ==", "cpu": [ - "x64" + "loong64" ], "optional": true, "os": [ - "android" + "linux" ], "engines": { "node": ">=12" } }, - "node_modules/@esbuild/darwin-arm64": { + "node_modules/@esbuild/linux-mips64el": { "version": "0.17.16", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.17.16.tgz", - "integrity": "sha512-/Ofw8UXZxuzTLsNFmz1+lmarQI6ztMZ9XktvXedTbt3SNWDn0+ODTwxExLYQ/Hod91EZB4vZPQJLoqLF0jvEzA==", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.17.16.tgz", + "integrity": "sha512-UPeRuFKCCJYpBbIdczKyHLAIU31GEm0dZl1eMrdYeXDH+SJZh/i+2cAmD3A1Wip9pIc5Sc6Kc5cFUrPXtR0XHA==", "cpu": [ - "arm64" + "mips64el" ], "optional": true, "os": [ - "darwin" + "linux" ], "engines": { "node": ">=12" } }, - "node_modules/@esbuild/darwin-x64": { + "node_modules/@esbuild/linux-ppc64": { "version": "0.17.16", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.17.16.tgz", - "integrity": "sha512-SzBQtCV3Pdc9kyizh36Ol+dNVhkDyIrGb/JXZqFq8WL37LIyrXU0gUpADcNV311sCOhvY+f2ivMhb5Tuv8nMOQ==", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.17.16.tgz", + "integrity": "sha512-io6yShgIEgVUhExJejJ21xvO5QtrbiSeI7vYUnr7l+v/O9t6IowyhdiYnyivX2X5ysOVHAuyHW+Wyi7DNhdw6Q==", "cpu": [ - "x64" + "ppc64" ], "optional": true, "os": [ - "darwin" + "linux" ], "engines": { "node": ">=12" } }, - "node_modules/@esbuild/freebsd-arm64": { + "node_modules/@esbuild/linux-riscv64": { "version": "0.17.16", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.16.tgz", - "integrity": "sha512-ZqftdfS1UlLiH1DnS2u3It7l4Bc3AskKeu+paJSfk7RNOMrOxmeFDhLTMQqMxycP1C3oj8vgkAT6xfAuq7ZPRA==", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.17.16.tgz", + "integrity": "sha512-WhlGeAHNbSdG/I2gqX2RK2gfgSNwyJuCiFHMc8s3GNEMMHUI109+VMBfhVqRb0ZGzEeRiibi8dItR3ws3Lk+cA==", "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/freebsd-x64": { - "version": "0.17.16", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.17.16.tgz", - "integrity": "sha512-rHV6zNWW1tjgsu0dKQTX9L0ByiJHHLvQKrWtnz8r0YYJI27FU3Xu48gpK2IBj1uCSYhJ+pEk6Y0Um7U3rIvV8g==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-arm": { - "version": "0.17.16", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.17.16.tgz", - "integrity": "sha512-n4O8oVxbn7nl4+m+ISb0a68/lcJClIbaGAoXwqeubj/D1/oMMuaAXmJVfFlRjJLu/ZvHkxoiFJnmbfp4n8cdSw==", - "cpu": [ - "arm" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-arm64": { - "version": "0.17.16", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.17.16.tgz", - "integrity": "sha512-8yoZhGkU6aHu38WpaM4HrRLTFc7/VVD9Q2SvPcmIQIipQt2I/GMTZNdEHXoypbbGao5kggLcxg0iBKjo0SQYKA==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-ia32": { - "version": "0.17.16", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.17.16.tgz", - "integrity": "sha512-9ZBjlkdaVYxPNO8a7OmzDbOH9FMQ1a58j7Xb21UfRU29KcEEU3VTHk+Cvrft/BNv0gpWJMiiZ/f4w0TqSP0gLA==", - "cpu": [ - "ia32" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-loong64": { - "version": "0.17.16", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.17.16.tgz", - "integrity": "sha512-TIZTRojVBBzdgChY3UOG7BlPhqJz08AL7jdgeeu+kiObWMFzGnQD7BgBBkWRwOtKR1i2TNlO7YK6m4zxVjjPRQ==", - "cpu": [ - "loong64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-mips64el": { - "version": "0.17.16", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.17.16.tgz", - "integrity": "sha512-UPeRuFKCCJYpBbIdczKyHLAIU31GEm0dZl1eMrdYeXDH+SJZh/i+2cAmD3A1Wip9pIc5Sc6Kc5cFUrPXtR0XHA==", - "cpu": [ - "mips64el" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-ppc64": { - "version": "0.17.16", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.17.16.tgz", - "integrity": "sha512-io6yShgIEgVUhExJejJ21xvO5QtrbiSeI7vYUnr7l+v/O9t6IowyhdiYnyivX2X5ysOVHAuyHW+Wyi7DNhdw6Q==", - "cpu": [ - "ppc64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-riscv64": { - "version": "0.17.16", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.17.16.tgz", - "integrity": "sha512-WhlGeAHNbSdG/I2gqX2RK2gfgSNwyJuCiFHMc8s3GNEMMHUI109+VMBfhVqRb0ZGzEeRiibi8dItR3ws3Lk+cA==", - "cpu": [ - "riscv64" + "riscv64" ], "optional": true, "os": [ @@ -1706,739 +1305,1299 @@ "@hapi/topo": "3.x.x" } }, - "node_modules/@hapi/topo": { - "version": "3.1.6", + "node_modules/@hapi/topo": { + "version": "3.1.6", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@hapi/hoek": "^8.3.0" + } + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.11.8", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanwhocodes/object-schema": "^1.2.1", + "debug": "^4.1.1", + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "1.2.1", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dev": true, + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true + }, + "node_modules/@isaacs/cliui/node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@isaacs/cliui/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/@isaacs/ts-node-temp-fork-for-pr-2009": { + "version": "10.9.1", + "resolved": "https://registry.npmjs.org/@isaacs/ts-node-temp-fork-for-pr-2009/-/ts-node-temp-fork-for-pr-2009-10.9.1.tgz", + "integrity": "sha512-MY4rUonz835NsTbd4dcgKZvZFYX9IkLnYFZV9M7GQV8t39fawafLin/Qw6VXD4yfMs4HcBq8P3ddeU0QHMH1YQ==", + "dev": true, + "dependencies": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node14": "*", + "@tsconfig/node16": "*", + "@tsconfig/node18": "*", + "@tsconfig/node20": "*", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-esm": "dist/bin-esm.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js" + }, + "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=4.2" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } + } + }, + "node_modules/@istanbuljs/schema": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", + "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.14", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.20", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz", + "integrity": "sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@kwsites/file-exists": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@kwsites/file-exists/-/file-exists-1.1.1.tgz", + "integrity": "sha512-m9/5YGR18lIwxSFDwfE3oA7bWuq9kdau6ugN4H2rJeyhFQZcG9AgSHkQtSD15a8WvTgfz9aikZMrKPHvbpqFiw==", + "dev": true, + "dependencies": { + "debug": "^4.1.1" + } + }, + "node_modules/@kwsites/promise-deferred": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@kwsites/promise-deferred/-/promise-deferred-1.1.1.tgz", + "integrity": "sha512-GaHYm+c0O9MjZRu0ongGBRbinu8gVAMd2UZjji6jVmqKtZluZnptXGWhz1E8j8D2HJ3f/yMxKAUC0b+57wncIw==", + "dev": true + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@npmcli/agent": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@npmcli/agent/-/agent-2.2.0.tgz", + "integrity": "sha512-2yThA1Es98orMkpSLVqlDZAMPK3jHJhifP2gnNUdk1754uZ8yI5c+ulCoVG+WlntQA6MzhrURMXjSd9Z7dJ2/Q==", + "dev": true, + "dependencies": { + "agent-base": "^7.1.0", + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.1", + "lru-cache": "^10.0.1", + "socks-proxy-agent": "^8.0.1" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/agent/node_modules/agent-base": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.0.tgz", + "integrity": "sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg==", + "dev": true, + "dependencies": { + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/@npmcli/agent/node_modules/https-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.2.tgz", + "integrity": "sha512-NmLNjm6ucYwtcUmL7JQC1ZQ57LmHP4lT15FQ8D61nak1rO6DH+fz5qNK2Ap5UN4ZapYICE3/0KodcLYSPsPbaA==", + "dev": true, + "dependencies": { + "agent-base": "^7.0.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/@npmcli/fs": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-3.1.0.tgz", + "integrity": "sha512-7kZUAaLscfgbwBQRbvdMYaZOWyMEcPTH/tJjnyAWJ/dvvs9Ef+CERx/qJb9GExJpl1qipaDGn7KqHnFGGixd0w==", + "dev": true, + "dependencies": { + "semver": "^7.3.5" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/git": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/@npmcli/git/-/git-5.0.3.tgz", + "integrity": "sha512-UZp9NwK+AynTrKvHn5k3KviW/hA5eENmFsu3iAPe7sWRt0lFUdsY/wXIYjpDFe7cdSNwOIzbObfwgt6eL5/2zw==", + "dev": true, + "dependencies": { + "@npmcli/promise-spawn": "^7.0.0", + "lru-cache": "^10.0.1", + "npm-pick-manifest": "^9.0.0", + "proc-log": "^3.0.0", + "promise-inflight": "^1.0.1", + "promise-retry": "^2.0.1", + "semver": "^7.3.5", + "which": "^4.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/git/node_modules/isexe": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", + "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", + "dev": true, + "engines": { + "node": ">=16" + } + }, + "node_modules/@npmcli/git/node_modules/which": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", + "integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==", + "dev": true, + "dependencies": { + "isexe": "^3.1.1" + }, + "bin": { + "node-which": "bin/which.js" + }, + "engines": { + "node": "^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/installed-package-contents": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@npmcli/installed-package-contents/-/installed-package-contents-2.0.2.tgz", + "integrity": "sha512-xACzLPhnfD51GKvTOOuNX2/V4G4mz9/1I2MfDoye9kBM3RYe5g2YbscsaGoTlaWqkxeiapBWyseULVKpSVHtKQ==", + "dev": true, + "dependencies": { + "npm-bundled": "^3.0.0", + "npm-normalize-package-bin": "^3.0.0" + }, + "bin": { + "installed-package-contents": "lib/index.js" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/node-gyp": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@npmcli/node-gyp/-/node-gyp-3.0.0.tgz", + "integrity": "sha512-gp8pRXC2oOxu0DUE1/M3bYtb1b3/DbJ5aM113+XJBgfXdussRAsX0YOrOhdd8WvnAR6auDBvJomGAkLKA5ydxA==", + "dev": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/promise-spawn": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@npmcli/promise-spawn/-/promise-spawn-7.0.0.tgz", + "integrity": "sha512-wBqcGsMELZna0jDblGd7UXgOby45TQaMWmbFwWX+SEotk4HV6zG2t6rT9siyLhPk4P6YYqgfL1UO8nMWDBVJXQ==", + "dev": true, + "dependencies": { + "which": "^4.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/promise-spawn/node_modules/isexe": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", + "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", + "dev": true, + "engines": { + "node": ">=16" + } + }, + "node_modules/@npmcli/promise-spawn/node_modules/which": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", + "integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==", + "dev": true, + "dependencies": { + "isexe": "^3.1.1" + }, + "bin": { + "node-which": "bin/which.js" + }, + "engines": { + "node": "^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/run-script": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@npmcli/run-script/-/run-script-7.0.2.tgz", + "integrity": "sha512-Omu0rpA8WXvcGeY6DDzyRoY1i5DkCBkzyJ+m2u7PD6quzb0TvSqdIPOkTn8ZBOj7LbbcbMfZ3c5skwSu6m8y2w==", + "dev": true, + "dependencies": { + "@npmcli/node-gyp": "^3.0.0", + "@npmcli/promise-spawn": "^7.0.0", + "node-gyp": "^10.0.0", + "read-package-json-fast": "^3.0.0", + "which": "^4.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/run-script/node_modules/isexe": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", + "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", + "dev": true, + "engines": { + "node": ">=16" + } + }, + "node_modules/@npmcli/run-script/node_modules/which": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", + "integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==", + "dev": true, + "dependencies": { + "isexe": "^3.1.1" + }, + "bin": { + "node-which": "bin/which.js" + }, + "engines": { + "node": "^16.13.0 || >=18.0.0" + } + }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "dev": true, + "optional": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@serverless/dashboard-plugin": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@serverless/dashboard-plugin/-/dashboard-plugin-7.1.0.tgz", + "integrity": "sha512-mAiTU2ERsDHdCrXJa/tihh/r+8ZwSuYYBqln3SkwuBD/49ct9QrK7S00cpiqFoY/geMFlHpOkriGzCPz6UP/rw==", + "dev": true, + "dependencies": { + "@aws-sdk/client-cloudformation": "^3.410.0", + "@aws-sdk/client-sts": "^3.410.0", + "@serverless/event-mocks": "^1.1.1", + "@serverless/platform-client": "^4.4.0", + "@serverless/utils": "^6.14.0", + "child-process-ext": "^3.0.1", + "chokidar": "^3.5.3", + "flat": "^5.0.2", + "fs-extra": "^9.1.0", + "js-yaml": "^4.1.0", + "jszip": "^3.10.1", + "lodash": "^4.17.21", + "memoizee": "^0.4.15", + "ncjsm": "^4.3.2", + "node-dir": "^0.1.17", + "node-fetch": "^2.6.8", + "open": "^7.4.2", + "semver": "^7.3.8", + "simple-git": "^3.16.0", + "timers-ext": "^0.1.7", + "type": "^2.7.2", + "uuid": "^8.3.2", + "yamljs": "^0.3.0" + }, + "engines": { + "node": ">=12.0" + } + }, + "node_modules/@serverless/dashboard-plugin/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/@serverless/dashboard-plugin/node_modules/child-process-ext": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/child-process-ext/-/child-process-ext-3.0.2.tgz", + "integrity": "sha512-oBePsLbQpTJFxzwyCvs9yWWF0OEM6vGGepHwt1stqmX7QQqOuDc8j2ywdvAs9Tvi44TT7d9ackqhR4Q10l1u8w==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.3", + "es5-ext": "^0.10.62", + "log": "^6.3.1", + "split2": "^3.2.2", + "stream-promise": "^3.2.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/@serverless/dashboard-plugin/node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/@serverless/dashboard-plugin/node_modules/open": { + "version": "7.4.2", + "resolved": "https://registry.npmjs.org/open/-/open-7.4.2.tgz", + "integrity": "sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q==", + "dev": true, + "dependencies": { + "is-docker": "^2.0.0", + "is-wsl": "^2.1.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@serverless/event-mocks": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@serverless/event-mocks/-/event-mocks-1.1.1.tgz", + "integrity": "sha512-YAV5V/y+XIOfd+HEVeXfPWZb8C6QLruFk9tBivoX2roQLWVq145s4uxf8D0QioCueuRzkukHUS4JIj+KVoS34A==", "dev": true, - "license": "BSD-3-Clause", "dependencies": { - "@hapi/hoek": "^8.3.0" + "@types/lodash": "^4.14.123", + "lodash": "^4.17.11" } }, - "node_modules/@humanwhocodes/config-array": { - "version": "0.11.8", + "node_modules/@serverless/platform-client": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@serverless/platform-client/-/platform-client-4.4.0.tgz", + "integrity": "sha512-urL7SNefRqC2EOFDcpvm8fyn/06B5yXWneKpyGw7ylGt0Qr9JHZCB9TiUeTkIpPUNz0jTvKUaJ2+M/JNEiaVIA==", "dev": true, - "license": "Apache-2.0", "dependencies": { - "@humanwhocodes/object-schema": "^1.2.1", - "debug": "^4.1.1", - "minimatch": "^3.0.5" + "adm-zip": "^0.5.5", + "archiver": "^5.3.0", + "axios": "^0.21.1", + "fast-glob": "^3.2.7", + "https-proxy-agent": "^5.0.0", + "ignore": "^5.1.8", + "isomorphic-ws": "^4.0.1", + "js-yaml": "^3.14.1", + "jwt-decode": "^2.2.0", + "minimatch": "^3.0.4", + "querystring": "^0.2.1", + "run-parallel-limit": "^1.1.0", + "throat": "^5.0.0", + "traverse": "^0.6.6", + "ws": "^7.5.3" }, "engines": { - "node": ">=10.10.0" + "node": ">=10.0" } }, - "node_modules/@humanwhocodes/module-importer": { - "version": "1.0.1", + "node_modules/@serverless/platform-client/node_modules/axios": { + "version": "0.21.4", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz", + "integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==", "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=12.22" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" + "dependencies": { + "follow-redirects": "^1.14.0" } }, - "node_modules/@humanwhocodes/object-schema": { - "version": "1.2.1", - "dev": true, - "license": "BSD-3-Clause" - }, - "node_modules/@isaacs/cliui": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", - "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "node_modules/@serverless/utils": { + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/@serverless/utils/-/utils-6.15.0.tgz", + "integrity": "sha512-7eDbqKv/OBd11jjdZjUwFGN8sHWkeUqLeHXHQxQ1azja2IM7WIH+z/aLgzR6LhB3/MINNwtjesDpjGqTMj2JKQ==", "dev": true, "dependencies": { - "string-width": "^5.1.2", - "string-width-cjs": "npm:string-width@^4.2.0", - "strip-ansi": "^7.0.1", - "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", - "wrap-ansi": "^8.1.0", - "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + "archive-type": "^4.0.0", + "chalk": "^4.1.2", + "ci-info": "^3.8.0", + "cli-progress-footer": "^2.3.2", + "content-disposition": "^0.5.4", + "d": "^1.0.1", + "decompress": "^4.2.1", + "event-emitter": "^0.3.5", + "ext": "^1.7.0", + "ext-name": "^5.0.0", + "file-type": "^16.5.4", + "filenamify": "^4.3.0", + "get-stream": "^6.0.1", + "got": "^11.8.6", + "inquirer": "^8.2.5", + "js-yaml": "^4.1.0", + "jwt-decode": "^3.1.2", + "lodash": "^4.17.21", + "log": "^6.3.1", + "log-node": "^8.0.3", + "make-dir": "^4.0.0", + "memoizee": "^0.4.15", + "ms": "^2.1.3", + "ncjsm": "^4.3.2", + "node-fetch": "^2.6.11", + "open": "^8.4.2", + "p-event": "^4.2.0", + "supports-color": "^8.1.1", + "timers-ext": "^0.1.7", + "type": "^2.7.2", + "uni-global": "^1.0.0", + "uuid": "^8.3.2", + "write-file-atomic": "^4.0.2" }, "engines": { - "node": ">=12" + "node": ">=12.0" } }, - "node_modules/@isaacs/cliui/node_modules/ansi-regex": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", - "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "node_modules/@serverless/utils/node_modules/argparse": { + "version": "2.0.1", "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } + "license": "Python-2.0" }, - "node_modules/@isaacs/cliui/node_modules/ansi-styles": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", - "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "node_modules/@serverless/utils/node_modules/js-yaml": { + "version": "4.1.0", "dev": true, - "engines": { - "node": ">=12" + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "bin": { + "js-yaml": "bin/js-yaml.js" } }, - "node_modules/@isaacs/cliui/node_modules/emoji-regex": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "node_modules/@serverless/utils/node_modules/jwt-decode": { + "version": "3.1.2", + "dev": true, + "license": "MIT" + }, + "node_modules/@serverless/utils/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "dev": true }, - "node_modules/@isaacs/cliui/node_modules/string-width": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", - "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "node_modules/@serverless/utils/node_modules/supports-color": { + "version": "8.1.1", "dev": true, + "license": "MIT", "dependencies": { - "eastasianwidth": "^0.2.0", - "emoji-regex": "^9.2.2", - "strip-ansi": "^7.0.1" + "has-flag": "^4.0.0" }, "engines": { - "node": ">=12" + "node": ">=10" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/chalk/supports-color?sponsor=1" } }, - "node_modules/@isaacs/cliui/node_modules/strip-ansi": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", - "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "node_modules/@serverless/utils/node_modules/write-file-atomic": { + "version": "4.0.2", "dev": true, + "license": "ISC", "dependencies": { - "ansi-regex": "^6.0.1" + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.7" }, "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", - "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "node_modules/@sigstore/bundle": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@sigstore/bundle/-/bundle-2.1.0.tgz", + "integrity": "sha512-89uOo6yh/oxaU8AeOUnVrTdVMcGk9Q1hJa7Hkvalc6G3Z3CupWk4Xe9djSgJm9fMkH69s0P0cVHUoKSOemLdng==", "dev": true, "dependencies": { - "ansi-styles": "^6.1.0", - "string-width": "^5.0.1", - "strip-ansi": "^7.0.1" + "@sigstore/protobuf-specs": "^0.2.1" }, "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + "node": "^16.14.0 || >=18.0.0" } }, - "node_modules/@isaacs/ts-node-temp-fork-for-pr-2009": { - "version": "10.9.1", - "resolved": "https://registry.npmjs.org/@isaacs/ts-node-temp-fork-for-pr-2009/-/ts-node-temp-fork-for-pr-2009-10.9.1.tgz", - "integrity": "sha512-MY4rUonz835NsTbd4dcgKZvZFYX9IkLnYFZV9M7GQV8t39fawafLin/Qw6VXD4yfMs4HcBq8P3ddeU0QHMH1YQ==", + "node_modules/@sigstore/protobuf-specs": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/@sigstore/protobuf-specs/-/protobuf-specs-0.2.1.tgz", + "integrity": "sha512-XTWVxnWJu+c1oCshMLwnKvz8ZQJJDVOlciMfgpJBQbThVjKTCG8dwyhgLngBD2KN0ap9F/gOV8rFDEx8uh7R2A==", + "dev": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@sigstore/sign": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@sigstore/sign/-/sign-2.2.0.tgz", + "integrity": "sha512-AAbmnEHDQv6CSfrWA5wXslGtzLPtAtHZleKOgxdQYvx/s76Fk6T6ZVt7w2IGV9j1UrFeBocTTQxaXG2oRrDhYA==", "dev": true, "dependencies": { - "@cspotcode/source-map-support": "^0.8.0", - "@tsconfig/node14": "*", - "@tsconfig/node16": "*", - "@tsconfig/node18": "*", - "@tsconfig/node20": "*", - "acorn": "^8.4.1", - "acorn-walk": "^8.1.1", - "arg": "^4.1.0", - "diff": "^4.0.1", - "make-error": "^1.1.1", - "v8-compile-cache-lib": "^3.0.1" - }, - "bin": { - "ts-node": "dist/bin.js", - "ts-node-cwd": "dist/bin-cwd.js", - "ts-node-esm": "dist/bin-esm.js", - "ts-node-script": "dist/bin-script.js", - "ts-node-transpile-only": "dist/bin-transpile.js" - }, - "peerDependencies": { - "@swc/core": ">=1.2.50", - "@swc/wasm": ">=1.2.50", - "@types/node": "*", - "typescript": ">=4.2" + "@sigstore/bundle": "^2.1.0", + "@sigstore/protobuf-specs": "^0.2.1", + "make-fetch-happen": "^13.0.0" }, - "peerDependenciesMeta": { - "@swc/core": { - "optional": true - }, - "@swc/wasm": { - "optional": true - } + "engines": { + "node": "^16.14.0 || >=18.0.0" } }, - "node_modules/@istanbuljs/schema": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", - "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", + "node_modules/@sigstore/tuf": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@sigstore/tuf/-/tuf-2.2.0.tgz", + "integrity": "sha512-KKATZ5orWfqd9ZG6MN8PtCIx4eevWSuGRKQvofnWXRpyMyUEpmrzg5M5BrCpjM+NfZ0RbNGOh5tCz/P2uoRqOA==", "dev": true, + "dependencies": { + "@sigstore/protobuf-specs": "^0.2.1", + "tuf-js": "^2.1.0" + }, "engines": { - "node": ">=8" + "node": "^16.14.0 || >=18.0.0" } }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.0", + "node_modules/@sindresorhus/is": { + "version": "4.6.0", "dev": true, "license": "MIT", "engines": { - "node": ">=6.0.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/is?sponsor=1" } }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.14", - "dev": true, - "license": "MIT" - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.20", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz", - "integrity": "sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==", + "node_modules/@smithy/abort-controller": { + "version": "2.0.13", + "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-2.0.13.tgz", + "integrity": "sha512-eeOPD+GF9BzF/Mjy3PICLePx4l0f3rG/nQegQHRLTloN5p1lSJJNZsyn+FzDnW8P2AduragZqJdtKNCxXozB1Q==", "dev": true, "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" + "@smithy/types": "^2.5.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" } }, - "node_modules/@kwsites/file-exists": { - "version": "1.1.1", + "node_modules/@smithy/config-resolver": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/@smithy/config-resolver/-/config-resolver-2.0.18.tgz", + "integrity": "sha512-761sJSgNbvsqcsKW6/WZbrZr4H+0Vp/QKKqwyrxCPwD8BsiPEXNHyYnqNgaeK9xRWYswjon0Uxbpe3DWQo0j/g==", "dev": true, - "license": "MIT", "dependencies": { - "debug": "^4.1.1" + "@smithy/node-config-provider": "^2.1.5", + "@smithy/types": "^2.5.0", + "@smithy/util-config-provider": "^2.0.0", + "@smithy/util-middleware": "^2.0.6", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" } }, - "node_modules/@kwsites/promise-deferred": { - "version": "1.1.1", - "dev": true, - "license": "MIT" - }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", + "node_modules/@smithy/credential-provider-imds": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-2.1.1.tgz", + "integrity": "sha512-gw5G3FjWC6sNz8zpOJgPpH5HGKrpoVFQpToNAwLwJVyI/LJ2jDJRjSKEsM6XI25aRpYjMSE/Qptxx305gN1vHw==", "dev": true, - "license": "MIT", "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" + "@smithy/node-config-provider": "^2.1.5", + "@smithy/property-provider": "^2.0.14", + "@smithy/types": "^2.5.0", + "@smithy/url-parser": "^2.0.13", + "tslib": "^2.5.0" }, "engines": { - "node": ">= 8" + "node": ">=14.0.0" } }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", + "node_modules/@smithy/eventstream-codec": { + "version": "2.0.13", + "resolved": "https://registry.npmjs.org/@smithy/eventstream-codec/-/eventstream-codec-2.0.13.tgz", + "integrity": "sha512-CExbelIYp+DxAHG8RIs0l9QL7ElqhG4ym9BNoSpkPa4ptBQfzJdep3LbOSVJIE2VUdBAeObdeL6EDB3Jo85n3g==", "dev": true, - "license": "MIT", - "engines": { - "node": ">= 8" + "dependencies": { + "@aws-crypto/crc32": "3.0.0", + "@smithy/types": "^2.5.0", + "@smithy/util-hex-encoding": "^2.0.0", + "tslib": "^2.5.0" } }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", + "node_modules/@smithy/fetch-http-handler": { + "version": "2.2.6", + "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-2.2.6.tgz", + "integrity": "sha512-PStY3XO1Ksjwn3wMKye5U6m6zxXpXrXZYqLy/IeCbh3nM9QB3Jgw/B0PUSLUWKdXg4U8qgEu300e3ZoBvZLsDg==", "dev": true, - "license": "MIT", "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, - "engines": { - "node": ">= 8" + "@smithy/protocol-http": "^3.0.9", + "@smithy/querystring-builder": "^2.0.13", + "@smithy/types": "^2.5.0", + "@smithy/util-base64": "^2.0.1", + "tslib": "^2.5.0" } }, - "node_modules/@npmcli/agent": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@npmcli/agent/-/agent-2.2.0.tgz", - "integrity": "sha512-2yThA1Es98orMkpSLVqlDZAMPK3jHJhifP2gnNUdk1754uZ8yI5c+ulCoVG+WlntQA6MzhrURMXjSd9Z7dJ2/Q==", + "node_modules/@smithy/hash-node": { + "version": "2.0.15", + "resolved": "https://registry.npmjs.org/@smithy/hash-node/-/hash-node-2.0.15.tgz", + "integrity": "sha512-t/qjEJZu/G46A22PAk1k/IiJZT4ncRkG5GOCNWN9HPPy5rCcSZUbh7gwp7CGKgJJ7ATMMg+0Td7i9o1lQTwOfQ==", "dev": true, "dependencies": { - "agent-base": "^7.1.0", - "http-proxy-agent": "^7.0.0", - "https-proxy-agent": "^7.0.1", - "lru-cache": "^10.0.1", - "socks-proxy-agent": "^8.0.1" + "@smithy/types": "^2.5.0", + "@smithy/util-buffer-from": "^2.0.0", + "@smithy/util-utf8": "^2.0.2", + "tslib": "^2.5.0" }, "engines": { - "node": "^16.14.0 || >=18.0.0" + "node": ">=14.0.0" } }, - "node_modules/@npmcli/agent/node_modules/agent-base": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.0.tgz", - "integrity": "sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg==", + "node_modules/@smithy/invalid-dependency": { + "version": "2.0.13", + "resolved": "https://registry.npmjs.org/@smithy/invalid-dependency/-/invalid-dependency-2.0.13.tgz", + "integrity": "sha512-XsGYhVhvEikX1Yz0kyIoLssJf2Rs6E0U2w2YuKdT4jSra5A/g8V2oLROC1s56NldbgnpesTYB2z55KCHHbKyjw==", "dev": true, "dependencies": { - "debug": "^4.3.4" - }, - "engines": { - "node": ">= 14" + "@smithy/types": "^2.5.0", + "tslib": "^2.5.0" } }, - "node_modules/@npmcli/agent/node_modules/https-proxy-agent": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.2.tgz", - "integrity": "sha512-NmLNjm6ucYwtcUmL7JQC1ZQ57LmHP4lT15FQ8D61nak1rO6DH+fz5qNK2Ap5UN4ZapYICE3/0KodcLYSPsPbaA==", + "node_modules/@smithy/is-array-buffer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-2.0.0.tgz", + "integrity": "sha512-z3PjFjMyZNI98JFRJi/U0nGoLWMSJlDjAW4QUX2WNZLas5C0CmVV6LJ01JI0k90l7FvpmixjWxPFmENSClQ7ug==", "dev": true, "dependencies": { - "agent-base": "^7.0.2", - "debug": "4" + "tslib": "^2.5.0" }, "engines": { - "node": ">= 14" + "node": ">=14.0.0" } }, - "node_modules/@npmcli/fs": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-3.1.0.tgz", - "integrity": "sha512-7kZUAaLscfgbwBQRbvdMYaZOWyMEcPTH/tJjnyAWJ/dvvs9Ef+CERx/qJb9GExJpl1qipaDGn7KqHnFGGixd0w==", + "node_modules/@smithy/middleware-content-length": { + "version": "2.0.15", + "resolved": "https://registry.npmjs.org/@smithy/middleware-content-length/-/middleware-content-length-2.0.15.tgz", + "integrity": "sha512-xH4kRBw01gJgWiU+/mNTrnyFXeozpZHw39gLb3JKGsFDVmSrJZ8/tRqu27tU/ki1gKkxr2wApu+dEYjI3QwV1Q==", "dev": true, "dependencies": { - "semver": "^7.3.5" + "@smithy/protocol-http": "^3.0.9", + "@smithy/types": "^2.5.0", + "tslib": "^2.5.0" }, "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": ">=14.0.0" } }, - "node_modules/@npmcli/git": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/@npmcli/git/-/git-5.0.3.tgz", - "integrity": "sha512-UZp9NwK+AynTrKvHn5k3KviW/hA5eENmFsu3iAPe7sWRt0lFUdsY/wXIYjpDFe7cdSNwOIzbObfwgt6eL5/2zw==", + "node_modules/@smithy/middleware-endpoint": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-2.2.0.tgz", + "integrity": "sha512-tddRmaig5URk2106PVMiNX6mc5BnKIKajHHDxb7K0J5MLdcuQluHMGnjkv18iY9s9O0tF+gAcPd/pDXA5L9DZw==", "dev": true, "dependencies": { - "@npmcli/promise-spawn": "^7.0.0", - "lru-cache": "^10.0.1", - "npm-pick-manifest": "^9.0.0", - "proc-log": "^3.0.0", - "promise-inflight": "^1.0.1", - "promise-retry": "^2.0.1", - "semver": "^7.3.5", - "which": "^4.0.0" + "@smithy/middleware-serde": "^2.0.13", + "@smithy/node-config-provider": "^2.1.5", + "@smithy/shared-ini-file-loader": "^2.2.4", + "@smithy/types": "^2.5.0", + "@smithy/url-parser": "^2.0.13", + "@smithy/util-middleware": "^2.0.6", + "tslib": "^2.5.0" }, "engines": { - "node": "^16.14.0 || >=18.0.0" + "node": ">=14.0.0" } }, - "node_modules/@npmcli/git/node_modules/isexe": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", - "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", + "node_modules/@smithy/middleware-retry": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-2.0.20.tgz", + "integrity": "sha512-X2yrF/SHDk2WDd8LflRNS955rlzQ9daz9UWSp15wW8KtzoTXg3bhHM78HbK1cjr48/FWERSJKh9AvRUUGlIawg==", "dev": true, + "dependencies": { + "@smithy/node-config-provider": "^2.1.5", + "@smithy/protocol-http": "^3.0.9", + "@smithy/service-error-classification": "^2.0.6", + "@smithy/types": "^2.5.0", + "@smithy/util-middleware": "^2.0.6", + "@smithy/util-retry": "^2.0.6", + "tslib": "^2.5.0", + "uuid": "^8.3.2" + }, "engines": { - "node": ">=16" + "node": ">=14.0.0" } }, - "node_modules/@npmcli/git/node_modules/which": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", - "integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==", + "node_modules/@smithy/middleware-serde": { + "version": "2.0.13", + "resolved": "https://registry.npmjs.org/@smithy/middleware-serde/-/middleware-serde-2.0.13.tgz", + "integrity": "sha512-tBGbeXw+XsE6pPr4UaXOh+UIcXARZeiA8bKJWxk2IjJcD1icVLhBSUQH9myCIZLNNzJIH36SDjUX8Wqk4xJCJg==", "dev": true, "dependencies": { - "isexe": "^3.1.1" - }, - "bin": { - "node-which": "bin/which.js" + "@smithy/types": "^2.5.0", + "tslib": "^2.5.0" }, "engines": { - "node": "^16.13.0 || >=18.0.0" + "node": ">=14.0.0" } }, - "node_modules/@npmcli/installed-package-contents": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@npmcli/installed-package-contents/-/installed-package-contents-2.0.2.tgz", - "integrity": "sha512-xACzLPhnfD51GKvTOOuNX2/V4G4mz9/1I2MfDoye9kBM3RYe5g2YbscsaGoTlaWqkxeiapBWyseULVKpSVHtKQ==", + "node_modules/@smithy/middleware-stack": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@smithy/middleware-stack/-/middleware-stack-2.0.7.tgz", + "integrity": "sha512-L1KLAAWkXbGx1t2jjCI/mDJ2dDNq+rp4/ifr/HcC6FHngxho5O7A5bQLpKHGlkfATH6fUnOEx0VICEVFA4sUzw==", "dev": true, "dependencies": { - "npm-bundled": "^3.0.0", - "npm-normalize-package-bin": "^3.0.0" - }, - "bin": { - "installed-package-contents": "lib/index.js" + "@smithy/types": "^2.5.0", + "tslib": "^2.5.0" }, "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": ">=14.0.0" } }, - "node_modules/@npmcli/node-gyp": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@npmcli/node-gyp/-/node-gyp-3.0.0.tgz", - "integrity": "sha512-gp8pRXC2oOxu0DUE1/M3bYtb1b3/DbJ5aM113+XJBgfXdussRAsX0YOrOhdd8WvnAR6auDBvJomGAkLKA5ydxA==", + "node_modules/@smithy/node-config-provider": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-2.1.5.tgz", + "integrity": "sha512-3Omb5/h4tOCuKRx4p4pkYTvEYRCYoKk52bOYbKUyz/G/8gERbagsN8jFm4FjQubkrcIqQEghTpQaUw6uk+0edw==", "dev": true, + "dependencies": { + "@smithy/property-provider": "^2.0.14", + "@smithy/shared-ini-file-loader": "^2.2.4", + "@smithy/types": "^2.5.0", + "tslib": "^2.5.0" + }, "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": ">=14.0.0" } }, - "node_modules/@npmcli/promise-spawn": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@npmcli/promise-spawn/-/promise-spawn-7.0.0.tgz", - "integrity": "sha512-wBqcGsMELZna0jDblGd7UXgOby45TQaMWmbFwWX+SEotk4HV6zG2t6rT9siyLhPk4P6YYqgfL1UO8nMWDBVJXQ==", + "node_modules/@smithy/node-http-handler": { + "version": "2.1.9", + "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-2.1.9.tgz", + "integrity": "sha512-+K0q3SlNcocmo9OZj+fz67gY4lwhOCvIJxVbo/xH+hfWObvaxrMTx7JEzzXcluK0thnnLz++K3Qe7Z/8MDUreA==", "dev": true, "dependencies": { - "which": "^4.0.0" + "@smithy/abort-controller": "^2.0.13", + "@smithy/protocol-http": "^3.0.9", + "@smithy/querystring-builder": "^2.0.13", + "@smithy/types": "^2.5.0", + "tslib": "^2.5.0" }, "engines": { - "node": "^16.14.0 || >=18.0.0" + "node": ">=14.0.0" } }, - "node_modules/@npmcli/promise-spawn/node_modules/isexe": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", - "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", + "node_modules/@smithy/property-provider": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-2.0.14.tgz", + "integrity": "sha512-k3D2qp9o6imTrLaXRj6GdLYEJr1sXqS99nLhzq8fYmJjSVOeMg/G+1KVAAc7Oxpu71rlZ2f8SSZxcSxkevuR0A==", "dev": true, + "dependencies": { + "@smithy/types": "^2.5.0", + "tslib": "^2.5.0" + }, "engines": { - "node": ">=16" + "node": ">=14.0.0" } }, - "node_modules/@npmcli/promise-spawn/node_modules/which": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", - "integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==", + "node_modules/@smithy/protocol-http": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-3.0.9.tgz", + "integrity": "sha512-U1wl+FhYu4/BC+rjwh1lg2gcJChQhytiNQSggREgQ9G2FzmoK9sACBZvx7thyWMvRyHQTE22mO2d5UM8gMKDBg==", "dev": true, "dependencies": { - "isexe": "^3.1.1" - }, - "bin": { - "node-which": "bin/which.js" + "@smithy/types": "^2.5.0", + "tslib": "^2.5.0" }, "engines": { - "node": "^16.13.0 || >=18.0.0" + "node": ">=14.0.0" } }, - "node_modules/@npmcli/run-script": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@npmcli/run-script/-/run-script-7.0.2.tgz", - "integrity": "sha512-Omu0rpA8WXvcGeY6DDzyRoY1i5DkCBkzyJ+m2u7PD6quzb0TvSqdIPOkTn8ZBOj7LbbcbMfZ3c5skwSu6m8y2w==", + "node_modules/@smithy/querystring-builder": { + "version": "2.0.13", + "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-2.0.13.tgz", + "integrity": "sha512-JhXKwp3JtsFUe96XLHy/nUPEbaXqn6r7xE4sNaH8bxEyytE5q1fwt0ew/Ke6+vIC7gP87HCHgQpJHg1X1jN2Fw==", "dev": true, "dependencies": { - "@npmcli/node-gyp": "^3.0.0", - "@npmcli/promise-spawn": "^7.0.0", - "node-gyp": "^10.0.0", - "read-package-json-fast": "^3.0.0", - "which": "^4.0.0" + "@smithy/types": "^2.5.0", + "@smithy/util-uri-escape": "^2.0.0", + "tslib": "^2.5.0" }, "engines": { - "node": "^16.14.0 || >=18.0.0" + "node": ">=14.0.0" } }, - "node_modules/@npmcli/run-script/node_modules/isexe": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", - "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", + "node_modules/@smithy/querystring-parser": { + "version": "2.0.13", + "resolved": "https://registry.npmjs.org/@smithy/querystring-parser/-/querystring-parser-2.0.13.tgz", + "integrity": "sha512-TEiT6o8CPZVxJ44Rly/rrsATTQsE+b/nyBVzsYn2sa75xAaZcurNxsFd8z1haoUysONiyex24JMHoJY6iCfLdA==", "dev": true, + "dependencies": { + "@smithy/types": "^2.5.0", + "tslib": "^2.5.0" + }, "engines": { - "node": ">=16" + "node": ">=14.0.0" } }, - "node_modules/@npmcli/run-script/node_modules/which": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", - "integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==", + "node_modules/@smithy/service-error-classification": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@smithy/service-error-classification/-/service-error-classification-2.0.6.tgz", + "integrity": "sha512-fCQ36frtYra2fqY2/DV8+3/z2d0VB/1D1hXbjRcM5wkxTToxq6xHbIY/NGGY6v4carskMyG8FHACxgxturJ9Pg==", "dev": true, "dependencies": { - "isexe": "^3.1.1" - }, - "bin": { - "node-which": "bin/which.js" + "@smithy/types": "^2.5.0" }, "engines": { - "node": "^16.13.0 || >=18.0.0" + "node": ">=14.0.0" } }, - "node_modules/@pkgjs/parseargs": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", - "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "node_modules/@smithy/shared-ini-file-loader": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-2.2.4.tgz", + "integrity": "sha512-9dRknGgvYlRIsoTcmMJXuoR/3ekhGwhRq4un3ns2/byre4Ql5hyUN4iS0x8eITohjU90YOnUCsbRwZRvCkbRfw==", "dev": true, - "optional": true, + "dependencies": { + "@smithy/types": "^2.5.0", + "tslib": "^2.5.0" + }, "engines": { - "node": ">=14" + "node": ">=14.0.0" } }, - "node_modules/@serverless/dashboard-plugin": { - "version": "6.2.3", + "node_modules/@smithy/signature-v4": { + "version": "2.0.15", + "resolved": "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-2.0.15.tgz", + "integrity": "sha512-SRTEJSEhQYVlBKIIdZ9SZpqW+KFqxqcNnEcBX+8xkDdWx+DItme9VcCDkdN32yTIrICC+irUufnUdV7mmHPjoA==", "dev": true, - "license": "MIT", "dependencies": { - "@serverless/event-mocks": "^1.1.1", - "@serverless/platform-client": "^4.3.2", - "@serverless/utils": "^6.8.2", - "child-process-ext": "^2.1.1", - "chokidar": "^3.5.3", - "flat": "^5.0.2", - "fs-extra": "^9.1.0", - "js-yaml": "^4.1.0", - "jszip": "^3.10.1", - "lodash": "^4.17.21", - "memoizee": "^0.4.15", - "ncjsm": "^4.3.2", - "node-dir": "^0.1.17", - "node-fetch": "^2.6.8", - "open": "^7.4.2", - "semver": "^7.3.8", - "simple-git": "^3.16.0", - "type": "^2.7.2", - "uuid": "^8.3.2", - "yamljs": "^0.3.0" + "@smithy/eventstream-codec": "^2.0.13", + "@smithy/is-array-buffer": "^2.0.0", + "@smithy/types": "^2.5.0", + "@smithy/util-hex-encoding": "^2.0.0", + "@smithy/util-middleware": "^2.0.6", + "@smithy/util-uri-escape": "^2.0.0", + "@smithy/util-utf8": "^2.0.2", + "tslib": "^2.5.0" }, "engines": { - "node": ">=12.0" - } - }, - "node_modules/@serverless/dashboard-plugin/node_modules/argparse": { - "version": "2.0.1", - "dev": true, - "license": "Python-2.0" + "node": ">=14.0.0" + } }, - "node_modules/@serverless/dashboard-plugin/node_modules/js-yaml": { - "version": "4.1.0", + "node_modules/@smithy/smithy-client": { + "version": "2.1.15", + "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-2.1.15.tgz", + "integrity": "sha512-rngZcQu7Jvs9UbHihK1EI67RMPuzkc3CJmu4MBgB7D7yBnMGuFR86tq5rqHfL2gAkNnMelBN/8kzQVvZjNKefQ==", "dev": true, - "license": "MIT", "dependencies": { - "argparse": "^2.0.1" + "@smithy/middleware-stack": "^2.0.7", + "@smithy/types": "^2.5.0", + "@smithy/util-stream": "^2.0.20", + "tslib": "^2.5.0" }, - "bin": { - "js-yaml": "bin/js-yaml.js" + "engines": { + "node": ">=14.0.0" } }, - "node_modules/@serverless/dashboard-plugin/node_modules/open": { - "version": "7.4.2", + "node_modules/@smithy/types": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-2.5.0.tgz", + "integrity": "sha512-/a31lYofrMBkJb3BuPlYJTMKDj0hUmKUP6JFZQu6YVuQVoAjubiY0A52U9S0Uysd33n/djexCUSNJ+G9bf3/aA==", "dev": true, - "license": "MIT", "dependencies": { - "is-docker": "^2.0.0", - "is-wsl": "^2.1.1" + "tslib": "^2.5.0" }, "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=14.0.0" } }, - "node_modules/@serverless/event-mocks": { - "version": "1.1.1", + "node_modules/@smithy/url-parser": { + "version": "2.0.13", + "resolved": "https://registry.npmjs.org/@smithy/url-parser/-/url-parser-2.0.13.tgz", + "integrity": "sha512-okWx2P/d9jcTsZWTVNnRMpFOE7fMkzloSFyM53fA7nLKJQObxM2T4JlZ5KitKKuXq7pxon9J6SF2kCwtdflIrA==", "dev": true, - "license": "Apache-2.0", "dependencies": { - "@types/lodash": "^4.14.123", - "lodash": "^4.17.11" + "@smithy/querystring-parser": "^2.0.13", + "@smithy/types": "^2.5.0", + "tslib": "^2.5.0" } }, - "node_modules/@serverless/platform-client": { - "version": "4.3.2", + "node_modules/@smithy/util-base64": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@smithy/util-base64/-/util-base64-2.0.1.tgz", + "integrity": "sha512-DlI6XFYDMsIVN+GH9JtcRp3j02JEVuWIn/QOZisVzpIAprdsxGveFed0bjbMRCqmIFe8uetn5rxzNrBtIGrPIQ==", "dev": true, - "license": "ISC", "dependencies": { - "adm-zip": "^0.5.5", - "archiver": "^5.3.0", - "axios": "^0.21.1", - "fast-glob": "^3.2.7", - "https-proxy-agent": "^5.0.0", - "ignore": "^5.1.8", - "isomorphic-ws": "^4.0.1", - "js-yaml": "^3.14.1", - "jwt-decode": "^2.2.0", - "minimatch": "^3.0.4", - "querystring": "^0.2.1", - "run-parallel-limit": "^1.1.0", - "throat": "^5.0.0", - "traverse": "^0.6.6", - "ws": "^7.5.3" + "@smithy/util-buffer-from": "^2.0.0", + "tslib": "^2.5.0" }, "engines": { - "node": ">=10.0" + "node": ">=14.0.0" } }, - "node_modules/@serverless/platform-client/node_modules/axios": { - "version": "0.21.4", + "node_modules/@smithy/util-body-length-browser": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-body-length-browser/-/util-body-length-browser-2.0.0.tgz", + "integrity": "sha512-JdDuS4ircJt+FDnaQj88TzZY3+njZ6O+D3uakS32f2VNnDo3vyEuNdBOh/oFd8Df1zSZOuH1HEChk2AOYDezZg==", "dev": true, - "license": "MIT", "dependencies": { - "follow-redirects": "^1.14.0" + "tslib": "^2.5.0" } }, - "node_modules/@serverless/platform-client/node_modules/throat": { - "version": "5.0.0", - "dev": true, - "license": "MIT" - }, - "node_modules/@serverless/utils": { - "version": "6.8.2", + "node_modules/@smithy/util-body-length-node": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@smithy/util-body-length-node/-/util-body-length-node-2.1.0.tgz", + "integrity": "sha512-/li0/kj/y3fQ3vyzn36NTLGmUwAICb7Jbe/CsWCktW363gh1MOcpEcSO3mJ344Gv2dqz8YJCLQpb6hju/0qOWw==", "dev": true, - "license": "MIT", "dependencies": { - "archive-type": "^4.0.0", - "chalk": "^4.1.2", - "ci-info": "^3.5.0", - "cli-progress-footer": "^2.3.2", - "content-disposition": "^0.5.4", - "d": "^1.0.1", - "decompress": "^4.2.1", - "event-emitter": "^0.3.5", - "ext": "^1.7.0", - "ext-name": "^5.0.0", - "file-type": "^16.5.4", - "filenamify": "^4.3.0", - "get-stream": "^6.0.1", - "got": "^11.8.5", - "inquirer": "^8.2.5", - "js-yaml": "^4.1.0", - "jwt-decode": "^3.1.2", - "lodash": "^4.17.21", - "log": "^6.3.1", - "log-node": "^8.0.3", - "make-dir": "^3.1.0", - "memoizee": "^0.4.15", - "ncjsm": "^4.3.1", - "node-fetch": "^2.6.7", - "open": "^8.4.0", - "p-event": "^4.2.0", - "supports-color": "^8.1.1", - "timers-ext": "^0.1.7", - "type": "^2.7.2", - "uni-global": "^1.0.0", - "uuid": "^8.3.2", - "write-file-atomic": "^4.0.2" + "tslib": "^2.5.0" }, "engines": { - "node": ">=12.0" + "node": ">=14.0.0" } }, - "node_modules/@serverless/utils/node_modules/argparse": { - "version": "2.0.1", + "node_modules/@smithy/util-buffer-from": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-2.0.0.tgz", + "integrity": "sha512-/YNnLoHsR+4W4Vf2wL5lGv0ksg8Bmk3GEGxn2vEQt52AQaPSCuaO5PM5VM7lP1K9qHRKHwrPGktqVoAHKWHxzw==", "dev": true, - "license": "Python-2.0" + "dependencies": { + "@smithy/is-array-buffer": "^2.0.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } }, - "node_modules/@serverless/utils/node_modules/js-yaml": { - "version": "4.1.0", + "node_modules/@smithy/util-config-provider": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-config-provider/-/util-config-provider-2.0.0.tgz", + "integrity": "sha512-xCQ6UapcIWKxXHEU4Mcs2s7LcFQRiU3XEluM2WcCjjBtQkUN71Tb+ydGmJFPxMUrW/GWMgQEEGipLym4XG0jZg==", "dev": true, - "license": "MIT", "dependencies": { - "argparse": "^2.0.1" + "tslib": "^2.5.0" }, - "bin": { - "js-yaml": "bin/js-yaml.js" + "engines": { + "node": ">=14.0.0" } }, - "node_modules/@serverless/utils/node_modules/jwt-decode": { - "version": "3.1.2", + "node_modules/@smithy/util-defaults-mode-browser": { + "version": "2.0.19", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-2.0.19.tgz", + "integrity": "sha512-VHP8xdFR7/orpiABJwgoTB0t8Zhhwpf93gXhNfUBiwAE9O0rvsv7LwpQYjgvbOUDDO8JfIYQB2GYJNkqqGWsXw==", "dev": true, - "license": "MIT" + "dependencies": { + "@smithy/property-provider": "^2.0.14", + "@smithy/smithy-client": "^2.1.15", + "@smithy/types": "^2.5.0", + "bowser": "^2.11.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">= 10.0.0" + } }, - "node_modules/@serverless/utils/node_modules/supports-color": { - "version": "8.1.1", + "node_modules/@smithy/util-defaults-mode-node": { + "version": "2.0.25", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-2.0.25.tgz", + "integrity": "sha512-jkmep6/JyWmn2ADw9VULDeGbugR4N/FJCKOt+gYyVswmN1BJOfzF2umaYxQ1HhQDvna3kzm1Dbo1qIfBW4iuHA==", "dev": true, - "license": "MIT", "dependencies": { - "has-flag": "^4.0.0" + "@smithy/config-resolver": "^2.0.18", + "@smithy/credential-provider-imds": "^2.1.1", + "@smithy/node-config-provider": "^2.1.5", + "@smithy/property-provider": "^2.0.14", + "@smithy/smithy-client": "^2.1.15", + "@smithy/types": "^2.5.0", + "tslib": "^2.5.0" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" + "node": ">= 10.0.0" } }, - "node_modules/@serverless/utils/node_modules/write-file-atomic": { - "version": "4.0.2", + "node_modules/@smithy/util-endpoints": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@smithy/util-endpoints/-/util-endpoints-1.0.4.tgz", + "integrity": "sha512-FPry8j1xye5yzrdnf4xKUXVnkQErxdN7bUIaqC0OFoGsv2NfD9b2UUMuZSSt+pr9a8XWAqj0HoyVNUfPiZ/PvQ==", "dev": true, - "license": "ISC", "dependencies": { - "imurmurhash": "^0.1.4", - "signal-exit": "^3.0.7" + "@smithy/node-config-provider": "^2.1.5", + "@smithy/types": "^2.5.0", + "tslib": "^2.5.0" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": ">= 14.0.0" } }, - "node_modules/@sigstore/bundle": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@sigstore/bundle/-/bundle-2.1.0.tgz", - "integrity": "sha512-89uOo6yh/oxaU8AeOUnVrTdVMcGk9Q1hJa7Hkvalc6G3Z3CupWk4Xe9djSgJm9fMkH69s0P0cVHUoKSOemLdng==", + "node_modules/@smithy/util-hex-encoding": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-hex-encoding/-/util-hex-encoding-2.0.0.tgz", + "integrity": "sha512-c5xY+NUnFqG6d7HFh1IFfrm3mGl29lC+vF+geHv4ToiuJCBmIfzx6IeHLg+OgRdPFKDXIw6pvi+p3CsscaMcMA==", "dev": true, "dependencies": { - "@sigstore/protobuf-specs": "^0.2.1" + "tslib": "^2.5.0" }, "engines": { - "node": "^16.14.0 || >=18.0.0" + "node": ">=14.0.0" } }, - "node_modules/@sigstore/protobuf-specs": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/@sigstore/protobuf-specs/-/protobuf-specs-0.2.1.tgz", - "integrity": "sha512-XTWVxnWJu+c1oCshMLwnKvz8ZQJJDVOlciMfgpJBQbThVjKTCG8dwyhgLngBD2KN0ap9F/gOV8rFDEx8uh7R2A==", + "node_modules/@smithy/util-middleware": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-2.0.6.tgz", + "integrity": "sha512-7W4uuwBvSLgKoLC1x4LfeArCVcbuHdtVaC4g30kKsD1erfICyQ45+tFhhs/dZNeQg+w392fhunCm/+oCcb6BSA==", "dev": true, + "dependencies": { + "@smithy/types": "^2.5.0", + "tslib": "^2.5.0" + }, "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": ">=14.0.0" } }, - "node_modules/@sigstore/sign": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@sigstore/sign/-/sign-2.2.0.tgz", - "integrity": "sha512-AAbmnEHDQv6CSfrWA5wXslGtzLPtAtHZleKOgxdQYvx/s76Fk6T6ZVt7w2IGV9j1UrFeBocTTQxaXG2oRrDhYA==", + "node_modules/@smithy/util-retry": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@smithy/util-retry/-/util-retry-2.0.6.tgz", + "integrity": "sha512-PSO41FofOBmyhPQJwBQJ6mVlaD7Sp9Uff9aBbnfBJ9eqXOE/obrqQjn0PNdkfdvViiPXl49BINfnGcFtSP4kYw==", "dev": true, "dependencies": { - "@sigstore/bundle": "^2.1.0", - "@sigstore/protobuf-specs": "^0.2.1", - "make-fetch-happen": "^13.0.0" + "@smithy/service-error-classification": "^2.0.6", + "@smithy/types": "^2.5.0", + "tslib": "^2.5.0" }, "engines": { - "node": "^16.14.0 || >=18.0.0" + "node": ">= 14.0.0" } }, - "node_modules/@sigstore/tuf": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@sigstore/tuf/-/tuf-2.2.0.tgz", - "integrity": "sha512-KKATZ5orWfqd9ZG6MN8PtCIx4eevWSuGRKQvofnWXRpyMyUEpmrzg5M5BrCpjM+NfZ0RbNGOh5tCz/P2uoRqOA==", + "node_modules/@smithy/util-stream": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-2.0.20.tgz", + "integrity": "sha512-tT8VASuD8jJu0yjHEMTCPt1o5E3FVzgdsxK6FQLAjXKqVv5V8InCnc0EOsYrijgspbfDqdAJg7r0o2sySfcHVg==", "dev": true, "dependencies": { - "@sigstore/protobuf-specs": "^0.2.1", - "tuf-js": "^2.1.0" + "@smithy/fetch-http-handler": "^2.2.6", + "@smithy/node-http-handler": "^2.1.9", + "@smithy/types": "^2.5.0", + "@smithy/util-base64": "^2.0.1", + "@smithy/util-buffer-from": "^2.0.0", + "@smithy/util-hex-encoding": "^2.0.0", + "@smithy/util-utf8": "^2.0.2", + "tslib": "^2.5.0" }, "engines": { - "node": "^16.14.0 || >=18.0.0" + "node": ">=14.0.0" } }, - "node_modules/@sindresorhus/is": { - "version": "4.6.0", + "node_modules/@smithy/util-uri-escape": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-uri-escape/-/util-uri-escape-2.0.0.tgz", + "integrity": "sha512-ebkxsqinSdEooQduuk9CbKcI+wheijxEb3utGXkCoYQkJnwTnLbH1JXGimJtUkQwNQbsbuYwG2+aFVyZf5TLaw==", "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" + "dependencies": { + "tslib": "^2.5.0" }, - "funding": { - "url": "https://github.com/sindresorhus/is?sponsor=1" + "engines": { + "node": ">=14.0.0" } }, - "node_modules/@smithy/protocol-http": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-1.0.1.tgz", - "integrity": "sha512-9OrEn0WfOVtBNYJUjUAn9AOiJ4lzERCJJ/JeZs8E6yajTGxBaFRxUnNBHiNqoDJVg076hY36UmEnPx7xXrvUSg==", + "node_modules/@smithy/util-utf8": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-2.0.2.tgz", + "integrity": "sha512-qOiVORSPm6Ce4/Yu6hbSgNHABLP2VMv8QOC3tTDNHHlWY19pPyc++fBTbZPtx6egPXi4HQxKDnMxVxpbtX2GoA==", "dev": true, "dependencies": { - "@smithy/types": "^1.0.0", + "@smithy/util-buffer-from": "^2.0.0", "tslib": "^2.5.0" }, "engines": { "node": ">=14.0.0" } }, - "node_modules/@smithy/types": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-1.0.0.tgz", - "integrity": "sha512-kc1m5wPBHQCTixwuaOh9vnak/iJm21DrSf9UK6yDE5S3mQQ4u11pqAUiKWnlrZnYkeLfAI9UEHj9OaMT1v5Umg==", + "node_modules/@smithy/util-waiter": { + "version": "2.0.13", + "resolved": "https://registry.npmjs.org/@smithy/util-waiter/-/util-waiter-2.0.13.tgz", + "integrity": "sha512-YovIQatiuM7giEsRFotqJa2i3EbU2EE3PgtpXgtLgpx5rXiZMAwPxXYDFVFhuO0lbqvc/Zx4n+ZIisXOHPSqyg==", "dev": true, "dependencies": { + "@smithy/abort-controller": "^2.0.13", + "@smithy/types": "^2.5.0", "tslib": "^2.5.0" }, "engines": { @@ -3914,8 +4073,9 @@ }, "node_modules/2-thenable": { "version": "1.0.0", + "resolved": "https://registry.npmjs.org/2-thenable/-/2-thenable-1.0.0.tgz", + "integrity": "sha512-HqiDzaLDFCXkcCO/SwoyhRwqYtINFHF7t9BDRq4x90TOKNAJpiqUt9X5lQ08bwxYzc067HUywDjGySpebHcUpw==", "dev": true, - "license": "ISC", "dependencies": { "d": "1", "es5-ext": "^0.10.47" @@ -3983,16 +4143,18 @@ }, "node_modules/adm-zip": { "version": "0.5.10", + "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.5.10.tgz", + "integrity": "sha512-x0HvcHqVJNTPk/Bw8JbLWlWoo6Wwnsug0fnYYro1HBrjxZ3G7/AZk7Ahv8JwDe1uIcz8eBqvu86FuF1POiG7vQ==", "dev": true, - "license": "MIT", "engines": { "node": ">=6.0" } }, "node_modules/agent-base": { "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", "dev": true, - "license": "MIT", "dependencies": { "debug": "4" }, @@ -4122,15 +4284,16 @@ } }, "node_modules/archiver": { - "version": "5.3.1", + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/archiver/-/archiver-5.3.2.tgz", + "integrity": "sha512-+25nxyyznAXF7Nef3y0EbBeqmGZgeN/BxHX29Rs39djAfaFalmQ89SE6CWyDCHzGL0yt/ycBtNOmGTW0FyGWNw==", "dev": true, - "license": "MIT", "dependencies": { "archiver-utils": "^2.1.0", - "async": "^3.2.3", + "async": "^3.2.4", "buffer-crc32": "^0.2.1", "readable-stream": "^3.6.0", - "readdir-glob": "^1.0.0", + "readdir-glob": "^1.1.2", "tar-stream": "^2.2.0", "zip-stream": "^4.1.0" }, @@ -4140,8 +4303,9 @@ }, "node_modules/archiver-utils": { "version": "2.1.0", + "resolved": "https://registry.npmjs.org/archiver-utils/-/archiver-utils-2.1.0.tgz", + "integrity": "sha512-bEL/yUb/fNNiNTuUz979Z0Yg5L+LzLxGJz8x79lYmR54fmTIb6ob/hNQgkQnIUDWIFjZVQwl9Xs356I6BAMHfw==", "dev": true, - "license": "MIT", "dependencies": { "glob": "^7.1.4", "graceful-fs": "^4.2.0", @@ -4160,8 +4324,9 @@ }, "node_modules/archiver-utils/node_modules/readable-stream": { "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", "dev": true, - "license": "MIT", "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -4174,13 +4339,15 @@ }, "node_modules/archiver-utils/node_modules/safe-buffer": { "version": "5.1.2", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true }, "node_modules/archiver-utils/node_modules/string_decoder": { "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, - "license": "MIT", "dependencies": { "safe-buffer": "~5.1.0" } @@ -4302,9 +4469,10 @@ } }, "node_modules/async": { - "version": "3.2.4", - "dev": true, - "license": "MIT" + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.5.tgz", + "integrity": "sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==", + "dev": true }, "node_modules/async-hook-domain": { "version": "4.0.1", @@ -4322,8 +4490,9 @@ }, "node_modules/at-least-node": { "version": "1.0.0", + "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", + "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", "dev": true, - "license": "ISC", "engines": { "node": ">= 4.0.0" } @@ -4714,9 +4883,9 @@ } }, "node_modules/aws-sdk": { - "version": "2.1397.0", - "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1397.0.tgz", - "integrity": "sha512-Km+jUscV6vW3vuurSsGrTjEqaNfrE9ykA3IJmJb85V2z5tklJvoBU+7JcCiF6h3BDKegNjiFOM7uoL3cGVGz4g==", + "version": "2.1496.0", + "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1496.0.tgz", + "integrity": "sha512-w/JnK6kmYBDSJ+vt9KKJbYYh3SXak5NFB7uLiev0Ysl3dkxnA3ScSmc1x7KZvDkHcbkACI0VeMPTkftEGvY9kQ==", "dev": true, "dependencies": { "buffer": "4.9.2", @@ -4750,9 +4919,9 @@ } }, "node_modules/axios": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.3.5.tgz", - "integrity": "sha512-glL/PvG/E+xCWwV8S6nCHcrfg1exGx7vxyUIivIA1iL7BIh6bePylCfVHwp6k13ao7SATxB6imau2kqY+I67kw==", + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.2.tgz", + "integrity": "sha512-7i24Ri4pmDRfJTR7LDBhsOTtcm+9kjX5WiY1X3wIisx6G9So3pfMkEiU7emUBe46oceVImccTEM3k6C5dbVW8A==", "dev": true, "dependencies": { "follow-redirects": "^1.15.0", @@ -4791,6 +4960,41 @@ "node": ">=8" } }, + "node_modules/bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "dev": true, + "dependencies": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "node_modules/bl/node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, "node_modules/bluebird": { "version": "3.7.2", "dev": true, @@ -5137,8 +5341,9 @@ }, "node_modules/child-process-ext": { "version": "2.1.1", + "resolved": "https://registry.npmjs.org/child-process-ext/-/child-process-ext-2.1.1.tgz", + "integrity": "sha512-0UQ55f51JBkOFa+fvR76ywRzxiPwQS3Xe8oe5bZRphpv+dIMeerW5Zn5e4cUy4COJwVtJyU0R79RMnw+aCqmGA==", "dev": true, - "license": "ISC", "dependencies": { "cross-spawn": "^6.0.5", "es5-ext": "^0.10.53", @@ -5149,8 +5354,9 @@ }, "node_modules/child-process-ext/node_modules/cross-spawn": { "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", "dev": true, - "license": "MIT", "dependencies": { "nice-try": "^1.0.4", "path-key": "^2.0.1", @@ -5164,24 +5370,27 @@ }, "node_modules/child-process-ext/node_modules/path-key": { "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==", "dev": true, - "license": "MIT", "engines": { "node": ">=4" } }, "node_modules/child-process-ext/node_modules/semver": { - "version": "5.7.1", + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", "dev": true, - "license": "ISC", "bin": { "semver": "bin/semver" } }, "node_modules/child-process-ext/node_modules/shebang-command": { "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==", "dev": true, - "license": "MIT", "dependencies": { "shebang-regex": "^1.0.0" }, @@ -5191,16 +5400,18 @@ }, "node_modules/child-process-ext/node_modules/shebang-regex": { "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==", "dev": true, - "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/child-process-ext/node_modules/which": { "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", "dev": true, - "license": "ISC", "dependencies": { "isexe": "^2.0.0" }, @@ -5608,9 +5819,10 @@ "license": "MIT" }, "node_modules/compress-commons": { - "version": "4.1.1", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/compress-commons/-/compress-commons-4.1.2.tgz", + "integrity": "sha512-D3uMHtGc/fcO1Gt1/L7i1e33VOvD4A9hfQLP+6ewd+BvG/gQ84Yh4oftEhAdjSMgBgwGL+jsppT7JYNpo6MHHg==", "dev": true, - "license": "MIT", "dependencies": { "buffer-crc32": "^0.2.13", "crc32-stream": "^4.0.2", @@ -5694,8 +5906,9 @@ }, "node_modules/crc-32": { "version": "1.2.2", + "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz", + "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==", "dev": true, - "license": "Apache-2.0", "bin": { "crc32": "bin/crc32.njs" }, @@ -5704,9 +5917,10 @@ } }, "node_modules/crc32-stream": { - "version": "4.0.2", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/crc32-stream/-/crc32-stream-4.0.3.tgz", + "integrity": "sha512-NT7w2JVU7DFroFdYkeq8cywxrgjPHWkdX1wjpRQXPX5Asews3tA+Ght6lddQO5Mkumffp3X7GEqku3epj2toIw==", "dev": true, - "license": "MIT", "dependencies": { "crc-32": "^1.2.0", "readable-stream": "^3.4.0" @@ -5754,9 +5968,10 @@ "license": "ISC" }, "node_modules/dayjs": { - "version": "1.11.7", - "dev": true, - "license": "MIT" + "version": "1.11.10", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.10.tgz", + "integrity": "sha512-vjAczensTgRcqDERK0SR2XMwsF/tSvnvlv6VcF2GIhg6Sx4yOIt/irsr1RDJsKiIyBzJDpCoXiWWq28MqH2cnQ==", + "dev": true }, "node_modules/debug": { "version": "4.3.4", @@ -5847,14 +6062,6 @@ "node": ">=4" } }, - "node_modules/decompress-tar/node_modules/is-stream": { - "version": "1.1.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/decompress-tar/node_modules/readable-stream": { "version": "2.3.8", "dev": true, @@ -5922,14 +6129,6 @@ "node": ">=4" } }, - "node_modules/decompress-tarbz2/node_modules/is-stream": { - "version": "1.1.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/decompress-targz": { "version": "4.1.1", "dev": true, @@ -5951,14 +6150,6 @@ "node": ">=4" } }, - "node_modules/decompress-targz/node_modules/is-stream": { - "version": "1.1.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/decompress-unzip": { "version": "4.0.1", "dev": true, @@ -6149,17 +6340,22 @@ } }, "node_modules/dotenv": { - "version": "16.0.3", + "version": "16.3.1", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.3.1.tgz", + "integrity": "sha512-IPzF4w4/Rd94bA9imS68tZBaYyBWSCE47V1RGuMrB94iyTOIEwRmVL2x/4An+6mETpLrKJ5hQkB8W4kFAadeIQ==", "dev": true, - "license": "BSD-2-Clause", "engines": { "node": ">=12" + }, + "funding": { + "url": "https://github.com/motdotla/dotenv?sponsor=1" } }, "node_modules/dotenv-expand": { - "version": "9.0.0", + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-10.0.0.tgz", + "integrity": "sha512-GopVGCpVS1UKH75VKHGuQFqS1Gusej0z4FyQkPdwjil2gNIv+LNsqBlboOzpJFZKVT95GkCyWJbBSdFEFUWI2A==", "dev": true, - "license": "BSD-2-Clause", "engines": { "node": ">=12" } @@ -6681,9 +6877,10 @@ } }, "node_modules/eslint-plugin-import/node_modules/semver": { - "version": "6.3.0", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, - "license": "ISC", "bin": { "semver": "bin/semver.js" } @@ -6774,9 +6971,10 @@ } }, "node_modules/eslint-plugin-node/node_modules/semver": { - "version": "6.3.0", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, - "license": "ISC", "bin": { "semver": "bin/semver.js" } @@ -7129,9 +7327,9 @@ "license": "MIT" }, "node_modules/fast-xml-parser": { - "version": "4.2.4", - "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.2.4.tgz", - "integrity": "sha512-fbfMDvgBNIdDJLdLOwacjFAPYt67tr31H9ZhWSm45CDAxvd0I6WTlSOUo7K2P/K5sA5JgMKG64PI3DMcaFdWpQ==", + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.2.5.tgz", + "integrity": "sha512-B9/wizE4WngqQftFPmdaMYlXoJlJOYxGQOanC77fq9k8+Z0v5dDSVh+3glErdIROP//s/jgb7ZuxKfB8nVyo0g==", "dev": true, "funding": [ { @@ -7248,9 +7446,10 @@ } }, "node_modules/filesize": { - "version": "10.0.6", + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/filesize/-/filesize-10.1.0.tgz", + "integrity": "sha512-GTLKYyBSDz3nPhlLVPjPWZCnhkd9TrrRArNcy8Z+J2cqScB7h2McAzR6NBX6nYOoWafql0roY8hrocxnZBv9CQ==", "dev": true, - "license": "BSD-3-Clause", "engines": { "node": ">= 10.4.0" } @@ -7295,8 +7494,9 @@ }, "node_modules/flat": { "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", "dev": true, - "license": "BSD-3-Clause", "bin": { "flat": "cli.js" } @@ -7436,8 +7636,9 @@ }, "node_modules/fs-extra": { "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", "dev": true, - "license": "MIT", "dependencies": { "at-least-node": "^1.0.0", "graceful-fs": "^4.2.0", @@ -7713,9 +7914,10 @@ } }, "node_modules/graceful-fs": { - "version": "4.2.10", - "dev": true, - "license": "ISC" + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true }, "node_modules/grapheme-splitter": { "version": "1.0.4", @@ -7731,9 +7933,9 @@ } }, "node_modules/graphql": { - "version": "16.6.0", - "resolved": "https://registry.npmjs.org/graphql/-/graphql-16.6.0.tgz", - "integrity": "sha512-KPIBPDlW7NxrbT/eh4qPXz5FiFdL5UbaA0XUNz2Rp3Z3hqBSkbj0GVjwFDztsWVauZUWsbKHgMg++sk8UX0bkw==", + "version": "16.8.1", + "resolved": "https://registry.npmjs.org/graphql/-/graphql-16.8.1.tgz", + "integrity": "sha512-59LZHPdGZVh695Ud9lRzPBVTtlX9ZCV150Er2W43ro37wVof0ctenSaskPPjN7lVTIN8mSZt8PHUNKZuNQUuxw==", "dev": true, "peer": true, "engines": { @@ -7943,8 +8145,9 @@ }, "node_modules/https-proxy-agent": { "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", "dev": true, - "license": "MIT", "dependencies": { "agent-base": "6", "debug": "4" @@ -8030,8 +8233,9 @@ }, "node_modules/immediate": { "version": "3.0.6", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", + "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==", + "dev": true }, "node_modules/import-fresh": { "version": "3.3.0", @@ -8687,6 +8891,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/is-string": { "version": "1.0.7", "dev": true, @@ -8787,8 +9000,9 @@ }, "node_modules/isomorphic-ws": { "version": "4.0.1", + "resolved": "https://registry.npmjs.org/isomorphic-ws/-/isomorphic-ws-4.0.1.tgz", + "integrity": "sha512-BhBvN2MBpWTaSHdWRb/bwdZJ1WaehQ2L1KngkCkfLUGF0mAWAT1sQUQacEmQ0jXkFw/czDXPNQSL5u2/Krsz1w==", "dev": true, - "license": "MIT", "peerDependencies": { "ws": "*" } @@ -8816,21 +9030,6 @@ "node": ">=10" } }, - "node_modules/istanbul-lib-report/node_modules/make-dir": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", - "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", - "dev": true, - "dependencies": { - "semver": "^7.5.3" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/istanbul-reports": { "version": "3.1.6", "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.6.tgz", @@ -8908,10 +9107,92 @@ "dev": true, "license": "MIT" }, + "node_modules/json-colorizer": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/json-colorizer/-/json-colorizer-2.2.2.tgz", + "integrity": "sha512-56oZtwV1piXrQnRNTtJeqRv+B9Y/dXAYLqBBaYl/COcUdoZxgLBLAO88+CnkbT6MxNs0c5E9mPBIb2sFcNz3vw==", + "dev": true, + "dependencies": { + "chalk": "^2.4.1", + "lodash.get": "^4.4.2" + } + }, + "node_modules/json-colorizer/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/json-colorizer/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/json-colorizer/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/json-colorizer/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "node_modules/json-colorizer/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/json-colorizer/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/json-colorizer/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/json-cycle": { - "version": "1.3.0", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/json-cycle/-/json-cycle-1.5.0.tgz", + "integrity": "sha512-GOehvd5PO2FeZ5T4c+RxobeT5a1PiGpF4u9/3+UvrMU4bhnVqzJY7hm39wg8PDCqkU91fWGH8qjWR4bn+wgq9w==", "dev": true, - "license": "MIT", "engines": { "node": ">= 4" } @@ -9001,8 +9282,9 @@ }, "node_modules/jszip": { "version": "3.10.1", + "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz", + "integrity": "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==", "dev": true, - "license": "(MIT OR GPL-3.0-or-later)", "dependencies": { "lie": "~3.3.0", "pako": "~1.0.2", @@ -9012,8 +9294,9 @@ }, "node_modules/jszip/node_modules/readable-stream": { "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", "dev": true, - "license": "MIT", "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -9026,21 +9309,24 @@ }, "node_modules/jszip/node_modules/safe-buffer": { "version": "5.1.2", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true }, "node_modules/jszip/node_modules/string_decoder": { "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, - "license": "MIT", "dependencies": { "safe-buffer": "~5.1.0" } }, "node_modules/jwt-decode": { "version": "2.2.0", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/jwt-decode/-/jwt-decode-2.2.0.tgz", + "integrity": "sha512-86GgN2vzfUu7m9Wcj63iUkuDzFNYFVmjeDm2GzWpUk+opB0pEpMsw6ePCMrhYkumz2C1ihqtZzOMAg7FiXcNoQ==", + "dev": true }, "node_modules/keygrip": { "version": "1.1.0", @@ -9117,8 +9403,9 @@ }, "node_modules/lazystream": { "version": "1.0.1", + "resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.1.tgz", + "integrity": "sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==", "dev": true, - "license": "MIT", "dependencies": { "readable-stream": "^2.0.5" }, @@ -9128,8 +9415,9 @@ }, "node_modules/lazystream/node_modules/readable-stream": { "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", "dev": true, - "license": "MIT", "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -9142,13 +9430,15 @@ }, "node_modules/lazystream/node_modules/safe-buffer": { "version": "5.1.2", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true }, "node_modules/lazystream/node_modules/string_decoder": { "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, - "license": "MIT", "dependencies": { "safe-buffer": "~5.1.0" } @@ -9167,8 +9457,9 @@ }, "node_modules/lie": { "version": "3.3.0", + "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz", + "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==", "dev": true, - "license": "MIT", "dependencies": { "immediate": "~3.0.5" } @@ -9408,23 +9699,33 @@ }, "node_modules/lodash.defaults": { "version": "4.2.0", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz", + "integrity": "sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==", + "dev": true }, "node_modules/lodash.difference": { "version": "4.5.0", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/lodash.difference/-/lodash.difference-4.5.0.tgz", + "integrity": "sha512-dS2j+W26TQ7taQBGN8Lbbq04ssV3emRw4NY58WErlTO29pIqS0HmoT5aJ9+TUQ1N3G+JOZSji4eugsWwGp9yPA==", + "dev": true }, "node_modules/lodash.flatten": { "version": "4.4.0", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz", + "integrity": "sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g==", + "dev": true + }, + "node_modules/lodash.get": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", + "integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==", + "dev": true }, "node_modules/lodash.isplainobject": { "version": "4.0.6", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", + "dev": true }, "node_modules/lodash.merge": { "version": "4.6.2", @@ -9433,8 +9734,9 @@ }, "node_modules/lodash.union": { "version": "4.6.0", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/lodash.union/-/lodash.union-4.6.0.tgz", + "integrity": "sha512-c4pB2CdGrGdjMKYLA+XiRDO7Y0PRQbm/Gzg8qMj+QH+pFVAoTp5sBpO0odL3FjoPCGjK96p6qsP+yQoiLoOBcw==", + "dev": true }, "node_modules/log": { "version": "6.3.1", @@ -9587,27 +9889,20 @@ } }, "node_modules/make-dir": { - "version": "3.1.0", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", + "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", "dev": true, - "license": "MIT", "dependencies": { - "semver": "^6.0.0" + "semver": "^7.5.3" }, "engines": { - "node": ">=8" + "node": ">=10" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/make-dir/node_modules/semver": { - "version": "6.3.0", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - } - }, "node_modules/make-error": { "version": "1.3.6", "license": "ISC" @@ -9959,13 +10254,15 @@ }, "node_modules/nice-try": { "version": "1.0.5", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", + "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", + "dev": true }, "node_modules/node-dir": { "version": "0.1.17", + "resolved": "https://registry.npmjs.org/node-dir/-/node-dir-0.1.17.tgz", + "integrity": "sha512-tmPX422rYgofd4epzrNoOXiE8XFZYOcCq1vD7MAXCDO+O+zndlA2ztdKKMa+EeuBG5tHETpr4ml4RGgpqDCCAg==", "dev": true, - "license": "MIT", "dependencies": { "minimatch": "^3.0.2" }, @@ -9974,9 +10271,10 @@ } }, "node_modules/node-fetch": { - "version": "2.6.9", + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", "dev": true, - "license": "MIT", "dependencies": { "whatwg-url": "^5.0.0" }, @@ -10466,39 +10764,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/ora/node_modules/bl": { - "version": "4.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "buffer": "^5.5.0", - "inherits": "^2.0.4", - "readable-stream": "^3.4.0" - } - }, - "node_modules/ora/node_modules/buffer": { - "version": "5.7.1", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT", - "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.1.13" - } - }, "node_modules/os-tmpdir": { "version": "1.0.2", "dev": true, @@ -10646,8 +10911,9 @@ }, "node_modules/pako": { "version": "1.0.11", - "dev": true, - "license": "(MIT AND Zlib)" + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", + "dev": true }, "node_modules/parent-module": { "version": "1.0.1", @@ -11093,8 +11359,10 @@ }, "node_modules/querystring": { "version": "0.2.1", + "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.1.tgz", + "integrity": "sha512-wkvS7mL/JMugcup3/rMitHmd9ecIGd2lhFhK9N3UUQ450h66d1r3Y9nvXzQAW1Lq+wyx61k/1pfKS5KuKiyEbg==", + "deprecated": "The querystring API is considered Legacy. new code should use the URLSearchParams API instead.", "dev": true, - "license": "MIT", "engines": { "node": ">=0.4.x" } @@ -11314,25 +11582,28 @@ } }, "node_modules/readdir-glob": { - "version": "1.1.2", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/readdir-glob/-/readdir-glob-1.1.3.tgz", + "integrity": "sha512-v05I2k7xN8zXvPD9N+z/uhXPaj0sUFCe2rcWZIpBsqxfP7xXFQ0tipAd/wjj1YxWyWtUS5IDJpOG82JKt2EAVA==", "dev": true, - "license": "Apache-2.0", "dependencies": { "minimatch": "^5.1.0" } }, "node_modules/readdir-glob/node_modules/brace-expansion": { "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", "dev": true, - "license": "MIT", "dependencies": { "balanced-match": "^1.0.0" } }, "node_modules/readdir-glob/node_modules/minimatch": { "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", "dev": true, - "license": "ISC", "dependencies": { "brace-expansion": "^2.0.1" }, @@ -11600,6 +11871,8 @@ }, "node_modules/run-parallel-limit": { "version": "1.1.0", + "resolved": "https://registry.npmjs.org/run-parallel-limit/-/run-parallel-limit-1.1.0.tgz", + "integrity": "sha512-jJA7irRNM91jaKc3Hcl1npHsFLOXOoTkPCUL1JEa1R82O2miplXXRaGdjW/KM/98YQWDhJLiSs793CnXfblJUw==", "dev": true, "funding": [ { @@ -11615,7 +11888,6 @@ "url": "https://feross.org/support" } ], - "license": "MIT", "dependencies": { "queue-microtask": "^1.2.2" } @@ -11740,19 +12012,20 @@ "license": "ISC" }, "node_modules/serverless": { - "version": "3.28.1", - "resolved": "https://registry.npmjs.org/serverless/-/serverless-3.28.1.tgz", - "integrity": "sha512-zC+8ItbRYtJkIY5YZkU5RrCGd+JPkn8DUeGpHX6C9NKV/555DppiaMXURcNWJqN6VFV3fhmZrtefTzDF/B6+Rg==", + "version": "3.36.0", + "resolved": "https://registry.npmjs.org/serverless/-/serverless-3.36.0.tgz", + "integrity": "sha512-VY7UzP4u1/yuTNpF2Wssrru16qhhReLCjgL2oeHCvhujxPyTFv9TQGSlLhaT0ZUCXhRBphwVwITTRopo6NSUgA==", "dev": true, "hasInstallScript": true, "dependencies": { - "@serverless/dashboard-plugin": "^6.2.3", - "@serverless/platform-client": "^4.3.2", - "@serverless/utils": "^6.8.2", + "@serverless/dashboard-plugin": "^7.1.0", + "@serverless/platform-client": "^4.4.0", + "@serverless/utils": "^6.13.1", + "abort-controller": "^3.0.0", "ajv": "^8.12.0", "ajv-formats": "^2.1.1", "archiver": "^5.3.1", - "aws-sdk": "^2.1326.0", + "aws-sdk": "^2.1404.0", "bluebird": "^3.7.2", "cachedir": "^2.3.0", "chalk": "^4.1.2", @@ -11760,28 +12033,28 @@ "ci-info": "^3.8.0", "cli-progress-footer": "^2.3.2", "d": "^1.0.1", - "dayjs": "^1.11.7", + "dayjs": "^1.11.8", "decompress": "^4.2.1", - "dotenv": "^16.0.3", - "dotenv-expand": "^9.0.0", + "dotenv": "^16.3.1", + "dotenv-expand": "^10.0.0", "essentials": "^1.2.0", "ext": "^1.7.0", "fastest-levenshtein": "^1.0.16", - "filesize": "^10.0.6", + "filesize": "^10.0.7", "fs-extra": "^10.1.0", "get-stdin": "^8.0.0", "globby": "^11.1.0", - "got": "^11.8.6", - "graceful-fs": "^4.2.10", + "graceful-fs": "^4.2.11", "https-proxy-agent": "^5.0.1", "is-docker": "^2.2.1", "js-yaml": "^4.1.0", - "json-cycle": "^1.3.0", + "json-colorizer": "^2.2.2", + "json-cycle": "^1.5.0", "json-refs": "^3.0.15", "lodash": "^4.17.21", "memoizee": "^0.4.15", "micromatch": "^4.0.5", - "node-fetch": "^2.6.9", + "node-fetch": "^2.6.11", "npm-registry-utilities": "^1.0.0", "object-hash": "^3.0.0", "open": "^8.4.2", @@ -11789,15 +12062,17 @@ "process-utils": "^4.0.0", "promise-queue": "^2.2.5", "require-from-string": "^2.0.2", - "semver": "^7.3.8", + "semver": "^7.5.3", "signal-exit": "^3.0.7", + "stream-buffers": "^3.0.2", "strip-ansi": "^6.0.1", "supports-color": "^8.1.1", - "tar": "^6.1.13", + "tar": "^6.1.15", "timers-ext": "^0.1.7", "type": "^2.7.2", "untildify": "^4.0.0", "uuid": "^9.0.0", + "ws": "^7.5.9", "yaml-ast-parser": "0.0.43" }, "bin": { @@ -11911,8 +12186,9 @@ }, "node_modules/setimmediate": { "version": "1.0.5", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==", + "dev": true }, "node_modules/setprototypeof": { "version": "1.2.0", @@ -11973,9 +12249,10 @@ } }, "node_modules/simple-git": { - "version": "3.16.1", + "version": "3.20.0", + "resolved": "https://registry.npmjs.org/simple-git/-/simple-git-3.20.0.tgz", + "integrity": "sha512-ozK8tl2hvLts8ijTs18iFruE+RoqmC/mqZhjs/+V7gS5W68JpJ3+FCTmLVqmR59MaUQ52MfGQuWsIqfsTbbJ0Q==", "dev": true, - "license": "MIT", "dependencies": { "@kwsites/file-exists": "^1.1.1", "@kwsites/promise-deferred": "^1.1.1", @@ -12166,8 +12443,9 @@ }, "node_modules/split2": { "version": "3.2.2", + "resolved": "https://registry.npmjs.org/split2/-/split2-3.2.2.tgz", + "integrity": "sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg==", "dev": true, - "license": "ISC", "dependencies": { "readable-stream": "^3.0.0" } @@ -12236,24 +12514,26 @@ "node": ">= 0.6" } }, + "node_modules/stream-buffers": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/stream-buffers/-/stream-buffers-3.0.2.tgz", + "integrity": "sha512-DQi1h8VEBA/lURbSwFtEHnSTb9s2/pwLEaFuNhXwy1Dx3Sa0lOuYT2yNUr4/j2fs8oCAMANtrZ5OrPZtyVs3MQ==", + "dev": true, + "engines": { + "node": ">= 0.10.0" + } + }, "node_modules/stream-promise": { "version": "3.2.0", + "resolved": "https://registry.npmjs.org/stream-promise/-/stream-promise-3.2.0.tgz", + "integrity": "sha512-P+7muTGs2C8yRcgJw/PPt61q7O517tDHiwYEzMWo1GSBCcZedUMT/clz7vUNsSxFphIlJ6QUL4GexQKlfJoVtA==", "dev": true, - "license": "ISC", "dependencies": { "2-thenable": "^1.0.0", "es5-ext": "^0.10.49", "is-stream": "^1.1.0" } }, - "node_modules/stream-promise/node_modules/is-stream": { - "version": "1.1.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/string_decoder": { "version": "1.3.0", "dev": true, @@ -12690,13 +12970,14 @@ } }, "node_modules/tar": { - "version": "6.1.13", + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.0.tgz", + "integrity": "sha512-/Wo7DcT0u5HUV486xg675HtjNd3BXZ6xDbzsCUZPt5iw8bTQ63bP0Raut3mvro9u+CUyq7YQd8Cx55fsZXxqLQ==", "dev": true, - "license": "ISC", "dependencies": { "chownr": "^2.0.0", "fs-minipass": "^2.0.0", - "minipass": "^4.0.0", + "minipass": "^5.0.0", "minizlib": "^2.1.1", "mkdirp": "^1.0.3", "yallist": "^4.0.0" @@ -12707,8 +12988,9 @@ }, "node_modules/tar-stream": { "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", + "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", "dev": true, - "license": "MIT", "dependencies": { "bl": "^4.0.3", "end-of-stream": "^1.4.1", @@ -12720,43 +13002,11 @@ "node": ">=6" } }, - "node_modules/tar-stream/node_modules/bl": { - "version": "4.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "buffer": "^5.5.0", - "inherits": "^2.0.4", - "readable-stream": "^3.4.0" - } - }, - "node_modules/tar-stream/node_modules/buffer": { - "version": "5.7.1", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT", - "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.1.13" - } - }, "node_modules/tar/node_modules/minipass": { - "version": "4.2.4", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", + "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", "dev": true, - "license": "ISC", "engines": { "node": ">=8" } @@ -12818,6 +13068,12 @@ "real-require": "^0.2.0" } }, + "node_modules/throat": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/throat/-/throat-5.0.0.tgz", + "integrity": "sha512-fcwX4mndzpLQKBS1DVYhGAcYaYt7vsHNIvQV+WXMvnow5cgjPphq5CaayLaGsjRdSCKZFNGt7/GYAuXaNOiYCA==", + "dev": true + }, "node_modules/through": { "version": "2.3.8", "dev": true, @@ -12905,8 +13161,9 @@ }, "node_modules/traverse": { "version": "0.6.7", + "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.6.7.tgz", + "integrity": "sha512-/y956gpUo9ZNCb99YjxG7OaslxZWHfCHAUUfshwqOXmxUIvqLjVO581BT+gM59+QV9tFe6/CGG53tsA1Y7RSdg==", "dev": true, - "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -13597,9 +13854,10 @@ } }, "node_modules/word-wrap": { - "version": "1.2.3", + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", "dev": true, - "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -13645,8 +13903,9 @@ }, "node_modules/ws": { "version": "7.5.9", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz", + "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==", "dev": true, - "license": "MIT", "engines": { "node": ">=8.3.0" }, @@ -13738,8 +13997,9 @@ }, "node_modules/yamljs": { "version": "0.3.0", + "resolved": "https://registry.npmjs.org/yamljs/-/yamljs-0.3.0.tgz", + "integrity": "sha512-C/FsVVhht4iPQYXOInoxUM/1ELSf9EsgKH34FofQOp6hwCPrW4vG4w5++TED3xRUo8gD7l0P1J1dLlDYzODsTQ==", "dev": true, - "license": "MIT", "dependencies": { "argparse": "^1.0.7", "glob": "^7.0.5" @@ -13819,12 +14079,34 @@ "dev": true }, "node_modules/zip-stream": { - "version": "4.1.0", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/zip-stream/-/zip-stream-4.1.1.tgz", + "integrity": "sha512-9qv4rlDiopXg4E69k+vMHjNN63YFMe9sZMrdlvKnCjlCRWeCBswPPMPUfx+ipsAWq1LXHe70RcbaHdJJpS6hyQ==", "dev": true, - "license": "MIT", "dependencies": { - "archiver-utils": "^2.1.0", - "compress-commons": "^4.1.0", + "archiver-utils": "^3.0.4", + "compress-commons": "^4.1.2", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/zip-stream/node_modules/archiver-utils": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/archiver-utils/-/archiver-utils-3.0.4.tgz", + "integrity": "sha512-KVgf4XQVrTjhyWmx6cte4RxonPLR9onExufI1jhvw/MQ4BB6IsZD5gT8Lq+u/+pRkWna/6JoHpiQioaqFP5Rzw==", + "dev": true, + "dependencies": { + "glob": "^7.2.3", + "graceful-fs": "^4.2.0", + "lazystream": "^1.0.0", + "lodash.defaults": "^4.2.0", + "lodash.difference": "^4.5.0", + "lodash.flatten": "^4.4.0", + "lodash.isplainobject": "^4.0.6", + "lodash.union": "^4.6.0", + "normalize-path": "^3.0.0", "readable-stream": "^3.6.0" }, "engines": { @@ -14168,780 +14450,480 @@ } } }, - "@aws-sdk/abort-controller": { - "version": "3.347.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/abort-controller/-/abort-controller-3.347.0.tgz", - "integrity": "sha512-P/2qE6ntYEmYG4Ez535nJWZbXqgbkJx8CMz7ChEuEg3Gp3dvVYEKg+iEUEvlqQ2U5dWP5J3ehw5po9t86IsVPQ==", - "dev": true, - "requires": { - "@aws-sdk/types": "3.347.0", - "tslib": "^2.5.0" - } - }, - "@aws-sdk/client-cloudwatch": { - "version": "3.352.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-cloudwatch/-/client-cloudwatch-3.352.0.tgz", - "integrity": "sha512-TdPEpzoHBIme1hMtEv/01PGAZr89QzjXkFcX8II+FojDdHL6ojwPsx8MMD6F/jnzoxpU4nJ0go5uEUcpqOGbAw==", + "@aws-sdk/client-cloudformation": { + "version": "3.451.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-cloudformation/-/client-cloudformation-3.451.0.tgz", + "integrity": "sha512-rc8MWRsWA1OgOq/hASLONtVTEbRggjf8VFYmW7UdL1g+oRQoDFWEWPv7kW5868UTpS6SmHdjCrXP8YREtR4ZSQ==", "dev": true, "requires": { "@aws-crypto/sha256-browser": "3.0.0", "@aws-crypto/sha256-js": "3.0.0", - "@aws-sdk/client-sts": "3.352.0", - "@aws-sdk/config-resolver": "3.347.0", - "@aws-sdk/credential-provider-node": "3.352.0", - "@aws-sdk/fetch-http-handler": "3.347.0", - "@aws-sdk/hash-node": "3.347.0", - "@aws-sdk/invalid-dependency": "3.347.0", - "@aws-sdk/middleware-content-length": "3.347.0", - "@aws-sdk/middleware-endpoint": "3.347.0", - "@aws-sdk/middleware-host-header": "3.347.0", - "@aws-sdk/middleware-logger": "3.347.0", - "@aws-sdk/middleware-recursion-detection": "3.347.0", - "@aws-sdk/middleware-retry": "3.347.0", - "@aws-sdk/middleware-serde": "3.347.0", - "@aws-sdk/middleware-signing": "3.347.0", - "@aws-sdk/middleware-stack": "3.347.0", - "@aws-sdk/middleware-user-agent": "3.352.0", - "@aws-sdk/node-config-provider": "3.347.0", - "@aws-sdk/node-http-handler": "3.350.0", - "@aws-sdk/smithy-client": "3.347.0", - "@aws-sdk/types": "3.347.0", - "@aws-sdk/url-parser": "3.347.0", - "@aws-sdk/util-base64": "3.310.0", - "@aws-sdk/util-body-length-browser": "3.310.0", - "@aws-sdk/util-body-length-node": "3.310.0", - "@aws-sdk/util-defaults-mode-browser": "3.347.0", - "@aws-sdk/util-defaults-mode-node": "3.347.0", - "@aws-sdk/util-endpoints": "3.352.0", - "@aws-sdk/util-retry": "3.347.0", - "@aws-sdk/util-user-agent-browser": "3.347.0", - "@aws-sdk/util-user-agent-node": "3.347.0", - "@aws-sdk/util-utf8": "3.310.0", - "@aws-sdk/util-waiter": "3.347.0", - "@smithy/protocol-http": "^1.0.1", - "@smithy/types": "^1.0.0", - "fast-xml-parser": "4.2.4", - "tslib": "^2.5.0" + "@aws-sdk/client-sts": "3.451.0", + "@aws-sdk/core": "3.451.0", + "@aws-sdk/credential-provider-node": "3.451.0", + "@aws-sdk/middleware-host-header": "3.451.0", + "@aws-sdk/middleware-logger": "3.451.0", + "@aws-sdk/middleware-recursion-detection": "3.451.0", + "@aws-sdk/middleware-signing": "3.451.0", + "@aws-sdk/middleware-user-agent": "3.451.0", + "@aws-sdk/region-config-resolver": "3.451.0", + "@aws-sdk/types": "3.451.0", + "@aws-sdk/util-endpoints": "3.451.0", + "@aws-sdk/util-user-agent-browser": "3.451.0", + "@aws-sdk/util-user-agent-node": "3.451.0", + "@smithy/config-resolver": "^2.0.18", + "@smithy/fetch-http-handler": "^2.2.6", + "@smithy/hash-node": "^2.0.15", + "@smithy/invalid-dependency": "^2.0.13", + "@smithy/middleware-content-length": "^2.0.15", + "@smithy/middleware-endpoint": "^2.2.0", + "@smithy/middleware-retry": "^2.0.20", + "@smithy/middleware-serde": "^2.0.13", + "@smithy/middleware-stack": "^2.0.7", + "@smithy/node-config-provider": "^2.1.5", + "@smithy/node-http-handler": "^2.1.9", + "@smithy/protocol-http": "^3.0.9", + "@smithy/smithy-client": "^2.1.15", + "@smithy/types": "^2.5.0", + "@smithy/url-parser": "^2.0.13", + "@smithy/util-base64": "^2.0.1", + "@smithy/util-body-length-browser": "^2.0.0", + "@smithy/util-body-length-node": "^2.1.0", + "@smithy/util-defaults-mode-browser": "^2.0.19", + "@smithy/util-defaults-mode-node": "^2.0.25", + "@smithy/util-endpoints": "^1.0.4", + "@smithy/util-retry": "^2.0.6", + "@smithy/util-utf8": "^2.0.2", + "@smithy/util-waiter": "^2.0.13", + "fast-xml-parser": "4.2.5", + "tslib": "^2.5.0", + "uuid": "^8.3.2" } }, - "@aws-sdk/client-sso": { - "version": "3.352.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.352.0.tgz", - "integrity": "sha512-oeO36rvRvYbUlsgzYtLI2/BPwXdUK4KtYw+OFmirYeONUyX5uYx8kWXD66r3oXViIYMqhyHKN3fhkiFmFcVluQ==", + "@aws-sdk/client-cloudwatch": { + "version": "3.451.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-cloudwatch/-/client-cloudwatch-3.451.0.tgz", + "integrity": "sha512-qTOtdSRVdizBst94HK3ZAoCyi7gB7AFXZyHxu+acJwxFi28sAByPtwCVvmeTuFzivC+22JZs5mYRaXBWwL7USw==", "dev": true, "requires": { "@aws-crypto/sha256-browser": "3.0.0", "@aws-crypto/sha256-js": "3.0.0", - "@aws-sdk/config-resolver": "3.347.0", - "@aws-sdk/fetch-http-handler": "3.347.0", - "@aws-sdk/hash-node": "3.347.0", - "@aws-sdk/invalid-dependency": "3.347.0", - "@aws-sdk/middleware-content-length": "3.347.0", - "@aws-sdk/middleware-endpoint": "3.347.0", - "@aws-sdk/middleware-host-header": "3.347.0", - "@aws-sdk/middleware-logger": "3.347.0", - "@aws-sdk/middleware-recursion-detection": "3.347.0", - "@aws-sdk/middleware-retry": "3.347.0", - "@aws-sdk/middleware-serde": "3.347.0", - "@aws-sdk/middleware-stack": "3.347.0", - "@aws-sdk/middleware-user-agent": "3.352.0", - "@aws-sdk/node-config-provider": "3.347.0", - "@aws-sdk/node-http-handler": "3.350.0", - "@aws-sdk/smithy-client": "3.347.0", - "@aws-sdk/types": "3.347.0", - "@aws-sdk/url-parser": "3.347.0", - "@aws-sdk/util-base64": "3.310.0", - "@aws-sdk/util-body-length-browser": "3.310.0", - "@aws-sdk/util-body-length-node": "3.310.0", - "@aws-sdk/util-defaults-mode-browser": "3.347.0", - "@aws-sdk/util-defaults-mode-node": "3.347.0", - "@aws-sdk/util-endpoints": "3.352.0", - "@aws-sdk/util-retry": "3.347.0", - "@aws-sdk/util-user-agent-browser": "3.347.0", - "@aws-sdk/util-user-agent-node": "3.347.0", - "@aws-sdk/util-utf8": "3.310.0", - "@smithy/protocol-http": "^1.0.1", - "@smithy/types": "^1.0.0", + "@aws-sdk/client-sts": "3.451.0", + "@aws-sdk/core": "3.451.0", + "@aws-sdk/credential-provider-node": "3.451.0", + "@aws-sdk/middleware-host-header": "3.451.0", + "@aws-sdk/middleware-logger": "3.451.0", + "@aws-sdk/middleware-recursion-detection": "3.451.0", + "@aws-sdk/middleware-signing": "3.451.0", + "@aws-sdk/middleware-user-agent": "3.451.0", + "@aws-sdk/region-config-resolver": "3.451.0", + "@aws-sdk/types": "3.451.0", + "@aws-sdk/util-endpoints": "3.451.0", + "@aws-sdk/util-user-agent-browser": "3.451.0", + "@aws-sdk/util-user-agent-node": "3.451.0", + "@smithy/config-resolver": "^2.0.18", + "@smithy/fetch-http-handler": "^2.2.6", + "@smithy/hash-node": "^2.0.15", + "@smithy/invalid-dependency": "^2.0.13", + "@smithy/middleware-content-length": "^2.0.15", + "@smithy/middleware-endpoint": "^2.2.0", + "@smithy/middleware-retry": "^2.0.20", + "@smithy/middleware-serde": "^2.0.13", + "@smithy/middleware-stack": "^2.0.7", + "@smithy/node-config-provider": "^2.1.5", + "@smithy/node-http-handler": "^2.1.9", + "@smithy/protocol-http": "^3.0.9", + "@smithy/smithy-client": "^2.1.15", + "@smithy/types": "^2.5.0", + "@smithy/url-parser": "^2.0.13", + "@smithy/util-base64": "^2.0.1", + "@smithy/util-body-length-browser": "^2.0.0", + "@smithy/util-body-length-node": "^2.1.0", + "@smithy/util-defaults-mode-browser": "^2.0.19", + "@smithy/util-defaults-mode-node": "^2.0.25", + "@smithy/util-endpoints": "^1.0.4", + "@smithy/util-retry": "^2.0.6", + "@smithy/util-utf8": "^2.0.2", + "@smithy/util-waiter": "^2.0.13", + "fast-xml-parser": "4.2.5", "tslib": "^2.5.0" } }, - "@aws-sdk/client-sso-oidc": { - "version": "3.352.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso-oidc/-/client-sso-oidc-3.352.0.tgz", - "integrity": "sha512-PQdp0KOr478CaJNohASTgtt03W8Y/qINwsalLNguK01tWIGzellg2N3bA+IdyYXU8Oz3+Ab1oIJMKkUxtuNiGg==", + "@aws-sdk/client-sso": { + "version": "3.451.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.451.0.tgz", + "integrity": "sha512-KkYSke3Pdv3MfVH/5fT528+MKjMyPKlcLcd4zQb0x6/7Bl7EHrPh1JZYjzPLHelb+UY5X0qN8+cb8iSu1eiwIQ==", "dev": true, "requires": { "@aws-crypto/sha256-browser": "3.0.0", "@aws-crypto/sha256-js": "3.0.0", - "@aws-sdk/config-resolver": "3.347.0", - "@aws-sdk/fetch-http-handler": "3.347.0", - "@aws-sdk/hash-node": "3.347.0", - "@aws-sdk/invalid-dependency": "3.347.0", - "@aws-sdk/middleware-content-length": "3.347.0", - "@aws-sdk/middleware-endpoint": "3.347.0", - "@aws-sdk/middleware-host-header": "3.347.0", - "@aws-sdk/middleware-logger": "3.347.0", - "@aws-sdk/middleware-recursion-detection": "3.347.0", - "@aws-sdk/middleware-retry": "3.347.0", - "@aws-sdk/middleware-serde": "3.347.0", - "@aws-sdk/middleware-stack": "3.347.0", - "@aws-sdk/middleware-user-agent": "3.352.0", - "@aws-sdk/node-config-provider": "3.347.0", - "@aws-sdk/node-http-handler": "3.350.0", - "@aws-sdk/smithy-client": "3.347.0", - "@aws-sdk/types": "3.347.0", - "@aws-sdk/url-parser": "3.347.0", - "@aws-sdk/util-base64": "3.310.0", - "@aws-sdk/util-body-length-browser": "3.310.0", - "@aws-sdk/util-body-length-node": "3.310.0", - "@aws-sdk/util-defaults-mode-browser": "3.347.0", - "@aws-sdk/util-defaults-mode-node": "3.347.0", - "@aws-sdk/util-endpoints": "3.352.0", - "@aws-sdk/util-retry": "3.347.0", - "@aws-sdk/util-user-agent-browser": "3.347.0", - "@aws-sdk/util-user-agent-node": "3.347.0", - "@aws-sdk/util-utf8": "3.310.0", - "@smithy/protocol-http": "^1.0.1", - "@smithy/types": "^1.0.0", + "@aws-sdk/core": "3.451.0", + "@aws-sdk/middleware-host-header": "3.451.0", + "@aws-sdk/middleware-logger": "3.451.0", + "@aws-sdk/middleware-recursion-detection": "3.451.0", + "@aws-sdk/middleware-user-agent": "3.451.0", + "@aws-sdk/region-config-resolver": "3.451.0", + "@aws-sdk/types": "3.451.0", + "@aws-sdk/util-endpoints": "3.451.0", + "@aws-sdk/util-user-agent-browser": "3.451.0", + "@aws-sdk/util-user-agent-node": "3.451.0", + "@smithy/config-resolver": "^2.0.18", + "@smithy/fetch-http-handler": "^2.2.6", + "@smithy/hash-node": "^2.0.15", + "@smithy/invalid-dependency": "^2.0.13", + "@smithy/middleware-content-length": "^2.0.15", + "@smithy/middleware-endpoint": "^2.2.0", + "@smithy/middleware-retry": "^2.0.20", + "@smithy/middleware-serde": "^2.0.13", + "@smithy/middleware-stack": "^2.0.7", + "@smithy/node-config-provider": "^2.1.5", + "@smithy/node-http-handler": "^2.1.9", + "@smithy/protocol-http": "^3.0.9", + "@smithy/smithy-client": "^2.1.15", + "@smithy/types": "^2.5.0", + "@smithy/url-parser": "^2.0.13", + "@smithy/util-base64": "^2.0.1", + "@smithy/util-body-length-browser": "^2.0.0", + "@smithy/util-body-length-node": "^2.1.0", + "@smithy/util-defaults-mode-browser": "^2.0.19", + "@smithy/util-defaults-mode-node": "^2.0.25", + "@smithy/util-endpoints": "^1.0.4", + "@smithy/util-retry": "^2.0.6", + "@smithy/util-utf8": "^2.0.2", "tslib": "^2.5.0" } }, "@aws-sdk/client-sts": { - "version": "3.352.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.352.0.tgz", - "integrity": "sha512-Lt7uSdwgOrwYx8S6Bhz76ewOeoJNFiPD+Q7v8S/mJK8T7HUE/houjomXC3UnFaJjcecjWv273zEqV67FgP5l5g==", + "version": "3.451.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.451.0.tgz", + "integrity": "sha512-48NcIRxWBdP1fom6RSjwn2R2u7SE7eeV3p+c4s7ukEOfrHhBxJfn3EpqBVQMGzdiU55qFImy+Fe81iA2lXq3Jw==", "dev": true, "requires": { "@aws-crypto/sha256-browser": "3.0.0", "@aws-crypto/sha256-js": "3.0.0", - "@aws-sdk/config-resolver": "3.347.0", - "@aws-sdk/credential-provider-node": "3.352.0", - "@aws-sdk/fetch-http-handler": "3.347.0", - "@aws-sdk/hash-node": "3.347.0", - "@aws-sdk/invalid-dependency": "3.347.0", - "@aws-sdk/middleware-content-length": "3.347.0", - "@aws-sdk/middleware-endpoint": "3.347.0", - "@aws-sdk/middleware-host-header": "3.347.0", - "@aws-sdk/middleware-logger": "3.347.0", - "@aws-sdk/middleware-recursion-detection": "3.347.0", - "@aws-sdk/middleware-retry": "3.347.0", - "@aws-sdk/middleware-sdk-sts": "3.347.0", - "@aws-sdk/middleware-serde": "3.347.0", - "@aws-sdk/middleware-signing": "3.347.0", - "@aws-sdk/middleware-stack": "3.347.0", - "@aws-sdk/middleware-user-agent": "3.352.0", - "@aws-sdk/node-config-provider": "3.347.0", - "@aws-sdk/node-http-handler": "3.350.0", - "@aws-sdk/smithy-client": "3.347.0", - "@aws-sdk/types": "3.347.0", - "@aws-sdk/url-parser": "3.347.0", - "@aws-sdk/util-base64": "3.310.0", - "@aws-sdk/util-body-length-browser": "3.310.0", - "@aws-sdk/util-body-length-node": "3.310.0", - "@aws-sdk/util-defaults-mode-browser": "3.347.0", - "@aws-sdk/util-defaults-mode-node": "3.347.0", - "@aws-sdk/util-endpoints": "3.352.0", - "@aws-sdk/util-retry": "3.347.0", - "@aws-sdk/util-user-agent-browser": "3.347.0", - "@aws-sdk/util-user-agent-node": "3.347.0", - "@aws-sdk/util-utf8": "3.310.0", - "@smithy/protocol-http": "^1.0.1", - "@smithy/types": "^1.0.0", - "fast-xml-parser": "4.2.4", + "@aws-sdk/core": "3.451.0", + "@aws-sdk/credential-provider-node": "3.451.0", + "@aws-sdk/middleware-host-header": "3.451.0", + "@aws-sdk/middleware-logger": "3.451.0", + "@aws-sdk/middleware-recursion-detection": "3.451.0", + "@aws-sdk/middleware-sdk-sts": "3.451.0", + "@aws-sdk/middleware-signing": "3.451.0", + "@aws-sdk/middleware-user-agent": "3.451.0", + "@aws-sdk/region-config-resolver": "3.451.0", + "@aws-sdk/types": "3.451.0", + "@aws-sdk/util-endpoints": "3.451.0", + "@aws-sdk/util-user-agent-browser": "3.451.0", + "@aws-sdk/util-user-agent-node": "3.451.0", + "@smithy/config-resolver": "^2.0.18", + "@smithy/fetch-http-handler": "^2.2.6", + "@smithy/hash-node": "^2.0.15", + "@smithy/invalid-dependency": "^2.0.13", + "@smithy/middleware-content-length": "^2.0.15", + "@smithy/middleware-endpoint": "^2.2.0", + "@smithy/middleware-retry": "^2.0.20", + "@smithy/middleware-serde": "^2.0.13", + "@smithy/middleware-stack": "^2.0.7", + "@smithy/node-config-provider": "^2.1.5", + "@smithy/node-http-handler": "^2.1.9", + "@smithy/protocol-http": "^3.0.9", + "@smithy/smithy-client": "^2.1.15", + "@smithy/types": "^2.5.0", + "@smithy/url-parser": "^2.0.13", + "@smithy/util-base64": "^2.0.1", + "@smithy/util-body-length-browser": "^2.0.0", + "@smithy/util-body-length-node": "^2.1.0", + "@smithy/util-defaults-mode-browser": "^2.0.19", + "@smithy/util-defaults-mode-node": "^2.0.25", + "@smithy/util-endpoints": "^1.0.4", + "@smithy/util-retry": "^2.0.6", + "@smithy/util-utf8": "^2.0.2", + "fast-xml-parser": "4.2.5", "tslib": "^2.5.0" } }, - "@aws-sdk/config-resolver": { - "version": "3.347.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/config-resolver/-/config-resolver-3.347.0.tgz", - "integrity": "sha512-2ja+Sf/VnUO7IQ3nKbDQ5aumYKKJUaTm/BuVJ29wNho8wYHfuf7wHZV0pDTkB8RF5SH7IpHap7zpZAj39Iq+EA==", + "@aws-sdk/core": { + "version": "3.451.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.451.0.tgz", + "integrity": "sha512-SamWW2zHEf1ZKe3j1w0Piauryl8BQIlej0TBS18A4ACzhjhWXhCs13bO1S88LvPR5mBFXok3XOT6zPOnKDFktw==", "dev": true, "requires": { - "@aws-sdk/types": "3.347.0", - "@aws-sdk/util-config-provider": "3.310.0", - "@aws-sdk/util-middleware": "3.347.0", + "@smithy/smithy-client": "^2.1.15", "tslib": "^2.5.0" } }, "@aws-sdk/credential-provider-env": { - "version": "3.347.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.347.0.tgz", - "integrity": "sha512-UnEM+LKGpXKzw/1WvYEQsC6Wj9PupYZdQOE+e2Dgy2dqk/pVFy4WueRtFXYDT2B41ppv3drdXUuKZRIDVqIgNQ==", - "dev": true, - "requires": { - "@aws-sdk/property-provider": "3.347.0", - "@aws-sdk/types": "3.347.0", - "tslib": "^2.5.0" - } - }, - "@aws-sdk/credential-provider-imds": { - "version": "3.347.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-imds/-/credential-provider-imds-3.347.0.tgz", - "integrity": "sha512-7scCy/DCDRLIhlqTxff97LQWDnRwRXji3bxxMg+xWOTTaJe7PWx+etGSbBWaL42vsBHFShQjSLvJryEgoBktpw==", + "version": "3.451.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.451.0.tgz", + "integrity": "sha512-9dAav7DcRgaF7xCJEQR5ER9ErXxnu/tdnVJ+UPmb1NPeIZdESv1A3lxFDEq1Fs8c4/lzAj9BpshGyJVIZwZDKg==", "dev": true, "requires": { - "@aws-sdk/node-config-provider": "3.347.0", - "@aws-sdk/property-provider": "3.347.0", - "@aws-sdk/types": "3.347.0", - "@aws-sdk/url-parser": "3.347.0", + "@aws-sdk/types": "3.451.0", + "@smithy/property-provider": "^2.0.0", + "@smithy/types": "^2.5.0", "tslib": "^2.5.0" } }, "@aws-sdk/credential-provider-ini": { - "version": "3.352.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.352.0.tgz", - "integrity": "sha512-lnQUJznvOhI2er1u/OVf99/2JIyDH7W+6tfWNXEoVgEi4WXtdyZ+GpPNoZsmCtHB2Jwlsh51IxmYdCj6b6SdwQ==", - "dev": true, - "requires": { - "@aws-sdk/credential-provider-env": "3.347.0", - "@aws-sdk/credential-provider-imds": "3.347.0", - "@aws-sdk/credential-provider-process": "3.347.0", - "@aws-sdk/credential-provider-sso": "3.352.0", - "@aws-sdk/credential-provider-web-identity": "3.347.0", - "@aws-sdk/property-provider": "3.347.0", - "@aws-sdk/shared-ini-file-loader": "3.347.0", - "@aws-sdk/types": "3.347.0", + "version": "3.451.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.451.0.tgz", + "integrity": "sha512-TySt64Ci5/ZbqFw1F9Z0FIGvYx5JSC9e6gqDnizIYd8eMnn8wFRUscRrD7pIHKfrhvVKN5h0GdYovmMO/FMCBw==", + "dev": true, + "requires": { + "@aws-sdk/credential-provider-env": "3.451.0", + "@aws-sdk/credential-provider-process": "3.451.0", + "@aws-sdk/credential-provider-sso": "3.451.0", + "@aws-sdk/credential-provider-web-identity": "3.451.0", + "@aws-sdk/types": "3.451.0", + "@smithy/credential-provider-imds": "^2.0.0", + "@smithy/property-provider": "^2.0.0", + "@smithy/shared-ini-file-loader": "^2.0.6", + "@smithy/types": "^2.5.0", "tslib": "^2.5.0" } }, "@aws-sdk/credential-provider-node": { - "version": "3.352.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.352.0.tgz", - "integrity": "sha512-8UZ5EQpoqHCh+XSGq2CdhzHZyKLOwF1taDw5A/gmV4O5lAWL0AGs0cPIEUORJyggU6Hv43zZOpLgK6dMgWOLgA==", - "dev": true, - "requires": { - "@aws-sdk/credential-provider-env": "3.347.0", - "@aws-sdk/credential-provider-imds": "3.347.0", - "@aws-sdk/credential-provider-ini": "3.352.0", - "@aws-sdk/credential-provider-process": "3.347.0", - "@aws-sdk/credential-provider-sso": "3.352.0", - "@aws-sdk/credential-provider-web-identity": "3.347.0", - "@aws-sdk/property-provider": "3.347.0", - "@aws-sdk/shared-ini-file-loader": "3.347.0", - "@aws-sdk/types": "3.347.0", + "version": "3.451.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.451.0.tgz", + "integrity": "sha512-AEwM1WPyxUdKrKyUsKyFqqRFGU70e4qlDyrtBxJnSU9NRLZI8tfEZ67bN7fHSxBUBODgDXpMSlSvJiBLh5/3pw==", + "dev": true, + "requires": { + "@aws-sdk/credential-provider-env": "3.451.0", + "@aws-sdk/credential-provider-ini": "3.451.0", + "@aws-sdk/credential-provider-process": "3.451.0", + "@aws-sdk/credential-provider-sso": "3.451.0", + "@aws-sdk/credential-provider-web-identity": "3.451.0", + "@aws-sdk/types": "3.451.0", + "@smithy/credential-provider-imds": "^2.0.0", + "@smithy/property-provider": "^2.0.0", + "@smithy/shared-ini-file-loader": "^2.0.6", + "@smithy/types": "^2.5.0", "tslib": "^2.5.0" } }, "@aws-sdk/credential-provider-process": { - "version": "3.347.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.347.0.tgz", - "integrity": "sha512-yl1z4MsaBdXd4GQ2halIvYds23S67kElyOwz7g8kaQ4kHj+UoYWxz3JVW/DGusM6XmQ9/F67utBrUVA0uhQYyw==", + "version": "3.451.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.451.0.tgz", + "integrity": "sha512-HQywSdKeD5PErcLLnZfSyCJO+6T+ZyzF+Lm/QgscSC+CbSUSIPi//s15qhBRVely/3KBV6AywxwNH+5eYgt4lQ==", "dev": true, "requires": { - "@aws-sdk/property-provider": "3.347.0", - "@aws-sdk/shared-ini-file-loader": "3.347.0", - "@aws-sdk/types": "3.347.0", + "@aws-sdk/types": "3.451.0", + "@smithy/property-provider": "^2.0.0", + "@smithy/shared-ini-file-loader": "^2.0.6", + "@smithy/types": "^2.5.0", "tslib": "^2.5.0" } }, "@aws-sdk/credential-provider-sso": { - "version": "3.352.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.352.0.tgz", - "integrity": "sha512-YiooGNy9LYN1bFqKwO2wHC++1pYReiSqQDWBeluJfC3uZWpCyIUMdeYBR1X3XZDVtK6bl5KmhxldxJ3ntt/Q4w==", + "version": "3.451.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.451.0.tgz", + "integrity": "sha512-Usm/N51+unOt8ID4HnQzxIjUJDrkAQ1vyTOC0gSEEJ7h64NSSPGD5yhN7il5WcErtRd3EEtT1a8/GTC5TdBctg==", "dev": true, "requires": { - "@aws-sdk/client-sso": "3.352.0", - "@aws-sdk/property-provider": "3.347.0", - "@aws-sdk/shared-ini-file-loader": "3.347.0", - "@aws-sdk/token-providers": "3.352.0", - "@aws-sdk/types": "3.347.0", + "@aws-sdk/client-sso": "3.451.0", + "@aws-sdk/token-providers": "3.451.0", + "@aws-sdk/types": "3.451.0", + "@smithy/property-provider": "^2.0.0", + "@smithy/shared-ini-file-loader": "^2.0.6", + "@smithy/types": "^2.5.0", "tslib": "^2.5.0" } }, "@aws-sdk/credential-provider-web-identity": { - "version": "3.347.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.347.0.tgz", - "integrity": "sha512-DxoTlVK8lXjS1zVphtz/Ab+jkN/IZor9d6pP2GjJHNoAIIzXfRwwj5C8vr4eTayx/5VJ7GRP91J8GJ2cKly8Qw==", - "dev": true, - "requires": { - "@aws-sdk/property-provider": "3.347.0", - "@aws-sdk/types": "3.347.0", - "tslib": "^2.5.0" - } - }, - "@aws-sdk/eventstream-codec": { - "version": "3.347.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/eventstream-codec/-/eventstream-codec-3.347.0.tgz", - "integrity": "sha512-61q+SyspjsaQ4sdgjizMyRgVph2CiW4aAtfpoH69EJFJfTxTR/OqnZ9Jx/3YiYi0ksrvDenJddYodfWWJqD8/w==", - "dev": true, - "requires": { - "@aws-crypto/crc32": "3.0.0", - "@aws-sdk/types": "3.347.0", - "@aws-sdk/util-hex-encoding": "3.310.0", - "tslib": "^2.5.0" - } - }, - "@aws-sdk/fetch-http-handler": { - "version": "3.347.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/fetch-http-handler/-/fetch-http-handler-3.347.0.tgz", - "integrity": "sha512-sQ5P7ivY8//7wdxfA76LT1sF6V2Tyyz1qF6xXf9sihPN5Q1Y65c+SKpMzXyFSPqWZ82+SQQuDliYZouVyS6kQQ==", - "dev": true, - "requires": { - "@aws-sdk/protocol-http": "3.347.0", - "@aws-sdk/querystring-builder": "3.347.0", - "@aws-sdk/types": "3.347.0", - "@aws-sdk/util-base64": "3.310.0", - "tslib": "^2.5.0" - } - }, - "@aws-sdk/hash-node": { - "version": "3.347.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/hash-node/-/hash-node-3.347.0.tgz", - "integrity": "sha512-96+ml/4EaUaVpzBdOLGOxdoXOjkPgkoJp/0i1fxOJEvl8wdAQSwc3IugVK9wZkCxy2DlENtgOe6DfIOhfffm/g==", - "dev": true, - "requires": { - "@aws-sdk/types": "3.347.0", - "@aws-sdk/util-buffer-from": "3.310.0", - "@aws-sdk/util-utf8": "3.310.0", - "tslib": "^2.5.0" - } - }, - "@aws-sdk/invalid-dependency": { - "version": "3.347.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/invalid-dependency/-/invalid-dependency-3.347.0.tgz", - "integrity": "sha512-8imQcwLwqZ/wTJXZqzXT9pGLIksTRckhGLZaXT60tiBOPKuerTsus2L59UstLs5LP8TKaVZKFFSsjRIn9dQdmQ==", - "dev": true, - "requires": { - "@aws-sdk/types": "3.347.0", - "tslib": "^2.5.0" - } - }, - "@aws-sdk/is-array-buffer": { - "version": "3.310.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/is-array-buffer/-/is-array-buffer-3.310.0.tgz", - "integrity": "sha512-urnbcCR+h9NWUnmOtet/s4ghvzsidFmspfhYaHAmSRdy9yDjdjBJMFjjsn85A1ODUktztm+cVncXjQ38WCMjMQ==", - "dev": true, - "requires": { - "tslib": "^2.5.0" - } - }, - "@aws-sdk/middleware-content-length": { - "version": "3.347.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-content-length/-/middleware-content-length-3.347.0.tgz", - "integrity": "sha512-i4qtWTDImMaDUtwKQPbaZpXsReiwiBomM1cWymCU4bhz81HL01oIxOxOBuiM+3NlDoCSPr3KI6txZSz/8cqXCQ==", - "dev": true, - "requires": { - "@aws-sdk/protocol-http": "3.347.0", - "@aws-sdk/types": "3.347.0", - "tslib": "^2.5.0" - } - }, - "@aws-sdk/middleware-endpoint": { - "version": "3.347.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-endpoint/-/middleware-endpoint-3.347.0.tgz", - "integrity": "sha512-unF0c6dMaUL1ffU+37Ugty43DgMnzPWXr/Jup/8GbK5fzzWT5NQq6dj9KHPubMbWeEjQbmczvhv25JuJdK8gNQ==", + "version": "3.451.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.451.0.tgz", + "integrity": "sha512-Xtg3Qw65EfDjWNG7o2xD6sEmumPfsy3WDGjk2phEzVg8s7hcZGxf5wYwe6UY7RJvlEKrU0rFA+AMn6Hfj5oOzg==", "dev": true, "requires": { - "@aws-sdk/middleware-serde": "3.347.0", - "@aws-sdk/types": "3.347.0", - "@aws-sdk/url-parser": "3.347.0", - "@aws-sdk/util-middleware": "3.347.0", + "@aws-sdk/types": "3.451.0", + "@smithy/property-provider": "^2.0.0", + "@smithy/types": "^2.5.0", "tslib": "^2.5.0" } }, "@aws-sdk/middleware-host-header": { - "version": "3.347.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.347.0.tgz", - "integrity": "sha512-kpKmR9OvMlnReqp5sKcJkozbj1wmlblbVSbnQAIkzeQj2xD5dnVR3Nn2ogQKxSmU1Fv7dEroBtrruJ1o3fY38A==", + "version": "3.451.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.451.0.tgz", + "integrity": "sha512-j8a5jAfhWmsK99i2k8oR8zzQgXrsJtgrLxc3js6U+525mcZytoiDndkWTmD5fjJ1byU1U2E5TaPq+QJeDip05Q==", "dev": true, "requires": { - "@aws-sdk/protocol-http": "3.347.0", - "@aws-sdk/types": "3.347.0", + "@aws-sdk/types": "3.451.0", + "@smithy/protocol-http": "^3.0.9", + "@smithy/types": "^2.5.0", "tslib": "^2.5.0" } }, "@aws-sdk/middleware-logger": { - "version": "3.347.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.347.0.tgz", - "integrity": "sha512-NYC+Id5UCkVn+3P1t/YtmHt75uED06vwaKyxDy0UmB2K66PZLVtwWbLpVWrhbroaw1bvUHYcRyQ9NIfnVcXQjA==", + "version": "3.451.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.451.0.tgz", + "integrity": "sha512-0kHrYEyVeB2QBfP6TfbI240aRtatLZtcErJbhpiNUb+CQPgEL3crIjgVE8yYiJumZ7f0jyjo8HLPkwD1/2APaw==", "dev": true, "requires": { - "@aws-sdk/types": "3.347.0", + "@aws-sdk/types": "3.451.0", + "@smithy/types": "^2.5.0", "tslib": "^2.5.0" } }, "@aws-sdk/middleware-recursion-detection": { - "version": "3.347.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.347.0.tgz", - "integrity": "sha512-qfnSvkFKCAMjMHR31NdsT0gv5Sq/ZHTUD4yQsSLpbVQ6iYAS834lrzXt41iyEHt57Y514uG7F/Xfvude3u4icQ==", + "version": "3.451.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.451.0.tgz", + "integrity": "sha512-J6jL6gJ7orjHGM70KDRcCP7so/J2SnkN4vZ9YRLTeeZY6zvBuHDjX8GCIgSqPn/nXFXckZO8XSnA7u6+3TAT0w==", "dev": true, "requires": { - "@aws-sdk/protocol-http": "3.347.0", - "@aws-sdk/types": "3.347.0", + "@aws-sdk/types": "3.451.0", + "@smithy/protocol-http": "^3.0.9", + "@smithy/types": "^2.5.0", "tslib": "^2.5.0" } }, - "@aws-sdk/middleware-retry": { - "version": "3.347.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-retry/-/middleware-retry-3.347.0.tgz", - "integrity": "sha512-CpdM+8dCSbX96agy4FCzOfzDmhNnGBM/pxrgIVLm5nkYTLuXp/d7ubpFEUHULr+4hCd5wakHotMt7yO29NFaVw==", - "dev": true, - "requires": { - "@aws-sdk/protocol-http": "3.347.0", - "@aws-sdk/service-error-classification": "3.347.0", - "@aws-sdk/types": "3.347.0", - "@aws-sdk/util-middleware": "3.347.0", - "@aws-sdk/util-retry": "3.347.0", - "tslib": "^2.5.0", - "uuid": "^8.3.2" - } - }, "@aws-sdk/middleware-sdk-sts": { - "version": "3.347.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-sdk-sts/-/middleware-sdk-sts-3.347.0.tgz", - "integrity": "sha512-38LJ0bkIoVF3W97x6Jyyou72YV9Cfbml4OaDEdnrCOo0EssNZM5d7RhjMvQDwww7/3OBY/BzeOcZKfJlkYUXGw==", - "dev": true, - "requires": { - "@aws-sdk/middleware-signing": "3.347.0", - "@aws-sdk/types": "3.347.0", - "tslib": "^2.5.0" - } - }, - "@aws-sdk/middleware-serde": { - "version": "3.347.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-serde/-/middleware-serde-3.347.0.tgz", - "integrity": "sha512-x5Foi7jRbVJXDu9bHfyCbhYDH5pKK+31MmsSJ3k8rY8keXLBxm2XEEg/AIoV9/TUF9EeVvZ7F1/RmMpJnWQsEg==", - "dev": true, - "requires": { - "@aws-sdk/types": "3.347.0", - "tslib": "^2.5.0" - } - }, - "@aws-sdk/middleware-signing": { - "version": "3.347.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-signing/-/middleware-signing-3.347.0.tgz", - "integrity": "sha512-zVBF/4MGKnvhAE/J+oAL/VAehiyv+trs2dqSQXwHou9j8eA8Vm8HS2NdOwpkZQchIxTuwFlqSusDuPEdYFbvGw==", - "dev": true, - "requires": { - "@aws-sdk/property-provider": "3.347.0", - "@aws-sdk/protocol-http": "3.347.0", - "@aws-sdk/signature-v4": "3.347.0", - "@aws-sdk/types": "3.347.0", - "@aws-sdk/util-middleware": "3.347.0", - "tslib": "^2.5.0" - } - }, - "@aws-sdk/middleware-stack": { - "version": "3.347.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-stack/-/middleware-stack-3.347.0.tgz", - "integrity": "sha512-Izidg4rqtYMcKuvn2UzgEpPLSmyd8ub9+LQ2oIzG3mpIzCBITq7wp40jN1iNkMg+X6KEnX9vdMJIYZsPYMCYuQ==", - "dev": true, - "requires": { - "tslib": "^2.5.0" - } - }, - "@aws-sdk/middleware-user-agent": { - "version": "3.352.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.352.0.tgz", - "integrity": "sha512-QGqblMTsVDqeomy22KPm9LUW8PHZXBA2Hjk9Hcw8U1uFS8IKYJrewInG3ae2+9FAcTyug4LFWDf8CRr9YH2B3Q==", - "dev": true, - "requires": { - "@aws-sdk/protocol-http": "3.347.0", - "@aws-sdk/types": "3.347.0", - "@aws-sdk/util-endpoints": "3.352.0", - "tslib": "^2.5.0" - } - }, - "@aws-sdk/node-config-provider": { - "version": "3.347.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/node-config-provider/-/node-config-provider-3.347.0.tgz", - "integrity": "sha512-faU93d3+5uTTUcotGgMXF+sJVFjrKh+ufW+CzYKT4yUHammyaIab/IbTPWy2hIolcEGtuPeVoxXw8TXbkh/tuw==", - "dev": true, - "requires": { - "@aws-sdk/property-provider": "3.347.0", - "@aws-sdk/shared-ini-file-loader": "3.347.0", - "@aws-sdk/types": "3.347.0", - "tslib": "^2.5.0" - } - }, - "@aws-sdk/node-http-handler": { - "version": "3.350.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/node-http-handler/-/node-http-handler-3.350.0.tgz", - "integrity": "sha512-oD96GAlmpzYilCdC8wwyURM5lNfNHZCjm/kxBkQulHKa2kRbIrnD9GfDqdCkWA5cTpjh1NzGLT4D6e6UFDjt9w==", - "dev": true, - "requires": { - "@aws-sdk/abort-controller": "3.347.0", - "@aws-sdk/protocol-http": "3.347.0", - "@aws-sdk/querystring-builder": "3.347.0", - "@aws-sdk/types": "3.347.0", - "tslib": "^2.5.0" - } - }, - "@aws-sdk/property-provider": { - "version": "3.347.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/property-provider/-/property-provider-3.347.0.tgz", - "integrity": "sha512-t3nJ8CYPLKAF2v9nIHOHOlF0CviQbTvbFc2L4a+A+EVd/rM4PzL3+3n8ZJsr0h7f6uD04+b5YRFgKgnaqLXlEg==", - "dev": true, - "requires": { - "@aws-sdk/types": "3.347.0", - "tslib": "^2.5.0" - } - }, - "@aws-sdk/protocol-http": { - "version": "3.347.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/protocol-http/-/protocol-http-3.347.0.tgz", - "integrity": "sha512-2YdBhc02Wvy03YjhGwUxF0UQgrPWEy8Iq75pfS42N+/0B/+eWX1aQgfjFxIpLg7YSjT5eKtYOQGlYd4MFTgj9g==", - "dev": true, - "requires": { - "@aws-sdk/types": "3.347.0", - "tslib": "^2.5.0" - } - }, - "@aws-sdk/querystring-builder": { - "version": "3.347.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/querystring-builder/-/querystring-builder-3.347.0.tgz", - "integrity": "sha512-phtKTe6FXoV02MoPkIVV6owXI8Mwr5IBN3bPoxhcPvJG2AjEmnetSIrhb8kwc4oNhlwfZwH6Jo5ARW/VEWbZtg==", - "dev": true, - "requires": { - "@aws-sdk/types": "3.347.0", - "@aws-sdk/util-uri-escape": "3.310.0", - "tslib": "^2.5.0" - } - }, - "@aws-sdk/querystring-parser": { - "version": "3.347.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/querystring-parser/-/querystring-parser-3.347.0.tgz", - "integrity": "sha512-5VXOhfZz78T2W7SuXf2avfjKglx1VZgZgp9Zfhrt/Rq+MTu2D+PZc5zmJHhYigD7x83jLSLogpuInQpFMA9LgA==", - "dev": true, - "requires": { - "@aws-sdk/types": "3.347.0", - "tslib": "^2.5.0" - } - }, - "@aws-sdk/service-error-classification": { - "version": "3.347.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/service-error-classification/-/service-error-classification-3.347.0.tgz", - "integrity": "sha512-xZ3MqSY81Oy2gh5g0fCtooAbahqh9VhsF8vcKjVX8+XPbGC8y+kej82+MsMg4gYL8gRFB9u4hgYbNgIS6JTAvg==", - "dev": true - }, - "@aws-sdk/shared-ini-file-loader": { - "version": "3.347.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/shared-ini-file-loader/-/shared-ini-file-loader-3.347.0.tgz", - "integrity": "sha512-Xw+zAZQVLb+xMNHChXQ29tzzLqm3AEHsD8JJnlkeFjeMnWQtXdUfOARl5s8NzAppcKQNlVe2gPzjaKjoy2jz1Q==", - "dev": true, - "requires": { - "@aws-sdk/types": "3.347.0", - "tslib": "^2.5.0" - } - }, - "@aws-sdk/signature-v4": { - "version": "3.347.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/signature-v4/-/signature-v4-3.347.0.tgz", - "integrity": "sha512-58Uq1do+VsTHYkP11dTK+DF53fguoNNJL9rHRWhzP+OcYv3/mBMLoS2WPz/x9FO5mBg4ESFsug0I6mXbd36tjw==", - "dev": true, - "requires": { - "@aws-sdk/eventstream-codec": "3.347.0", - "@aws-sdk/is-array-buffer": "3.310.0", - "@aws-sdk/types": "3.347.0", - "@aws-sdk/util-hex-encoding": "3.310.0", - "@aws-sdk/util-middleware": "3.347.0", - "@aws-sdk/util-uri-escape": "3.310.0", - "@aws-sdk/util-utf8": "3.310.0", - "tslib": "^2.5.0" - } - }, - "@aws-sdk/smithy-client": { - "version": "3.347.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/smithy-client/-/smithy-client-3.347.0.tgz", - "integrity": "sha512-PaGTDsJLGK0sTjA6YdYQzILRlPRN3uVFyqeBUkfltXssvUzkm8z2t1lz2H4VyJLAhwnG5ZuZTNEV/2mcWrU7JQ==", - "dev": true, - "requires": { - "@aws-sdk/middleware-stack": "3.347.0", - "@aws-sdk/types": "3.347.0", - "tslib": "^2.5.0" - } - }, - "@aws-sdk/token-providers": { - "version": "3.352.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.352.0.tgz", - "integrity": "sha512-cmmAgieLP/aAl9WdPiBoaC0Abd6KncSLig/ElLPoNsADR10l3QgxQcVF3YMtdX0U0d917+/SeE1PdrPD2x15cw==", - "dev": true, - "requires": { - "@aws-sdk/client-sso-oidc": "3.352.0", - "@aws-sdk/property-provider": "3.347.0", - "@aws-sdk/shared-ini-file-loader": "3.347.0", - "@aws-sdk/types": "3.347.0", - "tslib": "^2.5.0" - } - }, - "@aws-sdk/types": { - "version": "3.347.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.347.0.tgz", - "integrity": "sha512-GkCMy79mdjU9OTIe5KT58fI/6uqdf8UmMdWqVHmFJ+UpEzOci7L/uw4sOXWo7xpPzLs6cJ7s5ouGZW4GRPmHFA==", - "dev": true, - "requires": { - "tslib": "^2.5.0" - } - }, - "@aws-sdk/url-parser": { - "version": "3.347.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/url-parser/-/url-parser-3.347.0.tgz", - "integrity": "sha512-lhrnVjxdV7hl+yCnJfDZOaVLSqKjxN20MIOiijRiqaWGLGEAiSqBreMhL89X1WKCifxAs4zZf9YB9SbdziRpAA==", - "dev": true, - "requires": { - "@aws-sdk/querystring-parser": "3.347.0", - "@aws-sdk/types": "3.347.0", - "tslib": "^2.5.0" - } - }, - "@aws-sdk/util-base64": { - "version": "3.310.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-base64/-/util-base64-3.310.0.tgz", - "integrity": "sha512-v3+HBKQvqgdzcbL+pFswlx5HQsd9L6ZTlyPVL2LS9nNXnCcR3XgGz9jRskikRUuUvUXtkSG1J88GAOnJ/apTPg==", - "dev": true, - "requires": { - "@aws-sdk/util-buffer-from": "3.310.0", - "tslib": "^2.5.0" - } - }, - "@aws-sdk/util-body-length-browser": { - "version": "3.310.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-body-length-browser/-/util-body-length-browser-3.310.0.tgz", - "integrity": "sha512-sxsC3lPBGfpHtNTUoGXMQXLwjmR0zVpx0rSvzTPAuoVILVsp5AU/w5FphNPxD5OVIjNbZv9KsKTuvNTiZjDp9g==", - "dev": true, - "requires": { - "tslib": "^2.5.0" - } - }, - "@aws-sdk/util-body-length-node": { - "version": "3.310.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-body-length-node/-/util-body-length-node-3.310.0.tgz", - "integrity": "sha512-2tqGXdyKhyA6w4zz7UPoS8Ip+7sayOg9BwHNidiGm2ikbDxm1YrCfYXvCBdwaJxa4hJfRVz+aL9e+d3GqPI9pQ==", - "dev": true, - "requires": { - "tslib": "^2.5.0" - } - }, - "@aws-sdk/util-buffer-from": { - "version": "3.310.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-buffer-from/-/util-buffer-from-3.310.0.tgz", - "integrity": "sha512-i6LVeXFtGih5Zs8enLrt+ExXY92QV25jtEnTKHsmlFqFAuL3VBeod6boeMXkN2p9lbSVVQ1sAOOYZOHYbYkntw==", - "dev": true, - "requires": { - "@aws-sdk/is-array-buffer": "3.310.0", - "tslib": "^2.5.0" - } - }, - "@aws-sdk/util-config-provider": { - "version": "3.310.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-config-provider/-/util-config-provider-3.310.0.tgz", - "integrity": "sha512-xIBaYo8dwiojCw8vnUcIL4Z5tyfb1v3yjqyJKJWV/dqKUFOOS0U591plmXbM+M/QkXyML3ypon1f8+BoaDExrg==", - "dev": true, - "requires": { - "tslib": "^2.5.0" - } - }, - "@aws-sdk/util-defaults-mode-browser": { - "version": "3.347.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-defaults-mode-browser/-/util-defaults-mode-browser-3.347.0.tgz", - "integrity": "sha512-+JHFA4reWnW/nMWwrLKqL2Lm/biw/Dzi/Ix54DAkRZ08C462jMKVnUlzAI+TfxQE3YLm99EIa0G7jiEA+p81Qw==", + "version": "3.451.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-sdk-sts/-/middleware-sdk-sts-3.451.0.tgz", + "integrity": "sha512-UJ6UfVUEgp0KIztxpAeelPXI5MLj9wUtUCqYeIMP7C1ZhoEMNm3G39VLkGN43dNhBf1LqjsV9jkKMZbVfYXuwg==", "dev": true, "requires": { - "@aws-sdk/property-provider": "3.347.0", - "@aws-sdk/types": "3.347.0", - "bowser": "^2.11.0", + "@aws-sdk/middleware-signing": "3.451.0", + "@aws-sdk/types": "3.451.0", + "@smithy/types": "^2.5.0", "tslib": "^2.5.0" } }, - "@aws-sdk/util-defaults-mode-node": { - "version": "3.347.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-defaults-mode-node/-/util-defaults-mode-node-3.347.0.tgz", - "integrity": "sha512-A8BzIVhAAZE5WEukoAN2kYebzTc99ZgncbwOmgCCbvdaYlk5tzguR/s+uoT4G0JgQGol/4hAMuJEl7elNgU6RQ==", + "@aws-sdk/middleware-signing": { + "version": "3.451.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-signing/-/middleware-signing-3.451.0.tgz", + "integrity": "sha512-s5ZlcIoLNg1Huj4Qp06iKniE8nJt/Pj1B/fjhWc6cCPCM7XJYUCejCnRh6C5ZJoBEYodjuwZBejPc1Wh3j+znA==", "dev": true, "requires": { - "@aws-sdk/config-resolver": "3.347.0", - "@aws-sdk/credential-provider-imds": "3.347.0", - "@aws-sdk/node-config-provider": "3.347.0", - "@aws-sdk/property-provider": "3.347.0", - "@aws-sdk/types": "3.347.0", + "@aws-sdk/types": "3.451.0", + "@smithy/property-provider": "^2.0.0", + "@smithy/protocol-http": "^3.0.9", + "@smithy/signature-v4": "^2.0.0", + "@smithy/types": "^2.5.0", + "@smithy/util-middleware": "^2.0.6", "tslib": "^2.5.0" } }, - "@aws-sdk/util-endpoints": { - "version": "3.352.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.352.0.tgz", - "integrity": "sha512-PjWMPdoIUWfBPgAWLyOrWFbdSS/3DJtc0OmFb/JrE8C8rKFYl+VGW5f1p0cVdRWiDR0xCGr0s67p8itAakVqjw==", + "@aws-sdk/middleware-user-agent": { + "version": "3.451.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.451.0.tgz", + "integrity": "sha512-8NM/0JiKLNvT9wtAQVl1DFW0cEO7OvZyLSUBLNLTHqyvOZxKaZ8YFk7d8PL6l76LeUKRxq4NMxfZQlUIRe0eSA==", "dev": true, "requires": { - "@aws-sdk/types": "3.347.0", + "@aws-sdk/types": "3.451.0", + "@aws-sdk/util-endpoints": "3.451.0", + "@smithy/protocol-http": "^3.0.9", + "@smithy/types": "^2.5.0", "tslib": "^2.5.0" } }, - "@aws-sdk/util-hex-encoding": { - "version": "3.310.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-hex-encoding/-/util-hex-encoding-3.310.0.tgz", - "integrity": "sha512-sVN7mcCCDSJ67pI1ZMtk84SKGqyix6/0A1Ab163YKn+lFBQRMKexleZzpYzNGxYzmQS6VanP/cfU7NiLQOaSfA==", + "@aws-sdk/region-config-resolver": { + "version": "3.451.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.451.0.tgz", + "integrity": "sha512-3iMf4OwzrFb4tAAmoROXaiORUk2FvSejnHIw/XHvf/jjR4EqGGF95NZP/n/MeFZMizJWVssrwS412GmoEyoqhg==", "dev": true, "requires": { + "@smithy/node-config-provider": "^2.1.5", + "@smithy/types": "^2.5.0", + "@smithy/util-config-provider": "^2.0.0", + "@smithy/util-middleware": "^2.0.6", "tslib": "^2.5.0" } }, - "@aws-sdk/util-locate-window": { - "version": "3.310.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-locate-window/-/util-locate-window-3.310.0.tgz", - "integrity": "sha512-qo2t/vBTnoXpjKxlsC2e1gBrRm80M3bId27r0BRB2VniSSe7bL1mmzM+/HFtujm0iAxtPM+aLEflLJlJeDPg0w==", + "@aws-sdk/token-providers": { + "version": "3.451.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.451.0.tgz", + "integrity": "sha512-ij1L5iUbn6CwxVOT1PG4NFjsrsKN9c4N1YEM0lkl6DwmaNOscjLKGSNyj9M118vSWsOs1ZDbTwtj++h0O/BWrQ==", "dev": true, "requires": { + "@aws-crypto/sha256-browser": "3.0.0", + "@aws-crypto/sha256-js": "3.0.0", + "@aws-sdk/middleware-host-header": "3.451.0", + "@aws-sdk/middleware-logger": "3.451.0", + "@aws-sdk/middleware-recursion-detection": "3.451.0", + "@aws-sdk/middleware-user-agent": "3.451.0", + "@aws-sdk/region-config-resolver": "3.451.0", + "@aws-sdk/types": "3.451.0", + "@aws-sdk/util-endpoints": "3.451.0", + "@aws-sdk/util-user-agent-browser": "3.451.0", + "@aws-sdk/util-user-agent-node": "3.451.0", + "@smithy/config-resolver": "^2.0.18", + "@smithy/fetch-http-handler": "^2.2.6", + "@smithy/hash-node": "^2.0.15", + "@smithy/invalid-dependency": "^2.0.13", + "@smithy/middleware-content-length": "^2.0.15", + "@smithy/middleware-endpoint": "^2.2.0", + "@smithy/middleware-retry": "^2.0.20", + "@smithy/middleware-serde": "^2.0.13", + "@smithy/middleware-stack": "^2.0.7", + "@smithy/node-config-provider": "^2.1.5", + "@smithy/node-http-handler": "^2.1.9", + "@smithy/property-provider": "^2.0.0", + "@smithy/protocol-http": "^3.0.9", + "@smithy/shared-ini-file-loader": "^2.0.6", + "@smithy/smithy-client": "^2.1.15", + "@smithy/types": "^2.5.0", + "@smithy/url-parser": "^2.0.13", + "@smithy/util-base64": "^2.0.1", + "@smithy/util-body-length-browser": "^2.0.0", + "@smithy/util-body-length-node": "^2.1.0", + "@smithy/util-defaults-mode-browser": "^2.0.19", + "@smithy/util-defaults-mode-node": "^2.0.25", + "@smithy/util-endpoints": "^1.0.4", + "@smithy/util-retry": "^2.0.6", + "@smithy/util-utf8": "^2.0.2", "tslib": "^2.5.0" } }, - "@aws-sdk/util-middleware": { - "version": "3.347.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-middleware/-/util-middleware-3.347.0.tgz", - "integrity": "sha512-8owqUA3ePufeYTUvlzdJ7Z0miLorTwx+rNol5lourGQZ9JXsVMo23+yGA7nOlFuXSGkoKpMOtn6S0BT2bcfeiw==", + "@aws-sdk/types": { + "version": "3.451.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.451.0.tgz", + "integrity": "sha512-rhK+qeYwCIs+laJfWCcrYEjay2FR/9VABZJ2NRM89jV/fKqGVQR52E5DQqrI+oEIL5JHMhhnr4N4fyECMS35lw==", "dev": true, "requires": { + "@smithy/types": "^2.5.0", "tslib": "^2.5.0" } }, - "@aws-sdk/util-retry": { - "version": "3.347.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-retry/-/util-retry-3.347.0.tgz", - "integrity": "sha512-NxnQA0/FHFxriQAeEgBonA43Q9/VPFQa8cfJDuT2A1YZruMasgjcltoZszi1dvoIRWSZsFTW42eY2gdOd0nffQ==", + "@aws-sdk/util-endpoints": { + "version": "3.451.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.451.0.tgz", + "integrity": "sha512-giqLGBTnRIcKkDqwU7+GQhKbtJ5Ku35cjGQIfMyOga6pwTBUbaK0xW1Sdd8sBQ1GhApscnChzI9o/R9x0368vw==", "dev": true, "requires": { - "@aws-sdk/service-error-classification": "3.347.0", + "@aws-sdk/types": "3.451.0", + "@smithy/util-endpoints": "^1.0.4", "tslib": "^2.5.0" } }, - "@aws-sdk/util-uri-escape": { + "@aws-sdk/util-locate-window": { "version": "3.310.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-uri-escape/-/util-uri-escape-3.310.0.tgz", - "integrity": "sha512-drzt+aB2qo2LgtDoiy/3sVG8w63cgLkqFIa2NFlGpUgHFWTXkqtbgf4L5QdjRGKWhmZsnqkbtL7vkSWEcYDJ4Q==", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-locate-window/-/util-locate-window-3.310.0.tgz", + "integrity": "sha512-qo2t/vBTnoXpjKxlsC2e1gBrRm80M3bId27r0BRB2VniSSe7bL1mmzM+/HFtujm0iAxtPM+aLEflLJlJeDPg0w==", "dev": true, "requires": { "tslib": "^2.5.0" } }, "@aws-sdk/util-user-agent-browser": { - "version": "3.347.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.347.0.tgz", - "integrity": "sha512-ydxtsKVtQefgbk1Dku1q7pMkjDYThauG9/8mQkZUAVik55OUZw71Zzr3XO8J8RKvQG8lmhPXuAQ0FKAyycc0RA==", + "version": "3.451.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.451.0.tgz", + "integrity": "sha512-Ws5mG3J0TQifH7OTcMrCTexo7HeSAc3cBgjfhS/ofzPUzVCtsyg0G7I6T7wl7vJJETix2Kst2cpOsxygPgPD9w==", "dev": true, "requires": { - "@aws-sdk/types": "3.347.0", + "@aws-sdk/types": "3.451.0", + "@smithy/types": "^2.5.0", "bowser": "^2.11.0", "tslib": "^2.5.0" } }, "@aws-sdk/util-user-agent-node": { - "version": "3.347.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.347.0.tgz", - "integrity": "sha512-6X0b9qGsbD1s80PmbaB6v1/ZtLfSx6fjRX8caM7NN0y/ObuLoX8LhYnW6WlB2f1+xb4EjaCNgpP/zCf98MXosw==", + "version": "3.451.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.451.0.tgz", + "integrity": "sha512-TBzm6P+ql4mkGFAjPlO1CI+w3yUT+NulaiALjl/jNX/nnUp6HsJsVxJf4nVFQTG5KRV0iqMypcs7I3KIhH+LmA==", "dev": true, "requires": { - "@aws-sdk/node-config-provider": "3.347.0", - "@aws-sdk/types": "3.347.0", - "tslib": "^2.5.0" - } - }, - "@aws-sdk/util-utf8": { - "version": "3.310.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-utf8/-/util-utf8-3.310.0.tgz", - "integrity": "sha512-DnLfFT8uCO22uOJc0pt0DsSNau1GTisngBCDw8jQuWT5CqogMJu4b/uXmwEqfj8B3GX6Xsz8zOd6JpRlPftQoA==", - "dev": true, - "requires": { - "@aws-sdk/util-buffer-from": "3.310.0", + "@aws-sdk/types": "3.451.0", + "@smithy/node-config-provider": "^2.1.5", + "@smithy/types": "^2.5.0", "tslib": "^2.5.0" } }, @@ -14954,17 +14936,6 @@ "tslib": "^2.3.1" } }, - "@aws-sdk/util-waiter": { - "version": "3.347.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-waiter/-/util-waiter-3.347.0.tgz", - "integrity": "sha512-3ze/0PkwkzUzLncukx93tZgGL0JX9NaP8DxTi6WzflnL/TEul5Z63PCruRNK0om17iZYAWKrf8q2mFoHYb4grA==", - "dev": true, - "requires": { - "@aws-sdk/abort-controller": "3.347.0", - "@aws-sdk/types": "3.347.0", - "tslib": "^2.5.0" - } - }, "@base2/pretty-print-object": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@base2/pretty-print-object/-/pretty-print-object-1.0.1.tgz", @@ -15359,6 +15330,8 @@ }, "@kwsites/file-exists": { "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@kwsites/file-exists/-/file-exists-1.1.1.tgz", + "integrity": "sha512-m9/5YGR18lIwxSFDwfE3oA7bWuq9kdau6ugN4H2rJeyhFQZcG9AgSHkQtSD15a8WvTgfz9aikZMrKPHvbpqFiw==", "dev": true, "requires": { "debug": "^4.1.1" @@ -15366,6 +15339,8 @@ }, "@kwsites/promise-deferred": { "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@kwsites/promise-deferred/-/promise-deferred-1.1.1.tgz", + "integrity": "sha512-GaHYm+c0O9MjZRu0ongGBRbinu8gVAMd2UZjji6jVmqKtZluZnptXGWhz1E8j8D2HJ3f/yMxKAUC0b+57wncIw==", "dev": true }, "@nodelib/fs.scandir": { @@ -15544,13 +15519,17 @@ "optional": true }, "@serverless/dashboard-plugin": { - "version": "6.2.3", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@serverless/dashboard-plugin/-/dashboard-plugin-7.1.0.tgz", + "integrity": "sha512-mAiTU2ERsDHdCrXJa/tihh/r+8ZwSuYYBqln3SkwuBD/49ct9QrK7S00cpiqFoY/geMFlHpOkriGzCPz6UP/rw==", "dev": true, "requires": { + "@aws-sdk/client-cloudformation": "^3.410.0", + "@aws-sdk/client-sts": "^3.410.0", "@serverless/event-mocks": "^1.1.1", - "@serverless/platform-client": "^4.3.2", - "@serverless/utils": "^6.8.2", - "child-process-ext": "^2.1.1", + "@serverless/platform-client": "^4.4.0", + "@serverless/utils": "^6.14.0", + "child-process-ext": "^3.0.1", "chokidar": "^3.5.3", "flat": "^5.0.2", "fs-extra": "^9.1.0", @@ -15564,6 +15543,7 @@ "open": "^7.4.2", "semver": "^7.3.8", "simple-git": "^3.16.0", + "timers-ext": "^0.1.7", "type": "^2.7.2", "uuid": "^8.3.2", "yamljs": "^0.3.0" @@ -15571,10 +15551,27 @@ "dependencies": { "argparse": { "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", "dev": true }, + "child-process-ext": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/child-process-ext/-/child-process-ext-3.0.2.tgz", + "integrity": "sha512-oBePsLbQpTJFxzwyCvs9yWWF0OEM6vGGepHwt1stqmX7QQqOuDc8j2ywdvAs9Tvi44TT7d9ackqhR4Q10l1u8w==", + "dev": true, + "requires": { + "cross-spawn": "^7.0.3", + "es5-ext": "^0.10.62", + "log": "^6.3.1", + "split2": "^3.2.2", + "stream-promise": "^3.2.0" + } + }, "js-yaml": { "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", "dev": true, "requires": { "argparse": "^2.0.1" @@ -15582,6 +15579,8 @@ }, "open": { "version": "7.4.2", + "resolved": "https://registry.npmjs.org/open/-/open-7.4.2.tgz", + "integrity": "sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q==", "dev": true, "requires": { "is-docker": "^2.0.0", @@ -15592,6 +15591,8 @@ }, "@serverless/event-mocks": { "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@serverless/event-mocks/-/event-mocks-1.1.1.tgz", + "integrity": "sha512-YAV5V/y+XIOfd+HEVeXfPWZb8C6QLruFk9tBivoX2roQLWVq145s4uxf8D0QioCueuRzkukHUS4JIj+KVoS34A==", "dev": true, "requires": { "@types/lodash": "^4.14.123", @@ -15599,7 +15600,9 @@ } }, "@serverless/platform-client": { - "version": "4.3.2", + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@serverless/platform-client/-/platform-client-4.4.0.tgz", + "integrity": "sha512-urL7SNefRqC2EOFDcpvm8fyn/06B5yXWneKpyGw7ylGt0Qr9JHZCB9TiUeTkIpPUNz0jTvKUaJ2+M/JNEiaVIA==", "dev": true, "requires": { "adm-zip": "^0.5.5", @@ -15621,24 +15624,24 @@ "dependencies": { "axios": { "version": "0.21.4", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz", + "integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==", "dev": true, "requires": { "follow-redirects": "^1.14.0" } - }, - "throat": { - "version": "5.0.0", - "dev": true } } }, "@serverless/utils": { - "version": "6.8.2", + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/@serverless/utils/-/utils-6.15.0.tgz", + "integrity": "sha512-7eDbqKv/OBd11jjdZjUwFGN8sHWkeUqLeHXHQxQ1azja2IM7WIH+z/aLgzR6LhB3/MINNwtjesDpjGqTMj2JKQ==", "dev": true, "requires": { "archive-type": "^4.0.0", "chalk": "^4.1.2", - "ci-info": "^3.5.0", + "ci-info": "^3.8.0", "cli-progress-footer": "^2.3.2", "content-disposition": "^0.5.4", "d": "^1.0.1", @@ -15649,18 +15652,19 @@ "file-type": "^16.5.4", "filenamify": "^4.3.0", "get-stream": "^6.0.1", - "got": "^11.8.5", + "got": "^11.8.6", "inquirer": "^8.2.5", "js-yaml": "^4.1.0", "jwt-decode": "^3.1.2", "lodash": "^4.17.21", "log": "^6.3.1", "log-node": "^8.0.3", - "make-dir": "^3.1.0", + "make-dir": "^4.0.0", "memoizee": "^0.4.15", - "ncjsm": "^4.3.1", - "node-fetch": "^2.6.7", - "open": "^8.4.0", + "ms": "^2.1.3", + "ncjsm": "^4.3.2", + "node-fetch": "^2.6.11", + "open": "^8.4.2", "p-event": "^4.2.0", "supports-color": "^8.1.1", "timers-ext": "^0.1.7", @@ -15685,6 +15689,12 @@ "version": "3.1.2", "dev": true }, + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, "supports-color": { "version": "8.1.1", "dev": true, @@ -15702,62 +15712,492 @@ } } }, - "@sigstore/bundle": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@sigstore/bundle/-/bundle-2.1.0.tgz", - "integrity": "sha512-89uOo6yh/oxaU8AeOUnVrTdVMcGk9Q1hJa7Hkvalc6G3Z3CupWk4Xe9djSgJm9fMkH69s0P0cVHUoKSOemLdng==", + "@sigstore/bundle": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@sigstore/bundle/-/bundle-2.1.0.tgz", + "integrity": "sha512-89uOo6yh/oxaU8AeOUnVrTdVMcGk9Q1hJa7Hkvalc6G3Z3CupWk4Xe9djSgJm9fMkH69s0P0cVHUoKSOemLdng==", + "dev": true, + "requires": { + "@sigstore/protobuf-specs": "^0.2.1" + } + }, + "@sigstore/protobuf-specs": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/@sigstore/protobuf-specs/-/protobuf-specs-0.2.1.tgz", + "integrity": "sha512-XTWVxnWJu+c1oCshMLwnKvz8ZQJJDVOlciMfgpJBQbThVjKTCG8dwyhgLngBD2KN0ap9F/gOV8rFDEx8uh7R2A==", + "dev": true + }, + "@sigstore/sign": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@sigstore/sign/-/sign-2.2.0.tgz", + "integrity": "sha512-AAbmnEHDQv6CSfrWA5wXslGtzLPtAtHZleKOgxdQYvx/s76Fk6T6ZVt7w2IGV9j1UrFeBocTTQxaXG2oRrDhYA==", + "dev": true, + "requires": { + "@sigstore/bundle": "^2.1.0", + "@sigstore/protobuf-specs": "^0.2.1", + "make-fetch-happen": "^13.0.0" + } + }, + "@sigstore/tuf": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@sigstore/tuf/-/tuf-2.2.0.tgz", + "integrity": "sha512-KKATZ5orWfqd9ZG6MN8PtCIx4eevWSuGRKQvofnWXRpyMyUEpmrzg5M5BrCpjM+NfZ0RbNGOh5tCz/P2uoRqOA==", + "dev": true, + "requires": { + "@sigstore/protobuf-specs": "^0.2.1", + "tuf-js": "^2.1.0" + } + }, + "@sindresorhus/is": { + "version": "4.6.0", + "dev": true + }, + "@smithy/abort-controller": { + "version": "2.0.13", + "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-2.0.13.tgz", + "integrity": "sha512-eeOPD+GF9BzF/Mjy3PICLePx4l0f3rG/nQegQHRLTloN5p1lSJJNZsyn+FzDnW8P2AduragZqJdtKNCxXozB1Q==", + "dev": true, + "requires": { + "@smithy/types": "^2.5.0", + "tslib": "^2.5.0" + } + }, + "@smithy/config-resolver": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/@smithy/config-resolver/-/config-resolver-2.0.18.tgz", + "integrity": "sha512-761sJSgNbvsqcsKW6/WZbrZr4H+0Vp/QKKqwyrxCPwD8BsiPEXNHyYnqNgaeK9xRWYswjon0Uxbpe3DWQo0j/g==", + "dev": true, + "requires": { + "@smithy/node-config-provider": "^2.1.5", + "@smithy/types": "^2.5.0", + "@smithy/util-config-provider": "^2.0.0", + "@smithy/util-middleware": "^2.0.6", + "tslib": "^2.5.0" + } + }, + "@smithy/credential-provider-imds": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-2.1.1.tgz", + "integrity": "sha512-gw5G3FjWC6sNz8zpOJgPpH5HGKrpoVFQpToNAwLwJVyI/LJ2jDJRjSKEsM6XI25aRpYjMSE/Qptxx305gN1vHw==", + "dev": true, + "requires": { + "@smithy/node-config-provider": "^2.1.5", + "@smithy/property-provider": "^2.0.14", + "@smithy/types": "^2.5.0", + "@smithy/url-parser": "^2.0.13", + "tslib": "^2.5.0" + } + }, + "@smithy/eventstream-codec": { + "version": "2.0.13", + "resolved": "https://registry.npmjs.org/@smithy/eventstream-codec/-/eventstream-codec-2.0.13.tgz", + "integrity": "sha512-CExbelIYp+DxAHG8RIs0l9QL7ElqhG4ym9BNoSpkPa4ptBQfzJdep3LbOSVJIE2VUdBAeObdeL6EDB3Jo85n3g==", + "dev": true, + "requires": { + "@aws-crypto/crc32": "3.0.0", + "@smithy/types": "^2.5.0", + "@smithy/util-hex-encoding": "^2.0.0", + "tslib": "^2.5.0" + } + }, + "@smithy/fetch-http-handler": { + "version": "2.2.6", + "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-2.2.6.tgz", + "integrity": "sha512-PStY3XO1Ksjwn3wMKye5U6m6zxXpXrXZYqLy/IeCbh3nM9QB3Jgw/B0PUSLUWKdXg4U8qgEu300e3ZoBvZLsDg==", + "dev": true, + "requires": { + "@smithy/protocol-http": "^3.0.9", + "@smithy/querystring-builder": "^2.0.13", + "@smithy/types": "^2.5.0", + "@smithy/util-base64": "^2.0.1", + "tslib": "^2.5.0" + } + }, + "@smithy/hash-node": { + "version": "2.0.15", + "resolved": "https://registry.npmjs.org/@smithy/hash-node/-/hash-node-2.0.15.tgz", + "integrity": "sha512-t/qjEJZu/G46A22PAk1k/IiJZT4ncRkG5GOCNWN9HPPy5rCcSZUbh7gwp7CGKgJJ7ATMMg+0Td7i9o1lQTwOfQ==", + "dev": true, + "requires": { + "@smithy/types": "^2.5.0", + "@smithy/util-buffer-from": "^2.0.0", + "@smithy/util-utf8": "^2.0.2", + "tslib": "^2.5.0" + } + }, + "@smithy/invalid-dependency": { + "version": "2.0.13", + "resolved": "https://registry.npmjs.org/@smithy/invalid-dependency/-/invalid-dependency-2.0.13.tgz", + "integrity": "sha512-XsGYhVhvEikX1Yz0kyIoLssJf2Rs6E0U2w2YuKdT4jSra5A/g8V2oLROC1s56NldbgnpesTYB2z55KCHHbKyjw==", + "dev": true, + "requires": { + "@smithy/types": "^2.5.0", + "tslib": "^2.5.0" + } + }, + "@smithy/is-array-buffer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-2.0.0.tgz", + "integrity": "sha512-z3PjFjMyZNI98JFRJi/U0nGoLWMSJlDjAW4QUX2WNZLas5C0CmVV6LJ01JI0k90l7FvpmixjWxPFmENSClQ7ug==", + "dev": true, + "requires": { + "tslib": "^2.5.0" + } + }, + "@smithy/middleware-content-length": { + "version": "2.0.15", + "resolved": "https://registry.npmjs.org/@smithy/middleware-content-length/-/middleware-content-length-2.0.15.tgz", + "integrity": "sha512-xH4kRBw01gJgWiU+/mNTrnyFXeozpZHw39gLb3JKGsFDVmSrJZ8/tRqu27tU/ki1gKkxr2wApu+dEYjI3QwV1Q==", + "dev": true, + "requires": { + "@smithy/protocol-http": "^3.0.9", + "@smithy/types": "^2.5.0", + "tslib": "^2.5.0" + } + }, + "@smithy/middleware-endpoint": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-2.2.0.tgz", + "integrity": "sha512-tddRmaig5URk2106PVMiNX6mc5BnKIKajHHDxb7K0J5MLdcuQluHMGnjkv18iY9s9O0tF+gAcPd/pDXA5L9DZw==", + "dev": true, + "requires": { + "@smithy/middleware-serde": "^2.0.13", + "@smithy/node-config-provider": "^2.1.5", + "@smithy/shared-ini-file-loader": "^2.2.4", + "@smithy/types": "^2.5.0", + "@smithy/url-parser": "^2.0.13", + "@smithy/util-middleware": "^2.0.6", + "tslib": "^2.5.0" + } + }, + "@smithy/middleware-retry": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-2.0.20.tgz", + "integrity": "sha512-X2yrF/SHDk2WDd8LflRNS955rlzQ9daz9UWSp15wW8KtzoTXg3bhHM78HbK1cjr48/FWERSJKh9AvRUUGlIawg==", + "dev": true, + "requires": { + "@smithy/node-config-provider": "^2.1.5", + "@smithy/protocol-http": "^3.0.9", + "@smithy/service-error-classification": "^2.0.6", + "@smithy/types": "^2.5.0", + "@smithy/util-middleware": "^2.0.6", + "@smithy/util-retry": "^2.0.6", + "tslib": "^2.5.0", + "uuid": "^8.3.2" + } + }, + "@smithy/middleware-serde": { + "version": "2.0.13", + "resolved": "https://registry.npmjs.org/@smithy/middleware-serde/-/middleware-serde-2.0.13.tgz", + "integrity": "sha512-tBGbeXw+XsE6pPr4UaXOh+UIcXARZeiA8bKJWxk2IjJcD1icVLhBSUQH9myCIZLNNzJIH36SDjUX8Wqk4xJCJg==", + "dev": true, + "requires": { + "@smithy/types": "^2.5.0", + "tslib": "^2.5.0" + } + }, + "@smithy/middleware-stack": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@smithy/middleware-stack/-/middleware-stack-2.0.7.tgz", + "integrity": "sha512-L1KLAAWkXbGx1t2jjCI/mDJ2dDNq+rp4/ifr/HcC6FHngxho5O7A5bQLpKHGlkfATH6fUnOEx0VICEVFA4sUzw==", + "dev": true, + "requires": { + "@smithy/types": "^2.5.0", + "tslib": "^2.5.0" + } + }, + "@smithy/node-config-provider": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-2.1.5.tgz", + "integrity": "sha512-3Omb5/h4tOCuKRx4p4pkYTvEYRCYoKk52bOYbKUyz/G/8gERbagsN8jFm4FjQubkrcIqQEghTpQaUw6uk+0edw==", + "dev": true, + "requires": { + "@smithy/property-provider": "^2.0.14", + "@smithy/shared-ini-file-loader": "^2.2.4", + "@smithy/types": "^2.5.0", + "tslib": "^2.5.0" + } + }, + "@smithy/node-http-handler": { + "version": "2.1.9", + "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-2.1.9.tgz", + "integrity": "sha512-+K0q3SlNcocmo9OZj+fz67gY4lwhOCvIJxVbo/xH+hfWObvaxrMTx7JEzzXcluK0thnnLz++K3Qe7Z/8MDUreA==", + "dev": true, + "requires": { + "@smithy/abort-controller": "^2.0.13", + "@smithy/protocol-http": "^3.0.9", + "@smithy/querystring-builder": "^2.0.13", + "@smithy/types": "^2.5.0", + "tslib": "^2.5.0" + } + }, + "@smithy/property-provider": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-2.0.14.tgz", + "integrity": "sha512-k3D2qp9o6imTrLaXRj6GdLYEJr1sXqS99nLhzq8fYmJjSVOeMg/G+1KVAAc7Oxpu71rlZ2f8SSZxcSxkevuR0A==", + "dev": true, + "requires": { + "@smithy/types": "^2.5.0", + "tslib": "^2.5.0" + } + }, + "@smithy/protocol-http": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-3.0.9.tgz", + "integrity": "sha512-U1wl+FhYu4/BC+rjwh1lg2gcJChQhytiNQSggREgQ9G2FzmoK9sACBZvx7thyWMvRyHQTE22mO2d5UM8gMKDBg==", + "dev": true, + "requires": { + "@smithy/types": "^2.5.0", + "tslib": "^2.5.0" + } + }, + "@smithy/querystring-builder": { + "version": "2.0.13", + "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-2.0.13.tgz", + "integrity": "sha512-JhXKwp3JtsFUe96XLHy/nUPEbaXqn6r7xE4sNaH8bxEyytE5q1fwt0ew/Ke6+vIC7gP87HCHgQpJHg1X1jN2Fw==", + "dev": true, + "requires": { + "@smithy/types": "^2.5.0", + "@smithy/util-uri-escape": "^2.0.0", + "tslib": "^2.5.0" + } + }, + "@smithy/querystring-parser": { + "version": "2.0.13", + "resolved": "https://registry.npmjs.org/@smithy/querystring-parser/-/querystring-parser-2.0.13.tgz", + "integrity": "sha512-TEiT6o8CPZVxJ44Rly/rrsATTQsE+b/nyBVzsYn2sa75xAaZcurNxsFd8z1haoUysONiyex24JMHoJY6iCfLdA==", + "dev": true, + "requires": { + "@smithy/types": "^2.5.0", + "tslib": "^2.5.0" + } + }, + "@smithy/service-error-classification": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@smithy/service-error-classification/-/service-error-classification-2.0.6.tgz", + "integrity": "sha512-fCQ36frtYra2fqY2/DV8+3/z2d0VB/1D1hXbjRcM5wkxTToxq6xHbIY/NGGY6v4carskMyG8FHACxgxturJ9Pg==", + "dev": true, + "requires": { + "@smithy/types": "^2.5.0" + } + }, + "@smithy/shared-ini-file-loader": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-2.2.4.tgz", + "integrity": "sha512-9dRknGgvYlRIsoTcmMJXuoR/3ekhGwhRq4un3ns2/byre4Ql5hyUN4iS0x8eITohjU90YOnUCsbRwZRvCkbRfw==", + "dev": true, + "requires": { + "@smithy/types": "^2.5.0", + "tslib": "^2.5.0" + } + }, + "@smithy/signature-v4": { + "version": "2.0.15", + "resolved": "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-2.0.15.tgz", + "integrity": "sha512-SRTEJSEhQYVlBKIIdZ9SZpqW+KFqxqcNnEcBX+8xkDdWx+DItme9VcCDkdN32yTIrICC+irUufnUdV7mmHPjoA==", + "dev": true, + "requires": { + "@smithy/eventstream-codec": "^2.0.13", + "@smithy/is-array-buffer": "^2.0.0", + "@smithy/types": "^2.5.0", + "@smithy/util-hex-encoding": "^2.0.0", + "@smithy/util-middleware": "^2.0.6", + "@smithy/util-uri-escape": "^2.0.0", + "@smithy/util-utf8": "^2.0.2", + "tslib": "^2.5.0" + } + }, + "@smithy/smithy-client": { + "version": "2.1.15", + "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-2.1.15.tgz", + "integrity": "sha512-rngZcQu7Jvs9UbHihK1EI67RMPuzkc3CJmu4MBgB7D7yBnMGuFR86tq5rqHfL2gAkNnMelBN/8kzQVvZjNKefQ==", + "dev": true, + "requires": { + "@smithy/middleware-stack": "^2.0.7", + "@smithy/types": "^2.5.0", + "@smithy/util-stream": "^2.0.20", + "tslib": "^2.5.0" + } + }, + "@smithy/types": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-2.5.0.tgz", + "integrity": "sha512-/a31lYofrMBkJb3BuPlYJTMKDj0hUmKUP6JFZQu6YVuQVoAjubiY0A52U9S0Uysd33n/djexCUSNJ+G9bf3/aA==", + "dev": true, + "requires": { + "tslib": "^2.5.0" + } + }, + "@smithy/url-parser": { + "version": "2.0.13", + "resolved": "https://registry.npmjs.org/@smithy/url-parser/-/url-parser-2.0.13.tgz", + "integrity": "sha512-okWx2P/d9jcTsZWTVNnRMpFOE7fMkzloSFyM53fA7nLKJQObxM2T4JlZ5KitKKuXq7pxon9J6SF2kCwtdflIrA==", + "dev": true, + "requires": { + "@smithy/querystring-parser": "^2.0.13", + "@smithy/types": "^2.5.0", + "tslib": "^2.5.0" + } + }, + "@smithy/util-base64": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@smithy/util-base64/-/util-base64-2.0.1.tgz", + "integrity": "sha512-DlI6XFYDMsIVN+GH9JtcRp3j02JEVuWIn/QOZisVzpIAprdsxGveFed0bjbMRCqmIFe8uetn5rxzNrBtIGrPIQ==", + "dev": true, + "requires": { + "@smithy/util-buffer-from": "^2.0.0", + "tslib": "^2.5.0" + } + }, + "@smithy/util-body-length-browser": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-body-length-browser/-/util-body-length-browser-2.0.0.tgz", + "integrity": "sha512-JdDuS4ircJt+FDnaQj88TzZY3+njZ6O+D3uakS32f2VNnDo3vyEuNdBOh/oFd8Df1zSZOuH1HEChk2AOYDezZg==", + "dev": true, + "requires": { + "tslib": "^2.5.0" + } + }, + "@smithy/util-body-length-node": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@smithy/util-body-length-node/-/util-body-length-node-2.1.0.tgz", + "integrity": "sha512-/li0/kj/y3fQ3vyzn36NTLGmUwAICb7Jbe/CsWCktW363gh1MOcpEcSO3mJ344Gv2dqz8YJCLQpb6hju/0qOWw==", + "dev": true, + "requires": { + "tslib": "^2.5.0" + } + }, + "@smithy/util-buffer-from": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-2.0.0.tgz", + "integrity": "sha512-/YNnLoHsR+4W4Vf2wL5lGv0ksg8Bmk3GEGxn2vEQt52AQaPSCuaO5PM5VM7lP1K9qHRKHwrPGktqVoAHKWHxzw==", + "dev": true, + "requires": { + "@smithy/is-array-buffer": "^2.0.0", + "tslib": "^2.5.0" + } + }, + "@smithy/util-config-provider": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-config-provider/-/util-config-provider-2.0.0.tgz", + "integrity": "sha512-xCQ6UapcIWKxXHEU4Mcs2s7LcFQRiU3XEluM2WcCjjBtQkUN71Tb+ydGmJFPxMUrW/GWMgQEEGipLym4XG0jZg==", + "dev": true, + "requires": { + "tslib": "^2.5.0" + } + }, + "@smithy/util-defaults-mode-browser": { + "version": "2.0.19", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-2.0.19.tgz", + "integrity": "sha512-VHP8xdFR7/orpiABJwgoTB0t8Zhhwpf93gXhNfUBiwAE9O0rvsv7LwpQYjgvbOUDDO8JfIYQB2GYJNkqqGWsXw==", "dev": true, "requires": { - "@sigstore/protobuf-specs": "^0.2.1" + "@smithy/property-provider": "^2.0.14", + "@smithy/smithy-client": "^2.1.15", + "@smithy/types": "^2.5.0", + "bowser": "^2.11.0", + "tslib": "^2.5.0" } }, - "@sigstore/protobuf-specs": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/@sigstore/protobuf-specs/-/protobuf-specs-0.2.1.tgz", - "integrity": "sha512-XTWVxnWJu+c1oCshMLwnKvz8ZQJJDVOlciMfgpJBQbThVjKTCG8dwyhgLngBD2KN0ap9F/gOV8rFDEx8uh7R2A==", - "dev": true + "@smithy/util-defaults-mode-node": { + "version": "2.0.25", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-2.0.25.tgz", + "integrity": "sha512-jkmep6/JyWmn2ADw9VULDeGbugR4N/FJCKOt+gYyVswmN1BJOfzF2umaYxQ1HhQDvna3kzm1Dbo1qIfBW4iuHA==", + "dev": true, + "requires": { + "@smithy/config-resolver": "^2.0.18", + "@smithy/credential-provider-imds": "^2.1.1", + "@smithy/node-config-provider": "^2.1.5", + "@smithy/property-provider": "^2.0.14", + "@smithy/smithy-client": "^2.1.15", + "@smithy/types": "^2.5.0", + "tslib": "^2.5.0" + } }, - "@sigstore/sign": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@sigstore/sign/-/sign-2.2.0.tgz", - "integrity": "sha512-AAbmnEHDQv6CSfrWA5wXslGtzLPtAtHZleKOgxdQYvx/s76Fk6T6ZVt7w2IGV9j1UrFeBocTTQxaXG2oRrDhYA==", + "@smithy/util-endpoints": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@smithy/util-endpoints/-/util-endpoints-1.0.4.tgz", + "integrity": "sha512-FPry8j1xye5yzrdnf4xKUXVnkQErxdN7bUIaqC0OFoGsv2NfD9b2UUMuZSSt+pr9a8XWAqj0HoyVNUfPiZ/PvQ==", "dev": true, "requires": { - "@sigstore/bundle": "^2.1.0", - "@sigstore/protobuf-specs": "^0.2.1", - "make-fetch-happen": "^13.0.0" + "@smithy/node-config-provider": "^2.1.5", + "@smithy/types": "^2.5.0", + "tslib": "^2.5.0" } }, - "@sigstore/tuf": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@sigstore/tuf/-/tuf-2.2.0.tgz", - "integrity": "sha512-KKATZ5orWfqd9ZG6MN8PtCIx4eevWSuGRKQvofnWXRpyMyUEpmrzg5M5BrCpjM+NfZ0RbNGOh5tCz/P2uoRqOA==", + "@smithy/util-hex-encoding": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-hex-encoding/-/util-hex-encoding-2.0.0.tgz", + "integrity": "sha512-c5xY+NUnFqG6d7HFh1IFfrm3mGl29lC+vF+geHv4ToiuJCBmIfzx6IeHLg+OgRdPFKDXIw6pvi+p3CsscaMcMA==", "dev": true, "requires": { - "@sigstore/protobuf-specs": "^0.2.1", - "tuf-js": "^2.1.0" + "tslib": "^2.5.0" } }, - "@sindresorhus/is": { - "version": "4.6.0", - "dev": true + "@smithy/util-middleware": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-2.0.6.tgz", + "integrity": "sha512-7W4uuwBvSLgKoLC1x4LfeArCVcbuHdtVaC4g30kKsD1erfICyQ45+tFhhs/dZNeQg+w392fhunCm/+oCcb6BSA==", + "dev": true, + "requires": { + "@smithy/types": "^2.5.0", + "tslib": "^2.5.0" + } }, - "@smithy/protocol-http": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-1.0.1.tgz", - "integrity": "sha512-9OrEn0WfOVtBNYJUjUAn9AOiJ4lzERCJJ/JeZs8E6yajTGxBaFRxUnNBHiNqoDJVg076hY36UmEnPx7xXrvUSg==", + "@smithy/util-retry": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@smithy/util-retry/-/util-retry-2.0.6.tgz", + "integrity": "sha512-PSO41FofOBmyhPQJwBQJ6mVlaD7Sp9Uff9aBbnfBJ9eqXOE/obrqQjn0PNdkfdvViiPXl49BINfnGcFtSP4kYw==", "dev": true, "requires": { - "@smithy/types": "^1.0.0", + "@smithy/service-error-classification": "^2.0.6", + "@smithy/types": "^2.5.0", "tslib": "^2.5.0" } }, - "@smithy/types": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-1.0.0.tgz", - "integrity": "sha512-kc1m5wPBHQCTixwuaOh9vnak/iJm21DrSf9UK6yDE5S3mQQ4u11pqAUiKWnlrZnYkeLfAI9UEHj9OaMT1v5Umg==", + "@smithy/util-stream": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-2.0.20.tgz", + "integrity": "sha512-tT8VASuD8jJu0yjHEMTCPt1o5E3FVzgdsxK6FQLAjXKqVv5V8InCnc0EOsYrijgspbfDqdAJg7r0o2sySfcHVg==", + "dev": true, + "requires": { + "@smithy/fetch-http-handler": "^2.2.6", + "@smithy/node-http-handler": "^2.1.9", + "@smithy/types": "^2.5.0", + "@smithy/util-base64": "^2.0.1", + "@smithy/util-buffer-from": "^2.0.0", + "@smithy/util-hex-encoding": "^2.0.0", + "@smithy/util-utf8": "^2.0.2", + "tslib": "^2.5.0" + } + }, + "@smithy/util-uri-escape": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-uri-escape/-/util-uri-escape-2.0.0.tgz", + "integrity": "sha512-ebkxsqinSdEooQduuk9CbKcI+wheijxEb3utGXkCoYQkJnwTnLbH1JXGimJtUkQwNQbsbuYwG2+aFVyZf5TLaw==", + "dev": true, + "requires": { + "tslib": "^2.5.0" + } + }, + "@smithy/util-utf8": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-2.0.2.tgz", + "integrity": "sha512-qOiVORSPm6Ce4/Yu6hbSgNHABLP2VMv8QOC3tTDNHHlWY19pPyc++fBTbZPtx6egPXi4HQxKDnMxVxpbtX2GoA==", + "dev": true, + "requires": { + "@smithy/util-buffer-from": "^2.0.0", + "tslib": "^2.5.0" + } + }, + "@smithy/util-waiter": { + "version": "2.0.13", + "resolved": "https://registry.npmjs.org/@smithy/util-waiter/-/util-waiter-2.0.13.tgz", + "integrity": "sha512-YovIQatiuM7giEsRFotqJa2i3EbU2EE3PgtpXgtLgpx5rXiZMAwPxXYDFVFhuO0lbqvc/Zx4n+ZIisXOHPSqyg==", "dev": true, "requires": { + "@smithy/abort-controller": "^2.0.13", + "@smithy/types": "^2.5.0", "tslib": "^2.5.0" } }, @@ -16672,6 +17112,8 @@ }, "2-thenable": { "version": "1.0.0", + "resolved": "https://registry.npmjs.org/2-thenable/-/2-thenable-1.0.0.tgz", + "integrity": "sha512-HqiDzaLDFCXkcCO/SwoyhRwqYtINFHF7t9BDRq4x90TOKNAJpiqUt9X5lQ08bwxYzc067HUywDjGySpebHcUpw==", "dev": true, "requires": { "d": "1", @@ -16717,10 +17159,14 @@ }, "adm-zip": { "version": "0.5.10", + "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.5.10.tgz", + "integrity": "sha512-x0HvcHqVJNTPk/Bw8JbLWlWoo6Wwnsug0fnYYro1HBrjxZ3G7/AZk7Ahv8JwDe1uIcz8eBqvu86FuF1POiG7vQ==", "dev": true }, "agent-base": { "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", "dev": true, "requires": { "debug": "4" @@ -16798,20 +17244,24 @@ } }, "archiver": { - "version": "5.3.1", + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/archiver/-/archiver-5.3.2.tgz", + "integrity": "sha512-+25nxyyznAXF7Nef3y0EbBeqmGZgeN/BxHX29Rs39djAfaFalmQ89SE6CWyDCHzGL0yt/ycBtNOmGTW0FyGWNw==", "dev": true, "requires": { "archiver-utils": "^2.1.0", - "async": "^3.2.3", + "async": "^3.2.4", "buffer-crc32": "^0.2.1", "readable-stream": "^3.6.0", - "readdir-glob": "^1.0.0", + "readdir-glob": "^1.1.2", "tar-stream": "^2.2.0", "zip-stream": "^4.1.0" } }, "archiver-utils": { "version": "2.1.0", + "resolved": "https://registry.npmjs.org/archiver-utils/-/archiver-utils-2.1.0.tgz", + "integrity": "sha512-bEL/yUb/fNNiNTuUz979Z0Yg5L+LzLxGJz8x79lYmR54fmTIb6ob/hNQgkQnIUDWIFjZVQwl9Xs356I6BAMHfw==", "dev": true, "requires": { "glob": "^7.1.4", @@ -16828,6 +17278,8 @@ "dependencies": { "readable-stream": { "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", "dev": true, "requires": { "core-util-is": "~1.0.0", @@ -16841,10 +17293,14 @@ }, "safe-buffer": { "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", "dev": true }, "string_decoder": { "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "requires": { "safe-buffer": "~5.1.0" @@ -16931,7 +17387,9 @@ "dev": true }, "async": { - "version": "3.2.4", + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.5.tgz", + "integrity": "sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==", "dev": true }, "async-hook-domain": { @@ -16946,6 +17404,8 @@ }, "at-least-node": { "version": "1.0.0", + "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", + "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", "dev": true }, "atomic-sleep": { @@ -17186,9 +17646,9 @@ } }, "aws-sdk": { - "version": "2.1397.0", - "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1397.0.tgz", - "integrity": "sha512-Km+jUscV6vW3vuurSsGrTjEqaNfrE9ykA3IJmJb85V2z5tklJvoBU+7JcCiF6h3BDKegNjiFOM7uoL3cGVGz4g==", + "version": "2.1496.0", + "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1496.0.tgz", + "integrity": "sha512-w/JnK6kmYBDSJ+vt9KKJbYYh3SXak5NFB7uLiev0Ysl3dkxnA3ScSmc1x7KZvDkHcbkACI0VeMPTkftEGvY9kQ==", "dev": true, "requires": { "buffer": "4.9.2", @@ -17214,9 +17674,9 @@ } }, "axios": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.3.5.tgz", - "integrity": "sha512-glL/PvG/E+xCWwV8S6nCHcrfg1exGx7vxyUIivIA1iL7BIh6bePylCfVHwp6k13ao7SATxB6imau2kqY+I67kw==", + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.2.tgz", + "integrity": "sha512-7i24Ri4pmDRfJTR7LDBhsOTtcm+9kjX5WiY1X3wIisx6G9So3pfMkEiU7emUBe46oceVImccTEM3k6C5dbVW8A==", "dev": true, "requires": { "follow-redirects": "^1.15.0", @@ -17235,6 +17695,29 @@ "version": "2.2.0", "dev": true }, + "bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "dev": true, + "requires": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + }, + "dependencies": { + "buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "dev": true, + "requires": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + } + } + }, "bluebird": { "version": "3.7.2", "dev": true @@ -17495,6 +17978,8 @@ }, "child-process-ext": { "version": "2.1.1", + "resolved": "https://registry.npmjs.org/child-process-ext/-/child-process-ext-2.1.1.tgz", + "integrity": "sha512-0UQ55f51JBkOFa+fvR76ywRzxiPwQS3Xe8oe5bZRphpv+dIMeerW5Zn5e4cUy4COJwVtJyU0R79RMnw+aCqmGA==", "dev": true, "requires": { "cross-spawn": "^6.0.5", @@ -17506,6 +17991,8 @@ "dependencies": { "cross-spawn": { "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", "dev": true, "requires": { "nice-try": "^1.0.4", @@ -17517,14 +18004,20 @@ }, "path-key": { "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==", "dev": true }, "semver": { - "version": "5.7.1", + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", "dev": true }, "shebang-command": { "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==", "dev": true, "requires": { "shebang-regex": "^1.0.0" @@ -17532,10 +18025,14 @@ }, "shebang-regex": { "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==", "dev": true }, "which": { "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", "dev": true, "requires": { "isexe": "^2.0.0" @@ -17795,7 +18292,9 @@ "dev": true }, "compress-commons": { - "version": "4.1.1", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/compress-commons/-/compress-commons-4.1.2.tgz", + "integrity": "sha512-D3uMHtGc/fcO1Gt1/L7i1e33VOvD4A9hfQLP+6ewd+BvG/gQ84Yh4oftEhAdjSMgBgwGL+jsppT7JYNpo6MHHg==", "dev": true, "requires": { "buffer-crc32": "^0.2.13", @@ -17858,10 +18357,14 @@ }, "crc-32": { "version": "1.2.2", + "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz", + "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==", "dev": true }, "crc32-stream": { - "version": "4.0.2", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/crc32-stream/-/crc32-stream-4.0.3.tgz", + "integrity": "sha512-NT7w2JVU7DFroFdYkeq8cywxrgjPHWkdX1wjpRQXPX5Asews3tA+Ght6lddQO5Mkumffp3X7GEqku3epj2toIw==", "dev": true, "requires": { "crc-32": "^1.2.0", @@ -17902,7 +18405,9 @@ } }, "dayjs": { - "version": "1.11.7", + "version": "1.11.10", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.10.tgz", + "integrity": "sha512-vjAczensTgRcqDERK0SR2XMwsF/tSvnvlv6VcF2GIhg6Sx4yOIt/irsr1RDJsKiIyBzJDpCoXiWWq28MqH2cnQ==", "dev": true }, "debug": { @@ -17975,10 +18480,6 @@ "version": "5.2.0", "dev": true }, - "is-stream": { - "version": "1.1.0", - "dev": true - }, "readable-stream": { "version": "2.3.8", "dev": true, @@ -18032,10 +18533,6 @@ "file-type": { "version": "6.2.0", "dev": true - }, - "is-stream": { - "version": "1.1.0", - "dev": true } } }, @@ -18051,10 +18548,6 @@ "file-type": { "version": "5.2.0", "dev": true - }, - "is-stream": { - "version": "1.1.0", - "dev": true } } }, @@ -18174,11 +18667,15 @@ } }, "dotenv": { - "version": "16.0.3", + "version": "16.3.1", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.3.1.tgz", + "integrity": "sha512-IPzF4w4/Rd94bA9imS68tZBaYyBWSCE47V1RGuMrB94iyTOIEwRmVL2x/4An+6mETpLrKJ5hQkB8W4kFAadeIQ==", "dev": true }, "dotenv-expand": { - "version": "9.0.0", + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-10.0.0.tgz", + "integrity": "sha512-GopVGCpVS1UKH75VKHGuQFqS1Gusej0z4FyQkPdwjil2gNIv+LNsqBlboOzpJFZKVT95GkCyWJbBSdFEFUWI2A==", "dev": true }, "duration": { @@ -18604,7 +19101,9 @@ } }, "semver": { - "version": "6.3.0", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true } } @@ -18659,7 +19158,9 @@ "dev": true }, "semver": { - "version": "6.3.0", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true } } @@ -18855,9 +19356,9 @@ "dev": true }, "fast-xml-parser": { - "version": "4.2.4", - "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.2.4.tgz", - "integrity": "sha512-fbfMDvgBNIdDJLdLOwacjFAPYt67tr31H9ZhWSm45CDAxvd0I6WTlSOUo7K2P/K5sA5JgMKG64PI3DMcaFdWpQ==", + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.2.5.tgz", + "integrity": "sha512-B9/wizE4WngqQftFPmdaMYlXoJlJOYxGQOanC77fq9k8+Z0v5dDSVh+3glErdIROP//s/jgb7ZuxKfB8nVyo0g==", "dev": true, "requires": { "strnum": "^1.0.5" @@ -18924,7 +19425,9 @@ } }, "filesize": { - "version": "10.0.6", + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/filesize/-/filesize-10.1.0.tgz", + "integrity": "sha512-GTLKYyBSDz3nPhlLVPjPWZCnhkd9TrrRArNcy8Z+J2cqScB7h2McAzR6NBX6nYOoWafql0roY8hrocxnZBv9CQ==", "dev": true }, "fill-range": { @@ -18952,6 +19455,8 @@ }, "flat": { "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", "dev": true }, "flat-cache": { @@ -19032,6 +19537,8 @@ }, "fs-extra": { "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", "dev": true, "requires": { "at-least-node": "^1.0.0", @@ -19202,7 +19709,9 @@ } }, "graceful-fs": { - "version": "4.2.10", + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", "dev": true }, "grapheme-splitter": { @@ -19217,9 +19726,9 @@ } }, "graphql": { - "version": "16.6.0", - "resolved": "https://registry.npmjs.org/graphql/-/graphql-16.6.0.tgz", - "integrity": "sha512-KPIBPDlW7NxrbT/eh4qPXz5FiFdL5UbaA0XUNz2Rp3Z3hqBSkbj0GVjwFDztsWVauZUWsbKHgMg++sk8UX0bkw==", + "version": "16.8.1", + "resolved": "https://registry.npmjs.org/graphql/-/graphql-16.8.1.tgz", + "integrity": "sha512-59LZHPdGZVh695Ud9lRzPBVTtlX9ZCV150Er2W43ro37wVof0ctenSaskPPjN7lVTIN8mSZt8PHUNKZuNQUuxw==", "dev": true, "peer": true }, @@ -19363,6 +19872,8 @@ }, "https-proxy-agent": { "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", "dev": true, "requires": { "agent-base": "6", @@ -19421,6 +19932,8 @@ }, "immediate": { "version": "3.0.6", + "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", + "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==", "dev": true }, "import-fresh": { @@ -19820,6 +20333,12 @@ "call-bind": "^1.0.2" } }, + "is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==", + "dev": true + }, "is-string": { "version": "1.0.7", "dev": true, @@ -19882,6 +20401,8 @@ }, "isomorphic-ws": { "version": "4.0.1", + "resolved": "https://registry.npmjs.org/isomorphic-ws/-/isomorphic-ws-4.0.1.tgz", + "integrity": "sha512-BhBvN2MBpWTaSHdWRb/bwdZJ1WaehQ2L1KngkCkfLUGF0mAWAT1sQUQacEmQ0jXkFw/czDXPNQSL5u2/Krsz1w==", "dev": true, "requires": {} }, @@ -19900,17 +20421,6 @@ "istanbul-lib-coverage": "^3.0.0", "make-dir": "^4.0.0", "supports-color": "^7.1.0" - }, - "dependencies": { - "make-dir": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", - "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", - "dev": true, - "requires": { - "semver": "^7.5.3" - } - } } }, "istanbul-reports": { @@ -19965,8 +20475,78 @@ "version": "3.0.1", "dev": true }, + "json-colorizer": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/json-colorizer/-/json-colorizer-2.2.2.tgz", + "integrity": "sha512-56oZtwV1piXrQnRNTtJeqRv+B9Y/dXAYLqBBaYl/COcUdoZxgLBLAO88+CnkbT6MxNs0c5E9mPBIb2sFcNz3vw==", + "dev": true, + "requires": { + "chalk": "^2.4.1", + "lodash.get": "^4.4.2" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, "json-cycle": { - "version": "1.3.0", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/json-cycle/-/json-cycle-1.5.0.tgz", + "integrity": "sha512-GOehvd5PO2FeZ5T4c+RxobeT5a1PiGpF4u9/3+UvrMU4bhnVqzJY7hm39wg8PDCqkU91fWGH8qjWR4bn+wgq9w==", "dev": true }, "json-parse-even-better-errors": { @@ -20025,6 +20605,8 @@ }, "jszip": { "version": "3.10.1", + "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz", + "integrity": "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==", "dev": true, "requires": { "lie": "~3.3.0", @@ -20035,6 +20617,8 @@ "dependencies": { "readable-stream": { "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", "dev": true, "requires": { "core-util-is": "~1.0.0", @@ -20048,10 +20632,14 @@ }, "safe-buffer": { "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", "dev": true }, "string_decoder": { "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "requires": { "safe-buffer": "~5.1.0" @@ -20061,6 +20649,8 @@ }, "jwt-decode": { "version": "2.2.0", + "resolved": "https://registry.npmjs.org/jwt-decode/-/jwt-decode-2.2.0.tgz", + "integrity": "sha512-86GgN2vzfUu7m9Wcj63iUkuDzFNYFVmjeDm2GzWpUk+opB0pEpMsw6ePCMrhYkumz2C1ihqtZzOMAg7FiXcNoQ==", "dev": true }, "keygrip": { @@ -20128,6 +20718,8 @@ }, "lazystream": { "version": "1.0.1", + "resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.1.tgz", + "integrity": "sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==", "dev": true, "requires": { "readable-stream": "^2.0.5" @@ -20135,6 +20727,8 @@ "dependencies": { "readable-stream": { "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", "dev": true, "requires": { "core-util-is": "~1.0.0", @@ -20148,10 +20742,14 @@ }, "safe-buffer": { "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", "dev": true }, "string_decoder": { "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "requires": { "safe-buffer": "~5.1.0" @@ -20169,6 +20767,8 @@ }, "lie": { "version": "3.3.0", + "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz", + "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==", "dev": true, "requires": { "immediate": "~3.0.5" @@ -20325,18 +20925,32 @@ }, "lodash.defaults": { "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz", + "integrity": "sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==", "dev": true }, "lodash.difference": { "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.difference/-/lodash.difference-4.5.0.tgz", + "integrity": "sha512-dS2j+W26TQ7taQBGN8Lbbq04ssV3emRw4NY58WErlTO29pIqS0HmoT5aJ9+TUQ1N3G+JOZSji4eugsWwGp9yPA==", "dev": true }, "lodash.flatten": { "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz", + "integrity": "sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g==", + "dev": true + }, + "lodash.get": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", + "integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==", "dev": true }, "lodash.isplainobject": { "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", "dev": true }, "lodash.merge": { @@ -20345,6 +20959,8 @@ }, "lodash.union": { "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.union/-/lodash.union-4.6.0.tgz", + "integrity": "sha512-c4pB2CdGrGdjMKYLA+XiRDO7Y0PRQbm/Gzg8qMj+QH+pFVAoTp5sBpO0odL3FjoPCGjK96p6qsP+yQoiLoOBcw==", "dev": true }, "log": { @@ -20454,16 +21070,12 @@ } }, "make-dir": { - "version": "3.1.0", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", + "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", "dev": true, "requires": { - "semver": "^6.0.0" - }, - "dependencies": { - "semver": { - "version": "6.3.0", - "dev": true - } + "semver": "^7.5.3" } }, "make-error": { @@ -20721,17 +21333,23 @@ }, "nice-try": { "version": "1.0.5", + "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", + "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", "dev": true }, "node-dir": { "version": "0.1.17", + "resolved": "https://registry.npmjs.org/node-dir/-/node-dir-0.1.17.tgz", + "integrity": "sha512-tmPX422rYgofd4epzrNoOXiE8XFZYOcCq1vD7MAXCDO+O+zndlA2ztdKKMa+EeuBG5tHETpr4ml4RGgpqDCCAg==", "dev": true, "requires": { "minimatch": "^3.0.2" } }, "node-fetch": { - "version": "2.6.9", + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", "dev": true, "requires": { "whatwg-url": "^5.0.0" @@ -21067,25 +21685,6 @@ "log-symbols": "^4.1.0", "strip-ansi": "^6.0.0", "wcwidth": "^1.0.1" - }, - "dependencies": { - "bl": { - "version": "4.1.0", - "dev": true, - "requires": { - "buffer": "^5.5.0", - "inherits": "^2.0.4", - "readable-stream": "^3.4.0" - } - }, - "buffer": { - "version": "5.7.1", - "dev": true, - "requires": { - "base64-js": "^1.3.1", - "ieee754": "^1.1.13" - } - } } }, "os-tmpdir": { @@ -21182,6 +21781,8 @@ }, "pako": { "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", "dev": true }, "parent-module": { @@ -21451,6 +22052,8 @@ }, "querystring": { "version": "0.2.1", + "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.1.tgz", + "integrity": "sha512-wkvS7mL/JMugcup3/rMitHmd9ecIGd2lhFhK9N3UUQ450h66d1r3Y9nvXzQAW1Lq+wyx61k/1pfKS5KuKiyEbg==", "dev": true }, "queue-microtask": { @@ -21595,7 +22198,9 @@ } }, "readdir-glob": { - "version": "1.1.2", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/readdir-glob/-/readdir-glob-1.1.3.tgz", + "integrity": "sha512-v05I2k7xN8zXvPD9N+z/uhXPaj0sUFCe2rcWZIpBsqxfP7xXFQ0tipAd/wjj1YxWyWtUS5IDJpOG82JKt2EAVA==", "dev": true, "requires": { "minimatch": "^5.1.0" @@ -21603,6 +22208,8 @@ "dependencies": { "brace-expansion": { "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", "dev": true, "requires": { "balanced-match": "^1.0.0" @@ -21610,6 +22217,8 @@ }, "minimatch": { "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", "dev": true, "requires": { "brace-expansion": "^2.0.1" @@ -21772,6 +22381,8 @@ }, "run-parallel-limit": { "version": "1.1.0", + "resolved": "https://registry.npmjs.org/run-parallel-limit/-/run-parallel-limit-1.1.0.tgz", + "integrity": "sha512-jJA7irRNM91jaKc3Hcl1npHsFLOXOoTkPCUL1JEa1R82O2miplXXRaGdjW/KM/98YQWDhJLiSs793CnXfblJUw==", "dev": true, "requires": { "queue-microtask": "^1.2.2" @@ -21858,18 +22469,19 @@ } }, "serverless": { - "version": "3.28.1", - "resolved": "https://registry.npmjs.org/serverless/-/serverless-3.28.1.tgz", - "integrity": "sha512-zC+8ItbRYtJkIY5YZkU5RrCGd+JPkn8DUeGpHX6C9NKV/555DppiaMXURcNWJqN6VFV3fhmZrtefTzDF/B6+Rg==", + "version": "3.36.0", + "resolved": "https://registry.npmjs.org/serverless/-/serverless-3.36.0.tgz", + "integrity": "sha512-VY7UzP4u1/yuTNpF2Wssrru16qhhReLCjgL2oeHCvhujxPyTFv9TQGSlLhaT0ZUCXhRBphwVwITTRopo6NSUgA==", "dev": true, "requires": { - "@serverless/dashboard-plugin": "^6.2.3", - "@serverless/platform-client": "^4.3.2", - "@serverless/utils": "^6.8.2", + "@serverless/dashboard-plugin": "^7.1.0", + "@serverless/platform-client": "^4.4.0", + "@serverless/utils": "^6.13.1", + "abort-controller": "^3.0.0", "ajv": "^8.12.0", "ajv-formats": "^2.1.1", "archiver": "^5.3.1", - "aws-sdk": "^2.1326.0", + "aws-sdk": "^2.1404.0", "bluebird": "^3.7.2", "cachedir": "^2.3.0", "chalk": "^4.1.2", @@ -21877,28 +22489,28 @@ "ci-info": "^3.8.0", "cli-progress-footer": "^2.3.2", "d": "^1.0.1", - "dayjs": "^1.11.7", + "dayjs": "^1.11.8", "decompress": "^4.2.1", - "dotenv": "^16.0.3", - "dotenv-expand": "^9.0.0", + "dotenv": "^16.3.1", + "dotenv-expand": "^10.0.0", "essentials": "^1.2.0", "ext": "^1.7.0", "fastest-levenshtein": "^1.0.16", - "filesize": "^10.0.6", + "filesize": "^10.0.7", "fs-extra": "^10.1.0", "get-stdin": "^8.0.0", "globby": "^11.1.0", - "got": "^11.8.6", - "graceful-fs": "^4.2.10", + "graceful-fs": "^4.2.11", "https-proxy-agent": "^5.0.1", "is-docker": "^2.2.1", "js-yaml": "^4.1.0", - "json-cycle": "^1.3.0", + "json-colorizer": "^2.2.2", + "json-cycle": "^1.5.0", "json-refs": "^3.0.15", "lodash": "^4.17.21", "memoizee": "^0.4.15", "micromatch": "^4.0.5", - "node-fetch": "^2.6.9", + "node-fetch": "^2.6.11", "npm-registry-utilities": "^1.0.0", "object-hash": "^3.0.0", "open": "^8.4.2", @@ -21906,15 +22518,17 @@ "process-utils": "^4.0.0", "promise-queue": "^2.2.5", "require-from-string": "^2.0.2", - "semver": "^7.3.8", + "semver": "^7.5.3", "signal-exit": "^3.0.7", + "stream-buffers": "^3.0.2", "strip-ansi": "^6.0.1", "supports-color": "^8.1.1", - "tar": "^6.1.13", + "tar": "^6.1.15", "timers-ext": "^0.1.7", "type": "^2.7.2", "untildify": "^4.0.0", "uuid": "^9.0.0", + "ws": "^7.5.9", "yaml-ast-parser": "0.0.43" }, "dependencies": { @@ -22121,6 +22735,8 @@ }, "setimmediate": { "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==", "dev": true }, "setprototypeof": { @@ -22166,7 +22782,9 @@ } }, "simple-git": { - "version": "3.16.1", + "version": "3.20.0", + "resolved": "https://registry.npmjs.org/simple-git/-/simple-git-3.20.0.tgz", + "integrity": "sha512-ozK8tl2hvLts8ijTs18iFruE+RoqmC/mqZhjs/+V7gS5W68JpJ3+FCTmLVqmR59MaUQ52MfGQuWsIqfsTbbJ0Q==", "dev": true, "requires": { "@kwsites/file-exists": "^1.1.1", @@ -22320,6 +22938,8 @@ }, "split2": { "version": "3.2.2", + "resolved": "https://registry.npmjs.org/split2/-/split2-3.2.2.tgz", + "integrity": "sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg==", "dev": true, "requires": { "readable-stream": "^3.0.0" @@ -22376,19 +22996,21 @@ "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", "dev": true }, + "stream-buffers": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/stream-buffers/-/stream-buffers-3.0.2.tgz", + "integrity": "sha512-DQi1h8VEBA/lURbSwFtEHnSTb9s2/pwLEaFuNhXwy1Dx3Sa0lOuYT2yNUr4/j2fs8oCAMANtrZ5OrPZtyVs3MQ==", + "dev": true + }, "stream-promise": { "version": "3.2.0", + "resolved": "https://registry.npmjs.org/stream-promise/-/stream-promise-3.2.0.tgz", + "integrity": "sha512-P+7muTGs2C8yRcgJw/PPt61q7O517tDHiwYEzMWo1GSBCcZedUMT/clz7vUNsSxFphIlJ6QUL4GexQKlfJoVtA==", "dev": true, "requires": { "2-thenable": "^1.0.0", "es5-ext": "^0.10.49", "is-stream": "^1.1.0" - }, - "dependencies": { - "is-stream": { - "version": "1.1.0", - "dev": true - } } }, "string_decoder": { @@ -22677,19 +23299,23 @@ } }, "tar": { - "version": "6.1.13", + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.0.tgz", + "integrity": "sha512-/Wo7DcT0u5HUV486xg675HtjNd3BXZ6xDbzsCUZPt5iw8bTQ63bP0Raut3mvro9u+CUyq7YQd8Cx55fsZXxqLQ==", "dev": true, "requires": { "chownr": "^2.0.0", "fs-minipass": "^2.0.0", - "minipass": "^4.0.0", + "minipass": "^5.0.0", "minizlib": "^2.1.1", "mkdirp": "^1.0.3", "yallist": "^4.0.0" }, "dependencies": { "minipass": { - "version": "4.2.4", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", + "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", "dev": true }, "yallist": { @@ -22700,6 +23326,8 @@ }, "tar-stream": { "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", + "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", "dev": true, "requires": { "bl": "^4.0.3", @@ -22707,25 +23335,6 @@ "fs-constants": "^1.0.0", "inherits": "^2.0.3", "readable-stream": "^3.1.1" - }, - "dependencies": { - "bl": { - "version": "4.1.0", - "dev": true, - "requires": { - "buffer": "^5.5.0", - "inherits": "^2.0.4", - "readable-stream": "^3.4.0" - } - }, - "buffer": { - "version": "5.7.1", - "dev": true, - "requires": { - "base64-js": "^1.3.1", - "ieee754": "^1.1.13" - } - } } }, "tcompare": { @@ -22770,6 +23379,12 @@ "real-require": "^0.2.0" } }, + "throat": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/throat/-/throat-5.0.0.tgz", + "integrity": "sha512-fcwX4mndzpLQKBS1DVYhGAcYaYt7vsHNIvQV+WXMvnow5cgjPphq5CaayLaGsjRdSCKZFNGt7/GYAuXaNOiYCA==", + "dev": true + }, "through": { "version": "2.3.8", "dev": true @@ -22822,6 +23437,8 @@ }, "traverse": { "version": "0.6.7", + "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.6.7.tgz", + "integrity": "sha512-/y956gpUo9ZNCb99YjxG7OaslxZWHfCHAUUfshwqOXmxUIvqLjVO581BT+gM59+QV9tFe6/CGG53tsA1Y7RSdg==", "dev": true }, "trim-repeated": { @@ -23287,7 +23904,9 @@ } }, "word-wrap": { - "version": "1.2.3", + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", "dev": true }, "wrap-ansi": { @@ -23316,6 +23935,8 @@ }, "ws": { "version": "7.5.9", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz", + "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==", "dev": true, "requires": {} }, @@ -23372,6 +23993,8 @@ }, "yamljs": { "version": "0.3.0", + "resolved": "https://registry.npmjs.org/yamljs/-/yamljs-0.3.0.tgz", + "integrity": "sha512-C/FsVVhht4iPQYXOInoxUM/1ELSf9EsgKH34FofQOp6hwCPrW4vG4w5++TED3xRUo8gD7l0P1J1dLlDYzODsTQ==", "dev": true, "requires": { "argparse": "^1.0.7", @@ -23427,12 +24050,34 @@ "dev": true }, "zip-stream": { - "version": "4.1.0", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/zip-stream/-/zip-stream-4.1.1.tgz", + "integrity": "sha512-9qv4rlDiopXg4E69k+vMHjNN63YFMe9sZMrdlvKnCjlCRWeCBswPPMPUfx+ipsAWq1LXHe70RcbaHdJJpS6hyQ==", "dev": true, "requires": { - "archiver-utils": "^2.1.0", - "compress-commons": "^4.1.0", + "archiver-utils": "^3.0.4", + "compress-commons": "^4.1.2", "readable-stream": "^3.6.0" + }, + "dependencies": { + "archiver-utils": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/archiver-utils/-/archiver-utils-3.0.4.tgz", + "integrity": "sha512-KVgf4XQVrTjhyWmx6cte4RxonPLR9onExufI1jhvw/MQ4BB6IsZD5gT8Lq+u/+pRkWna/6JoHpiQioaqFP5Rzw==", + "dev": true, + "requires": { + "glob": "^7.2.3", + "graceful-fs": "^4.2.0", + "lazystream": "^1.0.0", + "lodash.defaults": "^4.2.0", + "lodash.difference": "^4.5.0", + "lodash.flatten": "^4.4.0", + "lodash.isplainobject": "^4.0.6", + "lodash.union": "^4.6.0", + "normalize-path": "^3.0.0", + "readable-stream": "^3.6.0" + } + } } } } From 763a843502c089e65d8be9419c05f2cc10607e04 Mon Sep 17 00:00:00 2001 From: Eoin Shanaghy Date: Wed, 15 Nov 2023 23:33:55 +0000 Subject: [PATCH 11/35] fix: remove duplicate metrics from API GW widgets --- core/alarms/api-gateway.ts | 8 +- core/alarms/tests/api-gateway.test.ts | 2 +- core/alarms/tests/sqs.test.ts | 4 +- core/cf-template.ts | 2 +- core/dashboards/dashboard.ts | 9 +- core/dashboards/tests/dashboard-apigw.test.ts | 120 ++++++++++++++ core/dashboards/tests/dashboard.test.ts | 148 ++++++++---------- core/tests/testing-utils.ts | 49 ++++-- 8 files changed, 239 insertions(+), 103 deletions(-) create mode 100644 core/dashboards/tests/dashboard-apigw.test.ts diff --git a/core/alarms/api-gateway.ts b/core/alarms/api-gateway.ts index 592af135..f393b2ef 100644 --- a/core/alarms/api-gateway.ts +++ b/core/alarms/api-gateway.ts @@ -83,13 +83,15 @@ export default function createApiGatewayAlarms ( apiGwAlarmsConfig: SlicWatchApiGwAlarmsConfig, alarmActionsConfig: AlarmActionsConfig, compiledTemplate: Template ): CloudFormationResources { const resources: CloudFormationResources = {} - const configuredResources = getResourceAlarmConfigurationsByType('AWS::ApiGateway::RestApi', compiledTemplate, apiGwAlarmsConfig) + const configuredResources = getResourceAlarmConfigurationsByType( + 'AWS::ApiGateway::RestApi', compiledTemplate, apiGwAlarmsConfig + ) for (const [apiLogicalId, apiResource] of Object.entries(configuredResources.resources)) { for (const metric of executionMetrics) { const mergedConfig: SlicWatchMergedConfig = configuredResources.alarmConfigurations[apiLogicalId][metric] - if (mergedConfig.enabled) { - const { enabled, ...rest } = mergedConfig + const { enabled, ...rest } = mergedConfig + if (enabled) { const apiName = resolveRestApiNameAsCfn(apiResource, apiLogicalId) const apiNameForSub = resolveRestApiNameForSub(apiResource, apiLogicalId) const apiAlarmProperties: AlarmProperties = { diff --git a/core/alarms/tests/api-gateway.test.ts b/core/alarms/tests/api-gateway.test.ts index 311beac7..65a00eff 100644 --- a/core/alarms/tests/api-gateway.test.ts +++ b/core/alarms/tests/api-gateway.test.ts @@ -239,7 +239,7 @@ test('API Gateway alarms are created', (t) => { t.end() }) -test('API Gateway resource configuration overrides take precedence', (t) => { +test('resource config overrides take precedence', (t) => { const testConfig = createTestConfig(defaultConfig.alarms) const template = createTestCloudFormationTemplate(); diff --git a/core/alarms/tests/sqs.test.ts b/core/alarms/tests/sqs.test.ts index c79e6d17..a2a5e93a 100644 --- a/core/alarms/tests/sqs.test.ts +++ b/core/alarms/tests/sqs.test.ts @@ -170,7 +170,7 @@ test('queue resource configuration overrides take precedence', (t) => { alarms: { Period: 900, AgeOfOldestMessage: { - Statistic: 'P99', + Statistic: 'p99', Threshold: 51, enabled: true // this one is disabled by default }, @@ -190,7 +190,7 @@ test('queue resource configuration overrides take precedence', (t) => { const inFlightMessagesFifoAlarm = Object.entries(alarmResources).filter(([key, value]) => key.includes('fifo') && value?.Properties?.MetricName === 'ApproximateNumberOfMessagesNotVisible')[0][1] const inFlightMessagesRegularAlarm = Object.entries(alarmResources).filter(([key, value]) => key.includes('regular') && value?.Properties?.MetricName === 'ApproximateNumberOfMessagesNotVisible')[0][1] t.equal(ageOfOldestMessageAlarm?.Properties?.Threshold, 51) - t.equal(ageOfOldestMessageAlarm?.Properties?.Statistic, 'P99') + t.equal(ageOfOldestMessageAlarm?.Properties?.Statistic, 'p99') t.equal(ageOfOldestMessageAlarm?.Properties?.Period, 900) t.equal(inFlightMessagesFifoAlarm?.Properties?.Period, 60) t.equal(inFlightMessagesFifoAlarm?.Properties?.Threshold, Math.floor(0.8 * 20000)) diff --git a/core/cf-template.ts b/core/cf-template.ts index 226b722d..0b37e4f5 100644 --- a/core/cf-template.ts +++ b/core/cf-template.ts @@ -10,7 +10,7 @@ import { merge } from 'lodash' const logger = getLogger() -export type ResourceType = Record +export type ResourceType = Record /** * Take a CloudFormation reference to a Lambda Function name and attempt to resolve this function's diff --git a/core/dashboards/dashboard.ts b/core/dashboards/dashboard.ts index c3dd3703..c06b113b 100644 --- a/core/dashboards/dashboard.ts +++ b/core/dashboards/dashboard.ts @@ -92,6 +92,8 @@ export default function addDashboard (dashboardConfig: SlicWatchInputDashboardCo /** * Create a metric for the specified metrics * + * TODO - allow Widget Metric Properties to specify x and y axes configuration + * * @param {string} title The metric title * @param {Array.} metricDefs The metric definitions to render * @param {Object} config Cascaded widget/metric configuration @@ -213,9 +215,9 @@ export default function addDashboard (dashboardConfig: SlicWatchInputDashboardCo const apiWidgets: WidgetWithSize[] = [] for (const [logicalId, res] of Object.entries(configuredResources.resources)) { const apiName: string = resolveRestApiNameForSub(res, logicalId) // e.g., ${AWS::Stack} (Ref), ${OtherResource.Name} (GetAtt) - const widgetMetrics: MetricDefs[] = [] const mergedConfig = configuredResources.dashConfigurations[logicalId] for (const [metric, metricConfig] of Object.entries(getConfiguredMetrics(mergedConfig))) { + const widgetMetrics: MetricDefs[] = [] if (metricConfig.enabled) { for (const stat of metricConfig.Statistic) { widgetMetrics.push({ @@ -224,7 +226,8 @@ export default function addDashboard (dashboardConfig: SlicWatchInputDashboardCo dimensions: { ApiName: apiName }, - stat + stat, + yAxis: metricConfig.yAxis }) } } @@ -232,7 +235,7 @@ export default function addDashboard (dashboardConfig: SlicWatchInputDashboardCo const metricStatWidget = createMetricWidget( `${metric} API ${apiName}`, widgetMetrics, - apiGwDashConfig + metricConfig ) apiWidgets.push(metricStatWidget) } diff --git a/core/dashboards/tests/dashboard-apigw.test.ts b/core/dashboards/tests/dashboard-apigw.test.ts new file mode 100644 index 00000000..17d7c305 --- /dev/null +++ b/core/dashboards/tests/dashboard-apigw.test.ts @@ -0,0 +1,120 @@ +import { test } from 'tap' +import { type MetricWidgetProperties } from 'cloudwatch-dashboard-types' + +import addDashboard from '../dashboard' +import defaultConfig from '../../inputs/default-config' + +import { createTestCloudFormationTemplate, getDashboardFromTemplate, getDashboardWidgetsByTitle } from '../../tests/testing-utils' +import { type ResourceType } from '../../cf-template' + +test('dashboard contains configured API Gateway resources', (t) => { + t.test('includes API metrics', (t) => { + const template = createTestCloudFormationTemplate() + addDashboard(defaultConfig.dashboard, template) + + const { dashboard } = getDashboardFromTemplate(template) + const widgets = getDashboardWidgetsByTitle(dashboard, + /4XXError API /, + /5XXError API /, + /Count API /, + /Latency API / + ) + const [code4xxWidget, code5xxWidget, countWidget, latencyWidget] = widgets + + t.same((code4xxWidget.properties as MetricWidgetProperties).metrics, [ + ['AWS/ApiGateway', '4XXError', 'ApiName', 'dev-serverless-test-project', { stat: 'Sum', yAxis: 'left' }] + ]) + + t.same((code5xxWidget.properties as MetricWidgetProperties).metrics, [ + ['AWS/ApiGateway', '5XXError', 'ApiName', 'dev-serverless-test-project', { stat: 'Sum', yAxis: 'left' }] + ]) + + t.same((countWidget.properties as MetricWidgetProperties).metrics, [ + ['AWS/ApiGateway', 'Count', 'ApiName', 'dev-serverless-test-project', { stat: 'Sum', yAxis: 'left' }] + ]) + + t.same((latencyWidget.properties as MetricWidgetProperties).metrics, [ + ['AWS/ApiGateway', 'Latency', 'ApiName', 'dev-serverless-test-project', { stat: 'Average', yAxis: 'left' }], + ['AWS/ApiGateway', 'Latency', 'ApiName', 'dev-serverless-test-project', { stat: 'p95', yAxis: 'left' }] + ]) + + for (const widget of widgets) { + const props: MetricWidgetProperties = widget.properties as MetricWidgetProperties + t.ok((props.metrics?.length ?? 0) > 0) + t.equal(props.period, 300) + t.equal(props.view, 'timeSeries') + } + + t.end() + }) + + t.test('resource config overrides take precedence', (t) => { + const template = createTestCloudFormationTemplate(); + + (template.Resources as ResourceType).ApiGatewayRestApi.Metadata = { + slicWatch: { + dashboard: { + metricPeriod: 900, + width: 24, + height: 12, + '5XXError': { + enabled: true, + Statistic: ['p95'] + }, + '4XXError': { + enabled: false, + Statistic: ['p10'] + }, + Count: { + Statistic: ['Maximum', 'Minimum'] + }, + Latency: { + yAxis: 'right', + width: 24, + height: 24, + Statistic: ['Average', 'p50'] + } + } + } + } + + addDashboard(defaultConfig.dashboard, template) + + const { dashboard } = getDashboardFromTemplate(template) + const widgets = getDashboardWidgetsByTitle(dashboard, + /4XXError API /, + /5XXError API /, + /Count API /, + /Latency API / + ) + const [code4xxWidget, code5xxWidget, countWidget, latencyWidget] = widgets + + t.notOk(code4xxWidget) + + t.same((code5xxWidget.properties as MetricWidgetProperties).metrics, [ + ['AWS/ApiGateway', '5XXError', 'ApiName', 'dev-serverless-test-project', { stat: 'p95', yAxis: 'left' }] + ]) + t.match(code5xxWidget, { width: 24, height: 12 }) + + t.same((countWidget.properties as MetricWidgetProperties).metrics, [ + ['AWS/ApiGateway', 'Count', 'ApiName', 'dev-serverless-test-project', { stat: 'Maximum', yAxis: 'left' }], + ['AWS/ApiGateway', 'Count', 'ApiName', 'dev-serverless-test-project', { stat: 'Minimum', yAxis: 'left' }] + ]) + + t.same((latencyWidget.properties as MetricWidgetProperties).metrics, [ + ['AWS/ApiGateway', 'Latency', 'ApiName', 'dev-serverless-test-project', { stat: 'Average', yAxis: 'right' }], + ['AWS/ApiGateway', 'Latency', 'ApiName', 'dev-serverless-test-project', { stat: 'p50', yAxis: 'right' }] + ]) + t.match(latencyWidget, { width: 24, height: 24 }) + + for (const widget of widgets.filter(widget => Boolean(widget))) { + const props: MetricWidgetProperties = widget.properties as MetricWidgetProperties + t.ok((props.metrics?.length ?? 0) > 0) + t.equal(props.period, 900) + t.equal(props.view, 'timeSeries') + } + + t.end() + }) + t.end() +}) diff --git a/core/dashboards/tests/dashboard.test.ts b/core/dashboards/tests/dashboard.test.ts index 2447d3b7..7e459a8f 100644 --- a/core/dashboards/tests/dashboard.test.ts +++ b/core/dashboards/tests/dashboard.test.ts @@ -1,10 +1,11 @@ import _ from 'lodash' import { test } from 'tap' +import { type MetricWidgetProperties } from 'cloudwatch-dashboard-types' import addDashboard from '../dashboard' import defaultConfig from '../../inputs/default-config' -import { createTestCloudFormationTemplate, defaultCfTemplate, albCfTemplate, appSyncCfTemplate } from '../../tests/testing-utils' +import { createTestCloudFormationTemplate, defaultCfTemplate, albCfTemplate, appSyncCfTemplate, getDashboardFromTemplate } from '../../tests/testing-utils' import { type ResourceType, getResourcesByType } from '../../cf-template' import { type Widgets } from '../dashboard-types' @@ -20,26 +21,27 @@ test('An empty template creates no dashboard', (t) => { }) test('A dashboard includes metrics', (t) => { - const compiledTemplate = createTestCloudFormationTemplate() - addDashboard(defaultConfig.dashboard, compiledTemplate) - const dashResources = getResourcesByType('AWS::CloudWatch::Dashboard', compiledTemplate) - t.equal(Object.keys(dashResources).length, 1) - const [, dashResource] = Object.entries(dashResources)[0] - t.same(dashResource.Properties?.DashboardName, { 'Fn::Sub': '${AWS::StackName}-${AWS::Region}-Dashboard' }) - const dashBody = JSON.parse(dashResource.Properties?.DashboardBody['Fn::Sub']) + const template = createTestCloudFormationTemplate() + addDashboard(defaultConfig.dashboard, template) - t.ok(dashBody.start) + const { dashboard, dashProperties } = getDashboardFromTemplate(template) + t.ok(dashboard) + t.ok(dashProperties) + t.same(dashProperties.DashboardName, { 'Fn::Sub': '${AWS::StackName}-${AWS::Region}-Dashboard' }) + + t.ok(dashboard.start) t.test('dashboards includes Lambda metrics', (t) => { - const widgets = dashBody.widgets.filter(({ properties: { title } }) => - title.startsWith('Lambda') + const widgets = dashboard.widgets.filter(({ properties }) => + ((properties as MetricWidgetProperties).title ?? '').startsWith('Lambda') ) t.equal(widgets.length, 8) const namespaces = new Set() for (const widget of widgets) { - for (const metric of widget.properties.metrics) { + const widgetProperties = widget.properties as MetricWidgetProperties + for (const metric of widgetProperties.metrics ?? []) { t.equal(metric.length, 5) - const metricProperties = metric[4] + const metricProperties = metric[4] as object const propKeys = Object.keys(metricProperties) t.same(propKeys, ['stat']) namespaces.add(metric[0]) @@ -57,45 +59,22 @@ test('A dashboard includes metrics', (t) => { 'Lambda Errors Sum per Function' ]) const actualTitles = new Set( - widgets.map((widget) => widget.properties.title) - ) - t.same(actualTitles, expectedTitles) - t.end() - }) - - t.test('dashboards includes API metrics', (t) => { - const widgets = dashBody.widgets.filter((widget) => - widget.properties.title.indexOf(' API ') > 0 - ) - t.equal(widgets.length, 4) - const namespaces = new Set() - for (const widget of widgets) { - for (const metric of widget.properties.metrics) { - namespaces.add(metric[0]) - } - } - t.same(namespaces, new Set(['AWS/ApiGateway'])) - const expectedTitles = new Set([ - '4XXError API dev-serverless-test-project', - '5XXError API dev-serverless-test-project', - 'Count API dev-serverless-test-project', - 'Latency API dev-serverless-test-project' - ]) - const actualTitles = new Set( - widgets.map((widget) => widget.properties.title) + widgets.map((widget) => (widget.properties as MetricWidgetProperties).title) ) t.same(actualTitles, expectedTitles) t.end() }) t.test('dashboards includes Step Function metrics', (t) => { - const widgets = dashBody.widgets.filter((widget) => - widget.properties.title.endsWith('Step Function Executions') - ) + const widgets = dashboard.widgets.filter((widget) => { + const widgetProperties = widget.properties as MetricWidgetProperties + return (widgetProperties.title ?? '').endsWith('Step Function Executions') + }) t.equal(widgets.length, 2) const namespaces = new Set() for (const widget of widgets) { - for (const metric of widget.properties.metrics) { + const widgetProperties = widget.properties as MetricWidgetProperties + for (const metric of widgetProperties.metrics ?? []) { namespaces.add(metric[0]) } } @@ -103,20 +82,21 @@ test('A dashboard includes metrics', (t) => { const expectedTitles = new Set(['${Workflow.Name} Step Function Executions', '${ExpressWorkflow.Name} Step Function Executions']) const actualTitles = new Set( - widgets.map((widget) => widget.properties.title) + widgets.map((widget) => (widget.properties as MetricWidgetProperties).title) ) t.same(actualTitles, expectedTitles) t.end() }) t.test('dashboards includes DynamoDB metrics', (t) => { - const widgets = dashBody.widgets.filter(({ properties: { title } }) => - title.indexOf('Table') > 0 || title.indexOf('GSI') > 0 - ) + const widgets = dashboard.widgets.filter(({ properties }) => { + const title = (properties as MetricWidgetProperties).title ?? '' + return title.indexOf('Table') > 0 || title.indexOf('GSI') > 0 + }) t.equal(widgets.length, 4) const namespaces = new Set() for (const widget of widgets) { - for (const metric of widget.properties.metrics) { + for (const metric of (widget.properties as MetricWidgetProperties).metrics ?? []) { namespaces.add(metric[0]) } } @@ -129,20 +109,20 @@ test('A dashboard includes metrics', (t) => { ]) const actualTitles = new Set( - widgets.map((widget) => widget.properties.title) + widgets.map((widget) => (widget.properties as MetricWidgetProperties).title) ) t.same(actualTitles, expectedTitles) t.end() }) t.test('dashboard includes Kinesis metrics', (t) => { - const widgets = dashBody.widgets.filter(({ properties: { title } }) => - title.endsWith('Kinesis') + const widgets = dashboard.widgets.filter(({ properties }) => + ((properties as MetricWidgetProperties).title ?? '').endsWith('Kinesis') ) t.equal(widgets.length, 3) const namespaces = new Set() for (const widget of widgets) { - for (const metric of widget.properties.metrics) { + for (const metric of (widget.properties as MetricWidgetProperties).metrics ?? []) { namespaces.add(metric[0]) } } @@ -154,20 +134,20 @@ test('A dashboard includes metrics', (t) => { ]) const actualTitles = new Set( - widgets.map((widget) => widget.properties.title) + widgets.map((widget) => (widget.properties as MetricWidgetProperties).title) ) t.same(actualTitles, expectedTitles) t.end() }) t.test('dashboard includes SQS metrics', (t) => { - const widgets = dashBody.widgets.filter(({ properties: { title } }) => - title.endsWith('SQS') + const widgets = dashboard.widgets.filter(({ properties }) => + ((properties as MetricWidgetProperties).title ?? '').endsWith('SQS') ) t.equal(widgets.length, 6) // 3 groups * 2 queues const namespaces = new Set() for (const widget of widgets) { - for (const metric of widget.properties.metrics) { + for (const metric of (widget.properties as MetricWidgetProperties).metrics ?? []) { namespaces.add(metric[0]) } } @@ -182,20 +162,20 @@ test('A dashboard includes metrics', (t) => { ]) const actualTitles = new Set( - widgets.map((widget) => widget.properties.title) + widgets.map((widget) => (widget.properties as MetricWidgetProperties).title) ) t.same(actualTitles, expectedTitles) t.end() }) t.test('dashboard includes ECS metrics', (t) => { - const widgets = dashBody.widgets.filter(({ properties: { title } }) => - title.startsWith('ECS') + const widgets = dashboard.widgets.filter(({ properties }) => + ((properties as MetricWidgetProperties).title ?? '').startsWith('ECS') ) t.equal(widgets.length, 1) const namespaces = new Set() for (const widget of widgets) { - for (const metric of widget.properties.metrics) { + for (const metric of (widget.properties as MetricWidgetProperties).metrics ?? []) { namespaces.add(metric[0]) } } @@ -205,20 +185,20 @@ test('A dashboard includes metrics', (t) => { ]) const actualTitles = new Set( - widgets.map((widget) => widget.properties.title) + widgets.map((widget) => (widget.properties as MetricWidgetProperties).title) ) t.same(actualTitles, expectedTitles) t.end() }) t.test('dashboard includes SNS metrics', (t) => { - const widgets = dashBody.widgets.filter(({ properties: { title } }) => - title.startsWith('SNS') + const widgets = dashboard.widgets.filter(({ properties }) => + ((properties as MetricWidgetProperties).title ?? '').startsWith('SNS') ) t.equal(widgets.length, 1) const namespaces = new Set() for (const widget of widgets) { - for (const metric of widget.properties.metrics) { + for (const metric of (widget.properties as MetricWidgetProperties).metrics ?? []) { namespaces.add(metric[0]) } } @@ -226,20 +206,20 @@ test('A dashboard includes metrics', (t) => { const expectedTitles = new Set(['SNS Topic ${topic.TopicName}']) const actualTitles = new Set( - widgets.map((widget) => widget.properties.title) + widgets.map((widget) => (widget.properties as MetricWidgetProperties).title) ) t.same(actualTitles, expectedTitles) t.end() }) t.test('dashboard includes Events metrics', (t) => { - const widgets = dashBody.widgets.filter(({ properties: { title } }) => - title.startsWith('EventBridge') + const widgets = dashboard.widgets.filter(({ properties }) => + ((properties as MetricWidgetProperties).title ?? '').startsWith('EventBridge') ) t.equal(widgets.length, 1) const namespaces = new Set() for (const widget of widgets) { - for (const metric of widget.properties.metrics) { + for (const metric of (widget.properties as MetricWidgetProperties).metrics ?? []) { namespaces.add(metric[0]) } } @@ -247,7 +227,7 @@ test('A dashboard includes metrics', (t) => { const expectedTitles = new Set(['EventBridge Rule ${ServerlesstestprojectdeveventsRulerule1EventBridgeRule}']) const actualTitles = new Set( - widgets.map((widget) => widget.properties.title) + widgets.map((widget) => (widget.properties as MetricWidgetProperties).title) ) t.same(actualTitles, expectedTitles) t.end() @@ -263,12 +243,12 @@ test('A dashboard includes metrics for ALB', (t) => { t.equal(Object.keys(dashResources).length, 1) const [, dashResource] = Object.entries(dashResources)[0] t.same(dashResource.Properties?.DashboardName, { 'Fn::Sub': '${AWS::StackName}-${AWS::Region}-Dashboard' }) - const dashBody = JSON.parse(dashResource.Properties?.DashboardBody['Fn::Sub']) + const dashboard = JSON.parse(dashResource.Properties?.DashboardBody['Fn::Sub']) - t.ok(dashBody.start) + t.ok(dashboard.start) t.test('dashboard includes Application Load Balancer metrics', (t) => { - const widgets = dashBody.widgets.filter(({ properties: { title } }) => + const widgets = dashboard.widgets.filter(({ properties: { title } }) => title.startsWith('ALB') ) t.equal(widgets.length, 1) @@ -289,7 +269,7 @@ test('A dashboard includes metrics for ALB', (t) => { }) t.test('dashboard includes Application Load Balancer Target Groups metrics', (t) => { - const widgets = dashBody.widgets.filter(({ properties: { title } }) => + const widgets = dashboard.widgets.filter(({ properties: { title } }) => title.startsWith('Target') ) t.equal(widgets.length, 1) @@ -384,12 +364,12 @@ test('A dashboard includes metrics for ALB', (t) => { t.equal(Object.keys(dashResources).length, 1) const [, dashResource] = Object.entries(dashResources)[0] t.same(dashResource.Properties?.DashboardName, { 'Fn::Sub': '${AWS::StackName}-${AWS::Region}-Dashboard' }) - const dashBody = JSON.parse(dashResource.Properties?.DashboardBody['Fn::Sub']) + const dashboard = JSON.parse(dashResource.Properties?.DashboardBody['Fn::Sub']) - t.ok(dashBody.start) + t.ok(dashboard.start) t.test('dashboard includes AppSync metrics', (t) => { - const widgets = dashBody.widgets.filter(({ properties: { title } }) => + const widgets = dashboard.widgets.filter(({ properties: { title } }) => title.startsWith('AppSync') ) t.equal(widgets.length, 2) @@ -444,8 +424,8 @@ test('DynamoDB widgets are created without GSIs', (t) => { const dashResources = getResourcesByType('AWS::CloudWatch::Dashboard', compiledTemplate) const [, dashResource] = Object.entries(dashResources)[0] - const dashBody = JSON.parse(dashResource.Properties?.DashboardBody['Fn::Sub']) - const widgets = dashBody.widgets + const dashboard = JSON.parse(dashResource.Properties?.DashboardBody['Fn::Sub']) + const widgets = dashboard.widgets t.equal(widgets.length, 2) const expectedTitles = new Set([ @@ -498,9 +478,9 @@ test('A widget is not created for Lambda if disabled at a function level', (t) = addDashboard(defaultConfig.dashboard, compiledTemplate) const dashResources = getResourcesByType('AWS::CloudWatch::Dashboard', compiledTemplate) const [, dashResource] = Object.entries(dashResources)[0] - const dashBody = JSON.parse(dashResource.Properties?.DashboardBody['Fn::Sub']) + const dashboard = JSON.parse(dashResource.Properties?.DashboardBody['Fn::Sub']) - const widgets = dashBody.widgets.filter(({ properties: { title } }) => + const widgets = dashboard.widgets.filter(({ properties: { title } }) => title.startsWith(`Lambda ${metric}`) ) const widgetMetrics = widgets[0].properties.metrics @@ -525,9 +505,9 @@ test('A widget is not created for Lambda if disabled at a function level for eac addDashboard(defaultConfig.dashboard, compiledTemplate) const dashResources = getResourcesByType('AWS::CloudWatch::Dashboard', compiledTemplate) const [, dashResource] = Object.entries(dashResources)[0] - const dashBody = JSON.parse(dashResource.Properties?.DashboardBody['Fn::Sub']) + const dashboard = JSON.parse(dashResource.Properties?.DashboardBody['Fn::Sub']) - const widgets = dashBody.widgets.filter(({ properties: { title } }) => + const widgets = dashboard.widgets.filter(({ properties: { title } }) => title.startsWith(`Lambda ${metric}`) ) const widgetMetrics = widgets[0].properties.metrics @@ -554,9 +534,9 @@ test('No Lambda widgets are created if all metrics for functions are disabled', addDashboard(defaultConfig.dashboard, compiledTemplate) const dashResources = getResourcesByType('AWS::CloudWatch::Dashboard', compiledTemplate) const [, dashResource] = Object.entries(dashResources)[0] - const dashBody = JSON.parse(dashResource.Properties?.DashboardBody['Fn::Sub']) + const dashboard = JSON.parse(dashResource.Properties?.DashboardBody['Fn::Sub']) - const widgets = dashBody.widgets.filter(({ properties: { title } }) => + const widgets = dashboard.widgets.filter(({ properties: { title } }) => title.startsWith('Lambda') ) t.equal(widgets.length, 0) diff --git a/core/tests/testing-utils.ts b/core/tests/testing-utils.ts index be159e87..0fc74318 100644 --- a/core/tests/testing-utils.ts +++ b/core/tests/testing-utils.ts @@ -1,19 +1,23 @@ import _ from 'lodash' import type Template from 'cloudform-types/types/template' import type { AlarmProperties } from 'cloudform-types/types/cloudWatch/alarm' +import type { DashboardProperties } from 'cloudform-types/types/cloudWatch/dashboard' +import type { MetricWidgetProperties, Dashboard } from 'cloudwatch-dashboard-types' import { cascade } from '../inputs/cascading-config' import _defaultCfTemplate from '../cf-resources/cloudformation-template-stack.json' import _albCfTemplate from '../cf-resources/alb-cloudformation-template-stack.json' import _appSyncCfTemplate from '../cf-resources/appsync-cloudformation-template-stack.json' import { type AlarmActionsConfig } from '../alarms/alarm-types' +import { getResourcesByType } from '../cf-template' + const defaultCfTemplate = _defaultCfTemplate as Template const albCfTemplate = _albCfTemplate as Template const appSyncCfTemplate = _appSyncCfTemplate as unknown as Template const testAlarmActionsConfig: AlarmActionsConfig = { alarmActions: ['dummy-arn'], okActions: ['dummy-arn-2'], actionsEnabled: true } -function assertCommonAlarmProperties (t, al: AlarmProperties) { +export function assertCommonAlarmProperties (t, al: AlarmProperties) { t.ok(al.AlarmDescription) t.ok(al.ActionsEnabled) t.ok(al.AlarmActions) @@ -28,14 +32,14 @@ function assertCommonAlarmProperties (t, al: AlarmProperties) { * @param {*} alarmName The alarm name as a string or {'Fn::Sub': ...} object * @returns The inferred type */ -function alarmNameToType (alarmName) { +export function alarmNameToType (alarmName) { const resolvedName = typeof alarmName === 'string' ? alarmName : alarmName.payload[0] const components = resolvedName.split('_') components.pop() return components.join('_') } -function createTestConfig (from, cascadingChanges = {}): any { +export function createTestConfig (from, cascadingChanges = {}): any { return cascade( _.merge( {}, @@ -45,17 +49,44 @@ function createTestConfig (from, cascadingChanges = {}): any { ) } -function createTestCloudFormationTemplate (stackDefinition = defaultCfTemplate): Template { +export function createTestCloudFormationTemplate (stackDefinition = defaultCfTemplate): Template { return _.cloneDeep(stackDefinition) } +export interface TemplateDashboardFinding { + dashboard: Dashboard + dashProperties: DashboardProperties +} + +export function getDashboardFromTemplate (template: Template): TemplateDashboardFinding { + const dashResources = getResourcesByType('AWS::CloudWatch::Dashboard', template) + const [, dashResource] = Object.entries(dashResources)[0] + const dashboard = JSON.parse(dashResource.Properties?.DashboardBody['Fn::Sub']) + return { + dashboard, + dashProperties: dashResource.Properties as DashboardProperties + } +} + +export function getDashboardWidgetsByTitle (dashboard: Dashboard, ...patterns: RegExp[]) { + return patterns.map((pattern) => { + const widgets = dashboard.widgets.filter((widget) => { + const props = widget.properties as MetricWidgetProperties + if (typeof props?.title === 'string') { + return pattern.test(props.title) + } + return false + }) + if (widgets.length > 1) { + throw new Error(`Multiple widgets found matching ${pattern}`) + } + return widgets[0] + }) +} + export { albCfTemplate, appSyncCfTemplate, defaultCfTemplate, - testAlarmActionsConfig, - assertCommonAlarmProperties, - alarmNameToType, - createTestConfig, - createTestCloudFormationTemplate + testAlarmActionsConfig } From e775d934565ec9f9c18411ed1c8b2abf474b5241 Mon Sep 17 00:00:00 2001 From: Eoin Shanaghy Date: Sat, 18 Nov 2023 08:37:30 +0000 Subject: [PATCH 12/35] chore: extract and extend Lambda dashboard tests --- core/dashboards/dashboard.ts | 6 +- .../dashboards/tests/dashboard-lambda.test.ts | 189 ++++++++++++++++++ core/dashboards/tests/dashboard.test.ts | 34 ---- core/tests/testing-utils.ts | 2 +- 4 files changed, 194 insertions(+), 37 deletions(-) create mode 100644 core/dashboards/tests/dashboard-lambda.test.ts diff --git a/core/dashboards/dashboard.ts b/core/dashboards/dashboard.ts index c06b113b..e91b63d6 100644 --- a/core/dashboards/dashboard.ts +++ b/core/dashboards/dashboard.ts @@ -148,7 +148,8 @@ export default function addDashboard (dashboardConfig: SlicWatchInputDashboardCo namespace: 'AWS/Lambda', metric, dimensions: { FunctionName: `\${${funcLogicalId}}` }, - stat: stat as Statistic + stat: stat as Statistic, + yAxis: metricConfig.yAxis }) } } @@ -176,7 +177,8 @@ export default function addDashboard (dashboardConfig: SlicWatchInputDashboardCo namespace: 'AWS/Lambda', metric: 'IteratorAge', dimensions: { FunctionName: `\${${funcLogicalId}}` }, - stat: stat as Statistic + stat: stat as Statistic, + yAxis: metricConfig.yAxis })), metricConfig as Widgets ) diff --git a/core/dashboards/tests/dashboard-lambda.test.ts b/core/dashboards/tests/dashboard-lambda.test.ts new file mode 100644 index 00000000..7a8baeb7 --- /dev/null +++ b/core/dashboards/tests/dashboard-lambda.test.ts @@ -0,0 +1,189 @@ +import { merge } from 'lodash' + +import { test } from 'tap' +import { type MetricWidgetProperties } from 'cloudwatch-dashboard-types' + +import addDashboard from '../dashboard' +import defaultConfig from '../../inputs/default-config' + +import { createTestCloudFormationTemplate, getDashboardFromTemplate, getDashboardWidgetsByTitle } from '../../tests/testing-utils' +import { type ResourceType } from '../../cf-template' + +test('dashboard contains configured Lambda Function resources', (t) => { + t.test('dashboards includes Lambda metrics', (t) => { + const template = createTestCloudFormationTemplate() + addDashboard(defaultConfig.dashboard, template) + const { dashboard } = getDashboardFromTemplate(template) + + const widgets = getDashboardWidgetsByTitle(dashboard, + /Lambda Duration Average/, + /Lambda Duration p95/, + /Lambda Duration Maximum/, + /Lambda Invocations/, + /Lambda IteratorAge .* Maximum/, + /Lambda ConcurrentExecutions/, + /Lambda Throttles/, + /Lambda Errors/ + ) + + for (const widget of widgets) { + t.ok(widget) + } + + const [ + durationAvgWidget, durationP95Widget, durationMaxWidget, invocationsWidget, iteratorAgeWidget, concurrentExecutionsWidget, throttlesWidget, errorsWidget + ] = widgets + + t.match((durationAvgWidget.properties as MetricWidgetProperties).metrics, [ + ['AWS/Lambda', 'Duration', 'FunctionName', '${HelloLambdaFunction}', { stat: 'Average', yAxis: 'left' }] + ]) + t.match((durationP95Widget.properties as MetricWidgetProperties).metrics, [ + ['AWS/Lambda', 'Duration', 'FunctionName', '${HelloLambdaFunction}', { stat: 'p95', yAxis: 'left' }] + ]) + t.match((durationMaxWidget.properties as MetricWidgetProperties).metrics, [ + ['AWS/Lambda', 'Duration', 'FunctionName', '${HelloLambdaFunction}', { stat: 'Maximum', yAxis: 'left' }] + ]) + t.match((invocationsWidget.properties as MetricWidgetProperties).metrics, [ + ['AWS/Lambda', 'Invocations', 'FunctionName', '${HelloLambdaFunction}', { stat: 'Sum', yAxis: 'left' }] + ]) + t.match((iteratorAgeWidget.properties as MetricWidgetProperties).metrics, [ + ['AWS/Lambda', 'IteratorAge', 'FunctionName', '${StreamProcessorLambdaFunction}', { stat: 'Maximum', yAxis: 'left' }] + ]) + t.match((concurrentExecutionsWidget.properties as MetricWidgetProperties).metrics, [ + ['AWS/Lambda', 'ConcurrentExecutions', 'FunctionName', '${HelloLambdaFunction}', { stat: 'Maximum', yAxis: 'left' }] + ]) + t.match((throttlesWidget.properties as MetricWidgetProperties).metrics, [ + ['AWS/Lambda', 'Throttles', 'FunctionName', '${HelloLambdaFunction}', { stat: 'Sum', yAxis: 'left' }] + ]) + t.match((errorsWidget.properties as MetricWidgetProperties).metrics, [ + ['AWS/Lambda', 'Errors', 'FunctionName', '${HelloLambdaFunction}', { stat: 'Sum', yAxis: 'left' }] + ]) + + for (const widget of widgets) { + const props: MetricWidgetProperties = widget.properties as MetricWidgetProperties + t.ok((props.metrics?.length ?? 0) > 0) + t.equal(props.period, 300) + t.equal(props.view, 'timeSeries') + } + + t.end() + }) + + t.test('service config overrides take precedence', (t) => { + const template = createTestCloudFormationTemplate() + + const config = merge({}, defaultConfig.dashboard, { + widgets: { + Lambda: { + metricPeriod: 900, + width: 8, + height: 12, + Errors: { + Statistic: ['ts80'], + yAxis: 'right' + }, + Throttles: { + Statistic: ['Maximum'], + enabled: false + }, + Duration: { + Statistic: ['p90', 'Average', 'Maximum'] + }, + Invocations: { + Statistic: ['ts90'] + }, + ConcurrentExecutions: { + Statistic: ['p95'] + }, + IteratorAge: { + Statistic: ['p98'] + } + } + } + }) + + addDashboard(config, template) + + const { dashboard } = getDashboardFromTemplate(template) + const widgets = getDashboardWidgetsByTitle(dashboard, + /Lambda Duration Average/, + /Lambda Duration p90/, + /Lambda Duration Maximum/, + /Lambda Invocations/, + /Lambda IteratorAge .* p98/, + /Lambda ConcurrentExecutions/, + /Lambda Throttles/, + /Lambda Errors/ + ) + + const [ + durationAvgWidget, durationP90Widget, durationMaxWidget, invocationsWidget, iteratorAgeWidget, concurrentExecutionsWidget, throttlesWidget, errorsWidget + ] = widgets + + t.match((durationAvgWidget.properties as MetricWidgetProperties).metrics, [ + ['AWS/Lambda', 'Duration', 'FunctionName', '${HelloLambdaFunction}', { stat: 'Average', yAxis: 'left' }] + ]) + + t.match((durationP90Widget.properties as MetricWidgetProperties).metrics, [ + ['AWS/Lambda', 'Duration', 'FunctionName', '${HelloLambdaFunction}', { stat: 'p90', yAxis: 'left' }] + ]) + + t.match((durationMaxWidget.properties as MetricWidgetProperties).metrics, [ + ['AWS/Lambda', 'Duration', 'FunctionName', '${HelloLambdaFunction}', { stat: 'Maximum', yAxis: 'left' }] + ]) + + for (const widget of widgets) { + if (widget !== undefined) { + t.match(widget, { width: 8, height: 12 }) + t.equal((widget.properties as MetricWidgetProperties).period, 900) + } + } + t.notOk(throttlesWidget) + + t.match((invocationsWidget.properties as MetricWidgetProperties).metrics, [ + ['AWS/Lambda', 'Invocations', 'FunctionName', '${HelloLambdaFunction}', { stat: 'ts90', yAxis: 'left' }] + ]) + t.match((iteratorAgeWidget.properties as MetricWidgetProperties).metrics, [ + ['AWS/Lambda', 'IteratorAge', 'FunctionName', '${StreamProcessorLambdaFunction}', { stat: 'p98', yAxis: 'left' }] + ]) + t.match((concurrentExecutionsWidget.properties as MetricWidgetProperties).metrics, [ + ['AWS/Lambda', 'ConcurrentExecutions', 'FunctionName', '${HelloLambdaFunction}', { stat: 'p95', yAxis: 'left' }] + ]) + t.match((errorsWidget.properties as MetricWidgetProperties).metrics, [ + ['AWS/Lambda', 'Errors', 'FunctionName', '${HelloLambdaFunction}', { stat: 'ts80', yAxis: 'right' }] + ]) + + t.end() + }) + + t.test('resource config overrides take precedence', (t) => { + const template = createTestCloudFormationTemplate(); + + (template.Resources as ResourceType).HelloLambdaFunction.Metadata = { + slicWatch: { + dashboard: { + Errors: { + yAxis: 'right' + } + } + } + } + + addDashboard(defaultConfig.dashboard, template) + + const { dashboard } = getDashboardFromTemplate(template) + const widgets = getDashboardWidgetsByTitle(dashboard, + /Lambda Errors/ + ) + + const [errorsWidget] = widgets + t.equal((errorsWidget.properties as MetricWidgetProperties).period, 300) + + t.match((errorsWidget.properties as MetricWidgetProperties).metrics, [ + ['AWS/Lambda', 'Errors', 'FunctionName', '${HelloLambdaFunction}', { stat: 'Sum', yAxis: 'right' }] + ]) + + t.end() + }) + t.end() +}) diff --git a/core/dashboards/tests/dashboard.test.ts b/core/dashboards/tests/dashboard.test.ts index 7e459a8f..7e9afe3b 100644 --- a/core/dashboards/tests/dashboard.test.ts +++ b/core/dashboards/tests/dashboard.test.ts @@ -31,40 +31,6 @@ test('A dashboard includes metrics', (t) => { t.ok(dashboard.start) - t.test('dashboards includes Lambda metrics', (t) => { - const widgets = dashboard.widgets.filter(({ properties }) => - ((properties as MetricWidgetProperties).title ?? '').startsWith('Lambda') - ) - t.equal(widgets.length, 8) - const namespaces = new Set() - for (const widget of widgets) { - const widgetProperties = widget.properties as MetricWidgetProperties - for (const metric of widgetProperties.metrics ?? []) { - t.equal(metric.length, 5) - const metricProperties = metric[4] as object - const propKeys = Object.keys(metricProperties) - t.same(propKeys, ['stat']) - namespaces.add(metric[0]) - } - } - t.same(namespaces, new Set(['AWS/Lambda'])) - const expectedTitles = new Set([ - 'Lambda Duration Average per Function', - 'Lambda Duration p95 per Function', - 'Lambda Duration Maximum per Function', - 'Lambda Invocations Sum per Function', - 'Lambda IteratorAge ${StreamProcessorLambdaFunction} Maximum', - 'Lambda ConcurrentExecutions Maximum per Function', - 'Lambda Throttles Sum per Function', - 'Lambda Errors Sum per Function' - ]) - const actualTitles = new Set( - widgets.map((widget) => (widget.properties as MetricWidgetProperties).title) - ) - t.same(actualTitles, expectedTitles) - t.end() - }) - t.test('dashboards includes Step Function metrics', (t) => { const widgets = dashboard.widgets.filter((widget) => { const widgetProperties = widget.properties as MetricWidgetProperties diff --git a/core/tests/testing-utils.ts b/core/tests/testing-utils.ts index 0fc74318..5e26153f 100644 --- a/core/tests/testing-utils.ts +++ b/core/tests/testing-utils.ts @@ -29,7 +29,7 @@ export function assertCommonAlarmProperties (t, al: AlarmProperties) { /** * Derive an alarm 'type' by stripping the last component from the underscore-delimited name - * @param {*} alarmName The alarm name as a string or {'Fn::Sub': ...} object + * @param alarmName The alarm name as a string or {'Fn::Sub': ...} object * @returns The inferred type */ export function alarmNameToType (alarmName) { From 2d44c5953fd2c9f3695e38f01fc62fda4b4eda41 Mon Sep 17 00:00:00 2001 From: Eoin Shanaghy Date: Mon, 20 Nov 2023 09:57:03 +0000 Subject: [PATCH 13/35] chore: extract and extend DynamoDB dashboard tests --- core/dashboards/dashboard.ts | 17 +- .../tests/dashboard-dynamodb.test.ts | 171 ++++++++++++++++++ core/dashboards/tests/dashboard.test.ts | 27 --- 3 files changed, 181 insertions(+), 34 deletions(-) create mode 100644 core/dashboards/tests/dashboard-dynamodb.test.ts diff --git a/core/dashboards/dashboard.ts b/core/dashboards/dashboard.ts index e91b63d6..dd7b81c4 100644 --- a/core/dashboards/dashboard.ts +++ b/core/dashboards/dashboard.ts @@ -148,7 +148,7 @@ export default function addDashboard (dashboardConfig: SlicWatchInputDashboardCo namespace: 'AWS/Lambda', metric, dimensions: { FunctionName: `\${${funcLogicalId}}` }, - stat: stat as Statistic, + stat, yAxis: metricConfig.yAxis }) } @@ -294,9 +294,9 @@ export default function addDashboard (dashboardConfig: SlicWatchInputDashboardCo const ddbWidgets: WidgetWithSize[] = [] for (const [logicalId, res] of Object.entries(configuredResources.resources)) { const mergedConfig = configuredResources.dashConfigurations[logicalId] - const widgetMetrics: MetricDefs[] = [] for (const [metric, metricConfig] of Object.entries(getConfiguredMetrics(mergedConfig))) { if (metricConfig.enabled) { + const widgetMetrics: MetricDefs[] = [] for (const stat of metricConfig.Statistic) { widgetMetrics.push({ namespace: 'AWS/DynamoDB', @@ -304,7 +304,8 @@ export default function addDashboard (dashboardConfig: SlicWatchInputDashboardCo dimensions: { TableName: `\${${logicalId}}` }, - stat + stat, + yAxis: metricConfig.yAxis }) } if (widgetMetrics.length > 0) { @@ -316,22 +317,24 @@ export default function addDashboard (dashboardConfig: SlicWatchInputDashboardCo ddbWidgets.push(metricStatWidget) } for (const gsi of res.Properties?.GlobalSecondaryIndexes ?? []) { + const gsiWidgetMetrics: MetricDefs[] = [] const gsiName: string = gsi.IndexName for (const stat of metricConfig.Statistic) { - widgetMetrics.push({ + gsiWidgetMetrics.push({ namespace: 'AWS/DynamoDB', metric, dimensions: { TableName: `\${${logicalId}}`, GlobalSecondaryIndex: gsiName }, - stat + stat, + yAxis: metricConfig.yAxis }) } - if (widgetMetrics.length > 0) { + if (gsiWidgetMetrics.length > 0) { const metricStatWidget = createMetricWidget( `${metric} GSI ${gsiName} in \${${logicalId}}`, - widgetMetrics, + gsiWidgetMetrics, dynamoDbDashConfig ) ddbWidgets.push(metricStatWidget) diff --git a/core/dashboards/tests/dashboard-dynamodb.test.ts b/core/dashboards/tests/dashboard-dynamodb.test.ts new file mode 100644 index 00000000..e4edf58d --- /dev/null +++ b/core/dashboards/tests/dashboard-dynamodb.test.ts @@ -0,0 +1,171 @@ +import { merge } from 'lodash' +import { test } from 'tap' +import { type MetricWidgetProperties } from 'cloudwatch-dashboard-types' + +import { type ResourceType } from '../../cf-template' +import addDashboard from '../dashboard' +import defaultConfig from '../../inputs/default-config' + +import { createTestCloudFormationTemplate, getDashboardFromTemplate, getDashboardWidgetsByTitle } from '../../tests/testing-utils' +// import { type ResourceType } from '../../cf-template' + +test('dashboard contains configured DynamoDB resources', (t) => { + t.test('dashboards includes DynamoDB metrics', (t) => { + const template = createTestCloudFormationTemplate() + addDashboard(defaultConfig.dashboard, template) + const { dashboard } = getDashboardFromTemplate(template) + + const widgets = getDashboardWidgetsByTitle(dashboard, + /ReadThrottleEvents Table /, + /ReadThrottleEvents GSI GSI1 in /, + /WriteThrottleEvents Table /, + /WriteThrottleEvents GSI GSI1 in / + ) + + for (const widget of widgets) { + t.ok(widget) + } + + const [ + readThrottlesWidget, readThrottlesGsiWidget, writeThrottlesWidget, writeThrottlesGsiWidget + ] = widgets + t.match((readThrottlesWidget.properties as MetricWidgetProperties).metrics, [ + ['AWS/DynamoDB', 'ReadThrottleEvents', 'TableName', '${dataTable}', { stat: 'Sum', yAxis: 'left' }] + ]) + t.match((readThrottlesGsiWidget.properties as MetricWidgetProperties).metrics, [ + ['AWS/DynamoDB', 'ReadThrottleEvents', 'TableName', '${dataTable}', 'GlobalSecondaryIndex', 'GSI1', { stat: 'Sum', yAxis: 'left' }] + ]) + t.match((writeThrottlesWidget.properties as MetricWidgetProperties).metrics, [ + ['AWS/DynamoDB', 'WriteThrottleEvents', 'TableName', '${dataTable}', { stat: 'Sum', yAxis: 'left' }] + ]) + t.match((writeThrottlesGsiWidget.properties as MetricWidgetProperties).metrics, [ + ['AWS/DynamoDB', 'WriteThrottleEvents', 'TableName', '${dataTable}', 'GlobalSecondaryIndex', 'GSI1', { stat: 'Sum', yAxis: 'left' }] + ]) + + for (const widget of widgets) { + const props: MetricWidgetProperties = widget.properties as MetricWidgetProperties + t.ok((props.metrics?.length ?? 0) > 0) + t.equal(props.period, 300) + t.equal(props.view, 'timeSeries') + } + + t.end() + }) + + t.test('service config overrides take precedence', (t) => { + const template = createTestCloudFormationTemplate() + + const config = merge({}, defaultConfig.dashboard, { + widgets: { + DynamoDB: { + metricPeriod: 900, + width: 8, + height: 12, + ReadThrottleEvents: { + Statistic: ['ts80'], + yAxis: 'right', + enabled: false + }, + WriteThrottleEvents: { + Statistic: ['ts80'], + yAxis: 'right' + } + } + } + }) + + addDashboard(config, template) + const { dashboard } = getDashboardFromTemplate(template) + const widgets = getDashboardWidgetsByTitle(dashboard, + /ReadThrottleEvents Table /, + /ReadThrottleEvents GSI GSI1 in /, + /WriteThrottleEvents Table /, + /WriteThrottleEvents GSI GSI1 in / + ) + + const [ + readThrottlesWidget, readThrottlesGsiWidget, writeThrottlesWidget, writeThrottlesGsiWidget + ] = widgets + t.ok(writeThrottlesWidget) + t.ok(writeThrottlesGsiWidget) + t.notOk(readThrottlesWidget) + t.notOk(readThrottlesGsiWidget) + + t.match((writeThrottlesWidget.properties as MetricWidgetProperties).metrics, [ + ['AWS/DynamoDB', 'WriteThrottleEvents', 'TableName', '${dataTable}', { stat: 'ts80', yAxis: 'right' }] + ]) + t.match((writeThrottlesGsiWidget.properties as MetricWidgetProperties).metrics, [ + ['AWS/DynamoDB', 'WriteThrottleEvents', 'TableName', '${dataTable}', 'GlobalSecondaryIndex', 'GSI1', { stat: 'ts80', yAxis: 'right' }] + ]) + + for (const widget of widgets.filter(w => Boolean(w))) { + const props: MetricWidgetProperties = widget.properties as MetricWidgetProperties + t.equal(props.period, 900) + t.equal(props.view, 'timeSeries') + } + t.end() + }) + + t.test('resource config overrides take precedence', (t) => { + const template = createTestCloudFormationTemplate(); + (template.Resources as ResourceType).dataTable.Metadata = { + slicWatch: { + dashboard: { + ThrottledPutRecordCount: { + Statistic: ['Average'], + yAxis: 'right', + enabled: true + }, + ReadThrottleEvents: { + enabled: false, + metricPeriod: 600 + } + } + } + } + + addDashboard(defaultConfig.dashboard, template) + + const { dashboard } = getDashboardFromTemplate(template) + const widgets = getDashboardWidgetsByTitle(dashboard, + /ReadThrottleEvents Table /, + /ReadThrottleEvents GSI GSI1 in /, + /WriteThrottleEvents Table /, + /WriteThrottleEvents GSI GSI1 in /, + /ThrottledPutRecordCount Table /, + /ThrottledPutRecordCount GSI GSI1 in / + ) + + const [ + readThrottlesWidget, readThrottlesGsiWidget, writeThrottlesWidget, writeThrottlesGsiWidget, + throttledPutRecordWidget, throttledPutRecordGsiWidget, + ] = widgets + t.ok(writeThrottlesWidget) + t.ok(writeThrottlesGsiWidget) + t.notOk(readThrottlesWidget) + t.notOk(readThrottlesGsiWidget) + t.ok(throttledPutRecordWidget) + t.ok(throttledPutRecordGsiWidget) + + t.match((writeThrottlesWidget.properties as MetricWidgetProperties).metrics, [ + ['AWS/DynamoDB', 'WriteThrottleEvents', 'TableName', '${dataTable}', { stat: 'Sum', yAxis: 'left' }] + ]) + t.match((writeThrottlesGsiWidget.properties as MetricWidgetProperties).metrics, [ + ['AWS/DynamoDB', 'WriteThrottleEvents', 'TableName', '${dataTable}', 'GlobalSecondaryIndex', 'GSI1', { stat: 'Sum', yAxis: 'left' }] + ]) + const throttledPutRecordProps = throttledPutRecordWidget.properties as MetricWidgetProperties + t.equal(throttledPutRecordProps.period, 300) + t.equal(throttledPutRecordProps.view, 'timeSeries') + t.match(throttledPutRecordProps.metrics, [ + ['AWS/DynamoDB', 'ThrottledPutRecordCount', 'TableName', '${dataTable}', { stat: 'Average', yAxis: 'right' }] + ]) + const throttledPutRecordGsiProps = throttledPutRecordGsiWidget.properties as MetricWidgetProperties + t.equal(throttledPutRecordGsiProps.period, 300) + t.match(throttledPutRecordGsiProps.metrics, [ + ['AWS/DynamoDB', 'ThrottledPutRecordCount', 'TableName', '${dataTable}', 'GlobalSecondaryIndex', 'GSI1', { stat: 'Average', yAxis: 'right' }] + ]) + t.end() + }) + + t.end() +}) diff --git a/core/dashboards/tests/dashboard.test.ts b/core/dashboards/tests/dashboard.test.ts index 7e9afe3b..ec9a58dc 100644 --- a/core/dashboards/tests/dashboard.test.ts +++ b/core/dashboards/tests/dashboard.test.ts @@ -54,33 +54,6 @@ test('A dashboard includes metrics', (t) => { t.end() }) - t.test('dashboards includes DynamoDB metrics', (t) => { - const widgets = dashboard.widgets.filter(({ properties }) => { - const title = (properties as MetricWidgetProperties).title ?? '' - return title.indexOf('Table') > 0 || title.indexOf('GSI') > 0 - }) - t.equal(widgets.length, 4) - const namespaces = new Set() - for (const widget of widgets) { - for (const metric of (widget.properties as MetricWidgetProperties).metrics ?? []) { - namespaces.add(metric[0]) - } - } - t.same(namespaces, new Set(['AWS/DynamoDB'])) - const expectedTitles = new Set([ - 'ReadThrottleEvents Table ${dataTable}', - 'ReadThrottleEvents GSI GSI1 in ${dataTable}', - 'WriteThrottleEvents Table ${dataTable}', - 'WriteThrottleEvents GSI GSI1 in ${dataTable}' - ]) - - const actualTitles = new Set( - widgets.map((widget) => (widget.properties as MetricWidgetProperties).title) - ) - t.same(actualTitles, expectedTitles) - t.end() - }) - t.test('dashboard includes Kinesis metrics', (t) => { const widgets = dashboard.widgets.filter(({ properties }) => ((properties as MetricWidgetProperties).title ?? '').endsWith('Kinesis') From 56e4cd2cd57056c5011bfef633fef7ceb5387a97 Mon Sep 17 00:00:00 2001 From: Eoin Shanaghy Date: Mon, 20 Nov 2023 15:03:38 +0000 Subject: [PATCH 14/35] chore: extract and extend Kinesis Data Stream dashboard tests --- core/cf-template.ts | 4 +- core/dashboards/dashboard.ts | 9 +- .../tests/dashboard-dynamodb.test.ts | 4 +- .../tests/dashboard-kinesis.test.ts | 172 ++++++++++++++++++ 4 files changed, 182 insertions(+), 7 deletions(-) create mode 100644 core/dashboards/tests/dashboard-kinesis.test.ts diff --git a/core/cf-template.ts b/core/cf-template.ts index 0b37e4f5..2eda0bb2 100644 --- a/core/cf-template.ts +++ b/core/cf-template.ts @@ -5,7 +5,7 @@ import { filterObject } from './filter-object' import { getLogger } from './logging' import { cascade } from './inputs/cascading-config' import { type SlicWatchMergedConfig } from './alarms/alarm-types' -import { type SlicWatchDashboardConfig, type WidgetMetricProperties } from './dashboards/dashboard-types' +import { type WidgetMetricProperties } from './dashboards/dashboard-types' import { merge } from 'lodash' const logger = getLogger() @@ -89,7 +89,7 @@ export function getResourceDashboardConfigurationsByType = {} const resources = getResourcesByType(type, template) for (const [logicalId, resource] of Object.entries(resources)) { - dashConfigurations[logicalId] = merge({}, config, cascade(resource?.Metadata?.slicWatch?.dashboard ?? {}) as SlicWatchDashboardConfig) + dashConfigurations[logicalId] = cascade(merge({}, config, cascade(resource?.Metadata?.slicWatch?.dashboard ?? {}))) as T } return { resources, diff --git a/core/dashboards/dashboard.ts b/core/dashboards/dashboard.ts index dd7b81c4..0f3d83ab 100644 --- a/core/dashboards/dashboard.ts +++ b/core/dashboards/dashboard.ts @@ -312,7 +312,7 @@ export default function addDashboard (dashboardConfig: SlicWatchInputDashboardCo const metricStatWidget = createMetricWidget( `${metric} Table $\{${logicalId}}`, widgetMetrics, - dynamoDbDashConfig + metricConfig ) ddbWidgets.push(metricStatWidget) } @@ -335,7 +335,7 @@ export default function addDashboard (dashboardConfig: SlicWatchInputDashboardCo const metricStatWidget = createMetricWidget( `${metric} GSI ${gsiName} in \${${logicalId}}`, gsiWidgetMetrics, - dynamoDbDashConfig + metricConfig ) ddbWidgets.push(metricStatWidget) } @@ -373,7 +373,8 @@ export default function addDashboard (dashboardConfig: SlicWatchInputDashboardCo namespace: 'AWS/Kinesis', metric, dimensions: { StreamName: `\${${logicalId}}` }, - stat + stat, + yAxis: metricConfig.yAxis }) } } @@ -382,7 +383,7 @@ export default function addDashboard (dashboardConfig: SlicWatchInputDashboardCo streamWidgets.push(createMetricWidget( `${group} $\{${logicalId}} Kinesis`, widgetMetrics, - kinesisDashConfig + streamConfig )) } } diff --git a/core/dashboards/tests/dashboard-dynamodb.test.ts b/core/dashboards/tests/dashboard-dynamodb.test.ts index e4edf58d..423b62e8 100644 --- a/core/dashboards/tests/dashboard-dynamodb.test.ts +++ b/core/dashboards/tests/dashboard-dynamodb.test.ts @@ -102,6 +102,8 @@ test('dashboard contains configured DynamoDB resources', (t) => { const props: MetricWidgetProperties = widget.properties as MetricWidgetProperties t.equal(props.period, 900) t.equal(props.view, 'timeSeries') + t.equal(widget.width, 8) + t.equal(widget.height, 12) } t.end() }) @@ -138,7 +140,7 @@ test('dashboard contains configured DynamoDB resources', (t) => { const [ readThrottlesWidget, readThrottlesGsiWidget, writeThrottlesWidget, writeThrottlesGsiWidget, - throttledPutRecordWidget, throttledPutRecordGsiWidget, + throttledPutRecordWidget, throttledPutRecordGsiWidget ] = widgets t.ok(writeThrottlesWidget) t.ok(writeThrottlesGsiWidget) diff --git a/core/dashboards/tests/dashboard-kinesis.test.ts b/core/dashboards/tests/dashboard-kinesis.test.ts new file mode 100644 index 00000000..b6e4e415 --- /dev/null +++ b/core/dashboards/tests/dashboard-kinesis.test.ts @@ -0,0 +1,172 @@ +import { merge } from 'lodash' + +import { test } from 'tap' +import { type MetricWidgetProperties } from 'cloudwatch-dashboard-types' + +import addDashboard from '../dashboard' +import defaultConfig from '../../inputs/default-config' + +import { createTestCloudFormationTemplate, getDashboardFromTemplate, getDashboardWidgetsByTitle } from '../../tests/testing-utils' +import { type ResourceType } from '../../cf-template' + +test('dashboard contains configured Kinesis Data Stream resources', (t) => { + t.test('dashboards includes stream metrics', (t) => { + const template = createTestCloudFormationTemplate() + addDashboard(defaultConfig.dashboard, template) + const { dashboard } = getDashboardFromTemplate(template) + + const widgets = getDashboardWidgetsByTitle(dashboard, + /IteratorAge .* Kinesis/, + /Get\/Put Success .* Kinesis/, + /Provisioned Throughput .* Kinesis/ + ) + + for (const widget of widgets) { + t.ok(widget) + } + + const [ + iteratorAgeWidget, getPutSuccessWidget, provisionedThroughputWidget + ] = widgets + t.same((iteratorAgeWidget.properties as MetricWidgetProperties).metrics, [ + ['AWS/Kinesis', 'GetRecords.IteratorAgeMilliseconds', 'StreamName', '${stream}', { stat: 'Maximum', yAxis: 'left' }] + ]) + + t.same((getPutSuccessWidget.properties as MetricWidgetProperties).metrics, [ + ['AWS/Kinesis', 'PutRecord.Success', 'StreamName', '${stream}', { stat: 'Average', yAxis: 'left' }], + ['AWS/Kinesis', 'PutRecords.Success', 'StreamName', '${stream}', { stat: 'Average', yAxis: 'left' }], + ['AWS/Kinesis', 'GetRecords.Success', 'StreamName', '${stream}', { stat: 'Average', yAxis: 'left' }] + ]) + + t.same((provisionedThroughputWidget.properties as MetricWidgetProperties).metrics, [ + ['AWS/Kinesis', 'ReadProvisionedThroughputExceeded', 'StreamName', '${stream}', { stat: 'Sum', yAxis: 'left' }], + ['AWS/Kinesis', 'WriteProvisionedThroughputExceeded', 'StreamName', '${stream}', { stat: 'Sum', yAxis: 'left' }] + ]) + for (const widget of widgets) { + const props: MetricWidgetProperties = widget.properties as MetricWidgetProperties + t.ok((props.metrics?.length ?? 0) > 0) + t.equal(props.period, 300) + t.equal(props.view, 'timeSeries') + } + + t.end() + }) + + t.test('service config overrides take precedence', (t) => { + const template = createTestCloudFormationTemplate() + + const config = merge({}, defaultConfig.dashboard, { + widgets: { + Kinesis: { + metricPeriod: 900, + width: 8, + height: 12, + 'GetRecord.Success': { + yAxis: 'right' + }, + WriteProvisionedThroughputExceeded: { + Statistic: ['ts80'], + yAxis: 'right' + } + } + } + }) + + addDashboard(config, template) + const { dashboard } = getDashboardFromTemplate(template) + + const widgets = getDashboardWidgetsByTitle(dashboard, + /IteratorAge .* Kinesis/, + /Get\/Put Success .* Kinesis/, + /Provisioned Throughput .* Kinesis/ + ) + + for (const widget of widgets) { + t.ok(widget) + } + + const [ + iteratorAgeWidget, getPutSuccessWidget, provisionedThroughputWidget + ] = widgets + t.same((iteratorAgeWidget.properties as MetricWidgetProperties).metrics, [ + ['AWS/Kinesis', 'GetRecords.IteratorAgeMilliseconds', 'StreamName', '${stream}', { stat: 'Maximum', yAxis: 'left' }] + ]) + + t.same((getPutSuccessWidget.properties as MetricWidgetProperties).metrics, [ + ['AWS/Kinesis', 'PutRecord.Success', 'StreamName', '${stream}', { stat: 'Average', yAxis: 'left' }], + ['AWS/Kinesis', 'PutRecords.Success', 'StreamName', '${stream}', { stat: 'Average', yAxis: 'left' }], + ['AWS/Kinesis', 'GetRecords.Success', 'StreamName', '${stream}', { stat: 'Average', yAxis: 'left' }] + ]) + + t.same((provisionedThroughputWidget.properties as MetricWidgetProperties).metrics, [ + ['AWS/Kinesis', 'ReadProvisionedThroughputExceeded', 'StreamName', '${stream}', { stat: 'Sum', yAxis: 'left' }], + ['AWS/Kinesis', 'WriteProvisionedThroughputExceeded', 'StreamName', '${stream}', { stat: 'ts80', yAxis: 'right' }] + ]) + + for (const widget of widgets) { + const props: MetricWidgetProperties = widget.properties as MetricWidgetProperties + t.equal(widget.width, 8) + t.equal(widget.height, 12) + t.ok((props.metrics?.length ?? 0) > 0) + t.equal(props.period, 900) + t.equal(props.view, 'timeSeries') + } + + t.end() + }) + + t.test('resource config overrides take precedence', (t) => { + const template = createTestCloudFormationTemplate(); + (template.Resources as ResourceType).stream.Metadata = { + slicWatch: { + dashboard: { + 'GetRecords.IteratorAgeMilliseconds': { + Statistic: ['Average'], + yAxis: 'right', + enabled: true + }, + ReadProvisionedThroughputExceeded: { + enabled: false, + metricPeriod: 600 + }, + WriteProvisionedThroughputExceeded: { + yAxis: 'right' + } + } + } + } + + addDashboard(defaultConfig.dashboard, template) + const { dashboard } = getDashboardFromTemplate(template) + + const widgets = getDashboardWidgetsByTitle(dashboard, + /IteratorAge .* Kinesis/, + /Get\/Put Success .* Kinesis/, + /Provisioned Throughput .* Kinesis/ + ) + + for (const widget of widgets) { + t.ok(widget) + } + + const [ + iteratorAgeWidget, getPutSuccessWidget, provisionedThroughputWidget + ] = widgets + t.same((iteratorAgeWidget.properties as MetricWidgetProperties).metrics, [ + ['AWS/Kinesis', 'GetRecords.IteratorAgeMilliseconds', 'StreamName', '${stream}', { stat: 'Average', yAxis: 'right' }] + ]) + + t.same((getPutSuccessWidget.properties as MetricWidgetProperties).metrics, [ + ['AWS/Kinesis', 'PutRecord.Success', 'StreamName', '${stream}', { stat: 'Average', yAxis: 'left' }], + ['AWS/Kinesis', 'PutRecords.Success', 'StreamName', '${stream}', { stat: 'Average', yAxis: 'left' }], + ['AWS/Kinesis', 'GetRecords.Success', 'StreamName', '${stream}', { stat: 'Average', yAxis: 'left' }] + ]) + + t.same((provisionedThroughputWidget.properties as MetricWidgetProperties).metrics, [ + ['AWS/Kinesis', 'WriteProvisionedThroughputExceeded', 'StreamName', '${stream}', { stat: 'Sum', yAxis: 'right' }] + ]) + + t.end() + }) + t.end() +}) From 167d4a94e5ae27a7365d61b7ef6434ce8f02b6a9 Mon Sep 17 00:00:00 2001 From: Eoin Shanaghy Date: Mon, 20 Nov 2023 17:13:32 +0000 Subject: [PATCH 15/35] chore: extract and extend Step Function dashboard tests --- core/dashboards/dashboard.ts | 5 +- .../tests/dashboard-dynamodb.test.ts | 1 - .../dashboards/tests/dashboard-lambda.test.ts | 82 ++++++++- .../dashboards/tests/dashboard-stepfn.test.ts | 163 ++++++++++++++++++ core/dashboards/tests/dashboard.test.ts | 129 +------------- 5 files changed, 248 insertions(+), 132 deletions(-) create mode 100644 core/dashboards/tests/dashboard-stepfn.test.ts diff --git a/core/dashboards/dashboard.ts b/core/dashboards/dashboard.ts index 0f3d83ab..af3b226c 100644 --- a/core/dashboards/dashboard.ts +++ b/core/dashboards/dashboard.ts @@ -267,7 +267,8 @@ export default function addDashboard (dashboardConfig: SlicWatchInputDashboardCo dimensions: { StateMachineArn: `\${${logicalId}}` }, - stat + stat, + yAxis: metricConfig.yAxis }) } } @@ -276,7 +277,7 @@ export default function addDashboard (dashboardConfig: SlicWatchInputDashboardCo const metricStatWidget = createMetricWidget( `\${${logicalId}.Name} Step Function Executions`, widgetMetrics, - sfDashConfig + mergedConfig ) smWidgets.push(metricStatWidget) } diff --git a/core/dashboards/tests/dashboard-dynamodb.test.ts b/core/dashboards/tests/dashboard-dynamodb.test.ts index 423b62e8..7398dcec 100644 --- a/core/dashboards/tests/dashboard-dynamodb.test.ts +++ b/core/dashboards/tests/dashboard-dynamodb.test.ts @@ -7,7 +7,6 @@ import addDashboard from '../dashboard' import defaultConfig from '../../inputs/default-config' import { createTestCloudFormationTemplate, getDashboardFromTemplate, getDashboardWidgetsByTitle } from '../../tests/testing-utils' -// import { type ResourceType } from '../../cf-template' test('dashboard contains configured DynamoDB resources', (t) => { t.test('dashboards includes DynamoDB metrics', (t) => { diff --git a/core/dashboards/tests/dashboard-lambda.test.ts b/core/dashboards/tests/dashboard-lambda.test.ts index 7a8baeb7..213bbcd6 100644 --- a/core/dashboards/tests/dashboard-lambda.test.ts +++ b/core/dashboards/tests/dashboard-lambda.test.ts @@ -7,9 +7,11 @@ import addDashboard from '../dashboard' import defaultConfig from '../../inputs/default-config' import { createTestCloudFormationTemplate, getDashboardFromTemplate, getDashboardWidgetsByTitle } from '../../tests/testing-utils' -import { type ResourceType } from '../../cf-template' +import { getResourcesByType, type ResourceType } from '../../cf-template' test('dashboard contains configured Lambda Function resources', (t) => { + const lambdaMetrics = ['Errors', 'Duration', 'IteratorAge', 'Invocations', 'ConcurrentExecutions', 'Throttles'] + t.test('dashboards includes Lambda metrics', (t) => { const template = createTestCloudFormationTemplate() addDashboard(defaultConfig.dashboard, template) @@ -185,5 +187,83 @@ test('dashboard contains configured Lambda Function resources', (t) => { t.end() }) + + test('A widget is not created for Lambda if disabled at a function level', (t) => { + for (const metric of lambdaMetrics) { + const compiledTemplate = createTestCloudFormationTemplate(); + (compiledTemplate.Resources as ResourceType).HelloLambdaFunction.Metadata = { + slicWatch: { + dashboard: { enabled: false } + } + } + + addDashboard(defaultConfig.dashboard, compiledTemplate) + const dashResources = getResourcesByType('AWS::CloudWatch::Dashboard', compiledTemplate) + const [, dashResource] = Object.entries(dashResources)[0] + const dashboard = JSON.parse(dashResource.Properties?.DashboardBody['Fn::Sub']) + + const widgets = dashboard.widgets.filter(({ properties: { title } }) => + title.startsWith(`Lambda ${metric}`) + ) + const widgetMetrics = widgets[0].properties.metrics + const functionNames = widgetMetrics.map(widgetMetric => widgetMetric[3]) + t.ok(functionNames.length > 0) + t.equal(functionNames.indexOf('serverless-test-project-dev-hello'), -1, `${metric} is disabled`) + } + t.end() + }) + + test('No Lambda widgets are created if all metrics for functions are disabled', (t) => { + const compiledTemplate = createTestCloudFormationTemplate() + const allFunctionLogicalIds = Object.keys(getResourcesByType('AWS::Lambda::Function', compiledTemplate)) + for (const funcLogicalId of allFunctionLogicalIds) { + (compiledTemplate.Resources as ResourceType)[funcLogicalId].Metadata = { + slicWatch: { + dashboard: Object.fromEntries(lambdaMetrics.map((metric) => ([ + metric, { enabled: false } + ]))) + } + } + } + + addDashboard(defaultConfig.dashboard, compiledTemplate) + const dashResources = getResourcesByType('AWS::CloudWatch::Dashboard', compiledTemplate) + const [, dashResource] = Object.entries(dashResources)[0] + const dashboard = JSON.parse(dashResource.Properties?.DashboardBody['Fn::Sub']) + + const widgets = dashboard.widgets.filter(({ properties: { title } }) => + title.startsWith('Lambda') + ) + t.equal(widgets.length, 0) + t.end() + }) + + test('A widget is not created for Lambda if disabled at a function level for each metric', (t) => { + for (const metric of lambdaMetrics) { + const compiledTemplate = createTestCloudFormationTemplate(); + (compiledTemplate.Resources as ResourceType).HelloLambdaFunction.Metadata = { + slicWatch: { + dashboard: Object.fromEntries(lambdaMetrics.map((metric) => ([ + metric, { enabled: false } + ]))) + } + } + + addDashboard(defaultConfig.dashboard, compiledTemplate) + const dashResources = getResourcesByType('AWS::CloudWatch::Dashboard', compiledTemplate) + const [, dashResource] = Object.entries(dashResources)[0] + const dashboard = JSON.parse(dashResource.Properties?.DashboardBody['Fn::Sub']) + + const widgets = dashboard.widgets.filter(({ properties: { title } }) => + title.startsWith(`Lambda ${metric}`) + ) + const widgetMetrics = widgets[0].properties.metrics + const functionNames = widgetMetrics.map(widgetMetric => widgetMetric[3]) + t.ok(functionNames.length > 0) + t.equal(functionNames.indexOf('serverless-test-project-dev-hello'), -1, `${metric} is disabled`) + } + t.end() + }) + t.end() }) diff --git a/core/dashboards/tests/dashboard-stepfn.test.ts b/core/dashboards/tests/dashboard-stepfn.test.ts new file mode 100644 index 00000000..ad487582 --- /dev/null +++ b/core/dashboards/tests/dashboard-stepfn.test.ts @@ -0,0 +1,163 @@ +import { merge } from 'lodash' +import { test } from 'tap' +import { type MetricWidgetProperties } from 'cloudwatch-dashboard-types' + +import { type ResourceType } from '../../cf-template' +import addDashboard from '../dashboard' +import defaultConfig from '../../inputs/default-config' + +import { createTestCloudFormationTemplate, getDashboardFromTemplate, getDashboardWidgetsByTitle } from '../../tests/testing-utils' + +test('dashboard contains configured Step Function resources', (t) => { + t.test('dashboards includes Step Function metrics', (t) => { + const template = createTestCloudFormationTemplate() + addDashboard(defaultConfig.dashboard, template) + const { dashboard } = getDashboardFromTemplate(template) + + const widgets = getDashboardWidgetsByTitle(dashboard, + /\${Workflow\.Name\} Step Function Executions/, + /\${ExpressWorkflow\.Name\} Step Function Executions/ + ) + + for (const widget of widgets) { + t.ok(widget) + } + + const [ + standardWidget, expressWidget + ] = widgets + + t.match((standardWidget.properties as MetricWidgetProperties).metrics, [ + ['AWS/States', 'ExecutionsFailed', 'StateMachineArn', '${Workflow}', { stat: 'Sum', yAxis: 'left' }], + ['AWS/States', 'ExecutionThrottled', 'StateMachineArn', '${Workflow}', { stat: 'Sum', yAxis: 'left' }], + ['AWS/States', 'ExecutionsTimedOut', 'StateMachineArn', '${Workflow}', { stat: 'Sum', yAxis: 'left' }] + ]) + + t.match((expressWidget.properties as MetricWidgetProperties).metrics, [ + ['AWS/States', 'ExecutionsFailed', 'StateMachineArn', '${ExpressWorkflow}', { stat: 'Sum', yAxis: 'left' }], + ['AWS/States', 'ExecutionThrottled', 'StateMachineArn', '${ExpressWorkflow}', { stat: 'Sum', yAxis: 'left' }], + ['AWS/States', 'ExecutionsTimedOut', 'StateMachineArn', '${ExpressWorkflow}', { stat: 'Sum', yAxis: 'left' }] + ]) + + for (const widget of widgets) { + const props: MetricWidgetProperties = widget.properties as MetricWidgetProperties + t.ok((props.metrics?.length ?? 0) > 0) + t.equal(props.period, 300) + t.equal(props.view, 'timeSeries') + } + + t.end() + }) + + t.test('service config overrides take precedence', (t) => { + const template = createTestCloudFormationTemplate() + const config = merge({}, defaultConfig.dashboard, { + widgets: { + States: { + metricPeriod: 900, + width: 8, + height: 12, + ExecutionsFailed: { + Statistic: ['ts80'], + yAxis: 'right' + }, + ExecutionsTimedOut: { + enabled: false, + Statistic: ['ts80'], + yAxis: 'right' + } + } + } + }) + addDashboard(config, template) + const { dashboard } = getDashboardFromTemplate(template) + + const widgets = getDashboardWidgetsByTitle(dashboard, + /\${Workflow\.Name\} Step Function Executions/, + /\${ExpressWorkflow\.Name\} Step Function Executions/ + ) + + for (const widget of widgets) { + t.ok(widget) + } + + const [ + standardWidget, expressWidget + ] = widgets + + t.match((standardWidget.properties as MetricWidgetProperties).metrics, [ + ['AWS/States', 'ExecutionsFailed', 'StateMachineArn', '${Workflow}', { stat: 'ts80', yAxis: 'right' }], + ['AWS/States', 'ExecutionThrottled', 'StateMachineArn', '${Workflow}', { stat: 'Sum', yAxis: 'left' }] + ]) + + t.match((expressWidget.properties as MetricWidgetProperties).metrics, [ + ['AWS/States', 'ExecutionsFailed', 'StateMachineArn', '${ExpressWorkflow}', { stat: 'ts80', yAxis: 'right' }], + ['AWS/States', 'ExecutionThrottled', 'StateMachineArn', '${ExpressWorkflow}', { stat: 'Sum', yAxis: 'left' }] + ]) + + for (const widget of widgets) { + const props: MetricWidgetProperties = widget.properties as MetricWidgetProperties + t.ok((props.metrics?.length ?? 0) > 0) + t.equal(props.period, 900) + t.equal(props.view, 'timeSeries') + } + + t.end() + }) + + t.test('resource config overrides take precedence', (t) => { + const template = createTestCloudFormationTemplate(); + (template.Resources as ResourceType).ExpressWorkflow.Metadata = { + slicWatch: { + dashboard: { + ExecutionsFailed: { + Statistic: ['ts80'], + yAxis: 'right' + }, + ExecutionsTimedOut: { + enabled: false, + Statistic: ['ts80'], + yAxis: 'right' + } + } + } + } + + addDashboard(defaultConfig.dashboard, template) + const { dashboard } = getDashboardFromTemplate(template) + + const widgets = getDashboardWidgetsByTitle(dashboard, + /\${Workflow\.Name\} Step Function Executions/, + /\${ExpressWorkflow\.Name\} Step Function Executions/ + ) + + for (const widget of widgets) { + t.ok(widget) + } + + const [ + standardWidget, expressWidget + ] = widgets + + t.match((standardWidget.properties as MetricWidgetProperties).metrics, [ + ['AWS/States', 'ExecutionsFailed', 'StateMachineArn', '${Workflow}', { stat: 'Sum', yAxis: 'left' }], + ['AWS/States', 'ExecutionThrottled', 'StateMachineArn', '${Workflow}', { stat: 'Sum', yAxis: 'left' }] + ]) + + t.match((expressWidget.properties as MetricWidgetProperties).metrics, [ + ['AWS/States', 'ExecutionsFailed', 'StateMachineArn', '${ExpressWorkflow}', { stat: 'ts80', yAxis: 'right' }], + ['AWS/States', 'ExecutionThrottled', 'StateMachineArn', '${ExpressWorkflow}', { stat: 'Sum', yAxis: 'left' }] + ]) + + for (const widget of widgets) { + const props: MetricWidgetProperties = widget.properties as MetricWidgetProperties + t.ok((props.metrics?.length ?? 0) > 0) + t.equal(props.period, 300) + t.equal(props.view, 'timeSeries') + } + + t.end() + }) + + t.end() +}) diff --git a/core/dashboards/tests/dashboard.test.ts b/core/dashboards/tests/dashboard.test.ts index ec9a58dc..3f298b6e 100644 --- a/core/dashboards/tests/dashboard.test.ts +++ b/core/dashboards/tests/dashboard.test.ts @@ -6,11 +6,9 @@ import addDashboard from '../dashboard' import defaultConfig from '../../inputs/default-config' import { createTestCloudFormationTemplate, defaultCfTemplate, albCfTemplate, appSyncCfTemplate, getDashboardFromTemplate } from '../../tests/testing-utils' -import { type ResourceType, getResourcesByType } from '../../cf-template' +import { getResourcesByType } from '../../cf-template' import { type Widgets } from '../dashboard-types' -const lambdaMetrics = ['Errors', 'Duration', 'IteratorAge', 'Invocations', 'ConcurrentExecutions', 'Throttles'] - test('An empty template creates no dashboard', (t) => { const compiledTemplate = createTestCloudFormationTemplate({ Resources: {} }) addDashboard(defaultConfig.dashboard, compiledTemplate) @@ -31,54 +29,6 @@ test('A dashboard includes metrics', (t) => { t.ok(dashboard.start) - t.test('dashboards includes Step Function metrics', (t) => { - const widgets = dashboard.widgets.filter((widget) => { - const widgetProperties = widget.properties as MetricWidgetProperties - return (widgetProperties.title ?? '').endsWith('Step Function Executions') - }) - t.equal(widgets.length, 2) - const namespaces = new Set() - for (const widget of widgets) { - const widgetProperties = widget.properties as MetricWidgetProperties - for (const metric of widgetProperties.metrics ?? []) { - namespaces.add(metric[0]) - } - } - t.same(namespaces, new Set(['AWS/States'])) - const expectedTitles = new Set(['${Workflow.Name} Step Function Executions', '${ExpressWorkflow.Name} Step Function Executions']) - - const actualTitles = new Set( - widgets.map((widget) => (widget.properties as MetricWidgetProperties).title) - ) - t.same(actualTitles, expectedTitles) - t.end() - }) - - t.test('dashboard includes Kinesis metrics', (t) => { - const widgets = dashboard.widgets.filter(({ properties }) => - ((properties as MetricWidgetProperties).title ?? '').endsWith('Kinesis') - ) - t.equal(widgets.length, 3) - const namespaces = new Set() - for (const widget of widgets) { - for (const metric of (widget.properties as MetricWidgetProperties).metrics ?? []) { - namespaces.add(metric[0]) - } - } - t.same(namespaces, new Set(['AWS/Kinesis'])) - const expectedTitles = new Set([ - 'IteratorAge ${stream} Kinesis', - 'Get/Put Success ${stream} Kinesis', - 'Provisioned Throughput ${stream} Kinesis' - ]) - - const actualTitles = new Set( - widgets.map((widget) => (widget.properties as MetricWidgetProperties).title) - ) - t.same(actualTitles, expectedTitles) - t.end() - }) - t.test('dashboard includes SQS metrics', (t) => { const widgets = dashboard.widgets.filter(({ properties }) => ((properties as MetricWidgetProperties).title ?? '').endsWith('SQS') @@ -404,80 +354,3 @@ test('No dashboard is created if all metrics are disabled', (t) => { t.same(dashResources, {}) t.end() }) - -test('A widget is not created for Lambda if disabled at a function level', (t) => { - for (const metric of lambdaMetrics) { - const compiledTemplate = createTestCloudFormationTemplate(); - (compiledTemplate.Resources as ResourceType).HelloLambdaFunction.Metadata = { - slicWatch: { - dashboard: { enabled: false } - } - } - - addDashboard(defaultConfig.dashboard, compiledTemplate) - const dashResources = getResourcesByType('AWS::CloudWatch::Dashboard', compiledTemplate) - const [, dashResource] = Object.entries(dashResources)[0] - const dashboard = JSON.parse(dashResource.Properties?.DashboardBody['Fn::Sub']) - - const widgets = dashboard.widgets.filter(({ properties: { title } }) => - title.startsWith(`Lambda ${metric}`) - ) - const widgetMetrics = widgets[0].properties.metrics - const functionNames = widgetMetrics.map(widgetMetric => widgetMetric[3]) - t.ok(functionNames.length > 0) - t.equal(functionNames.indexOf('serverless-test-project-dev-hello'), -1, `${metric} is disabled`) - } - t.end() -}) - -test('A widget is not created for Lambda if disabled at a function level for each metric', (t) => { - for (const metric of lambdaMetrics) { - const compiledTemplate = createTestCloudFormationTemplate(); - (compiledTemplate.Resources as ResourceType).HelloLambdaFunction.Metadata = { - slicWatch: { - dashboard: Object.fromEntries(lambdaMetrics.map((metric) => ([ - metric, { enabled: false } - ]))) - } - } - - addDashboard(defaultConfig.dashboard, compiledTemplate) - const dashResources = getResourcesByType('AWS::CloudWatch::Dashboard', compiledTemplate) - const [, dashResource] = Object.entries(dashResources)[0] - const dashboard = JSON.parse(dashResource.Properties?.DashboardBody['Fn::Sub']) - - const widgets = dashboard.widgets.filter(({ properties: { title } }) => - title.startsWith(`Lambda ${metric}`) - ) - const widgetMetrics = widgets[0].properties.metrics - const functionNames = widgetMetrics.map(widgetMetric => widgetMetric[3]) - t.ok(functionNames.length > 0) - t.equal(functionNames.indexOf('serverless-test-project-dev-hello'), -1, `${metric} is disabled`) - } - t.end() -}) - -test('No Lambda widgets are created if all metrics for functions are disabled', (t) => { - const compiledTemplate = createTestCloudFormationTemplate() - const allFunctionLogicalIds = Object.keys(getResourcesByType('AWS::Lambda::Function', compiledTemplate)) - for (const funcLogicalId of allFunctionLogicalIds) { - (compiledTemplate.Resources as ResourceType)[funcLogicalId].Metadata = { - slicWatch: { - dashboard: Object.fromEntries(lambdaMetrics.map((metric) => ([ - metric, { enabled: false } - ]))) - } - } - } - - addDashboard(defaultConfig.dashboard, compiledTemplate) - const dashResources = getResourcesByType('AWS::CloudWatch::Dashboard', compiledTemplate) - const [, dashResource] = Object.entries(dashResources)[0] - const dashboard = JSON.parse(dashResource.Properties?.DashboardBody['Fn::Sub']) - - const widgets = dashboard.widgets.filter(({ properties: { title } }) => - title.startsWith('Lambda') - ) - t.equal(widgets.length, 0) - t.end() -}) From cb7614abbad5d1b9c61ee53e606408bf3efb3fa0 Mon Sep 17 00:00:00 2001 From: Eoin Shanaghy Date: Tue, 28 Nov 2023 14:06:06 +0000 Subject: [PATCH 16/35] chore: extract and extend SQS dashboard tests --- core/dashboards/dashboard.ts | 1 + core/dashboards/tests/dashboard-sqs.test.ts | 241 ++++++++++++++++++++ core/dashboards/tests/dashboard.test.ts | 28 --- 3 files changed, 242 insertions(+), 28 deletions(-) create mode 100644 core/dashboards/tests/dashboard-sqs.test.ts diff --git a/core/dashboards/dashboard.ts b/core/dashboards/dashboard.ts index af3b226c..58000843 100644 --- a/core/dashboards/dashboard.ts +++ b/core/dashboards/dashboard.ts @@ -419,6 +419,7 @@ export default function addDashboard (dashboardConfig: SlicWatchInputDashboardCo dimensions: { QueueName: `\${${logicalId}.QueueName}` }, + yAxis: metricConfig.yAxis, stat }) } diff --git a/core/dashboards/tests/dashboard-sqs.test.ts b/core/dashboards/tests/dashboard-sqs.test.ts new file mode 100644 index 00000000..63f82615 --- /dev/null +++ b/core/dashboards/tests/dashboard-sqs.test.ts @@ -0,0 +1,241 @@ +import { merge } from 'lodash' +import { test } from 'tap' +import { type MetricWidgetProperties } from 'cloudwatch-dashboard-types' + +import { type ResourceType } from '../../cf-template' +import addDashboard from '../dashboard' +import defaultConfig from '../../inputs/default-config' + +import { createTestCloudFormationTemplate, getDashboardFromTemplate, getDashboardWidgetsByTitle } from '../../tests/testing-utils' + +test('dashboard contains configured SQS resources', (t) => { + t.test('dashboards includes SQS metrics', (t) => { + const template = createTestCloudFormationTemplate() + addDashboard(defaultConfig.dashboard, template) + const { dashboard } = getDashboardFromTemplate(template) + + const widgets = getDashboardWidgetsByTitle(dashboard, + /Messages \$\{regularQueue\.QueueName\} SQS/, + /Oldest Message age .*regular.* SQS/, + /Messages in queue .*regular.* SQS/, + /Messages \$\{fifoQueue\.QueueName\} SQS/, + /Oldest Message age .*fifo.* SQS/, + /Messages in queue .*fifo.* SQS/ + ) + + for (const widget of widgets) { + t.ok(widget) + } + + const [ + regularMessagesWidget, regularOldestMessageAgeWidget, regularQueueMessagesWidget, + fifoMessagesWidget, fifoOldestMessageAgeWidget, fifoQueueMessagesWidget + ] = widgets + + t.same((regularMessagesWidget.properties as MetricWidgetProperties).metrics, [ + ['AWS/SQS', 'NumberOfMessagesSent', 'QueueName', '${regularQueue.QueueName}', { stat: 'Sum', yAxis: 'left' }], + ['AWS/SQS', 'NumberOfMessagesReceived', 'QueueName', '${regularQueue.QueueName}', { stat: 'Sum', yAxis: 'left' }], + ['AWS/SQS', 'NumberOfMessagesDeleted', 'QueueName', '${regularQueue.QueueName}', { stat: 'Sum', yAxis: 'left' }] + ]) + + t.same((regularOldestMessageAgeWidget.properties as MetricWidgetProperties).metrics, [ + ['AWS/SQS', 'ApproximateAgeOfOldestMessage', 'QueueName', '${regularQueue.QueueName}', { stat: 'Maximum', yAxis: 'left' }] + ]) + + t.same((regularQueueMessagesWidget.properties as MetricWidgetProperties).metrics, [ + ['AWS/SQS', 'ApproximateNumberOfMessagesVisible', 'QueueName', '${regularQueue.QueueName}', { stat: 'Maximum', yAxis: 'left' }] + ]) + + t.same((fifoMessagesWidget.properties as MetricWidgetProperties).metrics, [ + ['AWS/SQS', 'NumberOfMessagesSent', 'QueueName', '${fifoQueue.QueueName}', { stat: 'Sum', yAxis: 'left' }], + ['AWS/SQS', 'NumberOfMessagesReceived', 'QueueName', '${fifoQueue.QueueName}', { stat: 'Sum', yAxis: 'left' }], + ['AWS/SQS', 'NumberOfMessagesDeleted', 'QueueName', '${fifoQueue.QueueName}', { stat: 'Sum', yAxis: 'left' }] + ]) + + t.same((fifoOldestMessageAgeWidget.properties as MetricWidgetProperties).metrics, [ + ['AWS/SQS', 'ApproximateAgeOfOldestMessage', 'QueueName', '${fifoQueue.QueueName}', { stat: 'Maximum', yAxis: 'left' }] + ]) + + t.same((fifoQueueMessagesWidget.properties as MetricWidgetProperties).metrics, [ + ['AWS/SQS', 'ApproximateNumberOfMessagesVisible', 'QueueName', '${fifoQueue.QueueName}', { stat: 'Maximum', yAxis: 'left' }] + + ]) + + for (const widget of widgets) { + const props: MetricWidgetProperties = widget.properties as MetricWidgetProperties + t.ok((props.metrics?.length ?? 0) > 0) + t.equal(props.period, 300) + t.equal(props.view, 'timeSeries') + } + + t.end() + }) + + t.test('service config overrides take precedence', (t) => { + const template = createTestCloudFormationTemplate() + + const config = merge({}, defaultConfig.dashboard, { + widgets: { + SQS: { + metricPeriod: 900, + width: 8, + height: 12, + NumberOfMessagesSent: { + enabled: false + }, + NumberOfMessagesReceived: { + Statistic: ['ts80'], + yAxis: 'right' + }, + NumberOfMessagesDeleted: { + enabled: false + }, + ApproximateAgeOfOldestMessage: { + Statistic: ['ts85'], + yAxis: 'left' + }, + ApproximateNumberOfMessagesVisible: { + Statistic: ['ts90'], + enabled: false + } + } + } + }) + + addDashboard(config, template) + const { dashboard } = getDashboardFromTemplate(template) + + const widgets = getDashboardWidgetsByTitle(dashboard, + /Messages \$\{regularQueue\.QueueName\} SQS/, + /Oldest Message age .*regular.* SQS/, + /Messages in queue .*regular.* SQS/, + /Messages \$\{fifoQueue\.QueueName\} SQS/, + /Oldest Message age .*fifo.* SQS/, + /Messages in queue .*fifo.* SQS/ + ) + + const [ + regularMessagesWidget, regularOldestMessageAgeWidget, regularQueueMessagesWidget, + fifoMessagesWidget, fifoOldestMessageAgeWidget, fifoQueueMessagesWidget + ] = widgets + t.ok(regularMessagesWidget) + t.ok(regularOldestMessageAgeWidget) + t.notOk(regularQueueMessagesWidget) + t.ok(fifoMessagesWidget) + t.ok(fifoOldestMessageAgeWidget) + t.notOk(fifoQueueMessagesWidget) + + t.same((regularMessagesWidget.properties as MetricWidgetProperties).metrics, [ + ['AWS/SQS', 'NumberOfMessagesReceived', 'QueueName', '${regularQueue.QueueName}', { stat: 'ts80', yAxis: 'right' }] + ]) + + t.same((regularOldestMessageAgeWidget.properties as MetricWidgetProperties).metrics, [ + ['AWS/SQS', 'ApproximateAgeOfOldestMessage', 'QueueName', '${regularQueue.QueueName}', { stat: 'ts85', yAxis: 'left' }] + ]) + + t.same((fifoMessagesWidget.properties as MetricWidgetProperties).metrics, [ + ['AWS/SQS', 'NumberOfMessagesReceived', 'QueueName', '${fifoQueue.QueueName}', { stat: 'ts80', yAxis: 'right' }] + ]) + + t.same((fifoOldestMessageAgeWidget.properties as MetricWidgetProperties).metrics, [ + ['AWS/SQS', 'ApproximateAgeOfOldestMessage', 'QueueName', '${fifoQueue.QueueName}', { stat: 'ts85', yAxis: 'left' }] + ]) + + for (const widget of widgets) { + if (widget !== undefined) { + const props: MetricWidgetProperties = widget.properties as MetricWidgetProperties + t.ok((props.metrics?.length ?? 0) > 0) + t.equal(props.period, 900) + t.equal(props.view, 'timeSeries') + } + } + + t.end() + }) + + t.test('resource config overrides take precedence', (t) => { + const template = createTestCloudFormationTemplate(); + (template.Resources as ResourceType).fifoQueue.Metadata = { + slicWatch: { + dashboard: { + NumberOfMessagesSent: { + enabled: false + }, + NumberOfMessagesReceived: { + Statistic: ['ts80'], + yAxis: 'right' + }, + NumberOfMessagesDeleted: { + enabled: false + }, + ApproximateAgeOfOldestMessage: { + Statistic: ['ts85'], + yAxis: 'left' + }, + ApproximateNumberOfMessagesVisible: { + Statistic: ['ts90'], + enabled: false + } + } + } + } + + addDashboard(defaultConfig.dashboard, template) + + const { dashboard } = getDashboardFromTemplate(template) + const widgets = getDashboardWidgetsByTitle(dashboard, + /Messages \$\{regularQueue\.QueueName\} SQS/, + /Oldest Message age .*regular.* SQS/, + /Messages in queue .*regular.* SQS/, + /Messages \$\{fifoQueue\.QueueName\} SQS/, + /Oldest Message age .*fifo.* SQS/, + /Messages in queue .*fifo.* SQS/ + ) + + const [ + regularMessagesWidget, regularOldestMessageAgeWidget, regularQueueMessagesWidget, + fifoMessagesWidget, fifoOldestMessageAgeWidget, fifoQueueMessagesWidget + ] = widgets + t.ok(regularMessagesWidget) + t.ok(regularOldestMessageAgeWidget) + t.ok(regularQueueMessagesWidget) + t.ok(fifoMessagesWidget) + t.ok(fifoOldestMessageAgeWidget) + t.notOk(fifoQueueMessagesWidget) + + t.same((regularMessagesWidget.properties as MetricWidgetProperties).metrics, [ + ['AWS/SQS', 'NumberOfMessagesSent', 'QueueName', '${regularQueue.QueueName}', { stat: 'Sum', yAxis: 'left' }], + ['AWS/SQS', 'NumberOfMessagesReceived', 'QueueName', '${regularQueue.QueueName}', { stat: 'Sum', yAxis: 'left' }], + ['AWS/SQS', 'NumberOfMessagesDeleted', 'QueueName', '${regularQueue.QueueName}', { stat: 'Sum', yAxis: 'left' }] + ]) + + t.same((regularOldestMessageAgeWidget.properties as MetricWidgetProperties).metrics, [ + ['AWS/SQS', 'ApproximateAgeOfOldestMessage', 'QueueName', '${regularQueue.QueueName}', { stat: 'Maximum', yAxis: 'left' }] + ]) + + t.same((regularQueueMessagesWidget.properties as MetricWidgetProperties).metrics, [ + ['AWS/SQS', 'ApproximateNumberOfMessagesVisible', 'QueueName', '${regularQueue.QueueName}', { stat: 'Maximum', yAxis: 'left' }] + ]) + + t.same((fifoMessagesWidget.properties as MetricWidgetProperties).metrics, [ + ['AWS/SQS', 'NumberOfMessagesReceived', 'QueueName', '${fifoQueue.QueueName}', { stat: 'ts80', yAxis: 'right' }] + ]) + + t.same((fifoOldestMessageAgeWidget.properties as MetricWidgetProperties).metrics, [ + ['AWS/SQS', 'ApproximateAgeOfOldestMessage', 'QueueName', '${fifoQueue.QueueName}', { stat: 'ts85', yAxis: 'left' }] + ]) + + for (const widget of widgets) { + if (widget !== undefined) { + const props: MetricWidgetProperties = widget.properties as MetricWidgetProperties + t.ok((props.metrics?.length ?? 0) > 0) + t.equal(props.period, 300) + t.equal(props.view, 'timeSeries') + } + } + + t.end() + }) + + t.end() +}) diff --git a/core/dashboards/tests/dashboard.test.ts b/core/dashboards/tests/dashboard.test.ts index 3f298b6e..c7186faf 100644 --- a/core/dashboards/tests/dashboard.test.ts +++ b/core/dashboards/tests/dashboard.test.ts @@ -29,34 +29,6 @@ test('A dashboard includes metrics', (t) => { t.ok(dashboard.start) - t.test('dashboard includes SQS metrics', (t) => { - const widgets = dashboard.widgets.filter(({ properties }) => - ((properties as MetricWidgetProperties).title ?? '').endsWith('SQS') - ) - t.equal(widgets.length, 6) // 3 groups * 2 queues - const namespaces = new Set() - for (const widget of widgets) { - for (const metric of (widget.properties as MetricWidgetProperties).metrics ?? []) { - namespaces.add(metric[0]) - } - } - t.same(namespaces, new Set(['AWS/SQS'])) - const expectedTitles = new Set([ - 'Messages ${regularQueue.QueueName} SQS', - 'Oldest Message age ${regularQueue.QueueName} SQS', - 'Messages in queue ${regularQueue.QueueName} SQS', - 'Messages ${fifoQueue.QueueName} SQS', - 'Oldest Message age ${fifoQueue.QueueName} SQS', - 'Messages in queue ${fifoQueue.QueueName} SQS' - ]) - - const actualTitles = new Set( - widgets.map((widget) => (widget.properties as MetricWidgetProperties).title) - ) - t.same(actualTitles, expectedTitles) - t.end() - }) - t.test('dashboard includes ECS metrics', (t) => { const widgets = dashboard.widgets.filter(({ properties }) => ((properties as MetricWidgetProperties).title ?? '').startsWith('ECS') From dd5e5f3e15c8f2c9fff908b02c16e336f694a540 Mon Sep 17 00:00:00 2001 From: Eoin Shanaghy Date: Tue, 28 Nov 2023 16:44:50 +0000 Subject: [PATCH 17/35] chore: extract and extend SNS dashboard tests --- core/dashboards/dashboard.ts | 7 +- core/dashboards/tests/dashboard-sns.test.ts | 104 ++++++++++++++++++++ core/dashboards/tests/dashboard.test.ts | 21 ---- 3 files changed, 109 insertions(+), 23 deletions(-) create mode 100644 core/dashboards/tests/dashboard-sns.test.ts diff --git a/core/dashboards/dashboard.ts b/core/dashboards/dashboard.ts index 58000843..85a0a195 100644 --- a/core/dashboards/dashboard.ts +++ b/core/dashboards/dashboard.ts @@ -481,7 +481,9 @@ export default function addDashboard (dashboardConfig: SlicWatchInputDashboardCo * Create a set of CloudWatch Dashboard widgets for SNS services. */ function createTopicWidgets (): WidgetWithSize[] { - const configuredResources = getResourceDashboardConfigurationsByType('AWS::SNS::Topic', compiledTemplate, snsDashConfig) + const configuredResources = getResourceDashboardConfigurationsByType( + 'AWS::SNS::Topic', compiledTemplate, snsDashConfig + ) const topicWidgets: WidgetWithSize[] = [] for (const logicalId of Object.keys(configuredResources.resources)) { const widgetMetrics: MetricDefs[] = [] @@ -495,7 +497,8 @@ export default function addDashboard (dashboardConfig: SlicWatchInputDashboardCo dimensions: { TopicName: `\${${logicalId}.TopicName}` }, - stat + stat, + yAxis: metricConfig.yAxis }) } } diff --git a/core/dashboards/tests/dashboard-sns.test.ts b/core/dashboards/tests/dashboard-sns.test.ts new file mode 100644 index 00000000..7e3777b0 --- /dev/null +++ b/core/dashboards/tests/dashboard-sns.test.ts @@ -0,0 +1,104 @@ +import { merge } from 'lodash' +import { test } from 'tap' +import { type MetricWidgetProperties } from 'cloudwatch-dashboard-types' + +import { type ResourceType } from '../../cf-template' +import addDashboard from '../dashboard' +import defaultConfig from '../../inputs/default-config' + +import { createTestCloudFormationTemplate, getDashboardFromTemplate, getDashboardWidgetsByTitle } from '../../tests/testing-utils' + +test('dashboard contains configured SNS resources', (t) => { + t.test('dashboards includes SQS metrics', (t) => { + const template = createTestCloudFormationTemplate() + addDashboard(defaultConfig.dashboard, template) + const { dashboard } = getDashboardFromTemplate(template) + + const widgets = getDashboardWidgetsByTitle(dashboard, + /SNS Topic/ + ) + + const [snsTopicWidget] = widgets + t.ok(snsTopicWidget) + t.same((snsTopicWidget.properties as MetricWidgetProperties).metrics, [ + ['AWS/SNS', 'NumberOfNotificationsFilteredOut-InvalidAttributes', 'TopicName', '${topic.TopicName}', { stat: 'Sum', yAxis: 'left' }], + ['AWS/SNS', 'NumberOfNotificationsFailed', 'TopicName', '${topic.TopicName}', { stat: 'Sum', yAxis: 'left' }] + ]) + + t.end() + }) + + t.test('service config overrides take precedence', (t) => { + const template = createTestCloudFormationTemplate() + + const config = merge({}, defaultConfig.dashboard, { + widgets: { + SNS: { + metricPeriod: 900, + width: 8, + height: 12, + 'NumberOfNotificationsFilteredOut-InvalidAttributes': { + Statistic: ['ts80'], + yAxis: 'right' + }, + NumberOfNotificationsFailed: { + Statistic: ['ts85'], + yAxis: 'left' + } + } + } + }) + + addDashboard(config, template) + const { dashboard } = getDashboardFromTemplate(template) + + const widgets = getDashboardWidgetsByTitle(dashboard, + /SNS Topic/ + ) + + const [snsTopicWidget] = widgets + t.ok(snsTopicWidget) + t.same((snsTopicWidget.properties as MetricWidgetProperties).metrics, [ + ['AWS/SNS', 'NumberOfNotificationsFilteredOut-InvalidAttributes', 'TopicName', '${topic.TopicName}', { stat: 'ts80', yAxis: 'right' }], + ['AWS/SNS', 'NumberOfNotificationsFailed', 'TopicName', '${topic.TopicName}', { stat: 'ts85', yAxis: 'left' }] + ]) + + t.end() + }) + + t.test('resource config overrides take precedence', (t) => { + const template = createTestCloudFormationTemplate(); + (template.Resources as ResourceType).topic.Metadata = { + slicWatch: { + dashboard: { + 'NumberOfNotificationsFilteredOut-InvalidAttributes': { + Statistic: ['ts80'], + yAxis: 'right', + enabled: false + }, + NumberOfNotificationsFailed: { + Statistic: ['ts90'], + yAxis: 'right' + } + } + } + } + + addDashboard(defaultConfig.dashboard, template) + const { dashboard } = getDashboardFromTemplate(template) + + const widgets = getDashboardWidgetsByTitle(dashboard, + /SNS Topic/ + ) + + const [snsTopicWidget] = widgets + t.ok(snsTopicWidget) + t.same((snsTopicWidget.properties as MetricWidgetProperties).metrics, [ + ['AWS/SNS', 'NumberOfNotificationsFailed', 'TopicName', '${topic.TopicName}', { stat: 'ts90', yAxis: 'right' }] + ]) + + t.end() + }) + + t.end() +}) diff --git a/core/dashboards/tests/dashboard.test.ts b/core/dashboards/tests/dashboard.test.ts index c7186faf..c5c56bae 100644 --- a/core/dashboards/tests/dashboard.test.ts +++ b/core/dashboards/tests/dashboard.test.ts @@ -52,27 +52,6 @@ test('A dashboard includes metrics', (t) => { t.end() }) - t.test('dashboard includes SNS metrics', (t) => { - const widgets = dashboard.widgets.filter(({ properties }) => - ((properties as MetricWidgetProperties).title ?? '').startsWith('SNS') - ) - t.equal(widgets.length, 1) - const namespaces = new Set() - for (const widget of widgets) { - for (const metric of (widget.properties as MetricWidgetProperties).metrics ?? []) { - namespaces.add(metric[0]) - } - } - t.same(namespaces, new Set(['AWS/SNS'])) - const expectedTitles = new Set(['SNS Topic ${topic.TopicName}']) - - const actualTitles = new Set( - widgets.map((widget) => (widget.properties as MetricWidgetProperties).title) - ) - t.same(actualTitles, expectedTitles) - t.end() - }) - t.test('dashboard includes Events metrics', (t) => { const widgets = dashboard.widgets.filter(({ properties }) => ((properties as MetricWidgetProperties).title ?? '').startsWith('EventBridge') From 6f2c41654bbba719ad25708df8b85918ccbde4e1 Mon Sep 17 00:00:00 2001 From: Eoin Shanaghy Date: Tue, 28 Nov 2023 17:26:57 +0000 Subject: [PATCH 18/35] chore: extract and extend EventBridge dashboard tests --- core/dashboards/dashboard.ts | 3 +- .../tests/dashboard-eventbridge.test.ts | 120 ++++++++++++++++++ core/dashboards/tests/dashboard.test.ts | 21 --- 3 files changed, 122 insertions(+), 22 deletions(-) create mode 100644 core/dashboards/tests/dashboard-eventbridge.test.ts diff --git a/core/dashboards/dashboard.ts b/core/dashboards/dashboard.ts index 85a0a195..5ee93f52 100644 --- a/core/dashboards/dashboard.ts +++ b/core/dashboards/dashboard.ts @@ -533,7 +533,8 @@ export default function addDashboard (dashboardConfig: SlicWatchInputDashboardCo namespace: 'AWS/Events', metric, dimensions: { RuleName: `\${${logicalId}}` }, - stat + stat, + yAxis: metricConfig.yAxis }) } } diff --git a/core/dashboards/tests/dashboard-eventbridge.test.ts b/core/dashboards/tests/dashboard-eventbridge.test.ts new file mode 100644 index 00000000..f1e892b4 --- /dev/null +++ b/core/dashboards/tests/dashboard-eventbridge.test.ts @@ -0,0 +1,120 @@ +import { merge } from 'lodash' +import { test } from 'tap' +import { type MetricWidgetProperties } from 'cloudwatch-dashboard-types' + +import { type ResourceType } from '../../cf-template' +import addDashboard from '../dashboard' +import defaultConfig from '../../inputs/default-config' + +import { createTestCloudFormationTemplate, getDashboardFromTemplate, getDashboardWidgetsByTitle } from '../../tests/testing-utils' + +test('dashboard contains configured EventBridge resources', (t) => { + t.test('dashboards includes EventBridge metrics', (t) => { + const template = createTestCloudFormationTemplate() + addDashboard(defaultConfig.dashboard, template) + const { dashboard } = getDashboardFromTemplate(template) + + const widgets = getDashboardWidgetsByTitle(dashboard, /EventBridge Rule/) + const [ruleWidget] = widgets + + t.ok(ruleWidget) + + t.same((ruleWidget.properties as MetricWidgetProperties).metrics, [ + ['AWS/Events', 'FailedInvocations', 'RuleName', '${ServerlesstestprojectdeveventsRulerule1EventBridgeRule}', { stat: 'Sum', yAxis: 'left' }], + ['AWS/Events', 'ThrottledRules', 'RuleName', '${ServerlesstestprojectdeveventsRulerule1EventBridgeRule}', { stat: 'Sum', yAxis: 'left' }], + ['AWS/Events', 'Invocations', 'RuleName', '${ServerlesstestprojectdeveventsRulerule1EventBridgeRule}', { stat: 'Sum', yAxis: 'left' }] + ]) + + const props: MetricWidgetProperties = ruleWidget.properties as MetricWidgetProperties + t.ok((props.metrics?.length ?? 0) > 0) + t.equal(props.period, 300) + t.equal(props.view, 'timeSeries') + t.end() + }) + + t.test('service config overrides take precedence', (t) => { + const template = createTestCloudFormationTemplate() + + const config = merge({}, defaultConfig.dashboard, { + widgets: { + Events: { + metricPeriod: 900, + width: 8, + height: 12, + FailedInvocations: { + Statistic: ['Count'] + }, + ThrottledRules: { + Statistic: ['Sum'], + enabled: false + }, + Invocations: { + Statistic: ['ts85'], + yAxis: 'right' + } + } + } + }) + + addDashboard(config, template) + const { dashboard } = getDashboardFromTemplate(template) + const widgets = getDashboardWidgetsByTitle(dashboard, /EventBridge Rule/) + + const [ruleWidget] = widgets + t.ok(ruleWidget) + t.same((ruleWidget.properties as MetricWidgetProperties).metrics, [ + ['AWS/Events', 'FailedInvocations', 'RuleName', '${ServerlesstestprojectdeveventsRulerule1EventBridgeRule}', { stat: 'Count', yAxis: 'left' }], + ['AWS/Events', 'Invocations', 'RuleName', '${ServerlesstestprojectdeveventsRulerule1EventBridgeRule}', { stat: 'ts85', yAxis: 'right' }] + ]) + + const props: MetricWidgetProperties = ruleWidget.properties as MetricWidgetProperties + t.ok((props.metrics?.length ?? 0) > 0) + t.equal(props.period, 900) + t.equal(props.view, 'timeSeries') + + t.end() + }) + + t.test('resource config overrides take precedence', (t) => { + const template = createTestCloudFormationTemplate(); + (template.Resources as ResourceType).ServerlesstestprojectdeveventsRulerule1EventBridgeRule.Metadata = { + slicWatch: { + dashboard: { + FailedInvocations: { + Statistic: ['ts85'], + yAxis: 'left', + enabled: true + }, + ThrottledRules: { + Statistic: ['Sum'], + enabled: false + }, + Invocations: { + Statistic: ['ts85'], + yAxis: 'right' + } + } + } + } + + addDashboard(defaultConfig.dashboard, template) + const { dashboard } = getDashboardFromTemplate(template) + const widgets = getDashboardWidgetsByTitle(dashboard, /EventBridge Rule/) + + const [ruleWidget] = widgets + t.ok(ruleWidget) + t.same((ruleWidget.properties as MetricWidgetProperties).metrics, [ + ['AWS/Events', 'FailedInvocations', 'RuleName', '${ServerlesstestprojectdeveventsRulerule1EventBridgeRule}', { stat: 'ts85', yAxis: 'left' }], + ['AWS/Events', 'Invocations', 'RuleName', '${ServerlesstestprojectdeveventsRulerule1EventBridgeRule}', { stat: 'ts85', yAxis: 'right' }] + ]) + + const props: MetricWidgetProperties = ruleWidget.properties as MetricWidgetProperties + t.ok((props.metrics?.length ?? 0) > 0) + t.equal(props.period, 300) + t.equal(props.view, 'timeSeries') + + t.end() + }) + + t.end() +}) diff --git a/core/dashboards/tests/dashboard.test.ts b/core/dashboards/tests/dashboard.test.ts index c5c56bae..8745908d 100644 --- a/core/dashboards/tests/dashboard.test.ts +++ b/core/dashboards/tests/dashboard.test.ts @@ -52,27 +52,6 @@ test('A dashboard includes metrics', (t) => { t.end() }) - t.test('dashboard includes Events metrics', (t) => { - const widgets = dashboard.widgets.filter(({ properties }) => - ((properties as MetricWidgetProperties).title ?? '').startsWith('EventBridge') - ) - t.equal(widgets.length, 1) - const namespaces = new Set() - for (const widget of widgets) { - for (const metric of (widget.properties as MetricWidgetProperties).metrics ?? []) { - namespaces.add(metric[0]) - } - } - t.same(namespaces, new Set(['AWS/Events'])) - const expectedTitles = new Set(['EventBridge Rule ${ServerlesstestprojectdeveventsRulerule1EventBridgeRule}']) - - const actualTitles = new Set( - widgets.map((widget) => (widget.properties as MetricWidgetProperties).title) - ) - t.same(actualTitles, expectedTitles) - t.end() - }) - t.end() }) From 227f223aaa55e6f32541b4728d1752c17792beea Mon Sep 17 00:00:00 2001 From: Eoin Shanaghy Date: Tue, 28 Nov 2023 18:12:03 +0000 Subject: [PATCH 19/35] chore: extract and extend ECS dashboard tests --- core/dashboards/dashboard.ts | 3 +- core/dashboards/tests/dashboard-ecs.test.ts | 106 ++++++++++++++++++++ core/dashboards/tests/dashboard.test.ts | 23 ----- 3 files changed, 108 insertions(+), 24 deletions(-) create mode 100644 core/dashboards/tests/dashboard-ecs.test.ts diff --git a/core/dashboards/dashboard.ts b/core/dashboards/dashboard.ts index 5ee93f52..917dfc74 100644 --- a/core/dashboards/dashboard.ts +++ b/core/dashboards/dashboard.ts @@ -460,7 +460,8 @@ export default function addDashboard (dashboardConfig: SlicWatchInputDashboardCo ServiceName: `\${${logicalId}.Name}`, ClusterName: clusterName }, - stat + stat, + yAxis: metricConfig.yAxis }) } } diff --git a/core/dashboards/tests/dashboard-ecs.test.ts b/core/dashboards/tests/dashboard-ecs.test.ts new file mode 100644 index 00000000..626ff0c8 --- /dev/null +++ b/core/dashboards/tests/dashboard-ecs.test.ts @@ -0,0 +1,106 @@ +import { merge } from 'lodash' +import { test } from 'tap' +import { type MetricWidgetProperties } from 'cloudwatch-dashboard-types' + +import { type ResourceType } from '../../cf-template' +import addDashboard from '../dashboard' +import defaultConfig from '../../inputs/default-config' + +import { createTestCloudFormationTemplate, getDashboardFromTemplate, getDashboardWidgetsByTitle } from '../../tests/testing-utils' + +test('dashboard contains configured ECS resources', (t) => { + t.test('dashboard includes ECS metrics', (t) => { + const template = createTestCloudFormationTemplate() + addDashboard(defaultConfig.dashboard, template) + const { dashboard } = getDashboardFromTemplate(template) + + const widgets = getDashboardWidgetsByTitle(dashboard, /ECS/) + const [ecsWidget] = widgets + + t.ok(ecsWidget) + t.same((ecsWidget.properties as MetricWidgetProperties).metrics, [ + ['AWS/ECS', 'MemoryUtilization', 'ServiceName', '${ecsService.Name}', 'ClusterName', '${ecsCluster}', { stat: 'Average', yAxis: 'left' }], + ['AWS/ECS', 'CPUUtilization', 'ServiceName', '${ecsService.Name}', 'ClusterName', '${ecsCluster}', { stat: 'Average', yAxis: 'left' }] + ]) + + const props: MetricWidgetProperties = ecsWidget.properties as MetricWidgetProperties + t.ok((props.metrics?.length ?? 0) > 0) + t.equal(props.period, 300) + t.equal(props.view, 'timeSeries') + + t.end() + }) + + t.test('service config overrides take precedence', (t) => { + const template = createTestCloudFormationTemplate() + addDashboard(merge({}, defaultConfig.dashboard, { + widgets: { + ECS: { + metricPeriod: 900, + width: 8, + height: 12, + MemoryUtilization: { + Statistic: ['P99'] + }, + CPUUtilization: { + Statistic: ['P95'], + yAxis: 'right' + } + } + } + }), template) + const { dashboard } = getDashboardFromTemplate(template) + + const widgets = getDashboardWidgetsByTitle(dashboard, /ECS/) + const [ecsWidget] = widgets + + t.ok(ecsWidget) + t.same((ecsWidget.properties as MetricWidgetProperties).metrics, [ + ['AWS/ECS', 'MemoryUtilization', 'ServiceName', '${ecsService.Name}', 'ClusterName', '${ecsCluster}', { stat: 'P99', yAxis: 'left' }], + ['AWS/ECS', 'CPUUtilization', 'ServiceName', '${ecsService.Name}', 'ClusterName', '${ecsCluster}', { stat: 'P95', yAxis: 'right' }] + ]) + const props: MetricWidgetProperties = ecsWidget.properties as MetricWidgetProperties + t.ok((props.metrics?.length ?? 0) > 0) + t.equal(props.period, 900) + t.equal(props.view, 'timeSeries') + + t.end() + }) + + t.test('resource config overrides take precedence', (t) => { + const template = createTestCloudFormationTemplate(); + + (template.Resources as ResourceType).ecsService.Metadata = { + slicWatch: { + dashboard: { + MemoryUtilization: { + Statistic: ['P90'], + yAxis: 'right' + }, + CPUUtilization: { + Statistic: ['P50'], + yAxis: 'left', + enabled: false + } + } + } + } + addDashboard(defaultConfig.dashboard, template) + const { dashboard } = getDashboardFromTemplate(template) + + const widgets = getDashboardWidgetsByTitle(dashboard, /ECS/) + const [ecsWidget] = widgets + + t.ok(ecsWidget) + t.same((ecsWidget.properties as MetricWidgetProperties).metrics, [ + ['AWS/ECS', 'MemoryUtilization', 'ServiceName', '${ecsService.Name}', 'ClusterName', '${ecsCluster}', { stat: 'P90', yAxis: 'right' }] + ]) + const props: MetricWidgetProperties = ecsWidget.properties as MetricWidgetProperties + t.ok((props.metrics?.length ?? 0) > 0) + t.equal(props.period, 300) + t.equal(props.view, 'timeSeries') + t.end() + }) + + t.end() +}) diff --git a/core/dashboards/tests/dashboard.test.ts b/core/dashboards/tests/dashboard.test.ts index 8745908d..41fc1c32 100644 --- a/core/dashboards/tests/dashboard.test.ts +++ b/core/dashboards/tests/dashboard.test.ts @@ -29,29 +29,6 @@ test('A dashboard includes metrics', (t) => { t.ok(dashboard.start) - t.test('dashboard includes ECS metrics', (t) => { - const widgets = dashboard.widgets.filter(({ properties }) => - ((properties as MetricWidgetProperties).title ?? '').startsWith('ECS') - ) - t.equal(widgets.length, 1) - const namespaces = new Set() - for (const widget of widgets) { - for (const metric of (widget.properties as MetricWidgetProperties).metrics ?? []) { - namespaces.add(metric[0]) - } - } - t.same(namespaces, new Set(['AWS/ECS'])) - const expectedTitles = new Set([ - 'ECS Service ${ecsService.Name}' - ]) - - const actualTitles = new Set( - widgets.map((widget) => (widget.properties as MetricWidgetProperties).title) - ) - t.same(actualTitles, expectedTitles) - t.end() - }) - t.end() }) From 5bbc9fcb58179db652d4d341642b184ee7d4f068 Mon Sep 17 00:00:00 2001 From: Eoin Shanaghy Date: Tue, 28 Nov 2023 21:23:10 +0000 Subject: [PATCH 20/35] chore: extract and extend DynamoDB dashboard tests --- core/dashboards/dashboard.ts | 6 +- core/dashboards/tests/dashboard-alb.test.ts | 182 +++++++++++++++ .../tests/dashboard-dynamodb.test.ts | 24 ++ core/dashboards/tests/dashboard.test.ts | 207 +----------------- 4 files changed, 211 insertions(+), 208 deletions(-) create mode 100644 core/dashboards/tests/dashboard-alb.test.ts diff --git a/core/dashboards/dashboard.ts b/core/dashboards/dashboard.ts index 917dfc74..96814bc3 100644 --- a/core/dashboards/dashboard.ts +++ b/core/dashboards/dashboard.ts @@ -573,7 +573,8 @@ export default function addDashboard (dashboardConfig: SlicWatchInputDashboardCo dimensions: { LoadBalancer: loadBalancerFullName }, - stat + stat, + yAxis: metricConfig.yAxis }) } } @@ -619,7 +620,8 @@ export default function addDashboard (dashboardConfig: SlicWatchInputDashboardCo LoadBalancer: loadBalancerFullName, TargetGroup: targetGroupFullName }, - stat + stat, + yAxis: metricConfig.yAxis }) } } diff --git a/core/dashboards/tests/dashboard-alb.test.ts b/core/dashboards/tests/dashboard-alb.test.ts new file mode 100644 index 00000000..e6af329f --- /dev/null +++ b/core/dashboards/tests/dashboard-alb.test.ts @@ -0,0 +1,182 @@ +import { merge } from 'lodash' +import { test } from 'tap' +import { type MetricWidgetProperties } from 'cloudwatch-dashboard-types' + +import { type ResourceType } from '../../cf-template' +import addDashboard from '../dashboard' +import defaultConfig from '../../inputs/default-config' + +import { albCfTemplate, createTestCloudFormationTemplate, getDashboardFromTemplate, getDashboardWidgetsByTitle } from '../../tests/testing-utils' + +test('dashboard contains configured ALB resources', (t) => { + t.test('dashboards includes ALB metrics', (t) => { + const template = createTestCloudFormationTemplate(albCfTemplate) + addDashboard(defaultConfig.dashboard, template) + const { dashboard } = getDashboardFromTemplate(template) + + const widgets = getDashboardWidgetsByTitle(dashboard, + /ALB/, + /Target Group/ + ) + + const [albWidget, targetGroupWidget] = widgets + t.ok(albWidget) + t.ok(targetGroupWidget) + t.same((albWidget.properties as MetricWidgetProperties).metrics, [ + ['AWS/ApplicationELB', 'HTTPCode_ELB_5XX_Count', 'LoadBalancer', '${alb.LoadBalancerFullName}', { stat: 'Sum', yAxis: 'left' }], + ['AWS/ApplicationELB', 'RejectedConnectionCount', 'LoadBalancer', '${alb.LoadBalancerFullName}', { stat: 'Sum', yAxis: 'left' }] + ]) + t.same((targetGroupWidget.properties as MetricWidgetProperties).metrics, [ + ['AWS/ApplicationELB', 'HTTPCode_Target_5XX_Count', 'LoadBalancer', '${alb.LoadBalancerFullName}', 'TargetGroup', '${AlbEventAlbTargetGrouphttpListener.TargetGroupFullName}', { stat: 'Sum', yAxis: 'left' }], + ['AWS/ApplicationELB', 'UnHealthyHostCount', 'LoadBalancer', '${alb.LoadBalancerFullName}', 'TargetGroup', '${AlbEventAlbTargetGrouphttpListener.TargetGroupFullName}', { stat: 'Average', yAxis: 'left' }], + ['AWS/ApplicationELB', 'LambdaInternalError', 'LoadBalancer', '${alb.LoadBalancerFullName}', 'TargetGroup', '${AlbEventAlbTargetGrouphttpListener.TargetGroupFullName}', { stat: 'Sum', yAxis: 'left' }], + ['AWS/ApplicationELB', 'LambdaUserError', 'LoadBalancer', '${alb.LoadBalancerFullName}', 'TargetGroup', '${AlbEventAlbTargetGrouphttpListener.TargetGroupFullName}', { stat: 'Sum', yAxis: 'left' }] + ]) + + t.end() + }) + + t.test('service config overrides take precedence', (t) => { + const template = createTestCloudFormationTemplate(albCfTemplate) + + const config = merge({}, defaultConfig.dashboard, { + widgets: { + ApplicationELB: { + metricPeriod: 900, + width: 8, + height: 12, + HTTPCode_ELB_5XX_Count: { + Statistic: ['Average'], + enabled: false + }, + RejectedConnectionCount: { + Statistic: ['ts90'], + yAxis: 'right' + } + }, + ApplicationELBTarget: { + metricPeriod: 900, + width: 24, + height: 12, + HTTPCode_Target_5XX_Count: { + Statistic: ['ts80'], + yAxis: 'right' + }, + UnHealthyHostCount: { + Statistic: ['Count'], + yAxis: 'right' + }, + LambdaInternalError: { + Statistic: ['P99'], + yAxis: 'left' + }, + LambdaUserError: { + Statistic: ['Sum'], + enabled: false + } + } + } + }) + + addDashboard(config, template) + const { dashboard } = getDashboardFromTemplate(template) + + const widgets = getDashboardWidgetsByTitle(dashboard, + /ALB/, + /Target Group/ + ) + + const [albWidget, targetGroupWidget] = widgets + t.ok(albWidget) + t.ok(targetGroupWidget) + t.same((albWidget.properties as MetricWidgetProperties).metrics, [ + ['AWS/ApplicationELB', 'RejectedConnectionCount', 'LoadBalancer', '${alb.LoadBalancerFullName}', { stat: 'ts90', yAxis: 'right' }] + ]) + t.same((targetGroupWidget.properties as MetricWidgetProperties).metrics, [ + ['AWS/ApplicationELB', 'HTTPCode_Target_5XX_Count', 'LoadBalancer', '${alb.LoadBalancerFullName}', 'TargetGroup', '${AlbEventAlbTargetGrouphttpListener.TargetGroupFullName}', { stat: 'ts80', yAxis: 'right' }], + ['AWS/ApplicationELB', 'UnHealthyHostCount', 'LoadBalancer', '${alb.LoadBalancerFullName}', 'TargetGroup', '${AlbEventAlbTargetGrouphttpListener.TargetGroupFullName}', { stat: 'Count', yAxis: 'right' }], + ['AWS/ApplicationELB', 'LambdaInternalError', 'LoadBalancer', '${alb.LoadBalancerFullName}', 'TargetGroup', '${AlbEventAlbTargetGrouphttpListener.TargetGroupFullName}', { stat: 'P99', yAxis: 'left' }] + ]) + + for (const widget of widgets) { + const props: MetricWidgetProperties = widget.properties as MetricWidgetProperties + t.ok((props.metrics?.length ?? 0) > 0) + t.equal(props.period, 900) + t.equal(props.view, 'timeSeries') + } + + t.end() + }) + + t.test('resource config overrides take precedence', (t) => { + const template = createTestCloudFormationTemplate(albCfTemplate) + const resources = template.Resources as ResourceType + resources.alb.Metadata = { + slicWatch: { + dashboard: { + HTTPCode_ELB_5XX_Count: { + Statistic: ['Average'], + enabled: false + }, + RejectedConnectionCount: { + Statistic: ['ts90'], + yAxis: 'right' + } + } + } + } + + resources.AlbEventAlbTargetGrouphttpListener.Metadata = { + slicWatch: { + dashboard: { + HTTPCode_Target_5XX_Count: { + Statistic: ['ts99'], + yAxis: 'right' + }, + UnHealthyHostCount: { + Statistic: ['Count'], + yAxis: 'right', + enabled: false + }, + LambdaInternalError: { + Statistic: ['P99'], + yAxis: 'left' + }, + LambdaUserError: { + Statistic: ['Sum'], + enabled: false + } + } + } + } + addDashboard(defaultConfig.dashboard, template) + const { dashboard } = getDashboardFromTemplate(template) + + const widgets = getDashboardWidgetsByTitle(dashboard, + /ALB/, + /Target Group/ + ) + + const [albWidget, targetGroupWidget] = widgets + t.ok(albWidget) + t.ok(targetGroupWidget) + t.same((albWidget.properties as MetricWidgetProperties).metrics, [ + ['AWS/ApplicationELB', 'RejectedConnectionCount', 'LoadBalancer', '${alb.LoadBalancerFullName}', { stat: 'ts90', yAxis: 'right' }] + ]) + t.same((targetGroupWidget.properties as MetricWidgetProperties).metrics, [ + ['AWS/ApplicationELB', 'HTTPCode_Target_5XX_Count', 'LoadBalancer', '${alb.LoadBalancerFullName}', 'TargetGroup', '${AlbEventAlbTargetGrouphttpListener.TargetGroupFullName}', { stat: 'ts99', yAxis: 'right' }], + ['AWS/ApplicationELB', 'LambdaInternalError', 'LoadBalancer', '${alb.LoadBalancerFullName}', 'TargetGroup', '${AlbEventAlbTargetGrouphttpListener.TargetGroupFullName}', { stat: 'P99', yAxis: 'left' }] + ]) + + for (const widget of widgets) { + const props: MetricWidgetProperties = widget.properties as MetricWidgetProperties + t.ok((props.metrics?.length ?? 0) > 0) + t.equal(props.period, 300) + t.equal(props.view, 'timeSeries') + } + + t.end() + }) + + t.end() +}) diff --git a/core/dashboards/tests/dashboard-dynamodb.test.ts b/core/dashboards/tests/dashboard-dynamodb.test.ts index 7398dcec..f2829c97 100644 --- a/core/dashboards/tests/dashboard-dynamodb.test.ts +++ b/core/dashboards/tests/dashboard-dynamodb.test.ts @@ -1,6 +1,7 @@ import { merge } from 'lodash' import { test } from 'tap' import { type MetricWidgetProperties } from 'cloudwatch-dashboard-types' +import { type DynamoDB } from 'cloudform' import { type ResourceType } from '../../cf-template' import addDashboard from '../dashboard' @@ -51,6 +52,29 @@ test('dashboard contains configured DynamoDB resources', (t) => { t.end() }) + t.test('dashboards includes DynamoDB metrics without GSIs', (t) => { + const template = createTestCloudFormationTemplate() + delete ((template.Resources as ResourceType).dataTable as DynamoDB.Table).Properties.GlobalSecondaryIndexes + addDashboard(defaultConfig.dashboard, template) + const { dashboard } = getDashboardFromTemplate(template) + + const widgets = getDashboardWidgetsByTitle(dashboard, + /ReadThrottleEvents Table /, + /ReadThrottleEvents GSI GSI1 in /, + /WriteThrottleEvents Table /, + /WriteThrottleEvents GSI GSI1 in / + ) + + const [ + readThrottlesWidget, readThrottlesGsiWidget, writeThrottlesWidget, writeThrottlesGsiWidget + ] = widgets + t.ok(readThrottlesWidget) + t.notOk(readThrottlesGsiWidget) + t.ok(writeThrottlesWidget) + t.notOk(writeThrottlesGsiWidget) + t.end() + }) + t.test('service config overrides take precedence', (t) => { const template = createTestCloudFormationTemplate() diff --git a/core/dashboards/tests/dashboard.test.ts b/core/dashboards/tests/dashboard.test.ts index 41fc1c32..938f4a47 100644 --- a/core/dashboards/tests/dashboard.test.ts +++ b/core/dashboards/tests/dashboard.test.ts @@ -1,11 +1,10 @@ import _ from 'lodash' import { test } from 'tap' -import { type MetricWidgetProperties } from 'cloudwatch-dashboard-types' import addDashboard from '../dashboard' import defaultConfig from '../../inputs/default-config' -import { createTestCloudFormationTemplate, defaultCfTemplate, albCfTemplate, appSyncCfTemplate, getDashboardFromTemplate } from '../../tests/testing-utils' +import { createTestCloudFormationTemplate, getDashboardFromTemplate } from '../../tests/testing-utils' import { getResourcesByType } from '../../cf-template' import { type Widgets } from '../dashboard-types' @@ -32,210 +31,6 @@ test('A dashboard includes metrics', (t) => { t.end() }) -test('A dashboard includes metrics for ALB', (t) => { - const compiledTemplate = createTestCloudFormationTemplate((albCfTemplate)) - addDashboard(defaultConfig.dashboard, compiledTemplate) - const dashResources = getResourcesByType('AWS::CloudWatch::Dashboard', compiledTemplate) - t.equal(Object.keys(dashResources).length, 1) - const [, dashResource] = Object.entries(dashResources)[0] - t.same(dashResource.Properties?.DashboardName, { 'Fn::Sub': '${AWS::StackName}-${AWS::Region}-Dashboard' }) - const dashboard = JSON.parse(dashResource.Properties?.DashboardBody['Fn::Sub']) - - t.ok(dashboard.start) - - t.test('dashboard includes Application Load Balancer metrics', (t) => { - const widgets = dashboard.widgets.filter(({ properties: { title } }) => - title.startsWith('ALB') - ) - t.equal(widgets.length, 1) - const namespaces = new Set() - for (const widget of widgets) { - for (const metric of widget.properties.metrics) { - namespaces.add(metric[0]) - } - } - t.same(namespaces, new Set(['AWS/ApplicationELB'])) - const expectedTitles = new Set(['ALB ${alb.LoadBalancerName}']) - - const actualTitles = new Set( - widgets.map((widget) => widget.properties.title) - ) - t.same(actualTitles, expectedTitles) - t.end() - }) - - t.test('dashboard includes Application Load Balancer Target Groups metrics', (t) => { - const widgets = dashboard.widgets.filter(({ properties: { title } }) => - title.startsWith('Target') - ) - t.equal(widgets.length, 1) - const namespaces = new Set() - const metricNames: string[] = [] - for (const metric of widgets[0].properties.metrics) { - namespaces.add(metric[0]) - metricNames.push(metric[1]) - } - t.same(namespaces, new Set(['AWS/ApplicationELB'])) - t.same(metricNames.sort(), ['HTTPCode_Target_5XX_Count', 'UnHealthyHostCount', 'LambdaInternalError', 'LambdaUserError'].sort()) - const expectedTitles = new Set(['Target Group ${alb.LoadBalancerName}/${AlbEventAlbTargetGrouphttpListener.TargetGroupName}']) - - const actualTitles = new Set( - widgets.map((widget) => widget.properties.title) - ) - t.same(actualTitles, expectedTitles) - t.end() - - test('No widgets are created if all AppSync metrics are disabled', (t) => { - const services = ['Lambda', 'ApiGateway', 'States', 'DynamoDB', 'SQS', 'Kinesis', 'ECS', 'SNS', 'Events', 'ApplicationELB', 'ApplicationELBTarget', 'AppSync'] - const dashConfig = _.cloneDeep(defaultConfig.dashboard) - for (const service of services) { - (dashConfig.widgets as Widgets)[service].enabled = false - } - const compiledTemplate = createTestCloudFormationTemplate((appSyncCfTemplate)) - addDashboard(dashConfig, compiledTemplate) - const dashResources = getResourcesByType('AWS::CloudWatch::Dashboard', compiledTemplate) - t.same(dashResources, {}) - t.end() - }) - - test('No widgets are created if all Application Load Balancer metrics are disabled', (t) => { - const services = ['Lambda', 'ApiGateway', 'States', 'DynamoDB', 'SQS', 'Kinesis', 'ECS', 'SNS', 'Events', 'ApplicationELB', 'ApplicationELBTarget', 'AppSync'] - const dashConfig = _.cloneDeep(defaultConfig.dashboard) - for (const service of services) { - (dashConfig.widgets as Widgets)[service].enabled = false - } - const compiledTemplate = createTestCloudFormationTemplate((albCfTemplate)) - addDashboard(dashConfig, compiledTemplate) - const dashResources = getResourcesByType('AWS::CloudWatch::Dashboard', compiledTemplate) - t.same(dashResources, {}) - t.end() - }) - }) - - t.test('target groups with no Lambda targets are excluded from metrics', (t) => { - const compiledTemplate = createTestCloudFormationTemplate({ - Resources: { - listener: { - Type: 'AWS::ElasticLoadBalancingV2::Listener', - Properties: { - DefaultActions: [ - { - TargetGroupArn: { Ref: 'tg' } - } - ], - LoadBalancerArn: { Ref: 'alb' } - } - }, - tg: { - Type: 'AWS::ElasticLoadBalancingV2::TargetGroup', - Properties: { - TargetType: 'redirect' - } - }, - alb: { - Type: '' - } - } - }) - addDashboard(defaultConfig.dashboard, compiledTemplate) - const tgDashResource = Object.values(getResourcesByType('AWS::CloudWatch::Dashboard', compiledTemplate))[0] - const tgDashBody = JSON.parse(tgDashResource.Properties?.DashboardBody['Fn::Sub']) - - const widgets = tgDashBody.widgets.filter(({ properties: { title } }) => - title.startsWith('Target') - ) - t.equal(widgets.length, 1) - const metricNames: string[] = [] - for (const metric of widgets[0].properties.metrics) { - metricNames.push(metric[1]) - } - t.same(metricNames.sort(), ['HTTPCode_Target_5XX_Count', 'UnHealthyHostCount'].sort()) - t.end() - }) - - test('A dashboard includes metrics for AppSync', (t) => { - const compiledTemplate = createTestCloudFormationTemplate((appSyncCfTemplate)) - addDashboard(defaultConfig.dashboard, compiledTemplate) - const dashResources = getResourcesByType('AWS::CloudWatch::Dashboard', compiledTemplate) - t.equal(Object.keys(dashResources).length, 1) - const [, dashResource] = Object.entries(dashResources)[0] - t.same(dashResource.Properties?.DashboardName, { 'Fn::Sub': '${AWS::StackName}-${AWS::Region}-Dashboard' }) - const dashboard = JSON.parse(dashResource.Properties?.DashboardBody['Fn::Sub']) - - t.ok(dashboard.start) - - t.test('dashboard includes AppSync metrics', (t) => { - const widgets = dashboard.widgets.filter(({ properties: { title } }) => - title.startsWith('AppSync') - ) - t.equal(widgets.length, 2) - const namespaces = new Set() - for (const widget of widgets) { - for (const metric of widget.properties.metrics) { - namespaces.add(metric[0]) - } - } - t.same(namespaces, new Set(['AWS/AppSync'])) - const expectedTitles = new Set([ - 'AppSync API awesome-appsync', - 'AppSync Real-time Subscriptions awesome-appsync' - ]) - const actualTitles = new Set( - widgets.map((widget) => widget.properties.title) - ) - t.same(actualTitles, expectedTitles) - t.end() - }) - - test('No widgets are created if all AppSync metrics are disabled', (t) => { - const services = ['Lambda', 'ApiGateway', 'States', 'DynamoDB', 'SQS', 'Kinesis', 'ECS', 'SNS', 'Events', 'ApplicationELB', 'ApplicationELBTarget', 'AppSync'] - const dashConfig = _.cloneDeep(defaultConfig.dashboard) - for (const service of services) { - (dashConfig.widgets as Widgets)[service].enabled = false - } - const compiledTemplate = createTestCloudFormationTemplate((appSyncCfTemplate)) - addDashboard(dashConfig, compiledTemplate) - const dashResources = getResourcesByType('AWS::CloudWatch::Dashboard', compiledTemplate) - t.same(dashResources, {}) - t.end() - }) - - t.end() - }) - - t.end() -}) - -test('DynamoDB widgets are created without GSIs', (t) => { - const tableResource: any = _.cloneDeep(defaultCfTemplate.Resources?.dataTable) - delete tableResource?.Properties?.GlobalSecondaryIndexes - const compTemplates = { - Resources: { - dataTable: tableResource - } - } - - const compiledTemplate = createTestCloudFormationTemplate(compTemplates) - addDashboard(defaultConfig.dashboard, compiledTemplate) - - const dashResources = getResourcesByType('AWS::CloudWatch::Dashboard', compiledTemplate) - const [, dashResource] = Object.entries(dashResources)[0] - const dashboard = JSON.parse(dashResource.Properties?.DashboardBody['Fn::Sub']) - const widgets = dashboard.widgets - - t.equal(widgets.length, 2) - const expectedTitles = new Set([ - 'ReadThrottleEvents Table ${dataTable}', - 'WriteThrottleEvents Table ${dataTable}' - ]) - - const actualTitles = new Set( - widgets.map((widget) => widget.properties.title) - ) - t.same(actualTitles, expectedTitles) - t.end() -}) - test('No dashboard is created if all widgets are disabled', (t) => { const services = ['Lambda', 'ApiGateway', 'States', 'DynamoDB', 'SQS', 'Kinesis', 'ECS', 'SNS', 'Events', 'ApplicationELB', 'ApplicationELBTarget', 'AppSync'] const dashConfig = _.cloneDeep(defaultConfig.dashboard) From 27f725cad5237c27804e23cc9a1cf079b3d6c696 Mon Sep 17 00:00:00 2001 From: Eoin Shanaghy Date: Wed, 29 Nov 2023 07:14:54 +0000 Subject: [PATCH 21/35] chore: remove superfluous file --- .../test-data/stress-workflow.json | 1765 ----------------- 1 file changed, 1765 deletions(-) delete mode 100644 serverless-test-project/test-data/stress-workflow.json diff --git a/serverless-test-project/test-data/stress-workflow.json b/serverless-test-project/test-data/stress-workflow.json deleted file mode 100644 index 2595611e..00000000 --- a/serverless-test-project/test-data/stress-workflow.json +++ /dev/null @@ -1,1765 +0,0 @@ -{ - "destination": "stress", - "children": [ - { - "children": [ - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {} - ] - }, - { - "children": [ - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {} - ] - }, - { - "children": [ - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {} - ] - }, - { - "children": [ - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {} - ] - }, - { - "children": [ - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {} - ] - }, - { - "children": [ - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {} - ] - }, - { - "children": [ - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {} - ] - }, - { - "children": [ - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {} - ] - }, - { - "children": [ - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {} - ] - }, - { - "children": [ - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {} - ] - }, - { - "children": [ - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {} - ] - }, - { - "children": [ - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {} - ] - }, - { - "children": [ - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {} - ] - }, - { - "children": [ - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {} - ] - }, - { - "children": [ - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {} - ] - }, - { - "children": [ - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {} - ] - }, - { - "children": [ - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {} - ] - }, - { - "children": [ - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {} - ] - }, - { - "children": [ - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {} - ] - }, - { - "children": [ - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {} - ] - }, - { - "children": [ - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {} - ] - }, - { - "children": [ - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {} - ] - }, - { - "children": [ - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {} - ] - }, - { - "children": [ - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {} - ] - }, - { - "children": [ - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {} - ] - }, - { - "children": [ - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {} - ] - }, - { - "children": [ - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {} - ] - }, - { - "children": [ - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {} - ] - }, - { - "children": [ - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {} - ] - }, - { - "children": [ - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {} - ] - }, - { - "children": [ - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {} - ] - }, - { - "children": [ - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {} - ] - }, - { - "children": [ - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {} - ] - }, - { - "children": [ - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {} - ] - }, - { - "children": [ - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {} - ] - }, - { - "children": [ - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {} - ] - }, - { - "children": [ - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {} - ] - }, - { - "children": [ - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {} - ] - }, - { - "children": [ - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {} - ] - }, - { - "children": [ - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {} - ] - } - ] -} From f8ed3b8a718877865af2f96488c2111f4c7c11b7 Mon Sep 17 00:00:00 2001 From: Eoin Shanaghy Date: Fri, 1 Dec 2023 13:09:46 +0000 Subject: [PATCH 22/35] chore: remove superfluous import --- serverless-plugin/tests/index.test.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/serverless-plugin/tests/index.test.ts b/serverless-plugin/tests/index.test.ts index 34a4d6d2..c0de4146 100644 --- a/serverless-plugin/tests/index.test.ts +++ b/serverless-plugin/tests/index.test.ts @@ -5,7 +5,6 @@ import ServerlessError from 'serverless/lib/serverless-error' import ServerlessPlugin from '../serverless-plugin' import { getLogger } from 'slic-watch-core/logging' import { createMockServerless, dummyLogger, pluginUtils, slsYaml } from '../../test-utils/sls-test-utils' -import { type ResourceType } from 'slic-watch-core' interface TestData { schema? From 6405829d3366c7ef7fa2959397d8412988b8d8e6 Mon Sep 17 00:00:00 2001 From: Eoin Shanaghy Date: Mon, 4 Dec 2023 09:52:22 +0000 Subject: [PATCH 23/35] fix: metadata syntax for Lambda override in CDK test stacks --- .../fixtures/CdkECSStackTest-Europe.template.json | 2 +- .../fixtures/CdkGeneralStackTest-Europe.template.json | 8 +++----- .../fixtures/CdkGeneralStackTest-US.template.json | 8 +++----- .../fixtures/CdkSFNStackTest-Europe.template.json | 8 +++----- 4 files changed, 10 insertions(+), 16 deletions(-) diff --git a/cdk-test-project/tests/snapshot/fixtures/CdkECSStackTest-Europe.template.json b/cdk-test-project/tests/snapshot/fixtures/CdkECSStackTest-Europe.template.json index a1262399..5cb82351 100644 --- a/cdk-test-project/tests/snapshot/fixtures/CdkECSStackTest-Europe.template.json +++ b/cdk-test-project/tests/snapshot/fixtures/CdkECSStackTest-Europe.template.json @@ -853,7 +853,7 @@ "CDKMetadata": { "Type": "AWS::CDK::Metadata", "Properties": { - "Analytics": "v2:deflate64:H4sIAAAAAAAA/31Ry27CMBD8Fu7GbTlUXCmlCAm1UYK4IsfZpgvBjux1EIry73WepLSqFGlnx+PsembG58/8cSIudiqT0zTDmJcRCXlinjqUIO0hF0RglOWLPM9QCkKttlokLyITSkLyJkwqCCIwBUpgkAlLKDOviBsFqrSY8fLv24YtP3/2Yx1aAtVpejw63/nJQGujXV5LRm3FQPqZEUhnkK6D5H9ilRqw9he9US2/z2V9tg+WLHCxXyJysQJq9AMKtSPYiTiDG3/jFtZqic3yg7gGq01Ql3dBa2/lRVxZYLCoXR1+vFF1CjAI2k26bkE+s68zKKpfbnnZhbIT9vQKn6iwH3nPaEUCva8j7i7Qxo4OZs6n0OTRwYqhOPMy1O17mxpo702zYIsqlunU77TV6eB7j6uq7j4c5Y5YCFY7047sccWUToAf7UPxNOf+m02OFnFqnCI8Aw/b+g3+NWTOyAIAAA==" + "Analytics": "v2:deflate64:H4sIAAAAAAAA/31RTU8CMRD9LdxLRQ7GKyISEqMbIF7JbHdcR0q76UwhZrP/3ewHy4rG07x589r5eFN9f6cnIzjx2GT7saVUlxsBs1dw4l2JhncFiGBwrGdFYcmAkHfPHrIHsOAMZk8QchDcYDiSQYUWWMhYD1naKMjlx6ku/34d1Pz9Zz7UEQu6TnPGg/oWQo6yDD4WtWSQVgrNVJcbNDGQfPWS/4lFHpD5F71yLf9WmLr2lsxVElNLZhNTh9Loe7T2UXALqcULf+FmzN5QM3wvrsFildThBWQJgif4UkmgY33V/uOVq13AXtBO0mUzETAfB3RSb8667EzZAu8f8Z0cnVteM94JkMMw4K4Mbc7RQRtZWj86WCmCgy7Xvt23iYm3ZJoBW1Qp63PW5bPP+7ufcVXV2WuUIopaI/sY2pZnXCnnM9SffHOcTvTtRE9Gn0w0DtEJHVCv2/gNbRFl8sgCAAA=" }, "Metadata": { "aws:cdk:path": "CdkECSStackTest-Europe/CDKMetadata/Default" diff --git a/cdk-test-project/tests/snapshot/fixtures/CdkGeneralStackTest-Europe.template.json b/cdk-test-project/tests/snapshot/fixtures/CdkGeneralStackTest-Europe.template.json index 4f449249..36e6061a 100644 --- a/cdk-test-project/tests/snapshot/fixtures/CdkGeneralStackTest-Europe.template.json +++ b/cdk-test-project/tests/snapshot/fixtures/CdkGeneralStackTest-Europe.template.json @@ -97,10 +97,8 @@ "Metadata": { "slicWatch": { "alarms": { - "Lambda": { - "Invocations": { - "Threshold": 4 - } + "Invocations": { + "Threshold": 4 } } } @@ -903,7 +901,7 @@ "CDKMetadata": { "Type": "AWS::CDK::Metadata", "Properties": { - "Analytics": "v2:deflate64:H4sIAAAAAAAA/02Q30/DIBDH/5a9M9SZmL12Gp801rr3hdKzshaoPdhsGv53D5izCeE+9z24Xxu+feC3K3HGtWy6da9qPn84ITtG0mFGg3ze20FJ9vhpEgTWC103gs/P3kinrImhJZcwaoVIXmBKaD5XtocYiDYwvD8IRHDIi2jI5zsvO3A7gcDEoFrh4CwmPr+kQhWgKwaVEvxjIaX1xrEnGHo7aSAkdeHRFG2qmoG+Wj9KSEXK0f5Mf8olceZXcF+2iVKmwJrJCG0b2ste1HmOBIHBierQfip/Gc+n8b5Jevfgk5Yh3aXtlZyuYnZDuHbG0jpit8q08dmbd4N3y/YCM7YBfsSb092W09msjqjUeqRNKA28yvYXs0P/r9UBAAA=" + "Analytics": "v2:deflate64:H4sIAAAAAAAA/02QTU/DMAyGf8vumSmbhLhuIE4gRrf75KamZGuTUjsbVZT/jpKOsUvex68jfy3g8QGKGZ55ruvjvDUVhK2gPio88z6wZQg71xutnj5thqha7KoaIbx4q8U4m1K3vKGhM8zG2agMdhBK11JKJI2Kl3tkJmFYJVG8hLXXR5I1MinsTYNCZxwhvOZGJbGsepML/ONKa+etqGfqWzd2ZCW5N9FWsMldJyiJnR805Sabwf2Mf86l8MRvJF+uTtZEUdWjxc7VFYQdVtMeGaKiE1lhCKW/rOfzet8M4cOTz94E+d241ujxak5hjNfJVD5HmtbYJn1799J7uR0vKutqggPfnRYF3BdQzA5szHzwVkxHUE76CyBn/pPVAQAA" }, "Metadata": { "aws:cdk:path": "CdkGeneralStackTest-Europe/CDKMetadata/Default" diff --git a/cdk-test-project/tests/snapshot/fixtures/CdkGeneralStackTest-US.template.json b/cdk-test-project/tests/snapshot/fixtures/CdkGeneralStackTest-US.template.json index 31611708..fe6080b0 100644 --- a/cdk-test-project/tests/snapshot/fixtures/CdkGeneralStackTest-US.template.json +++ b/cdk-test-project/tests/snapshot/fixtures/CdkGeneralStackTest-US.template.json @@ -97,10 +97,8 @@ "Metadata": { "slicWatch": { "alarms": { - "Lambda": { - "Invocations": { - "Threshold": 4 - } + "Invocations": { + "Threshold": 4 } } } @@ -903,7 +901,7 @@ "CDKMetadata": { "Type": "AWS::CDK::Metadata", "Properties": { - "Analytics": "v2:deflate64:H4sIAAAAAAAA/02Q30/DIBDH/5a9M9SZmL12Gp801rr3hdKzshaoPdhsGv53D5izCeE+9z24Xxu+feC3K3HGtWy6da9qPn84ITtG0mFGg3ze20FJ9vhpEgTWC103gs/P3kinrImhJZcwaoVIXmBKaD5XtocYiDYwvD8IRHDIi2jI5zsvO3A7gcDEoFrh4CwmPr+kQhWgKwaVEvxjIaX1xrEnGHo7aSAkdeHRFG2qmoG+Wj9KSEXK0f5Mf8olceZXcF+2iVKmwJrJCG0b2ste1HmOBIHBierQfip/Gc+n8b5Jevfgk5Yh3aXtlZyuYnZDuHbG0jpit8q08dmbd4N3y/YCM7YBfsSb092W09msjqjUeqRNKA28yvYXs0P/r9UBAAA=" + "Analytics": "v2:deflate64:H4sIAAAAAAAA/02QTU/DMAyGf8vumSmbhLhuIE4gRrf75KamZGuTUjsbVZT/jpKOsUvex68jfy3g8QGKGZ55ruvjvDUVhK2gPio88z6wZQg71xutnj5thqha7KoaIbx4q8U4m1K3vKGhM8zG2agMdhBK11JKJI2Kl3tkJmFYJVG8hLXXR5I1MinsTYNCZxwhvOZGJbGsepML/ONKa+etqGfqWzd2ZCW5N9FWsMldJyiJnR805Sabwf2Mf86l8MRvJF+uTtZEUdWjxc7VFYQdVtMeGaKiE1lhCKW/rOfzet8M4cOTz94E+d241ujxak5hjNfJVD5HmtbYJn1799J7uR0vKutqggPfnRYF3BdQzA5szHzwVkxHUE76CyBn/pPVAQAA" }, "Metadata": { "aws:cdk:path": "CdkGeneralStackTest-US/CDKMetadata/Default" diff --git a/cdk-test-project/tests/snapshot/fixtures/CdkSFNStackTest-Europe.template.json b/cdk-test-project/tests/snapshot/fixtures/CdkSFNStackTest-Europe.template.json index 59a93a0f..6ab0f85c 100644 --- a/cdk-test-project/tests/snapshot/fixtures/CdkSFNStackTest-Europe.template.json +++ b/cdk-test-project/tests/snapshot/fixtures/CdkSFNStackTest-Europe.template.json @@ -92,10 +92,8 @@ "Metadata": { "slicWatch": { "alarms": { - "Lambda": { - "Invocations": { - "Threshold": 4 - } + "Invocations": { + "Threshold": 4 } } } @@ -230,7 +228,7 @@ "CDKMetadata": { "Type": "AWS::CDK::Metadata", "Properties": { - "Analytics": "v2:deflate64:H4sIAAAAAAAA/11P0UoDQQz8lr7nolaQvtpCoaAgp+Djke6lbbp7u6XZq8iy/+7etoIIgZnJhEwyx8UT3s/oSxvT28bJFtN7JGOhtLqkXjF9hJMYWO18JRkcDdueMK1Hb6IEP1m/PIPQgKkNjqd2xbfgxHxP8soy6GNHqhwVnycoGpejsRyXpAwa+bS77dMuklrFl5q58Zdg/w1g+iSJsCZxsDoEMQzlgcivZA7i6xV/dc7QsobxXOZqeDH34vf12puRwYee8ah3l4cFlprPjirSnEcfZWBsr/gDsE52pTwBAAA=" + "Analytics": "v2:deflate64:H4sIAAAAAAAA/11OTWvCQBD9Ld4n01RBeq2CUGihJEKPYdyMOibZFWeilGX/e8lqofT0voZ5b44vSyxndNPCtV3Ryw5jbeQ6oJs2Ub1i3IazOFjvfSYJehp2LWHcjN6ZBD9FvzyB0ICxCj1PdsbP0Iv7nuSdJdBFQ6psiq8TgC5wNbqObUXKoMbn/eOfNkbaKb7nzjd/Dd2/A4xfJAYbkh7WxyCOoTYy/iB3FJ9X/NUpQcUaxotjyOW10UH8Ia99BAl8aBlP+nSdl/hcYjk7qUhxGb3JwFjd8QcjaneZPAEAAA==" }, "Metadata": { "aws:cdk:path": "CdkSFNStackTest-Europe/CDKMetadata/Default" From 8ea0611c0e76e4232b3934c4f286cafa9bbdbf95 Mon Sep 17 00:00:00 2001 From: Eoin Shanaghy Date: Mon, 4 Dec 2023 10:17:37 +0000 Subject: [PATCH 24/35] fix: metadata syntax for Lambda override in SAM test stack --- sam-test-project/template.yaml | 69 +++++++------------ ...sam-test-project-transformed-template.json | 30 ++++---- 2 files changed, 36 insertions(+), 63 deletions(-) diff --git a/sam-test-project/template.yaml b/sam-test-project/template.yaml index 692963df..89221f28 100755 --- a/sam-test-project/template.yaml +++ b/sam-test-project/template.yaml @@ -1,16 +1,15 @@ AWSTemplateFormatVersion: 2010-09-09 -Description: >- - sam-test-project - +Description: sam-test-project Transform: - AWS::Serverless-2016-10-31 - Metadata: slicWatch: enabled: true alarmActionsConfig: - alarmActions: [!Ref MonitoringTopic] - okActions: [!Ref MonitoringTopic] + alarmActions: + - !Ref MonitoringTopic + okActions: + - !Ref MonitoringTopic actionsEnabled: true alarms: Lambda: @@ -24,14 +23,12 @@ Metadata: Threshold: 60 InFlightMessagesPc: Statistic: Maximum - Threshold: 1 # 1% = 1200 for regular queues or 180 for FIFO queues - + Threshold: 1 Resources: MonitoringTopic: Type: AWS::SNS::Topic Properties: TopicName: SS-Alarm-Topic3 - hello: Type: AWS::Serverless::Function Properties: @@ -40,10 +37,8 @@ Resources: Metadata: slicWatch: alarms: - Lambda: - Invocations: - Threshold: 2 - + Invocations: + Threshold: 2 ping: Type: AWS::Serverless::Function Properties: @@ -53,32 +48,27 @@ Resources: slicWatch: dashboard: enabled: false - throttler: Type: AWS::Serverless::Function Properties: Handler: basic-handler.hello Runtime: nodejs18.x ReservedConcurrentExecutions: 0 - driveStream: Type: AWS::Serverless::Function Properties: Handler: stream-test-handler.handleDrive Runtime: nodejs18.x - driveQueue: Type: AWS::Serverless::Function Properties: Handler: basic-handler.hello Runtime: nodejs18.x - driveTable: Type: AWS::Serverless::Function Properties: Handler: basic-handler.hello Runtime: nodejs18.x - streamProcessor: Type: AWS::Serverless::Function Properties: @@ -91,7 +81,6 @@ Resources: Stream: !GetAtt stream.Arn MaximumRetryAttempts: 0 StartingPosition: LATEST - httpGetter: Type: AWS::Serverless::Function Properties: @@ -102,9 +91,8 @@ Resources: HttpApiEvent: Type: HttpApi Properties: - Path: "item" + Path: item Method: GET - eventsRule: Type: AWS::Serverless::Function Properties: @@ -123,13 +111,10 @@ Resources: Metadata: slicWatch: alarms: - Lambda: - enabled: false - + enabled: false TestStateMachine: Type: AWS::Serverless::StateMachine Properties: - DefinitionUri: statemachine/test.asl.json DefinitionSubstitutions: HelloArn: !GetAtt hello.Arn AnotherHelloArn: !GetAtt hello.Arn @@ -138,42 +123,36 @@ Resources: FunctionName: !Ref hello - LambdaInvokePolicy: FunctionName: !Ref hello - + DefinitionUri: statemachine/test.asl.json stream: Type: AWS::Kinesis::Stream Properties: ShardCount: 1 - regularQueue: - Type: "AWS::SQS::Queue" - + Type: AWS::SQS::Queue fifoQueue: - Type: "AWS::SQS::Queue" + Type: AWS::SQS::Queue Properties: FifoQueue: true - vpc: Type: AWS::EC2::VPC Properties: CidrBlock: 10.0.0.0/16 - subnet: Type: AWS::EC2::Subnet Properties: AvailabilityZone: !Select - 0 - - Fn::GetAZs: !Ref "AWS::Region" + - !GetAZs + Ref: AWS::Region CidrBlock: 10.0.16.0/20 VpcId: !Ref vpc - ecsCluster: Type: AWS::ECS::Cluster - ecsService: Type: AWS::ECS::Service Properties: - Cluster: - Ref: ecsCluster + Cluster: !Ref ecsCluster DesiredCount: 0 LaunchType: FARGATE TaskDefinition: !Ref taskDef @@ -183,7 +162,6 @@ Resources: SecurityGroups: [] Subnets: - !Ref subnet - taskDef: Type: AWS::ECS::TaskDefinition Properties: @@ -192,18 +170,17 @@ Resources: Cpu: 256 Memory: 512 ContainerDefinitions: - - Name: "busybox" - Image: "busybox" + - Name: busybox + Image: busybox Cpu: 256 EntryPoint: - - "sh" - - "-c" + - sh + - '-c' Memory: 512 Command: - - '/bin/sh -c "while true; do echo Hello; sleep 10; done"' + - /bin/sh -c "while true; do echo Hello; sleep 10; done" Essential: true NetworkMode: awsvpc - dataTable: Type: AWS::DynamoDB::Table DeletionPolicy: Delete @@ -221,7 +198,7 @@ Resources: - AttributeName: gsi1sk AttributeType: S - AttributeName: timestamp - AttributeType: N + AttributeType: 'N' KeySchema: - AttributeName: pk KeyType: HASH @@ -251,4 +228,4 @@ Resources: Projection: NonKeyAttributes: - name - ProjectionType: INCLUDE + ProjectionType: INCLUDE \ No newline at end of file diff --git a/sam-test-project/tests/snapshot/fixtures/sam-test-project-transformed-template.json b/sam-test-project/tests/snapshot/fixtures/sam-test-project-transformed-template.json index 533fafae..51eaa214 100644 --- a/sam-test-project/tests/snapshot/fixtures/sam-test-project-transformed-template.json +++ b/sam-test-project/tests/snapshot/fixtures/sam-test-project-transformed-template.json @@ -263,10 +263,8 @@ "SamResourceId": "hello", "slicWatch": { "alarms": { - "Lambda": { - "Invocations": { - "Threshold": 2 - } + "Invocations": { + "Threshold": 2 } } } @@ -274,7 +272,7 @@ "Properties": { "Code": { "S3Bucket": "aws-sam-cli-managed-default-samclisourcebucket-167xnalzxxva4", - "S3Key": "sam-test-project/841a60f2d379216bd90fa34e033d0596" + "S3Key": "sam-test-project/810e2a73503f0ee11a4a06f488e12d55" }, "Handler": "basic-handler.hello", "Role": { @@ -335,7 +333,7 @@ "Properties": { "Code": { "S3Bucket": "aws-sam-cli-managed-default-samclisourcebucket-167xnalzxxva4", - "S3Key": "sam-test-project/841a60f2d379216bd90fa34e033d0596" + "S3Key": "sam-test-project/810e2a73503f0ee11a4a06f488e12d55" }, "Handler": "basic-handler.hello", "Role": { @@ -391,7 +389,7 @@ "Properties": { "Code": { "S3Bucket": "aws-sam-cli-managed-default-samclisourcebucket-167xnalzxxva4", - "S3Key": "sam-test-project/841a60f2d379216bd90fa34e033d0596" + "S3Key": "sam-test-project/810e2a73503f0ee11a4a06f488e12d55" }, "Handler": "basic-handler.hello", "Role": { @@ -448,7 +446,7 @@ "Properties": { "Code": { "S3Bucket": "aws-sam-cli-managed-default-samclisourcebucket-167xnalzxxva4", - "S3Key": "sam-test-project/841a60f2d379216bd90fa34e033d0596" + "S3Key": "sam-test-project/810e2a73503f0ee11a4a06f488e12d55" }, "Handler": "stream-test-handler.handleDrive", "Role": { @@ -504,7 +502,7 @@ "Properties": { "Code": { "S3Bucket": "aws-sam-cli-managed-default-samclisourcebucket-167xnalzxxva4", - "S3Key": "sam-test-project/841a60f2d379216bd90fa34e033d0596" + "S3Key": "sam-test-project/810e2a73503f0ee11a4a06f488e12d55" }, "Handler": "basic-handler.hello", "Role": { @@ -560,7 +558,7 @@ "Properties": { "Code": { "S3Bucket": "aws-sam-cli-managed-default-samclisourcebucket-167xnalzxxva4", - "S3Key": "sam-test-project/841a60f2d379216bd90fa34e033d0596" + "S3Key": "sam-test-project/810e2a73503f0ee11a4a06f488e12d55" }, "Handler": "basic-handler.hello", "Role": { @@ -616,7 +614,7 @@ "Properties": { "Code": { "S3Bucket": "aws-sam-cli-managed-default-samclisourcebucket-167xnalzxxva4", - "S3Key": "sam-test-project/841a60f2d379216bd90fa34e033d0596" + "S3Key": "sam-test-project/810e2a73503f0ee11a4a06f488e12d55" }, "Handler": "basic-handler.hello", "Role": { @@ -689,7 +687,7 @@ "Properties": { "Code": { "S3Bucket": "aws-sam-cli-managed-default-samclisourcebucket-167xnalzxxva4", - "S3Key": "sam-test-project/841a60f2d379216bd90fa34e033d0596" + "S3Key": "sam-test-project/810e2a73503f0ee11a4a06f488e12d55" }, "Handler": "apigw-handler.handleGet", "Role": { @@ -765,16 +763,14 @@ "SamResourceId": "eventsRule", "slicWatch": { "alarms": { - "Lambda": { - "enabled": false - } + "enabled": false } } }, "Properties": { "Code": { "S3Bucket": "aws-sam-cli-managed-default-samclisourcebucket-167xnalzxxva4", - "S3Key": "sam-test-project/841a60f2d379216bd90fa34e033d0596" + "S3Key": "sam-test-project/810e2a73503f0ee11a4a06f488e12d55" }, "Handler": "rule-handler.handleRule", "Role": { @@ -1026,4 +1022,4 @@ } } } -} +} \ No newline at end of file From a2000e5f4c3fda18a5557d8f1e6935292ea15cd0 Mon Sep 17 00:00:00 2001 From: Eoin Shanaghy Date: Mon, 4 Dec 2023 10:37:14 +0000 Subject: [PATCH 25/35] fix: cascade correctly with resource-level overrides --- cdk-test-project/source/general-stack.ts | 6 +- cdk-test-project/source/sfn-stack.ts | 6 +- core/alarms/alarm-utils.ts | 9 +- core/alarms/alb-target-group.ts | 3 +- core/alarms/alb.ts | 3 +- core/alarms/api-gateway.ts | 3 +- core/alarms/appsync.ts | 3 +- core/alarms/dynamodb.ts | 3 +- core/alarms/ecs.ts | 3 +- core/alarms/eventbridge.ts | 3 +- core/alarms/kinesis.ts | 3 +- core/alarms/lambda.ts | 3 +- core/alarms/sns.ts | 3 +- core/alarms/sqs.ts | 3 +- core/alarms/step-functions.ts | 3 +- core/cf-template.ts | 31 +- core/dashboards/dashboard-types.ts | 25 +- core/dashboards/dashboard.ts | 42 +- core/inputs/cascading-config.ts | 6 +- core/inputs/config-types.ts | 33 + package.json | 4 +- serverless-test-project-alb/serverless.yml | 2 +- serverless-test-project-alb/sls-resources.yml | 2 +- serverless-test-project/sls-resources.yml | 6 +- ...cdk-test-project-snapshot.test.ts.test.cjs | 536 ++++++++-------- ...sam-test-project-snapshot.test.ts.test.cjs | 347 ++++++----- ...test-project-alb-snapshot.test.ts.test.cjs | 39 +- ...-project-appsync-snapshot.test.ts.test.cjs | 15 +- ...ess-test-project-snapshot.test.ts.test.cjs | 577 +++++++++++------- test-utils/sls-test-utils.ts | 2 +- test-utils/snapshot-utils.ts | 4 +- 31 files changed, 959 insertions(+), 769 deletions(-) create mode 100644 core/inputs/config-types.ts diff --git a/cdk-test-project/source/general-stack.ts b/cdk-test-project/source/general-stack.ts index 706a1689..5db34168 100644 --- a/cdk-test-project/source/general-stack.ts +++ b/cdk-test-project/source/general-stack.ts @@ -55,10 +55,8 @@ export class CdkTestGeneralStack extends cdk.Stack { cfnFuncHello.cfnOptions.metadata = { slicWatch: { alarms: { - Lambda: { - Invocations: { - Threshold: 4 - } + Invocations: { + Threshold: 4 } } } diff --git a/cdk-test-project/source/sfn-stack.ts b/cdk-test-project/source/sfn-stack.ts index 3f0f252c..b35a537c 100644 --- a/cdk-test-project/source/sfn-stack.ts +++ b/cdk-test-project/source/sfn-stack.ts @@ -51,10 +51,8 @@ export class CdkSFNStack extends cdk.Stack { cfnFuncHello.cfnOptions.metadata = { slicWatch: { alarms: { - Lambda: { - Invocations: { - Threshold: 4 - } + Invocations: { + Threshold: 4 } } } diff --git a/core/alarms/alarm-utils.ts b/core/alarms/alarm-utils.ts index c66c7d47..524e3792 100644 --- a/core/alarms/alarm-utils.ts +++ b/core/alarms/alarm-utils.ts @@ -4,6 +4,7 @@ import { pascal } from 'case' import type { AlarmActionsConfig, AlarmTemplate, CloudFormationResources, OptionalAlarmProps, SlicWatchMergedConfig } from './alarm-types' import { getResourceAlarmConfigurationsByType } from '../cf-template' +import { type ConfigType } from '../inputs/config-types' /* * RegEx to filter out invalid CloudFormation Logical ID characters @@ -23,9 +24,9 @@ const LOGICAL_ID_FILTER_REGEX = /[^a-z0-9]/gi type SpecificAlarmPropertiesGeneratorFunction = (metric: string, resourceName: string, config: SlicWatchMergedConfig) => Omit /** - * Create CloudFormation 'AWS::CloudWatch::Alarm' resources based on metrics for a specfic resources type + * Create CloudFormation 'AWS::CloudWatch::Alarm' resources based on metrics for a specific resources type * - * @param type The resource CloudFormation type, e.g., `AWS::Lambda::Function` + * @param type The resource config type * @param service A human readable name for the service, e.g., 'Lambda' * @param metrics A list of metric names to use in the alarms * @param config The alarm configuration for this specific resource type @@ -36,7 +37,7 @@ type SpecificAlarmPropertiesGeneratorFunction = (metric: string, resourceName: s * @returns An object containing the alarm resources in CloudFormation syntax by logical ID */ export function createCfAlarms ( - type: string, service: string, metrics: string[], config: SlicWatchMergedConfig, alarmActionsConfig: AlarmActionsConfig, + type: ConfigType, service: string, metrics: string[], config: SlicWatchMergedConfig, alarmActionsConfig: AlarmActionsConfig, compiledTemplate: Template, genSpecificAlarmProps: SpecificAlarmPropertiesGeneratorFunction ): CloudFormationResources { const resources: CloudFormationResources = {} @@ -62,7 +63,7 @@ export function createCfAlarms ( } /** - * Create a CloudFormation Alarm resourc + * Create a CloudFormation Alarm resource * * @param alarmProperties The alarm configuration for this specific resource type * @param alarmActionsConfig Alarm actions diff --git a/core/alarms/alb-target-group.ts b/core/alarms/alb-target-group.ts index 6f25d4fc..3a4b0886 100644 --- a/core/alarms/alb-target-group.ts +++ b/core/alarms/alb-target-group.ts @@ -6,6 +6,7 @@ import type { AlarmActionsConfig, CloudFormationResources, InputOutput, SlicWatc import { createAlarm, getStatisticName, makeAlarmLogicalId } from './alarm-utils' import type { ResourceType } from '../cf-template' import { getResourceAlarmConfigurationsByType, getResourcesByType } from '../cf-template' +import { ConfigType } from '../inputs/config-types' export type SlicWatchAlbTargetAlarmsConfig = T & { HTTPCode_Target_5XX_Count: T @@ -128,7 +129,7 @@ function createAlbTargetCfAlarm ( export default function createAlbTargetAlarms ( albTargetAlarmsConfig: SlicWatchAlbTargetAlarmsConfig, alarmActionsConfig: AlarmActionsConfig, compiledTemplate: Template ): CloudFormationResources { - const resourceConfigs = getResourceAlarmConfigurationsByType('AWS::ElasticLoadBalancingV2::TargetGroup', compiledTemplate, albTargetAlarmsConfig) + const resourceConfigs = getResourceAlarmConfigurationsByType(ConfigType.ApplicationELBTarget, compiledTemplate, albTargetAlarmsConfig) const resources: CloudFormationResources = {} for (const [targetGroupLogicalId, targetGroupResource] of Object.entries(resourceConfigs.resources)) { const mergedConfig = resourceConfigs.alarmConfigurations[targetGroupLogicalId] diff --git a/core/alarms/alb.ts b/core/alarms/alb.ts index e5fefb47..5b6cabe8 100644 --- a/core/alarms/alb.ts +++ b/core/alarms/alb.ts @@ -4,6 +4,7 @@ import { Fn } from 'cloudform' import type { AlarmActionsConfig, CloudFormationResources, InputOutput, SlicWatchMergedConfig } from './alarm-types' import { createCfAlarms, getStatisticName } from './alarm-utils' +import { ConfigType } from '../inputs/config-types' export type SlicWatchAlbAlarmsConfig = T & { HTTPCode_ELB_5XX_Count: T @@ -43,7 +44,7 @@ export default function createAlbAlarms ( albAlarmsConfig: SlicWatchAlbAlarmsConfig, alarmActionsConfig: AlarmActionsConfig, compiledTemplate: Template ): CloudFormationResources { return createCfAlarms( - 'AWS::ElasticLoadBalancingV2::LoadBalancer', + ConfigType.ApplicationELB, 'LoadBalancer', executionMetrics, albAlarmsConfig, diff --git a/core/alarms/api-gateway.ts b/core/alarms/api-gateway.ts index f393b2ef..13e0938e 100644 --- a/core/alarms/api-gateway.ts +++ b/core/alarms/api-gateway.ts @@ -6,6 +6,7 @@ import { Fn } from 'cloudform' import type { AlarmActionsConfig, CloudFormationResources, InputOutput, SlicWatchMergedConfig } from './alarm-types' import { createAlarm, getStatisticName, makeAlarmLogicalId } from './alarm-utils' import { getResourceAlarmConfigurationsByType } from '../cf-template' +import { ConfigType } from '../inputs/config-types' export type SlicWatchApiGwAlarmsConfig = T & { '5XXError': T @@ -84,7 +85,7 @@ export default function createApiGatewayAlarms ( ): CloudFormationResources { const resources: CloudFormationResources = {} const configuredResources = getResourceAlarmConfigurationsByType( - 'AWS::ApiGateway::RestApi', compiledTemplate, apiGwAlarmsConfig + ConfigType.ApiGateway, compiledTemplate, apiGwAlarmsConfig ) for (const [apiLogicalId, apiResource] of Object.entries(configuredResources.resources)) { diff --git a/core/alarms/appsync.ts b/core/alarms/appsync.ts index 767141be..6cffb6bd 100644 --- a/core/alarms/appsync.ts +++ b/core/alarms/appsync.ts @@ -5,6 +5,7 @@ import { Fn } from 'cloudform' import type { AlarmActionsConfig, CloudFormationResources, InputOutput, SlicWatchMergedConfig } from './alarm-types' import { createAlarm, getStatisticName, makeAlarmLogicalId } from './alarm-utils' import { getResourceAlarmConfigurationsByType } from '../cf-template' +import { ConfigType } from '../inputs/config-types' export type SlicWatchAppSyncAlarmsConfig = T & { '5XXError': T @@ -27,7 +28,7 @@ export default function createAppSyncAlarms ( appSyncAlarmsConfig: SlicWatchAppSyncAlarmsConfig, alarmActionsConfig: AlarmActionsConfig, compiledTemplate: Template ): CloudFormationResources { const resources = {} - const configuredResources = getResourceAlarmConfigurationsByType('AWS::AppSync::GraphQLApi', compiledTemplate, appSyncAlarmsConfig) + const configuredResources = getResourceAlarmConfigurationsByType(ConfigType.AppSync, compiledTemplate, appSyncAlarmsConfig) for (const [appSyncLogicalId, appSyncResource] of Object.entries(configuredResources.resources)) { for (const metric of executionMetrics) { diff --git a/core/alarms/dynamodb.ts b/core/alarms/dynamodb.ts index 682295f9..416fe861 100644 --- a/core/alarms/dynamodb.ts +++ b/core/alarms/dynamodb.ts @@ -5,6 +5,7 @@ import { Fn } from 'cloudform' import type { AlarmActionsConfig, CloudFormationResources, InputOutput, SlicWatchMergedConfig } from './alarm-types' import { createAlarm, makeAlarmLogicalId } from './alarm-utils' import { getResourceAlarmConfigurationsByType } from '../cf-template' +import { ConfigType } from '../inputs/config-types' export type SlicWatchDynamoDbAlarmsConfig = T & { ReadThrottleEvents: T @@ -32,7 +33,7 @@ export default function createDynamoDbAlarms ( compiledTemplate: Template ): CloudFormationResources { const resources: CloudFormationResources = {} - const configuredResources = getResourceAlarmConfigurationsByType('AWS::DynamoDB::Table', compiledTemplate, dynamoDbAlarmsConfig) + const configuredResources = getResourceAlarmConfigurationsByType(ConfigType.DynamoDB, compiledTemplate, dynamoDbAlarmsConfig) for (const [tableLogicalId, tableResource] of Object.entries(configuredResources.resources)) { for (const metric of dynamoDbMetrics) { diff --git a/core/alarms/ecs.ts b/core/alarms/ecs.ts index 38bb8261..ad42212e 100644 --- a/core/alarms/ecs.ts +++ b/core/alarms/ecs.ts @@ -5,6 +5,7 @@ import { Fn } from 'cloudform' import type { AlarmActionsConfig, CloudFormationResources, InputOutput, SlicWatchMergedConfig } from './alarm-types' import { createAlarm } from './alarm-utils' import { getResourceAlarmConfigurationsByType } from '../cf-template' +import { ConfigType } from '../inputs/config-types' export type SlicWatchEcsAlarmsConfig = T & { MemoryUtilization: T @@ -49,7 +50,7 @@ export default function createECSAlarms ( ecsAlarmsConfig: SlicWatchEcsAlarmsConfig, alarmActionsConfig: AlarmActionsConfig, compiledTemplate: Template ): CloudFormationResources { const resources: CloudFormationResources = {} - const configuredResources = getResourceAlarmConfigurationsByType('AWS::ECS::Service', compiledTemplate, ecsAlarmsConfig) + const configuredResources = getResourceAlarmConfigurationsByType(ConfigType.ECS, compiledTemplate, ecsAlarmsConfig) for (const [serviceLogicalId, serviceResource] of Object.entries(configuredResources.resources)) { for (const metric of executionMetrics) { diff --git a/core/alarms/eventbridge.ts b/core/alarms/eventbridge.ts index 60e73e3e..8fcef5c9 100644 --- a/core/alarms/eventbridge.ts +++ b/core/alarms/eventbridge.ts @@ -3,6 +3,7 @@ import { Fn } from 'cloudform' import type { AlarmActionsConfig, CloudFormationResources, InputOutput, SlicWatchMergedConfig } from './alarm-types' import { createCfAlarms } from './alarm-utils' +import { ConfigType } from '../inputs/config-types' export type SlicWatchEventsAlarmsConfig = T & { FailedInvocations: T @@ -43,7 +44,7 @@ export default function createRuleAlarms ( eventsAlarmsConfig: SlicWatchEventsAlarmsConfig, alarmActionsConfig: AlarmActionsConfig, compiledTemplate: Template ): CloudFormationResources { return createCfAlarms( - 'AWS::Events::Rule', + ConfigType.Events, 'Events', executionMetrics, eventsAlarmsConfig, diff --git a/core/alarms/kinesis.ts b/core/alarms/kinesis.ts index a2a6b427..d55c8e48 100644 --- a/core/alarms/kinesis.ts +++ b/core/alarms/kinesis.ts @@ -6,6 +6,7 @@ import { pascal } from 'case' import { getResourceAlarmConfigurationsByType } from '../cf-template' import type { AlarmActionsConfig, CloudFormationResources, InputOutput, SlicWatchMergedConfig } from './alarm-types' import { createAlarm, getStatisticName, makeAlarmLogicalId } from './alarm-utils' +import { ConfigType } from '../inputs/config-types' export type SlicWatchKinesisAlarmsConfig = T & { 'GetRecords.IteratorAgeMilliseconds': T @@ -39,7 +40,7 @@ export default function createKinesisAlarms ( kinesisAlarmsConfig: SlicWatchKinesisAlarmsConfig, alarmActionsConfig: AlarmActionsConfig, compiledTemplate: Template ): CloudFormationResources { const resources: CloudFormationResources = {} - const configuredResources = getResourceAlarmConfigurationsByType('AWS::Kinesis::Stream', compiledTemplate, kinesisAlarmsConfig) + const configuredResources = getResourceAlarmConfigurationsByType(ConfigType.Kinesis, compiledTemplate, kinesisAlarmsConfig) for (const [streamLogicalId] of Object.entries(configuredResources.resources)) { for (const [type, metric] of Object.entries(kinesisAlarmTypes)) { diff --git a/core/alarms/lambda.ts b/core/alarms/lambda.ts index 08db913c..c183d0e2 100644 --- a/core/alarms/lambda.ts +++ b/core/alarms/lambda.ts @@ -5,6 +5,7 @@ import { Fn } from 'cloudform' import { getEventSourceMappingFunctions, getResourceAlarmConfigurationsByType } from '../cf-template' import type { AlarmActionsConfig, InputOutput, Value, SlicWatchMergedConfig } from './alarm-types' import { createAlarm } from './alarm-utils' +import { ConfigType } from '../inputs/config-types' export type SlicWatchLambdaAlarmsConfig = T & { Errors: T @@ -30,7 +31,7 @@ export default function createLambdaAlarms ( ) { const resources = {} - const configuredLambdaResources = getResourceAlarmConfigurationsByType('AWS::Lambda::Function', compiledTemplate, lambdaAlarmConfig) + const configuredLambdaResources = getResourceAlarmConfigurationsByType(ConfigType.Lambda, compiledTemplate, lambdaAlarmConfig) for (const [funcLogicalId, funcResource] of Object.entries(configuredLambdaResources.resources)) { const mergedConfig = configuredLambdaResources.alarmConfigurations[funcLogicalId] diff --git a/core/alarms/sns.ts b/core/alarms/sns.ts index 4160a0af..25c94f14 100644 --- a/core/alarms/sns.ts +++ b/core/alarms/sns.ts @@ -3,6 +3,7 @@ import { Fn } from 'cloudform' import type { AlarmActionsConfig, CloudFormationResources, InputOutput, SlicWatchMergedConfig } from './alarm-types' import { createCfAlarms } from './alarm-utils' +import { ConfigType } from '../inputs/config-types' export type SlicWatchSnsAlarmsConfig = T & { 'NumberOfNotificationsFilteredOut-InvalidAttributes': T @@ -41,7 +42,7 @@ export default function createSnsAlarms ( snsAlarmsConfig: SlicWatchSnsAlarmsConfig, alarmActionsConfig: AlarmActionsConfig, compiledTemplate: Template ): CloudFormationResources { return createCfAlarms( - 'AWS::SNS::Topic', + ConfigType.SNS, 'SNS', executionMetrics, snsAlarmsConfig, diff --git a/core/alarms/sqs.ts b/core/alarms/sqs.ts index c07e46a7..230e9a29 100644 --- a/core/alarms/sqs.ts +++ b/core/alarms/sqs.ts @@ -5,6 +5,7 @@ import { Fn } from 'cloudform' import type { AlarmActionsConfig, CloudFormationResources, InputOutput, SlicWatchMergedConfig } from './alarm-types' import { createAlarm } from './alarm-utils' import { getResourceAlarmConfigurationsByType } from '../cf-template' +import { ConfigType } from '../inputs/config-types' export type SlicWatchSqsAlarmsConfig = T & { InFlightMessagesPc: T @@ -25,7 +26,7 @@ export default function createSQSAlarms ( sqsAlarmsConfig: SlicWatchSqsAlarmsConfig, alarmActionsConfig: AlarmActionsConfig, compiledTemplate: Template ): CloudFormationResources { const resources: CloudFormationResources = {} - const configuredResources = getResourceAlarmConfigurationsByType('AWS::SQS::Queue', compiledTemplate, sqsAlarmsConfig) + const configuredResources = getResourceAlarmConfigurationsByType(ConfigType.SQS, compiledTemplate, sqsAlarmsConfig) for (const [queueLogicalId, queueResource] of Object.entries(configuredResources.resources)) { const mergedConfig = configuredResources.alarmConfigurations[queueLogicalId] diff --git a/core/alarms/step-functions.ts b/core/alarms/step-functions.ts index 1f775531..0243cd3e 100644 --- a/core/alarms/step-functions.ts +++ b/core/alarms/step-functions.ts @@ -3,6 +3,7 @@ import { Fn } from 'cloudform' import type { AlarmActionsConfig, CloudFormationResources, InputOutput, SlicWatchMergedConfig } from './alarm-types' import { createCfAlarms } from './alarm-utils' +import { ConfigType } from '../inputs/config-types' export type SlicWatchSfAlarmsConfig = T & { ExecutionThrottled: T @@ -43,7 +44,7 @@ export default function createStatesAlarms ( sfAlarmProperties: SlicWatchSfAlarmsConfig, alarmActionsConfig: AlarmActionsConfig, compiledTemplate: Template ): CloudFormationResources { return createCfAlarms( - 'AWS::StepFunctions::StateMachine', + ConfigType.States, 'States', executionMetrics, sfAlarmProperties, diff --git a/core/cf-template.ts b/core/cf-template.ts index 2eda0bb2..fb99ef7a 100644 --- a/core/cf-template.ts +++ b/core/cf-template.ts @@ -1,3 +1,5 @@ + +import { merge } from 'lodash' import type Resource from 'cloudform-types/types/resource' import type Template from 'cloudform-types/types/template' @@ -6,7 +8,8 @@ import { getLogger } from './logging' import { cascade } from './inputs/cascading-config' import { type SlicWatchMergedConfig } from './alarms/alarm-types' import { type WidgetMetricProperties } from './dashboards/dashboard-types' -import { merge } from 'lodash' +import { defaultConfig } from './inputs/default-config' +import { type ConfigType, cfTypeByConfigType } from './inputs/config-types' const logger = getLogger() @@ -55,18 +58,23 @@ export interface ResourceDashboardConfigurations ( - type: string, template: Template, config: M + type: ConfigType, template: Template, config: M ): ResourceAlarmConfigurations { const alarmConfigurations: Record = {} - const resources = getResourcesByType(type, template) + const resources = getResourcesByType(cfTypeByConfigType[type], template) for (const [funcLogicalId, resource] of Object.entries(resources)) { - alarmConfigurations[funcLogicalId] = merge({}, config, cascade(resource?.Metadata?.slicWatch?.alarms ?? {}) as M) + const resourceConfig = resource?.Metadata?.slicWatch?.alarms // Resource-specific overrides + const defaultResourceConfig = defaultConfig.alarms?.[type] // Default configuration for the type's alarms + // Cascade the default resource's configuration into the resource-specific overrides + const cascadedResourceConfig = resourceConfig !== undefined ? cascade(merge({}, defaultResourceConfig, resourceConfig)) : {} + // Lastly, cascade the full SLIC Watch config for any properties not yet set in the widget's config + alarmConfigurations[funcLogicalId] = cascade(merge({}, config, cascadedResourceConfig)) as M } return { resources, @@ -78,18 +86,23 @@ export function getResourceAlarmConfigurationsByType ( - type: string, template: Template, config: T + type: ConfigType, template: Template, config: T ): ResourceDashboardConfigurations { const dashConfigurations: Record = {} - const resources = getResourcesByType(type, template) + const resources = getResourcesByType(cfTypeByConfigType[type], template) for (const [logicalId, resource] of Object.entries(resources)) { - dashConfigurations[logicalId] = cascade(merge({}, config, cascade(resource?.Metadata?.slicWatch?.dashboard ?? {}))) as T + const resourceConfig = resource?.Metadata?.slicWatch?.dashboard // Resource-specific overrides + const defaultResourceConfig = defaultConfig.dashboard?.widgets?.[type] // Default configuration for the widget + // Cascade the default resource's configuration into the resource-specific overrides + const cascadedResourceConfig = resourceConfig !== undefined ? cascade(merge({}, defaultResourceConfig, resourceConfig)) : {} + // Lastly, cascade the full SLIC Watch config for any properties not yet set in the widget's config + dashConfigurations[logicalId] = cascade(merge({}, config, cascadedResourceConfig)) as T } return { resources, diff --git a/core/dashboards/dashboard-types.ts b/core/dashboards/dashboard-types.ts index 4a9454f5..52004608 100644 --- a/core/dashboards/dashboard-types.ts +++ b/core/dashboards/dashboard-types.ts @@ -1,4 +1,5 @@ import type { Widget } from 'cloudwatch-dashboard-types' +import { type ConfigType } from '../inputs/config-types' export type YAxisPos = 'left' | 'right' @@ -30,18 +31,18 @@ export interface WidgetMetricProperties { } export interface Widgets extends WidgetMetricProperties { - Lambda: LambdaDashboardProperties - ApiGateway: ApiGwDashboardProperties - States: SfDashboardProperties - DynamoDB: DynamoDbDashboardProperties - Kinesis: KinesisDashboardProperties - SQS: SqsDashboardProperties - ECS: EcsDashboardProperties - SNS: SnsDashboardProperties - Events: RuleDashboardProperties - ApplicationELB: AlbDashboardProperties - ApplicationELBTarget: AlbTargetDashboardProperties - AppSync: AppSyncDashboardProperties + [ConfigType.Lambda]: LambdaDashboardProperties + [ConfigType.ApiGateway]: ApiGwDashboardProperties + [ConfigType.States]: SfDashboardProperties + [ConfigType.DynamoDB]: DynamoDbDashboardProperties + [ConfigType.Kinesis]: KinesisDashboardProperties + [ConfigType.SQS]: SqsDashboardProperties + [ConfigType.ECS]: EcsDashboardProperties + [ConfigType.SNS]: SnsDashboardProperties + [ConfigType.Events]: RuleDashboardProperties + [ConfigType.ApplicationELB]: AlbDashboardProperties + [ConfigType.ApplicationELBTarget]: AlbTargetDashboardProperties + [ConfigType.AppSync]: AppSyncDashboardProperties } type NestedPartial = { diff --git a/core/dashboards/dashboard.ts b/core/dashboards/dashboard.ts index 96814bc3..4eec8caa 100644 --- a/core/dashboards/dashboard.ts +++ b/core/dashboards/dashboard.ts @@ -4,8 +4,7 @@ import { type Dashboard, type WidgetMetric, type Statistic, type YAxisPosition } import { cascade } from '../inputs/cascading-config' import { getEventSourceMappingFunctions, addResource, getResourceDashboardConfigurationsByType } from '../cf-template' import type { - WidgetMetricProperties, MetricDefs, SlicWatchDashboardConfig, SlicWatchInputDashboardConfig, - Widgets, WidgetWithSize + WidgetMetricProperties, MetricDefs, SlicWatchDashboardConfig, SlicWatchInputDashboardConfig, WidgetWithSize } from './dashboard-types' import { findLoadBalancersForTargetGroup } from '../alarms/alb-target-group' @@ -15,6 +14,7 @@ import { resolveLoadBalancerFullNameForSub, resolveTargetGroupFullNameForSub } from './dashboard-utils' import { getLogger } from '../logging' +import { ConfigType } from '../inputs/config-types' const MAX_WIDTH = 24 @@ -130,7 +130,7 @@ export default function addDashboard (dashboardConfig: SlicWatchInputDashboardCo * @return * Object with CloudFormation Lambda Function resources by resource name */ function createLambdaWidgets (): WidgetWithSize[] { - const configuredResources = getResourceDashboardConfigurationsByType('AWS::Lambda::Function', compiledTemplate, lambdaDashConfig) + const configuredResources = getResourceDashboardConfigurationsByType(ConfigType.Lambda, compiledTemplate, lambdaDashConfig) const eventSourceMappingFunctions = getEventSourceMappingFunctions(compiledTemplate) const lambdaWidgets: any = [] @@ -142,14 +142,14 @@ export default function addDashboard (dashboardConfig: SlicWatchInputDashboardCo const metricDefs: MetricDefs[] = [] for (const funcLogicalId of Object.keys(configuredResources.resources)) { const funcConfig = configuredResources.dashConfigurations[funcLogicalId] - const metricConfig = funcConfig[metric] - if (metricConfig.enabled !== false) { + const functionMetricConfig = funcConfig[metric] + if (functionMetricConfig.enabled !== false) { metricDefs.push({ namespace: 'AWS/Lambda', metric, dimensions: { FunctionName: `\${${funcLogicalId}}` }, stat, - yAxis: metricConfig.yAxis + yAxis: functionMetricConfig.yAxis }) } } @@ -158,7 +158,7 @@ export default function addDashboard (dashboardConfig: SlicWatchInputDashboardCo const metricStatWidget = createMetricWidget( `Lambda ${metric} ${stat} per Function`, metricDefs, - metricConfig as Widgets + metricConfig ) lambdaWidgets.push(metricStatWidget) } @@ -178,9 +178,9 @@ export default function addDashboard (dashboardConfig: SlicWatchInputDashboardCo metric: 'IteratorAge', dimensions: { FunctionName: `\${${funcLogicalId}}` }, stat: stat as Statistic, - yAxis: metricConfig.yAxis + yAxis: functionMetricConfig.yAxis })), - metricConfig as Widgets + functionMetricConfig ) lambdaWidgets.push(iteratorAgeWidget) } @@ -213,7 +213,7 @@ export default function addDashboard (dashboardConfig: SlicWatchInputDashboardCo */ function createApiWidgets (): WidgetWithSize[] { - const configuredResources = getResourceDashboardConfigurationsByType('AWS::ApiGateway::RestApi', compiledTemplate, apiGwDashConfig) + const configuredResources = getResourceDashboardConfigurationsByType(ConfigType.ApiGateway, compiledTemplate, apiGwDashConfig) const apiWidgets: WidgetWithSize[] = [] for (const [logicalId, res] of Object.entries(configuredResources.resources)) { const apiName: string = resolveRestApiNameForSub(res, logicalId) // e.g., ${AWS::Stack} (Ref), ${OtherResource.Name} (GetAtt) @@ -253,9 +253,9 @@ export default function addDashboard (dashboardConfig: SlicWatchInputDashboardCo * Object of Step Function State Machine resources by resource name */ function createStateMachineWidgets (): WidgetWithSize[] { - const stateMachineResources = getResourceDashboardConfigurationsByType('AWS::StepFunctions::StateMachine', compiledTemplate, sfDashConfig) + const stateMachineResources = getResourceDashboardConfigurationsByType(ConfigType.States, compiledTemplate, sfDashConfig) const smWidgets: WidgetWithSize[] = [] - for (const [logicalId] of Object.entries(stateMachineResources.resources)) { + for (const logicalId of Object.keys(stateMachineResources.resources)) { const mergedConfig = stateMachineResources.dashConfigurations[logicalId] const widgetMetrics: MetricDefs[] = [] for (const [metric, metricConfig] of Object.entries(getConfiguredMetrics(mergedConfig))) { @@ -291,7 +291,7 @@ export default function addDashboard (dashboardConfig: SlicWatchInputDashboardCo * Object of DynamoDB table resources by resource name */ function createDynamoDbWidgets (): WidgetWithSize[] { - const configuredResources = getResourceDashboardConfigurationsByType('AWS::DynamoDB::Table', compiledTemplate, dynamoDbDashConfig) + const configuredResources = getResourceDashboardConfigurationsByType(ConfigType.DynamoDB, compiledTemplate, dynamoDbDashConfig) const ddbWidgets: WidgetWithSize[] = [] for (const [logicalId, res] of Object.entries(configuredResources.resources)) { const mergedConfig = configuredResources.dashConfigurations[logicalId] @@ -353,7 +353,7 @@ export default function addDashboard (dashboardConfig: SlicWatchInputDashboardCo * Object with CloudFormation Kinesis Data Stream resources by resource name */ function createStreamWidgets (): WidgetWithSize[] { - const configuredResources = getResourceDashboardConfigurationsByType('AWS::Kinesis::Stream', compiledTemplate, kinesisDashConfig) + const configuredResources = getResourceDashboardConfigurationsByType(ConfigType.Kinesis, compiledTemplate, kinesisDashConfig) const streamWidgets: WidgetWithSize[] = [] const metricGroups = { @@ -397,7 +397,7 @@ export default function addDashboard (dashboardConfig: SlicWatchInputDashboardCo * Object with CloudFormation SQS resources by resource name */ function createQueueWidgets (): WidgetWithSize[] { - const configuredResources = getResourceDashboardConfigurationsByType('AWS::SQS::Queue', compiledTemplate, sqsDashConfig) + const configuredResources = getResourceDashboardConfigurationsByType(ConfigType.SQS, compiledTemplate, sqsDashConfig) const queueWidgets: WidgetWithSize[] = [] const metricGroups = { @@ -444,7 +444,7 @@ export default function addDashboard (dashboardConfig: SlicWatchInputDashboardCo * Object of ECS Service resources by resource name */ function createEcsWidgets (): WidgetWithSize[] { - const configuredResources = getResourceDashboardConfigurationsByType('AWS::ECS::Service', compiledTemplate, ecsDashConfig) + const configuredResources = getResourceDashboardConfigurationsByType(ConfigType.ECS, compiledTemplate, ecsDashConfig) const ecsWidgets: WidgetWithSize[] = [] for (const [logicalId, res] of Object.entries(configuredResources.resources)) { const clusterName = resolveEcsClusterNameForSub(res.Properties?.Cluster) @@ -483,7 +483,7 @@ export default function addDashboard (dashboardConfig: SlicWatchInputDashboardCo */ function createTopicWidgets (): WidgetWithSize[] { const configuredResources = getResourceDashboardConfigurationsByType( - 'AWS::SNS::Topic', compiledTemplate, snsDashConfig + ConfigType.SNS, compiledTemplate, snsDashConfig ) const topicWidgets: WidgetWithSize[] = [] for (const logicalId of Object.keys(configuredResources.resources)) { @@ -522,7 +522,7 @@ export default function addDashboard (dashboardConfig: SlicWatchInputDashboardCo * Object of EventBridge Service resources by resource name */ function createRuleWidgets (): WidgetWithSize[] { - const configuredResources = getResourceDashboardConfigurationsByType('AWS::Events::Rule', compiledTemplate, ruleDashConfig) + const configuredResources = getResourceDashboardConfigurationsByType(ConfigType.Events, compiledTemplate, ruleDashConfig) const ruleWidgets: WidgetWithSize[] = [] for (const [logicalId] of Object.entries(configuredResources.resources)) { const widgetMetrics: MetricDefs[] = [] @@ -556,7 +556,7 @@ export default function addDashboard (dashboardConfig: SlicWatchInputDashboardCo * Create a set of CloudWatch Dashboard widgets for Application Load Balancer services. */ function createLoadBalancerWidgets (): WidgetWithSize[] { - const configuredResources = getResourceDashboardConfigurationsByType('AWS::ElasticLoadBalancingV2::LoadBalancer', compiledTemplate, albDashConfig) + const configuredResources = getResourceDashboardConfigurationsByType(ConfigType.ApplicationELB, compiledTemplate, albDashConfig) const loadBalancerWidgets: WidgetWithSize[] = [] for (const [logicalId] of Object.entries(configuredResources.resources)) { const loadBalancerName = `\${${logicalId}.LoadBalancerName}` @@ -598,7 +598,7 @@ export default function addDashboard (dashboardConfig: SlicWatchInputDashboardCo * The full CloudFormation template instance used to look up associated listener and ALB resources */ function createTargetGroupWidgets (): WidgetWithSize[] { - const configuredResources = getResourceDashboardConfigurationsByType('AWS::ElasticLoadBalancingV2::TargetGroup', compiledTemplate, albTargetDashConfig) + const configuredResources = getResourceDashboardConfigurationsByType(ConfigType.ApplicationELBTarget, compiledTemplate, albTargetDashConfig) const targetGroupWidgets: WidgetWithSize[] = [] for (const [tgLogicalId, targetGroupResource] of Object.entries(configuredResources.resources)) { @@ -645,7 +645,7 @@ export default function addDashboard (dashboardConfig: SlicWatchInputDashboardCo * Object of AppSync Service resources by resource name */ function createAppSyncWidgets (): WidgetWithSize[] { - const configuredResources = getResourceDashboardConfigurationsByType('AWS::AppSync::GraphQLApi', compiledTemplate, appSyncDashConfig) + const configuredResources = getResourceDashboardConfigurationsByType(ConfigType.AppSync, compiledTemplate, appSyncDashConfig) const appSyncWidgets: WidgetWithSize[] = [] const metricGroups = { diff --git a/core/inputs/cascading-config.ts b/core/inputs/cascading-config.ts index 8f48f772..cfd0e028 100644 --- a/core/inputs/cascading-config.ts +++ b/core/inputs/cascading-config.ts @@ -4,10 +4,10 @@ const MAX_DEPTH = 10 * Accept an object configuration with multiple levels. Return an applied version of this object * with default parameters from parent nodes cascaded to child objects where no override is present. * - * node hierarchical configuration - * parentNode The configuration from the parent node to be applied to the current node where no conflict occurs + * @param node hierarchical configuration + * @param parentNode The configuration from the parent node to be applied to the current node where no conflict occurs */ -export function cascade (node: object, parentNode?: object, depth = 0): object { +export function cascade (node: object, parentNode: object = {}, depth = 0): object { if (depth > 10) { throw new Error(`Maximum configuration depth of ${MAX_DEPTH} reached`) } diff --git a/core/inputs/config-types.ts b/core/inputs/config-types.ts new file mode 100644 index 00000000..d94d0ac1 --- /dev/null +++ b/core/inputs/config-types.ts @@ -0,0 +1,33 @@ +export enum ConfigType { + Lambda = 'Lambda', + ApiGateway = 'ApiGateway', + States = 'States', + DynamoDB = 'DynamoDB', + Kinesis = 'Kinesis', + SQS = 'SQS', + ECS = 'ECS', + SNS = 'SNS', + Events = 'Events', + ApplicationELB = 'ApplicationELB', + ApplicationELBTarget = 'ApplicationELBTarget', + AppSync = 'AppSync' +} + +export const cfTypeByConfigType = { + [ConfigType.Lambda]: 'AWS::Lambda::Function', + [ConfigType.ApiGateway]: 'AWS::ApiGateway::RestApi', + [ConfigType.States]: 'AWS::StepFunctions::StateMachine', + [ConfigType.DynamoDB]: 'AWS::DynamoDB::Table', + [ConfigType.Kinesis]: 'AWS::Kinesis::Stream', + [ConfigType.SQS]: 'AWS::SQS::Queue', + [ConfigType.ECS]: 'AWS::ECS::Service', + [ConfigType.SNS]: 'AWS::SNS::Topic', + [ConfigType.Events]: 'AWS::Events::Rule', + [ConfigType.ApplicationELB]: 'AWS::ElasticLoadBalancingV2::LoadBalancer', + [ConfigType.ApplicationELBTarget]: 'AWS::ElasticLoadBalancingV2::TargetGroup', + [ConfigType.AppSync]: 'AWS::AppSync::GraphQLApi' +} + +export const configTypesByCfType = Object.fromEntries(Object.entries(cfTypeByConfigType).map( + ([configType, cfType]) => [cfType, configType] as [string, ConfigType] +)) diff --git a/package.json b/package.json index 98113605..cc0038b3 100644 --- a/package.json +++ b/package.json @@ -24,11 +24,11 @@ "build": "npm run build -w core && npm run build -w cf-macro && npm run build -w serverless-plugin", "lint": "eslint .", "lintfix": "eslint --cache --fix .", - "test:packages": "DEBUG_LEVEL=info tap --include='**/tests/**/*.ts' --coverage-report=lcovonly --allow-incomplete-coverage", + "test:packages": "DEBUG_LEVEL=info tap --include='**/tests/**/*.ts' --exclude='**/tests/**/*snapshot.test.ts' --coverage-report=lcovonly --allow-incomplete-coverage", "test:snapshots": "DEBUG_LEVEL=info tap --include='**/tests/**/*snapshot.test.ts' --coverage-report=lcovonly --allow-incomplete-coverage", "test:snapshots:generate": "TAP_SNAPSHOT=1 npm run test:snapshots", "test:report": "tap report html", - "test": "npm run lint && npm run test:packages", + "test": "npm run lint && npm run test:packages && npm run test:snapshots", "prepare": "test ! -d '.git' || is-ci || husky install", "version": "npm version $npm_package_version --workspaces && ./scripts/sync-macro-version.cjs && git add **/package.json cf-macro/template.yaml" }, diff --git a/serverless-test-project-alb/serverless.yml b/serverless-test-project-alb/serverless.yml index 260bc535..d17c8d29 100644 --- a/serverless-test-project-alb/serverless.yml +++ b/serverless-test-project-alb/serverless.yml @@ -52,7 +52,7 @@ functions: path: /handleALB method: - POST - healthCheck: true # it is by default false but can be enbaled true + healthCheck: true # it is by default false but can be enabled true #you can disable it for not getting redundant health-check logs on the CloudWatch logs resources: ${file(./sls-resources.yml)} diff --git a/serverless-test-project-alb/sls-resources.yml b/serverless-test-project-alb/sls-resources.yml index de7e3540..b74ca43c 100644 --- a/serverless-test-project-alb/sls-resources.yml +++ b/serverless-test-project-alb/sls-resources.yml @@ -99,7 +99,7 @@ Resources: - Type: redirect RedirectConfig: Protocol: HTTP - Port: 400 + Port: '400' Host: "#{host}" Path: "/#{path}" Query: "#{query}" diff --git a/serverless-test-project/sls-resources.yml b/serverless-test-project/sls-resources.yml index 78980caf..f2d73717 100644 --- a/serverless-test-project/sls-resources.yml +++ b/serverless-test-project/sls-resources.yml @@ -28,7 +28,7 @@ Resources: - AttributeName: gsi1sk AttributeType: S - AttributeName: timestamp - AttributeType: N + AttributeType: 'N' KeySchema: - AttributeName: pk KeyType: HASH @@ -121,8 +121,8 @@ Resources: Properties: RequiresCompatibilities: - FARGATE - Cpu: 256 - Memory: 512 + Cpu: '256' + Memory: '512' ContainerDefinitions: - Name: "busybox" Image: "busybox" diff --git a/tap-snapshots/cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts.test.cjs b/tap-snapshots/cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts.test.cjs index 75170058..0e5ea6fb 100644 --- a/tap-snapshots/cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts.test.cjs +++ b/tap-snapshots/cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts.test.cjs @@ -70,7 +70,7 @@ exports[`cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts > TAP "aws:cdk:path": "CdkECSStackTest-Europe/CDKMetadata/Default" }, "Properties": { - "Analytics": "v2:deflate64:H4sIAAAAAAAA/31Ry27CMBD8Fu7GbTlUXCmlCAm1UYK4IsfZpgvBjux1EIry73WepLSqFGlnx+PsembG58/8cSIudiqT0zTDmJcRCXlinjqUIO0hF0RglOWLPM9QCkKttlokLyITSkLyJkwqCCIwBUpgkAlLKDOviBsFqrSY8fLv24YtP3/2Yx1aAtVpejw63/nJQGujXV5LRm3FQPqZEUhnkK6D5H9ilRqw9he9US2/z2V9tg+WLHCxXyJysQJq9AMKtSPYiTiDG3/jFtZqic3yg7gGq01Ql3dBa2/lRVxZYLCoXR1+vFF1CjAI2k26bkE+s68zKKpfbnnZhbIT9vQKn6iwH3nPaEUCva8j7i7Qxo4OZs6n0OTRwYqhOPMy1O17mxpo702zYIsqlunU77TV6eB7j6uq7j4c5Y5YCFY7047sccWUToAf7UPxNOf+m02OFnFqnCI8Aw/b+g3+NWTOyAIAAA==" + "Analytics": "v2:deflate64:H4sIAAAAAAAA/31RTU8CMRD9LdxLRQ7GKyISEqMbIF7JbHdcR0q76UwhZrP/3ewHy4rG07x589r5eFN9f6cnIzjx2GT7saVUlxsBs1dw4l2JhncFiGBwrGdFYcmAkHfPHrIHsOAMZk8QchDcYDiSQYUWWMhYD1naKMjlx6ku/34d1Pz9Zz7UEQu6TnPGg/oWQo6yDD4WtWSQVgrNVJcbNDGQfPWS/4lFHpD5F71yLf9WmLr2lsxVElNLZhNTh9Loe7T2UXALqcULf+FmzN5QM3wvrsFildThBWQJgif4UkmgY33V/uOVq13AXtBO0mUzETAfB3RSb8667EzZAu8f8Z0cnVteM94JkMMw4K4Mbc7RQRtZWj86WCmCgy7Xvt23iYm3ZJoBW1Qp63PW5bPP+7ufcVXV2WuUIopaI/sY2pZnXCnnM9SffHOcTvTtRE9Gn0w0DtEJHVCv2/gNbRFl8sgCAAA=" }, "Type": "AWS::CDK::Metadata" }, @@ -917,7 +917,8 @@ exports[`cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts > TAP "ClusterName", "\${EcsDefaultClusterMnL3mNNYN926A5246}", { - "stat": "Average" + "stat": "Average", + "yAxis": "left" } ], [ @@ -928,7 +929,8 @@ exports[`cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts > TAP "ClusterName", "\${EcsDefaultClusterMnL3mNNYN926A5246}", { - "stat": "Average" + "stat": "Average", + "yAxis": "left" } ] ], @@ -952,7 +954,8 @@ exports[`cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts > TAP "LoadBalancer", "\${MyWebServerLB3B5FD3AB.LoadBalancerFullName}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ], [ @@ -961,7 +964,8 @@ exports[`cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts > TAP "LoadBalancer", "\${MyWebServerLB3B5FD3AB.LoadBalancerFullName}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ] ], @@ -987,7 +991,8 @@ exports[`cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts > TAP "TargetGroup", "\${MyWebServerLBPublicListenerECSGroup5AB9F1C3.TargetGroupFullName}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ], [ @@ -998,7 +1003,8 @@ exports[`cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts > TAP "TargetGroup", "\${MyWebServerLBPublicListenerECSGroup5AB9F1C3.TargetGroupFullName}", { - "stat": "Average" + "stat": "Average", + "yAxis": "left" } ] ], @@ -1345,7 +1351,7 @@ exports[`cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts > TAP "aws:cdk:path": "CdkGeneralStackTest-Europe/CDKMetadata/Default" }, "Properties": { - "Analytics": "v2:deflate64:H4sIAAAAAAAA/02Q30/DIBDH/5a9M9SZmL12Gp801rr3hdKzshaoPdhsGv53D5izCeE+9z24Xxu+feC3K3HGtWy6da9qPn84ITtG0mFGg3ze20FJ9vhpEgTWC103gs/P3kinrImhJZcwaoVIXmBKaD5XtocYiDYwvD8IRHDIi2jI5zsvO3A7gcDEoFrh4CwmPr+kQhWgKwaVEvxjIaX1xrEnGHo7aSAkdeHRFG2qmoG+Wj9KSEXK0f5Mf8olceZXcF+2iVKmwJrJCG0b2ste1HmOBIHBierQfip/Gc+n8b5Jevfgk5Yh3aXtlZyuYnZDuHbG0jpit8q08dmbd4N3y/YCM7YBfsSb092W09msjqjUeqRNKA28yvYXs0P/r9UBAAA=" + "Analytics": "v2:deflate64:H4sIAAAAAAAA/02QTU/DMAyGf8vumSmbhLhuIE4gRrf75KamZGuTUjsbVZT/jpKOsUvex68jfy3g8QGKGZ55ruvjvDUVhK2gPio88z6wZQg71xutnj5thqha7KoaIbx4q8U4m1K3vKGhM8zG2agMdhBK11JKJI2Kl3tkJmFYJVG8hLXXR5I1MinsTYNCZxwhvOZGJbGsepML/ONKa+etqGfqWzd2ZCW5N9FWsMldJyiJnR805Sabwf2Mf86l8MRvJF+uTtZEUdWjxc7VFYQdVtMeGaKiE1lhCKW/rOfzet8M4cOTz94E+d241ujxak5hjNfJVD5HmtbYJn1799J7uR0vKutqggPfnRYF3BdQzA5szHzwVkxHUE76CyBn/pPVAQAA" }, "Type": "AWS::CDK::Metadata" }, @@ -1592,10 +1598,8 @@ exports[`cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts > TAP "Metadata": { "slicWatch": { "alarms": { - "Lambda": { - "Invocations": { - "Threshold": 4 - } + "Invocations": { + "Threshold": 4 } } } @@ -2260,7 +2264,8 @@ exports[`cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts > TAP "ApiName", "myapi", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ] ], @@ -2278,22 +2283,14 @@ exports[`cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts > TAP "type": "metric", "properties": { "metrics": [ - [ - "AWS/ApiGateway", - "5XXError", - "ApiName", - "myapi", - { - "stat": "Sum" - } - ], [ "AWS/ApiGateway", "4XXError", "ApiName", "myapi", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ] ], @@ -2311,31 +2308,14 @@ exports[`cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts > TAP "type": "metric", "properties": { "metrics": [ - [ - "AWS/ApiGateway", - "5XXError", - "ApiName", - "myapi", - { - "stat": "Sum" - } - ], - [ - "AWS/ApiGateway", - "4XXError", - "ApiName", - "myapi", - { - "stat": "Sum" - } - ], [ "AWS/ApiGateway", "Latency", "ApiName", "myapi", { - "stat": "Average" + "stat": "Average", + "yAxis": "left" } ], [ @@ -2344,7 +2324,8 @@ exports[`cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts > TAP "ApiName", "myapi", { - "stat": "p95" + "stat": "p95", + "yAxis": "left" } ] ], @@ -2362,49 +2343,14 @@ exports[`cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts > TAP "type": "metric", "properties": { "metrics": [ - [ - "AWS/ApiGateway", - "5XXError", - "ApiName", - "myapi", - { - "stat": "Sum" - } - ], - [ - "AWS/ApiGateway", - "4XXError", - "ApiName", - "myapi", - { - "stat": "Sum" - } - ], - [ - "AWS/ApiGateway", - "Latency", - "ApiName", - "myapi", - { - "stat": "Average" - } - ], - [ - "AWS/ApiGateway", - "Latency", - "ApiName", - "myapi", - { - "stat": "p95" - } - ], [ "AWS/ApiGateway", "Count", "ApiName", "myapi", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ] ], @@ -2428,7 +2374,8 @@ exports[`cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts > TAP "TableName", "\${TableCD117FA1}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ] ], @@ -2446,22 +2393,14 @@ exports[`cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts > TAP "type": "metric", "properties": { "metrics": [ - [ - "AWS/DynamoDB", - "ReadThrottleEvents", - "TableName", - "\${TableCD117FA1}", - { - "stat": "Sum" - } - ], [ "AWS/DynamoDB", "WriteThrottleEvents", "TableName", "\${TableCD117FA1}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ] ], @@ -2485,7 +2424,8 @@ exports[`cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts > TAP "FunctionName", "\${HelloHandler2E4FBA4D}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ], [ @@ -2494,7 +2434,8 @@ exports[`cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts > TAP "FunctionName", "\${ThrottlerHandler750A7C89}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ], [ @@ -2503,7 +2444,8 @@ exports[`cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts > TAP "FunctionName", "\${DriveStreamHandler62F1767B}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ], [ @@ -2512,7 +2454,8 @@ exports[`cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts > TAP "FunctionName", "\${DriveQueueHandler9F657A00}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ], [ @@ -2521,7 +2464,8 @@ exports[`cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts > TAP "FunctionName", "\${DriveTableHandler119966B0}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ] ], @@ -2545,7 +2489,8 @@ exports[`cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts > TAP "FunctionName", "\${HelloHandler2E4FBA4D}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ], [ @@ -2554,7 +2499,8 @@ exports[`cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts > TAP "FunctionName", "\${ThrottlerHandler750A7C89}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ], [ @@ -2563,7 +2509,8 @@ exports[`cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts > TAP "FunctionName", "\${DriveStreamHandler62F1767B}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ], [ @@ -2572,7 +2519,8 @@ exports[`cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts > TAP "FunctionName", "\${DriveQueueHandler9F657A00}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ], [ @@ -2581,7 +2529,8 @@ exports[`cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts > TAP "FunctionName", "\${DriveTableHandler119966B0}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ] ], @@ -2605,7 +2554,8 @@ exports[`cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts > TAP "FunctionName", "\${HelloHandler2E4FBA4D}", { - "stat": "Average" + "stat": "Average", + "yAxis": "left" } ], [ @@ -2614,7 +2564,8 @@ exports[`cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts > TAP "FunctionName", "\${ThrottlerHandler750A7C89}", { - "stat": "Average" + "stat": "Average", + "yAxis": "left" } ], [ @@ -2623,7 +2574,8 @@ exports[`cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts > TAP "FunctionName", "\${DriveStreamHandler62F1767B}", { - "stat": "Average" + "stat": "Average", + "yAxis": "left" } ], [ @@ -2632,7 +2584,8 @@ exports[`cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts > TAP "FunctionName", "\${DriveQueueHandler9F657A00}", { - "stat": "Average" + "stat": "Average", + "yAxis": "left" } ], [ @@ -2641,7 +2594,8 @@ exports[`cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts > TAP "FunctionName", "\${DriveTableHandler119966B0}", { - "stat": "Average" + "stat": "Average", + "yAxis": "left" } ] ], @@ -2665,7 +2619,8 @@ exports[`cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts > TAP "FunctionName", "\${HelloHandler2E4FBA4D}", { - "stat": "p95" + "stat": "p95", + "yAxis": "left" } ], [ @@ -2674,7 +2629,8 @@ exports[`cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts > TAP "FunctionName", "\${ThrottlerHandler750A7C89}", { - "stat": "p95" + "stat": "p95", + "yAxis": "left" } ], [ @@ -2683,7 +2639,8 @@ exports[`cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts > TAP "FunctionName", "\${DriveStreamHandler62F1767B}", { - "stat": "p95" + "stat": "p95", + "yAxis": "left" } ], [ @@ -2692,7 +2649,8 @@ exports[`cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts > TAP "FunctionName", "\${DriveQueueHandler9F657A00}", { - "stat": "p95" + "stat": "p95", + "yAxis": "left" } ], [ @@ -2701,7 +2659,8 @@ exports[`cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts > TAP "FunctionName", "\${DriveTableHandler119966B0}", { - "stat": "p95" + "stat": "p95", + "yAxis": "left" } ] ], @@ -2725,7 +2684,8 @@ exports[`cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts > TAP "FunctionName", "\${HelloHandler2E4FBA4D}", { - "stat": "Maximum" + "stat": "Maximum", + "yAxis": "left" } ], [ @@ -2734,7 +2694,8 @@ exports[`cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts > TAP "FunctionName", "\${ThrottlerHandler750A7C89}", { - "stat": "Maximum" + "stat": "Maximum", + "yAxis": "left" } ], [ @@ -2743,7 +2704,8 @@ exports[`cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts > TAP "FunctionName", "\${DriveStreamHandler62F1767B}", { - "stat": "Maximum" + "stat": "Maximum", + "yAxis": "left" } ], [ @@ -2752,7 +2714,8 @@ exports[`cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts > TAP "FunctionName", "\${DriveQueueHandler9F657A00}", { - "stat": "Maximum" + "stat": "Maximum", + "yAxis": "left" } ], [ @@ -2761,7 +2724,8 @@ exports[`cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts > TAP "FunctionName", "\${DriveTableHandler119966B0}", { - "stat": "Maximum" + "stat": "Maximum", + "yAxis": "left" } ] ], @@ -2785,7 +2749,8 @@ exports[`cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts > TAP "FunctionName", "\${HelloHandler2E4FBA4D}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ], [ @@ -2794,7 +2759,8 @@ exports[`cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts > TAP "FunctionName", "\${ThrottlerHandler750A7C89}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ], [ @@ -2803,7 +2769,8 @@ exports[`cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts > TAP "FunctionName", "\${DriveStreamHandler62F1767B}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ], [ @@ -2812,7 +2779,8 @@ exports[`cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts > TAP "FunctionName", "\${DriveQueueHandler9F657A00}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ], [ @@ -2821,7 +2789,8 @@ exports[`cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts > TAP "FunctionName", "\${DriveTableHandler119966B0}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ] ], @@ -2845,7 +2814,8 @@ exports[`cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts > TAP "FunctionName", "\${HelloHandler2E4FBA4D}", { - "stat": "Maximum" + "stat": "Maximum", + "yAxis": "left" } ], [ @@ -2854,7 +2824,8 @@ exports[`cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts > TAP "FunctionName", "\${ThrottlerHandler750A7C89}", { - "stat": "Maximum" + "stat": "Maximum", + "yAxis": "left" } ], [ @@ -2863,7 +2834,8 @@ exports[`cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts > TAP "FunctionName", "\${DriveStreamHandler62F1767B}", { - "stat": "Maximum" + "stat": "Maximum", + "yAxis": "left" } ], [ @@ -2872,7 +2844,8 @@ exports[`cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts > TAP "FunctionName", "\${DriveQueueHandler9F657A00}", { - "stat": "Maximum" + "stat": "Maximum", + "yAxis": "left" } ], [ @@ -2881,7 +2854,8 @@ exports[`cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts > TAP "FunctionName", "\${DriveTableHandler119966B0}", { - "stat": "Maximum" + "stat": "Maximum", + "yAxis": "left" } ] ], @@ -2905,7 +2879,8 @@ exports[`cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts > TAP "QueueName", "\${DeadLetterQueue9F481546.QueueName}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ], [ @@ -2914,7 +2889,8 @@ exports[`cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts > TAP "QueueName", "\${DeadLetterQueue9F481546.QueueName}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ], [ @@ -2923,7 +2899,8 @@ exports[`cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts > TAP "QueueName", "\${DeadLetterQueue9F481546.QueueName}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ] ], @@ -2947,7 +2924,8 @@ exports[`cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts > TAP "QueueName", "\${DeadLetterQueue9F481546.QueueName}", { - "stat": "Maximum" + "stat": "Maximum", + "yAxis": "left" } ] ], @@ -2971,7 +2949,8 @@ exports[`cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts > TAP "QueueName", "\${DeadLetterQueue9F481546.QueueName}", { - "stat": "Maximum" + "stat": "Maximum", + "yAxis": "left" } ] ], @@ -2995,7 +2974,8 @@ exports[`cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts > TAP "TopicName", "\${MyTopic86869434.TopicName}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ], [ @@ -3004,7 +2984,8 @@ exports[`cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts > TAP "TopicName", "\${MyTopic86869434.TopicName}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ] ], @@ -3028,7 +3009,8 @@ exports[`cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts > TAP "RuleName", "\${ruleF2C1DCDC}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ], [ @@ -3037,7 +3019,8 @@ exports[`cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts > TAP "RuleName", "\${ruleF2C1DCDC}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ], [ @@ -3046,7 +3029,8 @@ exports[`cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts > TAP "RuleName", "\${ruleF2C1DCDC}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ] ], @@ -4843,7 +4827,7 @@ exports[`cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts > TAP "aws:cdk:path": "CdkGeneralStackTest-US/CDKMetadata/Default" }, "Properties": { - "Analytics": "v2:deflate64:H4sIAAAAAAAA/02Q30/DIBDH/5a9M9SZmL12Gp801rr3hdKzshaoPdhsGv53D5izCeE+9z24Xxu+feC3K3HGtWy6da9qPn84ITtG0mFGg3ze20FJ9vhpEgTWC103gs/P3kinrImhJZcwaoVIXmBKaD5XtocYiDYwvD8IRHDIi2jI5zsvO3A7gcDEoFrh4CwmPr+kQhWgKwaVEvxjIaX1xrEnGHo7aSAkdeHRFG2qmoG+Wj9KSEXK0f5Mf8olceZXcF+2iVKmwJrJCG0b2ste1HmOBIHBierQfip/Gc+n8b5Jevfgk5Yh3aXtlZyuYnZDuHbG0jpit8q08dmbd4N3y/YCM7YBfsSb092W09msjqjUeqRNKA28yvYXs0P/r9UBAAA=" + "Analytics": "v2:deflate64:H4sIAAAAAAAA/02QTU/DMAyGf8vumSmbhLhuIE4gRrf75KamZGuTUjsbVZT/jpKOsUvex68jfy3g8QGKGZ55ruvjvDUVhK2gPio88z6wZQg71xutnj5thqha7KoaIbx4q8U4m1K3vKGhM8zG2agMdhBK11JKJI2Kl3tkJmFYJVG8hLXXR5I1MinsTYNCZxwhvOZGJbGsepML/ONKa+etqGfqWzd2ZCW5N9FWsMldJyiJnR805Sabwf2Mf86l8MRvJF+uTtZEUdWjxc7VFYQdVtMeGaKiE1lhCKW/rOfzet8M4cOTz94E+d241ujxak5hjNfJVD5HmtbYJn1799J7uR0vKutqggPfnRYF3BdQzA5szHzwVkxHUE76CyBn/pPVAQAA" }, "Type": "AWS::CDK::Metadata" }, @@ -5090,10 +5074,8 @@ exports[`cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts > TAP "Metadata": { "slicWatch": { "alarms": { - "Lambda": { - "Invocations": { - "Threshold": 4 - } + "Invocations": { + "Threshold": 4 } } } @@ -5758,7 +5740,8 @@ exports[`cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts > TAP "ApiName", "myapi", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ] ], @@ -5776,22 +5759,14 @@ exports[`cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts > TAP "type": "metric", "properties": { "metrics": [ - [ - "AWS/ApiGateway", - "5XXError", - "ApiName", - "myapi", - { - "stat": "Sum" - } - ], [ "AWS/ApiGateway", "4XXError", "ApiName", "myapi", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ] ], @@ -5809,31 +5784,14 @@ exports[`cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts > TAP "type": "metric", "properties": { "metrics": [ - [ - "AWS/ApiGateway", - "5XXError", - "ApiName", - "myapi", - { - "stat": "Sum" - } - ], - [ - "AWS/ApiGateway", - "4XXError", - "ApiName", - "myapi", - { - "stat": "Sum" - } - ], [ "AWS/ApiGateway", "Latency", "ApiName", "myapi", { - "stat": "Average" + "stat": "Average", + "yAxis": "left" } ], [ @@ -5842,7 +5800,8 @@ exports[`cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts > TAP "ApiName", "myapi", { - "stat": "p95" + "stat": "p95", + "yAxis": "left" } ] ], @@ -5860,49 +5819,14 @@ exports[`cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts > TAP "type": "metric", "properties": { "metrics": [ - [ - "AWS/ApiGateway", - "5XXError", - "ApiName", - "myapi", - { - "stat": "Sum" - } - ], - [ - "AWS/ApiGateway", - "4XXError", - "ApiName", - "myapi", - { - "stat": "Sum" - } - ], - [ - "AWS/ApiGateway", - "Latency", - "ApiName", - "myapi", - { - "stat": "Average" - } - ], - [ - "AWS/ApiGateway", - "Latency", - "ApiName", - "myapi", - { - "stat": "p95" - } - ], [ "AWS/ApiGateway", "Count", "ApiName", "myapi", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ] ], @@ -5926,7 +5850,8 @@ exports[`cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts > TAP "TableName", "\${TableCD117FA1}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ] ], @@ -5944,22 +5869,14 @@ exports[`cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts > TAP "type": "metric", "properties": { "metrics": [ - [ - "AWS/DynamoDB", - "ReadThrottleEvents", - "TableName", - "\${TableCD117FA1}", - { - "stat": "Sum" - } - ], [ "AWS/DynamoDB", "WriteThrottleEvents", "TableName", "\${TableCD117FA1}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ] ], @@ -5983,7 +5900,8 @@ exports[`cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts > TAP "FunctionName", "\${HelloHandler2E4FBA4D}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ], [ @@ -5992,7 +5910,8 @@ exports[`cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts > TAP "FunctionName", "\${ThrottlerHandler750A7C89}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ], [ @@ -6001,7 +5920,8 @@ exports[`cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts > TAP "FunctionName", "\${DriveStreamHandler62F1767B}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ], [ @@ -6010,7 +5930,8 @@ exports[`cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts > TAP "FunctionName", "\${DriveQueueHandler9F657A00}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ], [ @@ -6019,7 +5940,8 @@ exports[`cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts > TAP "FunctionName", "\${DriveTableHandler119966B0}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ] ], @@ -6043,7 +5965,8 @@ exports[`cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts > TAP "FunctionName", "\${HelloHandler2E4FBA4D}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ], [ @@ -6052,7 +5975,8 @@ exports[`cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts > TAP "FunctionName", "\${ThrottlerHandler750A7C89}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ], [ @@ -6061,7 +5985,8 @@ exports[`cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts > TAP "FunctionName", "\${DriveStreamHandler62F1767B}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ], [ @@ -6070,7 +5995,8 @@ exports[`cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts > TAP "FunctionName", "\${DriveQueueHandler9F657A00}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ], [ @@ -6079,7 +6005,8 @@ exports[`cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts > TAP "FunctionName", "\${DriveTableHandler119966B0}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ] ], @@ -6103,7 +6030,8 @@ exports[`cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts > TAP "FunctionName", "\${HelloHandler2E4FBA4D}", { - "stat": "Average" + "stat": "Average", + "yAxis": "left" } ], [ @@ -6112,7 +6040,8 @@ exports[`cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts > TAP "FunctionName", "\${ThrottlerHandler750A7C89}", { - "stat": "Average" + "stat": "Average", + "yAxis": "left" } ], [ @@ -6121,7 +6050,8 @@ exports[`cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts > TAP "FunctionName", "\${DriveStreamHandler62F1767B}", { - "stat": "Average" + "stat": "Average", + "yAxis": "left" } ], [ @@ -6130,7 +6060,8 @@ exports[`cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts > TAP "FunctionName", "\${DriveQueueHandler9F657A00}", { - "stat": "Average" + "stat": "Average", + "yAxis": "left" } ], [ @@ -6139,7 +6070,8 @@ exports[`cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts > TAP "FunctionName", "\${DriveTableHandler119966B0}", { - "stat": "Average" + "stat": "Average", + "yAxis": "left" } ] ], @@ -6163,7 +6095,8 @@ exports[`cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts > TAP "FunctionName", "\${HelloHandler2E4FBA4D}", { - "stat": "p95" + "stat": "p95", + "yAxis": "left" } ], [ @@ -6172,7 +6105,8 @@ exports[`cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts > TAP "FunctionName", "\${ThrottlerHandler750A7C89}", { - "stat": "p95" + "stat": "p95", + "yAxis": "left" } ], [ @@ -6181,7 +6115,8 @@ exports[`cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts > TAP "FunctionName", "\${DriveStreamHandler62F1767B}", { - "stat": "p95" + "stat": "p95", + "yAxis": "left" } ], [ @@ -6190,7 +6125,8 @@ exports[`cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts > TAP "FunctionName", "\${DriveQueueHandler9F657A00}", { - "stat": "p95" + "stat": "p95", + "yAxis": "left" } ], [ @@ -6199,7 +6135,8 @@ exports[`cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts > TAP "FunctionName", "\${DriveTableHandler119966B0}", { - "stat": "p95" + "stat": "p95", + "yAxis": "left" } ] ], @@ -6223,7 +6160,8 @@ exports[`cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts > TAP "FunctionName", "\${HelloHandler2E4FBA4D}", { - "stat": "Maximum" + "stat": "Maximum", + "yAxis": "left" } ], [ @@ -6232,7 +6170,8 @@ exports[`cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts > TAP "FunctionName", "\${ThrottlerHandler750A7C89}", { - "stat": "Maximum" + "stat": "Maximum", + "yAxis": "left" } ], [ @@ -6241,7 +6180,8 @@ exports[`cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts > TAP "FunctionName", "\${DriveStreamHandler62F1767B}", { - "stat": "Maximum" + "stat": "Maximum", + "yAxis": "left" } ], [ @@ -6250,7 +6190,8 @@ exports[`cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts > TAP "FunctionName", "\${DriveQueueHandler9F657A00}", { - "stat": "Maximum" + "stat": "Maximum", + "yAxis": "left" } ], [ @@ -6259,7 +6200,8 @@ exports[`cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts > TAP "FunctionName", "\${DriveTableHandler119966B0}", { - "stat": "Maximum" + "stat": "Maximum", + "yAxis": "left" } ] ], @@ -6283,7 +6225,8 @@ exports[`cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts > TAP "FunctionName", "\${HelloHandler2E4FBA4D}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ], [ @@ -6292,7 +6235,8 @@ exports[`cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts > TAP "FunctionName", "\${ThrottlerHandler750A7C89}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ], [ @@ -6301,7 +6245,8 @@ exports[`cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts > TAP "FunctionName", "\${DriveStreamHandler62F1767B}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ], [ @@ -6310,7 +6255,8 @@ exports[`cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts > TAP "FunctionName", "\${DriveQueueHandler9F657A00}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ], [ @@ -6319,7 +6265,8 @@ exports[`cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts > TAP "FunctionName", "\${DriveTableHandler119966B0}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ] ], @@ -6343,7 +6290,8 @@ exports[`cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts > TAP "FunctionName", "\${HelloHandler2E4FBA4D}", { - "stat": "Maximum" + "stat": "Maximum", + "yAxis": "left" } ], [ @@ -6352,7 +6300,8 @@ exports[`cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts > TAP "FunctionName", "\${ThrottlerHandler750A7C89}", { - "stat": "Maximum" + "stat": "Maximum", + "yAxis": "left" } ], [ @@ -6361,7 +6310,8 @@ exports[`cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts > TAP "FunctionName", "\${DriveStreamHandler62F1767B}", { - "stat": "Maximum" + "stat": "Maximum", + "yAxis": "left" } ], [ @@ -6370,7 +6320,8 @@ exports[`cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts > TAP "FunctionName", "\${DriveQueueHandler9F657A00}", { - "stat": "Maximum" + "stat": "Maximum", + "yAxis": "left" } ], [ @@ -6379,7 +6330,8 @@ exports[`cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts > TAP "FunctionName", "\${DriveTableHandler119966B0}", { - "stat": "Maximum" + "stat": "Maximum", + "yAxis": "left" } ] ], @@ -6403,7 +6355,8 @@ exports[`cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts > TAP "QueueName", "\${DeadLetterQueue9F481546.QueueName}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ], [ @@ -6412,7 +6365,8 @@ exports[`cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts > TAP "QueueName", "\${DeadLetterQueue9F481546.QueueName}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ], [ @@ -6421,7 +6375,8 @@ exports[`cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts > TAP "QueueName", "\${DeadLetterQueue9F481546.QueueName}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ] ], @@ -6445,7 +6400,8 @@ exports[`cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts > TAP "QueueName", "\${DeadLetterQueue9F481546.QueueName}", { - "stat": "Maximum" + "stat": "Maximum", + "yAxis": "left" } ] ], @@ -6469,7 +6425,8 @@ exports[`cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts > TAP "QueueName", "\${DeadLetterQueue9F481546.QueueName}", { - "stat": "Maximum" + "stat": "Maximum", + "yAxis": "left" } ] ], @@ -6493,7 +6450,8 @@ exports[`cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts > TAP "TopicName", "\${MyTopic86869434.TopicName}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ], [ @@ -6502,7 +6460,8 @@ exports[`cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts > TAP "TopicName", "\${MyTopic86869434.TopicName}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ] ], @@ -6526,7 +6485,8 @@ exports[`cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts > TAP "RuleName", "\${ruleF2C1DCDC}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ], [ @@ -6535,7 +6495,8 @@ exports[`cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts > TAP "RuleName", "\${ruleF2C1DCDC}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ], [ @@ -6544,7 +6505,8 @@ exports[`cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts > TAP "RuleName", "\${ruleF2C1DCDC}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ] ], @@ -8312,7 +8274,7 @@ exports[`cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts > TAP "aws:cdk:path": "CdkSFNStackTest-Europe/CDKMetadata/Default" }, "Properties": { - "Analytics": "v2:deflate64:H4sIAAAAAAAA/11P0UoDQQz8lr7nolaQvtpCoaAgp+Djke6lbbp7u6XZq8iy/+7etoIIgZnJhEwyx8UT3s/oSxvT28bJFtN7JGOhtLqkXjF9hJMYWO18JRkcDdueMK1Hb6IEP1m/PIPQgKkNjqd2xbfgxHxP8soy6GNHqhwVnycoGpejsRyXpAwa+bS77dMuklrFl5q58Zdg/w1g+iSJsCZxsDoEMQzlgcivZA7i6xV/dc7QsobxXOZqeDH34vf12puRwYee8ah3l4cFlprPjirSnEcfZWBsr/gDsE52pTwBAAA=" + "Analytics": "v2:deflate64:H4sIAAAAAAAA/11OTWvCQBD9Ld4n01RBeq2CUGihJEKPYdyMOibZFWeilGX/e8lqofT0voZ5b44vSyxndNPCtV3Ryw5jbeQ6oJs2Ub1i3IazOFjvfSYJehp2LWHcjN6ZBD9FvzyB0ICxCj1PdsbP0Iv7nuSdJdBFQ6psiq8TgC5wNbqObUXKoMbn/eOfNkbaKb7nzjd/Dd2/A4xfJAYbkh7WxyCOoTYy/iB3FJ9X/NUpQcUaxotjyOW10UH8Ia99BAl8aBlP+nSdl/hcYjk7qUhxGb3JwFjd8QcjaneZPAEAAA==" }, "Type": "AWS::CDK::Metadata" }, @@ -8323,10 +8285,8 @@ exports[`cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts > TAP "Metadata": { "slicWatch": { "alarms": { - "Lambda": { - "Invocations": { - "Threshold": 4 - } + "Invocations": { + "Threshold": 4 } } } @@ -8405,7 +8365,8 @@ exports[`cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts > TAP "StateMachineArn", "\${StateMachine2E01A3A5}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ], [ @@ -8414,7 +8375,8 @@ exports[`cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts > TAP "StateMachineArn", "\${StateMachine2E01A3A5}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ], [ @@ -8423,7 +8385,8 @@ exports[`cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts > TAP "StateMachineArn", "\${StateMachine2E01A3A5}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ] ], @@ -8447,7 +8410,8 @@ exports[`cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts > TAP "FunctionName", "\${HelloHandler2E4FBA4D}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ] ], @@ -8471,7 +8435,8 @@ exports[`cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts > TAP "FunctionName", "\${HelloHandler2E4FBA4D}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ] ], @@ -8495,7 +8460,8 @@ exports[`cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts > TAP "FunctionName", "\${HelloHandler2E4FBA4D}", { - "stat": "Average" + "stat": "Average", + "yAxis": "left" } ] ], @@ -8519,7 +8485,8 @@ exports[`cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts > TAP "FunctionName", "\${HelloHandler2E4FBA4D}", { - "stat": "p95" + "stat": "p95", + "yAxis": "left" } ] ], @@ -8543,7 +8510,8 @@ exports[`cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts > TAP "FunctionName", "\${HelloHandler2E4FBA4D}", { - "stat": "Maximum" + "stat": "Maximum", + "yAxis": "left" } ] ], @@ -8567,7 +8535,8 @@ exports[`cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts > TAP "FunctionName", "\${HelloHandler2E4FBA4D}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ] ], @@ -8591,7 +8560,8 @@ exports[`cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts > TAP "FunctionName", "\${HelloHandler2E4FBA4D}", { - "stat": "Maximum" + "stat": "Maximum", + "yAxis": "left" } ] ], @@ -8615,7 +8585,8 @@ exports[`cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts > TAP "TopicName", "\${MyTopic86869434.TopicName}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ], [ @@ -8624,7 +8595,8 @@ exports[`cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts > TAP "TopicName", "\${MyTopic86869434.TopicName}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ] ], diff --git a/tap-snapshots/sam-test-project/tests/snapshot/sam-test-project-snapshot.test.ts.test.cjs b/tap-snapshots/sam-test-project/tests/snapshot/sam-test-project-snapshot.test.ts.test.cjs index 89cc3e3d..d7c70649 100644 --- a/tap-snapshots/sam-test-project/tests/snapshot/sam-test-project-snapshot.test.ts.test.cjs +++ b/tap-snapshots/sam-test-project/tests/snapshot/sam-test-project-snapshot.test.ts.test.cjs @@ -145,7 +145,7 @@ exports[`sam-test-project/tests/snapshot/sam-test-project-snapshot.test.ts > TAP "Properties": { "Code": { "S3Bucket": "aws-sam-cli-managed-default-samclisourcebucket-167xnalzxxva4", - "S3Key": "sam-test-project/841a60f2d379216bd90fa34e033d0596" + "S3Key": "sam-test-project/810e2a73503f0ee11a4a06f488e12d55" }, "Handler": "basic-handler.hello", "Role": { @@ -201,7 +201,7 @@ exports[`sam-test-project/tests/snapshot/sam-test-project-snapshot.test.ts > TAP "Properties": { "Code": { "S3Bucket": "aws-sam-cli-managed-default-samclisourcebucket-167xnalzxxva4", - "S3Key": "sam-test-project/841a60f2d379216bd90fa34e033d0596" + "S3Key": "sam-test-project/810e2a73503f0ee11a4a06f488e12d55" }, "Handler": "stream-test-handler.handleDrive", "Role": { @@ -257,7 +257,7 @@ exports[`sam-test-project/tests/snapshot/sam-test-project-snapshot.test.ts > TAP "Properties": { "Code": { "S3Bucket": "aws-sam-cli-managed-default-samclisourcebucket-167xnalzxxva4", - "S3Key": "sam-test-project/841a60f2d379216bd90fa34e033d0596" + "S3Key": "sam-test-project/810e2a73503f0ee11a4a06f488e12d55" }, "Handler": "basic-handler.hello", "Role": { @@ -344,16 +344,14 @@ exports[`sam-test-project/tests/snapshot/sam-test-project-snapshot.test.ts > TAP "SamResourceId": "eventsRule", "slicWatch": { "alarms": { - "Lambda": { - "enabled": false - } + "enabled": false } } }, "Properties": { "Code": { "S3Bucket": "aws-sam-cli-managed-default-samclisourcebucket-167xnalzxxva4", - "S3Key": "sam-test-project/841a60f2d379216bd90fa34e033d0596" + "S3Key": "sam-test-project/810e2a73503f0ee11a4a06f488e12d55" }, "Handler": "rule-handler.handleRule", "Role": { @@ -457,10 +455,8 @@ exports[`sam-test-project/tests/snapshot/sam-test-project-snapshot.test.ts > TAP "SamResourceId": "hello", "slicWatch": { "alarms": { - "Lambda": { - "Invocations": { - "Threshold": 2 - } + "Invocations": { + "Threshold": 2 } } } @@ -468,7 +464,7 @@ exports[`sam-test-project/tests/snapshot/sam-test-project-snapshot.test.ts > TAP "Properties": { "Code": { "S3Bucket": "aws-sam-cli-managed-default-samclisourcebucket-167xnalzxxva4", - "S3Key": "sam-test-project/841a60f2d379216bd90fa34e033d0596" + "S3Key": "sam-test-project/810e2a73503f0ee11a4a06f488e12d55" }, "Handler": "basic-handler.hello", "Role": { @@ -524,7 +520,7 @@ exports[`sam-test-project/tests/snapshot/sam-test-project-snapshot.test.ts > TAP "Properties": { "Code": { "S3Bucket": "aws-sam-cli-managed-default-samclisourcebucket-167xnalzxxva4", - "S3Key": "sam-test-project/841a60f2d379216bd90fa34e033d0596" + "S3Key": "sam-test-project/810e2a73503f0ee11a4a06f488e12d55" }, "Handler": "apigw-handler.handleGet", "Role": { @@ -616,7 +612,7 @@ exports[`sam-test-project/tests/snapshot/sam-test-project-snapshot.test.ts > TAP "Properties": { "Code": { "S3Bucket": "aws-sam-cli-managed-default-samclisourcebucket-167xnalzxxva4", - "S3Key": "sam-test-project/841a60f2d379216bd90fa34e033d0596" + "S3Key": "sam-test-project/810e2a73503f0ee11a4a06f488e12d55" }, "Handler": "basic-handler.hello", "Role": { @@ -735,7 +731,8 @@ exports[`sam-test-project/tests/snapshot/sam-test-project-snapshot.test.ts > TAP "StateMachineArn", "\${TestStateMachine}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ], [ @@ -744,7 +741,8 @@ exports[`sam-test-project/tests/snapshot/sam-test-project-snapshot.test.ts > TAP "StateMachineArn", "\${TestStateMachine}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ], [ @@ -753,7 +751,8 @@ exports[`sam-test-project/tests/snapshot/sam-test-project-snapshot.test.ts > TAP "StateMachineArn", "\${TestStateMachine}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ] ], @@ -777,7 +776,8 @@ exports[`sam-test-project/tests/snapshot/sam-test-project-snapshot.test.ts > TAP "TableName", "\${dataTable}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ] ], @@ -795,15 +795,6 @@ exports[`sam-test-project/tests/snapshot/sam-test-project-snapshot.test.ts > TAP "type": "metric", "properties": { "metrics": [ - [ - "AWS/DynamoDB", - "ReadThrottleEvents", - "TableName", - "\${dataTable}", - { - "stat": "Sum" - } - ], [ "AWS/DynamoDB", "ReadThrottleEvents", @@ -812,7 +803,8 @@ exports[`sam-test-project/tests/snapshot/sam-test-project-snapshot.test.ts > TAP "GlobalSecondaryIndex", "GSI1", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ] ], @@ -830,33 +822,14 @@ exports[`sam-test-project/tests/snapshot/sam-test-project-snapshot.test.ts > TAP "type": "metric", "properties": { "metrics": [ - [ - "AWS/DynamoDB", - "ReadThrottleEvents", - "TableName", - "\${dataTable}", - { - "stat": "Sum" - } - ], - [ - "AWS/DynamoDB", - "ReadThrottleEvents", - "TableName", - "\${dataTable}", - "GlobalSecondaryIndex", - "GSI1", - { - "stat": "Sum" - } - ], [ "AWS/DynamoDB", "WriteThrottleEvents", "TableName", "\${dataTable}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ] ], @@ -874,35 +847,6 @@ exports[`sam-test-project/tests/snapshot/sam-test-project-snapshot.test.ts > TAP "type": "metric", "properties": { "metrics": [ - [ - "AWS/DynamoDB", - "ReadThrottleEvents", - "TableName", - "\${dataTable}", - { - "stat": "Sum" - } - ], - [ - "AWS/DynamoDB", - "ReadThrottleEvents", - "TableName", - "\${dataTable}", - "GlobalSecondaryIndex", - "GSI1", - { - "stat": "Sum" - } - ], - [ - "AWS/DynamoDB", - "WriteThrottleEvents", - "TableName", - "\${dataTable}", - { - "stat": "Sum" - } - ], [ "AWS/DynamoDB", "WriteThrottleEvents", @@ -911,7 +855,8 @@ exports[`sam-test-project/tests/snapshot/sam-test-project-snapshot.test.ts > TAP "GlobalSecondaryIndex", "GSI1", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ] ], @@ -935,7 +880,8 @@ exports[`sam-test-project/tests/snapshot/sam-test-project-snapshot.test.ts > TAP "FunctionName", "\${hello}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ], [ @@ -944,7 +890,8 @@ exports[`sam-test-project/tests/snapshot/sam-test-project-snapshot.test.ts > TAP "FunctionName", "\${throttler}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ], [ @@ -953,7 +900,8 @@ exports[`sam-test-project/tests/snapshot/sam-test-project-snapshot.test.ts > TAP "FunctionName", "\${driveStream}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ], [ @@ -962,7 +910,8 @@ exports[`sam-test-project/tests/snapshot/sam-test-project-snapshot.test.ts > TAP "FunctionName", "\${driveQueue}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ], [ @@ -971,7 +920,8 @@ exports[`sam-test-project/tests/snapshot/sam-test-project-snapshot.test.ts > TAP "FunctionName", "\${driveTable}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ], [ @@ -980,7 +930,8 @@ exports[`sam-test-project/tests/snapshot/sam-test-project-snapshot.test.ts > TAP "FunctionName", "\${streamProcessor}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ], [ @@ -989,7 +940,8 @@ exports[`sam-test-project/tests/snapshot/sam-test-project-snapshot.test.ts > TAP "FunctionName", "\${httpGetter}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ], [ @@ -998,7 +950,8 @@ exports[`sam-test-project/tests/snapshot/sam-test-project-snapshot.test.ts > TAP "FunctionName", "\${eventsRule}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ] ], @@ -1022,7 +975,8 @@ exports[`sam-test-project/tests/snapshot/sam-test-project-snapshot.test.ts > TAP "FunctionName", "\${hello}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ], [ @@ -1031,7 +985,8 @@ exports[`sam-test-project/tests/snapshot/sam-test-project-snapshot.test.ts > TAP "FunctionName", "\${throttler}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ], [ @@ -1040,7 +995,8 @@ exports[`sam-test-project/tests/snapshot/sam-test-project-snapshot.test.ts > TAP "FunctionName", "\${driveStream}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ], [ @@ -1049,7 +1005,8 @@ exports[`sam-test-project/tests/snapshot/sam-test-project-snapshot.test.ts > TAP "FunctionName", "\${driveQueue}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ], [ @@ -1058,7 +1015,8 @@ exports[`sam-test-project/tests/snapshot/sam-test-project-snapshot.test.ts > TAP "FunctionName", "\${driveTable}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ], [ @@ -1067,7 +1025,8 @@ exports[`sam-test-project/tests/snapshot/sam-test-project-snapshot.test.ts > TAP "FunctionName", "\${streamProcessor}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ], [ @@ -1076,7 +1035,8 @@ exports[`sam-test-project/tests/snapshot/sam-test-project-snapshot.test.ts > TAP "FunctionName", "\${httpGetter}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ], [ @@ -1085,7 +1045,8 @@ exports[`sam-test-project/tests/snapshot/sam-test-project-snapshot.test.ts > TAP "FunctionName", "\${eventsRule}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ] ], @@ -1109,7 +1070,8 @@ exports[`sam-test-project/tests/snapshot/sam-test-project-snapshot.test.ts > TAP "FunctionName", "\${hello}", { - "stat": "Average" + "stat": "Average", + "yAxis": "left" } ], [ @@ -1118,7 +1080,8 @@ exports[`sam-test-project/tests/snapshot/sam-test-project-snapshot.test.ts > TAP "FunctionName", "\${throttler}", { - "stat": "Average" + "stat": "Average", + "yAxis": "left" } ], [ @@ -1127,7 +1090,8 @@ exports[`sam-test-project/tests/snapshot/sam-test-project-snapshot.test.ts > TAP "FunctionName", "\${driveStream}", { - "stat": "Average" + "stat": "Average", + "yAxis": "left" } ], [ @@ -1136,7 +1100,8 @@ exports[`sam-test-project/tests/snapshot/sam-test-project-snapshot.test.ts > TAP "FunctionName", "\${driveQueue}", { - "stat": "Average" + "stat": "Average", + "yAxis": "left" } ], [ @@ -1145,7 +1110,8 @@ exports[`sam-test-project/tests/snapshot/sam-test-project-snapshot.test.ts > TAP "FunctionName", "\${driveTable}", { - "stat": "Average" + "stat": "Average", + "yAxis": "left" } ], [ @@ -1154,7 +1120,8 @@ exports[`sam-test-project/tests/snapshot/sam-test-project-snapshot.test.ts > TAP "FunctionName", "\${streamProcessor}", { - "stat": "Average" + "stat": "Average", + "yAxis": "left" } ], [ @@ -1163,7 +1130,8 @@ exports[`sam-test-project/tests/snapshot/sam-test-project-snapshot.test.ts > TAP "FunctionName", "\${httpGetter}", { - "stat": "Average" + "stat": "Average", + "yAxis": "left" } ], [ @@ -1172,7 +1140,8 @@ exports[`sam-test-project/tests/snapshot/sam-test-project-snapshot.test.ts > TAP "FunctionName", "\${eventsRule}", { - "stat": "Average" + "stat": "Average", + "yAxis": "left" } ] ], @@ -1196,7 +1165,8 @@ exports[`sam-test-project/tests/snapshot/sam-test-project-snapshot.test.ts > TAP "FunctionName", "\${hello}", { - "stat": "p95" + "stat": "p95", + "yAxis": "left" } ], [ @@ -1205,7 +1175,8 @@ exports[`sam-test-project/tests/snapshot/sam-test-project-snapshot.test.ts > TAP "FunctionName", "\${throttler}", { - "stat": "p95" + "stat": "p95", + "yAxis": "left" } ], [ @@ -1214,7 +1185,8 @@ exports[`sam-test-project/tests/snapshot/sam-test-project-snapshot.test.ts > TAP "FunctionName", "\${driveStream}", { - "stat": "p95" + "stat": "p95", + "yAxis": "left" } ], [ @@ -1223,7 +1195,8 @@ exports[`sam-test-project/tests/snapshot/sam-test-project-snapshot.test.ts > TAP "FunctionName", "\${driveQueue}", { - "stat": "p95" + "stat": "p95", + "yAxis": "left" } ], [ @@ -1232,7 +1205,8 @@ exports[`sam-test-project/tests/snapshot/sam-test-project-snapshot.test.ts > TAP "FunctionName", "\${driveTable}", { - "stat": "p95" + "stat": "p95", + "yAxis": "left" } ], [ @@ -1241,7 +1215,8 @@ exports[`sam-test-project/tests/snapshot/sam-test-project-snapshot.test.ts > TAP "FunctionName", "\${streamProcessor}", { - "stat": "p95" + "stat": "p95", + "yAxis": "left" } ], [ @@ -1250,7 +1225,8 @@ exports[`sam-test-project/tests/snapshot/sam-test-project-snapshot.test.ts > TAP "FunctionName", "\${httpGetter}", { - "stat": "p95" + "stat": "p95", + "yAxis": "left" } ], [ @@ -1259,7 +1235,8 @@ exports[`sam-test-project/tests/snapshot/sam-test-project-snapshot.test.ts > TAP "FunctionName", "\${eventsRule}", { - "stat": "p95" + "stat": "p95", + "yAxis": "left" } ] ], @@ -1283,7 +1260,8 @@ exports[`sam-test-project/tests/snapshot/sam-test-project-snapshot.test.ts > TAP "FunctionName", "\${hello}", { - "stat": "Maximum" + "stat": "Maximum", + "yAxis": "left" } ], [ @@ -1292,7 +1270,8 @@ exports[`sam-test-project/tests/snapshot/sam-test-project-snapshot.test.ts > TAP "FunctionName", "\${throttler}", { - "stat": "Maximum" + "stat": "Maximum", + "yAxis": "left" } ], [ @@ -1301,7 +1280,8 @@ exports[`sam-test-project/tests/snapshot/sam-test-project-snapshot.test.ts > TAP "FunctionName", "\${driveStream}", { - "stat": "Maximum" + "stat": "Maximum", + "yAxis": "left" } ], [ @@ -1310,7 +1290,8 @@ exports[`sam-test-project/tests/snapshot/sam-test-project-snapshot.test.ts > TAP "FunctionName", "\${driveQueue}", { - "stat": "Maximum" + "stat": "Maximum", + "yAxis": "left" } ], [ @@ -1319,7 +1300,8 @@ exports[`sam-test-project/tests/snapshot/sam-test-project-snapshot.test.ts > TAP "FunctionName", "\${driveTable}", { - "stat": "Maximum" + "stat": "Maximum", + "yAxis": "left" } ], [ @@ -1328,7 +1310,8 @@ exports[`sam-test-project/tests/snapshot/sam-test-project-snapshot.test.ts > TAP "FunctionName", "\${streamProcessor}", { - "stat": "Maximum" + "stat": "Maximum", + "yAxis": "left" } ], [ @@ -1337,7 +1320,8 @@ exports[`sam-test-project/tests/snapshot/sam-test-project-snapshot.test.ts > TAP "FunctionName", "\${httpGetter}", { - "stat": "Maximum" + "stat": "Maximum", + "yAxis": "left" } ], [ @@ -1346,7 +1330,8 @@ exports[`sam-test-project/tests/snapshot/sam-test-project-snapshot.test.ts > TAP "FunctionName", "\${eventsRule}", { - "stat": "Maximum" + "stat": "Maximum", + "yAxis": "left" } ] ], @@ -1370,7 +1355,8 @@ exports[`sam-test-project/tests/snapshot/sam-test-project-snapshot.test.ts > TAP "FunctionName", "\${hello}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ], [ @@ -1379,7 +1365,8 @@ exports[`sam-test-project/tests/snapshot/sam-test-project-snapshot.test.ts > TAP "FunctionName", "\${throttler}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ], [ @@ -1388,7 +1375,8 @@ exports[`sam-test-project/tests/snapshot/sam-test-project-snapshot.test.ts > TAP "FunctionName", "\${driveStream}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ], [ @@ -1397,7 +1385,8 @@ exports[`sam-test-project/tests/snapshot/sam-test-project-snapshot.test.ts > TAP "FunctionName", "\${driveQueue}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ], [ @@ -1406,7 +1395,8 @@ exports[`sam-test-project/tests/snapshot/sam-test-project-snapshot.test.ts > TAP "FunctionName", "\${driveTable}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ], [ @@ -1415,7 +1405,8 @@ exports[`sam-test-project/tests/snapshot/sam-test-project-snapshot.test.ts > TAP "FunctionName", "\${streamProcessor}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ], [ @@ -1424,7 +1415,8 @@ exports[`sam-test-project/tests/snapshot/sam-test-project-snapshot.test.ts > TAP "FunctionName", "\${httpGetter}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ], [ @@ -1433,7 +1425,8 @@ exports[`sam-test-project/tests/snapshot/sam-test-project-snapshot.test.ts > TAP "FunctionName", "\${eventsRule}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ] ], @@ -1457,7 +1450,8 @@ exports[`sam-test-project/tests/snapshot/sam-test-project-snapshot.test.ts > TAP "FunctionName", "\${hello}", { - "stat": "Maximum" + "stat": "Maximum", + "yAxis": "left" } ], [ @@ -1466,7 +1460,8 @@ exports[`sam-test-project/tests/snapshot/sam-test-project-snapshot.test.ts > TAP "FunctionName", "\${throttler}", { - "stat": "Maximum" + "stat": "Maximum", + "yAxis": "left" } ], [ @@ -1475,7 +1470,8 @@ exports[`sam-test-project/tests/snapshot/sam-test-project-snapshot.test.ts > TAP "FunctionName", "\${driveStream}", { - "stat": "Maximum" + "stat": "Maximum", + "yAxis": "left" } ], [ @@ -1484,7 +1480,8 @@ exports[`sam-test-project/tests/snapshot/sam-test-project-snapshot.test.ts > TAP "FunctionName", "\${driveQueue}", { - "stat": "Maximum" + "stat": "Maximum", + "yAxis": "left" } ], [ @@ -1493,7 +1490,8 @@ exports[`sam-test-project/tests/snapshot/sam-test-project-snapshot.test.ts > TAP "FunctionName", "\${driveTable}", { - "stat": "Maximum" + "stat": "Maximum", + "yAxis": "left" } ], [ @@ -1502,7 +1500,8 @@ exports[`sam-test-project/tests/snapshot/sam-test-project-snapshot.test.ts > TAP "FunctionName", "\${streamProcessor}", { - "stat": "Maximum" + "stat": "Maximum", + "yAxis": "left" } ], [ @@ -1511,7 +1510,8 @@ exports[`sam-test-project/tests/snapshot/sam-test-project-snapshot.test.ts > TAP "FunctionName", "\${httpGetter}", { - "stat": "Maximum" + "stat": "Maximum", + "yAxis": "left" } ], [ @@ -1520,7 +1520,8 @@ exports[`sam-test-project/tests/snapshot/sam-test-project-snapshot.test.ts > TAP "FunctionName", "\${eventsRule}", { - "stat": "Maximum" + "stat": "Maximum", + "yAxis": "left" } ] ], @@ -1544,7 +1545,8 @@ exports[`sam-test-project/tests/snapshot/sam-test-project-snapshot.test.ts > TAP "FunctionName", "\${streamProcessor}", { - "stat": "Maximum" + "stat": "Maximum", + "yAxis": "left" } ] ], @@ -1568,7 +1570,8 @@ exports[`sam-test-project/tests/snapshot/sam-test-project-snapshot.test.ts > TAP "StreamName", "\${stream}", { - "stat": "Maximum" + "stat": "Maximum", + "yAxis": "left" } ] ], @@ -1592,7 +1595,8 @@ exports[`sam-test-project/tests/snapshot/sam-test-project-snapshot.test.ts > TAP "StreamName", "\${stream}", { - "stat": "Average" + "stat": "Average", + "yAxis": "left" } ], [ @@ -1601,7 +1605,8 @@ exports[`sam-test-project/tests/snapshot/sam-test-project-snapshot.test.ts > TAP "StreamName", "\${stream}", { - "stat": "Average" + "stat": "Average", + "yAxis": "left" } ], [ @@ -1610,7 +1615,8 @@ exports[`sam-test-project/tests/snapshot/sam-test-project-snapshot.test.ts > TAP "StreamName", "\${stream}", { - "stat": "Average" + "stat": "Average", + "yAxis": "left" } ] ], @@ -1634,7 +1640,8 @@ exports[`sam-test-project/tests/snapshot/sam-test-project-snapshot.test.ts > TAP "StreamName", "\${stream}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ], [ @@ -1643,7 +1650,8 @@ exports[`sam-test-project/tests/snapshot/sam-test-project-snapshot.test.ts > TAP "StreamName", "\${stream}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ] ], @@ -1667,7 +1675,8 @@ exports[`sam-test-project/tests/snapshot/sam-test-project-snapshot.test.ts > TAP "QueueName", "\${regularQueue.QueueName}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ], [ @@ -1676,7 +1685,8 @@ exports[`sam-test-project/tests/snapshot/sam-test-project-snapshot.test.ts > TAP "QueueName", "\${regularQueue.QueueName}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ], [ @@ -1685,7 +1695,8 @@ exports[`sam-test-project/tests/snapshot/sam-test-project-snapshot.test.ts > TAP "QueueName", "\${regularQueue.QueueName}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ] ], @@ -1709,7 +1720,8 @@ exports[`sam-test-project/tests/snapshot/sam-test-project-snapshot.test.ts > TAP "QueueName", "\${regularQueue.QueueName}", { - "stat": "Maximum" + "stat": "Maximum", + "yAxis": "left" } ] ], @@ -1733,7 +1745,8 @@ exports[`sam-test-project/tests/snapshot/sam-test-project-snapshot.test.ts > TAP "QueueName", "\${regularQueue.QueueName}", { - "stat": "Maximum" + "stat": "Maximum", + "yAxis": "left" } ] ], @@ -1757,7 +1770,8 @@ exports[`sam-test-project/tests/snapshot/sam-test-project-snapshot.test.ts > TAP "QueueName", "\${fifoQueue.QueueName}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ], [ @@ -1766,7 +1780,8 @@ exports[`sam-test-project/tests/snapshot/sam-test-project-snapshot.test.ts > TAP "QueueName", "\${fifoQueue.QueueName}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ], [ @@ -1775,7 +1790,8 @@ exports[`sam-test-project/tests/snapshot/sam-test-project-snapshot.test.ts > TAP "QueueName", "\${fifoQueue.QueueName}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ] ], @@ -1799,7 +1815,8 @@ exports[`sam-test-project/tests/snapshot/sam-test-project-snapshot.test.ts > TAP "QueueName", "\${fifoQueue.QueueName}", { - "stat": "Maximum" + "stat": "Maximum", + "yAxis": "left" } ] ], @@ -1823,7 +1840,8 @@ exports[`sam-test-project/tests/snapshot/sam-test-project-snapshot.test.ts > TAP "QueueName", "\${fifoQueue.QueueName}", { - "stat": "Maximum" + "stat": "Maximum", + "yAxis": "left" } ] ], @@ -1849,7 +1867,8 @@ exports[`sam-test-project/tests/snapshot/sam-test-project-snapshot.test.ts > TAP "ClusterName", "\${ecsCluster}", { - "stat": "Average" + "stat": "Average", + "yAxis": "left" } ], [ @@ -1860,7 +1879,8 @@ exports[`sam-test-project/tests/snapshot/sam-test-project-snapshot.test.ts > TAP "ClusterName", "\${ecsCluster}", { - "stat": "Average" + "stat": "Average", + "yAxis": "left" } ] ], @@ -1884,7 +1904,8 @@ exports[`sam-test-project/tests/snapshot/sam-test-project-snapshot.test.ts > TAP "TopicName", "\${MonitoringTopic.TopicName}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ], [ @@ -1893,7 +1914,8 @@ exports[`sam-test-project/tests/snapshot/sam-test-project-snapshot.test.ts > TAP "TopicName", "\${MonitoringTopic.TopicName}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ] ], @@ -1917,7 +1939,8 @@ exports[`sam-test-project/tests/snapshot/sam-test-project-snapshot.test.ts > TAP "RuleName", "\${eventsRuleTrigger}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ], [ @@ -1926,7 +1949,8 @@ exports[`sam-test-project/tests/snapshot/sam-test-project-snapshot.test.ts > TAP "RuleName", "\${eventsRuleTrigger}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ], [ @@ -1935,7 +1959,8 @@ exports[`sam-test-project/tests/snapshot/sam-test-project-snapshot.test.ts > TAP "RuleName", "\${eventsRuleTrigger}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ] ], @@ -4855,7 +4880,7 @@ exports[`sam-test-project/tests/snapshot/sam-test-project-snapshot.test.ts > TAP "Properties": { "Code": { "S3Bucket": "aws-sam-cli-managed-default-samclisourcebucket-167xnalzxxva4", - "S3Key": "sam-test-project/841a60f2d379216bd90fa34e033d0596" + "S3Key": "sam-test-project/810e2a73503f0ee11a4a06f488e12d55" }, "Handler": "basic-handler.hello", "Role": { @@ -5094,7 +5119,7 @@ exports[`sam-test-project/tests/snapshot/sam-test-project-snapshot.test.ts > TAP "Properties": { "Code": { "S3Bucket": "aws-sam-cli-managed-default-samclisourcebucket-167xnalzxxva4", - "S3Key": "sam-test-project/841a60f2d379216bd90fa34e033d0596" + "S3Key": "sam-test-project/810e2a73503f0ee11a4a06f488e12d55" }, "Handler": "basic-handler.hello", "ReservedConcurrentExecutions": 0, diff --git a/tap-snapshots/serverless-test-project-alb/tests/snapshot/serverless-test-project-alb-snapshot.test.ts.test.cjs b/tap-snapshots/serverless-test-project-alb/tests/snapshot/serverless-test-project-alb-snapshot.test.ts.test.cjs index 6ac1b7e9..6d98018f 100644 --- a/tap-snapshots/serverless-test-project-alb/tests/snapshot/serverless-test-project-alb-snapshot.test.ts.test.cjs +++ b/tap-snapshots/serverless-test-project-alb/tests/snapshot/serverless-test-project-alb-snapshot.test.ts.test.cjs @@ -511,7 +511,8 @@ exports[`serverless-test-project-alb/tests/snapshot/serverless-test-project-alb- "FunctionName", "\${AlbEventLambdaFunction}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ] ], @@ -535,7 +536,8 @@ exports[`serverless-test-project-alb/tests/snapshot/serverless-test-project-alb- "FunctionName", "\${AlbEventLambdaFunction}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ] ], @@ -559,7 +561,8 @@ exports[`serverless-test-project-alb/tests/snapshot/serverless-test-project-alb- "FunctionName", "\${AlbEventLambdaFunction}", { - "stat": "Average" + "stat": "Average", + "yAxis": "left" } ] ], @@ -583,7 +586,8 @@ exports[`serverless-test-project-alb/tests/snapshot/serverless-test-project-alb- "FunctionName", "\${AlbEventLambdaFunction}", { - "stat": "p95" + "stat": "p95", + "yAxis": "left" } ] ], @@ -607,7 +611,8 @@ exports[`serverless-test-project-alb/tests/snapshot/serverless-test-project-alb- "FunctionName", "\${AlbEventLambdaFunction}", { - "stat": "Maximum" + "stat": "Maximum", + "yAxis": "left" } ] ], @@ -631,7 +636,8 @@ exports[`serverless-test-project-alb/tests/snapshot/serverless-test-project-alb- "FunctionName", "\${AlbEventLambdaFunction}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ] ], @@ -655,7 +661,8 @@ exports[`serverless-test-project-alb/tests/snapshot/serverless-test-project-alb- "FunctionName", "\${AlbEventLambdaFunction}", { - "stat": "Maximum" + "stat": "Maximum", + "yAxis": "left" } ] ], @@ -679,7 +686,8 @@ exports[`serverless-test-project-alb/tests/snapshot/serverless-test-project-alb- "LoadBalancer", "\${alb.LoadBalancerFullName}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ], [ @@ -688,7 +696,8 @@ exports[`serverless-test-project-alb/tests/snapshot/serverless-test-project-alb- "LoadBalancer", "\${alb.LoadBalancerFullName}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ] ], @@ -714,7 +723,8 @@ exports[`serverless-test-project-alb/tests/snapshot/serverless-test-project-alb- "TargetGroup", "\${AlbEventAlbTargetGrouphttpListener.TargetGroupFullName}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ], [ @@ -725,7 +735,8 @@ exports[`serverless-test-project-alb/tests/snapshot/serverless-test-project-alb- "TargetGroup", "\${AlbEventAlbTargetGrouphttpListener.TargetGroupFullName}", { - "stat": "Average" + "stat": "Average", + "yAxis": "left" } ], [ @@ -736,7 +747,8 @@ exports[`serverless-test-project-alb/tests/snapshot/serverless-test-project-alb- "TargetGroup", "\${AlbEventAlbTargetGrouphttpListener.TargetGroupFullName}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ], [ @@ -747,7 +759,8 @@ exports[`serverless-test-project-alb/tests/snapshot/serverless-test-project-alb- "TargetGroup", "\${AlbEventAlbTargetGrouphttpListener.TargetGroupFullName}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ] ], diff --git a/tap-snapshots/serverless-test-project-appsync/tests/snapshot/serverless-test-project-appsync-snapshot.test.ts.test.cjs b/tap-snapshots/serverless-test-project-appsync/tests/snapshot/serverless-test-project-appsync-snapshot.test.ts.test.cjs index 7b5ec5d4..1863cd43 100644 --- a/tap-snapshots/serverless-test-project-appsync/tests/snapshot/serverless-test-project-appsync-snapshot.test.ts.test.cjs +++ b/tap-snapshots/serverless-test-project-appsync/tests/snapshot/serverless-test-project-appsync-snapshot.test.ts.test.cjs @@ -598,7 +598,8 @@ exports[`serverless-test-project-appsync/tests/snapshot/serverless-test-project- "TableName", "\${BooksTable}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ] ], @@ -616,22 +617,14 @@ exports[`serverless-test-project-appsync/tests/snapshot/serverless-test-project- "type": "metric", "properties": { "metrics": [ - [ - "AWS/DynamoDB", - "ReadThrottleEvents", - "TableName", - "\${BooksTable}", - { - "stat": "Sum" - } - ], [ "AWS/DynamoDB", "WriteThrottleEvents", "TableName", "\${BooksTable}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ] ], diff --git a/tap-snapshots/serverless-test-project/tests/snapshot/serverless-test-project-snapshot.test.ts.test.cjs b/tap-snapshots/serverless-test-project/tests/snapshot/serverless-test-project-snapshot.test.ts.test.cjs index c9ed6ceb..93211aad 100644 --- a/tap-snapshots/serverless-test-project/tests/snapshot/serverless-test-project-snapshot.test.ts.test.cjs +++ b/tap-snapshots/serverless-test-project/tests/snapshot/serverless-test-project-snapshot.test.ts.test.cjs @@ -1289,7 +1289,8 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "ApiName", "dev-serverless-test-project", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ] ], @@ -1307,22 +1308,14 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "type": "metric", "properties": { "metrics": [ - [ - "AWS/ApiGateway", - "5XXError", - "ApiName", - "dev-serverless-test-project", - { - "stat": "Sum" - } - ], [ "AWS/ApiGateway", "4XXError", "ApiName", "dev-serverless-test-project", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ] ], @@ -1340,31 +1333,14 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "type": "metric", "properties": { "metrics": [ - [ - "AWS/ApiGateway", - "5XXError", - "ApiName", - "dev-serverless-test-project", - { - "stat": "Sum" - } - ], - [ - "AWS/ApiGateway", - "4XXError", - "ApiName", - "dev-serverless-test-project", - { - "stat": "Sum" - } - ], [ "AWS/ApiGateway", "Latency", "ApiName", "dev-serverless-test-project", { - "stat": "Average" + "stat": "Average", + "yAxis": "left" } ], [ @@ -1373,7 +1349,8 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "ApiName", "dev-serverless-test-project", { - "stat": "p95" + "stat": "p95", + "yAxis": "left" } ] ], @@ -1391,49 +1368,14 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "type": "metric", "properties": { "metrics": [ - [ - "AWS/ApiGateway", - "5XXError", - "ApiName", - "dev-serverless-test-project", - { - "stat": "Sum" - } - ], - [ - "AWS/ApiGateway", - "4XXError", - "ApiName", - "dev-serverless-test-project", - { - "stat": "Sum" - } - ], - [ - "AWS/ApiGateway", - "Latency", - "ApiName", - "dev-serverless-test-project", - { - "stat": "Average" - } - ], - [ - "AWS/ApiGateway", - "Latency", - "ApiName", - "dev-serverless-test-project", - { - "stat": "p95" - } - ], [ "AWS/ApiGateway", "Count", "ApiName", "dev-serverless-test-project", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ] ], @@ -1457,7 +1399,8 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "StateMachineArn", "\${Workflow}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ], [ @@ -1466,7 +1409,8 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "StateMachineArn", "\${Workflow}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ], [ @@ -1475,7 +1419,8 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "StateMachineArn", "\${Workflow}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ] ], @@ -1499,7 +1444,8 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "StateMachineArn", "\${ExpressWorkflow}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ], [ @@ -1508,7 +1454,8 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "StateMachineArn", "\${ExpressWorkflow}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ], [ @@ -1517,7 +1464,8 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "StateMachineArn", "\${ExpressWorkflow}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ] ], @@ -1541,7 +1489,8 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "TableName", "\${dataTable}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ] ], @@ -1559,15 +1508,6 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "type": "metric", "properties": { "metrics": [ - [ - "AWS/DynamoDB", - "ReadThrottleEvents", - "TableName", - "\${dataTable}", - { - "stat": "Sum" - } - ], [ "AWS/DynamoDB", "ReadThrottleEvents", @@ -1576,7 +1516,8 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "GlobalSecondaryIndex", "GSI1", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ] ], @@ -1594,33 +1535,14 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "type": "metric", "properties": { "metrics": [ - [ - "AWS/DynamoDB", - "ReadThrottleEvents", - "TableName", - "\${dataTable}", - { - "stat": "Sum" - } - ], - [ - "AWS/DynamoDB", - "ReadThrottleEvents", - "TableName", - "\${dataTable}", - "GlobalSecondaryIndex", - "GSI1", - { - "stat": "Sum" - } - ], [ "AWS/DynamoDB", "WriteThrottleEvents", "TableName", "\${dataTable}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ] ], @@ -1638,35 +1560,6 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "type": "metric", "properties": { "metrics": [ - [ - "AWS/DynamoDB", - "ReadThrottleEvents", - "TableName", - "\${dataTable}", - { - "stat": "Sum" - } - ], - [ - "AWS/DynamoDB", - "ReadThrottleEvents", - "TableName", - "\${dataTable}", - "GlobalSecondaryIndex", - "GSI1", - { - "stat": "Sum" - } - ], - [ - "AWS/DynamoDB", - "WriteThrottleEvents", - "TableName", - "\${dataTable}", - { - "stat": "Sum" - } - ], [ "AWS/DynamoDB", "WriteThrottleEvents", @@ -1675,7 +1568,8 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "GlobalSecondaryIndex", "GSI1", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ] ], @@ -1699,7 +1593,8 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "FunctionName", "\${HelloLambdaFunction}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ], [ @@ -1708,7 +1603,8 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "FunctionName", "\${ThrottlerLambdaFunction}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ], [ @@ -1717,7 +1613,8 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "FunctionName", "\${DriveStreamLambdaFunction}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ], [ @@ -1726,7 +1623,8 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "FunctionName", "\${DriveQueueLambdaFunction}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ], [ @@ -1735,7 +1633,8 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "FunctionName", "\${DriveTableLambdaFunction}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ], [ @@ -1744,7 +1643,8 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "FunctionName", "\${StreamProcessorLambdaFunction}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ], [ @@ -1753,7 +1653,8 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "FunctionName", "\${HttpGetterLambdaFunction}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ], [ @@ -1762,7 +1663,8 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "FunctionName", "\${SubscriptionHandlerLambdaFunction}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ], [ @@ -1771,7 +1673,8 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "FunctionName", "\${EventsRuleLambdaFunction}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ] ], @@ -1795,7 +1698,8 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "FunctionName", "\${HelloLambdaFunction}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ], [ @@ -1804,7 +1708,8 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "FunctionName", "\${ThrottlerLambdaFunction}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ], [ @@ -1813,7 +1718,8 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "FunctionName", "\${DriveStreamLambdaFunction}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ], [ @@ -1822,7 +1728,8 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "FunctionName", "\${DriveQueueLambdaFunction}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ], [ @@ -1831,7 +1738,8 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "FunctionName", "\${DriveTableLambdaFunction}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ], [ @@ -1840,7 +1748,8 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "FunctionName", "\${StreamProcessorLambdaFunction}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ], [ @@ -1849,7 +1758,8 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "FunctionName", "\${HttpGetterLambdaFunction}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ], [ @@ -1858,7 +1768,8 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "FunctionName", "\${SubscriptionHandlerLambdaFunction}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ], [ @@ -1867,7 +1778,8 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "FunctionName", "\${EventsRuleLambdaFunction}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ] ], @@ -1891,7 +1803,8 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "FunctionName", "\${HelloLambdaFunction}", { - "stat": "Average" + "stat": "Average", + "yAxis": "left" } ], [ @@ -1900,7 +1813,8 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "FunctionName", "\${ThrottlerLambdaFunction}", { - "stat": "Average" + "stat": "Average", + "yAxis": "left" } ], [ @@ -1909,7 +1823,8 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "FunctionName", "\${DriveStreamLambdaFunction}", { - "stat": "Average" + "stat": "Average", + "yAxis": "left" } ], [ @@ -1918,7 +1833,8 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "FunctionName", "\${DriveQueueLambdaFunction}", { - "stat": "Average" + "stat": "Average", + "yAxis": "left" } ], [ @@ -1927,7 +1843,8 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "FunctionName", "\${DriveTableLambdaFunction}", { - "stat": "Average" + "stat": "Average", + "yAxis": "left" } ], [ @@ -1936,7 +1853,8 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "FunctionName", "\${StreamProcessorLambdaFunction}", { - "stat": "Average" + "stat": "Average", + "yAxis": "left" } ], [ @@ -1945,7 +1863,8 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "FunctionName", "\${HttpGetterLambdaFunction}", { - "stat": "Average" + "stat": "Average", + "yAxis": "left" } ], [ @@ -1954,7 +1873,8 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "FunctionName", "\${SubscriptionHandlerLambdaFunction}", { - "stat": "Average" + "stat": "Average", + "yAxis": "left" } ], [ @@ -1963,7 +1883,8 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "FunctionName", "\${EventsRuleLambdaFunction}", { - "stat": "Average" + "stat": "Average", + "yAxis": "left" } ] ], @@ -1987,7 +1908,8 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "FunctionName", "\${HelloLambdaFunction}", { - "stat": "p95" + "stat": "p95", + "yAxis": "left" } ], [ @@ -1996,7 +1918,8 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "FunctionName", "\${ThrottlerLambdaFunction}", { - "stat": "p95" + "stat": "p95", + "yAxis": "left" } ], [ @@ -2005,7 +1928,8 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "FunctionName", "\${DriveStreamLambdaFunction}", { - "stat": "p95" + "stat": "p95", + "yAxis": "left" } ], [ @@ -2014,7 +1938,8 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "FunctionName", "\${DriveQueueLambdaFunction}", { - "stat": "p95" + "stat": "p95", + "yAxis": "left" } ], [ @@ -2023,7 +1948,8 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "FunctionName", "\${DriveTableLambdaFunction}", { - "stat": "p95" + "stat": "p95", + "yAxis": "left" } ], [ @@ -2032,7 +1958,8 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "FunctionName", "\${StreamProcessorLambdaFunction}", { - "stat": "p95" + "stat": "p95", + "yAxis": "left" } ], [ @@ -2041,7 +1968,8 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "FunctionName", "\${HttpGetterLambdaFunction}", { - "stat": "p95" + "stat": "p95", + "yAxis": "left" } ], [ @@ -2050,7 +1978,8 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "FunctionName", "\${SubscriptionHandlerLambdaFunction}", { - "stat": "p95" + "stat": "p95", + "yAxis": "left" } ], [ @@ -2059,7 +1988,8 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "FunctionName", "\${EventsRuleLambdaFunction}", { - "stat": "p95" + "stat": "p95", + "yAxis": "left" } ] ], @@ -2083,7 +2013,8 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "FunctionName", "\${HelloLambdaFunction}", { - "stat": "Maximum" + "stat": "Maximum", + "yAxis": "left" } ], [ @@ -2092,7 +2023,8 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "FunctionName", "\${ThrottlerLambdaFunction}", { - "stat": "Maximum" + "stat": "Maximum", + "yAxis": "left" } ], [ @@ -2101,7 +2033,8 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "FunctionName", "\${DriveStreamLambdaFunction}", { - "stat": "Maximum" + "stat": "Maximum", + "yAxis": "left" } ], [ @@ -2110,7 +2043,8 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "FunctionName", "\${DriveQueueLambdaFunction}", { - "stat": "Maximum" + "stat": "Maximum", + "yAxis": "left" } ], [ @@ -2119,7 +2053,8 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "FunctionName", "\${DriveTableLambdaFunction}", { - "stat": "Maximum" + "stat": "Maximum", + "yAxis": "left" } ], [ @@ -2128,7 +2063,8 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "FunctionName", "\${StreamProcessorLambdaFunction}", { - "stat": "Maximum" + "stat": "Maximum", + "yAxis": "left" } ], [ @@ -2137,7 +2073,8 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "FunctionName", "\${HttpGetterLambdaFunction}", { - "stat": "Maximum" + "stat": "Maximum", + "yAxis": "left" } ], [ @@ -2146,7 +2083,8 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "FunctionName", "\${SubscriptionHandlerLambdaFunction}", { - "stat": "Maximum" + "stat": "Maximum", + "yAxis": "left" } ], [ @@ -2155,7 +2093,8 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "FunctionName", "\${EventsRuleLambdaFunction}", { - "stat": "Maximum" + "stat": "Maximum", + "yAxis": "left" } ] ], @@ -2179,7 +2118,8 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "FunctionName", "\${HelloLambdaFunction}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ], [ @@ -2188,7 +2128,8 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "FunctionName", "\${ThrottlerLambdaFunction}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ], [ @@ -2197,7 +2138,8 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "FunctionName", "\${DriveStreamLambdaFunction}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ], [ @@ -2206,7 +2148,8 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "FunctionName", "\${DriveQueueLambdaFunction}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ], [ @@ -2215,7 +2158,8 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "FunctionName", "\${DriveTableLambdaFunction}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ], [ @@ -2224,7 +2168,8 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "FunctionName", "\${StreamProcessorLambdaFunction}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ], [ @@ -2233,7 +2178,8 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "FunctionName", "\${HttpGetterLambdaFunction}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ], [ @@ -2242,7 +2188,8 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "FunctionName", "\${SubscriptionHandlerLambdaFunction}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ], [ @@ -2251,7 +2198,8 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "FunctionName", "\${EventsRuleLambdaFunction}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ] ], @@ -2275,7 +2223,8 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "FunctionName", "\${HelloLambdaFunction}", { - "stat": "Maximum" + "stat": "Maximum", + "yAxis": "left" } ], [ @@ -2284,7 +2233,8 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "FunctionName", "\${ThrottlerLambdaFunction}", { - "stat": "Maximum" + "stat": "Maximum", + "yAxis": "left" } ], [ @@ -2293,7 +2243,8 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "FunctionName", "\${DriveStreamLambdaFunction}", { - "stat": "Maximum" + "stat": "Maximum", + "yAxis": "left" } ], [ @@ -2302,7 +2253,8 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "FunctionName", "\${DriveQueueLambdaFunction}", { - "stat": "Maximum" + "stat": "Maximum", + "yAxis": "left" } ], [ @@ -2311,7 +2263,8 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "FunctionName", "\${DriveTableLambdaFunction}", { - "stat": "Maximum" + "stat": "Maximum", + "yAxis": "left" } ], [ @@ -2320,7 +2273,8 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "FunctionName", "\${StreamProcessorLambdaFunction}", { - "stat": "Maximum" + "stat": "Maximum", + "yAxis": "left" } ], [ @@ -2329,7 +2283,8 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "FunctionName", "\${HttpGetterLambdaFunction}", { - "stat": "Maximum" + "stat": "Maximum", + "yAxis": "left" } ], [ @@ -2338,7 +2293,8 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "FunctionName", "\${SubscriptionHandlerLambdaFunction}", { - "stat": "Maximum" + "stat": "Maximum", + "yAxis": "left" } ], [ @@ -2347,7 +2303,8 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "FunctionName", "\${EventsRuleLambdaFunction}", { - "stat": "Maximum" + "stat": "Maximum", + "yAxis": "left" } ] ], @@ -2371,7 +2328,8 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "FunctionName", "\${StreamProcessorLambdaFunction}", { - "stat": "Maximum" + "stat": "Maximum", + "yAxis": "left" } ] ], @@ -2395,7 +2353,8 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "StreamName", "\${stream}", { - "stat": "Maximum" + "stat": "Maximum", + "yAxis": "left" } ] ], @@ -2419,7 +2378,8 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "StreamName", "\${stream}", { - "stat": "Average" + "stat": "Average", + "yAxis": "left" } ], [ @@ -2428,7 +2388,8 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "StreamName", "\${stream}", { - "stat": "Average" + "stat": "Average", + "yAxis": "left" } ], [ @@ -2437,7 +2398,8 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "StreamName", "\${stream}", { - "stat": "Average" + "stat": "Average", + "yAxis": "left" } ] ], @@ -2461,7 +2423,8 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "StreamName", "\${stream}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ], [ @@ -2470,7 +2433,8 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "StreamName", "\${stream}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ] ], @@ -2494,7 +2458,8 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "QueueName", "\${regularQueue.QueueName}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ], [ @@ -2503,7 +2468,8 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "QueueName", "\${regularQueue.QueueName}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ], [ @@ -2512,7 +2478,8 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "QueueName", "\${regularQueue.QueueName}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ] ], @@ -2536,7 +2503,8 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "QueueName", "\${regularQueue.QueueName}", { - "stat": "Maximum" + "stat": "Maximum", + "yAxis": "left" } ] ], @@ -2560,7 +2528,8 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "QueueName", "\${regularQueue.QueueName}", { - "stat": "Maximum" + "stat": "Maximum", + "yAxis": "left" } ] ], @@ -2584,7 +2553,8 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "QueueName", "\${fifoQueue.QueueName}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ], [ @@ -2593,7 +2563,8 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "QueueName", "\${fifoQueue.QueueName}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ], [ @@ -2602,7 +2573,8 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "QueueName", "\${fifoQueue.QueueName}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ] ], @@ -2626,7 +2598,8 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "QueueName", "\${fifoQueue.QueueName}", { - "stat": "Maximum" + "stat": "Maximum", + "yAxis": "left" } ] ], @@ -2650,7 +2623,8 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "QueueName", "\${fifoQueue.QueueName}", { - "stat": "Maximum" + "stat": "Maximum", + "yAxis": "left" } ] ], @@ -2676,7 +2650,8 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "ClusterName", "\${ecsCluster}", { - "stat": "Average" + "stat": "Average", + "yAxis": "left" } ], [ @@ -2687,7 +2662,8 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "ClusterName", "\${ecsCluster}", { - "stat": "Average" + "stat": "Average", + "yAxis": "left" } ] ], @@ -2711,7 +2687,8 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "TopicName", "\${topic.TopicName}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ], [ @@ -2720,7 +2697,8 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "TopicName", "\${topic.TopicName}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ] ], @@ -2744,7 +2722,8 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "RuleName", "\${ServerlesstestprojectdeveventsRulerule1EventBridgeRule}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ], [ @@ -2753,7 +2732,8 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "RuleName", "\${ServerlesstestprojectdeveventsRulerule1EventBridgeRule}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ], [ @@ -2762,7 +2742,8 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "RuleName", "\${ServerlesstestprojectdeveventsRulerule1EventBridgeRule}", { - "stat": "Sum" + "stat": "Sum", + "yAxis": "left" } ] ], @@ -3378,6 +3359,44 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot }, "Type": "AWS::CloudWatch::Alarm" }, + "slicWatchLambdaDurationAlarmEventsRuleLambdaFunction": { + "Properties": { + "ActionsEnabled": true, + "AlarmActions": [ + "test-topic" + ], + "AlarmDescription": { + "Fn::Sub": [ + "Max duration for \${EventsRuleLambdaFunction} breaches 95% of timeout (6)", + {} + ] + }, + "AlarmName": { + "Fn::Sub": [ + "Lambda_Duration_\${EventsRuleLambdaFunction}", + {} + ] + }, + "ComparisonOperator": "GreaterThanThreshold", + "Dimensions": [ + { + "Name": "FunctionName", + "Value": { + "Ref": "EventsRuleLambdaFunction" + } + } + ], + "EvaluationPeriods": 1, + "MetricName": "Duration", + "Namespace": "AWS/Lambda", + "OKActions": [], + "Period": 60, + "Statistic": "Maximum", + "Threshold": 5700, + "TreatMissingData": "notBreaching" + }, + "Type": "AWS::CloudWatch::Alarm" + }, "slicWatchLambdaDurationAlarmHelloLambdaFunction": { "Properties": { "ActionsEnabled": true, @@ -3720,6 +3739,44 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot }, "Type": "AWS::CloudWatch::Alarm" }, + "slicWatchLambdaErrorsAlarmEventsRuleLambdaFunction": { + "Properties": { + "ActionsEnabled": true, + "AlarmActions": [ + "test-topic" + ], + "AlarmDescription": { + "Fn::Sub": [ + "Error count for \${EventsRuleLambdaFunction} breaches 0", + {} + ] + }, + "AlarmName": { + "Fn::Sub": [ + "Lambda_Errors_\${EventsRuleLambdaFunction}", + {} + ] + }, + "ComparisonOperator": "GreaterThanThreshold", + "Dimensions": [ + { + "Name": "FunctionName", + "Value": { + "Ref": "EventsRuleLambdaFunction" + } + } + ], + "EvaluationPeriods": 1, + "MetricName": "Errors", + "Namespace": "AWS/Lambda", + "OKActions": [], + "Period": 60, + "Statistic": "Sum", + "Threshold": 0, + "TreatMissingData": "notBreaching" + }, + "Type": "AWS::CloudWatch::Alarm" + }, "slicWatchLambdaErrorsAlarmHelloLambdaFunction": { "Properties": { "ActionsEnabled": true, @@ -4208,6 +4265,80 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot }, "Type": "AWS::CloudWatch::Alarm" }, + "slicWatchLambdaThrottlesAlarmEventsRuleLambdaFunction": { + "Properties": { + "ActionsEnabled": true, + "AlarmActions": [ + "test-topic" + ], + "AlarmDescription": { + "Fn::Sub": [ + "Throttles % for \${EventsRuleLambdaFunction} breaches 0", + {} + ] + }, + "AlarmName": { + "Fn::Sub": [ + "Lambda_Throttles_\${EventsRuleLambdaFunction}", + {} + ] + }, + "ComparisonOperator": "GreaterThanThreshold", + "EvaluationPeriods": 1, + "Metrics": [ + { + "Id": "throttles_pc", + "Expression": "(throttles / ( throttles + invocations )) * 100", + "Label": "% Throttles", + "ReturnData": true + }, + { + "Id": "throttles", + "MetricStat": { + "Metric": { + "Namespace": "AWS/Lambda", + "MetricName": "Throttles", + "Dimensions": [ + { + "Name": "FunctionName", + "Value": { + "Ref": "EventsRuleLambdaFunction" + } + } + ] + }, + "Period": 60, + "Stat": "Sum" + }, + "ReturnData": false + }, + { + "Id": "invocations", + "MetricStat": { + "Metric": { + "Namespace": "AWS/Lambda", + "MetricName": "Invocations", + "Dimensions": [ + { + "Name": "FunctionName", + "Value": { + "Ref": "EventsRuleLambdaFunction" + } + } + ] + }, + "Period": 60, + "Stat": "Sum" + }, + "ReturnData": false + } + ], + "OKActions": [], + "Threshold": 0, + "TreatMissingData": "notBreaching" + }, + "Type": "AWS::CloudWatch::Alarm" + }, "slicWatchLambdaThrottlesAlarmHelloLambdaFunction": { "Properties": { "ActionsEnabled": true, diff --git a/test-utils/sls-test-utils.ts b/test-utils/sls-test-utils.ts index 4c8311e4..e4368d3d 100644 --- a/test-utils/sls-test-utils.ts +++ b/test-utils/sls-test-utils.ts @@ -5,7 +5,7 @@ import pino from 'pino' const extras = ['levels', 'silent', 'onChild', 'trace', 'debug', 'info', 'warn', 'error', 'fatal'] const pinoLogger = pino() export const dummyLogger = Object.fromEntries( - Object.entries(pinoLogger).filter(([key]) => !extras.includes(key as string)) + Object.entries(pinoLogger).filter(([key]) => !extras.includes(key)) ) export const pluginUtils = { log: dummyLogger } diff --git a/test-utils/snapshot-utils.ts b/test-utils/snapshot-utils.ts index 9a8a6e83..06b589a1 100644 --- a/test-utils/snapshot-utils.ts +++ b/test-utils/snapshot-utils.ts @@ -20,9 +20,9 @@ export function formatSnapshot (template: Template): string { */ export function sortObject (obj: object): object { const sortedObj: Record = {} - for (const [key, value] of Object.entries(obj).toSorted(([a], [b]) => (a as string).localeCompare(b as string))) { + for (const [key, value] of Object.entries(obj).sort(([a], [b]) => (a).localeCompare(b))) { if (typeof value === 'object' && value !== null && !Array.isArray(value)) { - const obj = value as any + const obj = value sortedObj[key] = sortObject(typeof obj.toJSON === 'function' ? obj.toJSON() : obj) } else { sortedObj[key] = value From e1f3b0d29326339d354e8ee0ac88696c5d658fce Mon Sep 17 00:00:00 2001 From: Eoin Shanaghy Date: Mon, 4 Dec 2023 18:33:04 +0000 Subject: [PATCH 26/35] chore: restore SLIC Watch to sam-test-project --- sam-test-project/template.yaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sam-test-project/template.yaml b/sam-test-project/template.yaml index 89221f28..1247c826 100755 --- a/sam-test-project/template.yaml +++ b/sam-test-project/template.yaml @@ -2,6 +2,7 @@ AWSTemplateFormatVersion: 2010-09-09 Description: sam-test-project Transform: - AWS::Serverless-2016-10-31 + - SlicWatch-v3 Metadata: slicWatch: enabled: true @@ -228,4 +229,4 @@ Resources: Projection: NonKeyAttributes: - name - ProjectionType: INCLUDE \ No newline at end of file + ProjectionType: INCLUDE From 2c216ebb1f7c82600f2aa65f159b561bcd252272 Mon Sep 17 00:00:00 2001 From: Eoin Shanaghy Date: Tue, 5 Dec 2023 16:37:39 +0000 Subject: [PATCH 27/35] chore: update docs for resource-level customisations --- README.md | 53 +++++++- cdk-test-project/source/general-stack.ts | 18 +++ .../CdkGeneralStackTest-Europe.template.json | 16 ++- .../CdkGeneralStackTest-US.template.json | 16 ++- sam-test-project/template.yaml | 11 ++ ...sam-test-project-transformed-template.json | 33 +++-- serverless-plugin/serverless-plugin.ts | 5 +- serverless-test-project/sls-resources.yml | 10 ++ .../cloudformation-template-update-stack.json | 105 +++++++++------- ...cdk-test-project-snapshot.test.ts.test.cjs | 64 +++++----- ...sam-test-project-snapshot.test.ts.test.cjs | 51 ++++---- ...ess-test-project-snapshot.test.ts.test.cjs | 115 ++++++++++-------- 12 files changed, 335 insertions(+), 162 deletions(-) diff --git a/README.md b/README.md index d61cb87e..95d5cc43 100644 --- a/README.md +++ b/README.md @@ -36,7 +36,7 @@ Supported tools include: - [AppSync](#appsync) - [Configuration](#configuration) - [Top-level configuration](#top-level-configuration) - - [Function-level configuration](#function-level-configuration) + - [Resource-level configuration](#resource-level-configuration) - [Serverless Framework function-level configuration](#serverless-framework-function-level-configuration) - [SAM/CloudFormation function-level configuration](#samcloudformation-function-level-configuration) - [CDK function-level configuration](#cdk-function-level-configuration) @@ -337,10 +337,10 @@ Configuration is entirely optional - SLIC Watch provides defaults that work out You can customize the configuration: - at the top level, for all resources in each service, and/or -- at the level of individual functions. +- at the level of individual resources ### Top-level configuration -SLIC Watch configuration can be specified: +Top-level SLIC Watch configuration can be specified for all resources of each type: - For *Serverless Framework applications*, in the `custom` → `slicWatch` section of `serverless.yml`: ```yaml custom: @@ -385,11 +385,53 @@ Example projects are also provided for reference: - [serverless-test-project](./serverless-test-project) - [sam-test-project](./sam-test-project) -### Function-level configuration +### Resource-level configuration -For each function, add the `slicWatch` property to configure specific overrides for alarms and dashboards relating to the AWS Lambda Function resource. +Alarms and dashboards for each resource can be customised using CloudFormation metadata. This configuration will take precedence over the top-level configuration. + +```yaml +Resources: + regularQueue: + Type: AWS::SQS::Queue + Metadata: + slicWatch: + alarms: + InFlightMessagesPc: + Threshold: 95 + dashboard: + ApproximateAgeOfOldestMessage: + yAxis: right + NumberOfMessagesReceived: + enabled: false +``` + +This can be done for any CloudFormation, AWS and SAM resource. It can also be done for CDK with the following syntax. + +```typescript +const dlq = new sqs.Queue(this, 'DeadLetterQueue') +const cfnDlq = dlq.node.defaultChild as CfnResource +cfnDlq.cfnOptions.metadata = { + slicWatch: { + alarms: { + InFlightMessagesPc: { + Threshold: 95 + } + }, + dashboard: { + ApproximateAgeOfOldestMessage: { + yAxis: 'right' + }, + NumberOfMessagesReceived: { + enabled: false + } + } + } +} +``` #### Serverless Framework function-level configuration +Function-level configuration works a bit differently for Serverless Framework functions. Here, the `slicWatch` configuration parameter is set directly on the function: For each function, add the `slicWatch` property to configure specific overrides for alarms and dashboards relating to the AWS Lambda Function resource. + ```yaml functions: hello: @@ -447,6 +489,7 @@ Resources: Lambda: enabled: false ``` + #### CDK function-level configuration ```typescript const hello: lambda.Function; diff --git a/cdk-test-project/source/general-stack.ts b/cdk-test-project/source/general-stack.ts index 5db34168..da208dd1 100644 --- a/cdk-test-project/source/general-stack.ts +++ b/cdk-test-project/source/general-stack.ts @@ -128,5 +128,23 @@ export class CdkTestGeneralStack extends cdk.Stack { maxEventAge: cdk.Duration.hours(2), // Optional: set the maxEventAge retry policy retryAttempts: 2 // Optional: set the max number of retry attempts })) + const cfnDlq = dlq.node.defaultChild as CfnResource + cfnDlq.cfnOptions.metadata = { + slicWatch: { + alarms: { + InFlightMessagesPc: { + Threshold: 95 + } + }, + dashboard: { + ApproximateAgeOfOldestMessage: { + yAxis: 'right' + }, + NumberOfMessagesReceived: { + enabled: false + } + } + } + } } } diff --git a/cdk-test-project/tests/snapshot/fixtures/CdkGeneralStackTest-Europe.template.json b/cdk-test-project/tests/snapshot/fixtures/CdkGeneralStackTest-Europe.template.json index 36e6061a..ba028679 100644 --- a/cdk-test-project/tests/snapshot/fixtures/CdkGeneralStackTest-Europe.template.json +++ b/cdk-test-project/tests/snapshot/fixtures/CdkGeneralStackTest-Europe.template.json @@ -853,7 +853,21 @@ "UpdateReplacePolicy": "Delete", "DeletionPolicy": "Delete", "Metadata": { - "aws:cdk:path": "CdkGeneralStackTest-Europe/DeadLetterQueue/Resource" + "slicWatch": { + "alarms": { + "InFlightMessagesPc": { + "Threshold": 95 + } + }, + "dashboard": { + "ApproximateAgeOfOldestMessage": { + "yAxis": "right" + }, + "NumberOfMessagesReceived": { + "enabled": false + } + } + } } }, "DeadLetterQueuePolicyB1FB890C": { diff --git a/cdk-test-project/tests/snapshot/fixtures/CdkGeneralStackTest-US.template.json b/cdk-test-project/tests/snapshot/fixtures/CdkGeneralStackTest-US.template.json index fe6080b0..b013ae49 100644 --- a/cdk-test-project/tests/snapshot/fixtures/CdkGeneralStackTest-US.template.json +++ b/cdk-test-project/tests/snapshot/fixtures/CdkGeneralStackTest-US.template.json @@ -853,7 +853,21 @@ "UpdateReplacePolicy": "Delete", "DeletionPolicy": "Delete", "Metadata": { - "aws:cdk:path": "CdkGeneralStackTest-US/DeadLetterQueue/Resource" + "slicWatch": { + "alarms": { + "InFlightMessagesPc": { + "Threshold": 95 + } + }, + "dashboard": { + "ApproximateAgeOfOldestMessage": { + "yAxis": "right" + }, + "NumberOfMessagesReceived": { + "enabled": false + } + } + } } }, "DeadLetterQueuePolicyB1FB890C": { diff --git a/sam-test-project/template.yaml b/sam-test-project/template.yaml index 1247c826..18e92627 100755 --- a/sam-test-project/template.yaml +++ b/sam-test-project/template.yaml @@ -131,6 +131,17 @@ Resources: ShardCount: 1 regularQueue: Type: AWS::SQS::Queue + Metadata: + slicWatch: + alarms: + InFlightMessagesPc: + Threshold: 95 + dashboard: + ApproximateAgeOfOldestMessage: + yAxis: right + NumberOfMessagesReceived: + enabled: false + fifoQueue: Type: AWS::SQS::Queue Properties: diff --git a/sam-test-project/tests/snapshot/fixtures/sam-test-project-transformed-template.json b/sam-test-project/tests/snapshot/fixtures/sam-test-project-transformed-template.json index 51eaa214..61563f5d 100644 --- a/sam-test-project/tests/snapshot/fixtures/sam-test-project-transformed-template.json +++ b/sam-test-project/tests/snapshot/fixtures/sam-test-project-transformed-template.json @@ -60,6 +60,21 @@ "regularQueue": { "Type": "AWS::SQS::Queue", "Metadata": { + "slicWatch": { + "alarms": { + "InFlightMessagesPc": { + "Threshold": 95 + } + }, + "dashboard": { + "ApproximateAgeOfOldestMessage": { + "yAxis": "right" + }, + "NumberOfMessagesReceived": { + "enabled": false + } + } + }, "SamResourceId": "regularQueue" } }, @@ -272,7 +287,7 @@ "Properties": { "Code": { "S3Bucket": "aws-sam-cli-managed-default-samclisourcebucket-167xnalzxxva4", - "S3Key": "sam-test-project/810e2a73503f0ee11a4a06f488e12d55" + "S3Key": "sam-test-project/41c0564f2b084a83461942c11a0c2e07" }, "Handler": "basic-handler.hello", "Role": { @@ -333,7 +348,7 @@ "Properties": { "Code": { "S3Bucket": "aws-sam-cli-managed-default-samclisourcebucket-167xnalzxxva4", - "S3Key": "sam-test-project/810e2a73503f0ee11a4a06f488e12d55" + "S3Key": "sam-test-project/41c0564f2b084a83461942c11a0c2e07" }, "Handler": "basic-handler.hello", "Role": { @@ -389,7 +404,7 @@ "Properties": { "Code": { "S3Bucket": "aws-sam-cli-managed-default-samclisourcebucket-167xnalzxxva4", - "S3Key": "sam-test-project/810e2a73503f0ee11a4a06f488e12d55" + "S3Key": "sam-test-project/41c0564f2b084a83461942c11a0c2e07" }, "Handler": "basic-handler.hello", "Role": { @@ -446,7 +461,7 @@ "Properties": { "Code": { "S3Bucket": "aws-sam-cli-managed-default-samclisourcebucket-167xnalzxxva4", - "S3Key": "sam-test-project/810e2a73503f0ee11a4a06f488e12d55" + "S3Key": "sam-test-project/41c0564f2b084a83461942c11a0c2e07" }, "Handler": "stream-test-handler.handleDrive", "Role": { @@ -502,7 +517,7 @@ "Properties": { "Code": { "S3Bucket": "aws-sam-cli-managed-default-samclisourcebucket-167xnalzxxva4", - "S3Key": "sam-test-project/810e2a73503f0ee11a4a06f488e12d55" + "S3Key": "sam-test-project/41c0564f2b084a83461942c11a0c2e07" }, "Handler": "basic-handler.hello", "Role": { @@ -558,7 +573,7 @@ "Properties": { "Code": { "S3Bucket": "aws-sam-cli-managed-default-samclisourcebucket-167xnalzxxva4", - "S3Key": "sam-test-project/810e2a73503f0ee11a4a06f488e12d55" + "S3Key": "sam-test-project/41c0564f2b084a83461942c11a0c2e07" }, "Handler": "basic-handler.hello", "Role": { @@ -614,7 +629,7 @@ "Properties": { "Code": { "S3Bucket": "aws-sam-cli-managed-default-samclisourcebucket-167xnalzxxva4", - "S3Key": "sam-test-project/810e2a73503f0ee11a4a06f488e12d55" + "S3Key": "sam-test-project/41c0564f2b084a83461942c11a0c2e07" }, "Handler": "basic-handler.hello", "Role": { @@ -687,7 +702,7 @@ "Properties": { "Code": { "S3Bucket": "aws-sam-cli-managed-default-samclisourcebucket-167xnalzxxva4", - "S3Key": "sam-test-project/810e2a73503f0ee11a4a06f488e12d55" + "S3Key": "sam-test-project/41c0564f2b084a83461942c11a0c2e07" }, "Handler": "apigw-handler.handleGet", "Role": { @@ -770,7 +785,7 @@ "Properties": { "Code": { "S3Bucket": "aws-sam-cli-managed-default-samclisourcebucket-167xnalzxxva4", - "S3Key": "sam-test-project/810e2a73503f0ee11a4a06f488e12d55" + "S3Key": "sam-test-project/41c0564f2b084a83461942c11a0c2e07" }, "Handler": "rule-handler.handleRule", "Role": { diff --git a/serverless-plugin/serverless-plugin.ts b/serverless-plugin/serverless-plugin.ts index fe095c14..9735aa2f 100644 --- a/serverless-plugin/serverless-plugin.ts +++ b/serverless-plugin/serverless-plugin.ts @@ -63,11 +63,12 @@ class ServerlessPlugin { // Each Lambda Function declared in serverless.yml may have a slicWatch configuration // to set configuration overrides for the specific function. We transform those into // CloudFormation Metadata on the generate AWS::Lambda::Function resource - for (const funcName of this.serverless.service.getAllFunctions()) { + const allFunctions = this.serverless.service.getAllFunctions() as string[] + this.serverless.cli.log(`Setting SLIC Watch configuration for ${allFunctions}`) + for (const funcName of allFunctions) { const func = this.serverless.service.getFunction(funcName) as any const funcConfig = func.slicWatch ?? {} const functionLogicalId = awsProvider.naming.getLambdaLogicalId(funcName) - const templateResources = compiledTemplate.Resources as Record templateResources[functionLogicalId].Metadata = { ...templateResources[functionLogicalId].Metadata ?? {}, diff --git a/serverless-test-project/sls-resources.yml b/serverless-test-project/sls-resources.yml index f2d73717..ecacc6ab 100644 --- a/serverless-test-project/sls-resources.yml +++ b/serverless-test-project/sls-resources.yml @@ -59,6 +59,16 @@ Resources: NonKeyAttributes: - name ProjectionType: INCLUDE + Metadata: + slicWatch: + alarms: + UserErrors: + Threshold: 20 + dashboard: + ReadThrottleEvents: + yAxis: right + WriteThrottleEvents: + yAxis: right regularQueue: Type: "AWS::SQS::Queue" diff --git a/serverless-test-project/tests/snapshot/fixtures/cloudformation-template-update-stack.json b/serverless-test-project/tests/snapshot/fixtures/cloudformation-template-update-stack.json index ae39d840..8fe0f75c 100644 --- a/serverless-test-project/tests/snapshot/fixtures/cloudformation-template-update-stack.json +++ b/serverless-test-project/tests/snapshot/fixtures/cloudformation-template-update-stack.json @@ -233,7 +233,7 @@ "S3Bucket": { "Ref": "ServerlessDeploymentBucket" }, - "S3Key": "serverless/serverless-test-project/dev/1701242216679-2023-11-29T07:16:56.679Z/serverless-test-project.zip" + "S3Key": "serverless/serverless-test-project/dev/1701792788693-2023-12-05T16:13:08.693Z/serverless-test-project.zip" }, "Handler": "basic-handler.hello", "Runtime": "nodejs18.x", @@ -269,7 +269,7 @@ "S3Bucket": { "Ref": "ServerlessDeploymentBucket" }, - "S3Key": "serverless/serverless-test-project/dev/1701242216679-2023-11-29T07:16:56.679Z/serverless-test-project.zip" + "S3Key": "serverless/serverless-test-project/dev/1701792788693-2023-12-05T16:13:08.693Z/serverless-test-project.zip" }, "Handler": "basic-handler.hello", "Runtime": "nodejs18.x", @@ -301,7 +301,7 @@ "S3Bucket": { "Ref": "ServerlessDeploymentBucket" }, - "S3Key": "serverless/serverless-test-project/dev/1701242216679-2023-11-29T07:16:56.679Z/serverless-test-project.zip" + "S3Key": "serverless/serverless-test-project/dev/1701792788693-2023-12-05T16:13:08.693Z/serverless-test-project.zip" }, "Handler": "basic-handler.hello", "Runtime": "nodejs18.x", @@ -330,7 +330,7 @@ "S3Bucket": { "Ref": "ServerlessDeploymentBucket" }, - "S3Key": "serverless/serverless-test-project/dev/1701242216679-2023-11-29T07:16:56.679Z/serverless-test-project.zip" + "S3Key": "serverless/serverless-test-project/dev/1701792788693-2023-12-05T16:13:08.693Z/serverless-test-project.zip" }, "Handler": "stream-test-handler.handleDrive", "Runtime": "nodejs18.x", @@ -365,7 +365,7 @@ "S3Bucket": { "Ref": "ServerlessDeploymentBucket" }, - "S3Key": "serverless/serverless-test-project/dev/1701242216679-2023-11-29T07:16:56.679Z/serverless-test-project.zip" + "S3Key": "serverless/serverless-test-project/dev/1701792788693-2023-12-05T16:13:08.693Z/serverless-test-project.zip" }, "Handler": "queue-test-handler.handleDrive", "Runtime": "nodejs18.x", @@ -393,7 +393,7 @@ "S3Bucket": { "Ref": "ServerlessDeploymentBucket" }, - "S3Key": "serverless/serverless-test-project/dev/1701242216679-2023-11-29T07:16:56.679Z/serverless-test-project.zip" + "S3Key": "serverless/serverless-test-project/dev/1701792788693-2023-12-05T16:13:08.693Z/serverless-test-project.zip" }, "Handler": "table-test-hander.handleDrive", "Runtime": "nodejs18.x", @@ -421,7 +421,7 @@ "S3Bucket": { "Ref": "ServerlessDeploymentBucket" }, - "S3Key": "serverless/serverless-test-project/dev/1701242216679-2023-11-29T07:16:56.679Z/serverless-test-project.zip" + "S3Key": "serverless/serverless-test-project/dev/1701792788693-2023-12-05T16:13:08.693Z/serverless-test-project.zip" }, "Handler": "stream-handler.handle", "Runtime": "nodejs18.x", @@ -449,7 +449,7 @@ "S3Bucket": { "Ref": "ServerlessDeploymentBucket" }, - "S3Key": "serverless/serverless-test-project/dev/1701242216679-2023-11-29T07:16:56.679Z/serverless-test-project.zip" + "S3Key": "serverless/serverless-test-project/dev/1701792788693-2023-12-05T16:13:08.693Z/serverless-test-project.zip" }, "Handler": "apigw-handler.handleGet", "Runtime": "nodejs18.x", @@ -477,7 +477,7 @@ "S3Bucket": { "Ref": "ServerlessDeploymentBucket" }, - "S3Key": "serverless/serverless-test-project/dev/1701242216679-2023-11-29T07:16:56.679Z/serverless-test-project.zip" + "S3Key": "serverless/serverless-test-project/dev/1701792788693-2023-12-05T16:13:08.693Z/serverless-test-project.zip" }, "Handler": "apigw-handler.handleSubscription", "Runtime": "nodejs18.x", @@ -505,7 +505,7 @@ "S3Bucket": { "Ref": "ServerlessDeploymentBucket" }, - "S3Key": "serverless/serverless-test-project/dev/1701242216679-2023-11-29T07:16:56.679Z/serverless-test-project.zip" + "S3Key": "serverless/serverless-test-project/dev/1701792788693-2023-12-05T16:13:08.693Z/serverless-test-project.zip" }, "Handler": "rule-handler.handleRule", "Runtime": "nodejs18.x", @@ -532,104 +532,104 @@ } } }, - "HelloLambdaVersioncvZrQjYr4FdYsM3CaTj5TKuOJmUjyL07tfIDVXBSw4": { + "HelloLambdaVersionf42jv6Soivw25tYtUcrbFwOQEe9r1Gm34YtgGMrPRgk": { "Type": "AWS::Lambda::Version", "DeletionPolicy": "Retain", "Properties": { "FunctionName": { "Ref": "HelloLambdaFunction" }, - "CodeSha256": "8+6CAXAhHnCOtQPN1A6d4fRjjFV13css2+2nirSNse0=" + "CodeSha256": "x4BBRU8H8eI5d76pgM61FHBjsk7qAO0pFBi6yBCXhyM=" } }, - "PingLambdaVersionSQcuddhSFqI0xKYCyuQTTJMvwrlKCB77CNQ16xyQ": { + "PingLambdaVersionQn5C3FCwaJxuyEFz1PB1TbidW97srv2gHaU7DXZns": { "Type": "AWS::Lambda::Version", "DeletionPolicy": "Retain", "Properties": { "FunctionName": { "Ref": "PingLambdaFunction" }, - "CodeSha256": "8+6CAXAhHnCOtQPN1A6d4fRjjFV13css2+2nirSNse0=" + "CodeSha256": "x4BBRU8H8eI5d76pgM61FHBjsk7qAO0pFBi6yBCXhyM=" } }, - "ThrottlerLambdaVersion0UeWLgxZYywcyV3gGiutpyCQJEbO6Gk8zSSOP7dMEps": { + "ThrottlerLambdaVersiontRCTuOU8MbmZc930qzPjGs9fBwa7TSeXpdGX5TEBl4": { "Type": "AWS::Lambda::Version", "DeletionPolicy": "Retain", "Properties": { "FunctionName": { "Ref": "ThrottlerLambdaFunction" }, - "CodeSha256": "8+6CAXAhHnCOtQPN1A6d4fRjjFV13css2+2nirSNse0=" + "CodeSha256": "x4BBRU8H8eI5d76pgM61FHBjsk7qAO0pFBi6yBCXhyM=" } }, - "DriveStreamLambdaVersionsWkqlV7IV7mJdqIqQToVljMizTzZoDCso7qMazjI": { + "DriveStreamLambdaVersionP4u4hk59XD9172r9elN9B3yQAKgOqsVMcEqn33HWk": { "Type": "AWS::Lambda::Version", "DeletionPolicy": "Retain", "Properties": { "FunctionName": { "Ref": "DriveStreamLambdaFunction" }, - "CodeSha256": "8+6CAXAhHnCOtQPN1A6d4fRjjFV13css2+2nirSNse0=" + "CodeSha256": "x4BBRU8H8eI5d76pgM61FHBjsk7qAO0pFBi6yBCXhyM=" } }, - "DriveQueueLambdaVersionTmzx8HCxfunJ3etrLOOYLg8zG05MzRauykeVpZFz8WY": { + "DriveQueueLambdaVersionO9yL7x2X7on8V1vfBzVj8OmtJsaRIkID1qjEuFRNI": { "Type": "AWS::Lambda::Version", "DeletionPolicy": "Retain", "Properties": { "FunctionName": { "Ref": "DriveQueueLambdaFunction" }, - "CodeSha256": "8+6CAXAhHnCOtQPN1A6d4fRjjFV13css2+2nirSNse0=" + "CodeSha256": "x4BBRU8H8eI5d76pgM61FHBjsk7qAO0pFBi6yBCXhyM=" } }, - "DriveTableLambdaVersionkqI0DCnUasgza04mnCpqj0q5vePTOojYtyi4hxfE3ME": { + "DriveTableLambdaVersionCeL14112extLbZpU9IBiLCw0gjivyaXaSf664bPnc": { "Type": "AWS::Lambda::Version", "DeletionPolicy": "Retain", "Properties": { "FunctionName": { "Ref": "DriveTableLambdaFunction" }, - "CodeSha256": "8+6CAXAhHnCOtQPN1A6d4fRjjFV13css2+2nirSNse0=" + "CodeSha256": "x4BBRU8H8eI5d76pgM61FHBjsk7qAO0pFBi6yBCXhyM=" } }, - "StreamProcessorLambdaVersion24Kwch4oq5ogXKcIDJuLGB1qAJWt8aqgW43aCjKI": { + "StreamProcessorLambdaVersionVV0TLuhlwFPLxKh4EkN9lxAkgiMhMGAQYjd59YkRg4": { "Type": "AWS::Lambda::Version", "DeletionPolicy": "Retain", "Properties": { "FunctionName": { "Ref": "StreamProcessorLambdaFunction" }, - "CodeSha256": "8+6CAXAhHnCOtQPN1A6d4fRjjFV13css2+2nirSNse0=" + "CodeSha256": "x4BBRU8H8eI5d76pgM61FHBjsk7qAO0pFBi6yBCXhyM=" } }, - "HttpGetterLambdaVersionvK2ALwc1DFqBccIyulxoBU3GveALO98nQc2xP94J8": { + "HttpGetterLambdaVersionXJnLiB6AgdCzJn6ySnDV3jZfZFbgvZRNWY853JOnws": { "Type": "AWS::Lambda::Version", "DeletionPolicy": "Retain", "Properties": { "FunctionName": { "Ref": "HttpGetterLambdaFunction" }, - "CodeSha256": "8+6CAXAhHnCOtQPN1A6d4fRjjFV13css2+2nirSNse0=" + "CodeSha256": "x4BBRU8H8eI5d76pgM61FHBjsk7qAO0pFBi6yBCXhyM=" } }, - "SubscriptionHandlerLambdaVersion4kKEYaIgWsMN0XYzRQn4VAailfQcZ23kdSSOKepfB4A": { + "SubscriptionHandlerLambdaVersionRV0txVJkRLsjV5coDIOXnNx4aRSCVyx5VOtiMOYugQ": { "Type": "AWS::Lambda::Version", "DeletionPolicy": "Retain", "Properties": { "FunctionName": { "Ref": "SubscriptionHandlerLambdaFunction" }, - "CodeSha256": "8+6CAXAhHnCOtQPN1A6d4fRjjFV13css2+2nirSNse0=" + "CodeSha256": "x4BBRU8H8eI5d76pgM61FHBjsk7qAO0pFBi6yBCXhyM=" } }, - "EventsRuleLambdaVersionxBuN447jfeozyKD2CEV3oCIHhShTUOVe5XKOkBlbchQ": { + "EventsRuleLambdaVersioneJD8sIr8CoIFP1PPQEJI0gOwr9VlQOhSPmtxEJmpcA": { "Type": "AWS::Lambda::Version", "DeletionPolicy": "Retain", "Properties": { "FunctionName": { "Ref": "EventsRuleLambdaFunction" }, - "CodeSha256": "8+6CAXAhHnCOtQPN1A6d4fRjjFV13css2+2nirSNse0=" + "CodeSha256": "x4BBRU8H8eI5d76pgM61FHBjsk7qAO0pFBi6yBCXhyM=" } }, "WorkflowRole": { @@ -995,7 +995,7 @@ "SubscriptionHandlerLambdaPermissionApiGateway" ] }, - "ApiGatewayDeployment1701242215363": { + "ApiGatewayDeployment1701792785979": { "Type": "AWS::ApiGateway::Deployment", "Properties": { "RestApiId": { @@ -1277,6 +1277,23 @@ } } ] + }, + "Metadata": { + "slicWatch": { + "alarms": { + "UserErrors": { + "Threshold": 20 + } + }, + "dashboard": { + "ReadThrottleEvents": { + "yAxis": "right" + }, + "WriteThrottleEvents": { + "yAxis": "right" + } + } + } } }, "regularQueue": { @@ -1359,8 +1376,8 @@ "RequiresCompatibilities": [ "FARGATE" ], - "Cpu": 256, - "Memory": 512, + "Cpu": "256", + "Memory": "512", "ContainerDefinitions": [ { "Name": "busybox", @@ -1413,7 +1430,7 @@ "HelloLambdaFunctionQualifiedArn": { "Description": "Current Lambda function version", "Value": { - "Ref": "HelloLambdaVersioncvZrQjYr4FdYsM3CaTj5TKuOJmUjyL07tfIDVXBSw4" + "Ref": "HelloLambdaVersionf42jv6Soivw25tYtUcrbFwOQEe9r1Gm34YtgGMrPRgk" }, "Export": { "Name": "sls-serverless-test-project-dev-HelloLambdaFunctionQualifiedArn" @@ -1422,7 +1439,7 @@ "PingLambdaFunctionQualifiedArn": { "Description": "Current Lambda function version", "Value": { - "Ref": "PingLambdaVersionSQcuddhSFqI0xKYCyuQTTJMvwrlKCB77CNQ16xyQ" + "Ref": "PingLambdaVersionQn5C3FCwaJxuyEFz1PB1TbidW97srv2gHaU7DXZns" }, "Export": { "Name": "sls-serverless-test-project-dev-PingLambdaFunctionQualifiedArn" @@ -1431,7 +1448,7 @@ "ThrottlerLambdaFunctionQualifiedArn": { "Description": "Current Lambda function version", "Value": { - "Ref": "ThrottlerLambdaVersion0UeWLgxZYywcyV3gGiutpyCQJEbO6Gk8zSSOP7dMEps" + "Ref": "ThrottlerLambdaVersiontRCTuOU8MbmZc930qzPjGs9fBwa7TSeXpdGX5TEBl4" }, "Export": { "Name": "sls-serverless-test-project-dev-ThrottlerLambdaFunctionQualifiedArn" @@ -1440,7 +1457,7 @@ "DriveStreamLambdaFunctionQualifiedArn": { "Description": "Current Lambda function version", "Value": { - "Ref": "DriveStreamLambdaVersionsWkqlV7IV7mJdqIqQToVljMizTzZoDCso7qMazjI" + "Ref": "DriveStreamLambdaVersionP4u4hk59XD9172r9elN9B3yQAKgOqsVMcEqn33HWk" }, "Export": { "Name": "sls-serverless-test-project-dev-DriveStreamLambdaFunctionQualifiedArn" @@ -1449,7 +1466,7 @@ "DriveQueueLambdaFunctionQualifiedArn": { "Description": "Current Lambda function version", "Value": { - "Ref": "DriveQueueLambdaVersionTmzx8HCxfunJ3etrLOOYLg8zG05MzRauykeVpZFz8WY" + "Ref": "DriveQueueLambdaVersionO9yL7x2X7on8V1vfBzVj8OmtJsaRIkID1qjEuFRNI" }, "Export": { "Name": "sls-serverless-test-project-dev-DriveQueueLambdaFunctionQualifiedArn" @@ -1458,7 +1475,7 @@ "DriveTableLambdaFunctionQualifiedArn": { "Description": "Current Lambda function version", "Value": { - "Ref": "DriveTableLambdaVersionkqI0DCnUasgza04mnCpqj0q5vePTOojYtyi4hxfE3ME" + "Ref": "DriveTableLambdaVersionCeL14112extLbZpU9IBiLCw0gjivyaXaSf664bPnc" }, "Export": { "Name": "sls-serverless-test-project-dev-DriveTableLambdaFunctionQualifiedArn" @@ -1467,7 +1484,7 @@ "StreamProcessorLambdaFunctionQualifiedArn": { "Description": "Current Lambda function version", "Value": { - "Ref": "StreamProcessorLambdaVersion24Kwch4oq5ogXKcIDJuLGB1qAJWt8aqgW43aCjKI" + "Ref": "StreamProcessorLambdaVersionVV0TLuhlwFPLxKh4EkN9lxAkgiMhMGAQYjd59YkRg4" }, "Export": { "Name": "sls-serverless-test-project-dev-StreamProcessorLambdaFunctionQualifiedArn" @@ -1476,7 +1493,7 @@ "HttpGetterLambdaFunctionQualifiedArn": { "Description": "Current Lambda function version", "Value": { - "Ref": "HttpGetterLambdaVersionvK2ALwc1DFqBccIyulxoBU3GveALO98nQc2xP94J8" + "Ref": "HttpGetterLambdaVersionXJnLiB6AgdCzJn6ySnDV3jZfZFbgvZRNWY853JOnws" }, "Export": { "Name": "sls-serverless-test-project-dev-HttpGetterLambdaFunctionQualifiedArn" @@ -1485,7 +1502,7 @@ "SubscriptionHandlerLambdaFunctionQualifiedArn": { "Description": "Current Lambda function version", "Value": { - "Ref": "SubscriptionHandlerLambdaVersion4kKEYaIgWsMN0XYzRQn4VAailfQcZ23kdSSOKepfB4A" + "Ref": "SubscriptionHandlerLambdaVersionRV0txVJkRLsjV5coDIOXnNx4aRSCVyx5VOtiMOYugQ" }, "Export": { "Name": "sls-serverless-test-project-dev-SubscriptionHandlerLambdaFunctionQualifiedArn" @@ -1494,7 +1511,7 @@ "EventsRuleLambdaFunctionQualifiedArn": { "Description": "Current Lambda function version", "Value": { - "Ref": "EventsRuleLambdaVersionxBuN447jfeozyKD2CEV3oCIHhShTUOVe5XKOkBlbchQ" + "Ref": "EventsRuleLambdaVersioneJD8sIr8CoIFP1PPQEJI0gOwr9VlQOhSPmtxEJmpcA" }, "Export": { "Name": "sls-serverless-test-project-dev-EventsRuleLambdaFunctionQualifiedArn" @@ -1545,4 +1562,4 @@ } } } -} +} \ No newline at end of file diff --git a/tap-snapshots/cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts.test.cjs b/tap-snapshots/cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts.test.cjs index 0e5ea6fb..19291f4b 100644 --- a/tap-snapshots/cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts.test.cjs +++ b/tap-snapshots/cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts.test.cjs @@ -1358,7 +1358,21 @@ exports[`cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts > TAP "DeadLetterQueue9F481546": { "DeletionPolicy": "Delete", "Metadata": { - "aws:cdk:path": "CdkGeneralStackTest-Europe/DeadLetterQueue/Resource" + "slicWatch": { + "alarms": { + "InFlightMessagesPc": { + "Threshold": 95 + } + }, + "dashboard": { + "ApproximateAgeOfOldestMessage": { + "yAxis": "right" + }, + "NumberOfMessagesReceived": { + "enabled": false + } + } + } }, "Type": "AWS::SQS::Queue", "UpdateReplacePolicy": "Delete" @@ -2883,16 +2897,6 @@ exports[`cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts > TAP "yAxis": "left" } ], - [ - "AWS/SQS", - "NumberOfMessagesReceived", - "QueueName", - "\${DeadLetterQueue9F481546.QueueName}", - { - "stat": "Sum", - "yAxis": "left" - } - ], [ "AWS/SQS", "NumberOfMessagesDeleted", @@ -2925,7 +2929,7 @@ exports[`cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts > TAP "\${DeadLetterQueue9F481546.QueueName}", { "stat": "Maximum", - "yAxis": "left" + "yAxis": "right" } ] ], @@ -4402,7 +4406,7 @@ exports[`cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts > TAP ], "AlarmDescription": { "Fn::Sub": [ - "SQS in-flight messages for \${DeadLetterQueue9F481546.QueueName} breaches 1200 (1% of the hard limit of 120000)", + "SQS in-flight messages for \${DeadLetterQueue9F481546.QueueName} breaches 114000 (95% of the hard limit of 120000)", {} ] }, @@ -4430,7 +4434,7 @@ exports[`cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts > TAP "OKActions": [], "Period": 60, "Statistic": "Maximum", - "Threshold": 1200, + "Threshold": 114000, "TreatMissingData": "notBreaching" }, "Type": "AWS::CloudWatch::Alarm" @@ -4834,7 +4838,21 @@ exports[`cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts > TAP "DeadLetterQueue9F481546": { "DeletionPolicy": "Delete", "Metadata": { - "aws:cdk:path": "CdkGeneralStackTest-US/DeadLetterQueue/Resource" + "slicWatch": { + "alarms": { + "InFlightMessagesPc": { + "Threshold": 95 + } + }, + "dashboard": { + "ApproximateAgeOfOldestMessage": { + "yAxis": "right" + }, + "NumberOfMessagesReceived": { + "enabled": false + } + } + } }, "Type": "AWS::SQS::Queue", "UpdateReplacePolicy": "Delete" @@ -6359,16 +6377,6 @@ exports[`cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts > TAP "yAxis": "left" } ], - [ - "AWS/SQS", - "NumberOfMessagesReceived", - "QueueName", - "\${DeadLetterQueue9F481546.QueueName}", - { - "stat": "Sum", - "yAxis": "left" - } - ], [ "AWS/SQS", "NumberOfMessagesDeleted", @@ -6401,7 +6409,7 @@ exports[`cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts > TAP "\${DeadLetterQueue9F481546.QueueName}", { "stat": "Maximum", - "yAxis": "left" + "yAxis": "right" } ] ], @@ -7878,7 +7886,7 @@ exports[`cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts > TAP ], "AlarmDescription": { "Fn::Sub": [ - "SQS in-flight messages for \${DeadLetterQueue9F481546.QueueName} breaches 1200 (1% of the hard limit of 120000)", + "SQS in-flight messages for \${DeadLetterQueue9F481546.QueueName} breaches 114000 (95% of the hard limit of 120000)", {} ] }, @@ -7906,7 +7914,7 @@ exports[`cdk-test-project/tests/snapshot/cdk-test-project-snapshot.test.ts > TAP "OKActions": [], "Period": 60, "Statistic": "Maximum", - "Threshold": 1200, + "Threshold": 114000, "TreatMissingData": "notBreaching" }, "Type": "AWS::CloudWatch::Alarm" diff --git a/tap-snapshots/sam-test-project/tests/snapshot/sam-test-project-snapshot.test.ts.test.cjs b/tap-snapshots/sam-test-project/tests/snapshot/sam-test-project-snapshot.test.ts.test.cjs index d7c70649..be3b75aa 100644 --- a/tap-snapshots/sam-test-project/tests/snapshot/sam-test-project-snapshot.test.ts.test.cjs +++ b/tap-snapshots/sam-test-project/tests/snapshot/sam-test-project-snapshot.test.ts.test.cjs @@ -145,7 +145,7 @@ exports[`sam-test-project/tests/snapshot/sam-test-project-snapshot.test.ts > TAP "Properties": { "Code": { "S3Bucket": "aws-sam-cli-managed-default-samclisourcebucket-167xnalzxxva4", - "S3Key": "sam-test-project/810e2a73503f0ee11a4a06f488e12d55" + "S3Key": "sam-test-project/41c0564f2b084a83461942c11a0c2e07" }, "Handler": "basic-handler.hello", "Role": { @@ -201,7 +201,7 @@ exports[`sam-test-project/tests/snapshot/sam-test-project-snapshot.test.ts > TAP "Properties": { "Code": { "S3Bucket": "aws-sam-cli-managed-default-samclisourcebucket-167xnalzxxva4", - "S3Key": "sam-test-project/810e2a73503f0ee11a4a06f488e12d55" + "S3Key": "sam-test-project/41c0564f2b084a83461942c11a0c2e07" }, "Handler": "stream-test-handler.handleDrive", "Role": { @@ -257,7 +257,7 @@ exports[`sam-test-project/tests/snapshot/sam-test-project-snapshot.test.ts > TAP "Properties": { "Code": { "S3Bucket": "aws-sam-cli-managed-default-samclisourcebucket-167xnalzxxva4", - "S3Key": "sam-test-project/810e2a73503f0ee11a4a06f488e12d55" + "S3Key": "sam-test-project/41c0564f2b084a83461942c11a0c2e07" }, "Handler": "basic-handler.hello", "Role": { @@ -351,7 +351,7 @@ exports[`sam-test-project/tests/snapshot/sam-test-project-snapshot.test.ts > TAP "Properties": { "Code": { "S3Bucket": "aws-sam-cli-managed-default-samclisourcebucket-167xnalzxxva4", - "S3Key": "sam-test-project/810e2a73503f0ee11a4a06f488e12d55" + "S3Key": "sam-test-project/41c0564f2b084a83461942c11a0c2e07" }, "Handler": "rule-handler.handleRule", "Role": { @@ -464,7 +464,7 @@ exports[`sam-test-project/tests/snapshot/sam-test-project-snapshot.test.ts > TAP "Properties": { "Code": { "S3Bucket": "aws-sam-cli-managed-default-samclisourcebucket-167xnalzxxva4", - "S3Key": "sam-test-project/810e2a73503f0ee11a4a06f488e12d55" + "S3Key": "sam-test-project/41c0564f2b084a83461942c11a0c2e07" }, "Handler": "basic-handler.hello", "Role": { @@ -520,7 +520,7 @@ exports[`sam-test-project/tests/snapshot/sam-test-project-snapshot.test.ts > TAP "Properties": { "Code": { "S3Bucket": "aws-sam-cli-managed-default-samclisourcebucket-167xnalzxxva4", - "S3Key": "sam-test-project/810e2a73503f0ee11a4a06f488e12d55" + "S3Key": "sam-test-project/41c0564f2b084a83461942c11a0c2e07" }, "Handler": "apigw-handler.handleGet", "Role": { @@ -612,7 +612,7 @@ exports[`sam-test-project/tests/snapshot/sam-test-project-snapshot.test.ts > TAP "Properties": { "Code": { "S3Bucket": "aws-sam-cli-managed-default-samclisourcebucket-167xnalzxxva4", - "S3Key": "sam-test-project/810e2a73503f0ee11a4a06f488e12d55" + "S3Key": "sam-test-project/41c0564f2b084a83461942c11a0c2e07" }, "Handler": "basic-handler.hello", "Role": { @@ -663,7 +663,22 @@ exports[`sam-test-project/tests/snapshot/sam-test-project-snapshot.test.ts > TAP }, "regularQueue": { "Metadata": { - "SamResourceId": "regularQueue" + "SamResourceId": "regularQueue", + "slicWatch": { + "alarms": { + "InFlightMessagesPc": { + "Threshold": 95 + } + }, + "dashboard": { + "ApproximateAgeOfOldestMessage": { + "yAxis": "right" + }, + "NumberOfMessagesReceived": { + "enabled": false + } + } + } }, "Type": "AWS::SQS::Queue" }, @@ -1679,16 +1694,6 @@ exports[`sam-test-project/tests/snapshot/sam-test-project-snapshot.test.ts > TAP "yAxis": "left" } ], - [ - "AWS/SQS", - "NumberOfMessagesReceived", - "QueueName", - "\${regularQueue.QueueName}", - { - "stat": "Sum", - "yAxis": "left" - } - ], [ "AWS/SQS", "NumberOfMessagesDeleted", @@ -1721,7 +1726,7 @@ exports[`sam-test-project/tests/snapshot/sam-test-project-snapshot.test.ts > TAP "\${regularQueue.QueueName}", { "stat": "Maximum", - "yAxis": "left" + "yAxis": "right" } ] ], @@ -4425,7 +4430,7 @@ exports[`sam-test-project/tests/snapshot/sam-test-project-snapshot.test.ts > TAP ], "AlarmDescription": { "Fn::Sub": [ - "SQS in-flight messages for \${regularQueue.QueueName} breaches 1200 (1% of the hard limit of 120000)", + "SQS in-flight messages for \${regularQueue.QueueName} breaches 114000 (95% of the hard limit of 120000)", {} ] }, @@ -4457,7 +4462,7 @@ exports[`sam-test-project/tests/snapshot/sam-test-project-snapshot.test.ts > TAP ], "Period": 60, "Statistic": "Maximum", - "Threshold": 1200, + "Threshold": 114000, "TreatMissingData": "notBreaching" }, "Type": "AWS::CloudWatch::Alarm" @@ -4880,7 +4885,7 @@ exports[`sam-test-project/tests/snapshot/sam-test-project-snapshot.test.ts > TAP "Properties": { "Code": { "S3Bucket": "aws-sam-cli-managed-default-samclisourcebucket-167xnalzxxva4", - "S3Key": "sam-test-project/810e2a73503f0ee11a4a06f488e12d55" + "S3Key": "sam-test-project/41c0564f2b084a83461942c11a0c2e07" }, "Handler": "basic-handler.hello", "Role": { @@ -5119,7 +5124,7 @@ exports[`sam-test-project/tests/snapshot/sam-test-project-snapshot.test.ts > TAP "Properties": { "Code": { "S3Bucket": "aws-sam-cli-managed-default-samclisourcebucket-167xnalzxxva4", - "S3Key": "sam-test-project/810e2a73503f0ee11a4a06f488e12d55" + "S3Key": "sam-test-project/41c0564f2b084a83461942c11a0c2e07" }, "Handler": "basic-handler.hello", "ReservedConcurrentExecutions": 0, diff --git a/tap-snapshots/serverless-test-project/tests/snapshot/serverless-test-project-snapshot.test.ts.test.cjs b/tap-snapshots/serverless-test-project/tests/snapshot/serverless-test-project-snapshot.test.ts.test.cjs index 93211aad..9e05d180 100644 --- a/tap-snapshots/serverless-test-project/tests/snapshot/serverless-test-project-snapshot.test.ts.test.cjs +++ b/tap-snapshots/serverless-test-project/tests/snapshot/serverless-test-project-snapshot.test.ts.test.cjs @@ -16,7 +16,7 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "Name": "sls-serverless-test-project-dev-DriveQueueLambdaFunctionQualifiedArn" }, "Value": { - "Ref": "DriveQueueLambdaVersionTmzx8HCxfunJ3etrLOOYLg8zG05MzRauykeVpZFz8WY" + "Ref": "DriveQueueLambdaVersionO9yL7x2X7on8V1vfBzVj8OmtJsaRIkID1qjEuFRNI" } }, "DriveStreamLambdaFunctionQualifiedArn": { @@ -25,7 +25,7 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "Name": "sls-serverless-test-project-dev-DriveStreamLambdaFunctionQualifiedArn" }, "Value": { - "Ref": "DriveStreamLambdaVersionsWkqlV7IV7mJdqIqQToVljMizTzZoDCso7qMazjI" + "Ref": "DriveStreamLambdaVersionP4u4hk59XD9172r9elN9B3yQAKgOqsVMcEqn33HWk" } }, "DriveTableLambdaFunctionQualifiedArn": { @@ -34,7 +34,7 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "Name": "sls-serverless-test-project-dev-DriveTableLambdaFunctionQualifiedArn" }, "Value": { - "Ref": "DriveTableLambdaVersionkqI0DCnUasgza04mnCpqj0q5vePTOojYtyi4hxfE3ME" + "Ref": "DriveTableLambdaVersionCeL14112extLbZpU9IBiLCw0gjivyaXaSf664bPnc" } }, "EventsRuleLambdaFunctionQualifiedArn": { @@ -43,7 +43,7 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "Name": "sls-serverless-test-project-dev-EventsRuleLambdaFunctionQualifiedArn" }, "Value": { - "Ref": "EventsRuleLambdaVersionxBuN447jfeozyKD2CEV3oCIHhShTUOVe5XKOkBlbchQ" + "Ref": "EventsRuleLambdaVersioneJD8sIr8CoIFP1PPQEJI0gOwr9VlQOhSPmtxEJmpcA" } }, "ExpressWorkflowArn": { @@ -61,7 +61,7 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "Name": "sls-serverless-test-project-dev-HelloLambdaFunctionQualifiedArn" }, "Value": { - "Ref": "HelloLambdaVersioncvZrQjYr4FdYsM3CaTj5TKuOJmUjyL07tfIDVXBSw4" + "Ref": "HelloLambdaVersionf42jv6Soivw25tYtUcrbFwOQEe9r1Gm34YtgGMrPRgk" } }, "HttpGetterLambdaFunctionQualifiedArn": { @@ -70,7 +70,7 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "Name": "sls-serverless-test-project-dev-HttpGetterLambdaFunctionQualifiedArn" }, "Value": { - "Ref": "HttpGetterLambdaVersionvK2ALwc1DFqBccIyulxoBU3GveALO98nQc2xP94J8" + "Ref": "HttpGetterLambdaVersionXJnLiB6AgdCzJn6ySnDV3jZfZFbgvZRNWY853JOnws" } }, "PingLambdaFunctionQualifiedArn": { @@ -79,7 +79,7 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "Name": "sls-serverless-test-project-dev-PingLambdaFunctionQualifiedArn" }, "Value": { - "Ref": "PingLambdaVersionSQcuddhSFqI0xKYCyuQTTJMvwrlKCB77CNQ16xyQ" + "Ref": "PingLambdaVersionQn5C3FCwaJxuyEFz1PB1TbidW97srv2gHaU7DXZns" } }, "ServerlessDeploymentBucketName": { @@ -122,7 +122,7 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "Name": "sls-serverless-test-project-dev-StreamProcessorLambdaFunctionQualifiedArn" }, "Value": { - "Ref": "StreamProcessorLambdaVersion24Kwch4oq5ogXKcIDJuLGB1qAJWt8aqgW43aCjKI" + "Ref": "StreamProcessorLambdaVersionVV0TLuhlwFPLxKh4EkN9lxAkgiMhMGAQYjd59YkRg4" } }, "SubscriptionHandlerLambdaFunctionQualifiedArn": { @@ -131,7 +131,7 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "Name": "sls-serverless-test-project-dev-SubscriptionHandlerLambdaFunctionQualifiedArn" }, "Value": { - "Ref": "SubscriptionHandlerLambdaVersion4kKEYaIgWsMN0XYzRQn4VAailfQcZ23kdSSOKepfB4A" + "Ref": "SubscriptionHandlerLambdaVersionRV0txVJkRLsjV5coDIOXnNx4aRSCVyx5VOtiMOYugQ" } }, "ThrottlerLambdaFunctionQualifiedArn": { @@ -140,7 +140,7 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "Name": "sls-serverless-test-project-dev-ThrottlerLambdaFunctionQualifiedArn" }, "Value": { - "Ref": "ThrottlerLambdaVersion0UeWLgxZYywcyV3gGiutpyCQJEbO6Gk8zSSOP7dMEps" + "Ref": "ThrottlerLambdaVersiontRCTuOU8MbmZc930qzPjGs9fBwa7TSeXpdGX5TEBl4" } }, "WorkflowArn": { @@ -154,7 +154,7 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot } }, "Resources": { - "ApiGatewayDeployment1701242215363": { + "ApiGatewayDeployment1701792785979": { "DependsOn": [ "ApiGatewayMethodItemGet", "ApiGatewayMethodSubscriptionPost" @@ -311,6 +311,23 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot }, "dataTable": { "DeletionPolicy": "Delete", + "Metadata": { + "slicWatch": { + "alarms": { + "UserErrors": { + "Threshold": 20 + } + }, + "dashboard": { + "ReadThrottleEvents": { + "yAxis": "right" + }, + "WriteThrottleEvents": { + "yAxis": "right" + } + } + } + }, "Properties": { "AttributeDefinitions": [ { @@ -410,7 +427,7 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "S3Bucket": { "Ref": "ServerlessDeploymentBucket" }, - "S3Key": "serverless/serverless-test-project/dev/1701242216679-2023-11-29T07:16:56.679Z/serverless-test-project.zip" + "S3Key": "serverless/serverless-test-project/dev/1701792788693-2023-12-05T16:13:08.693Z/serverless-test-project.zip" }, "FunctionName": "serverless-test-project-dev-driveQueue", "Handler": "queue-test-handler.handleDrive", @@ -426,10 +443,10 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot }, "Type": "AWS::Lambda::Function" }, - "DriveQueueLambdaVersionTmzx8HCxfunJ3etrLOOYLg8zG05MzRauykeVpZFz8WY": { + "DriveQueueLambdaVersionO9yL7x2X7on8V1vfBzVj8OmtJsaRIkID1qjEuFRNI": { "DeletionPolicy": "Retain", "Properties": { - "CodeSha256": "8+6CAXAhHnCOtQPN1A6d4fRjjFV13css2+2nirSNse0=", + "CodeSha256": "x4BBRU8H8eI5d76pgM61FHBjsk7qAO0pFBi6yBCXhyM=", "FunctionName": { "Ref": "DriveQueueLambdaFunction" } @@ -454,7 +471,7 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "S3Bucket": { "Ref": "ServerlessDeploymentBucket" }, - "S3Key": "serverless/serverless-test-project/dev/1701242216679-2023-11-29T07:16:56.679Z/serverless-test-project.zip" + "S3Key": "serverless/serverless-test-project/dev/1701792788693-2023-12-05T16:13:08.693Z/serverless-test-project.zip" }, "Environment": { "Variables": { @@ -477,10 +494,10 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot }, "Type": "AWS::Lambda::Function" }, - "DriveStreamLambdaVersionsWkqlV7IV7mJdqIqQToVljMizTzZoDCso7qMazjI": { + "DriveStreamLambdaVersionP4u4hk59XD9172r9elN9B3yQAKgOqsVMcEqn33HWk": { "DeletionPolicy": "Retain", "Properties": { - "CodeSha256": "8+6CAXAhHnCOtQPN1A6d4fRjjFV13css2+2nirSNse0=", + "CodeSha256": "x4BBRU8H8eI5d76pgM61FHBjsk7qAO0pFBi6yBCXhyM=", "FunctionName": { "Ref": "DriveStreamLambdaFunction" } @@ -505,7 +522,7 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "S3Bucket": { "Ref": "ServerlessDeploymentBucket" }, - "S3Key": "serverless/serverless-test-project/dev/1701242216679-2023-11-29T07:16:56.679Z/serverless-test-project.zip" + "S3Key": "serverless/serverless-test-project/dev/1701792788693-2023-12-05T16:13:08.693Z/serverless-test-project.zip" }, "FunctionName": "serverless-test-project-dev-driveTable", "Handler": "table-test-hander.handleDrive", @@ -521,10 +538,10 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot }, "Type": "AWS::Lambda::Function" }, - "DriveTableLambdaVersionkqI0DCnUasgza04mnCpqj0q5vePTOojYtyi4hxfE3ME": { + "DriveTableLambdaVersionCeL14112extLbZpU9IBiLCw0gjivyaXaSf664bPnc": { "DeletionPolicy": "Retain", "Properties": { - "CodeSha256": "8+6CAXAhHnCOtQPN1A6d4fRjjFV13css2+2nirSNse0=", + "CodeSha256": "x4BBRU8H8eI5d76pgM61FHBjsk7qAO0pFBi6yBCXhyM=", "FunctionName": { "Ref": "DriveTableLambdaFunction" } @@ -626,7 +643,7 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "S3Bucket": { "Ref": "ServerlessDeploymentBucket" }, - "S3Key": "serverless/serverless-test-project/dev/1701242216679-2023-11-29T07:16:56.679Z/serverless-test-project.zip" + "S3Key": "serverless/serverless-test-project/dev/1701792788693-2023-12-05T16:13:08.693Z/serverless-test-project.zip" }, "FunctionName": "serverless-test-project-dev-eventsRule", "Handler": "rule-handler.handleRule", @@ -642,10 +659,10 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot }, "Type": "AWS::Lambda::Function" }, - "EventsRuleLambdaVersionxBuN447jfeozyKD2CEV3oCIHhShTUOVe5XKOkBlbchQ": { + "EventsRuleLambdaVersioneJD8sIr8CoIFP1PPQEJI0gOwr9VlQOhSPmtxEJmpcA": { "DeletionPolicy": "Retain", "Properties": { - "CodeSha256": "8+6CAXAhHnCOtQPN1A6d4fRjjFV13css2+2nirSNse0=", + "CodeSha256": "x4BBRU8H8eI5d76pgM61FHBjsk7qAO0pFBi6yBCXhyM=", "FunctionName": { "Ref": "EventsRuleLambdaFunction" } @@ -807,7 +824,7 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "S3Bucket": { "Ref": "ServerlessDeploymentBucket" }, - "S3Key": "serverless/serverless-test-project/dev/1701242216679-2023-11-29T07:16:56.679Z/serverless-test-project.zip" + "S3Key": "serverless/serverless-test-project/dev/1701792788693-2023-12-05T16:13:08.693Z/serverless-test-project.zip" }, "FunctionName": "serverless-test-project-dev-hello", "Handler": "basic-handler.hello", @@ -823,10 +840,10 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot }, "Type": "AWS::Lambda::Function" }, - "HelloLambdaVersioncvZrQjYr4FdYsM3CaTj5TKuOJmUjyL07tfIDVXBSw4": { + "HelloLambdaVersionf42jv6Soivw25tYtUcrbFwOQEe9r1Gm34YtgGMrPRgk": { "DeletionPolicy": "Retain", "Properties": { - "CodeSha256": "8+6CAXAhHnCOtQPN1A6d4fRjjFV13css2+2nirSNse0=", + "CodeSha256": "x4BBRU8H8eI5d76pgM61FHBjsk7qAO0pFBi6yBCXhyM=", "FunctionName": { "Ref": "HelloLambdaFunction" } @@ -851,7 +868,7 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "S3Bucket": { "Ref": "ServerlessDeploymentBucket" }, - "S3Key": "serverless/serverless-test-project/dev/1701242216679-2023-11-29T07:16:56.679Z/serverless-test-project.zip" + "S3Key": "serverless/serverless-test-project/dev/1701792788693-2023-12-05T16:13:08.693Z/serverless-test-project.zip" }, "FunctionName": "serverless-test-project-dev-httpGetter", "Handler": "apigw-handler.handleGet", @@ -904,10 +921,10 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot }, "Type": "AWS::Lambda::Permission" }, - "HttpGetterLambdaVersionvK2ALwc1DFqBccIyulxoBU3GveALO98nQc2xP94J8": { + "HttpGetterLambdaVersionXJnLiB6AgdCzJn6ySnDV3jZfZFbgvZRNWY853JOnws": { "DeletionPolicy": "Retain", "Properties": { - "CodeSha256": "8+6CAXAhHnCOtQPN1A6d4fRjjFV13css2+2nirSNse0=", + "CodeSha256": "x4BBRU8H8eI5d76pgM61FHBjsk7qAO0pFBi6yBCXhyM=", "FunctionName": { "Ref": "HttpGetterLambdaFunction" } @@ -1031,7 +1048,7 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "S3Bucket": { "Ref": "ServerlessDeploymentBucket" }, - "S3Key": "serverless/serverless-test-project/dev/1701242216679-2023-11-29T07:16:56.679Z/serverless-test-project.zip" + "S3Key": "serverless/serverless-test-project/dev/1701792788693-2023-12-05T16:13:08.693Z/serverless-test-project.zip" }, "FunctionName": "serverless-test-project-dev-ping", "Handler": "basic-handler.hello", @@ -1047,10 +1064,10 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot }, "Type": "AWS::Lambda::Function" }, - "PingLambdaVersionSQcuddhSFqI0xKYCyuQTTJMvwrlKCB77CNQ16xyQ": { + "PingLambdaVersionQn5C3FCwaJxuyEFz1PB1TbidW97srv2gHaU7DXZns": { "DeletionPolicy": "Retain", "Properties": { - "CodeSha256": "8+6CAXAhHnCOtQPN1A6d4fRjjFV13css2+2nirSNse0=", + "CodeSha256": "x4BBRU8H8eI5d76pgM61FHBjsk7qAO0pFBi6yBCXhyM=", "FunctionName": { "Ref": "PingLambdaFunction" } @@ -1490,7 +1507,7 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "\${dataTable}", { "stat": "Sum", - "yAxis": "left" + "yAxis": "right" } ] ], @@ -1517,7 +1534,7 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "GSI1", { "stat": "Sum", - "yAxis": "left" + "yAxis": "right" } ] ], @@ -1542,7 +1559,7 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "\${dataTable}", { "stat": "Sum", - "yAxis": "left" + "yAxis": "right" } ] ], @@ -1569,7 +1586,7 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "GSI1", { "stat": "Sum", - "yAxis": "left" + "yAxis": "right" } ] ], @@ -5259,7 +5276,7 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot ], "AlarmDescription": { "Fn::Sub": [ - "DynamoDB Sum for \${dataTable} breaches 0", + "DynamoDB Sum for \${dataTable} breaches 20", {} ] }, @@ -5284,7 +5301,7 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "OKActions": [], "Period": 60, "Statistic": "Sum", - "Threshold": 0, + "Threshold": 20, "TreatMissingData": "notBreaching" }, "Type": "AWS::CloudWatch::Alarm" @@ -5372,7 +5389,7 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "S3Bucket": { "Ref": "ServerlessDeploymentBucket" }, - "S3Key": "serverless/serverless-test-project/dev/1701242216679-2023-11-29T07:16:56.679Z/serverless-test-project.zip" + "S3Key": "serverless/serverless-test-project/dev/1701792788693-2023-12-05T16:13:08.693Z/serverless-test-project.zip" }, "FunctionName": "serverless-test-project-dev-streamProcessor", "Handler": "stream-handler.handle", @@ -5388,10 +5405,10 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot }, "Type": "AWS::Lambda::Function" }, - "StreamProcessorLambdaVersion24Kwch4oq5ogXKcIDJuLGB1qAJWt8aqgW43aCjKI": { + "StreamProcessorLambdaVersionVV0TLuhlwFPLxKh4EkN9lxAkgiMhMGAQYjd59YkRg4": { "DeletionPolicy": "Retain", "Properties": { - "CodeSha256": "8+6CAXAhHnCOtQPN1A6d4fRjjFV13css2+2nirSNse0=", + "CodeSha256": "x4BBRU8H8eI5d76pgM61FHBjsk7qAO0pFBi6yBCXhyM=", "FunctionName": { "Ref": "StreamProcessorLambdaFunction" } @@ -5426,7 +5443,7 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "S3Bucket": { "Ref": "ServerlessDeploymentBucket" }, - "S3Key": "serverless/serverless-test-project/dev/1701242216679-2023-11-29T07:16:56.679Z/serverless-test-project.zip" + "S3Key": "serverless/serverless-test-project/dev/1701792788693-2023-12-05T16:13:08.693Z/serverless-test-project.zip" }, "FunctionName": "serverless-test-project-dev-subscriptionHandler", "Handler": "apigw-handler.handleSubscription", @@ -5479,10 +5496,10 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot }, "Type": "AWS::Lambda::Permission" }, - "SubscriptionHandlerLambdaVersion4kKEYaIgWsMN0XYzRQn4VAailfQcZ23kdSSOKepfB4A": { + "SubscriptionHandlerLambdaVersionRV0txVJkRLsjV5coDIOXnNx4aRSCVyx5VOtiMOYugQ": { "DeletionPolicy": "Retain", "Properties": { - "CodeSha256": "8+6CAXAhHnCOtQPN1A6d4fRjjFV13css2+2nirSNse0=", + "CodeSha256": "x4BBRU8H8eI5d76pgM61FHBjsk7qAO0pFBi6yBCXhyM=", "FunctionName": { "Ref": "SubscriptionHandlerLambdaFunction" } @@ -5525,8 +5542,8 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "Essential": true } ], - "Cpu": 256, - "Memory": 512, + "Cpu": "256", + "Memory": "512", "NetworkMode": "awsvpc", "RequiresCompatibilities": [ "FARGATE" @@ -5546,7 +5563,7 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "S3Bucket": { "Ref": "ServerlessDeploymentBucket" }, - "S3Key": "serverless/serverless-test-project/dev/1701242216679-2023-11-29T07:16:56.679Z/serverless-test-project.zip" + "S3Key": "serverless/serverless-test-project/dev/1701792788693-2023-12-05T16:13:08.693Z/serverless-test-project.zip" }, "FunctionName": "serverless-test-project-dev-throttler", "Handler": "basic-handler.hello", @@ -5563,10 +5580,10 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot }, "Type": "AWS::Lambda::Function" }, - "ThrottlerLambdaVersion0UeWLgxZYywcyV3gGiutpyCQJEbO6Gk8zSSOP7dMEps": { + "ThrottlerLambdaVersiontRCTuOU8MbmZc930qzPjGs9fBwa7TSeXpdGX5TEBl4": { "DeletionPolicy": "Retain", "Properties": { - "CodeSha256": "8+6CAXAhHnCOtQPN1A6d4fRjjFV13css2+2nirSNse0=", + "CodeSha256": "x4BBRU8H8eI5d76pgM61FHBjsk7qAO0pFBi6yBCXhyM=", "FunctionName": { "Ref": "ThrottlerLambdaFunction" } From 576ceef8943a16e2f7ab2b9fd5c563431d3a7d8a Mon Sep 17 00:00:00 2001 From: Eoin Shanaghy Date: Wed, 13 Dec 2023 11:26:32 +0000 Subject: [PATCH 28/35] chore: use cloudwatch-dashboard-types@1.0.1 --- core/package.json | 2 +- package-lock.json | 16 ++++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/core/package.json b/core/package.json index ff856bd8..3e3993ab 100644 --- a/core/package.json +++ b/core/package.json @@ -36,7 +36,7 @@ "yaml": "^1.10.2" }, "devDependencies": { - "cloudwatch-dashboard-types": "^1.0.1-rc2", + "cloudwatch-dashboard-types": "^1.0.1", "ts-node": "^10.9.1" } } diff --git a/package-lock.json b/package-lock.json index 109b877b..0495c41b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -90,7 +90,7 @@ "yaml": "^1.10.2" }, "devDependencies": { - "cloudwatch-dashboard-types": "^1.0.1-rc2", + "cloudwatch-dashboard-types": "^1.0.1", "ts-node": "^10.9.1" } }, @@ -5745,9 +5745,9 @@ } }, "node_modules/cloudwatch-dashboard-types": { - "version": "1.0.1-rc2", - "resolved": "https://registry.npmjs.org/cloudwatch-dashboard-types/-/cloudwatch-dashboard-types-1.0.1-rc2.tgz", - "integrity": "sha512-8pdwBjVhaGFmEbqtfiqaZeUuf2yRb0oCaYOvHzea+0uFKH9nwVtXwB6R4GNffPk59zpZZ2kIrF9W/V581wnRjQ==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cloudwatch-dashboard-types/-/cloudwatch-dashboard-types-1.0.1.tgz", + "integrity": "sha512-AgjhUwRazWSXZAlnZFck9xbYSjEv+xVgd1rtvCbEX9Eqhbw8z7HZQ1kkpeYynBWZRL7GRInx0aGoFH+VlsWKBQ==", "dev": true }, "node_modules/co": { @@ -18239,9 +18239,9 @@ "version": "7.4.2" }, "cloudwatch-dashboard-types": { - "version": "1.0.1-rc2", - "resolved": "https://registry.npmjs.org/cloudwatch-dashboard-types/-/cloudwatch-dashboard-types-1.0.1-rc2.tgz", - "integrity": "sha512-8pdwBjVhaGFmEbqtfiqaZeUuf2yRb0oCaYOvHzea+0uFKH9nwVtXwB6R4GNffPk59zpZZ2kIrF9W/V581wnRjQ==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cloudwatch-dashboard-types/-/cloudwatch-dashboard-types-1.0.1.tgz", + "integrity": "sha512-AgjhUwRazWSXZAlnZFck9xbYSjEv+xVgd1rtvCbEX9Eqhbw8z7HZQ1kkpeYynBWZRL7GRInx0aGoFH+VlsWKBQ==", "dev": true }, "co": { @@ -22805,7 +22805,7 @@ "ajv": "^8.11.0", "case": "^1.6.3", "cloudform": "^7.4.2", - "cloudwatch-dashboard-types": "^1.0.1-rc2", + "cloudwatch-dashboard-types": "^1.0.1", "lodash": "^4.17.21", "pino": "^8.4.2", "ts-node": "^10.9.1", From e1b33ea7867ad5fcad9aacc588eca6212be244be Mon Sep 17 00:00:00 2001 From: Eoin Shanaghy Date: Wed, 13 Dec 2023 11:34:31 +0000 Subject: [PATCH 29/35] chore: fix typos and code review issues Co-authored-by: David Lynam --- README.md | 6 +++--- core/inputs/general-config.ts | 4 ++-- core/tests/testing-utils.ts | 5 +---- test-utils/snapshot-utils.ts | 3 +-- 4 files changed, 7 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 95d5cc43..5550aacc 100644 --- a/README.md +++ b/README.md @@ -133,7 +133,7 @@ Metadata: ``` See the [Configuration](#configuration) section below for more detailed instructions on fine tuning SLIC Watch to your needs. -If you want to override the default alarm and dashboard settings for each Lambda Functino resource, add the `slicWatch` property to the `Metadata` section. +If you want to override the default alarm and dashboard settings for each Lambda Function resource, add the `slicWatch` property to the `Metadata` section. ### Adding the SLIC Watch Transform to CDK Apps Once you have deployed the macro, add it to CDK Stack in the constructor of the class that extends Stack. It should be done for every Stack in the CDK App. @@ -181,7 +181,7 @@ this.templateOptions.metadata = { ## Features -CloudWatch Alarms and Dashboard widgets are created for all supported resources in the CloudFormation stack generated by The Serverless Framework. This includes generated resources as well as resources specifed explicitly in the `resources` section. +CloudWatch Alarms and Dashboard widgets are created for all supported resources in the CloudFormation stack generated by The Serverless Framework. This includes generated resources as well as resources specified explicitly in the `resources` section. Any feature can be configured or disabled completely - see the section on [configuration](#configuration) to see how. ### Lambda Functions @@ -366,7 +366,7 @@ this.templateOptions.metadata = { } ``` -- The `alarmActionsConfig` may be optionally added to specifc one or more SNS Topic destinations for all alarm status changes to `ALARM` and `OK`. If you omit destination topics, alarms are still created but are not sent to any destination. For example: +- The `alarmActionsConfig` may be optionally added to specific one or more SNS Topic destinations for all alarm status changes to `ALARM` and `OK`. If you omit destination topics, alarms are still created but are not sent to any destination. For example: ```yaml slicWatch: alarmActionsConfig: diff --git a/core/inputs/general-config.ts b/core/inputs/general-config.ts index 12866628..f7e787ed 100644 --- a/core/inputs/general-config.ts +++ b/core/inputs/general-config.ts @@ -29,8 +29,8 @@ export class ConfigError extends Error { /** * Validates and transforms the user-provided top-level configuration for SLIC Watch. - * The configuration is validated accoring to the config schema. Defaults are applied - * where not provided by the user. Finally, the alarm actions are addded. + * The configuration is validated according to the config schema. Defaults are applied + * where not provided by the user. Finally, the alarm actions are added. * * @param slicWatchConfig The user-provided configuration * @returns Resolved configuration diff --git a/core/tests/testing-utils.ts b/core/tests/testing-utils.ts index 5e26153f..c0f6147c 100644 --- a/core/tests/testing-utils.ts +++ b/core/tests/testing-utils.ts @@ -72,10 +72,7 @@ export function getDashboardWidgetsByTitle (dashboard: Dashboard, ...patterns: R return patterns.map((pattern) => { const widgets = dashboard.widgets.filter((widget) => { const props = widget.properties as MetricWidgetProperties - if (typeof props?.title === 'string') { - return pattern.test(props.title) - } - return false + return typeof props?.title === 'string' && pattern.test(props.title) }) if (widgets.length > 1) { throw new Error(`Multiple widgets found matching ${pattern}`) diff --git a/test-utils/snapshot-utils.ts b/test-utils/snapshot-utils.ts index 06b589a1..fde07bbf 100644 --- a/test-utils/snapshot-utils.ts +++ b/test-utils/snapshot-utils.ts @@ -22,8 +22,7 @@ export function sortObject (obj: object): object { const sortedObj: Record = {} for (const [key, value] of Object.entries(obj).sort(([a], [b]) => (a).localeCompare(b))) { if (typeof value === 'object' && value !== null && !Array.isArray(value)) { - const obj = value - sortedObj[key] = sortObject(typeof obj.toJSON === 'function' ? obj.toJSON() : obj) + sortedObj[key] = sortObject(typeof value.toJSON === 'function' ? value.toJSON() : value) } else { sortedObj[key] = value } From a795b01312fdfb45dc5ff0421d3cc216a83573d2 Mon Sep 17 00:00:00 2001 From: James Kyburz Date: Sat, 20 Jan 2024 17:05:54 +0000 Subject: [PATCH 30/35] fix(core): esbuild with cjs, fixes #115 --- core/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/package.json b/core/package.json index 2dceba1d..e3ff3e3c 100644 --- a/core/package.json +++ b/core/package.json @@ -12,7 +12,7 @@ "test:packages": "tap --no-check-coverage --no-coverage-report --test-regex='tests\\/.*(test.ts)'", "test:coverage": "tap --check-coverage --coverage-report=html --no-browser --branches=95 --lines=99 --statements=99 --functions=99", "test": "npm run test:packages && npm run test:coverage", - "build": "esbuild **/*.ts index.ts --outdir=dist/ --platform=node --format=esm --packages=external --bundle --sourcemap" + "build": "esbuild **/*.ts index.ts --outdir=dist/ --platform=node --format=cjs --packages=external --bundle --sourcemap" }, "tap": { "node-arg": [ From d3df602b725ae6c6a4bc79bd6351fee42722dfa6 Mon Sep 17 00:00:00 2001 From: Eoin Shanaghy Date: Mon, 22 Jan 2024 11:56:10 +0000 Subject: [PATCH 31/35] chore: update tap --- package-lock.json | 1326 ++++++++++++++++++++++++--------------------- package.json | 2 +- 2 files changed, 701 insertions(+), 627 deletions(-) diff --git a/package-lock.json b/package-lock.json index 0495c41b..4142c4e6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -47,7 +47,7 @@ "is-ci": "^3.0.1", "lint-staged": "^13.1.2", "regenerator-runtime": "^0.13.11", - "tap": "^18.5.3", + "tap": "^18.6.1", "ts-node": "^10.9.1", "type-fest": "^3.6.1", "typescript": "^4.9.5" @@ -820,8 +820,9 @@ }, "node_modules/@bcoe/v8-coverage": { "version": "0.2.3", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", + "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", + "dev": true }, "node_modules/@cspotcode/source-map-support": { "version": "0.8.1", @@ -1440,9 +1441,9 @@ } }, "node_modules/@isaacs/ts-node-temp-fork-for-pr-2009": { - "version": "10.9.1", - "resolved": "https://registry.npmjs.org/@isaacs/ts-node-temp-fork-for-pr-2009/-/ts-node-temp-fork-for-pr-2009-10.9.1.tgz", - "integrity": "sha512-MY4rUonz835NsTbd4dcgKZvZFYX9IkLnYFZV9M7GQV8t39fawafLin/Qw6VXD4yfMs4HcBq8P3ddeU0QHMH1YQ==", + "version": "10.9.5", + "resolved": "https://registry.npmjs.org/@isaacs/ts-node-temp-fork-for-pr-2009/-/ts-node-temp-fork-for-pr-2009-10.9.5.tgz", + "integrity": "sha512-hEDlwpHhIabtB+Urku8muNMEkGui0LVGlYLS3KoB9QBDf0Pw3r7q0RrfoQmFuk8CvRpGzErO3/vLQd9Ys+/g4g==", "dev": true, "dependencies": { "@cspotcode/source-map-support": "^0.8.0", @@ -1497,14 +1498,15 @@ } }, "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.14", - "dev": true, - "license": "MIT" + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", + "dev": true }, "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.20", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz", - "integrity": "sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==", + "version": "0.3.22", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.22.tgz", + "integrity": "sha512-Wf963MzWtA2sjrNt+g18IAln9lKnlRp+K2eH4jjIoF1wYeq3aMREpG09xhlhdzS0EjwU7qmUJYangWa+151vZw==", "dev": true, "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", @@ -1612,9 +1614,9 @@ } }, "node_modules/@npmcli/git": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/@npmcli/git/-/git-5.0.3.tgz", - "integrity": "sha512-UZp9NwK+AynTrKvHn5k3KviW/hA5eENmFsu3iAPe7sWRt0lFUdsY/wXIYjpDFe7cdSNwOIzbObfwgt6eL5/2zw==", + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/@npmcli/git/-/git-5.0.4.tgz", + "integrity": "sha512-nr6/WezNzuYUppzXRaYu/W4aT5rLxdXqEFupbh6e/ovlYFQ8hpu1UUPV3Ir/YTl+74iXl2ZOMlGzudh9ZPUchQ==", "dev": true, "dependencies": { "@npmcli/promise-spawn": "^7.0.0", @@ -1680,9 +1682,9 @@ } }, "node_modules/@npmcli/promise-spawn": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@npmcli/promise-spawn/-/promise-spawn-7.0.0.tgz", - "integrity": "sha512-wBqcGsMELZna0jDblGd7UXgOby45TQaMWmbFwWX+SEotk4HV6zG2t6rT9siyLhPk4P6YYqgfL1UO8nMWDBVJXQ==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/@npmcli/promise-spawn/-/promise-spawn-7.0.1.tgz", + "integrity": "sha512-P4KkF9jX3y+7yFUxgcUdDtLy+t4OlDGuEBLNs57AZsfSfg+uV6MLndqGpnl4831ggaEdXwR50XFoZP4VFtHolg==", "dev": true, "dependencies": { "which": "^4.0.0" @@ -1716,9 +1718,9 @@ } }, "node_modules/@npmcli/run-script": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@npmcli/run-script/-/run-script-7.0.2.tgz", - "integrity": "sha512-Omu0rpA8WXvcGeY6DDzyRoY1i5DkCBkzyJ+m2u7PD6quzb0TvSqdIPOkTn8ZBOj7LbbcbMfZ3c5skwSu6m8y2w==", + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/@npmcli/run-script/-/run-script-7.0.3.tgz", + "integrity": "sha512-ZMWGLHpzMq3rBGIwPyeaoaleaLMvrBrH8nugHxTi5ACkJZXTxXPtVuEH91ifgtss5hUwJQ2VDnzDBWPmz78rvg==", "dev": true, "dependencies": { "@npmcli/node-gyp": "^3.0.0", @@ -1992,9 +1994,9 @@ } }, "node_modules/@sigstore/bundle": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@sigstore/bundle/-/bundle-2.1.0.tgz", - "integrity": "sha512-89uOo6yh/oxaU8AeOUnVrTdVMcGk9Q1hJa7Hkvalc6G3Z3CupWk4Xe9djSgJm9fMkH69s0P0cVHUoKSOemLdng==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@sigstore/bundle/-/bundle-2.1.1.tgz", + "integrity": "sha512-v3/iS+1nufZdKQ5iAlQKcCsoh0jffQyABvYIxKsZQFWc4ubuGjwZklFHpDgV6O6T7vvV78SW5NHI91HFKEcxKg==", "dev": true, "dependencies": { "@sigstore/protobuf-specs": "^0.2.1" @@ -2003,6 +2005,15 @@ "node": "^16.14.0 || >=18.0.0" } }, + "node_modules/@sigstore/core": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@sigstore/core/-/core-0.2.0.tgz", + "integrity": "sha512-THobAPPZR9pDH2CAvDLpkrYedt7BlZnsyxDe+Isq4ZmGfPy5juOFZq487vCU2EgKD7aHSiTfE/i7sN7aEdzQnA==", + "dev": true, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, "node_modules/@sigstore/protobuf-specs": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/@sigstore/protobuf-specs/-/protobuf-specs-0.2.1.tgz", @@ -2013,12 +2024,13 @@ } }, "node_modules/@sigstore/sign": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@sigstore/sign/-/sign-2.2.0.tgz", - "integrity": "sha512-AAbmnEHDQv6CSfrWA5wXslGtzLPtAtHZleKOgxdQYvx/s76Fk6T6ZVt7w2IGV9j1UrFeBocTTQxaXG2oRrDhYA==", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@sigstore/sign/-/sign-2.2.1.tgz", + "integrity": "sha512-U5sKQEj+faE1MsnLou1f4DQQHeFZay+V9s9768lw48J4pKykPj34rWyI1lsMOGJ3Mae47Ye6q3HAJvgXO21rkQ==", "dev": true, "dependencies": { - "@sigstore/bundle": "^2.1.0", + "@sigstore/bundle": "^2.1.1", + "@sigstore/core": "^0.2.0", "@sigstore/protobuf-specs": "^0.2.1", "make-fetch-happen": "^13.0.0" }, @@ -2027,13 +2039,27 @@ } }, "node_modules/@sigstore/tuf": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@sigstore/tuf/-/tuf-2.2.0.tgz", - "integrity": "sha512-KKATZ5orWfqd9ZG6MN8PtCIx4eevWSuGRKQvofnWXRpyMyUEpmrzg5M5BrCpjM+NfZ0RbNGOh5tCz/P2uoRqOA==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@sigstore/tuf/-/tuf-2.3.0.tgz", + "integrity": "sha512-S98jo9cpJwO1mtQ+2zY7bOdcYyfVYCUaofCG6wWRzk3pxKHVAkSfshkfecto2+LKsx7Ovtqbgb2LS8zTRhxJ9Q==", "dev": true, "dependencies": { "@sigstore/protobuf-specs": "^0.2.1", - "tuf-js": "^2.1.0" + "tuf-js": "^2.2.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/@sigstore/verify": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/@sigstore/verify/-/verify-0.1.0.tgz", + "integrity": "sha512-2UzMNYAa/uaz11NhvgRnIQf4gpLTJ59bhb8ESXaoSS5sxedfS+eLak8bsdMc+qpNQfITUTFoSKFx5h8umlRRiA==", + "dev": true, + "dependencies": { + "@sigstore/bundle": "^2.1.1", + "@sigstore/core": "^0.2.0", + "@sigstore/protobuf-specs": "^0.2.1" }, "engines": { "node": "^16.14.0 || >=18.0.0" @@ -2857,109 +2883,109 @@ } }, "node_modules/@tapjs/after": { - "version": "1.1.13", - "resolved": "https://registry.npmjs.org/@tapjs/after/-/after-1.1.13.tgz", - "integrity": "sha512-E2yGUayyCmgtyGDGIcejcVZjdcTmqxEfQexS/TTdELE2cCVYDlkTog5sRJVW02fQUyKrqta0X6bfUjT5+VtO9g==", + "version": "1.1.17", + "resolved": "https://registry.npmjs.org/@tapjs/after/-/after-1.1.17.tgz", + "integrity": "sha512-14qeP+mHZ8nIMDGtdCwTgvKclLlHxfARMTasb9fw//tmF/8ZDZhTemtCDxAP75wihxy5P7nzVZo/6TpVeOZrwg==", "dev": true, "dependencies": { "is-actual-promise": "^1.0.0" }, "engines": { - "node": ">=16" + "node": "16 >=16.17.0 || 18 >= 18.6.0 || >=20" }, "peerDependencies": { - "@tapjs/core": "1.4.2" + "@tapjs/core": "1.4.6" } }, "node_modules/@tapjs/after-each": { - "version": "1.1.13", - "resolved": "https://registry.npmjs.org/@tapjs/after-each/-/after-each-1.1.13.tgz", - "integrity": "sha512-KnX5QCz+f0Qvm8ZkN+/QugSqbNznVTisNu+xbYWY+m2sOhUtyNYSsqvxcKEhpBTS+fRjTPl1wU5ocZv5dDUMEA==", + "version": "1.1.17", + "resolved": "https://registry.npmjs.org/@tapjs/after-each/-/after-each-1.1.17.tgz", + "integrity": "sha512-ia8sr00Wilni+2+wO4MKYCYikeRwUC41HamV8EPN63R2UmiBEOe/cMSf+KYADIh56JvxAiH7Xa0+GSFU+N2FQQ==", "dev": true, "dependencies": { "function-loop": "^4.0.0" }, "engines": { - "node": ">=16" + "node": "16 >=16.17.0 || 18 >= 18.6.0 || >=20" }, "peerDependencies": { - "@tapjs/core": "1.4.2" + "@tapjs/core": "1.4.6" } }, "node_modules/@tapjs/asserts": { - "version": "1.1.13", - "resolved": "https://registry.npmjs.org/@tapjs/asserts/-/asserts-1.1.13.tgz", - "integrity": "sha512-nX9Dzkz4BToVw6Foi/naQO2oId4kvu1nOd9Brql75TrLOhSIf0BNhmUtedPouzefqHTnOQcOK+wxPqm2mUCvHQ==", + "version": "1.1.17", + "resolved": "https://registry.npmjs.org/@tapjs/asserts/-/asserts-1.1.17.tgz", + "integrity": "sha512-eKmbWBORDXu9bUHtPTu7qFrXNj5UeeH2nABJeP9BGHIn2ydmTgMEWCO3E+ljf7tisHchY5/x672lr99+O/mbTQ==", "dev": true, "dependencies": { - "@tapjs/stack": "1.2.6", + "@tapjs/stack": "1.2.7", "is-actual-promise": "^1.0.0", - "tcompare": "6.4.3", + "tcompare": "6.4.5", "trivial-deferred": "^2.0.0" }, "engines": { - "node": ">=16" + "node": "16 >=16.17.0 || 18 >= 18.6.0 || >=20" }, "funding": { "url": "https://github.com/sponsors/isaacs" }, "peerDependencies": { - "@tapjs/core": "1.4.2" + "@tapjs/core": "1.4.6" } }, "node_modules/@tapjs/before": { - "version": "1.1.13", - "resolved": "https://registry.npmjs.org/@tapjs/before/-/before-1.1.13.tgz", - "integrity": "sha512-IBgbKmc5Mqw+4JX0A52ZSn3ycwIQSNkqfOEjzELrEqhLuzeyQnb99P6QZKYfcVDaMhPqeYHRO+ziJOgtbAgPkQ==", + "version": "1.1.17", + "resolved": "https://registry.npmjs.org/@tapjs/before/-/before-1.1.17.tgz", + "integrity": "sha512-pAmEAIMIqF9MPNUgEsnuWCM00iD/FJOX0P5eXSsWexWHjuZAkv5tIT/4qpXO9KYj+9c51Lh+7YSY2Xvk1Jjolw==", "dev": true, "dependencies": { "is-actual-promise": "^1.0.0" }, "engines": { - "node": ">=16" + "node": "16 >=16.17.0 || 18 >= 18.6.0 || >=20" }, "peerDependencies": { - "@tapjs/core": "1.4.2" + "@tapjs/core": "1.4.6" } }, "node_modules/@tapjs/before-each": { - "version": "1.1.13", - "resolved": "https://registry.npmjs.org/@tapjs/before-each/-/before-each-1.1.13.tgz", - "integrity": "sha512-wprmLLmX9QowI9Z5eNtQ8/PRpLHzip99PxukOR59V2839Ypmwu9e1vVfrSIU1F6u6CcUrb80SaJDf2Izm8hmBg==", + "version": "1.1.17", + "resolved": "https://registry.npmjs.org/@tapjs/before-each/-/before-each-1.1.17.tgz", + "integrity": "sha512-d2Um3Y2j0m563QNsSxczh+QeSg5sBngnBFGOelUtQVqmq91oNWU/7mY1pwN6ip8mMIQYD75CIhq5/Z57DGomWQ==", "dev": true, "dependencies": { "function-loop": "^4.0.0" }, "engines": { - "node": ">=16" + "node": "16 >=16.17.0 || 18 >= 18.6.0 || >=20" }, "peerDependencies": { - "@tapjs/core": "1.4.2" + "@tapjs/core": "1.4.6" } }, "node_modules/@tapjs/config": { - "version": "2.4.9", - "resolved": "https://registry.npmjs.org/@tapjs/config/-/config-2.4.9.tgz", - "integrity": "sha512-3coHlkF0XJn59ixl0ln2vRn2SyYPUXyoLDixu4jP/C38ZA7yYTlpsDYuovNiMhXUgJi1AMbWCqASmYL49rn8Sw==", + "version": "2.4.14", + "resolved": "https://registry.npmjs.org/@tapjs/config/-/config-2.4.14.tgz", + "integrity": "sha512-dkjPVJGbLJC9BxCAxudAGiijnKc6XcQbpBSMAGJ/+VoRSqXlPkMWz0d8Ad3rNt7s+g2GBEWBx1kV7wcKtLlxmw==", "dev": true, "dependencies": { - "@tapjs/core": "1.4.2", - "@tapjs/test": "1.3.13", + "@tapjs/core": "1.4.6", + "@tapjs/test": "1.3.17", "chalk": "^5.2.0", "jackspeak": "^2.3.6", "polite-json": "^4.0.1", - "tap-yaml": "2.2.0", + "tap-yaml": "2.2.1", "walk-up-path": "^3.0.1" }, "engines": { - "node": ">=16" + "node": "16 >=16.17.0 || 18 >= 18.6.0 || >=20" }, "funding": { "url": "https://github.com/sponsors/isaacs" }, "peerDependencies": { - "@tapjs/core": "1.4.2", - "@tapjs/test": "1.3.13" + "@tapjs/core": "1.4.6", + "@tapjs/test": "1.3.17" } }, "node_modules/@tapjs/config/node_modules/chalk": { @@ -2975,26 +3001,26 @@ } }, "node_modules/@tapjs/core": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/@tapjs/core/-/core-1.4.2.tgz", - "integrity": "sha512-+mI2R8l/LjRrf7VLcme7jumi9MZb8vx3ARrheuS/djaXdcUd7lWHMjJSvCvnWhV5twTTUsfnc7GytWeFL3N4vA==", + "version": "1.4.6", + "resolved": "https://registry.npmjs.org/@tapjs/core/-/core-1.4.6.tgz", + "integrity": "sha512-cAKtdGJslrziwi/RJBU7jF930P/eSsemv295t6yLekNVP0XUCNtLFYirxuS1Xwob0nt0g/k+94xXB7o1wdTQvA==", "dev": true, "dependencies": { - "@tapjs/processinfo": "^3.1.5", - "@tapjs/stack": "1.2.6", - "@tapjs/test": "1.3.13", + "@tapjs/processinfo": "^3.1.6", + "@tapjs/stack": "1.2.7", + "@tapjs/test": "1.3.17", "async-hook-domain": "^4.0.1", "diff": "^5.1.0", "is-actual-promise": "^1.0.0", "minipass": "^7.0.3", "signal-exit": "4.1", - "tap-parser": "15.3.0", - "tap-yaml": "2.2.0", - "tcompare": "6.4.3", + "tap-parser": "15.3.1", + "tap-yaml": "2.2.1", + "tcompare": "6.4.5", "trivial-deferred": "^2.0.0" }, "engines": { - "node": ">=16" + "node": "16 >=16.17.0 || 18 >= 18.6.0 || >=20" } }, "node_modules/@tapjs/core/node_modules/diff": { @@ -3028,15 +3054,15 @@ } }, "node_modules/@tapjs/error-serdes": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@tapjs/error-serdes/-/error-serdes-1.2.0.tgz", - "integrity": "sha512-Lt7kHWxILVCkfiRbsIZW5sfZ79+CmS1a+mp41dgp5oiiO2TJGBSpEWptD+bIfk9tegtU4wcMUwnStymfTKl4Xw==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@tapjs/error-serdes/-/error-serdes-1.2.1.tgz", + "integrity": "sha512-/7eLEcrGo+Qz3eWrjkhDC+VSEOjabkkzr9eRADeU+OLFeZaik8L/GRk0SGhnp4YsQkv0jcNV00A42bEx2HIZcw==", "dev": true, "dependencies": { "minipass": "^7.0.3" }, "engines": { - "node": ">=16" + "node": "16 >=16.17.0 || 18 >= 18.6.0 || >=20" }, "funding": { "url": "https://github.com/sponsors/isaacs" @@ -3052,37 +3078,37 @@ } }, "node_modules/@tapjs/filter": { - "version": "1.2.13", - "resolved": "https://registry.npmjs.org/@tapjs/filter/-/filter-1.2.13.tgz", - "integrity": "sha512-HahbPSl5gkJ12pIRqMq595A0zNMaTSUvQyLYtDX8GhQM7YanCMLPPPfxg5SFk2p7XinxN5HUiZ5i+Jh1W9tpeQ==", + "version": "1.2.17", + "resolved": "https://registry.npmjs.org/@tapjs/filter/-/filter-1.2.17.tgz", + "integrity": "sha512-ytsqoPThV92ML1+M+cHlhAS7nOQpDNRBJiPqw20/GmNeoQXsDzVUlWR89DP3WNNUPrr/c1pCVr9XHVhCIeYk0w==", "dev": true, "engines": { - "node": ">=16" + "node": "16 >=16.17.0 || 18 >= 18.6.0 || >=20" }, "funding": { "url": "https://github.com/sponsors/isaacs" }, "peerDependencies": { - "@tapjs/core": "1.4.2" + "@tapjs/core": "1.4.6" } }, "node_modules/@tapjs/fixture": { - "version": "1.2.13", - "resolved": "https://registry.npmjs.org/@tapjs/fixture/-/fixture-1.2.13.tgz", - "integrity": "sha512-PPw4EqgIwOzoPjaPSv4O6l7e5RKLEhJH1CbrTqdaM2YxuLgC9Gv9AN0LxJsXsfTnJgoWodzC29dE7JB5RJINuQ==", + "version": "1.2.17", + "resolved": "https://registry.npmjs.org/@tapjs/fixture/-/fixture-1.2.17.tgz", + "integrity": "sha512-eOOQxtsEcQ/sBxaZhpqdF9DCNxXAvLuiE5HgyL6d1eB4eceu57uIUKK7NDtFVv+vlbQH/NoiSTxmN/IBRbKT8w==", "dev": true, "dependencies": { "mkdirp": "^3.0.0", "rimraf": "^5.0.5" }, "engines": { - "node": ">=16" + "node": "16 >=16.17.0 || 18 >= 18.6.0 || >=20" }, "funding": { "url": "https://github.com/sponsors/isaacs" }, "peerDependencies": { - "@tapjs/core": "1.4.2" + "@tapjs/core": "1.4.6" } }, "node_modules/@tapjs/fixture/node_modules/brace-expansion": { @@ -3174,66 +3200,66 @@ } }, "node_modules/@tapjs/intercept": { - "version": "1.2.13", - "resolved": "https://registry.npmjs.org/@tapjs/intercept/-/intercept-1.2.13.tgz", - "integrity": "sha512-/miqU/GK+AFW1y7Wc3N/1OpcFYK++voQ/Ai4u2cORbcxnUt0cWBxHPOZOyepZqwX88sPwr1NdrCV1/B3BbgPWw==", + "version": "1.2.17", + "resolved": "https://registry.npmjs.org/@tapjs/intercept/-/intercept-1.2.17.tgz", + "integrity": "sha512-CNuYBxiFBMNALS1PxH3yGI10H8ObxOoD67C2xGWyzXeYrPJ/R4x31Sda9bqaoK3uf/vj28bC9kSECCFjRsNAEg==", "dev": true, "dependencies": { - "@tapjs/after": "1.1.13", - "@tapjs/stack": "1.2.6" + "@tapjs/after": "1.1.17", + "@tapjs/stack": "1.2.7" }, "engines": { - "node": ">=16" + "node": "16 >=16.17.0 || 18 >= 18.6.0 || >=20" }, "peerDependencies": { - "@tapjs/core": "1.4.2" + "@tapjs/core": "1.4.6" } }, "node_modules/@tapjs/mock": { - "version": "1.2.11", - "resolved": "https://registry.npmjs.org/@tapjs/mock/-/mock-1.2.11.tgz", - "integrity": "sha512-fXMvbQa04qfnNjgGN/cKWj52flYpN8J18/gkWQDbiOLieC1QJVtF1tkTohL602mqVbxn+9rOpTPjDvyJhi65zg==", + "version": "1.2.15", + "resolved": "https://registry.npmjs.org/@tapjs/mock/-/mock-1.2.15.tgz", + "integrity": "sha512-uXfVNDAMAbCGOu46B9jbryTau2pLSQjCdWnkAm/OUgZh/OtO0i7OORz9HdEPfEF2tuy1tLo9+vsCZm3lPU5F7w==", "dev": true, "dependencies": { - "@tapjs/after": "1.1.13", - "@tapjs/stack": "1.2.6", - "resolve-import": "^1.4.4", + "@tapjs/after": "1.1.17", + "@tapjs/stack": "1.2.7", + "resolve-import": "^1.4.5", "walk-up-path": "^3.0.1" }, "engines": { - "node": ">=16" + "node": "16 >=16.17.0 || 18 >= 18.6.0 || >=20" }, "funding": { "url": "https://github.com/sponsors/isaacs" }, "peerDependencies": { - "@tapjs/core": "1.4.2" + "@tapjs/core": "1.4.6" } }, "node_modules/@tapjs/node-serialize": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@tapjs/node-serialize/-/node-serialize-1.2.2.tgz", - "integrity": "sha512-ycPPYNxRsj/AFoqaGY5P38nehMVcwMAz7U0uRO7/2dh4vxUQcKyIBh5KNhB3z/EEas5wiQip+YJ1CW1fAx/PHg==", + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@tapjs/node-serialize/-/node-serialize-1.2.6.tgz", + "integrity": "sha512-xj1OJEsdTr0pQFlirfe/apN0dHUCMCx2Nm5H3SoiSOW4D1/FUKS65VZpWgo3mXMPxRyb/2T1DH3xON1eSGq4ww==", "dev": true, "dependencies": { - "@tapjs/error-serdes": "1.2.0", - "@tapjs/stack": "1.2.6", - "tap-parser": "15.3.0" + "@tapjs/error-serdes": "1.2.1", + "@tapjs/stack": "1.2.7", + "tap-parser": "15.3.1" }, "engines": { - "node": ">=16" + "node": "16 >=16.17.0 || 18 >= 18.6.0 || >=20" }, "funding": { "url": "https://github.com/sponsors/isaacs" }, "peerDependencies": { - "@tapjs/core": "1.4.2" + "@tapjs/core": "1.4.6" } }, "node_modules/@tapjs/processinfo": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/@tapjs/processinfo/-/processinfo-3.1.5.tgz", - "integrity": "sha512-KCx0Dbatmuja9soLFFK1asDwodz+16gwHL9QWiziz83b7LK4x5h9kiUbbhTi3I3wtKREeaN8caNA0Z2m6Yxsag==", + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/@tapjs/processinfo/-/processinfo-3.1.6.tgz", + "integrity": "sha512-ktDsaf79wJsLaoG1Pp+stHSRf6a1k/JydoRAaYVG5iJnd3DooL6yewZsciUi2yiN/WQc5tAXCIFTXL4uXGB8LA==", "dev": true, "dependencies": { "pirates": "^4.0.5", @@ -3258,13 +3284,13 @@ } }, "node_modules/@tapjs/reporter": { - "version": "1.3.10", - "resolved": "https://registry.npmjs.org/@tapjs/reporter/-/reporter-1.3.10.tgz", - "integrity": "sha512-5fDwmDMXe20NiW8p8AQ7Tn9mrnFCwY3qX7iBJ7z2+4cgAzvoLdkqcjoUwBW15KwxfcJPm8oFMhf0Wv+d84A7OQ==", + "version": "1.3.15", + "resolved": "https://registry.npmjs.org/@tapjs/reporter/-/reporter-1.3.15.tgz", + "integrity": "sha512-us1vXd6TW1V8wJxxnP2a8DNSP1WFTpODyYukqWg7ym5nCalREYnz2MFsn65rRNu/xJlmqsmv+9P63rupud7Zlg==", "dev": true, "dependencies": { - "@tapjs/config": "2.4.9", - "@tapjs/stack": "1.2.6", + "@tapjs/config": "2.4.14", + "@tapjs/stack": "1.2.7", "chalk": "^5.2.0", "ink": "^4.4.1", "minipass": "^7.0.3", @@ -3273,18 +3299,18 @@ "prismjs-terminal": "^1.2.3", "react": "^18.2.0", "string-length": "^6.0.0", - "tap-parser": "15.3.0", - "tap-yaml": "2.2.0", - "tcompare": "6.4.3" + "tap-parser": "15.3.1", + "tap-yaml": "2.2.1", + "tcompare": "6.4.5" }, "engines": { - "node": ">=16" + "node": "16 >=16.17.0 || 18 >= 18.6.0 || >=20" }, "funding": { "url": "https://github.com/sponsors/isaacs" }, "peerDependencies": { - "@tapjs/core": "1.4.2" + "@tapjs/core": "1.4.6" } }, "node_modules/@tapjs/reporter/node_modules/chalk": { @@ -3315,19 +3341,19 @@ "dev": true }, "node_modules/@tapjs/run": { - "version": "1.4.10", - "resolved": "https://registry.npmjs.org/@tapjs/run/-/run-1.4.10.tgz", - "integrity": "sha512-m1464ealbd+NL2WkYoevFveXhwCNU1I+MG0JpuAh/7MSEORRiG73ivRQOyfBVxfjeFMHVy4i99Sx1x9WDkHO7Q==", - "dev": true, - "dependencies": { - "@tapjs/after": "1.1.13", - "@tapjs/before": "1.1.13", - "@tapjs/config": "2.4.9", - "@tapjs/processinfo": "^3.1.5", - "@tapjs/reporter": "1.3.10", - "@tapjs/spawn": "1.1.13", - "@tapjs/stdin": "1.1.13", - "@tapjs/test": "1.3.13", + "version": "1.4.16", + "resolved": "https://registry.npmjs.org/@tapjs/run/-/run-1.4.16.tgz", + "integrity": "sha512-ZTESjBDj5SitZgWz2hQdzfBoxgaFs89jQjWzqobcdfro0iF7TVRpSrvpz9GTMdo2Tu9aeFfMNfmaAtwNWnDabw==", + "dev": true, + "dependencies": { + "@tapjs/after": "1.1.17", + "@tapjs/before": "1.1.17", + "@tapjs/config": "2.4.14", + "@tapjs/processinfo": "^3.1.6", + "@tapjs/reporter": "1.3.15", + "@tapjs/spawn": "1.1.17", + "@tapjs/stdin": "1.1.17", + "@tapjs/test": "1.3.17", "c8": "^8.0.1", "chalk": "^5.3.0", "chokidar": "^3.5.3", @@ -3337,13 +3363,13 @@ "mkdirp": "^3.0.1", "opener": "^1.5.2", "pacote": "^17.0.3", - "resolve-import": "^1.4.4", + "resolve-import": "^1.4.5", "rimraf": "^5.0.5", "semver": "^7.5.4", "signal-exit": "^4.1.0", - "tap-parser": "15.3.0", - "tap-yaml": "2.2.0", - "tcompare": "6.4.3", + "tap-parser": "15.3.1", + "tap-yaml": "2.2.1", + "tcompare": "6.4.5", "trivial-deferred": "^2.0.0", "which": "^4.0.0" }, @@ -3351,13 +3377,13 @@ "tap-run": "dist/esm/index.js" }, "engines": { - "node": ">=16" + "node": "16 >=16.17.0 || 18 >= 18.6.0 || >=20" }, "funding": { "url": "https://github.com/sponsors/isaacs" }, "peerDependencies": { - "@tapjs/core": "1.4.2" + "@tapjs/core": "1.4.6" } }, "node_modules/@tapjs/run/node_modules/brace-expansion": { @@ -3497,90 +3523,90 @@ } }, "node_modules/@tapjs/snapshot": { - "version": "1.2.13", - "resolved": "https://registry.npmjs.org/@tapjs/snapshot/-/snapshot-1.2.13.tgz", - "integrity": "sha512-/vW3kOxNA1vclsEU87A5vZ7edRbrL1Hlm7LauJwRAvAgdW2VrEcc1ivyCMbWvYi11csGu1MM9A2Poo/aOhzQ/Q==", + "version": "1.2.17", + "resolved": "https://registry.npmjs.org/@tapjs/snapshot/-/snapshot-1.2.17.tgz", + "integrity": "sha512-xDHys854ZA8s/1uCkE5PgBz4H1vYKChD6a4xjLVkaoRxpBHVp/IJZCD+8d69DRGnyuA4x2MGh0JLClTA9bLGrA==", "dev": true, "dependencies": { "is-actual-promise": "^1.0.0", - "tcompare": "6.4.3", + "tcompare": "6.4.5", "trivial-deferred": "^2.0.0" }, "engines": { - "node": ">=16" + "node": "16 >=16.17.0 || 18 >= 18.6.0 || >=20" }, "funding": { "url": "https://github.com/sponsors/isaacs" }, "peerDependencies": { - "@tapjs/core": "1.4.2" + "@tapjs/core": "1.4.6" } }, "node_modules/@tapjs/spawn": { - "version": "1.1.13", - "resolved": "https://registry.npmjs.org/@tapjs/spawn/-/spawn-1.1.13.tgz", - "integrity": "sha512-s2byTuuyyPv+8uI4xSspFhiFPddi/Bwz2a/RHQVm3IKuvO0gW9KA53J8PEjWIRXLFNgf5X0xWIYGgMXeklYN/w==", + "version": "1.1.17", + "resolved": "https://registry.npmjs.org/@tapjs/spawn/-/spawn-1.1.17.tgz", + "integrity": "sha512-Bbyxd91bgXEcglvXYKrRl2MaNHk00RajTZJ1kKe3Scr1ivaYv0maE6ZInAl4UE0a4SJl4Dskec+uKoZY3qGUYQ==", "dev": true, "engines": { - "node": ">=16" + "node": "16 >=16.17.0 || 18 >= 18.6.0 || >=20" }, "peerDependencies": { - "@tapjs/core": "1.4.2" + "@tapjs/core": "1.4.6" } }, "node_modules/@tapjs/stack": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/@tapjs/stack/-/stack-1.2.6.tgz", - "integrity": "sha512-us73FMZytpcvYT/gOSDDKHk/LLZQZ/bBLoz48VcEE5EFQmF0EELhNOlyg4Rrvj8DmuYuFjiliidiV/FB1Fchaw==", + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@tapjs/stack/-/stack-1.2.7.tgz", + "integrity": "sha512-7qUDWDmd+y7ZQ0vTrDTvFlWnJ+ND32NemS5HVuT1ZggHtBwJ62PQHIyCx/B5RopETBb6NvFPfUE21yTiex9Jkw==", "dev": true, "engines": { - "node": ">=16" + "node": "16 >=16.17.0 || 18 >= 18.6.0 || >=20" }, "funding": { "url": "https://github.com/sponsors/isaacs" } }, "node_modules/@tapjs/stdin": { - "version": "1.1.13", - "resolved": "https://registry.npmjs.org/@tapjs/stdin/-/stdin-1.1.13.tgz", - "integrity": "sha512-ilamAMcQ7TPzuB4fVLtTyCYaqU3bAh1YLssmwtcYwRE0J4szNIFLMsduVjWLNGnjViKRHI6x1iHGOZg2IwTXug==", + "version": "1.1.17", + "resolved": "https://registry.npmjs.org/@tapjs/stdin/-/stdin-1.1.17.tgz", + "integrity": "sha512-mDutFFPDnlVM2oYDAfyYKA+fC+aEiyz5n08D8x6YAbwZNbTIVp+h6ucyp7ygJ04fshd4l3s1HUmCZLSmHb2xEw==", "dev": true, "engines": { - "node": ">=16" + "node": "16 >=16.17.0 || 18 >= 18.6.0 || >=20" }, "peerDependencies": { - "@tapjs/core": "1.4.2" + "@tapjs/core": "1.4.6" } }, "node_modules/@tapjs/test": { - "version": "1.3.13", - "resolved": "https://registry.npmjs.org/@tapjs/test/-/test-1.3.13.tgz", - "integrity": "sha512-eqlrFgdMwOuqMeMGWMButPmas7q5Z0yEqmyBZIsjKk246wN1GUKIwGxX+K0THMBHaiSKW4c/PvXpMynZyywqbw==", - "dev": true, - "dependencies": { - "@isaacs/ts-node-temp-fork-for-pr-2009": "^10.9.1", - "@tapjs/after": "1.1.13", - "@tapjs/after-each": "1.1.13", - "@tapjs/asserts": "1.1.13", - "@tapjs/before": "1.1.13", - "@tapjs/before-each": "1.1.13", - "@tapjs/filter": "1.2.13", - "@tapjs/fixture": "1.2.13", - "@tapjs/intercept": "1.2.13", - "@tapjs/mock": "1.2.11", - "@tapjs/node-serialize": "1.2.2", - "@tapjs/snapshot": "1.2.13", - "@tapjs/spawn": "1.1.13", - "@tapjs/stdin": "1.1.13", - "@tapjs/typescript": "1.3.2", - "@tapjs/worker": "1.1.13", + "version": "1.3.17", + "resolved": "https://registry.npmjs.org/@tapjs/test/-/test-1.3.17.tgz", + "integrity": "sha512-yQ4uHC2GaDS+Gr5qwx9uMGxqvpYgnlVY+QexBReSeYZthWIN0KD8HDvnVt4An5Sx/Qhd7UlnNpNMBd6AkvPEew==", + "dev": true, + "dependencies": { + "@isaacs/ts-node-temp-fork-for-pr-2009": "^10.9.5", + "@tapjs/after": "1.1.17", + "@tapjs/after-each": "1.1.17", + "@tapjs/asserts": "1.1.17", + "@tapjs/before": "1.1.17", + "@tapjs/before-each": "1.1.17", + "@tapjs/filter": "1.2.17", + "@tapjs/fixture": "1.2.17", + "@tapjs/intercept": "1.2.17", + "@tapjs/mock": "1.2.15", + "@tapjs/node-serialize": "1.2.6", + "@tapjs/snapshot": "1.2.17", + "@tapjs/spawn": "1.1.17", + "@tapjs/stdin": "1.1.17", + "@tapjs/typescript": "1.3.6", + "@tapjs/worker": "1.1.17", "glob": "^10.3.10", "jackspeak": "^2.3.6", "mkdirp": "^3.0.0", - "resolve-import": "^1.4.4", + "resolve-import": "^1.4.5", "rimraf": "^5.0.5", "sync-content": "^1.0.1", - "tap-parser": "15.3.0", + "tap-parser": "15.3.1", "tshy": "^1.2.2", "typescript": "5.2" }, @@ -3588,10 +3614,10 @@ "generate-tap-test-class": "scripts/build.mjs" }, "engines": { - "node": ">=16" + "node": "16 >=16.17.0 || 18 >= 18.6.0 || >=20" }, "peerDependencies": { - "@tapjs/core": "1.4.2" + "@tapjs/core": "1.4.6" } }, "node_modules/@tapjs/test/node_modules/brace-expansion": { @@ -3696,30 +3722,30 @@ } }, "node_modules/@tapjs/typescript": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@tapjs/typescript/-/typescript-1.3.2.tgz", - "integrity": "sha512-R8E36Kd1ImufcygVzSbQt/rEgg5RIW+CvIBzJNmv1IczRoAVFo5/OElZwOThiko7CAxDMRJxI8Cla63uK3gsLA==", + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/@tapjs/typescript/-/typescript-1.3.6.tgz", + "integrity": "sha512-bHqQb06HcD1vFvSwElH0WK4cnCNthvA5OX/KBs5w1TNFHIeRHemp/hsSnGSNDwYwDETuOxD68rDZNTpNbzysBg==", "dev": true, "dependencies": { - "@isaacs/ts-node-temp-fork-for-pr-2009": "^10.9.1" + "@isaacs/ts-node-temp-fork-for-pr-2009": "^10.9.5" }, "engines": { - "node": ">=16" + "node": "16 >=16.17.0 || 18 >= 18.6.0 || >=20" }, "peerDependencies": { - "@tapjs/core": "1.4.2" + "@tapjs/core": "1.4.6" } }, "node_modules/@tapjs/worker": { - "version": "1.1.13", - "resolved": "https://registry.npmjs.org/@tapjs/worker/-/worker-1.1.13.tgz", - "integrity": "sha512-B/g1rdQcuOFdU6OeBHkdYUjzM6pbHo64nV+ckQNE7Atj4yzV0u7C+Emq+f7F+zItsGXaMm/a4Z7Zoliszy7YXw==", + "version": "1.1.17", + "resolved": "https://registry.npmjs.org/@tapjs/worker/-/worker-1.1.17.tgz", + "integrity": "sha512-DCRzEBT+OgP518rQqzlX6KawvGTegkeEjPVa/TB6Iifj8WOHJ+XtunkR7riIRGEoCEOMD49DCJXj70c+XP0jNw==", "dev": true, "engines": { - "node": ">=16" + "node": "16 >=16.17.0 || 18 >= 18.6.0 || >=20" }, "peerDependencies": { - "@tapjs/core": "1.4.2" + "@tapjs/core": "1.4.6" } }, "node_modules/@tokenizer/token": { @@ -3828,9 +3854,9 @@ "license": "MIT" }, "node_modules/@types/istanbul-lib-coverage": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.5.tgz", - "integrity": "sha512-zONci81DZYCZjiLe0r6equvZut0b+dBRPBN5kBDjsONnutYNtJMoWQ9uR2RkL1gLG9NMTzvf+29e5RFfPbeKhQ==", + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", + "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", "dev": true }, "node_modules/@types/json-schema": { @@ -4114,9 +4140,10 @@ } }, "node_modules/acorn": { - "version": "8.8.2", + "version": "8.11.3", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", + "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", "dev": true, - "license": "MIT", "bin": { "acorn": "bin/acorn" }, @@ -4133,9 +4160,9 @@ } }, "node_modules/acorn-walk": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.0.tgz", - "integrity": "sha512-FS7hV565M5l1R08MXqo8odwMTB02C2UqzB17RVgu9EyuYFBqJZ3/ZY97sQD5FewVu1UyDFc1yztUDrAwT0EypA==", + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.2.tgz", + "integrity": "sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A==", "dev": true, "engines": { "node": ">=0.4.0" @@ -5126,9 +5153,9 @@ } }, "node_modules/cacache": { - "version": "18.0.0", - "resolved": "https://registry.npmjs.org/cacache/-/cacache-18.0.0.tgz", - "integrity": "sha512-I7mVOPl3PUCeRub1U8YoGz2Lqv9WOBpobZ8RyWFXmReuILz+3OAyTa5oH3QPdtKZD7N0Yk00aLfzn0qvp8dZ1w==", + "version": "18.0.2", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-18.0.2.tgz", + "integrity": "sha512-r3NU8h/P+4lVUHfeRw1dtgQYar3DZMm4/cm2bZgOvrFC/su7budSOeqh52VJIC4U4iG1WWwV6vRW0znqBvxNuw==", "dev": true, "dependencies": { "@npmcli/fs": "^3.1.0", @@ -5136,7 +5163,7 @@ "glob": "^10.2.2", "lru-cache": "^10.0.1", "minipass": "^7.0.3", - "minipass-collect": "^1.0.2", + "minipass-collect": "^2.0.1", "minipass-flush": "^1.0.5", "minipass-pipeline": "^1.2.4", "p-map": "^4.0.0", @@ -8196,9 +8223,9 @@ } }, "node_modules/ignore-walk": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-6.0.3.tgz", - "integrity": "sha512-C7FfFoTA+bI10qfeydT8aZbvr91vAEU+2W5BZUlzPec47oNb07SsOfwYrtxuvOYdUApPP/Qlh4DtAO51Ekk2QA==", + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-6.0.4.tgz", + "integrity": "sha512-t7sv42WkwFkyKbivUCglsQW5YWMskWtbEf4MNKX5u/CCWHKSPzN4FtBQGsQZgCLbxOzpVlcbWVK5KB3auIOjSw==", "dev": true, "dependencies": { "minimatch": "^9.0.0" @@ -8533,9 +8560,9 @@ } }, "node_modules/ink/node_modules/ws": { - "version": "8.14.2", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.14.2.tgz", - "integrity": "sha512-wEBG1ftX4jcglPxgFCMJmZ2PLtSbJ2Peg6TmpJFTbe9GZYOQCDPdMYu/Tm0/bGZkw8paZnJY45J4K2PZrLYq8g==", + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.16.0.tgz", + "integrity": "sha512-HS0c//TP7Ina87TfiPUz1rQzMhHrl/SG2guqRcTOIUYD2q8uhUdNHZYJUaQ8aTGPzCh+c6oawMKW35nFl1dxyQ==", "dev": true, "engines": { "node": ">=10.0.0" @@ -9008,9 +9035,9 @@ } }, "node_modules/istanbul-lib-coverage": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", - "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==", + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", + "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", "dev": true, "engines": { "node": ">=8" @@ -9198,9 +9225,9 @@ } }, "node_modules/json-parse-even-better-errors": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-3.0.0.tgz", - "integrity": "sha512-iZbGHafX/59r39gPwVPRBGw0QQKnA7tte5pSMrhWOW7swGsVvVTjmfyAV9pNqk8YGT7tRCdxRu8uzcgZwoDooA==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-3.0.1.tgz", + "integrity": "sha512-aatBvbL26wVUCLmbWdCpeu9iF5wOyWpagiKkInA+kfws3sWdBrTnsvN2CKcyCYyUrc7rebNBlK6+kteg7ksecg==", "dev": true, "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0" @@ -9559,21 +9586,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/lint-staged/node_modules/npm-run-path": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.1.0.tgz", - "integrity": "sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q==", - "dev": true, - "dependencies": { - "path-key": "^4.0.0" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/lint-staged/node_modules/onetime": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", @@ -9589,30 +9601,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/lint-staged/node_modules/path-key": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", - "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/lint-staged/node_modules/strip-final-newline": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", - "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/lint-staged/node_modules/yaml": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.1.tgz", @@ -9872,9 +9860,9 @@ } }, "node_modules/lru-cache": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.0.1.tgz", - "integrity": "sha512-IJ4uwUTi2qCccrioU6g9g/5rvvVl13bsdczUUcqbciD9iLr095yj8DQKdObriEvuNSx325N1rV1O0sJFszx75g==", + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.1.0.tgz", + "integrity": "sha512-/1clY/ui8CzjKFyjdvwPWJUYKiFVXG2I2cY0ssG7h4+hwk+XOIX7ZSG9Q7TW8TW3Kp3BUSqgFWBLgL4PJ+Blag==", "dev": true, "engines": { "node": "14 || >=16.14" @@ -10072,15 +10060,24 @@ } }, "node_modules/minipass-collect": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-1.0.2.tgz", - "integrity": "sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-2.0.1.tgz", + "integrity": "sha512-D7V8PO9oaz7PWGLbCACuI1qEOsq7UKfLotx/C0Aet43fCUB/wfQ7DYeq2oR/svFJGYDHPr38SHATeaj/ZoKHKw==", "dev": true, "dependencies": { - "minipass": "^3.0.0" + "minipass": "^7.0.3" }, "engines": { - "node": ">= 8" + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/minipass-collect/node_modules/minipass": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", + "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==", + "dev": true, + "engines": { + "node": ">=16 || 14 >=14.17" } }, "node_modules/minipass-fetch": { @@ -10310,9 +10307,9 @@ } }, "node_modules/node-gyp": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-10.0.0.tgz", - "integrity": "sha512-LkaKUbjyacJGRHiuhUeUblzZNxTF1/XNooyAl6aiaJ6ZpeurR4Mk9sjxncGNSI7pETqyqM+hLAER0788oSxt0A==", + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-10.0.1.tgz", + "integrity": "sha512-gg3/bHehQfZivQVfqIyy8wTdSymF9yTyP4CJifK73imyNMU8AIGQE2pUa7dNWfmMeG9cDVF2eehiRMv0LC1iAg==", "dev": true, "dependencies": { "env-paths": "^2.2.0", @@ -10522,12 +10519,12 @@ } }, "node_modules/npm-packlist": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-8.0.0.tgz", - "integrity": "sha512-ErAGFB5kJUciPy1mmx/C2YFbvxoJ0QJ9uwkCZOeR6CqLLISPZBOiFModAbSXnjjlwW5lOhuhXva+fURsSGJqyw==", + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-8.0.2.tgz", + "integrity": "sha512-shYrPFIS/JLP4oQmAwDyk5HcyysKW8/JLTEA32S0Z5TzvpaeeX2yMFfoK1fjEBnCBvVyIB/Jj/GBFdm0wsgzbA==", "dev": true, "dependencies": { - "ignore-walk": "^6.0.0" + "ignore-walk": "^6.0.4" }, "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0" @@ -10592,6 +10589,33 @@ "node": ">=12.0" } }, + "node_modules/npm-run-path": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.2.0.tgz", + "integrity": "sha512-W4/tgAXFqFA0iL7fk0+uQ3g7wkL8xJmx3XdK0VGb4cHW//eZTtKGvFBBoRKVTpY7n6ze4NL9ly7rgXcHufqXKg==", + "dev": true, + "dependencies": { + "path-key": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npm-run-path/node_modules/path-key": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", + "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/object-assign": { "version": "4.1.1", "dev": true, @@ -10857,9 +10881,9 @@ } }, "node_modules/pacote": { - "version": "17.0.4", - "resolved": "https://registry.npmjs.org/pacote/-/pacote-17.0.4.tgz", - "integrity": "sha512-eGdLHrV/g5b5MtD5cTPyss+JxOlaOloSMG3UwPMAvL8ywaLJ6beONPF40K4KKl/UI6q5hTKCJq5rCu8tkF+7Dg==", + "version": "17.0.6", + "resolved": "https://registry.npmjs.org/pacote/-/pacote-17.0.6.tgz", + "integrity": "sha512-cJKrW21VRE8vVTRskJo78c/RCvwJCn1f4qgfxL4w77SOWrTCRcmfkYHlHtS0gqpgjv3zhXflRtgsrUCX5xwNnQ==", "dev": true, "dependencies": { "@npmcli/git": "^5.0.0", @@ -10877,7 +10901,7 @@ "promise-retry": "^2.0.1", "read-package-json": "^7.0.0", "read-package-json-fast": "^3.0.0", - "sigstore": "^2.0.0", + "sigstore": "^2.2.0", "ssri": "^10.0.0", "tar": "^6.1.11" }, @@ -11708,16 +11732,16 @@ } }, "node_modules/resolve-import": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/resolve-import/-/resolve-import-1.4.4.tgz", - "integrity": "sha512-+IccDyUypl5rHv25216cXu2m30flEoetrG8p4qDH3RsP53cytedI58Pz+pjCU4PAbxPOQgFkgmxTJLKI9tgf/g==", + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/resolve-import/-/resolve-import-1.4.5.tgz", + "integrity": "sha512-HXb4YqODuuXT7Icq1Z++0g2JmhgbUHSs3VT2xR83gqvAPUikYT2Xk+562KHQgiaNkbBOlPddYrDLsC44qQggzw==", "dev": true, "dependencies": { "glob": "^10.3.3", "walk-up-path": "^3.0.1" }, "engines": { - "node": ">=16" + "node": "16 >=16.17.0 || 18 >= 18.6.0 || >=20" }, "funding": { "url": "https://github.com/sponsors/isaacs" @@ -12234,15 +12258,17 @@ "license": "ISC" }, "node_modules/sigstore": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/sigstore/-/sigstore-2.1.0.tgz", - "integrity": "sha512-kPIj+ZLkyI3QaM0qX8V/nSsweYND3W448pwkDgS6CQ74MfhEkIR8ToK5Iyx46KJYRjseVcD3Rp9zAmUAj6ZjPw==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/sigstore/-/sigstore-2.2.0.tgz", + "integrity": "sha512-fcU9clHwEss2/M/11FFM8Jwc4PjBgbhXoNskoK5guoK0qGQBSeUbQZRJ+B2fDFIvhyf0gqCaPrel9mszbhAxug==", "dev": true, "dependencies": { - "@sigstore/bundle": "^2.1.0", + "@sigstore/bundle": "^2.1.1", + "@sigstore/core": "^0.2.0", "@sigstore/protobuf-specs": "^0.2.1", - "@sigstore/sign": "^2.1.0", - "@sigstore/tuf": "^2.1.0" + "@sigstore/sign": "^2.2.1", + "@sigstore/tuf": "^2.3.0", + "@sigstore/verify": "^0.1.0" }, "engines": { "node": "^16.14.0 || >=18.0.0" @@ -12678,6 +12704,18 @@ "is-natural-number": "^4.0.1" } }, + "node_modules/strip-final-newline": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", + "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/strip-json-comments": { "version": "3.1.1", "dev": true, @@ -12883,74 +12921,74 @@ } }, "node_modules/tap": { - "version": "18.5.3", - "resolved": "https://registry.npmjs.org/tap/-/tap-18.5.3.tgz", - "integrity": "sha512-TrcgwuQp0siTg/2MGJiZ1T5f3N+JZAOpPq+VR66+j6x9dCxw+1CuaUzWGW34ebCTxy8efT0akZ6dbGlbJVBhRA==", - "dev": true, - "dependencies": { - "@tapjs/after": "1.1.13", - "@tapjs/after-each": "1.1.13", - "@tapjs/asserts": "1.1.13", - "@tapjs/before": "1.1.13", - "@tapjs/before-each": "1.1.13", - "@tapjs/core": "1.4.2", - "@tapjs/filter": "1.2.13", - "@tapjs/fixture": "1.2.13", - "@tapjs/intercept": "1.2.13", - "@tapjs/mock": "1.2.11", - "@tapjs/node-serialize": "1.2.2", - "@tapjs/run": "1.4.10", - "@tapjs/snapshot": "1.2.13", - "@tapjs/spawn": "1.1.13", - "@tapjs/stdin": "1.1.13", - "@tapjs/test": "1.3.13", - "@tapjs/typescript": "1.3.2", - "@tapjs/worker": "1.1.13", - "resolve-import": "^1.4.4" + "version": "18.6.1", + "resolved": "https://registry.npmjs.org/tap/-/tap-18.6.1.tgz", + "integrity": "sha512-5cBQhJ1gdbsrTR3tA5kZZTts0HyOML6bcM7pEF7GF8d6y1ajfRMjbInS1Ty7/x2Ip0ko3cY1dYjPJ9JFNPsm7w==", + "dev": true, + "dependencies": { + "@tapjs/after": "1.1.17", + "@tapjs/after-each": "1.1.17", + "@tapjs/asserts": "1.1.17", + "@tapjs/before": "1.1.17", + "@tapjs/before-each": "1.1.17", + "@tapjs/core": "1.4.6", + "@tapjs/filter": "1.2.17", + "@tapjs/fixture": "1.2.17", + "@tapjs/intercept": "1.2.17", + "@tapjs/mock": "1.2.15", + "@tapjs/node-serialize": "1.2.6", + "@tapjs/run": "1.4.16", + "@tapjs/snapshot": "1.2.17", + "@tapjs/spawn": "1.1.17", + "@tapjs/stdin": "1.1.17", + "@tapjs/test": "1.3.17", + "@tapjs/typescript": "1.3.6", + "@tapjs/worker": "1.1.17", + "resolve-import": "^1.4.5" }, "bin": { "tap": "dist/esm/run.mjs" }, "engines": { - "node": ">=16" + "node": "16 >=16.17.0 || 18 >= 18.6.0 || >=20" }, "funding": { "url": "https://github.com/sponsors/isaacs" } }, "node_modules/tap-parser": { - "version": "15.3.0", - "resolved": "https://registry.npmjs.org/tap-parser/-/tap-parser-15.3.0.tgz", - "integrity": "sha512-R0yLuoC288K+gHtwcOhH7Af/8EocDglAyMpaASsmzNxV1chmq3v4juSAVhvMBbPx/pRVJYrPKe9Wsj9aaqMalQ==", + "version": "15.3.1", + "resolved": "https://registry.npmjs.org/tap-parser/-/tap-parser-15.3.1.tgz", + "integrity": "sha512-hwAtXX5TBGt2MJeYvASc7DjP48PUzA7P8RTbLxQcgKCEH7ICD5IsRco7l5YvkzjHlZbUbeI9wzO8B4hw2sKgnQ==", "dev": true, "dependencies": { "events-to-array": "^2.0.3", - "tap-yaml": "2.2.0" + "tap-yaml": "2.2.1" }, "bin": { "tap-parser": "bin/cmd.cjs" }, "engines": { - "node": ">=16" + "node": "16 >=16.17.0 || 18 >= 18.6.0 || >=20" } }, "node_modules/tap-yaml": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/tap-yaml/-/tap-yaml-2.2.0.tgz", - "integrity": "sha512-o8I7WDNiGpuF04tGAVaNYY5rX9waCtqw9A7Y0YVSQBGcFwNUJWUPLkr2lbhgLRTxc+Tpnw4xUXlIanZc+ZAGnw==", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tap-yaml/-/tap-yaml-2.2.1.tgz", + "integrity": "sha512-ovZuUMLAIH59jnFHXKEGJ+WyDYl6Cuduwg9qpvnqkZOUA1nU84q02Sry1HT0KXcdv2uB91bEKKxnIybBgrb6oA==", "dev": true, "dependencies": { "yaml": "^2.3.0", "yaml-types": "^0.3.0" }, "engines": { - "node": ">=16" + "node": "16 >=16.17.0 || 18 >= 18.6.0 || >=20" } }, "node_modules/tap-yaml/node_modules/yaml": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.3.tgz", - "integrity": "sha512-zw0VAJxgeZ6+++/su5AFoqBbZbrEakwu+X0M5HmcwUiBL7AzcuPKjj5we4xfQLp78LkEMpD0cOnUhmgOVy3KdQ==", + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.4.tgz", + "integrity": "sha512-8aAvwVUSHpfEqTQ4w/KMlf3HcRdt50E5ODIQJBw1fQ5RL34xabzxtUlzTXVqc4rkZsPbvrXKWnABCD7kWSmocA==", "dev": true, "engines": { "node": ">= 14" @@ -13017,16 +13055,16 @@ "license": "ISC" }, "node_modules/tcompare": { - "version": "6.4.3", - "resolved": "https://registry.npmjs.org/tcompare/-/tcompare-6.4.3.tgz", - "integrity": "sha512-bKVNHmQ6Nd7/K3+SFuhsppUrXGwQjXts/U9NAVz52JNYeOlyCjtVydNZHgscw3RmtHp+JdWuheYjVqPvY9x9kg==", + "version": "6.4.5", + "resolved": "https://registry.npmjs.org/tcompare/-/tcompare-6.4.5.tgz", + "integrity": "sha512-Whuz9xlKKI2XXICKDSDRKjXdBuC6gBNOgmEUtH7UFyQeYzfUMQ19DyjZULarGKDGFhgOg3CJ+IQUEfpkOPg0Uw==", "dev": true, "dependencies": { "diff": "^5.1.0", "react-element-to-jsx-string": "^15.0.0" }, "engines": { - "node": ">=16" + "node": "16 >=16.17.0 || 18 >= 18.6.0 || >=20" } }, "node_modules/tcompare/node_modules/diff": { @@ -13270,9 +13308,9 @@ } }, "node_modules/tshy": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/tshy/-/tshy-1.7.0.tgz", - "integrity": "sha512-ioFoMasVNtcOGkJACDpmo+C6xZfRqamimeK0hL2uyS0l7DliiCwAKJj8/x0LVlvdGvCoqkhOHfKpEPjHeI9U8Q==", + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/tshy/-/tshy-1.11.0.tgz", + "integrity": "sha512-5T5PVyuYQKTcOKz5a2lpwx4WKi8yEzQGO0Q5l+9clJMYupMaTI7ONEwKggGAZDQQGIgCOyUCfBWnSkG0XdJc+A==", "dev": true, "dependencies": { "chalk": "^5.3.0", @@ -13282,7 +13320,7 @@ "resolve-import": "^1.4.4", "rimraf": "^5.0.1", "sync-content": "^1.0.2", - "typescript": "5.2", + "typescript": "5.2 || 5.3", "walk-up-path": "^3.0.1" }, "bin": { @@ -13393,9 +13431,9 @@ } }, "node_modules/tshy/node_modules/typescript": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz", - "integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==", + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz", + "integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==", "dev": true, "bin": { "tsc": "bin/tsc", @@ -13439,9 +13477,9 @@ "license": "0BSD" }, "node_modules/tuf-js": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/tuf-js/-/tuf-js-2.1.0.tgz", - "integrity": "sha512-eD7YPPjVlMzdggrOeE8zwoegUaG/rt6Bt3jwoQPunRiNVzgcCE009UDFJKJjG+Gk9wFu6W/Vi+P5d/5QpdD9jA==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tuf-js/-/tuf-js-2.2.0.tgz", + "integrity": "sha512-ZSDngmP1z6zw+FIkIBjvOp/II/mIub/O7Pp12j1WNsiCpg5R5wAc//i555bBQsE44O94btLt0xM/Zr2LQjwdCg==", "dev": true, "dependencies": { "@tufjs/models": "2.0.0", @@ -13672,9 +13710,9 @@ "license": "MIT" }, "node_modules/v8-to-istanbul": { - "version": "9.1.3", - "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.1.3.tgz", - "integrity": "sha512-9lDD+EVI2fjFsMWXc6dy5JJzBsVTcQ2fVkfBvncZ6xJWG9wtBhOldG+mHkSL0+V1K/xgZz0JDO5UT5hFwHUghg==", + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.2.0.tgz", + "integrity": "sha512-/EH/sDgxU2eGxajKdwLCDmQ4FWq+kpi3uCmBGpw1xJtnAxEjlD8j8PEiGWpCIMIs3ciNAgH0d3TTJiUkYzyZjA==", "dev": true, "dependencies": { "@jridgewell/trace-mapping": "^0.3.12", @@ -14944,6 +14982,8 @@ }, "@bcoe/v8-coverage": { "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", + "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", "dev": true }, "@cspotcode/source-map-support": { @@ -15286,9 +15326,9 @@ } }, "@isaacs/ts-node-temp-fork-for-pr-2009": { - "version": "10.9.1", - "resolved": "https://registry.npmjs.org/@isaacs/ts-node-temp-fork-for-pr-2009/-/ts-node-temp-fork-for-pr-2009-10.9.1.tgz", - "integrity": "sha512-MY4rUonz835NsTbd4dcgKZvZFYX9IkLnYFZV9M7GQV8t39fawafLin/Qw6VXD4yfMs4HcBq8P3ddeU0QHMH1YQ==", + "version": "10.9.5", + "resolved": "https://registry.npmjs.org/@isaacs/ts-node-temp-fork-for-pr-2009/-/ts-node-temp-fork-for-pr-2009-10.9.5.tgz", + "integrity": "sha512-hEDlwpHhIabtB+Urku8muNMEkGui0LVGlYLS3KoB9QBDf0Pw3r7q0RrfoQmFuk8CvRpGzErO3/vLQd9Ys+/g4g==", "dev": true, "requires": { "@cspotcode/source-map-support": "^0.8.0", @@ -15315,13 +15355,15 @@ "dev": true }, "@jridgewell/sourcemap-codec": { - "version": "1.4.14", + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", "dev": true }, "@jridgewell/trace-mapping": { - "version": "0.3.20", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz", - "integrity": "sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==", + "version": "0.3.22", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.22.tgz", + "integrity": "sha512-Wf963MzWtA2sjrNt+g18IAln9lKnlRp+K2eH4jjIoF1wYeq3aMREpG09xhlhdzS0EjwU7qmUJYangWa+151vZw==", "dev": true, "requires": { "@jridgewell/resolve-uri": "^3.1.0", @@ -15407,9 +15449,9 @@ } }, "@npmcli/git": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/@npmcli/git/-/git-5.0.3.tgz", - "integrity": "sha512-UZp9NwK+AynTrKvHn5k3KviW/hA5eENmFsu3iAPe7sWRt0lFUdsY/wXIYjpDFe7cdSNwOIzbObfwgt6eL5/2zw==", + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/@npmcli/git/-/git-5.0.4.tgz", + "integrity": "sha512-nr6/WezNzuYUppzXRaYu/W4aT5rLxdXqEFupbh6e/ovlYFQ8hpu1UUPV3Ir/YTl+74iXl2ZOMlGzudh9ZPUchQ==", "dev": true, "requires": { "@npmcli/promise-spawn": "^7.0.0", @@ -15456,9 +15498,9 @@ "dev": true }, "@npmcli/promise-spawn": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@npmcli/promise-spawn/-/promise-spawn-7.0.0.tgz", - "integrity": "sha512-wBqcGsMELZna0jDblGd7UXgOby45TQaMWmbFwWX+SEotk4HV6zG2t6rT9siyLhPk4P6YYqgfL1UO8nMWDBVJXQ==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/@npmcli/promise-spawn/-/promise-spawn-7.0.1.tgz", + "integrity": "sha512-P4KkF9jX3y+7yFUxgcUdDtLy+t4OlDGuEBLNs57AZsfSfg+uV6MLndqGpnl4831ggaEdXwR50XFoZP4VFtHolg==", "dev": true, "requires": { "which": "^4.0.0" @@ -15482,9 +15524,9 @@ } }, "@npmcli/run-script": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@npmcli/run-script/-/run-script-7.0.2.tgz", - "integrity": "sha512-Omu0rpA8WXvcGeY6DDzyRoY1i5DkCBkzyJ+m2u7PD6quzb0TvSqdIPOkTn8ZBOj7LbbcbMfZ3c5skwSu6m8y2w==", + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/@npmcli/run-script/-/run-script-7.0.3.tgz", + "integrity": "sha512-ZMWGLHpzMq3rBGIwPyeaoaleaLMvrBrH8nugHxTi5ACkJZXTxXPtVuEH91ifgtss5hUwJQ2VDnzDBWPmz78rvg==", "dev": true, "requires": { "@npmcli/node-gyp": "^3.0.0", @@ -15713,14 +15755,20 @@ } }, "@sigstore/bundle": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@sigstore/bundle/-/bundle-2.1.0.tgz", - "integrity": "sha512-89uOo6yh/oxaU8AeOUnVrTdVMcGk9Q1hJa7Hkvalc6G3Z3CupWk4Xe9djSgJm9fMkH69s0P0cVHUoKSOemLdng==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@sigstore/bundle/-/bundle-2.1.1.tgz", + "integrity": "sha512-v3/iS+1nufZdKQ5iAlQKcCsoh0jffQyABvYIxKsZQFWc4ubuGjwZklFHpDgV6O6T7vvV78SW5NHI91HFKEcxKg==", "dev": true, "requires": { "@sigstore/protobuf-specs": "^0.2.1" } }, + "@sigstore/core": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@sigstore/core/-/core-0.2.0.tgz", + "integrity": "sha512-THobAPPZR9pDH2CAvDLpkrYedt7BlZnsyxDe+Isq4ZmGfPy5juOFZq487vCU2EgKD7aHSiTfE/i7sN7aEdzQnA==", + "dev": true + }, "@sigstore/protobuf-specs": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/@sigstore/protobuf-specs/-/protobuf-specs-0.2.1.tgz", @@ -15728,24 +15776,36 @@ "dev": true }, "@sigstore/sign": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@sigstore/sign/-/sign-2.2.0.tgz", - "integrity": "sha512-AAbmnEHDQv6CSfrWA5wXslGtzLPtAtHZleKOgxdQYvx/s76Fk6T6ZVt7w2IGV9j1UrFeBocTTQxaXG2oRrDhYA==", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@sigstore/sign/-/sign-2.2.1.tgz", + "integrity": "sha512-U5sKQEj+faE1MsnLou1f4DQQHeFZay+V9s9768lw48J4pKykPj34rWyI1lsMOGJ3Mae47Ye6q3HAJvgXO21rkQ==", "dev": true, "requires": { - "@sigstore/bundle": "^2.1.0", + "@sigstore/bundle": "^2.1.1", + "@sigstore/core": "^0.2.0", "@sigstore/protobuf-specs": "^0.2.1", "make-fetch-happen": "^13.0.0" } }, "@sigstore/tuf": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@sigstore/tuf/-/tuf-2.2.0.tgz", - "integrity": "sha512-KKATZ5orWfqd9ZG6MN8PtCIx4eevWSuGRKQvofnWXRpyMyUEpmrzg5M5BrCpjM+NfZ0RbNGOh5tCz/P2uoRqOA==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@sigstore/tuf/-/tuf-2.3.0.tgz", + "integrity": "sha512-S98jo9cpJwO1mtQ+2zY7bOdcYyfVYCUaofCG6wWRzk3pxKHVAkSfshkfecto2+LKsx7Ovtqbgb2LS8zTRhxJ9Q==", "dev": true, "requires": { "@sigstore/protobuf-specs": "^0.2.1", - "tuf-js": "^2.1.0" + "tuf-js": "^2.2.0" + } + }, + "@sigstore/verify": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/@sigstore/verify/-/verify-0.1.0.tgz", + "integrity": "sha512-2UzMNYAa/uaz11NhvgRnIQf4gpLTJ59bhb8ESXaoSS5sxedfS+eLak8bsdMc+qpNQfITUTFoSKFx5h8umlRRiA==", + "dev": true, + "requires": { + "@sigstore/bundle": "^2.1.1", + "@sigstore/core": "^0.2.0", + "@sigstore/protobuf-specs": "^0.2.1" } }, "@sindresorhus/is": { @@ -16333,65 +16393,65 @@ } }, "@tapjs/after": { - "version": "1.1.13", - "resolved": "https://registry.npmjs.org/@tapjs/after/-/after-1.1.13.tgz", - "integrity": "sha512-E2yGUayyCmgtyGDGIcejcVZjdcTmqxEfQexS/TTdELE2cCVYDlkTog5sRJVW02fQUyKrqta0X6bfUjT5+VtO9g==", + "version": "1.1.17", + "resolved": "https://registry.npmjs.org/@tapjs/after/-/after-1.1.17.tgz", + "integrity": "sha512-14qeP+mHZ8nIMDGtdCwTgvKclLlHxfARMTasb9fw//tmF/8ZDZhTemtCDxAP75wihxy5P7nzVZo/6TpVeOZrwg==", "dev": true, "requires": { "is-actual-promise": "^1.0.0" } }, "@tapjs/after-each": { - "version": "1.1.13", - "resolved": "https://registry.npmjs.org/@tapjs/after-each/-/after-each-1.1.13.tgz", - "integrity": "sha512-KnX5QCz+f0Qvm8ZkN+/QugSqbNznVTisNu+xbYWY+m2sOhUtyNYSsqvxcKEhpBTS+fRjTPl1wU5ocZv5dDUMEA==", + "version": "1.1.17", + "resolved": "https://registry.npmjs.org/@tapjs/after-each/-/after-each-1.1.17.tgz", + "integrity": "sha512-ia8sr00Wilni+2+wO4MKYCYikeRwUC41HamV8EPN63R2UmiBEOe/cMSf+KYADIh56JvxAiH7Xa0+GSFU+N2FQQ==", "dev": true, "requires": { "function-loop": "^4.0.0" } }, "@tapjs/asserts": { - "version": "1.1.13", - "resolved": "https://registry.npmjs.org/@tapjs/asserts/-/asserts-1.1.13.tgz", - "integrity": "sha512-nX9Dzkz4BToVw6Foi/naQO2oId4kvu1nOd9Brql75TrLOhSIf0BNhmUtedPouzefqHTnOQcOK+wxPqm2mUCvHQ==", + "version": "1.1.17", + "resolved": "https://registry.npmjs.org/@tapjs/asserts/-/asserts-1.1.17.tgz", + "integrity": "sha512-eKmbWBORDXu9bUHtPTu7qFrXNj5UeeH2nABJeP9BGHIn2ydmTgMEWCO3E+ljf7tisHchY5/x672lr99+O/mbTQ==", "dev": true, "requires": { - "@tapjs/stack": "1.2.6", + "@tapjs/stack": "1.2.7", "is-actual-promise": "^1.0.0", - "tcompare": "6.4.3", + "tcompare": "6.4.5", "trivial-deferred": "^2.0.0" } }, "@tapjs/before": { - "version": "1.1.13", - "resolved": "https://registry.npmjs.org/@tapjs/before/-/before-1.1.13.tgz", - "integrity": "sha512-IBgbKmc5Mqw+4JX0A52ZSn3ycwIQSNkqfOEjzELrEqhLuzeyQnb99P6QZKYfcVDaMhPqeYHRO+ziJOgtbAgPkQ==", + "version": "1.1.17", + "resolved": "https://registry.npmjs.org/@tapjs/before/-/before-1.1.17.tgz", + "integrity": "sha512-pAmEAIMIqF9MPNUgEsnuWCM00iD/FJOX0P5eXSsWexWHjuZAkv5tIT/4qpXO9KYj+9c51Lh+7YSY2Xvk1Jjolw==", "dev": true, "requires": { "is-actual-promise": "^1.0.0" } }, "@tapjs/before-each": { - "version": "1.1.13", - "resolved": "https://registry.npmjs.org/@tapjs/before-each/-/before-each-1.1.13.tgz", - "integrity": "sha512-wprmLLmX9QowI9Z5eNtQ8/PRpLHzip99PxukOR59V2839Ypmwu9e1vVfrSIU1F6u6CcUrb80SaJDf2Izm8hmBg==", + "version": "1.1.17", + "resolved": "https://registry.npmjs.org/@tapjs/before-each/-/before-each-1.1.17.tgz", + "integrity": "sha512-d2Um3Y2j0m563QNsSxczh+QeSg5sBngnBFGOelUtQVqmq91oNWU/7mY1pwN6ip8mMIQYD75CIhq5/Z57DGomWQ==", "dev": true, "requires": { "function-loop": "^4.0.0" } }, "@tapjs/config": { - "version": "2.4.9", - "resolved": "https://registry.npmjs.org/@tapjs/config/-/config-2.4.9.tgz", - "integrity": "sha512-3coHlkF0XJn59ixl0ln2vRn2SyYPUXyoLDixu4jP/C38ZA7yYTlpsDYuovNiMhXUgJi1AMbWCqASmYL49rn8Sw==", + "version": "2.4.14", + "resolved": "https://registry.npmjs.org/@tapjs/config/-/config-2.4.14.tgz", + "integrity": "sha512-dkjPVJGbLJC9BxCAxudAGiijnKc6XcQbpBSMAGJ/+VoRSqXlPkMWz0d8Ad3rNt7s+g2GBEWBx1kV7wcKtLlxmw==", "dev": true, "requires": { - "@tapjs/core": "1.4.2", - "@tapjs/test": "1.3.13", + "@tapjs/core": "1.4.6", + "@tapjs/test": "1.3.17", "chalk": "^5.2.0", "jackspeak": "^2.3.6", "polite-json": "^4.0.1", - "tap-yaml": "2.2.0", + "tap-yaml": "2.2.1", "walk-up-path": "^3.0.1" }, "dependencies": { @@ -16404,22 +16464,22 @@ } }, "@tapjs/core": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/@tapjs/core/-/core-1.4.2.tgz", - "integrity": "sha512-+mI2R8l/LjRrf7VLcme7jumi9MZb8vx3ARrheuS/djaXdcUd7lWHMjJSvCvnWhV5twTTUsfnc7GytWeFL3N4vA==", + "version": "1.4.6", + "resolved": "https://registry.npmjs.org/@tapjs/core/-/core-1.4.6.tgz", + "integrity": "sha512-cAKtdGJslrziwi/RJBU7jF930P/eSsemv295t6yLekNVP0XUCNtLFYirxuS1Xwob0nt0g/k+94xXB7o1wdTQvA==", "dev": true, "requires": { - "@tapjs/processinfo": "^3.1.5", - "@tapjs/stack": "1.2.6", - "@tapjs/test": "1.3.13", + "@tapjs/processinfo": "^3.1.6", + "@tapjs/stack": "1.2.7", + "@tapjs/test": "1.3.17", "async-hook-domain": "^4.0.1", "diff": "^5.1.0", "is-actual-promise": "^1.0.0", "minipass": "^7.0.3", "signal-exit": "4.1", - "tap-parser": "15.3.0", - "tap-yaml": "2.2.0", - "tcompare": "6.4.3", + "tap-parser": "15.3.1", + "tap-yaml": "2.2.1", + "tcompare": "6.4.5", "trivial-deferred": "^2.0.0" }, "dependencies": { @@ -16444,9 +16504,9 @@ } }, "@tapjs/error-serdes": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@tapjs/error-serdes/-/error-serdes-1.2.0.tgz", - "integrity": "sha512-Lt7kHWxILVCkfiRbsIZW5sfZ79+CmS1a+mp41dgp5oiiO2TJGBSpEWptD+bIfk9tegtU4wcMUwnStymfTKl4Xw==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@tapjs/error-serdes/-/error-serdes-1.2.1.tgz", + "integrity": "sha512-/7eLEcrGo+Qz3eWrjkhDC+VSEOjabkkzr9eRADeU+OLFeZaik8L/GRk0SGhnp4YsQkv0jcNV00A42bEx2HIZcw==", "dev": true, "requires": { "minipass": "^7.0.3" @@ -16461,16 +16521,16 @@ } }, "@tapjs/filter": { - "version": "1.2.13", - "resolved": "https://registry.npmjs.org/@tapjs/filter/-/filter-1.2.13.tgz", - "integrity": "sha512-HahbPSl5gkJ12pIRqMq595A0zNMaTSUvQyLYtDX8GhQM7YanCMLPPPfxg5SFk2p7XinxN5HUiZ5i+Jh1W9tpeQ==", + "version": "1.2.17", + "resolved": "https://registry.npmjs.org/@tapjs/filter/-/filter-1.2.17.tgz", + "integrity": "sha512-ytsqoPThV92ML1+M+cHlhAS7nOQpDNRBJiPqw20/GmNeoQXsDzVUlWR89DP3WNNUPrr/c1pCVr9XHVhCIeYk0w==", "dev": true, "requires": {} }, "@tapjs/fixture": { - "version": "1.2.13", - "resolved": "https://registry.npmjs.org/@tapjs/fixture/-/fixture-1.2.13.tgz", - "integrity": "sha512-PPw4EqgIwOzoPjaPSv4O6l7e5RKLEhJH1CbrTqdaM2YxuLgC9Gv9AN0LxJsXsfTnJgoWodzC29dE7JB5RJINuQ==", + "version": "1.2.17", + "resolved": "https://registry.npmjs.org/@tapjs/fixture/-/fixture-1.2.17.tgz", + "integrity": "sha512-eOOQxtsEcQ/sBxaZhpqdF9DCNxXAvLuiE5HgyL6d1eB4eceu57uIUKK7NDtFVv+vlbQH/NoiSTxmN/IBRbKT8w==", "dev": true, "requires": { "mkdirp": "^3.0.0", @@ -16532,42 +16592,42 @@ } }, "@tapjs/intercept": { - "version": "1.2.13", - "resolved": "https://registry.npmjs.org/@tapjs/intercept/-/intercept-1.2.13.tgz", - "integrity": "sha512-/miqU/GK+AFW1y7Wc3N/1OpcFYK++voQ/Ai4u2cORbcxnUt0cWBxHPOZOyepZqwX88sPwr1NdrCV1/B3BbgPWw==", + "version": "1.2.17", + "resolved": "https://registry.npmjs.org/@tapjs/intercept/-/intercept-1.2.17.tgz", + "integrity": "sha512-CNuYBxiFBMNALS1PxH3yGI10H8ObxOoD67C2xGWyzXeYrPJ/R4x31Sda9bqaoK3uf/vj28bC9kSECCFjRsNAEg==", "dev": true, "requires": { - "@tapjs/after": "1.1.13", - "@tapjs/stack": "1.2.6" + "@tapjs/after": "1.1.17", + "@tapjs/stack": "1.2.7" } }, "@tapjs/mock": { - "version": "1.2.11", - "resolved": "https://registry.npmjs.org/@tapjs/mock/-/mock-1.2.11.tgz", - "integrity": "sha512-fXMvbQa04qfnNjgGN/cKWj52flYpN8J18/gkWQDbiOLieC1QJVtF1tkTohL602mqVbxn+9rOpTPjDvyJhi65zg==", + "version": "1.2.15", + "resolved": "https://registry.npmjs.org/@tapjs/mock/-/mock-1.2.15.tgz", + "integrity": "sha512-uXfVNDAMAbCGOu46B9jbryTau2pLSQjCdWnkAm/OUgZh/OtO0i7OORz9HdEPfEF2tuy1tLo9+vsCZm3lPU5F7w==", "dev": true, "requires": { - "@tapjs/after": "1.1.13", - "@tapjs/stack": "1.2.6", - "resolve-import": "^1.4.4", + "@tapjs/after": "1.1.17", + "@tapjs/stack": "1.2.7", + "resolve-import": "^1.4.5", "walk-up-path": "^3.0.1" } }, "@tapjs/node-serialize": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@tapjs/node-serialize/-/node-serialize-1.2.2.tgz", - "integrity": "sha512-ycPPYNxRsj/AFoqaGY5P38nehMVcwMAz7U0uRO7/2dh4vxUQcKyIBh5KNhB3z/EEas5wiQip+YJ1CW1fAx/PHg==", + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@tapjs/node-serialize/-/node-serialize-1.2.6.tgz", + "integrity": "sha512-xj1OJEsdTr0pQFlirfe/apN0dHUCMCx2Nm5H3SoiSOW4D1/FUKS65VZpWgo3mXMPxRyb/2T1DH3xON1eSGq4ww==", "dev": true, "requires": { - "@tapjs/error-serdes": "1.2.0", - "@tapjs/stack": "1.2.6", - "tap-parser": "15.3.0" + "@tapjs/error-serdes": "1.2.1", + "@tapjs/stack": "1.2.7", + "tap-parser": "15.3.1" } }, "@tapjs/processinfo": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/@tapjs/processinfo/-/processinfo-3.1.5.tgz", - "integrity": "sha512-KCx0Dbatmuja9soLFFK1asDwodz+16gwHL9QWiziz83b7LK4x5h9kiUbbhTi3I3wtKREeaN8caNA0Z2m6Yxsag==", + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/@tapjs/processinfo/-/processinfo-3.1.6.tgz", + "integrity": "sha512-ktDsaf79wJsLaoG1Pp+stHSRf6a1k/JydoRAaYVG5iJnd3DooL6yewZsciUi2yiN/WQc5tAXCIFTXL4uXGB8LA==", "dev": true, "requires": { "pirates": "^4.0.5", @@ -16585,13 +16645,13 @@ } }, "@tapjs/reporter": { - "version": "1.3.10", - "resolved": "https://registry.npmjs.org/@tapjs/reporter/-/reporter-1.3.10.tgz", - "integrity": "sha512-5fDwmDMXe20NiW8p8AQ7Tn9mrnFCwY3qX7iBJ7z2+4cgAzvoLdkqcjoUwBW15KwxfcJPm8oFMhf0Wv+d84A7OQ==", + "version": "1.3.15", + "resolved": "https://registry.npmjs.org/@tapjs/reporter/-/reporter-1.3.15.tgz", + "integrity": "sha512-us1vXd6TW1V8wJxxnP2a8DNSP1WFTpODyYukqWg7ym5nCalREYnz2MFsn65rRNu/xJlmqsmv+9P63rupud7Zlg==", "dev": true, "requires": { - "@tapjs/config": "2.4.9", - "@tapjs/stack": "1.2.6", + "@tapjs/config": "2.4.14", + "@tapjs/stack": "1.2.7", "chalk": "^5.2.0", "ink": "^4.4.1", "minipass": "^7.0.3", @@ -16600,9 +16660,9 @@ "prismjs-terminal": "^1.2.3", "react": "^18.2.0", "string-length": "^6.0.0", - "tap-parser": "15.3.0", - "tap-yaml": "2.2.0", - "tcompare": "6.4.3" + "tap-parser": "15.3.1", + "tap-yaml": "2.2.1", + "tcompare": "6.4.5" }, "dependencies": { "chalk": { @@ -16626,19 +16686,19 @@ } }, "@tapjs/run": { - "version": "1.4.10", - "resolved": "https://registry.npmjs.org/@tapjs/run/-/run-1.4.10.tgz", - "integrity": "sha512-m1464ealbd+NL2WkYoevFveXhwCNU1I+MG0JpuAh/7MSEORRiG73ivRQOyfBVxfjeFMHVy4i99Sx1x9WDkHO7Q==", - "dev": true, - "requires": { - "@tapjs/after": "1.1.13", - "@tapjs/before": "1.1.13", - "@tapjs/config": "2.4.9", - "@tapjs/processinfo": "^3.1.5", - "@tapjs/reporter": "1.3.10", - "@tapjs/spawn": "1.1.13", - "@tapjs/stdin": "1.1.13", - "@tapjs/test": "1.3.13", + "version": "1.4.16", + "resolved": "https://registry.npmjs.org/@tapjs/run/-/run-1.4.16.tgz", + "integrity": "sha512-ZTESjBDj5SitZgWz2hQdzfBoxgaFs89jQjWzqobcdfro0iF7TVRpSrvpz9GTMdo2Tu9aeFfMNfmaAtwNWnDabw==", + "dev": true, + "requires": { + "@tapjs/after": "1.1.17", + "@tapjs/before": "1.1.17", + "@tapjs/config": "2.4.14", + "@tapjs/processinfo": "^3.1.6", + "@tapjs/reporter": "1.3.15", + "@tapjs/spawn": "1.1.17", + "@tapjs/stdin": "1.1.17", + "@tapjs/test": "1.3.17", "c8": "^8.0.1", "chalk": "^5.3.0", "chokidar": "^3.5.3", @@ -16648,13 +16708,13 @@ "mkdirp": "^3.0.1", "opener": "^1.5.2", "pacote": "^17.0.3", - "resolve-import": "^1.4.4", + "resolve-import": "^1.4.5", "rimraf": "^5.0.5", "semver": "^7.5.4", "signal-exit": "^4.1.0", - "tap-parser": "15.3.0", - "tap-yaml": "2.2.0", - "tcompare": "6.4.3", + "tap-parser": "15.3.1", + "tap-yaml": "2.2.1", + "tcompare": "6.4.5", "trivial-deferred": "^2.0.0", "which": "^4.0.0" }, @@ -16741,65 +16801,65 @@ } }, "@tapjs/snapshot": { - "version": "1.2.13", - "resolved": "https://registry.npmjs.org/@tapjs/snapshot/-/snapshot-1.2.13.tgz", - "integrity": "sha512-/vW3kOxNA1vclsEU87A5vZ7edRbrL1Hlm7LauJwRAvAgdW2VrEcc1ivyCMbWvYi11csGu1MM9A2Poo/aOhzQ/Q==", + "version": "1.2.17", + "resolved": "https://registry.npmjs.org/@tapjs/snapshot/-/snapshot-1.2.17.tgz", + "integrity": "sha512-xDHys854ZA8s/1uCkE5PgBz4H1vYKChD6a4xjLVkaoRxpBHVp/IJZCD+8d69DRGnyuA4x2MGh0JLClTA9bLGrA==", "dev": true, "requires": { "is-actual-promise": "^1.0.0", - "tcompare": "6.4.3", + "tcompare": "6.4.5", "trivial-deferred": "^2.0.0" } }, "@tapjs/spawn": { - "version": "1.1.13", - "resolved": "https://registry.npmjs.org/@tapjs/spawn/-/spawn-1.1.13.tgz", - "integrity": "sha512-s2byTuuyyPv+8uI4xSspFhiFPddi/Bwz2a/RHQVm3IKuvO0gW9KA53J8PEjWIRXLFNgf5X0xWIYGgMXeklYN/w==", + "version": "1.1.17", + "resolved": "https://registry.npmjs.org/@tapjs/spawn/-/spawn-1.1.17.tgz", + "integrity": "sha512-Bbyxd91bgXEcglvXYKrRl2MaNHk00RajTZJ1kKe3Scr1ivaYv0maE6ZInAl4UE0a4SJl4Dskec+uKoZY3qGUYQ==", "dev": true, "requires": {} }, "@tapjs/stack": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/@tapjs/stack/-/stack-1.2.6.tgz", - "integrity": "sha512-us73FMZytpcvYT/gOSDDKHk/LLZQZ/bBLoz48VcEE5EFQmF0EELhNOlyg4Rrvj8DmuYuFjiliidiV/FB1Fchaw==", + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@tapjs/stack/-/stack-1.2.7.tgz", + "integrity": "sha512-7qUDWDmd+y7ZQ0vTrDTvFlWnJ+ND32NemS5HVuT1ZggHtBwJ62PQHIyCx/B5RopETBb6NvFPfUE21yTiex9Jkw==", "dev": true }, "@tapjs/stdin": { - "version": "1.1.13", - "resolved": "https://registry.npmjs.org/@tapjs/stdin/-/stdin-1.1.13.tgz", - "integrity": "sha512-ilamAMcQ7TPzuB4fVLtTyCYaqU3bAh1YLssmwtcYwRE0J4szNIFLMsduVjWLNGnjViKRHI6x1iHGOZg2IwTXug==", + "version": "1.1.17", + "resolved": "https://registry.npmjs.org/@tapjs/stdin/-/stdin-1.1.17.tgz", + "integrity": "sha512-mDutFFPDnlVM2oYDAfyYKA+fC+aEiyz5n08D8x6YAbwZNbTIVp+h6ucyp7ygJ04fshd4l3s1HUmCZLSmHb2xEw==", "dev": true, "requires": {} }, "@tapjs/test": { - "version": "1.3.13", - "resolved": "https://registry.npmjs.org/@tapjs/test/-/test-1.3.13.tgz", - "integrity": "sha512-eqlrFgdMwOuqMeMGWMButPmas7q5Z0yEqmyBZIsjKk246wN1GUKIwGxX+K0THMBHaiSKW4c/PvXpMynZyywqbw==", - "dev": true, - "requires": { - "@isaacs/ts-node-temp-fork-for-pr-2009": "^10.9.1", - "@tapjs/after": "1.1.13", - "@tapjs/after-each": "1.1.13", - "@tapjs/asserts": "1.1.13", - "@tapjs/before": "1.1.13", - "@tapjs/before-each": "1.1.13", - "@tapjs/filter": "1.2.13", - "@tapjs/fixture": "1.2.13", - "@tapjs/intercept": "1.2.13", - "@tapjs/mock": "1.2.11", - "@tapjs/node-serialize": "1.2.2", - "@tapjs/snapshot": "1.2.13", - "@tapjs/spawn": "1.1.13", - "@tapjs/stdin": "1.1.13", - "@tapjs/typescript": "1.3.2", - "@tapjs/worker": "1.1.13", + "version": "1.3.17", + "resolved": "https://registry.npmjs.org/@tapjs/test/-/test-1.3.17.tgz", + "integrity": "sha512-yQ4uHC2GaDS+Gr5qwx9uMGxqvpYgnlVY+QexBReSeYZthWIN0KD8HDvnVt4An5Sx/Qhd7UlnNpNMBd6AkvPEew==", + "dev": true, + "requires": { + "@isaacs/ts-node-temp-fork-for-pr-2009": "^10.9.5", + "@tapjs/after": "1.1.17", + "@tapjs/after-each": "1.1.17", + "@tapjs/asserts": "1.1.17", + "@tapjs/before": "1.1.17", + "@tapjs/before-each": "1.1.17", + "@tapjs/filter": "1.2.17", + "@tapjs/fixture": "1.2.17", + "@tapjs/intercept": "1.2.17", + "@tapjs/mock": "1.2.15", + "@tapjs/node-serialize": "1.2.6", + "@tapjs/snapshot": "1.2.17", + "@tapjs/spawn": "1.1.17", + "@tapjs/stdin": "1.1.17", + "@tapjs/typescript": "1.3.6", + "@tapjs/worker": "1.1.17", "glob": "^10.3.10", "jackspeak": "^2.3.6", "mkdirp": "^3.0.0", - "resolve-import": "^1.4.4", + "resolve-import": "^1.4.5", "rimraf": "^5.0.5", "sync-content": "^1.0.1", - "tap-parser": "15.3.0", + "tap-parser": "15.3.1", "tshy": "^1.2.2", "typescript": "5.2" }, @@ -16865,18 +16925,18 @@ } }, "@tapjs/typescript": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@tapjs/typescript/-/typescript-1.3.2.tgz", - "integrity": "sha512-R8E36Kd1ImufcygVzSbQt/rEgg5RIW+CvIBzJNmv1IczRoAVFo5/OElZwOThiko7CAxDMRJxI8Cla63uK3gsLA==", + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/@tapjs/typescript/-/typescript-1.3.6.tgz", + "integrity": "sha512-bHqQb06HcD1vFvSwElH0WK4cnCNthvA5OX/KBs5w1TNFHIeRHemp/hsSnGSNDwYwDETuOxD68rDZNTpNbzysBg==", "dev": true, "requires": { - "@isaacs/ts-node-temp-fork-for-pr-2009": "^10.9.1" + "@isaacs/ts-node-temp-fork-for-pr-2009": "^10.9.5" } }, "@tapjs/worker": { - "version": "1.1.13", - "resolved": "https://registry.npmjs.org/@tapjs/worker/-/worker-1.1.13.tgz", - "integrity": "sha512-B/g1rdQcuOFdU6OeBHkdYUjzM6pbHo64nV+ckQNE7Atj4yzV0u7C+Emq+f7F+zItsGXaMm/a4Z7Zoliszy7YXw==", + "version": "1.1.17", + "resolved": "https://registry.npmjs.org/@tapjs/worker/-/worker-1.1.17.tgz", + "integrity": "sha512-DCRzEBT+OgP518rQqzlX6KawvGTegkeEjPVa/TB6Iifj8WOHJ+XtunkR7riIRGEoCEOMD49DCJXj70c+XP0jNw==", "dev": true, "requires": {} }, @@ -16969,9 +17029,9 @@ "dev": true }, "@types/istanbul-lib-coverage": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.5.tgz", - "integrity": "sha512-zONci81DZYCZjiLe0r6equvZut0b+dBRPBN5kBDjsONnutYNtJMoWQ9uR2RkL1gLG9NMTzvf+29e5RFfPbeKhQ==", + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", + "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", "dev": true }, "@types/json-schema": { @@ -17143,7 +17203,9 @@ } }, "acorn": { - "version": "8.8.2", + "version": "8.11.3", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", + "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", "dev": true }, "acorn-jsx": { @@ -17152,9 +17214,9 @@ "requires": {} }, "acorn-walk": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.0.tgz", - "integrity": "sha512-FS7hV565M5l1R08MXqo8odwMTB02C2UqzB17RVgu9EyuYFBqJZ3/ZY97sQD5FewVu1UyDFc1yztUDrAwT0EypA==", + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.2.tgz", + "integrity": "sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A==", "dev": true }, "adm-zip": { @@ -17819,9 +17881,9 @@ } }, "cacache": { - "version": "18.0.0", - "resolved": "https://registry.npmjs.org/cacache/-/cacache-18.0.0.tgz", - "integrity": "sha512-I7mVOPl3PUCeRub1U8YoGz2Lqv9WOBpobZ8RyWFXmReuILz+3OAyTa5oH3QPdtKZD7N0Yk00aLfzn0qvp8dZ1w==", + "version": "18.0.2", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-18.0.2.tgz", + "integrity": "sha512-r3NU8h/P+4lVUHfeRw1dtgQYar3DZMm4/cm2bZgOvrFC/su7budSOeqh52VJIC4U4iG1WWwV6vRW0znqBvxNuw==", "dev": true, "requires": { "@npmcli/fs": "^3.1.0", @@ -17829,7 +17891,7 @@ "glob": "^10.2.2", "lru-cache": "^10.0.1", "minipass": "^7.0.3", - "minipass-collect": "^1.0.2", + "minipass-collect": "^2.0.1", "minipass-flush": "^1.0.5", "minipass-pipeline": "^1.2.4", "p-map": "^4.0.0", @@ -19902,9 +19964,9 @@ "dev": true }, "ignore-walk": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-6.0.3.tgz", - "integrity": "sha512-C7FfFoTA+bI10qfeydT8aZbvr91vAEU+2W5BZUlzPec47oNb07SsOfwYrtxuvOYdUApPP/Qlh4DtAO51Ekk2QA==", + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-6.0.4.tgz", + "integrity": "sha512-t7sv42WkwFkyKbivUCglsQW5YWMskWtbEf4MNKX5u/CCWHKSPzN4FtBQGsQZgCLbxOzpVlcbWVK5KB3auIOjSw==", "dev": true, "requires": { "minimatch": "^9.0.0" @@ -20117,9 +20179,9 @@ } }, "ws": { - "version": "8.14.2", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.14.2.tgz", - "integrity": "sha512-wEBG1ftX4jcglPxgFCMJmZ2PLtSbJ2Peg6TmpJFTbe9GZYOQCDPdMYu/Tm0/bGZkw8paZnJY45J4K2PZrLYq8g==", + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.16.0.tgz", + "integrity": "sha512-HS0c//TP7Ina87TfiPUz1rQzMhHrl/SG2guqRcTOIUYD2q8uhUdNHZYJUaQ8aTGPzCh+c6oawMKW35nFl1dxyQ==", "dev": true, "requires": {} } @@ -20407,9 +20469,9 @@ "requires": {} }, "istanbul-lib-coverage": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", - "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==", + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", + "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", "dev": true }, "istanbul-lib-report": { @@ -20550,9 +20612,9 @@ "dev": true }, "json-parse-even-better-errors": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-3.0.0.tgz", - "integrity": "sha512-iZbGHafX/59r39gPwVPRBGw0QQKnA7tte5pSMrhWOW7swGsVvVTjmfyAV9pNqk8YGT7tRCdxRu8uzcgZwoDooA==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-3.0.1.tgz", + "integrity": "sha512-aatBvbL26wVUCLmbWdCpeu9iF5wOyWpagiKkInA+kfws3sWdBrTnsvN2CKcyCYyUrc7rebNBlK6+kteg7ksecg==", "dev": true }, "json-refs": { @@ -20836,15 +20898,6 @@ "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", "dev": true }, - "npm-run-path": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.1.0.tgz", - "integrity": "sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q==", - "dev": true, - "requires": { - "path-key": "^4.0.0" - } - }, "onetime": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", @@ -20854,18 +20907,6 @@ "mimic-fn": "^4.0.0" } }, - "path-key": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", - "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", - "dev": true - }, - "strip-final-newline": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", - "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", - "dev": true - }, "yaml": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.1.tgz", @@ -21057,9 +21098,9 @@ "dev": true }, "lru-cache": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.0.1.tgz", - "integrity": "sha512-IJ4uwUTi2qCccrioU6g9g/5rvvVl13bsdczUUcqbciD9iLr095yj8DQKdObriEvuNSx325N1rV1O0sJFszx75g==", + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.1.0.tgz", + "integrity": "sha512-/1clY/ui8CzjKFyjdvwPWJUYKiFVXG2I2cY0ssG7h4+hwk+XOIX7ZSG9Q7TW8TW3Kp3BUSqgFWBLgL4PJ+Blag==", "dev": true }, "lru-queue": { @@ -21196,12 +21237,20 @@ } }, "minipass-collect": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-1.0.2.tgz", - "integrity": "sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-2.0.1.tgz", + "integrity": "sha512-D7V8PO9oaz7PWGLbCACuI1qEOsq7UKfLotx/C0Aet43fCUB/wfQ7DYeq2oR/svFJGYDHPr38SHATeaj/ZoKHKw==", "dev": true, "requires": { - "minipass": "^3.0.0" + "minipass": "^7.0.3" + }, + "dependencies": { + "minipass": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", + "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==", + "dev": true + } } }, "minipass-fetch": { @@ -21374,9 +21423,9 @@ } }, "node-gyp": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-10.0.0.tgz", - "integrity": "sha512-LkaKUbjyacJGRHiuhUeUblzZNxTF1/XNooyAl6aiaJ6ZpeurR4Mk9sjxncGNSI7pETqyqM+hLAER0788oSxt0A==", + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-10.0.1.tgz", + "integrity": "sha512-gg3/bHehQfZivQVfqIyy8wTdSymF9yTyP4CJifK73imyNMU8AIGQE2pUa7dNWfmMeG9cDVF2eehiRMv0LC1iAg==", "dev": true, "requires": { "env-paths": "^2.2.0", @@ -21522,12 +21571,12 @@ } }, "npm-packlist": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-8.0.0.tgz", - "integrity": "sha512-ErAGFB5kJUciPy1mmx/C2YFbvxoJ0QJ9uwkCZOeR6CqLLISPZBOiFModAbSXnjjlwW5lOhuhXva+fURsSGJqyw==", + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-8.0.2.tgz", + "integrity": "sha512-shYrPFIS/JLP4oQmAwDyk5HcyysKW8/JLTEA32S0Z5TzvpaeeX2yMFfoK1fjEBnCBvVyIB/Jj/GBFdm0wsgzbA==", "dev": true, "requires": { - "ignore-walk": "^6.0.0" + "ignore-walk": "^6.0.4" } }, "npm-pick-manifest": { @@ -21578,6 +21627,23 @@ "validate-npm-package-name": "^3.0.0" } }, + "npm-run-path": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.2.0.tgz", + "integrity": "sha512-W4/tgAXFqFA0iL7fk0+uQ3g7wkL8xJmx3XdK0VGb4cHW//eZTtKGvFBBoRKVTpY7n6ze4NL9ly7rgXcHufqXKg==", + "dev": true, + "requires": { + "path-key": "^4.0.0" + }, + "dependencies": { + "path-key": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", + "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", + "dev": true + } + } + }, "object-assign": { "version": "4.1.1", "dev": true @@ -21737,9 +21803,9 @@ } }, "pacote": { - "version": "17.0.4", - "resolved": "https://registry.npmjs.org/pacote/-/pacote-17.0.4.tgz", - "integrity": "sha512-eGdLHrV/g5b5MtD5cTPyss+JxOlaOloSMG3UwPMAvL8ywaLJ6beONPF40K4KKl/UI6q5hTKCJq5rCu8tkF+7Dg==", + "version": "17.0.6", + "resolved": "https://registry.npmjs.org/pacote/-/pacote-17.0.6.tgz", + "integrity": "sha512-cJKrW21VRE8vVTRskJo78c/RCvwJCn1f4qgfxL4w77SOWrTCRcmfkYHlHtS0gqpgjv3zhXflRtgsrUCX5xwNnQ==", "dev": true, "requires": { "@npmcli/git": "^5.0.0", @@ -21757,7 +21823,7 @@ "promise-retry": "^2.0.1", "read-package-json": "^7.0.0", "read-package-json-fast": "^3.0.0", - "sigstore": "^2.0.0", + "sigstore": "^2.2.0", "ssri": "^10.0.0", "tar": "^6.1.11" }, @@ -22282,9 +22348,9 @@ "dev": true }, "resolve-import": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/resolve-import/-/resolve-import-1.4.4.tgz", - "integrity": "sha512-+IccDyUypl5rHv25216cXu2m30flEoetrG8p4qDH3RsP53cytedI58Pz+pjCU4PAbxPOQgFkgmxTJLKI9tgf/g==", + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/resolve-import/-/resolve-import-1.4.5.tgz", + "integrity": "sha512-HXb4YqODuuXT7Icq1Z++0g2JmhgbUHSs3VT2xR83gqvAPUikYT2Xk+562KHQgiaNkbBOlPddYrDLsC44qQggzw==", "dev": true, "requires": { "glob": "^10.3.3", @@ -22770,15 +22836,17 @@ "dev": true }, "sigstore": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/sigstore/-/sigstore-2.1.0.tgz", - "integrity": "sha512-kPIj+ZLkyI3QaM0qX8V/nSsweYND3W448pwkDgS6CQ74MfhEkIR8ToK5Iyx46KJYRjseVcD3Rp9zAmUAj6ZjPw==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/sigstore/-/sigstore-2.2.0.tgz", + "integrity": "sha512-fcU9clHwEss2/M/11FFM8Jwc4PjBgbhXoNskoK5guoK0qGQBSeUbQZRJ+B2fDFIvhyf0gqCaPrel9mszbhAxug==", "dev": true, "requires": { - "@sigstore/bundle": "^2.1.0", + "@sigstore/bundle": "^2.1.1", + "@sigstore/core": "^0.2.0", "@sigstore/protobuf-specs": "^0.2.1", - "@sigstore/sign": "^2.1.0", - "@sigstore/tuf": "^2.1.0" + "@sigstore/sign": "^2.2.1", + "@sigstore/tuf": "^2.3.0", + "@sigstore/verify": "^0.1.0" } }, "simple-git": { @@ -23111,6 +23179,12 @@ "is-natural-number": "^4.0.1" } }, + "strip-final-newline": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", + "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", + "dev": true + }, "strip-json-comments": { "version": "3.1.1", "dev": true @@ -23237,46 +23311,46 @@ } }, "tap": { - "version": "18.5.3", - "resolved": "https://registry.npmjs.org/tap/-/tap-18.5.3.tgz", - "integrity": "sha512-TrcgwuQp0siTg/2MGJiZ1T5f3N+JZAOpPq+VR66+j6x9dCxw+1CuaUzWGW34ebCTxy8efT0akZ6dbGlbJVBhRA==", - "dev": true, - "requires": { - "@tapjs/after": "1.1.13", - "@tapjs/after-each": "1.1.13", - "@tapjs/asserts": "1.1.13", - "@tapjs/before": "1.1.13", - "@tapjs/before-each": "1.1.13", - "@tapjs/core": "1.4.2", - "@tapjs/filter": "1.2.13", - "@tapjs/fixture": "1.2.13", - "@tapjs/intercept": "1.2.13", - "@tapjs/mock": "1.2.11", - "@tapjs/node-serialize": "1.2.2", - "@tapjs/run": "1.4.10", - "@tapjs/snapshot": "1.2.13", - "@tapjs/spawn": "1.1.13", - "@tapjs/stdin": "1.1.13", - "@tapjs/test": "1.3.13", - "@tapjs/typescript": "1.3.2", - "@tapjs/worker": "1.1.13", - "resolve-import": "^1.4.4" + "version": "18.6.1", + "resolved": "https://registry.npmjs.org/tap/-/tap-18.6.1.tgz", + "integrity": "sha512-5cBQhJ1gdbsrTR3tA5kZZTts0HyOML6bcM7pEF7GF8d6y1ajfRMjbInS1Ty7/x2Ip0ko3cY1dYjPJ9JFNPsm7w==", + "dev": true, + "requires": { + "@tapjs/after": "1.1.17", + "@tapjs/after-each": "1.1.17", + "@tapjs/asserts": "1.1.17", + "@tapjs/before": "1.1.17", + "@tapjs/before-each": "1.1.17", + "@tapjs/core": "1.4.6", + "@tapjs/filter": "1.2.17", + "@tapjs/fixture": "1.2.17", + "@tapjs/intercept": "1.2.17", + "@tapjs/mock": "1.2.15", + "@tapjs/node-serialize": "1.2.6", + "@tapjs/run": "1.4.16", + "@tapjs/snapshot": "1.2.17", + "@tapjs/spawn": "1.1.17", + "@tapjs/stdin": "1.1.17", + "@tapjs/test": "1.3.17", + "@tapjs/typescript": "1.3.6", + "@tapjs/worker": "1.1.17", + "resolve-import": "^1.4.5" } }, "tap-parser": { - "version": "15.3.0", - "resolved": "https://registry.npmjs.org/tap-parser/-/tap-parser-15.3.0.tgz", - "integrity": "sha512-R0yLuoC288K+gHtwcOhH7Af/8EocDglAyMpaASsmzNxV1chmq3v4juSAVhvMBbPx/pRVJYrPKe9Wsj9aaqMalQ==", + "version": "15.3.1", + "resolved": "https://registry.npmjs.org/tap-parser/-/tap-parser-15.3.1.tgz", + "integrity": "sha512-hwAtXX5TBGt2MJeYvASc7DjP48PUzA7P8RTbLxQcgKCEH7ICD5IsRco7l5YvkzjHlZbUbeI9wzO8B4hw2sKgnQ==", "dev": true, "requires": { "events-to-array": "^2.0.3", - "tap-yaml": "2.2.0" + "tap-yaml": "2.2.1" } }, "tap-yaml": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/tap-yaml/-/tap-yaml-2.2.0.tgz", - "integrity": "sha512-o8I7WDNiGpuF04tGAVaNYY5rX9waCtqw9A7Y0YVSQBGcFwNUJWUPLkr2lbhgLRTxc+Tpnw4xUXlIanZc+ZAGnw==", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tap-yaml/-/tap-yaml-2.2.1.tgz", + "integrity": "sha512-ovZuUMLAIH59jnFHXKEGJ+WyDYl6Cuduwg9qpvnqkZOUA1nU84q02Sry1HT0KXcdv2uB91bEKKxnIybBgrb6oA==", "dev": true, "requires": { "yaml": "^2.3.0", @@ -23284,9 +23358,9 @@ }, "dependencies": { "yaml": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.3.tgz", - "integrity": "sha512-zw0VAJxgeZ6+++/su5AFoqBbZbrEakwu+X0M5HmcwUiBL7AzcuPKjj5we4xfQLp78LkEMpD0cOnUhmgOVy3KdQ==", + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.4.tgz", + "integrity": "sha512-8aAvwVUSHpfEqTQ4w/KMlf3HcRdt50E5ODIQJBw1fQ5RL34xabzxtUlzTXVqc4rkZsPbvrXKWnABCD7kWSmocA==", "dev": true }, "yaml-types": { @@ -23338,9 +23412,9 @@ } }, "tcompare": { - "version": "6.4.3", - "resolved": "https://registry.npmjs.org/tcompare/-/tcompare-6.4.3.tgz", - "integrity": "sha512-bKVNHmQ6Nd7/K3+SFuhsppUrXGwQjXts/U9NAVz52JNYeOlyCjtVydNZHgscw3RmtHp+JdWuheYjVqPvY9x9kg==", + "version": "6.4.5", + "resolved": "https://registry.npmjs.org/tcompare/-/tcompare-6.4.5.tgz", + "integrity": "sha512-Whuz9xlKKI2XXICKDSDRKjXdBuC6gBNOgmEUtH7UFyQeYzfUMQ19DyjZULarGKDGFhgOg3CJ+IQUEfpkOPg0Uw==", "dev": true, "requires": { "diff": "^5.1.0", @@ -23505,9 +23579,9 @@ } }, "tshy": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/tshy/-/tshy-1.7.0.tgz", - "integrity": "sha512-ioFoMasVNtcOGkJACDpmo+C6xZfRqamimeK0hL2uyS0l7DliiCwAKJj8/x0LVlvdGvCoqkhOHfKpEPjHeI9U8Q==", + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/tshy/-/tshy-1.11.0.tgz", + "integrity": "sha512-5T5PVyuYQKTcOKz5a2lpwx4WKi8yEzQGO0Q5l+9clJMYupMaTI7ONEwKggGAZDQQGIgCOyUCfBWnSkG0XdJc+A==", "dev": true, "requires": { "chalk": "^5.3.0", @@ -23517,7 +23591,7 @@ "resolve-import": "^1.4.4", "rimraf": "^5.0.1", "sync-content": "^1.0.2", - "typescript": "5.2", + "typescript": "5.2 || 5.3", "walk-up-path": "^3.0.1" }, "dependencies": { @@ -23580,9 +23654,9 @@ } }, "typescript": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz", - "integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==", + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz", + "integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==", "dev": true } } @@ -23611,9 +23685,9 @@ } }, "tuf-js": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/tuf-js/-/tuf-js-2.1.0.tgz", - "integrity": "sha512-eD7YPPjVlMzdggrOeE8zwoegUaG/rt6Bt3jwoQPunRiNVzgcCE009UDFJKJjG+Gk9wFu6W/Vi+P5d/5QpdD9jA==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tuf-js/-/tuf-js-2.2.0.tgz", + "integrity": "sha512-ZSDngmP1z6zw+FIkIBjvOp/II/mIub/O7Pp12j1WNsiCpg5R5wAc//i555bBQsE44O94btLt0xM/Zr2LQjwdCg==", "dev": true, "requires": { "@tufjs/models": "2.0.0", @@ -23772,9 +23846,9 @@ "dev": true }, "v8-to-istanbul": { - "version": "9.1.3", - "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.1.3.tgz", - "integrity": "sha512-9lDD+EVI2fjFsMWXc6dy5JJzBsVTcQ2fVkfBvncZ6xJWG9wtBhOldG+mHkSL0+V1K/xgZz0JDO5UT5hFwHUghg==", + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.2.0.tgz", + "integrity": "sha512-/EH/sDgxU2eGxajKdwLCDmQ4FWq+kpi3uCmBGpw1xJtnAxEjlD8j8PEiGWpCIMIs3ciNAgH0d3TTJiUkYzyZjA==", "dev": true, "requires": { "@jridgewell/trace-mapping": "^0.3.12", diff --git a/package.json b/package.json index cc0038b3..2fe59a48 100644 --- a/package.json +++ b/package.json @@ -62,7 +62,7 @@ "is-ci": "^3.0.1", "lint-staged": "^13.1.2", "regenerator-runtime": "^0.13.11", - "tap": "^18.5.3", + "tap": "^18.6.1", "ts-node": "^10.9.1", "type-fest": "^3.6.1", "typescript": "^4.9.5" From 443cdc03074be7e59e8a2553603bf2817c35f23d Mon Sep 17 00:00:00 2001 From: Eoin Shanaghy Date: Mon, 22 Jan 2024 12:18:57 +0000 Subject: [PATCH 32/35] 3.2.0-rc1 --- cdk-test-project/package.json | 2 +- cf-macro/package.json | 2 +- cf-macro/template.yaml | 2 +- core/package.json | 2 +- package-lock.json | 22 ++++++++++---------- package.json | 2 +- sam-test-project/package.json | 2 +- serverless-plugin/package.json | 2 +- serverless-test-project-alb/package.json | 2 +- serverless-test-project-appsync/package.json | 2 +- serverless-test-project/package.json | 2 +- test-utils/package.json | 2 +- 12 files changed, 22 insertions(+), 22 deletions(-) diff --git a/cdk-test-project/package.json b/cdk-test-project/package.json index a8e2f764..938c3db3 100644 --- a/cdk-test-project/package.json +++ b/cdk-test-project/package.json @@ -1,6 +1,6 @@ { "name": "cdk-test-project", - "version": "3.1.0", + "version": "3.2.0-rc1", "scripts": { "build": "tsc", "watch": "tsc -w", diff --git a/cf-macro/package.json b/cf-macro/package.json index 42be80dc..59e86570 100644 --- a/cf-macro/package.json +++ b/cf-macro/package.json @@ -7,7 +7,7 @@ "url": "https://github.com/fourTheorem/slic-watch.git", "directory": "cf-macro" }, - "version": "3.1.0", + "version": "3.2.0-rc1", "private": true, "scripts": { "test": "tap --coverage-report=html --no-browser --no-check-coverage tests/**/*.test.ts", diff --git a/cf-macro/template.yaml b/cf-macro/template.yaml index 76a9f4e0..1788fbc3 100644 --- a/cf-macro/template.yaml +++ b/cf-macro/template.yaml @@ -10,7 +10,7 @@ Metadata: ReadmeUrl: ../README.md Labels: ["monitoring", "observability", "cloudwatch"] HomePageUrl: https://github.com/fourTheorem/slic-watch - SemanticVersion: 3.1.0 + SemanticVersion: 3.2.0-rc1 SourceCodeUrl: https://github.com/fourTheorem/slic-watch Resources: SlicWatch: diff --git a/core/package.json b/core/package.json index 911414e9..c2a73187 100644 --- a/core/package.json +++ b/core/package.json @@ -1,6 +1,6 @@ { "name": "slic-watch-core", - "version": "3.1.0", + "version": "3.2.0-rc1", "description": "SLIC Watch core library for adding alarms and dashboards to CloudFormation", "main": "dist/index.js", "repository": { diff --git a/package-lock.json b/package-lock.json index 4142c4e6..b2e0013c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "slic-watch", - "version": "3.1.0", + "version": "3.2.0-rc1", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "slic-watch", - "version": "3.1.0", + "version": "3.2.0-rc1", "license": "Apache", "workspaces": [ "core", @@ -57,7 +57,7 @@ } }, "cdk-test-project": { - "version": "3.1.0", + "version": "3.2.0-rc1", "dependencies": { "aws-cdk-lib": "^2.67.0", "constructs": "^10.1.266" @@ -68,7 +68,7 @@ }, "cf-macro": { "name": "cf-macro-slic-watch", - "version": "3.1.0", + "version": "3.2.0-rc1", "dependencies": { "ajv": "^8.12.0", "esbuild": "^0.17.16" @@ -76,7 +76,7 @@ }, "core": { "name": "slic-watch-core", - "version": "3.1.0", + "version": "3.2.0-rc1", "license": "ISC", "dependencies": { "@types/json-schema": "^7.0.14", @@ -14152,12 +14152,12 @@ } }, "sam-test-project": { - "version": "3.1.0", + "version": "3.2.0-rc1", "license": "Apache" }, "serverless-plugin": { "name": "serverless-slic-watch-plugin", - "version": "3.1.0", + "version": "3.2.0-rc1", "license": "Apache", "dependencies": { "ajv": "^8.11.0" @@ -14171,7 +14171,7 @@ } }, "serverless-test-project": { - "version": "3.1.0", + "version": "3.2.0-rc1", "license": "Apache", "devDependencies": { "axios": "^1.3.5", @@ -14180,14 +14180,14 @@ } }, "serverless-test-project-alb": { - "version": "3.1.0", + "version": "3.2.0-rc1", "license": "Apache", "devDependencies": { "serverless": "^3.28.1" } }, "serverless-test-project-appsync": { - "version": "3.1.0", + "version": "3.2.0-rc1", "license": "Apache", "devDependencies": { "serverless": "^3.28.1", @@ -14329,7 +14329,7 @@ "dev": true }, "test-utils": { - "version": "3.1.0", + "version": "3.2.0-rc1", "license": "Apache" } }, diff --git a/package.json b/package.json index 2fe59a48..9cfb4134 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "slic-watch", - "version": "3.1.0", + "version": "3.2.0-rc1", "description": "Root project for SLIC Watch", "main": "index.js", "type": "module", diff --git a/sam-test-project/package.json b/sam-test-project/package.json index ab4814ea..82903ea4 100755 --- a/sam-test-project/package.json +++ b/sam-test-project/package.json @@ -1,7 +1,7 @@ { "name": "sam-test-project", "description": "SLIC Watch test project for CloudFormation Macro", - "version": "3.1.0", + "version": "3.2.0-rc1", "main": "basic-handler.js", "repository": { "type": "git", diff --git a/serverless-plugin/package.json b/serverless-plugin/package.json index 907fc710..6f94bd5b 100644 --- a/serverless-plugin/package.json +++ b/serverless-plugin/package.json @@ -1,6 +1,6 @@ { "name": "serverless-slic-watch-plugin", - "version": "3.1.0", + "version": "3.2.0-rc1", "description": "Serverless plugin for automatic alarms and dashboards", "main": "dist/index.js", "repository": { diff --git a/serverless-test-project-alb/package.json b/serverless-test-project-alb/package.json index dcdc771f..57da1743 100644 --- a/serverless-test-project-alb/package.json +++ b/serverless-test-project-alb/package.json @@ -1,6 +1,6 @@ { "name": "serverless-test-project-alb", - "version": "3.1.0", + "version": "3.2.0-rc1", "description": "Test project for SLIC Watch serverless plugin", "main": "alb-handler.js", "repository": { diff --git a/serverless-test-project-appsync/package.json b/serverless-test-project-appsync/package.json index 29a4efd6..1f9629db 100644 --- a/serverless-test-project-appsync/package.json +++ b/serverless-test-project-appsync/package.json @@ -1,6 +1,6 @@ { "name": "serverless-test-project-appsync", - "version": "3.1.0", + "version": "3.2.0-rc1", "description": "Test project for SLIC Watch serverless plugin", "repository": { "type": "git", diff --git a/serverless-test-project/package.json b/serverless-test-project/package.json index f89f5d04..919a8cc0 100644 --- a/serverless-test-project/package.json +++ b/serverless-test-project/package.json @@ -1,6 +1,6 @@ { "name": "serverless-test-project", - "version": "3.1.0", + "version": "3.2.0-rc1", "description": "Test project for SLIC Watch serverless plugin", "main": "basic-handler.js", "repository": { diff --git a/test-utils/package.json b/test-utils/package.json index 28059e89..f5ceef5c 100755 --- a/test-utils/package.json +++ b/test-utils/package.json @@ -1,7 +1,7 @@ { "name": "test-utils", "description": "Common test utilities", - "version": "3.1.0", + "version": "3.2.0-rc1", "repository": { "type": "git", "url": "https://github.com/fourTheorem/slic-watch.git", From a76755c0d7f6e18827ebc83f5826bcd9ee7021b2 Mon Sep 17 00:00:00 2001 From: Eoin Shanaghy Date: Mon, 22 Jan 2024 21:30:58 +0000 Subject: [PATCH 33/35] fix: allow Lambda function config overrides without Lambda: property --- README.md | 24 ++--- core/alarms/lambda.ts | 4 +- core/cf-template.ts | 18 +++- serverless-plugin/serverless-plugin.ts | 5 +- serverless-plugin/tests/index.test.ts | 134 ++++++++++++++++++++++++- test-utils/sls-test-utils.ts | 7 +- 6 files changed, 163 insertions(+), 29 deletions(-) diff --git a/README.md b/README.md index 5550aacc..4ba9bb70 100644 --- a/README.md +++ b/README.md @@ -440,10 +440,9 @@ functions: dashboard: enabled: false # No Lambda widgets will be created for this function alarms: - Lambda: - Invocations: - Threshold: 2 # The invocation threshold is specific to - # this function's expected invocation count + Invocations: + Threshold: 2 # The invocation threshold is specific to + # this function's expected invocation count ``` To disable all alarms for any given function, use: @@ -454,8 +453,7 @@ functions: handler: basic-handler.hello slicWatch: alarms: - Lambda: - enabled: false + enabled: false ``` #### SAM/CloudFormation function-level configuration @@ -468,9 +466,8 @@ Resources: Metadata: slicWatch: alarms: - Lambda: - Invocations: - Threshold: 3 + Invocations: + Threshold: 3 dashboard: enabled: true ``` @@ -486,8 +483,7 @@ Resources: Metadata: slicWatch: alarms: - Lambda: - enabled: false + enabled: false ``` #### CDK function-level configuration @@ -497,10 +493,8 @@ const cfnFuncHello = hello.node.defaultChild as CfnResource; cfnFuncHello.cfnOptions.metadata = { slicWatch: { alarms: { - Lambda: { - Invocations: { - Threshold: 2 - } + Invocations: { + Threshold: 2 } } } diff --git a/core/alarms/lambda.ts b/core/alarms/lambda.ts index c183d0e2..8311592c 100644 --- a/core/alarms/lambda.ts +++ b/core/alarms/lambda.ts @@ -18,9 +18,9 @@ export type SlicWatchLambdaAlarmsConfig = T & { const lambdaMetrics = ['Errors', 'ThrottlesPc', 'DurationPc', 'Invocations'] /** - * Add all required Lambda alarms to the provided CloudFormation templatebased on the Lambda resources found within + * Add all required Lambda alarms to the provided CloudFormation template based on the Lambda resources found within * - * @param functionAlarmPropertiess The cascaded Lambda alarm configuration with function-specific overrides by function logical ID + * @param lambdaAlarmConfig Lambda-specific alarm configuration * @param alarmActionsConfig Notification configuration for alarm status change events * @compiledTemplate CloudFormation template object * diff --git a/core/cf-template.ts b/core/cf-template.ts index fb99ef7a..98c447f1 100644 --- a/core/cf-template.ts +++ b/core/cf-template.ts @@ -9,7 +9,7 @@ import { cascade } from './inputs/cascading-config' import { type SlicWatchMergedConfig } from './alarms/alarm-types' import { type WidgetMetricProperties } from './dashboards/dashboard-types' import { defaultConfig } from './inputs/default-config' -import { type ConfigType, cfTypeByConfigType } from './inputs/config-types' +import { ConfigType, cfTypeByConfigType } from './inputs/config-types' const logger = getLogger() @@ -69,7 +69,13 @@ export function getResourceAlarmConfigurationsByType = {} const resources = getResourcesByType(cfTypeByConfigType[type], template) for (const [funcLogicalId, resource] of Object.entries(resources)) { - const resourceConfig = resource?.Metadata?.slicWatch?.alarms // Resource-specific overrides + let legacyFallbackResourceConfig + if (type === ConfigType.Lambda) { + // Older versions only allowed function resource overrides and required the `Lambda` property within the config object + // If this is still present in configuration, we take it from here + legacyFallbackResourceConfig = resource?.Metadata?.slicWatch?.alarms?.Lambda + } + const resourceConfig = legacyFallbackResourceConfig ?? resource?.Metadata?.slicWatch?.alarms // Resource-specific overrides const defaultResourceConfig = defaultConfig.alarms?.[type] // Default configuration for the type's alarms // Cascade the default resource's configuration into the resource-specific overrides const cascadedResourceConfig = resourceConfig !== undefined ? cascade(merge({}, defaultResourceConfig, resourceConfig)) : {} @@ -97,7 +103,13 @@ export function getResourceDashboardConfigurationsByType = {} const resources = getResourcesByType(cfTypeByConfigType[type], template) for (const [logicalId, resource] of Object.entries(resources)) { - const resourceConfig = resource?.Metadata?.slicWatch?.dashboard // Resource-specific overrides + let legacyFallbackResourceConfig + if (type === ConfigType.Lambda) { + // Older versions only allowed function resource overrides and required the `Lambda` property within the config object + // If this is still present in configuration, we take it from here + legacyFallbackResourceConfig = resource?.Metadata?.slicWatch?.dashboard?.Lambda + } + const resourceConfig = legacyFallbackResourceConfig ?? resource?.Metadata?.slicWatch?.dashboard // Resource-specific overrides const defaultResourceConfig = defaultConfig.dashboard?.widgets?.[type] // Default configuration for the widget // Cascade the default resource's configuration into the resource-specific overrides const cascadedResourceConfig = resourceConfig !== undefined ? cascade(merge({}, defaultResourceConfig, resourceConfig)) : {} diff --git a/serverless-plugin/serverless-plugin.ts b/serverless-plugin/serverless-plugin.ts index 9735aa2f..e415efad 100644 --- a/serverless-plugin/serverless-plugin.ts +++ b/serverless-plugin/serverless-plugin.ts @@ -42,8 +42,8 @@ class ServerlessPlugin { } /** - * Modify the CloudFormation template before the package is finalized - */ + * Modify the CloudFormation template before the package is finalized + */ createSlicWatchResources () { const slicWatchConfig: SlicWatchConfig = this.serverless.service.custom?.slicWatch ?? {} @@ -65,6 +65,7 @@ class ServerlessPlugin { // CloudFormation Metadata on the generate AWS::Lambda::Function resource const allFunctions = this.serverless.service.getAllFunctions() as string[] this.serverless.cli.log(`Setting SLIC Watch configuration for ${allFunctions}`) + for (const funcName of allFunctions) { const func = this.serverless.service.getFunction(funcName) as any const funcConfig = func.slicWatch ?? {} diff --git a/serverless-plugin/tests/index.test.ts b/serverless-plugin/tests/index.test.ts index c0de4146..73707584 100644 --- a/serverless-plugin/tests/index.test.ts +++ b/serverless-plugin/tests/index.test.ts @@ -1,10 +1,14 @@ import { test } from 'tap' import _ from 'lodash' import ServerlessError from 'serverless/lib/serverless-error' +import type Template from 'cloudform-types/types/template' import ServerlessPlugin from '../serverless-plugin' import { getLogger } from 'slic-watch-core/logging' -import { createMockServerless, dummyLogger, pluginUtils, slsYaml } from '../../test-utils/sls-test-utils' +import { type SlsYaml, createMockServerless, dummyLogger, pluginUtils, slsYaml } from '../../test-utils/sls-test-utils' +import { type ResourceType } from 'slic-watch-core' +import { getDashboardFromTemplate, getDashboardWidgetsByTitle } from 'slic-watch-core/tests/testing-utils' +import { type MetricWidgetProperties } from 'cloudwatch-dashboard-types' interface TestData { schema? @@ -48,6 +52,134 @@ test('index', t => { t.end() }) + t.test('function-level overrides in serverless `functions` block take precedence', t => { + const compiledTemplate: Template = { + Resources: { + HelloLambdaFunction: { + Type: 'AWS::Lambda::Function', + Properties: { + FunctionName: 'serverless-test-project-dev-hello' + } + } + } + } + const slsConfig: SlsYaml = { + custom: { + slicWatch: { + alarms: { + Lambda: { + Invocations: { + enabled: true, + Threshold: 10 + } + } + }, + dashboard: { + widgets: { + Lambda: { + Invocations: { + yAxis: 'left' + } + } + } + } + } + }, + functions: { + hello: { + slicWatch: { + enabled: true + } + } + } + } + + t.test('Plugin succeeds without function-level overrides', t => { + const sls = createMockServerless(compiledTemplate, slsConfig) + const plugin = new ServerlessPlugin(sls, null, pluginUtils) + plugin.createSlicWatchResources() + const invocationAlarmProperties = (compiledTemplate.Resources as ResourceType).slicWatchLambdaInvocationsAlarmHelloLambdaFunction.Properties + t.equal(invocationAlarmProperties?.Threshold, 10) + + const { dashboard } = getDashboardFromTemplate(compiledTemplate) + const widgets = getDashboardWidgetsByTitle(dashboard, /Lambda Invocations/) + t.equal(widgets.length, 1) + t.match((widgets[0].properties as MetricWidgetProperties).metrics, [ + ['AWS/Lambda', 'Invocations', 'FunctionName', '${HelloLambdaFunction}', { stat: 'Sum', yAxis: 'left' }] + ]) + + t.end() + }) + + t.test('Plugin succeeds with function-level overrides', t => { + const modifiedSlsConfig = _.cloneDeep(slsConfig) + Object.assign(modifiedSlsConfig.functions.hello.slicWatch, { + alarms: { + Invocations: { + Threshold: 3, + enabled: true + } + }, + dashboard: { + Invocations: { + yAxis: 'right' + } + } + }) + + const sls = createMockServerless(compiledTemplate, modifiedSlsConfig) + const plugin = new ServerlessPlugin(sls, null, pluginUtils) + plugin.createSlicWatchResources() + const invocationAlarmProperties = (compiledTemplate.Resources as ResourceType).slicWatchLambdaInvocationsAlarmHelloLambdaFunction.Properties + t.equal(invocationAlarmProperties?.Threshold, 3) + + const { dashboard } = getDashboardFromTemplate(compiledTemplate) + const widgets = getDashboardWidgetsByTitle(dashboard, /Lambda Invocations/) + t.equal(widgets.length, 1) + t.match((widgets[0].properties as MetricWidgetProperties).metrics, [ + ['AWS/Lambda', 'Invocations', 'FunctionName', '${HelloLambdaFunction}', { stat: 'Sum', yAxis: 'right' }] + ]) + t.end() + }) + + t.test('Plugin succeeds with legacy function-level overrides', t => { + const modifiedSlsConfig = _.cloneDeep(slsConfig) + Object.assign(modifiedSlsConfig.functions.hello.slicWatch, { + alarms: { + Lambda: { // This extra property is the 'legacy' configuration bit + Invocations: { + Threshold: 4, + enabled: true + } + } + }, + dashboard: { + Lambda: { // This extra property is the 'legacy' configuration bit + Invocations: { + yAxis: 'right' + } + } + } + }) + + const sls = createMockServerless(compiledTemplate, modifiedSlsConfig) + const plugin = new ServerlessPlugin(sls, null, pluginUtils) + plugin.createSlicWatchResources() + const invocationAlarmProperties = (compiledTemplate.Resources as ResourceType).slicWatchLambdaInvocationsAlarmHelloLambdaFunction.Properties + t.equal(invocationAlarmProperties?.Threshold, 4) + + const { dashboard } = getDashboardFromTemplate(compiledTemplate) + const widgets = getDashboardWidgetsByTitle(dashboard, /Lambda Invocations/) + t.equal(widgets.length, 1) + t.match((widgets[0].properties as MetricWidgetProperties).metrics, [ + ['AWS/Lambda', 'Invocations', 'FunctionName', '${HelloLambdaFunction}', { stat: 'Sum', yAxis: 'right' }] + ]) + t.end() + }) + + t.end() + }) + t.test('Plugin succeeds with no custom section', t => { const plugin = new ServerlessPlugin({ ...mockServerless, diff --git a/test-utils/sls-test-utils.ts b/test-utils/sls-test-utils.ts index e4368d3d..a2c510bb 100644 --- a/test-utils/sls-test-utils.ts +++ b/test-utils/sls-test-utils.ts @@ -46,12 +46,7 @@ export function createMockServerless (compiledTemplate: Template, slsConfig = sl name: 'aws', compiledCloudFormationTemplate: compiledTemplate }, - custom: { - slicWatch: { - enabled: true, - topicArn: 'test-topic' - } - }, + custom: slsConfig.custom, getAllFunctions: () => Object.keys(slsConfig.functions ?? {}), getFunction: (funcRef) => slsConfig.functions[funcRef] } From 4c3beeac962437044a09260aad3475c230c11396 Mon Sep 17 00:00:00 2001 From: Eoin Shanaghy Date: Mon, 22 Jan 2024 21:40:20 +0000 Subject: [PATCH 34/35] fix: allow Lambda function config overrides without Lambda: property - regenerate snapshots --- ...test-project-alb-snapshot.test.ts.test.cjs | 56 +- ...-project-appsync-snapshot.test.ts.test.cjs | 12 +- ...ess-test-project-snapshot.test.ts.test.cjs | 1030 ++++++++++++----- 3 files changed, 773 insertions(+), 325 deletions(-) diff --git a/tap-snapshots/serverless-test-project-alb/tests/snapshot/serverless-test-project-alb-snapshot.test.ts.test.cjs b/tap-snapshots/serverless-test-project-alb/tests/snapshot/serverless-test-project-alb-snapshot.test.ts.test.cjs index 6d98018f..af3ef6f4 100644 --- a/tap-snapshots/serverless-test-project-alb/tests/snapshot/serverless-test-project-alb-snapshot.test.ts.test.cjs +++ b/tap-snapshots/serverless-test-project-alb/tests/snapshot/serverless-test-project-alb-snapshot.test.ts.test.cjs @@ -784,7 +784,7 @@ exports[`serverless-test-project-alb/tests/snapshot/serverless-test-project-alb- "Properties": { "ActionsEnabled": true, "AlarmActions": [ - "test-topic" + "\${env:ALARM_TOPIC}" ], "AlarmDescription": { "Fn::Sub": [ @@ -822,7 +822,7 @@ exports[`serverless-test-project-alb/tests/snapshot/serverless-test-project-alb- "Properties": { "ActionsEnabled": true, "AlarmActions": [ - "test-topic" + "\${env:ALARM_TOPIC}" ], "AlarmDescription": { "Fn::Sub": [ @@ -856,11 +856,49 @@ exports[`serverless-test-project-alb/tests/snapshot/serverless-test-project-alb- }, "Type": "AWS::CloudWatch::Alarm" }, + "slicWatchLambdaInvocationsAlarmAlbEventLambdaFunction": { + "Properties": { + "ActionsEnabled": true, + "AlarmActions": [ + "\${env:ALARM_TOPIC}" + ], + "AlarmDescription": { + "Fn::Sub": [ + "Total invocations for \${AlbEventLambdaFunction} breaches 10", + {} + ] + }, + "AlarmName": { + "Fn::Sub": [ + "Lambda_Invocations_\${AlbEventLambdaFunction}", + {} + ] + }, + "ComparisonOperator": "GreaterThanThreshold", + "Dimensions": [ + { + "Name": "FunctionName", + "Value": { + "Ref": "AlbEventLambdaFunction" + } + } + ], + "EvaluationPeriods": 1, + "MetricName": "Invocations", + "Namespace": "AWS/Lambda", + "OKActions": [], + "Period": 60, + "Statistic": "Sum", + "Threshold": 10, + "TreatMissingData": "notBreaching" + }, + "Type": "AWS::CloudWatch::Alarm" + }, "slicWatchLambdaThrottlesAlarmAlbEventLambdaFunction": { "Properties": { "ActionsEnabled": true, "AlarmActions": [ - "test-topic" + "\${env:ALARM_TOPIC}" ], "AlarmDescription": { "Fn::Sub": [ @@ -934,7 +972,7 @@ exports[`serverless-test-project-alb/tests/snapshot/serverless-test-project-alb- "Properties": { "ActionsEnabled": true, "AlarmActions": [ - "test-topic" + "\${env:ALARM_TOPIC}" ], "AlarmDescription": "LoadBalancer HTTPCodeELB5XXCount Sum for alb breaches 0", "AlarmName": "LoadBalancer_HTTPCodeELB5XXCountAlarm_alb", @@ -965,7 +1003,7 @@ exports[`serverless-test-project-alb/tests/snapshot/serverless-test-project-alb- "Properties": { "ActionsEnabled": true, "AlarmActions": [ - "test-topic" + "\${env:ALARM_TOPIC}" ], "AlarmDescription": "LoadBalancer HTTPCode_Target_5XX_Count Sum for AlbEventAlbTargetGrouphttpListener breaches 0", "AlarmName": "LoadBalancer_HTTPCodeTarget5XXCountAlarm_AlbEventAlbTargetGrouphttpListener", @@ -1005,7 +1043,7 @@ exports[`serverless-test-project-alb/tests/snapshot/serverless-test-project-alb- "Properties": { "ActionsEnabled": true, "AlarmActions": [ - "test-topic" + "\${env:ALARM_TOPIC}" ], "AlarmDescription": "LoadBalancer LambdaInternalError Sum for AlbEventAlbTargetGrouphttpListener breaches 0", "AlarmName": "LoadBalancer_LambdaInternalErrorAlarm_AlbEventAlbTargetGrouphttpListener", @@ -1045,7 +1083,7 @@ exports[`serverless-test-project-alb/tests/snapshot/serverless-test-project-alb- "Properties": { "ActionsEnabled": true, "AlarmActions": [ - "test-topic" + "\${env:ALARM_TOPIC}" ], "AlarmDescription": "LoadBalancer LambdaUserError Sum for AlbEventAlbTargetGrouphttpListener breaches 0", "AlarmName": "LoadBalancer_LambdaUserErrorAlarm_AlbEventAlbTargetGrouphttpListener", @@ -1085,7 +1123,7 @@ exports[`serverless-test-project-alb/tests/snapshot/serverless-test-project-alb- "Properties": { "ActionsEnabled": true, "AlarmActions": [ - "test-topic" + "\${env:ALARM_TOPIC}" ], "AlarmDescription": "LoadBalancer RejectedConnectionCount Sum for alb breaches 0", "AlarmName": "LoadBalancer_RejectedConnectionCountAlarm_alb", @@ -1116,7 +1154,7 @@ exports[`serverless-test-project-alb/tests/snapshot/serverless-test-project-alb- "Properties": { "ActionsEnabled": true, "AlarmActions": [ - "test-topic" + "\${env:ALARM_TOPIC}" ], "AlarmDescription": "LoadBalancer UnHealthyHostCount Average for AlbEventAlbTargetGrouphttpListener breaches 0", "AlarmName": "LoadBalancer_UnHealthyHostCountAlarm_AlbEventAlbTargetGrouphttpListener", diff --git a/tap-snapshots/serverless-test-project-appsync/tests/snapshot/serverless-test-project-appsync-snapshot.test.ts.test.cjs b/tap-snapshots/serverless-test-project-appsync/tests/snapshot/serverless-test-project-appsync-snapshot.test.ts.test.cjs index 1863cd43..1f6962b2 100644 --- a/tap-snapshots/serverless-test-project-appsync/tests/snapshot/serverless-test-project-appsync-snapshot.test.ts.test.cjs +++ b/tap-snapshots/serverless-test-project-appsync/tests/snapshot/serverless-test-project-appsync-snapshot.test.ts.test.cjs @@ -524,7 +524,7 @@ exports[`serverless-test-project-appsync/tests/snapshot/serverless-test-project- "Properties": { "ActionsEnabled": true, "AlarmActions": [ - "test-topic" + "\${env:ALARM_TOPIC}" ], "AlarmDescription": "AppSync 5XXError Sum for awesome-appsync breaches 0", "AlarmName": "AppSync_5XXErrorAlarm_awesome-appsync", @@ -555,7 +555,7 @@ exports[`serverless-test-project-appsync/tests/snapshot/serverless-test-project- "Properties": { "ActionsEnabled": true, "AlarmActions": [ - "test-topic" + "\${env:ALARM_TOPIC}" ], "AlarmDescription": "AppSync Latency Average for awesome-appsync breaches 0", "AlarmName": "AppSync_LatencyAlarm_awesome-appsync", @@ -768,7 +768,7 @@ exports[`serverless-test-project-appsync/tests/snapshot/serverless-test-project- "Properties": { "ActionsEnabled": true, "AlarmActions": [ - "test-topic" + "\${env:ALARM_TOPIC}" ], "AlarmDescription": { "Fn::Sub": [ @@ -806,7 +806,7 @@ exports[`serverless-test-project-appsync/tests/snapshot/serverless-test-project- "Properties": { "ActionsEnabled": true, "AlarmActions": [ - "test-topic" + "\${env:ALARM_TOPIC}" ], "AlarmDescription": { "Fn::Sub": [ @@ -844,7 +844,7 @@ exports[`serverless-test-project-appsync/tests/snapshot/serverless-test-project- "Properties": { "ActionsEnabled": true, "AlarmActions": [ - "test-topic" + "\${env:ALARM_TOPIC}" ], "AlarmDescription": { "Fn::Sub": [ @@ -882,7 +882,7 @@ exports[`serverless-test-project-appsync/tests/snapshot/serverless-test-project- "Properties": { "ActionsEnabled": true, "AlarmActions": [ - "test-topic" + "\${env:ALARM_TOPIC}" ], "AlarmDescription": { "Fn::Sub": [ diff --git a/tap-snapshots/serverless-test-project/tests/snapshot/serverless-test-project-snapshot.test.ts.test.cjs b/tap-snapshots/serverless-test-project/tests/snapshot/serverless-test-project-snapshot.test.ts.test.cjs index 9e05d180..3c4a87e5 100644 --- a/tap-snapshots/serverless-test-project/tests/snapshot/serverless-test-project-snapshot.test.ts.test.cjs +++ b/tap-snapshots/serverless-test-project/tests/snapshot/serverless-test-project-snapshot.test.ts.test.cjs @@ -1186,7 +1186,7 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "Properties": { "ActionsEnabled": true, "AlarmActions": [ - "test-topic" + "\${env:ALARM_TOPIC}" ], "AlarmDescription": { "Fn::Sub": [ @@ -1210,7 +1210,9 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "EvaluationPeriods": 1, "MetricName": "4XXError", "Namespace": "AWS/ApiGateway", - "OKActions": [], + "OKActions": [ + "\${env:ALARM_TOPIC}" + ], "Period": 60, "Statistic": "Average", "Threshold": 0.05, @@ -1222,7 +1224,7 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "Properties": { "ActionsEnabled": true, "AlarmActions": [ - "test-topic" + "\${env:ALARM_TOPIC}" ], "AlarmDescription": { "Fn::Sub": [ @@ -1246,7 +1248,9 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "EvaluationPeriods": 1, "MetricName": "5XXError", "Namespace": "AWS/ApiGateway", - "OKActions": [], + "OKActions": [ + "\${env:ALARM_TOPIC}" + ], "Period": 60, "Statistic": "Average", "Threshold": 0, @@ -1258,7 +1262,7 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "Properties": { "ActionsEnabled": true, "AlarmActions": [ - "test-topic" + "\${env:ALARM_TOPIC}" ], "AlarmDescription": { "Fn::Sub": [ @@ -1283,7 +1287,9 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "ExtendedStatistic": "p99", "MetricName": "Latency", "Namespace": "AWS/ApiGateway", - "OKActions": [], + "OKActions": [ + "\${env:ALARM_TOPIC}" + ], "Period": 60, "Threshold": 5000, "TreatMissingData": "notBreaching" @@ -2784,7 +2790,7 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "Properties": { "ActionsEnabled": true, "AlarmActions": [ - "test-topic" + "\${env:ALARM_TOPIC}" ], "AlarmDescription": { "Fn::Sub": [ @@ -2819,7 +2825,9 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "EvaluationPeriods": 1, "MetricName": "CPUUtilization", "Namespace": "AWS/ECS", - "OKActions": [], + "OKActions": [ + "\${env:ALARM_TOPIC}" + ], "Period": 60, "Statistic": "Average", "Threshold": 90, @@ -2831,7 +2839,7 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "Properties": { "ActionsEnabled": true, "AlarmActions": [ - "test-topic" + "\${env:ALARM_TOPIC}" ], "AlarmDescription": { "Fn::Sub": [ @@ -2866,7 +2874,9 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "EvaluationPeriods": 1, "MetricName": "MemoryUtilization", "Namespace": "AWS/ECS", - "OKActions": [], + "OKActions": [ + "\${env:ALARM_TOPIC}" + ], "Period": 60, "Statistic": "Average", "Threshold": 90, @@ -2878,7 +2888,7 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "Properties": { "ActionsEnabled": true, "AlarmActions": [ - "test-topic" + "\${env:ALARM_TOPIC}" ], "AlarmDescription": { "Fn::Sub": [ @@ -2904,7 +2914,9 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "EvaluationPeriods": 1, "MetricName": "FailedInvocations", "Namespace": "AWS/Events", - "OKActions": [], + "OKActions": [ + "\${env:ALARM_TOPIC}" + ], "Period": 60, "Statistic": "Sum", "Threshold": 1, @@ -2916,7 +2928,7 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "Properties": { "ActionsEnabled": true, "AlarmActions": [ - "test-topic" + "\${env:ALARM_TOPIC}" ], "AlarmDescription": { "Fn::Sub": [ @@ -2942,7 +2954,9 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "EvaluationPeriods": 1, "MetricName": "ThrottledRules", "Namespace": "AWS/Events", - "OKActions": [], + "OKActions": [ + "\${env:ALARM_TOPIC}" + ], "Period": 60, "Statistic": "Sum", "Threshold": 1, @@ -2954,7 +2968,7 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "Properties": { "ActionsEnabled": true, "AlarmActions": [ - "test-topic" + "\${env:ALARM_TOPIC}" ], "AlarmDescription": { "Fn::Sub": [ @@ -2984,7 +2998,9 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "EvaluationPeriods": 1, "MetricName": "ReadThrottleEvents", "Namespace": "AWS/DynamoDB", - "OKActions": [], + "OKActions": [ + "\${env:ALARM_TOPIC}" + ], "Period": 60, "Statistic": "Sum", "Threshold": 10, @@ -2996,7 +3012,7 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "Properties": { "ActionsEnabled": true, "AlarmActions": [ - "test-topic" + "\${env:ALARM_TOPIC}" ], "AlarmDescription": { "Fn::Sub": [ @@ -3026,7 +3042,9 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "EvaluationPeriods": 1, "MetricName": "WriteThrottleEvents", "Namespace": "AWS/DynamoDB", - "OKActions": [], + "OKActions": [ + "\${env:ALARM_TOPIC}" + ], "Period": 60, "Statistic": "Sum", "Threshold": 10, @@ -3038,7 +3056,7 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "Properties": { "ActionsEnabled": true, "AlarmActions": [ - "test-topic" + "\${env:ALARM_TOPIC}" ], "AlarmDescription": { "Fn::Sub": [ @@ -3064,7 +3082,9 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "EvaluationPeriods": 1, "MetricName": "GetRecords.Success", "Namespace": "AWS/Kinesis", - "OKActions": [], + "OKActions": [ + "\${env:ALARM_TOPIC}" + ], "Period": 60, "Statistic": "Average", "Threshold": 1, @@ -3076,7 +3096,7 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "Properties": { "ActionsEnabled": true, "AlarmActions": [ - "test-topic" + "\${env:ALARM_TOPIC}" ], "AlarmDescription": { "Fn::Sub": [ @@ -3102,7 +3122,9 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "EvaluationPeriods": 1, "MetricName": "GetRecords.IteratorAgeMilliseconds", "Namespace": "AWS/Kinesis", - "OKActions": [], + "OKActions": [ + "\${env:ALARM_TOPIC}" + ], "Period": 60, "Statistic": "Maximum", "Threshold": 10000, @@ -3114,7 +3136,7 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "Properties": { "ActionsEnabled": true, "AlarmActions": [ - "test-topic" + "\${env:ALARM_TOPIC}" ], "AlarmDescription": { "Fn::Sub": [ @@ -3140,7 +3162,9 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "EvaluationPeriods": 1, "MetricName": "PutRecords.Success", "Namespace": "AWS/Kinesis", - "OKActions": [], + "OKActions": [ + "\${env:ALARM_TOPIC}" + ], "Period": 60, "Statistic": "Average", "Threshold": 1, @@ -3152,7 +3176,7 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "Properties": { "ActionsEnabled": true, "AlarmActions": [ - "test-topic" + "\${env:ALARM_TOPIC}" ], "AlarmDescription": { "Fn::Sub": [ @@ -3178,7 +3202,9 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "EvaluationPeriods": 1, "MetricName": "PutRecord.Success", "Namespace": "AWS/Kinesis", - "OKActions": [], + "OKActions": [ + "\${env:ALARM_TOPIC}" + ], "Period": 60, "Statistic": "Average", "Threshold": 1, @@ -3190,7 +3216,7 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "Properties": { "ActionsEnabled": true, "AlarmActions": [ - "test-topic" + "\${env:ALARM_TOPIC}" ], "AlarmDescription": { "Fn::Sub": [ @@ -3216,7 +3242,9 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "EvaluationPeriods": 1, "MetricName": "ReadProvisionedThroughputExceeded", "Namespace": "AWS/Kinesis", - "OKActions": [], + "OKActions": [ + "\${env:ALARM_TOPIC}" + ], "Period": 60, "Statistic": "Sum", "Threshold": 0, @@ -3228,7 +3256,7 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "Properties": { "ActionsEnabled": true, "AlarmActions": [ - "test-topic" + "\${env:ALARM_TOPIC}" ], "AlarmDescription": { "Fn::Sub": [ @@ -3254,7 +3282,9 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "EvaluationPeriods": 1, "MetricName": "WriteProvisionedThroughputExceeded", "Namespace": "AWS/Kinesis", - "OKActions": [], + "OKActions": [ + "\${env:ALARM_TOPIC}" + ], "Period": 60, "Statistic": "Sum", "Threshold": 0, @@ -3266,7 +3296,7 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "Properties": { "ActionsEnabled": true, "AlarmActions": [ - "test-topic" + "\${env:ALARM_TOPIC}" ], "AlarmDescription": { "Fn::Sub": [ @@ -3292,7 +3322,9 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "EvaluationPeriods": 1, "MetricName": "Duration", "Namespace": "AWS/Lambda", - "OKActions": [], + "OKActions": [ + "\${env:ALARM_TOPIC}" + ], "Period": 60, "Statistic": "Maximum", "Threshold": 5700, @@ -3304,7 +3336,7 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "Properties": { "ActionsEnabled": true, "AlarmActions": [ - "test-topic" + "\${env:ALARM_TOPIC}" ], "AlarmDescription": { "Fn::Sub": [ @@ -3330,7 +3362,9 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "EvaluationPeriods": 1, "MetricName": "Duration", "Namespace": "AWS/Lambda", - "OKActions": [], + "OKActions": [ + "\${env:ALARM_TOPIC}" + ], "Period": 60, "Statistic": "Maximum", "Threshold": 5700, @@ -3342,7 +3376,7 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "Properties": { "ActionsEnabled": true, "AlarmActions": [ - "test-topic" + "\${env:ALARM_TOPIC}" ], "AlarmDescription": { "Fn::Sub": [ @@ -3368,45 +3402,9 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "EvaluationPeriods": 1, "MetricName": "Duration", "Namespace": "AWS/Lambda", - "OKActions": [], - "Period": 60, - "Statistic": "Maximum", - "Threshold": 5700, - "TreatMissingData": "notBreaching" - }, - "Type": "AWS::CloudWatch::Alarm" - }, - "slicWatchLambdaDurationAlarmEventsRuleLambdaFunction": { - "Properties": { - "ActionsEnabled": true, - "AlarmActions": [ - "test-topic" - ], - "AlarmDescription": { - "Fn::Sub": [ - "Max duration for \${EventsRuleLambdaFunction} breaches 95% of timeout (6)", - {} - ] - }, - "AlarmName": { - "Fn::Sub": [ - "Lambda_Duration_\${EventsRuleLambdaFunction}", - {} - ] - }, - "ComparisonOperator": "GreaterThanThreshold", - "Dimensions": [ - { - "Name": "FunctionName", - "Value": { - "Ref": "EventsRuleLambdaFunction" - } - } + "OKActions": [ + "\${env:ALARM_TOPIC}" ], - "EvaluationPeriods": 1, - "MetricName": "Duration", - "Namespace": "AWS/Lambda", - "OKActions": [], "Period": 60, "Statistic": "Maximum", "Threshold": 5700, @@ -3418,7 +3416,7 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "Properties": { "ActionsEnabled": true, "AlarmActions": [ - "test-topic" + "\${env:ALARM_TOPIC}" ], "AlarmDescription": { "Fn::Sub": [ @@ -3444,7 +3442,9 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "EvaluationPeriods": 1, "MetricName": "Duration", "Namespace": "AWS/Lambda", - "OKActions": [], + "OKActions": [ + "\${env:ALARM_TOPIC}" + ], "Period": 60, "Statistic": "Maximum", "Threshold": 5700, @@ -3456,7 +3456,7 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "Properties": { "ActionsEnabled": true, "AlarmActions": [ - "test-topic" + "\${env:ALARM_TOPIC}" ], "AlarmDescription": { "Fn::Sub": [ @@ -3482,7 +3482,9 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "EvaluationPeriods": 1, "MetricName": "Duration", "Namespace": "AWS/Lambda", - "OKActions": [], + "OKActions": [ + "\${env:ALARM_TOPIC}" + ], "Period": 60, "Statistic": "Maximum", "Threshold": 28500, @@ -3494,7 +3496,7 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "Properties": { "ActionsEnabled": true, "AlarmActions": [ - "test-topic" + "\${env:ALARM_TOPIC}" ], "AlarmDescription": { "Fn::Sub": [ @@ -3520,7 +3522,9 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "EvaluationPeriods": 1, "MetricName": "Duration", "Namespace": "AWS/Lambda", - "OKActions": [], + "OKActions": [ + "\${env:ALARM_TOPIC}" + ], "Period": 60, "Statistic": "Maximum", "Threshold": 5700, @@ -3532,7 +3536,7 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "Properties": { "ActionsEnabled": true, "AlarmActions": [ - "test-topic" + "\${env:ALARM_TOPIC}" ], "AlarmDescription": { "Fn::Sub": [ @@ -3558,7 +3562,9 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "EvaluationPeriods": 1, "MetricName": "Duration", "Namespace": "AWS/Lambda", - "OKActions": [], + "OKActions": [ + "\${env:ALARM_TOPIC}" + ], "Period": 60, "Statistic": "Maximum", "Threshold": 5700, @@ -3570,7 +3576,7 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "Properties": { "ActionsEnabled": true, "AlarmActions": [ - "test-topic" + "\${env:ALARM_TOPIC}" ], "AlarmDescription": { "Fn::Sub": [ @@ -3596,7 +3602,9 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "EvaluationPeriods": 1, "MetricName": "Duration", "Namespace": "AWS/Lambda", - "OKActions": [], + "OKActions": [ + "\${env:ALARM_TOPIC}" + ], "Period": 60, "Statistic": "Maximum", "Threshold": 28500, @@ -3608,7 +3616,7 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "Properties": { "ActionsEnabled": true, "AlarmActions": [ - "test-topic" + "\${env:ALARM_TOPIC}" ], "AlarmDescription": { "Fn::Sub": [ @@ -3634,7 +3642,9 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "EvaluationPeriods": 1, "MetricName": "Duration", "Namespace": "AWS/Lambda", - "OKActions": [], + "OKActions": [ + "\${env:ALARM_TOPIC}" + ], "Period": 60, "Statistic": "Maximum", "Threshold": 5700, @@ -3646,7 +3656,7 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "Properties": { "ActionsEnabled": true, "AlarmActions": [ - "test-topic" + "\${env:ALARM_TOPIC}" ], "AlarmDescription": { "Fn::Sub": [ @@ -3672,7 +3682,9 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "EvaluationPeriods": 1, "MetricName": "Errors", "Namespace": "AWS/Lambda", - "OKActions": [], + "OKActions": [ + "\${env:ALARM_TOPIC}" + ], "Period": 60, "Statistic": "Sum", "Threshold": 0, @@ -3684,7 +3696,7 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "Properties": { "ActionsEnabled": true, "AlarmActions": [ - "test-topic" + "\${env:ALARM_TOPIC}" ], "AlarmDescription": { "Fn::Sub": [ @@ -3710,7 +3722,9 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "EvaluationPeriods": 1, "MetricName": "Errors", "Namespace": "AWS/Lambda", - "OKActions": [], + "OKActions": [ + "\${env:ALARM_TOPIC}" + ], "Period": 60, "Statistic": "Sum", "Threshold": 0, @@ -3722,7 +3736,7 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "Properties": { "ActionsEnabled": true, "AlarmActions": [ - "test-topic" + "\${env:ALARM_TOPIC}" ], "AlarmDescription": { "Fn::Sub": [ @@ -3748,7 +3762,9 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "EvaluationPeriods": 1, "MetricName": "Errors", "Namespace": "AWS/Lambda", - "OKActions": [], + "OKActions": [ + "\${env:ALARM_TOPIC}" + ], "Period": 60, "Statistic": "Sum", "Threshold": 0, @@ -3756,21 +3772,21 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot }, "Type": "AWS::CloudWatch::Alarm" }, - "slicWatchLambdaErrorsAlarmEventsRuleLambdaFunction": { + "slicWatchLambdaErrorsAlarmHelloLambdaFunction": { "Properties": { "ActionsEnabled": true, "AlarmActions": [ - "test-topic" + "\${env:ALARM_TOPIC}" ], "AlarmDescription": { "Fn::Sub": [ - "Error count for \${EventsRuleLambdaFunction} breaches 0", + "Error count for \${HelloLambdaFunction} breaches 0", {} ] }, "AlarmName": { "Fn::Sub": [ - "Lambda_Errors_\${EventsRuleLambdaFunction}", + "Lambda_Errors_\${HelloLambdaFunction}", {} ] }, @@ -3779,14 +3795,16 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot { "Name": "FunctionName", "Value": { - "Ref": "EventsRuleLambdaFunction" + "Ref": "HelloLambdaFunction" } } ], "EvaluationPeriods": 1, "MetricName": "Errors", "Namespace": "AWS/Lambda", - "OKActions": [], + "OKActions": [ + "\${env:ALARM_TOPIC}" + ], "Period": 60, "Statistic": "Sum", "Threshold": 0, @@ -3794,21 +3812,21 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot }, "Type": "AWS::CloudWatch::Alarm" }, - "slicWatchLambdaErrorsAlarmHelloLambdaFunction": { + "slicWatchLambdaErrorsAlarmHttpGetterLambdaFunction": { "Properties": { "ActionsEnabled": true, "AlarmActions": [ - "test-topic" + "\${env:ALARM_TOPIC}" ], "AlarmDescription": { "Fn::Sub": [ - "Error count for \${HelloLambdaFunction} breaches 0", + "Error count for \${HttpGetterLambdaFunction} breaches 0", {} ] }, "AlarmName": { "Fn::Sub": [ - "Lambda_Errors_\${HelloLambdaFunction}", + "Lambda_Errors_\${HttpGetterLambdaFunction}", {} ] }, @@ -3817,14 +3835,16 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot { "Name": "FunctionName", "Value": { - "Ref": "HelloLambdaFunction" + "Ref": "HttpGetterLambdaFunction" } } ], "EvaluationPeriods": 1, "MetricName": "Errors", "Namespace": "AWS/Lambda", - "OKActions": [], + "OKActions": [ + "\${env:ALARM_TOPIC}" + ], "Period": 60, "Statistic": "Sum", "Threshold": 0, @@ -3832,21 +3852,21 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot }, "Type": "AWS::CloudWatch::Alarm" }, - "slicWatchLambdaErrorsAlarmHttpGetterLambdaFunction": { + "slicWatchLambdaErrorsAlarmPingLambdaFunction": { "Properties": { "ActionsEnabled": true, "AlarmActions": [ - "test-topic" + "\${env:ALARM_TOPIC}" ], "AlarmDescription": { "Fn::Sub": [ - "Error count for \${HttpGetterLambdaFunction} breaches 0", + "Error count for \${PingLambdaFunction} breaches 0", {} ] }, "AlarmName": { "Fn::Sub": [ - "Lambda_Errors_\${HttpGetterLambdaFunction}", + "Lambda_Errors_\${PingLambdaFunction}", {} ] }, @@ -3855,14 +3875,16 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot { "Name": "FunctionName", "Value": { - "Ref": "HttpGetterLambdaFunction" + "Ref": "PingLambdaFunction" } } ], "EvaluationPeriods": 1, "MetricName": "Errors", "Namespace": "AWS/Lambda", - "OKActions": [], + "OKActions": [ + "\${env:ALARM_TOPIC}" + ], "Period": 60, "Statistic": "Sum", "Threshold": 0, @@ -3870,21 +3892,21 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot }, "Type": "AWS::CloudWatch::Alarm" }, - "slicWatchLambdaErrorsAlarmPingLambdaFunction": { + "slicWatchLambdaErrorsAlarmStreamProcessorLambdaFunction": { "Properties": { "ActionsEnabled": true, "AlarmActions": [ - "test-topic" + "\${env:ALARM_TOPIC}" ], "AlarmDescription": { "Fn::Sub": [ - "Error count for \${PingLambdaFunction} breaches 0", + "Error count for \${StreamProcessorLambdaFunction} breaches 0", {} ] }, "AlarmName": { "Fn::Sub": [ - "Lambda_Errors_\${PingLambdaFunction}", + "Lambda_Errors_\${StreamProcessorLambdaFunction}", {} ] }, @@ -3893,14 +3915,16 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot { "Name": "FunctionName", "Value": { - "Ref": "PingLambdaFunction" + "Ref": "StreamProcessorLambdaFunction" } } ], "EvaluationPeriods": 1, "MetricName": "Errors", "Namespace": "AWS/Lambda", - "OKActions": [], + "OKActions": [ + "\${env:ALARM_TOPIC}" + ], "Period": 60, "Statistic": "Sum", "Threshold": 0, @@ -3908,21 +3932,21 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot }, "Type": "AWS::CloudWatch::Alarm" }, - "slicWatchLambdaErrorsAlarmStreamProcessorLambdaFunction": { + "slicWatchLambdaErrorsAlarmSubscriptionHandlerLambdaFunction": { "Properties": { "ActionsEnabled": true, "AlarmActions": [ - "test-topic" + "\${env:ALARM_TOPIC}" ], "AlarmDescription": { "Fn::Sub": [ - "Error count for \${StreamProcessorLambdaFunction} breaches 0", + "Error count for \${SubscriptionHandlerLambdaFunction} breaches 0", {} ] }, "AlarmName": { "Fn::Sub": [ - "Lambda_Errors_\${StreamProcessorLambdaFunction}", + "Lambda_Errors_\${SubscriptionHandlerLambdaFunction}", {} ] }, @@ -3931,14 +3955,16 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot { "Name": "FunctionName", "Value": { - "Ref": "StreamProcessorLambdaFunction" + "Ref": "SubscriptionHandlerLambdaFunction" } } ], "EvaluationPeriods": 1, "MetricName": "Errors", "Namespace": "AWS/Lambda", - "OKActions": [], + "OKActions": [ + "\${env:ALARM_TOPIC}" + ], "Period": 60, "Statistic": "Sum", "Threshold": 0, @@ -3946,21 +3972,21 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot }, "Type": "AWS::CloudWatch::Alarm" }, - "slicWatchLambdaErrorsAlarmSubscriptionHandlerLambdaFunction": { + "slicWatchLambdaErrorsAlarmThrottlerLambdaFunction": { "Properties": { "ActionsEnabled": true, "AlarmActions": [ - "test-topic" + "\${env:ALARM_TOPIC}" ], "AlarmDescription": { "Fn::Sub": [ - "Error count for \${SubscriptionHandlerLambdaFunction} breaches 0", + "Error count for \${ThrottlerLambdaFunction} breaches 0", {} ] }, "AlarmName": { "Fn::Sub": [ - "Lambda_Errors_\${SubscriptionHandlerLambdaFunction}", + "Lambda_Errors_\${ThrottlerLambdaFunction}", {} ] }, @@ -3969,14 +3995,16 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot { "Name": "FunctionName", "Value": { - "Ref": "SubscriptionHandlerLambdaFunction" + "Ref": "ThrottlerLambdaFunction" } } ], "EvaluationPeriods": 1, "MetricName": "Errors", "Namespace": "AWS/Lambda", - "OKActions": [], + "OKActions": [ + "\${env:ALARM_TOPIC}" + ], "Period": 60, "Statistic": "Sum", "Threshold": 0, @@ -3984,21 +4012,21 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot }, "Type": "AWS::CloudWatch::Alarm" }, - "slicWatchLambdaErrorsAlarmThrottlerLambdaFunction": { + "slicWatchLambdaInvocationsAlarmDriveQueueLambdaFunction": { "Properties": { "ActionsEnabled": true, "AlarmActions": [ - "test-topic" + "\${env:ALARM_TOPIC}" ], "AlarmDescription": { "Fn::Sub": [ - "Error count for \${ThrottlerLambdaFunction} breaches 0", + "Total invocations for \${DriveQueueLambdaFunction} breaches 10", {} ] }, "AlarmName": { "Fn::Sub": [ - "Lambda_Errors_\${ThrottlerLambdaFunction}", + "Lambda_Invocations_\${DriveQueueLambdaFunction}", {} ] }, @@ -4007,36 +4035,38 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot { "Name": "FunctionName", "Value": { - "Ref": "ThrottlerLambdaFunction" + "Ref": "DriveQueueLambdaFunction" } } ], "EvaluationPeriods": 1, - "MetricName": "Errors", + "MetricName": "Invocations", "Namespace": "AWS/Lambda", - "OKActions": [], + "OKActions": [ + "\${env:ALARM_TOPIC}" + ], "Period": 60, "Statistic": "Sum", - "Threshold": 0, + "Threshold": 10, "TreatMissingData": "notBreaching" }, "Type": "AWS::CloudWatch::Alarm" }, - "slicWatchLambdaIteratorAgeAlarmStreamProcessorLambdaFunction": { + "slicWatchLambdaInvocationsAlarmDriveStreamLambdaFunction": { "Properties": { "ActionsEnabled": true, "AlarmActions": [ - "test-topic" + "\${env:ALARM_TOPIC}" ], "AlarmDescription": { "Fn::Sub": [ - "IteratorAge for \${StreamProcessorLambdaFunction} breaches 10000", + "Total invocations for \${DriveStreamLambdaFunction} breaches 10", {} ] }, "AlarmName": { "Fn::Sub": [ - "Lambda_IteratorAge_\${StreamProcessorLambdaFunction}", + "Lambda_Invocations_\${DriveStreamLambdaFunction}", {} ] }, @@ -4045,193 +4075,367 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot { "Name": "FunctionName", "Value": { - "Ref": "StreamProcessorLambdaFunction" + "Ref": "DriveStreamLambdaFunction" } } ], "EvaluationPeriods": 1, - "MetricName": "IteratorAge", + "MetricName": "Invocations", "Namespace": "AWS/Lambda", - "OKActions": [], + "OKActions": [ + "\${env:ALARM_TOPIC}" + ], "Period": 60, - "Statistic": "Maximum", - "Threshold": 10000, + "Statistic": "Sum", + "Threshold": 10, "TreatMissingData": "notBreaching" }, "Type": "AWS::CloudWatch::Alarm" }, - "slicWatchLambdaThrottlesAlarmDriveQueueLambdaFunction": { + "slicWatchLambdaInvocationsAlarmDriveTableLambdaFunction": { "Properties": { "ActionsEnabled": true, "AlarmActions": [ - "test-topic" + "\${env:ALARM_TOPIC}" ], "AlarmDescription": { "Fn::Sub": [ - "Throttles % for \${DriveQueueLambdaFunction} breaches 0", + "Total invocations for \${DriveTableLambdaFunction} breaches 10", {} ] }, "AlarmName": { "Fn::Sub": [ - "Lambda_Throttles_\${DriveQueueLambdaFunction}", + "Lambda_Invocations_\${DriveTableLambdaFunction}", {} ] }, "ComparisonOperator": "GreaterThanThreshold", - "EvaluationPeriods": 1, - "Metrics": [ - { - "Id": "throttles_pc", - "Expression": "(throttles / ( throttles + invocations )) * 100", - "Label": "% Throttles", - "ReturnData": true - }, - { - "Id": "throttles", - "MetricStat": { - "Metric": { - "Namespace": "AWS/Lambda", - "MetricName": "Throttles", - "Dimensions": [ - { - "Name": "FunctionName", - "Value": { - "Ref": "DriveQueueLambdaFunction" - } - } - ] - }, - "Period": 60, - "Stat": "Sum" - }, - "ReturnData": false - }, + "Dimensions": [ { - "Id": "invocations", - "MetricStat": { - "Metric": { - "Namespace": "AWS/Lambda", - "MetricName": "Invocations", - "Dimensions": [ - { - "Name": "FunctionName", - "Value": { - "Ref": "DriveQueueLambdaFunction" - } - } - ] - }, - "Period": 60, - "Stat": "Sum" - }, - "ReturnData": false + "Name": "FunctionName", + "Value": { + "Ref": "DriveTableLambdaFunction" + } } ], - "OKActions": [], - "Threshold": 0, + "EvaluationPeriods": 1, + "MetricName": "Invocations", + "Namespace": "AWS/Lambda", + "OKActions": [ + "\${env:ALARM_TOPIC}" + ], + "Period": 60, + "Statistic": "Sum", + "Threshold": 10, "TreatMissingData": "notBreaching" }, "Type": "AWS::CloudWatch::Alarm" }, - "slicWatchLambdaThrottlesAlarmDriveStreamLambdaFunction": { + "slicWatchLambdaInvocationsAlarmHelloLambdaFunction": { "Properties": { "ActionsEnabled": true, "AlarmActions": [ - "test-topic" + "\${env:ALARM_TOPIC}" ], "AlarmDescription": { "Fn::Sub": [ - "Throttles % for \${DriveStreamLambdaFunction} breaches 0", + "Total invocations for \${HelloLambdaFunction} breaches 2", {} ] }, "AlarmName": { "Fn::Sub": [ - "Lambda_Throttles_\${DriveStreamLambdaFunction}", + "Lambda_Invocations_\${HelloLambdaFunction}", {} ] }, "ComparisonOperator": "GreaterThanThreshold", - "EvaluationPeriods": 1, - "Metrics": [ - { - "Id": "throttles_pc", - "Expression": "(throttles / ( throttles + invocations )) * 100", - "Label": "% Throttles", - "ReturnData": true - }, - { - "Id": "throttles", - "MetricStat": { - "Metric": { - "Namespace": "AWS/Lambda", - "MetricName": "Throttles", - "Dimensions": [ - { - "Name": "FunctionName", - "Value": { - "Ref": "DriveStreamLambdaFunction" - } - } - ] - }, - "Period": 60, - "Stat": "Sum" - }, - "ReturnData": false - }, + "Dimensions": [ { - "Id": "invocations", - "MetricStat": { - "Metric": { - "Namespace": "AWS/Lambda", - "MetricName": "Invocations", - "Dimensions": [ - { - "Name": "FunctionName", - "Value": { - "Ref": "DriveStreamLambdaFunction" - } - } - ] - }, - "Period": 60, - "Stat": "Sum" - }, - "ReturnData": false + "Name": "FunctionName", + "Value": { + "Ref": "HelloLambdaFunction" + } } ], - "OKActions": [], - "Threshold": 0, + "EvaluationPeriods": 1, + "MetricName": "Invocations", + "Namespace": "AWS/Lambda", + "OKActions": [ + "\${env:ALARM_TOPIC}" + ], + "Period": 60, + "Statistic": "Sum", + "Threshold": 2, "TreatMissingData": "notBreaching" }, "Type": "AWS::CloudWatch::Alarm" }, - "slicWatchLambdaThrottlesAlarmDriveTableLambdaFunction": { + "slicWatchLambdaInvocationsAlarmHttpGetterLambdaFunction": { "Properties": { "ActionsEnabled": true, "AlarmActions": [ - "test-topic" + "\${env:ALARM_TOPIC}" ], "AlarmDescription": { "Fn::Sub": [ - "Throttles % for \${DriveTableLambdaFunction} breaches 0", + "Total invocations for \${HttpGetterLambdaFunction} breaches 10", {} ] }, "AlarmName": { "Fn::Sub": [ - "Lambda_Throttles_\${DriveTableLambdaFunction}", + "Lambda_Invocations_\${HttpGetterLambdaFunction}", {} ] }, "ComparisonOperator": "GreaterThanThreshold", - "EvaluationPeriods": 1, - "Metrics": [ + "Dimensions": [ { - "Id": "throttles_pc", - "Expression": "(throttles / ( throttles + invocations )) * 100", + "Name": "FunctionName", + "Value": { + "Ref": "HttpGetterLambdaFunction" + } + } + ], + "EvaluationPeriods": 1, + "MetricName": "Invocations", + "Namespace": "AWS/Lambda", + "OKActions": [ + "\${env:ALARM_TOPIC}" + ], + "Period": 60, + "Statistic": "Sum", + "Threshold": 10, + "TreatMissingData": "notBreaching" + }, + "Type": "AWS::CloudWatch::Alarm" + }, + "slicWatchLambdaInvocationsAlarmPingLambdaFunction": { + "Properties": { + "ActionsEnabled": true, + "AlarmActions": [ + "\${env:ALARM_TOPIC}" + ], + "AlarmDescription": { + "Fn::Sub": [ + "Total invocations for \${PingLambdaFunction} breaches 10", + {} + ] + }, + "AlarmName": { + "Fn::Sub": [ + "Lambda_Invocations_\${PingLambdaFunction}", + {} + ] + }, + "ComparisonOperator": "GreaterThanThreshold", + "Dimensions": [ + { + "Name": "FunctionName", + "Value": { + "Ref": "PingLambdaFunction" + } + } + ], + "EvaluationPeriods": 1, + "MetricName": "Invocations", + "Namespace": "AWS/Lambda", + "OKActions": [ + "\${env:ALARM_TOPIC}" + ], + "Period": 60, + "Statistic": "Sum", + "Threshold": 10, + "TreatMissingData": "notBreaching" + }, + "Type": "AWS::CloudWatch::Alarm" + }, + "slicWatchLambdaInvocationsAlarmStreamProcessorLambdaFunction": { + "Properties": { + "ActionsEnabled": true, + "AlarmActions": [ + "\${env:ALARM_TOPIC}" + ], + "AlarmDescription": { + "Fn::Sub": [ + "Total invocations for \${StreamProcessorLambdaFunction} breaches 10", + {} + ] + }, + "AlarmName": { + "Fn::Sub": [ + "Lambda_Invocations_\${StreamProcessorLambdaFunction}", + {} + ] + }, + "ComparisonOperator": "GreaterThanThreshold", + "Dimensions": [ + { + "Name": "FunctionName", + "Value": { + "Ref": "StreamProcessorLambdaFunction" + } + } + ], + "EvaluationPeriods": 1, + "MetricName": "Invocations", + "Namespace": "AWS/Lambda", + "OKActions": [ + "\${env:ALARM_TOPIC}" + ], + "Period": 60, + "Statistic": "Sum", + "Threshold": 10, + "TreatMissingData": "notBreaching" + }, + "Type": "AWS::CloudWatch::Alarm" + }, + "slicWatchLambdaInvocationsAlarmSubscriptionHandlerLambdaFunction": { + "Properties": { + "ActionsEnabled": true, + "AlarmActions": [ + "\${env:ALARM_TOPIC}" + ], + "AlarmDescription": { + "Fn::Sub": [ + "Total invocations for \${SubscriptionHandlerLambdaFunction} breaches 10", + {} + ] + }, + "AlarmName": { + "Fn::Sub": [ + "Lambda_Invocations_\${SubscriptionHandlerLambdaFunction}", + {} + ] + }, + "ComparisonOperator": "GreaterThanThreshold", + "Dimensions": [ + { + "Name": "FunctionName", + "Value": { + "Ref": "SubscriptionHandlerLambdaFunction" + } + } + ], + "EvaluationPeriods": 1, + "MetricName": "Invocations", + "Namespace": "AWS/Lambda", + "OKActions": [ + "\${env:ALARM_TOPIC}" + ], + "Period": 60, + "Statistic": "Sum", + "Threshold": 10, + "TreatMissingData": "notBreaching" + }, + "Type": "AWS::CloudWatch::Alarm" + }, + "slicWatchLambdaInvocationsAlarmThrottlerLambdaFunction": { + "Properties": { + "ActionsEnabled": true, + "AlarmActions": [ + "\${env:ALARM_TOPIC}" + ], + "AlarmDescription": { + "Fn::Sub": [ + "Total invocations for \${ThrottlerLambdaFunction} breaches 10", + {} + ] + }, + "AlarmName": { + "Fn::Sub": [ + "Lambda_Invocations_\${ThrottlerLambdaFunction}", + {} + ] + }, + "ComparisonOperator": "GreaterThanThreshold", + "Dimensions": [ + { + "Name": "FunctionName", + "Value": { + "Ref": "ThrottlerLambdaFunction" + } + } + ], + "EvaluationPeriods": 1, + "MetricName": "Invocations", + "Namespace": "AWS/Lambda", + "OKActions": [ + "\${env:ALARM_TOPIC}" + ], + "Period": 60, + "Statistic": "Sum", + "Threshold": 10, + "TreatMissingData": "notBreaching" + }, + "Type": "AWS::CloudWatch::Alarm" + }, + "slicWatchLambdaIteratorAgeAlarmStreamProcessorLambdaFunction": { + "Properties": { + "ActionsEnabled": true, + "AlarmActions": [ + "\${env:ALARM_TOPIC}" + ], + "AlarmDescription": { + "Fn::Sub": [ + "IteratorAge for \${StreamProcessorLambdaFunction} breaches 10000", + {} + ] + }, + "AlarmName": { + "Fn::Sub": [ + "Lambda_IteratorAge_\${StreamProcessorLambdaFunction}", + {} + ] + }, + "ComparisonOperator": "GreaterThanThreshold", + "Dimensions": [ + { + "Name": "FunctionName", + "Value": { + "Ref": "StreamProcessorLambdaFunction" + } + } + ], + "EvaluationPeriods": 1, + "MetricName": "IteratorAge", + "Namespace": "AWS/Lambda", + "OKActions": [ + "\${env:ALARM_TOPIC}" + ], + "Period": 60, + "Statistic": "Maximum", + "Threshold": 10000, + "TreatMissingData": "notBreaching" + }, + "Type": "AWS::CloudWatch::Alarm" + }, + "slicWatchLambdaThrottlesAlarmDriveQueueLambdaFunction": { + "Properties": { + "ActionsEnabled": true, + "AlarmActions": [ + "\${env:ALARM_TOPIC}" + ], + "AlarmDescription": { + "Fn::Sub": [ + "Throttles % for \${DriveQueueLambdaFunction} breaches 0", + {} + ] + }, + "AlarmName": { + "Fn::Sub": [ + "Lambda_Throttles_\${DriveQueueLambdaFunction}", + {} + ] + }, + "ComparisonOperator": "GreaterThanThreshold", + "EvaluationPeriods": 1, + "Metrics": [ + { + "Id": "throttles_pc", + "Expression": "(throttles / ( throttles + invocations )) * 100", "Label": "% Throttles", "ReturnData": true }, @@ -4245,7 +4449,7 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot { "Name": "FunctionName", "Value": { - "Ref": "DriveTableLambdaFunction" + "Ref": "DriveQueueLambdaFunction" } } ] @@ -4265,7 +4469,7 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot { "Name": "FunctionName", "Value": { - "Ref": "DriveTableLambdaFunction" + "Ref": "DriveQueueLambdaFunction" } } ] @@ -4276,27 +4480,29 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "ReturnData": false } ], - "OKActions": [], + "OKActions": [ + "\${env:ALARM_TOPIC}" + ], "Threshold": 0, "TreatMissingData": "notBreaching" }, "Type": "AWS::CloudWatch::Alarm" }, - "slicWatchLambdaThrottlesAlarmEventsRuleLambdaFunction": { + "slicWatchLambdaThrottlesAlarmDriveStreamLambdaFunction": { "Properties": { "ActionsEnabled": true, "AlarmActions": [ - "test-topic" + "\${env:ALARM_TOPIC}" ], "AlarmDescription": { "Fn::Sub": [ - "Throttles % for \${EventsRuleLambdaFunction} breaches 0", + "Throttles % for \${DriveStreamLambdaFunction} breaches 0", {} ] }, "AlarmName": { "Fn::Sub": [ - "Lambda_Throttles_\${EventsRuleLambdaFunction}", + "Lambda_Throttles_\${DriveStreamLambdaFunction}", {} ] }, @@ -4319,7 +4525,7 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot { "Name": "FunctionName", "Value": { - "Ref": "EventsRuleLambdaFunction" + "Ref": "DriveStreamLambdaFunction" } } ] @@ -4339,7 +4545,7 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot { "Name": "FunctionName", "Value": { - "Ref": "EventsRuleLambdaFunction" + "Ref": "DriveStreamLambdaFunction" } } ] @@ -4350,7 +4556,85 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "ReturnData": false } ], - "OKActions": [], + "OKActions": [ + "\${env:ALARM_TOPIC}" + ], + "Threshold": 0, + "TreatMissingData": "notBreaching" + }, + "Type": "AWS::CloudWatch::Alarm" + }, + "slicWatchLambdaThrottlesAlarmDriveTableLambdaFunction": { + "Properties": { + "ActionsEnabled": true, + "AlarmActions": [ + "\${env:ALARM_TOPIC}" + ], + "AlarmDescription": { + "Fn::Sub": [ + "Throttles % for \${DriveTableLambdaFunction} breaches 0", + {} + ] + }, + "AlarmName": { + "Fn::Sub": [ + "Lambda_Throttles_\${DriveTableLambdaFunction}", + {} + ] + }, + "ComparisonOperator": "GreaterThanThreshold", + "EvaluationPeriods": 1, + "Metrics": [ + { + "Id": "throttles_pc", + "Expression": "(throttles / ( throttles + invocations )) * 100", + "Label": "% Throttles", + "ReturnData": true + }, + { + "Id": "throttles", + "MetricStat": { + "Metric": { + "Namespace": "AWS/Lambda", + "MetricName": "Throttles", + "Dimensions": [ + { + "Name": "FunctionName", + "Value": { + "Ref": "DriveTableLambdaFunction" + } + } + ] + }, + "Period": 60, + "Stat": "Sum" + }, + "ReturnData": false + }, + { + "Id": "invocations", + "MetricStat": { + "Metric": { + "Namespace": "AWS/Lambda", + "MetricName": "Invocations", + "Dimensions": [ + { + "Name": "FunctionName", + "Value": { + "Ref": "DriveTableLambdaFunction" + } + } + ] + }, + "Period": 60, + "Stat": "Sum" + }, + "ReturnData": false + } + ], + "OKActions": [ + "\${env:ALARM_TOPIC}" + ], "Threshold": 0, "TreatMissingData": "notBreaching" }, @@ -4360,7 +4644,7 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "Properties": { "ActionsEnabled": true, "AlarmActions": [ - "test-topic" + "\${env:ALARM_TOPIC}" ], "AlarmDescription": { "Fn::Sub": [ @@ -4424,7 +4708,9 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "ReturnData": false } ], - "OKActions": [], + "OKActions": [ + "\${env:ALARM_TOPIC}" + ], "Threshold": 0, "TreatMissingData": "notBreaching" }, @@ -4434,7 +4720,7 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "Properties": { "ActionsEnabled": true, "AlarmActions": [ - "test-topic" + "\${env:ALARM_TOPIC}" ], "AlarmDescription": { "Fn::Sub": [ @@ -4498,7 +4784,9 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "ReturnData": false } ], - "OKActions": [], + "OKActions": [ + "\${env:ALARM_TOPIC}" + ], "Threshold": 0, "TreatMissingData": "notBreaching" }, @@ -4508,7 +4796,7 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "Properties": { "ActionsEnabled": true, "AlarmActions": [ - "test-topic" + "\${env:ALARM_TOPIC}" ], "AlarmDescription": { "Fn::Sub": [ @@ -4572,7 +4860,9 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "ReturnData": false } ], - "OKActions": [], + "OKActions": [ + "\${env:ALARM_TOPIC}" + ], "Threshold": 0, "TreatMissingData": "notBreaching" }, @@ -4582,7 +4872,7 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "Properties": { "ActionsEnabled": true, "AlarmActions": [ - "test-topic" + "\${env:ALARM_TOPIC}" ], "AlarmDescription": { "Fn::Sub": [ @@ -4646,7 +4936,9 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "ReturnData": false } ], - "OKActions": [], + "OKActions": [ + "\${env:ALARM_TOPIC}" + ], "Threshold": 0, "TreatMissingData": "notBreaching" }, @@ -4656,7 +4948,7 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "Properties": { "ActionsEnabled": true, "AlarmActions": [ - "test-topic" + "\${env:ALARM_TOPIC}" ], "AlarmDescription": { "Fn::Sub": [ @@ -4720,7 +5012,9 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "ReturnData": false } ], - "OKActions": [], + "OKActions": [ + "\${env:ALARM_TOPIC}" + ], "Threshold": 0, "TreatMissingData": "notBreaching" }, @@ -4730,7 +5024,7 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "Properties": { "ActionsEnabled": true, "AlarmActions": [ - "test-topic" + "\${env:ALARM_TOPIC}" ], "AlarmDescription": { "Fn::Sub": [ @@ -4794,7 +5088,9 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "ReturnData": false } ], - "OKActions": [], + "OKActions": [ + "\${env:ALARM_TOPIC}" + ], "Threshold": 0, "TreatMissingData": "notBreaching" }, @@ -4804,7 +5100,7 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "Properties": { "ActionsEnabled": true, "AlarmActions": [ - "test-topic" + "\${env:ALARM_TOPIC}" ], "AlarmDescription": { "Fn::Sub": [ @@ -4833,7 +5129,9 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "EvaluationPeriods": 1, "MetricName": "NumberOfNotificationsFailed", "Namespace": "AWS/SNS", - "OKActions": [], + "OKActions": [ + "\${env:ALARM_TOPIC}" + ], "Period": 60, "Statistic": "Sum", "Threshold": 1, @@ -4845,7 +5143,7 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "Properties": { "ActionsEnabled": true, "AlarmActions": [ - "test-topic" + "\${env:ALARM_TOPIC}" ], "AlarmDescription": { "Fn::Sub": [ @@ -4874,7 +5172,9 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "EvaluationPeriods": 1, "MetricName": "NumberOfNotificationsFilteredOut-InvalidAttributes", "Namespace": "AWS/SNS", - "OKActions": [], + "OKActions": [ + "\${env:ALARM_TOPIC}" + ], "Period": 60, "Statistic": "Sum", "Threshold": 1, @@ -4886,11 +5186,11 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "Properties": { "ActionsEnabled": true, "AlarmActions": [ - "test-topic" + "\${env:ALARM_TOPIC}" ], "AlarmDescription": { "Fn::Sub": [ - "SQS in-flight messages for \${fifoQueue.QueueName} breaches 16000 (80% of the hard limit of 20000)", + "SQS in-flight messages for \${fifoQueue.QueueName} breaches 200 (1% of the hard limit of 20000)", {} ] }, @@ -4915,10 +5215,12 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "EvaluationPeriods": 1, "MetricName": "ApproximateNumberOfMessagesNotVisible", "Namespace": "AWS/SQS", - "OKActions": [], + "OKActions": [ + "\${env:ALARM_TOPIC}" + ], "Period": 60, "Statistic": "Maximum", - "Threshold": 16000, + "Threshold": 200, "TreatMissingData": "notBreaching" }, "Type": "AWS::CloudWatch::Alarm" @@ -4927,11 +5229,11 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "Properties": { "ActionsEnabled": true, "AlarmActions": [ - "test-topic" + "\${env:ALARM_TOPIC}" ], "AlarmDescription": { "Fn::Sub": [ - "SQS in-flight messages for \${regularQueue.QueueName} breaches 96000 (80% of the hard limit of 120000)", + "SQS in-flight messages for \${regularQueue.QueueName} breaches 1200 (1% of the hard limit of 120000)", {} ] }, @@ -4956,10 +5258,98 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "EvaluationPeriods": 1, "MetricName": "ApproximateNumberOfMessagesNotVisible", "Namespace": "AWS/SQS", - "OKActions": [], + "OKActions": [ + "\${env:ALARM_TOPIC}" + ], "Period": 60, "Statistic": "Maximum", - "Threshold": 96000, + "Threshold": 1200, + "TreatMissingData": "notBreaching" + }, + "Type": "AWS::CloudWatch::Alarm" + }, + "slicWatchSQSOldestMsgAgeAlarmfifoQueue": { + "Properties": { + "ActionsEnabled": true, + "AlarmActions": [ + "\${env:ALARM_TOPIC}" + ], + "AlarmDescription": { + "Fn::Sub": [ + "SQS age of oldest message in the queue \${fifoQueue.QueueName} breaches 60", + {} + ] + }, + "AlarmName": { + "Fn::Sub": [ + "SQS_ApproximateAgeOfOldestMessage_\${fifoQueue.QueueName}", + {} + ] + }, + "ComparisonOperator": "GreaterThanThreshold", + "Dimensions": [ + { + "Name": "QueueName", + "Value": { + "Fn::GetAtt": [ + "fifoQueue", + "QueueName" + ] + } + } + ], + "EvaluationPeriods": 1, + "MetricName": "ApproximateAgeOfOldestMessage", + "Namespace": "AWS/SQS", + "OKActions": [ + "\${env:ALARM_TOPIC}" + ], + "Period": 60, + "Statistic": "Maximum", + "Threshold": 60, + "TreatMissingData": "notBreaching" + }, + "Type": "AWS::CloudWatch::Alarm" + }, + "slicWatchSQSOldestMsgAgeAlarmregularQueue": { + "Properties": { + "ActionsEnabled": true, + "AlarmActions": [ + "\${env:ALARM_TOPIC}" + ], + "AlarmDescription": { + "Fn::Sub": [ + "SQS age of oldest message in the queue \${regularQueue.QueueName} breaches 60", + {} + ] + }, + "AlarmName": { + "Fn::Sub": [ + "SQS_ApproximateAgeOfOldestMessage_\${regularQueue.QueueName}", + {} + ] + }, + "ComparisonOperator": "GreaterThanThreshold", + "Dimensions": [ + { + "Name": "QueueName", + "Value": { + "Fn::GetAtt": [ + "regularQueue", + "QueueName" + ] + } + } + ], + "EvaluationPeriods": 1, + "MetricName": "ApproximateAgeOfOldestMessage", + "Namespace": "AWS/SQS", + "OKActions": [ + "\${env:ALARM_TOPIC}" + ], + "Period": 60, + "Statistic": "Maximum", + "Threshold": 60, "TreatMissingData": "notBreaching" }, "Type": "AWS::CloudWatch::Alarm" @@ -4968,7 +5358,7 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "Properties": { "ActionsEnabled": true, "AlarmActions": [ - "test-topic" + "\${env:ALARM_TOPIC}" ], "AlarmDescription": { "Fn::Sub": [ @@ -4994,7 +5384,9 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "EvaluationPeriods": 1, "MetricName": "ExecutionsFailed", "Namespace": "AWS/States", - "OKActions": [], + "OKActions": [ + "\${env:ALARM_TOPIC}" + ], "Period": 60, "Statistic": "Sum", "Threshold": 0, @@ -5006,7 +5398,7 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "Properties": { "ActionsEnabled": true, "AlarmActions": [ - "test-topic" + "\${env:ALARM_TOPIC}" ], "AlarmDescription": { "Fn::Sub": [ @@ -5032,7 +5424,9 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "EvaluationPeriods": 1, "MetricName": "ExecutionsFailed", "Namespace": "AWS/States", - "OKActions": [], + "OKActions": [ + "\${env:ALARM_TOPIC}" + ], "Period": 60, "Statistic": "Sum", "Threshold": 0, @@ -5044,7 +5438,7 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "Properties": { "ActionsEnabled": true, "AlarmActions": [ - "test-topic" + "\${env:ALARM_TOPIC}" ], "AlarmDescription": { "Fn::Sub": [ @@ -5070,7 +5464,9 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "EvaluationPeriods": 1, "MetricName": "ExecutionsTimedOut", "Namespace": "AWS/States", - "OKActions": [], + "OKActions": [ + "\${env:ALARM_TOPIC}" + ], "Period": 60, "Statistic": "Sum", "Threshold": 0, @@ -5082,7 +5478,7 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "Properties": { "ActionsEnabled": true, "AlarmActions": [ - "test-topic" + "\${env:ALARM_TOPIC}" ], "AlarmDescription": { "Fn::Sub": [ @@ -5108,7 +5504,9 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "EvaluationPeriods": 1, "MetricName": "ExecutionsTimedOut", "Namespace": "AWS/States", - "OKActions": [], + "OKActions": [ + "\${env:ALARM_TOPIC}" + ], "Period": 60, "Statistic": "Sum", "Threshold": 0, @@ -5120,7 +5518,7 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "Properties": { "ActionsEnabled": true, "AlarmActions": [ - "test-topic" + "\${env:ALARM_TOPIC}" ], "AlarmDescription": { "Fn::Sub": [ @@ -5146,7 +5544,9 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "EvaluationPeriods": 1, "MetricName": "ExecutionThrottled", "Namespace": "AWS/States", - "OKActions": [], + "OKActions": [ + "\${env:ALARM_TOPIC}" + ], "Period": 60, "Statistic": "Sum", "Threshold": 0, @@ -5158,7 +5558,7 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "Properties": { "ActionsEnabled": true, "AlarmActions": [ - "test-topic" + "\${env:ALARM_TOPIC}" ], "AlarmDescription": { "Fn::Sub": [ @@ -5184,7 +5584,9 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "EvaluationPeriods": 1, "MetricName": "ExecutionThrottled", "Namespace": "AWS/States", - "OKActions": [], + "OKActions": [ + "\${env:ALARM_TOPIC}" + ], "Period": 60, "Statistic": "Sum", "Threshold": 0, @@ -5196,7 +5598,7 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "Properties": { "ActionsEnabled": true, "AlarmActions": [ - "test-topic" + "\${env:ALARM_TOPIC}" ], "AlarmDescription": { "Fn::Sub": [ @@ -5222,7 +5624,9 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "EvaluationPeriods": 1, "MetricName": "ReadThrottleEvents", "Namespace": "AWS/DynamoDB", - "OKActions": [], + "OKActions": [ + "\${env:ALARM_TOPIC}" + ], "Period": 60, "Statistic": "Sum", "Threshold": 10, @@ -5234,7 +5638,7 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "Properties": { "ActionsEnabled": true, "AlarmActions": [ - "test-topic" + "\${env:ALARM_TOPIC}" ], "AlarmDescription": { "Fn::Sub": [ @@ -5260,7 +5664,9 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "EvaluationPeriods": 1, "MetricName": "SystemErrors", "Namespace": "AWS/DynamoDB", - "OKActions": [], + "OKActions": [ + "\${env:ALARM_TOPIC}" + ], "Period": 60, "Statistic": "Sum", "Threshold": 0, @@ -5272,7 +5678,7 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "Properties": { "ActionsEnabled": true, "AlarmActions": [ - "test-topic" + "\${env:ALARM_TOPIC}" ], "AlarmDescription": { "Fn::Sub": [ @@ -5298,7 +5704,9 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "EvaluationPeriods": 1, "MetricName": "UserErrors", "Namespace": "AWS/DynamoDB", - "OKActions": [], + "OKActions": [ + "\${env:ALARM_TOPIC}" + ], "Period": 60, "Statistic": "Sum", "Threshold": 20, @@ -5310,7 +5718,7 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "Properties": { "ActionsEnabled": true, "AlarmActions": [ - "test-topic" + "\${env:ALARM_TOPIC}" ], "AlarmDescription": { "Fn::Sub": [ @@ -5336,7 +5744,9 @@ exports[`serverless-test-project/tests/snapshot/serverless-test-project-snapshot "EvaluationPeriods": 1, "MetricName": "WriteThrottleEvents", "Namespace": "AWS/DynamoDB", - "OKActions": [], + "OKActions": [ + "\${env:ALARM_TOPIC}" + ], "Period": 60, "Statistic": "Sum", "Threshold": 10, From 66e5077503a48bfdf2d7e628dec49b02e7150d46 Mon Sep 17 00:00:00 2001 From: Eoin Shanaghy Date: Mon, 22 Jan 2024 21:43:14 +0000 Subject: [PATCH 35/35] 3.2.0-rc2 --- cdk-test-project/package.json | 2 +- cf-macro/package.json | 2 +- cf-macro/template.yaml | 2 +- core/package.json | 2 +- package-lock.json | 22 ++++++++++---------- package.json | 2 +- sam-test-project/package.json | 2 +- serverless-plugin/package.json | 2 +- serverless-test-project-alb/package.json | 2 +- serverless-test-project-appsync/package.json | 2 +- serverless-test-project/package.json | 2 +- test-utils/package.json | 2 +- 12 files changed, 22 insertions(+), 22 deletions(-) diff --git a/cdk-test-project/package.json b/cdk-test-project/package.json index 938c3db3..9faa0748 100644 --- a/cdk-test-project/package.json +++ b/cdk-test-project/package.json @@ -1,6 +1,6 @@ { "name": "cdk-test-project", - "version": "3.2.0-rc1", + "version": "3.2.0-rc2", "scripts": { "build": "tsc", "watch": "tsc -w", diff --git a/cf-macro/package.json b/cf-macro/package.json index 59e86570..6df847e1 100644 --- a/cf-macro/package.json +++ b/cf-macro/package.json @@ -7,7 +7,7 @@ "url": "https://github.com/fourTheorem/slic-watch.git", "directory": "cf-macro" }, - "version": "3.2.0-rc1", + "version": "3.2.0-rc2", "private": true, "scripts": { "test": "tap --coverage-report=html --no-browser --no-check-coverage tests/**/*.test.ts", diff --git a/cf-macro/template.yaml b/cf-macro/template.yaml index 1788fbc3..977b33ae 100644 --- a/cf-macro/template.yaml +++ b/cf-macro/template.yaml @@ -10,7 +10,7 @@ Metadata: ReadmeUrl: ../README.md Labels: ["monitoring", "observability", "cloudwatch"] HomePageUrl: https://github.com/fourTheorem/slic-watch - SemanticVersion: 3.2.0-rc1 + SemanticVersion: 3.2.0-rc2 SourceCodeUrl: https://github.com/fourTheorem/slic-watch Resources: SlicWatch: diff --git a/core/package.json b/core/package.json index c2a73187..d671e8ee 100644 --- a/core/package.json +++ b/core/package.json @@ -1,6 +1,6 @@ { "name": "slic-watch-core", - "version": "3.2.0-rc1", + "version": "3.2.0-rc2", "description": "SLIC Watch core library for adding alarms and dashboards to CloudFormation", "main": "dist/index.js", "repository": { diff --git a/package-lock.json b/package-lock.json index b2e0013c..51596239 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "slic-watch", - "version": "3.2.0-rc1", + "version": "3.2.0-rc2", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "slic-watch", - "version": "3.2.0-rc1", + "version": "3.2.0-rc2", "license": "Apache", "workspaces": [ "core", @@ -57,7 +57,7 @@ } }, "cdk-test-project": { - "version": "3.2.0-rc1", + "version": "3.2.0-rc2", "dependencies": { "aws-cdk-lib": "^2.67.0", "constructs": "^10.1.266" @@ -68,7 +68,7 @@ }, "cf-macro": { "name": "cf-macro-slic-watch", - "version": "3.2.0-rc1", + "version": "3.2.0-rc2", "dependencies": { "ajv": "^8.12.0", "esbuild": "^0.17.16" @@ -76,7 +76,7 @@ }, "core": { "name": "slic-watch-core", - "version": "3.2.0-rc1", + "version": "3.2.0-rc2", "license": "ISC", "dependencies": { "@types/json-schema": "^7.0.14", @@ -14152,12 +14152,12 @@ } }, "sam-test-project": { - "version": "3.2.0-rc1", + "version": "3.2.0-rc2", "license": "Apache" }, "serverless-plugin": { "name": "serverless-slic-watch-plugin", - "version": "3.2.0-rc1", + "version": "3.2.0-rc2", "license": "Apache", "dependencies": { "ajv": "^8.11.0" @@ -14171,7 +14171,7 @@ } }, "serverless-test-project": { - "version": "3.2.0-rc1", + "version": "3.2.0-rc2", "license": "Apache", "devDependencies": { "axios": "^1.3.5", @@ -14180,14 +14180,14 @@ } }, "serverless-test-project-alb": { - "version": "3.2.0-rc1", + "version": "3.2.0-rc2", "license": "Apache", "devDependencies": { "serverless": "^3.28.1" } }, "serverless-test-project-appsync": { - "version": "3.2.0-rc1", + "version": "3.2.0-rc2", "license": "Apache", "devDependencies": { "serverless": "^3.28.1", @@ -14329,7 +14329,7 @@ "dev": true }, "test-utils": { - "version": "3.2.0-rc1", + "version": "3.2.0-rc2", "license": "Apache" } }, diff --git a/package.json b/package.json index 9cfb4134..0cb83bbd 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "slic-watch", - "version": "3.2.0-rc1", + "version": "3.2.0-rc2", "description": "Root project for SLIC Watch", "main": "index.js", "type": "module", diff --git a/sam-test-project/package.json b/sam-test-project/package.json index 82903ea4..70222cf3 100755 --- a/sam-test-project/package.json +++ b/sam-test-project/package.json @@ -1,7 +1,7 @@ { "name": "sam-test-project", "description": "SLIC Watch test project for CloudFormation Macro", - "version": "3.2.0-rc1", + "version": "3.2.0-rc2", "main": "basic-handler.js", "repository": { "type": "git", diff --git a/serverless-plugin/package.json b/serverless-plugin/package.json index 6f94bd5b..8aae2c82 100644 --- a/serverless-plugin/package.json +++ b/serverless-plugin/package.json @@ -1,6 +1,6 @@ { "name": "serverless-slic-watch-plugin", - "version": "3.2.0-rc1", + "version": "3.2.0-rc2", "description": "Serverless plugin for automatic alarms and dashboards", "main": "dist/index.js", "repository": { diff --git a/serverless-test-project-alb/package.json b/serverless-test-project-alb/package.json index 57da1743..39a6dfa9 100644 --- a/serverless-test-project-alb/package.json +++ b/serverless-test-project-alb/package.json @@ -1,6 +1,6 @@ { "name": "serverless-test-project-alb", - "version": "3.2.0-rc1", + "version": "3.2.0-rc2", "description": "Test project for SLIC Watch serverless plugin", "main": "alb-handler.js", "repository": { diff --git a/serverless-test-project-appsync/package.json b/serverless-test-project-appsync/package.json index 1f9629db..f0129729 100644 --- a/serverless-test-project-appsync/package.json +++ b/serverless-test-project-appsync/package.json @@ -1,6 +1,6 @@ { "name": "serverless-test-project-appsync", - "version": "3.2.0-rc1", + "version": "3.2.0-rc2", "description": "Test project for SLIC Watch serverless plugin", "repository": { "type": "git", diff --git a/serverless-test-project/package.json b/serverless-test-project/package.json index 919a8cc0..6cf2c9b3 100644 --- a/serverless-test-project/package.json +++ b/serverless-test-project/package.json @@ -1,6 +1,6 @@ { "name": "serverless-test-project", - "version": "3.2.0-rc1", + "version": "3.2.0-rc2", "description": "Test project for SLIC Watch serverless plugin", "main": "basic-handler.js", "repository": { diff --git a/test-utils/package.json b/test-utils/package.json index f5ceef5c..a123a474 100755 --- a/test-utils/package.json +++ b/test-utils/package.json @@ -1,7 +1,7 @@ { "name": "test-utils", "description": "Common test utilities", - "version": "3.2.0-rc1", + "version": "3.2.0-rc2", "repository": { "type": "git", "url": "https://github.com/fourTheorem/slic-watch.git",