diff --git a/.github/package.json b/.github/package.json
index 41be8df67..82c57c793 100644
--- a/.github/package.json
+++ b/.github/package.json
@@ -1,6 +1,6 @@
{
"name": "@middy/github-workflows",
- "version": "7.3.4",
+ "version": "7.4.0",
"private": true,
"engines": {
"node": ">=24.0"
diff --git a/package-lock.json b/package-lock.json
index 1a9475e12..7b9d0eadd 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "@middy/monorepo",
- "version": "7.3.4",
+ "version": "7.4.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@middy/monorepo",
- "version": "7.3.4",
+ "version": "7.4.0",
"license": "MIT",
"workspaces": [
"packages/*",
@@ -31,7 +31,7 @@
},
".github": {
"name": "@middy/github-workflows",
- "version": "7.3.4",
+ "version": "7.4.0",
"devDependencies": {
"license-check-and-add": "4.0.5",
"lockfile-lint": "5.0.0"
@@ -275,9 +275,9 @@
}
},
"node_modules/@aws-sdk/client-apigatewaymanagementapi": {
- "version": "3.1039.0",
- "resolved": "https://registry.npmjs.org/@aws-sdk/client-apigatewaymanagementapi/-/client-apigatewaymanagementapi-3.1039.0.tgz",
- "integrity": "sha512-hz0NvJjPkyv26eQxQ6k+civhRdN825O8lbxPVXkGD60DCIyrVcrP7r2OPOFyTAC2Ar1GECCrAfqrKdPYjg1XVw==",
+ "version": "3.1040.0",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/client-apigatewaymanagementapi/-/client-apigatewaymanagementapi-3.1040.0.tgz",
+ "integrity": "sha512-1CYjlZ9vLlj8ISjPL9An7irI2wBufXzdbn/jH6vTPH6lDYB6/+GvaMWLTTh+/JvpfhDxpB93/t1g5u0KaVHbRg==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
@@ -326,9 +326,9 @@
}
},
"node_modules/@aws-sdk/client-appconfigdata": {
- "version": "3.1039.0",
- "resolved": "https://registry.npmjs.org/@aws-sdk/client-appconfigdata/-/client-appconfigdata-3.1039.0.tgz",
- "integrity": "sha512-AIk6lqgbRhD6lDPTHZP8p5GjUFrgjaKa4iDf4KCz/gA4aQ6eC+9I5BkhVBKy97PXsuG7THwCkPAyrd0pMKc3Zg==",
+ "version": "3.1040.0",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/client-appconfigdata/-/client-appconfigdata-3.1040.0.tgz",
+ "integrity": "sha512-UyxDikm5SYclAVEvK7edAgEmyhTxoFsiyHCaQWFLaGoMEq5DNJMTOGSM1SaVMLOj+6i6w7hXm+VQTVxv7hJ0Pw==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
@@ -378,9 +378,9 @@
}
},
"node_modules/@aws-sdk/client-cognito-identity": {
- "version": "3.1039.0",
- "resolved": "https://registry.npmjs.org/@aws-sdk/client-cognito-identity/-/client-cognito-identity-3.1039.0.tgz",
- "integrity": "sha512-jue1zZeTxtyCzD7vMxw5gq4XE1q8SUDoePqgdPEPPgjg5FTJsmEhpswgeLV2dP4sHkyeap4f4Pf7BCmwkgJuNQ==",
+ "version": "3.1040.0",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/client-cognito-identity/-/client-cognito-identity-3.1040.0.tgz",
+ "integrity": "sha512-7nwgQlDc2brGoPbNP7h3EBXs30zX7sb8m+tLaSQdqnNWpXCpq/AY0H/Fd5BQ5UWPlMB9k3sHAkMkCxm6kZXuLQ==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
@@ -429,9 +429,9 @@
}
},
"node_modules/@aws-sdk/client-dynamodb": {
- "version": "3.1039.0",
- "resolved": "https://registry.npmjs.org/@aws-sdk/client-dynamodb/-/client-dynamodb-3.1039.0.tgz",
- "integrity": "sha512-eqyrnSj2l0/y89LHENnGparEyKD33Wh8PQszgWbtb6t8bI5oriPaTHHXCdGUmFjOMkiNfqbsLCoo5HhMXlvbxw==",
+ "version": "3.1040.0",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/client-dynamodb/-/client-dynamodb-3.1040.0.tgz",
+ "integrity": "sha512-rxWgbYoaUwY11UnajsdJVKYYWp+ZE0AWquI2ImdPTodVcDVdYVhrxmb80my6QH1UFtOUmBCZIndx9fDT/Exp9g==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
@@ -483,9 +483,9 @@
}
},
"node_modules/@aws-sdk/client-lambda": {
- "version": "3.1039.0",
- "resolved": "https://registry.npmjs.org/@aws-sdk/client-lambda/-/client-lambda-3.1039.0.tgz",
- "integrity": "sha512-G6k9MYrrvINhGhHDNheF9NcJlVQ4vbtyLD6pjsgL+vDwugQB84OR95T7bNI9If5DlOxKrLx9s6BGid1YoWQKYA==",
+ "version": "3.1040.0",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/client-lambda/-/client-lambda-3.1040.0.tgz",
+ "integrity": "sha512-QEpUqgsKVYZXfNmZs0vREVcxDKVvT1FKYH788s3JkPa6zCmT2wBEgCqqIgKS0QdbFMMTPDYIPkIInmIFu3YWjQ==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
@@ -539,9 +539,9 @@
}
},
"node_modules/@aws-sdk/client-s3": {
- "version": "3.1039.0",
- "resolved": "https://registry.npmjs.org/@aws-sdk/client-s3/-/client-s3-3.1039.0.tgz",
- "integrity": "sha512-PVH9v0pHYBQnBADSR/m88NgcuJcYqPXfpmkcME66vRF75Y4swwbEVVFbTBFuvxu0YcZiLFXu3lw0FDK00vEa3A==",
+ "version": "3.1040.0",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/client-s3/-/client-s3-3.1040.0.tgz",
+ "integrity": "sha512-Ldfby1xDrlZwNY2NxP9pwdVrf8sqHbGBKP1UkoG/oWcePGlGhjY8iVwy8hRy9f1EQfHVFWIFunwHaPQxhYTnWQ==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
@@ -606,9 +606,9 @@
}
},
"node_modules/@aws-sdk/client-secrets-manager": {
- "version": "3.1039.0",
- "resolved": "https://registry.npmjs.org/@aws-sdk/client-secrets-manager/-/client-secrets-manager-3.1039.0.tgz",
- "integrity": "sha512-Ew0tUX3tKpzGIMMX+RyRyxR4FHcPTEPMjE9YSemyau3NyNFjlpHQjeTNwFvplLEl/LPCC9A5gk58LcaHtySk7A==",
+ "version": "3.1040.0",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/client-secrets-manager/-/client-secrets-manager-3.1040.0.tgz",
+ "integrity": "sha512-qszI/6MUy57rSqA2eSN3jbdjU1RFUDkayw7HbSX02jRmP896mSssWM0BC+mwYXuY7d3s1QntxmMKiNwXEXRdWg==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
@@ -657,9 +657,9 @@
}
},
"node_modules/@aws-sdk/client-servicediscovery": {
- "version": "3.1039.0",
- "resolved": "https://registry.npmjs.org/@aws-sdk/client-servicediscovery/-/client-servicediscovery-3.1039.0.tgz",
- "integrity": "sha512-9lL3eJAe/C+jhtgHtgThcD2WaMjNEP8srglAfaarLL3szfrrl2+G+N/4KxvfgN2xC6anpGryomKtHnaR8j8nAQ==",
+ "version": "3.1040.0",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/client-servicediscovery/-/client-servicediscovery-3.1040.0.tgz",
+ "integrity": "sha512-c+OnV3SCbykjlY0H0OmD/RqzPaCEwqFY2k6uf6G5EZ4uLL/BN44GQL9jgGEC3BSk++uYkfaTJiIJbRqjlgWbHw==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
@@ -708,9 +708,9 @@
}
},
"node_modules/@aws-sdk/client-sqs": {
- "version": "3.1039.0",
- "resolved": "https://registry.npmjs.org/@aws-sdk/client-sqs/-/client-sqs-3.1039.0.tgz",
- "integrity": "sha512-U8rooijGy5OnSdxEaJ/sIxuGPgHfspxE8K/az22eJJ4qnO2XcVMtkHljvbfQG0yL3wd93XaypNSPI52okdTyCA==",
+ "version": "3.1040.0",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/client-sqs/-/client-sqs-3.1040.0.tgz",
+ "integrity": "sha512-dzmxbJ6swad3IDAR3xTo0ju7HQKm1YMiwxWr5utZ223WagpkxnKhbAUAjPscQRzbPRLMU3ojXTDcrYEZ/IpUiw==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
@@ -761,9 +761,9 @@
}
},
"node_modules/@aws-sdk/client-ssm": {
- "version": "3.1039.0",
- "resolved": "https://registry.npmjs.org/@aws-sdk/client-ssm/-/client-ssm-3.1039.0.tgz",
- "integrity": "sha512-UvFJ/9HSIkQWxcLNbq/QaWemhqi7TChLW+ZSWBv8mNmSybTj4ZrMFpzbH2y9gJq38dN1KVR6FyjtOA/+FE6avg==",
+ "version": "3.1040.0",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/client-ssm/-/client-ssm-3.1040.0.tgz",
+ "integrity": "sha512-Su6vrzo32lx7jL6Dk/fatQpjrGjBCQIDr7pRdlpHOGOSTfg2L+UFg/XRrZRL5blz7dCNdfhZf2uuuMK1n0hrkg==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
@@ -813,9 +813,9 @@
}
},
"node_modules/@aws-sdk/client-sts": {
- "version": "3.1039.0",
- "resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.1039.0.tgz",
- "integrity": "sha512-FKwfa4agOd6rctrp6D+W/sUKT+c+wI5m23oYR0VyE01oad6ZYff+113JP/X2xbrxIFJtVz7GieQZdVUFqOuMuQ==",
+ "version": "3.1040.0",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.1040.0.tgz",
+ "integrity": "sha512-k5m8ofhqQ2102h6l0iqNFRpuSXdyhk62U9i13kmGmscfqtVX4JeKjg//IK1Mhaz6Owi6WxAl1jQ8vcx81gpzww==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
@@ -1088,13 +1088,13 @@
}
},
"node_modules/@aws-sdk/credential-providers": {
- "version": "3.1039.0",
- "resolved": "https://registry.npmjs.org/@aws-sdk/credential-providers/-/credential-providers-3.1039.0.tgz",
- "integrity": "sha512-zJdE1J5p3lxk6kw40hZoI7O3aZDy3exFUWyZjjE4BGppXvfM4PQTDFRcq466JxjUc7x3X//H2oNejsH8+UErIg==",
+ "version": "3.1040.0",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/credential-providers/-/credential-providers-3.1040.0.tgz",
+ "integrity": "sha512-9CUcij1A7f6i4XOp/7MczdQInHvHZ8KKoNHlXHq+UtR3HOtBbpk4/BzmLF/bSdvd4NI8i2XmQlP5fEUCo+zGPA==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
- "@aws-sdk/client-cognito-identity": "3.1039.0",
+ "@aws-sdk/client-cognito-identity": "3.1040.0",
"@aws-sdk/core": "^3.974.7",
"@aws-sdk/credential-provider-cognito-identity": "^3.972.30",
"@aws-sdk/credential-provider-env": "^3.972.33",
@@ -1119,6 +1119,30 @@
"node": ">=20.0.0"
}
},
+ "node_modules/@aws-sdk/dsql-signer": {
+ "version": "3.1040.0",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/dsql-signer/-/dsql-signer-3.1040.0.tgz",
+ "integrity": "sha512-8j19o9S88i7ZidWWZagJz/TLRMDX3sDauG+8oP3rgdR5R7QPfSW1s+gbRGc/WO27gD2UN0wsaJKnS9cVvTjv8g==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@aws-crypto/sha256-browser": "5.2.0",
+ "@aws-crypto/sha256-js": "5.2.0",
+ "@aws-sdk/credential-provider-node": "^3.972.38",
+ "@aws-sdk/util-format-url": "^3.972.10",
+ "@smithy/config-resolver": "^4.4.17",
+ "@smithy/hash-node": "^4.2.14",
+ "@smithy/invalid-dependency": "^4.2.14",
+ "@smithy/node-config-provider": "^4.3.14",
+ "@smithy/protocol-http": "^5.3.14",
+ "@smithy/signature-v4": "^5.3.14",
+ "@smithy/types": "^4.14.1",
+ "tslib": "^2.6.2"
+ },
+ "engines": {
+ "node": ">=20.0.0"
+ }
+ },
"node_modules/@aws-sdk/dynamodb-codec": {
"version": "3.973.7",
"resolved": "https://registry.npmjs.org/@aws-sdk/dynamodb-codec/-/dynamodb-codec-3.973.7.tgz",
@@ -1423,15 +1447,15 @@
}
},
"node_modules/@aws-sdk/rds-signer": {
- "version": "3.1039.0",
- "resolved": "https://registry.npmjs.org/@aws-sdk/rds-signer/-/rds-signer-3.1039.0.tgz",
- "integrity": "sha512-dmIZ5Fs92tsew4pmPjq9TeP6dnLrIasZHu4EfIlRKEzBXqqtV+kVEjfnhZsmRZNdm/kd3gVvO5nFaCg3C4TBLQ==",
+ "version": "3.1040.0",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/rds-signer/-/rds-signer-3.1040.0.tgz",
+ "integrity": "sha512-O5qQzhYKjm+8ARZRAdqTpZmbcaY35cNvjRAcJboBkLNyNgjZ5KLSc4vxgX/WqS7qo0b4qZYnXwdippdaMV01LQ==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
"@aws-crypto/sha256-browser": "5.2.0",
"@aws-crypto/sha256-js": "5.2.0",
- "@aws-sdk/credential-providers": "3.1039.0",
+ "@aws-sdk/credential-providers": "3.1040.0",
"@aws-sdk/util-format-url": "^3.972.10",
"@smithy/config-resolver": "^4.4.17",
"@smithy/hash-node": "^4.2.14",
@@ -1645,9 +1669,9 @@
}
},
"node_modules/@aws/durable-execution-sdk-js": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/@aws/durable-execution-sdk-js/-/durable-execution-sdk-js-1.1.1.tgz",
- "integrity": "sha512-ubuZu494xiZsIDjjZupGoVJwh8fSfeibZVp/4SjgejdXOetzd9w1V8AmB4bzAwcgsmhHbk3BPdg2cmvTebGBpA==",
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@aws/durable-execution-sdk-js/-/durable-execution-sdk-js-1.1.2.tgz",
+ "integrity": "sha512-STJU58rInEBfsPyUDtH/XIL8/jaCfpkTkx37EAwee7fFO1tdaXwInCmkOjxtIrImhSdkPJU8bRORKTij/N0I8A==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
@@ -1899,13 +1923,13 @@
}
},
"node_modules/@cloudflare/kv-asset-handler": {
- "version": "0.4.2",
- "resolved": "https://registry.npmjs.org/@cloudflare/kv-asset-handler/-/kv-asset-handler-0.4.2.tgz",
- "integrity": "sha512-SIOD2DxrRRwQ+jgzlXCqoEFiKOFqaPjhnNTGKXSRLvp1HiOvapLaFG2kEr9dYQTYe8rKrd9uvDUzmAITeNyaHQ==",
+ "version": "0.5.0",
+ "resolved": "https://registry.npmjs.org/@cloudflare/kv-asset-handler/-/kv-asset-handler-0.5.0.tgz",
+ "integrity": "sha512-jxQYkj8dSIzc0cD6cMMNdOc1UVjqSqu8BZdor5s8cGjW2I8BjODt/kWPVdY+u9zj3ms75Q5qaZgnxUad83+eAg==",
"dev": true,
"license": "MIT OR Apache-2.0",
"engines": {
- "node": ">=18.0.0"
+ "node": ">=22.0.0"
}
},
"node_modules/@cloudflare/unenv-preset": {
@@ -1925,9 +1949,9 @@
}
},
"node_modules/@cloudflare/workerd-darwin-64": {
- "version": "1.20260426.1",
- "resolved": "https://registry.npmjs.org/@cloudflare/workerd-darwin-64/-/workerd-darwin-64-1.20260426.1.tgz",
- "integrity": "sha512-Ch7DqsmYzSQRTY87pZpsGsFVz9VVBnLPnCBOHxKt1HH25a7oMu1w1PbPWqVmE0VerCLsj/TScX7Ob3v6E14TZw==",
+ "version": "1.20260430.1",
+ "resolved": "https://registry.npmjs.org/@cloudflare/workerd-darwin-64/-/workerd-darwin-64-1.20260430.1.tgz",
+ "integrity": "sha512-ADohZUHf7NBvPp2PdZig2Opxx+hDkk3ve7jrTne3JRx9kDSB73zc4LzcEeEN8LKkbAcqZmvfRJfpChSlusu0lA==",
"cpu": [
"x64"
],
@@ -1942,9 +1966,9 @@
}
},
"node_modules/@cloudflare/workerd-darwin-arm64": {
- "version": "1.20260426.1",
- "resolved": "https://registry.npmjs.org/@cloudflare/workerd-darwin-arm64/-/workerd-darwin-arm64-1.20260426.1.tgz",
- "integrity": "sha512-0m0U8vaPRH25SpKjbSyRql6gmPe4rCsETRV2WW0qBnuMdKNr5Vh5/Uez80xVrfiCCRMTULGeg63Nqg2vg6CDOA==",
+ "version": "1.20260430.1",
+ "resolved": "https://registry.npmjs.org/@cloudflare/workerd-darwin-arm64/-/workerd-darwin-arm64-1.20260430.1.tgz",
+ "integrity": "sha512-/DoYC/1wHs+YRZzzqSQg1/EHB4hiv1yV5U8FnmapRRIzVaPtnt+ApeOXeMrIdKidgKOI8TqQzgBU8xbIM7Cl4Q==",
"cpu": [
"arm64"
],
@@ -1959,9 +1983,9 @@
}
},
"node_modules/@cloudflare/workerd-linux-64": {
- "version": "1.20260426.1",
- "resolved": "https://registry.npmjs.org/@cloudflare/workerd-linux-64/-/workerd-linux-64-1.20260426.1.tgz",
- "integrity": "sha512-C8LlC8uSYzg49y51n++75esxZmMp+Uz1OKHHA/4lkv6rjOTbcHQJuEwSLppjybVIXpv7A8MBhbu9iyCTvyv1mw==",
+ "version": "1.20260430.1",
+ "resolved": "https://registry.npmjs.org/@cloudflare/workerd-linux-64/-/workerd-linux-64-1.20260430.1.tgz",
+ "integrity": "sha512-koJhBWvEVZPKCVFtMLp2iMHlYr+lFCF47wGbnlKdHVlemV0zTxJEyHI8aLlrhPLhBmOmYLp46rXw09/qJkRIhQ==",
"cpu": [
"x64"
],
@@ -1976,9 +2000,9 @@
}
},
"node_modules/@cloudflare/workerd-linux-arm64": {
- "version": "1.20260426.1",
- "resolved": "https://registry.npmjs.org/@cloudflare/workerd-linux-arm64/-/workerd-linux-arm64-1.20260426.1.tgz",
- "integrity": "sha512-ESVp/OIFMAqjQsa8BOP2BQQz5Vpfv6ncN6lNnIuNeOgsISQBdYk+LA60bwQHMud9tvmnSYtONp1zkZ8OQz+x6w==",
+ "version": "1.20260430.1",
+ "resolved": "https://registry.npmjs.org/@cloudflare/workerd-linux-arm64/-/workerd-linux-arm64-1.20260430.1.tgz",
+ "integrity": "sha512-hMdapNAzNQZDXGGkg4Slydc3fRJP5FUZLJVVcZCW/+imhhJro9Z1rv5n/wfR+txKoSWhTYR8eOp8Pyi2bzLzlw==",
"cpu": [
"arm64"
],
@@ -1993,9 +2017,9 @@
}
},
"node_modules/@cloudflare/workerd-windows-64": {
- "version": "1.20260426.1",
- "resolved": "https://registry.npmjs.org/@cloudflare/workerd-windows-64/-/workerd-windows-64-1.20260426.1.tgz",
- "integrity": "sha512-d3Xj/IjINRgNVwH+eKhpUn4xkkcEewbWXbOvBlapiirKWh5zl9m0Epi3qOqmjyRYK6MICqIGXg4qZBEt0lxudw==",
+ "version": "1.20260430.1",
+ "resolved": "https://registry.npmjs.org/@cloudflare/workerd-windows-64/-/workerd-windows-64-1.20260430.1.tgz",
+ "integrity": "sha512-jS3ffixjb5USOwz4frw4WzCz0HrjVxkgyU3WiYb06N7hBAfN6eOrveAJ4QRef0+suK4V1vQFoB1oKdRBsXe9Dw==",
"cpu": [
"x64"
],
@@ -2010,22 +2034,22 @@
}
},
"node_modules/@cloudflare/workers-types": {
- "version": "4.20260430.1",
- "resolved": "https://registry.npmjs.org/@cloudflare/workers-types/-/workers-types-4.20260430.1.tgz",
- "integrity": "sha512-Rguf/SdQNm1HG2yZi8m57K4qvVh2fic+Xny4UidY1pCgHagOAq7Cy0WIp1JKQx54T8lgOgOWFzIaCK4iwLpxlg==",
+ "version": "4.20260501.1",
+ "resolved": "https://registry.npmjs.org/@cloudflare/workers-types/-/workers-types-4.20260501.1.tgz",
+ "integrity": "sha512-B/VX2w3my/sCqxKyWOX7SxUpFC1uD8Gh7I2zbI1d3zA8p7Tx03AFsnuEx8lYLmcd8yONAA93YsAZb1wAaLK83w==",
"dev": true,
"license": "MIT OR Apache-2.0"
},
"node_modules/@commitlint/cli": {
- "version": "20.5.2",
- "resolved": "https://registry.npmjs.org/@commitlint/cli/-/cli-20.5.2.tgz",
- "integrity": "sha512-IXr5xd3IX8SEG936P8gcpozRplkDeDSwJlt8UvoY1winwIy2udTbQ/cOCgbaaxcjdDqVoS29VUcz/wkwnSozbA==",
+ "version": "20.5.3",
+ "resolved": "https://registry.npmjs.org/@commitlint/cli/-/cli-20.5.3.tgz",
+ "integrity": "sha512-OJdL0EXWD5y9LPa0nr/geOwzaS8BsdaybKkcloB0JgsguGxNv2R+hC2FTPqrAcprg35zF33KOQerY0x8W1aesA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@commitlint/format": "^20.5.0",
- "@commitlint/lint": "^20.5.0",
- "@commitlint/load": "^20.5.2",
+ "@commitlint/lint": "^20.5.3",
+ "@commitlint/load": "^20.5.3",
"@commitlint/read": "^20.5.0",
"@commitlint/types": "^20.5.0",
"tinyexec": "^1.0.0",
@@ -2039,9 +2063,9 @@
}
},
"node_modules/@commitlint/config-conventional": {
- "version": "20.5.0",
- "resolved": "https://registry.npmjs.org/@commitlint/config-conventional/-/config-conventional-20.5.0.tgz",
- "integrity": "sha512-t3Ni88rFw1XMa4nZHgOKJ8fIAT9M2j5TnKyTqJzsxea7FUetlNdYFus9dz+MhIRZmc16P0PPyEfh6X2d/qw8SA==",
+ "version": "20.5.3",
+ "resolved": "https://registry.npmjs.org/@commitlint/config-conventional/-/config-conventional-20.5.3.tgz",
+ "integrity": "sha512-j34Qqeaa152chJgz2ysyk0BCpHenJn1lV0Rx0VXf8k3ccQcED+48EZrzMvo9jLmJUyBrrBwvu89I+2er4gW7QQ==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -2067,18 +2091,14 @@
}
},
"node_modules/@commitlint/ensure": {
- "version": "20.5.0",
- "resolved": "https://registry.npmjs.org/@commitlint/ensure/-/ensure-20.5.0.tgz",
- "integrity": "sha512-IpHqAUesBeW1EDDdjzJeaOxU9tnogLAyXLRBn03SHlj1SGENn2JGZqSWGkFvBJkJzfXAuCNtsoYzax+ZPS+puw==",
+ "version": "20.5.3",
+ "resolved": "https://registry.npmjs.org/@commitlint/ensure/-/ensure-20.5.3.tgz",
+ "integrity": "sha512-4i4AgNvH62owG9MwSiWKrle7HGNpBHHdLnWFIp5fTsHUYe5kRuh15t08L/0pdbbrRk8JKXQxxN4hZQcn+szkrw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@commitlint/types": "^20.5.0",
- "lodash.camelcase": "^4.3.0",
- "lodash.kebabcase": "^4.1.1",
- "lodash.snakecase": "^4.1.1",
- "lodash.startcase": "^4.4.0",
- "lodash.upperfirst": "^4.3.1"
+ "es-toolkit": "^1.46.0"
},
"engines": {
"node": ">=v18"
@@ -2123,15 +2143,15 @@
}
},
"node_modules/@commitlint/lint": {
- "version": "20.5.0",
- "resolved": "https://registry.npmjs.org/@commitlint/lint/-/lint-20.5.0.tgz",
- "integrity": "sha512-jiM3hNUdu04jFBf1VgPdjtIPvbuVfDTBAc6L98AWcoLjF5sYqkulBHBzlVWll4rMF1T5zeQFB6r//a+s+BBKlA==",
+ "version": "20.5.3",
+ "resolved": "https://registry.npmjs.org/@commitlint/lint/-/lint-20.5.3.tgz",
+ "integrity": "sha512-M7JbWBNr2gXKaPc4i/KipsuW1gkDHpj35KPjWtKy3Z+2AQw5wu1gBi1LIO0uoaij67CqY4K8PxPZSGens4evCw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@commitlint/is-ignored": "^20.5.0",
"@commitlint/parse": "^20.5.0",
- "@commitlint/rules": "^20.5.0",
+ "@commitlint/rules": "^20.5.3",
"@commitlint/types": "^20.5.0"
},
"engines": {
@@ -2139,20 +2159,20 @@
}
},
"node_modules/@commitlint/load": {
- "version": "20.5.2",
- "resolved": "https://registry.npmjs.org/@commitlint/load/-/load-20.5.2.tgz",
- "integrity": "sha512-zmr0RGDz7vThxW1I8ohb9yBjnGuH9mqwJpn21hInjGla+IlLOkS9ey0+dD5HlkzFlY0lX2NYdA2lDW6/0rO7Gw==",
+ "version": "20.5.3",
+ "resolved": "https://registry.npmjs.org/@commitlint/load/-/load-20.5.3.tgz",
+ "integrity": "sha512-1FDZWuKyu98Myb8i7Tp31jPU2rZpOwAdYRyJcy2KoGg7Xk2A+bgHN8smhMaaNSNkmE8fwt53BokywZq8Gv/5XQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@commitlint/config-validator": "^20.5.0",
"@commitlint/execute-rule": "^20.0.0",
- "@commitlint/resolve-extends": "^20.5.2",
+ "@commitlint/resolve-extends": "^20.5.3",
"@commitlint/types": "^20.5.0",
"cosmiconfig": "^9.0.1",
"cosmiconfig-typescript-loader": "^6.1.0",
+ "es-toolkit": "^1.46.0",
"is-plain-obj": "^4.1.0",
- "lodash.mergewith": "^4.6.2",
"picocolors": "^1.1.1"
},
"engines": {
@@ -2202,17 +2222,17 @@
}
},
"node_modules/@commitlint/resolve-extends": {
- "version": "20.5.2",
- "resolved": "https://registry.npmjs.org/@commitlint/resolve-extends/-/resolve-extends-20.5.2.tgz",
- "integrity": "sha512-8EhSCU9eNos/5cI1yg64GW79UH1c64O69AfStCsj4zqy6An/qIphVEXj4/+2M6056T8coz00f+UXFn4WUUP1HQ==",
+ "version": "20.5.3",
+ "resolved": "https://registry.npmjs.org/@commitlint/resolve-extends/-/resolve-extends-20.5.3.tgz",
+ "integrity": "sha512-+ogW9v/u9JqpvAgTrLra/YTFo0KkjU6iNblF89pPsj4NebNc+DAWctsludwezI8YnsjBmfHpApSwcXprN/f/ew==",
"dev": true,
"license": "MIT",
"dependencies": {
"@commitlint/config-validator": "^20.5.0",
"@commitlint/types": "^20.5.0",
+ "es-toolkit": "^1.46.0",
"global-directory": "^5.0.0",
"import-meta-resolve": "^4.0.0",
- "lodash.mergewith": "^4.6.2",
"resolve-from": "^5.0.0"
},
"engines": {
@@ -2220,13 +2240,13 @@
}
},
"node_modules/@commitlint/rules": {
- "version": "20.5.0",
- "resolved": "https://registry.npmjs.org/@commitlint/rules/-/rules-20.5.0.tgz",
- "integrity": "sha512-5NdQXQEdnDPT5pK8O39ZA7HohzPRHEsDGU23cyVCNPQy4WegAbAwrQk3nIu7p2sl3dutPk8RZd91yKTrMTnRkQ==",
+ "version": "20.5.3",
+ "resolved": "https://registry.npmjs.org/@commitlint/rules/-/rules-20.5.3.tgz",
+ "integrity": "sha512-MPlMnb9D3wbszYMp+1hPtuhtPJndRo6I6yfkZVA4+jR8w7Kqp0u2u/Y+gzbaItx5Lltq5rw7FSZQWJMoXUC4NQ==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@commitlint/ensure": "^20.5.0",
+ "@commitlint/ensure": "^20.5.3",
"@commitlint/message": "^20.4.3",
"@commitlint/to-lines": "^20.0.0",
"@commitlint/types": "^20.5.0"
@@ -3534,6 +3554,10 @@
"resolved": "packages/do-not-wait-for-empty-event-loop",
"link": true
},
+ "node_modules/@middy/dsql-signer": {
+ "resolved": "packages/dsql-signer",
+ "link": true
+ },
"node_modules/@middy/dynamodb": {
"resolved": "packages/dynamodb",
"link": true
@@ -6334,9 +6358,9 @@
}
},
"node_modules/devalue": {
- "version": "5.7.1",
- "resolved": "https://registry.npmjs.org/devalue/-/devalue-5.7.1.tgz",
- "integrity": "sha512-MUbZ586EgQqdRnC4yDrlod3BEdyvE4TapGYHMW2CiaW+KkkFmWEFqBUaLltEZCGi0iFXCEjRF0OjF0DV2QHjOA==",
+ "version": "5.8.0",
+ "resolved": "https://registry.npmjs.org/devalue/-/devalue-5.8.0.tgz",
+ "integrity": "sha512-2zA9pFEsnp7vWBZbXF5JAgAq0fsUIt/1XPbRiAmRV3lp/2C3upzH+sADiyy66aFCihoLEsrQHxNM5w1gIDfsBg==",
"license": "MIT"
},
"node_modules/diff": {
@@ -6570,6 +6594,17 @@
"url": "https://github.com/sponsors/antfu"
}
},
+ "node_modules/es-toolkit": {
+ "version": "1.46.1",
+ "resolved": "https://registry.npmjs.org/es-toolkit/-/es-toolkit-1.46.1.tgz",
+ "integrity": "sha512-5eNtXOs3tbfxXOj04tjjseeWkRWaoCjdEI+96DgwzZoe6c9juL49pXlzAFTI72aWC9Y8p7168g6XIKjh7k6pyQ==",
+ "dev": true,
+ "license": "MIT",
+ "workspaces": [
+ "docs",
+ "benchmarks"
+ ]
+ },
"node_modules/esbuild": {
"version": "0.28.0",
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.0.tgz",
@@ -8005,48 +8040,6 @@
"dev": true,
"license": "MIT"
},
- "node_modules/lodash.camelcase": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz",
- "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/lodash.kebabcase": {
- "version": "4.1.1",
- "resolved": "https://registry.npmjs.org/lodash.kebabcase/-/lodash.kebabcase-4.1.1.tgz",
- "integrity": "sha512-N8XRTIMMqqDgSy4VLKPnJ/+hpGZN+PHQiJnSenYqPaVV/NCqEogTnAdZLQiGKhxX+JCs8waWq2t1XHWKOmlY8g==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/lodash.mergewith": {
- "version": "4.6.2",
- "resolved": "https://registry.npmjs.org/lodash.mergewith/-/lodash.mergewith-4.6.2.tgz",
- "integrity": "sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/lodash.snakecase": {
- "version": "4.1.1",
- "resolved": "https://registry.npmjs.org/lodash.snakecase/-/lodash.snakecase-4.1.1.tgz",
- "integrity": "sha512-QZ1d4xoBHYUeuouhEq3lk3Uq7ldgyFXGBhg04+oRLnIz8o9T65Eh+8YdroUwn846zchkA9yDsDl5CVVaV2nqYw==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/lodash.startcase": {
- "version": "4.4.0",
- "resolved": "https://registry.npmjs.org/lodash.startcase/-/lodash.startcase-4.4.0.tgz",
- "integrity": "sha512-+WKqsK294HMSc2jEbNgpHpd0JfIBhp7rEV4aqXWqFr6AlXov+SlcgB1Fv01y2kGe3Gc8nMW7VA0SrGuSkRfIEg==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/lodash.upperfirst": {
- "version": "4.3.1",
- "resolved": "https://registry.npmjs.org/lodash.upperfirst/-/lodash.upperfirst-4.3.1.tgz",
- "integrity": "sha512-sReKOYJIJf74dhJONhU4e0/shzi1trVbSWDOhKYE5XV2O+H7Sb2Dihwuc7xWxVl+DgFPyTqIN3zMfT9cq5iWDg==",
- "dev": true,
- "license": "MIT"
- },
"node_modules/lru-cache": {
"version": "10.4.3",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz",
@@ -8173,16 +8166,16 @@
"link": true
},
"node_modules/miniflare": {
- "version": "4.20260426.0",
- "resolved": "https://registry.npmjs.org/miniflare/-/miniflare-4.20260426.0.tgz",
- "integrity": "sha512-KM+v76d04qT+NsPfVKVQEgnnuLNE3uzCCl2QKMTJ5OXor5JbBm1vpkQwQ+l7o5ELCrZ74RnyKhJKLiJyUA39Tw==",
+ "version": "4.20260430.0",
+ "resolved": "https://registry.npmjs.org/miniflare/-/miniflare-4.20260430.0.tgz",
+ "integrity": "sha512-MWvMm3Siho9Yj7lbJZidLs8hbrRvIcOrif2mnsHQZdvoKfedpea+GaN8XJxbpRcq0B2WzNI1BB1ihdnqes3/ZA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@cspotcode/source-map-support": "0.8.1",
"sharp": "^0.34.5",
"undici": "7.24.8",
- "workerd": "1.20260426.1",
+ "workerd": "1.20260430.1",
"ws": "8.18.0",
"youch": "4.1.0-beta.10"
},
@@ -8190,7 +8183,7 @@
"miniflare": "bootstrap.js"
},
"engines": {
- "node": ">=18.0.0"
+ "node": ">=22.0.0"
}
},
"node_modules/miniflare/node_modules/undici": {
@@ -8269,9 +8262,9 @@
"license": "MIT"
},
"node_modules/nanoid": {
- "version": "3.3.11",
- "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz",
- "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==",
+ "version": "3.3.12",
+ "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.12.tgz",
+ "integrity": "sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==",
"dev": true,
"funding": [
{
@@ -8708,9 +8701,9 @@
}
},
"node_modules/postcss": {
- "version": "8.5.12",
- "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.12.tgz",
- "integrity": "sha512-W62t/Se6rA0Az3DfCL0AqJwXuKwBeYg6nOaIgzP+xZ7N5BFCI7DYi1qs6ygUYT6rvfi6t9k65UMLJC+PHZpDAA==",
+ "version": "8.5.13",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.13.tgz",
+ "integrity": "sha512-qif0+jGGZoLWdHey3UFHHWP0H7Gbmsk8T5VEqyYFbWqPr1XqvLGBbk/sl8V5exGmcYJklJOhOQq1pV9IcsiFag==",
"dev": true,
"funding": [
{
@@ -10012,9 +10005,9 @@
"license": "ISC"
},
"node_modules/workerd": {
- "version": "1.20260426.1",
- "resolved": "https://registry.npmjs.org/workerd/-/workerd-1.20260426.1.tgz",
- "integrity": "sha512-ELvGgN8c9oo+E6EPyecxk1TEf6/eAK4TxxQTW5mQ87C7jbjCzhMbg0P2ije49UBHV0dkBYPJcJvcklUltipl2A==",
+ "version": "1.20260430.1",
+ "resolved": "https://registry.npmjs.org/workerd/-/workerd-1.20260430.1.tgz",
+ "integrity": "sha512-KEgIWyiw3Jmn+DCd/L3ePo5fmiiYb/UcwKvDWPf/nLLOiwShDFzDSsegU5NY/JcwgvO/QsLHVi2FYrbkcXNY5Q==",
"dev": true,
"hasInstallScript": true,
"license": "Apache-2.0",
@@ -10025,11 +10018,11 @@
"node": ">=16"
},
"optionalDependencies": {
- "@cloudflare/workerd-darwin-64": "1.20260426.1",
- "@cloudflare/workerd-darwin-arm64": "1.20260426.1",
- "@cloudflare/workerd-linux-64": "1.20260426.1",
- "@cloudflare/workerd-linux-arm64": "1.20260426.1",
- "@cloudflare/workerd-windows-64": "1.20260426.1"
+ "@cloudflare/workerd-darwin-64": "1.20260430.1",
+ "@cloudflare/workerd-darwin-arm64": "1.20260430.1",
+ "@cloudflare/workerd-linux-64": "1.20260430.1",
+ "@cloudflare/workerd-linux-arm64": "1.20260430.1",
+ "@cloudflare/workerd-windows-64": "1.20260430.1"
}
},
"node_modules/worktop": {
@@ -10047,33 +10040,33 @@
}
},
"node_modules/wrangler": {
- "version": "4.86.0",
- "resolved": "https://registry.npmjs.org/wrangler/-/wrangler-4.86.0.tgz",
- "integrity": "sha512-9aa/gbF/HiUeeUEwyQpW5LDPBEzyt7iaE6xHwm0vk2Ly8A6J+jh03pzchqVnCCWR832mNyA28MD8oAYt0Kfvlw==",
+ "version": "4.87.0",
+ "resolved": "https://registry.npmjs.org/wrangler/-/wrangler-4.87.0.tgz",
+ "integrity": "sha512-lfhfKwLfQlowwgV0xhlYgE9fU3n0I30d4ccGY/rTCEm/n42Mjvlr0Ng3ZPNqlsrsKBcDR531V7dsPkgELvrk/Q==",
"dev": true,
"license": "MIT OR Apache-2.0",
"dependencies": {
- "@cloudflare/kv-asset-handler": "0.4.2",
+ "@cloudflare/kv-asset-handler": "0.5.0",
"@cloudflare/unenv-preset": "2.16.1",
"blake3-wasm": "2.1.5",
"esbuild": "0.27.3",
- "miniflare": "4.20260426.0",
+ "miniflare": "4.20260430.0",
"path-to-regexp": "6.3.0",
"unenv": "2.0.0-rc.24",
- "workerd": "1.20260426.1"
+ "workerd": "1.20260430.1"
},
"bin": {
"wrangler": "bin/wrangler.js",
"wrangler2": "bin/wrangler.js"
},
"engines": {
- "node": ">=20.3.0"
+ "node": ">=22.0.0"
},
"optionalDependencies": {
"fsevents": "~2.3.2"
},
"peerDependencies": {
- "@cloudflare/workers-types": "^4.20260426.1"
+ "@cloudflare/workers-types": "^4.20260430.1"
},
"peerDependenciesMeta": {
"@cloudflare/workers-types": {
@@ -10733,14 +10726,14 @@
},
"packages/appconfig": {
"name": "@middy/appconfig",
- "version": "7.3.4",
+ "version": "7.4.0",
"license": "MIT",
"dependencies": {
- "@middy/util": "7.3.4"
+ "@middy/util": "7.4.0"
},
"devDependencies": {
"@aws-sdk/client-appconfigdata": "^3.0.0",
- "@middy/core": "7.3.4",
+ "@middy/core": "7.4.0",
"@types/aws-lambda": "^8.0.0",
"@types/node": "^22.0.0",
"aws-xray-sdk": "^3.3.3"
@@ -10780,10 +10773,10 @@
},
"packages/cloudformation-response": {
"name": "@middy/cloudformation-response",
- "version": "7.3.4",
+ "version": "7.4.0",
"license": "MIT",
"devDependencies": {
- "@middy/core": "7.3.4",
+ "@middy/core": "7.4.0",
"@types/aws-lambda": "^8.0.0",
"@types/node": "^22.0.0"
},
@@ -10814,10 +10807,10 @@
},
"packages/cloudformation-router": {
"name": "@middy/cloudformation-router",
- "version": "7.3.4",
+ "version": "7.4.0",
"license": "MIT",
"devDependencies": {
- "@middy/core": "7.3.4",
+ "@middy/core": "7.4.0",
"@types/aws-lambda": "^8.0.0",
"@types/node": "^22.0.0"
},
@@ -10848,13 +10841,13 @@
},
"packages/cloudwatch-metrics": {
"name": "@middy/cloudwatch-metrics",
- "version": "7.3.4",
+ "version": "7.4.0",
"license": "MIT",
"dependencies": {
"aws-embedded-metrics": "4.2.1"
},
"devDependencies": {
- "@middy/core": "7.3.4",
+ "@middy/core": "7.4.0",
"@types/aws-lambda": "^8.0.0",
"@types/node": "^22.0.0"
},
@@ -10885,10 +10878,10 @@
},
"packages/core": {
"name": "@middy/core",
- "version": "7.3.4",
+ "version": "7.4.0",
"license": "MIT",
"dependencies": {
- "@middy/util": "7.3.4"
+ "@middy/util": "7.4.0"
},
"devDependencies": {
"@aws/durable-execution-sdk-js": "^1.0.0",
@@ -10932,13 +10925,13 @@
},
"packages/do-not-wait-for-empty-event-loop": {
"name": "@middy/do-not-wait-for-empty-event-loop",
- "version": "7.3.4",
+ "version": "7.4.0",
"license": "MIT",
"dependencies": {
- "@middy/util": "7.3.4"
+ "@middy/util": "7.4.0"
},
"devDependencies": {
- "@middy/core": "7.3.4",
+ "@middy/core": "7.4.0",
"@types/aws-lambda": "^8.0.0",
"@types/node": "^22.0.0"
},
@@ -10967,17 +10960,64 @@
"dev": true,
"license": "MIT"
},
+ "packages/dsql-signer": {
+ "name": "@middy/dsql-signer",
+ "version": "7.4.0",
+ "license": "MIT",
+ "dependencies": {
+ "@middy/util": "7.4.0"
+ },
+ "devDependencies": {
+ "@aws-sdk/dsql-signer": "^3.0.0",
+ "@middy/core": "7.4.0",
+ "@types/aws-lambda": "^8.0.0",
+ "@types/node": "^22.0.0",
+ "aws-xray-sdk": "^3.3.3"
+ },
+ "engines": {
+ "node": ">=22"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/willfarrell"
+ },
+ "peerDependencies": {
+ "@aws-sdk/dsql-signer": "^3.0.0"
+ },
+ "peerDependenciesMeta": {
+ "@aws-sdk/dsql-signer": {
+ "optional": true
+ }
+ }
+ },
+ "packages/dsql-signer/node_modules/@types/node": {
+ "version": "22.19.17",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-22.19.17.tgz",
+ "integrity": "sha512-wGdMcf+vPYM6jikpS/qhg6WiqSV/OhG+jeeHT/KlVqxYfD40iYJf9/AE1uQxVWFvU7MipKRkRv8NSHiCGgPr8Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "undici-types": "~6.21.0"
+ }
+ },
+ "packages/dsql-signer/node_modules/undici-types": {
+ "version": "6.21.0",
+ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz",
+ "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==",
+ "dev": true,
+ "license": "MIT"
+ },
"packages/dynamodb": {
"name": "@middy/dynamodb",
- "version": "7.3.4",
+ "version": "7.4.0",
"license": "MIT",
"dependencies": {
- "@middy/util": "7.3.4"
+ "@middy/util": "7.4.0"
},
"devDependencies": {
"@aws-sdk/client-dynamodb": "^3.0.0",
"@aws-sdk/util-dynamodb": "^3.0.0",
- "@middy/core": "7.3.4",
+ "@middy/core": "7.4.0",
"@types/aws-lambda": "^8.0.0",
"@types/node": "^22.0.0",
"aws-xray-sdk": "^3.3.3"
@@ -11021,10 +11061,10 @@
},
"packages/error-logger": {
"name": "@middy/error-logger",
- "version": "7.3.4",
+ "version": "7.4.0",
"license": "MIT",
"devDependencies": {
- "@middy/core": "7.3.4",
+ "@middy/core": "7.4.0",
"@types/aws-lambda": "^8.0.0",
"@types/node": "^22.0.0"
},
@@ -11055,13 +11095,13 @@
},
"packages/event-normalizer": {
"name": "@middy/event-normalizer",
- "version": "7.3.4",
+ "version": "7.4.0",
"license": "MIT",
"dependencies": {
- "@middy/util": "7.3.4"
+ "@middy/util": "7.4.0"
},
"devDependencies": {
- "@middy/core": "7.3.4",
+ "@middy/core": "7.4.0",
"@serverless/event-mocks": "^1.1.1",
"@types/aws-lambda": "^8.0.0",
"@types/node": "^22.0.0"
@@ -11093,14 +11133,14 @@
},
"packages/http-content-encoding": {
"name": "@middy/http-content-encoding",
- "version": "7.3.4",
+ "version": "7.4.0",
"license": "MIT",
"dependencies": {
- "@middy/util": "7.3.4"
+ "@middy/util": "7.4.0"
},
"devDependencies": {
"@datastream/core": "0.4.0",
- "@middy/core": "7.3.4",
+ "@middy/core": "7.4.0",
"@types/aws-lambda": "^8.0.0",
"@types/node": "^22.0.0"
},
@@ -11131,14 +11171,14 @@
},
"packages/http-content-negotiation": {
"name": "@middy/http-content-negotiation",
- "version": "7.3.4",
+ "version": "7.4.0",
"license": "MIT",
"dependencies": {
- "@middy/util": "7.3.4",
+ "@middy/util": "7.4.0",
"negotiator": "1.0.0"
},
"devDependencies": {
- "@middy/core": "7.3.4",
+ "@middy/core": "7.4.0",
"@types/aws-lambda": "^8.0.0",
"@types/node": "^22.0.0"
},
@@ -11169,13 +11209,13 @@
},
"packages/http-cors": {
"name": "@middy/http-cors",
- "version": "7.3.4",
+ "version": "7.4.0",
"license": "MIT",
"dependencies": {
- "@middy/util": "7.3.4"
+ "@middy/util": "7.4.0"
},
"devDependencies": {
- "@middy/core": "7.3.4",
+ "@middy/core": "7.4.0",
"@types/aws-lambda": "^8.0.0",
"@types/node": "^22.0.0"
},
@@ -11206,13 +11246,13 @@
},
"packages/http-error-handler": {
"name": "@middy/http-error-handler",
- "version": "7.3.4",
+ "version": "7.4.0",
"license": "MIT",
"dependencies": {
- "@middy/util": "7.3.4"
+ "@middy/util": "7.4.0"
},
"devDependencies": {
- "@middy/core": "7.3.4",
+ "@middy/core": "7.4.0",
"@types/http-errors": "^2.0.0",
"@types/node": "^22.0.0"
},
@@ -11243,10 +11283,10 @@
},
"packages/http-event-normalizer": {
"name": "@middy/http-event-normalizer",
- "version": "7.3.4",
+ "version": "7.4.0",
"license": "MIT",
"devDependencies": {
- "@middy/core": "7.3.4",
+ "@middy/core": "7.4.0",
"@types/aws-lambda": "^8.0.0",
"@types/node": "^22.0.0"
},
@@ -11277,10 +11317,10 @@
},
"packages/http-header-normalizer": {
"name": "@middy/http-header-normalizer",
- "version": "7.3.4",
+ "version": "7.4.0",
"license": "MIT",
"devDependencies": {
- "@middy/core": "7.3.4",
+ "@middy/core": "7.4.0",
"@types/node": "^22.0.0"
},
"engines": {
@@ -11310,13 +11350,13 @@
},
"packages/http-json-body-parser": {
"name": "@middy/http-json-body-parser",
- "version": "7.3.4",
+ "version": "7.4.0",
"license": "MIT",
"dependencies": {
- "@middy/util": "7.3.4"
+ "@middy/util": "7.4.0"
},
"devDependencies": {
- "@middy/core": "7.3.4",
+ "@middy/core": "7.4.0",
"@types/aws-lambda": "^8.0.0",
"@types/node": "^22.0.0",
"type-fest": "^5.0.0"
@@ -11348,14 +11388,14 @@
},
"packages/http-multipart-body-parser": {
"name": "@middy/http-multipart-body-parser",
- "version": "7.3.4",
+ "version": "7.4.0",
"license": "MIT",
"dependencies": {
"@fastify/busboy": "3.2.0",
- "@middy/util": "7.3.4"
+ "@middy/util": "7.4.0"
},
"devDependencies": {
- "@middy/core": "7.3.4",
+ "@middy/core": "7.4.0",
"@types/aws-lambda": "^8.0.0",
"@types/node": "^22.0.0",
"type-fest": "^5.0.0"
@@ -11387,14 +11427,14 @@
},
"packages/http-partial-response": {
"name": "@middy/http-partial-response",
- "version": "7.3.4",
+ "version": "7.4.0",
"license": "MIT",
"dependencies": {
- "@middy/util": "7.3.4",
+ "@middy/util": "7.4.0",
"json-mask": "2.0.0"
},
"devDependencies": {
- "@middy/core": "7.3.4",
+ "@middy/core": "7.4.0",
"@types/aws-lambda": "^8.0.0",
"@types/node": "^22.0.0"
},
@@ -11425,13 +11465,13 @@
},
"packages/http-response-serializer": {
"name": "@middy/http-response-serializer",
- "version": "7.3.4",
+ "version": "7.4.0",
"license": "MIT",
"dependencies": {
- "@middy/util": "7.3.4"
+ "@middy/util": "7.4.0"
},
"devDependencies": {
- "@middy/core": "7.3.4",
+ "@middy/core": "7.4.0",
"@types/aws-lambda": "^8.0.0",
"@types/node": "^22.0.0"
},
@@ -11462,13 +11502,13 @@
},
"packages/http-router": {
"name": "@middy/http-router",
- "version": "7.3.4",
+ "version": "7.4.0",
"license": "MIT",
"dependencies": {
- "@middy/util": "7.3.4"
+ "@middy/util": "7.4.0"
},
"devDependencies": {
- "@middy/core": "7.3.4",
+ "@middy/core": "7.4.0",
"@types/aws-lambda": "^8.0.0",
"@types/node": "^22.0.0"
},
@@ -11499,13 +11539,13 @@
},
"packages/http-security-headers": {
"name": "@middy/http-security-headers",
- "version": "7.3.4",
+ "version": "7.4.0",
"license": "MIT",
"dependencies": {
- "@middy/util": "7.3.4"
+ "@middy/util": "7.4.0"
},
"devDependencies": {
- "@middy/core": "7.3.4",
+ "@middy/core": "7.4.0",
"@types/aws-lambda": "^8.0.0",
"@types/node": "^22.0.0"
},
@@ -11536,13 +11576,13 @@
},
"packages/http-urlencode-body-parser": {
"name": "@middy/http-urlencode-body-parser",
- "version": "7.3.4",
+ "version": "7.4.0",
"license": "MIT",
"dependencies": {
- "@middy/util": "7.3.4"
+ "@middy/util": "7.4.0"
},
"devDependencies": {
- "@middy/core": "7.3.4",
+ "@middy/core": "7.4.0",
"@types/aws-lambda": "^8.0.0",
"@types/node": "^22.0.0",
"type-fest": "^5.0.0"
@@ -11574,13 +11614,13 @@
},
"packages/http-urlencode-path-parser": {
"name": "@middy/http-urlencode-path-parser",
- "version": "7.3.4",
+ "version": "7.4.0",
"license": "MIT",
"dependencies": {
- "@middy/util": "7.3.4"
+ "@middy/util": "7.4.0"
},
"devDependencies": {
- "@middy/core": "7.3.4",
+ "@middy/core": "7.4.0",
"@types/aws-lambda": "^8.0.0",
"@types/node": "^22.0.0",
"type-fest": "^5.0.0"
@@ -11612,14 +11652,14 @@
},
"packages/input-output-logger": {
"name": "@middy/input-output-logger",
- "version": "7.3.4",
+ "version": "7.4.0",
"license": "MIT",
"dependencies": {
- "@middy/util": "7.3.4"
+ "@middy/util": "7.4.0"
},
"devDependencies": {
"@datastream/core": "0.4.0",
- "@middy/core": "7.3.4",
+ "@middy/core": "7.4.0",
"@types/aws-lambda": "^8.0.0",
"@types/node": "^22.0.0"
},
@@ -11650,14 +11690,14 @@
},
"packages/rds-signer": {
"name": "@middy/rds-signer",
- "version": "7.3.4",
+ "version": "7.4.0",
"license": "MIT",
"dependencies": {
- "@middy/util": "7.3.4"
+ "@middy/util": "7.4.0"
},
"devDependencies": {
"@aws-sdk/rds-signer": "^3.0.0",
- "@middy/core": "7.3.4",
+ "@middy/core": "7.4.0",
"@types/aws-lambda": "^8.0.0",
"@types/node": "^22.0.0",
"aws-xray-sdk": "^3.3.3"
@@ -11697,14 +11737,14 @@
},
"packages/s3": {
"name": "@middy/s3",
- "version": "7.3.4",
+ "version": "7.4.0",
"license": "MIT",
"dependencies": {
- "@middy/util": "7.3.4"
+ "@middy/util": "7.4.0"
},
"devDependencies": {
"@aws-sdk/client-s3": "^3.0.0",
- "@middy/core": "7.3.4",
+ "@middy/core": "7.4.0",
"@types/aws-lambda": "^8.0.0",
"@types/node": "^22.0.0",
"aws-xray-sdk": "^3.3.3"
@@ -11727,14 +11767,14 @@
},
"packages/s3-object-response": {
"name": "@middy/s3-object-response",
- "version": "7.3.4",
+ "version": "7.4.0",
"license": "MIT",
"dependencies": {
- "@middy/util": "7.3.4"
+ "@middy/util": "7.4.0"
},
"devDependencies": {
"@aws-sdk/client-s3": "^3.0.0",
- "@middy/core": "7.3.4",
+ "@middy/core": "7.4.0",
"@types/aws-lambda": "^8.0.0",
"@types/node": "^22.0.0",
"aws-xray-sdk": "^3.3.3"
@@ -11791,14 +11831,14 @@
},
"packages/secrets-manager": {
"name": "@middy/secrets-manager",
- "version": "7.3.4",
+ "version": "7.4.0",
"license": "MIT",
"dependencies": {
- "@middy/util": "7.3.4"
+ "@middy/util": "7.4.0"
},
"devDependencies": {
"@aws-sdk/client-secrets-manager": "^3.0.0",
- "@middy/core": "7.3.4",
+ "@middy/core": "7.4.0",
"@types/aws-lambda": "^8.0.0",
"@types/node": "^22.0.0",
"aws-xray-sdk": "^3.3.3"
@@ -11838,14 +11878,14 @@
},
"packages/service-discovery": {
"name": "@middy/service-discovery",
- "version": "7.3.4",
+ "version": "7.4.0",
"license": "MIT",
"dependencies": {
- "@middy/util": "7.3.4"
+ "@middy/util": "7.4.0"
},
"devDependencies": {
"@aws-sdk/client-servicediscovery": "^3.0.0",
- "@middy/core": "7.3.4",
+ "@middy/core": "7.4.0",
"@types/aws-lambda": "^8.0.0",
"@types/node": "^22.0.0",
"aws-xray-sdk": "^3.3.3"
@@ -11885,11 +11925,11 @@
},
"packages/sqs-partial-batch-failure": {
"name": "@middy/sqs-partial-batch-failure",
- "version": "7.3.4",
+ "version": "7.4.0",
"license": "MIT",
"devDependencies": {
"@aws-sdk/client-sqs": "^3.0.0",
- "@middy/core": "7.3.4",
+ "@middy/core": "7.4.0",
"@serverless/event-mocks": "^1.1.1",
"@types/aws-lambda": "^8.0.0",
"@types/node": "^22.0.0"
@@ -11921,14 +11961,14 @@
},
"packages/ssm": {
"name": "@middy/ssm",
- "version": "7.3.4",
+ "version": "7.4.0",
"license": "MIT",
"dependencies": {
- "@middy/util": "7.3.4"
+ "@middy/util": "7.4.0"
},
"devDependencies": {
"@aws-sdk/client-ssm": "^3.0.0",
- "@middy/core": "7.3.4",
+ "@middy/core": "7.4.0",
"@types/aws-lambda": "^8.0.0",
"@types/node": "^22.0.0",
"aws-xray-sdk": "^3.3.3"
@@ -11968,14 +12008,14 @@
},
"packages/sts": {
"name": "@middy/sts",
- "version": "7.3.4",
+ "version": "7.4.0",
"license": "MIT",
"dependencies": {
- "@middy/util": "7.3.4"
+ "@middy/util": "7.4.0"
},
"devDependencies": {
"@aws-sdk/client-sts": "^3.0.0",
- "@middy/core": "7.3.4",
+ "@middy/core": "7.4.0",
"@types/aws-lambda": "^8.0.0",
"@types/node": "^22.0.0",
"aws-xray-sdk": "^3.3.3"
@@ -12015,11 +12055,11 @@
},
"packages/util": {
"name": "@middy/util",
- "version": "7.3.4",
+ "version": "7.4.0",
"license": "MIT",
"devDependencies": {
"@aws-sdk/client-ssm": "^3.0.0",
- "@middy/core": "7.3.4",
+ "@middy/core": "7.4.0",
"@types/aws-lambda": "^8.0.0",
"@types/node": "^22.0.0",
"aws-xray-sdk": "^3.3.3"
@@ -12051,10 +12091,10 @@
},
"packages/validator": {
"name": "@middy/validator",
- "version": "7.3.4",
+ "version": "7.4.0",
"license": "MIT",
"dependencies": {
- "@middy/util": "7.3.4",
+ "@middy/util": "7.4.0",
"@silverbucket/ajv-formats-draft2019": "1.6.5",
"ajv": "8.20.0",
"ajv-errors": "3.0.0",
@@ -12063,7 +12103,7 @@
"ajv-keywords": "5.1.0"
},
"devDependencies": {
- "@middy/core": "7.3.4",
+ "@middy/core": "7.4.0",
"@types/aws-lambda": "^8.0.0",
"@types/http-errors": "^2.0.0",
"@types/node": "^22.0.0",
@@ -12097,10 +12137,10 @@
},
"packages/warmup": {
"name": "@middy/warmup",
- "version": "7.3.4",
+ "version": "7.4.0",
"license": "MIT",
"devDependencies": {
- "@middy/core": "7.3.4",
+ "@middy/core": "7.4.0",
"@types/aws-lambda": "^8.0.0",
"@types/node": "^22.0.0"
},
@@ -12131,13 +12171,13 @@
},
"packages/ws-json-body-parser": {
"name": "@middy/ws-json-body-parser",
- "version": "7.3.4",
+ "version": "7.4.0",
"license": "MIT",
"dependencies": {
- "@middy/util": "7.3.4"
+ "@middy/util": "7.4.0"
},
"devDependencies": {
- "@middy/core": "7.3.4",
+ "@middy/core": "7.4.0",
"@types/aws-lambda": "^8.0.0",
"@types/node": "^22.0.0",
"type-fest": "^5.0.0"
@@ -12169,14 +12209,14 @@
},
"packages/ws-response": {
"name": "@middy/ws-response",
- "version": "7.3.4",
+ "version": "7.4.0",
"license": "MIT",
"dependencies": {
- "@middy/util": "7.3.4"
+ "@middy/util": "7.4.0"
},
"devDependencies": {
"@aws-sdk/client-apigatewaymanagementapi": "^3.0.0",
- "@middy/core": "7.3.4",
+ "@middy/core": "7.4.0",
"@types/aws-lambda": "^8.0.0",
"@types/node": "^22.0.0",
"aws-xray-sdk": "^3.3.3"
@@ -12216,13 +12256,13 @@
},
"packages/ws-router": {
"name": "@middy/ws-router",
- "version": "7.3.4",
+ "version": "7.4.0",
"license": "MIT",
"dependencies": {
- "@middy/util": "7.3.4"
+ "@middy/util": "7.4.0"
},
"devDependencies": {
- "@middy/core": "7.3.4",
+ "@middy/core": "7.4.0",
"@types/aws-lambda": "^8.0.0",
"@types/node": "^22.0.0"
},
@@ -12252,7 +12292,7 @@
"license": "MIT"
},
"websites/middy.js.org": {
- "version": "7.3.4",
+ "version": "7.4.0",
"dependencies": {
"@plausible-analytics/tracker": "0.4.4",
"@willfarrell-ds/svelte": "0.0.0-alpha.6",
diff --git a/package.json b/package.json
index 6d299ab72..fb7980d2b 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@middy/monorepo",
- "version": "7.3.4",
+ "version": "7.4.0",
"description": "🛵 The stylish Node.js middleware engine for AWS Lambda",
"private": true,
"type": "module",
@@ -80,7 +80,6 @@
"@sveltejs/kit": {
"cookie": "^0.7.2"
},
- "fast-xml-parser": ">=5.7.2",
"mathjs": ">=15.2.0"
},
"devEngines": {
diff --git a/packages/appconfig/package.json b/packages/appconfig/package.json
index 9249dd64d..e260de2f0 100644
--- a/packages/appconfig/package.json
+++ b/packages/appconfig/package.json
@@ -1,6 +1,6 @@
{
"name": "@middy/appconfig",
- "version": "7.3.4",
+ "version": "7.4.0",
"description": "AppConfig middleware for the middy framework",
"type": "module",
"engines": {
@@ -68,11 +68,11 @@
}
},
"dependencies": {
- "@middy/util": "7.3.4"
+ "@middy/util": "7.4.0"
},
"devDependencies": {
"@aws-sdk/client-appconfigdata": "^3.0.0",
- "@middy/core": "7.3.4",
+ "@middy/core": "7.4.0",
"@types/aws-lambda": "^8.0.0",
"@types/node": "^22.0.0",
"aws-xray-sdk": "^3.3.3"
diff --git a/packages/cloudformation-response/package.json b/packages/cloudformation-response/package.json
index d7caa724e..2cf17856e 100644
--- a/packages/cloudformation-response/package.json
+++ b/packages/cloudformation-response/package.json
@@ -1,6 +1,6 @@
{
"name": "@middy/cloudformation-response",
- "version": "7.3.4",
+ "version": "7.4.0",
"description": "CloudFormation Custom Response event response handling for the middy framework",
"type": "module",
"engines": {
@@ -61,7 +61,7 @@
"url": "https://github.com/sponsors/willfarrell"
},
"devDependencies": {
- "@middy/core": "7.3.4",
+ "@middy/core": "7.4.0",
"@types/aws-lambda": "^8.0.0",
"@types/node": "^22.0.0"
}
diff --git a/packages/cloudformation-router/package.json b/packages/cloudformation-router/package.json
index 18e44daf6..5462b5909 100644
--- a/packages/cloudformation-router/package.json
+++ b/packages/cloudformation-router/package.json
@@ -1,6 +1,6 @@
{
"name": "@middy/cloudformation-router",
- "version": "7.3.4",
+ "version": "7.4.0",
"description": "CloudFormation Custom Response event router for the middy framework",
"type": "module",
"engines": {
@@ -62,7 +62,7 @@
"url": "https://github.com/sponsors/willfarrell"
},
"devDependencies": {
- "@middy/core": "7.3.4",
+ "@middy/core": "7.4.0",
"@types/aws-lambda": "^8.0.0",
"@types/node": "^22.0.0"
}
diff --git a/packages/cloudwatch-metrics/package.json b/packages/cloudwatch-metrics/package.json
index 239a888f6..8d1a15954 100644
--- a/packages/cloudwatch-metrics/package.json
+++ b/packages/cloudwatch-metrics/package.json
@@ -1,6 +1,6 @@
{
"name": "@middy/cloudwatch-metrics",
- "version": "7.3.4",
+ "version": "7.4.0",
"description": "Embedded CloudWatch metrics middleware for the middy framework",
"type": "module",
"engines": {
@@ -68,7 +68,7 @@
"aws-embedded-metrics": "4.2.1"
},
"devDependencies": {
- "@middy/core": "7.3.4",
+ "@middy/core": "7.4.0",
"@types/aws-lambda": "^8.0.0",
"@types/node": "^22.0.0"
}
diff --git a/packages/core/package.json b/packages/core/package.json
index 9a15f93cd..fbf73f70f 100644
--- a/packages/core/package.json
+++ b/packages/core/package.json
@@ -1,6 +1,6 @@
{
"name": "@middy/core",
- "version": "7.3.4",
+ "version": "7.4.0",
"description": "🛵 The stylish Node.js middleware engine for AWS Lambda (core package)",
"type": "module",
"engines": {
@@ -103,7 +103,7 @@
"url": "https://github.com/sponsors/willfarrell"
},
"dependencies": {
- "@middy/util": "7.3.4"
+ "@middy/util": "7.4.0"
},
"peerDependencies": {
"@aws/durable-execution-sdk-js": "^1.0.0"
diff --git a/packages/do-not-wait-for-empty-event-loop/package.json b/packages/do-not-wait-for-empty-event-loop/package.json
index 409c247c8..1222fda19 100644
--- a/packages/do-not-wait-for-empty-event-loop/package.json
+++ b/packages/do-not-wait-for-empty-event-loop/package.json
@@ -1,6 +1,6 @@
{
"name": "@middy/do-not-wait-for-empty-event-loop",
- "version": "7.3.4",
+ "version": "7.4.0",
"description": "Middleware for the middy framework that allows to easily disable the wait for empty event loop in a Lambda function",
"type": "module",
"engines": {
@@ -60,10 +60,10 @@
"url": "https://github.com/sponsors/willfarrell"
},
"dependencies": {
- "@middy/util": "7.3.4"
+ "@middy/util": "7.4.0"
},
"devDependencies": {
- "@middy/core": "7.3.4",
+ "@middy/core": "7.4.0",
"@types/aws-lambda": "^8.0.0",
"@types/node": "^22.0.0"
}
diff --git a/packages/dsql-signer/README.md b/packages/dsql-signer/README.md
new file mode 100644
index 000000000..5bde2e8a4
--- /dev/null
+++ b/packages/dsql-signer/README.md
@@ -0,0 +1,50 @@
+
+
+## Install
+
+```bash
+npm install --save @middy/dsql-signer @aws-sdk/dsql-signer
+```
+
+
+## Documentation and examples
+
+For documentation and examples, refer to the main [Middy monorepo on GitHub](https://github.com/middyjs/middy) or [Middy official website](https://middy.js.org/docs/middlewares/dsql-signer).
+
+
+## Contributing
+
+Everyone is very welcome to contribute to this repository. Feel free to [raise issues](https://github.com/middyjs/middy/issues) or to [submit Pull Requests](https://github.com/middyjs/middy/pulls).
+
+
+## License
+
+Licensed under [MIT License](https://github.com/middyjs/middy/blob/main/LICENSE). Copyright (c) 2017-2026 [will Farrell](https://github.com/willfarrell), [Luciano Mammino](https://github.com/lmammino), and [Middy contributors](https://github.com/middyjs/middy/graphs/contributors).
diff --git a/packages/dsql-signer/index.d.ts b/packages/dsql-signer/index.d.ts
new file mode 100644
index 000000000..32fb4e2d1
--- /dev/null
+++ b/packages/dsql-signer/index.d.ts
@@ -0,0 +1,54 @@
+// Copyright 2017 - 2026 will Farrell, Luciano Mammino, and Middy contributors.
+// SPDX-License-Identifier: MIT
+import type { DsqlSigner, DsqlSignerConfig } from "@aws-sdk/dsql-signer";
+import type middy from "@middy/core";
+import type { Options as MiddyOptions } from "@middy/util";
+import type { Context as LambdaContext } from "aws-lambda";
+
+export type ParamType = string & { __returnType?: T };
+export declare function dsqlSignerParam(name: string): ParamType;
+
+export type DsqlSignerFetchConfig = DsqlSignerConfig & { username?: string };
+
+export type DsqlSignerOptions = Omit<
+ MiddyOptions,
+ "fetchData"
+> & {
+ fetchData?: {
+ [key: string]: DsqlSignerFetchConfig;
+ };
+};
+
+export type Context =
+ TOptions extends { setToContext: true }
+ ? TOptions extends { fetchData: infer TFetchData }
+ ? LambdaContext & {
+ [Key in keyof TFetchData]: string;
+ }
+ : never
+ : LambdaContext;
+
+export type Internal =
+ TOptions extends DsqlSignerOptions
+ ? TOptions extends { fetchData: infer TFetchData }
+ ? {
+ [Key in keyof TFetchData]: string;
+ }
+ : {}
+ : {};
+
+declare function dsqlSigner(
+ options?: TOptions,
+): middy.MiddlewareObj<
+ unknown,
+ unknown,
+ Error,
+ Context,
+ Internal
+>;
+
+export declare function dsqlSignerValidateOptions(
+ options?: Record,
+): void;
+
+export default dsqlSigner;
diff --git a/packages/dsql-signer/index.fuzz.js b/packages/dsql-signer/index.fuzz.js
new file mode 100644
index 000000000..9a028581f
--- /dev/null
+++ b/packages/dsql-signer/index.fuzz.js
@@ -0,0 +1,22 @@
+import { test } from "node:test";
+import fc from "fast-check";
+import middy from "../core/index.js";
+import middleware from "./index.js";
+
+const handler = middy((event) => event).use(middleware());
+const defaultContext = {
+ getRemainingTimeInMillis: () => 1000,
+};
+
+test("fuzz `event` w/ `object`", async () => {
+ await fc.assert(
+ fc.asyncProperty(fc.object(), async (event) => {
+ await handler(event, defaultContext);
+ }),
+ {
+ numRuns: 100_000,
+
+ examples: [],
+ },
+ );
+});
diff --git a/packages/dsql-signer/index.js b/packages/dsql-signer/index.js
new file mode 100644
index 000000000..f4f90bf70
--- /dev/null
+++ b/packages/dsql-signer/index.js
@@ -0,0 +1,136 @@
+// Copyright 2017 - 2026 will Farrell, Luciano Mammino, and Middy contributors.
+// SPDX-License-Identifier: MIT
+import { DsqlSigner } from "@aws-sdk/dsql-signer";
+import {
+ canPrefetch,
+ getCache,
+ getInternal,
+ modifyCache,
+ processCache,
+ validateOptions,
+} from "@middy/util";
+
+const name = "dsql-signer";
+const pkg = `@middy/${name}`;
+
+const defaults = {
+ AwsClient: DsqlSigner,
+ awsClientOptions: {},
+ fetchData: {},
+ disablePrefetch: false,
+ cacheKey: pkg,
+ cacheKeyExpiry: {},
+ cacheExpiry: -1,
+ setToContext: false,
+};
+
+const optionSchema = {
+ type: "object",
+ properties: {
+ AwsClient: { instanceof: "Function" },
+ awsClientOptions: { type: "object" },
+ fetchData: {
+ type: "object",
+ additionalProperties: {
+ type: "object",
+ properties: {
+ hostname: {
+ type: "string",
+ pattern:
+ "^[a-z0-9]+\\.dsql(-[a-z]+)?\\.[a-z]{2}(-[a-z]+){1,2}-\\d+\\.on\\.aws$",
+ },
+ username: { type: "string" },
+ },
+ required: [],
+ additionalProperties: true,
+ },
+ },
+ disablePrefetch: { type: "boolean" },
+ cacheKey: { type: "string" },
+ cacheKeyExpiry: {
+ type: "object",
+ additionalProperties: { type: "number", minimum: -1 },
+ },
+ cacheExpiry: { type: "number", minimum: -1 },
+ setToContext: { type: "boolean" },
+ },
+ additionalProperties: false,
+};
+
+export const dsqlSignerValidateOptions = (options) =>
+ validateOptions(pkg, optionSchema, options);
+
+const dsqlSignerMiddleware = (opts = {}) => {
+ const options = { ...defaults, ...opts };
+
+ const defaultFetchData = {
+ hostname: process.env.PGHOST ?? process.env.DBHOST,
+ username: process.env.PGUSER ?? process.env.DBUSER,
+ };
+ for (const key of Object.keys(options.fetchData)) {
+ options.fetchData[key] = { ...defaultFetchData, ...options.fetchData[key] };
+ }
+
+ const fetchDataKeys = Object.keys(options.fetchData);
+ const clients = {};
+ const fetchRequest = (request, cachedValues = {}) => {
+ const values = {};
+ for (const internalKey of fetchDataKeys) {
+ if (cachedValues[internalKey]) continue;
+
+ const { username, ...signerConfig } = options.fetchData[internalKey];
+ clients[internalKey] ??= new options.AwsClient({
+ ...options.awsClientOptions,
+ ...signerConfig,
+ });
+ const method =
+ username === "admin"
+ ? "getDbConnectAdminAuthToken"
+ : "getDbConnectAuthToken";
+ values[internalKey] = clients[internalKey]
+ [method]()
+ .then((token) => {
+ // Catch Missing token, this usually means there is something wrong with the credentials
+ if (!token.includes("X-Amz-Security-Token=")) {
+ throw new Error("X-Amz-Security-Token Missing", {
+ cause: { package: pkg, method },
+ });
+ }
+ return token;
+ })
+ .catch((e) => {
+ const value = getCache(options.cacheKey).value ?? {};
+ value[internalKey] = undefined;
+ modifyCache(options.cacheKey, value);
+ throw e;
+ });
+ }
+
+ return values;
+ };
+
+ if (canPrefetch(options)) {
+ processCache(options, fetchRequest);
+ }
+
+ const dsqlSignerMiddlewareBefore = async (request) => {
+ const { value } = processCache(options, fetchRequest, request);
+
+ Object.assign(request.internal, value);
+
+ if (options.setToContext) {
+ const data = await getInternal(fetchDataKeys, request);
+ Object.assign(request.context, data);
+ }
+ };
+
+ return {
+ before: dsqlSignerMiddlewareBefore,
+ };
+};
+export default dsqlSignerMiddleware;
+
+// used for TS type inference (see index.d.ts)
+export function dsqlSignerParam(name) {
+ return name;
+}
diff --git a/packages/dsql-signer/index.perf.js b/packages/dsql-signer/index.perf.js
new file mode 100644
index 000000000..4b9ee130d
--- /dev/null
+++ b/packages/dsql-signer/index.perf.js
@@ -0,0 +1,62 @@
+import { Bench } from "tinybench";
+import middy from "../core/index.js";
+import middleware from "./index.js";
+
+const bench = new Bench({
+ time: 1_000,
+ warmupTime: 500,
+ warmupIterations: 1_000,
+});
+
+const defaultContext = {
+ getRemainingTimeInMillis: () => 30000,
+};
+
+class MockDsqlSigner {
+ getDbConnectAuthToken() {
+ return Promise.resolve(
+ "cluster.dsql.us-east-1.on.aws/?Action=DbConnect&X-Amz-Security-Token=mock",
+ );
+ }
+ getDbConnectAdminAuthToken() {
+ return Promise.resolve(
+ "cluster.dsql.us-east-1.on.aws/?Action=DbConnectAdmin&X-Amz-Security-Token=mock",
+ );
+ }
+}
+
+const setupHandler = (options = {}) => {
+ const baseHandler = () => {};
+ return middy(baseHandler).use(
+ middleware({
+ ...options,
+ AwsClient: MockDsqlSigner,
+ fetchData: {
+ token: {
+ hostname: "cluster.dsql.us-east-1.on.aws",
+ region: "us-east-1",
+ },
+ },
+ }),
+ );
+};
+
+const coldHandler = setupHandler({ cacheExpiry: 0 });
+const warmHandler = setupHandler();
+
+const defaultEvent = {};
+await bench
+ .add("without cache", async () => {
+ try {
+ await coldHandler(defaultEvent, defaultContext);
+ } catch (_e) {}
+ })
+ .add("with cache", async () => {
+ try {
+ await warmHandler(defaultEvent, defaultContext);
+ } catch (_e) {}
+ })
+
+ .run();
+
+console.table(bench.table());
diff --git a/packages/dsql-signer/index.test.js b/packages/dsql-signer/index.test.js
new file mode 100644
index 000000000..ab846f724
--- /dev/null
+++ b/packages/dsql-signer/index.test.js
@@ -0,0 +1,545 @@
+import { deepStrictEqual, ok, strictEqual } from "node:assert/strict";
+import { after, before, test } from "node:test";
+import middy from "../core/index.js";
+import { clearCache, getInternal } from "../util/index.js";
+import dsqlSigner, { dsqlSignerValidateOptions } from "./index.js";
+
+before(() => {
+ process.env.PGHOST = "cluster.dsql.us-east-1.on.aws";
+});
+
+after(() => {
+ delete process.env.PGHOST;
+});
+
+test.afterEach((t) => {
+ t.mock.reset();
+ clearCache();
+});
+
+const defaultEvent = {};
+const defaultContext = {
+ getRemainingTimeInMillis: () => 1000,
+};
+
+test("It should set token to internal storage (token)", async (t) => {
+ const getDbConnectAuthToken = t.mock.fn(
+ async () =>
+ "cluster.dsql.us-east-1.on.aws/?Action=DbConnect&X-Amz-Security-Token=token",
+ );
+ class AwsClient {
+ getDbConnectAuthToken = getDbConnectAuthToken;
+ }
+ const handler = middy(() => {});
+
+ const middleware = async (request) => {
+ const values = await getInternal(true, request);
+ strictEqual(
+ values.token,
+ "cluster.dsql.us-east-1.on.aws/?Action=DbConnect&X-Amz-Security-Token=token",
+ );
+ };
+
+ handler
+ .use(
+ dsqlSigner({
+ AwsClient,
+ cacheExpiry: 0,
+ fetchData: {
+ token: { region: "us-east-1" },
+ },
+ disablePrefetch: true,
+ }),
+ )
+ .before(middleware);
+
+ await handler(defaultEvent, defaultContext);
+ strictEqual(getDbConnectAuthToken.mock.callCount(), 1);
+});
+
+test("It should call admin token method when username is 'admin'", async (t) => {
+ const getDbConnectAuthToken = t.mock.fn(
+ async () => "X-Amz-Security-Token=non-admin-token",
+ );
+ const getDbConnectAdminAuthToken = t.mock.fn(
+ async () => "X-Amz-Security-Token=admin-token",
+ );
+ class AwsClient {
+ getDbConnectAuthToken = getDbConnectAuthToken;
+ getDbConnectAdminAuthToken = getDbConnectAdminAuthToken;
+ }
+ const handler = middy(() => {});
+
+ const middleware = async (request) => {
+ const values = await getInternal(true, request);
+ strictEqual(values.token, "X-Amz-Security-Token=admin-token");
+ };
+
+ handler
+ .use(
+ dsqlSigner({
+ AwsClient,
+ cacheExpiry: 0,
+ fetchData: {
+ token: { region: "us-east-1", username: "admin" },
+ },
+ disablePrefetch: true,
+ }),
+ )
+ .before(middleware);
+
+ await handler(defaultEvent, defaultContext);
+ strictEqual(getDbConnectAdminAuthToken.mock.callCount(), 1);
+ strictEqual(getDbConnectAuthToken.mock.callCount(), 0);
+});
+
+test("It should call non-admin token method when username is a custom role", async (t) => {
+ const getDbConnectAuthToken = t.mock.fn(
+ async () => "X-Amz-Security-Token=role-token",
+ );
+ const getDbConnectAdminAuthToken = t.mock.fn(
+ async () => "X-Amz-Security-Token=admin-token",
+ );
+ class AwsClient {
+ getDbConnectAuthToken = getDbConnectAuthToken;
+ getDbConnectAdminAuthToken = getDbConnectAdminAuthToken;
+ }
+ const handler = middy(() => {});
+
+ const middleware = async (request) => {
+ const values = await getInternal(true, request);
+ strictEqual(values.token, "X-Amz-Security-Token=role-token");
+ };
+
+ handler
+ .use(
+ dsqlSigner({
+ AwsClient,
+ cacheExpiry: 0,
+ fetchData: {
+ token: { region: "us-east-1", username: "app_reader" },
+ },
+ disablePrefetch: true,
+ }),
+ )
+ .before(middleware);
+
+ await handler(defaultEvent, defaultContext);
+ strictEqual(getDbConnectAuthToken.mock.callCount(), 1);
+ strictEqual(getDbConnectAdminAuthToken.mock.callCount(), 0);
+});
+
+test("It should not pass `username` to the signer constructor", async (t) => {
+ let receivedConfig;
+ const getDbConnectAdminAuthToken = t.mock.fn(
+ async () => "X-Amz-Security-Token=admin-token",
+ );
+ class AwsClient {
+ constructor(config) {
+ receivedConfig = config;
+ }
+ getDbConnectAdminAuthToken = getDbConnectAdminAuthToken;
+ }
+ const handler = middy(() => {});
+
+ handler.use(
+ dsqlSigner({
+ AwsClient,
+ cacheExpiry: 0,
+ fetchData: {
+ token: { username: "admin" },
+ },
+ disablePrefetch: true,
+ }),
+ );
+
+ await handler(defaultEvent, defaultContext);
+ deepStrictEqual(receivedConfig, {
+ hostname: "cluster.dsql.us-east-1.on.aws",
+ });
+});
+
+test("It should set tokens to internal storage (multiple keys)", async (t) => {
+ const getDbConnectAuthToken = t.mock.fn(
+ async () => "X-Amz-Security-Token=token2",
+ async () => "X-Amz-Security-Token=token1",
+ { times: 1 },
+ );
+ class AwsClient {
+ getDbConnectAuthToken = getDbConnectAuthToken;
+ }
+
+ const handler = middy(() => {});
+
+ const middleware = async (request) => {
+ const values = await getInternal(true, request);
+ strictEqual(values.token1, "X-Amz-Security-Token=token1");
+ strictEqual(values.token2, "X-Amz-Security-Token=token2");
+ };
+
+ handler
+ .use(
+ dsqlSigner({
+ AwsClient,
+ cacheExpiry: 0,
+ fetchData: {
+ token1: {
+ region: "us-east-1",
+ hostname: "reader.dsql.us-east-1.on.aws",
+ },
+ token2: {
+ region: "us-east-1",
+ hostname: "writer.dsql.us-east-1.on.aws",
+ },
+ },
+ disablePrefetch: true,
+ }),
+ )
+ .before(middleware);
+
+ await handler(defaultEvent, defaultContext);
+});
+
+test("It should set DSQL token to context", async (t) => {
+ const getDbConnectAuthToken = t.mock.fn(
+ async () => "X-Amz-Security-Token=token",
+ );
+ class AwsClient {
+ getDbConnectAuthToken = getDbConnectAuthToken;
+ }
+ const handler = middy(() => {});
+
+ const middleware = async (request) => {
+ strictEqual(request.context.token, "X-Amz-Security-Token=token");
+ };
+
+ handler
+ .use(
+ dsqlSigner({
+ AwsClient,
+ cacheExpiry: 0,
+ fetchData: {
+ token: { region: "us-east-1" },
+ },
+ setToContext: true,
+ disablePrefetch: true,
+ }),
+ )
+ .before(middleware);
+
+ await handler(defaultEvent, defaultContext);
+});
+
+test("It should not call aws-sdk again if parameter is cached", async (t) => {
+ const getDbConnectAuthToken = t.mock.fn(
+ async () => "X-Amz-Security-Token=token",
+ );
+ class AwsClient {
+ getDbConnectAuthToken = getDbConnectAuthToken;
+ }
+ const handler = middy(() => {});
+
+ const middleware = async (request) => {
+ const values = await getInternal(true, request);
+ strictEqual(values.token, "X-Amz-Security-Token=token");
+ };
+
+ handler
+ .use(
+ dsqlSigner({
+ AwsClient,
+ cacheExpiry: -1,
+ fetchData: {
+ token: { region: "us-east-1" },
+ },
+ }),
+ )
+ .before(middleware);
+
+ await handler(defaultEvent, defaultContext);
+ await handler(defaultEvent, defaultContext);
+
+ strictEqual(getDbConnectAuthToken.mock.callCount(), 1);
+});
+
+test("It should call aws-sdk if cache enabled but cached param has expired", async (t) => {
+ const getDbConnectAuthToken = t.mock.fn(
+ async () => "X-Amz-Security-Token=token",
+ );
+ class AwsClient {
+ getDbConnectAuthToken = getDbConnectAuthToken;
+ }
+
+ const handler = middy(() => {});
+
+ const middleware = async (request) => {
+ const values = await getInternal(true, request);
+ strictEqual(values.token, "X-Amz-Security-Token=token");
+ };
+
+ handler
+ .use(
+ dsqlSigner({
+ AwsClient,
+ cacheExpiry: 0,
+ fetchData: {
+ token: { region: "us-east-1" },
+ },
+ disablePrefetch: true,
+ }),
+ )
+ .before(middleware);
+
+ await handler(defaultEvent, defaultContext);
+ await handler(defaultEvent, defaultContext);
+
+ strictEqual(getDbConnectAuthToken.mock.callCount(), 2);
+});
+
+test("It should catch if an error is returned from fetch", async (t) => {
+ const getDbConnectAuthToken = t.mock.fn(async () => {
+ throw new Error("timeout");
+ });
+ class AwsClient {
+ getDbConnectAuthToken = getDbConnectAuthToken;
+ }
+ const handler = middy(() => {}).use(
+ dsqlSigner({
+ AwsClient,
+ cacheExpiry: 0,
+ fetchData: {
+ token: { region: "us-east-1" },
+ },
+ setToContext: true,
+ disablePrefetch: true,
+ }),
+ );
+
+ try {
+ await handler(defaultEvent, defaultContext);
+ } catch (e) {
+ strictEqual(getDbConnectAuthToken.mock.callCount(), 1);
+ strictEqual(e.message, "Failed to resolve internal values");
+ deepStrictEqual(e.cause.data, [new Error("timeout")]);
+ }
+});
+
+test("It should catch if a token without X-Amz-Security-Token is returned from fetch", async (t) => {
+ const getDbConnectAuthToken = t.mock.fn(async () => "no-creds");
+ class AwsClient {
+ getDbConnectAuthToken = getDbConnectAuthToken;
+ }
+ const handler = middy(() => {}).use(
+ dsqlSigner({
+ AwsClient,
+ cacheExpiry: 0,
+ fetchData: {
+ token: { region: "us-east-1" },
+ },
+ setToContext: true,
+ disablePrefetch: true,
+ }),
+ );
+
+ try {
+ await handler(defaultEvent, defaultContext);
+ } catch (e) {
+ strictEqual(getDbConnectAuthToken.mock.callCount(), 1);
+ strictEqual(e.message, "Failed to resolve internal values");
+ deepStrictEqual(e.cause.data, [
+ new Error("X-Amz-Security-Token Missing", {
+ cause: {
+ package: "@middy/dsql-signer",
+ method: "getDbConnectAuthToken",
+ },
+ }),
+ ]);
+ }
+});
+
+test("It should skip fetching already cached values when fetching multiple keys", async (t) => {
+ let callCount = 0;
+ const getDbConnectAuthToken = t.mock.fn(async () => {
+ callCount++;
+ if (callCount === 1) return "X-Amz-Security-Token=token1";
+ if (callCount === 2) throw new Error("timeout");
+ if (callCount === 3) return "X-Amz-Security-Token=token2";
+ });
+ class AwsClient {
+ getDbConnectAuthToken = getDbConnectAuthToken;
+ }
+
+ const middleware = async (request) => {
+ const values = await getInternal(true, request);
+ strictEqual(values.token1, "X-Amz-Security-Token=token1");
+ strictEqual(values.token2, "X-Amz-Security-Token=token2");
+ };
+
+ const handler = middy(() => {});
+
+ handler
+ .use(
+ dsqlSigner({
+ AwsClient,
+ cacheExpiry: 1000,
+ fetchData: {
+ token1: {
+ region: "us-east-1",
+ hostname: "reader.dsql.us-east-1.on.aws",
+ },
+ token2: {
+ region: "us-east-1",
+ hostname: "writer.dsql.us-east-1.on.aws",
+ },
+ },
+ }),
+ )
+ .before(middleware);
+
+ try {
+ await handler(defaultEvent, defaultContext);
+ } catch (_e) {}
+
+ await handler(defaultEvent, defaultContext);
+
+ strictEqual(getDbConnectAuthToken.mock.callCount(), 3);
+});
+
+test("It should export dsqlSignerParam helper for TypeScript type inference", async (t) => {
+ const { dsqlSignerParam } = await import("./index.js");
+ const paramName = "test-param";
+ const result = dsqlSignerParam(paramName);
+ strictEqual(result, paramName);
+});
+
+test("It should use DBHOST/DBUSER env var defaults as fallback", async (t) => {
+ const savedPGHOST = process.env.PGHOST;
+ delete process.env.PGHOST;
+ process.env.DBHOST = "cluster.dsql.us-east-1.on.aws";
+ process.env.DBUSER = "app_reader";
+ t.after(() => {
+ delete process.env.DBHOST;
+ delete process.env.DBUSER;
+ process.env.PGHOST = savedPGHOST;
+ });
+
+ const getDbConnectAuthToken = t.mock.fn(
+ async () => "X-Amz-Security-Token=role-token",
+ );
+ let receivedConfig;
+ class AwsClient {
+ constructor(config) {
+ receivedConfig = config;
+ }
+ getDbConnectAuthToken = getDbConnectAuthToken;
+ }
+ const handler = middy(() => {}).use(
+ dsqlSigner({
+ AwsClient,
+ cacheExpiry: 0,
+ fetchData: { token: {} },
+ disablePrefetch: true,
+ }),
+ );
+
+ await handler(defaultEvent, defaultContext);
+ strictEqual(receivedConfig.hostname, "cluster.dsql.us-east-1.on.aws");
+ strictEqual(getDbConnectAuthToken.mock.callCount(), 1);
+});
+
+test("It should prefer explicit fetchData values over env var defaults", async (t) => {
+ const getDbConnectAuthToken = t.mock.fn(
+ async () => "X-Amz-Security-Token=role-token",
+ );
+ let receivedConfig;
+ class AwsClient {
+ constructor(config) {
+ receivedConfig = config;
+ }
+ getDbConnectAuthToken = getDbConnectAuthToken;
+ }
+ const handler = middy(() => {}).use(
+ dsqlSigner({
+ AwsClient,
+ cacheExpiry: 0,
+ fetchData: {
+ token: {
+ hostname: "explicit.dsql.us-east-1.on.aws",
+ username: "app_reader",
+ },
+ },
+ disablePrefetch: true,
+ }),
+ );
+
+ await handler(defaultEvent, defaultContext);
+ strictEqual(receivedConfig.hostname, "explicit.dsql.us-east-1.on.aws");
+ strictEqual(getDbConnectAuthToken.mock.callCount(), 1);
+});
+
+test("dsqlSignerValidateOptions accepts valid options and rejects typos", () => {
+ dsqlSignerValidateOptions({ cacheKey: "x", cacheExpiry: 0 });
+ dsqlSignerValidateOptions({});
+ try {
+ dsqlSignerValidateOptions({ cachExpiry: 60 });
+ ok(false, "expected throw");
+ } catch (e) {
+ ok(e instanceof TypeError);
+ strictEqual(e.cause.package, "@middy/dsql-signer");
+ }
+});
+
+test("dsqlSignerValidateOptions rejects wrong type", () => {
+ try {
+ dsqlSignerValidateOptions({ fetchData: 42 });
+ ok(false, "expected throw");
+ } catch (e) {
+ ok(e.message.includes("fetchData"));
+ }
+});
+
+test("dsqlSignerValidateOptions accepts valid fetchData entry", () => {
+ dsqlSignerValidateOptions({
+ fetchData: {
+ token: {
+ hostname: "cluster.dsql.us-east-1.on.aws",
+ username: "admin",
+ },
+ },
+ });
+});
+
+test("dsqlSignerValidateOptions accepts fetchData entry relying on env var defaults", () => {
+ dsqlSignerValidateOptions({ fetchData: { token: {} } });
+ dsqlSignerValidateOptions({ fetchData: { token: { username: "admin" } } });
+});
+
+test("dsqlSignerValidateOptions rejects fetchData entry with non-string username", () => {
+ try {
+ dsqlSignerValidateOptions({
+ fetchData: {
+ token: {
+ hostname: "cluster.dsql.us-east-1.on.aws",
+ username: true,
+ },
+ },
+ });
+ ok(false, "expected throw");
+ } catch (e) {
+ ok(e instanceof TypeError);
+ }
+});
+
+test("dsqlSignerValidateOptions rejects fetchData entry with non-DSQL hostname", () => {
+ try {
+ dsqlSignerValidateOptions({
+ fetchData: {
+ token: { hostname: "db.example.com" },
+ },
+ });
+ ok(false, "expected throw");
+ } catch (e) {
+ ok(e instanceof TypeError);
+ strictEqual(e.cause.package, "@middy/dsql-signer");
+ }
+});
diff --git a/packages/dsql-signer/index.tst.ts b/packages/dsql-signer/index.tst.ts
new file mode 100644
index 000000000..22ac632aa
--- /dev/null
+++ b/packages/dsql-signer/index.tst.ts
@@ -0,0 +1,78 @@
+import { DsqlSigner } from "@aws-sdk/dsql-signer";
+import middy from "@middy/core";
+import { getInternal } from "@middy/util";
+import type { Context as LambdaContext } from "aws-lambda";
+import { expect, test } from "tstyche";
+import dsqlSigner from "./index.js";
+
+test("use with default options", () => {
+ const middleware = dsqlSigner();
+ expect(middleware).type.toBe>();
+});
+
+const options = {
+ AwsClient: DsqlSigner,
+ awsClientOptions: {
+ credentials: {
+ secretAccessKey: "secret",
+ accessKeyId: "key",
+ },
+ },
+ awsClientAssumeRole: "some-role",
+ fetchData: {
+ foo: {
+ hostname: "cluster.dsql.ca-central-1.on.aws",
+ username: "admin",
+ },
+ },
+ disablePrefetch: true,
+ cacheKey: "some-key",
+ cacheExpiry: 60 * 60 * 5,
+ setToContext: true,
+};
+
+test("use with no options", () => {
+ expect(dsqlSigner()).type.toBe<
+ middy.MiddlewareObj
+ >();
+});
+
+test("use with all options", () => {
+ expect(dsqlSigner(options)).type.toBe<
+ middy.MiddlewareObj
+ >();
+});
+
+const handler = middy(async (event: {}, context: LambdaContext) => {
+ return await Promise.resolve({});
+});
+
+test("use with setToContext: true", () => {
+ handler
+ .use(
+ dsqlSigner({
+ ...options,
+ setToContext: true,
+ }),
+ )
+ .before(async (request) => {
+ expect(request.context.foo).type.toBe();
+
+ const data = await getInternal("foo", request);
+ expect(data.foo).type.toBe();
+ });
+});
+
+test("use with setToContext: false", () => {
+ handler
+ .use(
+ dsqlSigner({
+ ...options,
+ setToContext: false,
+ }),
+ )
+ .before(async (request) => {
+ const data = await getInternal("foo", request);
+ expect(data.foo).type.toBe();
+ });
+});
diff --git a/packages/dsql-signer/package.json b/packages/dsql-signer/package.json
new file mode 100644
index 000000000..7bb5648fc
--- /dev/null
+++ b/packages/dsql-signer/package.json
@@ -0,0 +1,82 @@
+{
+ "name": "@middy/dsql-signer",
+ "version": "7.4.0",
+ "description": "Aurora DSQL credentials middleware for the middy framework",
+ "type": "module",
+ "engines": {
+ "node": ">=22"
+ },
+ "engineStrict": true,
+ "publishConfig": {
+ "access": "public"
+ },
+ "module": "./index.js",
+ "sideEffects": false,
+ "exports": {
+ ".": {
+ "import": {
+ "types": "./index.d.ts",
+ "default": "./index.js"
+ }
+ }
+ },
+ "types": "index.d.ts",
+ "files": [
+ "index.js",
+ "index.d.ts"
+ ],
+ "scripts": {
+ "test": "npm run test:unit && npm run test:fuzz",
+ "test:unit": "node --test",
+ "test:fuzz": "node --test index.fuzz.js",
+ "test:perf": "node --test index.perf.js"
+ },
+ "license": "MIT",
+ "keywords": [
+ "Lambda",
+ "Middleware",
+ "Serverless",
+ "Framework",
+ "AWS",
+ "AWS Lambda",
+ "Middy",
+ "DSQL",
+ "Aurora DSQL",
+ "Credentials"
+ ],
+ "author": {
+ "name": "Middy contributors",
+ "url": "https://github.com/middyjs/middy/graphs/contributors"
+ },
+ "repository": {
+ "type": "git",
+ "url": "git+https://github.com/middyjs/middy.git",
+ "directory": "packages/dsql-signer"
+ },
+ "bugs": {
+ "url": "https://github.com/middyjs/middy/issues"
+ },
+ "homepage": "https://middy.js.org",
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/willfarrell"
+ },
+ "peerDependencies": {
+ "@aws-sdk/dsql-signer": "^3.0.0"
+ },
+ "peerDependenciesMeta": {
+ "@aws-sdk/dsql-signer": {
+ "optional": true
+ }
+ },
+ "dependencies": {
+ "@middy/util": "7.4.0"
+ },
+ "devDependencies": {
+ "@aws-sdk/dsql-signer": "^3.0.0",
+ "@middy/core": "7.4.0",
+ "@types/aws-lambda": "^8.0.0",
+ "@types/node": "^22.0.0",
+ "aws-xray-sdk": "^3.3.3"
+ }
+}
diff --git a/packages/dynamodb/package.json b/packages/dynamodb/package.json
index d5b45880b..e1d64f0db 100644
--- a/packages/dynamodb/package.json
+++ b/packages/dynamodb/package.json
@@ -1,6 +1,6 @@
{
"name": "@middy/dynamodb",
- "version": "7.3.4",
+ "version": "7.4.0",
"description": "DynamoDB middleware for the middy framework",
"type": "module",
"engines": {
@@ -72,12 +72,12 @@
}
},
"dependencies": {
- "@middy/util": "7.3.4"
+ "@middy/util": "7.4.0"
},
"devDependencies": {
"@aws-sdk/client-dynamodb": "^3.0.0",
"@aws-sdk/util-dynamodb": "^3.0.0",
- "@middy/core": "7.3.4",
+ "@middy/core": "7.4.0",
"@types/aws-lambda": "^8.0.0",
"@types/node": "^22.0.0",
"aws-xray-sdk": "^3.3.3"
diff --git a/packages/error-logger/package.json b/packages/error-logger/package.json
index 1d023c557..44ddac727 100644
--- a/packages/error-logger/package.json
+++ b/packages/error-logger/package.json
@@ -1,6 +1,6 @@
{
"name": "@middy/error-logger",
- "version": "7.3.4",
+ "version": "7.4.0",
"description": "Error logger middleware for the middy framework",
"type": "module",
"engines": {
@@ -61,7 +61,7 @@
"url": "https://github.com/sponsors/willfarrell"
},
"devDependencies": {
- "@middy/core": "7.3.4",
+ "@middy/core": "7.4.0",
"@types/aws-lambda": "^8.0.0",
"@types/node": "^22.0.0"
}
diff --git a/packages/event-normalizer/package.json b/packages/event-normalizer/package.json
index 88c9495d4..2849d2f39 100644
--- a/packages/event-normalizer/package.json
+++ b/packages/event-normalizer/package.json
@@ -1,6 +1,6 @@
{
"name": "@middy/event-normalizer",
- "version": "7.3.4",
+ "version": "7.4.0",
"description": "Parse and normalize AWS events middleware for the middy framework",
"type": "module",
"engines": {
@@ -64,10 +64,10 @@
"url": "https://github.com/sponsors/willfarrell"
},
"dependencies": {
- "@middy/util": "7.3.4"
+ "@middy/util": "7.4.0"
},
"devDependencies": {
- "@middy/core": "7.3.4",
+ "@middy/core": "7.4.0",
"@serverless/event-mocks": "^1.1.1",
"@types/aws-lambda": "^8.0.0",
"@types/node": "^22.0.0"
diff --git a/packages/http-content-encoding/package.json b/packages/http-content-encoding/package.json
index 85fbb1e24..edd390bcb 100644
--- a/packages/http-content-encoding/package.json
+++ b/packages/http-content-encoding/package.json
@@ -1,6 +1,6 @@
{
"name": "@middy/http-content-encoding",
- "version": "7.3.4",
+ "version": "7.4.0",
"description": "HTTP content encoding middleware for the middy framework",
"type": "module",
"engines": {
@@ -65,11 +65,11 @@
"url": "https://github.com/sponsors/willfarrell"
},
"dependencies": {
- "@middy/util": "7.3.4"
+ "@middy/util": "7.4.0"
},
"devDependencies": {
"@datastream/core": "0.4.0",
- "@middy/core": "7.3.4",
+ "@middy/core": "7.4.0",
"@types/aws-lambda": "^8.0.0",
"@types/node": "^22.0.0"
}
diff --git a/packages/http-content-negotiation/package.json b/packages/http-content-negotiation/package.json
index 06a2b195c..be693f19e 100644
--- a/packages/http-content-negotiation/package.json
+++ b/packages/http-content-negotiation/package.json
@@ -1,6 +1,6 @@
{
"name": "@middy/http-content-negotiation",
- "version": "7.3.4",
+ "version": "7.4.0",
"description": "HTTP content negotiation middleware for the middy framework",
"type": "module",
"engines": {
@@ -62,11 +62,11 @@
"url": "https://github.com/sponsors/willfarrell"
},
"dependencies": {
- "@middy/util": "7.3.4",
+ "@middy/util": "7.4.0",
"negotiator": "1.0.0"
},
"devDependencies": {
- "@middy/core": "7.3.4",
+ "@middy/core": "7.4.0",
"@types/aws-lambda": "^8.0.0",
"@types/node": "^22.0.0"
}
diff --git a/packages/http-cors/package.json b/packages/http-cors/package.json
index fb0741230..c36ca9407 100644
--- a/packages/http-cors/package.json
+++ b/packages/http-cors/package.json
@@ -1,6 +1,6 @@
{
"name": "@middy/http-cors",
- "version": "7.3.4",
+ "version": "7.4.0",
"description": "CORS (Cross-Origin Resource Sharing) middleware for the middy framework",
"type": "module",
"engines": {
@@ -61,10 +61,10 @@
"url": "https://github.com/sponsors/willfarrell"
},
"dependencies": {
- "@middy/util": "7.3.4"
+ "@middy/util": "7.4.0"
},
"devDependencies": {
- "@middy/core": "7.3.4",
+ "@middy/core": "7.4.0",
"@types/aws-lambda": "^8.0.0",
"@types/node": "^22.0.0"
}
diff --git a/packages/http-error-handler/package.json b/packages/http-error-handler/package.json
index 4d9bcb298..d67e187b3 100644
--- a/packages/http-error-handler/package.json
+++ b/packages/http-error-handler/package.json
@@ -1,6 +1,6 @@
{
"name": "@middy/http-error-handler",
- "version": "7.3.4",
+ "version": "7.4.0",
"description": "HTTP error handler middleware for the middy framework",
"type": "module",
"engines": {
@@ -63,10 +63,10 @@
"url": "https://github.com/sponsors/willfarrell"
},
"dependencies": {
- "@middy/util": "7.3.4"
+ "@middy/util": "7.4.0"
},
"devDependencies": {
- "@middy/core": "7.3.4",
+ "@middy/core": "7.4.0",
"@types/http-errors": "^2.0.0",
"@types/node": "^22.0.0"
}
diff --git a/packages/http-event-normalizer/package.json b/packages/http-event-normalizer/package.json
index b4dbeaaca..1a8172e0f 100644
--- a/packages/http-event-normalizer/package.json
+++ b/packages/http-event-normalizer/package.json
@@ -1,6 +1,6 @@
{
"name": "@middy/http-event-normalizer",
- "version": "7.3.4",
+ "version": "7.4.0",
"description": "HTTP event normalizer middleware for the middy framework",
"type": "module",
"engines": {
@@ -62,7 +62,7 @@
"url": "https://github.com/sponsors/willfarrell"
},
"devDependencies": {
- "@middy/core": "7.3.4",
+ "@middy/core": "7.4.0",
"@types/aws-lambda": "^8.0.0",
"@types/node": "^22.0.0"
}
diff --git a/packages/http-header-normalizer/package.json b/packages/http-header-normalizer/package.json
index 9dab9e9e3..c4a7da7d3 100644
--- a/packages/http-header-normalizer/package.json
+++ b/packages/http-header-normalizer/package.json
@@ -1,6 +1,6 @@
{
"name": "@middy/http-header-normalizer",
- "version": "7.3.4",
+ "version": "7.4.0",
"description": "HTTP header normalizer middleware for the middy framework",
"type": "module",
"engines": {
@@ -64,7 +64,7 @@
"url": "https://github.com/sponsors/willfarrell"
},
"devDependencies": {
- "@middy/core": "7.3.4",
+ "@middy/core": "7.4.0",
"@types/node": "^22.0.0"
}
}
diff --git a/packages/http-json-body-parser/package.json b/packages/http-json-body-parser/package.json
index 70b367e22..7ff202207 100644
--- a/packages/http-json-body-parser/package.json
+++ b/packages/http-json-body-parser/package.json
@@ -1,6 +1,6 @@
{
"name": "@middy/http-json-body-parser",
- "version": "7.3.4",
+ "version": "7.4.0",
"description": "HTTP JSON body parser middleware for the middy framework",
"type": "module",
"engines": {
@@ -64,10 +64,10 @@
"url": "https://github.com/sponsors/willfarrell"
},
"dependencies": {
- "@middy/util": "7.3.4"
+ "@middy/util": "7.4.0"
},
"devDependencies": {
- "@middy/core": "7.3.4",
+ "@middy/core": "7.4.0",
"@types/aws-lambda": "^8.0.0",
"@types/node": "^22.0.0",
"type-fest": "^5.0.0"
diff --git a/packages/http-multipart-body-parser/package.json b/packages/http-multipart-body-parser/package.json
index b926ec576..c7937f01f 100644
--- a/packages/http-multipart-body-parser/package.json
+++ b/packages/http-multipart-body-parser/package.json
@@ -1,6 +1,6 @@
{
"name": "@middy/http-multipart-body-parser",
- "version": "7.3.4",
+ "version": "7.4.0",
"description": "HTTP multipart body parser middleware for the middy framework",
"type": "module",
"engines": {
@@ -63,10 +63,10 @@
},
"dependencies": {
"@fastify/busboy": "3.2.0",
- "@middy/util": "7.3.4"
+ "@middy/util": "7.4.0"
},
"devDependencies": {
- "@middy/core": "7.3.4",
+ "@middy/core": "7.4.0",
"@types/aws-lambda": "^8.0.0",
"@types/node": "^22.0.0",
"type-fest": "^5.0.0"
diff --git a/packages/http-partial-response/package.json b/packages/http-partial-response/package.json
index 513e1d6f3..ae416df1b 100644
--- a/packages/http-partial-response/package.json
+++ b/packages/http-partial-response/package.json
@@ -1,6 +1,6 @@
{
"name": "@middy/http-partial-response",
- "version": "7.3.4",
+ "version": "7.4.0",
"description": "HTTP partial response middleware for the middy framework",
"type": "module",
"engines": {
@@ -63,11 +63,11 @@
"url": "https://github.com/sponsors/willfarrell"
},
"dependencies": {
- "@middy/util": "7.3.4",
+ "@middy/util": "7.4.0",
"json-mask": "2.0.0"
},
"devDependencies": {
- "@middy/core": "7.3.4",
+ "@middy/core": "7.4.0",
"@types/aws-lambda": "^8.0.0",
"@types/node": "^22.0.0"
}
diff --git a/packages/http-response-serializer/package.json b/packages/http-response-serializer/package.json
index a15430fa8..d43a3e639 100644
--- a/packages/http-response-serializer/package.json
+++ b/packages/http-response-serializer/package.json
@@ -1,6 +1,6 @@
{
"name": "@middy/http-response-serializer",
- "version": "7.3.4",
+ "version": "7.4.0",
"description": "HTTP response serializer middleware for the middy framework",
"type": "module",
"engines": {
@@ -65,10 +65,10 @@
"url": "https://github.com/sponsors/willfarrell"
},
"dependencies": {
- "@middy/util": "7.3.4"
+ "@middy/util": "7.4.0"
},
"devDependencies": {
- "@middy/core": "7.3.4",
+ "@middy/core": "7.4.0",
"@types/aws-lambda": "^8.0.0",
"@types/node": "^22.0.0"
}
diff --git a/packages/http-router/package.json b/packages/http-router/package.json
index c1f8a270a..a0ef51d0d 100644
--- a/packages/http-router/package.json
+++ b/packages/http-router/package.json
@@ -1,6 +1,6 @@
{
"name": "@middy/http-router",
- "version": "7.3.4",
+ "version": "7.4.0",
"description": "HTTP event router for the middy framework",
"type": "module",
"engines": {
@@ -62,10 +62,10 @@
"url": "https://github.com/sponsors/willfarrell"
},
"dependencies": {
- "@middy/util": "7.3.4"
+ "@middy/util": "7.4.0"
},
"devDependencies": {
- "@middy/core": "7.3.4",
+ "@middy/core": "7.4.0",
"@types/aws-lambda": "^8.0.0",
"@types/node": "^22.0.0"
}
diff --git a/packages/http-security-headers/package.json b/packages/http-security-headers/package.json
index 58bd21ac5..a21519d8b 100644
--- a/packages/http-security-headers/package.json
+++ b/packages/http-security-headers/package.json
@@ -1,6 +1,6 @@
{
"name": "@middy/http-security-headers",
- "version": "7.3.4",
+ "version": "7.4.0",
"description": "Applies best practice security headers to responses. It's a simplified port of HelmetJS",
"type": "module",
"engines": {
@@ -65,10 +65,10 @@
"url": "https://github.com/sponsors/willfarrell"
},
"dependencies": {
- "@middy/util": "7.3.4"
+ "@middy/util": "7.4.0"
},
"devDependencies": {
- "@middy/core": "7.3.4",
+ "@middy/core": "7.4.0",
"@types/aws-lambda": "^8.0.0",
"@types/node": "^22.0.0"
}
diff --git a/packages/http-urlencode-body-parser/package.json b/packages/http-urlencode-body-parser/package.json
index adf2b494f..b9ad1668a 100644
--- a/packages/http-urlencode-body-parser/package.json
+++ b/packages/http-urlencode-body-parser/package.json
@@ -1,6 +1,6 @@
{
"name": "@middy/http-urlencode-body-parser",
- "version": "7.3.4",
+ "version": "7.4.0",
"description": "Urlencode body parser middleware for the middy framework",
"type": "module",
"engines": {
@@ -63,10 +63,10 @@
"url": "https://github.com/sponsors/willfarrell"
},
"dependencies": {
- "@middy/util": "7.3.4"
+ "@middy/util": "7.4.0"
},
"devDependencies": {
- "@middy/core": "7.3.4",
+ "@middy/core": "7.4.0",
"@types/aws-lambda": "^8.0.0",
"@types/node": "^22.0.0",
"type-fest": "^5.0.0"
diff --git a/packages/http-urlencode-path-parser/package.json b/packages/http-urlencode-path-parser/package.json
index b29eb71f1..b02a73626 100644
--- a/packages/http-urlencode-path-parser/package.json
+++ b/packages/http-urlencode-path-parser/package.json
@@ -1,6 +1,6 @@
{
"name": "@middy/http-urlencode-path-parser",
- "version": "7.3.4",
+ "version": "7.4.0",
"description": "Urlencode path parser middleware for the middy framework",
"type": "module",
"engines": {
@@ -63,10 +63,10 @@
"url": "https://github.com/sponsors/willfarrell"
},
"dependencies": {
- "@middy/util": "7.3.4"
+ "@middy/util": "7.4.0"
},
"devDependencies": {
- "@middy/core": "7.3.4",
+ "@middy/core": "7.4.0",
"@types/aws-lambda": "^8.0.0",
"@types/node": "^22.0.0",
"type-fest": "^5.0.0"
diff --git a/packages/http-x402/index.d.ts b/packages/http-x402/index.d.ts
new file mode 100644
index 000000000..697ed419e
--- /dev/null
+++ b/packages/http-x402/index.d.ts
@@ -0,0 +1,27 @@
+import type middy from "@middy/core";
+
+export interface Options {
+ FacilitatorClient?: new (config: {
+ url?: string;
+ }) => {
+ verify(payload: unknown, requirements: unknown): Promise;
+ settle(payload: unknown, requirements: unknown): Promise;
+ };
+ facilitatorUrl?: string;
+ price: number;
+ decimals?: number;
+ network?: string;
+ payTo: string;
+ asset: string;
+ description?: string;
+ mimeType?: string;
+ human?: (request: middy.Request) => boolean;
+}
+
+declare function httpX402(options: Options): middy.MiddlewareObj;
+
+export declare function httpX402ValidateOptions(
+ options?: Record,
+): void;
+
+export default httpX402;
diff --git a/packages/http-x402/index.fuzz.js b/packages/http-x402/index.fuzz.js
new file mode 100644
index 000000000..306ca99d1
--- /dev/null
+++ b/packages/http-x402/index.fuzz.js
@@ -0,0 +1,53 @@
+import { strictEqual } from "node:assert/strict";
+import { test } from "node:test";
+import fc from "fast-check";
+import middy from "../core/index.js";
+import httpX402 from "./index.js";
+
+class AlwaysInvalidFacilitatorClient {
+ async verify() {
+ return { isValid: false, invalidReason: "invalid_payload" };
+ }
+ async settle() {
+ return { success: false, errorReason: "unexpected_settle_error" };
+ }
+}
+
+const fuzzOptions = {
+ price: 0.001,
+ payTo: "0xpayto",
+ asset: "0xasset",
+ FacilitatorClient: AlwaysInvalidFacilitatorClient,
+};
+const defaultContext = { getRemainingTimeInMillis: () => 1000 };
+
+test("fuzz payment-signature header values never crash", async () => {
+ const handler = middy(() => ({ statusCode: 200, body: "ok" })).use(
+ httpX402(fuzzOptions),
+ );
+
+ await fc.assert(
+ fc.asyncProperty(fc.string(), async (headerValue) => {
+ const response = await handler(
+ { headers: { "payment-signature": headerValue } },
+ defaultContext,
+ );
+ strictEqual(typeof response.statusCode, "number");
+ }),
+ { numRuns: 10_000, examples: [] },
+ );
+});
+
+test("fuzz arbitrary event objects never crash", async () => {
+ const handler = middy(() => ({ statusCode: 200, body: "ok" })).use(
+ httpX402(fuzzOptions),
+ );
+
+ await fc.assert(
+ fc.asyncProperty(fc.object(), async (event) => {
+ const response = await handler(event, defaultContext);
+ strictEqual(typeof response.statusCode, "number");
+ }),
+ { numRuns: 10_000, examples: [] },
+ );
+});
diff --git a/packages/http-x402/index.js b/packages/http-x402/index.js
new file mode 100644
index 000000000..de06e1960
--- /dev/null
+++ b/packages/http-x402/index.js
@@ -0,0 +1,173 @@
+// Copyright 2017 - 2026 will Farrell, Luciano Mammino, and Middy contributors.
+// SPDX-License-Identifier: MIT
+import { normalizeHttpResponse, validateOptions } from "@middy/util";
+import { HTTPFacilitatorClient } from "@x402/core/http";
+
+const name = "http-x402";
+const pkg = `@middy/${name}`;
+
+const defaults = {
+ FacilitatorClient: HTTPFacilitatorClient,
+ facilitatorUrl: "https://x402.org/facilitator",
+ price: undefined,
+ decimals: 6,
+ network: "eip155:8453",
+ payTo: undefined,
+ asset: undefined,
+ description: "",
+ mimeType: "application/json",
+ human: undefined,
+};
+
+const optionSchema = {
+ type: "object",
+ properties: {
+ FacilitatorClient: { instanceof: "Function" },
+ facilitatorUrl: { type: "string" },
+ price: { type: "number", exclusiveMinimum: 0 },
+ decimals: { type: "integer" },
+ network: { type: "string" },
+ payTo: { type: "string" },
+ asset: { type: "string" },
+ description: { type: "string" },
+ mimeType: { type: "string" },
+ human: (v) => typeof v === "function",
+ },
+ required: ["price", "payTo", "asset"],
+ additionalProperties: false,
+};
+
+export const httpX402ValidateOptions = (options) =>
+ validateOptions(pkg, optionSchema, options);
+
+const httpX402Middleware = (opts = {}) => {
+ const options = { ...defaults, ...opts };
+ const {
+ FacilitatorClient,
+ facilitatorUrl,
+ price,
+ decimals,
+ network,
+ payTo,
+ asset,
+ description,
+ mimeType,
+ human,
+ } = options;
+
+ const amount = String(Math.round(price * 10 ** decimals));
+ const requirements = {
+ scheme: "exact",
+ network,
+ amount,
+ asset,
+ payTo,
+ maxTimeoutSeconds: 60,
+ description,
+ mimeType,
+ };
+ const facilitator = new FacilitatorClient({ url: facilitatorUrl });
+
+ const httpX402MiddlewareBefore = async (request) => {
+ if (human?.(request)) return;
+
+ const headers = request.event.headers ?? {};
+ const paymentHeader = headers["payment-signature"];
+
+ const resource = buildResource(request.event);
+ const fullRequirements = { ...requirements, resource };
+
+ if (!paymentHeader) {
+ normalizeHttpResponse(request);
+ const paymentRequired = {
+ x402Version: 2,
+ error: "Payment required",
+ accepts: [fullRequirements],
+ };
+ request.response.statusCode = 402;
+ request.response.headers["Content-Type"] = "application/json";
+ request.response.headers["PAYMENT-REQUIRED"] =
+ encodeHeader(paymentRequired);
+ request.response.body = JSON.stringify(paymentRequired);
+ return request.response;
+ }
+
+ let payload;
+ try {
+ payload = decodeHeader(paymentHeader);
+ } catch {
+ normalizeHttpResponse(request);
+ request.response.statusCode = 402;
+ request.response.headers["Content-Type"] = "application/json";
+ request.response.body = JSON.stringify({
+ x402Version: 2,
+ error: "invalid_payment",
+ });
+ return request.response;
+ }
+
+ const verifyResult = await facilitator.verify(payload, fullRequirements);
+ if (!verifyResult.isValid) {
+ normalizeHttpResponse(request);
+ request.response.statusCode = 402;
+ request.response.headers["Content-Type"] = "application/json";
+ request.response.body = JSON.stringify({
+ x402Version: 2,
+ error: verifyResult.invalidReason,
+ });
+ return request.response;
+ }
+
+ request.internal.x402 = { payload, requirements: fullRequirements };
+ };
+
+ const httpX402MiddlewareAfter = async (request) => {
+ const stored = request.internal.x402;
+ if (!stored) return;
+
+ normalizeHttpResponse(request);
+ if (request.response.statusCode >= 400) return;
+
+ const { payload, requirements: fullRequirements } = stored;
+ const settleResult = await facilitator.settle(payload, fullRequirements);
+
+ if (!settleResult.success) {
+ request.response.statusCode = 402;
+ request.response.headers["Content-Type"] = "application/json";
+ request.response.body = JSON.stringify({
+ x402Version: 2,
+ error: settleResult.errorReason,
+ });
+ return;
+ }
+
+ request.internal.x402 = {
+ ...stored,
+ payer: settleResult.payer,
+ transaction: settleResult.transaction,
+ network: settleResult.network,
+ };
+ request.response.headers["PAYMENT-RESPONSE"] = encodeHeader(settleResult);
+ };
+
+ return {
+ before: httpX402MiddlewareBefore,
+ after: httpX402MiddlewareAfter,
+ };
+};
+
+const buildResource = (event) => {
+ if (event.version === "2.0") {
+ return `https://${event.requestContext.domainName}${event.requestContext.http.path}`;
+ }
+ const host = event.headers?.Host ?? event.headers?.host ?? "localhost";
+ return `https://${host}${event.path ?? "/"}`;
+};
+
+const encodeHeader = (obj) =>
+ Buffer.from(JSON.stringify(obj)).toString("base64");
+
+const decodeHeader = (header) =>
+ JSON.parse(Buffer.from(header, "base64").toString());
+
+export default httpX402Middleware;
diff --git a/packages/http-x402/index.test.js b/packages/http-x402/index.test.js
new file mode 100644
index 000000000..1d09ad963
--- /dev/null
+++ b/packages/http-x402/index.test.js
@@ -0,0 +1,453 @@
+import { ok, strictEqual } from "node:assert/strict";
+import { test } from "node:test";
+import middy from "../core/index.js";
+import httpX402, { httpX402ValidateOptions } from "./index.js";
+
+const defaultOptions = {
+ price: 0.001,
+ payTo: "0xpayto",
+ asset: "0xasset",
+};
+
+const defaultContext = { getRemainingTimeInMillis: () => 1000 };
+
+const makePaymentHeader = (payload) =>
+ Buffer.from(JSON.stringify(payload)).toString("base64");
+
+const testPayload = {
+ x402Version: 2,
+ scheme: "exact",
+ network: "eip155:8453",
+ payload: { signature: "0xsig", authorization: {} },
+};
+
+const makeMockClient = (t, verifyResult, settleResult) => {
+ const mockVerify = t.mock.fn(async () => verifyResult);
+ const mockSettle = t.mock.fn(async () => settleResult);
+ class MockFacilitatorClient {
+ verify(...args) {
+ return mockVerify(...args);
+ }
+ settle(...args) {
+ return mockSettle(...args);
+ }
+ }
+ return { MockFacilitatorClient, mockVerify, mockSettle };
+};
+
+const defaultVerifyResult = { isValid: true, payer: "0xpayer" };
+const defaultSettleResult = {
+ success: true,
+ payer: "0xpayer",
+ transaction: "0xtx",
+ network: "eip155:8453",
+};
+
+test("no payment-signature header returns 402", async (t) => {
+ const { MockFacilitatorClient, mockVerify } = makeMockClient(
+ t,
+ defaultVerifyResult,
+ defaultSettleResult,
+ );
+ const handler = middy(() => ({ statusCode: 200, body: "ok" })).use(
+ httpX402({ ...defaultOptions, FacilitatorClient: MockFacilitatorClient }),
+ );
+
+ const response = await handler({ headers: {} }, defaultContext);
+
+ strictEqual(response.statusCode, 402);
+ ok(response.headers["PAYMENT-REQUIRED"]);
+ strictEqual(response.headers["Content-Type"], "application/json");
+ const body = JSON.parse(response.body);
+ strictEqual(body.x402Version, 2);
+ strictEqual(body.error, "Payment required");
+ ok(Array.isArray(body.accepts));
+ strictEqual(body.accepts[0].scheme, "exact");
+ strictEqual(body.accepts[0].amount, "1000");
+ strictEqual(body.accepts[0].network, "eip155:8453");
+ strictEqual(body.accepts[0].payTo, "0xpayto");
+ strictEqual(body.accepts[0].asset, "0xasset");
+ strictEqual(mockVerify.mock.callCount(), 0);
+});
+
+test("missing headers object returns 402", async (t) => {
+ const { MockFacilitatorClient } = makeMockClient(
+ t,
+ defaultVerifyResult,
+ defaultSettleResult,
+ );
+ const handler = middy(() => ({ statusCode: 200, body: "ok" })).use(
+ httpX402({ ...defaultOptions, FacilitatorClient: MockFacilitatorClient }),
+ );
+
+ const response = await handler({}, defaultContext);
+ strictEqual(response.statusCode, 402);
+});
+
+test("malformed payment-signature header returns 402", async (t) => {
+ const { MockFacilitatorClient, mockVerify } = makeMockClient(
+ t,
+ defaultVerifyResult,
+ defaultSettleResult,
+ );
+ const handler = middy(() => ({ statusCode: 200, body: "ok" })).use(
+ httpX402({ ...defaultOptions, FacilitatorClient: MockFacilitatorClient }),
+ );
+
+ const response = await handler(
+ { headers: { "payment-signature": "not!!valid!!base64" } },
+ defaultContext,
+ );
+
+ strictEqual(response.statusCode, 402);
+ const body = JSON.parse(response.body);
+ strictEqual(body.error, "invalid_payment");
+ strictEqual(mockVerify.mock.callCount(), 0);
+});
+
+test("verify failure returns 402 with invalidReason", async (t) => {
+ const { MockFacilitatorClient, mockVerify, mockSettle } = makeMockClient(
+ t,
+ { isValid: false, invalidReason: "invalid_exact_evm_payload_signature" },
+ defaultSettleResult,
+ );
+ const handler = middy(() => ({ statusCode: 200, body: "ok" })).use(
+ httpX402({ ...defaultOptions, FacilitatorClient: MockFacilitatorClient }),
+ );
+
+ const response = await handler(
+ { headers: { "payment-signature": makePaymentHeader(testPayload) } },
+ defaultContext,
+ );
+
+ strictEqual(response.statusCode, 402);
+ const body = JSON.parse(response.body);
+ strictEqual(body.error, "invalid_exact_evm_payload_signature");
+ strictEqual(mockVerify.mock.callCount(), 1);
+ strictEqual(mockSettle.mock.callCount(), 0);
+});
+
+test("verify passes but handler returns 4xx - no settlement", async (t) => {
+ const { MockFacilitatorClient, mockVerify, mockSettle } = makeMockClient(
+ t,
+ defaultVerifyResult,
+ defaultSettleResult,
+ );
+ const handler = middy(() => ({
+ statusCode: 400,
+ body: "bad request",
+ headers: {},
+ })).use(
+ httpX402({ ...defaultOptions, FacilitatorClient: MockFacilitatorClient }),
+ );
+
+ const response = await handler(
+ { headers: { "payment-signature": makePaymentHeader(testPayload) } },
+ defaultContext,
+ );
+
+ strictEqual(response.statusCode, 400);
+ strictEqual(mockVerify.mock.callCount(), 1);
+ strictEqual(mockSettle.mock.callCount(), 0);
+});
+
+test("verify passes but handler returns 5xx - no settlement", async (t) => {
+ const { MockFacilitatorClient, mockSettle } = makeMockClient(
+ t,
+ defaultVerifyResult,
+ defaultSettleResult,
+ );
+ const handler = middy(() => ({
+ statusCode: 500,
+ body: "error",
+ headers: {},
+ })).use(
+ httpX402({ ...defaultOptions, FacilitatorClient: MockFacilitatorClient }),
+ );
+
+ const response = await handler(
+ { headers: { "payment-signature": makePaymentHeader(testPayload) } },
+ defaultContext,
+ );
+
+ strictEqual(response.statusCode, 500);
+ strictEqual(mockSettle.mock.callCount(), 0);
+});
+
+test("verify passes, settle fails - returns 402", async (t) => {
+ const { MockFacilitatorClient, mockSettle } = makeMockClient(
+ t,
+ defaultVerifyResult,
+ { success: false, errorReason: "insufficient_funds" },
+ );
+ const handler = middy(() => ({
+ statusCode: 200,
+ body: "ok",
+ headers: {},
+ })).use(
+ httpX402({ ...defaultOptions, FacilitatorClient: MockFacilitatorClient }),
+ );
+
+ const response = await handler(
+ { headers: { "payment-signature": makePaymentHeader(testPayload) } },
+ defaultContext,
+ );
+
+ strictEqual(response.statusCode, 402);
+ const body = JSON.parse(response.body);
+ strictEqual(body.error, "insufficient_funds");
+ strictEqual(mockSettle.mock.callCount(), 1);
+});
+
+test("verify and settle pass - adds PAYMENT-RESPONSE header", async (t) => {
+ const { MockFacilitatorClient, mockVerify, mockSettle } = makeMockClient(
+ t,
+ defaultVerifyResult,
+ defaultSettleResult,
+ );
+ const handler = middy(() => ({
+ statusCode: 200,
+ body: "ok",
+ headers: {},
+ })).use(
+ httpX402({ ...defaultOptions, FacilitatorClient: MockFacilitatorClient }),
+ );
+
+ const response = await handler(
+ { headers: { "payment-signature": makePaymentHeader(testPayload) } },
+ defaultContext,
+ );
+
+ strictEqual(response.statusCode, 200);
+ ok(response.headers["PAYMENT-RESPONSE"]);
+ strictEqual(mockVerify.mock.callCount(), 1);
+ strictEqual(mockSettle.mock.callCount(), 1);
+});
+
+test("settle passes - internal state has payer and transaction", async (t) => {
+ const { MockFacilitatorClient } = makeMockClient(
+ t,
+ defaultVerifyResult,
+ defaultSettleResult,
+ );
+
+ let capturedInternal;
+ const handler = middy(() => ({
+ statusCode: 200,
+ body: "ok",
+ headers: {},
+ }))
+ .after((request) => {
+ capturedInternal = request.internal.x402;
+ })
+ .use(
+ httpX402({ ...defaultOptions, FacilitatorClient: MockFacilitatorClient }),
+ );
+
+ await handler(
+ { headers: { "payment-signature": makePaymentHeader(testPayload) } },
+ defaultContext,
+ );
+
+ strictEqual(capturedInternal?.payer, "0xpayer");
+ strictEqual(capturedInternal?.transaction, "0xtx");
+});
+
+test("price conversion: 0.001 with default decimals produces amount 1000", async (t) => {
+ const { MockFacilitatorClient, mockVerify } = makeMockClient(
+ t,
+ defaultVerifyResult,
+ defaultSettleResult,
+ );
+ const handler = middy(() => ({
+ statusCode: 200,
+ body: "ok",
+ headers: {},
+ })).use(
+ httpX402({ ...defaultOptions, FacilitatorClient: MockFacilitatorClient }),
+ );
+
+ await handler(
+ { headers: { "payment-signature": makePaymentHeader(testPayload) } },
+ defaultContext,
+ );
+
+ const [, requirements] = mockVerify.mock.calls[0].arguments;
+ strictEqual(requirements.amount, "1000");
+});
+
+test("price conversion: 0.01 with decimals:6 produces amount 10000", async (t) => {
+ const { MockFacilitatorClient, mockVerify } = makeMockClient(
+ t,
+ defaultVerifyResult,
+ defaultSettleResult,
+ );
+ const handler = middy(() => ({
+ statusCode: 200,
+ body: "ok",
+ headers: {},
+ })).use(
+ httpX402({
+ ...defaultOptions,
+ price: 0.01,
+ decimals: 6,
+ FacilitatorClient: MockFacilitatorClient,
+ }),
+ );
+
+ await handler(
+ { headers: { "payment-signature": makePaymentHeader(testPayload) } },
+ defaultContext,
+ );
+
+ const [, requirements] = mockVerify.mock.calls[0].arguments;
+ strictEqual(requirements.amount, "10000");
+});
+
+test("human returns true - skips payment entirely", async (t) => {
+ const { MockFacilitatorClient, mockVerify } = makeMockClient(
+ t,
+ defaultVerifyResult,
+ defaultSettleResult,
+ );
+ const handler = middy(() => ({ statusCode: 200, body: "ok" })).use(
+ httpX402({
+ ...defaultOptions,
+ FacilitatorClient: MockFacilitatorClient,
+ human: () => true,
+ }),
+ );
+
+ const response = await handler({ headers: {} }, defaultContext);
+
+ strictEqual(response.statusCode, 200);
+ strictEqual(mockVerify.mock.callCount(), 0);
+});
+
+test("human returns false - normal payment flow", async (t) => {
+ const { MockFacilitatorClient } = makeMockClient(
+ t,
+ defaultVerifyResult,
+ defaultSettleResult,
+ );
+ const handler = middy(() => ({ statusCode: 200, body: "ok" })).use(
+ httpX402({
+ ...defaultOptions,
+ FacilitatorClient: MockFacilitatorClient,
+ human: () => false,
+ }),
+ );
+
+ const response = await handler({ headers: {} }, defaultContext);
+ strictEqual(response.statusCode, 402);
+});
+
+test("API Gateway v1 resource URL from Host header", async (t) => {
+ const { MockFacilitatorClient, mockVerify } = makeMockClient(
+ t,
+ defaultVerifyResult,
+ defaultSettleResult,
+ );
+ const handler = middy(() => ({
+ statusCode: 200,
+ body: "ok",
+ headers: {},
+ })).use(
+ httpX402({ ...defaultOptions, FacilitatorClient: MockFacilitatorClient }),
+ );
+
+ await handler(
+ {
+ headers: {
+ Host: "api.example.com",
+ "payment-signature": makePaymentHeader(testPayload),
+ },
+ path: "/api/data",
+ },
+ defaultContext,
+ );
+
+ const [, requirements] = mockVerify.mock.calls[0].arguments;
+ strictEqual(requirements.resource, "https://api.example.com/api/data");
+});
+
+test("API Gateway v2 resource URL from requestContext", async (t) => {
+ const { MockFacilitatorClient, mockVerify } = makeMockClient(
+ t,
+ defaultVerifyResult,
+ defaultSettleResult,
+ );
+ const handler = middy(() => ({
+ statusCode: 200,
+ body: "ok",
+ headers: {},
+ })).use(
+ httpX402({ ...defaultOptions, FacilitatorClient: MockFacilitatorClient }),
+ );
+
+ await handler(
+ {
+ version: "2.0",
+ headers: { "payment-signature": makePaymentHeader(testPayload) },
+ requestContext: {
+ domainName: "api.example.com",
+ http: { path: "/api/data" },
+ },
+ },
+ defaultContext,
+ );
+
+ const [, requirements] = mockVerify.mock.calls[0].arguments;
+ strictEqual(requirements.resource, "https://api.example.com/api/data");
+});
+
+test("httpX402ValidateOptions - missing required field payTo throws", () => {
+ let threw = false;
+ try {
+ httpX402ValidateOptions({ price: 0.001, asset: "0x" });
+ } catch (e) {
+ threw = true;
+ ok(e.message.includes("payTo"));
+ }
+ ok(threw);
+});
+
+test("httpX402ValidateOptions - missing required field asset throws", () => {
+ let threw = false;
+ try {
+ httpX402ValidateOptions({ price: 0.001, payTo: "0x" });
+ } catch (e) {
+ threw = true;
+ ok(e.message.includes("asset"));
+ }
+ ok(threw);
+});
+
+test("httpX402ValidateOptions - unknown option throws", () => {
+ let threw = false;
+ try {
+ httpX402ValidateOptions({
+ price: 0.001,
+ payTo: "0x",
+ asset: "0x",
+ unknown: true,
+ });
+ } catch (e) {
+ threw = true;
+ ok(e.message.includes("unknown"));
+ }
+ ok(threw);
+});
+
+test("httpX402ValidateOptions - valid minimal options pass", () => {
+ httpX402ValidateOptions({ price: 0.001, payTo: "0x", asset: "0x" });
+});
+
+test("httpX402ValidateOptions - valid options with human function pass", () => {
+ httpX402ValidateOptions({
+ price: 0.001,
+ payTo: "0x",
+ asset: "0x",
+ human: () => false,
+ });
+});
diff --git a/packages/http-x402/index.tst.ts b/packages/http-x402/index.tst.ts
new file mode 100644
index 000000000..babea9581
--- /dev/null
+++ b/packages/http-x402/index.tst.ts
@@ -0,0 +1,40 @@
+import type middy from "@middy/core";
+import { expect, test } from "tstyche";
+import httpX402, { type Options } from "./index.js";
+
+test("requires price, payTo, and asset", () => {
+ const middleware = httpX402({
+ price: 0.001,
+ payTo: "0xpayto",
+ asset: "0xasset",
+ });
+ expect(middleware).type.toBe();
+});
+
+test("all options", () => {
+ const middleware = httpX402({
+ facilitatorUrl: "https://my-facilitator.example.com/",
+ price: 0.001,
+ decimals: 6,
+ network: "eip155:8453",
+ payTo: "0xpayto",
+ asset: "0xasset",
+ description: "Premium API access",
+ mimeType: "application/json",
+ human: (request) =>
+ (request.event as { headers?: Record })?.headers?.[
+ "x-human"
+ ] === "true",
+ });
+ expect(middleware).type.toBe();
+});
+
+test("Options type requires price, payTo, asset", () => {
+ // @ts-expect-error missing the following properties
+ const _opts: Options = {};
+});
+
+test("Options type allows partial optional fields", () => {
+ const opts: Options = { price: 0.001, payTo: "0x", asset: "0x" };
+ expect(opts).type.toBe();
+});
diff --git a/packages/http-x402/package.json b/packages/http-x402/package.json
new file mode 100644
index 000000000..df6ac7910
--- /dev/null
+++ b/packages/http-x402/package.json
@@ -0,0 +1,76 @@
+{
+ "name": "@middy/http-x402",
+ "version": "7.3.4",
+ "description": "x402 payment middleware for the middy framework",
+ "type": "module",
+ "engines": {
+ "node": ">=22"
+ },
+ "engineStrict": true,
+ "publishConfig": {
+ "access": "public"
+ },
+ "module": "./index.js",
+ "sideEffects": false,
+ "exports": {
+ ".": {
+ "import": {
+ "types": "./index.d.ts",
+ "default": "./index.js"
+ }
+ }
+ },
+ "types": "index.d.ts",
+ "files": [
+ "index.js",
+ "index.d.ts"
+ ],
+ "scripts": {
+ "test": "npm run test:unit && npm run test:fuzz",
+ "test:unit": "node --test",
+ "test:fuzz": "node --test index.fuzz.js",
+ "test:perf": "node --test index.perf.js"
+ },
+ "license": "MIT",
+ "keywords": [
+ "Lambda",
+ "Middleware",
+ "Serverless",
+ "Framework",
+ "AWS",
+ "AWS Lambda",
+ "Middy",
+ "HTTP",
+ "x402",
+ "Payments",
+ "Web3"
+ ],
+ "author": {
+ "name": "Middy contributors",
+ "url": "https://github.com/middyjs/middy/graphs/contributors"
+ },
+ "repository": {
+ "type": "git",
+ "url": "git+https://github.com/middyjs/middy.git",
+ "directory": "packages/http-x402"
+ },
+ "bugs": {
+ "url": "https://github.com/middyjs/middy/issues"
+ },
+ "homepage": "https://middy.js.org",
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/willfarrell"
+ },
+ "peerDependencies": {
+ "@x402/core": "^2.0.0"
+ },
+ "dependencies": {
+ "@middy/util": "7.3.4"
+ },
+ "devDependencies": {
+ "@middy/core": "7.3.4",
+ "@x402/core": "^2.0.0",
+ "@types/node": "^22.0.0"
+ }
+}
diff --git a/packages/input-output-logger/package.json b/packages/input-output-logger/package.json
index 5892b3ae5..bb133ef63 100644
--- a/packages/input-output-logger/package.json
+++ b/packages/input-output-logger/package.json
@@ -1,6 +1,6 @@
{
"name": "@middy/input-output-logger",
- "version": "7.3.4",
+ "version": "7.4.0",
"description": "Input and output logger middleware for the middy framework",
"type": "module",
"engines": {
@@ -62,11 +62,11 @@
"url": "https://github.com/sponsors/willfarrell"
},
"dependencies": {
- "@middy/util": "7.3.4"
+ "@middy/util": "7.4.0"
},
"devDependencies": {
"@datastream/core": "0.4.0",
- "@middy/core": "7.3.4",
+ "@middy/core": "7.4.0",
"@types/aws-lambda": "^8.0.0",
"@types/node": "^22.0.0"
}
diff --git a/packages/rds-signer/index.js b/packages/rds-signer/index.js
index cb1aa687c..cbb390b9e 100644
--- a/packages/rds-signer/index.js
+++ b/packages/rds-signer/index.js
@@ -38,7 +38,7 @@ const optionSchema = {
port: { type: "integer", minimum: 1, maximum: 65535 },
username: { type: "string" },
},
- required: ["hostname", "port", "username"],
+ required: [],
additionalProperties: true,
},
},
@@ -60,6 +60,18 @@ export const rdsSignerValidateOptions = (options) =>
const rdsSignerMiddleware = (opts = {}) => {
const options = { ...defaults, ...opts };
+ const defaultFetchData = {
+ hostname: process.env.PGHOST ?? process.env.DBHOST,
+ port: Number.parseInt(
+ process.env.PGPORT ?? process.env.DBPORT ?? "5432",
+ 10,
+ ),
+ username: process.env.PGUSER ?? process.env.DBUSER,
+ };
+ for (const key of Object.keys(options.fetchData)) {
+ options.fetchData[key] = { ...defaultFetchData, ...options.fetchData[key] };
+ }
+
const fetchDataKeys = Object.keys(options.fetchData);
const clients = {};
const fetchRequest = (request, cachedValues = {}) => {
@@ -67,17 +79,19 @@ const rdsSignerMiddleware = (opts = {}) => {
for (const internalKey of fetchDataKeys) {
if (cachedValues[internalKey]) continue;
+ const signerConfig = options.fetchData[internalKey];
clients[internalKey] ??= new options.AwsClient({
...options.awsClientOptions,
- ...options.fetchData[internalKey],
+ ...signerConfig,
});
+ const method = "getAuthToken";
values[internalKey] = clients[internalKey]
- .getAuthToken()
+ [method]()
.then((token) => {
// Catch Missing token, this usually means there is something wrong with the credentials
if (!token.includes("X-Amz-Security-Token=")) {
throw new Error("X-Amz-Security-Token Missing", {
- cause: { package: pkg },
+ cause: { package: pkg, method },
});
}
return token;
diff --git a/packages/rds-signer/index.test.js b/packages/rds-signer/index.test.js
index 8718f6e4a..0dd74b396 100644
--- a/packages/rds-signer/index.test.js
+++ b/packages/rds-signer/index.test.js
@@ -1,9 +1,21 @@
import { deepStrictEqual, ok, strictEqual } from "node:assert/strict";
-import { test } from "node:test";
+import { after, before, test } from "node:test";
import middy from "../core/index.js";
import { clearCache, getInternal } from "../util/index.js";
import rdsSigner, { rdsSignerValidateOptions } from "./index.js";
+before(() => {
+ process.env.PGHOST = "hostname";
+ process.env.PGPORT = "5432";
+ process.env.PGUSER = "username";
+});
+
+after(() => {
+ delete process.env.PGHOST;
+ delete process.env.PGPORT;
+ delete process.env.PGUSER;
+});
+
test.afterEach((t) => {
t.mock.reset();
clearCache();
@@ -37,12 +49,7 @@ test("It should set token to internal storage (token)", async (t) => {
AwsClient,
cacheExpiry: 0,
fetchData: {
- token: {
- region: "us-east-1",
- hostname: "hostname",
- username: "username",
- port: 5432,
- },
+ token: { region: "us-east-1" },
},
disablePrefetch: true,
}),
@@ -82,18 +89,8 @@ test("It should set tokens to internal storage (token)", async (t) => {
AwsClient,
cacheExpiry: 0,
fetchData: {
- token1: {
- region: "us-east-1",
- hostname: "hostname-reader",
- username: "username",
- port: 5432,
- },
- token2: {
- region: "us-east-1",
- hostname: "hostname-writer",
- username: "username",
- port: 5432,
- },
+ token1: { region: "us-east-1", hostname: "hostname-reader" },
+ token2: { region: "us-east-1", hostname: "hostname-writer" },
},
disablePrefetch: true,
}),
@@ -126,12 +123,7 @@ test("It should set Signer token to internal storage without prefetch", async (t
AwsClient,
cacheExpiry: 0,
fetchData: {
- token: {
- region: "us-east-1",
- hostname: "hostname",
- username: "username",
- port: 5432,
- },
+ token: { region: "us-east-1" },
},
disablePrefetch: true,
}),
@@ -163,12 +155,7 @@ test("It should set Signer token to context", async (t) => {
AwsClient,
cacheExpiry: 0,
fetchData: {
- token: {
- region: "us-east-1",
- hostname: "hostname",
- username: "username",
- port: 5432,
- },
+ token: { region: "us-east-1" },
},
setToContext: true,
disablePrefetch: true,
@@ -202,12 +189,7 @@ test("It should not call aws-sdk again if parameter is cached", async (t) => {
AwsClient,
cacheExpiry: -1,
fetchData: {
- token: {
- region: "us-east-1",
- hostname: "hostname",
- username: "username",
- port: 5432,
- },
+ token: { region: "us-east-1" },
},
}),
)
@@ -243,12 +225,7 @@ test("It should call aws-sdk if cache enabled but cached param has expired", asy
AwsClient,
cacheExpiry: 0,
fetchData: {
- token: {
- region: "us-east-1",
- hostname: "hostname",
- username: "username",
- port: 5432,
- },
+ token: { region: "us-east-1" },
},
disablePrefetch: true,
}),
@@ -273,12 +250,7 @@ test("It should catch if an error is returned from fetch", async (t) => {
AwsClient,
cacheExpiry: 0,
fetchData: {
- token: {
- region: "us-east-1",
- hostname: "hostname",
- username: "username",
- port: 5432,
- },
+ token: { region: "us-east-1" },
},
setToContext: true,
disablePrefetch: true,
@@ -304,12 +276,7 @@ test("It should catch if an invalid response is returned from fetch", async (t)
AwsClient,
cacheExpiry: 0,
fetchData: {
- token: {
- region: "us-east-1",
- hostname: "hostname",
- username: "username",
- port: 5432,
- },
+ token: { region: "us-east-1" },
},
setToContext: true,
disablePrefetch: true,
@@ -323,7 +290,7 @@ test("It should catch if an invalid response is returned from fetch", async (t)
strictEqual(e.message, "Failed to resolve internal values");
deepStrictEqual(e.cause.data, [
new Error("X-Amz-Security-Token Missing", {
- cause: { package: "@middy/rds-signer" },
+ cause: { package: "@middy/rds-signer", method: "getAuthToken" },
}),
]);
}
@@ -370,18 +337,8 @@ test("It should skip fetching already cached values when fetching multiple keys"
AwsClient,
cacheExpiry: 1000,
fetchData: {
- token1: {
- region: "us-east-1",
- hostname: "hostname-reader",
- username: "username",
- port: 5432,
- },
- token2: {
- region: "us-east-1",
- hostname: "hostname-writer",
- username: "username",
- port: 5432,
- },
+ token1: { region: "us-east-1", hostname: "hostname-reader" },
+ token2: { region: "us-east-1", hostname: "hostname-writer" },
},
}),
)
@@ -408,6 +365,109 @@ test("It should export rdsSignerParam helper for TypeScript type inference", asy
strictEqual(result, paramName);
});
+test("It should use DBHOST/DBPORT/DBUSER env var defaults as fallback", async (t) => {
+ const savedPGHOST = process.env.PGHOST;
+ const savedPGPORT = process.env.PGPORT;
+ const savedPGUSER = process.env.PGUSER;
+ delete process.env.PGHOST;
+ delete process.env.PGPORT;
+ delete process.env.PGUSER;
+ process.env.DBHOST = "db.example.com";
+ process.env.DBPORT = "5434";
+ process.env.DBUSER = "dbuser";
+ t.after(() => {
+ delete process.env.DBHOST;
+ delete process.env.DBPORT;
+ delete process.env.DBUSER;
+ process.env.PGHOST = savedPGHOST;
+ process.env.PGPORT = savedPGPORT;
+ process.env.PGUSER = savedPGUSER;
+ });
+
+ let receivedConfig;
+ class AwsClient {
+ constructor(config) {
+ receivedConfig = config;
+ }
+ getAuthToken = t.mock.fn(
+ async () => "https://rds.amazonaws.com?X-Amz-Security-Token=token",
+ );
+ }
+ const handler = middy(() => {}).use(
+ rdsSigner({
+ AwsClient,
+ cacheExpiry: 0,
+ fetchData: { token: {} },
+ disablePrefetch: true,
+ }),
+ );
+
+ await handler(defaultEvent, defaultContext);
+ strictEqual(receivedConfig.hostname, "db.example.com");
+ strictEqual(receivedConfig.port, 5434);
+ strictEqual(receivedConfig.username, "dbuser");
+});
+
+test("It should use default port 5432 when no PGPORT/DBPORT env var is set", async (t) => {
+ const savedPGPORT = process.env.PGPORT;
+ delete process.env.PGPORT;
+ t.after(() => {
+ process.env.PGPORT = savedPGPORT;
+ });
+
+ let receivedConfig;
+ class AwsClient {
+ constructor(config) {
+ receivedConfig = config;
+ }
+ getAuthToken = t.mock.fn(
+ async () => "https://rds.amazonaws.com?X-Amz-Security-Token=token",
+ );
+ }
+ const handler = middy(() => {}).use(
+ rdsSigner({
+ AwsClient,
+ cacheExpiry: 0,
+ fetchData: { token: {} },
+ disablePrefetch: true,
+ }),
+ );
+
+ await handler(defaultEvent, defaultContext);
+ strictEqual(receivedConfig.port, 5432);
+});
+
+test("It should prefer explicit fetchData values over env var defaults", async (t) => {
+ let receivedConfig;
+ class AwsClient {
+ constructor(config) {
+ receivedConfig = config;
+ }
+ getAuthToken = t.mock.fn(
+ async () => "https://rds.amazonaws.com?X-Amz-Security-Token=token",
+ );
+ }
+ const handler = middy(() => {}).use(
+ rdsSigner({
+ AwsClient,
+ cacheExpiry: 0,
+ fetchData: {
+ token: {
+ hostname: "explicit.example.com",
+ port: 9999,
+ username: "explicit",
+ },
+ },
+ disablePrefetch: true,
+ }),
+ );
+
+ await handler(defaultEvent, defaultContext);
+ strictEqual(receivedConfig.hostname, "explicit.example.com");
+ strictEqual(receivedConfig.port, 9999);
+ strictEqual(receivedConfig.username, "explicit");
+});
+
test("rdsSignerValidateOptions accepts valid options and rejects typos", () => {
rdsSignerValidateOptions({ cacheKey: "x", cacheExpiry: 0 });
rdsSignerValidateOptions({});
@@ -442,16 +502,11 @@ test("rdsSignerValidateOptions accepts valid fetchData entry", () => {
});
});
-test("rdsSignerValidateOptions rejects fetchData entry missing required fields", () => {
- try {
- rdsSignerValidateOptions({
- fetchData: { token: { hostname: "db.example.com" } },
- });
- ok(false, "expected throw");
- } catch (e) {
- ok(e instanceof TypeError);
- strictEqual(e.cause.package, "@middy/rds-signer");
- }
+test("rdsSignerValidateOptions accepts fetchData entry relying on env var defaults", () => {
+ rdsSignerValidateOptions({ fetchData: { token: {} } });
+ rdsSignerValidateOptions({
+ fetchData: { token: { hostname: "db.example.com" } },
+ });
});
test("rdsSignerValidateOptions rejects fetchData entry with non-integer port", () => {
diff --git a/packages/rds-signer/package.json b/packages/rds-signer/package.json
index 2b288e7de..a6ea8fb0a 100644
--- a/packages/rds-signer/package.json
+++ b/packages/rds-signer/package.json
@@ -1,6 +1,6 @@
{
"name": "@middy/rds-signer",
- "version": "7.3.4",
+ "version": "7.4.0",
"description": "RDS (Relational Database Service) credentials middleware for the middy framework",
"type": "module",
"engines": {
@@ -70,11 +70,11 @@
}
},
"dependencies": {
- "@middy/util": "7.3.4"
+ "@middy/util": "7.4.0"
},
"devDependencies": {
"@aws-sdk/rds-signer": "^3.0.0",
- "@middy/core": "7.3.4",
+ "@middy/core": "7.4.0",
"@types/aws-lambda": "^8.0.0",
"@types/node": "^22.0.0",
"aws-xray-sdk": "^3.3.3"
diff --git a/packages/s3-object-response/package.json b/packages/s3-object-response/package.json
index 9c94451ab..ec2f354eb 100644
--- a/packages/s3-object-response/package.json
+++ b/packages/s3-object-response/package.json
@@ -1,6 +1,6 @@
{
"name": "@middy/s3-object-response",
- "version": "7.3.4",
+ "version": "7.4.0",
"description": "S3 object response handling middleware for the middy framework",
"type": "module",
"engines": {
@@ -70,11 +70,11 @@
}
},
"dependencies": {
- "@middy/util": "7.3.4"
+ "@middy/util": "7.4.0"
},
"devDependencies": {
"@aws-sdk/client-s3": "^3.0.0",
- "@middy/core": "7.3.4",
+ "@middy/core": "7.4.0",
"@types/aws-lambda": "^8.0.0",
"@types/node": "^22.0.0",
"aws-xray-sdk": "^3.3.3"
diff --git a/packages/s3/package.json b/packages/s3/package.json
index c8fde916b..66c776f36 100644
--- a/packages/s3/package.json
+++ b/packages/s3/package.json
@@ -1,6 +1,6 @@
{
"name": "@middy/s3",
- "version": "7.3.4",
+ "version": "7.4.0",
"description": "S3 middleware for the middy framework",
"type": "module",
"engines": {
@@ -60,7 +60,7 @@
"url": "https://github.com/sponsors/willfarrell"
},
"dependencies": {
- "@middy/util": "7.3.4"
+ "@middy/util": "7.4.0"
},
"peerDependencies": {
"@aws-sdk/client-s3": "^3.0.0"
@@ -72,7 +72,7 @@
},
"devDependencies": {
"@aws-sdk/client-s3": "^3.0.0",
- "@middy/core": "7.3.4",
+ "@middy/core": "7.4.0",
"@types/aws-lambda": "^8.0.0",
"@types/node": "^22.0.0",
"aws-xray-sdk": "^3.3.3"
diff --git a/packages/secrets-manager/package.json b/packages/secrets-manager/package.json
index 63f77bd38..522defbac 100644
--- a/packages/secrets-manager/package.json
+++ b/packages/secrets-manager/package.json
@@ -1,6 +1,6 @@
{
"name": "@middy/secrets-manager",
- "version": "7.3.4",
+ "version": "7.4.0",
"description": "Secrets Manager middleware for the middy framework",
"type": "module",
"engines": {
@@ -60,7 +60,7 @@
"url": "https://github.com/sponsors/willfarrell"
},
"dependencies": {
- "@middy/util": "7.3.4"
+ "@middy/util": "7.4.0"
},
"peerDependencies": {
"@aws-sdk/client-secrets-manager": "^3.0.0"
@@ -72,7 +72,7 @@
},
"devDependencies": {
"@aws-sdk/client-secrets-manager": "^3.0.0",
- "@middy/core": "7.3.4",
+ "@middy/core": "7.4.0",
"@types/aws-lambda": "^8.0.0",
"@types/node": "^22.0.0",
"aws-xray-sdk": "^3.3.3"
diff --git a/packages/service-discovery/package.json b/packages/service-discovery/package.json
index 26d2221c8..acb98f3bc 100644
--- a/packages/service-discovery/package.json
+++ b/packages/service-discovery/package.json
@@ -1,6 +1,6 @@
{
"name": "@middy/service-discovery",
- "version": "7.3.4",
+ "version": "7.4.0",
"description": "Service Discovery (Cloud Map) instances middleware for the middy framework",
"type": "module",
"engines": {
@@ -70,11 +70,11 @@
}
},
"dependencies": {
- "@middy/util": "7.3.4"
+ "@middy/util": "7.4.0"
},
"devDependencies": {
"@aws-sdk/client-servicediscovery": "^3.0.0",
- "@middy/core": "7.3.4",
+ "@middy/core": "7.4.0",
"@types/aws-lambda": "^8.0.0",
"@types/node": "^22.0.0",
"aws-xray-sdk": "^3.3.3"
diff --git a/packages/sqs-partial-batch-failure/package.json b/packages/sqs-partial-batch-failure/package.json
index e0ec6acec..2d2eb5f7d 100644
--- a/packages/sqs-partial-batch-failure/package.json
+++ b/packages/sqs-partial-batch-failure/package.json
@@ -1,6 +1,6 @@
{
"name": "@middy/sqs-partial-batch-failure",
- "version": "7.3.4",
+ "version": "7.4.0",
"description": "SQS partial batch failure middleware for the middy framework",
"type": "module",
"engines": {
@@ -63,7 +63,7 @@
},
"devDependencies": {
"@aws-sdk/client-sqs": "^3.0.0",
- "@middy/core": "7.3.4",
+ "@middy/core": "7.4.0",
"@serverless/event-mocks": "^1.1.1",
"@types/aws-lambda": "^8.0.0",
"@types/node": "^22.0.0"
diff --git a/packages/ssm/package.json b/packages/ssm/package.json
index c86741e64..d8e9ca59a 100644
--- a/packages/ssm/package.json
+++ b/packages/ssm/package.json
@@ -1,6 +1,6 @@
{
"name": "@middy/ssm",
- "version": "7.3.4",
+ "version": "7.4.0",
"description": "SSM (EC2 Systems Manager) parameters middleware for the middy framework",
"type": "module",
"engines": {
@@ -62,7 +62,7 @@
"url": "https://github.com/sponsors/willfarrell"
},
"dependencies": {
- "@middy/util": "7.3.4"
+ "@middy/util": "7.4.0"
},
"peerDependencies": {
"@aws-sdk/client-ssm": "^3.0.0"
@@ -74,7 +74,7 @@
},
"devDependencies": {
"@aws-sdk/client-ssm": "^3.0.0",
- "@middy/core": "7.3.4",
+ "@middy/core": "7.4.0",
"@types/aws-lambda": "^8.0.0",
"@types/node": "^22.0.0",
"aws-xray-sdk": "^3.3.3"
diff --git a/packages/sts/package.json b/packages/sts/package.json
index e21c2078c..59dae742e 100644
--- a/packages/sts/package.json
+++ b/packages/sts/package.json
@@ -1,6 +1,6 @@
{
"name": "@middy/sts",
- "version": "7.3.4",
+ "version": "7.4.0",
"description": "STS (Security Token Service) credentials middleware for the middy framework",
"type": "module",
"engines": {
@@ -62,7 +62,7 @@
"url": "https://github.com/sponsors/willfarrell"
},
"dependencies": {
- "@middy/util": "7.3.4"
+ "@middy/util": "7.4.0"
},
"peerDependencies": {
"@aws-sdk/client-sts": "^3.0.0"
@@ -74,7 +74,7 @@
},
"devDependencies": {
"@aws-sdk/client-sts": "^3.0.0",
- "@middy/core": "7.3.4",
+ "@middy/core": "7.4.0",
"@types/aws-lambda": "^8.0.0",
"@types/node": "^22.0.0",
"aws-xray-sdk": "^3.3.3"
diff --git a/packages/util/index.js b/packages/util/index.js
index 12281f73d..4775b1d14 100644
--- a/packages/util/index.js
+++ b/packages/util/index.js
@@ -15,7 +15,8 @@
// exclusiveMaximum?, multipleOf?, minLength?, maxLength?, pattern? }
// Numeric: `minimum`/`maximum` (inclusive), `exclusiveMinimum`/
// `exclusiveMaximum` (exclusive), `multipleOf` (number/integer).
-// String: `minLength`/`maxLength` (string length), `pattern` (regex source).
+// String: `minLength`/`maxLength` (string length), `pattern` (regex
+// source string per JSON Schema).
// { type: 'object' | 'object?', properties?: {...}, additionalProperties?: }
// `properties` validates known keys with the flat-schema form.
// `additionalProperties` validates every other key's value against the
@@ -215,7 +216,7 @@ const checkRule = (rule, value, path, fail) => {
fail(`Option '${path}' must be a multiple of ${multipleOf}`);
}
}
- if (pattern !== undefined && !pattern.test(value)) {
+ if (pattern !== undefined && !new RegExp(pattern).test(value)) {
fail(`Option '${path}' must match pattern ${pattern}`);
}
if (minLength !== undefined && value.length < minLength) {
diff --git a/packages/util/package.json b/packages/util/package.json
index e1bca6712..9ab892a89 100644
--- a/packages/util/package.json
+++ b/packages/util/package.json
@@ -1,6 +1,6 @@
{
"name": "@middy/util",
- "version": "7.3.4",
+ "version": "7.4.0",
"description": "🛵 The stylish Node.js middleware engine for AWS Lambda (util package)",
"type": "module",
"engines": {
@@ -57,7 +57,7 @@
},
"devDependencies": {
"@aws-sdk/client-ssm": "^3.0.0",
- "@middy/core": "7.3.4",
+ "@middy/core": "7.4.0",
"@types/aws-lambda": "^8.0.0",
"@types/node": "^22.0.0",
"aws-xray-sdk": "^3.3.3"
diff --git a/packages/validator/package.json b/packages/validator/package.json
index 66fdee114..d3b43a873 100644
--- a/packages/validator/package.json
+++ b/packages/validator/package.json
@@ -1,6 +1,6 @@
{
"name": "@middy/validator",
- "version": "7.3.4",
+ "version": "7.4.0",
"description": "Validator middleware for the middy framework",
"type": "module",
"engines": {
@@ -69,7 +69,7 @@
"url": "https://github.com/sponsors/willfarrell"
},
"dependencies": {
- "@middy/util": "7.3.4",
+ "@middy/util": "7.4.0",
"ajv": "8.20.0",
"ajv-errors": "3.0.0",
"ajv-formats": "3.0.1",
@@ -78,7 +78,7 @@
"ajv-keywords": "5.1.0"
},
"devDependencies": {
- "@middy/core": "7.3.4",
+ "@middy/core": "7.4.0",
"@types/aws-lambda": "^8.0.0",
"@types/http-errors": "^2.0.0",
"@types/node": "^22.0.0",
diff --git a/packages/warmup/package.json b/packages/warmup/package.json
index 7518bdecb..1e024dfa0 100644
--- a/packages/warmup/package.json
+++ b/packages/warmup/package.json
@@ -1,6 +1,6 @@
{
"name": "@middy/warmup",
- "version": "7.3.4",
+ "version": "7.4.0",
"description": "Warmup (cold start mitigation) middleware for the middy framework",
"type": "module",
"engines": {
@@ -62,7 +62,7 @@
"url": "https://github.com/sponsors/willfarrell"
},
"devDependencies": {
- "@middy/core": "7.3.4",
+ "@middy/core": "7.4.0",
"@types/aws-lambda": "^8.0.0",
"@types/node": "^22.0.0"
}
diff --git a/packages/ws-json-body-parser/package.json b/packages/ws-json-body-parser/package.json
index 9d00dedd3..0bdcb154d 100644
--- a/packages/ws-json-body-parser/package.json
+++ b/packages/ws-json-body-parser/package.json
@@ -1,6 +1,6 @@
{
"name": "@middy/ws-json-body-parser",
- "version": "7.3.4",
+ "version": "7.4.0",
"description": "WebSocket JSON body parser middleware for the middy framework",
"type": "module",
"engines": {
@@ -64,10 +64,10 @@
"url": "https://github.com/sponsors/willfarrell"
},
"dependencies": {
- "@middy/util": "7.3.4"
+ "@middy/util": "7.4.0"
},
"devDependencies": {
- "@middy/core": "7.3.4",
+ "@middy/core": "7.4.0",
"@types/aws-lambda": "^8.0.0",
"@types/node": "^22.0.0",
"type-fest": "^5.0.0"
diff --git a/packages/ws-response/package.json b/packages/ws-response/package.json
index 8d1367139..0fad8b7e2 100644
--- a/packages/ws-response/package.json
+++ b/packages/ws-response/package.json
@@ -1,6 +1,6 @@
{
"name": "@middy/ws-response",
- "version": "7.3.4",
+ "version": "7.4.0",
"description": "WebSocket response handling middleware for the middy framework",
"type": "module",
"engines": {
@@ -62,7 +62,7 @@
"url": "https://github.com/sponsors/willfarrell"
},
"dependencies": {
- "@middy/util": "7.3.4"
+ "@middy/util": "7.4.0"
},
"peerDependencies": {
"@aws-sdk/client-apigatewaymanagementapi": "^3.0.0"
@@ -74,7 +74,7 @@
},
"devDependencies": {
"@aws-sdk/client-apigatewaymanagementapi": "^3.0.0",
- "@middy/core": "7.3.4",
+ "@middy/core": "7.4.0",
"@types/aws-lambda": "^8.0.0",
"@types/node": "^22.0.0",
"aws-xray-sdk": "^3.3.3"
diff --git a/packages/ws-router/package.json b/packages/ws-router/package.json
index aed714c5b..8dee4e917 100644
--- a/packages/ws-router/package.json
+++ b/packages/ws-router/package.json
@@ -1,6 +1,6 @@
{
"name": "@middy/ws-router",
- "version": "7.3.4",
+ "version": "7.4.0",
"description": "WebSocket event router for the middy framework",
"type": "module",
"engines": {
@@ -62,10 +62,10 @@
"url": "https://github.com/sponsors/willfarrell"
},
"dependencies": {
- "@middy/util": "7.3.4"
+ "@middy/util": "7.4.0"
},
"devDependencies": {
- "@middy/core": "7.3.4",
+ "@middy/core": "7.4.0",
"@types/aws-lambda": "^8.0.0",
"@types/node": "^22.0.0"
}
diff --git a/websites/middy.js.org/package.json b/websites/middy.js.org/package.json
index c172c56be..dab5f11a5 100644
--- a/websites/middy.js.org/package.json
+++ b/websites/middy.js.org/package.json
@@ -2,7 +2,7 @@
"name": "middy.js.org",
"description": "SvelteKit SSR",
"private": true,
- "version": "7.3.4",
+ "version": "7.4.0",
"type": "module",
"scripts": {
"start": "vite dev",
diff --git a/websites/middy.js.org/src/components/docs/AsideNav.svelte b/websites/middy.js.org/src/components/docs/AsideNav.svelte
index c7bdcff80..4be51527a 100644
--- a/websites/middy.js.org/src/components/docs/AsideNav.svelte
+++ b/websites/middy.js.org/src/components/docs/AsideNav.svelte
@@ -31,6 +31,7 @@ const nav = {
"cloudwatch-metrics": "/docs/middlewares/cloudwatch-metrics",
"do-not-wait-for-empty-event-loop":
"/docs/middlewares/do-not-wait-for-empty-event-loop",
+ "dsql-signer": "/docs/middlewares/dsql-signer",
dynamodb: "/docs/middlewares/dynamodb",
"error-logger": "/docs/middlewares/error-logger",
"event-normalizer": "/docs/middlewares/event-normalizer",
diff --git a/websites/middy.js.org/src/routes/docs/best-practices/bundling/+page.md b/websites/middy.js.org/src/routes/docs/best-practices/bundling/+page.md
index 29f953247..d3fc78767 100644
--- a/websites/middy.js.org/src/routes/docs/best-practices/bundling/+page.md
+++ b/websites/middy.js.org/src/routes/docs/best-practices/bundling/+page.md
@@ -83,6 +83,7 @@ export default (input) => ({
external: [
// AWS SDK
'@aws-sdk/client-apigatewaymanagementapi', // @middy/ws-response
+ '@aws-sdk/dsql-signer', // @middy/dsql-signer
'@aws-sdk/client-rds', // @middy/rds-signer
'@aws-sdk/client-s3', // @middy/s3-object-response
'@aws-sdk/client-secretsmanager', // @middy/sercrets-manager
@@ -140,6 +141,7 @@ export default {
'zlib', // @middy/http-content-encoding
// AWS SDK
'@aws-sdk/client-apigatewaymanagementapi', // @middy/ws-response
+ '@aws-sdk/dsql-signer', // @middy/dsql-signer
'@aws-sdk/client-rds', // @middy/rds-signer
'@aws-sdk/client-s3', // @middy/s3-object-response
'@aws-sdk/client-secretsmanager', // @middy/sercrets-manager
diff --git a/websites/middy.js.org/src/routes/docs/middlewares/dsql-signer/+page.md b/websites/middy.js.org/src/routes/docs/middlewares/dsql-signer/+page.md
new file mode 100644
index 000000000..daf92e231
--- /dev/null
+++ b/websites/middy.js.org/src/routes/docs/middlewares/dsql-signer/+page.md
@@ -0,0 +1,82 @@
+---
+title: dsql-signer
+description: "Generate Aurora DSQL IAM authentication tokens for secure database connections in Lambda."
+---
+
+Fetches Aurora DSQL credentials to be used when connecting to a DSQL cluster with IAM roles.
+
+## Install
+
+To install this middleware you can use NPM:
+
+```bash npm2yarn
+npm install --save @middy/dsql-signer
+npm install --save-dev @aws-sdk/dsql-signer
+```
+
+## Options
+
+- `AwsClient` (object) (default `DsqlSigner`): Signer class constructor (i.e. that has been instrumented with AWS XRay). Must be from `@aws-sdk/dsql-signer`.
+- `awsClientOptions` (object) (optional): Options to pass to Signer class constructor.
+- `fetchData` (object) (required): Mapping of internal key name to API request parameters.
+ - `hostname` (string) (required): DSQL cluster endpoint, e.g. `.dsql..on.aws`. Validated against the DSQL hostname format.
+ - `username` (string) (optional): Database role. When set to `"admin"` the middleware calls `getDbConnectAdminAuthToken`; any other value (or omitted) calls `getDbConnectAuthToken`.
+- `disablePrefetch` (boolean) (default `false`): On cold start requests will trigger early if they can.
+- `cacheKey` (string) (default `dsql-signer`): Cache key for the fetched data responses. Must be unique across all middleware.
+- `cacheExpiry` (number) (default `-1`): How long fetch data responses should be cached for. `-1`: cache forever, `0`: never cache, `n`: cache for n ms. Note: DSQL tokens have a default TTL of 900 s; cache for less than that to avoid using expired tokens on warm invocations.
+- `setToContext` (boolean) (default `false`): Store role tokens to `request.context`.
+
+NOTES:
+
+- Lambda is required to have IAM permission for `dsql:DbConnect` (non-admin role) or `dsql:DbConnectAdmin` (admin role) on the cluster ARN.
+- DSQL connections always use port `5432`, database `postgres`, and require SSL.
+- Region is taken from the default credential provider chain (e.g. `AWS_REGION`); cross-region access is not a supported DSQL pattern.
+
+## Sample usage
+
+```javascript
+import middy from '@middy/core'
+import dsqlSigner from '@middy/dsql-signer'
+import { getInternal } from '@middy/util'
+import pg from 'pg'
+
+const lambdaHandler = async (event, context) => {
+ const { dsqlToken } = await getInternal(['dsqlToken'], context)
+
+ const client = new pg.Client({
+ host: 'cluster-id.dsql.us-east-1.on.aws',
+ port: 5432,
+ database: 'postgres',
+ user: 'admin',
+ password: dsqlToken,
+ ssl: true
+ })
+ await client.connect()
+
+ const { rows } = await client.query('SELECT 1')
+ await client.end()
+
+ return {
+ statusCode: 200,
+ headers: {},
+ body: JSON.stringify({ rows })
+ }
+}
+
+export const handler = middy()
+ .use(
+ dsqlSigner({
+ fetchData: {
+ dsqlToken: {
+ hostname: 'cluster-id.dsql.us-east-1.on.aws',
+ username: 'admin'
+ }
+ }
+ })
+ )
+ .handler(lambdaHandler)
+```
+
+## Bundling
+
+To exclude `@aws-sdk` add `@aws-sdk/dsql-signer` to the exclude list.
diff --git a/websites/middy.js.org/src/routes/docs/middlewares/intro/+page.md b/websites/middy.js.org/src/routes/docs/middlewares/intro/+page.md
index 8b5adf4fb..3a7aee8ee 100644
--- a/websites/middy.js.org/src/routes/docs/middlewares/intro/+page.md
+++ b/websites/middy.js.org/src/routes/docs/middlewares/intro/+page.md
@@ -49,6 +49,7 @@ Each middleware should do a single task. We try to balance each to be as perform
## Fetch Data
- [`appconfig`](/docs/middlewares/appconfig): Fetch JSON configurations from AppConfig.
+- [`dsql-signer`](/docs/middlewares/dsql-signer): Fetches token for connecting to Aurora DSQL with IAM users.
- [`dynamodb`](/docs/middlewares/dynamodb): Fetch configurations from DynamoDB.
- [`rds-signer`](/docs/middlewares/rds-signer): Fetches token for connecting to RDS with IAM users.
- [`s3`](/docs/middlewares/s3): Fetch JSON configurations from S3.
diff --git a/websites/middy.js.org/static/.well-known/mcp.json b/websites/middy.js.org/static/.well-known/mcp.json
index d922df7d0..016dce36b 100644
--- a/websites/middy.js.org/static/.well-known/mcp.json
+++ b/websites/middy.js.org/static/.well-known/mcp.json
@@ -2,6 +2,7 @@
"name": "middy",
"description": "Middy - The stylish Node.js middleware engine for AWS Lambda",
"documentation": "https://middy.js.org/",
+ "endpoint": "https://middy.js.org/.well-known/mcp.json",
"resources": [
{
"name": "llms.txt",