diff --git a/.changeset/dull-towns-attack.md b/.changeset/dull-towns-attack.md new file mode 100644 index 00000000000..f6fc426e915 --- /dev/null +++ b/.changeset/dull-towns-attack.md @@ -0,0 +1,6 @@ +--- +'@aws-amplify/deployed-backend-client': patch +'@aws-amplify/platform-core': patch +--- + +made regionfetcher public, added metadata to deployedbackendresource diff --git a/.changeset/loose-wings-stop.md b/.changeset/loose-wings-stop.md new file mode 100644 index 00000000000..4a48dcc67a3 --- /dev/null +++ b/.changeset/loose-wings-stop.md @@ -0,0 +1,5 @@ +--- +'@aws-amplify/cli-core': patch +--- + +pulled out normalizeCDKconstructPath diff --git a/.changeset/thin-paths-drum.md b/.changeset/thin-paths-drum.md new file mode 100644 index 00000000000..114d19072a7 --- /dev/null +++ b/.changeset/thin-paths-drum.md @@ -0,0 +1,8 @@ +--- +'@aws-amplify/sandbox': minor +'@aws-amplify/backend-cli': minor +'@aws-amplify/backend-deployer': patch +'@aws-amplify/ai-constructs': patch +--- + +Devtools PR2 diff --git a/.eslintignore b/.eslintignore index 85e6fabb91a..150b26dfd3f 100644 --- a/.eslintignore +++ b/.eslintignore @@ -19,3 +19,4 @@ packages/integration-tests/src/e2e-tests # Frontend code packages/cli/src/commands/sandbox/sandbox-devtools/react-app/** +!packages/cli/src/commands/sandbox/sandbox-devtools/react-app/package.json diff --git a/package-lock.json b/package-lock.json index 96c94675fd8..05fb2652ec1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,18 +11,23 @@ "workspaces": [ "packages/*" ], + "dependencies": { + "strip-ansi": "^7.1.0" + }, "devDependencies": { "@actions/core": "^1.10.1", "@actions/github": "^6.0.0", "@aws-amplify/eslint-plugin-amplify-backend-rules": "^0.0.2", "@aws-sdk/client-amplify": "^3.750.0", - "@aws-sdk/client-cloudformation": "^3.750.0", - "@aws-sdk/client-cloudwatch-logs": "^3.750.0", + "@aws-sdk/client-cloudformation": "^3.828.0", + "@aws-sdk/client-cloudwatch-logs": "^3.835.0", "@aws-sdk/client-cognito-identity-provider": "^3.750.0", "@aws-sdk/client-dynamodb": "^3.750.0", "@aws-sdk/client-iam": "^3.750.0", "@aws-sdk/client-s3": "^3.750.0", "@aws-sdk/client-ssm": "^3.750.0", + "@aws-sdk/eventstream-handler-node": "^3.821.0", + "@aws-sdk/middleware-eventstream": "^3.821.0", "@changesets/cli": "^2.26.1", "@changesets/get-release-plan": "^4.0.0", "@changesets/types": "^6.0.0", @@ -55,6 +60,7 @@ "husky": "^9.1.7", "lint-staged": "^15.2.10", "minimatch": "10.0.3", + "npm-force-resolutions": "^0.0.10", "prettier": "^3.5.3", "rimraf": "^6.0.1", "semver": "^7.5.4", @@ -274,6 +280,17 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/@ardatan/relay-compiler/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/@ardatan/relay-compiler/node_modules/wrap-ansi": { "version": "6.2.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", @@ -10535,6 +10552,17 @@ "uglify-js": "^3.1.4" } }, + "node_modules/@aws-amplify/graphql-docs-generator/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/@aws-amplify/graphql-docs-generator/node_modules/wrap-ansi": { "version": "6.2.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", @@ -12246,6 +12274,17 @@ "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", "license": "ISC" }, + "node_modules/@aws-amplify/graphql-schema-generator/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/@aws-amplify/graphql-schema-generator/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -12554,6 +12593,17 @@ "node": ">=0.10.0" } }, + "node_modules/@aws-amplify/graphql-types-generator/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/@aws-amplify/graphql-types-generator/node_modules/to-fast-properties": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", @@ -14980,50 +15030,49 @@ } }, "node_modules/@aws-sdk/client-cloudformation": { - "version": "3.799.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-cloudformation/-/client-cloudformation-3.799.0.tgz", - "integrity": "sha512-atV3CHwc42Nv+y9uL4pJEJyvHTmzM6F+Emq1lD6mc748B514cavwzijsZTbg4YvihIQTvNxNuSFkCyuXY4NTGw==", - "license": "Apache-2.0", + "version": "3.840.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-cloudformation/-/client-cloudformation-3.840.0.tgz", + "integrity": "sha512-WUvN/80yx5b/I8YYBr9RTvcfnU7tZFgpsyXhwf+cmYFK5CfpUH7lRBzZflmim5YKiMR8m3VYlzdUWij8VB9NDQ==", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "3.799.0", - "@aws-sdk/credential-provider-node": "3.799.0", - "@aws-sdk/middleware-host-header": "3.775.0", - "@aws-sdk/middleware-logger": "3.775.0", - "@aws-sdk/middleware-recursion-detection": "3.775.0", - "@aws-sdk/middleware-user-agent": "3.799.0", - "@aws-sdk/region-config-resolver": "3.775.0", - "@aws-sdk/types": "3.775.0", - "@aws-sdk/util-endpoints": "3.787.0", - "@aws-sdk/util-user-agent-browser": "3.775.0", - "@aws-sdk/util-user-agent-node": "3.799.0", - "@smithy/config-resolver": "^4.1.0", - "@smithy/core": "^3.3.0", - "@smithy/fetch-http-handler": "^5.0.2", - "@smithy/hash-node": "^4.0.2", - "@smithy/invalid-dependency": "^4.0.2", - "@smithy/middleware-content-length": "^4.0.2", - "@smithy/middleware-endpoint": "^4.1.1", - "@smithy/middleware-retry": "^4.1.1", - "@smithy/middleware-serde": "^4.0.3", - "@smithy/middleware-stack": "^4.0.2", - "@smithy/node-config-provider": "^4.0.2", - "@smithy/node-http-handler": "^4.0.4", - "@smithy/protocol-http": "^5.1.0", - "@smithy/smithy-client": "^4.2.1", - "@smithy/types": "^4.2.0", - "@smithy/url-parser": "^4.0.2", + "@aws-sdk/core": "3.840.0", + "@aws-sdk/credential-provider-node": "3.840.0", + "@aws-sdk/middleware-host-header": "3.840.0", + "@aws-sdk/middleware-logger": "3.840.0", + "@aws-sdk/middleware-recursion-detection": "3.840.0", + "@aws-sdk/middleware-user-agent": "3.840.0", + "@aws-sdk/region-config-resolver": "3.840.0", + "@aws-sdk/types": "3.840.0", + "@aws-sdk/util-endpoints": "3.840.0", + "@aws-sdk/util-user-agent-browser": "3.840.0", + "@aws-sdk/util-user-agent-node": "3.840.0", + "@smithy/config-resolver": "^4.1.4", + "@smithy/core": "^3.6.0", + "@smithy/fetch-http-handler": "^5.0.4", + "@smithy/hash-node": "^4.0.4", + "@smithy/invalid-dependency": "^4.0.4", + "@smithy/middleware-content-length": "^4.0.4", + "@smithy/middleware-endpoint": "^4.1.13", + "@smithy/middleware-retry": "^4.1.14", + "@smithy/middleware-serde": "^4.0.8", + "@smithy/middleware-stack": "^4.0.4", + "@smithy/node-config-provider": "^4.1.3", + "@smithy/node-http-handler": "^4.0.6", + "@smithy/protocol-http": "^5.1.2", + "@smithy/smithy-client": "^4.4.5", + "@smithy/types": "^4.3.1", + "@smithy/url-parser": "^4.0.4", "@smithy/util-base64": "^4.0.0", "@smithy/util-body-length-browser": "^4.0.0", "@smithy/util-body-length-node": "^4.0.0", - "@smithy/util-defaults-mode-browser": "^4.0.9", - "@smithy/util-defaults-mode-node": "^4.0.9", - "@smithy/util-endpoints": "^3.0.2", - "@smithy/util-middleware": "^4.0.2", - "@smithy/util-retry": "^4.0.2", + "@smithy/util-defaults-mode-browser": "^4.0.21", + "@smithy/util-defaults-mode-node": "^4.0.21", + "@smithy/util-endpoints": "^3.0.6", + "@smithy/util-middleware": "^4.0.4", + "@smithy/util-retry": "^4.0.6", "@smithy/util-utf8": "^4.0.0", - "@smithy/util-waiter": "^4.0.3", + "@smithy/util-waiter": "^4.0.6", "@types/uuid": "^9.0.1", "tslib": "^2.6.2", "uuid": "^9.0.1" @@ -15033,47 +15082,46 @@ } }, "node_modules/@aws-sdk/client-cloudformation/node_modules/@aws-sdk/client-sso": { - "version": "3.799.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.799.0.tgz", - "integrity": "sha512-/i/LG7AiWPmPxKCA2jnR2zaf7B3HYSTbxaZI21ElIz9wASlNAsKr8CnLY7qb50kOyXiNfQ834S5Q3Gl8dX9o3Q==", - "license": "Apache-2.0", + "version": "3.840.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.840.0.tgz", + "integrity": "sha512-3Zp+FWN2hhmKdpS0Ragi5V2ZPsZNScE3jlbgoJjzjI/roHZqO+e3/+XFN4TlM0DsPKYJNp+1TAjmhxN6rOnfYA==", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "3.799.0", - "@aws-sdk/middleware-host-header": "3.775.0", - "@aws-sdk/middleware-logger": "3.775.0", - "@aws-sdk/middleware-recursion-detection": "3.775.0", - "@aws-sdk/middleware-user-agent": "3.799.0", - "@aws-sdk/region-config-resolver": "3.775.0", - "@aws-sdk/types": "3.775.0", - "@aws-sdk/util-endpoints": "3.787.0", - "@aws-sdk/util-user-agent-browser": "3.775.0", - "@aws-sdk/util-user-agent-node": "3.799.0", - "@smithy/config-resolver": "^4.1.0", - "@smithy/core": "^3.3.0", - "@smithy/fetch-http-handler": "^5.0.2", - "@smithy/hash-node": "^4.0.2", - "@smithy/invalid-dependency": "^4.0.2", - "@smithy/middleware-content-length": "^4.0.2", - "@smithy/middleware-endpoint": "^4.1.1", - "@smithy/middleware-retry": "^4.1.1", - "@smithy/middleware-serde": "^4.0.3", - "@smithy/middleware-stack": "^4.0.2", - "@smithy/node-config-provider": "^4.0.2", - "@smithy/node-http-handler": "^4.0.4", - "@smithy/protocol-http": "^5.1.0", - "@smithy/smithy-client": "^4.2.1", - "@smithy/types": "^4.2.0", - "@smithy/url-parser": "^4.0.2", + "@aws-sdk/core": "3.840.0", + "@aws-sdk/middleware-host-header": "3.840.0", + "@aws-sdk/middleware-logger": "3.840.0", + "@aws-sdk/middleware-recursion-detection": "3.840.0", + "@aws-sdk/middleware-user-agent": "3.840.0", + "@aws-sdk/region-config-resolver": "3.840.0", + "@aws-sdk/types": "3.840.0", + "@aws-sdk/util-endpoints": "3.840.0", + "@aws-sdk/util-user-agent-browser": "3.840.0", + "@aws-sdk/util-user-agent-node": "3.840.0", + "@smithy/config-resolver": "^4.1.4", + "@smithy/core": "^3.6.0", + "@smithy/fetch-http-handler": "^5.0.4", + "@smithy/hash-node": "^4.0.4", + "@smithy/invalid-dependency": "^4.0.4", + "@smithy/middleware-content-length": "^4.0.4", + "@smithy/middleware-endpoint": "^4.1.13", + "@smithy/middleware-retry": "^4.1.14", + "@smithy/middleware-serde": "^4.0.8", + "@smithy/middleware-stack": "^4.0.4", + "@smithy/node-config-provider": "^4.1.3", + "@smithy/node-http-handler": "^4.0.6", + "@smithy/protocol-http": "^5.1.2", + "@smithy/smithy-client": "^4.4.5", + "@smithy/types": "^4.3.1", + "@smithy/url-parser": "^4.0.4", "@smithy/util-base64": "^4.0.0", "@smithy/util-body-length-browser": "^4.0.0", "@smithy/util-body-length-node": "^4.0.0", - "@smithy/util-defaults-mode-browser": "^4.0.9", - "@smithy/util-defaults-mode-node": "^4.0.9", - "@smithy/util-endpoints": "^3.0.2", - "@smithy/util-middleware": "^4.0.2", - "@smithy/util-retry": "^4.0.2", + "@smithy/util-defaults-mode-browser": "^4.0.21", + "@smithy/util-defaults-mode-node": "^4.0.21", + "@smithy/util-endpoints": "^3.0.6", + "@smithy/util-middleware": "^4.0.4", + "@smithy/util-retry": "^4.0.6", "@smithy/util-utf8": "^4.0.0", "tslib": "^2.6.2" }, @@ -15082,20 +15130,23 @@ } }, "node_modules/@aws-sdk/client-cloudformation/node_modules/@aws-sdk/core": { - "version": "3.799.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.799.0.tgz", - "integrity": "sha512-hkKF3Zpc6+H8GI1rlttYVRh9uEE77cqAzLmLpY3iu7sql8cZgPERRBfaFct8p1SaDyrksLNiboD1vKW58mbsYg==", - "license": "Apache-2.0", + "version": "3.840.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.840.0.tgz", + "integrity": "sha512-x3Zgb39tF1h2XpU+yA4OAAQlW6LVEfXNlSedSYJ7HGKXqA/E9h3rWQVpYfhXXVVsLdYXdNw5KBUkoAoruoZSZA==", "dependencies": { - "@aws-sdk/types": "3.775.0", - "@smithy/core": "^3.3.0", - "@smithy/node-config-provider": "^4.0.2", - "@smithy/property-provider": "^4.0.2", - "@smithy/protocol-http": "^5.1.0", - "@smithy/signature-v4": "^5.1.0", - "@smithy/smithy-client": "^4.2.1", - "@smithy/types": "^4.2.0", - "@smithy/util-middleware": "^4.0.2", + "@aws-sdk/types": "3.840.0", + "@aws-sdk/xml-builder": "3.821.0", + "@smithy/core": "^3.6.0", + "@smithy/node-config-provider": "^4.1.3", + "@smithy/property-provider": "^4.0.4", + "@smithy/protocol-http": "^5.1.2", + "@smithy/signature-v4": "^5.1.2", + "@smithy/smithy-client": "^4.4.5", + "@smithy/types": "^4.3.1", + "@smithy/util-base64": "^4.0.0", + "@smithy/util-body-length-browser": "^4.0.0", + "@smithy/util-middleware": "^4.0.4", + "@smithy/util-utf8": "^4.0.0", "fast-xml-parser": "4.4.1", "tslib": "^2.6.2" }, @@ -15104,15 +15155,14 @@ } }, "node_modules/@aws-sdk/client-cloudformation/node_modules/@aws-sdk/credential-provider-env": { - "version": "3.799.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.799.0.tgz", - "integrity": "sha512-vT/SSWtbUIOW/U21qgEySmmO44SFWIA7WeQPX1OrI8WJ5n7OEI23JWLHjLvHTkYmuZK6z1rPcv7HzRgmuGRibA==", - "license": "Apache-2.0", + "version": "3.840.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.840.0.tgz", + "integrity": "sha512-EzF6VcJK7XvQ/G15AVEfJzN2mNXU8fcVpXo4bRyr1S6t2q5zx6UPH/XjDbn18xyUmOq01t+r8gG+TmHEVo18fA==", "dependencies": { - "@aws-sdk/core": "3.799.0", - "@aws-sdk/types": "3.775.0", - "@smithy/property-provider": "^4.0.2", - "@smithy/types": "^4.2.0", + "@aws-sdk/core": "3.840.0", + "@aws-sdk/types": "3.840.0", + "@smithy/property-provider": "^4.0.4", + "@smithy/types": "^4.3.1", "tslib": "^2.6.2" }, "engines": { @@ -15120,43 +15170,64 @@ } }, "node_modules/@aws-sdk/client-cloudformation/node_modules/@aws-sdk/credential-provider-http": { - "version": "3.799.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.799.0.tgz", - "integrity": "sha512-2CjBpOWmhaPAExOgHnIB5nOkS5ef+mfRlJ1JC4nsnjAx0nrK4tk0XRE0LYz11P3+ue+a86cU8WTmBo+qjnGxPQ==", - "license": "Apache-2.0", + "version": "3.840.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.840.0.tgz", + "integrity": "sha512-wbnUiPGLVea6mXbUh04fu+VJmGkQvmToPeTYdHE8eRZq3NRDi3t3WltT+jArLBKD/4NppRpMjf2ju4coMCz91g==", "dependencies": { - "@aws-sdk/core": "3.799.0", - "@aws-sdk/types": "3.775.0", - "@smithy/fetch-http-handler": "^5.0.2", - "@smithy/node-http-handler": "^4.0.4", - "@smithy/property-provider": "^4.0.2", - "@smithy/protocol-http": "^5.1.0", - "@smithy/smithy-client": "^4.2.1", - "@smithy/types": "^4.2.0", - "@smithy/util-stream": "^4.2.0", + "@aws-sdk/core": "3.840.0", + "@aws-sdk/types": "3.840.0", + "@smithy/fetch-http-handler": "^5.0.4", + "@smithy/node-http-handler": "^4.0.6", + "@smithy/property-provider": "^4.0.4", + "@smithy/protocol-http": "^5.1.2", + "@smithy/smithy-client": "^4.4.5", + "@smithy/types": "^4.3.1", + "@smithy/util-stream": "^4.2.2", "tslib": "^2.6.2" }, "engines": { "node": ">=18.0.0" } }, - "node_modules/@aws-sdk/client-cloudformation/node_modules/@aws-sdk/credential-provider-node": { - "version": "3.799.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.799.0.tgz", - "integrity": "sha512-nd9fSJc0wUlgKUkIr2ldJhcIIrzJFS29AGZoyY22J3xih63nNDv61eTGVMsDZzHlV21XzMlPEljTR7axiimckg==", - "license": "Apache-2.0", + "node_modules/@aws-sdk/client-cloudformation/node_modules/@aws-sdk/credential-provider-ini": { + "version": "3.840.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.840.0.tgz", + "integrity": "sha512-7F290BsWydShHb+7InXd+IjJc3mlEIm9I0R57F/Pjl1xZB69MdkhVGCnuETWoBt4g53ktJd6NEjzm/iAhFXFmw==", "dependencies": { - "@aws-sdk/credential-provider-env": "3.799.0", - "@aws-sdk/credential-provider-http": "3.799.0", - "@aws-sdk/credential-provider-ini": "3.799.0", - "@aws-sdk/credential-provider-process": "3.799.0", - "@aws-sdk/credential-provider-sso": "3.799.0", - "@aws-sdk/credential-provider-web-identity": "3.799.0", - "@aws-sdk/types": "3.775.0", - "@smithy/credential-provider-imds": "^4.0.2", - "@smithy/property-provider": "^4.0.2", - "@smithy/shared-ini-file-loader": "^4.0.2", - "@smithy/types": "^4.2.0", + "@aws-sdk/core": "3.840.0", + "@aws-sdk/credential-provider-env": "3.840.0", + "@aws-sdk/credential-provider-http": "3.840.0", + "@aws-sdk/credential-provider-process": "3.840.0", + "@aws-sdk/credential-provider-sso": "3.840.0", + "@aws-sdk/credential-provider-web-identity": "3.840.0", + "@aws-sdk/nested-clients": "3.840.0", + "@aws-sdk/types": "3.840.0", + "@smithy/credential-provider-imds": "^4.0.6", + "@smithy/property-provider": "^4.0.4", + "@smithy/shared-ini-file-loader": "^4.0.4", + "@smithy/types": "^4.3.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-cloudformation/node_modules/@aws-sdk/credential-provider-node": { + "version": "3.840.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.840.0.tgz", + "integrity": "sha512-KufP8JnxA31wxklLm63evUPSFApGcH8X86z3mv9SRbpCm5ycgWIGVCTXpTOdgq6rPZrwT9pftzv2/b4mV/9clg==", + "dependencies": { + "@aws-sdk/credential-provider-env": "3.840.0", + "@aws-sdk/credential-provider-http": "3.840.0", + "@aws-sdk/credential-provider-ini": "3.840.0", + "@aws-sdk/credential-provider-process": "3.840.0", + "@aws-sdk/credential-provider-sso": "3.840.0", + "@aws-sdk/credential-provider-web-identity": "3.840.0", + "@aws-sdk/types": "3.840.0", + "@smithy/credential-provider-imds": "^4.0.6", + "@smithy/property-provider": "^4.0.4", + "@smithy/shared-ini-file-loader": "^4.0.4", + "@smithy/types": "^4.3.1", "tslib": "^2.6.2" }, "engines": { @@ -15164,16 +15235,15 @@ } }, "node_modules/@aws-sdk/client-cloudformation/node_modules/@aws-sdk/credential-provider-process": { - "version": "3.799.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.799.0.tgz", - "integrity": "sha512-g8jmNs2k98WNHMYcea1YKA+7ao2Ma4w0P42Dz4YpcI155pQHxHx25RwbOG+rsAKuo3bKwkW53HVE/ZTKhcWFgw==", - "license": "Apache-2.0", + "version": "3.840.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.840.0.tgz", + "integrity": "sha512-HkDQWHy8tCI4A0Ps2NVtuVYMv9cB4y/IuD/TdOsqeRIAT12h8jDb98BwQPNLAImAOwOWzZJ8Cu0xtSpX7CQhMw==", "dependencies": { - "@aws-sdk/core": "3.799.0", - "@aws-sdk/types": "3.775.0", - "@smithy/property-provider": "^4.0.2", - "@smithy/shared-ini-file-loader": "^4.0.2", - "@smithy/types": "^4.2.0", + "@aws-sdk/core": "3.840.0", + "@aws-sdk/types": "3.840.0", + "@smithy/property-provider": "^4.0.4", + "@smithy/shared-ini-file-loader": "^4.0.4", + "@smithy/types": "^4.3.1", "tslib": "^2.6.2" }, "engines": { @@ -15181,18 +15251,17 @@ } }, "node_modules/@aws-sdk/client-cloudformation/node_modules/@aws-sdk/credential-provider-sso": { - "version": "3.799.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.799.0.tgz", - "integrity": "sha512-lQv27QkNU9FJFZqEf5DIEN3uXEN409Iaym9WJzhOouGtxvTIAWiD23OYh1u8PvBdrordJGS2YddfQvhcmq9akw==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/client-sso": "3.799.0", - "@aws-sdk/core": "3.799.0", - "@aws-sdk/token-providers": "3.799.0", - "@aws-sdk/types": "3.775.0", - "@smithy/property-provider": "^4.0.2", - "@smithy/shared-ini-file-loader": "^4.0.2", - "@smithy/types": "^4.2.0", + "version": "3.840.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.840.0.tgz", + "integrity": "sha512-2qgdtdd6R0Z1y0KL8gzzwFUGmhBHSUx4zy85L2XV1CXhpRNwV71SVWJqLDVV5RVWVf9mg50Pm3AWrUC0xb0pcA==", + "dependencies": { + "@aws-sdk/client-sso": "3.840.0", + "@aws-sdk/core": "3.840.0", + "@aws-sdk/token-providers": "3.840.0", + "@aws-sdk/types": "3.840.0", + "@smithy/property-provider": "^4.0.4", + "@smithy/shared-ini-file-loader": "^4.0.4", + "@smithy/types": "^4.3.1", "tslib": "^2.6.2" }, "engines": { @@ -15200,16 +15269,15 @@ } }, "node_modules/@aws-sdk/client-cloudformation/node_modules/@aws-sdk/credential-provider-web-identity": { - "version": "3.799.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.799.0.tgz", - "integrity": "sha512-8k1i9ut+BEg0QZ+I6UQMxGNR1T8paLmAOAZXU+nLQR0lcxS6lr8v+dqofgzQPuHLBkWNCr1Av1IKeL3bJjgU7g==", - "license": "Apache-2.0", + "version": "3.840.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.840.0.tgz", + "integrity": "sha512-dpEeVXG8uNZSmVXReE4WP0lwoioX2gstk4RnUgrdUE3YaPq8A+hJiVAyc3h+cjDeIqfbsQbZm9qFetKC2LF9dQ==", "dependencies": { - "@aws-sdk/core": "3.799.0", - "@aws-sdk/nested-clients": "3.799.0", - "@aws-sdk/types": "3.775.0", - "@smithy/property-provider": "^4.0.2", - "@smithy/types": "^4.2.0", + "@aws-sdk/core": "3.840.0", + "@aws-sdk/nested-clients": "3.840.0", + "@aws-sdk/types": "3.840.0", + "@smithy/property-provider": "^4.0.4", + "@smithy/types": "^4.3.1", "tslib": "^2.6.2" }, "engines": { @@ -15217,14 +15285,13 @@ } }, "node_modules/@aws-sdk/client-cloudformation/node_modules/@aws-sdk/middleware-host-header": { - "version": "3.775.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.775.0.tgz", - "integrity": "sha512-tkSegM0Z6WMXpLB8oPys/d+umYIocvO298mGvcMCncpRl77L9XkvSLJIFzaHes+o7djAgIduYw8wKIMStFss2w==", - "license": "Apache-2.0", + "version": "3.840.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.840.0.tgz", + "integrity": "sha512-ub+hXJAbAje94+Ya6c6eL7sYujoE8D4Bumu1NUI8TXjUhVVn0HzVWQjpRLshdLsUp1AW7XyeJaxyajRaJQ8+Xg==", "dependencies": { - "@aws-sdk/types": "3.775.0", - "@smithy/protocol-http": "^5.1.0", - "@smithy/types": "^4.2.0", + "@aws-sdk/types": "3.840.0", + "@smithy/protocol-http": "^5.1.2", + "@smithy/types": "^4.3.1", "tslib": "^2.6.2" }, "engines": { @@ -15232,13 +15299,12 @@ } }, "node_modules/@aws-sdk/client-cloudformation/node_modules/@aws-sdk/middleware-logger": { - "version": "3.775.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.775.0.tgz", - "integrity": "sha512-FaxO1xom4MAoUJsldmR92nT1G6uZxTdNYOFYtdHfd6N2wcNaTuxgjIvqzg5y7QIH9kn58XX/dzf1iTjgqUStZw==", - "license": "Apache-2.0", + "version": "3.840.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.840.0.tgz", + "integrity": "sha512-lSV8FvjpdllpGaRspywss4CtXV8M7NNNH+2/j86vMH+YCOZ6fu2T/TyFd/tHwZ92vDfHctWkRbQxg0bagqwovA==", "dependencies": { - "@aws-sdk/types": "3.775.0", - "@smithy/types": "^4.2.0", + "@aws-sdk/types": "3.840.0", + "@smithy/types": "^4.3.1", "tslib": "^2.6.2" }, "engines": { @@ -15246,14 +15312,13 @@ } }, "node_modules/@aws-sdk/client-cloudformation/node_modules/@aws-sdk/middleware-recursion-detection": { - "version": "3.775.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.775.0.tgz", - "integrity": "sha512-GLCzC8D0A0YDG5u3F5U03Vb9j5tcOEFhr8oc6PDk0k0vm5VwtZOE6LvK7hcCSoAB4HXyOUM0sQuXrbaAh9OwXA==", - "license": "Apache-2.0", + "version": "3.840.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.840.0.tgz", + "integrity": "sha512-Gu7lGDyfddyhIkj1Z1JtrY5NHb5+x/CRiB87GjaSrKxkDaydtX2CU977JIABtt69l9wLbcGDIQ+W0uJ5xPof7g==", "dependencies": { - "@aws-sdk/types": "3.775.0", - "@smithy/protocol-http": "^5.1.0", - "@smithy/types": "^4.2.0", + "@aws-sdk/types": "3.840.0", + "@smithy/protocol-http": "^5.1.2", + "@smithy/types": "^4.3.1", "tslib": "^2.6.2" }, "engines": { @@ -15261,17 +15326,16 @@ } }, "node_modules/@aws-sdk/client-cloudformation/node_modules/@aws-sdk/middleware-user-agent": { - "version": "3.799.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.799.0.tgz", - "integrity": "sha512-TropQZanbOTxa+p+Nl4fWkzlRhgFwDfW+Wb6TR3jZN7IXHNlPpgGFpdrgvBExhW/RBhqr+94OsR8Ou58lp3hhA==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "3.799.0", - "@aws-sdk/types": "3.775.0", - "@aws-sdk/util-endpoints": "3.787.0", - "@smithy/core": "^3.3.0", - "@smithy/protocol-http": "^5.1.0", - "@smithy/types": "^4.2.0", + "version": "3.840.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.840.0.tgz", + "integrity": "sha512-hiiMf7BP5ZkAFAvWRcK67Mw/g55ar7OCrvrynC92hunx/xhMkrgSLM0EXIZ1oTn3uql9kH/qqGF0nqsK6K555A==", + "dependencies": { + "@aws-sdk/core": "3.840.0", + "@aws-sdk/types": "3.840.0", + "@aws-sdk/util-endpoints": "3.840.0", + "@smithy/core": "^3.6.0", + "@smithy/protocol-http": "^5.1.2", + "@smithy/types": "^4.3.1", "tslib": "^2.6.2" }, "engines": { @@ -15279,47 +15343,46 @@ } }, "node_modules/@aws-sdk/client-cloudformation/node_modules/@aws-sdk/nested-clients": { - "version": "3.799.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/nested-clients/-/nested-clients-3.799.0.tgz", - "integrity": "sha512-zILlWh7asrcQG9JYMYgnvEQBfwmWKfED0yWCf3UNAmQcfS9wkCAWCgicNy/y5KvNvEYnHidsU117STtyuUNG5g==", - "license": "Apache-2.0", + "version": "3.840.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/nested-clients/-/nested-clients-3.840.0.tgz", + "integrity": "sha512-LXYYo9+n4hRqnRSIMXLBb+BLz+cEmjMtTudwK1BF6Bn2RfdDv29KuyeDRrPCS3TwKl7ZKmXUmE9n5UuHAPfBpA==", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "3.799.0", - "@aws-sdk/middleware-host-header": "3.775.0", - "@aws-sdk/middleware-logger": "3.775.0", - "@aws-sdk/middleware-recursion-detection": "3.775.0", - "@aws-sdk/middleware-user-agent": "3.799.0", - "@aws-sdk/region-config-resolver": "3.775.0", - "@aws-sdk/types": "3.775.0", - "@aws-sdk/util-endpoints": "3.787.0", - "@aws-sdk/util-user-agent-browser": "3.775.0", - "@aws-sdk/util-user-agent-node": "3.799.0", - "@smithy/config-resolver": "^4.1.0", - "@smithy/core": "^3.3.0", - "@smithy/fetch-http-handler": "^5.0.2", - "@smithy/hash-node": "^4.0.2", - "@smithy/invalid-dependency": "^4.0.2", - "@smithy/middleware-content-length": "^4.0.2", - "@smithy/middleware-endpoint": "^4.1.1", - "@smithy/middleware-retry": "^4.1.1", - "@smithy/middleware-serde": "^4.0.3", - "@smithy/middleware-stack": "^4.0.2", - "@smithy/node-config-provider": "^4.0.2", - "@smithy/node-http-handler": "^4.0.4", - "@smithy/protocol-http": "^5.1.0", - "@smithy/smithy-client": "^4.2.1", - "@smithy/types": "^4.2.0", - "@smithy/url-parser": "^4.0.2", + "@aws-sdk/core": "3.840.0", + "@aws-sdk/middleware-host-header": "3.840.0", + "@aws-sdk/middleware-logger": "3.840.0", + "@aws-sdk/middleware-recursion-detection": "3.840.0", + "@aws-sdk/middleware-user-agent": "3.840.0", + "@aws-sdk/region-config-resolver": "3.840.0", + "@aws-sdk/types": "3.840.0", + "@aws-sdk/util-endpoints": "3.840.0", + "@aws-sdk/util-user-agent-browser": "3.840.0", + "@aws-sdk/util-user-agent-node": "3.840.0", + "@smithy/config-resolver": "^4.1.4", + "@smithy/core": "^3.6.0", + "@smithy/fetch-http-handler": "^5.0.4", + "@smithy/hash-node": "^4.0.4", + "@smithy/invalid-dependency": "^4.0.4", + "@smithy/middleware-content-length": "^4.0.4", + "@smithy/middleware-endpoint": "^4.1.13", + "@smithy/middleware-retry": "^4.1.14", + "@smithy/middleware-serde": "^4.0.8", + "@smithy/middleware-stack": "^4.0.4", + "@smithy/node-config-provider": "^4.1.3", + "@smithy/node-http-handler": "^4.0.6", + "@smithy/protocol-http": "^5.1.2", + "@smithy/smithy-client": "^4.4.5", + "@smithy/types": "^4.3.1", + "@smithy/url-parser": "^4.0.4", "@smithy/util-base64": "^4.0.0", "@smithy/util-body-length-browser": "^4.0.0", "@smithy/util-body-length-node": "^4.0.0", - "@smithy/util-defaults-mode-browser": "^4.0.9", - "@smithy/util-defaults-mode-node": "^4.0.9", - "@smithy/util-endpoints": "^3.0.2", - "@smithy/util-middleware": "^4.0.2", - "@smithy/util-retry": "^4.0.2", + "@smithy/util-defaults-mode-browser": "^4.0.21", + "@smithy/util-defaults-mode-node": "^4.0.21", + "@smithy/util-endpoints": "^3.0.6", + "@smithy/util-middleware": "^4.0.4", + "@smithy/util-retry": "^4.0.6", "@smithy/util-utf8": "^4.0.0", "tslib": "^2.6.2" }, @@ -15327,17 +15390,45 @@ "node": ">=18.0.0" } }, + "node_modules/@aws-sdk/client-cloudformation/node_modules/@aws-sdk/region-config-resolver": { + "version": "3.840.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.840.0.tgz", + "integrity": "sha512-Qjnxd/yDv9KpIMWr90ZDPtRj0v75AqGC92Lm9+oHXZ8p1MjG5JE2CW0HL8JRgK9iKzgKBL7pPQRXI8FkvEVfrA==", + "dependencies": { + "@aws-sdk/types": "3.840.0", + "@smithy/node-config-provider": "^4.1.3", + "@smithy/types": "^4.3.1", + "@smithy/util-config-provider": "^4.0.0", + "@smithy/util-middleware": "^4.0.4", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, "node_modules/@aws-sdk/client-cloudformation/node_modules/@aws-sdk/token-providers": { - "version": "3.799.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.799.0.tgz", - "integrity": "sha512-/8iDjnsJs/D8AhGbDAmdF5oSHzE4jsDsM2RIIxmBAKTZXkaaclQBNX9CmAqLKQmO3IUMZsDH2KENHLVAk/N/mw==", - "license": "Apache-2.0", + "version": "3.840.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.840.0.tgz", + "integrity": "sha512-6BuTOLTXvmgwjK7ve7aTg9JaWFdM5UoMolLVPMyh3wTv9Ufalh8oklxYHUBIxsKkBGO2WiHXytveuxH6tAgTYg==", "dependencies": { - "@aws-sdk/nested-clients": "3.799.0", - "@aws-sdk/types": "3.775.0", - "@smithy/property-provider": "^4.0.2", - "@smithy/shared-ini-file-loader": "^4.0.2", - "@smithy/types": "^4.2.0", + "@aws-sdk/core": "3.840.0", + "@aws-sdk/nested-clients": "3.840.0", + "@aws-sdk/types": "3.840.0", + "@smithy/property-provider": "^4.0.4", + "@smithy/shared-ini-file-loader": "^4.0.4", + "@smithy/types": "^4.3.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-cloudformation/node_modules/@aws-sdk/types": { + "version": "3.840.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.840.0.tgz", + "integrity": "sha512-xliuHaUFZxEx1NSXeLLZ9Dyu6+EJVQKEoD+yM+zqUo3YDZ7medKJWY6fIOKiPX/N7XbLdBYwajb15Q7IL8KkeA==", + "dependencies": { + "@smithy/types": "^4.3.1", "tslib": "^2.6.2" }, "engines": { @@ -15345,14 +15436,13 @@ } }, "node_modules/@aws-sdk/client-cloudformation/node_modules/@aws-sdk/util-endpoints": { - "version": "3.787.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.787.0.tgz", - "integrity": "sha512-fd3zkiOkwnbdbN0Xp9TsP5SWrmv0SpT70YEdbb8wAj2DWQwiCmFszaSs+YCvhoCdmlR3Wl9Spu0pGpSAGKeYvQ==", - "license": "Apache-2.0", + "version": "3.840.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.840.0.tgz", + "integrity": "sha512-eqE9ROdg/Kk0rj3poutyRCFauPDXIf/WSvCqFiRDDVi6QOnCv/M0g2XW8/jSvkJlOyaXkNCptapIp6BeeFFGYw==", "dependencies": { - "@aws-sdk/types": "3.775.0", - "@smithy/types": "^4.2.0", - "@smithy/util-endpoints": "^3.0.2", + "@aws-sdk/types": "3.840.0", + "@smithy/types": "^4.3.1", + "@smithy/util-endpoints": "^3.0.6", "tslib": "^2.6.2" }, "engines": { @@ -15360,27 +15450,25 @@ } }, "node_modules/@aws-sdk/client-cloudformation/node_modules/@aws-sdk/util-user-agent-browser": { - "version": "3.775.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.775.0.tgz", - "integrity": "sha512-txw2wkiJmZKVdDbscK7VBK+u+TJnRtlUjRTLei+elZg2ADhpQxfVAQl436FUeIv6AhB/oRHW6/K/EAGXUSWi0A==", - "license": "Apache-2.0", + "version": "3.840.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.840.0.tgz", + "integrity": "sha512-JdyZM3EhhL4PqwFpttZu1afDpPJCCc3eyZOLi+srpX11LsGj6sThf47TYQN75HT1CarZ7cCdQHGzP2uy3/xHfQ==", "dependencies": { - "@aws-sdk/types": "3.775.0", - "@smithy/types": "^4.2.0", + "@aws-sdk/types": "3.840.0", + "@smithy/types": "^4.3.1", "bowser": "^2.11.0", "tslib": "^2.6.2" } }, "node_modules/@aws-sdk/client-cloudformation/node_modules/@aws-sdk/util-user-agent-node": { - "version": "3.799.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.799.0.tgz", - "integrity": "sha512-iXBk38RbIWPF5Nq9O4AnktORAzXovSVqWYClvS1qbE7ILsnTLJbagU9HlU25O2iV5COVh1qZkwuP5NHQ2yTEyw==", - "license": "Apache-2.0", + "version": "3.840.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.840.0.tgz", + "integrity": "sha512-Fy5JUEDQU1tPm2Yw/YqRYYc27W5+QD/J4mYvQvdWjUGZLB5q3eLFMGD35Uc28ZFoGMufPr4OCxK/bRfWROBRHQ==", "dependencies": { - "@aws-sdk/middleware-user-agent": "3.799.0", - "@aws-sdk/types": "3.775.0", - "@smithy/node-config-provider": "^4.0.2", - "@smithy/types": "^4.2.0", + "@aws-sdk/middleware-user-agent": "3.840.0", + "@aws-sdk/types": "3.840.0", + "@smithy/node-config-provider": "^4.1.3", + "@smithy/types": "^4.3.1", "tslib": "^2.6.2" }, "engines": { @@ -15395,6 +15483,18 @@ } } }, + "node_modules/@aws-sdk/client-cloudformation/node_modules/@aws-sdk/xml-builder": { + "version": "3.821.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/xml-builder/-/xml-builder-3.821.0.tgz", + "integrity": "sha512-DIIotRnefVL6DiaHtO6/21DhJ4JZnnIwdNbpwiAhdt/AVbttcE4yw925gsjur0OGv5BTYXQXU3YnANBYnZjuQA==", + "dependencies": { + "@smithy/types": "^4.3.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, "node_modules/@aws-sdk/client-cloudformation/node_modules/@types/uuid": { "version": "9.0.8", "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.8.tgz", @@ -15871,51 +15971,50 @@ } }, "node_modules/@aws-sdk/client-cloudwatch-logs": { - "version": "3.758.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-cloudwatch-logs/-/client-cloudwatch-logs-3.758.0.tgz", - "integrity": "sha512-IlEIm5h4vfeoZyY8Op4W6lX1lqcEYE3DRKl+fMKRTFttvJ+AJfuZlAgFlMh9OPFQ0ZMLe8etoxHwKN50YCLivw==", - "license": "Apache-2.0", + "version": "3.840.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-cloudwatch-logs/-/client-cloudwatch-logs-3.840.0.tgz", + "integrity": "sha512-fLVyIpED/dSNoGadJdA/3Tv7iVgeuQmr20lWvIaGzKheZPziEmNqH7w8YsbQZoazsTiU6BfLgNSFhFwOmfFvhA==", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "3.758.0", - "@aws-sdk/credential-provider-node": "3.758.0", - "@aws-sdk/middleware-host-header": "3.734.0", - "@aws-sdk/middleware-logger": "3.734.0", - "@aws-sdk/middleware-recursion-detection": "3.734.0", - "@aws-sdk/middleware-user-agent": "3.758.0", - "@aws-sdk/region-config-resolver": "3.734.0", - "@aws-sdk/types": "3.734.0", - "@aws-sdk/util-endpoints": "3.743.0", - "@aws-sdk/util-user-agent-browser": "3.734.0", - "@aws-sdk/util-user-agent-node": "3.758.0", - "@smithy/config-resolver": "^4.0.1", - "@smithy/core": "^3.1.5", - "@smithy/eventstream-serde-browser": "^4.0.1", - "@smithy/eventstream-serde-config-resolver": "^4.0.1", - "@smithy/eventstream-serde-node": "^4.0.1", - "@smithy/fetch-http-handler": "^5.0.1", - "@smithy/hash-node": "^4.0.1", - "@smithy/invalid-dependency": "^4.0.1", - "@smithy/middleware-content-length": "^4.0.1", - "@smithy/middleware-endpoint": "^4.0.6", - "@smithy/middleware-retry": "^4.0.7", - "@smithy/middleware-serde": "^4.0.2", - "@smithy/middleware-stack": "^4.0.1", - "@smithy/node-config-provider": "^4.0.1", - "@smithy/node-http-handler": "^4.0.3", - "@smithy/protocol-http": "^5.0.1", - "@smithy/smithy-client": "^4.1.6", - "@smithy/types": "^4.1.0", - "@smithy/url-parser": "^4.0.1", + "@aws-sdk/core": "3.840.0", + "@aws-sdk/credential-provider-node": "3.840.0", + "@aws-sdk/middleware-host-header": "3.840.0", + "@aws-sdk/middleware-logger": "3.840.0", + "@aws-sdk/middleware-recursion-detection": "3.840.0", + "@aws-sdk/middleware-user-agent": "3.840.0", + "@aws-sdk/region-config-resolver": "3.840.0", + "@aws-sdk/types": "3.840.0", + "@aws-sdk/util-endpoints": "3.840.0", + "@aws-sdk/util-user-agent-browser": "3.840.0", + "@aws-sdk/util-user-agent-node": "3.840.0", + "@smithy/config-resolver": "^4.1.4", + "@smithy/core": "^3.6.0", + "@smithy/eventstream-serde-browser": "^4.0.4", + "@smithy/eventstream-serde-config-resolver": "^4.1.2", + "@smithy/eventstream-serde-node": "^4.0.4", + "@smithy/fetch-http-handler": "^5.0.4", + "@smithy/hash-node": "^4.0.4", + "@smithy/invalid-dependency": "^4.0.4", + "@smithy/middleware-content-length": "^4.0.4", + "@smithy/middleware-endpoint": "^4.1.13", + "@smithy/middleware-retry": "^4.1.14", + "@smithy/middleware-serde": "^4.0.8", + "@smithy/middleware-stack": "^4.0.4", + "@smithy/node-config-provider": "^4.1.3", + "@smithy/node-http-handler": "^4.0.6", + "@smithy/protocol-http": "^5.1.2", + "@smithy/smithy-client": "^4.4.5", + "@smithy/types": "^4.3.1", + "@smithy/url-parser": "^4.0.4", "@smithy/util-base64": "^4.0.0", "@smithy/util-body-length-browser": "^4.0.0", "@smithy/util-body-length-node": "^4.0.0", - "@smithy/util-defaults-mode-browser": "^4.0.7", - "@smithy/util-defaults-mode-node": "^4.0.7", - "@smithy/util-endpoints": "^3.0.1", - "@smithy/util-middleware": "^4.0.1", - "@smithy/util-retry": "^4.0.1", + "@smithy/util-defaults-mode-browser": "^4.0.21", + "@smithy/util-defaults-mode-node": "^4.0.21", + "@smithy/util-endpoints": "^3.0.6", + "@smithy/util-middleware": "^4.0.4", + "@smithy/util-retry": "^4.0.6", "@smithy/util-utf8": "^4.0.0", "@types/uuid": "^9.0.1", "tslib": "^2.6.2", @@ -15925,17 +16024,342 @@ "node": ">=18.0.0" } }, + "node_modules/@aws-sdk/client-cloudwatch-logs/node_modules/@aws-sdk/client-sso": { + "version": "3.840.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.840.0.tgz", + "integrity": "sha512-3Zp+FWN2hhmKdpS0Ragi5V2ZPsZNScE3jlbgoJjzjI/roHZqO+e3/+XFN4TlM0DsPKYJNp+1TAjmhxN6rOnfYA==", + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "3.840.0", + "@aws-sdk/middleware-host-header": "3.840.0", + "@aws-sdk/middleware-logger": "3.840.0", + "@aws-sdk/middleware-recursion-detection": "3.840.0", + "@aws-sdk/middleware-user-agent": "3.840.0", + "@aws-sdk/region-config-resolver": "3.840.0", + "@aws-sdk/types": "3.840.0", + "@aws-sdk/util-endpoints": "3.840.0", + "@aws-sdk/util-user-agent-browser": "3.840.0", + "@aws-sdk/util-user-agent-node": "3.840.0", + "@smithy/config-resolver": "^4.1.4", + "@smithy/core": "^3.6.0", + "@smithy/fetch-http-handler": "^5.0.4", + "@smithy/hash-node": "^4.0.4", + "@smithy/invalid-dependency": "^4.0.4", + "@smithy/middleware-content-length": "^4.0.4", + "@smithy/middleware-endpoint": "^4.1.13", + "@smithy/middleware-retry": "^4.1.14", + "@smithy/middleware-serde": "^4.0.8", + "@smithy/middleware-stack": "^4.0.4", + "@smithy/node-config-provider": "^4.1.3", + "@smithy/node-http-handler": "^4.0.6", + "@smithy/protocol-http": "^5.1.2", + "@smithy/smithy-client": "^4.4.5", + "@smithy/types": "^4.3.1", + "@smithy/url-parser": "^4.0.4", + "@smithy/util-base64": "^4.0.0", + "@smithy/util-body-length-browser": "^4.0.0", + "@smithy/util-body-length-node": "^4.0.0", + "@smithy/util-defaults-mode-browser": "^4.0.21", + "@smithy/util-defaults-mode-node": "^4.0.21", + "@smithy/util-endpoints": "^3.0.6", + "@smithy/util-middleware": "^4.0.4", + "@smithy/util-retry": "^4.0.6", + "@smithy/util-utf8": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-cloudwatch-logs/node_modules/@aws-sdk/core": { + "version": "3.840.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.840.0.tgz", + "integrity": "sha512-x3Zgb39tF1h2XpU+yA4OAAQlW6LVEfXNlSedSYJ7HGKXqA/E9h3rWQVpYfhXXVVsLdYXdNw5KBUkoAoruoZSZA==", + "dependencies": { + "@aws-sdk/types": "3.840.0", + "@aws-sdk/xml-builder": "3.821.0", + "@smithy/core": "^3.6.0", + "@smithy/node-config-provider": "^4.1.3", + "@smithy/property-provider": "^4.0.4", + "@smithy/protocol-http": "^5.1.2", + "@smithy/signature-v4": "^5.1.2", + "@smithy/smithy-client": "^4.4.5", + "@smithy/types": "^4.3.1", + "@smithy/util-base64": "^4.0.0", + "@smithy/util-body-length-browser": "^4.0.0", + "@smithy/util-middleware": "^4.0.4", + "@smithy/util-utf8": "^4.0.0", + "fast-xml-parser": "4.4.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-cloudwatch-logs/node_modules/@aws-sdk/credential-provider-env": { + "version": "3.840.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.840.0.tgz", + "integrity": "sha512-EzF6VcJK7XvQ/G15AVEfJzN2mNXU8fcVpXo4bRyr1S6t2q5zx6UPH/XjDbn18xyUmOq01t+r8gG+TmHEVo18fA==", + "dependencies": { + "@aws-sdk/core": "3.840.0", + "@aws-sdk/types": "3.840.0", + "@smithy/property-provider": "^4.0.4", + "@smithy/types": "^4.3.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-cloudwatch-logs/node_modules/@aws-sdk/credential-provider-http": { + "version": "3.840.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.840.0.tgz", + "integrity": "sha512-wbnUiPGLVea6mXbUh04fu+VJmGkQvmToPeTYdHE8eRZq3NRDi3t3WltT+jArLBKD/4NppRpMjf2ju4coMCz91g==", + "dependencies": { + "@aws-sdk/core": "3.840.0", + "@aws-sdk/types": "3.840.0", + "@smithy/fetch-http-handler": "^5.0.4", + "@smithy/node-http-handler": "^4.0.6", + "@smithy/property-provider": "^4.0.4", + "@smithy/protocol-http": "^5.1.2", + "@smithy/smithy-client": "^4.4.5", + "@smithy/types": "^4.3.1", + "@smithy/util-stream": "^4.2.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-cloudwatch-logs/node_modules/@aws-sdk/credential-provider-ini": { + "version": "3.840.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.840.0.tgz", + "integrity": "sha512-7F290BsWydShHb+7InXd+IjJc3mlEIm9I0R57F/Pjl1xZB69MdkhVGCnuETWoBt4g53ktJd6NEjzm/iAhFXFmw==", + "dependencies": { + "@aws-sdk/core": "3.840.0", + "@aws-sdk/credential-provider-env": "3.840.0", + "@aws-sdk/credential-provider-http": "3.840.0", + "@aws-sdk/credential-provider-process": "3.840.0", + "@aws-sdk/credential-provider-sso": "3.840.0", + "@aws-sdk/credential-provider-web-identity": "3.840.0", + "@aws-sdk/nested-clients": "3.840.0", + "@aws-sdk/types": "3.840.0", + "@smithy/credential-provider-imds": "^4.0.6", + "@smithy/property-provider": "^4.0.4", + "@smithy/shared-ini-file-loader": "^4.0.4", + "@smithy/types": "^4.3.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-cloudwatch-logs/node_modules/@aws-sdk/credential-provider-node": { + "version": "3.840.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.840.0.tgz", + "integrity": "sha512-KufP8JnxA31wxklLm63evUPSFApGcH8X86z3mv9SRbpCm5ycgWIGVCTXpTOdgq6rPZrwT9pftzv2/b4mV/9clg==", + "dependencies": { + "@aws-sdk/credential-provider-env": "3.840.0", + "@aws-sdk/credential-provider-http": "3.840.0", + "@aws-sdk/credential-provider-ini": "3.840.0", + "@aws-sdk/credential-provider-process": "3.840.0", + "@aws-sdk/credential-provider-sso": "3.840.0", + "@aws-sdk/credential-provider-web-identity": "3.840.0", + "@aws-sdk/types": "3.840.0", + "@smithy/credential-provider-imds": "^4.0.6", + "@smithy/property-provider": "^4.0.4", + "@smithy/shared-ini-file-loader": "^4.0.4", + "@smithy/types": "^4.3.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-cloudwatch-logs/node_modules/@aws-sdk/credential-provider-process": { + "version": "3.840.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.840.0.tgz", + "integrity": "sha512-HkDQWHy8tCI4A0Ps2NVtuVYMv9cB4y/IuD/TdOsqeRIAT12h8jDb98BwQPNLAImAOwOWzZJ8Cu0xtSpX7CQhMw==", + "dependencies": { + "@aws-sdk/core": "3.840.0", + "@aws-sdk/types": "3.840.0", + "@smithy/property-provider": "^4.0.4", + "@smithy/shared-ini-file-loader": "^4.0.4", + "@smithy/types": "^4.3.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-cloudwatch-logs/node_modules/@aws-sdk/credential-provider-sso": { + "version": "3.840.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.840.0.tgz", + "integrity": "sha512-2qgdtdd6R0Z1y0KL8gzzwFUGmhBHSUx4zy85L2XV1CXhpRNwV71SVWJqLDVV5RVWVf9mg50Pm3AWrUC0xb0pcA==", + "dependencies": { + "@aws-sdk/client-sso": "3.840.0", + "@aws-sdk/core": "3.840.0", + "@aws-sdk/token-providers": "3.840.0", + "@aws-sdk/types": "3.840.0", + "@smithy/property-provider": "^4.0.4", + "@smithy/shared-ini-file-loader": "^4.0.4", + "@smithy/types": "^4.3.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-cloudwatch-logs/node_modules/@aws-sdk/credential-provider-web-identity": { + "version": "3.840.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.840.0.tgz", + "integrity": "sha512-dpEeVXG8uNZSmVXReE4WP0lwoioX2gstk4RnUgrdUE3YaPq8A+hJiVAyc3h+cjDeIqfbsQbZm9qFetKC2LF9dQ==", + "dependencies": { + "@aws-sdk/core": "3.840.0", + "@aws-sdk/nested-clients": "3.840.0", + "@aws-sdk/types": "3.840.0", + "@smithy/property-provider": "^4.0.4", + "@smithy/types": "^4.3.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-cloudwatch-logs/node_modules/@aws-sdk/middleware-host-header": { + "version": "3.840.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.840.0.tgz", + "integrity": "sha512-ub+hXJAbAje94+Ya6c6eL7sYujoE8D4Bumu1NUI8TXjUhVVn0HzVWQjpRLshdLsUp1AW7XyeJaxyajRaJQ8+Xg==", + "dependencies": { + "@aws-sdk/types": "3.840.0", + "@smithy/protocol-http": "^5.1.2", + "@smithy/types": "^4.3.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-cloudwatch-logs/node_modules/@aws-sdk/middleware-logger": { + "version": "3.840.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.840.0.tgz", + "integrity": "sha512-lSV8FvjpdllpGaRspywss4CtXV8M7NNNH+2/j86vMH+YCOZ6fu2T/TyFd/tHwZ92vDfHctWkRbQxg0bagqwovA==", + "dependencies": { + "@aws-sdk/types": "3.840.0", + "@smithy/types": "^4.3.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-cloudwatch-logs/node_modules/@aws-sdk/middleware-recursion-detection": { + "version": "3.840.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.840.0.tgz", + "integrity": "sha512-Gu7lGDyfddyhIkj1Z1JtrY5NHb5+x/CRiB87GjaSrKxkDaydtX2CU977JIABtt69l9wLbcGDIQ+W0uJ5xPof7g==", + "dependencies": { + "@aws-sdk/types": "3.840.0", + "@smithy/protocol-http": "^5.1.2", + "@smithy/types": "^4.3.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-cloudwatch-logs/node_modules/@aws-sdk/middleware-user-agent": { + "version": "3.840.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.840.0.tgz", + "integrity": "sha512-hiiMf7BP5ZkAFAvWRcK67Mw/g55ar7OCrvrynC92hunx/xhMkrgSLM0EXIZ1oTn3uql9kH/qqGF0nqsK6K555A==", + "dependencies": { + "@aws-sdk/core": "3.840.0", + "@aws-sdk/types": "3.840.0", + "@aws-sdk/util-endpoints": "3.840.0", + "@smithy/core": "^3.6.0", + "@smithy/protocol-http": "^5.1.2", + "@smithy/types": "^4.3.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-cloudwatch-logs/node_modules/@aws-sdk/nested-clients": { + "version": "3.840.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/nested-clients/-/nested-clients-3.840.0.tgz", + "integrity": "sha512-LXYYo9+n4hRqnRSIMXLBb+BLz+cEmjMtTudwK1BF6Bn2RfdDv29KuyeDRrPCS3TwKl7ZKmXUmE9n5UuHAPfBpA==", + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "3.840.0", + "@aws-sdk/middleware-host-header": "3.840.0", + "@aws-sdk/middleware-logger": "3.840.0", + "@aws-sdk/middleware-recursion-detection": "3.840.0", + "@aws-sdk/middleware-user-agent": "3.840.0", + "@aws-sdk/region-config-resolver": "3.840.0", + "@aws-sdk/types": "3.840.0", + "@aws-sdk/util-endpoints": "3.840.0", + "@aws-sdk/util-user-agent-browser": "3.840.0", + "@aws-sdk/util-user-agent-node": "3.840.0", + "@smithy/config-resolver": "^4.1.4", + "@smithy/core": "^3.6.0", + "@smithy/fetch-http-handler": "^5.0.4", + "@smithy/hash-node": "^4.0.4", + "@smithy/invalid-dependency": "^4.0.4", + "@smithy/middleware-content-length": "^4.0.4", + "@smithy/middleware-endpoint": "^4.1.13", + "@smithy/middleware-retry": "^4.1.14", + "@smithy/middleware-serde": "^4.0.8", + "@smithy/middleware-stack": "^4.0.4", + "@smithy/node-config-provider": "^4.1.3", + "@smithy/node-http-handler": "^4.0.6", + "@smithy/protocol-http": "^5.1.2", + "@smithy/smithy-client": "^4.4.5", + "@smithy/types": "^4.3.1", + "@smithy/url-parser": "^4.0.4", + "@smithy/util-base64": "^4.0.0", + "@smithy/util-body-length-browser": "^4.0.0", + "@smithy/util-body-length-node": "^4.0.0", + "@smithy/util-defaults-mode-browser": "^4.0.21", + "@smithy/util-defaults-mode-node": "^4.0.21", + "@smithy/util-endpoints": "^3.0.6", + "@smithy/util-middleware": "^4.0.4", + "@smithy/util-retry": "^4.0.6", + "@smithy/util-utf8": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, "node_modules/@aws-sdk/client-cloudwatch-logs/node_modules/@aws-sdk/region-config-resolver": { - "version": "3.734.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.734.0.tgz", - "integrity": "sha512-Lvj1kPRC5IuJBr9DyJ9T9/plkh+EfKLy+12s/mykOy1JaKHDpvj+XGy2YO6YgYVOb8JFtaqloid+5COtje4JTQ==", - "license": "Apache-2.0", + "version": "3.840.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.840.0.tgz", + "integrity": "sha512-Qjnxd/yDv9KpIMWr90ZDPtRj0v75AqGC92Lm9+oHXZ8p1MjG5JE2CW0HL8JRgK9iKzgKBL7pPQRXI8FkvEVfrA==", "dependencies": { - "@aws-sdk/types": "3.734.0", - "@smithy/node-config-provider": "^4.0.1", - "@smithy/types": "^4.1.0", + "@aws-sdk/types": "3.840.0", + "@smithy/node-config-provider": "^4.1.3", + "@smithy/types": "^4.3.1", "@smithy/util-config-provider": "^4.0.0", - "@smithy/util-middleware": "^4.0.1", + "@smithy/util-middleware": "^4.0.4", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-cloudwatch-logs/node_modules/@aws-sdk/token-providers": { + "version": "3.840.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.840.0.tgz", + "integrity": "sha512-6BuTOLTXvmgwjK7ve7aTg9JaWFdM5UoMolLVPMyh3wTv9Ufalh8oklxYHUBIxsKkBGO2WiHXytveuxH6tAgTYg==", + "dependencies": { + "@aws-sdk/core": "3.840.0", + "@aws-sdk/nested-clients": "3.840.0", + "@aws-sdk/types": "3.840.0", + "@smithy/property-provider": "^4.0.4", + "@smithy/shared-ini-file-loader": "^4.0.4", + "@smithy/types": "^4.3.1", "tslib": "^2.6.2" }, "engines": { @@ -15943,12 +16367,71 @@ } }, "node_modules/@aws-sdk/client-cloudwatch-logs/node_modules/@aws-sdk/types": { - "version": "3.734.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.734.0.tgz", - "integrity": "sha512-o11tSPTT70nAkGV1fN9wm/hAIiLPyWX6SuGf+9JyTp7S/rC2cFWhR26MvA69nplcjNaXVzB0f+QFrLXXjOqCrg==", - "license": "Apache-2.0", + "version": "3.840.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.840.0.tgz", + "integrity": "sha512-xliuHaUFZxEx1NSXeLLZ9Dyu6+EJVQKEoD+yM+zqUo3YDZ7medKJWY6fIOKiPX/N7XbLdBYwajb15Q7IL8KkeA==", "dependencies": { - "@smithy/types": "^4.1.0", + "@smithy/types": "^4.3.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-cloudwatch-logs/node_modules/@aws-sdk/util-endpoints": { + "version": "3.840.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.840.0.tgz", + "integrity": "sha512-eqE9ROdg/Kk0rj3poutyRCFauPDXIf/WSvCqFiRDDVi6QOnCv/M0g2XW8/jSvkJlOyaXkNCptapIp6BeeFFGYw==", + "dependencies": { + "@aws-sdk/types": "3.840.0", + "@smithy/types": "^4.3.1", + "@smithy/util-endpoints": "^3.0.6", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-cloudwatch-logs/node_modules/@aws-sdk/util-user-agent-browser": { + "version": "3.840.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.840.0.tgz", + "integrity": "sha512-JdyZM3EhhL4PqwFpttZu1afDpPJCCc3eyZOLi+srpX11LsGj6sThf47TYQN75HT1CarZ7cCdQHGzP2uy3/xHfQ==", + "dependencies": { + "@aws-sdk/types": "3.840.0", + "@smithy/types": "^4.3.1", + "bowser": "^2.11.0", + "tslib": "^2.6.2" + } + }, + "node_modules/@aws-sdk/client-cloudwatch-logs/node_modules/@aws-sdk/util-user-agent-node": { + "version": "3.840.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.840.0.tgz", + "integrity": "sha512-Fy5JUEDQU1tPm2Yw/YqRYYc27W5+QD/J4mYvQvdWjUGZLB5q3eLFMGD35Uc28ZFoGMufPr4OCxK/bRfWROBRHQ==", + "dependencies": { + "@aws-sdk/middleware-user-agent": "3.840.0", + "@aws-sdk/types": "3.840.0", + "@smithy/node-config-provider": "^4.1.3", + "@smithy/types": "^4.3.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + }, + "peerDependencies": { + "aws-crt": ">=1.0.0" + }, + "peerDependenciesMeta": { + "aws-crt": { + "optional": true + } + } + }, + "node_modules/@aws-sdk/client-cloudwatch-logs/node_modules/@aws-sdk/xml-builder": { + "version": "3.821.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/xml-builder/-/xml-builder-3.821.0.tgz", + "integrity": "sha512-DIIotRnefVL6DiaHtO6/21DhJ4JZnnIwdNbpwiAhdt/AVbttcE4yw925gsjur0OGv5BTYXQXU3YnANBYnZjuQA==", + "dependencies": { + "@smithy/types": "^4.3.1", "tslib": "^2.6.2" }, "engines": { @@ -18425,50 +18908,49 @@ } }, "node_modules/@aws-sdk/client-iam": { - "version": "3.787.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-iam/-/client-iam-3.787.0.tgz", - "integrity": "sha512-m1dTjDlnIINKVJdMww4tXu/9v/FIuqoMxlys2Z5FQHkqVs+kNt2kKjE/btY5zT6wo+mMt0MJwqsqyTHs/42pAQ==", - "license": "Apache-2.0", + "version": "3.840.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-iam/-/client-iam-3.840.0.tgz", + "integrity": "sha512-+HWqpTwXQYhFzgwfjGFHfo+a0mRQwYq29BEYlgfcydo8UOApc1oxsVmEmnYh2nbukaefUkOaMDb1xORybsE6Lw==", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "3.775.0", - "@aws-sdk/credential-provider-node": "3.787.0", - "@aws-sdk/middleware-host-header": "3.775.0", - "@aws-sdk/middleware-logger": "3.775.0", - "@aws-sdk/middleware-recursion-detection": "3.775.0", - "@aws-sdk/middleware-user-agent": "3.787.0", - "@aws-sdk/region-config-resolver": "3.775.0", - "@aws-sdk/types": "3.775.0", - "@aws-sdk/util-endpoints": "3.787.0", - "@aws-sdk/util-user-agent-browser": "3.775.0", - "@aws-sdk/util-user-agent-node": "3.787.0", - "@smithy/config-resolver": "^4.1.0", - "@smithy/core": "^3.2.0", - "@smithy/fetch-http-handler": "^5.0.2", - "@smithy/hash-node": "^4.0.2", - "@smithy/invalid-dependency": "^4.0.2", - "@smithy/middleware-content-length": "^4.0.2", - "@smithy/middleware-endpoint": "^4.1.0", - "@smithy/middleware-retry": "^4.1.0", - "@smithy/middleware-serde": "^4.0.3", - "@smithy/middleware-stack": "^4.0.2", - "@smithy/node-config-provider": "^4.0.2", - "@smithy/node-http-handler": "^4.0.4", - "@smithy/protocol-http": "^5.1.0", - "@smithy/smithy-client": "^4.2.0", - "@smithy/types": "^4.2.0", - "@smithy/url-parser": "^4.0.2", + "@aws-sdk/core": "3.840.0", + "@aws-sdk/credential-provider-node": "3.840.0", + "@aws-sdk/middleware-host-header": "3.840.0", + "@aws-sdk/middleware-logger": "3.840.0", + "@aws-sdk/middleware-recursion-detection": "3.840.0", + "@aws-sdk/middleware-user-agent": "3.840.0", + "@aws-sdk/region-config-resolver": "3.840.0", + "@aws-sdk/types": "3.840.0", + "@aws-sdk/util-endpoints": "3.840.0", + "@aws-sdk/util-user-agent-browser": "3.840.0", + "@aws-sdk/util-user-agent-node": "3.840.0", + "@smithy/config-resolver": "^4.1.4", + "@smithy/core": "^3.6.0", + "@smithy/fetch-http-handler": "^5.0.4", + "@smithy/hash-node": "^4.0.4", + "@smithy/invalid-dependency": "^4.0.4", + "@smithy/middleware-content-length": "^4.0.4", + "@smithy/middleware-endpoint": "^4.1.13", + "@smithy/middleware-retry": "^4.1.14", + "@smithy/middleware-serde": "^4.0.8", + "@smithy/middleware-stack": "^4.0.4", + "@smithy/node-config-provider": "^4.1.3", + "@smithy/node-http-handler": "^4.0.6", + "@smithy/protocol-http": "^5.1.2", + "@smithy/smithy-client": "^4.4.5", + "@smithy/types": "^4.3.1", + "@smithy/url-parser": "^4.0.4", "@smithy/util-base64": "^4.0.0", "@smithy/util-body-length-browser": "^4.0.0", "@smithy/util-body-length-node": "^4.0.0", - "@smithy/util-defaults-mode-browser": "^4.0.8", - "@smithy/util-defaults-mode-node": "^4.0.8", - "@smithy/util-endpoints": "^3.0.2", - "@smithy/util-middleware": "^4.0.2", - "@smithy/util-retry": "^4.0.2", + "@smithy/util-defaults-mode-browser": "^4.0.21", + "@smithy/util-defaults-mode-node": "^4.0.21", + "@smithy/util-endpoints": "^3.0.6", + "@smithy/util-middleware": "^4.0.4", + "@smithy/util-retry": "^4.0.6", "@smithy/util-utf8": "^4.0.0", - "@smithy/util-waiter": "^4.0.3", + "@smithy/util-waiter": "^4.0.6", "tslib": "^2.6.2" }, "engines": { @@ -18476,47 +18958,46 @@ } }, "node_modules/@aws-sdk/client-iam/node_modules/@aws-sdk/client-sso": { - "version": "3.787.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.787.0.tgz", - "integrity": "sha512-L8R+Mh258G0DC73ktpSVrG4TT9i2vmDLecARTDR/4q5sRivdDQSL5bUp3LKcK80Bx+FRw3UETIlX6mYMLL9PJQ==", - "license": "Apache-2.0", + "version": "3.840.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.840.0.tgz", + "integrity": "sha512-3Zp+FWN2hhmKdpS0Ragi5V2ZPsZNScE3jlbgoJjzjI/roHZqO+e3/+XFN4TlM0DsPKYJNp+1TAjmhxN6rOnfYA==", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "3.775.0", - "@aws-sdk/middleware-host-header": "3.775.0", - "@aws-sdk/middleware-logger": "3.775.0", - "@aws-sdk/middleware-recursion-detection": "3.775.0", - "@aws-sdk/middleware-user-agent": "3.787.0", - "@aws-sdk/region-config-resolver": "3.775.0", - "@aws-sdk/types": "3.775.0", - "@aws-sdk/util-endpoints": "3.787.0", - "@aws-sdk/util-user-agent-browser": "3.775.0", - "@aws-sdk/util-user-agent-node": "3.787.0", - "@smithy/config-resolver": "^4.1.0", - "@smithy/core": "^3.2.0", - "@smithy/fetch-http-handler": "^5.0.2", - "@smithy/hash-node": "^4.0.2", - "@smithy/invalid-dependency": "^4.0.2", - "@smithy/middleware-content-length": "^4.0.2", - "@smithy/middleware-endpoint": "^4.1.0", - "@smithy/middleware-retry": "^4.1.0", - "@smithy/middleware-serde": "^4.0.3", - "@smithy/middleware-stack": "^4.0.2", - "@smithy/node-config-provider": "^4.0.2", - "@smithy/node-http-handler": "^4.0.4", - "@smithy/protocol-http": "^5.1.0", - "@smithy/smithy-client": "^4.2.0", - "@smithy/types": "^4.2.0", - "@smithy/url-parser": "^4.0.2", + "@aws-sdk/core": "3.840.0", + "@aws-sdk/middleware-host-header": "3.840.0", + "@aws-sdk/middleware-logger": "3.840.0", + "@aws-sdk/middleware-recursion-detection": "3.840.0", + "@aws-sdk/middleware-user-agent": "3.840.0", + "@aws-sdk/region-config-resolver": "3.840.0", + "@aws-sdk/types": "3.840.0", + "@aws-sdk/util-endpoints": "3.840.0", + "@aws-sdk/util-user-agent-browser": "3.840.0", + "@aws-sdk/util-user-agent-node": "3.840.0", + "@smithy/config-resolver": "^4.1.4", + "@smithy/core": "^3.6.0", + "@smithy/fetch-http-handler": "^5.0.4", + "@smithy/hash-node": "^4.0.4", + "@smithy/invalid-dependency": "^4.0.4", + "@smithy/middleware-content-length": "^4.0.4", + "@smithy/middleware-endpoint": "^4.1.13", + "@smithy/middleware-retry": "^4.1.14", + "@smithy/middleware-serde": "^4.0.8", + "@smithy/middleware-stack": "^4.0.4", + "@smithy/node-config-provider": "^4.1.3", + "@smithy/node-http-handler": "^4.0.6", + "@smithy/protocol-http": "^5.1.2", + "@smithy/smithy-client": "^4.4.5", + "@smithy/types": "^4.3.1", + "@smithy/url-parser": "^4.0.4", "@smithy/util-base64": "^4.0.0", "@smithy/util-body-length-browser": "^4.0.0", "@smithy/util-body-length-node": "^4.0.0", - "@smithy/util-defaults-mode-browser": "^4.0.8", - "@smithy/util-defaults-mode-node": "^4.0.8", - "@smithy/util-endpoints": "^3.0.2", - "@smithy/util-middleware": "^4.0.2", - "@smithy/util-retry": "^4.0.2", + "@smithy/util-defaults-mode-browser": "^4.0.21", + "@smithy/util-defaults-mode-node": "^4.0.21", + "@smithy/util-endpoints": "^3.0.6", + "@smithy/util-middleware": "^4.0.4", + "@smithy/util-retry": "^4.0.6", "@smithy/util-utf8": "^4.0.0", "tslib": "^2.6.2" }, @@ -18525,20 +19006,23 @@ } }, "node_modules/@aws-sdk/client-iam/node_modules/@aws-sdk/core": { - "version": "3.775.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.775.0.tgz", - "integrity": "sha512-8vpW4WihVfz0DX+7WnnLGm3GuQER++b0IwQG35JlQMlgqnc44M//KbJPsIHA0aJUJVwJAEShgfr5dUbY8WUzaA==", - "license": "Apache-2.0", + "version": "3.840.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.840.0.tgz", + "integrity": "sha512-x3Zgb39tF1h2XpU+yA4OAAQlW6LVEfXNlSedSYJ7HGKXqA/E9h3rWQVpYfhXXVVsLdYXdNw5KBUkoAoruoZSZA==", "dependencies": { - "@aws-sdk/types": "3.775.0", - "@smithy/core": "^3.2.0", - "@smithy/node-config-provider": "^4.0.2", - "@smithy/property-provider": "^4.0.2", - "@smithy/protocol-http": "^5.1.0", - "@smithy/signature-v4": "^5.0.2", - "@smithy/smithy-client": "^4.2.0", - "@smithy/types": "^4.2.0", - "@smithy/util-middleware": "^4.0.2", + "@aws-sdk/types": "3.840.0", + "@aws-sdk/xml-builder": "3.821.0", + "@smithy/core": "^3.6.0", + "@smithy/node-config-provider": "^4.1.3", + "@smithy/property-provider": "^4.0.4", + "@smithy/protocol-http": "^5.1.2", + "@smithy/signature-v4": "^5.1.2", + "@smithy/smithy-client": "^4.4.5", + "@smithy/types": "^4.3.1", + "@smithy/util-base64": "^4.0.0", + "@smithy/util-body-length-browser": "^4.0.0", + "@smithy/util-middleware": "^4.0.4", + "@smithy/util-utf8": "^4.0.0", "fast-xml-parser": "4.4.1", "tslib": "^2.6.2" }, @@ -18547,15 +19031,14 @@ } }, "node_modules/@aws-sdk/client-iam/node_modules/@aws-sdk/credential-provider-env": { - "version": "3.775.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.775.0.tgz", - "integrity": "sha512-6ESVxwCbGm7WZ17kY1fjmxQud43vzJFoLd4bmlR+idQSWdqlzGDYdcfzpjDKTcivdtNrVYmFvcH1JBUwCRAZhw==", - "license": "Apache-2.0", + "version": "3.840.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.840.0.tgz", + "integrity": "sha512-EzF6VcJK7XvQ/G15AVEfJzN2mNXU8fcVpXo4bRyr1S6t2q5zx6UPH/XjDbn18xyUmOq01t+r8gG+TmHEVo18fA==", "dependencies": { - "@aws-sdk/core": "3.775.0", - "@aws-sdk/types": "3.775.0", - "@smithy/property-provider": "^4.0.2", - "@smithy/types": "^4.2.0", + "@aws-sdk/core": "3.840.0", + "@aws-sdk/types": "3.840.0", + "@smithy/property-provider": "^4.0.4", + "@smithy/types": "^4.3.1", "tslib": "^2.6.2" }, "engines": { @@ -18563,20 +19046,19 @@ } }, "node_modules/@aws-sdk/client-iam/node_modules/@aws-sdk/credential-provider-http": { - "version": "3.775.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.775.0.tgz", - "integrity": "sha512-PjDQeDH/J1S0yWV32wCj2k5liRo0ssXMseCBEkCsD3SqsU8o5cU82b0hMX4sAib/RkglCSZqGO0xMiN0/7ndww==", - "license": "Apache-2.0", + "version": "3.840.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.840.0.tgz", + "integrity": "sha512-wbnUiPGLVea6mXbUh04fu+VJmGkQvmToPeTYdHE8eRZq3NRDi3t3WltT+jArLBKD/4NppRpMjf2ju4coMCz91g==", "dependencies": { - "@aws-sdk/core": "3.775.0", - "@aws-sdk/types": "3.775.0", - "@smithy/fetch-http-handler": "^5.0.2", - "@smithy/node-http-handler": "^4.0.4", - "@smithy/property-provider": "^4.0.2", - "@smithy/protocol-http": "^5.1.0", - "@smithy/smithy-client": "^4.2.0", - "@smithy/types": "^4.2.0", - "@smithy/util-stream": "^4.2.0", + "@aws-sdk/core": "3.840.0", + "@aws-sdk/types": "3.840.0", + "@smithy/fetch-http-handler": "^5.0.4", + "@smithy/node-http-handler": "^4.0.6", + "@smithy/property-provider": "^4.0.4", + "@smithy/protocol-http": "^5.1.2", + "@smithy/smithy-client": "^4.4.5", + "@smithy/types": "^4.3.1", + "@smithy/util-stream": "^4.2.2", "tslib": "^2.6.2" }, "engines": { @@ -18584,23 +19066,22 @@ } }, "node_modules/@aws-sdk/client-iam/node_modules/@aws-sdk/credential-provider-ini": { - "version": "3.787.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.787.0.tgz", - "integrity": "sha512-hc2taRoDlXn2uuNuHWDJljVWYrp3r9JF1a/8XmOAZhVUNY+ImeeStylHXhXXKEA4JOjW+5PdJj0f1UDkVCHJiQ==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "3.775.0", - "@aws-sdk/credential-provider-env": "3.775.0", - "@aws-sdk/credential-provider-http": "3.775.0", - "@aws-sdk/credential-provider-process": "3.775.0", - "@aws-sdk/credential-provider-sso": "3.787.0", - "@aws-sdk/credential-provider-web-identity": "3.787.0", - "@aws-sdk/nested-clients": "3.787.0", - "@aws-sdk/types": "3.775.0", - "@smithy/credential-provider-imds": "^4.0.2", - "@smithy/property-provider": "^4.0.2", - "@smithy/shared-ini-file-loader": "^4.0.2", - "@smithy/types": "^4.2.0", + "version": "3.840.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.840.0.tgz", + "integrity": "sha512-7F290BsWydShHb+7InXd+IjJc3mlEIm9I0R57F/Pjl1xZB69MdkhVGCnuETWoBt4g53ktJd6NEjzm/iAhFXFmw==", + "dependencies": { + "@aws-sdk/core": "3.840.0", + "@aws-sdk/credential-provider-env": "3.840.0", + "@aws-sdk/credential-provider-http": "3.840.0", + "@aws-sdk/credential-provider-process": "3.840.0", + "@aws-sdk/credential-provider-sso": "3.840.0", + "@aws-sdk/credential-provider-web-identity": "3.840.0", + "@aws-sdk/nested-clients": "3.840.0", + "@aws-sdk/types": "3.840.0", + "@smithy/credential-provider-imds": "^4.0.6", + "@smithy/property-provider": "^4.0.4", + "@smithy/shared-ini-file-loader": "^4.0.4", + "@smithy/types": "^4.3.1", "tslib": "^2.6.2" }, "engines": { @@ -18608,22 +19089,21 @@ } }, "node_modules/@aws-sdk/client-iam/node_modules/@aws-sdk/credential-provider-node": { - "version": "3.787.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.787.0.tgz", - "integrity": "sha512-JioVi44B1vDMaK2CdzqimwvJD3uzvzbQhaEWXsGMBcMcNHajXAXf08EF50JG3ZhLrhhUsT1ObXpbTaPINOhh+g==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/credential-provider-env": "3.775.0", - "@aws-sdk/credential-provider-http": "3.775.0", - "@aws-sdk/credential-provider-ini": "3.787.0", - "@aws-sdk/credential-provider-process": "3.775.0", - "@aws-sdk/credential-provider-sso": "3.787.0", - "@aws-sdk/credential-provider-web-identity": "3.787.0", - "@aws-sdk/types": "3.775.0", - "@smithy/credential-provider-imds": "^4.0.2", - "@smithy/property-provider": "^4.0.2", - "@smithy/shared-ini-file-loader": "^4.0.2", - "@smithy/types": "^4.2.0", + "version": "3.840.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.840.0.tgz", + "integrity": "sha512-KufP8JnxA31wxklLm63evUPSFApGcH8X86z3mv9SRbpCm5ycgWIGVCTXpTOdgq6rPZrwT9pftzv2/b4mV/9clg==", + "dependencies": { + "@aws-sdk/credential-provider-env": "3.840.0", + "@aws-sdk/credential-provider-http": "3.840.0", + "@aws-sdk/credential-provider-ini": "3.840.0", + "@aws-sdk/credential-provider-process": "3.840.0", + "@aws-sdk/credential-provider-sso": "3.840.0", + "@aws-sdk/credential-provider-web-identity": "3.840.0", + "@aws-sdk/types": "3.840.0", + "@smithy/credential-provider-imds": "^4.0.6", + "@smithy/property-provider": "^4.0.4", + "@smithy/shared-ini-file-loader": "^4.0.4", + "@smithy/types": "^4.3.1", "tslib": "^2.6.2" }, "engines": { @@ -18631,16 +19111,15 @@ } }, "node_modules/@aws-sdk/client-iam/node_modules/@aws-sdk/credential-provider-process": { - "version": "3.775.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.775.0.tgz", - "integrity": "sha512-A6k68H9rQp+2+7P7SGO90Csw6nrUEm0Qfjpn9Etc4EboZhhCLs9b66umUsTsSBHus4FDIe5JQxfCUyt1wgNogg==", - "license": "Apache-2.0", + "version": "3.840.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.840.0.tgz", + "integrity": "sha512-HkDQWHy8tCI4A0Ps2NVtuVYMv9cB4y/IuD/TdOsqeRIAT12h8jDb98BwQPNLAImAOwOWzZJ8Cu0xtSpX7CQhMw==", "dependencies": { - "@aws-sdk/core": "3.775.0", - "@aws-sdk/types": "3.775.0", - "@smithy/property-provider": "^4.0.2", - "@smithy/shared-ini-file-loader": "^4.0.2", - "@smithy/types": "^4.2.0", + "@aws-sdk/core": "3.840.0", + "@aws-sdk/types": "3.840.0", + "@smithy/property-provider": "^4.0.4", + "@smithy/shared-ini-file-loader": "^4.0.4", + "@smithy/types": "^4.3.1", "tslib": "^2.6.2" }, "engines": { @@ -18648,18 +19127,17 @@ } }, "node_modules/@aws-sdk/client-iam/node_modules/@aws-sdk/credential-provider-sso": { - "version": "3.787.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.787.0.tgz", - "integrity": "sha512-fHc08bsvwm4+dEMEQKnQ7c1irEQmmxbgS+Fq41y09pPvPh31nAhoMcjBSTWAaPHvvsRbTYvmP4Mf12ZGr8/nfg==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/client-sso": "3.787.0", - "@aws-sdk/core": "3.775.0", - "@aws-sdk/token-providers": "3.787.0", - "@aws-sdk/types": "3.775.0", - "@smithy/property-provider": "^4.0.2", - "@smithy/shared-ini-file-loader": "^4.0.2", - "@smithy/types": "^4.2.0", + "version": "3.840.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.840.0.tgz", + "integrity": "sha512-2qgdtdd6R0Z1y0KL8gzzwFUGmhBHSUx4zy85L2XV1CXhpRNwV71SVWJqLDVV5RVWVf9mg50Pm3AWrUC0xb0pcA==", + "dependencies": { + "@aws-sdk/client-sso": "3.840.0", + "@aws-sdk/core": "3.840.0", + "@aws-sdk/token-providers": "3.840.0", + "@aws-sdk/types": "3.840.0", + "@smithy/property-provider": "^4.0.4", + "@smithy/shared-ini-file-loader": "^4.0.4", + "@smithy/types": "^4.3.1", "tslib": "^2.6.2" }, "engines": { @@ -18667,16 +19145,15 @@ } }, "node_modules/@aws-sdk/client-iam/node_modules/@aws-sdk/credential-provider-web-identity": { - "version": "3.787.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.787.0.tgz", - "integrity": "sha512-SobmCwNbk6TfEsF283mZPQEI5vV2j6eY5tOCj8Er4Lzraxu9fBPADV+Bib2A8F6jlB1lMPJzOuDCbEasSt/RIw==", - "license": "Apache-2.0", + "version": "3.840.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.840.0.tgz", + "integrity": "sha512-dpEeVXG8uNZSmVXReE4WP0lwoioX2gstk4RnUgrdUE3YaPq8A+hJiVAyc3h+cjDeIqfbsQbZm9qFetKC2LF9dQ==", "dependencies": { - "@aws-sdk/core": "3.775.0", - "@aws-sdk/nested-clients": "3.787.0", - "@aws-sdk/types": "3.775.0", - "@smithy/property-provider": "^4.0.2", - "@smithy/types": "^4.2.0", + "@aws-sdk/core": "3.840.0", + "@aws-sdk/nested-clients": "3.840.0", + "@aws-sdk/types": "3.840.0", + "@smithy/property-provider": "^4.0.4", + "@smithy/types": "^4.3.1", "tslib": "^2.6.2" }, "engines": { @@ -18684,14 +19161,13 @@ } }, "node_modules/@aws-sdk/client-iam/node_modules/@aws-sdk/middleware-host-header": { - "version": "3.775.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.775.0.tgz", - "integrity": "sha512-tkSegM0Z6WMXpLB8oPys/d+umYIocvO298mGvcMCncpRl77L9XkvSLJIFzaHes+o7djAgIduYw8wKIMStFss2w==", - "license": "Apache-2.0", + "version": "3.840.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.840.0.tgz", + "integrity": "sha512-ub+hXJAbAje94+Ya6c6eL7sYujoE8D4Bumu1NUI8TXjUhVVn0HzVWQjpRLshdLsUp1AW7XyeJaxyajRaJQ8+Xg==", "dependencies": { - "@aws-sdk/types": "3.775.0", - "@smithy/protocol-http": "^5.1.0", - "@smithy/types": "^4.2.0", + "@aws-sdk/types": "3.840.0", + "@smithy/protocol-http": "^5.1.2", + "@smithy/types": "^4.3.1", "tslib": "^2.6.2" }, "engines": { @@ -18699,13 +19175,12 @@ } }, "node_modules/@aws-sdk/client-iam/node_modules/@aws-sdk/middleware-logger": { - "version": "3.775.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.775.0.tgz", - "integrity": "sha512-FaxO1xom4MAoUJsldmR92nT1G6uZxTdNYOFYtdHfd6N2wcNaTuxgjIvqzg5y7QIH9kn58XX/dzf1iTjgqUStZw==", - "license": "Apache-2.0", + "version": "3.840.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.840.0.tgz", + "integrity": "sha512-lSV8FvjpdllpGaRspywss4CtXV8M7NNNH+2/j86vMH+YCOZ6fu2T/TyFd/tHwZ92vDfHctWkRbQxg0bagqwovA==", "dependencies": { - "@aws-sdk/types": "3.775.0", - "@smithy/types": "^4.2.0", + "@aws-sdk/types": "3.840.0", + "@smithy/types": "^4.3.1", "tslib": "^2.6.2" }, "engines": { @@ -18713,14 +19188,13 @@ } }, "node_modules/@aws-sdk/client-iam/node_modules/@aws-sdk/middleware-recursion-detection": { - "version": "3.775.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.775.0.tgz", - "integrity": "sha512-GLCzC8D0A0YDG5u3F5U03Vb9j5tcOEFhr8oc6PDk0k0vm5VwtZOE6LvK7hcCSoAB4HXyOUM0sQuXrbaAh9OwXA==", - "license": "Apache-2.0", + "version": "3.840.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.840.0.tgz", + "integrity": "sha512-Gu7lGDyfddyhIkj1Z1JtrY5NHb5+x/CRiB87GjaSrKxkDaydtX2CU977JIABtt69l9wLbcGDIQ+W0uJ5xPof7g==", "dependencies": { - "@aws-sdk/types": "3.775.0", - "@smithy/protocol-http": "^5.1.0", - "@smithy/types": "^4.2.0", + "@aws-sdk/types": "3.840.0", + "@smithy/protocol-http": "^5.1.2", + "@smithy/types": "^4.3.1", "tslib": "^2.6.2" }, "engines": { @@ -18728,17 +19202,16 @@ } }, "node_modules/@aws-sdk/client-iam/node_modules/@aws-sdk/middleware-user-agent": { - "version": "3.787.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.787.0.tgz", - "integrity": "sha512-Lnfj8SmPLYtrDFthNIaNj66zZsBCam+E4XiUDr55DIHTGstH6qZ/q6vg0GfbukxwSmUcGMwSR4Qbn8rb8yd77g==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "3.775.0", - "@aws-sdk/types": "3.775.0", - "@aws-sdk/util-endpoints": "3.787.0", - "@smithy/core": "^3.2.0", - "@smithy/protocol-http": "^5.1.0", - "@smithy/types": "^4.2.0", + "version": "3.840.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.840.0.tgz", + "integrity": "sha512-hiiMf7BP5ZkAFAvWRcK67Mw/g55ar7OCrvrynC92hunx/xhMkrgSLM0EXIZ1oTn3uql9kH/qqGF0nqsK6K555A==", + "dependencies": { + "@aws-sdk/core": "3.840.0", + "@aws-sdk/types": "3.840.0", + "@aws-sdk/util-endpoints": "3.840.0", + "@smithy/core": "^3.6.0", + "@smithy/protocol-http": "^5.1.2", + "@smithy/types": "^4.3.1", "tslib": "^2.6.2" }, "engines": { @@ -18746,47 +19219,46 @@ } }, "node_modules/@aws-sdk/client-iam/node_modules/@aws-sdk/nested-clients": { - "version": "3.787.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/nested-clients/-/nested-clients-3.787.0.tgz", - "integrity": "sha512-xk03q1xpKNHgbuo+trEf1dFrI239kuMmjKKsqLEsHlAZbuFq4yRGMlHBrVMnKYOPBhVFDS/VineM991XI52fKg==", - "license": "Apache-2.0", + "version": "3.840.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/nested-clients/-/nested-clients-3.840.0.tgz", + "integrity": "sha512-LXYYo9+n4hRqnRSIMXLBb+BLz+cEmjMtTudwK1BF6Bn2RfdDv29KuyeDRrPCS3TwKl7ZKmXUmE9n5UuHAPfBpA==", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "3.775.0", - "@aws-sdk/middleware-host-header": "3.775.0", - "@aws-sdk/middleware-logger": "3.775.0", - "@aws-sdk/middleware-recursion-detection": "3.775.0", - "@aws-sdk/middleware-user-agent": "3.787.0", - "@aws-sdk/region-config-resolver": "3.775.0", - "@aws-sdk/types": "3.775.0", - "@aws-sdk/util-endpoints": "3.787.0", - "@aws-sdk/util-user-agent-browser": "3.775.0", - "@aws-sdk/util-user-agent-node": "3.787.0", - "@smithy/config-resolver": "^4.1.0", - "@smithy/core": "^3.2.0", - "@smithy/fetch-http-handler": "^5.0.2", - "@smithy/hash-node": "^4.0.2", - "@smithy/invalid-dependency": "^4.0.2", - "@smithy/middleware-content-length": "^4.0.2", - "@smithy/middleware-endpoint": "^4.1.0", - "@smithy/middleware-retry": "^4.1.0", - "@smithy/middleware-serde": "^4.0.3", - "@smithy/middleware-stack": "^4.0.2", - "@smithy/node-config-provider": "^4.0.2", - "@smithy/node-http-handler": "^4.0.4", - "@smithy/protocol-http": "^5.1.0", - "@smithy/smithy-client": "^4.2.0", - "@smithy/types": "^4.2.0", - "@smithy/url-parser": "^4.0.2", + "@aws-sdk/core": "3.840.0", + "@aws-sdk/middleware-host-header": "3.840.0", + "@aws-sdk/middleware-logger": "3.840.0", + "@aws-sdk/middleware-recursion-detection": "3.840.0", + "@aws-sdk/middleware-user-agent": "3.840.0", + "@aws-sdk/region-config-resolver": "3.840.0", + "@aws-sdk/types": "3.840.0", + "@aws-sdk/util-endpoints": "3.840.0", + "@aws-sdk/util-user-agent-browser": "3.840.0", + "@aws-sdk/util-user-agent-node": "3.840.0", + "@smithy/config-resolver": "^4.1.4", + "@smithy/core": "^3.6.0", + "@smithy/fetch-http-handler": "^5.0.4", + "@smithy/hash-node": "^4.0.4", + "@smithy/invalid-dependency": "^4.0.4", + "@smithy/middleware-content-length": "^4.0.4", + "@smithy/middleware-endpoint": "^4.1.13", + "@smithy/middleware-retry": "^4.1.14", + "@smithy/middleware-serde": "^4.0.8", + "@smithy/middleware-stack": "^4.0.4", + "@smithy/node-config-provider": "^4.1.3", + "@smithy/node-http-handler": "^4.0.6", + "@smithy/protocol-http": "^5.1.2", + "@smithy/smithy-client": "^4.4.5", + "@smithy/types": "^4.3.1", + "@smithy/url-parser": "^4.0.4", "@smithy/util-base64": "^4.0.0", "@smithy/util-body-length-browser": "^4.0.0", "@smithy/util-body-length-node": "^4.0.0", - "@smithy/util-defaults-mode-browser": "^4.0.8", - "@smithy/util-defaults-mode-node": "^4.0.8", - "@smithy/util-endpoints": "^3.0.2", - "@smithy/util-middleware": "^4.0.2", - "@smithy/util-retry": "^4.0.2", + "@smithy/util-defaults-mode-browser": "^4.0.21", + "@smithy/util-defaults-mode-node": "^4.0.21", + "@smithy/util-endpoints": "^3.0.6", + "@smithy/util-middleware": "^4.0.4", + "@smithy/util-retry": "^4.0.6", "@smithy/util-utf8": "^4.0.0", "tslib": "^2.6.2" }, @@ -18794,17 +19266,45 @@ "node": ">=18.0.0" } }, + "node_modules/@aws-sdk/client-iam/node_modules/@aws-sdk/region-config-resolver": { + "version": "3.840.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.840.0.tgz", + "integrity": "sha512-Qjnxd/yDv9KpIMWr90ZDPtRj0v75AqGC92Lm9+oHXZ8p1MjG5JE2CW0HL8JRgK9iKzgKBL7pPQRXI8FkvEVfrA==", + "dependencies": { + "@aws-sdk/types": "3.840.0", + "@smithy/node-config-provider": "^4.1.3", + "@smithy/types": "^4.3.1", + "@smithy/util-config-provider": "^4.0.0", + "@smithy/util-middleware": "^4.0.4", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, "node_modules/@aws-sdk/client-iam/node_modules/@aws-sdk/token-providers": { - "version": "3.787.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.787.0.tgz", - "integrity": "sha512-d7/NIqxq308Zg0RPMNrmn0QvzniL4Hx8Qdwzr6YZWLYAbUSvZYS2ppLR3BFWSkV6SsTJUx8BuDaj3P8vttkrog==", - "license": "Apache-2.0", + "version": "3.840.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.840.0.tgz", + "integrity": "sha512-6BuTOLTXvmgwjK7ve7aTg9JaWFdM5UoMolLVPMyh3wTv9Ufalh8oklxYHUBIxsKkBGO2WiHXytveuxH6tAgTYg==", "dependencies": { - "@aws-sdk/nested-clients": "3.787.0", - "@aws-sdk/types": "3.775.0", - "@smithy/property-provider": "^4.0.2", - "@smithy/shared-ini-file-loader": "^4.0.2", - "@smithy/types": "^4.2.0", + "@aws-sdk/core": "3.840.0", + "@aws-sdk/nested-clients": "3.840.0", + "@aws-sdk/types": "3.840.0", + "@smithy/property-provider": "^4.0.4", + "@smithy/shared-ini-file-loader": "^4.0.4", + "@smithy/types": "^4.3.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-iam/node_modules/@aws-sdk/types": { + "version": "3.840.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.840.0.tgz", + "integrity": "sha512-xliuHaUFZxEx1NSXeLLZ9Dyu6+EJVQKEoD+yM+zqUo3YDZ7medKJWY6fIOKiPX/N7XbLdBYwajb15Q7IL8KkeA==", + "dependencies": { + "@smithy/types": "^4.3.1", "tslib": "^2.6.2" }, "engines": { @@ -18812,14 +19312,13 @@ } }, "node_modules/@aws-sdk/client-iam/node_modules/@aws-sdk/util-endpoints": { - "version": "3.787.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.787.0.tgz", - "integrity": "sha512-fd3zkiOkwnbdbN0Xp9TsP5SWrmv0SpT70YEdbb8wAj2DWQwiCmFszaSs+YCvhoCdmlR3Wl9Spu0pGpSAGKeYvQ==", - "license": "Apache-2.0", + "version": "3.840.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.840.0.tgz", + "integrity": "sha512-eqE9ROdg/Kk0rj3poutyRCFauPDXIf/WSvCqFiRDDVi6QOnCv/M0g2XW8/jSvkJlOyaXkNCptapIp6BeeFFGYw==", "dependencies": { - "@aws-sdk/types": "3.775.0", - "@smithy/types": "^4.2.0", - "@smithy/util-endpoints": "^3.0.2", + "@aws-sdk/types": "3.840.0", + "@smithy/types": "^4.3.1", + "@smithy/util-endpoints": "^3.0.6", "tslib": "^2.6.2" }, "engines": { @@ -18827,27 +19326,25 @@ } }, "node_modules/@aws-sdk/client-iam/node_modules/@aws-sdk/util-user-agent-browser": { - "version": "3.775.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.775.0.tgz", - "integrity": "sha512-txw2wkiJmZKVdDbscK7VBK+u+TJnRtlUjRTLei+elZg2ADhpQxfVAQl436FUeIv6AhB/oRHW6/K/EAGXUSWi0A==", - "license": "Apache-2.0", + "version": "3.840.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.840.0.tgz", + "integrity": "sha512-JdyZM3EhhL4PqwFpttZu1afDpPJCCc3eyZOLi+srpX11LsGj6sThf47TYQN75HT1CarZ7cCdQHGzP2uy3/xHfQ==", "dependencies": { - "@aws-sdk/types": "3.775.0", - "@smithy/types": "^4.2.0", + "@aws-sdk/types": "3.840.0", + "@smithy/types": "^4.3.1", "bowser": "^2.11.0", "tslib": "^2.6.2" } }, "node_modules/@aws-sdk/client-iam/node_modules/@aws-sdk/util-user-agent-node": { - "version": "3.787.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.787.0.tgz", - "integrity": "sha512-mG7Lz8ydfG4SF9e8WSXiPQ/Lsn3n8A5B5jtPROidafi06I3ckV2WxyMLdwG14m919NoS6IOfWHyRGSqWIwbVKA==", - "license": "Apache-2.0", + "version": "3.840.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.840.0.tgz", + "integrity": "sha512-Fy5JUEDQU1tPm2Yw/YqRYYc27W5+QD/J4mYvQvdWjUGZLB5q3eLFMGD35Uc28ZFoGMufPr4OCxK/bRfWROBRHQ==", "dependencies": { - "@aws-sdk/middleware-user-agent": "3.787.0", - "@aws-sdk/types": "3.775.0", - "@smithy/node-config-provider": "^4.0.2", - "@smithy/types": "^4.2.0", + "@aws-sdk/middleware-user-agent": "3.840.0", + "@aws-sdk/types": "3.840.0", + "@smithy/node-config-provider": "^4.1.3", + "@smithy/types": "^4.3.1", "tslib": "^2.6.2" }, "engines": { @@ -18862,6 +19359,18 @@ } } }, + "node_modules/@aws-sdk/client-iam/node_modules/@aws-sdk/xml-builder": { + "version": "3.821.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/xml-builder/-/xml-builder-3.821.0.tgz", + "integrity": "sha512-DIIotRnefVL6DiaHtO6/21DhJ4JZnnIwdNbpwiAhdt/AVbttcE4yw925gsjur0OGv5BTYXQXU3YnANBYnZjuQA==", + "dependencies": { + "@smithy/types": "^4.3.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, "node_modules/@aws-sdk/client-kinesis": { "version": "3.621.0", "resolved": "https://registry.npmjs.org/@aws-sdk/client-kinesis/-/client-kinesis-3.621.0.tgz", @@ -20073,54 +20582,53 @@ } }, "node_modules/@aws-sdk/client-lambda": { - "version": "3.799.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-lambda/-/client-lambda-3.799.0.tgz", - "integrity": "sha512-6GTL1zLtbi4ebcx+RBpU1dVYX7ReI3lt+rG3lzdYzRFa1OFnKVLSC5h06Y6arIMub9jtIWE060LioD3DoQteLw==", - "license": "Apache-2.0", + "version": "3.840.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-lambda/-/client-lambda-3.840.0.tgz", + "integrity": "sha512-aUKHKWW4Z1nxQ0q/shHkSA278oyv+lRJSvpin1GJXQumDdMKcOuXktmufOCZzjbl6UVw/Pqaw6V1Vo2gda6RdQ==", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "3.799.0", - "@aws-sdk/credential-provider-node": "3.799.0", - "@aws-sdk/middleware-host-header": "3.775.0", - "@aws-sdk/middleware-logger": "3.775.0", - "@aws-sdk/middleware-recursion-detection": "3.775.0", - "@aws-sdk/middleware-user-agent": "3.799.0", - "@aws-sdk/region-config-resolver": "3.775.0", - "@aws-sdk/types": "3.775.0", - "@aws-sdk/util-endpoints": "3.787.0", - "@aws-sdk/util-user-agent-browser": "3.775.0", - "@aws-sdk/util-user-agent-node": "3.799.0", - "@smithy/config-resolver": "^4.1.0", - "@smithy/core": "^3.3.0", - "@smithy/eventstream-serde-browser": "^4.0.2", - "@smithy/eventstream-serde-config-resolver": "^4.1.0", - "@smithy/eventstream-serde-node": "^4.0.2", - "@smithy/fetch-http-handler": "^5.0.2", - "@smithy/hash-node": "^4.0.2", - "@smithy/invalid-dependency": "^4.0.2", - "@smithy/middleware-content-length": "^4.0.2", - "@smithy/middleware-endpoint": "^4.1.1", - "@smithy/middleware-retry": "^4.1.1", - "@smithy/middleware-serde": "^4.0.3", - "@smithy/middleware-stack": "^4.0.2", - "@smithy/node-config-provider": "^4.0.2", - "@smithy/node-http-handler": "^4.0.4", - "@smithy/protocol-http": "^5.1.0", - "@smithy/smithy-client": "^4.2.1", - "@smithy/types": "^4.2.0", - "@smithy/url-parser": "^4.0.2", + "@aws-sdk/core": "3.840.0", + "@aws-sdk/credential-provider-node": "3.840.0", + "@aws-sdk/middleware-host-header": "3.840.0", + "@aws-sdk/middleware-logger": "3.840.0", + "@aws-sdk/middleware-recursion-detection": "3.840.0", + "@aws-sdk/middleware-user-agent": "3.840.0", + "@aws-sdk/region-config-resolver": "3.840.0", + "@aws-sdk/types": "3.840.0", + "@aws-sdk/util-endpoints": "3.840.0", + "@aws-sdk/util-user-agent-browser": "3.840.0", + "@aws-sdk/util-user-agent-node": "3.840.0", + "@smithy/config-resolver": "^4.1.4", + "@smithy/core": "^3.6.0", + "@smithy/eventstream-serde-browser": "^4.0.4", + "@smithy/eventstream-serde-config-resolver": "^4.1.2", + "@smithy/eventstream-serde-node": "^4.0.4", + "@smithy/fetch-http-handler": "^5.0.4", + "@smithy/hash-node": "^4.0.4", + "@smithy/invalid-dependency": "^4.0.4", + "@smithy/middleware-content-length": "^4.0.4", + "@smithy/middleware-endpoint": "^4.1.13", + "@smithy/middleware-retry": "^4.1.14", + "@smithy/middleware-serde": "^4.0.8", + "@smithy/middleware-stack": "^4.0.4", + "@smithy/node-config-provider": "^4.1.3", + "@smithy/node-http-handler": "^4.0.6", + "@smithy/protocol-http": "^5.1.2", + "@smithy/smithy-client": "^4.4.5", + "@smithy/types": "^4.3.1", + "@smithy/url-parser": "^4.0.4", "@smithy/util-base64": "^4.0.0", "@smithy/util-body-length-browser": "^4.0.0", "@smithy/util-body-length-node": "^4.0.0", - "@smithy/util-defaults-mode-browser": "^4.0.9", - "@smithy/util-defaults-mode-node": "^4.0.9", - "@smithy/util-endpoints": "^3.0.2", - "@smithy/util-middleware": "^4.0.2", - "@smithy/util-retry": "^4.0.2", - "@smithy/util-stream": "^4.2.0", + "@smithy/util-defaults-mode-browser": "^4.0.21", + "@smithy/util-defaults-mode-node": "^4.0.21", + "@smithy/util-endpoints": "^3.0.6", + "@smithy/util-middleware": "^4.0.4", + "@smithy/util-retry": "^4.0.6", + "@smithy/util-stream": "^4.2.2", "@smithy/util-utf8": "^4.0.0", - "@smithy/util-waiter": "^4.0.3", + "@smithy/util-waiter": "^4.0.6", "tslib": "^2.6.2" }, "engines": { @@ -20128,47 +20636,46 @@ } }, "node_modules/@aws-sdk/client-lambda/node_modules/@aws-sdk/client-sso": { - "version": "3.799.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.799.0.tgz", - "integrity": "sha512-/i/LG7AiWPmPxKCA2jnR2zaf7B3HYSTbxaZI21ElIz9wASlNAsKr8CnLY7qb50kOyXiNfQ834S5Q3Gl8dX9o3Q==", - "license": "Apache-2.0", + "version": "3.840.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.840.0.tgz", + "integrity": "sha512-3Zp+FWN2hhmKdpS0Ragi5V2ZPsZNScE3jlbgoJjzjI/roHZqO+e3/+XFN4TlM0DsPKYJNp+1TAjmhxN6rOnfYA==", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "3.799.0", - "@aws-sdk/middleware-host-header": "3.775.0", - "@aws-sdk/middleware-logger": "3.775.0", - "@aws-sdk/middleware-recursion-detection": "3.775.0", - "@aws-sdk/middleware-user-agent": "3.799.0", - "@aws-sdk/region-config-resolver": "3.775.0", - "@aws-sdk/types": "3.775.0", - "@aws-sdk/util-endpoints": "3.787.0", - "@aws-sdk/util-user-agent-browser": "3.775.0", - "@aws-sdk/util-user-agent-node": "3.799.0", - "@smithy/config-resolver": "^4.1.0", - "@smithy/core": "^3.3.0", - "@smithy/fetch-http-handler": "^5.0.2", - "@smithy/hash-node": "^4.0.2", - "@smithy/invalid-dependency": "^4.0.2", - "@smithy/middleware-content-length": "^4.0.2", - "@smithy/middleware-endpoint": "^4.1.1", - "@smithy/middleware-retry": "^4.1.1", - "@smithy/middleware-serde": "^4.0.3", - "@smithy/middleware-stack": "^4.0.2", - "@smithy/node-config-provider": "^4.0.2", - "@smithy/node-http-handler": "^4.0.4", - "@smithy/protocol-http": "^5.1.0", - "@smithy/smithy-client": "^4.2.1", - "@smithy/types": "^4.2.0", - "@smithy/url-parser": "^4.0.2", + "@aws-sdk/core": "3.840.0", + "@aws-sdk/middleware-host-header": "3.840.0", + "@aws-sdk/middleware-logger": "3.840.0", + "@aws-sdk/middleware-recursion-detection": "3.840.0", + "@aws-sdk/middleware-user-agent": "3.840.0", + "@aws-sdk/region-config-resolver": "3.840.0", + "@aws-sdk/types": "3.840.0", + "@aws-sdk/util-endpoints": "3.840.0", + "@aws-sdk/util-user-agent-browser": "3.840.0", + "@aws-sdk/util-user-agent-node": "3.840.0", + "@smithy/config-resolver": "^4.1.4", + "@smithy/core": "^3.6.0", + "@smithy/fetch-http-handler": "^5.0.4", + "@smithy/hash-node": "^4.0.4", + "@smithy/invalid-dependency": "^4.0.4", + "@smithy/middleware-content-length": "^4.0.4", + "@smithy/middleware-endpoint": "^4.1.13", + "@smithy/middleware-retry": "^4.1.14", + "@smithy/middleware-serde": "^4.0.8", + "@smithy/middleware-stack": "^4.0.4", + "@smithy/node-config-provider": "^4.1.3", + "@smithy/node-http-handler": "^4.0.6", + "@smithy/protocol-http": "^5.1.2", + "@smithy/smithy-client": "^4.4.5", + "@smithy/types": "^4.3.1", + "@smithy/url-parser": "^4.0.4", "@smithy/util-base64": "^4.0.0", "@smithy/util-body-length-browser": "^4.0.0", "@smithy/util-body-length-node": "^4.0.0", - "@smithy/util-defaults-mode-browser": "^4.0.9", - "@smithy/util-defaults-mode-node": "^4.0.9", - "@smithy/util-endpoints": "^3.0.2", - "@smithy/util-middleware": "^4.0.2", - "@smithy/util-retry": "^4.0.2", + "@smithy/util-defaults-mode-browser": "^4.0.21", + "@smithy/util-defaults-mode-node": "^4.0.21", + "@smithy/util-endpoints": "^3.0.6", + "@smithy/util-middleware": "^4.0.4", + "@smithy/util-retry": "^4.0.6", "@smithy/util-utf8": "^4.0.0", "tslib": "^2.6.2" }, @@ -20177,20 +20684,23 @@ } }, "node_modules/@aws-sdk/client-lambda/node_modules/@aws-sdk/core": { - "version": "3.799.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.799.0.tgz", - "integrity": "sha512-hkKF3Zpc6+H8GI1rlttYVRh9uEE77cqAzLmLpY3iu7sql8cZgPERRBfaFct8p1SaDyrksLNiboD1vKW58mbsYg==", - "license": "Apache-2.0", + "version": "3.840.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.840.0.tgz", + "integrity": "sha512-x3Zgb39tF1h2XpU+yA4OAAQlW6LVEfXNlSedSYJ7HGKXqA/E9h3rWQVpYfhXXVVsLdYXdNw5KBUkoAoruoZSZA==", "dependencies": { - "@aws-sdk/types": "3.775.0", - "@smithy/core": "^3.3.0", - "@smithy/node-config-provider": "^4.0.2", - "@smithy/property-provider": "^4.0.2", - "@smithy/protocol-http": "^5.1.0", - "@smithy/signature-v4": "^5.1.0", - "@smithy/smithy-client": "^4.2.1", - "@smithy/types": "^4.2.0", - "@smithy/util-middleware": "^4.0.2", + "@aws-sdk/types": "3.840.0", + "@aws-sdk/xml-builder": "3.821.0", + "@smithy/core": "^3.6.0", + "@smithy/node-config-provider": "^4.1.3", + "@smithy/property-provider": "^4.0.4", + "@smithy/protocol-http": "^5.1.2", + "@smithy/signature-v4": "^5.1.2", + "@smithy/smithy-client": "^4.4.5", + "@smithy/types": "^4.3.1", + "@smithy/util-base64": "^4.0.0", + "@smithy/util-body-length-browser": "^4.0.0", + "@smithy/util-middleware": "^4.0.4", + "@smithy/util-utf8": "^4.0.0", "fast-xml-parser": "4.4.1", "tslib": "^2.6.2" }, @@ -20199,15 +20709,14 @@ } }, "node_modules/@aws-sdk/client-lambda/node_modules/@aws-sdk/credential-provider-env": { - "version": "3.799.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.799.0.tgz", - "integrity": "sha512-vT/SSWtbUIOW/U21qgEySmmO44SFWIA7WeQPX1OrI8WJ5n7OEI23JWLHjLvHTkYmuZK6z1rPcv7HzRgmuGRibA==", - "license": "Apache-2.0", + "version": "3.840.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.840.0.tgz", + "integrity": "sha512-EzF6VcJK7XvQ/G15AVEfJzN2mNXU8fcVpXo4bRyr1S6t2q5zx6UPH/XjDbn18xyUmOq01t+r8gG+TmHEVo18fA==", "dependencies": { - "@aws-sdk/core": "3.799.0", - "@aws-sdk/types": "3.775.0", - "@smithy/property-provider": "^4.0.2", - "@smithy/types": "^4.2.0", + "@aws-sdk/core": "3.840.0", + "@aws-sdk/types": "3.840.0", + "@smithy/property-provider": "^4.0.4", + "@smithy/types": "^4.3.1", "tslib": "^2.6.2" }, "engines": { @@ -20215,43 +20724,64 @@ } }, "node_modules/@aws-sdk/client-lambda/node_modules/@aws-sdk/credential-provider-http": { - "version": "3.799.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.799.0.tgz", - "integrity": "sha512-2CjBpOWmhaPAExOgHnIB5nOkS5ef+mfRlJ1JC4nsnjAx0nrK4tk0XRE0LYz11P3+ue+a86cU8WTmBo+qjnGxPQ==", - "license": "Apache-2.0", + "version": "3.840.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.840.0.tgz", + "integrity": "sha512-wbnUiPGLVea6mXbUh04fu+VJmGkQvmToPeTYdHE8eRZq3NRDi3t3WltT+jArLBKD/4NppRpMjf2ju4coMCz91g==", "dependencies": { - "@aws-sdk/core": "3.799.0", - "@aws-sdk/types": "3.775.0", - "@smithy/fetch-http-handler": "^5.0.2", - "@smithy/node-http-handler": "^4.0.4", - "@smithy/property-provider": "^4.0.2", - "@smithy/protocol-http": "^5.1.0", - "@smithy/smithy-client": "^4.2.1", - "@smithy/types": "^4.2.0", - "@smithy/util-stream": "^4.2.0", + "@aws-sdk/core": "3.840.0", + "@aws-sdk/types": "3.840.0", + "@smithy/fetch-http-handler": "^5.0.4", + "@smithy/node-http-handler": "^4.0.6", + "@smithy/property-provider": "^4.0.4", + "@smithy/protocol-http": "^5.1.2", + "@smithy/smithy-client": "^4.4.5", + "@smithy/types": "^4.3.1", + "@smithy/util-stream": "^4.2.2", "tslib": "^2.6.2" }, "engines": { "node": ">=18.0.0" } }, - "node_modules/@aws-sdk/client-lambda/node_modules/@aws-sdk/credential-provider-node": { - "version": "3.799.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.799.0.tgz", - "integrity": "sha512-nd9fSJc0wUlgKUkIr2ldJhcIIrzJFS29AGZoyY22J3xih63nNDv61eTGVMsDZzHlV21XzMlPEljTR7axiimckg==", - "license": "Apache-2.0", + "node_modules/@aws-sdk/client-lambda/node_modules/@aws-sdk/credential-provider-ini": { + "version": "3.840.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.840.0.tgz", + "integrity": "sha512-7F290BsWydShHb+7InXd+IjJc3mlEIm9I0R57F/Pjl1xZB69MdkhVGCnuETWoBt4g53ktJd6NEjzm/iAhFXFmw==", "dependencies": { - "@aws-sdk/credential-provider-env": "3.799.0", - "@aws-sdk/credential-provider-http": "3.799.0", - "@aws-sdk/credential-provider-ini": "3.799.0", - "@aws-sdk/credential-provider-process": "3.799.0", - "@aws-sdk/credential-provider-sso": "3.799.0", - "@aws-sdk/credential-provider-web-identity": "3.799.0", - "@aws-sdk/types": "3.775.0", - "@smithy/credential-provider-imds": "^4.0.2", - "@smithy/property-provider": "^4.0.2", - "@smithy/shared-ini-file-loader": "^4.0.2", - "@smithy/types": "^4.2.0", + "@aws-sdk/core": "3.840.0", + "@aws-sdk/credential-provider-env": "3.840.0", + "@aws-sdk/credential-provider-http": "3.840.0", + "@aws-sdk/credential-provider-process": "3.840.0", + "@aws-sdk/credential-provider-sso": "3.840.0", + "@aws-sdk/credential-provider-web-identity": "3.840.0", + "@aws-sdk/nested-clients": "3.840.0", + "@aws-sdk/types": "3.840.0", + "@smithy/credential-provider-imds": "^4.0.6", + "@smithy/property-provider": "^4.0.4", + "@smithy/shared-ini-file-loader": "^4.0.4", + "@smithy/types": "^4.3.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-lambda/node_modules/@aws-sdk/credential-provider-node": { + "version": "3.840.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.840.0.tgz", + "integrity": "sha512-KufP8JnxA31wxklLm63evUPSFApGcH8X86z3mv9SRbpCm5ycgWIGVCTXpTOdgq6rPZrwT9pftzv2/b4mV/9clg==", + "dependencies": { + "@aws-sdk/credential-provider-env": "3.840.0", + "@aws-sdk/credential-provider-http": "3.840.0", + "@aws-sdk/credential-provider-ini": "3.840.0", + "@aws-sdk/credential-provider-process": "3.840.0", + "@aws-sdk/credential-provider-sso": "3.840.0", + "@aws-sdk/credential-provider-web-identity": "3.840.0", + "@aws-sdk/types": "3.840.0", + "@smithy/credential-provider-imds": "^4.0.6", + "@smithy/property-provider": "^4.0.4", + "@smithy/shared-ini-file-loader": "^4.0.4", + "@smithy/types": "^4.3.1", "tslib": "^2.6.2" }, "engines": { @@ -20259,16 +20789,15 @@ } }, "node_modules/@aws-sdk/client-lambda/node_modules/@aws-sdk/credential-provider-process": { - "version": "3.799.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.799.0.tgz", - "integrity": "sha512-g8jmNs2k98WNHMYcea1YKA+7ao2Ma4w0P42Dz4YpcI155pQHxHx25RwbOG+rsAKuo3bKwkW53HVE/ZTKhcWFgw==", - "license": "Apache-2.0", + "version": "3.840.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.840.0.tgz", + "integrity": "sha512-HkDQWHy8tCI4A0Ps2NVtuVYMv9cB4y/IuD/TdOsqeRIAT12h8jDb98BwQPNLAImAOwOWzZJ8Cu0xtSpX7CQhMw==", "dependencies": { - "@aws-sdk/core": "3.799.0", - "@aws-sdk/types": "3.775.0", - "@smithy/property-provider": "^4.0.2", - "@smithy/shared-ini-file-loader": "^4.0.2", - "@smithy/types": "^4.2.0", + "@aws-sdk/core": "3.840.0", + "@aws-sdk/types": "3.840.0", + "@smithy/property-provider": "^4.0.4", + "@smithy/shared-ini-file-loader": "^4.0.4", + "@smithy/types": "^4.3.1", "tslib": "^2.6.2" }, "engines": { @@ -20276,18 +20805,17 @@ } }, "node_modules/@aws-sdk/client-lambda/node_modules/@aws-sdk/credential-provider-sso": { - "version": "3.799.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.799.0.tgz", - "integrity": "sha512-lQv27QkNU9FJFZqEf5DIEN3uXEN409Iaym9WJzhOouGtxvTIAWiD23OYh1u8PvBdrordJGS2YddfQvhcmq9akw==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/client-sso": "3.799.0", - "@aws-sdk/core": "3.799.0", - "@aws-sdk/token-providers": "3.799.0", - "@aws-sdk/types": "3.775.0", - "@smithy/property-provider": "^4.0.2", - "@smithy/shared-ini-file-loader": "^4.0.2", - "@smithy/types": "^4.2.0", + "version": "3.840.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.840.0.tgz", + "integrity": "sha512-2qgdtdd6R0Z1y0KL8gzzwFUGmhBHSUx4zy85L2XV1CXhpRNwV71SVWJqLDVV5RVWVf9mg50Pm3AWrUC0xb0pcA==", + "dependencies": { + "@aws-sdk/client-sso": "3.840.0", + "@aws-sdk/core": "3.840.0", + "@aws-sdk/token-providers": "3.840.0", + "@aws-sdk/types": "3.840.0", + "@smithy/property-provider": "^4.0.4", + "@smithy/shared-ini-file-loader": "^4.0.4", + "@smithy/types": "^4.3.1", "tslib": "^2.6.2" }, "engines": { @@ -20295,16 +20823,15 @@ } }, "node_modules/@aws-sdk/client-lambda/node_modules/@aws-sdk/credential-provider-web-identity": { - "version": "3.799.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.799.0.tgz", - "integrity": "sha512-8k1i9ut+BEg0QZ+I6UQMxGNR1T8paLmAOAZXU+nLQR0lcxS6lr8v+dqofgzQPuHLBkWNCr1Av1IKeL3bJjgU7g==", - "license": "Apache-2.0", + "version": "3.840.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.840.0.tgz", + "integrity": "sha512-dpEeVXG8uNZSmVXReE4WP0lwoioX2gstk4RnUgrdUE3YaPq8A+hJiVAyc3h+cjDeIqfbsQbZm9qFetKC2LF9dQ==", "dependencies": { - "@aws-sdk/core": "3.799.0", - "@aws-sdk/nested-clients": "3.799.0", - "@aws-sdk/types": "3.775.0", - "@smithy/property-provider": "^4.0.2", - "@smithy/types": "^4.2.0", + "@aws-sdk/core": "3.840.0", + "@aws-sdk/nested-clients": "3.840.0", + "@aws-sdk/types": "3.840.0", + "@smithy/property-provider": "^4.0.4", + "@smithy/types": "^4.3.1", "tslib": "^2.6.2" }, "engines": { @@ -20312,14 +20839,13 @@ } }, "node_modules/@aws-sdk/client-lambda/node_modules/@aws-sdk/middleware-host-header": { - "version": "3.775.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.775.0.tgz", - "integrity": "sha512-tkSegM0Z6WMXpLB8oPys/d+umYIocvO298mGvcMCncpRl77L9XkvSLJIFzaHes+o7djAgIduYw8wKIMStFss2w==", - "license": "Apache-2.0", + "version": "3.840.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.840.0.tgz", + "integrity": "sha512-ub+hXJAbAje94+Ya6c6eL7sYujoE8D4Bumu1NUI8TXjUhVVn0HzVWQjpRLshdLsUp1AW7XyeJaxyajRaJQ8+Xg==", "dependencies": { - "@aws-sdk/types": "3.775.0", - "@smithy/protocol-http": "^5.1.0", - "@smithy/types": "^4.2.0", + "@aws-sdk/types": "3.840.0", + "@smithy/protocol-http": "^5.1.2", + "@smithy/types": "^4.3.1", "tslib": "^2.6.2" }, "engines": { @@ -20327,13 +20853,12 @@ } }, "node_modules/@aws-sdk/client-lambda/node_modules/@aws-sdk/middleware-logger": { - "version": "3.775.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.775.0.tgz", - "integrity": "sha512-FaxO1xom4MAoUJsldmR92nT1G6uZxTdNYOFYtdHfd6N2wcNaTuxgjIvqzg5y7QIH9kn58XX/dzf1iTjgqUStZw==", - "license": "Apache-2.0", + "version": "3.840.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.840.0.tgz", + "integrity": "sha512-lSV8FvjpdllpGaRspywss4CtXV8M7NNNH+2/j86vMH+YCOZ6fu2T/TyFd/tHwZ92vDfHctWkRbQxg0bagqwovA==", "dependencies": { - "@aws-sdk/types": "3.775.0", - "@smithy/types": "^4.2.0", + "@aws-sdk/types": "3.840.0", + "@smithy/types": "^4.3.1", "tslib": "^2.6.2" }, "engines": { @@ -20341,14 +20866,13 @@ } }, "node_modules/@aws-sdk/client-lambda/node_modules/@aws-sdk/middleware-recursion-detection": { - "version": "3.775.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.775.0.tgz", - "integrity": "sha512-GLCzC8D0A0YDG5u3F5U03Vb9j5tcOEFhr8oc6PDk0k0vm5VwtZOE6LvK7hcCSoAB4HXyOUM0sQuXrbaAh9OwXA==", - "license": "Apache-2.0", + "version": "3.840.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.840.0.tgz", + "integrity": "sha512-Gu7lGDyfddyhIkj1Z1JtrY5NHb5+x/CRiB87GjaSrKxkDaydtX2CU977JIABtt69l9wLbcGDIQ+W0uJ5xPof7g==", "dependencies": { - "@aws-sdk/types": "3.775.0", - "@smithy/protocol-http": "^5.1.0", - "@smithy/types": "^4.2.0", + "@aws-sdk/types": "3.840.0", + "@smithy/protocol-http": "^5.1.2", + "@smithy/types": "^4.3.1", "tslib": "^2.6.2" }, "engines": { @@ -20356,17 +20880,16 @@ } }, "node_modules/@aws-sdk/client-lambda/node_modules/@aws-sdk/middleware-user-agent": { - "version": "3.799.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.799.0.tgz", - "integrity": "sha512-TropQZanbOTxa+p+Nl4fWkzlRhgFwDfW+Wb6TR3jZN7IXHNlPpgGFpdrgvBExhW/RBhqr+94OsR8Ou58lp3hhA==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "3.799.0", - "@aws-sdk/types": "3.775.0", - "@aws-sdk/util-endpoints": "3.787.0", - "@smithy/core": "^3.3.0", - "@smithy/protocol-http": "^5.1.0", - "@smithy/types": "^4.2.0", + "version": "3.840.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.840.0.tgz", + "integrity": "sha512-hiiMf7BP5ZkAFAvWRcK67Mw/g55ar7OCrvrynC92hunx/xhMkrgSLM0EXIZ1oTn3uql9kH/qqGF0nqsK6K555A==", + "dependencies": { + "@aws-sdk/core": "3.840.0", + "@aws-sdk/types": "3.840.0", + "@aws-sdk/util-endpoints": "3.840.0", + "@smithy/core": "^3.6.0", + "@smithy/protocol-http": "^5.1.2", + "@smithy/types": "^4.3.1", "tslib": "^2.6.2" }, "engines": { @@ -20374,47 +20897,46 @@ } }, "node_modules/@aws-sdk/client-lambda/node_modules/@aws-sdk/nested-clients": { - "version": "3.799.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/nested-clients/-/nested-clients-3.799.0.tgz", - "integrity": "sha512-zILlWh7asrcQG9JYMYgnvEQBfwmWKfED0yWCf3UNAmQcfS9wkCAWCgicNy/y5KvNvEYnHidsU117STtyuUNG5g==", - "license": "Apache-2.0", + "version": "3.840.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/nested-clients/-/nested-clients-3.840.0.tgz", + "integrity": "sha512-LXYYo9+n4hRqnRSIMXLBb+BLz+cEmjMtTudwK1BF6Bn2RfdDv29KuyeDRrPCS3TwKl7ZKmXUmE9n5UuHAPfBpA==", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "3.799.0", - "@aws-sdk/middleware-host-header": "3.775.0", - "@aws-sdk/middleware-logger": "3.775.0", - "@aws-sdk/middleware-recursion-detection": "3.775.0", - "@aws-sdk/middleware-user-agent": "3.799.0", - "@aws-sdk/region-config-resolver": "3.775.0", - "@aws-sdk/types": "3.775.0", - "@aws-sdk/util-endpoints": "3.787.0", - "@aws-sdk/util-user-agent-browser": "3.775.0", - "@aws-sdk/util-user-agent-node": "3.799.0", - "@smithy/config-resolver": "^4.1.0", - "@smithy/core": "^3.3.0", - "@smithy/fetch-http-handler": "^5.0.2", - "@smithy/hash-node": "^4.0.2", - "@smithy/invalid-dependency": "^4.0.2", - "@smithy/middleware-content-length": "^4.0.2", - "@smithy/middleware-endpoint": "^4.1.1", - "@smithy/middleware-retry": "^4.1.1", - "@smithy/middleware-serde": "^4.0.3", - "@smithy/middleware-stack": "^4.0.2", - "@smithy/node-config-provider": "^4.0.2", - "@smithy/node-http-handler": "^4.0.4", - "@smithy/protocol-http": "^5.1.0", - "@smithy/smithy-client": "^4.2.1", - "@smithy/types": "^4.2.0", - "@smithy/url-parser": "^4.0.2", + "@aws-sdk/core": "3.840.0", + "@aws-sdk/middleware-host-header": "3.840.0", + "@aws-sdk/middleware-logger": "3.840.0", + "@aws-sdk/middleware-recursion-detection": "3.840.0", + "@aws-sdk/middleware-user-agent": "3.840.0", + "@aws-sdk/region-config-resolver": "3.840.0", + "@aws-sdk/types": "3.840.0", + "@aws-sdk/util-endpoints": "3.840.0", + "@aws-sdk/util-user-agent-browser": "3.840.0", + "@aws-sdk/util-user-agent-node": "3.840.0", + "@smithy/config-resolver": "^4.1.4", + "@smithy/core": "^3.6.0", + "@smithy/fetch-http-handler": "^5.0.4", + "@smithy/hash-node": "^4.0.4", + "@smithy/invalid-dependency": "^4.0.4", + "@smithy/middleware-content-length": "^4.0.4", + "@smithy/middleware-endpoint": "^4.1.13", + "@smithy/middleware-retry": "^4.1.14", + "@smithy/middleware-serde": "^4.0.8", + "@smithy/middleware-stack": "^4.0.4", + "@smithy/node-config-provider": "^4.1.3", + "@smithy/node-http-handler": "^4.0.6", + "@smithy/protocol-http": "^5.1.2", + "@smithy/smithy-client": "^4.4.5", + "@smithy/types": "^4.3.1", + "@smithy/url-parser": "^4.0.4", "@smithy/util-base64": "^4.0.0", "@smithy/util-body-length-browser": "^4.0.0", "@smithy/util-body-length-node": "^4.0.0", - "@smithy/util-defaults-mode-browser": "^4.0.9", - "@smithy/util-defaults-mode-node": "^4.0.9", - "@smithy/util-endpoints": "^3.0.2", - "@smithy/util-middleware": "^4.0.2", - "@smithy/util-retry": "^4.0.2", + "@smithy/util-defaults-mode-browser": "^4.0.21", + "@smithy/util-defaults-mode-node": "^4.0.21", + "@smithy/util-endpoints": "^3.0.6", + "@smithy/util-middleware": "^4.0.4", + "@smithy/util-retry": "^4.0.6", "@smithy/util-utf8": "^4.0.0", "tslib": "^2.6.2" }, @@ -20422,17 +20944,45 @@ "node": ">=18.0.0" } }, + "node_modules/@aws-sdk/client-lambda/node_modules/@aws-sdk/region-config-resolver": { + "version": "3.840.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.840.0.tgz", + "integrity": "sha512-Qjnxd/yDv9KpIMWr90ZDPtRj0v75AqGC92Lm9+oHXZ8p1MjG5JE2CW0HL8JRgK9iKzgKBL7pPQRXI8FkvEVfrA==", + "dependencies": { + "@aws-sdk/types": "3.840.0", + "@smithy/node-config-provider": "^4.1.3", + "@smithy/types": "^4.3.1", + "@smithy/util-config-provider": "^4.0.0", + "@smithy/util-middleware": "^4.0.4", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, "node_modules/@aws-sdk/client-lambda/node_modules/@aws-sdk/token-providers": { - "version": "3.799.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.799.0.tgz", - "integrity": "sha512-/8iDjnsJs/D8AhGbDAmdF5oSHzE4jsDsM2RIIxmBAKTZXkaaclQBNX9CmAqLKQmO3IUMZsDH2KENHLVAk/N/mw==", - "license": "Apache-2.0", + "version": "3.840.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.840.0.tgz", + "integrity": "sha512-6BuTOLTXvmgwjK7ve7aTg9JaWFdM5UoMolLVPMyh3wTv9Ufalh8oklxYHUBIxsKkBGO2WiHXytveuxH6tAgTYg==", "dependencies": { - "@aws-sdk/nested-clients": "3.799.0", - "@aws-sdk/types": "3.775.0", - "@smithy/property-provider": "^4.0.2", - "@smithy/shared-ini-file-loader": "^4.0.2", - "@smithy/types": "^4.2.0", + "@aws-sdk/core": "3.840.0", + "@aws-sdk/nested-clients": "3.840.0", + "@aws-sdk/types": "3.840.0", + "@smithy/property-provider": "^4.0.4", + "@smithy/shared-ini-file-loader": "^4.0.4", + "@smithy/types": "^4.3.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-lambda/node_modules/@aws-sdk/types": { + "version": "3.840.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.840.0.tgz", + "integrity": "sha512-xliuHaUFZxEx1NSXeLLZ9Dyu6+EJVQKEoD+yM+zqUo3YDZ7medKJWY6fIOKiPX/N7XbLdBYwajb15Q7IL8KkeA==", + "dependencies": { + "@smithy/types": "^4.3.1", "tslib": "^2.6.2" }, "engines": { @@ -20440,14 +20990,13 @@ } }, "node_modules/@aws-sdk/client-lambda/node_modules/@aws-sdk/util-endpoints": { - "version": "3.787.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.787.0.tgz", - "integrity": "sha512-fd3zkiOkwnbdbN0Xp9TsP5SWrmv0SpT70YEdbb8wAj2DWQwiCmFszaSs+YCvhoCdmlR3Wl9Spu0pGpSAGKeYvQ==", - "license": "Apache-2.0", + "version": "3.840.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.840.0.tgz", + "integrity": "sha512-eqE9ROdg/Kk0rj3poutyRCFauPDXIf/WSvCqFiRDDVi6QOnCv/M0g2XW8/jSvkJlOyaXkNCptapIp6BeeFFGYw==", "dependencies": { - "@aws-sdk/types": "3.775.0", - "@smithy/types": "^4.2.0", - "@smithy/util-endpoints": "^3.0.2", + "@aws-sdk/types": "3.840.0", + "@smithy/types": "^4.3.1", + "@smithy/util-endpoints": "^3.0.6", "tslib": "^2.6.2" }, "engines": { @@ -20455,27 +21004,25 @@ } }, "node_modules/@aws-sdk/client-lambda/node_modules/@aws-sdk/util-user-agent-browser": { - "version": "3.775.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.775.0.tgz", - "integrity": "sha512-txw2wkiJmZKVdDbscK7VBK+u+TJnRtlUjRTLei+elZg2ADhpQxfVAQl436FUeIv6AhB/oRHW6/K/EAGXUSWi0A==", - "license": "Apache-2.0", + "version": "3.840.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.840.0.tgz", + "integrity": "sha512-JdyZM3EhhL4PqwFpttZu1afDpPJCCc3eyZOLi+srpX11LsGj6sThf47TYQN75HT1CarZ7cCdQHGzP2uy3/xHfQ==", "dependencies": { - "@aws-sdk/types": "3.775.0", - "@smithy/types": "^4.2.0", + "@aws-sdk/types": "3.840.0", + "@smithy/types": "^4.3.1", "bowser": "^2.11.0", "tslib": "^2.6.2" } }, "node_modules/@aws-sdk/client-lambda/node_modules/@aws-sdk/util-user-agent-node": { - "version": "3.799.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.799.0.tgz", - "integrity": "sha512-iXBk38RbIWPF5Nq9O4AnktORAzXovSVqWYClvS1qbE7ILsnTLJbagU9HlU25O2iV5COVh1qZkwuP5NHQ2yTEyw==", - "license": "Apache-2.0", + "version": "3.840.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.840.0.tgz", + "integrity": "sha512-Fy5JUEDQU1tPm2Yw/YqRYYc27W5+QD/J4mYvQvdWjUGZLB5q3eLFMGD35Uc28ZFoGMufPr4OCxK/bRfWROBRHQ==", "dependencies": { - "@aws-sdk/middleware-user-agent": "3.799.0", - "@aws-sdk/types": "3.775.0", - "@smithy/node-config-provider": "^4.0.2", - "@smithy/types": "^4.2.0", + "@aws-sdk/middleware-user-agent": "3.840.0", + "@aws-sdk/types": "3.840.0", + "@smithy/node-config-provider": "^4.1.3", + "@smithy/types": "^4.3.1", "tslib": "^2.6.2" }, "engines": { @@ -20490,6 +21037,18 @@ } } }, + "node_modules/@aws-sdk/client-lambda/node_modules/@aws-sdk/xml-builder": { + "version": "3.821.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/xml-builder/-/xml-builder-3.821.0.tgz", + "integrity": "sha512-DIIotRnefVL6DiaHtO6/21DhJ4JZnnIwdNbpwiAhdt/AVbttcE4yw925gsjur0OGv5BTYXQXU3YnANBYnZjuQA==", + "dependencies": { + "@smithy/types": "^4.3.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, "node_modules/@aws-sdk/client-personalize-events": { "version": "3.621.0", "resolved": "https://registry.npmjs.org/@aws-sdk/client-personalize-events/-/client-personalize-events-3.621.0.tgz", @@ -26809,6 +27368,34 @@ "node": ">=18.0.0" } }, + "node_modules/@aws-sdk/eventstream-handler-node": { + "version": "3.840.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/eventstream-handler-node/-/eventstream-handler-node-3.840.0.tgz", + "integrity": "sha512-m/zVrSSAEHq+6h4sy0JUEBScB1pGgs/1+iRVhfzfbnf+/gTr4ut2jRq4tDiNEX9pQ1oFVvw+ntPua5qfquQeRQ==", + "dev": true, + "dependencies": { + "@aws-sdk/types": "3.840.0", + "@smithy/eventstream-codec": "^4.0.4", + "@smithy/types": "^4.3.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/eventstream-handler-node/node_modules/@aws-sdk/types": { + "version": "3.840.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.840.0.tgz", + "integrity": "sha512-xliuHaUFZxEx1NSXeLLZ9Dyu6+EJVQKEoD+yM+zqUo3YDZ7medKJWY6fIOKiPX/N7XbLdBYwajb15Q7IL8KkeA==", + "dev": true, + "dependencies": { + "@smithy/types": "^4.3.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, "node_modules/@aws-sdk/lib-storage": { "version": "3.796.0", "resolved": "https://registry.npmjs.org/@aws-sdk/lib-storage/-/lib-storage-3.796.0.tgz", @@ -26880,6 +27467,34 @@ "node": ">=18.0.0" } }, + "node_modules/@aws-sdk/middleware-eventstream": { + "version": "3.840.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-eventstream/-/middleware-eventstream-3.840.0.tgz", + "integrity": "sha512-4khgf7AjJ4llh3aiNmZ+x4PGl4vkKNxRHn0xTgi6Iw1J3SChsF2mnNaLXK8hoXeydx756rw+JhqOuZH91i5l4w==", + "dev": true, + "dependencies": { + "@aws-sdk/types": "3.840.0", + "@smithy/protocol-http": "^5.1.2", + "@smithy/types": "^4.3.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/middleware-eventstream/node_modules/@aws-sdk/types": { + "version": "3.840.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.840.0.tgz", + "integrity": "sha512-xliuHaUFZxEx1NSXeLLZ9Dyu6+EJVQKEoD+yM+zqUo3YDZ7medKJWY6fIOKiPX/N7XbLdBYwajb15Q7IL8KkeA==", + "dev": true, + "dependencies": { + "@smithy/types": "^4.3.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, "node_modules/@aws-sdk/middleware-expect-continue": { "version": "3.775.0", "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-expect-continue/-/middleware-expect-continue-3.775.0.tgz", @@ -29311,13 +29926,12 @@ } }, "node_modules/@esbuild/aix-ppc64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.0.tgz", - "integrity": "sha512-O7vun9Sf8DFjH2UtqK8Ku3LkquL9SZL8OLY1T5NZkA34+wG3OQF7cl4Ql8vdNzM6fzBbYfLaiRLIOZ+2FOCgBQ==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.5.tgz", + "integrity": "sha512-9o3TMmpmftaCMepOdA5k/yDw8SfInyzWWTjYTFCX3kPSDJMROQTb8jg+h9Cnwnmm1vOzvxN7gIfB5V2ewpjtGA==", "cpu": [ "ppc64" ], - "license": "MIT", "optional": true, "os": [ "aix" @@ -29327,13 +29941,12 @@ } }, "node_modules/@esbuild/android-arm": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.0.tgz", - "integrity": "sha512-PTyWCYYiU0+1eJKmw21lWtC+d08JDZPQ5g+kFyxP0V+es6VPPSUhM6zk8iImp2jbV6GwjX4pap0JFbUQN65X1g==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.5.tgz", + "integrity": "sha512-AdJKSPeEHgi7/ZhuIPtcQKr5RQdo6OO2IL87JkianiMYMPbCtot9fxPbrMiBADOWWm3T2si9stAiVsGbTQFkbA==", "cpu": [ "arm" ], - "license": "MIT", "optional": true, "os": [ "android" @@ -29343,13 +29956,12 @@ } }, "node_modules/@esbuild/android-arm64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.0.tgz", - "integrity": "sha512-grvv8WncGjDSyUBjN9yHXNt+cq0snxXbDxy5pJtzMKGmmpPxeAmAhWxXI+01lU5rwZomDgD3kJwulEnhTRUd6g==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.5.tgz", + "integrity": "sha512-VGzGhj4lJO+TVGV1v8ntCZWJktV7SGCs3Pn1GRWI1SBFtRALoomm8k5E9Pmwg3HOAal2VDc2F9+PM/rEY6oIDg==", "cpu": [ "arm64" ], - "license": "MIT", "optional": true, "os": [ "android" @@ -29359,13 +29971,12 @@ } }, "node_modules/@esbuild/android-x64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.0.tgz", - "integrity": "sha512-m/ix7SfKG5buCnxasr52+LI78SQ+wgdENi9CqyCXwjVR2X4Jkz+BpC3le3AoBPYTC9NHklwngVXvbJ9/Akhrfg==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.5.tgz", + "integrity": "sha512-D2GyJT1kjvO//drbRT3Hib9XPwQeWd9vZoBJn+bu/lVsOZ13cqNdDeqIF/xQ5/VmWvMduP6AmXvylO/PIc2isw==", "cpu": [ "x64" ], - "license": "MIT", "optional": true, "os": [ "android" @@ -29375,13 +29986,12 @@ } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.0.tgz", - "integrity": "sha512-mVwdUb5SRkPayVadIOI78K7aAnPamoeFR2bT5nszFUZ9P8UpK4ratOdYbZZXYSqPKMHfS1wdHCJk1P1EZpRdvw==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.5.tgz", + "integrity": "sha512-GtaBgammVvdF7aPIgH2jxMDdivezgFu6iKpmT+48+F8Hhg5J/sfnDieg0aeG/jfSvkYQU2/pceFPDKlqZzwnfQ==", "cpu": [ "arm64" ], - "license": "MIT", "optional": true, "os": [ "darwin" @@ -29391,13 +30001,12 @@ } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.0.tgz", - "integrity": "sha512-DgDaYsPWFTS4S3nWpFcMn/33ZZwAAeAFKNHNa1QN0rI4pUjgqf0f7ONmXf6d22tqTY+H9FNdgeaAa+YIFUn2Rg==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.5.tgz", + "integrity": "sha512-1iT4FVL0dJ76/q1wd7XDsXrSW+oLoquptvh4CLR4kITDtqi2e/xwXwdCVH8hVHU43wgJdsq7Gxuzcs6Iq/7bxQ==", "cpu": [ "x64" ], - "license": "MIT", "optional": true, "os": [ "darwin" @@ -29407,13 +30016,12 @@ } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.0.tgz", - "integrity": "sha512-VN4ocxy6dxefN1MepBx/iD1dH5K8qNtNe227I0mnTRjry8tj5MRk4zprLEdG8WPyAPb93/e4pSgi1SoHdgOa4w==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.5.tgz", + "integrity": "sha512-nk4tGP3JThz4La38Uy/gzyXtpkPW8zSAmoUhK9xKKXdBCzKODMc2adkB2+8om9BDYugz+uGV7sLmpTYzvmz6Sw==", "cpu": [ "arm64" ], - "license": "MIT", "optional": true, "os": [ "freebsd" @@ -29423,13 +30031,12 @@ } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.0.tgz", - "integrity": "sha512-mrSgt7lCh07FY+hDD1TxiTyIHyttn6vnjesnPoVDNmDfOmggTLXRv8Id5fNZey1gl/V2dyVK1VXXqVsQIiAk+A==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.5.tgz", + "integrity": "sha512-PrikaNjiXdR2laW6OIjlbeuCPrPaAl0IwPIaRv+SMV8CiM8i2LqVUHFC1+8eORgWyY7yhQY+2U2fA55mBzReaw==", "cpu": [ "x64" ], - "license": "MIT", "optional": true, "os": [ "freebsd" @@ -29439,13 +30046,12 @@ } }, "node_modules/@esbuild/linux-arm": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.0.tgz", - "integrity": "sha512-vkB3IYj2IDo3g9xX7HqhPYxVkNQe8qTK55fraQyTzTX/fxaDtXiEnavv9geOsonh2Fd2RMB+i5cbhu2zMNWJwg==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.5.tgz", + "integrity": "sha512-cPzojwW2okgh7ZlRpcBEtsX7WBuqbLrNXqLU89GxWbNt6uIg78ET82qifUy3W6OVww6ZWobWub5oqZOVtwolfw==", "cpu": [ "arm" ], - "license": "MIT", "optional": true, "os": [ "linux" @@ -29455,13 +30061,12 @@ } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.0.tgz", - "integrity": "sha512-9QAQjTWNDM/Vk2bgBl17yWuZxZNQIF0OUUuPZRKoDtqF2k4EtYbpyiG5/Dk7nqeK6kIJWPYldkOcBqjXjrUlmg==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.5.tgz", + "integrity": "sha512-Z9kfb1v6ZlGbWj8EJk9T6czVEjjq2ntSYLY2cw6pAZl4oKtfgQuS4HOq41M/BcoLPzrUbNd+R4BXFyH//nHxVg==", "cpu": [ "arm64" ], - "license": "MIT", "optional": true, "os": [ "linux" @@ -29471,13 +30076,12 @@ } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.0.tgz", - "integrity": "sha512-43ET5bHbphBegyeqLb7I1eYn2P/JYGNmzzdidq/w0T8E2SsYL1U6un2NFROFRg1JZLTzdCoRomg8Rvf9M6W6Gg==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.5.tgz", + "integrity": "sha512-sQ7l00M8bSv36GLV95BVAdhJ2QsIbCuCjh/uYrWiMQSUuV+LpXwIqhgJDcvMTj+VsQmqAHL2yYaasENvJ7CDKA==", "cpu": [ "ia32" ], - "license": "MIT", "optional": true, "os": [ "linux" @@ -29487,13 +30091,12 @@ } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.0.tgz", - "integrity": "sha512-fC95c/xyNFueMhClxJmeRIj2yrSMdDfmqJnyOY4ZqsALkDrrKJfIg5NTMSzVBr5YW1jf+l7/cndBfP3MSDpoHw==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.5.tgz", + "integrity": "sha512-0ur7ae16hDUC4OL5iEnDb0tZHDxYmuQyhKhsPBV8f99f6Z9KQM02g33f93rNH5A30agMS46u2HP6qTdEt6Q1kg==", "cpu": [ "loong64" ], - "license": "MIT", "optional": true, "os": [ "linux" @@ -29503,13 +30106,12 @@ } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.0.tgz", - "integrity": "sha512-nkAMFju7KDW73T1DdH7glcyIptm95a7Le8irTQNO/qtkoyypZAnjchQgooFUDQhNAy4iu08N79W4T4pMBwhPwQ==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.5.tgz", + "integrity": "sha512-kB/66P1OsHO5zLz0i6X0RxlQ+3cu0mkxS3TKFvkb5lin6uwZ/ttOkP3Z8lfR9mJOBk14ZwZ9182SIIWFGNmqmg==", "cpu": [ "mips64el" ], - "license": "MIT", "optional": true, "os": [ "linux" @@ -29519,13 +30121,12 @@ } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.0.tgz", - "integrity": "sha512-NhyOejdhRGS8Iwv+KKR2zTq2PpysF9XqY+Zk77vQHqNbo/PwZCzB5/h7VGuREZm1fixhs4Q/qWRSi5zmAiO4Fw==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.5.tgz", + "integrity": "sha512-UZCmJ7r9X2fe2D6jBmkLBMQetXPXIsZjQJCjgwpVDz+YMcS6oFR27alkgGv3Oqkv07bxdvw7fyB71/olceJhkQ==", "cpu": [ "ppc64" ], - "license": "MIT", "optional": true, "os": [ "linux" @@ -29535,13 +30136,12 @@ } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.0.tgz", - "integrity": "sha512-5S/rbP5OY+GHLC5qXp1y/Mx//e92L1YDqkiBbO9TQOvuFXM+iDqUNG5XopAnXoRH3FjIUDkeGcY1cgNvnXp/kA==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.5.tgz", + "integrity": "sha512-kTxwu4mLyeOlsVIFPfQo+fQJAV9mh24xL+y+Bm6ej067sYANjyEw1dNHmvoqxJUCMnkBdKpvOn0Ahql6+4VyeA==", "cpu": [ "riscv64" ], - "license": "MIT", "optional": true, "os": [ "linux" @@ -29551,13 +30151,12 @@ } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.0.tgz", - "integrity": "sha512-XM2BFsEBz0Fw37V0zU4CXfcfuACMrppsMFKdYY2WuTS3yi8O1nFOhil/xhKTmE1nPmVyvQJjJivgDT+xh8pXJA==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.5.tgz", + "integrity": "sha512-K2dSKTKfmdh78uJ3NcWFiqyRrimfdinS5ErLSn3vluHNeHVnBAFWC8a4X5N+7FgVE1EjXS1QDZbpqZBjfrqMTQ==", "cpu": [ "s390x" ], - "license": "MIT", "optional": true, "os": [ "linux" @@ -29567,13 +30166,12 @@ } }, "node_modules/@esbuild/linux-x64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.0.tgz", - "integrity": "sha512-9yl91rHw/cpwMCNytUDxwj2XjFpxML0y9HAOH9pNVQDpQrBxHy01Dx+vaMu0N1CKa/RzBD2hB4u//nfc+Sd3Cw==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.5.tgz", + "integrity": "sha512-uhj8N2obKTE6pSZ+aMUbqq+1nXxNjZIIjCjGLfsWvVpy7gKCOL6rsY1MhRh9zLtUtAI7vpgLMK6DxjO8Qm9lJw==", "cpu": [ "x64" ], - "license": "MIT", "optional": true, "os": [ "linux" @@ -29583,13 +30181,12 @@ } }, "node_modules/@esbuild/netbsd-arm64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.0.tgz", - "integrity": "sha512-RuG4PSMPFfrkH6UwCAqBzauBWTygTvb1nxWasEJooGSJ/NwRw7b2HOwyRTQIU97Hq37l3npXoZGYMy3b3xYvPw==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.5.tgz", + "integrity": "sha512-pwHtMP9viAy1oHPvgxtOv+OkduK5ugofNTVDilIzBLpoWAM16r7b/mxBvfpuQDpRQFMfuVr5aLcn4yveGvBZvw==", "cpu": [ "arm64" ], - "license": "MIT", "optional": true, "os": [ "netbsd" @@ -29599,13 +30196,12 @@ } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.0.tgz", - "integrity": "sha512-jl+qisSB5jk01N5f7sPCsBENCOlPiS/xptD5yxOx2oqQfyourJwIKLRA2yqWdifj3owQZCL2sn6o08dBzZGQzA==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.5.tgz", + "integrity": "sha512-WOb5fKrvVTRMfWFNCroYWWklbnXH0Q5rZppjq0vQIdlsQKuw6mdSihwSo4RV/YdQ5UCKKvBy7/0ZZYLBZKIbwQ==", "cpu": [ "x64" ], - "license": "MIT", "optional": true, "os": [ "netbsd" @@ -29615,13 +30211,12 @@ } }, "node_modules/@esbuild/openbsd-arm64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.0.tgz", - "integrity": "sha512-21sUNbq2r84YE+SJDfaQRvdgznTD8Xc0oc3p3iW/a1EVWeNj/SdUCbm5U0itZPQYRuRTW20fPMWMpcrciH2EJw==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.5.tgz", + "integrity": "sha512-7A208+uQKgTxHd0G0uqZO8UjK2R0DDb4fDmERtARjSHWxqMTye4Erz4zZafx7Di9Cv+lNHYuncAkiGFySoD+Mw==", "cpu": [ "arm64" ], - "license": "MIT", "optional": true, "os": [ "openbsd" @@ -29631,13 +30226,12 @@ } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.0.tgz", - "integrity": "sha512-2gwwriSMPcCFRlPlKx3zLQhfN/2WjJ2NSlg5TKLQOJdV0mSxIcYNTMhk3H3ulL/cak+Xj0lY1Ym9ysDV1igceg==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.5.tgz", + "integrity": "sha512-G4hE405ErTWraiZ8UiSoesH8DaCsMm0Cay4fsFWOOUcz8b8rC6uCvnagr+gnioEjWn0wC+o1/TAHt+It+MpIMg==", "cpu": [ "x64" ], - "license": "MIT", "optional": true, "os": [ "openbsd" @@ -29647,13 +30241,12 @@ } }, "node_modules/@esbuild/sunos-x64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.0.tgz", - "integrity": "sha512-bxI7ThgLzPrPz484/S9jLlvUAHYMzy6I0XiU1ZMeAEOBcS0VePBFxh1JjTQt3Xiat5b6Oh4x7UC7IwKQKIJRIg==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.5.tgz", + "integrity": "sha512-l+azKShMy7FxzY0Rj4RCt5VD/q8mG/e+mDivgspo+yL8zW7qEwctQ6YqKX34DTEleFAvCIUviCFX1SDZRSyMQA==", "cpu": [ "x64" ], - "license": "MIT", "optional": true, "os": [ "sunos" @@ -29663,13 +30256,12 @@ } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.0.tgz", - "integrity": "sha512-ZUAc2YK6JW89xTbXvftxdnYy3m4iHIkDtK3CLce8wg8M2L+YZhIvO1DKpxrd0Yr59AeNNkTiic9YLf6FTtXWMw==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.5.tgz", + "integrity": "sha512-O2S7SNZzdcFG7eFKgvwUEZ2VG9D/sn/eIiz8XRZ1Q/DO5a3s76Xv0mdBzVM5j5R639lXQmPmSo0iRpHqUUrsxw==", "cpu": [ "arm64" ], - "license": "MIT", "optional": true, "os": [ "win32" @@ -29679,13 +30271,12 @@ } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.0.tgz", - "integrity": "sha512-eSNxISBu8XweVEWG31/JzjkIGbGIJN/TrRoiSVZwZ6pkC6VX4Im/WV2cz559/TXLcYbcrDN8JtKgd9DJVIo8GA==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.5.tgz", + "integrity": "sha512-onOJ02pqs9h1iMJ1PQphR+VZv8qBMQ77Klcsqv9CNW2w6yLqoURLcgERAIurY6QE63bbLuqgP9ATqajFLK5AMQ==", "cpu": [ "ia32" ], - "license": "MIT", "optional": true, "os": [ "win32" @@ -29695,13 +30286,12 @@ } }, "node_modules/@esbuild/win32-x64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.0.tgz", - "integrity": "sha512-ZENoHJBxA20C2zFzh6AI4fT6RraMzjYw4xKWemRTRmRVtN9c5DcH9r/f2ihEkMjOW5eGgrwCslG/+Y/3bL+DHQ==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.5.tgz", + "integrity": "sha512-TXv6YnJ8ZMVdX+SXWVBo/0p8LTcrUYngpWjvm91TMjjBQii7Oz11Lw5lbDV5Y0TzuhSJHwiH4hEtC1I42mMS0g==", "cpu": [ "x64" ], - "license": "MIT", "optional": true, "os": [ "win32" @@ -30529,6 +31119,17 @@ } } }, + "node_modules/@inquirer/core/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/@inquirer/core/node_modules/wrap-ansi": { "version": "6.2.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", @@ -30813,18 +31414,6 @@ "node": ">=12" } }, - "node_modules/@isaacs/cliui/node_modules/ansi-regex": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", - "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, "node_modules/@isaacs/cliui/node_modules/ansi-styles": { "version": "6.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", @@ -30854,21 +31443,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@isaacs/cliui/node_modules/strip-ansi": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", - "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", - "license": "MIT", - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { "version": "8.1.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", @@ -32516,12 +33090,11 @@ "license": "(Unlicense OR Apache-2.0)" }, "node_modules/@smithy/abort-controller": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-4.0.2.tgz", - "integrity": "sha512-Sl/78VDtgqKxN2+1qduaVE140XF+Xg+TafkncspwM4jFP/LHr76ZHmIY/y3V1M0mMLNk+Je6IGbzxy23RSToMw==", - "license": "Apache-2.0", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-4.0.4.tgz", + "integrity": "sha512-gJnEjZMvigPDQWHrW3oPrFhQtkrgqBkyjj3pCIdF3A5M6vsZODG93KNlfJprv6bp4245bdT32fsHK4kkH3KYDA==", "dependencies": { - "@smithy/types": "^4.2.0", + "@smithy/types": "^4.3.1", "tslib": "^2.6.2" }, "engines": { @@ -32554,15 +33127,14 @@ } }, "node_modules/@smithy/config-resolver": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@smithy/config-resolver/-/config-resolver-4.1.0.tgz", - "integrity": "sha512-8smPlwhga22pwl23fM5ew4T9vfLUCeFXlcqNOCD5M5h8VmNPNUE9j6bQSuRXpDSV11L/E/SwEBQuW8hr6+nS1A==", - "license": "Apache-2.0", + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/@smithy/config-resolver/-/config-resolver-4.1.4.tgz", + "integrity": "sha512-prmU+rDddxHOH0oNcwemL+SwnzcG65sBF2yXRO7aeXIn/xTlq2pX7JLVbkBnVLowHLg4/OL4+jBmv9hVrVGS+w==", "dependencies": { - "@smithy/node-config-provider": "^4.0.2", - "@smithy/types": "^4.2.0", + "@smithy/node-config-provider": "^4.1.3", + "@smithy/types": "^4.3.1", "@smithy/util-config-provider": "^4.0.0", - "@smithy/util-middleware": "^4.0.2", + "@smithy/util-middleware": "^4.0.4", "tslib": "^2.6.2" }, "engines": { @@ -32570,17 +33142,17 @@ } }, "node_modules/@smithy/core": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/@smithy/core/-/core-3.3.0.tgz", - "integrity": "sha512-r6gvs5OfRq/w+9unPm7B3po4rmWaGh0CIL/OwHntGGux7+RhOOZLGuurbeMgWV6W55ZuyMTypJLeH0vn/ZRaWQ==", - "license": "Apache-2.0", + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/@smithy/core/-/core-3.6.0.tgz", + "integrity": "sha512-Pgvfb+TQ4wUNLyHzvgCP4aYZMh16y7GcfF59oirRHcgGgkH1e/s9C0nv/v3WP+Quymyr5je71HeFQCwh+44XLg==", "dependencies": { - "@smithy/middleware-serde": "^4.0.3", - "@smithy/protocol-http": "^5.1.0", - "@smithy/types": "^4.2.0", + "@smithy/middleware-serde": "^4.0.8", + "@smithy/protocol-http": "^5.1.2", + "@smithy/types": "^4.3.1", + "@smithy/util-base64": "^4.0.0", "@smithy/util-body-length-browser": "^4.0.0", - "@smithy/util-middleware": "^4.0.2", - "@smithy/util-stream": "^4.2.0", + "@smithy/util-middleware": "^4.0.4", + "@smithy/util-stream": "^4.2.2", "@smithy/util-utf8": "^4.0.0", "tslib": "^2.6.2" }, @@ -32589,15 +33161,14 @@ } }, "node_modules/@smithy/credential-provider-imds": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-4.0.2.tgz", - "integrity": "sha512-32lVig6jCaWBHnY+OEQ6e6Vnt5vDHaLiydGrwYMW9tPqO688hPGTYRamYJ1EptxEC2rAwJrHWmPoKRBl4iTa8w==", - "license": "Apache-2.0", + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-4.0.6.tgz", + "integrity": "sha512-hKMWcANhUiNbCJouYkZ9V3+/Qf9pteR1dnwgdyzR09R4ODEYx8BbUysHwRSyex4rZ9zapddZhLFTnT4ZijR4pw==", "dependencies": { - "@smithy/node-config-provider": "^4.0.2", - "@smithy/property-provider": "^4.0.2", - "@smithy/types": "^4.2.0", - "@smithy/url-parser": "^4.0.2", + "@smithy/node-config-provider": "^4.1.3", + "@smithy/property-provider": "^4.0.4", + "@smithy/types": "^4.3.1", + "@smithy/url-parser": "^4.0.4", "tslib": "^2.6.2" }, "engines": { @@ -32605,13 +33176,12 @@ } }, "node_modules/@smithy/eventstream-codec": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@smithy/eventstream-codec/-/eventstream-codec-4.0.2.tgz", - "integrity": "sha512-p+f2kLSK7ZrXVfskU/f5dzksKTewZk8pJLPvER3aFHPt76C2MxD9vNatSfLzzQSQB4FNO96RK4PSXfhD1TTeMQ==", - "license": "Apache-2.0", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@smithy/eventstream-codec/-/eventstream-codec-4.0.4.tgz", + "integrity": "sha512-7XoWfZqWb/QoR/rAU4VSi0mWnO2vu9/ltS6JZ5ZSZv0eovLVfDfu0/AX4ub33RsJTOth3TiFWSHS5YdztvFnig==", "dependencies": { "@aws-crypto/crc32": "5.2.0", - "@smithy/types": "^4.2.0", + "@smithy/types": "^4.3.1", "@smithy/util-hex-encoding": "^4.0.0", "tslib": "^2.6.2" }, @@ -32620,13 +33190,12 @@ } }, "node_modules/@smithy/eventstream-serde-browser": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-browser/-/eventstream-serde-browser-4.0.2.tgz", - "integrity": "sha512-CepZCDs2xgVUtH7ZZ7oDdZFH8e6Y2zOv8iiX6RhndH69nlojCALSKK+OXwZUgOtUZEUaZ5e1hULVCHYbCn7pug==", - "license": "Apache-2.0", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-browser/-/eventstream-serde-browser-4.0.4.tgz", + "integrity": "sha512-3fb/9SYaYqbpy/z/H3yIi0bYKyAa89y6xPmIqwr2vQiUT2St+avRt8UKwsWt9fEdEasc5d/V+QjrviRaX1JRFA==", "dependencies": { - "@smithy/eventstream-serde-universal": "^4.0.2", - "@smithy/types": "^4.2.0", + "@smithy/eventstream-serde-universal": "^4.0.4", + "@smithy/types": "^4.3.1", "tslib": "^2.6.2" }, "engines": { @@ -32634,12 +33203,11 @@ } }, "node_modules/@smithy/eventstream-serde-config-resolver": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-config-resolver/-/eventstream-serde-config-resolver-4.1.0.tgz", - "integrity": "sha512-1PI+WPZ5TWXrfj3CIoKyUycYynYJgZjuQo8U+sphneOtjsgrttYybdqESFReQrdWJ+LKt6NEdbYzmmfDBmjX2A==", - "license": "Apache-2.0", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-config-resolver/-/eventstream-serde-config-resolver-4.1.2.tgz", + "integrity": "sha512-JGtambizrWP50xHgbzZI04IWU7LdI0nh/wGbqH3sJesYToMi2j/DcoElqyOcqEIG/D4tNyxgRuaqBXWE3zOFhQ==", "dependencies": { - "@smithy/types": "^4.2.0", + "@smithy/types": "^4.3.1", "tslib": "^2.6.2" }, "engines": { @@ -32647,13 +33215,12 @@ } }, "node_modules/@smithy/eventstream-serde-node": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-node/-/eventstream-serde-node-4.0.2.tgz", - "integrity": "sha512-C5bJ/C6x9ENPMx2cFOirspnF9ZsBVnBMtP6BdPl/qYSuUawdGQ34Lq0dMcf42QTjUZgWGbUIZnz6+zLxJlb9aw==", - "license": "Apache-2.0", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-node/-/eventstream-serde-node-4.0.4.tgz", + "integrity": "sha512-RD6UwNZ5zISpOWPuhVgRz60GkSIp0dy1fuZmj4RYmqLVRtejFqQ16WmfYDdoSoAjlp1LX+FnZo+/hkdmyyGZ1w==", "dependencies": { - "@smithy/eventstream-serde-universal": "^4.0.2", - "@smithy/types": "^4.2.0", + "@smithy/eventstream-serde-universal": "^4.0.4", + "@smithy/types": "^4.3.1", "tslib": "^2.6.2" }, "engines": { @@ -32661,13 +33228,12 @@ } }, "node_modules/@smithy/eventstream-serde-universal": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-universal/-/eventstream-serde-universal-4.0.2.tgz", - "integrity": "sha512-St8h9JqzvnbB52FtckiHPN4U/cnXcarMniXRXTKn0r4b4XesZOGiAyUdj1aXbqqn1icSqBlzzUsCl6nPB018ng==", - "license": "Apache-2.0", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-universal/-/eventstream-serde-universal-4.0.4.tgz", + "integrity": "sha512-UeJpOmLGhq1SLox79QWw/0n2PFX+oPRE1ZyRMxPIaFEfCqWaqpB7BU9C8kpPOGEhLF7AwEqfFbtwNxGy4ReENA==", "dependencies": { - "@smithy/eventstream-codec": "^4.0.2", - "@smithy/types": "^4.2.0", + "@smithy/eventstream-codec": "^4.0.4", + "@smithy/types": "^4.3.1", "tslib": "^2.6.2" }, "engines": { @@ -32675,14 +33241,13 @@ } }, "node_modules/@smithy/fetch-http-handler": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-5.0.2.tgz", - "integrity": "sha512-+9Dz8sakS9pe7f2cBocpJXdeVjMopUDLgZs1yWeu7h++WqSbjUYv/JAJwKwXw1HV6gq1jyWjxuyn24E2GhoEcQ==", - "license": "Apache-2.0", + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-5.0.4.tgz", + "integrity": "sha512-AMtBR5pHppYMVD7z7G+OlHHAcgAN7v0kVKEpHuTO4Gb199Gowh0taYi9oDStFeUhetkeP55JLSVlTW1n9rFtUw==", "dependencies": { - "@smithy/protocol-http": "^5.1.0", - "@smithy/querystring-builder": "^4.0.2", - "@smithy/types": "^4.2.0", + "@smithy/protocol-http": "^5.1.2", + "@smithy/querystring-builder": "^4.0.4", + "@smithy/types": "^4.3.1", "@smithy/util-base64": "^4.0.0", "tslib": "^2.6.2" }, @@ -32706,12 +33271,11 @@ } }, "node_modules/@smithy/hash-node": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@smithy/hash-node/-/hash-node-4.0.2.tgz", - "integrity": "sha512-VnTpYPnRUE7yVhWozFdlxcYknv9UN7CeOqSrMH+V877v4oqtVYuoqhIhtSjmGPvYrYnAkaM61sLMKHvxL138yg==", - "license": "Apache-2.0", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@smithy/hash-node/-/hash-node-4.0.4.tgz", + "integrity": "sha512-qnbTPUhCVnCgBp4z4BUJUhOEkVwxiEi1cyFM+Zj6o+aY8OFGxUQleKWq8ltgp3dujuhXojIvJWdoqpm6dVO3lQ==", "dependencies": { - "@smithy/types": "^4.2.0", + "@smithy/types": "^4.3.1", "@smithy/util-buffer-from": "^4.0.0", "@smithy/util-utf8": "^4.0.0", "tslib": "^2.6.2" @@ -32735,12 +33299,11 @@ } }, "node_modules/@smithy/invalid-dependency": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@smithy/invalid-dependency/-/invalid-dependency-4.0.2.tgz", - "integrity": "sha512-GatB4+2DTpgWPday+mnUkoumP54u/MDM/5u44KF9hIu8jF0uafZtQLcdfIKkIcUNuF/fBojpLEHZS/56JqPeXQ==", - "license": "Apache-2.0", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@smithy/invalid-dependency/-/invalid-dependency-4.0.4.tgz", + "integrity": "sha512-bNYMi7WKTJHu0gn26wg8OscncTt1t2b8KcsZxvOv56XA6cyXtOAAAaNP7+m45xfppXfOatXF3Sb1MNsLUgVLTw==", "dependencies": { - "@smithy/types": "^4.2.0", + "@smithy/types": "^4.3.1", "tslib": "^2.6.2" }, "engines": { @@ -32774,13 +33337,12 @@ } }, "node_modules/@smithy/middleware-content-length": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@smithy/middleware-content-length/-/middleware-content-length-4.0.2.tgz", - "integrity": "sha512-hAfEXm1zU+ELvucxqQ7I8SszwQ4znWMbNv6PLMndN83JJN41EPuS93AIyh2N+gJ6x8QFhzSO6b7q2e6oClDI8A==", - "license": "Apache-2.0", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@smithy/middleware-content-length/-/middleware-content-length-4.0.4.tgz", + "integrity": "sha512-F7gDyfI2BB1Kc+4M6rpuOLne5LOcEknH1n6UQB69qv+HucXBR1rkzXBnQTB2q46sFy1PM/zuSJOB532yc8bg3w==", "dependencies": { - "@smithy/protocol-http": "^5.1.0", - "@smithy/types": "^4.2.0", + "@smithy/protocol-http": "^5.1.2", + "@smithy/types": "^4.3.1", "tslib": "^2.6.2" }, "engines": { @@ -32788,18 +33350,17 @@ } }, "node_modules/@smithy/middleware-endpoint": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-4.1.1.tgz", - "integrity": "sha512-z5RmcHxjvScL+LwEDU2mTNCOhgUs4lu5PGdF1K36IPRmUHhNFxNxgenSB7smyDiYD4vdKQ7CAZtG5cUErqib9w==", - "license": "Apache-2.0", + "version": "4.1.13", + "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-4.1.13.tgz", + "integrity": "sha512-xg3EHV/Q5ZdAO5b0UiIMj3RIOCobuS40pBBODguUDVdko6YK6QIzCVRrHTogVuEKglBWqWenRnZ71iZnLL3ZAQ==", "dependencies": { - "@smithy/core": "^3.3.0", - "@smithy/middleware-serde": "^4.0.3", - "@smithy/node-config-provider": "^4.0.2", - "@smithy/shared-ini-file-loader": "^4.0.2", - "@smithy/types": "^4.2.0", - "@smithy/url-parser": "^4.0.2", - "@smithy/util-middleware": "^4.0.2", + "@smithy/core": "^3.6.0", + "@smithy/middleware-serde": "^4.0.8", + "@smithy/node-config-provider": "^4.1.3", + "@smithy/shared-ini-file-loader": "^4.0.4", + "@smithy/types": "^4.3.1", + "@smithy/url-parser": "^4.0.4", + "@smithy/util-middleware": "^4.0.4", "tslib": "^2.6.2" }, "engines": { @@ -32807,18 +33368,17 @@ } }, "node_modules/@smithy/middleware-retry": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-4.1.1.tgz", - "integrity": "sha512-mBJOxn9aUYwcBUPQpKv9ifzrCn4EbhPUFguEZv3jB57YOMh0caS4P8HoLvUeNUI1nx4bIVH2SIbogbDfFI9DUA==", - "license": "Apache-2.0", + "version": "4.1.14", + "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-4.1.14.tgz", + "integrity": "sha512-eoXaLlDGpKvdmvt+YBfRXE7HmIEtFF+DJCbTPwuLunP0YUnrydl+C4tS+vEM0+nyxXrX3PSUFqC+lP1+EHB1Tw==", "dependencies": { - "@smithy/node-config-provider": "^4.0.2", - "@smithy/protocol-http": "^5.1.0", - "@smithy/service-error-classification": "^4.0.2", - "@smithy/smithy-client": "^4.2.1", - "@smithy/types": "^4.2.0", - "@smithy/util-middleware": "^4.0.2", - "@smithy/util-retry": "^4.0.2", + "@smithy/node-config-provider": "^4.1.3", + "@smithy/protocol-http": "^5.1.2", + "@smithy/service-error-classification": "^4.0.6", + "@smithy/smithy-client": "^4.4.5", + "@smithy/types": "^4.3.1", + "@smithy/util-middleware": "^4.0.4", + "@smithy/util-retry": "^4.0.6", "tslib": "^2.6.2", "uuid": "^9.0.1" }, @@ -32840,12 +33400,12 @@ } }, "node_modules/@smithy/middleware-serde": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/@smithy/middleware-serde/-/middleware-serde-4.0.3.tgz", - "integrity": "sha512-rfgDVrgLEVMmMn0BI8O+8OVr6vXzjV7HZj57l0QxslhzbvVfikZbVfBVthjLHqib4BW44QhcIgJpvebHlRaC9A==", - "license": "Apache-2.0", + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/@smithy/middleware-serde/-/middleware-serde-4.0.8.tgz", + "integrity": "sha512-iSSl7HJoJaGyMIoNn2B7czghOVwJ9nD7TMvLhMWeSB5vt0TnEYyRRqPJu/TqW76WScaNvYYB8nRoiBHR9S1Ddw==", "dependencies": { - "@smithy/types": "^4.2.0", + "@smithy/protocol-http": "^5.1.2", + "@smithy/types": "^4.3.1", "tslib": "^2.6.2" }, "engines": { @@ -32853,12 +33413,11 @@ } }, "node_modules/@smithy/middleware-stack": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@smithy/middleware-stack/-/middleware-stack-4.0.2.tgz", - "integrity": "sha512-eSPVcuJJGVYrFYu2hEq8g8WWdJav3sdrI4o2c6z/rjnYDd3xH9j9E7deZQCzFn4QvGPouLngH3dQ+QVTxv5bOQ==", - "license": "Apache-2.0", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@smithy/middleware-stack/-/middleware-stack-4.0.4.tgz", + "integrity": "sha512-kagK5ggDrBUCCzI93ft6DjteNSfY8Ulr83UtySog/h09lTIOAJ/xUSObutanlPT0nhoHAkpmW9V5K8oPyLh+QA==", "dependencies": { - "@smithy/types": "^4.2.0", + "@smithy/types": "^4.3.1", "tslib": "^2.6.2" }, "engines": { @@ -32866,14 +33425,13 @@ } }, "node_modules/@smithy/node-config-provider": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-4.0.2.tgz", - "integrity": "sha512-WgCkILRZfJwJ4Da92a6t3ozN/zcvYyJGUTmfGbgS/FkCcoCjl7G4FJaCDN1ySdvLvemnQeo25FdkyMSTSwulsw==", - "license": "Apache-2.0", + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-4.1.3.tgz", + "integrity": "sha512-HGHQr2s59qaU1lrVH6MbLlmOBxadtzTsoO4c+bF5asdgVik3I8o7JIOzoeqWc5MjVa+vD36/LWE0iXKpNqooRw==", "dependencies": { - "@smithy/property-provider": "^4.0.2", - "@smithy/shared-ini-file-loader": "^4.0.2", - "@smithy/types": "^4.2.0", + "@smithy/property-provider": "^4.0.4", + "@smithy/shared-ini-file-loader": "^4.0.4", + "@smithy/types": "^4.3.1", "tslib": "^2.6.2" }, "engines": { @@ -32881,15 +33439,14 @@ } }, "node_modules/@smithy/node-http-handler": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-4.0.4.tgz", - "integrity": "sha512-/mdqabuAT3o/ihBGjL94PUbTSPSRJ0eeVTdgADzow0wRJ0rN4A27EOrtlK56MYiO1fDvlO3jVTCxQtQmK9dZ1g==", - "license": "Apache-2.0", + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-4.0.6.tgz", + "integrity": "sha512-NqbmSz7AW2rvw4kXhKGrYTiJVDHnMsFnX4i+/FzcZAfbOBauPYs2ekuECkSbtqaxETLLTu9Rl/ex6+I2BKErPA==", "dependencies": { - "@smithy/abort-controller": "^4.0.2", - "@smithy/protocol-http": "^5.1.0", - "@smithy/querystring-builder": "^4.0.2", - "@smithy/types": "^4.2.0", + "@smithy/abort-controller": "^4.0.4", + "@smithy/protocol-http": "^5.1.2", + "@smithy/querystring-builder": "^4.0.4", + "@smithy/types": "^4.3.1", "tslib": "^2.6.2" }, "engines": { @@ -32897,12 +33454,11 @@ } }, "node_modules/@smithy/property-provider": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-4.0.2.tgz", - "integrity": "sha512-wNRoQC1uISOuNc2s4hkOYwYllmiyrvVXWMtq+TysNRVQaHm4yoafYQyjN/goYZS+QbYlPIbb/QRjaUZMuzwQ7A==", - "license": "Apache-2.0", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-4.0.4.tgz", + "integrity": "sha512-qHJ2sSgu4FqF4U/5UUp4DhXNmdTrgmoAai6oQiM+c5RZ/sbDwJ12qxB1M6FnP+Tn/ggkPZf9ccn4jqKSINaquw==", "dependencies": { - "@smithy/types": "^4.2.0", + "@smithy/types": "^4.3.1", "tslib": "^2.6.2" }, "engines": { @@ -32910,12 +33466,11 @@ } }, "node_modules/@smithy/protocol-http": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-5.1.0.tgz", - "integrity": "sha512-KxAOL1nUNw2JTYrtviRRjEnykIDhxc84qMBzxvu1MUfQfHTuBlCG7PA6EdVwqpJjH7glw7FqQoFxUJSyBQgu7g==", - "license": "Apache-2.0", + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-5.1.2.tgz", + "integrity": "sha512-rOG5cNLBXovxIrICSBm95dLqzfvxjEmuZx4KK3hWwPFHGdW3lxY0fZNXfv2zebfRO7sJZ5pKJYHScsqopeIWtQ==", "dependencies": { - "@smithy/types": "^4.2.0", + "@smithy/types": "^4.3.1", "tslib": "^2.6.2" }, "engines": { @@ -32923,12 +33478,11 @@ } }, "node_modules/@smithy/querystring-builder": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-4.0.2.tgz", - "integrity": "sha512-NTOs0FwHw1vimmQM4ebh+wFQvOwkEf/kQL6bSM1Lock+Bv4I89B3hGYoUEPkmvYPkDKyp5UdXJYu+PoTQ3T31Q==", - "license": "Apache-2.0", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-4.0.4.tgz", + "integrity": "sha512-SwREZcDnEYoh9tLNgMbpop+UTGq44Hl9tdj3rf+yeLcfH7+J8OXEBaMc2kDxtyRHu8BhSg9ADEx0gFHvpJgU8w==", "dependencies": { - "@smithy/types": "^4.2.0", + "@smithy/types": "^4.3.1", "@smithy/util-uri-escape": "^4.0.0", "tslib": "^2.6.2" }, @@ -32937,12 +33491,11 @@ } }, "node_modules/@smithy/querystring-parser": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@smithy/querystring-parser/-/querystring-parser-4.0.2.tgz", - "integrity": "sha512-v6w8wnmZcVXjfVLjxw8qF7OwESD9wnpjp0Dqry/Pod0/5vcEA3qxCr+BhbOHlxS8O+29eLpT3aagxXGwIoEk7Q==", - "license": "Apache-2.0", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@smithy/querystring-parser/-/querystring-parser-4.0.4.tgz", + "integrity": "sha512-6yZf53i/qB8gRHH/l2ZwUG5xgkPgQF15/KxH0DdXMDHjesA9MeZje/853ifkSY0x4m5S+dfDZ+c4x439PF0M2w==", "dependencies": { - "@smithy/types": "^4.2.0", + "@smithy/types": "^4.3.1", "tslib": "^2.6.2" }, "engines": { @@ -32950,24 +33503,22 @@ } }, "node_modules/@smithy/service-error-classification": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@smithy/service-error-classification/-/service-error-classification-4.0.2.tgz", - "integrity": "sha512-LA86xeFpTKn270Hbkixqs5n73S+LVM0/VZco8dqd+JT75Dyx3Lcw/MraL7ybjmz786+160K8rPOmhsq0SocoJQ==", - "license": "Apache-2.0", + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@smithy/service-error-classification/-/service-error-classification-4.0.6.tgz", + "integrity": "sha512-RRoTDL//7xi4tn5FrN2NzH17jbgmnKidUqd4KvquT0954/i6CXXkh1884jBiunq24g9cGtPBEXlU40W6EpNOOg==", "dependencies": { - "@smithy/types": "^4.2.0" + "@smithy/types": "^4.3.1" }, "engines": { "node": ">=18.0.0" } }, "node_modules/@smithy/shared-ini-file-loader": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-4.0.2.tgz", - "integrity": "sha512-J9/gTWBGVuFZ01oVA6vdb4DAjf1XbDhK6sLsu3OS9qmLrS6KB5ygpeHiM3miIbj1qgSJ96GYszXFWv6ErJ8QEw==", - "license": "Apache-2.0", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-4.0.4.tgz", + "integrity": "sha512-63X0260LoFBjrHifPDs+nM9tV0VMkOTl4JRMYNuKh/f5PauSjowTfvF3LogfkWdcPoxsA9UjqEOgjeYIbhb7Nw==", "dependencies": { - "@smithy/types": "^4.2.0", + "@smithy/types": "^4.3.1", "tslib": "^2.6.2" }, "engines": { @@ -32975,16 +33526,15 @@ } }, "node_modules/@smithy/signature-v4": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-5.1.0.tgz", - "integrity": "sha512-4t5WX60sL3zGJF/CtZsUQTs3UrZEDO2P7pEaElrekbLqkWPYkgqNW1oeiNYC6xXifBnT9dVBOnNQRvOE9riU9w==", - "license": "Apache-2.0", + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-5.1.2.tgz", + "integrity": "sha512-d3+U/VpX7a60seHziWnVZOHuEgJlclufjkS6zhXvxcJgkJq4UWdH5eOBLzHRMx6gXjsdT9h6lfpmLzbrdupHgQ==", "dependencies": { "@smithy/is-array-buffer": "^4.0.0", - "@smithy/protocol-http": "^5.1.0", - "@smithy/types": "^4.2.0", + "@smithy/protocol-http": "^5.1.2", + "@smithy/types": "^4.3.1", "@smithy/util-hex-encoding": "^4.0.0", - "@smithy/util-middleware": "^4.0.2", + "@smithy/util-middleware": "^4.0.4", "@smithy/util-uri-escape": "^4.0.0", "@smithy/util-utf8": "^4.0.0", "tslib": "^2.6.2" @@ -32994,17 +33544,16 @@ } }, "node_modules/@smithy/smithy-client": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-4.2.1.tgz", - "integrity": "sha512-fbniZef60QdsBc4ZY0iyI8xbFHIiC/QRtPi66iE4ufjiE/aaz7AfUXzcWMkpO8r+QhLeNRIfmPchIG+3/QDZ6g==", - "license": "Apache-2.0", + "version": "4.4.5", + "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-4.4.5.tgz", + "integrity": "sha512-+lynZjGuUFJaMdDYSTMnP/uPBBXXukVfrJlP+1U/Dp5SFTEI++w6NMga8DjOENxecOF71V9Z2DllaVDYRnGlkg==", "dependencies": { - "@smithy/core": "^3.3.0", - "@smithy/middleware-endpoint": "^4.1.1", - "@smithy/middleware-stack": "^4.0.2", - "@smithy/protocol-http": "^5.1.0", - "@smithy/types": "^4.2.0", - "@smithy/util-stream": "^4.2.0", + "@smithy/core": "^3.6.0", + "@smithy/middleware-endpoint": "^4.1.13", + "@smithy/middleware-stack": "^4.0.4", + "@smithy/protocol-http": "^5.1.2", + "@smithy/types": "^4.3.1", + "@smithy/util-stream": "^4.2.2", "tslib": "^2.6.2" }, "engines": { @@ -33012,10 +33561,9 @@ } }, "node_modules/@smithy/types": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.2.0.tgz", - "integrity": "sha512-7eMk09zQKCO+E/ivsjQv+fDlOupcFUCSC/L2YUPgwhvowVGWbPQHjEFcmjt7QQ4ra5lyowS92SV53Zc6XD4+fg==", - "license": "Apache-2.0", + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.3.1.tgz", + "integrity": "sha512-UqKOQBL2x6+HWl3P+3QqFD4ncKq0I8Nuz9QItGv5WuKuMHuuwlhvqcZCoXGfc+P1QmfJE7VieykoYYmrOoFJxA==", "dependencies": { "tslib": "^2.6.2" }, @@ -33024,13 +33572,12 @@ } }, "node_modules/@smithy/url-parser": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@smithy/url-parser/-/url-parser-4.0.2.tgz", - "integrity": "sha512-Bm8n3j2ScqnT+kJaClSVCMeiSenK6jVAzZCNewsYWuZtnBehEz4r2qP0riZySZVfzB+03XZHJeqfmJDkeeSLiQ==", - "license": "Apache-2.0", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@smithy/url-parser/-/url-parser-4.0.4.tgz", + "integrity": "sha512-eMkc144MuN7B0TDA4U2fKs+BqczVbk3W+qIvcoCY6D1JY3hnAdCuhCZODC+GAeaxj0p6Jroz4+XMUn3PCxQQeQ==", "dependencies": { - "@smithy/querystring-parser": "^4.0.2", - "@smithy/types": "^4.2.0", + "@smithy/querystring-parser": "^4.0.4", + "@smithy/types": "^4.3.1", "tslib": "^2.6.2" }, "engines": { @@ -33101,14 +33648,13 @@ } }, "node_modules/@smithy/util-defaults-mode-browser": { - "version": "4.0.9", - "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-4.0.9.tgz", - "integrity": "sha512-B8j0XsElvyhv6+5hlFf6vFV/uCSyLKcInpeXOGnOImX2mGXshE01RvPoGipTlRpIk53e6UfYj7WdDdgbVfXDZw==", - "license": "Apache-2.0", + "version": "4.0.21", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-4.0.21.tgz", + "integrity": "sha512-wM0jhTytgXu3wzJoIqpbBAG5U6BwiubZ6QKzSbP7/VbmF1v96xlAbX2Am/mz0Zep0NLvLh84JT0tuZnk3wmYQA==", "dependencies": { - "@smithy/property-provider": "^4.0.2", - "@smithy/smithy-client": "^4.2.1", - "@smithy/types": "^4.2.0", + "@smithy/property-provider": "^4.0.4", + "@smithy/smithy-client": "^4.4.5", + "@smithy/types": "^4.3.1", "bowser": "^2.11.0", "tslib": "^2.6.2" }, @@ -33117,17 +33663,16 @@ } }, "node_modules/@smithy/util-defaults-mode-node": { - "version": "4.0.9", - "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-4.0.9.tgz", - "integrity": "sha512-wTDU8P/zdIf9DOpV5qm64HVgGRXvqjqB/fJZTEQbrz3s79JHM/E7XkMm/876Oq+ZLHJQgnXM9QHDo29dlM62eA==", - "license": "Apache-2.0", + "version": "4.0.21", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-4.0.21.tgz", + "integrity": "sha512-/F34zkoU0GzpUgLJydHY8Rxu9lBn8xQC/s/0M0U9lLBkYbA1htaAFjWYJzpzsbXPuri5D1H8gjp2jBum05qBrA==", "dependencies": { - "@smithy/config-resolver": "^4.1.0", - "@smithy/credential-provider-imds": "^4.0.2", - "@smithy/node-config-provider": "^4.0.2", - "@smithy/property-provider": "^4.0.2", - "@smithy/smithy-client": "^4.2.1", - "@smithy/types": "^4.2.0", + "@smithy/config-resolver": "^4.1.4", + "@smithy/credential-provider-imds": "^4.0.6", + "@smithy/node-config-provider": "^4.1.3", + "@smithy/property-provider": "^4.0.4", + "@smithy/smithy-client": "^4.4.5", + "@smithy/types": "^4.3.1", "tslib": "^2.6.2" }, "engines": { @@ -33135,13 +33680,12 @@ } }, "node_modules/@smithy/util-endpoints": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@smithy/util-endpoints/-/util-endpoints-3.0.2.tgz", - "integrity": "sha512-6QSutU5ZyrpNbnd51zRTL7goojlcnuOB55+F9VBD+j8JpRY50IGamsjlycrmpn8PQkmJucFW8A0LSfXj7jjtLQ==", - "license": "Apache-2.0", + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@smithy/util-endpoints/-/util-endpoints-3.0.6.tgz", + "integrity": "sha512-YARl3tFL3WgPuLzljRUnrS2ngLiUtkwhQtj8PAL13XZSyUiNLQxwG3fBBq3QXFqGFUXepIN73pINp3y8c2nBmA==", "dependencies": { - "@smithy/node-config-provider": "^4.0.2", - "@smithy/types": "^4.2.0", + "@smithy/node-config-provider": "^4.1.3", + "@smithy/types": "^4.3.1", "tslib": "^2.6.2" }, "engines": { @@ -33161,12 +33705,11 @@ } }, "node_modules/@smithy/util-middleware": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-4.0.2.tgz", - "integrity": "sha512-6GDamTGLuBQVAEuQ4yDQ+ti/YINf/MEmIegrEeg7DdB/sld8BX1lqt9RRuIcABOhAGTA50bRbPzErez7SlDtDQ==", - "license": "Apache-2.0", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-4.0.4.tgz", + "integrity": "sha512-9MLKmkBmf4PRb0ONJikCbCwORACcil6gUWojwARCClT7RmLzF04hUR4WdRprIXal7XVyrddadYNfp2eF3nrvtQ==", "dependencies": { - "@smithy/types": "^4.2.0", + "@smithy/types": "^4.3.1", "tslib": "^2.6.2" }, "engines": { @@ -33174,13 +33717,12 @@ } }, "node_modules/@smithy/util-retry": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@smithy/util-retry/-/util-retry-4.0.2.tgz", - "integrity": "sha512-Qryc+QG+7BCpvjloFLQrmlSd0RsVRHejRXd78jNO3+oREueCjwG1CCEH1vduw/ZkM1U9TztwIKVIi3+8MJScGg==", - "license": "Apache-2.0", + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@smithy/util-retry/-/util-retry-4.0.6.tgz", + "integrity": "sha512-+YekoF2CaSMv6zKrA6iI/N9yva3Gzn4L6n35Luydweu5MMPYpiGZlWqehPHDHyNbnyaYlz/WJyYAZnC+loBDZg==", "dependencies": { - "@smithy/service-error-classification": "^4.0.2", - "@smithy/types": "^4.2.0", + "@smithy/service-error-classification": "^4.0.6", + "@smithy/types": "^4.3.1", "tslib": "^2.6.2" }, "engines": { @@ -33188,14 +33730,13 @@ } }, "node_modules/@smithy/util-stream": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-4.2.0.tgz", - "integrity": "sha512-Vj1TtwWnuWqdgQI6YTUF5hQ/0jmFiOYsc51CSMgj7QfyO+RF4EnT2HNjoviNlOOmgzgvf3f5yno+EiC4vrnaWQ==", - "license": "Apache-2.0", + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-4.2.2.tgz", + "integrity": "sha512-aI+GLi7MJoVxg24/3J1ipwLoYzgkB4kUfogZfnslcYlynj3xsQ0e7vk4TnTro9hhsS5PvX1mwmkRqqHQjwcU7w==", "dependencies": { - "@smithy/fetch-http-handler": "^5.0.2", - "@smithy/node-http-handler": "^4.0.4", - "@smithy/types": "^4.2.0", + "@smithy/fetch-http-handler": "^5.0.4", + "@smithy/node-http-handler": "^4.0.6", + "@smithy/types": "^4.3.1", "@smithy/util-base64": "^4.0.0", "@smithy/util-buffer-from": "^4.0.0", "@smithy/util-hex-encoding": "^4.0.0", @@ -33361,13 +33902,12 @@ } }, "node_modules/@smithy/util-waiter": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/@smithy/util-waiter/-/util-waiter-4.0.3.tgz", - "integrity": "sha512-JtaY3FxmD+te+KSI2FJuEcfNC9T/DGGVf551babM7fAaXhjJUt7oSYurH1Devxd2+BOSUACCgt3buinx4UnmEA==", - "license": "Apache-2.0", + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@smithy/util-waiter/-/util-waiter-4.0.6.tgz", + "integrity": "sha512-slcr1wdRbX7NFphXZOxtxRNA7hXAAtJAXJDE/wdoMAos27SIquVCKiSqfB6/28YzQ8FCsB5NKkhdM5gMADbqxg==", "dependencies": { - "@smithy/abort-controller": "^4.0.2", - "@smithy/types": "^4.2.0", + "@smithy/abort-controller": "^4.0.4", + "@smithy/types": "^4.3.1", "tslib": "^2.6.2" }, "engines": { @@ -34643,6 +35183,166 @@ "url": "https://opencollective.com/verdaccio" } }, + "node_modules/@verdaccio/middleware/node_modules/body-parser": { + "version": "1.20.3", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", + "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", + "dev": true, + "dependencies": { + "bytes": "3.1.2", + "content-type": "~1.0.5", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.13.0", + "raw-body": "2.5.2", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/@verdaccio/middleware/node_modules/body-parser/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/@verdaccio/middleware/node_modules/body-parser/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/@verdaccio/middleware/node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "dev": true, + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/@verdaccio/middleware/node_modules/express": { + "version": "4.21.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz", + "integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==", + "dev": true, + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.3", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.7.1", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.3.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.3", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.12", + "proxy-addr": "~2.0.7", + "qs": "6.13.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.19.0", + "serve-static": "1.16.2", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/@verdaccio/middleware/node_modules/express-rate-limit": { + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-5.5.1.tgz", + "integrity": "sha512-MTjE2eIbHv5DyfuFz4zLYWxpqVhEhkTiwFGuB74Q9CSou2WHO52nlE5y3Zlg6SIsiYUIPj6ifFxnkPz6O3sIUg==", + "dev": true + }, + "node_modules/@verdaccio/middleware/node_modules/express/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/@verdaccio/middleware/node_modules/express/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/@verdaccio/middleware/node_modules/finalhandler": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz", + "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==", + "dev": true, + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/@verdaccio/middleware/node_modules/finalhandler/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/@verdaccio/middleware/node_modules/finalhandler/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/@verdaccio/middleware/node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/@verdaccio/middleware/node_modules/lru-cache": { "version": "7.18.3", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", @@ -34653,6 +35353,148 @@ "node": ">=12" } }, + "node_modules/@verdaccio/middleware/node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/@verdaccio/middleware/node_modules/merge-descriptors": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", + "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@verdaccio/middleware/node_modules/path-to-regexp": { + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz", + "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==", + "dev": true + }, + "node_modules/@verdaccio/middleware/node_modules/qs": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", + "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", + "dev": true, + "dependencies": { + "side-channel": "^1.0.6" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/@verdaccio/middleware/node_modules/raw-body": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", + "dev": true, + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/@verdaccio/middleware/node_modules/send": { + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", + "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", + "dev": true, + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/@verdaccio/middleware/node_modules/send/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/@verdaccio/middleware/node_modules/send/node_modules/debug/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/@verdaccio/middleware/node_modules/send/node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/@verdaccio/middleware/node_modules/send/node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dev": true, + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@verdaccio/middleware/node_modules/serve-static": { + "version": "1.16.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz", + "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==", + "dev": true, + "dependencies": { + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.19.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/@verdaccio/middleware/node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dev": true, + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/@verdaccio/search-indexer": { "version": "8.0.0-next-8.4", "resolved": "https://registry.npmjs.org/@verdaccio/search-indexer/-/search-indexer-8.0.0-next-8.4.tgz", @@ -35219,8 +36061,7 @@ "node_modules/array-flatten": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", - "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", - "license": "MIT" + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" }, "node_modules/array-includes": { "version": "3.1.8", @@ -36314,57 +37155,35 @@ } }, "node_modules/body-parser": { - "version": "1.20.3", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", - "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", - "license": "MIT", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.0.tgz", + "integrity": "sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg==", + "peer": true, "dependencies": { - "bytes": "3.1.2", - "content-type": "~1.0.5", - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "on-finished": "2.4.1", - "qs": "6.13.0", - "raw-body": "2.5.2", - "type-is": "~1.6.18", - "unpipe": "1.0.0" + "bytes": "^3.1.2", + "content-type": "^1.0.5", + "debug": "^4.4.0", + "http-errors": "^2.0.0", + "iconv-lite": "^0.6.3", + "on-finished": "^2.4.1", + "qs": "^6.14.0", + "raw-body": "^3.0.0", + "type-is": "^2.0.0" }, "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" - } - }, - "node_modules/body-parser/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "license": "MIT", - "dependencies": { - "ms": "2.0.0" + "node": ">=18" } }, - "node_modules/body-parser/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "license": "MIT" - }, - "node_modules/body-parser/node_modules/qs": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", - "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", - "license": "BSD-3-Clause", + "node_modules/body-parser/node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "peer": true, "dependencies": { - "side-channel": "^1.0.6" + "safer-buffer": ">= 2.1.2 < 3.0.0" }, "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=0.10.0" } }, "node_modules/bowser": { @@ -36955,19 +37774,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/cli-truncate/node_modules/ansi-regex": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", - "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, "node_modules/cli-truncate/node_modules/emoji-regex": { "version": "10.4.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.4.0.tgz", @@ -36993,22 +37799,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/cli-truncate/node_modules/strip-ansi": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", - "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, "node_modules/cli-width": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-4.1.0.tgz", @@ -37048,6 +37838,17 @@ "node": ">=12" } }, + "node_modules/cliui/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/clone": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", @@ -37207,10 +38008,10 @@ "license": "Apache-2.0" }, "node_modules/content-disposition": { - "version": "0.5.4", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", - "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", - "license": "MIT", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.0.tgz", + "integrity": "sha512-Au9nRL8VNUut/XSzbQA38+M78dzP4D+eqg3gfJHMIHHYa3bg067xj1KxMUWj+VULbiZMowKngFFbKczUrNJ1mg==", + "peer": true, "dependencies": { "safe-buffer": "5.2.1" }, @@ -37222,7 +38023,6 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", - "license": "MIT", "engines": { "node": ">= 0.6" } @@ -37640,7 +38440,6 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", - "license": "MIT", "engines": { "node": ">= 0.8", "npm": "1.2.8000 || >= 1.4.16" @@ -37826,8 +38625,7 @@ "node_modules/ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", - "license": "MIT" + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" }, "node_modules/electron-to-chromium": { "version": "1.5.112", @@ -37845,7 +38643,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", - "license": "MIT", "engines": { "node": ">= 0.8" } @@ -38001,6 +38798,18 @@ "node": ">=8.6" } }, + "node_modules/enquirer/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/entities": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", @@ -38224,11 +39033,10 @@ } }, "node_modules/esbuild": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.0.tgz", - "integrity": "sha512-BXq5mqc8ltbaN34cDqWuYKyNhX8D/Z0J1xdtdQ8UcIIIyJyz+ZMKUt58tF3SrZ85jcfN/PZYhjR5uDQAYNVbuw==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.5.tgz", + "integrity": "sha512-P8OtKZRv/5J5hhz0cUAdu/cLuPIKXpQl1R9pZtvmHWQvrAUVd0UNIPT4IB4W3rNOqVO0rlqHmCIbSwxh/c9yUQ==", "hasInstallScript": true, - "license": "MIT", "bin": { "esbuild": "bin/esbuild" }, @@ -38236,31 +39044,31 @@ "node": ">=18" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.25.0", - "@esbuild/android-arm": "0.25.0", - "@esbuild/android-arm64": "0.25.0", - "@esbuild/android-x64": "0.25.0", - "@esbuild/darwin-arm64": "0.25.0", - "@esbuild/darwin-x64": "0.25.0", - "@esbuild/freebsd-arm64": "0.25.0", - "@esbuild/freebsd-x64": "0.25.0", - "@esbuild/linux-arm": "0.25.0", - "@esbuild/linux-arm64": "0.25.0", - "@esbuild/linux-ia32": "0.25.0", - "@esbuild/linux-loong64": "0.25.0", - "@esbuild/linux-mips64el": "0.25.0", - "@esbuild/linux-ppc64": "0.25.0", - "@esbuild/linux-riscv64": "0.25.0", - "@esbuild/linux-s390x": "0.25.0", - "@esbuild/linux-x64": "0.25.0", - "@esbuild/netbsd-arm64": "0.25.0", - "@esbuild/netbsd-x64": "0.25.0", - "@esbuild/openbsd-arm64": "0.25.0", - "@esbuild/openbsd-x64": "0.25.0", - "@esbuild/sunos-x64": "0.25.0", - "@esbuild/win32-arm64": "0.25.0", - "@esbuild/win32-ia32": "0.25.0", - "@esbuild/win32-x64": "0.25.0" + "@esbuild/aix-ppc64": "0.25.5", + "@esbuild/android-arm": "0.25.5", + "@esbuild/android-arm64": "0.25.5", + "@esbuild/android-x64": "0.25.5", + "@esbuild/darwin-arm64": "0.25.5", + "@esbuild/darwin-x64": "0.25.5", + "@esbuild/freebsd-arm64": "0.25.5", + "@esbuild/freebsd-x64": "0.25.5", + "@esbuild/linux-arm": "0.25.5", + "@esbuild/linux-arm64": "0.25.5", + "@esbuild/linux-ia32": "0.25.5", + "@esbuild/linux-loong64": "0.25.5", + "@esbuild/linux-mips64el": "0.25.5", + "@esbuild/linux-ppc64": "0.25.5", + "@esbuild/linux-riscv64": "0.25.5", + "@esbuild/linux-s390x": "0.25.5", + "@esbuild/linux-x64": "0.25.5", + "@esbuild/netbsd-arm64": "0.25.5", + "@esbuild/netbsd-x64": "0.25.5", + "@esbuild/openbsd-arm64": "0.25.5", + "@esbuild/openbsd-x64": "0.25.5", + "@esbuild/sunos-x64": "0.25.5", + "@esbuild/win32-arm64": "0.25.5", + "@esbuild/win32-ia32": "0.25.5", + "@esbuild/win32-x64": "0.25.5" } }, "node_modules/escalade": { @@ -38275,8 +39083,7 @@ "node_modules/escape-html": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", - "license": "MIT" + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" }, "node_modules/escape-string-regexp": { "version": "4.0.0", @@ -39114,6 +39921,17 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/eslint/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/eslint/node_modules/type-fest": { "version": "0.20.2", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", @@ -39226,7 +40044,6 @@ "version": "1.8.1", "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", - "license": "MIT", "engines": { "node": ">= 0.6" } @@ -39295,45 +40112,41 @@ } }, "node_modules/express": { - "version": "4.21.2", - "resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz", - "integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==", - "license": "MIT", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/express/-/express-5.1.0.tgz", + "integrity": "sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA==", + "peer": true, "dependencies": { - "accepts": "~1.3.8", - "array-flatten": "1.1.1", - "body-parser": "1.20.3", - "content-disposition": "0.5.4", - "content-type": "~1.0.4", - "cookie": "0.7.1", - "cookie-signature": "1.0.6", - "debug": "2.6.9", - "depd": "2.0.0", - "encodeurl": "~2.0.0", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "finalhandler": "1.3.1", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "merge-descriptors": "1.0.3", - "methods": "~1.1.2", - "on-finished": "2.4.1", - "parseurl": "~1.3.3", - "path-to-regexp": "0.1.12", - "proxy-addr": "~2.0.7", - "qs": "6.13.0", - "range-parser": "~1.2.1", - "safe-buffer": "5.2.1", - "send": "0.19.0", - "serve-static": "1.16.2", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "type-is": "~1.6.18", - "utils-merge": "1.0.1", - "vary": "~1.1.2" + "accepts": "^2.0.0", + "body-parser": "^2.2.0", + "content-disposition": "^1.0.0", + "content-type": "^1.0.5", + "cookie": "^0.7.1", + "cookie-signature": "^1.2.1", + "debug": "^4.4.0", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "finalhandler": "^2.1.0", + "fresh": "^2.0.0", + "http-errors": "^2.0.0", + "merge-descriptors": "^2.0.0", + "mime-types": "^3.0.0", + "on-finished": "^2.4.1", + "once": "^1.4.0", + "parseurl": "^1.3.3", + "proxy-addr": "^2.0.7", + "qs": "^6.14.0", + "range-parser": "^1.2.1", + "router": "^2.2.0", + "send": "^1.1.0", + "serve-static": "^2.2.0", + "statuses": "^2.0.1", + "type-is": "^2.0.1", + "vary": "^1.1.2" }, "engines": { - "node": ">= 0.10.0" + "node": ">= 18" }, "funding": { "type": "opencollective", @@ -39341,40 +40154,60 @@ } }, "node_modules/express-rate-limit": { - "version": "5.5.1", - "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-5.5.1.tgz", - "integrity": "sha512-MTjE2eIbHv5DyfuFz4zLYWxpqVhEhkTiwFGuB74Q9CSou2WHO52nlE5y3Zlg6SIsiYUIPj6ifFxnkPz6O3sIUg==", - "dev": true, - "license": "MIT" + "version": "7.5.1", + "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-7.5.1.tgz", + "integrity": "sha512-7iN8iPMDzOMHPUYllBEsQdWVB6fPDMPqwjBaFrgr4Jgr/+okjvzAy+UHlYYL/Vs0OsOrMkwS6PJDkFlJwoxUnw==", + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://github.com/sponsors/express-rate-limit" + }, + "peerDependencies": { + "express": ">= 4.11" + } }, - "node_modules/express/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "license": "MIT", + "node_modules/express/node_modules/accepts": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz", + "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==", + "peer": true, "dependencies": { - "ms": "2.0.0" + "mime-types": "^3.0.0", + "negotiator": "^1.0.0" + }, + "engines": { + "node": ">= 0.6" } }, - "node_modules/express/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "license": "MIT" + "node_modules/express/node_modules/cookie-signature": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz", + "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==", + "peer": true, + "engines": { + "node": ">=6.6.0" + } }, - "node_modules/express/node_modules/qs": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", - "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", - "license": "BSD-3-Clause", + "node_modules/express/node_modules/mime-types": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.1.tgz", + "integrity": "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==", + "peer": true, "dependencies": { - "side-channel": "^1.0.6" + "mime-db": "^1.54.0" }, "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">= 0.6" + } + }, + "node_modules/express/node_modules/negotiator": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz", + "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==", + "peer": true, + "engines": { + "node": ">= 0.6" } }, "node_modules/extend": { @@ -39612,38 +40445,22 @@ } }, "node_modules/finalhandler": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz", - "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==", - "license": "MIT", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.0.tgz", + "integrity": "sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q==", + "peer": true, "dependencies": { - "debug": "2.6.9", - "encodeurl": "~2.0.0", - "escape-html": "~1.0.3", - "on-finished": "2.4.1", - "parseurl": "~1.3.3", - "statuses": "2.0.1", - "unpipe": "~1.0.0" + "debug": "^4.4.0", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "on-finished": "^2.4.1", + "parseurl": "^1.3.3", + "statuses": "^2.0.1" }, "engines": { "node": ">= 0.8" } }, - "node_modules/finalhandler/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "license": "MIT", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/finalhandler/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "license": "MIT" - }, "node_modules/find-up": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", @@ -39793,12 +40610,12 @@ } }, "node_modules/fresh": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", - "license": "MIT", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz", + "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==", + "peer": true, "engines": { - "node": ">= 0.6" + "node": ">= 0.8" } }, "node_modules/fs-extra": { @@ -41501,6 +42318,12 @@ "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", "license": "MIT" }, + "node_modules/json-format": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-format/-/json-format-1.0.1.tgz", + "integrity": "sha512-MoKIg/lBeQALqjYnqEanikfo3zBKRwclpXJexdF0FUniYAAN2ypEIXBEtpQb+9BkLFtDK1fyTLAsnGlyGfLGxw==", + "dev": true + }, "node_modules/json-parse-even-better-errors": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", @@ -42101,19 +42924,6 @@ "node": ">=18.0.0" } }, - "node_modules/listr2/node_modules/ansi-regex": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", - "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, "node_modules/listr2/node_modules/ansi-styles": { "version": "6.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", @@ -42152,22 +42962,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/listr2/node_modules/strip-ansi": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", - "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, "node_modules/listr2/node_modules/wrap-ansi": { "version": "9.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.0.tgz", @@ -42405,19 +43199,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/log-update/node_modules/ansi-regex": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", - "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, "node_modules/log-update/node_modules/ansi-styles": { "version": "6.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", @@ -42489,22 +43270,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/log-update/node_modules/strip-ansi": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", - "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, "node_modules/log-update/node_modules/wrap-ansi": { "version": "9.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.0.tgz", @@ -42680,19 +43445,22 @@ "license": "MIT" }, "node_modules/media-typer": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", - "license": "MIT", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz", + "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==", + "peer": true, "engines": { - "node": ">= 0.6" + "node": ">= 0.8" } }, "node_modules/merge-descriptors": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", - "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", - "license": "MIT", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz", + "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==", + "peer": true, + "engines": { + "node": ">=18" + }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } @@ -42717,7 +43485,6 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", - "license": "MIT", "engines": { "node": ">= 0.6" } @@ -42751,7 +43518,6 @@ "version": "1.54.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.6" @@ -43014,16 +43780,6 @@ "@sinonjs/commons": "^3.0.1" } }, - "node_modules/nise/node_modules/path-to-regexp": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.2.0.tgz", - "integrity": "sha512-TdrF7fW9Rphjq4RjrW0Kp2AW0Ahwu9sRGTkS6bvDi0SCwZlEZYmcfDbEsTz8RVk0EHIS/Vd1bv3JhG+1xZuAyQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=16" - } - }, "node_modules/no-case": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", @@ -43130,6 +43886,20 @@ "node": ">=0.10.0" } }, + "node_modules/npm-force-resolutions": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/npm-force-resolutions/-/npm-force-resolutions-0.0.10.tgz", + "integrity": "sha512-Jscex+xIU6tw3VsyrwxM1TeT+dd9Fd3UOMAjy6J1TMpuYeEqg4LQZnATQO5vjPrsARm3und6zc6Dii/GUyRE5A==", + "dev": true, + "dependencies": { + "json-format": "^1.0.1", + "source-map-support": "^0.5.5", + "xmlhttprequest": "^1.8.0" + }, + "bin": { + "npm-force-resolutions": "index.js" + } + }, "node_modules/npm-run-path": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-6.0.0.tgz", @@ -43312,7 +44082,6 @@ "version": "2.4.1", "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", - "license": "MIT", "dependencies": { "ee-first": "1.1.1" }, @@ -43425,18 +44194,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/ora/node_modules/ansi-regex": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", - "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, "node_modules/ora/node_modules/chalk": { "version": "5.4.1", "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.4.1.tgz", @@ -43472,21 +44229,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/ora/node_modules/strip-ansi": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", - "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", - "license": "MIT", - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, "node_modules/os-tmpdir": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", @@ -43696,7 +44438,6 @@ "version": "1.3.3", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", - "license": "MIT", "engines": { "node": ">= 0.8" } @@ -43801,10 +44542,12 @@ } }, "node_modules/path-to-regexp": { - "version": "0.1.12", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz", - "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==", - "license": "MIT" + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.2.0.tgz", + "integrity": "sha512-TdrF7fW9Rphjq4RjrW0Kp2AW0Ahwu9sRGTkS6bvDi0SCwZlEZYmcfDbEsTz8RVk0EHIS/Vd1bv3JhG+1xZuAyQ==", + "engines": { + "node": ">=16" + } }, "node_modules/path-type": { "version": "4.0.0", @@ -44353,7 +45096,6 @@ "version": "6.14.0", "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.0.tgz", "integrity": "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==", - "dev": true, "license": "BSD-3-Clause", "dependencies": { "side-channel": "^1.1.0" @@ -44423,26 +45165,37 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", - "license": "MIT", "engines": { "node": ">= 0.6" } }, "node_modules/raw-body": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", - "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", - "license": "MIT", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.0.tgz", + "integrity": "sha512-RmkhL8CAyCRPXCE28MMH0z2PNWQBNk2Q09ZdxM9IOOXwxwZbN+qbWaatPkdkWIKL2ZVDImrN/pK5HTRz2PcS4g==", + "peer": true, "dependencies": { "bytes": "3.1.2", "http-errors": "2.0.0", - "iconv-lite": "0.4.24", + "iconv-lite": "0.6.3", "unpipe": "1.0.0" }, "engines": { "node": ">= 0.8" } }, + "node_modules/raw-body/node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "peer": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/react": { "version": "18.3.1", "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", @@ -44880,6 +45633,28 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/router": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz", + "integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==", + "peer": true, + "dependencies": { + "debug": "^4.4.0", + "depd": "^2.0.0", + "is-promise": "^4.0.0", + "parseurl": "^1.3.3", + "path-to-regexp": "^8.0.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/router/node_modules/is-promise": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz", + "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==", + "peer": true + }, "node_modules/run-applescript": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-7.0.0.tgz", @@ -45052,63 +45827,37 @@ } }, "node_modules/send": { - "version": "0.19.0", - "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", - "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", - "license": "MIT", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/send/-/send-1.2.0.tgz", + "integrity": "sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw==", + "peer": true, "dependencies": { - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "mime": "1.6.0", - "ms": "2.1.3", - "on-finished": "2.4.1", - "range-parser": "~1.2.1", - "statuses": "2.0.1" + "debug": "^4.3.5", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "fresh": "^2.0.0", + "http-errors": "^2.0.0", + "mime-types": "^3.0.1", + "ms": "^2.1.3", + "on-finished": "^2.4.1", + "range-parser": "^1.2.1", + "statuses": "^2.0.1" }, "engines": { - "node": ">= 0.8.0" + "node": ">= 18" } }, - "node_modules/send/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "license": "MIT", + "node_modules/send/node_modules/mime-types": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.1.tgz", + "integrity": "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==", + "peer": true, "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/send/node_modules/debug/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "license": "MIT" - }, - "node_modules/send/node_modules/encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/send/node_modules/mime": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", - "license": "MIT", - "bin": { - "mime": "cli.js" + "mime-db": "^1.54.0" }, "engines": { - "node": ">=4" + "node": ">= 0.6" } }, "node_modules/sentence-case": { @@ -45128,18 +45877,18 @@ "integrity": "sha512-hr3Wtp/GZIc/6DAGPDcV4/9WoZhjrkXsi5B/07QgX8tsdc6ilr7BFM6PM6rbdAX1kFSDYeZGLipIZZKyQP0O5Q==" }, "node_modules/serve-static": { - "version": "1.16.2", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz", - "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==", - "license": "MIT", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.0.tgz", + "integrity": "sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ==", + "peer": true, "dependencies": { - "encodeurl": "~2.0.0", - "escape-html": "~1.0.3", - "parseurl": "~1.3.3", - "send": "0.19.0" + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "parseurl": "^1.3.3", + "send": "^1.2.0" }, "engines": { - "node": ">= 0.8.0" + "node": ">= 18" } }, "node_modules/set-blocking": { @@ -45857,6 +46606,17 @@ "node": ">=8" } }, + "node_modules/string-width-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/string-width/node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", @@ -45872,6 +46632,17 @@ "node": ">=8" } }, + "node_modules/string-width/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/string.prototype.includes": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/string.prototype.includes/-/string.prototype.includes-2.0.1.tgz", @@ -45983,15 +46754,17 @@ } }, "node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "license": "MIT", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", "dependencies": { - "ansi-regex": "^5.0.1" + "ansi-regex": "^6.0.1" }, "engines": { - "node": ">=8" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, "node_modules/strip-ansi-cjs": { @@ -46007,6 +46780,17 @@ "node": ">=8" } }, + "node_modules/strip-ansi/node_modules/ansi-regex": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, "node_modules/strip-bom": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", @@ -46207,6 +46991,17 @@ "url": "https://github.com/chalk/slice-ansi?sponsor=1" } }, + "node_modules/table/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/tar-stream": { "version": "3.1.7", "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.1.7.tgz", @@ -46712,13 +47507,26 @@ } }, "node_modules/type-is": { - "version": "1.6.18", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", - "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", - "license": "MIT", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.0.1.tgz", + "integrity": "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==", + "peer": true, "dependencies": { - "media-typer": "0.3.0", - "mime-types": "~2.1.24" + "content-type": "^1.0.5", + "media-typer": "^1.1.0", + "mime-types": "^3.0.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/type-is/node_modules/mime-types": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.1.tgz", + "integrity": "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==", + "peer": true, + "dependencies": { + "mime-db": "^1.54.0" }, "engines": { "node": ">= 0.6" @@ -46988,7 +47796,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", - "license": "MIT", "engines": { "node": ">= 0.8" } @@ -47098,7 +47905,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", - "license": "MIT", "engines": { "node": ">= 0.4.0" } @@ -47255,6 +48061,160 @@ "node": ">= 6.0.0" } }, + "node_modules/verdaccio-audit/node_modules/body-parser": { + "version": "1.20.3", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", + "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", + "dev": true, + "dependencies": { + "bytes": "3.1.2", + "content-type": "~1.0.5", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.13.0", + "raw-body": "2.5.2", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/verdaccio-audit/node_modules/body-parser/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/verdaccio-audit/node_modules/body-parser/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/verdaccio-audit/node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "dev": true, + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/verdaccio-audit/node_modules/express": { + "version": "4.21.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz", + "integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==", + "dev": true, + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.3", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.7.1", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.3.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.3", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.12", + "proxy-addr": "~2.0.7", + "qs": "6.13.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.19.0", + "serve-static": "1.16.2", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/verdaccio-audit/node_modules/express/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/verdaccio-audit/node_modules/express/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/verdaccio-audit/node_modules/finalhandler": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz", + "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==", + "dev": true, + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/verdaccio-audit/node_modules/finalhandler/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/verdaccio-audit/node_modules/finalhandler/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/verdaccio-audit/node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/verdaccio-audit/node_modules/https-proxy-agent": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", @@ -47269,6 +48229,148 @@ "node": ">= 6" } }, + "node_modules/verdaccio-audit/node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/verdaccio-audit/node_modules/merge-descriptors": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", + "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/verdaccio-audit/node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dev": true, + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/verdaccio-audit/node_modules/path-to-regexp": { + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz", + "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==", + "dev": true + }, + "node_modules/verdaccio-audit/node_modules/qs": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", + "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", + "dev": true, + "dependencies": { + "side-channel": "^1.0.6" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/verdaccio-audit/node_modules/raw-body": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", + "dev": true, + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/verdaccio-audit/node_modules/send": { + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", + "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", + "dev": true, + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/verdaccio-audit/node_modules/send/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/verdaccio-audit/node_modules/send/node_modules/debug/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/verdaccio-audit/node_modules/send/node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/verdaccio-audit/node_modules/serve-static": { + "version": "1.16.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz", + "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==", + "dev": true, + "dependencies": { + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.19.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/verdaccio-audit/node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dev": true, + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/verdaccio-htpasswd": { "version": "13.0.0-next-8.15", "resolved": "https://registry.npmjs.org/verdaccio-htpasswd/-/verdaccio-htpasswd-13.0.0-next-8.15.tgz", @@ -47310,6 +48412,160 @@ "url": "https://opencollective.com/verdaccio" } }, + "node_modules/verdaccio/node_modules/body-parser": { + "version": "1.20.3", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", + "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", + "dev": true, + "dependencies": { + "bytes": "3.1.2", + "content-type": "~1.0.5", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.13.0", + "raw-body": "2.5.2", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/verdaccio/node_modules/body-parser/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/verdaccio/node_modules/body-parser/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/verdaccio/node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "dev": true, + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/verdaccio/node_modules/express": { + "version": "4.21.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz", + "integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==", + "dev": true, + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.3", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.7.1", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.3.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.3", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.12", + "proxy-addr": "~2.0.7", + "qs": "6.13.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.19.0", + "serve-static": "1.16.2", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/verdaccio/node_modules/express/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/verdaccio/node_modules/express/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/verdaccio/node_modules/finalhandler": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz", + "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==", + "dev": true, + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/verdaccio/node_modules/finalhandler/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/verdaccio/node_modules/finalhandler/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/verdaccio/node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/verdaccio/node_modules/lru-cache": { "version": "7.18.3", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", @@ -47320,6 +48576,24 @@ "node": ">=12" } }, + "node_modules/verdaccio/node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/verdaccio/node_modules/merge-descriptors": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", + "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/verdaccio/node_modules/mime": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/mime/-/mime-3.0.0.tgz", @@ -47333,6 +48607,42 @@ "node": ">=10.0.0" } }, + "node_modules/verdaccio/node_modules/path-to-regexp": { + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz", + "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==", + "dev": true + }, + "node_modules/verdaccio/node_modules/qs": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", + "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", + "dev": true, + "dependencies": { + "side-channel": "^1.0.6" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/verdaccio/node_modules/raw-body": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", + "dev": true, + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/verdaccio/node_modules/semver": { "version": "7.6.3", "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", @@ -47346,6 +48656,94 @@ "node": ">=10" } }, + "node_modules/verdaccio/node_modules/send": { + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", + "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", + "dev": true, + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/verdaccio/node_modules/send/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/verdaccio/node_modules/send/node_modules/debug/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/verdaccio/node_modules/send/node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/verdaccio/node_modules/send/node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dev": true, + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/verdaccio/node_modules/serve-static": { + "version": "1.16.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz", + "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==", + "dev": true, + "dependencies": { + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.19.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/verdaccio/node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dev": true, + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/verror": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", @@ -47573,6 +48971,28 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, + "node_modules/wrap-ansi-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", @@ -47624,6 +49044,15 @@ "node": ">=4.0" } }, + "node_modules/xmlhttprequest": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/xmlhttprequest/-/xmlhttprequest-1.8.0.tgz", + "integrity": "sha512-58Im/U0mlVBLM38NdZjHyhuMtCqa61469k2YP/AaPbvCoV9aQGUpbJBj1QRm2ytRiVQBD/fsw7L2bJGDVQswBA==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/xmlhttprequest-ssl": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.1.2.tgz", @@ -49857,19 +51286,6 @@ "@aws-cdk/cli-plugin-contract": "^2" } }, - "packages/backend-deployer/node_modules/@smithy/abort-controller": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-4.0.4.tgz", - "integrity": "sha512-gJnEjZMvigPDQWHrW3oPrFhQtkrgqBkyjj3pCIdF3A5M6vsZODG93KNlfJprv6bp4245bdT32fsHK4kkH3KYDA==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/types": "^4.3.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, "packages/backend-deployer/node_modules/@smithy/core": { "version": "3.5.3", "resolved": "https://registry.npmjs.org/@smithy/core/-/core-3.5.3.tgz", @@ -49890,22 +51306,6 @@ "node": ">=18.0.0" } }, - "packages/backend-deployer/node_modules/@smithy/fetch-http-handler": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-5.0.4.tgz", - "integrity": "sha512-AMtBR5pHppYMVD7z7G+OlHHAcgAN7v0kVKEpHuTO4Gb199Gowh0taYi9oDStFeUhetkeP55JLSVlTW1n9rFtUw==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/protocol-http": "^5.1.2", - "@smithy/querystring-builder": "^4.0.4", - "@smithy/types": "^4.3.1", - "@smithy/util-base64": "^4.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, "packages/backend-deployer/node_modules/@smithy/middleware-endpoint": { "version": "4.1.11", "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-4.1.11.tgz", @@ -49925,104 +51325,6 @@ "node": ">=18.0.0" } }, - "packages/backend-deployer/node_modules/@smithy/middleware-serde": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/@smithy/middleware-serde/-/middleware-serde-4.0.8.tgz", - "integrity": "sha512-iSSl7HJoJaGyMIoNn2B7czghOVwJ9nD7TMvLhMWeSB5vt0TnEYyRRqPJu/TqW76WScaNvYYB8nRoiBHR9S1Ddw==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/protocol-http": "^5.1.2", - "@smithy/types": "^4.3.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "packages/backend-deployer/node_modules/@smithy/node-config-provider": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-4.1.3.tgz", - "integrity": "sha512-HGHQr2s59qaU1lrVH6MbLlmOBxadtzTsoO4c+bF5asdgVik3I8o7JIOzoeqWc5MjVa+vD36/LWE0iXKpNqooRw==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/property-provider": "^4.0.4", - "@smithy/shared-ini-file-loader": "^4.0.4", - "@smithy/types": "^4.3.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "packages/backend-deployer/node_modules/@smithy/node-http-handler": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-4.0.6.tgz", - "integrity": "sha512-NqbmSz7AW2rvw4kXhKGrYTiJVDHnMsFnX4i+/FzcZAfbOBauPYs2ekuECkSbtqaxETLLTu9Rl/ex6+I2BKErPA==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/abort-controller": "^4.0.4", - "@smithy/protocol-http": "^5.1.2", - "@smithy/querystring-builder": "^4.0.4", - "@smithy/types": "^4.3.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "packages/backend-deployer/node_modules/@smithy/property-provider": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-4.0.4.tgz", - "integrity": "sha512-qHJ2sSgu4FqF4U/5UUp4DhXNmdTrgmoAai6oQiM+c5RZ/sbDwJ12qxB1M6FnP+Tn/ggkPZf9ccn4jqKSINaquw==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/types": "^4.3.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "packages/backend-deployer/node_modules/@smithy/protocol-http": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-5.1.2.tgz", - "integrity": "sha512-rOG5cNLBXovxIrICSBm95dLqzfvxjEmuZx4KK3hWwPFHGdW3lxY0fZNXfv2zebfRO7sJZ5pKJYHScsqopeIWtQ==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/types": "^4.3.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "packages/backend-deployer/node_modules/@smithy/querystring-builder": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-4.0.4.tgz", - "integrity": "sha512-SwREZcDnEYoh9tLNgMbpop+UTGq44Hl9tdj3rf+yeLcfH7+J8OXEBaMc2kDxtyRHu8BhSg9ADEx0gFHvpJgU8w==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/types": "^4.3.1", - "@smithy/util-uri-escape": "^4.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "packages/backend-deployer/node_modules/@smithy/querystring-parser": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/@smithy/querystring-parser/-/querystring-parser-4.0.4.tgz", - "integrity": "sha512-6yZf53i/qB8gRHH/l2ZwUG5xgkPgQF15/KxH0DdXMDHjesA9MeZje/853ifkSY0x4m5S+dfDZ+c4x439PF0M2w==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/types": "^4.3.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, "packages/backend-deployer/node_modules/@smithy/service-error-classification": { "version": "4.0.5", "resolved": "https://registry.npmjs.org/@smithy/service-error-classification/-/service-error-classification-4.0.5.tgz", @@ -50035,58 +51337,6 @@ "node": ">=18.0.0" } }, - "packages/backend-deployer/node_modules/@smithy/shared-ini-file-loader": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-4.0.4.tgz", - "integrity": "sha512-63X0260LoFBjrHifPDs+nM9tV0VMkOTl4JRMYNuKh/f5PauSjowTfvF3LogfkWdcPoxsA9UjqEOgjeYIbhb7Nw==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/types": "^4.3.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "packages/backend-deployer/node_modules/@smithy/types": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.3.1.tgz", - "integrity": "sha512-UqKOQBL2x6+HWl3P+3QqFD4ncKq0I8Nuz9QItGv5WuKuMHuuwlhvqcZCoXGfc+P1QmfJE7VieykoYYmrOoFJxA==", - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "packages/backend-deployer/node_modules/@smithy/url-parser": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/@smithy/url-parser/-/url-parser-4.0.4.tgz", - "integrity": "sha512-eMkc144MuN7B0TDA4U2fKs+BqczVbk3W+qIvcoCY6D1JY3hnAdCuhCZODC+GAeaxj0p6Jroz4+XMUn3PCxQQeQ==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/querystring-parser": "^4.0.4", - "@smithy/types": "^4.3.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "packages/backend-deployer/node_modules/@smithy/util-middleware": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-4.0.4.tgz", - "integrity": "sha512-9MLKmkBmf4PRb0ONJikCbCwORACcil6gUWojwARCClT7RmLzF04hUR4WdRprIXal7XVyrddadYNfp2eF3nrvtQ==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/types": "^4.3.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, "packages/backend-deployer/node_modules/@smithy/util-retry": { "version": "4.0.5", "resolved": "https://registry.npmjs.org/@smithy/util-retry/-/util-retry-4.0.5.tgz", @@ -50101,25 +51351,6 @@ "node": ">=18.0.0" } }, - "packages/backend-deployer/node_modules/@smithy/util-stream": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-4.2.2.tgz", - "integrity": "sha512-aI+GLi7MJoVxg24/3J1ipwLoYzgkB4kUfogZfnslcYlynj3xsQ0e7vk4TnTro9hhsS5PvX1mwmkRqqHQjwcU7w==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/fetch-http-handler": "^5.0.4", - "@smithy/node-http-handler": "^4.0.6", - "@smithy/types": "^4.3.1", - "@smithy/util-base64": "^4.0.0", - "@smithy/util-buffer-from": "^4.0.0", - "@smithy/util-hex-encoding": "^4.0.0", - "@smithy/util-utf8": "^4.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, "packages/backend-deployer/node_modules/@smithy/util-waiter": { "version": "4.0.5", "resolved": "https://registry.npmjs.org/@smithy/util-waiter/-/util-waiter-4.0.5.tgz", @@ -50134,18 +51365,6 @@ "node": ">=18.0.0" } }, - "packages/backend-deployer/node_modules/ansi-regex": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", - "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, "packages/backend-deployer/node_modules/cdk-from-cfn": { "version": "0.220.0", "resolved": "https://registry.npmjs.org/cdk-from-cfn/-/cdk-from-cfn-0.220.0.tgz", @@ -50209,21 +51428,6 @@ "node": ">=10" } }, - "packages/backend-deployer/node_modules/strip-ansi": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", - "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", - "license": "MIT", - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, "packages/backend-function": { "name": "@aws-amplify/backend-function", "version": "1.14.1", @@ -50316,7 +51520,6 @@ "packages/cli": { "name": "@aws-amplify/backend-cli", "version": "1.8.0", - "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { "@aws-amplify/backend-deployer": "^2.1.2", @@ -50354,6 +51557,7 @@ "semver": "^7.6.3", "socket.io": "^4.8.1", "socket.io-client": "^4.8.1", + "strip-ansi": "^7.1.0", "typescript": "^5.8.3", "ws": "^8.18.2", "yargs": "^17.7.2", @@ -50393,18 +51597,6 @@ "zod": "3.25.17" } }, - "packages/cli-core/node_modules/ansi-regex": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", - "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, "packages/cli-core/node_modules/ansi-styles": { "version": "6.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", @@ -50440,21 +51632,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "packages/cli-core/node_modules/strip-ansi": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", - "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", - "license": "MIT", - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, "packages/cli-core/node_modules/wrap-ansi": { "version": "9.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.0.tgz", @@ -50472,459 +51649,238 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, - "packages/cli/node_modules/@esbuild/aix-ppc64": { - "version": "0.25.5", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.5.tgz", - "integrity": "sha512-9o3TMmpmftaCMepOdA5k/yDw8SfInyzWWTjYTFCX3kPSDJMROQTb8jg+h9Cnwnmm1vOzvxN7gIfB5V2ewpjtGA==", - "cpu": [ - "ppc64" - ], - "license": "MIT", - "optional": true, - "os": [ - "aix" - ], - "engines": { - "node": ">=18" - } - }, - "packages/cli/node_modules/@esbuild/android-arm": { - "version": "0.25.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.5.tgz", - "integrity": "sha512-AdJKSPeEHgi7/ZhuIPtcQKr5RQdo6OO2IL87JkianiMYMPbCtot9fxPbrMiBADOWWm3T2si9stAiVsGbTQFkbA==", - "cpu": [ - "arm" - ], - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "packages/cli/node_modules/@esbuild/android-arm64": { - "version": "0.25.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.5.tgz", - "integrity": "sha512-VGzGhj4lJO+TVGV1v8ntCZWJktV7SGCs3Pn1GRWI1SBFtRALoomm8k5E9Pmwg3HOAal2VDc2F9+PM/rEY6oIDg==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "packages/cli/node_modules/@esbuild/android-x64": { - "version": "0.25.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.5.tgz", - "integrity": "sha512-D2GyJT1kjvO//drbRT3Hib9XPwQeWd9vZoBJn+bu/lVsOZ13cqNdDeqIF/xQ5/VmWvMduP6AmXvylO/PIc2isw==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "packages/cli/node_modules/@esbuild/darwin-arm64": { - "version": "0.25.5", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.5.tgz", - "integrity": "sha512-GtaBgammVvdF7aPIgH2jxMDdivezgFu6iKpmT+48+F8Hhg5J/sfnDieg0aeG/jfSvkYQU2/pceFPDKlqZzwnfQ==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "packages/cli/node_modules/@esbuild/darwin-x64": { - "version": "0.25.5", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.5.tgz", - "integrity": "sha512-1iT4FVL0dJ76/q1wd7XDsXrSW+oLoquptvh4CLR4kITDtqi2e/xwXwdCVH8hVHU43wgJdsq7Gxuzcs6Iq/7bxQ==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "packages/cli/node_modules/@esbuild/freebsd-arm64": { - "version": "0.25.5", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.5.tgz", - "integrity": "sha512-nk4tGP3JThz4La38Uy/gzyXtpkPW8zSAmoUhK9xKKXdBCzKODMc2adkB2+8om9BDYugz+uGV7sLmpTYzvmz6Sw==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "packages/cli/node_modules/@esbuild/freebsd-x64": { - "version": "0.25.5", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.5.tgz", - "integrity": "sha512-PrikaNjiXdR2laW6OIjlbeuCPrPaAl0IwPIaRv+SMV8CiM8i2LqVUHFC1+8eORgWyY7yhQY+2U2fA55mBzReaw==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "packages/cli/node_modules/@esbuild/linux-arm": { - "version": "0.25.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.5.tgz", - "integrity": "sha512-cPzojwW2okgh7ZlRpcBEtsX7WBuqbLrNXqLU89GxWbNt6uIg78ET82qifUy3W6OVww6ZWobWub5oqZOVtwolfw==", - "cpu": [ - "arm" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "packages/cli/node_modules/@esbuild/linux-arm64": { - "version": "0.25.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.5.tgz", - "integrity": "sha512-Z9kfb1v6ZlGbWj8EJk9T6czVEjjq2ntSYLY2cw6pAZl4oKtfgQuS4HOq41M/BcoLPzrUbNd+R4BXFyH//nHxVg==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "packages/cli/node_modules/@esbuild/linux-ia32": { - "version": "0.25.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.5.tgz", - "integrity": "sha512-sQ7l00M8bSv36GLV95BVAdhJ2QsIbCuCjh/uYrWiMQSUuV+LpXwIqhgJDcvMTj+VsQmqAHL2yYaasENvJ7CDKA==", - "cpu": [ - "ia32" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "packages/cli/node_modules/body-parser": { + "version": "1.20.3", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", + "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", + "dependencies": { + "bytes": "3.1.2", + "content-type": "~1.0.5", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.13.0", + "raw-body": "2.5.2", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, "engines": { - "node": ">=18" + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" } }, - "packages/cli/node_modules/@esbuild/linux-loong64": { - "version": "0.25.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.5.tgz", - "integrity": "sha512-0ur7ae16hDUC4OL5iEnDb0tZHDxYmuQyhKhsPBV8f99f6Z9KQM02g33f93rNH5A30agMS46u2HP6qTdEt6Q1kg==", - "cpu": [ - "loong64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "packages/cli/node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "dependencies": { + "safe-buffer": "5.2.1" + }, "engines": { - "node": ">=18" + "node": ">= 0.6" } }, - "packages/cli/node_modules/@esbuild/linux-mips64el": { - "version": "0.25.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.5.tgz", - "integrity": "sha512-kB/66P1OsHO5zLz0i6X0RxlQ+3cu0mkxS3TKFvkb5lin6uwZ/ttOkP3Z8lfR9mJOBk14ZwZ9182SIIWFGNmqmg==", - "cpu": [ - "mips64el" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" + "packages/cli/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" } }, - "packages/cli/node_modules/@esbuild/linux-ppc64": { - "version": "0.25.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.5.tgz", - "integrity": "sha512-UZCmJ7r9X2fe2D6jBmkLBMQetXPXIsZjQJCjgwpVDz+YMcS6oFR27alkgGv3Oqkv07bxdvw7fyB71/olceJhkQ==", - "cpu": [ - "ppc64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } + "packages/cli/node_modules/debug/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" }, - "packages/cli/node_modules/@esbuild/linux-riscv64": { - "version": "0.25.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.5.tgz", - "integrity": "sha512-kTxwu4mLyeOlsVIFPfQo+fQJAV9mh24xL+y+Bm6ej067sYANjyEw1dNHmvoqxJUCMnkBdKpvOn0Ahql6+4VyeA==", - "cpu": [ - "riscv64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "packages/cli/node_modules/express": { + "version": "4.21.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz", + "integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==", + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.3", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.7.1", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.3.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.3", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.12", + "proxy-addr": "~2.0.7", + "qs": "6.13.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.19.0", + "serve-static": "1.16.2", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, "engines": { - "node": ">=18" + "node": ">= 0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, - "packages/cli/node_modules/@esbuild/linux-s390x": { - "version": "0.25.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.5.tgz", - "integrity": "sha512-K2dSKTKfmdh78uJ3NcWFiqyRrimfdinS5ErLSn3vluHNeHVnBAFWC8a4X5N+7FgVE1EjXS1QDZbpqZBjfrqMTQ==", - "cpu": [ - "s390x" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "packages/cli/node_modules/finalhandler": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz", + "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==", + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + }, "engines": { - "node": ">=18" + "node": ">= 0.8" } }, - "packages/cli/node_modules/@esbuild/linux-x64": { - "version": "0.25.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.5.tgz", - "integrity": "sha512-uhj8N2obKTE6pSZ+aMUbqq+1nXxNjZIIjCjGLfsWvVpy7gKCOL6rsY1MhRh9zLtUtAI7vpgLMK6DxjO8Qm9lJw==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "packages/cli/node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", "engines": { - "node": ">=18" + "node": ">= 0.6" } }, - "packages/cli/node_modules/@esbuild/netbsd-arm64": { - "version": "0.25.5", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.5.tgz", - "integrity": "sha512-pwHtMP9viAy1oHPvgxtOv+OkduK5ugofNTVDilIzBLpoWAM16r7b/mxBvfpuQDpRQFMfuVr5aLcn4yveGvBZvw==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], + "packages/cli/node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", "engines": { - "node": ">=18" + "node": ">= 0.6" } }, - "packages/cli/node_modules/@esbuild/netbsd-x64": { - "version": "0.25.5", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.5.tgz", - "integrity": "sha512-WOb5fKrvVTRMfWFNCroYWWklbnXH0Q5rZppjq0vQIdlsQKuw6mdSihwSo4RV/YdQ5UCKKvBy7/0ZZYLBZKIbwQ==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" + "packages/cli/node_modules/merge-descriptors": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", + "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "packages/cli/node_modules/@esbuild/openbsd-arm64": { - "version": "0.25.5", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.5.tgz", - "integrity": "sha512-7A208+uQKgTxHd0G0uqZO8UjK2R0DDb4fDmERtARjSHWxqMTye4Erz4zZafx7Di9Cv+lNHYuncAkiGFySoD+Mw==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], + "packages/cli/node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "bin": { + "mime": "cli.js" + }, "engines": { - "node": ">=18" + "node": ">=4" } }, - "packages/cli/node_modules/@esbuild/openbsd-x64": { - "version": "0.25.5", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.5.tgz", - "integrity": "sha512-G4hE405ErTWraiZ8UiSoesH8DaCsMm0Cay4fsFWOOUcz8b8rC6uCvnagr+gnioEjWn0wC+o1/TAHt+It+MpIMg==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } + "packages/cli/node_modules/path-to-regexp": { + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz", + "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==" }, - "packages/cli/node_modules/@esbuild/sunos-x64": { - "version": "0.25.5", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.5.tgz", - "integrity": "sha512-l+azKShMy7FxzY0Rj4RCt5VD/q8mG/e+mDivgspo+yL8zW7qEwctQ6YqKX34DTEleFAvCIUviCFX1SDZRSyMQA==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "sunos" - ], + "packages/cli/node_modules/qs": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", + "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", + "dependencies": { + "side-channel": "^1.0.6" + }, "engines": { - "node": ">=18" + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "packages/cli/node_modules/@esbuild/win32-arm64": { - "version": "0.25.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.5.tgz", - "integrity": "sha512-O2S7SNZzdcFG7eFKgvwUEZ2VG9D/sn/eIiz8XRZ1Q/DO5a3s76Xv0mdBzVM5j5R639lXQmPmSo0iRpHqUUrsxw==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], + "packages/cli/node_modules/raw-body": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, "engines": { - "node": ">=18" + "node": ">= 0.8" } }, - "packages/cli/node_modules/@esbuild/win32-ia32": { - "version": "0.25.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.5.tgz", - "integrity": "sha512-onOJ02pqs9h1iMJ1PQphR+VZv8qBMQ77Klcsqv9CNW2w6yLqoURLcgERAIurY6QE63bbLuqgP9ATqajFLK5AMQ==", - "cpu": [ - "ia32" - ], - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], + "packages/cli/node_modules/send": { + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", + "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, "engines": { - "node": ">=18" + "node": ">= 0.8.0" } }, - "packages/cli/node_modules/@esbuild/win32-x64": { - "version": "0.25.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.5.tgz", - "integrity": "sha512-TXv6YnJ8ZMVdX+SXWVBo/0p8LTcrUYngpWjvm91TMjjBQii7Oz11Lw5lbDV5Y0TzuhSJHwiH4hEtC1I42mMS0g==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], + "packages/cli/node_modules/send/node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", "engines": { - "node": ">=18" + "node": ">= 0.8" } }, - "packages/cli/node_modules/esbuild": { - "version": "0.25.5", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.5.tgz", - "integrity": "sha512-P8OtKZRv/5J5hhz0cUAdu/cLuPIKXpQl1R9pZtvmHWQvrAUVd0UNIPT4IB4W3rNOqVO0rlqHmCIbSwxh/c9yUQ==", - "hasInstallScript": true, - "license": "MIT", - "bin": { - "esbuild": "bin/esbuild" + "packages/cli/node_modules/serve-static": { + "version": "1.16.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz", + "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==", + "dependencies": { + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.19.0" }, "engines": { - "node": ">=18" - }, - "optionalDependencies": { - "@esbuild/aix-ppc64": "0.25.5", - "@esbuild/android-arm": "0.25.5", - "@esbuild/android-arm64": "0.25.5", - "@esbuild/android-x64": "0.25.5", - "@esbuild/darwin-arm64": "0.25.5", - "@esbuild/darwin-x64": "0.25.5", - "@esbuild/freebsd-arm64": "0.25.5", - "@esbuild/freebsd-x64": "0.25.5", - "@esbuild/linux-arm": "0.25.5", - "@esbuild/linux-arm64": "0.25.5", - "@esbuild/linux-ia32": "0.25.5", - "@esbuild/linux-loong64": "0.25.5", - "@esbuild/linux-mips64el": "0.25.5", - "@esbuild/linux-ppc64": "0.25.5", - "@esbuild/linux-riscv64": "0.25.5", - "@esbuild/linux-s390x": "0.25.5", - "@esbuild/linux-x64": "0.25.5", - "@esbuild/netbsd-arm64": "0.25.5", - "@esbuild/netbsd-x64": "0.25.5", - "@esbuild/openbsd-arm64": "0.25.5", - "@esbuild/openbsd-x64": "0.25.5", - "@esbuild/sunos-x64": "0.25.5", - "@esbuild/win32-arm64": "0.25.5", - "@esbuild/win32-ia32": "0.25.5", - "@esbuild/win32-x64": "0.25.5" + "node": ">= 0.8.0" } }, - "packages/cli/node_modules/express-rate-limit": { - "version": "7.5.1", - "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-7.5.1.tgz", - "integrity": "sha512-7iN8iPMDzOMHPUYllBEsQdWVB6fPDMPqwjBaFrgr4Jgr/+okjvzAy+UHlYYL/Vs0OsOrMkwS6PJDkFlJwoxUnw==", - "license": "MIT", - "engines": { - "node": ">= 16" - }, - "funding": { - "url": "https://github.com/sponsors/express-rate-limit" + "packages/cli/node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" }, - "peerDependencies": { - "express": ">= 4.11" + "engines": { + "node": ">= 0.6" } }, "packages/client-config": { @@ -53206,35 +54162,6 @@ "node": ">=16.0.0" } }, - "packages/integration-tests/node_modules/ansi-regex": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", - "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "packages/integration-tests/node_modules/strip-ansi": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", - "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, "packages/model-generator": { "name": "@aws-amplify/model-generator", "version": "1.2.0", @@ -53390,19 +54317,6 @@ "@aws-cdk/cli-plugin-contract": "^2" } }, - "packages/plugin-types/node_modules/@smithy/abort-controller": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-4.0.4.tgz", - "integrity": "sha512-gJnEjZMvigPDQWHrW3oPrFhQtkrgqBkyjj3pCIdF3A5M6vsZODG93KNlfJprv6bp4245bdT32fsHK4kkH3KYDA==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/types": "^4.3.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, "packages/plugin-types/node_modules/@smithy/core": { "version": "3.5.3", "resolved": "https://registry.npmjs.org/@smithy/core/-/core-3.5.3.tgz", @@ -53423,22 +54337,6 @@ "node": ">=18.0.0" } }, - "packages/plugin-types/node_modules/@smithy/fetch-http-handler": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-5.0.4.tgz", - "integrity": "sha512-AMtBR5pHppYMVD7z7G+OlHHAcgAN7v0kVKEpHuTO4Gb199Gowh0taYi9oDStFeUhetkeP55JLSVlTW1n9rFtUw==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/protocol-http": "^5.1.2", - "@smithy/querystring-builder": "^4.0.4", - "@smithy/types": "^4.3.1", - "@smithy/util-base64": "^4.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, "packages/plugin-types/node_modules/@smithy/middleware-endpoint": { "version": "4.1.11", "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-4.1.11.tgz", @@ -53458,104 +54356,6 @@ "node": ">=18.0.0" } }, - "packages/plugin-types/node_modules/@smithy/middleware-serde": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/@smithy/middleware-serde/-/middleware-serde-4.0.8.tgz", - "integrity": "sha512-iSSl7HJoJaGyMIoNn2B7czghOVwJ9nD7TMvLhMWeSB5vt0TnEYyRRqPJu/TqW76WScaNvYYB8nRoiBHR9S1Ddw==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/protocol-http": "^5.1.2", - "@smithy/types": "^4.3.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "packages/plugin-types/node_modules/@smithy/node-config-provider": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-4.1.3.tgz", - "integrity": "sha512-HGHQr2s59qaU1lrVH6MbLlmOBxadtzTsoO4c+bF5asdgVik3I8o7JIOzoeqWc5MjVa+vD36/LWE0iXKpNqooRw==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/property-provider": "^4.0.4", - "@smithy/shared-ini-file-loader": "^4.0.4", - "@smithy/types": "^4.3.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "packages/plugin-types/node_modules/@smithy/node-http-handler": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-4.0.6.tgz", - "integrity": "sha512-NqbmSz7AW2rvw4kXhKGrYTiJVDHnMsFnX4i+/FzcZAfbOBauPYs2ekuECkSbtqaxETLLTu9Rl/ex6+I2BKErPA==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/abort-controller": "^4.0.4", - "@smithy/protocol-http": "^5.1.2", - "@smithy/querystring-builder": "^4.0.4", - "@smithy/types": "^4.3.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "packages/plugin-types/node_modules/@smithy/property-provider": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-4.0.4.tgz", - "integrity": "sha512-qHJ2sSgu4FqF4U/5UUp4DhXNmdTrgmoAai6oQiM+c5RZ/sbDwJ12qxB1M6FnP+Tn/ggkPZf9ccn4jqKSINaquw==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/types": "^4.3.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "packages/plugin-types/node_modules/@smithy/protocol-http": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-5.1.2.tgz", - "integrity": "sha512-rOG5cNLBXovxIrICSBm95dLqzfvxjEmuZx4KK3hWwPFHGdW3lxY0fZNXfv2zebfRO7sJZ5pKJYHScsqopeIWtQ==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/types": "^4.3.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "packages/plugin-types/node_modules/@smithy/querystring-builder": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-4.0.4.tgz", - "integrity": "sha512-SwREZcDnEYoh9tLNgMbpop+UTGq44Hl9tdj3rf+yeLcfH7+J8OXEBaMc2kDxtyRHu8BhSg9ADEx0gFHvpJgU8w==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/types": "^4.3.1", - "@smithy/util-uri-escape": "^4.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "packages/plugin-types/node_modules/@smithy/querystring-parser": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/@smithy/querystring-parser/-/querystring-parser-4.0.4.tgz", - "integrity": "sha512-6yZf53i/qB8gRHH/l2ZwUG5xgkPgQF15/KxH0DdXMDHjesA9MeZje/853ifkSY0x4m5S+dfDZ+c4x439PF0M2w==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/types": "^4.3.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, "packages/plugin-types/node_modules/@smithy/service-error-classification": { "version": "4.0.5", "resolved": "https://registry.npmjs.org/@smithy/service-error-classification/-/service-error-classification-4.0.5.tgz", @@ -53568,58 +54368,6 @@ "node": ">=18.0.0" } }, - "packages/plugin-types/node_modules/@smithy/shared-ini-file-loader": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-4.0.4.tgz", - "integrity": "sha512-63X0260LoFBjrHifPDs+nM9tV0VMkOTl4JRMYNuKh/f5PauSjowTfvF3LogfkWdcPoxsA9UjqEOgjeYIbhb7Nw==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/types": "^4.3.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "packages/plugin-types/node_modules/@smithy/types": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.3.1.tgz", - "integrity": "sha512-UqKOQBL2x6+HWl3P+3QqFD4ncKq0I8Nuz9QItGv5WuKuMHuuwlhvqcZCoXGfc+P1QmfJE7VieykoYYmrOoFJxA==", - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "packages/plugin-types/node_modules/@smithy/url-parser": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/@smithy/url-parser/-/url-parser-4.0.4.tgz", - "integrity": "sha512-eMkc144MuN7B0TDA4U2fKs+BqczVbk3W+qIvcoCY6D1JY3hnAdCuhCZODC+GAeaxj0p6Jroz4+XMUn3PCxQQeQ==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/querystring-parser": "^4.0.4", - "@smithy/types": "^4.3.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "packages/plugin-types/node_modules/@smithy/util-middleware": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-4.0.4.tgz", - "integrity": "sha512-9MLKmkBmf4PRb0ONJikCbCwORACcil6gUWojwARCClT7RmLzF04hUR4WdRprIXal7XVyrddadYNfp2eF3nrvtQ==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/types": "^4.3.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, "packages/plugin-types/node_modules/@smithy/util-retry": { "version": "4.0.5", "resolved": "https://registry.npmjs.org/@smithy/util-retry/-/util-retry-4.0.5.tgz", @@ -53634,25 +54382,6 @@ "node": ">=18.0.0" } }, - "packages/plugin-types/node_modules/@smithy/util-stream": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-4.2.2.tgz", - "integrity": "sha512-aI+GLi7MJoVxg24/3J1ipwLoYzgkB4kUfogZfnslcYlynj3xsQ0e7vk4TnTro9hhsS5PvX1mwmkRqqHQjwcU7w==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/fetch-http-handler": "^5.0.4", - "@smithy/node-http-handler": "^4.0.6", - "@smithy/types": "^4.3.1", - "@smithy/util-base64": "^4.0.0", - "@smithy/util-buffer-from": "^4.0.0", - "@smithy/util-hex-encoding": "^4.0.0", - "@smithy/util-utf8": "^4.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, "packages/plugin-types/node_modules/@smithy/util-waiter": { "version": "4.0.5", "resolved": "https://registry.npmjs.org/@smithy/util-waiter/-/util-waiter-4.0.5.tgz", diff --git a/package.json b/package.json index c5df92e0070..a03b3850237 100644 --- a/package.json +++ b/package.json @@ -66,6 +66,8 @@ "@aws-sdk/client-iam": "^3.750.0", "@aws-sdk/client-s3": "^3.750.0", "@aws-sdk/client-ssm": "^3.750.0", + "@aws-sdk/eventstream-handler-node": "^3.821.0", + "@aws-sdk/middleware-eventstream": "^3.821.0", "@changesets/cli": "^2.26.1", "@changesets/get-release-plan": "^4.0.0", "@changesets/types": "^6.0.0", @@ -97,6 +99,7 @@ "glob": "^11.0.2", "husky": "^9.1.7", "lint-staged": "^15.2.10", + "npm-force-resolutions": "^0.0.10", "prettier": "^3.5.3", "rimraf": "^6.0.1", "semver": "^7.5.4", diff --git a/packages/cli-core/API.md b/packages/cli-core/API.md index 975ae9cdee7..7d4f33387fe 100644 --- a/packages/cli-core/API.md +++ b/packages/cli-core/API.md @@ -90,6 +90,9 @@ export enum LogLevel { // @public (undocumented) export const minimumLogLevel: LogLevel; +// @public +export const normalizeCDKConstructPath: (constructPath: string) => string; + // @public (undocumented) export type Notice = z.infer; diff --git a/packages/cli-core/src/formatters/cdk_path_formatter.ts b/packages/cli-core/src/formatters/cdk_path_formatter.ts new file mode 100644 index 00000000000..49d58e5fcdc --- /dev/null +++ b/packages/cli-core/src/formatters/cdk_path_formatter.ts @@ -0,0 +1,22 @@ +/** + * Utilities for formatting CDK paths and constructs + */ + +/** + * Normalizes a CDK construct path to create a more readable friendly name + * @param constructPath The CDK construct path + * @returns A normalized construct path + */ +export const normalizeCDKConstructPath = (constructPath: string): string => { + // Don't process very long paths to avoid performance issues + if (constructPath.length > 1000) return constructPath; + + // Handle nested stack paths + const nestedStackRegex = + /(?[a-zA-Z0-9_]+)\.NestedStack\/\1\.NestedStackResource$/; + + return constructPath + .replace(nestedStackRegex, '$') + .replace('/amplifyAuth/', '/') + .replace('/amplifyData/', '/'); +}; diff --git a/packages/cli-core/src/index.ts b/packages/cli-core/src/index.ts index 366f908e1f8..027ec669b65 100644 --- a/packages/cli-core/src/index.ts +++ b/packages/cli-core/src/index.ts @@ -6,3 +6,4 @@ export * from './package-manager-controller/package_manager_controller_factory.j export * from './loggers/amplify_io_events_bridge_singleton_factory.js'; export * from './notices/notices.js'; export * from './notices/notices_manifest_validator.js'; +export { normalizeCDKConstructPath } from './formatters/cdk_path_formatter.js'; diff --git a/packages/cli-core/src/loggers/cfn-deployment-progress/cfn_deployment_progress_logger.ts b/packages/cli-core/src/loggers/cfn-deployment-progress/cfn_deployment_progress_logger.ts index 7da64d9acaf..57592c3df2d 100644 --- a/packages/cli-core/src/loggers/cfn-deployment-progress/cfn_deployment_progress_logger.ts +++ b/packages/cli-core/src/loggers/cfn-deployment-progress/cfn_deployment_progress_logger.ts @@ -3,6 +3,7 @@ import { StackEvent } from '@aws-sdk/client-cloudformation'; import { RewritableBlock } from './rewritable_block.js'; import { ColorName, format } from '../../format/format.js'; import { EOL } from 'os'; +import { normalizeCDKConstructPath } from '../../formatters/cdk_path_formatter.js'; /** * Collects events from CDK Toolkit about cfn deployment and structures them @@ -103,7 +104,7 @@ export class CfnDeploymentProgressLogger { if (metadata && metadata.constructPath) { if (!(event.LogicalResourceId in this.resourceNameCache)) { this.resourceNameCache[event.LogicalResourceId] = - this.normalizeCDKConstructPath(metadata.constructPath); + normalizeCDKConstructPath(metadata.constructPath); } } // Hydrate friendly name resource cache @@ -231,21 +232,6 @@ export class CfnDeploymentProgressLogger { await this.block.displayLines(lines); } - /** - * Extract nested stack names - */ - private normalizeCDKConstructPath = (constructPath: string): string => { - // Don't run regex on long strings, they are most likely not valid and could cause DOS attach. See CodeQL's js/polynomial-redos - if (constructPath.length > 1000) return constructPath; - const nestedStackRegex = - /(?[a-zA-Z0-9_]+)\.NestedStack\/\1\.NestedStackResource$/; - - return constructPath - .replace(nestedStackRegex, '$') - .replace('/amplifyAuth/', '/') - .replace('/amplifyData/', '/'); - }; - /** * Extract the failure reason from stack events */ diff --git a/packages/cli/package.json b/packages/cli/package.json index aee31f69eac..694466f89f2 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -72,6 +72,7 @@ "semver": "^7.6.3", "socket.io": "^4.8.1", "socket.io-client": "^4.8.1", + "strip-ansi": "^7.1.0", "typescript": "^5.8.3", "ws": "^8.18.2", "yargs": "^17.7.2", diff --git a/packages/cli/src/commands/sandbox/port_checker.ts b/packages/cli/src/commands/sandbox/port_checker.ts index 4d303189d00..d46d23380bd 100644 --- a/packages/cli/src/commands/sandbox/port_checker.ts +++ b/packages/cli/src/commands/sandbox/port_checker.ts @@ -1,10 +1,14 @@ import net from 'net'; /** - * Port checker class. Provides utilities for checking if ports are in use - * and if specific services are running. + * Port checker class. Provides utilities for checking if ports are in use. */ export class PortChecker { + /** + * Default DevTools port + */ + private static readonly defaultDevtoolsPort = 3333; + /** * Checks if a port is in use * @param port The port to check diff --git a/packages/cli/src/commands/sandbox/sandbox-devtools/logging/cloudformation_format.test.ts b/packages/cli/src/commands/sandbox/sandbox-devtools/logging/cloudformation_format.test.ts new file mode 100644 index 00000000000..c9c7a6ac85e --- /dev/null +++ b/packages/cli/src/commands/sandbox/sandbox-devtools/logging/cloudformation_format.test.ts @@ -0,0 +1,116 @@ +/* eslint-disable spellcheck/spell-checker */ +import { describe, it } from 'node:test'; +import assert from 'node:assert'; +import { createFriendlyName } from './cloudformation_format.js'; + +void describe('createFriendlyName function', () => { + void it('handles empty string by returning the original ID', () => { + const emptyId = ''; + assert.strictEqual(createFriendlyName(emptyId), emptyId); + }); + + void it('uses CDK metadata construct path when available', () => { + const logicalId = 'amplifyFunction123ABC45'; + const metadata = { constructPath: 'MyStack/MyFunction/Resource' }; + assert.strictEqual(createFriendlyName(logicalId, metadata), 'My Function'); + }); + + void it('removes amplify prefix and formats camel case', () => { + const logicalId = 'amplifyDataTable123ABC45'; + assert.strictEqual(createFriendlyName(logicalId), 'Data Table'); + }); + + void it('removes Amplify prefix (capitalized) and formats camel case', () => { + const logicalId = 'AmplifyDataTable123ABC45'; + assert.strictEqual(createFriendlyName(logicalId), 'Data Table'); + }); + + void it('handles IDs with only numeric characters', () => { + const numericId = '12345'; + assert.strictEqual(createFriendlyName(numericId), numericId); + }); + + void it('normalizes CDK construct paths', () => { + const logicalId = 'amplifyFunction'; + const metadata = { + constructPath: 'MyStack/auth.NestedStack/auth.NestedStackResource', + }; + assert.strictEqual(createFriendlyName(logicalId, metadata), 'auth'); + }); + + void it('skips Resource and Default in construct paths', () => { + const logicalId = 'amplifyFunction'; + const metadata = { constructPath: 'MyStack/Auth/Resource' }; + assert.strictEqual(createFriendlyName(logicalId, metadata), 'Auth'); + }); + + void it('handles multiple levels of Resource and Default', () => { + const logicalId = 'amplifyFunction'; + const metadata = { constructPath: 'MyStack/Auth/Default/Resource' }; + assert.strictEqual(createFriendlyName(logicalId, metadata), 'Auth'); + }); + + void it('formats camel case with multiple uppercase letters', () => { + const logicalId = 'amplifyGraphQLAPI123ABC45'; + assert.strictEqual(createFriendlyName(logicalId), 'Graph QLAPI'); + }); + + void it('handles complex CloudFormation resource IDs', () => { + const logicalId = 'TodoIAMRole2DA8E66E'; + assert.strictEqual(createFriendlyName(logicalId), 'Todo IAM Role'); + }); + + void it('handles empty construct path', () => { + const logicalId = 'amplifyFunction'; + const metadata = { constructPath: '' }; + assert.strictEqual(createFriendlyName(logicalId, metadata), 'Function'); + }); + + // Examples from documentation + void it('formats TodoTable correctly', () => { + const logicalId = 'TodoTable'; + assert.strictEqual(createFriendlyName(logicalId), 'Todo Table'); + }); + + void it('formats TodoIAMRole with ID correctly', () => { + const logicalId = 'TodoIAMRole2DA8E66E'; + assert.strictEqual(createFriendlyName(logicalId), 'Todo IAM Role'); + }); + + void it('formats amplifyDataGraphQLAPI with ID correctly', () => { + const logicalId = 'amplifyDataGraphQLAPI42A6FA33'; + assert.strictEqual(createFriendlyName(logicalId), 'Data Graph QLAPI'); + }); + + void it('formats testNameBucketPolicy with ID correctly', () => { + const logicalId = 'testNameBucketPolicyA5C458BB'; + assert.strictEqual( + createFriendlyName(logicalId), + 'test Name Bucket Policy', + ); + }); + + void it('handles CDK construct path example', () => { + const logicalId = 'somelogicalId'; + const metadata = { + constructPath: + 'amplify-amplifyvitereacttemplate-meghabit-sandbox-83e297d0db/data/modelIntrospectionSchemaBucket/Resource', + }; + assert.strictEqual( + createFriendlyName(logicalId, metadata), + 'model Introspection Schema Bucket', + ); + }); + + void it('handles CDK construct path example', () => { + const logicalId = 'someLogicalId'; + const metadata = { + constructPath: + 'amplify-amplifyvitereacttemplate-meghabit-sandbox-83e297d0db/data/GraphQLAPI/DefaultApiKey', + }; + assert.strictEqual( + createFriendlyName(logicalId, metadata), + 'Default Api Key', + ); + }); +}); diff --git a/packages/cli/src/commands/sandbox/sandbox-devtools/logging/cloudformation_format.ts b/packages/cli/src/commands/sandbox/sandbox-devtools/logging/cloudformation_format.ts new file mode 100644 index 00000000000..afb078589be --- /dev/null +++ b/packages/cli/src/commands/sandbox/sandbox-devtools/logging/cloudformation_format.ts @@ -0,0 +1,53 @@ +import { normalizeCDKConstructPath } from '@aws-amplify/cli-core'; + +/** + * Creates a friendly name for a resource, using CDK metadata when available. + * @param logicalId The logical ID of the resource + * @param metadata Optional CDK metadata that may contain construct path + * @param metadata.constructPath Optional construct path from CDK metadata + * @returns A user-friendly name for the resource + * + * Examples of friendly names: + * - "TodoTable" → "Todo Table" + * - "TodoIAMRole2DA8E66E" → "Todo IAM Role" + * - "amplifyDataGraphQLAPI42A6FA33" → "Data GraphQLAPI" + * - "testNameBucketPolicyA5C458BB" → "test Name Bucket Policy" + * + * For construct paths: + * - amplify-amplify-identifier-sandbox-83e297d0db/data/GraphQLAPI/DefaultApiKey → "Default Api Key" + * - amplify-amplify-identifier-sandbox-83e297d0db/auth/amplifyAuth/authenticatedUserRole/Resource → "authenticated User Role" + */ +export const createFriendlyName = ( + logicalId: string, + metadata?: { constructPath?: string }, +): string => { + let name = logicalId; + if (metadata?.constructPath) { + const normalizedPath = normalizeCDKConstructPath(metadata.constructPath); + const parts = normalizedPath.split('/'); + let resourceName = parts.pop(); + while ( + (resourceName === 'Resource' || resourceName === 'Default') && + parts.length > 0 + ) { + resourceName = parts.pop(); + } + + name = resourceName || logicalId; + } + + // Fall back to the basic transformation + name = name.replace(/^amplify/, '').replace(/^Amplify/, ''); + + name = name.replace(/([a-z])([A-Z])/g, '$1 $2'); + + name = name.replace(/([A-Z])([A-Z][a-z])/g, '$1 $2'); + + // Remove CloudFormation resource IDs (alphanumeric suffixes) + name = name.replace(/[0-9A-F]{6,}$/g, ''); + + name = name.replace(/\s+/g, ' ').trim(); + + const result = name || logicalId; + return result; +}; diff --git a/packages/cli/src/commands/sandbox/sandbox-devtools/react-app/index.css b/packages/cli/src/commands/sandbox/sandbox-devtools/react-app/index.css deleted file mode 100644 index 803b70f93cc..00000000000 --- a/packages/cli/src/commands/sandbox/sandbox-devtools/react-app/index.css +++ /dev/null @@ -1,29 +0,0 @@ -:root { - font-family: - -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, - Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif; - line-height: 1.5; - font-weight: 400; - - color-scheme: light dark; - color: rgba(255, 255, 255, 0.87); - background-color: #242424; - - font-synthesis: none; - text-rendering: optimizeLegibility; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; -} - -body { - margin: 0; - display: flex; - place-items: center; - min-width: 320px; - min-height: 100vh; -} - -#root { - width: 100%; - height: 100vh; -} diff --git a/packages/cli/src/commands/sandbox/sandbox-devtools/react-app/package-lock.json b/packages/cli/src/commands/sandbox/sandbox-devtools/react-app/package-lock.json index 5fbdac7cb69..aee8467ba48 100644 --- a/packages/cli/src/commands/sandbox/sandbox-devtools/react-app/package-lock.json +++ b/packages/cli/src/commands/sandbox/sandbox-devtools/react-app/package-lock.json @@ -14,7 +14,8 @@ "esbuild": "0.25.5", "react": "^19.1.0", "react-dom": "^19.1.0", - "socket.io-client": "^4.8.1" + "socket.io-client": "^4.8.1", + "strip-ansi": "^7.1.0" }, "devDependencies": { "@eslint/js": "^9.25.0", @@ -1816,6 +1817,17 @@ "url": "https://github.com/sponsors/epoberezkin" } }, + "node_modules/ansi-regex": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, "node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -3254,6 +3266,20 @@ "node": ">=0.10.0" } }, + "node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, "node_modules/strip-json-comments": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", diff --git a/packages/cli/src/commands/sandbox/sandbox-devtools/react-app/package.json b/packages/cli/src/commands/sandbox/sandbox-devtools/react-app/package.json index 5db38bde7b0..1618eef02bf 100644 --- a/packages/cli/src/commands/sandbox/sandbox-devtools/react-app/package.json +++ b/packages/cli/src/commands/sandbox/sandbox-devtools/react-app/package.json @@ -16,7 +16,8 @@ "esbuild": "0.25.5", "react": "^19.1.0", "react-dom": "^19.1.0", - "socket.io-client": "^4.8.1" + "socket.io-client": "^4.8.1", + "strip-ansi": "^7.1.0" }, "devDependencies": { "@eslint/js": "^9.25.0", diff --git a/packages/cli/src/commands/sandbox/sandbox-devtools/react-app/src/App.tsx b/packages/cli/src/commands/sandbox/sandbox-devtools/react-app/src/App.tsx index f1df5b3e8d0..fff716f2919 100644 --- a/packages/cli/src/commands/sandbox/sandbox-devtools/react-app/src/App.tsx +++ b/packages/cli/src/commands/sandbox/sandbox-devtools/react-app/src/App.tsx @@ -1,16 +1,488 @@ -import '../index.css'; +import { useState, useEffect, useRef } from 'react'; +import ConsoleViewer from './components/ConsoleViewer'; +import Header from './components/Header'; +import ResourceConsole from './components/ResourceConsole'; +import SandboxOptionsModal from './components/SandboxOptionsModal'; +import { DevToolsSandboxOptions } from '../../shared/socket_types'; +import { SocketClientProvider } from './contexts/socket_client_context'; +import { useSandboxClientService } from './contexts/socket_client_context'; +import { SandboxStatusData } from './services/sandbox_client_service'; +import { SandboxStatus } from '@aws-amplify/sandbox'; +// Define LogEntry interface for PR2 (will be replaced in PR3) +interface LogEntry { + id: string; + timestamp: string; + level: string; + message: string; +} + +import { + AppLayout, + Tabs, + ContentLayout, + SpaceBetween, + Alert, +} from '@cloudscape-design/components'; +import '@cloudscape-design/global-styles/index.css'; + +/** + * Main App component that wraps the application with the socket client provider + */ function App() { return ( -
-
-

Amplify Sandbox DevTools

-

Coming soon...

-
-
-

This is a placeholder for the Amplify Sandbox DevTools UI.

-
-
+ + + + ); +} + +/** + * Inner App component that uses the services + */ +function AppContent() { + const [logs, setLogs] = useState([]); + const [connected, setConnected] = useState(false); + const [activeTabId, setActiveTabId] = useState('logs'); + const [sandboxStatus, setSandboxStatus] = useState('unknown'); + const [sandboxIdentifier, setSandboxIdentifier] = useState< + string | undefined + >(undefined); + const [showOptionsModal, setShowOptionsModal] = useState(false); + const [connectionError, setConnectionError] = useState(null); + const statusRequestedRef = useRef(false); + const [isStartingLoading, setIsStartingLoading] = useState(false); + + const sandboxClientService = useSandboxClientService(); + + const deploymentInProgress = sandboxStatus === 'deploying'; + + const clearLogs = () => { + setLogs([]); + }; + + useEffect(() => { + // Register for sandbox status updates + const unsubscribeSandboxStatus = sandboxClientService.onSandboxStatus( + (data: SandboxStatusData) => { + console.log(`[CLIENT] Status update received: ${data.status}`, data); + + setSandboxStatus((prevStatus) => { + console.log( + `[CLIENT] Updating sandboxStatus from ${prevStatus} to ${data.status}`, + ); + return data.status; + }); + + if (data.identifier) { + setSandboxIdentifier((prevId) => { + console.log( + `[CLIENT] Updating sandboxIdentifier from ${prevId} to ${data.identifier}`, + ); + return data.identifier; + }); + } else if (data.status === 'nonexistent') { + setSandboxIdentifier((prevId) => { + console.log(`[CLIENT] Clearing sandboxIdentifier from ${prevId}`); + return undefined; + }); + } + + if (data.deploymentCompleted) { + console.log( + '[CLIENT] Deployment completed event received via sandboxStatus:', + data, + ); + + // Add deployment completion log + setLogs((prev) => [ + ...prev, + { + id: Date.now().toString(), + timestamp: data.timestamp || new Date().toISOString(), + level: data.error ? 'ERROR' : 'SUCCESS', + message: + data.message || + (data.error + ? 'Deployment failed' + : 'Deployment completed successfully'), + }, + ]); + } + + if (data.error) { + setLogs((prev) => [ + ...prev, + { + id: Date.now().toString(), + timestamp: new Date().toISOString(), + level: 'ERROR', + message: `Sandbox error: ${data.error}`, + }, + ]); + } else { + if (!data.deploymentCompleted) { + setLogs((prev) => [ + ...prev, + { + id: Date.now().toString(), + timestamp: new Date().toISOString(), + level: 'INFO', + message: data.identifier + ? `Sandbox status: ${data.status} (identifier: ${data.identifier})` + : `Sandbox status: ${data.status}`, + }, + ]); + } + } + + // Force a re-render by updating a dummy state + setLogs((prev) => [...prev]); + }, + ); + + // Handle connection events + const unsubscribeConnect = sandboxClientService.onConnect(() => { + console.log('Socket connected'); + setConnected(true); + setConnectionError(null); + // Add a short delay before requesting status to ensure socket handlers are set up + setTimeout(() => { + // Explicitly request sandbox status after a short delay + if (!statusRequestedRef.current) { + console.log('Requesting sandbox status after connection delay'); + sandboxClientService.getSandboxStatus(); + console.log('getSandboxStatus request sent'); // Confirm the request was sent + statusRequestedRef.current = true; + setLogs((prev) => [ + ...prev, + { + id: Date.now().toString(), + timestamp: new Date().toISOString(), + level: 'INFO', + message: + 'DevTools connected to Amplify Sandbox, requesting status...', + }, + ]); + } else { + setLogs((prev) => [ + ...prev, + { + id: Date.now().toString(), + timestamp: new Date().toISOString(), + level: 'INFO', + message: 'DevTools reconnected to Amplify Sandbox', + }, + ]); + } + }, 500); // 500ms delay + }); + + // Handle connection errors + const unsubscribeConnectError = sandboxClientService.onConnectError( + (error) => { + console.error('Socket connection error:', error); + setConnectionError('true'); + setLogs((prev) => [ + ...prev, + { + id: Date.now().toString(), + timestamp: new Date().toISOString(), + level: 'ERROR', + message: `Connection error: ${error.message}`, + }, + ]); + }, + ); + + const unsubscribeConnectTimeout = sandboxClientService.onConnectTimeout( + () => { + console.error('Socket connection timeout'); + setConnectionError('true'); + setLogs((prev) => [ + ...prev, + { + id: Date.now().toString(), + timestamp: new Date().toISOString(), + level: 'ERROR', + message: 'Connection timeout', + }, + ]); + }, + ); + + // Add reconnection logging + const unsubscribeReconnect = sandboxClientService.onReconnect( + (attemptNumber) => { + console.log(`Socket reconnected after ${attemptNumber} attempts`); + // Request sandbox status after reconnection + sandboxClientService.getSandboxStatus(); + }, + ); + + const unsubscribeReconnectAttempt = sandboxClientService.onReconnectAttempt( + (attemptNumber) => { + console.log(`Socket reconnection attempt ${attemptNumber}`); + }, + ); + + const unsubscribeReconnectError = sandboxClientService.onReconnectError( + (error) => { + console.log('Socket reconnection error:', error); + }, + ); + + const unsubscribeReconnectFailed = sandboxClientService.onReconnectFailed( + () => { + console.log('Socket reconnection failed'); + }, + ); + + // Subscribe to log events from the server + const unsubscribeLog = sandboxClientService.onLog((logData) => { + setLogs((prev) => [ + ...prev, + { + id: Date.now().toString(), + timestamp: logData.timestamp, + level: logData.level, + message: logData.message, + }, + ]); + }); + + // Handle disconnection + const unsubscribeDisconnect = sandboxClientService.onDisconnect( + (reason) => { + console.log(`Socket disconnected: ${reason}`); + setConnected(false); + setSandboxStatus('unknown'); + statusRequestedRef.current = false; // Reset so we request status on reconnect + + // Add to logs + setLogs((prev) => [ + ...prev, + { + id: Date.now().toString(), + timestamp: new Date().toISOString(), + level: 'WARNING', + message: `Disconnected from server: ${reason}`, + }, + ]); + + // If not a normal disconnect, set error + if (reason !== 'io client disconnect') { + setConnectionError('true'); + } + }, + ); + + // Set up a periodic ping to check connection health + const stopPing = sandboxClientService.startPingInterval(30000); + + // Clean up on unmount + return () => { + unsubscribeSandboxStatus.unsubscribe(); + unsubscribeConnect.unsubscribe(); + unsubscribeConnectError.unsubscribe(); + unsubscribeConnectTimeout.unsubscribe(); + unsubscribeReconnect.unsubscribe(); + unsubscribeReconnectAttempt.unsubscribe(); + unsubscribeReconnectError.unsubscribe(); + unsubscribeReconnectFailed.unsubscribe(); + unsubscribeDisconnect.unsubscribe(); + unsubscribeLog.unsubscribe(); + stopPing.unsubscribe(); + clearLogs(); + sandboxClientService.disconnect(); + }; + }, [sandboxClientService]); + + // Effect to periodically check sandbox status if unknown + useEffect(() => { + if (!connected || sandboxStatus !== 'unknown') return; + + // Periodic status check + const statusCheckInterval = setInterval(() => { + console.log('Requesting sandbox status due to unknown state'); + sandboxClientService.getSandboxStatus(); + + // Add a log entry to show we're still trying + setLogs((prev) => [ + ...prev, + { + id: Date.now().toString(), + timestamp: new Date().toISOString(), + level: 'INFO', + message: 'Requesting sandbox status...', + }, + ]); + }, 5000); // Check every 5 seconds + + // Force a status check after a short timeout + const forceStatusCheck = setTimeout(() => { + console.log('Forcing sandbox status check after timeout'); + sandboxClientService.getSandboxStatus(); + }, 2000); // Force a check after 2 seconds + + return () => { + clearInterval(statusCheckInterval); + clearTimeout(forceStatusCheck); + }; + }, [sandboxStatus, connected, sandboxClientService]); + + // Reset loading state when sandbox status changes + useEffect(() => { + if (sandboxStatus !== 'unknown') { + setIsStartingLoading(false); + } + }, [sandboxStatus]); + + const startSandbox = () => { + setIsStartingLoading(true); + setShowOptionsModal(true); + }; + + const handleStartSandboxWithOptions = (options: DevToolsSandboxOptions) => { + setShowOptionsModal(false); + + sandboxClientService.startSandboxWithOptions(options); + + const optionsText = + Object.keys(options).length > 0 + ? ` with options: ${JSON.stringify(options)}` + : ''; + + setLogs((prev) => [ + ...prev, + { + id: Date.now().toString(), + timestamp: new Date().toISOString(), + level: 'INFO', + message: `Requesting to start sandbox${optionsText}...`, + }, + ]); + }; + + const stopSandbox = () => { + sandboxClientService.stopSandbox(); + setLogs((prev) => [ + ...prev, + { + id: Date.now().toString(), + timestamp: new Date().toISOString(), + level: 'INFO', + message: 'Requesting to stop sandbox...', + }, + ]); + }; + + const deleteSandbox = () => { + sandboxClientService.deleteSandbox(); + setLogs((prev) => [ + ...prev, + { + id: Date.now().toString(), + timestamp: new Date().toISOString(), + level: 'INFO', + message: 'Requesting to delete sandbox...', + }, + ]); + }; + + const stopDevTools = () => { + sandboxClientService.stopDevTools(); + setLogs((prev) => [ + ...prev, + { + id: Date.now().toString(), + timestamp: new Date().toISOString(), + level: 'INFO', + message: 'Stopping DevTools process...', + }, + ]); + }; + + const mainContent = ( + {}} + isStartingLoading={isStartingLoading} + /> + } + > + {connectionError && ( + + Please restart it on the command line using:{' '} + npx ampx sandbox devtools + + )} + + {deploymentInProgress && ( + {}} + > + A sandbox deployment is currently in progress. You can view the + deployment details in the Console Logs tab. + + )} + + + setActiveTabId(detail.activeTabId)} + tabs={[ + { + id: 'logs', + label: 'Console Logs', + content: , + }, + { + id: 'resources', + label: 'Resources', + content: , + }, + ]} + /> + + + ); + + return ( + <> + + + { + setShowOptionsModal(false); + setIsStartingLoading(false); + }} + onConfirm={handleStartSandboxWithOptions} + /> + ); } diff --git a/packages/cli/src/commands/sandbox/sandbox-devtools/react-app/src/components/ConfirmationModal.tsx b/packages/cli/src/commands/sandbox/sandbox-devtools/react-app/src/components/ConfirmationModal.tsx new file mode 100644 index 00000000000..0323a3ed213 --- /dev/null +++ b/packages/cli/src/commands/sandbox/sandbox-devtools/react-app/src/components/ConfirmationModal.tsx @@ -0,0 +1,52 @@ +import React from 'react'; +import { + Modal, + Box, + SpaceBetween, + Button, + Header, +} from '@cloudscape-design/components'; + +interface ConfirmationModalProps { + visible: boolean; + title: string; + message: string; + confirmButtonText?: string; + cancelButtonText?: string; + onConfirm: () => void; + onCancel: () => void; +} + +const ConfirmationModal: React.FC = ({ + visible, + title, + message, + confirmButtonText = 'Confirm', + cancelButtonText = 'Cancel', + onConfirm, + onCancel, +}) => { + return ( + {title}} + footer={ + + + + + + + } + > + {message} + + ); +}; + +export default ConfirmationModal; diff --git a/packages/cli/src/commands/sandbox/sandbox-devtools/react-app/src/components/ConsoleViewer.tsx b/packages/cli/src/commands/sandbox/sandbox-devtools/react-app/src/components/ConsoleViewer.tsx new file mode 100644 index 00000000000..eba047a7abe --- /dev/null +++ b/packages/cli/src/commands/sandbox/sandbox-devtools/react-app/src/components/ConsoleViewer.tsx @@ -0,0 +1,231 @@ +import { useEffect, useRef, useState } from 'react'; +import { + Table, + Box, + Container, + StatusIndicator, + TextContent, + SpaceBetween, + Header, + Multiselect, + FormField, + Input, + Grid, +} from '@cloudscape-design/components'; +import '@cloudscape-design/global-styles/index.css'; +import stripAnsi from 'strip-ansi'; + +interface LogEntry { + id: string; + timestamp: string; + level: string; + message: string; +} + +interface ConsoleViewerProps { + logs: LogEntry[]; +} + +const ConsoleViewer = ({ logs }: ConsoleViewerProps) => { + const scrollContainerRef = useRef(null); + const [selectedLogLevels, setSelectedLogLevels] = useState([]); + const [searchQuery, setSearchQuery] = useState(''); + const [autoScroll, setAutoScroll] = useState(true); + + // Extract unique log levels from logs + const uniqueLevels = [...new Set(logs.map((log) => log.level))]; + const availableLogLevels = uniqueLevels.map((level) => ({ + label: level, + value: level, + })); + + const filteredLogs = logs.filter((log) => { + const matchesLevel = + selectedLogLevels.length === 0 || selectedLogLevels.includes(log.level); + + const matchesSearch = + !searchQuery || + log.message.toLowerCase().includes(searchQuery.toLowerCase()) || + log.level.toLowerCase().includes(searchQuery.toLowerCase()) || + log.timestamp.toLowerCase().includes(searchQuery.toLowerCase()); + + return matchesLevel && matchesSearch; + }); + + // Check if scrolled to bottom + const isAtBottom = (): boolean => { + if (!scrollContainerRef.current) return true; + + const { scrollTop, scrollHeight, clientHeight } = + scrollContainerRef.current; + // Consider "at bottom" if within 10px of the actual bottom + return scrollHeight - scrollTop - clientHeight < 10; + }; + + // Set up scroll event listener + useEffect(() => { + // Handle scroll events + const handleScroll = (): void => { + // If user manually scrolled to bottom, re-enable auto-scroll + if (isAtBottom() && !autoScroll) { + setAutoScroll(true); + } + + // If user scrolled up and auto-scroll is enabled, disable it + if (!isAtBottom() && autoScroll) { + setAutoScroll(false); + } + }; + + const scrollContainer = scrollContainerRef.current; + if (scrollContainer) { + scrollContainer.addEventListener('scroll', handleScroll); + } + + return () => { + if (scrollContainer) { + scrollContainer.removeEventListener('scroll', handleScroll); + } + }; + }, [autoScroll]); + + // Auto-scroll to bottom when logs change + useEffect(() => { + if (autoScroll && scrollContainerRef.current) { + scrollContainerRef.current.scrollTop = + scrollContainerRef.current.scrollHeight; + } + }, [filteredLogs, autoScroll]); + + const formatTimestamp = (timestamp: string) => { + try { + const date = new Date(timestamp); + return date.toLocaleTimeString(); + } catch { + return timestamp; + } + }; + + // Map log level to StatusIndicator type + const getStatusIndicatorIconForLogLevel = ( + level: string, + ): 'success' | 'info' | 'warning' | 'error' | 'pending' => { + const normalizedLevel = + typeof level === 'string' ? level.toLowerCase() : 'info'; + + switch (normalizedLevel) { + case 'error': + return 'error'; + case 'warn': + case 'warning': + return 'warning'; + case 'success': + return 'success'; + case 'info': + return 'info'; + case 'debug': + return 'pending'; + default: + return 'info'; + } + }; + + // Define table columns + const columnDefinitions = [ + { + id: 'timestamp', + header: 'Time', + cell: (item: LogEntry) => formatTimestamp(item.timestamp), + width: 100, + }, + { + id: 'level', + header: 'Level', + cell: (item: LogEntry) => ( + + {item.level} + + ), + width: 150, + }, + { + id: 'message', + header: 'Message', + cell: (item: LogEntry) => stripAnsi(item.message), + width: 'auto', + }, + ]; + + const emptyState = ( + + + +

No logs available

+

Logs will appear here when they are generated.

+
+
+
+ ); + + return ( + + +
Console Logs
+ + + + ({ + label: level, + value: level, + }))} + onChange={({ detail }) => + setSelectedLogLevels( + detail.selectedOptions.map( + (option) => option.value as string, + ), + ) + } + options={availableLogLevels} + placeholder="Select log levels to filter" + filteringType="auto" + deselectAriaLabel={(option) => `Remove ${option.label}`} + /> + + + + setSearchQuery(detail.value)} + placeholder="Search in logs..." + /> + + + +
+ + + + + ); +}; + +export default ConsoleViewer; diff --git a/packages/cli/src/commands/sandbox/sandbox-devtools/react-app/src/components/Header.tsx b/packages/cli/src/commands/sandbox/sandbox-devtools/react-app/src/components/Header.tsx new file mode 100644 index 00000000000..c99d8b4c4ac --- /dev/null +++ b/packages/cli/src/commands/sandbox/sandbox-devtools/react-app/src/components/Header.tsx @@ -0,0 +1,224 @@ +import { + Header as CloudscapeHeader, + Button, + StatusIndicator, + SpaceBetween, +} from '@cloudscape-design/components'; +import '@cloudscape-design/global-styles/index.css'; +import { useState, useEffect } from 'react'; +import { SandboxStatus } from '@aws-amplify/sandbox'; +import ConfirmationModal from './ConfirmationModal'; + +interface HeaderProps { + connected: boolean; + sandboxStatus: SandboxStatus; + sandboxIdentifier?: string; + onStartSandbox: () => void; + onStopSandbox: () => void; + onDeleteSandbox?: () => void; + onStopDevTools?: () => void; + onOpenSettings?: () => void; + isStartingLoading?: boolean; +} + +const Header = ({ + connected, + sandboxStatus, + sandboxIdentifier, + onStartSandbox, + onStopSandbox, + onDeleteSandbox, + onStopDevTools, + onOpenSettings, + isStartingLoading = false, +}: HeaderProps) => { + const [isLoading, setIsLoading] = useState(false); + const [showDeleteConfirmation, setShowDeleteConfirmation] = useState(false); + const [showStopDevToolsConfirmation, setShowStopDevToolsConfirmation] = + useState(false); + + // Reset loading state when sandbox status changes + useEffect(() => { + setIsLoading(false); + }, [sandboxStatus]); + + const handleStartSandbox = () => { + onStartSandbox(); + }; + + const handleStopSandbox = () => { + setIsLoading(true); + onStopSandbox(); + }; + + const handleDeleteSandbox = () => { + setShowDeleteConfirmation(true); + }; + + const confirmDeleteSandbox = () => { + setShowDeleteConfirmation(false); + setIsLoading(true); + onDeleteSandbox?.(); + }; + + const cancelDeleteSandbox = () => { + setShowDeleteConfirmation(false); + }; + + const handleStopDevTools = () => { + setShowStopDevToolsConfirmation(true); + }; + + const confirmStopDevTools = () => { + setShowStopDevToolsConfirmation(false); + onStopDevTools?.(); + }; + + const cancelStopDevTools = () => { + setShowStopDevToolsConfirmation(false); + }; + + const getSandboxStatusIndicator = () => { + const statusText = + sandboxIdentifier && sandboxStatus !== 'nonexistent' + ? `Sandbox (${sandboxIdentifier})` + : 'Sandbox'; + + switch (sandboxStatus) { + case 'running': + return ( + {statusText} Running + ); + case 'stopped': + return ( + {statusText} Stopped + ); + case 'nonexistent': + return No Sandbox; + case 'deploying': + return ( + + {statusText} Deploying + + ); + case 'deleting': + return ( + + {statusText} Deleting + + ); + default: + return ( + + Waiting for status... + + ); + } + }; + + // Check if the sandbox is in deploying or deleting state + const isDeploying = sandboxStatus === 'deploying'; + const isDeleting = sandboxStatus === 'deleting'; + + return ( + <> + + + + + + + {connected ? 'Connected' : 'Disconnected'} + + {getSandboxStatusIndicator()} + + } + actions={ + + {sandboxStatus === 'running' ? ( + + ) : ( + + )} + {onDeleteSandbox && ( + + )} + {onOpenSettings && ( + + )} + {/* */} + {onStopDevTools && ( + + )} + + } + > + Amplify Sandbox DevTools + + + ); +}; + +export default Header; diff --git a/packages/cli/src/commands/sandbox/sandbox-devtools/react-app/src/components/ResourceConsole.tsx b/packages/cli/src/commands/sandbox/sandbox-devtools/react-app/src/components/ResourceConsole.tsx new file mode 100644 index 00000000000..386480699c8 --- /dev/null +++ b/packages/cli/src/commands/sandbox/sandbox-devtools/react-app/src/components/ResourceConsole.tsx @@ -0,0 +1,688 @@ +import React, { useState, useMemo, useEffect } from 'react'; +import { useResourceManager } from '../hooks/useResourceManager'; +import { ResourceWithFriendlyName } from '../services/resource_client_service'; +import { useResourceClientService } from '../contexts/socket_client_context'; +import '@cloudscape-design/global-styles/index.css'; +import { + Button, + Container, + Header, + Spinner, + Table, + TextContent, + Box, + SpaceBetween, + ExpandableSection, + StatusIndicator, + Input, + FormField, + Grid, + Multiselect, + SelectProps, + Modal, +} from '@cloudscape-design/components'; +import { SandboxStatus } from '@aws-amplify/sandbox'; + +interface ResourceConsoleProps { + sandboxStatus?: SandboxStatus; +} + +// Define column definitions type +type ColumnDefinition = { + id: string; + header: string; + cell: (item: ResourceWithFriendlyName) => React.ReactNode; + width: number; + minWidth: number; +}; + +const ResourceConsole: React.FC = ({ + sandboxStatus = 'unknown', +}) => { + const [lastRefreshTime, setLastRefreshTime] = useState(0); + const deploymentInProgress = sandboxStatus === 'deploying'; + const [initializing, setInitializing] = useState(true); + const [editingResource, setEditingResource] = + useState(null); + const [editingFriendlyName, setEditingFriendlyName] = useState(''); + const REFRESH_COOLDOWN_MS = 5000; // 5 seconds minimum between refreshes + + // Use the resource manager hook + const { + resources, + isLoading, + error, + region, + updateCustomFriendlyName, + removeCustomFriendlyName, + getResourceDisplayName, + refreshResources: originalRefreshResources, + } = useResourceManager(undefined, sandboxStatus); + + // Get the resource client service + const resourceClientService = useResourceClientService(); + + // Define column definitions for all tables + const columnDefinitions = React.useMemo( + () => [ + { + id: 'name', + header: 'Resource Name', + cell: (item: ResourceWithFriendlyName) => { + return ( + +
+ {getResourceDisplayName(item)} +
+
+ ); + }, + width: 600, + minWidth: 200, + }, + { + id: 'logicalId', + header: 'Logical ID', + cell: (item: ResourceWithFriendlyName) => item.logicalResourceId, + width: 600, + minWidth: 200, + }, + { + id: 'status', + header: 'Status', + cell: (item: ResourceWithFriendlyName) => ( + + + + {getStatusType(item.resourceStatus)} + + + + ), + width: 200, + minWidth: 200, + }, + { + id: 'physicalId', + header: 'Physical ID', + cell: (item: ResourceWithFriendlyName) => item.physicalResourceId, + width: 600, + minWidth: 300, + }, + { + id: 'actions', + header: 'Actions', + cell: (item: ResourceWithFriendlyName) => { + const url = item.consoleUrl; + + return ( + + {url && + (deploymentInProgress ? ( + + View in AWS Console (disabled during deployment) + + ) : ( + + ))} + + ); + }, + width: 250, + minWidth: 250, + }, + ], + [deploymentInProgress], + ); + + // Empty state for tables + const emptyState = ( + + + +

No resources found

+
+
+
+ ); + + // Clear initializing state after a timeout or when resources are loaded + useEffect(() => { + const timer = setTimeout(() => { + setInitializing(false); + }, 3000); // Give it 3 seconds to initialize + + if (resources) { + setInitializing(false); + } + + return () => clearTimeout(timer); + }, [resources]); + + const refreshResources = React.useCallback(() => { + const now = Date.now(); + if (now - lastRefreshTime < REFRESH_COOLDOWN_MS) { + console.log( + 'ResourceConsole: Refresh cooldown in effect, skipping refresh', + ); + return; + } + + console.log('ResourceConsole: Refreshing resources'); + originalRefreshResources(); + setLastRefreshTime(now); + }, [originalRefreshResources, lastRefreshTime, REFRESH_COOLDOWN_MS]); + + const [searchQuery, setSearchQuery] = useState(''); + const [selectedServiceTypes, setSelectedServiceTypes] = useState< + readonly SelectProps.Option[] + >([]); + const [selectedStatuses, setSelectedStatuses] = useState< + readonly SelectProps.Option[] + >([]); + + // Extract all unique resource types and statuses for filter options + const serviceTypeOptions = useMemo(() => { + if (!resources) return []; + + const types = new Set(); + resources.forEach((resource: ResourceWithFriendlyName) => { + if (resource.resourceType !== 'AWS::CDK::Metadata') { + types.add(resource.resourceType); + } + }); + + return Array.from(types).map((type) => ({ label: type, value: type })); + }, [resources, sandboxStatus]); + + const statusOptions = useMemo(() => { + if (!resources) return []; + + const statuses = new Set(); + resources.forEach((resource: ResourceWithFriendlyName) => { + statuses.add(resource.resourceStatus); + }); + + return Array.from(statuses).map((status) => ({ + label: status, + value: status, + })); + }, [resources]); + + // Extract service name from resource type (e.g., "Lambda" from "AWS::Lambda::Function") + const getServiceName = (resourceType: string): string => { + const parts = resourceType.split('::'); + return parts.length >= 2 ? parts[1] : resourceType; + }; + + // Get a friendly resource type name without the AWS:: prefix + const getFriendlyResourceType = (resourceType: string): string => { + const parts = resourceType.split('::'); + if (parts.length == 3) { + return `${parts[1]} ${parts[2]}`; + } else if (parts.length > 3) { + return `${parts[1]} ${parts[2]} ${parts[3]}`; + } + return resourceType; + }; + + // Handle editing a resource's friendly name + const handleEditFriendlyName = (resource: ResourceWithFriendlyName) => { + setEditingResource(resource); + setEditingFriendlyName(getResourceDisplayName(resource)); + }; + + const refreshFriendlyNames = () => { + resourceClientService.getCustomFriendlyNames(); + }; + + const handleSaveFriendlyName = () => { + if (editingResource) { + updateCustomFriendlyName( + editingResource.physicalResourceId, + editingFriendlyName, + ); + + setEditingResource(null); + + refreshFriendlyNames(); + } + }; + + const handleRemoveFriendlyName = () => { + if (editingResource) { + removeCustomFriendlyName(editingResource.physicalResourceId); + + setEditingResource(null); + + refreshFriendlyNames(); + } + }; + + // Filter resources based on search query and selected filters + const filteredResources = useMemo(() => { + if (!resources) return []; + + return resources.filter((resource: ResourceWithFriendlyName) => { + // Filter out CDK metadata + if (resource.resourceType === 'AWS::CDK::Metadata') return false; + + // Apply search filter + const searchLower = searchQuery.toLowerCase(); + const matchesSearch = + searchQuery === '' || + resource.logicalResourceId.toLowerCase().includes(searchLower) || + resource.physicalResourceId.toLowerCase().includes(searchLower) || + getResourceDisplayName(resource).toLowerCase().includes(searchLower) || + resource.resourceType.toLowerCase().includes(searchLower); + + const matchesServiceType = + selectedServiceTypes.length === 0 || + selectedServiceTypes.some( + (option) => option.value === resource.resourceType, + ); + + const matchesStatus = + selectedStatuses.length === 0 || + selectedStatuses.some( + (option) => option.value === resource.resourceStatus, + ); + + return matchesSearch && matchesServiceType && matchesStatus; + }); + }, [ + resources, + searchQuery, + selectedServiceTypes, + selectedStatuses, + getResourceDisplayName, + ]); + + // Group filtered resources by service and then by resource type + const groupedResources = useMemo(() => { + const serviceGroups: Record< + string, + Record + > = {}; + + filteredResources.forEach((resource: ResourceWithFriendlyName) => { + const service = getServiceName(resource.resourceType); + const resourceType = getFriendlyResourceType(resource.resourceType); + + if (!serviceGroups[service]) { + serviceGroups[service] = {}; + } + + if (!serviceGroups[service][resourceType]) { + serviceGroups[service][resourceType] = []; + } + + serviceGroups[service][resourceType].push(resource); + }); + + return serviceGroups; + }, [filteredResources]); + + const getStatusType = ( + status: string, + ): + | 'Deployed' + | 'Failed' + | 'Deleted' + | 'Deleting' + | 'Deploying' + | 'Unknown' => { + if (status.includes('DEPLOYED')) return 'Deployed'; + if (status.includes('FAILED')) return 'Failed'; + if (status.includes('DELETED')) return 'Deleted'; + if (status.includes('DELETING')) return 'Deleting'; + if (status.includes('DEPLOYING')) return 'Deploying'; + return 'Unknown'; // Default for unknown status types + }; + + const regionAvailable = region !== null; + + // Check for nonexistent sandbox first, before showing loading spinner + if (sandboxStatus === 'nonexistent') { + return ( + + + + No sandbox exists + +

+ You need to create a sandbox first. Use the Start Sandbox button + in the header. +

+
+
+
+
+ ); + } + + // Show loading spinner during initialization or when loading resources for the first time + if ( + (initializing || (isLoading && (!resources || resources.length === 0))) && + !deploymentInProgress + ) { + return ( + + + + + +

+ {initializing + ? 'Initializing DevTools and loading resources...' + : 'Loading resources...'} +

+
+
+
+
+ ); + } + + if (sandboxStatus === 'deploying' || deploymentInProgress) { + // Show a loading state but still display resources if available + return ( + + + + + Sandbox is deploying + + +

+ The sandbox is currently being deployed. This may take a few + minutes. +

+ {resources && resources.length > 0 && ( +

Showing resources from the previous deployment.

+ )} +
+ +
+ + {/* Show resources if available, even during deployment */} + {resources && resources.length > 0 && ( + + )} +
+
+ ); + } + + if (error) { + return ( + + + + Error: {error} + + + + + ); + } + + if (!resources || resources.length === 0) { + return ( + + + + +

No resources found.

+
+ +
+
+
+ ); + } + + // Main render with split-screen layout + return ( + + {/* Friendly Name Edit Modal */} + setEditingResource(null)} + header="Edit Resource Name" + footer={ + + + + + + + + } + > + + +
{editingResource?.physicalResourceId}
+
+ +
{editingResource?.resourceType}
+
+ + setEditingFriendlyName(detail.value)} + /> + +
+
+ +
+ Refresh + + } + > + Deployed Resources +
+ + {!regionAvailable && ( + + AWS region could not be detected. Console links are unavailable. + + )} + + {/* Warning banner for stopped state */} + {sandboxStatus === 'stopped' && ( + + Sandbox is stopped + +

+ The sandbox is currently stopped. Use the Start Sandbox button + in the header to start it. +

+

Showing resources from the most recent deployment.

+
+ +
+ )} + + {/* Full width layout for resources */} + + {/* Left side - Resources */} +
+ + + setSearchQuery(detail.value)} + placeholder="Search by ID, type, or status..." + /> + + + + + + setSelectedServiceTypes(detail.selectedOptions) + } + options={serviceTypeOptions} + placeholder="Select service types" + filteringType="auto" + /> + + + + + setSelectedStatuses(detail.selectedOptions) + } + options={statusOptions} + placeholder="Select statuses" + filteringType="auto" + /> + + + + + {Object.entries(groupedResources).map( + ([serviceName, resourceTypes]) => ( + + + {Object.entries(resourceTypes).map( + ([resourceType, resources]) => ( + +
+ + ), + )} + + + ), + )} + + + {/* Log viewer will be added in PR 3 */} + + + + ); +}; + +interface ResourceDisplayProps { + groupedResources: Record>; + columnDefinitions: ColumnDefinition[]; + emptyState: React.ReactNode; + refreshResources: () => void; + regionAvailable: boolean; +} + +const ResourceDisplay: React.FC = ({ + groupedResources, + columnDefinitions, + emptyState, + refreshResources, + regionAvailable, +}) => { + return ( + +
+ Refresh + + } + > + Deployed Resources +
+ + {!regionAvailable && ( + + AWS region could not be detected. Console links are unavailable. + + )} + + {Object.entries(groupedResources).map(([serviceName, resourceTypes]) => ( + + + {Object.entries(resourceTypes).map(([resourceType, resources]) => ( + +
+ + ))} + + + ))} + + ); +}; + +export default ResourceConsole; diff --git a/packages/cli/src/commands/sandbox/sandbox-devtools/react-app/src/components/SandboxOptionsModal.tsx b/packages/cli/src/commands/sandbox/sandbox-devtools/react-app/src/components/SandboxOptionsModal.tsx new file mode 100644 index 00000000000..89c4a937aea --- /dev/null +++ b/packages/cli/src/commands/sandbox/sandbox-devtools/react-app/src/components/SandboxOptionsModal.tsx @@ -0,0 +1,216 @@ +import React, { useState } from 'react'; +import { + Modal, + Box, + SpaceBetween, + Button, + FormField, + Input, + Header, + Checkbox, + Select, +} from '@cloudscape-design/components'; +import { DevToolsSandboxOptions } from '../../../shared/socket_types'; + +interface SandboxOptionsModalProps { + visible: boolean; + onDismiss: () => void; + onConfirm: (options: DevToolsSandboxOptions) => void; +} + +/** + * SandboxOptionsModal component allows users to configure sandbox settings + * + * NOTE: Type Handling + * This component uses DevToolsSandboxOptions from shared/socket_types.ts which is + * designed to be compatible with socket communication. The key differences from + * the actual @aws-amplify/sandbox SandboxOptions type are: + * + * 1. Different property names (e.g., 'dirToWatch' here vs 'dir' in the actual SandboxOptions) + * 2. The 'exclude' and 'logsFilter' are passed as strings rather than string arrays + * 3. We cannot use ClientConfigFormat directly in the React app + * + * The conversion between these types happens in the socket_handlers.ts file + * which processes these fields before passing them to the sandbox. + */ +const SandboxOptionsModal: React.FC = ({ + visible, + onDismiss, + onConfirm, +}) => { + const [identifier, setIdentifier] = useState(''); + const [dirToWatch, setDirToWatch] = useState('./amplify'); + const [excludeInput, setExcludeInput] = useState(''); + const [outputsFormat, setOutputsFormat] = useState(''); + const [once, setOnce] = useState(false); + const [streamFunctionLogs, setStreamFunctionLogs] = useState(false); + const [logsFilterInput, setLogsFilterInput] = useState(''); + const [logsOutFile, setLogsOutFile] = useState(''); + + const handleConfirm = () => { + const options: DevToolsSandboxOptions = {}; + + if (identifier.trim()) { + options.identifier = identifier.trim(); + } + + if (dirToWatch.trim() && dirToWatch !== './amplify') { + options.dirToWatch = dirToWatch.trim(); + } + + if (excludeInput.trim()) { + options.exclude = excludeInput.trim(); + } + + if (outputsFormat) { + options.outputsFormat = outputsFormat; + } + + if (once) { + options.once = true; + } + + if (streamFunctionLogs) { + options.streamFunctionLogs = true; + + if (logsFilterInput.trim()) { + options.logsFilter = logsFilterInput.trim(); + } + + if (logsOutFile.trim()) { + options.logsOutFile = logsOutFile.trim(); + } + } + + onConfirm(options); + }; + + return ( + Sandbox Options} + size="large" + footer={ + + + + + + + } + > + + + setIdentifier(detail.value)} + placeholder="e.g., my-sandbox" + /> + + + + setDirToWatch(detail.value)} + placeholder="./amplify" + /> + + + + setExcludeInput(detail.value)} + placeholder="e.g., node_modules,dist" + /> + + + + setLogsFilterInput(detail.value)} + placeholder="e.g., auth,api" + /> + + + + setLogsOutFile(detail.value)} + placeholder="e.g., ./logs/function-logs.txt" + /> + + + )} + + + ); +}; + +export default SandboxOptionsModal; diff --git a/packages/cli/src/commands/sandbox/sandbox-devtools/react-app/src/contexts/socket_client_context.tsx b/packages/cli/src/commands/sandbox/sandbox-devtools/react-app/src/contexts/socket_client_context.tsx new file mode 100644 index 00000000000..464d3edc7de --- /dev/null +++ b/packages/cli/src/commands/sandbox/sandbox-devtools/react-app/src/contexts/socket_client_context.tsx @@ -0,0 +1,91 @@ +import React, { createContext, useContext, ReactNode } from 'react'; +import { SocketClientService } from '../services/socket_client_service'; +import { SandboxClientService } from '../services/sandbox_client_service'; +import { ResourceClientService } from '../services/resource_client_service'; + +/** + * Interface for socket client services + */ +interface SocketClientServices { + socketClientService: SocketClientService; + sandboxClientService: SandboxClientService; + resourceClientService: ResourceClientService; +} + +/** + * Context for socket client services + */ +const SocketClientContext = createContext(null); + +/** + * Props for SocketClientProvider + */ +interface SocketClientProviderProps { + children: ReactNode; +} + +/** + * Provider for socket client services + */ +export const SocketClientProvider: React.FC = ({ + children, +}) => { + // Create singleton instances of each service + const socketClientService = new SocketClientService(); + const sandboxClientService = new SandboxClientService(); + const resourceClientService = new ResourceClientService(); + + const services: SocketClientServices = { + socketClientService, + sandboxClientService, + resourceClientService, + }; + + return ( + + {children} + + ); +}; + +/** + * Hook to access the socket client service + * @returns The socket client service + */ +export const useSocketClientService = (): SocketClientService => { + const context = useContext(SocketClientContext); + if (!context) { + throw new Error( + 'useSocketClientService must be used within a SocketClientProvider', + ); + } + return context.socketClientService; +}; + +/** + * Hook to access the sandbox client service + * @returns The sandbox client service + */ +export const useSandboxClientService = (): SandboxClientService => { + const context = useContext(SocketClientContext); + if (!context) { + throw new Error( + 'useSandboxClientService must be used within a SocketClientProvider', + ); + } + return context.sandboxClientService; +}; + +/** + * Hook to access the resource client service + * @returns The resource client service + */ +export const useResourceClientService = (): ResourceClientService => { + const context = useContext(SocketClientContext); + if (!context) { + throw new Error( + 'useResourceClientService must be used within a SocketClientProvider', + ); + } + return context.resourceClientService; +}; diff --git a/packages/cli/src/commands/sandbox/sandbox-devtools/react-app/src/hooks/useResourceManager.ts b/packages/cli/src/commands/sandbox/sandbox-devtools/react-app/src/hooks/useResourceManager.ts new file mode 100644 index 00000000000..de4423b92bf --- /dev/null +++ b/packages/cli/src/commands/sandbox/sandbox-devtools/react-app/src/hooks/useResourceManager.ts @@ -0,0 +1,194 @@ +import { useState, useEffect, useCallback } from 'react'; +import { SandboxStatus } from '@aws-amplify/sandbox'; +import { useResourceClientService } from '../contexts/socket_client_context'; +import { + ResourceWithFriendlyName, + BackendResourcesData, +} from '../services/resource_client_service'; + +/** + * Hook for managing backend resources + * @param onResourcesLoaded Callback function called when resources are loaded + * @param sandboxStatus The current sandbox status + * @returns The resource manager state and functions + */ +export const useResourceManager = ( + onResourcesLoaded?: (data: BackendResourcesData) => void, + sandboxStatus?: SandboxStatus, +) => { + const resourceClientService = useResourceClientService(); + const [resources, setResources] = useState([]); + const [isLoading, setIsLoading] = useState(false); + const [error, setError] = useState(null); + const [customFriendlyNames, setCustomFriendlyNames] = useState< + Record + >({}); + const [region, setRegion] = useState(null); + const [backendName, setBackendName] = useState(''); + + useEffect(() => { + // Add a small random delay on initial load to prevent all tabs from requesting at the same time + const initialDelay = Math.random() * 2000; // Random delay between 0-2000ms + + const loadResources = () => { + setIsLoading(true); + setError(null); + + resourceClientService.getCustomFriendlyNames(); + resourceClientService.getSavedResources(); + resourceClientService.getDeployedBackendResources(); + }; + + // Apply initial delay to prevent thundering herd problem when multiple tabs reconnect + setTimeout(loadResources, initialDelay); + + const handleSavedResources = (data: BackendResourcesData) => { + if (data && data.resources) { + setResources(data.resources); + setRegion(data.region); + setBackendName(data.name || ''); + + if (onResourcesLoaded) { + onResourcesLoaded(data); + } + } + }; + + // Listen for deployed backend resources + const handleDeployedBackendResources = (data: BackendResourcesData) => { + setIsLoading(false); + + if (data && data.resources) { + setResources(data.resources); + setRegion(data.region); + setBackendName(data.name || ''); + + if (onResourcesLoaded) { + onResourcesLoaded(data); + } + } else if (data && data.message) { + setError(data.message); + } + }; + + // Listen for custom friendly names + const handleCustomFriendlyNames = (data: Record) => { + setCustomFriendlyNames(data || {}); + }; + + // Listen for custom friendly name updates + const handleCustomFriendlyNameUpdated = (data: { + resourceId: string; + friendlyName: string; + }) => { + setCustomFriendlyNames((prev) => ({ + ...prev, + [data.resourceId]: data.friendlyName, + })); + }; + + // Listen for custom friendly name removals + const handleCustomFriendlyNameRemoved = (data: { resourceId: string }) => { + setCustomFriendlyNames((prev) => { + const newNames = { ...prev }; + delete newNames[data.resourceId]; + return newNames; + }); + }; + + // Listen for errors + const handleError = (data: { message: string }) => { + setIsLoading(false); + setError(data.message); + }; + + // Register event handlers + const unsubscribeSavedResources = + resourceClientService.onSavedResources(handleSavedResources); + const unsubscribeDeployedBackendResources = + resourceClientService.onDeployedBackendResources( + handleDeployedBackendResources, + ); + const unsubscribeCustomFriendlyNames = + resourceClientService.onCustomFriendlyNames(handleCustomFriendlyNames); + const unsubscribeCustomFriendlyNameUpdated = + resourceClientService.onCustomFriendlyNameUpdated( + handleCustomFriendlyNameUpdated, + ); + const unsubscribeCustomFriendlyNameRemoved = + resourceClientService.onCustomFriendlyNameRemoved( + handleCustomFriendlyNameRemoved, + ); + const unsubscribeError = resourceClientService.onError(handleError); + + // Cleanup function to unsubscribe from events + return () => { + unsubscribeSavedResources.unsubscribe(); + unsubscribeDeployedBackendResources.unsubscribe(); + unsubscribeCustomFriendlyNames.unsubscribe(); + unsubscribeCustomFriendlyNameUpdated.unsubscribe(); + unsubscribeCustomFriendlyNameRemoved.unsubscribe(); + unsubscribeError.unsubscribe(); + }; + }, [resourceClientService, sandboxStatus, onResourcesLoaded]); + + /** + * Updates a custom friendly name for a resource + * @param resourceId The resource ID + * @param friendlyName The friendly name + */ + const updateCustomFriendlyName = ( + resourceId: string, + friendlyName: string, + ) => { + resourceClientService.updateCustomFriendlyName(resourceId, friendlyName); + }; + + /** + * Removes a custom friendly name for a resource + * @param resourceId The resource ID + */ + const removeCustomFriendlyName = (resourceId: string) => { + resourceClientService.removeCustomFriendlyName(resourceId); + }; + + /** + * Gets the display name for a resource + * @param resource The resource + * @returns The display name + */ + const getResourceDisplayName = useCallback( + (resource: ResourceWithFriendlyName): string => { + // Check if there's a custom friendly name + if (customFriendlyNames[resource.physicalResourceId]) { + return customFriendlyNames[resource.physicalResourceId]; + } + + // Otherwise use the friendly name or logical ID + return resource.friendlyName || resource.logicalResourceId; + }, + [customFriendlyNames], + ); + + /** + * Refreshes the resources + */ + const refreshResources = () => { + setIsLoading(true); + setError(null); + resourceClientService.getDeployedBackendResources(); + }; + + return { + resources, + isLoading, + error, + customFriendlyNames, + region, + backendName, + updateCustomFriendlyName, + removeCustomFriendlyName, + getResourceDisplayName, + refreshResources, + }; +}; diff --git a/packages/cli/src/commands/sandbox/sandbox-devtools/react-app/src/main.tsx b/packages/cli/src/commands/sandbox/sandbox-devtools/react-app/src/main.tsx index 95ad22cdba7..c018515cd7f 100644 --- a/packages/cli/src/commands/sandbox/sandbox-devtools/react-app/src/main.tsx +++ b/packages/cli/src/commands/sandbox/sandbox-devtools/react-app/src/main.tsx @@ -1,7 +1,6 @@ import React from 'react'; import ReactDOM from 'react-dom/client'; import App from './App'; -import '../index.css'; ReactDOM.createRoot(document.getElementById('root')!).render( diff --git a/packages/cli/src/commands/sandbox/sandbox-devtools/react-app/src/services/resource_client_service.ts b/packages/cli/src/commands/sandbox/sandbox-devtools/react-app/src/services/resource_client_service.ts new file mode 100644 index 00000000000..75d8e14f45c --- /dev/null +++ b/packages/cli/src/commands/sandbox/sandbox-devtools/react-app/src/services/resource_client_service.ts @@ -0,0 +1,140 @@ +import { SocketClientService } from './socket_client_service'; +import { SOCKET_EVENTS } from '../../../shared/socket_events'; + +/** + * Type for a resource with friendly name + */ +export interface ResourceWithFriendlyName { + logicalResourceId: string; + physicalResourceId: string; + resourceType: string; + resourceStatus: string; + friendlyName?: string; + consoleUrl?: string | null; +} + +/** + * Type for backend resources data + */ +export interface BackendResourcesData { + name: string; + status: string; + resources: ResourceWithFriendlyName[]; + region: string | null; + message?: string; +} + +/** + * Service for handling resource-related socket communication + */ +export class ResourceClientService extends SocketClientService { + /** + * Requests custom friendly names from the server + */ + public getCustomFriendlyNames(): void { + this.emit(SOCKET_EVENTS.GET_CUSTOM_FRIENDLY_NAMES); + } + + /** + * Requests saved resources from the server + */ + public getSavedResources(): void { + this.emit(SOCKET_EVENTS.GET_SAVED_RESOURCES); + } + + /** + * Requests deployed backend resources from the server + */ + public getDeployedBackendResources(): void { + this.emit(SOCKET_EVENTS.GET_DEPLOYED_BACKEND_RESOURCES); + } + + /** + * Updates a custom friendly name for a resource + * @param resourceId The resource ID + * @param friendlyName The friendly name + */ + public updateCustomFriendlyName( + resourceId: string, + friendlyName: string, + ): void { + this.emit(SOCKET_EVENTS.UPDATE_CUSTOM_FRIENDLY_NAME, { + resourceId, + friendlyName, + }); + } + + /** + * Removes a custom friendly name for a resource + * @param resourceId The resource ID + */ + public removeCustomFriendlyName(resourceId: string): void { + this.emit(SOCKET_EVENTS.REMOVE_CUSTOM_FRIENDLY_NAME, { resourceId }); + } + + /** + * Registers a handler for saved resources events + * @param handler The event handler + * @returns A function to unsubscribe + */ + public onSavedResources(handler: (data: BackendResourcesData) => void): { + unsubscribe: () => void; + } { + return this.on(SOCKET_EVENTS.SAVED_RESOURCES, handler); + } + + /** + * Registers a handler for deployed backend resources events + * @param handler The event handler + * @returns A function to unsubscribe + */ + public onDeployedBackendResources( + handler: (data: BackendResourcesData) => void, + ): { unsubscribe: () => void } { + return this.on(SOCKET_EVENTS.DEPLOYED_BACKEND_RESOURCES, handler); + } + + /** + * Registers a handler for custom friendly names events + * @param handler The event handler + * @returns A function to unsubscribe + */ + public onCustomFriendlyNames( + handler: (data: Record) => void, + ): { unsubscribe: () => void } { + return this.on(SOCKET_EVENTS.CUSTOM_FRIENDLY_NAMES, handler); + } + + /** + * Registers a handler for custom friendly name updated events + * @param handler The event handler + * @returns A function to unsubscribe + */ + public onCustomFriendlyNameUpdated( + handler: (data: { resourceId: string; friendlyName: string }) => void, + ): { unsubscribe: () => void } { + return this.on(SOCKET_EVENTS.CUSTOM_FRIENDLY_NAME_UPDATED, handler); + } + + /** + * Registers a handler for custom friendly name removed events + * @param handler The event handler + * @returns A function to unsubscribe + */ + public onCustomFriendlyNameRemoved( + handler: (data: { resourceId: string }) => void, + ): { unsubscribe: () => void } { + return this.on(SOCKET_EVENTS.CUSTOM_FRIENDLY_NAME_REMOVED, handler); + } + + /** + * Registers a handler for error events + * @param handler The event handler + * @returns A function to unsubscribe + */ + public onError(handler: (data: { message: string }) => void): { + unsubscribe: () => void; + } { + return this.on(SOCKET_EVENTS.ERROR, handler); + } +} diff --git a/packages/cli/src/commands/sandbox/sandbox-devtools/react-app/src/services/sandbox_client_service.ts b/packages/cli/src/commands/sandbox/sandbox-devtools/react-app/src/services/sandbox_client_service.ts new file mode 100644 index 00000000000..c9501a308b3 --- /dev/null +++ b/packages/cli/src/commands/sandbox/sandbox-devtools/react-app/src/services/sandbox_client_service.ts @@ -0,0 +1,98 @@ +import { SocketClientService } from './socket_client_service'; +import { SOCKET_EVENTS } from '../../../shared/socket_events'; +import { SandboxStatus } from '@aws-amplify/sandbox'; +import { DevToolsSandboxOptions } from '../../../shared/socket_types'; + +/** + * Interface for sandbox status data + */ +export interface SandboxStatusData { + status: SandboxStatus; + error?: string; + identifier?: string; + stackStatus?: string; + deploymentCompleted?: boolean; + message?: string; + timestamp?: string; +} + +/** + * Service for handling sandbox-related socket communication + */ +export class SandboxClientService extends SocketClientService { + /** + * Requests the current sandbox status + */ + public getSandboxStatus(): void { + this.emit(SOCKET_EVENTS.GET_SANDBOX_STATUS); + } + + /** + * Starts the sandbox with the specified options + * @param options The sandbox options + */ + public startSandboxWithOptions(options: DevToolsSandboxOptions): void { + this.emit(SOCKET_EVENTS.START_SANDBOX_WITH_OPTIONS, options); + } + + /** + * Stops the sandbox + */ + public stopSandbox(): void { + this.emit(SOCKET_EVENTS.STOP_SANDBOX); + } + + /** + * Deletes the sandbox + */ + public deleteSandbox(): void { + this.emit(SOCKET_EVENTS.DELETE_SANDBOX); + } + + /** + * Stops the DevTools process + */ + public stopDevTools(): void { + this.emit(SOCKET_EVENTS.STOP_DEV_TOOLS); + } + + /** + * Registers a handler for sandbox status events + * @param handler The event handler + * @returns An object with an unsubscribe method + */ + public onSandboxStatus(handler: (data: SandboxStatusData) => void): { + unsubscribe: () => void; + } { + return this.on(SOCKET_EVENTS.SANDBOX_STATUS, handler); + } + + /** + * Gets saved deployment progress + */ + public getSavedDeploymentProgress(): void { + this.emit(SOCKET_EVENTS.GET_SAVED_DEPLOYMENT_PROGRESS); + } + + /** + * Gets log settings + */ + public getLogSettings(): void { + this.emit(SOCKET_EVENTS.GET_LOG_SETTINGS); + } + + /** + * Registers a handler for log events + * @param handler The event handler + * @returns An object with an unsubscribe method + */ + public onLog( + handler: (data: { + timestamp: string; + level: string; + message: string; + }) => void, + ): { unsubscribe: () => void } { + return this.on('log', handler); + } +} diff --git a/packages/cli/src/commands/sandbox/sandbox-devtools/react-app/src/services/socket_client_service.ts b/packages/cli/src/commands/sandbox/sandbox-devtools/react-app/src/services/socket_client_service.ts new file mode 100644 index 00000000000..d08506d82b7 --- /dev/null +++ b/packages/cli/src/commands/sandbox/sandbox-devtools/react-app/src/services/socket_client_service.ts @@ -0,0 +1,318 @@ +import { io, Socket } from 'socket.io-client'; + +type ConnectionHandler = () => void; +type ErrorHandler = (error: Error) => void; + +/** + * Base service for handling client-side socket communication + */ +export class SocketClientService { + protected socket: Socket | null = null; + private requestBackoffTimer: number = 0; + private lastRequestTime: number = 0; + private requestQueue: Array<() => void> = []; + private processingQueue: boolean = false; + private tabId: string = Math.random().toString(36).substring(2, 10); + + /** + * Creates a new SocketClientService + */ + constructor() { + this.initialize(); + } + + /** + * Initializes the socket connection + */ + private initialize(): void { + const currentUrl = window.location.origin; + console.log( + `Connecting to socket at: ${currentUrl} (Tab ID: ${this.tabId})`, + ); + + this.socket = io(currentUrl, { + reconnectionAttempts: 10, + reconnectionDelay: 1000, // Start with 1s delay + reconnectionDelayMax: 10000, // Max delay of 10s + randomizationFactor: 0.5, // Add randomization to prevent all clients reconnecting at the same time + timeout: 10000, + }); + } + + /** + * Checks if the socket is connected + * @returns Whether the socket is connected + */ + public isConnected(): boolean { + return this.socket?.connected || false; + } + + /** + * Disconnects the socket + */ + public disconnect(): void { + this.socket?.disconnect(); + } + + /** + * Registers a handler for connection events + * @param handler The event handler + * @returns A function to unsubscribe + */ + /** + * Registers a handler for connection events + * @param handler The event handler + * @returns An object with an unsubscribe method + */ + public onConnect(handler: ConnectionHandler): { unsubscribe: () => void } { + if (!this.socket) return { unsubscribe: () => {} }; + this.socket.on('connect', handler); + return { unsubscribe: () => this.socket?.off('connect', handler) }; + } + + /** + * Registers a handler for disconnection events + * @param handler The event handler + * @returns A function to unsubscribe + */ + /** + * Registers a handler for disconnection events + * @param handler The event handler + * @returns An object with an unsubscribe method + */ + public onDisconnect(handler: (reason: string) => void): { + unsubscribe: () => void; + } { + if (!this.socket) return { unsubscribe: () => {} }; + this.socket.on('disconnect', handler); + return { unsubscribe: () => this.socket?.off('disconnect', handler) }; + } + + /** + * Registers a handler for connection error events + * @param handler The event handler + * @returns A function to unsubscribe + */ + /** + * Registers a handler for connection error events + * @param handler The event handler + * @returns An object with an unsubscribe method + */ + public onConnectError(handler: ErrorHandler): { unsubscribe: () => void } { + if (!this.socket) return { unsubscribe: () => {} }; + this.socket.on('connect_error', handler); + return { unsubscribe: () => this.socket?.off('connect_error', handler) }; + } + + /** + * Registers a handler for connection timeout events + * @param handler The event handler + * @returns A function to unsubscribe + */ + /** + * Registers a handler for connection timeout events + * @param handler The event handler + * @returns An object with an unsubscribe method + */ + public onConnectTimeout(handler: ConnectionHandler): { + unsubscribe: () => void; + } { + if (!this.socket) return { unsubscribe: () => {} }; + this.socket.on('connect_timeout', handler); + return { unsubscribe: () => this.socket?.off('connect_timeout', handler) }; + } + + /** + * Registers a handler for reconnection events + * @param handler The event handler + * @returns A function to unsubscribe + */ + /** + * Registers a handler for reconnection events + * @param handler The event handler + * @returns An object with an unsubscribe method + */ + public onReconnect(handler: (attempt: number) => void): { + unsubscribe: () => void; + } { + if (!this.socket) return { unsubscribe: () => {} }; + this.socket.on('reconnect', handler); + return { unsubscribe: () => this.socket?.off('reconnect', handler) }; + } + + /** + * Registers a handler for reconnection attempt events + * @param handler The event handler + * @returns A function to unsubscribe + */ + /** + * Registers a handler for reconnection attempt events + * @param handler The event handler + * @returns An object with an unsubscribe method + */ + public onReconnectAttempt(handler: (attempt: number) => void): { + unsubscribe: () => void; + } { + if (!this.socket) return { unsubscribe: () => {} }; + this.socket.on('reconnect_attempt', handler); + return { + unsubscribe: () => this.socket?.off('reconnect_attempt', handler), + }; + } + + /** + * Registers a handler for reconnection error events + * @param handler The event handler + * @returns A function to unsubscribe + */ + /** + * Registers a handler for reconnection error events + * @param handler The event handler + * @returns An object with an unsubscribe method + */ + public onReconnectError(handler: ErrorHandler): { unsubscribe: () => void } { + if (!this.socket) return { unsubscribe: () => {} }; + this.socket.on('reconnect_error', handler); + return { unsubscribe: () => this.socket?.off('reconnect_error', handler) }; + } + + /** + * Registers a handler for reconnection failed events + * @param handler The event handler + * @returns A function to unsubscribe + */ + /** + * Registers a handler for reconnection failed events + * @param handler The event handler + * @returns An object with an unsubscribe method + */ + public onReconnectFailed(handler: ConnectionHandler): { + unsubscribe: () => void; + } { + if (!this.socket) return { unsubscribe: () => {} }; + this.socket.on('reconnect_failed', handler); + return { unsubscribe: () => this.socket?.off('reconnect_failed', handler) }; + } + + /** + * Starts a periodic ping to check connection health + * @param interval The ping interval in milliseconds + * @returns A function to stop the ping + */ + /** + * Starts a periodic ping to check connection health + * @param interval The ping interval in milliseconds + * @returns An object with an unsubscribe method to stop the ping + */ + public startPingInterval(interval: number = 30000): { + unsubscribe: () => void; + } { + if (!this.socket) return { unsubscribe: () => {} }; + + const pingInterval = setInterval(() => { + if (this.socket?.connected) { + this.socket.emit( + 'ping', + {}, + (response: { error?: string } | undefined) => { + if (!response || response.error) { + console.warn('Ping failed:', response?.error || 'No response'); + } + }, + ); + } + }, interval); + + return { unsubscribe: () => clearInterval(pingInterval) }; + } + + /** + * Adds a request to the queue with exponential backoff + * @param request The request function to queue + */ + private queueRequest(request: () => void): void { + this.requestQueue.push(request); + this.processQueue(); + } + + /** + * Processes the request queue with exponential backoff + */ + private processQueue(): void { + if (this.processingQueue || this.requestQueue.length === 0) return; + + this.processingQueue = true; + const now = Date.now(); + const timeSinceLastRequest = now - this.lastRequestTime; + + // If we've waited long enough, process the next request + if (timeSinceLastRequest >= this.requestBackoffTimer) { + const request = this.requestQueue.shift(); + if (request) { + this.lastRequestTime = now; + // Increase backoff time for next request (max 5 seconds) + this.requestBackoffTimer = Math.min( + 5000, + Math.max(200, this.requestBackoffTimer * 1.5), + ); + request(); + + // Reset backoff after 10 seconds of no requests + setTimeout(() => { + if (Date.now() - this.lastRequestTime >= 10000) { + this.requestBackoffTimer = 0; + } + }, 10000); + } + + this.processingQueue = false; + if (this.requestQueue.length > 0) { + setTimeout(() => this.processQueue(), this.requestBackoffTimer); + } + } else { + const waitTime = this.requestBackoffTimer - timeSinceLastRequest; + setTimeout(() => { + this.processingQueue = false; + this.processQueue(); + }, waitTime); + } + } + + /** + * Emits an event to the server with exponential backoff + * @param event The event name + * @param data The event data + */ + protected emit(event: string, data?: T): void { + if (!this.socket) { + throw new Error(`Cannot emit ${event}: Socket is not initialized`); + } + + // Queue the emit request with exponential backoff + this.queueRequest(() => { + console.log(`[Tab ${this.tabId}] Emitting ${event}`); + this.socket?.emit(event, data); + }); + } + + /** + * Registers a handler for an event + * @param event The event name + * @param handler The event handler + * @returns A function to unsubscribe + */ + /** + * Registers a handler for an event + * @param event The event name + * @param handler The event handler + * @returns An object with an unsubscribe method + */ + protected on( + event: string, + handler: (data: T) => void, + ): { unsubscribe: () => void } { + if (!this.socket) return { unsubscribe: () => {} }; + this.socket.on(event, handler); + return { unsubscribe: () => this.socket?.off(event, handler) }; + } +} diff --git a/packages/cli/src/commands/sandbox/sandbox-devtools/react-app/src/tsconfig.json b/packages/cli/src/commands/sandbox/sandbox-devtools/react-app/src/tsconfig.json new file mode 100644 index 00000000000..eb02907fa15 --- /dev/null +++ b/packages/cli/src/commands/sandbox/sandbox-devtools/react-app/src/tsconfig.json @@ -0,0 +1,20 @@ +{ + "compilerOptions": { + "target": "ES2020", + "useDefineForClassFields": true, + "lib": ["ES2020", "DOM", "DOM.Iterable", "ScriptHost"], + "module": "ESNext", + "skipLibCheck": true, + "moduleResolution": "node", + "allowSyntheticDefaultImports": true, + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": true, + "jsx": "react-jsx", + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true + }, + "include": ["."] +} diff --git a/packages/cli/src/commands/sandbox/sandbox-devtools/resource_console_functions.test.ts b/packages/cli/src/commands/sandbox/sandbox-devtools/resource_console_functions.test.ts new file mode 100644 index 00000000000..abccd3243f5 --- /dev/null +++ b/packages/cli/src/commands/sandbox/sandbox-devtools/resource_console_functions.test.ts @@ -0,0 +1,336 @@ +/* eslint-disable spellcheck/spell-checker */ +import { describe, it } from 'node:test'; +import assert from 'node:assert'; +import { + type ResourceWithFriendlyName, + canProvideConsoleLink, + getAwsConsoleUrl, + isGlobalService, +} from './resource_console_functions.js'; + +// Test resources +const testResources: ResourceWithFriendlyName[] = [ + { + logicalResourceId: 'amplifyLambdaFunction123ABC45', + physicalResourceId: 'test-lambda-function', + resourceType: 'AWS::Lambda::Function', + resourceStatus: 'DEPLOYED', + friendlyName: 'Lambda Function', + }, + { + logicalResourceId: 'amplifyDynamoDBTable123ABC45', + physicalResourceId: 'test-table', + resourceType: 'AWS::DynamoDB::Table', + resourceStatus: 'DEPLOYED', + friendlyName: 'DynamoDB Table', + }, + { + logicalResourceId: 'amplifyS3Bucket123ABC45', + physicalResourceId: 'test-bucket', + resourceType: 'AWS::S3::Bucket', + resourceStatus: 'DEPLOYED', + friendlyName: 'S3 Bucket', + }, + { + logicalResourceId: 'amplifyIAMRole123ABC45', + physicalResourceId: 'test-role', + resourceType: 'AWS::IAM::Role', + resourceStatus: 'DEPLOYED', + friendlyName: 'IAM Role', + }, + { + logicalResourceId: 'amplifyUnsupportedResource123ABC45', + physicalResourceId: 'test-unsupported', + resourceType: 'AWS::Unsupported::Type', + resourceStatus: 'DEPLOYED', + friendlyName: 'Unsupported Resource', + }, + { + logicalResourceId: 'amplifyFailedResource123ABC45', + physicalResourceId: 'test-failed', + resourceType: 'AWS::IAM::Role', + resourceStatus: 'FAILED', + friendlyName: 'Failed Resource', + }, +]; + +void describe('canProvideConsoleLink function', () => { + void it('returns true for supported resource types with DEPLOYED status', () => { + assert.strictEqual( + canProvideConsoleLink('AWS::Lambda::Function', 'DEPLOYED'), + true, + ); + assert.strictEqual( + canProvideConsoleLink('AWS::S3::Bucket', 'DEPLOYED'), + true, + ); + assert.strictEqual( + canProvideConsoleLink('AWS::IAM::Role', 'DEPLOYED'), + true, + ); + }); + + void it('returns false for unsupported resource types', () => { + assert.strictEqual( + canProvideConsoleLink('AWS::Unsupported::Type', 'DEPLOYED'), + false, + ); + }); + + void it('returns false for non-deployed resources', () => { + assert.strictEqual( + canProvideConsoleLink('AWS::Lambda::Function', 'CREATE_IN_PROGRESS'), + false, + ); + assert.strictEqual( + canProvideConsoleLink('AWS::Lambda::Function', 'DELETED'), + false, + ); + }); + + void it('handles all supported resource types', () => { + const supportedTypes = [ + 'AWS::Lambda::Function', + 'AWS::Lambda::LayerVersion', + 'AWS::DynamoDB::Table', + 'AWS::S3::Bucket', + 'AWS::ApiGateway::RestApi', + 'AWS::IAM::Role', + 'AWS::Cognito::UserPool', + 'AWS::Cognito::UserPoolGroup', + 'AWS::Cognito::IdentityPool', + 'AWS::AppSync::GraphQLApi', + 'AWS::AppSync::DataSource', + 'AWS::AppSync::FunctionConfiguration', + 'AWS::AppSync::Resolver', + 'AWS::AppSync::ApiKey', + 'AWS::CloudWatch::Alarm', + 'AWS::StepFunctions::StateMachine', + 'AWS::SecretsManager::Secret', + 'AWS::Logs::LogGroup', + 'Custom::AmplifyDynamoDBTable', + ]; + + for (const resourceType of supportedTypes) { + assert.strictEqual( + canProvideConsoleLink(resourceType, 'DEPLOYED'), + true, + `Expected ${resourceType} to be supported`, + ); + } + }); + + void it('returns true for newly supported resource types', () => { + const previouslyCommentedOutTypes = [ + 'AWS::DynamoDB::Table', + 'AWS::ApiGateway::RestApi', + 'AWS::CloudWatch::Alarm', + 'AWS::SecretsManager::Secret', + 'AWS::Logs::LogGroup', + ]; + + for (const resourceType of previouslyCommentedOutTypes) { + assert.strictEqual( + canProvideConsoleLink(resourceType, 'DEPLOYED'), + true, + `Expected ${resourceType} to be supported`, + ); + } + }); +}); + +void describe('isGlobalService function', () => { + void it('returns true for IAM service', () => { + assert.strictEqual(isGlobalService('iam'), true); + }); + + void it('returns true for CloudFront service', () => { + // eslint-disable-next-line spellcheck/spell-checker + assert.strictEqual(isGlobalService('cloudfront'), true); + }); + + void it('returns true for Route53 service', () => { + assert.strictEqual(isGlobalService('route53'), true); + }); + + void it('returns false for regional services', () => { + assert.strictEqual(isGlobalService('lambda'), false); + assert.strictEqual(isGlobalService('dynamodb'), false); + assert.strictEqual(isGlobalService('s3'), false); + }); + + void it('handles case insensitivity', () => { + assert.strictEqual(isGlobalService('IAM'), true); + assert.strictEqual(isGlobalService('CloudFront'), true); + assert.strictEqual(isGlobalService('Route53'), true); + }); + + void it('handles empty string', () => { + assert.strictEqual(isGlobalService(''), false); + }); + + void it('handles undefined service', () => { + assert.strictEqual(isGlobalService(undefined as unknown as string), false); + }); +}); + +void describe('getAwsConsoleUrl function', () => { + const testRegion = 'us-west-2'; + + void it('returns null when region is not available', () => { + assert.strictEqual(getAwsConsoleUrl(testResources[0], null), null); + }); + + void it('returns null when physical ID is not available', () => { + const resourceWithoutPhysicalId = { + ...testResources[0], + physicalResourceId: '', + }; + assert.strictEqual( + getAwsConsoleUrl(resourceWithoutPhysicalId, testRegion), + null, + ); + }); + + void it('returns null for unsupported resource types', () => { + assert.strictEqual(getAwsConsoleUrl(testResources[4], testRegion), null); + }); + + void it('generates correct URL for Lambda function', () => { + const url = getAwsConsoleUrl(testResources[0], testRegion); + assert.strictEqual( + url, + `https://${testRegion}.console.aws.amazon.com/lambda/home?region=${testRegion}#/functions/test-lambda-function`, + ); + }); + + void it('generates correct URL for DynamoDB table', () => { + const url = getAwsConsoleUrl(testResources[1], testRegion); + assert.strictEqual( + url, + `https://${testRegion}.console.aws.amazon.com/dynamodbv2/home?region=${testRegion}#table?name=test-table`, + ); + }); + + void it('generates correct URL for S3 bucket', () => { + const url = getAwsConsoleUrl(testResources[2], testRegion); + assert.strictEqual( + url, + `https://${testRegion}.console.aws.amazon.com/s3/buckets/test-bucket?region=${testRegion}`, + ); + }); + + void it('generates correct URL for IAM role (global service)', () => { + const url = getAwsConsoleUrl(testResources[3], testRegion); + assert.strictEqual( + url, + `https://${testRegion}.console.aws.amazon.com/iam/home#/roles/details/test-role?section=permissions`, + ); + }); + + void it('extracts function name from ARN for Lambda resources', () => { + const lambdaWithArn = { + ...testResources[0], + physicalResourceId: + 'arn:aws:lambda:us-west-2:123456789012:function:my-function', + }; + const url = getAwsConsoleUrl(lambdaWithArn, testRegion); + assert.strictEqual( + url, + `https://${testRegion}.console.aws.amazon.com/lambda/home?region=${testRegion}#/functions/my-function`, + ); + }); + + void it('extracts user pool ID from ARN for Cognito resources', () => { + const cognitoResource = { + logicalResourceId: 'amplifyUserPool123ABC45', + physicalResourceId: + 'arn:aws:cognito-idp:us-west-2:123456789012:userpool/us-west-2_hello', + resourceType: 'AWS::Cognito::UserPool', + resourceStatus: 'DEPLOYED', + friendlyName: 'User Pool', + }; + const url = getAwsConsoleUrl(cognitoResource, testRegion); + assert.strictEqual( + url, + `https://${testRegion}.console.aws.amazon.com/cognito/v2/idp/user-pools/us-west-2_hello/users?region=${testRegion}`, + ); + }); + + void it('handles resources with special characters in physical ID', () => { + const resourceWithSpecialChars = { + ...testResources[2], + physicalResourceId: 'my-bucket-with-special/chars+and&symbols', + }; + const url = getAwsConsoleUrl(resourceWithSpecialChars, testRegion); + assert.strictEqual( + url, + `https://${testRegion}.console.aws.amazon.com/s3/buckets/${encodeURIComponent('my-bucket-with-special/chars+and&symbols')}?region=${testRegion}`, + ); + }); + + void it('returns null for resources with non-DEPLOYED status', () => { + const url = getAwsConsoleUrl(testResources[5], testRegion); + assert.strictEqual(url, null); + }); + + void it('generates correct URL for ApiGateway RestApi', () => { + const apiGatewayResource = { + logicalResourceId: 'amplifyRestApi123ABC45', + physicalResourceId: 'abc123def456', + resourceType: 'AWS::ApiGateway::RestApi', + resourceStatus: 'DEPLOYED', + friendlyName: 'REST API', + }; + const url = getAwsConsoleUrl(apiGatewayResource, testRegion); + assert.strictEqual( + url, + `https://${testRegion}.console.aws.amazon.com/apigateway/main/apis/abc123def456/resources?api=abc123def456®ion=${testRegion}`, + ); + }); + + void it('generates correct URL for CloudWatch Alarm', () => { + const cloudWatchAlarmResource = { + logicalResourceId: 'amplifyAlarm123ABC45', + physicalResourceId: 'TestAlarm', + resourceType: 'AWS::CloudWatch::Alarm', + resourceStatus: 'DEPLOYED', + friendlyName: 'CloudWatch Alarm', + }; + const url = getAwsConsoleUrl(cloudWatchAlarmResource, testRegion); + assert.strictEqual( + url, + `https://${testRegion}.console.aws.amazon.com/cloudwatch/home?region=${testRegion}#alarmsV2:alarm/TestAlarm`, + ); + }); + + void it('generates correct URL for SecretsManager Secret', () => { + const secretsManagerResource = { + logicalResourceId: 'amplifySecret123ABC45', + physicalResourceId: 'TestSecret', + resourceType: 'AWS::SecretsManager::Secret', + resourceStatus: 'DEPLOYED', + friendlyName: 'Secrets Manager Secret', + }; + const url = getAwsConsoleUrl(secretsManagerResource, testRegion); + assert.strictEqual( + url, + `https://${testRegion}.console.aws.amazon.com/secretsmanager/home?region=${testRegion}#/secret?name=TestSecret`, + ); + }); + + void it('generates correct URL for Logs LogGroup', () => { + const logsResource = { + logicalResourceId: 'amplifyLogGroup123ABC45', + physicalResourceId: '/aws/test/console-url-testing', + resourceType: 'AWS::Logs::LogGroup', + resourceStatus: 'DEPLOYED', + friendlyName: 'Log Group', + }; + const url = getAwsConsoleUrl(logsResource, testRegion); + assert.strictEqual( + url, + `https://${testRegion}.console.aws.amazon.com/cloudwatch/home?region=${testRegion}#logsV2:log-groups/log-group/${encodeURIComponent('/aws/test/console-url-testing')}`, + ); + }); +}); diff --git a/packages/cli/src/commands/sandbox/sandbox-devtools/resource_console_functions.ts b/packages/cli/src/commands/sandbox/sandbox-devtools/resource_console_functions.ts new file mode 100644 index 00000000000..da53e68cbfd --- /dev/null +++ b/packages/cli/src/commands/sandbox/sandbox-devtools/resource_console_functions.ts @@ -0,0 +1,263 @@ +/* eslint-disable no-case-declarations */ +/* eslint-disable spellcheck/spell-checker */ +/** + * Utility functions for AWS console resource handling + * These functions are used by both the React component and test files + */ +import { DeployedBackendResource } from '@aws-amplify/deployed-backend-client'; + +/** + * Extended resource type with friendly name + */ +export type ResourceWithFriendlyName = DeployedBackendResource & { + logicalResourceId: string; + physicalResourceId: string; + resourceType: string; + resourceStatus: string; + friendlyName?: string; + consoleUrl?: string | null; +}; + +/** + * Type guard to ensure required fields exist in a resource + */ +export const isCompleteResource = ( + resource: DeployedBackendResource, +): resource is Required< + Pick< + DeployedBackendResource, + | 'logicalResourceId' + | 'physicalResourceId' + | 'resourceType' + | 'resourceStatus' + > +> & + DeployedBackendResource => { + return Boolean( + resource.logicalResourceId && + resource.physicalResourceId && + resource.resourceType && + resource.resourceStatus, + ); +}; + +/** + * Determines if a console link can be provided for a given resource type and status + */ +export const canProvideConsoleLink = ( + resourceType: string, + resourceStatus: string, +): boolean => { + const supportedResourceTypes = [ + 'AWS::Lambda::Function', + 'AWS::Lambda::LayerVersion', + 'AWS::DynamoDB::Table', + 'AWS::S3::Bucket', + 'AWS::ApiGateway::RestApi', + 'AWS::IAM::Role', + 'AWS::Cognito::UserPool', + 'AWS::Cognito::UserPoolGroup', + 'AWS::Cognito::IdentityPool', + 'AWS::AppSync::GraphQLApi', + 'AWS::AppSync::DataSource', + 'AWS::AppSync::FunctionConfiguration', + 'AWS::AppSync::Resolver', + 'AWS::AppSync::ApiKey', + 'AWS::CloudWatch::Alarm', + 'AWS::StepFunctions::StateMachine', + 'AWS::SecretsManager::Secret', + 'AWS::Logs::LogGroup', + 'Custom::AmplifyDynamoDBTable', + ]; + + const isDeployed = resourceStatus.includes('DEPLOYED'); + return supportedResourceTypes.includes(resourceType) && isDeployed; +}; + +/** + * Determines if a service is a global AWS service + */ +export const isGlobalService = (service?: string): boolean => { + if (!service) return false; + return ['iam', 'cloudfront', 'route53'].includes(service.toLowerCase()); +}; + +/** + * Generates an AWS console URL for a given resource + * @param resource - The resource to generate the URL for + * @param region - The AWS region for the resource + * @returns The AWS console URL for the resource, or null if not applicable + */ +export const getAwsConsoleUrl = ( + resource: ResourceWithFriendlyName, + region: string | null, +): string | null => { + // If region is not available, don't provide any links + // The front end handles null links gracefully (no display at all) + if (!region) { + return null; + } + + const resourceType = resource.resourceType; + const physicalId = resource.physicalResourceId; + + // If physical ID is not available or resource type is not supported, don't provide a link + if ( + !physicalId || + physicalId === '' || + !canProvideConsoleLink(resourceType, resource.resourceStatus) + ) { + return null; + } + + // Some services use a global console URL (like IAM) + const service = resourceType.split('::')[1]?.toLowerCase(); + const baseUrl = isGlobalService(service) + ? 'https://console.aws.amazon.com' + : `https://${region}.console.aws.amazon.com`; + + switch (resourceType) { + case 'AWS::Lambda::Function': + // Check if physicalId is an ARN and extract function name if needed + const lambdaFunctionName = physicalId.includes(':function:') + ? physicalId.split(':function:')[1] + : physicalId; + return `${baseUrl}/lambda/home?region=${region}#/functions/${lambdaFunctionName}`; + + case 'AWS::DynamoDB::Table': + // Check if physicalId is an ARN and extract table name if needed + const dynamoTableName = physicalId.includes(':table/') + ? physicalId.split(':table/')[1] + : physicalId; + return `${baseUrl}/dynamodbv2/home?region=${region}#table?name=${encodeURIComponent(dynamoTableName)}`; + + case 'AWS::S3::Bucket': + return `${baseUrl}/s3/buckets/${encodeURIComponent(physicalId)}?region=${region}`; + + case 'AWS::ApiGateway::RestApi': + return `${baseUrl}/apigateway/main/apis/${physicalId}/resources?api=${physicalId}®ion=${region}`; + + case 'AWS::IAM::Role': + // For IAM roles, the physical ID is already the role name + // Even though IAM is a global service, the console URL includes the region (why?) + return `https://${region}.console.aws.amazon.com/iam/home#/roles/details/${encodeURIComponent(physicalId)}?section=permissions`; + + case 'AWS::Cognito::UserPool': + // Check if physicalId is an ARN and extract pool ID if needed + const userPoolId = physicalId.includes(':userpool/') + ? physicalId.split(':userpool/')[1] + : physicalId; + return `${baseUrl}/cognito/v2/idp/user-pools/${userPoolId}/users?region=${region}`; + + case 'AWS::Cognito::UserPoolGroup': + // For Cognito user pool groups, we need both the user pool ID and group name + if (physicalId.includes('/')) { + const [userPoolId, groupName] = physicalId.split('/'); + return `${baseUrl}/cognito/v2/idp/user-pools/${encodeURIComponent(userPoolId)}/user-management/groups/details/${encodeURIComponent(groupName)}?region=${region}`; + } + // If we can't parse it, just go to the user pools page + return `${baseUrl}/cognito/v2/idp/user-pools?region=${region}`; + + case 'AWS::AppSync::GraphQLApi': + // Extract API ID from ARN if available + if (physicalId.includes(':apis/')) { + const apiId = physicalId.split(':apis/')[1]; + return `${baseUrl}/appsync/home?region=${region}#/${apiId}/v1/`; + } + return `${baseUrl}/appsync/home?region=${region}#/${physicalId}/v1/`; + + case 'AWS::CloudWatch::Alarm': + return `${baseUrl}/cloudwatch/home?region=${region}#alarmsV2:alarm/${physicalId}`; + + case 'AWS::StepFunctions::StateMachine': + return `${baseUrl}/states/home?region=${region}#/statemachines/view/${physicalId}`; + + case 'AWS::SecretsManager::Secret': + return `${baseUrl}/secretsmanager/home?region=${region}#/secret?name=${physicalId}`; + + case 'AWS::Logs::LogGroup': + return `${baseUrl}/cloudwatch/home?region=${region}#logsV2:log-groups/log-group/${encodeURIComponent(physicalId)}`; + + case 'AWS::Cognito::IdentityPool': + // Check if physicalId is an ARN and extract identity pool ID if needed + const identityPoolId = physicalId.includes(':identitypool/') + ? physicalId.split(':identitypool/')[1] + : physicalId; + return `${baseUrl}/cognito/v2/identity/identity-pools/${encodeURIComponent(identityPoolId)}/?region=${region}`; + + case 'AWS::Lambda::LayerVersion': + // For Lambda layers, the physical ID is typically the layer ARN + // Extract the layer name from the ARN + if (physicalId.includes(':layer:')) { + const layerParts = physicalId.split(':layer:')[1].split(':'); + const layerName = layerParts[0]; + const versionNumber = layerParts.length > 1 ? layerParts[1] : ''; + return `${baseUrl}/lambda/home?region=${region}#/layers/${encodeURIComponent(layerName)}/versions/${versionNumber}`; + } + // If we can't extract the layer name, go to the Lambda layers list + return `${baseUrl}/lambda/home?region=${region}#/layers`; + + case 'AWS::AppSync::DataSource': + // Extract API ID and data source name from ARN if available + if ( + physicalId.includes(':apis/') && + physicalId.includes('/datasources/') + ) { + const apiId = physicalId.split(':apis/')[1].split('/')[0]; + const dataSourceName = physicalId.split('/datasources/')[1]; + return `${baseUrl}/appsync/home?region=${region}#/${apiId}/v1/datasources/${dataSourceName}/edit`; + } + if (physicalId.includes('/')) { + const apiId = physicalId.split('/')[0]; + return `${baseUrl}/appsync/home?region=${region}#/${encodeURIComponent(apiId)}/v1/datasources`; + } + return `${baseUrl}/appsync/home?region=${region}`; + + case 'AWS::AppSync::FunctionConfiguration': + // Extract API ID and function ID from ARN if available + if (physicalId.includes(':apis/') && physicalId.includes('/functions/')) { + const apiId = physicalId.split(':apis/')[1].split('/')[0]; + const functionId = physicalId.split('/functions/')[1]; + return `${baseUrl}/appsync/home?region=${region}#/${apiId}/v1/functions/${functionId}/edit`; + } + if (physicalId.includes('/')) { + const apiId = physicalId.split('/')[0]; + return `${baseUrl}/appsync/home?region=${region}#/${encodeURIComponent(apiId)}/v1/functions`; + } + return `${baseUrl}/appsync/home?region=${region}`; + + case 'AWS::AppSync::Resolver': + // Extract API ID from ARN if available + if (physicalId.includes(':apis/')) { + //Just goes to the schema page, where all resolvers are + const apiId = physicalId.split(':apis/')[1].split('/')[0]; + return `${baseUrl}/appsync/home?region=${region}#/${apiId}/v1/schema`; + } + // If we can't extract the API ID, use the old logic + if (physicalId.includes('/')) { + const apiId = physicalId.split('/')[0]; + return `${baseUrl}/appsync/home?region=${region}#/${encodeURIComponent(apiId)}/v1/schema`; + } + return `${baseUrl}/appsync/home?region=${region}`; + + case 'AWS::AppSync::ApiKey': + // Extract API ID from ARN if available + if (physicalId.includes(':apis/')) { + const apiId = physicalId.split(':apis/')[1].split('/')[0]; + return `${baseUrl}/appsync/home?region=${region}#/${apiId}/v1/settings`; + } + // If we can't extract the API ID, use the old logic + if (physicalId.includes('/')) { + const apiId = physicalId.split('/')[0]; + return `${baseUrl}/appsync/home?region=${region}#/${encodeURIComponent(apiId)}/v1/settings`; + } + return `${baseUrl}/appsync/home?region=${region}`; + + case 'Custom::AmplifyDynamoDBTable': + //For the amplify specific dynamo DB table + return `${baseUrl}/dynamodbv2/home?region=${region}#table?name=${encodeURIComponent(physicalId)}`; + + default: + return null; + } +}; diff --git a/packages/cli/src/commands/sandbox/sandbox-devtools/sandbox_devtools_command.test.ts b/packages/cli/src/commands/sandbox/sandbox-devtools/sandbox_devtools_command.test.ts new file mode 100644 index 00000000000..f0eb384ef46 --- /dev/null +++ b/packages/cli/src/commands/sandbox/sandbox-devtools/sandbox_devtools_command.test.ts @@ -0,0 +1,229 @@ +import { afterEach, beforeEach, describe, it, mock } from 'node:test'; +import assert from 'node:assert'; +import { SandboxDevToolsCommand } from './sandbox_devtools_command.js'; +import { format, printer } from '@aws-amplify/cli-core'; +import { DevToolsLoggerFactory } from './services/devtools_logger_factory.js'; +import { PortChecker } from '../port_checker.js'; +import { SandboxBackendIdResolver } from '../sandbox_id_resolver.js'; +import { S3Client } from '@aws-sdk/client-s3'; +import { AmplifyClient } from '@aws-sdk/client-amplify'; +import { CloudFormationClient } from '@aws-sdk/client-cloudformation'; +import { createServer } from 'node:http'; + +void describe('SandboxDevToolsCommand', () => { + let command: SandboxDevToolsCommand; + let originalHandler: () => Promise; + let mockSandboxBackendIdResolver: SandboxBackendIdResolver; + let mockAwsClientProvider: { + getS3Client: () => S3Client; + getAmplifyClient: () => AmplifyClient; + getCloudFormationClient: () => CloudFormationClient; + }; + let mockPortChecker: PortChecker; + let mockDevToolsLoggerFactory: DevToolsLoggerFactory; + + beforeEach(() => { + mock.reset(); + + // Mock DevToolsLoggerFactory + mockDevToolsLoggerFactory = { + createLogger: mock.fn(() => ({ + log: () => {}, + print: () => {}, + startSpinner: () => {}, + stopSpinner: () => {}, + updateSpinner: () => {}, + emitToClient: () => {}, + })), + } as unknown as DevToolsLoggerFactory; + + // Mock printer methods + mock.method(printer, 'print', () => {}); + mock.method(printer, 'log', () => {}); + mock.method(format, 'highlight', (text: string) => text); + + // Create mock for SandboxBackendIdResolver + mockSandboxBackendIdResolver = { + resolve: () => + Promise.resolve({ + name: 'test-backend', + namespace: 'test', + type: 'sandbox', + }), + } as unknown as SandboxBackendIdResolver; + + // Create mock for AWS client provider + mockAwsClientProvider = { + getS3Client: () => ({}) as S3Client, + getAmplifyClient: () => ({}) as AmplifyClient, + getCloudFormationClient: () => ({}) as CloudFormationClient, + }; + + // Mock PortChecker to prevent actual port operations + mockPortChecker = new PortChecker(); + mock.method(mockPortChecker, 'isPortInUse', () => Promise.resolve(false)); + + command = new SandboxDevToolsCommand( + mockSandboxBackendIdResolver, + mockAwsClientProvider, + mockPortChecker, + format, + printer, + mockDevToolsLoggerFactory, + ); + originalHandler = command.handler; + }); + + afterEach(() => { + // Restore original handler + command.handler = originalHandler; + mock.reset(); + }); + + void describe('constructor', () => { + void it('initializes with correct command and description', () => { + assert.strictEqual(command.command, 'devtools'); + assert.strictEqual( + command.describe, + 'Starts a development console for Amplify sandbox', + ); + }); + }); + + void describe('checkPortAvailability', () => { + void it('does not throw when port is available', async (contextual) => { + // Mock port checker to report port is available + contextual.mock.method(mockPortChecker, 'isPortInUse', () => + Promise.resolve(false), + ); + + // This should not throw an error + await command.checkPortAvailability(3333); + + // If we reach here, the test passes + assert.ok(true); + }); + + void it('throws error when port is already in use', async (contextual) => { + // Mock port checker to report port is in use + contextual.mock.method(mockPortChecker, 'isPortInUse', () => + Promise.resolve(true), + ); + + // Mock printer.log to catch error message + const logMock = contextual.mock.method(printer, 'log'); + + // This should throw an error + await assert.rejects( + () => command.checkPortAvailability(3333), + (error: Error) => { + assert.match(error.message, /Port .* is required for DevTools/); + return true; + }, + ); + + // Verify error was logged + assert.strictEqual(logMock.mock.callCount(), 1); + assert.match( + logMock.mock.calls[0].arguments[0], + /Port .* is already in use/, + ); + }); + + void it('handles port checker errors', async (contextual) => { + // Mock port checker to throw an error + contextual.mock.method(mockPortChecker, 'isPortInUse', () => { + throw new Error('Port check failed'); + }); + + // This should throw the same error + await assert.rejects( + () => command.checkPortAvailability(3333), + (error: Error) => { + assert.strictEqual(error.message, 'Port check failed'); + return true; + }, + ); + }); + }); + + void describe('startServer', () => { + void it('starts the server and prints the start message', (contextual) => { + const mockServer = { + listen: contextual.mock.fn(), + }; + + const printMock = contextual.mock.method(printer, 'print'); + + // Start the server + command.startServer( + mockServer as unknown as ReturnType, + 3333, + ); + + // Check that the server was started with the correct port + assert.strictEqual(mockServer.listen.mock.callCount(), 1); + assert.strictEqual(mockServer.listen.mock.calls[0].arguments[0], 3333); + + // Check that the start message was printed + assert.strictEqual(printMock.mock.callCount(), 1); + assert.match( + printMock.mock.calls[0].arguments[0], + /DevTools server started at http:\/\/localhost:3333/, + ); + }); + }); + + void describe('setupProcessHandlers', () => { + void it('registers SIGINT and SIGTERM handlers', (contextual) => { + const processOnceMock = contextual.mock.method(process, 'once'); + + const mockShutdownService = { + shutdown: contextual.mock.fn(() => Promise.resolve()), + }; + + command.setupProcessHandlers(mockShutdownService); + + assert.strictEqual(processOnceMock.mock.callCount(), 2); + + const sigintCall = processOnceMock.mock.calls.find( + (call) => call.arguments[0] === 'SIGINT', + ); + assert.ok(sigintCall, 'Should register SIGINT handler'); + + // Check SIGTERM is registered + // eslint-disable-next-line spellcheck/spell-checker + const sigtermCall = processOnceMock.mock.calls.find( + (call) => call.arguments[0] === 'SIGTERM', + ); + // eslint-disable-next-line spellcheck/spell-checker + assert.ok(sigtermCall, 'Should register SIGTERM handler'); + + // Simulate SIGINT to verify shutdown is called + if (sigintCall) { + const sigintHandler = sigintCall.arguments[1]; + sigintHandler(); + // We can't easily assert async functions called inside an IIFE + } + }); + }); + + void it('prints server start message when server starts', (contextual) => { + const printMock = contextual.mock.method(printer, 'print'); + + const mockServer = { + listen: contextual.mock.fn(), + }; + + command.startServer( + mockServer as unknown as ReturnType, + 3333, + ); + + assert.strictEqual(printMock.mock.callCount(), 1); + assert.match( + printMock.mock.calls[0].arguments[0], + /DevTools server started at http:\/\/localhost:3333/, + ); + }); +}); diff --git a/packages/cli/src/commands/sandbox/sandbox-devtools/sandbox_devtools_command.ts b/packages/cli/src/commands/sandbox/sandbox-devtools/sandbox_devtools_command.ts index b051a5db47e..63db4730563 100644 --- a/packages/cli/src/commands/sandbox/sandbox-devtools/sandbox_devtools_command.ts +++ b/packages/cli/src/commands/sandbox/sandbox-devtools/sandbox_devtools_command.ts @@ -1,10 +1,56 @@ -import { Argv, CommandModule } from 'yargs'; -import { LogLevel, printer } from '@aws-amplify/cli-core'; +import { CommandModule } from 'yargs'; +import express from 'express'; +import rateLimit from 'express-rate-limit'; +import { createServer } from 'node:http'; +import { fileURLToPath } from 'node:url'; +import { dirname, join } from 'node:path'; +import { Server } from 'socket.io'; +import { + LogLevel, + format as defaultFormat, + printer as defaultPrinter, + minimumLogLevel, +} from '@aws-amplify/cli-core'; +import { BackendIdentifierConversions } from '@aws-amplify/platform-core'; +import { + Sandbox, + SandboxSingletonFactory, + SandboxStatus, +} from '@aws-amplify/sandbox'; +import { SDKProfileResolverProvider } from '../../../sdk_profile_resolver_provider.js'; +import { SandboxBackendIdResolver } from '../sandbox_id_resolver.js'; +import { DeployedBackendClientFactory } from '@aws-amplify/deployed-backend-client'; +import { S3Client } from '@aws-sdk/client-s3'; +import { AmplifyClient } from '@aws-sdk/client-amplify'; +import { + CloudFormationClient, + DescribeStacksCommand, +} from '@aws-sdk/client-cloudformation'; +import { EOL } from 'os'; +import { ShutdownService } from './services/shutdown_service.js'; +import { SocketHandlerService } from './services/socket_handlers.js'; +import { ResourceService } from './services/resource_service.js'; +import { PortChecker } from '../port_checker.js'; +import { DevToolsLogger } from './services/devtools_logger.js'; +import { DevToolsLoggerFactory } from './services/devtools_logger_factory.js'; +import { BackendIdentifier } from '@aws-amplify/plugin-types'; /** - * Command that starts the sandbox devtools. + * Type for sandbox status data */ -export class SandboxDevToolsCommand implements CommandModule { +type SandboxStatusData = { + status: SandboxStatus; + identifier: string; + error?: boolean; + message?: string; + timestamp: string; + deploymentCompleted?: boolean; +}; + +/** + * Command to start devtools console. + */ +export class SandboxDevToolsCommand implements CommandModule { /** * @inheritDoc */ @@ -16,25 +62,428 @@ export class SandboxDevToolsCommand implements CommandModule { readonly describe: string; /** - * Creates sandbox devtools command. + * DevTools command constructor. + * @param sandboxBackendIdResolver Resolver for sandbox backend ID + * @param awsClientProvider Provider for AWS clients + * @param awsClientProvider.getS3Client Function to get S3 client + * @param awsClientProvider.getAmplifyClient Function to get Amplify client + * @param awsClientProvider.getCloudFormationClient Function to get CloudFormation client + * @param portChecker Checker for port availability + * @param format Formatter for console output + * @param printer Printer for console output + * @param devToolsLoggerFactory Factory for creating DevToolsLogger instances */ - constructor() { + constructor( + private readonly sandboxBackendIdResolver: SandboxBackendIdResolver, + private readonly awsClientProvider: { + getS3Client: () => S3Client; + getAmplifyClient: () => AmplifyClient; + getCloudFormationClient: () => CloudFormationClient; + }, + private readonly portChecker: PortChecker = new PortChecker(), + private readonly format = defaultFormat, + private printer = defaultPrinter, + private readonly devToolsLoggerFactory?: DevToolsLoggerFactory, + ) { this.command = 'devtools'; - this.describe = 'Starts the sandbox devtools UI'; + this.describe = 'Starts a development console for Amplify sandbox'; } /** - * @inheritDoc + * Check if a port is available for use. + * @param port The port number to check + * @throws Error if port is already in use */ - handler = async (): Promise => { - printer.log('Sandbox DevTools UI is coming soon...', LogLevel.INFO); - printer.log('This is a placeholder implementation for PR 1', LogLevel.INFO); - }; + async checkPortAvailability(port: number): Promise { + const isInUse = await this.portChecker.isPortInUse(port); + + if (isInUse) { + this.printer.log( + `Port ${port} is already in use. Close any applications using this port and try again.`, + LogLevel.ERROR, + ); + throw new Error( + `Port ${port} is required for DevTools. Ensure it's available and no other instance of DevTools is already running`, + ); + } + } + + /** + * Set up the Express app and HTTP server + * @returns The HTTP server instance + */ + setupServer(): ReturnType { + const app = express(); + // eslint-disable-next-line @typescript-eslint/no-misused-promises + const server = createServer(app); + + // Serve static files from the React app's 'dist' directory + const publicPath = join( + dirname(fileURLToPath(import.meta.url)), + './react-app/dist', + ); + app.use(express.static(publicPath)); + + // Apply rate limiting to all routes + // DevTools runs locally on developers' machines, and developers are the sole users, so rate limiting is not strictly necessary + // Included to satisfy CodeQL rule on rate limiting: https://codeql.github.com/codeql-query-help/javascript/js-missing-rate-limiting/ + const limiter = rateLimit({ + windowMs: 15 * 60 * 1000, // 15 minutes + max: 100, // Limit each IP to 100 requests per windowMs + standardHeaders: true, // Return rate limit info in the `RateLimit-*` headers + legacyHeaders: false, // Disable the `X-RateLimit-*` headers + }); + + // Apply the rate limiting middleware to all requests + app.use(limiter); + + // For any other request, serve the index.html (for React router) + app.get('*', (req, res) => { + res.sendFile(join(publicPath, 'index.html')); + }); + + return server; + } + + /** + * Start the server listening on the specified port + * @param server The HTTP server to start + * @param port The port number to listen on + */ + startServer(server: ReturnType, port: number): void { + server.listen(port); + + this.printer.print( + `${EOL}DevTools server started at ${this.format.highlight(`http://localhost:${port}`)}`, + ); + } + + /** + * Setup all event listeners for the sandbox events + * @param sandbox The sandbox instance + * @param io The Socket.IO server instance + * @param backendId The backend ID + * @param backendId.name The name of the backend + * @param backendId.namespace The namespace of the backend (optional) + * @param getSandboxState Function to get the current sandbox state + * @param storageManager The storage manager instance + * @param storageManager.clearAll Method to clear all storage + * @param storageManager.clearResources Method to clear resources storage + */ + setupEventListeners( + sandbox: Sandbox, + io: Server, + backendId: { name: string; namespace?: string }, + getSandboxState: () => Promise, + storageManager: { clearAll: () => void; clearResources: () => void }, + ): void { + // Listen for deployment started + sandbox.on('deploymentStarted', (data: { timestamp?: string }) => { + this.printer.log('Deployment started', LogLevel.DEBUG); + + const statusData: SandboxStatusData = { + status: sandbox.getState(), // This should be 'deploying' after deployment starts, + identifier: backendId.name, + message: 'Deployment started', + timestamp: data.timestamp || new Date().toISOString(), + }; + + io.emit('sandboxStatus', statusData); + }); + + sandbox.on('successfulDeployment', () => { + void (async () => { + this.printer.log('Successful deployment detected', LogLevel.DEBUG); + + const currentState = await getSandboxState(); + + storageManager.clearResources(); + + const statusData: SandboxStatusData = { + status: currentState, + identifier: backendId.name, + message: 'Deployment completed successfully', + timestamp: new Date().toISOString(), + deploymentCompleted: true, + }; + io.emit('sandboxStatus', statusData); + })(); + }); + + sandbox.on('deletionStarted', (data: { timestamp?: string }) => { + this.printer.log('Deletion started', LogLevel.DEBUG); + + const statusData: SandboxStatusData = { + status: sandbox.getState(), // This should be 'deleting' after deletion starts + identifier: backendId.name, + message: 'Deletion started', + timestamp: data.timestamp || new Date().toISOString(), + }; + + io.emit('sandboxStatus', statusData); + }); + + sandbox.on('successfulDeletion', () => { + this.printer.log('Successful deletion detected', LogLevel.DEBUG); + + const statusData: SandboxStatusData = { + status: sandbox.getState(), // This should be 'nonexistent' after deletion + identifier: backendId.name, + message: 'Sandbox deleted successfully', + timestamp: new Date().toISOString(), + deploymentCompleted: true, + }; + + io.emit('sandboxStatus', statusData); + }); + + sandbox.on('failedDeletion', (error: unknown) => { + void (async () => { + this.printer.log('Failed deletion detected', LogLevel.DEBUG); + + // Get the current sandbox state + const currentState = await getSandboxState(); + + // Emit sandbox status update with deletion failure information + const statusData: SandboxStatusData = { + status: currentState as SandboxStatus, + identifier: backendId.name, + error: true, + message: `Deletion failed: ${error as Error}`, + timestamp: new Date().toISOString(), + deploymentCompleted: true, + }; + + // Emit to all connected clients + io.emit('sandboxStatus', statusData); + })(); + }); + + // Listen for failed deployment + sandbox.on('failedDeployment', (error: unknown) => { + void (async () => { + this.printer.log( + 'Failed deployment detected, checking current status', + LogLevel.DEBUG, + ); + + // Get the current sandbox state + const currentState = await getSandboxState(); + + // Emit sandbox status update with deployment failure information + const statusData: SandboxStatusData = { + status: currentState as SandboxStatus, + identifier: backendId.name, + error: true, + message: `Deployment failed: ${error as Error}`, + timestamp: new Date().toISOString(), + deploymentCompleted: true, + }; + + // Emit to all connected clients + io.emit('sandboxStatus', statusData); + + this.printer.log( + `Emitted status '${currentState}' and deployment failure info`, + LogLevel.DEBUG, + ); + })(); + }); + + // Listen for successful stop + sandbox.on('successfulStop', () => { + io.emit('sandboxStatus', { + status: 'stopped', + identifier: backendId.name, + message: 'Sandbox stopped successfully', + timestamp: new Date().toISOString(), + }); + }); + + // Listen for failed stop + sandbox.on('failedStop', (error: unknown) => { + io.emit('sandboxStatus', { + status: sandbox.getState(), + identifier: backendId.name, + error: true, + message: `Error stopping sandbox: ${String(error)}`, + timestamp: new Date().toISOString(), + }); + }); + + // Listen for initialization errors + sandbox.on('initializationError', (error: unknown) => { + void (async () => { + this.printer.log('Initialization error detected', LogLevel.DEBUG); + + // Emit sandbox status update with initialization failure information + const statusData: SandboxStatusData = { + status: sandbox.getState() as SandboxStatus, + identifier: backendId.name, + error: true, + message: `Initialization failed: ${String(error)}`, + timestamp: new Date().toISOString(), + }; + + // Emit to all connected clients + io.emit('sandboxStatus', statusData); + })(); + }); + } + + /** + * Set up process signal handlers + * @param shutdownService The shutdown service instance + * @param shutdownService.shutdown Method to gracefully shut down the server + */ + setupProcessHandlers(shutdownService: { + shutdown: (signal: string, exit: boolean) => Promise; + }): void { + process.once('SIGINT', () => { + void (async () => { + await shutdownService.shutdown('SIGINT', true); + })(); + }); + + // Also handle process termination signals + process.once('SIGTERM', () => { + void (async () => { + await shutdownService.shutdown('SIGTERM', true); + })(); + }); + } + + /** + * Create a function that retrieves the sandbox state + * @param sandbox The sandbox instance + * @param backendId The backend ID + * @returns A function that returns the current sandbox state + */ + createGetSandboxStateFunction( + sandbox: Sandbox, + backendId: BackendIdentifier, + ): () => Promise { + return async () => { + const state = sandbox.getState(); + if (state === 'unknown') { + try { + const cfnClient = this.awsClientProvider.getCloudFormationClient(); + const stackName = BackendIdentifierConversions.toStackName(backendId); + const response = await cfnClient.send( + new DescribeStacksCommand({ StackName: stackName }), + ); + + if (!response || !response.Stacks || response.Stacks.length === 0) { + return 'nonexistent'; + } + + return 'stopped'; // Stack exists, default to stopped + } catch (error) { + if (String(error).includes('does not exist')) { + return 'nonexistent'; + } + } + } + return state; + }; + } /** * @inheritDoc */ - builder = (yargs: Argv): Argv => { - return yargs.version(false); + handler = async (): Promise => { + // Set up Express app and HTTP server + const server = this.setupServer(); + const io = new Server(server); + + const backendId = await this.sandboxBackendIdResolver.resolve(); + + // Initialize the backend client + const backendClient = new DeployedBackendClientFactory().getInstance( + this.awsClientProvider, + ); + + // Create a custom logger that forwards logs to Socket.IO clients + // Either use the injected factory or create a logger directly + let devToolsLogger: DevToolsLogger; + if (this.devToolsLoggerFactory) { + devToolsLogger = this.devToolsLoggerFactory.createLogger(io); + } else { + // Fallback to direct instantiation for backward compatibility + devToolsLogger = new DevToolsLogger(this.printer, io, minimumLogLevel); + } + this.printer = devToolsLogger; // Use the custom logger for all CLI output from now on + + // Get the sandbox instance from the injected sandbox factory + // Pass our custom logger to the getInstance method + const sandbox = await new SandboxSingletonFactory( + this.sandboxBackendIdResolver.resolve, + new SDKProfileResolverProvider().resolve, + this.printer, // Original printer + this.format, + ).getInstance(devToolsLogger); // Pass the devToolsLogger as a parameter + + const getSandboxState = this.createGetSandboxStateFunction( + sandbox, + backendId, + ); + + // Create a simple storage manager for PR 2 + const storageManager = { + clearAll: () => {}, + clearResources: () => {}, + }; + + // Initialize the shutdown service + const shutdownService = new ShutdownService( + io, + server, + storageManager, + sandbox, + getSandboxState, + devToolsLogger, + ); + + // Initialize the resource service + const resourceService = new ResourceService( + backendId.name, + backendClient, + backendId.namespace, + undefined, // Use default RegionFetcher + devToolsLogger, // Pass our custom logger + ); + + // Initialize the socket handler service + const socketHandlerService = new SocketHandlerService( + io, + sandbox, + getSandboxState, + backendId, + shutdownService, + resourceService, + devToolsLogger, + ); + + const port = 3333; + await this.checkPortAvailability(port); + + this.startServer(server, port); + + const open = (await import('open')).default; + await open(`http://localhost:${port}`); + + this.setupEventListeners( + sandbox, + io, + backendId, + getSandboxState, + storageManager, + ); + + io.on('connection', (socket) => { + socketHandlerService.setupSocketHandlers(socket); + }); + + this.setupProcessHandlers(shutdownService); }; } diff --git a/packages/cli/src/commands/sandbox/sandbox-devtools/sandbox_devtools_command_factory.ts b/packages/cli/src/commands/sandbox/sandbox-devtools/sandbox_devtools_command_factory.ts index d0446169d07..4a4dae1c275 100644 --- a/packages/cli/src/commands/sandbox/sandbox-devtools/sandbox_devtools_command_factory.ts +++ b/packages/cli/src/commands/sandbox/sandbox-devtools/sandbox_devtools_command_factory.ts @@ -1,15 +1,48 @@ import { CommandModule } from 'yargs'; import { SandboxDevToolsCommand } from './sandbox_devtools_command.js'; +import { SandboxBackendIdResolver } from '../sandbox_id_resolver.js'; +import { LocalNamespaceResolver } from '../../../backend-identifier/local_namespace_resolver.js'; +import { PackageJsonReader } from '@aws-amplify/platform-core'; +import { format, minimumLogLevel, printer } from '@aws-amplify/cli-core'; +import { S3Client } from '@aws-sdk/client-s3'; +import { AmplifyClient } from '@aws-sdk/client-amplify'; +import { CloudFormationClient } from '@aws-sdk/client-cloudformation'; +import { PortChecker } from '../port_checker.js'; +import { DevToolsLoggerFactory } from './services/devtools_logger_factory.js'; /** - * Factory for creating SandboxDevToolsCommand instances. + * Creates a wired sandbox devtools command. + * @returns A CommandModule instance for the sandbox devtools command */ -export class SandboxDevToolsCommandFactory { - /** - * Creates a new SandboxDevToolsCommand instance. - * @returns A CommandModule instance for the sandbox devtools command - */ - create(): CommandModule { - return new SandboxDevToolsCommand(); - } -} +export const createSandboxDevToolsCommand = (): CommandModule< + object, + object +> => { + const sandboxBackendIdResolver = new SandboxBackendIdResolver( + new LocalNamespaceResolver(new PackageJsonReader()), + ); + const s3Client = new S3Client(); + const amplifyClient = new AmplifyClient(); + const cloudFormationClient = new CloudFormationClient(); + + const awsClientProvider = { + getS3Client: () => s3Client, + getAmplifyClient: () => amplifyClient, + getCloudFormationClient: () => cloudFormationClient, + }; + + const portChecker = new PortChecker(); + const devToolsLoggerFactory = new DevToolsLoggerFactory( + printer, + minimumLogLevel, + ); + + return new SandboxDevToolsCommand( + sandboxBackendIdResolver, + awsClientProvider, + portChecker, + format, + printer, + devToolsLoggerFactory, + ); +}; diff --git a/packages/cli/src/commands/sandbox/sandbox-devtools/services/devtools_logger.test.ts b/packages/cli/src/commands/sandbox/sandbox-devtools/services/devtools_logger.test.ts new file mode 100644 index 00000000000..a3544330544 --- /dev/null +++ b/packages/cli/src/commands/sandbox/sandbox-devtools/services/devtools_logger.test.ts @@ -0,0 +1,404 @@ +import { beforeEach, describe, it, mock } from 'node:test'; +import assert from 'node:assert'; +import { LogLevel, Printer } from '@aws-amplify/cli-core'; +import { DevToolsLogger } from './devtools_logger.js'; +import { Server } from 'socket.io'; + +// Define a type for the mock function to make TypeScript happy +type MockFn = ReturnType; + +// Type for log event data that's emitted by the DevToolsLogger +type LogEventData = { + timestamp: string; + level: string; + message: string; +}; + +void describe('DevToolsLogger', () => { + let devToolsLogger: DevToolsLogger; + let mockOriginalPrinter: Printer; + let mockIo: Server; + const minimumLogLevel = LogLevel.INFO; + + beforeEach(() => { + mock.reset(); + + // Create mock for Printer + mockOriginalPrinter = { + log: mock.fn(), + print: mock.fn(), + startSpinner: mock.fn(), + stopSpinner: mock.fn(), + updateSpinner: mock.fn(), + } as unknown as Printer; + + // Create mock for Socket.IO server + mockIo = { + emit: mock.fn(), + } as unknown as Server; + + // Create the DevToolsLogger instance + devToolsLogger = new DevToolsLogger( + mockOriginalPrinter, + mockIo, + minimumLogLevel, + ); + }); + + void describe('constructor', () => { + void it('creates an instance with provided parameters', () => { + assert.ok(devToolsLogger); + }); + + void it('sets minimum log level correctly', () => { + const debugLogger = new DevToolsLogger( + mockOriginalPrinter, + mockIo, + LogLevel.DEBUG, + ); + assert.ok(debugLogger); + + const errorLogger = new DevToolsLogger( + mockOriginalPrinter, + mockIo, + LogLevel.ERROR, + ); + assert.ok(errorLogger); + }); + }); + + void describe('log', () => { + void it('delegates to original printer', () => { + const testMessage = 'Test log message'; + + devToolsLogger.log(testMessage); + + const mockLogFn = mockOriginalPrinter.log as unknown as MockFn; + assert.strictEqual(mockLogFn.mock.callCount(), 1); + assert.deepStrictEqual(mockLogFn.mock.calls[0].arguments, [ + testMessage, + undefined, + ]); + }); + + void it('delegates to original printer with specified log level', () => { + const testMessage = 'Test log message with level'; + const testLevel = LogLevel.WARN; + + devToolsLogger.log(testMessage, testLevel); + + const mockLogFn = mockOriginalPrinter.log as unknown as MockFn; + assert.strictEqual(mockLogFn.mock.callCount(), 1); + assert.deepStrictEqual(mockLogFn.mock.calls[0].arguments, [ + testMessage, + testLevel, + ]); + }); + + void it('emits log event to Socket.IO clients', () => { + const testMessage = 'Test log message for socket'; + + devToolsLogger.log(testMessage); + + const mockEmitFn = mockIo.emit as unknown as MockFn; + assert.strictEqual(mockEmitFn.mock.callCount(), 1); + assert.strictEqual(mockEmitFn.mock.calls[0].arguments[0], 'log'); + + const logData = mockEmitFn.mock.calls[0].arguments[1] as LogEventData; + assert.strictEqual(logData.message, testMessage); + assert.strictEqual(logData.level, 'INFO'); + assert.ok(logData.timestamp); // Ensure timestamp exists + }); + + void it('emits log event with specified log level', () => { + const testMessage = 'Test log message with level for socket'; + const testLevel = LogLevel.WARN; + + devToolsLogger.log(testMessage, testLevel); + + const mockEmitFn = mockIo.emit as unknown as MockFn; + assert.strictEqual(mockEmitFn.mock.callCount(), 1); + assert.strictEqual(mockEmitFn.mock.calls[0].arguments[0], 'log'); + + const logData = mockEmitFn.mock.calls[0].arguments[1] as LogEventData; + assert.strictEqual(logData.message, testMessage); + assert.strictEqual(logData.level, 'WARN'); + assert.ok(logData.timestamp); + }); + + void it('respects minimum log level when emitting events', () => { + // Create a new logger with INFO as minimum level + const infoLevelLogger = new DevToolsLogger( + mockOriginalPrinter, + mockIo, + LogLevel.INFO, + ); + + // This should be emitted (same as minimum level) + infoLevelLogger.log('Info message', LogLevel.INFO); + + // This should be emitted (higher than minimum level) + infoLevelLogger.log('Error message', LogLevel.ERROR); + + // This should not be emitted (lower than minimum level) + infoLevelLogger.log('Debug message', LogLevel.DEBUG); + + const mockEmitFn = mockIo.emit as unknown as MockFn; + assert.strictEqual(mockEmitFn.mock.callCount(), 2); // Only 2 messages should be emitted + + // Verify the call arguments + assert.ok(mockEmitFn.mock.calls.length >= 2); + + const firstLogData = mockEmitFn.mock.calls[0] + .arguments[1] as LogEventData; + assert.strictEqual(firstLogData.message, 'Info message'); + assert.strictEqual(firstLogData.level, 'INFO'); + + const secondLogData = mockEmitFn.mock.calls[1] + .arguments[1] as LogEventData; + assert.strictEqual(secondLogData.message, 'Error message'); + assert.strictEqual(secondLogData.level, 'ERROR'); + }); + + void it('strips ANSI escape codes from messages', () => { + const ansiMessage = '\u001b[31mThis is red\u001b[0m'; + const cleanMessage = 'This is red'; + + devToolsLogger.log(ansiMessage); + + const mockEmitFn = mockIo.emit as unknown as MockFn; + assert.strictEqual(mockEmitFn.mock.callCount(), 1); + + const logData = mockEmitFn.mock.calls[0].arguments[1] as LogEventData; + assert.strictEqual(logData.message, cleanMessage); + }); + }); + + void describe('print', () => { + void it('delegates to original printer', () => { + const testMessage = 'Test print message'; + + devToolsLogger.print(testMessage); + + const mockPrintFn = mockOriginalPrinter.print as unknown as MockFn; + assert.strictEqual(mockPrintFn.mock.callCount(), 1); + assert.deepStrictEqual(mockPrintFn.mock.calls[0].arguments, [ + testMessage, + ]); + }); + + void it('emits log event to Socket.IO clients', () => { + const testMessage = 'Test print message for socket'; + + devToolsLogger.print(testMessage); + + const mockEmitFn = mockIo.emit as unknown as MockFn; + assert.strictEqual(mockEmitFn.mock.callCount(), 1); + assert.strictEqual(mockEmitFn.mock.calls[0].arguments[0], 'log'); + + const logData = mockEmitFn.mock.calls[0].arguments[1] as LogEventData; + assert.strictEqual(logData.message, testMessage); + assert.strictEqual(logData.level, 'INFO'); + assert.ok(logData.timestamp); + }); + }); + + void describe('startSpinner', () => { + void it('delegates to original printer', () => { + const spinnerMessage = 'Loading...'; + const options = { timeoutSeconds: 30 }; + + devToolsLogger.startSpinner(spinnerMessage, options); + + const mockStartSpinnerFn = + mockOriginalPrinter.startSpinner as unknown as MockFn; + assert.strictEqual(mockStartSpinnerFn.mock.callCount(), 1); + assert.deepStrictEqual(mockStartSpinnerFn.mock.calls[0].arguments, [ + spinnerMessage, + options, + ]); + }); + + void it('emits log event to Socket.IO clients', () => { + const spinnerMessage = 'Loading...'; + + devToolsLogger.startSpinner(spinnerMessage); + + const mockEmitFn = mockIo.emit as unknown as MockFn; + assert.strictEqual(mockEmitFn.mock.callCount(), 1); + assert.strictEqual(mockEmitFn.mock.calls[0].arguments[0], 'log'); + + const logData = mockEmitFn.mock.calls[0].arguments[1] as LogEventData; + assert.strictEqual(logData.message, spinnerMessage); + assert.strictEqual(logData.level, 'INFO'); + assert.ok(logData.timestamp); + }); + }); + + void describe('stopSpinner', () => { + void it('delegates to original printer', () => { + const successMessage = 'Operation completed!'; + + devToolsLogger.stopSpinner(successMessage); + + const mockStopSpinnerFn = + mockOriginalPrinter.stopSpinner as unknown as MockFn; + assert.strictEqual(mockStopSpinnerFn.mock.callCount(), 1); + assert.deepStrictEqual(mockStopSpinnerFn.mock.calls[0].arguments, [ + successMessage, + ]); + }); + + void it('emits log event to Socket.IO clients when success message is provided', () => { + const successMessage = 'Operation completed!'; + + devToolsLogger.stopSpinner(successMessage); + + const mockEmitFn = mockIo.emit as unknown as MockFn; + assert.strictEqual(mockEmitFn.mock.callCount(), 1); + assert.strictEqual(mockEmitFn.mock.calls[0].arguments[0], 'log'); + + const logData = mockEmitFn.mock.calls[0].arguments[1] as LogEventData; + assert.strictEqual(logData.message, successMessage); + assert.strictEqual(logData.level, 'INFO'); + assert.ok(logData.timestamp); + }); + + void it('does not emit log event when success message is not provided', () => { + devToolsLogger.stopSpinner(); + + const mockEmitFn = mockIo.emit as unknown as MockFn; + assert.strictEqual(mockEmitFn.mock.callCount(), 0); + }); + }); + + void describe('updateSpinner', () => { + void it('delegates to original printer', () => { + const options = { + message: 'Updating...', + prefixText: 'Step 2:', + }; + + devToolsLogger.updateSpinner(options); + + const mockUpdateSpinnerFn = + mockOriginalPrinter.updateSpinner as unknown as MockFn; + assert.strictEqual(mockUpdateSpinnerFn.mock.callCount(), 1); + assert.deepStrictEqual(mockUpdateSpinnerFn.mock.calls[0].arguments, [ + options, + ]); + }); + + void it('emits log events for message and prefixText', () => { + const options = { + message: 'Updating...', + prefixText: 'Step 2:', + }; + + devToolsLogger.updateSpinner(options); + + const mockEmitFn = mockIo.emit as unknown as MockFn; + assert.strictEqual(mockEmitFn.mock.callCount(), 2); // One for message, one for prefixText + + assert.strictEqual(mockEmitFn.mock.calls[0].arguments[0], 'log'); + const messageLogData = mockEmitFn.mock.calls[0] + .arguments[1] as LogEventData; + assert.strictEqual(messageLogData.message, 'Updating...'); + + assert.strictEqual(mockEmitFn.mock.calls[1].arguments[0], 'log'); + const prefixLogData = mockEmitFn.mock.calls[1] + .arguments[1] as LogEventData; + assert.strictEqual(prefixLogData.message, 'Step 2:'); + }); + + void it('emits log event only for provided options', () => { + // Test with only message + devToolsLogger.updateSpinner({ message: 'Only message' }); + + const mockEmitFn = mockIo.emit as unknown as MockFn; + assert.strictEqual(mockEmitFn.mock.callCount(), 1); + + const messageLogData = mockEmitFn.mock.calls[0] + .arguments[1] as LogEventData; + assert.strictEqual(messageLogData.message, 'Only message'); + + // Reset mock for next test + (mockEmitFn as MockFn).mock.resetCalls(); + + // Test with only prefixText + devToolsLogger.updateSpinner({ prefixText: 'Only prefix' }); + + assert.strictEqual(mockEmitFn.mock.callCount(), 1); + + const prefixLogData = mockEmitFn.mock.calls[0] + .arguments[1] as LogEventData; + assert.strictEqual(prefixLogData.message, 'Only prefix'); + }); + + void it('does not emit log event when no text options are provided', () => { + devToolsLogger.updateSpinner({}); + + const mockEmitFn = mockIo.emit as unknown as MockFn; + assert.strictEqual(mockEmitFn.mock.callCount(), 0); + }); + }); + + void describe('integration with sandbox logs', () => { + void it('emits sandbox log messages to socket clients', () => { + const sandboxLogMessage = '[Sandbox] Deployed function: hello-world'; + + devToolsLogger.log(sandboxLogMessage, LogLevel.INFO); + + const mockLogFn = mockOriginalPrinter.log as unknown as MockFn; + assert.strictEqual(mockLogFn.mock.callCount(), 1); + assert.deepStrictEqual(mockLogFn.mock.calls[0].arguments, [ + sandboxLogMessage, + LogLevel.INFO, + ]); + + const mockEmitFn = mockIo.emit as unknown as MockFn; + assert.strictEqual(mockEmitFn.mock.callCount(), 1); + + const logData = mockEmitFn.mock.calls[0].arguments[1] as LogEventData; + assert.strictEqual(logData.message, sandboxLogMessage); + assert.strictEqual(logData.level, 'INFO'); + }); + }); + + void describe('full flow testing', () => { + void it('logs to terminal and UI for all log levels above minimum', () => { + // Create a new logger with WARN as minimum level + const warnLevelLogger = new DevToolsLogger( + mockOriginalPrinter, + mockIo, + LogLevel.WARN, + ); + + // This should log to terminal but not emit to UI (lower than minimum) + warnLevelLogger.log('Info message', LogLevel.INFO); + + // These should log to terminal and emit to UI (>= minimum level) + warnLevelLogger.log('Warn message', LogLevel.WARN); + warnLevelLogger.log('Error message', LogLevel.ERROR); + + const mockLogFn = mockOriginalPrinter.log as unknown as MockFn; + assert.strictEqual(mockLogFn.mock.callCount(), 3); // All messages should log to terminal + + const mockEmitFn = mockIo.emit as unknown as MockFn; + assert.strictEqual(mockEmitFn.mock.callCount(), 2); // Only WARN and ERROR should emit to UI + + // Verify the emitted log events + assert.ok(mockEmitFn.mock.calls.length >= 2); + + const firstLogData = mockEmitFn.mock.calls[0] + .arguments[1] as LogEventData; + assert.strictEqual(firstLogData.message, 'Warn message'); + assert.strictEqual(firstLogData.level, 'WARN'); + + const secondLogData = mockEmitFn.mock.calls[1] + .arguments[1] as LogEventData; + assert.strictEqual(secondLogData.message, 'Error message'); + assert.strictEqual(secondLogData.level, 'ERROR'); + }); + }); +}); diff --git a/packages/cli/src/commands/sandbox/sandbox-devtools/services/devtools_logger.ts b/packages/cli/src/commands/sandbox/sandbox-devtools/services/devtools_logger.ts new file mode 100644 index 00000000000..2e2ae2cd3c1 --- /dev/null +++ b/packages/cli/src/commands/sandbox/sandbox-devtools/services/devtools_logger.ts @@ -0,0 +1,106 @@ +import { LogLevel, Printer } from '@aws-amplify/cli-core'; +import { Server } from 'socket.io'; +import stripAnsi from 'strip-ansi'; + +/** + * Type for log event data + */ +type LogEventData = { + timestamp: string; + level: string; + message: string; +}; + +/** + * DevTools logger that streams logs to Socket.IO clients + */ +export class DevToolsLogger extends Printer { + /** + * Creates an instance of DevToolsLogger. + * @param originalPrinter The original printer instance to delegate logging. + * @param io The Socket.IO server instance for emitting log events. + */ + private _minimumLogLevel: LogLevel; + + /** + * Constructs a new DevToolsLogger. + * @param originalPrinter The original printer instance to delegate logging. + * @param io The Socket.IO server instance for emitting log events. + * @param minimumLogLevel The minimum log level for emitting logs. + */ + constructor( + private originalPrinter: Printer, + private io: Server, + minimumLogLevel: LogLevel, + ) { + super(minimumLogLevel); + this._minimumLogLevel = minimumLogLevel; + } + + /** + * Logs a message and emits it to the client. + * @param message The message to log. + * @param level The log level. + */ + log = (message: string, level?: LogLevel) => { + this.originalPrinter.log(message, level); + // Not using shorthand because 0 is a valid log level (LogLevel.INFO) but falsy + if (level !== undefined) { + this.emitToClient(message, level); + } else { + this.emitToClient(message, LogLevel.INFO); + } + }; + + /** + * Prints a message and emits it to the client. + */ + print = (message: string) => { + this.originalPrinter.print(message); + this.emitToClient(message, LogLevel.INFO); + }; + + /** + * Starts a spinner and emits the message to the client. + */ + startSpinner = (message: string, options?: { timeoutSeconds: number }) => { + this.originalPrinter.startSpinner(message, options); + this.emitToClient(message, LogLevel.INFO); + }; + + /** + * Stops the spinner and emits the success message to the client if provided. + */ + stopSpinner = (successMessage?: string) => { + this.originalPrinter.stopSpinner(successMessage); + if (successMessage) { + this.emitToClient(successMessage, LogLevel.INFO); + } + }; + + /** + * Updates the spinner and emits any new messages to the client. + */ + updateSpinner = (options: { message?: string; prefixText?: string }) => { + this.originalPrinter.updateSpinner(options); + if (options.message) { + this.emitToClient(options.message, LogLevel.INFO); + } + if (options.prefixText) { + this.emitToClient(options.prefixText, LogLevel.INFO); + } + }; + + private emitToClient(message: string, level: LogLevel) { + if (level > this._minimumLogLevel) { + return; + } + const cleanMessage = stripAnsi(message); + const logData: LogEventData = { + timestamp: new Date().toISOString(), + level: LogLevel[level], + message: cleanMessage, + }; + this.io.emit('log', logData); + } +} diff --git a/packages/cli/src/commands/sandbox/sandbox-devtools/services/devtools_logger_factory.test.ts b/packages/cli/src/commands/sandbox/sandbox-devtools/services/devtools_logger_factory.test.ts new file mode 100644 index 00000000000..c0a9e617176 --- /dev/null +++ b/packages/cli/src/commands/sandbox/sandbox-devtools/services/devtools_logger_factory.test.ts @@ -0,0 +1,32 @@ +import { describe, it, mock } from 'node:test'; +import assert from 'node:assert'; +import { DevToolsLoggerFactory } from './devtools_logger_factory.js'; +import { DevToolsLogger } from './devtools_logger.js'; +import { LogLevel, Printer } from '@aws-amplify/cli-core'; +import { Server } from 'socket.io'; + +void describe('DevToolsLoggerFactory', () => { + void it('creates a logger with the provided printer and log level', () => { + const mockPrinterLog = mock.fn(); + const mockPrinterPrint = mock.fn(); + const mockPrinter = { + log: mockPrinterLog, + print: mockPrinterPrint, + } as unknown as Printer; + + const mockIoEmit = mock.fn(); + const mockIo = { emit: mockIoEmit } as unknown as Server; + + const minimumLogLevel = LogLevel.INFO; + + const factory = new DevToolsLoggerFactory(mockPrinter, minimumLogLevel); + + const logger = factory.createLogger(mockIo); + + assert.ok(logger instanceof DevToolsLogger); + + logger.log('Test message'); + + assert.strictEqual(mockPrinterLog.mock.callCount(), 1); + }); +}); diff --git a/packages/cli/src/commands/sandbox/sandbox-devtools/services/devtools_logger_factory.ts b/packages/cli/src/commands/sandbox/sandbox-devtools/services/devtools_logger_factory.ts new file mode 100644 index 00000000000..9df494e2ee9 --- /dev/null +++ b/packages/cli/src/commands/sandbox/sandbox-devtools/services/devtools_logger_factory.ts @@ -0,0 +1,27 @@ +import { LogLevel, Printer } from '@aws-amplify/cli-core'; +import { Server } from 'socket.io'; +import { DevToolsLogger } from './devtools_logger.js'; + +/** + * Factory for creating DevToolsLogger instances + */ +export class DevToolsLoggerFactory { + /** + * Creates an instance of DevToolsLoggerFactory. + * @param printer The original printer instance to delegate logging. + * @param minimumLogLevel The minimum log level for emitting logs. + */ + constructor( + private readonly printer: Printer, + private readonly minimumLogLevel: LogLevel, + ) {} + + /** + * Creates a new DevToolsLogger instance + * @param io The Socket.IO server instance for emitting log events. + * @returns A new DevToolsLogger instance + */ + createLogger(io: Server): DevToolsLogger { + return new DevToolsLogger(this.printer, io, this.minimumLogLevel); + } +} diff --git a/packages/cli/src/commands/sandbox/sandbox-devtools/services/resource_service.test.ts b/packages/cli/src/commands/sandbox/sandbox-devtools/services/resource_service.test.ts new file mode 100644 index 00000000000..d59ede99384 --- /dev/null +++ b/packages/cli/src/commands/sandbox/sandbox-devtools/services/resource_service.test.ts @@ -0,0 +1,286 @@ +import { beforeEach, describe, it, mock } from 'node:test'; +import assert from 'node:assert'; +import { ResourceService } from './resource_service.js'; +import { + BackendDeploymentStatus, + BackendMetadata, + DeployedBackendClient, +} from '@aws-amplify/deployed-backend-client'; +import { RegionFetcher } from '@aws-amplify/platform-core'; +import { BackendIdentifier } from '@aws-amplify/plugin-types'; +import { STSClient } from '@aws-sdk/client-sts'; + +// Define a type for the mock implementation +//eslint-disable-next-line @typescript-eslint/no-explicit-any +type MockWithImplementation any> = { + mock: { + mockImplementation: (implementation: T) => void; + calls: { arguments: Parameters; result: ReturnType }[]; + resetCalls: () => void; + }; +}; + +void describe('ResourceService', () => { + let resourceService: ResourceService; + let mockBackendClient: DeployedBackendClient; + let mockRegionFetcher: RegionFetcher; + const backendName = 'test-backend'; + const namespace = 'amplify-backend'; + + beforeEach(() => { + mock.reset(); + + const mockGetBackendMetadata = mock.fn(); + const mockListBackends = mock.fn(); + const mockDeleteSandbox = mock.fn(); + + mockBackendClient = { + getBackendMetadata: mockGetBackendMetadata, + listBackends: mockListBackends, + deleteSandbox: mockDeleteSandbox, + } as unknown as DeployedBackendClient; + + mockRegionFetcher = { + fetch: async () => 'us-east-1', + stsClient: {} as STSClient, + } as unknown as RegionFetcher; + + resourceService = new ResourceService( + backendName, + mockBackendClient, + namespace, + mockRegionFetcher, + ); + }); + + void describe('getDeployedBackendResources', () => { + void it('fetches backend metadata', async () => { + const mockResources = [ + { + logicalResourceId: 'amplifyFunction123ABC', + physicalResourceId: 'my-function-123', + resourceType: 'AWS::Lambda::Function', + resourceStatus: 'CREATE_COMPLETE', + metadata: { constructPath: 'MyStack/MyFunction/Resource' }, + }, + ]; + + const mockMetadata: BackendMetadata = { + name: 'test-backend', + resources: mockResources, + lastUpdated: new Date(), + deploymentType: 'sandbox', + status: BackendDeploymentStatus.DEPLOYED, + }; + + ( + mockBackendClient.getBackendMetadata as unknown as MockWithImplementation< + (backendId: BackendIdentifier) => Promise + > + ).mock.mockImplementation((backendId: BackendIdentifier) => { + assert.deepStrictEqual(backendId, { + namespace, + name: backendName, + type: 'sandbox', + }); + return Promise.resolve(mockMetadata); + }); + + const result = await resourceService.getDeployedBackendResources(); + + assert.strictEqual(result.name, 'test-backend'); + assert.strictEqual(result.region, 'us-east-1'); + assert.strictEqual(result.resources.length, 1); + assert.strictEqual(result.resources[0].friendlyName, 'My Function'); + assert.strictEqual( + result.resources[0].resourceType, + 'AWS::Lambda::Function', + ); + assert.strictEqual(result.resources[0].consoleUrl, null); + }); + + void it('handles deployment in progress error', async () => { + ( + mockBackendClient.getBackendMetadata as unknown as MockWithImplementation< + (backendId: BackendIdentifier) => Promise + > + ).mock.mockImplementation(() => { + throw new Error('deployment is in progress'); + }); + + const result = await resourceService.getDeployedBackendResources(); + + assert.strictEqual(result.name, backendName); + assert.strictEqual(result.status, 'deploying'); + assert.strictEqual(result.resources.length, 0); + assert.strictEqual(result.region, null); + assert.strictEqual( + result.message, + 'Sandbox deployment is in progress. Resources will update when deployment completes.', + ); + }); + + void it('handles non-existent stack error', async () => { + ( + mockBackendClient.getBackendMetadata as unknown as MockWithImplementation< + (backendId: BackendIdentifier) => Promise + > + ).mock.mockImplementation(() => { + throw new Error('does not exist'); + }); + + const result = await resourceService.getDeployedBackendResources(); + + assert.strictEqual(result.name, backendName); + assert.strictEqual(result.status, 'nonexistent'); + assert.strictEqual(result.resources.length, 0); + assert.strictEqual(result.region, null); + assert.strictEqual( + result.message, + 'No sandbox exists. Please create a sandbox first.', + ); + }); + + void it('throws error for unexpected errors', async () => { + ( + mockBackendClient.getBackendMetadata as unknown as MockWithImplementation< + (backendId: BackendIdentifier) => Promise + > + ).mock.mockImplementation(() => { + throw new Error('unexpected error'); + }); + + await assert.rejects( + () => resourceService.getDeployedBackendResources(), + (error: Error) => { + assert.strictEqual(error.message, 'unexpected error'); + return true; + }, + ); + }); + + void it('handles multiple resources with different types', async () => { + const mockResources = [ + { + logicalResourceId: 'amplifyFunction123ABC', + physicalResourceId: 'my-function-123', + resourceType: 'AWS::Lambda::Function', + resourceStatus: 'CREATE_COMPLETE', + metadata: { constructPath: 'MyStack/MyFunction/Resource' }, + }, + { + logicalResourceId: 'amplifyTable456DEF', + physicalResourceId: 'my-table-456', + resourceType: 'AWS::DynamoDB::Table', + resourceStatus: 'CREATE_COMPLETE', + }, + { + logicalResourceId: 'customResource789GHI', + physicalResourceId: 'my-custom-789', + resourceType: 'CUSTOM::MyCustomResource', + resourceStatus: 'CREATE_COMPLETE', + }, + ]; + + const mockMetadata: BackendMetadata = { + name: 'test-backend', + resources: mockResources, + lastUpdated: new Date(), + deploymentType: 'sandbox', + status: BackendDeploymentStatus.DEPLOYED, + }; + + ( + mockBackendClient.getBackendMetadata as unknown as MockWithImplementation< + (backendId: BackendIdentifier) => Promise + > + ).mock.mockImplementation(() => Promise.resolve(mockMetadata)); + + const result = await resourceService.getDeployedBackendResources(); + + assert.strictEqual(result.resources.length, 3); + assert.strictEqual( + result.resources[0].resourceType, + 'AWS::Lambda::Function', + ); + assert.strictEqual( + result.resources[1].resourceType, + 'AWS::DynamoDB::Table', + ); + assert.strictEqual(result.resources[2].resourceType, 'MyCustomResource'); + }); + + void it('handles region fetch error gracefully', async () => { + const mockResources = [ + { + logicalResourceId: 'amplifyFunction123ABC', + physicalResourceId: 'my-function-123', + resourceType: 'AWS::Lambda::Function', + resourceStatus: 'CREATE_COMPLETE', + }, + ]; + + const mockMetadata: BackendMetadata = { + name: 'test-backend', + resources: mockResources, + lastUpdated: new Date(), + deploymentType: 'sandbox', + status: BackendDeploymentStatus.DEPLOYED, + }; + + ( + mockBackendClient.getBackendMetadata as unknown as MockWithImplementation< + (backendId: BackendIdentifier) => Promise + > + ).mock.mockImplementation(() => Promise.resolve(mockMetadata)); + + mockRegionFetcher = { + fetch: async () => { + throw new Error('Region fetch failed'); + }, + stsClient: {} as STSClient, + } as unknown as RegionFetcher; + + resourceService = new ResourceService( + backendName, + mockBackendClient, + namespace, + mockRegionFetcher, + ); + + const result = await resourceService.getDeployedBackendResources(); + + assert.strictEqual(result.region, null); + assert.strictEqual(result.resources.length, 1); + }); + + void it('handles empty resources array', async () => { + const mockMetadata: BackendMetadata = { + name: 'test-backend', + resources: [], + lastUpdated: new Date(), + deploymentType: 'sandbox', + status: BackendDeploymentStatus.DEPLOYED, + }; + + ( + mockBackendClient.getBackendMetadata as unknown as MockWithImplementation< + (backendId: BackendIdentifier) => Promise + > + ).mock.mockImplementation(() => Promise.resolve(mockMetadata)); + + const result = await resourceService.getDeployedBackendResources(); + + assert.strictEqual(result.name, 'test-backend'); + assert.strictEqual(result.resources.length, 0); + assert.strictEqual(result.region, 'us-east-1'); + }); + }); + + void describe('constructor', () => { + void it('creates instance with default parameters', () => { + const service = new ResourceService('test-name', mockBackendClient); + assert.ok(service); + }); + }); +}); diff --git a/packages/cli/src/commands/sandbox/sandbox-devtools/services/resource_service.ts b/packages/cli/src/commands/sandbox/sandbox-devtools/services/resource_service.ts new file mode 100644 index 00000000000..cbe76da2103 --- /dev/null +++ b/packages/cli/src/commands/sandbox/sandbox-devtools/services/resource_service.ts @@ -0,0 +1,165 @@ +import { + LogLevel, + Printer, + printer as printerUtil, +} from '@aws-amplify/cli-core'; +import { DeployedBackendClient } from '@aws-amplify/deployed-backend-client'; +import { BackendIdentifier } from '@aws-amplify/plugin-types'; +import { RegionFetcher } from '@aws-amplify/platform-core'; +import { createFriendlyName } from '../logging/cloudformation_format.js'; + +import { + ResourceWithFriendlyName, + getAwsConsoleUrl, + isCompleteResource, +} from '../resource_console_functions.js'; + +/** + * Type for deployed backend resources response + */ +export type DeployedBackendResources = { + name: string; + status: string; + resources: ResourceWithFriendlyName[]; + region: string | null; + message?: string; +}; + +/** + * Service for managing backend resources + */ +export class ResourceService { + /** + * Creates a new ResourceService + */ + constructor( + private readonly backendName: string, + private readonly backendClient: DeployedBackendClient, + private readonly namespace: string = 'amplify-backend', // Add namespace parameter with default + private readonly regionFetcher: RegionFetcher = new RegionFetcher(), + private readonly printer: Printer = printerUtil, + ) {} + + /** + * Gets the deployed backend resources + * @returns The deployed backend resources with friendly names + */ + public async getDeployedBackendResources(): Promise { + try { + try { + this.printer.log('Fetching backend metadata...', LogLevel.DEBUG); + // Create a BackendIdentifier object for the sandbox + const backendId: BackendIdentifier = { + namespace: this.namespace, // Use the provided namespace + name: this.backendName, + type: 'sandbox', + }; + const data = await this.backendClient.getBackendMetadata(backendId); + this.printer.log( + 'Successfully fetched backend metadata', + LogLevel.DEBUG, + ); + + // Get the AWS region using RegionFetcher + let region: string | null = null; + try { + region = (await this.regionFetcher.fetch()) ?? null; + } catch (error) { + this.printer.log('Error getting region: ' + error, LogLevel.ERROR); + region = null; + } + + // Process resources and add friendly names + const resourcesWithFriendlyNames = data.resources + .filter(isCompleteResource) + .map((resource) => { + let resourceType = resource.resourceType; + + // Remove CUSTOM:: prefix from resource type + if (resourceType.startsWith('CUSTOM::')) { + resourceType = resourceType.substring(8); // Remove "CUSTOM::" (8 characters) + } else if (resourceType.startsWith('Custom::')) { + resourceType = resourceType.substring(8); // Remove "Custom::" (8 characters) + } + + // Check if the resource has metadata with a construct path + // Use a type guard to check if the resource has a metadata property + let metadata = undefined; + + if ('metadata' in resource) { + if ( + typeof resource.metadata === 'object' && + resource.metadata !== null && + 'constructPath' in resource.metadata + ) { + metadata = { + constructPath: resource.metadata.constructPath as string, + }; + } + } + + const resourceWithFriendlyName = { + ...resource, + resourceType, + friendlyName: createFriendlyName( + resource.logicalResourceId, + metadata, + ), + } as ResourceWithFriendlyName; + + // Add console URL + resourceWithFriendlyName.consoleUrl = getAwsConsoleUrl( + resourceWithFriendlyName, + region, + ); + + return resourceWithFriendlyName; + }); + + // Add region and resources with friendly names to the data + const enhancedData = { + ...data, + region, + resources: resourcesWithFriendlyNames, + }; + + return enhancedData; + } catch (error) { + const errorMessage = String(error); + this.printer.log( + `Error getting backend resources: ${errorMessage}`, + LogLevel.ERROR, + ); + + // Check if this is a deployment in progress error + if (errorMessage.includes('deployment is in progress')) { + return { + name: this.backendName, + status: 'deploying', + resources: [], + region: null, + message: + 'Sandbox deployment is in progress. Resources will update when deployment completes.', + }; + } else if (errorMessage.includes('does not exist')) { + // If the stack doesn't exist, return empty resources + return { + name: this.backendName, + status: 'nonexistent', + resources: [], + region: null, + message: 'No sandbox exists. Please create a sandbox first.', + }; + } + // For other errors, throw the error + throw error; + } + } catch (error) { + this.printer.log( + `Error checking sandbox status: ${String(error)}`, + LogLevel.ERROR, + ); + throw error; + } + } +} diff --git a/packages/cli/src/commands/sandbox/sandbox-devtools/services/shutdown_service.ts b/packages/cli/src/commands/sandbox/sandbox-devtools/services/shutdown_service.ts new file mode 100644 index 00000000000..c9a5b00c51a --- /dev/null +++ b/packages/cli/src/commands/sandbox/sandbox-devtools/services/shutdown_service.ts @@ -0,0 +1,80 @@ +import { LogLevel, Printer } from '@aws-amplify/cli-core'; +import { Server as SocketIOServer } from 'socket.io'; +import { Server as HttpServer } from 'node:http'; +import { Sandbox } from '@aws-amplify/sandbox'; + +/** + * Service for handling the shutdown process of the DevTools server + */ +export class ShutdownService { + /** + * Creates a new ShutdownService + * @param io The Socket.IO server + * @param server The HTTP server + * @param storageManager The local storage manager + * @param storageManager.clearAll Function to clear all stored data + * @param sandbox The sandbox instance + * @param getSandboxState Function to get the current sandbox state + * @param printer Printer for console output + */ + constructor( + private readonly io: SocketIOServer, + private readonly server: HttpServer, + private readonly storageManager: { clearAll: () => void }, + private readonly sandbox: Sandbox, + private readonly getSandboxState: () => Promise, + private readonly printer: Printer, + ) {} + + /** + * Performs the shutdown process + * @param reason The reason for shutting down (e.g., 'SIGINT', 'SIGTERM', 'user request') + * @param exitProcess Whether to exit the process after shutdown + */ + public async shutdown( + reason: string, + exitProcess: boolean = false, + ): Promise { + this.printer.print(`\nStopping the devtools server (${String(reason)}).`); + + // Check if sandbox is running and stop it + const status = await this.getSandboxState(); + + if (status === 'running') { + this.printer.log('Stopping sandbox before exiting...', LogLevel.DEBUG); + try { + this.printer.log( + `Stopping sandbox from ${reason} handler`, + LogLevel.DEBUG, + ); + await this.sandbox.stop(); + this.printer.log('Sandbox stopped successfully', LogLevel.INFO); + } catch (error) { + this.printer.log( + `Error stopping sandbox: ${String(error)}`, + LogLevel.ERROR, + ); + if (error instanceof Error && error.stack) { + this.printer.log(`Error stack: ${error.stack}`, LogLevel.DEBUG); + } + } + } + + // Clear all stored resources when devtools ends + this.storageManager.clearAll(); + + await this.io.close(); + + // Properly wait for the HTTP server to close + await new Promise((resolve) => { + void this.server.close(() => resolve()); + }); + + // Exit the process if requested + if (exitProcess) { + process.exit(0); + } + + return Promise.resolve(); + } +} diff --git a/packages/cli/src/commands/sandbox/sandbox-devtools/services/socket_handlers.test.ts b/packages/cli/src/commands/sandbox/sandbox-devtools/services/socket_handlers.test.ts new file mode 100644 index 00000000000..c1823d38e51 --- /dev/null +++ b/packages/cli/src/commands/sandbox/sandbox-devtools/services/socket_handlers.test.ts @@ -0,0 +1,953 @@ +import { beforeEach, describe, it, mock } from 'node:test'; +import assert from 'node:assert'; +import { SocketHandlerService } from './socket_handlers.js'; +import { printer } from '@aws-amplify/cli-core'; +import type { Server, Socket } from 'socket.io'; +import type { ResourceService } from './resource_service.js'; +import type { ShutdownService } from './shutdown_service.js'; +import type { Sandbox } from '@aws-amplify/sandbox'; +import { SOCKET_EVENTS } from '../shared/socket_events.js'; +import { ClientConfigFormat } from '@aws-amplify/client-config'; + +// Define the return type of mock.fn() +type MockFn = ReturnType; + +// Type for handler functions +// eslint-disable-next-line @typescript-eslint/no-explicit-any +type EventHandler = (...args: any[]) => void | Promise; + +// Type for sandbox status data +type SandboxStatusData = { + status: string; + identifier: string; + error?: string; + timestamp?: string; + message?: string; +}; + +// Type for backend resources data +type BackendResourcesData = { + name: string; + status: string; + resources: unknown[]; + region: string | null; + message?: string; + error?: string; +}; + +// Mock call type with more specific typing +// eslint-disable-next-line @typescript-eslint/no-explicit-any +type MockCall = { + arguments: readonly unknown[]; +}; + +void describe('SocketHandlerService', () => { + let service: SocketHandlerService; + let mockIo: Server; + let mockSocket: Socket; + let mockSandbox: Sandbox; + let mockShutdownService: ShutdownService; + let mockResourceService: ResourceService; + let mockGetSandboxState: () => Promise; + + beforeEach(() => { + mock.reset(); + mock.method(printer, 'log'); + + mockIo = { emit: mock.fn() } as unknown as Server; + mockSocket = { on: mock.fn(), emit: mock.fn() } as unknown as Socket; + mockSandbox = { + start: mock.fn(() => Promise.resolve()), + stop: mock.fn(() => Promise.resolve()), + delete: mock.fn(() => Promise.resolve()), + } as unknown as Sandbox; + mockShutdownService = { shutdown: mock.fn() } as unknown as ShutdownService; + mockResourceService = { + getDeployedBackendResources: mock.fn(() => + Promise.resolve({ + name: 'test-backend', + status: 'running', + resources: [], + region: 'us-east-1', + }), + ), + } as unknown as ResourceService; + mockGetSandboxState = mock.fn(() => Promise.resolve('running')); + + service = new SocketHandlerService( + mockIo, + mockSandbox, + mockGetSandboxState, + { name: 'test-backend' }, + mockShutdownService, + mockResourceService, + ); + }); + + void describe('setupSocketHandlers', () => { + void it('registers all socket event handlers', () => { + service.setupSocketHandlers(mockSocket); + const mockFn = mockSocket.on as unknown as MockFn; + const eventNames = mockFn.mock.calls.map( + (call: MockCall) => call.arguments[0] as string, + ); + + // Verify all expected handlers are registered + const expectedHandlers = [ + SOCKET_EVENTS.GET_SANDBOX_STATUS, + SOCKET_EVENTS.GET_DEPLOYED_BACKEND_RESOURCES, + SOCKET_EVENTS.GET_CUSTOM_FRIENDLY_NAMES, + SOCKET_EVENTS.UPDATE_CUSTOM_FRIENDLY_NAME, + SOCKET_EVENTS.REMOVE_CUSTOM_FRIENDLY_NAME, + SOCKET_EVENTS.START_SANDBOX_WITH_OPTIONS, + SOCKET_EVENTS.STOP_SANDBOX, + SOCKET_EVENTS.DELETE_SANDBOX, + SOCKET_EVENTS.STOP_DEV_TOOLS, + ]; + + expectedHandlers.forEach((handler) => { + assert.ok( + eventNames.includes(handler), + `Handler "${handler}" should be registered`, + ); + }); + + // Verify the exact number of handlers + assert.strictEqual( + eventNames.length, + expectedHandlers.length, + `Expected ${expectedHandlers.length} handlers to be registered, got ${eventNames.length}`, + ); + }); + }); + + void describe('handleGetSandboxStatus', () => { + void it('emits sandbox status', async () => { + service.setupSocketHandlers(mockSocket); + const mockOnFn = mockSocket.on as unknown as MockFn; + const foundCall = mockOnFn.mock.calls.find( + (call: MockCall) => + call.arguments[0] === SOCKET_EVENTS.GET_SANDBOX_STATUS, + ); + + assert.ok(foundCall, 'Could not find getSandboxStatus handler'); + const handler = foundCall?.arguments[1] as EventHandler; + + await handler(); + + const mockEmitFn = mockSocket.emit as unknown as MockFn; + assert.strictEqual(mockEmitFn.mock.callCount(), 1); + + // Check if there are any calls before accessing + assert.ok( + mockEmitFn.mock.calls.length > 0, + 'Should have at least one emit call', + ); + assert.strictEqual( + mockEmitFn.mock.calls[0].arguments[0], + SOCKET_EVENTS.SANDBOX_STATUS, + ); + + const statusData = mockEmitFn.mock.calls[0] + .arguments[1] as SandboxStatusData; + assert.strictEqual(statusData.status, 'running'); + assert.strictEqual(statusData.identifier, 'test-backend'); + }); + + void it('handles errors when getting sandbox status', async () => { + // Setup a sandbox state getter that throws an error + const errorMessage = 'Failed to get sandbox state'; + const errorService = new SocketHandlerService( + mockIo, + mockSandbox, + async () => { + throw new Error(errorMessage); + }, + { name: 'test-backend' }, + mockShutdownService, + mockResourceService, + ); + + errorService.setupSocketHandlers(mockSocket); + const mockOnFn = mockSocket.on as unknown as MockFn; + const foundCall = mockOnFn.mock.calls.find( + (call: MockCall) => + call.arguments[0] === SOCKET_EVENTS.GET_SANDBOX_STATUS, + ); + + assert.ok(foundCall, 'Could not find getSandboxStatus handler'); + const handler = foundCall?.arguments[1] as EventHandler; + + await handler(); + + const mockEmitFn = mockSocket.emit as unknown as MockFn; + assert.strictEqual(mockEmitFn.mock.callCount(), 1); + + // Check if there are any calls before accessing + assert.ok( + mockEmitFn.mock.calls.length > 0, + 'Should have at least one emit call', + ); + assert.strictEqual( + mockEmitFn.mock.calls[0].arguments[0], + SOCKET_EVENTS.SANDBOX_STATUS, + ); + + const statusData = mockEmitFn.mock.calls[0] + .arguments[1] as SandboxStatusData; + assert.strictEqual(statusData.status, 'unknown'); + assert.strictEqual(statusData.identifier, 'test-backend'); + assert.strictEqual(statusData.error, `Error: ${errorMessage}`); + }); + }); + + void describe('handleGetDeployedBackendResources', () => { + void it('emits deployed backend resources when sandbox is running', async () => { + const mockResources = { + name: 'test-backend', + status: 'running', + resources: [{ id: 'resource1' }], + region: 'us-east-1', + }; + + ( + mockResourceService.getDeployedBackendResources as unknown as MockFn + ).mock.mockImplementation(() => Promise.resolve(mockResources)); + + service.setupSocketHandlers(mockSocket); + const mockOnFn = mockSocket.on as unknown as MockFn; + const foundCall = mockOnFn.mock.calls.find( + (call: MockCall) => + call.arguments[0] === SOCKET_EVENTS.GET_DEPLOYED_BACKEND_RESOURCES, + ); + + assert.ok( + foundCall, + 'Could not find getDeployedBackendResources handler', + ); + const handler = foundCall?.arguments[1] as EventHandler; + + await handler(); + + const mockEmitFn = mockSocket.emit as unknown as MockFn; + assert.strictEqual(mockEmitFn.mock.callCount(), 1); + + assert.ok( + mockEmitFn.mock.calls.length > 0, + 'Should have at least one emit call', + ); + assert.strictEqual( + mockEmitFn.mock.calls[0].arguments[0], + SOCKET_EVENTS.DEPLOYED_BACKEND_RESOURCES, + ); + + const emittedData = mockEmitFn.mock.calls[0] + .arguments[1] as BackendResourcesData; + assert.strictEqual(emittedData.name, 'test-backend'); + assert.strictEqual(emittedData.status, 'running'); + assert.deepStrictEqual(emittedData.resources, [{ id: 'resource1' }]); + assert.strictEqual(emittedData.region, 'us-east-1'); + }); + + void it('handles deployment in progress error', async () => { + ( + mockResourceService.getDeployedBackendResources as unknown as MockFn + ).mock.mockImplementation(() => + Promise.reject(new Error('deployment is in progress')), + ); + + service.setupSocketHandlers(mockSocket); + const mockOnFn = mockSocket.on as unknown as MockFn; + const foundCall = mockOnFn.mock.calls.find( + (call: MockCall) => + call.arguments[0] === SOCKET_EVENTS.GET_DEPLOYED_BACKEND_RESOURCES, + ); + + assert.ok( + foundCall, + 'Could not find getDeployedBackendResources handler', + ); + const handler = foundCall?.arguments[1] as EventHandler; + + await handler(); + + const mockEmitFn = mockSocket.emit as unknown as MockFn; + assert.strictEqual(mockEmitFn.mock.callCount(), 1); + + assert.ok( + mockEmitFn.mock.calls.length > 0, + 'Should have at least one emit call', + ); + assert.strictEqual( + mockEmitFn.mock.calls[0].arguments[0], + SOCKET_EVENTS.DEPLOYED_BACKEND_RESOURCES, + ); + + const emittedData = mockEmitFn.mock.calls[0] + .arguments[1] as BackendResourcesData; + assert.strictEqual(emittedData.status, 'deploying'); + assert.strictEqual(emittedData.name, 'test-backend'); + assert.deepStrictEqual(emittedData.resources, []); + assert.strictEqual(emittedData.region, null); + assert.ok(emittedData.message?.includes('deployment is in progress')); + }); + + void it('handles does not exist error', async () => { + ( + mockResourceService.getDeployedBackendResources as unknown as MockFn + ).mock.mockImplementation(() => + Promise.reject(new Error('does not exist')), + ); + + service.setupSocketHandlers(mockSocket); + const mockOnFn = mockSocket.on as unknown as MockFn; + const foundCall = mockOnFn.mock.calls.find( + (call: MockCall) => + call.arguments[0] === SOCKET_EVENTS.GET_DEPLOYED_BACKEND_RESOURCES, + ); + + assert.ok( + foundCall, + 'Could not find getDeployedBackendResources handler', + ); + const handler = foundCall?.arguments[1] as EventHandler; + + await handler(); + + const mockEmitFn = mockSocket.emit as unknown as MockFn; + assert.strictEqual(mockEmitFn.mock.callCount(), 1); + + assert.ok( + mockEmitFn.mock.calls.length > 0, + 'Should have at least one emit call', + ); + assert.strictEqual( + mockEmitFn.mock.calls[0].arguments[0], + SOCKET_EVENTS.DEPLOYED_BACKEND_RESOURCES, + ); + + const emittedData = mockEmitFn.mock.calls[0] + .arguments[1] as BackendResourcesData; + assert.strictEqual(emittedData.status, 'nonexistent'); + assert.strictEqual(emittedData.name, 'test-backend'); + assert.deepStrictEqual(emittedData.resources, []); + assert.strictEqual(emittedData.region, null); + assert.ok(emittedData.message?.includes('No sandbox exists')); + }); + + void it('handles other errors', async () => { + ( + mockResourceService.getDeployedBackendResources as unknown as MockFn + ).mock.mockImplementation(() => + Promise.reject(new Error('some other error')), + ); + + service.setupSocketHandlers(mockSocket); + const mockOnFn = mockSocket.on as unknown as MockFn; + const foundCall = mockOnFn.mock.calls.find( + (call: MockCall) => + call.arguments[0] === SOCKET_EVENTS.GET_DEPLOYED_BACKEND_RESOURCES, + ); + + assert.ok( + foundCall, + 'Could not find getDeployedBackendResources handler', + ); + const handler = foundCall?.arguments[1] as EventHandler; + + await handler(); + + const mockEmitFn = mockSocket.emit as unknown as MockFn; + assert.strictEqual(mockEmitFn.mock.callCount(), 1); + + assert.ok( + mockEmitFn.mock.calls.length > 0, + 'Should have at least one emit call', + ); + assert.strictEqual( + mockEmitFn.mock.calls[0].arguments[0], + SOCKET_EVENTS.DEPLOYED_BACKEND_RESOURCES, + ); + + const emittedData = mockEmitFn.mock.calls[0] + .arguments[1] as BackendResourcesData; + assert.strictEqual(emittedData.status, 'error'); + assert.strictEqual(emittedData.name, 'test-backend'); + assert.deepStrictEqual(emittedData.resources, []); + assert.strictEqual(emittedData.region, null); + assert.ok(emittedData.message?.includes('Error fetching resources')); + assert.strictEqual(emittedData.error, 'Error: some other error'); + }); + + void it('emits appropriate status when sandbox is not running', async () => { + (mockGetSandboxState as unknown as MockFn).mock.mockImplementation(() => + Promise.resolve('nonexistent'), + ); + + service.setupSocketHandlers(mockSocket); + const mockOnFn = mockSocket.on as unknown as MockFn; + const foundCall = mockOnFn.mock.calls.find( + (call: MockCall) => + call.arguments[0] === SOCKET_EVENTS.GET_DEPLOYED_BACKEND_RESOURCES, + ); + + assert.ok( + foundCall, + 'Could not find getDeployedBackendResources handler', + ); + const handler = foundCall?.arguments[1] as EventHandler; + + await handler(); + + const mockEmitFn = mockSocket.emit as unknown as MockFn; + assert.strictEqual(mockEmitFn.mock.callCount(), 1); + + assert.ok( + mockEmitFn.mock.calls.length > 0, + 'Should have at least one emit call', + ); + assert.strictEqual( + mockEmitFn.mock.calls[0].arguments[0], + SOCKET_EVENTS.DEPLOYED_BACKEND_RESOURCES, + ); + + const emittedData = mockEmitFn.mock.calls[0] + .arguments[1] as BackendResourcesData; + assert.strictEqual(emittedData.status, 'nonexistent'); + assert.strictEqual(emittedData.name, 'test-backend'); + assert.deepStrictEqual(emittedData.resources, []); + assert.strictEqual(emittedData.region, null); + assert.ok(emittedData.message?.includes('No sandbox exists')); + }); + + void it('handles errors when getting sandbox state', async () => { + (mockGetSandboxState as unknown as MockFn).mock.mockImplementation(() => + Promise.reject(new Error('state error')), + ); + + service.setupSocketHandlers(mockSocket); + const mockOnFn = mockSocket.on as unknown as MockFn; + const foundCall = mockOnFn.mock.calls.find( + (call: MockCall) => + call.arguments[0] === SOCKET_EVENTS.GET_DEPLOYED_BACKEND_RESOURCES, + ); + + assert.ok( + foundCall, + 'Could not find getDeployedBackendResources handler', + ); + const handler = foundCall?.arguments[1] as EventHandler; + + await handler(); + + const mockEmitFn = mockSocket.emit as unknown as MockFn; + assert.strictEqual(mockEmitFn.mock.callCount(), 1); + + assert.ok( + mockEmitFn.mock.calls.length > 0, + 'Should have at least one emit call', + ); + assert.strictEqual( + mockEmitFn.mock.calls[0].arguments[0], + SOCKET_EVENTS.DEPLOYED_BACKEND_RESOURCES, + ); + + const emittedData = mockEmitFn.mock.calls[0] + .arguments[1] as BackendResourcesData; + assert.strictEqual(emittedData.status, 'error'); + assert.strictEqual(emittedData.name, 'test-backend'); + assert.deepStrictEqual(emittedData.resources, []); + assert.strictEqual(emittedData.region, null); + assert.ok(emittedData.message?.includes('Error checking sandbox status')); + assert.strictEqual(emittedData.error, 'Error: state error'); + }); + }); + + void describe('handleGetCustomFriendlyNames', () => { + void it('emits empty object for custom friendly names', () => { + service.setupSocketHandlers(mockSocket); + const mockOnFn = mockSocket.on as unknown as MockFn; + const foundCall = mockOnFn.mock.calls.find( + (call: MockCall) => + call.arguments[0] === SOCKET_EVENTS.GET_CUSTOM_FRIENDLY_NAMES, + ); + + assert.ok(foundCall, 'Could not find getCustomFriendlyNames handler'); + const handler = foundCall?.arguments[1] as EventHandler; + + void handler(); + + const mockEmitFn = mockSocket.emit as unknown as MockFn; + assert.strictEqual(mockEmitFn.mock.callCount(), 1); + + assert.ok( + mockEmitFn.mock.calls.length > 0, + 'Should have at least one emit call', + ); + assert.strictEqual( + mockEmitFn.mock.calls[0].arguments[0], + SOCKET_EVENTS.CUSTOM_FRIENDLY_NAMES, + ); + + const emittedData = mockEmitFn.mock.calls[0].arguments[1] as Record< + string, + string + >; + assert.deepStrictEqual(emittedData, {}); + }); + }); + + void describe('handleUpdateCustomFriendlyName', () => { + void it('emits custom friendly name updated event', () => { + service.setupSocketHandlers(mockSocket); + const mockOnFn = mockSocket.on as unknown as MockFn; + const foundCall = mockOnFn.mock.calls.find( + (call: MockCall) => + call.arguments[0] === SOCKET_EVENTS.UPDATE_CUSTOM_FRIENDLY_NAME, + ); + + assert.ok(foundCall, 'Could not find updateCustomFriendlyName handler'); + const handler = foundCall?.arguments[1] as EventHandler; + + const testData = { + resourceId: 'test-resource', + friendlyName: 'Test Resource', + }; + void handler(testData); + + const mockIoEmitFn = mockIo.emit as unknown as MockFn; + assert.strictEqual(mockIoEmitFn.mock.callCount(), 1); + + assert.ok( + mockIoEmitFn.mock.calls.length > 0, + 'Should have at least one io.emit call', + ); + assert.strictEqual( + mockIoEmitFn.mock.calls[0].arguments[0], + SOCKET_EVENTS.CUSTOM_FRIENDLY_NAME_UPDATED, + ); + + const emittedData = mockIoEmitFn.mock.calls[0].arguments[1] as { + resourceId: string; + friendlyName: string; + }; + assert.deepStrictEqual(emittedData, testData); + }); + + void it('does nothing when data is invalid', () => { + service.setupSocketHandlers(mockSocket); + const mockOnFn = mockSocket.on as unknown as MockFn; + const foundCall = mockOnFn.mock.calls.find( + (call: MockCall) => + call.arguments[0] === SOCKET_EVENTS.UPDATE_CUSTOM_FRIENDLY_NAME, + ); + + assert.ok(foundCall, 'Could not find updateCustomFriendlyName handler'); + const handler = foundCall?.arguments[1] as EventHandler; + + // Call with invalid data + void handler(null); + + const mockIoEmitFn = mockIo.emit as unknown as MockFn; + assert.strictEqual(mockIoEmitFn.mock.callCount(), 0); + }); + }); + + void describe('handleRemoveCustomFriendlyName', () => { + void it('emits custom friendly name removed event', () => { + service.setupSocketHandlers(mockSocket); + const mockOnFn = mockSocket.on as unknown as MockFn; + const foundCall = mockOnFn.mock.calls.find( + (call: MockCall) => + call.arguments[0] === SOCKET_EVENTS.REMOVE_CUSTOM_FRIENDLY_NAME, + ); + + assert.ok(foundCall, 'Could not find removeCustomFriendlyName handler'); + const handler = foundCall?.arguments[1] as EventHandler; + + const testData = { + resourceId: 'test-resource', + }; + void handler(testData); + + const mockIoEmitFn = mockIo.emit as unknown as MockFn; + assert.strictEqual(mockIoEmitFn.mock.callCount(), 1); + + assert.ok( + mockIoEmitFn.mock.calls.length > 0, + 'Should have at least one io.emit call', + ); + assert.strictEqual( + mockIoEmitFn.mock.calls[0].arguments[0], + SOCKET_EVENTS.CUSTOM_FRIENDLY_NAME_REMOVED, + ); + + const emittedData = mockIoEmitFn.mock.calls[0].arguments[1] as { + resourceId: string; + }; + assert.deepStrictEqual(emittedData, testData); + }); + + void it('does nothing when data is invalid', () => { + service.setupSocketHandlers(mockSocket); + const mockOnFn = mockSocket.on as unknown as MockFn; + const foundCall = mockOnFn.mock.calls.find( + (call: MockCall) => + call.arguments[0] === SOCKET_EVENTS.REMOVE_CUSTOM_FRIENDLY_NAME, + ); + + assert.ok(foundCall, 'Could not find removeCustomFriendlyName handler'); + const handler = foundCall?.arguments[1] as EventHandler; + + // Call with invalid data + void handler(null); + + const mockIoEmitFn = mockIo.emit as unknown as MockFn; + assert.strictEqual(mockIoEmitFn.mock.callCount(), 0); + }); + }); + + void describe('handleStartSandboxWithOptions', () => { + void it('starts sandbox with default options', async () => { + service.setupSocketHandlers(mockSocket); + const mockOnFn = mockSocket.on as unknown as MockFn; + const foundCall = mockOnFn.mock.calls.find( + (call: MockCall) => + call.arguments[0] === SOCKET_EVENTS.START_SANDBOX_WITH_OPTIONS, + ); + + assert.ok(foundCall, 'Could not find startSandboxWithOptions handler'); + const handler = foundCall?.arguments[1] as EventHandler; + + await handler({}); + + // Verify socket emit was called with deploying status + const mockEmitFn = mockSocket.emit as unknown as MockFn; + assert.strictEqual(mockEmitFn.mock.callCount(), 1); + + assert.ok( + mockEmitFn.mock.calls.length > 0, + 'Should have at least one emit call', + ); + assert.strictEqual( + mockEmitFn.mock.calls[0].arguments[0], + SOCKET_EVENTS.SANDBOX_STATUS, + ); + + const statusData = mockEmitFn.mock.calls[0] + .arguments[1] as SandboxStatusData; + assert.strictEqual(statusData.status, 'deploying'); + assert.strictEqual(statusData.identifier, 'test-backend'); + assert.strictEqual(statusData.message, 'Starting sandbox...'); + + // Verify sandbox.start was called with correct options + const mockStartFn = mockSandbox.start as unknown as MockFn; + assert.strictEqual(mockStartFn.mock.callCount(), 1); + + assert.ok( + mockStartFn.mock.calls.length > 0, + 'Should have at least one start call', + ); + const startOptions = mockStartFn.mock.calls[0].arguments[0] as { + dir: string; + watchForChanges: boolean; + }; + assert.strictEqual(startOptions.dir, './amplify'); + assert.strictEqual(startOptions.watchForChanges, true); + }); + + void it('starts sandbox with custom options', async () => { + service.setupSocketHandlers(mockSocket); + const mockOnFn = mockSocket.on as unknown as MockFn; + const foundCall = mockOnFn.mock.calls.find( + (call: MockCall) => + call.arguments[0] === SOCKET_EVENTS.START_SANDBOX_WITH_OPTIONS, + ); + + assert.ok(foundCall, 'Could not find startSandboxWithOptions handler'); + const handler = foundCall?.arguments[1] as EventHandler; + + const options = { + identifier: 'custom-backend', + dirToWatch: './custom-dir', + exclude: 'node_modules,dist', + once: true, + outputsFormat: 'typescript' as ClientConfigFormat, + streamFunctionLogs: true, + logsFilter: 'function1,function2', + logsOutFile: 'logs.txt', + }; + await handler(options); + + // Verify socket emit was called with deploying status + const mockEmitFn = mockSocket.emit as unknown as MockFn; + assert.strictEqual(mockEmitFn.mock.callCount(), 1); + + assert.ok( + mockEmitFn.mock.calls.length > 0, + 'Should have at least one emit call', + ); + assert.strictEqual( + mockEmitFn.mock.calls[0].arguments[0], + SOCKET_EVENTS.SANDBOX_STATUS, + ); + + const statusData = mockEmitFn.mock.calls[0] + .arguments[1] as SandboxStatusData; + assert.strictEqual(statusData.status, 'deploying'); + assert.strictEqual(statusData.identifier, 'custom-backend'); + assert.strictEqual(statusData.message, 'Starting sandbox...'); + + // Verify sandbox.start was called with correct options + const mockStartFn = mockSandbox.start as unknown as MockFn; + assert.strictEqual(mockStartFn.mock.callCount(), 1); + + assert.ok( + mockStartFn.mock.calls.length > 0, + 'Should have at least one start call', + ); + const startOptions = mockStartFn.mock.calls[0].arguments[0] as { + dir: string; + identifier: string; + exclude: string[]; + format: string; + watchForChanges: boolean; + functionStreamingOptions: { + enabled: boolean; + logsFilters: string[]; + logsOutFile: string; + }; + }; + assert.strictEqual(startOptions.dir, './custom-dir'); + assert.strictEqual(startOptions.identifier, 'custom-backend'); + assert.deepStrictEqual(startOptions.exclude, ['node_modules', 'dist']); + assert.strictEqual(startOptions.format, 'typescript'); + assert.strictEqual(startOptions.watchForChanges, false); + assert.deepStrictEqual(startOptions.functionStreamingOptions, { + enabled: true, + logsFilters: ['function1', 'function2'], + logsOutFile: 'logs.txt', + }); + }); + + void it('handles errors when starting sandbox', async () => { + const errorMessage = 'Failed to start sandbox'; + (mockSandbox.start as unknown as MockFn).mock.mockImplementation(() => + Promise.reject(new Error(errorMessage)), + ); + + service.setupSocketHandlers(mockSocket); + const mockOnFn = mockSocket.on as unknown as MockFn; + const foundCall = mockOnFn.mock.calls.find( + (call: MockCall) => + call.arguments[0] === SOCKET_EVENTS.START_SANDBOX_WITH_OPTIONS, + ); + + assert.ok(foundCall, 'Could not find startSandboxWithOptions handler'); + const handler = foundCall?.arguments[1] as EventHandler; + + await handler({}); + + // Verify socket emit was called with error status + const mockEmitFn = mockSocket.emit as unknown as MockFn; + assert.strictEqual(mockEmitFn.mock.callCount(), 2); // First for deploying, then for error + + assert.ok( + mockEmitFn.mock.calls.length > 1, + 'Should have at least two emit calls', + ); + assert.strictEqual( + mockEmitFn.mock.calls[1].arguments[0], + SOCKET_EVENTS.SANDBOX_STATUS, + ); + + const statusData = mockEmitFn.mock.calls[1] + .arguments[1] as SandboxStatusData; + assert.strictEqual(statusData.status, 'error'); + assert.strictEqual(statusData.identifier, 'test-backend'); + assert.strictEqual(statusData.error, `Error: ${errorMessage}`); + }); + }); + + void describe('handleStopSandbox', () => { + void it('stops sandbox and emits status', async () => { + service.setupSocketHandlers(mockSocket); + const mockOnFn = mockSocket.on as unknown as MockFn; + const foundCall = mockOnFn.mock.calls.find( + (call: MockCall) => call.arguments[0] === SOCKET_EVENTS.STOP_SANDBOX, + ); + + assert.ok(foundCall, 'Could not find stopSandbox handler'); + const handler = foundCall?.arguments[1] as EventHandler; + + await handler(); + + // Verify sandbox.stop was called + const mockStopFn = mockSandbox.stop as unknown as MockFn; + assert.strictEqual(mockStopFn.mock.callCount(), 1); + + // Verify socket emit was called with stopped status + const mockEmitFn = mockSocket.emit as unknown as MockFn; + assert.strictEqual(mockEmitFn.mock.callCount(), 1); + + assert.ok( + mockEmitFn.mock.calls.length > 0, + 'Should have at least one emit call', + ); + assert.strictEqual( + mockEmitFn.mock.calls[0].arguments[0], + SOCKET_EVENTS.SANDBOX_STATUS, + ); + + const statusData = mockEmitFn.mock.calls[0] + .arguments[1] as SandboxStatusData; + assert.strictEqual(statusData.status, 'stopped'); + assert.strictEqual(statusData.identifier, 'test-backend'); + assert.strictEqual(statusData.message, 'Sandbox stopped successfully'); + }); + + void it('handles errors when stopping sandbox', async () => { + const errorMessage = 'Failed to stop sandbox'; + (mockSandbox.stop as unknown as MockFn).mock.mockImplementation(() => + Promise.reject(new Error(errorMessage)), + ); + + service.setupSocketHandlers(mockSocket); + const mockOnFn = mockSocket.on as unknown as MockFn; + const foundCall = mockOnFn.mock.calls.find( + (call: MockCall) => call.arguments[0] === SOCKET_EVENTS.STOP_SANDBOX, + ); + + assert.ok(foundCall, 'Could not find stopSandbox handler'); + const handler = foundCall?.arguments[1] as EventHandler; + + await handler(); + + // Verify socket emit was called with error status + const mockEmitFn = mockSocket.emit as unknown as MockFn; + assert.strictEqual(mockEmitFn.mock.callCount(), 1); + + assert.ok( + mockEmitFn.mock.calls.length > 0, + 'Should have at least one emit call', + ); + assert.strictEqual( + mockEmitFn.mock.calls[0].arguments[0], + SOCKET_EVENTS.SANDBOX_STATUS, + ); + + const statusData = mockEmitFn.mock.calls[0] + .arguments[1] as SandboxStatusData; + assert.strictEqual(statusData.status, 'error'); + assert.strictEqual(statusData.identifier, 'test-backend'); + assert.strictEqual(statusData.error, `Error: ${errorMessage}`); + }); + }); + + void describe('handleDeleteSandbox', () => { + void it('deletes sandbox and emits status', async () => { + service.setupSocketHandlers(mockSocket); + const mockOnFn = mockSocket.on as unknown as MockFn; + const foundCall = mockOnFn.mock.calls.find( + (call: MockCall) => call.arguments[0] === SOCKET_EVENTS.DELETE_SANDBOX, + ); + + assert.ok(foundCall, 'Could not find deleteSandbox handler'); + const handler = foundCall?.arguments[1] as EventHandler; + + await handler(); + + // Verify sandbox.delete was called with correct identifier + const mockDeleteFn = mockSandbox.delete as unknown as MockFn; + assert.strictEqual(mockDeleteFn.mock.callCount(), 1); + assert.deepStrictEqual(mockDeleteFn.mock.calls[0].arguments[0], { + identifier: 'test-backend', + }); + + // Verify socket emit was called with deleting status + const mockEmitFn = mockSocket.emit as unknown as MockFn; + assert.strictEqual(mockEmitFn.mock.callCount(), 1); + + assert.ok( + mockEmitFn.mock.calls.length > 0, + 'Should have at least one emit call', + ); + assert.strictEqual( + mockEmitFn.mock.calls[0].arguments[0], + SOCKET_EVENTS.SANDBOX_STATUS, + ); + + const statusData = mockEmitFn.mock.calls[0] + .arguments[1] as SandboxStatusData; + assert.strictEqual(statusData.status, 'deleting'); + assert.strictEqual(statusData.identifier, 'test-backend'); + assert.strictEqual(statusData.message, 'Deleting sandbox...'); + }); + + void it('handles errors when deleting sandbox', async () => { + const errorMessage = 'Failed to delete sandbox'; + (mockSandbox.delete as unknown as MockFn).mock.mockImplementation(() => + Promise.reject(new Error(errorMessage)), + ); + + service.setupSocketHandlers(mockSocket); + const mockOnFn = mockSocket.on as unknown as MockFn; + const foundCall = mockOnFn.mock.calls.find( + (call: MockCall) => call.arguments[0] === SOCKET_EVENTS.DELETE_SANDBOX, + ); + + assert.ok(foundCall, 'Could not find deleteSandbox handler'); + const handler = foundCall?.arguments[1] as EventHandler; + + await handler(); + + // Verify socket emit was called with error status + const mockEmitFn = mockSocket.emit as unknown as MockFn; + assert.strictEqual(mockEmitFn.mock.callCount(), 2); // First for deleting, then for error + + assert.ok( + mockEmitFn.mock.calls.length > 1, + 'Should have at least two emit calls', + ); + assert.strictEqual( + mockEmitFn.mock.calls[1].arguments[0], + SOCKET_EVENTS.SANDBOX_STATUS, + ); + + const statusData = mockEmitFn.mock.calls[1] + .arguments[1] as SandboxStatusData; + assert.strictEqual(statusData.status, 'error'); + assert.strictEqual(statusData.identifier, 'test-backend'); + assert.strictEqual(statusData.error, `Error: ${errorMessage}`); + }); + }); + + void describe('handleStopDevTools', () => { + void it('calls shutdown service', async () => { + service.setupSocketHandlers(mockSocket); + const mockOnFn = mockSocket.on as unknown as MockFn; + const foundCall = mockOnFn.mock.calls.find( + (call: MockCall) => call.arguments[0] === SOCKET_EVENTS.STOP_DEV_TOOLS, + ); + + assert.ok(foundCall, 'Could not find stopDevTools handler'); + const handler = foundCall?.arguments[1] as EventHandler; + + await handler(); + + // Verify shutdownService.shutdown was called with correct parameters + const mockShutdownFn = mockShutdownService.shutdown as unknown as MockFn; + assert.strictEqual(mockShutdownFn.mock.callCount(), 1); + + assert.ok( + mockShutdownFn.mock.calls.length > 0, + 'Should have at least one shutdown call', + ); + assert.strictEqual( + mockShutdownFn.mock.calls[0].arguments[0], + 'user request', + ); + assert.strictEqual(mockShutdownFn.mock.calls[0].arguments[1], true); + }); + }); +}); diff --git a/packages/cli/src/commands/sandbox/sandbox-devtools/services/socket_handlers.ts b/packages/cli/src/commands/sandbox/sandbox-devtools/services/socket_handlers.ts new file mode 100644 index 00000000000..58f1725910a --- /dev/null +++ b/packages/cli/src/commands/sandbox/sandbox-devtools/services/socket_handlers.ts @@ -0,0 +1,410 @@ +import { + LogLevel, + Printer, + printer as printerUtil, +} from '@aws-amplify/cli-core'; +import { Server, Socket } from 'socket.io'; +import { Sandbox, SandboxOptions } from '@aws-amplify/sandbox'; +import { ClientConfigFormat } from '@aws-amplify/client-config'; +import { ResourceService } from './resource_service.js'; +import { SOCKET_EVENTS } from '../shared/socket_events.js'; +import { ShutdownService } from './shutdown_service.js'; +import { DevToolsSandboxOptions } from '../shared/socket_types.js'; + +// Simple type definitions for PR 2 +export type ResourceWithFriendlyName = { + logicalResourceId: string; + physicalResourceId: string; + resourceType: string; + resourceStatus: string; + friendlyName?: string; +}; + +/** + * Interface for socket event data types + */ +export type SocketEvents = { + getSandboxStatus: void; + deploymentInProgress: { + message: string; + timestamp: string; + }; + getDeployedBackendResources: void; + startSandboxWithOptions: DevToolsSandboxOptions; + stopSandbox: void; + deleteSandbox: void; + stopDevTools: void; + getSavedDeploymentProgress: void; + getSavedResources: void; + getCustomFriendlyNames: void; + updateCustomFriendlyName: { + resourceId: string; + friendlyName: string; + }; + removeCustomFriendlyName: { + resourceId: string; + }; +}; + +/** + * Service for handling socket events + */ +export class SocketHandlerService { + /** + * Creates a new SocketHandlerService + */ + constructor( + private io: Server, + private sandbox: Sandbox, + private getSandboxState: () => Promise, + private backendId: { name: string }, + private shutdownService: ShutdownService, + private resourceService: ResourceService, + private printer: Printer = printerUtil, // Optional printer, defaults to cli-core printer + ) {} + + /** + * Sets up all socket event handlers + * @param socket The socket connection + */ + public setupSocketHandlers(socket: Socket): void { + // Sandbox status handlers + socket.on( + SOCKET_EVENTS.GET_SANDBOX_STATUS, + this.handleGetSandboxStatus.bind(this, socket), + ); + + // Resource handlers + socket.on( + SOCKET_EVENTS.GET_DEPLOYED_BACKEND_RESOURCES, + this.handleGetDeployedBackendResources.bind(this, socket), + ); + + // Friendly name handlers + socket.on( + SOCKET_EVENTS.GET_CUSTOM_FRIENDLY_NAMES, + this.handleGetCustomFriendlyNames.bind(this, socket), + ); + socket.on( + SOCKET_EVENTS.UPDATE_CUSTOM_FRIENDLY_NAME, + this.handleUpdateCustomFriendlyName.bind(this, socket), + ); + socket.on( + SOCKET_EVENTS.REMOVE_CUSTOM_FRIENDLY_NAME, + this.handleRemoveCustomFriendlyName.bind(this, socket), + ); + + // Sandbox operation handlers + socket.on( + SOCKET_EVENTS.START_SANDBOX_WITH_OPTIONS, + this.handleStartSandboxWithOptions.bind(this, socket), + ); + socket.on( + SOCKET_EVENTS.STOP_SANDBOX, + this.handleStopSandbox.bind(this, socket), + ); + socket.on( + SOCKET_EVENTS.DELETE_SANDBOX, + this.handleDeleteSandbox.bind(this, socket), + ); + + // DevTools handlers + socket.on(SOCKET_EVENTS.STOP_DEV_TOOLS, this.handleStopDevTools.bind(this)); + } + + /** + * Handles the getSandboxStatus event + */ + private async handleGetSandboxStatus(socket: Socket): Promise { + try { + const status = await this.getSandboxState(); + + socket.emit(SOCKET_EVENTS.SANDBOX_STATUS, { + status, + identifier: this.backendId.name, + }); + } catch (error) { + this.printer.log( + `Error getting sandbox status on request: ${String(error)}`, + LogLevel.ERROR, + ); + socket.emit(SOCKET_EVENTS.SANDBOX_STATUS, { + status: 'unknown', + error: `${String(error)}`, + identifier: this.backendId.name, + }); + } + } + + /** + * Handles the getDeployedBackendResources event + */ + private async handleGetDeployedBackendResources( + socket: Socket, + ): Promise { + try { + this.printer.log('Fetching deployed backend resources...', LogLevel.INFO); + + // Get the current sandbox state + const status = await this.getSandboxState(); + + // If sandbox is running or stopped, fetch actual resources + if (status === 'running' || status === 'stopped') { + try { + // Use the ResourceService to get deployed backend resources + const resources = + await this.resourceService.getDeployedBackendResources(); + socket.emit(SOCKET_EVENTS.DEPLOYED_BACKEND_RESOURCES, resources); + return; + } catch (error) { + const errorMessage = String(error); + this.printer.log( + `Error getting backend resources: ${errorMessage}`, + LogLevel.ERROR, + ); + + if (errorMessage.includes('deployment is in progress')) { + socket.emit(SOCKET_EVENTS.DEPLOYED_BACKEND_RESOURCES, { + name: this.backendId.name, + status: 'deploying', + resources: [], + region: null, + message: + 'Sandbox deployment is in progress. Resources will update when deployment completes.', + }); + } else if (errorMessage.includes('does not exist')) { + socket.emit(SOCKET_EVENTS.DEPLOYED_BACKEND_RESOURCES, { + name: this.backendId.name, + status: 'nonexistent', + resources: [], + region: null, + message: 'No sandbox exists. Please create a sandbox first.', + }); + } else { + socket.emit(SOCKET_EVENTS.DEPLOYED_BACKEND_RESOURCES, { + name: this.backendId.name, + status: 'error', + resources: [], + region: null, + message: `Error fetching resources: ${errorMessage}`, + error: errorMessage, + }); + } + return; + } + } + + // For non-running states, return appropriate status + socket.emit(SOCKET_EVENTS.DEPLOYED_BACKEND_RESOURCES, { + name: this.backendId.name, + status: status, + resources: [], + region: null, + message: + status === 'nonexistent' + ? 'No sandbox exists. Please create a sandbox first.' + : `Sandbox is ${status}. Start the sandbox to see resources.`, + }); + } catch (error) { + this.printer.log( + `Error checking sandbox status: ${String(error)}`, + LogLevel.ERROR, + ); + socket.emit(SOCKET_EVENTS.DEPLOYED_BACKEND_RESOURCES, { + name: this.backendId.name, + status: 'error', + resources: [], + region: null, + message: `Error checking sandbox status: ${String(error)}`, + error: String(error), + }); + } + } + + /** + * Handles the startSandboxWithOptions event + */ + private async handleStartSandboxWithOptions( + socket: Socket, + options: SocketEvents['startSandboxWithOptions'], + ): Promise { + try { + this.printer.log( + `Starting sandbox with options: ${JSON.stringify(options)}`, + LogLevel.INFO, + ); + + // Emit status update to indicate we're starting + socket.emit(SOCKET_EVENTS.SANDBOX_STATUS, { + status: 'deploying', + identifier: options.identifier || this.backendId.name, + message: 'Starting sandbox...', + }); + + // Converting from DevToolsSandboxOptions to the actual @aws-amplify/sandbox SandboxOptions type + // This conversion is necessary because: + // 1. The field names are different (dirToWatch -> dir) + // 2. The exclude and logsFilter fields need to be split from strings into string arrays + // 3. We need to handle the format as ClientConfigFormat, which can't be imported in the React app + // 4. The function streaming options need to be nested in a functionStreamingOptions object + + const sandboxOptions: SandboxOptions = { + dir: options.dirToWatch || './amplify', + exclude: options.exclude ? options.exclude.split(',') : undefined, + identifier: options.identifier, + format: options.outputsFormat as ClientConfigFormat | undefined, + watchForChanges: !options.once, + functionStreamingOptions: { + enabled: options.streamFunctionLogs || false, + logsFilters: options.logsFilter + ? options.logsFilter.split(',') + : undefined, + logsOutFile: options.logsOutFile, + }, + }; + + // Actually start the sandbox + await this.sandbox.start(sandboxOptions); + + // The sandbox will emit events that update the UI status + this.printer.log( + 'Sandbox start command issued successfully', + LogLevel.DEBUG, + ); + } catch (error) { + this.printer.log( + `Error starting sandbox: ${String(error)}`, + LogLevel.ERROR, + ); + socket.emit(SOCKET_EVENTS.SANDBOX_STATUS, { + status: 'error', + identifier: options.identifier || this.backendId.name, + error: `${String(error)}`, + }); + } + } + + /** + * Handles the stopSandbox event + */ + private async handleStopSandbox(socket: Socket): Promise { + try { + this.printer.log('Stopping sandbox...', LogLevel.INFO); + + await this.sandbox.stop(); + + socket.emit(SOCKET_EVENTS.SANDBOX_STATUS, { + status: 'stopped', + identifier: this.backendId.name, + message: 'Sandbox stopped successfully', + }); + + this.printer.log('Sandbox stopped successfully', LogLevel.INFO); + } catch (error) { + this.printer.log( + `Error stopping sandbox: ${String(error)}`, + LogLevel.ERROR, + ); + socket.emit(SOCKET_EVENTS.SANDBOX_STATUS, { + status: 'error', + identifier: this.backendId.name, + error: `${String(error)}`, + }); + } + } + + /** + * Handles the deleteSandbox event + */ + private async handleDeleteSandbox(socket: Socket): Promise { + try { + this.printer.log('Deleting sandbox...', LogLevel.INFO); + + socket.emit(SOCKET_EVENTS.SANDBOX_STATUS, { + status: 'deleting', + identifier: this.backendId.name, + message: 'Deleting sandbox...', + }); + + await this.sandbox.delete({ identifier: this.backendId.name }); + + this.printer.log( + 'Sandbox delete command issued successfully', + LogLevel.DEBUG, + ); + } catch (error) { + this.printer.log( + `Error deleting sandbox: ${String(error)}`, + LogLevel.ERROR, + ); + socket.emit(SOCKET_EVENTS.SANDBOX_STATUS, { + status: 'error', + identifier: this.backendId.name, + error: `${String(error)}`, + }); + } + } + + /** + * Handles the getCustomFriendlyNames event + */ + private handleGetCustomFriendlyNames(socket: Socket): void { + // In PR 2, we don't have actual storage for custom friendly names + // Just return an empty object + socket.emit(SOCKET_EVENTS.CUSTOM_FRIENDLY_NAMES, {}); + } + + /** + * Handles the updateCustomFriendlyName event + */ + private handleUpdateCustomFriendlyName( + socket: Socket, + data: SocketEvents['updateCustomFriendlyName'], + ): void { + if (!data || !data.resourceId || !data.friendlyName) { + return; + } + + // In PR 2, we don't actually store the custom friendly name + // Just emit the event to acknowledge the update + this.io.emit(SOCKET_EVENTS.CUSTOM_FRIENDLY_NAME_UPDATED, { + resourceId: data.resourceId, + friendlyName: data.friendlyName, + }); + + this.printer.log( + `Custom friendly name updated for ${data.resourceId}: ${data.friendlyName}`, + LogLevel.INFO, + ); + } + + /** + * Handles the removeCustomFriendlyName event + */ + private handleRemoveCustomFriendlyName( + socket: Socket, + data: SocketEvents['removeCustomFriendlyName'], + ): void { + if (!data || !data.resourceId) { + return; + } + + // In PR 2, we don't actually store the custom friendly name + // Just emit the event to acknowledge the removal + this.io.emit(SOCKET_EVENTS.CUSTOM_FRIENDLY_NAME_REMOVED, { + resourceId: data.resourceId, + }); + + this.printer.log( + `Custom friendly name removed for ${data.resourceId}`, + LogLevel.INFO, + ); + } + + /** + * Handles the stopDevTools event + */ + private async handleStopDevTools(): Promise { + await this.shutdownService.shutdown('user request', true); + } +} diff --git a/packages/cli/src/commands/sandbox/sandbox-devtools/shared/socket_events.ts b/packages/cli/src/commands/sandbox/sandbox-devtools/shared/socket_events.ts new file mode 100644 index 00000000000..64dbbe6b053 --- /dev/null +++ b/packages/cli/src/commands/sandbox/sandbox-devtools/shared/socket_events.ts @@ -0,0 +1,111 @@ +/** + * Socket event constants for communication between client and server + */ +export const SOCKET_EVENTS = { + // Resource-related events + /** + * Event to request custom friendly names from the server + */ + GET_CUSTOM_FRIENDLY_NAMES: 'getCustomFriendlyNames', + + /** + * Event received when custom friendly names are sent from the server + */ + CUSTOM_FRIENDLY_NAMES: 'customFriendlyNames', + + /** + * Event to request saved resources from the server + */ + GET_SAVED_RESOURCES: 'getSavedResources', + + /** + * Event received when saved resources are sent from the server + */ + SAVED_RESOURCES: 'savedResources', + + /** + * Event to request deployed backend resources from the server + */ + GET_DEPLOYED_BACKEND_RESOURCES: 'getDeployedBackendResources', + + /** + * Event received when deployed backend resources are sent from the server + */ + DEPLOYED_BACKEND_RESOURCES: 'deployedBackendResources', + + /** + * Event to update a custom friendly name for a resource + */ + UPDATE_CUSTOM_FRIENDLY_NAME: 'updateCustomFriendlyName', + + /** + * Event received when a custom friendly name is updated + */ + CUSTOM_FRIENDLY_NAME_UPDATED: 'customFriendlyNameUpdated', + + /** + * Event to remove a custom friendly name for a resource + */ + REMOVE_CUSTOM_FRIENDLY_NAME: 'removeCustomFriendlyName', + + /** + * Event received when a custom friendly name is removed + */ + CUSTOM_FRIENDLY_NAME_REMOVED: 'customFriendlyNameRemoved', + + // Sandbox-related events + /** + * Event to request the current sandbox status + */ + GET_SANDBOX_STATUS: 'getSandboxStatus', + + /** + * Event received when sandbox status is sent from the server + */ + SANDBOX_STATUS: 'sandboxStatus', + + /** + * Event to start the sandbox with options + */ + START_SANDBOX_WITH_OPTIONS: 'startSandboxWithOptions', + + /** + * Event to stop the sandbox + */ + STOP_SANDBOX: 'stopSandbox', + + /** + * Event to delete the sandbox + */ + DELETE_SANDBOX: 'deleteSandbox', + + /** + * Event to stop the DevTools process + */ + STOP_DEV_TOOLS: 'stopDevTools', + + /** + * Event to get saved deployment progress + */ + GET_SAVED_DEPLOYMENT_PROGRESS: 'getSavedDeploymentProgress', + + /** + * Event to get log settings + */ + GET_LOG_SETTINGS: 'getLogSettings', + + /** + * Event received when deployment is in progress + */ + DEPLOYMENT_IN_PROGRESS: 'deploymentInProgress', + + /** + * Event received when a log message is sent from the server + */ + LOG: 'log', + + /** + * Event received when an error occurs + */ + ERROR: 'error', +} as const; diff --git a/packages/cli/src/commands/sandbox/sandbox-devtools/shared/socket_types.ts b/packages/cli/src/commands/sandbox/sandbox-devtools/shared/socket_types.ts new file mode 100644 index 00000000000..24f9f6076a7 --- /dev/null +++ b/packages/cli/src/commands/sandbox/sandbox-devtools/shared/socket_types.ts @@ -0,0 +1,32 @@ +/** + * Shared types for socket communication between client and server + */ + +/** + * Interface for DevTools Sandbox options + * + * This is the format used by the React frontend and for communication with + * the backend socket_handlers. It differs from the actual @aws-amplify/sandbox SandboxOptions type because the + * ClientConfigFormat cannot be used in DevTools React App due to compatibility issues. + * + * ISSUE: There's a type mismatch between the frontend and backend: + * 1. The frontend uses string literals like 'json', 'ts', etc. for outputsFormat + * 2. The backend expects ClientConfigFormat enum values like ClientConfigFormat.JSON + * + * This is an architectural issue that should be fixed: + * - Ideally, the frontend should use ClientConfigFormat enum (e.g., ClientConfigFormat.JSON instead of 'json') + * - However, we can't directly import ClientConfigFormat in the React app + * - As a temporary solution, the socket_handlers converts the string values to the proper enum format + * when creating the SandboxOptions object to pass to the sandbox + */ +export type DevToolsSandboxOptions = { + identifier?: string; + dirToWatch?: string; + exclude?: string; + outputsFormat?: string; + once?: boolean; + streamFunctionLogs?: boolean; + logsFilter?: string; + logsOutFile?: string; + debugMode?: boolean; +}; diff --git a/packages/cli/src/commands/sandbox/sandbox_command.ts b/packages/cli/src/commands/sandbox/sandbox_command.ts index 1e9409e6a05..ac345340cd1 100644 --- a/packages/cli/src/commands/sandbox/sandbox_command.ts +++ b/packages/cli/src/commands/sandbox/sandbox_command.ts @@ -117,6 +117,9 @@ export class SandboxCommand handlers.forEach((handler) => sandbox.on(event, handler)); }); } + sandbox.on('initializationError', (error) => { + printer.log(`Initialization error: ${String(error)}`, LogLevel.ERROR); + }); const watchExclusions = args.exclude ?? []; const fileName = getClientConfigFileName( args.outputsVersion as ClientConfigVersion, diff --git a/packages/cli/src/commands/sandbox/sandbox_command_factory.ts b/packages/cli/src/commands/sandbox/sandbox_command_factory.ts index 410a4190699..f388aa0da25 100644 --- a/packages/cli/src/commands/sandbox/sandbox_command_factory.ts +++ b/packages/cli/src/commands/sandbox/sandbox_command_factory.ts @@ -7,7 +7,7 @@ import { import { SandboxSingletonFactory } from '@aws-amplify/sandbox'; import { SandboxDeleteCommand } from './sandbox-delete/sandbox_delete_command.js'; import { SandboxSeedCommand } from './sandbox-seed/sandbox_seed_command.js'; -import { SandboxDevToolsCommandFactory } from './sandbox-devtools/sandbox_devtools_command_factory.js'; +import { createSandboxDevToolsCommand } from './sandbox-devtools/sandbox_devtools_command_factory.js'; import { SandboxBackendIdResolver } from './sandbox_id_resolver.js'; import { ClientConfigGeneratorAdapter } from '../../client-config/client_config_generator_adapter.js'; import { LocalNamespaceResolver } from '../../backend-identifier/local_namespace_resolver.js'; @@ -87,7 +87,7 @@ export const createSandboxCommand = ( new SandboxSeedCommand(sandboxBackendIdPartsResolver, [ new SandboxSeedGeneratePolicyCommand(sandboxBackendIdPartsResolver), ]), - new SandboxDevToolsCommandFactory().create(), + createSandboxDevToolsCommand(), ], clientConfigGeneratorAdapter, commandMiddleWare, diff --git a/packages/deployed-backend-client/API.md b/packages/deployed-backend-client/API.md index 3c5353103ac..8324cd522e7 100644 --- a/packages/deployed-backend-client/API.md +++ b/packages/deployed-backend-client/API.md @@ -182,6 +182,9 @@ export type DeployedBackendResource = { resourceType?: string; physicalResourceId?: string; arn?: string; + metadata?: { + constructPath?: string; + }; }; // @public (undocumented) diff --git a/packages/deployed-backend-client/src/deployed-backend-client/deployed_resources_enumerator.test.ts b/packages/deployed-backend-client/src/deployed-backend-client/deployed_resources_enumerator.test.ts index e448a691984..dbc79e94e6a 100644 --- a/packages/deployed-backend-client/src/deployed-backend-client/deployed_resources_enumerator.test.ts +++ b/packages/deployed-backend-client/src/deployed-backend-client/deployed_resources_enumerator.test.ts @@ -153,6 +153,7 @@ void describe('listDeployedResources', () => { resourceType: 'AWS::AppSync::API', physicalResourceId: 'apiSubStackAppSyncPhysicalResourceId', arn: undefined, + metadata: undefined, }, { logicalResourceId: 'apiStackUserPoolLogicalResourceId', @@ -162,6 +163,7 @@ void describe('listDeployedResources', () => { resourceType: 'AWS::Cognito::UserPool', physicalResourceId: 'apiStackUserPoolPhysicalResourceId', arn: undefined, + metadata: undefined, }, { logicalResourceId: 'authStackUserPoolLogicalResourceId', @@ -171,6 +173,7 @@ void describe('listDeployedResources', () => { resourceType: 'AWS::Cognito::UserPool', physicalResourceId: 'authStackUserPoolPhysicalResourceId', arn: undefined, + metadata: undefined, }, { logicalResourceId: 'rootStackIamRoleLogicalResourceId', @@ -180,6 +183,7 @@ void describe('listDeployedResources', () => { resourceType: 'AWS::IAM::Role', physicalResourceId: 'rootStackIamRolePhysicalResourceId', arn: undefined, + metadata: undefined, }, ]; assert.deepEqual(deployedResources, expectedResources); diff --git a/packages/deployed-backend-client/src/deployed-backend-client/deployed_resources_enumerator.ts b/packages/deployed-backend-client/src/deployed-backend-client/deployed_resources_enumerator.ts index 6b5f5798ea7..68bf1d093ea 100644 --- a/packages/deployed-backend-client/src/deployed-backend-client/deployed_resources_enumerator.ts +++ b/packages/deployed-backend-client/src/deployed-backend-client/deployed_resources_enumerator.ts @@ -1,5 +1,6 @@ import { CloudFormationClient, + GetTemplateCommand, ListStackResourcesCommand, ListStackResourcesCommandOutput, StackResourceSummary, @@ -87,6 +88,12 @@ export class DeployedResourcesEnumerator { }, ) ?? []; + // Fetch template metadata + const templateMetadata = await this.getTemplateMetadata( + cfnClient, + stackName, + ); + const parentDeployedNonStackResources = parentStackNonStackResources.map( (stackResourceSummary: StackResourceSummary) => ({ logicalResourceId: stackResourceSummary.LogicalResourceId, @@ -102,10 +109,78 @@ export class DeployedResourcesEnumerator { region, accountId, ), + metadata: stackResourceSummary.LogicalResourceId + ? templateMetadata[stackResourceSummary.LogicalResourceId] + : undefined, }), ); deployedBackendResources.push(...parentDeployedNonStackResources); return deployedBackendResources; }; + + /** + * Fetches CloudFormation template metadata for construct paths + */ + private async getTemplateMetadata( + cfnClient: CloudFormationClient, + stackName: string, + ): Promise> { + try { + const template = await cfnClient.send( + new GetTemplateCommand({ StackName: stackName }), + ); + + const templateBody = + typeof template.TemplateBody === 'string' + ? JSON.parse(template.TemplateBody) + : template.TemplateBody; + + if (!templateBody?.Resources) { + return {}; + } + + const metadata: Record = {}; + + Object.entries(templateBody.Resources).forEach( + ([logicalId, resource]: [string, unknown]) => { + if (typeof resource !== 'object' || resource === null) { + return; + } + + const resourceObj = resource as Record; + if ( + !resourceObj.Metadata || + typeof resourceObj.Metadata !== 'object' || + resourceObj.Metadata === null + ) { + return; + } + + const resourceMetadata = resourceObj.Metadata as Record< + string, + unknown + >; + if ( + !('aws:cdk:path' in resourceMetadata) || + typeof resourceMetadata['aws:cdk:path'] !== 'string' + ) { + return; + } + + metadata[logicalId] = { + constructPath: resourceMetadata['aws:cdk:path'], + }; + }, + ); + + return metadata; + } catch { + // Silently handle failures when retrieving template metadata (like API errors, + // throttling, or malformed templates) since metadata is non-critical. Consumers + // of this API need a complete resource listing even when metadata can't be fetched, + // and will function properly with missing metadata fields. + return {}; + } + } } diff --git a/packages/deployed-backend-client/src/deployed_backend_client_factory.ts b/packages/deployed-backend-client/src/deployed_backend_client_factory.ts index ff49b4c413e..c1476ee828d 100644 --- a/packages/deployed-backend-client/src/deployed_backend_client_factory.ts +++ b/packages/deployed-backend-client/src/deployed_backend_client_factory.ts @@ -47,6 +47,7 @@ export type DeployedBackendResource = { resourceType?: string; physicalResourceId?: string; arn?: string; + metadata?: { constructPath?: string }; }; export type BackendMetadata = { diff --git a/packages/platform-core/API.md b/packages/platform-core/API.md index 5745c8b8767..15d568b35ee 100644 --- a/packages/platform-core/API.md +++ b/packages/platform-core/API.md @@ -16,6 +16,7 @@ import { LogRetention } from '@aws-amplify/plugin-types'; import { RetentionDays } from 'aws-cdk-lib/aws-logs'; import { Span } from '@opentelemetry/api'; import { SpanProcessor } from '@opentelemetry/sdk-trace-base'; +import { STSClient } from '@aws-sdk/client-sts'; import z from 'zod'; declare namespace __export__cdk { @@ -225,6 +226,13 @@ export class ParameterPathConversions { static toResourceReferenceFullPath(backendId: BackendIdentifier, referenceName: string): string; } +// @public +export class RegionFetcher { + constructor(stsClient?: STSClient); + // (undocumented) + fetch: () => Promise; +} + // @public export const setSpanAttributes: (span: Span, obj: DeepPartial | ErrorDetails, prefix?: string) => void; diff --git a/packages/platform-core/src/index.ts b/packages/platform-core/src/index.ts index 05d6655f715..c882dbc4bb7 100644 --- a/packages/platform-core/src/index.ts +++ b/packages/platform-core/src/index.ts @@ -26,3 +26,4 @@ export { TELEMETRY_ENABLED, telemetrySpanAttributeCountLimit, } from './telemetry/constants.js'; +export { RegionFetcher } from './telemetry/region_fetcher.js'; diff --git a/packages/sandbox/API.md b/packages/sandbox/API.md index 88b735a3e6c..ffdf2a40ff8 100644 --- a/packages/sandbox/API.md +++ b/packages/sandbox/API.md @@ -19,6 +19,7 @@ export type Sandbox = { start: (options: SandboxOptions) => Promise; stop: () => Promise; delete: (options: SandboxDeleteOptions) => Promise; + getState: () => SandboxStatus; } & EventEmitter; // @public (undocumented) @@ -27,7 +28,7 @@ export type SandboxDeleteOptions = { }; // @public (undocumented) -export type SandboxEvents = 'successfulDeployment' | 'failedDeployment' | 'successfulDeletion'; +export type SandboxEvents = 'deploymentStarted' | 'successfulDeployment' | 'failedDeployment' | 'deletionStarted' | 'successfulDeletion' | 'failedDeletion' | 'successfulStop' | 'failedStop' | 'initializationError'; // @public (undocumented) export type SandboxFunctionStreamingOptions = { @@ -49,9 +50,12 @@ export type SandboxOptions = { // @public export class SandboxSingletonFactory { constructor(sandboxIdResolver: BackendIdSandboxResolver, sdkProfileResolver: SDKProfileResolver, printer: Printer, format: Format); - getInstance: () => Promise; + getInstance: (logger?: Printer) => Promise; } +// @public +export type SandboxStatus = 'running' | 'stopped' | 'nonexistent' | 'unknown' | 'deploying' | 'deleting'; + // (No @packageDocumentation comment for this package) ``` diff --git a/packages/sandbox/src/file_watching_sandbox.test.ts b/packages/sandbox/src/file_watching_sandbox.test.ts index e55e4ecc4c3..59c9bd33691 100644 --- a/packages/sandbox/src/file_watching_sandbox.test.ts +++ b/packages/sandbox/src/file_watching_sandbox.test.ts @@ -183,7 +183,9 @@ void describe('Sandbox to check if region is bootstrapped', () => { printer.print.mock.resetCalls(); }); - void it('when region has not bootstrapped, then opens console to initiate bootstrap', async () => { + void it('when region has not bootstrapped, then opens console to initiate bootstrap and state remains unknown', async () => { + // Initial state should be unknown + assert.strictEqual(sandboxInstance.getState(), 'unknown'); ssmClientSendMock.mock.mockImplementationOnce(() => { throw new ParameterNotFound({ $metadata: {}, @@ -212,6 +214,9 @@ void describe('Sandbox to check if region is bootstrapped', () => { )} to specify a profile with the correct region.`, ); assert.strictEqual(printer.log.mock.calls[0].arguments[1], undefined); + + // State should remain unknown when bootstrap fails + assert.strictEqual(sandboxInstance.getState(), 'unknown'); }); void it('when region has not bootstrapped, and opening console url fails prints url to initiate bootstrap', async () => { @@ -308,7 +313,9 @@ void describe('Sandbox to check if region is bootstrapped', () => { ); }); - void it('when region has bootstrapped, resumes sandbox command successfully', async () => { + void it('when region has bootstrapped, resumes sandbox command successfully and transitions to running state', async () => { + // Initial state should be unknown + assert.strictEqual(sandboxInstance.getState(), 'unknown'); await sandboxInstance.start({ dir: 'testDir', exclude: ['exclude1', 'exclude2'], @@ -316,6 +323,9 @@ void describe('Sandbox to check if region is bootstrapped', () => { assert.strictEqual(ssmClientSendMock.mock.callCount(), 1); assert.strictEqual(openMock.mock.callCount(), 0); + + // State should be running after successful bootstrap and deployment + assert.strictEqual(sandboxInstance.getState(), 'running'); }); }); @@ -612,15 +622,20 @@ void describe('Sandbox using local project name resolver', () => { ]); }); - void it('queues deployment if a file change is detected during an ongoing deployment', async () => { + void it('queues deployment if a file change is detected during an ongoing deployment and maintains correct state transitions', async () => { ({ sandboxInstance, fileChangeEventCallback } = await setupAndStartSandbox({ executor: sandboxExecutor, ssmClient: ssmClientMock, functionsLogStreamer: functionsLogStreamerMock as unknown as LambdaFunctionLogStreamer, })); - // Mimic BackendDeployer taking 200 ms. + // Initial state should be running + assert.strictEqual(sandboxInstance.getState(), 'running'); + + // Mimic BackendDeployer taking 200 ms and capture state during deployment + let stateCheck: string | null = null; backendDeployerDeployMock.mock.mockImplementationOnce(async () => { + stateCheck = sandboxInstance.getState(); await new Promise((resolve) => setTimeout(resolve, 200)); return { deploymentTimes: {}, stdout: '', stderr: '' }; }); @@ -640,6 +655,12 @@ void describe('Sandbox using local project name resolver', () => { await Promise.all([firstFileChange, secondFileChange]); + // Verify state was deploying during deployment + assert.strictEqual(stateCheck, 'deploying'); + + // State should return to running after deployment + assert.strictEqual(sandboxInstance.getState(), 'running'); + assert.strictEqual(backendDeployerDeployMock.mock.callCount(), 2); // BackendDeployer should be called with the right params assert.deepEqual(backendDeployerDeployMock.mock.calls[0].arguments, [ @@ -659,14 +680,25 @@ void describe('Sandbox using local project name resolver', () => { ]); }); - void it('calls BackendDeployer destroy when delete is called', async () => { + void it('calls BackendDeployer destroy when delete is called and transitions state correctly', async () => { ({ sandboxInstance } = await setupAndStartSandbox({ executor: sandboxExecutor, ssmClient: ssmClientMock, functionsLogStreamer: functionsLogStreamerMock as unknown as LambdaFunctionLogStreamer, })); - await sandboxInstance.delete({}); + + // Initial state should be running after setup + assert.strictEqual(sandboxInstance.getState(), 'running'); + + // Start the delete operation + const deletePromise = sandboxInstance.delete({}); + + // State should be deleting during operation + assert.strictEqual(sandboxInstance.getState(), 'deleting'); + + // Wait for delete to complete + await deletePromise; // BackendDeployer should be called once to destroy assert.strictEqual(backendDeployerDestroyMock.mock.callCount(), 1); @@ -675,9 +707,12 @@ void describe('Sandbox using local project name resolver', () => { assert.deepEqual(backendDeployerDestroyMock.mock.calls[0].arguments, [ testSandboxBackendId, ]); + + // State should be nonexistent after deletion + assert.strictEqual(sandboxInstance.getState(), 'nonexistent'); }); - void it('handles error thrown by BackendDeployer and does not crash while deploying', async (contextual) => { + void it('handles error thrown by BackendDeployer and does not crash while deploying, maintaining proper state', async (contextual) => { ({ sandboxInstance, fileChangeEventCallback } = await setupAndStartSandbox({ executor: sandboxExecutor, ssmClient: ssmClientMock, @@ -686,10 +721,18 @@ void describe('Sandbox using local project name resolver', () => { })); const mockEmit = mock.fn(); contextual.mock.method(sandboxInstance, 'emit', mockEmit); + // Initial state should be running + assert.strictEqual(sandboxInstance.getState(), 'running'); + + // Mock deployment to fail but capture state during deployment + let stateCheck: string | null = null; const contextualBackendDeployerMock = contextual.mock.method( backendDeployer, 'deploy', - () => Promise.reject(new Error('random BackendDeployer error')), + async () => { + stateCheck = sandboxInstance.getState(); + throw new Error('random BackendDeployer error'); + }, { times: 1 }, ); @@ -713,10 +756,10 @@ void describe('Sandbox using local project name resolver', () => { assert.strictEqual(backendDeployerDeployMock.mock.callCount(), 1); // of the two file change events, successfulDeployment event should only be fired once - assert.strictEqual(mockEmit.mock.callCount(), 2); - assert.strictEqual(mockEmit.mock.calls[0].arguments[0], 'failedDeployment'); + assert.strictEqual(mockEmit.mock.callCount(), 4); + assert.strictEqual(mockEmit.mock.calls[1].arguments[0], 'failedDeployment'); assert.strictEqual( - mockEmit.mock.calls[1].arguments[0], + mockEmit.mock.calls[3].arguments[0], 'successfulDeployment', ); @@ -737,9 +780,15 @@ void describe('Sandbox using local project name resolver', () => { /file_watching_sandbox.ts/, ); assert.strictEqual(printer.log.mock.calls[7].arguments[1], LogLevel.DEBUG); + + // Verify state was deploying during deployment + assert.strictEqual(stateCheck, 'deploying'); + + // State should return to running after failed deployment in watch mode + assert.strictEqual(sandboxInstance.getState(), 'running'); }); - void it('handles UpdateNotSupported error while deploying and offers to reset sandbox and customer says yes', async (contextual) => { + void it('handles UpdateNotSupported error while deploying and offers to reset sandbox and customer says yes, with proper state transitions', async (contextual) => { ({ sandboxInstance, fileChangeEventCallback } = await setupAndStartSandbox({ executor: sandboxExecutor, ssmClient: ssmClientMock, @@ -1025,7 +1074,7 @@ void describe('Sandbox using local project name resolver', () => { { type: 'update', path: 'foo/test1.ts' }, ]); - assert.strictEqual(mockEmit.mock.callCount(), 1); + assert.strictEqual(mockEmit.mock.callCount(), 2); }); void it('emits the successfulDeletion event after delete is finished', async () => { @@ -1058,6 +1107,58 @@ void describe('Sandbox using local project name resolver', () => { assert.strictEqual(subscribeMock.mock.callCount(), 0); }); + void it('properly tracks state transitions during sandbox lifecycle', async () => { + // Create a new sandbox instance + ({ sandboxInstance } = await setupAndStartSandbox( + { + executor: sandboxExecutor, + ssmClient: ssmClientMock, + functionsLogStreamer: + functionsLogStreamerMock as unknown as LambdaFunctionLogStreamer, + }, + { watchForChanges: true }, + false, + )); + + // Initial state should be running with watchForChanges=true + assert.strictEqual(sandboxInstance.getState(), 'running'); + + // Create another sandbox with watchForChanges=false + const sandboxWithoutWatch = new FileWatchingSandbox( + async () => testSandboxBackendId, + sandboxExecutor, + ssmClientMock, + functionsLogStreamerMock as unknown as LambdaFunctionLogStreamer, + printer as unknown as Printer, + openMock as never, + subscribeMock as never, + ); + + // Initial state should be unknown + assert.strictEqual(sandboxWithoutWatch.getState(), 'unknown'); + + // Start with watchForChanges=false + await sandboxWithoutWatch.start({ watchForChanges: false }); + + // State should be stopped with watchForChanges=false + assert.strictEqual(sandboxWithoutWatch.getState(), 'stopped'); + + // Start delete operation + const deletePromise = sandboxWithoutWatch.delete({}); + + // State should be deleting during operation + assert.strictEqual(sandboxWithoutWatch.getState(), 'deleting'); + + // Wait for delete to complete + await deletePromise; + + // State should be nonexistent after deletion + assert.strictEqual(sandboxWithoutWatch.getState(), 'nonexistent'); + + // Clean up + await sandboxWithoutWatch.stop(); + }); + void it('start lambda function log watcher regardless if asked to in sandbox options', async () => { ({ sandboxInstance } = await setupAndStartSandbox( { diff --git a/packages/sandbox/src/file_watching_sandbox.ts b/packages/sandbox/src/file_watching_sandbox.ts index f5076416dfe..787ec80e117 100644 --- a/packages/sandbox/src/file_watching_sandbox.ts +++ b/packages/sandbox/src/file_watching_sandbox.ts @@ -7,6 +7,7 @@ import { SandboxDeleteOptions, SandboxEvents, SandboxOptions, + SandboxStatus, } from './sandbox.js'; import parseGitIgnore from 'parse-gitignore'; import path from 'path'; @@ -75,6 +76,7 @@ export class FileWatchingSandbox extends EventEmitter implements Sandbox { private watcherSubscription: Awaited>; private outputFilesExcludedFromWatch = ['.amplify']; private filesChangesTracker: FilesChangesTracker; + private state: SandboxStatus = 'unknown'; /** * Creates a watcher process for this instance @@ -94,6 +96,14 @@ export class FileWatchingSandbox extends EventEmitter implements Sandbox { this.interceptStderr(); } + /** + * Gets the current state of the sandbox + * @returns The current state: 'running', 'stopped', 'deploying', 'deleting', 'nonexistent', or 'unknown' + */ + getState = (): SandboxStatus => { + return this.state; + }; + /** * @inheritdoc */ @@ -119,11 +129,16 @@ export class FileWatchingSandbox extends EventEmitter implements Sandbox { const watchForChanges = options.watchForChanges ?? true; if (!fs.existsSync(watchDir)) { - throw new AmplifyUserError('PathNotFoundError', { + const error = new AmplifyUserError('PathNotFoundError', { message: `${watchDir} does not exist.`, resolution: 'Make sure you are running this command from your project root directory.', }); + + // Emit initialization error event before throwing + this.emit('initializationError', error); + + throw error; } this.filesChangesTracker = await createFilesChangesTracker(watchDir); @@ -158,6 +173,9 @@ export class FileWatchingSandbox extends EventEmitter implements Sandbox { return; } + // Set state to running at the beginning of start + this.state = 'running'; + const ignoredPaths = this.getGitIgnoredPaths(); this.outputFilesExcludedFromWatch = this.outputFilesExcludedFromWatch.concat(...ignoredPaths); @@ -259,10 +277,37 @@ export class FileWatchingSandbox extends EventEmitter implements Sandbox { * @inheritdoc */ stop = async () => { - this.printer.log(`[Sandbox] Shutting down`, LogLevel.DEBUG); - this.functionsLogStreamer?.stopStreamingLogs(); - // can be undefined if command exits before subscription - await this.watcherSubscription?.unsubscribe(); + this.printer.log(`[Sandbox] Stop operation initiated`, LogLevel.DEBUG); + + try { + // Stop function log streaming + this.functionsLogStreamer?.stopStreamingLogs(); + this.printer.log( + `[Sandbox] Function log streaming stopped successfully`, + LogLevel.DEBUG, + ); + + // Unsubscribe from watcher + if (this.watcherSubscription) { + await this.watcherSubscription.unsubscribe(); + } + + // Update state to stopped + this.state = 'stopped'; + this.printer.log(`[Sandbox] Stop operation completed`, LogLevel.DEBUG); + + // Emit successful stop event + this.emit('successfulStop'); + } catch (error) { + this.printer.log( + `[Sandbox] Error during stop operation: ${String(error)}`, + LogLevel.ERROR, + ); + + // Emit failed stop event + this.emit('failedStop', error); + throw error; + } }; /** @@ -272,11 +317,43 @@ export class FileWatchingSandbox extends EventEmitter implements Sandbox { this.printer.log( '[Sandbox] Deleting all the resources in the sandbox environment...', ); - await this.executor.destroy( - await this.backendIdSandboxResolver(options.identifier), - ); - this.emit('successfulDeletion'); - this.printer.log('[Sandbox] Finished deleting.'); + + // Update state to deleting + this.state = 'deleting'; + + // Emit deletionStarted event with relevant info + this.emit('deletionStarted', { + identifier: options.identifier, + timestamp: new Date().toISOString(), + }); + + try { + const backendId = await this.backendIdSandboxResolver(options.identifier); + + await this.executor.destroy(backendId); + + // Update state to nonexistent + this.state = 'nonexistent'; + + this.emit('successfulDeletion'); + this.printer.log('[Sandbox] Finished deleting.'); + } catch (error) { + this.printer.log( + `[Sandbox] Error during deletion: ${String(error)}`, + LogLevel.ERROR, + ); + if (error instanceof Error && error.stack) { + this.printer.log( + `[Sandbox] Error stack: ${error.stack}`, + LogLevel.DEBUG, + ); + } + + // Emit failedDeletion event + this.emit('failedDeletion', error); + + throw error; + } }; private shouldValidateAppSources = (): boolean => { @@ -295,11 +372,20 @@ export class FileWatchingSandbox extends EventEmitter implements Sandbox { const tracer = openTelemetryTrace.getTracer('amplify-backend'); await tracer.startActiveSpan('sandbox', async (span: Span) => { const startTime = Date.now(); + // Track state before deployment for error handling + const stateBeforeDeployment = this.state; try { + // Set state to deploying + this.state = 'deploying'; + + // Emit deploymentStarted event with relevant info + this.emit('deploymentStarted', { + identifier: options.identifier, + timestamp: new Date().toISOString(), + }); + const deployResult = await this.executor.deploy( await this.backendIdSandboxResolver(options.identifier), - // It's important to pass this as callback so that debounce does - // not reset tracker prematurely this.shouldValidateAppSources, ); const data: DeepPartial = { @@ -321,7 +407,17 @@ export class FileWatchingSandbox extends EventEmitter implements Sandbox { }; setSpanAttributes(span, data); span.end(); + this.printer.log('[Sandbox] Deployment successful', LogLevel.DEBUG); + + // Set state based on watchForChanges option + if (options.watchForChanges === false) { + // If --once flag was used, set state to stopped + this.state = 'stopped'; + } else { + // Otherwise set state to running + this.state = 'running'; + } this.emit('successfulDeployment', deployResult); } catch (error) { const amplifyError = AmplifyError.isAmplifyError(error) @@ -364,6 +460,18 @@ export class FileWatchingSandbox extends EventEmitter implements Sandbox { : undefined; } + // Update state based on error type and state before deployment + if (stateBeforeDeployment === 'nonexistent') { + // If this was an initial creation attempt, stay nonexistent + this.state = 'nonexistent'; + } else if (options.watchForChanges === false) { + // If --once flag was used, set to stopped on error + this.state = 'stopped'; + } else { + // For watch mode, keep running to allow fixes + this.state = 'running'; + } + this.emit('failedDeployment', error); // If the error is because of a non-allowed destructive change such as @@ -454,7 +562,7 @@ export class FileWatchingSandbox extends EventEmitter implements Sandbox { 'InvalidSignatureException', ].includes(e.name) ) { - throw new AmplifyUserError( + const error = new AmplifyUserError( 'SSMCredentialsError', { message: `${e.name}: ${e.message}`, @@ -463,6 +571,11 @@ export class FileWatchingSandbox extends EventEmitter implements Sandbox { }, e, ); + + // Emit initialization error event before throwing + this.emit('initializationError', error); + + throw error; } // If we are unable to retrieve bootstrap version parameter due to other reasons, we fail fast. diff --git a/packages/sandbox/src/sandbox.ts b/packages/sandbox/src/sandbox.ts index 5a476d31a11..46ff4e86bd9 100644 --- a/packages/sandbox/src/sandbox.ts +++ b/packages/sandbox/src/sandbox.ts @@ -4,6 +4,16 @@ import EventEmitter from 'events'; import { ClientConfigFormat } from '@aws-amplify/client-config'; import { BackendIdentifier } from '@aws-amplify/plugin-types'; +/** + * Type definition for sandbox status + */ +export type SandboxStatus = + | 'running' + | 'stopped' + | 'nonexistent' + | 'unknown' + | 'deploying' + | 'deleting'; /** * Interface for Sandbox. */ @@ -23,12 +33,24 @@ export type Sandbox = { * Deletes this environment */ delete: (options: SandboxDeleteOptions) => Promise; + + /** + * Gets the current state of the sandbox + * @returns The current state: 'running', 'stopped', 'deploying', 'deleting', 'nonexistent', or 'unknown' + */ + getState: () => SandboxStatus; } & EventEmitter; export type SandboxEvents = + | 'deploymentStarted' | 'successfulDeployment' | 'failedDeployment' - | 'successfulDeletion'; + | 'deletionStarted' + | 'successfulDeletion' + | 'failedDeletion' + | 'successfulStop' + | 'failedStop' + | 'initializationError'; export type SandboxOptions = { dir?: string; diff --git a/packages/sandbox/src/sandbox_singleton_factory.ts b/packages/sandbox/src/sandbox_singleton_factory.ts index 07997c09ed8..aa4a5111e09 100644 --- a/packages/sandbox/src/sandbox_singleton_factory.ts +++ b/packages/sandbox/src/sandbox_singleton_factory.ts @@ -34,13 +34,15 @@ export class SandboxSingletonFactory { /** * Returns a singleton instance of a Sandbox + * @param logger Optional logger to override the default printer */ - getInstance = async (): Promise => { + getInstance = async (logger?: Printer): Promise => { if (!SandboxSingletonFactory.instance) { + const printerToUse = logger || this.printer; const packageManagerControllerFactory = - new PackageManagerControllerFactory(process.cwd(), this.printer); + new PackageManagerControllerFactory(process.cwd(), printerToUse); const cdkEventsBridgeIoHost = new AmplifyIOEventsBridgeSingletonFactory( - this.printer, + printerToUse, ).getInstance(); const backendDeployerFactory = new BackendDeployerFactory( @@ -54,16 +56,16 @@ export class SandboxSingletonFactory { new AmplifySandboxExecutor( backendDeployerFactory.getInstance(), getSecretClientWithAmplifyErrorHandling(), - this.printer, + printerToUse, ), new SSMClient(), new LambdaFunctionLogStreamer( new LambdaClient(), new CloudWatchLogEventMonitor(new CloudWatchLogsClient()), BackendOutputClientFactory.getInstance(), - this.printer, + printerToUse, ), - this.printer, + printerToUse, ); } return SandboxSingletonFactory.instance;