From 3251b9c7c90e21e6ac46bcf72f1c28116a3f2620 Mon Sep 17 00:00:00 2001 From: Alexander Schueren Date: Tue, 11 Jul 2023 16:31:17 +0200 Subject: [PATCH 01/11] fix canary deploy in ci with correct workspace name (#1601) --- .github/workflows/reusable_deploy_layer_stack.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/reusable_deploy_layer_stack.yml b/.github/workflows/reusable_deploy_layer_stack.yml index e044615f1c..27521fc887 100644 --- a/.github/workflows/reusable_deploy_layer_stack.yml +++ b/.github/workflows/reusable_deploy_layer_stack.yml @@ -95,7 +95,7 @@ jobs: if-no-files-found: error retention-days: 1 - name: CDK deploy canary - run: npm run cdk -w layer -- deploy --app cdk.out --context region=${{ matrix.region }} 'CanaryStack' --require-approval never --verbose --outputs-file cdk-outputs.json + run: npm run cdk -w layers -- deploy --app cdk.out --context region=${{ matrix.region }} 'CanaryStack' --require-approval never --verbose --outputs-file cdk-outputs.json update_layer_arn_docs: needs: deploy-cdk-stack permissions: From 7cfac60bd5f597348c3dbb6a1aebdbf22a0fed3d Mon Sep 17 00:00:00 2001 From: "Release bot[bot]" Date: Tue, 11 Jul 2023 14:43:15 +0000 Subject: [PATCH 02/11] chore: update layer ARN on documentation --- docs/index.md | 68 +++++++++++++++++++++++++-------------------------- 1 file changed, 34 insertions(+), 34 deletions(-) diff --git a/docs/index.md b/docs/index.md index 5f599adfe4..6378415085 100644 --- a/docs/index.md +++ b/docs/index.md @@ -26,7 +26,7 @@ You can use Powertools for AWS Lambda (TypeScript) in both TypeScript and JavaSc You can install Powertools for AWS Lambda (TypeScript) using one of the following options: -* **Lambda Layer**: [**arn:aws:lambda:{region}:094274105915:layer:AWSLambdaPowertoolsTypeScript:15**](#){: .copyMe}:clipboard: +* **Lambda Layer**: [**arn:aws:lambda:{region}:094274105915:layer:AWSLambdaPowertoolsTypeScript:16**](#){: .copyMe}:clipboard: * **npm**: [`npm install @aws-lambda-powertools/tracer @aws-lambda-powertools/metrics @aws-lambda-powertools/logger`](#){: .copyMe}:clipboard: ### Lambda Layer @@ -41,31 +41,31 @@ You can include Powertools for AWS Lambda (TypeScript) Lambda Layer using [AWS L | Region | Layer ARN | | ---------------- | ------------------------------------------------------------------------------------------------------------ | - | `us-east-1` | [arn:aws:lambda:us-east-1:094274105915:layer:AWSLambdaPowertoolsTypeScript:15](#){: .copyMe}:clipboard: | - | `us-east-2` | [arn:aws:lambda:us-east-2:094274105915:layer:AWSLambdaPowertoolsTypeScript:15](#){: .copyMe}:clipboard: | - | `us-west-1` | [arn:aws:lambda:us-west-1:094274105915:layer:AWSLambdaPowertoolsTypeScript:15](#){: .copyMe}:clipboard: | - | `us-west-2` | [arn:aws:lambda:us-west-2:094274105915:layer:AWSLambdaPowertoolsTypeScript:15](#){: .copyMe}:clipboard: | - | `ap-south-1` | [arn:aws:lambda:ap-south-1:094274105915:layer:AWSLambdaPowertoolsTypeScript:15](#){: .copyMe}:clipboard: | - | `ap-east-1` | [arn:aws:lambda:ap-east-1:094274105915:layer:AWSLambdaPowertoolsTypeScript:15](#){: .copyMe}:clipboard: | - | `ap-northeast-1` | [arn:aws:lambda:ap-northeast-1:094274105915:layer:AWSLambdaPowertoolsTypeScript:15](#){: .copyMe}:clipboard: | - | `ap-northeast-2` | [arn:aws:lambda:ap-northeast-2:094274105915:layer:AWSLambdaPowertoolsTypeScript:15](#){: .copyMe}:clipboard: | - | `ap-northeast-3` | [arn:aws:lambda:ap-northeast-3:094274105915:layer:AWSLambdaPowertoolsTypeScript:15](#){: .copyMe}:clipboard: | - | `ap-southeast-1` | [arn:aws:lambda:ap-southeast-1:094274105915:layer:AWSLambdaPowertoolsTypeScript:15](#){: .copyMe}:clipboard: | - | `ap-southeast-2` | [arn:aws:lambda:ap-southeast-2:094274105915:layer:AWSLambdaPowertoolsTypeScript:15](#){: .copyMe}:clipboard: | - | `ap-southeast-3` | [arn:aws:lambda:ap-southeast-3:094274105915:layer:AWSLambdaPowertoolsTypeScript:15](#){: .copyMe}:clipboard: | - | `ap-southeast-4` | [arn:aws:lambda:ap-southeast-4:094274105915:layer:AWSLambdaPowertoolsTypeScript:15](#){: .copyMe}:clipboard: | - | `eu-central-1` | [arn:aws:lambda:eu-central-1:094274105915:layer:AWSLambdaPowertoolsTypeScript:15](#){: .copyMe}:clipboard: | - | `eu-central-2` | [arn:aws:lambda:eu-central-1:094274105915:layer:AWSLambdaPowertoolsTypeScript:15](#){: .copyMe}:clipboard: | - | `eu-west-1` | [arn:aws:lambda:eu-west-1:094274105915:layer:AWSLambdaPowertoolsTypeScript:15](#){: .copyMe}:clipboard: | - | `eu-west-2` | [arn:aws:lambda:eu-west-2:094274105915:layer:AWSLambdaPowertoolsTypeScript:15](#){: .copyMe}:clipboard: | - | `eu-west-3` | [arn:aws:lambda:eu-west-3:094274105915:layer:AWSLambdaPowertoolsTypeScript:15](#){: .copyMe}:clipboard: | - | `eu-north-1` | [arn:aws:lambda:eu-north-1:094274105915:layer:AWSLambdaPowertoolsTypeScript:15](#){: .copyMe}:clipboard: | - | `eu-south-1` | [arn:aws:lambda:eu-south-1:094274105915:layer:AWSLambdaPowertoolsTypeScript:15](#){: .copyMe}:clipboard: | - | `eu-south-2` | [arn:aws:lambda:eu-south-2:094274105915:layer:AWSLambdaPowertoolsTypeScript:15](#){: .copyMe}:clipboard: | - | `ca-central-1` | [arn:aws:lambda:ca-central-1:094274105915:layer:AWSLambdaPowertoolsTypeScript:15](#){: .copyMe}:clipboard: | - | `sa-east-1` | [arn:aws:lambda:sa-east-1:094274105915:layer:AWSLambdaPowertoolsTypeScript:15](#){: .copyMe}:clipboard: | - | `af-south-1` | [arn:aws:lambda:af-south-1:094274105915:layer:AWSLambdaPowertoolsTypeScript:15](#){: .copyMe}:clipboard: | - | `me-south-1` | [arn:aws:lambda:me-south-1:094274105915:layer:AWSLambdaPowertoolsTypeScript:15](#){: .copyMe}:clipboard: | + | `us-east-1` | [arn:aws:lambda:us-east-1:094274105915:layer:AWSLambdaPowertoolsTypeScript:16](#){: .copyMe}:clipboard: | + | `us-east-2` | [arn:aws:lambda:us-east-2:094274105915:layer:AWSLambdaPowertoolsTypeScript:16](#){: .copyMe}:clipboard: | + | `us-west-1` | [arn:aws:lambda:us-west-1:094274105915:layer:AWSLambdaPowertoolsTypeScript:16](#){: .copyMe}:clipboard: | + | `us-west-2` | [arn:aws:lambda:us-west-2:094274105915:layer:AWSLambdaPowertoolsTypeScript:16](#){: .copyMe}:clipboard: | + | `ap-south-1` | [arn:aws:lambda:ap-south-1:094274105915:layer:AWSLambdaPowertoolsTypeScript:16](#){: .copyMe}:clipboard: | + | `ap-east-1` | [arn:aws:lambda:ap-east-1:094274105915:layer:AWSLambdaPowertoolsTypeScript:16](#){: .copyMe}:clipboard: | + | `ap-northeast-1` | [arn:aws:lambda:ap-northeast-1:094274105915:layer:AWSLambdaPowertoolsTypeScript:16](#){: .copyMe}:clipboard: | + | `ap-northeast-2` | [arn:aws:lambda:ap-northeast-2:094274105915:layer:AWSLambdaPowertoolsTypeScript:16](#){: .copyMe}:clipboard: | + | `ap-northeast-3` | [arn:aws:lambda:ap-northeast-3:094274105915:layer:AWSLambdaPowertoolsTypeScript:16](#){: .copyMe}:clipboard: | + | `ap-southeast-1` | [arn:aws:lambda:ap-southeast-1:094274105915:layer:AWSLambdaPowertoolsTypeScript:16](#){: .copyMe}:clipboard: | + | `ap-southeast-2` | [arn:aws:lambda:ap-southeast-2:094274105915:layer:AWSLambdaPowertoolsTypeScript:16](#){: .copyMe}:clipboard: | + | `ap-southeast-3` | [arn:aws:lambda:ap-southeast-3:094274105915:layer:AWSLambdaPowertoolsTypeScript:16](#){: .copyMe}:clipboard: | + | `ap-southeast-4` | [arn:aws:lambda:ap-southeast-4:094274105915:layer:AWSLambdaPowertoolsTypeScript:16](#){: .copyMe}:clipboard: | + | `eu-central-1` | [arn:aws:lambda:eu-central-1:094274105915:layer:AWSLambdaPowertoolsTypeScript:16](#){: .copyMe}:clipboard: | + | `eu-central-2` | [arn:aws:lambda:eu-central-1:094274105915:layer:AWSLambdaPowertoolsTypeScript:16](#){: .copyMe}:clipboard: | + | `eu-west-1` | [arn:aws:lambda:eu-west-1:094274105915:layer:AWSLambdaPowertoolsTypeScript:16](#){: .copyMe}:clipboard: | + | `eu-west-2` | [arn:aws:lambda:eu-west-2:094274105915:layer:AWSLambdaPowertoolsTypeScript:16](#){: .copyMe}:clipboard: | + | `eu-west-3` | [arn:aws:lambda:eu-west-3:094274105915:layer:AWSLambdaPowertoolsTypeScript:16](#){: .copyMe}:clipboard: | + | `eu-north-1` | [arn:aws:lambda:eu-north-1:094274105915:layer:AWSLambdaPowertoolsTypeScript:16](#){: .copyMe}:clipboard: | + | `eu-south-1` | [arn:aws:lambda:eu-south-1:094274105915:layer:AWSLambdaPowertoolsTypeScript:16](#){: .copyMe}:clipboard: | + | `eu-south-2` | [arn:aws:lambda:eu-south-2:094274105915:layer:AWSLambdaPowertoolsTypeScript:16](#){: .copyMe}:clipboard: | + | `ca-central-1` | [arn:aws:lambda:ca-central-1:094274105915:layer:AWSLambdaPowertoolsTypeScript:16](#){: .copyMe}:clipboard: | + | `sa-east-1` | [arn:aws:lambda:sa-east-1:094274105915:layer:AWSLambdaPowertoolsTypeScript:16](#){: .copyMe}:clipboard: | + | `af-south-1` | [arn:aws:lambda:af-south-1:094274105915:layer:AWSLambdaPowertoolsTypeScript:16](#){: .copyMe}:clipboard: | + | `me-south-1` | [arn:aws:lambda:me-south-1:094274105915:layer:AWSLambdaPowertoolsTypeScript:16](#){: .copyMe}:clipboard: | ??? note "Click to expand and copy code snippets for popular frameworks" @@ -76,7 +76,7 @@ You can include Powertools for AWS Lambda (TypeScript) Lambda Layer using [AWS L Type: AWS::Serverless::Function Properties: Layers: - - !Sub arn:aws:lambda:${AWS::Region}:094274105915:layer:AWSLambdaPowertoolsTypeScript:15 + - !Sub arn:aws:lambda:${AWS::Region}:094274105915:layer:AWSLambdaPowertoolsTypeScript:16 ``` If you use `esbuild` to bundle your code, make sure to exclude `@aws-lambda-powertools` from being bundled since the packages will be already present the Layer: @@ -107,7 +107,7 @@ You can include Powertools for AWS Lambda (TypeScript) Lambda Layer using [AWS L hello: handler: lambda_function.lambda_handler layers: - - arn:aws:lambda:${aws::region}:094274105915:layer:AWSLambdaPowertoolsTypeScript:15 + - arn:aws:lambda:${aws::region}:094274105915:layer:AWSLambdaPowertoolsTypeScript:16 ``` If you use `esbuild` to bundle your code, make sure to exclude `@aws-lambda-powertools` from being bundled since the packages will be already present the Layer: @@ -139,7 +139,7 @@ You can include Powertools for AWS Lambda (TypeScript) Lambda Layer using [AWS L const powertoolsLayer = lambda.LayerVersion.fromLayerVersionArn( this, 'PowertoolsLayer', - `arn:aws:lambda:${cdk.Stack.of(this).region}:094274105915:layer:AWSLambdaPowertoolsTypeScript:15` + `arn:aws:lambda:${cdk.Stack.of(this).region}:094274105915:layer:AWSLambdaPowertoolsTypeScript:16` ); new lambda.Function(this, 'Function', { @@ -191,7 +191,7 @@ You can include Powertools for AWS Lambda (TypeScript) Lambda Layer using [AWS L role = ... handler = "index.handler" runtime = "nodejs16.x" - layers = ["arn:aws:lambda:{aws::region}:094274105915:layer:AWSLambdaPowertoolsTypeScript:15"] + layers = ["arn:aws:lambda:{aws::region}:094274105915:layer:AWSLambdaPowertoolsTypeScript:16"] source_code_hash = filebase64sha256("lambda_function_payload.zip") } ``` @@ -209,7 +209,7 @@ You can include Powertools for AWS Lambda (TypeScript) Lambda Layer using [AWS L const lambdaFunction = new aws.lambda.Function('function', { layers: [ - pulumi.interpolate`arn:aws:lambda:${aws.getRegionOutput().name}:094274105915:layer:AWSLambdaPowertoolsTypeScript:15` + pulumi.interpolate`arn:aws:lambda:${aws.getRegionOutput().name}:094274105915:layer:AWSLambdaPowertoolsTypeScript:16` ], code: new pulumi.asset.FileArchive('lambda_function_payload.zip'), tracingConfig: { @@ -233,7 +233,7 @@ You can include Powertools for AWS Lambda (TypeScript) Lambda Layer using [AWS L ? Do you want to configure advanced settings? Yes ... ? Do you want to enable Lambda layers for this function? Yes - ? Enter up to 5 existing Lambda layer ARNs (comma-separated): arn:aws:lambda:{aws::region}:094274105915:layer:AWSLambdaPowertoolsTypeScript:15 + ? Enter up to 5 existing Lambda layer ARNs (comma-separated): arn:aws:lambda:{aws::region}:094274105915:layer:AWSLambdaPowertoolsTypeScript:16 ❯ amplify push -y # Updating an existing function and add the layer @@ -243,7 +243,7 @@ You can include Powertools for AWS Lambda (TypeScript) Lambda Layer using [AWS L - Name: ? Which setting do you want to update? Lambda layers configuration ? Do you want to enable Lambda layers for this function? Yes - ? Enter up to 5 existing Lambda layer ARNs (comma-separated): arn:aws:lambda:{aws::region}:094274105915:layer:AWSLambdaPowertoolsTypeScript:15 + ? Enter up to 5 existing Lambda layer ARNs (comma-separated): arn:aws:lambda:{aws::region}:094274105915:layer:AWSLambdaPowertoolsTypeScript:16 ? Do you want to edit the local lambda function now? No ``` @@ -253,7 +253,7 @@ You can include Powertools for AWS Lambda (TypeScript) Lambda Layer using [AWS L Change {region} to your AWS region, e.g. `eu-west-1` ```bash title="AWS CLI" - aws lambda get-layer-version-by-arn --arn arn:aws:lambda:{aws::region}:094274105915:layer:AWSLambdaPowertoolsTypeScript:15 --region {region} + aws lambda get-layer-version-by-arn --arn arn:aws:lambda:{aws::region}:094274105915:layer:AWSLambdaPowertoolsTypeScript:16 --region {region} ``` The pre-signed URL to download this Lambda Layer will be within `Location` key. From fa3e1a1c83a92df2c90e1d8ceaebf3a2b5876a78 Mon Sep 17 00:00:00 2001 From: Alexander Schueren Date: Fri, 14 Jul 2023 21:16:21 +0200 Subject: [PATCH 03/11] remove proxy-agent (#1611) --- package-lock.json | 1088 +++++++++++++++++++++++++++++++++++++-------- package.json | 1 - 2 files changed, 896 insertions(+), 193 deletions(-) diff --git a/package-lock.json b/package-lock.json index d9d180d8ae..6d7e8a340d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -387,6 +387,15 @@ "source-map": "^0.6.0" } }, + "node_modules/@aashutoshrathi/word-wrap": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", + "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/@ampproject/remapping": { "version": "2.2.0", "dev": true, @@ -423,16 +432,17 @@ } }, "node_modules/@aws-cdk/cloud-assembly-schema": { - "version": "2.73.0", + "version": "2.87.0", + "resolved": "https://registry.npmjs.org/@aws-cdk/cloud-assembly-schema/-/cloud-assembly-schema-2.87.0.tgz", + "integrity": "sha512-uXbereQy1bjhQAh2rbMkfG0uyaheCQCfkT+EzCr9NdeSGt9fSXjBg2O8E/SqA/RPmEH+YsgkVLVtlPc/i5wdUg==", "bundleDependencies": [ "jsonschema", "semver" ], "dev": true, - "license": "Apache-2.0", "dependencies": { "jsonschema": "^1.4.1", - "semver": "^7.3.8" + "semver": "^7.5.1" }, "engines": { "node": ">= 14.15.0" @@ -460,7 +470,7 @@ } }, "node_modules/@aws-cdk/cloud-assembly-schema/node_modules/semver": { - "version": "7.3.8", + "version": "7.5.2", "dev": true, "inBundle": true, "license": "ISC", @@ -497,21 +507,22 @@ } }, "node_modules/@aws-cdk/cx-api": { - "version": "2.73.0", + "version": "2.87.0", + "resolved": "https://registry.npmjs.org/@aws-cdk/cx-api/-/cx-api-2.87.0.tgz", + "integrity": "sha512-8KTgc1mL77/Ej2jKebjJUzSCH8DVV35i/kXDm9p8MCpxZpS2qN7tTDy8Y3ppubLkBMpG4HD4Tmlddy5ThS9ZWQ==", "bundleDependencies": [ "semver" ], "dev": true, - "license": "Apache-2.0", "dependencies": { - "@aws-cdk/cloud-assembly-schema": "2.73.0", - "semver": "^7.3.8" + "@aws-cdk/cloud-assembly-schema": "2.87.0", + "semver": "^7.5.1" }, "engines": { "node": ">= 14.15.0" }, "peerDependencies": { - "@aws-cdk/cloud-assembly-schema": "2.73.0" + "@aws-cdk/cloud-assembly-schema": "2.87.0" } }, "node_modules/@aws-cdk/cx-api/node_modules/lru-cache": { @@ -527,7 +538,7 @@ } }, "node_modules/@aws-cdk/cx-api/node_modules/semver": { - "version": "7.3.8", + "version": "7.5.2", "dev": true, "inBundle": true, "license": "ISC", @@ -6051,9 +6062,9 @@ } }, "node_modules/aws-cdk-lib": { - "version": "2.80.0", - "resolved": "https://registry.npmjs.org/aws-cdk-lib/-/aws-cdk-lib-2.80.0.tgz", - "integrity": "sha512-PoqD3Yms5I0ajuTi071nTW/hpkH3XsdyZzn5gYsPv0qD7mqP3h6Qr+6RiGx+yQ1KcVFyxWdX15uK+DsC0KwvcQ==", + "version": "2.87.0", + "resolved": "https://registry.npmjs.org/aws-cdk-lib/-/aws-cdk-lib-2.87.0.tgz", + "integrity": "sha512-9kirXX7L7OP/yGmCbaYlkt5OAtowGiGw0AYFIQvSwvx/UU3aJO5XuDwAgDsvToDkRpBi0yX0bNwqa0DItu+C6A==", "bundleDependencies": [ "@balena/dockerignore", "case", @@ -6293,7 +6304,7 @@ } }, "node_modules/aws-cdk-lib/node_modules/semver": { - "version": "7.5.1", + "version": "7.5.2", "inBundle": true, "license": "ISC", "dependencies": { @@ -6889,227 +6900,911 @@ "integrity": "sha512-12+IR2CB2C28MMAw0Ncqwj5QbTcs0nGIhgJzYWzDkb21vWmfNI83KS4f3Ci6GI98WreIfG7o9UXp3C0qbpA8nQ==", "dev": true, "dependencies": { - "minipass": "^5.0.0" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "minipass": "^5.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/call-bind": { + "version": "1.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase": { + "version": "5.3.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase-keys": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-6.2.2.tgz", + "integrity": "sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg==", + "dev": true, + "dependencies": { + "camelcase": "^5.3.1", + "map-obj": "^4.0.0", + "quick-lru": "^4.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001439", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/cdk-assets": { + "version": "2.87.0", + "resolved": "https://registry.npmjs.org/cdk-assets/-/cdk-assets-2.87.0.tgz", + "integrity": "sha512-/OniPxjVxMCip24Pb/3B876FTJoFhIUgWXWxG/PfM3TlLYBTb4DyMgLaTHI4hnco0fJPGHZMGwIFjmch818PMg==", + "dev": true, + "hasShrinkwrap": true, + "dependencies": { + "@aws-cdk/cloud-assembly-schema": "2.87.0", + "@aws-cdk/cx-api": "2.87.0", + "archiver": "^5.3.1", + "aws-sdk": "^2.1379.0", + "glob": "^7.2.3", + "mime": "^2.6.0", + "yargs": "^16.2.0" + }, + "bin": { + "cdk-assets": "bin/cdk-assets", + "docker-credential-cdk-assets": "bin/docker-credential-cdk-assets" + }, + "engines": { + "node": ">= 14.15.0" + } + }, + "node_modules/cdk-assets/node_modules/@aws-cdk/cloud-assembly-schema": { + "version": "2.87.0", + "dev": true, + "dependencies": { + "jsonschema": "^1.4.1", + "semver": "^7.5.1" + } + }, + "node_modules/cdk-assets/node_modules/@aws-cdk/cx-api": { + "version": "2.87.0", + "dev": true, + "dependencies": { + "@aws-cdk/cloud-assembly-schema": "2.87.0", + "semver": "^7.5.1" + } + }, + "node_modules/cdk-assets/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true + }, + "node_modules/cdk-assets/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + } + }, + "node_modules/cdk-assets/node_modules/archiver": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/archiver/-/archiver-5.3.1.tgz#21e92811d6f09ecfce649fbefefe8c79e57cbbb6", + "integrity": "sha512-8KyabkmbYrH+9ibcTScQ1xCJC/CGcugdVIwB+53f5sZziXgwUh3iXlAlANMxcZyDEfTHMe6+Z5FofV8nopXP7w==", + "dev": true, + "dependencies": { + "archiver-utils": "^2.1.0", + "async": "^3.2.3", + "buffer-crc32": "^0.2.1", + "readable-stream": "^3.6.0", + "readdir-glob": "^1.0.0", + "tar-stream": "^2.2.0", + "zip-stream": "^4.1.0" + } + }, + "node_modules/cdk-assets/node_modules/archiver-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/archiver-utils/-/archiver-utils-2.1.0.tgz#e8a460e94b693c3e3da182a098ca6285ba9249e2", + "integrity": "sha512-bEL/yUb/fNNiNTuUz979Z0Yg5L+LzLxGJz8x79lYmR54fmTIb6ob/hNQgkQnIUDWIFjZVQwl9Xs356I6BAMHfw==", + "dev": true, + "dependencies": { + "glob": "^7.1.4", + "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": "^2.0.0" + } + }, + "node_modules/cdk-assets/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#91125e8042bba1b9887f49345f6277027ce8be9b", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/cdk-assets/node_modules/async": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.4.tgz#2d22e00f8cddeb5fde5dd33522b56d1cf569a81c", + "integrity": "sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==", + "dev": true + }, + "node_modules/cdk-assets/node_modules/available-typed-arrays": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz#92f95616501069d07d10edb2fc37d3e1c65123b7", + "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", + "dev": true + }, + "node_modules/cdk-assets/node_modules/aws-sdk": { + "version": "2.1401.0", + "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1401.0.tgz#c283de69b9beb76a39243d1331c63c21f0ff5a0e", + "integrity": "sha512-qzuMxIvCmH1Df194sYn+L5yDrChIKzZG/fBLElPVSN1fB18qhPSYUfr9uVCMeTpDCmdTW1Ojk7cAkByzzAnKjA==", + "dev": true, + "dependencies": { + "buffer": "4.9.2", + "events": "1.1.1", + "ieee754": "1.1.13", + "jmespath": "0.16.0", + "querystring": "0.2.0", + "sax": "1.2.1", + "url": "0.10.3", + "util": "^0.12.4", + "uuid": "8.0.0", + "xml2js": "0.5.0" + } + }, + "node_modules/cdk-assets/node_modules/aws-sdk/node_modules/buffer": { + "version": "4.9.2", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz#230ead344002988644841ab0244af8c44bbe3ef8", + "integrity": "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==", + "dev": true, + "dependencies": { + "base64-js": "^1.0.2", + "ieee754": "^1.1.4", + "isarray": "^1.0.0" + } + }, + "node_modules/cdk-assets/node_modules/aws-sdk/node_modules/buffer/node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "dev": true + }, + "node_modules/cdk-assets/node_modules/aws-sdk/node_modules/ieee754": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz#ec168558e95aa181fd87d37f55c32bbcb6708b84", + "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==", + "dev": true + }, + "node_modules/cdk-assets/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "node_modules/cdk-assets/node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "dev": true + }, + "node_modules/cdk-assets/node_modules/bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz#451535264182bec2fbbc83a62ab98cf11d9f7b3a", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "dev": true, + "dependencies": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "node_modules/cdk-assets/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/cdk-assets/node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "dev": true, + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/cdk-assets/node_modules/buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242", + "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", + "dev": true + }, + "node_modules/cdk-assets/node_modules/call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + } + }, + "node_modules/cdk-assets/node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/cdk-assets/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + } + }, + "node_modules/cdk-assets/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/cdk-assets/node_modules/compress-commons": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/compress-commons/-/compress-commons-4.1.1.tgz#df2a09a7ed17447642bad10a85cc9a19e5c42a7d", + "integrity": "sha512-QLdDLCKNV2dtoTorqgxngQCMA+gWXkM/Nwu7FpeBhk/RdkzimqC3jueb/FDmaZeXh+uby1jkBqE3xArsLBE5wQ==", + "dev": true, + "dependencies": { + "buffer-crc32": "^0.2.13", + "crc32-stream": "^4.0.2", + "normalize-path": "^3.0.0", + "readable-stream": "^3.6.0" + } + }, + "node_modules/cdk-assets/node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "node_modules/cdk-assets/node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "dev": true + }, + "node_modules/cdk-assets/node_modules/crc-32": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz#3cad35a934b8bf71f25ca524b6da51fb7eace2ff", + "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==", + "dev": true + }, + "node_modules/cdk-assets/node_modules/crc32-stream": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/crc32-stream/-/crc32-stream-4.0.2.tgz#c922ad22b38395abe9d3870f02fa8134ed709007", + "integrity": "sha512-DxFZ/Hk473b/muq1VJ///PMNLj0ZMnzye9thBpmjpJKCc5eMgB95aK8zCGrGfQ90cWo561Te6HK9D+j4KPdM6w==", + "dev": true, + "dependencies": { + "crc-32": "^1.2.0", + "readable-stream": "^3.4.0" + } + }, + "node_modules/cdk-assets/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/cdk-assets/node_modules/end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dev": true, + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/cdk-assets/node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true + }, + "node_modules/cdk-assets/node_modules/events": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz#9ebdb7635ad099c70dcc4c2a1f5004288e8bd924", + "integrity": "sha512-kEcvvCBByWXGnZy6JUlgAp2gBIUjfCAV6P6TgT1/aaQKcmuAEC4OZTV1I4EWQLz2gxZw76atuVyvHhTxvi0Flw==", + "dev": true + }, + "node_modules/cdk-assets/node_modules/for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz#69b447e88a0a5d32c3e7084f3f1710034b21376e", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "dev": true, + "dependencies": { + "is-callable": "^1.1.3" + } + }, + "node_modules/cdk-assets/node_modules/fs-constants": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz#6be0de9be998ce16af8afc24497b9ee9b7ccd9ad", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", + "dev": true + }, + "node_modules/cdk-assets/node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "node_modules/cdk-assets/node_modules/function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "node_modules/cdk-assets/node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true + }, + "node_modules/cdk-assets/node_modules/get-intrinsic": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.1.tgz#d295644fed4505fc9cde952c37ee12b477a83d82", + "integrity": "sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3" + } + }, + "node_modules/cdk-assets/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "node_modules/cdk-assets/node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz#29ff76de69dac7489b7c0918a5788e56477c332c", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.1.3" + } + }, + "node_modules/cdk-assets/node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true + }, + "node_modules/cdk-assets/node_modules/has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1" + } + }, + "node_modules/cdk-assets/node_modules/has-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz#1885c1305538958aff469fef37937c22795408e0", + "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", + "dev": true + }, + "node_modules/cdk-assets/node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "dev": true + }, + "node_modules/cdk-assets/node_modules/has-tostringtag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz#7e133818a7d394734f941e73c3d3f9291e658b25", + "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "dev": true, + "dependencies": { + "has-symbols": "^1.0.2" + } + }, + "node_modules/cdk-assets/node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "dev": true + }, + "node_modules/cdk-assets/node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/cdk-assets/node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "node_modules/cdk-assets/node_modules/is-arguments": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz#15b3f88fda01f2a97fec84ca761a560f123efa9b", + "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + } + }, + "node_modules/cdk-assets/node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz#3bc2a85ea742d9e36205dcacdd72ca1fdc51b055", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "dev": true + }, + "node_modules/cdk-assets/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + }, + "node_modules/cdk-assets/node_modules/is-generator-function": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz#f1558baf1ac17e0deea7c0415c438351ff2b3c72", + "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + } + }, + "node_modules/cdk-assets/node_modules/is-typed-array": { + "version": "1.1.10", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.10.tgz#36a5b5cb4189b575d1a3e4b08536bfb485801e3f", + "integrity": "sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A==", + "dev": true, + "dependencies": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0" + } + }, + "node_modules/cdk-assets/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true + }, + "node_modules/cdk-assets/node_modules/jmespath": { + "version": "0.16.0", + "resolved": "https://registry.npmjs.org/jmespath/-/jmespath-0.16.0.tgz#b15b0a85dfd4d930d43e69ed605943c802785076", + "integrity": "sha512-9FzQjJ7MATs1tSpnco1K6ayiYE3figslrXA72G2HQ/n76RzvYlofyi5QM+iX4YRs/pu3yzxlVQSST23+dMDknw==", + "dev": true + }, + "node_modules/cdk-assets/node_modules/jsonschema": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jsonschema/-/jsonschema-1.4.1.tgz#cc4c3f0077fb4542982973d8a083b6b34f482dab", + "integrity": "sha512-S6cATIPVv1z0IlxdN+zUk5EPjkGCdnhN4wVSBlvoUO1tOLJootbo9CquNJmbIh4yikWHiUedhRYrNPn1arpEmQ==", + "dev": true + }, + "node_modules/cdk-assets/node_modules/lazystream": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.1.tgz#494c831062f1f9408251ec44db1cba29242a2638", + "integrity": "sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==", + "dev": true, + "dependencies": { + "readable-stream": "^2.0.5" + } + }, + "node_modules/cdk-assets/node_modules/lazystream/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz#91125e8042bba1b9887f49345f6277027ce8be9b", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/cdk-assets/node_modules/lodash.defaults": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz#d09178716ffea4dde9e5fb7b37f6f0802274580c", + "integrity": "sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==", + "dev": true + }, + "node_modules/cdk-assets/node_modules/lodash.difference": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.difference/-/lodash.difference-4.5.0.tgz#9ccb4e505d486b91651345772885a2df27fd017c", + "integrity": "sha512-dS2j+W26TQ7taQBGN8Lbbq04ssV3emRw4NY58WErlTO29pIqS0HmoT5aJ9+TUQ1N3G+JOZSji4eugsWwGp9yPA==", + "dev": true + }, + "node_modules/cdk-assets/node_modules/lodash.flatten": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz#f31c22225a9632d2bbf8e4addbef240aa765a61f", + "integrity": "sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g==", + "dev": true + }, + "node_modules/cdk-assets/node_modules/lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", + "dev": true + }, + "node_modules/cdk-assets/node_modules/lodash.union": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.union/-/lodash.union-4.6.0.tgz#48bb5088409f16f1821666641c44dd1aaae3cd88", + "integrity": "sha512-c4pB2CdGrGdjMKYLA+XiRDO7Y0PRQbm/Gzg8qMj+QH+pFVAoTp5sBpO0odL3FjoPCGjK96p6qsP+yQoiLoOBcw==", + "dev": true + }, + "node_modules/cdk-assets/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + } + }, + "node_modules/cdk-assets/node_modules/mime": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz#a2a682a95cd4d0cb1d6257e28f83da7e35800367", + "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", + "dev": true + }, + "node_modules/cdk-assets/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + } + }, + "node_modules/cdk-assets/node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true + }, + "node_modules/cdk-assets/node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/cdk-assets/node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true + }, + "node_modules/cdk-assets/node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true + }, + "node_modules/cdk-assets/node_modules/punycode": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d", + "integrity": "sha512-RofWgt/7fL5wP1Y7fxE7/EmTLzQVnB0ycyibJ0OOHIlJqTNzglYFxVwETOcIoJqJmpDXJ9xImDv+Fq34F/d4Dw==", + "dev": true + }, + "node_modules/cdk-assets/node_modules/querystring": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620", + "integrity": "sha512-X/xY82scca2tau62i9mDyU9K+I+djTMUsvwf7xnUX5GLvVzgJybOJf4Y6o9Zx3oJK/LSXg5tTZBjwzqVPaPO2g==", + "dev": true + }, + "node_modules/cdk-assets/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz#56a9b36ea965c00c5a93ef31eb111a0f11056967", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" } }, - "node_modules/call-bind": { - "version": "1.0.2", + "node_modules/cdk-assets/node_modules/readable-stream/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true + }, + "node_modules/cdk-assets/node_modules/readable-stream/node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", "dev": true, - "license": "MIT", "dependencies": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "safe-buffer": "~5.2.0" } }, - "node_modules/callsites": { - "version": "3.1.0", + "node_modules/cdk-assets/node_modules/readdir-glob": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/readdir-glob/-/readdir-glob-1.1.3.tgz#c3d831f51f5e7bfa62fa2ffbe4b508c640f09584", + "integrity": "sha512-v05I2k7xN8zXvPD9N+z/uhXPaj0sUFCe2rcWZIpBsqxfP7xXFQ0tipAd/wjj1YxWyWtUS5IDJpOG82JKt2EAVA==", "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" + "dependencies": { + "minimatch": "^5.1.0" } }, - "node_modules/camelcase": { - "version": "5.3.1", + "node_modules/cdk-assets/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#1edc459e0f0c548486ecf9fc99f2221364b9a0ae", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" + "dependencies": { + "balanced-match": "^1.0.0" } }, - "node_modules/camelcase-keys": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-6.2.2.tgz", - "integrity": "sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg==", + "node_modules/cdk-assets/node_modules/readdir-glob/node_modules/minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz#1cfcb8cf5522ea69952cd2af95ae09477f122a96", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", "dev": true, "dependencies": { - "camelcase": "^5.3.1", - "map-obj": "^4.0.0", - "quick-lru": "^4.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "brace-expansion": "^2.0.1" } }, - "node_modules/caniuse-lite": { - "version": "1.0.30001439", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/caniuse-lite" - } - ], - "license": "CC-BY-4.0" + "node_modules/cdk-assets/node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true }, - "node_modules/cdk-assets": { - "version": "2.72.1", + "node_modules/cdk-assets/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "node_modules/cdk-assets/node_modules/sax": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.1.tgz#7b8e656190b228e81a66aea748480d828cd2d37a", + "integrity": "sha512-8I2a3LovHTOpm7NV5yOyO8IHqgVsfK4+UuySrXU8YXkSRX7k6hCV9b3HrkKCr3nMpgj+0bmocaJJWpvp1oc7ZA==", + "dev": true + }, + "node_modules/cdk-assets/node_modules/semver": { + "version": "7.5.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.2.tgz#5b851e66d1be07c1cdaf37dfc856f543325a2beb", + "integrity": "sha512-SoftuTROv/cRjCze/scjGyiDtcUyxw1rgYQSZY7XTmtR5hX+dm76iDbTH8TkLPHCQmlbQVSSbNZCPM2hb0knnQ==", "dev": true, - "license": "Apache-2.0", "dependencies": { - "@aws-cdk/cloud-assembly-schema": "2.72.1", - "@aws-cdk/cx-api": "2.72.1", - "archiver": "^5.3.1", - "aws-sdk": "^2.1329.0", - "glob": "^7.2.3", - "mime": "^2.6.0", - "yargs": "^16.2.0" - }, - "bin": { - "cdk-assets": "bin/cdk-assets", - "docker-credential-cdk-assets": "bin/docker-credential-cdk-assets" - }, - "engines": { - "node": ">= 14.15.0" + "lru-cache": "^6.0.0" } }, - "node_modules/cdk-assets/node_modules/@aws-cdk/cloud-assembly-schema": { - "version": "2.72.1", - "bundleDependencies": [ - "jsonschema", - "semver" - ], + "node_modules/cdk-assets/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, - "license": "Apache-2.0", "dependencies": { - "jsonschema": "^1.4.1", - "semver": "^7.3.8" - }, - "engines": { - "node": ">= 14.15.0" + "safe-buffer": "~5.1.0" } }, - "node_modules/cdk-assets/node_modules/@aws-cdk/cloud-assembly-schema/node_modules/jsonschema": { - "version": "1.4.1", + "node_modules/cdk-assets/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, - "inBundle": true, - "license": "MIT", - "engines": { - "node": "*" + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" } }, - "node_modules/cdk-assets/node_modules/@aws-cdk/cloud-assembly-schema/node_modules/lru-cache": { - "version": "6.0.0", + "node_modules/cdk-assets/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, - "inBundle": true, - "license": "ISC", "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" + "ansi-regex": "^5.0.1" } }, - "node_modules/cdk-assets/node_modules/@aws-cdk/cloud-assembly-schema/node_modules/semver": { - "version": "7.3.8", + "node_modules/cdk-assets/node_modules/tar-stream": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz#acad84c284136b060dc3faa64474aa9aebd77287", + "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", "dev": true, - "inBundle": true, - "license": "ISC", "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" + "bl": "^4.0.3", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" } }, - "node_modules/cdk-assets/node_modules/@aws-cdk/cloud-assembly-schema/node_modules/yallist": { - "version": "4.0.0", + "node_modules/cdk-assets/node_modules/url": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/url/-/url-0.10.3.tgz#021e4d9c7705f21bbf37d03ceb58767402774c64", + "integrity": "sha512-hzSUW2q06EqL1gKM/a+obYHLIO6ct2hwPuviqTTOcfFVc61UbfJ2Q32+uGL/HCPxKqrdGB5QUwIe7UqlDgwsOQ==", "dev": true, - "inBundle": true, - "license": "ISC" + "dependencies": { + "punycode": "1.3.2", + "querystring": "0.2.0" + } }, - "node_modules/cdk-assets/node_modules/@aws-cdk/cx-api": { - "version": "2.72.1", - "bundleDependencies": [ - "semver" - ], + "node_modules/cdk-assets/node_modules/util": { + "version": "0.12.5", + "resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz#5f17a6059b73db61a875668781a1c2b136bd6fbc", + "integrity": "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==", "dev": true, - "license": "Apache-2.0", "dependencies": { - "@aws-cdk/cloud-assembly-schema": "2.72.1", - "semver": "^7.3.8" - }, - "engines": { - "node": ">= 14.15.0" - }, - "peerDependencies": { - "@aws-cdk/cloud-assembly-schema": "2.72.1" + "inherits": "^2.0.3", + "is-arguments": "^1.0.4", + "is-generator-function": "^1.0.7", + "is-typed-array": "^1.1.3", + "which-typed-array": "^1.1.2" } }, - "node_modules/cdk-assets/node_modules/@aws-cdk/cx-api/node_modules/lru-cache": { - "version": "6.0.0", + "node_modules/cdk-assets/node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true + }, + "node_modules/cdk-assets/node_modules/uuid": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.0.0.tgz#bc6ccf91b5ff0ac07bbcdbf1c7c4e150db4dbb6c", + "integrity": "sha512-jOXGuXZAWdsTH7eZLtyXMqUb9EcWMGZNbL9YcGBJl4MH4nrxHmZJhEHvyLFrkxo+28uLb/NYRcStH48fnD0Vzw==", + "dev": true + }, + "node_modules/cdk-assets/node_modules/which-typed-array": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.9.tgz#307cf898025848cf995e795e8423c7f337efbde6", + "integrity": "sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA==", "dev": true, - "inBundle": true, - "license": "ISC", "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0", + "is-typed-array": "^1.1.10" } }, - "node_modules/cdk-assets/node_modules/@aws-cdk/cx-api/node_modules/semver": { - "version": "7.3.8", + "node_modules/cdk-assets/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", "dev": true, - "inBundle": true, - "license": "ISC", "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" } }, - "node_modules/cdk-assets/node_modules/@aws-cdk/cx-api/node_modules/yallist": { - "version": "4.0.0", - "dev": true, - "inBundle": true, - "license": "ISC" + "node_modules/cdk-assets/node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true }, - "node_modules/cdk-assets/node_modules/cliui": { - "version": "7.0.4", + "node_modules/cdk-assets/node_modules/xml2js": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.5.0.tgz#d9440631fbb2ed800203fad106f2724f62c493b7", + "integrity": "sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA==", "dev": true, - "license": "ISC", "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" + "sax": ">=0.6.0", + "xmlbuilder": "~11.0.0" } }, - "node_modules/cdk-assets/node_modules/mime": { - "version": "2.6.0", - "dev": true, - "license": "MIT", - "bin": { - "mime": "cli.js" - }, - "engines": { - "node": ">=4.0.0" - } + "node_modules/cdk-assets/node_modules/xml2js/node_modules/sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", + "dev": true + }, + "node_modules/cdk-assets/node_modules/xmlbuilder": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz#be9bae1c8a046e76b31127726347d0ad7002beb3", + "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", + "dev": true + }, + "node_modules/cdk-assets/node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true + }, + "node_modules/cdk-assets/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true }, "node_modules/cdk-assets/node_modules/yargs": { "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", "dev": true, - "license": "MIT", "dependencies": { "cliui": "^7.0.2", "escalade": "^3.1.1", @@ -7118,17 +7813,23 @@ "string-width": "^4.2.0", "y18n": "^5.0.5", "yargs-parser": "^20.2.2" - }, - "engines": { - "node": ">=10" } }, "node_modules/cdk-assets/node_modules/yargs-parser": { "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "dev": true + }, + "node_modules/cdk-assets/node_modules/zip-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/zip-stream/-/zip-stream-4.1.0.tgz#51dd326571544e36aa3f756430b313576dc8fc79", + "integrity": "sha512-zshzwQW7gG7hjpBlgeQP9RuyPGNxvJdzR8SUM3QhxCnLjWN2E7j3dOvpeDcQoETfHx0urRS7EtmVToql7YpU4A==", "dev": true, - "license": "ISC", - "engines": { - "node": ">=10" + "dependencies": { + "archiver-utils": "^2.1.0", + "compress-commons": "^4.1.0", + "readable-stream": "^3.6.0" } }, "node_modules/cdk-sample": { @@ -7968,14 +8669,15 @@ } }, "node_modules/degenerator": { - "version": "3.0.2", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/degenerator/-/degenerator-3.0.4.tgz", + "integrity": "sha512-Z66uPeBfHZAHVmue3HPfyKu2Q0rC2cRxbTOsvmU/po5fvvcx27W4mIu9n0PUlQih4oUYvcG1BsbtVv8x7KDOSw==", "dev": true, - "license": "MIT", "dependencies": { "ast-types": "^0.13.2", "escodegen": "^1.8.1", "esprima": "^4.0.0", - "vm2": "^3.9.8" + "vm2": "^3.9.17" }, "engines": { "node": ">= 6" @@ -14480,16 +15182,17 @@ } }, "node_modules/optionator": { - "version": "0.9.1", + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", + "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", "dev": true, - "license": "MIT", "dependencies": { + "@aashutoshrathi/word-wrap": "^1.2.3", "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", "levn": "^0.4.1", "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.3" + "type-check": "^0.4.0" }, "engines": { "node": ">= 0.8.0" @@ -17593,9 +18296,10 @@ } }, "node_modules/vm2": { - "version": "3.9.18", - "resolved": "https://registry.npmjs.org/vm2/-/vm2-3.9.18.tgz", - "integrity": "sha512-iM7PchOElv6Uv6Q+0Hq7dcgDtWWT6SizYqVcvol+1WQc+E9HlgTCnPozbQNSP3yDV9oXHQOEQu530w2q/BCVZg==", + "version": "3.9.19", + "resolved": "https://registry.npmjs.org/vm2/-/vm2-3.9.19.tgz", + "integrity": "sha512-J637XF0DHDMV57R6JyVsTak7nIL8gy5KH4r1HiwWLf/4GBbb5MKL5y7LpmF4A8E2nR6XmzpmMFQ7V7ppPTmUQg==", + "deprecated": "The library contains critical security issues and should not be used for production! The maintenance of the project has been discontinued. Consider migrating your code to isolated-vm.", "dev": true, "dependencies": { "acorn": "^8.7.0", diff --git a/package.json b/package.json index 467365c53e..598ef8b6bd 100644 --- a/package.json +++ b/package.json @@ -72,7 +72,6 @@ "lint-staged": "^13.1.2", "prettier": "^2.8.8", "promptly": "^3.2.0", - "proxy-agent": "^5.0.0", "rimraf": "^5.0.1", "ts-jest": "^29.0.3", "ts-node": "^10.9.1", From d445d3f75827eeb7de04483a5c35832d03de080b Mon Sep 17 00:00:00 2001 From: Alexander Schueren Date: Fri, 14 Jul 2023 21:33:04 +0200 Subject: [PATCH 04/11] clean up package-lock.json (#1613) --- package-lock.json | 393 ---------------------------------------------- 1 file changed, 393 deletions(-) diff --git a/package-lock.json b/package-lock.json index 6d7e8a340d..824e10e2ba 100644 --- a/package-lock.json +++ b/package-lock.json @@ -49,7 +49,6 @@ "lint-staged": "^13.1.2", "prettier": "^2.8.8", "promptly": "^3.2.0", - "proxy-agent": "^5.0.0", "rimraf": "^5.0.1", "ts-jest": "^29.0.3", "ts-node": "^10.9.1", @@ -5140,14 +5139,6 @@ "node": ">=14.0.0" } }, - "node_modules/@tootallnate/once": { - "version": "1.1.2", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 6" - } - }, "node_modules/@tsconfig/node10": { "version": "1.0.9", "dev": true, @@ -5985,17 +5976,6 @@ "node": ">=0.10.0" } }, - "node_modules/ast-types": { - "version": "0.13.4", - "dev": true, - "license": "MIT", - "dependencies": { - "tslib": "^2.0.1" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/astral-regex": { "version": "2.0.0", "dev": true, @@ -6808,14 +6788,6 @@ "node": ">=10" } }, - "node_modules/bytes": { - "version": "3.1.2", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, "node_modules/cacache": { "version": "17.1.3", "resolved": "https://registry.npmjs.org/cacache/-/cacache-17.1.3.tgz", @@ -8549,14 +8521,6 @@ "node": ">=8" } }, - "node_modules/data-uri-to-buffer": { - "version": "3.0.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 6" - } - }, "node_modules/dateformat": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-3.0.3.tgz", @@ -8668,21 +8632,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/degenerator": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/degenerator/-/degenerator-3.0.4.tgz", - "integrity": "sha512-Z66uPeBfHZAHVmue3HPfyKu2Q0rC2cRxbTOsvmU/po5fvvcx27W4mIu9n0PUlQih4oUYvcG1BsbtVv8x7KDOSw==", - "dev": true, - "dependencies": { - "ast-types": "^0.13.2", - "escodegen": "^1.8.1", - "esprima": "^4.0.0", - "vm2": "^3.9.17" - }, - "engines": { - "node": ">= 6" - } - }, "node_modules/del": { "version": "6.1.1", "resolved": "https://registry.npmjs.org/del/-/del-6.1.1.tgz", @@ -9423,73 +9372,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/escodegen": { - "version": "1.14.3", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "esprima": "^4.0.1", - "estraverse": "^4.2.0", - "esutils": "^2.0.2", - "optionator": "^0.8.1" - }, - "bin": { - "escodegen": "bin/escodegen.js", - "esgenerate": "bin/esgenerate.js" - }, - "engines": { - "node": ">=4.0" - }, - "optionalDependencies": { - "source-map": "~0.6.1" - } - }, - "node_modules/escodegen/node_modules/levn": { - "version": "0.3.0", - "dev": true, - "license": "MIT", - "dependencies": { - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/escodegen/node_modules/optionator": { - "version": "0.8.3", - "dev": true, - "license": "MIT", - "dependencies": { - "deep-is": "~0.1.3", - "fast-levenshtein": "~2.0.6", - "levn": "~0.3.0", - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2", - "word-wrap": "~1.2.3" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/escodegen/node_modules/prelude-ls": { - "version": "1.1.2", - "dev": true, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/escodegen/node_modules/type-check": { - "version": "0.3.2", - "dev": true, - "license": "MIT", - "dependencies": { - "prelude-ls": "~1.1.2" - }, - "engines": { - "node": ">= 0.8.0" - } - }, "node_modules/eslint": { "version": "8.30.0", "dev": true, @@ -10103,14 +9985,6 @@ "node": "^10.12.0 || >=12.0.0" } }, - "node_modules/file-uri-to-path": { - "version": "2.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 6" - } - }, "node_modules/file-url": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/file-url/-/file-url-3.0.0.tgz", @@ -10317,38 +10191,6 @@ "dev": true, "license": "ISC" }, - "node_modules/ftp": { - "version": "0.3.10", - "dev": true, - "dependencies": { - "readable-stream": "1.1.x", - "xregexp": "2.0.0" - }, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/ftp/node_modules/isarray": { - "version": "0.0.1", - "dev": true, - "license": "MIT" - }, - "node_modules/ftp/node_modules/readable-stream": { - "version": "1.1.14", - "dev": true, - "license": "MIT", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" - } - }, - "node_modules/ftp/node_modules/string_decoder": { - "version": "0.10.31", - "dev": true, - "license": "MIT" - }, "node_modules/function-bind": { "version": "1.1.1", "dev": true, @@ -10592,51 +10434,6 @@ "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" } }, - "node_modules/get-uri": { - "version": "3.0.2", - "dev": true, - "license": "MIT", - "dependencies": { - "@tootallnate/once": "1", - "data-uri-to-buffer": "3", - "debug": "4", - "file-uri-to-path": "2", - "fs-extra": "^8.1.0", - "ftp": "^0.3.10" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/get-uri/node_modules/fs-extra": { - "version": "8.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" - }, - "engines": { - "node": ">=6 <7 || >=8" - } - }, - "node_modules/get-uri/node_modules/jsonfile": { - "version": "4.0.0", - "dev": true, - "license": "MIT", - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/get-uri/node_modules/universalify": { - "version": "0.1.2", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 4.0.0" - } - }, "node_modules/git-raw-commits": { "version": "2.0.11", "resolved": "https://registry.npmjs.org/git-raw-commits/-/git-raw-commits-2.0.11.tgz", @@ -10958,34 +10755,6 @@ "dev": true, "license": "BSD-2-Clause" }, - "node_modules/http-errors": { - "version": "2.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "depd": "2.0.0", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "toidentifier": "1.0.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/http-proxy-agent": { - "version": "4.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "@tootallnate/once": "1", - "agent-base": "6", - "debug": "4" - }, - "engines": { - "node": ">= 6" - } - }, "node_modules/https-proxy-agent": { "version": "5.0.1", "dev": true, @@ -11259,11 +11028,6 @@ "node": ">= 0.4" } }, - "node_modules/ip": { - "version": "1.1.8", - "dev": true, - "license": "MIT" - }, "node_modules/is-arguments": { "version": "1.1.1", "dev": true, @@ -14213,14 +13977,6 @@ "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", "dev": true }, - "node_modules/netmask": { - "version": "2.0.2", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4.0" - } - }, "node_modules/nise": { "version": "5.1.4", "dev": true, @@ -15359,38 +15115,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/pac-proxy-agent": { - "version": "5.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@tootallnate/once": "1", - "agent-base": "6", - "debug": "4", - "get-uri": "3", - "http-proxy-agent": "^4.0.1", - "https-proxy-agent": "5", - "pac-resolver": "^5.0.0", - "raw-body": "^2.2.0", - "socks-proxy-agent": "5" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/pac-resolver": { - "version": "5.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "degenerator": "^3.0.2", - "ip": "^1.1.5", - "netmask": "^2.0.2" - }, - "engines": { - "node": ">= 8" - } - }, "node_modules/pacote": { "version": "15.1.1", "resolved": "https://registry.npmjs.org/pacote/-/pacote-15.1.1.tgz", @@ -16046,37 +15770,6 @@ "integrity": "sha512-/XJ368cyBJ7fzLMwLKv1e4vLxOju2MNAIokcr7meSaNcVbWz/CPcW22cP04mwxOErdA5mwjA8Q6w/cdAQxVn7Q==", "dev": true }, - "node_modules/proxy-agent": { - "version": "5.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "agent-base": "^6.0.0", - "debug": "4", - "http-proxy-agent": "^4.0.0", - "https-proxy-agent": "^5.0.0", - "lru-cache": "^5.1.1", - "pac-proxy-agent": "^5.0.0", - "proxy-from-env": "^1.0.0", - "socks-proxy-agent": "^5.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/proxy-agent/node_modules/lru-cache": { - "version": "5.1.1", - "dev": true, - "license": "ISC", - "dependencies": { - "yallist": "^3.0.2" - } - }, - "node_modules/proxy-agent/node_modules/yallist": { - "version": "3.1.1", - "dev": true, - "license": "ISC" - }, "node_modules/proxy-from-env": { "version": "1.1.0", "dev": true, @@ -16134,20 +15827,6 @@ "node": ">=8" } }, - "node_modules/raw-body": { - "version": "2.5.1", - "dev": true, - "license": "MIT", - "dependencies": { - "bytes": "3.1.2", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, "node_modules/react-is": { "version": "18.2.0", "dev": true, @@ -16824,11 +16503,6 @@ "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", "dev": true }, - "node_modules/setprototypeof": { - "version": "1.2.0", - "dev": true, - "license": "ISC" - }, "node_modules/shallow-clone": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", @@ -17089,19 +16763,6 @@ "npm": ">= 3.0.0" } }, - "node_modules/socks-proxy-agent": { - "version": "5.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "agent-base": "^6.0.2", - "debug": "4", - "socks": "^2.3.3" - }, - "engines": { - "node": ">= 6" - } - }, "node_modules/socks/node_modules/ip": { "version": "2.0.0", "dev": true, @@ -17238,14 +16899,6 @@ "node": ">=8" } }, - "node_modules/statuses": { - "version": "2.0.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, "node_modules/string_decoder": { "version": "1.3.0", "dev": true, @@ -17676,14 +17329,6 @@ "node": ">=8.0" } }, - "node_modules/toidentifier": { - "version": "1.0.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.6" - } - }, "node_modules/tr46": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", @@ -18155,14 +17800,6 @@ "node": ">= 10.0.0" } }, - "node_modules/unpipe": { - "version": "1.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, "node_modules/upath": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/upath/-/upath-2.0.1.tgz", @@ -18295,23 +17932,6 @@ "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "node_modules/vm2": { - "version": "3.9.19", - "resolved": "https://registry.npmjs.org/vm2/-/vm2-3.9.19.tgz", - "integrity": "sha512-J637XF0DHDMV57R6JyVsTak7nIL8gy5KH4r1HiwWLf/4GBbb5MKL5y7LpmF4A8E2nR6XmzpmMFQ7V7ppPTmUQg==", - "deprecated": "The library contains critical security issues and should not be used for production! The maintenance of the project has been discontinued. Consider migrating your code to isolated-vm.", - "dev": true, - "dependencies": { - "acorn": "^8.7.0", - "acorn-walk": "^8.2.0" - }, - "bin": { - "vm2": "bin/vm2" - }, - "engines": { - "node": ">=6.0" - } - }, "node_modules/vscode-oniguruma": { "version": "1.7.0", "resolved": "https://registry.npmjs.org/vscode-oniguruma/-/vscode-oniguruma-1.7.0.tgz", @@ -18419,14 +18039,6 @@ "string-width": "^1.0.2 || 2 || 3 || 4" } }, - "node_modules/word-wrap": { - "version": "1.2.3", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/wordwrap": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", @@ -18586,11 +18198,6 @@ "node": ">=4.0" } }, - "node_modules/xregexp": { - "version": "2.0.0", - "dev": true, - "license": "MIT" - }, "node_modules/xtend": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", From a57dc113a875ea098b659cdf5f90c34010664097 Mon Sep 17 00:00:00 2001 From: Andrea Amorosi Date: Sat, 15 Jul 2023 03:11:13 +0200 Subject: [PATCH 05/11] chore(ci): restore dependencies & fix e2e tests (#1615) --- package-lock.json | 1343 +++++++++++++++++---------------------------- package.json | 1 + 2 files changed, 517 insertions(+), 827 deletions(-) diff --git a/package-lock.json b/package-lock.json index 824e10e2ba..d9d180d8ae 100644 --- a/package-lock.json +++ b/package-lock.json @@ -49,6 +49,7 @@ "lint-staged": "^13.1.2", "prettier": "^2.8.8", "promptly": "^3.2.0", + "proxy-agent": "^5.0.0", "rimraf": "^5.0.1", "ts-jest": "^29.0.3", "ts-node": "^10.9.1", @@ -386,15 +387,6 @@ "source-map": "^0.6.0" } }, - "node_modules/@aashutoshrathi/word-wrap": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", - "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/@ampproject/remapping": { "version": "2.2.0", "dev": true, @@ -431,17 +423,16 @@ } }, "node_modules/@aws-cdk/cloud-assembly-schema": { - "version": "2.87.0", - "resolved": "https://registry.npmjs.org/@aws-cdk/cloud-assembly-schema/-/cloud-assembly-schema-2.87.0.tgz", - "integrity": "sha512-uXbereQy1bjhQAh2rbMkfG0uyaheCQCfkT+EzCr9NdeSGt9fSXjBg2O8E/SqA/RPmEH+YsgkVLVtlPc/i5wdUg==", + "version": "2.73.0", "bundleDependencies": [ "jsonschema", "semver" ], "dev": true, + "license": "Apache-2.0", "dependencies": { "jsonschema": "^1.4.1", - "semver": "^7.5.1" + "semver": "^7.3.8" }, "engines": { "node": ">= 14.15.0" @@ -469,7 +460,7 @@ } }, "node_modules/@aws-cdk/cloud-assembly-schema/node_modules/semver": { - "version": "7.5.2", + "version": "7.3.8", "dev": true, "inBundle": true, "license": "ISC", @@ -506,22 +497,21 @@ } }, "node_modules/@aws-cdk/cx-api": { - "version": "2.87.0", - "resolved": "https://registry.npmjs.org/@aws-cdk/cx-api/-/cx-api-2.87.0.tgz", - "integrity": "sha512-8KTgc1mL77/Ej2jKebjJUzSCH8DVV35i/kXDm9p8MCpxZpS2qN7tTDy8Y3ppubLkBMpG4HD4Tmlddy5ThS9ZWQ==", + "version": "2.73.0", "bundleDependencies": [ "semver" ], "dev": true, + "license": "Apache-2.0", "dependencies": { - "@aws-cdk/cloud-assembly-schema": "2.87.0", - "semver": "^7.5.1" + "@aws-cdk/cloud-assembly-schema": "2.73.0", + "semver": "^7.3.8" }, "engines": { "node": ">= 14.15.0" }, "peerDependencies": { - "@aws-cdk/cloud-assembly-schema": "2.87.0" + "@aws-cdk/cloud-assembly-schema": "2.73.0" } }, "node_modules/@aws-cdk/cx-api/node_modules/lru-cache": { @@ -537,7 +527,7 @@ } }, "node_modules/@aws-cdk/cx-api/node_modules/semver": { - "version": "7.5.2", + "version": "7.3.8", "dev": true, "inBundle": true, "license": "ISC", @@ -5139,6 +5129,14 @@ "node": ">=14.0.0" } }, + "node_modules/@tootallnate/once": { + "version": "1.1.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, "node_modules/@tsconfig/node10": { "version": "1.0.9", "dev": true, @@ -5976,6 +5974,17 @@ "node": ">=0.10.0" } }, + "node_modules/ast-types": { + "version": "0.13.4", + "dev": true, + "license": "MIT", + "dependencies": { + "tslib": "^2.0.1" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/astral-regex": { "version": "2.0.0", "dev": true, @@ -6042,9 +6051,9 @@ } }, "node_modules/aws-cdk-lib": { - "version": "2.87.0", - "resolved": "https://registry.npmjs.org/aws-cdk-lib/-/aws-cdk-lib-2.87.0.tgz", - "integrity": "sha512-9kirXX7L7OP/yGmCbaYlkt5OAtowGiGw0AYFIQvSwvx/UU3aJO5XuDwAgDsvToDkRpBi0yX0bNwqa0DItu+C6A==", + "version": "2.80.0", + "resolved": "https://registry.npmjs.org/aws-cdk-lib/-/aws-cdk-lib-2.80.0.tgz", + "integrity": "sha512-PoqD3Yms5I0ajuTi071nTW/hpkH3XsdyZzn5gYsPv0qD7mqP3h6Qr+6RiGx+yQ1KcVFyxWdX15uK+DsC0KwvcQ==", "bundleDependencies": [ "@balena/dockerignore", "case", @@ -6284,7 +6293,7 @@ } }, "node_modules/aws-cdk-lib/node_modules/semver": { - "version": "7.5.2", + "version": "7.5.1", "inBundle": true, "license": "ISC", "dependencies": { @@ -6788,6 +6797,14 @@ "node": ">=10" } }, + "node_modules/bytes": { + "version": "3.1.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/cacache": { "version": "17.1.3", "resolved": "https://registry.npmjs.org/cacache/-/cacache-17.1.3.tgz", @@ -6939,16 +6956,14 @@ "license": "CC-BY-4.0" }, "node_modules/cdk-assets": { - "version": "2.87.0", - "resolved": "https://registry.npmjs.org/cdk-assets/-/cdk-assets-2.87.0.tgz", - "integrity": "sha512-/OniPxjVxMCip24Pb/3B876FTJoFhIUgWXWxG/PfM3TlLYBTb4DyMgLaTHI4hnco0fJPGHZMGwIFjmch818PMg==", + "version": "2.72.1", "dev": true, - "hasShrinkwrap": true, + "license": "Apache-2.0", "dependencies": { - "@aws-cdk/cloud-assembly-schema": "2.87.0", - "@aws-cdk/cx-api": "2.87.0", + "@aws-cdk/cloud-assembly-schema": "2.72.1", + "@aws-cdk/cx-api": "2.72.1", "archiver": "^5.3.1", - "aws-sdk": "^2.1379.0", + "aws-sdk": "^2.1329.0", "glob": "^7.2.3", "mime": "^2.6.0", "yargs": "^16.2.0" @@ -6962,846 +6977,158 @@ } }, "node_modules/cdk-assets/node_modules/@aws-cdk/cloud-assembly-schema": { - "version": "2.87.0", + "version": "2.72.1", + "bundleDependencies": [ + "jsonschema", + "semver" + ], "dev": true, + "license": "Apache-2.0", "dependencies": { "jsonschema": "^1.4.1", - "semver": "^7.5.1" - } - }, - "node_modules/cdk-assets/node_modules/@aws-cdk/cx-api": { - "version": "2.87.0", - "dev": true, - "dependencies": { - "@aws-cdk/cloud-assembly-schema": "2.87.0", - "semver": "^7.5.1" - } - }, - "node_modules/cdk-assets/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true - }, - "node_modules/cdk-assets/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - } - }, - "node_modules/cdk-assets/node_modules/archiver": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/archiver/-/archiver-5.3.1.tgz#21e92811d6f09ecfce649fbefefe8c79e57cbbb6", - "integrity": "sha512-8KyabkmbYrH+9ibcTScQ1xCJC/CGcugdVIwB+53f5sZziXgwUh3iXlAlANMxcZyDEfTHMe6+Z5FofV8nopXP7w==", - "dev": true, - "dependencies": { - "archiver-utils": "^2.1.0", - "async": "^3.2.3", - "buffer-crc32": "^0.2.1", - "readable-stream": "^3.6.0", - "readdir-glob": "^1.0.0", - "tar-stream": "^2.2.0", - "zip-stream": "^4.1.0" + "semver": "^7.3.8" + }, + "engines": { + "node": ">= 14.15.0" } }, - "node_modules/cdk-assets/node_modules/archiver-utils": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/archiver-utils/-/archiver-utils-2.1.0.tgz#e8a460e94b693c3e3da182a098ca6285ba9249e2", - "integrity": "sha512-bEL/yUb/fNNiNTuUz979Z0Yg5L+LzLxGJz8x79lYmR54fmTIb6ob/hNQgkQnIUDWIFjZVQwl9Xs356I6BAMHfw==", + "node_modules/cdk-assets/node_modules/@aws-cdk/cloud-assembly-schema/node_modules/jsonschema": { + "version": "1.4.1", "dev": true, - "dependencies": { - "glob": "^7.1.4", - "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": "^2.0.0" + "inBundle": true, + "license": "MIT", + "engines": { + "node": "*" } }, - "node_modules/cdk-assets/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#91125e8042bba1b9887f49345f6277027ce8be9b", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "node_modules/cdk-assets/node_modules/@aws-cdk/cloud-assembly-schema/node_modules/lru-cache": { + "version": "6.0.0", "dev": true, + "inBundle": true, + "license": "ISC", "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" } }, - "node_modules/cdk-assets/node_modules/async": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/async/-/async-3.2.4.tgz#2d22e00f8cddeb5fde5dd33522b56d1cf569a81c", - "integrity": "sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==", - "dev": true - }, - "node_modules/cdk-assets/node_modules/available-typed-arrays": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz#92f95616501069d07d10edb2fc37d3e1c65123b7", - "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", - "dev": true - }, - "node_modules/cdk-assets/node_modules/aws-sdk": { - "version": "2.1401.0", - "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1401.0.tgz#c283de69b9beb76a39243d1331c63c21f0ff5a0e", - "integrity": "sha512-qzuMxIvCmH1Df194sYn+L5yDrChIKzZG/fBLElPVSN1fB18qhPSYUfr9uVCMeTpDCmdTW1Ojk7cAkByzzAnKjA==", + "node_modules/cdk-assets/node_modules/@aws-cdk/cloud-assembly-schema/node_modules/semver": { + "version": "7.3.8", "dev": true, + "inBundle": true, + "license": "ISC", "dependencies": { - "buffer": "4.9.2", - "events": "1.1.1", - "ieee754": "1.1.13", - "jmespath": "0.16.0", - "querystring": "0.2.0", - "sax": "1.2.1", - "url": "0.10.3", - "util": "^0.12.4", - "uuid": "8.0.0", - "xml2js": "0.5.0" + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" } }, - "node_modules/cdk-assets/node_modules/aws-sdk/node_modules/buffer": { - "version": "4.9.2", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz#230ead344002988644841ab0244af8c44bbe3ef8", - "integrity": "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==", + "node_modules/cdk-assets/node_modules/@aws-cdk/cloud-assembly-schema/node_modules/yallist": { + "version": "4.0.0", "dev": true, - "dependencies": { - "base64-js": "^1.0.2", - "ieee754": "^1.1.4", - "isarray": "^1.0.0" - } - }, - "node_modules/cdk-assets/node_modules/aws-sdk/node_modules/buffer/node_modules/ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "dev": true - }, - "node_modules/cdk-assets/node_modules/aws-sdk/node_modules/ieee754": { - "version": "1.1.13", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz#ec168558e95aa181fd87d37f55c32bbcb6708b84", - "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==", - "dev": true - }, - "node_modules/cdk-assets/node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true - }, - "node_modules/cdk-assets/node_modules/base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "dev": true + "inBundle": true, + "license": "ISC" }, - "node_modules/cdk-assets/node_modules/bl": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz#451535264182bec2fbbc83a62ab98cf11d9f7b3a", - "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "node_modules/cdk-assets/node_modules/@aws-cdk/cx-api": { + "version": "2.72.1", + "bundleDependencies": [ + "semver" + ], "dev": true, + "license": "Apache-2.0", "dependencies": { - "buffer": "^5.5.0", - "inherits": "^2.0.4", - "readable-stream": "^3.4.0" + "@aws-cdk/cloud-assembly-schema": "2.72.1", + "semver": "^7.3.8" + }, + "engines": { + "node": ">= 14.15.0" + }, + "peerDependencies": { + "@aws-cdk/cloud-assembly-schema": "2.72.1" } }, - "node_modules/cdk-assets/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "node_modules/cdk-assets/node_modules/@aws-cdk/cx-api/node_modules/lru-cache": { + "version": "6.0.0", "dev": true, + "inBundle": true, + "license": "ISC", "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" } }, - "node_modules/cdk-assets/node_modules/buffer": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0", - "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "node_modules/cdk-assets/node_modules/@aws-cdk/cx-api/node_modules/semver": { + "version": "7.3.8", "dev": true, + "inBundle": true, + "license": "ISC", "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.1.13" + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" } }, - "node_modules/cdk-assets/node_modules/buffer-crc32": { - "version": "0.2.13", - "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242", - "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", - "dev": true - }, - "node_modules/cdk-assets/node_modules/call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "node_modules/cdk-assets/node_modules/@aws-cdk/cx-api/node_modules/yallist": { + "version": "4.0.0", "dev": true, - "dependencies": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" - } + "inBundle": true, + "license": "ISC" }, "node_modules/cdk-assets/node_modules/cliui": { "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", "dev": true, + "license": "ISC", "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.0", "wrap-ansi": "^7.0.0" } }, - "node_modules/cdk-assets/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - } - }, - "node_modules/cdk-assets/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/cdk-assets/node_modules/compress-commons": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/compress-commons/-/compress-commons-4.1.1.tgz#df2a09a7ed17447642bad10a85cc9a19e5c42a7d", - "integrity": "sha512-QLdDLCKNV2dtoTorqgxngQCMA+gWXkM/Nwu7FpeBhk/RdkzimqC3jueb/FDmaZeXh+uby1jkBqE3xArsLBE5wQ==", - "dev": true, - "dependencies": { - "buffer-crc32": "^0.2.13", - "crc32-stream": "^4.0.2", - "normalize-path": "^3.0.0", - "readable-stream": "^3.6.0" - } - }, - "node_modules/cdk-assets/node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true - }, - "node_modules/cdk-assets/node_modules/core-util-is": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85", - "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", - "dev": true - }, - "node_modules/cdk-assets/node_modules/crc-32": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz#3cad35a934b8bf71f25ca524b6da51fb7eace2ff", - "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==", - "dev": true - }, - "node_modules/cdk-assets/node_modules/crc32-stream": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/crc32-stream/-/crc32-stream-4.0.2.tgz#c922ad22b38395abe9d3870f02fa8134ed709007", - "integrity": "sha512-DxFZ/Hk473b/muq1VJ///PMNLj0ZMnzye9thBpmjpJKCc5eMgB95aK8zCGrGfQ90cWo561Te6HK9D+j4KPdM6w==", + "node_modules/cdk-assets/node_modules/mime": { + "version": "2.6.0", "dev": true, - "dependencies": { - "crc-32": "^1.2.0", - "readable-stream": "^3.4.0" + "license": "MIT", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4.0.0" } }, - "node_modules/cdk-assets/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "node_modules/cdk-assets/node_modules/end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "node_modules/cdk-assets/node_modules/yargs": { + "version": "16.2.0", "dev": true, + "license": "MIT", "dependencies": { - "once": "^1.4.0" - } - }, - "node_modules/cdk-assets/node_modules/escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", - "dev": true - }, - "node_modules/cdk-assets/node_modules/events": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz#9ebdb7635ad099c70dcc4c2a1f5004288e8bd924", - "integrity": "sha512-kEcvvCBByWXGnZy6JUlgAp2gBIUjfCAV6P6TgT1/aaQKcmuAEC4OZTV1I4EWQLz2gxZw76atuVyvHhTxvi0Flw==", - "dev": true - }, - "node_modules/cdk-assets/node_modules/for-each": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz#69b447e88a0a5d32c3e7084f3f1710034b21376e", - "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", - "dev": true, - "dependencies": { - "is-callable": "^1.1.3" - } - }, - "node_modules/cdk-assets/node_modules/fs-constants": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz#6be0de9be998ce16af8afc24497b9ee9b7ccd9ad", - "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", - "dev": true - }, - "node_modules/cdk-assets/node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true - }, - "node_modules/cdk-assets/node_modules/function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true - }, - "node_modules/cdk-assets/node_modules/get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true - }, - "node_modules/cdk-assets/node_modules/get-intrinsic": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.1.tgz#d295644fed4505fc9cde952c37ee12b477a83d82", - "integrity": "sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3" - } - }, - "node_modules/cdk-assets/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "node_modules/cdk-assets/node_modules/gopd": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz#29ff76de69dac7489b7c0918a5788e56477c332c", - "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", - "dev": true, - "dependencies": { - "get-intrinsic": "^1.1.3" - } - }, - "node_modules/cdk-assets/node_modules/graceful-fs": { - "version": "4.2.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "dev": true - }, - "node_modules/cdk-assets/node_modules/has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.1" - } - }, - "node_modules/cdk-assets/node_modules/has-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz#1885c1305538958aff469fef37937c22795408e0", - "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", - "dev": true - }, - "node_modules/cdk-assets/node_modules/has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", - "dev": true - }, - "node_modules/cdk-assets/node_modules/has-tostringtag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz#7e133818a7d394734f941e73c3d3f9291e658b25", - "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", - "dev": true, - "dependencies": { - "has-symbols": "^1.0.2" - } - }, - "node_modules/cdk-assets/node_modules/ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "dev": true - }, - "node_modules/cdk-assets/node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "dev": true, - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/cdk-assets/node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true - }, - "node_modules/cdk-assets/node_modules/is-arguments": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz#15b3f88fda01f2a97fec84ca761a560f123efa9b", - "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - } - }, - "node_modules/cdk-assets/node_modules/is-callable": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz#3bc2a85ea742d9e36205dcacdd72ca1fdc51b055", - "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", - "dev": true - }, - "node_modules/cdk-assets/node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true - }, - "node_modules/cdk-assets/node_modules/is-generator-function": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz#f1558baf1ac17e0deea7c0415c438351ff2b3c72", - "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==", - "dev": true, - "dependencies": { - "has-tostringtag": "^1.0.0" - } - }, - "node_modules/cdk-assets/node_modules/is-typed-array": { - "version": "1.1.10", - "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.10.tgz#36a5b5cb4189b575d1a3e4b08536bfb485801e3f", - "integrity": "sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A==", - "dev": true, - "dependencies": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-tostringtag": "^1.0.0" - } - }, - "node_modules/cdk-assets/node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "dev": true - }, - "node_modules/cdk-assets/node_modules/jmespath": { - "version": "0.16.0", - "resolved": "https://registry.npmjs.org/jmespath/-/jmespath-0.16.0.tgz#b15b0a85dfd4d930d43e69ed605943c802785076", - "integrity": "sha512-9FzQjJ7MATs1tSpnco1K6ayiYE3figslrXA72G2HQ/n76RzvYlofyi5QM+iX4YRs/pu3yzxlVQSST23+dMDknw==", - "dev": true - }, - "node_modules/cdk-assets/node_modules/jsonschema": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/jsonschema/-/jsonschema-1.4.1.tgz#cc4c3f0077fb4542982973d8a083b6b34f482dab", - "integrity": "sha512-S6cATIPVv1z0IlxdN+zUk5EPjkGCdnhN4wVSBlvoUO1tOLJootbo9CquNJmbIh4yikWHiUedhRYrNPn1arpEmQ==", - "dev": true - }, - "node_modules/cdk-assets/node_modules/lazystream": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.1.tgz#494c831062f1f9408251ec44db1cba29242a2638", - "integrity": "sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==", - "dev": true, - "dependencies": { - "readable-stream": "^2.0.5" - } - }, - "node_modules/cdk-assets/node_modules/lazystream/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz#91125e8042bba1b9887f49345f6277027ce8be9b", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "dev": true, - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/cdk-assets/node_modules/lodash.defaults": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz#d09178716ffea4dde9e5fb7b37f6f0802274580c", - "integrity": "sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==", - "dev": true - }, - "node_modules/cdk-assets/node_modules/lodash.difference": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.difference/-/lodash.difference-4.5.0.tgz#9ccb4e505d486b91651345772885a2df27fd017c", - "integrity": "sha512-dS2j+W26TQ7taQBGN8Lbbq04ssV3emRw4NY58WErlTO29pIqS0HmoT5aJ9+TUQ1N3G+JOZSji4eugsWwGp9yPA==", - "dev": true - }, - "node_modules/cdk-assets/node_modules/lodash.flatten": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz#f31c22225a9632d2bbf8e4addbef240aa765a61f", - "integrity": "sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g==", - "dev": true - }, - "node_modules/cdk-assets/node_modules/lodash.isplainobject": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb", - "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", - "dev": true - }, - "node_modules/cdk-assets/node_modules/lodash.union": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/lodash.union/-/lodash.union-4.6.0.tgz#48bb5088409f16f1821666641c44dd1aaae3cd88", - "integrity": "sha512-c4pB2CdGrGdjMKYLA+XiRDO7Y0PRQbm/Gzg8qMj+QH+pFVAoTp5sBpO0odL3FjoPCGjK96p6qsP+yQoiLoOBcw==", - "dev": true - }, - "node_modules/cdk-assets/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - } - }, - "node_modules/cdk-assets/node_modules/mime": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz#a2a682a95cd4d0cb1d6257e28f83da7e35800367", - "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", - "dev": true - }, - "node_modules/cdk-assets/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - } - }, - "node_modules/cdk-assets/node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true - }, - "node_modules/cdk-assets/node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dev": true, - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/cdk-assets/node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "dev": true - }, - "node_modules/cdk-assets/node_modules/process-nextick-args": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", - "dev": true - }, - "node_modules/cdk-assets/node_modules/punycode": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d", - "integrity": "sha512-RofWgt/7fL5wP1Y7fxE7/EmTLzQVnB0ycyibJ0OOHIlJqTNzglYFxVwETOcIoJqJmpDXJ9xImDv+Fq34F/d4Dw==", - "dev": true - }, - "node_modules/cdk-assets/node_modules/querystring": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620", - "integrity": "sha512-X/xY82scca2tau62i9mDyU9K+I+djTMUsvwf7xnUX5GLvVzgJybOJf4Y6o9Zx3oJK/LSXg5tTZBjwzqVPaPO2g==", - "dev": true - }, - "node_modules/cdk-assets/node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz#56a9b36ea965c00c5a93ef31eb111a0f11056967", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "dev": true, - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - }, - "node_modules/cdk-assets/node_modules/readable-stream/node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true - }, - "node_modules/cdk-assets/node_modules/readable-stream/node_modules/string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "dev": true, - "dependencies": { - "safe-buffer": "~5.2.0" - } - }, - "node_modules/cdk-assets/node_modules/readdir-glob": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/readdir-glob/-/readdir-glob-1.1.3.tgz#c3d831f51f5e7bfa62fa2ffbe4b508c640f09584", - "integrity": "sha512-v05I2k7xN8zXvPD9N+z/uhXPaj0sUFCe2rcWZIpBsqxfP7xXFQ0tipAd/wjj1YxWyWtUS5IDJpOG82JKt2EAVA==", - "dev": true, - "dependencies": { - "minimatch": "^5.1.0" - } - }, - "node_modules/cdk-assets/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#1edc459e0f0c548486ecf9fc99f2221364b9a0ae", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/cdk-assets/node_modules/readdir-glob/node_modules/minimatch": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz#1cfcb8cf5522ea69952cd2af95ae09477f122a96", - "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", - "dev": true, - "dependencies": { - "brace-expansion": "^2.0.1" - } - }, - "node_modules/cdk-assets/node_modules/require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", - "dev": true - }, - "node_modules/cdk-assets/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true - }, - "node_modules/cdk-assets/node_modules/sax": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.1.tgz#7b8e656190b228e81a66aea748480d828cd2d37a", - "integrity": "sha512-8I2a3LovHTOpm7NV5yOyO8IHqgVsfK4+UuySrXU8YXkSRX7k6hCV9b3HrkKCr3nMpgj+0bmocaJJWpvp1oc7ZA==", - "dev": true - }, - "node_modules/cdk-assets/node_modules/semver": { - "version": "7.5.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.2.tgz#5b851e66d1be07c1cdaf37dfc856f543325a2beb", - "integrity": "sha512-SoftuTROv/cRjCze/scjGyiDtcUyxw1rgYQSZY7XTmtR5hX+dm76iDbTH8TkLPHCQmlbQVSSbNZCPM2hb0knnQ==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - } - }, - "node_modules/cdk-assets/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, - "node_modules/cdk-assets/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - } - }, - "node_modules/cdk-assets/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.1" - } - }, - "node_modules/cdk-assets/node_modules/tar-stream": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz#acad84c284136b060dc3faa64474aa9aebd77287", - "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", - "dev": true, - "dependencies": { - "bl": "^4.0.3", - "end-of-stream": "^1.4.1", - "fs-constants": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^3.1.1" - } - }, - "node_modules/cdk-assets/node_modules/url": { - "version": "0.10.3", - "resolved": "https://registry.npmjs.org/url/-/url-0.10.3.tgz#021e4d9c7705f21bbf37d03ceb58767402774c64", - "integrity": "sha512-hzSUW2q06EqL1gKM/a+obYHLIO6ct2hwPuviqTTOcfFVc61UbfJ2Q32+uGL/HCPxKqrdGB5QUwIe7UqlDgwsOQ==", - "dev": true, - "dependencies": { - "punycode": "1.3.2", - "querystring": "0.2.0" - } - }, - "node_modules/cdk-assets/node_modules/util": { - "version": "0.12.5", - "resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz#5f17a6059b73db61a875668781a1c2b136bd6fbc", - "integrity": "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==", - "dev": true, - "dependencies": { - "inherits": "^2.0.3", - "is-arguments": "^1.0.4", - "is-generator-function": "^1.0.7", - "is-typed-array": "^1.1.3", - "which-typed-array": "^1.1.2" - } - }, - "node_modules/cdk-assets/node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "dev": true - }, - "node_modules/cdk-assets/node_modules/uuid": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.0.0.tgz#bc6ccf91b5ff0ac07bbcdbf1c7c4e150db4dbb6c", - "integrity": "sha512-jOXGuXZAWdsTH7eZLtyXMqUb9EcWMGZNbL9YcGBJl4MH4nrxHmZJhEHvyLFrkxo+28uLb/NYRcStH48fnD0Vzw==", - "dev": true - }, - "node_modules/cdk-assets/node_modules/which-typed-array": { - "version": "1.1.9", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.9.tgz#307cf898025848cf995e795e8423c7f337efbde6", - "integrity": "sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA==", - "dev": true, - "dependencies": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-tostringtag": "^1.0.0", - "is-typed-array": "^1.1.10" - } - }, - "node_modules/cdk-assets/node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - } - }, - "node_modules/cdk-assets/node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true - }, - "node_modules/cdk-assets/node_modules/xml2js": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.5.0.tgz#d9440631fbb2ed800203fad106f2724f62c493b7", - "integrity": "sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA==", - "dev": true, - "dependencies": { - "sax": ">=0.6.0", - "xmlbuilder": "~11.0.0" - } - }, - "node_modules/cdk-assets/node_modules/xml2js/node_modules/sax": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9", - "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", - "dev": true - }, - "node_modules/cdk-assets/node_modules/xmlbuilder": { - "version": "11.0.1", - "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz#be9bae1c8a046e76b31127726347d0ad7002beb3", - "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", - "dev": true - }, - "node_modules/cdk-assets/node_modules/y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "dev": true - }, - "node_modules/cdk-assets/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "node_modules/cdk-assets/node_modules/yargs": { - "version": "16.2.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", - "dev": true, - "dependencies": { - "cliui": "^7.0.2", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.0", - "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=10" } }, "node_modules/cdk-assets/node_modules/yargs-parser": { "version": "20.2.9", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee", - "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", - "dev": true - }, - "node_modules/cdk-assets/node_modules/zip-stream": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/zip-stream/-/zip-stream-4.1.0.tgz#51dd326571544e36aa3f756430b313576dc8fc79", - "integrity": "sha512-zshzwQW7gG7hjpBlgeQP9RuyPGNxvJdzR8SUM3QhxCnLjWN2E7j3dOvpeDcQoETfHx0urRS7EtmVToql7YpU4A==", - "dev": true, - "dependencies": { - "archiver-utils": "^2.1.0", - "compress-commons": "^4.1.0", - "readable-stream": "^3.6.0" + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" } }, "node_modules/cdk-sample": { @@ -8521,6 +7848,14 @@ "node": ">=8" } }, + "node_modules/data-uri-to-buffer": { + "version": "3.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, "node_modules/dateformat": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-3.0.3.tgz", @@ -8632,6 +7967,20 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/degenerator": { + "version": "3.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "ast-types": "^0.13.2", + "escodegen": "^1.8.1", + "esprima": "^4.0.0", + "vm2": "^3.9.8" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/del": { "version": "6.1.1", "resolved": "https://registry.npmjs.org/del/-/del-6.1.1.tgz", @@ -9372,6 +8721,73 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/escodegen": { + "version": "1.14.3", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esprima": "^4.0.1", + "estraverse": "^4.2.0", + "esutils": "^2.0.2", + "optionator": "^0.8.1" + }, + "bin": { + "escodegen": "bin/escodegen.js", + "esgenerate": "bin/esgenerate.js" + }, + "engines": { + "node": ">=4.0" + }, + "optionalDependencies": { + "source-map": "~0.6.1" + } + }, + "node_modules/escodegen/node_modules/levn": { + "version": "0.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/escodegen/node_modules/optionator": { + "version": "0.8.3", + "dev": true, + "license": "MIT", + "dependencies": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.6", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "word-wrap": "~1.2.3" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/escodegen/node_modules/prelude-ls": { + "version": "1.1.2", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/escodegen/node_modules/type-check": { + "version": "0.3.2", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, "node_modules/eslint": { "version": "8.30.0", "dev": true, @@ -9985,6 +9401,14 @@ "node": "^10.12.0 || >=12.0.0" } }, + "node_modules/file-uri-to-path": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, "node_modules/file-url": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/file-url/-/file-url-3.0.0.tgz", @@ -10191,6 +9615,38 @@ "dev": true, "license": "ISC" }, + "node_modules/ftp": { + "version": "0.3.10", + "dev": true, + "dependencies": { + "readable-stream": "1.1.x", + "xregexp": "2.0.0" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/ftp/node_modules/isarray": { + "version": "0.0.1", + "dev": true, + "license": "MIT" + }, + "node_modules/ftp/node_modules/readable-stream": { + "version": "1.1.14", + "dev": true, + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, + "node_modules/ftp/node_modules/string_decoder": { + "version": "0.10.31", + "dev": true, + "license": "MIT" + }, "node_modules/function-bind": { "version": "1.1.1", "dev": true, @@ -10434,6 +9890,51 @@ "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" } }, + "node_modules/get-uri": { + "version": "3.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "@tootallnate/once": "1", + "data-uri-to-buffer": "3", + "debug": "4", + "file-uri-to-path": "2", + "fs-extra": "^8.1.0", + "ftp": "^0.3.10" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/get-uri/node_modules/fs-extra": { + "version": "8.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "node_modules/get-uri/node_modules/jsonfile": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/get-uri/node_modules/universalify": { + "version": "0.1.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4.0.0" + } + }, "node_modules/git-raw-commits": { "version": "2.0.11", "resolved": "https://registry.npmjs.org/git-raw-commits/-/git-raw-commits-2.0.11.tgz", @@ -10755,6 +10256,34 @@ "dev": true, "license": "BSD-2-Clause" }, + "node_modules/http-errors": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/http-proxy-agent": { + "version": "4.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@tootallnate/once": "1", + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/https-proxy-agent": { "version": "5.0.1", "dev": true, @@ -11028,6 +10557,11 @@ "node": ">= 0.4" } }, + "node_modules/ip": { + "version": "1.1.8", + "dev": true, + "license": "MIT" + }, "node_modules/is-arguments": { "version": "1.1.1", "dev": true, @@ -13977,6 +13511,14 @@ "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", "dev": true }, + "node_modules/netmask": { + "version": "2.0.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4.0" + } + }, "node_modules/nise": { "version": "5.1.4", "dev": true, @@ -14938,17 +14480,16 @@ } }, "node_modules/optionator": { - "version": "0.9.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", - "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", + "version": "0.9.1", "dev": true, + "license": "MIT", "dependencies": { - "@aashutoshrathi/word-wrap": "^1.2.3", "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", "levn": "^0.4.1", "prelude-ls": "^1.2.1", - "type-check": "^0.4.0" + "type-check": "^0.4.0", + "word-wrap": "^1.2.3" }, "engines": { "node": ">= 0.8.0" @@ -15115,6 +14656,38 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/pac-proxy-agent": { + "version": "5.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@tootallnate/once": "1", + "agent-base": "6", + "debug": "4", + "get-uri": "3", + "http-proxy-agent": "^4.0.1", + "https-proxy-agent": "5", + "pac-resolver": "^5.0.0", + "raw-body": "^2.2.0", + "socks-proxy-agent": "5" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/pac-resolver": { + "version": "5.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "degenerator": "^3.0.2", + "ip": "^1.1.5", + "netmask": "^2.0.2" + }, + "engines": { + "node": ">= 8" + } + }, "node_modules/pacote": { "version": "15.1.1", "resolved": "https://registry.npmjs.org/pacote/-/pacote-15.1.1.tgz", @@ -15770,6 +15343,37 @@ "integrity": "sha512-/XJ368cyBJ7fzLMwLKv1e4vLxOju2MNAIokcr7meSaNcVbWz/CPcW22cP04mwxOErdA5mwjA8Q6w/cdAQxVn7Q==", "dev": true }, + "node_modules/proxy-agent": { + "version": "5.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^6.0.0", + "debug": "4", + "http-proxy-agent": "^4.0.0", + "https-proxy-agent": "^5.0.0", + "lru-cache": "^5.1.1", + "pac-proxy-agent": "^5.0.0", + "proxy-from-env": "^1.0.0", + "socks-proxy-agent": "^5.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/proxy-agent/node_modules/lru-cache": { + "version": "5.1.1", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/proxy-agent/node_modules/yallist": { + "version": "3.1.1", + "dev": true, + "license": "ISC" + }, "node_modules/proxy-from-env": { "version": "1.1.0", "dev": true, @@ -15827,6 +15431,20 @@ "node": ">=8" } }, + "node_modules/raw-body": { + "version": "2.5.1", + "dev": true, + "license": "MIT", + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/react-is": { "version": "18.2.0", "dev": true, @@ -16503,6 +16121,11 @@ "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", "dev": true }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "dev": true, + "license": "ISC" + }, "node_modules/shallow-clone": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", @@ -16763,6 +16386,19 @@ "npm": ">= 3.0.0" } }, + "node_modules/socks-proxy-agent": { + "version": "5.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^6.0.2", + "debug": "4", + "socks": "^2.3.3" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/socks/node_modules/ip": { "version": "2.0.0", "dev": true, @@ -16899,6 +16535,14 @@ "node": ">=8" } }, + "node_modules/statuses": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/string_decoder": { "version": "1.3.0", "dev": true, @@ -17329,6 +16973,14 @@ "node": ">=8.0" } }, + "node_modules/toidentifier": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.6" + } + }, "node_modules/tr46": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", @@ -17800,6 +17452,14 @@ "node": ">= 10.0.0" } }, + "node_modules/unpipe": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/upath": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/upath/-/upath-2.0.1.tgz", @@ -17932,6 +17592,22 @@ "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, + "node_modules/vm2": { + "version": "3.9.18", + "resolved": "https://registry.npmjs.org/vm2/-/vm2-3.9.18.tgz", + "integrity": "sha512-iM7PchOElv6Uv6Q+0Hq7dcgDtWWT6SizYqVcvol+1WQc+E9HlgTCnPozbQNSP3yDV9oXHQOEQu530w2q/BCVZg==", + "dev": true, + "dependencies": { + "acorn": "^8.7.0", + "acorn-walk": "^8.2.0" + }, + "bin": { + "vm2": "bin/vm2" + }, + "engines": { + "node": ">=6.0" + } + }, "node_modules/vscode-oniguruma": { "version": "1.7.0", "resolved": "https://registry.npmjs.org/vscode-oniguruma/-/vscode-oniguruma-1.7.0.tgz", @@ -18039,6 +17715,14 @@ "string-width": "^1.0.2 || 2 || 3 || 4" } }, + "node_modules/word-wrap": { + "version": "1.2.3", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/wordwrap": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", @@ -18198,6 +17882,11 @@ "node": ">=4.0" } }, + "node_modules/xregexp": { + "version": "2.0.0", + "dev": true, + "license": "MIT" + }, "node_modules/xtend": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", diff --git a/package.json b/package.json index 598ef8b6bd..467365c53e 100644 --- a/package.json +++ b/package.json @@ -72,6 +72,7 @@ "lint-staged": "^13.1.2", "prettier": "^2.8.8", "promptly": "^3.2.0", + "proxy-agent": "^5.0.0", "rimraf": "^5.0.1", "ts-jest": "^29.0.3", "ts-node": "^10.9.1", From 6a145959249db6eeb89fdfe3ed4c6e30ab155f9c Mon Sep 17 00:00:00 2001 From: Andrea Amorosi Date: Mon, 17 Jul 2023 14:46:52 +0200 Subject: [PATCH 06/11] feat(logger): add cause to formatted error (#1617) --- packages/logger/src/formatter/LogFormatter.ts | 22 +++++++ .../formatter/PowertoolLogFormatter.test.ts | 65 +++++++++++++++++++ 2 files changed, 87 insertions(+) diff --git a/packages/logger/src/formatter/LogFormatter.ts b/packages/logger/src/formatter/LogFormatter.ts index dac142a05a..539d0b814d 100644 --- a/packages/logger/src/formatter/LogFormatter.ts +++ b/packages/logger/src/formatter/LogFormatter.ts @@ -1,6 +1,23 @@ import { LogFormatterInterface } from '.'; import { LogAttributes, UnformattedAttributes } from '../types'; +/** + * Typeguard to monkey patch Error to add a cause property. + * + * This is needed because the `cause` property was added in Node 16.x. + * Since we want to be able to format errors in Node 14.x, we need to + * add this property ourselves. We can remove this once we drop support + * for Node 14.x. + * + * @see 1361 + * @see https://nodejs.org/api/errors.html#errors_error_cause + */ +const isErrorWithCause = ( + error: Error +): error is Error & { cause: unknown } => { + return 'cause' in error; +}; + /** * This class defines and implements common methods for the formatting of log attributes. * @@ -31,6 +48,11 @@ abstract class LogFormatter implements LogFormatterInterface { location: this.getCodeLocation(error.stack), message: error.message, stack: error.stack, + cause: isErrorWithCause(error) + ? error.cause instanceof Error + ? this.formatError(error.cause) + : error.cause + : undefined, }; } diff --git a/packages/logger/tests/unit/formatter/PowertoolLogFormatter.test.ts b/packages/logger/tests/unit/formatter/PowertoolLogFormatter.test.ts index 49daebe597..02e1e2a303 100644 --- a/packages/logger/tests/unit/formatter/PowertoolLogFormatter.test.ts +++ b/packages/logger/tests/unit/formatter/PowertoolLogFormatter.test.ts @@ -307,6 +307,71 @@ describe('Class: PowertoolLogFormatter', () => { expect(shouldThrow).toThrowError(expect.any(URIError)); }); + + test('when an error with cause of type Error is formatted, the cause key is included and formatted', () => { + // Prepare + const formatter = new PowertoolLogFormatter(); + class ErrorWithCause extends Error { + public cause?: Error; + public constructor(message: string, options?: { cause: Error }) { + super(message); + this.cause = options?.cause; + } + } + + // Act + const formattedURIError = formatter.formatError( + new ErrorWithCause('foo', { cause: new Error('bar') }) + ); + + // Assess + expect(formattedURIError).toEqual({ + location: expect.stringMatching(/PowertoolLogFormatter.test.ts:[0-9]+/), + message: 'foo', + name: 'Error', + stack: expect.stringMatching( + /PowertoolLogFormatter.test.ts:[0-9]+:[0-9]+/ + ), + cause: { + location: expect.stringMatching( + /PowertoolLogFormatter.test.ts:[0-9]+/ + ), + message: 'bar', + name: 'Error', + stack: expect.stringMatching( + /PowertoolLogFormatter.test.ts:[0-9]+:[0-9]+/ + ), + }, + }); + }); + + test('when an error with cause of type other than Error is formatted, the cause key is included as-is', () => { + // Prepare + const formatter = new PowertoolLogFormatter(); + class ErrorWithCause extends Error { + public cause?: unknown; + public constructor(message: string, options?: { cause: unknown }) { + super(message); + this.cause = options?.cause; + } + } + + // Act + const formattedURIError = formatter.formatError( + new ErrorWithCause('foo', { cause: 'bar' }) + ); + + // Assess + expect(formattedURIError).toEqual({ + location: expect.stringMatching(/PowertoolLogFormatter.test.ts:[0-9]+/), + message: 'foo', + name: 'Error', + stack: expect.stringMatching( + /PowertoolLogFormatter.test.ts:[0-9]+:[0-9]+/ + ), + cause: 'bar', + }); + }); }); describe('Method: formatTimestamp', () => { From 0b575a1f136044c7e00b40a95cc66bf0d07963f5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 19 Jul 2023 10:27:22 +0200 Subject: [PATCH 07/11] chore(maintenance): bump word-wrap from 1.2.3 to 1.2.4 (#1618) Bumps [word-wrap](https://github.com/jonschlinkert/word-wrap) from 1.2.3 to 1.2.4. - [Release notes](https://github.com/jonschlinkert/word-wrap/releases) - [Commits](https://github.com/jonschlinkert/word-wrap/compare/1.2.3...1.2.4) --- updated-dependencies: - dependency-name: word-wrap dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index d9d180d8ae..b0050f1e8e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17716,9 +17716,10 @@ } }, "node_modules/word-wrap": { - "version": "1.2.3", + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.4.tgz", + "integrity": "sha512-2V81OA4ugVo5pRo46hAoD2ivUJx8jXmWXfUkY4KFNw0hEptvN0QfH3K4nHiwzGeKl5rFKedV48QVoqYavy4YpA==", "dev": true, - "license": "MIT", "engines": { "node": ">=0.10.0" } From c4e6b192c3658cbcc3f458a579a0752153e3c201 Mon Sep 17 00:00:00 2001 From: Andrea Amorosi Date: Tue, 25 Jul 2023 12:14:51 +0200 Subject: [PATCH 08/11] feat(batch): add batch processing utility (#1625) * chore: init workspace * chore: init workspace * feat(batch): Implementation of base batch processing classes (#1588) * chore: init workspace * chore: init workspace * Initial base class implementation * Added BatchProcessor implementation, attempted fix for async * Added unit tests * Refactoring unit tests * Lint fix, updated docstrings * Added response and identifier typings * test(idempotency): improve integration tests for utility (#1591) * docs: new name * chore: rename e2e files * tests(idempotency): expand integration tests * chore(idempotency): remove unreachable code * Removed unnecessary type casting * Moved exports for handlers and factories * Updated imports, refactored randomization in factories * Refactored EventType to be const instead of enum * Refactored and added documentation for errors * Removed debugging line * chore(ci): add canary to layer deployment (#1593) * docs(idempotency): write utility docs (#1592) * docs: base docs * wip * chore: added paths to snippets tsconfig * chore: added page to docs menu * docs(idempotency): utility docs * highlights * chore: remove CDK mention * build(internal): bump semver from 5.7.1 to 5.7.2 (#1594) Bumps [semver](https://github.com/npm/node-semver) from 5.7.1 to 5.7.2. - [Release notes](https://github.com/npm/node-semver/releases) - [Changelog](https://github.com/npm/node-semver/blob/v5.7.2/CHANGELOG.md) - [Commits](https://github.com/npm/node-semver/compare/v5.7.1...v5.7.2) --- updated-dependencies: - dependency-name: semver dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * chore(idempotency): mark the utility ready public beta (#1595) * chore(idempotency): mark utility as public beta * chore: manually increment version in commons * docs(internal): update AWS SDK links to new docs (#1597) * chore(maintenance): remove parameters utility from layer bundling and layers e2e tests (#1599) * remove parameter from e2e tests * remove parameters from canary stack as well * chore(release): v1.11.1 [skip ci] * fix canary deploy in ci with correct workspace name (#1601) * chore: update layer ARN on documentation --------- Signed-off-by: dependabot[bot] Co-authored-by: Andrea Amorosi Co-authored-by: Alexander Schueren Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: github-actions[bot] Co-authored-by: Release bot[bot] * feat(batch): Batch processing wrapper function (#1605) * Refactored some types, added function wrapper and base test * Added record check and tests, renamed factories * Refactored type check logic in function * Refactor test to remove error ignore * feat(batch): Implement SQS FIFO processor class (#1606) * Added SQS FIFO processor and unit tests * Added docstring for pbatch processing function * feat(batch): Support for Lambda context access in batch processing (#1609) * Added types and parameter for lambda context, added unit tests * Refactor parameter checking * Added test for malformed context handling * docs: created utility docs * docs: fixed white spaces * feat(batch): add async processor (#1616) * feat(batch): add async processor * tests: improved unit tests * chore: removed docstring + edited test handler * chore: fix typos * docs: added README * chore: added package to beta release * chore: marked package as public * chore: added new batch page to docs * chore: added utility to lerna workspace * chore: added utility to main readme * chore: added utility to CI --------- Signed-off-by: dependabot[bot] Co-authored-by: Erika Yao <71943596+erikayao93@users.noreply.github.com> Co-authored-by: Alexander Schueren Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: github-actions[bot] Co-authored-by: Release bot[bot] --- .github/scripts/release_patch_package_json.js | 5 +- ...sable-run-linting-check-and-unit-tests.yml | 4 +- README.md | 1 + docs/snippets/batch/accessLambdaContext.ts | 37 +++ .../snippets/batch/accessProcessedMessages.ts | 38 +++ docs/snippets/batch/customPartialProcessor.ts | 98 ++++++ docs/snippets/batch/extendingFailure.ts | 53 ++++ docs/snippets/batch/gettingStartedAsync.ts | 31 ++ .../batch/gettingStartedDynamoDBStreams.ts | 35 +++ docs/snippets/batch/gettingStartedKinesis.ts | 30 ++ docs/snippets/batch/gettingStartedSQS.ts | 33 ++ docs/snippets/batch/gettingStartedSQSFifo.ts | 31 ++ .../samples/sampleDynamoDBStreamsEvent.json | 50 +++ .../sampleDynamoDBStreamsResponse.json | 7 + .../batch/samples/sampleKinesisEvent.json | 36 +++ .../batch/samples/sampleKinesisResponse.json | 7 + .../batch/samples/sampleSQSEvent.json | 36 +++ .../batch/samples/sampleSQSResponse.json | 7 + .../batch/templates/sam/dynamodb.yaml | 66 ++++ .../snippets/batch/templates/sam/kinesis.yaml | 56 ++++ docs/snippets/batch/templates/sam/sqs.yaml | 43 +++ docs/snippets/batch/testingYourCode.ts | 32 ++ docs/snippets/package.json | 7 +- docs/snippets/tsconfig.json | 23 +- docs/utilities/batch.md | 269 ++++++++++++++++ lerna.json | 1 + mkdocs.yml | 1 + package-lock.json | 17 +- package.json | 3 +- packages/batch/README.md | 263 ++++++++++++++++ packages/batch/jest.config.js | 28 ++ packages/batch/package.json | 54 ++++ packages/batch/src/AsyncBatchProcessor.ts | 31 ++ .../batch/src/BasePartialBatchProcessor.ts | 157 ++++++++++ packages/batch/src/BasePartialProcessor.ts | 168 ++++++++++ packages/batch/src/BatchProcessor.ts | 31 ++ packages/batch/src/SqsFifoPartialProcessor.ts | 68 ++++ .../batch/src/asyncProcessPartialResponse.ts | 38 +++ packages/batch/src/constants.ts | 25 ++ packages/batch/src/errors.ts | 49 +++ packages/batch/src/index.ts | 10 + packages/batch/src/processPartialResponse.ts | 38 +++ packages/batch/src/types.ts | 37 +++ packages/batch/tests/helpers/factories.ts | 75 +++++ packages/batch/tests/helpers/handlers.ts | 109 +++++++ .../helpers/populateEnvironmentVariables.ts | 12 + .../tests/unit/AsyncBatchProcessor.test.ts | 296 ++++++++++++++++++ .../batch/tests/unit/BatchProcessor.test.ts | 285 +++++++++++++++++ .../unit/SqsFifoPartialProcessor.test.ts | 59 ++++ .../unit/asyncProcessPartialResponse.test.ts | 231 ++++++++++++++ .../tests/unit/processPartialResponse.test.ts | 209 +++++++++++++ packages/batch/tsconfig-dev.json | 11 + packages/batch/tsconfig.es.json | 11 + packages/batch/tsconfig.json | 29 ++ packages/batch/typedoc.json | 9 + 55 files changed, 3367 insertions(+), 23 deletions(-) create mode 100644 docs/snippets/batch/accessLambdaContext.ts create mode 100644 docs/snippets/batch/accessProcessedMessages.ts create mode 100644 docs/snippets/batch/customPartialProcessor.ts create mode 100644 docs/snippets/batch/extendingFailure.ts create mode 100644 docs/snippets/batch/gettingStartedAsync.ts create mode 100644 docs/snippets/batch/gettingStartedDynamoDBStreams.ts create mode 100644 docs/snippets/batch/gettingStartedKinesis.ts create mode 100644 docs/snippets/batch/gettingStartedSQS.ts create mode 100644 docs/snippets/batch/gettingStartedSQSFifo.ts create mode 100644 docs/snippets/batch/samples/sampleDynamoDBStreamsEvent.json create mode 100644 docs/snippets/batch/samples/sampleDynamoDBStreamsResponse.json create mode 100644 docs/snippets/batch/samples/sampleKinesisEvent.json create mode 100644 docs/snippets/batch/samples/sampleKinesisResponse.json create mode 100644 docs/snippets/batch/samples/sampleSQSEvent.json create mode 100644 docs/snippets/batch/samples/sampleSQSResponse.json create mode 100644 docs/snippets/batch/templates/sam/dynamodb.yaml create mode 100644 docs/snippets/batch/templates/sam/kinesis.yaml create mode 100644 docs/snippets/batch/templates/sam/sqs.yaml create mode 100644 docs/snippets/batch/testingYourCode.ts create mode 100644 docs/utilities/batch.md create mode 100644 packages/batch/README.md create mode 100644 packages/batch/jest.config.js create mode 100644 packages/batch/package.json create mode 100644 packages/batch/src/AsyncBatchProcessor.ts create mode 100644 packages/batch/src/BasePartialBatchProcessor.ts create mode 100644 packages/batch/src/BasePartialProcessor.ts create mode 100644 packages/batch/src/BatchProcessor.ts create mode 100644 packages/batch/src/SqsFifoPartialProcessor.ts create mode 100644 packages/batch/src/asyncProcessPartialResponse.ts create mode 100644 packages/batch/src/constants.ts create mode 100644 packages/batch/src/errors.ts create mode 100644 packages/batch/src/index.ts create mode 100644 packages/batch/src/processPartialResponse.ts create mode 100644 packages/batch/src/types.ts create mode 100644 packages/batch/tests/helpers/factories.ts create mode 100644 packages/batch/tests/helpers/handlers.ts create mode 100644 packages/batch/tests/helpers/populateEnvironmentVariables.ts create mode 100644 packages/batch/tests/unit/AsyncBatchProcessor.test.ts create mode 100644 packages/batch/tests/unit/BatchProcessor.test.ts create mode 100644 packages/batch/tests/unit/SqsFifoPartialProcessor.test.ts create mode 100644 packages/batch/tests/unit/asyncProcessPartialResponse.test.ts create mode 100644 packages/batch/tests/unit/processPartialResponse.test.ts create mode 100644 packages/batch/tsconfig-dev.json create mode 100644 packages/batch/tsconfig.es.json create mode 100644 packages/batch/tsconfig.json create mode 100644 packages/batch/typedoc.json diff --git a/.github/scripts/release_patch_package_json.js b/.github/scripts/release_patch_package_json.js index 0108d3aa36..73c1758246 100644 --- a/.github/scripts/release_patch_package_json.js +++ b/.github/scripts/release_patch_package_json.js @@ -18,7 +18,10 @@ if (process.argv.length < 3) { const basePath = resolve(process.argv[2]); const packageJsonPath = join(basePath, 'package.json'); const alphaPackages = []; -const betaPackages = ['@aws-lambda-powertools/idempotency']; +const betaPackages = [ + '@aws-lambda-powertools/idempotency', + '@aws-lambda-powertools/batch', +]; (() => { try { diff --git a/.github/workflows/reusable-run-linting-check-and-unit-tests.yml b/.github/workflows/reusable-run-linting-check-and-unit-tests.yml index 8782e5999e..6c350943b1 100644 --- a/.github/workflows/reusable-run-linting-check-and-unit-tests.yml +++ b/.github/workflows/reusable-run-linting-check-and-unit-tests.yml @@ -27,9 +27,9 @@ jobs: with: nodeVersion: ${{ matrix.version }} - name: Run linting - run: npm run lint -w packages/commons -w packages/logger -w packages/tracer -w packages/metrics -w packages/parameters -w packages/idempotency + run: npm run lint -w packages/commons -w packages/logger -w packages/tracer -w packages/metrics -w packages/parameters -w packages/idempotency -w packages/batch - name: Run unit tests - run: npm t -w packages/commons -w packages/logger -w packages/tracer -w packages/metrics -w packages/parameters -w packages/idempotency + run: npm t -w packages/commons -w packages/logger -w packages/tracer -w packages/metrics -w packages/parameters -w packages/idempotency -w packages/batch check-examples: runs-on: ubuntu-latest env: diff --git a/README.md b/README.md index 03746c86a5..9b7168ae19 100644 --- a/README.md +++ b/README.md @@ -36,6 +36,7 @@ You can use the library in both TypeScript and JavaScript code bases. * **[Metrics](https://docs.powertools.aws.dev/lambda-typescript/latest/core/metrics/)** - Custom Metrics created asynchronously via CloudWatch Embedded Metric Format (EMF) * **[Parameters](https://docs.powertools.aws.dev/lambda-typescript/latest/utilities/parameters/)** - High-level functions to retrieve one or more parameters from AWS SSM Parameter Store, AWS Secrets Manager, AWS AppConfig, and Amazon DynamoDB * **[Idempotency (beta)](https://docs.powertools.aws.dev/lambda-typescript/latest/utilities/idempotency/)** - Class method decorator, Middy middleware, and function wrapper to make your Lambda functions idempotent and prevent duplicate execution based on payload content +* **[Batch Processing (beta)](https://docs.powertools.aws.dev/lambda-typescript/latest/utilities/batch/)** - Utility to handle partial failures when processing batches from Amazon SQS, Amazon Kinesis Data Streams, and Amazon DynamoDB Streams. ## Getting started diff --git a/docs/snippets/batch/accessLambdaContext.ts b/docs/snippets/batch/accessLambdaContext.ts new file mode 100644 index 0000000000..0f8aa89409 --- /dev/null +++ b/docs/snippets/batch/accessLambdaContext.ts @@ -0,0 +1,37 @@ +import { + BatchProcessor, + EventType, + processPartialResponse, +} from '@aws-lambda-powertools/batch'; +import { Logger } from '@aws-lambda-powertools/logger'; +import type { + SQSEvent, + SQSRecord, + Context, + SQSBatchResponse, +} from 'aws-lambda'; + +const processor = new BatchProcessor(EventType.SQS); +const logger = new Logger(); + +const recordHandler = (record: SQSRecord, lambdaContext?: Context): void => { + const payload = record.body; + if (payload) { + const item = JSON.parse(payload); + logger.info('Processed item', { item }); + } + if (lambdaContext) { + logger.info('Remaining time', { + time: lambdaContext.getRemainingTimeInMillis(), + }); + } +}; + +export const handler = async ( + event: SQSEvent, + context: Context +): Promise => { + return processPartialResponse(event, recordHandler, processor, { + context, + }); +}; diff --git a/docs/snippets/batch/accessProcessedMessages.ts b/docs/snippets/batch/accessProcessedMessages.ts new file mode 100644 index 0000000000..6dbd338c7b --- /dev/null +++ b/docs/snippets/batch/accessProcessedMessages.ts @@ -0,0 +1,38 @@ +import { BatchProcessor, EventType } from '@aws-lambda-powertools/batch'; +import { Logger } from '@aws-lambda-powertools/logger'; +import type { + SQSEvent, + SQSRecord, + Context, + SQSBatchResponse, +} from 'aws-lambda'; + +const processor = new BatchProcessor(EventType.SQS); +const logger = new Logger(); + +const recordHandler = (record: SQSRecord): void => { + const payload = record.body; + if (payload) { + const item = JSON.parse(payload); + logger.info('Processed item', { item }); + } +}; + +export const handler = async ( + event: SQSEvent, + context: Context +): Promise => { + const batch = event.Records; + + processor.register(batch, recordHandler, { context }); + const processedMessages = processor.process(); + + for (const message of processedMessages) { + const status: 'success' | 'fail' = message[0]; + const record = message[2]; + + logger.info('Processed record', { status, record }); + } + + return processor.response(); +}; diff --git a/docs/snippets/batch/customPartialProcessor.ts b/docs/snippets/batch/customPartialProcessor.ts new file mode 100644 index 0000000000..d44b99a602 --- /dev/null +++ b/docs/snippets/batch/customPartialProcessor.ts @@ -0,0 +1,98 @@ +import { randomInt } from 'node:crypto'; +import { + DynamoDBClient, + BatchWriteItemCommand, +} from '@aws-sdk/client-dynamodb'; +import { marshall } from '@aws-sdk/util-dynamodb'; +import { + BasePartialProcessor, + processPartialResponse, +} from '@aws-lambda-powertools/batch'; +import type { + SuccessResponse, + FailureResponse, + EventSourceType, +} from '@aws-lambda-powertools/batch'; +import type { SQSEvent, Context, SQSBatchResponse } from 'aws-lambda'; + +const tableName = process.env.TABLE_NAME || 'table-not-found'; + +class MyPartialProcessor extends BasePartialProcessor { + #tableName: string; + #client?: DynamoDBClient; + + public constructor(tableName: string) { + super(); + this.#tableName = tableName; + } + + public async asyncProcessRecord( + _record: EventSourceType + ): Promise { + throw new Error('Not implemented'); + } + + /** + * It's called once, **after** processing the batch. + * + * Here we are writing all the processed messages to DynamoDB. + */ + public clean(): void { + // We know that the client is defined because clean() is called after prepare() + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + this.#client!.send( + new BatchWriteItemCommand({ + RequestItems: { + [this.#tableName]: this.successMessages.map((message) => ({ + PutRequest: { + Item: marshall(message), + }, + })), + }, + }) + ); + } + + /** + * It's called once, **before** processing the batch. + * + * It initializes a new client and cleans up any existing data. + */ + public prepare(): void { + this.#client = new DynamoDBClient({}); + this.successMessages = []; + } + + /** + * It handles how your record is processed. + * + * Here we are keeping the status of each run, `this.handler` is + * the function that is passed when calling `processor.register()`. + */ + public processRecord( + record: EventSourceType + ): SuccessResponse | FailureResponse { + try { + const result = this.handler(record); + + return this.successHandler(record, result); + } catch (error) { + return this.failureHandler(record, error as Error); + } + } +} + +const processor = new MyPartialProcessor(tableName); + +const recordHandler = (): number => { + return Math.floor(randomInt(1, 10)); +}; + +export const handler = async ( + event: SQSEvent, + context: Context +): Promise => { + return processPartialResponse(event, recordHandler, processor, { + context, + }); +}; diff --git a/docs/snippets/batch/extendingFailure.ts b/docs/snippets/batch/extendingFailure.ts new file mode 100644 index 0000000000..ab1ef530f9 --- /dev/null +++ b/docs/snippets/batch/extendingFailure.ts @@ -0,0 +1,53 @@ +import { Metrics, MetricUnits } from '@aws-lambda-powertools/metrics'; +import { + BatchProcessor, + EventType, + FailureResponse, + EventSourceType, + processPartialResponse, +} from '@aws-lambda-powertools/batch'; +import { Logger } from '@aws-lambda-powertools/logger'; +import type { + SQSEvent, + SQSRecord, + Context, + SQSBatchResponse, +} from 'aws-lambda'; + +class MyProcessor extends BatchProcessor { + #metrics: Metrics; + + public constructor(eventType: keyof typeof EventType) { + super(eventType); + this.#metrics = new Metrics({ namespace: 'test' }); + } + + public failureHandler( + record: EventSourceType, + error: Error + ): FailureResponse { + this.#metrics.addMetric('BatchRecordFailures', MetricUnits.Count, 1); + + return super.failureHandler(record, error); + } +} + +const processor = new MyProcessor(EventType.SQS); +const logger = new Logger(); + +const recordHandler = (record: SQSRecord): void => { + const payload = record.body; + if (payload) { + const item = JSON.parse(payload); + logger.info('Processed item', { item }); + } +}; + +export const handler = async ( + event: SQSEvent, + context: Context +): Promise => { + return processPartialResponse(event, recordHandler, processor, { + context, + }); +}; diff --git a/docs/snippets/batch/gettingStartedAsync.ts b/docs/snippets/batch/gettingStartedAsync.ts new file mode 100644 index 0000000000..0080752026 --- /dev/null +++ b/docs/snippets/batch/gettingStartedAsync.ts @@ -0,0 +1,31 @@ +import { + AsyncBatchProcessor, + EventType, + asyncProcessPartialResponse, +} from '@aws-lambda-powertools/batch'; +import axios from 'axios'; // axios is an external dependency +import type { + SQSEvent, + SQSRecord, + Context, + SQSBatchResponse, +} from 'aws-lambda'; + +const processor = new AsyncBatchProcessor(EventType.SQS); + +const recordHandler = async (record: SQSRecord): Promise => { + const res = await axios.post('https://httpbin.org/anything', { + message: record.body, + }); + + return res.status; +}; + +export const handler = async ( + event: SQSEvent, + context: Context +): Promise => { + return await asyncProcessPartialResponse(event, recordHandler, processor, { + context, + }); +}; diff --git a/docs/snippets/batch/gettingStartedDynamoDBStreams.ts b/docs/snippets/batch/gettingStartedDynamoDBStreams.ts new file mode 100644 index 0000000000..4d1842bcec --- /dev/null +++ b/docs/snippets/batch/gettingStartedDynamoDBStreams.ts @@ -0,0 +1,35 @@ +import { + BatchProcessor, + EventType, + processPartialResponse, +} from '@aws-lambda-powertools/batch'; +import { Logger } from '@aws-lambda-powertools/logger'; +import type { + DynamoDBStreamEvent, + DynamoDBRecord, + Context, + DynamoDBBatchResponse, +} from 'aws-lambda'; + +const processor = new BatchProcessor(EventType.DynamoDBStreams); +const logger = new Logger(); + +const recordHandler = (record: DynamoDBRecord): void => { + if (record.dynamodb && record.dynamodb.NewImage) { + logger.info('Processing record', { record: record.dynamodb.NewImage }); + const message = record.dynamodb.NewImage.Message.S; + if (message) { + const payload = JSON.parse(message); + logger.info('Processed item', { item: payload }); + } + } +}; + +export const handler = async ( + event: DynamoDBStreamEvent, + context: Context +): Promise => { + return processPartialResponse(event, recordHandler, processor, { + context, + }); +}; diff --git a/docs/snippets/batch/gettingStartedKinesis.ts b/docs/snippets/batch/gettingStartedKinesis.ts new file mode 100644 index 0000000000..eb1c8a8810 --- /dev/null +++ b/docs/snippets/batch/gettingStartedKinesis.ts @@ -0,0 +1,30 @@ +import { + BatchProcessor, + EventType, + processPartialResponse, +} from '@aws-lambda-powertools/batch'; +import { Logger } from '@aws-lambda-powertools/logger'; +import type { + KinesisStreamEvent, + KinesisStreamRecord, + Context, + KinesisStreamBatchResponse, +} from 'aws-lambda'; + +const processor = new BatchProcessor(EventType.KinesisDataStreams); +const logger = new Logger(); + +const recordHandler = (record: KinesisStreamRecord): void => { + logger.info('Processing record', { record: record.kinesis.data }); + const payload = JSON.parse(record.kinesis.data); + logger.info('Processed item', { item: payload }); +}; + +export const handler = async ( + event: KinesisStreamEvent, + context: Context +): Promise => { + return processPartialResponse(event, recordHandler, processor, { + context, + }); +}; diff --git a/docs/snippets/batch/gettingStartedSQS.ts b/docs/snippets/batch/gettingStartedSQS.ts new file mode 100644 index 0000000000..3ee6a3fa56 --- /dev/null +++ b/docs/snippets/batch/gettingStartedSQS.ts @@ -0,0 +1,33 @@ +import { + BatchProcessor, + EventType, + processPartialResponse, +} from '@aws-lambda-powertools/batch'; +import { Logger } from '@aws-lambda-powertools/logger'; +import type { + SQSEvent, + SQSRecord, + Context, + SQSBatchResponse, +} from 'aws-lambda'; + +const processor = new BatchProcessor(EventType.SQS); +const logger = new Logger(); + +const recordHandler = (record: SQSRecord): void => { + const payload = record.body; + if (payload) { + const item = JSON.parse(payload); + logger.info('Processed item', { item }); + } +}; + +export const handler = async ( + event: SQSEvent, + context: Context +): Promise => { + return processPartialResponse(event, recordHandler, processor, { + context, + }); +}; +export { processor }; diff --git a/docs/snippets/batch/gettingStartedSQSFifo.ts b/docs/snippets/batch/gettingStartedSQSFifo.ts new file mode 100644 index 0000000000..34ff76e705 --- /dev/null +++ b/docs/snippets/batch/gettingStartedSQSFifo.ts @@ -0,0 +1,31 @@ +import { + SqsFifoPartialProcessor, + processPartialResponse, +} from '@aws-lambda-powertools/batch'; +import { Logger } from '@aws-lambda-powertools/logger'; +import type { + SQSEvent, + SQSRecord, + Context, + SQSBatchResponse, +} from 'aws-lambda'; + +const processor = new SqsFifoPartialProcessor(); +const logger = new Logger(); + +const recordHandler = (record: SQSRecord): void => { + const payload = record.body; + if (payload) { + const item = JSON.parse(payload); + logger.info('Processed item', { item }); + } +}; + +export const handler = async ( + event: SQSEvent, + context: Context +): Promise => { + return processPartialResponse(event, recordHandler, processor, { + context, + }); +}; diff --git a/docs/snippets/batch/samples/sampleDynamoDBStreamsEvent.json b/docs/snippets/batch/samples/sampleDynamoDBStreamsEvent.json new file mode 100644 index 0000000000..f74c2429a5 --- /dev/null +++ b/docs/snippets/batch/samples/sampleDynamoDBStreamsEvent.json @@ -0,0 +1,50 @@ +{ + "Records": [ + { + "eventID": "1", + "eventVersion": "1.0", + "dynamodb": { + "Keys": { + "Id": { + "N": "101" + } + }, + "NewImage": { + "Message": { + "S": "failure" + } + }, + "StreamViewType": "NEW_AND_OLD_IMAGES", + "SequenceNumber": "3275880929", + "SizeBytes": 26 + }, + "awsRegion": "us-west-2", + "eventName": "INSERT", + "eventSourceARN": "eventsource_arn", + "eventSource": "aws:dynamodb" + }, + { + "eventID": "1", + "eventVersion": "1.0", + "dynamodb": { + "Keys": { + "Id": { + "N": "101" + } + }, + "NewImage": { + "SomethingElse": { + "S": "success" + } + }, + "StreamViewType": "NEW_AND_OLD_IMAGES", + "SequenceNumber": "8640712661", + "SizeBytes": 26 + }, + "awsRegion": "us-west-2", + "eventName": "INSERT", + "eventSourceARN": "eventsource_arn", + "eventSource": "aws:dynamodb" + } + ] +} diff --git a/docs/snippets/batch/samples/sampleDynamoDBStreamsResponse.json b/docs/snippets/batch/samples/sampleDynamoDBStreamsResponse.json new file mode 100644 index 0000000000..9ccbde9ba9 --- /dev/null +++ b/docs/snippets/batch/samples/sampleDynamoDBStreamsResponse.json @@ -0,0 +1,7 @@ +{ + "batchItemFailures": [ + { + "itemIdentifier": "8640712661" + } + ] +} diff --git a/docs/snippets/batch/samples/sampleKinesisEvent.json b/docs/snippets/batch/samples/sampleKinesisEvent.json new file mode 100644 index 0000000000..2721ad7d9a --- /dev/null +++ b/docs/snippets/batch/samples/sampleKinesisEvent.json @@ -0,0 +1,36 @@ +{ + "Records": [ + { + "kinesis": { + "kinesisSchemaVersion": "1.0", + "partitionKey": "1", + "sequenceNumber": "4107859083838847772757075850904226111829882106684065", + "data": "eyJNZXNzYWdlIjogInN1Y2Nlc3MifQ==", + "approximateArrivalTimestamp": 1545084650.987 + }, + "eventSource": "aws:kinesis", + "eventVersion": "1.0", + "eventID": "shardId-000000000006:4107859083838847772757075850904226111829882106684065", + "eventName": "aws:kinesis:record", + "invokeIdentityArn": "arn:aws:iam::123456789012:role/lambda-role", + "awsRegion": "us-east-2", + "eventSourceARN": "arn:aws:kinesis:us-east-2:123456789012:stream/lambda-stream" + }, + { + "kinesis": { + "kinesisSchemaVersion": "1.0", + "partitionKey": "1", + "sequenceNumber": "6006958808509702859251049540584488075644979031228738", + "data": "c3VjY2Vzcw==", + "approximateArrivalTimestamp": 1545084650.987 + }, + "eventSource": "aws:kinesis", + "eventVersion": "1.0", + "eventID": "shardId-000000000006:6006958808509702859251049540584488075644979031228738", + "eventName": "aws:kinesis:record", + "invokeIdentityArn": "arn:aws:iam::123456789012:role/lambda-role", + "awsRegion": "us-east-2", + "eventSourceARN": "arn:aws:kinesis:us-east-2:123456789012:stream/lambda-stream" + } + ] +} diff --git a/docs/snippets/batch/samples/sampleKinesisResponse.json b/docs/snippets/batch/samples/sampleKinesisResponse.json new file mode 100644 index 0000000000..7ebd013d7f --- /dev/null +++ b/docs/snippets/batch/samples/sampleKinesisResponse.json @@ -0,0 +1,7 @@ +{ + "batchItemFailures": [ + { + "itemIdentifier": "6006958808509702859251049540584488075644979031228738" + } + ] +} diff --git a/docs/snippets/batch/samples/sampleSQSEvent.json b/docs/snippets/batch/samples/sampleSQSEvent.json new file mode 100644 index 0000000000..50a411be86 --- /dev/null +++ b/docs/snippets/batch/samples/sampleSQSEvent.json @@ -0,0 +1,36 @@ +{ + "Records": [ + { + "messageId": "059f36b4-87a3-44ab-83d2-661975830a7d", + "receiptHandle": "AQEBwJnKyrHigUMZj6rYigCgxlaS3SLy0a", + "body": "{\"Message\": \"success\"}", + "attributes": { + "ApproximateReceiveCount": "1", + "SentTimestamp": "1545082649183", + "SenderId": "AIDAIENQZJOLO23YVJ4VO", + "ApproximateFirstReceiveTimestamp": "1545082649185" + }, + "messageAttributes": {}, + "md5OfBody": "e4e68fb7bd0e697a0ae8f1bb342846b3", + "eventSource": "aws:sqs", + "eventSourceARN": "arn:aws:sqs:us-east-2: 123456789012:my-queue", + "awsRegion": "us-east-1" + }, + { + "messageId": "244fc6b4-87a3-44ab-83d2-361172410c3a", + "receiptHandle": "AQEBwJnKyrHigUMZj6rYigCgxlaS3SLy0a", + "body": "SGVsbG8sIHRoaXMgaXMgYSB0ZXN0Lg==", + "attributes": { + "ApproximateReceiveCount": "1", + "SentTimestamp": "1545082649183", + "SenderId": "AIDAIENQZJOLO23YVJ4VO", + "ApproximateFirstReceiveTimestamp": "1545082649185" + }, + "messageAttributes": {}, + "md5OfBody": "e4e68fb7bd0e697a0ae8f1bb342846b3", + "eventSource": "aws:sqs", + "eventSourceARN": "arn:aws:sqs:us-east-2: 123456789012:my-queue", + "awsRegion": "us-east-1" + } + ] +} diff --git a/docs/snippets/batch/samples/sampleSQSResponse.json b/docs/snippets/batch/samples/sampleSQSResponse.json new file mode 100644 index 0000000000..9802316a68 --- /dev/null +++ b/docs/snippets/batch/samples/sampleSQSResponse.json @@ -0,0 +1,7 @@ +{ + "batchItemFailures": [ + { + "itemIdentifier": "244fc6b4-87a3-44ab-83d2-361172410c3a" + } + ] +} diff --git a/docs/snippets/batch/templates/sam/dynamodb.yaml b/docs/snippets/batch/templates/sam/dynamodb.yaml new file mode 100644 index 0000000000..c95dea07b7 --- /dev/null +++ b/docs/snippets/batch/templates/sam/dynamodb.yaml @@ -0,0 +1,66 @@ +AWSTemplateFormatVersion: '2010-09-09' +Transform: AWS::Serverless-2016-10-31 +Description: partial batch response sample + +Globals: + Function: + Timeout: 5 + MemorySize: 256 + Runtime: nodejs18.x + Tracing: Active + Environment: + Variables: + LOG_LEVEL: INFO + POWERTOOLS_SERVICE_NAME: hello + +Resources: + HelloWorldFunction: + Type: AWS::Serverless::Function + Properties: + Handler: index.handler + CodeUri: hello_world + Policies: + # Lambda Destinations require additional permissions + # to send failure records from Kinesis/DynamoDB + - Version: '2012-10-17' + Statement: + Effect: 'Allow' + Action: + - sqs:GetQueueAttributes + - sqs:GetQueueUrl + - sqs:SendMessage + Resource: !GetAtt SampleDLQ.Arn + Events: + DynamoDBStream: + Type: DynamoDB + Properties: + Stream: !GetAtt SampleTable.StreamArn + StartingPosition: LATEST + MaximumRetryAttempts: 2 + DestinationConfig: + OnFailure: + Destination: !GetAtt SampleDLQ.Arn + FunctionResponseTypes: + - ReportBatchItemFailures + + SampleDLQ: + Type: AWS::SQS::Queue + + SampleTable: + Type: AWS::DynamoDB::Table + Properties: + BillingMode: PAY_PER_REQUEST + AttributeDefinitions: + - AttributeName: pk + AttributeType: S + - AttributeName: sk + AttributeType: S + KeySchema: + - AttributeName: pk + KeyType: HASH + - AttributeName: sk + KeyType: RANGE + SSESpecification: + SSEEnabled: true + StreamSpecification: + StreamViewType: NEW_AND_OLD_IMAGES diff --git a/docs/snippets/batch/templates/sam/kinesis.yaml b/docs/snippets/batch/templates/sam/kinesis.yaml new file mode 100644 index 0000000000..032b354a74 --- /dev/null +++ b/docs/snippets/batch/templates/sam/kinesis.yaml @@ -0,0 +1,56 @@ +AWSTemplateFormatVersion: '2010-09-09' +Transform: AWS::Serverless-2016-10-31 +Description: partial batch response sample + +Globals: + Function: + Timeout: 5 + MemorySize: 256 + Runtime: nodejs18.x + Tracing: Active + Environment: + Variables: + LOG_LEVEL: INFO + POWERTOOLS_SERVICE_NAME: hello + +Resources: + HelloWorldFunction: + Type: AWS::Serverless::Function + Properties: + Handler: index.handler + CodeUri: hello_world + Policies: + # Lambda Destinations require additional permissions + # to send failure records to DLQ from Kinesis/DynamoDB + - Version: '2012-10-17' + Statement: + Effect: 'Allow' + Action: + - sqs:GetQueueAttributes + - sqs:GetQueueUrl + - sqs:SendMessage + Resource: !GetAtt SampleDLQ.Arn + Events: + KinesisStream: + Type: Kinesis + Properties: + Stream: !GetAtt SampleStream.Arn + BatchSize: 100 + StartingPosition: LATEST + MaximumRetryAttempts: 2 + DestinationConfig: + OnFailure: + Destination: !GetAtt SampleDLQ.Arn + FunctionResponseTypes: + - ReportBatchItemFailures + + SampleDLQ: + Type: AWS::SQS::Queue + + SampleStream: + Type: AWS::Kinesis::Stream + Properties: + ShardCount: 1 + StreamEncryption: + EncryptionType: KMS + KeyId: alias/aws/kinesis diff --git a/docs/snippets/batch/templates/sam/sqs.yaml b/docs/snippets/batch/templates/sam/sqs.yaml new file mode 100644 index 0000000000..65b91507eb --- /dev/null +++ b/docs/snippets/batch/templates/sam/sqs.yaml @@ -0,0 +1,43 @@ +AWSTemplateFormatVersion: '2010-09-09' +Transform: AWS::Serverless-2016-10-31 +Description: partial batch response sample + +Globals: + Function: + Timeout: 5 + MemorySize: 256 + Runtime: nodejs18.x + Tracing: Active + Environment: + Variables: + LOG_LEVEL: INFO + POWERTOOLS_SERVICE_NAME: hello + +Resources: + HelloWorldFunction: + Type: AWS::Serverless::Function + Properties: + Handler: index.handler + CodeUri: hello_world + Policies: + - SQSPollerPolicy: + QueueName: !GetAtt SampleQueue.QueueName + Events: + Batch: + Type: SQS + Properties: + Queue: !GetAtt SampleQueue.Arn + FunctionResponseTypes: + - ReportBatchItemFailures + + SampleDLQ: + Type: AWS::SQS::Queue + + SampleQueue: + Type: AWS::SQS::Queue + Properties: + VisibilityTimeout: 30 # Fn timeout * 6 + SqsManagedSseEnabled: true + RedrivePolicy: + maxReceiveCount: 2 + deadLetterTargetArn: !GetAtt SampleDLQ.Arn diff --git a/docs/snippets/batch/testingYourCode.ts b/docs/snippets/batch/testingYourCode.ts new file mode 100644 index 0000000000..a7ffa0e5be --- /dev/null +++ b/docs/snippets/batch/testingYourCode.ts @@ -0,0 +1,32 @@ +import { ContextExamples as dummyContext } from '@aws-lambda-powertools/commons'; +import { handler, processor } from './gettingStartedSQS'; +import sqsEvent from './samples/sampleSQSEvent.json'; + +describe('Function tests', () => { + beforeEach(() => { + jest.clearAllMocks(); + }); + + test('should return one failed message', async () => { + // Prepare + const context = dummyContext.helloworldContext; + const processorResult = processor; // access processor for additional assertions + const successfulRecord = sqsEvent.Records[0]; + const failedRecord = sqsEvent.Records[1]; + const expectedResponse = { + batchItemFailures: [ + { + itemIdentifier: failedRecord.messageId, + }, + ], + }; + + // Act + const response = await handler(sqsEvent, context); + + // Assess + expect(response).toEqual(expectedResponse); + expect(processorResult.failureMessages).toHaveLength(1); + expect(processorResult.successMessages[0]).toEqual(successfulRecord); + }); +}); diff --git a/docs/snippets/package.json b/docs/snippets/package.json index 5e067b21e3..0258196766 100644 --- a/docs/snippets/package.json +++ b/docs/snippets/package.json @@ -14,8 +14,9 @@ "lint-fix": "eslint --fix --ext .ts,.js --no-error-on-unmatched-pattern ." }, "lint-staged": { - "*.ts": "npm run lint-fix", - "*.js": "npm run lint-fix" + "*.{js,ts}": "npm run lint-fix", + "*.json": "prettier --write \"**/samples/*.json\" --single-quote false", + "*.yaml": "prettier --write \"**/templates/sam/*.yaml\"" }, "license": "MIT-0", "repository": { @@ -38,4 +39,4 @@ "axios": "^1.2.4", "hashi-vault-js": "^0.4.13" } -} \ No newline at end of file +} diff --git a/docs/snippets/tsconfig.json b/docs/snippets/tsconfig.json index 59dfbd1435..2d76b059c1 100644 --- a/docs/snippets/tsconfig.json +++ b/docs/snippets/tsconfig.json @@ -35,26 +35,19 @@ "@aws-lambda-powertools/idempotency/persistence": [ "../../packages/idempotency/lib/persistence" ], - "@aws-lambda-powertools/idempotency": [ - "../../packages/idempotency/lib" - ], + "@aws-lambda-powertools/idempotency": ["../../packages/idempotency/lib"], "@aws-lambda-powertools/idempotency/middleware": [ "../../packages/idempotency/lib/middleware" - ] - }, + ], + "@aws-lambda-powertools/batch": ["../../packages/batch/lib"] + } }, - "exclude": [ - "./node_modules" - ], + "exclude": ["./node_modules"], "watchOptions": { "watchFile": "useFsEvents", "watchDirectory": "useFsEvents", "fallbackPolling": "dynamicPriority" }, - "lib": [ - "ES2020" - ], - "types": [ - "node" - ] -} \ No newline at end of file + "lib": ["ES2020"], + "types": ["node"] +} diff --git a/docs/utilities/batch.md b/docs/utilities/batch.md new file mode 100644 index 0000000000..6c8c96d004 --- /dev/null +++ b/docs/utilities/batch.md @@ -0,0 +1,269 @@ +--- +title: Batch Processing +description: Utility +--- + + + +???+ warning + **This page refers to an unreleased utility that has yet to be published on the npm registry. Any version of the package built from source, as well as all future versions tagged with the `-alpha` suffix should be treated as experimental. Follow the [Beta release](https://github.com/aws-powertools/powertools-lambda-typescript/milestone/13) milestone for updates on the progress of this utility.** + +The batch processing utility handles partial failures when processing batches from Amazon SQS, Amazon Kinesis Data Streams, and Amazon DynamoDB Streams. + +## Key features + +* Reports batch item failures to reduce number of retries for a record upon errors +* Simple interface to process each batch record +* Build your own batch processor by extending primitives + +## Background + +When using SQS, Kinesis Data Streams, or DynamoDB Streams as a Lambda event source, your Lambda functions are triggered with a batch of messages. + +If your function fails to process any message from the batch, the entire batch returns to your queue or stream. This same batch is then retried until either condition happens first: **a)** your Lambda function returns a successful response, **b)** record reaches maximum retry attempts, or **c)** when records expire. + +With this utility, batch records are processed individually – only messages that failed to be processed return to the queue or stream for a further retry. This works when two mechanisms are in place: + +1. `ReportBatchItemFailures` is set in your SQS, Kinesis, or DynamoDB event source properties +2. [A specific response](https://docs.aws.amazon.com/lambda/latest/dg/with-sqs.html#services-sqs-batchfailurereporting){target="_blank"} is returned so Lambda knows which records should not be deleted during partial responses + + + +???+ warning "Warning: This utility lowers the chance of processing records more than once; it does not guarantee it" + We recommend implementing processing logic in an [idempotent manner](idempotency.md){target="_blank"} wherever possible. + + You can find more details on how Lambda works with either [SQS](https://docs.aws.amazon.com/lambda/latest/dg/with-sqs.html){target="_blank"}, [Kinesis](https://docs.aws.amazon.com/lambda/latest/dg/with-kinesis.html){target="_blank"}, or [DynamoDB](https://docs.aws.amazon.com/lambda/latest/dg/with-ddb.html){target="_blank"} in the AWS Documentation. + +## Getting started + +Regardless whether you're using SQS, Kinesis Data Streams or DynamoDB Streams, you must configure your Lambda function event source to use `ReportBatchItemFailures`. + +You do not need any additional IAM permissions to use this utility, except for what each event source requires. + +### Required resources + +The remaining sections of the documentation will rely on these samples. For completeness, this demonstrates IAM permissions and Dead Letter Queue where batch records will be sent after 2 retries were attempted. + +=== "SQS" + + ```yaml title="template.yaml" hl_lines="30-31" + --8<-- "docs/snippets/batch/templates/sam/sqs.yaml" + ``` + +=== "Kinesis Data Streams" + + ```yaml title="template.yaml" hl_lines="44-45" + --8<-- "docs/snippets/batch/templates/sam/kinesis.yaml" + ``` + +=== "DynamoDB Streams" + + ```yaml title="template.yaml" hl_lines="43-44" + --8<-- "docs/snippets/batch/templates/sam/dynamodb.yaml" + ``` + +### Processing messages from SQS + +Processing batches from SQS works in three stages: + +1. Instantiate **`BatchProcessor`** and choose **`EventType.SQS`** for the event type +2. Define your function to handle each batch record, and use the `SQSRecord` type annotation for autocompletion +3. Use **`processPartialResponse`** to kick off processing + +???+ info + This code example optionally uses Logger for completion. + +=== "index.ts" + + ```typescript hl_lines="1-5 14 17 29-31" + --8<-- "docs/snippets/batch/gettingStartedSQS.ts::32" + ``` + +=== "Sample response" + + The second record failed to be processed, therefore the processor added its message ID in the response. + + ```json + --8<-- "docs/snippets/batch/samples/sampleSQSResponse.json" + ``` + +=== "Sample event" + + ```json + --8<-- "docs/snippets/batch/samples/sampleSQSEvent.json" + ``` + +#### FIFO queues + +When using [SQS FIFO queues](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/FIFO-queues.html){target="_blank"}, we will stop processing messages after the first failure, and return all failed and unprocessed messages in `batchItemFailures`. +This helps preserve the ordering of messages in your queue. + +```typescript hl_lines="1-4 13 28-30" +--8<-- "docs/snippets/batch/gettingStartedSQSFifo.ts" +``` + +### Processing messages from Kinesis + +Processing batches from Kinesis works in three stages: + +1. Instantiate **`BatchProcessor`** and choose **`EventType.KinesisDataStreams`** for the event type +2. Define your function to handle each batch record, and use the `KinesisStreamRecord` type annotation for autocompletion +3. Use **`processPartialResponse`** to kick off processing + +???+ info + This code example optionally uses Logger for completion. + +=== "index.ts" + + ```typescript hl_lines="1-5 14 17 27-29" + --8<-- "docs/snippets/batch/gettingStartedKinesis.ts" + ``` + +=== "Sample response" + + The second record failed to be processed, therefore the processor added its sequence number in the response. + + ```json + --8<-- "docs/snippets/batch/samples/sampleKinesisEvent.json" + ``` + +=== "Sample event" + + ```json + --8<-- "docs/snippets/batch/samples/sampleKinesisResponse.json" + ``` + +### Processing messages from DynamoDB + +Processing batches from DynamoDB Streams works in three stages: + +1. Instantiate **`BatchProcessor`** and choose **`EventType.DynamoDBStreams`** for the event type +2. Define your function to handle each batch record, and use the `DynamoDBRecord` type annotation for autocompletion +3. Use **`processPartialResponse`** to kick off processing + +???+ info + This code example optionally uses Logger for completion. + +=== "index.ts" + + ```typescript hl_lines="1-5 14 17 32-34" + --8<-- "docs/snippets/batch/gettingStartedDynamoDBStreams.ts" + ``` + +=== "Sample response" + + The second record failed to be processed, therefore the processor added its sequence number in the response. + + ```json + --8<-- "docs/snippets/batch/samples/sampleDynamoDBStreamsResponse.json" + ``` + +=== "Sample event" + + ```json + --8<-- "docs/snippets/batch/samples/sampleDynamoDBStreamsEvent.json" + ``` + +### Partial failure mechanics + +All records in the batch will be passed to this handler for processing, even if exceptions are thrown - Here's the behaviour after completing the batch: + +* **All records successfully processed**. We will return an empty list of item failures `{'batchItemFailures': []}` +* **Partial success with some exceptions**. We will return a list of all item IDs/sequence numbers that failed processing +* **All records failed to be processed**. We will raise `BatchProcessingError` exception with a list of all exceptions raised when processing + +### Processing messages asynchronously + +You can use `AsyncBatchProcessor` class and `asyncProcessPartialResponse` function to process messages concurrently. + +???+ question "When is this useful?" + Your use case might be able to process multiple records at the same time without conflicting with one another. + + For example, imagine you need to process multiple loyalty points and incrementally save in a database. While you await the database to confirm your records are saved, you could start processing another request concurrently. + + The reason this is not the default behaviour is that not all use cases can handle concurrency safely (e.g., loyalty points must be updated in order). + +```typescript hl_lines="1-5 14 28-30" title="High-concurrency with AsyncBatchProcessor" +--8<-- "docs/snippets/batch/gettingStartedAsync.ts" +``` + +## Advanced + +### Accessing processed messages + +Use the `BatchProcessor` directly in your function to access a list of all returned values from your `recordHandler` function. + +* **When successful**. We will include a tuple with `success`, the result of `recordHandler`, and the batch record +* **When failed**. We will include a tuple with `fail`, exception as a string, and the batch record + +```typescript hl_lines="27-28 30-32 37" title="Accessing processed messages" +--8<-- "docs/snippets/batch/accessProcessedMessages.ts" +``` + +### Accessing Lambda Context + +Within your `recordHandler` function, you might need access to the Lambda context to determine how much time you have left before your function times out. + +We can automatically inject the [Lambda context](https://docs.aws.amazon.com/lambda/latest/dg/typescript-context.html){target="_blank"} into your `recordHandler` as optional second argument if you register it when using `BatchProcessor` or the `processPartialResponse` function. + +```typescript hl_lines="17 35" +--8<-- "docs/snippets/batch/accessLambdaContext.ts" +``` + +### Extending BatchProcessor + +You might want to bring custom logic to the existing `BatchProcessor` to slightly override how we handle successes and failures. + +For these scenarios, you can subclass `BatchProcessor` and quickly override `successHandler` and `failureHandler` methods: + +* **`successHandler()`** – Keeps track of successful batch records +* **`failureHandler()`** – Keeps track of failed batch records + +???+ example + Let's suppose you'd like to add a metric named `BatchRecordFailures` for each batch record that failed processing + +```typescript hl_lines="5-6 17-33 35 50-52" title="Extending failure handling mechanism in BatchProcessor" +--8<-- "docs/snippets/batch/extendingFailure.ts" +``` + +### Create your own partial processor + +You can create your own partial batch processor from scratch by inheriting the `BasePartialProcessor` class, and implementing the `prepare()`, `clean()`, `processRecord()` and `asyncProcessRecord()` abstract methods. + +* **`processRecord()`** – handles all processing logic for each individual message of a batch, including calling the `recordHandler` (`this.handler`) +* **`prepare()`** – called once as part of the processor initialization +* **`clean()`** – teardown logic called once after `processRecord` completes +* **`asyncProcessRecord()`** – If you need to implement asynchronous logic, use this method, otherwise define it in your class with empty logic + +You can then use this class as a context manager, or pass it to `processPartialResponse` to process the records in your Lambda handler function. + +```typescript hl_lines="7 11-13 19 28 39 60 71 82 92-94" title="Creating a custom batch processor" +--8<-- "docs/snippets/batch/customPartialProcessor.ts" +``` + +## Testing your code + +As there is no external calls, you can unit test your code with `BatchProcessor` quite easily. + +**Example**: + +Given a SQS batch where the first batch record succeeds and the second fails processing, we should have a single item reported in the function response. + +=== "index.test.ts" + + ```typescript + --8<-- "docs/snippets/batch/testingYourCode.ts" + ``` + +=== "index.ts" + + ```typescript + --8<-- "docs/snippets/batch/gettingStartedSQS.ts" + ``` + +=== "Sample SQS event" + + ```json title="events/sqs_event.json" + --8<-- "docs/snippets/batch/samples/sampleSQSEvent.json" + ``` \ No newline at end of file diff --git a/lerna.json b/lerna.json index 27a6315be8..ee57bfb2a1 100644 --- a/lerna.json +++ b/lerna.json @@ -6,6 +6,7 @@ "packages/metrics", "packages/parameters", "packages/idempotency", + "packages/batch", "examples/cdk", "examples/sam", "layers" diff --git a/mkdocs.yml b/mkdocs.yml index f5b7408590..f5f85643d4 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -17,6 +17,7 @@ nav: - Utilities: - utilities/parameters.md - utilities/idempotency.md + - utilities/batch.md theme: name: material diff --git a/package-lock.json b/package-lock.json index b0050f1e8e..9a430ff6eb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,6 +15,7 @@ "packages/tracer", "packages/parameters", "packages/idempotency", + "packages/batch", "docs/snippets", "layers", "examples/cdk", @@ -638,6 +639,10 @@ "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" }, + "node_modules/@aws-lambda-powertools/batch": { + "resolved": "packages/batch", + "link": true + }, "node_modules/@aws-lambda-powertools/commons": { "resolved": "packages/commons", "link": true @@ -6590,6 +6595,10 @@ ], "license": "MIT" }, + "node_modules/batch": { + "resolved": "packages/batch", + "link": true + }, "node_modules/before-after-hook": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.3.tgz", @@ -17984,6 +17993,12 @@ "node": ">= 10" } }, + "packages/batch": { + "name": "@aws-lambda-powertools/batch", + "version": "1.10.0", + "license": "MIT-0", + "devDependencies": {} + }, "packages/commons": { "name": "@aws-lambda-powertools/commons", "version": "1.11.1", @@ -18482,4 +18497,4 @@ } } } -} +} \ No newline at end of file diff --git a/package.json b/package.json index 467365c53e..73bd6845da 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,8 @@ "docs/snippets", "layers", "examples/cdk", - "examples/sam" + "examples/sam", + "packages/batch" ], "scripts": { "init-environment": "husky install", diff --git a/packages/batch/README.md b/packages/batch/README.md new file mode 100644 index 0000000000..caf8bae3ea --- /dev/null +++ b/packages/batch/README.md @@ -0,0 +1,263 @@ +# Powertools for AWS Lambda (TypeScript) - Batch Processing Utility + + +| ⚠️ **WARNING: Do not use this utility in production just yet!** ⚠️ | +| :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| **This utility is currently released as beta developer preview** and is intended strictly for feedback and testing purposes **and not for production workloads**.. The version and all future versions tagged with the `-beta` suffix should be treated as not stable. Up until before the [General Availability release](https://github.com/aws-powertools/powertools-lambda-typescript/milestone/14) we might introduce significant breaking changes and improvements in response to customers feedback. | _ | + + +Powertools for AWS Lambda (TypeScript) is a developer toolkit to implement Serverless [best practices and increase developer velocity](https://docs.powertools.aws.dev/lambda-typescript/latest/#features). + +You can use the package in both TypeScript and JavaScript code bases. + +- [Intro](#intro) +- [Key features](#key-features) +- [Usage](#usage) + - [Batch Processor](#batch-processor) + - [SQS Processor](#sqs-processor) + - [Kinesis Processor](#kinesis-processor) + - [DynamoDB Streams Processor](#dynamodb-streams-processor) + - [Async processing](#async-processing) +- [Contribute](#contribute) +- [Roadmap](#roadmap) +- [Connect](#connect) +- [How to support Powertools for AWS Lambda (TypeScript)?](#how-to-support-powertools-for-aws-lambda-typescript) + - [Becoming a reference customer](#becoming-a-reference-customer) + - [Sharing your work](#sharing-your-work) + - [Using Lambda Layer](#using-lambda-layer) +- [Credits](#credits) +- [License](#license) + +## Intro + +The batch processing utility handles partial failures when processing batches from Amazon SQS, Amazon Kinesis Data Streams, and Amazon DynamoDB Streams. + +## Key features + +* Reports batch item failures to reduce number of retries for a record upon errors +* Simple interface to process each batch record +* Build your own batch processor by extending primitives + +## Usage + +To get started, install the library by running: + +```sh +npm install @aws-lambda-powertools/batch +``` + +### Batch Processor + +When using SQS, Kinesis Data Streams, or DynamoDB Streams as a Lambda event source, your Lambda functions are triggered with a batch of messages. + +If your function fails to process any message from the batch, the entire batch returns to your queue or stream. This same batch is then retried until either condition happens first: **a)** your Lambda function returns a successful response, **b)** record reaches maximum retry attempts, or **c)** when records expire. + +With this utility, batch records are processed individually – only messages that failed to be processed return to the queue or stream for a further retry. + +### SQS Processor + +When using SQS as a Lambda event source, you can specify the `EventType.SQS` to process the records. The response will be a `SQSBatchResponse` which contains a list of items that failed to be processed. + +```ts +import { + BatchProcessor, + EventType, + processPartialResponse, +} from '@aws-lambda-powertools/batch'; +import { Logger } from '@aws-lambda-powertools/logger'; +import type { + SQSEvent, + SQSRecord, + Context, + SQSBatchResponse, +} from 'aws-lambda'; + +const processor = new BatchProcessor(EventType.SQS); +const logger = new Logger(); + +const recordHandler = (record: SQSRecord): void => { + const payload = record.body; + if (payload) { + const item = JSON.parse(payload); + logger.info('Processed item', { item }); + } +}; + +export const handler = async ( + event: SQSEvent, + context: Context +): Promise => { + return processPartialResponse(event, recordHandler, processor, { + context, + }); +}; +export { processor }; +``` + +### Kinesis Processor + +When using Kinesis Data Streams as a Lambda event source, you can specify the `EventType.KinesisDataStreams` to process the records. The response will be a `KinesisStreamBatchResponse` which contains a list of items that failed to be processed. + +```ts +import { + BatchProcessor, + EventType, + processPartialResponse, +} from '@aws-lambda-powertools/batch'; +import { Logger } from '@aws-lambda-powertools/logger'; +import type { + KinesisStreamEvent, + KinesisStreamRecord, + Context, + KinesisStreamBatchResponse, +} from 'aws-lambda'; + +const processor = new BatchProcessor(EventType.KinesisDataStreams); +const logger = new Logger(); + +const recordHandler = (record: KinesisStreamRecord): void => { + logger.info('Processing record', { record: record.kinesis.data }); + const payload = JSON.parse(record.kinesis.data); + logger.info('Processed item', { item: payload }); +}; + +export const handler = async ( + event: KinesisStreamEvent, + context: Context +): Promise => { + return processPartialResponse(event, recordHandler, processor, { + context, + }); +}; +``` + +### DynamoDB Streams Processor + +When using DynamoDB Streams as a Lambda event source, you can use the `BatchProcessor` with the `EventType.DynamoDBStreams` to process the records. The response will be a `DynamoDBBatchResponse` which contains a list of items that failed to be processed. + +```ts +import { + BatchProcessor, + EventType, + processPartialResponse, +} from '@aws-lambda-powertools/batch'; +import { Logger } from '@aws-lambda-powertools/logger'; +import type { + DynamoDBStreamEvent, + DynamoDBRecord, + Context, + DynamoDBBatchResponse, +} from 'aws-lambda'; + +const processor = new BatchProcessor(EventType.DynamoDBStreams); +const logger = new Logger(); + +const recordHandler = (record: DynamoDBRecord): void => { + if (record.dynamodb && record.dynamodb.NewImage) { + logger.info('Processing record', { record: record.dynamodb.NewImage }); + const message = record.dynamodb.NewImage.Message.S; + if (message) { + const payload = JSON.parse(message); + logger.info('Processed item', { item: payload }); + } + } +}; + +export const handler = async ( + event: DynamoDBStreamEvent, + context: Context +): Promise => { + return processPartialResponse(event, recordHandler, processor, { + context, + }); +}; +``` + +### Async processing + +If your use case allows you to process multiple records at the same time without conflicting with each other, you can use the `AsyncBatchProcessor` to process records asynchronously. This will create an array of promises that will be resolved once all records have been processed. + +```ts +import { + AsyncBatchProcessor, + EventType, + asyncProcessPartialResponse, +} from '@aws-lambda-powertools/batch'; +import axios from 'axios'; // axios is an external dependency +import type { + SQSEvent, + SQSRecord, + Context, + SQSBatchResponse, +} from 'aws-lambda'; + +const processor = new AsyncBatchProcessor(EventType.SQS); + +const recordHandler = async (record: SQSRecord): Promise => { + const res = await axios.post('https://httpbin.org/anything', { + message: record.body, + }); + + return res.status; +}; + +export const handler = async ( + event: SQSEvent, + context: Context +): Promise => { + return await asyncProcessPartialResponse(event, recordHandler, processor, { + context, + }); +}; +``` + +Check the [docs](https://docs.powertools.aws.dev/lambda/typescript/latest/utilities/batch/) for more examples. + + + +## Contribute + +If you are interested in contributing to this project, please refer to our [Contributing Guidelines](https://github.com/aws-powertools/powertools-lambda-typescript/blob/main/CONTRIBUTING.md). + +## Roadmap + +The roadmap of Powertools for AWS Lambda (TypeScript) is driven by customers’ demand. +Help us prioritize upcoming functionalities or utilities by [upvoting existing RFCs and feature requests](https://github.com/aws-powertools/powertools-lambda-typescript/issues), or [creating new ones](https://github.com/aws-powertools/powertools-lambda-typescript/issues/new/choose), in this GitHub repository. + +## Connect + +* **Powertools for AWS Lambda on Discord**: `#typescript` - **[Invite link](https://discord.gg/B8zZKbbyET)** +* **Email**: aws-lambda-powertools-feedback@amazon.com + +## How to support Powertools for AWS Lambda (TypeScript)? + +### Becoming a reference customer + +Knowing which companies are using this library is important to help prioritize the project internally. If your company is using Powertools for AWS Lambda (TypeScript), you can request to have your name and logo added to the README file by raising a [Support Powertools for AWS Lambda (TypeScript) (become a reference)](https://github.com/aws-powertools/powertools-lambda-typescript/issues/new?assignees=&labels=customer-reference&template=support_powertools.yml&title=%5BSupport+Lambda+Powertools%5D%3A+%3Cyour+organization+name%3E) issue. + +The following companies, among others, use Powertools: + +* [Hashnode](https://hashnode.com/) +* [Trek10](https://www.trek10.com/) +* [Elva](https://elva-group.com) +* [globaldatanet](https://globaldatanet.com/) +* [Bailey Nelson](https://www.baileynelson.com.au) +* [Perfect Post](https://www.perfectpost.fr) +* [Sennder](https://sennder.com/) +* [Certible](https://www.certible.com/) + +### Sharing your work + +Share what you did with Powertools for AWS Lambda (TypeScript) 💞💞. Blog post, workshops, presentation, sample apps and others. Check out what the community has already shared about Powertools for AWS Lambda (TypeScript) [here](https://docs.powertools.aws.dev/lambda-typescript/latest/we_made_this). + +### Using Lambda Layer + +This helps us understand who uses Powertools for AWS Lambda (TypeScript) in a non-intrusive way, and helps us gain future investments for other Powertools for AWS Lambda languages. When [using Layers](#lambda-layers), you can add Powertools as a dev dependency (or as part of your virtual env) to not impact the development process. + +## Credits + +Credits for the Lambda Powertools for AWS Lambda (TypeScript) idea go to [DAZN](https://github.com/getndazn) and their [DAZN Lambda Powertools](https://github.com/getndazn/dazn-lambda-powertools/). + +## License + +This library is licensed under the MIT-0 License. See the LICENSE file. diff --git a/packages/batch/jest.config.js b/packages/batch/jest.config.js new file mode 100644 index 0000000000..3db7c7a6da --- /dev/null +++ b/packages/batch/jest.config.js @@ -0,0 +1,28 @@ +module.exports = { + displayName: { + name: 'Powertools for AWS Lambda (TypeScript) utility: BATCH', + color: 'orange', + }, + runner: 'groups', + preset: 'ts-jest', + transform: { + '^.+\\.ts?$': 'ts-jest', + }, + moduleFileExtensions: ['js', 'ts'], + collectCoverageFrom: ['**/src/**/*.ts', '!**/node_modules/**'], + testMatch: ['**/?(*.)+(spec|test).ts'], + roots: ['/src', '/tests'], + testPathIgnorePatterns: ['/node_modules/'], + testEnvironment: 'node', + coveragePathIgnorePatterns: ['/node_modules/', '/types/'], + coverageThreshold: { + global: { + statements: 100, + branches: 100, + functions: 100, + lines: 100, + }, + }, + coverageReporters: ['json-summary', 'text', 'lcov'], + setupFiles: ['/tests/helpers/populateEnvironmentVariables.ts'], +}; diff --git a/packages/batch/package.json b/packages/batch/package.json new file mode 100644 index 0000000000..f87fb225ac --- /dev/null +++ b/packages/batch/package.json @@ -0,0 +1,54 @@ +{ + "name": "@aws-lambda-powertools/batch", + "version": "1.11.1", + "description": "The batch processing package for the Powertools for AWS Lambda (TypeScript) library.", + "author": { + "name": "Amazon Web Services", + "url": "https://aws.amazon.com" + }, + "publishConfig": { + "access": "public" + }, + "scripts": { + "test": "npm run test:unit", + "test:unit": "jest --group=unit --detectOpenHandles --coverage --verbose", + "test:e2e:nodejs14x": "echo 'Not Implemented'", + "test:e2e:nodejs16x": "echo 'Not Implemented'", + "test:e2e:nodejs18x": "echo 'Not Implemented'", + "test:e2e": "echo 'Not Implemented'", + "watch": "jest --watch", + "build": "tsc", + "lint": "eslint --ext .ts,.js --no-error-on-unmatched-pattern .", + "lint-fix": "eslint --fix --ext .ts,.js --no-error-on-unmatched-pattern .", + "prebuild": "rimraf ./lib", + "prepack": "node ../../.github/scripts/release_patch_package_json.js ." + }, + "lint-staged": { + "*.{js,ts}": "npm run lint-fix" + }, + "homepage": "https://github.com/aws-powertools/powertools-lambda-typescript/tree/main/packages/batch#readme", + "license": "MIT-0", + "main": "./lib/index.js", + "types": "./lib/index.d.ts", + "files": [ + "lib" + ], + "repository": { + "type": "git", + "url": "git+https://github.com/aws-powertools/powertools-lambda-typescript.git" + }, + "bugs": { + "url": "https://github.com/aws-powertools/powertools-lambda-typescript/issues" + }, + "dependencies": {}, + "keywords": [ + "aws", + "lambda", + "powertools", + "batch", + "batch-processing", + "serverless", + "nodejs" + ], + "devDependencies": {} +} \ No newline at end of file diff --git a/packages/batch/src/AsyncBatchProcessor.ts b/packages/batch/src/AsyncBatchProcessor.ts new file mode 100644 index 0000000000..781c7f1c79 --- /dev/null +++ b/packages/batch/src/AsyncBatchProcessor.ts @@ -0,0 +1,31 @@ +import { BasePartialBatchProcessor } from './BasePartialBatchProcessor'; +import type { BaseRecord, FailureResponse, SuccessResponse } from './types'; + +/** + * Process native partial responses from SQS, Kinesis Data Streams, and DynamoDB + */ +class AsyncBatchProcessor extends BasePartialBatchProcessor { + public async asyncProcessRecord( + record: BaseRecord + ): Promise { + try { + const data = this.toBatchType(record, this.eventType); + const result = await this.handler(data, this.options); + + return this.successHandler(record, result); + } catch (error) { + return this.failureHandler(record, error as Error); + } + } + + /** + * Process a record with instance's handler + * @param record Batch record to be processed + * @returns response of success or failure + */ + public processRecord(_record: BaseRecord): SuccessResponse | FailureResponse { + throw new Error('Not implemented. Use asyncProcess() instead.'); + } +} + +export { AsyncBatchProcessor }; diff --git a/packages/batch/src/BasePartialBatchProcessor.ts b/packages/batch/src/BasePartialBatchProcessor.ts new file mode 100644 index 0000000000..d4cfd7e9ce --- /dev/null +++ b/packages/batch/src/BasePartialBatchProcessor.ts @@ -0,0 +1,157 @@ +import type { + DynamoDBRecord, + KinesisStreamRecord, + SQSRecord, +} from 'aws-lambda'; +import { BasePartialProcessor } from './BasePartialProcessor'; +import { DATA_CLASS_MAPPING, DEFAULT_RESPONSE, EventType } from './constants'; +import { BatchProcessingError } from './errors'; +import type { + EventSourceDataClassTypes, + PartialItemFailureResponse, + PartialItemFailures, +} from './types'; + +/** + * Process batch and partially report failed items + */ +abstract class BasePartialBatchProcessor extends BasePartialProcessor { + public COLLECTOR_MAPPING; + + public batchResponse: PartialItemFailureResponse; + + public eventType: keyof typeof EventType; + + /** + * Initializes base batch processing class + * @param eventType Whether this is SQS, DynamoDB stream, or Kinesis data stream event + */ + public constructor(eventType: keyof typeof EventType) { + super(); + this.eventType = eventType; + this.batchResponse = DEFAULT_RESPONSE; + this.COLLECTOR_MAPPING = { + [EventType.SQS]: () => this.collectSqsFailures(), + [EventType.KinesisDataStreams]: () => this.collectKinesisFailures(), + [EventType.DynamoDBStreams]: () => this.collectDynamoDBFailures(), + }; + } + + /** + * Report messages to be deleted in case of partial failures + */ + public clean(): void { + if (!this.hasMessagesToReport()) { + return; + } + + if (this.entireBatchFailed()) { + throw new BatchProcessingError( + 'All records failed processing. ' + + this.exceptions.length + + ' individual errors logged separately below.', + this.exceptions + ); + } + + const messages: PartialItemFailures[] = this.getMessagesToReport(); + this.batchResponse = { batchItemFailures: messages }; + } + + /** + * Collects identifiers of failed items for a DynamoDB stream + * @returns list of identifiers for failed items + */ + public collectDynamoDBFailures(): PartialItemFailures[] { + const failures: PartialItemFailures[] = []; + + for (const msg of this.failureMessages) { + const msgId = (msg as DynamoDBRecord).dynamodb?.SequenceNumber; + if (msgId) { + failures.push({ itemIdentifier: msgId }); + } + } + + return failures; + } + + /** + * Collects identifiers of failed items for a Kinesis stream + * @returns list of identifiers for failed items + */ + public collectKinesisFailures(): PartialItemFailures[] { + const failures: PartialItemFailures[] = []; + + for (const msg of this.failureMessages) { + const msgId = (msg as KinesisStreamRecord).kinesis.sequenceNumber; + failures.push({ itemIdentifier: msgId }); + } + + return failures; + } + + /** + * Collects identifiers of failed items for an SQS batch + * @returns list of identifiers for failed items + */ + public collectSqsFailures(): PartialItemFailures[] { + const failures: PartialItemFailures[] = []; + + for (const msg of this.failureMessages) { + const msgId = (msg as SQSRecord).messageId; + failures.push({ itemIdentifier: msgId }); + } + + return failures; + } + + /** + * Determines whether all records in a batch failed to process + * @returns true if all records resulted in exception results + */ + public entireBatchFailed(): boolean { + return this.exceptions.length == this.records.length; + } + + /** + * Collects identifiers for failed batch items + * @returns formatted messages to use in batch deletion + */ + public getMessagesToReport(): PartialItemFailures[] { + return this.COLLECTOR_MAPPING[this.eventType](); + } + + /** + * Determines if any records failed to process + * @returns true if any records resulted in exception + */ + public hasMessagesToReport(): boolean { + return this.failureMessages.length != 0; + } + + /** + * Remove results from previous execution + */ + public prepare(): void { + this.successMessages.length = 0; + this.failureMessages.length = 0; + this.exceptions.length = 0; + this.batchResponse = DEFAULT_RESPONSE; + } + + /** + * @returns Batch items that failed processing, if any + */ + public response(): PartialItemFailureResponse { + return this.batchResponse; + } + + public toBatchType( + record: EventSourceDataClassTypes, + eventType: keyof typeof EventType + ): SQSRecord | KinesisStreamRecord | DynamoDBRecord { + return DATA_CLASS_MAPPING[eventType](record); + } +} + +export { BasePartialBatchProcessor }; diff --git a/packages/batch/src/BasePartialProcessor.ts b/packages/batch/src/BasePartialProcessor.ts new file mode 100644 index 0000000000..ecd62c29b0 --- /dev/null +++ b/packages/batch/src/BasePartialProcessor.ts @@ -0,0 +1,168 @@ +import type { + BaseRecord, + BatchProcessingOptions, + EventSourceDataClassTypes, + FailureResponse, + ResultType, + SuccessResponse, +} from './types'; + +/** + * Abstract class for batch processors. + */ +abstract class BasePartialProcessor { + public exceptions: Error[]; + + public failureMessages: EventSourceDataClassTypes[]; + + public handler: CallableFunction; + + public options?: BatchProcessingOptions; + + public records: BaseRecord[]; + + public successMessages: EventSourceDataClassTypes[]; + + /** + * Initializes base processor class + */ + public constructor() { + this.successMessages = []; + this.failureMessages = []; + this.exceptions = []; + this.records = []; + this.handler = new Function(); + } + + /** + * Call instance's handler for each record + * @returns List of processed records + */ + public async asyncProcess(): Promise<(SuccessResponse | FailureResponse)[]> { + /** + * If this is an sync processor, user should have called process instead, + * so we call the method early to throw the error early thus failing fast. + */ + if (this.constructor.name === 'BatchProcessor') { + await this.asyncProcessRecord(this.records[0]); + } + this.prepare(); + + const processingPromises: Promise[] = + this.records.map((record) => this.asyncProcessRecord(record)); + + const processedRecords: (SuccessResponse | FailureResponse)[] = + await Promise.all(processingPromises); + + this.clean(); + + return processedRecords; + } + + /** + * Process a record with an asyncronous handler + * + * @param record Record to be processed + */ + public abstract asyncProcessRecord( + record: BaseRecord + ): Promise; + + /** + * Clean class instance after processing + */ + public abstract clean(): void; + + /** + * Keeps track of batch records that failed processing + * @param record record that failed processing + * @param exception exception that was thrown + * @returns FailureResponse object with ["fail", exception, original record] + */ + public failureHandler( + record: EventSourceDataClassTypes, + exception: Error + ): FailureResponse { + const entry: FailureResponse = ['fail', exception.message, record]; + this.exceptions.push(exception); + this.failureMessages.push(record); + + return entry; + } + + /** + * Prepare class instance before processing + */ + public abstract prepare(): void; + + /** + * Call instance's handler for each record + * @returns List of processed records + */ + public process(): (SuccessResponse | FailureResponse)[] { + /** + * If this is an async processor, user should have called processAsync instead, + * so we call the method early to throw the error early thus failing fast. + */ + if (this.constructor.name === 'AsyncBatchProcessor') { + this.processRecord(this.records[0]); + } + this.prepare(); + + const processedRecords: (SuccessResponse | FailureResponse)[] = []; + for (const record of this.records) { + processedRecords.push(this.processRecord(record)); + } + + this.clean(); + + return processedRecords; + } + + /** + * Process a record with the handler + * @param record Record to be processed + */ + public abstract processRecord( + record: BaseRecord + ): SuccessResponse | FailureResponse; + + /** + * Set class instance attributes before execution + * @param records List of records to be processed + * @param handler CallableFunction to process entries of "records" + * @returns this object + */ + public register( + records: BaseRecord[], + handler: CallableFunction, + options?: BatchProcessingOptions + ): BasePartialProcessor { + this.records = records; + this.handler = handler; + + if (options) { + this.options = options; + } + + return this; + } + + /** + * Keeps track of batch records that were processed successfully + * @param record record that succeeded processing + * @param result result from record handler + * @returns SuccessResponse object with ["success", result, original record] + */ + public successHandler( + record: EventSourceDataClassTypes, + result: ResultType + ): SuccessResponse { + const entry: SuccessResponse = ['success', result, record]; + this.successMessages.push(record); + + return entry; + } +} + +export { BasePartialProcessor }; diff --git a/packages/batch/src/BatchProcessor.ts b/packages/batch/src/BatchProcessor.ts new file mode 100644 index 0000000000..3d2a75a8da --- /dev/null +++ b/packages/batch/src/BatchProcessor.ts @@ -0,0 +1,31 @@ +import { BasePartialBatchProcessor } from './BasePartialBatchProcessor'; +import type { BaseRecord, FailureResponse, SuccessResponse } from './types'; + +/** + * Process native partial responses from SQS, Kinesis Data Streams, and DynamoDB + */ +class BatchProcessor extends BasePartialBatchProcessor { + public async asyncProcessRecord( + _record: BaseRecord + ): Promise { + throw new Error('Not implemented. Use process() instead.'); + } + + /** + * Process a record with instance's handler + * @param record Batch record to be processed + * @returns response of success or failure + */ + public processRecord(record: BaseRecord): SuccessResponse | FailureResponse { + try { + const data = this.toBatchType(record, this.eventType); + const result = this.handler(data, this.options); + + return this.successHandler(record, result); + } catch (error) { + return this.failureHandler(record, error as Error); + } + } +} + +export { BatchProcessor }; diff --git a/packages/batch/src/SqsFifoPartialProcessor.ts b/packages/batch/src/SqsFifoPartialProcessor.ts new file mode 100644 index 0000000000..0c10993273 --- /dev/null +++ b/packages/batch/src/SqsFifoPartialProcessor.ts @@ -0,0 +1,68 @@ +import { BatchProcessor } from './BatchProcessor'; +import { EventType } from './constants'; +import type { FailureResponse, SuccessResponse } from './types'; + +/** + * Process native partial responses from SQS FIFO queues + * Stops processing records when the first record fails + * The remaining records are reported as failed items + */ +class SqsFifoPartialProcessor extends BatchProcessor { + public constructor() { + super(EventType.SQS); + } + + /** + * Call instance's handler for each record. + * When the first failed message is detected, the process is short-circuited + * And the remaining messages are reported as failed items + */ + public process(): (SuccessResponse | FailureResponse)[] { + this.prepare(); + + const processedRecords: (SuccessResponse | FailureResponse)[] = []; + let currentIndex = 0; + for (const record of this.records) { + // If we have any failed messages, it means the last message failed + // We should then short circuit the process and fail remaining messages + if (this.failureMessages.length != 0) { + return this.shortCircuitProcessing(currentIndex, processedRecords); + } + + processedRecords.push(this.processRecord(record)); + currentIndex++; + } + + this.clean(); + + return processedRecords; + } + + /** + * Starting from the first failure index, fail all remaining messages and append them to the result list + * @param firstFailureIndex Index of first message that failed + * @param result List of success and failure responses with remaining messages failed + */ + public shortCircuitProcessing( + firstFailureIndex: number, + processedRecords: (SuccessResponse | FailureResponse)[] + ): (SuccessResponse | FailureResponse)[] { + const remainingRecords = this.records.slice(firstFailureIndex); + + for (const record of remainingRecords) { + const data = this.toBatchType(record, this.eventType); + processedRecords.push( + this.failureHandler( + data, + new Error('A previous record failed processing') + ) + ); + } + + this.clean(); + + return processedRecords; + } +} + +export { SqsFifoPartialProcessor }; diff --git a/packages/batch/src/asyncProcessPartialResponse.ts b/packages/batch/src/asyncProcessPartialResponse.ts new file mode 100644 index 0000000000..eee584ed1f --- /dev/null +++ b/packages/batch/src/asyncProcessPartialResponse.ts @@ -0,0 +1,38 @@ +import { BasePartialBatchProcessor } from './BasePartialBatchProcessor'; +import { EventType } from './constants'; +import type { + BaseRecord, + BatchProcessingOptions, + PartialItemFailureResponse, +} from './types'; + +/** + * Higher level function to handle batch event processing + * @param event Lambda's original event + * @param recordHandler Callable function to process each record from the batch + * @param processor Batch processor to handle partial failure cases + * @returns Lambda Partial Batch Response + */ +const asyncProcessPartialResponse = async ( + event: { Records: BaseRecord[] }, + recordHandler: CallableFunction, + processor: BasePartialBatchProcessor, + options?: BatchProcessingOptions +): Promise => { + if (!event.Records) { + const eventTypes: string = Object.values(EventType).toString(); + throw new Error( + 'Failed to convert event to record batch for processing.\nPlease ensure batch event is a valid ' + + eventTypes + + ' event.' + ); + } + + processor.register(event.Records, recordHandler, options); + + await processor.asyncProcess(); + + return processor.response(); +}; + +export { asyncProcessPartialResponse }; diff --git a/packages/batch/src/constants.ts b/packages/batch/src/constants.ts new file mode 100644 index 0000000000..02437e356c --- /dev/null +++ b/packages/batch/src/constants.ts @@ -0,0 +1,25 @@ +import { DynamoDBRecord, KinesisStreamRecord, SQSRecord } from 'aws-lambda'; +import type { + PartialItemFailureResponse, + EventSourceDataClassTypes, +} from './types'; + +const EventType = { + SQS: 'SQS', + KinesisDataStreams: 'KinesisDataStreams', + DynamoDBStreams: 'DynamoDBStreams', +} as const; + +const DEFAULT_RESPONSE: PartialItemFailureResponse = { + batchItemFailures: [], +}; + +const DATA_CLASS_MAPPING = { + [EventType.SQS]: (record: EventSourceDataClassTypes) => record as SQSRecord, + [EventType.KinesisDataStreams]: (record: EventSourceDataClassTypes) => + record as KinesisStreamRecord, + [EventType.DynamoDBStreams]: (record: EventSourceDataClassTypes) => + record as DynamoDBRecord, +}; + +export { EventType, DEFAULT_RESPONSE, DATA_CLASS_MAPPING }; diff --git a/packages/batch/src/errors.ts b/packages/batch/src/errors.ts new file mode 100644 index 0000000000..ed5bd4fc9e --- /dev/null +++ b/packages/batch/src/errors.ts @@ -0,0 +1,49 @@ +/** + * Base error type for batch processing + * All errors thrown by major failures extend this base class + */ +class BaseBatchProcessingError extends Error { + public childErrors: Error[]; + + public msg: string; + + public constructor(msg: string, childErrors: Error[]) { + super(msg); + this.msg = msg; + this.childErrors = childErrors; + } + + /** + * Generates a list of errors that were generated by the major failure + * @returns Formatted string listing all the errors that occurred + * + * @example + * When all batch records fail to be processed, this will generate a string like: + * All records failed processing. 3 individual errors logged separately below. + * ,Failed to process record. + * ,Failed to process record. + * ,Failed to process record. + */ + public formatErrors(parentErrorString: string): string { + const errorList: string[] = [parentErrorString + '\n']; + + for (const error of this.childErrors) { + errorList.push(error.message + '\n'); + } + + return '\n' + errorList; + } +} + +/** + * When all batch records failed to be processed + */ +class BatchProcessingError extends BaseBatchProcessingError { + public constructor(msg: string, childErrors: Error[]) { + super(msg, childErrors); + const parentErrorString: string = this.message; + this.message = this.formatErrors(parentErrorString); + } +} + +export { BaseBatchProcessingError, BatchProcessingError }; diff --git a/packages/batch/src/index.ts b/packages/batch/src/index.ts new file mode 100644 index 0000000000..96f931823d --- /dev/null +++ b/packages/batch/src/index.ts @@ -0,0 +1,10 @@ +export * from './constants'; +export * from './errors'; +export * from './types'; +export * from './BasePartialProcessor'; +export * from './BasePartialBatchProcessor'; +export * from './BatchProcessor'; +export * from './AsyncBatchProcessor'; +export * from './processPartialResponse'; +export * from './asyncProcessPartialResponse'; +export * from './SqsFifoPartialProcessor'; diff --git a/packages/batch/src/processPartialResponse.ts b/packages/batch/src/processPartialResponse.ts new file mode 100644 index 0000000000..d09e7be6b9 --- /dev/null +++ b/packages/batch/src/processPartialResponse.ts @@ -0,0 +1,38 @@ +import { BasePartialBatchProcessor } from './BasePartialBatchProcessor'; +import { EventType } from './constants'; +import type { + BaseRecord, + BatchProcessingOptions, + PartialItemFailureResponse, +} from './types'; + +/** + * Higher level function to handle batch event processing + * @param event Lambda's original event + * @param recordHandler Callable function to process each record from the batch + * @param processor Batch processor to handle partial failure cases + * @returns Lambda Partial Batch Response + */ +const processPartialResponse = ( + event: { Records: BaseRecord[] }, + recordHandler: CallableFunction, + processor: BasePartialBatchProcessor, + options?: BatchProcessingOptions +): PartialItemFailureResponse => { + if (!event.Records) { + const eventTypes: string = Object.values(EventType).toString(); + throw new Error( + 'Failed to convert event to record batch for processing.\nPlease ensure batch event is a valid ' + + eventTypes + + ' event.' + ); + } + + processor.register(event.Records, recordHandler, options); + + processor.process(); + + return processor.response(); +}; + +export { processPartialResponse }; diff --git a/packages/batch/src/types.ts b/packages/batch/src/types.ts new file mode 100644 index 0000000000..17ce3633c7 --- /dev/null +++ b/packages/batch/src/types.ts @@ -0,0 +1,37 @@ +import { + Context, + DynamoDBRecord, + KinesisStreamRecord, + SQSRecord, +} from 'aws-lambda'; + +type BatchProcessingOptions = { + context: Context; +}; + +type EventSourceDataClassTypes = + | SQSRecord + | KinesisStreamRecord + | DynamoDBRecord; + +type RecordValue = unknown; +type BaseRecord = { [key: string]: RecordValue } | EventSourceDataClassTypes; + +type ResultType = unknown; +type SuccessResponse = ['success', ResultType, EventSourceDataClassTypes]; + +type FailureResponse = ['fail', string, EventSourceDataClassTypes]; + +type PartialItemFailures = { itemIdentifier: string }; +type PartialItemFailureResponse = { batchItemFailures: PartialItemFailures[] }; + +export type { + BatchProcessingOptions, + BaseRecord, + EventSourceDataClassTypes, + ResultType, + SuccessResponse, + FailureResponse, + PartialItemFailures, + PartialItemFailureResponse, +}; diff --git a/packages/batch/tests/helpers/factories.ts b/packages/batch/tests/helpers/factories.ts new file mode 100644 index 0000000000..7df6110742 --- /dev/null +++ b/packages/batch/tests/helpers/factories.ts @@ -0,0 +1,75 @@ +import type { + DynamoDBRecord, + KinesisStreamRecord, + SQSRecord, +} from 'aws-lambda'; +import { randomInt, randomUUID } from 'node:crypto'; + +const sqsRecordFactory = (body: string): SQSRecord => { + return { + messageId: randomUUID(), + receiptHandle: 'AQEBwJnKyrHigUMZj6rYigCgxlaS3SLy0a', + body: body, + attributes: { + ApproximateReceiveCount: '1', + SentTimestamp: '1545082649183', + SenderId: 'AIDAIENQZJOLO23YVJ4VO', + ApproximateFirstReceiveTimestamp: '1545082649185', + }, + messageAttributes: {}, + md5OfBody: 'e4e68fb7bd0e697a0ae8f1bb342846b3', + eventSource: 'aws:sqs', + eventSourceARN: 'arn:aws:sqs:us-east-2:123456789012:my-queue', + awsRegion: 'us-east-1', + }; +}; + +const kinesisRecordFactory = (body: string): KinesisStreamRecord => { + let seq = ''; + for (let i = 0; i < 52; i++) { + seq = seq + randomInt(10); + } + + return { + kinesis: { + kinesisSchemaVersion: '1.0', + partitionKey: '1', + sequenceNumber: seq, + data: body, + approximateArrivalTimestamp: 1545084650.987, + }, + eventSource: 'aws:kinesis', + eventVersion: '1.0', + eventID: 'shardId-000000000006:' + seq, + eventName: 'aws:kinesis:record', + invokeIdentityArn: 'arn:aws:iam::123456789012:role/lambda-role', + awsRegion: 'us-east-2', + eventSourceARN: + 'arn:aws:kinesis:us-east-2:123456789012:stream/lambda-stream', + }; +}; + +const dynamodbRecordFactory = (body: string): DynamoDBRecord => { + let seq = ''; + for (let i = 0; i < 10; i++) { + seq = seq + randomInt(10); + } + + return { + eventID: '1', + eventVersion: '1.0', + dynamodb: { + Keys: { Id: { N: '101' } }, + NewImage: { Message: { S: body } }, + StreamViewType: 'NEW_AND_OLD_IMAGES', + SequenceNumber: seq, + SizeBytes: 26, + }, + awsRegion: 'us-west-2', + eventName: 'INSERT', + eventSourceARN: 'eventsource_arn', + eventSource: 'aws:dynamodb', + }; +}; + +export { sqsRecordFactory, kinesisRecordFactory, dynamodbRecordFactory }; diff --git a/packages/batch/tests/helpers/handlers.ts b/packages/batch/tests/helpers/handlers.ts new file mode 100644 index 0000000000..3a6d17b76a --- /dev/null +++ b/packages/batch/tests/helpers/handlers.ts @@ -0,0 +1,109 @@ +import type { + DynamoDBRecord, + KinesisStreamRecord, + SQSRecord, +} from 'aws-lambda'; +import type { BatchProcessingOptions } from '../../src/types'; + +const sqsRecordHandler = (record: SQSRecord): string => { + const body = record.body; + if (body.includes('fail')) { + throw Error('Failed to process record.'); + } + + return body; +}; + +const asyncSqsRecordHandler = async (record: SQSRecord): Promise => { + const body = record.body; + if (body.includes('fail')) { + throw Error('Failed to process record.'); + } + + return body; +}; + +const kinesisRecordHandler = (record: KinesisStreamRecord): string => { + const body = record.kinesis.data; + if (body.includes('fail')) { + throw Error('Failed to process record.'); + } + + return body; +}; + +const asyncKinesisRecordHandler = async ( + record: KinesisStreamRecord +): Promise => { + const body = record.kinesis.data; + if (body.includes('fail')) { + throw Error('Failed to process record.'); + } + + return body; +}; + +const dynamodbRecordHandler = (record: DynamoDBRecord): object => { + const body = record.dynamodb?.NewImage?.Message || { S: 'fail' }; + if (body['S']?.includes('fail')) { + throw Error('Failed to process record.'); + } + + return body; +}; + +const asyncDynamodbRecordHandler = async ( + record: DynamoDBRecord +): Promise => { + const body = record.dynamodb?.NewImage?.Message || { S: 'fail' }; + if (body['S']?.includes('fail')) { + throw Error('Failed to process record.'); + } + + return body; +}; + +const handlerWithContext = ( + record: SQSRecord, + options: BatchProcessingOptions +): string => { + const context = options.context; + + try { + if (context.getRemainingTimeInMillis() == 0) { + throw Error('No time remaining.'); + } + } catch (e) { + throw Error('Context possibly malformed. Displaying context:\n' + context); + } + + return record.body; +}; + +const asyncHandlerWithContext = async ( + record: SQSRecord, + options: BatchProcessingOptions +): Promise => { + const context = options.context; + + try { + if (context.getRemainingTimeInMillis() == 0) { + throw Error('No time remaining.'); + } + } catch (e) { + throw Error('Context possibly malformed. Displaying context:\n' + context); + } + + return Promise.resolve(record.body); +}; + +export { + sqsRecordHandler, + asyncSqsRecordHandler, + kinesisRecordHandler, + asyncKinesisRecordHandler, + dynamodbRecordHandler, + asyncDynamodbRecordHandler, + handlerWithContext, + asyncHandlerWithContext, +}; diff --git a/packages/batch/tests/helpers/populateEnvironmentVariables.ts b/packages/batch/tests/helpers/populateEnvironmentVariables.ts new file mode 100644 index 0000000000..cb0b37f295 --- /dev/null +++ b/packages/batch/tests/helpers/populateEnvironmentVariables.ts @@ -0,0 +1,12 @@ +// Reserved variables +process.env._X_AMZN_TRACE_ID = '1-abcdef12-3456abcdef123456abcdef12'; +process.env.AWS_LAMBDA_FUNCTION_NAME = 'my-lambda-function'; +process.env.AWS_EXECUTION_ENV = 'nodejs18.x'; +process.env.AWS_LAMBDA_FUNCTION_MEMORY_SIZE = '128'; +if ( + process.env.AWS_REGION === undefined && + process.env.CDK_DEFAULT_REGION === undefined +) { + process.env.AWS_REGION = 'eu-west-1'; +} +process.env._HANDLER = 'index.handler'; diff --git a/packages/batch/tests/unit/AsyncBatchProcessor.test.ts b/packages/batch/tests/unit/AsyncBatchProcessor.test.ts new file mode 100644 index 0000000000..9079a1c464 --- /dev/null +++ b/packages/batch/tests/unit/AsyncBatchProcessor.test.ts @@ -0,0 +1,296 @@ +/** + * Test AsyncBatchProcessor class + * + * @group unit/batch/class/asyncBatchProcessor + */ +import type { Context } from 'aws-lambda'; +import { helloworldContext as dummyContext } from '../../../commons/src/samples/resources/contexts'; +import { AsyncBatchProcessor } from '../../src/AsyncBatchProcessor'; +import { EventType } from '../../src/constants'; +import { BatchProcessingError } from '../../src/errors'; +import type { BatchProcessingOptions } from '../../src/types'; +import { + dynamodbRecordFactory, + kinesisRecordFactory, + sqsRecordFactory, +} from '../helpers/factories'; +import { + asyncDynamodbRecordHandler, + asyncKinesisRecordHandler, + asyncSqsRecordHandler, + asyncHandlerWithContext, +} from '../helpers/handlers'; + +describe('Class: AsyncBatchProcessor', () => { + const ENVIRONMENT_VARIABLES = process.env; + const options: BatchProcessingOptions = { context: dummyContext }; + + beforeEach(() => { + jest.clearAllMocks(); + jest.resetModules(); + process.env = { ...ENVIRONMENT_VARIABLES }; + }); + + afterAll(() => { + process.env = ENVIRONMENT_VARIABLES; + }); + + describe('Asynchronously processing SQS Records', () => { + test('Batch processing SQS records with no failures', async () => { + // Prepare + const firstRecord = sqsRecordFactory('success'); + const secondRecord = sqsRecordFactory('success'); + const records = [firstRecord, secondRecord]; + const processor = new AsyncBatchProcessor(EventType.SQS); + + // Act + processor.register(records, asyncSqsRecordHandler); + const processedMessages = await processor.asyncProcess(); + + // Assess + expect(processedMessages).toStrictEqual([ + ['success', firstRecord.body, firstRecord], + ['success', secondRecord.body, secondRecord], + ]); + }); + + test('Batch processing SQS records with some failures', async () => { + // Prepare + const firstRecord = sqsRecordFactory('failure'); + const secondRecord = sqsRecordFactory('success'); + const thirdRecord = sqsRecordFactory('fail'); + const records = [firstRecord, secondRecord, thirdRecord]; + const processor = new AsyncBatchProcessor(EventType.SQS); + + // Act + processor.register(records, asyncSqsRecordHandler); + const processedMessages = await processor.asyncProcess(); + + // Assess + expect(processedMessages[1]).toStrictEqual([ + 'success', + secondRecord.body, + secondRecord, + ]); + expect(processor.failureMessages.length).toBe(2); + expect(processor.response()).toStrictEqual({ + batchItemFailures: [ + { itemIdentifier: firstRecord.messageId }, + { itemIdentifier: thirdRecord.messageId }, + ], + }); + }); + + test('Batch processing SQS records with all failures', async () => { + // Prepare + const firstRecord = sqsRecordFactory('failure'); + const secondRecord = sqsRecordFactory('failure'); + const thirdRecord = sqsRecordFactory('fail'); + + const records = [firstRecord, secondRecord, thirdRecord]; + const processor = new AsyncBatchProcessor(EventType.SQS); + + // Act + processor.register(records, asyncSqsRecordHandler); + + // Assess + await expect(processor.asyncProcess()).rejects.toThrowError( + BatchProcessingError + ); + }); + }); + + describe('Asynchronously processing Kinesis Records', () => { + test('Batch processing Kinesis records with no failures', async () => { + // Prepare + const firstRecord = kinesisRecordFactory('success'); + const secondRecord = kinesisRecordFactory('success'); + const records = [firstRecord, secondRecord]; + const processor = new AsyncBatchProcessor(EventType.KinesisDataStreams); + + // Act + processor.register(records, asyncKinesisRecordHandler); + const processedMessages = await processor.asyncProcess(); + + // Assess + expect(processedMessages).toStrictEqual([ + ['success', firstRecord.kinesis.data, firstRecord], + ['success', secondRecord.kinesis.data, secondRecord], + ]); + }); + + test('Batch processing Kinesis records with some failures', async () => { + // Prepare + const firstRecord = kinesisRecordFactory('failure'); + const secondRecord = kinesisRecordFactory('success'); + const thirdRecord = kinesisRecordFactory('fail'); + const records = [firstRecord, secondRecord, thirdRecord]; + const processor = new AsyncBatchProcessor(EventType.KinesisDataStreams); + + // Act + processor.register(records, asyncKinesisRecordHandler); + const processedMessages = await processor.asyncProcess(); + + // Assess + expect(processedMessages[1]).toStrictEqual([ + 'success', + secondRecord.kinesis.data, + secondRecord, + ]); + expect(processor.failureMessages.length).toBe(2); + expect(processor.response()).toStrictEqual({ + batchItemFailures: [ + { itemIdentifier: firstRecord.kinesis.sequenceNumber }, + { itemIdentifier: thirdRecord.kinesis.sequenceNumber }, + ], + }); + }); + + test('Batch processing Kinesis records with all failures', async () => { + // Prepare + const firstRecord = kinesisRecordFactory('failure'); + const secondRecord = kinesisRecordFactory('failure'); + const thirdRecord = kinesisRecordFactory('fail'); + + const records = [firstRecord, secondRecord, thirdRecord]; + const processor = new AsyncBatchProcessor(EventType.KinesisDataStreams); + + // Act + processor.register(records, asyncKinesisRecordHandler); + + // Assess + await expect(processor.asyncProcess()).rejects.toThrowError( + BatchProcessingError + ); + }); + }); + + describe('Asynchronously processing DynamoDB Records', () => { + test('Batch processing DynamoDB records with no failures', async () => { + // Prepare + const firstRecord = dynamodbRecordFactory('success'); + const secondRecord = dynamodbRecordFactory('success'); + const records = [firstRecord, secondRecord]; + const processor = new AsyncBatchProcessor(EventType.DynamoDBStreams); + + // Act + processor.register(records, asyncDynamodbRecordHandler); + const processedMessages = await processor.asyncProcess(); + + // Assess + expect(processedMessages).toStrictEqual([ + ['success', firstRecord.dynamodb?.NewImage?.Message, firstRecord], + ['success', secondRecord.dynamodb?.NewImage?.Message, secondRecord], + ]); + }); + + test('Batch processing DynamoDB records with some failures', async () => { + // Prepare + const firstRecord = dynamodbRecordFactory('failure'); + const secondRecord = dynamodbRecordFactory('success'); + const thirdRecord = dynamodbRecordFactory('fail'); + const records = [firstRecord, secondRecord, thirdRecord]; + const processor = new AsyncBatchProcessor(EventType.DynamoDBStreams); + + // Act + processor.register(records, asyncDynamodbRecordHandler); + const processedMessages = await processor.asyncProcess(); + + // Assess + expect(processedMessages[1]).toStrictEqual([ + 'success', + secondRecord.dynamodb?.NewImage?.Message, + secondRecord, + ]); + expect(processor.failureMessages.length).toBe(2); + expect(processor.response()).toStrictEqual({ + batchItemFailures: [ + { itemIdentifier: firstRecord.dynamodb?.SequenceNumber }, + { itemIdentifier: thirdRecord.dynamodb?.SequenceNumber }, + ], + }); + }); + + test('Batch processing DynamoDB records with all failures', async () => { + // Prepare + const firstRecord = dynamodbRecordFactory('failure'); + const secondRecord = dynamodbRecordFactory('failure'); + const thirdRecord = dynamodbRecordFactory('fail'); + + const records = [firstRecord, secondRecord, thirdRecord]; + const processor = new AsyncBatchProcessor(EventType.DynamoDBStreams); + + // Act + processor.register(records, asyncDynamodbRecordHandler); + + // Assess + await expect(processor.asyncProcess()).rejects.toThrowError( + BatchProcessingError + ); + }); + }); + + describe('Batch processing with Lambda context', () => { + test('Batch processing when context is provided and handler accepts', async () => { + // Prepare + const firstRecord = sqsRecordFactory('success'); + const secondRecord = sqsRecordFactory('success'); + const records = [firstRecord, secondRecord]; + const processor = new AsyncBatchProcessor(EventType.SQS); + + // Act + processor.register(records, asyncHandlerWithContext, options); + const processedMessages = await processor.asyncProcess(); + + // Assess + expect(processedMessages).toStrictEqual([ + ['success', firstRecord.body, firstRecord], + ['success', secondRecord.body, secondRecord], + ]); + }); + + test('Batch processing when context is provided and handler does not accept', async () => { + // Prepare + const firstRecord = sqsRecordFactory('success'); + const secondRecord = sqsRecordFactory('success'); + const records = [firstRecord, secondRecord]; + const processor = new AsyncBatchProcessor(EventType.SQS); + + // Act + processor.register(records, asyncSqsRecordHandler, options); + const processedMessages = await processor.asyncProcess(); + + // Assess + expect(processedMessages).toStrictEqual([ + ['success', firstRecord.body, firstRecord], + ['success', secondRecord.body, secondRecord], + ]); + }); + + test('Batch processing when malformed context is provided and handler attempts to use', async () => { + // Prepare + const firstRecord = sqsRecordFactory('success'); + const secondRecord = sqsRecordFactory('success'); + const records = [firstRecord, secondRecord]; + const processor = new AsyncBatchProcessor(EventType.SQS); + const badContext = { foo: 'bar' }; + const badOptions = { context: badContext as unknown as Context }; + + // Act + processor.register(records, asyncHandlerWithContext, badOptions); + await expect(() => processor.asyncProcess()).rejects.toThrowError( + BatchProcessingError + ); + }); + }); + + test('When calling the sync process method, it should throw an error', () => { + // Prepare + const processor = new AsyncBatchProcessor(EventType.SQS); + + // Act & Assess + expect(() => processor.process()).toThrowError( + 'Not implemented. Use asyncProcess() instead.' + ); + }); +}); diff --git a/packages/batch/tests/unit/BatchProcessor.test.ts b/packages/batch/tests/unit/BatchProcessor.test.ts new file mode 100644 index 0000000000..5be28271d2 --- /dev/null +++ b/packages/batch/tests/unit/BatchProcessor.test.ts @@ -0,0 +1,285 @@ +/** + * Test BatchProcessor class + * + * @group unit/batch/class/batchprocessor + */ +import type { Context } from 'aws-lambda'; +import { helloworldContext as dummyContext } from '../../../commons/src/samples/resources/contexts'; +import { BatchProcessor } from '../../src/BatchProcessor'; +import { EventType } from '../../src/constants'; +import { BatchProcessingError } from '../../src/errors'; +import type { BatchProcessingOptions } from '../../src/types'; +import { + dynamodbRecordFactory, + kinesisRecordFactory, + sqsRecordFactory, +} from '../helpers/factories'; +import { + dynamodbRecordHandler, + handlerWithContext, + kinesisRecordHandler, + sqsRecordHandler, +} from '../helpers/handlers'; + +describe('Class: BatchProcessor', () => { + const ENVIRONMENT_VARIABLES = process.env; + const options: BatchProcessingOptions = { context: dummyContext }; + + beforeEach(() => { + jest.clearAllMocks(); + jest.resetModules(); + process.env = { ...ENVIRONMENT_VARIABLES }; + }); + + afterAll(() => { + process.env = ENVIRONMENT_VARIABLES; + }); + + describe('Synchronously processing SQS Records', () => { + test('Batch processing SQS records with no failures', () => { + // Prepare + const firstRecord = sqsRecordFactory('success'); + const secondRecord = sqsRecordFactory('success'); + const records = [firstRecord, secondRecord]; + const processor = new BatchProcessor(EventType.SQS); + + // Act + processor.register(records, sqsRecordHandler); + const processedMessages = processor.process(); + + // Assess + expect(processedMessages).toStrictEqual([ + ['success', firstRecord.body, firstRecord], + ['success', secondRecord.body, secondRecord], + ]); + }); + + test('Batch processing SQS records with some failures', () => { + // Prepare + const firstRecord = sqsRecordFactory('failure'); + const secondRecord = sqsRecordFactory('success'); + const thirdRecord = sqsRecordFactory('fail'); + const records = [firstRecord, secondRecord, thirdRecord]; + const processor = new BatchProcessor(EventType.SQS); + + // Act + processor.register(records, sqsRecordHandler); + const processedMessages = processor.process(); + + // Assess + expect(processedMessages[1]).toStrictEqual([ + 'success', + secondRecord.body, + secondRecord, + ]); + expect(processor.failureMessages.length).toBe(2); + expect(processor.response()).toStrictEqual({ + batchItemFailures: [ + { itemIdentifier: firstRecord.messageId }, + { itemIdentifier: thirdRecord.messageId }, + ], + }); + }); + + test('Batch processing SQS records with all failures', () => { + // Prepare + const firstRecord = sqsRecordFactory('failure'); + const secondRecord = sqsRecordFactory('failure'); + const thirdRecord = sqsRecordFactory('fail'); + + const records = [firstRecord, secondRecord, thirdRecord]; + const processor = new BatchProcessor(EventType.SQS); + + // Act & Assess + processor.register(records, sqsRecordHandler); + expect(() => processor.process()).toThrowError(BatchProcessingError); + }); + }); + + describe('Synchronously processing Kinesis Records', () => { + test('Batch processing Kinesis records with no failures', () => { + // Prepare + const firstRecord = kinesisRecordFactory('success'); + const secondRecord = kinesisRecordFactory('success'); + const records = [firstRecord, secondRecord]; + const processor = new BatchProcessor(EventType.KinesisDataStreams); + + // Act + processor.register(records, kinesisRecordHandler); + const processedMessages = processor.process(); + + // Assess + expect(processedMessages).toStrictEqual([ + ['success', firstRecord.kinesis.data, firstRecord], + ['success', secondRecord.kinesis.data, secondRecord], + ]); + }); + + test('Batch processing Kinesis records with some failures', () => { + // Prepare + const firstRecord = kinesisRecordFactory('failure'); + const secondRecord = kinesisRecordFactory('success'); + const thirdRecord = kinesisRecordFactory('fail'); + const records = [firstRecord, secondRecord, thirdRecord]; + const processor = new BatchProcessor(EventType.KinesisDataStreams); + + // Act + processor.register(records, kinesisRecordHandler); + const processedMessages = processor.process(); + + // Assess + expect(processedMessages[1]).toStrictEqual([ + 'success', + secondRecord.kinesis.data, + secondRecord, + ]); + expect(processor.failureMessages.length).toBe(2); + expect(processor.response()).toStrictEqual({ + batchItemFailures: [ + { itemIdentifier: firstRecord.kinesis.sequenceNumber }, + { itemIdentifier: thirdRecord.kinesis.sequenceNumber }, + ], + }); + }); + + test('Batch processing Kinesis records with all failures', () => { + const firstRecord = kinesisRecordFactory('failure'); + const secondRecord = kinesisRecordFactory('failure'); + const thirdRecord = kinesisRecordFactory('fail'); + + const records = [firstRecord, secondRecord, thirdRecord]; + const processor = new BatchProcessor(EventType.KinesisDataStreams); + + // Act + processor.register(records, kinesisRecordHandler); + + // Assess + expect(() => processor.process()).toThrowError(BatchProcessingError); + }); + }); + + describe('Synchronously processing DynamoDB Records', () => { + test('Batch processing DynamoDB records with no failures', () => { + // Prepare + const firstRecord = dynamodbRecordFactory('success'); + const secondRecord = dynamodbRecordFactory('success'); + const records = [firstRecord, secondRecord]; + const processor = new BatchProcessor(EventType.DynamoDBStreams); + + // Act + processor.register(records, dynamodbRecordHandler); + const processedMessages = processor.process(); + + // Assess + expect(processedMessages).toStrictEqual([ + ['success', firstRecord.dynamodb?.NewImage?.Message, firstRecord], + ['success', secondRecord.dynamodb?.NewImage?.Message, secondRecord], + ]); + }); + + test('Batch processing DynamoDB records with some failures', () => { + // Prepare + const firstRecord = dynamodbRecordFactory('failure'); + const secondRecord = dynamodbRecordFactory('success'); + const thirdRecord = dynamodbRecordFactory('fail'); + const records = [firstRecord, secondRecord, thirdRecord]; + const processor = new BatchProcessor(EventType.DynamoDBStreams); + + // Act + processor.register(records, dynamodbRecordHandler); + const processedMessages = processor.process(); + + // Assess + expect(processedMessages[1]).toStrictEqual([ + 'success', + secondRecord.dynamodb?.NewImage?.Message, + secondRecord, + ]); + expect(processor.failureMessages.length).toBe(2); + expect(processor.response()).toStrictEqual({ + batchItemFailures: [ + { itemIdentifier: firstRecord.dynamodb?.SequenceNumber }, + { itemIdentifier: thirdRecord.dynamodb?.SequenceNumber }, + ], + }); + }); + + test('Batch processing DynamoDB records with all failures', () => { + // Prepare + const firstRecord = dynamodbRecordFactory('failure'); + const secondRecord = dynamodbRecordFactory('failure'); + const thirdRecord = dynamodbRecordFactory('fail'); + + const records = [firstRecord, secondRecord, thirdRecord]; + const processor = new BatchProcessor(EventType.DynamoDBStreams); + + // Act + processor.register(records, dynamodbRecordHandler); + + // Assess + expect(() => processor.process()).toThrowError(BatchProcessingError); + }); + }); + + describe('Batch processing with Lambda context', () => { + test('Batch processing when context is provided and handler accepts', () => { + // Prepare + const firstRecord = sqsRecordFactory('success'); + const secondRecord = sqsRecordFactory('success'); + const records = [firstRecord, secondRecord]; + const processor = new BatchProcessor(EventType.SQS); + + // Act + processor.register(records, handlerWithContext, options); + const processedMessages = processor.process(); + + // Assess + expect(processedMessages).toStrictEqual([ + ['success', firstRecord.body, firstRecord], + ['success', secondRecord.body, secondRecord], + ]); + }); + + test('Batch processing when context is provided and handler does not accept', () => { + // Prepare + const firstRecord = sqsRecordFactory('success'); + const secondRecord = sqsRecordFactory('success'); + const records = [firstRecord, secondRecord]; + const processor = new BatchProcessor(EventType.SQS); + + // Act + processor.register(records, sqsRecordHandler, options); + const processedMessages = processor.process(); + + // Assess + expect(processedMessages).toStrictEqual([ + ['success', firstRecord.body, firstRecord], + ['success', secondRecord.body, secondRecord], + ]); + }); + + test('Batch processing when malformed context is provided and handler attempts to use', () => { + // Prepare + const firstRecord = sqsRecordFactory('success'); + const secondRecord = sqsRecordFactory('success'); + const records = [firstRecord, secondRecord]; + const processor = new BatchProcessor(EventType.SQS); + const badContext = { foo: 'bar' }; + const badOptions = { context: badContext as unknown as Context }; + + // Act + processor.register(records, handlerWithContext, badOptions); + expect(() => processor.process()).toThrowError(BatchProcessingError); + }); + }); + + test('When calling the async process method, it should throw an error', async () => { + // Prepare + const processor = new BatchProcessor(EventType.SQS); + + // Act & Assess + await expect(() => processor.asyncProcess()).rejects.toThrow( + 'Not implemented. Use process() instead.' + ); + }); +}); diff --git a/packages/batch/tests/unit/SqsFifoPartialProcessor.test.ts b/packages/batch/tests/unit/SqsFifoPartialProcessor.test.ts new file mode 100644 index 0000000000..564886b1d8 --- /dev/null +++ b/packages/batch/tests/unit/SqsFifoPartialProcessor.test.ts @@ -0,0 +1,59 @@ +/** + * Test SqsFifoBatchProcessor class + * + * @group unit/batch/class/sqsfifobatchprocessor + */ +import { SqsFifoPartialProcessor, processPartialResponse } from '../../src'; +import { sqsRecordFactory } from '../helpers/factories'; +import { sqsRecordHandler } from '../helpers/handlers'; + +describe('Class: SqsFifoBatchProcessor', () => { + const ENVIRONMENT_VARIABLES = process.env; + + beforeEach(() => { + jest.clearAllMocks(); + jest.resetModules(); + process.env = { ...ENVIRONMENT_VARIABLES }; + }); + + afterAll(() => { + process.env = ENVIRONMENT_VARIABLES; + }); + + describe('Synchronous SQS FIFO batch processing', () => { + test('SQS FIFO Batch processor with no failures', () => { + // Prepare + const firstRecord = sqsRecordFactory('success'); + const secondRecord = sqsRecordFactory('success'); + const event = { Records: [firstRecord, secondRecord] }; + const processor = new SqsFifoPartialProcessor(); + + // Act + const result = processPartialResponse(event, sqsRecordHandler, processor); + + // Assess + expect(result['batchItemFailures']).toStrictEqual([]); + }); + + test('SQS FIFO Batch processor with failures', () => { + // Prepare + const firstRecord = sqsRecordFactory('success'); + const secondRecord = sqsRecordFactory('fail'); + const thirdRecord = sqsRecordFactory('success'); + const event = { Records: [firstRecord, secondRecord, thirdRecord] }; + const processor = new SqsFifoPartialProcessor(); + + // Act + const result = processPartialResponse(event, sqsRecordHandler, processor); + + // Assess + expect(result['batchItemFailures'].length).toBe(2); + expect(result['batchItemFailures'][0]['itemIdentifier']).toBe( + secondRecord.messageId + ); + expect(result['batchItemFailures'][1]['itemIdentifier']).toBe( + thirdRecord.messageId + ); + }); + }); +}); diff --git a/packages/batch/tests/unit/asyncProcessPartialResponse.test.ts b/packages/batch/tests/unit/asyncProcessPartialResponse.test.ts new file mode 100644 index 0000000000..fde15ccf42 --- /dev/null +++ b/packages/batch/tests/unit/asyncProcessPartialResponse.test.ts @@ -0,0 +1,231 @@ +/** + * Test asyncProcessPartialResponse function + * + * @group unit/batch/function/asyncProcesspartialresponse + */ +import type { + Context, + DynamoDBStreamEvent, + KinesisStreamEvent, + SQSEvent, +} from 'aws-lambda'; +import { helloworldContext as dummyContext } from '../../../commons/src/samples/resources/contexts'; +import { Custom as dummyEvent } from '../../../commons/src/samples/resources/events'; +import { AsyncBatchProcessor, asyncProcessPartialResponse } from '../../src'; +import { EventType } from '../../src/constants'; +import type { + BatchProcessingOptions, + PartialItemFailureResponse, +} from '../../src/types'; +import { + dynamodbRecordFactory, + kinesisRecordFactory, + sqsRecordFactory, +} from '../helpers/factories'; +import { + asyncDynamodbRecordHandler, + asyncHandlerWithContext, + asyncKinesisRecordHandler, + asyncSqsRecordHandler, +} from '../helpers/handlers'; + +describe('Function: processPartialResponse()', () => { + const ENVIRONMENT_VARIABLES = process.env; + const context = dummyContext; + const options: BatchProcessingOptions = { context: dummyContext }; + + beforeEach(() => { + jest.clearAllMocks(); + jest.resetModules(); + process.env = { ...ENVIRONMENT_VARIABLES }; + }); + + afterAll(() => { + process.env = ENVIRONMENT_VARIABLES; + }); + + describe('Process partial response function call tests', () => { + test('Process partial response function call with asynchronous handler', async () => { + // Prepare + const records = [ + sqsRecordFactory('success'), + sqsRecordFactory('success'), + ]; + const batch = { Records: records }; + const processor = new AsyncBatchProcessor(EventType.SQS); + + // Act + const ret = await asyncProcessPartialResponse( + batch, + asyncSqsRecordHandler, + processor + ); + + // Assess + expect(ret).toStrictEqual({ batchItemFailures: [] }); + }); + + test('Process partial response function call with context provided', async () => { + // Prepare + const records = [ + sqsRecordFactory('success'), + sqsRecordFactory('success'), + ]; + const batch = { Records: records }; + const processor = new AsyncBatchProcessor(EventType.SQS); + + // Act + const ret = await asyncProcessPartialResponse( + batch, + asyncHandlerWithContext, + processor, + options + ); + + // Assess + expect(ret).toStrictEqual({ batchItemFailures: [] }); + }); + }); + + describe('Process partial response function call through handler', () => { + test('Process partial response through handler with SQS event', async () => { + // Prepare + const records = [ + sqsRecordFactory('success'), + sqsRecordFactory('success'), + ]; + const processor = new AsyncBatchProcessor(EventType.SQS); + const event: SQSEvent = { Records: records }; + + const handler = async ( + event: SQSEvent, + _context: Context + ): Promise => { + return asyncProcessPartialResponse( + event, + asyncSqsRecordHandler, + processor + ); + }; + + // Act + const result = await handler(event, context); + + // Assess + expect(result).toStrictEqual({ batchItemFailures: [] }); + }); + + test('Process partial response through handler with Kinesis event', async () => { + // Prepare + const records = [ + kinesisRecordFactory('success'), + kinesisRecordFactory('success'), + ]; + const processor = new AsyncBatchProcessor(EventType.KinesisDataStreams); + const event: KinesisStreamEvent = { Records: records }; + + const handler = async ( + event: KinesisStreamEvent, + _context: Context + ): Promise => { + return await asyncProcessPartialResponse( + event, + asyncKinesisRecordHandler, + processor + ); + }; + + // Act + const result = await handler(event, context); + + // Assess + expect(result).toStrictEqual({ batchItemFailures: [] }); + }); + + test('Process partial response through handler with DynamoDB event', async () => { + // Prepare + const records = [ + dynamodbRecordFactory('success'), + dynamodbRecordFactory('success'), + ]; + const processor = new AsyncBatchProcessor(EventType.DynamoDBStreams); + const event: DynamoDBStreamEvent = { Records: records }; + + const handler = async ( + event: DynamoDBStreamEvent, + _context: Context + ): Promise => { + return await asyncProcessPartialResponse( + event, + asyncDynamodbRecordHandler, + processor + ); + }; + + // Act + const result = await handler(event, context); + + // Assess + expect(result).toStrictEqual({ batchItemFailures: [] }); + }); + + test('Process partial response through handler for SQS records with incorrect event type', async () => { + // Prepare + const processor = new AsyncBatchProcessor(EventType.SQS); + const event = dummyEvent; + const eventTypes: string = Object.values(EventType).toString(); + + const handler = async ( + event: SQSEvent, + _context: Context + ): Promise => { + return await asyncProcessPartialResponse( + event, + asyncSqsRecordHandler, + processor + ); + }; + + // Act & Assess + await expect(() => + handler(event as unknown as SQSEvent, context) + ).rejects.toThrowError( + new Error( + 'Failed to convert event to record batch for processing.\nPlease ensure batch event is a valid ' + + eventTypes + + ' event.' + ) + ); + }); + + test('Process partial response through handler with context provided', async () => { + // Prepare + const records = [ + sqsRecordFactory('success'), + sqsRecordFactory('success'), + ]; + const processor = new AsyncBatchProcessor(EventType.SQS); + const event: SQSEvent = { Records: records }; + + const handler = async ( + event: SQSEvent, + context: Context + ): Promise => { + const options: BatchProcessingOptions = { context: context }; + + return await asyncProcessPartialResponse( + event, + asyncHandlerWithContext, + processor, + options + ); + }; + + // Act + const result = await handler(event, context); + + // Assess + expect(result).toStrictEqual({ batchItemFailures: [] }); + }); + }); +}); diff --git a/packages/batch/tests/unit/processPartialResponse.test.ts b/packages/batch/tests/unit/processPartialResponse.test.ts new file mode 100644 index 0000000000..3de2edcce3 --- /dev/null +++ b/packages/batch/tests/unit/processPartialResponse.test.ts @@ -0,0 +1,209 @@ +/** + * Test processPartialResponse function + * + * @group unit/batch/function/processpartialresponse + */ +import type { + Context, + DynamoDBStreamEvent, + KinesisStreamEvent, + SQSEvent, +} from 'aws-lambda'; +import { helloworldContext as dummyContext } from '../../../commons/src/samples/resources/contexts'; +import { Custom as dummyEvent } from '../../../commons/src/samples/resources/events'; +import { BatchProcessor, processPartialResponse } from '../../src'; +import { EventType } from '../../src/constants'; +import type { + BatchProcessingOptions, + PartialItemFailureResponse, +} from '../../src/types'; +import { + dynamodbRecordFactory, + kinesisRecordFactory, + sqsRecordFactory, +} from '../helpers/factories'; +import { + dynamodbRecordHandler, + handlerWithContext, + kinesisRecordHandler, + sqsRecordHandler, +} from '../helpers/handlers'; + +describe('Function: processPartialResponse()', () => { + const ENVIRONMENT_VARIABLES = process.env; + const context = dummyContext; + const options: BatchProcessingOptions = { context: dummyContext }; + + beforeEach(() => { + jest.clearAllMocks(); + jest.resetModules(); + process.env = { ...ENVIRONMENT_VARIABLES }; + }); + + afterAll(() => { + process.env = ENVIRONMENT_VARIABLES; + }); + + describe('Process partial response function call tests', () => { + test('Process partial response function call with synchronous handler', () => { + // Prepare + const records = [ + sqsRecordFactory('success'), + sqsRecordFactory('success'), + ]; + const batch = { Records: records }; + const processor = new BatchProcessor(EventType.SQS); + + // Act + const ret = processPartialResponse(batch, sqsRecordHandler, processor); + + // Assess + expect(ret).toStrictEqual({ batchItemFailures: [] }); + }); + + test('Process partial response function call with context provided', () => { + // Prepare + const records = [ + sqsRecordFactory('success'), + sqsRecordFactory('success'), + ]; + const batch = { Records: records }; + const processor = new BatchProcessor(EventType.SQS); + + // Act + const ret = processPartialResponse( + batch, + handlerWithContext, + processor, + options + ); + + // Assess + expect(ret).toStrictEqual({ batchItemFailures: [] }); + }); + }); + + describe('Process partial response function call through handler', () => { + test('Process partial response through handler with SQS event', () => { + // Prepare + const records = [ + sqsRecordFactory('success'), + sqsRecordFactory('success'), + ]; + const processor = new BatchProcessor(EventType.SQS); + const event: SQSEvent = { Records: records }; + + const handler = ( + event: SQSEvent, + _context: Context + ): PartialItemFailureResponse => { + return processPartialResponse(event, sqsRecordHandler, processor); + }; + + // Act + const result = handler(event, context); + + // Assess + expect(result).toStrictEqual({ batchItemFailures: [] }); + }); + + test('Process partial response through handler with Kinesis event', () => { + // Prepare + const records = [ + kinesisRecordFactory('success'), + kinesisRecordFactory('success'), + ]; + const processor = new BatchProcessor(EventType.KinesisDataStreams); + const event: KinesisStreamEvent = { Records: records }; + + const handler = ( + event: KinesisStreamEvent, + _context: Context + ): PartialItemFailureResponse => { + return processPartialResponse(event, kinesisRecordHandler, processor); + }; + + // Act + const result = handler(event, context); + + // Assess + expect(result).toStrictEqual({ batchItemFailures: [] }); + }); + + test('Process partial response through handler with DynamoDB event', () => { + // Prepare + const records = [ + dynamodbRecordFactory('success'), + dynamodbRecordFactory('success'), + ]; + const processor = new BatchProcessor(EventType.DynamoDBStreams); + const event: DynamoDBStreamEvent = { Records: records }; + + const handler = ( + event: DynamoDBStreamEvent, + _context: Context + ): PartialItemFailureResponse => { + return processPartialResponse(event, dynamodbRecordHandler, processor); + }; + + // Act + const result = handler(event, context); + + // Assess + expect(result).toStrictEqual({ batchItemFailures: [] }); + }); + + test('Process partial response through handler for SQS records with incorrect event type', () => { + // Prepare + const processor = new BatchProcessor(EventType.SQS); + const event = dummyEvent; + const eventTypes: string = Object.values(EventType).toString(); + + const handler = ( + event: SQSEvent, + _context: Context + ): PartialItemFailureResponse => { + return processPartialResponse(event, sqsRecordHandler, processor); + }; + + // Act & Assess + expect(() => handler(event as unknown as SQSEvent, context)).toThrowError( + new Error( + 'Failed to convert event to record batch for processing.\nPlease ensure batch event is a valid ' + + eventTypes + + ' event.' + ) + ); + }); + + test('Process partial response through handler with context provided', () => { + // Prepare + const records = [ + sqsRecordFactory('success'), + sqsRecordFactory('success'), + ]; + const processor = new BatchProcessor(EventType.SQS); + const event: SQSEvent = { Records: records }; + + const handler = ( + event: SQSEvent, + context: Context + ): PartialItemFailureResponse => { + const options: BatchProcessingOptions = { context: context }; + + return processPartialResponse( + event, + handlerWithContext, + processor, + options + ); + }; + + // Act + const result = handler(event, context); + + // Assess + expect(result).toStrictEqual({ batchItemFailures: [] }); + }); + }); +}); diff --git a/packages/batch/tsconfig-dev.json b/packages/batch/tsconfig-dev.json new file mode 100644 index 0000000000..6f766859ea --- /dev/null +++ b/packages/batch/tsconfig-dev.json @@ -0,0 +1,11 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "declarationMap": true, + "esModuleInterop": false + }, + "include": [ "src/**/*", "examples/**/*", "**/tests/**/*" ], + "types": [ + "jest" + ] +} \ No newline at end of file diff --git a/packages/batch/tsconfig.es.json b/packages/batch/tsconfig.es.json new file mode 100644 index 0000000000..6f766859ea --- /dev/null +++ b/packages/batch/tsconfig.es.json @@ -0,0 +1,11 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "declarationMap": true, + "esModuleInterop": false + }, + "include": [ "src/**/*", "examples/**/*", "**/tests/**/*" ], + "types": [ + "jest" + ] +} \ No newline at end of file diff --git a/packages/batch/tsconfig.json b/packages/batch/tsconfig.json new file mode 100644 index 0000000000..09df4b9ba4 --- /dev/null +++ b/packages/batch/tsconfig.json @@ -0,0 +1,29 @@ +{ + "compilerOptions": { + "experimentalDecorators": true, + "noImplicitAny": true, + "target": "ES2020", + "module": "commonjs", + "declaration": true, + "outDir": "lib", + "strict": true, + "inlineSourceMap": true, + "moduleResolution": "node", + "resolveJsonModule": true, + "pretty": true, + "baseUrl": "src/", + "rootDirs": [ "src/" ], + "esModuleInterop": true + }, + "include": [ "src/**/*" ], + "exclude": [ "./node_modules"], + "watchOptions": { + "watchFile": "useFsEvents", + "watchDirectory": "useFsEvents", + "fallbackPolling": "dynamicPriority" + }, + "lib": [ "es2020" ], + "types": [ + "node" + ] +} \ No newline at end of file diff --git a/packages/batch/typedoc.json b/packages/batch/typedoc.json new file mode 100644 index 0000000000..ed0ca6fc47 --- /dev/null +++ b/packages/batch/typedoc.json @@ -0,0 +1,9 @@ +{ + "extends": [ + "../../typedoc.base.json" + ], + "entryPoints": [ + "./src/index.ts" + ], + "readme": "README.md" +} \ No newline at end of file From 02cd84bbe8505345c7f6bf8d7cdf123d3608daa0 Mon Sep 17 00:00:00 2001 From: Alexander Schueren Date: Tue, 25 Jul 2023 12:40:50 +0200 Subject: [PATCH 09/11] docs(parameters): add parameters examples cdk and sam (#1622) * add ssm to example * add parameters to cdk example * update cleanup * add sam tempalte with dedicated uuid api gw * added deps for examples * clean up corructed deps * fix test and revert back to cdk 2.73.0 * revert to previous package lock * swtich to randomUUID * removed unused param, bumped powertools version * add PT_VERSION from commons instead of string variable * add nosonar for temp resources in example --- examples/cdk/functions/common/getUuid.ts | 22 ++ examples/cdk/functions/common/powertools.ts | 5 +- examples/cdk/functions/get-all-items.ts | 21 +- examples/cdk/functions/get-by-id.ts | 17 +- examples/cdk/functions/put-item.ts | 15 +- examples/cdk/functions/uuid.ts | 8 + examples/cdk/package.json | 3 + examples/cdk/src/example-stack.ts | 52 ++- examples/cdk/tests/cdk-app.test.ts | 2 +- examples/sam/package.json | 4 +- examples/sam/src/common/getUuid.ts | 22 ++ examples/sam/src/common/powertools.ts | 5 +- examples/sam/src/get-all-items.ts | 9 +- examples/sam/src/get-by-id.ts | 17 +- examples/sam/src/get-uuid.ts | 8 + examples/sam/src/put-item.ts | 16 +- examples/sam/template.yaml | 151 +++++++- package-lock.json | 375 +++++++++++++++++++- 18 files changed, 660 insertions(+), 92 deletions(-) create mode 100644 examples/cdk/functions/common/getUuid.ts create mode 100644 examples/cdk/functions/uuid.ts create mode 100644 examples/sam/src/common/getUuid.ts create mode 100644 examples/sam/src/get-uuid.ts diff --git a/examples/cdk/functions/common/getUuid.ts b/examples/cdk/functions/common/getUuid.ts new file mode 100644 index 0000000000..eb567314bd --- /dev/null +++ b/examples/cdk/functions/common/getUuid.ts @@ -0,0 +1,22 @@ +import { logger } from './powertools'; +import { getParameter } from '@aws-lambda-powertools/parameters/ssm'; +import { randomUUID } from 'node:crypto'; +import { default as request } from 'phin'; + +export const getUuid = async (): Promise => { + const uuidApiUrl = await getParameter('/app/uuid-api-url'); + if (!uuidApiUrl) { + // create uuid locally + logger.warn('No uuid-api-url parameter found, creating uuid locally'); + + return randomUUID(); + } else { + // Request a sample random uuid from a webservice + const res = await request<{ uuid: string }>({ + url: uuidApiUrl, + parse: 'json', + }); + + return res.body.uuid; + } +}; diff --git a/examples/cdk/functions/common/powertools.ts b/examples/cdk/functions/common/powertools.ts index 0b5a768326..01949a91ac 100644 --- a/examples/cdk/functions/common/powertools.ts +++ b/examples/cdk/functions/common/powertools.ts @@ -1,8 +1,7 @@ import { Logger } from '@aws-lambda-powertools/logger'; import { Metrics } from '@aws-lambda-powertools/metrics'; import { Tracer } from '@aws-lambda-powertools/tracer'; - -const awsLambdaPowertoolsVersion = '1.5.0'; +import { PT_VERSION } from '@aws-lambda-powertools/commons/lib/version'; const defaultValues = { region: process.env.AWS_REGION || 'N/A', @@ -14,7 +13,7 @@ const logger = new Logger({ ...defaultValues, logger: { name: '@aws-lambda-powertools/logger', - version: awsLambdaPowertoolsVersion, + version: PT_VERSION, }, }, }); diff --git a/examples/cdk/functions/get-all-items.ts b/examples/cdk/functions/get-all-items.ts index a0b69aa0ff..d0b1acb4b8 100644 --- a/examples/cdk/functions/get-all-items.ts +++ b/examples/cdk/functions/get-all-items.ts @@ -1,17 +1,17 @@ +import { injectLambdaContext } from '@aws-lambda-powertools/logger'; +import { logMetrics } from '@aws-lambda-powertools/metrics'; +import { captureLambdaHandler } from '@aws-lambda-powertools/tracer'; +import { ScanCommand } from '@aws-sdk/lib-dynamodb'; +import middy from '@middy/core'; import { APIGatewayProxyEvent, APIGatewayProxyResult, Context, } from 'aws-lambda'; -import middy from '@middy/core'; import { tableName } from './common/constants'; -import { logger, tracer, metrics } from './common/powertools'; -import { logMetrics } from '@aws-lambda-powertools/metrics'; -import { injectLambdaContext } from '@aws-lambda-powertools/logger'; -import { captureLambdaHandler } from '@aws-lambda-powertools/tracer'; import { docClient } from './common/dynamodb-client'; -import { ScanCommand } from '@aws-sdk/lib-dynamodb'; -import { default as request } from 'phin'; +import { getUuid } from './common/getUuid'; +import { logger, metrics, tracer } from './common/powertools'; /* * @@ -45,12 +45,7 @@ const getAllItemsHandler = async ( awsRequestId: context.awsRequestId, }); - // Request a sample random uuid from a webservice - const res = await request<{ uuid: string }>({ - url: 'https://httpbin.org/uuid', - parse: 'json', - }); - const { uuid } = res.body; + const uuid = await getUuid(); // Logger: Append uuid to each log statement logger.appendKeys({ uuid }); diff --git a/examples/cdk/functions/get-by-id.ts b/examples/cdk/functions/get-by-id.ts index db536b3f23..9ad13fcb2f 100644 --- a/examples/cdk/functions/get-by-id.ts +++ b/examples/cdk/functions/get-by-id.ts @@ -1,14 +1,14 @@ +import { LambdaInterface } from '@aws-lambda-powertools/commons'; +import { GetCommand } from '@aws-sdk/lib-dynamodb'; import { APIGatewayProxyEvent, APIGatewayProxyResult, Context, } from 'aws-lambda'; import { tableName } from './common/constants'; -import { logger, tracer, metrics } from './common/powertools'; -import { LambdaInterface } from '@aws-lambda-powertools/commons'; import { docClient } from './common/dynamodb-client'; -import { GetCommand } from '@aws-sdk/lib-dynamodb'; -import { default as request } from 'phin'; +import { getUuid } from './common/getUuid'; +import { logger, metrics, tracer } from './common/powertools'; /* * @@ -28,14 +28,7 @@ import { default as request } from 'phin'; class Lambda implements LambdaInterface { @tracer.captureMethod() public async getUuid(): Promise { - // Request a sample random uuid from a webservice - const res = await request<{ uuid: string }>({ - url: 'https://httpbin.org/uuid', - parse: 'json', - }); - const { uuid } = res.body; - - return uuid; + return getUuid(); } @tracer.captureLambdaHandler({ captureResponse: false }) // by default the tracer would add the response as metadata on the segment, but there is a chance to hit the 64kb segment size limit. Therefore set captureResponse: false diff --git a/examples/cdk/functions/put-item.ts b/examples/cdk/functions/put-item.ts index c51b37c094..b686244d2f 100644 --- a/examples/cdk/functions/put-item.ts +++ b/examples/cdk/functions/put-item.ts @@ -1,14 +1,14 @@ +import { PutCommand } from '@aws-sdk/lib-dynamodb'; import { APIGatewayProxyEvent, APIGatewayProxyResult, Context, } from 'aws-lambda'; +import type { Subsegment } from 'aws-xray-sdk-core'; import { tableName } from './common/constants'; -import { logger, tracer, metrics } from './common/powertools'; import { docClient } from './common/dynamodb-client'; -import { PutCommand } from '@aws-sdk/lib-dynamodb'; -import { default as request } from 'phin'; -import type { Subsegment } from 'aws-xray-sdk-core'; +import { getUuid } from './common/getUuid'; +import { logger, metrics, tracer } from './common/powertools'; /** * @@ -59,12 +59,7 @@ export const handler = async ( awsRequestId: context.awsRequestId, }); - // Request a sample random uuid from a webservice - const res = await request<{ uuid: string }>({ - url: 'https://httpbin.org/uuid', - parse: 'json', - }); - const { uuid } = res.body; + const uuid = await getUuid(); // Logger: Append uuid to each log statement logger.appendKeys({ uuid }); diff --git a/examples/cdk/functions/uuid.ts b/examples/cdk/functions/uuid.ts new file mode 100644 index 0000000000..58e017dbea --- /dev/null +++ b/examples/cdk/functions/uuid.ts @@ -0,0 +1,8 @@ +import { randomUUID } from 'node:crypto'; + +exports.handler = async (_event) => { + return { + statusCode: 200, + body: JSON.stringify(randomUUID()), + }; +}; diff --git a/examples/cdk/package.json b/examples/cdk/package.json index aba33bb7a1..d5c5454281 100644 --- a/examples/cdk/package.json +++ b/examples/cdk/package.json @@ -25,9 +25,12 @@ "*.js": "npm run lint-fix" }, "devDependencies": { + "@aws-lambda-powertools/commons": "^1.11.1", "@aws-lambda-powertools/logger": "^1.11.1", "@aws-lambda-powertools/metrics": "^1.11.1", + "@aws-lambda-powertools/parameters": "^1.11.1", "@aws-lambda-powertools/tracer": "^1.11.1", + "@aws-sdk/client-ssm": "^3.360.0", "@aws-sdk/lib-dynamodb": "^3.360.0", "@types/aws-lambda": "^8.10.109", "@types/jest": "^29.2.4", diff --git a/examples/cdk/src/example-stack.ts b/examples/cdk/src/example-stack.ts index e79efc42b8..179f86149b 100644 --- a/examples/cdk/src/example-stack.ts +++ b/examples/cdk/src/example-stack.ts @@ -1,13 +1,14 @@ -import { Stack, StackProps, Duration } from 'aws-cdk-lib'; -import { Construct } from 'constructs'; -import { Table, BillingMode, AttributeType } from 'aws-cdk-lib/aws-dynamodb'; +import { Duration, Stack, StackProps } from 'aws-cdk-lib'; +import { LambdaIntegration, RestApi } from 'aws-cdk-lib/aws-apigateway'; +import { AttributeType, BillingMode, Table } from 'aws-cdk-lib/aws-dynamodb'; +import { LayerVersion, Runtime, Tracing } from 'aws-cdk-lib/aws-lambda'; import { NodejsFunction, NodejsFunctionProps, } from 'aws-cdk-lib/aws-lambda-nodejs'; -import { Runtime, Tracing, LayerVersion } from 'aws-cdk-lib/aws-lambda'; import { RetentionDays } from 'aws-cdk-lib/aws-logs'; -import { RestApi, LambdaIntegration } from 'aws-cdk-lib/aws-apigateway'; +import { StringParameter } from 'aws-cdk-lib/aws-ssm'; +import { Construct } from 'constructs'; const commonProps: Partial = { runtime: Runtime.NODEJS_18_X, @@ -37,6 +38,8 @@ export class CdkAppStack extends Stack { public constructor(scope: Construct, id: string, props?: StackProps) { super(scope, id, props); + const uuidApi = new UuidApi(this, 'uuid-api'); + const table = new Table(this, 'Table', { billingMode: BillingMode.PAY_PER_REQUEST, partitionKey: { @@ -51,7 +54,7 @@ export class CdkAppStack extends Stack { 'powertools-layer', `arn:aws:lambda:${ Stack.of(this).region - }:094274105915:layer:AWSLambdaPowertoolsTypeScript:6` + }:094274105915:layer:AWSLambdaPowertoolsTypeScript:16` ) ); @@ -76,12 +79,20 @@ export class CdkAppStack extends Stack { entry: './functions/get-by-id.ts', handler: 'handler', }); + + uuidApi.apiUrlParam.grantRead(getByIdFn); + uuidApi.apiUrlParam.grantRead(putItemFn); + uuidApi.apiUrlParam.grantRead(getAllItemsFn); + getByIdFn.addEnvironment('SAMPLE_TABLE', table.tableName); table.grantReadData(getByIdFn); const api = new RestApi(this, 'items-api', { restApiName: 'Items Service', description: 'This service serves items.', + deployOptions: { + tracingEnabled: true, + }, }); const itemPutIntegration = new LambdaIntegration(putItemFn); @@ -95,3 +106,32 @@ export class CdkAppStack extends Stack { item.addMethod('GET', itemIntegration); } } + +class UuidApi extends Construct { + public readonly apiUrlParam: StringParameter; + public constructor(scope: Construct, id: string) { + super(scope, id); + + const uuidFn = new NodejsFunction(this, 'UuidFn', { + runtime: Runtime.NODEJS_18_X, + entry: './functions/uuid.ts', + }); + + const api = new RestApi(this, 'uuid-api', { + restApiName: 'UUID Service', + description: 'This service serves UUIDs.', + deployOptions: { + tracingEnabled: true, + }, + }); + + const uuidIntegration = new LambdaIntegration(uuidFn); + const uuid = api.root.addResource('uuid'); + uuid.addMethod('GET', uuidIntegration); + + this.apiUrlParam = new StringParameter(this, 'uuid-api-url', { + parameterName: '/app/uuid-api-url', + stringValue: `${api.url}/uuid`, + }); + } +} diff --git a/examples/cdk/tests/cdk-app.test.ts b/examples/cdk/tests/cdk-app.test.ts index f67fce3d66..83ebfe2105 100644 --- a/examples/cdk/tests/cdk-app.test.ts +++ b/examples/cdk/tests/cdk-app.test.ts @@ -5,5 +5,5 @@ import * as CdkApp from '../src/example-stack'; test('CDK code synthesize', () => { const app = new cdk.App(); const stack = new CdkApp.CdkAppStack(app, 'MyTestStack'); - Template.fromStack(stack).resourceCountIs('AWS::Lambda::Function', 4); // The stack has 4 functions: 3 for the example, and 1 for the log retention that is deployed by CDK + Template.fromStack(stack).resourceCountIs('AWS::Lambda::Function', 5); // The stack has 4 functions: 3 for the example, and 1 for the log retention that is deployed by CDK }); diff --git a/examples/sam/package.json b/examples/sam/package.json index 65f00d0543..9a35d20c62 100644 --- a/examples/sam/package.json +++ b/examples/sam/package.json @@ -26,7 +26,6 @@ "@types/node": "18.11.17", "@typescript-eslint/eslint-plugin": "^5.46.1", "@typescript-eslint/parser": "^5.46.1", - "esbuild": "^0.16.9", "eslint": "^8.30.0", "eslint-import-resolver-node": "^0.3.6", "eslint-import-resolver-typescript": "^3.5.2", @@ -40,9 +39,12 @@ "@aws-lambda-powertools/logger": "^1.11.1", "@aws-lambda-powertools/metrics": "^1.11.1", "@aws-lambda-powertools/tracer": "^1.11.1", + "@aws-lambda-powertools/parameters": "^1.11.1", "@aws-sdk/client-dynamodb": "^3.360.0", + "@aws-sdk/client-ssm": "^3.360.0", "@aws-sdk/lib-dynamodb": "^3.360.0", "@middy/core": "^3.6.2", + "esbuild": "^0.18.14", "phin": "^3.7.0" } } diff --git a/examples/sam/src/common/getUuid.ts b/examples/sam/src/common/getUuid.ts new file mode 100644 index 0000000000..eb567314bd --- /dev/null +++ b/examples/sam/src/common/getUuid.ts @@ -0,0 +1,22 @@ +import { logger } from './powertools'; +import { getParameter } from '@aws-lambda-powertools/parameters/ssm'; +import { randomUUID } from 'node:crypto'; +import { default as request } from 'phin'; + +export const getUuid = async (): Promise => { + const uuidApiUrl = await getParameter('/app/uuid-api-url'); + if (!uuidApiUrl) { + // create uuid locally + logger.warn('No uuid-api-url parameter found, creating uuid locally'); + + return randomUUID(); + } else { + // Request a sample random uuid from a webservice + const res = await request<{ uuid: string }>({ + url: uuidApiUrl, + parse: 'json', + }); + + return res.body.uuid; + } +}; diff --git a/examples/sam/src/common/powertools.ts b/examples/sam/src/common/powertools.ts index 0b5a768326..01949a91ac 100644 --- a/examples/sam/src/common/powertools.ts +++ b/examples/sam/src/common/powertools.ts @@ -1,8 +1,7 @@ import { Logger } from '@aws-lambda-powertools/logger'; import { Metrics } from '@aws-lambda-powertools/metrics'; import { Tracer } from '@aws-lambda-powertools/tracer'; - -const awsLambdaPowertoolsVersion = '1.5.0'; +import { PT_VERSION } from '@aws-lambda-powertools/commons/lib/version'; const defaultValues = { region: process.env.AWS_REGION || 'N/A', @@ -14,7 +13,7 @@ const logger = new Logger({ ...defaultValues, logger: { name: '@aws-lambda-powertools/logger', - version: awsLambdaPowertoolsVersion, + version: PT_VERSION, }, }, }); diff --git a/examples/sam/src/get-all-items.ts b/examples/sam/src/get-all-items.ts index a0b69aa0ff..b0e3ec9ae6 100644 --- a/examples/sam/src/get-all-items.ts +++ b/examples/sam/src/get-all-items.ts @@ -11,7 +11,7 @@ import { injectLambdaContext } from '@aws-lambda-powertools/logger'; import { captureLambdaHandler } from '@aws-lambda-powertools/tracer'; import { docClient } from './common/dynamodb-client'; import { ScanCommand } from '@aws-sdk/lib-dynamodb'; -import { default as request } from 'phin'; +import { getUuid } from './common/getUuid'; /* * @@ -45,12 +45,7 @@ const getAllItemsHandler = async ( awsRequestId: context.awsRequestId, }); - // Request a sample random uuid from a webservice - const res = await request<{ uuid: string }>({ - url: 'https://httpbin.org/uuid', - parse: 'json', - }); - const { uuid } = res.body; + const uuid = await getUuid(); // Logger: Append uuid to each log statement logger.appendKeys({ uuid }); diff --git a/examples/sam/src/get-by-id.ts b/examples/sam/src/get-by-id.ts index db536b3f23..9ad13fcb2f 100644 --- a/examples/sam/src/get-by-id.ts +++ b/examples/sam/src/get-by-id.ts @@ -1,14 +1,14 @@ +import { LambdaInterface } from '@aws-lambda-powertools/commons'; +import { GetCommand } from '@aws-sdk/lib-dynamodb'; import { APIGatewayProxyEvent, APIGatewayProxyResult, Context, } from 'aws-lambda'; import { tableName } from './common/constants'; -import { logger, tracer, metrics } from './common/powertools'; -import { LambdaInterface } from '@aws-lambda-powertools/commons'; import { docClient } from './common/dynamodb-client'; -import { GetCommand } from '@aws-sdk/lib-dynamodb'; -import { default as request } from 'phin'; +import { getUuid } from './common/getUuid'; +import { logger, metrics, tracer } from './common/powertools'; /* * @@ -28,14 +28,7 @@ import { default as request } from 'phin'; class Lambda implements LambdaInterface { @tracer.captureMethod() public async getUuid(): Promise { - // Request a sample random uuid from a webservice - const res = await request<{ uuid: string }>({ - url: 'https://httpbin.org/uuid', - parse: 'json', - }); - const { uuid } = res.body; - - return uuid; + return getUuid(); } @tracer.captureLambdaHandler({ captureResponse: false }) // by default the tracer would add the response as metadata on the segment, but there is a chance to hit the 64kb segment size limit. Therefore set captureResponse: false diff --git a/examples/sam/src/get-uuid.ts b/examples/sam/src/get-uuid.ts new file mode 100644 index 0000000000..58e017dbea --- /dev/null +++ b/examples/sam/src/get-uuid.ts @@ -0,0 +1,8 @@ +import { randomUUID } from 'node:crypto'; + +exports.handler = async (_event) => { + return { + statusCode: 200, + body: JSON.stringify(randomUUID()), + }; +}; diff --git a/examples/sam/src/put-item.ts b/examples/sam/src/put-item.ts index 27ca35f06c..aab7116602 100644 --- a/examples/sam/src/put-item.ts +++ b/examples/sam/src/put-item.ts @@ -1,14 +1,14 @@ +import { PutCommand } from '@aws-sdk/lib-dynamodb'; import { APIGatewayProxyEvent, APIGatewayProxyResult, Context, } from 'aws-lambda'; +import type { Subsegment } from 'aws-xray-sdk-core'; import { tableName } from './common/constants'; -import { logger, tracer, metrics } from './common/powertools'; import { docClient } from './common/dynamodb-client'; -import { PutCommand } from '@aws-sdk/lib-dynamodb'; -import { default as request } from 'phin'; -import type { Subsegment } from 'aws-xray-sdk-core'; +import { logger, metrics, tracer } from './common/powertools'; +import { getUuid } from './common/getUuid'; /** * @@ -61,13 +61,7 @@ export const handler = async ( awsRequestId: context.awsRequestId, }); - // Request a sample random uuid from a webservice - const res = await request<{ uuid: string }>({ - url: 'https://httpbin.org/uuid', - parse: 'json', - }); - const { uuid } = res.body; - + const uuid = await getUuid(); // Logger: Append uuid to each log statement logger.appendKeys({ uuid }); diff --git a/examples/sam/template.yaml b/examples/sam/template.yaml index e44c619096..46e18f412e 100644 --- a/examples/sam/template.yaml +++ b/examples/sam/template.yaml @@ -11,6 +11,22 @@ Description: >- # https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/transform-section-structure.html Transform: AWS::Serverless-2016-10-31 +Parameters: + apiGatewayName: + Type: String + Default: uuid-api + apiGatewayStageName: + Type: String + AllowedPattern: '[a-z0-9]+' + Default: dev + apiGatewayHTTPMethod: + Type: String + Default: GET + lambdaFunctionName: + Type: String + AllowedPattern: '[a-zA-Z0-9]+[a-zA-Z0-9-]+[a-zA-Z0-9]+' + Default: uuid-lambda + # Global configuration that all Functions inherit # https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-specification-template-anatomy-globals.html Globals: @@ -37,6 +53,8 @@ Resources: # Give Create/Read/Update/Delete Permissions to the SampleTable - DynamoDBReadPolicy: TableName: !Ref SampleTable + - SSMParameterWithSlashPrefixReadPolicy: + ParameterName: !Ref uuidApiUrlParameter Tracing: Active Environment: Variables: @@ -53,7 +71,7 @@ Resources: Properties: Path: / Method: GET - Metadata: + Metadata: # Manage esbuild properties BuildMethod: esbuild BuildProperties: @@ -76,6 +94,9 @@ Resources: # Give Create/Read/Update/Delete Permissions to the SampleTable - DynamoDBReadPolicy: TableName: !Ref SampleTable + # add ssm:getParameter permission to the function + - SSMParameterWithSlashPrefixReadPolicy: + ParameterName: !Ref uuidApiUrlParameter Tracing: Active Environment: Variables: @@ -92,7 +113,7 @@ Resources: Properties: Path: /{id} Method: GET - Metadata: + Metadata: # Manage esbuild properties BuildMethod: esbuild BuildProperties: @@ -105,6 +126,53 @@ Resources: EntryPoints: - src/get-by-id.ts + # This is a Lambda function config associated with the source code: get-uuid.js + getUuidFunction: + Type: AWS::Serverless::Function + Properties: + Handler: src/get-uuid.handler + Description: A simple example includes a HTTP get method to get a UUID. + Tracing: Active + FunctionName: !Ref lambdaFunctionName + Role: !GetAtt lambdaIAMRole.Arn + Environment: + Variables: + POWERTOOLS_SERVICE_NAME: items-store + POWERTOOLS_METRICS_NAMESPACE: PowertoolsSAMExample + LOG_LEVEL: Debug + # add ssm:getParameter permission to the function + Policies: + - SSMParameterWithSlashPrefixReadPolicy: + ParameterName: !Ref uuidApiUrlParameter + Events: + Api: + Type: Api + Properties: + Path: / + Method: GET + RestApiId: !Ref apiGateway + Metadata: + # Manage esbuild properties + BuildMethod: esbuild + BuildProperties: + Minify: true + Target: "ES2020" + Sourcemap: true + External: + - "uuid" + EntryPoints: + - src/get-uuid.ts + + # create ssm parameter with the value of the uuid api url + uuidApiUrlParameter: + Type: AWS::SSM::Parameter + Properties: + Name: /app/uuid-api-url + Type: String + Description: "Example parameter for UUID API URL" + Value: !Sub "https://${apiGateway}.execute-api.${AWS::Region}.amazonaws.com/${apiGatewayStageName}/" + + # This is a Lambda function config associated with the source code: put-item.js putItemFunction: Type: AWS::Serverless::Function @@ -115,6 +183,8 @@ Resources: # Give Create/Read/Update/Delete Permissions to the SampleTable - DynamoDBCrudPolicy: TableName: !Ref SampleTable + - SSMParameterWithSlashPrefixReadPolicy: + ParameterName: !Ref uuidApiUrlParameter Tracing: Active Environment: Variables: @@ -131,7 +201,7 @@ Resources: Properties: Path: / Method: POST - Metadata: + Metadata: # Manage esbuild properties BuildMethod: esbuild BuildProperties: @@ -141,7 +211,7 @@ Resources: External: - "@aws-sdk/lib-dynamodb" - "@aws-sdk/client-dynamodb" - EntryPoints: + EntryPoints: - src/put-item.ts # DynamoDB table to store item: {id: , name: } @@ -152,14 +222,75 @@ Resources: Name: id Type: String - Api: + apiGateway: Type: AWS::ApiGateway::RestApi Properties: - Name: !Sub ${AWS::StackName}-api - Description: "Example API" + Name: !Sub ${AWS::StackName}-uuid-api + Description: "Example API for UUID generation" + + apiGatewayDeployment: + Type: AWS::ApiGateway::Deployment + DependsOn: + - apiGatewayRootMethod + Properties: + RestApiId: !Ref apiGateway + StageName: !Ref apiGatewayStageName + + apiGatewayRootMethod: + Type: AWS::ApiGateway::Method + Properties: + AuthorizationType: NONE # NOSONAR + HttpMethod: !Ref apiGatewayHTTPMethod + Integration: + IntegrationHttpMethod: POST + Type: AWS_PROXY + Uri: !Sub + - arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${lambdaArn}/invocations + - lambdaArn: !GetAtt getUuidFunction.Arn + ResourceId: !GetAtt apiGateway.RootResourceId + RestApiId: !Ref apiGateway + + lambdaApiGatewayInvoke: + Type: AWS::Lambda::Permission + Properties: + Action: lambda:InvokeFunction + FunctionName: !GetAtt getUuidFunction.Arn + Principal: apigateway.amazonaws.com + SourceArn: !Sub arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${apiGateway}/${apiGatewayStageName}/*/ + lambdaIAMRole: + Type: AWS::IAM::Role + Properties: + AssumeRolePolicyDocument: + Version: 2012-10-17 + Statement: + - Action: + - sts:AssumeRole + Effect: Allow + Principal: + Service: + - lambda.amazonaws.com + Policies: + - PolicyDocument: + Version: 2012-10-17 + Statement: + - Action: + - logs:CreateLogGroup + - logs:CreateLogStream + - logs:PutLogEvents + Effect: Allow + Resource: + - !Sub arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/${lambdaFunctionName}:* + PolicyName: lambda + + lambdaLogGroup: + Type: AWS::Logs::LogGroup + Properties: + LogGroupName: !Sub /aws/lambda/${lambdaFunctionName} + RetentionInDays: 1 Outputs: - WebEndpoint: - Description: "API Gateway endpoint URL for Prod stage" - Value: !Sub "https://${Api}.execute-api.${AWS::Region}.amazonaws.com/Prod/" + + UuidWebEndpoint: + Description: "API Gateway endpoint URL for UUID endpoint" + Value: !Sub "https://${apiGateway}.execute-api.${AWS::Region}.amazonaws.com/dev/" \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 9a430ff6eb..a0a06fc835 100644 --- a/package-lock.json +++ b/package-lock.json @@ -298,9 +298,12 @@ "cdk-app": "bin/cdk-app.js" }, "devDependencies": { + "@aws-lambda-powertools/commons": "^1.11.1", "@aws-lambda-powertools/logger": "^1.11.1", "@aws-lambda-powertools/metrics": "^1.11.1", + "@aws-lambda-powertools/parameters": "^1.11.1", "@aws-lambda-powertools/tracer": "^1.11.1", + "@aws-sdk/client-ssm": "^3.360.0", "@aws-sdk/lib-dynamodb": "^3.360.0", "@types/aws-lambda": "^8.10.109", "@types/jest": "^29.2.4", @@ -340,10 +343,13 @@ "dependencies": { "@aws-lambda-powertools/logger": "^1.11.1", "@aws-lambda-powertools/metrics": "^1.11.1", + "@aws-lambda-powertools/parameters": "^1.11.1", "@aws-lambda-powertools/tracer": "^1.11.1", "@aws-sdk/client-dynamodb": "^3.360.0", + "@aws-sdk/client-ssm": "^3.360.0", "@aws-sdk/lib-dynamodb": "^3.360.0", "@middy/core": "^3.6.2", + "esbuild": "^0.18.14", "phin": "^3.7.0" }, "devDependencies": { @@ -352,7 +358,6 @@ "@types/node": "18.11.17", "@typescript-eslint/eslint-plugin": "^5.46.1", "@typescript-eslint/parser": "^5.46.1", - "esbuild": "^0.16.9", "eslint": "^8.30.0", "eslint-import-resolver-node": "^0.3.6", "eslint-import-resolver-typescript": "^3.5.2", @@ -363,12 +368,63 @@ "typescript": "^4.9.4" } }, + "examples/sam/node_modules/@esbuild/linux-arm64": { + "version": "0.18.15", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.18.15.tgz", + "integrity": "sha512-BWncQeuWDgYv0jTNzJjaNgleduV4tMbQjmk/zpPh/lUdMcNEAxy+jvneDJ6RJkrqloG7tB9S9rCrtfk/kuplsQ==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, "examples/sam/node_modules/@types/node": { "version": "18.11.17", "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.17.tgz", "integrity": "sha512-HJSUJmni4BeDHhfzn6nF0sVmd1SMezP7/4F0Lq+aXzmp2xm9O7WXrUtHW/CHlYVtZUbByEvWidHqRtcJXGF2Ng==", "dev": true }, + "examples/sam/node_modules/esbuild": { + "version": "0.18.15", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.18.15.tgz", + "integrity": "sha512-3WOOLhrvuTGPRzQPU6waSDWrDTnQriia72McWcn6UCi43GhCHrXH4S59hKMeez+IITmdUuUyvbU9JIp+t3xlPQ==", + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/android-arm": "0.18.15", + "@esbuild/android-arm64": "0.18.15", + "@esbuild/android-x64": "0.18.15", + "@esbuild/darwin-arm64": "0.18.15", + "@esbuild/darwin-x64": "0.18.15", + "@esbuild/freebsd-arm64": "0.18.15", + "@esbuild/freebsd-x64": "0.18.15", + "@esbuild/linux-arm": "0.18.15", + "@esbuild/linux-arm64": "0.18.15", + "@esbuild/linux-ia32": "0.18.15", + "@esbuild/linux-loong64": "0.18.15", + "@esbuild/linux-mips64el": "0.18.15", + "@esbuild/linux-ppc64": "0.18.15", + "@esbuild/linux-riscv64": "0.18.15", + "@esbuild/linux-s390x": "0.18.15", + "@esbuild/linux-x64": "0.18.15", + "@esbuild/netbsd-x64": "0.18.15", + "@esbuild/openbsd-x64": "0.18.15", + "@esbuild/sunos-x64": "0.18.15", + "@esbuild/win32-arm64": "0.18.15", + "@esbuild/win32-ia32": "0.18.15", + "@esbuild/win32-x64": "0.18.15" + } + }, "layers": { "version": "1.11.1", "license": "MIT-0", @@ -944,7 +1000,6 @@ "version": "3.360.0", "resolved": "https://registry.npmjs.org/@aws-sdk/client-ssm/-/client-ssm-3.360.0.tgz", "integrity": "sha512-VpykmgTlXeoCpOZFuvRuanJTJHa0OGrN84t2/07xAY1oxii0O+/ZH7/lcENpJAm9CJH1a/64smE/vVW4d0TFiw==", - "dev": true, "dependencies": { "@aws-crypto/sha256-browser": "3.0.0", "@aws-crypto/sha256-js": "3.0.0", @@ -991,7 +1046,6 @@ }, "node_modules/@aws-sdk/client-ssm/node_modules/uuid": { "version": "8.3.2", - "dev": true, "license": "MIT", "bin": { "uuid": "dist/bin/uuid" @@ -2720,6 +2774,126 @@ "@jridgewell/sourcemap-codec": "^1.4.10" } }, + "node_modules/@esbuild/android-arm": { + "version": "0.18.15", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.15.tgz", + "integrity": "sha512-wlkQBWb79/jeEEoRmrxt/yhn5T1lU236OCNpnfRzaCJHZ/5gf82uYx1qmADTBWE0AR/v7FiozE1auk2riyQd3w==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.18.15", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.18.15.tgz", + "integrity": "sha512-NI/gnWcMl2kXt1HJKOn2H69SYn4YNheKo6NZt1hyfKWdMbaGadxjZIkcj4Gjk/WPxnbFXs9/3HjGHaknCqjrww==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.18.15", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.18.15.tgz", + "integrity": "sha512-FM9NQamSaEm/IZIhegF76aiLnng1kEsZl2eve/emxDeReVfRuRNmvT28l6hoFD9TsCxpK+i4v8LPpEj74T7yjA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.18.15", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.18.15.tgz", + "integrity": "sha512-XmrFwEOYauKte9QjS6hz60FpOCnw4zaPAb7XV7O4lx1r39XjJhTN7ZpXqJh4sN6q60zbP6QwAVVA8N/wUyBH/w==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.18.15", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.18.15.tgz", + "integrity": "sha512-bMqBmpw1e//7Fh5GLetSZaeo9zSC4/CMtrVFdj+bqKPGJuKyfNJ5Nf2m3LknKZTS+Q4oyPiON+v3eaJ59sLB5A==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.18.15", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.15.tgz", + "integrity": "sha512-LoTK5N3bOmNI9zVLCeTgnk5Rk0WdUTrr9dyDAQGVMrNTh9EAPuNwSTCgaKOKiDpverOa0htPcO9NwslSE5xuLA==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.18.15", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.18.15.tgz", + "integrity": "sha512-62jX5n30VzgrjAjOk5orYeHFq6sqjvsIj1QesXvn5OZtdt5Gdj0vUNJy9NIpjfdNdqr76jjtzBJKf+h2uzYuTQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.18.15", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.18.15.tgz", + "integrity": "sha512-dT4URUv6ir45ZkBqhwZwyFV6cH61k8MttIwhThp2BGiVtagYvCToF+Bggyx2VI57RG4Fbt21f9TmXaYx0DeUJg==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, "node_modules/@esbuild/linux-arm64": { "version": "0.16.10", "cpu": [ @@ -2735,6 +2909,201 @@ "node": ">=12" } }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.18.15", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.18.15.tgz", + "integrity": "sha512-JPXORvgHRHITqfms1dWT/GbEY89u848dC08o0yK3fNskhp0t2TuNUnsrrSgOdH28ceb1hJuwyr8R/1RnyPwocw==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.18.15", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.18.15.tgz", + "integrity": "sha512-kArPI0DopjJCEplsVj/H+2Qgzz7vdFSacHNsgoAKpPS6W/Ndh8Oe24HRDQ5QCu4jHgN6XOtfFfLpRx3TXv/mEg==", + "cpu": [ + "loong64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.18.15", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.18.15.tgz", + "integrity": "sha512-b/tmngUfO02E00c1XnNTw/0DmloKjb6XQeqxaYuzGwHe0fHVgx5/D6CWi+XH1DvkszjBUkK9BX7n1ARTOst59w==", + "cpu": [ + "mips64el" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.18.15", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.18.15.tgz", + "integrity": "sha512-KXPY69MWw79QJkyvUYb2ex/OgnN/8N/Aw5UDPlgoRtoEfcBqfeLodPr42UojV3NdkoO4u10NXQdamWm1YEzSKw==", + "cpu": [ + "ppc64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.18.15", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.18.15.tgz", + "integrity": "sha512-komK3NEAeeGRnvFEjX1SfVg6EmkfIi5aKzevdvJqMydYr9N+pRQK0PGJXk+bhoPZwOUgLO4l99FZmLGk/L1jWg==", + "cpu": [ + "riscv64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.18.15", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.18.15.tgz", + "integrity": "sha512-632T5Ts6gQ2WiMLWRRyeflPAm44u2E/s/TJvn+BP6M5mnHSk93cieaypj3VSMYO2ePTCRqAFXtuYi1yv8uZJNA==", + "cpu": [ + "s390x" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.18.15", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.18.15.tgz", + "integrity": "sha512-MsHtX0NgvRHsoOtYkuxyk4Vkmvk3PLRWfA4okK7c+6dT0Fu4SUqXAr9y4Q3d8vUf1VWWb6YutpL4XNe400iQ1g==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.18.15", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.18.15.tgz", + "integrity": "sha512-djST6s+jQiwxMIVQ5rlt24JFIAr4uwUnzceuFL7BQT4CbrRtqBPueS4GjXSiIpmwVri1Icj/9pFRJ7/aScvT+A==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.18.15", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.18.15.tgz", + "integrity": "sha512-naeRhUIvhsgeounjkF5mvrNAVMGAm6EJWiabskeE5yOeBbLp7T89tAEw0j5Jm/CZAwyLe3c67zyCWH6fsBLCpw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.18.15", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.18.15.tgz", + "integrity": "sha512-qkT2+WxyKbNIKV1AEhI8QiSIgTHMcRctzSaa/I3kVgMS5dl3fOeoqkb7pW76KwxHoriImhx7Mg3TwN/auMDsyQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.18.15", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.18.15.tgz", + "integrity": "sha512-HC4/feP+pB2Vb+cMPUjAnFyERs+HJN7E6KaeBlFdBv799MhD+aPJlfi/yk36SED58J9TPwI8MAcVpJgej4ud0A==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.18.15", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.18.15.tgz", + "integrity": "sha512-ovjwoRXI+gf52EVF60u9sSDj7myPixPxqzD5CmkEUmvs+W9Xd0iqISVBQn8xcx4ciIaIVlWCuTbYDOXOnOL44Q==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.18.15", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.18.15.tgz", + "integrity": "sha512-imUxH9a3WJARyAvrG7srLyiK73XdX83NXQkjKvQ+7vPh3ZxoLrzvPkQKKw2DwZ+RV2ZB6vBfNHP8XScAmQC3aA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, "node_modules/@eslint/eslintrc": { "version": "1.4.0", "dev": true, From ee0a141523aa1c5b151086629cd3ad0f2fe11a73 Mon Sep 17 00:00:00 2001 From: Andrea Amorosi Date: Tue, 25 Jul 2023 13:25:04 +0200 Subject: [PATCH 10/11] chore(commons): bump version prior to release (#1628) --- packages/commons/src/version.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/commons/src/version.ts b/packages/commons/src/version.ts index 60a864ee4c..420b30006c 100644 --- a/packages/commons/src/version.ts +++ b/packages/commons/src/version.ts @@ -1,2 +1,2 @@ // this file is auto generated, do not modify -export const PT_VERSION = '1.11.1'; +export const PT_VERSION = '1.12.0'; From 368bb0ddf5edf0c0f9a3bfc0f1568af3d31fb834 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Tue, 25 Jul 2023 11:53:51 +0000 Subject: [PATCH 11/11] chore(release): v1.12.0 [skip ci] --- CHANGELOG.md | 7 ++++ examples/cdk/CHANGELOG.md | 4 ++ examples/cdk/package.json | 12 +++--- examples/sam/CHANGELOG.md | 4 ++ examples/sam/package.json | 10 ++--- layers/CHANGELOG.md | 4 ++ layers/package.json | 2 +- lerna.json | 2 +- package-lock.json | 61 ++++++++++++++----------------- packages/batch/CHANGELOG.md | 10 +++++ packages/batch/package.json | 8 ++-- packages/commons/CHANGELOG.md | 4 ++ packages/commons/package.json | 2 +- packages/idempotency/CHANGELOG.md | 4 ++ packages/idempotency/package.json | 4 +- packages/logger/CHANGELOG.md | 6 +++ packages/logger/package.json | 4 +- packages/metrics/CHANGELOG.md | 4 ++ packages/metrics/package.json | 4 +- packages/parameters/CHANGELOG.md | 4 ++ packages/parameters/package.json | 4 +- packages/tracer/CHANGELOG.md | 4 ++ packages/tracer/package.json | 4 +- 23 files changed, 110 insertions(+), 62 deletions(-) create mode 100644 packages/batch/CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md index 53a55d6ce7..f7776da538 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,13 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [1.12.0](https://github.com/aws-powertools/powertools-lambda-typescript/compare/v1.11.1...v1.12.0) (2023-07-25) + +### Features + +- **batch:** add batch processing utility ([#1625](https://github.com/aws-powertools/powertools-lambda-typescript/issues/1625)) ([c4e6b19](https://github.com/aws-powertools/powertools-lambda-typescript/commit/c4e6b192c3658cbcc3f458a579a0752153e3c201)), closes [#1588](https://github.com/aws-powertools/powertools-lambda-typescript/issues/1588) [#1591](https://github.com/aws-powertools/powertools-lambda-typescript/issues/1591) [#1593](https://github.com/aws-powertools/powertools-lambda-typescript/issues/1593) [#1592](https://github.com/aws-powertools/powertools-lambda-typescript/issues/1592) [#1594](https://github.com/aws-powertools/powertools-lambda-typescript/issues/1594) +- **logger:** add cause to formatted error ([#1617](https://github.com/aws-powertools/powertools-lambda-typescript/issues/1617)) ([6a14595](https://github.com/aws-powertools/powertools-lambda-typescript/commit/6a145959249db6eeb89fdfe3ed4c6e30ab155f9c)) + ## [1.11.1](https://github.com/aws-powertools/powertools-lambda-typescript/compare/v1.11.0...v1.11.1) (2023-07-11) ### Bug Fixes diff --git a/examples/cdk/CHANGELOG.md b/examples/cdk/CHANGELOG.md index e4efad8067..52106fd385 100644 --- a/examples/cdk/CHANGELOG.md +++ b/examples/cdk/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [1.12.0](https://github.com/aws-powertools/powertools-lambda-typescript/compare/v1.11.1...v1.12.0) (2023-07-25) + +**Note:** Version bump only for package cdk-sample + ## [1.11.1](https://github.com/aws-powertools/powertools-lambda-typescript/compare/v1.11.0...v1.11.1) (2023-07-11) **Note:** Version bump only for package cdk-sample diff --git a/examples/cdk/package.json b/examples/cdk/package.json index d5c5454281..22df4a149c 100644 --- a/examples/cdk/package.json +++ b/examples/cdk/package.json @@ -1,6 +1,6 @@ { "name": "cdk-sample", - "version": "1.11.1", + "version": "1.12.0", "author": { "name": "Amazon Web Services", "url": "https://aws.amazon.com" @@ -25,11 +25,11 @@ "*.js": "npm run lint-fix" }, "devDependencies": { - "@aws-lambda-powertools/commons": "^1.11.1", - "@aws-lambda-powertools/logger": "^1.11.1", - "@aws-lambda-powertools/metrics": "^1.11.1", - "@aws-lambda-powertools/parameters": "^1.11.1", - "@aws-lambda-powertools/tracer": "^1.11.1", + "@aws-lambda-powertools/commons": "^1.12.0", + "@aws-lambda-powertools/logger": "^1.12.0", + "@aws-lambda-powertools/metrics": "^1.12.0", + "@aws-lambda-powertools/parameters": "^1.12.0", + "@aws-lambda-powertools/tracer": "^1.12.0", "@aws-sdk/client-ssm": "^3.360.0", "@aws-sdk/lib-dynamodb": "^3.360.0", "@types/aws-lambda": "^8.10.109", diff --git a/examples/sam/CHANGELOG.md b/examples/sam/CHANGELOG.md index 940b2e83c4..74aed3e7a4 100644 --- a/examples/sam/CHANGELOG.md +++ b/examples/sam/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [1.12.0](https://github.com/aws-powertools/powertools-lambda-typescript/compare/v1.11.1...v1.12.0) (2023-07-25) + +**Note:** Version bump only for package sam-example + ## [1.11.1](https://github.com/aws-powertools/powertools-lambda-typescript/compare/v1.11.0...v1.11.1) (2023-07-11) **Note:** Version bump only for package sam-example diff --git a/examples/sam/package.json b/examples/sam/package.json index 9a35d20c62..af2bf4e46e 100644 --- a/examples/sam/package.json +++ b/examples/sam/package.json @@ -1,6 +1,6 @@ { "name": "sam-example", - "version": "1.11.1", + "version": "1.12.0", "author": { "name": "Amazon Web Services", "url": "https://aws.amazon.com" @@ -36,10 +36,10 @@ "typescript": "^4.9.4" }, "dependencies": { - "@aws-lambda-powertools/logger": "^1.11.1", - "@aws-lambda-powertools/metrics": "^1.11.1", - "@aws-lambda-powertools/tracer": "^1.11.1", - "@aws-lambda-powertools/parameters": "^1.11.1", + "@aws-lambda-powertools/logger": "^1.12.0", + "@aws-lambda-powertools/metrics": "^1.12.0", + "@aws-lambda-powertools/parameters": "^1.12.0", + "@aws-lambda-powertools/tracer": "^1.12.0", "@aws-sdk/client-dynamodb": "^3.360.0", "@aws-sdk/client-ssm": "^3.360.0", "@aws-sdk/lib-dynamodb": "^3.360.0", diff --git a/layers/CHANGELOG.md b/layers/CHANGELOG.md index ed53105c60..a83cac7762 100644 --- a/layers/CHANGELOG.md +++ b/layers/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [1.12.0](https://github.com/aws-powertools/powertools-lambda-typescript/compare/v1.11.1...v1.12.0) (2023-07-25) + +**Note:** Version bump only for package layers + ## [1.11.1](https://github.com/aws-powertools/powertools-lambda-typescript/compare/v1.11.0...v1.11.1) (2023-07-11) **Note:** Version bump only for package layers diff --git a/layers/package.json b/layers/package.json index a7b43a2954..655b801af3 100644 --- a/layers/package.json +++ b/layers/package.json @@ -1,6 +1,6 @@ { "name": "layers", - "version": "1.11.1", + "version": "1.12.0", "bin": { "layer": "bin/layers.js" }, diff --git a/lerna.json b/lerna.json index ee57bfb2a1..29b0682966 100644 --- a/lerna.json +++ b/lerna.json @@ -11,7 +11,7 @@ "examples/sam", "layers" ], - "version": "1.11.1", + "version": "1.12.0", "npmClient": "npm", "message": "chore(release): %s [skip ci]" } diff --git a/package-lock.json b/package-lock.json index a0a06fc835..304f5c94fc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,11 +15,11 @@ "packages/tracer", "packages/parameters", "packages/idempotency", - "packages/batch", "docs/snippets", "layers", "examples/cdk", - "examples/sam" + "examples/sam", + "packages/batch" ], "devDependencies": { "@aws-cdk/cloudformation-diff": "^2.73.0", @@ -285,7 +285,7 @@ }, "examples/cdk": { "name": "cdk-sample", - "version": "1.11.1", + "version": "1.12.0", "license": "MIT-0", "dependencies": { "@middy/core": "^3.6.2", @@ -298,11 +298,11 @@ "cdk-app": "bin/cdk-app.js" }, "devDependencies": { - "@aws-lambda-powertools/commons": "^1.11.1", - "@aws-lambda-powertools/logger": "^1.11.1", - "@aws-lambda-powertools/metrics": "^1.11.1", - "@aws-lambda-powertools/parameters": "^1.11.1", - "@aws-lambda-powertools/tracer": "^1.11.1", + "@aws-lambda-powertools/commons": "^1.12.0", + "@aws-lambda-powertools/logger": "^1.12.0", + "@aws-lambda-powertools/metrics": "^1.12.0", + "@aws-lambda-powertools/parameters": "^1.12.0", + "@aws-lambda-powertools/tracer": "^1.12.0", "@aws-sdk/client-ssm": "^3.360.0", "@aws-sdk/lib-dynamodb": "^3.360.0", "@types/aws-lambda": "^8.10.109", @@ -338,13 +338,13 @@ }, "examples/sam": { "name": "sam-example", - "version": "1.11.1", + "version": "1.12.0", "license": "MIT-0", "dependencies": { - "@aws-lambda-powertools/logger": "^1.11.1", - "@aws-lambda-powertools/metrics": "^1.11.1", - "@aws-lambda-powertools/parameters": "^1.11.1", - "@aws-lambda-powertools/tracer": "^1.11.1", + "@aws-lambda-powertools/logger": "^1.12.0", + "@aws-lambda-powertools/metrics": "^1.12.0", + "@aws-lambda-powertools/parameters": "^1.12.0", + "@aws-lambda-powertools/tracer": "^1.12.0", "@aws-sdk/client-dynamodb": "^3.360.0", "@aws-sdk/client-ssm": "^3.360.0", "@aws-sdk/lib-dynamodb": "^3.360.0", @@ -426,7 +426,7 @@ } }, "layers": { - "version": "1.11.1", + "version": "1.12.0", "license": "MIT-0", "bin": { "layer": "bin/layers.js" @@ -6964,10 +6964,6 @@ ], "license": "MIT" }, - "node_modules/batch": { - "resolved": "packages/batch", - "link": true - }, "node_modules/before-after-hook": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.3.tgz", @@ -18364,13 +18360,12 @@ }, "packages/batch": { "name": "@aws-lambda-powertools/batch", - "version": "1.10.0", - "license": "MIT-0", - "devDependencies": {} + "version": "1.12.0", + "license": "MIT-0" }, "packages/commons": { "name": "@aws-lambda-powertools/commons", - "version": "1.11.1", + "version": "1.12.0", "license": "MIT-0", "devDependencies": { "@aws-sdk/client-appconfigdata": "^3.360.0", @@ -18383,10 +18378,10 @@ }, "packages/idempotency": { "name": "@aws-lambda-powertools/idempotency", - "version": "1.11.1", + "version": "1.12.0", "license": "MIT-0", "dependencies": { - "@aws-lambda-powertools/commons": "^1.11.1", + "@aws-lambda-powertools/commons": "^1.12.0", "@aws-sdk/lib-dynamodb": "^3.231.0", "@aws-sdk/util-base64-node": "^3.209.0", "jmespath": "^0.16.0" @@ -18603,10 +18598,10 @@ }, "packages/logger": { "name": "@aws-lambda-powertools/logger", - "version": "1.11.1", + "version": "1.12.0", "license": "MIT-0", "dependencies": { - "@aws-lambda-powertools/commons": "^1.11.1", + "@aws-lambda-powertools/commons": "^1.12.0", "lodash.merge": "^4.6.2" }, "devDependencies": { @@ -18615,10 +18610,10 @@ }, "packages/metrics": { "name": "@aws-lambda-powertools/metrics", - "version": "1.11.1", + "version": "1.12.0", "license": "MIT-0", "dependencies": { - "@aws-lambda-powertools/commons": "^1.11.1" + "@aws-lambda-powertools/commons": "^1.12.0" }, "devDependencies": { "@aws-sdk/client-cloudwatch": "^3.360.0", @@ -18628,10 +18623,10 @@ }, "packages/parameters": { "name": "@aws-lambda-powertools/parameters", - "version": "1.11.1", + "version": "1.12.0", "license": "MIT-0", "dependencies": { - "@aws-lambda-powertools/commons": "^1.11.1", + "@aws-lambda-powertools/commons": "^1.12.0", "@aws-sdk/util-base64-node": "^3.209.0" }, "devDependencies": { @@ -18849,10 +18844,10 @@ }, "packages/tracer": { "name": "@aws-lambda-powertools/tracer", - "version": "1.11.1", + "version": "1.12.0", "license": "MIT-0", "dependencies": { - "@aws-lambda-powertools/commons": "^1.11.1", + "@aws-lambda-powertools/commons": "^1.12.0", "aws-xray-sdk-core": "^3.4.1" }, "devDependencies": { @@ -18866,4 +18861,4 @@ } } } -} \ No newline at end of file +} diff --git a/packages/batch/CHANGELOG.md b/packages/batch/CHANGELOG.md new file mode 100644 index 0000000000..fc29760c74 --- /dev/null +++ b/packages/batch/CHANGELOG.md @@ -0,0 +1,10 @@ +# Change Log + +All notable changes to this project will be documented in this file. +See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. + +# [1.12.0](https://github.com/aws-powertools/powertools-lambda-typescript/compare/v1.11.1...v1.12.0) (2023-07-25) + +### Features + +- **batch:** add batch processing utility ([#1625](https://github.com/aws-powertools/powertools-lambda-typescript/issues/1625)) ([c4e6b19](https://github.com/aws-powertools/powertools-lambda-typescript/commit/c4e6b192c3658cbcc3f458a579a0752153e3c201)), closes [#1588](https://github.com/aws-powertools/powertools-lambda-typescript/issues/1588) [#1591](https://github.com/aws-powertools/powertools-lambda-typescript/issues/1591) [#1593](https://github.com/aws-powertools/powertools-lambda-typescript/issues/1593) [#1592](https://github.com/aws-powertools/powertools-lambda-typescript/issues/1592) [#1594](https://github.com/aws-powertools/powertools-lambda-typescript/issues/1594) diff --git a/packages/batch/package.json b/packages/batch/package.json index f87fb225ac..8a310e6367 100644 --- a/packages/batch/package.json +++ b/packages/batch/package.json @@ -1,6 +1,6 @@ { "name": "@aws-lambda-powertools/batch", - "version": "1.11.1", + "version": "1.12.0", "description": "The batch processing package for the Powertools for AWS Lambda (TypeScript) library.", "author": { "name": "Amazon Web Services", @@ -40,7 +40,6 @@ "bugs": { "url": "https://github.com/aws-powertools/powertools-lambda-typescript/issues" }, - "dependencies": {}, "keywords": [ "aws", "lambda", @@ -49,6 +48,5 @@ "batch-processing", "serverless", "nodejs" - ], - "devDependencies": {} -} \ No newline at end of file + ] +} diff --git a/packages/commons/CHANGELOG.md b/packages/commons/CHANGELOG.md index 5feb285227..86e753be19 100644 --- a/packages/commons/CHANGELOG.md +++ b/packages/commons/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [1.12.0](https://github.com/aws-powertools/powertools-lambda-typescript/compare/v1.11.1...v1.12.0) (2023-07-25) + +**Note:** Version bump only for package @aws-lambda-powertools/commons + ## [1.11.1](https://github.com/aws-powertools/powertools-lambda-typescript/compare/v1.11.0...v1.11.1) (2023-07-11) **Note:** Version bump only for package @aws-lambda-powertools/commons diff --git a/packages/commons/package.json b/packages/commons/package.json index 7830b218bc..995fe39b30 100644 --- a/packages/commons/package.json +++ b/packages/commons/package.json @@ -1,6 +1,6 @@ { "name": "@aws-lambda-powertools/commons", - "version": "1.11.1", + "version": "1.12.0", "description": "A shared utility package for Powertools for AWS Lambda (TypeScript) libraries", "author": { "name": "Amazon Web Services", diff --git a/packages/idempotency/CHANGELOG.md b/packages/idempotency/CHANGELOG.md index 67a7488b19..0ae8805b66 100644 --- a/packages/idempotency/CHANGELOG.md +++ b/packages/idempotency/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [1.12.0](https://github.com/aws-powertools/powertools-lambda-typescript/compare/v1.11.1...v1.12.0) (2023-07-25) + +**Note:** Version bump only for package @aws-lambda-powertools/idempotency + ## [1.11.1](https://github.com/aws-powertools/powertools-lambda-typescript/compare/v1.11.0...v1.11.1) (2023-07-11) ### Bug Fixes diff --git a/packages/idempotency/package.json b/packages/idempotency/package.json index cdd66eb073..7a6f98b336 100644 --- a/packages/idempotency/package.json +++ b/packages/idempotency/package.json @@ -1,6 +1,6 @@ { "name": "@aws-lambda-powertools/idempotency", - "version": "1.11.1", + "version": "1.12.0", "description": "The idempotency package for the Powertools for AWS Lambda (TypeScript) library. It provides options to make your Lambda functions idempotent and safe to retry.", "author": { "name": "Amazon Web Services", @@ -80,7 +80,7 @@ "url": "https://github.com/aws-powertools/powertools-lambda-typescript/issues" }, "dependencies": { - "@aws-lambda-powertools/commons": "^1.11.1", + "@aws-lambda-powertools/commons": "^1.12.0", "@aws-sdk/lib-dynamodb": "^3.231.0", "@aws-sdk/util-base64-node": "^3.209.0", "jmespath": "^0.16.0" diff --git a/packages/logger/CHANGELOG.md b/packages/logger/CHANGELOG.md index f43ac30a1b..e017c2dbd4 100644 --- a/packages/logger/CHANGELOG.md +++ b/packages/logger/CHANGELOG.md @@ -3,6 +3,12 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [1.12.0](https://github.com/aws-powertools/powertools-lambda-typescript/compare/v1.11.1...v1.12.0) (2023-07-25) + +### Features + +- **logger:** add cause to formatted error ([#1617](https://github.com/aws-powertools/powertools-lambda-typescript/issues/1617)) ([6a14595](https://github.com/aws-powertools/powertools-lambda-typescript/commit/6a145959249db6eeb89fdfe3ed4c6e30ab155f9c)) + ## [1.11.1](https://github.com/aws-powertools/powertools-lambda-typescript/compare/v1.11.0...v1.11.1) (2023-07-11) **Note:** Version bump only for package @aws-lambda-powertools/logger diff --git a/packages/logger/package.json b/packages/logger/package.json index 77bc0399e3..7165950e39 100644 --- a/packages/logger/package.json +++ b/packages/logger/package.json @@ -1,6 +1,6 @@ { "name": "@aws-lambda-powertools/logger", - "version": "1.11.1", + "version": "1.12.0", "description": "The logging package for the Powertools for AWS Lambda (TypeScript) library", "author": { "name": "Amazon Web Services", @@ -45,7 +45,7 @@ "url": "https://github.com/aws-powertools/powertools-lambda-typescript/issues" }, "dependencies": { - "@aws-lambda-powertools/commons": "^1.11.1", + "@aws-lambda-powertools/commons": "^1.12.0", "lodash.merge": "^4.6.2" }, "keywords": [ diff --git a/packages/metrics/CHANGELOG.md b/packages/metrics/CHANGELOG.md index 847089eba3..735f525ea8 100644 --- a/packages/metrics/CHANGELOG.md +++ b/packages/metrics/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [1.12.0](https://github.com/aws-powertools/powertools-lambda-typescript/compare/v1.11.1...v1.12.0) (2023-07-25) + +**Note:** Version bump only for package @aws-lambda-powertools/metrics + ## [1.11.1](https://github.com/aws-powertools/powertools-lambda-typescript/compare/v1.11.0...v1.11.1) (2023-07-11) **Note:** Version bump only for package @aws-lambda-powertools/metrics diff --git a/packages/metrics/package.json b/packages/metrics/package.json index 195c2d9635..5370c0410a 100644 --- a/packages/metrics/package.json +++ b/packages/metrics/package.json @@ -1,6 +1,6 @@ { "name": "@aws-lambda-powertools/metrics", - "version": "1.11.1", + "version": "1.12.0", "description": "The metrics package for the Powertools for AWS Lambda (TypeScript) library", "author": { "name": "Amazon Web Services", @@ -47,7 +47,7 @@ "url": "https://github.com/aws-powertools/powertools-lambda-typescript/issues" }, "dependencies": { - "@aws-lambda-powertools/commons": "^1.11.1" + "@aws-lambda-powertools/commons": "^1.12.0" }, "keywords": [ "aws", diff --git a/packages/parameters/CHANGELOG.md b/packages/parameters/CHANGELOG.md index 9c5c8d8f05..83ade15f60 100644 --- a/packages/parameters/CHANGELOG.md +++ b/packages/parameters/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [1.12.0](https://github.com/aws-powertools/powertools-lambda-typescript/compare/v1.11.1...v1.12.0) (2023-07-25) + +**Note:** Version bump only for package @aws-lambda-powertools/parameters + ## [1.11.1](https://github.com/aws-powertools/powertools-lambda-typescript/compare/v1.11.0...v1.11.1) (2023-07-11) **Note:** Version bump only for package @aws-lambda-powertools/parameters diff --git a/packages/parameters/package.json b/packages/parameters/package.json index 6f65015f98..c0bb82c41f 100644 --- a/packages/parameters/package.json +++ b/packages/parameters/package.json @@ -1,6 +1,6 @@ { "name": "@aws-lambda-powertools/parameters", - "version": "1.11.1", + "version": "1.12.0", "description": "The parameters package for the Powertools for AWS Lambda (TypeScript) library", "author": { "name": "Amazon Web Services", @@ -147,7 +147,7 @@ "aws-sdk-client-mock-jest": "^2.2.0" }, "dependencies": { - "@aws-lambda-powertools/commons": "^1.11.1", + "@aws-lambda-powertools/commons": "^1.12.0", "@aws-sdk/util-base64-node": "^3.209.0" } } diff --git a/packages/tracer/CHANGELOG.md b/packages/tracer/CHANGELOG.md index 3c70c2dad8..1ef9cde6b8 100644 --- a/packages/tracer/CHANGELOG.md +++ b/packages/tracer/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [1.12.0](https://github.com/aws-powertools/powertools-lambda-typescript/compare/v1.11.1...v1.12.0) (2023-07-25) + +**Note:** Version bump only for package @aws-lambda-powertools/tracer + ## [1.11.1](https://github.com/aws-powertools/powertools-lambda-typescript/compare/v1.11.0...v1.11.1) (2023-07-11) **Note:** Version bump only for package @aws-lambda-powertools/tracer diff --git a/packages/tracer/package.json b/packages/tracer/package.json index d3c98ff426..5615fc7111 100644 --- a/packages/tracer/package.json +++ b/packages/tracer/package.json @@ -1,6 +1,6 @@ { "name": "@aws-lambda-powertools/tracer", - "version": "1.11.1", + "version": "1.12.0", "description": "The tracer package for the Powertools for AWS Lambda (TypeScript) library", "author": { "name": "Amazon Web Services", @@ -51,7 +51,7 @@ "url": "https://github.com/aws-powertools/powertools-lambda-typescript/issues" }, "dependencies": { - "@aws-lambda-powertools/commons": "^1.11.1", + "@aws-lambda-powertools/commons": "^1.12.0", "aws-xray-sdk-core": "^3.4.1" }, "keywords": [