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" diff --git a/cf-macro/index.ts b/cf-macro/index.ts index 2f1d09e8..c5f12fbd 100644 --- a/cf-macro/index.ts +++ b/cf-macro/index.ts @@ -1,10 +1,9 @@ -import _ from 'lodash' +import { type Template } from 'cloudform-types' import pino from 'pino' -import { addAlarms, addDashboard, getResourcesByType } from '../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' -import { type Template } from 'cloudform-types' const logger = pino({ name: 'macroHandler' }) setLogger(logger) @@ -37,23 +36,11 @@ 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) + logger.error({ err }) errorMessage = (err as Error).message status = 'fail' } 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/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 2a7b4b94..af224a36 100644 --- a/core/alarms/alarm-types.ts +++ b/core/alarms/alarm-types.ts @@ -23,29 +23,31 @@ export interface AlarmTemplate { Properties: AlarmProperties } +/** + * Alarm configuration type used *before* all mandatory fields have been applied + */ export interface SlicWatchAlarmConfig extends Omit { ComparisonOperator?: string + EvaluationPeriods?: number enabled?: boolean } +/** + * Alarm configuration type used *after* all mandatory fields have been applied + */ export interface SlicWatchMergedConfig extends AlarmProperties { enabled: boolean } export type InputOutput = SlicWatchAlarmConfig | SlicWatchMergedConfig -export interface ReturnAlarm { - resourceName: string - resource: Resource -} - export interface AlarmActionsConfig { actionsEnabled?: boolean okActions?: string[] alarmActions?: string[] } -export interface SlicWatchCascadedAlarmsConfig extends AlarmProperties { +export type SlicWatchCascadedAlarmsConfig = T & { enabled: boolean Lambda: SlicWatchLambdaAlarmsConfig ApiGateway: SlicWatchApiGwAlarmsConfig 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/alarms.ts b/core/alarms/alarms.ts index dcfd4798..193990b2 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,12 +47,11 @@ 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 }> = [ + const funcsWithConfig: Array<{ config: SlicWatchMergedConfig, alarmFunc: any }> = [ { config: apiGwConfig, alarmFunc: createApiGatewayAlarms }, { config: sfConfig, alarmFunc: createStatesAlarms }, { config: dynamoDbConfig, alarmFunc: createDynamoDbAlarms }, @@ -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/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..f393b2ef 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,20 @@ 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] + const { enabled, ...rest } = mergedConfig + if (enabled) { 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..767141be 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,13 +27,13 @@ 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] - if (config.enabled) { - const { enabled, ...rest } = config + const config: SlicWatchMergedConfig = configuredResources.alarmConfigurations[appSyncLogicalId][metric] + 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 3a64c1f0..682295f9 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 @@ -27,16 +27,18 @@ 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) + 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}`, {}), @@ -51,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/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 14c59f15..08db913c 100644 --- a/core/alarms/lambda.ts +++ b/core/alarms/lambda.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 { 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' -export interface SlicWatchLambdaAlarmsConfig extends SlicWatchAlarmConfig { +export type SlicWatchLambdaAlarmsConfig = T & { Errors: T ThrottlesPc: T DurationPc: T @@ -14,19 +14,6 @@ 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 -} - const lambdaMetrics = ['Errors', 'ThrottlesPc', 'DurationPc', 'Invocations'] /** @@ -38,93 +25,89 @@ 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) - for (const [funcLogicalId, funcResource] of Object.entries(lambdaResources)) { - const config: SlicWatchLambdaAlarmsConfig = functionAlarmProperties[funcLogicalId] + const configuredLambdaResources = getResourceAlarmConfigurationsByType('AWS::Lambda::Function', compiledTemplate, lambdaAlarmConfig) + for (const [funcLogicalId, funcResource] of Object.entries(configuredLambdaResources.resources)) { + const mergedConfig = configuredLambdaResources.alarmConfigurations[funcLogicalId] - 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 (!mergedConfig.enabled || mergedConfig[metric].enabled === false) { + continue + } + if (metric === 'ThrottlesPc') { + const properties = mergedConfig.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 = 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})`, {}) + properties.AlarmDescription = alarmDescription + properties.Threshold = (threshold * funcTimeout * 1000) / 100 + } + if (metric === 'Errors') { + const properties = mergedConfig.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 = mergedConfig.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 = mergedConfig.Invocations + const alarmDescription = Fn.Sub(`Total invocations for \${${funcLogicalId}} breaches ${properties.Threshold}`, {}) + properties.AlarmDescription = alarmDescription } + + Object.assign(resources, createLambdaCfAlarm(mergedConfig[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) { - Object.assign(resources, createLambdaCfAlarm(config.IteratorAge, 'IteratorAge', funcLogicalId, compiledTemplate, alarmActionsConfig)) - } + } + for (const funcLogicalId of Object.keys(getEventSourceMappingFunctions(compiledTemplate))) { + const config = configuredLambdaResources.alarmConfigurations[funcLogicalId] + if (config.enabled && config.IteratorAge.enabled) { + Object.assign(resources, createLambdaCfAlarm(config.IteratorAge, 'IteratorAge', funcLogicalId, compiledTemplate, alarmActionsConfig)) } } return resources 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..c07e46a7 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 = 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.') } - 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/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/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..65a00eff 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('resource config 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/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/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..a2a5e93a 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 fcddf343..2eda0bb2 100644 --- a/core/cf-template.ts +++ b/core/cf-template.ts @@ -3,10 +3,14 @@ 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' +import { type WidgetMetricProperties } from './dashboards/dashboard-types' +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 @@ -37,6 +41,62 @@ 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 +} + +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 + * + * @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)) { + alarmConfigurations[funcLogicalId] = merge({}, config, cascade(resource?.Metadata?.slicWatch?.alarms ?? {}) as M) + } + return { + resources, + alarmConfigurations + } +} + +/** + * Find all resources of a given type and merge any resource-specific SLIC Watch configuration with + * the global dashboard configuration for resources of that type + * + * @param type The CloudFormation resource type + * @param template The CloudFormation template + * @param config The global dashboard configuration for resources of this type + * @returns The resources along with the merged configuration for each resource by logical ID + */ +export function getResourceDashboardConfigurationsByType ( + 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] = cascade(merge({}, config, cascade(resource?.Metadata?.slicWatch?.dashboard ?? {}))) as T + } + return { + resources, + dashConfigurations + } +} + export function getEventSourceMappingFunctions (compiledTemplate): ResourceType { const eventSourceMappings = getResourcesByType( 'AWS::Lambda::EventSourceMapping', compiledTemplate) diff --git a/core/dashboards/dashboard-types.ts b/core/dashboards/dashboard-types.ts index 8d627b27..4a9454f5 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,131 @@ interface TimeRange { export interface MetricDefs { namespace: string metric: string - dimensions: object + dimensions: Record stat: string - yAxis?: YAxis -} -export interface Properties { - metrics: any[][] - title: string - view: string - region: string - period?: number - yAxis?: YAxis + yAxis?: YAxisPos } -export interface CreateMetricWidget { - type: string - properties: Properties +export interface WidgetWithSize extends Omit { 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 } -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..5ee93f52 100644 --- a/core/dashboards/dashboard.ts +++ b/core/dashboards/dashboard.ts @@ -1,33 +1,34 @@ -import type { Entries } from 'type-fest' 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 type { CreateMetricWidget, DashboardBodyProperties, FunctionDashboardConfigs, MetricDefs, ServiceDashConfig, SlicWatchDashboardConfig, Widgets } from './dashboard-types' +import { getEventSourceMappingFunctions, addResource, getResourceDashboardConfigurationsByType } from '../cf-template' +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() /** + * 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 {*} 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: { @@ -46,39 +47,18 @@ export default function addDashboard (dashboardConfig: SlicWatchDashboardConfig, } } = 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, @@ -96,7 +76,7 @@ export default function addDashboard (dashboardConfig: SlicWatchDashboardConfig, ]) if (positionedWidgets.length > 0) { - const dash = { 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: { @@ -112,12 +92,14 @@ export default function addDashboard (dashboardConfig: SlicWatchDashboardConfig, /** * 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 */ - function createMetricWidget (title: string, metricDefs: MetricDefs[], config: DashboardBodyProperties): CreateMetricWidget { - const metrics = metricDefs.map( + function createMetricWidget (title: string, metricDefs: MetricDefs[], config: WidgetMetricProperties): WidgetWithSize { + const metrics: WidgetMetric[] = metricDefs.map( ({ namespace, metric, dimensions, stat, yAxis }) => [ namespace, metric, @@ -125,7 +107,7 @@ export default function addDashboard (dashboardConfig: SlicWatchDashboardConfig, (acc: string[], [name, value]) => [...acc, name, value], [] ), - { stat, yAxis } + { stat: stat as Statistic, yAxis: yAxis as YAxisPosition } ] ) return { @@ -137,68 +119,70 @@ export default function addDashboard (dashboardConfig: SlicWatchDashboardConfig, region: '${AWS::Region}', period: config.metricPeriod }, - width: config.width as number, - height: config.height as number + width: config.width, + height: config.height } } /** - * 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: FunctionDashboardConfigs, eventSourceMappingFunctionResourceNames: string[]): CreateMetricWidget[] { + function createLambdaWidgets (): WidgetWithSize[] { + const configuredResources = getResourceDashboardConfigurationsByType('AWS::Lambda::Function', compiledTemplate, lambdaDashConfig) + const eventSourceMappingFunctions = getEventSourceMappingFunctions(compiledTemplate) + const lambdaWidgets: any = [] - if (Object.keys(functionResources).length > 0) { + + if (Object.keys(configuredResources.resources).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(configuredResources.resources)) { + const funcConfig = configuredResources.dashConfigurations[funcLogicalId] + const metricConfig = funcConfig[metric] + if (metricConfig.enabled !== false) { + metricDefs.push({ + namespace: 'AWS/Lambda', + metric, + dimensions: { FunctionName: `\${${funcLogicalId}}` }, + stat, + yAxis: metricConfig.yAxis + }) } + } - 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 Object.keys(eventSourceMappingFunctions)) { + // Add IteratorAge alarm if the Lambda function has an EventSourceMapping trigger + const funcConfig = configuredResources.dashConfigurations[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 Statistic, + yAxis: metricConfig.yAxis + })), + metricConfig as Widgets + ) + lambdaWidgets.push(iteratorAgeWidget) } } } @@ -212,11 +196,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,21 +212,24 @@ export default function addDashboard (dashboardConfig: SlicWatchDashboardConfig, * Object of CloudFormation RestApi resources by resource name */ - function createApiWidgets (apiResources: ResourceType): CreateMetricWidget[] { - const apiWidgets: CreateMetricWidget[] = [] - 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) { - for (const stat of metricConfig?.Statistic ?? []) { + function createApiWidgets (): WidgetWithSize[] { + const configuredResources = getResourceDashboardConfigurationsByType('AWS::ApiGateway::RestApi', 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) + 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({ namespace: 'AWS/ApiGateway', metric, dimensions: { ApiName: apiName }, - stat + stat, + yAxis: metricConfig.yAxis }) } } @@ -248,7 +237,7 @@ export default function addDashboard (dashboardConfig: SlicWatchDashboardConfig, const metricStatWidget = createMetricWidget( `${metric} API ${apiName}`, widgetMetrics, - apiGwDashConfig as Widgets + metricConfig ) apiWidgets.push(metricStatWidget) } @@ -263,20 +252,23 @@ export default function addDashboard (dashboardConfig: SlicWatchDashboardConfig, * * Object of Step Function State Machine resources by resource name */ - function createStateMachineWidgets (smResources: ResourceType): CreateMetricWidget[] { - const smWidgets: CreateMetricWidget[] = [] - for (const [logicalId] of Object.entries(smResources)) { + function createStateMachineWidgets (): WidgetWithSize[] { + const stateMachineResources = getResourceDashboardConfigurationsByType('AWS::StepFunctions::StateMachine', compiledTemplate, sfDashConfig) + const smWidgets: WidgetWithSize[] = [] + 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))) { - if (metricConfig?.enabled !== false) { - for (const stat of metricConfig?.Statistic ?? []) { + for (const [metric, metricConfig] of Object.entries(getConfiguredMetrics(mergedConfig))) { + if (metricConfig.enabled) { + for (const stat of metricConfig.Statistic) { widgetMetrics.push({ namespace: 'AWS/States', metric, dimensions: { StateMachineArn: `\${${logicalId}}` }, - stat + stat, + yAxis: metricConfig.yAxis }) } } @@ -285,7 +277,7 @@ export default function addDashboard (dashboardConfig: SlicWatchDashboardConfig, const metricStatWidget = createMetricWidget( `\${${logicalId}.Name} Step Function Executions`, widgetMetrics, - sfDashConfig as Widgets + mergedConfig ) smWidgets.push(metricStatWidget) } @@ -298,48 +290,53 @@ export default function addDashboard (dashboardConfig: SlicWatchDashboardConfig, * * Object of DynamoDB table resources by resource name */ - function createDynamoDbWidgets (tableResources: ResourceType): CreateMetricWidget[] { - const ddbWidgets: CreateMetricWidget[] = [] - for (const [logicalId, res] of Object.entries(tableResources)) { - const widgetMetrics: MetricDefs[] = [] - for (const [metric, metricConfig] of Object.entries(getConfiguredMetrics(dynamoDbDashConfig))) { - if (metricConfig?.enabled !== false) { - for (const stat of metricConfig?.Statistic ?? []) { + function createDynamoDbWidgets (): WidgetWithSize[] { + const configuredResources = getResourceDashboardConfigurationsByType('AWS::DynamoDB::Table', compiledTemplate, dynamoDbDashConfig) + const ddbWidgets: WidgetWithSize[] = [] + for (const [logicalId, res] of Object.entries(configuredResources.resources)) { + const mergedConfig = configuredResources.dashConfigurations[logicalId] + 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', metric, dimensions: { TableName: `\${${logicalId}}` }, - stat + stat, + yAxis: metricConfig.yAxis }) } if (widgetMetrics.length > 0) { const metricStatWidget = createMetricWidget( `${metric} Table $\{${logicalId}}`, widgetMetrics, - dynamoDbDashConfig as Widgets + metricConfig ) 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({ + for (const stat of metricConfig.Statistic) { + 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, - dynamoDbDashConfig as Widgets + gsiWidgetMetrics, + metricConfig ) ddbWidgets.push(metricStatWidget) } @@ -355,28 +352,30 @@ 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 (): WidgetWithSize[] { + const configuredResources = getResourceDashboardConfigurationsByType('AWS::Kinesis::Stream', compiledTemplate, kinesisDashConfig) + const streamWidgets: WidgetWithSize[] = [] const metricGroups = { IteratorAge: ['GetRecords.IteratorAgeMilliseconds'], '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 as boolean) { + const metricConfig = streamConfig[metric] + if (metricConfig.enabled !== false) { for (const stat of metricConfig.Statistic) { widgetMetrics.push({ namespace: 'AWS/Kinesis', metric, dimensions: { StreamName: `\${${logicalId}}` }, - stat + stat, + yAxis: metricConfig.yAxis }) } } @@ -385,7 +384,7 @@ export default function addDashboard (dashboardConfig: SlicWatchDashboardConfig, streamWidgets.push(createMetricWidget( `${group} $\{${logicalId}} Kinesis`, widgetMetrics, - kinesisDashConfig as Widgets + streamConfig )) } } @@ -397,21 +396,21 @@ 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 (): WidgetWithSize[] { + const configuredResources = getResourceDashboardConfigurationsByType('AWS::SQS::Queue', compiledTemplate, sqsDashConfig) + const queueWidgets: WidgetWithSize[] = [] const metricGroups = { Messages: ['NumberOfMessagesSent', 'NumberOfMessagesReceived', 'NumberOfMessagesDeleted'], '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] + const metricConfig = mergedConfig[metric] if (metricConfig.enabled !== false) { for (const stat of metricConfig.Statistic) { widgetMetrics.push({ @@ -420,6 +419,7 @@ export default function addDashboard (dashboardConfig: SlicWatchDashboardConfig, dimensions: { QueueName: `\${${logicalId}.QueueName}` }, + yAxis: metricConfig.yAxis, stat }) } @@ -429,7 +429,7 @@ export default function addDashboard (dashboardConfig: SlicWatchDashboardConfig, queueWidgets.push(createMetricWidget( `${group} \${${logicalId}.QueueName} SQS`, widgetMetrics, - sqsDashConfig as Widgets + sqsDashConfig )) } } @@ -443,15 +443,16 @@ export default function addDashboard (dashboardConfig: SlicWatchDashboardConfig, * * Object of ECS Service resources by resource name */ - function createEcsWidgets (ecsServiceResources: ResourceType): CreateMetricWidget[] { - const ecsWidgets: CreateMetricWidget[] = [] - for (const [logicalId, res] of Object.entries(ecsServiceResources)) { + function createEcsWidgets (): WidgetWithSize[] { + const configuredResources = getResourceDashboardConfigurationsByType('AWS::ECS::Service', compiledTemplate, ecsDashConfig) + const ecsWidgets: WidgetWithSize[] = [] + 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))) { - if (metricConfig?.enabled !== false) { - for (const stat of metricConfig?.Statistic ?? []) { + for (const [metric, metricConfig] of Object.entries(getConfiguredMetrics(mergedConfig))) { + if (metricConfig.enabled) { + for (const stat of metricConfig.Statistic) { widgetMetrics.push({ namespace: 'AWS/ECS', metric, @@ -468,7 +469,7 @@ export default function addDashboard (dashboardConfig: SlicWatchDashboardConfig, const metricStatWidget = createMetricWidget( `ECS Service \${${logicalId}.Name}`, widgetMetrics, - ecsDashConfig as Widgets + ecsDashConfig ) ecsWidgets.push(metricStatWidget) } @@ -478,23 +479,26 @@ export default function addDashboard (dashboardConfig: SlicWatchDashboardConfig, /** * Create a set of CloudWatch Dashboard widgets for SNS services. - * - * Object of SNS Service resources by resource name */ - function createTopicWidgets (topicResources: ResourceType): CreateMetricWidget[] { - const topicWidgets: CreateMetricWidget[] = [] - for (const logicalId of Object.keys(topicResources)) { + function createTopicWidgets (): WidgetWithSize[] { + const configuredResources = getResourceDashboardConfigurationsByType( + 'AWS::SNS::Topic', compiledTemplate, snsDashConfig + ) + const topicWidgets: WidgetWithSize[] = [] + for (const logicalId of Object.keys(configuredResources.resources)) { const widgetMetrics: MetricDefs[] = [] - for (const [metric, metricConfig] of Object.entries(getConfiguredMetrics(snsDashConfig))) { - if (metricConfig?.enabled !== false) { - for (const stat of metricConfig?.Statistic ?? []) { + 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({ namespace: 'AWS/SNS', metric, dimensions: { TopicName: `\${${logicalId}.TopicName}` }, - stat + stat, + yAxis: metricConfig.yAxis }) } } @@ -503,7 +507,7 @@ export default function addDashboard (dashboardConfig: SlicWatchDashboardConfig, const metricStatWidget = createMetricWidget( `SNS Topic \${${logicalId}.TopicName}`, widgetMetrics, - snsDashConfig as Widgets + snsDashConfig ) topicWidgets.push(metricStatWidget) } @@ -516,18 +520,21 @@ export default function addDashboard (dashboardConfig: SlicWatchDashboardConfig, * * Object of EventBridge Service resources by resource name */ - function createRuleWidgets (ruleResources: ResourceType): CreateMetricWidget[] { - const ruleWidgets: CreateMetricWidget[] = [] - for (const [logicalId] of Object.entries(ruleResources)) { + function createRuleWidgets (): WidgetWithSize[] { + const configuredResources = getResourceDashboardConfigurationsByType('AWS::Events::Rule', compiledTemplate, ruleDashConfig) + const ruleWidgets: WidgetWithSize[] = [] + for (const [logicalId] of Object.entries(configuredResources.resources)) { const widgetMetrics: MetricDefs[] = [] - for (const [metric, metricConfig] of Object.entries(getConfiguredMetrics(ruleDashConfig))) { - if (metricConfig?.enabled !== false) { - for (const stat of metricConfig?.Statistic ?? []) { + 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({ namespace: 'AWS/Events', metric, dimensions: { RuleName: `\${${logicalId}}` }, - stat + stat, + yAxis: metricConfig.yAxis }) } } @@ -536,7 +543,7 @@ export default function addDashboard (dashboardConfig: SlicWatchDashboardConfig, const metricStatWidget = createMetricWidget( `EventBridge Rule \${${logicalId}}`, widgetMetrics, - ruleDashConfig as Widgets + mergedConfig ) ruleWidgets.push(metricStatWidget) } @@ -546,19 +553,19 @@ export default function addDashboard (dashboardConfig: SlicWatchDashboardConfig, /** * 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): CreateMetricWidget[] { - const loadBalancerWidgets: CreateMetricWidget[] = [] - for (const [logicalId] of Object.entries(loadBalancerResources)) { + function createLoadBalancerWidgets (): WidgetWithSize[] { + const configuredResources = getResourceDashboardConfigurationsByType('AWS::ElasticLoadBalancingV2::LoadBalancer', compiledTemplate, albDashConfig) + const loadBalancerWidgets: WidgetWithSize[] = [] + 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))) { - if (metricConfig?.enabled !== false) { - for (const stat of metricConfig?.Statistic ?? []) { + for (const [metric, metricConfig] of Object.entries(getConfiguredMetrics(mergedConfig))) { + if (metricConfig.enabled) { + for (const stat of metricConfig.Statistic) { widgetMetrics.push({ namespace: 'AWS/ApplicationELB', metric, @@ -574,7 +581,7 @@ export default function addDashboard (dashboardConfig: SlicWatchDashboardConfig, const metricStatWidget = createMetricWidget( `ALB ${loadBalancerName}`, widgetMetrics, - albDashConfig as Widgets + mergedConfig ) loadBalancerWidgets.push(metricStatWidget) } @@ -588,19 +595,22 @@ 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[] = [] - for (const [tgLogicalId, targetGroupResource] of Object.entries(targetGroupResources)) { + function createTargetGroupWidgets (): WidgetWithSize[] { + const configuredResources = getResourceDashboardConfigurationsByType('AWS::ElasticLoadBalancingV2::TargetGroup', compiledTemplate, albTargetDashConfig) + + const targetGroupWidgets: WidgetWithSize[] = [] + 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))) { - if ((metricConfig?.enabled !== false) && + for (const [metric, metricConfig] of Object.entries(getConfiguredMetrics(mergedConfig))) { + 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, @@ -617,7 +627,7 @@ export default function addDashboard (dashboardConfig: SlicWatchDashboardConfig, const metricStatWidget = createMetricWidget( `Target Group \${${loadBalancerLogicalId}.LoadBalancerName}/\${${tgLogicalId}.TargetGroupName}`, widgetMetrics, - albTargetDashConfig as Widgets + mergedConfig ) targetGroupWidgets.push(metricStatWidget) } @@ -631,42 +641,42 @@ export default function addDashboard (dashboardConfig: SlicWatchDashboardConfig, * * Object of AppSync Service resources by resource name */ - function createAppSyncWidgets (appSyncResources: ResourceType): CreateMetricWidget[] { - const appSyncWidgets: CreateMetricWidget[] = [] + 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: DashboardBodyProperties | Widgets = metricConfigs[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, - yAxis: metricConfig.yAxis - }) - } + 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 as Widgets - )) - } + } + if (widgetMetrics.length > 0) { + appSyncWidgets.push(createMetricWidget( + `AppSync ${group} ${appSyncResourceName}`, + widgetMetrics, + mergedConfig + )) } } } @@ -679,7 +689,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-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-dynamodb.test.ts b/core/dashboards/tests/dashboard-dynamodb.test.ts new file mode 100644 index 00000000..7398dcec --- /dev/null +++ b/core/dashboards/tests/dashboard-dynamodb.test.ts @@ -0,0 +1,172 @@ +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 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.equal(widget.width, 8) + t.equal(widget.height, 12) + } + 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-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-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() +}) diff --git a/core/dashboards/tests/dashboard-lambda.test.ts b/core/dashboards/tests/dashboard-lambda.test.ts new file mode 100644 index 00000000..213bbcd6 --- /dev/null +++ b/core/dashboards/tests/dashboard-lambda.test.ts @@ -0,0 +1,269 @@ +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 { 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) + 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() + }) + + 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-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-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-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 b9be9499..6a583ddd 100644 --- a/core/dashboards/tests/dashboard.test.ts +++ b/core/dashboards/tests/dashboard.test.ts @@ -1,19 +1,18 @@ 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 { getResourcesByType } from '../../cf-template' - -const lambdaMetrics = ['Errors', 'Duration', 'IteratorAge', 'Invocations', 'ConcurrentExecutions', 'Throttles'] -const emptyFuncConfigs = {} +import { type Widgets } from '../dashboard-types' 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,182 +20,24 @@ test('An empty template creates no dashboard', (t) => { }) test('A dashboard includes metrics', (t) => { - const compiledTemplate = createTestCloudFormationTemplate() - addDashboard(defaultConfig.dashboard, emptyFuncConfigs, 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']) - - t.ok(dashBody.start) - - t.test('dashboards includes Lambda metrics', (t) => { - const widgets = dashBody.widgets.filter(({ properties: { title } }) => - title.startsWith('Lambda') - ) - t.equal(widgets.length, 8) - const namespaces = new Set() - for (const widget of widgets) { - for (const metric of widget.properties.metrics) { - t.equal(metric.length, 5) - const metricProperties = metric[4] - 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.title) - ) - t.same(actualTitles, expectedTitles) - t.end() - }) + const template = createTestCloudFormationTemplate() + addDashboard(defaultConfig.dashboard, template) - 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) - ) - t.same(actualTitles, expectedTitles) - t.end() - }) + const { dashboard, dashProperties } = getDashboardFromTemplate(template) + t.ok(dashboard) + t.ok(dashProperties) + t.same(dashProperties.DashboardName, { 'Fn::Sub': '${AWS::StackName}-${AWS::Region}-Dashboard' }) - t.test('dashboards includes Step Function metrics', (t) => { - const widgets = dashBody.widgets.filter((widget) => - widget.properties.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) { - 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.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 - ) - 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/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.title) - ) - t.same(actualTitles, expectedTitles) - t.end() - }) - - t.test('dashboard includes Kinesis metrics', (t) => { - const widgets = dashBody.widgets.filter(({ properties: { title } }) => - title.endsWith('Kinesis') - ) - t.equal(widgets.length, 3) - 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/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.title) - ) - t.same(actualTitles, expectedTitles) - t.end() - }) - - t.test('dashboard includes SQS metrics', (t) => { - const widgets = dashBody.widgets.filter(({ properties: { title } }) => - 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) { - 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.title) - ) - t.same(actualTitles, expectedTitles) - t.end() - }) + t.ok(dashboard.start) 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]) } } @@ -206,49 +47,7 @@ test('A dashboard includes metrics', (t) => { ]) const actualTitles = new Set( - widgets.map((widget) => widget.properties.title) - ) - t.same(actualTitles, expectedTitles) - t.end() - }) - - t.test('dashboard includes SNS metrics', (t) => { - const widgets = dashBody.widgets.filter(({ properties: { title } }) => - title.startsWith('SNS') - ) - 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/SNS'])) - const expectedTitles = new Set(['SNS Topic ${topic.TopicName}']) - - const actualTitles = new Set( - widgets.map((widget) => widget.properties.title) - ) - t.same(actualTitles, expectedTitles) - t.end() - }) - - t.test('dashboard includes Events metrics', (t) => { - const widgets = dashBody.widgets.filter(({ properties: { title } }) => - title.startsWith('EventBridge') - ) - 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/Events'])) - 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() @@ -259,17 +58,17 @@ 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] 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) @@ -290,7 +89,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) @@ -314,10 +113,10 @@ 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, emptyFuncConfigs, compiledTemplate) + addDashboard(dashConfig, compiledTemplate) const dashResources = getResourcesByType('AWS::CloudWatch::Dashboard', compiledTemplate) t.same(dashResources, {}) t.end() @@ -327,10 +126,10 @@ 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, emptyFuncConfigs, compiledTemplate) + addDashboard(dashConfig, compiledTemplate) const dashResources = getResourcesByType('AWS::CloudWatch::Dashboard', compiledTemplate) t.same(dashResources, {}) t.end() @@ -362,7 +161,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']) @@ -380,17 +179,17 @@ 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] 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) @@ -416,10 +215,10 @@ 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, emptyFuncConfigs, compiledTemplate) + addDashboard(dashConfig, compiledTemplate) const dashResources = getResourcesByType('AWS::CloudWatch::Dashboard', compiledTemplate) t.same(dashResources, {}) t.end() @@ -441,12 +240,12 @@ 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] - 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([ @@ -465,10 +264,10 @@ 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, emptyFuncConfigs, compiledTemplate) + addDashboard(dashConfig, compiledTemplate) const dashResources = getResourcesByType('AWS::CloudWatch::Dashboard', compiledTemplate) t.same(dashResources, {}) t.end() @@ -478,58 +277,11 @@ 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, 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() - addDashboard(defaultConfig.dashboard, funcConfigs, 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(disabledFunctionName), -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 } - } - } - addDashboard(defaultConfig.dashboard, funcConfigs, 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') - ) - t.equal(widgets.length, 0) - t.end() -}) 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/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/core/package.json b/core/package.json index 2dceba1d..ff856bd8 100644 --- a/core/package.json +++ b/core/package.json @@ -36,6 +36,7 @@ "yaml": "^1.10.2" }, "devDependencies": { + "cloudwatch-dashboard-types": "^1.0.1-rc2", "ts-node": "^10.9.1" } } diff --git a/core/tests/testing-utils.ts b/core/tests/testing-utils.ts index 24d2bf50..5e26153f 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) @@ -25,17 +29,17 @@ 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 */ -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 } diff --git a/package-lock.json b/package-lock.json index d8bec7f1..9e0b1c92 100644 --- a/package-lock.json +++ b/package-lock.json @@ -89,6 +89,7 @@ "yaml": "^1.10.2" }, "devDependencies": { + "cloudwatch-dashboard-types": "^1.0.1-rc2", "ts-node": "^10.9.1" } }, @@ -247,150 +248,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": { @@ -398,62 +401,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": { @@ -461,29 +465,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": { @@ -491,19 +480,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": { @@ -511,20 +501,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": { @@ -532,14 +523,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": { @@ -547,16 +539,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": { @@ -564,885 +557,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": [ @@ -1704,739 +1304,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": ">=14.0.0" } }, - "node_modules/@serverless/dashboard-plugin/node_modules/argparse": { - "version": "2.0.1", - "dev": true, - "license": "Python-2.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": { @@ -3912,8 +4072,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" @@ -3981,16 +4142,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" }, @@ -4120,15 +4283,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" }, @@ -4138,8 +4302,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", @@ -4158,8 +4323,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", @@ -4172,13 +4338,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" } @@ -4300,9 +4468,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", @@ -4320,8 +4489,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" } @@ -4712,9 +4882,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", @@ -4748,9 +4918,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", @@ -4789,6 +4959,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, @@ -5135,8 +5340,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", @@ -5147,8 +5353,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", @@ -5162,24 +5369,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" }, @@ -5189,16 +5399,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" }, @@ -5531,6 +5743,12 @@ "node": ">=4.2.0" } }, + "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==", + "dev": true + }, "node_modules/co": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", @@ -5600,9 +5818,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", @@ -5686,8 +5905,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" }, @@ -5696,9 +5916,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" @@ -5746,9 +5967,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", @@ -5839,14 +6061,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, @@ -5914,14 +6128,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, @@ -5943,14 +6149,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, @@ -6141,17 +6339,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" } @@ -6673,9 +6876,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" } @@ -6766,9 +6970,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" } @@ -7121,9 +7326,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": [ { @@ -7240,9 +7445,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" } @@ -7287,8 +7493,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" } @@ -7428,8 +7635,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", @@ -7705,9 +7913,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", @@ -7723,9 +7932,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": { @@ -7935,8 +8144,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" @@ -8022,8 +8232,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", @@ -8679,6 +8890,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, @@ -8779,8 +8999,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": "*" } @@ -8808,21 +9029,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", @@ -8900,10 +9106,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" } @@ -8993,8 +9281,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", @@ -9004,8 +9293,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", @@ -9018,21 +9308,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", @@ -9109,8 +9402,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" }, @@ -9120,8 +9414,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", @@ -9134,13 +9429,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" } @@ -9159,8 +9456,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" } @@ -9400,23 +9698,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", @@ -9425,8 +9733,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", @@ -9579,27 +9888,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" @@ -9951,13 +10253,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" }, @@ -9966,9 +10270,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" }, @@ -10458,39 +10763,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, @@ -10638,8 +10910,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", @@ -11085,8 +11358,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" } @@ -11306,25 +11581,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" }, @@ -11592,6 +11870,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": [ { @@ -11607,7 +11887,6 @@ "url": "https://feross.org/support" } ], - "license": "MIT", "dependencies": { "queue-microtask": "^1.2.2" } @@ -11732,19 +12011,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", @@ -11752,28 +12032,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", @@ -11781,15 +12061,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": { @@ -11903,8 +12185,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", @@ -11965,9 +12248,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", @@ -12158,8 +12442,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" } @@ -12228,24 +12513,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, @@ -12682,13 +12969,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" @@ -12699,8 +12987,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", @@ -12712,43 +13001,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" } @@ -12806,6 +13063,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, @@ -12893,8 +13156,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" } @@ -13585,9 +13849,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" } @@ -13633,8 +13898,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" }, @@ -13726,8 +13992,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" @@ -13807,12 +14074,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": { @@ -14152,780 +14441,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==", + "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/types": "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" } }, "@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==", + "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/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", + "@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/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==", - "dev": true, - "requires": { - "@aws-sdk/property-provider": "3.347.0", - "@aws-sdk/types": "3.347.0", - "bowser": "^2.11.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==", - "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", - "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==", - "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==", + "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/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" } }, @@ -14938,17 +14927,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", @@ -15343,6 +15321,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" @@ -15350,6 +15330,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": { @@ -15528,13 +15510,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", @@ -15548,6 +15534,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" @@ -15555,10 +15542,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" @@ -15566,6 +15570,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", @@ -15576,6 +15582,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", @@ -15583,7 +15591,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", @@ -15605,24 +15615,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", @@ -15633,18 +15643,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", @@ -15669,6 +15680,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, @@ -15686,62 +15703,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": { + "@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" + } + }, + "@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": { - "@sigstore/protobuf-specs": "^0.2.1" + "@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/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-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": { + "@smithy/node-config-provider": "^2.1.5", + "@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-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/bundle": "^2.1.0", - "@sigstore/protobuf-specs": "^0.2.1", - "make-fetch-happen": "^13.0.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-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": { - "@sigstore/protobuf-specs": "^0.2.1", - "tuf-js": "^2.1.0" + "@smithy/types": "^2.5.0", + "tslib": "^2.5.0" } }, - "@sindresorhus/is": { - "version": "4.6.0", - "dev": true + "@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/service-error-classification": "^2.0.6", + "@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-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/types": "^1.0.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" } }, - "@smithy/types": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-1.0.0.tgz", - "integrity": "sha512-kc1m5wPBHQCTixwuaOh9vnak/iJm21DrSf9UK6yDE5S3mQQ4u11pqAUiKWnlrZnYkeLfAI9UEHj9OaMT1v5Umg==", + "@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" } }, @@ -16656,6 +17103,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", @@ -16701,10 +17150,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" @@ -16782,20 +17235,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", @@ -16812,6 +17269,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", @@ -16825,10 +17284,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" @@ -16915,7 +17378,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": { @@ -16930,6 +17395,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": { @@ -17170,9 +17637,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", @@ -17198,9 +17665,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", @@ -17219,6 +17686,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 @@ -17479,6 +17969,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", @@ -17490,6 +17982,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", @@ -17501,14 +17995,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" @@ -17516,10 +18016,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" @@ -17725,6 +18229,12 @@ "cloudform-types": { "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==", + "dev": true + }, "co": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", @@ -17773,7 +18283,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", @@ -17836,10 +18348,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", @@ -17880,7 +18396,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": { @@ -17953,10 +18471,6 @@ "version": "5.2.0", "dev": true }, - "is-stream": { - "version": "1.1.0", - "dev": true - }, "readable-stream": { "version": "2.3.8", "dev": true, @@ -18010,10 +18524,6 @@ "file-type": { "version": "6.2.0", "dev": true - }, - "is-stream": { - "version": "1.1.0", - "dev": true } } }, @@ -18029,10 +18539,6 @@ "file-type": { "version": "5.2.0", "dev": true - }, - "is-stream": { - "version": "1.1.0", - "dev": true } } }, @@ -18152,11 +18658,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": { @@ -18582,7 +19092,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 } } @@ -18637,7 +19149,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 } } @@ -18833,9 +19347,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" @@ -18902,7 +19416,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": { @@ -18930,6 +19446,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": { @@ -19010,6 +19528,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", @@ -19180,7 +19700,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": { @@ -19195,9 +19717,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 }, @@ -19341,6 +19863,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", @@ -19399,6 +19923,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": { @@ -19798,6 +20324,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, @@ -19860,6 +20392,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": {} }, @@ -19878,17 +20412,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": { @@ -19943,8 +20466,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": { @@ -20003,6 +20596,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", @@ -20013,6 +20608,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", @@ -20026,10 +20623,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" @@ -20039,6 +20640,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": { @@ -20106,6 +20709,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" @@ -20113,6 +20718,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", @@ -20126,10 +20733,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" @@ -20147,6 +20758,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" @@ -20303,18 +20916,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": { @@ -20323,6 +20950,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": { @@ -20432,16 +21061,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": { @@ -20699,17 +21324,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" @@ -21045,25 +21676,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": { @@ -21160,6 +21772,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": { @@ -21429,6 +22043,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": { @@ -21573,7 +22189,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" @@ -21581,6 +22199,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" @@ -21588,6 +22208,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" @@ -21750,6 +22372,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" @@ -21836,18 +22460,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", @@ -21855,28 +22480,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", @@ -21884,15 +22509,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": { @@ -22099,6 +22726,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": { @@ -22144,7 +22773,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", @@ -22165,6 +22796,7 @@ "ajv": "^8.11.0", "case": "^1.6.3", "cloudform": "^7.4.2", + "cloudwatch-dashboard-types": "^1.0.1-rc2", "lodash": "^4.17.21", "pino": "^8.4.2", "ts-node": "^10.9.1", @@ -22297,6 +22929,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" @@ -22353,19 +22987,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": { @@ -22654,19 +23290,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": { @@ -22677,6 +23317,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", @@ -22684,25 +23326,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": { @@ -22744,6 +23367,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 @@ -22796,6 +23425,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": { @@ -23261,7 +23892,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": { @@ -23290,6 +23923,8 @@ }, "ws": { "version": "7.5.9", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz", + "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==", "dev": true, "requires": {} }, @@ -23346,6 +23981,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", @@ -23401,12 +24038,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" + } + } } } } diff --git a/sam-test-project/template.yaml b/sam-test-project/template.yaml index c59475a4..ce186a11 100755 --- a/sam-test-project/template.yaml +++ b/sam-test-project/template.yaml @@ -9,11 +9,10 @@ Transform: Metadata: slicWatch: enabled: true - alarmActionsConfig: { - alarmActions: [!Ref MonitoringTopic], - okActions: [!Ref MonitoringTopic], + alarmActionsConfig: + alarmActions: [!Ref MonitoringTopic] + okActions: [!Ref MonitoringTopic] actionsEnabled: true - } alarms: Lambda: Invocations: 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) } } } diff --git a/serverless-plugin/tests/index.test.ts b/serverless-plugin/tests/index.test.ts index dddcd764..d24129ed 100644 --- a/serverless-plugin/tests/index.test.ts +++ b/serverless-plugin/tests/index.test.ts @@ -73,23 +73,6 @@ const mockServerless = { } } -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 @@ -219,77 +202,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 = { - getProvider: () => { - }, - service: { - getAllFunctions: () => [], - provider: { - name: 'aws', - compiledCloudFormationTemplate: { - Resources: { - HelloTestLambda: { - Type: 'AWS::Lambda::Function', - MemorySize: 256, - Runtime: 'nodejs12', - Timeout: 60 - } - } - } - }, - custom: { - slicWatch: { - enabled: true - } - } - } - } - const plugin = new ServerlessPlugin(mockServerless, null, pluginUtils) - plugin.createSlicWatchResources() - t.same(Object.keys(mockServerless.service.provider.compiledCloudFormationTemplate.Resources), ['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() }) diff --git a/tsconfig.json b/tsconfig.json index c026ead6..0cdde55f 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -13,7 +13,7 @@ "resolveJsonModule": true, "target": "ESNext", "allowSyntheticDefaultImports": true, - "esModuleInterop": true + "esModuleInterop": true, }, "ts-node": { "swc": true,