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-mpp/README.md b/packages/http-mpp/README.md
new file mode 100644
index 000000000..a0d99a90b
--- /dev/null
+++ b/packages/http-mpp/README.md
@@ -0,0 +1,161 @@
+
+
+## What is MPP?
+
+[Machine Payments Protocol (MPP)](https://mpp.dev) enables APIs to charge for access via HTTP 402. The flow:
+
+1. Client requests a payment-gated resource
+2. Server returns `402 Payment Required` with a `WWW-Authenticate: MPP ...` challenge
+3. Client pays via Tempo (EVM stablecoin), Stripe, or Lightning
+4. Client retries with `Authorization: MPP `
+5. Server verifies the token and serves the resource
+
+## Install
+
+```bash
+npm install --save @middy/http-mpp
+```
+
+To use the built-in `mppx` verify helper, also install the optional peer dependency:
+
+```bash
+npm install --save mppx
+```
+
+## Options
+
+| Option | Type | Default | Description |
+|---|---|---|---|
+| `realm` | `string` | `"api"` | Value for `realm` in the `WWW-Authenticate` header |
+| `methods` | `MethodOptions[]` | required | One or more payment method descriptors |
+| `methods[].method` | `string` | required | Payment method name (e.g. `"tempo"`, `"lightning"`, `"stripe"`) |
+| `methods[].recipient` | `string` | required | Recipient wallet/account address |
+| `methods[].currency` | `string` | required | Token contract address or currency code |
+| `methods[].amount` | `number` | required | Amount to charge (must be > 0) |
+| `verify` | `function` | `undefined` | Token verification function. **Omitting this is insecure in production.** |
+
+## Basic usage with mppx
+
+```js
+import middy from '@middy/core'
+import httpMpp from '@middy/http-mpp'
+import { httpMppVerify } from '@middy/http-mpp/mppx'
+import { tempo } from 'mppx/server'
+
+const verify = httpMppVerify({
+ methods: [
+ tempo({
+ recipient: process.env.MPP_RECIPIENT,
+ currency: process.env.MPP_CURRENCY,
+ decimals: 6,
+ }),
+ ],
+ realm: 'api',
+ secretKey: process.env.MPP_SECRET_KEY,
+})
+
+export const handler = middy(async (event) => {
+ return { statusCode: 200, body: JSON.stringify({ message: 'Premium content!' }) }
+})
+ .use(httpHeaderNormalizer())
+ .use(httpMpp({
+ methods: [
+ {
+ method: 'tempo',
+ recipient: process.env.MPP_RECIPIENT,
+ currency: process.env.MPP_CURRENCY,
+ amount: 0.01,
+ },
+ ],
+ verify,
+ }))
+ .use(httpErrorHandler())
+```
+
+## Verify patterns
+
+**Charge model** - one payment, one token, on-chain verification (~600ms):
+
+```js
+import { httpMppVerify } from '@middy/http-mpp/mppx'
+import { tempo } from 'mppx/server'
+
+const verify = httpMppVerify({
+ methods: [tempo({ recipient: '0x...', currency: '0x...', decimals: 6 })],
+ secretKey: process.env.MPP_SECRET_KEY,
+})
+```
+
+**Session model** - payment channel, cache-backed verification (~10ms):
+
+```js
+import { httpMppVerify } from '@middy/http-mpp/mppx'
+import { tempo } from 'mppx/server'
+
+const verify = httpMppVerify({
+ methods: [tempo({ recipient: '0x...', currency: '0x...', decimals: 6, waitForConfirmation: false })],
+ secretKey: process.env.MPP_SECRET_KEY,
+})
+```
+
+**Custom verify with DynamoDB replay prevention**:
+
+```js
+const verify = async (token) => {
+ const used = await dynamo.get({ TableName: 'usedTokens', Key: { token } }).promise()
+ if (used.Item) return false
+ const valid = await checkOnChain(token)
+ if (valid) {
+ await dynamo.put({ TableName: 'usedTokens', Item: { token, ttl: Math.floor(Date.now() / 1000) + 3600 } }).promise()
+ }
+ return valid
+}
+```
+
+## Recommended middleware stack order
+
+```js
+middy(handler)
+ .use(httpHeaderNormalizer()) // normalize header casing
+ .use(httpMpp({ ... })) // payment gate
+ .use(httpErrorHandler()) // format error responses
+```
+
+## Security note
+
+Omitting the `verify` option puts the middleware in header-presence-only mode: any request with `Authorization: MPP ` is allowed through. This is useful for local development and testing but **must not be used in production**.
+
+## 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/http-mpp/index.d.ts b/packages/http-mpp/index.d.ts
new file mode 100644
index 000000000..e9e873ea0
--- /dev/null
+++ b/packages/http-mpp/index.d.ts
@@ -0,0 +1,29 @@
+// Copyright 2017 - 2026 will Farrell, Luciano Mammino, and Middy contributors.
+// SPDX-License-Identifier: MIT
+import type middy from "@middy/core";
+
+export interface MethodOptions {
+ method: string;
+ recipient: string;
+ currency: string;
+ amount: number;
+}
+
+export interface Options {
+ realm?: string;
+ methods?: MethodOptions[];
+ verify?: (
+ token: string,
+ request: middy.Request,
+ ) => boolean | Promise;
+}
+
+declare function httpMpp(
+ options?: Options,
+): middy.MiddlewareObj;
+
+export declare function httpMppValidateOptions(
+ options?: Record,
+): void;
+
+export default httpMpp;
diff --git a/packages/http-mpp/index.fuzz.js b/packages/http-mpp/index.fuzz.js
new file mode 100644
index 000000000..f9980545e
--- /dev/null
+++ b/packages/http-mpp/index.fuzz.js
@@ -0,0 +1,74 @@
+import { test } from "node:test";
+import fc from "fast-check";
+import middy from "../core/index.js";
+import middleware from "./index.js";
+
+const defaultMethods = [
+ {
+ method: "tempo",
+ recipient: "0x1234567890123456789012345678901234567890",
+ currency: "0xabcdef0123456789012345678901234567890123",
+ amount: 0.01,
+ },
+];
+
+const handler = middy(() => ({ statusCode: 200 })).use(
+ middleware({ methods: defaultMethods }),
+);
+
+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: [],
+ },
+ );
+});
+
+test("fuzz `event` w/ `record`", async () => {
+ await fc.assert(
+ fc.asyncProperty(
+ fc.record({
+ headers: fc.object(),
+ }),
+ async (event) => {
+ await handler(event, defaultContext);
+ },
+ ),
+ {
+ numRuns: 100_000,
+ examples: [],
+ },
+ );
+});
+
+test("fuzz `Authorization` header value", async () => {
+ await fc.assert(
+ fc.asyncProperty(
+ fc.record({
+ headers: fc.record({
+ Authorization: fc.oneof(
+ fc.constant(undefined),
+ fc.constant("MPP "),
+ fc.string().map((s) => `MPP ${s}`),
+ fc.string(),
+ ),
+ }),
+ }),
+ async (event) => {
+ await handler(event, defaultContext);
+ },
+ ),
+ {
+ numRuns: 100_000,
+ examples: [],
+ },
+ );
+});
diff --git a/packages/http-mpp/index.js b/packages/http-mpp/index.js
new file mode 100644
index 000000000..ae302ce58
--- /dev/null
+++ b/packages/http-mpp/index.js
@@ -0,0 +1,98 @@
+// Copyright 2017 - 2026 will Farrell, Luciano Mammino, and Middy contributors.
+// SPDX-License-Identifier: MIT
+import { normalizeHttpResponse, validateOptions } from "@middy/util";
+
+const name = "http-mpp";
+const pkg = `@middy/${name}`;
+
+const methodSchema = {
+ type: "object",
+ properties: {
+ method: { type: "string" },
+ recipient: { type: "string" },
+ currency: { type: "string" },
+ amount: { type: "number", exclusiveMinimum: 0 },
+ },
+ required: ["method", "recipient", "currency", "amount"],
+ additionalProperties: false,
+};
+
+const optionSchema = {
+ type: "object",
+ properties: {
+ realm: { type: "string" },
+ methods: { type: "array", items: methodSchema },
+ verify: { instanceof: "Function" },
+ },
+ additionalProperties: false,
+};
+
+export const httpMppValidateOptions = (options) =>
+ validateOptions(pkg, optionSchema, options);
+
+const defaults = {
+ realm: "api",
+ methods: [],
+ verify: undefined,
+};
+
+const buildWwwAuthenticateValues = (realm, methods) =>
+ methods.map(
+ ({ method, recipient, currency, amount }) =>
+ `MPP realm="${realm}", method="${method}", params="recipient=${recipient},currency=${currency},amount=${amount}"`,
+ );
+
+const httpMppMiddleware = (opts = {}) => {
+ const options = { ...defaults, ...opts };
+ httpMppValidateOptions(options);
+
+ if (!Array.isArray(options.methods) || options.methods.length === 0) {
+ throw new Error("options.methods must be a non-empty array", {
+ cause: { package: pkg },
+ });
+ }
+
+ const wwwAuthValues = buildWwwAuthenticateValues(
+ options.realm,
+ options.methods,
+ );
+
+ const httpMppMiddlewareBefore = async (request) => {
+ const eventHeaders = request.event?.headers ?? {};
+ const authHeader = eventHeaders.Authorization ?? eventHeaders.authorization;
+
+ if (!authHeader?.startsWith("MPP ")) {
+ return buildChallengeResponse(request, wwwAuthValues);
+ }
+
+ const token = authHeader.slice(4);
+
+ if (!options.verify) return;
+
+ let verified = false;
+ try {
+ verified = await options.verify(token, request);
+ } catch {
+ verified = false;
+ }
+
+ if (!verified) {
+ return buildChallengeResponse(request, wwwAuthValues);
+ }
+ };
+
+ return { before: httpMppMiddlewareBefore };
+};
+
+const buildChallengeResponse = (request, wwwAuthValues) => {
+ normalizeHttpResponse(request);
+ request.response.statusCode = 402;
+ request.response.headers["WWW-Authenticate"] = wwwAuthValues.join(", ");
+ if (wwwAuthValues.length > 1) {
+ request.response.multiValueHeaders ??= {};
+ request.response.multiValueHeaders["WWW-Authenticate"] = wwwAuthValues;
+ }
+ return request.response;
+};
+
+export default httpMppMiddleware;
diff --git a/packages/http-mpp/index.test.js b/packages/http-mpp/index.test.js
new file mode 100644
index 000000000..5806e7eae
--- /dev/null
+++ b/packages/http-mpp/index.test.js
@@ -0,0 +1,388 @@
+import {
+ deepStrictEqual,
+ doesNotThrow,
+ ok,
+ strictEqual,
+ throws,
+} from "node:assert/strict";
+import { test } from "node:test";
+import middy from "../core/index.js";
+import httpMpp, { httpMppValidateOptions } from "./index.js";
+
+const defaultContext = {
+ getRemainingTimeInMillis: () => 1000,
+};
+
+const defaultMethods = [
+ {
+ method: "tempo",
+ recipient: "0x1234567890123456789012345678901234567890",
+ currency: "0xabcdef0123456789012345678901234567890123",
+ amount: 0.01,
+ },
+];
+
+// *** challenge - missing/wrong Authorization ***
+
+test("Should return 402 with WWW-Authenticate when no Authorization header (v1.0 event)", async () => {
+ const handler = middy(() => ({ statusCode: 200 }));
+ handler.use(httpMpp({ methods: defaultMethods }));
+
+ const event = { httpMethod: "GET", headers: {} };
+ const response = await handler(event, defaultContext);
+
+ deepStrictEqual(response, {
+ statusCode: 402,
+ headers: {
+ "WWW-Authenticate":
+ 'MPP realm="api", method="tempo", params="recipient=0x1234567890123456789012345678901234567890,currency=0xabcdef0123456789012345678901234567890123,amount=0.01"',
+ },
+ });
+});
+
+test("Should return 402 with WWW-Authenticate when no Authorization header (v2.0 event)", async () => {
+ const handler = middy(() => ({ statusCode: 200 }));
+ handler.use(httpMpp({ methods: defaultMethods }));
+
+ const event = {
+ version: "2.0",
+ requestContext: { http: { method: "GET" } },
+ headers: {},
+ };
+ const response = await handler(event, defaultContext);
+
+ strictEqual(response.statusCode, 402);
+ ok(response.headers["WWW-Authenticate"].startsWith("MPP "));
+});
+
+test("Should return 402 when Authorization header has wrong scheme", async () => {
+ const handler = middy(() => ({ statusCode: 200 }));
+ handler.use(httpMpp({ methods: defaultMethods }));
+
+ const event = { headers: { Authorization: "Bearer sometoken" } };
+ const response = await handler(event, defaultContext);
+
+ strictEqual(response.statusCode, 402);
+ ok(response.headers["WWW-Authenticate"]);
+});
+
+test("Should return 402 when Authorization header is Basic scheme", async () => {
+ const handler = middy(() => ({ statusCode: 200 }));
+ handler.use(httpMpp({ methods: defaultMethods }));
+
+ const event = { headers: { Authorization: "Basic dXNlcjpwYXNz" } };
+ const response = await handler(event, defaultContext);
+
+ strictEqual(response.statusCode, 402);
+});
+
+test("Should return 402 when event has no headers property", async () => {
+ const handler = middy(() => ({ statusCode: 200 }));
+ handler.use(httpMpp({ methods: defaultMethods }));
+
+ const event = {};
+ const response = await handler(event, defaultContext);
+
+ strictEqual(response.statusCode, 402);
+});
+
+test("Should not call handler when Authorization is absent", async () => {
+ let handlerCalled = false;
+ const handler = middy(() => {
+ handlerCalled = true;
+ return { statusCode: 200 };
+ });
+ handler.use(httpMpp({ methods: defaultMethods }));
+
+ const event = { headers: {} };
+ await handler(event, defaultContext);
+
+ strictEqual(handlerCalled, false);
+});
+
+// *** token present, no verify (dev mode) ***
+
+test("Should allow request when MPP token present and no verify option", async () => {
+ const handler = middy(() => ({ statusCode: 200 }));
+ handler.use(httpMpp({ methods: defaultMethods }));
+
+ const event = { headers: { Authorization: "MPP sometoken" } };
+ const response = await handler(event, defaultContext);
+
+ strictEqual(response.statusCode, 200);
+});
+
+test("Should allow request with lowercase authorization header (APIGW v2)", async () => {
+ const handler = middy(() => ({ statusCode: 200 }));
+ handler.use(httpMpp({ methods: defaultMethods }));
+
+ const event = { headers: { authorization: "MPP sometoken" } };
+ const response = await handler(event, defaultContext);
+
+ strictEqual(response.statusCode, 200);
+});
+
+// *** verify function ***
+
+test("Should allow request when verify returns true", async () => {
+ const handler = middy(() => ({ statusCode: 200 }));
+ handler.use(
+ httpMpp({
+ methods: defaultMethods,
+ verify: async () => true,
+ }),
+ );
+
+ const event = { headers: { Authorization: "MPP validtoken" } };
+ const response = await handler(event, defaultContext);
+
+ strictEqual(response.statusCode, 200);
+});
+
+test("Should return 402 when verify returns false", async () => {
+ const handler = middy(() => ({ statusCode: 200 }));
+ handler.use(
+ httpMpp({
+ methods: defaultMethods,
+ verify: async () => false,
+ }),
+ );
+
+ const event = { headers: { Authorization: "MPP badtoken" } };
+ const response = await handler(event, defaultContext);
+
+ strictEqual(response.statusCode, 402);
+ ok(response.headers["WWW-Authenticate"]);
+});
+
+test("Should return 402 when verify throws", async () => {
+ const handler = middy(() => ({ statusCode: 200 }));
+ handler.use(
+ httpMpp({
+ methods: defaultMethods,
+ verify: async () => {
+ throw new Error("network error");
+ },
+ }),
+ );
+
+ const event = { headers: { Authorization: "MPP sometoken" } };
+ const response = await handler(event, defaultContext);
+
+ strictEqual(response.statusCode, 402);
+});
+
+test("Should pass token string to verify without MPP prefix", async () => {
+ let capturedToken = null;
+ const handler = middy(() => ({ statusCode: 200 }));
+ handler.use(
+ httpMpp({
+ methods: defaultMethods,
+ verify: async (token) => {
+ capturedToken = token;
+ return true;
+ },
+ }),
+ );
+
+ const event = { headers: { Authorization: "MPP mytoken123" } };
+ await handler(event, defaultContext);
+
+ strictEqual(capturedToken, "mytoken123");
+});
+
+test("Should pass request object to verify as second argument", async () => {
+ let capturedRequest = null;
+ const handler = middy(() => ({ statusCode: 200 }));
+ handler.use(
+ httpMpp({
+ methods: defaultMethods,
+ verify: async (token, request) => {
+ capturedRequest = request;
+ return true;
+ },
+ }),
+ );
+
+ const event = { headers: { Authorization: "MPP sometoken" } };
+ await handler(event, defaultContext);
+
+ ok(capturedRequest);
+ ok(capturedRequest.event);
+});
+
+test("Should support async verify returning Promise", async () => {
+ const handler = middy(() => ({ statusCode: 200 }));
+ handler.use(
+ httpMpp({
+ methods: defaultMethods,
+ verify: (token) => Promise.resolve(token === "validtoken"),
+ }),
+ );
+
+ const event = { headers: { Authorization: "MPP validtoken" } };
+ const response = await handler(event, defaultContext);
+
+ strictEqual(response.statusCode, 200);
+});
+
+// *** WWW-Authenticate header format ***
+
+test("Should format WWW-Authenticate header with correct realm, method, and params", async () => {
+ const handler = middy(() => ({ statusCode: 200 }));
+ handler.use(
+ httpMpp({
+ methods: [
+ {
+ method: "tempo",
+ recipient: "0xabc",
+ currency: "0xdef",
+ amount: 0.01,
+ },
+ ],
+ }),
+ );
+
+ const event = { headers: {} };
+ const response = await handler(event, defaultContext);
+
+ strictEqual(
+ response.headers["WWW-Authenticate"],
+ 'MPP realm="api", method="tempo", params="recipient=0xabc,currency=0xdef,amount=0.01"',
+ );
+});
+
+test("Should use custom realm in WWW-Authenticate", async () => {
+ const handler = middy(() => ({ statusCode: 200 }));
+ handler.use(
+ httpMpp({
+ realm: "myapp",
+ methods: [
+ {
+ method: "tempo",
+ recipient: "0xabc",
+ currency: "0xdef",
+ amount: 0.01,
+ },
+ ],
+ }),
+ );
+
+ const event = { headers: {} };
+ const response = await handler(event, defaultContext);
+
+ ok(response.headers["WWW-Authenticate"].includes('realm="myapp"'));
+});
+
+test("Should use default realm 'api' when not specified", async () => {
+ const handler = middy(() => ({ statusCode: 200 }));
+ handler.use(
+ httpMpp({
+ methods: [
+ { method: "tempo", recipient: "0x", currency: "0x", amount: 0.01 },
+ ],
+ }),
+ );
+
+ const event = { headers: {} };
+ const response = await handler(event, defaultContext);
+
+ ok(response.headers["WWW-Authenticate"].includes('realm="api"'));
+});
+
+test("Should set multiValueHeaders for multiple payment methods", async () => {
+ const handler = middy(() => ({ statusCode: 200 }));
+ handler.use(
+ httpMpp({
+ methods: [
+ {
+ method: "tempo",
+ recipient: "0xabc",
+ currency: "0xdef",
+ amount: 0.01,
+ },
+ {
+ method: "lightning",
+ recipient: "lnbc...",
+ currency: "BTC",
+ amount: 0.0001,
+ },
+ ],
+ }),
+ );
+
+ const event = { headers: {} };
+ const response = await handler(event, defaultContext);
+
+ strictEqual(response.statusCode, 402);
+ strictEqual(
+ Array.isArray(response.multiValueHeaders["WWW-Authenticate"]),
+ true,
+ );
+ strictEqual(response.multiValueHeaders["WWW-Authenticate"].length, 2);
+});
+
+// *** validateOptions ***
+
+test("httpMppValidateOptions accepts valid options", () => {
+ doesNotThrow(() =>
+ httpMppValidateOptions({
+ realm: "api",
+ methods: [
+ {
+ method: "tempo",
+ recipient: "0x",
+ currency: "0x",
+ amount: 0.01,
+ },
+ ],
+ verify: () => true,
+ }),
+ );
+});
+
+test("httpMppValidateOptions accepts empty options object", () => {
+ doesNotThrow(() => httpMppValidateOptions({}));
+});
+
+test("httpMppValidateOptions rejects unknown top-level keys", () => {
+ throws(() => httpMppValidateOptions({ unknownKey: "value" }));
+});
+
+test("httpMppValidateOptions rejects non-positive amount", () => {
+ throws(() =>
+ httpMppValidateOptions({
+ methods: [
+ { method: "tempo", recipient: "0x", currency: "0x", amount: 0 },
+ ],
+ }),
+ );
+});
+
+test("httpMppValidateOptions rejects negative amount", () => {
+ throws(() =>
+ httpMppValidateOptions({
+ methods: [
+ { method: "tempo", recipient: "0x", currency: "0x", amount: -1 },
+ ],
+ }),
+ );
+});
+
+test("httpMppValidateOptions rejects non-function verify", () => {
+ throws(() => httpMppValidateOptions({ verify: "not-a-function" }));
+});
+
+// *** construction errors ***
+
+test("Should throw at construction when methods is empty array", () => {
+ throws(() => httpMpp({ methods: [] }), {
+ message: "options.methods must be a non-empty array",
+ });
+});
+
+test("Should throw at construction when methods is not provided", () => {
+ throws(() => httpMpp({}), {
+ message: "options.methods must be a non-empty array",
+ });
+});
diff --git a/packages/http-mpp/index.tst.ts b/packages/http-mpp/index.tst.ts
new file mode 100644
index 000000000..62f9db51f
--- /dev/null
+++ b/packages/http-mpp/index.tst.ts
@@ -0,0 +1,58 @@
+import type middy from "@middy/core";
+import { expect, test } from "tstyche";
+import httpMpp, { type MethodOptions } from "./index.js";
+
+test("use with required methods", () => {
+ const middleware = httpMpp({
+ methods: [
+ { method: "tempo", recipient: "0x", currency: "0x", amount: 0.01 },
+ ],
+ });
+ expect(middleware).type.toBe>();
+});
+
+test("use with all options", () => {
+ const middleware = httpMpp({
+ realm: "api",
+ methods: [
+ { method: "tempo", recipient: "0xabc", currency: "0xdef", amount: 0.01 },
+ {
+ method: "lightning",
+ recipient: "lnbc...",
+ currency: "BTC",
+ amount: 0.0001,
+ },
+ ],
+ verify: async (token: string) => token.length > 0,
+ });
+ expect(middleware).type.toBe>();
+});
+
+test("verify receives middy.Request as second argument", () => {
+ httpMpp({
+ methods: [
+ { method: "tempo", recipient: "0x", currency: "0x", amount: 0.01 },
+ ],
+ verify: async (token: string, request: middy.Request) =>
+ request.event !== undefined,
+ });
+});
+
+test("verify can be synchronous", () => {
+ httpMpp({
+ methods: [
+ { method: "tempo", recipient: "0x", currency: "0x", amount: 0.01 },
+ ],
+ verify: (token: string) => token.length > 0,
+ });
+});
+
+test("MethodOptions interface is exported", () => {
+ const method: MethodOptions = {
+ method: "tempo",
+ recipient: "0x",
+ currency: "0x",
+ amount: 0.01,
+ };
+ expect(method).type.toBe();
+});
diff --git a/packages/http-mpp/mppx.d.ts b/packages/http-mpp/mppx.d.ts
new file mode 100644
index 000000000..b7f45c364
--- /dev/null
+++ b/packages/http-mpp/mppx.d.ts
@@ -0,0 +1,13 @@
+// Copyright 2017 - 2026 will Farrell, Luciano Mammino, and Middy contributors.
+// SPDX-License-Identifier: MIT
+
+interface MppxConfig {
+ methods: unknown[];
+ realm?: string;
+ secretKey?: string;
+ transport?: unknown;
+}
+
+export declare function httpMppVerify(
+ mppxConfig: MppxConfig,
+): (token: string) => Promise;
diff --git a/packages/http-mpp/mppx.js b/packages/http-mpp/mppx.js
new file mode 100644
index 000000000..120509b84
--- /dev/null
+++ b/packages/http-mpp/mppx.js
@@ -0,0 +1,15 @@
+// Copyright 2017 - 2026 will Farrell, Luciano Mammino, and Middy contributors.
+// SPDX-License-Identifier: MIT
+import { Mppx } from "mppx/server";
+
+export const httpMppVerify = (mppxConfig) => {
+ const mppx = Mppx.create(mppxConfig);
+ return async (token) => {
+ try {
+ await mppx.verifyCredential(token);
+ return true;
+ } catch {
+ return false;
+ }
+ };
+};
diff --git a/packages/http-mpp/package.json b/packages/http-mpp/package.json
new file mode 100644
index 000000000..a7830aef5
--- /dev/null
+++ b/packages/http-mpp/package.json
@@ -0,0 +1,89 @@
+{
+ "name": "@middy/http-mpp",
+ "version": "7.3.4",
+ "description": "Machine Payments Protocol (MPP) HTTP 402 payment gate 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"
+ }
+ },
+ "./mppx": {
+ "import": {
+ "types": "./mppx.d.ts",
+ "default": "./mppx.js"
+ }
+ }
+ },
+ "types": "index.d.ts",
+ "files": [
+ "index.js",
+ "index.d.ts",
+ "mppx.js",
+ "mppx.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",
+ "MPP",
+ "402",
+ "payment",
+ "Machine Payments Protocol"
+ ],
+ "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-mpp"
+ },
+ "bugs": {
+ "url": "https://github.com/middyjs/middy/issues"
+ },
+ "homepage": "https://middy.js.org",
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/willfarrell"
+ },
+ "dependencies": {
+ "@middy/util": "7.3.4"
+ },
+ "peerDependencies": {
+ "mppx": ">=0.6.0"
+ },
+ "peerDependenciesMeta": {
+ "mppx": {
+ "optional": true
+ }
+ },
+ "devDependencies": {
+ "@middy/core": "7.3.4",
+ "@types/aws-lambda": "^8.0.0",
+ "@types/node": "^22.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/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",