From cab716df528b0f6ce9082dbc089cd5c234ab1264 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 7 Mar 2025 10:21:43 +0100 Subject: [PATCH 01/56] chore(ci): update layer ARN on documentation (#3703) --- docs/index.md | 80 +++++++++++++++++++++++++-------------------------- 1 file changed, 40 insertions(+), 40 deletions(-) diff --git a/docs/index.md b/docs/index.md index 592fc46a73..680d346464 100644 --- a/docs/index.md +++ b/docs/index.md @@ -69,7 +69,7 @@ You can use Powertools for AWS Lambda (TypeScript) by installing it with your fa For the latter, make sure to replace `{region}` with your AWS region, e.g., `eu-west-1`. - __arn:aws:lambda:{region}:094274105915:layer:AWSLambdaPowertoolsTypeScriptV2:21__{: .copyMe}:clipboard: + __arn:aws:lambda:{region}:094274105915:layer:AWSLambdaPowertoolsTypeScriptV2:22__{: .copyMe}:clipboard: ???+ note "Code snippets for popular infrastructure as code frameworks" @@ -89,7 +89,7 @@ You can use Powertools for AWS Lambda (TypeScript) by installing it with your fa const powertoolsLayer = LayerVersion.fromLayerVersionArn( this, 'PowertoolsLayer', - `arn:aws:lambda:${Stack.of(this).region}:094274105915:layer:AWSLambdaPowertoolsTypeScriptV2:21` + `arn:aws:lambda:${Stack.of(this).region}:094274105915:layer:AWSLambdaPowertoolsTypeScriptV2:22` ); new Function(this, 'Function', { @@ -126,7 +126,7 @@ You can use Powertools for AWS Lambda (TypeScript) by installing it with your fa Type: AWS::Serverless::Function Properties: Layers: - - !Sub arn:aws:lambda:${AWS::Region}:094274105915:layer:AWSLambdaPowertoolsTypeScriptV2:21 + - !Sub arn:aws:lambda:${AWS::Region}:094274105915:layer:AWSLambdaPowertoolsTypeScriptV2:22 ``` You can also use AWS SSM Parameter Store to dynamically add Powertools for AWS Lambda. The `{version}` placeholder is the semantic version number (e,g. 2.1.0) for a release or `_latest_`. @@ -165,7 +165,7 @@ You can use Powertools for AWS Lambda (TypeScript) by installing it with your fa hello: handler: lambda_function.lambda_handler layers: - - arn:aws:lambda:${aws:region}:094274105915:layer:AWSLambdaPowertoolsTypeScriptV2:21 + - arn:aws:lambda:${aws:region}:094274105915:layer:AWSLambdaPowertoolsTypeScriptV2:22 ``` If you use `esbuild` to bundle your code, make sure to exclude `@aws-lambda-powertools/*` and `@aws-sdk/*` from being bundled since the packages are already present the layer: @@ -200,7 +200,7 @@ You can use Powertools for AWS Lambda (TypeScript) by installing it with your fa role = ... handler = "index.handler" runtime = "nodejs22.x" - layers = ["arn:aws:lambda:{aws::region}:094274105915:layer:AWSLambdaPowertoolsTypeScriptV2:21"] + layers = ["arn:aws:lambda:{aws::region}:094274105915:layer:AWSLambdaPowertoolsTypeScriptV2:22"] source_code_hash = filebase64sha256("lambda_function_payload.zip") } ``` @@ -235,7 +235,7 @@ You can use Powertools for AWS Lambda (TypeScript) by installing it with your fa const lambdaFunction = new aws.lambda.Function('function', { layers: [ - pulumi.interpolate`arn:aws:lambda:${aws.getRegionOutput().name}:094274105915:layer:AWSLambdaPowertoolsTypeScriptV2:21` + pulumi.interpolate`arn:aws:lambda:${aws.getRegionOutput().name}:094274105915:layer:AWSLambdaPowertoolsTypeScriptV2:22` ], code: new pulumi.asset.FileArchive('lambda_function_payload.zip'), tracingConfig: { @@ -259,7 +259,7 @@ You can use Powertools for AWS Lambda (TypeScript) by installing it with your fa name: "my-function", layers: { "@aws-lambda-powertools/*": - "arn:aws:lambda:${AWS::Region}:094274105915:layer:AWSLambdaPowertoolsTypeScriptV2:21", + "arn:aws:lambda:${AWS::Region}:094274105915:layer:AWSLambdaPowertoolsTypeScriptV2:22", }, }); ``` @@ -273,38 +273,38 @@ You can use the Lambda Layer both with CommonJS and ESM (ECMAScript modules) for ??? note "Click to expand and copy any regional Lambda Layer ARN" | Region | Layer ARN | | ---------------- | ------------------------------------------------------------------------------------------------------------- | - | `us-east-1` | [arn:aws:lambda:us-east-1:094274105915:layer:AWSLambdaPowertoolsTypeScriptV2:21](#){: .copyMe}:clipboard: | - | `us-east-2` | [arn:aws:lambda:us-east-2:094274105915:layer:AWSLambdaPowertoolsTypeScriptV2:21](#){: .copyMe}:clipboard: | - | `us-west-1` | [arn:aws:lambda:us-west-1:094274105915:layer:AWSLambdaPowertoolsTypeScriptV2:21](#){: .copyMe}:clipboard: | - | `us-west-2` | [arn:aws:lambda:us-west-2:094274105915:layer:AWSLambdaPowertoolsTypeScriptV2:21](#){: .copyMe}:clipboard: | - | `ap-south-1` | [arn:aws:lambda:ap-south-1:094274105915:layer:AWSLambdaPowertoolsTypeScriptV2:21](#){: .copyMe}:clipboard: | - | `ap-south-2` | [arn:aws:lambda:ap-south-2:094274105915:layer:AWSLambdaPowertoolsTypeScriptV2:21](#){: .copyMe}:clipboard: | - | `ap-east-1` | [arn:aws:lambda:ap-east-1:094274105915:layer:AWSLambdaPowertoolsTypeScriptV2:21](#){: .copyMe}:clipboard: | - | `ap-northeast-1` | [arn:aws:lambda:ap-northeast-1:094274105915:layer:AWSLambdaPowertoolsTypeScriptV2:21](#){: .copyMe}:clipboard: | - | `ap-northeast-2` | [arn:aws:lambda:ap-northeast-2:094274105915:layer:AWSLambdaPowertoolsTypeScriptV2:21](#){: .copyMe}:clipboard: | - | `ap-northeast-3` | [arn:aws:lambda:ap-northeast-3:094274105915:layer:AWSLambdaPowertoolsTypeScriptV2:21](#){: .copyMe}:clipboard: | - | `ap-southeast-1` | [arn:aws:lambda:ap-southeast-1:094274105915:layer:AWSLambdaPowertoolsTypeScriptV2:21](#){: .copyMe}:clipboard: | - | `ap-southeast-2` | [arn:aws:lambda:ap-southeast-2:094274105915:layer:AWSLambdaPowertoolsTypeScriptV2:21](#){: .copyMe}:clipboard: | - | `ap-southeast-3` | [arn:aws:lambda:ap-southeast-3:094274105915:layer:AWSLambdaPowertoolsTypeScriptV2:21](#){: .copyMe}:clipboard: | - | `ap-southeast-4` | [arn:aws:lambda:ap-southeast-4:094274105915:layer:AWSLambdaPowertoolsTypeScriptV2:21](#){: .copyMe}:clipboard: | - | `ap-southeast-5` | [arn:aws:lambda:ap-southeast-5:094274105915:layer:AWSLambdaPowertoolsTypeScriptV2:21](#){: .copyMe}:clipboard: | - | `ap-southeast-7` | [arn:aws:lambda:ap-southeast-7:094274105915:layer:AWSLambdaPowertoolsTypeScriptV2:21](#){: .copyMe}:clipboard: | - | `eu-central-1` | [arn:aws:lambda:eu-central-1:094274105915:layer:AWSLambdaPowertoolsTypeScriptV2:21](#){: .copyMe}:clipboard: | - | `eu-central-2` | [arn:aws:lambda:eu-central-1:094274105915:layer:AWSLambdaPowertoolsTypeScriptV2:21](#){: .copyMe}:clipboard: | - | `eu-west-1` | [arn:aws:lambda:eu-west-1:094274105915:layer:AWSLambdaPowertoolsTypeScriptV2:21](#){: .copyMe}:clipboard: | - | `eu-west-2` | [arn:aws:lambda:eu-west-2:094274105915:layer:AWSLambdaPowertoolsTypeScriptV2:21](#){: .copyMe}:clipboard: | - | `eu-west-3` | [arn:aws:lambda:eu-west-3:094274105915:layer:AWSLambdaPowertoolsTypeScriptV2:21](#){: .copyMe}:clipboard: | - | `eu-north-1` | [arn:aws:lambda:eu-north-1:094274105915:layer:AWSLambdaPowertoolsTypeScriptV2:21](#){: .copyMe}:clipboard: | - | `eu-south-1` | [arn:aws:lambda:eu-south-1:094274105915:layer:AWSLambdaPowertoolsTypeScriptV2:21](#){: .copyMe}:clipboard: | - | `eu-south-2` | [arn:aws:lambda:eu-south-2:094274105915:layer:AWSLambdaPowertoolsTypeScriptV2:21](#){: .copyMe}:clipboard: | - | `ca-central-1` | [arn:aws:lambda:ca-central-1:094274105915:layer:AWSLambdaPowertoolsTypeScriptV2:21](#){: .copyMe}:clipboard: | - | `ca-west-1` | [arn:aws:lambda:ca-west-1:094274105915:layer:AWSLambdaPowertoolsTypeScriptV2:21](#){: .copyMe}:clipboard: | - | `sa-east-1` | [arn:aws:lambda:sa-east-1:094274105915:layer:AWSLambdaPowertoolsTypeScriptV2:21](#){: .copyMe}:clipboard: | - | `af-south-1` | [arn:aws:lambda:af-south-1:094274105915:layer:AWSLambdaPowertoolsTypeScriptV2:21](#){: .copyMe}:clipboard: | - | `me-south-1` | [arn:aws:lambda:me-south-1:094274105915:layer:AWSLambdaPowertoolsTypeScriptV2:21](#){: .copyMe}:clipboard: | - | `me-central-1` | [arn:aws:lambda:me-central-1:094274105915:layer:AWSLambdaPowertoolsTypeScriptV2:21](#){: .copyMe}:clipboard: | - | `il-central-1` | [arn:aws:lambda:il-central-1:094274105915:layer:AWSLambdaPowertoolsTypeScriptV2:21](#){: .copyMe}:clipboard: | - | `mx-central-1` | [arn:aws:lambda:mx-central-1:094274105915:layer:AWSLambdaPowertoolsTypeScriptV2:21](#){: .copyMe}:clipboard: | + | `us-east-1` | [arn:aws:lambda:us-east-1:094274105915:layer:AWSLambdaPowertoolsTypeScriptV2:22](#){: .copyMe}:clipboard: | + | `us-east-2` | [arn:aws:lambda:us-east-2:094274105915:layer:AWSLambdaPowertoolsTypeScriptV2:22](#){: .copyMe}:clipboard: | + | `us-west-1` | [arn:aws:lambda:us-west-1:094274105915:layer:AWSLambdaPowertoolsTypeScriptV2:22](#){: .copyMe}:clipboard: | + | `us-west-2` | [arn:aws:lambda:us-west-2:094274105915:layer:AWSLambdaPowertoolsTypeScriptV2:22](#){: .copyMe}:clipboard: | + | `ap-south-1` | [arn:aws:lambda:ap-south-1:094274105915:layer:AWSLambdaPowertoolsTypeScriptV2:22](#){: .copyMe}:clipboard: | + | `ap-south-2` | [arn:aws:lambda:ap-south-2:094274105915:layer:AWSLambdaPowertoolsTypeScriptV2:22](#){: .copyMe}:clipboard: | + | `ap-east-1` | [arn:aws:lambda:ap-east-1:094274105915:layer:AWSLambdaPowertoolsTypeScriptV2:22](#){: .copyMe}:clipboard: | + | `ap-northeast-1` | [arn:aws:lambda:ap-northeast-1:094274105915:layer:AWSLambdaPowertoolsTypeScriptV2:22](#){: .copyMe}:clipboard: | + | `ap-northeast-2` | [arn:aws:lambda:ap-northeast-2:094274105915:layer:AWSLambdaPowertoolsTypeScriptV2:22](#){: .copyMe}:clipboard: | + | `ap-northeast-3` | [arn:aws:lambda:ap-northeast-3:094274105915:layer:AWSLambdaPowertoolsTypeScriptV2:22](#){: .copyMe}:clipboard: | + | `ap-southeast-1` | [arn:aws:lambda:ap-southeast-1:094274105915:layer:AWSLambdaPowertoolsTypeScriptV2:22](#){: .copyMe}:clipboard: | + | `ap-southeast-2` | [arn:aws:lambda:ap-southeast-2:094274105915:layer:AWSLambdaPowertoolsTypeScriptV2:22](#){: .copyMe}:clipboard: | + | `ap-southeast-3` | [arn:aws:lambda:ap-southeast-3:094274105915:layer:AWSLambdaPowertoolsTypeScriptV2:22](#){: .copyMe}:clipboard: | + | `ap-southeast-4` | [arn:aws:lambda:ap-southeast-4:094274105915:layer:AWSLambdaPowertoolsTypeScriptV2:22](#){: .copyMe}:clipboard: | + | `ap-southeast-5` | [arn:aws:lambda:ap-southeast-5:094274105915:layer:AWSLambdaPowertoolsTypeScriptV2:22](#){: .copyMe}:clipboard: | + | `ap-southeast-7` | [arn:aws:lambda:ap-southeast-7:094274105915:layer:AWSLambdaPowertoolsTypeScriptV2:22](#){: .copyMe}:clipboard: | + | `eu-central-1` | [arn:aws:lambda:eu-central-1:094274105915:layer:AWSLambdaPowertoolsTypeScriptV2:22](#){: .copyMe}:clipboard: | + | `eu-central-2` | [arn:aws:lambda:eu-central-1:094274105915:layer:AWSLambdaPowertoolsTypeScriptV2:22](#){: .copyMe}:clipboard: | + | `eu-west-1` | [arn:aws:lambda:eu-west-1:094274105915:layer:AWSLambdaPowertoolsTypeScriptV2:22](#){: .copyMe}:clipboard: | + | `eu-west-2` | [arn:aws:lambda:eu-west-2:094274105915:layer:AWSLambdaPowertoolsTypeScriptV2:22](#){: .copyMe}:clipboard: | + | `eu-west-3` | [arn:aws:lambda:eu-west-3:094274105915:layer:AWSLambdaPowertoolsTypeScriptV2:22](#){: .copyMe}:clipboard: | + | `eu-north-1` | [arn:aws:lambda:eu-north-1:094274105915:layer:AWSLambdaPowertoolsTypeScriptV2:22](#){: .copyMe}:clipboard: | + | `eu-south-1` | [arn:aws:lambda:eu-south-1:094274105915:layer:AWSLambdaPowertoolsTypeScriptV2:22](#){: .copyMe}:clipboard: | + | `eu-south-2` | [arn:aws:lambda:eu-south-2:094274105915:layer:AWSLambdaPowertoolsTypeScriptV2:22](#){: .copyMe}:clipboard: | + | `ca-central-1` | [arn:aws:lambda:ca-central-1:094274105915:layer:AWSLambdaPowertoolsTypeScriptV2:22](#){: .copyMe}:clipboard: | + | `ca-west-1` | [arn:aws:lambda:ca-west-1:094274105915:layer:AWSLambdaPowertoolsTypeScriptV2:22](#){: .copyMe}:clipboard: | + | `sa-east-1` | [arn:aws:lambda:sa-east-1:094274105915:layer:AWSLambdaPowertoolsTypeScriptV2:22](#){: .copyMe}:clipboard: | + | `af-south-1` | [arn:aws:lambda:af-south-1:094274105915:layer:AWSLambdaPowertoolsTypeScriptV2:22](#){: .copyMe}:clipboard: | + | `me-south-1` | [arn:aws:lambda:me-south-1:094274105915:layer:AWSLambdaPowertoolsTypeScriptV2:22](#){: .copyMe}:clipboard: | + | `me-central-1` | [arn:aws:lambda:me-central-1:094274105915:layer:AWSLambdaPowertoolsTypeScriptV2:22](#){: .copyMe}:clipboard: | + | `il-central-1` | [arn:aws:lambda:il-central-1:094274105915:layer:AWSLambdaPowertoolsTypeScriptV2:22](#){: .copyMe}:clipboard: | + | `mx-central-1` | [arn:aws:lambda:mx-central-1:094274105915:layer:AWSLambdaPowertoolsTypeScriptV2:22](#){: .copyMe}:clipboard: | **Want to inspect the contents of the Layer?** @@ -313,7 +313,7 @@ The pre-signed URL to download this Lambda Layer will be within `Location` key i Change `{aws::region}` to your AWS region, e.g. `eu-west-1`, and run the following command: ```bash title="AWS CLI command to download Lambda Layer content" -aws lambda get-layer-version-by-arn --arn arn:aws:lambda:{aws::region}:094274105915:layer:AWSLambdaPowertoolsTypeScriptV2:21 --region {aws::region} +aws lambda get-layer-version-by-arn --arn arn:aws:lambda:{aws::region}:094274105915:layer:AWSLambdaPowertoolsTypeScriptV2:22 --region {aws::region} ``` ## Instrumentation From 661f5ff7f3f3805e24f515892e98430dccebf979 Mon Sep 17 00:00:00 2001 From: Andrea Amorosi Date: Tue, 11 Mar 2025 12:27:14 +0100 Subject: [PATCH 02/56] fix(idempotency): include sk in error msgs when using composite key (#3709) --- .../idempotency/src/IdempotencyHandler.ts | 6 +- .../persistence/DynamoDBPersistenceLayer.ts | 6 +- .../src/persistence/IdempotencyRecord.ts | 6 + .../src/types/IdempotencyRecord.ts | 24 ++++ .../tests/unit/IdempotencyHandler.test.ts | 59 ++++++---- .../DynamoDbPersistenceLayer.test.ts | 104 ++++++++++++------ 6 files changed, 149 insertions(+), 56 deletions(-) diff --git a/packages/idempotency/src/IdempotencyHandler.ts b/packages/idempotency/src/IdempotencyHandler.ts index 90b7372317..dcf27d3264 100644 --- a/packages/idempotency/src/IdempotencyHandler.ts +++ b/packages/idempotency/src/IdempotencyHandler.ts @@ -120,7 +120,11 @@ export class IdempotencyHandler { ); } throw new IdempotencyAlreadyInProgressError( - `There is already an execution in progress with idempotency key: ${idempotencyRecord.idempotencyKey}` + `There is already an execution in progress with idempotency key: ${idempotencyRecord.idempotencyKey}${ + idempotencyRecord.sortKey + ? ` and sort key: ${idempotencyRecord.sortKey}` + : '' + }` ); } diff --git a/packages/idempotency/src/persistence/DynamoDBPersistenceLayer.ts b/packages/idempotency/src/persistence/DynamoDBPersistenceLayer.ts index 3c84f1850f..e7e50fb744 100644 --- a/packages/idempotency/src/persistence/DynamoDBPersistenceLayer.ts +++ b/packages/idempotency/src/persistence/DynamoDBPersistenceLayer.ts @@ -122,6 +122,7 @@ class DynamoDBPersistenceLayer extends BasePersistenceLayer { return new IdempotencyRecord({ idempotencyKey: item[this.keyAttr], + sortKey: this.sortKeyAttr && item[this.sortKeyAttr], status: item[this.statusAttr], expiryTimestamp: item[this.expiryAttr], inProgressExpiryTimestamp: item[this.inProgressExpiryAttr], @@ -207,6 +208,7 @@ class DynamoDBPersistenceLayer extends BasePersistenceLayer { item && new IdempotencyRecord({ idempotencyKey: item[this.keyAttr], + sortKey: this.sortKeyAttr && item[this.sortKeyAttr], status: item[this.statusAttr], expiryTimestamp: item[this.expiryAttr], inProgressExpiryTimestamp: item[this.inProgressExpiryAttr], @@ -214,7 +216,9 @@ class DynamoDBPersistenceLayer extends BasePersistenceLayer { payloadHash: item[this.validationKeyAttr], }); throw new IdempotencyItemAlreadyExistsError( - `Failed to put record for already existing idempotency key: ${record.idempotencyKey}`, + `Failed to put record for already existing idempotency key: ${record.idempotencyKey}${ + this.sortKeyAttr ? ` and sort key: ${record.sortKey}` : '' + }`, idempotencyRecord ); } diff --git a/packages/idempotency/src/persistence/IdempotencyRecord.ts b/packages/idempotency/src/persistence/IdempotencyRecord.ts index 2b99cadc4f..b0aa037a63 100644 --- a/packages/idempotency/src/persistence/IdempotencyRecord.ts +++ b/packages/idempotency/src/persistence/IdempotencyRecord.ts @@ -5,6 +5,7 @@ import type { IdempotencyRecordOptions, IdempotencyRecordStatusValue, } from '../types/IdempotencyRecord.js'; +import type { DynamoDBPersistenceLayer } from './DynamoDBPersistenceLayer.js'; /** * Class representing an idempotency record. @@ -19,6 +20,10 @@ class IdempotencyRecord { * The idempotency key of the record that is used to identify the record. */ public idempotencyKey: string; + /** + * An optional sort key that can be used with the {@link DynamoDBPersistenceLayer | `DynamoDBPersistenceLayer`}. + */ + public sortKey?: string; /** * The expiry timestamp of the in progress record in milliseconds UTC. */ @@ -46,6 +51,7 @@ class IdempotencyRecord { this.responseData = config.responseData; this.payloadHash = config.payloadHash; this.status = config.status; + this.sortKey = config.sortKey; } /** diff --git a/packages/idempotency/src/types/IdempotencyRecord.ts b/packages/idempotency/src/types/IdempotencyRecord.ts index cfd01a44bf..9c941b9787 100644 --- a/packages/idempotency/src/types/IdempotencyRecord.ts +++ b/packages/idempotency/src/types/IdempotencyRecord.ts @@ -11,11 +11,35 @@ type IdempotencyRecordStatusValue = * Options for creating a new IdempotencyRecord */ type IdempotencyRecordOptions = { + /** + * The idempotency key of the record that is used to identify the record. + */ idempotencyKey: string; + /** + * An optional sort key that can be used with the {@link DynamoDBPersistenceLayer | `DynamoDBPersistenceLayer`}. + */ + sortKey?: string; + /** + * The idempotency record status can be COMPLETED, IN_PROGRESS or EXPIRED. + * We check the status during idempotency processing to make sure we don't process an expired record and handle concurrent requests. + * {@link constants.IdempotencyRecordStatusValue | IdempotencyRecordStatusValue} + */ status: IdempotencyRecordStatusValue; + /** + * The expiry timestamp of the record in milliseconds UTC. + */ expiryTimestamp?: number; + /** + * The expiry timestamp of the in progress record in milliseconds UTC. + */ inProgressExpiryTimestamp?: number; + /** + * The response data of the request, this will be returned if the payload hash matches. + */ responseData?: JSONValue; + /** + * The hash of the payload of the request, used for comparing requests. + */ payloadHash?: string; }; diff --git a/packages/idempotency/tests/unit/IdempotencyHandler.test.ts b/packages/idempotency/tests/unit/IdempotencyHandler.test.ts index c64e3c10f7..22f574ac53 100644 --- a/packages/idempotency/tests/unit/IdempotencyHandler.test.ts +++ b/packages/idempotency/tests/unit/IdempotencyHandler.test.ts @@ -49,25 +49,46 @@ describe('Class IdempotencyHandler', () => { }); describe('Method: determineResultFromIdempotencyRecord', () => { - it('throws when the record is in progress and within expiry window', async () => { - // Prepare - const stubRecord = new IdempotencyRecord({ - idempotencyKey: 'idempotencyKey', - expiryTimestamp: Date.now() + 1000, // should be in the future - inProgressExpiryTimestamp: 0, // less than current time in milliseconds - responseData: { responseData: 'responseData' }, - payloadHash: 'payloadHash', - status: IdempotencyRecordStatus.INPROGRESS, - }); - - // Act & Assess - expect(stubRecord.isExpired()).toBe(false); - expect(stubRecord.getStatus()).toBe(IdempotencyRecordStatus.INPROGRESS); - expect(() => - idempotentHandler.determineResultFromIdempotencyRecord(stubRecord) - ).toThrow(IdempotencyAlreadyInProgressError); - expect(mockResponseHook).not.toHaveBeenCalled(); - }); + it.each([ + { + keys: { + idempotencyKey: 'idempotencyKey', + sortKey: 'sk', + }, + expectedErrorMsg: + 'There is already an execution in progress with idempotency key: idempotencyKey and sort key: sk', + case: 'pk & sk', + }, + { + keys: { + idempotencyKey: 'idempotencyKey', + }, + expectedErrorMsg: + 'There is already an execution in progress with idempotency key: idempotencyKey', + case: 'pk only', + }, + ])( + 'throws when the record is in progress and within expiry window ($case)', + async ({ keys, expectedErrorMsg }) => { + // Prepare + const stubRecord = new IdempotencyRecord({ + ...keys, + expiryTimestamp: Date.now() + 1000, // should be in the future + inProgressExpiryTimestamp: 0, // less than current time in milliseconds + responseData: { responseData: 'responseData' }, + payloadHash: 'payloadHash', + status: IdempotencyRecordStatus.INPROGRESS, + }); + + // Act & Assess + expect(stubRecord.isExpired()).toBe(false); + expect(stubRecord.getStatus()).toBe(IdempotencyRecordStatus.INPROGRESS); + expect(() => + idempotentHandler.determineResultFromIdempotencyRecord(stubRecord) + ).toThrow(new IdempotencyAlreadyInProgressError(expectedErrorMsg)); + expect(mockResponseHook).not.toHaveBeenCalled(); + } + ); it('throws when the record is in progress and outside expiry window', async () => { // Prepare diff --git a/packages/idempotency/tests/unit/persistence/DynamoDbPersistenceLayer.test.ts b/packages/idempotency/tests/unit/persistence/DynamoDbPersistenceLayer.test.ts index 51b893caab..bb72789986 100644 --- a/packages/idempotency/tests/unit/persistence/DynamoDbPersistenceLayer.test.ts +++ b/packages/idempotency/tests/unit/persistence/DynamoDbPersistenceLayer.test.ts @@ -346,41 +346,75 @@ describe('Class: DynamoDBPersistenceLayer', () => { persistenceLayerSpy.mockRestore(); }); - it('throws when called with a record that fails any condition', async () => { - // Prepare - const record = new IdempotencyRecord({ - idempotencyKey: dummyKey, - status: IdempotencyRecordStatus.EXPIRED, - expiryTimestamp: 0, - }); - const expiration = Date.now(); - client.on(PutItemCommand).rejects( - new ConditionalCheckFailedException({ - $metadata: { - httpStatusCode: 400, - requestId: 'someRequestId', - }, - message: 'Conditional check failed', - Item: { - id: { S: 'test-key' }, - status: { S: 'INPROGRESS' }, - expiration: { N: expiration.toString() }, - }, - }) - ); - - // Act & Assess - await expect(persistenceLayer._putRecord(record)).rejects.toThrowError( - new IdempotencyItemAlreadyExistsError( - `Failed to put record for already existing idempotency key: ${record.idempotencyKey}`, - new IdempotencyRecord({ - idempotencyKey: 'test-key', - status: IdempotencyRecordStatus.INPROGRESS, - expiryTimestamp: expiration, + it.each([ + { + keys: { + id: 'idempotency#my-lambda-function', + sortKey: dummyKey, + }, + case: 'composite key', + }, + { + keys: { + id: dummyKey, + }, + case: 'single key', + }, + ])( + 'throws when called with a record that fails any condition ($case)', + async ({ keys }) => { + // Prepare + const { id, sortKey } = keys; + + const record = new IdempotencyRecord({ + idempotencyKey: id, + sortKey, + status: IdempotencyRecordStatus.EXPIRED, + expiryTimestamp: 0, + }); + const expiration = Date.now(); + client.on(PutItemCommand).rejects( + new ConditionalCheckFailedException({ + $metadata: { + httpStatusCode: 400, + requestId: 'someRequestId', + }, + message: 'Conditional check failed', + Item: { + id: { S: 'test-key' }, + ...(sortKey ? { sortKey: { S: sortKey } } : {}), + status: { S: 'INPROGRESS' }, + expiration: { N: expiration.toString() }, + }, }) - ) - ); - }); + ); + const testPersistenceLayer = sortKey + ? new DynamoDBPersistenceLayerTestClass({ + tableName: dummyTableName, + sortKeyAttr: 'sortKey', + }) + : persistenceLayer; + + // Act & Assess + await expect( + testPersistenceLayer._putRecord(record) + ).rejects.toThrowError( + new IdempotencyItemAlreadyExistsError( + `Failed to put record for already existing idempotency key: ${ + sortKey + ? `${record.idempotencyKey} and sort key: ${sortKey}` + : record.idempotencyKey + }`, + new IdempotencyRecord({ + idempotencyKey: 'test-key', + sortKey, + status: IdempotencyRecordStatus.INPROGRESS, + expiryTimestamp: expiration, + }) + ) + ); + } + ); it('throws when encountering an unknown error', async () => { // Prepare @@ -445,7 +479,7 @@ describe('Class: DynamoDBPersistenceLayer', () => { ); }); - it('it builds the request correctly when using composite keys', async () => { + it('builds the request correctly when using composite keys', async () => { // Prepare const persistenceLayer = new DynamoDBPersistenceLayerTestClass({ tableName: dummyTableName, From 4cb373ee4b9fd79de38f49ccd5b7d2104391a29d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 11 Mar 2025 15:57:18 +0100 Subject: [PATCH 03/56] chore(deps-dev): bump the vitest group across 1 directory with 2 updates (#3704) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 268 +++++++++++++++++++++++----------------------- package.json | 2 +- 2 files changed, 135 insertions(+), 135 deletions(-) diff --git a/package-lock.json b/package-lock.json index a8a5b2abfa..59bb3dbc7c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -29,7 +29,7 @@ "@biomejs/biome": "^1.9.4", "@types/aws-lambda": "^8.10.147", "@types/node": "^22.13.9", - "@vitest/coverage-v8": "^3.0.7", + "@vitest/coverage-v8": "^3.0.8", "husky": "^9.1.7", "lerna": "8.1.2", "lint-staged": "^15.4.3", @@ -8544,9 +8544,9 @@ } }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.34.8", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.34.8.tgz", - "integrity": "sha512-q217OSE8DTp8AFHuNHXo0Y86e1wtlfVrXiAlwkIvGRQv9zbc6mE3sjIVfwI8sYUyNxwOg0j/Vm1RKM04JcWLJw==", + "version": "4.35.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.35.0.tgz", + "integrity": "sha512-uYQ2WfPaqz5QtVgMxfN6NpLD+no0MYHDBywl7itPYd3K5TjjSghNKmX8ic9S8NU8w81NVhJv/XojcHptRly7qQ==", "cpu": [ "arm" ], @@ -8558,9 +8558,9 @@ ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.34.8", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.34.8.tgz", - "integrity": "sha512-Gigjz7mNWaOL9wCggvoK3jEIUUbGul656opstjaUSGC3eT0BM7PofdAJaBfPFWWkXNVAXbaQtC99OCg4sJv70Q==", + "version": "4.35.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.35.0.tgz", + "integrity": "sha512-FtKddj9XZudurLhdJnBl9fl6BwCJ3ky8riCXjEw3/UIbjmIY58ppWwPEvU3fNu+W7FUsAsB1CdH+7EQE6CXAPA==", "cpu": [ "arm64" ], @@ -8572,9 +8572,9 @@ ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.34.8", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.34.8.tgz", - "integrity": "sha512-02rVdZ5tgdUNRxIUrFdcMBZQoaPMrxtwSb+/hOfBdqkatYHR3lZ2A2EGyHq2sGOd0Owk80oV3snlDASC24He3Q==", + "version": "4.35.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.35.0.tgz", + "integrity": "sha512-Uk+GjOJR6CY844/q6r5DR/6lkPFOw0hjfOIzVx22THJXMxktXG6CbejseJFznU8vHcEBLpiXKY3/6xc+cBm65Q==", "cpu": [ "arm64" ], @@ -8586,9 +8586,9 @@ ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.34.8", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.34.8.tgz", - "integrity": "sha512-qIP/elwR/tq/dYRx3lgwK31jkZvMiD6qUtOycLhTzCvrjbZ3LjQnEM9rNhSGpbLXVJYQ3rq39A6Re0h9tU2ynw==", + "version": "4.35.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.35.0.tgz", + "integrity": "sha512-3IrHjfAS6Vkp+5bISNQnPogRAW5GAV1n+bNCrDwXmfMHbPl5EhTmWtfmwlJxFRUCBZ+tZ/OxDyU08aF6NI/N5Q==", "cpu": [ "x64" ], @@ -8600,9 +8600,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.34.8", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.34.8.tgz", - "integrity": "sha512-IQNVXL9iY6NniYbTaOKdrlVP3XIqazBgJOVkddzJlqnCpRi/yAeSOa8PLcECFSQochzqApIOE1GHNu3pCz+BDA==", + "version": "4.35.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.35.0.tgz", + "integrity": "sha512-sxjoD/6F9cDLSELuLNnY0fOrM9WA0KrM0vWm57XhrIMf5FGiN8D0l7fn+bpUeBSU7dCgPV2oX4zHAsAXyHFGcQ==", "cpu": [ "arm64" ], @@ -8614,9 +8614,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.34.8", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.34.8.tgz", - "integrity": "sha512-TYXcHghgnCqYFiE3FT5QwXtOZqDj5GmaFNTNt3jNC+vh22dc/ukG2cG+pi75QO4kACohZzidsq7yKTKwq/Jq7Q==", + "version": "4.35.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.35.0.tgz", + "integrity": "sha512-2mpHCeRuD1u/2kruUiHSsnjWtHjqVbzhBkNVQ1aVD63CcexKVcQGwJ2g5VphOd84GvxfSvnnlEyBtQCE5hxVVw==", "cpu": [ "x64" ], @@ -8628,9 +8628,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.34.8", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.34.8.tgz", - "integrity": "sha512-A4iphFGNkWRd+5m3VIGuqHnG3MVnqKe7Al57u9mwgbyZ2/xF9Jio72MaY7xxh+Y87VAHmGQr73qoKL9HPbXj1g==", + "version": "4.35.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.35.0.tgz", + "integrity": "sha512-mrA0v3QMy6ZSvEuLs0dMxcO2LnaCONs1Z73GUDBHWbY8tFFocM6yl7YyMu7rz4zS81NDSqhrUuolyZXGi8TEqg==", "cpu": [ "arm" ], @@ -8642,9 +8642,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.34.8", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.34.8.tgz", - "integrity": "sha512-S0lqKLfTm5u+QTxlFiAnb2J/2dgQqRy/XvziPtDd1rKZFXHTyYLoVL58M/XFwDI01AQCDIevGLbQrMAtdyanpA==", + "version": "4.35.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.35.0.tgz", + "integrity": "sha512-DnYhhzcvTAKNexIql8pFajr0PiDGrIsBYPRvCKlA5ixSS3uwo/CWNZxB09jhIapEIg945KOzcYEAGGSmTSpk7A==", "cpu": [ "arm" ], @@ -8656,9 +8656,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.34.8", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.34.8.tgz", - "integrity": "sha512-jpz9YOuPiSkL4G4pqKrus0pn9aYwpImGkosRKwNi+sJSkz+WU3anZe6hi73StLOQdfXYXC7hUfsQlTnjMd3s1A==", + "version": "4.35.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.35.0.tgz", + "integrity": "sha512-uagpnH2M2g2b5iLsCTZ35CL1FgyuzzJQ8L9VtlJ+FckBXroTwNOaD0z0/UF+k5K3aNQjbm8LIVpxykUOQt1m/A==", "cpu": [ "arm64" ], @@ -8670,9 +8670,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.34.8", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.34.8.tgz", - "integrity": "sha512-KdSfaROOUJXgTVxJNAZ3KwkRc5nggDk+06P6lgi1HLv1hskgvxHUKZ4xtwHkVYJ1Rep4GNo+uEfycCRRxht7+Q==", + "version": "4.35.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.35.0.tgz", + "integrity": "sha512-XQxVOCd6VJeHQA/7YcqyV0/88N6ysSVzRjJ9I9UA/xXpEsjvAgDTgH3wQYz5bmr7SPtVK2TsP2fQ2N9L4ukoUg==", "cpu": [ "arm64" ], @@ -8684,9 +8684,9 @@ ] }, "node_modules/@rollup/rollup-linux-loongarch64-gnu": { - "version": "4.34.8", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.34.8.tgz", - "integrity": "sha512-NyF4gcxwkMFRjgXBM6g2lkT58OWztZvw5KkV2K0qqSnUEqCVcqdh2jN4gQrTn/YUpAcNKyFHfoOZEer9nwo6uQ==", + "version": "4.35.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.35.0.tgz", + "integrity": "sha512-5pMT5PzfgwcXEwOaSrqVsz/LvjDZt+vQ8RT/70yhPU06PTuq8WaHhfT1LW+cdD7mW6i/J5/XIkX/1tCAkh1W6g==", "cpu": [ "loong64" ], @@ -8698,9 +8698,9 @@ ] }, "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { - "version": "4.34.8", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.34.8.tgz", - "integrity": "sha512-LMJc999GkhGvktHU85zNTDImZVUCJ1z/MbAJTnviiWmmjyckP5aQsHtcujMjpNdMZPT2rQEDBlJfubhs3jsMfw==", + "version": "4.35.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.35.0.tgz", + "integrity": "sha512-c+zkcvbhbXF98f4CtEIP1EBA/lCic5xB0lToneZYvMeKu5Kamq3O8gqrxiYYLzlZH6E3Aq+TSW86E4ay8iD8EA==", "cpu": [ "ppc64" ], @@ -8712,9 +8712,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.34.8", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.34.8.tgz", - "integrity": "sha512-xAQCAHPj8nJq1PI3z8CIZzXuXCstquz7cIOL73HHdXiRcKk8Ywwqtx2wrIy23EcTn4aZ2fLJNBB8d0tQENPCmw==", + "version": "4.35.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.35.0.tgz", + "integrity": "sha512-s91fuAHdOwH/Tad2tzTtPX7UZyytHIRR6V4+2IGlV0Cej5rkG0R61SX4l4y9sh0JBibMiploZx3oHKPnQBKe4g==", "cpu": [ "riscv64" ], @@ -8726,9 +8726,9 @@ ] }, "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.34.8", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.34.8.tgz", - "integrity": "sha512-DdePVk1NDEuc3fOe3dPPTb+rjMtuFw89gw6gVWxQFAuEqqSdDKnrwzZHrUYdac7A7dXl9Q2Vflxpme15gUWQFA==", + "version": "4.35.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.35.0.tgz", + "integrity": "sha512-hQRkPQPLYJZYGP+Hj4fR9dDBMIM7zrzJDWFEMPdTnTy95Ljnv0/4w/ixFw3pTBMEuuEuoqtBINYND4M7ujcuQw==", "cpu": [ "s390x" ], @@ -8740,9 +8740,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.34.8", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.34.8.tgz", - "integrity": "sha512-8y7ED8gjxITUltTUEJLQdgpbPh1sUQ0kMTmufRF/Ns5tI9TNMNlhWtmPKKHCU0SilX+3MJkZ0zERYYGIVBYHIA==", + "version": "4.35.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.35.0.tgz", + "integrity": "sha512-Pim1T8rXOri+0HmV4CdKSGrqcBWX0d1HoPnQ0uw0bdp1aP5SdQVNBy8LjYncvnLgu3fnnCt17xjWGd4cqh8/hA==", "cpu": [ "x64" ], @@ -8754,9 +8754,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.34.8", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.34.8.tgz", - "integrity": "sha512-SCXcP0ZpGFIe7Ge+McxY5zKxiEI5ra+GT3QRxL0pMMtxPfpyLAKleZODi1zdRHkz5/BhueUrYtYVgubqe9JBNQ==", + "version": "4.35.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.35.0.tgz", + "integrity": "sha512-QysqXzYiDvQWfUiTm8XmJNO2zm9yC9P/2Gkrwg2dH9cxotQzunBHYr6jk4SujCTqnfGxduOmQcI7c2ryuW8XVg==", "cpu": [ "x64" ], @@ -8768,9 +8768,9 @@ ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.34.8", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.34.8.tgz", - "integrity": "sha512-YHYsgzZgFJzTRbth4h7Or0m5O74Yda+hLin0irAIobkLQFRQd1qWmnoVfwmKm9TXIZVAD0nZ+GEb2ICicLyCnQ==", + "version": "4.35.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.35.0.tgz", + "integrity": "sha512-OUOlGqPkVJCdJETKOCEf1mw848ZyJ5w50/rZ/3IBQVdLfR5jk/6Sr5m3iO2tdPgwo0x7VcncYuOvMhBWZq8ayg==", "cpu": [ "arm64" ], @@ -8782,9 +8782,9 @@ ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.34.8", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.34.8.tgz", - "integrity": "sha512-r3NRQrXkHr4uWy5TOjTpTYojR9XmF0j/RYgKCef+Ag46FWUTltm5ziticv8LdNsDMehjJ543x/+TJAek/xBA2w==", + "version": "4.35.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.35.0.tgz", + "integrity": "sha512-2/lsgejMrtwQe44glq7AFFHLfJBPafpsTa6JvP2NGef/ifOa4KBoglVf7AKN7EV9o32evBPRqfg96fEHzWo5kw==", "cpu": [ "ia32" ], @@ -8796,9 +8796,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.34.8", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.34.8.tgz", - "integrity": "sha512-U0FaE5O1BCpZSeE6gBl3c5ObhePQSfk9vDRToMmTkbhCOgW4jqvtS5LGyQ76L1fH8sM0keRp4uDTsbjiUyjk0g==", + "version": "4.35.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.35.0.tgz", + "integrity": "sha512-PIQeY5XDkrOysbQblSW7v3l1MDZzkTEzAfTPkj5VAu3FW8fS4ynyLg2sINp0fp3SjZ8xkRYpLqoKcYqAkhU1dw==", "cpu": [ "x64" ], @@ -10091,9 +10091,9 @@ "integrity": "sha512-jg+97EGIcY9AGHJJRaaPVgetKDsrTgbRjQ5Msgjh/DQKEFl0DtyRr/VCOyD1T2R1MNeWPK/u7JoGhlDZnKBAfA==" }, "node_modules/@vitest/coverage-v8": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-3.0.7.tgz", - "integrity": "sha512-Av8WgBJLTrfLOer0uy3CxjlVuWK4CzcLBndW1Nm2vI+3hZ2ozHututkfc7Blu1u6waeQ7J8gzPK/AsBRnWA5mQ==", + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-3.0.8.tgz", + "integrity": "sha512-y7SAKsQirsEJ2F8bulBck4DoluhI2EEgTimHd6EEUgJBGKy9tC25cpywh1MH4FvDGoG2Unt7+asVd1kj4qOSAw==", "dev": true, "license": "MIT", "dependencies": { @@ -10114,8 +10114,8 @@ "url": "https://opencollective.com/vitest" }, "peerDependencies": { - "@vitest/browser": "3.0.7", - "vitest": "3.0.7" + "@vitest/browser": "3.0.8", + "vitest": "3.0.8" }, "peerDependenciesMeta": { "@vitest/browser": { @@ -10167,14 +10167,14 @@ } }, "node_modules/@vitest/expect": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-3.0.7.tgz", - "integrity": "sha512-QP25f+YJhzPfHrHfYHtvRn+uvkCFCqFtW9CktfBxmB+25QqWsx7VB2As6f4GmwllHLDhXNHvqedwhvMmSnNmjw==", + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-3.0.8.tgz", + "integrity": "sha512-Xu6TTIavTvSSS6LZaA3EebWFr6tsoXPetOWNMOlc7LO88QVVBwq2oQWBoDiLCN6YTvNYsGSjqOO8CAdjom5DCQ==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/spy": "3.0.7", - "@vitest/utils": "3.0.7", + "@vitest/spy": "3.0.8", + "@vitest/utils": "3.0.8", "chai": "^5.2.0", "tinyrainbow": "^2.0.0" }, @@ -10183,13 +10183,13 @@ } }, "node_modules/@vitest/mocker": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-3.0.7.tgz", - "integrity": "sha512-qui+3BLz9Eonx4EAuR/i+QlCX6AUZ35taDQgwGkK/Tw6/WgwodSrjN1X2xf69IA/643ZX5zNKIn2svvtZDrs4w==", + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-3.0.8.tgz", + "integrity": "sha512-n3LjS7fcW1BCoF+zWZxG7/5XvuYH+lsFg+BDwwAz0arIwHQJFUEsKBQ0BLU49fCxuM/2HSeBPHQD8WjgrxMfow==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/spy": "3.0.7", + "@vitest/spy": "3.0.8", "estree-walker": "^3.0.3", "magic-string": "^0.30.17" }, @@ -10210,9 +10210,9 @@ } }, "node_modules/@vitest/pretty-format": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-3.0.7.tgz", - "integrity": "sha512-CiRY0BViD/V8uwuEzz9Yapyao+M9M008/9oMOSQydwbwb+CMokEq3XVaF3XK/VWaOK0Jm9z7ENhybg70Gtxsmg==", + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-3.0.8.tgz", + "integrity": "sha512-BNqwbEyitFhzYMYHUVbIvepOyeQOSFA/NeJMIP9enMntkkxLgOcgABH6fjyXG85ipTgvero6noreavGIqfJcIg==", "dev": true, "license": "MIT", "dependencies": { @@ -10223,13 +10223,13 @@ } }, "node_modules/@vitest/runner": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-3.0.7.tgz", - "integrity": "sha512-WeEl38Z0S2ZcuRTeyYqaZtm4e26tq6ZFqh5y8YD9YxfWuu0OFiGFUbnxNynwLjNRHPsXyee2M9tV7YxOTPZl2g==", + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-3.0.8.tgz", + "integrity": "sha512-c7UUw6gEcOzI8fih+uaAXS5DwjlBaCJUo7KJ4VvJcjL95+DSR1kova2hFuRt3w41KZEFcOEiq098KkyrjXeM5w==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/utils": "3.0.7", + "@vitest/utils": "3.0.8", "pathe": "^2.0.3" }, "funding": { @@ -10237,13 +10237,13 @@ } }, "node_modules/@vitest/snapshot": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-3.0.7.tgz", - "integrity": "sha512-eqTUryJWQN0Rtf5yqCGTQWsCFOQe4eNz5Twsu21xYEcnFJtMU5XvmG0vgebhdLlrHQTSq5p8vWHJIeJQV8ovsA==", + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-3.0.8.tgz", + "integrity": "sha512-x8IlMGSEMugakInj44nUrLSILh/zy1f2/BgH0UeHpNyOocG18M9CWVIFBaXPt8TrqVZWmcPjwfG/ht5tnpba8A==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/pretty-format": "3.0.7", + "@vitest/pretty-format": "3.0.8", "magic-string": "^0.30.17", "pathe": "^2.0.3" }, @@ -10252,9 +10252,9 @@ } }, "node_modules/@vitest/spy": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-3.0.7.tgz", - "integrity": "sha512-4T4WcsibB0B6hrKdAZTM37ekuyFZt2cGbEGd2+L0P8ov15J1/HUsUaqkXEQPNAWr4BtPPe1gI+FYfMHhEKfR8w==", + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-3.0.8.tgz", + "integrity": "sha512-MR+PzJa+22vFKYb934CejhR4BeRpMSoxkvNoDit68GQxRLSf11aT6CTj3XaqUU9rxgWJFnqicN/wxw6yBRkI1Q==", "dev": true, "license": "MIT", "dependencies": { @@ -10265,13 +10265,13 @@ } }, "node_modules/@vitest/utils": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-3.0.7.tgz", - "integrity": "sha512-xePVpCRfooFX3rANQjwoditoXgWb1MaFbzmGuPP59MK6i13mrnDw/yEIyJudLeW6/38mCNcwCiJIGmpDPibAIg==", + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-3.0.8.tgz", + "integrity": "sha512-nkBC3aEhfX2PdtQI/QwAWp8qZWwzASsU4Npbcd5RdMPBSSLCpkZp52P3xku3s3uA0HIEhGvEcF8rNkBsz9dQ4Q==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/pretty-format": "3.0.7", + "@vitest/pretty-format": "3.0.8", "loupe": "^3.1.3", "tinyrainbow": "^2.0.0" }, @@ -17052,9 +17052,9 @@ "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==" }, "node_modules/nanoid": { - "version": "3.3.8", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.8.tgz", - "integrity": "sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==", + "version": "3.3.9", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.9.tgz", + "integrity": "sha512-SppoicMGpZvbF1l3z4x7No3OlIjP7QJvC9XR7AhZr1kL133KHnKPztkKDc+Ir4aJ/1VhTySrtKhrsycmrMQfvg==", "dev": true, "funding": [ { @@ -19349,9 +19349,9 @@ } }, "node_modules/rollup": { - "version": "4.34.8", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.34.8.tgz", - "integrity": "sha512-489gTVMzAYdiZHFVA/ig/iYFllCcWFHMvUHI1rpFmkoUtRlQxqh6/yiNqnYibjMZ2b/+FUQwldG+aLsEt6bglQ==", + "version": "4.35.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.35.0.tgz", + "integrity": "sha512-kg6oI4g+vc41vePJyO6dHt/yl0Rz3Thv0kJeVQ3D1kS3E5XSuKbPc29G4IpT/Kv1KQwgHVcN+HtyS+HYLNSvQg==", "dev": true, "license": "MIT", "dependencies": { @@ -19365,25 +19365,25 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.34.8", - "@rollup/rollup-android-arm64": "4.34.8", - "@rollup/rollup-darwin-arm64": "4.34.8", - "@rollup/rollup-darwin-x64": "4.34.8", - "@rollup/rollup-freebsd-arm64": "4.34.8", - "@rollup/rollup-freebsd-x64": "4.34.8", - "@rollup/rollup-linux-arm-gnueabihf": "4.34.8", - "@rollup/rollup-linux-arm-musleabihf": "4.34.8", - "@rollup/rollup-linux-arm64-gnu": "4.34.8", - "@rollup/rollup-linux-arm64-musl": "4.34.8", - "@rollup/rollup-linux-loongarch64-gnu": "4.34.8", - "@rollup/rollup-linux-powerpc64le-gnu": "4.34.8", - "@rollup/rollup-linux-riscv64-gnu": "4.34.8", - "@rollup/rollup-linux-s390x-gnu": "4.34.8", - "@rollup/rollup-linux-x64-gnu": "4.34.8", - "@rollup/rollup-linux-x64-musl": "4.34.8", - "@rollup/rollup-win32-arm64-msvc": "4.34.8", - "@rollup/rollup-win32-ia32-msvc": "4.34.8", - "@rollup/rollup-win32-x64-msvc": "4.34.8", + "@rollup/rollup-android-arm-eabi": "4.35.0", + "@rollup/rollup-android-arm64": "4.35.0", + "@rollup/rollup-darwin-arm64": "4.35.0", + "@rollup/rollup-darwin-x64": "4.35.0", + "@rollup/rollup-freebsd-arm64": "4.35.0", + "@rollup/rollup-freebsd-x64": "4.35.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.35.0", + "@rollup/rollup-linux-arm-musleabihf": "4.35.0", + "@rollup/rollup-linux-arm64-gnu": "4.35.0", + "@rollup/rollup-linux-arm64-musl": "4.35.0", + "@rollup/rollup-linux-loongarch64-gnu": "4.35.0", + "@rollup/rollup-linux-powerpc64le-gnu": "4.35.0", + "@rollup/rollup-linux-riscv64-gnu": "4.35.0", + "@rollup/rollup-linux-s390x-gnu": "4.35.0", + "@rollup/rollup-linux-x64-gnu": "4.35.0", + "@rollup/rollup-linux-x64-musl": "4.35.0", + "@rollup/rollup-win32-arm64-msvc": "4.35.0", + "@rollup/rollup-win32-ia32-msvc": "4.35.0", + "@rollup/rollup-win32-x64-msvc": "4.35.0", "fsevents": "~2.3.2" } }, @@ -20848,9 +20848,9 @@ } }, "node_modules/vite": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/vite/-/vite-6.2.0.tgz", - "integrity": "sha512-7dPxoo+WsT/64rDcwoOjk76XHj+TqNTIvHKcuMQ1k4/SeHDaQt5GFAeLYzrimZrMpn/O6DtdI03WUjdxuPM0oQ==", + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/vite/-/vite-6.2.1.tgz", + "integrity": "sha512-n2GnqDb6XPhlt9B8olZPrgMD/es/Nd1RdChF6CBD/fHW6pUyUTt2sQW2fPRX5GiD9XEa6+8A6A4f2vT6pSsE7Q==", "dev": true, "license": "MIT", "dependencies": { @@ -20920,9 +20920,9 @@ } }, "node_modules/vite-node": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-3.0.7.tgz", - "integrity": "sha512-2fX0QwX4GkkkpULXdT1Pf4q0tC1i1lFOyseKoonavXUNlQ77KpW2XqBGGNIm/J4Ows4KxgGJzDguYVPKwG/n5A==", + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-3.0.8.tgz", + "integrity": "sha512-6PhR4H9VGlcwXZ+KWCdMqbtG649xCPZqfI9j2PsK1FcXgEzro5bGHcVKFCTqPLaNKZES8Evqv4LwvZARsq5qlg==", "dev": true, "license": "MIT", "dependencies": { @@ -20958,19 +20958,19 @@ } }, "node_modules/vitest": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/vitest/-/vitest-3.0.7.tgz", - "integrity": "sha512-IP7gPK3LS3Fvn44x30X1dM9vtawm0aesAa2yBIZ9vQf+qB69NXC5776+Qmcr7ohUXIQuLhk7xQR0aSUIDPqavg==", + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-3.0.8.tgz", + "integrity": "sha512-dfqAsNqRGUc8hB9OVR2P0w8PZPEckti2+5rdZip0WIz9WW0MnImJ8XiR61QhqLa92EQzKP2uPkzenKOAHyEIbA==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/expect": "3.0.7", - "@vitest/mocker": "3.0.7", - "@vitest/pretty-format": "^3.0.7", - "@vitest/runner": "3.0.7", - "@vitest/snapshot": "3.0.7", - "@vitest/spy": "3.0.7", - "@vitest/utils": "3.0.7", + "@vitest/expect": "3.0.8", + "@vitest/mocker": "3.0.8", + "@vitest/pretty-format": "^3.0.8", + "@vitest/runner": "3.0.8", + "@vitest/snapshot": "3.0.8", + "@vitest/spy": "3.0.8", + "@vitest/utils": "3.0.8", "chai": "^5.2.0", "debug": "^4.4.0", "expect-type": "^1.1.0", @@ -20982,7 +20982,7 @@ "tinypool": "^1.0.2", "tinyrainbow": "^2.0.0", "vite": "^5.0.0 || ^6.0.0", - "vite-node": "3.0.7", + "vite-node": "3.0.8", "why-is-node-running": "^2.3.0" }, "bin": { @@ -20998,8 +20998,8 @@ "@edge-runtime/vm": "*", "@types/debug": "^4.1.12", "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", - "@vitest/browser": "3.0.7", - "@vitest/ui": "3.0.7", + "@vitest/browser": "3.0.8", + "@vitest/ui": "3.0.8", "happy-dom": "*", "jsdom": "*" }, diff --git a/package.json b/package.json index be0ee6e7ff..d8a4677cb0 100644 --- a/package.json +++ b/package.json @@ -54,7 +54,7 @@ "@biomejs/biome": "^1.9.4", "@types/aws-lambda": "^8.10.147", "@types/node": "^22.13.9", - "@vitest/coverage-v8": "^3.0.7", + "@vitest/coverage-v8": "^3.0.8", "husky": "^9.1.7", "lerna": "8.1.2", "lint-staged": "^15.4.3", From 3973d3863b92754cd71d5fe68452447c6e774fbe Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 11 Mar 2025 16:14:25 +0100 Subject: [PATCH 04/56] chore(deps-dev): bump axios from 1.7.4 to 1.8.2 (#3711) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 59bb3dbc7c..5616e455a0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11250,10 +11250,11 @@ } }, "node_modules/axios": { - "version": "1.7.4", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.4.tgz", - "integrity": "sha512-DukmaFRnY6AzAALSH4J2M3k6PkaC+MfaAGdEERRWcC9q3/TWQwLpHR8ZRLKTdQ3aBDL64EdluRDjJqKw+BPZEw==", + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.8.2.tgz", + "integrity": "sha512-ls4GYBm5aig9vWx8AWDSGLpnpDQRtWAfrjU+EuytuODrFBkqesN2RkOQCBzrA1RQNHw1SmRMSDDDSwzNAYQ6Rg==", "dev": true, + "license": "MIT", "dependencies": { "follow-redirects": "^1.15.6", "form-data": "^4.0.0", From a0795fc6b686677ac4b013234e9eddfbc044087a Mon Sep 17 00:00:00 2001 From: Andrea Amorosi Date: Wed, 12 Mar 2025 14:38:45 +0100 Subject: [PATCH 05/56] docs(validation): api docs & minor fixes (#3713) --- README.md | 4 +- packages/validation/README.md | 221 +++++++++++++++++- packages/validation/package.json | 41 +++- packages/validation/src/decorator.ts | 153 +++++++++++- packages/validation/src/errors.ts | 86 ++++++- packages/validation/src/index.ts | 3 - packages/validation/src/middleware.ts | 177 +++++++++++--- packages/validation/src/types.ts | 73 ++++-- packages/validation/src/utils.ts | 16 ++ packages/validation/src/validate.ts | 138 ++++++++++- .../validation/tests/unit/decorator.test.ts | 32 ++- packages/validation/tests/unit/index.test.ts | 18 -- .../validation/tests/unit/middleware.test.ts | 81 ++++--- .../validation/tests/unit/validate.test.ts | 19 +- packages/validation/typedoc.json | 13 ++ vitest.config.ts | 12 +- 16 files changed, 910 insertions(+), 177 deletions(-) delete mode 100644 packages/validation/src/index.ts create mode 100644 packages/validation/src/utils.ts delete mode 100644 packages/validation/tests/unit/index.test.ts create mode 100644 packages/validation/typedoc.json diff --git a/README.md b/README.md index a69ad12ec5..f5d4d566b5 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # Powertools for AWS Lambda (TypeScript) -![NodeSupport](https://img.shields.io/static/v1?label=node&message=%2016|%2018|%2020&color=green?style=flat-square&logo=node) +![NodeSupport](https://img.shields.io/static/v1?label=node&message=%2018|%2020|%2022&color=green?style=flat-square&logo=node) ![GitHub Release](https://img.shields.io/github/v/release/aws-powertools/powertools-lambda-typescript?style=flat-square) [![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=aws-powertools_powertools-lambda-typescript&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=aws-powertools_powertools-lambda-typescript) [![Security Rating](https://sonarcloud.io/api/project_badges/measure?project=aws-powertools_powertools-lambda-typescript&metric=security_rating)](https://sonarcloud.io/summary/new_code?id=aws-powertools_powertools-lambda-typescript) @@ -28,6 +28,7 @@ Find the complete project's [documentation here](https://docs.powertools.aws.dev - **[Batch Processing](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. - **[JMESPath Functions](https://docs.powertools.aws.dev/lambda/typescript/latest/utilities/jmespath/)** - Built-in JMESPath functions to easily deserialize common encoded JSON payloads in Lambda functions. - **[Parser (Zod)](https://docs.powertools.aws.dev/lambda/typescript/latest/utilities/parser/)** - Utility that provides data validation and parsing using Zod, a TypeScript-first schema declaration and validation library. +- **[Validation](https://docs.powertools.aws.dev/lambda/typescript/latest/utilities/validation/)** - JSON Schema validation for events and responses, including JMESPath support to unwrap events before validation. ## Install @@ -41,6 +42,7 @@ You can use Powertools for AWS Lambda (TypeScript) by installing it with your fa - **Batch**: `npm install @aws-lambda-powertools/batch` - **JMESPath Functions**: `npm install @aws-lambda-powertools/jmespath` - **Parser**: `npm install @aws-lambda-powertools/parser zod@~3` +- **Validation**: `npm install @aws-lambda-powertools/validation` ### Examples diff --git a/packages/validation/README.md b/packages/validation/README.md index b843d1823b..77a2fdfc68 100644 --- a/packages/validation/README.md +++ b/packages/validation/README.md @@ -2,9 +2,6 @@ This utility provides JSON Schema validation for events and responses, including JMESPath support to unwrap events before validation. -> [!Warning] -> This feature is currently under development. As such it's considered not stable and we might make significant breaking changes before going before its release. You are welcome to [provide feedback](https://github.com/aws-powertools/powertools-lambda-typescript/discussions/3519) and [contribute to its implementation](https://github.com/aws-powertools/powertools-lambda-typescript/milestone/18). - 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 library in both TypeScript and JavaScript code bases. To get started, install the package by running: @@ -13,8 +10,222 @@ To get started, install the package by running: npm i @aws-lambda-powertools/validation ``` -> [!Note] -> This readme is a work in progress. +## Features + +You can validate inbound and outbound payloads using the `@validator` class method decorator or `validator` Middy.js middleware. + +You can also use the standalone `validate` function, if you want more control over the validation process such as handling a validation error. + +### Validator decorator + +The `@validator` decorator is a TypeScript class method decorator that you can use to validate both the incoming event and the response payload. + +If the validation fails, we will throw a `SchemaValidationError`. + +```typescript +import { validator } from '@aws-lambda-powertools/validation/decorator'; +import type { Context } from 'aws-lambda'; + +const inboundSchema = { + type: 'object', + properties: { + value: { type: 'number' }, + }, + required: ['value'], + additionalProperties: false, +}; + +const outboundSchema = { + type: 'object', + properties: { + result: { type: 'number' }, + }, + required: ['result'], + additionalProperties: false, +}; + +class Lambda { + @validator({ + inboundSchema, + outboundSchema, + }) + async handler(event: { value: number }, _context: Context) { + // Your handler logic here + return { result: event.value * 2 }; + } +} + +const lambda = new Lambda(); +export const handler = lambda.handler.bind(lambda); +``` + +It's not mandatory to validate both the inbound and outbound payloads. You can either use one, the other, or both. + +### Validator middleware + +If you are using Middy.js, you can instead use the `validator` middleware to validate the incoming event and response payload. + +```typescript +import { validator } from '@aws-lambda-powertools/validation/middleware'; +import middy from '@middy/core'; + +const inboundSchema = { + type: 'object', + properties: { + foo: { type: 'string' }, + }, + required: ['foo'], + additionalProperties: false, +}; + +const outboundSchema = { + type: 'object', + properties: { + bar: { type: 'number' }, + }, + required: ['bar'], + additionalProperties: false, +}; + +export const handler = middy() + .use(validation({ inboundSchema, outboundSchema })) + .handler(async (event) => { + // Your handler logic here + return { bar: 42 }; + }); +``` + +Like the `@validator` decorator, you can choose to validate only the inbound or outbound payload. + +### Standalone validate function + +The `validate` function gives you more control over the validation process, and is typically used within the Lambda handler, or any other function that needs to validate data. + +When using the standalone function, you can gracefully handle schema validation errors by catching `SchemaValidationError` errors. + +```typescript +import { validate } from '@aws-lambda-powertools/validation'; +import { SchemaValidationError } from '@aws-lambda-powertools/validation/errors'; + +const schema = { + type: 'object', + properties: { + name: { type: 'string' }, + age: { type: 'number' }, + }, + required: ['name', 'age'], + additionalProperties: false, +} as const; + +const payload = { name: 'John', age: 30 }; + +export const handler = async (event: unknown) => { + try { + const validatedData = validate({ + payload, + schema, + }); + + // Your handler logic here + } catch (error) { + if (error instanceof SchemaValidationError) { + // Handle the validation error + return { + statusCode: 400, + body: JSON.stringify({ message: error.message }), + }; + } + // Handle other errors + throw error; + } +} +``` + +### JMESPath support + +In some cases you might want to validate only a portion of the event payload - this is what the `envelope` option is for. + +You can use JMESPath expressions to specify the path to the property you want to validate. The validator will unwrap the event before validating it. + +```typescript +import { validate } from '@aws-lambda-powertools/validation'; + +const schema = { + type: 'object', + properties: { + user: { type: 'string' }, + }, + required: ['user'], + additionalProperties: false, +} as const; + +const payload = { + data: { + user: 'Alice', + }, +}; + +const validatedData = validate({ + payload, + schema, + envelope: 'data', +}); +``` + +### Extending the validator + +Since the validator is built on top of [Ajv](https://ajv.js.org/), you can extend it with custom formats and external schemas, as well as bringing your own `ajv` instance. + +The example below shows how to pass additional options to the `validate` function, but you can also pass them to the `@validator` decorator and `validator` middleware. + +```typescript +import { validate } from '@aws-lambda-powertools/validation'; + +const formats = { + ageRange: (value: number) => return value >= 0 && value <= 120, +}; + +const definitionSchema = { + $id: 'https://example.com/schemas/definitions.json', + definitions: { + user: { + type: 'object', + properties: { + name: { type: 'string' }, + age: { type: 'number', format: 'ageRange' }, + }, + required: ['name', 'age'], + additionalProperties: false, + } + } +} as const; + +const schema = { + $id: 'https://example.com/schemas/user.json', + type: 'object', + properties: { + user: { $ref: 'definitions.json#/definitions/user' }, + }, + required: ['user'], + additionalProperties: false, +} as const; + +const payload = { + user: { + name: 'Alice', + age: 25, + }, +}; + +const validatedData = validate({ + payload, + schema, + externalRefs: [definitionSchema], + formats, +}); +``` + +For more information on how to use the `validate` function, please refer to the [documentation](https://docs.powertools.aws.dev/lambda/typescript/latest/utilities/validation). ## Contribute diff --git a/packages/validation/package.json b/packages/validation/package.json index d842f95518..2231fe1dbb 100644 --- a/packages/validation/package.json +++ b/packages/validation/package.json @@ -6,7 +6,6 @@ "name": "Amazon Web Services", "url": "https://aws.amazon.com" }, - "private": true, "scripts": { "test": "vitest --run", "test:unit": "vitest --run", @@ -18,7 +17,7 @@ "test:e2e": "echo \"Not implemented\"", "build:cjs": "tsc --build tsconfig.json && echo '{ \"type\": \"commonjs\" }' > lib/cjs/package.json", "build:esm": "tsc --build tsconfig.esm.json && echo '{ \"type\": \"module\" }' > lib/esm/package.json", - "build": "echo \"Not implemented\"", + "build": "npm run build:esm & npm run build:cjs", "lint": "biome lint .", "lint:fix": "biome check --write .", "prepack": "node ../../.github/scripts/release_patch_package_json.js ." @@ -29,12 +28,42 @@ "exports": { ".": { "require": { - "types": "./lib/cjs/index.d.ts", - "default": "./lib/cjs/index.js" + "types": "./lib/cjs/validate.d.ts", + "default": "./lib/cjs/validate.js" }, "import": { - "types": "./lib/esm/index.d.ts", - "default": "./lib/esm/index.js" + "types": "./lib/esm/validate.d.ts", + "default": "./lib/esm/validate.js" + } + }, + "./middleware": { + "require": { + "types": "./lib/cjs/middleware.d.ts", + "default": "./lib/cjs/middleware.js" + }, + "import": { + "types": "./lib/esm/middleware.d.ts", + "default": "./lib/esm/middleware.js" + } + }, + "./errors": { + "require": { + "types": "./lib/cjs/errors.d.ts", + "default": "./lib/cjs/errors.js" + }, + "import": { + "types": "./lib/esm/errors.d.ts", + "default": "./lib/esm/errors.js" + } + }, + "./decorator": { + "require": { + "types": "./lib/cjs/decorator.d.ts", + "default": "./lib/cjs/decorator.js" + }, + "import": { + "types": "./lib/esm/decorator.d.ts", + "default": "./lib/esm/decorator.js" } } }, diff --git a/packages/validation/src/decorator.ts b/packages/validation/src/decorator.ts index 45a9edfb3d..a9020e3469 100644 --- a/packages/validation/src/decorator.ts +++ b/packages/validation/src/decorator.ts @@ -1,15 +1,148 @@ import { SchemaValidationError } from './errors.js'; import type { ValidatorOptions } from './types.js'; +import { getErrorCause } from './utils.js'; import { validate } from './validate.js'; -export function validator(options: ValidatorOptions) { + +/** + * Class method decorator to validate the input and output of a method using JSON Schema. + * + * @example + * ```typescript + * import { validator } from '@aws-lambda-powertools/validation/decorator'; + * import type { Context } from 'aws-lambda'; + * + * const inboundSchema = { + * type: 'object', + * properties: { + * value: { type: 'number' }, + * }, + * required: ['value'], + * additionalProperties: false, + * }; + * + * const outboundSchema = { + * type: 'object', + * properties: { + * result: { type: 'number' }, + * }, + * required: ['result'], + * additionalProperties: false, + * }; + * + * class Lambda { + * ⁣@validator({ + * inboundSchema, + * outboundSchema, + * }) + * async handler(event: { value: number }, _context: Context) { + * // Your handler logic here + * return { result: event.value * 2 }; + * } + * } + * + * const lambda = new Lambda(); + * export const handler = lambda.handler.bind(lambda); + * ``` + * + * When validating nested payloads, you can also provide an optional JMESPath expression to extract a specific part of the payload + * before validation using the `envelope` parameter. This is useful when the payload is nested or when you want to validate only a specific part of it. + * + * @example + * ```typescript + * import { validator } from '@aws-lambda-powertools/validation/decorator'; + * + * class Lambda { + * ⁣@validator({ + * inboundSchema: { + * type: 'number', + * }, + * envelope: 'nested', + * }) + * async handler(event: number, _context: Context) { + * return { result: event * 2 }; + * } + * } + * + * const lambda = new Lambda(); + * export const handler = lambda.handler.bind(lambda); + * ``` + * + * Since the Validation utility is built on top of Ajv, you can also provide custom formats and external references + * to the validation process. This allows you to extend the validation capabilities of Ajv to suit your specific needs. + * + * @example + * ```typescript + * import { validate } from '@aws-lambda-powertools/validation'; + * + * const formats = { + * ageRange: (value: number) => return value >= 0 && value <= 120, + * }; + * + * const definitionSchema = { + * $id: 'https://example.com/schemas/definitions.json', + * definitions: { + * user: { + * type: 'object', + * properties: { + * name: { type: 'string' }, + * age: { type: 'number', format: 'ageRange' }, + * }, + * required: ['name', 'age'], + * additionalProperties: false, + * } + * } + * } as const; + * + * const schema = { + * $id: 'https://example.com/schemas/user.json', + * type: 'object', + * properties: { + * user: { $ref: 'definitions.json#/definitions/user' }, + * }, + * required: ['user'], + * additionalProperties: false, + * } as const; + * + * const payload = { + * user: { + * name: 'Alice', + * age: 25, + * }, + * }; + * + * class Lambda { + * ⁣@validator({ + * inboundSchema: schema, + * externalRefs: [definitionSchema], + * formats, + * }) + * async handler(event: { value: number }, _context: Context) { + * // Your handler logic here + * return { result: event.value * 2 }; + * } + * } + * + * const lambda = new Lambda(); + * export const handler = lambda.handler.bind(lambda); + * ``` + * + * Additionally, you can provide an existing Ajv instance to reuse the same instance across multiple validations. If + * you don't provide an Ajv instance, a new one will be created for each validation. + * + * @param options - The validation options + * @param options.inboundSchema - The JSON schema for inbound validation. + * @param options.outboundSchema - The JSON schema for outbound validation. + * @param options.envelope - Optional JMESPath expression to use as envelope for the payload. + * @param options.formats - Optional formats for validation. + * @param options.externalRefs - Optional external references for validation. + * @param options.ajv - Optional Ajv instance to use for validation, if not provided a new instance will be created. + */ +function validator(options: ValidatorOptions) { return ( _target: unknown, _propertyKey: string | symbol, descriptor: PropertyDescriptor ) => { - if (!descriptor.value) { - return descriptor; - } const { inboundSchema, outboundSchema, @@ -18,7 +151,7 @@ export function validator(options: ValidatorOptions) { externalRefs, ajv, } = options; - if (!inboundSchema && !outboundSchema) { + if (!options.inboundSchema && !outboundSchema) { return descriptor; } const originalMethod = descriptor.value; @@ -35,7 +168,9 @@ export function validator(options: ValidatorOptions) { ajv: ajv, }); } catch (error) { - throw new SchemaValidationError('Inbound validation failed', error); + throw new SchemaValidationError('Inbound schema validation failed', { + cause: getErrorCause(error), + }); } } const result = await originalMethod.apply(this, [ @@ -52,7 +187,9 @@ export function validator(options: ValidatorOptions) { ajv: ajv, }); } catch (error) { - throw new SchemaValidationError('Outbound Validation failed', error); + throw new SchemaValidationError('Outbound schema validation failed', { + cause: getErrorCause(error), + }); } } return result; @@ -60,3 +197,5 @@ export function validator(options: ValidatorOptions) { return descriptor; }; } + +export { validator }; diff --git a/packages/validation/src/errors.ts b/packages/validation/src/errors.ts index db41e7f7e5..ce925b5465 100644 --- a/packages/validation/src/errors.ts +++ b/packages/validation/src/errors.ts @@ -1,9 +1,85 @@ -export class SchemaValidationError extends Error { - public errors: unknown; +/** + * Base error class for all validation errors. + * + * This error is usually not thrown directly, but it's used as a base class for + * other errors thrown by the Validation utility. You can use it to catch all + * validation errors in a single catch block. + */ +class ValidationError extends Error { + constructor(message: string, options?: ErrorOptions) { + super(message, options); + this.name = 'ValidationError'; + } +} - constructor(message: string, errors?: unknown) { - super(message); +/** + * Error thrown when a schema validation fails. + * + * This error is thrown when the validation of a payload against a schema fails, + * the `cause` property contains the original Ajv issues. + * + * @example + * ```typescript + * import { validate } from '@aws-lambda-powertools/validation'; + * import { ValidationError } from '@aws-lambda-powertools/validation/errors'; + * + * const schema = { + * type: 'number', + * minimum: 0, + * maximum: 100, + * }; + * + * const payload = -1; + * + * try { + * validate({ payload, schema }); + * } catch (error) { + * if (error instanceof ValidationError) { + * // cause includes the original Ajv issues + * const { message, cause } = error; + * // ... handle the error + * } + * + * // handle other errors + * } + * ``` + */ +class SchemaValidationError extends ValidationError { + constructor(message: string, options?: ErrorOptions) { + super(message, options); this.name = 'SchemaValidationError'; - this.errors = errors; } } + +/** + * Error thrown when a schema compilation fails. + * + * This error is thrown when you pass an invalid schema to the validator. + * + * @example + * ```typescript + * import { validate } from '@aws-lambda-powertools/validation'; + * + * const schema = { + * invalid: 'schema', + * }; + * + * try { + * validate({ payload: {}, schema }); + * } catch (error) { + * if (error instanceof SchemaCompilationError) { + * // handle the error + * } + * + * // handle other errors + * } + * ``` + */ +class SchemaCompilationError extends ValidationError { + constructor(message: string, options?: ErrorOptions) { + super(message, options); + this.name = 'SchemaCompilationError'; + } +} + +export { ValidationError, SchemaValidationError, SchemaCompilationError }; diff --git a/packages/validation/src/index.ts b/packages/validation/src/index.ts deleted file mode 100644 index 039a9236fa..0000000000 --- a/packages/validation/src/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export { validate } from './validate.js'; -export { SchemaValidationError } from './errors.js'; -export { validator } from './decorator.js'; diff --git a/packages/validation/src/middleware.ts b/packages/validation/src/middleware.ts index e706d6c846..af6d953033 100644 --- a/packages/validation/src/middleware.ts +++ b/packages/validation/src/middleware.ts @@ -1,39 +1,152 @@ +import type { + MiddlewareFn, + MiddyLikeRequest, +} from '@aws-lambda-powertools/commons/types'; import { SchemaValidationError } from './errors.js'; import type { ValidatorOptions } from './types.js'; +import { getErrorCause } from './utils.js'; import { validate } from './validate.js'; -export function validation(options: ValidatorOptions) { - return { - before: async (handler: { event: unknown }) => { - if (options.inboundSchema) { - try { - handler.event = validate({ - payload: handler.event, - schema: options.inboundSchema, - envelope: options.envelope, - formats: options.formats, - externalRefs: options.externalRefs, - ajv: options.ajv, - }); - } catch (error) { - throw new SchemaValidationError('Inbound validation failed', error); - } +/** + * Middy.js middleware to validate your event and response payloads using JSON schema. + * + * Both inbound and outbound schemas are optional. If only one is provided, only that one will be validated. + * + * @example + * ```typescript + * import { validation } from '@aws-lambda-powertools/validation/middleware'; + * import middy from '@middy/core'; + * + * const inboundSchema = { + * type: 'object', + * properties: { + * foo: { type: 'string' }, + * }, + * required: ['foo'], + * additionalProperties: false, + * }; + * + * const outboundSchema = { + * type: 'object', + * properties: { + * bar: { type: 'number' }, + * }, + * required: ['bar'], + * additionalProperties: false, + * }; + * + * export const handler = middy() + * .use(validation({ inboundSchema, outboundSchema })) + * .handler(async (event) => { + * // Your handler logic here + * return { bar: 42 }; + * }); + * ``` + * + * Since the Validation utility is built on top of Ajv, you can also provide custom formats and external references + * to the validation process. This allows you to extend the validation capabilities of Ajv to suit your specific needs. + * + * @example + * ```typescript + * import { validator } from '@aws-lambda-powertools/validation/middleware'; + * import middy from '@middy/core'; + * + * const formats = { + * ageRange: (value: number) => return value >= 0 && value <= 120, + * }; + * + * const definitionSchema = { + * $id: 'https://example.com/schemas/definitions.json', + * definitions: { + * user: { + * type: 'object', + * properties: { + * name: { type: 'string' }, + * age: { type: 'number', format: 'ageRange' }, + * }, + * required: ['name', 'age'], + * additionalProperties: false, + * } + * } + * } as const; + * + * const schema = { + * $id: 'https://example.com/schemas/user.json', + * type: 'object', + * properties: { + * user: { $ref: 'definitions.json#/definitions/user' }, + * }, + * required: ['user'], + * additionalProperties: false, + * } as const; + * + * export const handler = middy() + * .use(validation({ + * inboundSchema, + * outboundSchema, + * externalRefs: [definitionSchema], + * formats, + * })) + * .handler(async (event) => { + * // Your handler logic here + * return { bar: 42 }; + * }); + * ``` + * + * Additionally, you can provide an existing Ajv instance to reuse the same instance across multiple validations. If + * you don't provide an Ajv instance, a new one will be created for each validation. + * + * @param options - The validation options + * @param options.inboundSchema - The JSON schema for inbound validation. + * @param options.outboundSchema - The JSON schema for outbound validation. + * @param options.envelope - Optional JMESPath expression to use as envelope for the payload. + * @param options.formats - Optional formats for validation. + * @param options.externalRefs - Optional external references for validation. + * @param options.ajv - Optional Ajv instance to use for validation, if not provided a new instance will be created. + */ +const validator = (options: ValidatorOptions) => { + const before: MiddlewareFn = async (request) => { + if (options.inboundSchema) { + const originalEvent = structuredClone(request.event); + try { + request.event = validate({ + payload: originalEvent, + schema: options.inboundSchema, + envelope: options.envelope, + formats: options.formats, + externalRefs: options.externalRefs, + ajv: options.ajv, + }); + } catch (error) { + throw new SchemaValidationError('Inbound schema validation failed', { + cause: getErrorCause(error), + }); } - }, - after: async (handler: { response: unknown }) => { - if (options.outboundSchema) { - try { - handler.response = validate({ - payload: handler.response, - schema: options.outboundSchema, - formats: options.formats, - externalRefs: options.externalRefs, - ajv: options.ajv, - }); - } catch (error) { - throw new SchemaValidationError('Outbound validation failed', error); - } + } + }; + + const after = async (handler: MiddyLikeRequest) => { + if (options.outboundSchema) { + try { + handler.response = validate({ + payload: handler.response, + schema: options.outboundSchema, + formats: options.formats, + externalRefs: options.externalRefs, + ajv: options.ajv, + }); + } catch (error) { + throw new SchemaValidationError('Outbound schema validation failed', { + cause: getErrorCause(error), + }); } - }, + } }; -} + + return { + before, + after, + }; +}; + +export { validator }; diff --git a/packages/validation/src/types.ts b/packages/validation/src/types.ts index 4543e6ffe9..c5d63d89cc 100644 --- a/packages/validation/src/types.ts +++ b/packages/validation/src/types.ts @@ -1,36 +1,65 @@ -import type { - Ajv, - AnySchema, - AsyncFormatDefinition, - FormatDefinition, -} from 'ajv'; +import type { Ajv, AnySchema, Format } from 'ajv'; type Prettify = { [K in keyof T]: T[K]; } & {}; +/** + * Options to customize the JSON Schema validation. + * + * @param payload - The data to validate. + * @param schema - The JSON schema for validation. + * @param envelope - Optional JMESPATH expression to use as envelope for the payload. + * @param formats - Optional formats for validation. + * @param externalRefs - Optional external references for validation. + * @param ajv - Optional Ajv instance to use for validation, if not provided a new instance will be created. + */ type ValidateParams = { + /** + * The data to validate. + */ payload: unknown; + /** + * The JSON schema for validation. + */ schema: AnySchema; + /** + * Optional JMESPATH expression to use as envelope for the payload. + */ envelope?: string; - formats?: Record< - string, - | string - | RegExp - | FormatDefinition - | FormatDefinition - | AsyncFormatDefinition - | AsyncFormatDefinition - >; - externalRefs?: object[]; + /** + * Optional formats for validation. + */ + formats?: Record; + /** + * Optional external references for validation. + */ + externalRefs?: AnySchema | AnySchema[]; + /** + * Optional Ajv instance to use for validation, if not provided a new instance will be created. + */ ajv?: Ajv; }; -type ValidatorOptions = Prettify< - Omit & { - inboundSchema?: AnySchema; - outboundSchema?: AnySchema; - } ->; +/** + * Options to customize the JSON Schema validation. + * + * @param inboundSchema - The JSON schema for inbound validation. + * @param outboundSchema - The JSON schema for outbound validation. + * @param envelope - Optional JMESPATH expression to use as envelope for the payload. + * @param formats - Optional formats for validation. + * @param externalRefs - Optional external references for validation. + * @param ajv - Optional Ajv instance to use for validation, if not provided a new instance will be created. + */ +interface ValidatorOptions extends Omit { + /** + * The JSON schema for inbound validation. + */ + inboundSchema?: AnySchema; + /** + * The JSON schema for outbound validation. + */ + outboundSchema?: AnySchema; +} export type { ValidateParams, ValidatorOptions }; diff --git a/packages/validation/src/utils.ts b/packages/validation/src/utils.ts new file mode 100644 index 0000000000..dbace4fd00 --- /dev/null +++ b/packages/validation/src/utils.ts @@ -0,0 +1,16 @@ +/** + * Get the original cause of the error if it is a `SchemaValidationError`. + * + * This is useful so that we don't rethrow the same error type. + * + * @param error - The error to extract the cause from. + */ +const getErrorCause = (error: unknown): unknown => { + let cause = error; + if (error instanceof Error && error.name === 'SchemaValidationError') { + cause = error.cause; + } + return cause; +}; + +export { getErrorCause }; diff --git a/packages/validation/src/validate.ts b/packages/validation/src/validate.ts index 36d0fccb0a..b618a32d39 100644 --- a/packages/validation/src/validate.ts +++ b/packages/validation/src/validate.ts @@ -1,9 +1,124 @@ import { search } from '@aws-lambda-powertools/jmespath'; import { Ajv, type ValidateFunction } from 'ajv'; -import { SchemaValidationError } from './errors.js'; +import { SchemaCompilationError, SchemaValidationError } from './errors.js'; import type { ValidateParams } from './types.js'; -export function validate(params: ValidateParams): T { +/** + * Validates a payload against a JSON schema using Ajv. + * + * @example + * ```typescript + * import { validate } from '@aws-lambda-powertools/validation'; + * + * const schema = { + * type: 'object', + * properties: { + * name: { type: 'string' }, + * age: { type: 'number' }, + * }, + * required: ['name', 'age'], + * additionalProperties: false, + * } as const; + * + * const payload = { name: 'John', age: 30 }; + * + * const validatedData = validate({ + * payload, + * schema, + * }); + * ``` + * + * When validating, you can also provide an optional JMESPath expression to extract a specific part of the payload + * before validation using the `envelope` parameter. This is useful when the payload is nested or when you want to + * validate only a specific part of it. + * + * ```typescript + * import { validate } from '@aws-lambda-powertools/validation'; + * + * const schema = { + * type: 'object', + * properties: { + * user: { type: 'string' }, + * }, + * required: ['user'], + * additionalProperties: false, + * } as const; + * + * const payload = { + * data: { + * user: 'Alice', + * }, + * }; + * + * const validatedData = validate({ + * payload, + * schema, + * envelope: 'data', + * }); + * ``` + * + * Since the Validation utility is built on top of Ajv, you can also provide custom formats and external references + * to the validation process. This allows you to extend the validation capabilities of Ajv to suit your specific needs. + * + * @example + * ```typescript + * import { validate } from '@aws-lambda-powertools/validation'; + * + * const formats = { + * ageRange: (value: number) => return value >= 0 && value <= 120, + * }; + * + * const definitionSchema = { + * $id: 'https://example.com/schemas/definitions.json', + * definitions: { + * user: { + * type: 'object', + * properties: { + * name: { type: 'string' }, + * age: { type: 'number', format: 'ageRange' }, + * }, + * required: ['name', 'age'], + * additionalProperties: false, + * } + * } + * } as const; + * + * const schema = { + * $id: 'https://example.com/schemas/user.json', + * type: 'object', + * properties: { + * user: { $ref: 'definitions.json#/definitions/user' }, + * }, + * required: ['user'], + * additionalProperties: false, + * } as const; + * + * const payload = { + * user: { + * name: 'Alice', + * age: 25, + * }, + * }; + * + * const validatedData = validate({ + * payload, + * schema, + * externalRefs: [definitionSchema], + * formats, + * }); + * ``` + * + * Additionally, you can provide an existing Ajv instance to reuse the same instance across multiple validations. If + * you don't provide an Ajv instance, a new one will be created for each validation. + * + * @param params.payload - The payload to validate. + * @param params.schema - The JSON schema to validate against. + * @param params.envelope - Optional JMESPath expression to use as envelope for the payload. + * @param params.formats - Optional formats for validation. + * @param params.externalRefs - Optional external references for validation. + * @param params.ajv - Optional Ajv instance to use for validation, if not provided a new instance will be created. + */ +const validate = (params: ValidateParams): T => { const { payload, schema, envelope, formats, externalRefs, ajv } = params; const ajvInstance = ajv || new Ajv({ allErrors: true }); @@ -14,16 +129,16 @@ export function validate(params: ValidateParams): T { } if (externalRefs) { - for (const refSchema of externalRefs) { - ajvInstance.addSchema(refSchema); - } + ajvInstance.addSchema(externalRefs); } let validateFn: ValidateFunction; try { validateFn = ajvInstance.compile(schema); } catch (error) { - throw new SchemaValidationError('Failed to compile schema', error); + throw new SchemaCompilationError('Failed to compile schema', { + cause: error, + }); } const trimmedEnvelope = envelope?.trim(); @@ -33,11 +148,12 @@ export function validate(params: ValidateParams): T { const valid = validateFn(dataToValidate); if (!valid) { - throw new SchemaValidationError( - 'Schema validation failed', - validateFn.errors - ); + throw new SchemaValidationError('Schema validation failed', { + cause: validateFn.errors, + }); } return dataToValidate as T; -} +}; + +export { validate }; diff --git a/packages/validation/tests/unit/decorator.test.ts b/packages/validation/tests/unit/decorator.test.ts index 94ba2f0c40..b2b6df0562 100644 --- a/packages/validation/tests/unit/decorator.test.ts +++ b/packages/validation/tests/unit/decorator.test.ts @@ -20,7 +20,7 @@ const outboundSchema = { additionalProperties: false, }; -describe('validator decorator', () => { +describe('Decorator: validator', () => { it('should validate inbound and outbound successfully', async () => { // Prepare class TestClass { @@ -31,8 +31,10 @@ describe('validator decorator', () => { } const instance = new TestClass(); const input = { value: 5 }; + // Act const output = await instance.multiply(input); + // Assess expect(output).toEqual({ result: 10 }); }); @@ -49,6 +51,7 @@ describe('validator decorator', () => { const invalidInput = { value: 'not a number' } as unknown as { value: number; }; + // Act & Assess await expect(instance.multiply(invalidInput)).rejects.toThrow( SchemaValidationError @@ -59,14 +62,14 @@ describe('validator decorator', () => { // Prepare class TestClassInvalid { @validator({ inboundSchema, outboundSchema }) - async multiply(input: { value: number }): Promise<{ result: number }> { - return { result: 'invalid' } as unknown as { result: number }; + async multiply(_input: { value: number }) { + return { result: 'invalid' }; } } const instance = new TestClassInvalid(); - const input = { value: 5 }; + // Act & Assess - await expect(instance.multiply(input)).rejects.toThrow( + await expect(instance.multiply({ value: 5 })).rejects.toThrow( SchemaValidationError ); }); @@ -81,23 +84,12 @@ describe('validator decorator', () => { } const instance = new TestClassNoOp(); const data = { foo: 'bar' }; + // Act const result = await instance.echo(data); - // Assess - expect(result).toEqual(data); - }); - it('should return descriptor unmodified if descriptor.value is undefined', () => { - // Prepare - const descriptor: PropertyDescriptor = {}; - // Act - const result = validator({ inboundSchema })( - null as unknown as object, - 'testMethod', - descriptor - ); // Assess - expect(result).toEqual(descriptor); + expect(result).toEqual(data); }); it('should validate inbound only', async () => { @@ -110,8 +102,10 @@ describe('validator decorator', () => { } const instance = new TestClassInbound(); const input = { value: 10 }; + // Act const output = await instance.process(input); + // Assess expect(output).toEqual({ data: JSON.stringify(input) }); }); @@ -126,8 +120,10 @@ describe('validator decorator', () => { } const instance = new TestClassOutbound(); const input = { text: 'hello' }; + // Act const output = await instance.process(input); + // Assess expect(output).toEqual({ result: 42 }); }); diff --git a/packages/validation/tests/unit/index.test.ts b/packages/validation/tests/unit/index.test.ts deleted file mode 100644 index e2af63bd92..0000000000 --- a/packages/validation/tests/unit/index.test.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { beforeEach, describe, expect, it, vi } from 'vitest'; -import { SchemaValidationError, validate } from '../../src/index.js'; - -describe('Index exports', () => { - beforeEach(() => { - vi.clearAllMocks(); - }); - - it('should export validate as a function', () => { - // Act & Assess - expect(typeof validate).toBe('function'); - }); - - it('should export SchemaValidationError as a function', () => { - // Act & Assess - expect(typeof SchemaValidationError).toBe('function'); - }); -}); diff --git a/packages/validation/tests/unit/middleware.test.ts b/packages/validation/tests/unit/middleware.test.ts index 204c61aadb..1d2796638a 100644 --- a/packages/validation/tests/unit/middleware.test.ts +++ b/packages/validation/tests/unit/middleware.test.ts @@ -1,7 +1,8 @@ import middy from '@middy/core'; +import type { Context } from 'aws-lambda'; import { describe, expect, it } from 'vitest'; import { SchemaValidationError } from '../../src/errors.js'; -import { validation } from '../../src/middleware.js'; +import { validator } from '../../src/middleware.js'; const inboundSchema = { type: 'object', @@ -21,53 +22,71 @@ const outboundSchema = { additionalProperties: false, }; -const response = { outputValue: 20 }; -const baseHandler = async (event: unknown) => { - return response; +const baseHandler = async (event: { inputValue: unknown }) => { + return { + outputValue: event.inputValue, + }; }; -describe('validation middleware with Middy', () => { - it('should validate inbound and outbound successfully', async () => { +describe('Middleware: validator', () => { + it('validates both inbound and outbound successfully', async () => { // Prepare - const middleware = validation({ inboundSchema, outboundSchema }); - const wrappedHandler = middy(baseHandler).use(middleware); - const event = { inputValue: 10 }; + const handler = middy(baseHandler).use( + validator({ inboundSchema, outboundSchema }) + ); + // Act - const result = await wrappedHandler(event); + const result = await handler({ inputValue: 10 }, {} as Context); + // Assess - expect(result).toEqual(response); + expect(result).toEqual({ outputValue: 10 }); }); - it('should throw error on inbound validation failure', async () => { + it('throws an error on inbound validation failure', async () => { // Prepare - const middleware = validation({ inboundSchema }); - const wrappedHandler = middy(baseHandler).use(middleware); - const invalidEvent = { inputValue: 'invalid' }; + const handler = middy(baseHandler).use(validator({ inboundSchema })); + // Act & Assess - await expect(wrappedHandler(invalidEvent)).rejects.toThrow( - SchemaValidationError + await expect( + handler({ inputValue: 'invalid' }, {} as Context) + ).rejects.toThrow( + new SchemaValidationError('Inbound schema validation failed', { + cause: [ + expect.objectContaining({ + keyword: 'type', + message: 'must be number', + }), + ], + }) ); }); - it('should throw error on outbound validation failure', async () => { - const invalidHandler = async (_event: unknown) => { - return { outputValue: 'invalid' }; - }; - const middleware = validation({ outboundSchema }); - const wrappedHandler = middy(invalidHandler).use(middleware); - const event = { any: 'value' }; + it('throws an error on outbound validation failure', async () => { + const handler = middy(() => { + return 'invalid output'; + }).use(validator({ outboundSchema })); + // Act & Assess - await expect(wrappedHandler(event)).rejects.toThrow(SchemaValidationError); + await expect(handler({ inputValue: 10 }, {} as Context)).rejects.toThrow( + new SchemaValidationError('Outbound schema validation failed', { + cause: [ + expect.objectContaining({ + keyword: 'type', + message: 'must be object', + }), + ], + }) + ); }); - it('should no-op when no schemas are provided', async () => { + it('skips validation when no schemas are provided', async () => { // Prepare - const middleware = validation({}); - const wrappedHandler = middy(baseHandler).use(middleware); - const event = { anyKey: 'anyValue' }; + const handler = middy(baseHandler).use(validator({})); + // Act - const result = await wrappedHandler(event); + const result = await handler({ inputValue: 'bar' }, {} as Context); + // Assess - expect(result).toEqual(response); + expect(result).toEqual({ outputValue: 'bar' }); }); }); diff --git a/packages/validation/tests/unit/validate.test.ts b/packages/validation/tests/unit/validate.test.ts index b4480f580e..c1e46cd1ca 100644 --- a/packages/validation/tests/unit/validate.test.ts +++ b/packages/validation/tests/unit/validate.test.ts @@ -1,6 +1,9 @@ import Ajv from 'ajv'; import { describe, expect, it } from 'vitest'; -import { SchemaValidationError } from '../../src/errors.js'; +import { + SchemaCompilationError, + SchemaValidationError, +} from '../../src/errors.js'; import type { ValidateParams } from '../../src/types.js'; import { validate } from '../../src/validate.js'; @@ -17,8 +20,7 @@ describe('validate function', () => { required: ['name', 'age'], additionalProperties: false, }; - - const params: ValidateParams = { payload, schema }; + const params: ValidateParams = { payload, schema }; // Act const result = validate(params); @@ -75,22 +77,23 @@ describe('validate function', () => { it('uses provided ajv instance and custom formats', () => { // Prepare - const payload = { email: 'test@example.com' }; + const payload = { email: 'test@example.com', region: 'us-east-1' }; const schema = { type: 'object', properties: { email: { type: 'string', format: 'custom-email' }, + region: { type: 'string', format: 'allowedRegions' }, }, - required: ['email'], + required: ['email', 'region'], additionalProperties: false, }; const ajvInstance = new Ajv({ allErrors: true }); const formats = { 'custom-email': { - type: 'string', validate: (email: string) => email.includes('@'), }, + allowedRegions: /^(us-east-1|us-west-1)$/, }; const params: ValidateParams = { @@ -149,7 +152,7 @@ describe('validate function', () => { expect(result).toEqual(payload); }); - it('throws SchemaValidationError when schema compilation fails', () => { + it('throws the correct error when schema compilation fails', () => { // Prepare const payload = { name: 'John' }; const schema = { @@ -162,6 +165,6 @@ describe('validate function', () => { const params: ValidateParams = { payload, schema }; // Act & Assess - expect(() => validate(params)).toThrow(SchemaValidationError); + expect(() => validate(params)).toThrow(SchemaCompilationError); }); }); diff --git a/packages/validation/typedoc.json b/packages/validation/typedoc.json new file mode 100644 index 0000000000..3032e9d15e --- /dev/null +++ b/packages/validation/typedoc.json @@ -0,0 +1,13 @@ +{ + "extends": [ + "../../typedoc.base.json" + ], + "entryPoints": [ + "./src/types.ts", + "./src/validate.ts", + "./src/middleware.ts", + "./src/decorator.ts", + "./src/errors.ts", + ], + "readme": "README.md" +} \ No newline at end of file diff --git a/vitest.config.ts b/vitest.config.ts index e8056e9a46..5d81a103f8 100644 --- a/vitest.config.ts +++ b/vitest.config.ts @@ -13,18 +13,10 @@ export default defineConfig({ include: ['packages/*/src/**'], exclude: [ ...coverageConfigDefaults.exclude, - 'packages/batch/src/types.ts', - 'packages/commons/src/types/**', - 'packages/event-handler/src/types/**', - 'packages/idempotency/src/types/**', - 'packages/jmespath/src/types.ts', - 'packages/logger/src/types/**', - 'packages/metrics/src/types/**', - 'packages/parameters/src/types/**', - 'packages/parser/src/types/**', 'layers/**', + 'packages/*/src/types/**', + 'packages/*/src/types.ts', 'packages/testing/**', - 'packages/tracer/src/types/**', ], }, setupFiles: ['./packages/testing/src/setupEnv.ts'], From 6e19415498e6c36b5e2a3fbae04107befb5158b9 Mon Sep 17 00:00:00 2001 From: Andrea Amorosi Date: Wed, 12 Mar 2025 16:43:19 +0100 Subject: [PATCH 06/56] chore: add api docs in mkdocs build (#3715) --- .github/workflows/reusable_publish_docs.yml | 4 --- CONTRIBUTING.md | 32 +++++++++++++++++-- README.md | 2 +- docs/Dockerfile | 3 ++ docs/contributing/setup.md | 34 ++++++++++++++++++--- docs/requirements.in | 3 +- docs/requirements.txt | 17 +++++++---- examples/snippets/validation/.gitignore | 0 mkdocs.yml | 34 +++++++++++++++++++-- package.json | 11 +++---- 10 files changed, 113 insertions(+), 27 deletions(-) create mode 100644 examples/snippets/validation/.gitignore diff --git a/.github/workflows/reusable_publish_docs.yml b/.github/workflows/reusable_publish_docs.yml index 15d53aae7c..68cacc068a 100644 --- a/.github/workflows/reusable_publish_docs.yml +++ b/.github/workflows/reusable_publish_docs.yml @@ -82,10 +82,6 @@ jobs: run: | rm -rf site mkdocs build - - name: Build API docs - run: | - rm -rf api - npm run docs-generateApiDoc - name: Configure AWS credentials uses: aws-actions/configure-aws-credentials@ececac1a45f3b08a01d2dd070d28d111c5fe6722 # v4.1.0 with: diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c548ea5beb..1fb13dda87 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -115,9 +115,35 @@ GitHub provides additional document on [forking a repository](https://help.githu You might find useful to run both the documentation website and the API reference locally while contributing: -- **Docs website**: `npm run docs-runLocalDocker` - - If this is your first time running the docs, you need to build the image: `npm run docs-buildDockerImage` -- **API reference**: `npm run docs-api-build-run` +#### Using Docker (recommended) + +1. Build the Docker image (only needed the first time): + + ```bash + npm run docs:docker:build + ``` + +2. Run the documentation website: + + ```bash + npm run docs:docker:run + ``` + +#### Using Python directly + +If you have Python 3.x installed, you can run the documentation website and API reference locally without Docker: + +1. Create a virtual environment and install dependencies: + + ```bash + npm run docs:local:setup + ``` + +2. Run the documentation website: + + ```bash + npm run docs:local:run + ``` ## Conventions diff --git a/README.md b/README.md index f5d4d566b5..3057c33ca9 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ -# Powertools for AWS Lambda (TypeScript) +# Powertools for AWS Lambda (TypeScript) ![NodeSupport](https://img.shields.io/static/v1?label=node&message=%2018|%2020|%2022&color=green?style=flat-square&logo=node) ![GitHub Release](https://img.shields.io/github/v/release/aws-powertools/powertools-lambda-typescript?style=flat-square) diff --git a/docs/Dockerfile b/docs/Dockerfile index 309fa6a2c6..5db3fb151f 100644 --- a/docs/Dockerfile +++ b/docs/Dockerfile @@ -1,5 +1,8 @@ # version 9.5.35 FROM squidfunk/mkdocs-material@sha256:047452c6641137c9caa3647d050ddb7fa67b59ed48cc67ec3a4995f3d360ab32 +# Install Node.js +RUN apk add --no-cache nodejs=20.15.1-r0 npm + COPY requirements.txt /tmp/ RUN pip install --require-hashes -r /tmp/requirements.txt diff --git a/docs/contributing/setup.md b/docs/contributing/setup.md index 68bcf2cba6..7f10903d87 100644 --- a/docs/contributing/setup.md +++ b/docs/contributing/setup.md @@ -65,10 +65,36 @@ You can use `npm run setup-local` to install all dependencies locally and setup !!! note "Curious about what `setup-local` does under the hood?" We use npm scripts to [automate common tasks](https://github.com/aws-powertools/powertools-lambda-typescript/blob/main/package.json#L24){target="_blank" rel="nofollow"} locally and in Continuous Integration environments. -## Local documentation +### Local documentation You might find useful to run both the documentation website and the API reference locally while contributing: -* **Docs website**: `npm run docs-runLocalDocker` - * If this is your first time running the docs, you need to build the image: `npm run docs-buildDockerImage` -* **API reference**: `npm run docs-api-build-run` +#### Using Docker (recommended) + +1. Build the Docker image (only needed the first time): + + ```bash + npm run docs:docker:build + ``` + +2. Run the documentation website: + + ```bash + npm run docs:docker:run + ``` + +#### Using Python directly + +If you have Python installed, you can run the documentation website and API reference locally without Docker: + +1. Create a virtual environment and install dependencies: + + ```bash + npm run docs:local:setup + ``` + +2. Run the documentation website: + + ```bash + npm run docs:local:run + ``` diff --git a/docs/requirements.in b/docs/requirements.in index d124923b00..99df90a461 100644 --- a/docs/requirements.in +++ b/docs/requirements.in @@ -1,4 +1,5 @@ mike==1.1.2 mkdocs-material==9.6.7 mkdocs-git-revision-date-plugin==0.3.2 -mkdocs-exclude==1.0.2 \ No newline at end of file +mkdocs-exclude==1.0.2 +mkdocs-typedoc==1.0.4 \ No newline at end of file diff --git a/docs/requirements.txt b/docs/requirements.txt index 650a901075..4dff4bac49 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -1,8 +1,8 @@ # -# This file is autogenerated by pip-compile with Python 3.12 +# This file is autogenerated by pip-compile with Python 3.13 # by the following command: # -# pip-compile --generate-hashes --output-file=requirements.txt requirements.in +# pip-compile --generate-hashes --output-file=docs/requirements.txt docs/requirements.in # babel==2.16.0 \ --hash=sha256:368b5b98b37c06b7daf6696391c3240c938b37767d4584413e8438c5c435fa8b \ @@ -224,7 +224,7 @@ mergedeep==1.3.4 \ mike==1.1.2 \ --hash=sha256:4c307c28769834d78df10f834f57f810f04ca27d248f80a75f49c6fa2d1527ca \ --hash=sha256:56c3f1794c2d0b5fdccfa9b9487beb013ca813de2e3ad0744724e9d34d40b77b - # via -r requirements.in + # via -r docs/requirements.in mkdocs==1.6.1 \ --hash=sha256:7b432f01d928c084353ab39c57282f29f92136665bdd6abf7c1ec8d822ef86f2 \ --hash=sha256:db91759624d1647f3f34aa0c3f327dd2601beae39a366d6e064c03468d35c20e @@ -233,24 +233,29 @@ mkdocs==1.6.1 \ # mkdocs-exclude # mkdocs-git-revision-date-plugin # mkdocs-material + # mkdocs-typedoc mkdocs-exclude==1.0.2 \ --hash=sha256:ba6fab3c80ddbe3fd31d3e579861fd3124513708271180a5f81846da8c7e2a51 - # via -r requirements.in + # via -r docs/requirements.in mkdocs-get-deps==0.2.0 \ --hash=sha256:162b3d129c7fad9b19abfdcb9c1458a651628e4b1dea628ac68790fb3061c60c \ --hash=sha256:2bf11d0b133e77a0dd036abeeb06dec8775e46efa526dc70667d8863eefc6134 # via mkdocs mkdocs-git-revision-date-plugin==0.3.2 \ --hash=sha256:2e67956cb01823dd2418e2833f3623dee8604cdf223bddd005fe36226a56f6ef - # via -r requirements.in + # via -r docs/requirements.in mkdocs-material==9.6.7 \ --hash=sha256:3e2c1fceb9410056c2d91f334a00cdea3215c28750e00c691c1e46b2a33309b4 \ --hash=sha256:8a159e45e80fcaadd9fbeef62cbf928569b93df954d4dc5ba76d46820caf7b47 - # via -r requirements.in + # via -r docs/requirements.in mkdocs-material-extensions==1.3.1 \ --hash=sha256:10c9511cea88f568257f960358a467d12b970e1f7b2c0e5fb2bb48cab1928443 \ --hash=sha256:adff8b62700b25cb77b53358dad940f3ef973dd6db797907c49e3c2ef3ab4e31 # via mkdocs-material +mkdocs-typedoc==1.0.4 \ + --hash=sha256:839b54c51a64bbb77c1c253eb81baad12462ea5cf38d361e262f5cfa8a45567a \ + --hash=sha256:a9601d6b04ed4fd5658c7170c58a3a52f584357be2a3c1e39995c6eed3712b1e + # via -r docs/requirements.in packaging==24.1 \ --hash=sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002 \ --hash=sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124 diff --git a/examples/snippets/validation/.gitignore b/examples/snippets/validation/.gitignore new file mode 100644 index 0000000000..e69de29bb2 diff --git a/mkdocs.yml b/mkdocs.yml index 090841d535..994dc80125 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -4,12 +4,35 @@ site_author: Amazon Web Services repo_url: https://github.com/aws-powertools/powertools-lambda-typescript edit_uri: edit/main/docs site_url: https://docs.powertools.aws.dev/lambda/typescript +watch: [ + docs, + packages/batch/src, + examples/snippets/batch, + packages/commons/src, + packages/event-handler/src, + examples/snippets/event-handler, + packages/idempotency/src, + examples/snippets/idempotency, + packages/jmespath/src, + examples/snippets/jmespath, + packages/logger/src, + examples/snippets/logger, + packages/metrics/src, + examples/snippets/metrics, + packages/parameters/src, + examples/snippets/parameters, + packages/parser/src, + examples/snippets/parser, + packages/tracer/src, + examples/snippets/tracer, + packages/validation/src, + examples/snippets/validation, +] nav: - Homepage: - index.md - Changelog: changelog.md - - API reference: api/" target="_blank - Upgrade guide: upgrade.md - We Made This (Community): we_made_this.md - Workshop: https://s12d.com/powertools-for-aws-lambda-workshop" target="_blank @@ -23,6 +46,7 @@ nav: - utilities/batch.md - utilities/jmespath.md - utilities/parser.md + - API reference: api" - Processes: - Roadmap: roadmap.md - Versioning policy: versioning.md @@ -101,7 +125,7 @@ markdown_extensions: - pymdownx.tasklist: custom_checkbox: true -copyright: Copyright © 2023 Amazon Web Services +copyright: Copyright © 2025 Amazon Web Services plugins: - privacy @@ -112,6 +136,12 @@ plugins: - snippets/node_modules/* - snippets/package.json - snippets/CHANGELOG.md + - typedoc: + source: '.' + output_dir: 'api' + tsconfig: 'tsconfig.json' + options: 'typedoc.json' + name: 'API Reference' extra_css: - stylesheets/extra.css diff --git a/package.json b/package.json index d8a4677cb0..255ae14623 100644 --- a/package.json +++ b/package.json @@ -27,12 +27,11 @@ "commit": "commit", "setup-local": "npm ci && npm run build && husky", "build": "npm run build -ws", - "docs-website-build-run": "npm run docs-buildDockerImage && npm run docs-runLocalDocker", - "docs-buildDockerImage": "docker build -t powertools-typescript/docs ./docs/", - "docs-runLocalDocker": "docker run --rm -it -p 8000:8000 -v ${PWD}:/docs powertools-typescript/docs", - "docs-api-build-run": "npm run docs-generateApiDoc && npx live-server api", - "docs-generateApiDoc": "typedoc .", - "docs-runLocalApiDoc": "npx live-server api", + "docs:docker:build": "docker build -t powertools-typescript/docs ./docs/", + "docs:docker:run": "docker run --rm -it -p 8000:8000 -v ${PWD}:/docs powertools-typescript/docs", + "docs:local:setup": "python3 -m venv .venv && .venv/bin/pip install -r docs/requirements.txt", + "docs:local:run": ".venv/bin/mkdocs serve", + "docs:local:api": "typedoc .", "postpublish": "git restore .", "lint:markdown": "markdownlint-cli2 '**/*.md' '#node_modules' '#**/*/node_modules' '#docs/changelog.md' '#LICENSE.md' '#.github' '#**/*/CHANGELOG.md' '#examples/app/README.md'" }, From 501f3517e2f7652f0d1b553c76cef0ecdbcb87b4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 12 Mar 2025 18:20:40 +0100 Subject: [PATCH 07/56] chore(deps): bump esbuild from 0.25.0 to 0.25.1 (#3707) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- examples/app/package.json | 2 +- layers/package.json | 2 +- package-lock.json | 212 +++++++++++++++++----------------- packages/testing/package.json | 2 +- 4 files changed, 109 insertions(+), 109 deletions(-) diff --git a/examples/app/package.json b/examples/app/package.json index e6e590a119..71a7805251 100644 --- a/examples/app/package.json +++ b/examples/app/package.json @@ -51,7 +51,7 @@ "@types/node": "22.13.9", "aws-cdk": "^2.1002.0", "constructs": "^10.4.2", - "esbuild": "^0.25.0", + "esbuild": "^0.25.1", "typescript": "^5.7.3" } } diff --git a/layers/package.json b/layers/package.json index 319f82100d..7f96725e27 100644 --- a/layers/package.json +++ b/layers/package.json @@ -42,7 +42,7 @@ "dependencies": { "aws-cdk": "^2.1002.0", "aws-cdk-lib": "^2.181.1", - "esbuild": "^0.25.0", + "esbuild": "^0.25.1", "tsx": "^4.19.3" } } diff --git a/package-lock.json b/package-lock.json index 5616e455a0..fa3c6cd0d9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -65,7 +65,7 @@ "@types/node": "22.13.9", "aws-cdk": "^2.1002.0", "constructs": "^10.4.2", - "esbuild": "^0.25.0", + "esbuild": "^0.25.1", "typescript": "^5.7.3" }, "devDependencies": { @@ -110,7 +110,7 @@ "dependencies": { "aws-cdk": "^2.1002.0", "aws-cdk-lib": "^2.181.1", - "esbuild": "^0.25.0", + "esbuild": "^0.25.1", "tsx": "^4.19.3" }, "bin": { @@ -7177,9 +7177,9 @@ } }, "node_modules/@esbuild/aix-ppc64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.0.tgz", - "integrity": "sha512-O7vun9Sf8DFjH2UtqK8Ku3LkquL9SZL8OLY1T5NZkA34+wG3OQF7cl4Ql8vdNzM6fzBbYfLaiRLIOZ+2FOCgBQ==", + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.1.tgz", + "integrity": "sha512-kfYGy8IdzTGy+z0vFGvExZtxkFlA4zAxgKEahG9KE1ScBjpQnFsNOX8KTU5ojNru5ed5CVoJYXFtoxaq5nFbjQ==", "cpu": [ "ppc64" ], @@ -7193,9 +7193,9 @@ } }, "node_modules/@esbuild/android-arm": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.0.tgz", - "integrity": "sha512-PTyWCYYiU0+1eJKmw21lWtC+d08JDZPQ5g+kFyxP0V+es6VPPSUhM6zk8iImp2jbV6GwjX4pap0JFbUQN65X1g==", + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.1.tgz", + "integrity": "sha512-dp+MshLYux6j/JjdqVLnMglQlFu+MuVeNrmT5nk6q07wNhCdSnB7QZj+7G8VMUGh1q+vj2Bq8kRsuyA00I/k+Q==", "cpu": [ "arm" ], @@ -7209,9 +7209,9 @@ } }, "node_modules/@esbuild/android-arm64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.0.tgz", - "integrity": "sha512-grvv8WncGjDSyUBjN9yHXNt+cq0snxXbDxy5pJtzMKGmmpPxeAmAhWxXI+01lU5rwZomDgD3kJwulEnhTRUd6g==", + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.1.tgz", + "integrity": "sha512-50tM0zCJW5kGqgG7fQ7IHvQOcAn9TKiVRuQ/lN0xR+T2lzEFvAi1ZcS8DiksFcEpf1t/GYOeOfCAgDHFpkiSmA==", "cpu": [ "arm64" ], @@ -7225,9 +7225,9 @@ } }, "node_modules/@esbuild/android-x64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.0.tgz", - "integrity": "sha512-m/ix7SfKG5buCnxasr52+LI78SQ+wgdENi9CqyCXwjVR2X4Jkz+BpC3le3AoBPYTC9NHklwngVXvbJ9/Akhrfg==", + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.1.tgz", + "integrity": "sha512-GCj6WfUtNldqUzYkN/ITtlhwQqGWu9S45vUXs7EIYf+7rCiiqH9bCloatO9VhxsL0Pji+PF4Lz2XXCES+Q8hDw==", "cpu": [ "x64" ], @@ -7241,9 +7241,9 @@ } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.0.tgz", - "integrity": "sha512-mVwdUb5SRkPayVadIOI78K7aAnPamoeFR2bT5nszFUZ9P8UpK4ratOdYbZZXYSqPKMHfS1wdHCJk1P1EZpRdvw==", + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.1.tgz", + "integrity": "sha512-5hEZKPf+nQjYoSr/elb62U19/l1mZDdqidGfmFutVUjjUZrOazAtwK+Kr+3y0C/oeJfLlxo9fXb1w7L+P7E4FQ==", "cpu": [ "arm64" ], @@ -7257,9 +7257,9 @@ } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.0.tgz", - "integrity": "sha512-DgDaYsPWFTS4S3nWpFcMn/33ZZwAAeAFKNHNa1QN0rI4pUjgqf0f7ONmXf6d22tqTY+H9FNdgeaAa+YIFUn2Rg==", + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.1.tgz", + "integrity": "sha512-hxVnwL2Dqs3fM1IWq8Iezh0cX7ZGdVhbTfnOy5uURtao5OIVCEyj9xIzemDi7sRvKsuSdtCAhMKarxqtlyVyfA==", "cpu": [ "x64" ], @@ -7273,9 +7273,9 @@ } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.0.tgz", - "integrity": "sha512-VN4ocxy6dxefN1MepBx/iD1dH5K8qNtNe227I0mnTRjry8tj5MRk4zprLEdG8WPyAPb93/e4pSgi1SoHdgOa4w==", + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.1.tgz", + "integrity": "sha512-1MrCZs0fZa2g8E+FUo2ipw6jw5qqQiH+tERoS5fAfKnRx6NXH31tXBKI3VpmLijLH6yriMZsxJtaXUyFt/8Y4A==", "cpu": [ "arm64" ], @@ -7289,9 +7289,9 @@ } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.0.tgz", - "integrity": "sha512-mrSgt7lCh07FY+hDD1TxiTyIHyttn6vnjesnPoVDNmDfOmggTLXRv8Id5fNZey1gl/V2dyVK1VXXqVsQIiAk+A==", + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.1.tgz", + "integrity": "sha512-0IZWLiTyz7nm0xuIs0q1Y3QWJC52R8aSXxe40VUxm6BB1RNmkODtW6LHvWRrGiICulcX7ZvyH6h5fqdLu4gkww==", "cpu": [ "x64" ], @@ -7305,9 +7305,9 @@ } }, "node_modules/@esbuild/linux-arm": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.0.tgz", - "integrity": "sha512-vkB3IYj2IDo3g9xX7HqhPYxVkNQe8qTK55fraQyTzTX/fxaDtXiEnavv9geOsonh2Fd2RMB+i5cbhu2zMNWJwg==", + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.1.tgz", + "integrity": "sha512-NdKOhS4u7JhDKw9G3cY6sWqFcnLITn6SqivVArbzIaf3cemShqfLGHYMx8Xlm/lBit3/5d7kXvriTUGa5YViuQ==", "cpu": [ "arm" ], @@ -7321,9 +7321,9 @@ } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.0.tgz", - "integrity": "sha512-9QAQjTWNDM/Vk2bgBl17yWuZxZNQIF0OUUuPZRKoDtqF2k4EtYbpyiG5/Dk7nqeK6kIJWPYldkOcBqjXjrUlmg==", + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.1.tgz", + "integrity": "sha512-jaN3dHi0/DDPelk0nLcXRm1q7DNJpjXy7yWaWvbfkPvI+7XNSc/lDOnCLN7gzsyzgu6qSAmgSvP9oXAhP973uQ==", "cpu": [ "arm64" ], @@ -7337,9 +7337,9 @@ } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.0.tgz", - "integrity": "sha512-43ET5bHbphBegyeqLb7I1eYn2P/JYGNmzzdidq/w0T8E2SsYL1U6un2NFROFRg1JZLTzdCoRomg8Rvf9M6W6Gg==", + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.1.tgz", + "integrity": "sha512-OJykPaF4v8JidKNGz8c/q1lBO44sQNUQtq1KktJXdBLn1hPod5rE/Hko5ugKKZd+D2+o1a9MFGUEIUwO2YfgkQ==", "cpu": [ "ia32" ], @@ -7353,9 +7353,9 @@ } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.0.tgz", - "integrity": "sha512-fC95c/xyNFueMhClxJmeRIj2yrSMdDfmqJnyOY4ZqsALkDrrKJfIg5NTMSzVBr5YW1jf+l7/cndBfP3MSDpoHw==", + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.1.tgz", + "integrity": "sha512-nGfornQj4dzcq5Vp835oM/o21UMlXzn79KobKlcs3Wz9smwiifknLy4xDCLUU0BWp7b/houtdrgUz7nOGnfIYg==", "cpu": [ "loong64" ], @@ -7369,9 +7369,9 @@ } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.0.tgz", - "integrity": "sha512-nkAMFju7KDW73T1DdH7glcyIptm95a7Le8irTQNO/qtkoyypZAnjchQgooFUDQhNAy4iu08N79W4T4pMBwhPwQ==", + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.1.tgz", + "integrity": "sha512-1osBbPEFYwIE5IVB/0g2X6i1qInZa1aIoj1TdL4AaAb55xIIgbg8Doq6a5BzYWgr+tEcDzYH67XVnTmUzL+nXg==", "cpu": [ "mips64el" ], @@ -7385,9 +7385,9 @@ } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.0.tgz", - "integrity": "sha512-NhyOejdhRGS8Iwv+KKR2zTq2PpysF9XqY+Zk77vQHqNbo/PwZCzB5/h7VGuREZm1fixhs4Q/qWRSi5zmAiO4Fw==", + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.1.tgz", + "integrity": "sha512-/6VBJOwUf3TdTvJZ82qF3tbLuWsscd7/1w+D9LH0W/SqUgM5/JJD0lrJ1fVIfZsqB6RFmLCe0Xz3fmZc3WtyVg==", "cpu": [ "ppc64" ], @@ -7401,9 +7401,9 @@ } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.0.tgz", - "integrity": "sha512-5S/rbP5OY+GHLC5qXp1y/Mx//e92L1YDqkiBbO9TQOvuFXM+iDqUNG5XopAnXoRH3FjIUDkeGcY1cgNvnXp/kA==", + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.1.tgz", + "integrity": "sha512-nSut/Mx5gnilhcq2yIMLMe3Wl4FK5wx/o0QuuCLMtmJn+WeWYoEGDN1ipcN72g1WHsnIbxGXd4i/MF0gTcuAjQ==", "cpu": [ "riscv64" ], @@ -7417,9 +7417,9 @@ } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.0.tgz", - "integrity": "sha512-XM2BFsEBz0Fw37V0zU4CXfcfuACMrppsMFKdYY2WuTS3yi8O1nFOhil/xhKTmE1nPmVyvQJjJivgDT+xh8pXJA==", + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.1.tgz", + "integrity": "sha512-cEECeLlJNfT8kZHqLarDBQso9a27o2Zd2AQ8USAEoGtejOrCYHNtKP8XQhMDJMtthdF4GBmjR2au3x1udADQQQ==", "cpu": [ "s390x" ], @@ -7433,9 +7433,9 @@ } }, "node_modules/@esbuild/linux-x64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.0.tgz", - "integrity": "sha512-9yl91rHw/cpwMCNytUDxwj2XjFpxML0y9HAOH9pNVQDpQrBxHy01Dx+vaMu0N1CKa/RzBD2hB4u//nfc+Sd3Cw==", + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.1.tgz", + "integrity": "sha512-xbfUhu/gnvSEg+EGovRc+kjBAkrvtk38RlerAzQxvMzlB4fXpCFCeUAYzJvrnhFtdeyVCDANSjJvOvGYoeKzFA==", "cpu": [ "x64" ], @@ -7449,9 +7449,9 @@ } }, "node_modules/@esbuild/netbsd-arm64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.0.tgz", - "integrity": "sha512-RuG4PSMPFfrkH6UwCAqBzauBWTygTvb1nxWasEJooGSJ/NwRw7b2HOwyRTQIU97Hq37l3npXoZGYMy3b3xYvPw==", + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.1.tgz", + "integrity": "sha512-O96poM2XGhLtpTh+s4+nP7YCCAfb4tJNRVZHfIE7dgmax+yMP2WgMd2OecBuaATHKTHsLWHQeuaxMRnCsH8+5g==", "cpu": [ "arm64" ], @@ -7465,9 +7465,9 @@ } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.0.tgz", - "integrity": "sha512-jl+qisSB5jk01N5f7sPCsBENCOlPiS/xptD5yxOx2oqQfyourJwIKLRA2yqWdifj3owQZCL2sn6o08dBzZGQzA==", + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.1.tgz", + "integrity": "sha512-X53z6uXip6KFXBQ+Krbx25XHV/NCbzryM6ehOAeAil7X7oa4XIq+394PWGnwaSQ2WRA0KI6PUO6hTO5zeF5ijA==", "cpu": [ "x64" ], @@ -7481,9 +7481,9 @@ } }, "node_modules/@esbuild/openbsd-arm64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.0.tgz", - "integrity": "sha512-21sUNbq2r84YE+SJDfaQRvdgznTD8Xc0oc3p3iW/a1EVWeNj/SdUCbm5U0itZPQYRuRTW20fPMWMpcrciH2EJw==", + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.1.tgz", + "integrity": "sha512-Na9T3szbXezdzM/Kfs3GcRQNjHzM6GzFBeU1/6IV/npKP5ORtp9zbQjvkDJ47s6BCgaAZnnnu/cY1x342+MvZg==", "cpu": [ "arm64" ], @@ -7497,9 +7497,9 @@ } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.0.tgz", - "integrity": "sha512-2gwwriSMPcCFRlPlKx3zLQhfN/2WjJ2NSlg5TKLQOJdV0mSxIcYNTMhk3H3ulL/cak+Xj0lY1Ym9ysDV1igceg==", + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.1.tgz", + "integrity": "sha512-T3H78X2h1tszfRSf+txbt5aOp/e7TAz3ptVKu9Oyir3IAOFPGV6O9c2naym5TOriy1l0nNf6a4X5UXRZSGX/dw==", "cpu": [ "x64" ], @@ -7513,9 +7513,9 @@ } }, "node_modules/@esbuild/sunos-x64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.0.tgz", - "integrity": "sha512-bxI7ThgLzPrPz484/S9jLlvUAHYMzy6I0XiU1ZMeAEOBcS0VePBFxh1JjTQt3Xiat5b6Oh4x7UC7IwKQKIJRIg==", + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.1.tgz", + "integrity": "sha512-2H3RUvcmULO7dIE5EWJH8eubZAI4xw54H1ilJnRNZdeo8dTADEZ21w6J22XBkXqGJbe0+wnNJtw3UXRoLJnFEg==", "cpu": [ "x64" ], @@ -7529,9 +7529,9 @@ } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.0.tgz", - "integrity": "sha512-ZUAc2YK6JW89xTbXvftxdnYy3m4iHIkDtK3CLce8wg8M2L+YZhIvO1DKpxrd0Yr59AeNNkTiic9YLf6FTtXWMw==", + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.1.tgz", + "integrity": "sha512-GE7XvrdOzrb+yVKB9KsRMq+7a2U/K5Cf/8grVFRAGJmfADr/e/ODQ134RK2/eeHqYV5eQRFxb1hY7Nr15fv1NQ==", "cpu": [ "arm64" ], @@ -7545,9 +7545,9 @@ } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.0.tgz", - "integrity": "sha512-eSNxISBu8XweVEWG31/JzjkIGbGIJN/TrRoiSVZwZ6pkC6VX4Im/WV2cz559/TXLcYbcrDN8JtKgd9DJVIo8GA==", + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.1.tgz", + "integrity": "sha512-uOxSJCIcavSiT6UnBhBzE8wy3n0hOkJsBOzy7HDAuTDE++1DJMRRVCPGisULScHL+a/ZwdXPpXD3IyFKjA7K8A==", "cpu": [ "ia32" ], @@ -7561,9 +7561,9 @@ } }, "node_modules/@esbuild/win32-x64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.0.tgz", - "integrity": "sha512-ZENoHJBxA20C2zFzh6AI4fT6RraMzjYw4xKWemRTRmRVtN9c5DcH9r/f2ihEkMjOW5eGgrwCslG/+Y/3bL+DHQ==", + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.1.tgz", + "integrity": "sha512-Y1EQdcfwMSeQN/ujR5VayLOJ1BHaK+ssyk0AEzPjC+t1lITgsnccPqFjb6V+LsTp/9Iov4ysfjxLaGJ9RPtkVg==", "cpu": [ "x64" ], @@ -12947,9 +12947,9 @@ "license": "MIT" }, "node_modules/esbuild": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.0.tgz", - "integrity": "sha512-BXq5mqc8ltbaN34cDqWuYKyNhX8D/Z0J1xdtdQ8UcIIIyJyz+ZMKUt58tF3SrZ85jcfN/PZYhjR5uDQAYNVbuw==", + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.1.tgz", + "integrity": "sha512-BGO5LtrGC7vxnqucAe/rmvKdJllfGaYWdyABvyMoXQlfYMb2bbRuReWR5tEGE//4LcNJj9XrkovTqNYRFZHAMQ==", "hasInstallScript": true, "license": "MIT", "bin": { @@ -12959,31 +12959,31 @@ "node": ">=18" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.25.0", - "@esbuild/android-arm": "0.25.0", - "@esbuild/android-arm64": "0.25.0", - "@esbuild/android-x64": "0.25.0", - "@esbuild/darwin-arm64": "0.25.0", - "@esbuild/darwin-x64": "0.25.0", - "@esbuild/freebsd-arm64": "0.25.0", - "@esbuild/freebsd-x64": "0.25.0", - "@esbuild/linux-arm": "0.25.0", - "@esbuild/linux-arm64": "0.25.0", - "@esbuild/linux-ia32": "0.25.0", - "@esbuild/linux-loong64": "0.25.0", - "@esbuild/linux-mips64el": "0.25.0", - "@esbuild/linux-ppc64": "0.25.0", - "@esbuild/linux-riscv64": "0.25.0", - "@esbuild/linux-s390x": "0.25.0", - "@esbuild/linux-x64": "0.25.0", - "@esbuild/netbsd-arm64": "0.25.0", - "@esbuild/netbsd-x64": "0.25.0", - "@esbuild/openbsd-arm64": "0.25.0", - "@esbuild/openbsd-x64": "0.25.0", - "@esbuild/sunos-x64": "0.25.0", - "@esbuild/win32-arm64": "0.25.0", - "@esbuild/win32-ia32": "0.25.0", - "@esbuild/win32-x64": "0.25.0" + "@esbuild/aix-ppc64": "0.25.1", + "@esbuild/android-arm": "0.25.1", + "@esbuild/android-arm64": "0.25.1", + "@esbuild/android-x64": "0.25.1", + "@esbuild/darwin-arm64": "0.25.1", + "@esbuild/darwin-x64": "0.25.1", + "@esbuild/freebsd-arm64": "0.25.1", + "@esbuild/freebsd-x64": "0.25.1", + "@esbuild/linux-arm": "0.25.1", + "@esbuild/linux-arm64": "0.25.1", + "@esbuild/linux-ia32": "0.25.1", + "@esbuild/linux-loong64": "0.25.1", + "@esbuild/linux-mips64el": "0.25.1", + "@esbuild/linux-ppc64": "0.25.1", + "@esbuild/linux-riscv64": "0.25.1", + "@esbuild/linux-s390x": "0.25.1", + "@esbuild/linux-x64": "0.25.1", + "@esbuild/netbsd-arm64": "0.25.1", + "@esbuild/netbsd-x64": "0.25.1", + "@esbuild/openbsd-arm64": "0.25.1", + "@esbuild/openbsd-x64": "0.25.1", + "@esbuild/sunos-x64": "0.25.1", + "@esbuild/win32-arm64": "0.25.1", + "@esbuild/win32-ia32": "0.25.1", + "@esbuild/win32-x64": "0.25.1" } }, "node_modules/escalade": { @@ -21618,7 +21618,7 @@ "@aws-sdk/client-lambda": "^3.758.0", "@smithy/util-utf8": "^4.0.0", "aws-cdk-lib": "^2.181.1", - "esbuild": "^0.25.0", + "esbuild": "^0.25.1", "promise-retry": "^2.0.1" }, "devDependencies": { diff --git a/packages/testing/package.json b/packages/testing/package.json index 640cf4ae71..a699cc3e8b 100644 --- a/packages/testing/package.json +++ b/packages/testing/package.json @@ -101,7 +101,7 @@ "@aws-sdk/client-lambda": "^3.758.0", "@smithy/util-utf8": "^4.0.0", "aws-cdk-lib": "^2.181.1", - "esbuild": "^0.25.0", + "esbuild": "^0.25.1", "promise-retry": "^2.0.1" }, "devDependencies": { From dc870f85487a7d487dfd5b98ef6074501fedb03e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 12 Mar 2025 18:43:31 +0100 Subject: [PATCH 08/56] chore(deps): bump the aws-cdk group across 1 directory with 3 updates (#3699) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- examples/app/package.json | 4 +- layers/package.json | 4 +- package-lock.json | 196 +++++++++++++++++++--------------- packages/testing/package.json | 4 +- 4 files changed, 113 insertions(+), 95 deletions(-) diff --git a/examples/app/package.json b/examples/app/package.json index 71a7805251..c43dabdb70 100644 --- a/examples/app/package.json +++ b/examples/app/package.json @@ -30,7 +30,7 @@ "devDependencies": { "@types/aws-lambda": "^8.10.147", "@types/node": "22.13.9", - "aws-cdk-lib": "^2.181.1", + "aws-cdk-lib": "^2.183.0", "constructs": "^10.4.2", "source-map-support": "^0.5.21", "tsx": "^4.19.3", @@ -49,7 +49,7 @@ "@middy/core": "^4.7.0", "@types/aws-lambda": "^8.10.147", "@types/node": "22.13.9", - "aws-cdk": "^2.1002.0", + "aws-cdk": "^2.1003.0", "constructs": "^10.4.2", "esbuild": "^0.25.1", "typescript": "^5.7.3" diff --git a/layers/package.json b/layers/package.json index 7f96725e27..a6380c4495 100644 --- a/layers/package.json +++ b/layers/package.json @@ -40,8 +40,8 @@ "source-map-support": "^0.5.21" }, "dependencies": { - "aws-cdk": "^2.1002.0", - "aws-cdk-lib": "^2.181.1", + "aws-cdk": "^2.1003.0", + "aws-cdk-lib": "^2.183.0", "esbuild": "^0.25.1", "tsx": "^4.19.3" } diff --git a/package-lock.json b/package-lock.json index fa3c6cd0d9..bd574a0ad6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -63,7 +63,7 @@ "@middy/core": "^4.7.0", "@types/aws-lambda": "^8.10.147", "@types/node": "22.13.9", - "aws-cdk": "^2.1002.0", + "aws-cdk": "^2.1003.0", "constructs": "^10.4.2", "esbuild": "^0.25.1", "typescript": "^5.7.3" @@ -71,7 +71,7 @@ "devDependencies": { "@types/aws-lambda": "^8.10.147", "@types/node": "22.13.9", - "aws-cdk-lib": "^2.181.1", + "aws-cdk-lib": "^2.183.0", "constructs": "^10.4.2", "source-map-support": "^0.5.21", "tsx": "^4.19.3", @@ -108,8 +108,8 @@ "version": "2.16.0", "license": "MIT-0", "dependencies": { - "aws-cdk": "^2.1002.0", - "aws-cdk-lib": "^2.181.1", + "aws-cdk": "^2.1003.0", + "aws-cdk-lib": "^2.183.0", "esbuild": "^0.25.1", "tsx": "^4.19.3" }, @@ -164,9 +164,9 @@ } }, "node_modules/@aws-cdk/cloud-assembly-schema": { - "version": "39.2.7", - "resolved": "https://registry.npmjs.org/@aws-cdk/cloud-assembly-schema/-/cloud-assembly-schema-39.2.7.tgz", - "integrity": "sha512-aZWc9dxnar5S9PheEp6f7F5Q3GGkft+cm8wypbTuIkqUjU6yn21oQzOWTikhBnNKf1vdaoYbjAqhBOlfoqaH+w==", + "version": "40.7.0", + "resolved": "https://registry.npmjs.org/@aws-cdk/cloud-assembly-schema/-/cloud-assembly-schema-40.7.0.tgz", + "integrity": "sha512-00wVKn9pOOGXbeNwA4E8FUFt0zIB4PmSO7PvIiDWgpaFX3G/sWyy0A3s6bg/n2Yvkghu8r4a8ckm+mAzkAYmfA==", "bundleDependencies": [ "jsonschema", "semver" @@ -174,7 +174,10 @@ "license": "Apache-2.0", "dependencies": { "jsonschema": "~1.4.1", - "semver": "^7.6.3" + "semver": "^7.7.1" + }, + "engines": { + "node": ">= 14.15.0" } }, "node_modules/@aws-cdk/cloud-assembly-schema/node_modules/jsonschema": { @@ -186,7 +189,7 @@ } }, "node_modules/@aws-cdk/cloud-assembly-schema/node_modules/semver": { - "version": "7.6.3", + "version": "7.7.1", "inBundle": true, "license": "ISC", "bin": { @@ -214,39 +217,10 @@ "node": ">= 14.15.0" } }, - "node_modules/@aws-cdk/cx-api": { - "version": "2.181.1", - "resolved": "https://registry.npmjs.org/@aws-cdk/cx-api/-/cx-api-2.181.1.tgz", - "integrity": "sha512-1uFbmLxP04K5W8pqbIqwrx8V87JtSPeO1xe57NRddUcJCPdGQrnXByD7jq+amiFcJ2NyKH6C5gV3gp3pMdJs6w==", - "bundleDependencies": [ - "semver" - ], - "license": "Apache-2.0", - "dependencies": { - "semver": "^7.6.3" - }, - "engines": { - "node": ">= 14.15.0" - }, - "peerDependencies": { - "@aws-cdk/cloud-assembly-schema": "^39.2.0" - } - }, - "node_modules/@aws-cdk/cx-api/node_modules/semver": { - "version": "7.6.3", - "inBundle": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/@aws-cdk/region-info": { - "version": "2.181.0", - "resolved": "https://registry.npmjs.org/@aws-cdk/region-info/-/region-info-2.181.0.tgz", - "integrity": "sha512-3hzW9cy/7PG+DTg7OUB31m5w17cZI/vUmvWz+CfLL9o85eMDJbsnxc+YckcxKRfxINRLPC2ISVyqCdQPWyPHhA==", + "version": "2.183.0", + "resolved": "https://registry.npmjs.org/@aws-cdk/region-info/-/region-info-2.183.0.tgz", + "integrity": "sha512-D79pFpPO3YBLd8a4N7XvYa5CYwLegycZGNr26uJc7Sr7fH1N/4cISuA/8df9LcqD1M+nTbP3sgDuLWbv6kap6g==", "license": "Apache-2.0", "engines": { "node": ">= 14.15.0" @@ -262,15 +236,15 @@ } }, "node_modules/@aws-cdk/toolkit-lib": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@aws-cdk/toolkit-lib/-/toolkit-lib-0.1.3.tgz", - "integrity": "sha512-EBl+czCQXJW9YWOH4LhnDbPQAhda2X/1Z+uVoW3KNmKLFidBrP2y1uCRXMBxEMCCzjXfun8hnoTtEr0p6MdvVA==", + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/@aws-cdk/toolkit-lib/-/toolkit-lib-0.1.4.tgz", + "integrity": "sha512-i+LWGu9st+bDPQmKG2ml+xqICLnhXhDQLYBb1m1qKp8GaMyPd7r3mYkTakX5StPVhrUgb4Tsu/zH0qjSCOYvoA==", "license": "Apache-2.0", "dependencies": { - "@aws-cdk/cloud-assembly-schema": "^40.7.0", + "@aws-cdk/cloud-assembly-schema": "^41.0.0", "@aws-cdk/cloudformation-diff": "^2.179.0", - "@aws-cdk/cx-api": "^2.180.0", - "@aws-cdk/region-info": "^2.180.0", + "@aws-cdk/cx-api": "^2.181.1", + "@aws-cdk/region-info": "^2.181.1", "@aws-sdk/client-appsync": "^3", "@aws-sdk/client-cloudcontrol": "^3", "@aws-sdk/client-cloudformation": "^3", @@ -292,7 +266,6 @@ "@aws-sdk/credential-providers": "^3", "@aws-sdk/ec2-metadata-service": "^3", "@aws-sdk/lib-storage": "^3", - "@jsii/check-node": "^1.108.0", "@smithy/middleware-endpoint": "^4.0.6", "@smithy/node-http-handler": "^4.0.3", "@smithy/property-provider": "^4.0.1", @@ -302,8 +275,8 @@ "@smithy/util-waiter": "^4.0.2", "archiver": "^7.0.1", "camelcase": "^6", - "cdk-assets": "^3.0.0", - "cdk-from-cfn": "^0.191.0", + "cdk-assets": "^3.1.0", + "cdk-from-cfn": "^0.193.0", "chalk": "^4", "chokidar": "^3", "decamelize": "^5", @@ -328,9 +301,9 @@ } }, "node_modules/@aws-cdk/toolkit-lib/node_modules/@aws-cdk/cloud-assembly-schema": { - "version": "40.7.0", - "resolved": "https://registry.npmjs.org/@aws-cdk/cloud-assembly-schema/-/cloud-assembly-schema-40.7.0.tgz", - "integrity": "sha512-00wVKn9pOOGXbeNwA4E8FUFt0zIB4PmSO7PvIiDWgpaFX3G/sWyy0A3s6bg/n2Yvkghu8r4a8ckm+mAzkAYmfA==", + "version": "41.0.0", + "resolved": "https://registry.npmjs.org/@aws-cdk/cloud-assembly-schema/-/cloud-assembly-schema-41.0.0.tgz", + "integrity": "sha512-Jgs3gelFN0Ghr5tbAhPxRsf78jKLGrMbUno4nXTGz3QiPkFqfrq0kodxmKP/IVSp55A5I3CsJ5QErQTit39GdA==", "bundleDependencies": [ "jsonschema", "semver" @@ -363,6 +336,35 @@ "node": ">=10" } }, + "node_modules/@aws-cdk/toolkit-lib/node_modules/@aws-cdk/cx-api": { + "version": "2.183.0", + "resolved": "https://registry.npmjs.org/@aws-cdk/cx-api/-/cx-api-2.183.0.tgz", + "integrity": "sha512-14HcLwL/lPNnBdSfpFK0C6XSkgBv/35lgyzNPsmghSHmUX8OKlv5or1HFLAL2E7Jhp5b8KHsTxw3o8IoeU3tHw==", + "bundleDependencies": [ + "semver" + ], + "license": "Apache-2.0", + "dependencies": { + "semver": "^7.6.3" + }, + "engines": { + "node": ">= 14.15.0" + }, + "peerDependencies": { + "@aws-cdk/cloud-assembly-schema": "^40.6.0" + } + }, + "node_modules/@aws-cdk/toolkit-lib/node_modules/@aws-cdk/cx-api/node_modules/semver": { + "version": "7.6.3", + "inBundle": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/@aws-cdk/toolkit-lib/node_modules/camelcase": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", @@ -3388,9 +3390,9 @@ } }, "node_modules/@aws-sdk/client-ecr": { - "version": "3.758.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-ecr/-/client-ecr-3.758.0.tgz", - "integrity": "sha512-9nTE01CuK5Vq0kPkmw3xdE6lrPDZSXOlX4wRc194GhnhxdppRla5dG6+gvZWTmpkC9a2mGqjXYsbvoSg6kZPHg==", + "version": "3.766.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-ecr/-/client-ecr-3.766.0.tgz", + "integrity": "sha512-hW4CtlS22Wu6hs2BlkqtZdpzMtwCyb5k4VetSrchLLmiq+jPopPh0NGqp42OgqUYDJGqPJZF2LJaL/k/UtacPg==", "license": "Apache-2.0", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", @@ -7763,19 +7765,6 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, - "node_modules/@jsii/check-node": { - "version": "1.108.0", - "resolved": "https://registry.npmjs.org/@jsii/check-node/-/check-node-1.108.0.tgz", - "integrity": "sha512-wa8AGH31Cl0x1jU/KtM6JB32IurBmK1YiX5ZnCndifRCehLnS8DmJCPYrzJbKD4xqmHigaq6696fAnM/L7qIsw==", - "license": "Apache-2.0", - "dependencies": { - "chalk": "^4.1.2", - "semver": "^7.6.3" - }, - "engines": { - "node": ">= 14.17.0" - } - }, "node_modules/@lerna/create": { "version": "8.1.2", "resolved": "https://registry.npmjs.org/@lerna/create/-/create-8.1.2.tgz", @@ -10772,9 +10761,9 @@ } }, "node_modules/aws-cdk": { - "version": "2.1002.0", - "resolved": "https://registry.npmjs.org/aws-cdk/-/aws-cdk-2.1002.0.tgz", - "integrity": "sha512-2lq1ho1Rq/sDMTieA6zna9aogk3qHM3Oq/mF7QCx2Jj0+e8/ZJOJW+5xU9oUBclRpUIxfUevC93H3eCSr1VW6g==", + "version": "2.1003.0", + "resolved": "https://registry.npmjs.org/aws-cdk/-/aws-cdk-2.1003.0.tgz", + "integrity": "sha512-FORPDGW8oUg4tXFlhX+lv/j+152LO9wwi3/CwNr1WY3c3HwJUtc0fZGb2B3+Fzy6NhLWGHJclUsJPEhjEt8Nhg==", "license": "Apache-2.0", "bin": { "cdk": "bin/cdk" @@ -10787,9 +10776,9 @@ } }, "node_modules/aws-cdk-lib": { - "version": "2.181.1", - "resolved": "https://registry.npmjs.org/aws-cdk-lib/-/aws-cdk-lib-2.181.1.tgz", - "integrity": "sha512-PDxYiqzet17tigJ8icjzoZIzmcdusQfKNnwpRzcGu5//n3YqlKf/vGEkQuU0xcgt4lBMX4Yjuqfsl8wYidCESw==", + "version": "2.183.0", + "resolved": "https://registry.npmjs.org/aws-cdk-lib/-/aws-cdk-lib-2.183.0.tgz", + "integrity": "sha512-xwdDMm7qKBgN+dRjn8XxwS0YDRFM9JnUavFWM2bzaOzFeaBCiwFMrG0xLZaZs6GBImV804/jj8PnjmbOCsDZdw==", "bundleDependencies": [ "@balena/dockerignore", "case", @@ -10807,7 +10796,7 @@ "dependencies": { "@aws-cdk/asset-awscli-v1": "^2.2.208", "@aws-cdk/asset-node-proxy-agent-v6": "^2.1.0", - "@aws-cdk/cloud-assembly-schema": "^39.2.0", + "@aws-cdk/cloud-assembly-schema": "^40.6.0", "@balena/dockerignore": "^1.0.2", "case": "1.6.3", "fs-extra": "^11.2.0", @@ -11518,13 +11507,13 @@ } }, "node_modules/cdk-assets": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cdk-assets/-/cdk-assets-3.0.0.tgz", - "integrity": "sha512-bYcIwAFwkkjB+DR/aFTC3HhkvurLZFokbzdLbbs8w/hmtAl0PUzQpD9bckDTbwzUvHo6QZYA4jn/gVkL6Yvf8Q==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cdk-assets/-/cdk-assets-3.1.0.tgz", + "integrity": "sha512-4xO5mRzdxqTxiar7+Y8qOy/yWoY1yaW8y3XrhBsSiwhldRuDbXYkn4O1HmCV35i+ietS2nUnRQ+zYucdF/6A5Q==", "license": "Apache-2.0", "dependencies": { - "@aws-cdk/cloud-assembly-schema": "^40.7.0", - "@aws-cdk/cx-api": "^2.180.0", + "@aws-cdk/cloud-assembly-schema": "^41.0.0", + "@aws-cdk/cx-api": "^2.181.1", "@aws-sdk/client-ecr": "^3", "@aws-sdk/client-s3": "^3", "@aws-sdk/client-secrets-manager": "^3", @@ -11547,9 +11536,9 @@ } }, "node_modules/cdk-assets/node_modules/@aws-cdk/cloud-assembly-schema": { - "version": "40.7.0", - "resolved": "https://registry.npmjs.org/@aws-cdk/cloud-assembly-schema/-/cloud-assembly-schema-40.7.0.tgz", - "integrity": "sha512-00wVKn9pOOGXbeNwA4E8FUFt0zIB4PmSO7PvIiDWgpaFX3G/sWyy0A3s6bg/n2Yvkghu8r4a8ckm+mAzkAYmfA==", + "version": "41.0.0", + "resolved": "https://registry.npmjs.org/@aws-cdk/cloud-assembly-schema/-/cloud-assembly-schema-41.0.0.tgz", + "integrity": "sha512-Jgs3gelFN0Ghr5tbAhPxRsf78jKLGrMbUno4nXTGz3QiPkFqfrq0kodxmKP/IVSp55A5I3CsJ5QErQTit39GdA==", "bundleDependencies": [ "jsonschema", "semver" @@ -11582,6 +11571,35 @@ "node": ">=10" } }, + "node_modules/cdk-assets/node_modules/@aws-cdk/cx-api": { + "version": "2.183.0", + "resolved": "https://registry.npmjs.org/@aws-cdk/cx-api/-/cx-api-2.183.0.tgz", + "integrity": "sha512-14HcLwL/lPNnBdSfpFK0C6XSkgBv/35lgyzNPsmghSHmUX8OKlv5or1HFLAL2E7Jhp5b8KHsTxw3o8IoeU3tHw==", + "bundleDependencies": [ + "semver" + ], + "license": "Apache-2.0", + "dependencies": { + "semver": "^7.6.3" + }, + "engines": { + "node": ">= 14.15.0" + }, + "peerDependencies": { + "@aws-cdk/cloud-assembly-schema": "^40.6.0" + } + }, + "node_modules/cdk-assets/node_modules/@aws-cdk/cx-api/node_modules/semver": { + "version": "7.6.3", + "inBundle": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/cdk-assets/node_modules/glob": { "version": "11.0.1", "resolved": "https://registry.npmjs.org/glob/-/glob-11.0.1.tgz", @@ -11661,9 +11679,9 @@ } }, "node_modules/cdk-from-cfn": { - "version": "0.191.0", - "resolved": "https://registry.npmjs.org/cdk-from-cfn/-/cdk-from-cfn-0.191.0.tgz", - "integrity": "sha512-j+TKUSmje5iSiOQzWstH/BkrsL8L9WV57zXll+BHlGT8w5wTrou4dZvNvFQWELW9aaS+UBX0ivsJRZwuO7GiIw==", + "version": "0.193.0", + "resolved": "https://registry.npmjs.org/cdk-from-cfn/-/cdk-from-cfn-0.193.0.tgz", + "integrity": "sha512-LBKqAnsg12RRhyz+zyByI3H6REiDVNm1vofhdnEXSAIGIBuO0H/cw4mbCpz0Qr9huZYssF9ozGsbwa1K3RF2Tg==", "license": "MIT OR Apache-2.0" }, "node_modules/chai": { @@ -21614,10 +21632,10 @@ "version": "2.16.0", "license": "MIT-0", "dependencies": { - "@aws-cdk/toolkit-lib": "^0.1.3", + "@aws-cdk/toolkit-lib": "^0.1.4", "@aws-sdk/client-lambda": "^3.758.0", "@smithy/util-utf8": "^4.0.0", - "aws-cdk-lib": "^2.181.1", + "aws-cdk-lib": "^2.183.0", "esbuild": "^0.25.1", "promise-retry": "^2.0.1" }, diff --git a/packages/testing/package.json b/packages/testing/package.json index a699cc3e8b..df637496af 100644 --- a/packages/testing/package.json +++ b/packages/testing/package.json @@ -97,10 +97,10 @@ }, "homepage": "https://github.com/aws-powertools/powertools-lambda-typescript/tree/main/packages/testing#readme", "dependencies": { - "@aws-cdk/toolkit-lib": "^0.1.3", + "@aws-cdk/toolkit-lib": "^0.1.4", "@aws-sdk/client-lambda": "^3.758.0", "@smithy/util-utf8": "^4.0.0", - "aws-cdk-lib": "^2.181.1", + "aws-cdk-lib": "^2.183.0", "esbuild": "^0.25.1", "promise-retry": "^2.0.1" }, From b84d6c7578ba72e1190862f8593c9f7e7910f7eb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 12 Mar 2025 18:51:11 +0100 Subject: [PATCH 09/56] chore(deps): bump @types/node from 22.13.9 to 22.13.10 (#3706) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- examples/app/package.json | 4 ++-- package-lock.json | 12 ++++++------ package.json | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/examples/app/package.json b/examples/app/package.json index c43dabdb70..99876652d2 100644 --- a/examples/app/package.json +++ b/examples/app/package.json @@ -29,7 +29,7 @@ }, "devDependencies": { "@types/aws-lambda": "^8.10.147", - "@types/node": "22.13.9", + "@types/node": "22.13.10", "aws-cdk-lib": "^2.183.0", "constructs": "^10.4.2", "source-map-support": "^0.5.21", @@ -48,7 +48,7 @@ "@aws-sdk/lib-dynamodb": "^3.758.0", "@middy/core": "^4.7.0", "@types/aws-lambda": "^8.10.147", - "@types/node": "22.13.9", + "@types/node": "22.13.10", "aws-cdk": "^2.1003.0", "constructs": "^10.4.2", "esbuild": "^0.25.1", diff --git a/package-lock.json b/package-lock.json index bd574a0ad6..57afce102e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -28,7 +28,7 @@ "devDependencies": { "@biomejs/biome": "^1.9.4", "@types/aws-lambda": "^8.10.147", - "@types/node": "^22.13.9", + "@types/node": "^22.13.10", "@vitest/coverage-v8": "^3.0.8", "husky": "^9.1.7", "lerna": "8.1.2", @@ -62,7 +62,7 @@ "@aws-sdk/lib-dynamodb": "^3.758.0", "@middy/core": "^4.7.0", "@types/aws-lambda": "^8.10.147", - "@types/node": "22.13.9", + "@types/node": "22.13.10", "aws-cdk": "^2.1003.0", "constructs": "^10.4.2", "esbuild": "^0.25.1", @@ -70,7 +70,7 @@ }, "devDependencies": { "@types/aws-lambda": "^8.10.147", - "@types/node": "22.13.9", + "@types/node": "22.13.10", "aws-cdk-lib": "^2.183.0", "constructs": "^10.4.2", "source-map-support": "^0.5.21", @@ -10023,9 +10023,9 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "22.13.9", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.13.9.tgz", - "integrity": "sha512-acBjXdRJ3A6Pb3tqnw9HZmyR3Fiol3aGxRCK1x3d+6CDAMjl7I649wpSd+yNURCjbOUGu9tqtLKnTGxmK6CyGw==", + "version": "22.13.10", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.13.10.tgz", + "integrity": "sha512-I6LPUvlRH+O6VRUqYOcMudhaIdUVWfsjnZavnsraHvpBwaEyMN29ry+0UVJhImYL16xsscu0aske3yA+uPOWfw==", "license": "MIT", "dependencies": { "undici-types": "~6.20.0" diff --git a/package.json b/package.json index 255ae14623..4a5a4140c1 100644 --- a/package.json +++ b/package.json @@ -52,7 +52,7 @@ "devDependencies": { "@biomejs/biome": "^1.9.4", "@types/aws-lambda": "^8.10.147", - "@types/node": "^22.13.9", + "@types/node": "^22.13.10", "@vitest/coverage-v8": "^3.0.8", "husky": "^9.1.7", "lerna": "8.1.2", From da2f315babc593ebed2953f79f154286eb49259e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 12 Mar 2025 18:57:53 +0100 Subject: [PATCH 10/56] chore(deps): bump github/codeql-action from 3.28.10 to 3.28.11 (#3708) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Andrea Amorosi --- .github/workflows/ossf_scorecard.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ossf_scorecard.yml b/.github/workflows/ossf_scorecard.yml index 2fc25f122f..4d2b817922 100644 --- a/.github/workflows/ossf_scorecard.yml +++ b/.github/workflows/ossf_scorecard.yml @@ -43,6 +43,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@b56ba49b26e50535fa1e7f7db0f4f7b4bf65d80d # v3.28.10 + uses: github/codeql-action/upload-sarif@6bb031afdd8eb862ea3fc1848194185e076637e5 # v3.28.11 with: sarif_file: results.sarif From 16208c2dbe46c72b65a9b5c2124af736f44032a3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 13 Mar 2025 09:23:11 +0100 Subject: [PATCH 11/56] chore(deps): bump the typescript group across 1 directory with 2 updates (#3688) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Andrea Amorosi --- examples/app/package.json | 4 ++-- package-lock.json | 23 ++++++++++++----------- package.json | 4 ++-- 3 files changed, 16 insertions(+), 15 deletions(-) diff --git a/examples/app/package.json b/examples/app/package.json index 99876652d2..42cfba83d1 100644 --- a/examples/app/package.json +++ b/examples/app/package.json @@ -34,7 +34,7 @@ "constructs": "^10.4.2", "source-map-support": "^0.5.21", "tsx": "^4.19.3", - "typescript": "^5.7.3", + "typescript": "^5.8.2", "vitest": "^3.0.5" }, "dependencies": { @@ -52,6 +52,6 @@ "aws-cdk": "^2.1003.0", "constructs": "^10.4.2", "esbuild": "^0.25.1", - "typescript": "^5.7.3" + "typescript": "^5.8.2" } } diff --git a/package-lock.json b/package-lock.json index 57afce102e..2b34c4fa10 100644 --- a/package-lock.json +++ b/package-lock.json @@ -39,8 +39,8 @@ "middy6": "npm:@middy/core@^6.0.0", "typedoc": "^0.27.9", "typedoc-plugin-missing-exports": "^3.1.0", - "typedoc-plugin-zod": "^1.3.1", - "typescript": "^5.7.3", + "typedoc-plugin-zod": "^1.4.0", + "typescript": "^5.8.2", "vitest": "^3.0.5" }, "engines": { @@ -66,7 +66,7 @@ "aws-cdk": "^2.1003.0", "constructs": "^10.4.2", "esbuild": "^0.25.1", - "typescript": "^5.7.3" + "typescript": "^5.8.2" }, "devDependencies": { "@types/aws-lambda": "^8.10.147", @@ -75,7 +75,7 @@ "constructs": "^10.4.2", "source-map-support": "^0.5.21", "tsx": "^4.19.3", - "typescript": "^5.7.3", + "typescript": "^5.8.2", "vitest": "^3.0.5" } }, @@ -20682,12 +20682,13 @@ } }, "node_modules/typedoc-plugin-zod": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/typedoc-plugin-zod/-/typedoc-plugin-zod-1.3.1.tgz", - "integrity": "sha512-u4NH1Ez168gRNnhUd0x4pZhp85maJ9y050IxSok9XwdzTpUA9NN0ee3ho8ssrzmxsvO2UDbDEiks7xtI0p6UXA==", + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/typedoc-plugin-zod/-/typedoc-plugin-zod-1.4.0.tgz", + "integrity": "sha512-Mr4hoEfjIR1xjp0RqtEyfba03NDUE4jLvgErg0VQz9L60eCVLcUrV0x+71+B7rykDMexrTx0I9Yk6SS0PuSbKw==", "dev": true, + "license": "MIT", "peerDependencies": { - "typedoc": "0.23.x || 0.24.x || 0.25.x || 0.26.x || 0.27.x" + "typedoc": "0.23.x || 0.24.x || 0.25.x || 0.26.x || 0.27.x || 0.28.x" } }, "node_modules/typedoc/node_modules/minimatch": { @@ -20706,9 +20707,9 @@ } }, "node_modules/typescript": { - "version": "5.7.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.3.tgz", - "integrity": "sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==", + "version": "5.8.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.2.tgz", + "integrity": "sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ==", "dev": true, "license": "Apache-2.0", "bin": { diff --git a/package.json b/package.json index 4a5a4140c1..2c4877e3ca 100644 --- a/package.json +++ b/package.json @@ -63,8 +63,8 @@ "middy6": "npm:@middy/core@^6.0.0", "typedoc": "^0.27.9", "typedoc-plugin-missing-exports": "^3.1.0", - "typedoc-plugin-zod": "^1.3.1", - "typescript": "^5.7.3", + "typedoc-plugin-zod": "^1.4.0", + "typescript": "^5.8.2", "vitest": "^3.0.5" }, "lint-staged": { From 4f8b15a897b4bf7429c42524135cf7d86c70f7ec Mon Sep 17 00:00:00 2001 From: Andrea Amorosi Date: Thu, 13 Mar 2025 09:40:29 +0100 Subject: [PATCH 12/56] docs(validation): add main docs page (#3717) --- docs/utilities/validation.md | 582 ++---------------- .../{validation => event-handler}/.gitignore | 0 .../validation/advancedBringAjvInstance.ts | 30 + .../validation/advancedCustomFormats.ts | 43 ++ .../validation/advancedExternalRefs.ts | 25 + .../validation/gettingStartedDecorator.ts | 27 + .../validation/gettingStartedEnvelope.ts | 19 + .../gettingStartedEnvelopeBuiltin.ts | 20 + .../validation/gettingStartedMiddy.ts | 22 + .../validation/gettingStartedStandalone.ts | 26 + .../samples/gettingStartedEnvelopeEvent.json | 13 + .../gettingStartedSQSEnvelopeEvent.json | 36 ++ .../samples/schemaWithCustomFormat.json | 16 + examples/snippets/validation/schemas.ts | 38 ++ .../validation/schemasWithExternalRefs.ts | 43 ++ mkdocs.yml | 1 + 16 files changed, 410 insertions(+), 531 deletions(-) rename examples/snippets/{validation => event-handler}/.gitignore (100%) create mode 100644 examples/snippets/validation/advancedBringAjvInstance.ts create mode 100644 examples/snippets/validation/advancedCustomFormats.ts create mode 100644 examples/snippets/validation/advancedExternalRefs.ts create mode 100644 examples/snippets/validation/gettingStartedDecorator.ts create mode 100644 examples/snippets/validation/gettingStartedEnvelope.ts create mode 100644 examples/snippets/validation/gettingStartedEnvelopeBuiltin.ts create mode 100644 examples/snippets/validation/gettingStartedMiddy.ts create mode 100644 examples/snippets/validation/gettingStartedStandalone.ts create mode 100644 examples/snippets/validation/samples/gettingStartedEnvelopeEvent.json create mode 100644 examples/snippets/validation/samples/gettingStartedSQSEnvelopeEvent.json create mode 100644 examples/snippets/validation/samples/schemaWithCustomFormat.json create mode 100644 examples/snippets/validation/schemas.ts create mode 100644 examples/snippets/validation/schemasWithExternalRefs.ts diff --git a/docs/utilities/validation.md b/docs/utilities/validation.md index bfbaa2aac3..87038ee15a 100644 --- a/docs/utilities/validation.md +++ b/docs/utilities/validation.md @@ -1,15 +1,13 @@ --- -title: Validation (JSON Schema) +title: Validation descrition: Utility +status: new --- This utility provides [JSON Schema](https://json-schema.org) validation for events and responses, including JMESPath support to unwrap events before validation. -!!! warning - This feature is currently under development. As such it's considered not stable and we might make significant breaking changes before going before its release. You are welcome to [provide feedback](https://github.com/aws-powertools/powertools-lambda-typescript/discussions/3519) and [contribute to its implementation](https://github.com/aws-powertools/powertools-lambda-typescript/milestone/18). - ## Key features - Validate incoming event and response payloads @@ -20,7 +18,7 @@ This utility provides [JSON Schema](https://json-schema.org) validation for even ## Getting started ```bash -npm install @aws-lambda-powertools/validation ajv +npm install @aws-lambda-powertools/validation ``` You can validate inbound and outbound payloads using the validator class method decorator or Middy.js middleware. @@ -41,75 +39,16 @@ If the validation fails, we will throw a `SchemaValidationError`. All our decorators assume that the method they are decorating is an async method. This means that even when decorating a synchronous method, it will return a promise. If this is not the desired behavior, you can use one of the other patterns to validate your payloads. -=== "getting_started_decorator.ts" +=== "gettingStartedDecorator.ts" - ```typescript - import { validator } from '@aws-lambda-powertools/validation'; - import type { Context } from 'aws-lambda'; - import { - inboundSchema, - outboundSchema, - type InboundSchema, - type OutboundSchema - } from './getting_started_schemas.js'; - - class Lambda { - @validator({ - inboundSchema, - outboundSchema, - }) - async handler(event: InboundSchema, context: Context): Promise { - return { - statusCode: 200, - body: `Hello from ${event.userId}`, - } - } - } - - export const handler = new Lambda().handler + ```typescript hl_lines="1 11-14" + --8<-- "examples/snippets/validation/gettingStartedDecorator.ts" ``` -=== "getting_started_schemas.ts" +=== "schemas.ts" ```typescript - const inboundSchema = { - type: 'object', - properties: { - userId: { - type: 'string' - } - }, - required: ['userId'] - } as const; - - type InboundSchema = { - userId: string; - }; - - const outboundSchema = { - type: 'object', - properties: { - body: { - type: 'string' - }, - statusCode: { - type: 'number' - } - }, - required: ['body', 'statusCode'] - } as const; - - type OutboundSchema = { - body: string; - statusCode: number; - }; - - export { - inboundSchema, - outboundSchema, - type InboundSchema, - type OutboundSchema - }; + --8<-- "examples/snippets/validation/schemas.ts" ``` It's not mandatory to validate both the inbound and outbound payloads. You can either use one, the other, or both. @@ -125,73 +64,16 @@ If you are using Middy.js, you can use the `validator` middleware to validate th Like the class method decorator, if the validation fails, we will throw a `SchemaValidationError`, and you don't need to use both the inbound and outbound schemas if you don't need to. -=== "getting_started_middy.ts" +=== "gettingStartedMiddy.ts" - ```typescript - import { validator } from '@aws-lambda-powertools/validation/middleware'; - import middy from '@middy/core'; - import { - inboundSchema, - outboundSchema, - type InboundSchema, - type OutboundSchema - } from './getting_started_schemas.js'; - - export const handler = middy() - .use(validator({ - inboundSchema, - outboundSchema, - })) - .handler( - async (event: InboundSchema, context: Context): Promise => { - return { - statusCode: 200, - body: `Hello from ${event.userId}`, - } - }); + ```typescript hl_lines="1 12-15" + --8<-- "examples/snippets/validation/gettingStartedMiddy.ts" ``` -=== "getting_started_schemas.ts" +=== "schemas.ts" ```typescript - const inboundSchema = { - type: 'object', - properties: { - userId: { - type: 'string' - } - }, - required: ['userId'] - } as const; - - type InboundSchema = { - userId: string; - }; - - const outboundSchema = { - type: 'object', - properties: { - body: { - type: 'string' - }, - statusCode: { - type: 'number' - } - }, - required: ['body', 'statusCode'] - } as const; - - type OutboundSchema = { - body: string; - statusCode: number; - }; - - export { - inboundSchema, - outboundSchema, - type InboundSchema, - type OutboundSchema - }; + --8<-- "examples/snippets/validation/schemas.ts" ``` ### Standalone validation @@ -200,80 +82,18 @@ The `validate` function gives you more control over the validation process, and You can also gracefully handle schema validation errors by catching `SchemaValidationError` errors. -=== "getting_started_standalone.ts" +=== "gettingStartedStandalone.ts" - ```typescript - import { validate, SchemaValidationError } from '@aws-lambda-powertools/validation'; - import { Logger } from '@aws-lambda-powertools/logger'; - import { - inboundSchema, - type InboundSchema, - } from './getting_started_schemas.js'; - - const logger = new Logger(); - - export const handler = async (event: InboundSchema, context: Context) => { - try { - await validate({ - payload: event, - schema: inboundSchema, - }) - - return { // since we are not validating the output, we can return anything - message: 'ok' - } - } catch (error) { - if (error instanceof SchemaValidationError) { - logger.error('Schema validation failed', error) - throw new Error('Invalid event payload') - } - - throw error - } - } + ```typescript hl_lines="2 3 10-13 19" + --8<-- "examples/snippets/validation/gettingStartedStandalone.ts" ``` -=== "getting_started_schemas.ts" + 1. Since we are not validating the output, we can return anything + +=== "schemas.ts" ```typescript - const inboundSchema = { - type: 'object', - properties: { - userId: { - type: 'string' - } - }, - required: ['userId'] - } as const; - - type InboundSchema = { - userId: string; - }; - - const outboundSchema = { - type: 'object', - properties: { - body: { - type: 'string' - }, - statusCode: { - type: 'number' - } - }, - required: ['body', 'statusCode'] - } as const; - - type OutboundSchema = { - body: string; - statusCode: number; - }; - - export { - inboundSchema, - outboundSchema, - type InboundSchema, - type OutboundSchema - }; + --8<-- "examples/snippets/validation/schemas.ts" ``` ### Unwrapping events prior to validation @@ -284,92 +104,22 @@ Envelopes are [JMESPath expressions](https://jmespath.org/tutorial.html) to extr Here is a sample custom EventBridge event, where we only want to validate the `detail` part of the event: -=== "getting_started_envelope.ts" +=== "gettingStartedEnvelope.ts" - ```typescript - import { validator } from '@aws-lambda-powertools/validation'; - import type { Context } from 'aws-lambda'; - import { - inboundSchema, - type InboundSchema, - type OutboundSchema - } from './getting_started_schemas.js'; - - class Lambda { - @validator({ - inboundSchema, - envelope: 'detail', - }) - async handler(event: InboundSchema, context: Context) { - return { - message: `processed ${event.userId}`, - success: true, - } - } - } - - export const handler = new Lambda().handler + ```typescript hl_lines="8" + --8<-- "examples/snippets/validation/gettingStartedEnvelope.ts" ``` -=== "getting_started_schemas.ts" +=== "schemas.ts" ```typescript - const inboundSchema = { - type: 'object', - properties: { - userId: { - type: 'string' - } - }, - required: ['userId'] - } as const; - - type InboundSchema = { - userId: string; - }; - - const outboundSchema = { - type: 'object', - properties: { - body: { - type: 'string' - }, - statusCode: { - type: 'number' - } - }, - required: ['body', 'statusCode'] - } as const; - - type OutboundSchema = { - body: string; - statusCode: number; - }; - - export { - inboundSchema, - outboundSchema, - type InboundSchema, - type OutboundSchema - }; + --8<-- "examples/snippets/validation/schemas.ts" ``` -=== "getting_started_envelope_event.json" +=== "gettingStartedEnvelopeEvent.json" ```json - { - "version": "0", - "id": "12345678-1234-1234-1234-123456789012", - "detail-type": "myDetailType", - "source": "myEventSource", - "account": "123456789012", - "time": "2017-12-22T18:43:48Z", - "region": "us-west-2", - "resources": [], - "detail": { - "userId": "123" - } - } + --8<-- "examples/snippets/validation/samples/gettingStartedEnvelopeEvent.json" ``` This is quite powerful as it allows you to validate only the part of the event that you are interested in, and thanks to JMESPath, you can extract records from [arrays](https://jmespath.org/tutorial.html#list-and-slice-projections), combine [pipe](https://jmespath.org/tutorial.html#pipe-expressions) and filter expressions, and more. @@ -382,115 +132,22 @@ We provide built-in envelopes to easily extract payloads from popular AWS event Here is an example of how you can use the built-in envelope for SQS events: -=== "getting_started_envelope_builtin.ts" +=== "gettingStartedEnvelopeBuiltin.ts" - ```typescript - import { validator } from '@aws-lambda-powertools/validation'; - import { SQS } from '@aws-lambda-powertools/validation/envelopes/sqs'; - import type { Context } from 'aws-lambda'; - import { - inboundSchema, - type InboundSchema, - } from './getting_started_schemas.js'; - - const logger = new Logger(); - - export const handler = middy() - .use(validator({ - inboundSchema, - envelope: SQS, - })) - .handler( - async (event: Array, context: Context) => { - for (const record of event) { - logger.info(`Processing message ${record.userId}`); - } - } - ) + ```typescript hl_lines="1 13" + --8<-- "examples/snippets/validation/gettingStartedEnvelopeBuiltin.ts" ``` -=== "getting_started_schemas.ts" +=== "schemas.ts" ```typescript - const inboundSchema = { - type: 'object', - properties: { - userId: { - type: 'string' - } - }, - required: ['userId'] - } as const; - - type InboundSchema = { - userId: string; - }; - - const outboundSchema = { - type: 'object', - properties: { - body: { - type: 'string' - }, - statusCode: { - type: 'number' - } - }, - required: ['body', 'statusCode'] - } as const; - - type OutboundSchema = { - body: string; - statusCode: number; - }; - - export { - inboundSchema, - outboundSchema, - type InboundSchema, - type OutboundSchema - }; + --8<-- "examples/snippets/validation/schemas.ts" ``` -=== "getting_started_envelope_event.json" +=== "gettingStartedSQSEnvelopeEvent.json" ```json - { - "Records": [ - { - "messageId": "c80e8021-a70a-42c7-a470-796e1186f753", - "receiptHandle": "AQEBwJnKyrHigUMZj6rYigCgxlaS3SLy0a...", - "body": "{\"userId\":\"123\"}", - "attributes": { - "ApproximateReceiveCount": "3", - "SentTimestamp": "1529104986221", - "SenderId": "AIDAIC6K7FJUZ7Q", - "ApproximateFirstReceiveTimestamp": "1529104986230" - }, - "messageAttributes": {}, - "md5OfBody": "098f6bcd4621d373cade4e832627b4f6", - "eventSource": "aws:sqs", - "eventSourceARN": "arn:aws:sqs:us-west-2:123456789012:my-queue", - "awsRegion": "us-west-2" - }, - { - "messageId": "c80e8021-a70a-42c7-a470-796e1186f753", - "receiptHandle": "AQEBwJnKyrHigUMZj6rYigCgxlaS3SLy0a...", - "body": "{\"userId\":\"456\"}", - "attributes": { - "ApproximateReceiveCount": "3", - "SentTimestamp": "1529104986221", - "SenderId": "AIDAIC6K7FJUZ7Q", - "ApproximateFirstReceiveTimestamp": "1529104986230" - }, - "messageAttributes": {}, - "md5OfBody": "098f6bcd4621d373cade4e832627b4f6", - "eventSource": "aws:sqs", - "eventSourceARN": "arn:aws:sqs:us-west-2:123456789012:my-queue", - "awsRegion": "us-west-2" - } - ] - } + --8<-- "examples/snippets/validation/samples/gettingStartedSQSEnvelopeEvent.json" ``` For a complete list of built-in envelopes, check the built-in envelopes section [here](https://docs.powertools.aws.dev/lambda/typescript/latest/utilities/jmespath/#built-in-envelopes). @@ -505,70 +162,20 @@ This is useful when you have a specific format that is not covered by the built- JSON Schemas with custom formats like `awsaccountid` will fail validation if the format is not defined. You can define custom formats using the `formats` option to any of the validation methods. -=== "schema_with_custom_format.json" +=== "schemaWithCustomFormat.json" ```json - { - "type": "object", - "properties": { - "accountId": { - "type": "string", - "format": "awsaccountid" - }, - "creditCard": { - "type": "string", - "format": "creditcard" - } - }, - "required": ["accountId"] - } + --8<-- "examples/snippets/validation/samples/schemaWithCustomFormat.json" ``` For each one of these custom formats, you need to tell us how to validate them. To do so, you can either pass a `RegExp` object or a function that receives the value and returns a boolean. For example, to validate using the schema above, you can define a custom format for `awsaccountid` like this: -=== "advanced_custom_format.ts" +=== "advancedCustomFormats.ts" - ```typescript - import { validate, SchemaValidationError } from '@aws-lambda-powertools/validation'; - import { Logger } from '@aws-lambda-powertools/logger'; - - const logger = new Logger(); - - const customFormats = { - awsaccountid: new RegExp('^[0-9]{12}$'), - creditcard: (value: string) => { - // Luhn algorithm (for demonstration purposes only - do not use in production) - const sum = value.split('').reverse().reduce((acc, digit, index) => { - const num = parseInt(digit, 10); - return acc + (index % 2 === 0 ? num : num < 5 ? num * 2 : num * 2 - 9); - }, 0); - - return sum % 10 === 0; - } - }; - - export const handler = async (event: any, context: Context) => { - try { - await validate({ - payload: event, - schema: schemaWithCustomFormat, - formats: customFormats, - }) - - return { // since we are not validating the output, we can return anything - message: 'ok' - } - } catch (error) { - if (error instanceof SchemaValidationError) { - logger.error('Schema validation failed', error) - throw new Error('Invalid event payload') - } - - throw error - } - } + ```typescript hl_lines="29" + --8<-- "examples/snippets/validation/advancedCustomFormats.ts" ``` ### Built-in JMESpath functions @@ -589,78 +196,16 @@ JSON Schema allows schemas to reference other schemas using the `$ref` keyword. You can use the `externalRefs` option to pass a list of schemas that you want to reference in your inbound and outbound schemas. -=== "advanced_custom_format.ts" +=== "advancedExternalRefs.ts" - ```typescript - import { validate } from '@aws-lambda-powertools/validation'; - import { - inboundSchema, - outboundSchema, - defsSchema, - type InboundSchema, - } from './schemas_with_external_ref.ts'; - - class Lambda { - @validator({ - inboundSchema, - outboundSchema, - externalRefs: [defsSchema], - }) - async handler(event: InboundSchema, context: Context) { - return { - message: `processed ${event.userId}`, - success: true, - } - } - } + ```typescript hl_lines="14" + --8<-- "examples/snippets/validation/advancedExternalRefs.ts" ``` -=== "schemas_with_external_ref.ts" - - ```ts - const defsSchema = { - $id: 'http://example.com/schemas/defs.json', - definitions: { - int: { type: 'integer' }, - str: { type: 'string' }, - }, - } as const; - - const inboundSchema = { - $id: 'http://example.com/schemas/inbound.json', - type: 'object', - properties: { - userId: { $ref: 'defs.json#/definitions/str' } - }, - required: ['userId'] - } as const; - - type InboundSchema = { - userId: string; - }; - - const outboundSchema = { - $id: 'http://example.com/schemas/outbound.json', - type: 'object', - properties: { - body: { $ref: 'defs.json#/definitions/str' }, - statusCode: { $ref: 'defs.json#/definitions/int' } - }, - required: ['body', 'statusCode'] - } as const; - - type OutboundSchema = { - body: string; - statusCode: number; - }; - - export { - defsSchema, - inboundSchema, - outboundSchema, - type InboundSchema, - type OutboundSchema - }; +=== "schemasWithExternalRefs.ts" + + ```typescript + --8<-- "examples/snippets/validation/schemasWithExternalRefs.ts" ``` ### Bringing your own `ajv` instance @@ -669,39 +214,14 @@ By default, we use JSON Schema draft-07. If you want to use a different draft, y This is also useful if you want to configure `ajv` with custom options like keywords and more. -=== "advanced_custom_format.ts" +=== "advancedBringAjvInstance.ts" - ```typescript - import { validate } from '@aws-lambda-powertools/validation'; - import Ajv2019 from "ajv/dist/2019" - import { Logger } from '@aws-lambda-powertools/logger'; - - const logger = new Logger(); - - const ajv = new Ajv2019(); - - export const handler = async (event: any, context: Context) => { - try { - await validate({ - payload: event, - schema: schemaWithCustomFormat, - ajv, - }) - - return { // since we are not validating the output, we can return anything - message: 'ok' - } - } catch (error) { - if (error instanceof SchemaValidationError) { - logger.error('Schema validation failed', error) - throw new Error('Invalid event payload') - } - - throw error - } - } + ```typescript hl_lines="9 16" + --8<-- "examples/snippets/validation/advancedBringAjvInstance.ts" ``` + 1. You can pass your own `ajv` instance to any of the validation methods. This is useful if you want to configure `ajv` with custom options like keywords and more. + ## Should I use this or Parser? One of Powertools for AWS Lambda [tenets](../index.md#tenets) is to be progressive. This means that our utilities are designed to be incrementally adopted by customers at any stage of their serverless journey. diff --git a/examples/snippets/validation/.gitignore b/examples/snippets/event-handler/.gitignore similarity index 100% rename from examples/snippets/validation/.gitignore rename to examples/snippets/event-handler/.gitignore diff --git a/examples/snippets/validation/advancedBringAjvInstance.ts b/examples/snippets/validation/advancedBringAjvInstance.ts new file mode 100644 index 0000000000..8d0187e09b --- /dev/null +++ b/examples/snippets/validation/advancedBringAjvInstance.ts @@ -0,0 +1,30 @@ +import { Logger } from '@aws-lambda-powertools/logger'; +import { validate } from '@aws-lambda-powertools/validation'; +import { SchemaValidationError } from '@aws-lambda-powertools/validation/errors'; +import Ajv2019 from 'ajv/dist/2019'; +import { inboundSchema } from './schemas.js'; + +const logger = new Logger(); + +const ajv = new Ajv2019(); + +export const handler = async (event: unknown) => { + try { + await validate({ + payload: event, + schema: inboundSchema, + ajv, // (1)! + }); + + return { + message: 'ok', + }; + } catch (error) { + if (error instanceof SchemaValidationError) { + logger.error('Schema validation failed', error); + throw new Error('Invalid event payload'); + } + + throw error; + } +}; diff --git a/examples/snippets/validation/advancedCustomFormats.ts b/examples/snippets/validation/advancedCustomFormats.ts new file mode 100644 index 0000000000..ccc3f8610b --- /dev/null +++ b/examples/snippets/validation/advancedCustomFormats.ts @@ -0,0 +1,43 @@ +import { Logger } from '@aws-lambda-powertools/logger'; +import { validate } from '@aws-lambda-powertools/validation'; +import { SchemaValidationError } from '@aws-lambda-powertools/validation/errors'; +import schemaWithCustomFormat from './samples/schemaWithCustomFormat.json'; + +const logger = new Logger(); + +const customFormats = { + awsaccountid: /^\d{12}$/, + creditcard: (value: string) => { + // Luhn algorithm (for demonstration purposes only - do not use in production) + const sum = value + .split('') + .reverse() + .reduce((acc, digit, index) => { + const num = Number.parseInt(digit, 10); + return acc + (index % 2 === 0 ? num : num < 5 ? num * 2 : num * 2 - 9); + }, 0); + + return sum % 10 === 0; + }, +}; + +export const handler = async (event: unknown) => { + try { + await validate({ + payload: event, + schema: schemaWithCustomFormat, + formats: customFormats, + }); + + return { + message: 'ok', + }; + } catch (error) { + if (error instanceof SchemaValidationError) { + logger.error('Schema validation failed', error); + throw new Error('Invalid event payload'); + } + + throw error; + } +}; diff --git a/examples/snippets/validation/advancedExternalRefs.ts b/examples/snippets/validation/advancedExternalRefs.ts new file mode 100644 index 0000000000..87ab0824ac --- /dev/null +++ b/examples/snippets/validation/advancedExternalRefs.ts @@ -0,0 +1,25 @@ +import { validator } from '@aws-lambda-powertools/validation/decorator'; +import type { Context } from 'aws-lambda'; +import { + type InboundSchema, + defsSchema, + inboundSchema, + outboundSchema, +} from './schemasWithExternalRefs.js'; + +class Lambda { + @validator({ + inboundSchema, + outboundSchema, + externalRefs: [defsSchema], + }) + async handler(event: InboundSchema, _context: Context) { + return { + message: `processed ${event.userId}`, + success: true, + }; + } +} + +const lambda = new Lambda(); +export const handler = lambda.handler.bind(lambda); diff --git a/examples/snippets/validation/gettingStartedDecorator.ts b/examples/snippets/validation/gettingStartedDecorator.ts new file mode 100644 index 0000000000..50cf98fa14 --- /dev/null +++ b/examples/snippets/validation/gettingStartedDecorator.ts @@ -0,0 +1,27 @@ +import { validator } from '@aws-lambda-powertools/validation/decorator'; +import type { Context } from 'aws-lambda'; +import { + type InboundSchema, + type OutboundSchema, + inboundSchema, + outboundSchema, +} from './schemas.js'; + +class Lambda { + @validator({ + inboundSchema, + outboundSchema, + }) + async handler( + event: InboundSchema, + _context: Context + ): Promise { + return { + statusCode: 200, + body: `Hello from ${event.userId}`, + }; + } +} + +const lambda = new Lambda(); +export const handler = lambda.handler.bind(lambda); diff --git a/examples/snippets/validation/gettingStartedEnvelope.ts b/examples/snippets/validation/gettingStartedEnvelope.ts new file mode 100644 index 0000000000..520e006bed --- /dev/null +++ b/examples/snippets/validation/gettingStartedEnvelope.ts @@ -0,0 +1,19 @@ +import { validator } from '@aws-lambda-powertools/validation/decorator'; +import type { Context } from 'aws-lambda'; +import { type InboundSchema, inboundSchema } from './schemas.js'; + +class Lambda { + @validator({ + inboundSchema, + envelope: 'detail', + }) + async handler(event: InboundSchema, context: Context) { + return { + message: `processed ${event.userId}`, + success: true, + }; + } +} + +const lambda = new Lambda(); +export const handler = lambda.handler.bind(lambda); diff --git a/examples/snippets/validation/gettingStartedEnvelopeBuiltin.ts b/examples/snippets/validation/gettingStartedEnvelopeBuiltin.ts new file mode 100644 index 0000000000..0cd1f788fa --- /dev/null +++ b/examples/snippets/validation/gettingStartedEnvelopeBuiltin.ts @@ -0,0 +1,20 @@ +import { SQS } from '@aws-lambda-powertools/jmespath/envelopes'; +import { Logger } from '@aws-lambda-powertools/logger'; +import { validator } from '@aws-lambda-powertools/validation/middleware'; +import middy from '@middy/core'; +import { type InboundSchema, inboundSchema } from './schemas.js'; + +const logger = new Logger(); + +export const handler = middy() + .use( + validator({ + inboundSchema, + envelope: SQS, + }) + ) + .handler(async (event: Array) => { + for (const record of event) { + logger.info(`Processing message ${record.userId}`); + } + }); diff --git a/examples/snippets/validation/gettingStartedMiddy.ts b/examples/snippets/validation/gettingStartedMiddy.ts new file mode 100644 index 0000000000..9b700ab9cf --- /dev/null +++ b/examples/snippets/validation/gettingStartedMiddy.ts @@ -0,0 +1,22 @@ +import { validator } from '@aws-lambda-powertools/validation/middleware'; +import middy from '@middy/core'; +import { + type InboundSchema, + type OutboundSchema, + inboundSchema, + outboundSchema, +} from './schemas.js'; + +export const handler = middy() + .use( + validator({ + inboundSchema, + outboundSchema, + }) + ) + .handler( + async (event: InboundSchema): Promise => ({ + statusCode: 200, + body: `Hello from ${event.userId}`, + }) + ); diff --git a/examples/snippets/validation/gettingStartedStandalone.ts b/examples/snippets/validation/gettingStartedStandalone.ts new file mode 100644 index 0000000000..3b8ae7aebd --- /dev/null +++ b/examples/snippets/validation/gettingStartedStandalone.ts @@ -0,0 +1,26 @@ +import { Logger } from '@aws-lambda-powertools/logger'; +import { validate } from '@aws-lambda-powertools/validation'; +import { SchemaValidationError } from '@aws-lambda-powertools/validation/errors'; +import { type InboundSchema, inboundSchema } from './schemas.js'; + +const logger = new Logger(); + +export const handler = async (event: InboundSchema) => { + try { + validate({ + payload: event, + schema: inboundSchema, + }); + + return { + message: 'ok', // (1)! + }; + } catch (error) { + if (error instanceof SchemaValidationError) { + logger.error('Schema validation failed', error); + throw new Error('Invalid event payload'); + } + + throw error; + } +}; diff --git a/examples/snippets/validation/samples/gettingStartedEnvelopeEvent.json b/examples/snippets/validation/samples/gettingStartedEnvelopeEvent.json new file mode 100644 index 0000000000..17c1c5672e --- /dev/null +++ b/examples/snippets/validation/samples/gettingStartedEnvelopeEvent.json @@ -0,0 +1,13 @@ +{ + "version": "0", + "id": "12345678-1234-1234-1234-123456789012", + "detail-type": "myDetailType", + "source": "myEventSource", + "account": "123456789012", + "time": "2017-12-22T18:43:48Z", + "region": "us-west-2", + "resources": [], + "detail": { + "userId": "123" + } +} \ No newline at end of file diff --git a/examples/snippets/validation/samples/gettingStartedSQSEnvelopeEvent.json b/examples/snippets/validation/samples/gettingStartedSQSEnvelopeEvent.json new file mode 100644 index 0000000000..a8df4bf107 --- /dev/null +++ b/examples/snippets/validation/samples/gettingStartedSQSEnvelopeEvent.json @@ -0,0 +1,36 @@ +{ + "Records": [ + { + "messageId": "c80e8021-a70a-42c7-a470-796e1186f753", + "receiptHandle": "AQEBwJnKyrHigUMZj6rYigCgxlaS3SLy0a...", + "body": "{\"userId\":\"123\"}", + "attributes": { + "ApproximateReceiveCount": "3", + "SentTimestamp": "1529104986221", + "SenderId": "AIDAIC6K7FJUZ7Q", + "ApproximateFirstReceiveTimestamp": "1529104986230" + }, + "messageAttributes": {}, + "md5OfBody": "098f6bcd4621d373cade4e832627b4f6", + "eventSource": "aws:sqs", + "eventSourceARN": "arn:aws:sqs:us-west-2:123456789012:my-queue", + "awsRegion": "us-west-2" + }, + { + "messageId": "c80e8021-a70a-42c7-a470-796e1186f753", + "receiptHandle": "AQEBwJnKyrHigUMZj6rYigCgxlaS3SLy0a...", + "body": "{\"userId\":\"456\"}", + "attributes": { + "ApproximateReceiveCount": "3", + "SentTimestamp": "1529104986221", + "SenderId": "AIDAIC6K7FJUZ7Q", + "ApproximateFirstReceiveTimestamp": "1529104986230" + }, + "messageAttributes": {}, + "md5OfBody": "098f6bcd4621d373cade4e832627b4f6", + "eventSource": "aws:sqs", + "eventSourceARN": "arn:aws:sqs:us-west-2:123456789012:my-queue", + "awsRegion": "us-west-2" + } + ] +} \ No newline at end of file diff --git a/examples/snippets/validation/samples/schemaWithCustomFormat.json b/examples/snippets/validation/samples/schemaWithCustomFormat.json new file mode 100644 index 0000000000..954fe05ddd --- /dev/null +++ b/examples/snippets/validation/samples/schemaWithCustomFormat.json @@ -0,0 +1,16 @@ +{ + "type": "object", + "properties": { + "accountId": { + "type": "string", + "format": "awsaccountid" + }, + "creditCard": { + "type": "string", + "format": "creditcard" + } + }, + "required": [ + "accountId" + ] +} \ No newline at end of file diff --git a/examples/snippets/validation/schemas.ts b/examples/snippets/validation/schemas.ts new file mode 100644 index 0000000000..60f6a199e5 --- /dev/null +++ b/examples/snippets/validation/schemas.ts @@ -0,0 +1,38 @@ +const inboundSchema = { + type: 'object', + properties: { + userId: { + type: 'string', + }, + }, + required: ['userId'], +} as const; + +type InboundSchema = { + userId: string; +}; + +const outboundSchema = { + type: 'object', + properties: { + body: { + type: 'string', + }, + statusCode: { + type: 'number', + }, + }, + required: ['body', 'statusCode'], +} as const; + +type OutboundSchema = { + body: string; + statusCode: number; +}; + +export { + inboundSchema, + outboundSchema, + type InboundSchema, + type OutboundSchema, +}; diff --git a/examples/snippets/validation/schemasWithExternalRefs.ts b/examples/snippets/validation/schemasWithExternalRefs.ts new file mode 100644 index 0000000000..d8a8a293ce --- /dev/null +++ b/examples/snippets/validation/schemasWithExternalRefs.ts @@ -0,0 +1,43 @@ +const defsSchema = { + $id: 'http://example.com/schemas/defs.json', + definitions: { + int: { type: 'integer' }, + str: { type: 'string' }, + }, +} as const; + +const inboundSchema = { + $id: 'http://example.com/schemas/inbound.json', + type: 'object', + properties: { + userId: { $ref: 'defs.json#/definitions/str' }, + }, + required: ['userId'], +} as const; + +type InboundSchema = { + userId: string; +}; + +const outboundSchema = { + $id: 'http://example.com/schemas/outbound.json', + type: 'object', + properties: { + body: { $ref: 'defs.json#/definitions/str' }, + statusCode: { $ref: 'defs.json#/definitions/int' }, + }, + required: ['body', 'statusCode'], +} as const; + +type OutboundSchema = { + body: string; + statusCode: number; +}; + +export { + defsSchema, + inboundSchema, + outboundSchema, + type InboundSchema, + type OutboundSchema, +}; diff --git a/mkdocs.yml b/mkdocs.yml index 994dc80125..5bfc63b52c 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -46,6 +46,7 @@ nav: - utilities/batch.md - utilities/jmespath.md - utilities/parser.md + - utilities/validation.md - API reference: api" - Processes: - Roadmap: roadmap.md From 847a438d16a6a73131724c15d4aa4f2bf2614f23 Mon Sep 17 00:00:00 2001 From: Andrea Amorosi Date: Thu, 13 Mar 2025 20:18:17 +0100 Subject: [PATCH 13/56] chore(ci): remove old api copy step (#3725) --- .github/workflows/reusable_publish_docs.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.github/workflows/reusable_publish_docs.yml b/.github/workflows/reusable_publish_docs.yml index 68cacc068a..c4b640529d 100644 --- a/.github/workflows/reusable_publish_docs.yml +++ b/.github/workflows/reusable_publish_docs.yml @@ -88,9 +88,6 @@ jobs: aws-region: us-east-1 role-to-assume: ${{ secrets.AWS_DOCS_ROLE_ARN }} mask-aws-account-id: true - - name: Copy API Docs - run: | - cp -r api site/ - name: Create Artifact (Site) uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 # v4.6.1 with: From 2692ca4d1b15763936659b05e1830d998a4d2020 Mon Sep 17 00:00:00 2001 From: Andrea Amorosi Date: Thu, 13 Mar 2025 22:21:18 +0100 Subject: [PATCH 14/56] fix(logger): correctly refresh sample rate (#3722) Co-authored-by: Alexander Schueren --- docs/core/logger.md | 99 +++---------------- examples/snippets/logger/logSampling.ts | 25 ++--- .../samples/debugLogSamplingNotSampled.json | 8 ++ .../samples/debugLogSamplingSampled.json | 34 +++++++ packages/logger/src/Logger.ts | 60 ++++++++--- .../tests/unit/injectLambdaContext.test.ts | 86 +++++++++------- packages/logger/tests/unit/sampling.test.ts | 4 +- 7 files changed, 162 insertions(+), 154 deletions(-) create mode 100644 examples/snippets/logger/samples/debugLogSamplingNotSampled.json create mode 100644 examples/snippets/logger/samples/debugLogSamplingSampled.json diff --git a/docs/core/logger.md b/docs/core/logger.md index 523214a147..7913ee3503 100644 --- a/docs/core/logger.md +++ b/docs/core/logger.md @@ -805,114 +805,41 @@ You can use values ranging from `0` to `1` (100%) when setting the `sampleRateVa This feature takes into account transient issues where additional debugging information can be useful. -Sampling decision happens at the Logger initialization. When using the `injectLambdaContext` method either as a decorator or middleware, the sampling decision is refreshed at the beginning of each Lambda invocation for you, except for cold starts. +Sampling decision happens at the Logger initialization. When using the `injectLambdaContext` method either as a decorator or Middy.js middleware, the sampling decision is refreshed at the beginning of each Lambda invocation for you, except for cold starts. If you're not using either of these, you'll need to manually call the `refreshSamplingRate()` function at the start of your handler to refresh the sampling decision for each invocation. === "handler.ts" - ```typescript hl_lines="6" + ```typescript hl_lines="5 9" --8<-- "examples/snippets/logger/logSampling.ts" ``` -=== "Example CloudWatch Logs excerpt - Invocation #1" + 1. The log level must be set to a more verbose level than `DEBUG` for log sampling to kick in. + 2. You need to call `logger.refreshSamplingRate()` at the start of your handler **only** if you're not using the `injectLambdaContext()` class method decorator or Middy.js middleware. + +=== "Example Logs Request #1 (not sampled)" ```json - { - "level": "ERROR", - "message": "This is an ERROR log", - "sampling_rate": "0.5", - "service": "serverlessAirline", - "timestamp": "2021-12-12T22:59:06.334Z", - "xray_trace_id": "abcdef123456abcdef123456abcdef123456" - } - { - "level": "DEBUG", - "message": "This is a DEBUG log that has 50% chance of being printed", - "sampling_rate": "0.5", - "service": "serverlessAirline", - "timestamp": "2021-12-12T22:59:06.337Z", - "xray_trace_id": "abcdef123456abcdef123456abcdef123456" - } - { - "level": "INFO", - "message": "This is an INFO log that has 50% chance of being printed", - "sampling_rate": "0.5", - "service": "serverlessAirline", - "timestamp": "2021-12-12T22:59:06.338Z", - "xray_trace_id": "abcdef123456abcdef123456abcdef123456" - } - { - "level": "WARN", - "message": "This is a WARN log that has 50% chance of being printed", - "sampling_rate": "0.5", - "service": "serverlessAirline", - "timestamp": "2021-12-12T22:59:06.338Z", - "xray_trace_id": "abcdef123456abcdef123456abcdef123456" - } + --8<-- "examples/snippets/logger/samples/debugLogSamplingNotSampled.json" ``` -=== "Example CloudWatch Logs excerpt - Invocation #2" +=== "Example Logs Request #2 (sampled)" ```json - { - "level": "ERROR", - "message": "This is an ERROR log", - "sampling_rate": "0.5", - "service": "serverlessAirline", - "timestamp": "2021-12-12T22:59:06.334Z", - "xray_trace_id": "abcdef123456abcdef123456abcdef123456" - } + --8<-- "examples/snippets/logger/samples/debugLogSamplingSampled.json" ``` -=== "Example CloudWatch Logs excerpt - Invocation #3" +=== "Example Logs Request #3 (sampled)" ```json - { - "level": "ERROR", - "message": "This is an ERROR log", - "sampling_rate": "0.5", - "service": "serverlessAirline", - "timestamp": "2021-12-12T22:59:06.334Z", - "xray_trace_id": "abcdef123456abcdef123456abcdef123456" - } - { - "level": "DEBUG", - "message": "This is a DEBUG log that has 50% chance of being printed", - "sampling_rate": "0.5", - "service": "serverlessAirline", - "timestamp": "2021-12-12T22:59:06.337Z", - "xray_trace_id": "abcdef123456abcdef123456abcdef123456" - } - { - "level": "INFO", - "message": "This is an INFO log that has 50% chance of being printed", - "sampling_rate": "0.5", - "service": "serverlessAirline", - "timestamp": "2021-12-12T22:59:06.338Z", - "xray_trace_id": "abcdef123456abcdef123456abcdef123456" - } - { - "level": "WARN", - "message": "This is a WARN log that has 50% chance of being printed", - "sampling_rate": "0.5", - "service": "serverlessAirline", - "timestamp": "2021-12-12T22:59:06.338Z", - "xray_trace_id": "abcdef123456abcdef123456abcdef123456" - } + --8<-- "examples/snippets/logger/samples/debugLogSamplingSampled.json" ``` -=== "Example CloudWatch Logs excerpt - Invocation #4" +=== "Example Logs Request #4 (not sampled)" ```json - { - "level": "ERROR", - "message": "This is an ERROR log", - "sampling_rate": "0.5", - "service": "serverlessAirline", - "timestamp": "2021-12-12T22:59:06.334Z", - "xray_trace_id": "abcdef123456abcdef123456abcdef123456" - } + --8<-- "examples/snippets/logger/samples/debugLogSamplingNotSampled.json" ``` ### Custom Log formatter diff --git a/examples/snippets/logger/logSampling.ts b/examples/snippets/logger/logSampling.ts index 0067afb73f..94318e4454 100644 --- a/examples/snippets/logger/logSampling.ts +++ b/examples/snippets/logger/logSampling.ts @@ -1,27 +1,16 @@ import { Logger } from '@aws-lambda-powertools/logger'; -// Notice the log level set to 'ERROR' const logger = new Logger({ - logLevel: 'ERROR', + logLevel: 'ERROR', // (1)! sampleRateValue: 0.5, }); -export const handler = async ( - _event: unknown, - _context: unknown -): Promise => { - // Refresh sample rate calculation on runtime, only when not using injectLambdaContext - logger.refreshSampleRateCalculation(); - // This log item (equal to log level 'ERROR') will be printed to standard output - // in all Lambda invocations - logger.error('This is an ERROR log'); +export const handler = async () => { + logger.refreshSampleRateCalculation(); // (2)! - // These log items (below the log level 'ERROR') have ~50% chance - // of being printed in a Lambda invocation - logger.debug('This is a DEBUG log that has 50% chance of being printed'); - logger.info('This is an INFO log that has 50% chance of being printed'); - logger.warn('This is a WARN log that has 50% chance of being printed'); + logger.error('This log is always emitted'); - // Optional: refresh sample rate calculation on runtime - // logger.refreshSampleRateCalculation(); + logger.debug('This log has ~50% chance of being emitted'); + logger.info('This log has ~50% chance of being emitted'); + logger.warn('This log has ~50% chance of being emitted'); }; diff --git a/examples/snippets/logger/samples/debugLogSamplingNotSampled.json b/examples/snippets/logger/samples/debugLogSamplingNotSampled.json new file mode 100644 index 0000000000..f876f36306 --- /dev/null +++ b/examples/snippets/logger/samples/debugLogSamplingNotSampled.json @@ -0,0 +1,8 @@ +{ + "level": "ERROR", + "message": "This log is always emitted", + "sampling_rate": "0.5", + "service": "serverlessAirline", + "timestamp": "2021-12-12T22:59:06.334Z", + "xray_trace_id": "abcdef123456abcdef123456abcdef123456" +} \ No newline at end of file diff --git a/examples/snippets/logger/samples/debugLogSamplingSampled.json b/examples/snippets/logger/samples/debugLogSamplingSampled.json new file mode 100644 index 0000000000..ae95e28aa1 --- /dev/null +++ b/examples/snippets/logger/samples/debugLogSamplingSampled.json @@ -0,0 +1,34 @@ +[ + { + "level": "ERROR", + "message": "This log is always emitted", + "sampling_rate": "0.5", + "service": "serverlessAirline", + "timestamp": "2021-12-12T22:59:06.334Z", + "xray_trace_id": "abcdef123456abcdef123456abcdef123456" + }, + { + "level": "DEBUG", + "message": "This log has ~50% chance of being emitted", + "sampling_rate": "0.5", + "service": "serverlessAirline", + "timestamp": "2021-12-12T22:59:06.337Z", + "xray_trace_id": "abcdef123456abcdef123456abcdef123456" + }, + { + "level": "INFO", + "message": "This log has ~50% chance of being emitted", + "sampling_rate": "0.5", + "service": "serverlessAirline", + "timestamp": "2021-12-12T22:59:06.338Z", + "xray_trace_id": "abcdef123456abcdef123456abcdef123456" + }, + { + "level": "WARN", + "message": "This log has ~50% chance of being emitted", + "sampling_rate": "0.5", + "service": "serverlessAirline", + "timestamp": "2021-12-12T22:59:06.338Z", + "xray_trace_id": "abcdef123456abcdef123456abcdef123456" + } +] \ No newline at end of file diff --git a/packages/logger/src/Logger.ts b/packages/logger/src/Logger.ts index f39bb8ef0e..babfc4f77c 100644 --- a/packages/logger/src/Logger.ts +++ b/packages/logger/src/Logger.ts @@ -140,7 +140,9 @@ class Logger extends Utility implements LoggerInterface { /** * Standard attributes managed by Powertools that will be logged in all log items. */ - private powertoolsLogData: PowertoolsLogData = {}; + private powertoolsLogData: PowertoolsLogData = { + sampleRateValue: 0, + }; /** * Temporary log attributes that can be appended with `appendKeys()` method. */ @@ -213,6 +215,22 @@ class Logger extends Utility implements LoggerInterface { */ #buffer?: CircularMap; + /** + * The debug sampling rate configuration. + */ + readonly #debugLogSampling = { + /** + * The sampling rate value used to determine if the log level should be set to DEBUG. + */ + sampleRateValue: 0, + /** + * The number of times the debug sampling rate has been refreshed. + * + * We use this to determine if we should refresh it again. + */ + refreshedTimes: 0, + }; + /** * Log level used by the current instance of Logger. * @@ -302,7 +320,7 @@ class Logger extends Utility implements LoggerInterface { { logLevel: this.getLevelName(), serviceName: this.powertoolsLogData.serviceName, - sampleRateValue: this.powertoolsLogData.sampleRateValue, + sampleRateValue: this.#debugLogSampling.sampleRateValue, logFormatter: this.getLogFormatter(), customConfigService: this.getCustomConfigService(), environment: this.powertoolsLogData.environment, @@ -547,8 +565,18 @@ class Logger extends Utility implements LoggerInterface { * This only works for warm starts, because we don't to avoid double sampling. */ public refreshSampleRateCalculation(): void { - if (!this.coldStart) { - this.setInitialSampleRate(this.powertoolsLogData.sampleRateValue); + if (this.#debugLogSampling.refreshedTimes === 0) { + this.#debugLogSampling.refreshedTimes++; + return; + } + if ( + this.#shouldEnableDebugSampling() && + this.logLevel > LogLevelThreshold.TRACE + ) { + this.setLogLevel('DEBUG'); + this.debug('Setting log level to DEBUG due to sampling rate'); + } else { + this.setLogLevel(this.getLogLevelNameFromNumber(this.#initialLogLevel)); } } @@ -891,6 +919,16 @@ class Logger extends Utility implements LoggerInterface { } } + /** + * Make a new debug log sampling decision based on the sample rate value. + */ + #shouldEnableDebugSampling() { + return ( + this.#debugLogSampling.sampleRateValue && + randomInt(0, 100) / 100 <= this.#debugLogSampling.sampleRateValue + ); + } + /** * Check if a given key is reserved and warn the user if it is. * @@ -1142,30 +1180,24 @@ class Logger extends Utility implements LoggerInterface { * @param sampleRateValue - The sample rate value */ private setInitialSampleRate(sampleRateValue?: number): void { - this.powertoolsLogData.sampleRateValue = 0; const constructorValue = sampleRateValue; const customConfigValue = this.getCustomConfigService()?.getSampleRateValue(); const envVarsValue = this.getEnvVarsService().getSampleRateValue(); for (const value of [constructorValue, customConfigValue, envVarsValue]) { if (this.isValidSampleRate(value)) { + this.#debugLogSampling.sampleRateValue = value; this.powertoolsLogData.sampleRateValue = value; if ( - this.logLevel > LogLevelThreshold.DEBUG && - value && - randomInt(0, 100) / 100 <= value + this.#shouldEnableDebugSampling() && + this.logLevel > LogLevelThreshold.TRACE ) { - // only change logLevel if higher than debug, i.e. don't change from e.g. tracing to debug this.setLogLevel('DEBUG'); this.debug('Setting log level to DEBUG due to sampling rate'); - } else { - this.setLogLevel( - this.getLogLevelNameFromNumber(this.#initialLogLevel) - ); } - return; + break; } } } diff --git a/packages/logger/tests/unit/injectLambdaContext.test.ts b/packages/logger/tests/unit/injectLambdaContext.test.ts index 36c6d7c6fa..9518e5b6af 100644 --- a/packages/logger/tests/unit/injectLambdaContext.test.ts +++ b/packages/logger/tests/unit/injectLambdaContext.test.ts @@ -185,38 +185,58 @@ describe('Inject Lambda Context', () => { ); }); - it('refreshes sample rate calculation before each invocation using decorator for warm start only', async () => { - // Prepare - const logger = new Logger({ sampleRateValue: 0.5 }); - const refreshSpy = vi.spyOn(logger, 'refreshSampleRateCalculation'); - - class Lambda { - @logger.injectLambdaContext() - public async handler(_event: unknown, _context: Context): Promise { - logger.info('test'); - } + it.each([ + { + case: 'middleware', + getHandler: (logger: Logger) => + middy(async () => { + logger.info('Hello, world!'); + }).use(injectLambdaContext(logger)), + }, + { + case: 'decorator', + getHandler: (logger: Logger) => { + class Lambda { + @logger.injectLambdaContext() + public async handler( + _event: unknown, + _context: Context + ): Promise { + logger.info('test'); + } + } + const lambda = new Lambda(); + return lambda.handler.bind(lambda); + }, + }, + ])( + 'refreshes sample rate calculation before only during warm starts ($case)', + async ({ getHandler }) => { + // Prepare + const logger = new Logger({ sampleRateValue: 1 }); + const setLogLevelSpy = vi.spyOn(logger, 'setLogLevel'); + + const handler = getHandler(logger); + + // Act + await handler(event, context); // cold start + await handler(event, context); // warm start + + // Assess + expect(setLogLevelSpy).toHaveBeenCalledTimes(1); + expect(console.debug).toHaveBeenCalledTimes(2); + expect(console.debug).toHaveLoggedNth( + 1, + expect.objectContaining({ + message: 'Setting log level to DEBUG due to sampling rate', + }) + ); + expect(console.debug).toHaveLoggedNth( + 2, + expect.objectContaining({ + message: 'Setting log level to DEBUG due to sampling rate', + }) + ); } - const lambda = new Lambda(); - // Act - await lambda.handler({}, {} as Context); - - // Assess - expect(refreshSpy).toHaveBeenCalledTimes(1); - }); - - it('refreshes sample rate calculation before each invocation using middleware for warm start only', async () => { - // Prepare - const logger = new Logger({ sampleRateValue: 0.5 }); - const refreshSpy = vi.spyOn(logger, 'refreshSampleRateCalculation'); - - const handler = middy(async () => { - logger.info('Hello, world!'); - }).use(injectLambdaContext(logger)); - - // Act - await handler(event, context); - - // Assess - expect(refreshSpy).toHaveBeenCalledTimes(1); - }); + ); }); diff --git a/packages/logger/tests/unit/sampling.test.ts b/packages/logger/tests/unit/sampling.test.ts index 2453afc7f3..2179e4d041 100644 --- a/packages/logger/tests/unit/sampling.test.ts +++ b/packages/logger/tests/unit/sampling.test.ts @@ -129,15 +129,13 @@ describe('Log sampling', () => { expect(logger.getLevelName()).toBe(LogLevel.INFO); }); - it('when sample rate calculation is refreshed, it respects probability sampling and change log level to DEBUG when not in coldStart ', () => { + it('refreshes and applies log sampling', () => { // Prepare const logger = new Logger({ logLevel: LogLevel.ERROR, sampleRateValue: 0.1, // 10% probability }); - logger.getColdStart(); // Set coldStart to false - let logLevelChangedToDebug = 0; const numOfIterations = 1000; const minExpected = numOfIterations * 0.05; // Min expected based on 5% probability From aa74fc8548ccb8cb313ffd1742184c66e8d6c22c Mon Sep 17 00:00:00 2001 From: Alexander Schueren Date: Fri, 14 Mar 2025 15:41:01 +0100 Subject: [PATCH 15/56] feat(logger): set correlation ID in logs (#3726) --- docs/core/logger.md | 70 +++++++ .../snippets/logger/correlationIdDecorator.ts | 19 ++ .../snippets/logger/correlationIdLogger.ts | 6 + .../snippets/logger/correlationIdManual.ts | 10 + .../snippets/logger/correlationIdMiddy.ts | 18 ++ .../snippets/logger/correlationIdPaths.ts | 22 +++ .../logger/samples/correlationIdOutput.json | 7 + .../logger/samples/correlationIdPayload.json | 5 + packages/logger/package.json | 14 +- packages/logger/src/Logger.ts | 61 ++++++ packages/logger/src/correlationId.ts | 60 ++++++ packages/logger/src/index.ts | 4 +- packages/logger/src/middleware/middy.ts | 4 + packages/logger/src/types/Logger.ts | 26 ++- packages/logger/src/types/index.ts | 12 +- .../tests/unit/injectLambdaContext.test.ts | 174 ++++++++++++++++++ 16 files changed, 494 insertions(+), 18 deletions(-) create mode 100644 examples/snippets/logger/correlationIdDecorator.ts create mode 100644 examples/snippets/logger/correlationIdLogger.ts create mode 100644 examples/snippets/logger/correlationIdManual.ts create mode 100644 examples/snippets/logger/correlationIdMiddy.ts create mode 100644 examples/snippets/logger/correlationIdPaths.ts create mode 100644 examples/snippets/logger/samples/correlationIdOutput.json create mode 100644 examples/snippets/logger/samples/correlationIdPayload.json create mode 100644 packages/logger/src/correlationId.ts diff --git a/docs/core/logger.md b/docs/core/logger.md index 7913ee3503..23b5d1ea9b 100644 --- a/docs/core/logger.md +++ b/docs/core/logger.md @@ -207,6 +207,76 @@ When debugging in non-production environments, you can log the incoming event us Use `POWERTOOLS_LOGGER_LOG_EVENT` environment variable to enable or disable (`true`/`false`) this feature. When using Middy.js middleware or class method decorator, the `logEvent` option will take precedence over the environment variable. +### Setting a Correlation ID + +To get started, install the `@aws-lambda-powertools/jmespath` package, and pass the search function using the `correlationIdSearchFn` constructor parameter: + +=== "Setup the Logger to use JMESPath search" + + ```typescript hl_lines="5" + --8<-- "examples/snippets/logger/correlationIdLogger.ts" + ``` + +???+ tip + You can retrieve correlation IDs via `getCorrelationId` method. + +You can set a correlation ID using `correlationIdPath` parameter by passing a JMESPath expression, including our custom JMESPath functions or set it manually by calling `setCorrelationId` function. + +=== "Setting correlation ID manually" + + ```typescript hl_lines="7" + --8<-- "examples/snippets/logger/correlationIdManual.ts" + ``` + + 1. Alternatively, if the payload is more complex you can use a JMESPath expression as second parameter when prividing a search function in the constructor. + +=== "Middy.js" + + ```typescript hl_lines="13" + --8<-- "examples/snippets/logger/correlationIdMiddy.ts" + ``` + +=== "Decorator" + + ```typescript hl_lines="11" + --8<-- "examples/snippets/logger/correlationIdDecorator.ts" + ``` + +=== "payload.json" + + ```typescript + --8<-- "examples/snippets/logger/samples/correlationIdPayload.json" + ``` + +=== "log-output.json" + + ```json hl_lines="6" + --8<-- "examples/snippets/logger/samples/correlationIdOutput.json" + ``` + +To ease routine tasks like extracting correlation ID from popular event sources, we provide built-in JMESPath expressions. + +=== "Decorator" + + ```typescript hl_lines="4 14" + --8<-- "examples/snippets/logger/correlationIdPaths.ts" + ``` + +???+ note "Note: Any object key named with `-` must be escaped" + For example, **`request.headers."x-amzn-trace-id"`**. + +| Name | Expression | Description | +| ----------------------------- | ------------------------------------- | ------------------------------- | +| **API_GATEWAY_REST** | `'requestContext.requestId'` | API Gateway REST API request ID | +| **API_GATEWAY_HTTP** | `'requestContext.requestId'` | API Gateway HTTP API request ID | +| **APPSYNC_AUTHORIZER** | `'requestContext.requestId'` | AppSync resolver request ID | +| **APPSYNC_RESOLVER** | `'request.headers."x-amzn-trace-id"'` | AppSync X-Ray Trace ID | +| **APPLICATION_LOAD_BALANCER** | `'headers."x-amzn-trace-id"'` | ALB X-Ray Trace ID | +| **EVENT_BRIDGE** | `'id'` | EventBridge Event ID | +| **LAMBDA_FUNCTION_URL** | `'requestContext.requestId'` | Lambda Function URL request ID | +| **S3_OBJECT_LAMBDA** | `'xAmzRequestId'` | S3 Object trigger request ID | +| **VPC_LATTICE** | `'headers."x-amzn-trace-id'` | VPC Lattice X-Ray Trace ID | + ### Appending additional keys You can append additional keys using either mechanism: diff --git a/examples/snippets/logger/correlationIdDecorator.ts b/examples/snippets/logger/correlationIdDecorator.ts new file mode 100644 index 0000000000..f4b93fb7f4 --- /dev/null +++ b/examples/snippets/logger/correlationIdDecorator.ts @@ -0,0 +1,19 @@ +import type { LambdaInterface } from '@aws-lambda-powertools/commons/types'; +import { Logger } from '@aws-lambda-powertools/logger'; +import { search } from '@aws-lambda-powertools/logger/correlationId'; + +const logger = new Logger({ + correlationIdSearchFn: search, +}); + +class Lambda implements LambdaInterface { + @logger.injectLambdaContext({ + correlationIdPath: 'headers.my_request_id_header', + }) + public async handler(_event: unknown, _context: unknown): Promise { + logger.info('This is an INFO log with some context'); + } +} + +const myFunction = new Lambda(); +export const handler = myFunction.handler.bind(myFunction); diff --git a/examples/snippets/logger/correlationIdLogger.ts b/examples/snippets/logger/correlationIdLogger.ts new file mode 100644 index 0000000000..3c003fb0a5 --- /dev/null +++ b/examples/snippets/logger/correlationIdLogger.ts @@ -0,0 +1,6 @@ +import { Logger } from '@aws-lambda-powertools/logger'; +import { search } from '@aws-lambda-powertools/logger/correlationId'; + +const logger = new Logger({ + correlationIdSearchFn: search, +}); diff --git a/examples/snippets/logger/correlationIdManual.ts b/examples/snippets/logger/correlationIdManual.ts new file mode 100644 index 0000000000..1037bdd86f --- /dev/null +++ b/examples/snippets/logger/correlationIdManual.ts @@ -0,0 +1,10 @@ +import { Logger } from '@aws-lambda-powertools/logger'; +import type { APIGatewayProxyEvent } from 'aws-lambda'; + +const logger = new Logger(); + +export const handler = async (event: APIGatewayProxyEvent) => { + logger.setCorrelationId(event.requestContext.requestId); // (1)! + + logger.info('log with correlation_id'); +}; diff --git a/examples/snippets/logger/correlationIdMiddy.ts b/examples/snippets/logger/correlationIdMiddy.ts new file mode 100644 index 0000000000..c0a4ff10d6 --- /dev/null +++ b/examples/snippets/logger/correlationIdMiddy.ts @@ -0,0 +1,18 @@ +import { Logger } from '@aws-lambda-powertools/logger'; +import { search } from '@aws-lambda-powertools/logger/correlationId'; +import { injectLambdaContext } from '@aws-lambda-powertools/logger/middleware'; +import middy from '@middy/core'; + +const logger = new Logger({ + correlationIdSearchFn: search, +}); + +export const handler = middy() + .use( + injectLambdaContext(logger, { + correlationIdPath: 'headers.my_request_id_header', + }) + ) + .handler(async () => { + logger.info('log with correlation_id'); + }); diff --git a/examples/snippets/logger/correlationIdPaths.ts b/examples/snippets/logger/correlationIdPaths.ts new file mode 100644 index 0000000000..b6cb3f500e --- /dev/null +++ b/examples/snippets/logger/correlationIdPaths.ts @@ -0,0 +1,22 @@ +import type { LambdaInterface } from '@aws-lambda-powertools/commons/types'; +import { Logger } from '@aws-lambda-powertools/logger'; +import { + correlationPaths, + search, +} from '@aws-lambda-powertools/logger/correlationId'; + +const logger = new Logger({ + correlationIdSearchFn: search, +}); + +class Lambda implements LambdaInterface { + @logger.injectLambdaContext({ + correlationIdPath: correlationPaths.API_GATEWAY_REST, + }) + public async handler(_event: unknown, _context: unknown): Promise { + logger.info('This is an INFO log with some context'); + } +} + +const myFunction = new Lambda(); +export const handler = myFunction.handler.bind(myFunction); diff --git a/examples/snippets/logger/samples/correlationIdOutput.json b/examples/snippets/logger/samples/correlationIdOutput.json new file mode 100644 index 0000000000..b71e1984dc --- /dev/null +++ b/examples/snippets/logger/samples/correlationIdOutput.json @@ -0,0 +1,7 @@ +{ + "level": "INFO", + "message": "This is an INFO log with some context", + "timestamp": "2021-05-03 11:47:12,494+0000", + "service": "payment", + "correlation_id": "correlation_id_value" +} diff --git a/examples/snippets/logger/samples/correlationIdPayload.json b/examples/snippets/logger/samples/correlationIdPayload.json new file mode 100644 index 0000000000..ce2e8d8014 --- /dev/null +++ b/examples/snippets/logger/samples/correlationIdPayload.json @@ -0,0 +1,5 @@ +{ + "headers": { + "my_request_id_header": "correlation_id_value" + } +} diff --git a/packages/logger/package.json b/packages/logger/package.json index 544314ce05..acf8b56457 100644 --- a/packages/logger/package.json +++ b/packages/logger/package.json @@ -47,6 +47,10 @@ "./types": { "import": "./lib/esm/types/index.js", "require": "./lib/cjs/types/index.js" + }, + "./correlationId": { + "import": "./lib/esm/correlationId.js", + "require": "./lib/cjs/correlationId.js" } }, "typesVersions": { @@ -68,16 +72,18 @@ "@types/lodash.merge": "^4.6.9" }, "peerDependencies": { - "@middy/core": "4.x || 5.x || 6.x" + "@middy/core": "4.x || 5.x || 6.x", + "@aws-lambda-powertools/jmespath": "2.x" }, "peerDependenciesMeta": { "@middy/core": { "optional": true + }, + "@aws-lambda-powertools/jmespath": { + "optional": true } }, - "files": [ - "lib" - ], + "files": ["lib"], "repository": { "type": "git", "url": "git+https://github.com/aws-powertools/powertools-lambda-typescript.git" diff --git a/packages/logger/src/Logger.ts b/packages/logger/src/Logger.ts index babfc4f77c..be5ae0dba8 100644 --- a/packages/logger/src/Logger.ts +++ b/packages/logger/src/Logger.ts @@ -215,6 +215,11 @@ class Logger extends Utility implements LoggerInterface { */ #buffer?: CircularMap; + /** + * Search function for the correlation ID. + */ + #correlationIdSearchFn?: (expression: string, data: unknown) => unknown; + /** * The debug sampling rate configuration. */ @@ -326,6 +331,7 @@ class Logger extends Utility implements LoggerInterface { environment: this.powertoolsLogData.environment, persistentLogAttributes: this.persistentLogAttributes, jsonReplacerFn: this.#jsonReplacerFn, + correlationIdSearchFn: this.#correlationIdSearchFn, ...(this.#bufferConfig.enabled && { logBufferOptions: { maxBytes: this.#bufferConfig.maxBytes, @@ -480,6 +486,9 @@ class Logger extends Utility implements LoggerInterface { loggerRef.refreshSampleRateCalculation(); loggerRef.addContext(context); loggerRef.logEventIfEnabled(event, options?.logEvent); + if (options?.correlationIdPath) { + loggerRef.setCorrelationId(event, options?.correlationIdPath); + } try { return await originalMethod.apply(this, [event, context, callback]); @@ -1261,6 +1270,7 @@ class Logger extends Utility implements LoggerInterface { jsonReplacerFn, logRecordOrder, logBufferOptions, + correlationIdSearchFn, } = options; if (persistentLogAttributes && persistentKeys) { @@ -1287,6 +1297,7 @@ class Logger extends Utility implements LoggerInterface { this.setLogIndentation(); this.#jsonReplacerFn = jsonReplacerFn; this.#setLogBuffering(logBufferOptions); + this.#correlationIdSearchFn = correlationIdSearchFn; return this; } @@ -1439,6 +1450,56 @@ class Logger extends Utility implements LoggerInterface { logLevel <= this.#bufferConfig.bufferAtVerbosity ); } + + /** + * Set the correlation ID for the log item. + * This method can be used to set the correlation ID for the log item or to search for the correlation ID in the event. + * + * @example + * ```typescript + * import { Logger } from '@aws-lambda-powertools/logger'; + * + * const logger = new Logger(); + * logger.setCorrelationId('my-correlation-id'); // sets the correlation ID directly with the first argument as value + * ``` + * + * ```typescript + * import { Logger } from '@aws-lambda-powertools/logger'; + * import { search } from '@aws-lambda-powertools/logger/correlationId'; + * + * const logger = new Logger({ correlationIdSearchFn: search }); + * logger.setCorrelationId(event, 'requestContext.requestId'); // sets the correlation ID from the event using JMSPath expression + * ``` + * + * @param value - The value to set as the correlation ID or the event to search for the correlation ID + * @param correlationIdPath - Optional JMESPath expression to extract the correlation ID for the payload + */ + public setCorrelationId(value: unknown, correlationIdPath?: string): void { + if (typeof correlationIdPath === 'string') { + if (!this.#correlationIdSearchFn) { + this.warn( + 'correlationIdPath is set but no search function was provided. The correlation ID will not be added to the log attributes.' + ); + return; + } + const correlationId = this.#correlationIdSearchFn( + correlationIdPath, + value + ); + if (correlationId) this.appendKeys({ correlation_id: correlationId }); + return; + } + + // If no correlationIdPath is provided, set the correlation ID directly + this.appendKeys({ correlation_id: value }); + } + + /** + * Get the correlation ID from the log attributes. + */ + public getCorrelationId(): unknown { + return this.temporaryLogAttributes.correlation_id; + } } export { Logger }; diff --git a/packages/logger/src/correlationId.ts b/packages/logger/src/correlationId.ts new file mode 100644 index 0000000000..1e9ab271ce --- /dev/null +++ b/packages/logger/src/correlationId.ts @@ -0,0 +1,60 @@ +import type { JSONObject } from '@aws-lambda-powertools/commons/types'; +import { search as JMESPathSearch } from '@aws-lambda-powertools/jmespath'; +import { PowertoolsFunctions } from '@aws-lambda-powertools/jmespath/functions'; + +/** + * This function is used to search for a correlation ID in the event data and is a wrapper + * around the JMESPath search function. It allows you to specify a JMESPath expression + * to extract the correlation ID from the event data. + * @param expression - The JMESPath expression to use for searching the correlation ID. + * @param data - The event data to search in. + */ +const search = (expression: string, data: unknown) => { + return JMESPathSearch(expression, data as JSONObject, { + customFunctions: new PowertoolsFunctions(), + }); +}; + +/** + * The correlationPaths object contains the JMESPath expressions for extracting the correlation ID for various AWS services. + */ +const correlationPaths = { + /** + * API Gateway REST API request ID + */ + API_GATEWAY_REST: 'requestContext.requestId', + /** + * API Gateway HTTP API request ID + */ + API_GATEWAY_HTTP: 'requestContext.requestId', + /** + * AppSync API request ID + */ + APPSYNC_AUTHORIZER: 'requestContext.requestId', + /** + * AppSync resolver X-Ray trace ID + */ + APPSYNC_RESOLVER: 'request.headers."x-amzn-trace-id"', + /** + * ALB X-Ray trace ID + */ + APPLICATION_LOAD_BALANCER: 'headers."x-amzn-trace-id"', + /** + * EventBridge event ID + */ + EVENT_BRIDGE: 'id', + /** + * Lambda Function URL request ID + */ + LAMBDA_FUNCTION_URL: 'requestContext.requestId', + /** + * S3 Object trigger request ID + */ + S3_OBJECT_LAMBDA: 'xAmzRequestId', + /** + * VPC Lattice X-Ray trace ID + */ + VPC_LATTICE: 'headers."x-amzn-trace-id"', +} as const; + +export { correlationPaths, search }; diff --git a/packages/logger/src/index.ts b/packages/logger/src/index.ts index ae100eb930..f736cbff35 100644 --- a/packages/logger/src/index.ts +++ b/packages/logger/src/index.ts @@ -1,4 +1,4 @@ -export { Logger } from './Logger.js'; +export { LogLevel, LogLevelThreshold } from './constants.js'; export { LogFormatter } from './formatter/LogFormatter.js'; export { LogItem } from './formatter/LogItem.js'; -export { LogLevel, LogLevelThreshold } from './constants.js'; +export { Logger } from './Logger.js'; diff --git a/packages/logger/src/middleware/middy.ts b/packages/logger/src/middleware/middy.ts index f85b1af9f8..eeaef4fd49 100644 --- a/packages/logger/src/middleware/middy.ts +++ b/packages/logger/src/middleware/middy.ts @@ -95,6 +95,10 @@ const injectLambdaContext = ( request.context, options ); + + if (options?.correlationIdPath) { + logger.setCorrelationId(request.event, options.correlationIdPath); + } } }; diff --git a/packages/logger/src/types/Logger.ts b/packages/logger/src/types/Logger.ts index 01b7fbad20..e127f9441d 100644 --- a/packages/logger/src/types/Logger.ts +++ b/packages/logger/src/types/Logger.ts @@ -54,6 +54,11 @@ type InjectLambdaContextOptions = { * @default `false` */ flushBufferOnUncaughtError?: boolean; + + /** + * The path to the correlation ID in the event object, used to extract the correlation ID from the event object and add it to the log attributes. + */ + correlationIdPath?: string; }; /** @@ -217,13 +222,21 @@ type LogBufferOption = { }; }; +type CorrelationIdOption = { + /** + * The search function for the correlation ID. + */ + correlationIdSearchFn?: (expression: string, data: unknown) => unknown; +}; + /** * Options to configure the Logger. */ type ConstructorOptions = BaseConstructorOptions & (PersistentKeysOption | DeprecatedPersistentKeysOption) & (LogFormatterOption | LogRecordOrderOption) & - LogBufferOption; + LogBufferOption & + CorrelationIdOption; type LogItemMessage = string | LogAttributesWithMessage; type LogItemExtraInput = [Error | string] | LogAttributes[]; @@ -252,6 +265,7 @@ type LoggerInterface = { removeKeys(keys?: string[]): void; removePersistentLogAttributes(keys?: string[]): void; resetKeys(): void; + setCorrelationId(value: unknown, correlationIdPath?: string): void; setLogLevel(logLevel: LogLevel): void; setPersistentLogAttributes(attributes?: LogAttributes): void; shouldLogEvent(overwriteValue?: boolean): boolean; @@ -260,14 +274,14 @@ type LoggerInterface = { }; export type { + ConstructorOptions, + CustomJsonReplacerFn, Environment, + InjectLambdaContextOptions, LogAttributes, - LogLevel, LogFunction, LoggerInterface, - LogItemMessage, LogItemExtraInput, - ConstructorOptions, - InjectLambdaContextOptions, - CustomJsonReplacerFn, + LogItemMessage, + LogLevel, }; diff --git a/packages/logger/src/types/index.ts b/packages/logger/src/types/index.ts index 9544419a66..30a0e6a1d7 100644 --- a/packages/logger/src/types/index.ts +++ b/packages/logger/src/types/index.ts @@ -1,12 +1,12 @@ export type { - Environment, - LogAttributes, - LogLevel, - LogItemMessage, - LogItemExtraInput, ConstructorOptions, - InjectLambdaContextOptions, CustomJsonReplacerFn, + Environment, + InjectLambdaContextOptions, + LogAttributes, LoggerInterface, + LogItemExtraInput, + LogItemMessage, + LogLevel, } from './Logger.js'; export type { UnformattedAttributes } from './logKeys.js'; diff --git a/packages/logger/tests/unit/injectLambdaContext.test.ts b/packages/logger/tests/unit/injectLambdaContext.test.ts index 9518e5b6af..949969e967 100644 --- a/packages/logger/tests/unit/injectLambdaContext.test.ts +++ b/packages/logger/tests/unit/injectLambdaContext.test.ts @@ -3,6 +3,7 @@ import middy from '@middy/core'; import type { Context } from 'aws-lambda'; import { beforeEach, describe, expect, it, vi } from 'vitest'; import { Logger } from '../../src/Logger.js'; +import { search } from '../../src/correlationId.js'; import { injectLambdaContext } from '../../src/middleware/middy.js'; const event = { @@ -239,4 +240,177 @@ describe('Inject Lambda Context', () => { ); } ); + + it.each([ + { + case: 'middleware', + getHandler: (logger: Logger) => + middy(async () => { + logger.info('Hello, world!'); + }).use( + injectLambdaContext(logger, { + correlationIdPath: 'headers."x-correlation-id"', + }) + ), + }, + { + case: 'decorator', + getHandler: (logger: Logger) => { + class Lambda { + @logger.injectLambdaContext({ + correlationIdPath: 'headers."x-correlation-id"', + }) + public async handler( + _event: unknown, + _context: Context + ): Promise { + logger.info('Hello, world!'); + } + } + const lambda = new Lambda(); + return lambda.handler.bind(lambda); + }, + }, + ])('sets correlation ID through $case', async ({ getHandler }) => { + // Prepare + const logger = new Logger({ correlationIdSearchFn: search }); + const handler = getHandler(logger); + const testEvent = { + headers: { + 'x-correlation-id': '12345-test-id', + }, + }; + + // Act + await handler(testEvent, context); + + // Assess + expect(console.info).toHaveBeenCalledTimes(1); + expect(console.info).toHaveLoggedNth( + 1, + expect.objectContaining({ + message: 'Hello, world!', + correlation_id: '12345-test-id', + ...getContextLogEntries(), + }) + ); + expect(logger.getCorrelationId()).toBe('12345-test-id'); + }); + + it('warns when correlationIdPath is provided but no search function is available', async () => { + // Prepare + const logger = new Logger(); // No search function provided + const warnSpy = vi.spyOn(logger, 'warn'); + const testEvent = { + headers: { + 'x-correlation-id': '12345-test-id', + }, + }; + // Act - Use middleware which will internally call setCorrelationIdFromPath + const handler = middy(async () => { + logger.info('Hello, world!'); + }).use( + injectLambdaContext(logger, { + correlationIdPath: 'headers.x-correlation-id', + }) + ); + + await handler(testEvent, context); + + // Assess + expect(warnSpy).toHaveBeenCalledWith( + 'correlationIdPath is set but no search function was provided. The correlation ID will not be added to the log attributes.' + ); + }); + + it('does not set correlation ID when search function returns falsy value', async () => { + // Prepare + const logger = new Logger({ correlationIdSearchFn: search }); + + // Act - Use middleware which will internally call setCorrelationIdFromPath + const handler = middy(async () => { + logger.info('Hello, world!'); + }).use( + injectLambdaContext(logger, { + correlationIdPath: 'headers."non-existent"', + }) + ); + + await handler({ foo: 'bar' }, context); + + // Assess + expect(logger.getCorrelationId()).toBeUndefined(); + expect(console.info).toHaveBeenCalledTimes(1); + expect(console.info).toHaveLoggedNth( + 1, + expect.not.objectContaining({ + correlation_id: expect.anything(), + }) + ); + }); + + it('propagates search function to child loggers', () => { + // Prepare + const mockSearch = vi.fn().mockReturnValue('found-id'); + const logger = new Logger({ correlationIdSearchFn: mockSearch }); + + // Act + const childLogger = logger.createChild(); + childLogger.setCorrelationId({ some: 'event' }, 'some.path'); + + // Assess + expect(mockSearch).toHaveBeenCalledWith('some.path', { some: 'event' }); + expect(childLogger.getCorrelationId()).toBe('found-id'); + }); + + it('allows using different types as correlation ID', () => { + // Prepare + const logger = new Logger(); + const numericId = 12345; + + // Act + logger.setCorrelationId(numericId); + logger.info('Using numeric ID'); + + // Assess + expect(console.info).toHaveBeenCalledTimes(1); + expect(console.info).toHaveLoggedNth( + 1, + expect.objectContaining({ + message: 'Using numeric ID', + correlation_id: numericId, + }) + ); + expect(logger.getCorrelationId()).toBe(numericId); + }); + + it('uses the API_GATEWAY_REST predefined path to extract correlation ID', async () => { + // Prepare + const logger = new Logger({ correlationIdSearchFn: search }); + const handler = middy(async () => { + logger.info('Using API Gateway request ID'); + }).use( + injectLambdaContext(logger, { + correlationIdPath: 'requestContext.requestId', + }) + ); + const testEvent = { + requestContext: { + requestId: 'api-gateway-request-id', + }, + }; + + // Act + await handler(testEvent, context); + + // Assess + expect(console.info).toHaveBeenCalledTimes(1); + expect(console.info).toHaveLoggedNth( + 1, + expect.objectContaining({ + message: 'Using API Gateway request ID', + correlation_id: 'api-gateway-request-id', + }) + ); + }); }); From 75cc45da5f4e414eea1a201be333861163822381 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 14 Mar 2025 16:06:04 +0100 Subject: [PATCH 16/56] chore(deps): bump the aws-sdk-v3 group across 1 directory with 3 updates (#3727) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- examples/app/package.json | 2 +- examples/snippets/package.json | 4 +-- package-lock.json | 44 +++++++++++++++++-------------- packages/idempotency/package.json | 4 +-- packages/parameters/package.json | 4 +-- packages/tracer/package.json | 2 +- 6 files changed, 32 insertions(+), 28 deletions(-) diff --git a/examples/app/package.json b/examples/app/package.json index 42cfba83d1..9a7e01e634 100644 --- a/examples/app/package.json +++ b/examples/app/package.json @@ -45,7 +45,7 @@ "@aws-lambda-powertools/parameters": "^2.16.0", "@aws-lambda-powertools/tracer": "^2.16.0", "@aws-sdk/client-ssm": "^3.759.0", - "@aws-sdk/lib-dynamodb": "^3.758.0", + "@aws-sdk/lib-dynamodb": "^3.767.0", "@middy/core": "^4.7.0", "@types/aws-lambda": "^8.10.147", "@types/node": "22.13.10", diff --git a/examples/snippets/package.json b/examples/snippets/package.json index 403c574f4b..8f9e4e18d4 100644 --- a/examples/snippets/package.json +++ b/examples/snippets/package.json @@ -33,10 +33,10 @@ "@aws-lambda-powertools/parser": "^2.16.0", "@aws-lambda-powertools/tracer": "^2.16.0", "@aws-sdk/client-appconfigdata": "^3.758.0", - "@aws-sdk/client-dynamodb": "^3.758.0", + "@aws-sdk/client-dynamodb": "^3.767.0", "@aws-sdk/client-secrets-manager": "^3.758.0", "@aws-sdk/client-ssm": "^3.759.0", - "@aws-sdk/util-dynamodb": "^3.758.0", + "@aws-sdk/util-dynamodb": "^3.767.0", "@middy/core": "^4.7.0", "aws-sdk": "^2.1692.0", "aws-sdk-client-mock": "^4.1.0", diff --git a/package-lock.json b/package-lock.json index 2b34c4fa10..aa6244ffd6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -59,7 +59,7 @@ "@aws-lambda-powertools/parameters": "^2.16.0", "@aws-lambda-powertools/tracer": "^2.16.0", "@aws-sdk/client-ssm": "^3.759.0", - "@aws-sdk/lib-dynamodb": "^3.758.0", + "@aws-sdk/lib-dynamodb": "^3.767.0", "@middy/core": "^4.7.0", "@types/aws-lambda": "^8.10.147", "@types/node": "22.13.10", @@ -93,10 +93,10 @@ "@aws-lambda-powertools/parser": "^2.16.0", "@aws-lambda-powertools/tracer": "^2.16.0", "@aws-sdk/client-appconfigdata": "^3.758.0", - "@aws-sdk/client-dynamodb": "^3.758.0", + "@aws-sdk/client-dynamodb": "^3.767.0", "@aws-sdk/client-secrets-manager": "^3.758.0", "@aws-sdk/client-ssm": "^3.759.0", - "@aws-sdk/util-dynamodb": "^3.758.0", + "@aws-sdk/util-dynamodb": "^3.767.0", "@middy/core": "^4.7.0", "aws-sdk": "^2.1692.0", "aws-sdk-client-mock": "^4.1.0", @@ -2951,9 +2951,9 @@ } }, "node_modules/@aws-sdk/client-dynamodb": { - "version": "3.758.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-dynamodb/-/client-dynamodb-3.758.0.tgz", - "integrity": "sha512-ZdVVCvmQ4wlV22HgYZKndIYNKkFfTLi8PIOF5rOkqthgYRTfVzKajrVbYebCs5jMDTk73LPLl2Ze/EYBEHKlBA==", + "version": "3.767.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-dynamodb/-/client-dynamodb-3.767.0.tgz", + "integrity": "sha512-uoZFUnQr9jhxPdhPz0o4/1osstDXdteOIw8tNRTe3JKK9eIWAG3YrVv9wfJPxEFUGvntUe+anvdiy+8ycKmsYQ==", "license": "Apache-2.0", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", @@ -6348,13 +6348,13 @@ } }, "node_modules/@aws-sdk/lib-dynamodb": { - "version": "3.758.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/lib-dynamodb/-/lib-dynamodb-3.758.0.tgz", - "integrity": "sha512-lkxh7nkFMHY2zbPxhGQz7hVA43yRPu+ERrSiRu7I11arAOz/MJlt7MjHmt0B8x7x6isF1utNixkU28HKh9hgWQ==", + "version": "3.767.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/lib-dynamodb/-/lib-dynamodb-3.767.0.tgz", + "integrity": "sha512-Vl93kIcntUzVdnJZf1VgHhtkue8Xk6pVK3L5hoc90z2RUlqLyl279+LiK8lE5xYaiRTxoCu+BI0dxSp0F1G8YQ==", "license": "Apache-2.0", "dependencies": { "@aws-sdk/core": "3.758.0", - "@aws-sdk/util-dynamodb": "3.758.0", + "@aws-sdk/util-dynamodb": "3.767.0", "@smithy/core": "^3.1.5", "@smithy/smithy-client": "^4.1.6", "@smithy/types": "^4.1.0", @@ -6364,7 +6364,7 @@ "node": ">=18.0.0" }, "peerDependencies": { - "@aws-sdk/client-dynamodb": "^3.758.0" + "@aws-sdk/client-dynamodb": "^3.767.0" } }, "node_modules/@aws-sdk/lib-storage": { @@ -6755,9 +6755,9 @@ } }, "node_modules/@aws-sdk/util-dynamodb": { - "version": "3.758.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-dynamodb/-/util-dynamodb-3.758.0.tgz", - "integrity": "sha512-JjBbhJLajilyMWJ/z82bYgIMj9XGISZ/QMYSpNBdzGFRmL1AL9s6NwLB6FuquRvpY9Lo3Y5vwEbedqdZPIrRFg==", + "version": "3.767.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-dynamodb/-/util-dynamodb-3.767.0.tgz", + "integrity": "sha512-/unz0bnrEc6XyVFai4drJipigb2B2NdK9Hku5V7Tq3a98YQtDvi5aLdWFt3pte38FqKW4snU1v15sbl3ZH1i5A==", "license": "Apache-2.0", "dependencies": { "tslib": "^2.6.2" @@ -6766,7 +6766,7 @@ "node": ">=18.0.0" }, "peerDependencies": { - "@aws-sdk/client-dynamodb": "^3.758.0" + "@aws-sdk/client-dynamodb": "^3.767.0" } }, "node_modules/@aws-sdk/util-endpoints": { @@ -21490,8 +21490,8 @@ }, "devDependencies": { "@aws-lambda-powertools/testing-utils": "file:../testing", - "@aws-sdk/client-dynamodb": "^3.758.0", - "@aws-sdk/lib-dynamodb": "^3.758.0", + "@aws-sdk/client-dynamodb": "^3.767.0", + "@aws-sdk/lib-dynamodb": "^3.767.0", "aws-sdk-client-mock": "^4.1.0" }, "peerDependencies": { @@ -21532,9 +21532,13 @@ "@types/lodash.merge": "^4.6.9" }, "peerDependencies": { + "@aws-lambda-powertools/jmespath": "2.x", "@middy/core": "4.x || 5.x || 6.x" }, "peerDependenciesMeta": { + "@aws-lambda-powertools/jmespath": { + "optional": true + }, "@middy/core": { "optional": true } @@ -21572,10 +21576,10 @@ "devDependencies": { "@aws-lambda-powertools/testing-utils": "file:../testing", "@aws-sdk/client-appconfigdata": "^3.758.0", - "@aws-sdk/client-dynamodb": "^3.758.0", + "@aws-sdk/client-dynamodb": "^3.767.0", "@aws-sdk/client-secrets-manager": "^3.758.0", "@aws-sdk/client-ssm": "^3.759.0", - "@aws-sdk/util-dynamodb": "^3.758.0", + "@aws-sdk/util-dynamodb": "^3.767.0", "@smithy/util-base64": "^4.0.0", "aws-sdk-client-mock": "^4.1.0" }, @@ -21655,7 +21659,7 @@ }, "devDependencies": { "@aws-lambda-powertools/testing-utils": "file:../testing", - "@aws-sdk/client-dynamodb": "^3.758.0", + "@aws-sdk/client-dynamodb": "^3.767.0", "@aws-sdk/client-xray": "^3.758.0" }, "peerDependencies": { diff --git a/packages/idempotency/package.json b/packages/idempotency/package.json index f788caf2b3..4a7d9c5077 100644 --- a/packages/idempotency/package.json +++ b/packages/idempotency/package.json @@ -127,8 +127,8 @@ ], "devDependencies": { "@aws-lambda-powertools/testing-utils": "file:../testing", - "@aws-sdk/client-dynamodb": "^3.758.0", - "@aws-sdk/lib-dynamodb": "^3.758.0", + "@aws-sdk/client-dynamodb": "^3.767.0", + "@aws-sdk/lib-dynamodb": "^3.767.0", "aws-sdk-client-mock": "^4.1.0" } } diff --git a/packages/parameters/package.json b/packages/parameters/package.json index 57260ad26b..fc7e34366b 100644 --- a/packages/parameters/package.json +++ b/packages/parameters/package.json @@ -157,10 +157,10 @@ "devDependencies": { "@aws-lambda-powertools/testing-utils": "file:../testing", "@aws-sdk/client-appconfigdata": "^3.758.0", - "@aws-sdk/client-dynamodb": "^3.758.0", + "@aws-sdk/client-dynamodb": "^3.767.0", "@aws-sdk/client-secrets-manager": "^3.758.0", "@aws-sdk/client-ssm": "^3.759.0", - "@aws-sdk/util-dynamodb": "^3.758.0", + "@aws-sdk/util-dynamodb": "^3.767.0", "@smithy/util-base64": "^4.0.0", "aws-sdk-client-mock": "^4.1.0" }, diff --git a/packages/tracer/package.json b/packages/tracer/package.json index b6fa0a6feb..09eb0517bf 100644 --- a/packages/tracer/package.json +++ b/packages/tracer/package.json @@ -30,7 +30,7 @@ "license": "MIT-0", "devDependencies": { "@aws-lambda-powertools/testing-utils": "file:../testing", - "@aws-sdk/client-dynamodb": "^3.758.0", + "@aws-sdk/client-dynamodb": "^3.767.0", "@aws-sdk/client-xray": "^3.758.0" }, "peerDependencies": { From 5d5fd55d6ce92c0d28dd5b284e2b874d626fce54 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 14 Mar 2025 17:15:27 +0100 Subject: [PATCH 17/56] chore(deps): bump squidfunk/mkdocs-material from `047452c` to `479a06a` in /docs (#3719) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Andrea Amorosi --- docs/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/Dockerfile b/docs/Dockerfile index 5db3fb151f..a5e04b5275 100644 --- a/docs/Dockerfile +++ b/docs/Dockerfile @@ -1,5 +1,5 @@ # version 9.5.35 -FROM squidfunk/mkdocs-material@sha256:047452c6641137c9caa3647d050ddb7fa67b59ed48cc67ec3a4995f3d360ab32 +FROM squidfunk/mkdocs-material@sha256:479a06a8f5a320a9b2b17e72cb7012388d66ea71a8568235cfa072eb152bc30c # Install Node.js RUN apk add --no-cache nodejs=20.15.1-r0 npm From 962dd0123ffc568cc19fe7b6273257df5dc73845 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 14 Mar 2025 17:30:20 +0100 Subject: [PATCH 18/56] chore(deps-dev): bump lint-staged from 15.4.3 to 15.5.0 (#3720) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Andrea Amorosi --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index aa6244ffd6..fb8505b354 100644 --- a/package-lock.json +++ b/package-lock.json @@ -32,7 +32,7 @@ "@vitest/coverage-v8": "^3.0.8", "husky": "^9.1.7", "lerna": "8.1.2", - "lint-staged": "^15.4.3", + "lint-staged": "^15.5.0", "markdownlint-cli2": "^0.17.2", "middy4": "npm:@middy/core@^4.7.0", "middy5": "npm:@middy/core@^5.4.3", @@ -15201,9 +15201,9 @@ } }, "node_modules/lint-staged": { - "version": "15.4.3", - "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-15.4.3.tgz", - "integrity": "sha512-FoH1vOeouNh1pw+90S+cnuoFwRfUD9ijY2GKy5h7HS3OR7JVir2N2xrsa0+Twc1B7cW72L+88geG5cW4wIhn7g==", + "version": "15.5.0", + "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-15.5.0.tgz", + "integrity": "sha512-WyCzSbfYGhK7cU+UuDDkzUiytbfbi0ZdPy2orwtM75P3WTtQBzmG40cCxIa8Ii2+XjfxzLH6Be46tUfWS85Xfg==", "dev": true, "license": "MIT", "dependencies": { diff --git a/package.json b/package.json index 2c4877e3ca..e605df0bd1 100644 --- a/package.json +++ b/package.json @@ -56,7 +56,7 @@ "@vitest/coverage-v8": "^3.0.8", "husky": "^9.1.7", "lerna": "8.1.2", - "lint-staged": "^15.4.3", + "lint-staged": "^15.5.0", "markdownlint-cli2": "^0.17.2", "middy4": "npm:@middy/core@^4.7.0", "middy5": "npm:@middy/core@^5.4.3", From 17934878d6d62a6f11779ce08d695f42a938647d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 14 Mar 2025 17:45:06 +0100 Subject: [PATCH 19/56] chore(deps): bump the aws-cdk group across 1 directory with 3 updates (#3728) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- examples/app/package.json | 4 +- layers/package.json | 4 +- package-lock.json | 162 ++++++++++++++-------------------- packages/testing/package.json | 4 +- 4 files changed, 73 insertions(+), 101 deletions(-) diff --git a/examples/app/package.json b/examples/app/package.json index 9a7e01e634..78ac519678 100644 --- a/examples/app/package.json +++ b/examples/app/package.json @@ -30,7 +30,7 @@ "devDependencies": { "@types/aws-lambda": "^8.10.147", "@types/node": "22.13.10", - "aws-cdk-lib": "^2.183.0", + "aws-cdk-lib": "^2.184.1", "constructs": "^10.4.2", "source-map-support": "^0.5.21", "tsx": "^4.19.3", @@ -49,7 +49,7 @@ "@middy/core": "^4.7.0", "@types/aws-lambda": "^8.10.147", "@types/node": "22.13.10", - "aws-cdk": "^2.1003.0", + "aws-cdk": "^2.1004.0", "constructs": "^10.4.2", "esbuild": "^0.25.1", "typescript": "^5.8.2" diff --git a/layers/package.json b/layers/package.json index a6380c4495..2792d85ebc 100644 --- a/layers/package.json +++ b/layers/package.json @@ -40,8 +40,8 @@ "source-map-support": "^0.5.21" }, "dependencies": { - "aws-cdk": "^2.1003.0", - "aws-cdk-lib": "^2.183.0", + "aws-cdk": "^2.1004.0", + "aws-cdk-lib": "^2.184.1", "esbuild": "^0.25.1", "tsx": "^4.19.3" } diff --git a/package-lock.json b/package-lock.json index fb8505b354..a234abdf71 100644 --- a/package-lock.json +++ b/package-lock.json @@ -63,7 +63,7 @@ "@middy/core": "^4.7.0", "@types/aws-lambda": "^8.10.147", "@types/node": "22.13.10", - "aws-cdk": "^2.1003.0", + "aws-cdk": "^2.1004.0", "constructs": "^10.4.2", "esbuild": "^0.25.1", "typescript": "^5.8.2" @@ -71,7 +71,7 @@ "devDependencies": { "@types/aws-lambda": "^8.10.147", "@types/node": "22.13.10", - "aws-cdk-lib": "^2.183.0", + "aws-cdk-lib": "^2.184.1", "constructs": "^10.4.2", "source-map-support": "^0.5.21", "tsx": "^4.19.3", @@ -108,8 +108,8 @@ "version": "2.16.0", "license": "MIT-0", "dependencies": { - "aws-cdk": "^2.1003.0", - "aws-cdk-lib": "^2.183.0", + "aws-cdk": "^2.1004.0", + "aws-cdk-lib": "^2.184.1", "esbuild": "^0.25.1", "tsx": "^4.19.3" }, @@ -135,9 +135,10 @@ } }, "node_modules/@aws-cdk/asset-awscli-v1": { - "version": "2.2.209", - "resolved": "https://registry.npmjs.org/@aws-cdk/asset-awscli-v1/-/asset-awscli-v1-2.2.209.tgz", - "integrity": "sha512-tL7aBDzx/QBuZoQso9OST2BMCoev89v01iQZicOKlR0J6vWQLPiqZfn4vd9nissFbM4X+xIwi3UKasPBTQL0WQ==" + "version": "2.2.227", + "resolved": "https://registry.npmjs.org/@aws-cdk/asset-awscli-v1/-/asset-awscli-v1-2.2.227.tgz", + "integrity": "sha512-BAZwZGtX166K9KRYnRBbRj/fU0FY00LOnki11OsDQMfZ9H6tno+LIhv/ZY5U4LGIaI8yP881pAhbrVxpKQnYLg==", + "license": "Apache-2.0" }, "node_modules/@aws-cdk/asset-node-proxy-agent-v6": { "version": "2.1.0", @@ -217,6 +218,35 @@ "node": ">= 14.15.0" } }, + "node_modules/@aws-cdk/cx-api": { + "version": "2.184.1", + "resolved": "https://registry.npmjs.org/@aws-cdk/cx-api/-/cx-api-2.184.1.tgz", + "integrity": "sha512-D2JbqzU5uEkol0LEglTb3cjdbS3o9jbUrEZfBSk7zNb6Kjzu06TgYajcL/ZwAxYKs7U1HenwRaXBofPYENReGg==", + "bundleDependencies": [ + "semver" + ], + "license": "Apache-2.0", + "dependencies": { + "semver": "^7.7.1" + }, + "engines": { + "node": ">= 14.15.0" + }, + "peerDependencies": { + "@aws-cdk/cloud-assembly-schema": "^40.6.0" + } + }, + "node_modules/@aws-cdk/cx-api/node_modules/semver": { + "version": "7.7.1", + "inBundle": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/@aws-cdk/region-info": { "version": "2.183.0", "resolved": "https://registry.npmjs.org/@aws-cdk/region-info/-/region-info-2.183.0.tgz", @@ -236,12 +266,12 @@ } }, "node_modules/@aws-cdk/toolkit-lib": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/@aws-cdk/toolkit-lib/-/toolkit-lib-0.1.4.tgz", - "integrity": "sha512-i+LWGu9st+bDPQmKG2ml+xqICLnhXhDQLYBb1m1qKp8GaMyPd7r3mYkTakX5StPVhrUgb4Tsu/zH0qjSCOYvoA==", + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/@aws-cdk/toolkit-lib/-/toolkit-lib-0.1.5.tgz", + "integrity": "sha512-C8+LjlkSFXQqVV9ZyhQ1VSkg6uMvwgnN5Fwp5l0+d3g/aR82YK3cVJYPppNjHZ4w4dOVErprVM4OdIfyf7Vmkg==", "license": "Apache-2.0", "dependencies": { - "@aws-cdk/cloud-assembly-schema": "^41.0.0", + "@aws-cdk/cloud-assembly-schema": "^41.1.0", "@aws-cdk/cloudformation-diff": "^2.179.0", "@aws-cdk/cx-api": "^2.181.1", "@aws-cdk/region-info": "^2.181.1", @@ -275,7 +305,7 @@ "@smithy/util-waiter": "^4.0.2", "archiver": "^7.0.1", "camelcase": "^6", - "cdk-assets": "^3.1.0", + "cdk-assets": "^3.1.1", "cdk-from-cfn": "^0.193.0", "chalk": "^4", "chokidar": "^3", @@ -301,9 +331,9 @@ } }, "node_modules/@aws-cdk/toolkit-lib/node_modules/@aws-cdk/cloud-assembly-schema": { - "version": "41.0.0", - "resolved": "https://registry.npmjs.org/@aws-cdk/cloud-assembly-schema/-/cloud-assembly-schema-41.0.0.tgz", - "integrity": "sha512-Jgs3gelFN0Ghr5tbAhPxRsf78jKLGrMbUno4nXTGz3QiPkFqfrq0kodxmKP/IVSp55A5I3CsJ5QErQTit39GdA==", + "version": "41.1.0", + "resolved": "https://registry.npmjs.org/@aws-cdk/cloud-assembly-schema/-/cloud-assembly-schema-41.1.0.tgz", + "integrity": "sha512-V+twOy4asXv6IIH1jxanugBOhBjRdC0Wsr56fSmN8fECp5aJQeqZ5XAiuFSCfwkNoJa72P0cMDm5eFsLK3PzhQ==", "bundleDependencies": [ "jsonschema", "semver" @@ -336,35 +366,6 @@ "node": ">=10" } }, - "node_modules/@aws-cdk/toolkit-lib/node_modules/@aws-cdk/cx-api": { - "version": "2.183.0", - "resolved": "https://registry.npmjs.org/@aws-cdk/cx-api/-/cx-api-2.183.0.tgz", - "integrity": "sha512-14HcLwL/lPNnBdSfpFK0C6XSkgBv/35lgyzNPsmghSHmUX8OKlv5or1HFLAL2E7Jhp5b8KHsTxw3o8IoeU3tHw==", - "bundleDependencies": [ - "semver" - ], - "license": "Apache-2.0", - "dependencies": { - "semver": "^7.6.3" - }, - "engines": { - "node": ">= 14.15.0" - }, - "peerDependencies": { - "@aws-cdk/cloud-assembly-schema": "^40.6.0" - } - }, - "node_modules/@aws-cdk/toolkit-lib/node_modules/@aws-cdk/cx-api/node_modules/semver": { - "version": "7.6.3", - "inBundle": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/@aws-cdk/toolkit-lib/node_modules/camelcase": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", @@ -10761,9 +10762,9 @@ } }, "node_modules/aws-cdk": { - "version": "2.1003.0", - "resolved": "https://registry.npmjs.org/aws-cdk/-/aws-cdk-2.1003.0.tgz", - "integrity": "sha512-FORPDGW8oUg4tXFlhX+lv/j+152LO9wwi3/CwNr1WY3c3HwJUtc0fZGb2B3+Fzy6NhLWGHJclUsJPEhjEt8Nhg==", + "version": "2.1004.0", + "resolved": "https://registry.npmjs.org/aws-cdk/-/aws-cdk-2.1004.0.tgz", + "integrity": "sha512-3E5ICmSc7ZCZCwLX7NY+HFmmdUYgRaL+67h/BDoDQmkhx9StC8wG4xgzHFY9k8WQS0+ib/MP28f2d9yzHtQLlQ==", "license": "Apache-2.0", "bin": { "cdk": "bin/cdk" @@ -10776,9 +10777,9 @@ } }, "node_modules/aws-cdk-lib": { - "version": "2.183.0", - "resolved": "https://registry.npmjs.org/aws-cdk-lib/-/aws-cdk-lib-2.183.0.tgz", - "integrity": "sha512-xwdDMm7qKBgN+dRjn8XxwS0YDRFM9JnUavFWM2bzaOzFeaBCiwFMrG0xLZaZs6GBImV804/jj8PnjmbOCsDZdw==", + "version": "2.184.1", + "resolved": "https://registry.npmjs.org/aws-cdk-lib/-/aws-cdk-lib-2.184.1.tgz", + "integrity": "sha512-No9g0SGadiDz0IEUIeJg4wSV/jFCGcouW2zUOTjV8OU4gTMoGiqC8BYSv7E6ucUtW6rmSFVK+pbc8XOFZOo1cg==", "bundleDependencies": [ "@balena/dockerignore", "case", @@ -10794,19 +10795,19 @@ ], "license": "Apache-2.0", "dependencies": { - "@aws-cdk/asset-awscli-v1": "^2.2.208", + "@aws-cdk/asset-awscli-v1": "^2.2.227", "@aws-cdk/asset-node-proxy-agent-v6": "^2.1.0", - "@aws-cdk/cloud-assembly-schema": "^40.6.0", + "@aws-cdk/cloud-assembly-schema": "^40.7.0", "@balena/dockerignore": "^1.0.2", "case": "1.6.3", - "fs-extra": "^11.2.0", + "fs-extra": "^11.3.0", "ignore": "^5.3.2", - "jsonschema": "^1.4.1", + "jsonschema": "^1.5.0", "mime-types": "^2.1.35", "minimatch": "^3.1.2", "punycode": "^2.3.1", - "semver": "^7.6.3", - "table": "^6.8.2", + "semver": "^7.7.1", + "table": "^6.9.0", "yaml": "1.10.2" }, "engines": { @@ -11044,7 +11045,7 @@ } }, "node_modules/aws-cdk-lib/node_modules/semver": { - "version": "7.6.3", + "version": "7.7.1", "inBundle": true, "license": "ISC", "bin": { @@ -11507,12 +11508,12 @@ } }, "node_modules/cdk-assets": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/cdk-assets/-/cdk-assets-3.1.0.tgz", - "integrity": "sha512-4xO5mRzdxqTxiar7+Y8qOy/yWoY1yaW8y3XrhBsSiwhldRuDbXYkn4O1HmCV35i+ietS2nUnRQ+zYucdF/6A5Q==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/cdk-assets/-/cdk-assets-3.1.1.tgz", + "integrity": "sha512-EGu1vbmfkfNEf3cHJek522UHUoKlL+na1gCqeei3c2amhoRRPSn0n96SOU7wFz5RvSh/Ruizi4pEVROddN76AA==", "license": "Apache-2.0", "dependencies": { - "@aws-cdk/cloud-assembly-schema": "^41.0.0", + "@aws-cdk/cloud-assembly-schema": "^41.1.0", "@aws-cdk/cx-api": "^2.181.1", "@aws-sdk/client-ecr": "^3", "@aws-sdk/client-s3": "^3", @@ -11536,9 +11537,9 @@ } }, "node_modules/cdk-assets/node_modules/@aws-cdk/cloud-assembly-schema": { - "version": "41.0.0", - "resolved": "https://registry.npmjs.org/@aws-cdk/cloud-assembly-schema/-/cloud-assembly-schema-41.0.0.tgz", - "integrity": "sha512-Jgs3gelFN0Ghr5tbAhPxRsf78jKLGrMbUno4nXTGz3QiPkFqfrq0kodxmKP/IVSp55A5I3CsJ5QErQTit39GdA==", + "version": "41.1.0", + "resolved": "https://registry.npmjs.org/@aws-cdk/cloud-assembly-schema/-/cloud-assembly-schema-41.1.0.tgz", + "integrity": "sha512-V+twOy4asXv6IIH1jxanugBOhBjRdC0Wsr56fSmN8fECp5aJQeqZ5XAiuFSCfwkNoJa72P0cMDm5eFsLK3PzhQ==", "bundleDependencies": [ "jsonschema", "semver" @@ -11571,35 +11572,6 @@ "node": ">=10" } }, - "node_modules/cdk-assets/node_modules/@aws-cdk/cx-api": { - "version": "2.183.0", - "resolved": "https://registry.npmjs.org/@aws-cdk/cx-api/-/cx-api-2.183.0.tgz", - "integrity": "sha512-14HcLwL/lPNnBdSfpFK0C6XSkgBv/35lgyzNPsmghSHmUX8OKlv5or1HFLAL2E7Jhp5b8KHsTxw3o8IoeU3tHw==", - "bundleDependencies": [ - "semver" - ], - "license": "Apache-2.0", - "dependencies": { - "semver": "^7.6.3" - }, - "engines": { - "node": ">= 14.15.0" - }, - "peerDependencies": { - "@aws-cdk/cloud-assembly-schema": "^40.6.0" - } - }, - "node_modules/cdk-assets/node_modules/@aws-cdk/cx-api/node_modules/semver": { - "version": "7.6.3", - "inBundle": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/cdk-assets/node_modules/glob": { "version": "11.0.1", "resolved": "https://registry.npmjs.org/glob/-/glob-11.0.1.tgz", @@ -21637,10 +21609,10 @@ "version": "2.16.0", "license": "MIT-0", "dependencies": { - "@aws-cdk/toolkit-lib": "^0.1.4", + "@aws-cdk/toolkit-lib": "^0.1.5", "@aws-sdk/client-lambda": "^3.758.0", "@smithy/util-utf8": "^4.0.0", - "aws-cdk-lib": "^2.183.0", + "aws-cdk-lib": "^2.184.1", "esbuild": "^0.25.1", "promise-retry": "^2.0.1" }, diff --git a/packages/testing/package.json b/packages/testing/package.json index df637496af..936fc76df8 100644 --- a/packages/testing/package.json +++ b/packages/testing/package.json @@ -97,10 +97,10 @@ }, "homepage": "https://github.com/aws-powertools/powertools-lambda-typescript/tree/main/packages/testing#readme", "dependencies": { - "@aws-cdk/toolkit-lib": "^0.1.4", + "@aws-cdk/toolkit-lib": "^0.1.5", "@aws-sdk/client-lambda": "^3.758.0", "@smithy/util-utf8": "^4.0.0", - "aws-cdk-lib": "^2.183.0", + "aws-cdk-lib": "^2.184.1", "esbuild": "^0.25.1", "promise-retry": "^2.0.1" }, From 204e7e13862e6bed118372c090aaa1ea557cde2b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 14 Mar 2025 18:30:25 +0100 Subject: [PATCH 20/56] chore(deps): bump mkdocs-material from 9.6.7 to 9.6.8 in /docs (#3721) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Andrea Amorosi --- docs/requirements.in | 2 +- docs/requirements.txt | 16 ++++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/docs/requirements.in b/docs/requirements.in index 99df90a461..8bff50e938 100644 --- a/docs/requirements.in +++ b/docs/requirements.in @@ -1,5 +1,5 @@ mike==1.1.2 -mkdocs-material==9.6.7 +mkdocs-material==9.6.8 mkdocs-git-revision-date-plugin==0.3.2 mkdocs-exclude==1.0.2 mkdocs-typedoc==1.0.4 \ No newline at end of file diff --git a/docs/requirements.txt b/docs/requirements.txt index 4dff4bac49..33c9cee13e 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -224,7 +224,7 @@ mergedeep==1.3.4 \ mike==1.1.2 \ --hash=sha256:4c307c28769834d78df10f834f57f810f04ca27d248f80a75f49c6fa2d1527ca \ --hash=sha256:56c3f1794c2d0b5fdccfa9b9487beb013ca813de2e3ad0744724e9d34d40b77b - # via -r docs/requirements.in + # via -r requirements.in mkdocs==1.6.1 \ --hash=sha256:7b432f01d928c084353ab39c57282f29f92136665bdd6abf7c1ec8d822ef86f2 \ --hash=sha256:db91759624d1647f3f34aa0c3f327dd2601beae39a366d6e064c03468d35c20e @@ -236,18 +236,18 @@ mkdocs==1.6.1 \ # mkdocs-typedoc mkdocs-exclude==1.0.2 \ --hash=sha256:ba6fab3c80ddbe3fd31d3e579861fd3124513708271180a5f81846da8c7e2a51 - # via -r docs/requirements.in + # via -r requirements.in mkdocs-get-deps==0.2.0 \ --hash=sha256:162b3d129c7fad9b19abfdcb9c1458a651628e4b1dea628ac68790fb3061c60c \ --hash=sha256:2bf11d0b133e77a0dd036abeeb06dec8775e46efa526dc70667d8863eefc6134 # via mkdocs mkdocs-git-revision-date-plugin==0.3.2 \ --hash=sha256:2e67956cb01823dd2418e2833f3623dee8604cdf223bddd005fe36226a56f6ef - # via -r docs/requirements.in -mkdocs-material==9.6.7 \ - --hash=sha256:3e2c1fceb9410056c2d91f334a00cdea3215c28750e00c691c1e46b2a33309b4 \ - --hash=sha256:8a159e45e80fcaadd9fbeef62cbf928569b93df954d4dc5ba76d46820caf7b47 - # via -r docs/requirements.in + # via -r requirements.in +mkdocs-material==9.6.8 \ + --hash=sha256:0a51532dd8aa80b232546c073fe3ef60dfaef1b1b12196ac7191ee01702d1cf8 \ + --hash=sha256:8de31bb7566379802532b248bd56d9c4bc834afc4625884bf5769f9412c6a354 + # via -r requirements.in mkdocs-material-extensions==1.3.1 \ --hash=sha256:10c9511cea88f568257f960358a467d12b970e1f7b2c0e5fb2bb48cab1928443 \ --hash=sha256:adff8b62700b25cb77b53358dad940f3ef973dd6db797907c49e3c2ef3ab4e31 @@ -255,7 +255,7 @@ mkdocs-material-extensions==1.3.1 \ mkdocs-typedoc==1.0.4 \ --hash=sha256:839b54c51a64bbb77c1c253eb81baad12462ea5cf38d361e262f5cfa8a45567a \ --hash=sha256:a9601d6b04ed4fd5658c7170c58a3a52f584357be2a3c1e39995c6eed3712b1e - # via -r docs/requirements.in + # via -r requirements.in packaging==24.1 \ --hash=sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002 \ --hash=sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124 From d005ef6a12378cc433fb5c2211df4acf5e291314 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 17 Mar 2025 15:55:07 +0100 Subject: [PATCH 21/56] chore(deps-dev): bump the vitest group across 1 directory with 2 updates (#3734) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 268 +++++++++++++++++++++++----------------------- package.json | 2 +- 2 files changed, 135 insertions(+), 135 deletions(-) diff --git a/package-lock.json b/package-lock.json index a234abdf71..c7d28b2159 100644 --- a/package-lock.json +++ b/package-lock.json @@ -29,7 +29,7 @@ "@biomejs/biome": "^1.9.4", "@types/aws-lambda": "^8.10.147", "@types/node": "^22.13.10", - "@vitest/coverage-v8": "^3.0.8", + "@vitest/coverage-v8": "^3.0.9", "husky": "^9.1.7", "lerna": "8.1.2", "lint-staged": "^15.5.0", @@ -8534,9 +8534,9 @@ } }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.35.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.35.0.tgz", - "integrity": "sha512-uYQ2WfPaqz5QtVgMxfN6NpLD+no0MYHDBywl7itPYd3K5TjjSghNKmX8ic9S8NU8w81NVhJv/XojcHptRly7qQ==", + "version": "4.36.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.36.0.tgz", + "integrity": "sha512-jgrXjjcEwN6XpZXL0HUeOVGfjXhPyxAbbhD0BlXUB+abTOpbPiN5Wb3kOT7yb+uEtATNYF5x5gIfwutmuBA26w==", "cpu": [ "arm" ], @@ -8548,9 +8548,9 @@ ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.35.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.35.0.tgz", - "integrity": "sha512-FtKddj9XZudurLhdJnBl9fl6BwCJ3ky8riCXjEw3/UIbjmIY58ppWwPEvU3fNu+W7FUsAsB1CdH+7EQE6CXAPA==", + "version": "4.36.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.36.0.tgz", + "integrity": "sha512-NyfuLvdPdNUfUNeYKUwPwKsE5SXa2J6bCt2LdB/N+AxShnkpiczi3tcLJrm5mA+eqpy0HmaIY9F6XCa32N5yzg==", "cpu": [ "arm64" ], @@ -8562,9 +8562,9 @@ ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.35.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.35.0.tgz", - "integrity": "sha512-Uk+GjOJR6CY844/q6r5DR/6lkPFOw0hjfOIzVx22THJXMxktXG6CbejseJFznU8vHcEBLpiXKY3/6xc+cBm65Q==", + "version": "4.36.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.36.0.tgz", + "integrity": "sha512-JQ1Jk5G4bGrD4pWJQzWsD8I1n1mgPXq33+/vP4sk8j/z/C2siRuxZtaUA7yMTf71TCZTZl/4e1bfzwUmFb3+rw==", "cpu": [ "arm64" ], @@ -8576,9 +8576,9 @@ ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.35.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.35.0.tgz", - "integrity": "sha512-3IrHjfAS6Vkp+5bISNQnPogRAW5GAV1n+bNCrDwXmfMHbPl5EhTmWtfmwlJxFRUCBZ+tZ/OxDyU08aF6NI/N5Q==", + "version": "4.36.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.36.0.tgz", + "integrity": "sha512-6c6wMZa1lrtiRsbDziCmjE53YbTkxMYhhnWnSW8R/yqsM7a6mSJ3uAVT0t8Y/DGt7gxUWYuFM4bwWk9XCJrFKA==", "cpu": [ "x64" ], @@ -8590,9 +8590,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.35.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.35.0.tgz", - "integrity": "sha512-sxjoD/6F9cDLSELuLNnY0fOrM9WA0KrM0vWm57XhrIMf5FGiN8D0l7fn+bpUeBSU7dCgPV2oX4zHAsAXyHFGcQ==", + "version": "4.36.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.36.0.tgz", + "integrity": "sha512-KXVsijKeJXOl8QzXTsA+sHVDsFOmMCdBRgFmBb+mfEb/7geR7+C8ypAml4fquUt14ZyVXaw2o1FWhqAfOvA4sg==", "cpu": [ "arm64" ], @@ -8604,9 +8604,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.35.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.35.0.tgz", - "integrity": "sha512-2mpHCeRuD1u/2kruUiHSsnjWtHjqVbzhBkNVQ1aVD63CcexKVcQGwJ2g5VphOd84GvxfSvnnlEyBtQCE5hxVVw==", + "version": "4.36.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.36.0.tgz", + "integrity": "sha512-dVeWq1ebbvByI+ndz4IJcD4a09RJgRYmLccwlQ8bPd4olz3Y213uf1iwvc7ZaxNn2ab7bjc08PrtBgMu6nb4pQ==", "cpu": [ "x64" ], @@ -8618,9 +8618,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.35.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.35.0.tgz", - "integrity": "sha512-mrA0v3QMy6ZSvEuLs0dMxcO2LnaCONs1Z73GUDBHWbY8tFFocM6yl7YyMu7rz4zS81NDSqhrUuolyZXGi8TEqg==", + "version": "4.36.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.36.0.tgz", + "integrity": "sha512-bvXVU42mOVcF4le6XSjscdXjqx8okv4n5vmwgzcmtvFdifQ5U4dXFYaCB87namDRKlUL9ybVtLQ9ztnawaSzvg==", "cpu": [ "arm" ], @@ -8632,9 +8632,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.35.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.35.0.tgz", - "integrity": "sha512-DnYhhzcvTAKNexIql8pFajr0PiDGrIsBYPRvCKlA5ixSS3uwo/CWNZxB09jhIapEIg945KOzcYEAGGSmTSpk7A==", + "version": "4.36.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.36.0.tgz", + "integrity": "sha512-JFIQrDJYrxOnyDQGYkqnNBtjDwTgbasdbUiQvcU8JmGDfValfH1lNpng+4FWlhaVIR4KPkeddYjsVVbmJYvDcg==", "cpu": [ "arm" ], @@ -8646,9 +8646,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.35.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.35.0.tgz", - "integrity": "sha512-uagpnH2M2g2b5iLsCTZ35CL1FgyuzzJQ8L9VtlJ+FckBXroTwNOaD0z0/UF+k5K3aNQjbm8LIVpxykUOQt1m/A==", + "version": "4.36.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.36.0.tgz", + "integrity": "sha512-KqjYVh3oM1bj//5X7k79PSCZ6CvaVzb7Qs7VMWS+SlWB5M8p3FqufLP9VNp4CazJ0CsPDLwVD9r3vX7Ci4J56A==", "cpu": [ "arm64" ], @@ -8660,9 +8660,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.35.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.35.0.tgz", - "integrity": "sha512-XQxVOCd6VJeHQA/7YcqyV0/88N6ysSVzRjJ9I9UA/xXpEsjvAgDTgH3wQYz5bmr7SPtVK2TsP2fQ2N9L4ukoUg==", + "version": "4.36.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.36.0.tgz", + "integrity": "sha512-QiGnhScND+mAAtfHqeT+cB1S9yFnNQ/EwCg5yE3MzoaZZnIV0RV9O5alJAoJKX/sBONVKeZdMfO8QSaWEygMhw==", "cpu": [ "arm64" ], @@ -8674,9 +8674,9 @@ ] }, "node_modules/@rollup/rollup-linux-loongarch64-gnu": { - "version": "4.35.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.35.0.tgz", - "integrity": "sha512-5pMT5PzfgwcXEwOaSrqVsz/LvjDZt+vQ8RT/70yhPU06PTuq8WaHhfT1LW+cdD7mW6i/J5/XIkX/1tCAkh1W6g==", + "version": "4.36.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.36.0.tgz", + "integrity": "sha512-1ZPyEDWF8phd4FQtTzMh8FQwqzvIjLsl6/84gzUxnMNFBtExBtpL51H67mV9xipuxl1AEAerRBgBwFNpkw8+Lg==", "cpu": [ "loong64" ], @@ -8688,9 +8688,9 @@ ] }, "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { - "version": "4.35.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.35.0.tgz", - "integrity": "sha512-c+zkcvbhbXF98f4CtEIP1EBA/lCic5xB0lToneZYvMeKu5Kamq3O8gqrxiYYLzlZH6E3Aq+TSW86E4ay8iD8EA==", + "version": "4.36.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.36.0.tgz", + "integrity": "sha512-VMPMEIUpPFKpPI9GZMhJrtu8rxnp6mJR3ZzQPykq4xc2GmdHj3Q4cA+7avMyegXy4n1v+Qynr9fR88BmyO74tg==", "cpu": [ "ppc64" ], @@ -8702,9 +8702,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.35.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.35.0.tgz", - "integrity": "sha512-s91fuAHdOwH/Tad2tzTtPX7UZyytHIRR6V4+2IGlV0Cej5rkG0R61SX4l4y9sh0JBibMiploZx3oHKPnQBKe4g==", + "version": "4.36.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.36.0.tgz", + "integrity": "sha512-ttE6ayb/kHwNRJGYLpuAvB7SMtOeQnVXEIpMtAvx3kepFQeowVED0n1K9nAdraHUPJ5hydEMxBpIR7o4nrm8uA==", "cpu": [ "riscv64" ], @@ -8716,9 +8716,9 @@ ] }, "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.35.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.35.0.tgz", - "integrity": "sha512-hQRkPQPLYJZYGP+Hj4fR9dDBMIM7zrzJDWFEMPdTnTy95Ljnv0/4w/ixFw3pTBMEuuEuoqtBINYND4M7ujcuQw==", + "version": "4.36.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.36.0.tgz", + "integrity": "sha512-4a5gf2jpS0AIe7uBjxDeUMNcFmaRTbNv7NxI5xOCs4lhzsVyGR/0qBXduPnoWf6dGC365saTiwag8hP1imTgag==", "cpu": [ "s390x" ], @@ -8730,9 +8730,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.35.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.35.0.tgz", - "integrity": "sha512-Pim1T8rXOri+0HmV4CdKSGrqcBWX0d1HoPnQ0uw0bdp1aP5SdQVNBy8LjYncvnLgu3fnnCt17xjWGd4cqh8/hA==", + "version": "4.36.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.36.0.tgz", + "integrity": "sha512-5KtoW8UWmwFKQ96aQL3LlRXX16IMwyzMq/jSSVIIyAANiE1doaQsx/KRyhAvpHlPjPiSU/AYX/8m+lQ9VToxFQ==", "cpu": [ "x64" ], @@ -8744,9 +8744,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.35.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.35.0.tgz", - "integrity": "sha512-QysqXzYiDvQWfUiTm8XmJNO2zm9yC9P/2Gkrwg2dH9cxotQzunBHYr6jk4SujCTqnfGxduOmQcI7c2ryuW8XVg==", + "version": "4.36.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.36.0.tgz", + "integrity": "sha512-sycrYZPrv2ag4OCvaN5js+f01eoZ2U+RmT5as8vhxiFz+kxwlHrsxOwKPSA8WyS+Wc6Epid9QeI/IkQ9NkgYyQ==", "cpu": [ "x64" ], @@ -8758,9 +8758,9 @@ ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.35.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.35.0.tgz", - "integrity": "sha512-OUOlGqPkVJCdJETKOCEf1mw848ZyJ5w50/rZ/3IBQVdLfR5jk/6Sr5m3iO2tdPgwo0x7VcncYuOvMhBWZq8ayg==", + "version": "4.36.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.36.0.tgz", + "integrity": "sha512-qbqt4N7tokFwwSVlWDsjfoHgviS3n/vZ8LK0h1uLG9TYIRuUTJC88E1xb3LM2iqZ/WTqNQjYrtmtGmrmmawB6A==", "cpu": [ "arm64" ], @@ -8772,9 +8772,9 @@ ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.35.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.35.0.tgz", - "integrity": "sha512-2/lsgejMrtwQe44glq7AFFHLfJBPafpsTa6JvP2NGef/ifOa4KBoglVf7AKN7EV9o32evBPRqfg96fEHzWo5kw==", + "version": "4.36.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.36.0.tgz", + "integrity": "sha512-t+RY0JuRamIocMuQcfwYSOkmdX9dtkr1PbhKW42AMvaDQa+jOdpUYysroTF/nuPpAaQMWp7ye+ndlmmthieJrQ==", "cpu": [ "ia32" ], @@ -8786,9 +8786,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.35.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.35.0.tgz", - "integrity": "sha512-PIQeY5XDkrOysbQblSW7v3l1MDZzkTEzAfTPkj5VAu3FW8fS4ynyLg2sINp0fp3SjZ8xkRYpLqoKcYqAkhU1dw==", + "version": "4.36.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.36.0.tgz", + "integrity": "sha512-aRXd7tRZkWLqGbChgcMMDEHjOKudo1kChb1Jt1IfR8cY/KIpgNviLeJy5FUb9IpSuQj8dU2fAYNMPW/hLKOSTw==", "cpu": [ "x64" ], @@ -10081,9 +10081,9 @@ "integrity": "sha512-jg+97EGIcY9AGHJJRaaPVgetKDsrTgbRjQ5Msgjh/DQKEFl0DtyRr/VCOyD1T2R1MNeWPK/u7JoGhlDZnKBAfA==" }, "node_modules/@vitest/coverage-v8": { - "version": "3.0.8", - "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-3.0.8.tgz", - "integrity": "sha512-y7SAKsQirsEJ2F8bulBck4DoluhI2EEgTimHd6EEUgJBGKy9tC25cpywh1MH4FvDGoG2Unt7+asVd1kj4qOSAw==", + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-3.0.9.tgz", + "integrity": "sha512-15OACZcBtQ34keIEn19JYTVuMFTlFrClclwWjHo/IRPg/8ELpkgNTl0o7WLP9WO9XGH6+tip9CPYtEOrIDJvBA==", "dev": true, "license": "MIT", "dependencies": { @@ -10104,8 +10104,8 @@ "url": "https://opencollective.com/vitest" }, "peerDependencies": { - "@vitest/browser": "3.0.8", - "vitest": "3.0.8" + "@vitest/browser": "3.0.9", + "vitest": "3.0.9" }, "peerDependenciesMeta": { "@vitest/browser": { @@ -10157,14 +10157,14 @@ } }, "node_modules/@vitest/expect": { - "version": "3.0.8", - "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-3.0.8.tgz", - "integrity": "sha512-Xu6TTIavTvSSS6LZaA3EebWFr6tsoXPetOWNMOlc7LO88QVVBwq2oQWBoDiLCN6YTvNYsGSjqOO8CAdjom5DCQ==", + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-3.0.9.tgz", + "integrity": "sha512-5eCqRItYgIML7NNVgJj6TVCmdzE7ZVgJhruW0ziSQV4V7PvLkDL1bBkBdcTs/VuIz0IxPb5da1IDSqc1TR9eig==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/spy": "3.0.8", - "@vitest/utils": "3.0.8", + "@vitest/spy": "3.0.9", + "@vitest/utils": "3.0.9", "chai": "^5.2.0", "tinyrainbow": "^2.0.0" }, @@ -10173,13 +10173,13 @@ } }, "node_modules/@vitest/mocker": { - "version": "3.0.8", - "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-3.0.8.tgz", - "integrity": "sha512-n3LjS7fcW1BCoF+zWZxG7/5XvuYH+lsFg+BDwwAz0arIwHQJFUEsKBQ0BLU49fCxuM/2HSeBPHQD8WjgrxMfow==", + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-3.0.9.tgz", + "integrity": "sha512-ryERPIBOnvevAkTq+L1lD+DTFBRcjueL9lOUfXsLfwP92h4e+Heb+PjiqS3/OURWPtywfafK0kj++yDFjWUmrA==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/spy": "3.0.8", + "@vitest/spy": "3.0.9", "estree-walker": "^3.0.3", "magic-string": "^0.30.17" }, @@ -10200,9 +10200,9 @@ } }, "node_modules/@vitest/pretty-format": { - "version": "3.0.8", - "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-3.0.8.tgz", - "integrity": "sha512-BNqwbEyitFhzYMYHUVbIvepOyeQOSFA/NeJMIP9enMntkkxLgOcgABH6fjyXG85ipTgvero6noreavGIqfJcIg==", + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-3.0.9.tgz", + "integrity": "sha512-OW9F8t2J3AwFEwENg3yMyKWweF7oRJlMyHOMIhO5F3n0+cgQAJZBjNgrF8dLwFTEXl5jUqBLXd9QyyKv8zEcmA==", "dev": true, "license": "MIT", "dependencies": { @@ -10213,13 +10213,13 @@ } }, "node_modules/@vitest/runner": { - "version": "3.0.8", - "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-3.0.8.tgz", - "integrity": "sha512-c7UUw6gEcOzI8fih+uaAXS5DwjlBaCJUo7KJ4VvJcjL95+DSR1kova2hFuRt3w41KZEFcOEiq098KkyrjXeM5w==", + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-3.0.9.tgz", + "integrity": "sha512-NX9oUXgF9HPfJSwl8tUZCMP1oGx2+Sf+ru6d05QjzQz4OwWg0psEzwY6VexP2tTHWdOkhKHUIZH+fS6nA7jfOw==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/utils": "3.0.8", + "@vitest/utils": "3.0.9", "pathe": "^2.0.3" }, "funding": { @@ -10227,13 +10227,13 @@ } }, "node_modules/@vitest/snapshot": { - "version": "3.0.8", - "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-3.0.8.tgz", - "integrity": "sha512-x8IlMGSEMugakInj44nUrLSILh/zy1f2/BgH0UeHpNyOocG18M9CWVIFBaXPt8TrqVZWmcPjwfG/ht5tnpba8A==", + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-3.0.9.tgz", + "integrity": "sha512-AiLUiuZ0FuA+/8i19mTYd+re5jqjEc2jZbgJ2up0VY0Ddyyxg/uUtBDpIFAy4uzKaQxOW8gMgBdAJJ2ydhu39A==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/pretty-format": "3.0.8", + "@vitest/pretty-format": "3.0.9", "magic-string": "^0.30.17", "pathe": "^2.0.3" }, @@ -10242,9 +10242,9 @@ } }, "node_modules/@vitest/spy": { - "version": "3.0.8", - "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-3.0.8.tgz", - "integrity": "sha512-MR+PzJa+22vFKYb934CejhR4BeRpMSoxkvNoDit68GQxRLSf11aT6CTj3XaqUU9rxgWJFnqicN/wxw6yBRkI1Q==", + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-3.0.9.tgz", + "integrity": "sha512-/CcK2UDl0aQ2wtkp3YVWldrpLRNCfVcIOFGlVGKO4R5eajsH393Z1yiXLVQ7vWsj26JOEjeZI0x5sm5P4OGUNQ==", "dev": true, "license": "MIT", "dependencies": { @@ -10255,13 +10255,13 @@ } }, "node_modules/@vitest/utils": { - "version": "3.0.8", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-3.0.8.tgz", - "integrity": "sha512-nkBC3aEhfX2PdtQI/QwAWp8qZWwzASsU4Npbcd5RdMPBSSLCpkZp52P3xku3s3uA0HIEhGvEcF8rNkBsz9dQ4Q==", + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-3.0.9.tgz", + "integrity": "sha512-ilHM5fHhZ89MCp5aAaM9uhfl1c2JdxVxl3McqsdVyVNN6JffnEen8UMCdRTzOhGXNQGo5GNL9QugHrz727Wnng==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/pretty-format": "3.0.8", + "@vitest/pretty-format": "3.0.9", "loupe": "^3.1.3", "tinyrainbow": "^2.0.0" }, @@ -17043,9 +17043,9 @@ "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==" }, "node_modules/nanoid": { - "version": "3.3.9", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.9.tgz", - "integrity": "sha512-SppoicMGpZvbF1l3z4x7No3OlIjP7QJvC9XR7AhZr1kL133KHnKPztkKDc+Ir4aJ/1VhTySrtKhrsycmrMQfvg==", + "version": "3.3.10", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.10.tgz", + "integrity": "sha512-vSJJTG+t/dIKAUhUDw/dLdZ9s//5OxcHqLaDWWrW4Cdq7o6tdLIczUkMXt2MBNmk6sJRZBZRXVixs7URY1CmIg==", "dev": true, "funding": [ { @@ -19340,9 +19340,9 @@ } }, "node_modules/rollup": { - "version": "4.35.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.35.0.tgz", - "integrity": "sha512-kg6oI4g+vc41vePJyO6dHt/yl0Rz3Thv0kJeVQ3D1kS3E5XSuKbPc29G4IpT/Kv1KQwgHVcN+HtyS+HYLNSvQg==", + "version": "4.36.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.36.0.tgz", + "integrity": "sha512-zwATAXNQxUcd40zgtQG0ZafcRK4g004WtEl7kbuhTWPvf07PsfohXl39jVUvPF7jvNAIkKPQ2XrsDlWuxBd++Q==", "dev": true, "license": "MIT", "dependencies": { @@ -19356,25 +19356,25 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.35.0", - "@rollup/rollup-android-arm64": "4.35.0", - "@rollup/rollup-darwin-arm64": "4.35.0", - "@rollup/rollup-darwin-x64": "4.35.0", - "@rollup/rollup-freebsd-arm64": "4.35.0", - "@rollup/rollup-freebsd-x64": "4.35.0", - "@rollup/rollup-linux-arm-gnueabihf": "4.35.0", - "@rollup/rollup-linux-arm-musleabihf": "4.35.0", - "@rollup/rollup-linux-arm64-gnu": "4.35.0", - "@rollup/rollup-linux-arm64-musl": "4.35.0", - "@rollup/rollup-linux-loongarch64-gnu": "4.35.0", - "@rollup/rollup-linux-powerpc64le-gnu": "4.35.0", - "@rollup/rollup-linux-riscv64-gnu": "4.35.0", - "@rollup/rollup-linux-s390x-gnu": "4.35.0", - "@rollup/rollup-linux-x64-gnu": "4.35.0", - "@rollup/rollup-linux-x64-musl": "4.35.0", - "@rollup/rollup-win32-arm64-msvc": "4.35.0", - "@rollup/rollup-win32-ia32-msvc": "4.35.0", - "@rollup/rollup-win32-x64-msvc": "4.35.0", + "@rollup/rollup-android-arm-eabi": "4.36.0", + "@rollup/rollup-android-arm64": "4.36.0", + "@rollup/rollup-darwin-arm64": "4.36.0", + "@rollup/rollup-darwin-x64": "4.36.0", + "@rollup/rollup-freebsd-arm64": "4.36.0", + "@rollup/rollup-freebsd-x64": "4.36.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.36.0", + "@rollup/rollup-linux-arm-musleabihf": "4.36.0", + "@rollup/rollup-linux-arm64-gnu": "4.36.0", + "@rollup/rollup-linux-arm64-musl": "4.36.0", + "@rollup/rollup-linux-loongarch64-gnu": "4.36.0", + "@rollup/rollup-linux-powerpc64le-gnu": "4.36.0", + "@rollup/rollup-linux-riscv64-gnu": "4.36.0", + "@rollup/rollup-linux-s390x-gnu": "4.36.0", + "@rollup/rollup-linux-x64-gnu": "4.36.0", + "@rollup/rollup-linux-x64-musl": "4.36.0", + "@rollup/rollup-win32-arm64-msvc": "4.36.0", + "@rollup/rollup-win32-ia32-msvc": "4.36.0", + "@rollup/rollup-win32-x64-msvc": "4.36.0", "fsevents": "~2.3.2" } }, @@ -20840,9 +20840,9 @@ } }, "node_modules/vite": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/vite/-/vite-6.2.1.tgz", - "integrity": "sha512-n2GnqDb6XPhlt9B8olZPrgMD/es/Nd1RdChF6CBD/fHW6pUyUTt2sQW2fPRX5GiD9XEa6+8A6A4f2vT6pSsE7Q==", + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/vite/-/vite-6.2.2.tgz", + "integrity": "sha512-yW7PeMM+LkDzc7CgJuRLMW2Jz0FxMOsVJ8Lv3gpgW9WLcb9cTW+121UEr1hvmfR7w3SegR5ItvYyzVz1vxNJgQ==", "dev": true, "license": "MIT", "dependencies": { @@ -20912,9 +20912,9 @@ } }, "node_modules/vite-node": { - "version": "3.0.8", - "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-3.0.8.tgz", - "integrity": "sha512-6PhR4H9VGlcwXZ+KWCdMqbtG649xCPZqfI9j2PsK1FcXgEzro5bGHcVKFCTqPLaNKZES8Evqv4LwvZARsq5qlg==", + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-3.0.9.tgz", + "integrity": "sha512-w3Gdx7jDcuT9cNn9jExXgOyKmf5UOTb6WMHz8LGAm54eS1Elf5OuBhCxl6zJxGhEeIkgsE1WbHuoL0mj/UXqXg==", "dev": true, "license": "MIT", "dependencies": { @@ -20950,19 +20950,19 @@ } }, "node_modules/vitest": { - "version": "3.0.8", - "resolved": "https://registry.npmjs.org/vitest/-/vitest-3.0.8.tgz", - "integrity": "sha512-dfqAsNqRGUc8hB9OVR2P0w8PZPEckti2+5rdZip0WIz9WW0MnImJ8XiR61QhqLa92EQzKP2uPkzenKOAHyEIbA==", + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-3.0.9.tgz", + "integrity": "sha512-BbcFDqNyBlfSpATmTtXOAOj71RNKDDvjBM/uPfnxxVGrG+FSH2RQIwgeEngTaTkuU/h0ScFvf+tRcKfYXzBybQ==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/expect": "3.0.8", - "@vitest/mocker": "3.0.8", - "@vitest/pretty-format": "^3.0.8", - "@vitest/runner": "3.0.8", - "@vitest/snapshot": "3.0.8", - "@vitest/spy": "3.0.8", - "@vitest/utils": "3.0.8", + "@vitest/expect": "3.0.9", + "@vitest/mocker": "3.0.9", + "@vitest/pretty-format": "^3.0.9", + "@vitest/runner": "3.0.9", + "@vitest/snapshot": "3.0.9", + "@vitest/spy": "3.0.9", + "@vitest/utils": "3.0.9", "chai": "^5.2.0", "debug": "^4.4.0", "expect-type": "^1.1.0", @@ -20974,7 +20974,7 @@ "tinypool": "^1.0.2", "tinyrainbow": "^2.0.0", "vite": "^5.0.0 || ^6.0.0", - "vite-node": "3.0.8", + "vite-node": "3.0.9", "why-is-node-running": "^2.3.0" }, "bin": { @@ -20990,8 +20990,8 @@ "@edge-runtime/vm": "*", "@types/debug": "^4.1.12", "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", - "@vitest/browser": "3.0.8", - "@vitest/ui": "3.0.8", + "@vitest/browser": "3.0.9", + "@vitest/ui": "3.0.9", "happy-dom": "*", "jsdom": "*" }, diff --git a/package.json b/package.json index e605df0bd1..874e3d337b 100644 --- a/package.json +++ b/package.json @@ -53,7 +53,7 @@ "@biomejs/biome": "^1.9.4", "@types/aws-lambda": "^8.10.147", "@types/node": "^22.13.10", - "@vitest/coverage-v8": "^3.0.8", + "@vitest/coverage-v8": "^3.0.9", "husky": "^9.1.7", "lerna": "8.1.2", "lint-staged": "^15.5.0", From cdd613b140cd5023fcf8aa21315d0bfa47fe57b4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 17 Mar 2025 15:58:24 +0100 Subject: [PATCH 22/56] chore(deps): bump squidfunk/mkdocs-material from `479a06a` to `f226a2d` in /docs (#3732) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Andrea Amorosi --- docs/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/Dockerfile b/docs/Dockerfile index a5e04b5275..8ae37f1976 100644 --- a/docs/Dockerfile +++ b/docs/Dockerfile @@ -1,5 +1,5 @@ # version 9.5.35 -FROM squidfunk/mkdocs-material@sha256:479a06a8f5a320a9b2b17e72cb7012388d66ea71a8568235cfa072eb152bc30c +FROM squidfunk/mkdocs-material@sha256:f226a2d2d5983643cab401491fc40e8a5711a50e90c21433f80e91c014cff1f5 # Install Node.js RUN apk add --no-cache nodejs=20.15.1-r0 npm From 1dcf438ac9654321de977312ed4cb17c3f84c20c Mon Sep 17 00:00:00 2001 From: Andrea Amorosi Date: Mon, 17 Mar 2025 16:02:36 +0100 Subject: [PATCH 23/56] test: fix transient fails in log sampling tests (#3736) --- .../sampleRate.decorator.test.FunctionCode.ts | 13 +---- packages/testing/src/TestStack.ts | 50 +++++++++++++++++-- 2 files changed, 48 insertions(+), 15 deletions(-) diff --git a/packages/logger/tests/e2e/sampleRate.decorator.test.FunctionCode.ts b/packages/logger/tests/e2e/sampleRate.decorator.test.FunctionCode.ts index bc770fe560..b0cd540189 100644 --- a/packages/logger/tests/e2e/sampleRate.decorator.test.FunctionCode.ts +++ b/packages/logger/tests/e2e/sampleRate.decorator.test.FunctionCode.ts @@ -9,23 +9,12 @@ const LOG_MSG = process.env.LOG_MSG || 'Hello World'; const logger = new Logger({ sampleRateValue: SAMPLE_RATE, }); -let firstInvocation = true; class Lambda implements LambdaInterface { - private readonly logMsg: string; + private readonly logMsg = LOG_MSG; - public constructor() { - this.logMsg = LOG_MSG; - } - - // Decorate your handler class method @logger.injectLambdaContext() public async handler(_event: TestEvent, context: Context): TestOutput { - if (firstInvocation) { - firstInvocation = false; - } else { - logger.refreshSampleRateCalculation(); - } this.printLogInAllLevels(); return { diff --git a/packages/testing/src/TestStack.ts b/packages/testing/src/TestStack.ts index 63b5a193c3..5ed69d1448 100644 --- a/packages/testing/src/TestStack.ts +++ b/packages/testing/src/TestStack.ts @@ -66,19 +66,63 @@ class TestStack { Service: 'Powertools-for-AWS-e2e-tests', }, }); + let lastCreateLog = 0; + let lastDestroyLog = 0; + const creationDeleteLogFrequency = 10000; // 10 seconds + const that = this; this.#cli = new Toolkit({ color: false, ioHost: { + /** + * Log messages to the console depending on the log level. + * + * If the `RUNNER_DEBUG` environment variable is set to `1`, all messages are logged. + * + * Otherwise, we log messages that are either warnings or errors as well as periodic + * updates on the stack creation and destruction process. + * + * @param msg - Message to log sent by the CDK CLI + */ async notify(msg) { + if (process.env.RUNNER_DEBUG === '1') { + testConsole.log(msg); + return; + } + if (msg.message.includes('destroyed') && msg.message.includes('✅')) { + testConsole.log(msg.message); + return; + } + if (msg.message.includes('✅') && !msg.message.includes('deployed')) { + testConsole.log(`${that.testName} deployed successfully`); + return; + } + if (msg.message.includes('CREATE_IN_PROGRESS')) { + if (Date.now() - lastCreateLog < creationDeleteLogFrequency) { + return; + } + lastCreateLog = Date.now(); + testConsole.log(`${that.testName} stack is being created...`); + return; + } + if (msg.message.includes('DELETE_IN_PROGRESS')) { + if (Date.now() - lastDestroyLog < creationDeleteLogFrequency) { + return; + } + lastDestroyLog = Date.now(); + testConsole.log(`${that.testName} stack is being destroyed...`); + return; + } + if (['warning', 'error'].includes(msg.level)) { + testConsole.log(msg); + } + }, + async requestResponse(msg) { if ( process.env.RUNNER_DEBUG === '1' || ['warning', 'error'].includes(msg.level) ) { testConsole.log(msg); } - }, - async requestResponse(msg) { - testConsole.log(msg); return msg.defaultResponse; }, }, From 3aab762b81c6b6f074474a41090642aedf96a848 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 17 Mar 2025 16:37:57 +0100 Subject: [PATCH 24/56] chore(deps): bump mkdocs-material from 9.6.8 to 9.6.9 in /docs (#3731) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Andrea Amorosi --- docs/requirements.in | 2 +- docs/requirements.txt | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/requirements.in b/docs/requirements.in index 8bff50e938..b5b21ca673 100644 --- a/docs/requirements.in +++ b/docs/requirements.in @@ -1,5 +1,5 @@ mike==1.1.2 -mkdocs-material==9.6.8 +mkdocs-material==9.6.9 mkdocs-git-revision-date-plugin==0.3.2 mkdocs-exclude==1.0.2 mkdocs-typedoc==1.0.4 \ No newline at end of file diff --git a/docs/requirements.txt b/docs/requirements.txt index 33c9cee13e..8d6a794769 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -244,9 +244,9 @@ mkdocs-get-deps==0.2.0 \ mkdocs-git-revision-date-plugin==0.3.2 \ --hash=sha256:2e67956cb01823dd2418e2833f3623dee8604cdf223bddd005fe36226a56f6ef # via -r requirements.in -mkdocs-material==9.6.8 \ - --hash=sha256:0a51532dd8aa80b232546c073fe3ef60dfaef1b1b12196ac7191ee01702d1cf8 \ - --hash=sha256:8de31bb7566379802532b248bd56d9c4bc834afc4625884bf5769f9412c6a354 +mkdocs-material==9.6.9 \ + --hash=sha256:6e61b7fb623ce2aa4622056592b155a9eea56ff3487d0835075360be45a4c8d1 \ + --hash=sha256:a4872139715a1f27b2aa3f3dc31a9794b7bbf36333c0ba4607cf04786c94f89c # via -r requirements.in mkdocs-material-extensions==1.3.1 \ --hash=sha256:10c9511cea88f568257f960358a467d12b970e1f7b2c0e5fb2bb48cab1928443 \ From 0c26e1387a285b2af7ab1d7b9980d82ab12eb20d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 17 Mar 2025 16:51:17 +0100 Subject: [PATCH 25/56] chore(deps): bump actions/setup-node from 4.2.0 to 4.3.0 (#3738) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Andrea Amorosi --- .github/workflows/bootstrap_region.yml | 2 +- .github/workflows/make-release.yml | 2 +- .github/workflows/make-version.yml | 2 +- .github/workflows/publish-package.yml | 2 +- .github/workflows/publish_layer.yml | 2 +- .github/workflows/quality_check.yml | 10 +++++----- .../reusable-run-linting-check-and-unit-tests.yml | 10 +++++----- .github/workflows/reusable_deploy_layer_stack.yml | 2 +- .github/workflows/reusable_publish_docs.yml | 2 +- .github/workflows/run-e2e-tests.yml | 2 +- 10 files changed, 18 insertions(+), 18 deletions(-) diff --git a/.github/workflows/bootstrap_region.yml b/.github/workflows/bootstrap_region.yml index 1bac0f82fa..3da43bc3f3 100644 --- a/.github/workflows/bootstrap_region.yml +++ b/.github/workflows/bootstrap_region.yml @@ -47,7 +47,7 @@ jobs: with: ref: ${{ github.sha }} - name: Setup Node.js - uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0 + uses: actions/setup-node@cdca7365b2dadb8aad0a33bc7601856ffabcc48e # v4.3.0 with: node-version: "22" - name: Setup dependencies diff --git a/.github/workflows/make-release.yml b/.github/workflows/make-release.yml index 8cfe629f9e..54231b0411 100644 --- a/.github/workflows/make-release.yml +++ b/.github/workflows/make-release.yml @@ -49,7 +49,7 @@ jobs: with: ref: ${{ github.sha }} - name: Setup NodeJS - uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0 + uses: actions/setup-node@cdca7365b2dadb8aad0a33bc7601856ffabcc48e # v4.3.0 with: node-version: "22" cache: "npm" diff --git a/.github/workflows/make-version.yml b/.github/workflows/make-version.yml index 051b20f0c4..bf578ce4d7 100644 --- a/.github/workflows/make-version.yml +++ b/.github/workflows/make-version.yml @@ -23,7 +23,7 @@ jobs: ref: ${{ github.ref }} fetch-depth: 0 # fetch all history, commits and tags, lerna scans it to the last tag and looks at commits, we need all of it to determine the next version - name: Setup NodeJS - uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0 + uses: actions/setup-node@cdca7365b2dadb8aad0a33bc7601856ffabcc48e # v4.3.0 with: node-version: "22" cache: "npm" diff --git a/.github/workflows/publish-package.yml b/.github/workflows/publish-package.yml index d71bbab195..d43c776124 100644 --- a/.github/workflows/publish-package.yml +++ b/.github/workflows/publish-package.yml @@ -39,7 +39,7 @@ jobs: with: ref: ${{ github.sha }} - name: Setup NodeJS - uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0 + uses: actions/setup-node@cdca7365b2dadb8aad0a33bc7601856ffabcc48e # v4.3.0 with: node-version: "22" cache: "npm" diff --git a/.github/workflows/publish_layer.yml b/.github/workflows/publish_layer.yml index 9c311df723..c0d537803d 100644 --- a/.github/workflows/publish_layer.yml +++ b/.github/workflows/publish_layer.yml @@ -35,7 +35,7 @@ jobs: with: ref: ${{ github.sha }} - name: Setup Node.js - uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0 + uses: actions/setup-node@cdca7365b2dadb8aad0a33bc7601856ffabcc48e # v4.3.0 with: node-version: "22" - name: Setup dependencies diff --git a/.github/workflows/quality_check.yml b/.github/workflows/quality_check.yml index 8debce5930..b3de8d873c 100644 --- a/.github/workflows/quality_check.yml +++ b/.github/workflows/quality_check.yml @@ -37,7 +37,7 @@ jobs: - name: Checkout code uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Setup NodeJS - uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0 + uses: actions/setup-node@cdca7365b2dadb8aad0a33bc7601856ffabcc48e # v4.3.0 with: node-version: ${{ matrix.version }} cache: "npm" @@ -66,7 +66,7 @@ jobs: - name: Checkout code uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Setup NodeJS - uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0 + uses: actions/setup-node@cdca7365b2dadb8aad0a33bc7601856ffabcc48e # v4.3.0 with: node-version: 22 cache: "npm" @@ -84,7 +84,7 @@ jobs: - name: Checkout code uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Setup NodeJS - uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0 + uses: actions/setup-node@cdca7365b2dadb8aad0a33bc7601856ffabcc48e # v4.3.0 with: node-version: 22 cache: "npm" @@ -102,7 +102,7 @@ jobs: - name: Checkout code uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Setup NodeJS - uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0 + uses: actions/setup-node@cdca7365b2dadb8aad0a33bc7601856ffabcc48e # v4.3.0 with: node-version: 22 cache: "npm" @@ -118,7 +118,7 @@ jobs: - name: Checkout code uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Setup NodeJS - uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0 + uses: actions/setup-node@cdca7365b2dadb8aad0a33bc7601856ffabcc48e # v4.3.0 with: node-version: 22 cache: "npm" 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 01e7c8fef8..c3d2c4a8e8 100644 --- a/.github/workflows/reusable-run-linting-check-and-unit-tests.yml +++ b/.github/workflows/reusable-run-linting-check-and-unit-tests.yml @@ -58,7 +58,7 @@ jobs: - name: Checkout code uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Setup NodeJS - uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0 + uses: actions/setup-node@cdca7365b2dadb8aad0a33bc7601856ffabcc48e # v4.3.0 with: node-version: ${{ matrix.version }} cache: "npm" @@ -87,7 +87,7 @@ jobs: - name: Checkout code uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Setup NodeJS - uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0 + uses: actions/setup-node@cdca7365b2dadb8aad0a33bc7601856ffabcc48e # v4.3.0 with: node-version: 22 cache: "npm" @@ -105,7 +105,7 @@ jobs: - name: Checkout code uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Setup NodeJS - uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0 + uses: actions/setup-node@cdca7365b2dadb8aad0a33bc7601856ffabcc48e # v4.3.0 with: node-version: 22 cache: "npm" @@ -123,7 +123,7 @@ jobs: - name: Checkout code uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Setup NodeJS - uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0 + uses: actions/setup-node@cdca7365b2dadb8aad0a33bc7601856ffabcc48e # v4.3.0 with: node-version: 22 cache: "npm" @@ -139,7 +139,7 @@ jobs: - name: Checkout code uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Setup NodeJS - uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0 + uses: actions/setup-node@cdca7365b2dadb8aad0a33bc7601856ffabcc48e # v4.3.0 with: node-version: 22 cache: "npm" diff --git a/.github/workflows/reusable_deploy_layer_stack.yml b/.github/workflows/reusable_deploy_layer_stack.yml index 7b56062034..75d3b98122 100644 --- a/.github/workflows/reusable_deploy_layer_stack.yml +++ b/.github/workflows/reusable_deploy_layer_stack.yml @@ -75,7 +75,7 @@ jobs: role-to-assume: ${{ secrets.target-account-role }} mask-aws-account-id: true - name: Setup Node.js - uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0 + uses: actions/setup-node@cdca7365b2dadb8aad0a33bc7601856ffabcc48e # v4.3.0 with: node-version: "22" - name: Setup dependencies diff --git a/.github/workflows/reusable_publish_docs.yml b/.github/workflows/reusable_publish_docs.yml index c4b640529d..7f40edc3d6 100644 --- a/.github/workflows/reusable_publish_docs.yml +++ b/.github/workflows/reusable_publish_docs.yml @@ -52,7 +52,7 @@ jobs: - name: Checkout code uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Setup NodeJS - uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0 + uses: actions/setup-node@cdca7365b2dadb8aad0a33bc7601856ffabcc48e # v4.3.0 with: node-version: "22" cache: "npm" diff --git a/.github/workflows/run-e2e-tests.yml b/.github/workflows/run-e2e-tests.yml index c5447a7aaf..4a9145fd19 100644 --- a/.github/workflows/run-e2e-tests.yml +++ b/.github/workflows/run-e2e-tests.yml @@ -55,7 +55,7 @@ jobs: with: ref: ${{ steps.extract_PR_details.outputs.headSHA }} - name: Setup NodeJS - uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0 + uses: actions/setup-node@cdca7365b2dadb8aad0a33bc7601856ffabcc48e # v4.3.0 with: node-version: '22' - name: Setup dependencies From 61725f4b75d3f19f200aecec5c4eb509e9b192e6 Mon Sep 17 00:00:00 2001 From: Andrea Amorosi Date: Wed, 19 Mar 2025 10:14:00 +0100 Subject: [PATCH 26/56] test: advanced test use cases (#3737) --- .github/scripts/get_pr_info.js | 30 - .github/workflows/run-e2e-tests.yml | 24 +- layers/tests/e2e/constants.ts | 4 - layers/tests/e2e/layerPublisher.test.ts | 10 +- layers/vitest.config.ts | 2 + package-lock.json | 2 +- package.json | 2 +- packages/idempotency/tests/e2e/constants.ts | 5 - .../tests/e2e/idempotentDecorator.test.ts | 567 +++++++++--------- .../tests/e2e/makeHandlerIdempotent.test.ts | 450 +++++++------- .../tests/e2e/makeIdempotent.test.ts | 416 ++++++------- packages/idempotency/vitest.config.ts | 2 + packages/logger/package.json | 4 + .../e2e/advancedUses.test.FunctionCode.ts | 63 ++ .../logger/tests/e2e/advancedUses.test.ts | 163 +++++ .../tests/e2e/basicFeatures.middy.test.ts | 445 ++++++-------- .../tests/e2e/childLogger.manual.test.ts | 159 +++-- packages/logger/tests/e2e/constants.ts | 8 - .../e2e/logEventEnvVarSetting.middy.test.ts | 50 +- .../tests/e2e/sampleRate.decorator.test.ts | 104 ++-- packages/logger/vitest.config.ts | 2 + .../e2e/basicFeatures.decorators.test.ts | 235 ++++---- .../tests/e2e/basicFeatures.manual.test.ts | 211 +++---- packages/metrics/tests/e2e/constants.ts | 13 +- packages/metrics/vitest.config.ts | 2 + .../tests/e2e/appConfigProvider.class.test.ts | 81 +-- packages/parameters/tests/e2e/constants.ts | 4 - .../tests/e2e/dynamoDBProvider.class.test.ts | 91 ++- .../tests/e2e/secretsProvider.class.test.ts | 73 +-- .../tests/e2e/ssmProvider.class.test.ts | 299 ++++----- packages/parameters/vitest.config.ts | 2 + packages/testing/src/TestInvocationLogs.ts | 13 +- .../src/resources/TestNodejsFunction.ts | 16 +- packages/testing/src/setupEnv.ts | 1 + packages/testing/src/types.ts | 6 + packages/tracer/tests/e2e/constants.ts | 9 - packages/tracer/tests/e2e/decorator.test.ts | 6 +- packages/tracer/tests/e2e/manual.test.ts | 6 +- packages/tracer/tests/e2e/middy.test.ts | 6 +- packages/tracer/vitest.config.ts | 2 + vitest.config.ts | 2 + 41 files changed, 1727 insertions(+), 1863 deletions(-) delete mode 100644 .github/scripts/get_pr_info.js create mode 100644 packages/logger/tests/e2e/advancedUses.test.FunctionCode.ts create mode 100644 packages/logger/tests/e2e/advancedUses.test.ts diff --git a/.github/scripts/get_pr_info.js b/.github/scripts/get_pr_info.js deleted file mode 100644 index ece2f97f44..0000000000 --- a/.github/scripts/get_pr_info.js +++ /dev/null @@ -1,30 +0,0 @@ -module.exports = async ({ github, context, core }) => { - const prNumber = process.env.PR_NUMBER; - - if (prNumber === '') { - core.setFailed(`No PR number was passed. Aborting`); - } - - // Remove the `#` prefix from the PR number if it exists - const prNumberWithoutPrefix = prNumber.replace('#', ''); - - try { - const { - data: { head, base }, - } = await github.rest.pulls.get({ - owner: context.repo.owner, - repo: context.repo.repo, - pull_number: prNumberWithoutPrefix, - }); - - core.setOutput('headRef', head.ref); - core.setOutput('headSHA', head.sha); - core.setOutput('baseRef', base.ref); - core.setOutput('baseSHA', base.sha); - } catch (error) { - core.setFailed( - `Unable to retrieve info from PR number ${prNumber}.\n\n Error details: ${error}` - ); - throw error; - } -}; diff --git a/.github/workflows/run-e2e-tests.yml b/.github/workflows/run-e2e-tests.yml index 4a9145fd19..0601b33d7f 100644 --- a/.github/workflows/run-e2e-tests.yml +++ b/.github/workflows/run-e2e-tests.yml @@ -17,20 +17,21 @@ jobs: env: NODE_ENV: dev PR_NUMBER: ${{ inputs.prNumber }} + GH_TOKEN: ${{ github.token }} permissions: id-token: write # needed to interact with GitHub's OIDC Token endpoint. contents: read strategy: - max-parallel: 30 + max-parallel: 25 matrix: package: [ - layers, + packages/idempotency, packages/logger, packages/metrics, - packages/tracer, packages/parameters, - packages/idempotency, + packages/tracer, + layers, ] version: [18, 20, 22] arch: [x86_64, arm64] @@ -42,11 +43,14 @@ jobs: - name: Extract PR details id: extract_PR_details if: ${{ inputs.prNumber != '' }} - uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 - with: - script: | - const script = require('.github/scripts/get_pr_info.js'); - await script({github, context, core}); + run: | + # Get the PR number from the input + pr_number=${{ inputs.prNumber }} + # Get the headSHA of the PR + head_sha=$(gh pr view $pr_number --json headRefOid -q '.headRefOid') + # Set the headSHA as an output variable + echo "headSHA=$head_sha" >> $GITHUB_OUTPUT + echo "headSHA=$head_sha" # Only if a PR Number was passed and the headSHA of the PR extracted, # we checkout the PR at that point in time - name: Checkout PR code @@ -75,4 +79,4 @@ jobs: ARCH: ${{ matrix.arch }} JSII_SILENCE_WARNING_DEPRECATED_NODE_VERSION: true RUNNER_DEBUG: ${{ env.RUNNER_DEBUG }} - run: npm run test:e2e -w ${{ matrix.package }} + run: npm run test:e2e -w ${{ matrix.package }} \ No newline at end of file diff --git a/layers/tests/e2e/constants.ts b/layers/tests/e2e/constants.ts index b6b477031b..e8c5d84251 100644 --- a/layers/tests/e2e/constants.ts +++ b/layers/tests/e2e/constants.ts @@ -1,5 +1 @@ export const RESOURCE_NAME_PREFIX = 'Layers-E2E'; -export const ONE_MINUTE = 60 * 1000; -export const TEST_CASE_TIMEOUT = 3 * ONE_MINUTE; -export const SETUP_TIMEOUT = 7 * ONE_MINUTE; -export const TEARDOWN_TIMEOUT = 5 * ONE_MINUTE; diff --git a/layers/tests/e2e/layerPublisher.test.ts b/layers/tests/e2e/layerPublisher.test.ts index cbffc8abfa..1f932ca98a 100644 --- a/layers/tests/e2e/layerPublisher.test.ts +++ b/layers/tests/e2e/layerPublisher.test.ts @@ -11,11 +11,7 @@ import { LayerVersion } from 'aws-cdk-lib/aws-lambda'; import { afterAll, beforeAll, describe, expect, it, vi } from 'vitest'; import packageJson from '../../package.json'; import { LayerPublisherStack } from '../../src/layer-publisher-stack.js'; -import { - RESOURCE_NAME_PREFIX, - SETUP_TIMEOUT, - TEARDOWN_TIMEOUT, -} from './constants.js'; +import { RESOURCE_NAME_PREFIX } from './constants.js'; /** * This test has two stacks: @@ -121,7 +117,7 @@ describe('Layers E2E tests', () => { }) ); } - }, SETUP_TIMEOUT); + }); it.each(cases)( 'imports and instantiates all utilities (%s)', @@ -198,5 +194,5 @@ describe('Layers E2E tests', () => { await testLayerStack.destroy(); await testStack.destroy(); } - }, TEARDOWN_TIMEOUT); + }); }); diff --git a/layers/vitest.config.ts b/layers/vitest.config.ts index d5aa737c68..1469ff8a66 100644 --- a/layers/vitest.config.ts +++ b/layers/vitest.config.ts @@ -3,5 +3,7 @@ import { defineProject } from 'vitest/config'; export default defineProject({ test: { environment: 'node', + hookTimeout: 1_000 * 60 * 10, // 10 minutes + testTimeout: 1_000 * 60 * 3, // 3 minutes }, }); diff --git a/package-lock.json b/package-lock.json index c7d28b2159..df85f91675 100644 --- a/package-lock.json +++ b/package-lock.json @@ -41,7 +41,7 @@ "typedoc-plugin-missing-exports": "^3.1.0", "typedoc-plugin-zod": "^1.4.0", "typescript": "^5.8.2", - "vitest": "^3.0.5" + "vitest": "^3.0.9" }, "engines": { "node": ">=18" diff --git a/package.json b/package.json index 874e3d337b..bef9e2663d 100644 --- a/package.json +++ b/package.json @@ -65,7 +65,7 @@ "typedoc-plugin-missing-exports": "^3.1.0", "typedoc-plugin-zod": "^1.4.0", "typescript": "^5.8.2", - "vitest": "^3.0.5" + "vitest": "^3.0.9" }, "lint-staged": { "*.{js,ts}": "biome check --write", diff --git a/packages/idempotency/tests/e2e/constants.ts b/packages/idempotency/tests/e2e/constants.ts index 38ae9b6c83..e9cec8eadc 100644 --- a/packages/idempotency/tests/e2e/constants.ts +++ b/packages/idempotency/tests/e2e/constants.ts @@ -1,6 +1 @@ export const RESOURCE_NAME_PREFIX = 'Idempotency'; - -export const ONE_MINUTE = 60 * 1_000; -export const TEARDOWN_TIMEOUT = 5 * ONE_MINUTE; -export const SETUP_TIMEOUT = 7 * ONE_MINUTE; -export const TEST_CASE_TIMEOUT = 5 * ONE_MINUTE; diff --git a/packages/idempotency/tests/e2e/idempotentDecorator.test.ts b/packages/idempotency/tests/e2e/idempotentDecorator.test.ts index 00f0aa236d..9c83ab5417 100644 --- a/packages/idempotency/tests/e2e/idempotentDecorator.test.ts +++ b/packages/idempotency/tests/e2e/idempotentDecorator.test.ts @@ -11,12 +11,7 @@ import { Duration } from 'aws-cdk-lib'; import { AttributeType } from 'aws-cdk-lib/aws-dynamodb'; import { afterAll, beforeAll, describe, expect, it } from 'vitest'; import { IdempotencyTestNodejsFunctionAndDynamoTable } from '../helpers/resources.js'; -import { - RESOURCE_NAME_PREFIX, - SETUP_TIMEOUT, - TEARDOWN_TIMEOUT, - TEST_CASE_TIMEOUT, -} from './constants.js'; +import { RESOURCE_NAME_PREFIX } from './constants.js'; const dynamoDBClient = new DynamoDBClient({}); @@ -160,315 +155,289 @@ describe('Idempotency e2e test decorator, default settings', () => { functionNameDataIndex = testStack.findAndGetStackOutputValue('dataIndexFn'); tableNameDataIndex = testStack.findAndGetStackOutputValue('dataIndexTable'); - }, SETUP_TIMEOUT); + }); - it( - 'returns the same result and runs the handler once when called multiple times', - async () => { - const payload = { foo: 'bar' }; + it('returns the same result and runs the handler once when called multiple times', async () => { + const payload = { foo: 'bar' }; - const payloadHash = createHash('md5') - .update(JSON.stringify(payload)) - .digest('base64'); + const payloadHash = createHash('md5') + .update(JSON.stringify(payload)) + .digest('base64'); - const logs = await invokeFunction({ - functionName: functionNameDefault, - times: 2, - invocationMode: 'SEQUENTIAL', - payload: payload, - }); + const logs = await invokeFunction({ + functionName: functionNameDefault, + times: 2, + invocationMode: 'SEQUENTIAL', + payload: payload, + }); - const functionLogs = logs.map((log) => log.getFunctionLogs()); + const functionLogs = logs.map((log) => log.getFunctionLogs()); - const idempotencyRecord = await dynamoDBClient.send( - new ScanCommand({ - TableName: tableNameDefault, - }) - ); - expect(idempotencyRecord.Items).toHaveLength(1); - expect(idempotencyRecord.Items?.[0].id).toEqual( - `${functionNameDefault}#${payloadHash}` - ); - expect(idempotencyRecord.Items?.[0].data).toBeUndefined(); - expect(idempotencyRecord.Items?.[0].status).toEqual('COMPLETED'); - // During the first invocation the handler should be called, so the logs should contain 1 log - expect(functionLogs[0]).toHaveLength(1); - // We test the content of the log as well as the presence of fields from the context, this - // ensures that the all the arguments are passed to the handler when made idempotent - expect(TestInvocationLogs.parseFunctionLog(functionLogs[0][0])).toEqual( - expect.objectContaining({ - message: 'Got test event: {"foo":"bar"}', - }) - ); - }, - TEST_CASE_TIMEOUT - ); + const idempotencyRecord = await dynamoDBClient.send( + new ScanCommand({ + TableName: tableNameDefault, + }) + ); + expect(idempotencyRecord.Items).toHaveLength(1); + expect(idempotencyRecord.Items?.[0].id).toEqual( + `${functionNameDefault}#${payloadHash}` + ); + expect(idempotencyRecord.Items?.[0].data).toBeUndefined(); + expect(idempotencyRecord.Items?.[0].status).toEqual('COMPLETED'); + // During the first invocation the handler should be called, so the logs should contain 1 log + expect(functionLogs[0]).toHaveLength(1); + // We test the content of the log as well as the presence of fields from the context, this + // ensures that the all the arguments are passed to the handler when made idempotent + expect(TestInvocationLogs.parseFunctionLog(functionLogs[0][0])).toEqual( + expect.objectContaining({ + message: 'Got test event: {"foo":"bar"}', + }) + ); + }); - it( - 'handles parallel invocations correctly', - async () => { - const payload = { foo: 'bar' }; - const payloadHash = createHash('md5') - .update(JSON.stringify(payload)) - .digest('base64'); - const logs = await invokeFunction({ - functionName: functionNameDefaultParallel, - times: 2, - invocationMode: 'PARALLEL', - payload: payload, - }); - - const functionLogs = logs.map((log) => log.getFunctionLogs()); - - const idempotencyRecords = await dynamoDBClient.send( - new ScanCommand({ - TableName: tableNameDefaultParallel, - }) - ); - expect(idempotencyRecords.Items).toHaveLength(1); - expect(idempotencyRecords.Items?.[0].id).toEqual( - `${functionNameDefaultParallel}#${payloadHash}` - ); - expect(idempotencyRecords.Items?.[0].data).toEqual('bar'); - expect(idempotencyRecords.Items?.[0].status).toEqual('COMPLETED'); - expect(idempotencyRecords?.Items?.[0].expiration).toBeGreaterThan( - Date.now() / 1000 - ); - const successfulInvocationLogs = functionLogs.find( - (functionLog) => - functionLog.toString().includes('Processed event') !== undefined - ); - - const failedInvocationLogs = functionLogs.find( - (functionLog) => - functionLog - .toString() - .includes('There is already an execution in progres') !== undefined - ); - - expect(successfulInvocationLogs).toBeDefined(); - expect(failedInvocationLogs).toBeDefined(); - }, - TEST_CASE_TIMEOUT - ); + it('handles parallel invocations correctly', async () => { + const payload = { foo: 'bar' }; + const payloadHash = createHash('md5') + .update(JSON.stringify(payload)) + .digest('base64'); + const logs = await invokeFunction({ + functionName: functionNameDefaultParallel, + times: 2, + invocationMode: 'PARALLEL', + payload: payload, + }); + + const functionLogs = logs.map((log) => log.getFunctionLogs()); + + const idempotencyRecords = await dynamoDBClient.send( + new ScanCommand({ + TableName: tableNameDefaultParallel, + }) + ); + expect(idempotencyRecords.Items).toHaveLength(1); + expect(idempotencyRecords.Items?.[0].id).toEqual( + `${functionNameDefaultParallel}#${payloadHash}` + ); + expect(idempotencyRecords.Items?.[0].data).toEqual('bar'); + expect(idempotencyRecords.Items?.[0].status).toEqual('COMPLETED'); + expect(idempotencyRecords?.Items?.[0].expiration).toBeGreaterThan( + Date.now() / 1000 + ); + const successfulInvocationLogs = functionLogs.find( + (functionLog) => + functionLog.toString().includes('Processed event') !== undefined + ); - it( - 'recovers from a timed out request and processes the next one', - async () => { - const payload = { foo: 'bar' }; - const payloadHash = createHash('md5') - .update(JSON.stringify(payload.foo)) - .digest('base64'); - - const logs = await invokeFunction({ - functionName: functionNameTimeout, - times: 2, - invocationMode: 'SEQUENTIAL', - payload: Array.from({ length: 2 }, (_, index) => ({ - ...payload, - invocation: index, - })), - }); - const functionLogs = logs.map((log) => log.getFunctionLogs()); - const idempotencyRecord = await dynamoDBClient.send( - new ScanCommand({ - TableName: tableNameTimeout, - }) - ); - expect(idempotencyRecord.Items).toHaveLength(1); - expect(idempotencyRecord.Items?.[0].id).toEqual( - `${functionNameTimeout}#${payloadHash}` - ); - expect(idempotencyRecord.Items?.[0].data).toEqual({ - ...payload, - invocation: 1, - }); - expect(idempotencyRecord.Items?.[0].status).toEqual('COMPLETED'); - - try { - // During the first invocation the handler should be called, so the logs should contain 1 log - expect(functionLogs[0]).toHaveLength(2); - expect(functionLogs[0][0]).toContain('Task timed out after'); - } catch { - // During the first invocation the function should timeout so the logs should not contain any log and the report log should contain a timeout message - expect(functionLogs[0]).toHaveLength(0); - expect(logs[0].getReportLog()).toMatch(/Status: timeout$/); - } - - expect(functionLogs[1]).toHaveLength(1); - expect(TestInvocationLogs.parseFunctionLog(functionLogs[1][0])).toEqual( - expect.objectContaining({ - message: 'Processed event', - details: 'bar', - function_name: functionNameTimeout, - }) - ); - }, - TEST_CASE_TIMEOUT - ); + const failedInvocationLogs = functionLogs.find( + (functionLog) => + functionLog + .toString() + .includes('There is already an execution in progres') !== undefined + ); - it( - 'recovers from an expired idempotency record and processes the next request', - async () => { - const payload = { - foo: 'baz', - }; - const payloadHash = createHash('md5') - .update(JSON.stringify(payload.foo)) - .digest('base64'); - - // Act - const logs = [ - ( - await invokeFunction({ - functionName: functionNameExpired, - times: 1, - invocationMode: 'SEQUENTIAL', - payload: { ...payload, invocation: 0 }, - }) - )[0], - ]; - // Wait for the idempotency record to expire - await new Promise((resolve) => setTimeout(resolve, 2000)); - logs.push( - ( - await invokeFunction({ - functionName: functionNameExpired, - times: 1, - invocationMode: 'SEQUENTIAL', - payload: { ...payload, invocation: 1 }, - }) - )[0] - ); - const functionLogs = logs.map((log) => log.getFunctionLogs()); - - // Assess - const idempotencyRecords = await dynamoDBClient.send( - new ScanCommand({ - TableName: tableNameExpired, - }) - ); - expect(idempotencyRecords.Items).toHaveLength(1); - expect(idempotencyRecords.Items?.[0].id).toEqual( - `${functionNameExpired}#${payloadHash}` - ); - expect(idempotencyRecords.Items?.[0].data).toEqual({ + expect(successfulInvocationLogs).toBeDefined(); + expect(failedInvocationLogs).toBeDefined(); + }); + + it('recovers from a timed out request and processes the next one', async () => { + const payload = { foo: 'bar' }; + const payloadHash = createHash('md5') + .update(JSON.stringify(payload.foo)) + .digest('base64'); + + const logs = await invokeFunction({ + functionName: functionNameTimeout, + times: 2, + invocationMode: 'SEQUENTIAL', + payload: Array.from({ length: 2 }, (_, index) => ({ ...payload, - invocation: 1, - }); - expect(idempotencyRecords.Items?.[0].status).toEqual('COMPLETED'); - - // Both invocations should be successful and the logs should contain 1 log each - expect(functionLogs[0]).toHaveLength(1); - expect(TestInvocationLogs.parseFunctionLog(functionLogs[1][0])).toEqual( - expect.objectContaining({ - message: 'Processed event', - details: 'baz', - function_name: functionNameExpired, - }) - ); - // During the second invocation the handler should be called and complete, so the logs should - // contain 1 log - expect(functionLogs[1]).toHaveLength(1); - expect(TestInvocationLogs.parseFunctionLog(functionLogs[1][0])).toEqual( - expect.objectContaining({ - message: 'Processed event', - details: 'baz', - function_name: functionNameExpired, - }) - ); - }, - TEST_CASE_TIMEOUT - ); + invocation: index, + })), + }); + const functionLogs = logs.map((log) => log.getFunctionLogs()); + const idempotencyRecord = await dynamoDBClient.send( + new ScanCommand({ + TableName: tableNameTimeout, + }) + ); + expect(idempotencyRecord.Items).toHaveLength(1); + expect(idempotencyRecord.Items?.[0].id).toEqual( + `${functionNameTimeout}#${payloadHash}` + ); + expect(idempotencyRecord.Items?.[0].data).toEqual({ + ...payload, + invocation: 1, + }); + expect(idempotencyRecord.Items?.[0].status).toEqual('COMPLETED'); - it( - 'uses the provided custom idempotency record attributes', - async () => { - const payload = { foo: 'bar' }; - const payloadHash = createHash('md5') - .update(JSON.stringify(payload)) - .digest('base64'); - const logs = await invokeFunction({ - functionName: functionCustomConfig, - times: 1, - invocationMode: 'SEQUENTIAL', - payload: payload, - }); - - const functionLogs = logs.map((log) => log.getFunctionLogs()); - - const idempotencyRecord = await dynamoDBClient.send( - new ScanCommand({ - TableName: tableNameCustomConfig, - }) - ); - expect(idempotencyRecord.Items?.[0]).toStrictEqual({ - customId: `${functionCustomConfig}#${payloadHash}`, - dataAttr: 'bar', - statusAttr: 'COMPLETED', - expiryAttr: expect.any(Number), - inProgressExpiryAttr: expect.any(Number), - }); - - expect(functionLogs[0]).toHaveLength(1); - expect(TestInvocationLogs.parseFunctionLog(functionLogs[0][0])).toEqual( - expect.objectContaining({ - message: 'Processed event', - details: 'bar', - }) - ); - }, - TEST_CASE_TIMEOUT - ); + try { + // During the first invocation the handler should be called, so the logs should contain 1 log + expect(functionLogs[0]).toHaveLength(2); + expect(functionLogs[0][0]).toContain('Task timed out after'); + } catch { + // During the first invocation the function should timeout so the logs should not contain any log and the report log should contain a timeout message + expect(functionLogs[0]).toHaveLength(0); + expect(logs[0].getReportLog()).toMatch(/Status: timeout$/); + } - it( - 'takes the data index argument into account when making the function idempotent', - async () => { - const payload = [{ id: '1234' }, { id: '5678' }]; - const payloadHash = createHash('md5') - .update(JSON.stringify('bar')) - .digest('base64'); - - const logs = await invokeFunction({ - functionName: functionNameDataIndex, - times: 2, - invocationMode: 'SEQUENTIAL', - payload: payload, - }); - - const functionLogs = logs.map((log) => log.getFunctionLogs()); - - const idempotencyRecord = await dynamoDBClient.send( - new ScanCommand({ - TableName: tableNameDataIndex, + expect(functionLogs[1]).toHaveLength(1); + expect(TestInvocationLogs.parseFunctionLog(functionLogs[1][0])).toEqual( + expect.objectContaining({ + message: 'Processed event', + details: 'bar', + function_name: functionNameTimeout, + }) + ); + }); + + it('recovers from an expired idempotency record and processes the next request', async () => { + const payload = { + foo: 'baz', + }; + const payloadHash = createHash('md5') + .update(JSON.stringify(payload.foo)) + .digest('base64'); + + // Act + const logs = [ + ( + await invokeFunction({ + functionName: functionNameExpired, + times: 1, + invocationMode: 'SEQUENTIAL', + payload: { ...payload, invocation: 0 }, }) - ); - expect(idempotencyRecord.Items).toHaveLength(1); - expect(idempotencyRecord.Items?.[0].id).toEqual( - `${functionNameDataIndex}#${payloadHash}` - ); - expect(idempotencyRecord.Items?.[0].data).toEqual( - 'idempotent result: bar' - ); - expect(idempotencyRecord.Items?.[0].status).toEqual('COMPLETED'); - // During the first invocation the handler should be called, so the logs should contain 1 log - expect(functionLogs[0]).toHaveLength(1); - // We test the content of the log as well as the presence of fields from the context, this - // ensures that the all the arguments are passed to the handler when made idempotent - expect(TestInvocationLogs.parseFunctionLog(functionLogs[0][0])).toEqual( - expect.objectContaining({ - message: 'Got test event', - id: '1234', - foo: 'bar', + )[0], + ]; + // Wait for the idempotency record to expire + await new Promise((resolve) => setTimeout(resolve, 2000)); + logs.push( + ( + await invokeFunction({ + functionName: functionNameExpired, + times: 1, + invocationMode: 'SEQUENTIAL', + payload: { ...payload, invocation: 1 }, }) - ); - }, - TEST_CASE_TIMEOUT - ); + )[0] + ); + const functionLogs = logs.map((log) => log.getFunctionLogs()); + + // Assess + const idempotencyRecords = await dynamoDBClient.send( + new ScanCommand({ + TableName: tableNameExpired, + }) + ); + expect(idempotencyRecords.Items).toHaveLength(1); + expect(idempotencyRecords.Items?.[0].id).toEqual( + `${functionNameExpired}#${payloadHash}` + ); + expect(idempotencyRecords.Items?.[0].data).toEqual({ + ...payload, + invocation: 1, + }); + expect(idempotencyRecords.Items?.[0].status).toEqual('COMPLETED'); + + // Both invocations should be successful and the logs should contain 1 log each + expect(functionLogs[0]).toHaveLength(1); + expect(TestInvocationLogs.parseFunctionLog(functionLogs[1][0])).toEqual( + expect.objectContaining({ + message: 'Processed event', + details: 'baz', + function_name: functionNameExpired, + }) + ); + // During the second invocation the handler should be called and complete, so the logs should + // contain 1 log + expect(functionLogs[1]).toHaveLength(1); + expect(TestInvocationLogs.parseFunctionLog(functionLogs[1][0])).toEqual( + expect.objectContaining({ + message: 'Processed event', + details: 'baz', + function_name: functionNameExpired, + }) + ); + }); + + it('uses the provided custom idempotency record attributes', async () => { + const payload = { foo: 'bar' }; + const payloadHash = createHash('md5') + .update(JSON.stringify(payload)) + .digest('base64'); + const logs = await invokeFunction({ + functionName: functionCustomConfig, + times: 1, + invocationMode: 'SEQUENTIAL', + payload: payload, + }); + + const functionLogs = logs.map((log) => log.getFunctionLogs()); + + const idempotencyRecord = await dynamoDBClient.send( + new ScanCommand({ + TableName: tableNameCustomConfig, + }) + ); + expect(idempotencyRecord.Items?.[0]).toStrictEqual({ + customId: `${functionCustomConfig}#${payloadHash}`, + dataAttr: 'bar', + statusAttr: 'COMPLETED', + expiryAttr: expect.any(Number), + inProgressExpiryAttr: expect.any(Number), + }); + + expect(functionLogs[0]).toHaveLength(1); + expect(TestInvocationLogs.parseFunctionLog(functionLogs[0][0])).toEqual( + expect.objectContaining({ + message: 'Processed event', + details: 'bar', + }) + ); + }); + + it('takes the data index argument into account when making the function idempotent', async () => { + const payload = [{ id: '1234' }, { id: '5678' }]; + const payloadHash = createHash('md5') + .update(JSON.stringify('bar')) + .digest('base64'); + + const logs = await invokeFunction({ + functionName: functionNameDataIndex, + times: 2, + invocationMode: 'SEQUENTIAL', + payload: payload, + }); + + const functionLogs = logs.map((log) => log.getFunctionLogs()); + + const idempotencyRecord = await dynamoDBClient.send( + new ScanCommand({ + TableName: tableNameDataIndex, + }) + ); + expect(idempotencyRecord.Items).toHaveLength(1); + expect(idempotencyRecord.Items?.[0].id).toEqual( + `${functionNameDataIndex}#${payloadHash}` + ); + expect(idempotencyRecord.Items?.[0].data).toEqual('idempotent result: bar'); + expect(idempotencyRecord.Items?.[0].status).toEqual('COMPLETED'); + // During the first invocation the handler should be called, so the logs should contain 1 log + expect(functionLogs[0]).toHaveLength(1); + // We test the content of the log as well as the presence of fields from the context, this + // ensures that the all the arguments are passed to the handler when made idempotent + expect(TestInvocationLogs.parseFunctionLog(functionLogs[0][0])).toEqual( + expect.objectContaining({ + message: 'Got test event', + id: '1234', + foo: 'bar', + }) + ); + }); afterAll(async () => { if (!process.env.DISABLE_TEARDOWN) { await testStack.destroy(); } - }, TEARDOWN_TIMEOUT); + }); }); diff --git a/packages/idempotency/tests/e2e/makeHandlerIdempotent.test.ts b/packages/idempotency/tests/e2e/makeHandlerIdempotent.test.ts index f6a2cfbf63..9b92a56af8 100644 --- a/packages/idempotency/tests/e2e/makeHandlerIdempotent.test.ts +++ b/packages/idempotency/tests/e2e/makeHandlerIdempotent.test.ts @@ -10,12 +10,7 @@ import { ScanCommand } from '@aws-sdk/lib-dynamodb'; import { Duration } from 'aws-cdk-lib'; import { afterAll, beforeAll, describe, expect, it } from 'vitest'; import { IdempotencyTestNodejsFunctionAndDynamoTable } from '../helpers/resources.js'; -import { - RESOURCE_NAME_PREFIX, - SETUP_TIMEOUT, - TEARDOWN_TIMEOUT, - TEST_CASE_TIMEOUT, -} from './constants.js'; +import { RESOURCE_NAME_PREFIX } from './constants.js'; const ddb = new DynamoDBClient({}); @@ -110,255 +105,238 @@ describe('Idempotency E2E tests, middy middleware usage', () => { tableNameTimeout = testStack.findAndGetStackOutputValue('timeoutTable'); functionNameExpired = testStack.findAndGetStackOutputValue('expiredFn'); tableNameExpired = testStack.findAndGetStackOutputValue('expiredTable'); - }, SETUP_TIMEOUT); - - it( - 'returns the same result and runs the handler once when called multiple times', - async () => { - // Prepare - const payload = { - foo: 'bar', - }; - const payloadHash = createHash('md5') - .update(JSON.stringify(payload)) - .digest('base64'); + }); - // Act - const logs = await invokeFunction({ - functionName: functionNameDefault, - times: 2, - invocationMode: 'SEQUENTIAL', - payload, - }); - const functionLogs = logs.map((log) => log.getFunctionLogs()); + it('returns the same result and runs the handler once when called multiple times', async () => { + // Prepare + const payload = { + foo: 'bar', + }; + const payloadHash = createHash('md5') + .update(JSON.stringify(payload)) + .digest('base64'); - // Assess - const idempotencyRecords = await ddb.send( - new ScanCommand({ - TableName: tableNameDefault, - }) - ); - expect(idempotencyRecords.Items?.length).toEqual(1); - expect(idempotencyRecords.Items?.[0].id).toEqual( - `${functionNameDefault}#${payloadHash}` - ); - expect(idempotencyRecords.Items?.[0].data).toEqual('bar'); - expect(idempotencyRecords.Items?.[0].status).toEqual('COMPLETED'); + // Act + const logs = await invokeFunction({ + functionName: functionNameDefault, + times: 2, + invocationMode: 'SEQUENTIAL', + payload, + }); + const functionLogs = logs.map((log) => log.getFunctionLogs()); - // During the first invocation the handler should be called, so the logs should contain 1 log - expect(functionLogs[0]).toHaveLength(1); - // We test the content of the log as well as the presence of fields from the context, this - // ensures that the all the arguments are passed to the handler when made idempotent - expect(TestInvocationLogs.parseFunctionLog(functionLogs[0][0])).toEqual( - expect.objectContaining({ - message: 'foo', - details: 'bar', - function_name: functionNameDefault, - }) - ); - // During the second invocation the handler should not be called, so the logs should be empty - expect(functionLogs[1]).toHaveLength(0); - }, - TEST_CASE_TIMEOUT - ); + // Assess + const idempotencyRecords = await ddb.send( + new ScanCommand({ + TableName: tableNameDefault, + }) + ); + expect(idempotencyRecords.Items?.length).toEqual(1); + expect(idempotencyRecords.Items?.[0].id).toEqual( + `${functionNameDefault}#${payloadHash}` + ); + expect(idempotencyRecords.Items?.[0].data).toEqual('bar'); + expect(idempotencyRecords.Items?.[0].status).toEqual('COMPLETED'); - it( - 'handles parallel invocations correctly', - async () => { - // Prepare - const payload = { - foo: 'bar', - }; - const payloadHash = createHash('md5') - .update(JSON.stringify(payload)) - .digest('base64'); + // During the first invocation the handler should be called, so the logs should contain 1 log + expect(functionLogs[0]).toHaveLength(1); + // We test the content of the log as well as the presence of fields from the context, this + // ensures that the all the arguments are passed to the handler when made idempotent + expect(TestInvocationLogs.parseFunctionLog(functionLogs[0][0])).toEqual( + expect.objectContaining({ + message: 'foo', + details: 'bar', + function_name: functionNameDefault, + }) + ); + // During the second invocation the handler should not be called, so the logs should be empty + expect(functionLogs[1]).toHaveLength(0); + }); - // Act - const logs = await invokeFunction({ - functionName: functionNameDefaultParallel, - times: 2, - invocationMode: 'PARALLEL', - payload, - }); - const functionLogs = logs.map((log) => log.getFunctionLogs()); + it('handles parallel invocations correctly', async () => { + // Prepare + const payload = { + foo: 'bar', + }; + const payloadHash = createHash('md5') + .update(JSON.stringify(payload)) + .digest('base64'); - // Assess - const idempotencyRecords = await ddb.send( - new ScanCommand({ - TableName: tableNameDefaultParallel, - }) - ); - expect(idempotencyRecords.Items?.length).toEqual(1); - expect(idempotencyRecords.Items?.[0].id).toEqual( - `${functionNameDefaultParallel}#${payloadHash}` - ); - expect(idempotencyRecords.Items?.[0].data).toEqual('bar'); - expect(idempotencyRecords.Items?.[0].status).toEqual('COMPLETED'); + // Act + const logs = await invokeFunction({ + functionName: functionNameDefaultParallel, + times: 2, + invocationMode: 'PARALLEL', + payload, + }); + const functionLogs = logs.map((log) => log.getFunctionLogs()); - /** - * Since the requests are sent in parallel we don't know which one will be processed first, - * however we expect that only on of them will be processed by the handler, while the other - * one will be rejected with IdempotencyAlreadyInProgressError. - * - * We filter the logs to find which one was successful and which one failed, then we check - * that they contain the expected logs. - */ - const successfulInvocationLogs = functionLogs.find( - (functionLog) => - functionLog.find((log) => log.includes('Processed event')) !== - undefined - ); - const failedInvocationLogs = functionLogs.find( - (functionLog) => - functionLog.find((log) => - log.includes('There is already an execution in progress') - ) !== undefined - ); - expect(successfulInvocationLogs).toHaveLength(1); - expect(failedInvocationLogs).toHaveLength(1); - }, - TEST_CASE_TIMEOUT - ); + // Assess + const idempotencyRecords = await ddb.send( + new ScanCommand({ + TableName: tableNameDefaultParallel, + }) + ); + expect(idempotencyRecords.Items?.length).toEqual(1); + expect(idempotencyRecords.Items?.[0].id).toEqual( + `${functionNameDefaultParallel}#${payloadHash}` + ); + expect(idempotencyRecords.Items?.[0].data).toEqual('bar'); + expect(idempotencyRecords.Items?.[0].status).toEqual('COMPLETED'); - it( - 'recovers from a timed out request and processes the next one', - async () => { - // Prepare - const payload = { - foo: 'bar', - }; - const payloadHash = createHash('md5') - .update(JSON.stringify(payload.foo)) - .digest('base64'); + /** + * Since the requests are sent in parallel we don't know which one will be processed first, + * however we expect that only on of them will be processed by the handler, while the other + * one will be rejected with IdempotencyAlreadyInProgressError. + * + * We filter the logs to find which one was successful and which one failed, then we check + * that they contain the expected logs. + */ + const successfulInvocationLogs = functionLogs.find( + (functionLog) => + functionLog.find((log) => log.includes('Processed event')) !== undefined + ); + const failedInvocationLogs = functionLogs.find( + (functionLog) => + functionLog.find((log) => + log.includes('There is already an execution in progress') + ) !== undefined + ); + expect(successfulInvocationLogs).toHaveLength(1); + expect(failedInvocationLogs).toHaveLength(1); + }); - // Act - const logs = await invokeFunction({ - functionName: functionNameTimeout, - times: 2, - invocationMode: 'SEQUENTIAL', - payload: Array.from({ length: 2 }, (_, index) => ({ - ...payload, - invocation: index, - })), - }); - const functionLogs = logs.map((log) => log.getFunctionLogs()); + it('recovers from a timed out request and processes the next one', async () => { + // Prepare + const payload = { + foo: 'bar', + }; + const payloadHash = createHash('md5') + .update(JSON.stringify(payload.foo)) + .digest('base64'); - // Assess - const idempotencyRecords = await ddb.send( - new ScanCommand({ - TableName: tableNameTimeout, - }) - ); - expect(idempotencyRecords.Items?.length).toEqual(1); - expect(idempotencyRecords.Items?.[0].id).toEqual( - `${functionNameTimeout}#${payloadHash}` - ); - expect(idempotencyRecords.Items?.[0].data).toEqual({ + // Act + const logs = await invokeFunction({ + functionName: functionNameTimeout, + times: 2, + invocationMode: 'SEQUENTIAL', + payload: Array.from({ length: 2 }, (_, index) => ({ ...payload, - invocation: 1, - }); - expect(idempotencyRecords.Items?.[0].status).toEqual('COMPLETED'); - - try { - // During the first invocation the handler should be called, so the logs should contain 1 log - expect(functionLogs[0]).toHaveLength(2); - expect(functionLogs[0][0]).toContain('Task timed out after'); - } catch { - // During the first invocation the function should timeout so the logs should not contain any log and the report log should contain a timeout message - expect(functionLogs[0]).toHaveLength(0); - expect(logs[0].getReportLog()).toMatch(/Status: timeout$/); - } + invocation: index, + })), + }); + const functionLogs = logs.map((log) => log.getFunctionLogs()); - // During the second invocation the handler should be called and complete, so the logs should - // contain 1 log - expect(functionLogs[1]).toHaveLength(1); - expect(TestInvocationLogs.parseFunctionLog(functionLogs[1][0])).toEqual( - expect.objectContaining({ - message: 'Processed event', - details: 'bar', - function_name: functionNameTimeout, - }) - ); - }, - TEST_CASE_TIMEOUT - ); + // Assess + const idempotencyRecords = await ddb.send( + new ScanCommand({ + TableName: tableNameTimeout, + }) + ); + expect(idempotencyRecords.Items?.length).toEqual(1); + expect(idempotencyRecords.Items?.[0].id).toEqual( + `${functionNameTimeout}#${payloadHash}` + ); + expect(idempotencyRecords.Items?.[0].data).toEqual({ + ...payload, + invocation: 1, + }); + expect(idempotencyRecords.Items?.[0].status).toEqual('COMPLETED'); - it( - 'recovers from an expired idempotency record and processes the next request', - async () => { - // Prepare - const payload = { - foo: 'bar', - }; - const payloadHash = createHash('md5') - .update(JSON.stringify(payload.foo)) - .digest('base64'); + try { + // During the first invocation the handler should be called, so the logs should contain 1 log + expect(functionLogs[0]).toHaveLength(2); + expect(functionLogs[0][0]).toContain('Task timed out after'); + } catch { + // During the first invocation the function should timeout so the logs should not contain any log and the report log should contain a timeout message + expect(functionLogs[0]).toHaveLength(0); + expect(logs[0].getReportLog()).toMatch(/Status: timeout$/); + } - // Act - const logs = [ - ( - await invokeFunction({ - functionName: functionNameExpired, - times: 1, - invocationMode: 'SEQUENTIAL', - payload: { ...payload, invocation: 0 }, - }) - )[0], - ]; - // Wait for the idempotency record to expire - await new Promise((resolve) => setTimeout(resolve, 2000)); - logs.push( - ( - await invokeFunction({ - functionName: functionNameExpired, - times: 1, - invocationMode: 'SEQUENTIAL', - payload: { ...payload, invocation: 1 }, - }) - )[0] - ); - const functionLogs = logs.map((log) => log.getFunctionLogs()); + // During the second invocation the handler should be called and complete, so the logs should + // contain 1 log + expect(functionLogs[1]).toHaveLength(1); + expect(TestInvocationLogs.parseFunctionLog(functionLogs[1][0])).toEqual( + expect.objectContaining({ + message: 'Processed event', + details: 'bar', + function_name: functionNameTimeout, + }) + ); + }); - // Assess - const idempotencyRecords = await ddb.send( - new ScanCommand({ - TableName: tableNameExpired, - }) - ); - expect(idempotencyRecords.Items?.length).toEqual(1); - expect(idempotencyRecords.Items?.[0].id).toEqual( - `${functionNameExpired}#${payloadHash}` - ); - expect(idempotencyRecords.Items?.[0].data).toEqual({ - ...payload, - invocation: 1, - }); - expect(idempotencyRecords.Items?.[0].status).toEqual('COMPLETED'); + it('recovers from an expired idempotency record and processes the next request', async () => { + // Prepare + const payload = { + foo: 'bar', + }; + const payloadHash = createHash('md5') + .update(JSON.stringify(payload.foo)) + .digest('base64'); - // Both invocations should be successful and the logs should contain 1 log each - expect(functionLogs[0]).toHaveLength(1); - expect(TestInvocationLogs.parseFunctionLog(functionLogs[1][0])).toEqual( - expect.objectContaining({ - message: 'Processed event', - details: 'bar', - function_name: functionNameExpired, + // Act + const logs = [ + ( + await invokeFunction({ + functionName: functionNameExpired, + times: 1, + invocationMode: 'SEQUENTIAL', + payload: { ...payload, invocation: 0 }, }) - ); - // During the second invocation the handler should be called and complete, so the logs should - // contain 1 log - expect(functionLogs[1]).toHaveLength(1); - expect(TestInvocationLogs.parseFunctionLog(functionLogs[1][0])).toEqual( - expect.objectContaining({ - message: 'Processed event', - details: 'bar', - function_name: functionNameExpired, + )[0], + ]; + // Wait for the idempotency record to expire + await new Promise((resolve) => setTimeout(resolve, 2000)); + logs.push( + ( + await invokeFunction({ + functionName: functionNameExpired, + times: 1, + invocationMode: 'SEQUENTIAL', + payload: { ...payload, invocation: 1 }, }) - ); - }, - TEST_CASE_TIMEOUT - ); + )[0] + ); + const functionLogs = logs.map((log) => log.getFunctionLogs()); + + // Assess + const idempotencyRecords = await ddb.send( + new ScanCommand({ + TableName: tableNameExpired, + }) + ); + expect(idempotencyRecords.Items?.length).toEqual(1); + expect(idempotencyRecords.Items?.[0].id).toEqual( + `${functionNameExpired}#${payloadHash}` + ); + expect(idempotencyRecords.Items?.[0].data).toEqual({ + ...payload, + invocation: 1, + }); + expect(idempotencyRecords.Items?.[0].status).toEqual('COMPLETED'); + + // Both invocations should be successful and the logs should contain 1 log each + expect(functionLogs[0]).toHaveLength(1); + expect(TestInvocationLogs.parseFunctionLog(functionLogs[1][0])).toEqual( + expect.objectContaining({ + message: 'Processed event', + details: 'bar', + function_name: functionNameExpired, + }) + ); + // During the second invocation the handler should be called and complete, so the logs should + // contain 1 log + expect(functionLogs[1]).toHaveLength(1); + expect(TestInvocationLogs.parseFunctionLog(functionLogs[1][0])).toEqual( + expect.objectContaining({ + message: 'Processed event', + details: 'bar', + function_name: functionNameExpired, + }) + ); + }); afterAll(async () => { await testStack.destroy(); - }, TEARDOWN_TIMEOUT); + }); }); diff --git a/packages/idempotency/tests/e2e/makeIdempotent.test.ts b/packages/idempotency/tests/e2e/makeIdempotent.test.ts index d510a0c893..c87bc9f6b7 100644 --- a/packages/idempotency/tests/e2e/makeIdempotent.test.ts +++ b/packages/idempotency/tests/e2e/makeIdempotent.test.ts @@ -10,12 +10,7 @@ import { ScanCommand } from '@aws-sdk/lib-dynamodb'; import { AttributeType } from 'aws-cdk-lib/aws-dynamodb'; import { afterAll, beforeAll, describe, expect, it } from 'vitest'; import { IdempotencyTestNodejsFunctionAndDynamoTable } from '../helpers/resources.js'; -import { - RESOURCE_NAME_PREFIX, - SETUP_TIMEOUT, - TEARDOWN_TIMEOUT, - TEST_CASE_TIMEOUT, -} from './constants'; +import { RESOURCE_NAME_PREFIX } from './constants'; describe('Idempotency E2E tests, wrapper function usage', () => { const testStack = new TestStack({ @@ -99,239 +94,224 @@ describe('Idempotency E2E tests, wrapper function usage', () => { testStack.findAndGetStackOutputValue('handlerFn'); tableNameLambdaHandler = testStack.findAndGetStackOutputValue('handlerTable'); - }, SETUP_TIMEOUT); + }); - it( - 'when called twice with the same payload, it returns the same result', - async () => { - // Prepare - const payload = { - records: [ - { foo: 'bar', id: 1 }, - { foo: 'baz', id: 2 }, - { foo: 'bar', id: 1 }, - ], - }; - const payloadHashes = payload.records.map((record) => - createHash('md5').update(JSON.stringify(record)).digest('base64') - ); + it('when called twice with the same payload, it returns the same result', async () => { + // Prepare + const payload = { + records: [ + { foo: 'bar', id: 1 }, + { foo: 'baz', id: 2 }, + { foo: 'bar', id: 1 }, + ], + }; + const payloadHashes = payload.records.map((record) => + createHash('md5').update(JSON.stringify(record)).digest('base64') + ); - // Act - const logs = await invokeFunction({ - functionName: functionNameDefault, - times: 2, - invocationMode: 'SEQUENTIAL', - payload, - }); - const functionLogs = logs.map((log) => log.getFunctionLogs()); + // Act + const logs = await invokeFunction({ + functionName: functionNameDefault, + times: 2, + invocationMode: 'SEQUENTIAL', + payload, + }); + const functionLogs = logs.map((log) => log.getFunctionLogs()); - // Assess - const idempotencyRecords = await ddb.send( - new ScanCommand({ - TableName: tableNameDefault, - }) - ); - // Since records 1 and 3 have the same payload, only 2 records should be created - expect(idempotencyRecords?.Items?.length).toEqual(2); - const idempotencyRecordsItems = [ - idempotencyRecords.Items?.find( - (record) => record.id === `${functionNameDefault}#${payloadHashes[0]}` - ), - idempotencyRecords.Items?.find( - (record) => record.id === `${functionNameDefault}#${payloadHashes[1]}` - ), - ]; + // Assess + const idempotencyRecords = await ddb.send( + new ScanCommand({ + TableName: tableNameDefault, + }) + ); + // Since records 1 and 3 have the same payload, only 2 records should be created + expect(idempotencyRecords?.Items?.length).toEqual(2); + const idempotencyRecordsItems = [ + idempotencyRecords.Items?.find( + (record) => record.id === `${functionNameDefault}#${payloadHashes[0]}` + ), + idempotencyRecords.Items?.find( + (record) => record.id === `${functionNameDefault}#${payloadHashes[1]}` + ), + ]; - expect(idempotencyRecordsItems?.[0]).toStrictEqual({ - id: `${functionNameDefault}#${payloadHashes[0]}`, - data: 'Processing done: bar', - status: 'COMPLETED', - expiration: expect.any(Number), - in_progress_expiration: expect.any(Number), - }); + expect(idempotencyRecordsItems?.[0]).toStrictEqual({ + id: `${functionNameDefault}#${payloadHashes[0]}`, + data: 'Processing done: bar', + status: 'COMPLETED', + expiration: expect.any(Number), + in_progress_expiration: expect.any(Number), + }); - expect(idempotencyRecordsItems?.[1]).toStrictEqual({ - id: `${functionNameDefault}#${payloadHashes[1]}`, - data: 'Processing done: baz', - status: 'COMPLETED', - expiration: expect.any(Number), - in_progress_expiration: expect.any(Number), - }); + expect(idempotencyRecordsItems?.[1]).toStrictEqual({ + id: `${functionNameDefault}#${payloadHashes[1]}`, + data: 'Processing done: baz', + status: 'COMPLETED', + expiration: expect.any(Number), + in_progress_expiration: expect.any(Number), + }); - expect(functionLogs[0]).toHaveLength(2); - }, - TEST_CASE_TIMEOUT - ); + expect(functionLogs[0]).toHaveLength(2); + }); - it( - 'creates a DynamoDB item with the correct attributes', - async () => { - // Prepare - const payload = { - records: [ - { foo: 'bar', id: 1 }, - { foo: 'baq', id: 2 }, - { foo: 'bar', id: 3 }, - ], - }; - const payloadHashes = payload.records.map((record) => - createHash('md5').update(JSON.stringify(record)).digest('base64') - ); - const validationHashes = payload.records.map((record) => - createHash('md5').update(JSON.stringify(record.foo)).digest('base64') - ); + it('creates a DynamoDB item with the correct attributes', async () => { + // Prepare + const payload = { + records: [ + { foo: 'bar', id: 1 }, + { foo: 'baq', id: 2 }, + { foo: 'bar', id: 3 }, + ], + }; + const payloadHashes = payload.records.map((record) => + createHash('md5').update(JSON.stringify(record)).digest('base64') + ); + const validationHashes = payload.records.map((record) => + createHash('md5').update(JSON.stringify(record.foo)).digest('base64') + ); - // Act - const logs = await invokeFunction({ - functionName: functionNameCustomConfig, - times: 2, - invocationMode: 'SEQUENTIAL', - payload, - }); - const functionLogs = logs.map((log) => log.getFunctionLogs()); + // Act + const logs = await invokeFunction({ + functionName: functionNameCustomConfig, + times: 2, + invocationMode: 'SEQUENTIAL', + payload, + }); + const functionLogs = logs.map((log) => log.getFunctionLogs()); - // Assess - const idempotencyRecords = await ddb.send( - new ScanCommand({ - TableName: tableNameCustomConfig, - }) - ); - /** - * Each record should have a corresponding entry in the persistence store, - * if so then we retrieve the records based on their custom IDs - * The records are retrieved in the same order as the payload records. - */ - expect(idempotencyRecords.Items?.length).toEqual(3); - const idempotencyRecordsItems = [ - idempotencyRecords.Items?.find( - (record) => - record.customId === - `${functionNameCustomConfig}#${payloadHashes[0]}` - ), - idempotencyRecords.Items?.find( - (record) => - record.customId === - `${functionNameCustomConfig}#${payloadHashes[1]}` - ), - idempotencyRecords.Items?.find( - (record) => - record.customId === - `${functionNameCustomConfig}#${payloadHashes[2]}` - ), - ]; + // Assess + const idempotencyRecords = await ddb.send( + new ScanCommand({ + TableName: tableNameCustomConfig, + }) + ); + /** + * Each record should have a corresponding entry in the persistence store, + * if so then we retrieve the records based on their custom IDs + * The records are retrieved in the same order as the payload records. + */ + expect(idempotencyRecords.Items?.length).toEqual(3); + const idempotencyRecordsItems = [ + idempotencyRecords.Items?.find( + (record) => + record.customId === `${functionNameCustomConfig}#${payloadHashes[0]}` + ), + idempotencyRecords.Items?.find( + (record) => + record.customId === `${functionNameCustomConfig}#${payloadHashes[1]}` + ), + idempotencyRecords.Items?.find( + (record) => + record.customId === `${functionNameCustomConfig}#${payloadHashes[2]}` + ), + ]; - expect(idempotencyRecordsItems?.[0]).toStrictEqual({ - customId: `${functionNameCustomConfig}#${payloadHashes[0]}`, - dataAttr: payload.records[0], - statusAttr: 'COMPLETED', - expiryAttr: expect.any(Number), - inProgressExpiryAttr: expect.any(Number), - validationKeyAttr: validationHashes[0], - }); + expect(idempotencyRecordsItems?.[0]).toStrictEqual({ + customId: `${functionNameCustomConfig}#${payloadHashes[0]}`, + dataAttr: payload.records[0], + statusAttr: 'COMPLETED', + expiryAttr: expect.any(Number), + inProgressExpiryAttr: expect.any(Number), + validationKeyAttr: validationHashes[0], + }); - expect(idempotencyRecordsItems?.[1]).toStrictEqual({ - customId: `${functionNameCustomConfig}#${payloadHashes[1]}`, - dataAttr: payload.records[1], - statusAttr: 'COMPLETED', - expiryAttr: expect.any(Number), - inProgressExpiryAttr: expect.any(Number), - validationKeyAttr: validationHashes[1], - }); + expect(idempotencyRecordsItems?.[1]).toStrictEqual({ + customId: `${functionNameCustomConfig}#${payloadHashes[1]}`, + dataAttr: payload.records[1], + statusAttr: 'COMPLETED', + expiryAttr: expect.any(Number), + inProgressExpiryAttr: expect.any(Number), + validationKeyAttr: validationHashes[1], + }); - expect(idempotencyRecordsItems?.[2]).toStrictEqual({ - customId: `${functionNameCustomConfig}#${payloadHashes[2]}`, - dataAttr: payload.records[2], - statusAttr: 'COMPLETED', - expiryAttr: expect.any(Number), - inProgressExpiryAttr: expect.any(Number), - validationKeyAttr: validationHashes[2], - }); + expect(idempotencyRecordsItems?.[2]).toStrictEqual({ + customId: `${functionNameCustomConfig}#${payloadHashes[2]}`, + dataAttr: payload.records[2], + statusAttr: 'COMPLETED', + expiryAttr: expect.any(Number), + inProgressExpiryAttr: expect.any(Number), + validationKeyAttr: validationHashes[2], + }); - // During the first invocation, the processing function should have been called 3 times (once for each record) - expect(functionLogs[0]).toHaveLength(3); - expect(TestInvocationLogs.parseFunctionLog(functionLogs[0][0])).toEqual( - expect.objectContaining({ - baz: 0, // index of recursion in handler, assess that all function arguments are preserved - record: payload.records[0], - message: 'Got test event', - }) - ); - expect(TestInvocationLogs.parseFunctionLog(functionLogs[0][1])).toEqual( - expect.objectContaining({ - baz: 1, - record: payload.records[1], - message: 'Got test event', - }) - ); - expect(TestInvocationLogs.parseFunctionLog(functionLogs[0][2])).toEqual( - expect.objectContaining({ - baz: 2, - record: payload.records[2], - message: 'Got test event', - }) - ); + // During the first invocation, the processing function should have been called 3 times (once for each record) + expect(functionLogs[0]).toHaveLength(3); + expect(TestInvocationLogs.parseFunctionLog(functionLogs[0][0])).toEqual( + expect.objectContaining({ + baz: 0, // index of recursion in handler, assess that all function arguments are preserved + record: payload.records[0], + message: 'Got test event', + }) + ); + expect(TestInvocationLogs.parseFunctionLog(functionLogs[0][1])).toEqual( + expect.objectContaining({ + baz: 1, + record: payload.records[1], + message: 'Got test event', + }) + ); + expect(TestInvocationLogs.parseFunctionLog(functionLogs[0][2])).toEqual( + expect.objectContaining({ + baz: 2, + record: payload.records[2], + message: 'Got test event', + }) + ); - // During the second invocation, the processing function should have been called 0 times (all records are idempotent) - expect(functionLogs[1]).toHaveLength(0); - }, - TEST_CASE_TIMEOUT - ); + // During the second invocation, the processing function should have been called 0 times (all records are idempotent) + expect(functionLogs[1]).toHaveLength(0); + }); - it( - 'calls the wrapped function once and always returns the same result when called multiple times', - async () => { - // Prepare - const payload = { - body: JSON.stringify({ - foo: 'bar', - }), - }; - const payloadHash = createHash('md5') - .update(JSON.stringify('bar')) - .digest('base64'); + it('calls the wrapped function once and always returns the same result when called multiple times', async () => { + // Prepare + const payload = { + body: JSON.stringify({ + foo: 'bar', + }), + }; + const payloadHash = createHash('md5') + .update(JSON.stringify('bar')) + .digest('base64'); - // Act - const logs = await invokeFunction({ - functionName: functionNameLambdaHandler, - times: 2, - invocationMode: 'SEQUENTIAL', - payload, - }); - const functionLogs = logs.map((log) => log.getFunctionLogs()); + // Act + const logs = await invokeFunction({ + functionName: functionNameLambdaHandler, + times: 2, + invocationMode: 'SEQUENTIAL', + payload, + }); + const functionLogs = logs.map((log) => log.getFunctionLogs()); - // Assess - const idempotencyRecords = await ddb.send( - new ScanCommand({ - TableName: tableNameLambdaHandler, - }) - ); - expect(idempotencyRecords.Items?.length).toEqual(1); - expect(idempotencyRecords.Items?.[0].id).toEqual( - `${functionNameLambdaHandler}#${payloadHash}` - ); - expect(idempotencyRecords.Items?.[0].data).toEqual('bar'); - expect(idempotencyRecords.Items?.[0].status).toEqual('COMPLETED'); + // Assess + const idempotencyRecords = await ddb.send( + new ScanCommand({ + TableName: tableNameLambdaHandler, + }) + ); + expect(idempotencyRecords.Items?.length).toEqual(1); + expect(idempotencyRecords.Items?.[0].id).toEqual( + `${functionNameLambdaHandler}#${payloadHash}` + ); + expect(idempotencyRecords.Items?.[0].data).toEqual('bar'); + expect(idempotencyRecords.Items?.[0].status).toEqual('COMPLETED'); - // During the first invocation the handler should be called, so the logs should contain 1 log - expect(functionLogs[0]).toHaveLength(1); - // We test the content of the log as well as the presence of fields from the context, this - // ensures that the all the arguments are passed to the handler when made idempotent - expect(TestInvocationLogs.parseFunctionLog(functionLogs[0][0])).toEqual( - expect.objectContaining({ - message: 'foo', - details: 'bar', - function_name: functionNameLambdaHandler, - }) - ); - // During the second invocation the handler should not be called, so the logs should be empty - expect(functionLogs[1]).toHaveLength(0); - }, - TEST_CASE_TIMEOUT - ); + // During the first invocation the handler should be called, so the logs should contain 1 log + expect(functionLogs[0]).toHaveLength(1); + // We test the content of the log as well as the presence of fields from the context, this + // ensures that the all the arguments are passed to the handler when made idempotent + expect(TestInvocationLogs.parseFunctionLog(functionLogs[0][0])).toEqual( + expect.objectContaining({ + message: 'foo', + details: 'bar', + function_name: functionNameLambdaHandler, + }) + ); + // During the second invocation the handler should not be called, so the logs should be empty + expect(functionLogs[1]).toHaveLength(0); + }); afterAll(async () => { if (!process.env.DISABLE_TEARDOWN) { await testStack.destroy(); } - }, TEARDOWN_TIMEOUT); + }); }); diff --git a/packages/idempotency/vitest.config.ts b/packages/idempotency/vitest.config.ts index 9f1196ef1f..baa5cf7463 100644 --- a/packages/idempotency/vitest.config.ts +++ b/packages/idempotency/vitest.config.ts @@ -4,5 +4,7 @@ export default defineProject({ test: { environment: 'node', setupFiles: ['../testing/src/setupEnv.ts'], + hookTimeout: 1_000 * 60 * 10, // 10 minutes + testTimeout: 1_000 * 60 * 3, // 3 minutes }, }); diff --git a/packages/logger/package.json b/packages/logger/package.json index acf8b56457..093551c0be 100644 --- a/packages/logger/package.json +++ b/packages/logger/package.json @@ -62,6 +62,10 @@ "types": [ "lib/cjs/types/index.d.ts", "lib/esm/types/index.d.ts" + ], + "correlationId": [ + "lib/cjs/correlationId.d.ts", + "lib/esm/correlationId.d.ts" ] } }, diff --git a/packages/logger/tests/e2e/advancedUses.test.FunctionCode.ts b/packages/logger/tests/e2e/advancedUses.test.FunctionCode.ts new file mode 100644 index 0000000000..1e601c6097 --- /dev/null +++ b/packages/logger/tests/e2e/advancedUses.test.FunctionCode.ts @@ -0,0 +1,63 @@ +import { Logger } from '@aws-lambda-powertools/logger'; +import { + correlationPaths, + search, +} from '@aws-lambda-powertools/logger/correlationId'; +import { injectLambdaContext } from '@aws-lambda-powertools/logger/middleware'; +import type { Context } from 'aws-lambda'; +import middy from 'middy5'; + +const logger = new Logger({ + logLevel: 'DEBUG', + logBufferOptions: { + enabled: true, + flushOnErrorLog: true, + }, + correlationIdSearchFn: search, +}); + +logger.debug('a never buffered debug log'); + +export const handlerManual = async (event: unknown) => { + logger.addContext({} as Context); // we want only the cold start value + logger.setCorrelationId(event, correlationPaths.EVENT_BRIDGE); + + logger.debug('a buffered debug log'); + logger.info('an info log'); + try { + throw new Error('ops'); + } catch (error) { + logger.error('Uncaught error detected, flushing log buffer before exit', { + error, + }); + } finally { + logger.clearBuffer(); + } +}; + +export const handlerMiddy = middy() + .use( + injectLambdaContext(logger, { + correlationIdPath: correlationPaths.EVENT_BRIDGE, + flushBufferOnUncaughtError: true, + }) + ) + .handler(async () => { + logger.debug('a buffered debug log'); + logger.info('an info log'); + throw new Error('ops'); + }); + +class Lambda { + @logger.injectLambdaContext({ + correlationIdPath: correlationPaths.EVENT_BRIDGE, + flushBufferOnUncaughtError: true, + }) + public async handler(_event: unknown, _context: Context) { + logger.debug('a buffered debug log'); + logger.info('an info log'); + throw new Error('ops'); + } +} +const lambda = new Lambda(); +export const handlerDecorator = lambda.handler.bind(lambda); diff --git a/packages/logger/tests/e2e/advancedUses.test.ts b/packages/logger/tests/e2e/advancedUses.test.ts new file mode 100644 index 0000000000..c41aaec409 --- /dev/null +++ b/packages/logger/tests/e2e/advancedUses.test.ts @@ -0,0 +1,163 @@ +import { join } from 'node:path'; +import { + TestInvocationLogs, + TestStack, + invokeFunction, +} from '@aws-lambda-powertools/testing-utils'; +import { afterAll, beforeAll, describe, expect, it } from 'vitest'; +import { LoggerTestNodejsFunction } from '../helpers/resources.js'; +import { RESOURCE_NAME_PREFIX, STACK_OUTPUT_LOG_GROUP } from './constants.js'; + +/** + * In this e2e test for Logger, we test a number of advanced use cases: + * - Log buffering enabled with flush on error (both manually on logger.error and automatically on uncaught error) + * - Correlation ID injection (both manually and automatically) + * + * The test is split into three cases: + * - Manual instrumentation + * - Middy middleware + * - Decorator + */ +describe('Logger E2E - Advanced uses', () => { + const testStack = new TestStack({ + stackNameProps: { + stackNamePrefix: RESOURCE_NAME_PREFIX, + testName: 'Advanced', + }, + }); + + // Location of the lambda function code + const lambdaFunctionCodeFilePath = join( + __dirname, + 'advancedUses.test.FunctionCode.ts' + ); + + const invocationCount = 2; + const invocationLogs = new Map(); + const manualCase = 'Manual'; + const middyCase = 'Middy'; + const decoratorCase = 'Decorator'; + + beforeAll(async () => { + invocationLogs.set(manualCase, []); + invocationLogs.set(middyCase, []); + invocationLogs.set(decoratorCase, []); + for (const caseKey of invocationLogs.keys()) { + new LoggerTestNodejsFunction( + testStack, + { + entry: lambdaFunctionCodeFilePath, + handler: `handler${caseKey}`, + }, + { + logGroupOutputKey: STACK_OUTPUT_LOG_GROUP, + nameSuffix: caseKey, + createAlias: true, + } + ); + } + + await testStack.deploy(); + + for (const caseKey of invocationLogs.keys()) { + const functionArn = testStack.findAndGetStackOutputValue(caseKey); + const logs = await invokeFunction({ + functionName: functionArn, + times: invocationCount, + invocationMode: 'SEQUENTIAL', + payload: [ + { + id: 1, + }, + { + id: 2, + }, + ], + }); + invocationLogs.set(caseKey, logs); + } + }); + + it.each([ + { + caseKey: manualCase, + }, + { + caseKey: middyCase, + }, + { + caseKey: decoratorCase, + }, + ])('$caseKey instrumentation', ({ caseKey }) => { + for (let i = 0; i < invocationCount; i++) { + const isFirstInvocation = i === 0; + // Get log messages of the i-th invocation + const fnLogs = invocationLogs.get(caseKey)?.at(i)?.getFunctionLogs(); + if (!fnLogs || fnLogs.length === 0) { + throw new Error(`Failed to get logs for ${caseKey} invocation ${i}`); + } + // When using decorator & middleware, we are actually throwing an error + // which is logged by the runtime, so we need to filter out the logs that are + // not JSON formatted + const logs = fnLogs.filter((log) => { + try { + JSON.parse(log); + return true; + } catch (error) { + return false; + } + }); + + if (isFirstInvocation) { + // Logs outside of the function handler are only present on the first invocation + expect(TestInvocationLogs.parseFunctionLog(logs[0])).toEqual( + expect.objectContaining({ + level: 'DEBUG', + message: 'a never buffered debug log', + }) + ); + } + // Since we have an extra log (above) on the first invocation, we need to + // adjust the index of the logs we are checking + const logIndexOffset = isFirstInvocation ? 1 : 0; + const correlationId = i + 1; + expect( + TestInvocationLogs.parseFunctionLog(logs[0 + logIndexOffset]) + ).toEqual( + expect.objectContaining({ + level: 'INFO', + message: 'an info log', + correlation_id: correlationId, + }) + ); + expect( + TestInvocationLogs.parseFunctionLog(logs[1 + logIndexOffset]) + ).toEqual( + expect.objectContaining({ + level: 'DEBUG', + message: 'a buffered debug log', + correlation_id: correlationId, + }) + ); + expect( + TestInvocationLogs.parseFunctionLog(logs.at(-1) as string) + ).toEqual( + expect.objectContaining({ + level: 'ERROR', + message: 'Uncaught error detected, flushing log buffer before exit', + correlation_id: correlationId, + error: expect.objectContaining({ + name: 'Error', + message: 'ops', + }), + }) + ); + } + }); + + afterAll(async () => { + if (!process.env.DISABLE_TEARDOWN) { + await testStack.destroy(); + } + }); +}); diff --git a/packages/logger/tests/e2e/basicFeatures.middy.test.ts b/packages/logger/tests/e2e/basicFeatures.middy.test.ts index 9f373c718d..04a6eb5200 100644 --- a/packages/logger/tests/e2e/basicFeatures.middy.test.ts +++ b/packages/logger/tests/e2e/basicFeatures.middy.test.ts @@ -9,10 +9,7 @@ import { afterAll, beforeAll, describe, expect, it } from 'vitest'; import { LoggerTestNodejsFunction } from '../helpers/resources.js'; import { RESOURCE_NAME_PREFIX, - SETUP_TIMEOUT, STACK_OUTPUT_LOG_GROUP, - TEARDOWN_TIMEOUT, - TEST_CASE_TIMEOUT, XRAY_TRACE_ID_REGEX, commonEnvironmentVars, } from './constants.js'; @@ -65,297 +62,227 @@ describe('Logger E2E tests, basic functionalities middy usage', () => { }); console.log('logGroupName', logGroupName); - }, SETUP_TIMEOUT); + }); describe('Log level filtering', () => { - it( - 'should filter log based on POWERTOOLS_LOG_LEVEL (INFO) environment variable in Lambda', - async () => { - for (let i = 0; i < invocationCount; i++) { - // Get log messages of the invocation and filter by level - const debugLogs = invocationLogs[i].getFunctionLogs('DEBUG'); - // Check that no log message below INFO level is logged - expect(debugLogs.length).toBe(0); - } - }, - TEST_CASE_TIMEOUT - ); + it('should filter log based on POWERTOOLS_LOG_LEVEL (INFO) environment variable in Lambda', async () => { + for (let i = 0; i < invocationCount; i++) { + // Get log messages of the invocation and filter by level + const debugLogs = invocationLogs[i].getFunctionLogs('DEBUG'); + // Check that no log message below INFO level is logged + expect(debugLogs.length).toBe(0); + } + }); }); describe('Context data', () => { - it( - 'should inject context info in each log', - async () => { - for (let i = 0; i < invocationCount; i++) { - // Get log messages of the invocation - const logMessages = invocationLogs[i].getFunctionLogs(); - // Check that the context is logged on every log - for (const message of logMessages) { - const log = TestInvocationLogs.parseFunctionLog(message); - expect(log).toHaveProperty('function_arn'); - expect(log).toHaveProperty('function_memory_size'); - expect(log).toHaveProperty('function_name'); - expect(log).toHaveProperty('function_request_id'); - expect(log).toHaveProperty('timestamp'); - } + it('should inject context info in each log', async () => { + for (let i = 0; i < invocationCount; i++) { + // Get log messages of the invocation + const logMessages = invocationLogs[i].getFunctionLogs(); + // Check that the context is logged on every log + for (const message of logMessages) { + const log = TestInvocationLogs.parseFunctionLog(message); + expect(log).toHaveProperty('function_arn'); + expect(log).toHaveProperty('function_memory_size'); + expect(log).toHaveProperty('function_name'); + expect(log).toHaveProperty('function_request_id'); + expect(log).toHaveProperty('timestamp'); } - }, - TEST_CASE_TIMEOUT - ); + } + }); - it( - 'should include coldStart equal to TRUE only on the first invocation, FALSE otherwise', - async () => { - for (let i = 0; i < invocationCount; i++) { - // Get log messages of the invocation - const logMessages = invocationLogs[i].getFunctionLogs(); - // Check that cold start is logged correctly on every log - for (const message of logMessages) { - const log = TestInvocationLogs.parseFunctionLog(message); - if (i === 0) { - expect(log.cold_start).toBe(true); - } else { - expect(log.cold_start).toBe(false); - } + it('should include coldStart equal to TRUE only on the first invocation, FALSE otherwise', async () => { + for (let i = 0; i < invocationCount; i++) { + // Get log messages of the invocation + const logMessages = invocationLogs[i].getFunctionLogs(); + // Check that cold start is logged correctly on every log + for (const message of logMessages) { + const log = TestInvocationLogs.parseFunctionLog(message); + if (i === 0) { + expect(log.cold_start).toBe(true); + } else { + expect(log.cold_start).toBe(false); } } - }, - TEST_CASE_TIMEOUT - ); + } + }); }); - describe('Log event', () => { - it( - 'should log the event as the first log of each invocation only', - async () => { - for (let i = 0; i < invocationCount; i++) { - // Get log messages of the invocation - const logMessages = invocationLogs[i].getFunctionLogs(); - - for (const [index, message] of logMessages.entries()) { - const log = TestInvocationLogs.parseFunctionLog(message); - // Check that the event is logged on the first log - if (index === 0) { - expect(log).toHaveProperty('event'); - expect(log.event).toStrictEqual( - expect.objectContaining({ foo: 'bar' }) - ); - // Check that the event is not logged again on the rest of the logs - } else { - expect(log).not.toHaveProperty('event'); - } - } - } - }, - TEST_CASE_TIMEOUT - ); + it('logs the event for every invocation, only once, and without keys from previous invocations', async () => { + const { RUNTIME_ADDED_KEY: runtimeAddedKey } = commonEnvironmentVars; + + for (let i = 0; i < invocationCount; i++) { + // Get log messages of the invocation + const logMessages = invocationLogs[i].getFunctionLogs(); + + const eventLog = logMessages.filter((log) => + log.includes('Lambda invocation event') + ); + + // Check that the event log is logged only once + expect(eventLog).toHaveLength(1); + const log = TestInvocationLogs.parseFunctionLog(eventLog[0]); + // Check that the event log is logged correctly + expect(log).toHaveProperty('event'); + expect(log.event).toStrictEqual(expect.objectContaining({ foo: 'bar' })); + // Check that the event log does not contain keys from previous invocations + expect(log).not.toHaveProperty(runtimeAddedKey); + } }); describe('Persistent additional log keys and values', () => { - it( - 'should contain persistent value in every log', - async () => { - const { - PERSISTENT_KEY: persistentKey, - PERSISTENT_VALUE: persistentValue, - } = commonEnvironmentVars; - - for (let i = 0; i < invocationCount; i++) { - // Get log messages of the invocation - const logMessages = invocationLogs[i].getFunctionLogs(); - - for (const message of logMessages) { - const log = TestInvocationLogs.parseFunctionLog(message); - // Check that the persistent key is present in every log - expect(log).toHaveProperty(persistentKey); - expect(log[persistentKey]).toBe(persistentValue); - } + it('should contain persistent value in every log', async () => { + const { + PERSISTENT_KEY: persistentKey, + PERSISTENT_VALUE: persistentValue, + } = commonEnvironmentVars; + + for (let i = 0; i < invocationCount; i++) { + // Get log messages of the invocation + const logMessages = invocationLogs[i].getFunctionLogs(); + + for (const message of logMessages) { + const log = TestInvocationLogs.parseFunctionLog(message); + // Check that the persistent key is present in every log + expect(log).toHaveProperty(persistentKey); + expect(log[persistentKey]).toBe(persistentValue); } - }, - TEST_CASE_TIMEOUT - ); - - it( - 'should not contain persistent keys that were removed on runtime', - async () => { - const { REMOVABLE_KEY: removableKey, REMOVABLE_VALUE: removableValue } = - commonEnvironmentVars; - - for (let i = 0; i < invocationCount; i++) { - // Get log messages of the invocation - const logMessages = invocationLogs[i].getFunctionLogs(); - - for (const [index, message] of logMessages.entries()) { - const log = TestInvocationLogs.parseFunctionLog(message); - // Check that at the time of logging the event, which happens before the handler, - // the key was still present - if (index === 0) { - expect(log).toHaveProperty(removableKey); - expect(log[removableKey]).toBe(removableValue); - // Check that all other logs that happen at runtime do not contain the key - } else { - expect(log).not.toHaveProperty(removableValue); - } - } - } - }, - TEST_CASE_TIMEOUT - ); - - it( - 'should not leak any persistent keys added runtime since clearState is enabled', - async () => { - const { RUNTIME_ADDED_KEY: runtimeAddedKey } = commonEnvironmentVars; - - for (let i = 0; i < invocationCount; i++) { - // Get log messages of the invocation - const logMessages = invocationLogs[i].getFunctionLogs(); + } + }); - for (const [index, message] of logMessages.entries()) { - const log = TestInvocationLogs.parseFunctionLog(message); - // Check that at the time of logging the event, which happens before the handler, - // the key is NOT present - if (index === 0) { - expect(log).not.toHaveProperty(runtimeAddedKey); - } else { - // Check that all other logs that happen at runtime do contain the key - expect(log).toHaveProperty(runtimeAddedKey); - // Check that the value is the same for all logs - expect(log[runtimeAddedKey]).toEqual('bar'); - } + it('should not contain persistent keys that were removed on runtime', async () => { + const { REMOVABLE_KEY: removableKey, REMOVABLE_VALUE: removableValue } = + commonEnvironmentVars; + + for (let i = 0; i < invocationCount; i++) { + // Get log messages of the invocation + const logMessages = invocationLogs[i].getFunctionLogs(); + + for (const [index, message] of logMessages.entries()) { + const log = TestInvocationLogs.parseFunctionLog(message); + // Check that at the time of logging the event, which happens before the handler, + // the key was still present + if (index === 0) { + expect(log).toHaveProperty(removableKey); + expect(log[removableKey]).toBe(removableValue); + // Check that all other logs that happen at runtime do not contain the key + } else { + expect(log).not.toHaveProperty(removableValue); } } - }, - TEST_CASE_TIMEOUT - ); + } + }); }); describe('One-time additional log keys and values', () => { - it( - 'should log additional keys and value only once', - async () => { - const { - SINGLE_LOG_ITEM_KEY: singleLogItemKey, - SINGLE_LOG_ITEM_VALUE: singleLogItemValue, - } = commonEnvironmentVars; - - for (let i = 0; i < invocationCount; i++) { - // Get log messages of the invocation - const logMessages = invocationLogs[i].getFunctionLogs(); - // Check that the additional log is logged only once - const logMessagesWithAdditionalLog = logMessages.filter((log) => - log.includes(singleLogItemKey) - ); - expect(logMessagesWithAdditionalLog).toHaveLength(1); - // Check that the additional log is logged correctly - const parsedLog = TestInvocationLogs.parseFunctionLog( - logMessagesWithAdditionalLog[0] - ); - expect(parsedLog[singleLogItemKey]).toBe(singleLogItemValue); - } - }, - TEST_CASE_TIMEOUT - ); + it('should log additional keys and value only once', async () => { + const { + SINGLE_LOG_ITEM_KEY: singleLogItemKey, + SINGLE_LOG_ITEM_VALUE: singleLogItemValue, + } = commonEnvironmentVars; + + for (let i = 0; i < invocationCount; i++) { + // Get log messages of the invocation + const logMessages = invocationLogs[i].getFunctionLogs(); + // Check that the additional log is logged only once + const logMessagesWithAdditionalLog = logMessages.filter((log) => + log.includes(singleLogItemKey) + ); + expect(logMessagesWithAdditionalLog).toHaveLength(1); + // Check that the additional log is logged correctly + const parsedLog = TestInvocationLogs.parseFunctionLog( + logMessagesWithAdditionalLog[0] + ); + expect(parsedLog[singleLogItemKey]).toBe(singleLogItemValue); + } + }); }); describe('Error logging', () => { - it( - 'should log error only once', - async () => { - const { ERROR_MSG: errorMsg } = commonEnvironmentVars; - - for (let i = 0; i < invocationCount; i++) { - // Get log messages of the invocation filtered by error level - const logMessages = invocationLogs[i].getFunctionLogs('ERROR'); - - // Check that the error is logged only once - expect(logMessages).toHaveLength(1); - - // Check that the error is logged correctly - const errorLog = TestInvocationLogs.parseFunctionLog(logMessages[0]); - expect(errorLog).toHaveProperty('error'); - expect(errorLog.error).toStrictEqual( - expect.objectContaining({ - location: expect.any(String), - name: 'Error', - message: errorMsg, - stack: expect.anything(), - }) - ); - } - }, - TEST_CASE_TIMEOUT - ); + it('should log error only once', async () => { + const { ERROR_MSG: errorMsg } = commonEnvironmentVars; + + for (let i = 0; i < invocationCount; i++) { + // Get log messages of the invocation filtered by error level + const logMessages = invocationLogs[i].getFunctionLogs('ERROR'); + + // Check that the error is logged only once + expect(logMessages).toHaveLength(1); + + // Check that the error is logged correctly + const errorLog = TestInvocationLogs.parseFunctionLog(logMessages[0]); + expect(errorLog).toHaveProperty('error'); + expect(errorLog.error).toStrictEqual( + expect.objectContaining({ + location: expect.any(String), + name: 'Error', + message: errorMsg, + stack: expect.anything(), + }) + ); + } + }); }); describe('Arbitrary object logging', () => { - it( - 'should log additional arbitrary object only once', - async () => { - const { - ARBITRARY_OBJECT_KEY: objectKey, - ARBITRARY_OBJECT_DATA: objectData, - } = commonEnvironmentVars; - - for (let i = 0; i < invocationCount; i++) { - // Get log messages of the invocation - const logMessages = invocationLogs[i].getFunctionLogs(); - // Get the log messages that contains the arbitrary object - const filteredLogs = logMessages.filter((log) => - log.includes(objectData) - ); - // Check that the arbitrary object is logged only once - expect(filteredLogs).toHaveLength(1); - const logObject = TestInvocationLogs.parseFunctionLog( - filteredLogs[0] - ); - // Check that the arbitrary object is logged correctly - expect(logObject).toHaveProperty(objectKey); - const arbitrary = logObject[objectKey] as APIGatewayAuthorizerResult; - expect(arbitrary.principalId).toBe(objectData); - expect(arbitrary.policyDocument).toEqual( - expect.objectContaining({ - Version: 'Version 1', - Statement: [ - { - Effect: 'Allow', - Action: 'geo:*', - Resource: '*', - }, - ], - }) - ); - } - }, - TEST_CASE_TIMEOUT - ); + it('should log additional arbitrary object only once', async () => { + const { + ARBITRARY_OBJECT_KEY: objectKey, + ARBITRARY_OBJECT_DATA: objectData, + } = commonEnvironmentVars; + + for (let i = 0; i < invocationCount; i++) { + // Get log messages of the invocation + const logMessages = invocationLogs[i].getFunctionLogs(); + // Get the log messages that contains the arbitrary object + const filteredLogs = logMessages.filter((log) => + log.includes(objectData) + ); + // Check that the arbitrary object is logged only once + expect(filteredLogs).toHaveLength(1); + const logObject = TestInvocationLogs.parseFunctionLog(filteredLogs[0]); + // Check that the arbitrary object is logged correctly + expect(logObject).toHaveProperty(objectKey); + const arbitrary = logObject[objectKey] as APIGatewayAuthorizerResult; + expect(arbitrary.principalId).toBe(objectData); + expect(arbitrary.policyDocument).toEqual( + expect.objectContaining({ + Version: 'Version 1', + Statement: [ + { + Effect: 'Allow', + Action: 'geo:*', + Resource: '*', + }, + ], + }) + ); + } + }); }); describe('X-Ray Trace ID injection', () => { - it( - 'should inject & parse the X-Ray Trace ID of the current invocation into every log', - async () => { - for (let i = 0; i < invocationCount; i++) { - // Get log messages of the invocation - const logMessages = invocationLogs[i].getFunctionLogs(); - - // Check that the X-Ray Trace ID is logged on every log - const traceIds: string[] = []; - for (const message of logMessages) { - const log = TestInvocationLogs.parseFunctionLog(message); - expect(log).toHaveProperty('xray_trace_id'); - expect(log.xray_trace_id).toMatch(XRAY_TRACE_ID_REGEX); - traceIds.push(log.xray_trace_id as string); - } + it('should inject & parse the X-Ray Trace ID of the current invocation into every log', async () => { + for (let i = 0; i < invocationCount; i++) { + // Get log messages of the invocation + const logMessages = invocationLogs[i].getFunctionLogs(); + + // Check that the X-Ray Trace ID is logged on every log + const traceIds: string[] = []; + for (const message of logMessages) { + const log = TestInvocationLogs.parseFunctionLog(message); + expect(log).toHaveProperty('xray_trace_id'); + expect(log.xray_trace_id).toMatch(XRAY_TRACE_ID_REGEX); + traceIds.push(log.xray_trace_id as string); } - }, - TEST_CASE_TIMEOUT - ); + } + }); }); afterAll(async () => { if (!process.env.DISABLE_TEARDOWN) { await testStack.destroy(); } - }, TEARDOWN_TIMEOUT); + }); }); diff --git a/packages/logger/tests/e2e/childLogger.manual.test.ts b/packages/logger/tests/e2e/childLogger.manual.test.ts index a52584ab25..57dd63c926 100644 --- a/packages/logger/tests/e2e/childLogger.manual.test.ts +++ b/packages/logger/tests/e2e/childLogger.manual.test.ts @@ -8,10 +8,7 @@ import { afterAll, beforeAll, describe, expect, it } from 'vitest'; import { LoggerTestNodejsFunction } from '../helpers/resources.js'; import { RESOURCE_NAME_PREFIX, - SETUP_TIMEOUT, STACK_OUTPUT_LOG_GROUP, - TEARDOWN_TIMEOUT, - TEST_CASE_TIMEOUT, commonEnvironmentVars, } from './constants.js'; @@ -57,105 +54,89 @@ describe('Logger E2E tests, child logger', () => { }); console.log('logGroupName', logGroupName); - }, SETUP_TIMEOUT); + }); describe('Child logger', () => { - it( - 'should not log at same level of parent because of its own logLevel', - async () => { - const { PARENT_LOG_MSG: parentLogMsg, CHILD_LOG_MSG: childLogMsg } = - commonEnvironmentVars; - - for (let i = 0; i < invocationCount; i++) { - // Get log messages of the invocation and filter by level - const infoLogs = invocationLogs[i].getFunctionLogs('INFO'); - - const parentInfoLogs = infoLogs.filter((message) => - message.includes(parentLogMsg) - ); - const childInfoLogs = infoLogs.filter((message) => - message.includes(childLogMsg) - ); - - expect(parentInfoLogs).toHaveLength(infoLogs.length); - expect(childInfoLogs).toHaveLength(0); - } - }, - TEST_CASE_TIMEOUT - ); + it('should not log at same level of parent because of its own logLevel', async () => { + const { PARENT_LOG_MSG: parentLogMsg, CHILD_LOG_MSG: childLogMsg } = + commonEnvironmentVars; + + for (let i = 0; i < invocationCount; i++) { + // Get log messages of the invocation and filter by level + const infoLogs = invocationLogs[i].getFunctionLogs('INFO'); + + const parentInfoLogs = infoLogs.filter((message) => + message.includes(parentLogMsg) + ); + const childInfoLogs = infoLogs.filter((message) => + message.includes(childLogMsg) + ); + + expect(parentInfoLogs).toHaveLength(infoLogs.length); + expect(childInfoLogs).toHaveLength(0); + } + }); - it( - 'should log only level passed to a child', - async () => { - const { CHILD_LOG_MSG: childLogMsg } = commonEnvironmentVars; - for (let i = 0; i < invocationCount; i++) { - // Get log messages of the invocation - const logMessages = invocationLogs[i].getFunctionLogs(); - - // Filter child logs by level - const errorChildLogs = logMessages.filter( - (message) => - message.includes('ERROR') && message.includes(childLogMsg) - ); - - // Check that the child logger only logged once (the other) - // log was filtered out by the child logger because of its logLevel - expect(errorChildLogs).toHaveLength(1); - } - }, - TEST_CASE_TIMEOUT - ); + it('should log only level passed to a child', async () => { + const { CHILD_LOG_MSG: childLogMsg } = commonEnvironmentVars; + for (let i = 0; i < invocationCount; i++) { + // Get log messages of the invocation + const logMessages = invocationLogs[i].getFunctionLogs(); + + // Filter child logs by level + const errorChildLogs = logMessages.filter( + (message) => + message.includes('ERROR') && message.includes(childLogMsg) + ); + + // Check that the child logger only logged once (the other) + // log was filtered out by the child logger because of its logLevel + expect(errorChildLogs).toHaveLength(1); + } + }); - it( - 'should NOT inject context into the child logger', - async () => { - const { CHILD_LOG_MSG: childLogMsg } = commonEnvironmentVars; - - for (let i = 0; i < invocationCount; i++) { - // Get log messages of the invocation - const logMessages = invocationLogs[i].getFunctionLogs(); - - // Filter child logs by level - const childLogMessages = logMessages.filter((message) => - message.includes(childLogMsg) - ); - - // Check that the context is not present in any of the child logs - for (const message of childLogMessages) { - const log = TestInvocationLogs.parseFunctionLog(message); - expect(log).not.toHaveProperty('function_arn'); - expect(log).not.toHaveProperty('function_memory_size'); - expect(log).not.toHaveProperty('function_name'); - expect(log).not.toHaveProperty('function_request_id'); - } + it('should NOT inject context into the child logger', async () => { + const { CHILD_LOG_MSG: childLogMsg } = commonEnvironmentVars; + + for (let i = 0; i < invocationCount; i++) { + // Get log messages of the invocation + const logMessages = invocationLogs[i].getFunctionLogs(); + + // Filter child logs by level + const childLogMessages = logMessages.filter((message) => + message.includes(childLogMsg) + ); + + // Check that the context is not present in any of the child logs + for (const message of childLogMessages) { + const log = TestInvocationLogs.parseFunctionLog(message); + expect(log).not.toHaveProperty('function_arn'); + expect(log).not.toHaveProperty('function_memory_size'); + expect(log).not.toHaveProperty('function_name'); + expect(log).not.toHaveProperty('function_request_id'); } - }, - TEST_CASE_TIMEOUT - ); + } + }); - it( - 'both logger instances should have the same persistent key/value', - async () => { - const { PERSISTENT_KEY: persistentKey } = commonEnvironmentVars; + it('both logger instances should have the same persistent key/value', async () => { + const { PERSISTENT_KEY: persistentKey } = commonEnvironmentVars; - for (let i = 0; i < invocationCount; i++) { - // Get log messages of the invocation - const logMessages = invocationLogs[i].getFunctionLogs(); + for (let i = 0; i < invocationCount; i++) { + // Get log messages of the invocation + const logMessages = invocationLogs[i].getFunctionLogs(); - // Check that all logs have the persistent key/value - for (const message of logMessages) { - const log = TestInvocationLogs.parseFunctionLog(message); - expect(log).toHaveProperty(persistentKey); - } + // Check that all logs have the persistent key/value + for (const message of logMessages) { + const log = TestInvocationLogs.parseFunctionLog(message); + expect(log).toHaveProperty(persistentKey); } - }, - TEST_CASE_TIMEOUT - ); + } + }); }); afterAll(async () => { if (!process.env.DISABLE_TEARDOWN) { await testStack.destroy(); } - }, TEARDOWN_TIMEOUT); + }); }); diff --git a/packages/logger/tests/e2e/constants.ts b/packages/logger/tests/e2e/constants.ts index a719a35b83..6770b144ad 100644 --- a/packages/logger/tests/e2e/constants.ts +++ b/packages/logger/tests/e2e/constants.ts @@ -1,10 +1,6 @@ import { randomUUID } from 'node:crypto'; const RESOURCE_NAME_PREFIX = 'Logger'; -const ONE_MINUTE = 60 * 1000; -const TEST_CASE_TIMEOUT = ONE_MINUTE; -const SETUP_TIMEOUT = 7 * ONE_MINUTE; -const TEARDOWN_TIMEOUT = 5 * ONE_MINUTE; const STACK_OUTPUT_LOG_GROUP = 'LogGroupName'; const XRAY_TRACE_ID_REGEX = /^1-[0-9a-f]{8}-[0-9a-f]{24}$/; @@ -28,10 +24,6 @@ const commonEnvironmentVars = { export { RESOURCE_NAME_PREFIX, - ONE_MINUTE, - TEST_CASE_TIMEOUT, - SETUP_TIMEOUT, - TEARDOWN_TIMEOUT, STACK_OUTPUT_LOG_GROUP, XRAY_TRACE_ID_REGEX, commonEnvironmentVars, diff --git a/packages/logger/tests/e2e/logEventEnvVarSetting.middy.test.ts b/packages/logger/tests/e2e/logEventEnvVarSetting.middy.test.ts index 21c2dad621..3a3efe2609 100644 --- a/packages/logger/tests/e2e/logEventEnvVarSetting.middy.test.ts +++ b/packages/logger/tests/e2e/logEventEnvVarSetting.middy.test.ts @@ -6,13 +6,7 @@ import { } from '@aws-lambda-powertools/testing-utils'; import { afterAll, beforeAll, describe, expect, it } from 'vitest'; import { LoggerTestNodejsFunction } from '../helpers/resources.js'; -import { - RESOURCE_NAME_PREFIX, - SETUP_TIMEOUT, - STACK_OUTPUT_LOG_GROUP, - TEARDOWN_TIMEOUT, - TEST_CASE_TIMEOUT, -} from './constants.js'; +import { RESOURCE_NAME_PREFIX, STACK_OUTPUT_LOG_GROUP } from './constants.js'; describe('Logger E2E tests, log event via env var setting with middy', () => { const testStack = new TestStack({ @@ -63,38 +57,34 @@ describe('Logger E2E tests, log event via env var setting with middy', () => { }); console.log('logGroupName', logGroupName); - }, SETUP_TIMEOUT); + }); describe('Log event', () => { - it( - 'should log the event as the first log of each invocation only', - async () => { - for (let i = 0; i < invocationCount; i++) { - // Get log messages of the invocation - const logMessages = invocationLogs[i].getFunctionLogs(); + it('should log the event as the first log of each invocation only', async () => { + for (let i = 0; i < invocationCount; i++) { + // Get log messages of the invocation + const logMessages = invocationLogs[i].getFunctionLogs(); - for (const [index, message] of logMessages.entries()) { - const log = TestInvocationLogs.parseFunctionLog(message); - // Check that the event is logged on the first log - if (index === 0) { - expect(log).toHaveProperty('event'); - expect(log.event).toStrictEqual( - expect.objectContaining({ foo: 'bar' }) - ); - // Check that the event is not logged again on the rest of the logs - } else { - expect(log).not.toHaveProperty('event'); - } + for (const [index, message] of logMessages.entries()) { + const log = TestInvocationLogs.parseFunctionLog(message); + // Check that the event is logged on the first log + if (index === 0) { + expect(log).toHaveProperty('event'); + expect(log.event).toStrictEqual( + expect.objectContaining({ foo: 'bar' }) + ); + // Check that the event is not logged again on the rest of the logs + } else { + expect(log).not.toHaveProperty('event'); } } - }, - TEST_CASE_TIMEOUT - ); + } + }); }); afterAll(async () => { if (!process.env.DISABLE_TEARDOWN) { await testStack.destroy(); } - }, TEARDOWN_TIMEOUT); + }); }); diff --git a/packages/logger/tests/e2e/sampleRate.decorator.test.ts b/packages/logger/tests/e2e/sampleRate.decorator.test.ts index 011a72d02d..d6e848f06e 100644 --- a/packages/logger/tests/e2e/sampleRate.decorator.test.ts +++ b/packages/logger/tests/e2e/sampleRate.decorator.test.ts @@ -7,13 +7,7 @@ import { } from '@aws-lambda-powertools/testing-utils'; import { afterAll, beforeAll, describe, expect, it } from 'vitest'; import { LoggerTestNodejsFunction } from '../helpers/resources.js'; -import { - RESOURCE_NAME_PREFIX, - SETUP_TIMEOUT, - STACK_OUTPUT_LOG_GROUP, - TEARDOWN_TIMEOUT, - TEST_CASE_TIMEOUT, -} from './constants.js'; +import { RESOURCE_NAME_PREFIX, STACK_OUTPUT_LOG_GROUP } from './constants.js'; describe('Logger E2E tests, sample rate and injectLambdaContext()', () => { const testStack = new TestStack({ @@ -62,73 +56,65 @@ describe('Logger E2E tests, sample rate and injectLambdaContext()', () => { }); console.log('logGroupName', logGroupName); - }, SETUP_TIMEOUT); + }); describe('Enabling sample rate', () => { - it( - 'should log all levels based on given sample rate, not just ERROR', - async () => { - // Fetch log streams from all invocations - let countSampled = 0; - let countNotSampled = 0; + it('should log all levels based on given sample rate, not just ERROR', async () => { + // Fetch log streams from all invocations + let countSampled = 0; + let countNotSampled = 0; - for (let i = 0; i < invocationCount; i++) { - // Get log messages of the invocation - const logMessages = invocationLogs[i].getFunctionLogs(); + for (let i = 0; i < invocationCount; i++) { + // Get log messages of the invocation + const logMessages = invocationLogs[i].getFunctionLogs(); - if (logMessages.length === 1 && logMessages[0].includes('ERROR')) { - countNotSampled++; - } else if ( - (logMessages.length === 5 && - logMessages[0].includes( - 'Setting log level to DEBUG due to sampling rate' - )) || - logMessages.length === 4 - ) { - countSampled++; - } else { - console.error(`Log group ${logGroupName} contains missing log`); - throw new Error( - 'Sampled log should have either 1 error log or 5 logs of all levels' - ); - } + if (logMessages.length === 1 && logMessages[0].includes('ERROR')) { + countNotSampled++; + } else if ( + (logMessages.length === 5 && + logMessages[0].includes( + 'Setting log level to DEBUG due to sampling rate' + )) || + logMessages.length === 4 + ) { + countSampled++; + } else { + console.error(`Log group ${logGroupName} contains missing log`); + throw new Error( + 'Sampled log should have either 1 error log or 5 logs of all levels' + ); } + } - // Given that we set rate to 0.5. The chance that we get all invocationCount sampled - // (or not sampled) is less than 0.5^20 - expect(countSampled).toBeGreaterThan(0); - expect(countNotSampled).toBeGreaterThan(0); - }, - TEST_CASE_TIMEOUT - ); + // Given that we set rate to 0.5. The chance that we get all invocationCount sampled + // (or not sampled) is less than 0.5^20 + expect(countSampled).toBeGreaterThan(0); + expect(countNotSampled).toBeGreaterThan(0); + }); }); describe('Decorator injectLambdaContext()', () => { - it( - 'should inject Lambda context into every log emitted', - async () => { - for (let i = 0; i < invocationCount; i++) { - // Get log messages of the invocation - const logMessages = invocationLogs[i].getFunctionLogs('ERROR'); + it('should inject Lambda context into every log emitted', async () => { + for (let i = 0; i < invocationCount; i++) { + // Get log messages of the invocation + const logMessages = invocationLogs[i].getFunctionLogs('ERROR'); - // Check that the context is logged on every log - for (const message of logMessages) { - const log = TestInvocationLogs.parseFunctionLog(message); - expect(log).toHaveProperty('function_arn'); - expect(log).toHaveProperty('function_memory_size'); - expect(log).toHaveProperty('function_name'); - expect(log).toHaveProperty('function_request_id'); - expect(log).toHaveProperty('timestamp'); - } + // Check that the context is logged on every log + for (const message of logMessages) { + const log = TestInvocationLogs.parseFunctionLog(message); + expect(log).toHaveProperty('function_arn'); + expect(log).toHaveProperty('function_memory_size'); + expect(log).toHaveProperty('function_name'); + expect(log).toHaveProperty('function_request_id'); + expect(log).toHaveProperty('timestamp'); } - }, - TEST_CASE_TIMEOUT - ); + } + }); }); afterAll(async () => { if (!process.env.DISABLE_TEARDOWN) { await testStack.destroy(); } - }, TEARDOWN_TIMEOUT); + }); }); diff --git a/packages/logger/vitest.config.ts b/packages/logger/vitest.config.ts index 9f1196ef1f..baa5cf7463 100644 --- a/packages/logger/vitest.config.ts +++ b/packages/logger/vitest.config.ts @@ -4,5 +4,7 @@ export default defineProject({ test: { environment: 'node', setupFiles: ['../testing/src/setupEnv.ts'], + hookTimeout: 1_000 * 60 * 10, // 10 minutes + testTimeout: 1_000 * 60 * 3, // 3 minutes }, }); diff --git a/packages/metrics/tests/e2e/basicFeatures.decorators.test.ts b/packages/metrics/tests/e2e/basicFeatures.decorators.test.ts index 58398e562f..39ce36248a 100644 --- a/packages/metrics/tests/e2e/basicFeatures.decorators.test.ts +++ b/packages/metrics/tests/e2e/basicFeatures.decorators.test.ts @@ -10,14 +10,7 @@ import { import { afterAll, beforeAll, describe, expect, it } from 'vitest'; import { getMetrics, sortDimensions } from '../helpers/metricsUtils.js'; import { MetricsTestNodejsFunction } from '../helpers/resources.js'; -import { - ONE_MINUTE, - RESOURCE_NAME_PREFIX, - SETUP_TIMEOUT, - TEARDOWN_TIMEOUT, - TEST_CASE_TIMEOUT, - commonEnvironmentVars, -} from './constants.js'; +import { RESOURCE_NAME_PREFIX, commonEnvironmentVars } from './constants.js'; describe('Metrics E2E tests, basic features decorator usage', () => { const testStack = new TestStack({ @@ -66,133 +59,123 @@ describe('Metrics E2E tests, basic features decorator usage', () => { times: invocations, invocationMode: 'SEQUENTIAL', }); - }, SETUP_TIMEOUT); + }); describe('ColdStart metrics', () => { - it( - 'captures the ColdStart Metric', - async () => { - const { - EXPECTED_NAMESPACE: expectedNamespace, - EXPECTED_DEFAULT_DIMENSIONS: expectedDefaultDimensions, - } = commonEnvironmentVars; - - const expectedDimensions = [ - { Name: 'service', Value: expectedServiceName }, - { Name: 'function_name', Value: fnNameBasicFeatures }, - { - Name: Object.keys(expectedDefaultDimensions)[0], - Value: expectedDefaultDimensions.MyDimension, - }, - ]; - // Check coldstart metric dimensions - const coldStartMetrics = await getMetrics( - cloudwatchClient, - expectedNamespace, - 'ColdStart', - 1 - ); - - expect(coldStartMetrics.Metrics?.length).toBe(1); - const coldStartMetric = coldStartMetrics.Metrics?.[0]; - expect(sortDimensions(coldStartMetric?.Dimensions)).toStrictEqual( - sortDimensions(expectedDimensions) - ); - - // Check coldstart metric value - const adjustedStartTime = new Date(startTime.getTime() - ONE_MINUTE); - const endTime = new Date(new Date().getTime() + ONE_MINUTE); - const coldStartMetricStat = await cloudwatchClient.send( - new GetMetricStatisticsCommand({ - Namespace: expectedNamespace, - StartTime: adjustedStartTime, - Dimensions: expectedDimensions, - EndTime: endTime, - Period: 60, - MetricName: 'ColdStart', - Statistics: ['Sum'], - }) - ); - - // Despite lambda has been called twice, coldstart metric sum should only be 1 - const singleDataPoint = coldStartMetricStat.Datapoints - ? coldStartMetricStat.Datapoints[0] - : {}; - expect(singleDataPoint?.Sum).toBe(1); - }, - TEST_CASE_TIMEOUT - ); + it('captures the ColdStart Metric', async () => { + const { + EXPECTED_NAMESPACE: expectedNamespace, + EXPECTED_DEFAULT_DIMENSIONS: expectedDefaultDimensions, + } = commonEnvironmentVars; + + const expectedDimensions = [ + { Name: 'service', Value: expectedServiceName }, + { Name: 'function_name', Value: fnNameBasicFeatures }, + { + Name: Object.keys(expectedDefaultDimensions)[0], + Value: expectedDefaultDimensions.MyDimension, + }, + ]; + // Check coldstart metric dimensions + const coldStartMetrics = await getMetrics( + cloudwatchClient, + expectedNamespace, + 'ColdStart', + 1 + ); + + expect(coldStartMetrics.Metrics?.length).toBe(1); + const coldStartMetric = coldStartMetrics.Metrics?.[0]; + expect(sortDimensions(coldStartMetric?.Dimensions)).toStrictEqual( + sortDimensions(expectedDimensions) + ); + + // Check coldstart metric value + const adjustedStartTime = new Date(startTime.getTime() - 60 * 1000); + const endTime = new Date(new Date().getTime() + 60 * 1000); + const coldStartMetricStat = await cloudwatchClient.send( + new GetMetricStatisticsCommand({ + Namespace: expectedNamespace, + StartTime: adjustedStartTime, + Dimensions: expectedDimensions, + EndTime: endTime, + Period: 60, + MetricName: 'ColdStart', + Statistics: ['Sum'], + }) + ); + + // Despite lambda has been called twice, coldstart metric sum should only be 1 + const singleDataPoint = coldStartMetricStat.Datapoints + ? coldStartMetricStat.Datapoints[0] + : {}; + expect(singleDataPoint?.Sum).toBe(1); + }); }); describe('Default and extra dimensions', () => { - it( - 'produces a Metric with the default and extra one dimensions', - async () => { - const { - EXPECTED_NAMESPACE: expectedNamespace, - EXPECTED_METRIC_NAME: expectedMetricName, - EXPECTED_METRIC_VALUE: expectedMetricValue, - EXPECTED_DEFAULT_DIMENSIONS: expectedDefaultDimensions, - EXPECTED_EXTRA_DIMENSION: expectedExtraDimension, - } = commonEnvironmentVars; - - // Check metric dimensions - const metrics = await getMetrics( - cloudwatchClient, - expectedNamespace, - expectedMetricName, - 1 - ); - - expect(metrics.Metrics?.length).toBe(1); - const metric = metrics.Metrics?.[0]; - const expectedDimensions = [ - { Name: 'service', Value: expectedServiceName }, - { - Name: Object.keys(expectedDefaultDimensions)[0], - Value: expectedDefaultDimensions.MyDimension, - }, - { - Name: Object.keys(expectedExtraDimension)[0], - Value: expectedExtraDimension.MyExtraDimension, - }, - ]; - expect(sortDimensions(metric?.Dimensions)).toStrictEqual( - sortDimensions(expectedDimensions) - ); - - // Check coldstart metric value - const adjustedStartTime = new Date( - startTime.getTime() - 3 * ONE_MINUTE - ); - const endTime = new Date(new Date().getTime() + ONE_MINUTE); - const metricStat = await cloudwatchClient.send( - new GetMetricStatisticsCommand({ - Namespace: expectedNamespace, - StartTime: adjustedStartTime, - Dimensions: expectedDimensions, - EndTime: endTime, - Period: 60, - MetricName: expectedMetricName, - Statistics: ['Sum'], - }) - ); - - // Since lambda has been called twice in this test and potentially more in others, metric sum should be at least of expectedMetricValue * invocationCount - const singleDataPoint = metricStat.Datapoints - ? metricStat.Datapoints[0] - : {}; - expect(singleDataPoint?.Sum).toBeGreaterThanOrEqual( - Number.parseInt(expectedMetricValue) * invocations - ); - }, - TEST_CASE_TIMEOUT - ); + it('produces a Metric with the default and extra one dimensions', async () => { + const { + EXPECTED_NAMESPACE: expectedNamespace, + EXPECTED_METRIC_NAME: expectedMetricName, + EXPECTED_METRIC_VALUE: expectedMetricValue, + EXPECTED_DEFAULT_DIMENSIONS: expectedDefaultDimensions, + EXPECTED_EXTRA_DIMENSION: expectedExtraDimension, + } = commonEnvironmentVars; + + // Check metric dimensions + const metrics = await getMetrics( + cloudwatchClient, + expectedNamespace, + expectedMetricName, + 1 + ); + + expect(metrics.Metrics?.length).toBe(1); + const metric = metrics.Metrics?.[0]; + const expectedDimensions = [ + { Name: 'service', Value: expectedServiceName }, + { + Name: Object.keys(expectedDefaultDimensions)[0], + Value: expectedDefaultDimensions.MyDimension, + }, + { + Name: Object.keys(expectedExtraDimension)[0], + Value: expectedExtraDimension.MyExtraDimension, + }, + ]; + expect(sortDimensions(metric?.Dimensions)).toStrictEqual( + sortDimensions(expectedDimensions) + ); + + // Check coldstart metric value + const adjustedStartTime = new Date(startTime.getTime() - 3 * 60 * 1000); + const endTime = new Date(new Date().getTime() + 60 * 1000); + const metricStat = await cloudwatchClient.send( + new GetMetricStatisticsCommand({ + Namespace: expectedNamespace, + StartTime: adjustedStartTime, + Dimensions: expectedDimensions, + EndTime: endTime, + Period: 60, + MetricName: expectedMetricName, + Statistics: ['Sum'], + }) + ); + + // Since lambda has been called twice in this test and potentially more in others, metric sum should be at least of expectedMetricValue * invocationCount + const singleDataPoint = metricStat.Datapoints + ? metricStat.Datapoints[0] + : {}; + expect(singleDataPoint?.Sum).toBeGreaterThanOrEqual( + Number.parseInt(expectedMetricValue) * invocations + ); + }); }); afterAll(async () => { if (!process.env.DISABLE_TEARDOWN) { await testStack.destroy(); } - }, TEARDOWN_TIMEOUT); + }); }); diff --git a/packages/metrics/tests/e2e/basicFeatures.manual.test.ts b/packages/metrics/tests/e2e/basicFeatures.manual.test.ts index 5272ee8578..694d444847 100644 --- a/packages/metrics/tests/e2e/basicFeatures.manual.test.ts +++ b/packages/metrics/tests/e2e/basicFeatures.manual.test.ts @@ -10,14 +10,7 @@ import { import { afterAll, beforeAll, describe, expect, it } from 'vitest'; import { getMetrics, sortDimensions } from '../helpers/metricsUtils.js'; import { MetricsTestNodejsFunction } from '../helpers/resources.js'; -import { - ONE_MINUTE, - RESOURCE_NAME_PREFIX, - SETUP_TIMEOUT, - TEARDOWN_TIMEOUT, - TEST_CASE_TIMEOUT, - commonEnvironmentVars, -} from './constants.js'; +import { RESOURCE_NAME_PREFIX, commonEnvironmentVars } from './constants.js'; describe('Metrics E2E tests, manual usage', () => { const testStack = new TestStack({ @@ -64,121 +57,111 @@ describe('Metrics E2E tests, manual usage', () => { times: invocations, invocationMode: 'SEQUENTIAL', }); - }, SETUP_TIMEOUT); + }); describe('ColdStart metrics', () => { - it( - 'captures the ColdStart Metric', - async () => { - const { EXPECTED_NAMESPACE: expectedNamespace } = commonEnvironmentVars; - - // Check coldstart metric dimensions - const coldStartMetrics = await getMetrics( - cloudwatchClient, - expectedNamespace, - 'ColdStart', - 1 - ); - expect(coldStartMetrics.Metrics?.length).toBe(1); - const coldStartMetric = coldStartMetrics.Metrics?.[0]; - expect(coldStartMetric?.Dimensions).toStrictEqual([ - { Name: 'service', Value: expectedServiceName }, - ]); - - // Check coldstart metric value - const adjustedStartTime = new Date(startTime.getTime() - 60 * 1000); - const endTime = new Date(new Date().getTime() + 60 * 1000); - const coldStartMetricStat = await cloudwatchClient.send( - new GetMetricStatisticsCommand({ - Namespace: expectedNamespace, - StartTime: adjustedStartTime, - Dimensions: [{ Name: 'service', Value: expectedServiceName }], - EndTime: endTime, - Period: 60, - MetricName: 'ColdStart', - Statistics: ['Sum'], - }) - ); - - // Despite lambda has been called twice, coldstart metric sum should only be 1 - const singleDataPoint = coldStartMetricStat.Datapoints - ? coldStartMetricStat.Datapoints[0] - : {}; - expect(singleDataPoint?.Sum).toBe(1); - }, - TEST_CASE_TIMEOUT - ); + it('captures the ColdStart Metric', async () => { + const { EXPECTED_NAMESPACE: expectedNamespace } = commonEnvironmentVars; + + // Check coldstart metric dimensions + const coldStartMetrics = await getMetrics( + cloudwatchClient, + expectedNamespace, + 'ColdStart', + 1 + ); + expect(coldStartMetrics.Metrics?.length).toBe(1); + const coldStartMetric = coldStartMetrics.Metrics?.[0]; + expect(coldStartMetric?.Dimensions).toStrictEqual([ + { Name: 'service', Value: expectedServiceName }, + ]); + + // Check coldstart metric value + const adjustedStartTime = new Date(startTime.getTime() - 60 * 1000); + const endTime = new Date(new Date().getTime() + 60 * 1000); + const coldStartMetricStat = await cloudwatchClient.send( + new GetMetricStatisticsCommand({ + Namespace: expectedNamespace, + StartTime: adjustedStartTime, + Dimensions: [{ Name: 'service', Value: expectedServiceName }], + EndTime: endTime, + Period: 60, + MetricName: 'ColdStart', + Statistics: ['Sum'], + }) + ); + + // Despite lambda has been called twice, coldstart metric sum should only be 1 + const singleDataPoint = coldStartMetricStat.Datapoints + ? coldStartMetricStat.Datapoints[0] + : {}; + expect(singleDataPoint?.Sum).toBe(1); + }); }); describe('Default and extra dimensions', () => { - it( - 'produces a Metric with the default and extra one dimensions', - async () => { - const { - EXPECTED_NAMESPACE: expectedNamespace, - EXPECTED_METRIC_NAME: expectedMetricName, - EXPECTED_METRIC_VALUE: expectedMetricValue, - EXPECTED_DEFAULT_DIMENSIONS: expectedDefaultDimensions, - EXPECTED_EXTRA_DIMENSION: expectedExtraDimension, - } = commonEnvironmentVars; - - // Check metric dimensions - const metrics = await getMetrics( - cloudwatchClient, - expectedNamespace, - expectedMetricName, - 1 - ); - - expect(metrics.Metrics?.length).toBe(1); - const metric = metrics.Metrics?.[0]; - const expectedDimensions = [ - { Name: 'service', Value: expectedServiceName }, - { - Name: Object.keys(expectedDefaultDimensions)[0], - Value: expectedDefaultDimensions.MyDimension, - }, - { - Name: Object.keys(expectedExtraDimension)[0], - Value: expectedExtraDimension.MyExtraDimension, - }, - ]; - expect(sortDimensions(metric?.Dimensions)).toStrictEqual( - sortDimensions(expectedDimensions) - ); - - // Check coldstart metric value - const adjustedStartTime = new Date( - startTime.getTime() - 3 * ONE_MINUTE - ); - const endTime = new Date(new Date().getTime() + ONE_MINUTE); - const metricStat = await cloudwatchClient.send( - new GetMetricStatisticsCommand({ - Namespace: expectedNamespace, - StartTime: adjustedStartTime, - Dimensions: expectedDimensions, - EndTime: endTime, - Period: 60, - MetricName: expectedMetricName, - Statistics: ['Sum'], - }) - ); - - // Since lambda has been called twice in this test and potentially more in others, metric sum should be at least of expectedMetricValue * invocationCount - const singleDataPoint = metricStat.Datapoints - ? metricStat.Datapoints[0] - : {}; - expect(singleDataPoint.Sum).toBeGreaterThanOrEqual( - Number.parseInt(expectedMetricValue) * invocations - ); - }, - TEST_CASE_TIMEOUT - ); + it('produces a Metric with the default and extra one dimensions', async () => { + const { + EXPECTED_NAMESPACE: expectedNamespace, + EXPECTED_METRIC_NAME: expectedMetricName, + EXPECTED_METRIC_VALUE: expectedMetricValue, + EXPECTED_DEFAULT_DIMENSIONS: expectedDefaultDimensions, + EXPECTED_EXTRA_DIMENSION: expectedExtraDimension, + } = commonEnvironmentVars; + + // Check metric dimensions + const metrics = await getMetrics( + cloudwatchClient, + expectedNamespace, + expectedMetricName, + 1 + ); + + expect(metrics.Metrics?.length).toBe(1); + const metric = metrics.Metrics?.[0]; + const expectedDimensions = [ + { Name: 'service', Value: expectedServiceName }, + { + Name: Object.keys(expectedDefaultDimensions)[0], + Value: expectedDefaultDimensions.MyDimension, + }, + { + Name: Object.keys(expectedExtraDimension)[0], + Value: expectedExtraDimension.MyExtraDimension, + }, + ]; + expect(sortDimensions(metric?.Dimensions)).toStrictEqual( + sortDimensions(expectedDimensions) + ); + + // Check coldstart metric value + const adjustedStartTime = new Date(startTime.getTime() - 3 * 60 * 1000); + const endTime = new Date(new Date().getTime() + 60 * 1000); + const metricStat = await cloudwatchClient.send( + new GetMetricStatisticsCommand({ + Namespace: expectedNamespace, + StartTime: adjustedStartTime, + Dimensions: expectedDimensions, + EndTime: endTime, + Period: 60, + MetricName: expectedMetricName, + Statistics: ['Sum'], + }) + ); + + // Since lambda has been called twice in this test and potentially more in others, metric sum should be at least of expectedMetricValue * invocationCount + const singleDataPoint = metricStat.Datapoints + ? metricStat.Datapoints[0] + : {}; + expect(singleDataPoint.Sum).toBeGreaterThanOrEqual( + Number.parseInt(expectedMetricValue) * invocations + ); + }); }); afterAll(async () => { if (!process.env.DISABLE_TEARDOWN) { await testStack.destroy(); } - }, TEARDOWN_TIMEOUT); + }); }); diff --git a/packages/metrics/tests/e2e/constants.ts b/packages/metrics/tests/e2e/constants.ts index dbffabf33a..7837b7e551 100644 --- a/packages/metrics/tests/e2e/constants.ts +++ b/packages/metrics/tests/e2e/constants.ts @@ -2,10 +2,6 @@ import { randomUUID } from 'node:crypto'; import { MetricUnit } from '../../src/index.js'; const RESOURCE_NAME_PREFIX = 'Metrics'; -const ONE_MINUTE = 60 * 1000; -const TEST_CASE_TIMEOUT = 3 * ONE_MINUTE; -const SETUP_TIMEOUT = 7 * ONE_MINUTE; -const TEARDOWN_TIMEOUT = 5 * ONE_MINUTE; const commonEnvironmentVars = { EXPECTED_METRIC_NAME: 'MyMetric', @@ -21,11 +17,4 @@ const commonEnvironmentVars = { POWERTOOLS_SERVICE_NAME: 'metrics-e2e-testing', }; -export { - RESOURCE_NAME_PREFIX, - ONE_MINUTE, - TEST_CASE_TIMEOUT, - SETUP_TIMEOUT, - TEARDOWN_TIMEOUT, - commonEnvironmentVars, -}; +export { RESOURCE_NAME_PREFIX, commonEnvironmentVars }; diff --git a/packages/metrics/vitest.config.ts b/packages/metrics/vitest.config.ts index 9f1196ef1f..baa5cf7463 100644 --- a/packages/metrics/vitest.config.ts +++ b/packages/metrics/vitest.config.ts @@ -4,5 +4,7 @@ export default defineProject({ test: { environment: 'node', setupFiles: ['../testing/src/setupEnv.ts'], + hookTimeout: 1_000 * 60 * 10, // 10 minutes + testTimeout: 1_000 * 60 * 3, // 3 minutes }, }); diff --git a/packages/parameters/tests/e2e/appConfigProvider.class.test.ts b/packages/parameters/tests/e2e/appConfigProvider.class.test.ts index 3bd7e3a9b7..5159600f79 100644 --- a/packages/parameters/tests/e2e/appConfigProvider.class.test.ts +++ b/packages/parameters/tests/e2e/appConfigProvider.class.test.ts @@ -8,12 +8,7 @@ import { TestNodejsFunction } from '@aws-lambda-powertools/testing-utils/resourc import { toBase64 } from '@smithy/util-base64'; import { afterAll, beforeAll, describe, expect, it } from 'vitest'; import { TestAppConfigWithProfiles } from '../helpers/resources.js'; -import { - RESOURCE_NAME_PREFIX, - SETUP_TIMEOUT, - TEARDOWN_TIMEOUT, - TEST_CASE_TIMEOUT, -} from './constants.js'; +import { RESOURCE_NAME_PREFIX } from './constants.js'; /** * This test suite deploys a CDK stack with a Lambda function and a number of AppConfig parameters. @@ -172,7 +167,7 @@ describe('Parameters E2E tests, AppConfig provider', () => { invocationLogs = await invokeFunctionOnce({ functionName, }); - }, SETUP_TIMEOUT); + }); describe('AppConfigProvider usage', () => { // Test 1 - get a single parameter as-is (no transformation - should return an Uint8Array) @@ -222,62 +217,50 @@ describe('Parameters E2E tests, AppConfig provider', () => { // Test 5 - get parameter twice with middleware, which counts the number // of requests, we check later if we only called AppConfig API once - it( - 'should retrieve single parameter cached', - () => { - const logs = invocationLogs.getFunctionLogs(); - const testLog = TestInvocationLogs.parseFunctionLog(logs[4]); + it('should retrieve single parameter cached', () => { + const logs = invocationLogs.getFunctionLogs(); + const testLog = TestInvocationLogs.parseFunctionLog(logs[4]); - expect(testLog).toStrictEqual({ - test: 'get-cached', - value: 1, - }); - }, - TEST_CASE_TIMEOUT - ); + expect(testLog).toStrictEqual({ + test: 'get-cached', + value: 1, + }); + }); // Test 6 - get parameter twice, but force fetch 2nd time, // we count number of SDK requests and check that we made two API calls - it( - 'should retrieve single parameter twice without caching', - async () => { - const logs = invocationLogs.getFunctionLogs(); - const testLog = TestInvocationLogs.parseFunctionLog(logs[5]); + it('should retrieve single parameter twice without caching', async () => { + const logs = invocationLogs.getFunctionLogs(); + const testLog = TestInvocationLogs.parseFunctionLog(logs[5]); - expect(testLog).toStrictEqual({ - test: 'get-forced', - value: 2, - }); - }, - TEST_CASE_TIMEOUT - ); + expect(testLog).toStrictEqual({ + test: 'get-forced', + value: 2, + }); + }); // Test 7 - get parameter twice, using maxAge to avoid primary cache // we count number of SDK requests and check that we made two API calls // and check that the values match - it( - 'should retrieve single parameter twice, with expiration between and matching values', - async () => { - const logs = invocationLogs.getFunctionLogs(); - const testLog = TestInvocationLogs.parseFunctionLog(logs[6]); - const result = freeFormPlainTextValue; + it('should retrieve single parameter twice, with expiration between and matching values', async () => { + const logs = invocationLogs.getFunctionLogs(); + const testLog = TestInvocationLogs.parseFunctionLog(logs[6]); + const result = freeFormPlainTextValue; - expect(testLog).toStrictEqual({ - test: 'get-expired', - value: { - counter: 2, - result1: result, - result2: result, - }, - }); - }, - TEST_CASE_TIMEOUT - ); + expect(testLog).toStrictEqual({ + test: 'get-expired', + value: { + counter: 2, + result1: result, + result2: result, + }, + }); + }); }); afterAll(async () => { if (!process.env.DISABLE_TEARDOWN) { await testStack.destroy(); } - }, TEARDOWN_TIMEOUT); + }); }); diff --git a/packages/parameters/tests/e2e/constants.ts b/packages/parameters/tests/e2e/constants.ts index b9b9e6ef30..42e1837795 100644 --- a/packages/parameters/tests/e2e/constants.ts +++ b/packages/parameters/tests/e2e/constants.ts @@ -1,5 +1 @@ export const RESOURCE_NAME_PREFIX = 'Parameters'; -export const ONE_MINUTE = 60 * 1000; -export const TEST_CASE_TIMEOUT = 3 * ONE_MINUTE; -export const SETUP_TIMEOUT = 7 * ONE_MINUTE; -export const TEARDOWN_TIMEOUT = 5 * ONE_MINUTE; diff --git a/packages/parameters/tests/e2e/dynamoDBProvider.class.test.ts b/packages/parameters/tests/e2e/dynamoDBProvider.class.test.ts index 17c56600d2..333bbb7fce 100644 --- a/packages/parameters/tests/e2e/dynamoDBProvider.class.test.ts +++ b/packages/parameters/tests/e2e/dynamoDBProvider.class.test.ts @@ -8,12 +8,7 @@ import { TestNodejsFunction } from '@aws-lambda-powertools/testing-utils/resourc import { AttributeType } from 'aws-cdk-lib/aws-dynamodb'; import { afterAll, beforeAll, describe, expect, it } from 'vitest'; import { TestDynamodbTableWithItems } from '../helpers/resources.js'; -import { - RESOURCE_NAME_PREFIX, - SETUP_TIMEOUT, - TEARDOWN_TIMEOUT, - TEST_CASE_TIMEOUT, -} from './constants.js'; +import { RESOURCE_NAME_PREFIX } from './constants.js'; /** * This test suite deploys a CDK stack with a Lambda function and a number of DynamoDB tables. @@ -264,68 +259,52 @@ describe('Parameters E2E tests, dynamoDB provider', () => { invocationLogs = await invokeFunctionOnce({ functionName, }); - }, SETUP_TIMEOUT); + }); describe('DynamoDBProvider usage', () => { // Test 1 - get a single parameter with default options (keyAttr: 'id', valueAttr: 'value') - it( - 'should retrieve a single parameter', - async () => { - const logs = invocationLogs.getFunctionLogs(); - const testLog = TestInvocationLogs.parseFunctionLog(logs[0]); + it('should retrieve a single parameter', async () => { + const logs = invocationLogs.getFunctionLogs(); + const testLog = TestInvocationLogs.parseFunctionLog(logs[0]); - expect(testLog).toStrictEqual({ - test: 'get', - value: 'foo', - }); - }, - TEST_CASE_TIMEOUT - ); + expect(testLog).toStrictEqual({ + test: 'get', + value: 'foo', + }); + }); // Test 2 - get multiple parameters with default options (keyAttr: 'id', sortAttr: 'sk', valueAttr: 'value') - it( - 'should retrieve multiple parameters', - async () => { - const logs = invocationLogs.getFunctionLogs(); - const testLog = TestInvocationLogs.parseFunctionLog(logs[1]); + it('should retrieve multiple parameters', async () => { + const logs = invocationLogs.getFunctionLogs(); + const testLog = TestInvocationLogs.parseFunctionLog(logs[1]); - expect(testLog).toStrictEqual({ - test: 'get-multiple', - value: { config: 'bar', key: 'baz' }, - }); - }, - TEST_CASE_TIMEOUT - ); + expect(testLog).toStrictEqual({ + test: 'get-multiple', + value: { config: 'bar', key: 'baz' }, + }); + }); // Test 3 - get a single parameter with custom options (keyAttr: 'key', valueAttr: 'val') - it( - 'should retrieve a single parameter', - async () => { - const logs = invocationLogs.getFunctionLogs(); - const testLog = TestInvocationLogs.parseFunctionLog(logs[2]); + it('should retrieve a single parameter', async () => { + const logs = invocationLogs.getFunctionLogs(); + const testLog = TestInvocationLogs.parseFunctionLog(logs[2]); - expect(testLog).toStrictEqual({ - test: 'get-custom', - value: 'foo', - }); - }, - TEST_CASE_TIMEOUT - ); + expect(testLog).toStrictEqual({ + test: 'get-custom', + value: 'foo', + }); + }); // Test 4 - get multiple parameters with custom options (keyAttr: 'key', sortAttr: 'sort', valueAttr: 'val') - it( - 'should retrieve multiple parameters', - async () => { - const logs = invocationLogs.getFunctionLogs(); - const testLog = TestInvocationLogs.parseFunctionLog(logs[3]); + it('should retrieve multiple parameters', async () => { + const logs = invocationLogs.getFunctionLogs(); + const testLog = TestInvocationLogs.parseFunctionLog(logs[3]); - expect(testLog).toStrictEqual({ - test: 'get-multiple-custom', - value: { config: 'bar', key: 'baz' }, - }); - }, - TEST_CASE_TIMEOUT - ); + expect(testLog).toStrictEqual({ + test: 'get-multiple-custom', + value: { config: 'bar', key: 'baz' }, + }); + }); // Test 5 - get a single parameter with json transform it('should retrieve a single parameter with json transform', async () => { @@ -390,5 +369,5 @@ describe('Parameters E2E tests, dynamoDB provider', () => { if (!process.env.DISABLE_TEARDOWN) { await testStack.destroy(); } - }, TEARDOWN_TIMEOUT); + }); }); diff --git a/packages/parameters/tests/e2e/secretsProvider.class.test.ts b/packages/parameters/tests/e2e/secretsProvider.class.test.ts index 4acbd65eba..87467a9b06 100644 --- a/packages/parameters/tests/e2e/secretsProvider.class.test.ts +++ b/packages/parameters/tests/e2e/secretsProvider.class.test.ts @@ -8,12 +8,7 @@ import { TestNodejsFunction } from '@aws-lambda-powertools/testing-utils/resourc import { SecretValue } from 'aws-cdk-lib'; import { afterAll, beforeAll, describe, expect, it } from 'vitest'; import { TestSecret } from '../helpers/resources.js'; -import { - RESOURCE_NAME_PREFIX, - SETUP_TIMEOUT, - TEARDOWN_TIMEOUT, - TEST_CASE_TIMEOUT, -} from './constants.js'; +import { RESOURCE_NAME_PREFIX } from './constants.js'; /** * Collection of e2e tests for SecretsProvider utility. @@ -138,50 +133,38 @@ describe('Parameters E2E tests, Secrets Manager provider', () => { invocationLogs = await invokeFunctionOnce({ functionName, }); - }, SETUP_TIMEOUT); + }); describe('SecretsProvider usage', () => { - it( - 'should retrieve a secret as plain string', - async () => { - const logs = invocationLogs.getFunctionLogs(); - const testLog = TestInvocationLogs.parseFunctionLog(logs[0]); - - expect(testLog).toStrictEqual({ - test: 'get-plain', - value: 'foo', - }); - }, - TEST_CASE_TIMEOUT - ); + it('should retrieve a secret as plain string', async () => { + const logs = invocationLogs.getFunctionLogs(); + const testLog = TestInvocationLogs.parseFunctionLog(logs[0]); + + expect(testLog).toStrictEqual({ + test: 'get-plain', + value: 'foo', + }); + }); - it( - 'should retrieve a secret using transform json option', - async () => { - const logs = invocationLogs.getFunctionLogs(); - const testLog = TestInvocationLogs.parseFunctionLog(logs[1]); + it('should retrieve a secret using transform json option', async () => { + const logs = invocationLogs.getFunctionLogs(); + const testLog = TestInvocationLogs.parseFunctionLog(logs[1]); - expect(testLog).toStrictEqual({ - test: 'get-transform-json', - value: { foo: 'bar' }, - }); - }, - TEST_CASE_TIMEOUT - ); + expect(testLog).toStrictEqual({ + test: 'get-transform-json', + value: { foo: 'bar' }, + }); + }); - it( - 'should retrieve a secret using transform binary option', - async () => { - const logs = invocationLogs.getFunctionLogs(); - const testLog = TestInvocationLogs.parseFunctionLog(logs[2]); + it('should retrieve a secret using transform binary option', async () => { + const logs = invocationLogs.getFunctionLogs(); + const testLog = TestInvocationLogs.parseFunctionLog(logs[2]); - expect(testLog).toStrictEqual({ - test: 'get-transform-binary', - value: 'foo', - }); - }, - TEST_CASE_TIMEOUT - ); + expect(testLog).toStrictEqual({ + test: 'get-transform-binary', + value: 'foo', + }); + }); }); it('should retrieve a secret twice with cached value', async () => { @@ -210,5 +193,5 @@ describe('Parameters E2E tests, Secrets Manager provider', () => { if (!process.env.DISABLE_TEARDOWN) { await testStack.destroy(); } - }, TEARDOWN_TIMEOUT); + }); }); diff --git a/packages/parameters/tests/e2e/ssmProvider.class.test.ts b/packages/parameters/tests/e2e/ssmProvider.class.test.ts index 71d7f75a1d..fa5bf8931b 100644 --- a/packages/parameters/tests/e2e/ssmProvider.class.test.ts +++ b/packages/parameters/tests/e2e/ssmProvider.class.test.ts @@ -10,12 +10,7 @@ import { TestSecureStringParameter, TestStringParameter, } from '../helpers/resources.js'; -import { - RESOURCE_NAME_PREFIX, - SETUP_TIMEOUT, - TEARDOWN_TIMEOUT, - TEST_CASE_TIMEOUT, -} from './constants.js'; +import { RESOURCE_NAME_PREFIX } from './constants.js'; /** * This test suite deploys a CDK stack with a Lambda function and a number of SSM parameters. @@ -189,200 +184,160 @@ describe('Parameters E2E tests, SSM provider', () => { invocationLogs = await invokeFunctionOnce({ functionName, }); - }, SETUP_TIMEOUT); + }); describe('SSMProvider usage', () => { // Test 1 - get a single parameter by name with default options - it( - 'should retrieve a single parameter', - async () => { - const logs = invocationLogs.getFunctionLogs(); - const testLog = TestInvocationLogs.parseFunctionLog(logs[0]); - - expect(testLog).toStrictEqual({ - test: 'get', - value: paramAValue, - }); - }, - TEST_CASE_TIMEOUT - ); + it('should retrieve a single parameter', async () => { + const logs = invocationLogs.getFunctionLogs(); + const testLog = TestInvocationLogs.parseFunctionLog(logs[0]); + + expect(testLog).toStrictEqual({ + test: 'get', + value: paramAValue, + }); + }); // Test 2 - get a single parameter by name with decrypt - it( - 'should retrieve a single parameter with decryption', - async () => { - const logs = invocationLogs.getFunctionLogs(); - const testLog = TestInvocationLogs.parseFunctionLog(logs[1]); - - expect(testLog).toStrictEqual({ - test: 'get-decrypt', - value: paramEncryptedAValue, - }); - }, - TEST_CASE_TIMEOUT - ); + it('should retrieve a single parameter with decryption', async () => { + const logs = invocationLogs.getFunctionLogs(); + const testLog = TestInvocationLogs.parseFunctionLog(logs[1]); + + expect(testLog).toStrictEqual({ + test: 'get-decrypt', + value: paramEncryptedAValue, + }); + }); // Test 3 - get multiple parameters by path with default options - it( - 'should retrieve multiple parameters', - async () => { - const logs = invocationLogs.getFunctionLogs(); - const testLog = TestInvocationLogs.parseFunctionLog(logs[2]); - const expectedParameterNameA = paramA.substring( - paramA.lastIndexOf('/') + 1 - ); - const expectedParameterNameB = paramB.substring( - paramB.lastIndexOf('/') + 1 - ); - - expect(testLog).toStrictEqual({ - test: 'get-multiple', - value: { - [expectedParameterNameA]: paramAValue, - [expectedParameterNameB]: paramBValue, - }, - }); - }, - TEST_CASE_TIMEOUT - ); + it('should retrieve multiple parameters', async () => { + const logs = invocationLogs.getFunctionLogs(); + const testLog = TestInvocationLogs.parseFunctionLog(logs[2]); + const expectedParameterNameA = paramA.substring( + paramA.lastIndexOf('/') + 1 + ); + const expectedParameterNameB = paramB.substring( + paramB.lastIndexOf('/') + 1 + ); + + expect(testLog).toStrictEqual({ + test: 'get-multiple', + value: { + [expectedParameterNameA]: paramAValue, + [expectedParameterNameB]: paramBValue, + }, + }); + }); // Test 4 - get multiple parameters by path recursively // (aka. get all parameters under a path recursively) i.e. // given /param, retrieve /param/get/a and /param/get/b (note path depth) - it( - 'should retrieve multiple parameters recursively', - async () => { - const logs = invocationLogs.getFunctionLogs(); - const testLog = TestInvocationLogs.parseFunctionLog(logs[3]); - const expectedParameterNameA = paramA.substring( - paramA.lastIndexOf('/') + 1 - ); - const expectedParameterNameB = paramB.substring( - paramB.lastIndexOf('/') + 1 - ); - - expect(testLog).toStrictEqual({ - test: 'get-multiple-recursive', - value: { - [expectedParameterNameA]: paramAValue, - [expectedParameterNameB]: paramBValue, - }, - }); - }, - TEST_CASE_TIMEOUT - ); + it('should retrieve multiple parameters recursively', async () => { + const logs = invocationLogs.getFunctionLogs(); + const testLog = TestInvocationLogs.parseFunctionLog(logs[3]); + const expectedParameterNameA = paramA.substring( + paramA.lastIndexOf('/') + 1 + ); + const expectedParameterNameB = paramB.substring( + paramB.lastIndexOf('/') + 1 + ); + + expect(testLog).toStrictEqual({ + test: 'get-multiple-recursive', + value: { + [expectedParameterNameA]: paramAValue, + [expectedParameterNameB]: paramBValue, + }, + }); + }); - it( - 'should retrieve multiple parameters with decryption', - async () => { - const logs = invocationLogs.getFunctionLogs(); - const testLog = TestInvocationLogs.parseFunctionLog(logs[4]); - const expectedParameterNameA = paramEncryptedA.substring( - paramEncryptedA.lastIndexOf('/') + 1 - ); - const expectedParameterNameB = paramEncryptedB.substring( - paramEncryptedB.lastIndexOf('/') + 1 - ); - - expect(testLog).toStrictEqual({ - test: 'get-multiple-decrypt', - value: { - [expectedParameterNameA]: paramEncryptedAValue, - [expectedParameterNameB]: paramEncryptedBValue, - }, - }); - }, - TEST_CASE_TIMEOUT - ); + it('should retrieve multiple parameters with decryption', async () => { + const logs = invocationLogs.getFunctionLogs(); + const testLog = TestInvocationLogs.parseFunctionLog(logs[4]); + const expectedParameterNameA = paramEncryptedA.substring( + paramEncryptedA.lastIndexOf('/') + 1 + ); + const expectedParameterNameB = paramEncryptedB.substring( + paramEncryptedB.lastIndexOf('/') + 1 + ); + + expect(testLog).toStrictEqual({ + test: 'get-multiple-decrypt', + value: { + [expectedParameterNameA]: paramEncryptedAValue, + [expectedParameterNameB]: paramEncryptedBValue, + }, + }); + }); // Test 6 - get multiple parameters by name with default options - it( - 'should retrieve multiple parameters by name', - async () => { - const logs = invocationLogs.getFunctionLogs(); - const testLog = TestInvocationLogs.parseFunctionLog(logs[5]); - - expect(testLog).toStrictEqual({ - test: 'get-multiple-by-name', - value: { - [paramA]: paramAValue, - [paramB]: paramBValue, - }, - }); - }, - TEST_CASE_TIMEOUT - ); + it('should retrieve multiple parameters by name', async () => { + const logs = invocationLogs.getFunctionLogs(); + const testLog = TestInvocationLogs.parseFunctionLog(logs[5]); + + expect(testLog).toStrictEqual({ + test: 'get-multiple-by-name', + value: { + [paramA]: paramAValue, + [paramB]: paramBValue, + }, + }); + }); // Test 7 - get multiple parameters by name, some of them encrypted and some not - it( - 'should retrieve multiple parameters by name with mixed decryption', - async () => { - const logs = invocationLogs.getFunctionLogs(); - const testLog = TestInvocationLogs.parseFunctionLog(logs[6]); - - expect(testLog).toStrictEqual({ - test: 'get-multiple-by-name-mixed-decrypt', - value: { - [paramEncryptedA]: paramEncryptedAValue, - [paramEncryptedB]: paramEncryptedBValue, - [paramA]: paramAValue, - }, - }); - }, - TEST_CASE_TIMEOUT - ); + it('should retrieve multiple parameters by name with mixed decryption', async () => { + const logs = invocationLogs.getFunctionLogs(); + const testLog = TestInvocationLogs.parseFunctionLog(logs[6]); + + expect(testLog).toStrictEqual({ + test: 'get-multiple-by-name-mixed-decrypt', + value: { + [paramEncryptedA]: paramEncryptedAValue, + [paramEncryptedB]: paramEncryptedBValue, + [paramA]: paramAValue, + }, + }); + }); // Test 8 - get parameter twice with middleware, which counts the number // of requests, we check later if we only called SSM API once - it( - 'should retrieve single parameter cached', - async () => { - const logs = invocationLogs.getFunctionLogs(); - const testLog = TestInvocationLogs.parseFunctionLog(logs[7]); - - expect(testLog).toStrictEqual({ - test: 'get-cached', - value: 1, - }); - }, - TEST_CASE_TIMEOUT - ); + it('should retrieve single parameter cached', async () => { + const logs = invocationLogs.getFunctionLogs(); + const testLog = TestInvocationLogs.parseFunctionLog(logs[7]); + + expect(testLog).toStrictEqual({ + test: 'get-cached', + value: 1, + }); + }); // Test 9 - get parameter twice, but force fetch 2nd time, // we count number of SDK requests and check that we made two API calls - it( - 'should retrieve single parameter twice without caching', - async () => { - const logs = invocationLogs.getFunctionLogs(); - const testLog = TestInvocationLogs.parseFunctionLog(logs[8]); - - expect(testLog).toStrictEqual({ - test: 'get-forced', - value: 2, - }); - }, - TEST_CASE_TIMEOUT - ); + it('should retrieve single parameter twice without caching', async () => { + const logs = invocationLogs.getFunctionLogs(); + const testLog = TestInvocationLogs.parseFunctionLog(logs[8]); + + expect(testLog).toStrictEqual({ + test: 'get-forced', + value: 2, + }); + }); // Test 10 - store and overwrite single parameter - it( - 'should store and overwrite single parameter', - async () => { - const logs = invocationLogs.getFunctionLogs(); - const testLog = TestInvocationLogs.parseFunctionLog(logs[9]); - - expect(testLog).toStrictEqual({ - test: 'set', - value: 'overwritten', - }); - }, - TEST_CASE_TIMEOUT - ); + it('should store and overwrite single parameter', async () => { + const logs = invocationLogs.getFunctionLogs(); + const testLog = TestInvocationLogs.parseFunctionLog(logs[9]); + + expect(testLog).toStrictEqual({ + test: 'set', + value: 'overwritten', + }); + }); }); afterAll(async () => { if (!process.env.DISABLE_TEARDOWN) { await testStack.destroy(); } - }, TEARDOWN_TIMEOUT); + }); }); diff --git a/packages/parameters/vitest.config.ts b/packages/parameters/vitest.config.ts index 9f1196ef1f..baa5cf7463 100644 --- a/packages/parameters/vitest.config.ts +++ b/packages/parameters/vitest.config.ts @@ -4,5 +4,7 @@ export default defineProject({ test: { environment: 'node', setupFiles: ['../testing/src/setupEnv.ts'], + hookTimeout: 1_000 * 60 * 10, // 10 minutes + testTimeout: 1_000 * 60 * 3, // 3 minutes }, }); diff --git a/packages/testing/src/TestInvocationLogs.ts b/packages/testing/src/TestInvocationLogs.ts index 2de21918ae..45c189aa5f 100644 --- a/packages/testing/src/TestInvocationLogs.ts +++ b/packages/testing/src/TestInvocationLogs.ts @@ -4,6 +4,7 @@ import type { FunctionLog } from './types.js'; const CloudWatchLogKeywords = { END: 'END RequestId', INIT_START: 'INIT_START', + INIT_REPORT: 'INIT_REPORT', REPORT: 'REPORT RequestId', START: 'START RequestId', XRAY: 'XRAY TraceId', @@ -99,13 +100,15 @@ class TestInvocationLogs { } /** - * Return the index of the log that contains `INIT_START` - * @param logs - * @returns {number} index of the log that contains `INIT_START` + * Return the index of the log that contains `INIT_START` or `INIT_REPORT` + * + * @param logs - Array of logs */ public static getInitLogIndex(logs: string[]): number { - return logs.findIndex((log) => - log.startsWith(CloudWatchLogKeywords.INIT_START) + return logs.findIndex( + (log) => + log.startsWith(CloudWatchLogKeywords.INIT_START) || + log.startsWith(CloudWatchLogKeywords.INIT_REPORT) ); } diff --git a/packages/testing/src/resources/TestNodejsFunction.ts b/packages/testing/src/resources/TestNodejsFunction.ts index 01a383153f..e20ee86183 100644 --- a/packages/testing/src/resources/TestNodejsFunction.ts +++ b/packages/testing/src/resources/TestNodejsFunction.ts @@ -1,6 +1,6 @@ import { randomUUID } from 'node:crypto'; -import { CfnOutput, type CfnResource, Duration } from 'aws-cdk-lib'; -import { Tracing } from 'aws-cdk-lib/aws-lambda'; +import { CfnOutput, Duration } from 'aws-cdk-lib'; +import { Alias, Tracing } from 'aws-cdk-lib/aws-lambda'; import { NodejsFunction, OutputFormat } from 'aws-cdk-lib/aws-lambda-nodejs'; import { LogGroup, RetentionDays } from 'aws-cdk-lib/aws-logs'; import type { TestStack } from '../TestStack.js'; @@ -56,8 +56,18 @@ class TestNodejsFunction extends NodejsFunction { logGroup, }); + let outputValue = this.functionName; + if (extraProps.createAlias) { + const dev = new Alias(this, 'dev', { + aliasName: 'dev', + version: this.currentVersion, + provisionedConcurrentExecutions: 1, + }); + outputValue = dev.functionArn; + } + new CfnOutput(this, extraProps.nameSuffix, { - value: this.functionName, + value: outputValue, }); } } diff --git a/packages/testing/src/setupEnv.ts b/packages/testing/src/setupEnv.ts index 0a0c83b84a..9caf9e724f 100644 --- a/packages/testing/src/setupEnv.ts +++ b/packages/testing/src/setupEnv.ts @@ -377,3 +377,4 @@ if ( process.env._HANDLER = 'index.handler'; process.env.POWERTOOLS_SERVICE_NAME = 'hello-world'; process.env.AWS_XRAY_LOGGING_LEVEL = 'silent'; +process.env.AWS_LAMBDA_INITIALIZATION_TYPE = 'on-demand'; diff --git a/packages/testing/src/types.ts b/packages/testing/src/types.ts index 454c2d87b4..432f01e42f 100644 --- a/packages/testing/src/types.ts +++ b/packages/testing/src/types.ts @@ -19,6 +19,12 @@ interface ExtraTestProps { * @default 'CJS' */ outputFormat?: 'CJS' | 'ESM'; + /** + * Whether to create an alias for the function. + * + * @default false + */ + createAlias?: boolean; } type TestDynamodbTableProps = Omit< diff --git a/packages/tracer/tests/e2e/constants.ts b/packages/tracer/tests/e2e/constants.ts index 77ea5c9ed2..e4db5268cf 100644 --- a/packages/tracer/tests/e2e/constants.ts +++ b/packages/tracer/tests/e2e/constants.ts @@ -1,10 +1,5 @@ // Prefix for all resources created by the E2E tests const RESOURCE_NAME_PREFIX = 'Tracer'; -// Constants relating time to be used in the tests -const ONE_MINUTE = 60 * 1_000; -const TEST_CASE_TIMEOUT = 5 * ONE_MINUTE; -const SETUP_TIMEOUT = 7 * ONE_MINUTE; -const TEARDOWN_TIMEOUT = 5 * ONE_MINUTE; // Expected values for custom annotations, metadata, and response const EXPECTED_ANNOTATION_KEY = 'myAnnotation'; @@ -17,10 +12,6 @@ const EXPECTED_SUBSEGMENT_NAME = '### mySubsegment'; export { RESOURCE_NAME_PREFIX, - ONE_MINUTE, - TEST_CASE_TIMEOUT, - SETUP_TIMEOUT, - TEARDOWN_TIMEOUT, EXPECTED_ANNOTATION_KEY, EXPECTED_ANNOTATION_VALUE, EXPECTED_METADATA_KEY, diff --git a/packages/tracer/tests/e2e/decorator.test.ts b/packages/tracer/tests/e2e/decorator.test.ts index 8a87282431..260dfae659 100644 --- a/packages/tracer/tests/e2e/decorator.test.ts +++ b/packages/tracer/tests/e2e/decorator.test.ts @@ -8,8 +8,6 @@ import { afterAll, beforeAll, describe, expect, it } from 'vitest'; import { invokeAllTestCases } from '../helpers/invokeAllTests.js'; import { RESOURCE_NAME_PREFIX, - SETUP_TIMEOUT, - TEARDOWN_TIMEOUT, EXPECTED_ANNOTATION_KEY as expectedCustomAnnotationKey, EXPECTED_ANNOTATION_VALUE as expectedCustomAnnotationValue, EXPECTED_ERROR_MESSAGE as expectedCustomErrorMessage, @@ -82,13 +80,13 @@ describe('Tracer E2E tests, decorator instrumentation', () => { */ expectedSegmentsCount: 4, }); - }, SETUP_TIMEOUT); + }); afterAll(async () => { if (!process.env.DISABLE_TEARDOWN) { await testStack.destroy(); } - }, TEARDOWN_TIMEOUT); + }); it('should generate all trace data correctly', async () => { // Assess diff --git a/packages/tracer/tests/e2e/manual.test.ts b/packages/tracer/tests/e2e/manual.test.ts index 80fa766be1..52dbab375e 100644 --- a/packages/tracer/tests/e2e/manual.test.ts +++ b/packages/tracer/tests/e2e/manual.test.ts @@ -8,8 +8,6 @@ import { afterAll, beforeAll, describe, expect, it } from 'vitest'; import { invokeAllTestCases } from '../helpers/invokeAllTests.js'; import { RESOURCE_NAME_PREFIX, - SETUP_TIMEOUT, - TEARDOWN_TIMEOUT, EXPECTED_ANNOTATION_KEY as expectedCustomAnnotationKey, EXPECTED_ANNOTATION_VALUE as expectedCustomAnnotationValue, EXPECTED_ERROR_MESSAGE as expectedCustomErrorMessage, @@ -79,13 +77,13 @@ describe('Tracer E2E tests, manual instantiation', () => { */ expectedSegmentsCount: 2, }); - }, SETUP_TIMEOUT); + }); afterAll(async () => { if (!process.env.DISABLE_TEARDOWN) { await testStack.destroy(); } - }, TEARDOWN_TIMEOUT); + }); it('should generate all trace data correctly', async () => { // Assess diff --git a/packages/tracer/tests/e2e/middy.test.ts b/packages/tracer/tests/e2e/middy.test.ts index 0a33d4377e..361c350166 100644 --- a/packages/tracer/tests/e2e/middy.test.ts +++ b/packages/tracer/tests/e2e/middy.test.ts @@ -8,8 +8,6 @@ import { afterAll, beforeAll, describe, expect, it } from 'vitest'; import { invokeAllTestCases } from '../helpers/invokeAllTests.js'; import { RESOURCE_NAME_PREFIX, - SETUP_TIMEOUT, - TEARDOWN_TIMEOUT, EXPECTED_ANNOTATION_KEY as expectedCustomAnnotationKey, EXPECTED_ANNOTATION_VALUE as expectedCustomAnnotationValue, EXPECTED_ERROR_MESSAGE as expectedCustomErrorMessage, @@ -81,13 +79,13 @@ describe('Tracer E2E tests, middy instrumentation', () => { */ expectedSegmentsCount: 4, }); - }, SETUP_TIMEOUT); + }); afterAll(async () => { if (!process.env.DISABLE_TEARDOWN) { await testStack.destroy(); } - }, TEARDOWN_TIMEOUT); + }); it('should generate all trace data correctly', () => { // Assess diff --git a/packages/tracer/vitest.config.ts b/packages/tracer/vitest.config.ts index 9f1196ef1f..baa5cf7463 100644 --- a/packages/tracer/vitest.config.ts +++ b/packages/tracer/vitest.config.ts @@ -4,5 +4,7 @@ export default defineProject({ test: { environment: 'node', setupFiles: ['../testing/src/setupEnv.ts'], + hookTimeout: 1_000 * 60 * 10, // 10 minutes + testTimeout: 1_000 * 60 * 3, // 3 minutes }, }); diff --git a/vitest.config.ts b/vitest.config.ts index 5d81a103f8..78c6de7f3e 100644 --- a/vitest.config.ts +++ b/vitest.config.ts @@ -20,5 +20,7 @@ export default defineConfig({ ], }, setupFiles: ['./packages/testing/src/setupEnv.ts'], + hookTimeout: 1_000 * 60 * 10, // 10 minutes + testTimeout: 1_000 * 60 * 3, // 3 minutes }, }); From c28e45ecba315bac8fbc7744dbe21a3461747d44 Mon Sep 17 00:00:00 2001 From: Andrea Amorosi Date: Wed, 19 Mar 2025 13:55:26 +0100 Subject: [PATCH 27/56] feat(commons): make utilities aware of provisioned concurrency (#3724) --- packages/commons/src/Utility.ts | 31 +++++++++++++++++ packages/commons/tests/unit/Utility.test.ts | 34 +++++++++++++++++++ .../commons/tests/unit/awsSdkUtils.test.ts | 4 +++ packages/commons/vitest.config.ts | 1 + .../logger/tests/e2e/advancedUses.test.ts | 4 +++ 5 files changed, 74 insertions(+) diff --git a/packages/commons/src/Utility.ts b/packages/commons/src/Utility.ts index 2932785e0d..89f1dbd03d 100644 --- a/packages/commons/src/Utility.ts +++ b/packages/commons/src/Utility.ts @@ -51,15 +51,46 @@ * ``` */ export class Utility { + readonly #initializationType: + | 'unknown' + | 'on-demand' + | 'provisioned-concurrency'; protected coldStart = true; protected readonly defaultServiceName: string = 'service_undefined'; + public constructor() { + this.#initializationType = this.getInitializationType(); + if (this.#initializationType !== 'on-demand') { + this.coldStart = false; + } + } + + /** + * Get the value of the `AWS_LAMBDA_INITIALIZATION_TYPE` environment variable. + */ + protected getInitializationType(): + | 'unknown' + | 'on-demand' + | 'provisioned-concurrency' { + const envVarValue = process.env.AWS_LAMBDA_INITIALIZATION_TYPE?.trim(); + if (envVarValue === 'on-demand') { + return 'on-demand'; + } + if (envVarValue === 'provisioned-concurrency') { + return 'provisioned-concurrency'; + } + return 'unknown'; + } + /** * Get the cold start status of the current execution environment. * * The method also flips the cold start status to `false` after the first invocation. */ protected getColdStart(): boolean { + if (this.#initializationType !== 'on-demand') { + return false; + } if (this.coldStart) { this.coldStart = false; diff --git a/packages/commons/tests/unit/Utility.test.ts b/packages/commons/tests/unit/Utility.test.ts index 16f88c3f38..15b3309538 100644 --- a/packages/commons/tests/unit/Utility.test.ts +++ b/packages/commons/tests/unit/Utility.test.ts @@ -15,6 +15,12 @@ describe('Class: Utility', () => { public validateServiceName(serviceName: string): boolean { return this.isValidServiceName(serviceName); } + public getInitializationType(): + | 'unknown' + | 'on-demand' + | 'provisioned-concurrency' { + return super.getInitializationType(); + } } it('returns the correct cold start value', () => { @@ -27,6 +33,15 @@ describe('Class: Utility', () => { expect(utility.dummyMethod()).toBe(false); }); + it('returns the correct cold start value when provisioned concurrency is used', () => { + // Prepare + process.env.AWS_LAMBDA_INITIALIZATION_TYPE = 'provisioned-concurrency'; + const utility = new TestUtility(); + + // Act & Assess + expect(utility.dummyMethod()).toBe(false); + }); + it('flips the cold start value', () => { // Prepare const utility = new TestUtility(); @@ -54,4 +69,23 @@ describe('Class: Utility', () => { expect(utility.validateServiceName('serverlessAirline')).toBe(true); expect(utility.validateServiceName('')).toBe(false); }); + + it.each([ + { value: 'on-demand', expected: 'on-demand' }, + { value: 'provisioned-concurrency', expected: 'provisioned-concurrency' }, + { value: '', expected: 'unknown' }, + ])( + 'returns the correct initialization type ($value)', + ({ value, expected }) => { + // Prepare + process.env.AWS_LAMBDA_INITIALIZATION_TYPE = value; + const utility = new TestUtility(); + + // Act + const initializationType = utility.getInitializationType(); + + // Assess + expect(initializationType).toBe(expected); + } + ); }); diff --git a/packages/commons/tests/unit/awsSdkUtils.test.ts b/packages/commons/tests/unit/awsSdkUtils.test.ts index c8f233e355..7af7af9d3a 100644 --- a/packages/commons/tests/unit/awsSdkUtils.test.ts +++ b/packages/commons/tests/unit/awsSdkUtils.test.ts @@ -6,6 +6,10 @@ import { PT_VERSION as version, } from '../../src/index.js'; +vi.hoisted(() => { + process.env.AWS_EXECUTION_ENV = ''; +}); + describe('Helpers: awsSdk', () => { describe('Function: userAgentMiddleware', () => { beforeAll(() => { diff --git a/packages/commons/vitest.config.ts b/packages/commons/vitest.config.ts index d5aa737c68..9f1196ef1f 100644 --- a/packages/commons/vitest.config.ts +++ b/packages/commons/vitest.config.ts @@ -3,5 +3,6 @@ import { defineProject } from 'vitest/config'; export default defineProject({ test: { environment: 'node', + setupFiles: ['../testing/src/setupEnv.ts'], }, }); diff --git a/packages/logger/tests/e2e/advancedUses.test.ts b/packages/logger/tests/e2e/advancedUses.test.ts index c41aaec409..6682042226 100644 --- a/packages/logger/tests/e2e/advancedUses.test.ts +++ b/packages/logger/tests/e2e/advancedUses.test.ts @@ -12,6 +12,7 @@ import { RESOURCE_NAME_PREFIX, STACK_OUTPUT_LOG_GROUP } from './constants.js'; * In this e2e test for Logger, we test a number of advanced use cases: * - Log buffering enabled with flush on error (both manually on logger.error and automatically on uncaught error) * - Correlation ID injection (both manually and automatically) + * - Cold start detection for provisioned concurrency (always false) * * The test is split into three cases: * - Manual instrumentation @@ -127,6 +128,7 @@ describe('Logger E2E - Advanced uses', () => { expect.objectContaining({ level: 'INFO', message: 'an info log', + cold_start: false, correlation_id: correlationId, }) ); @@ -136,6 +138,7 @@ describe('Logger E2E - Advanced uses', () => { expect.objectContaining({ level: 'DEBUG', message: 'a buffered debug log', + cold_start: false, correlation_id: correlationId, }) ); @@ -145,6 +148,7 @@ describe('Logger E2E - Advanced uses', () => { expect.objectContaining({ level: 'ERROR', message: 'Uncaught error detected, flushing log buffer before exit', + cold_start: false, correlation_id: correlationId, error: expect.objectContaining({ name: 'Error', From 51a3410be8502496362d5ed13a64fe55691604ba Mon Sep 17 00:00:00 2001 From: Andrea Amorosi Date: Wed, 19 Mar 2025 14:53:25 +0100 Subject: [PATCH 28/56] fix(parser): ddb base schema + other exports (#3741) Co-authored-by: Alexander Schueren --- docs/utilities/parser.md | 30 +- examples/snippets/parser/envelopeDecorator.ts | 2 +- examples/snippets/parser/envelopeMiddy.ts | 26 +- examples/snippets/parser/extend.ts | 2 +- .../parser/extendDynamoDBStreamSchema.ts | 3 +- .../parser/handlerSafeParseDecorator.ts | 2 +- examples/snippets/parser/manual.ts | 4 +- examples/snippets/parser/manualSafeParse.ts | 4 +- examples/snippets/parser/middy.ts | 24 +- .../snippets/parser/safeParseDecorator.ts | 13 +- examples/snippets/parser/safeParseMiddy.ts | 37 +-- examples/snippets/parser/unitTestDecorator.ts | 1 + examples/snippets/parser/unitTestSafeParse.ts | 1 + packages/parser/package.json | 264 +++++------------- packages/parser/src/envelopes/api-gateway.ts | 2 +- .../parser/src/envelopes/api-gatewayv2.ts | 2 +- .../src/{helpers.ts => helpers/index.ts} | 3 - .../src/middleware/{parser.ts => index.ts} | 0 .../src/schemas/{apigw.ts => api-gateway.ts} | 0 .../schemas/{apigwv2.ts => api-gatewayv2.ts} | 0 packages/parser/src/schemas/dynamodb.ts | 1 + packages/parser/src/schemas/index.ts | 4 +- packages/parser/src/schemas/lambda.ts | 2 +- packages/parser/src/schemas/s3.ts | 2 +- .../tests/unit/envelopes/api-gateway.test.ts | 2 +- .../unit/envelopes/api-gatewayv2.test.ts | 2 +- .../tests/unit/envelopes/cloudwatch.test.ts | 2 +- .../parser/tests/unit/envelopes/kafka.test.ts | 2 +- .../unit/envelopes/kinesis-firehose.test.ts | 2 +- .../tests/unit/envelopes/sns-sqs.test.ts | 2 +- .../parser/tests/unit/envelopes/sns.test.ts | 2 +- .../parser/tests/unit/envelopes/sqs.test.ts | 2 +- .../tests/unit/envelopes/vpc-lattice.test.ts | 2 +- .../unit/envelopes/vpc-latticev2.test.ts | 2 +- packages/parser/tests/unit/helpers.test.ts | 2 +- .../parser/tests/unit/parser.middy.test.ts | 2 +- packages/parser/typedoc.json | 4 +- 37 files changed, 157 insertions(+), 300 deletions(-) rename packages/parser/src/{helpers.ts => helpers/index.ts} (95%) rename packages/parser/src/middleware/{parser.ts => index.ts} (100%) rename packages/parser/src/schemas/{apigw.ts => api-gateway.ts} (100%) rename packages/parser/src/schemas/{apigwv2.ts => api-gatewayv2.ts} (100%) diff --git a/docs/utilities/parser.md b/docs/utilities/parser.md index e4dcd5dfdd..da315c47c8 100644 --- a/docs/utilities/parser.md +++ b/docs/utilities/parser.md @@ -44,7 +44,7 @@ Both are also able to parse either an object or JSON string as an input. Be cautious when using multiple decorators that expect event to have a specific structure, the order of evaluation for decorators is from bottom to top. === "Middy middleware" - ```typescript hl_lines="34" + ```typescript hl_lines="22" --8<-- "examples/snippets/parser/middy.ts" ``` @@ -157,7 +157,7 @@ If you want to extend a schema and transform a JSON stringified payload to an ob If you want to parse a DynamoDB stream event with unmarshalling, you can use the helper function `DynamoDBMarshalled`: === "DynamoDBStreamSchema with DynamoDBMarshalled" - ```typescript hl_lines="17" + ```typescript hl_lines="18" --8<-- "examples/snippets/parser/extendDynamoDBStreamSchema.ts" ``` @@ -180,12 +180,12 @@ Envelopes can be used via envelope parameter available in middy and decorator. Here's an example of parsing a custom schema in an event coming from EventBridge, where all you want is what's inside the detail key. === "Middy middleware" - ```typescript hl_lines="5 36" + ```typescript hl_lines="23" --8<-- "examples/snippets/parser/envelopeMiddy.ts" ``` === "Decorator" - ```typescript hl_lines="5 26 30" + ```typescript hl_lines="26" --8<-- "examples/snippets/parser/envelopeDecorator.ts" ``` @@ -230,26 +230,24 @@ The `ParsedResult` object will have `success`, `data`, or `error` and `original If the parsing is successful, the `data` field will contain the parsed event, otherwise you can access the `error` field and the `originalEvent` to handle the error and recover the original event. === "Middy middleware" - ```typescript hl_lines="32 35 38 39 44" + ```typescript hl_lines="23 28 32-33" --8<-- "examples/snippets/parser/safeParseMiddy.ts" ``` 1. Use `safeParse` option to parse the event without throwing an error - 2. Check if the result is successful or not and handle the error accordingly - 3. Use `data` to access the parsed event - 4. Use `error` to handle the error message - 5. Use `originalEvent` to get the original event and recover + 2. Use `data` to access the parsed event when successful + 3. Use `error` to handle the error message + 4. Use `originalEvent` to get the original event and recover === "Decorator" - ```typescript hl_lines="29 35 37 40 41" + ```typescript hl_lines="33 41 45-46" --8<-- "examples/snippets/parser/safeParseDecorator.ts" ``` 1. Use `safeParse` option to parse the event without throwing an error - 2. Check if the result is successful or not and handle the error accordingly - 3. Use `data` to access the parsed event - 4. Use `error` to handle the error message - 5. Use `originalEvent` to get the original event and recover + 2. Use `data` to access the parsed event when successful + 3. Use `error` to handle the error message + 4. Use `originalEvent` to get the original event and recover ## Manual parsing @@ -316,7 +314,7 @@ If you are you use middy middleware, you don't need to do this. === "handlerDecorator.test.ts" - ```typescript hl_lines="26" + ```typescript hl_lines="27" --8<-- "examples/snippets/parser/unitTestDecorator.ts" ``` @@ -338,7 +336,7 @@ This also works when using `safeParse` option. === "handlerSafeParse.test.ts" - ```typescript hl_lines="21-29 35 45" + ```typescript hl_lines="21-30 36 46" --8<-- "examples/snippets/parser/unitTestSafeParse.ts" ``` diff --git a/examples/snippets/parser/envelopeDecorator.ts b/examples/snippets/parser/envelopeDecorator.ts index 5b04d80488..5fd09d23e1 100644 --- a/examples/snippets/parser/envelopeDecorator.ts +++ b/examples/snippets/parser/envelopeDecorator.ts @@ -1,7 +1,7 @@ import type { LambdaInterface } from '@aws-lambda-powertools/commons/types'; import { Logger } from '@aws-lambda-powertools/logger'; import { parser } from '@aws-lambda-powertools/parser'; -import { EventBridgeEnvelope } from '@aws-lambda-powertools/parser/envelopes'; +import { EventBridgeEnvelope } from '@aws-lambda-powertools/parser/envelopes/eventbridge'; import type { Context } from 'aws-lambda'; import { z } from 'zod'; diff --git a/examples/snippets/parser/envelopeMiddy.ts b/examples/snippets/parser/envelopeMiddy.ts index 0a6034970f..0a20ad1132 100644 --- a/examples/snippets/parser/envelopeMiddy.ts +++ b/examples/snippets/parser/envelopeMiddy.ts @@ -1,8 +1,7 @@ import { Logger } from '@aws-lambda-powertools/logger'; -import { EventBridgeEnvelope } from '@aws-lambda-powertools/parser/envelopes'; +import { EventBridgeEnvelope } from '@aws-lambda-powertools/parser/envelopes/eventbridge'; import { parser } from '@aws-lambda-powertools/parser/middleware'; import middy from '@middy/core'; -import type { Context } from 'aws-lambda'; import { z } from 'zod'; const logger = new Logger(); @@ -20,18 +19,11 @@ const orderSchema = z.object({ optionalField: z.string().optional(), }); -type Order = z.infer; - -const lambdaHandler = async ( - event: Order, - _context: Context -): Promise => { - for (const item of event.items) { - // item is parsed as OrderItem - logger.info('Processing item', { item }); - } -}; - -export const handler = middy(lambdaHandler).use( - parser({ schema: orderSchema, envelope: EventBridgeEnvelope }) -); +export const handler = middy() + .use(parser({ schema: orderSchema, envelope: EventBridgeEnvelope })) + .handler(async (event): Promise => { + for (const item of event.items) { + // item is parsed as OrderItem + logger.info('Processing item', { item }); + } + }); diff --git a/examples/snippets/parser/extend.ts b/examples/snippets/parser/extend.ts index 8dca184aa4..d49cf406dd 100644 --- a/examples/snippets/parser/extend.ts +++ b/examples/snippets/parser/extend.ts @@ -1,7 +1,7 @@ import type { LambdaInterface } from '@aws-lambda-powertools/commons/types'; import { Logger } from '@aws-lambda-powertools/logger'; import { parser } from '@aws-lambda-powertools/parser'; -import { EventBridgeSchema } from '@aws-lambda-powertools/parser/schemas'; +import { EventBridgeSchema } from '@aws-lambda-powertools/parser/schemas/eventbridge'; import type { Context } from 'aws-lambda'; import { z } from 'zod'; diff --git a/examples/snippets/parser/extendDynamoDBStreamSchema.ts b/examples/snippets/parser/extendDynamoDBStreamSchema.ts index 86639f5cfb..30fc8abe2e 100644 --- a/examples/snippets/parser/extendDynamoDBStreamSchema.ts +++ b/examples/snippets/parser/extendDynamoDBStreamSchema.ts @@ -1,5 +1,6 @@ import { DynamoDBMarshalled } from '@aws-lambda-powertools/parser/helpers/dynamodb'; import { + DynamoDBStreamChangeRecordBase, DynamoDBStreamRecord, DynamoDBStreamSchema, } from '@aws-lambda-powertools/parser/schemas/dynamodb'; @@ -13,7 +14,7 @@ const customSchema = z.object({ const extendedSchema = DynamoDBStreamSchema.extend({ Records: z.array( DynamoDBStreamRecord.extend({ - dynamodb: z.object({ + dynamodb: DynamoDBStreamChangeRecordBase.extend({ NewImage: DynamoDBMarshalled(customSchema).optional(), }), }) diff --git a/examples/snippets/parser/handlerSafeParseDecorator.ts b/examples/snippets/parser/handlerSafeParseDecorator.ts index ac081c5e66..2c6afbe2ce 100644 --- a/examples/snippets/parser/handlerSafeParseDecorator.ts +++ b/examples/snippets/parser/handlerSafeParseDecorator.ts @@ -1,7 +1,7 @@ import type { LambdaInterface } from '@aws-lambda-powertools/commons/types'; import { Logger } from '@aws-lambda-powertools/logger'; import { parser } from '@aws-lambda-powertools/parser'; -import { EventBridgeEnvelope } from '@aws-lambda-powertools/parser/envelopes'; +import { EventBridgeEnvelope } from '@aws-lambda-powertools/parser/envelopes/eventbridge'; import type { EventBridgeEvent, ParsedResult, diff --git a/examples/snippets/parser/manual.ts b/examples/snippets/parser/manual.ts index 839f62bafd..c0b33295d0 100644 --- a/examples/snippets/parser/manual.ts +++ b/examples/snippets/parser/manual.ts @@ -1,6 +1,6 @@ import { Logger } from '@aws-lambda-powertools/logger'; -import { EventBridgeEnvelope } from '@aws-lambda-powertools/parser/envelopes'; -import { EventBridgeSchema } from '@aws-lambda-powertools/parser/schemas'; +import { EventBridgeEnvelope } from '@aws-lambda-powertools/parser/envelopes/eventbridge'; +import { EventBridgeSchema } from '@aws-lambda-powertools/parser/schemas/eventbridge'; import type { EventBridgeEvent } from '@aws-lambda-powertools/parser/types'; import type { Context } from 'aws-lambda'; import { z } from 'zod'; diff --git a/examples/snippets/parser/manualSafeParse.ts b/examples/snippets/parser/manualSafeParse.ts index 63dc0ac204..5af37162da 100644 --- a/examples/snippets/parser/manualSafeParse.ts +++ b/examples/snippets/parser/manualSafeParse.ts @@ -1,6 +1,6 @@ import { Logger } from '@aws-lambda-powertools/logger'; -import { EventBridgeEnvelope } from '@aws-lambda-powertools/parser/envelopes'; -import { EventBridgeSchema } from '@aws-lambda-powertools/parser/schemas'; +import { EventBridgeEnvelope } from '@aws-lambda-powertools/parser/envelopes/eventbridge'; +import { EventBridgeSchema } from '@aws-lambda-powertools/parser/schemas/eventbridge'; import type { EventBridgeEvent } from '@aws-lambda-powertools/parser/types'; import type { Context } from 'aws-lambda'; import { z } from 'zod'; diff --git a/examples/snippets/parser/middy.ts b/examples/snippets/parser/middy.ts index 763fa8246a..e8c19fb3cf 100644 --- a/examples/snippets/parser/middy.ts +++ b/examples/snippets/parser/middy.ts @@ -1,7 +1,6 @@ import { Logger } from '@aws-lambda-powertools/logger'; import { parser } from '@aws-lambda-powertools/parser/middleware'; import middy from '@middy/core'; -import type { Context } from 'aws-lambda'; import { z } from 'zod'; const logger = new Logger(); @@ -19,18 +18,11 @@ const orderSchema = z.object({ optionalField: z.string().optional(), }); -type Order = z.infer; - -const lambdaHandler = async ( - event: Order, - _context: Context -): Promise => { - for (const item of event.items) { - // item is parsed as OrderItem - logger.info('Processing item', { item }); - } -}; - -export const handler = middy(lambdaHandler).use( - parser({ schema: orderSchema }) -); +export const handler = middy() + .use(parser({ schema: orderSchema })) + .handler(async (event): Promise => { + for (const item of event.items) { + // item is parsed as OrderItem + logger.info('Processing item', { item }); + } + }); diff --git a/examples/snippets/parser/safeParseDecorator.ts b/examples/snippets/parser/safeParseDecorator.ts index a9e466be92..67caf35c6e 100644 --- a/examples/snippets/parser/safeParseDecorator.ts +++ b/examples/snippets/parser/safeParseDecorator.ts @@ -1,7 +1,7 @@ import type { LambdaInterface } from '@aws-lambda-powertools/commons/types'; import { Logger } from '@aws-lambda-powertools/logger'; import { parser } from '@aws-lambda-powertools/parser'; -import { EventBridgeEnvelope } from '@aws-lambda-powertools/parser/envelopes'; +import { EventBridgeEnvelope } from '@aws-lambda-powertools/parser/envelopes/eventbridge'; import type { EventBridgeEvent, ParsedResult, @@ -30,20 +30,19 @@ class Lambda implements LambdaInterface { @parser({ schema: orderSchema, envelope: EventBridgeEnvelope, - safeParse: true, - }) // (1)! + safeParse: true, // (1)! + }) public async handler( event: ParsedResult, _context: Context ): Promise { if (event.success) { - // (2)! for (const item of event.data.items) { - logger.info('Processing item', { item }); // (3)! + logger.info('Processing item', { item }); // (2)! } } else { - logger.error('Failed to parse event', event.error); // (4)! - logger.error('Original event is: ', event.originalEvent); // (5)! + logger.error('Failed to parse event', { error: event.error }); // (3)! + logger.error('Original event is ', { original: event.originalEvent }); // (4)! } } } diff --git a/examples/snippets/parser/safeParseMiddy.ts b/examples/snippets/parser/safeParseMiddy.ts index d73bc49096..e7efb5cb2b 100644 --- a/examples/snippets/parser/safeParseMiddy.ts +++ b/examples/snippets/parser/safeParseMiddy.ts @@ -1,11 +1,6 @@ import { Logger } from '@aws-lambda-powertools/logger'; import { parser } from '@aws-lambda-powertools/parser/middleware'; -import type { - EventBridgeEvent, - ParsedResult, -} from '@aws-lambda-powertools/parser/types'; import middy from '@middy/core'; -import type { Context } from 'aws-lambda'; import { z } from 'zod'; const logger = new Logger(); @@ -23,23 +18,17 @@ const orderSchema = z.object({ optionalField: z.string().optional(), }); -type Order = z.infer; - -const lambdaHandler = async ( - event: ParsedResult, - _context: Context -): Promise => { - if (event.success) { - // (2)! - for (const item of event.data.items) { - logger.info('Processing item', { item }); // (3)! +export const handler = middy() + .use( + parser({ schema: orderSchema, safeParse: true }) // (1)! + ) + .handler(async (event): Promise => { + if (event.success) { + for (const item of event.data.items) { + logger.info('Processing item', { item }); // (2)! + } + } else { + logger.error('Error parsing event', { event: event.error }); // (3)! + logger.error('Original event', { event: event.originalEvent }); // (4)! } - } else { - logger.error('Error parsing event', { event: event.error }); // (4)! - logger.error('Original event', { event: event.originalEvent }); // (5)! - } -}; - -export const handler = middy(lambdaHandler).use( - parser({ schema: orderSchema, safeParse: true }) // (1)! -); + }); diff --git a/examples/snippets/parser/unitTestDecorator.ts b/examples/snippets/parser/unitTestDecorator.ts index 3e327a6224..5653cabd3c 100644 --- a/examples/snippets/parser/unitTestDecorator.ts +++ b/examples/snippets/parser/unitTestDecorator.ts @@ -1,4 +1,5 @@ import type { Context } from 'aws-lambda'; +import { describe, expect, it } from 'vitest'; import { handler } from './decorator.js'; import type { Order } from './schema.js'; diff --git a/examples/snippets/parser/unitTestSafeParse.ts b/examples/snippets/parser/unitTestSafeParse.ts index bc2e80a220..cad6f08006 100644 --- a/examples/snippets/parser/unitTestSafeParse.ts +++ b/examples/snippets/parser/unitTestSafeParse.ts @@ -3,6 +3,7 @@ import type { ParsedResult, } from '@aws-lambda-powertools/parser/types'; import type { Context } from 'aws-lambda'; +import { describe, expect, it } from 'vitest'; import { handler } from './safeParseDecorator.js'; import type { Order } from './schema.js'; diff --git a/packages/parser/package.json b/packages/parser/package.json index 9619e754a3..a613d41369 100644 --- a/packages/parser/package.json +++ b/packages/parser/package.json @@ -41,208 +41,94 @@ } }, "./middleware": { - "require": "./lib/cjs/middleware/parser.js", - "import": "./lib/esm/middleware/parser.js" + "require": { + "types": "./lib/cjs/middleware/index.d.ts", + "default": "./lib/cjs/middleware/index.js" + }, + "import": { + "types": "./lib/esm/middleware/index.d.ts", + "default": "./lib/esm/middleware/index.js" + } }, "./schemas": { - "require": "./lib/cjs/schemas/index.js", - "import": "./lib/esm/schemas/index.js" - }, - "./schemas/alb": { - "require": "./lib/cjs/schemas/alb.js", - "import": "./lib/esm/schemas/alb.js" - }, - "./schemas/api-gateway": { - "require": "./lib/cjs/schemas/apigw.js", - "import": "./lib/esm/schemas/apigw.js" - }, - "./schemas/api-gatewayv2": { - "require": "./lib/cjs/schemas/apigwv2.js", - "import": "./lib/esm/schemas/apigwv2.js" - }, - "./schemas/appsync": { - "require": "./lib/cjs/schemas/appsync.js", - "import": "./lib/esm/schemas/appsync.js" - }, - "./schemas/cloudformation-custom-resources": { - "require": "./lib/cjs/schemas/cloudformation-custom-resources.js", - "import": "./lib/esm/schemas/cloudformation-custom-resources.js" - }, - "./schemas/cloudwatch": { - "require": "./lib/cjs/schemas/cloudwatch.js", - "import": "./lib/esm/schemas/cloudwatch.js" - }, - "./schemas/dynamodb": { - "require": "./lib/cjs/schemas/dynamodb.js", - "import": "./lib/esm/schemas/dynamodb.js" - }, - "./schemas/eventbridge": { - "require": "./lib/cjs/schemas/eventbridge.js", - "import": "./lib/esm/schemas/eventbridge.js" - }, - "./schemas/kafka": { - "require": "./lib/cjs/schemas/kafka.js", - "import": "./lib/esm/schemas/kafka.js" - }, - "./schemas/kinesis": { - "require": "./lib/cjs/schemas/kinesis.js", - "import": "./lib/esm/schemas/kinesis.js" - }, - "./schemas/kinesis-firehose": { - "require": "./lib/cjs/schemas/kinesis-firehose.js", - "import": "./lib/esm/schemas/kinesis-firehose.js" - }, - "./schemas/lambda": { - "require": "./lib/cjs/schemas/lambda.js", - "import": "./lib/esm/schemas/lambda.js" - }, - "./schemas/s3": { - "require": "./lib/cjs/schemas/s3.js", - "import": "./lib/esm/schemas/s3.js" - }, - "./schemas/ses": { - "require": "./lib/cjs/schemas/ses.js", - "import": "./lib/esm/schemas/ses.js" - }, - "./schemas/sns": { - "require": "./lib/cjs/schemas/sns.js", - "import": "./lib/esm/schemas/sns.js" - }, - "./schemas/sqs": { - "require": "./lib/cjs/schemas/sqs.js", - "import": "./lib/esm/schemas/sqs.js" - }, - "./schemas/transfer-family": { - "require": "./lib/cjs/schemas/transfer-family.js", - "import": "./lib/esm/schemas/transfer-family.js" - }, - "./schemas/vpc-lattice": { - "require": "./lib/cjs/schemas/vpc-lattice.js", - "import": "./lib/esm/schemas/vpc-lattice.js" + "require": { + "types": "./lib/cjs/schemas/index.d.ts", + "default": "./lib/cjs/schemas/index.js" + }, + "import": { + "types": "./lib/esm/schemas/index.d.ts", + "default": "./lib/esm/schemas/index.js" + } }, - "./schemas/vpc-latticev2": { - "require": "./lib/cjs/schemas/vpc-latticev2.js", - "import": "./lib/esm/schemas/vpc-latticev2.js" + "./schemas/*": { + "require": { + "types": "./lib/cjs/schemas/*.d.ts", + "default": "./lib/cjs/schemas/*.js" + }, + "import": { + "types": "./lib/esm/schemas/*.d.ts", + "default": "./lib/esm/schemas/*.js" + } }, "./envelopes": { - "require": "./lib/cjs/envelopes/index.js", - "import": "./lib/esm/envelopes/index.js" + "require": { + "types": "./lib/cjs/envelopes/index.d.ts", + "default": "./lib/cjs/envelopes/index.js" + }, + "import": { + "types": "./lib/esm/envelopes/index.d.ts", + "default": "./lib/esm/envelopes/index.js" + } }, "./envelopes/*": { - "require": "./lib/cjs/envelopes/*.js", - "import": "./lib/esm/envelopes/*.js" + "require": { + "types": "./lib/cjs/envelopes/*.d.ts", + "default": "./lib/cjs/envelopes/*.js" + }, + "import": { + "types": "./lib/esm/envelopes/*.d.ts", + "default": "./lib/esm/envelopes/*.js" + } }, "./helpers": { - "require": "./lib/cjs/helpers.js", - "import": "./lib/esm/helpers.js" + "require": { + "types": "./lib/cjs/helpers/index.d.ts", + "default": "./lib/cjs/helpers/index.js" + }, + "import": { + "types": "./lib/esm/helpers/index.d.ts", + "default": "./lib/esm/helpers/index.js" + } }, "./helpers/dynamodb": { - "require": "./lib/cjs/helpers/dynamodb.js", - "import": "./lib/esm/helpers/dynamodb.js" + "require": { + "types": "./lib/cjs/helpers/dynamodb.d.ts", + "default": "./lib/cjs/helpers/dynamodb.js" + }, + "import": { + "types": "./lib/esm/helpers/dynamodb.d.ts", + "default": "./lib/esm/helpers/dynamodb.js" + } }, "./types": { - "require": "./lib/cjs/types/index.js", - "import": "./lib/esm/types/index.js" - } - }, - "typesVersions": { - "*": { - "types": [ - "./lib/cjs/types/index.d.ts", - "./lib/esm/types/index.d.ts" - ], - "middleware": [ - "./lib/cjs/middleware/parser.d.ts", - "./lib/esm/middleware/parser.d.ts" - ], - "schemas": [ - "./lib/cjs/schemas/index.d.ts", - "./lib/esm/schemas/index.d.ts" - ], - "schemas/alb": [ - "./lib/cjs/schemas/alb.d.ts", - "./lib/esm/schemas/alb.d.ts" - ], - "schemas/api-gateway": [ - "./lib/cjs/schemas/apigw.d.ts", - "./lib/esm/schemas/apigw.d.ts" - ], - "schemas/api-gatewayv2": [ - "./lib/cjs/schemas/apigwv2.d.ts", - "./lib/esm/schemas/apigwv2.d.ts" - ], - "schemas/appsync": [ - "./lib/cjs/schemas/appsync.d.ts", - "./lib/esm/schemas/appsync.d.ts" - ], - "schemas/cloudformation-custom-resources": [ - "./lib/cjs/schemas/cloudformation-custom-resources.d.ts", - "./lib/esm/schemas/cloudformation-custom-resources.d.ts" - ], - "schemas/cloudwatch": [ - "./lib/cjs/schemas/cloudwatch.d.ts", - "./lib/esm/schemas/cloudwatch.d.ts" - ], - "schemas/dynamodb": [ - "./lib/cjs/schemas/dynamodb.d.ts", - "./lib/esm/schemas/dynamodb.d.ts" - ], - "schemas/eventbridge": [ - "./lib/cjs/schemas/eventbridge.d.ts", - "./lib/esm/schemas/eventbridge.d.ts" - ], - "schemas/kafka": [ - "./lib/cjs/schemas/kafka.d.ts", - "./lib/esm/schemas/kafka.d.ts" - ], - "schemas/kinesis": [ - "./lib/cjs/schemas/kinesis.d.ts", - "./lib/esm/schemas/kinesis.d.ts" - ], - "schemas/kinesis-firehose": [ - "./lib/cjs/schemas/kinesis-firehose.d.ts", - "./lib/esm/schemas/kinesis-firehose.d.ts" - ], - "schemas/lambda": [ - "./lib/cjs/schemas/lambda.d.ts", - "./lib/esm/schemas/lambda.d.ts" - ], - "schemas/s3": [ - "./lib/cjs/schemas/s3.d.ts", - "./lib/esm/schemas/s3.d.ts" - ], - "schemas/ses": [ - "./lib/cjs/schemas/ses.d.ts", - "./lib/esm/schemas/ses.d.ts" - ], - "schemas/sns": [ - "./lib/cjs/schemas/sns.d.ts", - "./lib/esm/schemas/sns.d.ts" - ], - "schemas/sqs": [ - "./lib/cjs/schemas/sqs.d.ts", - "./lib/esm/schemas/sqs.d.ts" - ], - "schemas/vpc-lattice": [ - "./lib/cjs/schemas/vpc-lattice.d.ts", - "./lib/esm/schemas/vpc-lattice.d.ts" - ], - "schemas/vpc-latticev2": [ - "./lib/cjs/schemas/vpc-latticev2.d.ts", - "./lib/esm/schemas/vpc-latticev2.d.ts" - ], - "envelopes": [ - "./lib/cjs/envelopes/index.d.ts", - "./lib/esm/envelopes/index.d.ts" - ], - "envelopes/*": [ - "./lib/cjs/envelopes/*.d.ts", - "./lib/esm/envelopes/*.d.ts" - ], - "helpers": [ - "./lib/cjs/helpers.d.ts", - "./lib/esm/helpers.d.ts" - ] + "require": { + "types": "./lib/cjs/types/index.d.ts", + "default": "./lib/cjs/types/index.js" + }, + "import": { + "types": "./lib/esm/types/index.d.ts", + "default": "./lib/esm/types/index.js" + } + }, + "./errors": { + "require": { + "types": "./lib/cjs/errors.d.ts", + "default": "./lib/cjs/errors.js" + }, + "import": { + "types": "./lib/esm/errors.d.ts", + "default": "./lib/esm/errors.js" + } } }, "main": "./lib/cjs/index.js", diff --git a/packages/parser/src/envelopes/api-gateway.ts b/packages/parser/src/envelopes/api-gateway.ts index 2ff9d3b8ab..0abaecc6d8 100644 --- a/packages/parser/src/envelopes/api-gateway.ts +++ b/packages/parser/src/envelopes/api-gateway.ts @@ -1,6 +1,6 @@ import type { ZodSchema, z } from 'zod'; import { ParseError } from '../errors.js'; -import { APIGatewayProxyEventSchema } from '../schemas/apigw.js'; +import { APIGatewayProxyEventSchema } from '../schemas/api-gateway.js'; import type { ParsedResult } from '../types/parser.js'; import { envelopeDiscriminator } from './envelope.js'; diff --git a/packages/parser/src/envelopes/api-gatewayv2.ts b/packages/parser/src/envelopes/api-gatewayv2.ts index 486fb74593..408bcde42c 100644 --- a/packages/parser/src/envelopes/api-gatewayv2.ts +++ b/packages/parser/src/envelopes/api-gatewayv2.ts @@ -1,6 +1,6 @@ import type { ZodSchema, z } from 'zod'; import { ParseError } from '../errors.js'; -import { APIGatewayProxyEventV2Schema } from '../schemas/apigwv2.js'; +import { APIGatewayProxyEventV2Schema } from '../schemas/api-gatewayv2.js'; import type { ParsedResult } from '../types/index.js'; import { envelopeDiscriminator } from './envelope.js'; diff --git a/packages/parser/src/helpers.ts b/packages/parser/src/helpers/index.ts similarity index 95% rename from packages/parser/src/helpers.ts rename to packages/parser/src/helpers/index.ts index 10915620d7..f24424d17b 100644 --- a/packages/parser/src/helpers.ts +++ b/packages/parser/src/helpers/index.ts @@ -1,7 +1,4 @@ import { type ZodTypeAny, z } from 'zod'; -/** - * @typedef {import('../schemas/alb').AlbSchema} AlbSchema - */ /** * A helper function to parse a JSON string and validate it against a schema. diff --git a/packages/parser/src/middleware/parser.ts b/packages/parser/src/middleware/index.ts similarity index 100% rename from packages/parser/src/middleware/parser.ts rename to packages/parser/src/middleware/index.ts diff --git a/packages/parser/src/schemas/apigw.ts b/packages/parser/src/schemas/api-gateway.ts similarity index 100% rename from packages/parser/src/schemas/apigw.ts rename to packages/parser/src/schemas/api-gateway.ts diff --git a/packages/parser/src/schemas/apigwv2.ts b/packages/parser/src/schemas/api-gatewayv2.ts similarity index 100% rename from packages/parser/src/schemas/apigwv2.ts rename to packages/parser/src/schemas/api-gatewayv2.ts diff --git a/packages/parser/src/schemas/dynamodb.ts b/packages/parser/src/schemas/dynamodb.ts index ee361b783b..00170ac672 100644 --- a/packages/parser/src/schemas/dynamodb.ts +++ b/packages/parser/src/schemas/dynamodb.ts @@ -230,5 +230,6 @@ export { DynamoDBStreamSchema, DynamoDBStreamRecord, DynamoDBStreamChangeRecord, + DynamoDBStreamChangeRecordBase, UserIdentity, }; diff --git a/packages/parser/src/schemas/index.ts b/packages/parser/src/schemas/index.ts index 18f3a35424..eedaaeb800 100644 --- a/packages/parser/src/schemas/index.ts +++ b/packages/parser/src/schemas/index.ts @@ -4,7 +4,7 @@ export { APIGatewayRequestAuthorizerEventSchema, APIGatewayTokenAuthorizerEventSchema, APIGatewayEventRequestContextSchema, -} from './apigw.js'; +} from './api-gateway.js'; export { AppSyncResolverSchema, AppSyncBatchResolverSchema, @@ -14,7 +14,7 @@ export { APIGatewayRequestAuthorizerEventV2Schema, APIGatewayRequestAuthorizerV2Schema, APIGatewayRequestContextV2Schema, -} from './apigwv2.js'; +} from './api-gatewayv2.js'; export { CloudFormationCustomResourceCreateSchema, CloudFormationCustomResourceDeleteSchema, diff --git a/packages/parser/src/schemas/lambda.ts b/packages/parser/src/schemas/lambda.ts index 0530f56d67..e5fe679329 100644 --- a/packages/parser/src/schemas/lambda.ts +++ b/packages/parser/src/schemas/lambda.ts @@ -1,4 +1,4 @@ -import { APIGatewayProxyEventV2Schema } from './apigwv2.js'; +import { APIGatewayProxyEventV2Schema } from './api-gatewayv2.js'; /** * Zod schema for Lambda Function URL follows the API Gateway HTTP APIs Payload Format Version 2.0. diff --git a/packages/parser/src/schemas/s3.ts b/packages/parser/src/schemas/s3.ts index c7d0b78541..650712a78a 100644 --- a/packages/parser/src/schemas/s3.ts +++ b/packages/parser/src/schemas/s3.ts @@ -1,5 +1,5 @@ import { z } from 'zod'; -import { JSONStringified } from '../helpers.js'; +import { JSONStringified } from '../helpers/index.js'; import { EventBridgeSchema } from './eventbridge.js'; import { SqsRecordSchema } from './sqs.js'; diff --git a/packages/parser/tests/unit/envelopes/api-gateway.test.ts b/packages/parser/tests/unit/envelopes/api-gateway.test.ts index 275d9d7c1b..83c6b3b455 100644 --- a/packages/parser/tests/unit/envelopes/api-gateway.test.ts +++ b/packages/parser/tests/unit/envelopes/api-gateway.test.ts @@ -2,7 +2,7 @@ import { describe, expect, it } from 'vitest'; import { ZodError, z } from 'zod'; import { ApiGatewayEnvelope } from '../../../src/envelopes/index.js'; import { ParseError } from '../../../src/errors.js'; -import { JSONStringified } from '../../../src/helpers.js'; +import { JSONStringified } from '../../../src/helpers/index.js'; import type { APIGatewayProxyEvent } from '../../../src/types/schema.js'; import { getTestEvent, omit } from '../helpers/utils.js'; diff --git a/packages/parser/tests/unit/envelopes/api-gatewayv2.test.ts b/packages/parser/tests/unit/envelopes/api-gatewayv2.test.ts index 99f90373a0..4d03b6f2f1 100644 --- a/packages/parser/tests/unit/envelopes/api-gatewayv2.test.ts +++ b/packages/parser/tests/unit/envelopes/api-gatewayv2.test.ts @@ -2,7 +2,7 @@ import { describe, expect, it } from 'vitest'; import { ZodError, z } from 'zod'; import { ApiGatewayV2Envelope } from '../../../src/envelopes/api-gatewayv2.js'; import { ParseError } from '../../../src/errors.js'; -import { JSONStringified } from '../../../src/helpers.js'; +import { JSONStringified } from '../../../src/helpers/index.js'; import type { APIGatewayProxyEventV2 } from '../../../src/types/schema.js'; import { getTestEvent, omit } from '../helpers/utils.js'; diff --git a/packages/parser/tests/unit/envelopes/cloudwatch.test.ts b/packages/parser/tests/unit/envelopes/cloudwatch.test.ts index 4e617e088d..139666b57d 100644 --- a/packages/parser/tests/unit/envelopes/cloudwatch.test.ts +++ b/packages/parser/tests/unit/envelopes/cloudwatch.test.ts @@ -4,7 +4,7 @@ import { ZodError, z } from 'zod'; import { ParseError } from '../../../src'; import { CloudWatchEnvelope } from '../../../src/envelopes/cloudwatch.js'; import { DecompressError } from '../../../src/errors.js'; -import { JSONStringified } from '../../../src/helpers.js'; +import { JSONStringified } from '../../../src/helpers/index'; import { getTestEvent } from '../helpers/utils.js'; const decompressRecordToJSON = ( diff --git a/packages/parser/tests/unit/envelopes/kafka.test.ts b/packages/parser/tests/unit/envelopes/kafka.test.ts index 70df419978..284bd89ea9 100644 --- a/packages/parser/tests/unit/envelopes/kafka.test.ts +++ b/packages/parser/tests/unit/envelopes/kafka.test.ts @@ -2,7 +2,7 @@ import { describe, expect, it } from 'vitest'; import { ZodError, z } from 'zod'; import { KafkaEnvelope } from '../../../src/envelopes/kafka.js'; import { ParseError } from '../../../src/errors.js'; -import { JSONStringified } from '../../../src/helpers.js'; +import { JSONStringified } from '../../../src/helpers/index.js'; import { getTestEvent } from '../helpers/utils.js'; describe('Envelope: Kafka', () => { diff --git a/packages/parser/tests/unit/envelopes/kinesis-firehose.test.ts b/packages/parser/tests/unit/envelopes/kinesis-firehose.test.ts index bf5476c412..77e788d87c 100644 --- a/packages/parser/tests/unit/envelopes/kinesis-firehose.test.ts +++ b/packages/parser/tests/unit/envelopes/kinesis-firehose.test.ts @@ -2,7 +2,7 @@ import { describe, expect, it } from 'vitest'; import { ZodError, z } from 'zod'; import { KinesisFirehoseEnvelope } from '../../../src/envelopes/kinesis-firehose.js'; import { ParseError } from '../../../src/errors.js'; -import { JSONStringified } from '../../../src/helpers.js'; +import { JSONStringified } from '../../../src/helpers/index.js'; import type { KinesisFireHoseEvent, KinesisFireHoseSqsEvent, diff --git a/packages/parser/tests/unit/envelopes/sns-sqs.test.ts b/packages/parser/tests/unit/envelopes/sns-sqs.test.ts index 93c193a227..8d8c0d7e07 100644 --- a/packages/parser/tests/unit/envelopes/sns-sqs.test.ts +++ b/packages/parser/tests/unit/envelopes/sns-sqs.test.ts @@ -2,7 +2,7 @@ import { describe, expect, it } from 'vitest'; import { ZodError, z } from 'zod'; import { SnsSqsEnvelope } from '../../../src/envelopes/sns-sqs.js'; import { ParseError } from '../../../src/errors.js'; -import { JSONStringified } from '../../../src/helpers.js'; +import { JSONStringified } from '../../../src/helpers/index.js'; import type { SqsEvent } from '../../../src/types/schema.js'; import { getTestEvent } from '../helpers/utils.js'; diff --git a/packages/parser/tests/unit/envelopes/sns.test.ts b/packages/parser/tests/unit/envelopes/sns.test.ts index ee0793fd0c..7e4eee6552 100644 --- a/packages/parser/tests/unit/envelopes/sns.test.ts +++ b/packages/parser/tests/unit/envelopes/sns.test.ts @@ -2,7 +2,7 @@ import { describe, expect, it } from 'vitest'; import { ZodError, z } from 'zod'; import { SnsEnvelope } from '../../../src/envelopes/sns.js'; import { ParseError } from '../../../src/errors.js'; -import { JSONStringified } from '../../../src/helpers.js'; +import { JSONStringified } from '../../../src/helpers/index.js'; import type { SnsEvent } from '../../../src/types/schema.js'; import { getTestEvent } from '../helpers/utils.js'; diff --git a/packages/parser/tests/unit/envelopes/sqs.test.ts b/packages/parser/tests/unit/envelopes/sqs.test.ts index 97a0539709..99fd3cb35f 100644 --- a/packages/parser/tests/unit/envelopes/sqs.test.ts +++ b/packages/parser/tests/unit/envelopes/sqs.test.ts @@ -2,7 +2,7 @@ import { describe, expect, it } from 'vitest'; import { ZodError, z } from 'zod'; import { SqsEnvelope } from '../../../src/envelopes/sqs.js'; import { ParseError } from '../../../src/errors.js'; -import { JSONStringified } from '../../../src/helpers.js'; +import { JSONStringified } from '../../../src/helpers/index.js'; import type { SqsEvent } from '../../../src/types/schema.js'; import { getTestEvent } from '../helpers/utils.js'; diff --git a/packages/parser/tests/unit/envelopes/vpc-lattice.test.ts b/packages/parser/tests/unit/envelopes/vpc-lattice.test.ts index 9a77317d81..1980db49e9 100644 --- a/packages/parser/tests/unit/envelopes/vpc-lattice.test.ts +++ b/packages/parser/tests/unit/envelopes/vpc-lattice.test.ts @@ -2,7 +2,7 @@ import { describe, expect, it } from 'vitest'; import { ZodError, z } from 'zod'; import { VpcLatticeEnvelope } from '../../../src/envelopes/vpc-lattice.js'; import { ParseError } from '../../../src/errors.js'; -import { JSONStringified } from '../../../src/helpers.js'; +import { JSONStringified } from '../../../src/helpers/index.js'; import type { VpcLatticeEvent } from '../../../src/types/index.js'; import { getTestEvent, omit } from '../helpers/utils.js'; diff --git a/packages/parser/tests/unit/envelopes/vpc-latticev2.test.ts b/packages/parser/tests/unit/envelopes/vpc-latticev2.test.ts index a3097b741e..49f5ec81bf 100644 --- a/packages/parser/tests/unit/envelopes/vpc-latticev2.test.ts +++ b/packages/parser/tests/unit/envelopes/vpc-latticev2.test.ts @@ -2,7 +2,7 @@ import { describe, expect, it } from 'vitest'; import { ZodError, z } from 'zod'; import { VpcLatticeV2Envelope } from '../../../src/envelopes/vpc-latticev2.js'; import { ParseError } from '../../../src/errors.js'; -import { JSONStringified } from '../../../src/helpers.js'; +import { JSONStringified } from '../../../src/helpers/index.js'; import type { VpcLatticeEventV2 } from '../../../src/types/index.js'; import { getTestEvent, omit } from '../helpers/utils.js'; diff --git a/packages/parser/tests/unit/helpers.test.ts b/packages/parser/tests/unit/helpers.test.ts index fd4b73eb14..9811234c2d 100644 --- a/packages/parser/tests/unit/helpers.test.ts +++ b/packages/parser/tests/unit/helpers.test.ts @@ -1,7 +1,7 @@ import { describe, expect, it } from 'vitest'; import { z } from 'zod'; -import { JSONStringified } from '../../src/helpers.js'; import { DynamoDBMarshalled } from '../../src/helpers/dynamodb.js'; +import { JSONStringified } from '../../src/helpers/index.js'; import { AlbSchema } from '../../src/schemas/alb.js'; import { DynamoDBStreamRecord, diff --git a/packages/parser/tests/unit/parser.middy.test.ts b/packages/parser/tests/unit/parser.middy.test.ts index c6bfdb34cc..34a3f1caf8 100644 --- a/packages/parser/tests/unit/parser.middy.test.ts +++ b/packages/parser/tests/unit/parser.middy.test.ts @@ -5,7 +5,7 @@ import { z } from 'zod'; import { EventBridgeEnvelope } from '../../src/envelopes/eventbridge.js'; import { SqsEnvelope } from '../../src/envelopes/sqs.js'; import { ParseError } from '../../src/errors.js'; -import { parser } from '../../src/middleware/parser.js'; +import { parser } from '../../src/middleware/index.js'; import type { EventBridgeEvent, ParsedResult, diff --git a/packages/parser/typedoc.json b/packages/parser/typedoc.json index 0650b79fad..cc06598557 100644 --- a/packages/parser/typedoc.json +++ b/packages/parser/typedoc.json @@ -2,11 +2,11 @@ "extends": ["../../typedoc.base.json"], "entryPoints": [ "./src/index.ts", - "./src/middleware/parser.ts", + "./src/middleware/index.ts", "./src/types/index.ts", "./src/envelopes/index.ts", "./src/schemas/index.ts", - "./src/helpers.ts", + "./src/helpers/index.ts", "./src/helpers/dynamodb.ts" ], "readme": "README.md" From d13f3c6236b853dd1800409bd4942680ab2abfd0 Mon Sep 17 00:00:00 2001 From: Andrea Amorosi Date: Wed, 19 Mar 2025 14:57:03 +0100 Subject: [PATCH 29/56] chore(logger): clear prev request buffers in manual mode (#3742) Co-authored-by: Alexander Schueren --- docs/core/logger.md | 11 +++++++---- packages/logger/src/Logger.ts | 8 +++++++- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/docs/core/logger.md b/docs/core/logger.md index 23b5d1ea9b..6a72664bb3 100644 --- a/docs/core/logger.md +++ b/docs/core/logger.md @@ -767,16 +767,19 @@ sequenceDiagram 4. **What happens if the log buffer reaches its maximum size?** Older logs are removed from the buffer to make room for new logs. This means that if the buffer is full, you may lose some logs if they are not flushed before the buffer reaches its maximum size. When this happens, we emit a warning when flushing the buffer to indicate that some logs have been dropped. -5. **What timestamp is used when I flush the logs?** +5. **How is the log size of a log line calculated?** + The log size is calculated based on the size of the stringified log line in bytes. This includes the size of the log message, the size of any additional keys, and the size of the timestamp. + +6. **What timestamp is used when I flush the logs?** The timestamp preserves the original time when the log record was created. If you create a log record at 11:00:10 and flush it at 11:00:25, the log line will retain its original timestamp of 11:00:10. -6. **What happens if I try to add a log line that is bigger than max buffer size?** +7. **What happens if I try to add a log line that is bigger than max buffer size?** The log will be emitted directly to standard output and not buffered. When this happens, we emit a warning to indicate that the log line was too big to be buffered. -7. **What happens if Lambda times out without flushing the buffer?** +8. **What happens if Lambda times out without flushing the buffer?** Logs that are still in the buffer will be lost. If you are using the log buffer to log asynchronously, you should ensure that the buffer is flushed before the Lambda function times out. You can do this by calling the `logger.flushBuffer()` method at the end of your Lambda function. -8. **Do child loggers inherit the buffer?** +9. **Do child loggers inherit the buffer?** No, child loggers do not inherit the buffer from their parent logger but only the buffer configuration. This means that if you create a child logger, it will have its own buffer and will not share the buffer with the parent logger. ### Reordering log keys position diff --git a/packages/logger/src/Logger.ts b/packages/logger/src/Logger.ts index be5ae0dba8..f1217a1e6f 100644 --- a/packages/logger/src/Logger.ts +++ b/packages/logger/src/Logger.ts @@ -1374,6 +1374,12 @@ class Logger extends Utility implements LoggerInterface { logLevel: number ): void { log.prepareForPrint(); + // This is the first time we see this traceId, so we need to clear the buffer + // from previous requests. This is ok because in AWS Lambda, the same sandbox + // environment can only ever be used by one request at a time. + if (this.#buffer?.has(xrayTraceId) === false) { + this.#buffer?.clear(); + } this.#buffer?.setItem( xrayTraceId, JSON.stringify( @@ -1424,7 +1430,6 @@ class Logger extends Utility implements LoggerInterface { /** * Empties the buffer for the current request - * */ public clearBuffer(): void { const traceId = this.envVarsService.getXrayTraceId(); @@ -1453,6 +1458,7 @@ class Logger extends Utility implements LoggerInterface { /** * Set the correlation ID for the log item. + * * This method can be used to set the correlation ID for the log item or to search for the correlation ID in the event. * * @example From 2659c9da97759afc889aa72641c62b34fdfdbec2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 20 Mar 2025 10:46:23 +0100 Subject: [PATCH 30/56] chore(deps): bump github/codeql-action from 3.28.11 to 3.28.12 (#3746) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Andrea Amorosi --- .github/workflows/ossf_scorecard.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ossf_scorecard.yml b/.github/workflows/ossf_scorecard.yml index 4d2b817922..4003144531 100644 --- a/.github/workflows/ossf_scorecard.yml +++ b/.github/workflows/ossf_scorecard.yml @@ -43,6 +43,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@6bb031afdd8eb862ea3fc1848194185e076637e5 # v3.28.11 + uses: github/codeql-action/upload-sarif@5f8171a638ada777af81d42b55959a643bb29017 # v3.28.12 with: sarif_file: results.sarif From 224536b83bd78150f0791d40c7d99cf8044f2288 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 20 Mar 2025 10:59:53 +0100 Subject: [PATCH 31/56] chore(deps): bump actions/setup-go from 5.3.0 to 5.4.0 (#3745) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Andrea Amorosi --- .github/workflows/bootstrap_region.yml | 2 +- .github/workflows/layer_balance.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/bootstrap_region.yml b/.github/workflows/bootstrap_region.yml index 3da43bc3f3..b22fa47028 100644 --- a/.github/workflows/bootstrap_region.yml +++ b/.github/workflows/bootstrap_region.yml @@ -88,7 +88,7 @@ jobs: mask-aws-account-id: true - id: go-setup name: Setup Go - uses: actions/setup-go@f111f3307d8850f501ac008e886eec1fd1932a34 # v5.3.0 + uses: actions/setup-go@0aaccfd150d50ccaeb58ebd88d36e91967a5f35b # v5.4.0 with: go-version: '>=1.23.0' - id: go-env diff --git a/.github/workflows/layer_balance.yml b/.github/workflows/layer_balance.yml index a1df2a8f44..bf02146db5 100644 --- a/.github/workflows/layer_balance.yml +++ b/.github/workflows/layer_balance.yml @@ -50,7 +50,7 @@ jobs: mask-aws-account-id: true - id: go-setup name: Setup Go - uses: actions/setup-go@f111f3307d8850f501ac008e886eec1fd1932a34 # v5.3.0 + uses: actions/setup-go@0aaccfd150d50ccaeb58ebd88d36e91967a5f35b # v5.4.0 with: go-version: '>=1.23.0' - id: go-env From 8986244c41977de2bbb262c6ce43d7799ede5140 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 20 Mar 2025 11:10:19 +0100 Subject: [PATCH 32/56] chore(deps): bump vscode/devcontainers/javascript-node from `896bfba` to `78fda8c` in /.devcontainer (#3739) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Andrea Amorosi --- .devcontainer/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index 880e13ea2a..d93cb69d0e 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -1,5 +1,5 @@ # See here for image contents: https://github.com/microsoft/vscode-dev-containers/blob/v0.212.0/containers/javascript-node/.devcontainer/base.Dockerfile -FROM mcr.microsoft.com/vscode/devcontainers/javascript-node@sha256:896bfba10582c9239d1c36bab53b80af06253019f62b846fa440ee643ca63eb1 +FROM mcr.microsoft.com/vscode/devcontainers/javascript-node@sha256:78fda8c284dd3247d7385d55974e278314233f1acc130ba89757703137dbda45 # Install fnm to manage Node.js versions RUN curl -fsSL https://fnm.vercel.app/install -o /tmp/install \ From e71f02e60b937ec39a69c29a08631e8614d20a04 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 20 Mar 2025 11:12:56 +0100 Subject: [PATCH 33/56] chore(deps): bump the aws-cdk group across 1 directory with 2 updates (#3743) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Andrea Amorosi --- examples/app/package.json | 2 +- layers/package.json | 2 +- package-lock.json | 26 +++++++++++++------------- packages/testing/package.json | 2 +- 4 files changed, 16 insertions(+), 16 deletions(-) diff --git a/examples/app/package.json b/examples/app/package.json index 78ac519678..c9debbde6b 100644 --- a/examples/app/package.json +++ b/examples/app/package.json @@ -49,7 +49,7 @@ "@middy/core": "^4.7.0", "@types/aws-lambda": "^8.10.147", "@types/node": "22.13.10", - "aws-cdk": "^2.1004.0", + "aws-cdk": "^2.1005.0", "constructs": "^10.4.2", "esbuild": "^0.25.1", "typescript": "^5.8.2" diff --git a/layers/package.json b/layers/package.json index 2792d85ebc..31c27bef1b 100644 --- a/layers/package.json +++ b/layers/package.json @@ -40,7 +40,7 @@ "source-map-support": "^0.5.21" }, "dependencies": { - "aws-cdk": "^2.1004.0", + "aws-cdk": "^2.1005.0", "aws-cdk-lib": "^2.184.1", "esbuild": "^0.25.1", "tsx": "^4.19.3" diff --git a/package-lock.json b/package-lock.json index df85f91675..5cc7436e49 100644 --- a/package-lock.json +++ b/package-lock.json @@ -63,7 +63,7 @@ "@middy/core": "^4.7.0", "@types/aws-lambda": "^8.10.147", "@types/node": "22.13.10", - "aws-cdk": "^2.1004.0", + "aws-cdk": "^2.1005.0", "constructs": "^10.4.2", "esbuild": "^0.25.1", "typescript": "^5.8.2" @@ -108,7 +108,7 @@ "version": "2.16.0", "license": "MIT-0", "dependencies": { - "aws-cdk": "^2.1004.0", + "aws-cdk": "^2.1005.0", "aws-cdk-lib": "^2.184.1", "esbuild": "^0.25.1", "tsx": "^4.19.3" @@ -266,12 +266,12 @@ } }, "node_modules/@aws-cdk/toolkit-lib": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/@aws-cdk/toolkit-lib/-/toolkit-lib-0.1.5.tgz", - "integrity": "sha512-C8+LjlkSFXQqVV9ZyhQ1VSkg6uMvwgnN5Fwp5l0+d3g/aR82YK3cVJYPppNjHZ4w4dOVErprVM4OdIfyf7Vmkg==", + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/@aws-cdk/toolkit-lib/-/toolkit-lib-0.1.6.tgz", + "integrity": "sha512-65ojo2cIpsXnA8C9e3k9vmIQ5UziZHkzPQGhCWvjf9TUNV/U8Phge5YeTKzMTOm/t8hvPfs1n5qCIBINwVPMAg==", "license": "Apache-2.0", "dependencies": { - "@aws-cdk/cloud-assembly-schema": "^41.1.0", + "@aws-cdk/cloud-assembly-schema": "^41.2.0", "@aws-cdk/cloudformation-diff": "^2.179.0", "@aws-cdk/cx-api": "^2.181.1", "@aws-cdk/region-info": "^2.181.1", @@ -331,9 +331,9 @@ } }, "node_modules/@aws-cdk/toolkit-lib/node_modules/@aws-cdk/cloud-assembly-schema": { - "version": "41.1.0", - "resolved": "https://registry.npmjs.org/@aws-cdk/cloud-assembly-schema/-/cloud-assembly-schema-41.1.0.tgz", - "integrity": "sha512-V+twOy4asXv6IIH1jxanugBOhBjRdC0Wsr56fSmN8fECp5aJQeqZ5XAiuFSCfwkNoJa72P0cMDm5eFsLK3PzhQ==", + "version": "41.2.0", + "resolved": "https://registry.npmjs.org/@aws-cdk/cloud-assembly-schema/-/cloud-assembly-schema-41.2.0.tgz", + "integrity": "sha512-JaulVS6z9y5+u4jNmoWbHZRs9uGOnmn/ktXygNWKNu1k6lF3ad4so3s18eRu15XCbUIomxN9WPYT6Ehh7hzONw==", "bundleDependencies": [ "jsonschema", "semver" @@ -10762,9 +10762,9 @@ } }, "node_modules/aws-cdk": { - "version": "2.1004.0", - "resolved": "https://registry.npmjs.org/aws-cdk/-/aws-cdk-2.1004.0.tgz", - "integrity": "sha512-3E5ICmSc7ZCZCwLX7NY+HFmmdUYgRaL+67h/BDoDQmkhx9StC8wG4xgzHFY9k8WQS0+ib/MP28f2d9yzHtQLlQ==", + "version": "2.1005.0", + "resolved": "https://registry.npmjs.org/aws-cdk/-/aws-cdk-2.1005.0.tgz", + "integrity": "sha512-4ejfGGrGCEl0pg1xcqkxK0lpBEZqNI48wtrXhk6dYOFYPYMZtqn1kdla29ONN+eO2unewkNF4nLP1lPYhlf9Pg==", "license": "Apache-2.0", "bin": { "cdk": "bin/cdk" @@ -21609,7 +21609,7 @@ "version": "2.16.0", "license": "MIT-0", "dependencies": { - "@aws-cdk/toolkit-lib": "^0.1.5", + "@aws-cdk/toolkit-lib": "^0.1.6", "@aws-sdk/client-lambda": "^3.758.0", "@smithy/util-utf8": "^4.0.0", "aws-cdk-lib": "^2.184.1", diff --git a/packages/testing/package.json b/packages/testing/package.json index 936fc76df8..3ccbd9dbfb 100644 --- a/packages/testing/package.json +++ b/packages/testing/package.json @@ -97,7 +97,7 @@ }, "homepage": "https://github.com/aws-powertools/powertools-lambda-typescript/tree/main/packages/testing#readme", "dependencies": { - "@aws-cdk/toolkit-lib": "^0.1.5", + "@aws-cdk/toolkit-lib": "^0.1.6", "@aws-sdk/client-lambda": "^3.758.0", "@smithy/util-utf8": "^4.0.0", "aws-cdk-lib": "^2.184.1", From 80c7eb9ea401652d2b74d4f5925b674432c1ed0b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 20 Mar 2025 11:59:11 +0100 Subject: [PATCH 34/56] chore(deps): bump actions/download-artifact from 4.1.9 to 4.2.0 (#3744) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Andrea Amorosi --- .github/workflows/publish_layer.yml | 2 +- .github/workflows/reusable_deploy_layer_stack.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/publish_layer.yml b/.github/workflows/publish_layer.yml index c0d537803d..567ad13e57 100644 --- a/.github/workflows/publish_layer.yml +++ b/.github/workflows/publish_layer.yml @@ -97,7 +97,7 @@ jobs: with: ref: ${{ github.sha }} - name: Download CDK layer artifacts - uses: actions/download-artifact@cc203385981b70ca67e1cc392babf9cc229d5806 # v4.1.9 + uses: actions/download-artifact@95815c38cf2ff2164869cbab79da8d1f422bc89e # v4.2.1 with: path: cdk-layer-stack pattern: cdk-layer-stack-* # merge all Layer artifacts created per region earlier (reusable_deploy_layer_stack.yml; step "Save Layer ARN artifact") diff --git a/.github/workflows/reusable_deploy_layer_stack.yml b/.github/workflows/reusable_deploy_layer_stack.yml index 75d3b98122..19b7d856c9 100644 --- a/.github/workflows/reusable_deploy_layer_stack.yml +++ b/.github/workflows/reusable_deploy_layer_stack.yml @@ -81,7 +81,7 @@ jobs: - name: Setup dependencies uses: aws-powertools/actions/.github/actions/cached-node-modules@29979bc5339bf54f76a11ac36ff67701986bb0f0 - name: Download artifact - uses: actions/download-artifact@cc203385981b70ca67e1cc392babf9cc229d5806 # v4.1.9 + uses: actions/download-artifact@95815c38cf2ff2164869cbab79da8d1f422bc89e # v4.2.1 with: name: ${{ inputs.artifact-name }} - name: Unzip artifact From de4d158dbea2ea0b3dc5892971c0d1a51378487e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 20 Mar 2025 15:22:15 +0100 Subject: [PATCH 35/56] chore(deps): bump actions/upload-artifact from 4.6.1 to 4.6.2 (#3751) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ossf_scorecard.yml | 2 +- .github/workflows/publish_layer.yml | 2 +- .github/workflows/record_pr.yml | 2 +- .github/workflows/reusable_deploy_layer_stack.yml | 2 +- .github/workflows/reusable_publish_docs.yml | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ossf_scorecard.yml b/.github/workflows/ossf_scorecard.yml index 4003144531..f2cfdaa6ce 100644 --- a/.github/workflows/ossf_scorecard.yml +++ b/.github/workflows/ossf_scorecard.yml @@ -35,7 +35,7 @@ jobs: # repo_token: ${{ secrets.SCORECARD_TOKEN }} # read-only fine-grained token to read branch protection settings - name: "Upload results" - uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 # v4.6.1 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 with: name: SARIF file path: results.sarif diff --git a/.github/workflows/publish_layer.yml b/.github/workflows/publish_layer.yml index 567ad13e57..cfa014959b 100644 --- a/.github/workflows/publish_layer.yml +++ b/.github/workflows/publish_layer.yml @@ -45,7 +45,7 @@ jobs: - name: Zip output run: zip -r cdk.out.zip layers/cdk.out - name: Archive CDK artifacts - uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 # v4.6.1 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 with: name: cdk-layer-artifact path: cdk.out.zip diff --git a/.github/workflows/record_pr.yml b/.github/workflows/record_pr.yml index a1fa413003..f0eacda57a 100644 --- a/.github/workflows/record_pr.yml +++ b/.github/workflows/record_pr.yml @@ -53,7 +53,7 @@ jobs: script: | const script = require('.github/scripts/save_pr_details.js') await script({github, context, core}) - - uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 # v4.6.1 + - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 with: name: pr path: pr.txt diff --git a/.github/workflows/reusable_deploy_layer_stack.yml b/.github/workflows/reusable_deploy_layer_stack.yml index 19b7d856c9..77ef81c3bd 100644 --- a/.github/workflows/reusable_deploy_layer_stack.yml +++ b/.github/workflows/reusable_deploy_layer_stack.yml @@ -96,7 +96,7 @@ jobs: cat cdk-layer-stack/${{ matrix.region }}-layer-version.txt - name: Save Layer ARN artifact if: ${{ inputs.stage == 'PROD' }} - uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 # v4.6.1 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 with: name: cdk-layer-stack-${{ matrix.region }} path: ./cdk-layer-stack/* # NOTE: upload-artifact does not inherit working-directory setting. diff --git a/.github/workflows/reusable_publish_docs.yml b/.github/workflows/reusable_publish_docs.yml index 7f40edc3d6..e485dce686 100644 --- a/.github/workflows/reusable_publish_docs.yml +++ b/.github/workflows/reusable_publish_docs.yml @@ -89,7 +89,7 @@ jobs: role-to-assume: ${{ secrets.AWS_DOCS_ROLE_ARN }} mask-aws-account-id: true - name: Create Artifact (Site) - uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 # v4.6.1 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 with: name: site path: site From 3176fa08e1886d5c86e7b327134cc988b82cf8d8 Mon Sep 17 00:00:00 2001 From: Steven Brice Date: Thu, 20 Mar 2025 07:32:22 -0700 Subject: [PATCH 36/56] feat(metrics): allow setting functionName via constructor parameter and environment variable (#3696) Co-authored-by: Andrea Amorosi --- docs/core/metrics.md | 38 +++- docs/index.md | 33 ++-- .../metrics/captureColdStartMetric.ts | 17 ++ examples/snippets/metrics/functionName.ts | 18 ++ packages/metrics/src/Metrics.ts | 55 +++--- .../src/config/EnvironmentVariablesService.ts | 11 +- packages/metrics/src/middleware/middy.ts | 3 +- .../src/types/ConfigServiceInterface.ts | 4 + packages/metrics/src/types/Metrics.ts | 39 +++-- .../tests/unit/coldStartMetric.test.ts | 43 ++++- .../tests/unit/initializeMetrics.test.ts | 122 ++++++++++++- .../metrics/tests/unit/logMetrics.test.ts | 164 +++++++++++++++++- 12 files changed, 463 insertions(+), 84 deletions(-) create mode 100644 examples/snippets/metrics/captureColdStartMetric.ts create mode 100644 examples/snippets/metrics/functionName.ts diff --git a/docs/core/metrics.md b/docs/core/metrics.md index 42bc929ebe..f2d61eabf9 100644 --- a/docs/core/metrics.md +++ b/docs/core/metrics.md @@ -66,11 +66,12 @@ The library requires two settings. You can set them as environment variables, or These settings will be used across all metrics emitted: -| Setting | Description | Environment variable | Default | Allowed Values | Example | Constructor parameter | -| -------------------- | ---------------------------------------------------------------- | ------------------------------ | ------------------- | -------------- | ------------------- | --------------------- | -| **Service** | Optionally, sets **service** metric dimension across all metrics | `POWERTOOLS_SERVICE_NAME` | `service_undefined` | Any string | `serverlessAirline` | `serviceName` | -| **Metric namespace** | Logical container where all metrics will be placed | `POWERTOOLS_METRICS_NAMESPACE` | `default_namespace` | Any string | `serverlessAirline` | `default_namespace` | -| **Enabled** | Whether to emit metrics to standard output or not | `POWERTOOLS_METRICS_ENABLED` | `true` | Boolean | `false` | | +| Setting | Description | Environment variable | Default | Allowed Values | Example | Constructor parameter | +|----------------------|------------------------------------------------------------------|------------------------------------|----------------------------------------------------------|----------------|---------------------|-----------------------| +| **Service** | Optionally, sets **service** metric dimension across all metrics | `POWERTOOLS_SERVICE_NAME` | `service_undefined` | Any string | `serverlessAirline` | `serviceName` | +| **Metric namespace** | Logical container where all metrics will be placed | `POWERTOOLS_METRICS_NAMESPACE` | `default_namespace` | Any string | `serverlessAirline` | `default_namespace` | +| **Function Name** | Function name used as dimension for the `ColdStart` metric | `POWERTOOLS_METRICS_FUNCTION_NAME` | [See docs](#capturing-a-cold-start-invocation-as-metric) | Any string | `my-function-name` | `functionName` | +| **Enabled** | Whether to emit metrics to standard output or not | `POWERTOOLS_METRICS_ENABLED` | `true` | Boolean | `false` | | !!! tip Use your application name or main service as the metric namespace to easily group all metrics @@ -87,7 +88,7 @@ The `Metrics` utility is instantiated outside of the Lambda handler. In doing th === "template.yml" - ```yaml hl_lines="9 10" + ```yaml hl_lines="8-10" Resources: HelloWorldFunction: Type: AWS::Serverless::Function @@ -97,6 +98,7 @@ The `Metrics` utility is instantiated outside of the Lambda handler. In doing th Variables: POWERTOOLS_SERVICE_NAME: orders POWERTOOLS_METRICS_NAMESPACE: serverlessAirline + POWERTOOLS_METRICS_FUNCTION_NAME: my-function-name ``` You can initialize Metrics anywhere in your code - It'll keep track of your aggregate metrics in memory. @@ -184,7 +186,7 @@ You can call `addMetric()` with the same name multiple times. The values will be ### Adding default dimensions -You can add default dimensions to your metrics by passing them as parameters in 4 ways: +You can add default dimensions to your metrics by passing them as parameters in 4 ways: * in the constructor * in the [Middy-compatible](https://github.com/middyjs/middy){target=_blank} middleware @@ -405,6 +407,28 @@ This has the advantage of keeping cold start metric separate from your applicati !!! info "We do not emit 0 as a value for the ColdStart metric for cost-efficiency reasons. [Let us know](https://github.com/aws-powertools/powertools-lambda-typescript/issues/new?assignees=&labels=feature-request%2C+triage&template=feature_request.md&title=) if you'd prefer a flag to override it." +#### Setting function name + +When emitting cold start metrics, the `function_name` dimension defaults to `context.functionName`. If you want to change the value you can set the `functionName` parameter in the metrics constructor, define the environment variable `POWERTOOLS_METRICS_FUNCTION_NAME`, or pass a value to `captureColdStartMetric`. + +The priority of the `function_name` dimension value is defined as: + +1. `functionName` constructor option +2. `POWERTOOLS_METRICS_FUNCTION_NAME` environment variable +3. The value passed in the `captureColdStartMetric` call, or `context.functionName` if using logMetrics decorator or Middy middleware + +=== "constructor" + + ```typescript hl_lines="6" + --8<-- "examples/snippets/metrics/functionName.ts" + ``` + +=== "captureColdStartMetric method" + + ```typescript hl_lines="12" + --8<-- "examples/snippets/metrics/captureColdStartMetric.ts" + ``` + ## Advanced ### Adding metadata diff --git a/docs/index.md b/docs/index.md index 680d346464..cb6256f2ba 100644 --- a/docs/index.md +++ b/docs/index.md @@ -351,22 +351,23 @@ Core utilities such as Tracing, Logging, and Metrics will be available across al ???+ info Explicit parameters take precedence over environment variables -| Environment variable | Description | Utility | Default | -| -------------------------------------------- | ------------------------------------------------------------------------------------------------------------- | --------------------------------------- | ------------------- | -| **POWERTOOLS_SERVICE_NAME** | Set service name used for tracing namespace, metrics dimension and structured logging | All | `service_undefined` | -| **POWERTOOLS_METRICS_NAMESPACE** | Set namespace used for metrics | [Metrics](core/metrics.md) | `default_namespace` | -| **POWERTOOLS_METRICS_ENABLED** | Explicitly disables emitting metrics to stdout | [Metrics](core/metrics.md) | `true` | -| **POWERTOOLS_TRACE_ENABLED** | Explicitly disables tracing | [Tracer](core/tracer.md) | `true` | -| **POWERTOOLS_TRACER_CAPTURE_RESPONSE** | Capture Lambda or method return as metadata. | [Tracer](core/tracer.md) | `true` | -| **POWERTOOLS_TRACER_CAPTURE_ERROR** | Capture Lambda or method exception as metadata. | [Tracer](core/tracer.md) | `true` | -| **POWERTOOLS_TRACER_CAPTURE_HTTPS_REQUESTS** | Capture HTTP(s) requests as segments. | [Tracer](core/tracer.md) | `true` | -| **POWERTOOLS_LOGGER_LOG_EVENT** | Log incoming event | [Logger](core/logger.md) | `false` | -| **POWERTOOLS_LOGGER_SAMPLE_RATE** | Debug log sampling | [Logger](core/logger.md) | `0` | -| **POWERTOOLS_DEV** | Increase JSON indentation to ease debugging when running functions locally or in a non-production environment | [Logger](core/logger.md) | `false` | -| **POWERTOOLS_LOG_LEVEL** | Sets how verbose Logger should be, from the most verbose to the least verbose (no logs) | [Logger](core/logger.md) | `INFO` | -| **POWERTOOLS_PARAMETERS_MAX_AGE** | Adjust how long values are kept in cache (in seconds) | [Parameters](utilities/parameters.md) | `5` | -| **POWERTOOLS_PARAMETERS_SSM_DECRYPT** | Set whether to decrypt or not values retrieved from AWS Systems Manager Parameters Store | [Parameters](utilities/parameters.md) | `false` | -| **POWERTOOLS_IDEMPOTENCY_DISABLED** | Disable the Idempotency logic without changing your code, useful for testing | [Idempotency](utilities/idempotency.md) | `false` | +| Environment variable | Description | Utility | Default | +| -------------------------------------------- |------------------------------------------------------------------------------------------| --------------------------------------- |-------------------------------------------------| +| **POWERTOOLS_SERVICE_NAME** | Set service name used for tracing namespace, metrics dimension and structured logging | All | `service_undefined` | +| **POWERTOOLS_METRICS_NAMESPACE** | Set namespace used for metrics | [Metrics](core/metrics.md) | `default_namespace` | +| **POWERTOOLS_METRICS_FUNCTION_NAME** | Function name used as dimension for the `ColdStart` metric | [Metrics](core/metrics.md) | [See docs](core/metrics/#setting-function-name) | +| **POWERTOOLS_METRICS_ENABLED** | Explicitly disables emitting metrics to stdout | [Metrics](core/metrics.md) | `true` | +| **POWERTOOLS_TRACE_ENABLED** | Explicitly disables tracing | [Tracer](core/tracer.md) | `true` | +| **POWERTOOLS_TRACER_CAPTURE_RESPONSE** | Capture Lambda or method return as metadata. | [Tracer](core/tracer.md) | `true` | +| **POWERTOOLS_TRACER_CAPTURE_ERROR** | Capture Lambda or method exception as metadata. | [Tracer](core/tracer.md) | `true` | +| **POWERTOOLS_TRACER_CAPTURE_HTTPS_REQUESTS** | Capture HTTP(s) requests as segments. | [Tracer](core/tracer.md) | `true` | +| **POWERTOOLS_LOGGER_LOG_EVENT** | Log incoming event | [Logger](core/logger.md) | `false` | +| **POWERTOOLS_LOGGER_SAMPLE_RATE** | Debug log sampling | [Logger](core/logger.md) | `0` | +| **POWERTOOLS_DEV** | Pretty-print logs, disable metrics flushing, and disable traces - use for dev only | See section below | `false` | +| **POWERTOOLS_LOG_LEVEL** | Sets how verbose Logger should be, from the most verbose to the least verbose (no logs) | [Logger](core/logger.md) | `INFO` | +| **POWERTOOLS_PARAMETERS_MAX_AGE** | Adjust how long values are kept in cache (in seconds) | [Parameters](utilities/parameters.md) | `5` | +| **POWERTOOLS_PARAMETERS_SSM_DECRYPT** | Set whether to decrypt or not values retrieved from AWS Systems Manager Parameters Store | [Parameters](utilities/parameters.md) | `false` | +| **POWERTOOLS_IDEMPOTENCY_DISABLED** | Disable the Idempotency logic without changing your code, useful for testing | [Idempotency](utilities/idempotency.md) | `false` | Each Utility page provides information on example values and allowed values. diff --git a/examples/snippets/metrics/captureColdStartMetric.ts b/examples/snippets/metrics/captureColdStartMetric.ts new file mode 100644 index 0000000000..289934f9a7 --- /dev/null +++ b/examples/snippets/metrics/captureColdStartMetric.ts @@ -0,0 +1,17 @@ +import { MetricUnit, Metrics } from '@aws-lambda-powertools/metrics'; + +const metrics = new Metrics({ + namespace: 'serverlessAirline', + serviceName: 'orders', +}); + +export const handler = async ( + _event: unknown, + _context: unknown +): Promise => { + metrics.captureColdStartMetric('my-function-name'); + + metrics.addMetric('successfulBooking', MetricUnit.Count, 1); + + metrics.publishStoredMetrics(); +}; diff --git a/examples/snippets/metrics/functionName.ts b/examples/snippets/metrics/functionName.ts new file mode 100644 index 0000000000..2811a45af1 --- /dev/null +++ b/examples/snippets/metrics/functionName.ts @@ -0,0 +1,18 @@ +import { MetricUnit, Metrics } from '@aws-lambda-powertools/metrics'; + +const metrics = new Metrics({ + namespace: 'serverlessAirline', + serviceName: 'orders', + functionName: 'my-function-name', +}); + +export const handler = async ( + _event: unknown, + _context: unknown +): Promise => { + metrics.captureColdStartMetric(); + + metrics.addMetric('successfulBooking', MetricUnit.Count, 1); + + metrics.publishStoredMetrics(); +}; diff --git a/packages/metrics/src/Metrics.ts b/packages/metrics/src/Metrics.ts index 93b2e35787..a3a743e96d 100644 --- a/packages/metrics/src/Metrics.ts +++ b/packages/metrics/src/Metrics.ts @@ -371,8 +371,10 @@ class Metrics extends Utility implements MetricsInterface { * metrics.captureColdStartMetric(); * }; * ``` + * + * @param functionName - Optional function name to use as `function_name` dimension in the metric. It's used only if the `functionName` constructor parameter or environment variable are not set. */ - public captureColdStartMetric(): void { + public captureColdStartMetric(functionName?: string): void { if (!this.getColdStart()) return; const singleMetric = this.singleMetric(); @@ -381,8 +383,9 @@ class Metrics extends Utility implements MetricsInterface { service: this.defaultDimensions.service, }); } - if (this.functionName != null) { - singleMetric.addDimension('function_name', this.functionName); + const value = this.functionName?.trim() ?? functionName?.trim(); + if (value && value.length > 0) { + singleMetric.addDimension('function_name', value); } singleMetric.addMetric(COLD_START_METRIC, MetricUnits.Count, 1); } @@ -543,8 +546,9 @@ class Metrics extends Utility implements MetricsInterface { context: Context, callback: Callback ): Promise { - metricsRef.functionName = context.functionName; - if (captureColdStartMetric) metricsRef.captureColdStartMetric(); + if (captureColdStartMetric) { + metricsRef.captureColdStartMetric(context.functionName); + } let result: unknown; try { @@ -749,28 +753,14 @@ class Metrics extends Utility implements MetricsInterface { } /** - * Set the function name to be added to each metric as a dimension. - * - * When using the {@link Metrics.logMetrics | `logMetrics()`} decorator, or the Middy.js middleware, the function - * name is automatically inferred from the Lambda context. - * - * @example - * ```typescript - * import { Metrics } from '@aws-lambda-powertools/metrics'; - * - * const metrics = new Metrics({ - * namespace: 'serverlessAirline', - * serviceName: 'orders' - * }); - * - * metrics.setFunctionName('my-function-name'); - * ``` - * - * @param name - The function name + * @deprecated Override the function name for `ColdStart` metrics inferred from the context either via: + * - `functionName` constructor parameter + * - `POWERTOOLS_FUNCTION_NAME` environment variable + * - {@link Metrics.captureColdStartMetric | `captureColdStartMetric('myFunctionName')`} method */ - public setFunctionName(name: string): void { + /* v8 ignore start */ public setFunctionName(name: string): void { this.functionName = name; - } + } /* v8 ignore end */ /** * Set the flag to throw an error if no metrics are emitted. @@ -917,6 +907,19 @@ class Metrics extends Utility implements MetricsInterface { this.envVarsService = new EnvironmentVariablesService(); } + /** + * Set the function name for the cold start metric. + * + * @param functionName - The function name to be used for the cold start metric set in the constructor + */ + protected setFunctionNameForColdStartMetric(functionName?: string): void { + const value = + functionName?.trim() ?? this.getEnvVarsService().getFunctionName().trim(); + if (value && value.length > 0) { + this.functionName = value; + } + } + /** * Set the namespace to be used. * @@ -951,6 +954,7 @@ class Metrics extends Utility implements MetricsInterface { serviceName, singleMetric, defaultDimensions, + functionName, } = options; this.setEnvVarsService(); @@ -960,6 +964,7 @@ class Metrics extends Utility implements MetricsInterface { this.setNamespace(namespace); this.setService(serviceName); this.setDefaultDimensions(defaultDimensions); + this.setFunctionNameForColdStartMetric(functionName); this.isSingleMetric = singleMetric || false; return this; diff --git a/packages/metrics/src/config/EnvironmentVariablesService.ts b/packages/metrics/src/config/EnvironmentVariablesService.ts index a611308649..6fb6c6719c 100644 --- a/packages/metrics/src/config/EnvironmentVariablesService.ts +++ b/packages/metrics/src/config/EnvironmentVariablesService.ts @@ -11,8 +11,8 @@ class EnvironmentVariablesService extends CommonEnvironmentVariablesService implements ConfigServiceInterface { - private namespaceVariable = 'POWERTOOLS_METRICS_NAMESPACE'; - + private readonly namespaceVariable = 'POWERTOOLS_METRICS_NAMESPACE'; + private readonly functionNameVariable = 'POWERTOOLS_METRICS_FUNCTION_NAME'; private readonly disabledVariable = 'POWERTOOLS_METRICS_DISABLED'; /** @@ -22,6 +22,13 @@ class EnvironmentVariablesService return this.get(this.namespaceVariable); } + /** + * Get the value of the `POWERTOOLS_METRICS_FUNCTION_NAME` environment variable. + */ + public getFunctionName(): string { + return this.get(this.functionNameVariable); + } + /** * Get the value of the `POWERTOOLS_METRICS_DISABLED` or `POWERTOOLS_DEV` environment variables. * diff --git a/packages/metrics/src/middleware/middy.ts b/packages/metrics/src/middleware/middy.ts index e02a39d79a..d06a0977e4 100644 --- a/packages/metrics/src/middleware/middy.ts +++ b/packages/metrics/src/middleware/middy.ts @@ -62,7 +62,6 @@ const logMetrics = ( const logMetricsBefore = async (request: MiddyLikeRequest): Promise => { for (const metrics of metricsInstances) { - metrics.setFunctionName(request.context.functionName); const { throwOnEmptyMetrics, defaultDimensions, captureColdStartMetric } = options; if (throwOnEmptyMetrics) { @@ -72,7 +71,7 @@ const logMetrics = ( metrics.setDefaultDimensions(defaultDimensions); } if (captureColdStartMetric) { - metrics.captureColdStartMetric(); + metrics.captureColdStartMetric(request.context.functionName); } } diff --git a/packages/metrics/src/types/ConfigServiceInterface.ts b/packages/metrics/src/types/ConfigServiceInterface.ts index 81caa2d53b..68a86e1571 100644 --- a/packages/metrics/src/types/ConfigServiceInterface.ts +++ b/packages/metrics/src/types/ConfigServiceInterface.ts @@ -12,6 +12,10 @@ interface ConfigServiceInterface extends ConfigServiceBaseInterface { * Get the value of the `POWERTOOLS_METRICS_NAMESPACE` environment variable. */ getNamespace(): string; + /** + * Get the value of the `POWERTOOLS_METRICS_FUNCTION_NAME` environment variable. + */ + getFunctionName(): string; } export type { ConfigServiceInterface }; diff --git a/packages/metrics/src/types/Metrics.ts b/packages/metrics/src/types/Metrics.ts index da71711501..ccd914351e 100644 --- a/packages/metrics/src/types/Metrics.ts +++ b/packages/metrics/src/types/Metrics.ts @@ -60,6 +60,19 @@ type MetricsOptions = { * @see {@link MetricsInterface.setDefaultDimensions | `setDefaultDimensions()`} */ defaultDimensions?: Dimensions; + /** + * Function name to use as dimension for the `ColdStart` metric. + * + * When not provided, the function name is inferred either via: + * - `POWERTOOLS_FUNCTION_NAME` environment variable + * - AWS Lambda function context, **only** when using the {@link MetricsInterface.logMetrics | `logMetrics()`} decorator or the Middy.js middleware + * - `functionName` parameter in the {@link MetricsInterface.captureColdStartMetric | `captureColdStartMetric()`} method + * + * If none of the above are available, the `ColdStart` metric will not include a function name dimension. + * + * @see {@link MetricsInterface.setFunctionName | `setFunctionName()`} + */ + functionName?: string; /** * Logger object to be used for emitting debug, warning, and error messages. * @@ -272,8 +285,10 @@ interface MetricsInterface { * metrics.captureColdStartMetric(); * }; * ``` + * + * @param functionName - Optional function name to use as `function_name` dimension in the metric. It's used only if the `functionName` constructor parameter or environment variable are not set. */ - captureColdStartMetric(): void; + captureColdStartMetric(functionName?: string): void; /** * Clear all previously set default dimensions. * @@ -445,24 +460,10 @@ interface MetricsInterface { */ setDefaultDimensions(dimensions: Dimensions | undefined): void; /** - * Set the function name to be added to each metric as a dimension. - * - * When using the {@link MetricsInterface.logMetrics | `logMetrics()`} decorator, or the Middy.js middleware, the function - * name is automatically inferred from the Lambda context. - * - * @example - * ```typescript - * import { Metrics } from '@aws-lambda-powertools/metrics'; - * - * const metrics = new Metrics({ - * namespace: 'serverlessAirline', - * serviceName: 'orders' - * }); - * - * metrics.setFunctionName('my-function-name'); - * ``` - * - * @param name - The function name + * @deprecated Override the function name for `ColdStart` metrics inferred from the context either via: + * - `functionName` constructor parameter + * - `POWERTOOLS_FUNCTION_NAME` environment variable + * - {@link MetricsInterface.captureColdStartMetric | `captureColdStartMetric()`} method */ setFunctionName(name: string): void; /** diff --git a/packages/metrics/tests/unit/coldStartMetric.test.ts b/packages/metrics/tests/unit/coldStartMetric.test.ts index 9a9cba37c9..e63ee9eb72 100644 --- a/packages/metrics/tests/unit/coldStartMetric.test.ts +++ b/packages/metrics/tests/unit/coldStartMetric.test.ts @@ -65,27 +65,62 @@ describe('ColdStart metric', () => { ); }); - it('includes the function name in the cold start metric', () => { + it('does not override the function name from constructor in the cold start metric', () => { // Prepare const functionName = 'my-function'; const metrics = new Metrics({ namespace: DEFAULT_NAMESPACE, + functionName: 'another-function', }); - metrics.setFunctionName(functionName); // Act - metrics.captureColdStartMetric(); + metrics.captureColdStartMetric(functionName); // Assess expect(console.log).toHaveEmittedEMFWith( expect.objectContaining({ service: 'hello-world', [COLD_START_METRIC]: 1, - function_name: 'my-function', + function_name: 'another-function', }) ); }); + it.each([ + { + case: 'empty string', + functionName: '', + }, + { + case: 'undefined', + functionName: undefined, + }, + ])( + 'does not include the function name if not set or invalid ($case)', + ({ functionName }) => { + // Prepare + const metrics = new Metrics({ + namespace: DEFAULT_NAMESPACE, + }); + + // Act + metrics.captureColdStartMetric(functionName); + + // Assess + expect(console.log).toHaveEmittedEMFWith( + expect.objectContaining({ + service: 'hello-world', + [COLD_START_METRIC]: 1, + }) + ); + expect(console.log).toHaveEmittedEMFWith( + expect.not.objectContaining({ + function_name: 'my-function', + }) + ); + } + ); + it('emits the metric only once', () => { // Prepare const metrics = new Metrics({ diff --git a/packages/metrics/tests/unit/initializeMetrics.test.ts b/packages/metrics/tests/unit/initializeMetrics.test.ts index 663328a294..a6b4a62a9d 100644 --- a/packages/metrics/tests/unit/initializeMetrics.test.ts +++ b/packages/metrics/tests/unit/initializeMetrics.test.ts @@ -1,5 +1,5 @@ import { beforeEach, describe, expect, it, vi } from 'vitest'; -import { DEFAULT_NAMESPACE } from '../../src/constants.js'; +import { COLD_START_METRIC, DEFAULT_NAMESPACE } from '../../src/constants.js'; import { MetricUnit, Metrics } from '../../src/index.js'; import type { ConfigServiceInterface } from '../../src/types/index.js'; @@ -113,6 +113,123 @@ describe('Initialize Metrics', () => { ); }); + it('prioritizes the function name provided in the constructor', () => { + // Prepare + process.env.POWERTOOLS_METRICS_FUNCTION_NAME = 'another-function'; + const metrics = new Metrics({ + namespace: DEFAULT_NAMESPACE, + functionName: 'my-function-name', + }); + + // Act + metrics.captureColdStartMetric(); + + // Assess + expect(console.log).toHaveBeenCalledTimes(1); + expect(console.log).toHaveEmittedEMFWith( + expect.objectContaining({ + service: 'hello-world', + [COLD_START_METRIC]: 1, + function_name: 'my-function-name', + }) + ); + }); + + it('uses the function name provided in the environment variables', () => { + // Prepare + process.env.POWERTOOLS_METRICS_FUNCTION_NAME = 'another-function'; + const metrics = new Metrics({ + namespace: DEFAULT_NAMESPACE, + }); + + // Act + metrics.captureColdStartMetric(); + + // Assess + expect(console.log).toHaveBeenCalledTimes(1); + expect(console.log).toHaveEmittedEMFWith( + expect.objectContaining({ + service: 'hello-world', + [COLD_START_METRIC]: 1, + function_name: 'another-function', + }) + ); + }); + + it.each([ + { + case: 'an empty string', + functionName: '', + }, + { + case: 'undefined', + functionName: undefined, + }, + ])( + 'does not set the function name from env when is $case', + ({ functionName }) => { + // Prepare + process.env.POWERTOOLS_METRICS_FUNCTION_NAME = functionName; + const metrics = new Metrics({ + namespace: DEFAULT_NAMESPACE, + }); + + // Act + metrics.captureColdStartMetric(); + + // Assess + expect(console.log).toHaveBeenCalledTimes(1); + expect(console.log).toHaveEmittedEMFWith( + expect.objectContaining({ + service: 'hello-world', + [COLD_START_METRIC]: 1, + }) + ); + expect(console.log).toHaveEmittedEMFWith( + expect.not.objectContaining({ + function_name: expect.anything(), + }) + ); + } + ); + + it.each([ + { + case: 'an empty string', + functionName: '', + }, + { + case: 'undefined', + functionName: undefined, + }, + ])( + 'does not set the function name from constructor when is $case', + ({ functionName }) => { + // Prepare + const metrics = new Metrics({ + namespace: DEFAULT_NAMESPACE, + functionName, + }); + + // Act + metrics.captureColdStartMetric(); + + // Assess + expect(console.log).toHaveBeenCalledTimes(1); + expect(console.log).toHaveEmittedEMFWith( + expect.objectContaining({ + service: 'hello-world', + [COLD_START_METRIC]: 1, + }) + ); + expect(console.log).toHaveEmittedEMFWith( + expect.not.objectContaining({ + function_name: expect.anything(), + }) + ); + } + ); + it('uses the custom config service provided', () => { // Prepare const configService = { @@ -128,6 +245,9 @@ describe('Initialize Metrics', () => { isValueTrue(value: string): boolean { return value === 'true'; }, + getFunctionName(): string { + return 'custom-function-name'; + }, }; const metrics = new Metrics({ singleMetric: true, diff --git a/packages/metrics/tests/unit/logMetrics.test.ts b/packages/metrics/tests/unit/logMetrics.test.ts index 90234c1e60..a0e2a33447 100644 --- a/packages/metrics/tests/unit/logMetrics.test.ts +++ b/packages/metrics/tests/unit/logMetrics.test.ts @@ -6,6 +6,11 @@ import { COLD_START_METRIC, DEFAULT_NAMESPACE } from '../../src/constants.js'; import { MetricUnit, Metrics } from '../../src/index.js'; import { logMetrics } from '../../src/middleware/middy.js'; +const contextFunctionName = 'context-function-name'; +const contextWithFunctionName = { + functionName: contextFunctionName, +} as Context; + describe('LogMetrics decorator & Middy.js middleware', () => { const ENVIRONMENT_VARIABLES = process.env; @@ -45,8 +50,8 @@ describe('LogMetrics decorator & Middy.js middleware', () => { const handler = lambda.handler.bind(lambda); // Act - await handler({}, {} as Context); - await handler({}, {} as Context); + await handler({}, contextWithFunctionName); + await handler({}, contextWithFunctionName); // Assess expect(metrics.publishStoredMetrics).toHaveBeenCalledTimes(2); @@ -56,6 +61,7 @@ describe('LogMetrics decorator & Middy.js middleware', () => { expect.objectContaining({ [COLD_START_METRIC]: 1, service: 'hello-world', + function_name: contextFunctionName, }) ); expect(console.log).toHaveEmittedNthMetricWith( @@ -82,6 +88,94 @@ describe('LogMetrics decorator & Middy.js middleware', () => { ); }); + it('default function name in the cold start metric to context.functionName when using decorator', async () => { + // Prepare + const metrics = new Metrics({ + singleMetric: false, + namespace: DEFAULT_NAMESPACE, + }); + + vi.spyOn(metrics, 'publishStoredMetrics'); + class Test { + readonly #metricName: string; + + public constructor(name: string) { + this.#metricName = name; + } + + @metrics.logMetrics({ captureColdStartMetric: true }) + async handler(_event: unknown, _context: Context) { + this.addGreetingMetric(); + } + + addGreetingMetric() { + metrics.addMetric(this.#metricName, MetricUnit.Count, 1); + } + } + const lambda = new Test('greetings'); + const handler = lambda.handler.bind(lambda); + + // Act + await handler({}, contextWithFunctionName); + + // Assess + expect(metrics.publishStoredMetrics).toHaveBeenCalledTimes(1); + expect(console.log).toHaveBeenCalledTimes(2); + expect(console.log).toHaveEmittedNthEMFWith( + 1, + expect.objectContaining({ + [COLD_START_METRIC]: 1, + service: 'hello-world', + function_name: contextFunctionName, + }) + ); + }); + + it('does not override existing function name in the cold start metric when using decorator', async () => { + // Prepare + const functionName = 'function-name'; + const metrics = new Metrics({ + singleMetric: false, + namespace: DEFAULT_NAMESPACE, + functionName, + }); + + vi.spyOn(metrics, 'publishStoredMetrics'); + class Test { + readonly #metricName: string; + + public constructor(name: string) { + this.#metricName = name; + } + + @metrics.logMetrics({ captureColdStartMetric: true }) + async handler(_event: unknown, _context: Context) { + this.addGreetingMetric(); + } + + addGreetingMetric() { + metrics.addMetric(this.#metricName, MetricUnit.Count, 1); + } + } + const lambda = new Test('greetings'); + const handler = lambda.handler.bind(lambda); + + // Act + await handler({}, contextWithFunctionName); + + // Assess + expect(metrics.publishStoredMetrics).toHaveBeenCalledTimes(1); + expect(console.log).toHaveBeenCalledTimes(2); + expect(console.log).toHaveEmittedNthEMFWith( + 1, + expect.objectContaining({ + [COLD_START_METRIC]: 1, + service: 'hello-world', + function_name: functionName, + }) + ); + }); + it('captures the cold start metric on the first invocation when using the Middy.js middleware', async () => { // Prepare const metrics = new Metrics({ @@ -94,8 +188,8 @@ describe('LogMetrics decorator & Middy.js middleware', () => { }).use(logMetrics(metrics, { captureColdStartMetric: true })); // Act - await handler({}, {} as Context); - await handler({}, {} as Context); + await handler({}, contextWithFunctionName); + await handler({}, contextWithFunctionName); // Assess expect(metrics.publishStoredMetrics).toHaveBeenCalledTimes(2); @@ -109,6 +203,60 @@ describe('LogMetrics decorator & Middy.js middleware', () => { ); }); + it('default function name in the cold start metric to context.functionName when using the Middy.js middleware', async () => { + // Prepare + const metrics = new Metrics({ + namespace: DEFAULT_NAMESPACE, + }); + + vi.spyOn(metrics, 'publishStoredMetrics'); + const handler = middy(async () => { + metrics.addMetric('greetings', MetricUnit.Count, 1); + }).use(logMetrics(metrics, { captureColdStartMetric: true })); + + // Act + await handler({}, contextWithFunctionName); + + // Assess + expect(metrics.publishStoredMetrics).toHaveBeenCalledTimes(1); + expect(console.log).toHaveEmittedNthEMFWith( + 1, + expect.objectContaining({ + [COLD_START_METRIC]: 1, + service: 'hello-world', + function_name: contextFunctionName, + }) + ); + }); + + it('does not override existing function name in the cold start metric when using the Middy.js middleware', async () => { + // Prepare + const functionName = 'my-function'; + const metrics = new Metrics({ + namespace: DEFAULT_NAMESPACE, + functionName, + }); + + vi.spyOn(metrics, 'publishStoredMetrics'); + const handler = middy(async () => { + metrics.addMetric('greetings', MetricUnit.Count, 1); + }).use(logMetrics(metrics, { captureColdStartMetric: true })); + + // Act + await handler({}, contextWithFunctionName); + + // Assess + expect(metrics.publishStoredMetrics).toHaveBeenCalledTimes(1); + expect(console.log).toHaveEmittedNthEMFWith( + 1, + expect.objectContaining({ + [COLD_START_METRIC]: 1, + service: 'hello-world', + function_name: functionName, + }) + ); + }); + it('includes default dimensions passed in the decorator', async () => { // Prepare const metrics = new Metrics({ @@ -125,7 +273,7 @@ describe('LogMetrics decorator & Middy.js middleware', () => { const handler = lambda.handler.bind(lambda); // Act - await handler({}, {} as Context); + await handler({}, contextWithFunctionName); // Assess expect(console.log).toHaveBeenCalledTimes(1); @@ -157,7 +305,7 @@ describe('LogMetrics decorator & Middy.js middleware', () => { ); // Act - await handler({}, {} as Context); + await handler({}, contextWithFunctionName); // Assess expect(console.log).toHaveBeenCalledTimes(1); @@ -261,8 +409,8 @@ describe('LogMetrics decorator & Middy.js middleware', () => { .use(myCustomMiddleware()); // Act - await handler({ idx: 0 }, {} as Context); - await handler({ idx: 1 }, {} as Context); + await handler({ idx: 0 }, contextWithFunctionName); + await handler({ idx: 1 }, contextWithFunctionName); // Assess expect(metrics.publishStoredMetrics).toHaveBeenCalledTimes(2); From 550118e803d4d0192851037772a3b92dcc39a9d7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 20 Mar 2025 15:39:15 +0100 Subject: [PATCH 37/56] chore(deps): bump @aws-sdk/client-lambda from 3.758.0 to 3.771.0 in the aws-sdk-v3 group across 1 directory (#3749) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Andrea Amorosi --- package-lock.json | 8 ++++---- packages/testing/package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 5cc7436e49..d3ee16f9c6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4971,9 +4971,9 @@ } }, "node_modules/@aws-sdk/client-lambda": { - "version": "3.758.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-lambda/-/client-lambda-3.758.0.tgz", - "integrity": "sha512-k7L9fe0NN1v2Vhg4ofA1pb26gTdGVFdkA6XUQyElLEdcKzJzoYiQ60faNLuMPfH0zsKNvy/xKfNOD6DFZWjgEg==", + "version": "3.771.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-lambda/-/client-lambda-3.771.0.tgz", + "integrity": "sha512-0/4IGf4Nbc9Dfo6/9P0Qq7O5B1L7DGsfUg6Yl963GTOaM8wwYc8WzZy7F3EqMYIrGPz0M12IdYL9bU0hThnZvA==", "license": "Apache-2.0", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", @@ -21610,7 +21610,7 @@ "license": "MIT-0", "dependencies": { "@aws-cdk/toolkit-lib": "^0.1.6", - "@aws-sdk/client-lambda": "^3.758.0", + "@aws-sdk/client-lambda": "^3.771.0", "@smithy/util-utf8": "^4.0.0", "aws-cdk-lib": "^2.184.1", "esbuild": "^0.25.1", diff --git a/packages/testing/package.json b/packages/testing/package.json index 3ccbd9dbfb..74e6091b35 100644 --- a/packages/testing/package.json +++ b/packages/testing/package.json @@ -98,7 +98,7 @@ "homepage": "https://github.com/aws-powertools/powertools-lambda-typescript/tree/main/packages/testing#readme", "dependencies": { "@aws-cdk/toolkit-lib": "^0.1.6", - "@aws-sdk/client-lambda": "^3.758.0", + "@aws-sdk/client-lambda": "^3.771.0", "@smithy/util-utf8": "^4.0.0", "aws-cdk-lib": "^2.184.1", "esbuild": "^0.25.1", From 8dcaa2107be4fad7710d28ffa017b72beb66c519 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 20 Mar 2025 16:42:24 +0100 Subject: [PATCH 38/56] chore(deps): bump aws-cdk-lib from 2.184.1 to 2.185.0 in the aws-cdk group across 1 directory (#3750) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Andrea Amorosi --- examples/app/package.json | 2 +- layers/package.json | 2 +- package-lock.json | 12 ++++++------ packages/testing/package.json | 2 +- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/examples/app/package.json b/examples/app/package.json index c9debbde6b..c69453785a 100644 --- a/examples/app/package.json +++ b/examples/app/package.json @@ -30,7 +30,7 @@ "devDependencies": { "@types/aws-lambda": "^8.10.147", "@types/node": "22.13.10", - "aws-cdk-lib": "^2.184.1", + "aws-cdk-lib": "^2.185.0", "constructs": "^10.4.2", "source-map-support": "^0.5.21", "tsx": "^4.19.3", diff --git a/layers/package.json b/layers/package.json index 31c27bef1b..45cb514bf4 100644 --- a/layers/package.json +++ b/layers/package.json @@ -41,7 +41,7 @@ }, "dependencies": { "aws-cdk": "^2.1005.0", - "aws-cdk-lib": "^2.184.1", + "aws-cdk-lib": "^2.185.0", "esbuild": "^0.25.1", "tsx": "^4.19.3" } diff --git a/package-lock.json b/package-lock.json index d3ee16f9c6..de7f04a34e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -71,7 +71,7 @@ "devDependencies": { "@types/aws-lambda": "^8.10.147", "@types/node": "22.13.10", - "aws-cdk-lib": "^2.184.1", + "aws-cdk-lib": "^2.185.0", "constructs": "^10.4.2", "source-map-support": "^0.5.21", "tsx": "^4.19.3", @@ -109,7 +109,7 @@ "license": "MIT-0", "dependencies": { "aws-cdk": "^2.1005.0", - "aws-cdk-lib": "^2.184.1", + "aws-cdk-lib": "^2.185.0", "esbuild": "^0.25.1", "tsx": "^4.19.3" }, @@ -10777,9 +10777,9 @@ } }, "node_modules/aws-cdk-lib": { - "version": "2.184.1", - "resolved": "https://registry.npmjs.org/aws-cdk-lib/-/aws-cdk-lib-2.184.1.tgz", - "integrity": "sha512-No9g0SGadiDz0IEUIeJg4wSV/jFCGcouW2zUOTjV8OU4gTMoGiqC8BYSv7E6ucUtW6rmSFVK+pbc8XOFZOo1cg==", + "version": "2.185.0", + "resolved": "https://registry.npmjs.org/aws-cdk-lib/-/aws-cdk-lib-2.185.0.tgz", + "integrity": "sha512-RNcQeNnInumDF1hq3gAf+/A6jhvYDof5a7418gEs/y6359gTYZpTCQkgItC50iV3MmkgerrBAdOE7CDEtQNDWw==", "bundleDependencies": [ "@balena/dockerignore", "case", @@ -21612,7 +21612,7 @@ "@aws-cdk/toolkit-lib": "^0.1.6", "@aws-sdk/client-lambda": "^3.771.0", "@smithy/util-utf8": "^4.0.0", - "aws-cdk-lib": "^2.184.1", + "aws-cdk-lib": "^2.185.0", "esbuild": "^0.25.1", "promise-retry": "^2.0.1" }, diff --git a/packages/testing/package.json b/packages/testing/package.json index 74e6091b35..af4334d075 100644 --- a/packages/testing/package.json +++ b/packages/testing/package.json @@ -100,7 +100,7 @@ "@aws-cdk/toolkit-lib": "^0.1.6", "@aws-sdk/client-lambda": "^3.771.0", "@smithy/util-utf8": "^4.0.0", - "aws-cdk-lib": "^2.184.1", + "aws-cdk-lib": "^2.185.0", "esbuild": "^0.25.1", "promise-retry": "^2.0.1" }, From 42f0cf4215d85f33bfc436aa0f407b0d6d0aba84 Mon Sep 17 00:00:00 2001 From: Alexander Schueren Date: Fri, 21 Mar 2025 12:11:55 +0100 Subject: [PATCH 39/56] chore(layers): add workflows for govcloud layers (#3747) --- .github/workflows/layer_govcloud_verify.yml | 81 +++++++++ .github/workflows/layers_govcloud.yml | 187 ++++++++++++++++++++ docs/index.md | 13 +- 3 files changed, 280 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/layer_govcloud_verify.yml create mode 100644 .github/workflows/layers_govcloud.yml diff --git a/.github/workflows/layer_govcloud_verify.yml b/.github/workflows/layer_govcloud_verify.yml new file mode 100644 index 0000000000..3a4b5f32eb --- /dev/null +++ b/.github/workflows/layer_govcloud_verify.yml @@ -0,0 +1,81 @@ +# GovCloud Layer Verification +# --- +# This workflow queries the GovCloud layer info in production only + +on: + workflow_dispatch: + inputs: + version: + description: Layer version to verify information + type: string + required: true + workflow_call: + inputs: + version: + description: Layer version to verify information + type: string + required: true + +name: Layer Verification (GovCloud) +run-name: Layer Verification (GovCloud) - version ${{ inputs.version }} + +permissions: {} + +jobs: + commercial: + runs-on: ubuntu-latest + permissions: + id-token: write + contents: read + environment: Prod (Readonly) + steps: + - name: Configure AWS Credentials + uses: aws-actions/configure-aws-credentials@ececac1a45f3b08a01d2dd070d28d111c5fe6722 # v4.1.0 + with: + role-to-assume: ${{ secrets.AWS_IAM_ROLE }} + aws-region: us-east-1 + mask-aws-account-id: true + - name: Output AWSLambdaPowertoolsTypeScriptV2 + # fetch the specific layer version information from the us-east-1 commercial region + run: | + aws --region us-east-1 lambda get-layer-version-by-arn --arn 'arn:aws:lambda:us-east-1:094274105915:layer:AWSLambdaPowertoolsTypeScriptV2:${{ inputs.version }}' | jq -r '{"Layer Version Arn": .LayerVersionArn, "Version": .Version, "Description": .Description, "Compatible Runtimes": .CompatibleRuntimes[0], "Compatible Architectures": .CompatibleArchitectures[0], "SHA": .Content.CodeSha256} | keys[] as $k | [$k, .[$k]] | @tsv' | column -t -s $'\t' + + gov_east: + name: Verify (East) + needs: commercial + runs-on: ubuntu-latest + permissions: + id-token: write + contents: read + environment: GovCloud Prod (East) + steps: + - name: Configure AWS Credentials + uses: aws-actions/configure-aws-credentials@ececac1a45f3b08a01d2dd070d28d111c5fe6722 # v4.1.0 + with: + role-to-assume: ${{ secrets.AWS_IAM_ROLE }} + aws-region: us-gov-east-1 + mask-aws-account-id: true + - name: Verify Layer AWSLambdaPowertoolsTypeScriptV2 + id: verify-layer + run: | + aws --region us-gov-east-1 lambda get-layer-version-by-arn --arn 'arn:aws-us-gov:lambda:us-gov-east-1:${{ secrets.AWS_ACCOUNT_ID }}:layer:AWSLambdaPowertoolsTypeScriptV2:${{ inputs.version }}' | jq -r '{"Layer Version Arn": .LayerVersionArn, "Version": .Version, "Description": .Description, "Compatible Runtimes": .CompatibleRuntimes[0], "Compatible Architectures": .CompatibleArchitectures[0], "SHA": .Content.CodeSha256} | keys[] as $k | [$k, .[$k]] | @tsv' | column -t -s $'\t' + + gov_west: + name: Verify (West) + needs: commercial + runs-on: ubuntu-latest + permissions: + id-token: write + contents: read + environment: GovCloud Prod (West) + steps: + - name: Configure AWS Credentials + uses: aws-actions/configure-aws-credentials@ececac1a45f3b08a01d2dd070d28d111c5fe6722 # v4.1.0 + with: + role-to-assume: ${{ secrets.AWS_IAM_ROLE }} + aws-region: us-gov-east-1 + mask-aws-account-id: true + - name: Verify Layer AWSLambdaPowertoolsTypeScriptV2 + id: verify-layer + run: | + aws --region us-gov-west-1 lambda get-layer-version-by-arn --arn 'arn:aws-us-gov:lambda:us-gov-west-1:${{ secrets.AWS_ACCOUNT_ID }}:layer:AWSLambdaPowertoolsTypeScriptV2:${{ inputs.version }}' | jq -r '{"Layer Version Arn": .LayerVersionArn, "Version": .Version, "Description": .Description, "Compatible Runtimes": .CompatibleRuntimes[0], "Compatible Architectures": .CompatibleArchitectures[0], "SHA": .Content.CodeSha256} | keys[] as $k | [$k, .[$k]] | @tsv' | column -t -s $'\t' \ No newline at end of file diff --git a/.github/workflows/layers_govcloud.yml b/.github/workflows/layers_govcloud.yml new file mode 100644 index 0000000000..222219e4af --- /dev/null +++ b/.github/workflows/layers_govcloud.yml @@ -0,0 +1,187 @@ +name: Layer Deployment (GovCloud) + +# GovCloud Layer Publish +# --- +# This workflow publishes a specific layer version in an AWS account based on the environment input. +# +# We pull each the version of the layer and store them as artifacts, the we upload them to each of the GovCloud AWS accounts. +# +# A number of safety checks are performed to ensure safety. + +on: + workflow_dispatch: + inputs: + environment: + description: Deployment environment + type: choice + options: + - Gamma + - Prod + required: true + version: + description: Layer version to duplicate + type: string + required: true + workflow_call: + inputs: + environment: + description: Deployment environment + type: string + required: true + version: + description: Layer version to duplicate + type: string + required: true + +run-name: Layer Deployment (GovCloud) - ${{ inputs.environment }} - version - ${{ inputs.version }} + +permissions: + contents: read + +jobs: + download: + runs-on: ubuntu-latest + permissions: + id-token: write + contents: read + environment: Prod (Readonly) + steps: + - name: Configure AWS Credentials + uses: aws-actions/configure-aws-credentials@ececac1a45f3b08a01d2dd070d28d111c5fe6722 # v4.1.0 + with: + role-to-assume: ${{ secrets.AWS_IAM_ROLE }} + aws-region: us-east-1 + mask-aws-account-id: true + - name: Grab Zip + run: | + aws --region us-east-1 lambda get-layer-version-by-arn --arn arn:aws:lambda:us-east-1:094274105915:layer:AWSLambdaPowertoolsTypeScriptV2:${{ inputs.version }} --query 'Content.Location' | xargs curl -L -o AWSLambdaPowertoolsTypeScriptV2.zip + aws --region us-east-1 lambda get-layer-version-by-arn --arn arn:aws:lambda:us-east-1:094274105915:layer:AWSLambdaPowertoolsTypeScriptV2:${{ inputs.version }} > AWSLambdaPowertoolsTypeScriptV2.json + - name: Store Zip + uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 # v4.6.1 + with: + name: AWSLambdaPowertoolsTypeScriptV2.zip + path: AWSLambdaPowertoolsTypeScriptV2.zip + retention-days: 1 + if-no-files-found: error + - name: Store Metadata + uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 # v4.6.1 + with: + name: AWSLambdaPowertoolsTypeScriptV2.json + path: AWSLambdaPowertoolsTypeScriptV2.json + retention-days: 1 + if-no-files-found: error + + copy_east: + name: Copy (East) + needs: download + runs-on: ubuntu-latest + permissions: + id-token: write + contents: read + environment: GovCloud ${{ inputs.environment }} (East) + steps: + - name: Download Zip + uses: actions/download-artifact@b14cf4c92620c250e1c074ab0a5800e37df86765 # v4.2.0 + with: + name: AWSLambdaPowertoolsTypeScriptV2.zip + - name: Download Metadata + uses: actions/download-artifact@b14cf4c92620c250e1c074ab0a5800e37df86765 # v4.2.0 + with: + name: AWSLambdaPowertoolsTypeScriptV2.json + - name: Verify Layer Signature + run: | + SHA=$(jq -r '.Content.CodeSha256' 'AWSLambdaPowertoolsTypeScriptV2.json') + test "$(openssl dgst -sha256 -binary AWSLambdaPowertoolsTypeScriptV2.zip | openssl enc -base64)" == "$SHA" && echo "SHA OK: ${SHA}" || exit 1 + - name: Configure AWS Credentials + uses: aws-actions/configure-aws-credentials@ececac1a45f3b08a01d2dd070d28d111c5fe6722 # v4.1.0 + with: + role-to-assume: ${{ secrets.AWS_IAM_ROLE }} + aws-region: us-gov-east-1 + mask-aws-account-id: true + - name: Create Layer + id: create-layer + run: | + LAYER_VERSION=$(aws --region us-gov-east-1 lambda publish-layer-version \ + --layer-name AWSLambdaPowertoolsTypeScriptV2 \ + --zip-file fileb://./AWSLambdaPowertoolsTypeScriptV2.zip \ + --compatible-runtimes "$(jq -r '.CompatibleRuntimes[0]' 'AWSLambdaPowertoolsTypeScriptV2.json')" \ + --compatible-architectures "$(jq -r '.CompatibleArchitectures[0]' 'AWSLambdaPowertoolsTypeScriptV2.json')" \ + --license-info "MIT-0" \ + --description "$(jq -r '.Description' 'AWSLambdaPowertoolsTypeScriptV2.json')" \ + --query 'Version' \ + --output text) + + echo "LAYER_VERSION=$LAYER_VERSION" >> "$GITHUB_OUTPUT" + + aws --region us-gov-east-1 lambda add-layer-version-permission \ + --layer-name 'AWSLambdaPowertoolsTypeScriptV2' \ + --statement-id 'PublicLayer' \ + --action lambda:GetLayerVersion \ + --principal '*' \ + --version-number "$LAYER_VERSION" + - name: Verify Layer + env: + LAYER_VERSION: ${{ steps.create-layer.outputs.LAYER_VERSION }} + run: | + REMOTE_SHA=$(aws --region us-gov-east-1 lambda get-layer-version-by-arn --arn 'arn:aws-us-gov:lambda:us-gov-east-1:${{ secrets.AWS_ACCOUNT_ID }}:layer:AWSLambdaPowertoolsTypeScriptV2:${{ env.LAYER_VERSION }}' --query 'Content.CodeSha256' --output text) + SHA=$(jq -r '.Content.CodeSha256' 'AWSLambdaPowertoolsTypeScriptV2.json') + test "$REMOTE_SHA" == "$SHA" && echo "SHA OK: ${SHA}" || exit 1 + aws --region us-gov-east-1 lambda get-layer-version-by-arn --arn 'arn:aws-us-gov:lambda:us-gov-east-1:${{ secrets.AWS_ACCOUNT_ID }}:layer:AWSLambdaPowertoolsTypeScriptV2:${{ env.LAYER_VERSION }}' --output table + + copy_west: + name: Copy (West) + needs: download + runs-on: ubuntu-latest + permissions: + id-token: write + contents: read + environment: + name: GovCloud ${{ inputs.environment }} (West) + steps: + - name: Download Zip + uses: actions/download-artifact@b14cf4c92620c250e1c074ab0a5800e37df86765 # v4.2.0 + with: + name: AWSLambdaPowertoolsTypeScriptV2.zip + - name: Download Metadata + uses: actions/download-artifact@b14cf4c92620c250e1c074ab0a5800e37df86765 # v4.2.0 + with: + name: AWSLambdaPowertoolsTypeScriptV2.json + - name: Verify Layer Signature + run: | + SHA=$(jq -r '.Content.CodeSha256' 'AWSLambdaPowertoolsTypeScriptV2.json') + test "$(openssl dgst -sha256 -binary AWSLambdaPowertoolsTypeScriptV2.zip | openssl enc -base64)" == "$SHA" && echo "SHA OK: ${SHA}" || exit 1 + - name: Configure AWS Credentials + uses: aws-actions/configure-aws-credentials@ececac1a45f3b08a01d2dd070d28d111c5fe6722 # v4.1.0 + with: + role-to-assume: ${{ secrets.AWS_IAM_ROLE }} + aws-region: us-gov-west-1 + mask-aws-account-id: true + - name: Create Layer + id: create-layer + run: | + LAYER_VERSION=$(aws --region us-gov-west-1 lambda publish-layer-version \ + --layer-name AWSLambdaPowertoolsTypeScriptV2 \ + --zip-file fileb://./AWSLambdaPowertoolsTypeScriptV2.zip \ + --compatible-runtimes "$(jq -r '.CompatibleRuntimes[0]' 'AWSLambdaPowertoolsTypeScriptV2.json')" \ + --compatible-architectures "$(jq -r '.CompatibleArchitectures[0]' 'AWSLambdaPowertoolsTypeScriptV2.json')" \ + --license-info "MIT-0" \ + --description "$(jq -r '.Description' 'AWSLambdaPowertoolsTypeScriptV2.json')" \ + --query 'Version' \ + --output text) + + echo "LAYER_VERSION=$LAYER_VERSION" >> "$GITHUB_OUTPUT" + + aws --region us-gov-west-1 lambda add-layer-version-permission \ + --layer-name 'AWSLambdaPowertoolsTypeScriptV2' \ + --statement-id 'PublicLayer' \ + --action lambda:GetLayerVersion \ + --principal '*' \ + --version-number "$LAYER_VERSION" + - name: Verify Layer + env: + LAYER_VERSION: ${{ steps.create-layer.outputs.LAYER_VERSION }} + run: | + REMOTE_SHA=$(aws --region us-gov-west-1 lambda get-layer-version-by-arn --arn 'arn:aws-us-gov:lambda:us-gov-west-1:${{ secrets.AWS_ACCOUNT_ID }}:layer:AWSLambdaPowertoolsTypeScriptV2:${{ env.LAYER_VERSION }}' --query 'Content.CodeSha256' --output text) + SHA=$(jq -r '.Content.CodeSha256' 'AWSLambdaPowertoolsTypeScriptV2.json') + test "$REMOTE_SHA" == "$SHA" && echo "SHA OK: ${SHA}" || exit 1 + aws --region us-gov-west-1 lambda get-layer-version-by-arn --arn 'arn:aws-us-gov:lambda:us-gov-west-1:${{ secrets.AWS_ACCOUNT_ID }}:layer:AWSLambdaPowertoolsTypeScriptV2:${{ env.LAYER_VERSION }}' --output table \ No newline at end of file diff --git a/docs/index.md b/docs/index.md index cb6256f2ba..34afcd44e8 100644 --- a/docs/index.md +++ b/docs/index.md @@ -69,7 +69,9 @@ You can use Powertools for AWS Lambda (TypeScript) by installing it with your fa For the latter, make sure to replace `{region}` with your AWS region, e.g., `eu-west-1`. - __arn:aws:lambda:{region}:094274105915:layer:AWSLambdaPowertoolsTypeScriptV2:22__{: .copyMe}:clipboard: + !!! abstract "" + + __arn:aws:lambda:{region}:094274105915:layer:AWSLambdaPowertoolsTypeScriptV2:22__{: .copyMe}:clipboard: ???+ note "Code snippets for popular infrastructure as code frameworks" @@ -264,6 +266,15 @@ You can use Powertools for AWS Lambda (TypeScript) by installing it with your fa }); ``` +=== "Layer in GovCloud" + + We also provide layers in two GovCloud regions: + + !!! abstract "" + + * __arn:aws-us-gov:lambda:us-gov-east-1:165087284144:layer:AWSLambdaPowertoolsTypeScriptV2:22__{: .copyMe}:clipboard: + * __arn:aws-us-gov:lambda:us-gov-west-1:165093116878:layer:AWSLambdaPowertoolsTypeScriptV2:22__{: .copyMe}:clipboard: + ### Lambda Layer [Lambda Layer](https://docs.aws.amazon.com/lambda/latest/dg/configuration-layers.html){target="_blank"} is a `.zip` file archive that can contain additional code, pre-packaged dependencies, data, or configuration files. We compile and optimize [all dependencies](#install) to achieve an optimal build. From dafa49602ea45227384b63bff4d3f39d69e982d8 Mon Sep 17 00:00:00 2001 From: Simon Thulbourn Date: Fri, 21 Mar 2025 13:20:36 +0100 Subject: [PATCH 40/56] fix(ci): Remove --compatible-architectures from workflow (#3752) --- .github/workflows/layers_govcloud.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/workflows/layers_govcloud.yml b/.github/workflows/layers_govcloud.yml index 222219e4af..790cecc719 100644 --- a/.github/workflows/layers_govcloud.yml +++ b/.github/workflows/layers_govcloud.yml @@ -105,7 +105,6 @@ jobs: --layer-name AWSLambdaPowertoolsTypeScriptV2 \ --zip-file fileb://./AWSLambdaPowertoolsTypeScriptV2.zip \ --compatible-runtimes "$(jq -r '.CompatibleRuntimes[0]' 'AWSLambdaPowertoolsTypeScriptV2.json')" \ - --compatible-architectures "$(jq -r '.CompatibleArchitectures[0]' 'AWSLambdaPowertoolsTypeScriptV2.json')" \ --license-info "MIT-0" \ --description "$(jq -r '.Description' 'AWSLambdaPowertoolsTypeScriptV2.json')" \ --query 'Version' \ @@ -163,7 +162,6 @@ jobs: --layer-name AWSLambdaPowertoolsTypeScriptV2 \ --zip-file fileb://./AWSLambdaPowertoolsTypeScriptV2.zip \ --compatible-runtimes "$(jq -r '.CompatibleRuntimes[0]' 'AWSLambdaPowertoolsTypeScriptV2.json')" \ - --compatible-architectures "$(jq -r '.CompatibleArchitectures[0]' 'AWSLambdaPowertoolsTypeScriptV2.json')" \ --license-info "MIT-0" \ --description "$(jq -r '.Description' 'AWSLambdaPowertoolsTypeScriptV2.json')" \ --query 'Version' \ @@ -184,4 +182,4 @@ jobs: REMOTE_SHA=$(aws --region us-gov-west-1 lambda get-layer-version-by-arn --arn 'arn:aws-us-gov:lambda:us-gov-west-1:${{ secrets.AWS_ACCOUNT_ID }}:layer:AWSLambdaPowertoolsTypeScriptV2:${{ env.LAYER_VERSION }}' --query 'Content.CodeSha256' --output text) SHA=$(jq -r '.Content.CodeSha256' 'AWSLambdaPowertoolsTypeScriptV2.json') test "$REMOTE_SHA" == "$SHA" && echo "SHA OK: ${SHA}" || exit 1 - aws --region us-gov-west-1 lambda get-layer-version-by-arn --arn 'arn:aws-us-gov:lambda:us-gov-west-1:${{ secrets.AWS_ACCOUNT_ID }}:layer:AWSLambdaPowertoolsTypeScriptV2:${{ env.LAYER_VERSION }}' --output table \ No newline at end of file + aws --region us-gov-west-1 lambda get-layer-version-by-arn --arn 'arn:aws-us-gov:lambda:us-gov-west-1:${{ secrets.AWS_ACCOUNT_ID }}:layer:AWSLambdaPowertoolsTypeScriptV2:${{ env.LAYER_VERSION }}' --output table From 29d3f7f4391ce78b45d8059584e5a06097702c8c Mon Sep 17 00:00:00 2001 From: Simon Thulbourn Date: Fri, 21 Mar 2025 15:13:20 +0100 Subject: [PATCH 41/56] chore(ci): fix compat runtimes in govcloud layer creation (#3759) --- .github/workflows/layers_govcloud.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/layers_govcloud.yml b/.github/workflows/layers_govcloud.yml index 790cecc719..92579507ea 100644 --- a/.github/workflows/layers_govcloud.yml +++ b/.github/workflows/layers_govcloud.yml @@ -104,7 +104,7 @@ jobs: LAYER_VERSION=$(aws --region us-gov-east-1 lambda publish-layer-version \ --layer-name AWSLambdaPowertoolsTypeScriptV2 \ --zip-file fileb://./AWSLambdaPowertoolsTypeScriptV2.zip \ - --compatible-runtimes "$(jq -r '.CompatibleRuntimes[0]' 'AWSLambdaPowertoolsTypeScriptV2.json')" \ + --compatible-runtimes "$(echo \"$(jq -r '.CompatibleRuntimes | join(" ")' 'AWSLambdaPowertoolsTypeScriptV2.json')\" | sed -e "s/ /\" \"/g")" \ --license-info "MIT-0" \ --description "$(jq -r '.Description' 'AWSLambdaPowertoolsTypeScriptV2.json')" \ --query 'Version' \ @@ -161,7 +161,7 @@ jobs: LAYER_VERSION=$(aws --region us-gov-west-1 lambda publish-layer-version \ --layer-name AWSLambdaPowertoolsTypeScriptV2 \ --zip-file fileb://./AWSLambdaPowertoolsTypeScriptV2.zip \ - --compatible-runtimes "$(jq -r '.CompatibleRuntimes[0]' 'AWSLambdaPowertoolsTypeScriptV2.json')" \ + --compatible-runtimes "$(echo \"$(jq -r '.CompatibleRuntimes | join(" ")' 'AWSLambdaPowertoolsTypeScriptV2.json')\" | sed -e "s/ /\" \"/g")" \ --license-info "MIT-0" \ --description "$(jq -r '.Description' 'AWSLambdaPowertoolsTypeScriptV2.json')" \ --query 'Version' \ From 9982f29402e56e69500bf494b034534071175013 Mon Sep 17 00:00:00 2001 From: Simon Thulbourn Date: Fri, 21 Mar 2025 15:52:57 +0100 Subject: [PATCH 42/56] chore(ci): switch GovCloud publish-layer-version to --cli-input-json (#3760) --- .github/workflows/layers_govcloud.yml | 40 +++++++++++++++++++-------- 1 file changed, 28 insertions(+), 12 deletions(-) diff --git a/.github/workflows/layers_govcloud.yml b/.github/workflows/layers_govcloud.yml index 92579507ea..6e964fdd09 100644 --- a/.github/workflows/layers_govcloud.yml +++ b/.github/workflows/layers_govcloud.yml @@ -101,12 +101,16 @@ jobs: - name: Create Layer id: create-layer run: | - LAYER_VERSION=$(aws --region us-gov-east-1 lambda publish-layer-version \ - --layer-name AWSLambdaPowertoolsTypeScriptV2 \ + cat AWSLambdaPowertoolsTypeScriptV2.json | jq '{ + "LayerName": "AWSLambdaPowertoolsTypeScriptV2", + "Description": .Description, + "CompatibleRuntimes": .CompatibleRuntimes, + "LicenseInfo": .LicenseInfo + }' > input.json + + LAYER_VERSION=$(aws --region us-gov-west-1 lambda publish-layer-version \ --zip-file fileb://./AWSLambdaPowertoolsTypeScriptV2.zip \ - --compatible-runtimes "$(echo \"$(jq -r '.CompatibleRuntimes | join(" ")' 'AWSLambdaPowertoolsTypeScriptV2.json')\" | sed -e "s/ /\" \"/g")" \ - --license-info "MIT-0" \ - --description "$(jq -r '.Description' 'AWSLambdaPowertoolsTypeScriptV2.json')" \ + --cli-input-json file://./input.json --query 'Version' \ --output text) @@ -125,8 +129,12 @@ jobs: REMOTE_SHA=$(aws --region us-gov-east-1 lambda get-layer-version-by-arn --arn 'arn:aws-us-gov:lambda:us-gov-east-1:${{ secrets.AWS_ACCOUNT_ID }}:layer:AWSLambdaPowertoolsTypeScriptV2:${{ env.LAYER_VERSION }}' --query 'Content.CodeSha256' --output text) SHA=$(jq -r '.Content.CodeSha256' 'AWSLambdaPowertoolsTypeScriptV2.json') test "$REMOTE_SHA" == "$SHA" && echo "SHA OK: ${SHA}" || exit 1 - aws --region us-gov-east-1 lambda get-layer-version-by-arn --arn 'arn:aws-us-gov:lambda:us-gov-east-1:${{ secrets.AWS_ACCOUNT_ID }}:layer:AWSLambdaPowertoolsTypeScriptV2:${{ env.LAYER_VERSION }}' --output table - + aws --region us-gov-east-1 lambda get-layer-version-by-arn --arn 'arn:aws-us-gov:lambda:us-gov-east-1:${{ secrets.AWS_ACCOUNT_ID }}:layer:AWSLambdaPowertoolsTypeScriptV2:${{ env.LAYER_VERSION }}' > govcloud.json + echo ::notice::GovCloud Details + cat govcloud.json | jq -r '{"Layer Version Arn": .LayerVersionArn, "Version": .Version, "Description": .Description, "Compatible Runtimes": .CompatibleRuntimes, "SHA": .Content.CodeSha256} | keys[] as $k | [$k, .[$k]] | @tsv' | column -t -s $'\t' + echo ::notice::Commercial Details + cat AWSLambdaPowertoolsTypeScriptV2.json | jq -r '{"Layer Version Arn": .LayerVersionArn, "Version": .Version, "Description": .Description, "Compatible Runtimes": .CompatibleRuntimes, "SHA": .Content.CodeSha256} | keys[] as $k | [$k, .[$k]] | @tsv' | column -t -s $'\t' + copy_west: name: Copy (West) needs: download @@ -158,12 +166,16 @@ jobs: - name: Create Layer id: create-layer run: | + cat AWSLambdaPowertoolsTypeScriptV2.json | jq '{ + "LayerName": "AWSLambdaPowertoolsTypeScriptV2", + "Description": .Description, + "CompatibleRuntimes": .CompatibleRuntimes, + "LicenseInfo": .LicenseInfo + }' > input.json + LAYER_VERSION=$(aws --region us-gov-west-1 lambda publish-layer-version \ - --layer-name AWSLambdaPowertoolsTypeScriptV2 \ --zip-file fileb://./AWSLambdaPowertoolsTypeScriptV2.zip \ - --compatible-runtimes "$(echo \"$(jq -r '.CompatibleRuntimes | join(" ")' 'AWSLambdaPowertoolsTypeScriptV2.json')\" | sed -e "s/ /\" \"/g")" \ - --license-info "MIT-0" \ - --description "$(jq -r '.Description' 'AWSLambdaPowertoolsTypeScriptV2.json')" \ + --cli-input-json file://./input.json --query 'Version' \ --output text) @@ -182,4 +194,8 @@ jobs: REMOTE_SHA=$(aws --region us-gov-west-1 lambda get-layer-version-by-arn --arn 'arn:aws-us-gov:lambda:us-gov-west-1:${{ secrets.AWS_ACCOUNT_ID }}:layer:AWSLambdaPowertoolsTypeScriptV2:${{ env.LAYER_VERSION }}' --query 'Content.CodeSha256' --output text) SHA=$(jq -r '.Content.CodeSha256' 'AWSLambdaPowertoolsTypeScriptV2.json') test "$REMOTE_SHA" == "$SHA" && echo "SHA OK: ${SHA}" || exit 1 - aws --region us-gov-west-1 lambda get-layer-version-by-arn --arn 'arn:aws-us-gov:lambda:us-gov-west-1:${{ secrets.AWS_ACCOUNT_ID }}:layer:AWSLambdaPowertoolsTypeScriptV2:${{ env.LAYER_VERSION }}' --output table + aws --region us-gov-west-1 lambda get-layer-version-by-arn --arn 'arn:aws-us-gov:lambda:us-gov-west-1:${{ secrets.AWS_ACCOUNT_ID }}:layer:AWSLambdaPowertoolsTypeScriptV2:${{ env.LAYER_VERSION }}' > govcloud.json + echo ::notice::GovCloud Details + cat govcloud.json | jq -r '{"Layer Version Arn": .LayerVersionArn, "Version": .Version, "Description": .Description, "Compatible Runtimes": .CompatibleRuntimes, "SHA": .Content.CodeSha256} | keys[] as $k | [$k, .[$k]] | @tsv' | column -t -s $'\t' + echo ::notice::Commercial Details + cat AWSLambdaPowertoolsTypeScriptV2.json | jq -r '{"Layer Version Arn": .LayerVersionArn, "Version": .Version, "Description": .Description, "Compatible Runtimes": .CompatibleRuntimes, "SHA": .Content.CodeSha256} | keys[] as $k | [$k, .[$k]] | @tsv' | column -t -s $'\t' From 505d4546f7fc1fd22fa26c1aafd468a8951c56f4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 21 Mar 2025 16:18:04 +0100 Subject: [PATCH 43/56] chore(deps): bump actions/upload-artifact from 4.6.1 to 4.6.2 (#3755) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/layers_govcloud.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/layers_govcloud.yml b/.github/workflows/layers_govcloud.yml index 6e964fdd09..b043be75af 100644 --- a/.github/workflows/layers_govcloud.yml +++ b/.github/workflows/layers_govcloud.yml @@ -57,14 +57,14 @@ jobs: aws --region us-east-1 lambda get-layer-version-by-arn --arn arn:aws:lambda:us-east-1:094274105915:layer:AWSLambdaPowertoolsTypeScriptV2:${{ inputs.version }} --query 'Content.Location' | xargs curl -L -o AWSLambdaPowertoolsTypeScriptV2.zip aws --region us-east-1 lambda get-layer-version-by-arn --arn arn:aws:lambda:us-east-1:094274105915:layer:AWSLambdaPowertoolsTypeScriptV2:${{ inputs.version }} > AWSLambdaPowertoolsTypeScriptV2.json - name: Store Zip - uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 # v4.6.1 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 with: name: AWSLambdaPowertoolsTypeScriptV2.zip path: AWSLambdaPowertoolsTypeScriptV2.zip retention-days: 1 if-no-files-found: error - name: Store Metadata - uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 # v4.6.1 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 with: name: AWSLambdaPowertoolsTypeScriptV2.json path: AWSLambdaPowertoolsTypeScriptV2.json From 6492d3fbb247947bf21dbd48086d34de32783808 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 21 Mar 2025 16:41:42 +0100 Subject: [PATCH 44/56] chore(deps): bump @types/node from 22.13.10 to 22.13.11 (#3758) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Andrea Amorosi --- examples/app/package.json | 4 ++-- package-lock.json | 12 ++++++------ package.json | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/examples/app/package.json b/examples/app/package.json index c69453785a..2dd7f84889 100644 --- a/examples/app/package.json +++ b/examples/app/package.json @@ -29,7 +29,7 @@ }, "devDependencies": { "@types/aws-lambda": "^8.10.147", - "@types/node": "22.13.10", + "@types/node": "22.13.11", "aws-cdk-lib": "^2.185.0", "constructs": "^10.4.2", "source-map-support": "^0.5.21", @@ -48,7 +48,7 @@ "@aws-sdk/lib-dynamodb": "^3.767.0", "@middy/core": "^4.7.0", "@types/aws-lambda": "^8.10.147", - "@types/node": "22.13.10", + "@types/node": "22.13.11", "aws-cdk": "^2.1005.0", "constructs": "^10.4.2", "esbuild": "^0.25.1", diff --git a/package-lock.json b/package-lock.json index de7f04a34e..0fe8a719a5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -28,7 +28,7 @@ "devDependencies": { "@biomejs/biome": "^1.9.4", "@types/aws-lambda": "^8.10.147", - "@types/node": "^22.13.10", + "@types/node": "^22.13.11", "@vitest/coverage-v8": "^3.0.9", "husky": "^9.1.7", "lerna": "8.1.2", @@ -62,7 +62,7 @@ "@aws-sdk/lib-dynamodb": "^3.767.0", "@middy/core": "^4.7.0", "@types/aws-lambda": "^8.10.147", - "@types/node": "22.13.10", + "@types/node": "22.13.11", "aws-cdk": "^2.1005.0", "constructs": "^10.4.2", "esbuild": "^0.25.1", @@ -70,7 +70,7 @@ }, "devDependencies": { "@types/aws-lambda": "^8.10.147", - "@types/node": "22.13.10", + "@types/node": "22.13.11", "aws-cdk-lib": "^2.185.0", "constructs": "^10.4.2", "source-map-support": "^0.5.21", @@ -10024,9 +10024,9 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "22.13.10", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.13.10.tgz", - "integrity": "sha512-I6LPUvlRH+O6VRUqYOcMudhaIdUVWfsjnZavnsraHvpBwaEyMN29ry+0UVJhImYL16xsscu0aske3yA+uPOWfw==", + "version": "22.13.11", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.13.11.tgz", + "integrity": "sha512-iEUCUJoU0i3VnrCmgoWCXttklWcvoCIx4jzcP22fioIVSdTmjgoEvmAO/QPw6TcS9k5FrNgn4w7q5lGOd1CT5g==", "license": "MIT", "dependencies": { "undici-types": "~6.20.0" diff --git a/package.json b/package.json index bef9e2663d..4f7b499f94 100644 --- a/package.json +++ b/package.json @@ -52,7 +52,7 @@ "devDependencies": { "@biomejs/biome": "^1.9.4", "@types/aws-lambda": "^8.10.147", - "@types/node": "^22.13.10", + "@types/node": "^22.13.11", "@vitest/coverage-v8": "^3.0.9", "husky": "^9.1.7", "lerna": "8.1.2", From 6c443ba44d3ec2569422d1dba5d3d49bfa88a7a7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 21 Mar 2025 16:50:08 +0100 Subject: [PATCH 45/56] chore(deps): bump actions/download-artifact from 4.2.0 to 4.2.1 (#3756) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Andrea Amorosi --- .github/workflows/layers_govcloud.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/layers_govcloud.yml b/.github/workflows/layers_govcloud.yml index b043be75af..f8d23f1ec3 100644 --- a/.github/workflows/layers_govcloud.yml +++ b/.github/workflows/layers_govcloud.yml @@ -81,11 +81,11 @@ jobs: environment: GovCloud ${{ inputs.environment }} (East) steps: - name: Download Zip - uses: actions/download-artifact@b14cf4c92620c250e1c074ab0a5800e37df86765 # v4.2.0 + uses: actions/download-artifact@95815c38cf2ff2164869cbab79da8d1f422bc89e # v4.2.1 with: name: AWSLambdaPowertoolsTypeScriptV2.zip - name: Download Metadata - uses: actions/download-artifact@b14cf4c92620c250e1c074ab0a5800e37df86765 # v4.2.0 + uses: actions/download-artifact@95815c38cf2ff2164869cbab79da8d1f422bc89e # v4.2.1 with: name: AWSLambdaPowertoolsTypeScriptV2.json - name: Verify Layer Signature @@ -146,11 +146,11 @@ jobs: name: GovCloud ${{ inputs.environment }} (West) steps: - name: Download Zip - uses: actions/download-artifact@b14cf4c92620c250e1c074ab0a5800e37df86765 # v4.2.0 + uses: actions/download-artifact@95815c38cf2ff2164869cbab79da8d1f422bc89e # v4.2.1 with: name: AWSLambdaPowertoolsTypeScriptV2.zip - name: Download Metadata - uses: actions/download-artifact@b14cf4c92620c250e1c074ab0a5800e37df86765 # v4.2.0 + uses: actions/download-artifact@95815c38cf2ff2164869cbab79da8d1f422bc89e # v4.2.1 with: name: AWSLambdaPowertoolsTypeScriptV2.json - name: Verify Layer Signature From 1ed25e8b12a61c93b4a92df6eeaac9d32fb0e67c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 21 Mar 2025 16:55:42 +0100 Subject: [PATCH 46/56] chore(deps): bump the aws-sdk-v3 group across 1 directory with 9 updates (#3757) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Andrea Amorosi --- examples/app/package.json | 4 +- examples/snippets/package.json | 10 +- package-lock.json | 2087 +++++++++++++++++++++++++---- packages/idempotency/package.json | 4 +- packages/metrics/package.json | 2 +- packages/parameters/package.json | 10 +- packages/testing/package.json | 2 +- packages/tracer/package.json | 4 +- 8 files changed, 1819 insertions(+), 304 deletions(-) diff --git a/examples/app/package.json b/examples/app/package.json index 2dd7f84889..0b35cd97e5 100644 --- a/examples/app/package.json +++ b/examples/app/package.json @@ -44,8 +44,8 @@ "@aws-lambda-powertools/metrics": "^2.16.0", "@aws-lambda-powertools/parameters": "^2.16.0", "@aws-lambda-powertools/tracer": "^2.16.0", - "@aws-sdk/client-ssm": "^3.759.0", - "@aws-sdk/lib-dynamodb": "^3.767.0", + "@aws-sdk/client-ssm": "^3.772.0", + "@aws-sdk/lib-dynamodb": "^3.772.0", "@middy/core": "^4.7.0", "@types/aws-lambda": "^8.10.147", "@types/node": "22.13.11", diff --git a/examples/snippets/package.json b/examples/snippets/package.json index 8f9e4e18d4..ecf240b427 100644 --- a/examples/snippets/package.json +++ b/examples/snippets/package.json @@ -32,11 +32,11 @@ "@aws-lambda-powertools/parameters": "^2.16.0", "@aws-lambda-powertools/parser": "^2.16.0", "@aws-lambda-powertools/tracer": "^2.16.0", - "@aws-sdk/client-appconfigdata": "^3.758.0", - "@aws-sdk/client-dynamodb": "^3.767.0", - "@aws-sdk/client-secrets-manager": "^3.758.0", - "@aws-sdk/client-ssm": "^3.759.0", - "@aws-sdk/util-dynamodb": "^3.767.0", + "@aws-sdk/client-appconfigdata": "^3.772.0", + "@aws-sdk/client-dynamodb": "^3.772.0", + "@aws-sdk/client-secrets-manager": "^3.772.0", + "@aws-sdk/client-ssm": "^3.772.0", + "@aws-sdk/util-dynamodb": "^3.772.0", "@middy/core": "^4.7.0", "aws-sdk": "^2.1692.0", "aws-sdk-client-mock": "^4.1.0", diff --git a/package-lock.json b/package-lock.json index 0fe8a719a5..18f2c3a497 100644 --- a/package-lock.json +++ b/package-lock.json @@ -58,8 +58,8 @@ "@aws-lambda-powertools/metrics": "^2.16.0", "@aws-lambda-powertools/parameters": "^2.16.0", "@aws-lambda-powertools/tracer": "^2.16.0", - "@aws-sdk/client-ssm": "^3.759.0", - "@aws-sdk/lib-dynamodb": "^3.767.0", + "@aws-sdk/client-ssm": "^3.772.0", + "@aws-sdk/lib-dynamodb": "^3.772.0", "@middy/core": "^4.7.0", "@types/aws-lambda": "^8.10.147", "@types/node": "22.13.11", @@ -92,11 +92,11 @@ "@aws-lambda-powertools/parameters": "^2.16.0", "@aws-lambda-powertools/parser": "^2.16.0", "@aws-lambda-powertools/tracer": "^2.16.0", - "@aws-sdk/client-appconfigdata": "^3.758.0", - "@aws-sdk/client-dynamodb": "^3.767.0", - "@aws-sdk/client-secrets-manager": "^3.758.0", - "@aws-sdk/client-ssm": "^3.759.0", - "@aws-sdk/util-dynamodb": "^3.767.0", + "@aws-sdk/client-appconfigdata": "^3.772.0", + "@aws-sdk/client-dynamodb": "^3.772.0", + "@aws-sdk/client-secrets-manager": "^3.772.0", + "@aws-sdk/client-ssm": "^3.772.0", + "@aws-sdk/util-dynamodb": "^3.772.0", "@middy/core": "^4.7.0", "aws-sdk": "^2.1692.0", "aws-sdk-client-mock": "^4.1.0", @@ -880,19 +880,19 @@ "link": true }, "node_modules/@aws-sdk/client-appconfigdata": { - "version": "3.758.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-appconfigdata/-/client-appconfigdata-3.758.0.tgz", - "integrity": "sha512-/c3i4p29ry3RCQXEhGOrYLW0ropDqgrMZ0/OS4bhbl6VaPQwSkhzgO1jiA7RNKmxjblcUwa0HDPwgVOGWxkH+Q==", + "version": "3.772.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-appconfigdata/-/client-appconfigdata-3.772.0.tgz", + "integrity": "sha512-Iv/AganfpN/LfnkxLf9bZC8YL5PCgbxFRR9qdKcur/i6JkMB/sI1xj+4tf5bctj3rRdVEXIyYdparV+cvpDv2g==", "dev": true, "license": "Apache-2.0", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.758.0", - "@aws-sdk/credential-provider-node": "3.758.0", + "@aws-sdk/credential-provider-node": "3.772.0", "@aws-sdk/middleware-host-header": "3.734.0", "@aws-sdk/middleware-logger": "3.734.0", - "@aws-sdk/middleware-recursion-detection": "3.734.0", + "@aws-sdk/middleware-recursion-detection": "3.772.0", "@aws-sdk/middleware-user-agent": "3.758.0", "@aws-sdk/region-config-resolver": "3.734.0", "@aws-sdk/types": "3.734.0", @@ -931,6 +931,227 @@ "node": ">=18.0.0" } }, + "node_modules/@aws-sdk/client-appconfigdata/node_modules/@aws-sdk/client-sso": { + "version": "3.772.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.772.0.tgz", + "integrity": "sha512-sDdxepi74+cL6gXJJ2yw3UNSI7GBvoGTwZqFyPoNAzcURvaYwo8dBr7G4jS9GDanjTlO3CGVAf2VMcpqEvmoEw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "3.758.0", + "@aws-sdk/middleware-host-header": "3.734.0", + "@aws-sdk/middleware-logger": "3.734.0", + "@aws-sdk/middleware-recursion-detection": "3.772.0", + "@aws-sdk/middleware-user-agent": "3.758.0", + "@aws-sdk/region-config-resolver": "3.734.0", + "@aws-sdk/types": "3.734.0", + "@aws-sdk/util-endpoints": "3.743.0", + "@aws-sdk/util-user-agent-browser": "3.734.0", + "@aws-sdk/util-user-agent-node": "3.758.0", + "@smithy/config-resolver": "^4.0.1", + "@smithy/core": "^3.1.5", + "@smithy/fetch-http-handler": "^5.0.1", + "@smithy/hash-node": "^4.0.1", + "@smithy/invalid-dependency": "^4.0.1", + "@smithy/middleware-content-length": "^4.0.1", + "@smithy/middleware-endpoint": "^4.0.6", + "@smithy/middleware-retry": "^4.0.7", + "@smithy/middleware-serde": "^4.0.2", + "@smithy/middleware-stack": "^4.0.1", + "@smithy/node-config-provider": "^4.0.1", + "@smithy/node-http-handler": "^4.0.3", + "@smithy/protocol-http": "^5.0.1", + "@smithy/smithy-client": "^4.1.6", + "@smithy/types": "^4.1.0", + "@smithy/url-parser": "^4.0.1", + "@smithy/util-base64": "^4.0.0", + "@smithy/util-body-length-browser": "^4.0.0", + "@smithy/util-body-length-node": "^4.0.0", + "@smithy/util-defaults-mode-browser": "^4.0.7", + "@smithy/util-defaults-mode-node": "^4.0.7", + "@smithy/util-endpoints": "^3.0.1", + "@smithy/util-middleware": "^4.0.1", + "@smithy/util-retry": "^4.0.1", + "@smithy/util-utf8": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-appconfigdata/node_modules/@aws-sdk/credential-provider-ini": { + "version": "3.772.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.772.0.tgz", + "integrity": "sha512-T1Ec9Q25zl5c/eZUPHZsiq8vgBeWBjHM7WM5xtZszZRPqqhQGnmFlomz1r9rwhW8RFB5k8HRaD/SLKo6jtYl/A==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.758.0", + "@aws-sdk/credential-provider-env": "3.758.0", + "@aws-sdk/credential-provider-http": "3.758.0", + "@aws-sdk/credential-provider-process": "3.758.0", + "@aws-sdk/credential-provider-sso": "3.772.0", + "@aws-sdk/credential-provider-web-identity": "3.772.0", + "@aws-sdk/nested-clients": "3.772.0", + "@aws-sdk/types": "3.734.0", + "@smithy/credential-provider-imds": "^4.0.1", + "@smithy/property-provider": "^4.0.1", + "@smithy/shared-ini-file-loader": "^4.0.1", + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-appconfigdata/node_modules/@aws-sdk/credential-provider-node": { + "version": "3.772.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.772.0.tgz", + "integrity": "sha512-0IdVfjBO88Mtekq/KaScYSIEPIeR+ABRvBOWyj/c/qQ2KJyI0GRlSAzpANfxDLHVPn3yEHuZd9nRL6sOmOMI0A==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/credential-provider-env": "3.758.0", + "@aws-sdk/credential-provider-http": "3.758.0", + "@aws-sdk/credential-provider-ini": "3.772.0", + "@aws-sdk/credential-provider-process": "3.758.0", + "@aws-sdk/credential-provider-sso": "3.772.0", + "@aws-sdk/credential-provider-web-identity": "3.772.0", + "@aws-sdk/types": "3.734.0", + "@smithy/credential-provider-imds": "^4.0.1", + "@smithy/property-provider": "^4.0.1", + "@smithy/shared-ini-file-loader": "^4.0.1", + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-appconfigdata/node_modules/@aws-sdk/credential-provider-sso": { + "version": "3.772.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.772.0.tgz", + "integrity": "sha512-yR3Y5RAVPa4ogojcBOpZUx6XyRVAkynIJCjd0avdlxW1hhnzSr5/pzoiJ6u21UCbkxlJJTDZE3jfFe7tt+HA4w==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/client-sso": "3.772.0", + "@aws-sdk/core": "3.758.0", + "@aws-sdk/token-providers": "3.772.0", + "@aws-sdk/types": "3.734.0", + "@smithy/property-provider": "^4.0.1", + "@smithy/shared-ini-file-loader": "^4.0.1", + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-appconfigdata/node_modules/@aws-sdk/credential-provider-web-identity": { + "version": "3.772.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.772.0.tgz", + "integrity": "sha512-yHAT5Y2y0fnecSuWRUn8NMunKfDqFYhnOpGq8UyCEcwz9aXzibU0hqRIEm51qpR81hqo0GMFDH0EOmegZ/iW5w==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.758.0", + "@aws-sdk/nested-clients": "3.772.0", + "@aws-sdk/types": "3.734.0", + "@smithy/property-provider": "^4.0.1", + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-appconfigdata/node_modules/@aws-sdk/middleware-recursion-detection": { + "version": "3.772.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.772.0.tgz", + "integrity": "sha512-zg0LjJa4v7fcLzn5QzZvtVS+qyvmsnu7oQnb86l6ckduZpWDCDC9+A0ZzcXTrxblPCJd3JqkoG1+Gzi4S4Ny/Q==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.734.0", + "@smithy/protocol-http": "^5.0.1", + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-appconfigdata/node_modules/@aws-sdk/nested-clients": { + "version": "3.772.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/nested-clients/-/nested-clients-3.772.0.tgz", + "integrity": "sha512-gNJbBxR5YlEumsCS9EWWEASXEnysL0aDnr9MNPX1ip/g1xOqRHmytgV/+t8RFZFTKg0OprbWTq5Ich3MqsEuCQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "3.758.0", + "@aws-sdk/middleware-host-header": "3.734.0", + "@aws-sdk/middleware-logger": "3.734.0", + "@aws-sdk/middleware-recursion-detection": "3.772.0", + "@aws-sdk/middleware-user-agent": "3.758.0", + "@aws-sdk/region-config-resolver": "3.734.0", + "@aws-sdk/types": "3.734.0", + "@aws-sdk/util-endpoints": "3.743.0", + "@aws-sdk/util-user-agent-browser": "3.734.0", + "@aws-sdk/util-user-agent-node": "3.758.0", + "@smithy/config-resolver": "^4.0.1", + "@smithy/core": "^3.1.5", + "@smithy/fetch-http-handler": "^5.0.1", + "@smithy/hash-node": "^4.0.1", + "@smithy/invalid-dependency": "^4.0.1", + "@smithy/middleware-content-length": "^4.0.1", + "@smithy/middleware-endpoint": "^4.0.6", + "@smithy/middleware-retry": "^4.0.7", + "@smithy/middleware-serde": "^4.0.2", + "@smithy/middleware-stack": "^4.0.1", + "@smithy/node-config-provider": "^4.0.1", + "@smithy/node-http-handler": "^4.0.3", + "@smithy/protocol-http": "^5.0.1", + "@smithy/smithy-client": "^4.1.6", + "@smithy/types": "^4.1.0", + "@smithy/url-parser": "^4.0.1", + "@smithy/util-base64": "^4.0.0", + "@smithy/util-body-length-browser": "^4.0.0", + "@smithy/util-body-length-node": "^4.0.0", + "@smithy/util-defaults-mode-browser": "^4.0.7", + "@smithy/util-defaults-mode-node": "^4.0.7", + "@smithy/util-endpoints": "^3.0.1", + "@smithy/util-middleware": "^4.0.1", + "@smithy/util-retry": "^4.0.1", + "@smithy/util-utf8": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-appconfigdata/node_modules/@aws-sdk/token-providers": { + "version": "3.772.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.772.0.tgz", + "integrity": "sha512-d1Waa1vyebuokcAWYlkZdtFlciIgob7B39vPRmtxMObbGumJKiOy/qCe2/FB/72h1Ej9Ih32lwvbxUjORQWN4g==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/nested-clients": "3.772.0", + "@aws-sdk/types": "3.734.0", + "@smithy/property-provider": "^4.0.1", + "@smithy/shared-ini-file-loader": "^4.0.1", + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, "node_modules/@aws-sdk/client-appsync": { "version": "3.741.0", "resolved": "https://registry.npmjs.org/@aws-sdk/client-appsync/-/client-appsync-3.741.0.tgz", @@ -2082,19 +2303,19 @@ } }, "node_modules/@aws-sdk/client-cloudwatch": { - "version": "3.758.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-cloudwatch/-/client-cloudwatch-3.758.0.tgz", - "integrity": "sha512-A4l/gMNqsyCpzgobPcBAEc6WAGWlv5B8WaBJ6YpCKbDwUFLBSbGYFHDIlDrUHfQWq8A3O1rz/oUjjnLeHf07EA==", + "version": "3.772.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-cloudwatch/-/client-cloudwatch-3.772.0.tgz", + "integrity": "sha512-eVEsD7f5RQLs9DTAniGBDcooXMIdmDqs4hPNU5ReM7xppNi/P1vExTpfIM2wkDh9OI1bGG3WSt37UdtstPs14g==", "dev": true, "license": "Apache-2.0", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.758.0", - "@aws-sdk/credential-provider-node": "3.758.0", + "@aws-sdk/credential-provider-node": "3.772.0", "@aws-sdk/middleware-host-header": "3.734.0", "@aws-sdk/middleware-logger": "3.734.0", - "@aws-sdk/middleware-recursion-detection": "3.734.0", + "@aws-sdk/middleware-recursion-detection": "3.772.0", "@aws-sdk/middleware-user-agent": "3.758.0", "@aws-sdk/region-config-resolver": "3.734.0", "@aws-sdk/types": "3.734.0", @@ -2520,46 +2741,46 @@ } } }, - "node_modules/@aws-sdk/client-codebuild": { - "version": "3.741.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-codebuild/-/client-codebuild-3.741.0.tgz", - "integrity": "sha512-oHKptRuG6MNKj75EEsOzndRqLrZBoi+LYSkNXKdSlDN8Pes+bua1Zu5Ex3iM4rAYqN390pD7P4avOz/SDcMLHg==", + "node_modules/@aws-sdk/client-cloudwatch/node_modules/@aws-sdk/client-sso": { + "version": "3.772.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.772.0.tgz", + "integrity": "sha512-sDdxepi74+cL6gXJJ2yw3UNSI7GBvoGTwZqFyPoNAzcURvaYwo8dBr7G4jS9GDanjTlO3CGVAf2VMcpqEvmoEw==", + "dev": true, "license": "Apache-2.0", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "3.734.0", - "@aws-sdk/credential-provider-node": "3.741.0", + "@aws-sdk/core": "3.758.0", "@aws-sdk/middleware-host-header": "3.734.0", "@aws-sdk/middleware-logger": "3.734.0", - "@aws-sdk/middleware-recursion-detection": "3.734.0", - "@aws-sdk/middleware-user-agent": "3.734.0", + "@aws-sdk/middleware-recursion-detection": "3.772.0", + "@aws-sdk/middleware-user-agent": "3.758.0", "@aws-sdk/region-config-resolver": "3.734.0", "@aws-sdk/types": "3.734.0", - "@aws-sdk/util-endpoints": "3.734.0", + "@aws-sdk/util-endpoints": "3.743.0", "@aws-sdk/util-user-agent-browser": "3.734.0", - "@aws-sdk/util-user-agent-node": "3.734.0", + "@aws-sdk/util-user-agent-node": "3.758.0", "@smithy/config-resolver": "^4.0.1", - "@smithy/core": "^3.1.1", + "@smithy/core": "^3.1.5", "@smithy/fetch-http-handler": "^5.0.1", "@smithy/hash-node": "^4.0.1", "@smithy/invalid-dependency": "^4.0.1", "@smithy/middleware-content-length": "^4.0.1", - "@smithy/middleware-endpoint": "^4.0.2", - "@smithy/middleware-retry": "^4.0.3", - "@smithy/middleware-serde": "^4.0.1", + "@smithy/middleware-endpoint": "^4.0.6", + "@smithy/middleware-retry": "^4.0.7", + "@smithy/middleware-serde": "^4.0.2", "@smithy/middleware-stack": "^4.0.1", "@smithy/node-config-provider": "^4.0.1", - "@smithy/node-http-handler": "^4.0.2", + "@smithy/node-http-handler": "^4.0.3", "@smithy/protocol-http": "^5.0.1", - "@smithy/smithy-client": "^4.1.2", + "@smithy/smithy-client": "^4.1.6", "@smithy/types": "^4.1.0", "@smithy/url-parser": "^4.0.1", "@smithy/util-base64": "^4.0.0", "@smithy/util-body-length-browser": "^4.0.0", "@smithy/util-body-length-node": "^4.0.0", - "@smithy/util-defaults-mode-browser": "^4.0.3", - "@smithy/util-defaults-mode-node": "^4.0.3", + "@smithy/util-defaults-mode-browser": "^4.0.7", + "@smithy/util-defaults-mode-node": "^4.0.7", "@smithy/util-endpoints": "^3.0.1", "@smithy/util-middleware": "^4.0.1", "@smithy/util-retry": "^4.0.1", @@ -2570,44 +2791,265 @@ "node": ">=18.0.0" } }, - "node_modules/@aws-sdk/client-codebuild/node_modules/@aws-sdk/client-sso": { - "version": "3.734.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.734.0.tgz", - "integrity": "sha512-oerepp0mut9VlgTwnG5Ds/lb0C0b2/rQ+hL/rF6q+HGKPfGsCuPvFx1GtwGKCXd49ase88/jVgrhcA9OQbz3kg==", + "node_modules/@aws-sdk/client-cloudwatch/node_modules/@aws-sdk/credential-provider-ini": { + "version": "3.772.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.772.0.tgz", + "integrity": "sha512-T1Ec9Q25zl5c/eZUPHZsiq8vgBeWBjHM7WM5xtZszZRPqqhQGnmFlomz1r9rwhW8RFB5k8HRaD/SLKo6jtYl/A==", + "dev": true, "license": "Apache-2.0", "dependencies": { - "@aws-crypto/sha256-browser": "5.2.0", - "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "3.734.0", - "@aws-sdk/middleware-host-header": "3.734.0", - "@aws-sdk/middleware-logger": "3.734.0", - "@aws-sdk/middleware-recursion-detection": "3.734.0", - "@aws-sdk/middleware-user-agent": "3.734.0", - "@aws-sdk/region-config-resolver": "3.734.0", + "@aws-sdk/core": "3.758.0", + "@aws-sdk/credential-provider-env": "3.758.0", + "@aws-sdk/credential-provider-http": "3.758.0", + "@aws-sdk/credential-provider-process": "3.758.0", + "@aws-sdk/credential-provider-sso": "3.772.0", + "@aws-sdk/credential-provider-web-identity": "3.772.0", + "@aws-sdk/nested-clients": "3.772.0", "@aws-sdk/types": "3.734.0", - "@aws-sdk/util-endpoints": "3.734.0", - "@aws-sdk/util-user-agent-browser": "3.734.0", - "@aws-sdk/util-user-agent-node": "3.734.0", - "@smithy/config-resolver": "^4.0.1", - "@smithy/core": "^3.1.1", - "@smithy/fetch-http-handler": "^5.0.1", - "@smithy/hash-node": "^4.0.1", - "@smithy/invalid-dependency": "^4.0.1", - "@smithy/middleware-content-length": "^4.0.1", - "@smithy/middleware-endpoint": "^4.0.2", - "@smithy/middleware-retry": "^4.0.3", - "@smithy/middleware-serde": "^4.0.1", - "@smithy/middleware-stack": "^4.0.1", - "@smithy/node-config-provider": "^4.0.1", - "@smithy/node-http-handler": "^4.0.2", - "@smithy/protocol-http": "^5.0.1", - "@smithy/smithy-client": "^4.1.2", + "@smithy/credential-provider-imds": "^4.0.1", + "@smithy/property-provider": "^4.0.1", + "@smithy/shared-ini-file-loader": "^4.0.1", "@smithy/types": "^4.1.0", - "@smithy/url-parser": "^4.0.1", - "@smithy/util-base64": "^4.0.0", - "@smithy/util-body-length-browser": "^4.0.0", - "@smithy/util-body-length-node": "^4.0.0", - "@smithy/util-defaults-mode-browser": "^4.0.3", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-cloudwatch/node_modules/@aws-sdk/credential-provider-node": { + "version": "3.772.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.772.0.tgz", + "integrity": "sha512-0IdVfjBO88Mtekq/KaScYSIEPIeR+ABRvBOWyj/c/qQ2KJyI0GRlSAzpANfxDLHVPn3yEHuZd9nRL6sOmOMI0A==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/credential-provider-env": "3.758.0", + "@aws-sdk/credential-provider-http": "3.758.0", + "@aws-sdk/credential-provider-ini": "3.772.0", + "@aws-sdk/credential-provider-process": "3.758.0", + "@aws-sdk/credential-provider-sso": "3.772.0", + "@aws-sdk/credential-provider-web-identity": "3.772.0", + "@aws-sdk/types": "3.734.0", + "@smithy/credential-provider-imds": "^4.0.1", + "@smithy/property-provider": "^4.0.1", + "@smithy/shared-ini-file-loader": "^4.0.1", + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-cloudwatch/node_modules/@aws-sdk/credential-provider-sso": { + "version": "3.772.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.772.0.tgz", + "integrity": "sha512-yR3Y5RAVPa4ogojcBOpZUx6XyRVAkynIJCjd0avdlxW1hhnzSr5/pzoiJ6u21UCbkxlJJTDZE3jfFe7tt+HA4w==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/client-sso": "3.772.0", + "@aws-sdk/core": "3.758.0", + "@aws-sdk/token-providers": "3.772.0", + "@aws-sdk/types": "3.734.0", + "@smithy/property-provider": "^4.0.1", + "@smithy/shared-ini-file-loader": "^4.0.1", + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-cloudwatch/node_modules/@aws-sdk/credential-provider-web-identity": { + "version": "3.772.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.772.0.tgz", + "integrity": "sha512-yHAT5Y2y0fnecSuWRUn8NMunKfDqFYhnOpGq8UyCEcwz9aXzibU0hqRIEm51qpR81hqo0GMFDH0EOmegZ/iW5w==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.758.0", + "@aws-sdk/nested-clients": "3.772.0", + "@aws-sdk/types": "3.734.0", + "@smithy/property-provider": "^4.0.1", + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-cloudwatch/node_modules/@aws-sdk/middleware-recursion-detection": { + "version": "3.772.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.772.0.tgz", + "integrity": "sha512-zg0LjJa4v7fcLzn5QzZvtVS+qyvmsnu7oQnb86l6ckduZpWDCDC9+A0ZzcXTrxblPCJd3JqkoG1+Gzi4S4Ny/Q==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.734.0", + "@smithy/protocol-http": "^5.0.1", + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-cloudwatch/node_modules/@aws-sdk/nested-clients": { + "version": "3.772.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/nested-clients/-/nested-clients-3.772.0.tgz", + "integrity": "sha512-gNJbBxR5YlEumsCS9EWWEASXEnysL0aDnr9MNPX1ip/g1xOqRHmytgV/+t8RFZFTKg0OprbWTq5Ich3MqsEuCQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "3.758.0", + "@aws-sdk/middleware-host-header": "3.734.0", + "@aws-sdk/middleware-logger": "3.734.0", + "@aws-sdk/middleware-recursion-detection": "3.772.0", + "@aws-sdk/middleware-user-agent": "3.758.0", + "@aws-sdk/region-config-resolver": "3.734.0", + "@aws-sdk/types": "3.734.0", + "@aws-sdk/util-endpoints": "3.743.0", + "@aws-sdk/util-user-agent-browser": "3.734.0", + "@aws-sdk/util-user-agent-node": "3.758.0", + "@smithy/config-resolver": "^4.0.1", + "@smithy/core": "^3.1.5", + "@smithy/fetch-http-handler": "^5.0.1", + "@smithy/hash-node": "^4.0.1", + "@smithy/invalid-dependency": "^4.0.1", + "@smithy/middleware-content-length": "^4.0.1", + "@smithy/middleware-endpoint": "^4.0.6", + "@smithy/middleware-retry": "^4.0.7", + "@smithy/middleware-serde": "^4.0.2", + "@smithy/middleware-stack": "^4.0.1", + "@smithy/node-config-provider": "^4.0.1", + "@smithy/node-http-handler": "^4.0.3", + "@smithy/protocol-http": "^5.0.1", + "@smithy/smithy-client": "^4.1.6", + "@smithy/types": "^4.1.0", + "@smithy/url-parser": "^4.0.1", + "@smithy/util-base64": "^4.0.0", + "@smithy/util-body-length-browser": "^4.0.0", + "@smithy/util-body-length-node": "^4.0.0", + "@smithy/util-defaults-mode-browser": "^4.0.7", + "@smithy/util-defaults-mode-node": "^4.0.7", + "@smithy/util-endpoints": "^3.0.1", + "@smithy/util-middleware": "^4.0.1", + "@smithy/util-retry": "^4.0.1", + "@smithy/util-utf8": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-cloudwatch/node_modules/@aws-sdk/token-providers": { + "version": "3.772.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.772.0.tgz", + "integrity": "sha512-d1Waa1vyebuokcAWYlkZdtFlciIgob7B39vPRmtxMObbGumJKiOy/qCe2/FB/72h1Ej9Ih32lwvbxUjORQWN4g==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/nested-clients": "3.772.0", + "@aws-sdk/types": "3.734.0", + "@smithy/property-provider": "^4.0.1", + "@smithy/shared-ini-file-loader": "^4.0.1", + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-codebuild": { + "version": "3.741.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-codebuild/-/client-codebuild-3.741.0.tgz", + "integrity": "sha512-oHKptRuG6MNKj75EEsOzndRqLrZBoi+LYSkNXKdSlDN8Pes+bua1Zu5Ex3iM4rAYqN390pD7P4avOz/SDcMLHg==", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "3.734.0", + "@aws-sdk/credential-provider-node": "3.741.0", + "@aws-sdk/middleware-host-header": "3.734.0", + "@aws-sdk/middleware-logger": "3.734.0", + "@aws-sdk/middleware-recursion-detection": "3.734.0", + "@aws-sdk/middleware-user-agent": "3.734.0", + "@aws-sdk/region-config-resolver": "3.734.0", + "@aws-sdk/types": "3.734.0", + "@aws-sdk/util-endpoints": "3.734.0", + "@aws-sdk/util-user-agent-browser": "3.734.0", + "@aws-sdk/util-user-agent-node": "3.734.0", + "@smithy/config-resolver": "^4.0.1", + "@smithy/core": "^3.1.1", + "@smithy/fetch-http-handler": "^5.0.1", + "@smithy/hash-node": "^4.0.1", + "@smithy/invalid-dependency": "^4.0.1", + "@smithy/middleware-content-length": "^4.0.1", + "@smithy/middleware-endpoint": "^4.0.2", + "@smithy/middleware-retry": "^4.0.3", + "@smithy/middleware-serde": "^4.0.1", + "@smithy/middleware-stack": "^4.0.1", + "@smithy/node-config-provider": "^4.0.1", + "@smithy/node-http-handler": "^4.0.2", + "@smithy/protocol-http": "^5.0.1", + "@smithy/smithy-client": "^4.1.2", + "@smithy/types": "^4.1.0", + "@smithy/url-parser": "^4.0.1", + "@smithy/util-base64": "^4.0.0", + "@smithy/util-body-length-browser": "^4.0.0", + "@smithy/util-body-length-node": "^4.0.0", + "@smithy/util-defaults-mode-browser": "^4.0.3", + "@smithy/util-defaults-mode-node": "^4.0.3", + "@smithy/util-endpoints": "^3.0.1", + "@smithy/util-middleware": "^4.0.1", + "@smithy/util-retry": "^4.0.1", + "@smithy/util-utf8": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-codebuild/node_modules/@aws-sdk/client-sso": { + "version": "3.734.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.734.0.tgz", + "integrity": "sha512-oerepp0mut9VlgTwnG5Ds/lb0C0b2/rQ+hL/rF6q+HGKPfGsCuPvFx1GtwGKCXd49ase88/jVgrhcA9OQbz3kg==", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "3.734.0", + "@aws-sdk/middleware-host-header": "3.734.0", + "@aws-sdk/middleware-logger": "3.734.0", + "@aws-sdk/middleware-recursion-detection": "3.734.0", + "@aws-sdk/middleware-user-agent": "3.734.0", + "@aws-sdk/region-config-resolver": "3.734.0", + "@aws-sdk/types": "3.734.0", + "@aws-sdk/util-endpoints": "3.734.0", + "@aws-sdk/util-user-agent-browser": "3.734.0", + "@aws-sdk/util-user-agent-node": "3.734.0", + "@smithy/config-resolver": "^4.0.1", + "@smithy/core": "^3.1.1", + "@smithy/fetch-http-handler": "^5.0.1", + "@smithy/hash-node": "^4.0.1", + "@smithy/invalid-dependency": "^4.0.1", + "@smithy/middleware-content-length": "^4.0.1", + "@smithy/middleware-endpoint": "^4.0.2", + "@smithy/middleware-retry": "^4.0.3", + "@smithy/middleware-serde": "^4.0.1", + "@smithy/middleware-stack": "^4.0.1", + "@smithy/node-config-provider": "^4.0.1", + "@smithy/node-http-handler": "^4.0.2", + "@smithy/protocol-http": "^5.0.1", + "@smithy/smithy-client": "^4.1.2", + "@smithy/types": "^4.1.0", + "@smithy/url-parser": "^4.0.1", + "@smithy/util-base64": "^4.0.0", + "@smithy/util-body-length-browser": "^4.0.0", + "@smithy/util-body-length-node": "^4.0.0", + "@smithy/util-defaults-mode-browser": "^4.0.3", "@smithy/util-defaults-mode-node": "^4.0.3", "@smithy/util-endpoints": "^3.0.1", "@smithy/util-middleware": "^4.0.1", @@ -2952,19 +3394,19 @@ } }, "node_modules/@aws-sdk/client-dynamodb": { - "version": "3.767.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-dynamodb/-/client-dynamodb-3.767.0.tgz", - "integrity": "sha512-uoZFUnQr9jhxPdhPz0o4/1osstDXdteOIw8tNRTe3JKK9eIWAG3YrVv9wfJPxEFUGvntUe+anvdiy+8ycKmsYQ==", + "version": "3.772.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-dynamodb/-/client-dynamodb-3.772.0.tgz", + "integrity": "sha512-MxUqb6vmWkZSR5UMuL7t5Bni22gwSZAweWdOEA9eXC/W4D7NIa8rMbsNl1lPvgF8OzIBvZBjkMzIHPuW/w4MrQ==", "license": "Apache-2.0", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.758.0", - "@aws-sdk/credential-provider-node": "3.758.0", + "@aws-sdk/credential-provider-node": "3.772.0", "@aws-sdk/middleware-endpoint-discovery": "3.734.0", "@aws-sdk/middleware-host-header": "3.734.0", "@aws-sdk/middleware-logger": "3.734.0", - "@aws-sdk/middleware-recursion-detection": "3.734.0", + "@aws-sdk/middleware-recursion-detection": "3.772.0", "@aws-sdk/middleware-user-agent": "3.758.0", "@aws-sdk/region-config-resolver": "3.734.0", "@aws-sdk/types": "3.734.0", @@ -3005,72 +3447,285 @@ "node": ">=18.0.0" } }, - "node_modules/@aws-sdk/client-ec2": { - "version": "3.741.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-ec2/-/client-ec2-3.741.0.tgz", - "integrity": "sha512-PQiqFeVVykHmB3Vk/RlK6JPuzoOLZ+clxcu2d7RcfuwbGaiXhjaHSIVefjF+NOFekO5PHornG6r05H4RRf3M7w==", + "node_modules/@aws-sdk/client-dynamodb/node_modules/@aws-sdk/client-sso": { + "version": "3.772.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.772.0.tgz", + "integrity": "sha512-sDdxepi74+cL6gXJJ2yw3UNSI7GBvoGTwZqFyPoNAzcURvaYwo8dBr7G4jS9GDanjTlO3CGVAf2VMcpqEvmoEw==", "license": "Apache-2.0", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "3.734.0", - "@aws-sdk/credential-provider-node": "3.741.0", + "@aws-sdk/core": "3.758.0", "@aws-sdk/middleware-host-header": "3.734.0", "@aws-sdk/middleware-logger": "3.734.0", - "@aws-sdk/middleware-recursion-detection": "3.734.0", - "@aws-sdk/middleware-sdk-ec2": "3.734.0", - "@aws-sdk/middleware-user-agent": "3.734.0", + "@aws-sdk/middleware-recursion-detection": "3.772.0", + "@aws-sdk/middleware-user-agent": "3.758.0", "@aws-sdk/region-config-resolver": "3.734.0", "@aws-sdk/types": "3.734.0", - "@aws-sdk/util-endpoints": "3.734.0", + "@aws-sdk/util-endpoints": "3.743.0", "@aws-sdk/util-user-agent-browser": "3.734.0", - "@aws-sdk/util-user-agent-node": "3.734.0", + "@aws-sdk/util-user-agent-node": "3.758.0", "@smithy/config-resolver": "^4.0.1", - "@smithy/core": "^3.1.1", + "@smithy/core": "^3.1.5", "@smithy/fetch-http-handler": "^5.0.1", "@smithy/hash-node": "^4.0.1", "@smithy/invalid-dependency": "^4.0.1", "@smithy/middleware-content-length": "^4.0.1", - "@smithy/middleware-endpoint": "^4.0.2", - "@smithy/middleware-retry": "^4.0.3", - "@smithy/middleware-serde": "^4.0.1", + "@smithy/middleware-endpoint": "^4.0.6", + "@smithy/middleware-retry": "^4.0.7", + "@smithy/middleware-serde": "^4.0.2", "@smithy/middleware-stack": "^4.0.1", "@smithy/node-config-provider": "^4.0.1", - "@smithy/node-http-handler": "^4.0.2", + "@smithy/node-http-handler": "^4.0.3", "@smithy/protocol-http": "^5.0.1", - "@smithy/smithy-client": "^4.1.2", + "@smithy/smithy-client": "^4.1.6", "@smithy/types": "^4.1.0", "@smithy/url-parser": "^4.0.1", "@smithy/util-base64": "^4.0.0", "@smithy/util-body-length-browser": "^4.0.0", "@smithy/util-body-length-node": "^4.0.0", - "@smithy/util-defaults-mode-browser": "^4.0.3", - "@smithy/util-defaults-mode-node": "^4.0.3", + "@smithy/util-defaults-mode-browser": "^4.0.7", + "@smithy/util-defaults-mode-node": "^4.0.7", "@smithy/util-endpoints": "^3.0.1", "@smithy/util-middleware": "^4.0.1", "@smithy/util-retry": "^4.0.1", "@smithy/util-utf8": "^4.0.0", - "@smithy/util-waiter": "^4.0.2", - "@types/uuid": "^9.0.1", - "tslib": "^2.6.2", - "uuid": "^9.0.1" + "tslib": "^2.6.2" }, "engines": { "node": ">=18.0.0" } }, - "node_modules/@aws-sdk/client-ec2/node_modules/@aws-sdk/client-sso": { - "version": "3.734.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.734.0.tgz", - "integrity": "sha512-oerepp0mut9VlgTwnG5Ds/lb0C0b2/rQ+hL/rF6q+HGKPfGsCuPvFx1GtwGKCXd49ase88/jVgrhcA9OQbz3kg==", + "node_modules/@aws-sdk/client-dynamodb/node_modules/@aws-sdk/credential-provider-ini": { + "version": "3.772.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.772.0.tgz", + "integrity": "sha512-T1Ec9Q25zl5c/eZUPHZsiq8vgBeWBjHM7WM5xtZszZRPqqhQGnmFlomz1r9rwhW8RFB5k8HRaD/SLKo6jtYl/A==", "license": "Apache-2.0", "dependencies": { - "@aws-crypto/sha256-browser": "5.2.0", - "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "3.734.0", - "@aws-sdk/middleware-host-header": "3.734.0", - "@aws-sdk/middleware-logger": "3.734.0", - "@aws-sdk/middleware-recursion-detection": "3.734.0", + "@aws-sdk/core": "3.758.0", + "@aws-sdk/credential-provider-env": "3.758.0", + "@aws-sdk/credential-provider-http": "3.758.0", + "@aws-sdk/credential-provider-process": "3.758.0", + "@aws-sdk/credential-provider-sso": "3.772.0", + "@aws-sdk/credential-provider-web-identity": "3.772.0", + "@aws-sdk/nested-clients": "3.772.0", + "@aws-sdk/types": "3.734.0", + "@smithy/credential-provider-imds": "^4.0.1", + "@smithy/property-provider": "^4.0.1", + "@smithy/shared-ini-file-loader": "^4.0.1", + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-dynamodb/node_modules/@aws-sdk/credential-provider-node": { + "version": "3.772.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.772.0.tgz", + "integrity": "sha512-0IdVfjBO88Mtekq/KaScYSIEPIeR+ABRvBOWyj/c/qQ2KJyI0GRlSAzpANfxDLHVPn3yEHuZd9nRL6sOmOMI0A==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/credential-provider-env": "3.758.0", + "@aws-sdk/credential-provider-http": "3.758.0", + "@aws-sdk/credential-provider-ini": "3.772.0", + "@aws-sdk/credential-provider-process": "3.758.0", + "@aws-sdk/credential-provider-sso": "3.772.0", + "@aws-sdk/credential-provider-web-identity": "3.772.0", + "@aws-sdk/types": "3.734.0", + "@smithy/credential-provider-imds": "^4.0.1", + "@smithy/property-provider": "^4.0.1", + "@smithy/shared-ini-file-loader": "^4.0.1", + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-dynamodb/node_modules/@aws-sdk/credential-provider-sso": { + "version": "3.772.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.772.0.tgz", + "integrity": "sha512-yR3Y5RAVPa4ogojcBOpZUx6XyRVAkynIJCjd0avdlxW1hhnzSr5/pzoiJ6u21UCbkxlJJTDZE3jfFe7tt+HA4w==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/client-sso": "3.772.0", + "@aws-sdk/core": "3.758.0", + "@aws-sdk/token-providers": "3.772.0", + "@aws-sdk/types": "3.734.0", + "@smithy/property-provider": "^4.0.1", + "@smithy/shared-ini-file-loader": "^4.0.1", + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-dynamodb/node_modules/@aws-sdk/credential-provider-web-identity": { + "version": "3.772.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.772.0.tgz", + "integrity": "sha512-yHAT5Y2y0fnecSuWRUn8NMunKfDqFYhnOpGq8UyCEcwz9aXzibU0hqRIEm51qpR81hqo0GMFDH0EOmegZ/iW5w==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.758.0", + "@aws-sdk/nested-clients": "3.772.0", + "@aws-sdk/types": "3.734.0", + "@smithy/property-provider": "^4.0.1", + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-dynamodb/node_modules/@aws-sdk/middleware-recursion-detection": { + "version": "3.772.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.772.0.tgz", + "integrity": "sha512-zg0LjJa4v7fcLzn5QzZvtVS+qyvmsnu7oQnb86l6ckduZpWDCDC9+A0ZzcXTrxblPCJd3JqkoG1+Gzi4S4Ny/Q==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.734.0", + "@smithy/protocol-http": "^5.0.1", + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-dynamodb/node_modules/@aws-sdk/nested-clients": { + "version": "3.772.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/nested-clients/-/nested-clients-3.772.0.tgz", + "integrity": "sha512-gNJbBxR5YlEumsCS9EWWEASXEnysL0aDnr9MNPX1ip/g1xOqRHmytgV/+t8RFZFTKg0OprbWTq5Ich3MqsEuCQ==", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "3.758.0", + "@aws-sdk/middleware-host-header": "3.734.0", + "@aws-sdk/middleware-logger": "3.734.0", + "@aws-sdk/middleware-recursion-detection": "3.772.0", + "@aws-sdk/middleware-user-agent": "3.758.0", + "@aws-sdk/region-config-resolver": "3.734.0", + "@aws-sdk/types": "3.734.0", + "@aws-sdk/util-endpoints": "3.743.0", + "@aws-sdk/util-user-agent-browser": "3.734.0", + "@aws-sdk/util-user-agent-node": "3.758.0", + "@smithy/config-resolver": "^4.0.1", + "@smithy/core": "^3.1.5", + "@smithy/fetch-http-handler": "^5.0.1", + "@smithy/hash-node": "^4.0.1", + "@smithy/invalid-dependency": "^4.0.1", + "@smithy/middleware-content-length": "^4.0.1", + "@smithy/middleware-endpoint": "^4.0.6", + "@smithy/middleware-retry": "^4.0.7", + "@smithy/middleware-serde": "^4.0.2", + "@smithy/middleware-stack": "^4.0.1", + "@smithy/node-config-provider": "^4.0.1", + "@smithy/node-http-handler": "^4.0.3", + "@smithy/protocol-http": "^5.0.1", + "@smithy/smithy-client": "^4.1.6", + "@smithy/types": "^4.1.0", + "@smithy/url-parser": "^4.0.1", + "@smithy/util-base64": "^4.0.0", + "@smithy/util-body-length-browser": "^4.0.0", + "@smithy/util-body-length-node": "^4.0.0", + "@smithy/util-defaults-mode-browser": "^4.0.7", + "@smithy/util-defaults-mode-node": "^4.0.7", + "@smithy/util-endpoints": "^3.0.1", + "@smithy/util-middleware": "^4.0.1", + "@smithy/util-retry": "^4.0.1", + "@smithy/util-utf8": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-dynamodb/node_modules/@aws-sdk/token-providers": { + "version": "3.772.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.772.0.tgz", + "integrity": "sha512-d1Waa1vyebuokcAWYlkZdtFlciIgob7B39vPRmtxMObbGumJKiOy/qCe2/FB/72h1Ej9Ih32lwvbxUjORQWN4g==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/nested-clients": "3.772.0", + "@aws-sdk/types": "3.734.0", + "@smithy/property-provider": "^4.0.1", + "@smithy/shared-ini-file-loader": "^4.0.1", + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-ec2": { + "version": "3.741.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-ec2/-/client-ec2-3.741.0.tgz", + "integrity": "sha512-PQiqFeVVykHmB3Vk/RlK6JPuzoOLZ+clxcu2d7RcfuwbGaiXhjaHSIVefjF+NOFekO5PHornG6r05H4RRf3M7w==", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "3.734.0", + "@aws-sdk/credential-provider-node": "3.741.0", + "@aws-sdk/middleware-host-header": "3.734.0", + "@aws-sdk/middleware-logger": "3.734.0", + "@aws-sdk/middleware-recursion-detection": "3.734.0", + "@aws-sdk/middleware-sdk-ec2": "3.734.0", + "@aws-sdk/middleware-user-agent": "3.734.0", + "@aws-sdk/region-config-resolver": "3.734.0", + "@aws-sdk/types": "3.734.0", + "@aws-sdk/util-endpoints": "3.734.0", + "@aws-sdk/util-user-agent-browser": "3.734.0", + "@aws-sdk/util-user-agent-node": "3.734.0", + "@smithy/config-resolver": "^4.0.1", + "@smithy/core": "^3.1.1", + "@smithy/fetch-http-handler": "^5.0.1", + "@smithy/hash-node": "^4.0.1", + "@smithy/invalid-dependency": "^4.0.1", + "@smithy/middleware-content-length": "^4.0.1", + "@smithy/middleware-endpoint": "^4.0.2", + "@smithy/middleware-retry": "^4.0.3", + "@smithy/middleware-serde": "^4.0.1", + "@smithy/middleware-stack": "^4.0.1", + "@smithy/node-config-provider": "^4.0.1", + "@smithy/node-http-handler": "^4.0.2", + "@smithy/protocol-http": "^5.0.1", + "@smithy/smithy-client": "^4.1.2", + "@smithy/types": "^4.1.0", + "@smithy/url-parser": "^4.0.1", + "@smithy/util-base64": "^4.0.0", + "@smithy/util-body-length-browser": "^4.0.0", + "@smithy/util-body-length-node": "^4.0.0", + "@smithy/util-defaults-mode-browser": "^4.0.3", + "@smithy/util-defaults-mode-node": "^4.0.3", + "@smithy/util-endpoints": "^3.0.1", + "@smithy/util-middleware": "^4.0.1", + "@smithy/util-retry": "^4.0.1", + "@smithy/util-utf8": "^4.0.0", + "@smithy/util-waiter": "^4.0.2", + "@types/uuid": "^9.0.1", + "tslib": "^2.6.2", + "uuid": "^9.0.1" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-ec2/node_modules/@aws-sdk/client-sso": { + "version": "3.734.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.734.0.tgz", + "integrity": "sha512-oerepp0mut9VlgTwnG5Ds/lb0C0b2/rQ+hL/rF6q+HGKPfGsCuPvFx1GtwGKCXd49ase88/jVgrhcA9OQbz3kg==", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "3.734.0", + "@aws-sdk/middleware-host-header": "3.734.0", + "@aws-sdk/middleware-logger": "3.734.0", + "@aws-sdk/middleware-recursion-detection": "3.734.0", "@aws-sdk/middleware-user-agent": "3.734.0", "@aws-sdk/region-config-resolver": "3.734.0", "@aws-sdk/types": "3.734.0", @@ -4971,18 +5626,18 @@ } }, "node_modules/@aws-sdk/client-lambda": { - "version": "3.771.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-lambda/-/client-lambda-3.771.0.tgz", - "integrity": "sha512-0/4IGf4Nbc9Dfo6/9P0Qq7O5B1L7DGsfUg6Yl963GTOaM8wwYc8WzZy7F3EqMYIrGPz0M12IdYL9bU0hThnZvA==", + "version": "3.772.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-lambda/-/client-lambda-3.772.0.tgz", + "integrity": "sha512-oe+EfCzLwSHY5d8J0eh0/DNhupMUyeLCLAQ+4RwlEbMkWESa2oyV9hNZ2n7+v0xE+qG9svQXLp3jW/hVM63ncA==", "license": "Apache-2.0", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.758.0", - "@aws-sdk/credential-provider-node": "3.758.0", + "@aws-sdk/credential-provider-node": "3.772.0", "@aws-sdk/middleware-host-header": "3.734.0", "@aws-sdk/middleware-logger": "3.734.0", - "@aws-sdk/middleware-recursion-detection": "3.734.0", + "@aws-sdk/middleware-recursion-detection": "3.772.0", "@aws-sdk/middleware-user-agent": "3.758.0", "@aws-sdk/region-config-resolver": "3.734.0", "@aws-sdk/types": "3.734.0", @@ -5025,90 +5680,303 @@ "node": ">=18.0.0" } }, - "node_modules/@aws-sdk/client-route-53": { - "version": "3.741.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-route-53/-/client-route-53-3.741.0.tgz", - "integrity": "sha512-TV2qOzJeKKiRZtFP88DHZvUpdXIKfdDsyhbJkkVLVJ4Rd2QNpekPZz3ce6eaokqzilHJu5LFn4D1vdgv4YZLKg==", + "node_modules/@aws-sdk/client-lambda/node_modules/@aws-sdk/client-sso": { + "version": "3.772.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.772.0.tgz", + "integrity": "sha512-sDdxepi74+cL6gXJJ2yw3UNSI7GBvoGTwZqFyPoNAzcURvaYwo8dBr7G4jS9GDanjTlO3CGVAf2VMcpqEvmoEw==", "license": "Apache-2.0", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "3.734.0", - "@aws-sdk/credential-provider-node": "3.741.0", + "@aws-sdk/core": "3.758.0", "@aws-sdk/middleware-host-header": "3.734.0", "@aws-sdk/middleware-logger": "3.734.0", - "@aws-sdk/middleware-recursion-detection": "3.734.0", - "@aws-sdk/middleware-sdk-route53": "3.734.0", - "@aws-sdk/middleware-user-agent": "3.734.0", + "@aws-sdk/middleware-recursion-detection": "3.772.0", + "@aws-sdk/middleware-user-agent": "3.758.0", "@aws-sdk/region-config-resolver": "3.734.0", "@aws-sdk/types": "3.734.0", - "@aws-sdk/util-endpoints": "3.734.0", + "@aws-sdk/util-endpoints": "3.743.0", "@aws-sdk/util-user-agent-browser": "3.734.0", - "@aws-sdk/util-user-agent-node": "3.734.0", - "@aws-sdk/xml-builder": "3.734.0", + "@aws-sdk/util-user-agent-node": "3.758.0", "@smithy/config-resolver": "^4.0.1", - "@smithy/core": "^3.1.1", + "@smithy/core": "^3.1.5", "@smithy/fetch-http-handler": "^5.0.1", "@smithy/hash-node": "^4.0.1", "@smithy/invalid-dependency": "^4.0.1", "@smithy/middleware-content-length": "^4.0.1", - "@smithy/middleware-endpoint": "^4.0.2", - "@smithy/middleware-retry": "^4.0.3", - "@smithy/middleware-serde": "^4.0.1", + "@smithy/middleware-endpoint": "^4.0.6", + "@smithy/middleware-retry": "^4.0.7", + "@smithy/middleware-serde": "^4.0.2", "@smithy/middleware-stack": "^4.0.1", "@smithy/node-config-provider": "^4.0.1", - "@smithy/node-http-handler": "^4.0.2", + "@smithy/node-http-handler": "^4.0.3", "@smithy/protocol-http": "^5.0.1", - "@smithy/smithy-client": "^4.1.2", + "@smithy/smithy-client": "^4.1.6", "@smithy/types": "^4.1.0", "@smithy/url-parser": "^4.0.1", "@smithy/util-base64": "^4.0.0", "@smithy/util-body-length-browser": "^4.0.0", "@smithy/util-body-length-node": "^4.0.0", - "@smithy/util-defaults-mode-browser": "^4.0.3", - "@smithy/util-defaults-mode-node": "^4.0.3", + "@smithy/util-defaults-mode-browser": "^4.0.7", + "@smithy/util-defaults-mode-node": "^4.0.7", "@smithy/util-endpoints": "^3.0.1", "@smithy/util-middleware": "^4.0.1", "@smithy/util-retry": "^4.0.1", "@smithy/util-utf8": "^4.0.0", - "@smithy/util-waiter": "^4.0.2", "tslib": "^2.6.2" }, "engines": { "node": ">=18.0.0" } }, - "node_modules/@aws-sdk/client-route-53/node_modules/@aws-sdk/client-sso": { - "version": "3.734.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.734.0.tgz", - "integrity": "sha512-oerepp0mut9VlgTwnG5Ds/lb0C0b2/rQ+hL/rF6q+HGKPfGsCuPvFx1GtwGKCXd49ase88/jVgrhcA9OQbz3kg==", + "node_modules/@aws-sdk/client-lambda/node_modules/@aws-sdk/credential-provider-ini": { + "version": "3.772.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.772.0.tgz", + "integrity": "sha512-T1Ec9Q25zl5c/eZUPHZsiq8vgBeWBjHM7WM5xtZszZRPqqhQGnmFlomz1r9rwhW8RFB5k8HRaD/SLKo6jtYl/A==", "license": "Apache-2.0", "dependencies": { - "@aws-crypto/sha256-browser": "5.2.0", - "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "3.734.0", - "@aws-sdk/middleware-host-header": "3.734.0", - "@aws-sdk/middleware-logger": "3.734.0", - "@aws-sdk/middleware-recursion-detection": "3.734.0", - "@aws-sdk/middleware-user-agent": "3.734.0", - "@aws-sdk/region-config-resolver": "3.734.0", + "@aws-sdk/core": "3.758.0", + "@aws-sdk/credential-provider-env": "3.758.0", + "@aws-sdk/credential-provider-http": "3.758.0", + "@aws-sdk/credential-provider-process": "3.758.0", + "@aws-sdk/credential-provider-sso": "3.772.0", + "@aws-sdk/credential-provider-web-identity": "3.772.0", + "@aws-sdk/nested-clients": "3.772.0", "@aws-sdk/types": "3.734.0", - "@aws-sdk/util-endpoints": "3.734.0", - "@aws-sdk/util-user-agent-browser": "3.734.0", - "@aws-sdk/util-user-agent-node": "3.734.0", - "@smithy/config-resolver": "^4.0.1", - "@smithy/core": "^3.1.1", - "@smithy/fetch-http-handler": "^5.0.1", - "@smithy/hash-node": "^4.0.1", - "@smithy/invalid-dependency": "^4.0.1", - "@smithy/middleware-content-length": "^4.0.1", - "@smithy/middleware-endpoint": "^4.0.2", - "@smithy/middleware-retry": "^4.0.3", - "@smithy/middleware-serde": "^4.0.1", - "@smithy/middleware-stack": "^4.0.1", - "@smithy/node-config-provider": "^4.0.1", - "@smithy/node-http-handler": "^4.0.2", - "@smithy/protocol-http": "^5.0.1", + "@smithy/credential-provider-imds": "^4.0.1", + "@smithy/property-provider": "^4.0.1", + "@smithy/shared-ini-file-loader": "^4.0.1", + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-lambda/node_modules/@aws-sdk/credential-provider-node": { + "version": "3.772.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.772.0.tgz", + "integrity": "sha512-0IdVfjBO88Mtekq/KaScYSIEPIeR+ABRvBOWyj/c/qQ2KJyI0GRlSAzpANfxDLHVPn3yEHuZd9nRL6sOmOMI0A==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/credential-provider-env": "3.758.0", + "@aws-sdk/credential-provider-http": "3.758.0", + "@aws-sdk/credential-provider-ini": "3.772.0", + "@aws-sdk/credential-provider-process": "3.758.0", + "@aws-sdk/credential-provider-sso": "3.772.0", + "@aws-sdk/credential-provider-web-identity": "3.772.0", + "@aws-sdk/types": "3.734.0", + "@smithy/credential-provider-imds": "^4.0.1", + "@smithy/property-provider": "^4.0.1", + "@smithy/shared-ini-file-loader": "^4.0.1", + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-lambda/node_modules/@aws-sdk/credential-provider-sso": { + "version": "3.772.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.772.0.tgz", + "integrity": "sha512-yR3Y5RAVPa4ogojcBOpZUx6XyRVAkynIJCjd0avdlxW1hhnzSr5/pzoiJ6u21UCbkxlJJTDZE3jfFe7tt+HA4w==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/client-sso": "3.772.0", + "@aws-sdk/core": "3.758.0", + "@aws-sdk/token-providers": "3.772.0", + "@aws-sdk/types": "3.734.0", + "@smithy/property-provider": "^4.0.1", + "@smithy/shared-ini-file-loader": "^4.0.1", + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-lambda/node_modules/@aws-sdk/credential-provider-web-identity": { + "version": "3.772.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.772.0.tgz", + "integrity": "sha512-yHAT5Y2y0fnecSuWRUn8NMunKfDqFYhnOpGq8UyCEcwz9aXzibU0hqRIEm51qpR81hqo0GMFDH0EOmegZ/iW5w==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.758.0", + "@aws-sdk/nested-clients": "3.772.0", + "@aws-sdk/types": "3.734.0", + "@smithy/property-provider": "^4.0.1", + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-lambda/node_modules/@aws-sdk/middleware-recursion-detection": { + "version": "3.772.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.772.0.tgz", + "integrity": "sha512-zg0LjJa4v7fcLzn5QzZvtVS+qyvmsnu7oQnb86l6ckduZpWDCDC9+A0ZzcXTrxblPCJd3JqkoG1+Gzi4S4Ny/Q==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.734.0", + "@smithy/protocol-http": "^5.0.1", + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-lambda/node_modules/@aws-sdk/nested-clients": { + "version": "3.772.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/nested-clients/-/nested-clients-3.772.0.tgz", + "integrity": "sha512-gNJbBxR5YlEumsCS9EWWEASXEnysL0aDnr9MNPX1ip/g1xOqRHmytgV/+t8RFZFTKg0OprbWTq5Ich3MqsEuCQ==", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "3.758.0", + "@aws-sdk/middleware-host-header": "3.734.0", + "@aws-sdk/middleware-logger": "3.734.0", + "@aws-sdk/middleware-recursion-detection": "3.772.0", + "@aws-sdk/middleware-user-agent": "3.758.0", + "@aws-sdk/region-config-resolver": "3.734.0", + "@aws-sdk/types": "3.734.0", + "@aws-sdk/util-endpoints": "3.743.0", + "@aws-sdk/util-user-agent-browser": "3.734.0", + "@aws-sdk/util-user-agent-node": "3.758.0", + "@smithy/config-resolver": "^4.0.1", + "@smithy/core": "^3.1.5", + "@smithy/fetch-http-handler": "^5.0.1", + "@smithy/hash-node": "^4.0.1", + "@smithy/invalid-dependency": "^4.0.1", + "@smithy/middleware-content-length": "^4.0.1", + "@smithy/middleware-endpoint": "^4.0.6", + "@smithy/middleware-retry": "^4.0.7", + "@smithy/middleware-serde": "^4.0.2", + "@smithy/middleware-stack": "^4.0.1", + "@smithy/node-config-provider": "^4.0.1", + "@smithy/node-http-handler": "^4.0.3", + "@smithy/protocol-http": "^5.0.1", + "@smithy/smithy-client": "^4.1.6", + "@smithy/types": "^4.1.0", + "@smithy/url-parser": "^4.0.1", + "@smithy/util-base64": "^4.0.0", + "@smithy/util-body-length-browser": "^4.0.0", + "@smithy/util-body-length-node": "^4.0.0", + "@smithy/util-defaults-mode-browser": "^4.0.7", + "@smithy/util-defaults-mode-node": "^4.0.7", + "@smithy/util-endpoints": "^3.0.1", + "@smithy/util-middleware": "^4.0.1", + "@smithy/util-retry": "^4.0.1", + "@smithy/util-utf8": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-lambda/node_modules/@aws-sdk/token-providers": { + "version": "3.772.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.772.0.tgz", + "integrity": "sha512-d1Waa1vyebuokcAWYlkZdtFlciIgob7B39vPRmtxMObbGumJKiOy/qCe2/FB/72h1Ej9Ih32lwvbxUjORQWN4g==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/nested-clients": "3.772.0", + "@aws-sdk/types": "3.734.0", + "@smithy/property-provider": "^4.0.1", + "@smithy/shared-ini-file-loader": "^4.0.1", + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-route-53": { + "version": "3.741.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-route-53/-/client-route-53-3.741.0.tgz", + "integrity": "sha512-TV2qOzJeKKiRZtFP88DHZvUpdXIKfdDsyhbJkkVLVJ4Rd2QNpekPZz3ce6eaokqzilHJu5LFn4D1vdgv4YZLKg==", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "3.734.0", + "@aws-sdk/credential-provider-node": "3.741.0", + "@aws-sdk/middleware-host-header": "3.734.0", + "@aws-sdk/middleware-logger": "3.734.0", + "@aws-sdk/middleware-recursion-detection": "3.734.0", + "@aws-sdk/middleware-sdk-route53": "3.734.0", + "@aws-sdk/middleware-user-agent": "3.734.0", + "@aws-sdk/region-config-resolver": "3.734.0", + "@aws-sdk/types": "3.734.0", + "@aws-sdk/util-endpoints": "3.734.0", + "@aws-sdk/util-user-agent-browser": "3.734.0", + "@aws-sdk/util-user-agent-node": "3.734.0", + "@aws-sdk/xml-builder": "3.734.0", + "@smithy/config-resolver": "^4.0.1", + "@smithy/core": "^3.1.1", + "@smithy/fetch-http-handler": "^5.0.1", + "@smithy/hash-node": "^4.0.1", + "@smithy/invalid-dependency": "^4.0.1", + "@smithy/middleware-content-length": "^4.0.1", + "@smithy/middleware-endpoint": "^4.0.2", + "@smithy/middleware-retry": "^4.0.3", + "@smithy/middleware-serde": "^4.0.1", + "@smithy/middleware-stack": "^4.0.1", + "@smithy/node-config-provider": "^4.0.1", + "@smithy/node-http-handler": "^4.0.2", + "@smithy/protocol-http": "^5.0.1", + "@smithy/smithy-client": "^4.1.2", + "@smithy/types": "^4.1.0", + "@smithy/url-parser": "^4.0.1", + "@smithy/util-base64": "^4.0.0", + "@smithy/util-body-length-browser": "^4.0.0", + "@smithy/util-body-length-node": "^4.0.0", + "@smithy/util-defaults-mode-browser": "^4.0.3", + "@smithy/util-defaults-mode-node": "^4.0.3", + "@smithy/util-endpoints": "^3.0.1", + "@smithy/util-middleware": "^4.0.1", + "@smithy/util-retry": "^4.0.1", + "@smithy/util-utf8": "^4.0.0", + "@smithy/util-waiter": "^4.0.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-route-53/node_modules/@aws-sdk/client-sso": { + "version": "3.734.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.734.0.tgz", + "integrity": "sha512-oerepp0mut9VlgTwnG5Ds/lb0C0b2/rQ+hL/rF6q+HGKPfGsCuPvFx1GtwGKCXd49ase88/jVgrhcA9OQbz3kg==", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "3.734.0", + "@aws-sdk/middleware-host-header": "3.734.0", + "@aws-sdk/middleware-logger": "3.734.0", + "@aws-sdk/middleware-recursion-detection": "3.734.0", + "@aws-sdk/middleware-user-agent": "3.734.0", + "@aws-sdk/region-config-resolver": "3.734.0", + "@aws-sdk/types": "3.734.0", + "@aws-sdk/util-endpoints": "3.734.0", + "@aws-sdk/util-user-agent-browser": "3.734.0", + "@aws-sdk/util-user-agent-node": "3.734.0", + "@smithy/config-resolver": "^4.0.1", + "@smithy/core": "^3.1.1", + "@smithy/fetch-http-handler": "^5.0.1", + "@smithy/hash-node": "^4.0.1", + "@smithy/invalid-dependency": "^4.0.1", + "@smithy/middleware-content-length": "^4.0.1", + "@smithy/middleware-endpoint": "^4.0.2", + "@smithy/middleware-retry": "^4.0.3", + "@smithy/middleware-serde": "^4.0.1", + "@smithy/middleware-stack": "^4.0.1", + "@smithy/node-config-provider": "^4.0.1", + "@smithy/node-http-handler": "^4.0.2", + "@smithy/protocol-http": "^5.0.1", "@smithy/smithy-client": "^4.1.2", "@smithy/types": "^4.1.0", "@smithy/url-parser": "^4.0.1", @@ -5477,18 +6345,18 @@ } }, "node_modules/@aws-sdk/client-secrets-manager": { - "version": "3.758.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-secrets-manager/-/client-secrets-manager-3.758.0.tgz", - "integrity": "sha512-Vi4cdCim0jQx3rrU5R1W4v3czoWL0ajBtoI15oSSt7cwLjzNA0xq4nXSa6rahjTgtZWlLeBprbquvxNzY3qg5Q==", + "version": "3.772.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-secrets-manager/-/client-secrets-manager-3.772.0.tgz", + "integrity": "sha512-hY/MWUbjeHW9fQpRQbm6AXHDwL7++/cZYu+b7vxT4gH/6g4ivLiO/kgMI0F6Xeu3v6/fMumTUuNuLDfWfE7vpQ==", "license": "Apache-2.0", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.758.0", - "@aws-sdk/credential-provider-node": "3.758.0", + "@aws-sdk/credential-provider-node": "3.772.0", "@aws-sdk/middleware-host-header": "3.734.0", "@aws-sdk/middleware-logger": "3.734.0", - "@aws-sdk/middleware-recursion-detection": "3.734.0", + "@aws-sdk/middleware-recursion-detection": "3.772.0", "@aws-sdk/middleware-user-agent": "3.758.0", "@aws-sdk/region-config-resolver": "3.734.0", "@aws-sdk/types": "3.734.0", @@ -5528,74 +6396,287 @@ "node": ">=18.0.0" } }, - "node_modules/@aws-sdk/client-sfn": { - "version": "3.741.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sfn/-/client-sfn-3.741.0.tgz", - "integrity": "sha512-VW5q2tgTc49Xa8OfNR3jCiQvsMd2y/GYmpMWES/HlWMnWdwb/T/7QfJbJ51SDIoZ9C0x4qKZpbjPwgqbdi82nA==", + "node_modules/@aws-sdk/client-secrets-manager/node_modules/@aws-sdk/client-sso": { + "version": "3.772.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.772.0.tgz", + "integrity": "sha512-sDdxepi74+cL6gXJJ2yw3UNSI7GBvoGTwZqFyPoNAzcURvaYwo8dBr7G4jS9GDanjTlO3CGVAf2VMcpqEvmoEw==", "license": "Apache-2.0", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "3.734.0", - "@aws-sdk/credential-provider-node": "3.741.0", + "@aws-sdk/core": "3.758.0", "@aws-sdk/middleware-host-header": "3.734.0", "@aws-sdk/middleware-logger": "3.734.0", - "@aws-sdk/middleware-recursion-detection": "3.734.0", - "@aws-sdk/middleware-user-agent": "3.734.0", + "@aws-sdk/middleware-recursion-detection": "3.772.0", + "@aws-sdk/middleware-user-agent": "3.758.0", "@aws-sdk/region-config-resolver": "3.734.0", "@aws-sdk/types": "3.734.0", - "@aws-sdk/util-endpoints": "3.734.0", + "@aws-sdk/util-endpoints": "3.743.0", "@aws-sdk/util-user-agent-browser": "3.734.0", - "@aws-sdk/util-user-agent-node": "3.734.0", + "@aws-sdk/util-user-agent-node": "3.758.0", "@smithy/config-resolver": "^4.0.1", - "@smithy/core": "^3.1.1", + "@smithy/core": "^3.1.5", "@smithy/fetch-http-handler": "^5.0.1", "@smithy/hash-node": "^4.0.1", "@smithy/invalid-dependency": "^4.0.1", "@smithy/middleware-content-length": "^4.0.1", - "@smithy/middleware-endpoint": "^4.0.2", - "@smithy/middleware-retry": "^4.0.3", - "@smithy/middleware-serde": "^4.0.1", + "@smithy/middleware-endpoint": "^4.0.6", + "@smithy/middleware-retry": "^4.0.7", + "@smithy/middleware-serde": "^4.0.2", "@smithy/middleware-stack": "^4.0.1", "@smithy/node-config-provider": "^4.0.1", - "@smithy/node-http-handler": "^4.0.2", + "@smithy/node-http-handler": "^4.0.3", "@smithy/protocol-http": "^5.0.1", - "@smithy/smithy-client": "^4.1.2", + "@smithy/smithy-client": "^4.1.6", "@smithy/types": "^4.1.0", "@smithy/url-parser": "^4.0.1", "@smithy/util-base64": "^4.0.0", "@smithy/util-body-length-browser": "^4.0.0", "@smithy/util-body-length-node": "^4.0.0", - "@smithy/util-defaults-mode-browser": "^4.0.3", - "@smithy/util-defaults-mode-node": "^4.0.3", + "@smithy/util-defaults-mode-browser": "^4.0.7", + "@smithy/util-defaults-mode-node": "^4.0.7", "@smithy/util-endpoints": "^3.0.1", "@smithy/util-middleware": "^4.0.1", "@smithy/util-retry": "^4.0.1", "@smithy/util-utf8": "^4.0.0", - "@types/uuid": "^9.0.1", - "tslib": "^2.6.2", - "uuid": "^9.0.1" + "tslib": "^2.6.2" }, "engines": { "node": ">=18.0.0" } }, - "node_modules/@aws-sdk/client-sfn/node_modules/@aws-sdk/client-sso": { - "version": "3.734.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.734.0.tgz", - "integrity": "sha512-oerepp0mut9VlgTwnG5Ds/lb0C0b2/rQ+hL/rF6q+HGKPfGsCuPvFx1GtwGKCXd49ase88/jVgrhcA9OQbz3kg==", + "node_modules/@aws-sdk/client-secrets-manager/node_modules/@aws-sdk/credential-provider-ini": { + "version": "3.772.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.772.0.tgz", + "integrity": "sha512-T1Ec9Q25zl5c/eZUPHZsiq8vgBeWBjHM7WM5xtZszZRPqqhQGnmFlomz1r9rwhW8RFB5k8HRaD/SLKo6jtYl/A==", "license": "Apache-2.0", "dependencies": { - "@aws-crypto/sha256-browser": "5.2.0", - "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "3.734.0", - "@aws-sdk/middleware-host-header": "3.734.0", - "@aws-sdk/middleware-logger": "3.734.0", - "@aws-sdk/middleware-recursion-detection": "3.734.0", - "@aws-sdk/middleware-user-agent": "3.734.0", - "@aws-sdk/region-config-resolver": "3.734.0", + "@aws-sdk/core": "3.758.0", + "@aws-sdk/credential-provider-env": "3.758.0", + "@aws-sdk/credential-provider-http": "3.758.0", + "@aws-sdk/credential-provider-process": "3.758.0", + "@aws-sdk/credential-provider-sso": "3.772.0", + "@aws-sdk/credential-provider-web-identity": "3.772.0", + "@aws-sdk/nested-clients": "3.772.0", "@aws-sdk/types": "3.734.0", - "@aws-sdk/util-endpoints": "3.734.0", + "@smithy/credential-provider-imds": "^4.0.1", + "@smithy/property-provider": "^4.0.1", + "@smithy/shared-ini-file-loader": "^4.0.1", + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-secrets-manager/node_modules/@aws-sdk/credential-provider-node": { + "version": "3.772.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.772.0.tgz", + "integrity": "sha512-0IdVfjBO88Mtekq/KaScYSIEPIeR+ABRvBOWyj/c/qQ2KJyI0GRlSAzpANfxDLHVPn3yEHuZd9nRL6sOmOMI0A==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/credential-provider-env": "3.758.0", + "@aws-sdk/credential-provider-http": "3.758.0", + "@aws-sdk/credential-provider-ini": "3.772.0", + "@aws-sdk/credential-provider-process": "3.758.0", + "@aws-sdk/credential-provider-sso": "3.772.0", + "@aws-sdk/credential-provider-web-identity": "3.772.0", + "@aws-sdk/types": "3.734.0", + "@smithy/credential-provider-imds": "^4.0.1", + "@smithy/property-provider": "^4.0.1", + "@smithy/shared-ini-file-loader": "^4.0.1", + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-secrets-manager/node_modules/@aws-sdk/credential-provider-sso": { + "version": "3.772.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.772.0.tgz", + "integrity": "sha512-yR3Y5RAVPa4ogojcBOpZUx6XyRVAkynIJCjd0avdlxW1hhnzSr5/pzoiJ6u21UCbkxlJJTDZE3jfFe7tt+HA4w==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/client-sso": "3.772.0", + "@aws-sdk/core": "3.758.0", + "@aws-sdk/token-providers": "3.772.0", + "@aws-sdk/types": "3.734.0", + "@smithy/property-provider": "^4.0.1", + "@smithy/shared-ini-file-loader": "^4.0.1", + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-secrets-manager/node_modules/@aws-sdk/credential-provider-web-identity": { + "version": "3.772.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.772.0.tgz", + "integrity": "sha512-yHAT5Y2y0fnecSuWRUn8NMunKfDqFYhnOpGq8UyCEcwz9aXzibU0hqRIEm51qpR81hqo0GMFDH0EOmegZ/iW5w==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.758.0", + "@aws-sdk/nested-clients": "3.772.0", + "@aws-sdk/types": "3.734.0", + "@smithy/property-provider": "^4.0.1", + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-secrets-manager/node_modules/@aws-sdk/middleware-recursion-detection": { + "version": "3.772.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.772.0.tgz", + "integrity": "sha512-zg0LjJa4v7fcLzn5QzZvtVS+qyvmsnu7oQnb86l6ckduZpWDCDC9+A0ZzcXTrxblPCJd3JqkoG1+Gzi4S4Ny/Q==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.734.0", + "@smithy/protocol-http": "^5.0.1", + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-secrets-manager/node_modules/@aws-sdk/nested-clients": { + "version": "3.772.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/nested-clients/-/nested-clients-3.772.0.tgz", + "integrity": "sha512-gNJbBxR5YlEumsCS9EWWEASXEnysL0aDnr9MNPX1ip/g1xOqRHmytgV/+t8RFZFTKg0OprbWTq5Ich3MqsEuCQ==", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "3.758.0", + "@aws-sdk/middleware-host-header": "3.734.0", + "@aws-sdk/middleware-logger": "3.734.0", + "@aws-sdk/middleware-recursion-detection": "3.772.0", + "@aws-sdk/middleware-user-agent": "3.758.0", + "@aws-sdk/region-config-resolver": "3.734.0", + "@aws-sdk/types": "3.734.0", + "@aws-sdk/util-endpoints": "3.743.0", + "@aws-sdk/util-user-agent-browser": "3.734.0", + "@aws-sdk/util-user-agent-node": "3.758.0", + "@smithy/config-resolver": "^4.0.1", + "@smithy/core": "^3.1.5", + "@smithy/fetch-http-handler": "^5.0.1", + "@smithy/hash-node": "^4.0.1", + "@smithy/invalid-dependency": "^4.0.1", + "@smithy/middleware-content-length": "^4.0.1", + "@smithy/middleware-endpoint": "^4.0.6", + "@smithy/middleware-retry": "^4.0.7", + "@smithy/middleware-serde": "^4.0.2", + "@smithy/middleware-stack": "^4.0.1", + "@smithy/node-config-provider": "^4.0.1", + "@smithy/node-http-handler": "^4.0.3", + "@smithy/protocol-http": "^5.0.1", + "@smithy/smithy-client": "^4.1.6", + "@smithy/types": "^4.1.0", + "@smithy/url-parser": "^4.0.1", + "@smithy/util-base64": "^4.0.0", + "@smithy/util-body-length-browser": "^4.0.0", + "@smithy/util-body-length-node": "^4.0.0", + "@smithy/util-defaults-mode-browser": "^4.0.7", + "@smithy/util-defaults-mode-node": "^4.0.7", + "@smithy/util-endpoints": "^3.0.1", + "@smithy/util-middleware": "^4.0.1", + "@smithy/util-retry": "^4.0.1", + "@smithy/util-utf8": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-secrets-manager/node_modules/@aws-sdk/token-providers": { + "version": "3.772.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.772.0.tgz", + "integrity": "sha512-d1Waa1vyebuokcAWYlkZdtFlciIgob7B39vPRmtxMObbGumJKiOy/qCe2/FB/72h1Ej9Ih32lwvbxUjORQWN4g==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/nested-clients": "3.772.0", + "@aws-sdk/types": "3.734.0", + "@smithy/property-provider": "^4.0.1", + "@smithy/shared-ini-file-loader": "^4.0.1", + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-sfn": { + "version": "3.741.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sfn/-/client-sfn-3.741.0.tgz", + "integrity": "sha512-VW5q2tgTc49Xa8OfNR3jCiQvsMd2y/GYmpMWES/HlWMnWdwb/T/7QfJbJ51SDIoZ9C0x4qKZpbjPwgqbdi82nA==", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "3.734.0", + "@aws-sdk/credential-provider-node": "3.741.0", + "@aws-sdk/middleware-host-header": "3.734.0", + "@aws-sdk/middleware-logger": "3.734.0", + "@aws-sdk/middleware-recursion-detection": "3.734.0", + "@aws-sdk/middleware-user-agent": "3.734.0", + "@aws-sdk/region-config-resolver": "3.734.0", + "@aws-sdk/types": "3.734.0", + "@aws-sdk/util-endpoints": "3.734.0", + "@aws-sdk/util-user-agent-browser": "3.734.0", + "@aws-sdk/util-user-agent-node": "3.734.0", + "@smithy/config-resolver": "^4.0.1", + "@smithy/core": "^3.1.1", + "@smithy/fetch-http-handler": "^5.0.1", + "@smithy/hash-node": "^4.0.1", + "@smithy/invalid-dependency": "^4.0.1", + "@smithy/middleware-content-length": "^4.0.1", + "@smithy/middleware-endpoint": "^4.0.2", + "@smithy/middleware-retry": "^4.0.3", + "@smithy/middleware-serde": "^4.0.1", + "@smithy/middleware-stack": "^4.0.1", + "@smithy/node-config-provider": "^4.0.1", + "@smithy/node-http-handler": "^4.0.2", + "@smithy/protocol-http": "^5.0.1", + "@smithy/smithy-client": "^4.1.2", + "@smithy/types": "^4.1.0", + "@smithy/url-parser": "^4.0.1", + "@smithy/util-base64": "^4.0.0", + "@smithy/util-body-length-browser": "^4.0.0", + "@smithy/util-body-length-node": "^4.0.0", + "@smithy/util-defaults-mode-browser": "^4.0.3", + "@smithy/util-defaults-mode-node": "^4.0.3", + "@smithy/util-endpoints": "^3.0.1", + "@smithy/util-middleware": "^4.0.1", + "@smithy/util-retry": "^4.0.1", + "@smithy/util-utf8": "^4.0.0", + "@types/uuid": "^9.0.1", + "tslib": "^2.6.2", + "uuid": "^9.0.1" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-sfn/node_modules/@aws-sdk/client-sso": { + "version": "3.734.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.734.0.tgz", + "integrity": "sha512-oerepp0mut9VlgTwnG5Ds/lb0C0b2/rQ+hL/rF6q+HGKPfGsCuPvFx1GtwGKCXd49ase88/jVgrhcA9OQbz3kg==", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "3.734.0", + "@aws-sdk/middleware-host-header": "3.734.0", + "@aws-sdk/middleware-logger": "3.734.0", + "@aws-sdk/middleware-recursion-detection": "3.734.0", + "@aws-sdk/middleware-user-agent": "3.734.0", + "@aws-sdk/region-config-resolver": "3.734.0", + "@aws-sdk/types": "3.734.0", + "@aws-sdk/util-endpoints": "3.734.0", "@aws-sdk/util-user-agent-browser": "3.734.0", "@aws-sdk/util-user-agent-node": "3.734.0", "@smithy/config-resolver": "^4.0.1", @@ -5912,18 +6993,18 @@ } }, "node_modules/@aws-sdk/client-ssm": { - "version": "3.759.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-ssm/-/client-ssm-3.759.0.tgz", - "integrity": "sha512-+h1D1jBi6p2fG+ePxwIn2N4TOZcx7ExzhZJnpPT2actC9bV6vkRbeulGr/2fqNu11/S59DZJLfOHjVDH9X1nWA==", + "version": "3.772.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-ssm/-/client-ssm-3.772.0.tgz", + "integrity": "sha512-NPXybSztwGakQNonIHbMlwzTUaiHTSR+RsJnNrZkXpfp57Zny2zxcea8P/9OGQsCg3neUzRtoZxgPWb4jA9hLA==", "license": "Apache-2.0", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.758.0", - "@aws-sdk/credential-provider-node": "3.758.0", + "@aws-sdk/credential-provider-node": "3.772.0", "@aws-sdk/middleware-host-header": "3.734.0", "@aws-sdk/middleware-logger": "3.734.0", - "@aws-sdk/middleware-recursion-detection": "3.734.0", + "@aws-sdk/middleware-recursion-detection": "3.772.0", "@aws-sdk/middleware-user-agent": "3.758.0", "@aws-sdk/region-config-resolver": "3.734.0", "@aws-sdk/types": "3.734.0", @@ -5964,10 +7045,10 @@ "node": ">=18.0.0" } }, - "node_modules/@aws-sdk/client-sso": { - "version": "3.758.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.758.0.tgz", - "integrity": "sha512-BoGO6IIWrLyLxQG6txJw6RT2urmbtlwfggapNCrNPyYjlXpzTSJhBYjndg7TpDATFd0SXL0zm8y/tXsUXNkdYQ==", + "node_modules/@aws-sdk/client-ssm/node_modules/@aws-sdk/client-sso": { + "version": "3.772.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.772.0.tgz", + "integrity": "sha512-sDdxepi74+cL6gXJJ2yw3UNSI7GBvoGTwZqFyPoNAzcURvaYwo8dBr7G4jS9GDanjTlO3CGVAf2VMcpqEvmoEw==", "license": "Apache-2.0", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", @@ -5975,7 +7056,7 @@ "@aws-sdk/core": "3.758.0", "@aws-sdk/middleware-host-header": "3.734.0", "@aws-sdk/middleware-logger": "3.734.0", - "@aws-sdk/middleware-recursion-detection": "3.734.0", + "@aws-sdk/middleware-recursion-detection": "3.772.0", "@aws-sdk/middleware-user-agent": "3.758.0", "@aws-sdk/region-config-resolver": "3.734.0", "@aws-sdk/types": "3.734.0", @@ -6013,76 +7094,122 @@ "node": ">=18.0.0" } }, - "node_modules/@aws-sdk/client-sts": { - "version": "3.758.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.758.0.tgz", - "integrity": "sha512-ue9hbzjWNQmmyoSeWDRPwnYddsD3BVao5mSFA1kXFNVqWPEenjpkZ1xAlBVzHMMNoEz7LvGI+onXIHntNyiOLQ==", + "node_modules/@aws-sdk/client-ssm/node_modules/@aws-sdk/credential-provider-ini": { + "version": "3.772.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.772.0.tgz", + "integrity": "sha512-T1Ec9Q25zl5c/eZUPHZsiq8vgBeWBjHM7WM5xtZszZRPqqhQGnmFlomz1r9rwhW8RFB5k8HRaD/SLKo6jtYl/A==", "license": "Apache-2.0", "dependencies": { - "@aws-crypto/sha256-browser": "5.2.0", - "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "3.758.0", - "@aws-sdk/credential-provider-node": "3.758.0", - "@aws-sdk/middleware-host-header": "3.734.0", - "@aws-sdk/middleware-logger": "3.734.0", - "@aws-sdk/middleware-recursion-detection": "3.734.0", - "@aws-sdk/middleware-user-agent": "3.758.0", - "@aws-sdk/region-config-resolver": "3.734.0", + "@aws-sdk/credential-provider-env": "3.758.0", + "@aws-sdk/credential-provider-http": "3.758.0", + "@aws-sdk/credential-provider-process": "3.758.0", + "@aws-sdk/credential-provider-sso": "3.772.0", + "@aws-sdk/credential-provider-web-identity": "3.772.0", + "@aws-sdk/nested-clients": "3.772.0", "@aws-sdk/types": "3.734.0", - "@aws-sdk/util-endpoints": "3.743.0", - "@aws-sdk/util-user-agent-browser": "3.734.0", - "@aws-sdk/util-user-agent-node": "3.758.0", - "@smithy/config-resolver": "^4.0.1", - "@smithy/core": "^3.1.5", - "@smithy/fetch-http-handler": "^5.0.1", - "@smithy/hash-node": "^4.0.1", - "@smithy/invalid-dependency": "^4.0.1", - "@smithy/middleware-content-length": "^4.0.1", - "@smithy/middleware-endpoint": "^4.0.6", - "@smithy/middleware-retry": "^4.0.7", - "@smithy/middleware-serde": "^4.0.2", - "@smithy/middleware-stack": "^4.0.1", - "@smithy/node-config-provider": "^4.0.1", - "@smithy/node-http-handler": "^4.0.3", - "@smithy/protocol-http": "^5.0.1", - "@smithy/smithy-client": "^4.1.6", + "@smithy/credential-provider-imds": "^4.0.1", + "@smithy/property-provider": "^4.0.1", + "@smithy/shared-ini-file-loader": "^4.0.1", "@smithy/types": "^4.1.0", - "@smithy/url-parser": "^4.0.1", - "@smithy/util-base64": "^4.0.0", - "@smithy/util-body-length-browser": "^4.0.0", - "@smithy/util-body-length-node": "^4.0.0", - "@smithy/util-defaults-mode-browser": "^4.0.7", - "@smithy/util-defaults-mode-node": "^4.0.7", - "@smithy/util-endpoints": "^3.0.1", - "@smithy/util-middleware": "^4.0.1", - "@smithy/util-retry": "^4.0.1", - "@smithy/util-utf8": "^4.0.0", "tslib": "^2.6.2" }, "engines": { "node": ">=18.0.0" } }, - "node_modules/@aws-sdk/client-xray": { - "version": "3.758.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-xray/-/client-xray-3.758.0.tgz", - "integrity": "sha512-poHaIK6+G9tDqEpyWsn4IuKovMfP16XQsK0uQEJ2qdK80JbXB5RP+XJ9/6R156hCNoGhZ1DAy7ze0lVaw/9rBQ==", - "dev": true, + "node_modules/@aws-sdk/client-ssm/node_modules/@aws-sdk/credential-provider-node": { + "version": "3.772.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.772.0.tgz", + "integrity": "sha512-0IdVfjBO88Mtekq/KaScYSIEPIeR+ABRvBOWyj/c/qQ2KJyI0GRlSAzpANfxDLHVPn3yEHuZd9nRL6sOmOMI0A==", "license": "Apache-2.0", "dependencies": { - "@aws-crypto/sha256-browser": "5.2.0", - "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "3.758.0", - "@aws-sdk/credential-provider-node": "3.758.0", - "@aws-sdk/middleware-host-header": "3.734.0", - "@aws-sdk/middleware-logger": "3.734.0", - "@aws-sdk/middleware-recursion-detection": "3.734.0", - "@aws-sdk/middleware-user-agent": "3.758.0", - "@aws-sdk/region-config-resolver": "3.734.0", + "@aws-sdk/credential-provider-env": "3.758.0", + "@aws-sdk/credential-provider-http": "3.758.0", + "@aws-sdk/credential-provider-ini": "3.772.0", + "@aws-sdk/credential-provider-process": "3.758.0", + "@aws-sdk/credential-provider-sso": "3.772.0", + "@aws-sdk/credential-provider-web-identity": "3.772.0", "@aws-sdk/types": "3.734.0", - "@aws-sdk/util-endpoints": "3.743.0", - "@aws-sdk/util-user-agent-browser": "3.734.0", - "@aws-sdk/util-user-agent-node": "3.758.0", + "@smithy/credential-provider-imds": "^4.0.1", + "@smithy/property-provider": "^4.0.1", + "@smithy/shared-ini-file-loader": "^4.0.1", + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-ssm/node_modules/@aws-sdk/credential-provider-sso": { + "version": "3.772.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.772.0.tgz", + "integrity": "sha512-yR3Y5RAVPa4ogojcBOpZUx6XyRVAkynIJCjd0avdlxW1hhnzSr5/pzoiJ6u21UCbkxlJJTDZE3jfFe7tt+HA4w==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/client-sso": "3.772.0", + "@aws-sdk/core": "3.758.0", + "@aws-sdk/token-providers": "3.772.0", + "@aws-sdk/types": "3.734.0", + "@smithy/property-provider": "^4.0.1", + "@smithy/shared-ini-file-loader": "^4.0.1", + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-ssm/node_modules/@aws-sdk/credential-provider-web-identity": { + "version": "3.772.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.772.0.tgz", + "integrity": "sha512-yHAT5Y2y0fnecSuWRUn8NMunKfDqFYhnOpGq8UyCEcwz9aXzibU0hqRIEm51qpR81hqo0GMFDH0EOmegZ/iW5w==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.758.0", + "@aws-sdk/nested-clients": "3.772.0", + "@aws-sdk/types": "3.734.0", + "@smithy/property-provider": "^4.0.1", + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-ssm/node_modules/@aws-sdk/middleware-recursion-detection": { + "version": "3.772.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.772.0.tgz", + "integrity": "sha512-zg0LjJa4v7fcLzn5QzZvtVS+qyvmsnu7oQnb86l6ckduZpWDCDC9+A0ZzcXTrxblPCJd3JqkoG1+Gzi4S4Ny/Q==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.734.0", + "@smithy/protocol-http": "^5.0.1", + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-ssm/node_modules/@aws-sdk/nested-clients": { + "version": "3.772.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/nested-clients/-/nested-clients-3.772.0.tgz", + "integrity": "sha512-gNJbBxR5YlEumsCS9EWWEASXEnysL0aDnr9MNPX1ip/g1xOqRHmytgV/+t8RFZFTKg0OprbWTq5Ich3MqsEuCQ==", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "3.758.0", + "@aws-sdk/middleware-host-header": "3.734.0", + "@aws-sdk/middleware-logger": "3.734.0", + "@aws-sdk/middleware-recursion-detection": "3.772.0", + "@aws-sdk/middleware-user-agent": "3.758.0", + "@aws-sdk/region-config-resolver": "3.734.0", + "@aws-sdk/types": "3.734.0", + "@aws-sdk/util-endpoints": "3.743.0", + "@aws-sdk/util-user-agent-browser": "3.734.0", + "@aws-sdk/util-user-agent-node": "3.758.0", "@smithy/config-resolver": "^4.0.1", "@smithy/core": "^3.1.5", "@smithy/fetch-http-handler": "^5.0.1", @@ -6114,6 +7241,394 @@ "node": ">=18.0.0" } }, + "node_modules/@aws-sdk/client-ssm/node_modules/@aws-sdk/token-providers": { + "version": "3.772.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.772.0.tgz", + "integrity": "sha512-d1Waa1vyebuokcAWYlkZdtFlciIgob7B39vPRmtxMObbGumJKiOy/qCe2/FB/72h1Ej9Ih32lwvbxUjORQWN4g==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/nested-clients": "3.772.0", + "@aws-sdk/types": "3.734.0", + "@smithy/property-provider": "^4.0.1", + "@smithy/shared-ini-file-loader": "^4.0.1", + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-sso": { + "version": "3.758.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.758.0.tgz", + "integrity": "sha512-BoGO6IIWrLyLxQG6txJw6RT2urmbtlwfggapNCrNPyYjlXpzTSJhBYjndg7TpDATFd0SXL0zm8y/tXsUXNkdYQ==", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "3.758.0", + "@aws-sdk/middleware-host-header": "3.734.0", + "@aws-sdk/middleware-logger": "3.734.0", + "@aws-sdk/middleware-recursion-detection": "3.734.0", + "@aws-sdk/middleware-user-agent": "3.758.0", + "@aws-sdk/region-config-resolver": "3.734.0", + "@aws-sdk/types": "3.734.0", + "@aws-sdk/util-endpoints": "3.743.0", + "@aws-sdk/util-user-agent-browser": "3.734.0", + "@aws-sdk/util-user-agent-node": "3.758.0", + "@smithy/config-resolver": "^4.0.1", + "@smithy/core": "^3.1.5", + "@smithy/fetch-http-handler": "^5.0.1", + "@smithy/hash-node": "^4.0.1", + "@smithy/invalid-dependency": "^4.0.1", + "@smithy/middleware-content-length": "^4.0.1", + "@smithy/middleware-endpoint": "^4.0.6", + "@smithy/middleware-retry": "^4.0.7", + "@smithy/middleware-serde": "^4.0.2", + "@smithy/middleware-stack": "^4.0.1", + "@smithy/node-config-provider": "^4.0.1", + "@smithy/node-http-handler": "^4.0.3", + "@smithy/protocol-http": "^5.0.1", + "@smithy/smithy-client": "^4.1.6", + "@smithy/types": "^4.1.0", + "@smithy/url-parser": "^4.0.1", + "@smithy/util-base64": "^4.0.0", + "@smithy/util-body-length-browser": "^4.0.0", + "@smithy/util-body-length-node": "^4.0.0", + "@smithy/util-defaults-mode-browser": "^4.0.7", + "@smithy/util-defaults-mode-node": "^4.0.7", + "@smithy/util-endpoints": "^3.0.1", + "@smithy/util-middleware": "^4.0.1", + "@smithy/util-retry": "^4.0.1", + "@smithy/util-utf8": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-sts": { + "version": "3.758.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.758.0.tgz", + "integrity": "sha512-ue9hbzjWNQmmyoSeWDRPwnYddsD3BVao5mSFA1kXFNVqWPEenjpkZ1xAlBVzHMMNoEz7LvGI+onXIHntNyiOLQ==", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "3.758.0", + "@aws-sdk/credential-provider-node": "3.758.0", + "@aws-sdk/middleware-host-header": "3.734.0", + "@aws-sdk/middleware-logger": "3.734.0", + "@aws-sdk/middleware-recursion-detection": "3.734.0", + "@aws-sdk/middleware-user-agent": "3.758.0", + "@aws-sdk/region-config-resolver": "3.734.0", + "@aws-sdk/types": "3.734.0", + "@aws-sdk/util-endpoints": "3.743.0", + "@aws-sdk/util-user-agent-browser": "3.734.0", + "@aws-sdk/util-user-agent-node": "3.758.0", + "@smithy/config-resolver": "^4.0.1", + "@smithy/core": "^3.1.5", + "@smithy/fetch-http-handler": "^5.0.1", + "@smithy/hash-node": "^4.0.1", + "@smithy/invalid-dependency": "^4.0.1", + "@smithy/middleware-content-length": "^4.0.1", + "@smithy/middleware-endpoint": "^4.0.6", + "@smithy/middleware-retry": "^4.0.7", + "@smithy/middleware-serde": "^4.0.2", + "@smithy/middleware-stack": "^4.0.1", + "@smithy/node-config-provider": "^4.0.1", + "@smithy/node-http-handler": "^4.0.3", + "@smithy/protocol-http": "^5.0.1", + "@smithy/smithy-client": "^4.1.6", + "@smithy/types": "^4.1.0", + "@smithy/url-parser": "^4.0.1", + "@smithy/util-base64": "^4.0.0", + "@smithy/util-body-length-browser": "^4.0.0", + "@smithy/util-body-length-node": "^4.0.0", + "@smithy/util-defaults-mode-browser": "^4.0.7", + "@smithy/util-defaults-mode-node": "^4.0.7", + "@smithy/util-endpoints": "^3.0.1", + "@smithy/util-middleware": "^4.0.1", + "@smithy/util-retry": "^4.0.1", + "@smithy/util-utf8": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-xray": { + "version": "3.772.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-xray/-/client-xray-3.772.0.tgz", + "integrity": "sha512-75BLs9JROxsuL8qbPqSLszu4iCCZgJuq7s2E/hnO3B/AaJIjxGDpYSJotQcgB9F0zioJ3vmfDejtQyb+/+j3mw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "3.758.0", + "@aws-sdk/credential-provider-node": "3.772.0", + "@aws-sdk/middleware-host-header": "3.734.0", + "@aws-sdk/middleware-logger": "3.734.0", + "@aws-sdk/middleware-recursion-detection": "3.772.0", + "@aws-sdk/middleware-user-agent": "3.758.0", + "@aws-sdk/region-config-resolver": "3.734.0", + "@aws-sdk/types": "3.734.0", + "@aws-sdk/util-endpoints": "3.743.0", + "@aws-sdk/util-user-agent-browser": "3.734.0", + "@aws-sdk/util-user-agent-node": "3.758.0", + "@smithy/config-resolver": "^4.0.1", + "@smithy/core": "^3.1.5", + "@smithy/fetch-http-handler": "^5.0.1", + "@smithy/hash-node": "^4.0.1", + "@smithy/invalid-dependency": "^4.0.1", + "@smithy/middleware-content-length": "^4.0.1", + "@smithy/middleware-endpoint": "^4.0.6", + "@smithy/middleware-retry": "^4.0.7", + "@smithy/middleware-serde": "^4.0.2", + "@smithy/middleware-stack": "^4.0.1", + "@smithy/node-config-provider": "^4.0.1", + "@smithy/node-http-handler": "^4.0.3", + "@smithy/protocol-http": "^5.0.1", + "@smithy/smithy-client": "^4.1.6", + "@smithy/types": "^4.1.0", + "@smithy/url-parser": "^4.0.1", + "@smithy/util-base64": "^4.0.0", + "@smithy/util-body-length-browser": "^4.0.0", + "@smithy/util-body-length-node": "^4.0.0", + "@smithy/util-defaults-mode-browser": "^4.0.7", + "@smithy/util-defaults-mode-node": "^4.0.7", + "@smithy/util-endpoints": "^3.0.1", + "@smithy/util-middleware": "^4.0.1", + "@smithy/util-retry": "^4.0.1", + "@smithy/util-utf8": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-xray/node_modules/@aws-sdk/client-sso": { + "version": "3.772.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.772.0.tgz", + "integrity": "sha512-sDdxepi74+cL6gXJJ2yw3UNSI7GBvoGTwZqFyPoNAzcURvaYwo8dBr7G4jS9GDanjTlO3CGVAf2VMcpqEvmoEw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "3.758.0", + "@aws-sdk/middleware-host-header": "3.734.0", + "@aws-sdk/middleware-logger": "3.734.0", + "@aws-sdk/middleware-recursion-detection": "3.772.0", + "@aws-sdk/middleware-user-agent": "3.758.0", + "@aws-sdk/region-config-resolver": "3.734.0", + "@aws-sdk/types": "3.734.0", + "@aws-sdk/util-endpoints": "3.743.0", + "@aws-sdk/util-user-agent-browser": "3.734.0", + "@aws-sdk/util-user-agent-node": "3.758.0", + "@smithy/config-resolver": "^4.0.1", + "@smithy/core": "^3.1.5", + "@smithy/fetch-http-handler": "^5.0.1", + "@smithy/hash-node": "^4.0.1", + "@smithy/invalid-dependency": "^4.0.1", + "@smithy/middleware-content-length": "^4.0.1", + "@smithy/middleware-endpoint": "^4.0.6", + "@smithy/middleware-retry": "^4.0.7", + "@smithy/middleware-serde": "^4.0.2", + "@smithy/middleware-stack": "^4.0.1", + "@smithy/node-config-provider": "^4.0.1", + "@smithy/node-http-handler": "^4.0.3", + "@smithy/protocol-http": "^5.0.1", + "@smithy/smithy-client": "^4.1.6", + "@smithy/types": "^4.1.0", + "@smithy/url-parser": "^4.0.1", + "@smithy/util-base64": "^4.0.0", + "@smithy/util-body-length-browser": "^4.0.0", + "@smithy/util-body-length-node": "^4.0.0", + "@smithy/util-defaults-mode-browser": "^4.0.7", + "@smithy/util-defaults-mode-node": "^4.0.7", + "@smithy/util-endpoints": "^3.0.1", + "@smithy/util-middleware": "^4.0.1", + "@smithy/util-retry": "^4.0.1", + "@smithy/util-utf8": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-xray/node_modules/@aws-sdk/credential-provider-ini": { + "version": "3.772.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.772.0.tgz", + "integrity": "sha512-T1Ec9Q25zl5c/eZUPHZsiq8vgBeWBjHM7WM5xtZszZRPqqhQGnmFlomz1r9rwhW8RFB5k8HRaD/SLKo6jtYl/A==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.758.0", + "@aws-sdk/credential-provider-env": "3.758.0", + "@aws-sdk/credential-provider-http": "3.758.0", + "@aws-sdk/credential-provider-process": "3.758.0", + "@aws-sdk/credential-provider-sso": "3.772.0", + "@aws-sdk/credential-provider-web-identity": "3.772.0", + "@aws-sdk/nested-clients": "3.772.0", + "@aws-sdk/types": "3.734.0", + "@smithy/credential-provider-imds": "^4.0.1", + "@smithy/property-provider": "^4.0.1", + "@smithy/shared-ini-file-loader": "^4.0.1", + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-xray/node_modules/@aws-sdk/credential-provider-node": { + "version": "3.772.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.772.0.tgz", + "integrity": "sha512-0IdVfjBO88Mtekq/KaScYSIEPIeR+ABRvBOWyj/c/qQ2KJyI0GRlSAzpANfxDLHVPn3yEHuZd9nRL6sOmOMI0A==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/credential-provider-env": "3.758.0", + "@aws-sdk/credential-provider-http": "3.758.0", + "@aws-sdk/credential-provider-ini": "3.772.0", + "@aws-sdk/credential-provider-process": "3.758.0", + "@aws-sdk/credential-provider-sso": "3.772.0", + "@aws-sdk/credential-provider-web-identity": "3.772.0", + "@aws-sdk/types": "3.734.0", + "@smithy/credential-provider-imds": "^4.0.1", + "@smithy/property-provider": "^4.0.1", + "@smithy/shared-ini-file-loader": "^4.0.1", + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-xray/node_modules/@aws-sdk/credential-provider-sso": { + "version": "3.772.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.772.0.tgz", + "integrity": "sha512-yR3Y5RAVPa4ogojcBOpZUx6XyRVAkynIJCjd0avdlxW1hhnzSr5/pzoiJ6u21UCbkxlJJTDZE3jfFe7tt+HA4w==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/client-sso": "3.772.0", + "@aws-sdk/core": "3.758.0", + "@aws-sdk/token-providers": "3.772.0", + "@aws-sdk/types": "3.734.0", + "@smithy/property-provider": "^4.0.1", + "@smithy/shared-ini-file-loader": "^4.0.1", + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-xray/node_modules/@aws-sdk/credential-provider-web-identity": { + "version": "3.772.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.772.0.tgz", + "integrity": "sha512-yHAT5Y2y0fnecSuWRUn8NMunKfDqFYhnOpGq8UyCEcwz9aXzibU0hqRIEm51qpR81hqo0GMFDH0EOmegZ/iW5w==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.758.0", + "@aws-sdk/nested-clients": "3.772.0", + "@aws-sdk/types": "3.734.0", + "@smithy/property-provider": "^4.0.1", + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-xray/node_modules/@aws-sdk/middleware-recursion-detection": { + "version": "3.772.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.772.0.tgz", + "integrity": "sha512-zg0LjJa4v7fcLzn5QzZvtVS+qyvmsnu7oQnb86l6ckduZpWDCDC9+A0ZzcXTrxblPCJd3JqkoG1+Gzi4S4Ny/Q==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.734.0", + "@smithy/protocol-http": "^5.0.1", + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-xray/node_modules/@aws-sdk/nested-clients": { + "version": "3.772.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/nested-clients/-/nested-clients-3.772.0.tgz", + "integrity": "sha512-gNJbBxR5YlEumsCS9EWWEASXEnysL0aDnr9MNPX1ip/g1xOqRHmytgV/+t8RFZFTKg0OprbWTq5Ich3MqsEuCQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "3.758.0", + "@aws-sdk/middleware-host-header": "3.734.0", + "@aws-sdk/middleware-logger": "3.734.0", + "@aws-sdk/middleware-recursion-detection": "3.772.0", + "@aws-sdk/middleware-user-agent": "3.758.0", + "@aws-sdk/region-config-resolver": "3.734.0", + "@aws-sdk/types": "3.734.0", + "@aws-sdk/util-endpoints": "3.743.0", + "@aws-sdk/util-user-agent-browser": "3.734.0", + "@aws-sdk/util-user-agent-node": "3.758.0", + "@smithy/config-resolver": "^4.0.1", + "@smithy/core": "^3.1.5", + "@smithy/fetch-http-handler": "^5.0.1", + "@smithy/hash-node": "^4.0.1", + "@smithy/invalid-dependency": "^4.0.1", + "@smithy/middleware-content-length": "^4.0.1", + "@smithy/middleware-endpoint": "^4.0.6", + "@smithy/middleware-retry": "^4.0.7", + "@smithy/middleware-serde": "^4.0.2", + "@smithy/middleware-stack": "^4.0.1", + "@smithy/node-config-provider": "^4.0.1", + "@smithy/node-http-handler": "^4.0.3", + "@smithy/protocol-http": "^5.0.1", + "@smithy/smithy-client": "^4.1.6", + "@smithy/types": "^4.1.0", + "@smithy/url-parser": "^4.0.1", + "@smithy/util-base64": "^4.0.0", + "@smithy/util-body-length-browser": "^4.0.0", + "@smithy/util-body-length-node": "^4.0.0", + "@smithy/util-defaults-mode-browser": "^4.0.7", + "@smithy/util-defaults-mode-node": "^4.0.7", + "@smithy/util-endpoints": "^3.0.1", + "@smithy/util-middleware": "^4.0.1", + "@smithy/util-retry": "^4.0.1", + "@smithy/util-utf8": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-xray/node_modules/@aws-sdk/token-providers": { + "version": "3.772.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.772.0.tgz", + "integrity": "sha512-d1Waa1vyebuokcAWYlkZdtFlciIgob7B39vPRmtxMObbGumJKiOy/qCe2/FB/72h1Ej9Ih32lwvbxUjORQWN4g==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/nested-clients": "3.772.0", + "@aws-sdk/types": "3.734.0", + "@smithy/property-provider": "^4.0.1", + "@smithy/shared-ini-file-loader": "^4.0.1", + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, "node_modules/@aws-sdk/core": { "version": "3.758.0", "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.758.0.tgz", @@ -6349,13 +7864,13 @@ } }, "node_modules/@aws-sdk/lib-dynamodb": { - "version": "3.767.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/lib-dynamodb/-/lib-dynamodb-3.767.0.tgz", - "integrity": "sha512-Vl93kIcntUzVdnJZf1VgHhtkue8Xk6pVK3L5hoc90z2RUlqLyl279+LiK8lE5xYaiRTxoCu+BI0dxSp0F1G8YQ==", + "version": "3.772.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/lib-dynamodb/-/lib-dynamodb-3.772.0.tgz", + "integrity": "sha512-+ir8eClWxfkwrgYrgWCGh41EZ/07JPXJwvEmmhETzNDqvT/FaWLJC5rSKJW7o8nFxljW73lrwLreIO0oyBOsZw==", "license": "Apache-2.0", "dependencies": { "@aws-sdk/core": "3.758.0", - "@aws-sdk/util-dynamodb": "3.767.0", + "@aws-sdk/util-dynamodb": "3.772.0", "@smithy/core": "^3.1.5", "@smithy/smithy-client": "^4.1.6", "@smithy/types": "^4.1.0", @@ -6365,7 +7880,7 @@ "node": ">=18.0.0" }, "peerDependencies": { - "@aws-sdk/client-dynamodb": "^3.767.0" + "@aws-sdk/client-dynamodb": "^3.772.0" } }, "node_modules/@aws-sdk/lib-storage": { @@ -6756,9 +8271,9 @@ } }, "node_modules/@aws-sdk/util-dynamodb": { - "version": "3.767.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-dynamodb/-/util-dynamodb-3.767.0.tgz", - "integrity": "sha512-/unz0bnrEc6XyVFai4drJipigb2B2NdK9Hku5V7Tq3a98YQtDvi5aLdWFt3pte38FqKW4snU1v15sbl3ZH1i5A==", + "version": "3.772.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-dynamodb/-/util-dynamodb-3.772.0.tgz", + "integrity": "sha512-joFi/d2BJir7jCWKYe26CqBSbC5B0FZ33UmF9K+ft5tGPvpPkdDpfkqAXD/t+NN/119TbxfSpkLehnI8VowXZg==", "license": "Apache-2.0", "dependencies": { "tslib": "^2.6.2" @@ -6767,7 +8282,7 @@ "node": ">=18.0.0" }, "peerDependencies": { - "@aws-sdk/client-dynamodb": "^3.767.0" + "@aws-sdk/client-dynamodb": "^3.772.0" } }, "node_modules/@aws-sdk/util-endpoints": { @@ -21462,8 +22977,8 @@ }, "devDependencies": { "@aws-lambda-powertools/testing-utils": "file:../testing", - "@aws-sdk/client-dynamodb": "^3.767.0", - "@aws-sdk/lib-dynamodb": "^3.767.0", + "@aws-sdk/client-dynamodb": "^3.772.0", + "@aws-sdk/lib-dynamodb": "^3.772.0", "aws-sdk-client-mock": "^4.1.0" }, "peerDependencies": { @@ -21525,7 +23040,7 @@ }, "devDependencies": { "@aws-lambda-powertools/testing-utils": "file:../testing", - "@aws-sdk/client-cloudwatch": "^3.758.0", + "@aws-sdk/client-cloudwatch": "^3.772.0", "@types/promise-retry": "^1.1.3", "promise-retry": "^2.0.1" }, @@ -21547,11 +23062,11 @@ }, "devDependencies": { "@aws-lambda-powertools/testing-utils": "file:../testing", - "@aws-sdk/client-appconfigdata": "^3.758.0", - "@aws-sdk/client-dynamodb": "^3.767.0", - "@aws-sdk/client-secrets-manager": "^3.758.0", - "@aws-sdk/client-ssm": "^3.759.0", - "@aws-sdk/util-dynamodb": "^3.767.0", + "@aws-sdk/client-appconfigdata": "^3.772.0", + "@aws-sdk/client-dynamodb": "^3.772.0", + "@aws-sdk/client-secrets-manager": "^3.772.0", + "@aws-sdk/client-ssm": "^3.772.0", + "@aws-sdk/util-dynamodb": "^3.772.0", "@smithy/util-base64": "^4.0.0", "aws-sdk-client-mock": "^4.1.0" }, @@ -21610,7 +23125,7 @@ "license": "MIT-0", "dependencies": { "@aws-cdk/toolkit-lib": "^0.1.6", - "@aws-sdk/client-lambda": "^3.771.0", + "@aws-sdk/client-lambda": "^3.772.0", "@smithy/util-utf8": "^4.0.0", "aws-cdk-lib": "^2.185.0", "esbuild": "^0.25.1", @@ -21631,8 +23146,8 @@ }, "devDependencies": { "@aws-lambda-powertools/testing-utils": "file:../testing", - "@aws-sdk/client-dynamodb": "^3.767.0", - "@aws-sdk/client-xray": "^3.758.0" + "@aws-sdk/client-dynamodb": "^3.772.0", + "@aws-sdk/client-xray": "^3.772.0" }, "peerDependencies": { "@middy/core": "4.x || 5.x || 6.x" diff --git a/packages/idempotency/package.json b/packages/idempotency/package.json index 4a7d9c5077..cea2f4ee4b 100644 --- a/packages/idempotency/package.json +++ b/packages/idempotency/package.json @@ -127,8 +127,8 @@ ], "devDependencies": { "@aws-lambda-powertools/testing-utils": "file:../testing", - "@aws-sdk/client-dynamodb": "^3.767.0", - "@aws-sdk/lib-dynamodb": "^3.767.0", + "@aws-sdk/client-dynamodb": "^3.772.0", + "@aws-sdk/lib-dynamodb": "^3.772.0", "aws-sdk-client-mock": "^4.1.0" } } diff --git a/packages/metrics/package.json b/packages/metrics/package.json index f189e9f857..95cd89deb6 100644 --- a/packages/metrics/package.json +++ b/packages/metrics/package.json @@ -65,7 +65,7 @@ "main": "./lib/cjs/index.js", "devDependencies": { "@aws-lambda-powertools/testing-utils": "file:../testing", - "@aws-sdk/client-cloudwatch": "^3.758.0", + "@aws-sdk/client-cloudwatch": "^3.772.0", "@types/promise-retry": "^1.1.3", "promise-retry": "^2.0.1" }, diff --git a/packages/parameters/package.json b/packages/parameters/package.json index fc7e34366b..d58c5a3208 100644 --- a/packages/parameters/package.json +++ b/packages/parameters/package.json @@ -156,11 +156,11 @@ ], "devDependencies": { "@aws-lambda-powertools/testing-utils": "file:../testing", - "@aws-sdk/client-appconfigdata": "^3.758.0", - "@aws-sdk/client-dynamodb": "^3.767.0", - "@aws-sdk/client-secrets-manager": "^3.758.0", - "@aws-sdk/client-ssm": "^3.759.0", - "@aws-sdk/util-dynamodb": "^3.767.0", + "@aws-sdk/client-appconfigdata": "^3.772.0", + "@aws-sdk/client-dynamodb": "^3.772.0", + "@aws-sdk/client-secrets-manager": "^3.772.0", + "@aws-sdk/client-ssm": "^3.772.0", + "@aws-sdk/util-dynamodb": "^3.772.0", "@smithy/util-base64": "^4.0.0", "aws-sdk-client-mock": "^4.1.0" }, diff --git a/packages/testing/package.json b/packages/testing/package.json index af4334d075..9aa4ffa87a 100644 --- a/packages/testing/package.json +++ b/packages/testing/package.json @@ -98,7 +98,7 @@ "homepage": "https://github.com/aws-powertools/powertools-lambda-typescript/tree/main/packages/testing#readme", "dependencies": { "@aws-cdk/toolkit-lib": "^0.1.6", - "@aws-sdk/client-lambda": "^3.771.0", + "@aws-sdk/client-lambda": "^3.772.0", "@smithy/util-utf8": "^4.0.0", "aws-cdk-lib": "^2.185.0", "esbuild": "^0.25.1", diff --git a/packages/tracer/package.json b/packages/tracer/package.json index 09eb0517bf..6399102ae8 100644 --- a/packages/tracer/package.json +++ b/packages/tracer/package.json @@ -30,8 +30,8 @@ "license": "MIT-0", "devDependencies": { "@aws-lambda-powertools/testing-utils": "file:../testing", - "@aws-sdk/client-dynamodb": "^3.767.0", - "@aws-sdk/client-xray": "^3.758.0" + "@aws-sdk/client-dynamodb": "^3.772.0", + "@aws-sdk/client-xray": "^3.772.0" }, "peerDependencies": { "@middy/core": "4.x || 5.x || 6.x" From b44b1ebcb246d892940e85c60106c37e813a62aa Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 21 Mar 2025 17:23:30 +0100 Subject: [PATCH 47/56] chore(deps-dev): bump the typescript group across 1 directory with 2 updates (#3753) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Andrea Amorosi --- package-lock.json | 69 ++++++++++++++++++++++++++--------------------- package.json | 4 +-- 2 files changed, 40 insertions(+), 33 deletions(-) diff --git a/package-lock.json b/package-lock.json index 18f2c3a497..2d1ec5107b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -37,8 +37,8 @@ "middy4": "npm:@middy/core@^4.7.0", "middy5": "npm:@middy/core@^5.4.3", "middy6": "npm:@middy/core@^6.0.0", - "typedoc": "^0.27.9", - "typedoc-plugin-missing-exports": "^3.1.0", + "typedoc": "^0.28.1", + "typedoc-plugin-missing-exports": "^4.0.0", "typedoc-plugin-zod": "^1.4.0", "typescript": "^5.8.2", "vitest": "^3.0.9" @@ -9103,14 +9103,15 @@ } }, "node_modules/@gerrit0/mini-shiki": { - "version": "1.26.1", - "resolved": "https://registry.npmjs.org/@gerrit0/mini-shiki/-/mini-shiki-1.26.1.tgz", - "integrity": "sha512-gHFUvv9f1fU2Piou/5Y7Sx5moYxcERbC7CXc6rkDLQTUBg5Dgg9L4u29/nHqfoQ3Y9R0h0BcOhd14uOEZIBP7Q==", + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/@gerrit0/mini-shiki/-/mini-shiki-3.2.1.tgz", + "integrity": "sha512-HbzRC6MKB6U8kQhczz0APKPIzFHTrcqhaC7es2EXInq1SpjPVnpVSIsBe6hNoLWqqCx1n5VKiPXq6PfXnHZKOQ==", "dev": true, + "license": "MIT", "dependencies": { - "@shikijs/engine-oniguruma": "^1.26.1", - "@shikijs/types": "^1.26.1", - "@shikijs/vscode-textmate": "^10.0.1" + "@shikijs/engine-oniguruma": "^3.2.1", + "@shikijs/types": "^3.2.1", + "@shikijs/vscode-textmate": "^10.0.2" } }, "node_modules/@hutson/parse-repository-url": { @@ -10315,30 +10316,33 @@ ] }, "node_modules/@shikijs/engine-oniguruma": { - "version": "1.26.1", - "resolved": "https://registry.npmjs.org/@shikijs/engine-oniguruma/-/engine-oniguruma-1.26.1.tgz", - "integrity": "sha512-F5XuxN1HljLuvfXv7d+mlTkV7XukC1cawdtOo+7pKgPD83CAB1Sf8uHqP3PK0u7njFH0ZhoXE1r+0JzEgAQ+kg==", + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/@shikijs/engine-oniguruma/-/engine-oniguruma-3.2.1.tgz", + "integrity": "sha512-wZZAkayEn6qu2+YjenEoFqj0OyQI64EWsNR6/71d1EkG4sxEOFooowKivsWPpaWNBu3sxAG+zPz5kzBL/SsreQ==", "dev": true, + "license": "MIT", "dependencies": { - "@shikijs/types": "1.26.1", - "@shikijs/vscode-textmate": "^10.0.1" + "@shikijs/types": "3.2.1", + "@shikijs/vscode-textmate": "^10.0.2" } }, "node_modules/@shikijs/types": { - "version": "1.26.1", - "resolved": "https://registry.npmjs.org/@shikijs/types/-/types-1.26.1.tgz", - "integrity": "sha512-d4B00TKKAMaHuFYgRf3L0gwtvqpW4hVdVwKcZYbBfAAQXspgkbWqnFfuFl3MDH6gLbsubOcr+prcnsqah3ny7Q==", + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/@shikijs/types/-/types-3.2.1.tgz", + "integrity": "sha512-/NTWAk4KE2M8uac0RhOsIhYQf4pdU0OywQuYDGIGAJ6Mjunxl2cGiuLkvu4HLCMn+OTTLRWkjZITp+aYJv60yA==", "dev": true, + "license": "MIT", "dependencies": { - "@shikijs/vscode-textmate": "^10.0.1", + "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "node_modules/@shikijs/vscode-textmate": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/@shikijs/vscode-textmate/-/vscode-textmate-10.0.1.tgz", - "integrity": "sha512-fTIQwLF+Qhuws31iw7Ncl1R3HUDtGwIipiJ9iU+UsDUwMhegFcQKQHd51nZjb7CArq0MvON8rbgCGQYWHUKAdg==", - "dev": true + "version": "10.0.2", + "resolved": "https://registry.npmjs.org/@shikijs/vscode-textmate/-/vscode-textmate-10.0.2.tgz", + "integrity": "sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==", + "dev": true, + "license": "MIT" }, "node_modules/@sigstore/bundle": { "version": "1.1.0", @@ -11493,6 +11497,7 @@ "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==", "dev": true, + "license": "MIT", "dependencies": { "@types/unist": "*" } @@ -22137,35 +22142,37 @@ "dev": true }, "node_modules/typedoc": { - "version": "0.27.9", - "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.27.9.tgz", - "integrity": "sha512-/z585740YHURLl9DN2jCWe6OW7zKYm6VoQ93H0sxZ1cwHQEQrUn5BJrEnkWhfzUdyO+BLGjnKUZ9iz9hKloFDw==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.28.1.tgz", + "integrity": "sha512-Mn2VPNMaxoe/hlBiLriG4U55oyAa3Xo+8HbtEwV7F5WEOPXqtxzGuMZhJYHaqFJpajeQ6ZDUC2c990NAtTbdgw==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@gerrit0/mini-shiki": "^1.24.0", + "@gerrit0/mini-shiki": "^3.2.1", "lunr": "^2.3.9", "markdown-it": "^14.1.0", "minimatch": "^9.0.5", - "yaml": "^2.6.1" + "yaml": "^2.7.0 " }, "bin": { "typedoc": "bin/typedoc" }, "engines": { - "node": ">= 18" + "node": ">= 18", + "pnpm": ">= 10" }, "peerDependencies": { "typescript": "5.0.x || 5.1.x || 5.2.x || 5.3.x || 5.4.x || 5.5.x || 5.6.x || 5.7.x || 5.8.x" } }, "node_modules/typedoc-plugin-missing-exports": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/typedoc-plugin-missing-exports/-/typedoc-plugin-missing-exports-3.1.0.tgz", - "integrity": "sha512-Sogbaj+qDa21NjB3SlIw4JXSwmcl/WOjwiPNaVEcPhpNG/MiRTtpwV81cT7h1cbu9StpONFPbddYWR0KV/fTWA==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/typedoc-plugin-missing-exports/-/typedoc-plugin-missing-exports-4.0.0.tgz", + "integrity": "sha512-Z4ei+853xppDEhcqzyeyRs4+R0kUuKQWnMK1EtSTEd5LFkgkdW5Bdn8vfo/rsCGbYVJxOWU99fxgM1mROw5Fug==", "dev": true, + "license": "MIT", "peerDependencies": { - "typedoc": "0.26.x || 0.27.x" + "typedoc": "^0.28.1" } }, "node_modules/typedoc-plugin-zod": { diff --git a/package.json b/package.json index 4f7b499f94..ef091abcf2 100644 --- a/package.json +++ b/package.json @@ -61,8 +61,8 @@ "middy4": "npm:@middy/core@^4.7.0", "middy5": "npm:@middy/core@^5.4.3", "middy6": "npm:@middy/core@^6.0.0", - "typedoc": "^0.27.9", - "typedoc-plugin-missing-exports": "^3.1.0", + "typedoc": "^0.28.1", + "typedoc-plugin-missing-exports": "^4.0.0", "typedoc-plugin-zod": "^1.4.0", "typescript": "^5.8.2", "vitest": "^3.0.9" From 57d63442f2f4dc8f371f40ae85405568492692d6 Mon Sep 17 00:00:00 2001 From: Simon Thulbourn Date: Fri, 21 Mar 2025 18:32:01 +0100 Subject: [PATCH 48/56] chore(ci): fix workflow GovCloud formatting (#3761) --- .github/workflows/layers_govcloud.yml | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/.github/workflows/layers_govcloud.yml b/.github/workflows/layers_govcloud.yml index f8d23f1ec3..cbb2e36d38 100644 --- a/.github/workflows/layers_govcloud.yml +++ b/.github/workflows/layers_govcloud.yml @@ -101,16 +101,11 @@ jobs: - name: Create Layer id: create-layer run: | - cat AWSLambdaPowertoolsTypeScriptV2.json | jq '{ - "LayerName": "AWSLambdaPowertoolsTypeScriptV2", - "Description": .Description, - "CompatibleRuntimes": .CompatibleRuntimes, - "LicenseInfo": .LicenseInfo - }' > input.json + cat AWSLambdaPowertoolsTypeScriptV2.json | jq '{"LayerName": "AWSLambdaPowertoolsTypeScriptV2", "Description": .Description, "CompatibleRuntimes": .CompatibleRuntimes, "LicenseInfo": .LicenseInfo}' > input.json LAYER_VERSION=$(aws --region us-gov-west-1 lambda publish-layer-version \ --zip-file fileb://./AWSLambdaPowertoolsTypeScriptV2.zip \ - --cli-input-json file://./input.json + --cli-input-json file://./input.json \ --query 'Version' \ --output text) @@ -166,16 +161,11 @@ jobs: - name: Create Layer id: create-layer run: | - cat AWSLambdaPowertoolsTypeScriptV2.json | jq '{ - "LayerName": "AWSLambdaPowertoolsTypeScriptV2", - "Description": .Description, - "CompatibleRuntimes": .CompatibleRuntimes, - "LicenseInfo": .LicenseInfo - }' > input.json + cat AWSLambdaPowertoolsTypeScriptV2.json | jq '{"LayerName": "AWSLambdaPowertoolsTypeScriptV2", "Description": .Description, "CompatibleRuntimes": .CompatibleRuntimes, "LicenseInfo": .LicenseInfo}' > input.json LAYER_VERSION=$(aws --region us-gov-west-1 lambda publish-layer-version \ --zip-file fileb://./AWSLambdaPowertoolsTypeScriptV2.zip \ - --cli-input-json file://./input.json + --cli-input-json file://./input.json \ --query 'Version' \ --output text) From afab04fc10404e0c35571c9c210140436df79000 Mon Sep 17 00:00:00 2001 From: Simon Thulbourn Date: Mon, 24 Mar 2025 11:10:52 +0100 Subject: [PATCH 49/56] chore(ci): fix region typo in govcloud (#3762) --- .github/workflows/layers_govcloud.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/layers_govcloud.yml b/.github/workflows/layers_govcloud.yml index cbb2e36d38..cc8a318330 100644 --- a/.github/workflows/layers_govcloud.yml +++ b/.github/workflows/layers_govcloud.yml @@ -103,7 +103,7 @@ jobs: run: | cat AWSLambdaPowertoolsTypeScriptV2.json | jq '{"LayerName": "AWSLambdaPowertoolsTypeScriptV2", "Description": .Description, "CompatibleRuntimes": .CompatibleRuntimes, "LicenseInfo": .LicenseInfo}' > input.json - LAYER_VERSION=$(aws --region us-gov-west-1 lambda publish-layer-version \ + LAYER_VERSION=$(aws --region us-gov-east-1 lambda publish-layer-version \ --zip-file fileb://./AWSLambdaPowertoolsTypeScriptV2.zip \ --cli-input-json file://./input.json \ --query 'Version' \ From 5e9f051d2a0fe4a39b1ac64367ebf659235eacc8 Mon Sep 17 00:00:00 2001 From: Simon Thulbourn Date: Mon, 24 Mar 2025 14:18:36 +0100 Subject: [PATCH 50/56] chore(ci): Simplified GovCloud Deploy (#3763) --- .github/workflows/layer_govcloud_verify.yml | 87 ++++++++++------ .github/workflows/layers_govcloud.yml | 104 ++++++-------------- 2 files changed, 86 insertions(+), 105 deletions(-) diff --git a/.github/workflows/layer_govcloud_verify.yml b/.github/workflows/layer_govcloud_verify.yml index 3a4b5f32eb..8d5899b05e 100644 --- a/.github/workflows/layer_govcloud_verify.yml +++ b/.github/workflows/layer_govcloud_verify.yml @@ -5,19 +5,39 @@ on: workflow_dispatch: inputs: + environment: + description: Deployment environment + type: choice + options: + - Gamma + - Prod + required: true version: - description: Layer version to verify information + description: Layer version to verify type: string required: true + govcloud_version: + description: GovCloud Layer version to verify, this is mostly used in Gamma where a version mismatch might exist + type: string + required: false + workflow_call: inputs: + environment: + description: Deployment environment + type: string + required: true version: - description: Layer version to verify information + description: Layer version to verify type: string required: true + govcloud_version: + description: GovCloud Layer version to verify, this is mostly used in Gamma where a version mismatch might exist + type: string + required: false name: Layer Verification (GovCloud) -run-name: Layer Verification (GovCloud) - version ${{ inputs.version }} +run-name: Layer Verification (GovCloud) / Version ${{ inputs.version }} permissions: {} @@ -38,44 +58,51 @@ jobs: - name: Output AWSLambdaPowertoolsTypeScriptV2 # fetch the specific layer version information from the us-east-1 commercial region run: | - aws --region us-east-1 lambda get-layer-version-by-arn --arn 'arn:aws:lambda:us-east-1:094274105915:layer:AWSLambdaPowertoolsTypeScriptV2:${{ inputs.version }}' | jq -r '{"Layer Version Arn": .LayerVersionArn, "Version": .Version, "Description": .Description, "Compatible Runtimes": .CompatibleRuntimes[0], "Compatible Architectures": .CompatibleArchitectures[0], "SHA": .Content.CodeSha256} | keys[] as $k | [$k, .[$k]] | @tsv' | column -t -s $'\t' + aws --region us-east-1 lambda get-layer-version-by-arn --arn 'arn:aws:lambda:us-east-1:094274105915:layer:AWSLambdaPowertoolsTypeScriptV2:${{ inputs.version }}' > AWSLambdaPowertoolsTypeScriptV2.json + - name: Store Metadata + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 + with: + name: AWSLambdaPowertoolsTypeScriptV2.json + path: AWSLambdaPowertoolsTypeScriptV2.json + retention-days: 1 + if-no-files-found: error - gov_east: - name: Verify (East) + verify: + name: Verify needs: commercial runs-on: ubuntu-latest permissions: id-token: write contents: read - environment: GovCloud Prod (East) + environment: GovCloud ${{ inputs.environment }} + strategy: + matrix: + region: + - us-gov-east-1 + - us-gov-west-1 steps: - - name: Configure AWS Credentials - uses: aws-actions/configure-aws-credentials@ececac1a45f3b08a01d2dd070d28d111c5fe6722 # v4.1.0 + - name: Download Metadata + uses: actions/download-artifact@95815c38cf2ff2164869cbab79da8d1f422bc89e # v4.2.1 with: - role-to-assume: ${{ secrets.AWS_IAM_ROLE }} - aws-region: us-gov-east-1 - mask-aws-account-id: true - - name: Verify Layer AWSLambdaPowertoolsTypeScriptV2 - id: verify-layer + name: AWSLambdaPowertoolsTypeScriptV2.json + - id: transform run: | - aws --region us-gov-east-1 lambda get-layer-version-by-arn --arn 'arn:aws-us-gov:lambda:us-gov-east-1:${{ secrets.AWS_ACCOUNT_ID }}:layer:AWSLambdaPowertoolsTypeScriptV2:${{ inputs.version }}' | jq -r '{"Layer Version Arn": .LayerVersionArn, "Version": .Version, "Description": .Description, "Compatible Runtimes": .CompatibleRuntimes[0], "Compatible Architectures": .CompatibleArchitectures[0], "SHA": .Content.CodeSha256} | keys[] as $k | [$k, .[$k]] | @tsv' | column -t -s $'\t' - - gov_west: - name: Verify (West) - needs: commercial - runs-on: ubuntu-latest - permissions: - id-token: write - contents: read - environment: GovCloud Prod (West) - steps: + echo 'CONVERTED_REGION=${{ matrix.region }}' | tr 'a-z\-' 'A-Z_' >> "$GITHUB_OUTPUT" - name: Configure AWS Credentials uses: aws-actions/configure-aws-credentials@ececac1a45f3b08a01d2dd070d28d111c5fe6722 # v4.1.0 with: - role-to-assume: ${{ secrets.AWS_IAM_ROLE }} - aws-region: us-gov-east-1 + role-to-assume: ${{ secrets[format('IAM_ROLE_{0}', steps.transform.outputs.CONVERTED_REGION)] }} + aws-region: ${{ matrix.region}} mask-aws-account-id: true - - name: Verify Layer AWSLambdaPowertoolsTypeScriptV2 - id: verify-layer + - id: govcloud_version + name: GovCloud Layer Version + run: | + echo 'govcloud_version=$([[ -n "${{ inputs.govcloud_version}}" ]] && echo ${{ inputs.govcloud_version}} || echo ${{ inputs.version }} )' >> "$GITHUB_OUTPUT" + - name: Verify Layer run: | - aws --region us-gov-west-1 lambda get-layer-version-by-arn --arn 'arn:aws-us-gov:lambda:us-gov-west-1:${{ secrets.AWS_ACCOUNT_ID }}:layer:AWSLambdaPowertoolsTypeScriptV2:${{ inputs.version }}' | jq -r '{"Layer Version Arn": .LayerVersionArn, "Version": .Version, "Description": .Description, "Compatible Runtimes": .CompatibleRuntimes[0], "Compatible Architectures": .CompatibleArchitectures[0], "SHA": .Content.CodeSha256} | keys[] as $k | [$k, .[$k]] | @tsv' | column -t -s $'\t' \ No newline at end of file + export layer_output='AWSLambdaPowertoolsTypeScriptV2-${{matrix.region}}.json' + aws --region ${{ matrix.region}} lambda get-layer-version-by-arn --arn "arn:aws-us-gov:lambda:${{ matrix.region}}:${{ secrets[format('AWS_ACCOUNT_{0}', steps.transform.outputs.CONVERTED_REGION)] }}:layer:AWSLambdaPowertoolsTypeScriptV2:${{ steps.govcloud_version.outputs.govcloud_version }}" > $layer_output + REMOTE_SHA=$(jq -r '.Content.CodeSha256' $layer_output) + LOCAL_SHA=$(jq -r '.Content.CodeSha256' AWSLambdaPowertoolsTypeScriptV2.json) + test "$REMOTE_SHA" == "$LOCAL_SHA" && echo "SHA OK: ${LOCAL_SHA}" || exit 1 + jq -s -r '["Layer Arn", "Runtimes", "Version", "Description", "SHA256"], ([.[0], .[1]] | .[] | [.LayerArn, (.CompatibleRuntimes | join("/")), .Version, .Description, .Content.CodeSha256]) |@tsv' AWSLambdaPowertoolsTypeScriptV2.json $layer_output | column -t -s $'\t' \ No newline at end of file diff --git a/.github/workflows/layers_govcloud.yml b/.github/workflows/layers_govcloud.yml index cc8a318330..51d3d29db7 100644 --- a/.github/workflows/layers_govcloud.yml +++ b/.github/workflows/layers_govcloud.yml @@ -33,7 +33,7 @@ on: type: string required: true -run-name: Layer Deployment (GovCloud) - ${{ inputs.environment }} - version - ${{ inputs.version }} +run-name: Layer Deployment (GovCloud) - ${{ inputs.environment }} / Version - ${{ inputs.version }} permissions: contents: read @@ -71,14 +71,19 @@ jobs: retention-days: 1 if-no-files-found: error - copy_east: - name: Copy (East) + copy: + name: Copy needs: download runs-on: ubuntu-latest permissions: id-token: write contents: read - environment: GovCloud ${{ inputs.environment }} (East) + environment: GovCloud ${{ inputs.environment }} + strategy: + matrix: + region: + - us-gov-east-1 + - us-gov-west-1 steps: - name: Download Zip uses: actions/download-artifact@95815c38cf2ff2164869cbab79da8d1f422bc89e # v4.2.1 @@ -92,78 +97,21 @@ jobs: run: | SHA=$(jq -r '.Content.CodeSha256' 'AWSLambdaPowertoolsTypeScriptV2.json') test "$(openssl dgst -sha256 -binary AWSLambdaPowertoolsTypeScriptV2.zip | openssl enc -base64)" == "$SHA" && echo "SHA OK: ${SHA}" || exit 1 - - name: Configure AWS Credentials - uses: aws-actions/configure-aws-credentials@ececac1a45f3b08a01d2dd070d28d111c5fe6722 # v4.1.0 - with: - role-to-assume: ${{ secrets.AWS_IAM_ROLE }} - aws-region: us-gov-east-1 - mask-aws-account-id: true - - name: Create Layer - id: create-layer - run: | - cat AWSLambdaPowertoolsTypeScriptV2.json | jq '{"LayerName": "AWSLambdaPowertoolsTypeScriptV2", "Description": .Description, "CompatibleRuntimes": .CompatibleRuntimes, "LicenseInfo": .LicenseInfo}' > input.json - - LAYER_VERSION=$(aws --region us-gov-east-1 lambda publish-layer-version \ - --zip-file fileb://./AWSLambdaPowertoolsTypeScriptV2.zip \ - --cli-input-json file://./input.json \ - --query 'Version' \ - --output text) - - echo "LAYER_VERSION=$LAYER_VERSION" >> "$GITHUB_OUTPUT" - - aws --region us-gov-east-1 lambda add-layer-version-permission \ - --layer-name 'AWSLambdaPowertoolsTypeScriptV2' \ - --statement-id 'PublicLayer' \ - --action lambda:GetLayerVersion \ - --principal '*' \ - --version-number "$LAYER_VERSION" - - name: Verify Layer - env: - LAYER_VERSION: ${{ steps.create-layer.outputs.LAYER_VERSION }} + - id: transform run: | - REMOTE_SHA=$(aws --region us-gov-east-1 lambda get-layer-version-by-arn --arn 'arn:aws-us-gov:lambda:us-gov-east-1:${{ secrets.AWS_ACCOUNT_ID }}:layer:AWSLambdaPowertoolsTypeScriptV2:${{ env.LAYER_VERSION }}' --query 'Content.CodeSha256' --output text) - SHA=$(jq -r '.Content.CodeSha256' 'AWSLambdaPowertoolsTypeScriptV2.json') - test "$REMOTE_SHA" == "$SHA" && echo "SHA OK: ${SHA}" || exit 1 - aws --region us-gov-east-1 lambda get-layer-version-by-arn --arn 'arn:aws-us-gov:lambda:us-gov-east-1:${{ secrets.AWS_ACCOUNT_ID }}:layer:AWSLambdaPowertoolsTypeScriptV2:${{ env.LAYER_VERSION }}' > govcloud.json - echo ::notice::GovCloud Details - cat govcloud.json | jq -r '{"Layer Version Arn": .LayerVersionArn, "Version": .Version, "Description": .Description, "Compatible Runtimes": .CompatibleRuntimes, "SHA": .Content.CodeSha256} | keys[] as $k | [$k, .[$k]] | @tsv' | column -t -s $'\t' - echo ::notice::Commercial Details - cat AWSLambdaPowertoolsTypeScriptV2.json | jq -r '{"Layer Version Arn": .LayerVersionArn, "Version": .Version, "Description": .Description, "Compatible Runtimes": .CompatibleRuntimes, "SHA": .Content.CodeSha256} | keys[] as $k | [$k, .[$k]] | @tsv' | column -t -s $'\t' - - copy_west: - name: Copy (West) - needs: download - runs-on: ubuntu-latest - permissions: - id-token: write - contents: read - environment: - name: GovCloud ${{ inputs.environment }} (West) - steps: - - name: Download Zip - uses: actions/download-artifact@95815c38cf2ff2164869cbab79da8d1f422bc89e # v4.2.1 - with: - name: AWSLambdaPowertoolsTypeScriptV2.zip - - name: Download Metadata - uses: actions/download-artifact@95815c38cf2ff2164869cbab79da8d1f422bc89e # v4.2.1 - with: - name: AWSLambdaPowertoolsTypeScriptV2.json - - name: Verify Layer Signature - run: | - SHA=$(jq -r '.Content.CodeSha256' 'AWSLambdaPowertoolsTypeScriptV2.json') - test "$(openssl dgst -sha256 -binary AWSLambdaPowertoolsTypeScriptV2.zip | openssl enc -base64)" == "$SHA" && echo "SHA OK: ${SHA}" || exit 1 + echo 'CONVERTED_REGION=${{ matrix.region }}' | tr 'a-z\-' 'A-Z_' >> "$GITHUB_OUTPUT" - name: Configure AWS Credentials uses: aws-actions/configure-aws-credentials@ececac1a45f3b08a01d2dd070d28d111c5fe6722 # v4.1.0 with: - role-to-assume: ${{ secrets.AWS_IAM_ROLE }} - aws-region: us-gov-west-1 + role-to-assume: ${{ secrets[format('IAM_ROLE_{0}', steps.transform.outputs.CONVERTED_REGION)] }} + aws-region: ${{ matrix.region}} mask-aws-account-id: true - name: Create Layer id: create-layer run: | cat AWSLambdaPowertoolsTypeScriptV2.json | jq '{"LayerName": "AWSLambdaPowertoolsTypeScriptV2", "Description": .Description, "CompatibleRuntimes": .CompatibleRuntimes, "LicenseInfo": .LicenseInfo}' > input.json - LAYER_VERSION=$(aws --region us-gov-west-1 lambda publish-layer-version \ + LAYER_VERSION=$(aws --region ${{ matrix.region}} lambda publish-layer-version \ --zip-file fileb://./AWSLambdaPowertoolsTypeScriptV2.zip \ --cli-input-json file://./input.json \ --query 'Version' \ @@ -171,7 +119,7 @@ jobs: echo "LAYER_VERSION=$LAYER_VERSION" >> "$GITHUB_OUTPUT" - aws --region us-gov-west-1 lambda add-layer-version-permission \ + aws --region ${{ matrix.region}} lambda add-layer-version-permission \ --layer-name 'AWSLambdaPowertoolsTypeScriptV2' \ --statement-id 'PublicLayer' \ --action lambda:GetLayerVersion \ @@ -181,11 +129,17 @@ jobs: env: LAYER_VERSION: ${{ steps.create-layer.outputs.LAYER_VERSION }} run: | - REMOTE_SHA=$(aws --region us-gov-west-1 lambda get-layer-version-by-arn --arn 'arn:aws-us-gov:lambda:us-gov-west-1:${{ secrets.AWS_ACCOUNT_ID }}:layer:AWSLambdaPowertoolsTypeScriptV2:${{ env.LAYER_VERSION }}' --query 'Content.CodeSha256' --output text) - SHA=$(jq -r '.Content.CodeSha256' 'AWSLambdaPowertoolsTypeScriptV2.json') - test "$REMOTE_SHA" == "$SHA" && echo "SHA OK: ${SHA}" || exit 1 - aws --region us-gov-west-1 lambda get-layer-version-by-arn --arn 'arn:aws-us-gov:lambda:us-gov-west-1:${{ secrets.AWS_ACCOUNT_ID }}:layer:AWSLambdaPowertoolsTypeScriptV2:${{ env.LAYER_VERSION }}' > govcloud.json - echo ::notice::GovCloud Details - cat govcloud.json | jq -r '{"Layer Version Arn": .LayerVersionArn, "Version": .Version, "Description": .Description, "Compatible Runtimes": .CompatibleRuntimes, "SHA": .Content.CodeSha256} | keys[] as $k | [$k, .[$k]] | @tsv' | column -t -s $'\t' - echo ::notice::Commercial Details - cat AWSLambdaPowertoolsTypeScriptV2.json | jq -r '{"Layer Version Arn": .LayerVersionArn, "Version": .Version, "Description": .Description, "Compatible Runtimes": .CompatibleRuntimes, "SHA": .Content.CodeSha256} | keys[] as $k | [$k, .[$k]] | @tsv' | column -t -s $'\t' + export layer_output='AWSLambdaPowertoolsTypeScriptV2-${{matrix.region}}.json' + aws --region ${{ matrix.region}} lambda get-layer-version-by-arn --arn 'arn:aws-us-gov:lambda:${{ matrix.region}}:${{ secrets[format('AWS_ACCOUNT_{0}', steps.transform.outputs.CONVERTED_REGION)] }}:layer:AWSLambdaPowertoolsTypeScriptV2:${{ env.LAYER_VERSION }}' > $layer_output + REMOTE_SHA=$(jq -r '.Content.CodeSha256' $layer_output) + LOCAL_SHA=$(jq -r '.Content.CodeSha256' AWSLambdaPowertoolsTypeScriptV2.json) + test "$REMOTE_SHA" == "$LOCAL_SHA" && echo "SHA OK: ${LOCAL_SHA}" || exit 1 + jq -s -r '["Layer Arn", "Runtimes", "Version", "Description", "SHA256"], ([.[0], .[1]] | .[] | [.LayerArn, (.CompatibleRuntimes | join("/")), .Version, .Description, .Content.CodeSha256]) |@tsv' AWSLambdaPowertoolsTypeScriptV2.json $layer_output | column -t -s $'\t' + + - name: Store Metadata - ${{ matrix.region }} + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 + with: + name: AWSLambdaPowertoolsTypeScriptV2-${{ matrix.region }}.json + path: AWSLambdaPowertoolsTypeScriptV2-${{ matrix.region }}.json + retention-days: 1 + if-no-files-found: error \ No newline at end of file From 434cc8b3804ee10aa3b1f2023ff22a616c2950e8 Mon Sep 17 00:00:00 2001 From: Andrea Amorosi Date: Mon, 24 Mar 2025 22:43:35 +0100 Subject: [PATCH 51/56] chore: add Guild customer reference (#3769) --- README.md | 1 + docs/index.md | 3 +++ docs/media/logos/guild.png | Bin 0 -> 2834 bytes packages/batch/README.md | 1 + packages/commons/README.md | 1 + packages/event-handler/README.md | 1 + packages/idempotency/README.md | 1 + packages/jmespath/README.md | 1 + packages/logger/README.md | 1 + packages/metrics/README.md | 1 + packages/parameters/README.md | 1 + packages/parser/README.md | 1 + packages/tracer/README.md | 1 + packages/validation/README.md | 1 + 14 files changed, 15 insertions(+) create mode 100644 docs/media/logos/guild.png diff --git a/README.md b/README.md index 3057c33ca9..be3a9e3bcb 100644 --- a/README.md +++ b/README.md @@ -70,6 +70,7 @@ The following companies, among others, use Powertools: - [Elva](https://elva-group.com) - [Flyweight](https://flyweight.io/) - [globaldatanet](https://globaldatanet.com/) +- [Guild](https://guild.com) - [Hashnode](https://hashnode.com/) - [LocalStack](https://localstack.cloud/) - [Perfect Post](https://www.perfectpost.fr) diff --git a/docs/index.md b/docs/index.md index 34afcd44e8..081ec1849d 100644 --- a/docs/index.md +++ b/docs/index.md @@ -459,6 +459,9 @@ Knowing which companies are using this library is important to help prioritize t [**globaldatanet**](https://globaldatanet.com/){target="_blank" rel="nofollow"} { .card } +[**Guild**](https://guild.com){target="_blank" rel="nofollow"} +{ .card } + [**Hashnode**](https://hashnode.com/){target="_blank" rel="nofollow"} { .card } diff --git a/docs/media/logos/guild.png b/docs/media/logos/guild.png new file mode 100644 index 0000000000000000000000000000000000000000..e0aecf3a4dacbade5bf29f636f90e99f8f93dcb6 GIT binary patch literal 2834 zcmaJ@`8(8m8~%J}Y|Ypr`@YU3jI}c@GRZQG82ePxpt5fz$8hjXlCc+OD#9QVvPDPM zDOsWz*-D$WMs-4pVZ!Tu|A6=T;d$=sdY=2fuKSn!dgx>a8xfQ|3IHHtOSE(b0D^aL zG9PlMYxfegc7`U|-qp%JAYupp|4N8Hd2Z(d9qH`g0+8bcUs}YYbj&;qI|K0mpl;Y& z9(9fO8Y?({aZj&YZ;?%9oSB)P#~nOoK)^c|Cu`xfT<9#6{!r#B^Fn{@n<=;OJ}W~t zzSV}F3*xI*nTBLe!+zWJ;gIWXmMilmV*~y%+ao-C(uf;puft^C!q)M%l}TK-OS<@S zyUL(vUO|T9kAq6qsTqBY0C|k$b-k~8@)%vqgpT+Fhy&^%nKOC2`Lc!}%cAyuic^*{ zKqt7QC4xFNqgcMR!qLN^KP&7kA62KQf#R1nG&H0VGzVCRwl%-Iz84_Rt=NO)8dJ$T zVISgu_J&kDDqnHtB9<6F?GeA*r57Kat#BR?W?6F_1VDKeJwBdGh{~7m$Ay}R@~a-I zJu+ch-*9?a4sxl!4|M5UVTY9x^G_T3_Q@-Tftv3>%w^taRB%DI?g?;m+cA> zDkzxEeIu8-J-!T0-4Iaie7CrL=&1nYiwFaS>CbuZDOooG;g9xEkVCHgh(b#=xCVXz z+v=#0T;|u z%P@1&pUTa_O+5@AugXeNfUBHzRSYsD*H2i3zsv$7^l)GSPJP_O{3J$h02{dqpyjrI zj@!-eVg><7VkqFKmsmN4YA;*4`oylK^E>2o=do#fB0-}Bo9G21wGg=KmqL8(Sp$Pe8bnkYC2cdo zl(!ABY;uzF4i)~Ta40y4jsq8SK0_I%qP zA_`V>h7n9{%CH6!KB#zU1WG5db)VLL?^K6dLn08l%t`2JN%OsMjk>IU0WdS?Zre*q z%?fLo4@k=~T;U9LMRC9M8UOPdf{Q+l#SVpjXxp4Mr&9oM9&QSp~QNYT~Q0QHit}a56Bn|EYfhyK{8!t@F|hPv| z=6z-Xkn*d*ROy4jdl1n~1L)y%oyWzQHD$+~uivI`)n8AJBvh-w|c{g9J50zok9{J}OH7MK>OxaI*i8&rV$LUVv< zg_`Fa#LH&ISXwEvPZ4B=w_QimA$7j+{Nju{4RA)Tl-C&zF{S_1(gawY9!3ZbjLvi~ z0Z)0EH}*7$YPVm>OOVr#uR2nU@IR@jNEp{0szsQ%I=(oUqJ9No0!f0yhYh2%>Ohpf zVc(9^M!YIvtkQV_P>@Fhj;*Vy5}xQtalj=d7&Bd(gk=7XhRucG&Qzh;vtC4 zy&G@owDEuql&b8?kUQbFN{W?`WrkWU9%Sk4dDIi;mWM`B^SirsK}b`h|JrB%YkYO+ z%k8?r#V$f7Fx(qzmY^Z_jIP{@+82jHlle<)K&~!aBo2n8`S`Kx2u=Dh&39z@c^$}^ zMJj~Q10*4X`UDy<$Wy4R?9Nx*!<<5^UZQLaOYpM6oLHTJ-^I~qM-<_>$c{1u6LZYp z{@WFVy%t2|Pr)edzlT|!hBVOxQxd*k%cN-*2;er>MoQNK(x5zu9WmfG6Ga?dsCi{;0s61+}suhD16D6?pIOdO*&nS_} z;(%9@v7()<;@ay+uPoiV@%q|HpC6~no^|zqJt4sh2W5Rh1+pH1ouC?Lq7;5x%EEU( zM)_Sy$8$M}*tmh)=Ab%%HTR{mfjL$5NtAmPGUVRB1$aChN!7=CxE5;_Ob2_UAIC$J zf(Y2}o|*ox9NyGG>^wcRCXQT zX#UbD^Ad@evhUuIM@(t?4cod;Yy^LNC+XiC`*!~7ElC%7lO%s%t>v#5pEpDh^Y9Bo zMi&Kv02U`3LxV8&t>>TEn#HG`(P0tlk+|%U2zfiq(<-N%?}{~_NLR7Qw_v-F)y_^yBP=c%caFy5+6PYGtbhe zqX$hx4)gZ3fAoR&orNg!%~(b!yqGE_Dg4x(FF8=dy(hR=dp=DQl2fQPi;=f-AO4(u zKXfx#P1Vqt35Zd8$mC2y^2mr?!$)nO zlIzFXk!so-(LX(L_36sZF`cC4G@OGbZJTiRj*MTg5w9mxQQ?i;)$hFDZ~TU$^j|EV z0K+y#yL)jNG;@uPw<*B~)~MUbpD7!DDtfr>a9V8PNibY{D)*qkyragoDa6>m-Ti{W zNXyN2(%waU;YM%gEAowT%>}OznDaZJS7hPOYi-zQwY>wKE~3%-vaB=l58qx}baBjd zOgDO5vln}$%|w7%gn#e;`zGO_YUlIxU^_-?!G* L%E7Y6f|~dr2vz0! literal 0 HcmV?d00001 diff --git a/packages/batch/README.md b/packages/batch/README.md index fb6d8ade44..5ca98dd511 100644 --- a/packages/batch/README.md +++ b/packages/batch/README.md @@ -176,6 +176,7 @@ The following companies, among others, use Powertools: - [Elva](https://elva-group.com) - [Flyweight](https://flyweight.io/) - [globaldatanet](https://globaldatanet.com/) +- [Guild](https://guild.com) - [Hashnode](https://hashnode.com/) - [LocalStack](https://localstack.cloud/) - [Perfect Post](https://www.perfectpost.fr) diff --git a/packages/commons/README.md b/packages/commons/README.md index 8aa47fd986..d05fceffe5 100644 --- a/packages/commons/README.md +++ b/packages/commons/README.md @@ -126,6 +126,7 @@ The following companies, among others, use Powertools: - [Elva](https://elva-group.com) - [Flyweight](https://flyweight.io/) - [globaldatanet](https://globaldatanet.com/) +- [Guild](https://guild.com) - [Hashnode](https://hashnode.com/) - [LocalStack](https://localstack.cloud/) - [Perfect Post](https://www.perfectpost.fr) diff --git a/packages/event-handler/README.md b/packages/event-handler/README.md index 094ced856e..4689f15070 100644 --- a/packages/event-handler/README.md +++ b/packages/event-handler/README.md @@ -53,6 +53,7 @@ The following companies, among others, use Powertools: - [Elva](https://elva-group.com) - [Flyweight](https://flyweight.io/) - [globaldatanet](https://globaldatanet.com/) +- [Guild](https://guild.com) - [Hashnode](https://hashnode.com/) - [LocalStack](https://localstack.cloud/) - [Perfect Post](https://www.perfectpost.fr) diff --git a/packages/idempotency/README.md b/packages/idempotency/README.md index bd86eaec58..c4902e7370 100644 --- a/packages/idempotency/README.md +++ b/packages/idempotency/README.md @@ -347,6 +347,7 @@ The following companies, among others, use Powertools: - [Elva](https://elva-group.com) - [Flyweight](https://flyweight.io/) - [globaldatanet](https://globaldatanet.com/) +- [Guild](https://guild.com) - [Hashnode](https://hashnode.com/) - [LocalStack](https://localstack.cloud/) - [Perfect Post](https://www.perfectpost.fr) diff --git a/packages/jmespath/README.md b/packages/jmespath/README.md index f7dcad568f..490fcb40aa 100644 --- a/packages/jmespath/README.md +++ b/packages/jmespath/README.md @@ -202,6 +202,7 @@ The following companies, among others, use Powertools: - [Elva](https://elva-group.com) - [Flyweight](https://flyweight.io/) - [globaldatanet](https://globaldatanet.com/) +- [Guild](https://guild.com) - [Hashnode](https://hashnode.com/) - [LocalStack](https://localstack.cloud/) - [Perfect Post](https://www.perfectpost.fr) diff --git a/packages/logger/README.md b/packages/logger/README.md index 9c563c9547..a654fa63c4 100644 --- a/packages/logger/README.md +++ b/packages/logger/README.md @@ -243,6 +243,7 @@ The following companies, among others, use Powertools: - [Elva](https://elva-group.com) - [Flyweight](https://flyweight.io/) - [globaldatanet](https://globaldatanet.com/) +- [Guild](https://guild.com) - [Hashnode](https://hashnode.com/) - [LocalStack](https://localstack.cloud/) - [Perfect Post](https://www.perfectpost.fr) diff --git a/packages/metrics/README.md b/packages/metrics/README.md index c74a07a113..3187959a8e 100644 --- a/packages/metrics/README.md +++ b/packages/metrics/README.md @@ -164,6 +164,7 @@ The following companies, among others, use Powertools: - [Elva](https://elva-group.com) - [Flyweight](https://flyweight.io/) - [globaldatanet](https://globaldatanet.com/) +- [Guild](https://guild.com) - [Hashnode](https://hashnode.com/) - [LocalStack](https://localstack.cloud/) - [Perfect Post](https://www.perfectpost.fr) diff --git a/packages/parameters/README.md b/packages/parameters/README.md index d3544d96b7..e6a32c9d4b 100644 --- a/packages/parameters/README.md +++ b/packages/parameters/README.md @@ -229,6 +229,7 @@ The following companies, among others, use Powertools: - [Elva](https://elva-group.com) - [Flyweight](https://flyweight.io/) - [globaldatanet](https://globaldatanet.com/) +- [Guild](https://guild.com) - [Hashnode](https://hashnode.com/) - [LocalStack](https://localstack.cloud/) - [Perfect Post](https://www.perfectpost.fr) diff --git a/packages/parser/README.md b/packages/parser/README.md index d18ab9b107..c5176766df 100644 --- a/packages/parser/README.md +++ b/packages/parser/README.md @@ -316,6 +316,7 @@ The following companies, among others, use Powertools: - [Elva](https://elva-group.com) - [Flyweight](https://flyweight.io/) - [globaldatanet](https://globaldatanet.com/) +- [Guild](https://guild.com) - [Hashnode](https://hashnode.com/) - [LocalStack](https://localstack.cloud/) - [Perfect Post](https://www.perfectpost.fr) diff --git a/packages/tracer/README.md b/packages/tracer/README.md index 421418f139..e9411c0e56 100644 --- a/packages/tracer/README.md +++ b/packages/tracer/README.md @@ -154,6 +154,7 @@ The following companies, among others, use Powertools: - [Elva](https://elva-group.com) - [Flyweight](https://flyweight.io/) - [globaldatanet](https://globaldatanet.com/) +- [Guild](https://guild.com) - [Hashnode](https://hashnode.com/) - [LocalStack](https://localstack.cloud/) - [Perfect Post](https://www.perfectpost.fr) diff --git a/packages/validation/README.md b/packages/validation/README.md index 77a2fdfc68..74911812e6 100644 --- a/packages/validation/README.md +++ b/packages/validation/README.md @@ -258,6 +258,7 @@ The following companies, among others, use Powertools: - [Elva](https://elva-group.com) - [Flyweight](https://flyweight.io/) - [globaldatanet](https://globaldatanet.com/) +- [Guild](https://guild.com) - [Hashnode](https://hashnode.com/) - [LocalStack](https://localstack.cloud/) - [Perfect Post](https://www.perfectpost.fr) From 3cc04518715fdd3d450a314e3ca2c5a99725b0ca Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 25 Mar 2025 08:27:40 +0100 Subject: [PATCH 52/56] chore(deps): bump @types/node from 22.13.11 to 22.13.13 (#3766) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Andrea Amorosi --- examples/app/package.json | 4 ++-- package-lock.json | 12 ++++++------ package.json | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/examples/app/package.json b/examples/app/package.json index 0b35cd97e5..0f852b972d 100644 --- a/examples/app/package.json +++ b/examples/app/package.json @@ -29,7 +29,7 @@ }, "devDependencies": { "@types/aws-lambda": "^8.10.147", - "@types/node": "22.13.11", + "@types/node": "22.13.13", "aws-cdk-lib": "^2.185.0", "constructs": "^10.4.2", "source-map-support": "^0.5.21", @@ -48,7 +48,7 @@ "@aws-sdk/lib-dynamodb": "^3.772.0", "@middy/core": "^4.7.0", "@types/aws-lambda": "^8.10.147", - "@types/node": "22.13.11", + "@types/node": "22.13.13", "aws-cdk": "^2.1005.0", "constructs": "^10.4.2", "esbuild": "^0.25.1", diff --git a/package-lock.json b/package-lock.json index 2d1ec5107b..da23713db2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -28,7 +28,7 @@ "devDependencies": { "@biomejs/biome": "^1.9.4", "@types/aws-lambda": "^8.10.147", - "@types/node": "^22.13.11", + "@types/node": "^22.13.13", "@vitest/coverage-v8": "^3.0.9", "husky": "^9.1.7", "lerna": "8.1.2", @@ -62,7 +62,7 @@ "@aws-sdk/lib-dynamodb": "^3.772.0", "@middy/core": "^4.7.0", "@types/aws-lambda": "^8.10.147", - "@types/node": "22.13.11", + "@types/node": "22.13.13", "aws-cdk": "^2.1005.0", "constructs": "^10.4.2", "esbuild": "^0.25.1", @@ -70,7 +70,7 @@ }, "devDependencies": { "@types/aws-lambda": "^8.10.147", - "@types/node": "22.13.11", + "@types/node": "22.13.13", "aws-cdk-lib": "^2.185.0", "constructs": "^10.4.2", "source-map-support": "^0.5.21", @@ -11544,9 +11544,9 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "22.13.11", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.13.11.tgz", - "integrity": "sha512-iEUCUJoU0i3VnrCmgoWCXttklWcvoCIx4jzcP22fioIVSdTmjgoEvmAO/QPw6TcS9k5FrNgn4w7q5lGOd1CT5g==", + "version": "22.13.13", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.13.13.tgz", + "integrity": "sha512-ClsL5nMwKaBRwPcCvH8E7+nU4GxHVx1axNvMZTFHMEfNI7oahimt26P5zjVCRrjiIWj6YFXfE1v3dEp94wLcGQ==", "license": "MIT", "dependencies": { "undici-types": "~6.20.0" diff --git a/package.json b/package.json index ef091abcf2..7c36f5d2e0 100644 --- a/package.json +++ b/package.json @@ -52,7 +52,7 @@ "devDependencies": { "@biomejs/biome": "^1.9.4", "@types/aws-lambda": "^8.10.147", - "@types/node": "^22.13.11", + "@types/node": "^22.13.13", "@vitest/coverage-v8": "^3.0.9", "husky": "^9.1.7", "lerna": "8.1.2", From 103a7f98a317612c6290a8bb0ca2152779f9d18f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 25 Mar 2025 08:30:01 +0100 Subject: [PATCH 53/56] chore(deps): bump github/codeql-action from 3.28.12 to 3.28.13 (#3764) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Andrea Amorosi --- .github/workflows/ossf_scorecard.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ossf_scorecard.yml b/.github/workflows/ossf_scorecard.yml index f2cfdaa6ce..2871ecabba 100644 --- a/.github/workflows/ossf_scorecard.yml +++ b/.github/workflows/ossf_scorecard.yml @@ -43,6 +43,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@5f8171a638ada777af81d42b55959a643bb29017 # v3.28.12 + uses: github/codeql-action/upload-sarif@1b549b9259bda1cb5ddde3b41741a82a2d15a841 # v3.28.13 with: sarif_file: results.sarif From 64f5cf28b2f88fcb4993aa7278aadf4aa3402f67 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 25 Mar 2025 08:36:14 +0100 Subject: [PATCH 54/56] chore(deps): bump @types/aws-lambda from 8.10.147 to 8.10.148 (#3767) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Andrea Amorosi --- examples/app/package.json | 4 ++-- package-lock.json | 15 ++++++++------- package.json | 2 +- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/examples/app/package.json b/examples/app/package.json index 0f852b972d..ba7628a4a4 100644 --- a/examples/app/package.json +++ b/examples/app/package.json @@ -28,7 +28,7 @@ "#errors": "./functions/commons/errors.js" }, "devDependencies": { - "@types/aws-lambda": "^8.10.147", + "@types/aws-lambda": "^8.10.148", "@types/node": "22.13.13", "aws-cdk-lib": "^2.185.0", "constructs": "^10.4.2", @@ -47,7 +47,7 @@ "@aws-sdk/client-ssm": "^3.772.0", "@aws-sdk/lib-dynamodb": "^3.772.0", "@middy/core": "^4.7.0", - "@types/aws-lambda": "^8.10.147", + "@types/aws-lambda": "^8.10.148", "@types/node": "22.13.13", "aws-cdk": "^2.1005.0", "constructs": "^10.4.2", diff --git a/package-lock.json b/package-lock.json index da23713db2..801a374712 100644 --- a/package-lock.json +++ b/package-lock.json @@ -27,7 +27,7 @@ ], "devDependencies": { "@biomejs/biome": "^1.9.4", - "@types/aws-lambda": "^8.10.147", + "@types/aws-lambda": "^8.10.148", "@types/node": "^22.13.13", "@vitest/coverage-v8": "^3.0.9", "husky": "^9.1.7", @@ -61,7 +61,7 @@ "@aws-sdk/client-ssm": "^3.772.0", "@aws-sdk/lib-dynamodb": "^3.772.0", "@middy/core": "^4.7.0", - "@types/aws-lambda": "^8.10.147", + "@types/aws-lambda": "^8.10.148", "@types/node": "22.13.13", "aws-cdk": "^2.1005.0", "constructs": "^10.4.2", @@ -69,7 +69,7 @@ "typescript": "^5.8.2" }, "devDependencies": { - "@types/aws-lambda": "^8.10.147", + "@types/aws-lambda": "^8.10.148", "@types/node": "22.13.13", "aws-cdk-lib": "^2.185.0", "constructs": "^10.4.2", @@ -11462,10 +11462,11 @@ } }, "node_modules/@types/aws-lambda": { - "version": "8.10.147", - "resolved": "https://registry.npmjs.org/@types/aws-lambda/-/aws-lambda-8.10.147.tgz", - "integrity": "sha512-nD0Z9fNIZcxYX5Mai2CTmFD7wX7UldCkW2ezCF8D1T5hdiLsnTWDGRpfRYntU6VjTdLQjOvyszru7I1c1oCQew==", - "dev": true + "version": "8.10.148", + "resolved": "https://registry.npmjs.org/@types/aws-lambda/-/aws-lambda-8.10.148.tgz", + "integrity": "sha512-JL+2cfkY9ODQeE06hOxSFNkafjNk4JRBgY837kpoq1GHDttq2U3BA9IzKOWxS4DLjKoymGB4i9uBrlCkjUl1yg==", + "dev": true, + "license": "MIT" }, "node_modules/@types/cls-hooked": { "version": "4.3.8", diff --git a/package.json b/package.json index 7c36f5d2e0..d7f40a347e 100644 --- a/package.json +++ b/package.json @@ -51,7 +51,7 @@ "homepage": "https://github.com/aws-powertools/powertools-lambda-typescript#readme", "devDependencies": { "@biomejs/biome": "^1.9.4", - "@types/aws-lambda": "^8.10.147", + "@types/aws-lambda": "^8.10.148", "@types/node": "^22.13.13", "@vitest/coverage-v8": "^3.0.9", "husky": "^9.1.7", From fa414d57aeb7ea0acb3a336ecf7f4894125cf927 Mon Sep 17 00:00:00 2001 From: Andrea Amorosi Date: Tue, 25 Mar 2025 09:59:51 +0100 Subject: [PATCH 55/56] chore(parameters): update AWS SDK client type (#3768) --- docs/utilities/parameters.md | 2 +- examples/snippets/package.json | 1 - .../parameters/customProviderVault.ts | 69 +++++++++---------- .../parameters/customProviderVaultTypes.ts | 57 ++++----------- .../parameters/customProviderVaultUsage.ts | 31 ++++----- package-lock.json | 13 ---- packages/parameters/src/types/BaseProvider.ts | 2 +- 7 files changed, 62 insertions(+), 113 deletions(-) diff --git a/docs/utilities/parameters.md b/docs/utilities/parameters.md index d35188c9ea..dbbe813d5c 100644 --- a/docs/utilities/parameters.md +++ b/docs/utilities/parameters.md @@ -298,7 +298,7 @@ All caching logic is handled by the `BaseProvider`, and provided that the return Here's an example of implementing a custom parameter store using an external service like HashiCorp Vault, a widely popular key-value secret storage. === "Provider usage" - ```typescript hl_lines="5-8 12-16" + ```typescript hl_lines="12" --8<-- "examples/snippets/parameters/customProviderVaultUsage.ts" ``` diff --git a/examples/snippets/package.json b/examples/snippets/package.json index ecf240b427..1390f8ef70 100644 --- a/examples/snippets/package.json +++ b/examples/snippets/package.json @@ -40,7 +40,6 @@ "@middy/core": "^4.7.0", "aws-sdk": "^2.1692.0", "aws-sdk-client-mock": "^4.1.0", - "hashi-vault-js": "^0.4.16", "zod": "^3.24.2" } } diff --git a/examples/snippets/parameters/customProviderVault.ts b/examples/snippets/parameters/customProviderVault.ts index 838f1adc9d..0bbae8252b 100644 --- a/examples/snippets/parameters/customProviderVault.ts +++ b/examples/snippets/parameters/customProviderVault.ts @@ -1,41 +1,31 @@ import { BaseProvider } from '@aws-lambda-powertools/parameters/base'; import { GetParameterError } from '@aws-lambda-powertools/parameters/errors'; -import Vault from 'hashi-vault-js'; import type { HashiCorpVaultGetOptions, HashiCorpVaultProviderOptions, } from './customProviderVaultTypes.js'; class HashiCorpVaultProvider extends BaseProvider { - public client: Vault; + readonly #baseUrl: string; readonly #token: string; + readonly #rootPath?: string; + readonly #timeout: number; + readonly #abortController: AbortController; /** * It initializes the HashiCorpVaultProvider class. * - * @param {HashiCorpVaultProviderOptions} config - The configuration object. + * @param config - The configuration object. */ public constructor(config: HashiCorpVaultProviderOptions) { super({}); - const { url, token, clientConfig, vaultClient } = config; - if (vaultClient) { - if (vaultClient instanceof Vault) { - this.client = vaultClient; - } else { - throw Error('Not a valid Vault client provided'); - } - } else { - const config = { - baseUrl: url, - ...(clientConfig ?? { - timeout: 10000, - rootPath: '', - }), - }; - this.client = new Vault(config); - } + const { url, token, rootPath, timeout } = config; + this.#baseUrl = url; + this.#rootPath = rootPath ?? 'secret'; + this.#timeout = timeout ?? 5000; this.#token = token; + this.#abortController = new AbortController(); } /** @@ -46,8 +36,8 @@ class HashiCorpVaultProvider extends BaseProvider { * * `forceFetch` - Whether to always fetch a new value from the store regardless if already available in cache * * `sdkOptions` - Extra options to pass to the HashiCorp Vault SDK, e.g. `mount` or `version` * - * @param {string} name - The name of the secret - * @param {HashiCorpVaultGetOptions} options - Options to customize the retrieval of the secret + * @param name - The name of the secret + * @param options - Options to customize the retrieval of the secret */ public async get>( name: string, @@ -68,27 +58,36 @@ class HashiCorpVaultProvider extends BaseProvider { /** * Retrieve a secret from HashiCorp Vault. * - * @param {string} name - The name of the secret - * @param {HashiCorpVaultGetOptions} options - Options to customize the retrieval of the secret + * @param name - The name of the secret + * @param options - Options to customize the retrieval of the secret */ protected async _get( name: string, options?: HashiCorpVaultGetOptions ): Promise> { - const mount = options?.sdkOptions?.mount ?? 'secret'; - const version = options?.sdkOptions?.version; + const { sdkOptions } = options ?? {}; + const mount = sdkOptions?.mount ?? this.#rootPath; + const version = sdkOptions?.version + ? `?version=${sdkOptions?.version}` + : ''; - const response = await this.client.readKVSecret( - this.#token, - name, - version, - mount - ); + setTimeout(() => { + this.#abortController.abort(); + }, this.#timeout); - if (response.isVaultError) { - throw response; + const res = await fetch( + `${this.#baseUrl}/${mount}/data/${name}${version}`, + { + headers: { 'X-Vault-Token': this.#token }, + method: 'GET', + signal: this.#abortController.signal, + } + ); + if (!res.ok) { + throw new GetParameterError(`Failed to fetch secret ${res.statusText}`); } - return response.data; + const response = await res.json(); + return response.data.data; } /** diff --git a/examples/snippets/parameters/customProviderVaultTypes.ts b/examples/snippets/parameters/customProviderVaultTypes.ts index 4542865e49..d9436134b5 100644 --- a/examples/snippets/parameters/customProviderVaultTypes.ts +++ b/examples/snippets/parameters/customProviderVaultTypes.ts @@ -1,11 +1,13 @@ import type { GetOptionsInterface } from '@aws-lambda-powertools/parameters/base/types'; -import type Vault from 'hashi-vault-js'; /** - * Base interface for HashiCorpVaultProviderOptions. - * @interface + * Options for the HashiCorpVaultProvider class constructor. + * + * @param {string} url - Indicate the server name/IP, port and API version for the Vault instance, all paths are relative to this one. + * @param {string} token - The Vault token to use for authentication. + * */ -interface HashiCorpVaultProviderOptionsBase { +interface HashiCorpVaultProviderOptions { /** * Indicate the server name/IP, port and API version for the Vault instance, all paths are relative to this one. * @example 'https://vault.example.com:8200/v1' @@ -15,53 +17,18 @@ interface HashiCorpVaultProviderOptionsBase { * The Vault token to use for authentication. */ token: string; -} - -/** - * Interface for HashiCorpVaultProviderOptions with clientConfig property. - * @interface - */ -interface HashiCorpVaultProviderOptionsWithClientConfig - extends HashiCorpVaultProviderOptionsBase { /** - * Optional configuration to pass during client initialization to customize the `hashi-vault-js` client. + * The root path to use for the secret engine. Defaults to `secret`. */ - clientConfig?: unknown; + rootPath?: string; /** - * This property should never be passed. + * The timeout in milliseconds for the HTTP requests. Defaults to `5000`. + * @example 10000 + * @default 5000 */ - vaultClient?: never; + timeout?: number; } -/** - * Interface for HashiCorpVaultProviderOptions with vaultClient property. - * - * @interface - */ -interface HashiCorpVaultProviderOptionsWithClientInstance - extends HashiCorpVaultProviderOptionsBase { - /** - * Optional `hashi-vault-js` client to pass during HashiCorpVaultProvider class instantiation. If not provided, a new client will be created. - */ - vaultClient?: Vault; - /** - * This property should never be passed. - */ - clientConfig: never; -} - -/** - * Options for the HashiCorpVaultProvider class constructor. - * - * @param {string} url - Indicate the server name/IP, port and API version for the Vault instance, all paths are relative to this one. - * @param {string} token - The Vault token to use for authentication. - * @param {Vault.VaultConfig} [clientConfig] - Optional configuration to pass during client initialization, e.g. timeout. Mutually exclusive with vaultClient. - * @param {Vault} [vaultClient] - Optional `hashi-vault-js` client to pass during HashiCorpVaultProvider class instantiation. Mutually exclusive with clientConfig. - */ -type HashiCorpVaultProviderOptions = - | HashiCorpVaultProviderOptionsWithClientConfig - | HashiCorpVaultProviderOptionsWithClientInstance; - type HashiCorpVaultReadKVSecretOptions = { /** * The mount point of the secret engine to use. Defaults to `secret`. diff --git a/examples/snippets/parameters/customProviderVaultUsage.ts b/examples/snippets/parameters/customProviderVaultUsage.ts index 5ead5b0a46..014f3b3a2f 100644 --- a/examples/snippets/parameters/customProviderVaultUsage.ts +++ b/examples/snippets/parameters/customProviderVaultUsage.ts @@ -1,25 +1,22 @@ import { Logger } from '@aws-lambda-powertools/logger'; import { HashiCorpVaultProvider } from './customProviderVault.js'; -const logger = new Logger({ logLevel: 'DEBUG' }); +const logger = new Logger({ serviceName: 'serverless-airline' }); const secretsProvider = new HashiCorpVaultProvider({ url: 'https://vault.example.com:8200/v1', token: process.env.ROOT_TOKEN ?? '', + rootPath: 'kv', }); -try { - // Retrieve a secret from HashiCorp Vault - const secret = await secretsProvider.get<{ foo: 'string' }>('my-secret', { - sdkOptions: { - mount: 'secrets', - }, - }); - if (!secret) { - throw new Error('Secret not found'); - } - logger.debug('Secret retrieved!'); -} catch (error) { - if (error instanceof Error) { - logger.error(error.message, error); - } -} +// Retrieve a secret from HashiCorp Vault +const secret = await secretsProvider.get<{ foo: 'string' }>('my-secret'); + +const res = await fetch('https://example.com/api', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${secret?.foo}`, + }, + body: JSON.stringify({ data: 'example' }), +}); +logger.debug('res status', { status: res.status }); diff --git a/package-lock.json b/package-lock.json index 801a374712..a3c79f34c9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -100,7 +100,6 @@ "@middy/core": "^4.7.0", "aws-sdk": "^2.1692.0", "aws-sdk-client-mock": "^4.1.0", - "hashi-vault-js": "^0.4.16", "zod": "^3.24.2" } }, @@ -15388,18 +15387,6 @@ "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==", "dev": true }, - "node_modules/hashi-vault-js": { - "version": "0.4.16", - "resolved": "https://registry.npmjs.org/hashi-vault-js/-/hashi-vault-js-0.4.16.tgz", - "integrity": "sha512-5pEQEYGOUP7USJc9m1O0HRG4tX/Pdvx8V4U7FozpceiU0/ECSUhtR8NVTirnSYixLusiQ5HSuvYc+8u4IOFF9w==", - "dev": true, - "dependencies": { - "axios": "^1.7.0" - }, - "engines": { - "node": ">=18" - } - }, "node_modules/hasown": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", diff --git a/packages/parameters/src/types/BaseProvider.ts b/packages/parameters/src/types/BaseProvider.ts index 44c3ee417e..3154bb0893 100644 --- a/packages/parameters/src/types/BaseProvider.ts +++ b/packages/parameters/src/types/BaseProvider.ts @@ -17,7 +17,7 @@ type BaseProviderConstructorOptions = { * * If the `awsSdkV3Client` is not provided, this will be used to create a new client. */ - awsSdkV3ClientPrototype: new ( + awsSdkV3ClientPrototype?: new ( config?: unknown ) => unknown; }; From 577c76da79d069a2e9660e0af03fc352037284e9 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 25 Mar 2025 10:12:41 +0100 Subject: [PATCH 56/56] chore(ci): bump version to 2.17.0 (#3770) Co-authored-by: aws-powertools-bot <151832416+aws-powertools-bot@users.noreply.github.com> --- CHANGELOG.md | 21 ++++++++ examples/app/CHANGELOG.md | 8 +++ examples/app/package.json | 14 ++--- examples/snippets/CHANGELOG.md | 18 +++++++ examples/snippets/package.json | 18 +++---- layers/CHANGELOG.md | 8 +++ layers/package.json | 2 +- lerna.json | 2 +- package-lock.json | 80 ++++++++++++++--------------- packages/batch/CHANGELOG.md | 8 +++ packages/batch/package.json | 2 +- packages/commons/CHANGELOG.md | 11 ++++ packages/commons/package.json | 2 +- packages/commons/src/version.ts | 2 +- packages/event-handler/CHANGELOG.md | 8 +++ packages/event-handler/package.json | 4 +- packages/idempotency/CHANGELOG.md | 11 ++++ packages/idempotency/package.json | 6 +-- packages/jmespath/CHANGELOG.md | 8 +++ packages/jmespath/package.json | 4 +- packages/logger/CHANGELOG.md | 17 ++++++ packages/logger/package.json | 12 +++-- packages/metrics/CHANGELOG.md | 11 ++++ packages/metrics/package.json | 4 +- packages/parameters/CHANGELOG.md | 8 +++ packages/parameters/package.json | 4 +- packages/parser/CHANGELOG.md | 11 ++++ packages/parser/package.json | 4 +- packages/testing/CHANGELOG.md | 8 +++ packages/testing/package.json | 2 +- packages/tracer/CHANGELOG.md | 8 +++ packages/tracer/package.json | 4 +- packages/validation/CHANGELOG.md | 8 +++ packages/validation/package.json | 6 +-- 34 files changed, 259 insertions(+), 85 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e46a4810ca..24e38b6cdf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,27 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [2.17.0](https://github.com/aws-powertools/powertools-lambda-typescript/compare/v2.16.0...v2.17.0) (2025-03-25) + + +### Bug Fixes + +* **ci:** Remove --compatible-architectures from workflow ([#3752](https://github.com/aws-powertools/powertools-lambda-typescript/issues/3752)) ([dafa496](https://github.com/aws-powertools/powertools-lambda-typescript/commit/dafa49602ea45227384b63bff4d3f39d69e982d8)) +* **idempotency:** include sk in error msgs when using composite key ([#3709](https://github.com/aws-powertools/powertools-lambda-typescript/issues/3709)) ([661f5ff](https://github.com/aws-powertools/powertools-lambda-typescript/commit/661f5ff7f3f3805e24f515892e98430dccebf979)) +* **logger:** correctly refresh sample rate ([#3722](https://github.com/aws-powertools/powertools-lambda-typescript/issues/3722)) ([2692ca4](https://github.com/aws-powertools/powertools-lambda-typescript/commit/2692ca4d1b15763936659b05e1830d998a4d2020)) +* **parser:** ddb base schema + other exports ([#3741](https://github.com/aws-powertools/powertools-lambda-typescript/issues/3741)) ([51a3410](https://github.com/aws-powertools/powertools-lambda-typescript/commit/51a3410be8502496362d5ed13a64fe55691604ba)) + + +### Features + +* **commons:** make utilities aware of provisioned concurrency ([#3724](https://github.com/aws-powertools/powertools-lambda-typescript/issues/3724)) ([c28e45e](https://github.com/aws-powertools/powertools-lambda-typescript/commit/c28e45ecba315bac8fbc7744dbe21a3461747d44)) +* **logger:** set correlation ID in logs ([#3726](https://github.com/aws-powertools/powertools-lambda-typescript/issues/3726)) ([aa74fc8](https://github.com/aws-powertools/powertools-lambda-typescript/commit/aa74fc8548ccb8cb313ffd1742184c66e8d6c22c)) +* **metrics:** allow setting functionName via constructor parameter and environment variable ([#3696](https://github.com/aws-powertools/powertools-lambda-typescript/issues/3696)) ([3176fa0](https://github.com/aws-powertools/powertools-lambda-typescript/commit/3176fa08e1886d5c86e7b327134cc988b82cf8d8)) + + + + + # [2.16.0](https://github.com/aws-powertools/powertools-lambda-typescript/compare/v2.15.0...v2.16.0) (2025-03-07) diff --git a/examples/app/CHANGELOG.md b/examples/app/CHANGELOG.md index 98ef99ebeb..621ae9dd3a 100644 --- a/examples/app/CHANGELOG.md +++ b/examples/app/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [2.17.0](https://github.com/aws-powertools/powertools-lambda-typescript/compare/v2.16.0...v2.17.0) (2025-03-25) + +**Note:** Version bump only for package powertools-sample-app + + + + + # [2.16.0](https://github.com/aws-powertools/powertools-lambda-typescript/compare/v2.15.0...v2.16.0) (2025-03-07) **Note:** Version bump only for package powertools-sample-app diff --git a/examples/app/package.json b/examples/app/package.json index ba7628a4a4..cc0b7ed762 100644 --- a/examples/app/package.json +++ b/examples/app/package.json @@ -1,6 +1,6 @@ { "name": "powertools-sample-app", - "version": "2.16.0", + "version": "2.17.0", "author": { "name": "Amazon Web Services", "url": "https://aws.amazon.com" @@ -38,12 +38,12 @@ "vitest": "^3.0.5" }, "dependencies": { - "@aws-lambda-powertools/batch": "^2.16.0", - "@aws-lambda-powertools/idempotency": "^2.16.0", - "@aws-lambda-powertools/logger": "^2.16.0", - "@aws-lambda-powertools/metrics": "^2.16.0", - "@aws-lambda-powertools/parameters": "^2.16.0", - "@aws-lambda-powertools/tracer": "^2.16.0", + "@aws-lambda-powertools/batch": "^2.17.0", + "@aws-lambda-powertools/idempotency": "^2.17.0", + "@aws-lambda-powertools/logger": "^2.17.0", + "@aws-lambda-powertools/metrics": "^2.17.0", + "@aws-lambda-powertools/parameters": "^2.17.0", + "@aws-lambda-powertools/tracer": "^2.17.0", "@aws-sdk/client-ssm": "^3.772.0", "@aws-sdk/lib-dynamodb": "^3.772.0", "@middy/core": "^4.7.0", diff --git a/examples/snippets/CHANGELOG.md b/examples/snippets/CHANGELOG.md index 66abea5d81..1a62f8e50f 100644 --- a/examples/snippets/CHANGELOG.md +++ b/examples/snippets/CHANGELOG.md @@ -3,6 +3,24 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [2.17.0](https://github.com/aws-powertools/powertools-lambda-typescript/compare/v2.16.0...v2.17.0) (2025-03-25) + + +### Bug Fixes + +* **logger:** correctly refresh sample rate ([#3722](https://github.com/aws-powertools/powertools-lambda-typescript/issues/3722)) ([2692ca4](https://github.com/aws-powertools/powertools-lambda-typescript/commit/2692ca4d1b15763936659b05e1830d998a4d2020)) +* **parser:** ddb base schema + other exports ([#3741](https://github.com/aws-powertools/powertools-lambda-typescript/issues/3741)) ([51a3410](https://github.com/aws-powertools/powertools-lambda-typescript/commit/51a3410be8502496362d5ed13a64fe55691604ba)) + + +### Features + +* **logger:** set correlation ID in logs ([#3726](https://github.com/aws-powertools/powertools-lambda-typescript/issues/3726)) ([aa74fc8](https://github.com/aws-powertools/powertools-lambda-typescript/commit/aa74fc8548ccb8cb313ffd1742184c66e8d6c22c)) +* **metrics:** allow setting functionName via constructor parameter and environment variable ([#3696](https://github.com/aws-powertools/powertools-lambda-typescript/issues/3696)) ([3176fa0](https://github.com/aws-powertools/powertools-lambda-typescript/commit/3176fa08e1886d5c86e7b327134cc988b82cf8d8)) + + + + + # [2.16.0](https://github.com/aws-powertools/powertools-lambda-typescript/compare/v2.15.0...v2.16.0) (2025-03-07) diff --git a/examples/snippets/package.json b/examples/snippets/package.json index 1390f8ef70..7e21533935 100644 --- a/examples/snippets/package.json +++ b/examples/snippets/package.json @@ -1,6 +1,6 @@ { "name": "code-snippets", - "version": "2.16.0", + "version": "2.17.0", "description": "A collection code snippets for the Powertools for AWS Lambda (TypeScript) docs", "author": { "name": "Amazon Web Services", @@ -24,14 +24,14 @@ }, "homepage": "https://github.com/aws-powertools/powertools-lambda-typescript#readme", "devDependencies": { - "@aws-lambda-powertools/batch": "^2.16.0", - "@aws-lambda-powertools/idempotency": "^2.16.0", - "@aws-lambda-powertools/jmespath": "^2.16.0", - "@aws-lambda-powertools/logger": "^2.16.0", - "@aws-lambda-powertools/metrics": "^2.16.0", - "@aws-lambda-powertools/parameters": "^2.16.0", - "@aws-lambda-powertools/parser": "^2.16.0", - "@aws-lambda-powertools/tracer": "^2.16.0", + "@aws-lambda-powertools/batch": "^2.17.0", + "@aws-lambda-powertools/idempotency": "^2.17.0", + "@aws-lambda-powertools/jmespath": "^2.17.0", + "@aws-lambda-powertools/logger": "^2.17.0", + "@aws-lambda-powertools/metrics": "^2.17.0", + "@aws-lambda-powertools/parameters": "^2.17.0", + "@aws-lambda-powertools/parser": "^2.17.0", + "@aws-lambda-powertools/tracer": "^2.17.0", "@aws-sdk/client-appconfigdata": "^3.772.0", "@aws-sdk/client-dynamodb": "^3.772.0", "@aws-sdk/client-secrets-manager": "^3.772.0", diff --git a/layers/CHANGELOG.md b/layers/CHANGELOG.md index 1f71416fdb..38b84ee2d9 100644 --- a/layers/CHANGELOG.md +++ b/layers/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [2.17.0](https://github.com/aws-powertools/powertools-lambda-typescript/compare/v2.16.0...v2.17.0) (2025-03-25) + +**Note:** Version bump only for package layers + + + + + # [2.16.0](https://github.com/aws-powertools/powertools-lambda-typescript/compare/v2.15.0...v2.16.0) (2025-03-07) **Note:** Version bump only for package layers diff --git a/layers/package.json b/layers/package.json index 45cb514bf4..4e390633d2 100644 --- a/layers/package.json +++ b/layers/package.json @@ -1,6 +1,6 @@ { "name": "layers", - "version": "2.16.0", + "version": "2.17.0", "bin": { "layer": "bin/layers.js" }, diff --git a/lerna.json b/lerna.json index 982a374800..221add1dfa 100644 --- a/lerna.json +++ b/lerna.json @@ -16,7 +16,7 @@ "layers", "examples/snippets" ], - "version": "2.16.0", + "version": "2.17.0", "npmClient": "npm", "message": "chore(release): %s [skip ci]" } diff --git a/package-lock.json b/package-lock.json index a3c79f34c9..81864037e3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -49,15 +49,15 @@ }, "examples/app": { "name": "powertools-sample-app", - "version": "2.16.0", + "version": "2.17.0", "license": "MIT-0", "dependencies": { - "@aws-lambda-powertools/batch": "^2.16.0", - "@aws-lambda-powertools/idempotency": "^2.16.0", - "@aws-lambda-powertools/logger": "^2.16.0", - "@aws-lambda-powertools/metrics": "^2.16.0", - "@aws-lambda-powertools/parameters": "^2.16.0", - "@aws-lambda-powertools/tracer": "^2.16.0", + "@aws-lambda-powertools/batch": "^2.17.0", + "@aws-lambda-powertools/idempotency": "^2.17.0", + "@aws-lambda-powertools/logger": "^2.17.0", + "@aws-lambda-powertools/metrics": "^2.17.0", + "@aws-lambda-powertools/parameters": "^2.17.0", + "@aws-lambda-powertools/tracer": "^2.17.0", "@aws-sdk/client-ssm": "^3.772.0", "@aws-sdk/lib-dynamodb": "^3.772.0", "@middy/core": "^4.7.0", @@ -81,17 +81,17 @@ }, "examples/snippets": { "name": "code-snippets", - "version": "2.16.0", + "version": "2.17.0", "license": "MIT-0", "devDependencies": { - "@aws-lambda-powertools/batch": "^2.16.0", - "@aws-lambda-powertools/idempotency": "^2.16.0", - "@aws-lambda-powertools/jmespath": "^2.16.0", - "@aws-lambda-powertools/logger": "^2.16.0", - "@aws-lambda-powertools/metrics": "^2.16.0", - "@aws-lambda-powertools/parameters": "^2.16.0", - "@aws-lambda-powertools/parser": "^2.16.0", - "@aws-lambda-powertools/tracer": "^2.16.0", + "@aws-lambda-powertools/batch": "^2.17.0", + "@aws-lambda-powertools/idempotency": "^2.17.0", + "@aws-lambda-powertools/jmespath": "^2.17.0", + "@aws-lambda-powertools/logger": "^2.17.0", + "@aws-lambda-powertools/metrics": "^2.17.0", + "@aws-lambda-powertools/parameters": "^2.17.0", + "@aws-lambda-powertools/parser": "^2.17.0", + "@aws-lambda-powertools/tracer": "^2.17.0", "@aws-sdk/client-appconfigdata": "^3.772.0", "@aws-sdk/client-dynamodb": "^3.772.0", "@aws-sdk/client-secrets-manager": "^3.772.0", @@ -104,7 +104,7 @@ } }, "layers": { - "version": "2.16.0", + "version": "2.17.0", "license": "MIT-0", "dependencies": { "aws-cdk": "^2.1005.0", @@ -22940,7 +22940,7 @@ }, "packages/batch": { "name": "@aws-lambda-powertools/batch", - "version": "2.16.0", + "version": "2.17.0", "license": "MIT-0", "devDependencies": { "@aws-lambda-powertools/testing-utils": "file:../testing" @@ -22948,7 +22948,7 @@ }, "packages/commons": { "name": "@aws-lambda-powertools/commons", - "version": "2.16.0", + "version": "2.17.0", "license": "MIT-0", "devDependencies": { "@aws-lambda-powertools/testing-utils": "file:../testing" @@ -22956,19 +22956,19 @@ }, "packages/event-handler": { "name": "@aws-lambda-powertools/event-handler", - "version": "2.16.0", + "version": "2.17.0", "license": "MIT-0", "dependencies": { - "@aws-lambda-powertools/commons": "^2.16.0" + "@aws-lambda-powertools/commons": "^2.17.0" } }, "packages/idempotency": { "name": "@aws-lambda-powertools/idempotency", - "version": "2.16.0", + "version": "2.17.0", "license": "MIT-0", "dependencies": { - "@aws-lambda-powertools/commons": "^2.16.0", - "@aws-lambda-powertools/jmespath": "^2.16.0" + "@aws-lambda-powertools/commons": "^2.17.0", + "@aws-lambda-powertools/jmespath": "^2.17.0" }, "devDependencies": { "@aws-lambda-powertools/testing-utils": "file:../testing", @@ -22995,18 +22995,18 @@ }, "packages/jmespath": { "name": "@aws-lambda-powertools/jmespath", - "version": "2.16.0", + "version": "2.17.0", "license": "MIT-0", "dependencies": { - "@aws-lambda-powertools/commons": "^2.16.0" + "@aws-lambda-powertools/commons": "^2.17.0" } }, "packages/logger": { "name": "@aws-lambda-powertools/logger", - "version": "2.16.0", + "version": "2.17.0", "license": "MIT-0", "dependencies": { - "@aws-lambda-powertools/commons": "^2.16.0", + "@aws-lambda-powertools/commons": "^2.17.0", "lodash.merge": "^4.6.2" }, "devDependencies": { @@ -23028,10 +23028,10 @@ }, "packages/metrics": { "name": "@aws-lambda-powertools/metrics", - "version": "2.16.0", + "version": "2.17.0", "license": "MIT-0", "dependencies": { - "@aws-lambda-powertools/commons": "^2.16.0" + "@aws-lambda-powertools/commons": "^2.17.0" }, "devDependencies": { "@aws-lambda-powertools/testing-utils": "file:../testing", @@ -23050,10 +23050,10 @@ }, "packages/parameters": { "name": "@aws-lambda-powertools/parameters", - "version": "2.16.0", + "version": "2.17.0", "license": "MIT-0", "dependencies": { - "@aws-lambda-powertools/commons": "^2.16.0" + "@aws-lambda-powertools/commons": "^2.17.0" }, "devDependencies": { "@aws-lambda-powertools/testing-utils": "file:../testing", @@ -23096,10 +23096,10 @@ }, "packages/parser": { "name": "@aws-lambda-powertools/parser", - "version": "2.16.0", + "version": "2.17.0", "license": "MIT-0", "dependencies": { - "@aws-lambda-powertools/commons": "^2.16.0" + "@aws-lambda-powertools/commons": "^2.17.0" }, "peerDependencies": { "@middy/core": "4.x || 5.x || 6.x", @@ -23116,7 +23116,7 @@ }, "packages/testing": { "name": "@aws-lambda-powertools/testing-utils", - "version": "2.16.0", + "version": "2.17.0", "license": "MIT-0", "dependencies": { "@aws-cdk/toolkit-lib": "^0.1.6", @@ -23133,10 +23133,10 @@ }, "packages/tracer": { "name": "@aws-lambda-powertools/tracer", - "version": "2.16.0", + "version": "2.17.0", "license": "MIT-0", "dependencies": { - "@aws-lambda-powertools/commons": "^2.16.0", + "@aws-lambda-powertools/commons": "^2.17.0", "aws-xray-sdk-core": "^3.10.3" }, "devDependencies": { @@ -23155,11 +23155,11 @@ }, "packages/validation": { "name": "@aws-lambda-powertools/validation", - "version": "2.16.0", + "version": "2.17.0", "license": "MIT-0", "dependencies": { - "@aws-lambda-powertools/commons": "^2.16.0", - "@aws-lambda-powertools/jmespath": "^2.16.0", + "@aws-lambda-powertools/commons": "^2.17.0", + "@aws-lambda-powertools/jmespath": "^2.17.0", "ajv": "^8.17.1" } } diff --git a/packages/batch/CHANGELOG.md b/packages/batch/CHANGELOG.md index d026d98866..5f7dad62e6 100644 --- a/packages/batch/CHANGELOG.md +++ b/packages/batch/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [2.17.0](https://github.com/aws-powertools/powertools-lambda-typescript/compare/v2.16.0...v2.17.0) (2025-03-25) + +**Note:** Version bump only for package @aws-lambda-powertools/batch + + + + + # [2.16.0](https://github.com/aws-powertools/powertools-lambda-typescript/compare/v2.15.0...v2.16.0) (2025-03-07) diff --git a/packages/batch/package.json b/packages/batch/package.json index 5b6bfa9cd1..b9adc82d4f 100644 --- a/packages/batch/package.json +++ b/packages/batch/package.json @@ -1,6 +1,6 @@ { "name": "@aws-lambda-powertools/batch", - "version": "2.16.0", + "version": "2.17.0", "description": "The batch processing package for the Powertools for AWS Lambda (TypeScript) library.", "author": { "name": "Amazon Web Services", diff --git a/packages/commons/CHANGELOG.md b/packages/commons/CHANGELOG.md index 299a20b945..44e4d70d62 100644 --- a/packages/commons/CHANGELOG.md +++ b/packages/commons/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [2.17.0](https://github.com/aws-powertools/powertools-lambda-typescript/compare/v2.16.0...v2.17.0) (2025-03-25) + + +### Features + +* **commons:** make utilities aware of provisioned concurrency ([#3724](https://github.com/aws-powertools/powertools-lambda-typescript/issues/3724)) ([c28e45e](https://github.com/aws-powertools/powertools-lambda-typescript/commit/c28e45ecba315bac8fbc7744dbe21a3461747d44)) + + + + + # [2.16.0](https://github.com/aws-powertools/powertools-lambda-typescript/compare/v2.15.0...v2.16.0) (2025-03-07) diff --git a/packages/commons/package.json b/packages/commons/package.json index d089c99f0f..9ce3f3a630 100644 --- a/packages/commons/package.json +++ b/packages/commons/package.json @@ -1,6 +1,6 @@ { "name": "@aws-lambda-powertools/commons", - "version": "2.16.0", + "version": "2.17.0", "description": "A shared utility package for Powertools for AWS Lambda (TypeScript) libraries", "author": { "name": "Amazon Web Services", diff --git a/packages/commons/src/version.ts b/packages/commons/src/version.ts index c6e60572eb..9c78bb2091 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 = '2.16.0'; +export const PT_VERSION = '2.17.0'; diff --git a/packages/event-handler/CHANGELOG.md b/packages/event-handler/CHANGELOG.md index 7947464911..5afd0c1f6a 100644 --- a/packages/event-handler/CHANGELOG.md +++ b/packages/event-handler/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [2.17.0](https://github.com/aws-powertools/powertools-lambda-typescript/compare/v2.16.0...v2.17.0) (2025-03-25) + +**Note:** Version bump only for package @aws-lambda-powertools/event-handler + + + + + # [2.16.0](https://github.com/aws-powertools/powertools-lambda-typescript/compare/v2.15.0...v2.16.0) (2025-03-07) **Note:** Version bump only for package @aws-lambda-powertools/event-handler diff --git a/packages/event-handler/package.json b/packages/event-handler/package.json index b2a55759f8..296922d7ee 100644 --- a/packages/event-handler/package.json +++ b/packages/event-handler/package.json @@ -1,6 +1,6 @@ { "name": "@aws-lambda-powertools/event-handler", - "version": "2.16.0", + "version": "2.17.0", "description": "Lightweight routing to reduce boilerplate for API Gateway REST/HTTP API, ALB and Lambda Function URLs", "author": { "name": "Amazon Web Services", @@ -51,7 +51,7 @@ "url": "https://github.com/aws-powertools/powertools-lambda-typescript/issues" }, "dependencies": { - "@aws-lambda-powertools/commons": "^2.16.0" + "@aws-lambda-powertools/commons": "^2.17.0" }, "keywords": [ "aws", diff --git a/packages/idempotency/CHANGELOG.md b/packages/idempotency/CHANGELOG.md index 0edae7f140..35e708fb2b 100644 --- a/packages/idempotency/CHANGELOG.md +++ b/packages/idempotency/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [2.17.0](https://github.com/aws-powertools/powertools-lambda-typescript/compare/v2.16.0...v2.17.0) (2025-03-25) + + +### Bug Fixes + +* **idempotency:** include sk in error msgs when using composite key ([#3709](https://github.com/aws-powertools/powertools-lambda-typescript/issues/3709)) ([661f5ff](https://github.com/aws-powertools/powertools-lambda-typescript/commit/661f5ff7f3f3805e24f515892e98430dccebf979)) + + + + + # [2.16.0](https://github.com/aws-powertools/powertools-lambda-typescript/compare/v2.15.0...v2.16.0) (2025-03-07) **Note:** Version bump only for package @aws-lambda-powertools/idempotency diff --git a/packages/idempotency/package.json b/packages/idempotency/package.json index cea2f4ee4b..48b1f06d94 100644 --- a/packages/idempotency/package.json +++ b/packages/idempotency/package.json @@ -1,6 +1,6 @@ { "name": "@aws-lambda-powertools/idempotency", - "version": "2.16.0", + "version": "2.17.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", @@ -98,8 +98,8 @@ "url": "https://github.com/aws-powertools/powertools-lambda-typescript/issues" }, "dependencies": { - "@aws-lambda-powertools/commons": "^2.16.0", - "@aws-lambda-powertools/jmespath": "^2.16.0" + "@aws-lambda-powertools/commons": "^2.17.0", + "@aws-lambda-powertools/jmespath": "^2.17.0" }, "peerDependencies": { "@aws-sdk/client-dynamodb": ">=3.x", diff --git a/packages/jmespath/CHANGELOG.md b/packages/jmespath/CHANGELOG.md index 8852bd79c3..ad70cf1c3a 100644 --- a/packages/jmespath/CHANGELOG.md +++ b/packages/jmespath/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [2.17.0](https://github.com/aws-powertools/powertools-lambda-typescript/compare/v2.16.0...v2.17.0) (2025-03-25) + +**Note:** Version bump only for package @aws-lambda-powertools/jmespath + + + + + # [2.16.0](https://github.com/aws-powertools/powertools-lambda-typescript/compare/v2.15.0...v2.16.0) (2025-03-07) **Note:** Version bump only for package @aws-lambda-powertools/jmespath diff --git a/packages/jmespath/package.json b/packages/jmespath/package.json index fb318b2552..11270fd688 100644 --- a/packages/jmespath/package.json +++ b/packages/jmespath/package.json @@ -1,6 +1,6 @@ { "name": "@aws-lambda-powertools/jmespath", - "version": "2.16.0", + "version": "2.17.0", "description": "A type safe and modern jmespath module to parse and extract data from JSON documents using JMESPath", "author": { "name": "Amazon Web Services", @@ -71,7 +71,7 @@ "lib" ], "dependencies": { - "@aws-lambda-powertools/commons": "^2.16.0" + "@aws-lambda-powertools/commons": "^2.17.0" }, "repository": { "type": "git", diff --git a/packages/logger/CHANGELOG.md b/packages/logger/CHANGELOG.md index 14e17740cd..5632170d87 100644 --- a/packages/logger/CHANGELOG.md +++ b/packages/logger/CHANGELOG.md @@ -3,6 +3,23 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [2.17.0](https://github.com/aws-powertools/powertools-lambda-typescript/compare/v2.16.0...v2.17.0) (2025-03-25) + + +### Bug Fixes + +* **logger:** correctly refresh sample rate ([#3722](https://github.com/aws-powertools/powertools-lambda-typescript/issues/3722)) ([2692ca4](https://github.com/aws-powertools/powertools-lambda-typescript/commit/2692ca4d1b15763936659b05e1830d998a4d2020)) + + +### Features + +* **commons:** make utilities aware of provisioned concurrency ([#3724](https://github.com/aws-powertools/powertools-lambda-typescript/issues/3724)) ([c28e45e](https://github.com/aws-powertools/powertools-lambda-typescript/commit/c28e45ecba315bac8fbc7744dbe21a3461747d44)) +* **logger:** set correlation ID in logs ([#3726](https://github.com/aws-powertools/powertools-lambda-typescript/issues/3726)) ([aa74fc8](https://github.com/aws-powertools/powertools-lambda-typescript/commit/aa74fc8548ccb8cb313ffd1742184c66e8d6c22c)) + + + + + # [2.16.0](https://github.com/aws-powertools/powertools-lambda-typescript/compare/v2.15.0...v2.16.0) (2025-03-07) diff --git a/packages/logger/package.json b/packages/logger/package.json index 093551c0be..3175cbe001 100644 --- a/packages/logger/package.json +++ b/packages/logger/package.json @@ -1,6 +1,6 @@ { "name": "@aws-lambda-powertools/logger", - "version": "2.16.0", + "version": "2.17.0", "description": "The logging package for the Powertools for AWS Lambda (TypeScript) library", "author": { "name": "Amazon Web Services", @@ -76,8 +76,8 @@ "@types/lodash.merge": "^4.6.9" }, "peerDependencies": { - "@middy/core": "4.x || 5.x || 6.x", - "@aws-lambda-powertools/jmespath": "2.x" + "@aws-lambda-powertools/jmespath": "2.x", + "@middy/core": "4.x || 5.x || 6.x" }, "peerDependenciesMeta": { "@middy/core": { @@ -87,7 +87,9 @@ "optional": true } }, - "files": ["lib"], + "files": [ + "lib" + ], "repository": { "type": "git", "url": "git+https://github.com/aws-powertools/powertools-lambda-typescript.git" @@ -96,7 +98,7 @@ "url": "https://github.com/aws-powertools/powertools-lambda-typescript/issues" }, "dependencies": { - "@aws-lambda-powertools/commons": "^2.16.0", + "@aws-lambda-powertools/commons": "^2.17.0", "lodash.merge": "^4.6.2" }, "keywords": [ diff --git a/packages/metrics/CHANGELOG.md b/packages/metrics/CHANGELOG.md index 020b4ebb7e..6f07ec4795 100644 --- a/packages/metrics/CHANGELOG.md +++ b/packages/metrics/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [2.17.0](https://github.com/aws-powertools/powertools-lambda-typescript/compare/v2.16.0...v2.17.0) (2025-03-25) + + +### Features + +* **metrics:** allow setting functionName via constructor parameter and environment variable ([#3696](https://github.com/aws-powertools/powertools-lambda-typescript/issues/3696)) ([3176fa0](https://github.com/aws-powertools/powertools-lambda-typescript/commit/3176fa08e1886d5c86e7b327134cc988b82cf8d8)) + + + + + # [2.16.0](https://github.com/aws-powertools/powertools-lambda-typescript/compare/v2.15.0...v2.16.0) (2025-03-07) **Note:** Version bump only for package @aws-lambda-powertools/metrics diff --git a/packages/metrics/package.json b/packages/metrics/package.json index 95cd89deb6..c6e053de4d 100644 --- a/packages/metrics/package.json +++ b/packages/metrics/package.json @@ -1,6 +1,6 @@ { "name": "@aws-lambda-powertools/metrics", - "version": "2.16.0", + "version": "2.17.0", "description": "The metrics package for the Powertools for AWS Lambda (TypeScript) library", "author": { "name": "Amazon Web Services", @@ -88,7 +88,7 @@ "url": "https://github.com/aws-powertools/powertools-lambda-typescript/issues" }, "dependencies": { - "@aws-lambda-powertools/commons": "^2.16.0" + "@aws-lambda-powertools/commons": "^2.17.0" }, "keywords": [ "aws", diff --git a/packages/parameters/CHANGELOG.md b/packages/parameters/CHANGELOG.md index 4bbe48afe4..7cf5a9e4c2 100644 --- a/packages/parameters/CHANGELOG.md +++ b/packages/parameters/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [2.17.0](https://github.com/aws-powertools/powertools-lambda-typescript/compare/v2.16.0...v2.17.0) (2025-03-25) + +**Note:** Version bump only for package @aws-lambda-powertools/parameters + + + + + # [2.16.0](https://github.com/aws-powertools/powertools-lambda-typescript/compare/v2.15.0...v2.16.0) (2025-03-07) **Note:** Version bump only for package @aws-lambda-powertools/parameters diff --git a/packages/parameters/package.json b/packages/parameters/package.json index d58c5a3208..5e0969bdf5 100644 --- a/packages/parameters/package.json +++ b/packages/parameters/package.json @@ -1,6 +1,6 @@ { "name": "@aws-lambda-powertools/parameters", - "version": "2.16.0", + "version": "2.17.0", "description": "The parameters package for the Powertools for AWS Lambda (TypeScript) library", "author": { "name": "Amazon Web Services", @@ -165,7 +165,7 @@ "aws-sdk-client-mock": "^4.1.0" }, "dependencies": { - "@aws-lambda-powertools/commons": "^2.16.0" + "@aws-lambda-powertools/commons": "^2.17.0" }, "peerDependencies": { "@aws-sdk/client-appconfigdata": ">=3.x", diff --git a/packages/parser/CHANGELOG.md b/packages/parser/CHANGELOG.md index e0267efed4..cd69942fca 100644 --- a/packages/parser/CHANGELOG.md +++ b/packages/parser/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [2.17.0](https://github.com/aws-powertools/powertools-lambda-typescript/compare/v2.16.0...v2.17.0) (2025-03-25) + + +### Bug Fixes + +* **parser:** ddb base schema + other exports ([#3741](https://github.com/aws-powertools/powertools-lambda-typescript/issues/3741)) ([51a3410](https://github.com/aws-powertools/powertools-lambda-typescript/commit/51a3410be8502496362d5ed13a64fe55691604ba)) + + + + + # [2.16.0](https://github.com/aws-powertools/powertools-lambda-typescript/compare/v2.15.0...v2.16.0) (2025-03-07) diff --git a/packages/parser/package.json b/packages/parser/package.json index a613d41369..03ba6ebe3b 100644 --- a/packages/parser/package.json +++ b/packages/parser/package.json @@ -1,6 +1,6 @@ { "name": "@aws-lambda-powertools/parser", - "version": "2.16.0", + "version": "2.17.0", "description": "The parser package for the Powertools for AWS Lambda (TypeScript) library.", "author": { "name": "Amazon Web Services", @@ -160,7 +160,7 @@ "nodejs" ], "dependencies": { - "@aws-lambda-powertools/commons": "^2.16.0" + "@aws-lambda-powertools/commons": "^2.17.0" }, "peerDependencies": { "@middy/core": "4.x || 5.x || 6.x", diff --git a/packages/testing/CHANGELOG.md b/packages/testing/CHANGELOG.md index 8fe1002b88..05d203fc7c 100644 --- a/packages/testing/CHANGELOG.md +++ b/packages/testing/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [2.17.0](https://github.com/aws-powertools/powertools-lambda-typescript/compare/v2.16.0...v2.17.0) (2025-03-25) + +**Note:** Version bump only for package @aws-lambda-powertools/testing-utils + + + + + # [2.16.0](https://github.com/aws-powertools/powertools-lambda-typescript/compare/v2.15.0...v2.16.0) (2025-03-07) **Note:** Version bump only for package @aws-lambda-powertools/testing-utils diff --git a/packages/testing/package.json b/packages/testing/package.json index 9aa4ffa87a..6dc479ef4f 100644 --- a/packages/testing/package.json +++ b/packages/testing/package.json @@ -1,6 +1,6 @@ { "name": "@aws-lambda-powertools/testing-utils", - "version": "2.16.0", + "version": "2.17.0", "description": "A package containing utilities to test your serverless workloads", "author": { "name": "Amazon Web Services", diff --git a/packages/tracer/CHANGELOG.md b/packages/tracer/CHANGELOG.md index 15293fee91..74302884d9 100644 --- a/packages/tracer/CHANGELOG.md +++ b/packages/tracer/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [2.17.0](https://github.com/aws-powertools/powertools-lambda-typescript/compare/v2.16.0...v2.17.0) (2025-03-25) + +**Note:** Version bump only for package @aws-lambda-powertools/tracer + + + + + # [2.16.0](https://github.com/aws-powertools/powertools-lambda-typescript/compare/v2.15.0...v2.16.0) (2025-03-07) **Note:** Version bump only for package @aws-lambda-powertools/tracer diff --git a/packages/tracer/package.json b/packages/tracer/package.json index 6399102ae8..e0174d740e 100644 --- a/packages/tracer/package.json +++ b/packages/tracer/package.json @@ -1,6 +1,6 @@ { "name": "@aws-lambda-powertools/tracer", - "version": "2.16.0", + "version": "2.17.0", "description": "The tracer package for the Powertools for AWS Lambda (TypeScript) library", "author": { "name": "Amazon Web Services", @@ -87,7 +87,7 @@ "url": "https://github.com/aws-powertools/powertools-lambda-typescript/issues" }, "dependencies": { - "@aws-lambda-powertools/commons": "^2.16.0", + "@aws-lambda-powertools/commons": "^2.17.0", "aws-xray-sdk-core": "^3.10.3" }, "keywords": [ diff --git a/packages/validation/CHANGELOG.md b/packages/validation/CHANGELOG.md index 88ae494c5f..887a97fb5e 100644 --- a/packages/validation/CHANGELOG.md +++ b/packages/validation/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [2.17.0](https://github.com/aws-powertools/powertools-lambda-typescript/compare/v2.16.0...v2.17.0) (2025-03-25) + +**Note:** Version bump only for package @aws-lambda-powertools/validation + + + + + # [2.16.0](https://github.com/aws-powertools/powertools-lambda-typescript/compare/v2.15.0...v2.16.0) (2025-03-07) diff --git a/packages/validation/package.json b/packages/validation/package.json index 2231fe1dbb..24d1589bcb 100644 --- a/packages/validation/package.json +++ b/packages/validation/package.json @@ -1,6 +1,6 @@ { "name": "@aws-lambda-powertools/validation", - "version": "2.16.0", + "version": "2.17.0", "description": "An utility to validate events and responses using JSON Schemas", "author": { "name": "Amazon Web Services", @@ -80,8 +80,8 @@ "url": "https://github.com/aws-powertools/powertools-lambda-typescript/issues" }, "dependencies": { - "@aws-lambda-powertools/commons": "^2.16.0", - "@aws-lambda-powertools/jmespath": "^2.16.0", + "@aws-lambda-powertools/commons": "^2.17.0", + "@aws-lambda-powertools/jmespath": "^2.17.0", "ajv": "^8.17.1" }, "keywords": [