diff --git a/package-lock.json b/package-lock.json index be6ebfe5b50..a23a586adf1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -144,8 +144,6 @@ }, "node_modules/@aws-sdk/client-api-gateway": { "version": "3.693.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-api-gateway/-/client-api-gateway-3.693.0.tgz", - "integrity": "sha512-6Fz0YF4aQc1mrW5rGYYwXGntUDILsIkWgZvUkTDIVT5Hwyz9CmSeKOJCh8oESucEX6/N0UzVWnpW+Z36pElQUQ==", "license": "Apache-2.0", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", @@ -197,6 +195,486 @@ } }, "node_modules/@aws-sdk/client-api-gateway/node_modules/@aws-sdk/client-sso": { + "version": "3.693.0", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "3.693.0", + "@aws-sdk/middleware-host-header": "3.693.0", + "@aws-sdk/middleware-logger": "3.693.0", + "@aws-sdk/middleware-recursion-detection": "3.693.0", + "@aws-sdk/middleware-user-agent": "3.693.0", + "@aws-sdk/region-config-resolver": "3.693.0", + "@aws-sdk/types": "3.692.0", + "@aws-sdk/util-endpoints": "3.693.0", + "@aws-sdk/util-user-agent-browser": "3.693.0", + "@aws-sdk/util-user-agent-node": "3.693.0", + "@smithy/config-resolver": "^3.0.11", + "@smithy/core": "^2.5.2", + "@smithy/fetch-http-handler": "^4.1.0", + "@smithy/hash-node": "^3.0.9", + "@smithy/invalid-dependency": "^3.0.9", + "@smithy/middleware-content-length": "^3.0.11", + "@smithy/middleware-endpoint": "^3.2.2", + "@smithy/middleware-retry": "^3.0.26", + "@smithy/middleware-serde": "^3.0.9", + "@smithy/middleware-stack": "^3.0.9", + "@smithy/node-config-provider": "^3.1.10", + "@smithy/node-http-handler": "^3.3.0", + "@smithy/protocol-http": "^4.1.6", + "@smithy/smithy-client": "^3.4.3", + "@smithy/types": "^3.7.0", + "@smithy/url-parser": "^3.0.9", + "@smithy/util-base64": "^3.0.0", + "@smithy/util-body-length-browser": "^3.0.0", + "@smithy/util-body-length-node": "^3.0.0", + "@smithy/util-defaults-mode-browser": "^3.0.26", + "@smithy/util-defaults-mode-node": "^3.0.26", + "@smithy/util-endpoints": "^2.1.5", + "@smithy/util-middleware": "^3.0.9", + "@smithy/util-retry": "^3.0.9", + "@smithy/util-utf8": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-api-gateway/node_modules/@aws-sdk/client-sso-oidc": { + "version": "3.693.0", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "3.693.0", + "@aws-sdk/credential-provider-node": "3.693.0", + "@aws-sdk/middleware-host-header": "3.693.0", + "@aws-sdk/middleware-logger": "3.693.0", + "@aws-sdk/middleware-recursion-detection": "3.693.0", + "@aws-sdk/middleware-user-agent": "3.693.0", + "@aws-sdk/region-config-resolver": "3.693.0", + "@aws-sdk/types": "3.692.0", + "@aws-sdk/util-endpoints": "3.693.0", + "@aws-sdk/util-user-agent-browser": "3.693.0", + "@aws-sdk/util-user-agent-node": "3.693.0", + "@smithy/config-resolver": "^3.0.11", + "@smithy/core": "^2.5.2", + "@smithy/fetch-http-handler": "^4.1.0", + "@smithy/hash-node": "^3.0.9", + "@smithy/invalid-dependency": "^3.0.9", + "@smithy/middleware-content-length": "^3.0.11", + "@smithy/middleware-endpoint": "^3.2.2", + "@smithy/middleware-retry": "^3.0.26", + "@smithy/middleware-serde": "^3.0.9", + "@smithy/middleware-stack": "^3.0.9", + "@smithy/node-config-provider": "^3.1.10", + "@smithy/node-http-handler": "^3.3.0", + "@smithy/protocol-http": "^4.1.6", + "@smithy/smithy-client": "^3.4.3", + "@smithy/types": "^3.7.0", + "@smithy/url-parser": "^3.0.9", + "@smithy/util-base64": "^3.0.0", + "@smithy/util-body-length-browser": "^3.0.0", + "@smithy/util-body-length-node": "^3.0.0", + "@smithy/util-defaults-mode-browser": "^3.0.26", + "@smithy/util-defaults-mode-node": "^3.0.26", + "@smithy/util-endpoints": "^2.1.5", + "@smithy/util-middleware": "^3.0.9", + "@smithy/util-retry": "^3.0.9", + "@smithy/util-utf8": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "@aws-sdk/client-sts": "^3.693.0" + } + }, + "node_modules/@aws-sdk/client-api-gateway/node_modules/@aws-sdk/client-sts": { + "version": "3.693.0", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/client-sso-oidc": "3.693.0", + "@aws-sdk/core": "3.693.0", + "@aws-sdk/credential-provider-node": "3.693.0", + "@aws-sdk/middleware-host-header": "3.693.0", + "@aws-sdk/middleware-logger": "3.693.0", + "@aws-sdk/middleware-recursion-detection": "3.693.0", + "@aws-sdk/middleware-user-agent": "3.693.0", + "@aws-sdk/region-config-resolver": "3.693.0", + "@aws-sdk/types": "3.692.0", + "@aws-sdk/util-endpoints": "3.693.0", + "@aws-sdk/util-user-agent-browser": "3.693.0", + "@aws-sdk/util-user-agent-node": "3.693.0", + "@smithy/config-resolver": "^3.0.11", + "@smithy/core": "^2.5.2", + "@smithy/fetch-http-handler": "^4.1.0", + "@smithy/hash-node": "^3.0.9", + "@smithy/invalid-dependency": "^3.0.9", + "@smithy/middleware-content-length": "^3.0.11", + "@smithy/middleware-endpoint": "^3.2.2", + "@smithy/middleware-retry": "^3.0.26", + "@smithy/middleware-serde": "^3.0.9", + "@smithy/middleware-stack": "^3.0.9", + "@smithy/node-config-provider": "^3.1.10", + "@smithy/node-http-handler": "^3.3.0", + "@smithy/protocol-http": "^4.1.6", + "@smithy/smithy-client": "^3.4.3", + "@smithy/types": "^3.7.0", + "@smithy/url-parser": "^3.0.9", + "@smithy/util-base64": "^3.0.0", + "@smithy/util-body-length-browser": "^3.0.0", + "@smithy/util-body-length-node": "^3.0.0", + "@smithy/util-defaults-mode-browser": "^3.0.26", + "@smithy/util-defaults-mode-node": "^3.0.26", + "@smithy/util-endpoints": "^2.1.5", + "@smithy/util-middleware": "^3.0.9", + "@smithy/util-retry": "^3.0.9", + "@smithy/util-utf8": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-api-gateway/node_modules/@aws-sdk/core": { + "version": "3.693.0", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.692.0", + "@smithy/core": "^2.5.2", + "@smithy/node-config-provider": "^3.1.10", + "@smithy/property-provider": "^3.1.9", + "@smithy/protocol-http": "^4.1.6", + "@smithy/signature-v4": "^4.2.2", + "@smithy/smithy-client": "^3.4.3", + "@smithy/types": "^3.7.0", + "@smithy/util-middleware": "^3.0.9", + "fast-xml-parser": "4.4.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-api-gateway/node_modules/@aws-sdk/credential-provider-http": { + "version": "3.693.0", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.693.0", + "@aws-sdk/types": "3.692.0", + "@smithy/fetch-http-handler": "^4.1.0", + "@smithy/node-http-handler": "^3.3.0", + "@smithy/property-provider": "^3.1.9", + "@smithy/protocol-http": "^4.1.6", + "@smithy/smithy-client": "^3.4.3", + "@smithy/types": "^3.7.0", + "@smithy/util-stream": "^3.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-api-gateway/node_modules/@aws-sdk/credential-provider-ini": { + "version": "3.693.0", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.693.0", + "@aws-sdk/credential-provider-env": "3.693.0", + "@aws-sdk/credential-provider-http": "3.693.0", + "@aws-sdk/credential-provider-process": "3.693.0", + "@aws-sdk/credential-provider-sso": "3.693.0", + "@aws-sdk/credential-provider-web-identity": "3.693.0", + "@aws-sdk/types": "3.692.0", + "@smithy/credential-provider-imds": "^3.2.6", + "@smithy/property-provider": "^3.1.9", + "@smithy/shared-ini-file-loader": "^3.1.10", + "@smithy/types": "^3.7.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "@aws-sdk/client-sts": "^3.693.0" + } + }, + "node_modules/@aws-sdk/client-api-gateway/node_modules/@aws-sdk/credential-provider-node": { + "version": "3.693.0", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/credential-provider-env": "3.693.0", + "@aws-sdk/credential-provider-http": "3.693.0", + "@aws-sdk/credential-provider-ini": "3.693.0", + "@aws-sdk/credential-provider-process": "3.693.0", + "@aws-sdk/credential-provider-sso": "3.693.0", + "@aws-sdk/credential-provider-web-identity": "3.693.0", + "@aws-sdk/types": "3.692.0", + "@smithy/credential-provider-imds": "^3.2.6", + "@smithy/property-provider": "^3.1.9", + "@smithy/shared-ini-file-loader": "^3.1.10", + "@smithy/types": "^3.7.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-api-gateway/node_modules/@aws-sdk/credential-provider-sso": { + "version": "3.693.0", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/client-sso": "3.693.0", + "@aws-sdk/core": "3.693.0", + "@aws-sdk/token-providers": "3.693.0", + "@aws-sdk/types": "3.692.0", + "@smithy/property-provider": "^3.1.9", + "@smithy/shared-ini-file-loader": "^3.1.10", + "@smithy/types": "^3.7.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-api-gateway/node_modules/@aws-sdk/credential-provider-web-identity": { + "version": "3.693.0", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.693.0", + "@aws-sdk/types": "3.692.0", + "@smithy/property-provider": "^3.1.9", + "@smithy/types": "^3.7.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "@aws-sdk/client-sts": "^3.693.0" + } + }, + "node_modules/@aws-sdk/client-api-gateway/node_modules/@aws-sdk/middleware-host-header": { + "version": "3.693.0", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.692.0", + "@smithy/protocol-http": "^4.1.6", + "@smithy/types": "^3.7.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-api-gateway/node_modules/@aws-sdk/middleware-logger": { + "version": "3.693.0", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.692.0", + "@smithy/types": "^3.7.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-api-gateway/node_modules/@aws-sdk/middleware-recursion-detection": { + "version": "3.693.0", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.692.0", + "@smithy/protocol-http": "^4.1.6", + "@smithy/types": "^3.7.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-api-gateway/node_modules/@aws-sdk/middleware-user-agent": { + "version": "3.693.0", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.693.0", + "@aws-sdk/types": "3.692.0", + "@aws-sdk/util-endpoints": "3.693.0", + "@smithy/core": "^2.5.2", + "@smithy/protocol-http": "^4.1.6", + "@smithy/types": "^3.7.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-api-gateway/node_modules/@aws-sdk/region-config-resolver": { + "version": "3.693.0", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.692.0", + "@smithy/node-config-provider": "^3.1.10", + "@smithy/types": "^3.7.0", + "@smithy/util-config-provider": "^3.0.0", + "@smithy/util-middleware": "^3.0.9", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-api-gateway/node_modules/@aws-sdk/token-providers": { + "version": "3.693.0", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.692.0", + "@smithy/property-provider": "^3.1.9", + "@smithy/shared-ini-file-loader": "^3.1.10", + "@smithy/types": "^3.7.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "@aws-sdk/client-sso-oidc": "^3.693.0" + } + }, + "node_modules/@aws-sdk/client-api-gateway/node_modules/@aws-sdk/util-endpoints": { + "version": "3.693.0", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.692.0", + "@smithy/types": "^3.7.0", + "@smithy/util-endpoints": "^2.1.5", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-api-gateway/node_modules/@aws-sdk/util-user-agent-browser": { + "version": "3.693.0", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.692.0", + "@smithy/types": "^3.7.0", + "bowser": "^2.11.0", + "tslib": "^2.6.2" + } + }, + "node_modules/@aws-sdk/client-api-gateway/node_modules/@aws-sdk/util-user-agent-node": { + "version": "3.693.0", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/middleware-user-agent": "3.693.0", + "@aws-sdk/types": "3.692.0", + "@smithy/node-config-provider": "^3.1.10", + "@smithy/types": "^3.7.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "aws-crt": ">=1.0.0" + }, + "peerDependenciesMeta": { + "aws-crt": { + "optional": true + } + } + }, + "node_modules/@aws-sdk/client-api-gateway/node_modules/@smithy/is-array-buffer": { + "version": "3.0.0", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-api-gateway/node_modules/@smithy/util-buffer-from": { + "version": "3.0.0", + "license": "Apache-2.0", + "dependencies": { + "@smithy/is-array-buffer": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-api-gateway/node_modules/@smithy/util-utf8": { + "version": "3.0.0", + "license": "Apache-2.0", + "dependencies": { + "@smithy/util-buffer-from": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-apprunner": { + "version": "3.693.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-apprunner/-/client-apprunner-3.693.0.tgz", + "integrity": "sha512-6q3yxzp+1fZ2+O7NC8skDz7GSRH6fCcRfT9UU1nX3+kIx/C9cbutnM/WxU35vqJrnT4hq45cUoWj52xZgxFgAA==", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/client-sso-oidc": "3.693.0", + "@aws-sdk/client-sts": "3.693.0", + "@aws-sdk/core": "3.693.0", + "@aws-sdk/credential-provider-node": "3.693.0", + "@aws-sdk/middleware-host-header": "3.693.0", + "@aws-sdk/middleware-logger": "3.693.0", + "@aws-sdk/middleware-recursion-detection": "3.693.0", + "@aws-sdk/middleware-user-agent": "3.693.0", + "@aws-sdk/region-config-resolver": "3.693.0", + "@aws-sdk/types": "3.692.0", + "@aws-sdk/util-endpoints": "3.693.0", + "@aws-sdk/util-user-agent-browser": "3.693.0", + "@aws-sdk/util-user-agent-node": "3.693.0", + "@smithy/config-resolver": "^3.0.11", + "@smithy/core": "^2.5.2", + "@smithy/fetch-http-handler": "^4.1.0", + "@smithy/hash-node": "^3.0.9", + "@smithy/invalid-dependency": "^3.0.9", + "@smithy/middleware-content-length": "^3.0.11", + "@smithy/middleware-endpoint": "^3.2.2", + "@smithy/middleware-retry": "^3.0.26", + "@smithy/middleware-serde": "^3.0.9", + "@smithy/middleware-stack": "^3.0.9", + "@smithy/node-config-provider": "^3.1.10", + "@smithy/node-http-handler": "^3.3.0", + "@smithy/protocol-http": "^4.1.6", + "@smithy/smithy-client": "^3.4.3", + "@smithy/types": "^3.7.0", + "@smithy/url-parser": "^3.0.9", + "@smithy/util-base64": "^3.0.0", + "@smithy/util-body-length-browser": "^3.0.0", + "@smithy/util-body-length-node": "^3.0.0", + "@smithy/util-defaults-mode-browser": "^3.0.26", + "@smithy/util-defaults-mode-node": "^3.0.26", + "@smithy/util-endpoints": "^2.1.5", + "@smithy/util-middleware": "^3.0.9", + "@smithy/util-retry": "^3.0.9", + "@smithy/util-utf8": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-apprunner/node_modules/@aws-sdk/client-sso": { "version": "3.693.0", "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.693.0.tgz", "integrity": "sha512-QEynrBC26x6TG9ZMzApR/kZ3lmt4lEIs2D+cHuDxt6fDGzahBUsQFBwJqhizzsM97JJI5YvmJhmihoYjdSSaXA==", @@ -245,7 +723,7 @@ "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/client-api-gateway/node_modules/@aws-sdk/client-sso-oidc": { + "node_modules/@aws-sdk/client-apprunner/node_modules/@aws-sdk/client-sso-oidc": { "version": "3.693.0", "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso-oidc/-/client-sso-oidc-3.693.0.tgz", "integrity": "sha512-UEDbYlYtK/e86OOMyFR4zEPyenIxDzO2DRdz3fwVW7RzZ94wfmSwBh/8skzPTuY1G7sI064cjHW0b0QG01Sdtg==", @@ -298,7 +776,7 @@ "@aws-sdk/client-sts": "^3.693.0" } }, - "node_modules/@aws-sdk/client-api-gateway/node_modules/@aws-sdk/client-sts": { + "node_modules/@aws-sdk/client-apprunner/node_modules/@aws-sdk/client-sts": { "version": "3.693.0", "resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.693.0.tgz", "integrity": "sha512-4S2y7VEtvdnjJX4JPl4kDQlslxXEZFnC50/UXVUYSt/AMc5A/GgspFNA5FVz4E3Gwpfobbf23hR2NBF8AGvYoQ==", @@ -349,7 +827,7 @@ "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/client-api-gateway/node_modules/@aws-sdk/core": { + "node_modules/@aws-sdk/client-apprunner/node_modules/@aws-sdk/core": { "version": "3.693.0", "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.693.0.tgz", "integrity": "sha512-v6Z/kWmLFqRLDPEwl9hJGhtTgIFHjZugSfF1Yqffdxf4n1AWgtHS7qSegakuMyN5pP4K2tvUD8qHJ+gGe2Bw2A==", @@ -371,7 +849,7 @@ "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/client-api-gateway/node_modules/@aws-sdk/credential-provider-http": { + "node_modules/@aws-sdk/client-apprunner/node_modules/@aws-sdk/credential-provider-http": { "version": "3.693.0", "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.693.0.tgz", "integrity": "sha512-sL8MvwNJU7ZpD7/d2VVb3by1GknIJUxzTIgYtVkDVA/ojo+KRQSSHxcj0EWWXF5DTSh2Tm+LrEug3y1ZyKHsDA==", @@ -392,7 +870,7 @@ "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/client-api-gateway/node_modules/@aws-sdk/credential-provider-ini": { + "node_modules/@aws-sdk/client-apprunner/node_modules/@aws-sdk/credential-provider-ini": { "version": "3.693.0", "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.693.0.tgz", "integrity": "sha512-kvaa4mXhCCOuW7UQnBhYqYfgWmwy7WSBSDClutwSLPZvgrhYj2l16SD2lN4IfYdxARYMJJ1lFYp3/jJG/9Yk4Q==", @@ -418,7 +896,7 @@ "@aws-sdk/client-sts": "^3.693.0" } }, - "node_modules/@aws-sdk/client-api-gateway/node_modules/@aws-sdk/credential-provider-node": { + "node_modules/@aws-sdk/client-apprunner/node_modules/@aws-sdk/credential-provider-node": { "version": "3.693.0", "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.693.0.tgz", "integrity": "sha512-42WMsBjTNnjYxYuM3qD/Nq+8b7UdMopUq5OduMDxoM3mFTV6PXMMnfI4Z1TNnR4tYRvPXAnuNltF6xmjKbSJRA==", @@ -441,7 +919,7 @@ "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/client-api-gateway/node_modules/@aws-sdk/credential-provider-sso": { + "node_modules/@aws-sdk/client-apprunner/node_modules/@aws-sdk/credential-provider-sso": { "version": "3.693.0", "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.693.0.tgz", "integrity": "sha512-479UlJxY+BFjj3pJFYUNC0DCMrykuG7wBAXfsvZqQxKUa83DnH5Q1ID/N2hZLkxjGd4ZW0AC3lTOMxFelGzzpQ==", @@ -460,7 +938,7 @@ "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/client-api-gateway/node_modules/@aws-sdk/credential-provider-web-identity": { + "node_modules/@aws-sdk/client-apprunner/node_modules/@aws-sdk/credential-provider-web-identity": { "version": "3.693.0", "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.693.0.tgz", "integrity": "sha512-8LB210Pr6VeCiSb2hIra+sAH4KUBLyGaN50axHtIgufVK8jbKIctTZcVY5TO9Se+1107TsruzeXS7VeqVdJfFA==", @@ -479,7 +957,7 @@ "@aws-sdk/client-sts": "^3.693.0" } }, - "node_modules/@aws-sdk/client-api-gateway/node_modules/@aws-sdk/middleware-host-header": { + "node_modules/@aws-sdk/client-apprunner/node_modules/@aws-sdk/middleware-host-header": { "version": "3.693.0", "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.693.0.tgz", "integrity": "sha512-BCki6sAZ5jYwIN/t3ElCiwerHad69ipHwPsDCxJQyeiOnJ8HG+lEpnVIfrnI8A0fLQNSF3Gtx6ahfBpKiv1Oug==", @@ -494,7 +972,7 @@ "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/client-api-gateway/node_modules/@aws-sdk/middleware-logger": { + "node_modules/@aws-sdk/client-apprunner/node_modules/@aws-sdk/middleware-logger": { "version": "3.693.0", "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.693.0.tgz", "integrity": "sha512-dXnXDPr+wIiJ1TLADACI1g9pkSB21KkMIko2u4CJ2JCBoxi5IqeTnVoa6YcC8GdFNVRl+PorZ3Zqfmf1EOTC6w==", @@ -508,7 +986,7 @@ "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/client-api-gateway/node_modules/@aws-sdk/middleware-recursion-detection": { + "node_modules/@aws-sdk/client-apprunner/node_modules/@aws-sdk/middleware-recursion-detection": { "version": "3.693.0", "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.693.0.tgz", "integrity": "sha512-0LDmM+VxXp0u3rG0xQRWD/q6Ubi7G8I44tBPahevD5CaiDZTkmNTrVUf0VEJgVe0iCKBppACMBDkLB0/ETqkFw==", @@ -523,7 +1001,7 @@ "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/client-api-gateway/node_modules/@aws-sdk/middleware-user-agent": { + "node_modules/@aws-sdk/client-apprunner/node_modules/@aws-sdk/middleware-user-agent": { "version": "3.693.0", "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.693.0.tgz", "integrity": "sha512-/KUq/KEpFFbQmNmpp7SpAtFAdViquDfD2W0QcG07zYBfz9MwE2ig48ALynXm5sMpRmnG7sJXjdvPtTsSVPfkiw==", @@ -541,7 +1019,7 @@ "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/client-api-gateway/node_modules/@aws-sdk/region-config-resolver": { + "node_modules/@aws-sdk/client-apprunner/node_modules/@aws-sdk/region-config-resolver": { "version": "3.693.0", "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.693.0.tgz", "integrity": "sha512-YLUkMsUY0GLW/nfwlZ69cy1u07EZRmsv8Z9m0qW317/EZaVx59hcvmcvb+W4bFqj5E8YImTjoGfE4cZ0F9mkyw==", @@ -558,7 +1036,7 @@ "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/client-api-gateway/node_modules/@aws-sdk/token-providers": { + "node_modules/@aws-sdk/client-apprunner/node_modules/@aws-sdk/token-providers": { "version": "3.693.0", "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.693.0.tgz", "integrity": "sha512-nDBTJMk1l/YmFULGfRbToOA2wjf+FkQT4dMgYCv+V9uSYsMzQj8A7Tha2dz9yv4vnQgYaEiErQ8d7HVyXcVEoA==", @@ -577,7 +1055,7 @@ "@aws-sdk/client-sso-oidc": "^3.693.0" } }, - "node_modules/@aws-sdk/client-api-gateway/node_modules/@aws-sdk/util-endpoints": { + "node_modules/@aws-sdk/client-apprunner/node_modules/@aws-sdk/util-endpoints": { "version": "3.693.0", "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.693.0.tgz", "integrity": "sha512-eo4F6DRQ/kxS3gxJpLRv+aDNy76DxQJL5B3DPzpr9Vkq0ygVoi4GT5oIZLVaAVIJmi6k5qq9dLsYZfWLUxJJSg==", @@ -592,7 +1070,7 @@ "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/client-api-gateway/node_modules/@aws-sdk/util-user-agent-browser": { + "node_modules/@aws-sdk/client-apprunner/node_modules/@aws-sdk/util-user-agent-browser": { "version": "3.693.0", "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.693.0.tgz", "integrity": "sha512-6EUfuKOujtddy18OLJUaXfKBgs+UcbZ6N/3QV4iOkubCUdeM1maIqs++B9bhCbWeaeF5ORizJw5FTwnyNjE/mw==", @@ -604,7 +1082,7 @@ "tslib": "^2.6.2" } }, - "node_modules/@aws-sdk/client-api-gateway/node_modules/@aws-sdk/util-user-agent-node": { + "node_modules/@aws-sdk/client-apprunner/node_modules/@aws-sdk/util-user-agent-node": { "version": "3.693.0", "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.693.0.tgz", "integrity": "sha512-td0OVX8m5ZKiXtecIDuzY3Y3UZIzvxEr57Hp21NOwieqKCG2UeyQWWeGPv0FQaU7dpTkvFmVNI+tx9iB8V/Nhg==", @@ -628,7 +1106,7 @@ } } }, - "node_modules/@aws-sdk/client-api-gateway/node_modules/@smithy/is-array-buffer": { + "node_modules/@aws-sdk/client-apprunner/node_modules/@smithy/is-array-buffer": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-3.0.0.tgz", "integrity": "sha512-+Fsu6Q6C4RSJiy81Y8eApjEB5gVtM+oFKTffg+jSuwtvomJJrhUJBu2zS8wjXSgH/g1MKEWrzyChTBe6clb5FQ==", @@ -640,7 +1118,7 @@ "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/client-api-gateway/node_modules/@smithy/util-buffer-from": { + "node_modules/@aws-sdk/client-apprunner/node_modules/@smithy/util-buffer-from": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-3.0.0.tgz", "integrity": "sha512-aEOHCgq5RWFbP+UDPvPot26EJHjOC+bRgse5A8V3FSShqd5E5UN4qc7zkwsvJPPAVsf73QwYcHN1/gt/rtLwQA==", @@ -653,7 +1131,7 @@ "node": ">=16.0.0" } }, - "node_modules/@aws-sdk/client-api-gateway/node_modules/@smithy/util-utf8": { + "node_modules/@aws-sdk/client-apprunner/node_modules/@smithy/util-utf8": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-3.0.0.tgz", "integrity": "sha512-rUeT12bxFnplYDe815GXbq/oixEGHfRFFtcTF3YdDi/JaENIM6aSYYLJydG83UNzLXeRI5K8abYd/8Sp/QM0kA==", @@ -668,8 +1146,6 @@ }, "node_modules/@aws-sdk/client-cloudcontrol": { "version": "3.693.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-cloudcontrol/-/client-cloudcontrol-3.693.0.tgz", - "integrity": "sha512-kD5uaXjZ7KCLg+JTU6c49Ic1LkM821RNVj82Tgjmx7hS1JpChmf/q0v3XxRQU9GzA4Ip+gDxH/je7dzL9OxBIQ==", "license": "Apache-2.0", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", @@ -723,8 +1199,6 @@ }, "node_modules/@aws-sdk/client-cloudcontrol/node_modules/@aws-sdk/client-sso": { "version": "3.693.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.693.0.tgz", - "integrity": "sha512-QEynrBC26x6TG9ZMzApR/kZ3lmt4lEIs2D+cHuDxt6fDGzahBUsQFBwJqhizzsM97JJI5YvmJhmihoYjdSSaXA==", "license": "Apache-2.0", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", @@ -772,8 +1246,6 @@ }, "node_modules/@aws-sdk/client-cloudcontrol/node_modules/@aws-sdk/client-sso-oidc": { "version": "3.693.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso-oidc/-/client-sso-oidc-3.693.0.tgz", - "integrity": "sha512-UEDbYlYtK/e86OOMyFR4zEPyenIxDzO2DRdz3fwVW7RzZ94wfmSwBh/8skzPTuY1G7sI064cjHW0b0QG01Sdtg==", "license": "Apache-2.0", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", @@ -825,8 +1297,6 @@ }, "node_modules/@aws-sdk/client-cloudcontrol/node_modules/@aws-sdk/client-sts": { "version": "3.693.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.693.0.tgz", - "integrity": "sha512-4S2y7VEtvdnjJX4JPl4kDQlslxXEZFnC50/UXVUYSt/AMc5A/GgspFNA5FVz4E3Gwpfobbf23hR2NBF8AGvYoQ==", "license": "Apache-2.0", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", @@ -876,8 +1346,6 @@ }, "node_modules/@aws-sdk/client-cloudcontrol/node_modules/@aws-sdk/core": { "version": "3.693.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.693.0.tgz", - "integrity": "sha512-v6Z/kWmLFqRLDPEwl9hJGhtTgIFHjZugSfF1Yqffdxf4n1AWgtHS7qSegakuMyN5pP4K2tvUD8qHJ+gGe2Bw2A==", "license": "Apache-2.0", "dependencies": { "@aws-sdk/types": "3.692.0", @@ -898,8 +1366,6 @@ }, "node_modules/@aws-sdk/client-cloudcontrol/node_modules/@aws-sdk/credential-provider-http": { "version": "3.693.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.693.0.tgz", - "integrity": "sha512-sL8MvwNJU7ZpD7/d2VVb3by1GknIJUxzTIgYtVkDVA/ojo+KRQSSHxcj0EWWXF5DTSh2Tm+LrEug3y1ZyKHsDA==", "license": "Apache-2.0", "dependencies": { "@aws-sdk/core": "3.693.0", @@ -919,8 +1385,6 @@ }, "node_modules/@aws-sdk/client-cloudcontrol/node_modules/@aws-sdk/credential-provider-ini": { "version": "3.693.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.693.0.tgz", - "integrity": "sha512-kvaa4mXhCCOuW7UQnBhYqYfgWmwy7WSBSDClutwSLPZvgrhYj2l16SD2lN4IfYdxARYMJJ1lFYp3/jJG/9Yk4Q==", "license": "Apache-2.0", "dependencies": { "@aws-sdk/core": "3.693.0", @@ -945,8 +1409,6 @@ }, "node_modules/@aws-sdk/client-cloudcontrol/node_modules/@aws-sdk/credential-provider-node": { "version": "3.693.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.693.0.tgz", - "integrity": "sha512-42WMsBjTNnjYxYuM3qD/Nq+8b7UdMopUq5OduMDxoM3mFTV6PXMMnfI4Z1TNnR4tYRvPXAnuNltF6xmjKbSJRA==", "license": "Apache-2.0", "dependencies": { "@aws-sdk/credential-provider-env": "3.693.0", @@ -968,8 +1430,6 @@ }, "node_modules/@aws-sdk/client-cloudcontrol/node_modules/@aws-sdk/credential-provider-sso": { "version": "3.693.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.693.0.tgz", - "integrity": "sha512-479UlJxY+BFjj3pJFYUNC0DCMrykuG7wBAXfsvZqQxKUa83DnH5Q1ID/N2hZLkxjGd4ZW0AC3lTOMxFelGzzpQ==", "license": "Apache-2.0", "dependencies": { "@aws-sdk/client-sso": "3.693.0", @@ -987,8 +1447,6 @@ }, "node_modules/@aws-sdk/client-cloudcontrol/node_modules/@aws-sdk/credential-provider-web-identity": { "version": "3.693.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.693.0.tgz", - "integrity": "sha512-8LB210Pr6VeCiSb2hIra+sAH4KUBLyGaN50axHtIgufVK8jbKIctTZcVY5TO9Se+1107TsruzeXS7VeqVdJfFA==", "license": "Apache-2.0", "dependencies": { "@aws-sdk/core": "3.693.0", @@ -1006,8 +1464,6 @@ }, "node_modules/@aws-sdk/client-cloudcontrol/node_modules/@aws-sdk/middleware-host-header": { "version": "3.693.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.693.0.tgz", - "integrity": "sha512-BCki6sAZ5jYwIN/t3ElCiwerHad69ipHwPsDCxJQyeiOnJ8HG+lEpnVIfrnI8A0fLQNSF3Gtx6ahfBpKiv1Oug==", "license": "Apache-2.0", "dependencies": { "@aws-sdk/types": "3.692.0", @@ -1021,8 +1477,6 @@ }, "node_modules/@aws-sdk/client-cloudcontrol/node_modules/@aws-sdk/middleware-logger": { "version": "3.693.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.693.0.tgz", - "integrity": "sha512-dXnXDPr+wIiJ1TLADACI1g9pkSB21KkMIko2u4CJ2JCBoxi5IqeTnVoa6YcC8GdFNVRl+PorZ3Zqfmf1EOTC6w==", "license": "Apache-2.0", "dependencies": { "@aws-sdk/types": "3.692.0", @@ -1035,8 +1489,6 @@ }, "node_modules/@aws-sdk/client-cloudcontrol/node_modules/@aws-sdk/middleware-recursion-detection": { "version": "3.693.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.693.0.tgz", - "integrity": "sha512-0LDmM+VxXp0u3rG0xQRWD/q6Ubi7G8I44tBPahevD5CaiDZTkmNTrVUf0VEJgVe0iCKBppACMBDkLB0/ETqkFw==", "license": "Apache-2.0", "dependencies": { "@aws-sdk/types": "3.692.0", @@ -1050,8 +1502,6 @@ }, "node_modules/@aws-sdk/client-cloudcontrol/node_modules/@aws-sdk/middleware-user-agent": { "version": "3.693.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.693.0.tgz", - "integrity": "sha512-/KUq/KEpFFbQmNmpp7SpAtFAdViquDfD2W0QcG07zYBfz9MwE2ig48ALynXm5sMpRmnG7sJXjdvPtTsSVPfkiw==", "license": "Apache-2.0", "dependencies": { "@aws-sdk/core": "3.693.0", @@ -1068,8 +1518,6 @@ }, "node_modules/@aws-sdk/client-cloudcontrol/node_modules/@aws-sdk/region-config-resolver": { "version": "3.693.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.693.0.tgz", - "integrity": "sha512-YLUkMsUY0GLW/nfwlZ69cy1u07EZRmsv8Z9m0qW317/EZaVx59hcvmcvb+W4bFqj5E8YImTjoGfE4cZ0F9mkyw==", "license": "Apache-2.0", "dependencies": { "@aws-sdk/types": "3.692.0", @@ -1085,8 +1533,6 @@ }, "node_modules/@aws-sdk/client-cloudcontrol/node_modules/@aws-sdk/token-providers": { "version": "3.693.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.693.0.tgz", - "integrity": "sha512-nDBTJMk1l/YmFULGfRbToOA2wjf+FkQT4dMgYCv+V9uSYsMzQj8A7Tha2dz9yv4vnQgYaEiErQ8d7HVyXcVEoA==", "license": "Apache-2.0", "dependencies": { "@aws-sdk/types": "3.692.0", @@ -1104,8 +1550,6 @@ }, "node_modules/@aws-sdk/client-cloudcontrol/node_modules/@aws-sdk/util-endpoints": { "version": "3.693.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.693.0.tgz", - "integrity": "sha512-eo4F6DRQ/kxS3gxJpLRv+aDNy76DxQJL5B3DPzpr9Vkq0ygVoi4GT5oIZLVaAVIJmi6k5qq9dLsYZfWLUxJJSg==", "license": "Apache-2.0", "dependencies": { "@aws-sdk/types": "3.692.0", @@ -1119,8 +1563,6 @@ }, "node_modules/@aws-sdk/client-cloudcontrol/node_modules/@aws-sdk/util-user-agent-browser": { "version": "3.693.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.693.0.tgz", - "integrity": "sha512-6EUfuKOujtddy18OLJUaXfKBgs+UcbZ6N/3QV4iOkubCUdeM1maIqs++B9bhCbWeaeF5ORizJw5FTwnyNjE/mw==", "license": "Apache-2.0", "dependencies": { "@aws-sdk/types": "3.692.0", @@ -1131,8 +1573,6 @@ }, "node_modules/@aws-sdk/client-cloudcontrol/node_modules/@aws-sdk/util-user-agent-node": { "version": "3.693.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.693.0.tgz", - "integrity": "sha512-td0OVX8m5ZKiXtecIDuzY3Y3UZIzvxEr57Hp21NOwieqKCG2UeyQWWeGPv0FQaU7dpTkvFmVNI+tx9iB8V/Nhg==", "license": "Apache-2.0", "dependencies": { "@aws-sdk/middleware-user-agent": "3.693.0", @@ -1155,8 +1595,6 @@ }, "node_modules/@aws-sdk/client-cloudcontrol/node_modules/@smithy/is-array-buffer": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-3.0.0.tgz", - "integrity": "sha512-+Fsu6Q6C4RSJiy81Y8eApjEB5gVtM+oFKTffg+jSuwtvomJJrhUJBu2zS8wjXSgH/g1MKEWrzyChTBe6clb5FQ==", "license": "Apache-2.0", "dependencies": { "tslib": "^2.6.2" @@ -1167,8 +1605,6 @@ }, "node_modules/@aws-sdk/client-cloudcontrol/node_modules/@smithy/util-buffer-from": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-3.0.0.tgz", - "integrity": "sha512-aEOHCgq5RWFbP+UDPvPot26EJHjOC+bRgse5A8V3FSShqd5E5UN4qc7zkwsvJPPAVsf73QwYcHN1/gt/rtLwQA==", "license": "Apache-2.0", "dependencies": { "@smithy/is-array-buffer": "^3.0.0", @@ -1180,8 +1616,6 @@ }, "node_modules/@aws-sdk/client-cloudcontrol/node_modules/@smithy/util-utf8": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-3.0.0.tgz", - "integrity": "sha512-rUeT12bxFnplYDe815GXbq/oixEGHfRFFtcTF3YdDi/JaENIM6aSYYLJydG83UNzLXeRI5K8abYd/8Sp/QM0kA==", "license": "Apache-2.0", "dependencies": { "@smithy/util-buffer-from": "^3.0.0", @@ -9319,8 +9753,6 @@ }, "node_modules/@aws-sdk/middleware-sdk-api-gateway": { "version": "3.693.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-sdk-api-gateway/-/middleware-sdk-api-gateway-3.693.0.tgz", - "integrity": "sha512-SvvrnN1+hC0DmXBA/QA9aEEgf0+YIsGuydX43y3gej0wQGF6jrdMyOoBumKCmOmvnOqbDSrBCW9RhdLVPauQJw==", "license": "Apache-2.0", "dependencies": { "@aws-sdk/types": "3.692.0", @@ -10492,9 +10924,8 @@ }, "node_modules/@aws-toolkits/telemetry": { "version": "1.0.308", - "resolved": "https://registry.npmjs.org/@aws-toolkits/telemetry/-/telemetry-1.0.308.tgz", - "integrity": "sha512-cDyQABBXbfVyNpLBB7mcosH0sPuwGmCtFXToOdwHpxVTOcIUAlHtshhpaqDEoMbCO/jFAq28mAUYyk4xtBZogg==", "dev": true, + "license": "Apache-2.0", "dependencies": { "ajv": "^6.12.6", "cross-spawn": "^7.0.6", @@ -10514,14 +10945,6 @@ "@aws/language-server-runtimes-types": "^0.0.7" } }, - "node_modules/@aws/fully-qualified-names": { - "version": "2.1.4", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "web-tree-sitter": "^0.20.8" - } - }, "node_modules/@aws/language-server-runtimes": { "version": "0.2.27", "resolved": "https://registry.npmjs.org/@aws/language-server-runtimes/-/language-server-runtimes-0.2.27.tgz", @@ -10611,9 +11034,8 @@ }, "node_modules/@aws/mynah-ui": { "version": "4.25.1", - "resolved": "https://registry.npmjs.org/@aws/mynah-ui/-/mynah-ui-4.25.1.tgz", - "integrity": "sha512-CdOaaFzeG/f1PbqmTTG2xcYC/tIfvYC5RXKOyXswRGbL+Eh5Sec0DwYJQirhK2fpVC6FHsIni3t1o86PiOqFZg==", "hasInstallScript": true, + "license": "Apache License 2.0", "dependencies": { "escape-html": "^1.0.3", "highlight.js": "^11.11.0", @@ -22740,9 +23162,8 @@ }, "node_modules/ts-node": { "version": "10.9.2", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", - "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", "dev": true, + "license": "MIT", "dependencies": { "@cspotcode/source-map-support": "^0.8.0", "@tsconfig/node10": "^1.0.7", @@ -24400,7 +24821,7 @@ }, "packages/amazonq": { "name": "amazon-q-vscode", - "version": "1.52.0-SNAPSHOT", + "version": "1.53.0-SNAPSHOT", "license": "Apache-2.0", "dependencies": { "aws-core-vscode": "file:../core/" @@ -24419,6 +24840,7 @@ "@amzn/amazon-q-developer-streaming-client": "file:../../src.gen/@amzn/amazon-q-developer-streaming-client", "@amzn/codewhisperer-streaming": "file:../../src.gen/@amzn/codewhisperer-streaming", "@aws-sdk/client-api-gateway": "<3.696.0", + "@aws-sdk/client-apprunner": "<3.696.0", "@aws-sdk/client-cloudcontrol": "<3.696.0", "@aws-sdk/client-cloudformation": "<3.696.0", "@aws-sdk/client-cloudwatch-logs": "<3.696.0", @@ -24497,7 +24919,6 @@ "devDependencies": { "@aws-sdk/types": "^3.13.1", "@aws/chat-client-ui-types": "^0.0.8", - "@aws/fully-qualified-names": "^2.1.4", "@aws/language-server-runtimes": "^0.2.27", "@cspotcode/source-map-support": "^0.8.1", "@sinonjs/fake-timers": "^10.0.2", @@ -25202,7 +25623,7 @@ }, "packages/toolkit": { "name": "aws-toolkit-vscode", - "version": "3.51.0-SNAPSHOT", + "version": "3.52.0-SNAPSHOT", "license": "Apache-2.0", "dependencies": { "aws-core-vscode": "file:../core/" @@ -28991,7 +29412,7 @@ } }, "src.gen/@amzn/codewhisperer-streaming/node_modules/downlevel-dts/node_modules/typescript": { - "version": "5.8.0-dev.20250214", + "version": "5.9.0-dev.20250314", "dev": true, "license": "Apache-2.0", "bin": { diff --git a/packages/amazonq/.changes/1.52.0.json b/packages/amazonq/.changes/1.52.0.json new file mode 100644 index 00000000000..a4f357edc87 --- /dev/null +++ b/packages/amazonq/.changes/1.52.0.json @@ -0,0 +1,50 @@ +{ + "date": "2025-03-20", + "version": "1.52.0", + "entries": [ + { + "type": "Bug Fix", + "description": "Amazon Q chat: @Folders and @Files are missing `@` prefix in chat history" + }, + { + "type": "Bug Fix", + "description": "/review: Code Issues ellipses menu displays AWS Toolkit options, if installed." + }, + { + "type": "Bug Fix", + "description": "Amazon Q chat: Progress indicator height is stretched" + }, + { + "type": "Bug Fix", + "description": "Amazon Q chat: Long descriptions in context list are cut off" + }, + { + "type": "Bug Fix", + "description": "Amazon Q chat: Improve responses for saved prompts and workspace rules" + }, + { + "type": "Bug Fix", + "description": "/test: show descriptive error message" + }, + { + "type": "Bug Fix", + "description": "Code Review: Fixed a bug where issues are double counted in the Q chat" + }, + { + "type": "Bug Fix", + "description": "Amazon Q chat: Animation timings are too long" + }, + { + "type": "Bug Fix", + "description": "Fix inline completion failure due to context length exceeding the threshold" + }, + { + "type": "Feature", + "description": "/review: passing referenceTrackerConfiguration to StartCodeFixJob" + }, + { + "type": "Feature", + "description": "/review: rename setting `showInlineCodeSuggestionsWithCodeReferences` to `showCodeWithReferences`" + } + ] +} \ No newline at end of file diff --git a/packages/amazonq/.changes/next-release/Bug Fix-2ce6a8ba-dbc9-4798-92f4-db2abb4de17b.json b/packages/amazonq/.changes/next-release/Bug Fix-2ce6a8ba-dbc9-4798-92f4-db2abb4de17b.json deleted file mode 100644 index 3cf406600f7..00000000000 --- a/packages/amazonq/.changes/next-release/Bug Fix-2ce6a8ba-dbc9-4798-92f4-db2abb4de17b.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "type": "Bug Fix", - "description": "Amazon Q chat: @Folders and @Files are missing `@` prefix in chat history" -} diff --git a/packages/amazonq/.changes/next-release/Bug Fix-385a5132-b128-4acb-920a-53990ebdb7c4.json b/packages/amazonq/.changes/next-release/Bug Fix-385a5132-b128-4acb-920a-53990ebdb7c4.json deleted file mode 100644 index 8e65afb7cc8..00000000000 --- a/packages/amazonq/.changes/next-release/Bug Fix-385a5132-b128-4acb-920a-53990ebdb7c4.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "type": "Bug Fix", - "description": "/review: Code Issues ellipses menu displays AWS Toolkit options, if installed." -} diff --git a/packages/amazonq/.changes/next-release/Bug Fix-4116a3e0-6c6d-48bf-a991-3f872a68a121.json b/packages/amazonq/.changes/next-release/Bug Fix-4116a3e0-6c6d-48bf-a991-3f872a68a121.json deleted file mode 100644 index 78d0fb2249c..00000000000 --- a/packages/amazonq/.changes/next-release/Bug Fix-4116a3e0-6c6d-48bf-a991-3f872a68a121.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "type": "Bug Fix", - "description": "Amazon Q chat: Progress indicator height is stretched" -} diff --git a/packages/amazonq/.changes/next-release/Bug Fix-5bc056f9-796f-45e8-b04c-574821cb5171.json b/packages/amazonq/.changes/next-release/Bug Fix-5bc056f9-796f-45e8-b04c-574821cb5171.json deleted file mode 100644 index 3d4628e654b..00000000000 --- a/packages/amazonq/.changes/next-release/Bug Fix-5bc056f9-796f-45e8-b04c-574821cb5171.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "type": "Bug Fix", - "description": "Amazon Q chat: Long descriptions in context list are cut off" -} diff --git a/packages/amazonq/.changes/next-release/Bug Fix-7bb4ae68-204d-48a1-a510-490d2a2a938a.json b/packages/amazonq/.changes/next-release/Bug Fix-7bb4ae68-204d-48a1-a510-490d2a2a938a.json deleted file mode 100644 index b7f9ab81cc7..00000000000 --- a/packages/amazonq/.changes/next-release/Bug Fix-7bb4ae68-204d-48a1-a510-490d2a2a938a.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "type": "Bug Fix", - "description": "/test: show descriptive error message" -} diff --git a/packages/amazonq/.changes/next-release/Bug Fix-a24316fe-1ff9-44e4-9d5c-6b78aa7f0d1e.json b/packages/amazonq/.changes/next-release/Bug Fix-a24316fe-1ff9-44e4-9d5c-6b78aa7f0d1e.json deleted file mode 100644 index ed410a28f2b..00000000000 --- a/packages/amazonq/.changes/next-release/Bug Fix-a24316fe-1ff9-44e4-9d5c-6b78aa7f0d1e.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "type": "Bug Fix", - "description": "Code Review: Fixed a bug where issues are double counted in the Q chat" -} diff --git a/packages/amazonq/.changes/next-release/Bug Fix-b5a4a16d-16a4-40d2-985b-0d76abe475db.json b/packages/amazonq/.changes/next-release/Bug Fix-b5a4a16d-16a4-40d2-985b-0d76abe475db.json deleted file mode 100644 index ec6baa28e1a..00000000000 --- a/packages/amazonq/.changes/next-release/Bug Fix-b5a4a16d-16a4-40d2-985b-0d76abe475db.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "type": "Bug Fix", - "description": "Amazon Q chat: Animation timings are too long" -} diff --git a/packages/amazonq/.changes/next-release/Feature-7a3c930e-cc8e-4323-9ecd-c1bf767fd2ed.json b/packages/amazonq/.changes/next-release/Feature-7a3c930e-cc8e-4323-9ecd-c1bf767fd2ed.json new file mode 100644 index 00000000000..81a1e026db4 --- /dev/null +++ b/packages/amazonq/.changes/next-release/Feature-7a3c930e-cc8e-4323-9ecd-c1bf767fd2ed.json @@ -0,0 +1,4 @@ +{ + "type": "Feature", + "description": "(Experimental) Amazon Q inline code suggestions via Amazon Q Language Server. (enable with `aws.experiments.amazonqLSP: true`)" +} diff --git a/packages/amazonq/.changes/next-release/Feature-b0ddb09f-ae4a-453f-b689-a5c6c5f599f9.json b/packages/amazonq/.changes/next-release/Feature-b0ddb09f-ae4a-453f-b689-a5c6c5f599f9.json deleted file mode 100644 index d3d53817245..00000000000 --- a/packages/amazonq/.changes/next-release/Feature-b0ddb09f-ae4a-453f-b689-a5c6c5f599f9.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "type": "Feature", - "description": "/review: rename setting `showInlineCodeSuggestionsWithCodeReferences` to `showCodeWithReferences`" -} diff --git a/packages/amazonq/CHANGELOG.md b/packages/amazonq/CHANGELOG.md index 79d01a0624f..f938e36fbd6 100644 --- a/packages/amazonq/CHANGELOG.md +++ b/packages/amazonq/CHANGELOG.md @@ -1,3 +1,17 @@ +## 1.52.0 2025-03-20 + +- **Bug Fix** Amazon Q chat: @Folders and @Files are missing `@` prefix in chat history +- **Bug Fix** /review: Code Issues ellipses menu displays AWS Toolkit options, if installed. +- **Bug Fix** Amazon Q chat: Progress indicator height is stretched +- **Bug Fix** Amazon Q chat: Long descriptions in context list are cut off +- **Bug Fix** Amazon Q chat: Improve responses for saved prompts and workspace rules +- **Bug Fix** /test: show descriptive error message +- **Bug Fix** Code Review: Fixed a bug where issues are double counted in the Q chat +- **Bug Fix** Amazon Q chat: Animation timings are too long +- **Bug Fix** Fix inline completion failure due to context length exceeding the threshold +- **Feature** /review: passing referenceTrackerConfiguration to StartCodeFixJob +- **Feature** /review: rename setting `showInlineCodeSuggestionsWithCodeReferences` to `showCodeWithReferences` + ## 1.51.0 2025-03-12 - **Bug Fix** increase scan timeout to reduce front-end timeout errors diff --git a/packages/amazonq/package.json b/packages/amazonq/package.json index 7d4ce259787..5af0194206e 100644 --- a/packages/amazonq/package.json +++ b/packages/amazonq/package.json @@ -2,7 +2,7 @@ "name": "amazon-q-vscode", "displayName": "Amazon Q", "description": "The most capable generative AI-powered assistant for building, operating, and transforming software, with advanced capabilities for managing data and AI", - "version": "1.52.0-SNAPSHOT", + "version": "1.53.0-SNAPSHOT", "extensionKind": [ "workspace" ], @@ -32,7 +32,8 @@ "Codewhisperer", "AI", "Assistant", - "Chatbot" + "Chatbot", + "Q Developer" ], "preview": false, "qna": "https://github.com/aws/aws-toolkit-vscode/issues", diff --git a/packages/amazonq/scripts/build/copyFiles.ts b/packages/amazonq/scripts/build/copyFiles.ts index 725c66ad7c0..45b1d263f0b 100644 --- a/packages/amazonq/scripts/build/copyFiles.ts +++ b/packages/amazonq/scripts/build/copyFiles.ts @@ -56,17 +56,6 @@ const tasks: CopyTask[] = [ destination: 'vue/', }, - // Mynah - { - target: path.join( - '../../node_modules', - '@aws', - 'fully-qualified-names', - 'node', - 'aws_fully_qualified_names_bg.wasm' - ), - destination: path.join('src', 'aws_fully_qualified_names_bg.wasm'), - }, { target: path.join('../../node_modules', 'web-tree-sitter', 'tree-sitter.wasm'), destination: path.join('src', 'tree-sitter.wasm'), diff --git a/packages/amazonq/src/app/inline/completion.ts b/packages/amazonq/src/app/inline/completion.ts index 8ac523626a3..94700768607 100644 --- a/packages/amazonq/src/app/inline/completion.ts +++ b/packages/amazonq/src/app/inline/completion.ts @@ -22,40 +22,11 @@ import { logInlineCompletionSessionResultsNotificationType, LogInlineCompletionSessionResultsParams, } from '@aws/language-server-runtimes/protocol' - -export const CodewhispererInlineCompletionLanguages = [ - { scheme: 'file', language: 'typescript' }, - { scheme: 'file', language: 'javascript' }, - { scheme: 'file', language: 'json' }, - { scheme: 'file', language: 'yaml' }, - { scheme: 'file', language: 'java' }, - { scheme: 'file', language: 'go' }, - { scheme: 'file', language: 'php' }, - { scheme: 'file', language: 'rust' }, - { scheme: 'file', language: 'kotlin' }, - { scheme: 'file', language: 'terraform' }, - { scheme: 'file', language: 'ruby' }, - { scheme: 'file', language: 'shellscript' }, - { scheme: 'file', language: 'dart' }, - { scheme: 'file', language: 'lua' }, - { scheme: 'file', language: 'powershell' }, - { scheme: 'file', language: 'r' }, - { scheme: 'file', language: 'swift' }, - { scheme: 'file', language: 'systemverilog' }, - { scheme: 'file', language: 'scala' }, - { scheme: 'file', language: 'vue' }, - { scheme: 'file', language: 'csharp' }, - { scheme: 'file', language: 'python' }, - { scheme: 'file', language: 'c' }, - { scheme: 'file', language: 'cpp' }, - { scheme: 'file', language: 'sql' }, - { scheme: 'file', language: 'tsx' }, - { scheme: 'file', language: 'jsx' }, -] +import { CodeWhispererConstants } from 'aws-core-vscode/codewhisperer' export function registerInlineCompletion(languageClient: LanguageClient) { const inlineCompletionProvider = new AmazonQInlineCompletionItemProvider(languageClient) - languages.registerInlineCompletionItemProvider(CodewhispererInlineCompletionLanguages, inlineCompletionProvider) + languages.registerInlineCompletionItemProvider(CodeWhispererConstants.platformLanguageIds, inlineCompletionProvider) const onInlineAcceptance = async ( sessionId: string, diff --git a/packages/amazonq/src/extension.ts b/packages/amazonq/src/extension.ts index ae5d669c702..ad89a44ed4d 100644 --- a/packages/amazonq/src/extension.ts +++ b/packages/amazonq/src/extension.ts @@ -157,7 +157,7 @@ export async function activateAmazonQCommon(context: vscode.ExtensionContext, is context.subscriptions.push( Experiments.instance.onDidChange(async (event) => { - if (event.key === 'amazonqLSP') { + if (event.key === 'amazonqLSP' || event.key === 'amazonqChatLSP') { await vscode.window .showInformationMessage( 'Amazon Q LSP setting has changed. Reload VS Code for the changes to take effect.', diff --git a/packages/amazonq/src/extensionNode.ts b/packages/amazonq/src/extensionNode.ts index 1b9200f7b59..d9d36f828eb 100644 --- a/packages/amazonq/src/extensionNode.ts +++ b/packages/amazonq/src/extensionNode.ts @@ -7,7 +7,15 @@ import * as vscode from 'vscode' import { activateAmazonQCommon, amazonQContextPrefix, deactivateCommon } from './extension' import { DefaultAmazonQAppInitContext } from 'aws-core-vscode/amazonq' import { activate as activateQGumby } from 'aws-core-vscode/amazonqGumby' -import { ExtContext, globals, CrashMonitoring, getLogger, isNetworkError, isSageMaker } from 'aws-core-vscode/shared' +import { + ExtContext, + globals, + CrashMonitoring, + getLogger, + isNetworkError, + isSageMaker, + Experiments, +} from 'aws-core-vscode/shared' import { filetypes, SchemaService } from 'aws-core-vscode/sharedNode' import { updateDevMode } from 'aws-core-vscode/dev' import { CommonAuthViewProvider } from 'aws-core-vscode/login' @@ -43,8 +51,10 @@ async function activateAmazonQNode(context: vscode.ExtensionContext) { extensionContext: context, } - await activateCWChat(context) - await activateQGumby(extContext as ExtContext) + if (!Experiments.instance.get('amazonqChatLSP', false)) { + await activateCWChat(context) + await activateQGumby(extContext as ExtContext) + } const authProvider = new CommonAuthViewProvider( context, diff --git a/packages/amazonq/src/lsp/chat/activation.ts b/packages/amazonq/src/lsp/chat/activation.ts new file mode 100644 index 00000000000..406b753716f --- /dev/null +++ b/packages/amazonq/src/lsp/chat/activation.ts @@ -0,0 +1,34 @@ +/*! + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +import { window } from 'vscode' +import { LanguageClient } from 'vscode-languageclient' +import { AmazonQChatViewProvider } from './webviewProvider' +import { registerCommands } from './commands' +import { registerLanguageServerEventListener, registerMessageListeners } from './messages' +import { globals } from 'aws-core-vscode/shared' + +export function activate(languageClient: LanguageClient, encryptionKey: Buffer, mynahUIPath: string) { + const provider = new AmazonQChatViewProvider(mynahUIPath) + + globals.context.subscriptions.push( + window.registerWebviewViewProvider(AmazonQChatViewProvider.viewType, provider, { + webviewOptions: { + retainContextWhenHidden: true, + }, + }) + ) + + /** + * Commands are registered independent of the webview being open because when they're executed + * they focus the webview + **/ + registerCommands(provider) + registerLanguageServerEventListener(languageClient, provider) + + provider.onDidResolveWebview(() => { + registerMessageListeners(languageClient, provider, encryptionKey) + }) +} diff --git a/packages/amazonq/src/lsp/chat/commands.ts b/packages/amazonq/src/lsp/chat/commands.ts new file mode 100644 index 00000000000..3febc748442 --- /dev/null +++ b/packages/amazonq/src/lsp/chat/commands.ts @@ -0,0 +1,79 @@ +/*! + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +import * as vscode from 'vscode' +import { Commands, globals } from 'aws-core-vscode/shared' +import { window } from 'vscode' +import { AmazonQChatViewProvider } from './webviewProvider' + +export function registerCommands(provider: AmazonQChatViewProvider) { + globals.context.subscriptions.push( + registerGenericCommand('aws.amazonq.explainCode', 'Explain', provider), + registerGenericCommand('aws.amazonq.refactorCode', 'Refactor', provider), + registerGenericCommand('aws.amazonq.fixCode', 'Fix', provider), + registerGenericCommand('aws.amazonq.optimizeCode', 'Optimize', provider), + Commands.register('aws.amazonq.sendToPrompt', (data) => { + const triggerType = getCommandTriggerType(data) + const selection = getSelectedText() + + void focusAmazonQPanel().then(() => { + void provider.webview?.postMessage({ + command: 'sendToPrompt', + params: { selection: selection, triggerType }, + }) + }) + }), + Commands.register('aws.amazonq.openTab', () => { + void focusAmazonQPanel().then(() => { + void provider.webview?.postMessage({ + command: 'aws/chat/openTab', + params: {}, + }) + }) + }) + ) +} + +function getSelectedText(): string { + const editor = window.activeTextEditor + if (editor) { + const selection = editor.selection + const selectedText = editor.document.getText(selection) + return selectedText + } + + return ' ' +} + +function getCommandTriggerType(data: any): string { + // data is undefined when commands triggered from keybinding or command palette. Currently no + // way to differentiate keybinding and command palette, so both interactions are recorded as keybinding + return data === undefined ? 'hotkeys' : 'contextMenu' +} + +function registerGenericCommand(commandName: string, genericCommand: string, provider: AmazonQChatViewProvider) { + return Commands.register(commandName, (data) => { + const triggerType = getCommandTriggerType(data) + const selection = getSelectedText() + + void focusAmazonQPanel().then(() => { + void provider.webview?.postMessage({ + command: 'genericCommand', + params: { genericCommand, selection, triggerType }, + }) + }) + }) +} + +/** + * Importing focusAmazonQPanel from aws-core-vscode/amazonq leads to several dependencies down the chain not resolving since AmazonQ chat + * is currently only activated on node, but the language server is activated on both web and node. + * + * Instead, we just create our own as a temporary solution + */ +async function focusAmazonQPanel() { + await vscode.commands.executeCommand('aws.amazonq.AmazonQChatView.focus') + await vscode.commands.executeCommand('aws.amazonq.AmazonCommonAuth.focus') +} diff --git a/packages/amazonq/src/lsp/chat/messages.ts b/packages/amazonq/src/lsp/chat/messages.ts new file mode 100644 index 00000000000..4c9d93f7f65 --- /dev/null +++ b/packages/amazonq/src/lsp/chat/messages.ts @@ -0,0 +1,225 @@ +/*! + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +import { + isValidAuthFollowUpType, + INSERT_TO_CURSOR_POSITION, + AUTH_FOLLOW_UP_CLICKED, + CHAT_OPTIONS, + COPY_TO_CLIPBOARD, +} from '@aws/chat-client-ui-types' +import { + ChatResult, + chatRequestType, + ChatParams, + followUpClickNotificationType, + quickActionRequestType, + QuickActionResult, + QuickActionParams, + insertToCursorPositionNotificationType, +} from '@aws/language-server-runtimes/protocol' +import { v4 as uuidv4 } from 'uuid' +import { window } from 'vscode' +import { Disposable, LanguageClient, Position, State, TextDocumentIdentifier } from 'vscode-languageclient' +import * as jose from 'jose' +import { AmazonQChatViewProvider } from './webviewProvider' + +export function registerLanguageServerEventListener(languageClient: LanguageClient, provider: AmazonQChatViewProvider) { + languageClient.onDidChangeState(({ oldState, newState }) => { + if (oldState === State.Starting && newState === State.Running) { + languageClient.info( + 'Language client received initializeResult from server:', + JSON.stringify(languageClient.initializeResult) + ) + + const chatOptions = languageClient.initializeResult?.awsServerCapabilities?.chatOptions + + void provider.webview?.postMessage({ + command: CHAT_OPTIONS, + params: chatOptions, + }) + } + }) + + languageClient.onTelemetry((e) => { + languageClient.info(`[VSCode Client] Received telemetry event from server ${JSON.stringify(e)}`) + }) +} + +export function registerMessageListeners( + languageClient: LanguageClient, + provider: AmazonQChatViewProvider, + encryptionKey: Buffer +) { + provider.webview?.onDidReceiveMessage(async (message) => { + languageClient.info(`[VSCode Client] Received ${JSON.stringify(message)} from chat`) + + switch (message.command) { + case COPY_TO_CLIPBOARD: + // TODO see what we need to hook this up + languageClient.info('[VSCode Client] Copy to clipboard event received') + break + case INSERT_TO_CURSOR_POSITION: { + const editor = window.activeTextEditor + let textDocument: TextDocumentIdentifier | undefined = undefined + let cursorPosition: Position | undefined = undefined + if (editor) { + cursorPosition = editor.selection.active + textDocument = { uri: editor.document.uri.toString() } + } + + languageClient.sendNotification(insertToCursorPositionNotificationType.method, { + ...message.params, + cursorPosition, + textDocument, + }) + break + } + case AUTH_FOLLOW_UP_CLICKED: + // TODO hook this into auth + languageClient.info('[VSCode Client] AuthFollowUp clicked') + break + case chatRequestType.method: { + const partialResultToken = uuidv4() + const chatDisposable = languageClient.onProgress(chatRequestType, partialResultToken, (partialResult) => + handlePartialResult(partialResult, encryptionKey, provider, message.params.tabId) + ) + + const editor = + window.activeTextEditor || + window.visibleTextEditors.find((editor) => editor.document.languageId !== 'Log') + if (editor) { + message.params.cursorPosition = [editor.selection.active] + message.params.textDocument = { uri: editor.document.uri.toString() } + } + + const chatRequest = await encryptRequest(message.params, encryptionKey) + const chatResult = (await languageClient.sendRequest(chatRequestType.method, { + ...chatRequest, + partialResultToken, + })) as string | ChatResult + void handleCompleteResult( + chatResult, + encryptionKey, + provider, + message.params.tabId, + chatDisposable + ) + break + } + case quickActionRequestType.method: { + const quickActionPartialResultToken = uuidv4() + const quickActionDisposable = languageClient.onProgress( + quickActionRequestType, + quickActionPartialResultToken, + (partialResult) => + handlePartialResult( + partialResult, + encryptionKey, + provider, + message.params.tabId + ) + ) + + const quickActionRequest = await encryptRequest(message.params, encryptionKey) + const quickActionResult = (await languageClient.sendRequest(quickActionRequestType.method, { + ...quickActionRequest, + partialResultToken: quickActionPartialResultToken, + })) as string | ChatResult + void handleCompleteResult( + quickActionResult, + encryptionKey, + provider, + message.params.tabId, + quickActionDisposable + ) + break + } + case followUpClickNotificationType.method: + if (!isValidAuthFollowUpType(message.params.followUp.type)) { + languageClient.sendNotification(followUpClickNotificationType.method, message.params) + } + break + default: + if (isServerEvent(message.command)) { + languageClient.sendNotification(message.command, message.params) + } + break + } + }, undefined) +} + +function isServerEvent(command: string) { + return command.startsWith('aws/chat/') || command === 'telemetry/event' +} + +async function encryptRequest(params: T, encryptionKey: Buffer): Promise<{ message: string } | T> { + const payload = new TextEncoder().encode(JSON.stringify(params)) + + const encryptedMessage = await new jose.CompactEncrypt(payload) + .setProtectedHeader({ alg: 'dir', enc: 'A256GCM' }) + .encrypt(encryptionKey) + + return { message: encryptedMessage } +} + +async function decodeRequest(request: string, key: Buffer): Promise { + const result = await jose.jwtDecrypt(request, key, { + clockTolerance: 60, // Allow up to 60 seconds to account for clock differences + contentEncryptionAlgorithms: ['A256GCM'], + keyManagementAlgorithms: ['dir'], + }) + + if (!result.payload) { + throw new Error('JWT payload not found') + } + return result.payload as T +} + +/** + * Decodes partial chat responses from the language server before sending them to mynah UI + */ +async function handlePartialResult( + partialResult: string | T, + encryptionKey: Buffer | undefined, + provider: AmazonQChatViewProvider, + tabId: string +) { + const decryptedMessage = + typeof partialResult === 'string' && encryptionKey + ? await decodeRequest(partialResult, encryptionKey) + : (partialResult as T) + + if (decryptedMessage.body) { + void provider.webview?.postMessage({ + command: chatRequestType.method, + params: decryptedMessage, + isPartialResult: true, + tabId: tabId, + }) + } +} + +/** + * Decodes the final chat responses from the language server before sending it to mynah UI. + * Once this is called the answer response is finished + */ +async function handleCompleteResult( + result: string | T, + encryptionKey: Buffer | undefined, + provider: AmazonQChatViewProvider, + tabId: string, + disposable: Disposable +) { + const decryptedMessage = + typeof result === 'string' && encryptionKey ? await decodeRequest(result, encryptionKey) : result + + void provider.webview?.postMessage({ + command: chatRequestType.method, + params: decryptedMessage, + tabId: tabId, + }) + disposable.dispose() +} diff --git a/packages/amazonq/src/lsp/chat/webviewProvider.ts b/packages/amazonq/src/lsp/chat/webviewProvider.ts new file mode 100644 index 00000000000..7bfab17f3ae --- /dev/null +++ b/packages/amazonq/src/lsp/chat/webviewProvider.ts @@ -0,0 +1,73 @@ +/*! + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +import { + EventEmitter, + CancellationToken, + Webview, + WebviewView, + WebviewViewProvider, + WebviewViewResolveContext, + Uri, +} from 'vscode' +import { LanguageServerResolver } from 'aws-core-vscode/shared' + +export class AmazonQChatViewProvider implements WebviewViewProvider { + public static readonly viewType = 'aws.amazonq.AmazonQChatView' + private readonly onDidResolveWebviewEmitter = new EventEmitter() + public readonly onDidResolveWebview = this.onDidResolveWebviewEmitter.event + + webview: Webview | undefined + + constructor(private readonly mynahUIPath: string) {} + + public resolveWebviewView(webviewView: WebviewView, context: WebviewViewResolveContext, _token: CancellationToken) { + this.webview = webviewView.webview + + const lspDir = Uri.parse(LanguageServerResolver.defaultDir) + webviewView.webview.options = { + enableScripts: true, + enableCommandUris: true, + localResourceRoots: [lspDir], + } + + const uiPath = webviewView.webview.asWebviewUri(Uri.parse(this.mynahUIPath)).toString() + webviewView.webview.html = getWebviewContent(uiPath) + + this.onDidResolveWebviewEmitter.fire() + } +} + +function getWebviewContent(mynahUIPath: string) { + return ` + + + + + + Chat + + + + + + + ` +} diff --git a/packages/amazonq/src/lsp/client.ts b/packages/amazonq/src/lsp/client.ts index f9ef046221b..297ac21c1d6 100644 --- a/packages/amazonq/src/lsp/client.ts +++ b/packages/amazonq/src/lsp/client.ts @@ -11,18 +11,16 @@ import { registerInlineCompletion } from '../app/inline/completion' import { AmazonQLspAuth, encryptionKey, notificationTypes } from './auth' import { AuthUtil } from 'aws-core-vscode/codewhisperer' import { ConnectionMetadata } from '@aws/language-server-runtimes/protocol' -import { - ResourcePaths, - Settings, - oidcClientName, - createServerOptions, - globals, - getLogger, -} from 'aws-core-vscode/shared' +import { Settings, oidcClientName, createServerOptions, globals, Experiments, getLogger } from 'aws-core-vscode/shared' +import { activate } from './chat/activation' +import { AmazonQResourcePaths } from './lspInstaller' const localize = nls.loadMessageBundle() -export async function startLanguageServer(extensionContext: vscode.ExtensionContext, resourcePaths: ResourcePaths) { +export async function startLanguageServer( + extensionContext: vscode.ExtensionContext, + resourcePaths: AmazonQResourcePaths +) { const toDispose = extensionContext.subscriptions const serverModule = resourcePaths.lsp @@ -97,6 +95,9 @@ export async function startLanguageServer(extensionContext: vscode.ExtensionCont return client.onReady().then(async () => { await auth.init() registerInlineCompletion(client) + if (Experiments.instance.get('amazonqChatLSP', false)) { + activate(client, encryptionKey, resourcePaths.mynahUI) + } // Request handler for when the server wants to know about the clients auth connnection client.onRequest(notificationTypes.getConnectionMetadata.method, () => { diff --git a/packages/amazonq/src/lsp/lspInstaller.ts b/packages/amazonq/src/lsp/lspInstaller.ts index ae7fe39cca5..31866588e07 100644 --- a/packages/amazonq/src/lsp/lspInstaller.ts +++ b/packages/amazonq/src/lsp/lspInstaller.ts @@ -8,7 +8,11 @@ import path from 'path' import { getAmazonQLspConfig } from './config' import { LspConfig } from 'aws-core-vscode/amazonq' -export class AmazonQLspInstaller extends BaseLspInstaller.BaseLspInstaller { +export interface AmazonQResourcePaths extends ResourcePaths { + mynahUI: string +} + +export class AmazonQLspInstaller extends BaseLspInstaller.BaseLspInstaller { constructor(lspConfig: LspConfig = getAmazonQLspConfig()) { super(lspConfig, 'amazonqLsp') } @@ -18,11 +22,12 @@ export class AmazonQLspInstaller extends BaseLspInstaller.BaseLspInstaller { await fs.chmod(resourcePaths.node, 0o755) } - protected override resourcePaths(assetDirectory?: string): ResourcePaths { + protected override resourcePaths(assetDirectory?: string): AmazonQResourcePaths { if (!assetDirectory) { return { lsp: this.config.path ?? '', node: getNodeExecutableName(), + mynahUI: '', // TODO make mynah UI configurable } } @@ -30,6 +35,7 @@ export class AmazonQLspInstaller extends BaseLspInstaller.BaseLspInstaller { return { lsp: path.join(assetDirectory, 'servers/aws-lsp-codewhisperer.js'), node: nodePath, + mynahUI: path.join(assetDirectory, 'clients/amazonq-ui.js'), } } } diff --git a/packages/amazonq/test/unit/amazonqFeatureDev/util/files.test.ts b/packages/amazonq/test/unit/amazonqFeatureDev/util/files.test.ts index badc34f6dd7..574d0a25a19 100644 --- a/packages/amazonq/test/unit/amazonqFeatureDev/util/files.test.ts +++ b/packages/amazonq/test/unit/amazonqFeatureDev/util/files.test.ts @@ -11,11 +11,11 @@ import { maxRepoSizeBytes, } from 'aws-core-vscode/amazonqFeatureDev' import { assertTelemetry, getWorkspaceFolder, TestFolder } from 'aws-core-vscode/test' -import { fs, AmazonqCreateUpload, ZipStream } from 'aws-core-vscode/shared' +import { fs, AmazonqCreateUpload, ZipStream, ContentLengthError } from 'aws-core-vscode/shared' import { MetricName, Span } from 'aws-core-vscode/telemetry' import sinon from 'sinon' import { CodeWhispererSettings } from 'aws-core-vscode/codewhisperer' -import { ContentLengthError, CurrentWsFolders } from 'aws-core-vscode/amazonq' +import { CurrentWsFolders } from 'aws-core-vscode/amazonq' import path from 'path' const testDevfilePrepareRepo = async (devfileEnabled: boolean) => { diff --git a/packages/amazonq/test/unit/codewhisperer/util/supplemetalContextUtil.test.ts b/packages/amazonq/test/unit/codewhisperer/util/supplemetalContextUtil.test.ts index 051ac65bee1..a42b0aa6158 100644 --- a/packages/amazonq/test/unit/codewhisperer/util/supplemetalContextUtil.test.ts +++ b/packages/amazonq/test/unit/codewhisperer/util/supplemetalContextUtil.test.ts @@ -7,12 +7,15 @@ import assert from 'assert' import * as FakeTimers from '@sinonjs/fake-timers' import * as vscode from 'vscode' import * as sinon from 'sinon' +import * as os from 'os' import * as crossFile from 'aws-core-vscode/codewhisperer' import { TestFolder, assertTabCount, installFakeClock } from 'aws-core-vscode/test' -import { FeatureConfigProvider } from 'aws-core-vscode/codewhisperer' +import { CodeWhispererSupplementalContext, FeatureConfigProvider } from 'aws-core-vscode/codewhisperer' import { toTextEditor } from 'aws-core-vscode/test' import { LspController } from 'aws-core-vscode/amazonq' +const newLine = os.EOL + describe('supplementalContextUtil', function () { let testFolder: TestFolder let clock: FakeTimers.InstalledClock @@ -83,4 +86,180 @@ describe('supplementalContextUtil', function () { }) }) }) + + describe('truncation', function () { + it('truncate context should do nothing if everything fits in constraint', function () { + const chunkA: crossFile.CodeWhispererSupplementalContextItem = { + content: 'a', + filePath: 'a.java', + score: 0, + } + const chunkB: crossFile.CodeWhispererSupplementalContextItem = { + content: 'b', + filePath: 'b.java', + score: 1, + } + const chunks = [chunkA, chunkB] + + const supplementalContext: CodeWhispererSupplementalContext = { + isUtg: false, + isProcessTimeout: false, + supplementalContextItems: chunks, + contentsLength: 25000, + latency: 0, + strategy: 'codemap', + } + + const actual = crossFile.truncateSuppelementalContext(supplementalContext) + assert.strictEqual(actual.supplementalContextItems.length, 2) + assert.strictEqual(actual.supplementalContextItems[0].content, 'a') + assert.strictEqual(actual.supplementalContextItems[1].content, 'b') + }) + + it('truncateLineByLine should drop the last line if max length is greater than threshold', function () { + const input = + repeatString('a', 11) + + newLine + + repeatString('b', 11) + + newLine + + repeatString('c', 11) + + newLine + + repeatString('d', 11) + + newLine + + repeatString('e', 11) + + assert.ok(input.length > 50) + const actual = crossFile.truncateLineByLine(input, 50) + assert.ok(actual.length <= 50) + + const input2 = repeatString(`b${newLine}`, 10) + const actual2 = crossFile.truncateLineByLine(input2, 8) + assert.ok(actual2.length <= 8) + }) + + it('truncation context should make context length per item lte 10240 cap', function () { + const chunkA: crossFile.CodeWhispererSupplementalContextItem = { + content: repeatString(`a${newLine}`, 4000), + filePath: 'a.java', + score: 0, + } + const chunkB: crossFile.CodeWhispererSupplementalContextItem = { + content: repeatString(`b${newLine}`, 6000), + filePath: 'b.java', + score: 1, + } + const chunkC: crossFile.CodeWhispererSupplementalContextItem = { + content: repeatString(`c${newLine}`, 1000), + filePath: 'c.java', + score: 2, + } + const chunkD: crossFile.CodeWhispererSupplementalContextItem = { + content: repeatString(`d${newLine}`, 1500), + filePath: 'd.java', + score: 3, + } + + assert.ok( + chunkA.content.length + chunkB.content.length + chunkC.content.length + chunkD.content.length > 20480 + ) + + const supplementalContext: CodeWhispererSupplementalContext = { + isUtg: false, + isProcessTimeout: false, + supplementalContextItems: [chunkA, chunkB, chunkC, chunkD], + contentsLength: 25000, + latency: 0, + strategy: 'codemap', + } + + const actual = crossFile.truncateSuppelementalContext(supplementalContext) + assert.strictEqual(actual.supplementalContextItems.length, 3) + assert.ok(actual.contentsLength <= 20480) + assert.strictEqual(actual.strategy, 'codemap') + }) + + it('truncate context should make context items lte 5', function () { + const chunkA: crossFile.CodeWhispererSupplementalContextItem = { + content: 'a', + filePath: 'a.java', + score: 0, + } + const chunkB: crossFile.CodeWhispererSupplementalContextItem = { + content: 'b', + filePath: 'b.java', + score: 1, + } + const chunkC: crossFile.CodeWhispererSupplementalContextItem = { + content: 'c', + filePath: 'c.java', + score: 2, + } + const chunkD: crossFile.CodeWhispererSupplementalContextItem = { + content: 'd', + filePath: 'd.java', + score: 3, + } + const chunkE: crossFile.CodeWhispererSupplementalContextItem = { + content: 'e', + filePath: 'e.java', + score: 4, + } + const chunkF: crossFile.CodeWhispererSupplementalContextItem = { + content: 'f', + filePath: 'f.java', + score: 5, + } + const chunkG: crossFile.CodeWhispererSupplementalContextItem = { + content: 'g', + filePath: 'g.java', + score: 6, + } + const chunks = [chunkA, chunkB, chunkC, chunkD, chunkE, chunkF, chunkG] + + assert.strictEqual(chunks.length, 7) + + const supplementalContext: CodeWhispererSupplementalContext = { + isUtg: false, + isProcessTimeout: false, + supplementalContextItems: chunks, + contentsLength: 25000, + latency: 0, + strategy: 'codemap', + } + + const actual = crossFile.truncateSuppelementalContext(supplementalContext) + assert.strictEqual(actual.supplementalContextItems.length, 5) + }) + + describe('truncate line by line', function () { + it('should return empty if empty string is provided', function () { + const input = '' + const actual = crossFile.truncateLineByLine(input, 50) + assert.strictEqual(actual, '') + }) + + it('should return empty if 0 max length is provided', function () { + const input = 'aaaaa' + const actual = crossFile.truncateLineByLine(input, 0) + assert.strictEqual(actual, '') + }) + + it('should flip the value if negative max length is provided', function () { + const input = `aaaaa${newLine}bbbbb` + const actual = crossFile.truncateLineByLine(input, -6) + const expected = crossFile.truncateLineByLine(input, 6) + assert.strictEqual(actual, expected) + assert.strictEqual(actual, 'aaaaa') + }) + }) + }) }) + +function repeatString(s: string, n: number): string { + let output = '' + for (let i = 0; i < n; i++) { + output += s + } + + return output +} diff --git a/packages/core/package.json b/packages/core/package.json index 4081fcffb98..a4dbf94eaee 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -442,7 +442,6 @@ "@aws/language-server-runtimes": "^0.2.27", "@aws/chat-client-ui-types": "^0.0.8", "@aws-sdk/types": "^3.13.1", - "@aws/fully-qualified-names": "^2.1.4", "@cspotcode/source-map-support": "^0.8.1", "@sinonjs/fake-timers": "^10.0.2", "@types/adm-zip": "^0.4.34", @@ -499,6 +498,7 @@ "@amzn/amazon-q-developer-streaming-client": "file:../../src.gen/@amzn/amazon-q-developer-streaming-client", "@amzn/codewhisperer-streaming": "file:../../src.gen/@amzn/codewhisperer-streaming", "@aws-sdk/client-api-gateway": "<3.696.0", + "@aws-sdk/client-cloudcontrol": "<3.696.0", "@aws-sdk/client-cloudformation": "<3.696.0", "@aws-sdk/client-cloudwatch-logs": "<3.696.0", "@aws-sdk/client-codecatalyst": "<3.696.0", @@ -512,7 +512,7 @@ "@aws-sdk/client-ssm": "<3.696.0", "@aws-sdk/client-sso": "<3.696.0", "@aws-sdk/client-sso-oidc": "<3.696.0", - "@aws-sdk/client-cloudcontrol": "<3.696.0", + "@aws-sdk/client-apprunner": "<3.696.0", "@aws-sdk/credential-provider-env": "<3.696.0", "@aws-sdk/credential-provider-process": "<3.696.0", "@aws-sdk/credential-provider-sso": "<3.696.0", diff --git a/packages/core/src/amazonq/errors.ts b/packages/core/src/amazonq/errors.ts index 799206d7ab9..36e67d7a07e 100644 --- a/packages/core/src/amazonq/errors.ts +++ b/packages/core/src/amazonq/errors.ts @@ -9,10 +9,13 @@ * When thrown from common components, individual agents can catch and transform this error * to provide their own customized error messages. */ -import { ToolkitError } from '../shared/errors' +import { ErrorInformation, ToolkitError } from '../shared/errors' -export class ContentLengthError extends ToolkitError { - constructor(message: string) { - super(message, { code: 'ContentLengthError' }) +/** + * Errors extending this class are considered "LLM failures" in service metrics. + */ +export class LlmError extends ToolkitError { + constructor(message: string, info: ErrorInformation = {}) { + super(message, info) } } diff --git a/packages/core/src/amazonq/index.ts b/packages/core/src/amazonq/index.ts index 0f9c99a5ce8..98ab00087a3 100644 --- a/packages/core/src/amazonq/index.ts +++ b/packages/core/src/amazonq/index.ts @@ -45,7 +45,6 @@ export { CodeReference } from '../codewhispererChat/view/connector/connector' export { extractAuthFollowUp } from './util/authUtils' export { Messenger } from './commons/connector/baseMessenger' export * from './lsp/config' -export { ContentLengthError } from './errors' export * as WorkspaceLspInstaller from './lsp/workspaceInstaller' import { FeatureContext } from '../shared/featureConfig' diff --git a/packages/core/src/amazonq/util/files.ts b/packages/core/src/amazonq/util/files.ts index b7c25c7f887..f61d4632714 100644 --- a/packages/core/src/amazonq/util/files.ts +++ b/packages/core/src/amazonq/util/files.ts @@ -16,7 +16,7 @@ import { PrepareRepoFailedError } from '../../amazonqFeatureDev/errors' import { getLogger } from '../../shared/logger/logger' import { maxFileSizeBytes } from '../../amazonqFeatureDev/limits' import { CurrentWsFolders, DeletedFileInfo, NewFileInfo, NewFileZipContents } from '../../amazonqDoc/types' -import { hasCode, ToolkitError } from '../../shared/errors' +import { ContentLengthError, hasCode, ToolkitError } from '../../shared/errors' import { AmazonqCreateUpload, Span, telemetry as amznTelemetry, telemetry } from '../../shared/telemetry/telemetry' import { maxRepoSizeBytes } from '../../amazonqFeatureDev/constants' import { isCodeFile } from '../../shared/filetypes' @@ -28,7 +28,6 @@ import { ZipStream } from '../../shared/utilities/zipStream' import { isPresent } from '../../shared/utilities/collectionUtils' import { AuthUtil } from '../../codewhisperer/util/authUtil' import { TelemetryHelper } from '../util/telemetryHelper' -import { ContentLengthError } from '../errors' export const SvgFileExtension = '.svg' @@ -88,7 +87,7 @@ export async function prepareRepoData( } const files = await collectFiles(repoRootPaths, workspaceFolders, { - maxSizeBytes: maxRepoSizeBytes, + maxTotalSizeBytes: maxRepoSizeBytes, excludeByGitIgnore: true, excludePatterns: excludePatterns, filterFn: filterFn, diff --git a/packages/core/src/amazonq/webview/messages/messageDispatcher.ts b/packages/core/src/amazonq/webview/messages/messageDispatcher.ts index dc3bc4c77c8..f17de54e416 100644 --- a/packages/core/src/amazonq/webview/messages/messageDispatcher.ts +++ b/packages/core/src/amazonq/webview/messages/messageDispatcher.ts @@ -16,6 +16,8 @@ import globals from '../../../shared/extensionGlobals' import { openUrl } from '../../../shared/utilities/vsCodeUtils' import { DefaultAmazonQAppInitContext } from '../../apps/initContext' +const qChatModuleName = 'amazonqChat' + export function dispatchWebViewMessagesToApps( webview: Webview, webViewToAppsMessagePublishers: Map> @@ -29,8 +31,8 @@ export function dispatchWebViewMessagesToApps( * This would be equivalent of the duration between "user clicked open q" and "ui has become available" * NOTE: Amazon Q UI is only loaded ONCE. The state is saved between each hide/show of the webview. */ - telemetry.webview_load.emit({ - webviewName: 'amazonq', + telemetry.toolkit_didLoadModule.emit({ + module: qChatModuleName, duration: performance.measure(amazonqMark.uiReady, amazonqMark.open).duration, result: 'Succeeded', }) @@ -86,12 +88,19 @@ export function dispatchWebViewMessagesToApps( } if (msg.type === 'error') { - const event = msg.event === 'webview_load' ? telemetry.webview_load : telemetry.webview_error - event.emit({ - webviewName: 'amazonqChat', - result: 'Failed', - reasonDesc: msg.errorMessage, - }) + if (msg.event === 'toolkit_didLoadModule') { + telemetry.toolkit_didLoadModule.emit({ + module: qChatModuleName, + result: 'Failed', + reasonDesc: msg.errorMessage, + }) + } else { + telemetry.webview_error.emit({ + webviewName: qChatModuleName, + result: 'Failed', + reasonDesc: msg.errorMessage, + }) + } return } diff --git a/packages/core/src/amazonq/webview/ui/main.ts b/packages/core/src/amazonq/webview/ui/main.ts index d7285d81ba5..5ae03840f8f 100644 --- a/packages/core/src/amazonq/webview/ui/main.ts +++ b/packages/core/src/amazonq/webview/ui/main.ts @@ -63,7 +63,7 @@ export const createMynahUI = ( const { error, message } = e ideApi.postMessage({ type: 'error', - event: connector.isUIReady ? 'webview_error' : 'webview_load', + event: connector.isUIReady ? 'webview_error' : 'toolkit_didLoadModule', errorMessage: error ? error.toString() : message, }) }) diff --git a/packages/core/src/amazonqDoc/session/session.ts b/packages/core/src/amazonqDoc/session/session.ts index 301a9d0e0fa..ac4a3052694 100644 --- a/packages/core/src/amazonqDoc/session/session.ts +++ b/packages/core/src/amazonqDoc/session/session.ts @@ -30,8 +30,8 @@ import fs from '../../shared/fs/fs' import globals from '../../shared/extensionGlobals' import { extensionVersion } from '../../shared/vscode/env' import { getLogger } from '../../shared/logger/logger' +import { ContentLengthError as CommonContentLengthError } from '../../shared/errors' import { ContentLengthError } from '../errors' -import { ContentLengthError as CommonAmazonQContentLengthError } from '../../amazonq/errors' export class Session { private _state?: SessionState | Omit @@ -152,7 +152,7 @@ export class Session { return resp.interaction } catch (e) { - if (e instanceof CommonAmazonQContentLengthError) { + if (e instanceof CommonContentLengthError) { getLogger().debug(`Content length validation failed: ${e.message}`) throw new ContentLengthError() } diff --git a/packages/core/src/amazonqFeatureDev/client/featureDev.ts b/packages/core/src/amazonqFeatureDev/client/featureDev.ts index f025ac1743f..74692148e70 100644 --- a/packages/core/src/amazonqFeatureDev/client/featureDev.ts +++ b/packages/core/src/amazonqFeatureDev/client/featureDev.ts @@ -14,12 +14,14 @@ import { featureName, startTaskAssistLimitReachedMessage } from '../constants' import { CodeReference } from '../../amazonq/webview/ui/connector' import { ApiError, + ApiServiceError, CodeIterationLimitError, ContentLengthError, + FeatureDevServiceError, MonthlyConversationLimitError, UnknownApiError, } from '../errors' -import { ToolkitError, isAwsError } from '../../shared/errors' +import { isAwsError } from '../../shared/errors' import { getCodewhispererConfig } from '../../codewhisperer/client/codewhisperer' import { createCodeWhispererChatStreamingClient } from '../../shared/clients/codewhispererChatClient' import { getClientId, getOptOutPreference, getOperatingSystem } from '../../shared/telemetry/util' @@ -93,7 +95,7 @@ export class FeatureDevClient implements FeatureClient { ) { throw new MonthlyConversationLimitError(e.message) } - throw new ApiError(e.message, 'CreateConversation', e.code, e.statusCode ?? 400) + throw ApiError.of(e.message, 'CreateConversation', e.code, e.statusCode ?? 500) } throw new UnknownApiError(e instanceof Error ? e.message : 'Unknown error', 'CreateConversation') @@ -136,7 +138,7 @@ export class FeatureDevClient implements FeatureClient { if (e.code === 'ValidationException' && e.message.includes('Invalid contentLength')) { throw new ContentLengthError() } - throw new ApiError(e.message, 'CreateUploadUrl', e.code, e.statusCode ?? 400) + throw ApiError.of(e.message, 'CreateUploadUrl', e.code, e.statusCode ?? 500) } throw new UnknownApiError(e instanceof Error ? e.message : 'Unknown error', 'CreateUploadUrl') @@ -198,8 +200,10 @@ export class FeatureDevClient implements FeatureClient { ) { throw new CodeIterationLimitError() } + throw ApiError.of(e.message, 'StartTaskAssistCodeGeneration', e.code, e.statusCode ?? 500) } - throw new ToolkitError((e as Error).message, { code: 'StartCodeGenerationFailed' }) + + throw new UnknownApiError(e instanceof Error ? e.message : 'Unknown error', 'StartTaskAssistCodeGeneration') } } @@ -220,7 +224,12 @@ export class FeatureDevClient implements FeatureClient { (e as any).requestId }` ) - throw new ToolkitError((e as Error).message, { code: 'GetCodeGenerationFailed' }) + + if (isAwsError(e)) { + throw ApiError.of(e.message, 'GetTaskAssistCodeGeneration', e.code, e.statusCode ?? 500) + } + + throw new UnknownApiError(e instanceof Error ? e.message : 'Unknown error', 'GetTaskAssistCodeGeneration') } } @@ -235,7 +244,12 @@ export class FeatureDevClient implements FeatureClient { const archiveResponse = await streamingClient.exportResultArchive(params) const buffer: number[] = [] if (archiveResponse.body === undefined) { - throw new ToolkitError('Empty response from CodeWhisperer Streaming service.') + throw new ApiServiceError( + 'Empty response from CodeWhisperer Streaming service.', + 'ExportResultArchive', + 'EmptyResponse', + 500 + ) } for await (const chunk of archiveResponse.body) { if (chunk.internalServerException !== undefined) { @@ -274,7 +288,12 @@ export class FeatureDevClient implements FeatureClient { (e as any).requestId }` ) - throw new ToolkitError((e as Error).message, { code: 'ExportResultArchiveFailed' }) + + if (isAwsError(e)) { + throw ApiError.of(e.message, 'ExportResultArchive', e.code, e.statusCode ?? 500) + } + + throw new FeatureDevServiceError(e instanceof Error ? e.message : 'Unknown error', 'ExportResultArchive') } } diff --git a/packages/core/src/amazonqFeatureDev/controllers/chat/controller.ts b/packages/core/src/amazonqFeatureDev/controllers/chat/controller.ts index f2220221b20..6a05f451f8b 100644 --- a/packages/core/src/amazonqFeatureDev/controllers/chat/controller.ts +++ b/packages/core/src/amazonqFeatureDev/controllers/chat/controller.ts @@ -15,7 +15,7 @@ import { createUserFacingErrorMessage, denyListedErrors, FeatureDevServiceError, - isAPIClientError, + getMetricResult, MonthlyConversationLimitError, NoChangeRequiredException, PrepareRepoFailedError, @@ -550,34 +550,7 @@ export class FeatureDevController { this.messenger.sendUpdatePlaceholder(tabID, i18n('AWS.amazonq.featureDev.pillText.selectOption')) } catch (err: any) { getLogger().error(`${featureName}: Error during code generation: ${err}`) - - let result: string - switch (err.constructor.name) { - case FeatureDevServiceError.name: - if (err.code === 'EmptyPatchException') { - result = MetricDataResult.LlmFailure - } else if (err.code === 'GuardrailsException' || err.code === 'ThrottlingException') { - result = MetricDataResult.Error - } else { - result = MetricDataResult.Fault - } - break - case MonthlyConversationLimitError.name: - case CodeIterationLimitError.name: - case PromptRefusalException.name: - case NoChangeRequiredException.name: - result = MetricDataResult.Error - break - default: - if (isAPIClientError(err)) { - result = MetricDataResult.Error - } else { - result = MetricDataResult.Fault - } - break - } - - await session.sendMetricDataTelemetry(MetricDataOperationName.EndCodeGeneration, result) + await session.sendMetricDataTelemetry(MetricDataOperationName.EndCodeGeneration, getMetricResult(err)) throw err } finally { // Finish processing the event diff --git a/packages/core/src/amazonqFeatureDev/errors.ts b/packages/core/src/amazonqFeatureDev/errors.ts index f64217f94ad..2eb142f765b 100644 --- a/packages/core/src/amazonqFeatureDev/errors.ts +++ b/packages/core/src/amazonqFeatureDev/errors.ts @@ -3,17 +3,19 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { ToolkitError } from '../shared/errors' -import { - featureName, - clientErrorMessages, - startCodeGenClientErrorMessages, - startTaskAssistLimitReachedMessage, -} from './constants' +import { featureName, clientErrorMessages, startTaskAssistLimitReachedMessage } from './constants' import { uploadCodeError } from './userFacingText' import { i18n } from '../shared/i18n-helper' +import { LlmError } from '../amazonq/errors' +import { MetricDataResult } from '../amazonq/commons/types' +import { + ClientError, + ServiceError, + ContentLengthError as CommonContentLengthError, + ToolkitError, +} from '../shared/errors' -export class ConversationIdNotFoundError extends ToolkitError { +export class ConversationIdNotFoundError extends ServiceError { constructor() { super(i18n('AWS.amazonq.featureDev.error.conversationIdNotFoundError'), { code: 'ConversationIdNotFound', @@ -21,7 +23,7 @@ export class ConversationIdNotFoundError extends ToolkitError { } } -export class TabIdNotFoundError extends ToolkitError { +export class TabIdNotFoundError extends ServiceError { constructor() { super(i18n('AWS.amazonq.featureDev.error.tabIdNotFoundError'), { code: 'TabIdNotFound', @@ -29,7 +31,7 @@ export class TabIdNotFoundError extends ToolkitError { } } -export class WorkspaceFolderNotFoundError extends ToolkitError { +export class WorkspaceFolderNotFoundError extends ServiceError { constructor() { super(i18n('AWS.amazonq.featureDev.error.workspaceFolderNotFoundError'), { code: 'WorkspaceFolderNotFound', @@ -37,7 +39,7 @@ export class WorkspaceFolderNotFoundError extends ToolkitError { } } -export class UserMessageNotFoundError extends ToolkitError { +export class UserMessageNotFoundError extends ServiceError { constructor() { super(i18n('AWS.amazonq.featureDev.error.userMessageNotFoundError'), { code: 'MessageNotFound', @@ -45,7 +47,7 @@ export class UserMessageNotFoundError extends ToolkitError { } } -export class SelectedFolderNotInWorkspaceFolderError extends ToolkitError { +export class SelectedFolderNotInWorkspaceFolderError extends ClientError { constructor() { super(i18n('AWS.amazonq.featureDev.error.selectedFolderNotInWorkspaceFolderError'), { code: 'SelectedFolderNotInWorkspaceFolder', @@ -53,7 +55,7 @@ export class SelectedFolderNotInWorkspaceFolderError extends ToolkitError { } } -export class PromptRefusalException extends ToolkitError { +export class PromptRefusalException extends ClientError { constructor() { super(i18n('AWS.amazonq.featureDev.error.promptRefusalException'), { code: 'PromptRefusalException', @@ -61,7 +63,7 @@ export class PromptRefusalException extends ToolkitError { } } -export class NoChangeRequiredException extends ToolkitError { +export class NoChangeRequiredException extends ClientError { constructor() { super(i18n('AWS.amazonq.featureDev.error.noChangeRequiredException'), { code: 'NoChangeRequiredException', @@ -69,13 +71,13 @@ export class NoChangeRequiredException extends ToolkitError { } } -export class FeatureDevServiceError extends ToolkitError { +export class FeatureDevServiceError extends ServiceError { constructor(message: string, code: string) { super(message, { code }) } } -export class PrepareRepoFailedError extends ToolkitError { +export class PrepareRepoFailedError extends ServiceError { constructor() { super(i18n('AWS.amazonq.featureDev.error.prepareRepoFailedError'), { code: 'PrepareRepoFailed', @@ -83,60 +85,81 @@ export class PrepareRepoFailedError extends ToolkitError { } } -export class UploadCodeError extends ToolkitError { +export class UploadCodeError extends ServiceError { constructor(statusCode: string) { super(uploadCodeError, { code: `UploadCode-${statusCode}` }) } } -export class UploadURLExpired extends ToolkitError { +export class UploadURLExpired extends ClientError { constructor() { super(i18n('AWS.amazonq.featureDev.error.uploadURLExpired'), { code: 'UploadURLExpired' }) } } -export class IllegalStateTransition extends ToolkitError { +export class IllegalStateTransition extends ServiceError { constructor() { super(i18n('AWS.amazonq.featureDev.error.illegalStateTransition'), { code: 'IllegalStateTransition' }) } } -export class ContentLengthError extends ToolkitError { +export class IllegalStateError extends ServiceError { + constructor(message: string) { + super(message, { code: 'IllegalStateTransition' }) + } +} + +export class ContentLengthError extends CommonContentLengthError { constructor() { super(i18n('AWS.amazonq.featureDev.error.contentLengthError'), { code: ContentLengthError.name }) } } -export class ZipFileError extends ToolkitError { +export class ZipFileError extends ServiceError { constructor() { super(i18n('AWS.amazonq.featureDev.error.zipFileError'), { code: ZipFileError.name }) } } -export class CodeIterationLimitError extends ToolkitError { +export class CodeIterationLimitError extends ClientError { constructor() { super(i18n('AWS.amazonq.featureDev.error.codeIterationLimitError'), { code: CodeIterationLimitError.name }) } } -export class MonthlyConversationLimitError extends ToolkitError { +export class MonthlyConversationLimitError extends ClientError { constructor(message: string) { super(message, { code: MonthlyConversationLimitError.name }) } } -export class UnknownApiError extends ToolkitError { +export class UnknownApiError extends ServiceError { constructor(message: string, api: string) { super(message, { code: `${api}-Unknown` }) } } -export class ApiError extends ToolkitError { +export class ApiClientError extends ClientError { + constructor(message: string, api: string, errorName: string, errorCode: number) { + super(message, { code: `${api}-${errorName}-${errorCode}` }) + } +} + +export class ApiServiceError extends ServiceError { constructor(message: string, api: string, errorName: string, errorCode: number) { super(message, { code: `${api}-${errorName}-${errorCode}` }) } } +export class ApiError { + static of(message: string, api: string, errorName: string, errorCode: number) { + if (errorCode >= 400 && errorCode < 500) { + return new ApiClientError(message, api, errorName, errorCode) + } + return new ApiServiceError(message, api, errorName, errorCode) + } +} + export const denyListedErrors: string[] = ['Deserialization error', 'Inaccessible host'] export function createUserFacingErrorMessage(message: string) { @@ -146,11 +169,23 @@ export function createUserFacingErrorMessage(message: string) { return message } -export function isAPIClientError(error: { code?: string; message: string }): boolean { +function isAPIClientError(error: { code?: string; message: string }): boolean { return ( - (error.code === 'StartCodeGenerationFailed' && - startCodeGenClientErrorMessages.some((msg: string) => error.message.includes(msg))) || clientErrorMessages.some((msg: string) => error.message.includes(msg)) || error.message.includes(startTaskAssistLimitReachedMessage) ) } + +export function getMetricResult(error: ToolkitError): MetricDataResult { + if (error instanceof ClientError || isAPIClientError(error)) { + return MetricDataResult.Error + } + if (error instanceof ServiceError) { + return MetricDataResult.Fault + } + if (error instanceof LlmError) { + return MetricDataResult.LlmFailure + } + + return MetricDataResult.Fault +} diff --git a/packages/core/src/amazonqFeatureDev/session/session.ts b/packages/core/src/amazonqFeatureDev/session/session.ts index 6d692c297a4..d2b174f0f6f 100644 --- a/packages/core/src/amazonqFeatureDev/session/session.ts +++ b/packages/core/src/amazonqFeatureDev/session/session.ts @@ -14,7 +14,7 @@ import { type SessionStateConfig, UpdateFilesPathsParams, } from '../../amazonq/commons/types' -import { ContentLengthError, ConversationIdNotFoundError } from '../errors' +import { ContentLengthError, ConversationIdNotFoundError, IllegalStateError } from '../errors' import { featureDevChat, referenceLogText, featureDevScheme } from '../constants' import fs from '../../shared/fs/fs' import { FeatureDevClient } from '../client/featureDev' @@ -33,7 +33,7 @@ import { UpdateAnswerMessage } from '../../amazonq/commons/connector/connectorMe import { FollowUpTypes } from '../../amazonq/commons/types' import { SessionConfig } from '../../amazonq/commons/session/sessionConfigFactory' import { Messenger } from '../../amazonq/commons/connector/baseMessenger' -import { ContentLengthError as CommonAmazonQContentLengthError } from '../../amazonq/errors' +import { ContentLengthError as CommonContentLengthError } from '../../shared/errors' export class Session { private _state?: SessionState | Omit private task: string = '' @@ -159,7 +159,7 @@ export class Session { return resp.interaction } catch (e) { - if (e instanceof CommonAmazonQContentLengthError) { + if (e instanceof CommonContentLengthError) { getLogger().debug(`Content length validation failed: ${e.message}`) throw new ContentLengthError() } @@ -353,7 +353,7 @@ export class Session { get state() { if (!this._state) { - throw new Error("State should be initialized before it's read") + throw new IllegalStateError("State should be initialized before it's read") } return this._state } @@ -364,7 +364,7 @@ export class Session { get uploadId() { if (!('uploadId' in this.state)) { - throw new Error("UploadId has to be initialized before it's read") + throw new IllegalStateError("UploadId has to be initialized before it's read") } return this.state.uploadId } diff --git a/packages/core/src/amazonqFeatureDev/session/sessionState.ts b/packages/core/src/amazonqFeatureDev/session/sessionState.ts index 62f71dbaeec..5890539409f 100644 --- a/packages/core/src/amazonqFeatureDev/session/sessionState.ts +++ b/packages/core/src/amazonqFeatureDev/session/sessionState.ts @@ -6,11 +6,11 @@ import { MynahIcons } from '@aws/mynah-ui' import * as path from 'path' import * as vscode from 'vscode' -import { ToolkitError } from '../../shared/errors' import { getLogger } from '../../shared/logger/logger' import { featureDevScheme } from '../constants' import { - FeatureDevServiceError, + ApiClientError, + ApiServiceError, IllegalStateTransition, NoChangeRequiredException, PromptRefusalException, @@ -37,6 +37,7 @@ import { BasePrepareCodeGenState, CreateNextStateParams, } from '../../amazonq/session/sessionState' +import { LlmError } from '../../amazonq/errors' export class ConversationNotStartedState implements Omit { public tokenSource: vscode.CancellationTokenSource @@ -178,9 +179,11 @@ export class FeatureDevCodeGenState extends BaseCodeGenState { protected handleError(messenger: BaseMessenger, codegenResult: any): Error { switch (true) { case codegenResult.codeGenerationStatusDetail?.includes('Guardrails'): { - return new FeatureDevServiceError( + return new ApiClientError( i18n('AWS.amazonq.featureDev.error.codeGen.default'), - 'GuardrailsException' + 'GetTaskAssistCodeGeneration', + 'GuardrailsException', + 400 ) } case codegenResult.codeGenerationStatusDetail?.includes('PromptRefusal'): { @@ -190,21 +193,25 @@ export class FeatureDevCodeGenState extends BaseCodeGenState { if (codegenResult.codeGenerationStatusDetail?.includes('NO_CHANGE_REQUIRED')) { return new NoChangeRequiredException() } - return new FeatureDevServiceError( - i18n('AWS.amazonq.featureDev.error.codeGen.default'), - 'EmptyPatchException' - ) + return new LlmError(i18n('AWS.amazonq.featureDev.error.codeGen.default'), { + code: 'EmptyPatchException', + }) } case codegenResult.codeGenerationStatusDetail?.includes('Throttling'): { - return new FeatureDevServiceError( + return new ApiClientError( i18n('AWS.amazonq.featureDev.error.throttling'), - 'ThrottlingException' + 'GetTaskAssistCodeGeneration', + 'ThrottlingException', + 429 ) } default: { - return new ToolkitError(i18n('AWS.amazonq.featureDev.error.codeGen.default'), { - code: 'CodeGenFailed', - }) + return new ApiServiceError( + i18n('AWS.amazonq.featureDev.error.codeGen.default'), + 'GetTaskAssistCodeGeneration', + 'UnknownException', + 500 + ) } } } diff --git a/packages/core/src/awsService/apprunner/commands/createServiceFromEcr.ts b/packages/core/src/awsService/apprunner/commands/createServiceFromEcr.ts index 52e847723c5..dfd2c3df099 100644 --- a/packages/core/src/awsService/apprunner/commands/createServiceFromEcr.ts +++ b/packages/core/src/awsService/apprunner/commands/createServiceFromEcr.ts @@ -8,13 +8,13 @@ import { EcrRepositoryNode } from '../../../awsService/ecr/explorer/ecrRepositor import { EcrTagNode } from '../../../awsService/ecr/explorer/ecrTagNode' import { CreateAppRunnerServiceWizard } from '../wizards/apprunnerCreateServiceWizard' -import { DefaultAppRunnerClient } from '../../../shared/clients/apprunnerClient' +import { AppRunnerClient } from '../../../shared/clients/apprunner' import { telemetry } from '../../../shared/telemetry/telemetry' import { Result } from '../../../shared/telemetry/telemetry' export async function createFromEcr( node: EcrTagNode | EcrRepositoryNode, - client = new DefaultAppRunnerClient(node.regionCode) + client = new AppRunnerClient(node.regionCode) ): Promise { let telemetryResult: Result = 'Failed' diff --git a/packages/core/src/awsService/apprunner/explorer/apprunnerNode.ts b/packages/core/src/awsService/apprunner/explorer/apprunnerNode.ts index 4eb3c4bcf5b..6e8bc496472 100644 --- a/packages/core/src/awsService/apprunner/explorer/apprunnerNode.ts +++ b/packages/core/src/awsService/apprunner/explorer/apprunnerNode.ts @@ -8,15 +8,13 @@ import { AWSTreeNodeBase } from '../../../shared/treeview/nodes/awsTreeNodeBase' import { AppRunnerServiceNode } from './apprunnerServiceNode' import { PlaceholderNode } from '../../../shared/treeview/nodes/placeholderNode' import * as nls from 'vscode-nls' -import { AppRunnerClient } from '../../../shared/clients/apprunnerClient' -import { getPaginatedAwsCallIter } from '../../../shared/utilities/collectionUtils' -import { AppRunner } from 'aws-sdk' +import { AppRunnerClient, CreateServiceRequest, ServiceSummary } from '../../../shared/clients/apprunner' import { PollingSet } from '../../../shared/utilities/pollingSet' const localize = nls.loadMessageBundle() export class AppRunnerNode extends AWSTreeNodeBase { - private readonly serviceNodes: Map = new Map() + private readonly serviceNodes: Map = new Map() private readonly pollingSet: PollingSet = new PollingSet(20000, this.refresh.bind(this)) public constructor( @@ -43,30 +41,10 @@ export class AppRunnerNode extends AWSTreeNodeBase { }) } - private async getServiceSummaries(request: AppRunner.ListServicesRequest = {}): Promise { - const iterator = getPaginatedAwsCallIter({ - awsCall: async (request) => await this.client.listServices(request), - nextTokenNames: { - request: 'NextToken', - response: 'NextToken', - }, - request, - }) - - const services: AppRunner.Service[] = [] - - while (true) { - const next = await iterator.next() - - // eslint-disable-next-line unicorn/no-array-for-each - next.value.ServiceSummaryList.forEach((summary: AppRunner.Service) => services.push(summary)) - - if (next.done) { - break - } - } - - return services + private async getServiceSummaries(): Promise { + // TODO: avoid resolving all services at once. + const serviceCollection = this.client.paginateServices({}) + return await serviceCollection.flatten().promise() } public async updateChildren(): Promise { @@ -107,7 +85,7 @@ export class AppRunnerNode extends AWSTreeNodeBase { this.pollingSet.delete(id) } - public async createService(request: AppRunner.CreateServiceRequest): Promise { + public async createService(request: CreateServiceRequest): Promise { await this.client.createService(request) this.refresh() } diff --git a/packages/core/src/awsService/apprunner/explorer/apprunnerServiceNode.ts b/packages/core/src/awsService/apprunner/explorer/apprunnerServiceNode.ts index 66d578ca0ee..7a50f6f53f4 100644 --- a/packages/core/src/awsService/apprunner/explorer/apprunnerServiceNode.ts +++ b/packages/core/src/awsService/apprunner/explorer/apprunnerServiceNode.ts @@ -4,8 +4,7 @@ */ import AsyncLock from 'async-lock' -import { AppRunnerClient } from '../../../shared/clients/apprunnerClient' -import { AppRunner } from 'aws-sdk' +import { AppRunnerClient, ServiceSummary } from '../../../shared/clients/apprunner' import { AppRunnerNode } from './apprunnerNode' import { toArrayAsync, toMap } from '../../../shared/utilities/collectionUtils' @@ -15,6 +14,7 @@ import { AWSResourceNode } from '../../../shared/treeview/nodes/awsResourceNode' import * as nls from 'vscode-nls' import { getLogger } from '../../../shared/logger/logger' import { getIcon } from '../../../shared/icons' +import * as AppRunner from '@aws-sdk/client-apprunner' import { CloudWatchLogsClient } from '../../../shared/clients/cloudWatchLogs' import { LogGroup } from '@aws-sdk/client-cloudwatch-logs' const localize = nls.loadMessageBundle() @@ -41,7 +41,7 @@ export class AppRunnerServiceNode extends CloudWatchLogsBase implements AWSResou constructor( public readonly parent: AppRunnerNode, private readonly client: AppRunnerClient, - private _info: AppRunner.Service, + private _info: ServiceSummary, private currentOperation: AppRunner.OperationSummary & { Type?: ServiceOperation } = {}, cloudwatchClient = new CloudWatchLogsClient(client.regionCode) ) { @@ -55,7 +55,7 @@ export class AppRunnerServiceNode extends CloudWatchLogsBase implements AWSResou this.update(_info) } - public get info(): Readonly { + public get info(): Readonly { return this._info } @@ -81,7 +81,7 @@ export class AppRunnerServiceNode extends CloudWatchLogsBase implements AWSResou this.label = `${this._info.ServiceName} [${displayStatus}]` } - public update(info: AppRunner.ServiceSummary | AppRunner.Service): void { + public update(info: ServiceSummary): void { // update can be called multiple times during an event loop // this would rarely cause the node's status to appear as 'Operation in progress' this.lock @@ -135,7 +135,7 @@ export class AppRunnerServiceNode extends CloudWatchLogsBase implements AWSResou }) } - private updateInfo(info: AppRunner.ServiceSummary | AppRunner.Service): void { + private updateInfo(info: ServiceSummary): void { if (info.Status === 'OPERATION_IN_PROGRESS' && this.currentOperation.Type === undefined) { // Asynchronous since it is not currently possible for race-conditions to occur with updating operations void this.updateOperation() @@ -171,13 +171,14 @@ export class AppRunnerServiceNode extends CloudWatchLogsBase implements AWSResou this.setOperation(this._info, resp.OperationId, 'START_DEPLOYMENT') } - public setOperation(info: AppRunner.Service, id?: string, type?: ServiceOperation): void { + // eslint-disable-next-line @typescript-eslint/no-duplicate-type-constituents + public setOperation(info: ServiceSummary, id?: string, type?: ServiceOperation): void { this.currentOperation.Id = id this.currentOperation.Type = type this.update(info) } - public async describe(): Promise { + public async describe(): Promise { const resp = await this.client.describeService({ ServiceArn: this.arn }) this.update(resp.Service) return this._info diff --git a/packages/core/src/awsService/apprunner/wizards/apprunnerCreateServiceWizard.ts b/packages/core/src/awsService/apprunner/wizards/apprunnerCreateServiceWizard.ts index 3f29d9b39cc..913fdf93bec 100644 --- a/packages/core/src/awsService/apprunner/wizards/apprunnerCreateServiceWizard.ts +++ b/packages/core/src/awsService/apprunner/wizards/apprunnerCreateServiceWizard.ts @@ -3,7 +3,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { AppRunner } from 'aws-sdk' import * as nls from 'vscode-nls' import { createCommonButtons, QuickInputToggleButton } from '../../../shared/ui/buttons' import * as input from '../../../shared/ui/inputPrompter' @@ -17,8 +16,9 @@ import { makeDeploymentButton } from './deploymentButton' import { createExitPrompter } from '../../../shared/ui/common/exitPrompter' import { IamClient } from '../../../shared/clients/iam' import { DefaultEcrClient } from '../../../shared/clients/ecrClient' -import { DefaultAppRunnerClient } from '../../../shared/clients/apprunnerClient' +import { AppRunnerClient, CreateServiceRequest, SourceConfiguration } from '../../../shared/clients/apprunner' import { getAppRunnerCreateServiceDocUrl } from '../../../shared/extensionUtilities' +import * as AppRunner from '@aws-sdk/client-apprunner' const localize = nls.loadMessageBundle() @@ -74,10 +74,10 @@ function createInstanceStep(): Prompter { function createSourcePrompter( autoDeployButton: QuickInputToggleButton -): Prompter { +): Prompter { const ecrPath = { label: 'ECR', - data: { ImageRepository: {} } as AppRunner.SourceConfiguration, + data: { ImageRepository: {} } as SourceConfiguration, detail: localize( 'AWS.apprunner.createService.ecr.detail', 'Create a service from a public or private Elastic Container Registry repository' @@ -86,7 +86,7 @@ function createSourcePrompter( const repositoryPath = { label: 'Repository', - data: { CodeRepository: {} } as AppRunner.SourceConfiguration, + data: { CodeRepository: {} } as SourceConfiguration, detail: localize('AWS.apprunner.createService.repository.detail', 'Create a service from a GitHub repository'), } @@ -96,15 +96,15 @@ function createSourcePrompter( }) } -export class CreateAppRunnerServiceWizard extends Wizard { +export class CreateAppRunnerServiceWizard extends Wizard { public constructor( region: string, - initState: WizardState = {}, - implicitState: WizardState = {}, + initState: WizardState = {}, + implicitState: WizardState = {}, clients = { iam: new IamClient(region), ecr: new DefaultEcrClient(region), - apprunner: new DefaultAppRunnerClient(region), + apprunner: new AppRunnerClient(region), } ) { super({ diff --git a/packages/core/src/awsService/apprunner/wizards/codeRepositoryWizard.ts b/packages/core/src/awsService/apprunner/wizards/codeRepositoryWizard.ts index ef0fbf08b7c..04896648652 100644 --- a/packages/core/src/awsService/apprunner/wizards/codeRepositoryWizard.ts +++ b/packages/core/src/awsService/apprunner/wizards/codeRepositoryWizard.ts @@ -3,7 +3,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { AppRunner } from 'aws-sdk' import * as nls from 'vscode-nls' import { createCommonButtons, createRefreshButton, QuickInputToggleButton } from '../../../shared/ui/buttons' import { Remote } from '../../../../types/git.d' @@ -11,14 +10,25 @@ import { GitExtension } from '../../../shared/extensions/git' import * as vscode from 'vscode' import { WizardForm } from '../../../shared/wizards/wizardForm' import { createVariablesPrompter } from '../../../shared/ui/common/variablesPrompter' -import { AppRunnerClient } from '../../../shared/clients/apprunnerClient' +import { + AppRunnerClient, + SourceConfiguration, + CodeRepository, + CodeConfigurationValues, +} from '../../../shared/clients/apprunner' import { makeDeploymentButton } from './deploymentButton' -import { createLabelQuickPick, createQuickPick, QuickPickPrompter } from '../../../shared/ui/pickerPrompter' +import { + createLabelQuickPick, + createQuickPick, + DataQuickPickItem, + QuickPickPrompter, +} from '../../../shared/ui/pickerPrompter' import { createInputBox, InputBoxPrompter } from '../../../shared/ui/inputPrompter' -import { apprunnerConnectionHelpUrl, apprunnerConfigHelpUrl, apprunnerRuntimeHelpUrl } from '../../../shared/constants' +import { apprunnerConfigHelpUrl, apprunnerConnectionHelpUrl, apprunnerRuntimeHelpUrl } from '../../../shared/constants' import { Wizard, WIZARD_BACK } from '../../../shared/wizards/wizard' import { openUrl } from '../../../shared/utilities/vsCodeUtils' import { getAppRunnerCreateServiceDocUrl } from '../../../shared/extensionUtilities' +import * as AppRunner from '@aws-sdk/client-apprunner' const localize = nls.loadMessageBundle() @@ -82,9 +92,9 @@ function createBranchPrompter( } function createRuntimePrompter(): QuickPickPrompter { - const items = [ - { label: 'python3', data: 'PYTHON_3' }, - { label: 'nodejs12', data: 'NODEJS_16' }, + const items: DataQuickPickItem[] = [ + { label: 'python3', data: AppRunner.Runtime.PYTHON_3 }, + { label: 'nodejs16', data: AppRunner.Runtime.NODEJS_16 }, ] return createQuickPick(items, { @@ -158,10 +168,12 @@ export function createConnectionPrompter(client: AppRunnerClient) { const getItems = async () => { const resp = await client.listConnections() - return resp.ConnectionSummaryList.filter((conn) => conn.Status === 'AVAILABLE').map((conn) => ({ - label: conn.ConnectionName!, - data: conn, - })) + return resp + .filter((conn) => conn.Status === 'AVAILABLE') + .map((conn) => ({ + label: conn.ConnectionName!, + data: conn, + })) } const refreshButton = createRefreshButton() @@ -184,21 +196,24 @@ function createSourcePrompter(): QuickPickPrompter = { + label: apiLabel, + data: AppRunner.ConfigurationSource.API, + } + const repoItem: DataQuickPickItem = { + label: repoLabel, + data: AppRunner.ConfigurationSource.REPOSITORY, + detail: configDetail, + } - return createQuickPick( - [ - { label: apiLabel, data: 'API' }, - { label: repoLabel, data: 'REPOSITORY', detail: configDetail }, - ], - { - title: localize('AWS.apprunner.createService.configSource.title', 'Choose configuration source'), - buttons: createCommonButtons(apprunnerConfigHelpUrl), - } - ) + return createQuickPick([apiItem, repoItem], { + title: localize('AWS.apprunner.createService.configSource.title', 'Choose configuration source'), + buttons: createCommonButtons(apprunnerConfigHelpUrl), + }) } -function createCodeRepositorySubForm(git: GitExtension): WizardForm { - const subform = new WizardForm() +function createCodeRepositorySubForm(git: GitExtension): WizardForm { + const subform = new WizardForm() const form = subform.body form.RepositoryUrl.bindPrompter(() => createRepoPrompter(git).transform((r) => r.fetchUrl!)) @@ -210,7 +225,7 @@ function createCodeRepositorySubForm(git: GitExtension): WizardForm 'BRANCH') - const codeConfigForm = new WizardForm() + const codeConfigForm = new WizardForm() codeConfigForm.body.Runtime.bindPrompter(createRuntimePrompter) codeConfigForm.body.BuildCommand.bindPrompter((state) => createBuildCommandPrompter(state.Runtime!)) codeConfigForm.body.StartCommand.bindPrompter((state) => createStartCommandPrompter(state.Runtime!)) @@ -227,7 +242,7 @@ function createCodeRepositorySubForm(git: GitExtension): WizardForm { +export class AppRunnerCodeRepositoryWizard extends Wizard { constructor( client: AppRunnerClient, git: GitExtension, diff --git a/packages/core/src/awsService/apprunner/wizards/imageRepositoryWizard.ts b/packages/core/src/awsService/apprunner/wizards/imageRepositoryWizard.ts index c3efdf6b2ff..e906e249e71 100644 --- a/packages/core/src/awsService/apprunner/wizards/imageRepositoryWizard.ts +++ b/packages/core/src/awsService/apprunner/wizards/imageRepositoryWizard.ts @@ -3,7 +3,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { AppRunner } from 'aws-sdk' import { createCommonButtons, QuickInputButton, QuickInputToggleButton } from '../../../shared/ui/buttons' import { toArrayAsync } from '../../../shared/utilities/collectionUtils' import { EcrClient, EcrRepository } from '../../../shared/clients/ecrClient' @@ -22,6 +21,7 @@ import { createRolePrompter } from '../../../shared/ui/common/roles' import { getLogger } from '../../../shared/logger/logger' import { getAppRunnerCreateServiceDocUrl, isCloud9 } from '../../../shared/extensionUtilities' import { createExitPrompter } from '../../../shared/ui/common/exitPrompter' +import { ImageRepository, SourceConfiguration } from '../../../shared/clients/apprunner' const localize = nls.loadMessageBundle() @@ -223,8 +223,8 @@ export class ImageIdentifierForm extends WizardForm<{ repo: TaggedEcrRepository function createImageRepositorySubForm( ecrClient: EcrClient, autoDeployButton: QuickInputToggleButton -): WizardForm { - const subform = new WizardForm() +): WizardForm { + const subform = new WizardForm() const form = subform.body // note: this is intentionally initialized only once to preserve caches @@ -253,7 +253,7 @@ function createImageRepositorySubForm( return subform } -export class AppRunnerImageRepositoryWizard extends Wizard { +export class AppRunnerImageRepositoryWizard extends Wizard { constructor(ecrClient: EcrClient, iamClient: IamClient, autoDeployButton = makeDeploymentButton()) { super() const form = this.form diff --git a/packages/core/src/awsexplorer/regionNode.ts b/packages/core/src/awsexplorer/regionNode.ts index 62104d9b352..10e8d975fe8 100644 --- a/packages/core/src/awsexplorer/regionNode.ts +++ b/packages/core/src/awsexplorer/regionNode.ts @@ -22,7 +22,7 @@ import { ResourcesNode } from '../dynamicResources/explorer/nodes/resourcesNode' import { AppRunnerNode } from '../awsService/apprunner/explorer/apprunnerNode' import { DocumentDBNode } from '../docdb/explorer/docdbNode' import { DefaultDocumentDBClient } from '../shared/clients/docdbClient' -import { DefaultAppRunnerClient } from '../shared/clients/apprunnerClient' +import { AppRunnerClient } from '../shared/clients/apprunner' import { DefaultEcrClient } from '../shared/clients/ecrClient' import { DefaultRedshiftClient } from '../shared/clients/redshiftClient' import { DefaultIotClient } from '../shared/clients/iotClient' @@ -53,7 +53,7 @@ const serviceCandidates: ServiceNode[] = [ }, { serviceId: 'apprunner', - createFn: (regionCode: string) => new AppRunnerNode(regionCode, new DefaultAppRunnerClient(regionCode)), + createFn: (regionCode: string) => new AppRunnerNode(regionCode, new AppRunnerClient(regionCode)), }, { serviceId: 'cloudformation', diff --git a/packages/core/src/codewhisperer/client/user-service-2.json b/packages/core/src/codewhisperer/client/user-service-2.json index ed7661bec4c..833245ef183 100644 --- a/packages/core/src/codewhisperer/client/user-service-2.json +++ b/packages/core/src/codewhisperer/client/user-service-2.json @@ -2206,7 +2206,8 @@ "uploadId": { "shape": "UploadId" }, "description": { "shape": "StartCodeFixJobRequestDescriptionString" }, "ruleId": { "shape": "StartCodeFixJobRequestRuleIdString" }, - "codeFixName": { "shape": "CodeFixName" } + "codeFixName": { "shape": "CodeFixName" }, + "referenceTrackerConfiguration": { "shape": "ReferenceTrackerConfiguration" } } }, "StartCodeFixJobRequestDescriptionString": { diff --git a/packages/core/src/codewhisperer/commands/startCodeFixGeneration.ts b/packages/core/src/codewhisperer/commands/startCodeFixGeneration.ts index a255864c7eb..8e9a5240812 100644 --- a/packages/core/src/codewhisperer/commands/startCodeFixGeneration.ts +++ b/packages/core/src/codewhisperer/commands/startCodeFixGeneration.ts @@ -18,6 +18,7 @@ import AdmZip from 'adm-zip' import path from 'path' import { TelemetryHelper } from '../util/telemetryHelper' import { tempDirPath } from '../../shared/filesystemUtilities' +import { CodeWhispererSettings } from '../util/codewhispererSettings' export async function startCodeFixGeneration( client: DefaultCodeWhispererClient, @@ -69,6 +70,11 @@ export async function startCodeFixGeneration( end: { line: issue.endLine, character: 0 }, }, issue.recommendation.text, + { + recommendationsWithReferences: CodeWhispererSettings.instance.isSuggestionsWithCodeReferencesEnabled() + ? 'ALLOW' + : 'BLOCK', + }, codeFixName, issue.ruleId ) diff --git a/packages/core/src/codewhisperer/models/constants.ts b/packages/core/src/codewhisperer/models/constants.ts index 74b4e6d508e..5762f8609da 100644 --- a/packages/core/src/codewhisperer/models/constants.ts +++ b/packages/core/src/codewhisperer/models/constants.ts @@ -856,6 +856,8 @@ export const crossFileContextConfig = { topK: 3, numberOfLinesEachChunk: 50, maximumTotalLength: 20480, + maxLengthEachChunk: 10240, + maxContextCount: 5, } export const utgConfig = { diff --git a/packages/core/src/codewhisperer/service/codeFixHandler.ts b/packages/core/src/codewhisperer/service/codeFixHandler.ts index 854cb848a52..4aa74a91ac7 100644 --- a/packages/core/src/codewhisperer/service/codeFixHandler.ts +++ b/packages/core/src/codewhisperer/service/codeFixHandler.ts @@ -50,6 +50,7 @@ export async function createCodeFixJob( uploadId: string, snippetRange: CodeWhispererUserClient.Range, description: string, + referenceTrackerConfiguration: CodeWhispererUserClient.ReferenceTrackerConfiguration, codeFixName?: string, ruleId?: string ) { @@ -60,6 +61,7 @@ export async function createCodeFixJob( codeFixName, ruleId, description, + referenceTrackerConfiguration, } const resp = await client.startCodeFixJob(req).catch((err) => { diff --git a/packages/core/src/codewhisperer/util/supplementalContext/supplementalContextUtil.ts b/packages/core/src/codewhisperer/util/supplementalContext/supplementalContextUtil.ts index 03f9d59b3f2..bd214ace44e 100644 --- a/packages/core/src/codewhisperer/util/supplementalContext/supplementalContextUtil.ts +++ b/packages/core/src/codewhisperer/util/supplementalContext/supplementalContextUtil.ts @@ -11,6 +11,8 @@ import { CancellationError } from '../../../shared/utilities/timeoutUtils' import { ToolkitError } from '../../../shared/errors' import { getLogger } from '../../../shared/logger/logger' import { CodeWhispererSupplementalContext } from '../../models/model' +import * as os from 'os' +import { crossFileContextConfig } from '../../models/constants' export async function fetchSupplementalContext( editor: vscode.TextEditor, @@ -36,7 +38,7 @@ export async function fetchSupplementalContext( return supplementalContextPromise .then((value) => { if (value) { - return { + const resBeforeTruncation = { isUtg: isUtg, isProcessTimeout: false, supplementalContextItems: value.supplementalContextItems.filter( @@ -46,6 +48,8 @@ export async function fetchSupplementalContext( latency: performance.now() - timesBeforeFetching, strategy: value.strategy, } + + return truncateSuppelementalContext(resBeforeTruncation) } else { return undefined } @@ -68,3 +72,66 @@ export async function fetchSupplementalContext( } }) } + +/** + * Requirement + * - Maximum 5 supplemental context. + * - Each chunk can't exceed 10240 characters + * - Sum of all chunks can't exceed 20480 characters + */ +export function truncateSuppelementalContext( + context: CodeWhispererSupplementalContext +): CodeWhispererSupplementalContext { + let c = context.supplementalContextItems.map((item) => { + if (item.content.length > crossFileContextConfig.maxLengthEachChunk) { + return { + ...item, + content: truncateLineByLine(item.content, crossFileContextConfig.maxLengthEachChunk), + } + } else { + return item + } + }) + + if (c.length > crossFileContextConfig.maxContextCount) { + c = c.slice(0, crossFileContextConfig.maxContextCount) + } + + let curTotalLength = c.reduce((acc, cur) => { + return acc + cur.content.length + }, 0) + while (curTotalLength >= 20480 && c.length - 1 >= 0) { + const last = c[c.length - 1] + c = c.slice(0, -1) + curTotalLength -= last.content.length + } + + return { + ...context, + supplementalContextItems: c, + contentsLength: curTotalLength, + } +} + +export function truncateLineByLine(input: string, l: number): string { + const maxLength = l > 0 ? l : -1 * l + if (input.length === 0) { + return '' + } + + const shouldAddNewLineBack = input.endsWith(os.EOL) + let lines = input.trim().split(os.EOL) + let curLen = input.length + while (curLen > maxLength && lines.length - 1 >= 0) { + const last = lines[lines.length - 1] + lines = lines.slice(0, -1) + curLen -= last.length + 1 + } + + const r = lines.join(os.EOL) + if (shouldAddNewLineBack) { + return r + os.EOL + } else { + return r + } +} diff --git a/packages/core/src/codewhisperer/util/zipUtil.ts b/packages/core/src/codewhisperer/util/zipUtil.ts index 47ed91909bf..00ee0ae053d 100644 --- a/packages/core/src/codewhisperer/util/zipUtil.ts +++ b/packages/core/src/codewhisperer/util/zipUtil.ts @@ -420,7 +420,7 @@ export class ZipUtil { ) : vscode.workspace.workspaceFolders) as CurrentWsFolders, { - maxSizeBytes: this.getProjectScanPayloadSizeLimitInBytes(), + maxTotalSizeBytes: this.getProjectScanPayloadSizeLimitInBytes(), excludePatterns: useCase === FeatureUseCase.TEST_GENERATION ? [...CodeWhispererConstants.testGenExcludePatterns, ...defaultExcludePatterns] diff --git a/packages/core/src/codewhispererChat/controllers/chat/controller.ts b/packages/core/src/codewhispererChat/controllers/chat/controller.ts index e1a41d69a23..846f3c6e445 100644 --- a/packages/core/src/codewhispererChat/controllers/chat/controller.ts +++ b/packages/core/src/codewhispererChat/controllers/chat/controller.ts @@ -980,9 +980,15 @@ export class ChatController { if (Array.isArray(prompts) && prompts.length > 0) { triggerPayload.additionalContextLengths = this.telemetryHelper.getContextLengths(prompts) for (const prompt of prompts.slice(0, 20)) { + // Add system prompt for user prompts and workspace rules + const contextType = this.telemetryHelper.getContextType(prompt) + const description = + contextType === 'rule' || contextType === 'prompt' + ? `You must follow the instructions in ${prompt.relativePath}. Below are lines ${prompt.startLine}-${prompt.endLine} of this file:\n` + : prompt.description const entry = { name: prompt.name.substring(0, aditionalContentNameLimit), - description: prompt.description.substring(0, aditionalContentNameLimit), + description: description.substring(0, aditionalContentNameLimit), innerContext: prompt.content.substring(0, additionalContentInnerContextLimit), } // make sure the relevantDocument + additionalContext @@ -994,7 +1000,6 @@ export class ChatController { break } - const contextType = this.telemetryHelper.getContextType(prompt) if (contextType === 'rule') { triggerPayload.truncatedAdditionalContextLengths.ruleContextLength += entry.innerContext.length } else if (contextType === 'prompt') { diff --git a/packages/core/src/codewhispererChat/controllers/chat/telemetryHelper.ts b/packages/core/src/codewhispererChat/controllers/chat/telemetryHelper.ts index 8c63eb44972..eb99b8c5dca 100644 --- a/packages/core/src/codewhispererChat/controllers/chat/telemetryHelper.ts +++ b/packages/core/src/codewhispererChat/controllers/chat/telemetryHelper.ts @@ -42,7 +42,8 @@ import { AuthUtil } from '../../../codewhisperer/util/authUtil' import { getSelectedCustomization } from '../../../codewhisperer/util/customizationUtil' import { undefinedIfEmpty } from '../../../shared/utilities/textUtilities' import { AdditionalContextPrompt } from '../../../amazonq/lsp/types' -import { getUserPromptsDirectory } from '../../constants' +import { getUserPromptsDirectory, promptFileExtension } from '../../constants' +import { isInDirectory } from '../../../shared/filesystemUtilities' export function logSendTelemetryEventFailure(error: any) { let requestId: string | undefined @@ -148,13 +149,14 @@ export class CWCTelemetryHelper { } public getContextType(prompt: AdditionalContextPrompt): string { - if (prompt.relativePath.startsWith(path.join('.amazonq', 'rules'))) { - return 'rule' - } else if (prompt.filePath.startsWith(getUserPromptsDirectory())) { - return 'prompt' - } else { - return 'file' + if (prompt.filePath.endsWith(promptFileExtension)) { + if (isInDirectory(path.join('.amazonq', 'rules'), prompt.relativePath)) { + return 'rule' + } else if (isInDirectory(getUserPromptsDirectory(), prompt.filePath)) { + return 'prompt' + } } + return 'file' } public getContextLengths(prompts: AdditionalContextPrompt[]): AdditionalContextLengths { diff --git a/packages/core/src/login/webview/commonAuthViewProvider.ts b/packages/core/src/login/webview/commonAuthViewProvider.ts index 12caf3c2ad5..d9d6f3b4e30 100644 --- a/packages/core/src/login/webview/commonAuthViewProvider.ts +++ b/packages/core/src/login/webview/commonAuthViewProvider.ts @@ -135,9 +135,10 @@ export class CommonAuthViewProvider implements WebviewViewProvider { enableCommandUris: true, localResourceRoots: [dist, resources], } - webviewView.webview.html = this._getHtmlForWebview(this.extensionContext.extensionUri, webviewView.webview) // register the webview server await this.webView?.setup(webviewView.webview) + + webviewView.webview.html = this._getHtmlForWebview(this.extensionContext.extensionUri, webviewView.webview) } private _getHtmlForWebview(extensionURI: Uri, webview: vscode.Webview) { diff --git a/packages/core/src/login/webview/vue/amazonq/backend_amazonq.ts b/packages/core/src/login/webview/vue/amazonq/backend_amazonq.ts index 83c511ad9f6..7132e91afec 100644 --- a/packages/core/src/login/webview/vue/amazonq/backend_amazonq.ts +++ b/packages/core/src/login/webview/vue/amazonq/backend_amazonq.ts @@ -27,6 +27,7 @@ const className = 'AmazonQLoginWebview' export class AmazonQLoginWebview extends CommonAuthWebview { public override id: string = 'aws.amazonq.AmazonCommonAuth' public static sourcePath: string = 'vue/src/login/webview/vue/amazonq/index.js' + public override supportsLoadTelemetry: boolean = true override onActiveConnectionModified = new vscode.EventEmitter() diff --git a/packages/core/src/login/webview/vue/backend.ts b/packages/core/src/login/webview/vue/backend.ts index 9bc6c5ae339..43d86feedf9 100644 --- a/packages/core/src/login/webview/vue/backend.ts +++ b/packages/core/src/login/webview/vue/backend.ts @@ -62,18 +62,25 @@ export abstract class CommonAuthWebview extends VueWebview { } private didCall: { login: boolean; reauth: boolean } = { login: false, reauth: false } - public setUiReady(state: 'login' | 'reauth') { - // Prevent telemetry spam, since showing/hiding chat triggers this each time. - // So only emit once. + /** + * Called when the UI load process is completed, regardless of success or failure + * + * @param errorMessage IF an error is caught on the frontend, this is the message. It will result in a failure metric. + * Otherwise we assume success. + */ + public setUiReady(state: 'login' | 'reauth', errorMessage?: string) { + // Only emit once to prevent telemetry spam, since showing/hiding chat triggers this each time. + // TODO: Research how to not trigger this on every show/hide if (this.didCall[state]) { return } - telemetry.webview_load.emit({ - passive: true, - webviewName: state, - result: 'Succeeded', - }) + if (errorMessage) { + this.setLoadFailure(state, errorMessage) + } else { + this.setDidLoad(state) + } + this.didCall[state] = true } diff --git a/packages/core/src/login/webview/vue/login.vue b/packages/core/src/login/webview/vue/login.vue index d21bf911802..831a1dfcb22 100644 --- a/packages/core/src/login/webview/vue/login.vue +++ b/packages/core/src/login/webview/vue/login.vue @@ -145,6 +145,7 @@ >