diff --git a/.github/workflows/ui-test.yml b/.github/workflows/ui-test.yml index 8f36ce37dc..838dcdb0c0 100644 --- a/.github/workflows/ui-test.yml +++ b/.github/workflows/ui-test.yml @@ -210,7 +210,7 @@ jobs: TEAMSFX_TELEMETRY_TEST: true strategy: fail-fast: false - max-parallel: 50 + max-parallel: 80 matrix: ${{ fromJson(needs.setup.outputs.matrix) }} runs-on: ${{ matrix.os }} steps: diff --git a/.github/workflows/vscode-marketplace.yml b/.github/workflows/vscode-marketplace.yml deleted file mode 100644 index 533fcbb2c5..0000000000 --- a/.github/workflows/vscode-marketplace.yml +++ /dev/null @@ -1,74 +0,0 @@ -name: publish to VSCode marketplace -run-name: Publish-${{ inputs.run_id }}-${{ github.ref_name }}-isPreview-${{ inputs.isPreview }}-${{ inputs.series }} -on: - workflow_dispatch: - inputs: - run_id: - description: "Input the CD pipeline run ID to fetch the artifact" - required: true - default: "" - isPreview: - description: "Publish VSIX as a preview version(yes or no)" - required: true - default: "no" - series: - description: "release sprint series name" - required: false - default: "" - -jobs: - publish-to-vscode-marketplace: - runs-on: ubuntu-latest - environment: production - permissions: - id-token: write - actions: read - contents: write - - steps: - - uses: actions/checkout@v2 - with: - token: ${{ secrets.CD_PAT }} - ref: ${{ github.head_ref }} - - - name: Download release artifacts - uses: Legit-Labs/action-download-artifact@v2 - with: - run_id: ${{ github.event.inputs.run_id }} - name: release - github_token: ${{ secrets.CD_PAT }} - workflow: cd.yml - path: . - - - name: get VSC beta tag - if: ${{ github.event.inputs.isPreview != 'no' }} - id: vsc_ver - run: | - VSC_VER=$(jq -c -r '.[]|select(.name == "ms-teams-vscode-extension")|.name+"@"+.version' versions.json) - echo "-------------------" $VSC_VER - echo "::set-output name=vsc_ver::$VSC_VER" - - - uses: mathieudutour/github-tag-action@v6.0 - if: ${{ github.event.inputs.isPreview != 'no' }} - with: - github_token: ${{ secrets.CD_PAT }} - custom_tag: ${{ steps.vsc_ver.outputs.vsc_ver }} - tag_prefix: "" - - - name: Azure login - uses: azure/login@v2 - with: - client-id: ${{ secrets.PUBLISHER_AZURE_CLIENT_ID }} - tenant-id: ${{ secrets.PUBLISHER_AZURE_TENANT_ID }} - subscription-id: ${{ secrets.PUBLISHER_AZURE_SUBSCRIPTION_ID }} - enable-AzPSSession: true - - - name: release preview to VSCode marketplace - if: ${{ github.event.inputs.isPreview != 'no' }} - run: | - npx @vscode/vsce publish --pre-release --azure-credential --packagePath *.vsix --noVerify - - - name: release to VSCode marketplace - if: ${{ github.event.inputs.isPreview == 'no' }} - run: | - npx @vscode/vsce publish --azure-credential --packagePath *.vsix --noVerify diff --git a/packages/api/src/error.ts b/packages/api/src/error.ts index a1202ed37a..340052e1be 100644 --- a/packages/api/src/error.ts +++ b/packages/api/src/error.ts @@ -19,6 +19,8 @@ export interface FxError extends Error { categories?: string[]; + telemetryProperties?: Record; + /** * recommended operation for user to fix the error * e.g. "debug-in-test-tool" @@ -37,6 +39,7 @@ export interface ErrorOptionBase { userData?: any; displayMessage?: string; categories?: string[]; + telemetryProperties?: Record; /** * whether to skip process (such as mask secret tokens) in telemetry collection */ @@ -81,6 +84,8 @@ export class UserError extends Error implements FxError { categories?: string[]; + telemetryProperties?: Record; + /** * whether to skip process (such as mask secret tokens) in telemetry collection */ @@ -138,6 +143,7 @@ export class UserError extends Error implements FxError { this.timestamp = new Date(); this.categories = option.categories; this.skipProcessInTelemetry = option.skipProcessInTelemetry; + this.telemetryProperties = option.telemetryProperties; } } @@ -173,6 +179,8 @@ export class SystemError extends Error implements FxError { categories?: string[]; + telemetryProperties?: Record; + /** * whether to skip process (such as mask secret tokens) in telemetry collection */ @@ -230,5 +238,6 @@ export class SystemError extends Error implements FxError { this.timestamp = new Date(); this.categories = option.categories; this.skipProcessInTelemetry = option.skipProcessInTelemetry; + this.telemetryProperties = option.telemetryProperties; } } diff --git a/packages/cli/src/commonlib/telemetry.ts b/packages/cli/src/commonlib/telemetry.ts index 9fd0d985e9..5651d0cadb 100644 --- a/packages/cli/src/commonlib/telemetry.ts +++ b/packages/cli/src/commonlib/telemetry.ts @@ -65,7 +65,9 @@ export class CliTelemetryReporter implements TelemetryReporter { this.reporter.sendTelemetryErrorEvent(eventName, properties, measurements, errorProps); void logger.debug( - `sendTelemetryErrorEvent ===> ${eventName}, properties: ${JSON.stringify(properties)}` + `sendTelemetryErrorEvent ===> ${eventName}, properties: ${JSON.stringify( + properties + )}, measurements: ${JSON.stringify(measurements)}` ); } @@ -89,7 +91,9 @@ export class CliTelemetryReporter implements TelemetryReporter { this.reporter.sendTelemetryEvent(eventName, properties, measurements); void logger.debug( - `sendTelemetryEvent ===> ${eventName}, properties: ${JSON.stringify(properties)}` + `sendTelemetryEvent ===> ${eventName}, properties: ${JSON.stringify( + properties + )}, measurements: ${JSON.stringify(measurements)}` ); } diff --git a/packages/fx-core/resource/package.nls.json b/packages/fx-core/resource/package.nls.json index 787013f1de..f5813bd243 100644 --- a/packages/fx-core/resource/package.nls.json +++ b/packages/fx-core/resource/package.nls.json @@ -128,8 +128,8 @@ "plugins.frontend.checkStoragePermissionsTip": "Check if you have permissions to your Azure Storage Account.", "plugins.frontend.checkSystemTimeTip": "Incorrect system time may lead to expired credentials. Make sure your system time is correct.", "suggestions.retryTheCurrentStep": "Retry the current step.", - "plugins.appstudio.buildSucceedNotice": "Teams package is successfully built at [local address](%s).", - "plugins.appstudio.buildSucceedNotice.fallback": "Teams package is successfully built at %s.", + "plugins.appstudio.buildSucceedNotice": "Teams package successfully built at [local address](%s).", + "plugins.appstudio.buildSucceedNotice.fallback": "Teams package successfully built at %s.", "plugins.appstudio.createPackage.progressBar.message": "Building Teams app package...", "plugins.appstudio.validationFailedNotice": "Manifest Validation is unsuccessful!", "plugins.appstudio.validateManifest.progressBar.message": "Validating manifest...", @@ -149,7 +149,7 @@ "plugins.appstudio.previewOnly": "Preview only", "plugins.appstudio.previewAndUpdate": "Preview and update", "plugins.appstudio.overwriteAndUpdate": "Overwrite and update", - "plugins.appstudio.emptyAppPackage": "Unable to find any files in the app %s package.", + "plugins.appstudio.emptyAppPackage": "unable to find any files in the app %s package.", "plugins.appstudio.unprocessedFile": "Teams Toolkit did not process %s.", "plugins.appstudio.viewDeveloperPortal": "View in Developer Portal", "plugins.bot.questionHostTypeTrigger.title": "Select triggers", @@ -181,7 +181,9 @@ "error.appstudio.teamsAppUpdateFailed": "Unable to update Teams app with ID %s in Teams Developer Portal due to %s", "error.appstudio.apiFailed": "Unable to make API call to Developer Portal. Check [Output panel](command:fx-extension.showOutputChannel) for details.", "_error.appstudio.apiFailed.comment": " This is to describe API call, no need to translate '(command:fx-extension.showOutputChannel)'. ", - "error.appstudio.apiFailed.telemetry": "Unable to make API call to Developer Portal: %s, %s, API name: %s, X-Correlation-ID: %s. This may be due to a temporary service error. Try again after a few minutes.", + "error.appstudio.apiFailed.telemetry": "Unable to make API call to Developer Portal: %s, %s, API name: %s, X-Correlation-ID: %s.", + "error.appstudio.apiFailed.reason.common": "This may be due to a temporary service error. Try again after a few minutes.", + "error.appstudio.apiFailed.name.common": "API failed", "_error.appstudio.apiFailed.telemetry.comment": "This is to describe API call, no need to translate 'X-Correlation-ID'.", "error.appstudio.authServiceApiFailed": "Unable to make API call to Developer Portal: %s, %s, Request path: %s", "error.appstudio.publishFailed": "Unable to publish Teams app with ID %s.", @@ -315,7 +317,7 @@ "core.createProjectQuestion.projectType.customCopilot.placeholder": "Select an option", "core.createProjectQuestion.projectType.copilotHelp.label": "Don't know how to start? Use GitHub Copilot Chat", "core.createProjectQuestion.projectType.copilotHelp.detail": "Chat with GitHub Copilot and get step-by-step instructions to develop your Teams app", - "core.createProjectQuestion.projectType.copilotGroup.title": "Use Copilot", + "core.createProjectQuestion.projectType.copilotGroup.title": "Use GitHub Copilot", "core.createProjectQuestion.projectType.createGroup.title": "Create", "core.createProjectQuestion.projectType.declarativeCopilot.label": "Declarative Agent", "core.createProjectQuestion.projectType.declarativeCopilot.detail": "Create your own agent by declaring instructions, actions, & knowledge to suit your needs.", @@ -639,8 +641,6 @@ "plugins.bot.CheckLogAndFix": "Please check log-in Output panel and try to fix this issue.", "plugins.bot.AppStudioBotRegistration": "Developer Portal bot registration", "plugins.function.getTemplateFromLocal": "Unable to get latest template from GitHub, trying to use the local template.", - "error.depChecker.DefaultErrorMessage": "Install required dependencies manually.", - "depChecker.learnMoreButtonText": "Get more info", "depChecker.needInstallNpm": "You must have NPM installed to debug your local functions.", "depChecker.failToValidateFuncCoreTool": "Unable to validate Azure Functions Core Tools after installation.", "depChecker.symlinkDirAlreadyExist": "Symlink (%s) destination already exists, remove it and try again.", @@ -655,13 +655,9 @@ "depChecker.useGlobalDotnet": "Using dotnet from PATH:", "depChecker.dotnetInstallStderr": "dotnet-install command failed without error exit code but with non-empty standard error.", "depChecker.dotnetInstallErrorCode": "dotnet-install command failed.", - "depChecker.NodeNotFound": "Cannot find Node.js. The supported node versions are specified in the package.json. Go to %s to install a supported Node.js. Restart all your Visual Studio Code instances after the installation is finished.", - "depChecker.V3NodeNotSupported": "Node.js (%s) is not the officially supported version (%s). Your project may continue to work but we recommend to install the supported version. The supported node versions are specified in the package.json. Go to %s to install a supported Node.js.", - "depChecker.NodeNotLts": "Node.js (%s) is not a LTS version (%s). Go to %s to install a LTS Node.js.", "depChecker.dotnetNotFound": "Unable to find @NameVersion. To know why .NET SDK is needed, refer @HelpLink", "depChecker.depsNotFound": "Unable to find @SupportedPackages.\n\nTeams Toolkit requires these dependencies.\n\nClick \"Install\" to install @InstallPackages.", "depChecker.linuxDepsNotFound": "Unable to find @SupportedPackages. Install @SupportedPackages manually and restart Visual Studio Code.", - "depChecker.linuxDepsNotFoundHelpLinkMessage": "Unable to find @SupportedPackages.\n\nTeams Toolkit requires these dependencies.", "depChecker.failToDownloadFromUrl": "Unable to download file from '@Url', HTTP status '@Status'.", "depChecker.failToValidateVxTestAppInstallOptions": "Invalid argument for video extensibility test app prerequisites checker. Please review tasks.json file to ensure all arguments are correctly formatted and valid.", "depChecker.failToValidateVxTestApp": "Unable to validate video extensibility test app after installation.", @@ -819,7 +815,7 @@ "error.yaml.InvalidYmlActionNameError": "Action '%s' not found, yaml file: %s", "error.yaml.LifeCycleUndefinedError": "Lifecycle '%s' is undefined, yaml file: %s", "error.yaml.InvalidActionInputError": "The '%s' action cannot be completed as the following parameter(s): %s, are either missing or have an invalid value in the provided yaml file: %s. Ensure that the required parameters are provided and have valid values and try again.", - "error.common.InstallSoftwareError": "Unable to install %s. You can install it manually and restart Visual Studio Code if you are using the Toolkit in Visual Studio Code.", + "error.common.InstallSoftwareError": "Unable to install %s. You can install manually and restart Visual Studio Code if you are using the Toolkit in Visual Studio Code.", "error.common.VersionError": "Unable to find a version satisfying the version range %s.", "error.common.MissingEnvironmentVariablesError": "Missing environment variables '%s' for file: %s. Please edit the .env file '%s' or '%s', or adjust system environment variables. For new Teams Toolkit projects, make sure you've run provision or debug to set these variables correctly.", "error.common.InvalidProjectError": "This command only works for project created by Teams Toolkit. 'teamsapp.yml' or 'teamsapp.local.yml' not found", @@ -919,5 +915,13 @@ "driver.oauth.log.skipUpdateOauth": "Skip updating OAuth registration as the same property exists.", "driver.oauth.confirm.update": "The following parameters will be updated:\n%s\nDo you want to continue?", "driver.oauth.log.successUpdateOauth": "OAuth registration updated successfully!", - "driver.oauth.info.update": "OAuth registration updated successfully! The following parameters have been updated:\n%s" -} + "driver.oauth.info.update": "OAuth registration updated successfully! The following parameters have been updated:\n%s", + "error.dep.PortsConflictError": "Port occupation check failed. Candidate ports to check: %s. The following ports are occupied: %s. Please close them and try again.", + "error.dep.SideloadingDisabledError": "Your Microsoft 365 account admin hasn't enabled custom app upload permission.\n· Contact your Teams admin to fix this. Visit: https://docs.microsoft.com/en-us/microsoftteams/platform/m365-apps/prerequisites\n· For help, visit the Microsoft Teams documentation. To create a free testing tenant, click \"Custom App Upload Disabled\" label under your account.", + "error.dep.CopilotDisabledError": "Microsoft 365 account administrator hasn't enabled Copilot access for this account. Contact your Teams administrator to resolve this issue by enrolling in Microsoft 365 Copilot Early Access program. Visit: https://aka.ms/PluginsEarlyAccess", + "error.dep.NodejsNotFoundError": "Unable to find Node.js. Go to https://nodejs.org to install LTS Node.js.", + "error.dep.NodejsNotLtsError": "Node.js (%s) is not a LTS version (%s). Go to https://nodejs.org to install LTS Node.js.", + "error.dep.NodejsNotRecommendedError": "Node.js (%s) is not the officially supported version (%s). Your project may continue to work but we recommend to install the supported version. The supported node versions are specified in the package.json. Go to https://nodejs.org to install a supported Node.js.", + "error.dep.VxTestAppInvalidInstallOptionsError": "Invalid argument for video extensibility test app prerequisites checker. Please review tasks.json file to ensure all arguments are correctly formatted and valid.", + "error.dep.VxTestAppValidationError": "Unable to validate video extensibility test app after installation." +} \ No newline at end of file diff --git a/packages/fx-core/src/client/teamsDevPortalClient.ts b/packages/fx-core/src/client/teamsDevPortalClient.ts index afc8c17dba..ac72ba1148 100644 --- a/packages/fx-core/src/client/teamsDevPortalClient.ts +++ b/packages/fx-core/src/client/teamsDevPortalClient.ts @@ -3,10 +3,10 @@ import { hooks } from "@feathersjs/hooks"; import { SystemError } from "@microsoft/teamsfx-api"; -import { AxiosInstance } from "axios"; +import { AxiosInstance, AxiosResponse } from "axios"; import { HelpLinks } from "../common/constants"; import { ErrorContextMW, TOOLS } from "../common/globalVars"; -import { getLocalizedString } from "../common/localizeUtils"; +import { getDefaultString, getLocalizedString } from "../common/localizeUtils"; import { TelemetryEvent, TelemetryProperty, @@ -54,7 +54,8 @@ import { Messages } from "../component/resource/botService/messages"; import { CommonStrings, ConfigNames } from "../component/resource/botService/strings"; import { CheckSideloadingPermissionFailedError, - DeveloperPortalAPIFailedError, + DeveloperPortalAPIFailedSystemError, + DeveloperPortalAPIFailedUserError, } from "../error/teamsApp"; export class RetryHandler { @@ -156,16 +157,22 @@ export class TeamsDevPortalClient { ); return app; } else { - throw new Error(`Cannot create teams app`); + throw this.wrapException( + new Error("cannot create teams app"), + APP_STUDIO_API_NAMES.CREATE_APP + ); } } catch (e: any) { if (e.response?.status === 409) { - const error = AppStudioResultFactory.UserError( + throw this.wrapException( + e, + APP_STUDIO_API_NAMES.CREATE_APP, AppStudioError.TeamsAppCreateConflictError.name, - AppStudioError.TeamsAppCreateConflictError.message(), + AppStudioError.TeamsAppCreateConflictError.message()[0], + AppStudioError.TeamsAppCreateConflictError.message()[1], + true, HelpLinks.SwitchTenant ); - throw error; } // Corner case: The provided app ID conflict with an existing published app // See Developer Portal PR: 507264 @@ -173,11 +180,14 @@ export class TeamsDevPortalClient { e.response?.status == 422 && e.response?.data.includes("App already exists and published") ) { - const error = AppStudioResultFactory.UserError( + throw this.wrapException( + e, + APP_STUDIO_API_NAMES.CREATE_APP, AppStudioError.TeamsAppCreateConflictWithPublishedAppError.name, - AppStudioError.TeamsAppCreateConflictWithPublishedAppError.message() + AppStudioError.TeamsAppCreateConflictWithPublishedAppError.message()[0], + AppStudioError.TeamsAppCreateConflictWithPublishedAppError.message()[1], + true ); - throw error; } // Corner case: App Id must be a GUID if ( @@ -189,15 +199,17 @@ export class TeamsDevPortalClient { throw manifest.error; } else { const teamsAppId = manifest.value.id; - const error = AppStudioResultFactory.UserError( + throw this.wrapException( + e, + APP_STUDIO_API_NAMES.CREATE_APP, AppStudioError.InvalidTeamsAppIdError.name, - AppStudioError.InvalidTeamsAppIdError.message(teamsAppId) + AppStudioError.InvalidTeamsAppIdError.message(teamsAppId)[0], + AppStudioError.InvalidTeamsAppIdError.message(teamsAppId)[1], + true ); - throw error; } } - const error = this.wrapException(e, APP_STUDIO_API_NAMES.CREATE_APP); - throw error; + throw this.wrapException(e, APP_STUDIO_API_NAMES.CREATE_APP); } } @@ -216,10 +228,12 @@ export class TeamsDevPortalClient { TOOLS.logProvider.error("Cannot get the app definitions"); } } catch (e) { - const error = this.wrapException(e, APP_STUDIO_API_NAMES.LIST_APPS); - throw error; + throw this.wrapException(e, APP_STUDIO_API_NAMES.LIST_APPS); } - throw new Error("Cannot get the app definitions"); + throw this.wrapException( + new Error("cannot get the app definitions"), + APP_STUDIO_API_NAMES.LIST_APPS + ); } @hooks([ErrorContextMW({ source: "Teams", component: "TeamsDevPortalClient" })]) async deleteApp(appStudioToken: string, teamsAppId: string): Promise { @@ -242,10 +256,12 @@ export class TeamsDevPortalClient { } } } catch (e) { - const error = this.wrapException(e, APP_STUDIO_API_NAMES.DELETE_APP); - throw error; + throw this.wrapException(e, APP_STUDIO_API_NAMES.DELETE_APP); } - throw new Error("Cannot delete the app: " + teamsAppId); + throw this.wrapException( + new Error("cannot delete the app: " + teamsAppId), + APP_STUDIO_API_NAMES.DELETE_APP + ); } @hooks([ErrorContextMW({ source: "Teams", component: "TeamsDevPortalClient" })]) async getApp(token: string, teamsAppId: string): Promise { @@ -269,10 +285,12 @@ export class TeamsDevPortalClient { } } } catch (e) { - const error = this.wrapException(e, APP_STUDIO_API_NAMES.GET_APP); - throw error; + throw this.wrapException(e, APP_STUDIO_API_NAMES.GET_APP); } - throw new Error(`Cannot get the app definition with app ID ${teamsAppId}`); + throw this.wrapException( + new Error(`cannot get the app definition with app ID ${teamsAppId}`), + APP_STUDIO_API_NAMES.GET_APP + ); } @hooks([ErrorContextMW({ source: "Teams", component: "TeamsDevPortalClient" })]) async getBotId(token: string, teamsAppId: string): Promise { @@ -296,11 +314,13 @@ export class TeamsDevPortalClient { TOOLS.logProvider?.info("Download app package successfully"); return response.data; } else { - throw new Error(getLocalizedString("plugins.appstudio.emptyAppPackage", teamsAppId)); + throw this.wrapException( + new Error(getLocalizedString("plugins.appstudio.emptyAppPackage", teamsAppId)), + APP_STUDIO_API_NAMES.GET_APP_PACKAGE + ); } } catch (e) { - const error = this.wrapException(e, APP_STUDIO_API_NAMES.GET_APP_PACKAGE); - throw error; + throw this.wrapException(e, APP_STUDIO_API_NAMES.GET_APP_PACKAGE); } } @@ -361,36 +381,40 @@ export class TeamsDevPortalClient { try { return await this.publishTeamsAppUpdate(token, teamsAppId, file); } catch (e: any) { - // Update Published app failed as well - const error = AppStudioResultFactory.SystemError( - AppStudioError.TeamsAppPublishConflictError.name, - AppStudioError.TeamsAppPublishConflictError.message(teamsAppId), - e - ); - throw error; + if (e instanceof DeveloperPortalAPIFailedSystemError) { + throw this.wrapException( + this.wrapResponse(undefined, response), + APP_STUDIO_API_NAMES.PUBLISH_APP, + AppStudioError.TeamsAppPublishConflictError.name, + AppStudioError.TeamsAppPublishConflictError.message(teamsAppId)[0], + AppStudioError.TeamsAppPublishConflictError.message(teamsAppId)[1] + ); + } else { + throw e; + } } } - - const error = new Error(response?.data.error.message); - (error as any).response = response; - (error as any).request = response.request; - const exception = this.wrapException(error, APP_STUDIO_API_NAMES.PUBLISH_APP); - throw exception; + throw this.wrapException( + this.wrapResponse(undefined, response), + APP_STUDIO_API_NAMES.PUBLISH_APP + ); } else { return response.data.id; } } else { - throw AppStudioResultFactory.SystemError( + throw this.wrapException( + this.wrapResponse(new Error("empty response"), response), + APP_STUDIO_API_NAMES.PUBLISH_APP, AppStudioError.TeamsAppPublishFailedError.name, - AppStudioError.TeamsAppPublishFailedError.message(teamsAppId, "POST /api/publishing") + AppStudioError.TeamsAppPublishFailedError.message(teamsAppId, "POST /api/publishing")[0], + AppStudioError.TeamsAppPublishFailedError.message(teamsAppId, "POST /api/publishing")[1] ); } } catch (e: any) { if (e instanceof SystemError) { throw e; } else { - const error = this.wrapException(e, APP_STUDIO_API_NAMES.PUBLISH_APP); - throw error; + throw this.wrapException(e, APP_STUDIO_API_NAMES.PUBLISH_APP); } } } @@ -417,38 +441,45 @@ export class TeamsDevPortalClient { }) ); } else { - throw AppStudioResultFactory.SystemError( + throw this.wrapException( + new Error("API failed"), + APP_STUDIO_API_NAMES.GET_PUBLISHED_APP, AppStudioError.TeamsAppPublishFailedError.name, AppStudioError.TeamsAppPublishFailedError.message( teamsAppId, `GET /api/publishing/${teamsAppId}` - ) + )[0], + AppStudioError.TeamsAppPublishFailedError.message( + teamsAppId, + `GET /api/publishing/${teamsAppId}` + )[1] ); } // eslint-disable-next-line @typescript-eslint/restrict-template-expressions const requestPath = `${response?.request?.method} ${response?.request?.path}`; if (response && response.data) { if (response.data.error || response.data.errorMessage) { - const error = new Error(response.data.error?.message || response.data.errorMessage); - (error as any).response = response; - (error as any).request = response.request; - const exception = this.wrapException(error, APP_STUDIO_API_NAMES.UPDATE_PUBLISHED_APP); - throw exception; + throw this.wrapException( + this.wrapResponse(undefined, response), + APP_STUDIO_API_NAMES.UPDATE_PUBLISHED_APP + ); } else { return response.data.teamsAppId; } } else { - throw AppStudioResultFactory.SystemError( + throw this.wrapException( + new Error("empty response"), + APP_STUDIO_API_NAMES.UPDATE_PUBLISHED_APP, AppStudioError.TeamsAppPublishFailedError.name, - AppStudioError.TeamsAppPublishFailedError.message(teamsAppId, requestPath) + AppStudioError.TeamsAppPublishFailedError.message(teamsAppId, requestPath)[0], + AppStudioError.TeamsAppPublishFailedError.message(teamsAppId, requestPath)[1] ); } } catch (error: any) { - if (error instanceof SystemError) { + if (error instanceof DeveloperPortalAPIFailedSystemError) { throw error; } else { - const exception = this.wrapException(error, APP_STUDIO_API_NAMES.UPDATE_PUBLISHED_APP); - throw exception; + throw this.wrapException(error, APP_STUDIO_API_NAMES.UPDATE_PUBLISHED_APP); } } } @@ -544,8 +575,7 @@ export class TeamsDevPortalClient { throw new Error(ErrorMessages.GrantPermissionFailed); } } catch (err) { - const error = this.wrapException(err, APP_STUDIO_API_NAMES.UPDATE_OWNER); - throw error; + throw this.wrapException(err, APP_STUDIO_API_NAMES.UPDATE_OWNER); } } /** @@ -565,8 +595,7 @@ export class TeamsDevPortalClient { ); return response?.data; } catch (e) { - const error = this.wrapException(e, APP_STUDIO_API_NAMES.VALIDATE_APP_PACKAGE); - throw error; + throw this.wrapException(e, APP_STUDIO_API_NAMES.VALIDATE_APP_PACKAGE); } } @@ -589,11 +618,9 @@ export class TeamsDevPortalClient { @hooks([ErrorContextMW({ source: "Teams", component: "TeamsDevPortalClient" })]) async submitAppValidationRequest( token: string, - teamsAppId: string, - timeoutSeconds = 20 + teamsAppId: string ): Promise { const requester = this.createRequesterWithToken(token); - requester.defaults.timeout = timeoutSeconds * 1000; try { const response = await RetryHandler.Retry(() => requester.post(`/api/v1.0/appvalidations/appdefinition/validate`, { @@ -603,8 +630,7 @@ export class TeamsDevPortalClient { ); return response?.data; } catch (e) { - const error = this.wrapException(e, APP_STUDIO_API_NAMES.SUBMIT_APP_VALIDATION); - throw error; + throw this.wrapException(e, APP_STUDIO_API_NAMES.SUBMIT_APP_VALIDATION); } } @@ -623,8 +649,7 @@ export class TeamsDevPortalClient { ); return response?.data; } catch (e) { - const error = this.wrapException(e, APP_STUDIO_API_NAMES.GET_APP_VALIDATION_REQUESTS); - throw error; + throw this.wrapException(e, APP_STUDIO_API_NAMES.GET_APP_VALIDATION_REQUESTS); } } /** @@ -637,19 +662,16 @@ export class TeamsDevPortalClient { @hooks([ErrorContextMW({ source: "Teams", component: "TeamsDevPortalClient" })]) async getAppValidationById( token: string, - appValidationId: string, - timeoutSeconds = 20 + appValidationId: string ): Promise { const requester = this.createRequesterWithToken(token); - requester.defaults.timeout = timeoutSeconds * 1000; try { const response = await RetryHandler.Retry(() => requester.get(`/api/v1.0/appvalidations/${appValidationId}`) ); return response?.data; } catch (e) { - const error = this.wrapException(e, APP_STUDIO_API_NAMES.GET_APP_VALIDATION_RESULT); - throw error; + throw this.wrapException(e, APP_STUDIO_API_NAMES.GET_APP_VALIDATION_RESULT); } } @hooks([ErrorContextMW({ source: "Teams", component: "TeamsDevPortalClient" })]) @@ -699,7 +721,10 @@ export class TeamsDevPortalClient { error, error.response?.headers?.[Constants.CORRELATION_ID] ?? "", apiName, - error.response?.data ? `data: ${JSON.stringify(error.response.data)}` : "" + getDefaultString( + "error.appstudio.apiFailed.reason.common", + error.response?.data ? `data: ${JSON.stringify(error.response.data)}` : "" + ) ), { // eslint-disable-next-line @typescript-eslint/restrict-template-expressions @@ -729,8 +754,7 @@ export class TeamsDevPortalClient { ); return response?.data; } catch (e) { - const error = this.wrapException(e, APP_STUDIO_API_NAMES.CREATE_API_KEY); - throw error; + throw this.wrapException(e, APP_STUDIO_API_NAMES.CREATE_API_KEY); } } @@ -751,8 +775,7 @@ export class TeamsDevPortalClient { ); return response?.data; } catch (e) { - const error = this.wrapException(e, APP_STUDIO_API_NAMES.GET_API_KEY); - throw error; + throw this.wrapException(e, APP_STUDIO_API_NAMES.GET_API_KEY); } } @hooks([ErrorContextMW({ source: "Teams", component: "TeamsDevPortalClient" })]) @@ -771,8 +794,7 @@ export class TeamsDevPortalClient { ); return response?.data; } catch (e) { - const error = this.wrapException(e, APP_STUDIO_API_NAMES.UPDATE_API_KEY); - throw error; + throw this.wrapException(e, APP_STUDIO_API_NAMES.UPDATE_API_KEY); } } @@ -788,8 +810,7 @@ export class TeamsDevPortalClient { ); return response?.data; } catch (e) { - const error = this.wrapException(e, APP_STUDIO_API_NAMES.GET_OAUTH); - throw error; + throw this.wrapException(e, APP_STUDIO_API_NAMES.GET_OAUTH); } } @@ -805,8 +826,7 @@ export class TeamsDevPortalClient { ); return response?.data; } catch (e) { - const error = this.wrapException(e, APP_STUDIO_API_NAMES.CREATE_OAUTH); - throw error; + throw this.wrapException(e, APP_STUDIO_API_NAMES.CREATE_OAUTH); } } @@ -823,8 +843,7 @@ export class TeamsDevPortalClient { ); return response?.data; } catch (e) { - const error = this.wrapException(e, APP_STUDIO_API_NAMES.UPDATE_OAUTH); - throw error; + throw this.wrapException(e, APP_STUDIO_API_NAMES.UPDATE_OAUTH); } } @@ -838,7 +857,12 @@ export class TeamsDevPortalClient { return response!.data; // response cannot be undefined as it's checked in isHappyResponse. } else { // Defensive code and it should never reach here. - throw new Error("Failed to get data"); + throw this.wrapException( + this.wrapResponse(undefined, response), + APP_STUDIO_API_NAMES.GET_BOT, + getDefaultString("error.appstudio.apiFailed.name.common"), + "Failed to get data" + ); } } catch (e) { this.handleBotFrameworkError(e, APP_STUDIO_API_NAMES.GET_BOT); @@ -854,7 +878,12 @@ export class TeamsDevPortalClient { return response!.data; // response cannot be undefined as it's checked in isHappyResponse. } else { // Defensive code and it should never reach here. - throw new Error("Failed to get data"); + throw this.wrapException( + this.wrapResponse(undefined, response), + APP_STUDIO_API_NAMES.LIST_BOT, + getDefaultString("error.appstudio.apiFailed.name.common"), + "Failed to get data" + ); } } catch (e) { this.handleBotFrameworkError(e, APP_STUDIO_API_NAMES.LIST_BOT); @@ -940,11 +969,52 @@ export class TeamsDevPortalClient { throw this.wrapException(e, apiName) as SystemError; } } - wrapException(e: any, apiName: string): Error { - const correlationId = e.response?.headers[Constants.CORRELATION_ID]; + wrapResponse(e?: Error, response?: AxiosResponse): any { + const error = new Error( + e?.message || response?.data.error.message || response?.data.errorMessage + ); + (error as any).response = response; + (error as any).request = response?.request; + return error; + } + wrapException( + e: any, + apiName: string, + name = getDefaultString("error.appstudio.apiFailed.name.common"), + potentialReason = getDefaultString("error.appstudio.apiFailed.reason.common"), + disPlayMessage?: string, + isUserError = false, + helpLink?: string + ): Error { + e.name = name; + const correlationId = e.response?.headers?.[Constants.CORRELATION_ID]; // eslint-disable-next-line @typescript-eslint/restrict-template-expressions - const extraData = e.response?.data ? `data: ${JSON.stringify(e.response.data)}` : ""; - const error = new DeveloperPortalAPIFailedError(e, correlationId, apiName, extraData); + let extraData = `${potentialReason} ${ + e.response?.data ? `data: ${JSON.stringify(e.response.data)}` : "" + }`; + // add status code in extra data if the message does not have it. + if (!e.message?.toLowerCase().includes("status code") && e.response?.status) { + extraData = `Status code: ${e.response.status as string}. ${extraData}`; + } + let error; + if (isUserError) { + error = new DeveloperPortalAPIFailedUserError( + e, + correlationId, + apiName, + extraData, + disPlayMessage, + helpLink + ); + } else { + error = new DeveloperPortalAPIFailedSystemError( + e, + correlationId, + apiName, + extraData, + disPlayMessage + ); + } return error; } } diff --git a/packages/fx-core/src/common/featureFlags.ts b/packages/fx-core/src/common/featureFlags.ts index f375bc1e58..3811f782ee 100644 --- a/packages/fx-core/src/common/featureFlags.ts +++ b/packages/fx-core/src/common/featureFlags.ts @@ -33,6 +33,7 @@ export class FeatureFlagName { static readonly EnvFileFunc = "TEAMSFX_ENV_FILE_FUNC"; static readonly KiotaIntegration = "TEAMSFX_KIOTA_INTEGRATION"; static readonly ApiPluginAAD = "TEAMSFX_API_PLUGIN_AAD"; + static readonly CEAEnabled = "TEAMSFX_CEA_ENABLED"; } export interface FeatureFlag { @@ -104,6 +105,10 @@ export class FeatureFlags { name: FeatureFlagName.ApiPluginAAD, defaultValue: "false", }; + static readonly CEAEnabled = { + name: FeatureFlagName.CEAEnabled, + defaultValue: "false", + }; } export function isCopilotExtensionEnabled(): boolean { diff --git a/packages/fx-core/src/common/telemetry.ts b/packages/fx-core/src/common/telemetry.ts index c04102c902..d6b3c90994 100644 --- a/packages/fx-core/src/common/telemetry.ts +++ b/packages/fx-core/src/common/telemetry.ts @@ -305,6 +305,10 @@ class TelemetryUtils { props[TelemetryProperty.ErrorCat2] = error.categories[1]; props[TelemetryProperty.ErrorCat3] = error.categories[2]; } + + if (error.telemetryProperties) { + assign(props, error.telemetryProperties); + } } fillinProjectTypeProperties(props: Record, projectTypeRes: ProjectTypeResult) { diff --git a/packages/fx-core/src/common/wrappedAxiosClient.ts b/packages/fx-core/src/common/wrappedAxiosClient.ts index 5f9f051f42..2ac9267dbf 100644 --- a/packages/fx-core/src/common/wrappedAxiosClient.ts +++ b/packages/fx-core/src/common/wrappedAxiosClient.ts @@ -14,8 +14,9 @@ import { TelemetryPropertyValue, } from "../component/driver/teamsApp/utils/telemetry"; import { TelemetryEvent, TelemetryProperty, TelemetrySuccess } from "./telemetry"; -import { DeveloperPortalAPIFailedError } from "../error/teamsApp"; +import { DeveloperPortalAPIFailedSystemError } from "../error/teamsApp"; import { HttpMethod } from "../component/constant/commonConstant"; +import { getDefaultString } from "./localizeUtils"; /** * This client will send telemetries to record API request trace @@ -114,8 +115,11 @@ export class WrappedAxiosClient { if (eventName === TelemetryEvent.AppStudioApi) { const correlationId = error.response?.headers[Constants.CORRELATION_ID] ?? "undefined"; // eslint-disable-next-line @typescript-eslint/restrict-template-expressions - const extraData = error.response?.data ? `data: ${JSON.stringify(error.response.data)}` : ""; - const TDPApiFailedError = new DeveloperPortalAPIFailedError( + const extraData = getDefaultString( + "error.appstudio.apiFailed.reason.common", + error.response?.data ? `data: ${JSON.stringify(error.response.data)}` : "" + ); + const TDPApiFailedError = new DeveloperPortalAPIFailedSystemError( error, correlationId, apiName, diff --git a/packages/fx-core/src/component/coordinator/index.ts b/packages/fx-core/src/component/coordinator/index.ts index cb0a6e184d..d06f9be66d 100644 --- a/packages/fx-core/src/component/coordinator/index.ts +++ b/packages/fx-core/src/component/coordinator/index.ts @@ -24,6 +24,7 @@ import * as path from "path"; import * as uuid from "uuid"; import * as xml2js from "xml2js"; import { AppStudioScopes, getResourceGroupInPortal } from "../../common/constants"; +import { FeatureFlags, featureFlagManager } from "../../common/featureFlags"; import { ErrorContextMW, globalVars } from "../../common/globalVars"; import { getLocalizedString } from "../../common/localizeUtils"; import { convertToAlphanumericOnly } from "../../common/stringUtils"; @@ -54,6 +55,7 @@ import { developerPortalScaffoldUtils } from "../developerPortalScaffoldUtils"; import { DriverContext } from "../driver/interface/commonArgs"; import { updateTeamsAppV3ForPublish } from "../driver/teamsApp/appStudio"; import { Constants } from "../driver/teamsApp/constants"; +import { manifestUtils } from "../driver/teamsApp/utils/ManifestUtils"; import { Generator } from "../generator/generator"; import { Generators } from "../generator/generatorProvider"; import { ActionContext, ActionExecutionMW } from "../middleware/actionExecutionMW"; @@ -64,7 +66,6 @@ import { metadataUtil } from "../utils/metadataUtil"; import { pathUtils } from "../utils/pathUtils"; import { settingsUtil } from "../utils/settingsUtil"; import { SummaryReporter } from "./summary"; -import { featureFlagManager, FeatureFlags } from "../../common/featureFlags"; const M365Actions = [ "botAadApp/create", @@ -215,6 +216,10 @@ class Coordinator { return err(res.error); } } + + const trimRes = await manifestUtils.trimManifestShortName(projectPath); + if (trimRes.isErr()) return err(trimRes.error); + return ok({ projectPath: projectPath, warnings }); } diff --git a/packages/fx-core/src/component/deps-checker/constant/message.ts b/packages/fx-core/src/component/deps-checker/constant/message.ts index 7c9833cb4e..2f15ca4025 100644 --- a/packages/fx-core/src/component/deps-checker/constant/message.ts +++ b/packages/fx-core/src/component/deps-checker/constant/message.ts @@ -5,11 +5,6 @@ import { getDefaultString, getLocalizedString } from "../../../common/localizeUt import { nodeInstallationLink } from "./helpLink"; export const Messages = { - // learnMoreButtonText: getLocalizedString("depChecker.learnMoreButtonText"), - defaultErrorMessage: () => [ - getDefaultString("error.depChecker.DefaultErrorMessage"), - getLocalizedString("error.depChecker.DefaultErrorMessage"), - ], needInstallNpm: () => getLocalizedString("depChecker.needInstallNpm"), failToValidateFuncCoreTool: () => getLocalizedString("depChecker.failToValidateFuncCoreTool"), portableFuncNodeNotMatched: (nodeVersion: string, funcVersion: string) => @@ -30,25 +25,6 @@ export const Messages = { dotnetInstallStderr: () => getLocalizedString("depChecker.dotnetInstallStderr"), dotnetInstallErrorCode: () => getLocalizedString("depChecker.dotnetInstallErrorCode"), - NodeNotFound: () => getLocalizedString("depChecker.NodeNotFound", nodeInstallationLink), - - // In v3, the message will be displayed in the output. - // TODO: add localized string to FxError.displayMessage - V3NodeNotSupported: (currentVersion: string, supportedVersions: string) => - getDefaultString( - "depChecker.V3NodeNotSupported", - currentVersion, - supportedVersions, - nodeInstallationLink - ), - NodeNotLts: (currentVersion: string, supportedVersions: string) => - getDefaultString( - "depChecker.NodeNotLts", - currentVersion, - supportedVersions, - nodeInstallationLink - ), - dotnetNotFound: () => getLocalizedString("depChecker.dotnetNotFound"), // depsNotFound: () => getLocalizedString("depChecker.depsNotFound"), @@ -64,8 +40,4 @@ export const Messages = { failToDownloadFromUrl: () => getLocalizedString("depChecker.failToDownloadFromUrl"), linuxDepsNotFound: () => getLocalizedString("depChecker.linuxDepsNotFound"), - - // linuxDepsNotFoundHelpLinkMessage: () => getLocalizedString( - // "depChecker.linuxDepsNotFoundHelpLinkMessage" - // ), }; diff --git a/packages/fx-core/src/component/deps-checker/depsChecker.ts b/packages/fx-core/src/component/deps-checker/depsChecker.ts index 8fba804713..db1517f6f3 100644 --- a/packages/fx-core/src/component/deps-checker/depsChecker.ts +++ b/packages/fx-core/src/component/deps-checker/depsChecker.ts @@ -1,6 +1,6 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT license. -import { DepsCheckerError } from "./depsError"; +import { UserError } from "@microsoft/teamsfx-api"; export interface DepsChecker { getInstallationInfo(installOptions?: InstallOptions): Promise; @@ -20,7 +20,7 @@ export type DependencyStatus = { binFolders?: string[]; }; telemetryProperties?: { [key: string]: string }; - error?: DepsCheckerError; + error?: UserError; }; export interface DepsInfo { diff --git a/packages/fx-core/src/component/deps-checker/depsError.ts b/packages/fx-core/src/component/deps-checker/depsError.ts deleted file mode 100644 index f4f4e37733..0000000000 --- a/packages/fx-core/src/component/deps-checker/depsError.ts +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. - -export class DepsCheckerError extends Error { - public readonly helpLink: string; - - constructor(message: string, helpLink: string) { - super(message); - - this.helpLink = helpLink; - Object.setPrototypeOf(this, DepsCheckerError.prototype); - } -} - -export class NodeNotFoundError extends DepsCheckerError { - constructor(message: string, helpLink: string) { - super(message, helpLink); - - Object.setPrototypeOf(this, NodeNotFoundError.prototype); - } -} - -export class NodeNotLtsError extends DepsCheckerError { - constructor(message: string, helpLink: string) { - super(message, helpLink); - - Object.setPrototypeOf(this, NodeNotLtsError.prototype); - } -} - -export class V3NodeNotSupportedError extends DepsCheckerError { - constructor(message: string, helpLink: string) { - super(message, helpLink); - - Object.setPrototypeOf(this, V3NodeNotSupportedError.prototype); - } -} - -export class LinuxNotSupportedError extends DepsCheckerError { - constructor(message: string, helpLink: string) { - super(message, helpLink); - - Object.setPrototypeOf(this, LinuxNotSupportedError.prototype); - } -} - -export class VxTestAppCheckError extends DepsCheckerError { - constructor(message: string, helpLink: string) { - super(message, helpLink); - - Object.setPrototypeOf(this, VxTestAppCheckError.prototype); - } -} diff --git a/packages/fx-core/src/component/deps-checker/index.ts b/packages/fx-core/src/component/deps-checker/index.ts index f9ff1f5b7d..99c4813f84 100644 --- a/packages/fx-core/src/component/deps-checker/index.ts +++ b/packages/fx-core/src/component/deps-checker/index.ts @@ -4,7 +4,6 @@ export * from "./checkerFactory"; export * from "./depsChecker"; -export * from "./depsError"; export * from "./depsLogger"; export * from "./depsManager"; export * from "./depsTelemetry"; diff --git a/packages/fx-core/src/component/deps-checker/internal/dotnetChecker.ts b/packages/fx-core/src/component/deps-checker/internal/dotnetChecker.ts index 9d1588351a..7cbaf229eb 100644 --- a/packages/fx-core/src/component/deps-checker/internal/dotnetChecker.ts +++ b/packages/fx-core/src/component/deps-checker/internal/dotnetChecker.ts @@ -1,25 +1,25 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT license. -import * as os from "os"; +import { ConfigFolderName, UserError } from "@microsoft/teamsfx-api"; +import * as child_process from "child_process"; import * as fs from "fs-extra"; +import * as os from "os"; import * as path from "path"; -import * as child_process from "child_process"; -import * as util from "util"; -import { ConfigFolderName } from "@microsoft/teamsfx-api"; import { performance } from "perf_hooks"; -import { dotnetFailToInstallHelpLink, dotnetExplanationHelpLink } from "../constant/helpLink"; -import { DepsCheckerError, LinuxNotSupportedError } from "../depsError"; -import { runWithProgressIndicator } from "../util/progressIndicator"; -import { cpUtils } from "../util/cpUtils"; -import { isLinux, isWindows, isArm64, isMacOS } from "../util/system"; +import * as util from "util"; +import { getLocalizedString } from "../../../common/localizeUtils"; +import { DepsCheckerError, InstallSoftwareError } from "../../../error"; +import { getResourceFolder } from "../../../folder"; +import { dotnetExplanationHelpLink, dotnetFailToInstallHelpLink } from "../constant/helpLink"; +import { Messages } from "../constant/message"; import { DepsCheckerEvent, TelemtryMessages } from "../constant/telemetry"; +import { DependencyStatus, DepsChecker, DepsType } from "../depsChecker"; import { DepsLogger } from "../depsLogger"; import { DepsTelemetry } from "../depsTelemetry"; -import { DepsChecker, DependencyStatus, DepsType } from "../depsChecker"; -import { Messages } from "../constant/message"; -import { getResourceFolder } from "../../../folder"; -import { getLocalizedString } from "../../../common/localizeUtils"; +import { cpUtils } from "../util/cpUtils"; +import { runWithProgressIndicator } from "../util/progressIndicator"; +import { isArm64, isLinux, isMacOS, isWindows } from "../util/system"; const execFile = util.promisify(child_process.execFile); @@ -48,10 +48,7 @@ export class DotnetChecker implements DepsChecker { this._telemetry = telemetry; } - public async getDepsInfo( - isInstalled: boolean, - error?: DepsCheckerError - ): Promise { + public async getDepsInfo(isInstalled: boolean, error?: UserError): Promise { const execPath = await this.getDotnetExecPathFromConfig(); return { name: DotnetCoreSDKName, @@ -108,7 +105,7 @@ export class DotnetChecker implements DepsChecker { } catch (error) { this._logger.printDetailLog(); this._logger.error(`${error.message as string}, error = '${error.toString() as string}'`); - if (error instanceof DepsCheckerError) { + if (error instanceof UserError) { return await this.getDepsInfo(false, error); } return await this.getDepsInfo( @@ -122,10 +119,7 @@ export class DotnetChecker implements DepsChecker { public async install(): Promise { if (isLinux()) { - throw new LinuxNotSupportedError( - Messages.linuxDepsNotFound().split("@SupportedPackages").join(installedNameWithVersion), - dotnetExplanationHelpLink - ); + throw new InstallSoftwareError(installedNameWithVersion, dotnetExplanationHelpLink); } this._logger.debug(`[start] cleanup bin/dotnet and config`); diff --git a/packages/fx-core/src/component/deps-checker/internal/funcToolChecker.ts b/packages/fx-core/src/component/deps-checker/internal/funcToolChecker.ts index 60684879ac..e2f965e6f0 100644 --- a/packages/fx-core/src/component/deps-checker/internal/funcToolChecker.ts +++ b/packages/fx-core/src/component/deps-checker/internal/funcToolChecker.ts @@ -4,24 +4,24 @@ /** * @author Xiaofu Huang */ +import { ConfigFolderName, err, ok, Result, UserError } from "@microsoft/teamsfx-api"; import * as fs from "fs-extra"; import * as os from "os"; import * as path from "path"; import semver from "semver"; import * as uuid from "uuid"; -import { ConfigFolderName, err, ok, Result } from "@microsoft/teamsfx-api"; import { getLocalizedString } from "../../../common/localizeUtils"; -import { v3DefaultHelpLink, v3NodeNotFoundHelpLink } from "../constant/helpLink"; +import { DepsCheckerError, InstallSoftwareError, NodejsNotFoundError } from "../../../error"; +import { v3DefaultHelpLink } from "../constant/helpLink"; import { Messages } from "../constant/message"; +import { TelemetryProperties } from "../constant/telemetry"; import { DependencyStatus, DepsChecker, DepsType, FuncInstallOptions } from "../depsChecker"; -import { DepsCheckerError, LinuxNotSupportedError, NodeNotFoundError } from "../depsError"; import { DepsLogger } from "../depsLogger"; import { DepsTelemetry } from "../depsTelemetry"; import { cpUtils } from "../util/cpUtils"; import { createSymlink, rename, unlinkSymlink } from "../util/fileHelper"; import { isLinux, isWindows } from "../util/system"; import { NodeChecker } from "./nodeChecker"; -import { TelemetryProperties } from "../constant/telemetry"; type FuncVersion = { majorVersion: number; @@ -51,7 +51,7 @@ export class FuncToolChecker implements DepsChecker { public async getDepsInfo( funcVersion: FuncVersion | undefined, binFolder: string | undefined, - error?: DepsCheckerError + error?: UserError ): Promise { return Promise.resolve({ name: funcToolName, @@ -97,7 +97,7 @@ export class FuncToolChecker implements DepsChecker { return installationInfo; } catch (error) { - if (error instanceof DepsCheckerError) { + if (error instanceof UserError) { return await this.getDepsInfo(undefined, undefined, error); } return await this.getDepsInfo( @@ -156,7 +156,7 @@ export class FuncToolChecker implements DepsChecker { private async getNodeVersion(): Promise { const nodeVersion = (await NodeChecker.getInstalledNodeVersion())?.majorVersion; if (!nodeVersion) { - throw new NodeNotFoundError(Messages.NodeNotFound(), v3NodeNotFoundHelpLink); + throw new NodejsNotFoundError(); } return nodeVersion; } @@ -296,10 +296,7 @@ export class FuncToolChecker implements DepsChecker { symlinkDir: string | undefined ): Promise { if (isLinux()) { - throw new LinuxNotSupportedError( - Messages.linuxDepsNotFound().split("@SupportedPackages").join(funcToolName), - v3DefaultHelpLink - ); + throw new InstallSoftwareError(funcToolName, v3DefaultHelpLink); } if (!(await this.hasNPM())) { throw new DepsCheckerError(Messages.needInstallNpm(), v3DefaultHelpLink); diff --git a/packages/fx-core/src/component/deps-checker/internal/nodeChecker.ts b/packages/fx-core/src/component/deps-checker/internal/nodeChecker.ts index 97825ce1bf..ecd4d969d7 100644 --- a/packages/fx-core/src/component/deps-checker/internal/nodeChecker.ts +++ b/packages/fx-core/src/component/deps-checker/internal/nodeChecker.ts @@ -1,24 +1,23 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT license. +import { FxError, UserError } from "@microsoft/teamsfx-api"; import * as fs from "fs-extra"; import * as path from "path"; import semver from "semver"; +import { + DepsCheckerError, + NodejsNotFoundError, + NodejsNotLtsError, + NodejsNotRecommendedError, +} from "../../../error"; import { nodeNotFoundHelpLink, v3NodeNotFoundHelpLink, - v3NodeNotLtsHelpLink, v3NodeNotSupportedHelpLink, } from "../constant/helpLink"; -import { Messages } from "../constant/message"; import { DepsCheckerEvent } from "../constant/telemetry"; -import { DependencyStatus, DepsChecker, DepsType, BaseInstallOptions } from "../depsChecker"; -import { - DepsCheckerError, - NodeNotFoundError, - NodeNotLtsError, - V3NodeNotSupportedError, -} from "../depsError"; +import { BaseInstallOptions, DependencyStatus, DepsChecker, DepsType } from "../depsChecker"; import { DepsLogger } from "../depsLogger"; import { DepsTelemetry } from "../depsTelemetry"; import { cpUtils } from "../util/cpUtils"; @@ -44,7 +43,7 @@ export abstract class NodeChecker implements DepsChecker { protected abstract getVersionNotSupportedError( supportedVersions: string[], version: NodeVersion - ): DepsCheckerError; + ): UserError; protected abstract readonly _minErrorVersion: number; protected abstract readonly _maxErrorVersion: number; @@ -71,7 +70,7 @@ export abstract class NodeChecker implements DepsChecker { DepsCheckerEvent.nodeNotFound, "Node.js can't be found." ); - const error = new NodeNotFoundError(Messages.NodeNotFound(), this._nodeNotFoundHelpLink); + const error = new NodejsNotFoundError(); return await this.getDepsInfo(false, supportedVersions, undefined, error); } this._telemetry.sendEvent(DepsCheckerEvent.nodeVersion, { @@ -122,7 +121,7 @@ export abstract class NodeChecker implements DepsChecker { isInstalled: boolean, supportedVersions: string[], installVersion?: string, - error?: DepsCheckerError + error?: FxError ): Promise { return { name: NodeName, @@ -204,12 +203,9 @@ export class LtsNodeChecker extends NodeChecker { protected getVersionNotSupportedError( supportedVersions: string[], version: NodeVersion - ): DepsCheckerError { + ): UserError { const supportedVersionsString = supportedVersions.map((v) => "v" + v).join(", "); - return new NodeNotLtsError( - Messages.NodeNotLts(version.version, supportedVersionsString), - v3NodeNotLtsHelpLink - ); + return new NodejsNotLtsError(version.version, supportedVersionsString); } } @@ -256,11 +252,8 @@ export class ProjectNodeChecker extends NodeChecker { protected getVersionNotSupportedError( supportedVersions: string[], version: NodeVersion - ): DepsCheckerError { + ): UserError { const supportedVersionsString = supportedVersions.join(", "); - return new V3NodeNotSupportedError( - Messages.V3NodeNotSupported(version.version, supportedVersionsString), - v3NodeNotSupportedHelpLink - ); + return new NodejsNotRecommendedError(version.version, supportedVersionsString); } } diff --git a/packages/fx-core/src/component/deps-checker/internal/testToolChecker.ts b/packages/fx-core/src/component/deps-checker/internal/testToolChecker.ts index a059e931b3..e9e4ffd0a8 100644 --- a/packages/fx-core/src/component/deps-checker/internal/testToolChecker.ts +++ b/packages/fx-core/src/component/deps-checker/internal/testToolChecker.ts @@ -1,16 +1,20 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT license. +import { ConfigFolderName, err, ok, Result, UserError } from "@microsoft/teamsfx-api"; import * as fs from "fs-extra"; +import fetch from "node-fetch"; import * as os from "os"; import * as path from "path"; -import * as url from "url"; import semver from "semver"; +import maxSatisfying from "semver/ranges/max-satisfying"; +import * as url from "url"; import * as uuid from "uuid"; -import { ConfigFolderName, err, ok, Result } from "@microsoft/teamsfx-api"; import { getLocalizedString } from "../../../common/localizeUtils"; -import { v3DefaultHelpLink, v3NodeNotFoundHelpLink } from "../constant/helpLink"; +import { DepsCheckerError, NodejsNotFoundError } from "../../../error"; +import { v3DefaultHelpLink } from "../constant/helpLink"; import { Messages } from "../constant/message"; +import { TelemetryProperties } from "../constant/telemetry"; import { DependencyStatus, DepsChecker, @@ -18,14 +22,10 @@ import { TestToolInstallOptions, TestToolReleaseType, } from "../depsChecker"; -import { DepsCheckerError, NodeNotFoundError } from "../depsError"; -import { createSymlink, rename, unlinkSymlink, cleanup } from "../util/fileHelper"; -import { isWindows } from "../util/system"; -import { TelemetryProperties } from "../constant/telemetry"; import { cpUtils } from "../util"; -import fetch from "node-fetch"; -import maxSatisfying from "semver/ranges/max-satisfying"; import { downloadToTempFile, unzip } from "../util/downloadHelper"; +import { cleanup, createSymlink, rename, unlinkSymlink } from "../util/fileHelper"; +import { isWindows } from "../util/system"; enum InstallType { Global = "global", @@ -128,7 +128,7 @@ export class TestToolChecker implements DepsChecker { let installationInfo: TestToolDependencyStatus; try { if (installOptions.releaseType === TestToolReleaseType.Npm && !(await this.hasNode())) { - throw new NodeNotFoundError(Messages.NodeNotFound(), v3NodeNotFoundHelpLink); + throw new NodejsNotFoundError(); } installationInfo = await this.getInstallationInfo(installOptions); if (!installationInfo.isInstalled) { @@ -152,7 +152,7 @@ export class TestToolChecker implements DepsChecker { return installationInfo; } catch (error: any) { - if (error instanceof DepsCheckerError) { + if (error instanceof UserError) { return await this.createFailureDepsInfo(installOptions.versionRange, error); } return await this.createFailureDepsInfo( diff --git a/packages/fx-core/src/component/deps-checker/internal/vxTestAppChecker.ts b/packages/fx-core/src/component/deps-checker/internal/vxTestAppChecker.ts index d7f1205d3b..446f660410 100644 --- a/packages/fx-core/src/component/deps-checker/internal/vxTestAppChecker.ts +++ b/packages/fx-core/src/component/deps-checker/internal/vxTestAppChecker.ts @@ -1,18 +1,20 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT license. import * as fs from "fs-extra"; -import * as path from "path"; import * as os from "os"; +import * as path from "path"; -import { ConfigFolderName } from "@microsoft/teamsfx-api"; -import { Messages } from "../constant"; -import { DepsCheckerError, VxTestAppCheckError } from "../depsError"; +import { ConfigFolderName, UserError } from "@microsoft/teamsfx-api"; +import { + VxTestAppInvalidInstallOptionsError, + VxTestAppValidationError, +} from "../../../error/depCheck"; +import { BaseInstallOptions, DependencyStatus, DepsChecker, DepsType } from "../depsChecker"; import { DepsLogger } from "../depsLogger"; import { DepsTelemetry } from "../depsTelemetry"; -import { DepsChecker, DependencyStatus, DepsType, BaseInstallOptions } from "../depsChecker"; import { isMacOS, isWindows } from "../util"; -import { createSymlink } from "../util/fileHelper"; import { downloadToTempFile, unzip } from "../util/downloadHelper"; +import { createSymlink } from "../util/fileHelper"; interface InstallOptionsSafe { version: string; @@ -53,7 +55,7 @@ export class VxTestAppChecker implements DepsChecker { if (!this.isValidInstallOptions(installOptions)) { return VxTestAppChecker.newDependencyStatusForInstallError( // documentation no longer exists, replaced with empty string. - new VxTestAppCheckError(Messages.failToValidateVxTestAppInstallOptions(), "") + new VxTestAppInvalidInstallOptionsError() ); } @@ -77,7 +79,7 @@ export class VxTestAppChecker implements DepsChecker { if (!(await this.isValidInstalltion(projectInstallDir, installOptions.version))) { return VxTestAppChecker.newDependencyStatusForInstallError( // documentation no longer exists, replaced with empty string. - new VxTestAppCheckError(Messages.failToValidateVxTestApp(), "") + new VxTestAppValidationError() ); } @@ -99,7 +101,7 @@ export class VxTestAppChecker implements DepsChecker { if (!this.isValidInstallOptions(installOptions)) { return VxTestAppChecker.newDependencyStatusForInstallError( // documentation no longer exists, replaced with empty string. - new VxTestAppCheckError(Messages.failToValidateVxTestAppInstallOptions(), "") + new VxTestAppValidationError() ); } @@ -175,7 +177,7 @@ export class VxTestAppChecker implements DepsChecker { } private static newDependencyStatusForInstallError( - error: DepsCheckerError, + error: UserError, version?: string ): DependencyStatus { return { diff --git a/packages/fx-core/src/component/deps-checker/util/fileHelper.ts b/packages/fx-core/src/component/deps-checker/util/fileHelper.ts index 46e859f3e5..9f5c945d46 100644 --- a/packages/fx-core/src/component/deps-checker/util/fileHelper.ts +++ b/packages/fx-core/src/component/deps-checker/util/fileHelper.ts @@ -7,7 +7,7 @@ import * as fs from "fs-extra"; import { v3DefaultHelpLink } from "../constant/helpLink"; import { Messages } from "../constant/message"; -import { DepsCheckerError } from "../depsError"; +import { DepsCheckerError } from "../../../error/depCheck"; export async function unlinkSymlink(linkFilePath: string): Promise { try { diff --git a/packages/fx-core/src/component/driver/devTool/error/dotnetInstallationUserError.ts b/packages/fx-core/src/component/driver/devTool/error/dotnetInstallationUserError.ts index ee11f7a008..2d42e550da 100644 --- a/packages/fx-core/src/component/driver/devTool/error/dotnetInstallationUserError.ts +++ b/packages/fx-core/src/component/driver/devTool/error/dotnetInstallationUserError.ts @@ -3,8 +3,8 @@ import { UserError } from "@microsoft/teamsfx-api"; import { camelCase } from "lodash"; -import { DepsCheckerError } from "../../../deps-checker/depsError"; import { getDefaultString, getLocalizedString } from "../../../../common/localizeUtils"; +import { DepsCheckerError } from "../../../../error/depCheck"; const errorCode = "DotnetInstallationError"; const messageKey = "driver.prerequisite.error.dotnetInstallationError"; diff --git a/packages/fx-core/src/component/driver/devTool/error/funcInstallationUserError.ts b/packages/fx-core/src/component/driver/devTool/error/funcInstallationUserError.ts index 27ee7ec2f3..691ec45815 100644 --- a/packages/fx-core/src/component/driver/devTool/error/funcInstallationUserError.ts +++ b/packages/fx-core/src/component/driver/devTool/error/funcInstallationUserError.ts @@ -3,8 +3,8 @@ import { UserError } from "@microsoft/teamsfx-api"; import { camelCase } from "lodash"; -import { DepsCheckerError } from "../../../deps-checker/depsError"; import { getDefaultString, getLocalizedString } from "../../../../common/localizeUtils"; +import { DepsCheckerError } from "../../../../error/depCheck"; const errorCode = "FuncInstallationError"; const messageKey = "driver.prerequisite.error.funcInstallationError"; diff --git a/packages/fx-core/src/component/driver/devTool/error/testToolInstallationUserError.ts b/packages/fx-core/src/component/driver/devTool/error/testToolInstallationUserError.ts index 8b0db164ed..fb98c13b1a 100644 --- a/packages/fx-core/src/component/driver/devTool/error/testToolInstallationUserError.ts +++ b/packages/fx-core/src/component/driver/devTool/error/testToolInstallationUserError.ts @@ -3,8 +3,8 @@ import { UserError } from "@microsoft/teamsfx-api"; import { camelCase } from "lodash"; -import { DepsCheckerError } from "../../../deps-checker/depsError"; import { getDefaultString, getLocalizedString } from "../../../../common/localizeUtils"; +import { DepsCheckerError } from "../../../../error/depCheck"; const errorCode = "TestToolInstallationError"; const messageKey = "driver.prerequisite.error.testToolInstallationError"; diff --git a/packages/fx-core/src/component/driver/oauth/update.ts b/packages/fx-core/src/component/driver/oauth/update.ts index d3fba99de2..726b895fa9 100644 --- a/packages/fx-core/src/component/driver/oauth/update.ts +++ b/packages/fx-core/src/component/driver/oauth/update.ts @@ -19,7 +19,7 @@ import { import { OauthNameTooLongError } from "./error/oauthNameTooLong"; import { UpdateOauthArgs } from "./interface/updateOauthArgs"; import { logMessageKeys } from "./utility/constants"; -import { getandValidateOauthInfoFromSpec } from "./utility/utility"; +import { getandValidateOauthInfoFromSpec, OauthInfo } from "./utility/utility"; import { OauthDisablePKCEError } from "./error/oauthDisablePKCEError"; const actionName = "oauth/update"; // DO NOT MODIFY the name @@ -44,7 +44,6 @@ export class UpdateOauthDriver implements StepDriver { this.validateArgs(args); const authInfo = await getandValidateOauthInfoFromSpec(args, context, actionName); - const domain = authInfo.domain; const appStudioTokenRes = await context.m365TokenProvider.getAccessToken({ scopes: AppStudioScopes, }); @@ -61,7 +60,7 @@ export class UpdateOauthDriver implements StepDriver { throw new OauthDisablePKCEError(actionName); } - const diffMsgs = this.compareOauthRegistration(getOauthRes, args, domain); + const diffMsgs = this.compareOauthRegistration(getOauthRes, args, authInfo); // If there is no difference, skip the update if (!diffMsgs || diffMsgs.length === 0) { const summary = getLocalizedString(logMessageKeys.skipUpdateOauth); @@ -76,7 +75,9 @@ export class UpdateOauthDriver implements StepDriver { // If there is difference, ask user to confirm the update // Skip confirm if only targetUrlsShouldStartWith is different when the url contains devtunnel - if (!this.shouldSkipConfirm(diffMsgs, getOauthRes.targetUrlsShouldStartWith, domain)) { + if ( + !this.shouldSkipConfirm(diffMsgs, getOauthRes.targetUrlsShouldStartWith, authInfo.domain) + ) { const userConfirm = await context.ui!.confirm!({ name: "confirm-update-oauth", title: getLocalizedString("driver.oauth.confirm.update", diffMsgs.join(",\n")), @@ -87,7 +88,7 @@ export class UpdateOauthDriver implements StepDriver { } } - const oauth = this.mapArgsToOauthRegistration(args, domain); + const oauth = this.mapArgsToOauthRegistration(args, authInfo); await teamsDevPortalClient.updateOauthRegistration( appStudioToken, oauth, @@ -179,7 +180,7 @@ export class UpdateOauthDriver implements StepDriver { private compareOauthRegistration( current: OauthRegistration, input: UpdateOauthArgs, - domain: string[] + authInfo: OauthInfo ): string[] { const diffMsgs: string[] = []; if (current.description !== input.name) { @@ -201,6 +202,7 @@ export class UpdateOauthDriver implements StepDriver { } // Compare domain + const domain = authInfo.domain; if ( current.targetUrlsShouldStartWith.length !== domain.length || !current.targetUrlsShouldStartWith.every((value) => domain.includes(value)) || @@ -213,7 +215,46 @@ export class UpdateOauthDriver implements StepDriver { ); } - if (current.isPKCEEnabled !== input.isPKCEEnabled) { + // TODO: Need to separate the logic for different flows + // Compare authorizationEndpoint + if ( + authInfo.authorizationEndpoint && + current.authorizationEndpoint !== authInfo.authorizationEndpoint + ) { + diffMsgs.push( + `authorizationEndpoint: ${current.authorizationEndpoint} => ${authInfo.authorizationEndpoint}` + ); + } + + // Compare tokenExchangeEndpoint + if ( + authInfo.tokenExchangeEndpoint && + current.tokenExchangeEndpoint !== authInfo.tokenExchangeEndpoint + ) { + diffMsgs.push( + `tokenExchangeEndpoint: ${current.tokenExchangeEndpoint} => ${authInfo.tokenExchangeEndpoint}` + ); + } + + // Compare tokenRefreshEndpoint + if (current.tokenRefreshEndpoint !== authInfo.tokenRefreshEndpoint) { + diffMsgs.push( + `tokenRefreshEndpoint: ${current.tokenRefreshEndpoint ?? "Undefined"} => ${ + authInfo.tokenRefreshEndpoint ?? "Undefined" + }` + ); + } + + // Compare scopes + if (!this.compareScopes(current.scopes, authInfo.scopes)) { + diffMsgs.push( + `scopes: ${current.scopes.join(",")} => ${ + authInfo.scopes ? authInfo.scopes.join(",") : "Undefined" + }` + ); + } + + if (!!current.isPKCEEnabled !== !!input.isPKCEEnabled) { diffMsgs.push( `isPKCEEnabled: ${(!!current.isPKCEEnabled).toString()} => ${(!!input.isPKCEEnabled).toString()}` ); @@ -233,7 +274,10 @@ export class UpdateOauthDriver implements StepDriver { ); } - private mapArgsToOauthRegistration(args: UpdateOauthArgs, domain: string[]): OauthRegistration { + private mapArgsToOauthRegistration( + args: UpdateOauthArgs, + authInfo: OauthInfo + ): OauthRegistration { const targetAudience = args.targetAudience ? (args.targetAudience as OauthRegistrationTargetAudience) : undefined; @@ -243,11 +287,24 @@ export class UpdateOauthDriver implements StepDriver { return { description: args.name, - targetUrlsShouldStartWith: domain, + targetUrlsShouldStartWith: authInfo.domain, applicableToApps: applicableToApps, m365AppId: applicableToApps === OauthRegistrationAppType.SpecificApp ? args.appId : "", targetAudience: targetAudience, isPKCEEnabled: !!args.isPKCEEnabled, + authorizationEndpoint: authInfo.authorizationEndpoint, + tokenExchangeEndpoint: authInfo.tokenExchangeEndpoint, + tokenRefreshEndpoint: authInfo.tokenRefreshEndpoint, + scopes: authInfo.scopes ?? [], } as OauthRegistration; } + + private compareScopes(current: string[], input: string[] | undefined): boolean { + return ( + !!input && + current.length === input.length && + current.every((value) => input.includes(value)) && + input.every((value) => current.includes(value)) + ); + } } diff --git a/packages/fx-core/src/component/driver/oauth/utility/utility.ts b/packages/fx-core/src/component/driver/oauth/utility/utility.ts index 933783bd48..8c62346b44 100644 --- a/packages/fx-core/src/component/driver/oauth/utility/utility.ts +++ b/packages/fx-core/src/component/driver/oauth/utility/utility.ts @@ -60,46 +60,42 @@ export async function getandValidateOauthInfoFromSpec( }); validateDomain(domains, actionName); - if ("flow" in args) { - const authInfoArray = operations - .map((value) => { - let authInfo; - switch (args.flow) { - case "authorizationCode": - default: - authInfo = (value.auth?.authScheme as OpenAPIV3.OAuth2SecurityScheme).flows - .authorizationCode; - } - return { - authorizationUrl: authInfo!.authorizationUrl, - tokenUrl: authInfo!.tokenUrl, - refreshUrl: authInfo!.refreshUrl, - scopes: Object.keys(authInfo!.scopes), - }; - }) - .reduce((accumulator: AuthInfo[], currentValue) => { - if (!accumulator.find((item) => isEqual(item, currentValue))) { - accumulator.push(currentValue); - } - return accumulator; - }, []); + // Need to separate the logic for different flows + const flow = "flow" in args ? args.flow : "authorizationCode"; + const authInfoArray = operations + .map((value) => { + let authInfo; + switch (flow) { + case "authorizationCode": + default: + authInfo = (value.auth?.authScheme as OpenAPIV3.OAuth2SecurityScheme).flows + .authorizationCode; + } + return { + authorizationUrl: authInfo!.authorizationUrl, + tokenUrl: authInfo!.tokenUrl, + refreshUrl: authInfo!.refreshUrl, + scopes: Object.keys(authInfo!.scopes), + }; + }) + .reduce((accumulator: AuthInfo[], currentValue) => { + if (!accumulator.find((item) => isEqual(item, currentValue))) { + accumulator.push(currentValue); + } + return accumulator; + }, []); - if (authInfoArray.length !== 1) { - throw new OauthAuthInfoInvalid(actionName); - } - const authInfo = authInfoArray[0]; - return { - domain: domains, - authorizationEndpoint: authInfo.authorizationUrl, - tokenExchangeEndpoint: authInfo.tokenUrl, - tokenRefreshEndpoint: authInfo.refreshUrl, - scopes: authInfo.scopes, - }; - } else { - return { - domain: domains, - }; + if (authInfoArray.length !== 1) { + throw new OauthAuthInfoInvalid(actionName); } + const authInfo = authInfoArray[0]; + return { + domain: domains, + authorizationEndpoint: authInfo.authorizationUrl, + tokenExchangeEndpoint: authInfo.tokenUrl, + tokenRefreshEndpoint: authInfo.refreshUrl, + scopes: authInfo.scopes, + }; } function validateDomain(domain: string[], actionName: string): void { diff --git a/packages/fx-core/src/component/driver/teamsApp/clients/appStudioClient.ts b/packages/fx-core/src/component/driver/teamsApp/clients/appStudioClient.ts deleted file mode 100644 index a4efaa2801..0000000000 --- a/packages/fx-core/src/component/driver/teamsApp/clients/appStudioClient.ts +++ /dev/null @@ -1,887 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. - -// eslint-disable-next-line no-secrets/no-secrets -/** - * @author yuqizhou77 <86260893+yuqizhou77@users.noreply.github.com> - */ -import { LogProvider, SystemError } from "@microsoft/teamsfx-api"; -import axios, { AxiosInstance } from "axios"; -import { HelpLinks, getAppStudioEndpoint } from "../../../../common/constants"; -import { setErrorContext } from "../../../../common/globalVars"; -import { getLocalizedString } from "../../../../common/localizeUtils"; -import { - Component, - TelemetryEvent, - TelemetryProperty, - sendTelemetryErrorEvent, - sendTelemetryEvent, -} from "../../../../common/telemetry"; -import { waitSeconds } from "../../../../common/utils"; -import { WrappedAxiosClient } from "../../../../common/wrappedAxiosClient"; -import { - CheckSideloadingPermissionFailedError, - DeveloperPortalAPIFailedError, -} from "../../../../error/teamsApp"; -import { HttpStatusCode } from "../../../constant/commonConstant"; -import { IValidationResult } from "../../../driver/teamsApp/interfaces/appdefinitions/IValidationResult"; -import { AppDefinition } from "../../../driver/teamsApp/interfaces/appdefinitions/appDefinition"; -import { AppUser } from "../../../driver/teamsApp/interfaces/appdefinitions/appUser"; -import { APP_STUDIO_API_NAMES, Constants, ErrorMessages } from ".././constants"; -import { AppStudioError } from ".././errors"; -import { AppStudioResultFactory } from ".././results"; -import { - ApiSecretRegistration, - ApiSecretRegistrationUpdate, -} from "../interfaces/ApiSecretRegistration"; -import { AsyncAppValidationDetailsResponse } from "../interfaces/AsyncAppValidationDetailsResponse"; -import { AsyncAppValidationResponse } from "../interfaces/AsyncAppValidationResponse"; -import { AsyncAppValidationResultsResponse } from "../interfaces/AsyncAppValidationResultsResponse"; -import { OauthConfigurationId } from "../interfaces/OauthConfigurationId"; -import { OauthRegistration } from "../interfaces/OauthRegistration"; -import { IPublishingAppDenition } from "../interfaces/appdefinitions/IPublishingAppDefinition"; -import { manifestUtils } from "../utils/ManifestUtils"; -import { RetryHandler } from "../utils/utils"; - -// eslint-disable-next-line @typescript-eslint/no-namespace -export namespace AppStudioClient { - const baseUrl = getAppStudioEndpoint(); - - let region: string | undefined; - - /** - * Set user region - * @param _region e.g. https://dev.teams.microsoft.com/amer - */ - export function setRegion(_region: string) { - region = _region; - } - - /** - * Creates a new axios instance to call app studio to prevent setting the accessToken on global instance. - * @param {string} appStudioToken - * @returns {AxiosInstance} - */ - function createRequesterWithToken(appStudioToken: string, _regionalUrl?: string): AxiosInstance { - const instance = WrappedAxiosClient.create({ - baseURL: _regionalUrl ?? baseUrl, - }); - instance.defaults.headers.common["Authorization"] = `Bearer ${appStudioToken}`; - instance.defaults.headers.common["Client-Source"] = "teamstoolkit"; - return instance; - } - - export function wrapException(e: any, apiName: string): Error { - const correlationId = e.response?.headers[Constants.CORRELATION_ID]; - // eslint-disable-next-line @typescript-eslint/restrict-template-expressions - const extraData = e.response?.data ? `data: ${JSON.stringify(e.response.data)}` : ""; - const error = new DeveloperPortalAPIFailedError(e, correlationId, apiName, extraData); - return error; - } - - /** - * Import an app registration in app studio with the given archived file and returns the app definition. - * @param {Buffer} file - Zip file with manifest.json and two icons - * @param {string} appStudioToken - * @param {boolean} overwrite - * @param {LogProvider} logProvider - * @returns {Promise} - */ - export async function importApp( - file: Buffer, - appStudioToken: string, - logProvider: LogProvider, - overwrite = false - ): Promise { - setErrorContext({ source: "Teams" }); - try { - const requester = createRequesterWithToken(appStudioToken, region); - - logProvider.debug(`Sent API Request: ${region ?? baseUrl}/api/appdefinitions/v2/import`); - const response = await RetryHandler.Retry(() => - requester.post(`/api/appdefinitions/v2/import`, file, { - headers: { "Content-Type": "application/zip" }, - params: { - overwriteIfAppAlreadyExists: overwrite, - }, - }) - ); - - if (response && response.data) { - const app = response.data; - logProvider.debug(`Received data from Teams Developer Portal: ${JSON.stringify(app)}`); - return app; - } else { - throw new Error(`Cannot create teams app`); - } - } catch (e: any) { - if (e.response?.status === 409) { - const error = AppStudioResultFactory.UserError( - AppStudioError.TeamsAppCreateConflictError.name, - AppStudioError.TeamsAppCreateConflictError.message(), - HelpLinks.SwitchTenant - ); - throw error; - } - // Corner case: The provided app ID conflict with an existing published app - // See Developer Portal PR: 507264 - if ( - e.response?.status == 422 && - e.response?.data.includes("App already exists and published") - ) { - const error = AppStudioResultFactory.UserError( - AppStudioError.TeamsAppCreateConflictWithPublishedAppError.name, - AppStudioError.TeamsAppCreateConflictWithPublishedAppError.message() - ); - throw error; - } - // Corner case: App Id must be a GUID - if ( - e.response?.status === HttpStatusCode.BAD_REQUEST && - e.response?.data.includes("App Id must be a GUID") - ) { - const manifest = manifestUtils.extractManifestFromArchivedFile(file); - if (manifest.isErr()) { - throw manifest.error; - } else { - const teamsAppId = manifest.value.id; - const error = AppStudioResultFactory.UserError( - AppStudioError.InvalidTeamsAppIdError.name, - AppStudioError.InvalidTeamsAppIdError.message(teamsAppId) - ); - throw error; - } - } - - const error = wrapException(e, APP_STUDIO_API_NAMES.CREATE_APP); - throw error; - } - } - - export async function listApps( - appStudioToken: string, - logProvider: LogProvider - ): Promise { - if (!region) throw new Error("Failed to get region"); - setErrorContext({ source: "Teams" }); - let requester: AxiosInstance; - try { - requester = createRequesterWithToken(appStudioToken, region); - logProvider.debug(`Sent API Request: GET ${region}/api/appdefinitions`); - const response = await RetryHandler.Retry(() => requester.get(`/api/appdefinitions`)); - if (response && response.data) { - const apps = response.data; - if (apps) { - return apps; - } else { - logProvider?.error("Cannot get the app definitions"); - } - } - } catch (e) { - const error = wrapException(e, APP_STUDIO_API_NAMES.LIST_APPS); - throw error; - } - throw new Error("Cannot get the app definitions"); - } - export async function deleteApp( - teamsAppId: string, - appStudioToken: string, - logProvider: LogProvider - ): Promise { - if (!region) throw new Error("Failed to get region"); - setErrorContext({ source: "Teams" }); - let requester: AxiosInstance; - try { - requester = createRequesterWithToken(appStudioToken, region); - logProvider.debug(`Sent API Request: DELETE ${region}/api/appdefinitions/${teamsAppId}`); - const response = await RetryHandler.Retry(() => - requester.delete(`/api/appdefinitions/${teamsAppId}`) - ); - if (response && response.data) { - const success = response.data; - if (success) { - return success; - } else { - logProvider?.error("Cannot get the app definitions"); - } - } - } catch (e) { - const error = wrapException(e, APP_STUDIO_API_NAMES.DELETE_APP); - throw error; - } - throw new Error("Cannot delete the app: " + teamsAppId); - } - export async function getApp( - teamsAppId: string, - appStudioToken: string, - logProvider: LogProvider - ): Promise { - setErrorContext({ source: "Teams" }); - let requester: AxiosInstance; - try { - let response; - if (region) { - requester = createRequesterWithToken(appStudioToken, region); - logProvider.debug(`Sent API Request: GET ${region}/api/appdefinitions/${teamsAppId}`); - response = await RetryHandler.Retry(() => - requester.get(`/api/appdefinitions/${teamsAppId}`) - ); - } else { - logProvider.debug(`Sent API Request: GET ${baseUrl}/api/appdefinitions/${teamsAppId}`); - requester = createRequesterWithToken(appStudioToken); - response = await RetryHandler.Retry(() => - requester.get(`/api/appdefinitions/${teamsAppId}`) - ); - } - if (response && response.data) { - const app = response.data; - if (app && app.teamsAppId && app.teamsAppId === teamsAppId) { - return app; - } else { - // eslint-disable-next-line @typescript-eslint/restrict-template-expressions - logProvider?.error(`teamsAppId mismatch. Input: ${teamsAppId}. Got: ${app.teamsAppId}`); - } - } - } catch (e) { - const error = wrapException(e, APP_STUDIO_API_NAMES.GET_APP); - throw error; - } - throw new Error(`Cannot get the app definition with app ID ${teamsAppId}`); - } - - /** - * Check if app exists in the user's organization by the Teams app id - * @param teamsAppId - * @param appStudioToken - * @param logProvider - * @returns - */ - export async function checkExistsInTenant( - teamsAppId: string, - appStudioToken: string, - logProvider?: LogProvider - ): Promise { - setErrorContext({ source: "Teams" }); - const requester = createRequesterWithToken(appStudioToken, region); - try { - const response = await RetryHandler.Retry(() => - requester.get(`/api/appdefinitions/manifest/${teamsAppId}`) - ); - - if (response && response.data) { - return response.data; - } else { - return false; - } - } catch (e) { - return false; - } - } - - /** - * Publish Teams app to Teams App Catalog - * @param teamsAppId - * @param file - * @param appStudioToken - * @returns - */ - export async function publishTeamsApp( - teamsAppId: string, - file: Buffer, - appStudioToken: string - ): Promise { - try { - const requester = createRequesterWithToken(appStudioToken, region); - - const response = await RetryHandler.Retry(() => - requester.post("/api/publishing", file, { - headers: { "Content-Type": "application/zip" }, - }) - ); - - if (response && response.data) { - if (response.data.error) { - // To avoid App Studio BadGateway error - // The app is actually published to app catalog. - if (response.data.error.code === "BadGateway") { - const appDefinition = await getAppByTeamsAppId(teamsAppId, appStudioToken); - if (appDefinition) { - return appDefinition.teamsAppId; - } - } - - // Corner case - // Fail if an app with the same external.id exists in the staged app entitlements - // App with same id already exists in the staged apps, Invoke UpdateAPI instead. - if ( - response.data.error.code == "Conflict" && - response.data.error.innerError?.code == "AppDefinitionAlreadyExists" - ) { - try { - return await publishTeamsAppUpdate(teamsAppId, file, appStudioToken); - } catch (e: any) { - // Update Published app failed as well - const error = AppStudioResultFactory.SystemError( - AppStudioError.TeamsAppPublishConflictError.name, - AppStudioError.TeamsAppPublishConflictError.message(teamsAppId), - e - ); - throw error; - } - } - - const error = new Error(response?.data.error.message); - (error as any).response = response; - (error as any).request = response.request; - const exception = wrapException(error, APP_STUDIO_API_NAMES.PUBLISH_APP); - throw exception; - } else { - return response.data.id; - } - } else { - throw AppStudioResultFactory.SystemError( - AppStudioError.TeamsAppPublishFailedError.name, - AppStudioError.TeamsAppPublishFailedError.message(teamsAppId, "POST /api/publishing") - ); - } - } catch (e: any) { - if (e instanceof SystemError) { - throw e; - } else { - const error = wrapException(e, APP_STUDIO_API_NAMES.PUBLISH_APP); - throw error; - } - } - } - - /** - * Update existed publish request - * @param teamsAppId - * @param file - * @param appStudioToken - * @returns - */ - export async function publishTeamsAppUpdate( - teamsAppId: string, - file: Buffer, - appStudioToken: string - ): Promise { - setErrorContext({ source: "Teams" }); - try { - // Get App Definition from Teams App Catalog - const appDefinition = await getAppByTeamsAppId(teamsAppId, appStudioToken); - - const requester = createRequesterWithToken(appStudioToken, region); - let response = null; - if (appDefinition) { - // update the existing app - response = await requester.post( - `/api/publishing/${appDefinition.teamsAppId}/appdefinitions`, - file, - { headers: { "Content-Type": "application/zip" } } - ); - } else { - throw AppStudioResultFactory.SystemError( - AppStudioError.TeamsAppPublishFailedError.name, - AppStudioError.TeamsAppPublishFailedError.message( - teamsAppId, - `GET /api/publishing/${teamsAppId}` - ) - ); - } - - // eslint-disable-next-line @typescript-eslint/restrict-template-expressions - const requestPath = `${response.request?.method} ${response.request?.path}`; - if (response && response.data) { - if (response.data.error || response.data.errorMessage) { - const error = new Error(response.data.error?.message || response.data.errorMessage); - (error as any).response = response; - (error as any).request = response.request; - const exception = wrapException(error, APP_STUDIO_API_NAMES.UPDATE_PUBLISHED_APP); - throw exception; - } else { - return response.data.teamsAppId; - } - } else { - throw AppStudioResultFactory.SystemError( - AppStudioError.TeamsAppPublishFailedError.name, - AppStudioError.TeamsAppPublishFailedError.message(teamsAppId, requestPath) - ); - } - } catch (error: any) { - if (error instanceof SystemError) { - throw error; - } else { - const exception = wrapException(error, APP_STUDIO_API_NAMES.UPDATE_PUBLISHED_APP); - throw exception; - } - } - } - - /** - * Get Stagged Teams app from tenant app catalog - * @param teamsAppId manifest.id, which is externalId in app catalog. - * @param appStudioToken - * @returns - */ - export async function getAppByTeamsAppId( - teamsAppId: string, - appStudioToken: string - ): Promise { - setErrorContext({ source: "Teams" }); - const requester = createRequesterWithToken(appStudioToken, region); - try { - const response = await RetryHandler.Retry(() => - requester.get(`/api/publishing/${teamsAppId}`) - ); - if (response && response.data && response.data.value && response.data.value.length > 0) { - const appdefinitions: IPublishingAppDenition[] = response.data.value[0].appDefinitions.map( - (item: any) => { - return { - lastModifiedDateTime: item.lastModifiedDateTime - ? new Date(item.lastModifiedDateTime) - : null, - publishingState: item.publishingState, - teamsAppId: item.teamsAppId, - displayName: item.displayName, - }; - } - ); - return appdefinitions[appdefinitions.length - 1]; - } else { - return undefined; - } - } catch (e: any) { - return undefined; - } - } - - export async function getUserList( - teamsAppId: string, - appStudioToken: string, - logProvider: LogProvider - ): Promise { - let app; - try { - app = await getApp(teamsAppId, appStudioToken, logProvider); - } catch (error) { - throw error; - } - - return app.userList; - } - - export async function checkPermission( - teamsAppId: string, - appStudioToken: string, - userObjectId: string, - logProvider: LogProvider - ): Promise { - let userList; - try { - userList = await getUserList(teamsAppId, appStudioToken, logProvider); - } catch (error) { - return Constants.PERMISSIONS.noPermission; - } - - const findUser = userList?.find((user: AppUser) => user.aadId === userObjectId); - if (!findUser) { - return Constants.PERMISSIONS.noPermission; - } - - if (findUser.isAdministrator) { - return Constants.PERMISSIONS.admin; - } else { - return Constants.PERMISSIONS.operative; - } - } - - export async function grantPermission( - teamsAppId: string, - appStudioToken: string, - newUser: AppUser, - logProvider: LogProvider - ): Promise { - let app; - try { - app = await getApp(teamsAppId, appStudioToken, logProvider); - } catch (error) { - throw error; - } - - if (checkUser(app, newUser)) { - return; - } - - const findUser = app.userList?.findIndex((user: AppUser) => user["aadId"] === newUser.aadId); - if (findUser && findUser >= 0) { - return; - } - - app.userList?.push(newUser); - let requester: AxiosInstance; - try { - let response; - if (region) { - try { - logProvider.debug( - getLocalizedString( - "core.common.SendingApiRequest", - `${baseUrl}/api/appdefinitions/{teamsAppId}/owner`, - JSON.stringify(app) - ) - ); - requester = createRequesterWithToken(appStudioToken, region); - response = await requester.post(`/api/appdefinitions/${teamsAppId}/owner`, app); - logProvider.debug( - getLocalizedString("core.common.ReceiveApiResponse", JSON.stringify(response.data)) - ); - } catch (e: any) { - // Teams apps created by non-regional API cannot be found by regional API - if (e.response?.status == 404) { - requester = createRequesterWithToken(appStudioToken); - response = await requester.post(`/api/appdefinitions/${teamsAppId}/owner`, app); - } else { - throw e; - } - } - } else { - logProvider.debug( - getLocalizedString( - "core.common.SendingApiRequest", - `${baseUrl}/api/appdefinitions/{teamsAppId}/owner`, - JSON.stringify(app) - ) - ); - requester = createRequesterWithToken(appStudioToken); - response = await requester.post(`/api/appdefinitions/${teamsAppId}/owner`, app); - logProvider.debug( - getLocalizedString("core.common.ReceiveApiResponse", JSON.stringify(response.data)) - ); - } - if (!response || !response.data || !checkUser(response.data as AppDefinition, newUser)) { - throw new Error(ErrorMessages.GrantPermissionFailed); - } - } catch (err) { - if (err?.message?.indexOf("Request failed with status code 400") >= 0) { - requester = createRequesterWithToken(appStudioToken, region); - await requester.post(`/api/appdefinitions/${teamsAppId}/owner`, app.userList); - } else { - wrapException(err, APP_STUDIO_API_NAMES.UPDATE_OWNER); - throw err; - } - } - } - - export async function getAppPackage( - teamsAppId: string, - appStudioToken: string, - logProvider?: LogProvider - ): Promise { - setErrorContext({ source: "Teams" }); - logProvider?.info("Downloading app package for app " + teamsAppId); - const requester = createRequesterWithToken(appStudioToken, region); - try { - const response = await RetryHandler.Retry(() => - requester.get(`/api/appdefinitions/${teamsAppId}/manifest`) - ); - - if (response && response.data) { - logProvider?.info("Download app package successfully"); - return response.data; - } else { - throw new Error(getLocalizedString("plugins.appstudio.emptyAppPackage", teamsAppId)); - } - } catch (e) { - const error = wrapException(e, APP_STUDIO_API_NAMES.GET_APP_PACKAGE); - throw error; - } - } - - /** - * Send the app package for partner center validation - * @param file - * @param appStudioToken - * @returns - */ - export async function partnerCenterAppPackageValidation( - file: Buffer, - appStudioToken: string - ): Promise { - const requester = createRequesterWithToken(appStudioToken, region); - try { - const response = await RetryHandler.Retry(() => - requester.post("/api/appdefinitions/partnerCenterAppPackageValidation", file, { - headers: { "Content-Type": "application/zip" }, - }) - ); - return response?.data; - } catch (e) { - const error = wrapException(e, APP_STUDIO_API_NAMES.VALIDATE_APP_PACKAGE); - throw error; - } - } - - /** - * Submit App Validation Request (In-App) for which App Definitions are stored at TDP. - * @param teamsAppId - * @param appStudioToken - * @param timeoutSeconds - * @returns - */ - export async function submitAppValidationRequest( - teamsAppId: string, - appStudioToken: string, - timeoutSeconds = 20 - ): Promise { - const requester = createRequesterWithToken(appStudioToken, region); - requester.defaults.timeout = timeoutSeconds * 1000; - try { - const response = await RetryHandler.Retry(() => - requester.post(`/api/v1.0/appvalidations/appdefinition/validate`, { - AppEnvironmentId: null, - appDefinitionId: teamsAppId, - }) - ); - return response?.data; - } catch (e) { - const error = wrapException(e, APP_STUDIO_API_NAMES.SUBMIT_APP_VALIDATION); - throw error; - } - } - - /** - * Get App validation requests sumitted by the user - * @param teamsAppId - * @param appStudioToken - * @returns - */ - export async function getAppValidationRequestList( - teamsAppId: string, - appStudioToken: string - ): Promise { - const requester = createRequesterWithToken(appStudioToken, region); - try { - const response = await RetryHandler.Retry(() => - requester.get(`/api/v1.0/appvalidations/appdefinitions/${teamsAppId}`) - ); - return response?.data; - } catch (e) { - const error = wrapException(e, APP_STUDIO_API_NAMES.GET_APP_VALIDATION_REQUESTS); - throw error; - } - } - - /** - * Get App validation results by provided app validation id - * @param appValidationId - * @param appStudioToken - * @param timeoutSeconds - * @returns - */ - export async function getAppValidationById( - appValidationId: string, - appStudioToken: string, - timeoutSeconds = 20 - ): Promise { - const requester = createRequesterWithToken(appStudioToken, region); - requester.defaults.timeout = timeoutSeconds * 1000; - try { - const response = await RetryHandler.Retry(() => - requester.get(`/api/v1.0/appvalidations/${appValidationId}`) - ); - return response?.data; - } catch (e) { - const error = wrapException(e, APP_STUDIO_API_NAMES.GET_APP_VALIDATION_RESULT); - throw error; - } - } - - function checkUser(app: AppDefinition, newUser: AppUser): boolean { - const findUser = app.userList?.findIndex((user: AppUser) => user["aadId"] === newUser.aadId); - if (findUser != undefined && findUser >= 0) { - return true; - } else { - return false; - } - } - - export async function getSideloadingStatus(appStudioToken: string): Promise { - const apiName = ""; - const apiPath = "/api/usersettings/mtUserAppPolicy"; - const instance = axios.create({ - baseURL: region ?? getAppStudioEndpoint(), - }); - instance.defaults.headers.common["Authorization"] = `Bearer ${appStudioToken}`; - - let retry = 0; - const retryIntervalSeconds = 2; - do { - let response = undefined; - try { - response = await instance.get(apiPath); - let result: boolean | undefined; - if (response.status >= 400) { - result = undefined; - } else { - result = response.data?.value?.isSideloadingAllowed as boolean; - } - - if (result !== undefined) { - sendTelemetryEvent(Component.core, TelemetryEvent.CheckSideloading, { - [TelemetryProperty.IsSideloadingAllowed]: result.toString() + "", - }); - } else { - sendTelemetryErrorEvent( - Component.core, - TelemetryEvent.CheckSideloading, - new SystemError( - "M365Account", - "UnknownValue", - // eslint-disable-next-line @typescript-eslint/restrict-template-expressions - `AppStudio response code: ${response.status}, body: ${response.data}` - ), - { - [TelemetryProperty.CheckSideloadingStatusCode]: `${response.status}`, - [TelemetryProperty.CheckSideloadingMethod]: "get", - [TelemetryProperty.CheckSideloadingUrl]: apiName, - } - ); - } - - return result; - } catch (error: any) { - sendTelemetryErrorEvent( - Component.core, - TelemetryEvent.CheckSideloading, - new CheckSideloadingPermissionFailedError( - error, - error.response?.headers?.[Constants.CORRELATION_ID] ?? "", - apiName, - error.response?.data ? `data: ${JSON.stringify(error.response.data)}` : "" - ), - { - // eslint-disable-next-line @typescript-eslint/restrict-template-expressions - [TelemetryProperty.CheckSideloadingStatusCode]: `${error?.response?.status}`, - [TelemetryProperty.CheckSideloadingMethod]: "get", - [TelemetryProperty.CheckSideloadingUrl]: apiName, - } - ); - await waitSeconds((retry + 1) * retryIntervalSeconds); - } - } while (++retry < 3); - - return undefined; - } - - /** - * Create the Api Key registration. - * @param appStudioToken - * @param apiKeyRegistration - */ - export async function createApiKeyRegistration( - appStudioToken: string, - apiKeyRegistration: ApiSecretRegistration - ): Promise { - const requester = createRequesterWithToken(appStudioToken); - try { - const response = await RetryHandler.Retry(() => - requester.post("/api/v1.0/apiSecretRegistrations", apiKeyRegistration) - ); - return response?.data; - } catch (e) { - const error = wrapException(e, APP_STUDIO_API_NAMES.CREATE_API_KEY); - throw error; - } - } - - /** - * Get the Api Key registration by Id. - * @param appStudioToken - * @param apiSecretRegistrationId - */ - export async function getApiKeyRegistrationById( - appStudioToken: string, - apiSecretRegistrationId: string - ): Promise { - const requester = createRequesterWithToken(appStudioToken); - try { - const response = await RetryHandler.Retry(() => - requester.get(`/api/v1.0/apiSecretRegistrations/${apiSecretRegistrationId}`) - ); - return response?.data; - } catch (e) { - const error = wrapException(e, APP_STUDIO_API_NAMES.GET_API_KEY); - throw error; - } - } - - export async function updateApiKeyRegistration( - appStudioToken: string, - apiKeyRegistration: ApiSecretRegistrationUpdate, - apiKeyRegistrationId: string - ): Promise { - const requester = createRequesterWithToken(appStudioToken); - try { - const response = await RetryHandler.Retry(() => - requester.patch( - `/api/v1.0/apiSecretRegistrations/${apiKeyRegistrationId}`, - apiKeyRegistration - ) - ); - return response?.data; - } catch (e) { - const error = wrapException(e, APP_STUDIO_API_NAMES.UPDATE_API_KEY); - throw error; - } - } - - export async function getOauthRegistrationById( - appStudioToken: string, - oauthRegistrationId: string - ): Promise { - const requester = createRequesterWithToken(appStudioToken); - try { - const response = await RetryHandler.Retry(() => - requester.get(`/api/v1.0/oAuthConfigurations/${oauthRegistrationId}`) - ); - return response?.data; - } catch (e) { - const error = wrapException(e, APP_STUDIO_API_NAMES.GET_OAUTH); - throw error; - } - } - - export async function createOauthRegistration( - appStudioToken: string, - oauthRegistration: OauthRegistration - ): Promise { - const requester = createRequesterWithToken(appStudioToken); - try { - const response = await RetryHandler.Retry(() => - requester.post("/api/v1.0/oAuthConfigurations", oauthRegistration) - ); - return response?.data; - } catch (e) { - const error = wrapException(e, APP_STUDIO_API_NAMES.CREATE_OAUTH); - throw error; - } - } - - export async function updateOauthRegistration( - appStudioToken: string, - oauthRegistration: OauthRegistration, - oauthRegistrationId: string - ): Promise { - const requester = createRequesterWithToken(appStudioToken); - try { - const response = await RetryHandler.Retry(() => - requester.patch(`/api/v1.0/oAuthConfigurations/${oauthRegistrationId}`, oauthRegistration) - ); - return response?.data; - } catch (e) { - const error = wrapException(e, APP_STUDIO_API_NAMES.UPDATE_OAUTH); - throw error; - } - } -} diff --git a/packages/fx-core/src/component/driver/teamsApp/clients/authSvcClient.ts b/packages/fx-core/src/component/driver/teamsApp/clients/authSvcClient.ts deleted file mode 100644 index 81f31a8ab5..0000000000 --- a/packages/fx-core/src/component/driver/teamsApp/clients/authSvcClient.ts +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. - -import { AxiosInstance } from "axios"; -import { RetryHandler } from "../utils/utils"; -import { WrappedAxiosClient } from "../../../../common/wrappedAxiosClient"; - -// eslint-disable-next-line @typescript-eslint/no-namespace -export namespace AuthSvcClient { - const baseUrl = "https://authsvc.teams.microsoft.com"; - - /** - * Creates a new axios instance to prevent setting the accessToken on global instance. - * @param {string} authSvcToken - * @returns {AxiosInstance} - */ - function createRequesterWithToken(authSvcToken: string): AxiosInstance { - const instance = WrappedAxiosClient.create({ - baseURL: baseUrl, - }); - instance.defaults.headers.common["Authorization"] = `Bearer ${authSvcToken}`; - instance.defaults.headers.common["Client-Source"] = "teamstoolkit"; - return instance; - } - - /** - * Get the region of M365 user - * @param authSvcToken - * @returns e.g. https://dev.teams.microsoft.com/apac, https://dev.teams.microsoft.com/amer - */ - export async function getRegion(authSvcToken: string): Promise { - const requester = createRequesterWithToken(authSvcToken); - try { - const response = await RetryHandler.Retry(() => requester.post(`/v1.0/users/region`)); - return response?.data?.regionGtms?.teamsDevPortal as string; - } catch (e: any) { - return undefined; - } - } -} diff --git a/packages/fx-core/src/component/driver/teamsApp/errors.ts b/packages/fx-core/src/component/driver/teamsApp/errors.ts index 5659f403f9..64bb5ef450 100644 --- a/packages/fx-core/src/component/driver/teamsApp/errors.ts +++ b/packages/fx-core/src/component/driver/teamsApp/errors.ts @@ -71,17 +71,11 @@ export class AppStudioError { public static readonly TeamsAppPublishFailedError = { name: "TeamsAppPublishFailed", - message: ( - teamsAppId: string, - requestPath: string, - correlationId?: string - ): [string, string] => [ + message: (teamsAppId: string, requestPath: string): [string, string] => [ getDefaultString("error.appstudio.publishFailed", teamsAppId) + - `Request path: ${requestPath}` + - (correlationId ? `X-Correlation-ID: ${correlationId}` : ""), + ` Request path: ${requestPath}`, getLocalizedString("error.appstudio.publishFailed", teamsAppId) + - `Request path: ${requestPath}` + - (correlationId ? `X-Correlation-ID: ${correlationId}` : ""), + ` Request path: ${requestPath}`, ], }; diff --git a/packages/fx-core/src/component/driver/teamsApp/utils/ManifestUtils.ts b/packages/fx-core/src/component/driver/teamsApp/utils/ManifestUtils.ts index aa223e2968..57d60d2bf2 100644 --- a/packages/fx-core/src/component/driver/teamsApp/utils/ManifestUtils.ts +++ b/packages/fx-core/src/component/driver/teamsApp/utils/ManifestUtils.ts @@ -2,7 +2,6 @@ // Licensed under the MIT license. import { hooks } from "@feathersjs/hooks"; import { - Context, FxError, IComposeExtension, IMessagingExtensionCommand, @@ -21,35 +20,34 @@ import "reflect-metadata"; import stripBom from "strip-bom"; import { v4 } from "uuid"; import isUUID from "validator/lib/isUUID"; -import { getCapabilities as checkManifestCapabilities } from "../../../../common/projectTypeChecker"; import { ErrorContextMW } from "../../../../common/globalVars"; +import { getCapabilities as checkManifestCapabilities } from "../../../../common/projectTypeChecker"; import { FileNotFoundError, JSONSyntaxError, ReadFileError } from "../../../../error/common"; import { CapabilityOptions } from "../../../../question/constants"; import { BotScenario } from "../../../constants"; import { convertManifestTemplateToV2, convertManifestTemplateToV3 } from "../../../migrate"; import { expandEnvironmentVariable } from "../../../utils/common"; -import { WrapDriverContext } from "../../util/wrapUtil"; +import { ManifestType } from "../../../utils/envFunctionUtils"; +import { DriverContext } from "../../interface/commonArgs"; import { - getBotsTplExistingAppBasedOnVersion, - getBotsTplForCommandAndResponseBasedOnVersion, - getBotsTplForNotificationBasedOnVersion, - getBotsTplBasedOnVersion, COMPOSE_EXTENSIONS_TPL_EXISTING_APP, COMPOSE_EXTENSIONS_TPL_M365_V3, COMPOSE_EXTENSIONS_TPL_V3, - getConfigurableTabsTplExistingAppBasedOnVersion, - getConfigurableTabsTplBasedOnVersion, Constants, STATIC_TABS_MAX_ITEMS, STATIC_TABS_TPL_EXISTING_APP, STATIC_TABS_TPL_V3, WEB_APPLICATION_INFO_V3, + getBotsTplBasedOnVersion, + getBotsTplExistingAppBasedOnVersion, + getBotsTplForCommandAndResponseBasedOnVersion, + getBotsTplForNotificationBasedOnVersion, + getConfigurableTabsTplBasedOnVersion, + getConfigurableTabsTplExistingAppBasedOnVersion, } from "../constants"; import { AppStudioError } from "../errors"; import { AppStudioResultFactory } from "../results"; import { getResolvedManifest } from "./utils"; -import { ManifestType } from "../../../utils/envFunctionUtils"; -import { DriverContext } from "../../interface/commonArgs"; export class ManifestUtils { async readAppManifest(projectPath: string): Promise> { @@ -109,8 +107,12 @@ export class ManifestUtils { } getTeamsAppManifestPath(projectPath: string): string { - const filePath = path.join(projectPath, "appPackage", "manifest.json"); - return filePath; + // Samples from https://github.com/OfficeDev/Microsoft-Teams-Samples have the manifest in appManifest folder + const filePath = path.join(projectPath, "appManifest", "manifest.json"); + if (fs.existsSync(filePath)) { + return filePath; + } + return path.join(projectPath, "appPackage", "manifest.json"); } async addCapabilities( @@ -395,6 +397,32 @@ export class ManifestUtils { const manifest = JSON.parse(manifestString) as TeamsAppManifest; return ok(manifest); } + + /** + * trim the short name in manifest to make sure it is no more than 25 length + */ + async trimManifestShortName( + projectPath: string, + maxLength = 25 + ): Promise> { + const manifestPath = this.getTeamsAppManifestPath(projectPath); + const manifest = (await fs.readJson(manifestPath)) as TeamsAppManifest; + const shortName = manifest.name.short; + let hasSuffix = false; + let trimmedName = shortName; + if (shortName.includes("${{APP_NAME_SUFFIX}}")) { + hasSuffix = true; + trimmedName = shortName.replace("${{APP_NAME_SUFFIX}}", ""); + } + if (trimmedName.length <= maxLength) return ok(undefined); + let newShortName = trimmedName.replace(/\s/g, "").slice(0, maxLength); + if (hasSuffix) { + newShortName += "${{APP_NAME_SUFFIX}}"; + } + manifest.name.short = newShortName; + await fs.writeFile(manifestPath, JSON.stringify(manifest, null, 2)); + return ok(undefined); + } } export const manifestUtils = new ManifestUtils(); diff --git a/packages/fx-core/src/component/generator/apiSpec/generator.ts b/packages/fx-core/src/component/generator/apiSpec/generator.ts index fc8cbf0b11..e2b0dbb73a 100644 --- a/packages/fx-core/src/component/generator/apiSpec/generator.ts +++ b/packages/fx-core/src/component/generator/apiSpec/generator.ts @@ -312,7 +312,19 @@ export class SpecGenerator extends DefaultTemplateGenerator { const openapiSpecFileName = getTemplateInfosState.isYaml ? DefaultApiSpecYamlFileName : DefaultApiSpecJsonFileName; - const openapiSpecPath = path.join(apiSpecFolderPath, openapiSpecFileName); + + let openapiSpecPath = path.join(apiSpecFolderPath, openapiSpecFileName); + + if (getTemplateInfosState.templateName === forCustomCopilotRagCustomApi) { + const language = inputs[QuestionNames.ProgrammingLanguage] as ProgrammingLanguage; + if (language === ProgrammingLanguage.CSharp) { + openapiSpecPath = path.join( + destinationPath, + DefaultApiSpecFolderName, + openapiSpecFileName + ); + } + } await fs.ensureDir(apiSpecFolderPath); diff --git a/packages/fx-core/src/component/generator/apiSpec/helper.ts b/packages/fx-core/src/component/generator/apiSpec/helper.ts index 2571212703..ac23d879c7 100644 --- a/packages/fx-core/src/component/generator/apiSpec/helper.ts +++ b/packages/fx-core/src/component/generator/apiSpec/helper.ts @@ -94,9 +94,9 @@ export function getParserOptions( ? { isGptPlugin: isDeclarativeCopilot, allowAPIKeyAuth: false, - allowBearerTokenAuth: true, + allowBearerTokenAuth: !!platform && platform === Platform.VS ? false : true, allowMultipleParameters: true, - allowOauth2: true, + allowOauth2: !!platform && platform === Platform.VS ? false : true, projectType: ProjectType.Copilot, allowMissingId: true, allowSwagger: true, @@ -1036,7 +1036,12 @@ function parseSpec(spec: OpenAPIV3.Document): [SpecObject[], boolean] { return [res, needAuth]; } -const commonLanguages = [ProgrammingLanguage.TS, ProgrammingLanguage.JS, ProgrammingLanguage.PY]; +const commonLanguages = [ + ProgrammingLanguage.TS, + ProgrammingLanguage.JS, + ProgrammingLanguage.PY, + ProgrammingLanguage.CSharp, +]; async function updatePromptForCustomApi( spec: OpenAPIV3.Document, @@ -1058,7 +1063,10 @@ async function updateAdaptiveCardForCustomApi( destinationPath: string ): Promise { if (commonLanguages.includes(language as ProgrammingLanguage)) { - const adaptiveCardsFolderPath = path.join(destinationPath, "src", "adaptiveCards"); + let adaptiveCardsFolderPath = path.join(destinationPath, "src", "adaptiveCards"); + if (language === ProgrammingLanguage.CSharp) { + adaptiveCardsFolderPath = path.join(destinationPath, "adaptiveCards"); + } await fs.ensureDir(adaptiveCardsFolderPath); for (const item of specItems) { @@ -1073,6 +1081,41 @@ async function updateAdaptiveCardForCustomApi( } } +function filterSchema(schema: OpenAPIV3.SchemaObject): OpenAPIV3.SchemaObject { + const filteredSchema: any = { type: schema.type }; + + if (schema.description) { + filteredSchema.description = schema.description; + } + + if (schema.type === "object" && schema.properties) { + filteredSchema.properties = {}; + filteredSchema.required = schema.required; + for (const key in schema.properties) { + const property = schema.properties[key] as OpenAPIV3.SchemaObject; + if (property.type === "object") { + filteredSchema.properties[key] = filterSchema(property as OpenAPIV3.SchemaObject); + filteredSchema.required = schema.required; + } else if (property.type === "array") { + filteredSchema.properties[key] = { + type: "array", + items: filterSchema(property.items as OpenAPIV3.SchemaObject), + description: property.description, + }; + } else { + filteredSchema.properties[key] = { + type: property.type, + description: property.description, + }; + } + } + } else if (schema.type === "array" && schema.items) { + filteredSchema.items = filterSchema(schema.items as OpenAPIV3.SchemaObject); + } + + return filteredSchema; +} + async function updateActionForCustomApi( specItems: SpecObject[], language: string, @@ -1103,7 +1146,7 @@ async function updateActionForCustomApi( required: [], }; } - parameters.properties[paramType].properties[param.name] = schema; + parameters.properties[paramType].properties[param.name] = filterSchema(schema); parameters.properties[paramType].properties[param.name].description = param.description ?? ""; if (param.required) { @@ -1115,6 +1158,21 @@ async function updateActionForCustomApi( } } + const requestBody = item.item.requestBody as OpenAPIV3.RequestBodyObject; + if (requestBody) { + const content = requestBody.content; + if (content) { + const contentSchema = content["application/json"].schema as OpenAPIV3.SchemaObject; + if (Object.keys(contentSchema).length !== 0) { + parameters.properties["body"] = filterSchema(contentSchema); + parameters.properties["body"].description = requestBody.description ?? ""; + if (requestBody.required) { + parameters.required.push("body"); + } + } + } + } + actions.push({ name: item.item.operationId, description: item.item.description ?? item.item.summary, @@ -1193,6 +1251,28 @@ async def {{operationId}}( await context.send_activity(message) return "success" `, + cs: ` + [Action("{{operationId}}")] + public async Task {{functionName}}Async([ActionTurnContext] ITurnContext turnContext, [ActionTurnState] TurnState turnState, [ActionParameters] Dictionary args) + { + try + { + RequestParams requestParam = ParseRequestParams(args); + + var response = await Client.CallAsync("{{apiPath}}", Method.{{apiMethod}}, requestParam); + var data = response.Content; + + var cardTemplatePath = "./adaptiveCards/{{operationId}}.json"; + var message = RenderCardToMessage(cardTemplatePath, data); + + await turnContext.SendActivityAsync(message); + } + catch (Exception ex) { + await turnContext.SendActivityAsync("Failed to call API with error: " + ex.Message); + } + + return "complete"; + }`, }; const AuthCode = { @@ -1259,6 +1339,34 @@ async function updateCodeForCustomApi( .replace("{{OPENAPI_SPEC_PATH}}", openapiSpecFileName) .replace("# Replace with action code", actionsCode.join("\n")); await fs.writeFile(botFilePath, updateBotFileContent); + } else if (language === ProgrammingLanguage.CSharp) { + const actionsCode = []; + const codeTemplate = ActionCode["cs"]; + for (const item of specItems) { + const code = codeTemplate + .replace(/{{operationId}}/g, item.item.operationId!) + .replace(/{{apiPath}}/g, item.pathUrl) + .replace(/{{apiMethod}}/g, Utils.updateFirstLetter(item.method)) + .replace(/{{functionName}}/g, Utils.updateFirstLetter(item.item.operationId!)); + actionsCode.push(code); + } + + const apiActionCsFilePath = path.join(destinationPath, "APIActions.cs"); + const apiActionCsFileContent = (await fs.readFile(apiActionCsFilePath)).toString(); + const updateApiActionCsFileContent = apiActionCsFileContent + .replace("{{OPENAPI_SPEC_PATH}}", "apiSpecificationFile/" + openapiSpecFileName) + .replace("// Replace with action code", actionsCode.join("\n")); + await fs.writeFile(apiActionCsFilePath, updateApiActionCsFileContent); + + const files = await fs.readdir(destinationPath); + const projectFileName = files.find((file) => file.endsWith(".csproj")); + const projectFilePath = path.join(destinationPath, projectFileName!); + const projectFileContent = (await fs.readFile(projectFilePath)).toString(); + const updateProjectFileContent = projectFileContent.replace( + /{{OPENAPI_SPEC_PATH}}/g, + openapiSpecFileName + ); + await fs.writeFile(projectFilePath, updateProjectFileContent); } } @@ -1268,7 +1376,10 @@ export async function updateForCustomApi( destinationPath: string, openapiSpecFileName: string ): Promise { - const chatFolder = path.join(destinationPath, "src", "prompts", "chat"); + let chatFolder = path.join(destinationPath, "src", "prompts", "chat"); + if (language === ProgrammingLanguage.CSharp) { + chatFolder = path.join(destinationPath, "prompts", "Chat"); + } await fs.ensureDir(chatFolder); // 1. update prompt folder diff --git a/packages/fx-core/src/component/generator/officeAddin/generator.ts b/packages/fx-core/src/component/generator/officeAddin/generator.ts index c105cbe27c..cab2fb3a50 100644 --- a/packages/fx-core/src/component/generator/officeAddin/generator.ts +++ b/packages/fx-core/src/component/generator/officeAddin/generator.ts @@ -101,9 +101,6 @@ export class OfficeAddinGenerator { const name = inputs[QuestionNames.AppName] as string; const addinRoot = destinationPath; const fromFolder = inputs[QuestionNames.OfficeAddinFolder]; - const language = toLower(inputs[QuestionNames.ProgrammingLanguage]) as - | "javascript" - | "typescript"; const projectType = inputs[QuestionNames.ProjectType]; const capability = inputs[QuestionNames.Capabilities]; const inputHost = inputs[QuestionNames.OfficeAddinHost]; @@ -140,7 +137,6 @@ export class OfficeAddinGenerator { ); } // from template - const framework = getOfficeAddinFramework(inputs); const templateConfig = getOfficeAddinTemplateConfig(); const projectLink = projectType === ProjectTypeOptions.officeMetaOS().id diff --git a/packages/fx-core/src/component/resource/botService/appStudio/appStudioClient.ts b/packages/fx-core/src/component/resource/botService/appStudio/appStudioClient.ts deleted file mode 100644 index 11530268b2..0000000000 --- a/packages/fx-core/src/component/resource/botService/appStudio/appStudioClient.ts +++ /dev/null @@ -1,196 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. - -/** - * @author Qianhao Dong - */ -import { BotChannelType, IBotRegistration } from "./interfaces/IBotRegistration"; - -import { hooks } from "@feathersjs/hooks"; -import { Context, SystemError } from "@microsoft/teamsfx-api"; -import { AxiosInstance } from "axios"; -import { getAppStudioEndpoint } from "../../../../common/constants"; -import { ErrorContextMW } from "../../../../common/globalVars"; -import { WrappedAxiosClient } from "../../../../common/wrappedAxiosClient"; -import { HttpStatusCode } from "../../../constant/commonConstant"; -import { AppStudioClient as AppStudio } from "../../../driver/teamsApp/clients/appStudioClient"; -import { APP_STUDIO_API_NAMES } from "../../../driver/teamsApp/constants"; -import { isHappyResponse } from "../common"; -import { TeamsFxUrlNames } from "../constants"; -import { - BotFrameworkConflictResultError, - BotFrameworkForbiddenResultError, - BotFrameworkNotAllowedToAcquireTokenError, - BotRegistrationNotFoundError, - CheckThrowSomethingMissing, - ConfigUpdatingError, - ProvisionError, -} from "../errors"; -import { Messages } from "../messages"; -import { RetryHandler } from "../retryHandler"; -import { CommonStrings, ConfigNames } from "../strings"; - -function handleBotFrameworkError(e: any, apiName: string): void | undefined { - if (e.response?.status === HttpStatusCode.NOTFOUND) { - return undefined; // Stands for NotFound. - } else if (e.response?.status === HttpStatusCode.UNAUTHORIZED) { - throw new BotFrameworkNotAllowedToAcquireTokenError(); - } else if (e.response?.status === HttpStatusCode.FORBIDDEN) { - throw new BotFrameworkForbiddenResultError(); - } else if (e.response?.status === HttpStatusCode.TOOMANYREQS) { - throw new BotFrameworkConflictResultError(); - } else { - e.teamsfxUrlName = TeamsFxUrlNames[apiName]; - throw AppStudio.wrapException(e, apiName) as SystemError; - } -} - -export class AppStudioClient { - private static baseUrl = getAppStudioEndpoint(); - - public static newAxiosInstance(accessToken: string): AxiosInstance { - accessToken = CheckThrowSomethingMissing(ConfigNames.APPSTUDIO_TOKEN, accessToken); - const instance = WrappedAxiosClient.create({ - headers: { - post: { - Authorization: `Bearer ${accessToken}`, - "Client-Source": "teamstoolkit", - }, - get: { - Authorization: `Bearer ${accessToken}`, - "Client-Source": "teamstoolkit", - }, - }, - }); - return instance; - } - - /** - * Set user region - * @param _region e.g. https://dev.teams.microsoft.com/amer - */ - public static setRegion(region: string) { - AppStudioClient.baseUrl = region; - } - @hooks([ErrorContextMW({ source: "Teams", component: "AppStudioClient" })]) - public static async getBotRegistration( - token: string, - botId: string - ): Promise { - const axiosInstance = AppStudioClient.newAxiosInstance(token); - - try { - const response = await RetryHandler.Retry(() => - axiosInstance.get(`${AppStudioClient.baseUrl}/api/botframework/${botId}`) - ); - if (isHappyResponse(response)) { - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - return response!.data; // response cannot be undefined as it's checked in isHappyResponse. - } else { - // Defensive code and it should never reach here. - throw new Error("Failed to get data"); - } - } catch (e) { - handleBotFrameworkError(e, APP_STUDIO_API_NAMES.GET_BOT); - } - } - @hooks([ErrorContextMW({ source: "Teams", component: "AppStudioClient" })]) - public static async listBots(token: string): Promise { - const axiosInstance = AppStudioClient.newAxiosInstance(token); - try { - const response = await RetryHandler.Retry(() => - axiosInstance.get(`${AppStudioClient.baseUrl}/api/botframework`) - ); - if (isHappyResponse(response)) { - return response!.data; // response cannot be undefined as it's checked in isHappyResponse. - } else { - // Defensive code and it should never reach here. - throw new Error("Failed to get data"); - } - } catch (e) { - handleBotFrameworkError(e, APP_STUDIO_API_NAMES.LIST_BOT); - } - } - @hooks([ErrorContextMW({ source: "Teams", component: "AppStudioClient" })]) - public static async deleteBot(token: string, botId: string): Promise { - const axiosInstance = AppStudioClient.newAxiosInstance(token); - try { - await RetryHandler.Retry(() => - axiosInstance.delete(`${AppStudioClient.baseUrl}/api/botframework/${botId}`) - ); - } catch (e) { - handleBotFrameworkError(e, APP_STUDIO_API_NAMES.DELETE_BOT); - } - } - @hooks([ErrorContextMW({ source: "Teams", component: "AppStudioClient" })]) - public static async createBotRegistration( - token: string, - registration: IBotRegistration, - checkExistence = true, - context?: Context - ): Promise { - const axiosInstance = AppStudioClient.newAxiosInstance(token); - - if (registration.botId && checkExistence) { - const botReg = await AppStudioClient.getBotRegistration(token, registration.botId); - if (botReg) { - context?.logProvider?.info(Messages.BotResourceExist("Appstudio")); - return; - } - } - - try { - const response = await RetryHandler.Retry(() => - axiosInstance.post(`${AppStudioClient.baseUrl}/api/botframework`, registration) - ); - if (!isHappyResponse(response)) { - throw new ProvisionError(CommonStrings.APP_STUDIO_BOT_REGISTRATION); - } - } catch (e) { - handleBotFrameworkError(e, APP_STUDIO_API_NAMES.CREATE_BOT); - } - - return; - } - - public static async updateMessageEndpoint( - token: string, - botId: string, - endpoint: string - ): Promise { - const botReg = await AppStudioClient.getBotRegistration(token, botId); - if (!botReg) { - throw new BotRegistrationNotFoundError(botId); - } - - botReg.messagingEndpoint = endpoint; - if (botReg.configuredChannels === undefined || botReg.configuredChannels.length === 0) { - botReg.configuredChannels = [BotChannelType.MicrosoftTeams]; - } - - await AppStudioClient.updateBotRegistration(token, botReg); - - return; - } - @hooks([ErrorContextMW({ source: "Teams", component: "AppStudioClient" })]) - public static async updateBotRegistration( - token: string, - botReg: IBotRegistration - ): Promise { - const axiosInstance = AppStudioClient.newAxiosInstance(token); - - try { - const response = await RetryHandler.Retry(() => - // eslint-disable-next-line @typescript-eslint/restrict-template-expressions - axiosInstance.post(`${AppStudioClient.baseUrl}/api/botframework/${botReg.botId}`, botReg) - ); - if (!isHappyResponse(response)) { - throw new ConfigUpdatingError(ConfigNames.MESSAGE_ENDPOINT); - } - } catch (e) { - handleBotFrameworkError(e, APP_STUDIO_API_NAMES.UPDATE_BOT); - } - - return; - } -} diff --git a/packages/fx-core/src/error/depCheck.ts b/packages/fx-core/src/error/depCheck.ts new file mode 100644 index 0000000000..38c726540d --- /dev/null +++ b/packages/fx-core/src/error/depCheck.ts @@ -0,0 +1,150 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +import { UserError, UserErrorOptions } from "@microsoft/teamsfx-api"; +import { getDefaultString, getLocalizedString } from "../common/localizeUtils"; +import { ErrorCategory } from "./types"; + +export const NodejsNotFoundHelpLink = "https://aka.ms/teamsfx-node"; +export const NodejsNotRecommendedHelpLink = "https://aka.ms/teamsfx-node"; +export const NodejsNotLtsHelpLink = "https://aka.ms/teamsfx-node"; + +export class PortsConflictError extends UserError { + constructor(ports: number[], occupiedPorts: number[], source?: string) { + const key = "error.dep.PortsConflictError"; + const errorOptions: UserErrorOptions = { + source: source || "core", + name: "PortsConflictError", + message: getDefaultString(key, ports.join(", "), occupiedPorts.join(", ")), + displayMessage: getLocalizedString(key, ports.join(", "), occupiedPorts.join(", ")), + categories: [ErrorCategory.Internal], + telemetryProperties: { + ports: ports.join(", "), + "occupied-ports": occupiedPorts.join(", "), + }, + }; + super(errorOptions); + } +} + +export class SideloadingDisabledError extends UserError { + constructor(source?: string) { + const key = "error.dep.SideloadingDisabledError"; + const errorOptions: UserErrorOptions = { + source: source || "core", + name: "SideloadingDisabledError", + message: getDefaultString(key), + displayMessage: getLocalizedString(key), + categories: [ErrorCategory.External], + }; + super(errorOptions); + } +} + +export class CopilotDisabledError extends UserError { + constructor(source?: string) { + const key = "error.dep.CopilotDisabledError"; + const errorOptions: UserErrorOptions = { + source: source || "core", + name: "CopilotDisabledError", + message: getDefaultString(key), + displayMessage: getLocalizedString(key), + categories: [ErrorCategory.External], + }; + super(errorOptions); + } +} + +export class NodejsNotLtsError extends UserError { + constructor(version: string, source?: string) { + const key = "error.dep.NodejsNotLtsError"; + const errorOptions: UserErrorOptions = { + source: source || "core", + name: "NodejsNotLtsError", + message: getDefaultString(key, version), + displayMessage: getLocalizedString(key, version), + categories: [ErrorCategory.Internal], + helpLink: NodejsNotLtsHelpLink, + telemetryProperties: { + "nodejs-version": version, + }, + }; + super(errorOptions); + } +} + +export class NodejsNotFoundError extends UserError { + constructor(source?: string) { + const key = "error.dep.NodejsNotFoundError"; + const errorOptions: UserErrorOptions = { + source: source || "core", + name: "NodejsNotFoundError", + message: getDefaultString(key), + displayMessage: getLocalizedString(key), + categories: [ErrorCategory.Internal], + helpLink: NodejsNotFoundHelpLink, + }; + super(errorOptions); + } +} + +export class NodejsNotRecommendedError extends UserError { + constructor(version: string, recommendVersion: string, source?: string) { + const key = "error.dep.NodejsNotRecommendedError"; + const errorOptions: UserErrorOptions = { + source: source || "core", + name: "NodejsNotRecommendedError", + message: getDefaultString(key, version, recommendVersion), + displayMessage: getLocalizedString(key, version, recommendVersion), + categories: [ErrorCategory.Internal], + telemetryProperties: { + "nodejs-version": version, + "nodejs-version-recommended": recommendVersion, + }, + helpLink: NodejsNotRecommendedHelpLink, + }; + super(errorOptions); + } +} + +export class VxTestAppInvalidInstallOptionsError extends UserError { + constructor(source?: string) { + const key = "error.dep.VxTestAppInvalidInstallOptionsError"; + const errorOptions: UserErrorOptions = { + source: source || "core", + name: "VxTestAppInvalidInstallOptionsError", + message: getDefaultString(key), + displayMessage: getLocalizedString(key), + categories: [ErrorCategory.Internal], + }; + super(errorOptions); + } +} + +export class VxTestAppValidationError extends UserError { + constructor(source?: string) { + const key = "error.dep.VxTestAppValidationError"; + const errorOptions: UserErrorOptions = { + source: source || "core", + name: "VxTestAppValidationError", + message: getDefaultString(key), + displayMessage: getLocalizedString(key), + categories: [ErrorCategory.Internal], + }; + super(errorOptions); + } +} + +export class DepsCheckerError extends UserError { + constructor(message: string, helpLink: string, source?: string) { + const errorOptions: UserErrorOptions = { + source: source || "core", + name: "DepsCheckerError", + message: message, + displayMessage: message, + categories: [ErrorCategory.External], + helpLink: NodejsNotRecommendedHelpLink, + }; + super(errorOptions); + } +} diff --git a/packages/fx-core/src/error/index.ts b/packages/fx-core/src/error/index.ts index b812f03d4e..e71539a5e0 100644 --- a/packages/fx-core/src/error/index.ts +++ b/packages/fx-core/src/error/index.ts @@ -1,13 +1,14 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT license. -// export * from "./yml"; export * from "./arm"; export * from "./azure"; export * from "./common"; export * from "./deploy"; export * from "./m365"; export * from "./script"; +export * from "./teamsApp"; export * from "./upgrade"; export * from "./yml"; export * from "./types"; +export * from "./depCheck"; diff --git a/packages/fx-core/src/error/teamsApp.ts b/packages/fx-core/src/error/teamsApp.ts index ad6754998d..ed00e1df90 100644 --- a/packages/fx-core/src/error/teamsApp.ts +++ b/packages/fx-core/src/error/teamsApp.ts @@ -12,9 +12,17 @@ import { ErrorCategory } from "./types"; import { Constants } from "../component/driver/teamsApp/constants"; import { matchDnsError } from "./common"; -export class DeveloperPortalAPIFailedError extends SystemError { - constructor(e: any, correlationId: string, apiName: string, extraData: string) { - const displayMessage = matchDnsError(e.message); +export class DeveloperPortalAPIFailedSystemError extends SystemError { + constructor( + e: any, + correlationId: string, + apiName: string, + extraData: string, + displayMessage?: string + ) { + if (!displayMessage) { + displayMessage = matchDnsError(e.message); + } const errorOptions: SystemErrorOptions = { source: Constants.PLUGIN_NAME, error: e, @@ -34,6 +42,35 @@ export class DeveloperPortalAPIFailedError extends SystemError { } } +export class DeveloperPortalAPIFailedUserError extends UserError { + constructor( + e: any, + correlationId: string, + apiName: string, + extraData: string, + displayMessage?: string, + helpLink?: string + ) { + const errorOptions: UserErrorOptions = { + source: Constants.PLUGIN_NAME, + error: e, + message: getDefaultString( + // github issue workflow uses this template for matching. Please send a heads-up to the owner of workflows if you want to change it. + "error.appstudio.apiFailed.telemetry", + e.name, + e.message, + apiName, + correlationId, + extraData + ), + displayMessage: displayMessage || getLocalizedString("error.appstudio.apiFailed"), + categories: [ErrorCategory.Unhandled, apiName], + helpLink: helpLink, + }; + super(errorOptions); + } +} + export class CheckSideloadingPermissionFailedError extends SystemError { constructor(e: any, correlationId: string, apiName: string, extraData: string) { const errorOptions: SystemErrorOptions = { diff --git a/packages/fx-core/src/index.ts b/packages/fx-core/src/index.ts index eda2caa269..b7c7b57eb4 100644 --- a/packages/fx-core/src/index.ts +++ b/packages/fx-core/src/index.ts @@ -67,7 +67,6 @@ export { export { CoreDepsLoggerAdapter } from "./component/deps-checker/coreDepsLoggerAdapter"; export { CoreDepsTelemetryAdapter } from "./component/deps-checker/coreDepsTelemetryAdapter"; export * from "./component/deps-checker/depsChecker"; -export * from "./component/deps-checker/depsError"; export { DepsLogger, EmptyLogger } from "./component/deps-checker/depsLogger"; export { DepsManager } from "./component/deps-checker/depsManager"; export { DepsTelemetry, EmptyTelemetry } from "./component/deps-checker/depsTelemetry"; diff --git a/packages/fx-core/tests/client/tdpClient.test.ts b/packages/fx-core/tests/client/tdpClient.test.ts index e75217b24a..15a32326fe 100644 --- a/packages/fx-core/tests/client/tdpClient.test.ts +++ b/packages/fx-core/tests/client/tdpClient.test.ts @@ -32,9 +32,14 @@ import { AppStudioResultFactory } from "../../src/component/driver/teamsApp/resu import { manifestUtils } from "../../src/component/driver/teamsApp/utils/ManifestUtils"; import { IBotRegistration } from "../../src/component/resource/botService/appStudio/interfaces/IBotRegistration"; import { ErrorNames } from "../../src/component/resource/botService/constants"; -import { DeveloperPortalAPIFailedError } from "../../src/error/teamsApp"; +import { + DeveloperPortalAPIFailedSystemError, + DeveloperPortalAPIFailedUserError, +} from "../../src/error/teamsApp"; import { Messages } from "../component/resource/botService/messages"; import { MockTools } from "../core/utils"; +import { getDefaultString } from "../../src/common/localizeUtils"; +import { HelpLinks } from "../../src/common/constants"; describe("TeamsDevPortalClient Test", () => { const tools = new MockTools(); @@ -134,6 +139,17 @@ describe("TeamsDevPortalClient Test", () => { const res = await teamsDevPortalClient.publishTeamsApp(token, "fakeId", Buffer.from("")); chai.assert.equal(res, response.data.id); }); + it("return undefined response", async () => { + const fakeAxiosInstance = axios.create(); + sandbox.stub(axios, "create").returns(fakeAxiosInstance); + sandbox.stub(fakeAxiosInstance, "post").resolves(undefined); + try { + await teamsDevPortalClient.publishTeamsApp(token, "fakeId", Buffer.from("")); + } catch (e) { + chai.assert.equal(e.name, DeveloperPortalAPIFailedSystemError.name); + chai.assert.isTrue(e.message.includes(AppStudioError.TeamsAppPublishFailedError.name)); + } + }); it("return no data", async () => { const fakeAxiosInstance = axios.create(); sandbox.stub(axios, "create").returns(fakeAxiosInstance); @@ -142,7 +158,26 @@ describe("TeamsDevPortalClient Test", () => { try { await teamsDevPortalClient.publishTeamsApp(token, "fakeId", Buffer.from("")); } catch (e) { - chai.assert.equal(e.name, AppStudioError.TeamsAppPublishFailedError.name); + chai.assert.equal(e.name, DeveloperPortalAPIFailedSystemError.name); + chai.assert.isTrue(e.message.includes(AppStudioError.TeamsAppPublishFailedError.name)); + } + }); + it("return no data with correlation id", async () => { + const fakeAxiosInstance = axios.create(); + sandbox.stub(axios, "create").returns(fakeAxiosInstance); + const xCorrelationId = "fakeCorrelationId"; + const response = { + headers: { + "x-correlation-id": xCorrelationId, + }, + }; + sandbox.stub(fakeAxiosInstance, "post").resolves(response); + try { + await teamsDevPortalClient.publishTeamsApp(token, "fakeId", Buffer.from("")); + } catch (e) { + chai.assert.equal(e.name, DeveloperPortalAPIFailedSystemError.name); + chai.assert.isTrue(e.message.includes(AppStudioError.TeamsAppPublishFailedError.name)); + chai.assert.isTrue(e.message.includes(xCorrelationId)); } }); it("API Failure", async () => { @@ -158,7 +193,7 @@ describe("TeamsDevPortalClient Test", () => { try { await teamsDevPortalClient.publishTeamsApp(token, "fakeId", Buffer.from("")); } catch (error) { - chai.assert.equal(error.name, DeveloperPortalAPIFailedError.name); + chai.assert.equal(error.name, DeveloperPortalAPIFailedSystemError.name); } }); @@ -181,7 +216,7 @@ describe("TeamsDevPortalClient Test", () => { try { await teamsDevPortalClient.publishTeamsApp(token, "fakeId", Buffer.from("")); } catch (error) { - chai.assert.equal(error.name, DeveloperPortalAPIFailedError.name); + chai.assert.equal(error.name, DeveloperPortalAPIFailedSystemError.name); chai.assert.include(error.message, xCorrelationId); } }); @@ -293,7 +328,10 @@ describe("TeamsDevPortalClient Test", () => { try { await teamsDevPortalClient.publishTeamsApp(token, "fakeId", Buffer.from("")); } catch (error) { - chai.assert.equal(error.name, AppStudioError.TeamsAppPublishConflictError.name); + chai.assert.equal(error.name, DeveloperPortalAPIFailedSystemError.name); + chai.assert.isTrue( + error.message.includes(AppStudioError.TeamsAppPublishConflictError.name) + ); } }); }); @@ -341,7 +379,9 @@ describe("TeamsDevPortalClient Test", () => { try { await teamsDevPortalClient.importApp(token, Buffer.from("")); } catch (error) { - chai.assert.equal(error.name, AppStudioError.TeamsAppCreateConflictError.name); + chai.assert.equal(error.name, DeveloperPortalAPIFailedUserError.name); + chai.assert.isTrue(error.message.includes(AppStudioError.TeamsAppCreateConflictError.name)); + chai.assert.equal(error.helpLink, HelpLinks.SwitchTenant); } }); @@ -360,9 +400,34 @@ describe("TeamsDevPortalClient Test", () => { try { await teamsDevPortalClient.importApp(token, Buffer.from("")); } catch (error) { - chai.assert.equal( - error.name, - AppStudioError.TeamsAppCreateConflictWithPublishedAppError.name + chai.assert.equal(error.name, DeveloperPortalAPIFailedUserError.name); + chai.assert.isTrue( + error.message.includes(AppStudioError.TeamsAppCreateConflictWithPublishedAppError.name) + ); + } + }); + + it("422 conflict with unknown data", async () => { + const fakeAxiosInstance = axios.create(); + sandbox.stub(axios, "create").returns(fakeAxiosInstance); + + const error = { + response: { + status: 422, + data: "Unknown", + }, + }; + sandbox.stub(fakeAxiosInstance, "post").throws(error); + + try { + await teamsDevPortalClient.importApp(token, Buffer.from("")); + } catch (error) { + chai.assert.equal(error.name, DeveloperPortalAPIFailedSystemError.name); + chai.assert.isFalse( + error.message.includes(AppStudioError.TeamsAppCreateConflictWithPublishedAppError.name) + ); + chai.assert.isTrue( + error.message.includes(getDefaultString("error.appstudio.apiFailed.name.common")) ); } }); @@ -385,7 +450,7 @@ describe("TeamsDevPortalClient Test", () => { try { await teamsDevPortalClient.importApp(token, Buffer.from("")); } catch (error) { - chai.assert.equal(error.name, DeveloperPortalAPIFailedError.name); + chai.assert.equal(error.name, DeveloperPortalAPIFailedSystemError.name); } }); @@ -407,7 +472,8 @@ describe("TeamsDevPortalClient Test", () => { try { await teamsDevPortalClient.importApp(token, Buffer.from("")); } catch (error) { - chai.assert.equal(error.name, AppStudioError.InvalidTeamsAppIdError.name); + chai.assert.equal(error.name, DeveloperPortalAPIFailedUserError.name); + chai.assert.isTrue(error.message.includes(AppStudioError.InvalidTeamsAppIdError.name)); } }); @@ -456,7 +522,7 @@ describe("TeamsDevPortalClient Test", () => { try { await teamsDevPortalClient.importApp(token, Buffer.from("")); } catch (error) { - chai.assert.equal(error.name, DeveloperPortalAPIFailedError.name); + chai.assert.equal(error.name, DeveloperPortalAPIFailedSystemError.name); } }); @@ -474,7 +540,7 @@ describe("TeamsDevPortalClient Test", () => { try { await teamsDevPortalClient.importApp(token, Buffer.from("")); } catch (error) { - chai.assert.equal(error.name, DeveloperPortalAPIFailedError.name); + chai.assert.equal(error.name, DeveloperPortalAPIFailedSystemError.name); } }); }); @@ -506,7 +572,7 @@ describe("TeamsDevPortalClient Test", () => { try { await teamsDevPortalClient.getApp(token, appDef.teamsAppId!); } catch (error) { - chai.assert.equal(error.name, DeveloperPortalAPIFailedError.name); + chai.assert.equal(error.name, DeveloperPortalAPIFailedSystemError.name); } }); @@ -528,7 +594,7 @@ describe("TeamsDevPortalClient Test", () => { try { await teamsDevPortalClient.getApp(token, appDef.teamsAppId!); } catch (error) { - chai.assert.equal(error.name, DeveloperPortalAPIFailedError.name); + chai.assert.equal(error.name, DeveloperPortalAPIFailedSystemError.name); } finally { teamsDevPortalClient.setRegionEndpoint(undefined as unknown as string); } @@ -545,7 +611,7 @@ describe("TeamsDevPortalClient Test", () => { try { await teamsDevPortalClient.getApp(token, "anotherId"); } catch (e) { - chai.assert.isTrue(e.message.includes("Cannot get the app definition with app ID")); + chai.assert.isTrue(e.message.includes("cannot get the app definition with app ID")); } }); }); @@ -613,7 +679,7 @@ describe("TeamsDevPortalClient Test", () => { try { await teamsDevPortalClient.getAppPackage(token, appDef.teamsAppId!); } catch (error) { - chai.assert.equal(error.name, DeveloperPortalAPIFailedError.name); + chai.assert.equal(error.name, DeveloperPortalAPIFailedSystemError.name); } }); @@ -627,7 +693,7 @@ describe("TeamsDevPortalClient Test", () => { try { await teamsDevPortalClient.getAppPackage(token, appDef.teamsAppId!); } catch (e) { - chai.assert.isTrue(e instanceof DeveloperPortalAPIFailedError); + chai.assert.isTrue(e instanceof DeveloperPortalAPIFailedSystemError); } }); }); @@ -673,7 +739,7 @@ describe("TeamsDevPortalClient Test", () => { try { await teamsDevPortalClient.partnerCenterAppPackageValidation(token, Buffer.from("")); } catch (error) { - chai.assert.equal(error.name, DeveloperPortalAPIFailedError.name); + chai.assert.equal(error.name, DeveloperPortalAPIFailedSystemError.name); } }); }); @@ -716,7 +782,7 @@ describe("TeamsDevPortalClient Test", () => { try { await teamsDevPortalClient.checkExistsInTenant(token, appDef.teamsAppId!); } catch (error) { - chai.assert.equal(error.name, DeveloperPortalAPIFailedError.name); + chai.assert.equal(error.name, DeveloperPortalAPIFailedSystemError.name); } }); }); @@ -820,7 +886,7 @@ describe("TeamsDevPortalClient Test", () => { try { await teamsDevPortalClient.publishTeamsAppUpdate(token, "", Buffer.from("")); } catch (error) { - chai.assert.equal(error.name, DeveloperPortalAPIFailedError.name); + chai.assert.equal(error.name, DeveloperPortalAPIFailedSystemError.name); } }); }); @@ -855,7 +921,7 @@ describe("TeamsDevPortalClient Test", () => { try { await teamsDevPortalClient.grantPermission(token, appDef.teamsAppId!, appUser); } catch (e) { - chai.assert.isTrue(e instanceof DeveloperPortalAPIFailedError); + chai.assert.isTrue(e instanceof DeveloperPortalAPIFailedSystemError); } }); it("response no data", async () => { @@ -1010,7 +1076,7 @@ describe("TeamsDevPortalClient Test", () => { try { await teamsDevPortalClient.getApiKeyRegistrationById(token, "fakeId"); } catch (error) { - chai.assert.equal(error.name, DeveloperPortalAPIFailedError.name); + chai.assert.equal(error.name, DeveloperPortalAPIFailedSystemError.name); } }); @@ -1064,7 +1130,7 @@ describe("TeamsDevPortalClient Test", () => { try { await teamsDevPortalClient.createApiKeyRegistration(token, appApiRegistration); } catch (error) { - chai.assert.equal(error.name, DeveloperPortalAPIFailedError.name); + chai.assert.equal(error.name, DeveloperPortalAPIFailedSystemError.name); } }); }); @@ -1088,7 +1154,7 @@ describe("TeamsDevPortalClient Test", () => { try { await teamsDevPortalClient.updateApiKeyRegistration(token, appApiRegistration, "fakeId"); } catch (error) { - chai.assert.equal(error.name, DeveloperPortalAPIFailedError.name); + chai.assert.equal(error.name, DeveloperPortalAPIFailedSystemError.name); } }); @@ -1150,7 +1216,7 @@ describe("TeamsDevPortalClient Test", () => { try { await teamsDevPortalClient.createOauthRegistration(token, fakeOauthRegistration); } catch (error) { - chai.assert.equal(error.name, DeveloperPortalAPIFailedError.name); + chai.assert.equal(error.name, DeveloperPortalAPIFailedSystemError.name); } }); }); @@ -1182,7 +1248,7 @@ describe("TeamsDevPortalClient Test", () => { try { await teamsDevPortalClient.getOauthRegistrationById(token, "fakeId"); } catch (error) { - chai.assert.equal(error.name, DeveloperPortalAPIFailedError.name); + chai.assert.equal(error.name, DeveloperPortalAPIFailedSystemError.name); } }); }); @@ -1218,7 +1284,7 @@ describe("TeamsDevPortalClient Test", () => { try { await teamsDevPortalClient.updateOauthRegistration(token, fakeOauthRegistration, "fakeId"); } catch (error) { - chai.assert.equal(error.name, DeveloperPortalAPIFailedError.name); + chai.assert.equal(error.name, DeveloperPortalAPIFailedSystemError.name); } }); }); @@ -1261,7 +1327,7 @@ describe("TeamsDevPortalClient Test", () => { await teamsDevPortalClient.listApps(token); chai.assert.fail("should throw error"); } catch (e) { - chai.assert.isTrue(e instanceof DeveloperPortalAPIFailedError); + chai.assert.isTrue(e instanceof DeveloperPortalAPIFailedSystemError); } }); it("Error - no data", async () => { @@ -1277,7 +1343,11 @@ describe("TeamsDevPortalClient Test", () => { await teamsDevPortalClient.listApps(token); chai.assert.fail("should throw error"); } catch (e) { - chai.assert.equal(e.message, "Cannot get the app definitions"); + chai.assert.isTrue( + e.message.includes( + "Unable to make API call to Developer Portal: API failed, cannot get the app definitions, API name: list-app, X-Correlation-ID: undefined. This may be due to a temporary service error. Try again after a few minutes." + ) + ); } }); }); @@ -1319,7 +1389,7 @@ describe("TeamsDevPortalClient Test", () => { await teamsDevPortalClient.deleteApp(token, "testid"); chai.assert.fail("should throw error"); } catch (e) { - chai.assert.isTrue(e instanceof DeveloperPortalAPIFailedError); + chai.assert.isTrue(e instanceof DeveloperPortalAPIFailedSystemError); } }); it("Error - no data", async () => { @@ -1335,7 +1405,7 @@ describe("TeamsDevPortalClient Test", () => { await teamsDevPortalClient.deleteApp(token, "testid"); chai.assert.fail("should throw error"); } catch (e) { - chai.assert.equal(e.message, "Cannot delete the app: " + "testid"); + chai.assert.isTrue(e.message.includes("cannot delete the app: " + "testid")); } }); }); @@ -1384,7 +1454,7 @@ describe("TeamsDevPortalClient Test", () => { try { await teamsDevPortalClient.submitAppValidationRequest(token, "fakeId"); } catch (error) { - chai.assert.equal(error.name, DeveloperPortalAPIFailedError.name); + chai.assert.equal(error.name, DeveloperPortalAPIFailedSystemError.name); } }); }); @@ -1428,7 +1498,7 @@ describe("TeamsDevPortalClient Test", () => { try { await teamsDevPortalClient.getAppValidationRequestList(token, "fakeId"); } catch (error) { - chai.assert.equal(error.name, DeveloperPortalAPIFailedError.name); + chai.assert.equal(error.name, DeveloperPortalAPIFailedSystemError.name); } }); @@ -1445,7 +1515,7 @@ describe("TeamsDevPortalClient Test", () => { try { await teamsDevPortalClient.getAppValidationById(token, "fakeId"); } catch (error) { - chai.assert.equal(error.name, DeveloperPortalAPIFailedError.name); + chai.assert.equal(error.name, DeveloperPortalAPIFailedSystemError.name); } }); }); @@ -1517,7 +1587,7 @@ describe("TeamsDevPortalClient Test", () => { await teamsDevPortalClient.getBotRegistration("anything", "anything"); chai.assert.fail(Messages.ShouldNotReachHere); } catch (e) { - chai.assert.isTrue(e.name === DeveloperPortalAPIFailedError.name); + chai.assert.isTrue(e.name === DeveloperPortalAPIFailedSystemError.name); } }); }); @@ -1634,7 +1704,7 @@ describe("TeamsDevPortalClient Test", () => { await teamsDevPortalClient.createBotRegistration("anything", sampleBot); chai.assert.fail(Messages.ShouldNotReachHere); } catch (e) { - chai.assert.isTrue(e.name === DeveloperPortalAPIFailedError.name); + chai.assert.isTrue(e.name === DeveloperPortalAPIFailedSystemError.name); } }); }); @@ -1734,7 +1804,7 @@ describe("TeamsDevPortalClient Test", () => { await teamsDevPortalClient.updateBotRegistration("anything", sampleBot); chai.assert.fail(Messages.ShouldNotReachHere); } catch (e) { - chai.assert.isTrue(e.name === DeveloperPortalAPIFailedError.name); + chai.assert.isTrue(e.name === DeveloperPortalAPIFailedSystemError.name); } }); }); @@ -1812,7 +1882,7 @@ describe("TeamsDevPortalClient Test", () => { await teamsDevPortalClient.listBots("anything"); chai.assert.fail(Messages.ShouldNotReachHere); } catch (e) { - chai.assert.isTrue(e instanceof DeveloperPortalAPIFailedError); + chai.assert.isTrue(e instanceof DeveloperPortalAPIFailedSystemError); } }); }); diff --git a/packages/fx-core/tests/common/telemetry.test.ts b/packages/fx-core/tests/common/telemetry.test.ts index 0274c1543e..f63454ac70 100644 --- a/packages/fx-core/tests/common/telemetry.test.ts +++ b/packages/fx-core/tests/common/telemetry.test.ts @@ -56,7 +56,11 @@ describe("telemetry", () => { it("happy path", async () => { const props: any = {}; const error = new Error("error message"); - telemetryUtils.fillInErrorProperties(props, new ScriptExecutionError(error, "test")); + const fxError = new ScriptExecutionError(error, "test"); + fxError.telemetryProperties = { + k1: "v1", + }; + telemetryUtils.fillInErrorProperties(props, fxError); assert.equal( props[TelemetryProperty.ErrorData], maskSecret(JSON.stringify(error, Object.getOwnPropertyNames(error)), { replace: "***" }) diff --git a/packages/fx-core/tests/component/coordinator/coordinator.create.test.ts b/packages/fx-core/tests/component/coordinator/coordinator.create.test.ts index a422adb8c3..96472fca49 100644 --- a/packages/fx-core/tests/component/coordinator/coordinator.create.test.ts +++ b/packages/fx-core/tests/component/coordinator/coordinator.create.test.ts @@ -34,6 +34,7 @@ import { MockTools, randomAppName } from "../../core/utils"; import { MockedUserInteraction } from "../../plugins/solution/util"; import mockedEnv, { RestoreFn } from "mocked-env"; import { FeatureFlagName } from "../../../src/common/featureFlags"; +import { manifestUtils } from "../../../src/component/driver/teamsApp/utils/ManifestUtils"; describe("coordinator create", () => { const sandbox = sinon.createSandbox(); @@ -43,6 +44,7 @@ describe("coordinator create", () => { let mockedEnvRestore: RestoreFn; beforeEach(() => { sandbox.stub(fs, "ensureDir").resolves(); + sandbox.stub(manifestUtils, "trimManifestShortName").resolves(ok(undefined)); generator = sandbox .stub(DefaultTemplateGenerator.prototype, "scaffolding") .resolves(ok(undefined)); diff --git a/packages/fx-core/tests/component/deps-checker/funcToolChecker.test.ts b/packages/fx-core/tests/component/deps-checker/funcToolChecker.test.ts index 72ae9e1cc3..09132fc8b7 100644 --- a/packages/fx-core/tests/component/deps-checker/funcToolChecker.test.ts +++ b/packages/fx-core/tests/component/deps-checker/funcToolChecker.test.ts @@ -19,6 +19,7 @@ import { v3NodeNotFoundHelpLink, } from "../../../src/component/deps-checker/constant/helpLink"; import { DebugLogger, cpUtils } from "../../../src/component/deps-checker/util/cpUtils"; +import { DepsCheckerError, NodejsNotFoundError } from "../../../src/error"; describe("Func Tools Checker Test", () => { const sandbox = sinon.createSandbox(); @@ -523,7 +524,11 @@ describe("Func Tools Checker Test", () => { symlinkDir: "./devTools/func", }); delete res["telemetryProperties"]; + const error = res.error; + delete res.error; + delete failedResult.error; chai.assert.equal(JSON.stringify(res), JSON.stringify(failedResult)); + chai.assert.isTrue(error instanceof DepsCheckerError); chai.assert.isFalse(await fs.pathExists(path.resolve(mock.projectDir, "./devTools/func"))); // The data has been cleaned. const files = await fs.readdir(path.resolve(mock.homeDir, "./.fx/bin/azfunc"), { @@ -550,6 +555,8 @@ describe("Func Tools Checker Test", () => { symlinkDir: "./devTools/func", }); delete res["telemetryProperties"]; + const error = res.error; + delete res.error; chai.assert.equal( JSON.stringify(res), JSON.stringify({ @@ -563,11 +570,9 @@ describe("Func Tools Checker Test", () => { supportedVersions: [], binFolders: undefined, }, - error: { - helpLink: v3NodeNotFoundHelpLink, - }, }) ); + chai.assert.isTrue(error instanceof NodejsNotFoundError); }); it(`failed to find npm`, async () => { @@ -587,8 +592,11 @@ describe("Func Tools Checker Test", () => { symlinkDir: "./devTools/func", }); delete res["telemetryProperties"]; - + const error = res.error; + delete res.error; + delete failedResult.error; chai.assert.equal(JSON.stringify(res), JSON.stringify(failedResult)); + chai.assert.isTrue(error instanceof DepsCheckerError); }); it(`throw error in linux`, async () => { @@ -600,7 +608,8 @@ describe("Func Tools Checker Test", () => { symlinkDir: "./devTools/func", }); delete res["telemetryProperties"]; - + delete res.error; + delete failedResult.error; chai.assert.equal(JSON.stringify(res), JSON.stringify(failedResult)); }); @@ -657,7 +666,8 @@ describe("Func Tools Checker Test", () => { symlinkDir: "./devtools/func", }); delete res["telemetryProperties"]; - + delete res.error; + delete failedResult.error; chai.assert.equal(JSON.stringify(res), JSON.stringify(failedResult)); }); @@ -783,7 +793,8 @@ describe("Func Tools Checker Test", () => { symlinkDir: "./devtools/func", }); delete res["telemetryProperties"]; - + delete res.error; + delete failedResult.error; chai.assert.equal(JSON.stringify(res), JSON.stringify(failedResult)); }); @@ -870,7 +881,7 @@ describe("Func Tools Checker Test", () => { symlinkDir: "./devTools/func", }); delete res["telemetryProperties"]; - + delete res.error; chai.assert.equal( JSON.stringify(res), JSON.stringify({ @@ -884,7 +895,6 @@ describe("Func Tools Checker Test", () => { supportedVersions: [], binFolders: [path.resolve(mock.projectDir, "./devTools/func")], }, - error: nodeVersionValidationData.isSuccess ? undefined : { helpLink: v3DefaultHelpLink }, }) ); const stat = await fs.lstat(res.details.binFolders[0]); @@ -899,7 +909,7 @@ describe("Func Tools Checker Test", () => { }); }); - const failedResult = { + const failedResult: any = { name: "Azure Functions Core Tools", type: "func-core-tools", isInstalled: false, diff --git a/packages/fx-core/tests/component/deps-checker/testToolChecker.test.ts b/packages/fx-core/tests/component/deps-checker/testToolChecker.test.ts index da2e10a6dc..6dec2c0094 100644 --- a/packages/fx-core/tests/component/deps-checker/testToolChecker.test.ts +++ b/packages/fx-core/tests/component/deps-checker/testToolChecker.test.ts @@ -14,7 +14,6 @@ import * as sinon from "sinon"; import * as url from "url"; import { TelemetryProperties } from "../../../src/component/deps-checker/constant/telemetry"; import { TestToolReleaseType } from "../../../src/component/deps-checker/depsChecker"; -import { DepsCheckerError } from "../../../src/component/deps-checker/depsError"; import { GitHubHelpers, TestToolChecker, @@ -22,6 +21,7 @@ import { import { cpUtils } from "../../../src/component/deps-checker/util/cpUtils"; import * as downloadHelper from "../../../src/component/deps-checker/util/downloadHelper"; import * as fileHelper from "../../../src/component/deps-checker/util/fileHelper"; +import { DepsCheckerError, NodejsNotFoundError } from "../../../src/error/depCheck"; function isAncesterDir(parent: string, dir: string) { const relative = path.relative(parent, dir); @@ -519,7 +519,7 @@ describe("Test Tool Checker Test (npm version)", () => { // Assert expect(status.isInstalled).to.be.false; expect(status.details.binFolders).to.be.empty; - expect(status.error).instanceOf(DepsCheckerError); + expect(status.error).instanceOf(NodejsNotFoundError); expect(status.telemetryProperties?.[TelemetryProperties.InstallTestToolReleaseType]).to.eq( TestToolReleaseType.Npm ); @@ -604,7 +604,7 @@ describe("Test Tool Checker Test (npm version)", () => { // Assert expect(status.isInstalled).to.be.false; expect(status.details.binFolders).to.be.empty; - expect(status.error).instanceOf(DepsCheckerError); + expect(status.error).instanceOf(NodejsNotFoundError); expect(status.telemetryProperties?.[TelemetryProperties.InstallTestToolReleaseType]).to.eq( TestToolReleaseType.Npm ); diff --git a/packages/fx-core/tests/component/driver/devTool/installDriver.test.ts b/packages/fx-core/tests/component/driver/devTool/installDriver.test.ts index 3fdff125a1..d929cf27fe 100644 --- a/packages/fx-core/tests/component/driver/devTool/installDriver.test.ts +++ b/packages/fx-core/tests/component/driver/devTool/installDriver.test.ts @@ -6,14 +6,13 @@ import chai from "chai"; import "mocha"; import * as sinon from "sinon"; import { DepsType } from "../../../../src/component/deps-checker/depsChecker"; -import { DepsCheckerError } from "../../../../src/component/deps-checker/depsError"; import { DotnetChecker } from "../../../../src/component/deps-checker/internal/dotnetChecker"; import { FuncToolChecker } from "../../../../src/component/deps-checker/internal/funcToolChecker"; import { TestToolChecker } from "../../../../src/component/deps-checker/internal/testToolChecker"; import { ToolsInstallDriver } from "../../../../src/component/driver/devTool/installDriver"; import { InstallToolArgs } from "../../../../src/component/driver/devTool/interfaces/InstallToolArgs"; import { LocalCertificateManager } from "../../../../src/component/local/localCertificateManager"; -import { CoreSource } from "../../../../src/error"; +import { CoreSource, DepsCheckerError } from "../../../../src/error"; import { MockedLogProvider, MockedUserInteraction } from "../../../plugins/solution/util"; describe("Tools Install Driver test", () => { diff --git a/packages/fx-core/tests/component/driver/oauth/update.test.ts b/packages/fx-core/tests/component/driver/oauth/update.test.ts index 3278dabc8d..fc0ce4a086 100644 --- a/packages/fx-core/tests/component/driver/oauth/update.test.ts +++ b/packages/fx-core/tests/component/driver/oauth/update.test.ts @@ -117,6 +117,7 @@ describe("CreateOauthDriver", () => { authorizationCode: { authorizationUrl: "https://test", tokenUrl: "https://test", + refreshUrl: "https://test", scopes: { mockedScopes: "mockedScopes", }, @@ -137,6 +138,10 @@ describe("CreateOauthDriver", () => { expect((config as ConfirmConfig).title.includes("m365AppId")).to.be.true; expect((config as ConfirmConfig).title.includes("targetAudience")).to.be.true; expect((config as ConfirmConfig).title.includes("isPKCEEnabled")).to.be.true; + expect((config as ConfirmConfig).title.includes("authorizationEndpoint")).to.be.true; + expect((config as ConfirmConfig).title.includes("tokenExchangeEndpoint")).to.be.true; + expect((config as ConfirmConfig).title.includes("tokenRefreshEndpoint")).to.be.true; + expect((config as ConfirmConfig).title.includes("scopes")).to.be.true; return ok({ type: "success", value: true }); }); @@ -251,7 +256,7 @@ describe("CreateOauthDriver", () => { clientSecret: "mockedClientSecret", authorizationEndpoint: "mockedAuthorizationEndpoint", tokenExchangeEndpoint: "mockedTokenExchangeEndpoint", - scopes: ["mockedScope"], + scopes: ["mockedScopes"], }); sinon.stub(SpecParser.prototype, "list").resolves({ APIs: [ @@ -265,8 +270,8 @@ describe("CreateOauthDriver", () => { type: "oauth2", flows: { authorizationCode: { - authorizationUrl: "https://test", - tokenUrl: "https://test", + authorizationUrl: "mockedAuthorizationEndpoint", + tokenUrl: "mockedTokenExchangeEndpoint", scopes: { mockedScopes: "mockedScopes", }, @@ -290,7 +295,7 @@ describe("CreateOauthDriver", () => { authorizationUrl: "https://test", tokenUrl: "https://test", scopes: { - mockedScopes: "mockedScopes", + mockedScopes: "mockedScope", }, }, }, @@ -344,7 +349,7 @@ describe("CreateOauthDriver", () => { clientSecret: "mockedClientSecret", authorizationEndpoint: "mockedAuthorizationEndpoint", tokenExchangeEndpoint: "mockedTokenExchangeEndpoint", - scopes: ["mockedScope"], + scopes: ["mockedScopes"], }); sinon.stub(SpecParser.prototype, "list").resolves({ APIs: [ @@ -358,8 +363,8 @@ describe("CreateOauthDriver", () => { type: "oauth2", flows: { authorizationCode: { - authorizationUrl: "https://test", - tokenUrl: "https://test", + authorizationUrl: "mockedAuthorizationEndpoint", + tokenUrl: "mockedTokenExchangeEndpoint", scopes: { mockedScopes: "mockedScopes", }, @@ -684,4 +689,111 @@ describe("CreateOauthDriver", () => { expect(result.result.error.source).to.equal("oauthUpdate"); } }); + + it("should update if tokenRefreshEndpoint and scopes are undefined", async () => { + sinon.stub(teamsDevPortalClient, "updateOauthRegistration").resolves({ + description: "mockedDescription", + targetUrlsShouldStartWith: ["https://test2"], + applicableToApps: OauthRegistrationAppType.SpecificApp, + targetAudience: OauthRegistrationTargetAudience.HomeTenant, + m365AppId: "mockedAppId", + clientId: "mockedClientId", + clientSecret: "mockedClientSecret", + authorizationEndpoint: "mockedAuthorizationEndpoint", + tokenExchangeEndpoint: "mockedTokenExchangeEndpoint", + scopes: ["mockedScope"], + isPKCEEnabled: true, + }); + sinon.stub(teamsDevPortalClient, "getOauthRegistrationById").resolves({ + oAuthConfigId: "mockedRegistrationId", + description: "mockedDescription", + targetUrlsShouldStartWith: ["https://test"], + applicableToApps: OauthRegistrationAppType.AnyApp, + targetAudience: OauthRegistrationTargetAudience.AnyTenant, + clientId: "mockedClientId", + clientSecret: "mockedClientSecret", + authorizationEndpoint: "mockedAuthorizationEndpoint", + tokenExchangeEndpoint: "mockedTokenExchangeEndpoint", + tokenRefreshEndpoint: "mockedTokenRefreshEndpoint", + scopes: ["mockedScope"], + isPKCEEnabled: false, + }); + sinon.stub(SpecParser.prototype, "list").resolves({ + APIs: [ + { + api: "api", + server: "https://test", + operationId: "get", + auth: { + name: "test", + authScheme: { + type: "oauth2", + flows: { + authorizationCode: { + authorizationUrl: "https://test", + tokenUrl: "https://test", + scopes: { + mockedScopes: "mockedScopes", + }, + }, + }, + }, + }, + isValid: true, + reason: [], + }, + { + api: "api2", + server: "https://test", + operationId: "get", + auth: { + name: "test2", + authScheme: { + type: "oauth2", + flows: { + authorizationCode: { + authorizationUrl: "https://test", + tokenUrl: "https://test", + scopes: {}, + }, + }, + }, + }, + isValid: true, + reason: [], + }, + ], + allAPICount: 1, + validAPICount: 1, + }); + sinon.stub(mockedDriverContext.ui, "confirm").callsFake(async (config) => { + expect((config as ConfirmConfig).title.includes("description")).to.be.true; + expect((config as ConfirmConfig).title.includes("applicableToApps")).to.be.true; + expect((config as ConfirmConfig).title.includes("m365AppId")).to.be.true; + expect((config as ConfirmConfig).title.includes("targetAudience")).to.be.true; + expect((config as ConfirmConfig).title.includes("isPKCEEnabled")).to.be.true; + expect((config as ConfirmConfig).title.includes("authorizationEndpoint")).to.be.true; + expect((config as ConfirmConfig).title.includes("tokenExchangeEndpoint")).to.be.true; + expect((config as ConfirmConfig).title.includes("tokenRefreshEndpoint")).to.be.true; + expect((config as ConfirmConfig).title.includes("scopes")).to.be.true; + return ok({ type: "success", value: true }); + }); + + const args: UpdateOauthArgs = { + name: "test2", + appId: "mockedAppId", + apiSpecPath: "mockedPath", + targetAudience: "HomeTenant", + applicableToApps: "SpecificApp", + configurationId: "mockedRegistrationId", + isPKCEEnabled: true, + }; + + const result = await updateOauthDriver.execute(args, mockedDriverContext); + expect(result.result.isOk()).to.be.true; + if (result.result.isOk()) { + expect(result.result.value.size).to.equal(0); + expect(result.summaries.length).to.equal(1); + } + }); }); diff --git a/packages/fx-core/tests/component/driver/teamsApp/appstudioclient.test.ts b/packages/fx-core/tests/component/driver/teamsApp/appstudioclient.test.ts deleted file mode 100644 index 881e82e9f0..0000000000 --- a/packages/fx-core/tests/component/driver/teamsApp/appstudioclient.test.ts +++ /dev/null @@ -1,1328 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. - -import "mocha"; -import * as chai from "chai"; -import * as sinon from "sinon"; -import axios from "axios"; -import { v4 as uuid } from "uuid"; -import { TeamsAppManifest, ok, err } from "@microsoft/teamsfx-api"; -import { AppStudioClient } from "../../../../src/component/driver/teamsApp/clients/appStudioClient"; -import { AppDefinition } from "../../../../src/component/driver/teamsApp/interfaces/appdefinitions/appDefinition"; -import { AppUser } from "../../../../src/component/driver/teamsApp/interfaces/appdefinitions/appUser"; -import { AppStudioError } from "../../../../src/component/driver/teamsApp/errors"; -import { RetryHandler } from "../../../../src/component/driver/teamsApp/utils/utils"; -import { PublishingState } from "../../../../src/component/driver/teamsApp/interfaces/appdefinitions/IPublishingAppDefinition"; -import { manifestUtils } from "../../../../src/component/driver/teamsApp/utils/ManifestUtils"; -import { AppStudioResultFactory } from "../../../../src/component/driver/teamsApp/results"; -import { Constants } from "../../../../src/component/driver/teamsApp/constants"; -import { MockedLogProvider } from "../../../plugins/solution/util"; -import { DeveloperPortalAPIFailedError } from "../../../../src/error/teamsApp"; -import { - ApiSecretRegistration, - ApiSecretRegistrationAppType, - ApiSecretRegistrationUpdate, -} from "../../../../src/component/driver/teamsApp/interfaces/ApiSecretRegistration"; -import { AsyncAppValidationStatus } from "../../../../src/component/driver/teamsApp/interfaces/AsyncAppValidationResponse"; -import { - OauthRegistration, - OauthRegistrationAppType, - OauthRegistrationTargetAudience, - OauthRegistrationUserAccessType, -} from "../../../../src/component/driver/teamsApp/interfaces/OauthRegistration"; - -describe("App Studio API Test", () => { - const appStudioToken = "appStudioToken"; - const logProvider = new MockedLogProvider(); - - const appDef: AppDefinition = { - appName: "fake", - teamsAppId: uuid(), - userList: [], - }; - - const appApiRegistration: ApiSecretRegistration = { - id: "fakeId", - description: "An Api Key registration for auth", - clientSecrets: [ - { - id: uuid(), - value: "fakeValue", - isValueRedacted: false, - }, - ], - applicableToApps: ApiSecretRegistrationAppType.AnyApp, - targetUrlsShouldStartWith: ["https://www.example.com"], - }; - - const fakeOauthRegistration: OauthRegistration = { - description: "fake-description", - scopes: ["fake-scope"], - clientId: "fake-client-id", - clientSecret: "fake-client-secret", - authorizationEndpoint: "fake-authorization-url", - tokenExchangeEndpoint: "fake-token-endpoint", - tokenRefreshEndpoint: "fake-refresh-endpoint", - applicableToApps: OauthRegistrationAppType.AnyApp, - targetAudience: OauthRegistrationTargetAudience.AnyTenant, - manageableByUsers: [ - { - userId: "fake-user-id", - accessType: OauthRegistrationUserAccessType.ReadWrite, - }, - ], - targetUrlsShouldStartWith: ["fake-domain"], - }; - - beforeEach(() => { - sinon.stub(RetryHandler, "RETRIES").value(1); - }); - - afterEach(() => { - sinon.restore(); - }); - - describe("publish Teams app", () => { - it("Happy path", async () => { - const fakeAxiosInstance = axios.create(); - sinon.stub(axios, "create").returns(fakeAxiosInstance); - const response = { - data: { - id: "fakeId", - }, - }; - sinon.stub(fakeAxiosInstance, "post").resolves(response); - - const res = await AppStudioClient.publishTeamsApp( - appStudioToken, - Buffer.from(""), - appStudioToken - ); - chai.assert.equal(res, response.data.id); - }); - - it("API Failure", async () => { - const fakeAxiosInstance = axios.create(); - sinon.stub(axios, "create").returns(fakeAxiosInstance); - - const error = { - name: "error", - message: "fake message", - }; - sinon.stub(fakeAxiosInstance, "post").throws(error); - - try { - await AppStudioClient.publishTeamsApp(appStudioToken, Buffer.from(""), appStudioToken); - } catch (error) { - chai.assert.equal(error.name, DeveloperPortalAPIFailedError.name); - } - }); - - it("should contain x-correlation-id on BadeRequest with 2xx status code", async () => { - const fakeAxiosInstance = axios.create(); - sinon.stub(axios, "create").returns(fakeAxiosInstance); - - const xCorrelationId = "fakeCorrelationId"; - const response = { - data: { - error: "BadRequest", - }, - message: "fake message", - headers: { - "x-correlation-id": xCorrelationId, - }, - }; - sinon.stub(fakeAxiosInstance, "post").resolves(response); - - try { - await AppStudioClient.publishTeamsApp(appStudioToken, Buffer.from(""), appStudioToken); - } catch (error) { - chai.assert.equal(error.name, DeveloperPortalAPIFailedError.name); - chai.assert.include(error.message, xCorrelationId); - } - }); - - it("Bad gateway", async () => { - const fakeAxiosInstance = axios.create(); - sinon.stub(axios, "create").returns(fakeAxiosInstance); - - const postResponse = { - data: { - error: { - code: "BadGateway", - message: "fakeMessage", - }, - }, - }; - sinon.stub(fakeAxiosInstance, "post").resolves(postResponse); - - const getResponse = { - data: { - value: [ - { - appDefinitions: [ - { - lastModifiedDateTime: new Date(), - publishingState: PublishingState.submitted, - teamsAppId: uuid(), - displayName: "fakeApp", - }, - ], - }, - ], - }, - }; - sinon.stub(fakeAxiosInstance, "get").resolves(getResponse); - - const res = await AppStudioClient.publishTeamsApp( - appStudioToken, - Buffer.from(""), - appStudioToken - ); - chai.assert.equal(res, getResponse.data.value[0].appDefinitions[0].teamsAppId); - }); - - it("AppdefinitionsAlreadyExists - update", async () => { - const fakeAxiosInstance = axios.create(); - sinon.stub(axios, "create").returns(fakeAxiosInstance); - - const publishResponse = { - data: { - error: { - code: "Conflict", - message: "Conflict", - innerError: { - code: "AppDefinitionAlreadyExists", - }, - }, - }, - }; - - const updateResponse = { - data: { - teamsAppId: "fakeId", - }, - }; - sinon - .stub(fakeAxiosInstance, "post") - .onFirstCall() - .resolves(publishResponse) - .onSecondCall() - .resolves(updateResponse); - sinon.stub(AppStudioClient, "publishTeamsAppUpdate").resolves("fakeId"); - - const getResponse = { - data: { - value: [ - { - appDefinitions: [ - { - lastModifiedDateTime: new Date(), - publishingState: PublishingState.submitted, - teamsAppId: uuid(), - displayName: "fakeApp", - }, - ], - }, - ], - }, - }; - sinon.stub(fakeAxiosInstance, "get").resolves(getResponse); - - const res = await AppStudioClient.publishTeamsApp( - appStudioToken, - Buffer.from(""), - appStudioToken - ); - chai.assert.equal(res, "fakeId"); - }); - - it("AppdefinitionsAlreadyExists - failed", async () => { - const fakeAxiosInstance = axios.create(); - sinon.stub(axios, "create").returns(fakeAxiosInstance); - - const postResponse = { - data: { - error: { - code: "Conflict", - message: "Conflict", - innerError: { - code: "AppDefinitionAlreadyExists", - }, - }, - }, - }; - sinon.stub(fakeAxiosInstance, "post").resolves(postResponse); - - try { - await AppStudioClient.publishTeamsApp(appStudioToken, Buffer.from(""), appStudioToken); - } catch (error) { - chai.assert.equal(error.name, AppStudioError.TeamsAppPublishConflictError.name); - } - }); - }); - - describe("import Teams app", () => { - it("Happy path", async () => { - const fakeAxiosInstance = axios.create(); - sinon.stub(axios, "create").returns(fakeAxiosInstance); - - const response = { - data: appDef, - }; - sinon.stub(fakeAxiosInstance, "post").resolves(response); - - AppStudioClient.setRegion("https://dev.teams.microsoft.com/amer"); - - const res = await AppStudioClient.importApp(Buffer.from(""), appStudioToken, logProvider); - chai.assert.equal(res, appDef); - }); - - it("Happy path - with wrong region", async () => { - const fakeAxiosInstance = axios.create(); - sinon.stub(axios, "create").returns(fakeAxiosInstance); - - const response = { - data: appDef, - }; - sinon.stub(fakeAxiosInstance, "post").resolves(response); - AppStudioClient.setRegion("https://dev.teams.microsoft.com"); - - const res = await AppStudioClient.importApp(Buffer.from(""), appStudioToken, logProvider); - chai.assert.equal(res, appDef); - }); - - it("409 conflict", async () => { - const fakeAxiosInstance = axios.create(); - sinon.stub(axios, "create").returns(fakeAxiosInstance); - - const error = { - response: { - status: 409, - }, - }; - sinon.stub(fakeAxiosInstance, "post").throws(error); - - try { - await AppStudioClient.importApp(Buffer.from(""), appStudioToken, logProvider); - } catch (error) { - chai.assert.equal(error.name, AppStudioError.TeamsAppCreateConflictError.name); - } - }); - - it("422 conflict", async () => { - const fakeAxiosInstance = axios.create(); - sinon.stub(axios, "create").returns(fakeAxiosInstance); - - const error = { - response: { - status: 422, - data: "Unable import, App already exists and published. publishStatus: 'LobStore'", - }, - }; - sinon.stub(fakeAxiosInstance, "post").throws(error); - - try { - await AppStudioClient.importApp(Buffer.from(""), appStudioToken, logProvider); - } catch (error) { - chai.assert.equal( - error.name, - AppStudioError.TeamsAppCreateConflictWithPublishedAppError.name - ); - } - }); - - it("422 other error", async () => { - const fakeAxiosInstance = axios.create(); - sinon.stub(axios, "create").returns(fakeAxiosInstance); - - const error = { - response: { - status: 422, - data: "fake error message", - headers: { - "x-correlation-id": uuid(), - }, - }, - }; - sinon.stub(fakeAxiosInstance, "post").throws(error); - - try { - await AppStudioClient.importApp(Buffer.from(""), appStudioToken, logProvider); - } catch (error) { - chai.assert.equal(error.name, DeveloperPortalAPIFailedError.name); - } - }); - - it("invalid Teams app id", async () => { - const fakeAxiosInstance = axios.create(); - sinon.stub(axios, "create").returns(fakeAxiosInstance); - sinon - .stub(manifestUtils, "extractManifestFromArchivedFile") - .returns(ok(new TeamsAppManifest())); - - const error = { - response: { - status: 400, - data: "App Id must be a GUID", - }, - }; - sinon.stub(fakeAxiosInstance, "post").throws(error); - - try { - await AppStudioClient.importApp(Buffer.from(""), appStudioToken, logProvider); - } catch (error) { - chai.assert.equal(error.name, AppStudioError.InvalidTeamsAppIdError.name); - } - }); - - it("extract manifet failed", async () => { - const fakeAxiosInstance = axios.create(); - sinon.stub(axios, "create").returns(fakeAxiosInstance); - const fileNotFoundError = AppStudioResultFactory.UserError( - AppStudioError.FileNotFoundError.name, - AppStudioError.FileNotFoundError.message(Constants.MANIFEST_FILE) - ); - sinon.stub(manifestUtils, "extractManifestFromArchivedFile").returns(err(fileNotFoundError)); - - const error = { - response: { - status: 400, - data: "App Id must be a GUID", - }, - }; - sinon.stub(fakeAxiosInstance, "post").throws(error); - - try { - await AppStudioClient.importApp(Buffer.from(""), appStudioToken, logProvider); - } catch (error) { - chai.assert.equal(error.name, AppStudioError.FileNotFoundError.name); - } - }); - - it("400 bad reqeust", async () => { - const fakeAxiosInstance = axios.create(); - sinon.stub(axios, "create").returns(fakeAxiosInstance); - - const error = { - response: { - staus: 400, - data: "BadRequest", - headers: { - "x-correlation-id": uuid(), - }, - }, - message: "fake message", - }; - sinon.stub(fakeAxiosInstance, "post").throws(error); - - try { - await AppStudioClient.importApp(Buffer.from(""), appStudioToken, logProvider); - } catch (error) { - chai.assert.equal(error.name, DeveloperPortalAPIFailedError.name); - } - }); - }); - - describe("get Teams app", () => { - it("Happy path", async () => { - const fakeAxiosInstance = axios.create(); - sinon.stub(axios, "create").returns(fakeAxiosInstance); - - const response = { - data: appDef, - }; - sinon.stub(fakeAxiosInstance, "get").resolves(response); - - const res = await AppStudioClient.getApp(appDef.teamsAppId!, appStudioToken, logProvider); - chai.assert.equal(res, appDef); - }); - - it("404 not found", async () => { - const fakeAxiosInstance = axios.create(); - sinon.stub(axios, "create").returns(fakeAxiosInstance); - - const error = { - name: "404", - message: "fake message", - }; - sinon.stub(fakeAxiosInstance, "get").throws(error); - - try { - await AppStudioClient.getApp(appDef.teamsAppId!, appStudioToken, logProvider); - } catch (error) { - chai.assert.equal(error.name, DeveloperPortalAPIFailedError.name); - } - }); - - it("region - 404", async () => { - AppStudioClient.setRegion("https://dev.teams.microsoft.com/amer"); - const fakeAxiosInstance = axios.create(); - sinon.stub(axios, "create").returns(fakeAxiosInstance); - - const error = { - response: { - status: 404, - headers: { - "x-correlation-id": "fakeCorrelationId", - }, - }, - }; - sinon.stub(fakeAxiosInstance, "get").throws(error); - - try { - await AppStudioClient.getApp(appDef.teamsAppId!, appStudioToken, logProvider); - } catch (error) { - chai.assert.equal(error.name, DeveloperPortalAPIFailedError.name); - } finally { - AppStudioClient.setRegion(undefined as unknown as string); - } - }); - }); - - describe("get app package", () => { - it("Happy path", async () => { - const fakeAxiosInstance = axios.create(); - sinon.stub(axios, "create").returns(fakeAxiosInstance); - - const response = { - data: "fakeData", - }; - sinon.stub(fakeAxiosInstance, "get").resolves(response); - - const res = await AppStudioClient.getAppPackage( - appDef.teamsAppId!, - appStudioToken, - logProvider - ); - chai.assert.equal(res, "fakeData"); - }); - - it("404 not found", async () => { - const fakeAxiosInstance = axios.create(); - sinon.stub(axios, "create").returns(fakeAxiosInstance); - - const error = { - name: "404", - message: "fake message", - }; - sinon.stub(fakeAxiosInstance, "get").throws(error); - - try { - await AppStudioClient.getAppPackage(appDef.teamsAppId!, appStudioToken, logProvider); - } catch (error) { - chai.assert.equal(error.name, DeveloperPortalAPIFailedError.name); - } - }); - }); - - describe("partner center app validation", () => { - it("Happy path", async () => { - const fakeAxiosInstance = axios.create(); - sinon.stub(axios, "create").returns(fakeAxiosInstance); - - const response = { - data: { - status: "Accepted", - errors: [], - warnings: [], - notes: [], - addInDetails: { - displayName: "fakeApp", - developerName: "Teams", - version: "0.0.1", - manifestVersion: "1.17", - }, - }, - }; - sinon.stub(fakeAxiosInstance, "post").resolves(response); - - const res = await AppStudioClient.partnerCenterAppPackageValidation( - Buffer.from(""), - appStudioToken - ); - chai.assert.equal(res, response.data); - }); - - it("422", async () => { - const fakeAxiosInstance = axios.create(); - sinon.stub(axios, "create").returns(fakeAxiosInstance); - - const error = { - name: "422", - message: "Invalid zip", - }; - sinon.stub(fakeAxiosInstance, "post").throws(error); - - try { - await AppStudioClient.partnerCenterAppPackageValidation(Buffer.from(""), appStudioToken); - } catch (error) { - chai.assert.equal(error.name, DeveloperPortalAPIFailedError.name); - } - }); - }); - - describe("Check exists in tenant", () => { - it("Happy path", async () => { - const fakeAxiosInstance = axios.create(); - sinon.stub(axios, "create").returns(fakeAxiosInstance); - - const response = { - data: true, - }; - sinon.stub(fakeAxiosInstance, "get").resolves(response); - - const res = await AppStudioClient.checkExistsInTenant(appDef.teamsAppId!, appStudioToken); - chai.assert.isTrue(res); - }); - - it("404 not found", async () => { - const fakeAxiosInstance = axios.create(); - sinon.stub(axios, "create").returns(fakeAxiosInstance); - - const error = { - name: "404", - message: "fake message", - }; - sinon.stub(fakeAxiosInstance, "get").throws(error); - - try { - await AppStudioClient.checkExistsInTenant(appDef.teamsAppId!, appStudioToken); - } catch (error) { - chai.assert.equal(error.name, DeveloperPortalAPIFailedError.name); - } - }); - }); - - describe("publishTeamsAppUpdate", () => { - it("should contain x-correlation-id on BadeRequest with 2xx status code", async () => { - const fakeAxiosInstance = axios.create(); - sinon.stub(axios, "create").returns(fakeAxiosInstance); - - const xCorrelationId = "fakeCorrelationId"; - const postResponse = { - data: { - error: "BadRequest", - }, - message: "fake message", - headers: { - "x-correlation-id": xCorrelationId, - }, - }; - - sinon.stub(fakeAxiosInstance, "post").resolves(postResponse); - - const getResponse = { - data: { - value: [ - { - appDefinitions: [ - { - publishingState: PublishingState.submitted, - teamsAppId: "xx", - displayName: "xx", - lastModifiedDateTime: null, - }, - ], - }, - ], - }, - }; - sinon.stub(fakeAxiosInstance, "get").resolves(getResponse); - - try { - await AppStudioClient.publishTeamsAppUpdate("", Buffer.from(""), appStudioToken); - } catch (error) { - chai.assert.include(error.message, xCorrelationId); - } - }); - - it("API Failure", async () => { - const fakeAxiosInstance = axios.create(); - sinon.stub(axios, "create").returns(fakeAxiosInstance); - - const error = { - name: "error", - message: "fake message", - }; - sinon.stub(fakeAxiosInstance, "post").throws(error); - - const getResponse = { - data: { - value: [ - { - appDefinitions: [ - { - publishingState: PublishingState.submitted, - teamsAppId: "xx", - displayName: "xx", - lastModifiedDateTime: null, - }, - ], - }, - ], - }, - }; - sinon.stub(fakeAxiosInstance, "get").resolves(getResponse); - - try { - await AppStudioClient.publishTeamsAppUpdate( - appStudioToken, - Buffer.from(""), - appStudioToken - ); - } catch (error) { - chai.assert.equal(error.name, DeveloperPortalAPIFailedError.name); - } - }); - }); - - describe("grantPermission", () => { - it("API Failure", async () => { - const fakeAxiosInstance = axios.create(); - sinon.stub(axios, "create").returns(fakeAxiosInstance); - - const error = { - name: "error", - message: "fake message", - }; - sinon.stub(fakeAxiosInstance, "post").throws(error); - sinon.stub(fakeAxiosInstance, "get").resolves({ data: appDef }); - - const appUser: AppUser = { - tenantId: uuid(), - aadId: uuid(), - displayName: "fake", - userPrincipalName: "fake", - isAdministrator: false, - }; - - try { - await AppStudioClient.grantPermission( - appDef.teamsAppId!, - appStudioToken, - appUser, - logProvider - ); - } catch (e) { - chai.assert.equal(e.name, error.name); - } - }); - - it("happy path", async () => { - const fakeAxiosInstance = axios.create(); - sinon.stub(axios, "create").returns(fakeAxiosInstance); - - const newAppUser: AppUser = { - tenantId: "new-tenant-id", - aadId: "new-aad-id", - displayName: "fake", - userPrincipalName: "fake", - isAdministrator: false, - }; - const teamsAppId = appDef.teamsAppId!; - const appDefWithUser: AppDefinition = { - appName: "fake", - teamsAppId: teamsAppId, - userList: [ - { - tenantId: "fake-tenant-id", - aadId: "fake-aad-id", - displayName: "fake", - userPrincipalName: "fake", - isAdministrator: false, - }, - ], - }; - const appDefWithUserAdded: AppDefinition = { - appName: "fake", - teamsAppId: teamsAppId, - userList: [ - { - tenantId: "fake-tenant-id", - aadId: "fake-aad-id", - displayName: "fake", - userPrincipalName: "fake", - isAdministrator: false, - }, - newAppUser, - ], - }; - sinon.stub(fakeAxiosInstance, "get").resolves({ - data: appDefWithUser, - }); - sinon.stub(fakeAxiosInstance, "post").resolves({ - data: appDefWithUserAdded, - }); - - const res = await AppStudioClient.grantPermission( - appDef.teamsAppId!, - appStudioToken, - newAppUser, - logProvider - ); - }); - - it("happy path with region", async () => { - AppStudioClient.setRegion("https://dev.teams.microsoft.com/amer"); - - const fakeAxiosInstance = axios.create(); - sinon.stub(axios, "create").returns(fakeAxiosInstance); - - const newAppUser: AppUser = { - tenantId: "new-tenant-id", - aadId: "new-aad-id", - displayName: "fake", - userPrincipalName: "fake", - isAdministrator: false, - }; - const teamsAppId = appDef.teamsAppId!; - const appDefWithUser: AppDefinition = { - appName: "fake", - teamsAppId: teamsAppId, - userList: [ - { - tenantId: "fake-tenant-id", - aadId: "fake-aad-id", - displayName: "fake", - userPrincipalName: "fake", - isAdministrator: false, - }, - ], - }; - const appDefWithUserAdded: AppDefinition = { - appName: "fake", - teamsAppId: teamsAppId, - userList: [ - { - tenantId: "fake-tenant-id", - aadId: "fake-aad-id", - displayName: "fake", - userPrincipalName: "fake", - isAdministrator: false, - }, - newAppUser, - ], - }; - sinon.stub(fakeAxiosInstance, "get").resolves({ - data: appDefWithUser, - }); - sinon.stub(fakeAxiosInstance, "post").resolves({ - data: appDefWithUserAdded, - }); - - const res = await AppStudioClient.grantPermission( - appDef.teamsAppId!, - appStudioToken, - newAppUser, - logProvider - ); - }); - }); - - describe("getUserList", () => { - it("happy path", async () => { - const fakeAxiosInstance = axios.create(); - sinon.stub(axios, "create").returns(fakeAxiosInstance); - - const response = { - data: appDef, - }; - sinon.stub(fakeAxiosInstance, "get").resolves(response); - - const res = await AppStudioClient.getUserList( - appDef.teamsAppId!, - appStudioToken, - logProvider - ); - }); - }); - - describe("checkPermission", () => { - it("No permission", async () => { - const fakeAxiosInstance = axios.create(); - sinon.stub(axios, "create").returns(fakeAxiosInstance); - - const response = { - data: appDef, - }; - sinon.stub(fakeAxiosInstance, "get").resolves(response); - - const res = await AppStudioClient.checkPermission( - appDef.teamsAppId!, - appStudioToken, - "fakeUesrId", - logProvider - ); - chai.assert.equal(res, Constants.PERMISSIONS.noPermission); - }); - }); - - describe("getApiKeyRegistration", () => { - it("404 not found", async () => { - const fakeAxiosInstance = axios.create(); - sinon.stub(axios, "create").returns(fakeAxiosInstance); - - const error = { - name: "404", - message: "fake message", - }; - sinon.stub(fakeAxiosInstance, "get").throws(error); - - try { - await AppStudioClient.getApiKeyRegistrationById(appStudioToken, "fakeId"); - } catch (error) { - chai.assert.equal(error.name, DeveloperPortalAPIFailedError.name); - } - }); - - it("Happy path", async () => { - const fakeAxiosInstance = axios.create(); - sinon.stub(axios, "create").returns(fakeAxiosInstance); - - const response = { - data: appApiRegistration, - }; - sinon.stub(fakeAxiosInstance, "get").resolves(response); - - const res = await AppStudioClient.getApiKeyRegistrationById(appStudioToken, "fakeId"); - chai.assert.equal(res, appApiRegistration); - }); - }); - - describe("createApiKeyRegistration", () => { - it("Happy path", async () => { - const fakeAxiosInstance = axios.create(); - sinon.stub(axios, "create").returns(fakeAxiosInstance); - - const response = { - data: appApiRegistration, - }; - sinon.stub(fakeAxiosInstance, "post").resolves(response); - - const res = await AppStudioClient.createApiKeyRegistration( - appStudioToken, - appApiRegistration - ); - chai.assert.equal(res, appApiRegistration); - }); - - it("Graph API failure", async () => { - const fakeAxiosInstance = axios.create(); - sinon.stub(axios, "create").returns(fakeAxiosInstance); - - const error = { - response: { - staus: 400, - data: { - statusCode: 400, - errorMessage: - "Unsuccessful response received from Teams Graph Service. Error Message: System.Net.Http.HttpConnectionResponseContent", - }, - headers: { - "x-correlation-id": uuid(), - }, - }, - }; - sinon.stub(fakeAxiosInstance, "post").throws(error); - - try { - await AppStudioClient.createApiKeyRegistration(appStudioToken, appApiRegistration); - } catch (error) { - chai.assert.equal(error.name, DeveloperPortalAPIFailedError.name); - } - }); - }); - - describe("updateApiKeyRegistration", () => { - const appApiRegistration: ApiSecretRegistrationUpdate = { - description: "fake description", - applicableToApps: ApiSecretRegistrationAppType.AnyApp, - targetUrlsShouldStartWith: ["https://www.example.com"], - }; - it("404 not found", async () => { - const fakeAxiosInstance = axios.create(); - sinon.stub(axios, "create").returns(fakeAxiosInstance); - - const error = { - name: "404", - message: "fake message", - }; - sinon.stub(fakeAxiosInstance, "patch").throws(error); - - try { - await AppStudioClient.updateApiKeyRegistration( - appStudioToken, - appApiRegistration, - "fakeId" - ); - } catch (error) { - chai.assert.equal(error.name, DeveloperPortalAPIFailedError.name); - } - }); - - it("Happy path", async () => { - const fakeAxiosInstance = axios.create(); - sinon.stub(axios, "create").returns(fakeAxiosInstance); - - const response = { - data: appApiRegistration, - }; - sinon.stub(fakeAxiosInstance, "patch").resolves(response); - - const res = await AppStudioClient.updateApiKeyRegistration( - appStudioToken, - appApiRegistration, - "fakeId" - ); - chai.assert.equal(res, appApiRegistration); - }); - }); - - describe("createOauthRegistration", () => { - it("Happy path", async () => { - const fakeAxiosInstance = axios.create(); - sinon.stub(axios, "create").returns(fakeAxiosInstance); - - const response = { - data: { - configurationRegistrationId: { - oAuthConfigId: "fakeId", - }, - }, - }; - sinon.stub(fakeAxiosInstance, "post").resolves(response); - - const res = await AppStudioClient.createOauthRegistration( - appStudioToken, - fakeOauthRegistration - ); - chai.assert.equal(res.configurationRegistrationId.oAuthConfigId, "fakeId"); - }); - - it("Graph API failure", async () => { - const fakeAxiosInstance = axios.create(); - sinon.stub(axios, "create").returns(fakeAxiosInstance); - - const error = { - response: { - staus: 400, - data: { - statusCode: 400, - errorMessage: - "Unsuccessful response received from Teams Graph Service. Error Message: System.Net.Http.HttpConnectionResponseContent", - }, - headers: { - "x-correlation-id": uuid(), - }, - }, - }; - sinon.stub(fakeAxiosInstance, "get").throws(error); - - try { - await AppStudioClient.createOauthRegistration(appStudioToken, fakeOauthRegistration); - } catch (error) { - chai.assert.equal(error.name, DeveloperPortalAPIFailedError.name); - } - }); - }); - - describe("getOauthRegistration", () => { - it("Happy path", async () => { - const fakeAxiosInstance = axios.create(); - sinon.stub(axios, "create").returns(fakeAxiosInstance); - - const response = { - data: fakeOauthRegistration, - }; - sinon.stub(fakeAxiosInstance, "get").resolves(response); - - const res = await AppStudioClient.getOauthRegistrationById(appStudioToken, "fakeId"); - chai.assert.equal(res, fakeOauthRegistration); - }); - - it("Graph API failure", async () => { - const fakeAxiosInstance = axios.create(); - sinon.stub(axios, "create").returns(fakeAxiosInstance); - - const error = { - name: "404", - message: "fake message", - }; - sinon.stub(fakeAxiosInstance, "get").throws(error); - - try { - await AppStudioClient.getOauthRegistrationById(appStudioToken, "fakeId"); - } catch (error) { - chai.assert.equal(error.name, DeveloperPortalAPIFailedError.name); - } - }); - }); - - describe("updateOauthRegistration", () => { - it("Happy path", async () => { - const fakeAxiosInstance = axios.create(); - sinon.stub(axios, "create").returns(fakeAxiosInstance); - - const response = { - data: fakeOauthRegistration, - }; - sinon.stub(fakeAxiosInstance, "patch").resolves(response); - - const res = await AppStudioClient.updateOauthRegistration( - appStudioToken, - fakeOauthRegistration, - "fakeId" - ); - chai.assert.equal(res, fakeOauthRegistration); - }); - - it("Graph API failure", async () => { - const fakeAxiosInstance = axios.create(); - sinon.stub(axios, "create").returns(fakeAxiosInstance); - - const error = { - name: "404", - message: "fake message", - }; - sinon.stub(fakeAxiosInstance, "patch").throws(error); - - try { - await AppStudioClient.updateOauthRegistration( - appStudioToken, - fakeOauthRegistration, - "fakeId" - ); - } catch (error) { - chai.assert.equal(error.name, DeveloperPortalAPIFailedError.name); - } - }); - }); - - describe("list Teams app", () => { - it("Happy path", async () => { - const fakeAxiosInstance = axios.create(); - sinon.stub(axios, "create").returns(fakeAxiosInstance); - - const response = { - data: [appDef], - }; - sinon.stub(fakeAxiosInstance, "get").resolves(response); - AppStudioClient.setRegion("https://dev.teams.microsoft.com/amer"); - const res = await AppStudioClient.listApps(appStudioToken, logProvider); - chai.assert.deepEqual(res, [appDef]); - }); - it("Error - no region", async () => { - const fakeAxiosInstance = axios.create(); - sinon.stub(axios, "create").returns(fakeAxiosInstance); - - const response = { - data: [appDef], - }; - sinon.stub(fakeAxiosInstance, "get").resolves(response); - AppStudioClient.setRegion(""); - try { - await AppStudioClient.listApps(appStudioToken, logProvider); - chai.assert.fail("should throw error"); - } catch (e) { - chai.assert.isTrue(e instanceof Error); - } - }); - it("Error - api failure", async () => { - const fakeAxiosInstance = axios.create(); - sinon.stub(axios, "create").returns(fakeAxiosInstance); - sinon.stub(fakeAxiosInstance, "get").rejects(new Error()); - AppStudioClient.setRegion("https://dev.teams.microsoft.com/amer"); - try { - await AppStudioClient.listApps(appStudioToken, logProvider); - chai.assert.fail("should throw error"); - } catch (e) { - chai.assert.isTrue(e instanceof DeveloperPortalAPIFailedError); - } - }); - it("Error - no data", async () => { - const fakeAxiosInstance = axios.create(); - sinon.stub(axios, "create").returns(fakeAxiosInstance); - - const response = { - data: undefined, - }; - sinon.stub(fakeAxiosInstance, "get").resolves(response); - AppStudioClient.setRegion("https://dev.teams.microsoft.com/amer"); - try { - await AppStudioClient.listApps(appStudioToken, logProvider); - chai.assert.fail("should throw error"); - } catch (e) { - chai.assert.equal(e.message, "Cannot get the app definitions"); - } - }); - }); - - describe("delete Teams app", () => { - it("Happy path", async () => { - const fakeAxiosInstance = axios.create(); - sinon.stub(axios, "create").returns(fakeAxiosInstance); - const response = { - data: true, - }; - sinon.stub(fakeAxiosInstance, "delete").resolves(response); - AppStudioClient.setRegion("https://dev.teams.microsoft.com/amer"); - const res = await AppStudioClient.deleteApp("testid", appStudioToken, logProvider); - chai.assert.isTrue(res); - }); - it("Error - no region", async () => { - const fakeAxiosInstance = axios.create(); - sinon.stub(axios, "create").returns(fakeAxiosInstance); - - const response = { - data: [appDef], - }; - sinon.stub(fakeAxiosInstance, "delete").resolves(response); - AppStudioClient.setRegion(""); - try { - await AppStudioClient.deleteApp("testid", appStudioToken, logProvider); - chai.assert.fail("should throw error"); - } catch (e) { - chai.assert.isTrue(e instanceof Error); - } - }); - it("Error - api failure", async () => { - const fakeAxiosInstance = axios.create(); - sinon.stub(axios, "create").returns(fakeAxiosInstance); - sinon.stub(fakeAxiosInstance, "delete").rejects(new Error()); - AppStudioClient.setRegion("https://dev.teams.microsoft.com/amer"); - try { - await AppStudioClient.deleteApp("testid", appStudioToken, logProvider); - chai.assert.fail("should throw error"); - } catch (e) { - chai.assert.isTrue(e instanceof DeveloperPortalAPIFailedError); - } - }); - it("Error - no data", async () => { - const fakeAxiosInstance = axios.create(); - sinon.stub(axios, "create").returns(fakeAxiosInstance); - - const response = { - data: undefined, - }; - sinon.stub(fakeAxiosInstance, "delete").resolves(response); - AppStudioClient.setRegion("https://dev.teams.microsoft.com/amer"); - try { - await AppStudioClient.deleteApp("testid", appStudioToken, logProvider); - chai.assert.fail("should throw error"); - } catch (e) { - chai.assert.equal(e.message, "Cannot delete the app: " + "testid"); - } - }); - }); - - describe("Submit async app validation request", () => { - it("Happy path", async () => { - const fakeAxiosInstance = axios.create(); - sinon.stub(axios, "create").returns(fakeAxiosInstance); - const response = { - data: { - appValidationId: uuid(), - status: AsyncAppValidationStatus.Created, - }, - }; - sinon.stub(fakeAxiosInstance, "post").resolves(response); - const res = await AppStudioClient.submitAppValidationRequest("fakeId", appStudioToken); - chai.assert.equal(res.appValidationId, response.data.appValidationId); - }); - }); - - describe("Get async app validation request list", () => { - it("Happy path", async () => { - const fakeAxiosInstance = axios.create(); - sinon.stub(axios, "create").returns(fakeAxiosInstance); - const response = { - data: { - continuationToken: "", - appValidations: [], - }, - }; - sinon.stub(fakeAxiosInstance, "get").resolves(response); - const res = await AppStudioClient.getAppValidationRequestList("fakeId", appStudioToken); - chai.assert.equal(res.appValidations!.length, 0); - }); - - it("404 not found", async () => { - const fakeAxiosInstance = axios.create(); - sinon.stub(axios, "create").returns(fakeAxiosInstance); - - const error = { - name: "404", - message: "fake message", - }; - sinon.stub(fakeAxiosInstance, "post").throws(error); - - try { - await AppStudioClient.submitAppValidationRequest("fakeId", appStudioToken); - } catch (error) { - chai.assert.equal(error.name, DeveloperPortalAPIFailedError.name); - } - }); - }); - - describe("Get async app validation result details", () => { - it("Happy path", async () => { - const fakeAxiosInstance = axios.create(); - sinon.stub(axios, "create").returns(fakeAxiosInstance); - const response = { - data: { - appValidationId: "fakeId", - appId: "fakeAppId", - status: AsyncAppValidationStatus.Completed, - appVersion: "1.0.0", - manifestVersion: "1.17", - createdAt: Date(), - updatedAt: Date(), - validationResults: { - successes: [], - warnings: [], - failures: [], - skipped: [], - }, - }, - }; - sinon.stub(fakeAxiosInstance, "get").resolves(response); - const res = await AppStudioClient.getAppValidationById("fakeId", appStudioToken); - chai.assert.equal(res.appValidationId, "fakeId"); - }); - - it("404 not found", async () => { - const fakeAxiosInstance = axios.create(); - sinon.stub(axios, "create").returns(fakeAxiosInstance); - - const error = { - name: "404", - message: "fake message", - }; - sinon.stub(fakeAxiosInstance, "get").throws(error); - - try { - await AppStudioClient.getAppValidationRequestList("fakeId", appStudioToken); - } catch (error) { - chai.assert.equal(error.name, DeveloperPortalAPIFailedError.name); - } - }); - - it("404 not found", async () => { - const fakeAxiosInstance = axios.create(); - sinon.stub(axios, "create").returns(fakeAxiosInstance); - - const error = { - name: "404", - message: "fake message", - }; - sinon.stub(fakeAxiosInstance, "get").throws(error); - - try { - await AppStudioClient.getAppValidationById("fakeId", appStudioToken); - } catch (error) { - chai.assert.equal(error.name, DeveloperPortalAPIFailedError.name); - } - }); - }); -}); diff --git a/packages/fx-core/tests/component/driver/teamsApp/manifestUtils.test.ts b/packages/fx-core/tests/component/driver/teamsApp/manifestUtils.test.ts index f05da7055e..9ea5ed3dfc 100644 --- a/packages/fx-core/tests/component/driver/teamsApp/manifestUtils.test.ts +++ b/packages/fx-core/tests/component/driver/teamsApp/manifestUtils.test.ts @@ -435,3 +435,39 @@ describe("readAppManifestSync", () => { assert.isTrue(res.isErr() && res.error instanceof ReadFileError); }); }); + +describe("trimManifestShortName", () => { + const sandbox = sinon.createSandbox(); + + afterEach(() => { + sandbox.restore(); + }); + + it("Success", async () => { + const teamsManifest = new TeamsAppManifest(); + teamsManifest.name.short = "shortname abcdefghijklmn123456${{APP_NAME_SUFFIX}}"; + sandbox.stub(fs, "readJson").resolves(teamsManifest); + sandbox.stub(fs, "writeFile").resolves(); + const res = await manifestUtils.trimManifestShortName("projectPath"); + assert.isTrue(res.isOk()); + assert.equal(teamsManifest.name.short, "shortnameabcdefghijklmn12${{APP_NAME_SUFFIX}}"); + }); + it("Success no suffix", async () => { + const teamsManifest = new TeamsAppManifest(); + teamsManifest.name.short = "shortname abcdefghijklmn123456"; + sandbox.stub(fs, "readJson").resolves(teamsManifest); + sandbox.stub(fs, "writeFile").resolves(); + const res = await manifestUtils.trimManifestShortName("projectPath"); + assert.isTrue(res.isOk()); + assert.equal(teamsManifest.name.short, "shortnameabcdefghijklmn12"); + }); + it("No need to trim", async () => { + const teamsManifest = new TeamsAppManifest(); + teamsManifest.name.short = "shortname abcdefghijklmn${{APP_NAME_SUFFIX}}"; + sandbox.stub(fs, "readJson").resolves(teamsManifest); + sandbox.stub(fs, "writeFile").resolves(); + const res = await manifestUtils.trimManifestShortName("projectPath"); + assert.isTrue(res.isOk()); + assert.equal(teamsManifest.name.short, "shortname abcdefghijklmn${{APP_NAME_SUFFIX}}"); + }); +}); diff --git a/packages/fx-core/tests/component/generator/apiSpecGenerator.test.ts b/packages/fx-core/tests/component/generator/apiSpecGenerator.test.ts index 173c71743d..165d88f741 100644 --- a/packages/fx-core/tests/component/generator/apiSpecGenerator.test.ts +++ b/packages/fx-core/tests/component/generator/apiSpecGenerator.test.ts @@ -61,6 +61,7 @@ import mockedEnv, { RestoreFn } from "mocked-env"; import { FeatureFlagName } from "../../../src/common/featureFlags"; import * as commonUtils from "../../../src/common/utils"; import * as helper from "../../../src/component/generator/apiSpec/helper"; +import { fail } from "assert"; const teamsManifest: TeamsAppManifest = { name: { @@ -818,9 +819,61 @@ describe("updateForCustomApi", async () => { it("happy path: csharp", async () => { sandbox.stub(fs, "ensureDir").resolves(); - const mockWriteFile = sandbox.stub(fs, "writeFile").resolves(); + sandbox.stub(fs, "writeFile").callsFake((file, data) => { + if (file == path.join("path", "APIActions.cs")) { + expect(data).to.contains(`[Action("getHello")]`); + expect(data).to.contains(`public async Task GetHelloAsync`); + expect(data).to.contains("openapi.yaml"); + expect(data).not.to.contains("{{"); + expect(data).not.to.contains("# Replace with action code"); + } + + if (file.toString().endsWith("actions.json")) { + expect(file == path.join("path", "prompts", "Chat", "actions.json")).to.be.true; + } + + if (file.toString().endsWith("skprompt.txt")) { + expect(file == path.join("path", "prompts", "Chat", "skprompt.txt")).to.be.true; + } + + if (file.toString().endsWith("getHello.json")) { + expect(file == path.join("path", "adaptiveCards", "getHello.json")).to.be.true; + } + }); + + sandbox + .stub(fs, "readFile") + .resolves(Buffer.from("test code // Replace with action code {{OPENAPI_SPEC_PATH}}")); + + //sandbox fs.readdir(destinationPath) + sandbox.stub(fs, "readdir").resolves(["MyApp.csproj"] as any); await CopilotPluginHelper.updateForCustomApi(spec, "csharp", "path", "openapi.yaml"); - expect(mockWriteFile.notCalled).to.be.true; + }); + + it("unknown language: unknown", async () => { + sandbox.stub(fs, "ensureDir").resolves(); + sandbox.stub(fs, "writeFile").callsFake((file, data) => { + if (file == path.join("path", "APIActions.cs")) { + fail("actions.json should not be created for unknown language"); + } + + if (file.toString().endsWith("actions.json")) { + fail("actions.json should not be created for unknown language"); + } + + if (file.toString().endsWith("skprompt.txt")) { + fail("actions.json should not be created for unknown language"); + } + + if (file.toString().endsWith("getHello.json")) { + fail("actions.json should not be created for unknown language"); + } + }); + + sandbox + .stub(fs, "readFile") + .resolves(Buffer.from("test code // Replace with action code {{OPENAPI_SPEC_PATH}}")); + await CopilotPluginHelper.updateForCustomApi(spec, "unknown", "path", "openapi.yaml"); }); it("happy path with spec without path", async () => { @@ -1016,6 +1069,132 @@ describe("updateForCustomApi", async () => { await CopilotPluginHelper.updateForCustomApi(newSpec, "typescript", "path", "openapi.yaml"); }); + it("happy path with spec request body and schema contains format", async () => { + const newSpec = { + openapi: "3.0.0", + info: { + title: "My API", + version: "1.0.0", + }, + description: "test", + paths: { + "/hello": { + get: { + operationId: "getHello", + summary: "Returns a greeting", + parameters: [ + { + name: "query", + in: "query", + schema: { type: "string" }, + required: true, + }, + { + name: "query2", + in: "query", + schema: { type: "string" }, + requried: false, + }, + { + name: "query3", + in: "query", + schema: { type: "string" }, + requried: true, + description: "test", + }, + { + name: "query4", + in: "query", + schema: { + type: "array", + items: { + type: "string", + format: "test", + }, + }, + }, + ], + responses: { + "200": { + description: "", + content: { + "application/json": { + schema: { + type: "string", + }, + }, + }, + }, + }, + }, + post: { + operationId: "createPet", + summary: "Create a pet", + description: "", + requestBody: { + required: true, + description: "request body description", + content: { + "application/json": { + schema: { + type: "object", + required: ["date"], + properties: { + date: { + type: "string", + description: "", + format: "date-time", + }, + array: { + type: "array", + items: { + type: "string", + format: "test", + }, + }, + object: { + type: "object", + properties: { + nestedObjProperty: { + type: "string", + description: "", + format: "test", + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + } as OpenAPIV3.Document; + sandbox.stub(fs, "ensureDir").resolves(); + sandbox.stub(fs, "writeFile").callsFake((file, data) => { + if (file === path.join("path", "src", "prompts", "chat", "skprompt.txt")) { + expect(data).to.contains("The following is a conversation with an AI assistant."); + } else if (file === path.join("path", "src", "adaptiveCard", "hello.json")) { + expect(data).to.contains("getHello"); + } else if (file === path.join("path", "src", "prompts", "chat", "actions.json")) { + expect(data).to.contains("getHello"); + expect(data).to.contains("body"); + expect(data).to.not.contains("format"); + expect(data).to.contains("nestedObjProperty"); + expect(data).to.contains("array"); + } else if (file === path.join("path", "src", "app", "app.ts")) { + expect(data).to.contains(`app.ai.action("getHello"`); + expect(data).not.to.contains("{{"); + expect(data).not.to.contains("// Replace with action code"); + } + }); + sandbox + .stub(fs, "readFile") + .resolves(Buffer.from("test code // Replace with action code {{OPENAPI_SPEC_PATH}}")); + await CopilotPluginHelper.updateForCustomApi(newSpec, "typescript", "path", "openapi.yaml"); + }); + it("happy path with spec with auth", async () => { const authSpec = { openapi: "3.0.0", @@ -1389,6 +1568,37 @@ describe("listOperations", async () => { const res = await CopilotPluginHelper.listOperations(context, "", inputs, true, false, ""); expect(res.isOk()).to.be.true; }); + + it("should not allow auth for VS copilot project", async () => { + const inputs = { + platform: Platform.VS, + "api-plugin-type": "api-spec", + }; + sandbox.stub(CopilotPluginHelper, "formatValidationErrors").resolves([]); + sandbox.stub(CopilotPluginHelper, "logValidationResults").resolves(); + sandbox.stub(SpecParser.prototype, "validate").resolves({ + status: ValidationStatus.Valid, + warnings: [], + errors: [], + specHash: "xxx", + }); + sandbox.stub(SpecParser.prototype, "list").resolves({ + APIs: [ + { + api: "1", + server: "https://test", + operationId: "id1", + isValid: false, + reason: [ErrorType.AuthTypeIsNotSupported], + }, + ], + allAPICount: 1, + validAPICount: 0, + }); + + const res = await CopilotPluginHelper.listOperations(context, "", inputs, true, false, ""); + expect(res.isOk()).to.be.true; + }); }); describe("SpecGenerator", async () => { @@ -2128,6 +2338,58 @@ describe("SpecGenerator", async () => { assert.isTrue(generateBasedOnSpec.calledOnce); }); + it("generateCustomCopilot for csharp: success", async () => { + const inputs: Inputs = { + platform: Platform.VSCode, + projectPath: "path", + [QuestionNames.ProgrammingLanguage]: ProgrammingLanguage.CSharp, + [QuestionNames.ApiSpecLocation]: "test.yaml", + [QuestionNames.ApiOperation]: ["operation1"], + getTemplateInfosState: { + templateName: "custom-copilot-rag-custom-api", + isPlugin: false, + uri: "https://test.com", + isYaml: false, + type: ProjectType.TeamsAi, + }, + }; + const context = createContext(); + sandbox + .stub(SpecParser.prototype, "validate") + .resolves({ status: ValidationStatus.Valid, errors: [], warnings: [] }); + sandbox.stub(SpecParser.prototype, "getFilteredSpecs").resolves([ + { + openapi: "3.0.0", + info: { + title: "test", + version: "1.0", + }, + paths: {}, + }, + { + openapi: "3.0.0", + info: { + title: "test", + version: "1.0", + }, + paths: {}, + }, + ]); + sandbox.stub(CopilotPluginHelper, "updateForCustomApi").resolves(); + sandbox.stub(fs, "ensureDir").resolves(); + sandbox.stub(manifestUtils, "_readAppManifest").resolves(ok(teamsManifest)); + const generateBasedOnSpec = sandbox + .stub(SpecParser.prototype, "generate") + .resolves({ allSuccess: true, warnings: [] }); + sandbox.stub(pluginGeneratorHelper, "generateScaffoldingSummary").resolves(""); + + const generator = new SpecGenerator(); + const result = await generator.post(context, inputs, "projectPath"); + + assert.isTrue(result.isOk()); + assert.isTrue(generateBasedOnSpec.calledOnce); + }); + it("generateCustomCopilot: CLI with warning", async () => { const inputs: Inputs = { platform: Platform.CLI, diff --git a/packages/fx-core/tests/component/generator/officeAddinGenerator.test.ts b/packages/fx-core/tests/component/generator/officeAddinGenerator.test.ts index 5353181fb1..520a17d70b 100644 --- a/packages/fx-core/tests/component/generator/officeAddinGenerator.test.ts +++ b/packages/fx-core/tests/component/generator/officeAddinGenerator.test.ts @@ -1034,6 +1034,7 @@ describe("OfficeAddinGeneratorNew", () => { chai.assert.isTrue(res.isErr()); }); }); + describe("post()", () => { afterEach(() => { sandbox.restore(); diff --git a/packages/fx-core/tests/component/resource/botService/appStudioClient.test.ts b/packages/fx-core/tests/component/resource/botService/appStudioClient.test.ts deleted file mode 100644 index a42791c1ab..0000000000 --- a/packages/fx-core/tests/component/resource/botService/appStudioClient.test.ts +++ /dev/null @@ -1,436 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. - -/** - * @author Ivan Jobs - */ -import { assert, expect } from "chai"; -import "mocha"; -import { createSandbox } from "sinon"; -import { setTools } from "../../../../src/common/globalVars"; -import { MockTools } from "../../../core/utils"; -import { AppStudioClient } from "../../../../src/component/resource/botService/appStudio/appStudioClient"; -import { IBotRegistration } from "../../../../src/component/resource/botService/appStudio/interfaces/IBotRegistration"; -import { RetryHandler } from "../../../../src/component/resource/botService/retryHandler"; -import axios from "axios"; -import { ErrorNames } from "../../../../src/component/resource/botService/constants"; -import { Messages } from "./messages"; -import { DeveloperPortalAPIFailedError } from "../../../../src/error/teamsApp"; - -describe("AppStudio Client", () => { - const tools = new MockTools(); - const sandbox = createSandbox(); - setTools(tools); - const sampleBot: IBotRegistration = { - botId: "0cd14903-d43a-47f5-b907-73c523aff076", - name: "ruhe01290236-local-debug", - description: "", - iconUrl: - "https://docs.botframework.com/static/devportal/client/images/bot-framework-default.png", - messagingEndpoint: "https://8075-167-220-255-43.ngrok.io/api/messages", - callingEndpoint: "", - }; - - describe("getBotRegistration", () => { - afterEach(() => { - sandbox.restore(); - }); - - it("Should return a valid bot registration", async () => { - // Arrange - sandbox.stub(RetryHandler, "Retry").resolves({ - status: 200, - data: sampleBot, - }); - // Act - const res = await AppStudioClient.getBotRegistration("anything", "anything"); - - // Assert - assert.isTrue(res !== undefined); - assert.isTrue(res?.botId === sampleBot.botId); - }); - - it("Should return a undefined when 404 was throwed out", async () => { - // Arrange - const mockAxiosInstance = axios.create(); - sandbox.stub(mockAxiosInstance, "get").rejects({ - response: { - status: 404, - }, - }); - sandbox.stub(AppStudioClient, "newAxiosInstance").returns(mockAxiosInstance); - - // Act - const res = await AppStudioClient.getBotRegistration("anything", "anything"); - - // Assert - assert.isUndefined(res); - }); - - it("Should throw NotAllowedToAcquireToken error when 401 was throwed out", async () => { - // Arrange - const mockAxiosInstance = axios.create(); - sandbox.stub(mockAxiosInstance, "get").rejects({ - response: { - status: 401, - }, - }); - sandbox.stub(AppStudioClient, "newAxiosInstance").returns(mockAxiosInstance); - - // Act & Assert - try { - await AppStudioClient.getBotRegistration("anything", "anything"); - assert.fail(Messages.ShouldNotReachHere); - } catch (e) { - assert.isTrue(e.name === ErrorNames.ACQUIRE_BOT_FRAMEWORK_TOKEN_ERROR); - } - }); - - it("Should throw DeveloperPortalAPIFailed error when other exceptions (500) were throwed out", async () => { - // Arrange - sandbox.stub(RetryHandler, "Retry").rejects({ - response: { - headers: { - "x-correlation-id": "anything", - }, - status: 500, - }, - }); - - // Act & Assert - try { - await AppStudioClient.getBotRegistration("anything", "anything"); - assert.fail(Messages.ShouldNotReachHere); - } catch (e) { - assert.isTrue(e.name === DeveloperPortalAPIFailedError.name); - } - }); - }); - - describe("createBotRegistration", () => { - afterEach(() => { - sandbox.restore(); - }); - - it("Bot registration should be created successfully", async () => { - // Arrange - sandbox.stub(AppStudioClient, "getBotRegistration").resolves(undefined); - const mockAxiosInstance = axios.create(); - sandbox.stub(mockAxiosInstance, "post").resolves({ - status: 200, - data: sampleBot, - }); - sandbox.stub(AppStudioClient, "newAxiosInstance").returns(mockAxiosInstance); - - // Act & Assert - try { - await AppStudioClient.createBotRegistration("anything", sampleBot); - } catch (e) { - assert.fail(Messages.ShouldNotReachHere); - } - }); - - it("Bot registration creation should be skipped (existing bot case).", async () => { - // Arrange - sandbox.stub(AppStudioClient, "getBotRegistration").resolves(sampleBot); - - // Act & Assert - try { - await AppStudioClient.createBotRegistration("anything", sampleBot); - } catch (e) { - assert.fail(Messages.ShouldNotReachHere); - } - }); - - it("BotFrameworkNotAllowedToAcquireToken error should be throwed out (401)", async () => { - // Arrange - sandbox.stub(AppStudioClient, "getBotRegistration").resolves(undefined); - const mockAxiosInstance = axios.create(); - sandbox.stub(mockAxiosInstance, "post").rejects({ - response: { - status: 401, - }, - }); - sandbox.stub(AppStudioClient, "newAxiosInstance").returns(mockAxiosInstance); - - // Act & Assert - try { - await AppStudioClient.createBotRegistration("anything", sampleBot); - assert.fail(Messages.ShouldNotReachHere); - } catch (e) { - assert.isTrue(e.name === ErrorNames.ACQUIRE_BOT_FRAMEWORK_TOKEN_ERROR); - } - }); - - it("BotFrameworkForbiddenResult error should be throwed out (403)", async () => { - // Arrange - sandbox.stub(AppStudioClient, "getBotRegistration").resolves(undefined); - const mockAxiosInstance = axios.create(); - sandbox.stub(mockAxiosInstance, "post").rejects({ - response: { - status: 403, - }, - }); - sandbox.stub(AppStudioClient, "newAxiosInstance").returns(mockAxiosInstance); - - // Act & Assert - try { - await AppStudioClient.createBotRegistration("anything", sampleBot); - assert.fail(Messages.ShouldNotReachHere); - } catch (e) { - assert.isTrue(e.name === ErrorNames.FORBIDDEN_RESULT_BOT_FRAMEWORK_ERROR); - } - }); - - it("BotFrameworkConflictResult error should be throwed out (429)", async () => { - // Arrange - sandbox.stub(AppStudioClient, "getBotRegistration").resolves(undefined); - const mockAxiosInstance = axios.create(); - sandbox.stub(mockAxiosInstance, "post").rejects({ - response: { - status: 429, - }, - }); - sandbox.stub(AppStudioClient, "newAxiosInstance").returns(mockAxiosInstance); - - // Act & Assert - try { - await AppStudioClient.createBotRegistration("anything", sampleBot); - assert.fail(Messages.ShouldNotReachHere); - } catch (e) { - assert.isTrue(e.name === ErrorNames.CONFLICT_RESULT_BOT_FRAMEWORK_ERROR); - } - }); - - it("DeveloperPortalAPIFailed error should be throwed out (500)", async () => { - // Arrange - sandbox.stub(AppStudioClient, "getBotRegistration").resolves(undefined); - sandbox.stub(RetryHandler, "Retry").rejects({ - response: { - headers: { - "x-correlation-id": "anything", - }, - status: 500, - }, - }); - - // Act & Assert - try { - await AppStudioClient.createBotRegistration("anything", sampleBot); - assert.fail(Messages.ShouldNotReachHere); - } catch (e) { - assert.isTrue(e.name === DeveloperPortalAPIFailedError.name); - } - }); - }); - - describe("updateBotRegistration", () => { - afterEach(() => { - sandbox.restore(); - }); - - it("Bot registration should be updated successfully", async () => { - // Arrange - const mockAxiosInstance = axios.create(); - sandbox.stub(mockAxiosInstance, "post").resolves({ - status: 200, - data: sampleBot, - }); - sandbox.stub(AppStudioClient, "newAxiosInstance").returns(mockAxiosInstance); - - // Act & Assert - try { - await AppStudioClient.updateBotRegistration("anything", sampleBot); - } catch (e) { - assert.fail(Messages.ShouldNotReachHere); - } - }); - - it("BotFrameworkNotAllowedToAcquireToken error should be throwed out (401)", async () => { - // Arrange - const mockAxiosInstance = axios.create(); - sandbox.stub(mockAxiosInstance, "post").rejects({ - response: { - status: 401, - }, - }); - sandbox.stub(AppStudioClient, "newAxiosInstance").returns(mockAxiosInstance); - - // Act & Assert - try { - await AppStudioClient.updateBotRegistration("anything", sampleBot); - assert.fail(Messages.ShouldNotReachHere); - } catch (e) { - assert.isTrue(e.name === ErrorNames.ACQUIRE_BOT_FRAMEWORK_TOKEN_ERROR); - } - }); - - it("BotFrameworkForbiddenResult error should be throwed out (403)", async () => { - // Arrange - const mockAxiosInstance = axios.create(); - sandbox.stub(mockAxiosInstance, "post").rejects({ - response: { - status: 403, - }, - }); - sandbox.stub(AppStudioClient, "newAxiosInstance").returns(mockAxiosInstance); - - // Act & Assert - try { - await AppStudioClient.updateBotRegistration("anything", sampleBot); - assert.fail(Messages.ShouldNotReachHere); - } catch (e) { - assert.isTrue(e.name === ErrorNames.FORBIDDEN_RESULT_BOT_FRAMEWORK_ERROR); - } - }); - - it("BotFrameworkConflictResult error should be throwed out (429)", async () => { - // Arrange - const mockAxiosInstance = axios.create(); - sandbox.stub(mockAxiosInstance, "post").rejects({ - response: { - status: 429, - }, - }); - sandbox.stub(AppStudioClient, "newAxiosInstance").returns(mockAxiosInstance); - - // Act & Assert - try { - await AppStudioClient.updateBotRegistration("anything", sampleBot); - assert.fail(Messages.ShouldNotReachHere); - } catch (e) { - assert.isTrue(e.name === ErrorNames.CONFLICT_RESULT_BOT_FRAMEWORK_ERROR); - } - }); - - it("DeveloperPortalAPIFailed error should be throwed out (500)", async () => { - // Arrange - sandbox.stub(RetryHandler, "Retry").rejects({ - response: { - headers: { - "x-correlation-id": "anything", - }, - status: 500, - }, - }); - - // Act & Assert - try { - await AppStudioClient.updateBotRegistration("anything", sampleBot); - assert.fail(Messages.ShouldNotReachHere); - } catch (e) { - assert.isTrue(e.name === DeveloperPortalAPIFailedError.name); - } - }); - }); - - describe("updateMessageEndpoint", () => { - afterEach(() => { - sandbox.restore(); - }); - - it("Message endpoint should be updated successfully", async () => { - // Arrange - sandbox.stub(AppStudioClient, "getBotRegistration").resolves(sampleBot); - sandbox.stub(AppStudioClient, "updateBotRegistration").resolves(); - // Act & Assert - try { - await AppStudioClient.updateMessageEndpoint("anything", "anything", "anything"); - } catch (e) { - assert.fail(Messages.ShouldNotReachHere); - } - }); - - it("BotRegistrationNotFound error should be throwed out", async () => { - // Arrange - sandbox.stub(AppStudioClient, "getBotRegistration").resolves(undefined); - // Act & Assert - try { - await AppStudioClient.updateMessageEndpoint("anything", "anything", "anything"); - assert.fail(Messages.ShouldNotReachHere); - } catch (e) { - assert.isTrue(e.name === ErrorNames.BOT_REGISTRATION_NOTFOUND_ERROR); - } - }); - }); - - describe("listBots", () => { - afterEach(() => { - sandbox.restore(); - }); - it("happy", async () => { - // Arrange - const mockAxiosInstance = axios.create(); - sandbox.stub(AppStudioClient, "newAxiosInstance").returns(mockAxiosInstance); - sandbox.stub(mockAxiosInstance, "get").resolves({ - status: 200, - data: [sampleBot], - }); - // Act & Assert - try { - const res = await AppStudioClient.listBots("anything"); - assert.deepEqual(res, [sampleBot]); - } catch (e) { - assert.fail(Messages.ShouldNotReachHere); - } - }); - it("invalid response", async () => { - // Arrange - const mockAxiosInstance = axios.create(); - sandbox.stub(AppStudioClient, "newAxiosInstance").returns(mockAxiosInstance); - sandbox.stub(mockAxiosInstance, "get").resolves({ - status: 200, - }); - // Act & Assert - try { - await AppStudioClient.listBots("anything"); - assert.fail(Messages.ShouldNotReachHere); - } catch (e) {} - }); - it("api failure", async () => { - // Arrange - const mockAxiosInstance = axios.create(); - sandbox.stub(AppStudioClient, "newAxiosInstance").returns(mockAxiosInstance); - sandbox.stub(mockAxiosInstance, "get").resolves({ response: { status: 404 } }); - // Act & Assert - try { - await AppStudioClient.listBots("anything"); - assert.fail(Messages.ShouldNotReachHere); - } catch (e) { - assert.isTrue(e instanceof DeveloperPortalAPIFailedError); - } - }); - }); - describe("deleteBot", () => { - afterEach(() => { - sandbox.restore(); - }); - it("happy", async () => { - // Arrange - const mockAxiosInstance = axios.create(); - sandbox.stub(AppStudioClient, "newAxiosInstance").returns(mockAxiosInstance); - sandbox.stub(mockAxiosInstance, "delete").resolves({ - status: 200, - }); - // Act & Assert - try { - await AppStudioClient.deleteBot("anything", "anything"); - } catch (e) { - assert.fail(Messages.ShouldNotReachHere); - } - }); - it("api failure", async () => { - // Arrange - const mockAxiosInstance = axios.create(); - sandbox.stub(AppStudioClient, "newAxiosInstance").returns(mockAxiosInstance); - sandbox.stub(mockAxiosInstance, "delete").resolves({ response: { status: 404 } }); - // Act & Assert - try { - await AppStudioClient.deleteBot("anything", "anything"); - assert.fail(Messages.ShouldNotReachHere); - } catch (e) { - assert.isTrue(e instanceof Error); - } - }); - }); -}); diff --git a/packages/fx-core/tests/error/error.test.ts b/packages/fx-core/tests/error/error.test.ts index 095aaddd20..7a5b839bbd 100644 --- a/packages/fx-core/tests/error/error.test.ts +++ b/packages/fx-core/tests/error/error.test.ts @@ -28,6 +28,18 @@ import { import { BaseComponentInnerError } from "../../src/component/error/componentError"; import { InvalidYamlSchemaError } from "../../src/error/yml"; import { getLocalizedString } from "../../src/common/localizeUtils"; +import { + CopilotDisabledError, + NodejsNotLtsError, + PortsConflictError, + SideloadingDisabledError, + VxTestAppInvalidInstallOptionsError, + VxTestAppValidationError, +} from "../../src/error/depCheck"; +import { + DeveloperPortalAPIFailedSystemError, + DeveloperPortalAPIFailedUserError, +} from "../../src/error/teamsApp"; describe("Middleware - ErrorHandlerMW", () => { const inputs: Inputs = { platform: Platform.VSCode }; @@ -250,3 +262,73 @@ describe("matchDnsError", function () { assert.equal(res, undefined); }); }); + +describe("PortsConflictError", function () { + it("happy", () => { + const err = new PortsConflictError([8801, 8802], [8801]); + assert.deepEqual(err.telemetryProperties, { + ports: [8801, 8802].join(", "), + "occupied-ports": [8801].join(", "), + }); + }); +}); + +describe("SideloadingDisabledError", function () { + it("happy", () => { + const err = new SideloadingDisabledError("src"); + assert.deepEqual(err.source, "src"); + }); +}); + +describe("CopilotDisabledError", function () { + it("happy", () => { + const err = new CopilotDisabledError("src"); + assert.deepEqual(err.source, "src"); + }); +}); + +describe("NodejsNotLtsError", function () { + it("happy", () => { + const err = new NodejsNotLtsError("nodejs-v18", "src"); + assert.deepEqual(err.source, "src"); + }); +}); + +describe("VxTestAppInvalidInstallOptionsError", function () { + it("happy", () => { + const err = new VxTestAppInvalidInstallOptionsError("src"); + assert.deepEqual(err.source, "src"); + }); +}); + +describe("VxTestAppValidationError", function () { + it("happy", () => { + const err = new VxTestAppValidationError("src"); + assert.deepEqual(err.source, "src"); + }); +}); + +describe("DeveloperPortalAPIFailed error", function () { + it("system error", () => { + const error = new DeveloperPortalAPIFailedSystemError( + new Error("test"), + "correlationId", + "apiName", + "extraData" + ); + assert.isTrue(error instanceof SystemError); + assert.isTrue(!!error.displayMessage); + }); + + it("user error", () => { + const error = new DeveloperPortalAPIFailedUserError( + new Error("test"), + "correlationId", + "apiName", + "extraData" + ); + assert.isTrue(error instanceof UserError); + assert.isTrue(!!error.displayMessage); + assert.isFalse(!!error.helpLink); + }); +}); diff --git a/packages/fx-core/tests/plugins/resource/appstudio/unit/authSvcClient.test.ts b/packages/fx-core/tests/plugins/resource/appstudio/unit/authSvcClient.test.ts deleted file mode 100644 index 970b23a793..0000000000 --- a/packages/fx-core/tests/plugins/resource/appstudio/unit/authSvcClient.test.ts +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. - -import "mocha"; -import * as chai from "chai"; -import * as sinon from "sinon"; -import axios from "axios"; -import { RetryHandler } from "../../../../../src/component/driver/teamsApp/utils/utils"; -import { AuthSvcClient } from "../../../../../src/component/driver/teamsApp/clients/authSvcClient"; -import { AppStudioError } from "../../../../../src/component/driver/teamsApp/errors"; - -describe("Auth Service API Test", () => { - beforeEach(() => { - sinon.stub(RetryHandler, "RETRIES").value(1); - }); - - afterEach(() => { - sinon.restore(); - }); - - it("Happy Path", async () => { - const fakeAxiosInstance = axios.create(); - sinon.stub(axios, "create").returns(fakeAxiosInstance); - - const response = { - data: { - regionGtms: { - teamsDevPortal: "https://dev.teams.microsoft.com/amer", - }, - }, - }; - sinon.stub(fakeAxiosInstance, "post").resolves(response); - - const res = await AuthSvcClient.getRegion("fakeToken"); - chai.assert.equal(res, response.data.regionGtms.teamsDevPortal); - }); - - it("API Failure", async () => { - const fakeAxiosInstance = axios.create(); - sinon.stub(axios, "create").returns(fakeAxiosInstance); - - const error = { - response: { - status: 503, - }, - }; - sinon.stub(fakeAxiosInstance, "post").throws(error); - - try { - await AuthSvcClient.getRegion("fakeToken"); - } catch (error) { - chai.assert.equal(error.name, AppStudioError.AuthServiceAPIFailedError.name); - } - }); -}); diff --git a/packages/sdk-react/.eslintrc.json b/packages/sdk-react/.eslintrc.json index cbe645b881..c39075516d 100644 --- a/packages/sdk-react/.eslintrc.json +++ b/packages/sdk-react/.eslintrc.json @@ -9,11 +9,7 @@ "es6": true, "jest/globals": true }, - "extends": [ - "plugin:react/recommended", - "standard", - "plugin:jest/recommended" - ], + "extends": ["plugin:react/recommended", "standard", "plugin:jest/recommended"], "globals": { "Atomics": "readonly", "SharedArrayBuffer": "readonly" @@ -25,22 +21,11 @@ }, "ecmaVersion": 2018 }, - "plugins": [ - "react", - "@typescript-eslint", - "react-hooks", - "jest" - ], + "plugins": ["react", "@typescript-eslint", "react-hooks", "jest"], "rules": { "object-shorthand": 2, - "quotes": [ - "error", - "double" - ], - "semi": [ - "error", - "always" - ], + "quotes": ["error", "double"], + "semi": ["error", "always"], "indent": [ "error", 4, @@ -55,4 +40,4 @@ "react-hooks/rules-of-hooks": "error", // Checks rules of Hooks "react-hooks/exhaustive-deps": "warn" // Checks effect dependencies } -} \ No newline at end of file +} diff --git a/packages/sdk-react/babel.config.js b/packages/sdk-react/babel.config.js new file mode 100644 index 0000000000..19a7349741 --- /dev/null +++ b/packages/sdk-react/babel.config.js @@ -0,0 +1,7 @@ +module.exports = { + presets: [ + ["@babel/preset-env", { targets: { esmodules: true } }], + ["@babel/preset-react", { runtime: "automatic" }], + "@babel/preset-typescript", + ], +}; diff --git a/packages/sdk-react/jest.config.js b/packages/sdk-react/jest.config.js index 8d460fa2df..5ee90ffbf9 100644 --- a/packages/sdk-react/jest.config.js +++ b/packages/sdk-react/jest.config.js @@ -12,7 +12,11 @@ module.exports = { }, }, ], + "\\.jsx?$": "babel-jest", }, + transformIgnorePatterns: [ + "/../sdk/node_modules/(?!@azure/core-auth|@azure/core-http|botbuilder|botbuilder-core|botframework-connector)", + ], moduleNameMapper: { // Force module uuid to resolve with the CJS entry point, because Jest does not support package.json.exports. See https://github.com/uuidjs/uuid/issues/451 uuid: require.resolve("uuid"), diff --git a/packages/sdk-react/package.json b/packages/sdk-react/package.json index 3bdb8a7617..037d530907 100644 --- a/packages/sdk-react/package.json +++ b/packages/sdk-react/package.json @@ -1,6 +1,6 @@ { "name": "@microsoft/teamsfx-react", - "version": "3.1.3", + "version": "4.0.0-rc", "description": "React helper functions for Microsoft TeamsFx", "main": "build/cjs/index.js", "module": "build/esm/index.js", @@ -28,52 +28,53 @@ "precommit": "npm run check-sensitive && lint-staged" }, "devDependencies": { + "@babel/core": "^7.25.2", + "@babel/preset-env": "^7.25.4", + "@babel/preset-react": "^7.24.7", + "@babel/preset-typescript": "^7.24.7", "@istanbuljs/nyc-config-typescript": "^1.0.2", - "@testing-library/react": "^13.4.0", - "@types/enzyme": "^3.10.10", - "@types/jest": "^29.4.0", - "@types/node": "^14.0.0", - "@types/react": "^18.0.0", - "@types/react-dom": "^18.0.0", - "@typescript-eslint/eslint-plugin": "^5.13.0", - "@typescript-eslint/parser": "^6.5.0", - "eslint": "^8.15.0", - "eslint-config-standard": "^17.0.0", + "@testing-library/react": "^16.0.1", + "@types/enzyme": "^3.10.18", + "@types/jest": "^29.5.13", + "@types/node": "^18.0.0", + "@types/react": "^18.3.9", + "@types/react-dom": "^18.3.0", + "@typescript-eslint/eslint-plugin": "^8.7.0", + "@typescript-eslint/parser": "^8.7.0", + "babel-jest": "^29.7.0", + "eslint": "^8.6.0", "eslint-plugin-header": "^3.1.1", - "eslint-plugin-import": "^2.25.4", - "eslint-plugin-jest": "^27.2.1", - "eslint-plugin-n": "^15.2.0", - "eslint-plugin-no-secrets": "^0.8.9", - "eslint-plugin-prettier": "^4.0.0", - "eslint-plugin-promise": "^6.0.0", - "eslint-plugin-react": "^7.26.0", - "eslint-plugin-react-hooks": "^4.2.0", + "eslint-plugin-import": "^2.30.0", + "eslint-plugin-jest": "^28.8.3", + "eslint-plugin-n": "^17.10.3", + "eslint-plugin-no-secrets": "^1.0.2", + "eslint-plugin-prettier": "^5.2.1", + "eslint-plugin-promise": "^7.1.0", + "eslint-plugin-react": "^7.37.0", + "eslint-plugin-react-hooks": "^4.6.2", "isomorphic-fetch": "^3.0.0", - "jest": "^29.4.0", - "jest-environment-jsdom": "^29.4.1", - "jest-junit": "^15.0.0", - "jwt-decode": "^3.1.2", - "lint-staged": "^12.3.4", - "mocha": "^10.0.0", - "nyc": "^15.1.0", - "prettier": "^2.5.1", - "react-test-renderer": "^18.2.0", - "rimraf": "^3.0.2", - "scheduler": "^0.20.2", - "ts-jest": "29.1.0", - "tslib": "^2.3.1", - "typescript": "latest" + "jest": "^29.7.0", + "jest-environment-jsdom": "^29.7.0", + "jest-junit": "^16.0.0", + "jwt-decode": "^4.0.0", + "lint-staged": "^15.2.0", + "nyc": "^17.1.0", + "prettier": "^3.3.3", + "rimraf": "^6.0.1", + "ts-jest": "29.2.5", + "tslib": "^2.7.0", + "typescript": "~5.4.2" }, "peerDependencies": { - "@fluentui/react-components": "^9.15.0", + "@fluentui/react-components": "^9.54.16", "@microsoft/microsoft-graph-client": "^3.0.7", - "@microsoft/teams-js": "^2.19.0", - "@microsoft/teamsfx": "^2.2.2", + "@microsoft/teams-js": "^2.28.0", + "@microsoft/teamsfx": "^3.0.0-alpha", "react": ">=16.8.0 <19.0.0", "react-dom": ">=16.8.0 <19.0.0" }, "dependencies": { - "@fluentui/react": "^8.106.1", + "@fluentui/react": "^8.120.9", "@microsoft/teamsfx": "workspace:*" }, "publishConfig": { diff --git a/packages/sdk-react/pnpm-lock.yaml b/packages/sdk-react/pnpm-lock.yaml index f67a49d55d..7011412c67 100644 --- a/packages/sdk-react/pnpm-lock.yaml +++ b/packages/sdk-react/pnpm-lock.yaml @@ -6,178 +6,176 @@ settings: dependencies: '@fluentui/react': - specifier: ^8.106.1 - version: 8.106.1(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0) + specifier: ^8.120.9 + version: 8.120.9(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1) '@fluentui/react-components': - specifier: ^9.15.0 - version: 9.15.0(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0)(scheduler@0.20.2) + specifier: ^9.54.16 + version: 9.54.17(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1)(scheduler@0.23.0) '@microsoft/microsoft-graph-client': specifier: ^3.0.7 version: 3.0.7 '@microsoft/teams-js': - specifier: ^2.19.0 - version: 2.19.0 + specifier: ^2.28.0 + version: 2.28.0 '@microsoft/teamsfx': specifier: workspace:* version: link:../sdk react: specifier: '>=16.8.0 <19.0.0' - version: 18.2.0 + version: 18.3.1 react-dom: specifier: '>=16.8.0 <19.0.0' - version: 18.2.0(react@18.2.0) + version: 18.3.1(react@18.3.1) devDependencies: + '@babel/core': + specifier: ^7.25.2 + version: 7.25.2 + '@babel/preset-env': + specifier: ^7.25.4 + version: 7.25.4(@babel/core@7.25.2) + '@babel/preset-react': + specifier: ^7.24.7 + version: 7.24.7(@babel/core@7.25.2) + '@babel/preset-typescript': + specifier: ^7.24.7 + version: 7.24.7(@babel/core@7.25.2) '@istanbuljs/nyc-config-typescript': specifier: ^1.0.2 - version: 1.0.2(nyc@15.1.0) + version: 1.0.2(nyc@17.1.0) '@testing-library/react': - specifier: ^13.4.0 - version: 13.4.0(react-dom@18.2.0)(react@18.2.0) + specifier: ^16.0.1 + version: 16.0.1(@testing-library/dom@10.4.0)(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1) '@types/enzyme': - specifier: ^3.10.10 - version: 3.10.10 + specifier: ^3.10.18 + version: 3.10.18 '@types/jest': - specifier: ^29.4.0 - version: 29.4.0 + specifier: ^29.5.13 + version: 29.5.13 '@types/node': - specifier: ^14.0.0 - version: 14.17.4 - '@types/react': specifier: ^18.0.0 - version: 18.0.0 + version: 18.19.53 + '@types/react': + specifier: ^18.3.9 + version: 18.3.9 '@types/react-dom': - specifier: ^18.0.0 - version: 18.0.0 + specifier: ^18.3.0 + version: 18.3.0 '@typescript-eslint/eslint-plugin': - specifier: ^5.13.0 - version: 5.13.0(@typescript-eslint/parser@6.5.0)(eslint@8.15.0)(typescript@5.4.5) + specifier: ^8.7.0 + version: 8.7.0(@typescript-eslint/parser@8.7.0)(eslint@8.57.1)(typescript@5.4.5) '@typescript-eslint/parser': - specifier: ^6.5.0 - version: 6.5.0(eslint@8.15.0)(typescript@5.4.5) + specifier: ^8.7.0 + version: 8.7.0(eslint@8.57.1)(typescript@5.4.5) + babel-jest: + specifier: ^29.7.0 + version: 29.7.0(@babel/core@7.25.2) eslint: - specifier: ^8.15.0 - version: 8.15.0 - eslint-config-standard: - specifier: ^17.0.0 - version: 17.0.0(eslint-plugin-import@2.25.4)(eslint-plugin-n@15.2.0)(eslint-plugin-promise@6.0.0)(eslint@8.15.0) + specifier: ^8.6.0 + version: 8.57.1 eslint-plugin-header: specifier: ^3.1.1 - version: 3.1.1(eslint@8.15.0) + version: 3.1.1(eslint@8.57.1) eslint-plugin-import: - specifier: ^2.25.4 - version: 2.25.4(@typescript-eslint/parser@6.5.0)(eslint@8.15.0) + specifier: ^2.30.0 + version: 2.30.0(@typescript-eslint/parser@8.7.0)(eslint@8.57.1) eslint-plugin-jest: - specifier: ^27.2.1 - version: 27.2.1(@typescript-eslint/eslint-plugin@5.13.0)(eslint@8.15.0)(jest@29.4.0)(typescript@5.4.5) + specifier: ^28.8.3 + version: 28.8.3(@typescript-eslint/eslint-plugin@8.7.0)(eslint@8.57.1)(jest@29.7.0)(typescript@5.4.5) eslint-plugin-n: - specifier: ^15.2.0 - version: 15.2.0(eslint@8.15.0) + specifier: ^17.10.3 + version: 17.10.3(eslint@8.57.1) eslint-plugin-no-secrets: - specifier: ^0.8.9 - version: 0.8.9(eslint@8.15.0) + specifier: ^1.0.2 + version: 1.0.2(eslint@8.57.1) eslint-plugin-prettier: - specifier: ^4.0.0 - version: 4.0.0(eslint@8.15.0)(prettier@2.5.1) + specifier: ^5.2.1 + version: 5.2.1(eslint@8.57.1)(prettier@3.3.3) eslint-plugin-promise: - specifier: ^6.0.0 - version: 6.0.0(eslint@8.15.0) + specifier: ^7.1.0 + version: 7.1.0(eslint@8.57.1) eslint-plugin-react: - specifier: ^7.26.0 - version: 7.26.0(eslint@8.15.0) + specifier: ^7.37.0 + version: 7.37.0(eslint@8.57.1) eslint-plugin-react-hooks: - specifier: ^4.2.0 - version: 4.2.0(eslint@8.15.0) + specifier: ^4.6.2 + version: 4.6.2(eslint@8.57.1) isomorphic-fetch: specifier: ^3.0.0 version: 3.0.0 jest: - specifier: ^29.4.0 - version: 29.4.0(@types/node@14.17.4) + specifier: ^29.7.0 + version: 29.7.0(@types/node@18.19.53) jest-environment-jsdom: - specifier: ^29.4.1 - version: 29.4.1 + specifier: ^29.7.0 + version: 29.7.0 jest-junit: - specifier: ^15.0.0 - version: 15.0.0 + specifier: ^16.0.0 + version: 16.0.0 jwt-decode: - specifier: ^3.1.2 - version: 3.1.2 + specifier: ^4.0.0 + version: 4.0.0 lint-staged: - specifier: ^12.3.4 - version: 12.3.4 - mocha: - specifier: ^10.0.0 - version: 10.0.0 + specifier: ^15.2.0 + version: 15.2.10 nyc: - specifier: ^15.1.0 - version: 15.1.0 + specifier: ^17.1.0 + version: 17.1.0 prettier: - specifier: ^2.5.1 - version: 2.5.1 - react-test-renderer: - specifier: ^18.2.0 - version: 18.2.0(react@18.2.0) + specifier: ^3.3.3 + version: 3.3.3 rimraf: - specifier: ^3.0.2 - version: 3.0.2 - scheduler: - specifier: ^0.20.2 - version: 0.20.2 + specifier: ^6.0.1 + version: 6.0.1 ts-jest: - specifier: 29.1.0 - version: 29.1.0(@babel/core@7.23.7)(jest@29.4.0)(typescript@5.4.5) + specifier: 29.2.5 + version: 29.2.5(@babel/core@7.25.2)(babel-jest@29.7.0)(jest@29.7.0)(typescript@5.4.5) tslib: - specifier: ^2.3.1 - version: 2.6.1 + specifier: ^2.7.0 + version: 2.7.0 typescript: - specifier: latest + specifier: ~5.4.2 version: 5.4.5 packages: - /@aashutoshrathi/word-wrap@1.2.6: - resolution: {integrity: sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==} - engines: {node: '>=0.10.0'} - dev: true - - /@ampproject/remapping@2.2.1: - resolution: {integrity: sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==} + /@ampproject/remapping@2.3.0: + resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} engines: {node: '>=6.0.0'} dependencies: - '@jridgewell/gen-mapping': 0.3.3 - '@jridgewell/trace-mapping': 0.3.22 + '@jridgewell/gen-mapping': 0.3.5 + '@jridgewell/trace-mapping': 0.3.25 dev: true - /@babel/code-frame@7.23.5: - resolution: {integrity: sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==} + /@babel/code-frame@7.24.7: + resolution: {integrity: sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==} engines: {node: '>=6.9.0'} dependencies: - '@babel/highlight': 7.23.4 - chalk: 2.4.2 + '@babel/highlight': 7.24.7 + picocolors: 1.1.0 dev: true - /@babel/compat-data@7.23.5: - resolution: {integrity: sha512-uU27kfDRlhfKl+w1U6vp16IuvSLtjAxdArVXPa9BvLkrr7CYIsxH5adpHObeAGY/41+syctUWOZ140a2Rvkgjw==} + /@babel/compat-data@7.25.4: + resolution: {integrity: sha512-+LGRog6RAsCJrrrg/IO6LGmpphNe5DiK30dGjCoxxeGv49B10/3XYGxPsAwrDlMFcFEvdAUavDT8r9k/hSyQqQ==} engines: {node: '>=6.9.0'} dev: true - /@babel/core@7.23.7: - resolution: {integrity: sha512-+UpDgowcmqe36d4NwqvKsyPMlOLNGMsfMmQ5WGCu+siCe3t3dfe9njrzGfdN4qq+bcNUt0+Vw6haRxBOycs4dw==} + /@babel/core@7.25.2: + resolution: {integrity: sha512-BBt3opiCOxUr9euZ5/ro/Xv8/V7yJ5bjYMqG/C1YAo8MIKAnumZalCN+msbci3Pigy4lIQfPUpfMM27HMGaYEA==} engines: {node: '>=6.9.0'} dependencies: - '@ampproject/remapping': 2.2.1 - '@babel/code-frame': 7.23.5 - '@babel/generator': 7.23.6 - '@babel/helper-compilation-targets': 7.23.6 - '@babel/helper-module-transforms': 7.23.3(@babel/core@7.23.7) - '@babel/helpers': 7.23.8 - '@babel/parser': 7.23.6 - '@babel/template': 7.22.15 - '@babel/traverse': 7.23.7 - '@babel/types': 7.23.6 + '@ampproject/remapping': 2.3.0 + '@babel/code-frame': 7.24.7 + '@babel/generator': 7.25.6 + '@babel/helper-compilation-targets': 7.25.2 + '@babel/helper-module-transforms': 7.25.2(@babel/core@7.25.2) + '@babel/helpers': 7.25.6 + '@babel/parser': 7.25.6 + '@babel/template': 7.25.0 + '@babel/traverse': 7.25.6 + '@babel/types': 7.25.6 convert-source-map: 2.0.0 - debug: 4.3.4 + debug: 4.3.7 gensync: 1.0.0-beta.2 json5: 2.2.3 semver: 6.3.1 @@ -185,298 +183,1320 @@ packages: - supports-color dev: true - /@babel/generator@7.23.6: - resolution: {integrity: sha512-qrSfCYxYQB5owCmGLbl8XRpX1ytXlpueOb0N0UmQwA073KZxejgQTzAmJezxvpwQD9uGtK2shHdi55QT+MbjIw==} + /@babel/generator@7.25.6: + resolution: {integrity: sha512-VPC82gr1seXOpkjAAKoLhP50vx4vGNlF4msF64dSFq1P8RfB+QAuJWGHPXXPc8QyfVWwwB/TNNU4+ayZmHNbZw==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.23.6 - '@jridgewell/gen-mapping': 0.3.3 - '@jridgewell/trace-mapping': 0.3.22 + '@babel/types': 7.25.6 + '@jridgewell/gen-mapping': 0.3.5 + '@jridgewell/trace-mapping': 0.3.25 jsesc: 2.5.2 dev: true - /@babel/helper-compilation-targets@7.23.6: - resolution: {integrity: sha512-9JB548GZoQVmzrFgp8o7KxdgkTGm6xs9DW0o/Pim72UDjzr5ObUQ6ZzYPqA+g9OTS2bBQoctLJrky0RDCAWRgQ==} + /@babel/helper-annotate-as-pure@7.24.7: + resolution: {integrity: sha512-BaDeOonYvhdKw+JoMVkAixAAJzG2jVPIwWoKBPdYuY9b452e2rPuI9QPYh3KpofZ3pW2akOmwZLOiOsHMiqRAg==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.25.6 + dev: true + + /@babel/helper-builder-binary-assignment-operator-visitor@7.24.7: + resolution: {integrity: sha512-xZeCVVdwb4MsDBkkyZ64tReWYrLRHlMN72vP7Bdm3OUOuyFZExhsHUUnuWnm2/XOlAJzR0LfPpB56WXZn0X/lA==} engines: {node: '>=6.9.0'} dependencies: - '@babel/compat-data': 7.23.5 - '@babel/helper-validator-option': 7.23.5 - browserslist: 4.22.2 + '@babel/traverse': 7.25.6 + '@babel/types': 7.25.6 + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/helper-compilation-targets@7.25.2: + resolution: {integrity: sha512-U2U5LsSaZ7TAt3cfaymQ8WHh0pxvdHoEk6HVpaexxixjyEquMh0L0YNJNM6CTGKMXV1iksi0iZkGw4AcFkPaaw==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/compat-data': 7.25.4 + '@babel/helper-validator-option': 7.24.8 + browserslist: 4.24.0 lru-cache: 5.1.1 semver: 6.3.1 dev: true - /@babel/helper-environment-visitor@7.22.20: - resolution: {integrity: sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==} + /@babel/helper-create-class-features-plugin@7.25.4(@babel/core@7.25.2): + resolution: {integrity: sha512-ro/bFs3/84MDgDmMwbcHgDa8/E6J3QKNTk4xJJnVeFtGE+tL0K26E3pNxhYz2b67fJpt7Aphw5XcploKXuCvCQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/core': 7.25.2 + '@babel/helper-annotate-as-pure': 7.24.7 + '@babel/helper-member-expression-to-functions': 7.24.8 + '@babel/helper-optimise-call-expression': 7.24.7 + '@babel/helper-replace-supers': 7.25.0(@babel/core@7.25.2) + '@babel/helper-skip-transparent-expression-wrappers': 7.24.7 + '@babel/traverse': 7.25.6 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/helper-create-regexp-features-plugin@7.25.2(@babel/core@7.25.2): + resolution: {integrity: sha512-+wqVGP+DFmqwFD3EH6TMTfUNeqDehV3E/dl+Sd54eaXqm17tEUNbEIn4sVivVowbvUpOtIGxdo3GoXyDH9N/9g==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/core': 7.25.2 + '@babel/helper-annotate-as-pure': 7.24.7 + regexpu-core: 5.3.2 + semver: 6.3.1 + dev: true + + /@babel/helper-define-polyfill-provider@0.6.2(@babel/core@7.25.2): + resolution: {integrity: sha512-LV76g+C502biUK6AyZ3LK10vDpDyCzZnhZFXkH1L75zHPj68+qc8Zfpx2th+gzwA2MzyK+1g/3EPl62yFnVttQ==} + peerDependencies: + '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 + dependencies: + '@babel/core': 7.25.2 + '@babel/helper-compilation-targets': 7.25.2 + '@babel/helper-plugin-utils': 7.24.8 + debug: 4.3.7 + lodash.debounce: 4.0.8 + resolve: 1.22.8 + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/helper-member-expression-to-functions@7.24.8: + resolution: {integrity: sha512-LABppdt+Lp/RlBxqrh4qgf1oEH/WxdzQNDJIu5gC/W1GyvPVrOBiItmmM8wan2fm4oYqFuFfkXmlGpLQhPY8CA==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/traverse': 7.25.6 + '@babel/types': 7.25.6 + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/helper-module-imports@7.24.7: + resolution: {integrity: sha512-8AyH3C+74cgCVVXow/myrynrAGv+nTVg5vKu2nZph9x7RcRwzmh0VFallJuFTZ9mx6u4eSdXZfcOzSqTUm0HCA==} engines: {node: '>=6.9.0'} + dependencies: + '@babel/traverse': 7.25.6 + '@babel/types': 7.25.6 + transitivePeerDependencies: + - supports-color dev: true - /@babel/helper-function-name@7.23.0: - resolution: {integrity: sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==} + /@babel/helper-module-transforms@7.25.2(@babel/core@7.25.2): + resolution: {integrity: sha512-BjyRAbix6j/wv83ftcVJmBt72QtHI56C7JXZoG2xATiLpmoC7dpd8WnkikExHDVPpi/3qCmO6WY1EaXOluiecQ==} engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 dependencies: - '@babel/template': 7.22.15 - '@babel/types': 7.23.6 + '@babel/core': 7.25.2 + '@babel/helper-module-imports': 7.24.7 + '@babel/helper-simple-access': 7.24.7 + '@babel/helper-validator-identifier': 7.24.7 + '@babel/traverse': 7.25.6 + transitivePeerDependencies: + - supports-color dev: true - /@babel/helper-hoist-variables@7.22.5: - resolution: {integrity: sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==} + /@babel/helper-optimise-call-expression@7.24.7: + resolution: {integrity: sha512-jKiTsW2xmWwxT1ixIdfXUZp+P5yURx2suzLZr5Hi64rURpDYdMW0pv+Uf17EYk2Rd428Lx4tLsnjGJzYKDM/6A==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.23.6 + '@babel/types': 7.25.6 + dev: true + + /@babel/helper-plugin-utils@7.24.8: + resolution: {integrity: sha512-FFWx5142D8h2Mgr/iPVGH5G7w6jDn4jUSpZTyDnQO0Yn7Ks2Kuz6Pci8H6MPCoUJegd/UZQ3tAvfLCxQSnWWwg==} + engines: {node: '>=6.9.0'} + dev: true + + /@babel/helper-remap-async-to-generator@7.25.0(@babel/core@7.25.2): + resolution: {integrity: sha512-NhavI2eWEIz/H9dbrG0TuOicDhNexze43i5z7lEqwYm0WEZVTwnPpA0EafUTP7+6/W79HWIP2cTe3Z5NiSTVpw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/core': 7.25.2 + '@babel/helper-annotate-as-pure': 7.24.7 + '@babel/helper-wrap-function': 7.25.0 + '@babel/traverse': 7.25.6 + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/helper-replace-supers@7.25.0(@babel/core@7.25.2): + resolution: {integrity: sha512-q688zIvQVYtZu+i2PsdIu/uWGRpfxzr5WESsfpShfZECkO+d2o+WROWezCi/Q6kJ0tfPa5+pUGUlfx2HhrA3Bg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/core': 7.25.2 + '@babel/helper-member-expression-to-functions': 7.24.8 + '@babel/helper-optimise-call-expression': 7.24.7 + '@babel/traverse': 7.25.6 + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/helper-simple-access@7.24.7: + resolution: {integrity: sha512-zBAIvbCMh5Ts+b86r/CjU+4XGYIs+R1j951gxI3KmmxBMhCg4oQMsv6ZXQ64XOm/cvzfU1FmoCyt6+owc5QMYg==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/traverse': 7.25.6 + '@babel/types': 7.25.6 + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/helper-skip-transparent-expression-wrappers@7.24.7: + resolution: {integrity: sha512-IO+DLT3LQUElMbpzlatRASEyQtfhSE0+m465v++3jyyXeBTBUjtVZg28/gHeV5mrTJqvEKhKroBGAvhW+qPHiQ==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/traverse': 7.25.6 + '@babel/types': 7.25.6 + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/helper-string-parser@7.24.8: + resolution: {integrity: sha512-pO9KhhRcuUyGnJWwyEgnRJTSIZHiT+vMD0kPeD+so0l7mxkMT19g3pjY9GTnHySck/hDzq+dtW/4VgnMkippsQ==} + engines: {node: '>=6.9.0'} + dev: true + + /@babel/helper-validator-identifier@7.24.7: + resolution: {integrity: sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==} + engines: {node: '>=6.9.0'} + dev: true + + /@babel/helper-validator-option@7.24.8: + resolution: {integrity: sha512-xb8t9tD1MHLungh/AIoWYN+gVHaB9kwlu8gffXGSt3FFEIT7RjS+xWbc2vUD1UTZdIpKj/ab3rdqJ7ufngyi2Q==} + engines: {node: '>=6.9.0'} + dev: true + + /@babel/helper-wrap-function@7.25.0: + resolution: {integrity: sha512-s6Q1ebqutSiZnEjaofc/UKDyC4SbzV5n5SrA2Gq8UawLycr3i04f1dX4OzoQVnexm6aOCh37SQNYlJ/8Ku+PMQ==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/template': 7.25.0 + '@babel/traverse': 7.25.6 + '@babel/types': 7.25.6 + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/helpers@7.25.6: + resolution: {integrity: sha512-Xg0tn4HcfTijTwfDwYlvVCl43V6h4KyVVX2aEm4qdO/PC6L2YvzLHFdmxhoeSA3eslcE6+ZVXHgWwopXYLNq4Q==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/template': 7.25.0 + '@babel/types': 7.25.6 + dev: true + + /@babel/highlight@7.24.7: + resolution: {integrity: sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/helper-validator-identifier': 7.24.7 + chalk: 2.4.2 + js-tokens: 4.0.0 + picocolors: 1.1.0 + dev: true + + /@babel/parser@7.25.6: + resolution: {integrity: sha512-trGdfBdbD0l1ZPmcJ83eNxB9rbEax4ALFTF7fN386TMYbeCQbyme5cOEXQhbGXKebwGaB/J52w1mrklMcbgy6Q==} + engines: {node: '>=6.0.0'} + hasBin: true + dependencies: + '@babel/types': 7.25.6 + dev: true + + /@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.25.3(@babel/core@7.25.2): + resolution: {integrity: sha512-wUrcsxZg6rqBXG05HG1FPYgsP6EvwF4WpBbxIpWIIYnH8wG0gzx3yZY3dtEHas4sTAOGkbTsc9EGPxwff8lRoA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/core': 7.25.2 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/traverse': 7.25.6 + transitivePeerDependencies: + - supports-color dev: true - /@babel/helper-module-imports@7.22.15: - resolution: {integrity: sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==} + /@babel/plugin-bugfix-safari-class-field-initializer-scope@7.25.0(@babel/core@7.25.2): + resolution: {integrity: sha512-Bm4bH2qsX880b/3ziJ8KD711LT7z4u8CFudmjqle65AZj/HNUFhEf90dqYv6O86buWvSBmeQDjv0Tn2aF/bIBA==} engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/core': 7.25.2 + '@babel/helper-plugin-utils': 7.24.8 + dev: true + + /@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.25.0(@babel/core@7.25.2): + resolution: {integrity: sha512-lXwdNZtTmeVOOFtwM/WDe7yg1PL8sYhRk/XH0FzbR2HDQ0xC+EnQ/JHeoMYSavtU115tnUk0q9CDyq8si+LMAA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/core': 7.25.2 + '@babel/helper-plugin-utils': 7.24.8 + dev: true + + /@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.24.7(@babel/core@7.25.2): + resolution: {integrity: sha512-+izXIbke1T33mY4MSNnrqhPXDz01WYhEf3yF5NbnUtkiNnm+XBZJl3kNfoK6NKmYlz/D07+l2GWVK/QfDkNCuQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.13.0 + dependencies: + '@babel/core': 7.25.2 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/helper-skip-transparent-expression-wrappers': 7.24.7 + '@babel/plugin-transform-optional-chaining': 7.24.8(@babel/core@7.25.2) + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.25.0(@babel/core@7.25.2): + resolution: {integrity: sha512-tggFrk1AIShG/RUQbEwt2Tr/E+ObkfwrPjR6BjbRvsx24+PSjK8zrq0GWPNCjo8qpRx4DuJzlcvWJqlm+0h3kw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/core': 7.25.2 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/traverse': 7.25.6 + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2(@babel/core@7.25.2): + resolution: {integrity: sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.25.2 + dev: true + + /@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.25.2): + resolution: {integrity: sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.25.2 + '@babel/helper-plugin-utils': 7.24.8 + dev: true + + /@babel/plugin-syntax-bigint@7.8.3(@babel/core@7.25.2): + resolution: {integrity: sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.25.2 + '@babel/helper-plugin-utils': 7.24.8 + dev: true + + /@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.25.2): + resolution: {integrity: sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.25.2 + '@babel/helper-plugin-utils': 7.24.8 + dev: true + + /@babel/plugin-syntax-class-static-block@7.14.5(@babel/core@7.25.2): + resolution: {integrity: sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.25.2 + '@babel/helper-plugin-utils': 7.24.8 + dev: true + + /@babel/plugin-syntax-dynamic-import@7.8.3(@babel/core@7.25.2): + resolution: {integrity: sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.25.2 + '@babel/helper-plugin-utils': 7.24.8 + dev: true + + /@babel/plugin-syntax-export-namespace-from@7.8.3(@babel/core@7.25.2): + resolution: {integrity: sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.25.2 + '@babel/helper-plugin-utils': 7.24.8 + dev: true + + /@babel/plugin-syntax-import-assertions@7.25.6(@babel/core@7.25.2): + resolution: {integrity: sha512-aABl0jHw9bZ2karQ/uUD6XP4u0SG22SJrOHFoL6XB1R7dTovOP4TzTlsxOYC5yQ1pdscVK2JTUnF6QL3ARoAiQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.25.2 + '@babel/helper-plugin-utils': 7.24.8 + dev: true + + /@babel/plugin-syntax-import-attributes@7.25.6(@babel/core@7.25.2): + resolution: {integrity: sha512-sXaDXaJN9SNLymBdlWFA+bjzBhFD617ZaFiY13dGt7TVslVvVgA6fkZOP7Ki3IGElC45lwHdOTrCtKZGVAWeLQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.25.2 + '@babel/helper-plugin-utils': 7.24.8 + dev: true + + /@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.25.2): + resolution: {integrity: sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.25.2 + '@babel/helper-plugin-utils': 7.24.8 + dev: true + + /@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.25.2): + resolution: {integrity: sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.25.2 + '@babel/helper-plugin-utils': 7.24.8 + dev: true + + /@babel/plugin-syntax-jsx@7.24.7(@babel/core@7.25.2): + resolution: {integrity: sha512-6ddciUPe/mpMnOKv/U+RSd2vvVy+Yw/JfBB0ZHYjEZt9NLHmCUylNYlsbqCCS1Bffjlb0fCwC9Vqz+sBz6PsiQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.25.2 + '@babel/helper-plugin-utils': 7.24.8 + dev: true + + /@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.25.2): + resolution: {integrity: sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.25.2 + '@babel/helper-plugin-utils': 7.24.8 + dev: true + + /@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.25.2): + resolution: {integrity: sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.25.2 + '@babel/helper-plugin-utils': 7.24.8 + dev: true + + /@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.25.2): + resolution: {integrity: sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.25.2 + '@babel/helper-plugin-utils': 7.24.8 + dev: true + + /@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.25.2): + resolution: {integrity: sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.25.2 + '@babel/helper-plugin-utils': 7.24.8 + dev: true + + /@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.25.2): + resolution: {integrity: sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.25.2 + '@babel/helper-plugin-utils': 7.24.8 + dev: true + + /@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.25.2): + resolution: {integrity: sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.25.2 + '@babel/helper-plugin-utils': 7.24.8 + dev: true + + /@babel/plugin-syntax-private-property-in-object@7.14.5(@babel/core@7.25.2): + resolution: {integrity: sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.25.2 + '@babel/helper-plugin-utils': 7.24.8 + dev: true + + /@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.25.2): + resolution: {integrity: sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.25.2 + '@babel/helper-plugin-utils': 7.24.8 + dev: true + + /@babel/plugin-syntax-typescript@7.25.4(@babel/core@7.25.2): + resolution: {integrity: sha512-uMOCoHVU52BsSWxPOMVv5qKRdeSlPuImUCB2dlPuBSU+W2/ROE7/Zg8F2Kepbk+8yBa68LlRKxO+xgEVWorsDg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.25.2 + '@babel/helper-plugin-utils': 7.24.8 + dev: true + + /@babel/plugin-syntax-unicode-sets-regex@7.18.6(@babel/core@7.25.2): + resolution: {integrity: sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/core': 7.25.2 + '@babel/helper-create-regexp-features-plugin': 7.25.2(@babel/core@7.25.2) + '@babel/helper-plugin-utils': 7.24.8 + dev: true + + /@babel/plugin-transform-arrow-functions@7.24.7(@babel/core@7.25.2): + resolution: {integrity: sha512-Dt9LQs6iEY++gXUwY03DNFat5C2NbO48jj+j/bSAz6b3HgPs39qcPiYt77fDObIcFwj3/C2ICX9YMwGflUoSHQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.25.2 + '@babel/helper-plugin-utils': 7.24.8 + dev: true + + /@babel/plugin-transform-async-generator-functions@7.25.4(@babel/core@7.25.2): + resolution: {integrity: sha512-jz8cV2XDDTqjKPwVPJBIjORVEmSGYhdRa8e5k5+vN+uwcjSrSxUaebBRa4ko1jqNF2uxyg8G6XYk30Jv285xzg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.25.2 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/helper-remap-async-to-generator': 7.25.0(@babel/core@7.25.2) + '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.25.2) + '@babel/traverse': 7.25.6 + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/plugin-transform-async-to-generator@7.24.7(@babel/core@7.25.2): + resolution: {integrity: sha512-SQY01PcJfmQ+4Ash7NE+rpbLFbmqA2GPIgqzxfFTL4t1FKRq4zTms/7htKpoCUI9OcFYgzqfmCdH53s6/jn5fA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.25.2 + '@babel/helper-module-imports': 7.24.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/helper-remap-async-to-generator': 7.25.0(@babel/core@7.25.2) + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/plugin-transform-block-scoped-functions@7.24.7(@babel/core@7.25.2): + resolution: {integrity: sha512-yO7RAz6EsVQDaBH18IDJcMB1HnrUn2FJ/Jslc/WtPPWcjhpUJXU/rjbwmluzp7v/ZzWcEhTMXELnnsz8djWDwQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.25.2 + '@babel/helper-plugin-utils': 7.24.8 + dev: true + + /@babel/plugin-transform-block-scoping@7.25.0(@babel/core@7.25.2): + resolution: {integrity: sha512-yBQjYoOjXlFv9nlXb3f1casSHOZkWr29NX+zChVanLg5Nc157CrbEX9D7hxxtTpuFy7Q0YzmmWfJxzvps4kXrQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.25.2 + '@babel/helper-plugin-utils': 7.24.8 + dev: true + + /@babel/plugin-transform-class-properties@7.25.4(@babel/core@7.25.2): + resolution: {integrity: sha512-nZeZHyCWPfjkdU5pA/uHiTaDAFUEqkpzf1YoQT2NeSynCGYq9rxfyI3XpQbfx/a0hSnFH6TGlEXvae5Vi7GD8g==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.25.2 + '@babel/helper-create-class-features-plugin': 7.25.4(@babel/core@7.25.2) + '@babel/helper-plugin-utils': 7.24.8 + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/plugin-transform-class-static-block@7.24.7(@babel/core@7.25.2): + resolution: {integrity: sha512-HMXK3WbBPpZQufbMG4B46A90PkuuhN9vBCb5T8+VAHqvAqvcLi+2cKoukcpmUYkszLhScU3l1iudhrks3DggRQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.12.0 + dependencies: + '@babel/core': 7.25.2 + '@babel/helper-create-class-features-plugin': 7.25.4(@babel/core@7.25.2) + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.25.2) + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/plugin-transform-classes@7.25.4(@babel/core@7.25.2): + resolution: {integrity: sha512-oexUfaQle2pF/b6E0dwsxQtAol9TLSO88kQvym6HHBWFliV2lGdrPieX+WgMRLSJDVzdYywk7jXbLPuO2KLTLg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.25.2 + '@babel/helper-annotate-as-pure': 7.24.7 + '@babel/helper-compilation-targets': 7.25.2 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/helper-replace-supers': 7.25.0(@babel/core@7.25.2) + '@babel/traverse': 7.25.6 + globals: 11.12.0 + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/plugin-transform-computed-properties@7.24.7(@babel/core@7.25.2): + resolution: {integrity: sha512-25cS7v+707Gu6Ds2oY6tCkUwsJ9YIDbggd9+cu9jzzDgiNq7hR/8dkzxWfKWnTic26vsI3EsCXNd4iEB6e8esQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.25.2 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/template': 7.25.0 + dev: true + + /@babel/plugin-transform-destructuring@7.24.8(@babel/core@7.25.2): + resolution: {integrity: sha512-36e87mfY8TnRxc7yc6M9g9gOB7rKgSahqkIKwLpz4Ppk2+zC2Cy1is0uwtuSG6AE4zlTOUa+7JGz9jCJGLqQFQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.25.2 + '@babel/helper-plugin-utils': 7.24.8 + dev: true + + /@babel/plugin-transform-dotall-regex@7.24.7(@babel/core@7.25.2): + resolution: {integrity: sha512-ZOA3W+1RRTSWvyqcMJDLqbchh7U4NRGqwRfFSVbOLS/ePIP4vHB5e8T8eXcuqyN1QkgKyj5wuW0lcS85v4CrSw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.25.2 + '@babel/helper-create-regexp-features-plugin': 7.25.2(@babel/core@7.25.2) + '@babel/helper-plugin-utils': 7.24.8 + dev: true + + /@babel/plugin-transform-duplicate-keys@7.24.7(@babel/core@7.25.2): + resolution: {integrity: sha512-JdYfXyCRihAe46jUIliuL2/s0x0wObgwwiGxw/UbgJBr20gQBThrokO4nYKgWkD7uBaqM7+9x5TU7NkExZJyzw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.25.2 + '@babel/helper-plugin-utils': 7.24.8 + dev: true + + /@babel/plugin-transform-duplicate-named-capturing-groups-regex@7.25.0(@babel/core@7.25.2): + resolution: {integrity: sha512-YLpb4LlYSc3sCUa35un84poXoraOiQucUTTu8X1j18JV+gNa8E0nyUf/CjZ171IRGr4jEguF+vzJU66QZhn29g==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/core': 7.25.2 + '@babel/helper-create-regexp-features-plugin': 7.25.2(@babel/core@7.25.2) + '@babel/helper-plugin-utils': 7.24.8 + dev: true + + /@babel/plugin-transform-dynamic-import@7.24.7(@babel/core@7.25.2): + resolution: {integrity: sha512-sc3X26PhZQDb3JhORmakcbvkeInvxz+A8oda99lj7J60QRuPZvNAk9wQlTBS1ZynelDrDmTU4pw1tyc5d5ZMUg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.25.2 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.25.2) + dev: true + + /@babel/plugin-transform-exponentiation-operator@7.24.7(@babel/core@7.25.2): + resolution: {integrity: sha512-Rqe/vSc9OYgDajNIK35u7ot+KeCoetqQYFXM4Epf7M7ez3lWlOjrDjrwMei6caCVhfdw+mIKD4cgdGNy5JQotQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.25.2 + '@babel/helper-builder-binary-assignment-operator-visitor': 7.24.7 + '@babel/helper-plugin-utils': 7.24.8 + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/plugin-transform-export-namespace-from@7.24.7(@babel/core@7.25.2): + resolution: {integrity: sha512-v0K9uNYsPL3oXZ/7F9NNIbAj2jv1whUEtyA6aujhekLs56R++JDQuzRcP2/z4WX5Vg/c5lE9uWZA0/iUoFhLTA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.25.2 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-export-namespace-from': 7.8.3(@babel/core@7.25.2) + dev: true + + /@babel/plugin-transform-for-of@7.24.7(@babel/core@7.25.2): + resolution: {integrity: sha512-wo9ogrDG1ITTTBsy46oGiN1dS9A7MROBTcYsfS8DtsImMkHk9JXJ3EWQM6X2SUw4x80uGPlwj0o00Uoc6nEE3g==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.25.2 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/helper-skip-transparent-expression-wrappers': 7.24.7 + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/plugin-transform-function-name@7.25.1(@babel/core@7.25.2): + resolution: {integrity: sha512-TVVJVdW9RKMNgJJlLtHsKDTydjZAbwIsn6ySBPQaEAUU5+gVvlJt/9nRmqVbsV/IBanRjzWoaAQKLoamWVOUuA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.25.2 + '@babel/helper-compilation-targets': 7.25.2 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/traverse': 7.25.6 + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/plugin-transform-json-strings@7.24.7(@babel/core@7.25.2): + resolution: {integrity: sha512-2yFnBGDvRuxAaE/f0vfBKvtnvvqU8tGpMHqMNpTN2oWMKIR3NqFkjaAgGwawhqK/pIN2T3XdjGPdaG0vDhOBGw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.25.2 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.25.2) + dev: true + + /@babel/plugin-transform-literals@7.25.2(@babel/core@7.25.2): + resolution: {integrity: sha512-HQI+HcTbm9ur3Z2DkO+jgESMAMcYLuN/A7NRw9juzxAezN9AvqvUTnpKP/9kkYANz6u7dFlAyOu44ejuGySlfw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.25.2 + '@babel/helper-plugin-utils': 7.24.8 + dev: true + + /@babel/plugin-transform-logical-assignment-operators@7.24.7(@babel/core@7.25.2): + resolution: {integrity: sha512-4D2tpwlQ1odXmTEIFWy9ELJcZHqrStlzK/dAOWYyxX3zT0iXQB6banjgeOJQXzEc4S0E0a5A+hahxPaEFYftsw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.25.2 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.25.2) + dev: true + + /@babel/plugin-transform-member-expression-literals@7.24.7(@babel/core@7.25.2): + resolution: {integrity: sha512-T/hRC1uqrzXMKLQ6UCwMT85S3EvqaBXDGf0FaMf4446Qx9vKwlghvee0+uuZcDUCZU5RuNi4781UQ7R308zzBw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.25.2 + '@babel/helper-plugin-utils': 7.24.8 + dev: true + + /@babel/plugin-transform-modules-amd@7.24.7(@babel/core@7.25.2): + resolution: {integrity: sha512-9+pB1qxV3vs/8Hdmz/CulFB8w2tuu6EB94JZFsjdqxQokwGa9Unap7Bo2gGBGIvPmDIVvQrom7r5m/TCDMURhg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.25.2 + '@babel/helper-module-transforms': 7.25.2(@babel/core@7.25.2) + '@babel/helper-plugin-utils': 7.24.8 + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/plugin-transform-modules-commonjs@7.24.8(@babel/core@7.25.2): + resolution: {integrity: sha512-WHsk9H8XxRs3JXKWFiqtQebdh9b/pTk4EgueygFzYlTKAg0Ud985mSevdNjdXdFBATSKVJGQXP1tv6aGbssLKA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.25.2 + '@babel/helper-module-transforms': 7.25.2(@babel/core@7.25.2) + '@babel/helper-plugin-utils': 7.24.8 + '@babel/helper-simple-access': 7.24.7 + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/plugin-transform-modules-systemjs@7.25.0(@babel/core@7.25.2): + resolution: {integrity: sha512-YPJfjQPDXxyQWg/0+jHKj1llnY5f/R6a0p/vP4lPymxLu7Lvl4k2WMitqi08yxwQcCVUUdG9LCUj4TNEgAp3Jw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.25.2 + '@babel/helper-module-transforms': 7.25.2(@babel/core@7.25.2) + '@babel/helper-plugin-utils': 7.24.8 + '@babel/helper-validator-identifier': 7.24.7 + '@babel/traverse': 7.25.6 + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/plugin-transform-modules-umd@7.24.7(@babel/core@7.25.2): + resolution: {integrity: sha512-3aytQvqJ/h9z4g8AsKPLvD4Zqi2qT+L3j7XoFFu1XBlZWEl2/1kWnhmAbxpLgPrHSY0M6UA02jyTiwUVtiKR6A==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.25.2 + '@babel/helper-module-transforms': 7.25.2(@babel/core@7.25.2) + '@babel/helper-plugin-utils': 7.24.8 + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/plugin-transform-named-capturing-groups-regex@7.24.7(@babel/core@7.25.2): + resolution: {integrity: sha512-/jr7h/EWeJtk1U/uz2jlsCioHkZk1JJZVcc8oQsJ1dUlaJD83f4/6Zeh2aHt9BIFokHIsSeDfhUmju0+1GPd6g==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/core': 7.25.2 + '@babel/helper-create-regexp-features-plugin': 7.25.2(@babel/core@7.25.2) + '@babel/helper-plugin-utils': 7.24.8 + dev: true + + /@babel/plugin-transform-new-target@7.24.7(@babel/core@7.25.2): + resolution: {integrity: sha512-RNKwfRIXg4Ls/8mMTza5oPF5RkOW8Wy/WgMAp1/F1yZ8mMbtwXW+HDoJiOsagWrAhI5f57Vncrmr9XeT4CVapA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.25.2 + '@babel/helper-plugin-utils': 7.24.8 + dev: true + + /@babel/plugin-transform-nullish-coalescing-operator@7.24.7(@babel/core@7.25.2): + resolution: {integrity: sha512-Ts7xQVk1OEocqzm8rHMXHlxvsfZ0cEF2yomUqpKENHWMF4zKk175Y4q8H5knJes6PgYad50uuRmt3UJuhBw8pQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.25.2 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.25.2) + dev: true + + /@babel/plugin-transform-numeric-separator@7.24.7(@babel/core@7.25.2): + resolution: {integrity: sha512-e6q1TiVUzvH9KRvicuxdBTUj4AdKSRwzIyFFnfnezpCfP2/7Qmbb8qbU2j7GODbl4JMkblitCQjKYUaX/qkkwA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.25.2 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.25.2) + dev: true + + /@babel/plugin-transform-object-rest-spread@7.24.7(@babel/core@7.25.2): + resolution: {integrity: sha512-4QrHAr0aXQCEFni2q4DqKLD31n2DL+RxcwnNjDFkSG0eNQ/xCavnRkfCUjsyqGC2OviNJvZOF/mQqZBw7i2C5Q==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.25.2 + '@babel/helper-compilation-targets': 7.25.2 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.25.2) + '@babel/plugin-transform-parameters': 7.24.7(@babel/core@7.25.2) + dev: true + + /@babel/plugin-transform-object-super@7.24.7(@babel/core@7.25.2): + resolution: {integrity: sha512-A/vVLwN6lBrMFmMDmPPz0jnE6ZGx7Jq7d6sT/Ev4H65RER6pZ+kczlf1DthF5N0qaPHBsI7UXiE8Zy66nmAovg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.25.2 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/helper-replace-supers': 7.25.0(@babel/core@7.25.2) + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/plugin-transform-optional-catch-binding@7.24.7(@babel/core@7.25.2): + resolution: {integrity: sha512-uLEndKqP5BfBbC/5jTwPxLh9kqPWWgzN/f8w6UwAIirAEqiIVJWWY312X72Eub09g5KF9+Zn7+hT7sDxmhRuKA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 dependencies: - '@babel/types': 7.23.6 + '@babel/core': 7.25.2 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.25.2) dev: true - /@babel/helper-module-transforms@7.23.3(@babel/core@7.23.7): - resolution: {integrity: sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==} + /@babel/plugin-transform-optional-chaining@7.24.8(@babel/core@7.25.2): + resolution: {integrity: sha512-5cTOLSMs9eypEy8JUVvIKOu6NgvbJMnpG62VpIHrTmROdQ+L5mDAaI40g25k5vXti55JWNX5jCkq3HZxXBQANw==} engines: {node: '>=6.9.0'} peerDependencies: - '@babel/core': ^7.0.0 + '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.23.7 - '@babel/helper-environment-visitor': 7.22.20 - '@babel/helper-module-imports': 7.22.15 - '@babel/helper-simple-access': 7.22.5 - '@babel/helper-split-export-declaration': 7.22.6 - '@babel/helper-validator-identifier': 7.22.20 + '@babel/core': 7.25.2 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/helper-skip-transparent-expression-wrappers': 7.24.7 + '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.25.2) + transitivePeerDependencies: + - supports-color dev: true - /@babel/helper-plugin-utils@7.22.5: - resolution: {integrity: sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==} + /@babel/plugin-transform-parameters@7.24.7(@babel/core@7.25.2): + resolution: {integrity: sha512-yGWW5Rr+sQOhK0Ot8hjDJuxU3XLRQGflvT4lhlSY0DFvdb3TwKaY26CJzHtYllU0vT9j58hc37ndFPsqT1SrzA==} engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.25.2 + '@babel/helper-plugin-utils': 7.24.8 dev: true - /@babel/helper-simple-access@7.22.5: - resolution: {integrity: sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==} + /@babel/plugin-transform-private-methods@7.25.4(@babel/core@7.25.2): + resolution: {integrity: sha512-ao8BG7E2b/URaUQGqN3Tlsg+M3KlHY6rJ1O1gXAEUnZoyNQnvKyH87Kfg+FoxSeyWUB8ISZZsC91C44ZuBFytw==} engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 dependencies: - '@babel/types': 7.23.6 + '@babel/core': 7.25.2 + '@babel/helper-create-class-features-plugin': 7.25.4(@babel/core@7.25.2) + '@babel/helper-plugin-utils': 7.24.8 + transitivePeerDependencies: + - supports-color dev: true - /@babel/helper-split-export-declaration@7.22.6: - resolution: {integrity: sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==} + /@babel/plugin-transform-private-property-in-object@7.24.7(@babel/core@7.25.2): + resolution: {integrity: sha512-9z76mxwnwFxMyxZWEgdgECQglF2Q7cFLm0kMf8pGwt+GSJsY0cONKj/UuO4bOH0w/uAel3ekS4ra5CEAyJRmDA==} engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 dependencies: - '@babel/types': 7.23.6 + '@babel/core': 7.25.2 + '@babel/helper-annotate-as-pure': 7.24.7 + '@babel/helper-create-class-features-plugin': 7.25.4(@babel/core@7.25.2) + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.25.2) + transitivePeerDependencies: + - supports-color dev: true - /@babel/helper-string-parser@7.23.4: - resolution: {integrity: sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==} + /@babel/plugin-transform-property-literals@7.24.7(@babel/core@7.25.2): + resolution: {integrity: sha512-EMi4MLQSHfd2nrCqQEWxFdha2gBCqU4ZcCng4WBGZ5CJL4bBRW0ptdqqDdeirGZcpALazVVNJqRmsO8/+oNCBA==} engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.25.2 + '@babel/helper-plugin-utils': 7.24.8 dev: true - /@babel/helper-validator-identifier@7.22.20: - resolution: {integrity: sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==} + /@babel/plugin-transform-react-display-name@7.24.7(@babel/core@7.25.2): + resolution: {integrity: sha512-H/Snz9PFxKsS1JLI4dJLtnJgCJRoo0AUm3chP6NYr+9En1JMKloheEiLIhlp5MDVznWo+H3AAC1Mc8lmUEpsgg==} engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.25.2 + '@babel/helper-plugin-utils': 7.24.8 dev: true - /@babel/helper-validator-option@7.23.5: - resolution: {integrity: sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw==} + /@babel/plugin-transform-react-jsx-development@7.24.7(@babel/core@7.25.2): + resolution: {integrity: sha512-QG9EnzoGn+Qar7rxuW+ZOsbWOt56FvvI93xInqsZDC5fsekx1AlIO4KIJ5M+D0p0SqSH156EpmZyXq630B8OlQ==} engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.25.2 + '@babel/plugin-transform-react-jsx': 7.25.2(@babel/core@7.25.2) + transitivePeerDependencies: + - supports-color dev: true - /@babel/helpers@7.23.8: - resolution: {integrity: sha512-KDqYz4PiOWvDFrdHLPhKtCThtIcKVy6avWD2oG4GEvyQ+XDZwHD4YQd+H2vNMnq2rkdxsDkU82T+Vk8U/WXHRQ==} + /@babel/plugin-transform-react-jsx@7.25.2(@babel/core@7.25.2): + resolution: {integrity: sha512-KQsqEAVBpU82NM/B/N9j9WOdphom1SZH3R+2V7INrQUH+V9EBFwZsEJl8eBIVeQE62FxJCc70jzEZwqU7RcVqA==} engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 dependencies: - '@babel/template': 7.22.15 - '@babel/traverse': 7.23.7 - '@babel/types': 7.23.6 + '@babel/core': 7.25.2 + '@babel/helper-annotate-as-pure': 7.24.7 + '@babel/helper-module-imports': 7.24.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-jsx': 7.24.7(@babel/core@7.25.2) + '@babel/types': 7.25.6 transitivePeerDependencies: - supports-color dev: true - /@babel/highlight@7.23.4: - resolution: {integrity: sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==} + /@babel/plugin-transform-react-pure-annotations@7.24.7(@babel/core@7.25.2): + resolution: {integrity: sha512-PLgBVk3fzbmEjBJ/u8kFzOqS9tUeDjiaWud/rRym/yjCo/M9cASPlnrd2ZmmZpQT40fOOrvR8jh+n8jikrOhNA==} engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 dependencies: - '@babel/helper-validator-identifier': 7.22.20 - chalk: 2.4.2 - js-tokens: 4.0.0 + '@babel/core': 7.25.2 + '@babel/helper-annotate-as-pure': 7.24.7 + '@babel/helper-plugin-utils': 7.24.8 dev: true - /@babel/parser@7.23.6: - resolution: {integrity: sha512-Z2uID7YJ7oNvAI20O9X0bblw7Qqs8Q2hFy0R9tAfnfLkp5MW0UH9eUvnDSnFwKZ0AvgS1ucqR4KzvVHgnke1VQ==} - engines: {node: '>=6.0.0'} - hasBin: true + /@babel/plugin-transform-regenerator@7.24.7(@babel/core@7.25.2): + resolution: {integrity: sha512-lq3fvXPdimDrlg6LWBoqj+r/DEWgONuwjuOuQCSYgRroXDH/IdM1C0IZf59fL5cHLpjEH/O6opIRBbqv7ELnuA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 dependencies: - '@babel/types': 7.23.6 + '@babel/core': 7.25.2 + '@babel/helper-plugin-utils': 7.24.8 + regenerator-transform: 0.15.2 dev: true - /@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.23.7): - resolution: {integrity: sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==} + /@babel/plugin-transform-reserved-words@7.24.7(@babel/core@7.25.2): + resolution: {integrity: sha512-0DUq0pHcPKbjFZCfTss/pGkYMfy3vFWydkUBd9r0GHpIyfs2eCDENvqadMycRS9wZCXR41wucAfJHJmwA0UmoQ==} + engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.22.5 + '@babel/core': 7.25.2 + '@babel/helper-plugin-utils': 7.24.8 dev: true - /@babel/plugin-syntax-bigint@7.8.3(@babel/core@7.23.7): - resolution: {integrity: sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==} + /@babel/plugin-transform-shorthand-properties@7.24.7(@babel/core@7.25.2): + resolution: {integrity: sha512-KsDsevZMDsigzbA09+vacnLpmPH4aWjcZjXdyFKGzpplxhbeB4wYtury3vglQkg6KM/xEPKt73eCjPPf1PgXBA==} + engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.22.5 + '@babel/core': 7.25.2 + '@babel/helper-plugin-utils': 7.24.8 dev: true - /@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.23.7): - resolution: {integrity: sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==} + /@babel/plugin-transform-spread@7.24.7(@babel/core@7.25.2): + resolution: {integrity: sha512-x96oO0I09dgMDxJaANcRyD4ellXFLLiWhuwDxKZX5g2rWP1bTPkBSwCYv96VDXVT1bD9aPj8tppr5ITIh8hBng==} + engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.22.5 + '@babel/core': 7.25.2 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/helper-skip-transparent-expression-wrappers': 7.24.7 + transitivePeerDependencies: + - supports-color dev: true - /@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.23.7): - resolution: {integrity: sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==} + /@babel/plugin-transform-sticky-regex@7.24.7(@babel/core@7.25.2): + resolution: {integrity: sha512-kHPSIJc9v24zEml5geKg9Mjx5ULpfncj0wRpYtxbvKyTtHCYDkVE3aHQ03FrpEo4gEe2vrJJS1Y9CJTaThA52g==} + engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.22.5 + '@babel/core': 7.25.2 + '@babel/helper-plugin-utils': 7.24.8 dev: true - /@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.23.7): - resolution: {integrity: sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==} + /@babel/plugin-transform-template-literals@7.24.7(@babel/core@7.25.2): + resolution: {integrity: sha512-AfDTQmClklHCOLxtGoP7HkeMw56k1/bTQjwsfhL6pppo/M4TOBSq+jjBUBLmV/4oeFg4GWMavIl44ZeCtmmZTw==} + engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.22.5 + '@babel/core': 7.25.2 + '@babel/helper-plugin-utils': 7.24.8 dev: true - /@babel/plugin-syntax-jsx@7.23.3(@babel/core@7.23.7): - resolution: {integrity: sha512-EB2MELswq55OHUoRZLGg/zC7QWUKfNLpE57m/S2yr1uEneIgsTgrSzXP3NXEsMkVn76OlaVVnzN+ugObuYGwhg==} + /@babel/plugin-transform-typeof-symbol@7.24.8(@babel/core@7.25.2): + resolution: {integrity: sha512-adNTUpDCVnmAE58VEqKlAA6ZBlNkMnWD0ZcW76lyNFN3MJniyGFZfNwERVk8Ap56MCnXztmDr19T4mPTztcuaw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.22.5 + '@babel/core': 7.25.2 + '@babel/helper-plugin-utils': 7.24.8 dev: true - /@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.23.7): - resolution: {integrity: sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==} + /@babel/plugin-transform-typescript@7.25.2(@babel/core@7.25.2): + resolution: {integrity: sha512-lBwRvjSmqiMYe/pS0+1gggjJleUJi7NzjvQ1Fkqtt69hBa/0t1YuW/MLQMAPixfwaQOHUXsd6jeU3Z+vdGv3+A==} + engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.22.5 + '@babel/core': 7.25.2 + '@babel/helper-annotate-as-pure': 7.24.7 + '@babel/helper-create-class-features-plugin': 7.25.4(@babel/core@7.25.2) + '@babel/helper-plugin-utils': 7.24.8 + '@babel/helper-skip-transparent-expression-wrappers': 7.24.7 + '@babel/plugin-syntax-typescript': 7.25.4(@babel/core@7.25.2) + transitivePeerDependencies: + - supports-color dev: true - /@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.23.7): - resolution: {integrity: sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==} + /@babel/plugin-transform-unicode-escapes@7.24.7(@babel/core@7.25.2): + resolution: {integrity: sha512-U3ap1gm5+4edc2Q/P+9VrBNhGkfnf+8ZqppY71Bo/pzZmXhhLdqgaUl6cuB07O1+AQJtCLfaOmswiNbSQ9ivhw==} + engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.22.5 + '@babel/core': 7.25.2 + '@babel/helper-plugin-utils': 7.24.8 dev: true - /@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.23.7): - resolution: {integrity: sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==} + /@babel/plugin-transform-unicode-property-regex@7.24.7(@babel/core@7.25.2): + resolution: {integrity: sha512-uH2O4OV5M9FZYQrwc7NdVmMxQJOCCzFeYudlZSzUAHRFeOujQefa92E74TQDVskNHCzOXoigEuoyzHDhaEaK5w==} + engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.22.5 + '@babel/core': 7.25.2 + '@babel/helper-create-regexp-features-plugin': 7.25.2(@babel/core@7.25.2) + '@babel/helper-plugin-utils': 7.24.8 dev: true - /@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.23.7): - resolution: {integrity: sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==} + /@babel/plugin-transform-unicode-regex@7.24.7(@babel/core@7.25.2): + resolution: {integrity: sha512-hlQ96MBZSAXUq7ltkjtu3FJCCSMx/j629ns3hA3pXnBXjanNP0LHi+JpPeA81zaWgVK1VGH95Xuy7u0RyQ8kMg==} + engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.22.5 + '@babel/core': 7.25.2 + '@babel/helper-create-regexp-features-plugin': 7.25.2(@babel/core@7.25.2) + '@babel/helper-plugin-utils': 7.24.8 dev: true - /@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.23.7): - resolution: {integrity: sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==} + /@babel/plugin-transform-unicode-sets-regex@7.25.4(@babel/core@7.25.2): + resolution: {integrity: sha512-qesBxiWkgN1Q+31xUE9RcMk79eOXXDCv6tfyGMRSs4RGlioSg2WVyQAm07k726cSE56pa+Kb0y9epX2qaXzTvA==} + engines: {node: '>=6.9.0'} peerDependencies: - '@babel/core': ^7.0.0-0 + '@babel/core': ^7.0.0 dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.22.5 + '@babel/core': 7.25.2 + '@babel/helper-create-regexp-features-plugin': 7.25.2(@babel/core@7.25.2) + '@babel/helper-plugin-utils': 7.24.8 dev: true - /@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.23.7): - resolution: {integrity: sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==} + /@babel/preset-env@7.25.4(@babel/core@7.25.2): + resolution: {integrity: sha512-W9Gyo+KmcxjGahtt3t9fb14vFRWvPpu5pT6GBlovAK6BTBcxgjfVMSQCfJl4oi35ODrxP6xx2Wr8LNST57Mraw==} + engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.22.5 + '@babel/compat-data': 7.25.4 + '@babel/core': 7.25.2 + '@babel/helper-compilation-targets': 7.25.2 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/helper-validator-option': 7.24.8 + '@babel/plugin-bugfix-firefox-class-in-computed-class-key': 7.25.3(@babel/core@7.25.2) + '@babel/plugin-bugfix-safari-class-field-initializer-scope': 7.25.0(@babel/core@7.25.2) + '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression': 7.25.0(@babel/core@7.25.2) + '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining': 7.24.7(@babel/core@7.25.2) + '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly': 7.25.0(@babel/core@7.25.2) + '@babel/plugin-proposal-private-property-in-object': 7.21.0-placeholder-for-preset-env.2(@babel/core@7.25.2) + '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.25.2) + '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.25.2) + '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.25.2) + '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.25.2) + '@babel/plugin-syntax-export-namespace-from': 7.8.3(@babel/core@7.25.2) + '@babel/plugin-syntax-import-assertions': 7.25.6(@babel/core@7.25.2) + '@babel/plugin-syntax-import-attributes': 7.25.6(@babel/core@7.25.2) + '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.25.2) + '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.25.2) + '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.25.2) + '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.25.2) + '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.25.2) + '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.25.2) + '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.25.2) + '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.25.2) + '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.25.2) + '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.25.2) + '@babel/plugin-syntax-unicode-sets-regex': 7.18.6(@babel/core@7.25.2) + '@babel/plugin-transform-arrow-functions': 7.24.7(@babel/core@7.25.2) + '@babel/plugin-transform-async-generator-functions': 7.25.4(@babel/core@7.25.2) + '@babel/plugin-transform-async-to-generator': 7.24.7(@babel/core@7.25.2) + '@babel/plugin-transform-block-scoped-functions': 7.24.7(@babel/core@7.25.2) + '@babel/plugin-transform-block-scoping': 7.25.0(@babel/core@7.25.2) + '@babel/plugin-transform-class-properties': 7.25.4(@babel/core@7.25.2) + '@babel/plugin-transform-class-static-block': 7.24.7(@babel/core@7.25.2) + '@babel/plugin-transform-classes': 7.25.4(@babel/core@7.25.2) + '@babel/plugin-transform-computed-properties': 7.24.7(@babel/core@7.25.2) + '@babel/plugin-transform-destructuring': 7.24.8(@babel/core@7.25.2) + '@babel/plugin-transform-dotall-regex': 7.24.7(@babel/core@7.25.2) + '@babel/plugin-transform-duplicate-keys': 7.24.7(@babel/core@7.25.2) + '@babel/plugin-transform-duplicate-named-capturing-groups-regex': 7.25.0(@babel/core@7.25.2) + '@babel/plugin-transform-dynamic-import': 7.24.7(@babel/core@7.25.2) + '@babel/plugin-transform-exponentiation-operator': 7.24.7(@babel/core@7.25.2) + '@babel/plugin-transform-export-namespace-from': 7.24.7(@babel/core@7.25.2) + '@babel/plugin-transform-for-of': 7.24.7(@babel/core@7.25.2) + '@babel/plugin-transform-function-name': 7.25.1(@babel/core@7.25.2) + '@babel/plugin-transform-json-strings': 7.24.7(@babel/core@7.25.2) + '@babel/plugin-transform-literals': 7.25.2(@babel/core@7.25.2) + '@babel/plugin-transform-logical-assignment-operators': 7.24.7(@babel/core@7.25.2) + '@babel/plugin-transform-member-expression-literals': 7.24.7(@babel/core@7.25.2) + '@babel/plugin-transform-modules-amd': 7.24.7(@babel/core@7.25.2) + '@babel/plugin-transform-modules-commonjs': 7.24.8(@babel/core@7.25.2) + '@babel/plugin-transform-modules-systemjs': 7.25.0(@babel/core@7.25.2) + '@babel/plugin-transform-modules-umd': 7.24.7(@babel/core@7.25.2) + '@babel/plugin-transform-named-capturing-groups-regex': 7.24.7(@babel/core@7.25.2) + '@babel/plugin-transform-new-target': 7.24.7(@babel/core@7.25.2) + '@babel/plugin-transform-nullish-coalescing-operator': 7.24.7(@babel/core@7.25.2) + '@babel/plugin-transform-numeric-separator': 7.24.7(@babel/core@7.25.2) + '@babel/plugin-transform-object-rest-spread': 7.24.7(@babel/core@7.25.2) + '@babel/plugin-transform-object-super': 7.24.7(@babel/core@7.25.2) + '@babel/plugin-transform-optional-catch-binding': 7.24.7(@babel/core@7.25.2) + '@babel/plugin-transform-optional-chaining': 7.24.8(@babel/core@7.25.2) + '@babel/plugin-transform-parameters': 7.24.7(@babel/core@7.25.2) + '@babel/plugin-transform-private-methods': 7.25.4(@babel/core@7.25.2) + '@babel/plugin-transform-private-property-in-object': 7.24.7(@babel/core@7.25.2) + '@babel/plugin-transform-property-literals': 7.24.7(@babel/core@7.25.2) + '@babel/plugin-transform-regenerator': 7.24.7(@babel/core@7.25.2) + '@babel/plugin-transform-reserved-words': 7.24.7(@babel/core@7.25.2) + '@babel/plugin-transform-shorthand-properties': 7.24.7(@babel/core@7.25.2) + '@babel/plugin-transform-spread': 7.24.7(@babel/core@7.25.2) + '@babel/plugin-transform-sticky-regex': 7.24.7(@babel/core@7.25.2) + '@babel/plugin-transform-template-literals': 7.24.7(@babel/core@7.25.2) + '@babel/plugin-transform-typeof-symbol': 7.24.8(@babel/core@7.25.2) + '@babel/plugin-transform-unicode-escapes': 7.24.7(@babel/core@7.25.2) + '@babel/plugin-transform-unicode-property-regex': 7.24.7(@babel/core@7.25.2) + '@babel/plugin-transform-unicode-regex': 7.24.7(@babel/core@7.25.2) + '@babel/plugin-transform-unicode-sets-regex': 7.25.4(@babel/core@7.25.2) + '@babel/preset-modules': 0.1.6-no-external-plugins(@babel/core@7.25.2) + babel-plugin-polyfill-corejs2: 0.4.11(@babel/core@7.25.2) + babel-plugin-polyfill-corejs3: 0.10.6(@babel/core@7.25.2) + babel-plugin-polyfill-regenerator: 0.6.2(@babel/core@7.25.2) + core-js-compat: 3.38.1 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color dev: true - /@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.23.7): - resolution: {integrity: sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==} + /@babel/preset-modules@0.1.6-no-external-plugins(@babel/core@7.25.2): + resolution: {integrity: sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==} + peerDependencies: + '@babel/core': ^7.0.0-0 || ^8.0.0-0 <8.0.0 + dependencies: + '@babel/core': 7.25.2 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/types': 7.25.6 + esutils: 2.0.3 + dev: true + + /@babel/preset-react@7.24.7(@babel/core@7.25.2): + resolution: {integrity: sha512-AAH4lEkpmzFWrGVlHaxJB7RLH21uPQ9+He+eFLWHmF9IuFQVugz8eAsamaW0DXRrTfco5zj1wWtpdcXJUOfsag==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.22.5 + '@babel/core': 7.25.2 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/helper-validator-option': 7.24.8 + '@babel/plugin-transform-react-display-name': 7.24.7(@babel/core@7.25.2) + '@babel/plugin-transform-react-jsx': 7.25.2(@babel/core@7.25.2) + '@babel/plugin-transform-react-jsx-development': 7.24.7(@babel/core@7.25.2) + '@babel/plugin-transform-react-pure-annotations': 7.24.7(@babel/core@7.25.2) + transitivePeerDependencies: + - supports-color dev: true - /@babel/plugin-syntax-typescript@7.23.3(@babel/core@7.23.7): - resolution: {integrity: sha512-9EiNjVJOMwCO+43TqoTrgQ8jMwcAd0sWyXi9RPfIsLTj4R2MADDDQXELhffaUx/uJv2AYcxBgPwH6j4TIA4ytQ==} + /@babel/preset-typescript@7.24.7(@babel/core@7.25.2): + resolution: {integrity: sha512-SyXRe3OdWwIwalxDg5UtJnJQO+YPcTfwiIY2B0Xlddh9o7jpWLvv8X1RthIeDOxQ+O1ML5BLPCONToObyVQVuQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.22.5 + '@babel/core': 7.25.2 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/helper-validator-option': 7.24.8 + '@babel/plugin-syntax-jsx': 7.24.7(@babel/core@7.25.2) + '@babel/plugin-transform-modules-commonjs': 7.24.8(@babel/core@7.25.2) + '@babel/plugin-transform-typescript': 7.25.2(@babel/core@7.25.2) + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/regjsgen@0.8.0: + resolution: {integrity: sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==} dev: true - /@babel/runtime@7.23.8: - resolution: {integrity: sha512-Y7KbAP984rn1VGMbGqKmBLio9V7y5Je9GvU4rQPCPinCyNfUcToxIXl06d59URp/F3LwinvODxab5N/G6qggkw==} + /@babel/runtime@7.25.6: + resolution: {integrity: sha512-VBj9MYyDb9tuLq7yzqjgzt6Q+IBQLrGZfdjOekyEirZPHxXWoTSGUTMrpsfi58Up73d13NfYLv8HT9vmznjzhQ==} engines: {node: '>=6.9.0'} dependencies: regenerator-runtime: 0.14.1 - /@babel/template@7.22.15: - resolution: {integrity: sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==} + /@babel/template@7.25.0: + resolution: {integrity: sha512-aOOgh1/5XzKvg1jvVz7AVrx2piJ2XBi227DHmbY6y+bM9H2FlN+IfecYu4Xl0cNiiVejlsCri89LUsbj8vJD9Q==} engines: {node: '>=6.9.0'} dependencies: - '@babel/code-frame': 7.23.5 - '@babel/parser': 7.23.6 - '@babel/types': 7.23.6 + '@babel/code-frame': 7.24.7 + '@babel/parser': 7.25.6 + '@babel/types': 7.25.6 dev: true - /@babel/traverse@7.23.7: - resolution: {integrity: sha512-tY3mM8rH9jM0YHFGyfC0/xf+SB5eKUu7HPj7/k3fpi9dAlsMc5YbQvDi0Sh2QTPXqMhyaAtzAr807TIyfQrmyg==} + /@babel/traverse@7.25.6: + resolution: {integrity: sha512-9Vrcx5ZW6UwK5tvqsj0nGpp/XzqthkT0dqIc9g1AdtygFToNtTF67XzYS//dm+SAK9cp3B9R4ZO/46p63SCjlQ==} engines: {node: '>=6.9.0'} dependencies: - '@babel/code-frame': 7.23.5 - '@babel/generator': 7.23.6 - '@babel/helper-environment-visitor': 7.22.20 - '@babel/helper-function-name': 7.23.0 - '@babel/helper-hoist-variables': 7.22.5 - '@babel/helper-split-export-declaration': 7.22.6 - '@babel/parser': 7.23.6 - '@babel/types': 7.23.6 - debug: 4.3.4 + '@babel/code-frame': 7.24.7 + '@babel/generator': 7.25.6 + '@babel/parser': 7.25.6 + '@babel/template': 7.25.0 + '@babel/types': 7.25.6 + debug: 4.3.7 globals: 11.12.0 transitivePeerDependencies: - supports-color dev: true - /@babel/types@7.23.6: - resolution: {integrity: sha512-+uarb83brBzPKN38NX1MkB6vb6+mwvR6amUulqAE7ccQw1pEl+bCia9TbdG1lsnFP7lZySvUn37CHyXQdfTwzg==} + /@babel/types@7.25.6: + resolution: {integrity: sha512-/l42B1qxpG6RdfYf343Uw1vmDjeNhneUXtzhojE7pDgfpEypmRhI6j1kr17XCVv4Cgl9HdAiQY2x0GwKm7rWCw==} engines: {node: '>=6.9.0'} dependencies: - '@babel/helper-string-parser': 7.23.4 - '@babel/helper-validator-identifier': 7.22.20 + '@babel/helper-string-parser': 7.24.8 + '@babel/helper-validator-identifier': 7.24.7 to-fast-properties: 2.0.0 dev: true @@ -484,29 +1504,34 @@ packages: resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==} dev: true - /@emotion/hash@0.9.1: - resolution: {integrity: sha512-gJB6HLm5rYwSLI6PQa+X1t5CFGrv1J1TWG+sOyMCeKz2ojaj6Fnl/rZEspogG+cvqbt4AE/2eIyD2QfLKTBNlQ==} + /@emotion/hash@0.9.2: + resolution: {integrity: sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g==} dev: false - /@eslint-community/eslint-utils@4.4.0(eslint@8.15.0): + /@eslint-community/eslint-utils@4.4.0(eslint@8.57.1): resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 dependencies: - eslint: 8.15.0 + eslint: 8.57.1 eslint-visitor-keys: 3.4.3 dev: true - /@eslint/eslintrc@1.4.1: - resolution: {integrity: sha512-XXrH9Uarn0stsyldqDYq8r++mROmWRI1xKMXa640Bb//SY1+ECYX6VzT6Lcx5frD0V30XieqJ0oX9I2Xj5aoMA==} + /@eslint-community/regexpp@4.11.1: + resolution: {integrity: sha512-m4DVN9ZqskZoLU5GlWZadwDnYo3vAEydiUayB9widCl9ffWx2IvPnp6n3on5rJmziJSw9Bv+Z3ChDVdMwXCY8Q==} + engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} + dev: true + + /@eslint/eslintrc@2.1.4: + resolution: {integrity: sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dependencies: ajv: 6.12.6 - debug: 4.3.4 + debug: 4.3.7 espree: 9.6.1 globals: 13.24.0 - ignore: 5.3.0 + ignore: 5.3.2 import-fresh: 3.3.0 js-yaml: 4.1.0 minimatch: 3.1.2 @@ -515,149 +1540,157 @@ packages: - supports-color dev: true - /@floating-ui/core@1.5.3: - resolution: {integrity: sha512-O0WKDOo0yhJuugCx6trZQj5jVJ9yR0ystG2JaNAemYUWce+pmM6WUEFIibnWyEJKdrDxhm75NoSRME35FNaM/Q==} + /@eslint/js@8.57.1: + resolution: {integrity: sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dev: true + + /@floating-ui/core@1.6.8: + resolution: {integrity: sha512-7XJ9cPU+yI2QeLS+FCSlqNFZJq8arvswefkZrYI1yQBbftw6FyrZOxYSh+9S7z7TpeWlRt9zJ5IhM1WIL334jA==} dependencies: - '@floating-ui/utils': 0.2.1 + '@floating-ui/utils': 0.2.8 dev: false - /@floating-ui/devtools@0.2.1(@floating-ui/dom@1.5.4): + /@floating-ui/devtools@0.2.1(@floating-ui/dom@1.6.11): resolution: {integrity: sha512-8PHJLbD6VhBh+LJ1uty/Bz30qs02NXCE5u8WpOhSewlYXUWl03GNXknr9AS2yaAWJEQaY27x7eByJs44gODBcw==} peerDependencies: '@floating-ui/dom': '>=1.5.4' dependencies: - '@floating-ui/dom': 1.5.4 + '@floating-ui/dom': 1.6.11 dev: false - /@floating-ui/dom@1.5.4: - resolution: {integrity: sha512-jByEsHIY+eEdCjnTVu+E3ephzTOzkQ8hgUfGwos+bg7NlH33Zc5uO+QHz1mrQUOgIKKDD1RtS201P9NvAfq3XQ==} + /@floating-ui/dom@1.6.11: + resolution: {integrity: sha512-qkMCxSR24v2vGkhYDo/UzxfJN3D4syqSjyuTFz6C7XcpU1pASPRieNI0Kj5VP3/503mOfYiGY891ugBX1GlABQ==} dependencies: - '@floating-ui/core': 1.5.3 - '@floating-ui/utils': 0.2.1 + '@floating-ui/core': 1.6.8 + '@floating-ui/utils': 0.2.8 dev: false - /@floating-ui/utils@0.2.1: - resolution: {integrity: sha512-9TANp6GPoMtYzQdt54kfAyMmz1+osLlXdg2ENroU7zzrtflTLrrC/lgrIfaSe+Wu0b89GKccT7vxXA0MoAIO+Q==} + /@floating-ui/utils@0.2.8: + resolution: {integrity: sha512-kym7SodPp8/wloecOpcmSnWJsK7M0E5Wg8UcFA+uO4B9s5d0ywXOEro/8HM9x0rW+TljRzul/14UYz3TleT3ig==} dev: false - /@fluentui/date-time-utilities@8.5.16: - resolution: {integrity: sha512-l+mLfJ2VhdHjBpELLLPDaWgT7GMLynm2aqR7SttbEb6Jh7hc/7ck1MWm93RTb3gYVHYai8SENqimNcvIxHt/zg==} + /@fluentui/date-time-utilities@8.6.9: + resolution: {integrity: sha512-dgOlVm4nXBWDLqijmvn4iAtyv1hVpQZjN6p0So74BW+7ASUTkQGe3lf8PHV/OjBiXfZa4qwONvmTQBGCheNU0w==} dependencies: - '@fluentui/set-version': 8.2.14 - tslib: 2.6.1 + '@fluentui/set-version': 8.2.23 + tslib: 2.7.0 dev: false - /@fluentui/dom-utilities@2.2.14: - resolution: {integrity: sha512-+4DVm5sNfJh+l8fM+7ylpOkGNZkNr4X1z1uKQPzRJ1PRhlnvc6vLpWNNicGwpjTbgufSrVtGKXwP5sf++r81lg==} + /@fluentui/dom-utilities@2.3.7: + resolution: {integrity: sha512-AaTR9BhJEF0i042NS1Ju8l95f24p2tBMq6jVVbUEDtYnKaxWnpv8R9eYjOwy8SDniQc1ino+BkolIgCVXXvDmw==} dependencies: - '@fluentui/set-version': 8.2.14 - tslib: 2.6.1 + '@fluentui/set-version': 8.2.23 + tslib: 2.7.0 dev: false - /@fluentui/font-icons-mdl2@8.5.31(@types/react@18.0.0)(react@18.2.0): - resolution: {integrity: sha512-jioHZ9XUfR9vUT5XnxdCrJ+hoC9TpYim+4YdtlUE/euI8kdW1tDZ5zqlSNk1GLDR34n03R09yWj5gVDCcMJbyQ==} + /@fluentui/font-icons-mdl2@8.5.50(@types/react@18.3.9)(react@18.3.1): + resolution: {integrity: sha512-04pRRmuBf9r/3cnBlIedF+SFk2UW7GdRQvdfKxoMuL4dDMLPqo4ruPkI/dz8Mp3EDERQU01XDWtBx11w9obmFQ==} dependencies: - '@fluentui/set-version': 8.2.14 - '@fluentui/style-utilities': 8.10.2(@types/react@18.0.0)(react@18.2.0) - '@fluentui/utilities': 8.13.24(@types/react@18.0.0)(react@18.2.0) - tslib: 2.6.1 + '@fluentui/set-version': 8.2.23 + '@fluentui/style-utilities': 8.10.21(@types/react@18.3.9)(react@18.3.1) + '@fluentui/utilities': 8.15.15(@types/react@18.3.9)(react@18.3.1) + tslib: 2.7.0 transitivePeerDependencies: - '@types/react' - react dev: false - /@fluentui/foundation-legacy@8.2.51(@types/react@18.0.0)(react@18.2.0): - resolution: {integrity: sha512-z/jrp1imV66/D2MGpN/55LGk/Istymk5tN+XUFHDENDi+9zyb2MgSxFshp774DJIrg3vVlyuS8oo+dBuTM3UbQ==} + /@fluentui/foundation-legacy@8.4.16(@types/react@18.3.9)(react@18.3.1): + resolution: {integrity: sha512-01/uQPQ2pEkQ6nUUF+tXaYeOG8UssfoEgAVLPolYXr1DC4tT66hPi7Smgsh6tzUkt/Ljy0nw9TIMRoHDHlfRyg==} peerDependencies: '@types/react': '>=16.8.0 <19.0.0' react: '>=16.8.0 <19.0.0' dependencies: - '@fluentui/merge-styles': 8.5.15 - '@fluentui/set-version': 8.2.14 - '@fluentui/style-utilities': 8.10.2(@types/react@18.0.0)(react@18.2.0) - '@fluentui/utilities': 8.13.24(@types/react@18.0.0)(react@18.2.0) - '@types/react': 18.0.0 - react: 18.2.0 - tslib: 2.6.1 + '@fluentui/merge-styles': 8.6.13 + '@fluentui/set-version': 8.2.23 + '@fluentui/style-utilities': 8.10.21(@types/react@18.3.9)(react@18.3.1) + '@fluentui/utilities': 8.15.15(@types/react@18.3.9)(react@18.3.1) + '@types/react': 18.3.9 + react: 18.3.1 + tslib: 2.7.0 dev: false - /@fluentui/keyboard-key@0.4.14: - resolution: {integrity: sha512-XzZHcyFEM20H23h3i15UpkHi2AhRBriXPGAHq0Jm98TKFppXehedjjEFuUsh+CyU5JKBhDalWp8TAQ1ArpNzow==} + /@fluentui/keyboard-key@0.4.23: + resolution: {integrity: sha512-9GXeyUqNJUdg5JiQUZeGPiKnRzMRi9YEUn1l9zq6X/imYdMhxHrxpVZS12129cBfgvPyxt9ceJpywSfmLWqlKA==} dependencies: - tslib: 2.6.1 + tslib: 2.7.0 dev: false /@fluentui/keyboard-keys@9.0.7: resolution: {integrity: sha512-vaQ+lOveQTdoXJYqDQXWb30udSfTVcIuKk1rV0X0eGAgcHeSDeP1HxMy+OgHOQZH3OiBH4ZYeWxb+tmfiDiygQ==} dependencies: - '@swc/helpers': 0.5.3 + '@swc/helpers': 0.5.13 dev: false - /@fluentui/merge-styles@8.5.15: - resolution: {integrity: sha512-4CdKwo4k1Un2QLulpSVIz/KMgLNBMgin4NPyapmKDMVuO1OOxJUqfocubRGNO5x9mKgAMMYwBKGO9i0uxMMpJw==} + /@fluentui/merge-styles@8.6.13: + resolution: {integrity: sha512-IWgvi2CC+mcQ7/YlCvRjsmHL2+PUz7q+Pa2Rqk3a+QHN0V1uBvgIbKk5y/Y/awwDXy1yJHiqMCcDHjBNmS1d4A==} dependencies: - '@fluentui/set-version': 8.2.14 - tslib: 2.6.1 + '@fluentui/set-version': 8.2.23 + tslib: 2.7.0 dev: false - /@fluentui/priority-overflow@9.1.11: - resolution: {integrity: sha512-sdrpavvKX2kepQ1d6IaI3ObLq5SAQBPRHPGx2+wiMWL7cEx9vGGM0fmeicl3soqqmM5uwCmWnZk9QZv9XOY98w==} + /@fluentui/priority-overflow@9.1.13: + resolution: {integrity: sha512-yDojVpkhBZTXOYExrCgW1GXbw3x9pYIS617xlNJIc2t06Cd3H32y2p51QXFt94sBmlVyAvPu7UKBHaq1Yw7u+w==} dependencies: - '@swc/helpers': 0.5.3 + '@swc/helpers': 0.5.13 dev: false - /@fluentui/react-accordion@9.3.39(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0)(scheduler@0.20.2): - resolution: {integrity: sha512-5FkwvwdVyN9TcA9MeWu/673dCOTVQkwZhzGaentJFe1fMEK1cTCLKtqmYtzqjzm47xMiiVdxtDhN5Z/PU9GbtQ==} + /@fluentui/react-accordion@9.5.5(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1)(scheduler@0.23.0): + resolution: {integrity: sha512-4zwtmZTcD2jgjxbMTHajhMxRNkFFHIXG060dSVoK73H4vWLKtDYuwQJesfgi2swUim+xhemvcInrLXIoY8pLZw==} peerDependencies: '@types/react': '>=16.14.0 <19.0.0' '@types/react-dom': '>=16.9.0 <19.0.0' react: '>=16.14.0 <19.0.0' react-dom: '>=16.14.0 <19.0.0' - scheduler: ^0.19.0 || ^0.20.0 - dependencies: - '@fluentui/react-aria': 9.8.0(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0) - '@fluentui/react-context-selector': 9.1.50(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0)(scheduler@0.20.2) - '@fluentui/react-icons': 2.0.225(react@18.2.0) - '@fluentui/react-jsx-runtime': 9.0.28(@types/react@18.0.0)(react@18.2.0) - '@fluentui/react-shared-contexts': 9.14.0(@types/react@18.0.0)(react@18.2.0) - '@fluentui/react-tabster': 9.17.4(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0) - '@fluentui/react-theme': 9.1.16 - '@fluentui/react-utilities': 9.17.0(@types/react@18.0.0)(react@18.2.0) - '@griffel/react': 1.5.20(react@18.2.0) - '@swc/helpers': 0.5.3 - '@types/react': 18.0.0 - '@types/react-dom': 18.0.0 - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) - scheduler: 0.20.2 + dependencies: + '@fluentui/react-aria': 9.13.6(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1) + '@fluentui/react-context-selector': 9.1.67(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1)(scheduler@0.23.0) + '@fluentui/react-icons': 2.0.258(react@18.3.1) + '@fluentui/react-jsx-runtime': 9.0.44(@types/react@18.3.9)(react@18.3.1) + '@fluentui/react-motion': 9.5.2(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1) + '@fluentui/react-motion-components-preview': 0.1.4(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1) + '@fluentui/react-shared-contexts': 9.20.1(@types/react@18.3.9)(react@18.3.1) + '@fluentui/react-tabster': 9.22.7(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1) + '@fluentui/react-theme': 9.1.20 + '@fluentui/react-utilities': 9.18.15(@types/react@18.3.9)(react@18.3.1) + '@griffel/react': 1.5.25(react@18.3.1) + '@swc/helpers': 0.5.13 + '@types/react': 18.3.9 + '@types/react-dom': 18.3.0 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + transitivePeerDependencies: + - scheduler dev: false - /@fluentui/react-alert@9.0.0-beta.31(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0)(scheduler@0.20.2): - resolution: {integrity: sha512-kCvxen8cY1Vrn66IIR077yaA7KkHUCfSHnFPlFgLtaF82/hPIIWpb3floaWyEfUstCKspeBGDE3OJnD/Lqlqyg==} + /@fluentui/react-alert@9.0.0-beta.124(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1)(scheduler@0.23.0): + resolution: {integrity: sha512-yFBo3B5H9hnoaXxlkuz8wRz04DEyQ+ElYA/p5p+Vojf19Zuta8DmFZZ6JtWdtxcdnnQ4LvAfC5OYYlzdReozPA==} peerDependencies: - '@types/react': '>=16.8.0 <19.0.0' - '@types/react-dom': '>=16.8.0 <19.0.0' - react: '>=16.8.0 <19.0.0' - react-dom: '>=16.8.0 <19.0.0' + '@types/react': '>=16.14.0 <19.0.0' + '@types/react-dom': '>=16.9.0 <19.0.0' + react: '>=16.14.0 <19.0.0' + react-dom: '>=16.14.0 <19.0.0' dependencies: - '@fluentui/react-avatar': 9.6.10(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0)(scheduler@0.20.2) - '@fluentui/react-button': 9.3.66(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0) - '@fluentui/react-icons': 2.0.225(react@18.2.0) - '@fluentui/react-tabster': 9.17.4(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0) - '@fluentui/react-theme': 9.1.16 - '@fluentui/react-utilities': 9.17.0(@types/react@18.0.0)(react@18.2.0) - '@griffel/react': 1.5.20(react@18.2.0) - '@types/react': 18.0.0 - '@types/react-dom': 18.0.0 - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) - tslib: 2.6.1 + '@fluentui/react-avatar': 9.6.39(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1)(scheduler@0.23.0) + '@fluentui/react-button': 9.3.92(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1) + '@fluentui/react-icons': 2.0.258(react@18.3.1) + '@fluentui/react-jsx-runtime': 9.0.44(@types/react@18.3.9)(react@18.3.1) + '@fluentui/react-tabster': 9.22.7(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1) + '@fluentui/react-theme': 9.1.20 + '@fluentui/react-utilities': 9.18.15(@types/react@18.3.9)(react@18.3.1) + '@griffel/react': 1.5.25(react@18.3.1) + '@swc/helpers': 0.5.13 + '@types/react': 18.3.9 + '@types/react-dom': 18.3.0 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) transitivePeerDependencies: - scheduler dev: false - /@fluentui/react-aria@9.8.0(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-fnnwGXpS/8oh8O4vpQjh5R1rg0dT9mTk85pSdA9F7kz4KOoLW5byREHvXTsYgpiibBhXzipFxLunx5vDzC/g6w==} + /@fluentui/react-aria@9.13.6(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1): + resolution: {integrity: sha512-/bepLd2SKL+WHhiHJ8O/Lt+1FxvVeGB+pgbUuSjtPVwafwcA4RNXVlkMQaoYk8sQvnG4oqVa4ToTxUWURaOeNA==} peerDependencies: '@types/react': '>=16.14.0 <19.0.0' '@types/react-dom': '>=16.9.0 <19.0.0' @@ -665,67 +1698,93 @@ packages: react-dom: '>=16.14.0 <19.0.0' dependencies: '@fluentui/keyboard-keys': 9.0.7 - '@fluentui/react-shared-contexts': 9.14.0(@types/react@18.0.0)(react@18.2.0) - '@fluentui/react-tabster': 9.17.4(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0) - '@fluentui/react-utilities': 9.17.0(@types/react@18.0.0)(react@18.2.0) - '@swc/helpers': 0.5.3 - '@types/react': 18.0.0 - '@types/react-dom': 18.0.0 - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) + '@fluentui/react-jsx-runtime': 9.0.44(@types/react@18.3.9)(react@18.3.1) + '@fluentui/react-shared-contexts': 9.20.1(@types/react@18.3.9)(react@18.3.1) + '@fluentui/react-tabster': 9.22.7(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1) + '@fluentui/react-utilities': 9.18.15(@types/react@18.3.9)(react@18.3.1) + '@swc/helpers': 0.5.13 + '@types/react': 18.3.9 + '@types/react-dom': 18.3.0 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) dev: false - /@fluentui/react-avatar@9.6.10(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0)(scheduler@0.20.2): - resolution: {integrity: sha512-D2NS5+cuWFcvFKyXnG++bKnwxmfYtV7LNL3Sh0adTF4MCGixhmrTlD6aprI5FVQnddexAWK0/Hc1asNDafm9VQ==} + /@fluentui/react-avatar@9.6.39(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1)(scheduler@0.23.0): + resolution: {integrity: sha512-of2XMrwTZ4xKsiPEgayJupeI29dAiNBbWos4MCzBJaBS6u9BcaHRenSyzDFViC4jFyvoJQDqftWYThaSwH3PHw==} peerDependencies: '@types/react': '>=16.14.0 <19.0.0' '@types/react-dom': '>=16.9.0 <19.0.0' react: '>=16.14.0 <19.0.0' react-dom: '>=16.14.0 <19.0.0' - scheduler: ^0.19.0 || ^0.20.0 - dependencies: - '@fluentui/react-badge': 9.2.23(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0) - '@fluentui/react-context-selector': 9.1.50(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0)(scheduler@0.20.2) - '@fluentui/react-icons': 2.0.225(react@18.2.0) - '@fluentui/react-jsx-runtime': 9.0.28(@types/react@18.0.0)(react@18.2.0) - '@fluentui/react-popover': 9.8.34(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0)(scheduler@0.20.2) - '@fluentui/react-shared-contexts': 9.14.0(@types/react@18.0.0)(react@18.2.0) - '@fluentui/react-tabster': 9.17.4(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0) - '@fluentui/react-theme': 9.1.16 - '@fluentui/react-tooltip': 9.4.12(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0) - '@fluentui/react-utilities': 9.17.0(@types/react@18.0.0)(react@18.2.0) - '@griffel/react': 1.5.20(react@18.2.0) - '@swc/helpers': 0.5.3 - '@types/react': 18.0.0 - '@types/react-dom': 18.0.0 - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) - scheduler: 0.20.2 + dependencies: + '@fluentui/react-badge': 9.2.43(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1) + '@fluentui/react-context-selector': 9.1.67(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1)(scheduler@0.23.0) + '@fluentui/react-icons': 2.0.258(react@18.3.1) + '@fluentui/react-jsx-runtime': 9.0.44(@types/react@18.3.9)(react@18.3.1) + '@fluentui/react-popover': 9.9.21(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1)(scheduler@0.23.0) + '@fluentui/react-shared-contexts': 9.20.1(@types/react@18.3.9)(react@18.3.1) + '@fluentui/react-tabster': 9.22.7(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1) + '@fluentui/react-theme': 9.1.20 + '@fluentui/react-tooltip': 9.4.39(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1) + '@fluentui/react-utilities': 9.18.15(@types/react@18.3.9)(react@18.3.1) + '@griffel/react': 1.5.25(react@18.3.1) + '@swc/helpers': 0.5.13 + '@types/react': 18.3.9 + '@types/react-dom': 18.3.0 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + transitivePeerDependencies: + - scheduler + dev: false + + /@fluentui/react-badge@9.2.43(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1): + resolution: {integrity: sha512-E+J08RIj2UZ5daq1kN+IgOCf5x4VVnFQTO+XI2bXsqoc/6wFHS2FZ8I7pNQqkWbvZ6cspR7cG7S8RfTR5pQz1Q==} + peerDependencies: + '@types/react': '>=16.14.0 <19.0.0' + '@types/react-dom': '>=16.9.0 <19.0.0' + react: '>=16.14.0 <19.0.0' + react-dom: '>=16.14.0 <19.0.0' + dependencies: + '@fluentui/react-icons': 2.0.258(react@18.3.1) + '@fluentui/react-jsx-runtime': 9.0.44(@types/react@18.3.9)(react@18.3.1) + '@fluentui/react-shared-contexts': 9.20.1(@types/react@18.3.9)(react@18.3.1) + '@fluentui/react-theme': 9.1.20 + '@fluentui/react-utilities': 9.18.15(@types/react@18.3.9)(react@18.3.1) + '@griffel/react': 1.5.25(react@18.3.1) + '@swc/helpers': 0.5.13 + '@types/react': 18.3.9 + '@types/react-dom': 18.3.0 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) dev: false - /@fluentui/react-badge@9.2.23(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-0Fld2A7mCd3l7vKUoU0sm4EqGSkJN8GzduXwxKpl9DV+FWlMLO7K+9hU3o5MzYwHZzrkdHNGX4TwFM7+7pUN3g==} + /@fluentui/react-breadcrumb@9.0.39(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1): + resolution: {integrity: sha512-Y/d3+qwco1WPB/t7BpEES1LIqBrR1A/7r4jdVuNylgiK5OoRRDgRdu7+7ecT0sjnfyhHwv+PnImtXIOnGyKgrQ==} peerDependencies: '@types/react': '>=16.14.0 <19.0.0' '@types/react-dom': '>=16.9.0 <19.0.0' react: '>=16.14.0 <19.0.0' react-dom: '>=16.14.0 <19.0.0' dependencies: - '@fluentui/react-icons': 2.0.225(react@18.2.0) - '@fluentui/react-jsx-runtime': 9.0.28(@types/react@18.0.0)(react@18.2.0) - '@fluentui/react-shared-contexts': 9.14.0(@types/react@18.0.0)(react@18.2.0) - '@fluentui/react-theme': 9.1.16 - '@fluentui/react-utilities': 9.17.0(@types/react@18.0.0)(react@18.2.0) - '@griffel/react': 1.5.20(react@18.2.0) - '@swc/helpers': 0.5.3 - '@types/react': 18.0.0 - '@types/react-dom': 18.0.0 - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) + '@fluentui/react-aria': 9.13.6(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1) + '@fluentui/react-button': 9.3.92(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1) + '@fluentui/react-icons': 2.0.258(react@18.3.1) + '@fluentui/react-jsx-runtime': 9.0.44(@types/react@18.3.9)(react@18.3.1) + '@fluentui/react-link': 9.2.32(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1) + '@fluentui/react-shared-contexts': 9.20.1(@types/react@18.3.9)(react@18.3.1) + '@fluentui/react-tabster': 9.22.7(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1) + '@fluentui/react-theme': 9.1.20 + '@fluentui/react-utilities': 9.18.15(@types/react@18.3.9)(react@18.3.1) + '@griffel/react': 1.5.25(react@18.3.1) + '@swc/helpers': 0.5.13 + '@types/react': 18.3.9 + '@types/react-dom': 18.3.0 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) dev: false - /@fluentui/react-button@9.3.66(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-HOehSai3c4J1Y1KLjaP5FSzsSBeVKqI1stW2cpYkzBoxJZXHWbLAW8K9O7pvK/WJft1JfANgh0rgsfMk74jfvA==} + /@fluentui/react-button@9.3.92(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1): + resolution: {integrity: sha512-awMMtr3MnXB5Q8ItYJ6s4k5U3RKJImm8qAh0Zm/quK1Aj62fKa4Ro/P+dMzKhi+86VmE9wqVwWr9vim/MHGgow==} peerDependencies: '@types/react': '>=16.14.0 <19.0.0' '@types/react-dom': '>=16.9.0 <19.0.0' @@ -733,175 +1792,193 @@ packages: react-dom: '>=16.14.0 <19.0.0' dependencies: '@fluentui/keyboard-keys': 9.0.7 - '@fluentui/react-aria': 9.8.0(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0) - '@fluentui/react-icons': 2.0.225(react@18.2.0) - '@fluentui/react-jsx-runtime': 9.0.28(@types/react@18.0.0)(react@18.2.0) - '@fluentui/react-shared-contexts': 9.14.0(@types/react@18.0.0)(react@18.2.0) - '@fluentui/react-tabster': 9.17.4(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0) - '@fluentui/react-theme': 9.1.16 - '@fluentui/react-utilities': 9.17.0(@types/react@18.0.0)(react@18.2.0) - '@griffel/react': 1.5.20(react@18.2.0) - '@swc/helpers': 0.5.3 - '@types/react': 18.0.0 - '@types/react-dom': 18.0.0 - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) + '@fluentui/react-aria': 9.13.6(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1) + '@fluentui/react-icons': 2.0.258(react@18.3.1) + '@fluentui/react-jsx-runtime': 9.0.44(@types/react@18.3.9)(react@18.3.1) + '@fluentui/react-shared-contexts': 9.20.1(@types/react@18.3.9)(react@18.3.1) + '@fluentui/react-tabster': 9.22.7(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1) + '@fluentui/react-theme': 9.1.20 + '@fluentui/react-utilities': 9.18.15(@types/react@18.3.9)(react@18.3.1) + '@griffel/react': 1.5.25(react@18.3.1) + '@swc/helpers': 0.5.13 + '@types/react': 18.3.9 + '@types/react-dom': 18.3.0 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) dev: false - /@fluentui/react-card@9.0.0-beta.44(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-vDO9LbGhkKaHUC/4/MuBeKwJbcx2NKxjVmhvLwQmpuWAblXoka26X0xnzuhUha32QMDJEk3Ws7q5GneEgI4j/A==} + /@fluentui/react-card@9.0.94(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1): + resolution: {integrity: sha512-TUzQLdCFcBkESgj6fVRH201OHvYPWB1n8b7unDSX5VjxcnHT8MKu2DWj5KHFmVaEd6sNEgNm58qiAGGjTSvkgg==} peerDependencies: - '@types/react': '>=16.8.0 <19.0.0' - '@types/react-dom': '>=16.8.0 <19.0.0' - react: '>=16.8.0 <19.0.0' - react-dom: '>=16.8.0 <19.0.0' + '@types/react': '>=16.14.0 <19.0.0' + '@types/react-dom': '>=16.9.0 <19.0.0' + react: '>=16.14.0 <19.0.0' + react-dom: '>=16.14.0 <19.0.0' dependencies: '@fluentui/keyboard-keys': 9.0.7 - '@fluentui/react-tabster': 9.17.4(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0) - '@fluentui/react-theme': 9.1.16 - '@fluentui/react-utilities': 9.17.0(@types/react@18.0.0)(react@18.2.0) - '@griffel/react': 1.5.20(react@18.2.0) - '@types/react': 18.0.0 - '@types/react-dom': 18.0.0 - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) - tslib: 2.6.1 + '@fluentui/react-jsx-runtime': 9.0.44(@types/react@18.3.9)(react@18.3.1) + '@fluentui/react-tabster': 9.22.7(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1) + '@fluentui/react-text': 9.4.25(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1) + '@fluentui/react-theme': 9.1.20 + '@fluentui/react-utilities': 9.18.15(@types/react@18.3.9)(react@18.3.1) + '@griffel/react': 1.5.25(react@18.3.1) + '@swc/helpers': 0.5.13 + '@types/react': 18.3.9 + '@types/react-dom': 18.3.0 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) dev: false - /@fluentui/react-checkbox@9.2.9(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0)(scheduler@0.20.2): - resolution: {integrity: sha512-SNLAY+3595Zg0nRa07dRxbmYN0NUIRnawqs+8Z6K1zWxQZdSdjzf2NGwCw+qAX+hBhkjRBXNiMSRezVJYAFg+g==} + /@fluentui/react-checkbox@9.2.37(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1)(scheduler@0.23.0): + resolution: {integrity: sha512-qNJIsZaTqD7vYz547bp14q/nXd5le1bZKApR0NORVf6qLfID0/B5hJ48pUpQV03HrbgBFf8ZiVGzHfwwfHZiLQ==} peerDependencies: '@types/react': '>=16.14.0 <19.0.0' '@types/react-dom': '>=16.9.0 <19.0.0' react: '>=16.14.0 <19.0.0' react-dom: '>=16.14.0 <19.0.0' dependencies: - '@fluentui/react-field': 9.1.51(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0)(scheduler@0.20.2) - '@fluentui/react-icons': 2.0.225(react@18.2.0) - '@fluentui/react-jsx-runtime': 9.0.28(@types/react@18.0.0)(react@18.2.0) - '@fluentui/react-label': 9.1.59(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0) - '@fluentui/react-shared-contexts': 9.14.0(@types/react@18.0.0)(react@18.2.0) - '@fluentui/react-tabster': 9.17.4(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0) - '@fluentui/react-theme': 9.1.16 - '@fluentui/react-utilities': 9.17.0(@types/react@18.0.0)(react@18.2.0) - '@griffel/react': 1.5.20(react@18.2.0) - '@swc/helpers': 0.5.3 - '@types/react': 18.0.0 - '@types/react-dom': 18.0.0 - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) + '@fluentui/react-field': 9.1.76(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1)(scheduler@0.23.0) + '@fluentui/react-icons': 2.0.258(react@18.3.1) + '@fluentui/react-jsx-runtime': 9.0.44(@types/react@18.3.9)(react@18.3.1) + '@fluentui/react-label': 9.1.76(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1) + '@fluentui/react-shared-contexts': 9.20.1(@types/react@18.3.9)(react@18.3.1) + '@fluentui/react-tabster': 9.22.7(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1) + '@fluentui/react-theme': 9.1.20 + '@fluentui/react-utilities': 9.18.15(@types/react@18.3.9)(react@18.3.1) + '@griffel/react': 1.5.25(react@18.3.1) + '@swc/helpers': 0.5.13 + '@types/react': 18.3.9 + '@types/react-dom': 18.3.0 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) transitivePeerDependencies: - scheduler dev: false - /@fluentui/react-combobox@9.7.1(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0)(scheduler@0.20.2): - resolution: {integrity: sha512-mds3Bba2IbzgJFmJfDxjtjCoIGSGDOeBcOtD7sBycl3kECGLq4oKoSdihCn95+YvYa+iNF78HO/cBIsj+Ehkdw==} + /@fluentui/react-combobox@9.13.8(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1)(scheduler@0.23.0): + resolution: {integrity: sha512-+QuiFt1P93JwjtAy2b0cXah9BT0h9I2T1+fm4aX9j1sWME/r5XI/gGgYT15+PvAjxmBxcabYtd+VYYB0MKUoxw==} peerDependencies: '@types/react': '>=16.14.0 <19.0.0' '@types/react-dom': '>=16.9.0 <19.0.0' react: '>=16.14.0 <19.0.0' react-dom: '>=16.14.0 <19.0.0' - scheduler: ^0.19.0 || ^0.20.0 dependencies: '@fluentui/keyboard-keys': 9.0.7 - '@fluentui/react-context-selector': 9.1.50(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0)(scheduler@0.20.2) - '@fluentui/react-field': 9.1.51(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0)(scheduler@0.20.2) - '@fluentui/react-icons': 2.0.225(react@18.2.0) - '@fluentui/react-jsx-runtime': 9.0.28(@types/react@18.0.0)(react@18.2.0) - '@fluentui/react-portal': 9.4.11(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0) - '@fluentui/react-positioning': 9.12.5(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0) - '@fluentui/react-shared-contexts': 9.14.0(@types/react@18.0.0)(react@18.2.0) - '@fluentui/react-tabster': 9.17.4(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0) - '@fluentui/react-theme': 9.1.16 - '@fluentui/react-utilities': 9.17.0(@types/react@18.0.0)(react@18.2.0) - '@griffel/react': 1.5.20(react@18.2.0) - '@swc/helpers': 0.5.3 - '@types/react': 18.0.0 - '@types/react-dom': 18.0.0 - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) - scheduler: 0.20.2 + '@fluentui/react-aria': 9.13.6(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1) + '@fluentui/react-context-selector': 9.1.67(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1)(scheduler@0.23.0) + '@fluentui/react-field': 9.1.76(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1)(scheduler@0.23.0) + '@fluentui/react-icons': 2.0.258(react@18.3.1) + '@fluentui/react-jsx-runtime': 9.0.44(@types/react@18.3.9)(react@18.3.1) + '@fluentui/react-portal': 9.4.35(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1) + '@fluentui/react-positioning': 9.15.9(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1) + '@fluentui/react-shared-contexts': 9.20.1(@types/react@18.3.9)(react@18.3.1) + '@fluentui/react-tabster': 9.22.7(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1) + '@fluentui/react-theme': 9.1.20 + '@fluentui/react-utilities': 9.18.15(@types/react@18.3.9)(react@18.3.1) + '@griffel/react': 1.5.25(react@18.3.1) + '@swc/helpers': 0.5.13 + '@types/react': 18.3.9 + '@types/react-dom': 18.3.0 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + transitivePeerDependencies: + - scheduler dev: false - /@fluentui/react-components@9.15.0(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0)(scheduler@0.20.2): - resolution: {integrity: sha512-N9JWZVD5Byw/zizb84WSGv2y/WWxngqQioaERyLiOKa+YTI7eerLIHJf/8jPfmJh8rSW7VbzQNq4Pw+Dmsbsqw==} + /@fluentui/react-components@9.54.17(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1)(scheduler@0.23.0): + resolution: {integrity: sha512-brnvcEGQG+S16hc9o+cXB9EEJmpicjP1+plYBuc5xKtz2Ljo1fAijM5MGP/pwMcQUU0GATFiVkIzvGwyD7y5aQ==} peerDependencies: - '@types/react': '>=16.8.0 <19.0.0' - '@types/react-dom': '>=16.8.0 <19.0.0' - react: '>=16.8.0 <19.0.0' - react-dom: '>=16.8.0 <19.0.0' - scheduler: ^0.19.0 || ^0.20.0 - dependencies: - '@fluentui/react-accordion': 9.3.39(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0)(scheduler@0.20.2) - '@fluentui/react-alert': 9.0.0-beta.31(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0)(scheduler@0.20.2) - '@fluentui/react-avatar': 9.6.10(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0)(scheduler@0.20.2) - '@fluentui/react-badge': 9.2.23(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0) - '@fluentui/react-button': 9.3.66(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0) - '@fluentui/react-card': 9.0.0-beta.44(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0) - '@fluentui/react-checkbox': 9.2.9(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0)(scheduler@0.20.2) - '@fluentui/react-combobox': 9.7.1(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0)(scheduler@0.20.2) - '@fluentui/react-dialog': 9.9.8(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0)(scheduler@0.20.2) - '@fluentui/react-divider': 9.2.59(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0) - '@fluentui/react-field': 9.0.0-alpha.19(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0)(scheduler@0.20.2) - '@fluentui/react-image': 9.1.56(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0) - '@fluentui/react-infobutton': 9.0.0-beta.13(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0)(scheduler@0.20.2) - '@fluentui/react-input': 9.4.61(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0)(scheduler@0.20.2) - '@fluentui/react-label': 9.1.59(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0) - '@fluentui/react-link': 9.2.8(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0) - '@fluentui/react-menu': 9.12.46(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0)(scheduler@0.20.2) - '@fluentui/react-overflow': 9.1.9(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0)(scheduler@0.20.2) - '@fluentui/react-persona': 9.2.69(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0)(scheduler@0.20.2) - '@fluentui/react-popover': 9.8.34(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0)(scheduler@0.20.2) - '@fluentui/react-portal': 9.4.11(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0) - '@fluentui/react-positioning': 9.12.5(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0) - '@fluentui/react-progress': 9.0.0-alpha.16(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0)(scheduler@0.20.2) - '@fluentui/react-provider': 9.13.9(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0) - '@fluentui/react-radio': 9.2.4(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0)(scheduler@0.20.2) - '@fluentui/react-select': 9.1.61(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0)(scheduler@0.20.2) - '@fluentui/react-shared-contexts': 9.14.0(@types/react@18.0.0)(react@18.2.0) - '@fluentui/react-slider': 9.1.66(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0)(scheduler@0.20.2) - '@fluentui/react-spinbutton': 9.2.61(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0)(scheduler@0.20.2) - '@fluentui/react-spinner': 9.3.39(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0) - '@fluentui/react-switch': 9.1.66(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0)(scheduler@0.20.2) - '@fluentui/react-table': 9.0.0(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0)(scheduler@0.20.2) - '@fluentui/react-tabs': 9.4.7(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0)(scheduler@0.20.2) - '@fluentui/react-tabster': 9.17.4(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0) - '@fluentui/react-text': 9.4.8(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0) - '@fluentui/react-textarea': 9.3.61(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0)(scheduler@0.20.2) - '@fluentui/react-theme': 9.1.16 - '@fluentui/react-toolbar': 9.1.67(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0)(scheduler@0.20.2) - '@fluentui/react-tooltip': 9.4.12(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0) - '@fluentui/react-utilities': 9.17.0(@types/react@18.0.0)(react@18.2.0) - '@fluentui/react-virtualizer': 9.0.0-alpha.4(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0) - '@griffel/react': 1.5.20(react@18.2.0) - '@types/react': 18.0.0 - '@types/react-dom': 18.0.0 - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) - scheduler: 0.20.2 - tslib: 2.6.1 + '@types/react': '>=16.14.0 <19.0.0' + '@types/react-dom': '>=16.9.0 <19.0.0' + react: '>=16.14.0 <19.0.0' + react-dom: '>=16.14.0 <19.0.0' + dependencies: + '@fluentui/react-accordion': 9.5.5(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1)(scheduler@0.23.0) + '@fluentui/react-alert': 9.0.0-beta.124(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1)(scheduler@0.23.0) + '@fluentui/react-aria': 9.13.6(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1) + '@fluentui/react-avatar': 9.6.39(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1)(scheduler@0.23.0) + '@fluentui/react-badge': 9.2.43(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1) + '@fluentui/react-breadcrumb': 9.0.39(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1) + '@fluentui/react-button': 9.3.92(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1) + '@fluentui/react-card': 9.0.94(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1) + '@fluentui/react-checkbox': 9.2.37(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1)(scheduler@0.23.0) + '@fluentui/react-combobox': 9.13.8(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1)(scheduler@0.23.0) + '@fluentui/react-dialog': 9.11.16(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1)(scheduler@0.23.0) + '@fluentui/react-divider': 9.2.75(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1) + '@fluentui/react-drawer': 9.5.16(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1)(scheduler@0.23.0) + '@fluentui/react-field': 9.1.76(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1)(scheduler@0.23.0) + '@fluentui/react-image': 9.1.73(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1) + '@fluentui/react-infobutton': 9.0.0-beta.102(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1)(scheduler@0.23.0) + '@fluentui/react-infolabel': 9.0.46(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1)(scheduler@0.23.0) + '@fluentui/react-input': 9.4.89(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1)(scheduler@0.23.0) + '@fluentui/react-label': 9.1.76(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1) + '@fluentui/react-link': 9.2.32(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1) + '@fluentui/react-menu': 9.14.16(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1)(scheduler@0.23.0) + '@fluentui/react-message-bar': 9.2.12(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1) + '@fluentui/react-motion': 9.5.2(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1) + '@fluentui/react-overflow': 9.1.30(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1)(scheduler@0.23.0) + '@fluentui/react-persona': 9.2.98(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1)(scheduler@0.23.0) + '@fluentui/react-popover': 9.9.21(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1)(scheduler@0.23.0) + '@fluentui/react-portal': 9.4.35(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1) + '@fluentui/react-positioning': 9.15.9(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1) + '@fluentui/react-progress': 9.1.87(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1)(scheduler@0.23.0) + '@fluentui/react-provider': 9.17.4(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1) + '@fluentui/react-radio': 9.2.32(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1)(scheduler@0.23.0) + '@fluentui/react-rating': 9.0.19(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1) + '@fluentui/react-search': 9.0.18(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1)(scheduler@0.23.0) + '@fluentui/react-select': 9.1.87(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1)(scheduler@0.23.0) + '@fluentui/react-shared-contexts': 9.20.1(@types/react@18.3.9)(react@18.3.1) + '@fluentui/react-skeleton': 9.1.16(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1)(scheduler@0.23.0) + '@fluentui/react-slider': 9.1.94(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1)(scheduler@0.23.0) + '@fluentui/react-spinbutton': 9.2.88(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1)(scheduler@0.23.0) + '@fluentui/react-spinner': 9.4.14(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1) + '@fluentui/react-swatch-picker': 9.1.10(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1)(scheduler@0.23.0) + '@fluentui/react-switch': 9.1.94(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1)(scheduler@0.23.0) + '@fluentui/react-table': 9.15.18(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1)(scheduler@0.23.0) + '@fluentui/react-tabs': 9.5.1(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1)(scheduler@0.23.0) + '@fluentui/react-tabster': 9.22.7(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1) + '@fluentui/react-tag-picker': 9.3.4(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1)(scheduler@0.23.0) + '@fluentui/react-tags': 9.3.18(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1)(scheduler@0.23.0) + '@fluentui/react-teaching-popover': 9.1.18(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1)(scheduler@0.23.0) + '@fluentui/react-text': 9.4.25(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1) + '@fluentui/react-textarea': 9.3.88(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1)(scheduler@0.23.0) + '@fluentui/react-theme': 9.1.20 + '@fluentui/react-toast': 9.3.56(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1) + '@fluentui/react-toolbar': 9.2.6(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1)(scheduler@0.23.0) + '@fluentui/react-tooltip': 9.4.39(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1) + '@fluentui/react-tree': 9.8.2(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1)(scheduler@0.23.0) + '@fluentui/react-utilities': 9.18.15(@types/react@18.3.9)(react@18.3.1) + '@fluentui/react-virtualizer': 9.0.0-alpha.85(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1) + '@griffel/react': 1.5.25(react@18.3.1) + '@swc/helpers': 0.5.13 + '@types/react': 18.3.9 + '@types/react-dom': 18.3.0 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + transitivePeerDependencies: + - scheduler dev: false - /@fluentui/react-context-selector@9.1.50(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0)(scheduler@0.20.2): - resolution: {integrity: sha512-rSUCW1ja4wp4qcLNFDGd4WjVsFzR1WYW9G5rurqlK5jbQFxsRZ4B88GamnXkUQxlfQxfLjhBLBjui5ZZQCnJQg==} + /@fluentui/react-context-selector@9.1.67(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1)(scheduler@0.23.0): + resolution: {integrity: sha512-1jpOjt3NVOlyLcMY/nycyhyXvcPw57+0gkF7Eln4c9Hb2xFUlsAFX0x8MDLNsvyjGgKekLX9p+tPt9TUENWPOw==} peerDependencies: '@types/react': '>=16.14.0 <19.0.0' '@types/react-dom': '>=16.9.0 <19.0.0' react: '>=16.14.0 <19.0.0' react-dom: '>=16.14.0 <19.0.0' - scheduler: ^0.19.0 || ^0.20.0 - dependencies: - '@fluentui/react-utilities': 9.17.0(@types/react@18.0.0)(react@18.2.0) - '@swc/helpers': 0.5.3 - '@types/react': 18.0.0 - '@types/react-dom': 18.0.0 - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) - scheduler: 0.20.2 + scheduler: '>=0.19.0 <=0.23.0' + dependencies: + '@fluentui/react-utilities': 9.18.15(@types/react@18.3.9)(react@18.3.1) + '@swc/helpers': 0.5.13 + '@types/react': 18.3.9 + '@types/react-dom': 18.3.0 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + scheduler: 0.23.0 dev: false - /@fluentui/react-dialog@9.9.8(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0)(scheduler@0.20.2): - resolution: {integrity: sha512-YOovjoFpU+PQkYLqpkWShfv14GFoCV8s1tMhI13cuZMTEPNdG7HXnGs0+Ny0y3KU+hRg7uFIPpV3D1yYJaP80Q==} + /@fluentui/react-dialog@9.11.16(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1)(scheduler@0.23.0): + resolution: {integrity: sha512-PP15i+mN6XI7knfrdTNexNHtGLBNbf7WmJZGiXZViBWrlGEAUyxdRqmNwQEXwz0xYduqMX7ddEw26e/Ag/BzwA==} peerDependencies: '@types/react': '>=16.14.0 <19.0.0' '@types/react-dom': '>=16.9.0 <19.0.0' @@ -909,234 +1986,417 @@ packages: react-dom: '>=16.14.0 <19.0.0' dependencies: '@fluentui/keyboard-keys': 9.0.7 - '@fluentui/react-aria': 9.8.0(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0) - '@fluentui/react-context-selector': 9.1.50(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0)(scheduler@0.20.2) - '@fluentui/react-icons': 2.0.225(react@18.2.0) - '@fluentui/react-jsx-runtime': 9.0.28(@types/react@18.0.0)(react@18.2.0) - '@fluentui/react-portal': 9.4.11(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0) - '@fluentui/react-shared-contexts': 9.14.0(@types/react@18.0.0)(react@18.2.0) - '@fluentui/react-tabster': 9.17.4(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0) - '@fluentui/react-theme': 9.1.16 - '@fluentui/react-utilities': 9.17.0(@types/react@18.0.0)(react@18.2.0) - '@griffel/react': 1.5.20(react@18.2.0) - '@swc/helpers': 0.5.3 - '@types/react': 18.0.0 - '@types/react-dom': 18.0.0 - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) - react-transition-group: 4.4.5(react-dom@18.2.0)(react@18.2.0) + '@fluentui/react-aria': 9.13.6(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1) + '@fluentui/react-context-selector': 9.1.67(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1)(scheduler@0.23.0) + '@fluentui/react-icons': 2.0.258(react@18.3.1) + '@fluentui/react-jsx-runtime': 9.0.44(@types/react@18.3.9)(react@18.3.1) + '@fluentui/react-motion': 9.5.2(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1) + '@fluentui/react-portal': 9.4.35(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1) + '@fluentui/react-shared-contexts': 9.20.1(@types/react@18.3.9)(react@18.3.1) + '@fluentui/react-tabster': 9.22.7(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1) + '@fluentui/react-theme': 9.1.20 + '@fluentui/react-utilities': 9.18.15(@types/react@18.3.9)(react@18.3.1) + '@griffel/react': 1.5.25(react@18.3.1) + '@swc/helpers': 0.5.13 + '@types/react': 18.3.9 + '@types/react-dom': 18.3.0 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) transitivePeerDependencies: - scheduler dev: false - /@fluentui/react-divider@9.2.59(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-xT0dzJEw3UMGTkNqdNgg+lkPWbAo3FIzRhTPhy1svtOmcZlizRIESzrPnzxOylvikVYriKhMJ6/2CRkShGaMug==} + /@fluentui/react-divider@9.2.75(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1): + resolution: {integrity: sha512-pWWJH7ZLG4sHcfhwUO5nnhA0TsGK/JlSkcyEnndK76umQlWAzLrN4JWEHKTWplUIIa6STKWObAYPXkiTnkLEkQ==} peerDependencies: '@types/react': '>=16.14.0 <19.0.0' '@types/react-dom': '>=16.9.0 <19.0.0' react: '>=16.14.0 <19.0.0' react-dom: '>=16.14.0 <19.0.0' dependencies: - '@fluentui/react-jsx-runtime': 9.0.28(@types/react@18.0.0)(react@18.2.0) - '@fluentui/react-shared-contexts': 9.14.0(@types/react@18.0.0)(react@18.2.0) - '@fluentui/react-theme': 9.1.16 - '@fluentui/react-utilities': 9.17.0(@types/react@18.0.0)(react@18.2.0) - '@griffel/react': 1.5.20(react@18.2.0) - '@swc/helpers': 0.5.3 - '@types/react': 18.0.0 - '@types/react-dom': 18.0.0 - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) + '@fluentui/react-jsx-runtime': 9.0.44(@types/react@18.3.9)(react@18.3.1) + '@fluentui/react-shared-contexts': 9.20.1(@types/react@18.3.9)(react@18.3.1) + '@fluentui/react-theme': 9.1.20 + '@fluentui/react-utilities': 9.18.15(@types/react@18.3.9)(react@18.3.1) + '@griffel/react': 1.5.25(react@18.3.1) + '@swc/helpers': 0.5.13 + '@types/react': 18.3.9 + '@types/react-dom': 18.3.0 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) dev: false - /@fluentui/react-field@9.0.0-alpha.19(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0)(scheduler@0.20.2): - resolution: {integrity: sha512-5vULJh25/udaSvjWyvCtRkUP1Pa8+glV1SU8YPKdwgXmf1iJe6E97gG8I5oFlszFXoSrfmCfju2QrRg/4GfoIw==} + /@fluentui/react-drawer@9.5.16(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1)(scheduler@0.23.0): + resolution: {integrity: sha512-GORGm43E981KHfg2HB/picUwpf3BbdwcfPUVslAdyqaR2A6OJ+fQGKjGDcHn/CPIfgPsg0wHVpVTkvJLTt/BzA==} peerDependencies: - '@types/react': '>=16.8.0 <19.0.0' - '@types/react-dom': '>=16.8.0 <19.0.0' - react: '>=16.8.0 <19.0.0' - react-dom: '>=16.8.0 <19.0.0' + '@types/react': '>=16.14.0 <19.0.0' + '@types/react-dom': '>=16.9.0 <19.0.0' + react: '>=16.14.0 <19.0.0' + react-dom: '>=16.14.0 <19.0.0' dependencies: - '@fluentui/react-context-selector': 9.1.50(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0)(scheduler@0.20.2) - '@fluentui/react-icons': 2.0.225(react@18.2.0) - '@fluentui/react-label': 9.1.59(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0) - '@fluentui/react-theme': 9.1.16 - '@fluentui/react-utilities': 9.17.0(@types/react@18.0.0)(react@18.2.0) - '@griffel/react': 1.5.20(react@18.2.0) - '@types/react': 18.0.0 - '@types/react-dom': 18.0.0 - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) - tslib: 2.6.1 + '@fluentui/react-dialog': 9.11.16(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1)(scheduler@0.23.0) + '@fluentui/react-jsx-runtime': 9.0.44(@types/react@18.3.9)(react@18.3.1) + '@fluentui/react-motion': 9.5.2(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1) + '@fluentui/react-shared-contexts': 9.20.1(@types/react@18.3.9)(react@18.3.1) + '@fluentui/react-tabster': 9.22.7(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1) + '@fluentui/react-theme': 9.1.20 + '@fluentui/react-utilities': 9.18.15(@types/react@18.3.9)(react@18.3.1) + '@griffel/react': 1.5.25(react@18.3.1) + '@swc/helpers': 0.5.13 + '@types/react': 18.3.9 + '@types/react-dom': 18.3.0 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) transitivePeerDependencies: - scheduler dev: false - /@fluentui/react-field@9.1.51(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0)(scheduler@0.20.2): - resolution: {integrity: sha512-Q7UxdEUGQ07qf1RntXVuS3S7qa8M/evRpia2I5td3ds96XB6V6WRGaMJqt5WILmcdEZcdDecVbURb0qCRekrng==} + /@fluentui/react-field@9.1.76(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1)(scheduler@0.23.0): + resolution: {integrity: sha512-eV1MKB97lgvgiVEps9OakqXXeLGHTdLSK7Zd/QmD4HzSSV/XapRLCw+7fITBoG19Tp8AVkGbZI753iPPOv9RZA==} peerDependencies: '@types/react': '>=16.14.0 <19.0.0' '@types/react-dom': '>=16.9.0 <19.0.0' react: '>=16.14.0 <19.0.0' react-dom: '>=16.14.0 <19.0.0' dependencies: - '@fluentui/react-context-selector': 9.1.50(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0)(scheduler@0.20.2) - '@fluentui/react-icons': 2.0.225(react@18.2.0) - '@fluentui/react-jsx-runtime': 9.0.28(@types/react@18.0.0)(react@18.2.0) - '@fluentui/react-label': 9.1.59(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0) - '@fluentui/react-theme': 9.1.16 - '@fluentui/react-utilities': 9.17.0(@types/react@18.0.0)(react@18.2.0) - '@griffel/react': 1.5.20(react@18.2.0) - '@swc/helpers': 0.5.3 - '@types/react': 18.0.0 - '@types/react-dom': 18.0.0 - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) + '@fluentui/react-context-selector': 9.1.67(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1)(scheduler@0.23.0) + '@fluentui/react-icons': 2.0.258(react@18.3.1) + '@fluentui/react-jsx-runtime': 9.0.44(@types/react@18.3.9)(react@18.3.1) + '@fluentui/react-label': 9.1.76(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1) + '@fluentui/react-theme': 9.1.20 + '@fluentui/react-utilities': 9.18.15(@types/react@18.3.9)(react@18.3.1) + '@griffel/react': 1.5.25(react@18.3.1) + '@swc/helpers': 0.5.13 + '@types/react': 18.3.9 + '@types/react-dom': 18.3.0 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) transitivePeerDependencies: - scheduler dev: false - /@fluentui/react-focus@8.8.39(@types/react@18.0.0)(react@18.2.0): - resolution: {integrity: sha512-7PnI+3e37jxt0PlWykNfbCbPdnKroJY+olOxZDHkXfI/ANr8lm4YuyLAYNAtyapfnkf+FBoO6vxU51P8hNk7tQ==} + /@fluentui/react-focus@8.9.13(@types/react@18.3.9)(react@18.3.1): + resolution: {integrity: sha512-oUtY4F+tp0RmV0Wr30CoYFdTQEqHWKjU3/dYHPbI0xKH4emLrf8+sc0FAHJdeHH2rx4T1XSA807pm7YB4CQqWw==} peerDependencies: '@types/react': '>=16.8.0 <19.0.0' react: '>=16.8.0 <19.0.0' dependencies: - '@fluentui/keyboard-key': 0.4.14 - '@fluentui/merge-styles': 8.5.15 - '@fluentui/set-version': 8.2.14 - '@fluentui/style-utilities': 8.10.2(@types/react@18.0.0)(react@18.2.0) - '@fluentui/utilities': 8.13.24(@types/react@18.0.0)(react@18.2.0) - '@types/react': 18.0.0 - react: 18.2.0 - tslib: 2.6.1 + '@fluentui/keyboard-key': 0.4.23 + '@fluentui/merge-styles': 8.6.13 + '@fluentui/set-version': 8.2.23 + '@fluentui/style-utilities': 8.10.21(@types/react@18.3.9)(react@18.3.1) + '@fluentui/utilities': 8.15.15(@types/react@18.3.9)(react@18.3.1) + '@types/react': 18.3.9 + react: 18.3.1 + tslib: 2.7.0 dev: false - /@fluentui/react-hooks@8.6.36(@types/react@18.0.0)(react@18.2.0): - resolution: {integrity: sha512-kI0Z4Q4xHUs4SOmmI5n5OH5fPckqMSCovTRpiuxzCO2TNzLmfC861+nqf4Ygw/ChqNm2gWNZZfUADfnNAEsq+Q==} + /@fluentui/react-hooks@8.8.12(@types/react@18.3.9)(react@18.3.1): + resolution: {integrity: sha512-lplre6x5dONjd12D0BWs4LKq4lX++o0w07pIk2XhxikOW1e4Xfjn6VM52WSdtx+tU4rbLUoCA8drN2y/wDvhGg==} peerDependencies: '@types/react': '>=16.8.0 <19.0.0' react: '>=16.8.0 <19.0.0' dependencies: - '@fluentui/react-window-provider': 2.2.18(@types/react@18.0.0)(react@18.2.0) - '@fluentui/set-version': 8.2.14 - '@fluentui/utilities': 8.13.24(@types/react@18.0.0)(react@18.2.0) - '@types/react': 18.0.0 - react: 18.2.0 - tslib: 2.6.1 + '@fluentui/react-window-provider': 2.2.28(@types/react@18.3.9)(react@18.3.1) + '@fluentui/set-version': 8.2.23 + '@fluentui/utilities': 8.15.15(@types/react@18.3.9)(react@18.3.1) + '@types/react': 18.3.9 + react: 18.3.1 + tslib: 2.7.0 dev: false - /@fluentui/react-icons@2.0.225(react@18.2.0): - resolution: {integrity: sha512-L9phN3bAMlZCa5+/ObGjIO+5GI8M50ym766sraSq92jaJwgAXrCJDLWuDGWZRGrC63DcagtR2culptj3q7gMMg==} + /@fluentui/react-icons@2.0.258(react@18.3.1): + resolution: {integrity: sha512-SRCW+3q/fBBCwgucdnfuRad9ck/hQW92xAJ+tELKBJI4f9BJ1U8QyeZoRu14xMEKL/VsFLbEkeXNAgvjJ0IjkA==} peerDependencies: react: '>=16.8.0 <19.0.0' dependencies: - '@griffel/react': 1.5.20(react@18.2.0) - react: 18.2.0 - tslib: 2.6.1 + '@griffel/react': 1.5.25(react@18.3.1) + react: 18.3.1 + tslib: 2.7.0 + dev: false + + /@fluentui/react-image@9.1.73(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1): + resolution: {integrity: sha512-aVpillfiEIqqlyQGGFf17WtiKKFhhGyUMVUv3zLksick/5kifk7zdAW623PA8mpeQf6U1tSPJc8iaXSwr+5cwQ==} + peerDependencies: + '@types/react': '>=16.14.0 <19.0.0' + '@types/react-dom': '>=16.9.0 <19.0.0' + react: '>=16.14.0 <19.0.0' + react-dom: '>=16.14.0 <19.0.0' + dependencies: + '@fluentui/react-jsx-runtime': 9.0.44(@types/react@18.3.9)(react@18.3.1) + '@fluentui/react-shared-contexts': 9.20.1(@types/react@18.3.9)(react@18.3.1) + '@fluentui/react-theme': 9.1.20 + '@fluentui/react-utilities': 9.18.15(@types/react@18.3.9)(react@18.3.1) + '@griffel/react': 1.5.25(react@18.3.1) + '@swc/helpers': 0.5.13 + '@types/react': 18.3.9 + '@types/react-dom': 18.3.0 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) dev: false - /@fluentui/react-image@9.1.56(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-yeD08kQR4MJgjETfqaFKQLhtaCxUv3tuU1EluU6kGhfPxDJ+XzbHvpzXv4PJToyF5MpkBVfycK+ignh9zbJpHg==} + /@fluentui/react-infobutton@9.0.0-beta.102(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1)(scheduler@0.23.0): + resolution: {integrity: sha512-3kA4F0Vga8Ds6JGlBajLCCDOo/LmPuS786Wg7ui4ZTDYVIMzy1yp2XuVcZniifBFvEp0HQCUoDPWUV0VI3FfzQ==} peerDependencies: '@types/react': '>=16.14.0 <19.0.0' '@types/react-dom': '>=16.9.0 <19.0.0' react: '>=16.14.0 <19.0.0' react-dom: '>=16.14.0 <19.0.0' dependencies: - '@fluentui/react-jsx-runtime': 9.0.28(@types/react@18.0.0)(react@18.2.0) - '@fluentui/react-shared-contexts': 9.14.0(@types/react@18.0.0)(react@18.2.0) - '@fluentui/react-theme': 9.1.16 - '@fluentui/react-utilities': 9.17.0(@types/react@18.0.0)(react@18.2.0) - '@griffel/react': 1.5.20(react@18.2.0) - '@swc/helpers': 0.5.3 - '@types/react': 18.0.0 - '@types/react-dom': 18.0.0 - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) + '@fluentui/react-icons': 2.0.258(react@18.3.1) + '@fluentui/react-jsx-runtime': 9.0.44(@types/react@18.3.9)(react@18.3.1) + '@fluentui/react-label': 9.1.76(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1) + '@fluentui/react-popover': 9.9.21(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1)(scheduler@0.23.0) + '@fluentui/react-tabster': 9.22.7(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1) + '@fluentui/react-theme': 9.1.20 + '@fluentui/react-utilities': 9.18.15(@types/react@18.3.9)(react@18.3.1) + '@griffel/react': 1.5.25(react@18.3.1) + '@swc/helpers': 0.5.13 + '@types/react': 18.3.9 + '@types/react-dom': 18.3.0 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + transitivePeerDependencies: + - scheduler dev: false - /@fluentui/react-infobutton@9.0.0-beta.13(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0)(scheduler@0.20.2): - resolution: {integrity: sha512-X+/75w3cPEwYeZdIYjQbAhxtGwGPVbR6i1Kx7+K3gmfsPmzJrDhObYfiab0T9+1Ztblh1MTBBY672tvimA8LDQ==} + /@fluentui/react-infolabel@9.0.46(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1)(scheduler@0.23.0): + resolution: {integrity: sha512-sDJDlRLroP+9XOj76mpLBpyUVng/+cJDPVNuNvJtS7JBVCs9owlQlq8RBcKFzdbLNh7GZgpi2qe0kUPCNOZYOQ==} peerDependencies: '@types/react': '>=16.8.0 <19.0.0' '@types/react-dom': '>=16.8.0 <19.0.0' - react: '>=16.8.0 <19.0.0' + react: '>=16.14.0 <19.0.0' react-dom: '>=16.8.0 <19.0.0' dependencies: - '@fluentui/react-icons': 2.0.225(react@18.2.0) - '@fluentui/react-popover': 9.8.34(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0)(scheduler@0.20.2) - '@fluentui/react-tabster': 9.17.4(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0) - '@fluentui/react-theme': 9.1.16 - '@fluentui/react-utilities': 9.17.0(@types/react@18.0.0)(react@18.2.0) - '@griffel/react': 1.5.20(react@18.2.0) - '@types/react': 18.0.0 - '@types/react-dom': 18.0.0 - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) - tslib: 2.6.1 + '@fluentui/react-icons': 2.0.258(react@18.3.1) + '@fluentui/react-jsx-runtime': 9.0.44(@types/react@18.3.9)(react@18.3.1) + '@fluentui/react-label': 9.1.76(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1) + '@fluentui/react-popover': 9.9.21(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1)(scheduler@0.23.0) + '@fluentui/react-tabster': 9.22.7(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1) + '@fluentui/react-theme': 9.1.20 + '@fluentui/react-utilities': 9.18.15(@types/react@18.3.9)(react@18.3.1) + '@griffel/react': 1.5.25(react@18.3.1) + '@swc/helpers': 0.5.13 + '@types/react': 18.3.9 + '@types/react-dom': 18.3.0 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + transitivePeerDependencies: + - scheduler + dev: false + + /@fluentui/react-input@9.4.89(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1)(scheduler@0.23.0): + resolution: {integrity: sha512-O6THfgikbwpPgUYBcQBXbQ1dHpP6qY1P31gb7+epaX54AJMuo0xeANfSMBBhTkbLshyn6AS9OMOwrc/Zkvmfew==} + peerDependencies: + '@types/react': '>=16.14.0 <19.0.0' + '@types/react-dom': '>=16.9.0 <19.0.0' + react: '>=16.14.0 <19.0.0' + react-dom: '>=16.14.0 <19.0.0' + dependencies: + '@fluentui/react-field': 9.1.76(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1)(scheduler@0.23.0) + '@fluentui/react-jsx-runtime': 9.0.44(@types/react@18.3.9)(react@18.3.1) + '@fluentui/react-shared-contexts': 9.20.1(@types/react@18.3.9)(react@18.3.1) + '@fluentui/react-theme': 9.1.20 + '@fluentui/react-utilities': 9.18.15(@types/react@18.3.9)(react@18.3.1) + '@griffel/react': 1.5.25(react@18.3.1) + '@swc/helpers': 0.5.13 + '@types/react': 18.3.9 + '@types/react-dom': 18.3.0 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) transitivePeerDependencies: - scheduler dev: false - /@fluentui/react-input@9.4.61(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0)(scheduler@0.20.2): - resolution: {integrity: sha512-mjXEx/CMfKcOjqhqDe5imvV1ikVsxpj0ZZa6HUWZetXvYarP1jvVBeC2YViLJV/14o/IFFkBwfyDqFOBB7dXyQ==} + /@fluentui/react-jsx-runtime@9.0.44(@types/react@18.3.9)(react@18.3.1): + resolution: {integrity: sha512-cnFjiFaztl3zV2bL/Pgsa/dvLES/gNzSKkBUD3ShWeaEi7LbInc3+tnCcttBSTSNdLh8mcuzQkUCImVSD857VA==} + peerDependencies: + '@types/react': '>=16.14.0 <19.0.0' + react: '>=16.14.0 <19.0.0' + dependencies: + '@fluentui/react-utilities': 9.18.15(@types/react@18.3.9)(react@18.3.1) + '@swc/helpers': 0.5.13 + '@types/react': 18.3.9 + react: 18.3.1 + react-is: 17.0.2 + dev: false + + /@fluentui/react-label@9.1.76(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1): + resolution: {integrity: sha512-7lqil5XIYkxSQNy/GEqFypAo0eQyjYIPYu0LO2z8UPCuRyaItHA/ArSc3GnyIL/naY9Wz1EG2WvakLbgB+PkGg==} + peerDependencies: + '@types/react': '>=16.14.0 <19.0.0' + '@types/react-dom': '>=16.9.0 <19.0.0' + react: '>=16.14.0 <19.0.0' + react-dom: '>=16.14.0 <19.0.0' + dependencies: + '@fluentui/react-jsx-runtime': 9.0.44(@types/react@18.3.9)(react@18.3.1) + '@fluentui/react-shared-contexts': 9.20.1(@types/react@18.3.9)(react@18.3.1) + '@fluentui/react-theme': 9.1.20 + '@fluentui/react-utilities': 9.18.15(@types/react@18.3.9)(react@18.3.1) + '@griffel/react': 1.5.25(react@18.3.1) + '@swc/helpers': 0.5.13 + '@types/react': 18.3.9 + '@types/react-dom': 18.3.0 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + dev: false + + /@fluentui/react-link@9.2.32(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1): + resolution: {integrity: sha512-BsjDm8ixFMoh+7Hi7WRgDxLEKYj61gc0VjCs9ah0JxJoM1o+OoJhXKc29a13qRJHMSB3Gfndw6nYCineRPcFiA==} + peerDependencies: + '@types/react': '>=16.14.0 <19.0.0' + '@types/react-dom': '>=16.9.0 <19.0.0' + react: '>=16.14.0 <19.0.0' + react-dom: '>=16.14.0 <19.0.0' + dependencies: + '@fluentui/keyboard-keys': 9.0.7 + '@fluentui/react-jsx-runtime': 9.0.44(@types/react@18.3.9)(react@18.3.1) + '@fluentui/react-shared-contexts': 9.20.1(@types/react@18.3.9)(react@18.3.1) + '@fluentui/react-tabster': 9.22.7(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1) + '@fluentui/react-theme': 9.1.20 + '@fluentui/react-utilities': 9.18.15(@types/react@18.3.9)(react@18.3.1) + '@griffel/react': 1.5.25(react@18.3.1) + '@swc/helpers': 0.5.13 + '@types/react': 18.3.9 + '@types/react-dom': 18.3.0 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + dev: false + + /@fluentui/react-menu@9.14.16(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1)(scheduler@0.23.0): + resolution: {integrity: sha512-q0FVqSjTXQL8jO6Zf+fTFRbJglGBQS7dfkINZ966p9Kqq7zyHFMuaadXil2TpTkGcpo/Qva3wlFJoEeHki2PLQ==} peerDependencies: '@types/react': '>=16.14.0 <19.0.0' '@types/react-dom': '>=16.9.0 <19.0.0' react: '>=16.14.0 <19.0.0' react-dom: '>=16.14.0 <19.0.0' dependencies: - '@fluentui/react-field': 9.1.51(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0)(scheduler@0.20.2) - '@fluentui/react-jsx-runtime': 9.0.28(@types/react@18.0.0)(react@18.2.0) - '@fluentui/react-shared-contexts': 9.14.0(@types/react@18.0.0)(react@18.2.0) - '@fluentui/react-theme': 9.1.16 - '@fluentui/react-utilities': 9.17.0(@types/react@18.0.0)(react@18.2.0) - '@griffel/react': 1.5.20(react@18.2.0) - '@swc/helpers': 0.5.3 - '@types/react': 18.0.0 - '@types/react-dom': 18.0.0 - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) + '@fluentui/keyboard-keys': 9.0.7 + '@fluentui/react-aria': 9.13.6(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1) + '@fluentui/react-context-selector': 9.1.67(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1)(scheduler@0.23.0) + '@fluentui/react-icons': 2.0.258(react@18.3.1) + '@fluentui/react-jsx-runtime': 9.0.44(@types/react@18.3.9)(react@18.3.1) + '@fluentui/react-portal': 9.4.35(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1) + '@fluentui/react-positioning': 9.15.9(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1) + '@fluentui/react-shared-contexts': 9.20.1(@types/react@18.3.9)(react@18.3.1) + '@fluentui/react-tabster': 9.22.7(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1) + '@fluentui/react-theme': 9.1.20 + '@fluentui/react-utilities': 9.18.15(@types/react@18.3.9)(react@18.3.1) + '@griffel/react': 1.5.25(react@18.3.1) + '@swc/helpers': 0.5.13 + '@types/react': 18.3.9 + '@types/react-dom': 18.3.0 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) transitivePeerDependencies: - scheduler dev: false - /@fluentui/react-jsx-runtime@9.0.28(@types/react@18.0.0)(react@18.2.0): - resolution: {integrity: sha512-0BpDtSglE/o492jfR/EgW2cjCQRqWx7pzpmFqzTtlHp0rgi23WfjuKwMV9O2d4wfHkRxhAmn7/j5zIH/IAKhew==} + /@fluentui/react-message-bar@9.2.12(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1): + resolution: {integrity: sha512-d18VBkEJnKqhhkiuxzoan91BEt/x/at6/pR6TH0sn9C7Snvxu88Ywl2ZrKEpaNUAvG0Ww3qE0lNepm/fOEuR+g==} + peerDependencies: + '@types/react': '>=16.8.0 <19.0.0' + '@types/react-dom': '>=16.8.0 <19.0.0' + react: '>=16.14.0 <19.0.0' + react-dom: '>=16.8.0 <19.0.0' + dependencies: + '@fluentui/react-button': 9.3.92(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1) + '@fluentui/react-icons': 2.0.258(react@18.3.1) + '@fluentui/react-jsx-runtime': 9.0.44(@types/react@18.3.9)(react@18.3.1) + '@fluentui/react-shared-contexts': 9.20.1(@types/react@18.3.9)(react@18.3.1) + '@fluentui/react-theme': 9.1.20 + '@fluentui/react-utilities': 9.18.15(@types/react@18.3.9)(react@18.3.1) + '@griffel/react': 1.5.25(react@18.3.1) + '@swc/helpers': 0.5.13 + '@types/react': 18.3.9 + '@types/react-dom': 18.3.0 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + react-transition-group: 4.4.5(react-dom@18.3.1)(react@18.3.1) + dev: false + + /@fluentui/react-motion-components-preview@0.1.4(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1): + resolution: {integrity: sha512-nVZNKf+VDOAswQtWv7ZWBpPCZYApALBR/AK+F+TlRPx7qjij1ZOCUq5qtXfAV/mmomeeTHVtI1zKLBtNQIQ43A==} peerDependencies: '@types/react': '>=16.14.0 <19.0.0' + '@types/react-dom': '>=16.9.0 <19.0.0' + react: '>=16.14.0 <19.0.0' + react-dom: '>=16.14.0 <19.0.0' + dependencies: + '@fluentui/react-motion': 9.5.2(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1) + '@swc/helpers': 0.5.13 + '@types/react': 18.3.9 + '@types/react-dom': 18.3.0 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + dev: false + + /@fluentui/react-motion@9.5.2(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1): + resolution: {integrity: sha512-43Y1ZXhGxts8RIqOSyD7FXLAZl6Xyy4aQQuneXQJihY3vgsgMBtaEuQ9ZS2Ewo3zYJAf1kgZK+Q7OdQ3M9jmEg==} + peerDependencies: + '@types/react': '>=16.8.0 <19.0.0' + '@types/react-dom': '>=16.8.0 <19.0.0' react: '>=16.14.0 <19.0.0' + react-dom: '>=16.8.0 <19.0.0' dependencies: - '@fluentui/react-utilities': 9.17.0(@types/react@18.0.0)(react@18.2.0) - '@swc/helpers': 0.5.3 - '@types/react': 18.0.0 - react: 18.2.0 + '@fluentui/react-shared-contexts': 9.20.1(@types/react@18.3.9)(react@18.3.1) + '@fluentui/react-utilities': 9.18.15(@types/react@18.3.9)(react@18.3.1) + '@swc/helpers': 0.5.13 + '@types/react': 18.3.9 + '@types/react-dom': 18.3.0 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) react-is: 17.0.2 dev: false - /@fluentui/react-label@9.1.59(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-3Rsle1wvuwb7PRrSIezpPfqBpO5ZLXSOFWUxKijEBh05++4LH2nSjIoVxuThlLesGT2oo144DGkh3JH5CVuCFQ==} + /@fluentui/react-overflow@9.1.30(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1)(scheduler@0.23.0): + resolution: {integrity: sha512-4r0/YQaSX00OWeQwWsW9cctloTom1GguSaDRTxg2qMdwwr8gr9ZEni4LbCXJfH6soCNFzurnwdSeNOg4ogyT+g==} + peerDependencies: + '@types/react': '>=16.14.0 <19.0.0' + '@types/react-dom': '>=16.9.0 <19.0.0' + react: '>=16.14.0 <19.0.0' + react-dom: '>=16.14.0 <19.0.0' + dependencies: + '@fluentui/priority-overflow': 9.1.13 + '@fluentui/react-context-selector': 9.1.67(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1)(scheduler@0.23.0) + '@fluentui/react-theme': 9.1.20 + '@fluentui/react-utilities': 9.18.15(@types/react@18.3.9)(react@18.3.1) + '@griffel/react': 1.5.25(react@18.3.1) + '@swc/helpers': 0.5.13 + '@types/react': 18.3.9 + '@types/react-dom': 18.3.0 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + transitivePeerDependencies: + - scheduler + dev: false + + /@fluentui/react-persona@9.2.98(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1)(scheduler@0.23.0): + resolution: {integrity: sha512-PpgHB1puW1GwwgvPtSwMMUs+CpP3mQCRivHmWq6sf609rZZyV+ItGf4IzEdCDa+rD2GvkN53zfcFU9RJtrJwPg==} peerDependencies: '@types/react': '>=16.14.0 <19.0.0' '@types/react-dom': '>=16.9.0 <19.0.0' react: '>=16.14.0 <19.0.0' react-dom: '>=16.14.0 <19.0.0' dependencies: - '@fluentui/react-jsx-runtime': 9.0.28(@types/react@18.0.0)(react@18.2.0) - '@fluentui/react-shared-contexts': 9.14.0(@types/react@18.0.0)(react@18.2.0) - '@fluentui/react-theme': 9.1.16 - '@fluentui/react-utilities': 9.17.0(@types/react@18.0.0)(react@18.2.0) - '@griffel/react': 1.5.20(react@18.2.0) - '@swc/helpers': 0.5.3 - '@types/react': 18.0.0 - '@types/react-dom': 18.0.0 - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) + '@fluentui/react-avatar': 9.6.39(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1)(scheduler@0.23.0) + '@fluentui/react-badge': 9.2.43(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1) + '@fluentui/react-jsx-runtime': 9.0.44(@types/react@18.3.9)(react@18.3.1) + '@fluentui/react-shared-contexts': 9.20.1(@types/react@18.3.9)(react@18.3.1) + '@fluentui/react-theme': 9.1.20 + '@fluentui/react-utilities': 9.18.15(@types/react@18.3.9)(react@18.3.1) + '@griffel/react': 1.5.25(react@18.3.1) + '@swc/helpers': 0.5.13 + '@types/react': 18.3.9 + '@types/react-dom': 18.3.0 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + transitivePeerDependencies: + - scheduler dev: false - /@fluentui/react-link@9.2.8(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-pOlgUlPLXmmiCT12E/qNnKIR4ppKAq8pjEscWifON/2fcbtS2faX1YWmKK1Xs/L73iIMKTLk1ow0pFso6PbujQ==} + /@fluentui/react-popover@9.9.21(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1)(scheduler@0.23.0): + resolution: {integrity: sha512-7pM/+vaSFDc6fFc8gCHw44aX4EKUyz3jAZXXEzUwg6cjQfJrK42Pfq6EAt0ZzftJdmdOXXTBToI3tqRA7ENlSA==} peerDependencies: '@types/react': '>=16.14.0 <19.0.0' '@types/react-dom': '>=16.9.0 <19.0.0' @@ -1144,529 +2404,664 @@ packages: react-dom: '>=16.14.0 <19.0.0' dependencies: '@fluentui/keyboard-keys': 9.0.7 - '@fluentui/react-jsx-runtime': 9.0.28(@types/react@18.0.0)(react@18.2.0) - '@fluentui/react-shared-contexts': 9.14.0(@types/react@18.0.0)(react@18.2.0) - '@fluentui/react-tabster': 9.17.4(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0) - '@fluentui/react-theme': 9.1.16 - '@fluentui/react-utilities': 9.17.0(@types/react@18.0.0)(react@18.2.0) - '@griffel/react': 1.5.20(react@18.2.0) - '@swc/helpers': 0.5.3 - '@types/react': 18.0.0 - '@types/react-dom': 18.0.0 - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) + '@fluentui/react-aria': 9.13.6(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1) + '@fluentui/react-context-selector': 9.1.67(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1)(scheduler@0.23.0) + '@fluentui/react-jsx-runtime': 9.0.44(@types/react@18.3.9)(react@18.3.1) + '@fluentui/react-portal': 9.4.35(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1) + '@fluentui/react-positioning': 9.15.9(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1) + '@fluentui/react-shared-contexts': 9.20.1(@types/react@18.3.9)(react@18.3.1) + '@fluentui/react-tabster': 9.22.7(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1) + '@fluentui/react-theme': 9.1.20 + '@fluentui/react-utilities': 9.18.15(@types/react@18.3.9)(react@18.3.1) + '@griffel/react': 1.5.25(react@18.3.1) + '@swc/helpers': 0.5.13 + '@types/react': 18.3.9 + '@types/react-dom': 18.3.0 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + transitivePeerDependencies: + - scheduler + dev: false + + /@fluentui/react-portal-compat-context@9.0.12(@types/react@18.3.9)(react@18.3.1): + resolution: {integrity: sha512-5AVXWX9GnbvwnJZYUb4LSIF7BsI/N8oTI6+7Yn0w6B3yaWykA8Menlz757X5tgVBjouEj4Eom+AoVvA7u8gPDA==} + peerDependencies: + '@types/react': '>=16.14.0 <19.0.0' + react: '>=16.14.0 <19.0.0' + dependencies: + '@swc/helpers': 0.5.13 + '@types/react': 18.3.9 + react: 18.3.1 + dev: false + + /@fluentui/react-portal@9.4.35(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1): + resolution: {integrity: sha512-b0OTtFUmbHOU41wbRITqe3Wlqx3zpmXXUUsFh0KtSTKsMrWy2a2jtl7ZToNRsFfa3opwKsvlk+ohRT5CkDyQ4w==} + peerDependencies: + '@types/react': '>=16.14.0 <19.0.0' + '@types/react-dom': '>=16.9.0 <19.0.0' + react: '>=16.14.0 <19.0.0' + react-dom: '>=16.14.0 <19.0.0' + dependencies: + '@fluentui/react-shared-contexts': 9.20.1(@types/react@18.3.9)(react@18.3.1) + '@fluentui/react-tabster': 9.22.7(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1) + '@fluentui/react-utilities': 9.18.15(@types/react@18.3.9)(react@18.3.1) + '@griffel/react': 1.5.25(react@18.3.1) + '@swc/helpers': 0.5.13 + '@types/react': 18.3.9 + '@types/react-dom': 18.3.0 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + use-disposable: 1.0.2(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1) + dev: false + + /@fluentui/react-positioning@9.15.9(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1): + resolution: {integrity: sha512-X/0Fv3XxRdvOMLUgrL9T9RsIB8FQUgwfT9joQsldK4g2KUiRxpQcmGBO6+kOOB2CjakDrGLxlL5TWTwjibLJQQ==} + peerDependencies: + '@types/react': '>=16.14.0 <19.0.0' + '@types/react-dom': '>=16.9.0 <19.0.0' + react: '>=16.14.0 <19.0.0' + react-dom: '>=16.14.0 <19.0.0' + dependencies: + '@floating-ui/devtools': 0.2.1(@floating-ui/dom@1.6.11) + '@floating-ui/dom': 1.6.11 + '@fluentui/react-shared-contexts': 9.20.1(@types/react@18.3.9)(react@18.3.1) + '@fluentui/react-theme': 9.1.20 + '@fluentui/react-utilities': 9.18.15(@types/react@18.3.9)(react@18.3.1) + '@griffel/react': 1.5.25(react@18.3.1) + '@swc/helpers': 0.5.13 + '@types/react': 18.3.9 + '@types/react-dom': 18.3.0 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + dev: false + + /@fluentui/react-progress@9.1.87(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1)(scheduler@0.23.0): + resolution: {integrity: sha512-B3XK5hZgJDvKTQ536bDCvN8r6RjuA0ndlHjihAzjXefm5u990nEEI0FgjZcIlezEUGfWi5YPo3i3W17KjQ2QCA==} + peerDependencies: + '@types/react': '>=16.14.0 <19.0.0' + '@types/react-dom': '>=16.9.0 <19.0.0' + react: '>=16.14.0 <19.0.0' + react-dom: '>=16.14.0 <19.0.0' + dependencies: + '@fluentui/react-field': 9.1.76(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1)(scheduler@0.23.0) + '@fluentui/react-jsx-runtime': 9.0.44(@types/react@18.3.9)(react@18.3.1) + '@fluentui/react-shared-contexts': 9.20.1(@types/react@18.3.9)(react@18.3.1) + '@fluentui/react-theme': 9.1.20 + '@fluentui/react-utilities': 9.18.15(@types/react@18.3.9)(react@18.3.1) + '@griffel/react': 1.5.25(react@18.3.1) + '@swc/helpers': 0.5.13 + '@types/react': 18.3.9 + '@types/react-dom': 18.3.0 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + transitivePeerDependencies: + - scheduler + dev: false + + /@fluentui/react-provider@9.17.4(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1): + resolution: {integrity: sha512-BjnB8ZSuRPS2h6FP1RiMaR+hiTaX5iogqYktULhFYDeN8DoA6RDkLGrPcaaGqYQTIVKKAJUqN18QoPmh8WBh6A==} + peerDependencies: + '@types/react': '>=16.14.0 <19.0.0' + '@types/react-dom': '>=16.9.0 <19.0.0' + react: '>=16.14.0 <19.0.0' + react-dom: '>=16.14.0 <19.0.0' + dependencies: + '@fluentui/react-icons': 2.0.258(react@18.3.1) + '@fluentui/react-jsx-runtime': 9.0.44(@types/react@18.3.9)(react@18.3.1) + '@fluentui/react-shared-contexts': 9.20.1(@types/react@18.3.9)(react@18.3.1) + '@fluentui/react-tabster': 9.22.7(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1) + '@fluentui/react-theme': 9.1.20 + '@fluentui/react-utilities': 9.18.15(@types/react@18.3.9)(react@18.3.1) + '@griffel/core': 1.18.0 + '@griffel/react': 1.5.25(react@18.3.1) + '@swc/helpers': 0.5.13 + '@types/react': 18.3.9 + '@types/react-dom': 18.3.0 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) dev: false - /@fluentui/react-menu@9.12.46(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0)(scheduler@0.20.2): - resolution: {integrity: sha512-kn67z1tCONXR1nfxzIuG59q+GLm2HCeu39gW9+FhrikvBS8ue/Mq2xQgdrlrc192kCATcd0iA09m1X+DgyQQMA==} + /@fluentui/react-radio@9.2.32(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1)(scheduler@0.23.0): + resolution: {integrity: sha512-KwpK7rn+ATsRPRLXeNzHreCeoLQnMWIW+GzPfAoaHm3NI/cwQSqSdEItbUnWKq7i8evJpyGbPSooboMwlCo9Zw==} peerDependencies: '@types/react': '>=16.14.0 <19.0.0' '@types/react-dom': '>=16.9.0 <19.0.0' react: '>=16.14.0 <19.0.0' react-dom: '>=16.14.0 <19.0.0' - scheduler: ^0.19.0 || ^0.20.0 dependencies: - '@fluentui/keyboard-keys': 9.0.7 - '@fluentui/react-aria': 9.8.0(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0) - '@fluentui/react-context-selector': 9.1.50(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0)(scheduler@0.20.2) - '@fluentui/react-icons': 2.0.225(react@18.2.0) - '@fluentui/react-jsx-runtime': 9.0.28(@types/react@18.0.0)(react@18.2.0) - '@fluentui/react-portal': 9.4.11(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0) - '@fluentui/react-positioning': 9.12.5(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0) - '@fluentui/react-shared-contexts': 9.14.0(@types/react@18.0.0)(react@18.2.0) - '@fluentui/react-tabster': 9.17.4(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0) - '@fluentui/react-theme': 9.1.16 - '@fluentui/react-utilities': 9.17.0(@types/react@18.0.0)(react@18.2.0) - '@griffel/react': 1.5.20(react@18.2.0) - '@swc/helpers': 0.5.3 - '@types/react': 18.0.0 - '@types/react-dom': 18.0.0 - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) - scheduler: 0.20.2 + '@fluentui/react-field': 9.1.76(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1)(scheduler@0.23.0) + '@fluentui/react-jsx-runtime': 9.0.44(@types/react@18.3.9)(react@18.3.1) + '@fluentui/react-label': 9.1.76(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1) + '@fluentui/react-shared-contexts': 9.20.1(@types/react@18.3.9)(react@18.3.1) + '@fluentui/react-tabster': 9.22.7(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1) + '@fluentui/react-theme': 9.1.20 + '@fluentui/react-utilities': 9.18.15(@types/react@18.3.9)(react@18.3.1) + '@griffel/react': 1.5.25(react@18.3.1) + '@swc/helpers': 0.5.13 + '@types/react': 18.3.9 + '@types/react-dom': 18.3.0 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + transitivePeerDependencies: + - scheduler dev: false - /@fluentui/react-overflow@9.1.9(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0)(scheduler@0.20.2): - resolution: {integrity: sha512-MQWvslL/KQRx0LCdYU8Ewq4mqxcYs+6IyuRen+e2Q4IiylOTP4QOszTo7HS3PZYcLA2vaMa7FSecNeY86Ti60w==} + /@fluentui/react-rating@9.0.19(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1): + resolution: {integrity: sha512-c1/tEJXx2DpDeJ8r1AbrCtRQb+4RlM9tMoQDuHqLxscmrrxvvKCbjqCOvA/myiMczuAsp2z6Fvlc4LESjdqxpA==} peerDependencies: - '@types/react': '>=16.14.0 <19.0.0' - '@types/react-dom': '>=16.9.0 <19.0.0' + '@types/react': '>=16.8.0 <19.0.0' + '@types/react-dom': '>=16.8.0 <19.0.0' react: '>=16.14.0 <19.0.0' - react-dom: '>=16.14.0 <19.0.0' - scheduler: ^0.19.0 || ^0.20.0 - dependencies: - '@fluentui/priority-overflow': 9.1.11 - '@fluentui/react-context-selector': 9.1.50(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0)(scheduler@0.20.2) - '@fluentui/react-theme': 9.1.16 - '@fluentui/react-utilities': 9.17.0(@types/react@18.0.0)(react@18.2.0) - '@griffel/react': 1.5.20(react@18.2.0) - '@swc/helpers': 0.5.3 - '@types/react': 18.0.0 - '@types/react-dom': 18.0.0 - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) - scheduler: 0.20.2 + react-dom: '>=16.8.0 <19.0.0' + dependencies: + '@fluentui/react-icons': 2.0.258(react@18.3.1) + '@fluentui/react-jsx-runtime': 9.0.44(@types/react@18.3.9)(react@18.3.1) + '@fluentui/react-tabster': 9.22.7(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1) + '@fluentui/react-theme': 9.1.20 + '@fluentui/react-utilities': 9.18.15(@types/react@18.3.9)(react@18.3.1) + '@griffel/react': 1.5.25(react@18.3.1) + '@swc/helpers': 0.5.13 + '@types/react': 18.3.9 + '@types/react-dom': 18.3.0 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) dev: false - /@fluentui/react-persona@9.2.69(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0)(scheduler@0.20.2): - resolution: {integrity: sha512-9I3PppRQYGRdmytJVu4kQ/Nx124ke4yNHzMfgTqwnTzKVHzP4LvpHaY0Vb7MVppGetjUct3SdopMfThWiyVnPA==} + /@fluentui/react-search@9.0.18(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1)(scheduler@0.23.0): + resolution: {integrity: sha512-bUxi28d8KfrKKaG61n5YXE/A7qrp6amwrn/+iJo9PXYN4FlY8FAjYQ9vZOjR+1yWmNbaSisuZHKA7IisrmahEQ==} peerDependencies: '@types/react': '>=16.14.0 <19.0.0' '@types/react-dom': '>=16.9.0 <19.0.0' react: '>=16.14.0 <19.0.0' react-dom: '>=16.14.0 <19.0.0' dependencies: - '@fluentui/react-avatar': 9.6.10(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0)(scheduler@0.20.2) - '@fluentui/react-badge': 9.2.23(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0) - '@fluentui/react-jsx-runtime': 9.0.28(@types/react@18.0.0)(react@18.2.0) - '@fluentui/react-shared-contexts': 9.14.0(@types/react@18.0.0)(react@18.2.0) - '@fluentui/react-theme': 9.1.16 - '@fluentui/react-utilities': 9.17.0(@types/react@18.0.0)(react@18.2.0) - '@griffel/react': 1.5.20(react@18.2.0) - '@swc/helpers': 0.5.3 - '@types/react': 18.0.0 - '@types/react-dom': 18.0.0 - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) + '@fluentui/react-icons': 2.0.258(react@18.3.1) + '@fluentui/react-input': 9.4.89(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1)(scheduler@0.23.0) + '@fluentui/react-jsx-runtime': 9.0.44(@types/react@18.3.9)(react@18.3.1) + '@fluentui/react-theme': 9.1.20 + '@fluentui/react-utilities': 9.18.15(@types/react@18.3.9)(react@18.3.1) + '@griffel/react': 1.5.25(react@18.3.1) + '@swc/helpers': 0.5.13 + '@types/react': 18.3.9 + '@types/react-dom': 18.3.0 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) transitivePeerDependencies: - scheduler dev: false - /@fluentui/react-popover@9.8.34(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0)(scheduler@0.20.2): - resolution: {integrity: sha512-82NU4pE0uU3cBIFogFsXtJ8VH6izq7yizOKA0CUxnuxxlm8xwX5QgWHtBccARhuNm979jcHJcGwmVW2Yj2TB/A==} + /@fluentui/react-select@9.1.87(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1)(scheduler@0.23.0): + resolution: {integrity: sha512-LlREKNfCxpXh9j1D27FL/WLgoJs5vKK4HBFpAr4FGII0OFIl2wMCb7SpeaBziuPQU7EnEjeqHlG2hN5oVARoJw==} peerDependencies: '@types/react': '>=16.14.0 <19.0.0' '@types/react-dom': '>=16.9.0 <19.0.0' react: '>=16.14.0 <19.0.0' react-dom: '>=16.14.0 <19.0.0' - scheduler: ^0.19.0 || ^0.20.0 dependencies: - '@fluentui/keyboard-keys': 9.0.7 - '@fluentui/react-aria': 9.8.0(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0) - '@fluentui/react-context-selector': 9.1.50(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0)(scheduler@0.20.2) - '@fluentui/react-jsx-runtime': 9.0.28(@types/react@18.0.0)(react@18.2.0) - '@fluentui/react-portal': 9.4.11(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0) - '@fluentui/react-positioning': 9.12.5(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0) - '@fluentui/react-shared-contexts': 9.14.0(@types/react@18.0.0)(react@18.2.0) - '@fluentui/react-tabster': 9.17.4(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0) - '@fluentui/react-theme': 9.1.16 - '@fluentui/react-utilities': 9.17.0(@types/react@18.0.0)(react@18.2.0) - '@griffel/react': 1.5.20(react@18.2.0) - '@swc/helpers': 0.5.3 - '@types/react': 18.0.0 - '@types/react-dom': 18.0.0 - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) - scheduler: 0.20.2 + '@fluentui/react-field': 9.1.76(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1)(scheduler@0.23.0) + '@fluentui/react-icons': 2.0.258(react@18.3.1) + '@fluentui/react-jsx-runtime': 9.0.44(@types/react@18.3.9)(react@18.3.1) + '@fluentui/react-shared-contexts': 9.20.1(@types/react@18.3.9)(react@18.3.1) + '@fluentui/react-theme': 9.1.20 + '@fluentui/react-utilities': 9.18.15(@types/react@18.3.9)(react@18.3.1) + '@griffel/react': 1.5.25(react@18.3.1) + '@swc/helpers': 0.5.13 + '@types/react': 18.3.9 + '@types/react-dom': 18.3.0 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + transitivePeerDependencies: + - scheduler dev: false - /@fluentui/react-portal-compat-context@9.0.11(@types/react@18.0.0)(react@18.2.0): - resolution: {integrity: sha512-ubvW/ej0O+Pago9GH3mPaxzUgsNnBoqvghNamWjyKvZIViyaXUG6+sgcAl721R+qGAFac+A20akI5qDJz/xtdg==} + /@fluentui/react-shared-contexts@9.20.1(@types/react@18.3.9)(react@18.3.1): + resolution: {integrity: sha512-QoduMl+QkZ3FEyiSc+rCBbCLY88L/uX8o/eXoJOI0v1px/+5iYkCIUlQPiU9nCGjAI+C8AmG4pIJ7h5iLUlAyQ==} peerDependencies: '@types/react': '>=16.14.0 <19.0.0' react: '>=16.14.0 <19.0.0' dependencies: - '@swc/helpers': 0.5.3 - '@types/react': 18.0.0 - react: 18.2.0 + '@fluentui/react-theme': 9.1.20 + '@swc/helpers': 0.5.13 + '@types/react': 18.3.9 + react: 18.3.1 dev: false - /@fluentui/react-portal@9.4.11(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-9p2zwKDCW1V7MiAfV0/fPFSAizyiQzli5C7gTenrHCnIoAQGRjSBkWkJtlmtBSBeH+3pQuqFOGOodef0qKx7QA==} + /@fluentui/react-skeleton@9.1.16(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1)(scheduler@0.23.0): + resolution: {integrity: sha512-bRRB3DOxmX1lM1dAayAsIpVZU2rIOzlHpO7yVV9LhWGnGnfNRhYCcM3WSQXhdCmGdUSbb02lSo85PYB/JyW9Zw==} peerDependencies: '@types/react': '>=16.14.0 <19.0.0' '@types/react-dom': '>=16.9.0 <19.0.0' react: '>=16.14.0 <19.0.0' react-dom: '>=16.14.0 <19.0.0' dependencies: - '@fluentui/react-shared-contexts': 9.14.0(@types/react@18.0.0)(react@18.2.0) - '@fluentui/react-tabster': 9.17.4(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0) - '@fluentui/react-utilities': 9.17.0(@types/react@18.0.0)(react@18.2.0) - '@griffel/react': 1.5.20(react@18.2.0) - '@swc/helpers': 0.5.3 - '@types/react': 18.0.0 - '@types/react-dom': 18.0.0 - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) - use-disposable: 1.0.2(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0) + '@fluentui/react-field': 9.1.76(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1)(scheduler@0.23.0) + '@fluentui/react-jsx-runtime': 9.0.44(@types/react@18.3.9)(react@18.3.1) + '@fluentui/react-shared-contexts': 9.20.1(@types/react@18.3.9)(react@18.3.1) + '@fluentui/react-theme': 9.1.20 + '@fluentui/react-utilities': 9.18.15(@types/react@18.3.9)(react@18.3.1) + '@griffel/react': 1.5.25(react@18.3.1) + '@swc/helpers': 0.5.13 + '@types/react': 18.3.9 + '@types/react-dom': 18.3.0 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + transitivePeerDependencies: + - scheduler dev: false - /@fluentui/react-positioning@9.12.5(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-P01pyDxcthHeOlKv4CGlS/ll9qE/er5dGohq9/wN/FBnbb7F3c5+UYQPJwLfJXMO5fIsnH6RmfXndqRa8cKlqA==} + /@fluentui/react-slider@9.1.94(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1)(scheduler@0.23.0): + resolution: {integrity: sha512-7US332rPd6rH8KRFP3TvAwxMGx/UKJo/Bv0i9rtszNPDi0nF1988uvvj1sfC4MA2I343ASajs+lnaav14BUa9g==} peerDependencies: '@types/react': '>=16.14.0 <19.0.0' '@types/react-dom': '>=16.9.0 <19.0.0' react: '>=16.14.0 <19.0.0' react-dom: '>=16.14.0 <19.0.0' dependencies: - '@floating-ui/devtools': 0.2.1(@floating-ui/dom@1.5.4) - '@floating-ui/dom': 1.5.4 - '@fluentui/react-shared-contexts': 9.14.0(@types/react@18.0.0)(react@18.2.0) - '@fluentui/react-theme': 9.1.16 - '@fluentui/react-utilities': 9.17.0(@types/react@18.0.0)(react@18.2.0) - '@griffel/react': 1.5.20(react@18.2.0) - '@swc/helpers': 0.5.3 - '@types/react': 18.0.0 - '@types/react-dom': 18.0.0 - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) + '@fluentui/react-field': 9.1.76(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1)(scheduler@0.23.0) + '@fluentui/react-jsx-runtime': 9.0.44(@types/react@18.3.9)(react@18.3.1) + '@fluentui/react-shared-contexts': 9.20.1(@types/react@18.3.9)(react@18.3.1) + '@fluentui/react-tabster': 9.22.7(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1) + '@fluentui/react-theme': 9.1.20 + '@fluentui/react-utilities': 9.18.15(@types/react@18.3.9)(react@18.3.1) + '@griffel/react': 1.5.25(react@18.3.1) + '@swc/helpers': 0.5.13 + '@types/react': 18.3.9 + '@types/react-dom': 18.3.0 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + transitivePeerDependencies: + - scheduler dev: false - /@fluentui/react-progress@9.0.0-alpha.16(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0)(scheduler@0.20.2): - resolution: {integrity: sha512-HyDV4TfIcXsaWXnJNC2uNqv+xkm4dozDZo0r7J2HsGFaYU4ZZCjJdIC7hDfiOfeKPxDnZrMrM95tS/AL3eQGlw==} + /@fluentui/react-spinbutton@9.2.88(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1)(scheduler@0.23.0): + resolution: {integrity: sha512-UDsPhLOqQieGzPF5a9WNTB3qo49y65rhjNd7Fq1j2Vc003P02USl4MyonTkPugsNoMm30slxgErym5bLj3Cbug==} peerDependencies: - '@types/react': '>=16.8.0 <19.0.0' - '@types/react-dom': '>=16.8.0 <19.0.0' - react: '>=16.8.0 <19.0.0' - react-dom: '>=16.8.0 <19.0.0' + '@types/react': '>=16.14.0 <19.0.0' + '@types/react-dom': '>=16.9.0 <19.0.0' + react: '>=16.14.0 <19.0.0' + react-dom: '>=16.14.0 <19.0.0' dependencies: - '@fluentui/react-field': 9.0.0-alpha.19(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0)(scheduler@0.20.2) - '@fluentui/react-shared-contexts': 9.14.0(@types/react@18.0.0)(react@18.2.0) - '@fluentui/react-theme': 9.1.16 - '@fluentui/react-utilities': 9.17.0(@types/react@18.0.0)(react@18.2.0) - '@griffel/react': 1.5.20(react@18.2.0) - '@types/react': 18.0.0 - '@types/react-dom': 18.0.0 - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) - tslib: 2.6.1 + '@fluentui/keyboard-keys': 9.0.7 + '@fluentui/react-field': 9.1.76(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1)(scheduler@0.23.0) + '@fluentui/react-icons': 2.0.258(react@18.3.1) + '@fluentui/react-jsx-runtime': 9.0.44(@types/react@18.3.9)(react@18.3.1) + '@fluentui/react-shared-contexts': 9.20.1(@types/react@18.3.9)(react@18.3.1) + '@fluentui/react-theme': 9.1.20 + '@fluentui/react-utilities': 9.18.15(@types/react@18.3.9)(react@18.3.1) + '@griffel/react': 1.5.25(react@18.3.1) + '@swc/helpers': 0.5.13 + '@types/react': 18.3.9 + '@types/react-dom': 18.3.0 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) transitivePeerDependencies: - scheduler dev: false - /@fluentui/react-provider@9.13.9(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-3ctGun9WGeeSwP/GkJjJXzNxSX9zi4IlZC9b6FTagmRYOvaeskFiCQIcJmJuBYTxSKAcYKLm4M0RvrOjEt/wbg==} + /@fluentui/react-spinner@9.4.14(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1): + resolution: {integrity: sha512-CT38dZhvXWxcUWZaL0jwuxj5P0ttQp4Njx3ZhIXn87/8HIxGGT9QOirBjp+1nGq5gA5q1AYyPy4sbrcculA48Q==} peerDependencies: '@types/react': '>=16.14.0 <19.0.0' '@types/react-dom': '>=16.9.0 <19.0.0' react: '>=16.14.0 <19.0.0' react-dom: '>=16.14.0 <19.0.0' dependencies: - '@fluentui/react-icons': 2.0.225(react@18.2.0) - '@fluentui/react-jsx-runtime': 9.0.28(@types/react@18.0.0)(react@18.2.0) - '@fluentui/react-shared-contexts': 9.14.0(@types/react@18.0.0)(react@18.2.0) - '@fluentui/react-tabster': 9.17.4(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0) - '@fluentui/react-theme': 9.1.16 - '@fluentui/react-utilities': 9.17.0(@types/react@18.0.0)(react@18.2.0) - '@griffel/core': 1.15.2 - '@griffel/react': 1.5.20(react@18.2.0) - '@swc/helpers': 0.5.3 - '@types/react': 18.0.0 - '@types/react-dom': 18.0.0 - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) + '@fluentui/react-jsx-runtime': 9.0.44(@types/react@18.3.9)(react@18.3.1) + '@fluentui/react-label': 9.1.76(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1) + '@fluentui/react-shared-contexts': 9.20.1(@types/react@18.3.9)(react@18.3.1) + '@fluentui/react-theme': 9.1.20 + '@fluentui/react-utilities': 9.18.15(@types/react@18.3.9)(react@18.3.1) + '@griffel/react': 1.5.25(react@18.3.1) + '@swc/helpers': 0.5.13 + '@types/react': 18.3.9 + '@types/react-dom': 18.3.0 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) dev: false - /@fluentui/react-radio@9.2.4(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0)(scheduler@0.20.2): - resolution: {integrity: sha512-E+EwdRol4hniqTfuWqe7iqECCrEF8McKotr1gjkSRYOofqUxvwlZmX7rwAwITqauhNVb1ADD1QNkN5jClc2sIg==} + /@fluentui/react-swatch-picker@9.1.10(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1)(scheduler@0.23.0): + resolution: {integrity: sha512-3vymANhAbyD+iV0ENQe4atX0lEDqFfgO5uQzrVl7jQdfmkaBmuzdlqPJ9Tl/wyEsiEys3+1JkgDiS0MoOrTTlg==} peerDependencies: - '@types/react': '>=16.14.0 <19.0.0' - '@types/react-dom': '>=16.9.0 <19.0.0' + '@types/react': '>=16.8.0 <19.0.0' + '@types/react-dom': '>=16.8.0 <19.0.0' react: '>=16.14.0 <19.0.0' - react-dom: '>=16.14.0 <19.0.0' - scheduler: ^0.19.0 || ^0.20.0 - dependencies: - '@fluentui/react-field': 9.1.51(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0)(scheduler@0.20.2) - '@fluentui/react-jsx-runtime': 9.0.28(@types/react@18.0.0)(react@18.2.0) - '@fluentui/react-label': 9.1.59(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0) - '@fluentui/react-shared-contexts': 9.14.0(@types/react@18.0.0)(react@18.2.0) - '@fluentui/react-tabster': 9.17.4(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0) - '@fluentui/react-theme': 9.1.16 - '@fluentui/react-utilities': 9.17.0(@types/react@18.0.0)(react@18.2.0) - '@griffel/react': 1.5.20(react@18.2.0) - '@swc/helpers': 0.5.3 - '@types/react': 18.0.0 - '@types/react-dom': 18.0.0 - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) - scheduler: 0.20.2 + react-dom: '>=16.8.0 <19.0.0' + dependencies: + '@fluentui/react-context-selector': 9.1.67(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1)(scheduler@0.23.0) + '@fluentui/react-icons': 2.0.258(react@18.3.1) + '@fluentui/react-jsx-runtime': 9.0.44(@types/react@18.3.9)(react@18.3.1) + '@fluentui/react-shared-contexts': 9.20.1(@types/react@18.3.9)(react@18.3.1) + '@fluentui/react-tabster': 9.22.7(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1) + '@fluentui/react-theme': 9.1.20 + '@fluentui/react-utilities': 9.18.15(@types/react@18.3.9)(react@18.3.1) + '@griffel/react': 1.5.25(react@18.3.1) + '@swc/helpers': 0.5.13 + '@types/react': 18.3.9 + '@types/react-dom': 18.3.0 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + transitivePeerDependencies: + - scheduler dev: false - /@fluentui/react-select@9.1.61(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0)(scheduler@0.20.2): - resolution: {integrity: sha512-QRwzno9suuYthFLHdzb63/bLrA6w/EATbJTUKSVYPVrbQUzSjpm+NHyCf3PWXSU57+Yxujq5r1jBGua9VougrQ==} + /@fluentui/react-switch@9.1.94(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1)(scheduler@0.23.0): + resolution: {integrity: sha512-MXsOmfGHc9b/JEwplZi7LHmk7t8c/rzgK5Z9Avpbj19+sNsHJlnyl7IwLEVJHwxgO3r5dp1fgPbsmUdEoBEyOg==} peerDependencies: '@types/react': '>=16.14.0 <19.0.0' '@types/react-dom': '>=16.9.0 <19.0.0' react: '>=16.14.0 <19.0.0' react-dom: '>=16.14.0 <19.0.0' dependencies: - '@fluentui/react-field': 9.1.51(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0)(scheduler@0.20.2) - '@fluentui/react-icons': 2.0.225(react@18.2.0) - '@fluentui/react-jsx-runtime': 9.0.28(@types/react@18.0.0)(react@18.2.0) - '@fluentui/react-shared-contexts': 9.14.0(@types/react@18.0.0)(react@18.2.0) - '@fluentui/react-theme': 9.1.16 - '@fluentui/react-utilities': 9.17.0(@types/react@18.0.0)(react@18.2.0) - '@griffel/react': 1.5.20(react@18.2.0) - '@swc/helpers': 0.5.3 - '@types/react': 18.0.0 - '@types/react-dom': 18.0.0 - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) + '@fluentui/react-field': 9.1.76(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1)(scheduler@0.23.0) + '@fluentui/react-icons': 2.0.258(react@18.3.1) + '@fluentui/react-jsx-runtime': 9.0.44(@types/react@18.3.9)(react@18.3.1) + '@fluentui/react-label': 9.1.76(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1) + '@fluentui/react-shared-contexts': 9.20.1(@types/react@18.3.9)(react@18.3.1) + '@fluentui/react-tabster': 9.22.7(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1) + '@fluentui/react-theme': 9.1.20 + '@fluentui/react-utilities': 9.18.15(@types/react@18.3.9)(react@18.3.1) + '@griffel/react': 1.5.25(react@18.3.1) + '@swc/helpers': 0.5.13 + '@types/react': 18.3.9 + '@types/react-dom': 18.3.0 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) transitivePeerDependencies: - scheduler dev: false - /@fluentui/react-shared-contexts@9.14.0(@types/react@18.0.0)(react@18.2.0): - resolution: {integrity: sha512-P9yhg31WYfB1W66/gD3+qVCLBsyIEcOzQvKVaIQvd9UhF67lNW4kMXUB6YVOk5PV0Og4hXnkH/vuHl7YMD9RHw==} + /@fluentui/react-table@9.15.18(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1)(scheduler@0.23.0): + resolution: {integrity: sha512-JbQeo8JW3o6kZ/01ynouCv6kTA22+lOUnig5h6npbuxTc8pR8erJ0a+D384a80o+vjN26ww1KXhCpkJLDWG6Bg==} peerDependencies: '@types/react': '>=16.14.0 <19.0.0' + '@types/react-dom': '>=16.9.0 <19.0.0' react: '>=16.14.0 <19.0.0' + react-dom: '>=16.14.0 <19.0.0' dependencies: - '@fluentui/react-theme': 9.1.16 - '@swc/helpers': 0.5.3 - '@types/react': 18.0.0 - react: 18.2.0 + '@fluentui/keyboard-keys': 9.0.7 + '@fluentui/react-aria': 9.13.6(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1) + '@fluentui/react-avatar': 9.6.39(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1)(scheduler@0.23.0) + '@fluentui/react-checkbox': 9.2.37(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1)(scheduler@0.23.0) + '@fluentui/react-context-selector': 9.1.67(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1)(scheduler@0.23.0) + '@fluentui/react-icons': 2.0.258(react@18.3.1) + '@fluentui/react-jsx-runtime': 9.0.44(@types/react@18.3.9)(react@18.3.1) + '@fluentui/react-radio': 9.2.32(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1)(scheduler@0.23.0) + '@fluentui/react-shared-contexts': 9.20.1(@types/react@18.3.9)(react@18.3.1) + '@fluentui/react-tabster': 9.22.7(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1) + '@fluentui/react-theme': 9.1.20 + '@fluentui/react-utilities': 9.18.15(@types/react@18.3.9)(react@18.3.1) + '@griffel/react': 1.5.25(react@18.3.1) + '@swc/helpers': 0.5.13 + '@types/react': 18.3.9 + '@types/react-dom': 18.3.0 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + transitivePeerDependencies: + - scheduler dev: false - /@fluentui/react-slider@9.1.66(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0)(scheduler@0.20.2): - resolution: {integrity: sha512-gYUFU3HAqR735sUMcGOcyLaJ6iLgmoN4ZPN1G6bqQETiesyN34QpC4HqmW8i7TEerMjv2crUb/CjsvIOZfzdPw==} + /@fluentui/react-tabs@9.5.1(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1)(scheduler@0.23.0): + resolution: {integrity: sha512-tBPyIvTvQnDtTtvWW7qgmK9Wz4DUEZU7MUmG6/n5aKluzutiCA7uC33xa8ndUibxEBSMiVJVHL7VTeo/+1/3eQ==} peerDependencies: '@types/react': '>=16.14.0 <19.0.0' '@types/react-dom': '>=16.9.0 <19.0.0' react: '>=16.14.0 <19.0.0' react-dom: '>=16.14.0 <19.0.0' dependencies: - '@fluentui/react-field': 9.1.51(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0)(scheduler@0.20.2) - '@fluentui/react-jsx-runtime': 9.0.28(@types/react@18.0.0)(react@18.2.0) - '@fluentui/react-shared-contexts': 9.14.0(@types/react@18.0.0)(react@18.2.0) - '@fluentui/react-tabster': 9.17.4(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0) - '@fluentui/react-theme': 9.1.16 - '@fluentui/react-utilities': 9.17.0(@types/react@18.0.0)(react@18.2.0) - '@griffel/react': 1.5.20(react@18.2.0) - '@swc/helpers': 0.5.3 - '@types/react': 18.0.0 - '@types/react-dom': 18.0.0 - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) + '@fluentui/react-context-selector': 9.1.67(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1)(scheduler@0.23.0) + '@fluentui/react-jsx-runtime': 9.0.44(@types/react@18.3.9)(react@18.3.1) + '@fluentui/react-shared-contexts': 9.20.1(@types/react@18.3.9)(react@18.3.1) + '@fluentui/react-tabster': 9.22.7(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1) + '@fluentui/react-theme': 9.1.20 + '@fluentui/react-utilities': 9.18.15(@types/react@18.3.9)(react@18.3.1) + '@griffel/react': 1.5.25(react@18.3.1) + '@swc/helpers': 0.5.13 + '@types/react': 18.3.9 + '@types/react-dom': 18.3.0 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) transitivePeerDependencies: - scheduler dev: false - /@fluentui/react-spinbutton@9.2.61(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0)(scheduler@0.20.2): - resolution: {integrity: sha512-9+TBgSCvRhX78e/KPuhIvEH1bmAB9Wv6CsYhXmJdMSLdZt8R0Gx5oGvSynxCOLazIx/1/lvGi48AAnqTg0OEpQ==} + /@fluentui/react-tabster@9.22.7(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1): + resolution: {integrity: sha512-ITvm69INou9WGVN+l+iJhYFZ+8zEgP++IKu7/oUxOfjNYzqDzEm3Q8u4oxdlv9ofVGT1qXZhA7jSDE6DOnlXmA==} peerDependencies: '@types/react': '>=16.14.0 <19.0.0' '@types/react-dom': '>=16.9.0 <19.0.0' react: '>=16.14.0 <19.0.0' react-dom: '>=16.14.0 <19.0.0' dependencies: - '@fluentui/keyboard-keys': 9.0.7 - '@fluentui/react-field': 9.1.51(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0)(scheduler@0.20.2) - '@fluentui/react-icons': 2.0.225(react@18.2.0) - '@fluentui/react-jsx-runtime': 9.0.28(@types/react@18.0.0)(react@18.2.0) - '@fluentui/react-shared-contexts': 9.14.0(@types/react@18.0.0)(react@18.2.0) - '@fluentui/react-theme': 9.1.16 - '@fluentui/react-utilities': 9.17.0(@types/react@18.0.0)(react@18.2.0) - '@griffel/react': 1.5.20(react@18.2.0) - '@swc/helpers': 0.5.3 - '@types/react': 18.0.0 - '@types/react-dom': 18.0.0 - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) - transitivePeerDependencies: - - scheduler + '@fluentui/react-shared-contexts': 9.20.1(@types/react@18.3.9)(react@18.3.1) + '@fluentui/react-theme': 9.1.20 + '@fluentui/react-utilities': 9.18.15(@types/react@18.3.9)(react@18.3.1) + '@griffel/react': 1.5.25(react@18.3.1) + '@swc/helpers': 0.5.13 + '@types/react': 18.3.9 + '@types/react-dom': 18.3.0 + keyborg: 2.6.0 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + tabster: 8.2.0 dev: false - /@fluentui/react-spinner@9.3.39(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-1+MrNFFyN/Ceikan6eAAY2NWIGk3nr2TfY5RcMuG7ZVUb2Q/mYnxrRLEN+m18fqHNVUGC9UaejJ4hDuL2rmjjQ==} + /@fluentui/react-tag-picker@9.3.4(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1)(scheduler@0.23.0): + resolution: {integrity: sha512-eV6snlflC9LCZeqrhPDU/p9OeXC/Kb5CX502/N6yuT25GcV1u3pePvPBKG4ac090nSlC54/GgYBmCHS5m5+r4w==} peerDependencies: '@types/react': '>=16.14.0 <19.0.0' '@types/react-dom': '>=16.9.0 <19.0.0' react: '>=16.14.0 <19.0.0' react-dom: '>=16.14.0 <19.0.0' dependencies: - '@fluentui/react-jsx-runtime': 9.0.28(@types/react@18.0.0)(react@18.2.0) - '@fluentui/react-label': 9.1.59(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0) - '@fluentui/react-shared-contexts': 9.14.0(@types/react@18.0.0)(react@18.2.0) - '@fluentui/react-theme': 9.1.16 - '@fluentui/react-utilities': 9.17.0(@types/react@18.0.0)(react@18.2.0) - '@griffel/react': 1.5.20(react@18.2.0) - '@swc/helpers': 0.5.3 - '@types/react': 18.0.0 - '@types/react-dom': 18.0.0 - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) + '@fluentui/keyboard-keys': 9.0.7 + '@fluentui/react-aria': 9.13.6(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1) + '@fluentui/react-combobox': 9.13.8(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1)(scheduler@0.23.0) + '@fluentui/react-context-selector': 9.1.67(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1)(scheduler@0.23.0) + '@fluentui/react-field': 9.1.76(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1)(scheduler@0.23.0) + '@fluentui/react-icons': 2.0.258(react@18.3.1) + '@fluentui/react-jsx-runtime': 9.0.44(@types/react@18.3.9)(react@18.3.1) + '@fluentui/react-portal': 9.4.35(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1) + '@fluentui/react-positioning': 9.15.9(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1) + '@fluentui/react-shared-contexts': 9.20.1(@types/react@18.3.9)(react@18.3.1) + '@fluentui/react-tabster': 9.22.7(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1) + '@fluentui/react-tags': 9.3.18(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1)(scheduler@0.23.0) + '@fluentui/react-theme': 9.1.20 + '@fluentui/react-utilities': 9.18.15(@types/react@18.3.9)(react@18.3.1) + '@griffel/react': 1.5.25(react@18.3.1) + '@swc/helpers': 0.5.13 + '@types/react': 18.3.9 + '@types/react-dom': 18.3.0 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + transitivePeerDependencies: + - scheduler dev: false - /@fluentui/react-switch@9.1.66(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0)(scheduler@0.20.2): - resolution: {integrity: sha512-owrQy4hhTxcRQCG/9TPPWwu2cVET0FOHKQdnQzsCfbK6BoXJmFHg6tCYBeqJ1ZLKLN6VxWrSn8CUB2n1Zr8N8Q==} + /@fluentui/react-tags@9.3.18(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1)(scheduler@0.23.0): + resolution: {integrity: sha512-DSZJx95xeF3Hhw5VardJAAApeGdR9BHZt+oJmZl0qdHPShQTh9g848kSXy94iwK2xU3VWfenBWPSk+LqEIwxxg==} peerDependencies: '@types/react': '>=16.14.0 <19.0.0' '@types/react-dom': '>=16.9.0 <19.0.0' react: '>=16.14.0 <19.0.0' react-dom: '>=16.14.0 <19.0.0' dependencies: - '@fluentui/react-field': 9.1.51(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0)(scheduler@0.20.2) - '@fluentui/react-icons': 2.0.225(react@18.2.0) - '@fluentui/react-jsx-runtime': 9.0.28(@types/react@18.0.0)(react@18.2.0) - '@fluentui/react-label': 9.1.59(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0) - '@fluentui/react-shared-contexts': 9.14.0(@types/react@18.0.0)(react@18.2.0) - '@fluentui/react-tabster': 9.17.4(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0) - '@fluentui/react-theme': 9.1.16 - '@fluentui/react-utilities': 9.17.0(@types/react@18.0.0)(react@18.2.0) - '@griffel/react': 1.5.20(react@18.2.0) - '@swc/helpers': 0.5.3 - '@types/react': 18.0.0 - '@types/react-dom': 18.0.0 - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) + '@fluentui/keyboard-keys': 9.0.7 + '@fluentui/react-aria': 9.13.6(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1) + '@fluentui/react-avatar': 9.6.39(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1)(scheduler@0.23.0) + '@fluentui/react-icons': 2.0.258(react@18.3.1) + '@fluentui/react-jsx-runtime': 9.0.44(@types/react@18.3.9)(react@18.3.1) + '@fluentui/react-shared-contexts': 9.20.1(@types/react@18.3.9)(react@18.3.1) + '@fluentui/react-tabster': 9.22.7(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1) + '@fluentui/react-theme': 9.1.20 + '@fluentui/react-utilities': 9.18.15(@types/react@18.3.9)(react@18.3.1) + '@griffel/react': 1.5.25(react@18.3.1) + '@swc/helpers': 0.5.13 + '@types/react': 18.3.9 + '@types/react-dom': 18.3.0 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) transitivePeerDependencies: - scheduler dev: false - /@fluentui/react-table@9.0.0(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0)(scheduler@0.20.2): - resolution: {integrity: sha512-rDIQNykBSSJMvqDYcVH8OQogidnYOUTUuunsnfe5+5YYD6ASnQ60T4KfpE3yqnz4SGvSqrFJ3zRR2LetndowDg==} + /@fluentui/react-teaching-popover@9.1.18(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1)(scheduler@0.23.0): + resolution: {integrity: sha512-v2HMRMj9etIUPs8G+pfv57SODwjTnZ9trNoSq5IfM5Fh1Rg6TnFAUGweWA2k0M0JKtRXkCixOCqNUiBXen0zXw==} peerDependencies: '@types/react': '>=16.8.0 <19.0.0' '@types/react-dom': '>=16.8.0 <19.0.0' - react: '>=16.8.0 <19.0.0' + react: '>=16.14.0 <19.0.0' react-dom: '>=16.8.0 <19.0.0' dependencies: - '@fluentui/keyboard-keys': 9.0.7 - '@fluentui/react-aria': 9.8.0(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0) - '@fluentui/react-avatar': 9.6.10(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0)(scheduler@0.20.2) - '@fluentui/react-checkbox': 9.2.9(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0)(scheduler@0.20.2) - '@fluentui/react-context-selector': 9.1.50(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0)(scheduler@0.20.2) - '@fluentui/react-icons': 2.0.225(react@18.2.0) - '@fluentui/react-radio': 9.2.4(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0)(scheduler@0.20.2) - '@fluentui/react-shared-contexts': 9.14.0(@types/react@18.0.0)(react@18.2.0) - '@fluentui/react-tabster': 9.17.4(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0) - '@fluentui/react-theme': 9.1.16 - '@fluentui/react-utilities': 9.17.0(@types/react@18.0.0)(react@18.2.0) - '@griffel/react': 1.5.20(react@18.2.0) - '@types/react': 18.0.0 - '@types/react-dom': 18.0.0 - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) - tslib: 2.6.1 + '@fluentui/react-aria': 9.13.6(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1) + '@fluentui/react-button': 9.3.92(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1) + '@fluentui/react-context-selector': 9.1.67(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1)(scheduler@0.23.0) + '@fluentui/react-icons': 2.0.258(react@18.3.1) + '@fluentui/react-jsx-runtime': 9.0.44(@types/react@18.3.9)(react@18.3.1) + '@fluentui/react-popover': 9.9.21(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1)(scheduler@0.23.0) + '@fluentui/react-shared-contexts': 9.20.1(@types/react@18.3.9)(react@18.3.1) + '@fluentui/react-tabster': 9.22.7(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1) + '@fluentui/react-theme': 9.1.20 + '@fluentui/react-utilities': 9.18.15(@types/react@18.3.9)(react@18.3.1) + '@griffel/react': 1.5.25(react@18.3.1) + '@swc/helpers': 0.5.13 + '@types/react': 18.3.9 + '@types/react-dom': 18.3.0 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + use-sync-external-store: 1.2.2(react@18.3.1) transitivePeerDependencies: - scheduler dev: false - /@fluentui/react-tabs@9.4.7(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0)(scheduler@0.20.2): - resolution: {integrity: sha512-BZBamJCRF0eOw/lCFI1aH+FEsISBvR5g+Ck1f9m4OQf4/SxK1jsubCith/dlGVFfM5WiCwH5BSeAaKVtr8mO9A==} + /@fluentui/react-text@9.4.25(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1): + resolution: {integrity: sha512-PVEDG1X3z3C8igtI2g2bTSiWPWmzF/6lT2yB70W+lsWmI5+L54aW0rNF2/GOls25N/+MHRAGBIk5SmMWW+SH8g==} peerDependencies: '@types/react': '>=16.14.0 <19.0.0' '@types/react-dom': '>=16.9.0 <19.0.0' react: '>=16.14.0 <19.0.0' react-dom: '>=16.14.0 <19.0.0' - scheduler: ^0.19.0 || ^0.20.0 - dependencies: - '@fluentui/react-context-selector': 9.1.50(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0)(scheduler@0.20.2) - '@fluentui/react-jsx-runtime': 9.0.28(@types/react@18.0.0)(react@18.2.0) - '@fluentui/react-shared-contexts': 9.14.0(@types/react@18.0.0)(react@18.2.0) - '@fluentui/react-tabster': 9.17.4(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0) - '@fluentui/react-theme': 9.1.16 - '@fluentui/react-utilities': 9.17.0(@types/react@18.0.0)(react@18.2.0) - '@griffel/react': 1.5.20(react@18.2.0) - '@swc/helpers': 0.5.3 - '@types/react': 18.0.0 - '@types/react-dom': 18.0.0 - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) - scheduler: 0.20.2 + dependencies: + '@fluentui/react-jsx-runtime': 9.0.44(@types/react@18.3.9)(react@18.3.1) + '@fluentui/react-shared-contexts': 9.20.1(@types/react@18.3.9)(react@18.3.1) + '@fluentui/react-theme': 9.1.20 + '@fluentui/react-utilities': 9.18.15(@types/react@18.3.9)(react@18.3.1) + '@griffel/react': 1.5.25(react@18.3.1) + '@swc/helpers': 0.5.13 + '@types/react': 18.3.9 + '@types/react-dom': 18.3.0 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) dev: false - /@fluentui/react-tabster@9.17.4(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-VtRa1aWUJHKtzl9OYupohCgErioOimtSHpFNlBPQdpMvRqvLuDFMikYmvFFPxUwDpcQx3MIGc9T5++kC1uVNeQ==} + /@fluentui/react-textarea@9.3.88(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1)(scheduler@0.23.0): + resolution: {integrity: sha512-gjSgqvstE2vxUdY11Yw/zcFkXhZ5cAy/GJWppqhLV9KnBT4nTeT7ODmz44qMekJ1rNtwBx8Gk7RJe9HVhKbZTQ==} peerDependencies: '@types/react': '>=16.14.0 <19.0.0' '@types/react-dom': '>=16.9.0 <19.0.0' react: '>=16.14.0 <19.0.0' react-dom: '>=16.14.0 <19.0.0' dependencies: - '@fluentui/react-shared-contexts': 9.14.0(@types/react@18.0.0)(react@18.2.0) - '@fluentui/react-theme': 9.1.16 - '@fluentui/react-utilities': 9.17.0(@types/react@18.0.0)(react@18.2.0) - '@griffel/react': 1.5.20(react@18.2.0) - '@swc/helpers': 0.5.3 - '@types/react': 18.0.0 - '@types/react-dom': 18.0.0 - keyborg: 2.4.1 - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) - tabster: 5.3.0 + '@fluentui/react-field': 9.1.76(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1)(scheduler@0.23.0) + '@fluentui/react-jsx-runtime': 9.0.44(@types/react@18.3.9)(react@18.3.1) + '@fluentui/react-shared-contexts': 9.20.1(@types/react@18.3.9)(react@18.3.1) + '@fluentui/react-theme': 9.1.20 + '@fluentui/react-utilities': 9.18.15(@types/react@18.3.9)(react@18.3.1) + '@griffel/react': 1.5.25(react@18.3.1) + '@swc/helpers': 0.5.13 + '@types/react': 18.3.9 + '@types/react-dom': 18.3.0 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + transitivePeerDependencies: + - scheduler + dev: false + + /@fluentui/react-theme@9.1.20: + resolution: {integrity: sha512-Rh3N2ewCBlY9q+bucEKfii7sovp03HgZvN4Xwg8gbnVWA9zgX0QyTTPR+ynV+kMuwP1OiGmGHOiO+daz1k1dbg==} + dependencies: + '@fluentui/tokens': 1.0.0-alpha.17 + '@swc/helpers': 0.5.13 dev: false - /@fluentui/react-text@9.4.8(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-81Z8Zvr8hW+X13gzh7m0AjKpg7La3ktIMLNyal24HO6e5kdSabptE78oXR/zlcp09EJie5/OuuBmXrjwxqvPFA==} + /@fluentui/react-toast@9.3.56(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1): + resolution: {integrity: sha512-L3zHGTh32D5tACTCKnXAx4cdXWnY9zBFOVUl/Qpm1PdP4i/4mn4khNRmHDbN9U30a2VyxGWKiU/zQ70NuoMd+w==} peerDependencies: '@types/react': '>=16.14.0 <19.0.0' '@types/react-dom': '>=16.9.0 <19.0.0' react: '>=16.14.0 <19.0.0' react-dom: '>=16.14.0 <19.0.0' dependencies: - '@fluentui/react-jsx-runtime': 9.0.28(@types/react@18.0.0)(react@18.2.0) - '@fluentui/react-shared-contexts': 9.14.0(@types/react@18.0.0)(react@18.2.0) - '@fluentui/react-theme': 9.1.16 - '@fluentui/react-utilities': 9.17.0(@types/react@18.0.0)(react@18.2.0) - '@griffel/react': 1.5.20(react@18.2.0) - '@swc/helpers': 0.5.3 - '@types/react': 18.0.0 - '@types/react-dom': 18.0.0 - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) + '@fluentui/keyboard-keys': 9.0.7 + '@fluentui/react-aria': 9.13.6(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1) + '@fluentui/react-icons': 2.0.258(react@18.3.1) + '@fluentui/react-jsx-runtime': 9.0.44(@types/react@18.3.9)(react@18.3.1) + '@fluentui/react-motion': 9.5.2(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1) + '@fluentui/react-portal': 9.4.35(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1) + '@fluentui/react-shared-contexts': 9.20.1(@types/react@18.3.9)(react@18.3.1) + '@fluentui/react-tabster': 9.22.7(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1) + '@fluentui/react-theme': 9.1.20 + '@fluentui/react-utilities': 9.18.15(@types/react@18.3.9)(react@18.3.1) + '@griffel/react': 1.5.25(react@18.3.1) + '@swc/helpers': 0.5.13 + '@types/react': 18.3.9 + '@types/react-dom': 18.3.0 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) dev: false - /@fluentui/react-textarea@9.3.61(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0)(scheduler@0.20.2): - resolution: {integrity: sha512-5TVxGnHheB5GtEzSBQQuw88hUrVOHaUuqX0Ww7WPllQ8cfudsMPZLIjcAwqXjS0FLgBIFShDR0vr1semau7/2A==} + /@fluentui/react-toolbar@9.2.6(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1)(scheduler@0.23.0): + resolution: {integrity: sha512-G+rFX0vuufM+GZVIdcFn15kdVYw2+j32rj3jHHwAbT1wx8W6OVSR0opVGcJTwYAuKXq39J/1sHEcwbX4vAG0TQ==} peerDependencies: '@types/react': '>=16.14.0 <19.0.0' '@types/react-dom': '>=16.9.0 <19.0.0' react: '>=16.14.0 <19.0.0' react-dom: '>=16.14.0 <19.0.0' dependencies: - '@fluentui/react-field': 9.1.51(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0)(scheduler@0.20.2) - '@fluentui/react-jsx-runtime': 9.0.28(@types/react@18.0.0)(react@18.2.0) - '@fluentui/react-shared-contexts': 9.14.0(@types/react@18.0.0)(react@18.2.0) - '@fluentui/react-theme': 9.1.16 - '@fluentui/react-utilities': 9.17.0(@types/react@18.0.0)(react@18.2.0) - '@griffel/react': 1.5.20(react@18.2.0) - '@swc/helpers': 0.5.3 - '@types/react': 18.0.0 - '@types/react-dom': 18.0.0 - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) + '@fluentui/react-button': 9.3.92(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1) + '@fluentui/react-context-selector': 9.1.67(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1)(scheduler@0.23.0) + '@fluentui/react-divider': 9.2.75(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1) + '@fluentui/react-jsx-runtime': 9.0.44(@types/react@18.3.9)(react@18.3.1) + '@fluentui/react-radio': 9.2.32(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1)(scheduler@0.23.0) + '@fluentui/react-shared-contexts': 9.20.1(@types/react@18.3.9)(react@18.3.1) + '@fluentui/react-tabster': 9.22.7(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1) + '@fluentui/react-theme': 9.1.20 + '@fluentui/react-utilities': 9.18.15(@types/react@18.3.9)(react@18.3.1) + '@griffel/react': 1.5.25(react@18.3.1) + '@swc/helpers': 0.5.13 + '@types/react': 18.3.9 + '@types/react-dom': 18.3.0 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) transitivePeerDependencies: - scheduler dev: false - /@fluentui/react-theme@9.1.16: - resolution: {integrity: sha512-QK2dGE5aQXN1UGdiEmGKpYGP3tHXIchLvFf8DEEOWnF4XBc9SiEPNFYkvLMJjHxZmDz4D670rsOPe0r5jFDEKQ==} - dependencies: - '@fluentui/tokens': 1.0.0-alpha.13 - '@swc/helpers': 0.5.3 - dev: false - - /@fluentui/react-toolbar@9.1.67(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0)(scheduler@0.20.2): - resolution: {integrity: sha512-5dozwUEmzdIdWOFljV6rMuqwvWaWca9/NNJ8/em6rIqt+fuK60eZ6LLMJr/6nVqDZfDuFscDsyfj2fcuYioNoQ==} + /@fluentui/react-tooltip@9.4.39(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1): + resolution: {integrity: sha512-j424ZG4stTg3UbWUb1lYIteBCO37TB4pYNnX8ARLeaAE7kdQTD/t5GEDD2fyVhYYi097xJhUA4jMhsPig06Jow==} peerDependencies: '@types/react': '>=16.14.0 <19.0.0' '@types/react-dom': '>=16.9.0 <19.0.0' react: '>=16.14.0 <19.0.0' react-dom: '>=16.14.0 <19.0.0' dependencies: - '@fluentui/react-button': 9.3.66(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0) - '@fluentui/react-context-selector': 9.1.50(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0)(scheduler@0.20.2) - '@fluentui/react-divider': 9.2.59(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0) - '@fluentui/react-jsx-runtime': 9.0.28(@types/react@18.0.0)(react@18.2.0) - '@fluentui/react-radio': 9.2.4(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0)(scheduler@0.20.2) - '@fluentui/react-shared-contexts': 9.14.0(@types/react@18.0.0)(react@18.2.0) - '@fluentui/react-tabster': 9.17.4(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0) - '@fluentui/react-theme': 9.1.16 - '@fluentui/react-utilities': 9.17.0(@types/react@18.0.0)(react@18.2.0) - '@griffel/react': 1.5.20(react@18.2.0) - '@swc/helpers': 0.5.3 - '@types/react': 18.0.0 - '@types/react-dom': 18.0.0 - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) - transitivePeerDependencies: - - scheduler + '@fluentui/keyboard-keys': 9.0.7 + '@fluentui/react-jsx-runtime': 9.0.44(@types/react@18.3.9)(react@18.3.1) + '@fluentui/react-portal': 9.4.35(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1) + '@fluentui/react-positioning': 9.15.9(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1) + '@fluentui/react-shared-contexts': 9.20.1(@types/react@18.3.9)(react@18.3.1) + '@fluentui/react-tabster': 9.22.7(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1) + '@fluentui/react-theme': 9.1.20 + '@fluentui/react-utilities': 9.18.15(@types/react@18.3.9)(react@18.3.1) + '@griffel/react': 1.5.25(react@18.3.1) + '@swc/helpers': 0.5.13 + '@types/react': 18.3.9 + '@types/react-dom': 18.3.0 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) dev: false - /@fluentui/react-tooltip@9.4.12(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-9BScDBhQV2a3DW8RBALglAoGmV4KV2ajotCAZozK6amXpxzcY4x5ht9Lakd8nAcR2ADpqNhw3Zrx+2+jMYzdAw==} + /@fluentui/react-tree@9.8.2(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1)(scheduler@0.23.0): + resolution: {integrity: sha512-b4Zfq+pMQIgHGoQA6V6AnehnmOKoV8KMxNpUOn/73N16NphbhrI8KnsVph1Wst/pLT/7p6ANdKt9nnE9SMai/A==} peerDependencies: '@types/react': '>=16.14.0 <19.0.0' '@types/react-dom': '>=16.9.0 <19.0.0' @@ -1674,185 +3069,216 @@ packages: react-dom: '>=16.14.0 <19.0.0' dependencies: '@fluentui/keyboard-keys': 9.0.7 - '@fluentui/react-jsx-runtime': 9.0.28(@types/react@18.0.0)(react@18.2.0) - '@fluentui/react-portal': 9.4.11(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0) - '@fluentui/react-positioning': 9.12.5(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0) - '@fluentui/react-shared-contexts': 9.14.0(@types/react@18.0.0)(react@18.2.0) - '@fluentui/react-tabster': 9.17.4(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0) - '@fluentui/react-theme': 9.1.16 - '@fluentui/react-utilities': 9.17.0(@types/react@18.0.0)(react@18.2.0) - '@griffel/react': 1.5.20(react@18.2.0) - '@swc/helpers': 0.5.3 - '@types/react': 18.0.0 - '@types/react-dom': 18.0.0 - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) + '@fluentui/react-aria': 9.13.6(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1) + '@fluentui/react-avatar': 9.6.39(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1)(scheduler@0.23.0) + '@fluentui/react-button': 9.3.92(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1) + '@fluentui/react-checkbox': 9.2.37(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1)(scheduler@0.23.0) + '@fluentui/react-context-selector': 9.1.67(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1)(scheduler@0.23.0) + '@fluentui/react-icons': 2.0.258(react@18.3.1) + '@fluentui/react-jsx-runtime': 9.0.44(@types/react@18.3.9)(react@18.3.1) + '@fluentui/react-motion': 9.5.2(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1) + '@fluentui/react-motion-components-preview': 0.1.4(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1) + '@fluentui/react-radio': 9.2.32(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1)(scheduler@0.23.0) + '@fluentui/react-shared-contexts': 9.20.1(@types/react@18.3.9)(react@18.3.1) + '@fluentui/react-tabster': 9.22.7(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1) + '@fluentui/react-theme': 9.1.20 + '@fluentui/react-utilities': 9.18.15(@types/react@18.3.9)(react@18.3.1) + '@griffel/react': 1.5.25(react@18.3.1) + '@swc/helpers': 0.5.13 + '@types/react': 18.3.9 + '@types/react-dom': 18.3.0 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + transitivePeerDependencies: + - scheduler dev: false - /@fluentui/react-utilities@9.17.0(@types/react@18.0.0)(react@18.2.0): - resolution: {integrity: sha512-ZP6+Hcsvi6XXSU8m67lC0AVg5aXTSbKRGmZEXh0LbJNkc8QxO7VuoVvlP3VozUvM6FuT42pqRYpOmBQLedBmeg==} + /@fluentui/react-utilities@9.18.15(@types/react@18.3.9)(react@18.3.1): + resolution: {integrity: sha512-eJX6nyfHFRR6cZ3bi9c7s8rxIo6wCQE+phFzLqBke+RUV+p3Hwf6zW1IBVWauoaQKwPAW5RdWRYZrahqwo4DOA==} peerDependencies: '@types/react': '>=16.14.0 <19.0.0' react: '>=16.14.0 <19.0.0' dependencies: '@fluentui/keyboard-keys': 9.0.7 - '@fluentui/react-shared-contexts': 9.14.0(@types/react@18.0.0)(react@18.2.0) - '@swc/helpers': 0.5.3 - '@types/react': 18.0.0 - react: 18.2.0 + '@fluentui/react-shared-contexts': 9.20.1(@types/react@18.3.9)(react@18.3.1) + '@swc/helpers': 0.5.13 + '@types/react': 18.3.9 + react: 18.3.1 dev: false - /@fluentui/react-virtualizer@9.0.0-alpha.4(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-RMIJ+MKVfNyBmrv5m0/vhOSr3vpVfriMt97V7WOuDwMab9R7vh4rpgie/2Pfx4yptxQqxt96XyNTRc7acYx49w==} - peerDependencies: - '@types/react': '>=16.8.0 <18.0.0' - '@types/react-dom': '>=16.8.0 <18.0.0' - react: '>=16.8.0 <18.0.0' - react-dom: '>=16.8.0 <18.0.0' - dependencies: - '@fluentui/react-utilities': 9.17.0(@types/react@18.0.0)(react@18.2.0) - '@griffel/react': 1.5.20(react@18.2.0) - '@types/react': 18.0.0 - '@types/react-dom': 18.0.0 - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) - tslib: 2.6.1 + /@fluentui/react-virtualizer@9.0.0-alpha.85(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1): + resolution: {integrity: sha512-zdwqj3sLH1TeMwgXNFOVsWtWrH/zD4vmq1s/WkbB4Wu5h/CeemQEN3//WVpz0AB3cZGvcPiTitKH12AfaCqXIQ==} + peerDependencies: + '@types/react': '>=16.14.0 <19.0.0' + '@types/react-dom': '>=16.9.0 <19.0.0' + react: '>=16.14.0 <19.0.0' + react-dom: '>=16.14.0 <19.0.0' + dependencies: + '@fluentui/react-jsx-runtime': 9.0.44(@types/react@18.3.9)(react@18.3.1) + '@fluentui/react-shared-contexts': 9.20.1(@types/react@18.3.9)(react@18.3.1) + '@fluentui/react-utilities': 9.18.15(@types/react@18.3.9)(react@18.3.1) + '@griffel/react': 1.5.25(react@18.3.1) + '@swc/helpers': 0.5.13 + '@types/react': 18.3.9 + '@types/react-dom': 18.3.0 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) dev: false - /@fluentui/react-window-provider@2.2.18(@types/react@18.0.0)(react@18.2.0): - resolution: {integrity: sha512-nBKqxd0P8NmIR0qzFvka1urE2LVbUm6cse1I1T7TcOVNYa5jDf5BrO06+JRZfwbn00IJqOnIVoP0qONqceypWQ==} + /@fluentui/react-window-provider@2.2.28(@types/react@18.3.9)(react@18.3.1): + resolution: {integrity: sha512-YdZ74HTaoDwlvLDzoBST80/17ExIl93tLJpTxnqK5jlJOAUVQ+mxLPF2HQEJq+SZr5IMXHsQ56w/KaZVRn72YA==} peerDependencies: '@types/react': '>=16.8.0 <19.0.0' react: '>=16.8.0 <19.0.0' dependencies: - '@fluentui/set-version': 8.2.14 - '@types/react': 18.0.0 - react: 18.2.0 - tslib: 2.6.1 + '@fluentui/set-version': 8.2.23 + '@types/react': 18.3.9 + react: 18.3.1 + tslib: 2.7.0 dev: false - /@fluentui/react@8.106.1(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-cLagkBBsknKOYFXBeWBwAm5VryPeJFVUIgLa0XlXcxmeOco/IhmWlhY5gEEQ9YoX1dFyNVcYXWxNFR55KUpZoA==} + /@fluentui/react@8.120.9(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1): + resolution: {integrity: sha512-loZJYZ/qAjoz7la4uClrwJV50pYe+reopYjdgEZX3cjYMPzdIdDsAuRY+HJ9SqOOW97k6PTyBtYvpVpfy7OdEw==} peerDependencies: '@types/react': '>=16.8.0 <19.0.0' '@types/react-dom': '>=16.8.0 <19.0.0' react: '>=16.8.0 <19.0.0' react-dom: '>=16.8.0 <19.0.0' dependencies: - '@fluentui/date-time-utilities': 8.5.16 - '@fluentui/font-icons-mdl2': 8.5.31(@types/react@18.0.0)(react@18.2.0) - '@fluentui/foundation-legacy': 8.2.51(@types/react@18.0.0)(react@18.2.0) - '@fluentui/merge-styles': 8.5.15 - '@fluentui/react-focus': 8.8.39(@types/react@18.0.0)(react@18.2.0) - '@fluentui/react-hooks': 8.6.36(@types/react@18.0.0)(react@18.2.0) - '@fluentui/react-portal-compat-context': 9.0.11(@types/react@18.0.0)(react@18.2.0) - '@fluentui/react-window-provider': 2.2.18(@types/react@18.0.0)(react@18.2.0) - '@fluentui/set-version': 8.2.14 - '@fluentui/style-utilities': 8.10.2(@types/react@18.0.0)(react@18.2.0) - '@fluentui/theme': 2.6.41(@types/react@18.0.0)(react@18.2.0) - '@fluentui/utilities': 8.13.24(@types/react@18.0.0)(react@18.2.0) + '@fluentui/date-time-utilities': 8.6.9 + '@fluentui/font-icons-mdl2': 8.5.50(@types/react@18.3.9)(react@18.3.1) + '@fluentui/foundation-legacy': 8.4.16(@types/react@18.3.9)(react@18.3.1) + '@fluentui/merge-styles': 8.6.13 + '@fluentui/react-focus': 8.9.13(@types/react@18.3.9)(react@18.3.1) + '@fluentui/react-hooks': 8.8.12(@types/react@18.3.9)(react@18.3.1) + '@fluentui/react-portal-compat-context': 9.0.12(@types/react@18.3.9)(react@18.3.1) + '@fluentui/react-window-provider': 2.2.28(@types/react@18.3.9)(react@18.3.1) + '@fluentui/set-version': 8.2.23 + '@fluentui/style-utilities': 8.10.21(@types/react@18.3.9)(react@18.3.1) + '@fluentui/theme': 2.6.59(@types/react@18.3.9)(react@18.3.1) + '@fluentui/utilities': 8.15.15(@types/react@18.3.9)(react@18.3.1) '@microsoft/load-themed-styles': 1.10.295 - '@types/react': 18.0.0 - '@types/react-dom': 18.0.0 - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) - tslib: 2.6.1 + '@types/react': 18.3.9 + '@types/react-dom': 18.3.0 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + tslib: 2.7.0 dev: false - /@fluentui/set-version@8.2.14: - resolution: {integrity: sha512-f/QWJnSeyfAjGAqq57yjMb6a5ejPlwfzdExPmzFBuEOuupi8hHbV8Yno12XJcTW4I0KXEQGw+PUaM1aOf/j7jw==} + /@fluentui/set-version@8.2.23: + resolution: {integrity: sha512-VPXaBsiaa3Xn/AY40nLU9bvDQ62lpMVnFzFTlQ8CbpdwrjxNlRxDUY5vRToNzp1+Zu5gD/+CgsXqIZGcry5L5w==} dependencies: - tslib: 2.6.1 + tslib: 2.7.0 dev: false - /@fluentui/style-utilities@8.10.2(@types/react@18.0.0)(react@18.2.0): - resolution: {integrity: sha512-ocELtMb/85nBa3rSfiAIwYx6TydN+3rQqv1P0H/L7etYNNtxOfS86JSWfn8zAsHMejbwUKJ1ZsIKs47c598XGQ==} + /@fluentui/style-utilities@8.10.21(@types/react@18.3.9)(react@18.3.1): + resolution: {integrity: sha512-tqdSQI1MAnNUPtNKKV9LeNqmEhBZL+lpV+m6Ngl6SDuR0aQkMkuo1jA9rPxNRLUf5+pbI8LrNQ4WiCWqYkV/QQ==} dependencies: - '@fluentui/merge-styles': 8.5.15 - '@fluentui/set-version': 8.2.14 - '@fluentui/theme': 2.6.41(@types/react@18.0.0)(react@18.2.0) - '@fluentui/utilities': 8.13.24(@types/react@18.0.0)(react@18.2.0) + '@fluentui/merge-styles': 8.6.13 + '@fluentui/set-version': 8.2.23 + '@fluentui/theme': 2.6.59(@types/react@18.3.9)(react@18.3.1) + '@fluentui/utilities': 8.15.15(@types/react@18.3.9)(react@18.3.1) '@microsoft/load-themed-styles': 1.10.295 - tslib: 2.6.1 + tslib: 2.7.0 transitivePeerDependencies: - '@types/react' - react dev: false - /@fluentui/theme@2.6.41(@types/react@18.0.0)(react@18.2.0): - resolution: {integrity: sha512-h9RguEzqzJ0+59ys5Kkp7JtsjhDUxBLmQunu5rpHp5Mp788OtEjI/n1a9FIcOAL/priPSQwXN7RbuDpeP7+aSw==} + /@fluentui/theme@2.6.59(@types/react@18.3.9)(react@18.3.1): + resolution: {integrity: sha512-o/6UgKgPW6QI/+2OfCXeJfcOCbtzLIwM/3W/DzI2Pjt56ubT98IEcb32NCHoIKB2xkEnJoTjGgN1m+vHAvcQxA==} peerDependencies: '@types/react': '>=16.8.0 <19.0.0' react: '>=16.8.0 <19.0.0' dependencies: - '@fluentui/merge-styles': 8.5.15 - '@fluentui/set-version': 8.2.14 - '@fluentui/utilities': 8.13.24(@types/react@18.0.0)(react@18.2.0) - '@types/react': 18.0.0 - react: 18.2.0 - tslib: 2.6.1 + '@fluentui/merge-styles': 8.6.13 + '@fluentui/set-version': 8.2.23 + '@fluentui/utilities': 8.15.15(@types/react@18.3.9)(react@18.3.1) + '@types/react': 18.3.9 + react: 18.3.1 + tslib: 2.7.0 dev: false - /@fluentui/tokens@1.0.0-alpha.13: - resolution: {integrity: sha512-IzYysTTBkAH7tQZxYKpzhxYnTJkvwXhjhTOpmERgnqTFifHTP8/vaQjJAAm7dI/9zlDx1oN+y/I+KzL9bDLHZQ==} + /@fluentui/tokens@1.0.0-alpha.17: + resolution: {integrity: sha512-tD+sHoY9u31SrgnWOl1XwWawCUQEgLWZkR+WiQbekoj2s2RCe8aO6Bl33qkh+pcskThukBpcFU5lHwqqTgUKJA==} dependencies: - '@swc/helpers': 0.5.3 + '@swc/helpers': 0.5.13 dev: false - /@fluentui/utilities@8.13.24(@types/react@18.0.0)(react@18.2.0): - resolution: {integrity: sha512-/jo6hWCzTGCx06l2baAMwsjjBZ/dyMouls53uNaQLUGUUhUwXh/DcDDXMqLRJB3MaH9zvgfvRw61iKmm2s9fIA==} + /@fluentui/utilities@8.15.15(@types/react@18.3.9)(react@18.3.1): + resolution: {integrity: sha512-7GpET/AuWR8aBEQSQj9iO2j+9riAaoK1qBduCB4Ht6353d25vwwsKXreHZGqS8efv+NNIxQTlLWz0Rq73iQFWw==} peerDependencies: '@types/react': '>=16.8.0 <19.0.0' react: '>=16.8.0 <19.0.0' dependencies: - '@fluentui/dom-utilities': 2.2.14 - '@fluentui/merge-styles': 8.5.15 - '@fluentui/set-version': 8.2.14 - '@types/react': 18.0.0 - react: 18.2.0 - tslib: 2.6.1 + '@fluentui/dom-utilities': 2.3.7 + '@fluentui/merge-styles': 8.6.13 + '@fluentui/react-window-provider': 2.2.28(@types/react@18.3.9)(react@18.3.1) + '@fluentui/set-version': 8.2.23 + '@types/react': 18.3.9 + react: 18.3.1 + tslib: 2.7.0 dev: false - /@griffel/core@1.15.2: - resolution: {integrity: sha512-RlsIXoSS3gaYykUgxFpwKAs/DV9cRUKp3CW1kt3iPAtsDTWn/o+8bT1jvBws/tMM2GBu/Uc0EkaIzUPqD7uA+Q==} + /@griffel/core@1.18.0: + resolution: {integrity: sha512-3Dkn6f7ULeSzJ1wLyLfN1vc+v3q5shuEejeMe4XymBozQo0l35WIfH8FWcwB+Xrgip4fLLOy1p3sYN85gFGZxw==} dependencies: - '@emotion/hash': 0.9.1 - '@griffel/style-types': 1.0.3 + '@emotion/hash': 0.9.2 + '@griffel/style-types': 1.2.0 csstype: 3.1.3 rtl-css-js: 1.16.1 - stylis: 4.3.1 - tslib: 2.6.1 + stylis: 4.3.4 + tslib: 2.7.0 dev: false - /@griffel/react@1.5.20(react@18.2.0): - resolution: {integrity: sha512-1P2yaPctENFSCwyPIYXBmgpNH68c0lc/jwSzPij1QATHDK1AASKuSeq6hW108I67RKjhRyHCcALshdZ3GcQXSg==} + /@griffel/react@1.5.25(react@18.3.1): + resolution: {integrity: sha512-ZGiCdn71VIX56fd3AxM7ouCxgClPvunOFIpXxFKebGJ94/rdj4sIbahuI1QBUFuU4/bqUyD6QonjDEpFBl9ORw==} peerDependencies: react: '>=16.8.0 <19.0.0' dependencies: - '@griffel/core': 1.15.2 - react: 18.2.0 - tslib: 2.6.1 + '@griffel/core': 1.18.0 + react: 18.3.1 + tslib: 2.7.0 dev: false - /@griffel/style-types@1.0.3: - resolution: {integrity: sha512-AzbbYV/EobNIBtfMtyu2edFin895gjVxtu1nsRhTETUAIb0/LCZoue3Jd/kFLuPwe95rv5WRUBiQpVwJsrrFcw==} + /@griffel/style-types@1.2.0: + resolution: {integrity: sha512-x166MNw0vWe5l5qhinfNT4eyWOaP48iFzPyFOfIB0/BVidKTWsEe5PmqRJDDtrJFS3VHhd/tE0oM6tkEMh2tsg==} dependencies: csstype: 3.1.3 dev: false - /@humanwhocodes/config-array@0.9.5: - resolution: {integrity: sha512-ObyMyWxZiCu/yTisA7uzx81s40xR2fD5Cg/2Kq7G02ajkNubJf6BopgDTmDyc3U7sXpNKM8cYOw7s7Tyr+DnCw==} + /@humanwhocodes/config-array@0.13.0: + resolution: {integrity: sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==} engines: {node: '>=10.10.0'} + deprecated: Use @eslint/config-array instead dependencies: - '@humanwhocodes/object-schema': 1.2.1 - debug: 4.3.4 + '@humanwhocodes/object-schema': 2.0.3 + debug: 4.3.7 minimatch: 3.1.2 transitivePeerDependencies: - supports-color dev: true - /@humanwhocodes/object-schema@1.2.1: - resolution: {integrity: sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==} + /@humanwhocodes/module-importer@1.0.1: + resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} + engines: {node: '>=12.22'} + dev: true + + /@humanwhocodes/object-schema@2.0.3: + resolution: {integrity: sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==} + deprecated: Use @eslint/object-schema instead + dev: true + + /@isaacs/cliui@8.0.2: + resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} + engines: {node: '>=12'} + dependencies: + string-width: 5.1.2 + string-width-cjs: /string-width@4.2.3 + strip-ansi: 7.1.0 + strip-ansi-cjs: /strip-ansi@6.0.1 + wrap-ansi: 8.1.0 + wrap-ansi-cjs: /wrap-ansi@7.0.0 dev: true /@istanbuljs/load-nyc-config@1.1.0: @@ -1866,14 +3292,14 @@ packages: resolve-from: 5.0.0 dev: true - /@istanbuljs/nyc-config-typescript@1.0.2(nyc@15.1.0): + /@istanbuljs/nyc-config-typescript@1.0.2(nyc@17.1.0): resolution: {integrity: sha512-iKGIyMoyJuFnJRSVTZ78POIRvNnwZaWIf8vG4ZS3rQq58MMDrqEX2nnzx0R28V2X8JvmKYiqY9FP2hlJsm8A0w==} engines: {node: '>=8'} peerDependencies: nyc: '>=15' dependencies: '@istanbuljs/schema': 0.1.3 - nyc: 15.1.0 + nyc: 17.1.0 dev: true /@istanbuljs/schema@0.1.3: @@ -1886,7 +3312,7 @@ packages: engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: '@jest/types': 29.6.3 - '@types/node': 14.17.4 + '@types/node': 18.19.53 chalk: 4.1.2 jest-message-util: 29.7.0 jest-util: 29.7.0 @@ -1907,14 +3333,14 @@ packages: '@jest/test-result': 29.7.0 '@jest/transform': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 14.17.4 + '@types/node': 18.19.53 ansi-escapes: 4.3.2 chalk: 4.1.2 ci-info: 3.9.0 exit: 0.1.2 graceful-fs: 4.2.11 jest-changed-files: 29.7.0 - jest-config: 29.7.0(@types/node@14.17.4) + jest-config: 29.7.0(@types/node@18.19.53) jest-haste-map: 29.7.0 jest-message-util: 29.7.0 jest-regex-util: 29.6.3 @@ -1926,7 +3352,7 @@ packages: jest-util: 29.7.0 jest-validate: 29.7.0 jest-watcher: 29.7.0 - micromatch: 4.0.5 + micromatch: 4.0.8 pretty-format: 29.7.0 slash: 3.0.0 strip-ansi: 6.0.1 @@ -1942,7 +3368,7 @@ packages: dependencies: '@jest/fake-timers': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 14.17.4 + '@types/node': 18.19.53 jest-mock: 29.7.0 dev: true @@ -1969,7 +3395,7 @@ packages: dependencies: '@jest/types': 29.6.3 '@sinonjs/fake-timers': 10.3.0 - '@types/node': 14.17.4 + '@types/node': 18.19.53 jest-message-util: 29.7.0 jest-mock: 29.7.0 jest-util: 29.7.0 @@ -2001,25 +3427,25 @@ packages: '@jest/test-result': 29.7.0 '@jest/transform': 29.7.0 '@jest/types': 29.6.3 - '@jridgewell/trace-mapping': 0.3.22 - '@types/node': 14.17.4 + '@jridgewell/trace-mapping': 0.3.25 + '@types/node': 18.19.53 chalk: 4.1.2 collect-v8-coverage: 1.0.2 exit: 0.1.2 glob: 7.2.3 graceful-fs: 4.2.11 istanbul-lib-coverage: 3.2.2 - istanbul-lib-instrument: 6.0.1 + istanbul-lib-instrument: 6.0.3 istanbul-lib-report: 3.0.1 istanbul-lib-source-maps: 4.0.1 - istanbul-reports: 3.1.6 + istanbul-reports: 3.1.7 jest-message-util: 29.7.0 jest-util: 29.7.0 jest-worker: 29.7.0 slash: 3.0.0 string-length: 4.0.2 strip-ansi: 6.0.1 - v8-to-istanbul: 9.2.0 + v8-to-istanbul: 9.3.0 transitivePeerDependencies: - supports-color dev: true @@ -2035,7 +3461,7 @@ packages: resolution: {integrity: sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: - '@jridgewell/trace-mapping': 0.3.22 + '@jridgewell/trace-mapping': 0.3.25 callsites: 3.1.0 graceful-fs: 4.2.11 dev: true @@ -2064,9 +3490,9 @@ packages: resolution: {integrity: sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: - '@babel/core': 7.23.7 + '@babel/core': 7.25.2 '@jest/types': 29.6.3 - '@jridgewell/trace-mapping': 0.3.22 + '@jridgewell/trace-mapping': 0.3.25 babel-plugin-istanbul: 6.1.1 chalk: 4.1.2 convert-source-map: 2.0.0 @@ -2075,7 +3501,7 @@ packages: jest-haste-map: 29.7.0 jest-regex-util: 29.6.3 jest-util: 29.7.0 - micromatch: 4.0.5 + micromatch: 4.0.8 pirates: 4.0.6 slash: 3.0.0 write-file-atomic: 4.0.2 @@ -2090,39 +3516,39 @@ packages: '@jest/schemas': 29.6.3 '@types/istanbul-lib-coverage': 2.0.6 '@types/istanbul-reports': 3.0.4 - '@types/node': 14.17.4 - '@types/yargs': 17.0.32 + '@types/node': 18.19.53 + '@types/yargs': 17.0.33 chalk: 4.1.2 dev: true - /@jridgewell/gen-mapping@0.3.3: - resolution: {integrity: sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==} + /@jridgewell/gen-mapping@0.3.5: + resolution: {integrity: sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==} engines: {node: '>=6.0.0'} dependencies: - '@jridgewell/set-array': 1.1.2 - '@jridgewell/sourcemap-codec': 1.4.15 - '@jridgewell/trace-mapping': 0.3.22 + '@jridgewell/set-array': 1.2.1 + '@jridgewell/sourcemap-codec': 1.5.0 + '@jridgewell/trace-mapping': 0.3.25 dev: true - /@jridgewell/resolve-uri@3.1.1: - resolution: {integrity: sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==} + /@jridgewell/resolve-uri@3.1.2: + resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} engines: {node: '>=6.0.0'} dev: true - /@jridgewell/set-array@1.1.2: - resolution: {integrity: sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==} + /@jridgewell/set-array@1.2.1: + resolution: {integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==} engines: {node: '>=6.0.0'} dev: true - /@jridgewell/sourcemap-codec@1.4.15: - resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==} + /@jridgewell/sourcemap-codec@1.5.0: + resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==} dev: true - /@jridgewell/trace-mapping@0.3.22: - resolution: {integrity: sha512-Wf963MzWtA2sjrNt+g18IAln9lKnlRp+K2eH4jjIoF1wYeq3aMREpG09xhlhdzS0EjwU7qmUJYangWa+151vZw==} + /@jridgewell/trace-mapping@0.3.25: + resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==} dependencies: - '@jridgewell/resolve-uri': 3.1.1 - '@jridgewell/sourcemap-codec': 1.4.15 + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.0 dev: true /@microsoft/load-themed-styles@1.10.295: @@ -2147,14 +3573,15 @@ packages: stream-browserify: optional: true dependencies: - '@babel/runtime': 7.23.8 - tslib: 2.6.1 + '@babel/runtime': 7.25.6 + tslib: 2.7.0 dev: false - /@microsoft/teams-js@2.19.0: - resolution: {integrity: sha512-QpAK8JO6s9D5qOiW//fwS4bUgzhLr1GDxHCRw+BEs9Uuw5Z9YhwMClhtFlI5P7HlH5SFC4QSsh44HaV31ORXJA==} + /@microsoft/teams-js@2.28.0: + resolution: {integrity: sha512-WcQ2vWY+AvTOxToANe4znqDBvURDvZTztpjy5sYT24vsFimWKydOwT3OFE1/Av+gzofPrtqn+mf9bq6i9ED7Tg==} dependencies: - debug: 4.3.4 + base64-js: 1.5.1 + debug: 4.3.7 transitivePeerDependencies: - supports-color dev: false @@ -2177,7 +3604,16 @@ packages: engines: {node: '>= 8'} dependencies: '@nodelib/fs.scandir': 2.1.5 - fastq: 1.16.0 + fastq: 1.17.1 + dev: true + + /@pkgr/core@0.1.1: + resolution: {integrity: sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==} + engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} + dev: true + + /@rtsao/scc@1.1.0: + resolution: {integrity: sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==} dev: true /@sinclair/typebox@0.27.8: @@ -2196,38 +3632,47 @@ packages: '@sinonjs/commons': 3.0.1 dev: true - /@swc/helpers@0.5.3: - resolution: {integrity: sha512-FaruWX6KdudYloq1AHD/4nU+UsMTdNE8CKyrseXWEcgjDAbvkwJg2QGPAnfIJLIWsjZOSPLOAykK6fuYp4vp4A==} + /@swc/helpers@0.5.13: + resolution: {integrity: sha512-UoKGxQ3r5kYI9dALKJapMmuK+1zWM/H17Z1+iwnNmzcJRnfFuevZs375TA5rW31pu4BS4NoSy1fRsexDXfWn5w==} dependencies: - tslib: 2.6.1 + tslib: 2.7.0 dev: false - /@testing-library/dom@8.20.1: - resolution: {integrity: sha512-/DiOQ5xBxgdYRC8LNk7U+RWat0S3qRLeIw3ZIkMQ9kkVlRmwD/Eg8k8CqIpD6GW7u20JIUOfMKbxtiLutpjQ4g==} - engines: {node: '>=12'} + /@testing-library/dom@10.4.0: + resolution: {integrity: sha512-pemlzrSESWbdAloYml3bAJMEfNh1Z7EduzqPKprCH5S341frlpYnUEW0H72dLxa6IsYr+mPno20GiSm+h9dEdQ==} + engines: {node: '>=18'} dependencies: - '@babel/code-frame': 7.23.5 - '@babel/runtime': 7.23.8 + '@babel/code-frame': 7.24.7 + '@babel/runtime': 7.25.6 '@types/aria-query': 5.0.4 - aria-query: 5.1.3 + aria-query: 5.3.0 chalk: 4.1.2 dom-accessibility-api: 0.5.16 lz-string: 1.5.0 pretty-format: 27.5.1 dev: true - /@testing-library/react@13.4.0(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-sXOGON+WNTh3MLE9rve97ftaZukN3oNf2KjDy7YTx6hcTO2uuLHuCGynMDhFwGw/jYf4OJ2Qk0i4i79qMNNkyw==} - engines: {node: '>=12'} + /@testing-library/react@16.0.1(@testing-library/dom@10.4.0)(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1): + resolution: {integrity: sha512-dSmwJVtJXmku+iocRhWOUFbrERC76TX2Mnf0ATODz8brzAZrMBbzLwQixlBSanZxR6LddK3eiwpSFZgDET1URg==} + engines: {node: '>=18'} peerDependencies: + '@testing-library/dom': ^10.0.0 + '@types/react': ^18.0.0 + '@types/react-dom': ^18.0.0 react: ^18.0.0 react-dom: ^18.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true dependencies: - '@babel/runtime': 7.23.8 - '@testing-library/dom': 8.20.1 - '@types/react-dom': 18.0.0 - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) + '@babel/runtime': 7.25.6 + '@testing-library/dom': 10.4.0 + '@types/react': 18.3.9 + '@types/react-dom': 18.3.0 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) dev: true /@tootallnate/once@2.0.0: @@ -2242,49 +3687,49 @@ packages: /@types/babel__core@7.20.5: resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} dependencies: - '@babel/parser': 7.23.6 - '@babel/types': 7.23.6 + '@babel/parser': 7.25.6 + '@babel/types': 7.25.6 '@types/babel__generator': 7.6.8 '@types/babel__template': 7.4.4 - '@types/babel__traverse': 7.20.5 + '@types/babel__traverse': 7.20.6 dev: true /@types/babel__generator@7.6.8: resolution: {integrity: sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw==} dependencies: - '@babel/types': 7.23.6 + '@babel/types': 7.25.6 dev: true /@types/babel__template@7.4.4: resolution: {integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==} dependencies: - '@babel/parser': 7.23.6 - '@babel/types': 7.23.6 + '@babel/parser': 7.25.6 + '@babel/types': 7.25.6 dev: true - /@types/babel__traverse@7.20.5: - resolution: {integrity: sha512-WXCyOcRtH37HAUkpXhUduaxdm82b4GSlyTqajXviN4EfiuPgNYR109xMCKvpl6zPIpua0DGlMEDCq+g8EdoheQ==} + /@types/babel__traverse@7.20.6: + resolution: {integrity: sha512-r1bzfrm0tomOI8g1SzvCaQHo6Lcv6zu0EA+W2kHrt8dyrHQxGzBBL4kdkzIS+jBMV+EYcMAEAqXqYaLJq5rOZg==} dependencies: - '@babel/types': 7.23.6 + '@babel/types': 7.25.6 dev: true /@types/cheerio@0.22.35: resolution: {integrity: sha512-yD57BchKRvTV+JD53UZ6PD8KWY5g5rvvMLRnZR3EQBCZXiDT/HR+pKpMzFGlWNhFrXlo7VPZXtKvIEwZkAWOIA==} dependencies: - '@types/node': 14.17.4 + '@types/node': 18.19.53 dev: true - /@types/enzyme@3.10.10: - resolution: {integrity: sha512-/D4wFhiEjUDfPu+j5FVK0g/jf7rqeEIpNfAI+kyxzLpw5CKO0drnW3W5NC38alIjsWgnyQ8pbuPF5+UD+vhVyg==} + /@types/enzyme@3.10.18: + resolution: {integrity: sha512-RaO/TyyHZvXkpzinbMTZmd/S5biU4zxkvDsn22ujC29t9FMSzq8tnn8f2MxQ2P8GVhFRG5jTAL05DXKyTtpEQQ==} dependencies: '@types/cheerio': 0.22.35 - '@types/react': 18.0.0 + '@types/react': 16.14.61 dev: true /@types/graceful-fs@4.1.9: resolution: {integrity: sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==} dependencies: - '@types/node': 14.17.4 + '@types/node': 18.19.53 dev: true /@types/istanbul-lib-coverage@2.0.6: @@ -2303,8 +3748,8 @@ packages: '@types/istanbul-lib-report': 3.0.3 dev: true - /@types/jest@29.4.0: - resolution: {integrity: sha512-VaywcGQ9tPorCX/Jkkni7RWGFfI11whqzs8dvxF41P17Z+z872thvEvlIbznjPJ02kl1HMX3LmLOonsj2n7HeQ==} + /@types/jest@29.5.13: + resolution: {integrity: sha512-wd+MVEZCHt23V0/L642O5APvspWply/rGY5BcW4SUETo2UzPU3Z26qr8jC2qxpimI2jjx9h7+2cj2FwIr01bXg==} dependencies: expect: 29.7.0 pretty-format: 29.7.0 @@ -2313,43 +3758,45 @@ packages: /@types/jsdom@20.0.1: resolution: {integrity: sha512-d0r18sZPmMQr1eG35u12FZfhIXNrnsPU/g5wvRKCUf/tOGilKKwYMYGqh33BNR6ba+2gkHw1EUiHoN3mn7E5IQ==} dependencies: - '@types/node': 14.17.4 + '@types/node': 18.19.53 '@types/tough-cookie': 4.0.5 parse5: 7.1.2 dev: true - /@types/json-schema@7.0.15: - resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} - dev: true - /@types/json5@0.0.29: resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} dev: true - /@types/node@14.17.4: - resolution: {integrity: sha512-8kQ3+wKGRNN0ghtEn7EGps/B8CzuBz1nXZEIGGLP2GnwbqYn4dbTs7k+VKLTq1HvZLRCIDtN3Snx1Ege8B7L5A==} + /@types/node@18.19.53: + resolution: {integrity: sha512-GLxgUgHhDKO1Edw9Q0lvMbiO/IQXJwJlMaqxSGBXMpPy8uhkCs2iiPFaB2Q/gmobnFkckD3rqTBMVjXdwq+nKg==} + dependencies: + undici-types: 5.26.5 dev: true - /@types/prop-types@15.7.11: - resolution: {integrity: sha512-ga8y9v9uyeiLdpKddhxYQkxNDrfvuPrlFb0N1qnZZByvcElJaXthF1UhvCh9TLWJBEHeNtdnbysW7Y6Uq8CVng==} + /@types/prop-types@15.7.13: + resolution: {integrity: sha512-hCZTSvwbzWGvhqxp/RqVqwU999pBf2vp7hzIjiYOsl8wqOmUxkQ6ddw1cV3l8811+kdUFus/q4d1Y3E3SyEifA==} - /@types/react-dom@18.0.0: - resolution: {integrity: sha512-49897Y0UiCGmxZqpC8Blrf6meL8QUla6eb+BBhn69dTXlmuOlzkfr7HHY/O8J25e1lTUMs+YYxSlVDAaGHCOLg==} + /@types/react-dom@18.3.0: + resolution: {integrity: sha512-EhwApuTmMBmXuFOikhQLIBUn6uFg81SwLMOAUgodJF14SOBOCMdU04gDoYi0WOJJHD144TL32z4yDqCW3dnkQg==} dependencies: - '@types/react': 18.0.0 + '@types/react': 18.3.9 - /@types/react@18.0.0: - resolution: {integrity: sha512-7+K7zEQYu7NzOwQGLR91KwWXXDzmTFODRVizJyIALf6RfLv2GDpqpknX64pvRVILXCpXi7O/pua8NGk44dLvJw==} + /@types/react@16.14.61: + resolution: {integrity: sha512-CK3zd17pDWAEMnN5TdzwQJQlto2dK/lb0WZsI74owWgQ8PR60WRk0sCeBxLWuSuuqqDZKqeUcxod/8yECqrP/g==} dependencies: - '@types/prop-types': 15.7.11 + '@types/prop-types': 15.7.13 '@types/scheduler': 0.16.8 csstype: 3.1.3 + dev: true + + /@types/react@18.3.9: + resolution: {integrity: sha512-+BpAVyTpJkNWWSSnaLBk6ePpHLOGJKnEQNbINNovPWzvEUyAe3e+/d494QdEh71RekM/qV7lw6jzf1HGrJyAtQ==} + dependencies: + '@types/prop-types': 15.7.13 + csstype: 3.1.3 /@types/scheduler@0.16.8: resolution: {integrity: sha512-WZLiwShhwLRmeV6zH+GkbOFT6Z6VklCItrDioxUnv+u4Ll+8vKeFySoFyK/0ctcRpOmwAicELfmys1sDc/Rw+A==} - - /@types/semver@7.5.6: - resolution: {integrity: sha512-dn1l8LaMea/IjDoHNd9J52uBbInB796CDffS6VdIxvqYCPSG0V0DzHp76GpaWnlhg88uYyPbXCDIowa86ybd5A==} dev: true /@types/stack-utils@2.0.3: @@ -2364,245 +3811,140 @@ packages: resolution: {integrity: sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==} dev: true - /@types/yargs@17.0.32: - resolution: {integrity: sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==} + /@types/yargs@17.0.33: + resolution: {integrity: sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==} dependencies: '@types/yargs-parser': 21.0.3 dev: true - /@typescript-eslint/eslint-plugin@5.13.0(@typescript-eslint/parser@6.5.0)(eslint@8.15.0)(typescript@5.4.5): - resolution: {integrity: sha512-vLktb2Uec81fxm/cfz2Hd6QaWOs8qdmVAZXLdOBX6JFJDhf6oDZpMzZ4/LZ6SFM/5DgDcxIMIvy3F+O9yZBuiQ==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + /@typescript-eslint/eslint-plugin@8.7.0(@typescript-eslint/parser@8.7.0)(eslint@8.57.1)(typescript@5.4.5): + resolution: {integrity: sha512-RIHOoznhA3CCfSTFiB6kBGLQtB/sox+pJ6jeFu6FxJvqL8qRxq/FfGO/UhsGgQM9oGdXkV4xUgli+dt26biB6A==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - '@typescript-eslint/parser': ^5.0.0 - eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + '@typescript-eslint/parser': ^8.0.0 || ^8.0.0-alpha.0 + eslint: ^8.57.0 || ^9.0.0 typescript: '*' peerDependenciesMeta: typescript: optional: true dependencies: - '@typescript-eslint/parser': 6.5.0(eslint@8.15.0)(typescript@5.4.5) - '@typescript-eslint/scope-manager': 5.13.0 - '@typescript-eslint/type-utils': 5.13.0(eslint@8.15.0)(typescript@5.4.5) - '@typescript-eslint/utils': 5.13.0(eslint@8.15.0)(typescript@5.4.5) - debug: 4.3.4 - eslint: 8.15.0 - functional-red-black-tree: 1.0.1 - ignore: 5.3.0 - regexpp: 3.2.0 - semver: 7.5.4 - tsutils: 3.21.0(typescript@5.4.5) + '@eslint-community/regexpp': 4.11.1 + '@typescript-eslint/parser': 8.7.0(eslint@8.57.1)(typescript@5.4.5) + '@typescript-eslint/scope-manager': 8.7.0 + '@typescript-eslint/type-utils': 8.7.0(eslint@8.57.1)(typescript@5.4.5) + '@typescript-eslint/utils': 8.7.0(eslint@8.57.1)(typescript@5.4.5) + '@typescript-eslint/visitor-keys': 8.7.0 + eslint: 8.57.1 + graphemer: 1.4.0 + ignore: 5.3.2 + natural-compare: 1.4.0 + ts-api-utils: 1.3.0(typescript@5.4.5) typescript: 5.4.5 transitivePeerDependencies: - supports-color dev: true - /@typescript-eslint/parser@6.5.0(eslint@8.15.0)(typescript@5.4.5): - resolution: {integrity: sha512-LMAVtR5GN8nY0G0BadkG0XIe4AcNMeyEy3DyhKGAh9k4pLSMBO7rF29JvDBpZGCmp5Pgz5RLHP6eCpSYZJQDuQ==} - engines: {node: ^16.0.0 || >=18.0.0} + /@typescript-eslint/parser@8.7.0(eslint@8.57.1)(typescript@5.4.5): + resolution: {integrity: sha512-lN0btVpj2unxHlNYLI//BQ7nzbMJYBVQX5+pbNXvGYazdlgYonMn4AhhHifQ+J4fGRYA/m1DjaQjx+fDetqBOQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - eslint: ^7.0.0 || ^8.0.0 + eslint: ^8.57.0 || ^9.0.0 typescript: '*' peerDependenciesMeta: typescript: optional: true dependencies: - '@typescript-eslint/scope-manager': 6.5.0 - '@typescript-eslint/types': 6.5.0 - '@typescript-eslint/typescript-estree': 6.5.0(typescript@5.4.5) - '@typescript-eslint/visitor-keys': 6.5.0 - debug: 4.3.4 - eslint: 8.15.0 + '@typescript-eslint/scope-manager': 8.7.0 + '@typescript-eslint/types': 8.7.0 + '@typescript-eslint/typescript-estree': 8.7.0(typescript@5.4.5) + '@typescript-eslint/visitor-keys': 8.7.0 + debug: 4.3.7 + eslint: 8.57.1 typescript: 5.4.5 transitivePeerDependencies: - supports-color dev: true - /@typescript-eslint/scope-manager@5.13.0: - resolution: {integrity: sha512-T4N8UvKYDSfVYdmJq7g2IPJYCRzwtp74KyDZytkR4OL3NRupvswvmJQJ4CX5tDSurW2cvCc1Ia1qM7d0jpa7IA==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - dependencies: - '@typescript-eslint/types': 5.13.0 - '@typescript-eslint/visitor-keys': 5.13.0 - dev: true - - /@typescript-eslint/scope-manager@5.62.0: - resolution: {integrity: sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - dependencies: - '@typescript-eslint/types': 5.62.0 - '@typescript-eslint/visitor-keys': 5.62.0 - dev: true - - /@typescript-eslint/scope-manager@6.5.0: - resolution: {integrity: sha512-A8hZ7OlxURricpycp5kdPTH3XnjG85UpJS6Fn4VzeoH4T388gQJ/PGP4ole5NfKt4WDVhmLaQ/dBLNDC4Xl/Kw==} - engines: {node: ^16.0.0 || >=18.0.0} - dependencies: - '@typescript-eslint/types': 6.5.0 - '@typescript-eslint/visitor-keys': 6.5.0 - dev: true - - /@typescript-eslint/type-utils@5.13.0(eslint@8.15.0)(typescript@5.4.5): - resolution: {integrity: sha512-/nz7qFizaBM1SuqAKb7GLkcNn2buRdDgZraXlkhz+vUGiN1NZ9LzkA595tHHeduAiS2MsHqMNhE2zNzGdw43Yg==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - peerDependencies: - eslint: '*' - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true + /@typescript-eslint/scope-manager@8.7.0: + resolution: {integrity: sha512-87rC0k3ZlDOuz82zzXRtQ7Akv3GKhHs0ti4YcbAJtaomllXoSO8hi7Ix3ccEvCd824dy9aIX+j3d2UMAfCtVpg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} dependencies: - '@typescript-eslint/utils': 5.13.0(eslint@8.15.0)(typescript@5.4.5) - debug: 4.3.4 - eslint: 8.15.0 - tsutils: 3.21.0(typescript@5.4.5) - typescript: 5.4.5 - transitivePeerDependencies: - - supports-color - dev: true - - /@typescript-eslint/types@5.13.0: - resolution: {integrity: sha512-LmE/KO6DUy0nFY/OoQU0XelnmDt+V8lPQhh8MOVa7Y5k2gGRd6U9Kp3wAjhB4OHg57tUO0nOnwYQhRRyEAyOyg==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - dev: true - - /@typescript-eslint/types@5.62.0: - resolution: {integrity: sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - dev: true - - /@typescript-eslint/types@6.5.0: - resolution: {integrity: sha512-eqLLOEF5/lU8jW3Bw+8auf4lZSbbljHR2saKnYqON12G/WsJrGeeDHWuQePoEf9ro22+JkbPfWQwKEC5WwLQ3w==} - engines: {node: ^16.0.0 || >=18.0.0} + '@typescript-eslint/types': 8.7.0 + '@typescript-eslint/visitor-keys': 8.7.0 dev: true - /@typescript-eslint/typescript-estree@5.13.0(typescript@5.4.5): - resolution: {integrity: sha512-Q9cQow0DeLjnp5DuEDjLZ6JIkwGx3oYZe+BfcNuw/POhtpcxMTy18Icl6BJqTSd+3ftsrfuVb7mNHRZf7xiaNA==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + /@typescript-eslint/type-utils@8.7.0(eslint@8.57.1)(typescript@5.4.5): + resolution: {integrity: sha512-tl0N0Mj3hMSkEYhLkjREp54OSb/FI6qyCzfiiclvJvOqre6hsZTGSnHtmFLDU8TIM62G7ygEa1bI08lcuRwEnQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '*' peerDependenciesMeta: typescript: optional: true dependencies: - '@typescript-eslint/types': 5.13.0 - '@typescript-eslint/visitor-keys': 5.13.0 - debug: 4.3.4 - globby: 11.1.0 - is-glob: 4.0.3 - semver: 7.5.4 - tsutils: 3.21.0(typescript@5.4.5) + '@typescript-eslint/typescript-estree': 8.7.0(typescript@5.4.5) + '@typescript-eslint/utils': 8.7.0(eslint@8.57.1)(typescript@5.4.5) + debug: 4.3.7 + ts-api-utils: 1.3.0(typescript@5.4.5) typescript: 5.4.5 transitivePeerDependencies: + - eslint - supports-color dev: true - /@typescript-eslint/typescript-estree@5.62.0(typescript@5.4.5): - resolution: {integrity: sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - peerDependencies: - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true - dependencies: - '@typescript-eslint/types': 5.62.0 - '@typescript-eslint/visitor-keys': 5.62.0 - debug: 4.3.4 - globby: 11.1.0 - is-glob: 4.0.3 - semver: 7.5.4 - tsutils: 3.21.0(typescript@5.4.5) - typescript: 5.4.5 - transitivePeerDependencies: - - supports-color + /@typescript-eslint/types@8.7.0: + resolution: {integrity: sha512-LLt4BLHFwSfASHSF2K29SZ+ZCsbQOM+LuarPjRUuHm+Qd09hSe3GCeaQbcCr+Mik+0QFRmep/FyZBO6fJ64U3w==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} dev: true - /@typescript-eslint/typescript-estree@6.5.0(typescript@5.4.5): - resolution: {integrity: sha512-q0rGwSe9e5Kk/XzliB9h2LBc9tmXX25G0833r7kffbl5437FPWb2tbpIV9wAATebC/018pGa9fwPDuvGN+LxWQ==} - engines: {node: ^16.0.0 || >=18.0.0} + /@typescript-eslint/typescript-estree@8.7.0(typescript@5.4.5): + resolution: {integrity: sha512-MC8nmcGHsmfAKxwnluTQpNqceniT8SteVwd2voYlmiSWGOtjvGXdPl17dYu2797GVscK30Z04WRM28CrKS9WOg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '*' peerDependenciesMeta: typescript: optional: true dependencies: - '@typescript-eslint/types': 6.5.0 - '@typescript-eslint/visitor-keys': 6.5.0 - debug: 4.3.4 - globby: 11.1.0 + '@typescript-eslint/types': 8.7.0 + '@typescript-eslint/visitor-keys': 8.7.0 + debug: 4.3.7 + fast-glob: 3.3.2 is-glob: 4.0.3 - semver: 7.5.4 - ts-api-utils: 1.0.3(typescript@5.4.5) + minimatch: 9.0.5 + semver: 7.6.3 + ts-api-utils: 1.3.0(typescript@5.4.5) typescript: 5.4.5 transitivePeerDependencies: - supports-color dev: true - /@typescript-eslint/utils@5.13.0(eslint@8.15.0)(typescript@5.4.5): - resolution: {integrity: sha512-+9oHlPWYNl6AwwoEt5TQryEHwiKRVjz7Vk6kaBeD3/kwHE5YqTGHtm/JZY8Bo9ITOeKutFaXnBlMgSATMJALUQ==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + /@typescript-eslint/utils@8.7.0(eslint@8.57.1)(typescript@5.4.5): + resolution: {integrity: sha512-ZbdUdwsl2X/s3CiyAu3gOlfQzpbuG3nTWKPoIvAu1pu5r8viiJvv2NPN2AqArL35NCYtw/lrPPfM4gxrMLNLPw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + eslint: ^8.57.0 || ^9.0.0 dependencies: - '@types/json-schema': 7.0.15 - '@typescript-eslint/scope-manager': 5.13.0 - '@typescript-eslint/types': 5.13.0 - '@typescript-eslint/typescript-estree': 5.13.0(typescript@5.4.5) - eslint: 8.15.0 - eslint-scope: 5.1.1 - eslint-utils: 3.0.0(eslint@8.15.0) - transitivePeerDependencies: - - supports-color - - typescript - dev: true - - /@typescript-eslint/utils@5.62.0(eslint@8.15.0)(typescript@5.4.5): - resolution: {integrity: sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - peerDependencies: - eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 - dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@8.15.0) - '@types/json-schema': 7.0.15 - '@types/semver': 7.5.6 - '@typescript-eslint/scope-manager': 5.62.0 - '@typescript-eslint/types': 5.62.0 - '@typescript-eslint/typescript-estree': 5.62.0(typescript@5.4.5) - eslint: 8.15.0 - eslint-scope: 5.1.1 - semver: 7.5.4 + '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.1) + '@typescript-eslint/scope-manager': 8.7.0 + '@typescript-eslint/types': 8.7.0 + '@typescript-eslint/typescript-estree': 8.7.0(typescript@5.4.5) + eslint: 8.57.1 transitivePeerDependencies: - supports-color - typescript dev: true - /@typescript-eslint/visitor-keys@5.13.0: - resolution: {integrity: sha512-HLKEAS/qA1V7d9EzcpLFykTePmOQqOFim8oCvhY3pZgQ8Hi38hYpHd9e5GN6nQBFQNecNhws5wkS9Y5XIO0s/g==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - dependencies: - '@typescript-eslint/types': 5.13.0 - eslint-visitor-keys: 3.4.3 - dev: true - - /@typescript-eslint/visitor-keys@5.62.0: - resolution: {integrity: sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - dependencies: - '@typescript-eslint/types': 5.62.0 - eslint-visitor-keys: 3.4.3 - dev: true - - /@typescript-eslint/visitor-keys@6.5.0: - resolution: {integrity: sha512-yCB/2wkbv3hPsh02ZS8dFQnij9VVQXJMN/gbQsaaY+zxALkZnxa/wagvLEFsAWMPv7d7lxQmNsIzGU1w/T/WyA==} - engines: {node: ^16.0.0 || >=18.0.0} + /@typescript-eslint/visitor-keys@8.7.0: + resolution: {integrity: sha512-b1tx0orFCCh/THWPQa2ZwWzvOeyzzp36vkJYOpVg0u8UVOIsfVrnuC9FqAw9gRKn+rG2VmWQ/zDJZzkxUnj/XQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} dependencies: - '@typescript-eslint/types': 6.5.0 + '@typescript-eslint/types': 8.7.0 eslint-visitor-keys: 3.4.3 dev: true - /@ungap/promise-all-settled@1.1.2: - resolution: {integrity: sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==} + /@ungap/structured-clone@1.2.0: + resolution: {integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==} dev: true /abab@2.0.6: @@ -2613,25 +3955,27 @@ packages: /acorn-globals@7.0.1: resolution: {integrity: sha512-umOSDSDrfHbTNPuNpC2NSnnA3LUrqpevPb4T9jRx4MagXNS0rs+gwiTcAvqCRmsD6utzsrzNt+ebm00SNWiC3Q==} dependencies: - acorn: 8.11.3 - acorn-walk: 8.3.2 + acorn: 8.12.1 + acorn-walk: 8.3.4 dev: true - /acorn-jsx@5.3.2(acorn@8.11.3): + /acorn-jsx@5.3.2(acorn@8.12.1): resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} peerDependencies: acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 dependencies: - acorn: 8.11.3 + acorn: 8.12.1 dev: true - /acorn-walk@8.3.2: - resolution: {integrity: sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A==} + /acorn-walk@8.3.4: + resolution: {integrity: sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==} engines: {node: '>=0.4.0'} + dependencies: + acorn: 8.12.1 dev: true - /acorn@8.11.3: - resolution: {integrity: sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==} + /acorn@8.12.1: + resolution: {integrity: sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==} engines: {node: '>=0.4.0'} hasBin: true dev: true @@ -2640,7 +3984,7 @@ packages: resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==} engines: {node: '>= 6.0.0'} dependencies: - debug: 4.3.4 + debug: 4.3.7 transitivePeerDependencies: - supports-color dev: true @@ -2662,11 +4006,6 @@ packages: uri-js: 4.4.1 dev: true - /ansi-colors@4.1.1: - resolution: {integrity: sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==} - engines: {node: '>=6'} - dev: true - /ansi-escapes@4.3.2: resolution: {integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==} engines: {node: '>=8'} @@ -2674,13 +4013,20 @@ packages: type-fest: 0.21.3 dev: true + /ansi-escapes@7.0.0: + resolution: {integrity: sha512-GdYO7a61mR0fOlAsvC9/rIHf7L96sBc6dEWzeOu+KAea5bZyQRPIpojrVoI4AXGJS/ycu/fBTdLrUkA4ODrvjw==} + engines: {node: '>=18'} + dependencies: + environment: 1.1.0 + dev: true + /ansi-regex@5.0.1: resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} engines: {node: '>=8'} dev: true - /ansi-regex@6.0.1: - resolution: {integrity: sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==} + /ansi-regex@6.1.0: + resolution: {integrity: sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==} engines: {node: '>=12'} dev: true @@ -2737,42 +4083,63 @@ packages: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} dev: true - /aria-query@5.1.3: - resolution: {integrity: sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ==} + /aria-query@5.3.0: + resolution: {integrity: sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==} dependencies: - deep-equal: 2.2.3 + dequal: 2.0.3 dev: true - /array-buffer-byte-length@1.0.0: - resolution: {integrity: sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==} + /array-buffer-byte-length@1.0.1: + resolution: {integrity: sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==} + engines: {node: '>= 0.4'} dependencies: - call-bind: 1.0.5 - is-array-buffer: 3.0.2 + call-bind: 1.0.7 + is-array-buffer: 3.0.4 dev: true - /array-includes@3.1.7: - resolution: {integrity: sha512-dlcsNBIiWhPkHdOEEKnehA+RNUWDc4UqFtnIXU4uuYDPtA4LDkr7qip2p0VvFAEXNDr0yWZ9PJyIRiGjRLQzwQ==} + /array-includes@3.1.8: + resolution: {integrity: sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ==} engines: {node: '>= 0.4'} dependencies: - call-bind: 1.0.5 + call-bind: 1.0.7 define-properties: 1.2.1 - es-abstract: 1.22.3 - get-intrinsic: 1.2.2 + es-abstract: 1.23.3 + es-object-atoms: 1.0.0 + get-intrinsic: 1.2.4 is-string: 1.0.7 dev: true - /array-union@2.1.0: - resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} - engines: {node: '>=8'} + /array.prototype.findlast@1.2.5: + resolution: {integrity: sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 + es-errors: 1.3.0 + es-object-atoms: 1.0.0 + es-shim-unscopables: 1.0.2 + dev: true + + /array.prototype.findlastindex@1.2.5: + resolution: {integrity: sha512-zfETvRFA8o7EiNn++N5f/kaCw221hrpGsDmcpndVupkPzEc1Wuf3VgC0qby1BbHs7f5DVYjgtEU2LLh5bqeGfQ==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 + es-errors: 1.3.0 + es-object-atoms: 1.0.0 + es-shim-unscopables: 1.0.2 dev: true /array.prototype.flat@1.3.2: resolution: {integrity: sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==} engines: {node: '>= 0.4'} dependencies: - call-bind: 1.0.5 + call-bind: 1.0.7 define-properties: 1.2.1 - es-abstract: 1.22.3 + es-abstract: 1.23.3 es-shim-unscopables: 1.0.2 dev: true @@ -2780,50 +4147,63 @@ packages: resolution: {integrity: sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==} engines: {node: '>= 0.4'} dependencies: - call-bind: 1.0.5 + call-bind: 1.0.7 define-properties: 1.2.1 - es-abstract: 1.22.3 + es-abstract: 1.23.3 es-shim-unscopables: 1.0.2 dev: true - /arraybuffer.prototype.slice@1.0.2: - resolution: {integrity: sha512-yMBKppFur/fbHu9/6USUe03bZ4knMYiwFBcyiaXB8Go0qNehwX6inYPzK9U0NeQvGxKthcmHcaR8P5MStSRBAw==} + /array.prototype.tosorted@1.1.4: + resolution: {integrity: sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==} engines: {node: '>= 0.4'} dependencies: - array-buffer-byte-length: 1.0.0 - call-bind: 1.0.5 + call-bind: 1.0.7 define-properties: 1.2.1 - es-abstract: 1.22.3 - get-intrinsic: 1.2.2 - is-array-buffer: 3.0.2 - is-shared-array-buffer: 1.0.2 + es-abstract: 1.23.3 + es-errors: 1.3.0 + es-shim-unscopables: 1.0.2 dev: true - /astral-regex@2.0.0: - resolution: {integrity: sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==} - engines: {node: '>=8'} + /arraybuffer.prototype.slice@1.0.3: + resolution: {integrity: sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A==} + engines: {node: '>= 0.4'} + dependencies: + array-buffer-byte-length: 1.0.1 + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 + es-errors: 1.3.0 + get-intrinsic: 1.2.4 + is-array-buffer: 3.0.4 + is-shared-array-buffer: 1.0.3 + dev: true + + /async@3.2.6: + resolution: {integrity: sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==} dev: true /asynckit@0.4.0: resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} dev: true - /available-typed-arrays@1.0.5: - resolution: {integrity: sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==} + /available-typed-arrays@1.0.7: + resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} engines: {node: '>= 0.4'} + dependencies: + possible-typed-array-names: 1.0.0 dev: true - /babel-jest@29.7.0(@babel/core@7.23.7): + /babel-jest@29.7.0(@babel/core@7.25.2): resolution: {integrity: sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} peerDependencies: '@babel/core': ^7.8.0 dependencies: - '@babel/core': 7.23.7 + '@babel/core': 7.25.2 '@jest/transform': 29.7.0 '@types/babel__core': 7.20.5 babel-plugin-istanbul: 6.1.1 - babel-preset-jest: 29.6.3(@babel/core@7.23.7) + babel-preset-jest: 29.6.3(@babel/core@7.25.2) chalk: 4.1.2 graceful-fs: 4.2.11 slash: 3.0.0 @@ -2835,7 +4215,7 @@ packages: resolution: {integrity: sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==} engines: {node: '>=8'} dependencies: - '@babel/helper-plugin-utils': 7.22.5 + '@babel/helper-plugin-utils': 7.24.8 '@istanbuljs/load-nyc-config': 1.1.0 '@istanbuljs/schema': 0.1.3 istanbul-lib-instrument: 5.2.1 @@ -2848,51 +4228,89 @@ packages: resolution: {integrity: sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: - '@babel/template': 7.22.15 - '@babel/types': 7.23.6 + '@babel/template': 7.25.0 + '@babel/types': 7.25.6 '@types/babel__core': 7.20.5 - '@types/babel__traverse': 7.20.5 + '@types/babel__traverse': 7.20.6 + dev: true + + /babel-plugin-polyfill-corejs2@0.4.11(@babel/core@7.25.2): + resolution: {integrity: sha512-sMEJ27L0gRHShOh5G54uAAPaiCOygY/5ratXuiyb2G46FmlSpc9eFCzYVyDiPxfNbwzA7mYahmjQc5q+CZQ09Q==} + peerDependencies: + '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 + dependencies: + '@babel/compat-data': 7.25.4 + '@babel/core': 7.25.2 + '@babel/helper-define-polyfill-provider': 0.6.2(@babel/core@7.25.2) + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + dev: true + + /babel-plugin-polyfill-corejs3@0.10.6(@babel/core@7.25.2): + resolution: {integrity: sha512-b37+KR2i/khY5sKmWNVQAnitvquQbNdWy6lJdsr0kmquCKEEUgMKK4SboVM3HtfnZilfjr4MMQ7vY58FVWDtIA==} + peerDependencies: + '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 + dependencies: + '@babel/core': 7.25.2 + '@babel/helper-define-polyfill-provider': 0.6.2(@babel/core@7.25.2) + core-js-compat: 3.38.1 + transitivePeerDependencies: + - supports-color + dev: true + + /babel-plugin-polyfill-regenerator@0.6.2(@babel/core@7.25.2): + resolution: {integrity: sha512-2R25rQZWP63nGwaAswvDazbPXfrM3HwVoBXK6HcqeKrSrL/JqcC/rDcf95l4r7LXLyxDXc8uQDa064GubtCABg==} + peerDependencies: + '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 + dependencies: + '@babel/core': 7.25.2 + '@babel/helper-define-polyfill-provider': 0.6.2(@babel/core@7.25.2) + transitivePeerDependencies: + - supports-color dev: true - /babel-preset-current-node-syntax@1.0.1(@babel/core@7.23.7): - resolution: {integrity: sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==} + /babel-preset-current-node-syntax@1.1.0(@babel/core@7.25.2): + resolution: {integrity: sha512-ldYss8SbBlWva1bs28q78Ju5Zq1F+8BrqBZZ0VFhLBvhh6lCpC2o3gDJi/5DRLs9FgYZCnmPYIVFU4lRXCkyUw==} peerDependencies: '@babel/core': ^7.0.0 dependencies: - '@babel/core': 7.23.7 - '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.23.7) - '@babel/plugin-syntax-bigint': 7.8.3(@babel/core@7.23.7) - '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.23.7) - '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.23.7) - '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.23.7) - '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.23.7) - '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.23.7) - '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.23.7) - '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.23.7) - '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.23.7) - '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.23.7) - '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.23.7) - dev: true - - /babel-preset-jest@29.6.3(@babel/core@7.23.7): + '@babel/core': 7.25.2 + '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.25.2) + '@babel/plugin-syntax-bigint': 7.8.3(@babel/core@7.25.2) + '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.25.2) + '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.25.2) + '@babel/plugin-syntax-import-attributes': 7.25.6(@babel/core@7.25.2) + '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.25.2) + '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.25.2) + '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.25.2) + '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.25.2) + '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.25.2) + '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.25.2) + '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.25.2) + '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.25.2) + '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.25.2) + '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.25.2) + dev: true + + /babel-preset-jest@29.6.3(@babel/core@7.25.2): resolution: {integrity: sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} peerDependencies: '@babel/core': ^7.0.0 dependencies: - '@babel/core': 7.23.7 + '@babel/core': 7.25.2 babel-plugin-jest-hoist: 29.6.3 - babel-preset-current-node-syntax: 1.0.1(@babel/core@7.23.7) + babel-preset-current-node-syntax: 1.1.0(@babel/core@7.25.2) dev: true /balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} dev: true - /binary-extensions@2.2.0: - resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==} - engines: {node: '>=8'} - dev: true + /base64-js@1.5.1: + resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} + dev: false /brace-expansion@1.1.11: resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} @@ -2907,26 +4325,22 @@ packages: balanced-match: 1.0.2 dev: true - /braces@3.0.2: - resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==} + /braces@3.0.3: + resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} engines: {node: '>=8'} dependencies: - fill-range: 7.0.1 + fill-range: 7.1.1 dev: true - /browser-stdout@1.3.1: - resolution: {integrity: sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==} - dev: true - - /browserslist@4.22.2: - resolution: {integrity: sha512-0UgcrvQmBDvZHFGdYUehrCNIazki7/lUP3kkoi/r3YB2amZbFM9J43ZRkJTXBUZK4gmx56+Sqk9+Vs9mwZx9+A==} + /browserslist@4.24.0: + resolution: {integrity: sha512-Rmb62sR1Zpjql25eSanFGEhAxcFwfA1K0GuQcLoaJBAcENegrQut3hYdhXFF1obQfiDyqIW/cLM5HSJ/9k884A==} engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true dependencies: - caniuse-lite: 1.0.30001579 - electron-to-chromium: 1.4.645 - node-releases: 2.0.14 - update-browserslist-db: 1.0.13(browserslist@4.22.2) + caniuse-lite: 1.0.30001664 + electron-to-chromium: 1.5.29 + node-releases: 2.0.18 + update-browserslist-db: 1.1.0(browserslist@4.24.0) dev: true /bs-logger@0.2.6: @@ -2946,12 +4360,6 @@ packages: resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} dev: true - /builtins@4.1.0: - resolution: {integrity: sha512-1bPRZQtmKaO6h7qV1YHXNtr6nCK28k0Zo95KM4dXfILcZZwoHJBN1m3lfLv9LPkcOZlrSr+J1bzMaZFO98Yq0w==} - dependencies: - semver: 7.5.4 - dev: true - /caching-transform@4.0.0: resolution: {integrity: sha512-kpqOvwXnjjN44D89K5ccQC+RUrsy7jB/XLlRrx0D7/2HNcTPqzsb6XgYoErwko6QsV184CA2YgS1fxDiiDZMWA==} engines: {node: '>=8'} @@ -2962,12 +4370,15 @@ packages: write-file-atomic: 3.0.3 dev: true - /call-bind@1.0.5: - resolution: {integrity: sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ==} + /call-bind@1.0.7: + resolution: {integrity: sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==} + engines: {node: '>= 0.4'} dependencies: + es-define-property: 1.0.0 + es-errors: 1.3.0 function-bind: 1.1.2 - get-intrinsic: 1.2.2 - set-function-length: 1.2.0 + get-intrinsic: 1.2.4 + set-function-length: 1.2.2 dev: true /callsites@3.1.0: @@ -2985,8 +4396,8 @@ packages: engines: {node: '>=10'} dev: true - /caniuse-lite@1.0.30001579: - resolution: {integrity: sha512-u5AUVkixruKHJjw/pj9wISlcMpgFWzSrczLZbrqBSxukQixmg0SJ5sZTpvaFvxU0HoQKd4yoyAogyrAz9pzJnA==} + /caniuse-lite@1.0.30001664: + resolution: {integrity: sha512-AmE7k4dXiNKQipgn7a2xg558IRqPN3jMQY/rOsbxDhrd0tyChwbITBfiwtnqz8bi2M5mIWbxAYBvk7W7QBUS2g==} dev: true /chalk@2.4.2: @@ -3006,33 +4417,23 @@ packages: supports-color: 7.2.0 dev: true + /chalk@5.3.0: + resolution: {integrity: sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==} + engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} + dev: true + /char-regex@1.0.2: resolution: {integrity: sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==} engines: {node: '>=10'} dev: true - /chokidar@3.5.3: - resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==} - engines: {node: '>= 8.10.0'} - dependencies: - anymatch: 3.1.3 - braces: 3.0.2 - glob-parent: 5.1.2 - is-binary-path: 2.1.0 - is-glob: 4.0.3 - normalize-path: 3.0.0 - readdirp: 3.6.0 - optionalDependencies: - fsevents: 2.3.3 - dev: true - /ci-info@3.9.0: resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==} engines: {node: '>=8'} dev: true - /cjs-module-lexer@1.2.3: - resolution: {integrity: sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ==} + /cjs-module-lexer@1.4.1: + resolution: {integrity: sha512-cuSVIHi9/9E/+821Qjdvngor+xpnlwnuwIyZOaLmHBVdXL+gP+I6QQB9VkO7RI77YIcTV+S1W9AreJ5eN63JBA==} dev: true /clean-stack@2.2.0: @@ -3040,27 +4441,19 @@ packages: engines: {node: '>=6'} dev: true - /cli-cursor@3.1.0: - resolution: {integrity: sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==} - engines: {node: '>=8'} - dependencies: - restore-cursor: 3.1.0 - dev: true - - /cli-truncate@2.1.0: - resolution: {integrity: sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==} - engines: {node: '>=8'} + /cli-cursor@5.0.0: + resolution: {integrity: sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==} + engines: {node: '>=18'} dependencies: - slice-ansi: 3.0.0 - string-width: 4.2.3 + restore-cursor: 5.1.0 dev: true - /cli-truncate@3.1.0: - resolution: {integrity: sha512-wfOBkjXteqSnI59oPcJkcPl/ZmwvMMOj340qUIY1SKZCv0B9Cf4D4fAucRkIKQmsIuYK3x1rrgU7MeGRruiuiA==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + /cli-truncate@4.0.0: + resolution: {integrity: sha512-nPdaFdQ0h/GEigbPClz11D0v/ZJEwxmeVZGeMo3Z5StPtUTkA9o1lD6QwoirYiSDzbcwn2XcjwmCp68W1IS4TA==} + engines: {node: '>=18'} dependencies: slice-ansi: 5.0.0 - string-width: 5.1.2 + string-width: 7.2.0 dev: true /cliui@6.0.0: @@ -3071,14 +4464,6 @@ packages: wrap-ansi: 6.2.0 dev: true - /cliui@7.0.4: - resolution: {integrity: sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==} - dependencies: - string-width: 4.2.3 - strip-ansi: 6.0.1 - wrap-ansi: 7.0.0 - dev: true - /cliui@8.0.1: resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} engines: {node: '>=12'} @@ -3129,9 +4514,9 @@ packages: delayed-stream: 1.0.0 dev: true - /commander@8.3.0: - resolution: {integrity: sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==} - engines: {node: '>= 12'} + /commander@12.1.0: + resolution: {integrity: sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==} + engines: {node: '>=18'} dev: true /commondir@1.0.1: @@ -3150,7 +4535,13 @@ packages: resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} dev: true - /create-jest@29.7.0(@types/node@14.17.4): + /core-js-compat@3.38.1: + resolution: {integrity: sha512-JRH6gfXxGmrzF3tZ57lFx97YARxCXPaMzPo6jELZhv88pBH5VXpQ+y0znKGlFnzuaihqhLbefxSJxWJMPtfDzw==} + dependencies: + browserslist: 4.24.0 + dev: true + + /create-jest@29.7.0(@types/node@18.19.53): resolution: {integrity: sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} hasBin: true @@ -3159,7 +4550,7 @@ packages: chalk: 4.1.2 exit: 0.1.2 graceful-fs: 4.2.11 - jest-config: 29.7.0(@types/node@14.17.4) + jest-config: 29.7.0(@types/node@18.19.53) jest-util: 29.7.0 prompts: 2.4.2 transitivePeerDependencies: @@ -3205,54 +4596,46 @@ packages: whatwg-url: 11.0.0 dev: true - /debug@2.6.9: - resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true + /data-view-buffer@1.0.1: + resolution: {integrity: sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA==} + engines: {node: '>= 0.4'} dependencies: - ms: 2.0.0 + call-bind: 1.0.7 + es-errors: 1.3.0 + is-data-view: 1.0.1 dev: true - - /debug@3.2.7: - resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true + + /data-view-byte-length@1.0.1: + resolution: {integrity: sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ==} + engines: {node: '>= 0.4'} dependencies: - ms: 2.1.3 + call-bind: 1.0.7 + es-errors: 1.3.0 + is-data-view: 1.0.1 dev: true - /debug@4.3.4: - resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} - engines: {node: '>=6.0'} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true + /data-view-byte-offset@1.0.0: + resolution: {integrity: sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA==} + engines: {node: '>= 0.4'} dependencies: - ms: 2.1.2 + call-bind: 1.0.7 + es-errors: 1.3.0 + is-data-view: 1.0.1 + dev: true - /debug@4.3.4(supports-color@8.1.1): - resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} - engines: {node: '>=6.0'} + /debug@3.2.7: + resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==} peerDependencies: supports-color: '*' peerDependenciesMeta: supports-color: optional: true dependencies: - ms: 2.1.2 - supports-color: 8.1.1 + ms: 2.1.3 dev: true - /debug@4.3.4(supports-color@9.4.0): - resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} + /debug@4.3.7: + resolution: {integrity: sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==} engines: {node: '>=6.0'} peerDependencies: supports-color: '*' @@ -3260,26 +4643,19 @@ packages: supports-color: optional: true dependencies: - ms: 2.1.2 - supports-color: 9.4.0 - dev: true + ms: 2.1.3 /decamelize@1.2.0: resolution: {integrity: sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==} engines: {node: '>=0.10.0'} dev: true - /decamelize@4.0.0: - resolution: {integrity: sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==} - engines: {node: '>=10'} - dev: true - /decimal.js@10.4.3: resolution: {integrity: sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==} dev: true - /dedent@1.5.1: - resolution: {integrity: sha512-+LxW+KLWxu3HW3M2w2ympwtqPrqYRzU8fqi6Fhd18fBALe15blJPI/I4+UHveMVG6lJqB4JNd4UG0S5cnVHwIg==} + /dedent@1.5.3: + resolution: {integrity: sha512-NHQtfOOW68WD8lgypbLA5oT+Bt0xXJhiYvoR6SmmNXZfpzOGXwdKWmcwG8N7PwVVWV3eF/68nmD9BaJSsTBhyQ==} peerDependencies: babel-plugin-macros: ^3.1.0 peerDependenciesMeta: @@ -3287,30 +4663,6 @@ packages: optional: true dev: true - /deep-equal@2.2.3: - resolution: {integrity: sha512-ZIwpnevOurS8bpT4192sqAowWM76JDKSHYzMLty3BZGSswgq6pBaH3DhCSW5xVAZICZyKdOBPjwww5wfgT/6PA==} - engines: {node: '>= 0.4'} - dependencies: - array-buffer-byte-length: 1.0.0 - call-bind: 1.0.5 - es-get-iterator: 1.1.3 - get-intrinsic: 1.2.2 - is-arguments: 1.1.1 - is-array-buffer: 3.0.2 - is-date-object: 1.0.5 - is-regex: 1.1.4 - is-shared-array-buffer: 1.0.2 - isarray: 2.0.5 - object-is: 1.1.5 - object-keys: 1.1.1 - object.assign: 4.1.5 - regexp.prototype.flags: 1.5.1 - side-channel: 1.0.4 - which-boxed-primitive: 1.0.2 - which-collection: 1.0.1 - which-typed-array: 1.1.13 - dev: true - /deep-is@0.1.4: resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} dev: true @@ -3327,21 +4679,21 @@ packages: strip-bom: 4.0.0 dev: true - /define-data-property@1.1.1: - resolution: {integrity: sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ==} + /define-data-property@1.1.4: + resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} engines: {node: '>= 0.4'} dependencies: - get-intrinsic: 1.2.2 + es-define-property: 1.0.0 + es-errors: 1.3.0 gopd: 1.0.1 - has-property-descriptors: 1.0.1 dev: true /define-properties@1.2.1: resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} engines: {node: '>= 0.4'} dependencies: - define-data-property: 1.1.1 - has-property-descriptors: 1.0.1 + define-data-property: 1.1.4 + has-property-descriptors: 1.0.2 object-keys: 1.1.1 dev: true @@ -3350,6 +4702,11 @@ packages: engines: {node: '>=0.4.0'} dev: true + /dequal@2.0.3: + resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} + engines: {node: '>=6'} + dev: true + /detect-newline@3.1.0: resolution: {integrity: sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==} engines: {node: '>=8'} @@ -3360,18 +4717,6 @@ packages: engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dev: true - /diff@5.0.0: - resolution: {integrity: sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==} - engines: {node: '>=0.3.1'} - dev: true - - /dir-glob@3.0.1: - resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} - engines: {node: '>=8'} - dependencies: - path-type: 4.0.0 - dev: true - /doctrine@2.1.0: resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==} engines: {node: '>=0.10.0'} @@ -3393,7 +4738,7 @@ packages: /dom-helpers@5.2.1: resolution: {integrity: sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==} dependencies: - '@babel/runtime': 7.23.8 + '@babel/runtime': 7.25.6 csstype: 3.1.3 dev: false @@ -3409,8 +4754,16 @@ packages: resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} dev: true - /electron-to-chromium@1.4.645: - resolution: {integrity: sha512-EeS1oQDCmnYsRDRy2zTeC336a/4LZ6WKqvSaM1jLocEk5ZuyszkQtCpsqvuvaIXGOUjwtvF6LTcS8WueibXvSw==} + /ejs@3.1.10: + resolution: {integrity: sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==} + engines: {node: '>=0.10.0'} + hasBin: true + dependencies: + jake: 10.9.2 + dev: true + + /electron-to-chromium@1.5.29: + resolution: {integrity: sha512-PF8n2AlIhCKXQ+gTpiJi0VhcHDb69kYX4MtCiivctc2QD3XuNZ/XIOlbGzt7WAjjEev0TtaH6Cu3arZExm5DOw==} dev: true /emittery@0.13.1: @@ -3418,6 +4771,10 @@ packages: engines: {node: '>=12'} dev: true + /emoji-regex@10.4.0: + resolution: {integrity: sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw==} + dev: true + /emoji-regex@8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} dev: true @@ -3426,89 +4783,134 @@ packages: resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} dev: true + /enhanced-resolve@5.17.1: + resolution: {integrity: sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg==} + engines: {node: '>=10.13.0'} + dependencies: + graceful-fs: 4.2.11 + tapable: 2.2.1 + dev: true + /entities@4.5.0: resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} engines: {node: '>=0.12'} dev: true + /environment@1.1.0: + resolution: {integrity: sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==} + engines: {node: '>=18'} + dev: true + /error-ex@1.3.2: resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==} dependencies: is-arrayish: 0.2.1 dev: true - /es-abstract@1.22.3: - resolution: {integrity: sha512-eiiY8HQeYfYH2Con2berK+To6GrK2RxbPawDkGq4UiCQQfZHb6wX9qQqkbpPqaxQFcl8d9QzZqo0tGE0VcrdwA==} + /es-abstract@1.23.3: + resolution: {integrity: sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A==} engines: {node: '>= 0.4'} dependencies: - array-buffer-byte-length: 1.0.0 - arraybuffer.prototype.slice: 1.0.2 - available-typed-arrays: 1.0.5 - call-bind: 1.0.5 - es-set-tostringtag: 2.0.2 + array-buffer-byte-length: 1.0.1 + arraybuffer.prototype.slice: 1.0.3 + available-typed-arrays: 1.0.7 + call-bind: 1.0.7 + data-view-buffer: 1.0.1 + data-view-byte-length: 1.0.1 + data-view-byte-offset: 1.0.0 + es-define-property: 1.0.0 + es-errors: 1.3.0 + es-object-atoms: 1.0.0 + es-set-tostringtag: 2.0.3 es-to-primitive: 1.2.1 function.prototype.name: 1.1.6 - get-intrinsic: 1.2.2 - get-symbol-description: 1.0.0 - globalthis: 1.0.3 + get-intrinsic: 1.2.4 + get-symbol-description: 1.0.2 + globalthis: 1.0.4 gopd: 1.0.1 - has-property-descriptors: 1.0.1 - has-proto: 1.0.1 + has-property-descriptors: 1.0.2 + has-proto: 1.0.3 has-symbols: 1.0.3 - hasown: 2.0.0 - internal-slot: 1.0.6 - is-array-buffer: 3.0.2 + hasown: 2.0.2 + internal-slot: 1.0.7 + is-array-buffer: 3.0.4 is-callable: 1.2.7 - is-negative-zero: 2.0.2 + is-data-view: 1.0.1 + is-negative-zero: 2.0.3 is-regex: 1.1.4 - is-shared-array-buffer: 1.0.2 + is-shared-array-buffer: 1.0.3 is-string: 1.0.7 - is-typed-array: 1.1.12 + is-typed-array: 1.1.13 is-weakref: 1.0.2 - object-inspect: 1.13.1 + object-inspect: 1.13.2 object-keys: 1.1.1 object.assign: 4.1.5 - regexp.prototype.flags: 1.5.1 - safe-array-concat: 1.1.0 - safe-regex-test: 1.0.2 - string.prototype.trim: 1.2.8 - string.prototype.trimend: 1.0.7 - string.prototype.trimstart: 1.0.7 - typed-array-buffer: 1.0.0 - typed-array-byte-length: 1.0.0 - typed-array-byte-offset: 1.0.0 - typed-array-length: 1.0.4 + regexp.prototype.flags: 1.5.2 + safe-array-concat: 1.1.2 + safe-regex-test: 1.0.3 + string.prototype.trim: 1.2.9 + string.prototype.trimend: 1.0.8 + string.prototype.trimstart: 1.0.8 + typed-array-buffer: 1.0.2 + typed-array-byte-length: 1.0.1 + typed-array-byte-offset: 1.0.2 + typed-array-length: 1.0.6 unbox-primitive: 1.0.2 - which-typed-array: 1.1.13 + which-typed-array: 1.1.15 + dev: true + + /es-define-property@1.0.0: + resolution: {integrity: sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==} + engines: {node: '>= 0.4'} + dependencies: + get-intrinsic: 1.2.4 + dev: true + + /es-errors@1.3.0: + resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} + engines: {node: '>= 0.4'} dev: true - /es-get-iterator@1.1.3: - resolution: {integrity: sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw==} + /es-iterator-helpers@1.0.19: + resolution: {integrity: sha512-zoMwbCcH5hwUkKJkT8kDIBZSz9I6mVG//+lDCinLCGov4+r7NIy0ld8o03M0cJxl2spVf6ESYVS6/gpIfq1FFw==} + engines: {node: '>= 0.4'} dependencies: - call-bind: 1.0.5 - get-intrinsic: 1.2.2 + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 + es-errors: 1.3.0 + es-set-tostringtag: 2.0.3 + function-bind: 1.1.2 + get-intrinsic: 1.2.4 + globalthis: 1.0.4 + has-property-descriptors: 1.0.2 + has-proto: 1.0.3 has-symbols: 1.0.3 - is-arguments: 1.1.1 - is-map: 2.0.2 - is-set: 2.0.2 - is-string: 1.0.7 - isarray: 2.0.5 - stop-iteration-iterator: 1.0.0 + internal-slot: 1.0.7 + iterator.prototype: 1.1.2 + safe-array-concat: 1.1.2 + dev: true + + /es-object-atoms@1.0.0: + resolution: {integrity: sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==} + engines: {node: '>= 0.4'} + dependencies: + es-errors: 1.3.0 dev: true - /es-set-tostringtag@2.0.2: - resolution: {integrity: sha512-BuDyupZt65P9D2D2vA/zqcI3G5xRsklm5N3xCwuiy+/vKy8i0ifdsQP1sLgO4tZDSCaQUSnmC48khknGMV3D2Q==} + /es-set-tostringtag@2.0.3: + resolution: {integrity: sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ==} engines: {node: '>= 0.4'} dependencies: - get-intrinsic: 1.2.2 - has-tostringtag: 1.0.0 - hasown: 2.0.0 + get-intrinsic: 1.2.4 + has-tostringtag: 1.0.2 + hasown: 2.0.2 dev: true /es-shim-unscopables@1.0.2: resolution: {integrity: sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==} dependencies: - hasown: 2.0.0 + hasown: 2.0.2 dev: true /es-to-primitive@1.2.1: @@ -3524,8 +4926,8 @@ packages: resolution: {integrity: sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==} dev: true - /escalade@3.1.1: - resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==} + /escalade@3.2.0: + resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} engines: {node: '>=6'} dev: true @@ -3556,32 +4958,28 @@ packages: source-map: 0.6.1 dev: true - /eslint-config-standard@17.0.0(eslint-plugin-import@2.25.4)(eslint-plugin-n@15.2.0)(eslint-plugin-promise@6.0.0)(eslint@8.15.0): - resolution: {integrity: sha512-/2ks1GKyqSOkH7JFvXJicu0iMpoojkwB+f5Du/1SC0PtBL+s8v30k9njRZ21pm2drKYm2342jFnGWzttxPmZVg==} + /eslint-compat-utils@0.5.1(eslint@8.57.1): + resolution: {integrity: sha512-3z3vFexKIEnjHE3zCMRo6fn/e44U7T1khUjg+Hp0ZQMCigh28rALD0nPFBcGZuiLC5rLZa2ubQHDRln09JfU2Q==} + engines: {node: '>=12'} peerDependencies: - eslint: ^8.0.1 - eslint-plugin-import: ^2.25.2 - eslint-plugin-n: ^15.0.0 - eslint-plugin-promise: ^6.0.0 + eslint: '>=6.0.0' dependencies: - eslint: 8.15.0 - eslint-plugin-import: 2.25.4(@typescript-eslint/parser@6.5.0)(eslint@8.15.0) - eslint-plugin-n: 15.2.0(eslint@8.15.0) - eslint-plugin-promise: 6.0.0(eslint@8.15.0) + eslint: 8.57.1 + semver: 7.6.3 dev: true /eslint-import-resolver-node@0.3.9: resolution: {integrity: sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==} dependencies: debug: 3.2.7 - is-core-module: 2.13.1 + is-core-module: 2.15.1 resolve: 1.22.8 transitivePeerDependencies: - supports-color dev: true - /eslint-module-utils@2.8.0(@typescript-eslint/parser@6.5.0)(eslint-import-resolver-node@0.3.9)(eslint@8.15.0): - resolution: {integrity: sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw==} + /eslint-module-utils@2.12.0(@typescript-eslint/parser@8.7.0)(eslint-import-resolver-node@0.3.9)(eslint@8.57.1): + resolution: {integrity: sha512-wALZ0HFoytlyh/1+4wuZ9FJCD/leWHQzzrxJ8+rebyReSLk7LApMyd3WJaLVoN+D5+WIdJyDK1c6JnE65V4Zyg==} engines: {node: '>=4'} peerDependencies: '@typescript-eslint/parser': '*' @@ -3601,35 +4999,36 @@ packages: eslint-import-resolver-webpack: optional: true dependencies: - '@typescript-eslint/parser': 6.5.0(eslint@8.15.0)(typescript@5.4.5) + '@typescript-eslint/parser': 8.7.0(eslint@8.57.1)(typescript@5.4.5) debug: 3.2.7 - eslint: 8.15.0 + eslint: 8.57.1 eslint-import-resolver-node: 0.3.9 transitivePeerDependencies: - supports-color dev: true - /eslint-plugin-es@4.1.0(eslint@8.15.0): - resolution: {integrity: sha512-GILhQTnjYE2WorX5Jyi5i4dz5ALWxBIdQECVQavL6s7cI76IZTDWleTHkxz/QT3kvcs2QlGHvKLYsSlPOlPXnQ==} - engines: {node: '>=8.10.0'} + /eslint-plugin-es-x@7.8.0(eslint@8.57.1): + resolution: {integrity: sha512-7Ds8+wAAoV3T+LAKeu39Y5BzXCrGKrcISfgKEqTS4BDN8SFEDQd0S43jiQ8vIa3wUKD07qitZdfzlenSi8/0qQ==} + engines: {node: ^14.18.0 || >=16.0.0} peerDependencies: - eslint: '>=4.19.1' + eslint: '>=8' dependencies: - eslint: 8.15.0 - eslint-utils: 2.1.0 - regexpp: 3.2.0 + '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.1) + '@eslint-community/regexpp': 4.11.1 + eslint: 8.57.1 + eslint-compat-utils: 0.5.1(eslint@8.57.1) dev: true - /eslint-plugin-header@3.1.1(eslint@8.15.0): + /eslint-plugin-header@3.1.1(eslint@8.57.1): resolution: {integrity: sha512-9vlKxuJ4qf793CmeeSrZUvVClw6amtpghq3CuWcB5cUNnWHQhgcqy5eF8oVKFk1G3Y/CbchGfEaw3wiIJaNmVg==} peerDependencies: eslint: '>=7.7.0' dependencies: - eslint: 8.15.0 + eslint: 8.57.1 dev: true - /eslint-plugin-import@2.25.4(@typescript-eslint/parser@6.5.0)(eslint@8.15.0): - resolution: {integrity: sha512-/KJBASVFxpu0xg1kIBn9AUa8hQVnszpwgE7Ld0lKAlx7Ie87yzEzCgSkekt+le/YVhiaosO4Y14GDAOc41nfxA==} + /eslint-plugin-import@2.30.0(@typescript-eslint/parser@8.7.0)(eslint@8.57.1): + resolution: {integrity: sha512-/mHNE9jINJfiD2EKkg1BKyPyUk4zdnT54YgbOgfjSakWT5oyX/qQLVNTkehyfpcMxZXMy1zyonZ2v7hZTX43Yw==} engines: {node: '>=4'} peerDependencies: '@typescript-eslint/parser': '*' @@ -3638,20 +5037,25 @@ packages: '@typescript-eslint/parser': optional: true dependencies: - '@typescript-eslint/parser': 6.5.0(eslint@8.15.0)(typescript@5.4.5) - array-includes: 3.1.7 + '@rtsao/scc': 1.1.0 + '@typescript-eslint/parser': 8.7.0(eslint@8.57.1)(typescript@5.4.5) + array-includes: 3.1.8 + array.prototype.findlastindex: 1.2.5 array.prototype.flat: 1.3.2 - debug: 2.6.9 + array.prototype.flatmap: 1.3.2 + debug: 3.2.7 doctrine: 2.1.0 - eslint: 8.15.0 + eslint: 8.57.1 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.8.0(@typescript-eslint/parser@6.5.0)(eslint-import-resolver-node@0.3.9)(eslint@8.15.0) - has: 1.0.4 - is-core-module: 2.13.1 + eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.7.0)(eslint-import-resolver-node@0.3.9)(eslint@8.57.1) + hasown: 2.0.2 + is-core-module: 2.15.1 is-glob: 4.0.3 minimatch: 3.1.2 - object.values: 1.1.7 - resolve: 1.22.8 + object.fromentries: 2.0.8 + object.groupby: 1.0.3 + object.values: 1.2.0 + semver: 6.3.1 tsconfig-paths: 3.15.0 transitivePeerDependencies: - eslint-import-resolver-typescript @@ -3659,12 +5063,12 @@ packages: - supports-color dev: true - /eslint-plugin-jest@27.2.1(@typescript-eslint/eslint-plugin@5.13.0)(eslint@8.15.0)(jest@29.4.0)(typescript@5.4.5): - resolution: {integrity: sha512-l067Uxx7ZT8cO9NJuf+eJHvt6bqJyz2Z29wykyEdz/OtmcELQl2MQGQLX8J94O1cSJWAwUSEvCjwjA7KEK3Hmg==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + /eslint-plugin-jest@28.8.3(@typescript-eslint/eslint-plugin@8.7.0)(eslint@8.57.1)(jest@29.7.0)(typescript@5.4.5): + resolution: {integrity: sha512-HIQ3t9hASLKm2IhIOqnu+ifw7uLZkIlR7RYNv7fMcEi/p0CIiJmfriStQS2LDkgtY4nyLbIZAD+JL347Yc2ETQ==} + engines: {node: ^16.10.0 || ^18.12.0 || >=20.0.0} peerDependencies: - '@typescript-eslint/eslint-plugin': ^5.0.0 - eslint: ^7.0.0 || ^8.0.0 + '@typescript-eslint/eslint-plugin': ^6.0.0 || ^7.0.0 || ^8.0.0 + eslint: ^7.0.0 || ^8.0.0 || ^9.0.0 jest: '*' peerDependenciesMeta: '@typescript-eslint/eslint-plugin': @@ -3672,104 +5076,104 @@ packages: jest: optional: true dependencies: - '@typescript-eslint/eslint-plugin': 5.13.0(@typescript-eslint/parser@6.5.0)(eslint@8.15.0)(typescript@5.4.5) - '@typescript-eslint/utils': 5.62.0(eslint@8.15.0)(typescript@5.4.5) - eslint: 8.15.0 - jest: 29.4.0(@types/node@14.17.4) + '@typescript-eslint/eslint-plugin': 8.7.0(@typescript-eslint/parser@8.7.0)(eslint@8.57.1)(typescript@5.4.5) + '@typescript-eslint/utils': 8.7.0(eslint@8.57.1)(typescript@5.4.5) + eslint: 8.57.1 + jest: 29.7.0(@types/node@18.19.53) transitivePeerDependencies: - supports-color - typescript dev: true - /eslint-plugin-n@15.2.0(eslint@8.15.0): - resolution: {integrity: sha512-lWLg++jGwC88GDGGBX3CMkk0GIWq0y41aH51lavWApOKcMQcYoL3Ayd0lEdtD3SnQtR+3qBvWQS3qGbR2BxRWg==} - engines: {node: '>=12.22.0'} + /eslint-plugin-n@17.10.3(eslint@8.57.1): + resolution: {integrity: sha512-ySZBfKe49nQZWR1yFaA0v/GsH6Fgp8ah6XV0WDz6CN8WO0ek4McMzb7A2xnf4DCYV43frjCygvb9f/wx7UUxRw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - eslint: '>=7.0.0' + eslint: '>=8.23.0' dependencies: - builtins: 4.1.0 - eslint: 8.15.0 - eslint-plugin-es: 4.1.0(eslint@8.15.0) - eslint-utils: 3.0.0(eslint@8.15.0) - ignore: 5.3.0 - is-core-module: 2.13.1 - minimatch: 3.1.2 - resolve: 1.22.8 - semver: 6.3.1 + '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.1) + enhanced-resolve: 5.17.1 + eslint: 8.57.1 + eslint-plugin-es-x: 7.8.0(eslint@8.57.1) + get-tsconfig: 4.8.1 + globals: 15.9.0 + ignore: 5.3.2 + minimatch: 9.0.5 + semver: 7.6.3 dev: true - /eslint-plugin-no-secrets@0.8.9(eslint@8.15.0): - resolution: {integrity: sha512-CqaBxXrImABCtxMWspAnm8d5UKkpNylC7zqVveb+fJHEvsSiNGJlSWzdSIvBUnW1XhJXkzifNIZQC08rEII5Ng==} + /eslint-plugin-no-secrets@1.0.2(eslint@8.57.1): + resolution: {integrity: sha512-lXjGcPS6ZMxAouYWsuX5NGsLlOWQ5c+YFHHZFECzRCZIssYQgWVPINgZqAU7caquB32MoEAL+dXRQNDBX0fgwQ==} engines: {node: '>=10.0.0', npm: '>=6.9.0'} peerDependencies: eslint: '>=3.0.0' dependencies: - eslint: 8.15.0 + eslint: 8.57.1 dev: true - /eslint-plugin-prettier@4.0.0(eslint@8.15.0)(prettier@2.5.1): - resolution: {integrity: sha512-98MqmCJ7vJodoQK359bqQWaxOE0CS8paAz/GgjaZLyex4TTk3g9HugoO89EqWCrFiOqn9EVvcoo7gZzONCWVwQ==} - engines: {node: '>=6.0.0'} + /eslint-plugin-prettier@5.2.1(eslint@8.57.1)(prettier@3.3.3): + resolution: {integrity: sha512-gH3iR3g4JfF+yYPaJYkN7jEl9QbweL/YfkoRlNnuIEHEz1vHVlCmWOS+eGGiRuzHQXdJFCOTxRgvju9b8VUmrw==} + engines: {node: ^14.18.0 || >=16.0.0} peerDependencies: - eslint: '>=7.28.0' + '@types/eslint': '>=8.0.0' + eslint: '>=8.0.0' eslint-config-prettier: '*' - prettier: '>=2.0.0' + prettier: '>=3.0.0' peerDependenciesMeta: + '@types/eslint': + optional: true eslint-config-prettier: optional: true dependencies: - eslint: 8.15.0 - prettier: 2.5.1 + eslint: 8.57.1 + prettier: 3.3.3 prettier-linter-helpers: 1.0.0 + synckit: 0.9.1 dev: true - /eslint-plugin-promise@6.0.0(eslint@8.15.0): - resolution: {integrity: sha512-7GPezalm5Bfi/E22PnQxDWH2iW9GTvAlUNTztemeHb6c1BniSyoeTrM87JkC0wYdi6aQrZX9p2qEiAno8aTcbw==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + /eslint-plugin-promise@7.1.0(eslint@8.57.1): + resolution: {integrity: sha512-8trNmPxdAy3W620WKDpaS65NlM5yAumod6XeC4LOb+jxlkG4IVcp68c6dXY2ev+uT4U1PtG57YDV6EGAXN0GbQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - eslint: ^7.0.0 || ^8.0.0 + eslint: ^7.0.0 || ^8.0.0 || ^9.0.0 dependencies: - eslint: 8.15.0 + eslint: 8.57.1 dev: true - /eslint-plugin-react-hooks@4.2.0(eslint@8.15.0): - resolution: {integrity: sha512-623WEiZJqxR7VdxFCKLI6d6LLpwJkGPYKODnkH3D7WpOG5KM8yWueBd8TLsNAetEJNF5iJmolaAKO3F8yzyVBQ==} + /eslint-plugin-react-hooks@4.6.2(eslint@8.57.1): + resolution: {integrity: sha512-QzliNJq4GinDBcD8gPB5v0wh6g8q3SUi6EFF0x8N/BL9PoVs0atuGc47ozMRyOWAKdwaZ5OnbOEa3WR+dSGKuQ==} engines: {node: '>=10'} peerDependencies: - eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 + eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 dependencies: - eslint: 8.15.0 + eslint: 8.57.1 dev: true - /eslint-plugin-react@7.26.0(eslint@8.15.0): - resolution: {integrity: sha512-dceliS5itjk4EZdQYtLMz6GulcsasguIs+VTXuiC7Q5IPIdGTkyfXVdmsQOqEhlD9MciofH4cMcT1bw1WWNxCQ==} + /eslint-plugin-react@7.37.0(eslint@8.57.1): + resolution: {integrity: sha512-IHBePmfWH5lKhJnJ7WB1V+v/GolbB0rjS8XYVCSQCZKaQCAUhMoVoOEn1Ef8Z8Wf0a7l8KTJvuZg5/e4qrZ6nA==} engines: {node: '>=4'} peerDependencies: - eslint: ^3 || ^4 || ^5 || ^6 || ^7 + eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7 dependencies: - array-includes: 3.1.7 + array-includes: 3.1.8 + array.prototype.findlast: 1.2.5 array.prototype.flatmap: 1.3.2 + array.prototype.tosorted: 1.1.4 doctrine: 2.1.0 - eslint: 8.15.0 + es-iterator-helpers: 1.0.19 + eslint: 8.57.1 estraverse: 5.3.0 + hasown: 2.0.2 jsx-ast-utils: 3.3.5 minimatch: 3.1.2 - object.entries: 1.1.7 - object.fromentries: 2.0.7 - object.hasown: 1.1.3 - object.values: 1.1.7 + object.entries: 1.1.8 + object.fromentries: 2.0.8 + object.values: 1.2.0 prop-types: 15.8.1 resolve: 2.0.0-next.5 semver: 6.3.1 - string.prototype.matchall: 4.0.10 - dev: true - - /eslint-scope@5.1.1: - resolution: {integrity: sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==} - engines: {node: '>=8.0.0'} - dependencies: - esrecurse: 4.3.0 - estraverse: 4.3.0 + string.prototype.matchall: 4.0.11 + string.prototype.repeat: 1.0.0 dev: true /eslint-scope@7.2.2: @@ -3780,78 +5184,54 @@ packages: estraverse: 5.3.0 dev: true - /eslint-utils@2.1.0: - resolution: {integrity: sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==} - engines: {node: '>=6'} - dependencies: - eslint-visitor-keys: 1.3.0 - dev: true - - /eslint-utils@3.0.0(eslint@8.15.0): - resolution: {integrity: sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==} - engines: {node: ^10.0.0 || ^12.0.0 || >= 14.0.0} - peerDependencies: - eslint: '>=5' - dependencies: - eslint: 8.15.0 - eslint-visitor-keys: 2.1.0 - dev: true - - /eslint-visitor-keys@1.3.0: - resolution: {integrity: sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==} - engines: {node: '>=4'} - dev: true - - /eslint-visitor-keys@2.1.0: - resolution: {integrity: sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==} - engines: {node: '>=10'} - dev: true - /eslint-visitor-keys@3.4.3: resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dev: true - /eslint@8.15.0: - resolution: {integrity: sha512-GG5USZ1jhCu8HJkzGgeK8/+RGnHaNYZGrGDzUtigK3BsGESW/rs2az23XqE0WVwDxy1VRvvjSSGu5nB0Bu+6SA==} + /eslint@8.57.1: + resolution: {integrity: sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} hasBin: true dependencies: - '@eslint/eslintrc': 1.4.1 - '@humanwhocodes/config-array': 0.9.5 + '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.1) + '@eslint-community/regexpp': 4.11.1 + '@eslint/eslintrc': 2.1.4 + '@eslint/js': 8.57.1 + '@humanwhocodes/config-array': 0.13.0 + '@humanwhocodes/module-importer': 1.0.1 + '@nodelib/fs.walk': 1.2.8 + '@ungap/structured-clone': 1.2.0 ajv: 6.12.6 chalk: 4.1.2 cross-spawn: 7.0.3 - debug: 4.3.4 + debug: 4.3.7 doctrine: 3.0.0 escape-string-regexp: 4.0.0 eslint-scope: 7.2.2 - eslint-utils: 3.0.0(eslint@8.15.0) eslint-visitor-keys: 3.4.3 espree: 9.6.1 - esquery: 1.5.0 + esquery: 1.6.0 esutils: 2.0.3 fast-deep-equal: 3.1.3 file-entry-cache: 6.0.1 - functional-red-black-tree: 1.0.1 + find-up: 5.0.0 glob-parent: 6.0.2 globals: 13.24.0 - ignore: 5.3.0 - import-fresh: 3.3.0 + graphemer: 1.4.0 + ignore: 5.3.2 imurmurhash: 0.1.4 is-glob: 4.0.3 + is-path-inside: 3.0.3 js-yaml: 4.1.0 json-stable-stringify-without-jsonify: 1.0.1 levn: 0.4.1 lodash.merge: 4.6.2 minimatch: 3.1.2 natural-compare: 1.4.0 - optionator: 0.9.3 - regexpp: 3.2.0 + optionator: 0.9.4 strip-ansi: 6.0.1 - strip-json-comments: 3.1.1 text-table: 0.2.0 - v8-compile-cache: 2.4.0 transitivePeerDependencies: - supports-color dev: true @@ -3860,8 +5240,8 @@ packages: resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dependencies: - acorn: 8.11.3 - acorn-jsx: 5.3.2(acorn@8.11.3) + acorn: 8.12.1 + acorn-jsx: 5.3.2(acorn@8.12.1) eslint-visitor-keys: 3.4.3 dev: true @@ -3871,8 +5251,8 @@ packages: hasBin: true dev: true - /esquery@1.5.0: - resolution: {integrity: sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==} + /esquery@1.6.0: + resolution: {integrity: sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==} engines: {node: '>=0.10'} dependencies: estraverse: 5.3.0 @@ -3885,11 +5265,6 @@ packages: estraverse: 5.3.0 dev: true - /estraverse@4.3.0: - resolution: {integrity: sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==} - engines: {node: '>=4.0'} - dev: true - /estraverse@5.3.0: resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} engines: {node: '>=4.0'} @@ -3900,6 +5275,10 @@ packages: engines: {node: '>=0.10.0'} dev: true + /eventemitter3@5.0.1: + resolution: {integrity: sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==} + dev: true + /execa@5.1.1: resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==} engines: {node: '>=10'} @@ -3915,6 +5294,21 @@ packages: strip-final-newline: 2.0.0 dev: true + /execa@8.0.1: + resolution: {integrity: sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==} + engines: {node: '>=16.17'} + dependencies: + cross-spawn: 7.0.3 + get-stream: 8.0.1 + human-signals: 5.0.0 + is-stream: 3.0.0 + merge-stream: 2.0.0 + npm-run-path: 5.3.0 + onetime: 6.0.0 + signal-exit: 4.1.0 + strip-final-newline: 3.0.0 + dev: true + /exit@0.1.2: resolution: {integrity: sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==} engines: {node: '>= 0.8.0'} @@ -3947,7 +5341,7 @@ packages: '@nodelib/fs.walk': 1.2.8 glob-parent: 5.1.2 merge2: 1.4.1 - micromatch: 4.0.5 + micromatch: 4.0.8 dev: true /fast-json-stable-stringify@2.1.0: @@ -3958,8 +5352,8 @@ packages: resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} dev: true - /fastq@1.16.0: - resolution: {integrity: sha512-ifCoaXsDrsdkWTtiNJX5uzHDsrck5TzfKKDcuFFTIrrc/BS076qgEIfoIy1VeZqViznfKiysPYTh/QeHtnIsYA==} + /fastq@1.17.1: + resolution: {integrity: sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==} dependencies: reusify: 1.0.4 dev: true @@ -3977,8 +5371,14 @@ packages: flat-cache: 3.2.0 dev: true - /fill-range@7.0.1: - resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==} + /filelist@1.0.4: + resolution: {integrity: sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==} + dependencies: + minimatch: 5.1.6 + dev: true + + /fill-range@7.1.1: + resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} engines: {node: '>=8'} dependencies: to-regex-range: 5.0.1 @@ -4013,18 +5413,13 @@ packages: resolution: {integrity: sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==} engines: {node: ^10.12.0 || >=12.0.0} dependencies: - flatted: 3.2.9 + flatted: 3.3.1 keyv: 4.5.4 rimraf: 3.0.2 dev: true - /flat@5.0.2: - resolution: {integrity: sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==} - hasBin: true - dev: true - - /flatted@3.2.9: - resolution: {integrity: sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==} + /flatted@3.3.1: + resolution: {integrity: sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==} dev: true /for-each@0.3.3: @@ -4041,6 +5436,14 @@ packages: signal-exit: 3.0.7 dev: true + /foreground-child@3.3.0: + resolution: {integrity: sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==} + engines: {node: '>=14'} + dependencies: + cross-spawn: 7.0.3 + signal-exit: 4.1.0 + dev: true + /form-data@4.0.0: resolution: {integrity: sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==} engines: {node: '>= 6'} @@ -4074,16 +5477,12 @@ packages: resolution: {integrity: sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==} engines: {node: '>= 0.4'} dependencies: - call-bind: 1.0.5 + call-bind: 1.0.7 define-properties: 1.2.1 - es-abstract: 1.22.3 + es-abstract: 1.23.3 functions-have-names: 1.2.3 dev: true - /functional-red-black-tree@1.0.1: - resolution: {integrity: sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==} - dev: true - /functions-have-names@1.2.3: resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} dev: true @@ -4098,13 +5497,20 @@ packages: engines: {node: 6.* || 8.* || >= 10.*} dev: true - /get-intrinsic@1.2.2: - resolution: {integrity: sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA==} + /get-east-asian-width@1.2.0: + resolution: {integrity: sha512-2nk+7SIVb14QrgXFHcm84tD4bKQz0RxPuMT8Ag5KPOq7J5fEmAg0UbXdTOSHqNuHSU28k55qnceesxXRZGzKWA==} + engines: {node: '>=18'} + dev: true + + /get-intrinsic@1.2.4: + resolution: {integrity: sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==} + engines: {node: '>= 0.4'} dependencies: + es-errors: 1.3.0 function-bind: 1.1.2 - has-proto: 1.0.1 + has-proto: 1.0.3 has-symbols: 1.0.3 - hasown: 2.0.0 + hasown: 2.0.2 dev: true /get-package-type@0.1.0: @@ -4117,12 +5523,24 @@ packages: engines: {node: '>=10'} dev: true - /get-symbol-description@1.0.0: - resolution: {integrity: sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==} + /get-stream@8.0.1: + resolution: {integrity: sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==} + engines: {node: '>=16'} + dev: true + + /get-symbol-description@1.0.2: + resolution: {integrity: sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==} engines: {node: '>= 0.4'} dependencies: - call-bind: 1.0.5 - get-intrinsic: 1.2.2 + call-bind: 1.0.7 + es-errors: 1.3.0 + get-intrinsic: 1.2.4 + dev: true + + /get-tsconfig@4.8.1: + resolution: {integrity: sha512-k9PN+cFBmaLWtVz29SkUoqU5O0slLuHJXt/2P+tMVFT+phsSGXGkp9t3rQIqdz0e+06EHNGs3oM6ZX1s2zHxRg==} + dependencies: + resolve-pkg-maps: 1.0.0 dev: true /glob-parent@5.1.2: @@ -4139,19 +5557,22 @@ packages: is-glob: 4.0.3 dev: true - /glob@7.2.0: - resolution: {integrity: sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==} + /glob@11.0.0: + resolution: {integrity: sha512-9UiX/Bl6J2yaBbxKoEBRm4Cipxgok8kQYcOPEhScPwebu2I0HoQOuYdIO6S3hLuWoZgpDpwQZMzTFxgpkyT76g==} + engines: {node: 20 || >=22} + hasBin: true dependencies: - fs.realpath: 1.0.0 - inflight: 1.0.6 - inherits: 2.0.4 - minimatch: 3.1.2 - once: 1.4.0 - path-is-absolute: 1.0.1 + foreground-child: 3.3.0 + jackspeak: 4.0.2 + minimatch: 10.0.1 + minipass: 7.1.2 + package-json-from-dist: 1.0.1 + path-scurry: 2.0.0 dev: true /glob@7.2.3: resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} + deprecated: Glob versions prior to v9 are no longer supported dependencies: fs.realpath: 1.0.0 inflight: 1.0.6 @@ -4173,35 +5594,33 @@ packages: type-fest: 0.20.2 dev: true - /globalthis@1.0.3: - resolution: {integrity: sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==} - engines: {node: '>= 0.4'} - dependencies: - define-properties: 1.2.1 + /globals@15.9.0: + resolution: {integrity: sha512-SmSKyLLKFbSr6rptvP8izbyxJL4ILwqO9Jg23UA0sDlGlu58V59D1//I3vlc0KJphVdUR7vMjHIplYnzBxorQA==} + engines: {node: '>=18'} dev: true - /globby@11.1.0: - resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==} - engines: {node: '>=10'} + /globalthis@1.0.4: + resolution: {integrity: sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==} + engines: {node: '>= 0.4'} dependencies: - array-union: 2.1.0 - dir-glob: 3.0.1 - fast-glob: 3.3.2 - ignore: 5.3.0 - merge2: 1.4.1 - slash: 3.0.0 + define-properties: 1.2.1 + gopd: 1.0.1 dev: true /gopd@1.0.1: resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==} dependencies: - get-intrinsic: 1.2.2 + get-intrinsic: 1.2.4 dev: true /graceful-fs@4.2.11: resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} dev: true + /graphemer@1.4.0: + resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} + dev: true + /has-bigints@1.0.2: resolution: {integrity: sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==} dev: true @@ -4216,14 +5635,14 @@ packages: engines: {node: '>=8'} dev: true - /has-property-descriptors@1.0.1: - resolution: {integrity: sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg==} + /has-property-descriptors@1.0.2: + resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==} dependencies: - get-intrinsic: 1.2.2 + es-define-property: 1.0.0 dev: true - /has-proto@1.0.1: - resolution: {integrity: sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==} + /has-proto@1.0.3: + resolution: {integrity: sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==} engines: {node: '>= 0.4'} dev: true @@ -4232,18 +5651,13 @@ packages: engines: {node: '>= 0.4'} dev: true - /has-tostringtag@1.0.0: - resolution: {integrity: sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==} + /has-tostringtag@1.0.2: + resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} engines: {node: '>= 0.4'} dependencies: has-symbols: 1.0.3 dev: true - /has@1.0.4: - resolution: {integrity: sha512-qdSAmqLF6209RFj4VVItywPMbm3vWylknmB3nvNiUIs72xAimcM8nVYxYr7ncvZq5qzk9MKIZR8ijqD/1QuYjQ==} - engines: {node: '>= 0.4.0'} - dev: true - /hasha@5.2.2: resolution: {integrity: sha512-Hrp5vIK/xr5SkeN2onO32H0MgNZ0f17HRNH39WfL0SYUNOTZ5Lz1TJ8Pajo/87dYGEFlLMm7mIc/k/s6Bvz9HQ==} engines: {node: '>=8'} @@ -4252,18 +5666,13 @@ packages: type-fest: 0.8.1 dev: true - /hasown@2.0.0: - resolution: {integrity: sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==} + /hasown@2.0.2: + resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} engines: {node: '>= 0.4'} dependencies: function-bind: 1.1.2 dev: true - /he@1.2.0: - resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==} - hasBin: true - dev: true - /html-encoding-sniffer@3.0.0: resolution: {integrity: sha512-oWv4T4yJ52iKrufjnyZPkrN0CH3QnrUqdB6In1g5Fe1mia8GmF36gnfNySxoZtxD5+NmYw1EElVXiBk93UeskA==} engines: {node: '>=12'} @@ -4281,7 +5690,7 @@ packages: dependencies: '@tootallnate/once': 2.0.0 agent-base: 6.0.2 - debug: 4.3.4 + debug: 4.3.7 transitivePeerDependencies: - supports-color dev: true @@ -4291,7 +5700,7 @@ packages: engines: {node: '>= 6'} dependencies: agent-base: 6.0.2 - debug: 4.3.4 + debug: 4.3.7 transitivePeerDependencies: - supports-color dev: true @@ -4301,6 +5710,11 @@ packages: engines: {node: '>=10.17.0'} dev: true + /human-signals@5.0.0: + resolution: {integrity: sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==} + engines: {node: '>=16.17.0'} + dev: true + /iconv-lite@0.6.3: resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} engines: {node: '>=0.10.0'} @@ -4308,8 +5722,8 @@ packages: safer-buffer: 2.1.2 dev: true - /ignore@5.3.0: - resolution: {integrity: sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg==} + /ignore@5.3.2: + resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} engines: {node: '>= 4'} dev: true @@ -4321,8 +5735,8 @@ packages: resolve-from: 4.0.0 dev: true - /import-local@3.1.0: - resolution: {integrity: sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==} + /import-local@3.2.0: + resolution: {integrity: sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==} engines: {node: '>=8'} hasBin: true dependencies: @@ -4342,6 +5756,7 @@ packages: /inflight@1.0.6: resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} + deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful. dependencies: once: 1.4.0 wrappy: 1.0.2 @@ -4351,54 +5766,46 @@ packages: resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} dev: true - /internal-slot@1.0.6: - resolution: {integrity: sha512-Xj6dv+PsbtwyPpEflsejS+oIZxmMlV44zAhG479uYu89MsjcYOhCFnNyKrkJrihbsiasQyY0afoCl/9BLR65bg==} + /internal-slot@1.0.7: + resolution: {integrity: sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==} engines: {node: '>= 0.4'} dependencies: - get-intrinsic: 1.2.2 - hasown: 2.0.0 - side-channel: 1.0.4 + es-errors: 1.3.0 + hasown: 2.0.2 + side-channel: 1.0.6 dev: true - /is-arguments@1.1.1: - resolution: {integrity: sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==} + /is-array-buffer@3.0.4: + resolution: {integrity: sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==} engines: {node: '>= 0.4'} dependencies: - call-bind: 1.0.5 - has-tostringtag: 1.0.0 - dev: true - - /is-array-buffer@3.0.2: - resolution: {integrity: sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==} - dependencies: - call-bind: 1.0.5 - get-intrinsic: 1.2.2 - is-typed-array: 1.1.12 + call-bind: 1.0.7 + get-intrinsic: 1.2.4 dev: true /is-arrayish@0.2.1: resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} dev: true - /is-bigint@1.0.4: - resolution: {integrity: sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==} + /is-async-function@2.0.0: + resolution: {integrity: sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA==} + engines: {node: '>= 0.4'} dependencies: - has-bigints: 1.0.2 + has-tostringtag: 1.0.2 dev: true - /is-binary-path@2.1.0: - resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} - engines: {node: '>=8'} + /is-bigint@1.0.4: + resolution: {integrity: sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==} dependencies: - binary-extensions: 2.2.0 + has-bigints: 1.0.2 dev: true /is-boolean-object@1.1.2: resolution: {integrity: sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==} engines: {node: '>= 0.4'} dependencies: - call-bind: 1.0.5 - has-tostringtag: 1.0.0 + call-bind: 1.0.7 + has-tostringtag: 1.0.2 dev: true /is-callable@1.2.7: @@ -4406,17 +5813,25 @@ packages: engines: {node: '>= 0.4'} dev: true - /is-core-module@2.13.1: - resolution: {integrity: sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==} + /is-core-module@2.15.1: + resolution: {integrity: sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==} + engines: {node: '>= 0.4'} + dependencies: + hasown: 2.0.2 + dev: true + + /is-data-view@1.0.1: + resolution: {integrity: sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w==} + engines: {node: '>= 0.4'} dependencies: - hasown: 2.0.0 + is-typed-array: 1.1.13 dev: true /is-date-object@1.0.5: resolution: {integrity: sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==} engines: {node: '>= 0.4'} dependencies: - has-tostringtag: 1.0.0 + has-tostringtag: 1.0.2 dev: true /is-extglob@2.1.1: @@ -4424,6 +5839,12 @@ packages: engines: {node: '>=0.10.0'} dev: true + /is-finalizationregistry@1.0.2: + resolution: {integrity: sha512-0by5vtUJs8iFQb5TYUHHPudOR+qXYIMKtiUzvLIZITZUjknFmziyBJuLhVRc+Ds0dREFlskDNJKYIdIzu/9pfw==} + dependencies: + call-bind: 1.0.7 + dev: true + /is-fullwidth-code-point@3.0.0: resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} engines: {node: '>=8'} @@ -4434,11 +5855,25 @@ packages: engines: {node: '>=12'} dev: true + /is-fullwidth-code-point@5.0.0: + resolution: {integrity: sha512-OVa3u9kkBbw7b8Xw5F9P+D/T9X+Z4+JruYVNapTjPYZYUznQ5YfWeFkOj606XYYW8yugTfC8Pj0hYqvi4ryAhA==} + engines: {node: '>=18'} + dependencies: + get-east-asian-width: 1.2.0 + dev: true + /is-generator-fn@2.1.0: resolution: {integrity: sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==} engines: {node: '>=6'} dev: true + /is-generator-function@1.0.10: + resolution: {integrity: sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==} + engines: {node: '>= 0.4'} + dependencies: + has-tostringtag: 1.0.2 + dev: true + /is-glob@4.0.3: resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} engines: {node: '>=0.10.0'} @@ -4446,12 +5881,13 @@ packages: is-extglob: 2.1.1 dev: true - /is-map@2.0.2: - resolution: {integrity: sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==} + /is-map@2.0.3: + resolution: {integrity: sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==} + engines: {node: '>= 0.4'} dev: true - /is-negative-zero@2.0.2: - resolution: {integrity: sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==} + /is-negative-zero@2.0.3: + resolution: {integrity: sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==} engines: {node: '>= 0.4'} dev: true @@ -4459,7 +5895,7 @@ packages: resolution: {integrity: sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==} engines: {node: '>= 0.4'} dependencies: - has-tostringtag: 1.0.0 + has-tostringtag: 1.0.2 dev: true /is-number@7.0.0: @@ -4467,8 +5903,8 @@ packages: engines: {node: '>=0.12.0'} dev: true - /is-plain-obj@2.1.0: - resolution: {integrity: sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==} + /is-path-inside@3.0.3: + resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==} engines: {node: '>=8'} dev: true @@ -4480,18 +5916,20 @@ packages: resolution: {integrity: sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==} engines: {node: '>= 0.4'} dependencies: - call-bind: 1.0.5 - has-tostringtag: 1.0.0 + call-bind: 1.0.7 + has-tostringtag: 1.0.2 dev: true - /is-set@2.0.2: - resolution: {integrity: sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g==} + /is-set@2.0.3: + resolution: {integrity: sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==} + engines: {node: '>= 0.4'} dev: true - /is-shared-array-buffer@1.0.2: - resolution: {integrity: sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==} + /is-shared-array-buffer@1.0.3: + resolution: {integrity: sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==} + engines: {node: '>= 0.4'} dependencies: - call-bind: 1.0.5 + call-bind: 1.0.7 dev: true /is-stream@2.0.1: @@ -4499,11 +5937,16 @@ packages: engines: {node: '>=8'} dev: true + /is-stream@3.0.0: + resolution: {integrity: sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dev: true + /is-string@1.0.7: resolution: {integrity: sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==} engines: {node: '>= 0.4'} dependencies: - has-tostringtag: 1.0.0 + has-tostringtag: 1.0.2 dev: true /is-symbol@1.0.4: @@ -4513,37 +5956,34 @@ packages: has-symbols: 1.0.3 dev: true - /is-typed-array@1.1.12: - resolution: {integrity: sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg==} + /is-typed-array@1.1.13: + resolution: {integrity: sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==} engines: {node: '>= 0.4'} dependencies: - which-typed-array: 1.1.13 + which-typed-array: 1.1.15 dev: true /is-typedarray@1.0.0: resolution: {integrity: sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==} dev: true - /is-unicode-supported@0.1.0: - resolution: {integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==} - engines: {node: '>=10'} - dev: true - - /is-weakmap@2.0.1: - resolution: {integrity: sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA==} + /is-weakmap@2.0.2: + resolution: {integrity: sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==} + engines: {node: '>= 0.4'} dev: true /is-weakref@1.0.2: resolution: {integrity: sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==} dependencies: - call-bind: 1.0.5 + call-bind: 1.0.7 dev: true - /is-weakset@2.0.2: - resolution: {integrity: sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg==} + /is-weakset@2.0.3: + resolution: {integrity: sha512-LvIm3/KWzS9oRFHugab7d+M/GcBXuXX5xZkzPmN+NxihdQlZUQ4dWuSV1xR/sq6upL1TJEDrfBgRepHFdBtSNQ==} + engines: {node: '>= 0.4'} dependencies: - call-bind: 1.0.5 - get-intrinsic: 1.2.2 + call-bind: 1.0.7 + get-intrinsic: 1.2.4 dev: true /is-windows@1.0.2: @@ -4580,24 +6020,12 @@ packages: append-transform: 2.0.0 dev: true - /istanbul-lib-instrument@4.0.3: - resolution: {integrity: sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ==} - engines: {node: '>=8'} - dependencies: - '@babel/core': 7.23.7 - '@istanbuljs/schema': 0.1.3 - istanbul-lib-coverage: 3.2.2 - semver: 6.3.1 - transitivePeerDependencies: - - supports-color - dev: true - /istanbul-lib-instrument@5.2.1: resolution: {integrity: sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==} engines: {node: '>=8'} dependencies: - '@babel/core': 7.23.7 - '@babel/parser': 7.23.6 + '@babel/core': 7.25.2 + '@babel/parser': 7.25.6 '@istanbuljs/schema': 0.1.3 istanbul-lib-coverage: 3.2.2 semver: 6.3.1 @@ -4605,15 +6033,15 @@ packages: - supports-color dev: true - /istanbul-lib-instrument@6.0.1: - resolution: {integrity: sha512-EAMEJBsYuyyztxMxW3g7ugGPkrZsV57v0Hmv3mm1uQsmB+QnZuepg731CRaIgeUVSdmsTngOkSnauNF8p7FIhA==} + /istanbul-lib-instrument@6.0.3: + resolution: {integrity: sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==} engines: {node: '>=10'} dependencies: - '@babel/core': 7.23.7 - '@babel/parser': 7.23.6 + '@babel/core': 7.25.2 + '@babel/parser': 7.25.6 '@istanbuljs/schema': 0.1.3 istanbul-lib-coverage: 3.2.2 - semver: 7.5.4 + semver: 7.6.3 transitivePeerDependencies: - supports-color dev: true @@ -4643,21 +6071,49 @@ packages: resolution: {integrity: sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==} engines: {node: '>=10'} dependencies: - debug: 4.3.4 + debug: 4.3.7 istanbul-lib-coverage: 3.2.2 source-map: 0.6.1 transitivePeerDependencies: - supports-color dev: true - /istanbul-reports@3.1.6: - resolution: {integrity: sha512-TLgnMkKg3iTDsQ9PbPTdpfAK2DzjF9mqUG7RMgcQl8oFjad8ob4laGxv5XV5U9MAfx8D6tSJiUyuAwzLicaxlg==} + /istanbul-reports@3.1.7: + resolution: {integrity: sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==} engines: {node: '>=8'} dependencies: html-escaper: 2.0.2 istanbul-lib-report: 3.0.1 dev: true + /iterator.prototype@1.1.2: + resolution: {integrity: sha512-DR33HMMr8EzwuRL8Y9D3u2BMj8+RqSE850jfGu59kS7tbmPLzGkZmVSfyCFSDxuZiEY6Rzt3T2NA/qU+NwVj1w==} + dependencies: + define-properties: 1.2.1 + get-intrinsic: 1.2.4 + has-symbols: 1.0.3 + reflect.getprototypeof: 1.0.6 + set-function-name: 2.0.2 + dev: true + + /jackspeak@4.0.2: + resolution: {integrity: sha512-bZsjR/iRjl1Nk1UkjGpAzLNfQtzuijhn2g+pbZb98HQ1Gk8vM9hfbxeMBP+M2/UUdwj0RqGG3mlvk2MsAqwvEw==} + engines: {node: 20 || >=22} + dependencies: + '@isaacs/cliui': 8.0.2 + dev: true + + /jake@10.9.2: + resolution: {integrity: sha512-2P4SQ0HrLQ+fw6llpLnOaGAvN2Zu6778SJMrCUwns4fOoG9ayrTiZk3VV8sCPkVZF8ab0zksVpS8FDY5pRCNBA==} + engines: {node: '>=10'} + hasBin: true + dependencies: + async: 3.2.6 + chalk: 4.1.2 + filelist: 1.0.4 + minimatch: 3.1.2 + dev: true + /jest-changed-files@29.7.0: resolution: {integrity: sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -4675,10 +6131,10 @@ packages: '@jest/expect': 29.7.0 '@jest/test-result': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 14.17.4 + '@types/node': 18.19.53 chalk: 4.1.2 co: 4.6.0 - dedent: 1.5.1 + dedent: 1.5.3 is-generator-fn: 2.1.0 jest-each: 29.7.0 jest-matcher-utils: 29.7.0 @@ -4688,7 +6144,7 @@ packages: jest-util: 29.7.0 p-limit: 3.1.0 pretty-format: 29.7.0 - pure-rand: 6.0.4 + pure-rand: 6.1.0 slash: 3.0.0 stack-utils: 2.0.6 transitivePeerDependencies: @@ -4696,7 +6152,7 @@ packages: - supports-color dev: true - /jest-cli@29.7.0(@types/node@14.17.4): + /jest-cli@29.7.0(@types/node@18.19.53): resolution: {integrity: sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} hasBin: true @@ -4710,10 +6166,10 @@ packages: '@jest/test-result': 29.7.0 '@jest/types': 29.6.3 chalk: 4.1.2 - create-jest: 29.7.0(@types/node@14.17.4) + create-jest: 29.7.0(@types/node@18.19.53) exit: 0.1.2 - import-local: 3.1.0 - jest-config: 29.7.0(@types/node@14.17.4) + import-local: 3.2.0 + jest-config: 29.7.0(@types/node@18.19.53) jest-util: 29.7.0 jest-validate: 29.7.0 yargs: 17.7.2 @@ -4724,7 +6180,7 @@ packages: - ts-node dev: true - /jest-config@29.7.0(@types/node@14.17.4): + /jest-config@29.7.0(@types/node@18.19.53): resolution: {integrity: sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} peerDependencies: @@ -4736,11 +6192,11 @@ packages: ts-node: optional: true dependencies: - '@babel/core': 7.23.7 + '@babel/core': 7.25.2 '@jest/test-sequencer': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 14.17.4 - babel-jest: 29.7.0(@babel/core@7.23.7) + '@types/node': 18.19.53 + babel-jest: 29.7.0(@babel/core@7.25.2) chalk: 4.1.2 ci-info: 3.9.0 deepmerge: 4.3.1 @@ -4754,7 +6210,7 @@ packages: jest-runner: 29.7.0 jest-util: 29.7.0 jest-validate: 29.7.0 - micromatch: 4.0.5 + micromatch: 4.0.8 parse-json: 5.2.0 pretty-format: 29.7.0 slash: 3.0.0 @@ -4792,8 +6248,8 @@ packages: pretty-format: 29.7.0 dev: true - /jest-environment-jsdom@29.4.1: - resolution: {integrity: sha512-+KfYmRTl5CBHQst9hIz77TiiriHYvuWoLjMT855gx2AMxhHxpk1vtKvag1DQfyWCPVTWV/AG7SIqVh5WI1O/uw==} + /jest-environment-jsdom@29.7.0: + resolution: {integrity: sha512-k9iQbsf9OyOfdzWH8HDmrRT0gSIcX+FLNW7IQq94tFX0gynPwqDTW0Ho6iMVNjGz/nb+l/vW3dWM2bbLLpkbXA==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} peerDependencies: canvas: ^2.5.0 @@ -4805,7 +6261,7 @@ packages: '@jest/fake-timers': 29.7.0 '@jest/types': 29.6.3 '@types/jsdom': 20.0.1 - '@types/node': 14.17.4 + '@types/node': 18.19.53 jest-mock: 29.7.0 jest-util: 29.7.0 jsdom: 20.0.3 @@ -4822,7 +6278,7 @@ packages: '@jest/environment': 29.7.0 '@jest/fake-timers': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 14.17.4 + '@types/node': 18.19.53 jest-mock: 29.7.0 jest-util: 29.7.0 dev: true @@ -4838,21 +6294,21 @@ packages: dependencies: '@jest/types': 29.6.3 '@types/graceful-fs': 4.1.9 - '@types/node': 14.17.4 + '@types/node': 18.19.53 anymatch: 3.1.3 fb-watchman: 2.0.2 graceful-fs: 4.2.11 jest-regex-util: 29.6.3 jest-util: 29.7.0 jest-worker: 29.7.0 - micromatch: 4.0.5 + micromatch: 4.0.8 walker: 1.0.8 optionalDependencies: fsevents: 2.3.3 dev: true - /jest-junit@15.0.0: - resolution: {integrity: sha512-Z5sVX0Ag3HZdMUnD5DFlG+1gciIFSy7yIVPhOdGUi8YJaI9iLvvBb530gtQL2CHmv0JJeiwRZenr0VrSR7frvg==} + /jest-junit@16.0.0: + resolution: {integrity: sha512-A94mmw6NfJab4Fg/BlvVOUXzXgF0XIH6EmTgJ5NDPp4xoKq0Kr7sErb+4Xs9nZvu58pJojz5RFGpqnZYJTrRfQ==} engines: {node: '>=10.12.0'} dependencies: mkdirp: 1.0.4 @@ -4883,12 +6339,12 @@ packages: resolution: {integrity: sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: - '@babel/code-frame': 7.23.5 + '@babel/code-frame': 7.24.7 '@jest/types': 29.6.3 '@types/stack-utils': 2.0.3 chalk: 4.1.2 graceful-fs: 4.2.11 - micromatch: 4.0.5 + micromatch: 4.0.8 pretty-format: 29.7.0 slash: 3.0.0 stack-utils: 2.0.6 @@ -4899,7 +6355,7 @@ packages: engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: '@jest/types': 29.6.3 - '@types/node': 14.17.4 + '@types/node': 18.19.53 jest-util: 29.7.0 dev: true @@ -4954,7 +6410,7 @@ packages: '@jest/test-result': 29.7.0 '@jest/transform': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 14.17.4 + '@types/node': 18.19.53 chalk: 4.1.2 emittery: 0.13.1 graceful-fs: 4.2.11 @@ -4985,9 +6441,9 @@ packages: '@jest/test-result': 29.7.0 '@jest/transform': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 14.17.4 + '@types/node': 18.19.53 chalk: 4.1.2 - cjs-module-lexer: 1.2.3 + cjs-module-lexer: 1.4.1 collect-v8-coverage: 1.0.2 glob: 7.2.3 graceful-fs: 4.2.11 @@ -5008,15 +6464,15 @@ packages: resolution: {integrity: sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: - '@babel/core': 7.23.7 - '@babel/generator': 7.23.6 - '@babel/plugin-syntax-jsx': 7.23.3(@babel/core@7.23.7) - '@babel/plugin-syntax-typescript': 7.23.3(@babel/core@7.23.7) - '@babel/types': 7.23.6 + '@babel/core': 7.25.2 + '@babel/generator': 7.25.6 + '@babel/plugin-syntax-jsx': 7.24.7(@babel/core@7.25.2) + '@babel/plugin-syntax-typescript': 7.25.4(@babel/core@7.25.2) + '@babel/types': 7.25.6 '@jest/expect-utils': 29.7.0 '@jest/transform': 29.7.0 '@jest/types': 29.6.3 - babel-preset-current-node-syntax: 1.0.1(@babel/core@7.23.7) + babel-preset-current-node-syntax: 1.1.0(@babel/core@7.25.2) chalk: 4.1.2 expect: 29.7.0 graceful-fs: 4.2.11 @@ -5027,7 +6483,7 @@ packages: jest-util: 29.7.0 natural-compare: 1.4.0 pretty-format: 29.7.0 - semver: 7.5.4 + semver: 7.6.3 transitivePeerDependencies: - supports-color dev: true @@ -5037,7 +6493,7 @@ packages: engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: '@jest/types': 29.6.3 - '@types/node': 14.17.4 + '@types/node': 18.19.53 chalk: 4.1.2 ci-info: 3.9.0 graceful-fs: 4.2.11 @@ -5062,7 +6518,7 @@ packages: dependencies: '@jest/test-result': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 14.17.4 + '@types/node': 18.19.53 ansi-escapes: 4.3.2 chalk: 4.1.2 emittery: 0.13.1 @@ -5074,14 +6530,14 @@ packages: resolution: {integrity: sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: - '@types/node': 14.17.4 + '@types/node': 18.19.53 jest-util: 29.7.0 merge-stream: 2.0.0 supports-color: 8.1.1 dev: true - /jest@29.4.0(@types/node@14.17.4): - resolution: {integrity: sha512-Zfd4UzNxPkSoHRBkg225rBjQNa6pVqbh20MGniAzwaOzYLd+pQUcAwH+WPxSXxKFs+QWYfPYIq9hIVSmdVQmPA==} + /jest@29.7.0(@types/node@18.19.53): + resolution: {integrity: sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} hasBin: true peerDependencies: @@ -5092,8 +6548,8 @@ packages: dependencies: '@jest/core': 29.7.0 '@jest/types': 29.6.3 - import-local: 3.1.0 - jest-cli: 29.7.0(@types/node@14.17.4) + import-local: 3.2.0 + jest-cli: 29.7.0(@types/node@18.19.53) transitivePeerDependencies: - '@types/node' - babel-plugin-macros @@ -5129,7 +6585,7 @@ packages: optional: true dependencies: abab: 2.0.6 - acorn: 8.11.3 + acorn: 8.12.1 acorn-globals: 7.0.1 cssom: 0.5.0 cssstyle: 2.3.0 @@ -5142,17 +6598,17 @@ packages: http-proxy-agent: 5.0.0 https-proxy-agent: 5.0.1 is-potential-custom-element-name: 1.0.1 - nwsapi: 2.2.7 + nwsapi: 2.2.12 parse5: 7.1.2 saxes: 6.0.0 symbol-tree: 3.2.4 - tough-cookie: 4.1.3 + tough-cookie: 4.1.4 w3c-xmlserializer: 4.0.0 webidl-conversions: 7.0.0 whatwg-encoding: 2.0.0 whatwg-mimetype: 3.0.0 whatwg-url: 11.0.0 - ws: 8.16.0 + ws: 8.18.0 xml-name-validator: 4.0.0 transitivePeerDependencies: - bufferutil @@ -5160,6 +6616,11 @@ packages: - utf-8-validate dev: true + /jsesc@0.5.0: + resolution: {integrity: sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==} + hasBin: true + dev: true + /jsesc@2.5.2: resolution: {integrity: sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==} engines: {node: '>=4'} @@ -5199,18 +6660,19 @@ packages: resolution: {integrity: sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==} engines: {node: '>=4.0'} dependencies: - array-includes: 3.1.7 + array-includes: 3.1.8 array.prototype.flat: 1.3.2 object.assign: 4.1.5 - object.values: 1.1.7 + object.values: 1.2.0 dev: true - /jwt-decode@3.1.2: - resolution: {integrity: sha512-UfpWE/VZn0iP50d8cz9NrZLM9lSWhcJ+0Gt/nm4by88UL+J1SiKN8/5dkjMmbEzwL2CAe+67GsegCbIKtbp75A==} + /jwt-decode@4.0.0: + resolution: {integrity: sha512-+KJGIyHgkGuIq3IEBNftfhW/LfWhXUIY6OmyVWjliu5KH1y0fw7VQ8YndE2O4qZdMSd9SqbnC8GOcZEy0Om7sA==} + engines: {node: '>=18'} dev: true - /keyborg@2.4.1: - resolution: {integrity: sha512-B9EZwDd36WKlIq6JmimaTsTDx5E0aUqZcxtgTfK66ut1FbRXYhBmiB7Al2qKzB7CCX9C49sTBiiyVzsXCA6J4Q==} + /keyborg@2.6.0: + resolution: {integrity: sha512-o5kvLbuTF+o326CMVYpjlaykxqYP9DphFQZ2ZpgrvBouyvOxyEB7oqe8nOLFpiV5VCtz0D3pt8gXQYWpLpBnmA==} dev: false /keyv@4.5.4: @@ -5237,54 +6699,44 @@ packages: type-check: 0.4.0 dev: true - /lilconfig@2.0.4: - resolution: {integrity: sha512-bfTIN7lEsiooCocSISTWXkiWJkRqtL9wYtYy+8EK3Y41qh3mpwPU0ycTOgjdY9ErwXCc8QyrQp82bdL0Xkm9yA==} - engines: {node: '>=10'} + /lilconfig@3.1.2: + resolution: {integrity: sha512-eop+wDAvpItUys0FWkHIKeC9ybYrTGbU41U5K7+bttZZeohvnY7M9dZ5kB21GNWiFT2q1OoPTvncPCgSOVO5ow==} + engines: {node: '>=14'} dev: true /lines-and-columns@1.2.4: resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} dev: true - /lint-staged@12.3.4: - resolution: {integrity: sha512-yv/iK4WwZ7/v0GtVkNb3R82pdL9M+ScpIbJLJNyCXkJ1FGaXvRCOg/SeL59SZtPpqZhE7BD6kPKFLIDUhDx2/w==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + /lint-staged@15.2.10: + resolution: {integrity: sha512-5dY5t743e1byO19P9I4b3x8HJwalIznL5E1FWYnU6OWw33KxNBSLAc6Cy7F2PsFEO8FKnLwjwm5hx7aMF0jzZg==} + engines: {node: '>=18.12.0'} hasBin: true dependencies: - cli-truncate: 3.1.0 - colorette: 2.0.20 - commander: 8.3.0 - debug: 4.3.4(supports-color@9.4.0) - execa: 5.1.1 - lilconfig: 2.0.4 - listr2: 4.0.5 - micromatch: 4.0.5 - normalize-path: 3.0.0 - object-inspect: 1.13.1 + chalk: 5.3.0 + commander: 12.1.0 + debug: 4.3.7 + execa: 8.0.1 + lilconfig: 3.1.2 + listr2: 8.2.4 + micromatch: 4.0.8 + pidtree: 0.6.0 string-argv: 0.3.2 - supports-color: 9.4.0 - yaml: 1.10.2 + yaml: 2.5.1 transitivePeerDependencies: - - enquirer + - supports-color dev: true - /listr2@4.0.5: - resolution: {integrity: sha512-juGHV1doQdpNT3GSTs9IUN43QJb7KHdF9uqg7Vufs/tG9VTzpFphqF4pm/ICdAABGQxsyNn9CiYA3StkI6jpwA==} - engines: {node: '>=12'} - peerDependencies: - enquirer: '>= 2.3.0 < 3' - peerDependenciesMeta: - enquirer: - optional: true + /listr2@8.2.4: + resolution: {integrity: sha512-opevsywziHd3zHCVQGAj8zu+Z3yHNkkoYhWIGnq54RrCVwLz0MozotJEDnKsIBLvkfLGN6BLOyAeRrYI0pKA4g==} + engines: {node: '>=18.0.0'} dependencies: - cli-truncate: 2.1.0 + cli-truncate: 4.0.0 colorette: 2.0.20 - log-update: 4.0.0 - p-map: 4.0.0 - rfdc: 1.3.1 - rxjs: 7.8.1 - through: 2.3.8 - wrap-ansi: 7.0.0 + eventemitter3: 5.0.1 + log-update: 6.1.0 + rfdc: 1.4.1 + wrap-ansi: 9.0.0 dev: true /locate-path@5.0.0: @@ -5301,6 +6753,10 @@ packages: p-locate: 5.0.0 dev: true + /lodash.debounce@4.0.8: + resolution: {integrity: sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==} + dev: true + /lodash.flattendeep@4.4.0: resolution: {integrity: sha512-uHaJFihxmJcEX3kT4I23ABqKKalJ/zDrDg0lsFtc1h+3uw49SIJ5beyhx5ExVRti3AvKoOJngIj7xz3oylPdWQ==} dev: true @@ -5313,22 +6769,15 @@ packages: resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} dev: true - /log-symbols@4.1.0: - resolution: {integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==} - engines: {node: '>=10'} - dependencies: - chalk: 4.1.2 - is-unicode-supported: 0.1.0 - dev: true - - /log-update@4.0.0: - resolution: {integrity: sha512-9fkkDevMefjg0mmzWFBW8YkFP91OrizzkW3diF7CpG+S2EYdy4+TVfGwz1zeF8x7hCx1ovSPTOE9Ngib74qqUg==} - engines: {node: '>=10'} + /log-update@6.1.0: + resolution: {integrity: sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w==} + engines: {node: '>=18'} dependencies: - ansi-escapes: 4.3.2 - cli-cursor: 3.1.0 - slice-ansi: 4.0.0 - wrap-ansi: 6.2.0 + ansi-escapes: 7.0.0 + cli-cursor: 5.0.0 + slice-ansi: 7.1.0 + strip-ansi: 7.1.0 + wrap-ansi: 9.0.0 dev: true /loose-envify@1.4.0: @@ -5337,17 +6786,15 @@ packages: dependencies: js-tokens: 4.0.0 - /lru-cache@5.1.1: - resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} - dependencies: - yallist: 3.1.1 + /lru-cache@11.0.1: + resolution: {integrity: sha512-CgeuL5uom6j/ZVrg7G/+1IXqRY8JXX4Hghfy5YE0EhoYQWvndP1kufu58cmZLNIDKnRhZrXfdS9urVWx98AipQ==} + engines: {node: 20 || >=22} dev: true - /lru-cache@6.0.0: - resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} - engines: {node: '>=10'} + /lru-cache@5.1.1: + resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} dependencies: - yallist: 4.0.0 + yallist: 3.1.1 dev: true /lz-string@1.5.0: @@ -5366,7 +6813,7 @@ packages: resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==} engines: {node: '>=10'} dependencies: - semver: 7.5.4 + semver: 7.6.3 dev: true /make-error@1.3.6: @@ -5388,11 +6835,11 @@ packages: engines: {node: '>= 8'} dev: true - /micromatch@4.0.5: - resolution: {integrity: sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==} + /micromatch@4.0.8: + resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} engines: {node: '>=8.6'} dependencies: - braces: 3.0.2 + braces: 3.0.3 picomatch: 2.3.1 dev: true @@ -5413,74 +6860,60 @@ packages: engines: {node: '>=6'} dev: true + /mimic-fn@4.0.0: + resolution: {integrity: sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==} + engines: {node: '>=12'} + dev: true + + /mimic-function@5.0.1: + resolution: {integrity: sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==} + engines: {node: '>=18'} + dev: true + + /minimatch@10.0.1: + resolution: {integrity: sha512-ethXTt3SGGR+95gudmqJ1eNhRO7eGEGIgYA9vnPatK4/etz2MEVDno5GMCibdMTuBMyElzIlgxMna3K94XDIDQ==} + engines: {node: 20 || >=22} + dependencies: + brace-expansion: 2.0.1 + dev: true + /minimatch@3.1.2: resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} dependencies: brace-expansion: 1.1.11 dev: true - /minimatch@5.0.1: - resolution: {integrity: sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==} + /minimatch@5.1.6: + resolution: {integrity: sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==} engines: {node: '>=10'} dependencies: brace-expansion: 2.0.1 dev: true + /minimatch@9.0.5: + resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} + engines: {node: '>=16 || 14 >=14.17'} + dependencies: + brace-expansion: 2.0.1 + dev: true + /minimist@1.2.8: resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} dev: true + /minipass@7.1.2: + resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} + engines: {node: '>=16 || 14 >=14.17'} + dev: true + /mkdirp@1.0.4: resolution: {integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==} engines: {node: '>=10'} hasBin: true dev: true - /mocha@10.0.0: - resolution: {integrity: sha512-0Wl+elVUD43Y0BqPZBzZt8Tnkw9CMUdNYnUsTfOM1vuhJVZL+kiesFYsqwBkEEuEixaiPe5ZQdqDgX2jddhmoA==} - engines: {node: '>= 14.0.0'} - hasBin: true - dependencies: - '@ungap/promise-all-settled': 1.1.2 - ansi-colors: 4.1.1 - browser-stdout: 1.3.1 - chokidar: 3.5.3 - debug: 4.3.4(supports-color@8.1.1) - diff: 5.0.0 - escape-string-regexp: 4.0.0 - find-up: 5.0.0 - glob: 7.2.0 - he: 1.2.0 - js-yaml: 4.1.0 - log-symbols: 4.1.0 - minimatch: 5.0.1 - ms: 2.1.3 - nanoid: 3.3.3 - serialize-javascript: 6.0.0 - strip-json-comments: 3.1.1 - supports-color: 8.1.1 - workerpool: 6.2.1 - yargs: 16.2.0 - yargs-parser: 20.2.4 - yargs-unparser: 2.0.0 - dev: true - - /ms@2.0.0: - resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==} - dev: true - - /ms@2.1.2: - resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} - /ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} - dev: true - - /nanoid@3.3.3: - resolution: {integrity: sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==} - engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} - hasBin: true - dev: true /natural-compare@1.4.0: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} @@ -5509,8 +6942,8 @@ packages: process-on-spawn: 1.0.0 dev: true - /node-releases@2.0.14: - resolution: {integrity: sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==} + /node-releases@2.0.18: + resolution: {integrity: sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==} dev: true /normalize-path@3.0.0: @@ -5525,13 +6958,20 @@ packages: path-key: 3.1.1 dev: true - /nwsapi@2.2.7: - resolution: {integrity: sha512-ub5E4+FBPKwAZx0UwIQOjYWGHTEq5sPqHQNRN8Z9e4A7u3Tj1weLJsL59yH9vmvqEtBHaOmT6cYQKIZOxp35FQ==} + /npm-run-path@5.3.0: + resolution: {integrity: sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dependencies: + path-key: 4.0.0 + dev: true + + /nwsapi@2.2.12: + resolution: {integrity: sha512-qXDmcVlZV4XRtKFzddidpfVP4oMSGhga+xdMc25mv8kaLUHtgzCDhUxkrN8exkGdTlLNaXj7CV3GtON7zuGZ+w==} dev: true - /nyc@15.1.0: - resolution: {integrity: sha512-jMW04n9SxKdKi1ZMGhvUTHBN0EICCRkHemEoE5jm6mTYcqcdas0ATzgUgejlQUHMvpnOZqGB5Xxsv9KxJW1j8A==} - engines: {node: '>=8.9'} + /nyc@17.1.0: + resolution: {integrity: sha512-U42vQ4czpKa0QdI1hu950XuNhYqgoM+ZF1HT+VuUHL9hPfDPVvNQyltmMqdE9bUHMVa+8yNbc3QKTj8zQhlVxQ==} + engines: {node: '>=18'} hasBin: true dependencies: '@istanbuljs/load-nyc-config': 1.1.0 @@ -5541,16 +6981,16 @@ packages: decamelize: 1.2.0 find-cache-dir: 3.3.2 find-up: 4.1.0 - foreground-child: 2.0.0 + foreground-child: 3.3.0 get-package-type: 0.1.0 glob: 7.2.3 istanbul-lib-coverage: 3.2.2 istanbul-lib-hook: 3.0.0 - istanbul-lib-instrument: 4.0.3 + istanbul-lib-instrument: 6.0.3 istanbul-lib-processinfo: 2.0.3 istanbul-lib-report: 3.0.1 istanbul-lib-source-maps: 4.0.1 - istanbul-reports: 3.1.6 + istanbul-reports: 3.1.7 make-dir: 3.1.0 node-preload: 0.2.1 p-map: 3.0.0 @@ -5569,16 +7009,9 @@ packages: resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} engines: {node: '>=0.10.0'} - /object-inspect@1.13.1: - resolution: {integrity: sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==} - dev: true - - /object-is@1.1.5: - resolution: {integrity: sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==} + /object-inspect@1.13.2: + resolution: {integrity: sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==} engines: {node: '>= 0.4'} - dependencies: - call-bind: 1.0.5 - define-properties: 1.2.1 dev: true /object-keys@1.1.1: @@ -5590,44 +7023,47 @@ packages: resolution: {integrity: sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==} engines: {node: '>= 0.4'} dependencies: - call-bind: 1.0.5 + call-bind: 1.0.7 define-properties: 1.2.1 has-symbols: 1.0.3 object-keys: 1.1.1 dev: true - /object.entries@1.1.7: - resolution: {integrity: sha512-jCBs/0plmPsOnrKAfFQXRG2NFjlhZgjjcBLSmTnEhU8U6vVTsVe8ANeQJCHTl3gSsI4J+0emOoCgoKlmQPMgmA==} + /object.entries@1.1.8: + resolution: {integrity: sha512-cmopxi8VwRIAw/fkijJohSfpef5PdN0pMQJN6VC/ZKvn0LIknWD8KtgY6KlQdEc4tIjcQ3HxSMmnvtzIscdaYQ==} engines: {node: '>= 0.4'} dependencies: - call-bind: 1.0.5 + call-bind: 1.0.7 define-properties: 1.2.1 - es-abstract: 1.22.3 + es-object-atoms: 1.0.0 dev: true - /object.fromentries@2.0.7: - resolution: {integrity: sha512-UPbPHML6sL8PI/mOqPwsH4G6iyXcCGzLin8KvEPenOZN5lpCNBZZQ+V62vdjB1mQHrmqGQt5/OJzemUA+KJmEA==} + /object.fromentries@2.0.8: + resolution: {integrity: sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==} engines: {node: '>= 0.4'} dependencies: - call-bind: 1.0.5 + call-bind: 1.0.7 define-properties: 1.2.1 - es-abstract: 1.22.3 + es-abstract: 1.23.3 + es-object-atoms: 1.0.0 dev: true - /object.hasown@1.1.3: - resolution: {integrity: sha512-fFI4VcYpRHvSLXxP7yiZOMAd331cPfd2p7PFDVbgUsYOfCT3tICVqXWngbjr4m49OvsBwUBQ6O2uQoJvy3RexA==} + /object.groupby@1.0.3: + resolution: {integrity: sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==} + engines: {node: '>= 0.4'} dependencies: + call-bind: 1.0.7 define-properties: 1.2.1 - es-abstract: 1.22.3 + es-abstract: 1.23.3 dev: true - /object.values@1.1.7: - resolution: {integrity: sha512-aU6xnDFYT3x17e/f0IiiwlGPTy2jzMySGfUB4fq6z7CV8l85CWHDk5ErhyhpfDHhrOMwGFhSQkhMGHaIotA6Ng==} + /object.values@1.2.0: + resolution: {integrity: sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ==} engines: {node: '>= 0.4'} dependencies: - call-bind: 1.0.5 + call-bind: 1.0.7 define-properties: 1.2.1 - es-abstract: 1.22.3 + es-object-atoms: 1.0.0 dev: true /once@1.4.0: @@ -5643,16 +7079,30 @@ packages: mimic-fn: 2.1.0 dev: true - /optionator@0.9.3: - resolution: {integrity: sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==} + /onetime@6.0.0: + resolution: {integrity: sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==} + engines: {node: '>=12'} + dependencies: + mimic-fn: 4.0.0 + dev: true + + /onetime@7.0.0: + resolution: {integrity: sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==} + engines: {node: '>=18'} + dependencies: + mimic-function: 5.0.1 + dev: true + + /optionator@0.9.4: + resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} engines: {node: '>= 0.8.0'} dependencies: - '@aashutoshrathi/word-wrap': 1.2.6 deep-is: 0.1.4 fast-levenshtein: 2.0.6 levn: 0.4.1 prelude-ls: 1.2.1 type-check: 0.4.0 + word-wrap: 1.2.5 dev: true /p-limit@2.3.0: @@ -5690,13 +7140,6 @@ packages: aggregate-error: 3.1.0 dev: true - /p-map@4.0.0: - resolution: {integrity: sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==} - engines: {node: '>=10'} - dependencies: - aggregate-error: 3.1.0 - dev: true - /p-try@2.2.0: resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} engines: {node: '>=6'} @@ -5712,6 +7155,10 @@ packages: release-zalgo: 1.0.0 dev: true + /package-json-from-dist@1.0.1: + resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} + dev: true + /parent-module@1.0.1: resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} engines: {node: '>=6'} @@ -5723,7 +7170,7 @@ packages: resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} engines: {node: '>=8'} dependencies: - '@babel/code-frame': 7.23.5 + '@babel/code-frame': 7.24.7 error-ex: 1.3.2 json-parse-even-better-errors: 2.3.1 lines-and-columns: 1.2.4 @@ -5750,17 +7197,25 @@ packages: engines: {node: '>=8'} dev: true + /path-key@4.0.0: + resolution: {integrity: sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==} + engines: {node: '>=12'} + dev: true + /path-parse@1.0.7: resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} dev: true - /path-type@4.0.0: - resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} - engines: {node: '>=8'} + /path-scurry@2.0.0: + resolution: {integrity: sha512-ypGJsmGtdXUOeM5u93TyeIEfEhM6s+ljAhrk5vAvSx8uyY/02OvrZnA0YNGUrPXfpJMgI1ODd3nwz8Npx4O4cg==} + engines: {node: 20 || >=22} + dependencies: + lru-cache: 11.0.1 + minipass: 7.1.2 dev: true - /picocolors@1.0.0: - resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==} + /picocolors@1.1.0: + resolution: {integrity: sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw==} dev: true /picomatch@2.3.1: @@ -5768,6 +7223,12 @@ packages: engines: {node: '>=8.6'} dev: true + /pidtree@0.6.0: + resolution: {integrity: sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==} + engines: {node: '>=0.10'} + hasBin: true + dev: true + /pirates@4.0.6: resolution: {integrity: sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==} engines: {node: '>= 6'} @@ -5780,6 +7241,11 @@ packages: find-up: 4.1.0 dev: true + /possible-typed-array-names@1.0.0: + resolution: {integrity: sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==} + engines: {node: '>= 0.4'} + dev: true + /prelude-ls@1.2.1: resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} engines: {node: '>= 0.8.0'} @@ -5792,9 +7258,9 @@ packages: fast-diff: 1.3.0 dev: true - /prettier@2.5.1: - resolution: {integrity: sha512-vBZcPRUR5MZJwoyi3ZoyQlc1rXeEck8KgeC9AwwOn+exuxLxq5toTRDTSaVrXHxelDMHy9zlicw8u66yxoSUFg==} - engines: {node: '>=10.13.0'} + /prettier@3.3.3: + resolution: {integrity: sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==} + engines: {node: '>=14'} hasBin: true dev: true @@ -5813,7 +7279,7 @@ packages: dependencies: '@jest/schemas': 29.6.3 ansi-styles: 5.2.0 - react-is: 18.2.0 + react-is: 18.3.1 dev: true /process-on-spawn@1.0.0: @@ -5847,8 +7313,8 @@ packages: engines: {node: '>=6'} dev: true - /pure-rand@6.0.4: - resolution: {integrity: sha512-LA0Y9kxMYv47GIPJy6MI84fqTd2HmYZI83W/kM/SkKfDlajnZYfmXFTxkbY+xSBPkLJxltMa9hIkmdc29eguMA==} + /pure-rand@6.1.0: + resolution: {integrity: sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==} dev: true /querystringify@2.2.0: @@ -5859,20 +7325,14 @@ packages: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} dev: true - /randombytes@2.1.0: - resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==} - dependencies: - safe-buffer: 5.2.1 - dev: true - - /react-dom@18.2.0(react@18.2.0): - resolution: {integrity: sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==} + /react-dom@18.3.1(react@18.3.1): + resolution: {integrity: sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==} peerDependencies: - react: ^18.2.0 + react: ^18.3.1 dependencies: loose-envify: 1.4.0 - react: 18.2.0 - scheduler: 0.23.0 + react: 18.3.1 + scheduler: 0.23.2 /react-is@16.13.1: resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} @@ -5880,73 +7340,90 @@ packages: /react-is@17.0.2: resolution: {integrity: sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==} - /react-is@18.2.0: - resolution: {integrity: sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==} - dev: true - - /react-shallow-renderer@16.15.0(react@18.2.0): - resolution: {integrity: sha512-oScf2FqQ9LFVQgA73vr86xl2NaOIX73rh+YFqcOp68CWj56tSfgtGKrEbyhCj0rSijyG9M1CYprTh39fBi5hzA==} - peerDependencies: - react: ^16.0.0 || ^17.0.0 || ^18.0.0 - dependencies: - object-assign: 4.1.1 - react: 18.2.0 - react-is: 18.2.0 - dev: true - - /react-test-renderer@18.2.0(react@18.2.0): - resolution: {integrity: sha512-JWD+aQ0lh2gvh4NM3bBM42Kx+XybOxCpgYK7F8ugAlpaTSnWsX+39Z4XkOykGZAHrjwwTZT3x3KxswVWxHPUqA==} - peerDependencies: - react: ^18.2.0 - dependencies: - react: 18.2.0 - react-is: 18.2.0 - react-shallow-renderer: 16.15.0(react@18.2.0) - scheduler: 0.23.0 + /react-is@18.3.1: + resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==} dev: true - /react-transition-group@4.4.5(react-dom@18.2.0)(react@18.2.0): + /react-transition-group@4.4.5(react-dom@18.3.1)(react@18.3.1): resolution: {integrity: sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==} peerDependencies: react: '>=16.6.0' react-dom: '>=16.6.0' dependencies: - '@babel/runtime': 7.23.8 + '@babel/runtime': 7.25.6 dom-helpers: 5.2.1 loose-envify: 1.4.0 prop-types: 15.8.1 - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) dev: false - /react@18.2.0: - resolution: {integrity: sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==} + /react@18.3.1: + resolution: {integrity: sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==} engines: {node: '>=0.10.0'} dependencies: loose-envify: 1.4.0 - /readdirp@3.6.0: - resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} - engines: {node: '>=8.10.0'} + /reflect.getprototypeof@1.0.6: + resolution: {integrity: sha512-fmfw4XgoDke3kdI6h4xcUz1dG8uaiv5q9gcEwLS4Pnth2kxT+GZ7YehS1JTMGBQmtV7Y4GFGbs2re2NqhdozUg==} + engines: {node: '>= 0.4'} dependencies: - picomatch: 2.3.1 + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 + es-errors: 1.3.0 + get-intrinsic: 1.2.4 + globalthis: 1.0.4 + which-builtin-type: 1.1.4 + dev: true + + /regenerate-unicode-properties@10.2.0: + resolution: {integrity: sha512-DqHn3DwbmmPVzeKj9woBadqmXxLvQoQIwu7nopMc72ztvxVmVk2SBhSnx67zuye5TP+lJsb/TBQsjLKhnDf3MA==} + engines: {node: '>=4'} + dependencies: + regenerate: 1.4.2 + dev: true + + /regenerate@1.4.2: + resolution: {integrity: sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==} dev: true /regenerator-runtime@0.14.1: resolution: {integrity: sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==} - /regexp.prototype.flags@1.5.1: - resolution: {integrity: sha512-sy6TXMN+hnP/wMy+ISxg3krXx7BAtWVO4UouuCN/ziM9UEne0euamVNafDfvC83bRNr95y0V5iijeDQFUNpvrg==} + /regenerator-transform@0.15.2: + resolution: {integrity: sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg==} + dependencies: + '@babel/runtime': 7.25.6 + dev: true + + /regexp.prototype.flags@1.5.2: + resolution: {integrity: sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw==} engines: {node: '>= 0.4'} dependencies: - call-bind: 1.0.5 + call-bind: 1.0.7 define-properties: 1.2.1 - set-function-name: 2.0.1 + es-errors: 1.3.0 + set-function-name: 2.0.2 dev: true - /regexpp@3.2.0: - resolution: {integrity: sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==} - engines: {node: '>=8'} + /regexpu-core@5.3.2: + resolution: {integrity: sha512-RAM5FlZz+Lhmo7db9L298p2vHP5ZywrVXmVXpmAD9GuL5MPH6t9ROw1iA/wfHkQ76Qe7AaPF0nGuim96/IrQMQ==} + engines: {node: '>=4'} + dependencies: + '@babel/regjsgen': 0.8.0 + regenerate: 1.4.2 + regenerate-unicode-properties: 10.2.0 + regjsparser: 0.9.1 + unicode-match-property-ecmascript: 2.0.0 + unicode-match-property-value-ecmascript: 2.2.0 + dev: true + + /regjsparser@0.9.1: + resolution: {integrity: sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==} + hasBin: true + dependencies: + jsesc: 0.5.0 dev: true /release-zalgo@1.0.0: @@ -5986,6 +7463,10 @@ packages: engines: {node: '>=8'} dev: true + /resolve-pkg-maps@1.0.0: + resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} + dev: true + /resolve.exports@2.0.2: resolution: {integrity: sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg==} engines: {node: '>=10'} @@ -5995,7 +7476,7 @@ packages: resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==} hasBin: true dependencies: - is-core-module: 2.13.1 + is-core-module: 2.15.1 path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 dev: true @@ -6004,17 +7485,17 @@ packages: resolution: {integrity: sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==} hasBin: true dependencies: - is-core-module: 2.13.1 + is-core-module: 2.15.1 path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 dev: true - /restore-cursor@3.1.0: - resolution: {integrity: sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==} - engines: {node: '>=8'} + /restore-cursor@5.1.0: + resolution: {integrity: sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==} + engines: {node: '>=18'} dependencies: - onetime: 5.1.2 - signal-exit: 3.0.7 + onetime: 7.0.0 + signal-exit: 4.1.0 dev: true /reusify@1.0.4: @@ -6022,21 +7503,31 @@ packages: engines: {iojs: '>=1.0.0', node: '>=0.10.0'} dev: true - /rfdc@1.3.1: - resolution: {integrity: sha512-r5a3l5HzYlIC68TpmYKlxWjmOP6wiPJ1vWv2HeLhNsRZMrCkxeqxiHlQ21oXmQ4F3SiryXBHhAD7JZqvOJjFmg==} + /rfdc@1.4.1: + resolution: {integrity: sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==} dev: true /rimraf@3.0.2: resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} + deprecated: Rimraf versions prior to v4 are no longer supported hasBin: true dependencies: glob: 7.2.3 dev: true + /rimraf@6.0.1: + resolution: {integrity: sha512-9dkvaxAsk/xNXSJzMgFqqMCuFgt2+KsOFek3TMLfo8NCPfWpBmqwyNn5Y+NX56QUYfCtsyhF3ayiboEoUmJk/A==} + engines: {node: 20 || >=22} + hasBin: true + dependencies: + glob: 11.0.0 + package-json-from-dist: 1.0.1 + dev: true + /rtl-css-js@1.16.1: resolution: {integrity: sha512-lRQgou1mu19e+Ya0LsTvKrVJ5TYUbqCVPAiImX3UfLTenarvPUl1QFdvu5Z3PYmHT9RCcwIfbjRQBntExyj3Zg==} dependencies: - '@babel/runtime': 7.23.8 + '@babel/runtime': 7.25.6 dev: false /run-parallel@1.2.0: @@ -6045,32 +7536,22 @@ packages: queue-microtask: 1.2.3 dev: true - /rxjs@7.8.1: - resolution: {integrity: sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==} - dependencies: - tslib: 2.6.1 - dev: true - - /safe-array-concat@1.1.0: - resolution: {integrity: sha512-ZdQ0Jeb9Ofti4hbt5lX3T2JcAamT9hfzYU1MNB+z/jaEbB6wfFfPIR/zEORmZqobkCCJhSjodobH6WHNmJ97dg==} + /safe-array-concat@1.1.2: + resolution: {integrity: sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==} engines: {node: '>=0.4'} dependencies: - call-bind: 1.0.5 - get-intrinsic: 1.2.2 + call-bind: 1.0.7 + get-intrinsic: 1.2.4 has-symbols: 1.0.3 isarray: 2.0.5 dev: true - /safe-buffer@5.2.1: - resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} - dev: true - - /safe-regex-test@1.0.2: - resolution: {integrity: sha512-83S9w6eFq12BBIJYvjMux6/dkirb8+4zJRA9cxNBVb7Wq5fJBW+Xze48WqR8pxua7bDuAaaAxtVVd4Idjp1dBQ==} + /safe-regex-test@1.0.3: + resolution: {integrity: sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==} engines: {node: '>= 0.4'} dependencies: - call-bind: 1.0.5 - get-intrinsic: 1.2.2 + call-bind: 1.0.7 + es-errors: 1.3.0 is-regex: 1.1.4 dev: true @@ -6085,14 +7566,14 @@ packages: xmlchars: 2.2.0 dev: true - /scheduler@0.20.2: - resolution: {integrity: sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ==} + /scheduler@0.23.0: + resolution: {integrity: sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==} dependencies: loose-envify: 1.4.0 - object-assign: 4.1.1 + dev: false - /scheduler@0.23.0: - resolution: {integrity: sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==} + /scheduler@0.23.2: + resolution: {integrity: sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==} dependencies: loose-envify: 1.4.0 @@ -6101,42 +7582,36 @@ packages: hasBin: true dev: true - /semver@7.5.4: - resolution: {integrity: sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==} + /semver@7.6.3: + resolution: {integrity: sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==} engines: {node: '>=10'} hasBin: true - dependencies: - lru-cache: 6.0.0 - dev: true - - /serialize-javascript@6.0.0: - resolution: {integrity: sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==} - dependencies: - randombytes: 2.1.0 dev: true /set-blocking@2.0.0: resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==} dev: true - /set-function-length@1.2.0: - resolution: {integrity: sha512-4DBHDoyHlM1IRPGYcoxexgh67y4ueR53FKV1yyxwFMY7aCqcN/38M1+SwZ/qJQ8iLv7+ck385ot4CcisOAPT9w==} + /set-function-length@1.2.2: + resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} engines: {node: '>= 0.4'} dependencies: - define-data-property: 1.1.1 + define-data-property: 1.1.4 + es-errors: 1.3.0 function-bind: 1.1.2 - get-intrinsic: 1.2.2 + get-intrinsic: 1.2.4 gopd: 1.0.1 - has-property-descriptors: 1.0.1 + has-property-descriptors: 1.0.2 dev: true - /set-function-name@2.0.1: - resolution: {integrity: sha512-tMNCiqYVkXIZgc2Hnoy2IvC/f8ezc5koaRFkCjrpWzGpCd3qbZXPzVy9MAZzK1ch/X0jvSkojys3oqJN0qCmdA==} + /set-function-name@2.0.2: + resolution: {integrity: sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==} engines: {node: '>= 0.4'} dependencies: - define-data-property: 1.1.1 + define-data-property: 1.1.4 + es-errors: 1.3.0 functions-have-names: 1.2.3 - has-property-descriptors: 1.0.1 + has-property-descriptors: 1.0.2 dev: true /shebang-command@2.0.0: @@ -6151,18 +7626,25 @@ packages: engines: {node: '>=8'} dev: true - /side-channel@1.0.4: - resolution: {integrity: sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==} + /side-channel@1.0.6: + resolution: {integrity: sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==} + engines: {node: '>= 0.4'} dependencies: - call-bind: 1.0.5 - get-intrinsic: 1.2.2 - object-inspect: 1.13.1 + call-bind: 1.0.7 + es-errors: 1.3.0 + get-intrinsic: 1.2.4 + object-inspect: 1.13.2 dev: true /signal-exit@3.0.7: resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} dev: true + /signal-exit@4.1.0: + resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} + engines: {node: '>=14'} + dev: true + /sisteransi@1.0.5: resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} dev: true @@ -6172,24 +7654,6 @@ packages: engines: {node: '>=8'} dev: true - /slice-ansi@3.0.0: - resolution: {integrity: sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==} - engines: {node: '>=8'} - dependencies: - ansi-styles: 4.3.0 - astral-regex: 2.0.0 - is-fullwidth-code-point: 3.0.0 - dev: true - - /slice-ansi@4.0.0: - resolution: {integrity: sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==} - engines: {node: '>=10'} - dependencies: - ansi-styles: 4.3.0 - astral-regex: 2.0.0 - is-fullwidth-code-point: 3.0.0 - dev: true - /slice-ansi@5.0.0: resolution: {integrity: sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==} engines: {node: '>=12'} @@ -6198,6 +7662,14 @@ packages: is-fullwidth-code-point: 4.0.0 dev: true + /slice-ansi@7.1.0: + resolution: {integrity: sha512-bSiSngZ/jWeX93BqeIAbImyTbEihizcwNjFoRUIY/T1wWQsfsm2Vw1agPKylXvQTU7iASGdHhyqRlqQzfz+Htg==} + engines: {node: '>=18'} + dependencies: + ansi-styles: 6.2.1 + is-fullwidth-code-point: 5.0.0 + dev: true + /source-map-support@0.5.13: resolution: {integrity: sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==} dependencies: @@ -6233,13 +7705,6 @@ packages: escape-string-regexp: 2.0.0 dev: true - /stop-iteration-iterator@1.0.0: - resolution: {integrity: sha512-iCGQj+0l0HOdZ2AEeBADlsRC+vsnDsZsbdSiH1yNSjcfKM7fdpCMfqAL/dwF5BLiw/XhRft/Wax6zQbhq2BcjQ==} - engines: {node: '>= 0.4'} - dependencies: - internal-slot: 1.0.6 - dev: true - /string-argv@0.3.2: resolution: {integrity: sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==} engines: {node: '>=0.6.19'} @@ -6271,43 +7736,65 @@ packages: strip-ansi: 7.1.0 dev: true - /string.prototype.matchall@4.0.10: - resolution: {integrity: sha512-rGXbGmOEosIQi6Qva94HUjgPs9vKW+dkG7Y8Q5O2OYkWL6wFaTRZO8zM4mhP94uX55wgyrXzfS2aGtGzUL7EJQ==} + /string-width@7.2.0: + resolution: {integrity: sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==} + engines: {node: '>=18'} dependencies: - call-bind: 1.0.5 + emoji-regex: 10.4.0 + get-east-asian-width: 1.2.0 + strip-ansi: 7.1.0 + dev: true + + /string.prototype.matchall@4.0.11: + resolution: {integrity: sha512-NUdh0aDavY2og7IbBPenWqR9exH+E26Sv8e0/eTe1tltDGZL+GtBkDAnnyBtmekfK6/Dq3MkcGtzXFEd1LQrtg==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 define-properties: 1.2.1 - es-abstract: 1.22.3 - get-intrinsic: 1.2.2 + es-abstract: 1.23.3 + es-errors: 1.3.0 + es-object-atoms: 1.0.0 + get-intrinsic: 1.2.4 + gopd: 1.0.1 has-symbols: 1.0.3 - internal-slot: 1.0.6 - regexp.prototype.flags: 1.5.1 - set-function-name: 2.0.1 - side-channel: 1.0.4 + internal-slot: 1.0.7 + regexp.prototype.flags: 1.5.2 + set-function-name: 2.0.2 + side-channel: 1.0.6 + dev: true + + /string.prototype.repeat@1.0.0: + resolution: {integrity: sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w==} + dependencies: + define-properties: 1.2.1 + es-abstract: 1.23.3 dev: true - /string.prototype.trim@1.2.8: - resolution: {integrity: sha512-lfjY4HcixfQXOfaqCvcBuOIapyaroTXhbkfJN3gcB1OtyupngWK4sEET9Knd0cXd28kTUqu/kHoV4HKSJdnjiQ==} + /string.prototype.trim@1.2.9: + resolution: {integrity: sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw==} engines: {node: '>= 0.4'} dependencies: - call-bind: 1.0.5 + call-bind: 1.0.7 define-properties: 1.2.1 - es-abstract: 1.22.3 + es-abstract: 1.23.3 + es-object-atoms: 1.0.0 dev: true - /string.prototype.trimend@1.0.7: - resolution: {integrity: sha512-Ni79DqeB72ZFq1uH/L6zJ+DKZTkOtPIHovb3YZHQViE+HDouuU4mBrLOLDn5Dde3RF8qw5qVETEjhu9locMLvA==} + /string.prototype.trimend@1.0.8: + resolution: {integrity: sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ==} dependencies: - call-bind: 1.0.5 + call-bind: 1.0.7 define-properties: 1.2.1 - es-abstract: 1.22.3 + es-object-atoms: 1.0.0 dev: true - /string.prototype.trimstart@1.0.7: - resolution: {integrity: sha512-NGhtDFu3jCEm7B4Fy0DpLewdJQOZcQ0rGbwQ/+stjnrp2i+rlKeCvos9hOIeCmqwratM47OBxY7uFZzjxHXmrg==} + /string.prototype.trimstart@1.0.8: + resolution: {integrity: sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==} + engines: {node: '>= 0.4'} dependencies: - call-bind: 1.0.5 + call-bind: 1.0.7 define-properties: 1.2.1 - es-abstract: 1.22.3 + es-object-atoms: 1.0.0 dev: true /strip-ansi@6.0.1: @@ -6321,7 +7808,7 @@ packages: resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==} engines: {node: '>=12'} dependencies: - ansi-regex: 6.0.1 + ansi-regex: 6.1.0 dev: true /strip-bom@3.0.0: @@ -6339,13 +7826,18 @@ packages: engines: {node: '>=6'} dev: true + /strip-final-newline@3.0.0: + resolution: {integrity: sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==} + engines: {node: '>=12'} + dev: true + /strip-json-comments@3.1.1: resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} engines: {node: '>=8'} dev: true - /stylis@4.3.1: - resolution: {integrity: sha512-EQepAV+wMsIaGVGX1RECzgrcqRRU/0sYOHkeLsZ3fzHaHXZy4DaOOX0vOlGQdlsjkh3mFHAIlVimpwAs4dslyQ==} + /stylis@4.3.4: + resolution: {integrity: sha512-osIBl6BGUmSfDkyH2mB7EFvCJntXDrLhKjHTRj/rK6xLH0yuPrHULDRQzKokSOD4VoorhtKpfcfW1GAntu8now==} dev: false /supports-color@5.5.0: @@ -6369,11 +7861,6 @@ packages: has-flag: 4.0.0 dev: true - /supports-color@9.4.0: - resolution: {integrity: sha512-VL+lNrEoIXww1coLPOmiEmK/0sGigko5COxI09KzHc2VJXJsQ37UaQ+8quuxjDeA7+KnLGTWRyOXSLLR2Wb4jw==} - engines: {node: '>=12'} - dev: true - /supports-preserve-symlinks-flag@1.0.0: resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} engines: {node: '>= 0.4'} @@ -6383,13 +7870,26 @@ packages: resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==} dev: true - /tabster@5.3.0: - resolution: {integrity: sha512-3oqZ0gkWXrPSnc7LBbJ9FQmcZL9DFO+ToK8gGGshSvI5hCgp9AnCtq6CIqce3zpg2/aZZci51MUTgNQFbTUiUg==} + /synckit@0.9.1: + resolution: {integrity: sha512-7gr8p9TQP6RAHusBOSLs46F4564ZrjV8xFmw5zCmgmhGUcw2hxsShhJ6CEiHQMgPDwAQ1fWHPM0ypc4RMAig4A==} + engines: {node: ^14.18.0 || >=16.0.0} + dependencies: + '@pkgr/core': 0.1.1 + tslib: 2.7.0 + dev: true + + /tabster@8.2.0: + resolution: {integrity: sha512-Gvplk/Yl/12aVFA6FPOqGcq31Qv8hbPfYO0N+6IxrRgRT6eSLsipT6gkZBYjyOwGsp6BD5XlZAuJgupfG/GHoA==} dependencies: - keyborg: 2.4.1 - tslib: 2.6.1 + keyborg: 2.6.0 + tslib: 2.7.0 dev: false + /tapable@2.2.1: + resolution: {integrity: sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==} + engines: {node: '>=6'} + dev: true + /test-exclude@6.0.0: resolution: {integrity: sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==} engines: {node: '>=8'} @@ -6403,10 +7903,6 @@ packages: resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} dev: true - /through@2.3.8: - resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==} - dev: true - /tmpl@1.0.5: resolution: {integrity: sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==} dev: true @@ -6423,8 +7919,8 @@ packages: is-number: 7.0.0 dev: true - /tough-cookie@4.1.3: - resolution: {integrity: sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==} + /tough-cookie@4.1.4: + resolution: {integrity: sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==} engines: {node: '>=6'} dependencies: psl: 1.9.0 @@ -6444,21 +7940,22 @@ packages: punycode: 2.3.1 dev: true - /ts-api-utils@1.0.3(typescript@5.4.5): - resolution: {integrity: sha512-wNMeqtMz5NtwpT/UZGY5alT+VoKdSsOOP/kqHFcUW1P/VRhH2wJ48+DN2WwUliNbQ976ETwDL0Ifd2VVvgonvg==} - engines: {node: '>=16.13.0'} + /ts-api-utils@1.3.0(typescript@5.4.5): + resolution: {integrity: sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==} + engines: {node: '>=16'} peerDependencies: typescript: '>=4.2.0' dependencies: typescript: 5.4.5 dev: true - /ts-jest@29.1.0(@babel/core@7.23.7)(jest@29.4.0)(typescript@5.4.5): - resolution: {integrity: sha512-ZhNr7Z4PcYa+JjMl62ir+zPiNJfXJN6E8hSLnaUKhOgqcn8vb3e537cpkd0FuAfRK3sR1LSqM1MOhliXNgOFPA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + /ts-jest@29.2.5(@babel/core@7.25.2)(babel-jest@29.7.0)(jest@29.7.0)(typescript@5.4.5): + resolution: {integrity: sha512-KD8zB2aAZrcKIdGk4OwpJggeLcH1FgrICqDSROWqlnJXGCXK4Mn6FcdK2B6670Xr73lHMG1kHw8R87A0ecZ+vA==} + engines: {node: ^14.15.0 || ^16.10.0 || ^18.0.0 || >=20.0.0} hasBin: true peerDependencies: '@babel/core': '>=7.0.0-beta.0 <8' + '@jest/transform': ^29.0.0 '@jest/types': ^29.0.0 babel-jest: ^29.0.0 esbuild: '*' @@ -6467,6 +7964,8 @@ packages: peerDependenciesMeta: '@babel/core': optional: true + '@jest/transform': + optional: true '@jest/types': optional: true babel-jest: @@ -6474,15 +7973,17 @@ packages: esbuild: optional: true dependencies: - '@babel/core': 7.23.7 + '@babel/core': 7.25.2 + babel-jest: 29.7.0(@babel/core@7.25.2) bs-logger: 0.2.6 + ejs: 3.1.10 fast-json-stable-stringify: 2.1.0 - jest: 29.4.0(@types/node@14.17.4) + jest: 29.7.0(@types/node@18.19.53) jest-util: 29.7.0 json5: 2.2.3 lodash.memoize: 4.1.2 make-error: 1.3.6 - semver: 7.5.4 + semver: 7.6.3 typescript: 5.4.5 yargs-parser: 21.1.1 dev: true @@ -6496,22 +7997,8 @@ packages: strip-bom: 3.0.0 dev: true - /tslib@1.14.1: - resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==} - dev: true - - /tslib@2.6.1: - resolution: {integrity: sha512-t0hLfiEKfMUoqhG+U1oid7Pva4bbDPHYfJNiB7BiIjRkj1pyC++4N3huJfqY6aRH6VTB0rvtzQwjM4K6qpfOig==} - - /tsutils@3.21.0(typescript@5.4.5): - resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==} - engines: {node: '>= 6'} - peerDependencies: - typescript: '>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta' - dependencies: - tslib: 1.14.1 - typescript: 5.4.5 - dev: true + /tslib@2.7.0: + resolution: {integrity: sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==} /type-check@0.4.0: resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} @@ -6540,42 +8027,48 @@ packages: engines: {node: '>=8'} dev: true - /typed-array-buffer@1.0.0: - resolution: {integrity: sha512-Y8KTSIglk9OZEr8zywiIHG/kmQ7KWyjseXs1CbSo8vC42w7hg2HgYTxSWwP0+is7bWDc1H+Fo026CpHFwm8tkw==} + /typed-array-buffer@1.0.2: + resolution: {integrity: sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==} engines: {node: '>= 0.4'} dependencies: - call-bind: 1.0.5 - get-intrinsic: 1.2.2 - is-typed-array: 1.1.12 + call-bind: 1.0.7 + es-errors: 1.3.0 + is-typed-array: 1.1.13 dev: true - /typed-array-byte-length@1.0.0: - resolution: {integrity: sha512-Or/+kvLxNpeQ9DtSydonMxCx+9ZXOswtwJn17SNLvhptaXYDJvkFFP5zbfU/uLmvnBJlI4yrnXRxpdWH/M5tNA==} + /typed-array-byte-length@1.0.1: + resolution: {integrity: sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw==} engines: {node: '>= 0.4'} dependencies: - call-bind: 1.0.5 + call-bind: 1.0.7 for-each: 0.3.3 - has-proto: 1.0.1 - is-typed-array: 1.1.12 + gopd: 1.0.1 + has-proto: 1.0.3 + is-typed-array: 1.1.13 dev: true - /typed-array-byte-offset@1.0.0: - resolution: {integrity: sha512-RD97prjEt9EL8YgAgpOkf3O4IF9lhJFr9g0htQkm0rchFp/Vx7LW5Q8fSXXub7BXAODyUQohRMyOc3faCPd0hg==} + /typed-array-byte-offset@1.0.2: + resolution: {integrity: sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA==} engines: {node: '>= 0.4'} dependencies: - available-typed-arrays: 1.0.5 - call-bind: 1.0.5 + available-typed-arrays: 1.0.7 + call-bind: 1.0.7 for-each: 0.3.3 - has-proto: 1.0.1 - is-typed-array: 1.1.12 + gopd: 1.0.1 + has-proto: 1.0.3 + is-typed-array: 1.1.13 dev: true - /typed-array-length@1.0.4: - resolution: {integrity: sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==} + /typed-array-length@1.0.6: + resolution: {integrity: sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g==} + engines: {node: '>= 0.4'} dependencies: - call-bind: 1.0.5 + call-bind: 1.0.7 for-each: 0.3.3 - is-typed-array: 1.1.12 + gopd: 1.0.1 + has-proto: 1.0.3 + is-typed-array: 1.1.13 + possible-typed-array-names: 1.0.0 dev: true /typedarray-to-buffer@3.1.5: @@ -6593,26 +8086,53 @@ packages: /unbox-primitive@1.0.2: resolution: {integrity: sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==} dependencies: - call-bind: 1.0.5 + call-bind: 1.0.7 has-bigints: 1.0.2 has-symbols: 1.0.3 which-boxed-primitive: 1.0.2 dev: true + /undici-types@5.26.5: + resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} + dev: true + + /unicode-canonical-property-names-ecmascript@2.0.1: + resolution: {integrity: sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg==} + engines: {node: '>=4'} + dev: true + + /unicode-match-property-ecmascript@2.0.0: + resolution: {integrity: sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==} + engines: {node: '>=4'} + dependencies: + unicode-canonical-property-names-ecmascript: 2.0.1 + unicode-property-aliases-ecmascript: 2.1.0 + dev: true + + /unicode-match-property-value-ecmascript@2.2.0: + resolution: {integrity: sha512-4IehN3V/+kkr5YeSSDDQG8QLqO26XpL2XP3GQtqwlT/QYSECAwFztxVHjlbh0+gjJ3XmNLS0zDsbgs9jWKExLg==} + engines: {node: '>=4'} + dev: true + + /unicode-property-aliases-ecmascript@2.1.0: + resolution: {integrity: sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==} + engines: {node: '>=4'} + dev: true + /universalify@0.2.0: resolution: {integrity: sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==} engines: {node: '>= 4.0.0'} dev: true - /update-browserslist-db@1.0.13(browserslist@4.22.2): - resolution: {integrity: sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==} + /update-browserslist-db@1.1.0(browserslist@4.24.0): + resolution: {integrity: sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ==} hasBin: true peerDependencies: browserslist: '>= 4.21.0' dependencies: - browserslist: 4.22.2 - escalade: 3.1.1 - picocolors: 1.0.0 + browserslist: 4.24.0 + escalade: 3.2.0 + picocolors: 1.1.0 dev: true /uri-js@4.4.1: @@ -6628,7 +8148,7 @@ packages: requires-port: 1.0.0 dev: true - /use-disposable@1.0.2(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.2.0)(react@18.2.0): + /use-disposable@1.0.2(@types/react-dom@18.3.0)(@types/react@18.3.9)(react-dom@18.3.1)(react@18.3.1): resolution: {integrity: sha512-UMaXVlV77dWOu4GqAFNjRzHzowYKUKbJBQfCexvahrYeIz4OkUYUjna4Tjjdf92NH8Nm8J7wEfFRgTIwYjO5jg==} peerDependencies: '@types/react': '>=16.8.0 <19.0.0' @@ -6636,10 +8156,18 @@ packages: react: '>=16.8.0 <19.0.0' react-dom: '>=16.8.0 <19.0.0' dependencies: - '@types/react': 18.0.0 - '@types/react-dom': 18.0.0 - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) + '@types/react': 18.3.9 + '@types/react-dom': 18.3.0 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + dev: false + + /use-sync-external-store@1.2.2(react@18.3.1): + resolution: {integrity: sha512-PElTlVMwpblvbNqQ82d2n6RjStvdSoNe9FG28kNfz3WiXilJm4DdNkEzRhCZuIDwY8U08WVihhGR5iRqAwfDiw==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + dependencies: + react: 18.3.1 dev: false /uuid@8.3.2: @@ -6647,15 +8175,11 @@ packages: hasBin: true dev: true - /v8-compile-cache@2.4.0: - resolution: {integrity: sha512-ocyWc3bAHBB/guyqJQVI5o4BZkPhznPYUG2ea80Gond/BgNWpap8TOmLSeeQG7bnh2KMISxskdADG59j7zruhw==} - dev: true - - /v8-to-istanbul@9.2.0: - resolution: {integrity: sha512-/EH/sDgxU2eGxajKdwLCDmQ4FWq+kpi3uCmBGpw1xJtnAxEjlD8j8PEiGWpCIMIs3ciNAgH0d3TTJiUkYzyZjA==} + /v8-to-istanbul@9.3.0: + resolution: {integrity: sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==} engines: {node: '>=10.12.0'} dependencies: - '@jridgewell/trace-mapping': 0.3.22 + '@jridgewell/trace-mapping': 0.3.25 '@types/istanbul-lib-coverage': 2.0.6 convert-source-map: 2.0.0 dev: true @@ -6723,28 +8247,47 @@ packages: is-symbol: 1.0.4 dev: true - /which-collection@1.0.1: - resolution: {integrity: sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A==} + /which-builtin-type@1.1.4: + resolution: {integrity: sha512-bppkmBSsHFmIMSl8BO9TbsyzsvGjVoppt8xUiGzwiu/bhDCGxnpOKCxgqj6GuyHE0mINMDecBFPlOm2hzY084w==} + engines: {node: '>= 0.4'} + dependencies: + function.prototype.name: 1.1.6 + has-tostringtag: 1.0.2 + is-async-function: 2.0.0 + is-date-object: 1.0.5 + is-finalizationregistry: 1.0.2 + is-generator-function: 1.0.10 + is-regex: 1.1.4 + is-weakref: 1.0.2 + isarray: 2.0.5 + which-boxed-primitive: 1.0.2 + which-collection: 1.0.2 + which-typed-array: 1.1.15 + dev: true + + /which-collection@1.0.2: + resolution: {integrity: sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==} + engines: {node: '>= 0.4'} dependencies: - is-map: 2.0.2 - is-set: 2.0.2 - is-weakmap: 2.0.1 - is-weakset: 2.0.2 + is-map: 2.0.3 + is-set: 2.0.3 + is-weakmap: 2.0.2 + is-weakset: 2.0.3 dev: true /which-module@2.0.1: resolution: {integrity: sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==} dev: true - /which-typed-array@1.1.13: - resolution: {integrity: sha512-P5Nra0qjSncduVPEAr7xhoF5guty49ArDTwzJ/yNuPIbZppyRxFQsRCWrocxIY+CnMVG+qfbU2FmDKyvSGClow==} + /which-typed-array@1.1.15: + resolution: {integrity: sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==} engines: {node: '>= 0.4'} dependencies: - available-typed-arrays: 1.0.5 - call-bind: 1.0.5 + available-typed-arrays: 1.0.7 + call-bind: 1.0.7 for-each: 0.3.3 gopd: 1.0.1 - has-tostringtag: 1.0.0 + has-tostringtag: 1.0.2 dev: true /which@2.0.2: @@ -6755,8 +8298,9 @@ packages: isexe: 2.0.0 dev: true - /workerpool@6.2.1: - resolution: {integrity: sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==} + /word-wrap@1.2.5: + resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} + engines: {node: '>=0.10.0'} dev: true /wrap-ansi@6.2.0: @@ -6777,6 +8321,24 @@ packages: strip-ansi: 6.0.1 dev: true + /wrap-ansi@8.1.0: + resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} + engines: {node: '>=12'} + dependencies: + ansi-styles: 6.2.1 + string-width: 5.1.2 + strip-ansi: 7.1.0 + dev: true + + /wrap-ansi@9.0.0: + resolution: {integrity: sha512-G8ura3S+3Z2G+mkgNRq8dqaFZAuxfsxpBB8OCTGRTCtp+l/v9nbFNmCUP1BZMts3G1142MsZfn6eeUKrr4PD1Q==} + engines: {node: '>=18'} + dependencies: + ansi-styles: 6.2.1 + string-width: 7.2.0 + strip-ansi: 7.1.0 + dev: true + /wrappy@1.0.2: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} dev: true @@ -6798,8 +8360,8 @@ packages: signal-exit: 3.0.7 dev: true - /ws@8.16.0: - resolution: {integrity: sha512-HS0c//TP7Ina87TfiPUz1rQzMhHrl/SG2guqRcTOIUYD2q8uhUdNHZYJUaQ8aTGPzCh+c6oawMKW35nFl1dxyQ==} + /ws@8.18.0: + resolution: {integrity: sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==} engines: {node: '>=10.0.0'} peerDependencies: bufferutil: ^4.0.1 @@ -6837,13 +8399,10 @@ packages: resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} dev: true - /yallist@4.0.0: - resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} - dev: true - - /yaml@1.10.2: - resolution: {integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==} - engines: {node: '>= 6'} + /yaml@2.5.1: + resolution: {integrity: sha512-bLQOjaX/ADgQ20isPJRvF0iRUHIxVhYvr53Of7wGcWlO2jvtUlH5m87DsmulFVxRpNLOnI4tB6p/oh8D7kpn9Q==} + engines: {node: '>= 14'} + hasBin: true dev: true /yargs-parser@18.1.3: @@ -6854,26 +8413,11 @@ packages: decamelize: 1.2.0 dev: true - /yargs-parser@20.2.4: - resolution: {integrity: sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==} - engines: {node: '>=10'} - dev: true - /yargs-parser@21.1.1: resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} engines: {node: '>=12'} dev: true - /yargs-unparser@2.0.0: - resolution: {integrity: sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==} - engines: {node: '>=10'} - dependencies: - camelcase: 6.3.0 - decamelize: 4.0.0 - flat: 5.0.2 - is-plain-obj: 2.1.0 - dev: true - /yargs@15.4.1: resolution: {integrity: sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==} engines: {node: '>=8'} @@ -6891,25 +8435,12 @@ packages: yargs-parser: 18.1.3 dev: true - /yargs@16.2.0: - resolution: {integrity: sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==} - engines: {node: '>=10'} - dependencies: - cliui: 7.0.4 - escalade: 3.1.1 - get-caller-file: 2.0.5 - require-directory: 2.1.1 - string-width: 4.2.3 - y18n: 5.0.8 - yargs-parser: 20.2.4 - dev: true - /yargs@17.7.2: resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} engines: {node: '>=12'} dependencies: cliui: 8.0.1 - escalade: 3.1.1 + escalade: 3.2.0 get-caller-file: 2.0.5 require-directory: 2.1.1 string-width: 4.2.3 diff --git a/packages/sdk-react/src/index.ts b/packages/sdk-react/src/index.ts index 56630ed1fb..c2816d82c1 100644 --- a/packages/sdk-react/src/index.ts +++ b/packages/sdk-react/src/index.ts @@ -3,8 +3,7 @@ export { useTeams } from "./useTeams"; export { useData } from "./useData"; -export { useTeamsFx, TeamsFxContext } from "./useTeamsFx"; export { useTeamsUserCredential, TeamsContextWithCredential } from "./useTeamsUserCredential"; -export { useGraph, useGraphWithCredential } from "./useGraph"; +export { useGraphWithCredential } from "./useGraph"; export { BaseDashboard } from "./BaseDashboard"; export { BaseWidget, IWidgetClassNames } from "./BaseWidget"; diff --git a/packages/sdk-react/src/useData.ts b/packages/sdk-react/src/useData.ts index ac5ac37f22..661cbf85c5 100644 --- a/packages/sdk-react/src/useData.ts +++ b/packages/sdk-react/src/useData.ts @@ -54,7 +54,7 @@ const createReducer = */ export function useData( fetchDataAsync: () => Promise, - options?: { autoLoad: boolean } + options?: { autoLoad: boolean }, ): Data { const auto = options?.autoLoad ?? true; const [{ data, loading, error }, dispatch] = useReducer(createReducer(), { diff --git a/packages/sdk-react/src/useGraph.ts b/packages/sdk-react/src/useGraph.ts index beb887e42f..3b6362c7ef 100644 --- a/packages/sdk-react/src/useGraph.ts +++ b/packages/sdk-react/src/useGraph.ts @@ -3,8 +3,6 @@ import { Data, useData } from "./useData"; import { - TeamsFx, - createMicrosoftGraphClient, ErrorWithCode, TeamsUserCredential, TeamsUserCredentialAuthConfig, @@ -13,65 +11,11 @@ import { Client, GraphError } from "@microsoft/microsoft-graph-client"; import { TokenCredentialAuthenticationProvider } from "@microsoft/microsoft-graph-client/authProviders/azureTokenCredentials"; import { useState } from "react"; -type GraphOption = { - scope?: string[]; - teamsfx?: TeamsFx; -}; - type GraphOptionWithCredential = { scope?: string[]; credential?: TeamsUserCredential; }; -/** - * Helper function to call Microsoft Graph API with authentication. - * @deprecated Please use {@link useGraphWithCredential} instead. - * - * @param fetchGraphDataAsync - async function of how to call Graph API and fetch data. - * @param options - teamsfx instance and OAuth resource scope. - * @returns data, loading status, error and reload function - * - * @public - */ -export function useGraph( - fetchGraphDataAsync: (graph: Client, teamsfx: TeamsFx, scope: string[]) => Promise, - options?: GraphOption -): Data { - const { scope, teamsfx } = { scope: ["User.Read"], teamsfx: new TeamsFx(), ...options }; - const [needConsent, setNeedConsent] = useState(false); - const { data, error, loading, reload } = useData(async () => { - if (needConsent) { - try { - await teamsfx.login(scope); - setNeedConsent(false); - // Important: tokens are stored in sessionStorage, read more here: https://aka.ms/teamsfx-session-storage-notice - } catch (err: unknown) { - if (err instanceof ErrorWithCode && err.message?.includes("CancelledByUser")) { - const helpLink = "https://aka.ms/teamsfx-auth-code-flow"; - err.message += - '\nIf you see "AADSTS50011: The reply URL specified in the request does not match the reply URLs configured for the application" ' + - "in the popup window, you may be using unmatched version for TeamsFx SDK (version >= 0.5.0) and Teams Toolkit (version < 3.3.0) or " + - `cli (version < 0.11.0). Please refer to the help link for how to fix the issue: ${helpLink}`; - } - throw err; - } - } - try { - const graph = createMicrosoftGraphClient(teamsfx, scope); - const graphData = await fetchGraphDataAsync(graph, teamsfx, scope); - return graphData; - } catch (err: unknown) { - if (err instanceof GraphError && err.code?.includes("UiRequiredError")) { - // Silently fail for user didn't consent error - setNeedConsent(true); - } else { - throw err; - } - } - }); - return { data, error, loading, reload }; -} - /** * Helper function to call Microsoft Graph API with authentication. * @@ -85,9 +29,9 @@ export function useGraphWithCredential( fetchGraphDataAsync: ( graph: Client, credential: TeamsUserCredential, - scope: string[] + scope: string[], ) => Promise, - options?: GraphOptionWithCredential + options?: GraphOptionWithCredential, ): Data { let credential: TeamsUserCredential; if (!options?.credential) { diff --git a/packages/sdk-react/src/useTeams.ts b/packages/sdk-react/src/useTeams.ts index 26a64c0bc3..f0604016f0 100644 --- a/packages/sdk-react/src/useTeams.ts +++ b/packages/sdk-react/src/useTeams.ts @@ -41,7 +41,7 @@ export function useTeams(options?: { }, { setTheme: (theme: string | undefined) => void; - } + }, ] { const [loading, setLoading] = useState(undefined); const [inTeams, setInTeams] = useState(undefined); @@ -49,7 +49,7 @@ export function useTeams(options?: { const [theme, setTheme] = useState(teamsLightTheme); const [themeString, setThemeString] = useState("default"); const [initialTheme] = useState( - options && options.initialTheme ? options.initialTheme : getTheme() + options && options.initialTheme ? options.initialTheme : getTheme(), ); const [context, setContext] = useState(undefined); const themeChangeHandler = (theme: string | undefined) => { diff --git a/packages/sdk-react/src/useTeamsFx.ts b/packages/sdk-react/src/useTeamsFx.ts deleted file mode 100644 index b938287382..0000000000 --- a/packages/sdk-react/src/useTeamsFx.ts +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. - -import { LogLevel, setLogLevel, setLogFunction, TeamsFx, IdentityType } from "@microsoft/teamsfx"; -import { useTeams } from "./useTeams"; -import { Theme } from "@fluentui/react-components"; -import { useData } from "./useData"; - -export type TeamsFxContext = { - /** - * Instance of TeamsFx. - */ - teamsfx?: TeamsFx; - /** - * Status of data loading. - */ - loading: boolean; - /** - * Error information. - */ - error: unknown; - /** - * Indicates that current environment is in Teams - */ - inTeams?: boolean; - /** - * Teams theme. - */ - theme: Theme; - /** - * Teams theme string. - */ - themeString: string; - /** - * Teams context object. - */ - // eslint-disable-next-line @typescript-eslint/no-explicit-any - context?: any; -}; - -/** - * Initialize TeamsFx SDK with customized configuration. - * - * @param teamsfxConfig - custom configuration to override default ones. - * @returns TeamsFxContext object - * - * @public - */ -export function useTeamsFx(teamsfxConfig?: Record): TeamsFxContext { - const [result] = useTeams({}); - const { data, error, loading } = useData(async () => { - if (process.env.NODE_ENV === "development") { - setLogLevel(LogLevel.Verbose); - setLogFunction((level: LogLevel, message: string) => { - console.log(message); - }); - } - return new TeamsFx(IdentityType.User, teamsfxConfig); - }); - return { teamsfx: data, error, loading, ...result }; -} diff --git a/packages/sdk-react/src/useTeamsUserCredential.ts b/packages/sdk-react/src/useTeamsUserCredential.ts index d10edf894b..73b980d37b 100644 --- a/packages/sdk-react/src/useTeamsUserCredential.ts +++ b/packages/sdk-react/src/useTeamsUserCredential.ts @@ -53,7 +53,7 @@ export type TeamsContextWithCredential = { * @public */ export function useTeamsUserCredential( - authConfig: TeamsUserCredentialAuthConfig + authConfig: TeamsUserCredentialAuthConfig, ): TeamsContextWithCredential { const [result] = useTeams({}); const { data, error, loading } = useData(() => { diff --git a/packages/sdk-react/test/BaseDashboard.test.tsx b/packages/sdk-react/test/BaseDashboard.test.tsx index 143d1b8e2a..a6964b68e1 100644 --- a/packages/sdk-react/test/BaseDashboard.test.tsx +++ b/packages/sdk-react/test/BaseDashboard.test.tsx @@ -1,12 +1,13 @@ import React from "react"; import { render, screen } from "@testing-library/react"; - import { BaseDashboard } from "../src"; + class ResizeObserver { observe() {} unobserve() {} disconnect() {} } + describe("BaseDashboard", () => { window.ResizeObserver = ResizeObserver; it("render", () => { diff --git a/packages/sdk-react/test/BaseWidget.test.tsx b/packages/sdk-react/test/BaseWidget.test.tsx index 33aae3803b..c8d6174a4e 100644 --- a/packages/sdk-react/test/BaseWidget.test.tsx +++ b/packages/sdk-react/test/BaseWidget.test.tsx @@ -1,7 +1,5 @@ import React from "react"; - import { render, screen } from "@testing-library/react"; - import { BaseWidget } from "../src"; test("BaseWidget", () => { diff --git a/packages/sdk-react/test/index.test.ts b/packages/sdk-react/test/index.test.ts index de2b8a4d59..9c7192d2f2 100644 --- a/packages/sdk-react/test/index.test.ts +++ b/packages/sdk-react/test/index.test.ts @@ -12,16 +12,16 @@ describe("index", () => { expect(sdkReact.useTeams).toBeDefined(); }); - it("Should export useTeamsFx", () => { - expect(sdkReact.useTeamsFx).toBeDefined(); + it("Should export useTeamsUserCredential", () => { + expect(sdkReact.useTeamsUserCredential).toBeDefined(); }); it("Should export useData", () => { expect(sdkReact.useData).toBeDefined(); }); - it("Should export useGraph", () => { - expect(sdkReact.useGraph).toBeDefined(); + it("Should export useGraphWithCredential", () => { + expect(sdkReact.useGraphWithCredential).toBeDefined(); }); it("Should export BaseDashboard", () => { diff --git a/packages/sdk-react/test/useData.test.ts b/packages/sdk-react/test/useData.test.ts index a7d602ee53..bd6ca59b32 100644 --- a/packages/sdk-react/test/useData.test.ts +++ b/packages/sdk-react/test/useData.test.ts @@ -13,7 +13,7 @@ describe("useData() hook tests", () => { const { result } = renderHook(() => useData(() => { return Promise.resolve("data"); - }) + }), ); expect(result.current.reload).toBeDefined(); expect(result.current.data).toBe(undefined); @@ -26,7 +26,7 @@ describe("useData() hook tests", () => { expect(result.current.error).toBe(undefined); expect(result.current.loading).toBe(false); }, - { interval: 1 } + { interval: 1 }, ); }); @@ -34,7 +34,7 @@ describe("useData() hook tests", () => { const { result } = renderHook(() => useData(() => { return Promise.reject("test error"); - }) + }), ); expect(result.current.reload).toBeDefined(); expect(result.current.data).toBe(undefined); @@ -47,7 +47,7 @@ describe("useData() hook tests", () => { expect(result.current.error).toBe("test error"); expect(result.current.loading).toBe(false); }, - { interval: 1 } + { interval: 1 }, ); }); }); diff --git a/packages/sdk-react/test/useGraph.test.ts b/packages/sdk-react/test/useGraph.test.ts index 87ad1e50d5..71d7e897bf 100644 --- a/packages/sdk-react/test/useGraph.test.ts +++ b/packages/sdk-react/test/useGraph.test.ts @@ -7,185 +7,91 @@ import { renderHook, act, waitFor } from "@testing-library/react"; import { Client, GraphError } from "@microsoft/microsoft-graph-client"; -import { useGraph, useGraphWithCredential } from "../src/useGraph"; -import { TeamsFx, ErrorWithCode, ErrorCode } from "@microsoft/teamsfx"; +import { useGraphWithCredential } from "../src/useGraph"; +import { ErrorWithCode, ErrorCode, UserInfo } from "@microsoft/teamsfx"; import * as teamsfxlib from "@microsoft/teamsfx"; +import "isomorphic-fetch"; -require("isomorphic-fetch"); - -describe("useGraph() hook tests", () => { - let spyTeamsFxLogin: jest.SpyInstance; - - beforeEach(() => { - spyTeamsFxLogin = jest.spyOn(TeamsFx.prototype, "login"); - }); +describe("useGraphWithCredential() hook tests", () => { + beforeEach(() => {}); afterEach(() => { jest.resetAllMocks(); jest.clearAllMocks(); }); - it("call function after initialized", async () => { - let authenticatedGraph: Client | undefined; - let graphScope: string[] | undefined; - const { result } = renderHook(() => - useGraph((graph: Client, teamsfx: TeamsFx, scope: string[]) => { - authenticatedGraph = graph; - graphScope = scope; - return Promise.resolve("graph data"); - }) - ); - expect(result.current.reload).toBeDefined(); - expect(result.current.data).toBe(undefined); - expect(result.current.error).toBe(undefined); - expect(result.current.loading).toBe(true); - - await waitFor( - () => { - expect(result.current.data).toBe("graph data"); - expect(result.current.error).toBe(undefined); - expect(result.current.loading).toBe(false); - }, - { interval: 1 } - ); - - expect((authenticatedGraph as any).config.authProvider.credentialOrTeamsFx).toBeInstanceOf( - TeamsFx - ); - expect(graphScope && graphScope[0]).toBe("User.Read"); - }); - - it("call login() automatically when user has not consented", async () => { - let authenticatedGraph: Client | undefined; + it("call function after initialized without options", async () => { + jest + .spyOn(teamsfxlib, "TeamsUserCredential") + .mockImplementation((): teamsfxlib.TeamsUserCredential => { + return { + async login(): Promise {}, + async getToken(): Promise { + return null; + }, + async getUserInfo(): Promise { + return {} as UserInfo; + }, + }; + }); let graphScope: string[] | undefined; - let callTime = 0; - spyTeamsFxLogin.mockImplementation(() => { - return Promise.resolve(); - }); const { result } = renderHook(() => - useGraph((graph: Client, teamsfx: TeamsFx, scope: string[]) => { - authenticatedGraph = graph; - graphScope = scope; - if (callTime === 0) { - callTime++; - const error = new GraphError(); - error.code = ErrorCode.UiRequiredError; - return Promise.reject(error); - } else { + useGraphWithCredential( + (graph: Client, credential: teamsfxlib.TeamsUserCredential, scope: string[]) => { + graphScope = scope; return Promise.resolve("graph data"); - } - }) + }, + ), ); + expect(result.current.reload).toBeDefined(); expect(result.current.data).toBe(undefined); expect(result.current.error).toBe(undefined); expect(result.current.loading).toBe(true); - - await waitFor( - () => { - expect(result.current.data).toBe(undefined); - expect(result.current.error).toBe(undefined); - expect(result.current.loading).toBe(false); - }, - { interval: 1 } - ); - - expect((authenticatedGraph as any).config.authProvider.credentialOrTeamsFx).toBeInstanceOf( - TeamsFx - ); - expect(graphScope && graphScope[0]).toBe("User.Read"); - - act(() => result.current.reload()); await waitFor( () => { expect(result.current.data).toBe("graph data"); - }, - { interval: 1 } - ); - }); - - it("shows error message when user cancels consent dialog", async () => { - let authenticatedGraph: Client | undefined; - let graphScope: string[] | undefined; - const { result } = renderHook(() => - useGraph((graph: Client, teamsfx: TeamsFx, scope: string[]) => { - authenticatedGraph = graph; - graphScope = scope; - const error = new GraphError(); - error.code = ErrorCode.UiRequiredError; - return Promise.reject(error); - }) - ); - spyTeamsFxLogin.mockImplementation(() => { - throw new ErrorWithCode("CancelledByUser"); - }); - expect(result.current.reload).toBeDefined; - expect(result.current.data).toBe(undefined); - expect(result.current.error).toBe(undefined); - expect(result.current.loading).toBe(true); - - await waitFor( - () => { - expect(result.current.data).toBe(undefined); expect(result.current.error).toBe(undefined); expect(result.current.loading).toBe(false); + expect(graphScope && graphScope[0]).toBe("User.Read"); }, - { interval: 1 } - ); - - expect((authenticatedGraph as any).config.authProvider.credentialOrTeamsFx).toBeInstanceOf( - TeamsFx - ); - expect(graphScope && graphScope[0]).toBe("User.Read"); - - act(() => result.current.reload()); - await waitFor( - () => { - expect(result.current.data).toBe(undefined); - expect(result.current.error).toBeDefined; - expect((result.current.error as ErrorWithCode).message).toBe( - "CancelledByUser" + - '\nIf you see "AADSTS50011: The reply URL specified in the request does not match the reply URLs configured for the application" ' + - "in the popup window, you may be using unmatched version for TeamsFx SDK (version >= 0.5.0) and Teams Toolkit (version < 3.3.0) or " + - `cli (version < 0.11.0). Please refer to the help link for how to fix the issue: https://aka.ms/teamsfx-auth-code-flow` - ); - }, - { interval: 1 } + { interval: 1 }, ); }); -}); - -describe("useGraphWithCredential() hook tests", () => { - beforeEach(() => {}); - afterEach(() => { - jest.resetAllMocks(); - jest.clearAllMocks(); - }); - - it("call function after initialized", async () => { + it("call function after initialized with options", async () => { jest .spyOn(teamsfxlib, "TeamsUserCredential") - .mockImplementation( - (authConfig: teamsfxlib.AuthenticationConfiguration): teamsfxlib.TeamsUserCredential => { - return { - async login(): Promise {}, - async getToken(): Promise {}, - async getUserInfo(): Promise {}, - }; - } - ); + .mockImplementation((): teamsfxlib.TeamsUserCredential => { + return { + async login(): Promise {}, + async getToken(): Promise { + return null; + }, + async getUserInfo(): Promise { + return { displayName: "testUser" } as UserInfo; + }, + }; + }); - let authenticatedGraph: Client | undefined; + const teamsUserCredential = new teamsfxlib.TeamsUserCredential({ + clientId: "clientId", + initiateLoginEndpoint: "initiateLoginEndpoint", + }); let graphScope: string[] | undefined; + let fetchedCredential: teamsfxlib.TeamsUserCredential | undefined; const { result } = renderHook(() => useGraphWithCredential( (graph: Client, credential: teamsfxlib.TeamsUserCredential, scope: string[]) => { - authenticatedGraph = graph; graphScope = scope; - return Promise.resolve("graph data"); - } - ) + fetchedCredential = credential; + return Promise.resolve(fetchedCredential.getUserInfo()); + }, + { + scope: ["User.Read.All"], + credential: teamsUserCredential, + }, + ), ); expect(result.current.reload).toBeDefined(); @@ -194,12 +100,12 @@ describe("useGraphWithCredential() hook tests", () => { expect(result.current.loading).toBe(true); await waitFor( () => { - expect(result.current.data).toBe("graph data"); + expect(result.current.data).toStrictEqual({ displayName: "testUser" }); expect(result.current.error).toBe(undefined); expect(result.current.loading).toBe(false); - expect(graphScope && graphScope[0]).toBe("User.Read"); + expect(graphScope && graphScope[0]).toBe("User.Read.All"); }, - { interval: 1 } + { interval: 1 }, ); }); @@ -208,19 +114,21 @@ describe("useGraphWithCredential() hook tests", () => { .spyOn(teamsfxlib, "TeamsUserCredential") .mockImplementation((): teamsfxlib.TeamsUserCredential => { return { - async login(): Promise {}, - async getToken(): Promise {}, - async getUserInfo(): Promise {}, + async login(): Promise {}, + async getToken(): Promise { + return null; + }, + async getUserInfo(): Promise { + return {} as UserInfo; + }, }; }); - let authenticatedGraph: Client | undefined; let graphScope: string[] | undefined; let callTime = 0; const { result } = renderHook(() => useGraphWithCredential( (graph: Client, credential: teamsfxlib.TeamsUserCredential, scope: string[]) => { - authenticatedGraph = graph; graphScope = scope; if (callTime === 0) { callTime++; @@ -230,8 +138,8 @@ describe("useGraphWithCredential() hook tests", () => { } else { return Promise.resolve("graph data"); } - } - ) + }, + ), ); expect(result.current.reload).toBeDefined(); expect(result.current.data).toBe(undefined); @@ -245,7 +153,7 @@ describe("useGraphWithCredential() hook tests", () => { expect(result.current.loading).toBe(false); expect(graphScope && graphScope[0]).toBe("User.Read"); }, - { interval: 1 } + { interval: 1 }, ); act(() => result.current.reload()); @@ -253,7 +161,7 @@ describe("useGraphWithCredential() hook tests", () => { () => { expect(result.current.data).toBe("graph data"); }, - { interval: 1 } + { interval: 1 }, ); }); @@ -262,28 +170,30 @@ describe("useGraphWithCredential() hook tests", () => { .spyOn(teamsfxlib, "TeamsUserCredential") .mockImplementation((): teamsfxlib.TeamsUserCredential => { return { - async login(): Promise { + async login(): Promise { throw new ErrorWithCode("CancelledByUser"); }, - async getToken(): Promise {}, - async getUserInfo(): Promise {}, + async getToken(): Promise { + return null; + }, + async getUserInfo(): Promise { + return {} as UserInfo; + }, }; }); - let authenticatedGraph: Client | undefined; let graphScope: string[] | undefined; const { result } = renderHook(() => useGraphWithCredential( (graph: Client, credential: teamsfxlib.TeamsUserCredential, scope: string[]) => { - authenticatedGraph = graph; graphScope = scope; const error = new GraphError(); error.code = ErrorCode.UiRequiredError; return Promise.reject(error); - } - ) + }, + ), ); - expect(result.current.reload).toBeDefined; + expect(result.current.reload).toBeDefined(); expect(result.current.data).toBe(undefined); expect(result.current.error).toBe(undefined); expect(result.current.loading).toBe(true); @@ -296,22 +206,65 @@ describe("useGraphWithCredential() hook tests", () => { expect(graphScope && graphScope[0]).toBe("User.Read"); }, - { interval: 1 } + { interval: 1 }, ); act(() => result.current.reload()); await waitFor( () => { expect(result.current.data).toBe(undefined); - expect(result.current.error).toBeDefined; + expect(result.current.error).toBeDefined(); expect((result.current.error as ErrorWithCode).message).toBe( "CancelledByUser" + '\nIf you see "AADSTS50011: The reply URL specified in the request does not match the reply URLs configured for the application" ' + "in the popup window, you may be using unmatched version for TeamsFx SDK (version >= 0.5.0) and Teams Toolkit (version < 3.3.0) or " + - `cli (version < 0.11.0). Please refer to the help link for how to fix the issue: https://aka.ms/teamsfx-auth-code-flow` + `cli (version < 0.11.0). Please refer to the help link for how to fix the issue: https://aka.ms/teamsfx-auth-code-flow`, ); }, - { interval: 1 } + { interval: 1 }, + ); + }); + + it("throws unknown error", async () => { + jest + .spyOn(teamsfxlib, "TeamsUserCredential") + .mockImplementation((): teamsfxlib.TeamsUserCredential => { + return { + async login(): Promise { + throw new ErrorWithCode("CancelledByUser"); + }, + async getToken(): Promise { + return null; + }, + async getUserInfo(): Promise { + return {} as UserInfo; + }, + }; + }); + let graphScope: string[] | undefined; + const { result } = renderHook(() => + useGraphWithCredential( + (graph: Client, credential: teamsfxlib.TeamsUserCredential, scope: string[]) => { + graphScope = scope; + const error = new Error("unknown error"); + return Promise.reject(error); + }, + ), + ); + + expect(result.current.reload).toBeDefined(); + expect(result.current.data).toBe(undefined); + expect(result.current.error).toBe(undefined); + expect(result.current.loading).toBe(true); + + await waitFor( + () => { + expect(result.current.data).toBe(undefined); + expect(result.current.error).toStrictEqual(new Error("unknown error")); + expect(result.current.loading).toBe(false); + expect(graphScope && graphScope[0]).toBe("User.Read"); + }, + { interval: 1 }, ); }); }); diff --git a/packages/sdk-react/test/useTeamsFx.test.ts b/packages/sdk-react/test/useTeamsFx.test.ts deleted file mode 100644 index 66c827aa9b..0000000000 --- a/packages/sdk-react/test/useTeamsFx.test.ts +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. - -/** - * @jest-environment jsdom - */ - -import { renderHook, waitFor } from "@testing-library/react"; -import * as useTeams from "../src/useTeams"; -import * as useData from "../src/useData"; -import { useTeamsFx } from "../src/useTeamsFx"; -import { teamsLightTheme } from "@fluentui/react-components"; -import { TeamsFx } from "@microsoft/teamsfx"; - -describe("useTeamsFx() hook tests", () => { - let spyUseTeams: jest.SpyInstance; - let spyUseData: jest.SpyInstance; - - beforeEach(() => { - spyUseTeams = jest.spyOn(useTeams, "useTeams"); - spyUseTeams.mockImplementation(() => { - return [ - { inTeams: true, theme: teamsLightTheme, themeString: "default" }, - { setTheme: (undefined) => {} }, - ]; - }); - spyUseData = jest.spyOn(useData, "useData"); - }); - - afterEach(() => { - jest.resetAllMocks(); - jest.clearAllMocks(); - }); - - it("returns default teamsfx instance", async () => { - const { result } = renderHook(() => useTeamsFx({})); - expect(result.current.teamsfx).toBeUndefined(); - expect(result.current.error).toBeUndefined(); - expect(result.current.loading).toBe(true); - expect(result.current.inTeams).toBe(true); - expect(result.current.themeString).toBe("default"); - - await waitFor( - () => { - expect(result.current.teamsfx).toBeInstanceOf(TeamsFx); - expect(result.current.error).toBeUndefined(); - expect(result.current.loading).toBe(false); - expect(result.current.inTeams).toBe(true); - expect(result.current.themeString).toBe("default"); - }, - { interval: 1 } - ); - }); - - it("returns useData() error", async () => { - spyUseData.mockImplementation(() => { - return { error: "useData error", loading: false }; - }); - const { result } = renderHook(() => useTeamsFx({})); - expect(result.current.teamsfx).toBeUndefined; - expect(result.current.error).toBe("useData error"); - expect(result.current.loading).toBe(false); - expect(result.current.inTeams).toBe(true); - expect(result.current.themeString).toBe("default"); - }); -}); diff --git a/packages/sdk-react/test/useTeamsUserCredential.test.ts b/packages/sdk-react/test/useTeamsUserCredential.test.ts index 6e214ffbea..e65ef6b7c5 100644 --- a/packages/sdk-react/test/useTeamsUserCredential.test.ts +++ b/packages/sdk-react/test/useTeamsUserCredential.test.ts @@ -33,9 +33,13 @@ describe("useTeamsUserCredential() hook tests", () => { jest.spyOn(teamsfxlib, "TeamsUserCredential").mockImplementation((): TeamsUserCredential => { return { - async login(): Promise {}, - async getToken(): Promise {}, - async getUserInfo(): Promise {}, + async login(): Promise {}, + async getToken(): Promise { + return null; + }, + async getUserInfo(): Promise { + return {} as teamsfxlib.UserInfo; + }, }; }); }); @@ -60,7 +64,7 @@ describe("useTeamsUserCredential() hook tests", () => { expect(result.current.inTeams).toBe(true); expect(result.current.themeString).toBe("default"); }, - { interval: 1 } + { interval: 1 }, ); }); @@ -69,7 +73,7 @@ describe("useTeamsUserCredential() hook tests", () => { return { error: "useData error", loading: false }; }); const { result } = renderHook(() => useTeamsUserCredential(authConfig)); - expect(result.current.teamsUserCredential).toBeUndefined; + expect(result.current.teamsUserCredential).toBe(undefined); expect(result.current.error).toBe("useData error"); expect(result.current.loading).toBe(false); expect(result.current.inTeams).toBe(true); diff --git a/packages/sdk-react/tsconfig.es.json b/packages/sdk-react/tsconfig.es.json index 251d0f64f7..f3588546b1 100644 --- a/packages/sdk-react/tsconfig.es.json +++ b/packages/sdk-react/tsconfig.es.json @@ -5,4 +5,4 @@ "module": "esnext", "outDir": "./build/esm" } -} \ No newline at end of file +} diff --git a/packages/sdk-react/tsconfig.eslint.json b/packages/sdk-react/tsconfig.eslint.json index 283b4b75f5..09719abb50 100644 --- a/packages/sdk-react/tsconfig.eslint.json +++ b/packages/sdk-react/tsconfig.eslint.json @@ -1,14 +1,14 @@ { - // extend your base config to share compilerOptions, etc - "extends": "./tsconfig.json", - "compilerOptions": { - // ensure that nobody can accidentally use this config for a build - "noEmit": true - }, - "include": [ - // whatever paths you intend to lint - "src", - "tests" - ], - "exclude": [] -} \ No newline at end of file + // extend your base config to share compilerOptions, etc + "extends": "./tsconfig.json", + "compilerOptions": { + // ensure that nobody can accidentally use this config for a build + "noEmit": true + }, + "include": [ + // whatever paths you intend to lint + "src", + "tests" + ], + "exclude": [] +} diff --git a/packages/sdk-react/tsconfig.json b/packages/sdk-react/tsconfig.json index 93859104a9..6cdebf8d5f 100644 --- a/packages/sdk-react/tsconfig.json +++ b/packages/sdk-react/tsconfig.json @@ -2,11 +2,11 @@ "compilerOptions": { "jsx": "react", "outDir": "build/cjs", - "target": "es5" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017','ES2018' or 'ESNEXT'. */, + "target": "ES5" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017','ES2018' or 'ESNEXT'. */, "module": "commonjs" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */, "declaration": true /* Generates corresponding '.d.ts' file. */, "esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */, - "allowSyntheticDefaultImports":true, + "allowSyntheticDefaultImports": true, "sourceMap": false, "skipLibCheck": true, "forceConsistentCasingInFileNames": true, @@ -16,8 +16,8 @@ "declarationMap": true, "moduleResolution": "node", "resolveJsonModule": true, - "typeRoots": ["node_modules/@types"] + "typeRoots": ["./node_modules/@types"], }, "include": ["src"], - "exclude": ["node_modules", "**/test/*"], + "exclude": ["node_modules", "**/test/*"] } diff --git a/packages/sdk/package.json b/packages/sdk/package.json index 25495a1854..1d246a9b3b 100644 --- a/packages/sdk/package.json +++ b/packages/sdk/package.json @@ -1,6 +1,6 @@ { "name": "@microsoft/teamsfx", - "version": "2.3.3", + "version": "3.0.0-rc", "description": "Microsoft Teams Framework for Node.js and browser.", "main": "dist/index.node.cjs.js", "browser": "dist/index.esm2017.js", @@ -10,7 +10,7 @@ "scripts": { "prebuild": "npm run clean", "build": "rollup -c && api-extractor run --local", - "clean": "rimraf dist dist-* temp types *.tgz *.log", + "clean": "rimraf --glob dist dist-* temp types *.tgz *.log", "check-format": "prettier --list-different \"src/**/*.ts\" \"test/**/*.ts\" \"*.{js,json}\" \"config/*.js\"", "format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\" \"*.{js,json}\" \"config/*.js\"", "lint:staged": "lint-staged", @@ -45,49 +45,48 @@ "homepage": "https://github.com/OfficeDev/TeamsFx", "sideEffects": false, "dependencies": { - "@azure/identity": "^2.0.1", - "@azure/msal-browser": "^3.0.2", - "@azure/msal-node": "^1.14.6", "@microsoft/microsoft-graph-client": "^3.0.7", - "adaptive-expressions": "^4.22.3", + "@azure/identity": "^4.4.1", + "@azure/msal-browser": "^3.24.0", + "@azure/msal-node": "^2.14.0", "adaptivecards-templating": "^2.3.1", + "adaptive-expressions": "^4.23.1", "axios": "^1.7.5", - "botbuilder": "^4.22.3", - "botbuilder-dialogs": "^4.22.3", - "botframework-connector": "^4.22.3", - "botframework-schema": "^4.22.3", - "jwt-decode": "^3.1.2", - "tedious": "^14.3.0", - "uuid": "^8.3.2" + "botbuilder": "^4.23.1", + "botbuilder-dialogs": "^4.23.1", + "botframework-connector": "^4.23.1", + "botframework-schema": "^4.23.1", + "jwt-decode": "^4.0.0", + "uuid": "^10.0.0" }, "peerDependencies": { - "@microsoft/teams-js": "^2.19.0" + "@microsoft/teams-js": "^2.19.0", + "botbuilder": "^4.23.1" }, "devDependencies": { - "@azure/core-auth": "^1.4.0", - "@azure/msal-common": "^14.0.2", - "@istanbuljs/nyc-config-typescript": "^1.0.1", - "@microsoft/api-extractor": "^7.19.4", - "@rollup/plugin-json": "^4.1.0", + "@azure/core-auth": "^1.8.0", + "@azure/msal-common": "^14.15.0", + "@istanbuljs/nyc-config-typescript": "^1.0.2", + "@microsoft/api-extractor": "^7.47.9", + "@rollup/plugin-json": "^6.1.0", "@sinonjs/commons": "^3.0.0", "@sinonjs/fake-timers": "^11.1.0", "@sinonjs/samsam": "^8.0.0", "@types/chai": "^4.2.22", "@types/chai-as-promised": "^7.1.4", "@types/jsonwebtoken": "^9.0.2", - "@types/mocha": "^9.0.0", - "@types/mochawesome": "^6.2.1", - "@types/node": "^16.11.7", + "@types/mocha": "^10.0.8", + "@types/mochawesome": "^6.2.4", + "@types/node": "^18.0.0", "@types/sinon": "^10.0.6", - "@types/tedious": "^4.0.5", "@types/url-join": "^4.0.1", "@types/uuid": "^8.3.1", - "@typescript-eslint/eslint-plugin": "^5.0.0", - "@typescript-eslint/parser": "^4.13.0", + "@typescript-eslint/eslint-plugin": "^5.13.0", + "@typescript-eslint/parser": "^6.5.0", "adm-zip": "^0.5.9", "assertion-error": "^2.0.0", "axios-mock-adapter": "^1.20.0", - "botbuilder-core": "^4.22.3", + "botbuilder-core": "^4.23.1", "chai": "^4.3.4", "chai-as-promised": "^7.1.1", "check-error": "^2.0.0", @@ -95,7 +94,7 @@ "diff": "^5.1.0", "dotenv": "^10.0.0", "escape-html": "^1.0.3", - "eslint": "^8.1.0", + "eslint": "^8.15.0", "eslint-plugin-header": "^3.1.1", "eslint-plugin-import": "^2.25.2", "eslint-plugin-no-secrets": "^0.8.9", @@ -104,30 +103,30 @@ "got": "^11.8.5", "isomorphic-fetch": "^3.0.0", "jwt-builder": "^1.1.0", - "karma": "^6.3.8", - "karma-chrome-launcher": "^3.1.0", + "karma": "^6.4.4", + "karma-chrome-launcher": "^3.2.0", "karma-cli": "^2.0.0", - "karma-coverage": "^2.0.0", + "karma-coverage": "^2.2.1", "karma-env-preprocessor": "^0.1.1", "karma-junit-reporter": "^2.0.1", "karma-mocha": "^2.0.1", "karma-mocha-reporter": "^2.2.5", - "karma-sourcemap-loader": "^0.3.8", - "karma-webpack": "^5.0.0", + "karma-sourcemap-loader": "^0.4.0", + "karma-webpack": "^5.0.1", "lint-staged": "^11.2.6", "lodash.get": "^4.4.2", - "mocha": "^9.2.0", + "mocha": "^10.7.3", "mocha-multi-reporters": "^1.5.1", - "mochawesome": "^7.0.1", + "mochawesome": "^7.1.3", "mocked-env": "^1.3.5", - "nise": "^5.1.4", + "nise": "^5.1.9", "nyc": "^15.1.0", "pathval": "^2.0.0", "prettier": "^2.4.1", - "puppeteer": "^13.1.3", - "rimraf": "^3.0.2", - "rollup": "^2.41.0", - "rollup-plugin-typescript2": "0.31.1", + "puppeteer": "^23.4.1", + "rimraf": "^6.0.1", + "rollup": "^2.79.2", + "rollup-plugin-typescript2": "0.36.0", "sinon": "^12.0.1", "source-map-loader": "^3.0.0", "supports-color": "^9.4.0", @@ -136,7 +135,7 @@ "ts-node": "^10.4.0", "tslib": "^2.3.1", "type-detect": "^4.0.8", - "typescript": "^4.4.4", + "typescript": "~5.4.2", "url-join": "^4.0.1", "webpack": "^5.62.1", "yargs": "^17.2.1" diff --git a/packages/sdk/pnpm-lock.yaml b/packages/sdk/pnpm-lock.yaml index ba8b54455a..b71eada853 100644 --- a/packages/sdk/pnpm-lock.yaml +++ b/packages/sdk/pnpm-lock.yaml @@ -6,67 +6,64 @@ settings: dependencies: '@azure/identity': - specifier: ^2.0.1 - version: 2.0.1(supports-color@9.4.0) + specifier: ^4.4.1 + version: 4.4.1(supports-color@9.4.0) '@azure/msal-browser': - specifier: ^3.0.2 - version: 3.0.2 + specifier: ^3.24.0 + version: 3.24.0 '@azure/msal-node': - specifier: ^1.14.6 - version: 1.14.6 + specifier: ^2.14.0 + version: 2.14.0 '@microsoft/microsoft-graph-client': specifier: ^3.0.7 - version: 3.0.7(@azure/identity@2.0.1)(@azure/msal-browser@3.0.2) + version: 3.0.7(@azure/identity@4.4.1)(@azure/msal-browser@3.24.0) '@microsoft/teams-js': specifier: ^2.19.0 version: 2.19.0(supports-color@9.4.0) adaptive-expressions: - specifier: ^4.22.3 - version: 4.22.3 + specifier: ^4.23.1 + version: 4.23.1 adaptivecards-templating: specifier: ^2.3.1 - version: 2.3.1(adaptive-expressions@4.22.3) + version: 2.3.1(adaptive-expressions@4.23.1) axios: specifier: ^1.7.5 version: 1.7.5 botbuilder: - specifier: ^4.22.3 - version: 4.22.3(supports-color@9.4.0) + specifier: ^4.23.1 + version: 4.23.1(supports-color@9.4.0) botbuilder-dialogs: - specifier: ^4.22.3 - version: 4.22.3(supports-color@9.4.0) + specifier: ^4.23.1 + version: 4.23.1(supports-color@9.4.0) botframework-connector: - specifier: ^4.22.3 - version: 4.22.3(supports-color@9.4.0) + specifier: ^4.23.1 + version: 4.23.1(supports-color@9.4.0) botframework-schema: - specifier: ^4.22.3 - version: 4.22.3 + specifier: ^4.23.1 + version: 4.23.1 jwt-decode: - specifier: ^3.1.2 - version: 3.1.2 - tedious: - specifier: ^14.3.0 - version: 14.3.0(supports-color@9.4.0) + specifier: ^4.0.0 + version: 4.0.0 uuid: - specifier: ^8.3.2 - version: 8.3.2 + specifier: ^10.0.0 + version: 10.0.0 devDependencies: '@azure/core-auth': - specifier: ^1.4.0 - version: 1.4.0 + specifier: ^1.8.0 + version: 1.8.0 '@azure/msal-common': - specifier: ^14.0.2 - version: 14.0.2 + specifier: ^14.15.0 + version: 14.15.0 '@istanbuljs/nyc-config-typescript': - specifier: ^1.0.1 - version: 1.0.1(nyc@15.1.0)(source-map-support@0.5.21)(ts-node@10.4.0) + specifier: ^1.0.2 + version: 1.0.2(nyc@15.1.0) '@microsoft/api-extractor': - specifier: ^7.19.4 - version: 7.19.4 + specifier: ^7.47.9 + version: 7.47.9(@types/node@18.19.50) '@rollup/plugin-json': - specifier: ^4.1.0 - version: 4.1.0(rollup@2.41.0) + specifier: ^6.1.0 + version: 6.1.0(rollup@2.79.2) '@sinonjs/commons': specifier: ^3.0.0 version: 3.0.0 @@ -86,20 +83,17 @@ devDependencies: specifier: ^9.0.2 version: 9.0.2 '@types/mocha': - specifier: ^9.0.0 - version: 9.0.0 + specifier: ^10.0.8 + version: 10.0.8 '@types/mochawesome': - specifier: ^6.2.1 - version: 6.2.1 + specifier: ^6.2.4 + version: 6.2.4 '@types/node': - specifier: ^16.11.7 - version: 16.11.7 + specifier: ^18.0.0 + version: 18.19.50 '@types/sinon': specifier: ^10.0.6 version: 10.0.6 - '@types/tedious': - specifier: ^4.0.5 - version: 4.0.5 '@types/url-join': specifier: ^4.0.1 version: 4.0.1 @@ -107,11 +101,11 @@ devDependencies: specifier: ^8.3.1 version: 8.3.1 '@typescript-eslint/eslint-plugin': - specifier: ^5.0.0 - version: 5.0.0(@typescript-eslint/parser@4.13.0)(eslint@8.1.0)(supports-color@9.4.0)(typescript@4.4.4) + specifier: ^5.13.0 + version: 5.62.0(@typescript-eslint/parser@6.21.0)(eslint@8.57.1)(supports-color@9.4.0)(typescript@5.4.2) '@typescript-eslint/parser': - specifier: ^4.13.0 - version: 4.13.0(eslint@8.1.0)(supports-color@9.4.0)(typescript@4.4.4) + specifier: ^6.5.0 + version: 6.21.0(eslint@8.57.1)(supports-color@9.4.0)(typescript@5.4.2) adm-zip: specifier: ^0.5.9 version: 0.5.9 @@ -122,8 +116,8 @@ devDependencies: specifier: ^1.20.0 version: 1.20.0(axios@1.7.5) botbuilder-core: - specifier: ^4.22.3 - version: 4.22.3(supports-color@9.4.0) + specifier: ^4.23.1 + version: 4.23.1(supports-color@9.4.0) chai: specifier: ^4.3.4 version: 4.3.4 @@ -146,20 +140,20 @@ devDependencies: specifier: ^1.0.3 version: 1.0.3 eslint: - specifier: ^8.1.0 - version: 8.1.0(supports-color@9.4.0) + specifier: ^8.15.0 + version: 8.57.1(supports-color@9.4.0) eslint-plugin-header: specifier: ^3.1.1 - version: 3.1.1(eslint@8.1.0) + version: 3.1.1(eslint@8.57.1) eslint-plugin-import: specifier: ^2.25.2 - version: 2.25.2(@typescript-eslint/parser@4.13.0)(eslint@8.1.0)(supports-color@9.4.0) + version: 2.25.2(@typescript-eslint/parser@6.21.0)(eslint@8.57.1)(supports-color@9.4.0) eslint-plugin-no-secrets: specifier: ^0.8.9 - version: 0.8.9(eslint@8.1.0) + version: 0.8.9(eslint@8.57.1) eslint-plugin-prettier: specifier: ^4.0.0 - version: 4.0.0(eslint@8.1.0)(prettier@2.4.1) + version: 4.0.0(eslint@8.57.1)(prettier@2.4.1) get-func-name: specifier: ^3.0.0 version: 3.0.0 @@ -173,35 +167,35 @@ devDependencies: specifier: ^1.1.0 version: 1.1.0 karma: - specifier: ^6.3.8 - version: 6.3.16(supports-color@9.4.0) + specifier: ^6.4.4 + version: 6.4.4(supports-color@9.4.0) karma-chrome-launcher: - specifier: ^3.1.0 - version: 3.1.0 + specifier: ^3.2.0 + version: 3.2.0 karma-cli: specifier: ^2.0.0 version: 2.0.0 karma-coverage: - specifier: ^2.0.0 - version: 2.0.0(supports-color@9.4.0) + specifier: ^2.2.1 + version: 2.2.1(supports-color@9.4.0) karma-env-preprocessor: specifier: ^0.1.1 version: 0.1.1 karma-junit-reporter: specifier: ^2.0.1 - version: 2.0.1(karma@6.3.16) + version: 2.0.1(karma@6.4.4) karma-mocha: specifier: ^2.0.1 version: 2.0.1 karma-mocha-reporter: specifier: ^2.2.5 - version: 2.2.5(karma@6.3.16) + version: 2.2.5(karma@6.4.4) karma-sourcemap-loader: - specifier: ^0.3.8 - version: 0.3.8 + specifier: ^0.4.0 + version: 0.4.0 karma-webpack: - specifier: ^5.0.0 - version: 5.0.0(webpack@5.76.0) + specifier: ^5.0.1 + version: 5.0.1(webpack@5.76.0) lint-staged: specifier: ^11.2.6 version: 11.2.6 @@ -209,20 +203,20 @@ devDependencies: specifier: ^4.4.2 version: 4.4.2 mocha: - specifier: ^9.2.0 - version: 9.2.0 + specifier: ^10.7.3 + version: 10.7.3 mocha-multi-reporters: specifier: ^1.5.1 - version: 1.5.1(mocha@9.2.0)(supports-color@9.4.0) + version: 1.5.1(mocha@10.7.3)(supports-color@9.4.0) mochawesome: - specifier: ^7.0.1 - version: 7.0.1(mocha@9.2.0) + specifier: ^7.1.3 + version: 7.1.3(mocha@10.7.3) mocked-env: specifier: ^1.3.5 version: 1.3.5(supports-color@9.4.0) nise: - specifier: ^5.1.4 - version: 5.1.4 + specifier: ^5.1.9 + version: 5.1.9 nyc: specifier: ^15.1.0 version: 15.1.0(supports-color@9.4.0) @@ -233,17 +227,17 @@ devDependencies: specifier: ^2.4.1 version: 2.4.1 puppeteer: - specifier: ^13.1.3 - version: 13.1.3(supports-color@9.4.0) + specifier: ^23.4.1 + version: 23.4.1(supports-color@9.4.0)(typescript@5.4.2) rimraf: - specifier: ^3.0.2 - version: 3.0.2 + specifier: ^6.0.1 + version: 6.0.1 rollup: - specifier: ^2.41.0 - version: 2.41.0 + specifier: ^2.79.2 + version: 2.79.2 rollup-plugin-typescript2: - specifier: 0.31.1 - version: 0.31.1(rollup@2.41.0)(typescript@4.4.4) + specifier: 0.36.0 + version: 0.36.0(rollup@2.79.2)(typescript@5.4.2) sinon: specifier: ^12.0.1 version: 12.0.1 @@ -258,10 +252,10 @@ devDependencies: version: 0.1.1 ts-loader: specifier: ^9.2.6 - version: 9.2.6(typescript@4.4.4)(webpack@5.76.0) + version: 9.2.6(typescript@5.4.2)(webpack@5.76.0) ts-node: specifier: ^10.4.0 - version: 10.4.0(@types/node@16.11.7)(typescript@4.4.4) + version: 10.4.0(@types/node@18.19.50)(typescript@5.4.2) tslib: specifier: ^2.3.1 version: 2.3.1 @@ -269,8 +263,8 @@ devDependencies: specifier: ^4.0.8 version: 4.0.8 typescript: - specifier: ^4.4.4 - version: 4.4.4 + specifier: ~5.4.2 + version: 5.4.2 url-join: specifier: ^4.0.1 version: 4.0.1 @@ -300,46 +294,43 @@ packages: resolution: {integrity: sha512-TrRLIoSQVzfAJX9H1JeFjzAoDGcoK1IYX1UImfceTZpsyYfWr09Ss1aHW1y5TrrR3iq6RZLBwJ3E24uwPhwahw==} engines: {node: '>=12.0.0'} dependencies: - tslib: 2.3.1 + tslib: 2.7.0 - /@azure/core-auth@1.4.0: - resolution: {integrity: sha512-HFrcTgmuSuukRf/EdPmqBrc5l6Q5Uu+2TbuhaKbgaCpP2TfAeiNaQPAadxO+CYBRHGUzIDteMAjFspFLDLnKVQ==} - engines: {node: '>=12.0.0'} + /@azure/abort-controller@2.1.2: + resolution: {integrity: sha512-nBrLsEWm4J2u5LpAPjxADTlq3trDgVZZXHNKabeXZtpq3d3AbN/KGO82R87rdDz5/lYB024rtEf10/q0urNgsA==} + engines: {node: '>=18.0.0'} dependencies: - '@azure/abort-controller': 1.1.0 - tslib: 2.3.1 + tslib: 2.7.0 - /@azure/core-client@1.7.3(supports-color@9.4.0): - resolution: {integrity: sha512-kleJ1iUTxcO32Y06dH9Pfi9K4U+Tlb111WXEnbt7R/ne+NLRwppZiTGJuTD5VVoxTMK5NTbEtm5t2vcdNCFe2g==} - engines: {node: '>=14.0.0'} + /@azure/core-auth@1.8.0: + resolution: {integrity: sha512-YvFMowkXzLbXNM11yZtVLhUCmuG0ex7JKOH366ipjmHBhL3vpDcPAeWF+jf0X+jVXwFqo3UhsWUq4kH0ZPdu/g==} + engines: {node: '>=18.0.0'} dependencies: - '@azure/abort-controller': 1.1.0 - '@azure/core-auth': 1.4.0 - '@azure/core-rest-pipeline': 1.13.0(supports-color@9.4.0) - '@azure/core-tracing': 1.0.1 + '@azure/abort-controller': 2.1.2 '@azure/core-util': 1.6.1 - '@azure/logger': 1.0.4 - tslib: 2.3.1 - transitivePeerDependencies: - - supports-color + tslib: 2.7.0 - /@azure/core-http-compat@1.3.0(supports-color@9.4.0): - resolution: {integrity: sha512-ZN9avruqbQ5TxopzG3ih3KRy52n8OAbitX3fnZT5go4hzu0J+KVPSzkL+Wt3hpJpdG8WIfg1sBD1tWkgUdEpBA==} - engines: {node: '>=12.0.0'} + /@azure/core-client@1.9.2(supports-color@9.4.0): + resolution: {integrity: sha512-kRdry/rav3fUKHl/aDLd/pDLcB+4pOFwPPTVEExuMyaI5r+JBbMWqRbCY1pn5BniDaU3lRxO9eaQ1AmSMehl/w==} + engines: {node: '>=18.0.0'} dependencies: - '@azure/abort-controller': 1.1.0 - '@azure/core-client': 1.7.3(supports-color@9.4.0) + '@azure/abort-controller': 2.1.2 + '@azure/core-auth': 1.8.0 '@azure/core-rest-pipeline': 1.13.0(supports-color@9.4.0) + '@azure/core-tracing': 1.0.1 + '@azure/core-util': 1.6.1 + '@azure/logger': 1.0.4 + tslib: 2.7.0 transitivePeerDependencies: - supports-color - dev: false /@azure/core-http@3.0.4: resolution: {integrity: sha512-Fok9VVhMdxAFOtqiiAtg74fL0UJkt0z3D+ouUUxcRLzZNBioPRAMJFVxiWoJljYpXsRi4GDQHzQHDc9AiYaIUQ==} engines: {node: '>=14.0.0'} + deprecated: This package is no longer supported. Please migrate to use @azure/core-rest-pipeline dependencies: '@azure/abort-controller': 1.1.0 - '@azure/core-auth': 1.4.0 + '@azure/core-auth': 1.8.0 '@azure/core-tracing': 1.0.0-preview.13 '@azure/core-util': 1.6.1 '@azure/logger': 1.0.4 @@ -348,42 +339,25 @@ packages: form-data: 4.0.0 node-fetch: 2.7.0 process: 0.11.10 - tslib: 2.3.1 + tslib: 2.7.0 tunnel: 0.0.6 uuid: 8.3.2 xml2js: 0.5.0 transitivePeerDependencies: - encoding - /@azure/core-lro@2.5.4: - resolution: {integrity: sha512-3GJiMVH7/10bulzOKGrrLeG/uCBH/9VtxqaMcB9lIqAeamI/xYQSHJL/KcsLDuH+yTjYpro/u6D/MuRe4dN70Q==} - engines: {node: '>=14.0.0'} - dependencies: - '@azure/abort-controller': 1.1.0 - '@azure/core-util': 1.6.1 - '@azure/logger': 1.0.4 - tslib: 2.3.1 - dev: false - - /@azure/core-paging@1.5.0: - resolution: {integrity: sha512-zqWdVIt+2Z+3wqxEOGzR5hXFZ8MGKK52x4vFLw8n58pR6ZfKRx3EXYTxTaYxYHc/PexPUTyimcTWFJbji9Z6Iw==} - engines: {node: '>=14.0.0'} - dependencies: - tslib: 2.3.1 - dev: false - /@azure/core-rest-pipeline@1.13.0(supports-color@9.4.0): resolution: {integrity: sha512-a62aP/wppgmnfIkJLfcB4ssPBcH94WzrzPVJ3tlJt050zX4lfmtnvy95D3igDo3f31StO+9BgPrzvkj4aOxnoA==} engines: {node: '>=18.0.0'} dependencies: '@azure/abort-controller': 1.1.0 - '@azure/core-auth': 1.4.0 + '@azure/core-auth': 1.8.0 '@azure/core-tracing': 1.0.1 '@azure/core-util': 1.6.1 '@azure/logger': 1.0.4 http-proxy-agent: 5.0.0(supports-color@9.4.0) https-proxy-agent: 5.0.1(supports-color@9.4.0) - tslib: 2.3.1 + tslib: 2.7.0 transitivePeerDependencies: - supports-color @@ -392,150 +366,63 @@ packages: engines: {node: '>=12.0.0'} dependencies: '@opentelemetry/api': 1.7.0 - tslib: 2.3.1 + tslib: 2.7.0 /@azure/core-tracing@1.0.1: resolution: {integrity: sha512-I5CGMoLtX+pI17ZdiFJZgxMJApsK6jjfm85hpgp3oazCdq5Wxgh4wMr7ge/TTWW1B5WBuvIOI1fMU/FrOAMKrw==} engines: {node: '>=12.0.0'} dependencies: - tslib: 2.3.1 + tslib: 2.7.0 /@azure/core-util@1.6.1: resolution: {integrity: sha512-h5taHeySlsV9qxuK64KZxy4iln1BtMYlNt5jbuEFN3UFSAd1EwKg/Gjl5a6tZ/W8t6li3xPnutOx7zbDyXnPmQ==} engines: {node: '>=16.0.0'} dependencies: '@azure/abort-controller': 1.1.0 - tslib: 2.3.1 - - /@azure/identity@2.0.1(supports-color@9.4.0): - resolution: {integrity: sha512-gdGGuLKlKIQaf2RefA84keoBfmWfiAntbW2SzcdKvwLSGzsio/qkyY3sYUpXRz/sqLDxguuimgZukp7TPgwIlg==} - engines: {node: '>=12.0.0'} - dependencies: - '@azure/abort-controller': 1.1.0 - '@azure/core-auth': 1.4.0 - '@azure/core-client': 1.7.3(supports-color@9.4.0) - '@azure/core-rest-pipeline': 1.13.0(supports-color@9.4.0) - '@azure/core-tracing': 1.0.0-preview.13 - '@azure/core-util': 1.6.1 - '@azure/logger': 1.0.4 - '@azure/msal-browser': 2.38.3 - '@azure/msal-common': 4.5.1(supports-color@9.4.0) - '@azure/msal-node': 1.14.6 - '@types/stoppable': 1.1.3 - events: 3.3.0 - jws: 4.0.0 - open: 8.4.2 - stoppable: 1.1.0 - tslib: 2.3.1 - uuid: 8.3.2 - transitivePeerDependencies: - - supports-color - dev: false + tslib: 2.7.0 - /@azure/identity@2.1.0(supports-color@9.4.0): - resolution: {integrity: sha512-BPDz1sK7Ul9t0l9YKLEa8PHqWU4iCfhGJ+ELJl6c8CP3TpJt2urNCbm0ZHsthmxRsYoMPbz2Dvzj30zXZVmAFw==} - engines: {node: '>=12.0.0'} + /@azure/identity@4.4.1(supports-color@9.4.0): + resolution: {integrity: sha512-DwnG4cKFEM7S3T+9u05NstXU/HN0dk45kPOinUyNKsn5VWwpXd9sbPKEg6kgJzGbm1lMuhx9o31PVbCtM5sfBA==} + engines: {node: '>=18.0.0'} dependencies: '@azure/abort-controller': 1.1.0 - '@azure/core-auth': 1.4.0 - '@azure/core-client': 1.7.3(supports-color@9.4.0) + '@azure/core-auth': 1.8.0 + '@azure/core-client': 1.9.2(supports-color@9.4.0) '@azure/core-rest-pipeline': 1.13.0(supports-color@9.4.0) '@azure/core-tracing': 1.0.1 '@azure/core-util': 1.6.1 '@azure/logger': 1.0.4 - '@azure/msal-browser': 2.38.3 - '@azure/msal-common': 7.6.0 - '@azure/msal-node': 1.18.4 + '@azure/msal-browser': 3.24.0 + '@azure/msal-node': 2.14.0 events: 3.3.0 jws: 4.0.0 open: 8.4.2 stoppable: 1.1.0 tslib: 2.3.1 - uuid: 8.3.2 - transitivePeerDependencies: - - supports-color - - /@azure/keyvault-keys@4.7.2(supports-color@9.4.0): - resolution: {integrity: sha512-VdIH6PjbQ3J5ntK+xeI8eOe1WsDxF9ndXw8BPR/9MZVnIj0vQNtNCS6gpR7EFQeGcs8XjzMfHm0AvKGErobqJQ==} - engines: {node: '>=14.0.0'} - dependencies: - '@azure/abort-controller': 1.1.0 - '@azure/core-auth': 1.4.0 - '@azure/core-client': 1.7.3(supports-color@9.4.0) - '@azure/core-http-compat': 1.3.0(supports-color@9.4.0) - '@azure/core-lro': 2.5.4 - '@azure/core-paging': 1.5.0 - '@azure/core-rest-pipeline': 1.13.0(supports-color@9.4.0) - '@azure/core-tracing': 1.0.1 - '@azure/core-util': 1.6.1 - '@azure/logger': 1.0.4 - tslib: 2.3.1 transitivePeerDependencies: - supports-color - dev: false /@azure/logger@1.0.4: resolution: {integrity: sha512-ustrPY8MryhloQj7OWGe+HrYx+aoiOxzbXTtgblbV3xwCqpzUK36phH3XNHQKj3EPonyFUuDTfR3qFhTEAuZEg==} engines: {node: '>=14.0.0'} dependencies: - tslib: 2.3.1 - - /@azure/msal-browser@2.38.3: - resolution: {integrity: sha512-2WuLFnWWPR1IdvhhysT18cBbkXx1z0YIchVss5AwVA95g7CU5CpT3d+5BcgVGNXDXbUU7/5p0xYHV99V5z8C/A==} - engines: {node: '>=0.8.0'} - deprecated: A newer major version of this library is available. Please upgrade to the latest available version. - dependencies: - '@azure/msal-common': 13.3.1 + tslib: 2.7.0 - /@azure/msal-browser@3.0.2: - resolution: {integrity: sha512-a2lIzWGV8EJhxVTHu2Vd5sRdK6DTisueq2HCXt49CQqc1hG/j9pK+ds+hJi+QLlZHPo3FPMwiTCHEA9sNgX3HA==} + /@azure/msal-browser@3.24.0: + resolution: {integrity: sha512-JGNV9hTYAa7lsum9IMIibn2kKczAojNihGo1hi7pG0kNrcKej530Fl6jxwM05A44/6I079CSn6WxYxbVhKUmWg==} engines: {node: '>=0.8.0'} dependencies: - '@azure/msal-common': 14.0.2 - dev: false - - /@azure/msal-common@13.3.1: - resolution: {integrity: sha512-Lrk1ozoAtaP/cp53May3v6HtcFSVxdFrg2Pa/1xu5oIvsIwhxW6zSPibKefCOVgd5osgykMi5jjcZHv8XkzZEQ==} - engines: {node: '>=0.8.0'} - - /@azure/msal-common@14.0.2: - resolution: {integrity: sha512-yvVP63oXe20JFzvooTVxiX9UorxcL8VFoVwEtKuGlQnEnNGzrOpQZ6lKa1lqwGqxMtwKpW7oAFQhbbskG5RbYA==} - engines: {node: '>=0.8.0'} - - /@azure/msal-common@4.5.1(supports-color@9.4.0): - resolution: {integrity: sha512-/i5dXM+QAtO+6atYd5oHGBAx48EGSISkXNXViheliOQe+SIFMDo3gSq3lL54W0suOSAsVPws3XnTaIHlla0PIQ==} - engines: {node: '>=0.8.0'} - dependencies: - debug: 4.3.4(supports-color@9.4.0) - transitivePeerDependencies: - - supports-color - dev: false + '@azure/msal-common': 14.15.0 - /@azure/msal-common@7.6.0: - resolution: {integrity: sha512-XqfbglUTVLdkHQ8F9UQJtKseRr3sSnr9ysboxtoswvaMVaEfvyLtMoHv9XdKUfOc0qKGzNgRFd9yRjIWVepl6Q==} + /@azure/msal-common@14.15.0: + resolution: {integrity: sha512-ImAQHxmpMneJ/4S8BRFhjt1MZ3bppmpRPYYNyzeQPeFN288YKbb8TmmISQEbtfkQ1BPASvYZU5doIZOPBAqENQ==} engines: {node: '>=0.8.0'} - /@azure/msal-common@9.1.1: - resolution: {integrity: sha512-we9xR8lvu47fF0h+J8KyXoRy9+G/fPzm3QEa2TrdR3jaVS3LKAyE2qyMuUkNdbVkvzl8Zr9f7l+IUSP22HeqXw==} - engines: {node: '>=0.8.0'} - dev: false - - /@azure/msal-node@1.14.6: - resolution: {integrity: sha512-em/qqFL5tLMxMPl9vormAs13OgZpmQoJbiQ/GlWr+BA77eCLoL+Ehr5xRHowYo+LFe5b+p+PJVkRvT+mLvOkwA==} - engines: {node: 10 || 12 || 14 || 16 || 18} - deprecated: A newer major version of this library is available. Please upgrade to the latest available version. - dependencies: - '@azure/msal-common': 9.1.1 - jsonwebtoken: 9.0.2 - uuid: 8.3.2 - dev: false - - /@azure/msal-node@1.18.4: - resolution: {integrity: sha512-Kc/dRvhZ9Q4+1FSfsTFDME/v6+R2Y1fuMty/TfwqE5p9GTPw08BPbKgeWinE8JRHRp+LemjQbUZsn4Q4l6Lszg==} - engines: {node: 10 || 12 || 14 || 16 || 18} - deprecated: A newer major version of this library is available. Please upgrade to the latest available version. + /@azure/msal-node@2.14.0: + resolution: {integrity: sha512-rrfzIpG3Q1rHjVYZmHAEDidWAZZ2cgkxlIcMQ8dHebRISaZ2KCV33Q8Vs+uaV6lxweROabNxKFlR2lIKagZqYg==} + engines: {node: '>=16'} dependencies: - '@azure/msal-common': 13.3.1 + '@azure/msal-common': 14.15.0 jsonwebtoken: 9.0.2 uuid: 8.3.2 @@ -567,7 +454,7 @@ packages: '@babel/traverse': 7.23.7(supports-color@9.4.0) '@babel/types': 7.23.6 convert-source-map: 2.0.0 - debug: 4.3.4(supports-color@9.4.0) + debug: 4.3.7(supports-color@9.4.0) gensync: 1.0.0-beta.2 json5: 2.2.3 semver: 6.3.1 @@ -694,8 +581,8 @@ packages: '@babel/types': 7.23.6 dev: true - /@babel/runtime@7.23.8: - resolution: {integrity: sha512-Y7KbAP984rn1VGMbGqKmBLio9V7y5Je9GvU4rQPCPinCyNfUcToxIXl06d59URp/F3LwinvODxab5N/G6qggkw==} + /@babel/runtime@7.25.7: + resolution: {integrity: sha512-FjoyLe754PMiYsFaN5C94ttGiOmBNYTf6pLr4xXHAT5uctHb092PBszndLDR5XA/jghQvn4n7JMHl7dmTgbm9w==} engines: {node: '>=6.9.0'} dependencies: regenerator-runtime: 0.14.1 @@ -722,7 +609,7 @@ packages: '@babel/helper-split-export-declaration': 7.22.6 '@babel/parser': 7.23.6 '@babel/types': 7.23.6 - debug: 4.3.4(supports-color@9.4.0) + debug: 4.3.7(supports-color@9.4.0) globals: 11.12.0 transitivePeerDependencies: - supports-color @@ -737,6 +624,11 @@ packages: to-fast-properties: 2.0.0 dev: true + /@colors/colors@1.5.0: + resolution: {integrity: sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==} + engines: {node: '>=0.1.90'} + dev: true + /@cspotcode/source-map-consumer@0.8.0: resolution: {integrity: sha512-41qniHzTU8yAGbCp04ohlmSrZf8bkf/iJsl3V0dRGsQN/5GFfx+LbCSsCpp2gqrqjTVg/K6O8ycoV35JIwAzAg==} engines: {node: '>= 12'} @@ -749,15 +641,30 @@ packages: '@cspotcode/source-map-consumer': 0.8.0 dev: true - /@eslint/eslintrc@1.4.1(supports-color@9.4.0): - resolution: {integrity: sha512-XXrH9Uarn0stsyldqDYq8r++mROmWRI1xKMXa640Bb//SY1+ECYX6VzT6Lcx5frD0V30XieqJ0oX9I2Xj5aoMA==} + /@eslint-community/eslint-utils@4.4.0(eslint@8.57.1): + resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 + dependencies: + eslint: 8.57.1(supports-color@9.4.0) + eslint-visitor-keys: 3.4.3 + dev: true + + /@eslint-community/regexpp@4.11.1: + resolution: {integrity: sha512-m4DVN9ZqskZoLU5GlWZadwDnYo3vAEydiUayB9widCl9ffWx2IvPnp6n3on5rJmziJSw9Bv+Z3ChDVdMwXCY8Q==} + engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} + dev: true + + /@eslint/eslintrc@2.1.4(supports-color@9.4.0): + resolution: {integrity: sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dependencies: ajv: 6.12.6 - debug: 4.3.4(supports-color@9.4.0) + debug: 4.3.7(supports-color@9.4.0) espree: 9.6.1 globals: 13.24.0 - ignore: 5.3.0 + ignore: 5.3.2 import-fresh: 3.3.0 js-yaml: 4.1.0 minimatch: 3.1.2 @@ -766,19 +673,43 @@ packages: - supports-color dev: true - /@humanwhocodes/config-array@0.6.0(supports-color@9.4.0): - resolution: {integrity: sha512-JQlEKbcgEUjBFhLIF4iqM7u/9lwgHRBcpHrmUNCALK0Q3amXN6lxdoXLnF0sm11E9VqTmBALR87IlUg1bZ8A9A==} + /@eslint/js@8.57.1: + resolution: {integrity: sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dev: true + + /@humanwhocodes/config-array@0.13.0(supports-color@9.4.0): + resolution: {integrity: sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==} engines: {node: '>=10.10.0'} + deprecated: Use @eslint/config-array instead dependencies: - '@humanwhocodes/object-schema': 1.2.1 - debug: 4.3.4(supports-color@9.4.0) + '@humanwhocodes/object-schema': 2.0.3 + debug: 4.3.7(supports-color@9.4.0) minimatch: 3.1.2 transitivePeerDependencies: - supports-color dev: true - /@humanwhocodes/object-schema@1.2.1: - resolution: {integrity: sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==} + /@humanwhocodes/module-importer@1.0.1: + resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} + engines: {node: '>=12.22'} + dev: true + + /@humanwhocodes/object-schema@2.0.3: + resolution: {integrity: sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==} + deprecated: Use @eslint/object-schema instead + dev: true + + /@isaacs/cliui@8.0.2: + resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} + engines: {node: '>=12'} + dependencies: + string-width: 5.1.2 + string-width-cjs: /string-width@4.2.3 + strip-ansi: 7.1.0 + strip-ansi-cjs: /strip-ansi@6.0.1 + wrap-ansi: 8.1.0 + wrap-ansi-cjs: /wrap-ansi@7.0.0 dev: true /@istanbuljs/load-nyc-config@1.1.0: @@ -792,18 +723,14 @@ packages: resolve-from: 5.0.0 dev: true - /@istanbuljs/nyc-config-typescript@1.0.1(nyc@15.1.0)(source-map-support@0.5.21)(ts-node@10.4.0): - resolution: {integrity: sha512-/gz6LgVpky205LuoOfwEZmnUtaSmdk0QIMcNFj9OvxhiMhPpKftMgZmGN7jNj7jR+lr8IB1Yks3QSSSNSxfoaQ==} + /@istanbuljs/nyc-config-typescript@1.0.2(nyc@15.1.0): + resolution: {integrity: sha512-iKGIyMoyJuFnJRSVTZ78POIRvNnwZaWIf8vG4ZS3rQq58MMDrqEX2nnzx0R28V2X8JvmKYiqY9FP2hlJsm8A0w==} engines: {node: '>=8'} peerDependencies: nyc: '>=15' - source-map-support: '*' - ts-node: '*' dependencies: '@istanbuljs/schema': 0.1.3 nyc: 15.1.0(supports-color@9.4.0) - source-map-support: 0.5.21 - ts-node: 10.4.0(@types/node@16.11.7)(typescript@4.4.4) dev: true /@istanbuljs/schema@0.1.3: @@ -848,37 +775,38 @@ packages: '@jridgewell/sourcemap-codec': 1.4.15 dev: true - /@js-joda/core@4.3.1: - resolution: {integrity: sha512-oeaetlodcqVsiZDxnEcqsbs+sXBkASxua0mXs5OXuPQXz3/wdPTMlxwfQ4z2HKcOik3S9voW3QJkp/KLWDhvRQ==} - dev: false - - /@microsoft/api-extractor-model@7.15.3: - resolution: {integrity: sha512-NkSjolmSI7NGvbdz0Y7kjQfdpD+j9E5CwXTxEyjDqxd10MI7GXV8DnAsQ57GFJcgHKgTjf2aUnYfMJ9w3aMicw==} + /@microsoft/api-extractor-model@7.29.8(@types/node@18.19.50): + resolution: {integrity: sha512-t3Z/xcO6TRbMcnKGVMs4uMzv/gd5j0NhMiJIGjD4cJMeFJ1Hf8wnLSx37vxlRlL0GWlGJhnFgxvnaL6JlS+73g==} dependencies: - '@microsoft/tsdoc': 0.13.2 - '@microsoft/tsdoc-config': 0.15.2 - '@rushstack/node-core-library': 3.45.0 + '@microsoft/tsdoc': 0.15.0 + '@microsoft/tsdoc-config': 0.17.0 + '@rushstack/node-core-library': 5.9.0(@types/node@18.19.50) + transitivePeerDependencies: + - '@types/node' dev: true - /@microsoft/api-extractor@7.19.4: - resolution: {integrity: sha512-iehC6YA3DGJvxTUaK7HUtQmP6hAQU07+Q/OR8TG4dVR6KpqCi9UPEVk8AgCvQkiK+6FbVEFQTx0qLuYk4EeuHg==} + /@microsoft/api-extractor@7.47.9(@types/node@18.19.50): + resolution: {integrity: sha512-TTq30M1rikVsO5wZVToQT/dGyJY7UXJmjiRtkHPLb74Prx3Etw8+bX7Bv7iLuby6ysb7fuu1NFWqma+csym8Jw==} hasBin: true dependencies: - '@microsoft/api-extractor-model': 7.15.3 - '@microsoft/tsdoc': 0.13.2 - '@microsoft/tsdoc-config': 0.15.2 - '@rushstack/node-core-library': 3.45.0 - '@rushstack/rig-package': 0.3.7 - '@rushstack/ts-command-line': 4.10.6 - colors: 1.2.5 + '@microsoft/api-extractor-model': 7.29.8(@types/node@18.19.50) + '@microsoft/tsdoc': 0.15.0 + '@microsoft/tsdoc-config': 0.17.0 + '@rushstack/node-core-library': 5.9.0(@types/node@18.19.50) + '@rushstack/rig-package': 0.5.3 + '@rushstack/terminal': 0.14.2(@types/node@18.19.50) + '@rushstack/ts-command-line': 4.22.8(@types/node@18.19.50) lodash: 4.17.21 - resolve: 1.17.0 - semver: 7.3.8 + minimatch: 3.0.4 + resolve: 1.22.8 + semver: 7.5.4 source-map: 0.6.1 - typescript: 4.5.5 + typescript: 5.4.2 + transitivePeerDependencies: + - '@types/node' dev: true - /@microsoft/microsoft-graph-client@3.0.7(@azure/identity@2.0.1)(@azure/msal-browser@3.0.2): + /@microsoft/microsoft-graph-client@3.0.7(@azure/identity@4.4.1)(@azure/msal-browser@3.24.0): resolution: {integrity: sha512-/AazAV/F+HK4LIywF9C+NYHcJo038zEnWkteilcxC1FM/uK/4NVGDKGrxx7nNq1ybspAroRKT4I1FHfxQzxkUw==} engines: {node: '>=12.0.0'} peerDependencies: @@ -896,10 +824,10 @@ packages: stream-browserify: optional: true dependencies: - '@azure/identity': 2.0.1(supports-color@9.4.0) - '@azure/msal-browser': 3.0.2 - '@babel/runtime': 7.23.8 - tslib: 2.3.1 + '@azure/identity': 4.4.1(supports-color@9.4.0) + '@azure/msal-browser': 3.24.0 + '@babel/runtime': 7.25.7 + tslib: 2.7.0 dev: false /@microsoft/recognizers-text-choice@1.1.4: @@ -910,8 +838,8 @@ packages: grapheme-splitter: 1.0.4 dev: false - /@microsoft/recognizers-text-data-types-timex-expression@1.3.0: - resolution: {integrity: sha512-REHUXmMUI1jL3b9v+aSdzKxLxRdejsfg9McYRxY3LW0Gu4UbwD7Q+K6mtSo40cwg8uh6fiV9GY8hDuKXHH6dVA==} + /@microsoft/recognizers-text-data-types-timex-expression@1.3.1: + resolution: {integrity: sha512-jarJIFIJZBqeofy3hh0vdQo1yOmTM+jCjj6/zmo9JunsQ6LO750eZHCg9eLptQhsvq321XCt5xdRNLCwU8YeNA==} engines: {node: '>=10.3.0'} dev: false @@ -995,17 +923,17 @@ packages: - supports-color dev: false - /@microsoft/tsdoc-config@0.15.2: - resolution: {integrity: sha512-mK19b2wJHSdNf8znXSMYVShAHktVr/ib0Ck2FA3lsVBSEhSI/TfXT7DJQkAYgcztTuwazGcg58ZjYdk0hTCVrA==} + /@microsoft/tsdoc-config@0.17.0: + resolution: {integrity: sha512-v/EYRXnCAIHxOHW+Plb6OWuUoMotxTN0GLatnpOb1xq0KuTNw/WI3pamJx/UbsoJP5k9MCw1QxvvhPcF9pH3Zg==} dependencies: - '@microsoft/tsdoc': 0.13.2 - ajv: 6.12.6 + '@microsoft/tsdoc': 0.15.0 + ajv: 8.12.0 jju: 1.4.0 - resolve: 1.19.0 + resolve: 1.22.8 dev: true - /@microsoft/tsdoc@0.13.2: - resolution: {integrity: sha512-WrHvO8PDL8wd8T2+zBGKrMwVL5IyzR3ryWUsl0PXgEV0QHup4mTLi0QcATefGI6Gx9Anu7vthPyyyLpY0EpiQg==} + /@microsoft/tsdoc@0.15.0: + resolution: {integrity: sha512-HZpPoABogPvjeJOdzCOSJsXeL/SMCBgBZMVC3X3d7YYp2gf31MfxhUoYUNwf1ERPJOnQc0wkFn9trqI6ZEdZuA==} dev: true /@nodelib/fs.scandir@2.1.5: @@ -1033,25 +961,34 @@ packages: resolution: {integrity: sha512-AdY5wvN0P2vXBi3b29hxZgSFvdhdxPB9+f0B6s//P9Q8nibRWeA3cHm8UmLpio9ABigkVHJ5NMPk+Mz8VCCyrw==} engines: {node: '>=8.0.0'} - /@rollup/plugin-json@4.1.0(rollup@2.41.0): - resolution: {integrity: sha512-yfLbTdNS6amI/2OpmbiBoW12vngr5NW2jCJVZSBEz+H5KfUJZ2M7sDjk0U6GOOdCWFVScShte29o9NezJ53TPw==} - peerDependencies: - rollup: ^1.20.0 || ^2.0.0 + /@puppeteer/browsers@2.4.0(supports-color@9.4.0): + resolution: {integrity: sha512-x8J1csfIygOwf6D6qUAZ0ASk3z63zPb7wkNeHRerCMh82qWKUrOgkuP005AJC8lDL6/evtXETGEJVcwykKT4/g==} + engines: {node: '>=18'} + hasBin: true dependencies: - '@rollup/pluginutils': 3.1.0(rollup@2.41.0) - rollup: 2.41.0 + debug: 4.3.7(supports-color@9.4.0) + extract-zip: 2.0.1(supports-color@9.4.0) + progress: 2.0.3 + proxy-agent: 6.4.0(supports-color@9.4.0) + semver: 7.6.3 + tar-fs: 3.0.6 + unbzip2-stream: 1.4.3 + yargs: 17.7.2 + transitivePeerDependencies: + - supports-color dev: true - /@rollup/pluginutils@3.1.0(rollup@2.41.0): - resolution: {integrity: sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==} - engines: {node: '>= 8.0.0'} + /@rollup/plugin-json@6.1.0(rollup@2.79.2): + resolution: {integrity: sha512-EGI2te5ENk1coGeADSIwZ7G2Q8CJS2sF120T7jLw4xFw9n7wIOXHo+kIYRAoVpJAN+kmqZSoO3Fp4JtoNF4ReA==} + engines: {node: '>=14.0.0'} peerDependencies: - rollup: ^1.20.0||^2.0.0 + rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true dependencies: - '@types/estree': 0.0.39 - estree-walker: 1.0.1 - picomatch: 2.3.1 - rollup: 2.41.0 + '@rollup/pluginutils': 5.1.2(rollup@2.79.2) + rollup: 2.79.2 dev: true /@rollup/pluginutils@4.2.1: @@ -1062,34 +999,69 @@ packages: picomatch: 2.3.1 dev: true - /@rushstack/node-core-library@3.45.0: - resolution: {integrity: sha512-YMuIJl19vQT1+g/OU9mLY6T5ZBT9uDlmeXExDQACpGuxTJW+LHNbk/lRX+eCApQI2eLBlaL4U68r3kZlqwbdmw==} + /@rollup/pluginutils@5.1.2(rollup@2.79.2): + resolution: {integrity: sha512-/FIdS3PyZ39bjZlwqFnWqCOVnW7o963LtKMwQOD0NhQqw22gSr2YY1afu3FxRip4ZCZNsD5jq6Aaz6QV3D/Njw==} + engines: {node: '>=14.0.0'} + peerDependencies: + rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + dependencies: + '@types/estree': 1.0.6 + estree-walker: 2.0.2 + picomatch: 2.3.1 + rollup: 2.79.2 + dev: true + + /@rushstack/node-core-library@5.9.0(@types/node@18.19.50): + resolution: {integrity: sha512-MMsshEWkTbXqxqFxD4gcIUWQOCeBChlGczdZbHfqmNZQFLHB3yWxDFSMHFUdu2/OB9NUk7Awn5qRL+rws4HQNg==} + peerDependencies: + '@types/node': '*' + peerDependenciesMeta: + '@types/node': + optional: true dependencies: - '@types/node': 12.20.24 - colors: 1.2.5 + '@types/node': 18.19.50 + ajv: 8.13.0 + ajv-draft-04: 1.0.0(ajv@8.13.0) + ajv-formats: 3.0.1(ajv@8.13.0) fs-extra: 7.0.1 import-lazy: 4.0.0 jju: 1.4.0 - resolve: 1.17.0 - semver: 7.3.8 - timsort: 0.3.0 - z-schema: 5.0.5 + resolve: 1.22.8 + semver: 7.5.4 dev: true - /@rushstack/rig-package@0.3.7: - resolution: {integrity: sha512-pzMsTSeTC8IiZ6EJLr53gGMvhT4oLWH+hxD7907cHyWuIUlEXFtu/2pK25vUQT13nKp5DJCWxXyYoGRk/h6rtA==} + /@rushstack/rig-package@0.5.3: + resolution: {integrity: sha512-olzSSjYrvCNxUFZowevC3uz8gvKr3WTpHQ7BkpjtRpA3wK+T0ybep/SRUMfr195gBzJm5gaXw0ZMgjIyHqJUow==} dependencies: - resolve: 1.17.0 + resolve: 1.22.8 strip-json-comments: 3.1.1 dev: true - /@rushstack/ts-command-line@4.10.6: - resolution: {integrity: sha512-Y3GkUag39sTIlukDg9mUp8MCHrrlJ27POrBNRQGc/uF+VVgX8M7zMzHch5zP6O1QVquWgD7Engdpn2piPYaS/g==} + /@rushstack/terminal@0.14.2(@types/node@18.19.50): + resolution: {integrity: sha512-2fC1wqu1VCExKC0/L+0noVcFQEXEnoBOtCIex1TOjBzEDWcw8KzJjjj7aTP6mLxepG0XIyn9OufeFb6SFsa+sg==} + peerDependencies: + '@types/node': '*' + peerDependenciesMeta: + '@types/node': + optional: true + dependencies: + '@rushstack/node-core-library': 5.9.0(@types/node@18.19.50) + '@types/node': 18.19.50 + supports-color: 8.1.1 + dev: true + + /@rushstack/ts-command-line@4.22.8(@types/node@18.19.50): + resolution: {integrity: sha512-XbFjOoV7qZHJnSuFUHv0pKaFA4ixyCuki+xMjsMfDwfvQjs5MYG0IK5COal3tRnG7KCDe2l/G+9LrzYE/RJhgg==} dependencies: + '@rushstack/terminal': 0.14.2(@types/node@18.19.50) '@types/argparse': 1.0.38 argparse: 1.0.10 - colors: 1.2.5 string-argv: 0.3.2 + transitivePeerDependencies: + - '@types/node' dev: true /@sindresorhus/is@4.6.0: @@ -1115,10 +1087,10 @@ packages: type-detect: 4.0.8 dev: true - /@sinonjs/fake-timers@10.3.0: - resolution: {integrity: sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==} + /@sinonjs/commons@3.0.1: + resolution: {integrity: sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==} dependencies: - '@sinonjs/commons': 3.0.0 + type-detect: 4.0.8 dev: true /@sinonjs/fake-timers@11.1.0: @@ -1127,6 +1099,12 @@ packages: '@sinonjs/commons': 3.0.0 dev: true + /@sinonjs/fake-timers@11.3.1: + resolution: {integrity: sha512-EVJO7nW5M/F5Tur0Rf2z/QoMo+1Ia963RiMtapiQrEWvY0iBUvADo8Beegwjpnle5BHkyHuoxSTW3jF43H1XRA==} + dependencies: + '@sinonjs/commons': 3.0.1 + dev: true + /@sinonjs/fake-timers@7.1.2: resolution: {integrity: sha512-iQADsW4LBMISqZ6Ci1dupJL9pprqwcVFTcOsEmQOEhW+KLCVn/Y4Jrvg2k19fIHCp+iFprriYPTdRcQR8NbUPg==} dependencies: @@ -1155,8 +1133,8 @@ packages: type-detect: 4.0.8 dev: true - /@sinonjs/text-encoding@0.7.2: - resolution: {integrity: sha512-sXXKG+uL9IrKqViTtao2Ws6dy0znu9sOaP1di/jKGW1M6VssO8vlpXCQcpZ+jisQ1tTFAC5Jo/EOzFbggBagFQ==} + /@sinonjs/text-encoding@0.7.3: + resolution: {integrity: sha512-DE427ROAphMQzU4ENbliGYrBSYPXF+TtLg9S8vzeA+OF4ZKzoDdzfL8sxuMUGS/lgRhM6j1URSk9ghf7Xo1tyA==} dev: true /@socket.io/component-emitter@3.1.0: @@ -1174,6 +1152,10 @@ packages: resolution: {integrity: sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==} engines: {node: '>= 10'} + /@tootallnate/quickjs-emscripten@0.23.0: + resolution: {integrity: sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA==} + dev: true + /@tsconfig/node10@1.0.9: resolution: {integrity: sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==} dev: true @@ -1207,7 +1189,7 @@ packages: dependencies: '@types/http-cache-semantics': 4.0.4 '@types/keyv': 3.1.4 - '@types/node': 16.11.7 + '@types/node': 18.19.50 '@types/responselike': 1.0.3 dev: true @@ -1228,7 +1210,7 @@ packages: /@types/cors@2.8.17: resolution: {integrity: sha512-8CGDvrBj1zgo2qE+oS3pOCyYNqCPryMWY2bGfwA0dcfopWGgxs+78df0Rs3rc9THP4JkOhLsAa+15VdpAqkcUA==} dependencies: - '@types/node': 16.11.7 + '@types/node': 18.19.50 dev: true /@types/eslint-scope@3.7.7: @@ -1245,14 +1227,14 @@ packages: '@types/json-schema': 7.0.15 dev: true - /@types/estree@0.0.39: - resolution: {integrity: sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==} - dev: true - /@types/estree@0.0.51: resolution: {integrity: sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ==} dev: true + /@types/estree@1.0.6: + resolution: {integrity: sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==} + dev: true + /@types/http-cache-semantics@4.0.4: resolution: {integrity: sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA==} dev: true @@ -1265,21 +1247,21 @@ packages: resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} dev: true - /@types/jsonwebtoken@8.3.5: - resolution: {integrity: sha512-VGM1gb+LwsQ5EPevvbvdnKncajBdYqNcrvixBif1BsiDQiSF1q+j4bBTvKC6Bt9n2kqNSx+yNTY2TVJ360E7EQ==} - dependencies: - '@types/node': 16.11.7 - /@types/jsonwebtoken@9.0.2: resolution: {integrity: sha512-drE6uz7QBKq1fYqqoFKTDRdFCPHd5TCub75BM+D+cMx7NU9hUz7SESLfC2fSCXVFMO5Yj8sOWHuGqPgjc+fz0Q==} dependencies: - '@types/node': 16.11.7 + '@types/node': 18.19.50 dev: true + /@types/jsonwebtoken@9.0.6: + resolution: {integrity: sha512-/5hndP5dCjloafCXns6SZyESp3Ldq7YjH3zwzwczYnjxIT0Fqzk5ROSYVGfFyczIue7IUEj8hkvLbPoLQ18vQw==} + dependencies: + '@types/node': 18.19.50 + /@types/keyv@3.1.4: resolution: {integrity: sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==} dependencies: - '@types/node': 16.11.7 + '@types/node': 18.19.50 dev: true /@types/lodash.isequal@4.5.8: @@ -1296,32 +1278,32 @@ packages: resolution: {integrity: sha512-ssE3Vlrys7sdIzs5LOxCzTVMsU7i9oa/IaW92wF32JFb3CVczqOkru2xspuKczHEbG3nvmPY7IFqVmGGHdNbYw==} dev: false - /@types/mocha@9.0.0: - resolution: {integrity: sha512-scN0hAWyLVAvLR9AyW7HoFF5sJZglyBsbPuHO4fv7JRvfmPBMfp1ozWqOf/e4wwPNxezBZXRfWzMb6iFLgEVRA==} + /@types/mocha@10.0.8: + resolution: {integrity: sha512-HfMcUmy9hTMJh66VNcmeC9iVErIZJli2bszuXc6julh5YGuRb/W5OnkHjwLNYdFlMis0sY3If5SEAp+PktdJjw==} dev: true - /@types/mochawesome@6.2.1: - resolution: {integrity: sha512-AhQdBkT/CBdx3sI9ATeljqa5uJ3dGNKEJnsgzw9IkPeg9d9Lzxsz1eKFnenxq1qQojIW0XkIsCgdheRRXP2SQA==} + /@types/mochawesome@6.2.4: + resolution: {integrity: sha512-tWnTmoWX1bpxutRYyrrgVtLeOUvaLxmoPsO+sMw8pvVFQ90UT2TkOQwu8usUGgGbEajMOIIarSW3hpaA7AavOQ==} dependencies: - '@types/mocha': 9.0.0 + '@types/mocha': 10.0.8 dev: true /@types/node-fetch@2.6.11: resolution: {integrity: sha512-24xFj9R5+rfQJLRyM56qh+wnVSYhyXC2tkoBndtY0U+vubqNsYXGjufB2nn8Q6gt0LrARwL6UBtMCSVCwl4B1g==} dependencies: - '@types/node': 16.11.7 + '@types/node': 18.19.50 form-data: 4.0.0 - /@types/node@10.17.60: - resolution: {integrity: sha512-F0KIgDJfy2nA3zMLmWGKxcH2ZVEtCZXHHdOQs2gSaQ27+lNeEfGxzkIw90aXswATX7AZ33tahPbzy6KAfUreVw==} + /@types/node@18.19.47: + resolution: {integrity: sha512-1f7dB3BL/bpd9tnDJrrHb66Y+cVrhxSOTGorRNdHwYTUlTay3HuTDPKo9a/4vX9pMQkhYBcAbL4jQdNlhCFP9A==} + dependencies: + undici-types: 5.26.5 dev: false - /@types/node@12.20.24: - resolution: {integrity: sha512-yxDeaQIAJlMav7fH5AQqPH1u8YIuhYJXYBzxaQ4PifsU0GDO38MSdmEDeRlIxrKbC6NbEaaEHDanWb+y30U8SQ==} - dev: true - - /@types/node@16.11.7: - resolution: {integrity: sha512-QB5D2sqfSjCmTuWcBWyJ+/44bcjO7VbjSbOE0ucoVbAsSNQc4Lt6QkgkVXkTDwkL4z/beecZNDvVX15D4P8Jbw==} + /@types/node@18.19.50: + resolution: {integrity: sha512-xonK+NRrMBRtkL1hVCc3G+uXtjh1Al4opBLjqVmipe5ZAaBYWW6cNAiBVZ1BvmkBhep698rP3UM3aRAdSALuhg==} + dependencies: + undici-types: 5.26.5 /@types/parse-json@4.0.2: resolution: {integrity: sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==} @@ -1330,7 +1312,11 @@ packages: /@types/responselike@1.0.3: resolution: {integrity: sha512-H/+L+UkTV33uf49PH5pCAUBVPNj2nDBXTN+qS1dOwyyg24l3CcicicCA7ca+HMvJBZcFgl5r8e+RR6elsb4Lyw==} dependencies: - '@types/node': 16.11.7 + '@types/node': 18.19.50 + dev: true + + /@types/semver@7.5.8: + resolution: {integrity: sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==} dev: true /@types/sinon@10.0.6: @@ -1339,22 +1325,10 @@ packages: '@sinonjs/fake-timers': 7.1.2 dev: true - /@types/stoppable@1.1.3: - resolution: {integrity: sha512-7wGKIBJGE4ZxFjk9NkjAxZMLlIXroETqP1FJCdoSvKmEznwmBxQFmTB1dsCkAvVcNemuSZM5qkkd9HE/NL2JTw==} - dependencies: - '@types/node': 16.11.7 - dev: false - - /@types/tedious@4.0.5: - resolution: {integrity: sha512-zlnChTP63Bds6kMBuKOR+qJPB9wcYf1zVm78qiXTnT1gbcU6wdTmSp28cd2BPxePy4mrGM6TnQG1fmHxQW1pZw==} - dependencies: - '@types/node': 16.11.7 - dev: true - /@types/tunnel@0.0.3: resolution: {integrity: sha512-sOUTGn6h1SfQ+gbgqC364jLFBw2lnFqkgF3q0WovEHRLMrVD1sd5aufqi/aJObLekJO+Aq5z646U4Oxy6shXMA==} dependencies: - '@types/node': 16.11.7 + '@types/node': 18.19.50 /@types/url-join@4.0.1: resolution: {integrity: sha512-wDXw9LEEUHyV+7UWy7U315nrJGJ7p1BzaCxDpEoLr789Dk1WDVMMlf3iBfbG2F8NdWnYyFbtTxUn2ZNbm1Q4LQ==} @@ -1367,7 +1341,7 @@ packages: /@types/ws@6.0.4: resolution: {integrity: sha512-PpPrX7SZW9re6+Ha8ojZG4Se8AZXgf0GK6zmfqEuCsY49LFDNXO3SByp44X3dFEqtB73lkCDAdUazhAjVPiNwg==} dependencies: - '@types/node': 16.11.7 + '@types/node': 18.19.50 dev: false /@types/xmldom@0.1.34: @@ -1378,12 +1352,12 @@ packages: resolution: {integrity: sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==} requiresBuild: true dependencies: - '@types/node': 16.11.7 + '@types/node': 18.19.50 dev: true optional: true - /@typescript-eslint/eslint-plugin@5.0.0(@typescript-eslint/parser@4.13.0)(eslint@8.1.0)(supports-color@9.4.0)(typescript@4.4.4): - resolution: {integrity: sha512-T6V6fCD2U0YesOedvydTnrNtsC8E+c2QzpawIpDdlaObX0OX5dLo7tLU5c64FhTZvA1Xrdim+cXDI7NPsVx8Cg==} + /@typescript-eslint/eslint-plugin@5.62.0(@typescript-eslint/parser@6.21.0)(eslint@8.57.1)(supports-color@9.4.0)(typescript@5.4.2): + resolution: {integrity: sha512-TiZzBSJja/LbhNPvk6yc0JrX9XqhQ0hdh6M2svYfsHGejaKFIAGd9MQ+ERIMzLGlN/kZoYIgdxFV0PuljTKXag==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: '@typescript-eslint/parser': ^5.0.0 @@ -1393,146 +1367,171 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/experimental-utils': 5.0.0(eslint@8.1.0)(supports-color@9.4.0)(typescript@4.4.4) - '@typescript-eslint/parser': 4.13.0(eslint@8.1.0)(supports-color@9.4.0)(typescript@4.4.4) - '@typescript-eslint/scope-manager': 5.0.0 - debug: 4.3.4(supports-color@9.4.0) - eslint: 8.1.0(supports-color@9.4.0) - functional-red-black-tree: 1.0.1 - ignore: 5.3.0 - regexpp: 3.2.0 - semver: 7.5.4 - tsutils: 3.21.0(typescript@4.4.4) - typescript: 4.4.4 + '@eslint-community/regexpp': 4.11.1 + '@typescript-eslint/parser': 6.21.0(eslint@8.57.1)(supports-color@9.4.0)(typescript@5.4.2) + '@typescript-eslint/scope-manager': 5.62.0 + '@typescript-eslint/type-utils': 5.62.0(eslint@8.57.1)(supports-color@9.4.0)(typescript@5.4.2) + '@typescript-eslint/utils': 5.62.0(eslint@8.57.1)(supports-color@9.4.0)(typescript@5.4.2) + debug: 4.3.7(supports-color@9.4.0) + eslint: 8.57.1(supports-color@9.4.0) + graphemer: 1.4.0 + ignore: 5.3.2 + natural-compare-lite: 1.4.0 + semver: 7.6.3 + tsutils: 3.21.0(typescript@5.4.2) + typescript: 5.4.2 transitivePeerDependencies: - supports-color dev: true - /@typescript-eslint/experimental-utils@5.0.0(eslint@8.1.0)(supports-color@9.4.0)(typescript@4.4.4): - resolution: {integrity: sha512-Dnp4dFIsZcPawD6CT1p5NibNUQyGSEz80sULJZkyhyna8AEqArmfwMwJPbmKzWVo4PabqNVzHYlzmcdLQWk+pg==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + /@typescript-eslint/parser@6.21.0(eslint@8.57.1)(supports-color@9.4.0)(typescript@5.4.2): + resolution: {integrity: sha512-tbsV1jPne5CkFQCgPBcDOt30ItF7aJoZL997JSF7MhGQqOeT3svWRYxiqlfA5RUdlHN6Fi+EI9bxqbdyAUZjYQ==} + engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: - eslint: '*' + eslint: ^7.0.0 || ^8.0.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true dependencies: - '@types/json-schema': 7.0.15 - '@typescript-eslint/scope-manager': 5.0.0 - '@typescript-eslint/types': 5.0.0 - '@typescript-eslint/typescript-estree': 5.0.0(supports-color@9.4.0)(typescript@4.4.4) - eslint: 8.1.0(supports-color@9.4.0) - eslint-scope: 5.1.1 - eslint-utils: 3.0.0(eslint@8.1.0) + '@typescript-eslint/scope-manager': 6.21.0 + '@typescript-eslint/types': 6.21.0 + '@typescript-eslint/typescript-estree': 6.21.0(supports-color@9.4.0)(typescript@5.4.2) + '@typescript-eslint/visitor-keys': 6.21.0 + debug: 4.3.7(supports-color@9.4.0) + eslint: 8.57.1(supports-color@9.4.0) + typescript: 5.4.2 transitivePeerDependencies: - supports-color - - typescript dev: true - /@typescript-eslint/parser@4.13.0(eslint@8.1.0)(supports-color@9.4.0)(typescript@4.4.4): - resolution: {integrity: sha512-KO0J5SRF08pMXzq9+abyHnaGQgUJZ3Z3ax+pmqz9vl81JxmTTOUfQmq7/4awVfq09b6C4owNlOgOwp61pYRBSg==} - engines: {node: ^10.12.0 || >=12.0.0} + /@typescript-eslint/scope-manager@5.62.0: + resolution: {integrity: sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dependencies: + '@typescript-eslint/types': 5.62.0 + '@typescript-eslint/visitor-keys': 5.62.0 + dev: true + + /@typescript-eslint/scope-manager@6.21.0: + resolution: {integrity: sha512-OwLUIWZJry80O99zvqXVEioyniJMa+d2GrqpUTqi5/v5D5rOrppJVBPa0yKCblcigC0/aYAzxxqQ1B+DS2RYsg==} + engines: {node: ^16.0.0 || >=18.0.0} + dependencies: + '@typescript-eslint/types': 6.21.0 + '@typescript-eslint/visitor-keys': 6.21.0 + dev: true + + /@typescript-eslint/type-utils@5.62.0(eslint@8.57.1)(supports-color@9.4.0)(typescript@5.4.2): + resolution: {integrity: sha512-xsSQreu+VnfbqQpW5vnCJdq1Z3Q0U31qiWmRhr98ONQmcp/yhiPJFPq8MXiJVLiksmOKSjIldZzkebzHuCGzew==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: - eslint: ^5.0.0 || ^6.0.0 || ^7.0.0 + eslint: '*' typescript: '*' peerDependenciesMeta: typescript: optional: true dependencies: - '@typescript-eslint/scope-manager': 4.13.0 - '@typescript-eslint/types': 4.13.0 - '@typescript-eslint/typescript-estree': 4.13.0(supports-color@9.4.0)(typescript@4.4.4) - debug: 4.3.4(supports-color@9.4.0) - eslint: 8.1.0(supports-color@9.4.0) - typescript: 4.4.4 + '@typescript-eslint/typescript-estree': 5.62.0(supports-color@9.4.0)(typescript@5.4.2) + '@typescript-eslint/utils': 5.62.0(eslint@8.57.1)(supports-color@9.4.0)(typescript@5.4.2) + debug: 4.3.7(supports-color@9.4.0) + eslint: 8.57.1(supports-color@9.4.0) + tsutils: 3.21.0(typescript@5.4.2) + typescript: 5.4.2 transitivePeerDependencies: - supports-color dev: true - /@typescript-eslint/scope-manager@4.13.0: - resolution: {integrity: sha512-UpK7YLG2JlTp/9G4CHe7GxOwd93RBf3aHO5L+pfjIrhtBvZjHKbMhBXTIQNkbz7HZ9XOe++yKrXutYm5KmjWgQ==} - engines: {node: ^8.10.0 || ^10.13.0 || >=11.10.1} - dependencies: - '@typescript-eslint/types': 4.13.0 - '@typescript-eslint/visitor-keys': 4.13.0 - dev: true - - /@typescript-eslint/scope-manager@5.0.0: - resolution: {integrity: sha512-5RFjdA/ain/MDUHYXdF173btOKncIrLuBmA9s6FJhzDrRAyVSA+70BHg0/MW6TE+UiKVyRtX91XpVS0gVNwVDQ==} + /@typescript-eslint/types@5.62.0: + resolution: {integrity: sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - dependencies: - '@typescript-eslint/types': 5.0.0 - '@typescript-eslint/visitor-keys': 5.0.0 dev: true - /@typescript-eslint/types@4.13.0: - resolution: {integrity: sha512-/+aPaq163oX+ObOG00M0t9tKkOgdv9lq0IQv/y4SqGkAXmhFmCfgsELV7kOCTb2vVU5VOmVwXBXJTDr353C1rQ==} - engines: {node: ^8.10.0 || ^10.13.0 || >=11.10.1} + /@typescript-eslint/types@6.21.0: + resolution: {integrity: sha512-1kFmZ1rOm5epu9NZEZm1kckCDGj5UJEf7P1kliH4LKu/RkwpsfqqGmY2OOcUs18lSlQBKLDYBOGxRVtrMN5lpg==} + engines: {node: ^16.0.0 || >=18.0.0} dev: true - /@typescript-eslint/types@5.0.0: - resolution: {integrity: sha512-dU/pKBUpehdEqYuvkojmlv0FtHuZnLXFBn16zsDmlFF3LXkOpkAQ2vrKc3BidIIve9EMH2zfTlxqw9XM0fFN5w==} + /@typescript-eslint/typescript-estree@5.62.0(supports-color@9.4.0)(typescript@5.4.2): + resolution: {integrity: sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - dev: true - - /@typescript-eslint/typescript-estree@4.13.0(supports-color@9.4.0)(typescript@4.4.4): - resolution: {integrity: sha512-9A0/DFZZLlGXn5XA349dWQFwPZxcyYyCFX5X88nWs2uachRDwGeyPz46oTsm9ZJE66EALvEns1lvBwa4d9QxMg==} - engines: {node: ^10.12.0 || >=12.0.0} peerDependencies: typescript: '*' peerDependenciesMeta: typescript: optional: true dependencies: - '@typescript-eslint/types': 4.13.0 - '@typescript-eslint/visitor-keys': 4.13.0 - debug: 4.3.4(supports-color@9.4.0) + '@typescript-eslint/types': 5.62.0 + '@typescript-eslint/visitor-keys': 5.62.0 + debug: 4.3.7(supports-color@9.4.0) globby: 11.1.0 is-glob: 4.0.3 - lodash: 4.17.21 - semver: 7.5.4 - tsutils: 3.21.0(typescript@4.4.4) - typescript: 4.4.4 + semver: 7.6.3 + tsutils: 3.21.0(typescript@5.4.2) + typescript: 5.4.2 transitivePeerDependencies: - supports-color dev: true - /@typescript-eslint/typescript-estree@5.0.0(supports-color@9.4.0)(typescript@4.4.4): - resolution: {integrity: sha512-V/6w+PPQMhinWKSn+fCiX5jwvd1vRBm7AX7SJQXEGQtwtBvjMPjaU3YTQ1ik2UF1u96X7tsB96HMnulG3eLi9Q==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + /@typescript-eslint/typescript-estree@6.21.0(supports-color@9.4.0)(typescript@5.4.2): + resolution: {integrity: sha512-6npJTkZcO+y2/kr+z0hc4HwNfrrP4kNYh57ek7yCNlrBjWQ1Y0OS7jiZTkgumrvkX5HkEKXFZkkdFNkaW2wmUQ==} + engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: typescript: '*' peerDependenciesMeta: typescript: optional: true dependencies: - '@typescript-eslint/types': 5.0.0 - '@typescript-eslint/visitor-keys': 5.0.0 - debug: 4.3.4(supports-color@9.4.0) + '@typescript-eslint/types': 6.21.0 + '@typescript-eslint/visitor-keys': 6.21.0 + debug: 4.3.7(supports-color@9.4.0) globby: 11.1.0 is-glob: 4.0.3 - semver: 7.5.4 - tsutils: 3.21.0(typescript@4.4.4) - typescript: 4.4.4 + minimatch: 9.0.3 + semver: 7.6.3 + ts-api-utils: 1.3.0(typescript@5.4.2) + typescript: 5.4.2 transitivePeerDependencies: - supports-color dev: true - /@typescript-eslint/visitor-keys@4.13.0: - resolution: {integrity: sha512-6RoxWK05PAibukE7jElqAtNMq+RWZyqJ6Q/GdIxaiUj2Ept8jh8+FUVlbq9WxMYxkmEOPvCE5cRSyupMpwW31g==} - engines: {node: ^8.10.0 || ^10.13.0 || >=11.10.1} + /@typescript-eslint/utils@5.62.0(eslint@8.57.1)(supports-color@9.4.0)(typescript@5.4.2): + resolution: {integrity: sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 dependencies: - '@typescript-eslint/types': 4.13.0 - eslint-visitor-keys: 2.1.0 + '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.1) + '@types/json-schema': 7.0.15 + '@types/semver': 7.5.8 + '@typescript-eslint/scope-manager': 5.62.0 + '@typescript-eslint/types': 5.62.0 + '@typescript-eslint/typescript-estree': 5.62.0(supports-color@9.4.0)(typescript@5.4.2) + eslint: 8.57.1(supports-color@9.4.0) + eslint-scope: 5.1.1 + semver: 7.6.3 + transitivePeerDependencies: + - supports-color + - typescript dev: true - /@typescript-eslint/visitor-keys@5.0.0: - resolution: {integrity: sha512-yRyd2++o/IrJdyHuYMxyFyBhU762MRHQ/bAGQeTnN3pGikfh+nEmM61XTqaDH1XDp53afZ+waXrk0ZvenoZ6xw==} + /@typescript-eslint/visitor-keys@5.62.0: + resolution: {integrity: sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dependencies: - '@typescript-eslint/types': 5.0.0 + '@typescript-eslint/types': 5.62.0 + eslint-visitor-keys: 3.4.3 + dev: true + + /@typescript-eslint/visitor-keys@6.21.0: + resolution: {integrity: sha512-JJtkDduxLi9bivAB+cYOVMtbkqdPOhZ+ZI5LC47MIRrDV4Yn2o+ZnW10Nkmr28xRpSpdJ6Sm42Hjf2+REYXm0A==} + engines: {node: ^16.0.0 || >=18.0.0} + dependencies: + '@typescript-eslint/types': 6.21.0 eslint-visitor-keys: 3.4.3 dev: true - /@ungap/promise-all-settled@1.1.2: - resolution: {integrity: sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==} + /@ungap/structured-clone@1.2.0: + resolution: {integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==} dev: true /@webassemblyjs/ast@1.11.1: @@ -1654,23 +1653,11 @@ packages: resolution: {integrity: sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==} dev: true - /@yarn-tool/resolve-package@1.0.47: - resolution: {integrity: sha512-Zaw58gQxjQceJqhqybJi1oUDaORT8i2GTgwICPs8v/X/Pkx35FXQba69ldHVg5pQZ6YLKpROXgyHvBaCJOFXiA==} - dependencies: - pkg-dir: 5.0.0 - tslib: 2.3.1 - upath2: 3.1.19 - dev: true - /abab@2.0.6: resolution: {integrity: sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==} deprecated: Use your platform's native atob() and btoa() methods instead dev: true - /abbrev@1.0.9: - resolution: {integrity: sha512-LEyx4aLEC3x6T0UguF6YILf+ntvmOaWsVfENmIW0E9H09vKlLDGelMjjSm0jkDHALj8A8quZ/HapKNigzwge+Q==} - dev: true - /accepts@1.3.8: resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==} engines: {node: '>= 0.6'} @@ -1706,36 +1693,36 @@ packages: hasBin: true dev: true - /adaptive-expressions@4.22.3: - resolution: {integrity: sha512-ks2kYbmVIWtYVRV8Sh9snCEDPtoFutL1W1p/AHfKz3Z0VCxCaDYU/QooVUxVFgOvvMOCWi1yYNFW3UlMaNs99g==} + /adaptive-expressions@4.23.1: + resolution: {integrity: sha512-wQVhfmF8I0CI+8Bgcoc0sl/oLRek31XzjYq03QjdHyPjIeTmtofgf5qmJDdGQt6nz6fP9Jd0FlnesqasdUEjFA==} dependencies: - '@microsoft/recognizers-text-data-types-timex-expression': 1.3.0 + '@microsoft/recognizers-text-data-types-timex-expression': 1.3.1 '@types/atob-lite': 2.0.2 '@types/btoa-lite': 1.0.2 '@types/lodash.isequal': 4.5.8 '@types/lru-cache': 5.1.1 '@types/xmldom': 0.1.34 '@xmldom/xmldom': 0.8.10 - antlr4ts: 0.5.0-alpha.3 + antlr4ts: 0.5.0-alpha.4 atob-lite: 2.0.0 big-integer: 1.6.52 btoa-lite: 1.0.0 - d3-format: 1.4.5 - dayjs: 1.11.10 + d3-format: 2.0.0 + dayjs: 1.11.13 fast-xml-parser: 4.4.1 jspath: 0.4.0 lodash.isequal: 4.5.0 lru-cache: 5.1.1 - uuid: 8.3.2 - xpath: 0.0.32 + uuid: 10.0.0 + xpath: 0.0.34 dev: false - /adaptivecards-templating@2.3.1(adaptive-expressions@4.22.3): + /adaptivecards-templating@2.3.1(adaptive-expressions@4.23.1): resolution: {integrity: sha512-rYN1tCb+4NeWUCbo7xzGhwuOG3XllpGWCtgdl/drSJA32tljAvDrMeBO/eUk7uwXx8/1hSc5WJvzbAZQWMd35Q==} peerDependencies: adaptive-expressions: ^4.11.0 dependencies: - adaptive-expressions: 4.22.3 + adaptive-expressions: 4.23.1 dev: false /adaptivecards@1.2.3: @@ -1750,7 +1737,7 @@ packages: resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==} engines: {node: '>= 6.0.0'} dependencies: - debug: 4.3.4(supports-color@9.4.0) + debug: 4.3.7(supports-color@9.4.0) transitivePeerDependencies: - supports-color @@ -1758,11 +1745,20 @@ packages: resolution: {integrity: sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg==} engines: {node: '>= 14'} dependencies: - debug: 4.3.4(supports-color@9.4.0) + debug: 4.3.7(supports-color@9.4.0) transitivePeerDependencies: - supports-color - /aggregate-error@3.1.0: + /agent-base@7.1.1(supports-color@9.4.0): + resolution: {integrity: sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==} + engines: {node: '>= 14'} + dependencies: + debug: 4.3.7(supports-color@9.4.0) + transitivePeerDependencies: + - supports-color + dev: true + + /aggregate-error@3.1.0: resolution: {integrity: sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==} engines: {node: '>=8'} dependencies: @@ -1770,6 +1766,28 @@ packages: indent-string: 4.0.0 dev: true + /ajv-draft-04@1.0.0(ajv@8.13.0): + resolution: {integrity: sha512-mv00Te6nmYbRp5DCwclxtt7yV/joXJPGS7nM+97GdxvuttCOfgI3K4U25zboyeX0O+myI8ERluxQe5wljMmVIw==} + peerDependencies: + ajv: ^8.5.0 + peerDependenciesMeta: + ajv: + optional: true + dependencies: + ajv: 8.13.0 + dev: true + + /ajv-formats@3.0.1(ajv@8.13.0): + resolution: {integrity: sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==} + peerDependencies: + ajv: ^8.0.0 + peerDependenciesMeta: + ajv: + optional: true + dependencies: + ajv: 8.13.0 + dev: true + /ajv-keywords@3.5.2(ajv@6.12.6): resolution: {integrity: sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==} peerDependencies: @@ -1787,16 +1805,22 @@ packages: uri-js: 4.4.1 dev: true - /amdefine@1.0.1: - resolution: {integrity: sha512-S2Hw0TtNkMJhIabBwIojKL9YHO5T0n5eNqWJ7Lrlel/zDbftQpxpapi8tZs3X1HWa+u+QeydGmzzNU0m09+Rcg==} - engines: {node: '>=0.4.2'} - requiresBuild: true + /ajv@8.12.0: + resolution: {integrity: sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==} + dependencies: + fast-deep-equal: 3.1.3 + json-schema-traverse: 1.0.0 + require-from-string: 2.0.2 + uri-js: 4.4.1 dev: true - optional: true - /ansi-colors@4.1.1: - resolution: {integrity: sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==} - engines: {node: '>=6'} + /ajv@8.13.0: + resolution: {integrity: sha512-PRA911Blj99jR5RMeTunVbNXMF6Lp4vZXnk5GQjcnUWUTsrXtekg/pnmFFI2u/I36Y/2bITGS30GZCXei6uNkA==} + dependencies: + fast-deep-equal: 3.1.3 + json-schema-traverse: 1.0.0 + require-from-string: 2.0.2 + uri-js: 4.4.1 dev: true /ansi-colors@4.1.3: @@ -1821,6 +1845,11 @@ packages: engines: {node: '>=8'} dev: true + /ansi-regex@6.1.0: + resolution: {integrity: sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==} + engines: {node: '>=12'} + dev: true + /ansi-styles@3.2.1: resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==} engines: {node: '>=4'} @@ -1835,8 +1864,13 @@ packages: color-convert: 2.0.1 dev: true - /antlr4ts@0.5.0-alpha.3: - resolution: {integrity: sha512-La89tKkGcHFIVuruv4Bm1esc3zLmES2NOTEwwNS1pudz+zx/0FNqQeUu9p48i9/QHKPVqjN87LB+q3buTg7oDQ==} + /ansi-styles@6.2.1: + resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==} + engines: {node: '>=12'} + dev: true + + /antlr4ts@0.5.0-alpha.4: + resolution: {integrity: sha512-WPQDt1B74OfPv/IMS2ekXAKkTZIHl88uMetg6q3OTqgFxZ/dxDXI0EWLyZid/1Pe6hTftyg5N7gel5wNAGxXyQ==} dev: false /anymatch@3.1.3: @@ -1879,11 +1913,6 @@ packages: is-array-buffer: 3.0.2 dev: true - /array-find-index@1.0.2: - resolution: {integrity: sha512-M1HQyIXcBGtVywBt8WVdim+lrNaK7VHp99Qt5pSNziXznKHViIBbXWtfRTpEFpF/c4FdfxNAsCCwPp5phBYJtw==} - engines: {node: '>=0.10.0'} - dev: true - /array-includes@3.1.7: resolution: {integrity: sha512-dlcsNBIiWhPkHdOEEKnehA+RNUWDc4UqFtnIXU4uuYDPtA4LDkr7qip2p0VvFAEXNDr0yWZ9PJyIRiGjRLQzwQ==} engines: {node: '>= 0.4'} @@ -1923,6 +1952,13 @@ packages: is-shared-array-buffer: 1.0.2 dev: true + /asn1.js@4.10.1: + resolution: {integrity: sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==} + dependencies: + bn.js: 4.12.0 + inherits: 2.0.4 + minimalistic-assert: 1.0.1 + /assertion-error@1.1.0: resolution: {integrity: sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==} dev: true @@ -1932,15 +1968,18 @@ packages: engines: {node: '>=12'} dev: true + /ast-types@0.13.4: + resolution: {integrity: sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w==} + engines: {node: '>=4'} + dependencies: + tslib: 2.7.0 + dev: true + /astral-regex@2.0.0: resolution: {integrity: sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==} engines: {node: '>=8'} dev: true - /async@1.5.2: - resolution: {integrity: sha512-nSVgobk4rv61R9PUSDtYt7mPVB2olxNR5RWJcAsH676/ef11bUZwvu7+RGYrYauVdDPcO519v68wRhXQtxsV9w==} - dev: true - /asynckit@0.4.0: resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} @@ -1973,10 +2012,62 @@ packages: transitivePeerDependencies: - debug + /axios@1.7.7: + resolution: {integrity: sha512-S4kL7XrjgBmvdGut0sN3yJxqYzrDOnivkBiN0OFs6hLiUam3UPvswUo0kqGyhqUZGEOytHyumEdXsAkgCOUf3Q==} + dependencies: + follow-redirects: 1.15.6 + form-data: 4.0.0 + proxy-from-env: 1.1.0 + transitivePeerDependencies: + - debug + + /b4a@1.6.7: + resolution: {integrity: sha512-OnAYlL5b7LEkALw87fUVafQw5rVR9RjwGd4KUwNQ6DrrNmaVaUCgLipfVlzrPQ4tWOR9P0IXGNOx50jYCCdSJg==} + dev: true + /balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} dev: true + /bare-events@2.5.0: + resolution: {integrity: sha512-/E8dDe9dsbLyh2qrZ64PEPadOQ0F4gbl1sUJOrmph7xOiIxfY8vwab/4bFLh4Y88/Hk/ujKcrQKc+ps0mv873A==} + requiresBuild: true + dev: true + optional: true + + /bare-fs@2.3.5: + resolution: {integrity: sha512-SlE9eTxifPDJrT6YgemQ1WGFleevzwY+XAP1Xqgl56HtcrisC2CHCZ2tq6dBpcH2TnNxwUEUGhweo+lrQtYuiw==} + requiresBuild: true + dependencies: + bare-events: 2.5.0 + bare-path: 2.1.3 + bare-stream: 2.3.0 + dev: true + optional: true + + /bare-os@2.4.4: + resolution: {integrity: sha512-z3UiI2yi1mK0sXeRdc4O1Kk8aOa/e+FNWZcTiPB/dfTWyLypuE99LibgRaQki914Jq//yAWylcAt+mknKdixRQ==} + requiresBuild: true + dev: true + optional: true + + /bare-path@2.1.3: + resolution: {integrity: sha512-lh/eITfU8hrj9Ru5quUp0Io1kJWIk1bTjzo7JH1P5dWmQ2EL4hFUlfI8FonAhSlgIfhn63p84CDY/x+PisgcXA==} + requiresBuild: true + dependencies: + bare-os: 2.4.4 + dev: true + optional: true + + /bare-stream@2.3.0: + resolution: {integrity: sha512-pVRWciewGUeCyKEuRxwv06M079r+fRjAQjBEK2P6OYGrO43O+Z0LrPZZEjlc4mB6C2RpZ9AxJ1s7NLEtOHO6eA==} + requiresBuild: true + dependencies: + b4a: 1.6.7 + streamx: 2.20.1 + dev: true + optional: true + /base64-js@1.5.1: resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} @@ -1989,6 +2080,11 @@ packages: resolution: {integrity: sha512-ir1UPr3dkwexU7FdV8qBBbNDRUhMmIekYMFZfi+C/sLNnRESKPl23nB9b2pltqfOQNnGzsDdId90AEtG5tCx4A==} engines: {node: '>=6.0.0'} + /basic-ftp@5.0.5: + resolution: {integrity: sha512-4Bcg1P8xhUuqcii/S0Z9wiHIrQVPMermM1any+MX5GeGD7faD3/msQUDGLol9wOcz4/jbg/WJnGqoJF6LiBdtg==} + engines: {node: '>=10.0.0'} + dev: true + /big-integer@1.6.52: resolution: {integrity: sha512-QxD8cf2eVqJOOz63z6JIN9BzvVs/dlySa5HGSBH5xtR8dPteIRQnBxxKqkNTiT6jbDTF6jAfrd4oMcND9RGbQg==} engines: {node: '>=0.6'} @@ -2003,21 +2099,11 @@ packages: engines: {node: '>=8'} dev: true - /bl@4.1.0: - resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} - dependencies: - buffer: 5.7.1 - inherits: 2.0.4 - readable-stream: 3.6.2 - dev: true + /bn.js@4.12.0: + resolution: {integrity: sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==} - /bl@5.1.0: - resolution: {integrity: sha512-tv1ZJHLfTDnXE6tMHv73YgSJaWR2AFuPwMntBe7XL/GBFHnT0CLnsHMogfk5+GzCDC5ZWarSCYaIGATZt9dNsQ==} - dependencies: - buffer: 6.0.3 - inherits: 2.0.4 - readable-stream: 3.6.2 - dev: false + /bn.js@5.2.1: + resolution: {integrity: sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==} /body-parser@1.20.2(supports-color@9.4.0): resolution: {integrity: sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==} @@ -2039,66 +2125,66 @@ packages: - supports-color dev: true - /botbuilder-core@4.22.3(supports-color@9.4.0): - resolution: {integrity: sha512-159+ugNI/gp7u+ByYWIjVPE6csFEMfJzbYISf1HVFHhw0m/h0zEyXMvjoiwGu/fA7TI+TtpuFLdh75roEodOsw==} + /botbuilder-core@4.23.1(supports-color@9.4.0): + resolution: {integrity: sha512-lgWZ5Z8jl6MuVGxooq9eaJK/Jdqu5opJ3K3kQ/yFxG/C7VNte93BHeYviERESUMvcCNOhMRIiTrKyVYfKO4NDw==} dependencies: - botbuilder-dialogs-adaptive-runtime-core: 4.22.3-preview - botbuilder-stdlib: 4.22.3-internal - botframework-connector: 4.22.3(supports-color@9.4.0) - botframework-schema: 4.22.3 - uuid: 8.3.2 - zod: 3.22.4 + botbuilder-dialogs-adaptive-runtime-core: 4.23.1-preview + botbuilder-stdlib: 4.23.1-internal + botframework-connector: 4.23.1(supports-color@9.4.0) + botframework-schema: 4.23.1 + uuid: 10.0.0 + zod: 3.23.8 transitivePeerDependencies: - debug - encoding - supports-color - /botbuilder-dialogs-adaptive-runtime-core@4.22.3-preview: - resolution: {integrity: sha512-JbVKKmriLwUOgBI040unl5xVTmGhESFXnvC3O75nDzjFjdRpaIAwA2/L7ik6E3O4bOkwO2jDov2W+LWlbSnjXQ==} + /botbuilder-dialogs-adaptive-runtime-core@4.23.1-preview: + resolution: {integrity: sha512-6au9eGmEIpscP+cLYZ2G71azlj1E8rwL3WpAqfBG2RlWZCOuWH9uFNh2V9lg/KrDC2ks3O2YFk0tCym40i0XLQ==} dependencies: - dependency-graph: 0.10.0 + dependency-graph: 1.0.0 - /botbuilder-dialogs@4.22.3(supports-color@9.4.0): - resolution: {integrity: sha512-mrMVz+aiYoLCwIEpYzTyMXvrMVrxSl4OXWD1nFA7brlwbHwb6McG423I0DKoDTRN7buOLYY4CCWItXMp2mRq8Q==} + /botbuilder-dialogs@4.23.1(supports-color@9.4.0): + resolution: {integrity: sha512-yIlr4Kz03NFZ3Rvc1MrgWkvW2pupKghOEoXX/q9Lns0FFsSrRRTEoGRz+xQRlYbz7gf6tEbaYKMAXwTLsuJYmw==} requiresBuild: true dependencies: '@microsoft/recognizers-text-choice': 1.1.4 '@microsoft/recognizers-text-date-time': 1.1.4 '@microsoft/recognizers-text-number': 1.3.1 '@microsoft/recognizers-text-suite': 1.1.4 - botbuilder-core: 4.22.3(supports-color@9.4.0) - botbuilder-dialogs-adaptive-runtime-core: 4.22.3-preview - botframework-connector: 4.22.3(supports-color@9.4.0) + botbuilder-core: 4.23.1(supports-color@9.4.0) + botbuilder-dialogs-adaptive-runtime-core: 4.23.1-preview + botframework-connector: 4.23.1(supports-color@9.4.0) globalize: 1.7.0 lodash: 4.17.21 - uuid: 8.3.2 - zod: 3.22.4 + uuid: 10.0.0 + zod: 3.23.8 transitivePeerDependencies: - debug - encoding - supports-color dev: false - /botbuilder-stdlib@4.22.3-internal: - resolution: {integrity: sha512-DZwHRHpEZQNDQ426RpSmEpNKm9V/5k11lpXmQ41Eq2g0LHdaz1TqgV97US+Mj7Xyp4Fngp23HWcGivU8bQeArA==} + /botbuilder-stdlib@4.23.1-internal: + resolution: {integrity: sha512-ChtEcnSRCDRgFuMN6ji24fHqtMERdDUP/WENX6iZQwtQUEUb12G3PcYWuaOEQhllSae6qfo3QsDW0kjGsrBX+Q==} - /botbuilder@4.22.3(supports-color@9.4.0): - resolution: {integrity: sha512-vmsCBaqC6mvX9Kr6xVvU0Zlblh1d923HTXJqs196QspDMX9sedmxORfgX3u3P1vNXqx5jt4ODm52k5Aau+IP+w==} + /botbuilder@4.23.1(supports-color@9.4.0): + resolution: {integrity: sha512-0yCkRfeeeDXPic1bo9xX9Dj/SyUDB0nNAoxxSOpBxSbClztV+Mupx2rTtExMcUKRUbSUWIKYWHL9htkT2ya5JA==} dependencies: '@azure/core-http': 3.0.4 - '@azure/msal-node': 1.18.4 - axios: 1.7.5 - botbuilder-core: 4.22.3(supports-color@9.4.0) - botbuilder-stdlib: 4.22.3-internal - botframework-connector: 4.22.3(supports-color@9.4.0) - botframework-schema: 4.22.3 - botframework-streaming: 4.22.3 - dayjs: 1.11.10 + '@azure/msal-node': 2.14.0 + axios: 1.7.7 + botbuilder-core: 4.23.1(supports-color@9.4.0) + botbuilder-stdlib: 4.23.1-internal + botframework-connector: 4.23.1(supports-color@9.4.0) + botframework-schema: 4.23.1 + botframework-streaming: 4.23.1 + dayjs: 1.11.13 filenamify: 4.3.0 - fs-extra: 7.0.1 - htmlparser2: 6.1.0 - uuid: 8.3.2 - zod: 3.22.4 + fs-extra: 11.2.0 + htmlparser2: 9.1.0 + uuid: 10.0.0 + zod: 3.23.8 transitivePeerDependencies: - bufferutil - debug @@ -2107,42 +2193,47 @@ packages: - utf-8-validate dev: false - /botframework-connector@4.22.3(supports-color@9.4.0): - resolution: {integrity: sha512-xsGFfphSMECvaBJynWmvSXbG8o72WqX8Ba885kz/lxGXu1f6CjTObO0enxQdtH9O7YmCX4T0xOaHiFxnU2U61A==} + /botframework-connector@4.23.1(supports-color@9.4.0): + resolution: {integrity: sha512-UqOdVndOGNN1dgtLEKDD1rObPPI32tPwyrtU8WDuVukaPSL7KYp6z1SjudZ9ywDcrt5z+Rkbz2kGzaSidCVZWA==} dependencies: '@azure/core-http': 3.0.4 - '@azure/identity': 2.1.0(supports-color@9.4.0) - '@azure/msal-node': 1.18.4 - '@types/jsonwebtoken': 8.3.5 - axios: 1.7.5 + '@azure/identity': 4.4.1(supports-color@9.4.0) + '@azure/msal-node': 2.14.0 + '@types/jsonwebtoken': 9.0.6 + axios: 1.7.7 base64url: 3.0.1 - botbuilder-stdlib: 4.22.3-internal - botframework-schema: 4.22.3 - cross-fetch: 3.1.8 - https-proxy-agent: 7.0.4(supports-color@9.4.0) + botbuilder-stdlib: 4.23.1-internal + botframework-schema: 4.23.1 + buffer: 6.0.3 + cross-fetch: 4.0.0 + crypto-browserify: 3.12.0 + https-browserify: 1.0.0 + https-proxy-agent: 7.0.5(supports-color@9.4.0) jsonwebtoken: 9.0.2 node-fetch: 2.7.0 openssl-wrapper: 0.3.4 rsa-pem-from-mod-exp: 0.8.6 - zod: 3.22.4 + stream-browserify: 3.0.0 + stream-http: 3.2.0 + zod: 3.23.8 transitivePeerDependencies: - debug - encoding - supports-color - /botframework-schema@4.22.3: - resolution: {integrity: sha512-8d/IgrFPrVIJFOqExASROYYaV4ikQvDIq60sEN2DphVS+Cnlvm65Tl/6vv+3c27A6xrih23nyvjgAafhLmZ1gQ==} + /botframework-schema@4.23.1: + resolution: {integrity: sha512-J/cjL9IFewO3Q2yuV+QGtWyzVFPgKCp/3adY5/+0MrBQasJS5IIGm45W4CV/uYuoAstOIpYJ9nQPzvNWbDN16g==} dependencies: adaptivecards: 1.2.3 - uuid: 8.3.2 - zod: 3.22.4 + uuid: 10.0.0 + zod: 3.23.8 - /botframework-streaming@4.22.3: - resolution: {integrity: sha512-N0lI6eezH1wj5fkB+L5W+lDLL3EOOpqfj6OEf7xgzIdoJrDZy4vK/du66ptzWKZveyWK2MDd5Xme+pOm2H6dRA==} + /botframework-streaming@4.23.1: + resolution: {integrity: sha512-/BjIu2BR8y/HOdJ+Wdr1nZUvW2W53G8whH65msvM95kmjEyqskeEWP62xDpZLA1OM3sLD9APNix69BX1awcbdw==} dependencies: - '@types/node': 10.17.60 + '@types/node': 18.19.47 '@types/ws': 6.0.4 - uuid: 8.3.2 + uuid: 10.0.0 ws: 7.5.10 transitivePeerDependencies: - bufferutil @@ -2156,6 +2247,12 @@ packages: concat-map: 0.0.1 dev: true + /brace-expansion@2.0.1: + resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} + dependencies: + balanced-match: 1.0.2 + dev: true + /braces@3.0.2: resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==} engines: {node: '>=8'} @@ -2163,10 +2260,59 @@ packages: fill-range: 7.0.1 dev: true + /brorand@1.1.0: + resolution: {integrity: sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==} + /browser-stdout@1.3.1: resolution: {integrity: sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==} dev: true + /browserify-aes@1.2.0: + resolution: {integrity: sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==} + dependencies: + buffer-xor: 1.0.3 + cipher-base: 1.0.4 + create-hash: 1.2.0 + evp_bytestokey: 1.0.3 + inherits: 2.0.4 + safe-buffer: 5.2.1 + + /browserify-cipher@1.0.1: + resolution: {integrity: sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==} + dependencies: + browserify-aes: 1.2.0 + browserify-des: 1.0.2 + evp_bytestokey: 1.0.3 + + /browserify-des@1.0.2: + resolution: {integrity: sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==} + dependencies: + cipher-base: 1.0.4 + des.js: 1.1.0 + inherits: 2.0.4 + safe-buffer: 5.2.1 + + /browserify-rsa@4.1.0: + resolution: {integrity: sha512-AdEER0Hkspgno2aR97SAf6vi0y0k8NuOpGnVH3O99rcA5Q6sh8QxcngtHuJ6uXwnfAXNM4Gn1Gb7/MV1+Ymbog==} + dependencies: + bn.js: 5.2.1 + randombytes: 2.1.0 + + /browserify-sign@4.2.3: + resolution: {integrity: sha512-JWCZW6SKhfhjJxO8Tyiiy+XYB7cqd2S5/+WeYHsKdNKFlCBhKbblba1A/HN/90YwtxKc8tCErjffZl++UNmGiw==} + engines: {node: '>= 0.12'} + dependencies: + bn.js: 5.2.1 + browserify-rsa: 4.1.0 + create-hash: 1.2.0 + create-hmac: 1.1.7 + elliptic: 6.5.7 + hash-base: 3.0.4 + inherits: 2.0.4 + parse-asn1: 5.1.7 + readable-stream: 2.3.8 + safe-buffer: 5.2.1 + /browserslist@4.22.2: resolution: {integrity: sha512-0UgcrvQmBDvZHFGdYUehrCNIazki7/lUP3kkoi/r3YB2amZbFM9J43ZRkJTXBUZK4gmx56+Sqk9+Vs9mwZx9+A==} engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} @@ -2193,6 +2339,9 @@ packages: resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} dev: true + /buffer-xor@1.0.3: + resolution: {integrity: sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==} + /buffer@5.7.1: resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==} dependencies: @@ -2205,7 +2354,9 @@ packages: dependencies: base64-js: 1.5.1 ieee754: 1.2.1 - dev: false + + /builtin-status-codes@3.0.0: + resolution: {integrity: sha512-HpGFw18DgFWlncDfjTa2rcQ4W88O1mC8e8yZ2AvQY5KDaktSTwo+KRf6nHK6FRI5FyRyb/5T6+TSxfP7QyGsmQ==} /bytes@3.1.2: resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} @@ -2253,19 +2404,6 @@ packages: engines: {node: '>=6'} dev: true - /camelcase-keys@2.1.0: - resolution: {integrity: sha512-bA/Z/DERHKqoEOrp+qeGKw1QlvEQkGZSc0XaY6VnTxZr+Kv1G5zFwttpjv8qxZ/sBPT4nthwZaAcsAZTJlSKXQ==} - engines: {node: '>=0.10.0'} - dependencies: - camelcase: 2.1.1 - map-obj: 1.0.1 - dev: true - - /camelcase@2.1.1: - resolution: {integrity: sha512-DLIsRzJVBQu72meAKPkWQOLcujdXT32hwdfnkI1frSiSRMK1MofjKHf+MEx0SB6fjEFXL8fBDv1dKymBlOp4Qw==} - engines: {node: '>=0.10.0'} - dev: true - /camelcase@5.3.1: resolution: {integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==} engines: {node: '>=6'} @@ -2349,15 +2487,28 @@ packages: fsevents: 2.3.3 dev: true - /chownr@1.1.4: - resolution: {integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==} - dev: true - /chrome-trace-event@1.0.3: resolution: {integrity: sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==} engines: {node: '>=6.0'} dev: true + /chromium-bidi@0.6.5(devtools-protocol@0.0.1342118): + resolution: {integrity: sha512-RuLrmzYrxSb0s9SgpB+QN5jJucPduZQ/9SIe76MDxYJuecPW5mxMdacJ1f4EtgiV+R0p3sCkznTMvH0MPGFqjA==} + peerDependencies: + devtools-protocol: '*' + dependencies: + devtools-protocol: 0.0.1342118 + mitt: 3.0.1 + urlpattern-polyfill: 10.0.0 + zod: 3.23.8 + dev: true + + /cipher-base@1.0.4: + resolution: {integrity: sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==} + dependencies: + inherits: 2.0.4 + safe-buffer: 5.2.1 + /cldrjs@0.5.5: resolution: {integrity: sha512-KDwzwbmLIPfCgd8JERVDpQKrUUM1U4KpFJJg2IROv89rF172lLufoJnqJ/Wea6fXL5bO6WjuLMzY8V52UWPvkA==} dev: false @@ -2398,6 +2549,15 @@ packages: wrap-ansi: 7.0.0 dev: true + /cliui@8.0.1: + resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} + engines: {node: '>=12'} + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 7.0.0 + dev: true + /clone-response@1.0.3: resolution: {integrity: sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==} dependencies: @@ -2433,16 +2593,6 @@ packages: resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==} dev: true - /colors@1.2.5: - resolution: {integrity: sha512-erNRLao/Y3Fv54qUa0LBB+//Uf3YwMUmdJinN20yMXm9zdKKqH9wt7R9IIVZ+K7ShzfpLV/Zg8+VyrBJYB4lpg==} - engines: {node: '>=0.1.90'} - dev: true - - /colors@1.4.0: - resolution: {integrity: sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==} - engines: {node: '>=0.1.90'} - dev: true - /combined-stream@1.0.8: resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} engines: {node: '>= 0.8'} @@ -2458,13 +2608,6 @@ packages: engines: {node: '>= 12'} dev: true - /commander@9.5.0: - resolution: {integrity: sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==} - engines: {node: ^12.20.0 || >=14} - requiresBuild: true - dev: true - optional: true - /commondir@1.0.1: resolution: {integrity: sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==} dev: true @@ -2503,6 +2646,9 @@ packages: engines: {node: '>= 0.6'} dev: true + /core-util-is@1.0.3: + resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} + /cors@2.8.5: resolution: {integrity: sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==} engines: {node: '>= 0.10'} @@ -2522,12 +2668,53 @@ packages: yaml: 1.10.2 dev: true + /cosmiconfig@9.0.0(typescript@5.4.2): + resolution: {integrity: sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==} + engines: {node: '>=14'} + peerDependencies: + typescript: '>=4.9.5' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + env-paths: 2.2.1 + import-fresh: 3.3.0 + js-yaml: 4.1.0 + parse-json: 5.2.0 + typescript: 5.4.2 + dev: true + + /create-ecdh@4.0.4: + resolution: {integrity: sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A==} + dependencies: + bn.js: 4.12.0 + elliptic: 6.5.7 + + /create-hash@1.2.0: + resolution: {integrity: sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==} + dependencies: + cipher-base: 1.0.4 + inherits: 2.0.4 + md5.js: 1.3.5 + ripemd160: 2.0.2 + sha.js: 2.4.11 + + /create-hmac@1.1.7: + resolution: {integrity: sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==} + dependencies: + cipher-base: 1.0.4 + create-hash: 1.2.0 + inherits: 2.0.4 + ripemd160: 2.0.2 + safe-buffer: 5.2.1 + sha.js: 2.4.11 + /create-require@1.1.1: resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==} dev: true - /cross-fetch@3.1.8: - resolution: {integrity: sha512-cvA+JwZoU0Xq+h6WkMvAUqPEYy92Obet6UdKLfW60qn99ftItKjB5T+BkyWOFWe2pUyfQ+IJHmpOTznqk1M6Kg==} + /cross-fetch@4.0.0: + resolution: {integrity: sha512-e4a5N8lVvuLgAWgnCrLr2PP0YyDOTHa9H/Rj54dirp61qXnNq46m82bRhNqIA5VccJtWBvPTFRV3TtvHUKPB1g==} dependencies: node-fetch: 2.7.0 transitivePeerDependencies: @@ -2542,40 +2729,45 @@ packages: which: 2.0.2 dev: true - /currently-unhandled@0.4.1: - resolution: {integrity: sha512-/fITjgjGU50vjQ4FH6eUoYu+iUoUKIXws2hL15JJpIR+BbTxaXQsMuuyjtNh2WqsSBS5nsaZHFsFecyw5CCAng==} - engines: {node: '>=0.10.0'} + /crypto-browserify@3.12.0: + resolution: {integrity: sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==} dependencies: - array-find-index: 1.0.2 - dev: true + browserify-cipher: 1.0.1 + browserify-sign: 4.2.3 + create-ecdh: 4.0.4 + create-hash: 1.2.0 + create-hmac: 1.1.7 + diffie-hellman: 5.0.3 + inherits: 2.0.4 + pbkdf2: 3.1.2 + public-encrypt: 4.0.3 + randombytes: 2.1.0 + randomfill: 1.0.4 /custom-event@1.0.1: resolution: {integrity: sha512-GAj5FOq0Hd+RsCGVJxZuKaIDXDf3h6GQoNEjFgbLLI/trgtavwUbSnZ5pVfg27DVCaWjIohryS0JFwIJyT2cMg==} dev: true - /d3-format@1.4.5: - resolution: {integrity: sha512-J0piedu6Z8iB6TbIGfZgDzfXxUFN3qQRMofy2oPdXzQibYGqPB/9iMcxr/TGalU+2RsyDO+U4f33id8tbnSRMQ==} + /d3-format@2.0.0: + resolution: {integrity: sha512-Ab3S6XuE/Q+flY96HXT0jOXcM4EAClYFnRGY5zsjRGNy6qCYrQsMffs7cV5Q9xejb35zxW5hf/guKw34kvIKsA==} dev: false + /data-uri-to-buffer@6.0.2: + resolution: {integrity: sha512-7hvf7/GW8e86rW0ptuwS3OcBGDjIi6SZva7hCyWC0yYry2cOPmLIjXAUHI6DK2HsnwJd9ifmt57i8eV2n4YNpw==} + engines: {node: '>= 14'} + dev: true + /date-format@4.0.14: resolution: {integrity: sha512-39BOQLs9ZjKh0/patS9nrT8wc3ioX3/eA/zgbKNopnF2wCqJEoxywwwElATYvRsXdnOxA/OQeQoFZ3rFjVajhg==} engines: {node: '>=4.0'} dev: true - /dateformat@1.0.12: - resolution: {integrity: sha512-5sFRfAAmbHdIts+eKjR9kYJoF0ViCMVX9yqLu5A7S/v+nd077KgCITOMiirmyCBiZpKLDXbBOkYm6tu7rX/TKg==} - hasBin: true - dependencies: - get-stdin: 4.0.1 - meow: 3.7.0 - dev: true - /dateformat@4.6.3: resolution: {integrity: sha512-2P0p0pFGzHS5EMnhdxQi7aJN+iMheud0UhG4dlE1DLAlvL8JHjJJTX/CSm4JXwV0Ka5nGk3zC5mcb5bUQUxxMA==} dev: true - /dayjs@1.11.10: - resolution: {integrity: sha512-vjAczensTgRcqDERK0SR2XMwsF/tSvnvlv6VcF2GIhg6Sx4yOIt/irsr1RDJsKiIyBzJDpCoXiWWq28MqH2cnQ==} + /dayjs@1.11.13: + resolution: {integrity: sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==} dev: false /debug@2.6.9(supports-color@9.4.0): @@ -2615,8 +2807,8 @@ packages: supports-color: 9.4.0 dev: true - /debug@4.3.3(supports-color@8.1.1): - resolution: {integrity: sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==} + /debug@4.3.4(supports-color@8.1.1): + resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} engines: {node: '>=6.0'} peerDependencies: supports-color: '*' @@ -2628,7 +2820,7 @@ packages: supports-color: 8.1.1 dev: true - /debug@4.3.4(supports-color@8.1.1): + /debug@4.3.4(supports-color@9.4.0): resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} engines: {node: '>=6.0'} peerDependencies: @@ -2638,11 +2830,23 @@ packages: optional: true dependencies: ms: 2.1.2 + supports-color: 9.4.0 + + /debug@4.3.7(supports-color@8.1.1): + resolution: {integrity: sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + dependencies: + ms: 2.1.3 supports-color: 8.1.1 dev: true - /debug@4.3.4(supports-color@9.4.0): - resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} + /debug@4.3.7(supports-color@9.4.0): + resolution: {integrity: sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==} engines: {node: '>=6.0'} peerDependencies: supports-color: '*' @@ -2650,7 +2854,7 @@ packages: supports-color: optional: true dependencies: - ms: 2.1.2 + ms: 2.1.3 supports-color: 9.4.0 /decamelize@1.2.0: @@ -2722,6 +2926,15 @@ packages: object-keys: 1.1.1 dev: true + /degenerator@5.0.1: + resolution: {integrity: sha512-TllpMR/t0M5sqCXfj85i4XaAzxmS5tVA16dqvdkMwGmzI+dXLXnw3J+3Vdv7VKw+ThlTMboK6i9rnZ6Nntj5CQ==} + engines: {node: '>= 14'} + dependencies: + ast-types: 0.13.4 + escodegen: 2.1.0 + esprima: 4.0.1 + dev: true + /delayed-stream@1.0.0: resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} engines: {node: '>=0.4.0'} @@ -2731,17 +2944,23 @@ packages: engines: {node: '>= 0.8'} dev: true - /dependency-graph@0.10.0: - resolution: {integrity: sha512-c9amUgpgxSi1bE5/sbLwcs5diLD0ygCQYmhfM5H1s5VH1mCsYkcmAL3CcNdv4kdSw6JuMoHeDGzLgj/gAXdWVg==} - engines: {node: '>= 0.6.0'} + /dependency-graph@1.0.0: + resolution: {integrity: sha512-cW3gggJ28HZ/LExwxP2B++aiKxhJXMSIt9K48FOXQkm+vuG5gyatXnLsONRJdzO/7VfjDIiaOOa/bs4l464Lwg==} + engines: {node: '>=4'} + + /des.js@1.1.0: + resolution: {integrity: sha512-r17GxjhUCjSRy8aiJpr8/UadFIzMzJGexI3Nmz4ADi9LYSFx4gTBp80+NaX/YsXWWLhpZ7v/v/ubEc/bCNfKwg==} + dependencies: + inherits: 2.0.4 + minimalistic-assert: 1.0.1 /destroy@1.2.0: resolution: {integrity: sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==} engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} dev: true - /devtools-protocol@0.0.948846: - resolution: {integrity: sha512-5fGyt9xmMqUl2VI7+rnUkKCiAQIpLns8sfQtTENy5L70ktbNw0Z3TFJ1JoFNYdx/jffz4YXU45VF75wKZD7sZQ==} + /devtools-protocol@0.0.1342118: + resolution: {integrity: sha512-75fMas7PkYNDTmDyb6PRJCH7ILmHLp+BhrZGeMsa4bCh40DTxgCz2NRy5UDzII4C5KuD0oBMZ9vXKhEl6UD/3w==} dev: true /di@0.0.1: @@ -2753,16 +2972,23 @@ packages: engines: {node: '>=0.3.1'} dev: true - /diff@5.0.0: - resolution: {integrity: sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==} + /diff@5.1.0: + resolution: {integrity: sha512-D+mk+qE8VC/PAUrlAU34N+VfXev0ghe5ywmpqrawphmVZc1bEfn56uo9qpyGp1p4xpzOHkSW4ztBd6L7Xx4ACw==} engines: {node: '>=0.3.1'} dev: true - /diff@5.1.0: - resolution: {integrity: sha512-D+mk+qE8VC/PAUrlAU34N+VfXev0ghe5ywmpqrawphmVZc1bEfn56uo9qpyGp1p4xpzOHkSW4ztBd6L7Xx4ACw==} + /diff@5.2.0: + resolution: {integrity: sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==} engines: {node: '>=0.3.1'} dev: true + /diffie-hellman@5.0.3: + resolution: {integrity: sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==} + dependencies: + bn.js: 4.12.0 + miller-rabin: 4.0.1 + randombytes: 2.1.0 + /dir-glob@3.0.1: resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} engines: {node: '>=8'} @@ -2793,31 +3019,31 @@ packages: void-elements: 2.0.1 dev: true - /dom-serializer@1.4.1: - resolution: {integrity: sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==} + /dom-serializer@2.0.0: + resolution: {integrity: sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==} dependencies: domelementtype: 2.3.0 - domhandler: 4.3.1 - entities: 2.2.0 + domhandler: 5.0.3 + entities: 4.5.0 dev: false /domelementtype@2.3.0: resolution: {integrity: sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==} dev: false - /domhandler@4.3.1: - resolution: {integrity: sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==} + /domhandler@5.0.3: + resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==} engines: {node: '>= 4'} dependencies: domelementtype: 2.3.0 dev: false - /domutils@2.8.0: - resolution: {integrity: sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==} + /domutils@3.1.0: + resolution: {integrity: sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==} dependencies: - dom-serializer: 1.4.1 + dom-serializer: 2.0.0 domelementtype: 2.3.0 - domhandler: 4.3.1 + domhandler: 5.0.3 dev: false /dotenv@10.0.0: @@ -2825,6 +3051,10 @@ packages: engines: {node: '>=10'} dev: true + /eastasianwidth@0.2.0: + resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} + dev: true + /ecdsa-sig-formatter@1.0.11: resolution: {integrity: sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==} dependencies: @@ -2838,10 +3068,25 @@ packages: resolution: {integrity: sha512-EeS1oQDCmnYsRDRy2zTeC336a/4LZ6WKqvSaM1jLocEk5ZuyszkQtCpsqvuvaIXGOUjwtvF6LTcS8WueibXvSw==} dev: true + /elliptic@6.5.7: + resolution: {integrity: sha512-ESVCtTwiA+XhY3wyh24QqRGBoP3rEdDUl3EDUUo9tft074fi19IrdpH7hLCMMP3CIj7jb3W96rn8lt/BqIlt5Q==} + dependencies: + bn.js: 4.12.0 + brorand: 1.1.0 + hash.js: 1.1.7 + hmac-drbg: 1.0.1 + inherits: 2.0.4 + minimalistic-assert: 1.0.1 + minimalistic-crypto-utils: 1.0.1 + /emoji-regex@8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} dev: true + /emoji-regex@9.2.2: + resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} + dev: true + /encodeurl@1.0.2: resolution: {integrity: sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==} engines: {node: '>= 0.8'} @@ -2864,12 +3109,12 @@ packages: dependencies: '@types/cookie': 0.4.1 '@types/cors': 2.8.17 - '@types/node': 16.11.7 + '@types/node': 18.19.50 accepts: 1.3.8 base64id: 2.0.0 cookie: 0.4.2 cors: 2.8.5 - debug: 4.3.4(supports-color@9.4.0) + debug: 4.3.7(supports-color@9.4.0) engine.io-parser: 5.2.1 ws: 8.11.0 transitivePeerDependencies: @@ -2898,10 +3143,16 @@ packages: resolution: {integrity: sha512-GHrMyVZQWvTIdDtpiEXdHZnFQKzeO09apj8Cbl4pKWy4i0Oprcq17usfDt5aO63swf0JOeMWjWQE/LzgSRuWpA==} dev: true - /entities@2.2.0: - resolution: {integrity: sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==} + /entities@4.5.0: + resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} + engines: {node: '>=0.12'} dev: false + /env-paths@2.2.1: + resolution: {integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==} + engines: {node: '>=6'} + dev: true + /error-ex@1.3.2: resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==} dependencies: @@ -3003,17 +3254,16 @@ packages: engines: {node: '>=10'} dev: true - /escodegen@1.8.1: - resolution: {integrity: sha512-yhi5S+mNTOuRvyW4gWlg5W1byMaQGWWSYHXsuFZ7GBo7tpyOwi2EdzMP/QWxh9hwkD2m+wDVHJsxhRIj+v/b/A==} - engines: {node: '>=0.12.0'} + /escodegen@2.1.0: + resolution: {integrity: sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==} + engines: {node: '>=6.0'} hasBin: true dependencies: - esprima: 2.7.3 - estraverse: 1.9.3 + esprima: 4.0.1 + estraverse: 5.3.0 esutils: 2.0.3 - optionator: 0.8.3 optionalDependencies: - source-map: 0.2.0 + source-map: 0.6.1 dev: true /eslint-import-resolver-node@0.3.9(supports-color@9.4.0): @@ -3026,7 +3276,7 @@ packages: - supports-color dev: true - /eslint-module-utils@2.8.0(@typescript-eslint/parser@4.13.0)(eslint-import-resolver-node@0.3.9)(eslint@8.1.0)(supports-color@9.4.0): + /eslint-module-utils@2.8.0(@typescript-eslint/parser@6.21.0)(eslint-import-resolver-node@0.3.9)(eslint@8.57.1)(supports-color@9.4.0): resolution: {integrity: sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw==} engines: {node: '>=4'} peerDependencies: @@ -3047,23 +3297,23 @@ packages: eslint-import-resolver-webpack: optional: true dependencies: - '@typescript-eslint/parser': 4.13.0(eslint@8.1.0)(supports-color@9.4.0)(typescript@4.4.4) + '@typescript-eslint/parser': 6.21.0(eslint@8.57.1)(supports-color@9.4.0)(typescript@5.4.2) debug: 3.2.7(supports-color@9.4.0) - eslint: 8.1.0(supports-color@9.4.0) + eslint: 8.57.1(supports-color@9.4.0) eslint-import-resolver-node: 0.3.9(supports-color@9.4.0) transitivePeerDependencies: - supports-color dev: true - /eslint-plugin-header@3.1.1(eslint@8.1.0): + /eslint-plugin-header@3.1.1(eslint@8.57.1): resolution: {integrity: sha512-9vlKxuJ4qf793CmeeSrZUvVClw6amtpghq3CuWcB5cUNnWHQhgcqy5eF8oVKFk1G3Y/CbchGfEaw3wiIJaNmVg==} peerDependencies: eslint: '>=7.7.0' dependencies: - eslint: 8.1.0(supports-color@9.4.0) + eslint: 8.57.1(supports-color@9.4.0) dev: true - /eslint-plugin-import@2.25.2(@typescript-eslint/parser@4.13.0)(eslint@8.1.0)(supports-color@9.4.0): + /eslint-plugin-import@2.25.2(@typescript-eslint/parser@6.21.0)(eslint@8.57.1)(supports-color@9.4.0): resolution: {integrity: sha512-qCwQr9TYfoBHOFcVGKY9C9unq05uOxxdklmBXLVvcwo68y5Hta6/GzCZEMx2zQiu0woKNEER0LE7ZgaOfBU14g==} engines: {node: '>=4'} peerDependencies: @@ -3073,14 +3323,14 @@ packages: '@typescript-eslint/parser': optional: true dependencies: - '@typescript-eslint/parser': 4.13.0(eslint@8.1.0)(supports-color@9.4.0)(typescript@4.4.4) + '@typescript-eslint/parser': 6.21.0(eslint@8.57.1)(supports-color@9.4.0)(typescript@5.4.2) array-includes: 3.1.7 array.prototype.flat: 1.3.2 debug: 2.6.9(supports-color@9.4.0) doctrine: 2.1.0 - eslint: 8.1.0(supports-color@9.4.0) + eslint: 8.57.1(supports-color@9.4.0) eslint-import-resolver-node: 0.3.9(supports-color@9.4.0) - eslint-module-utils: 2.8.0(@typescript-eslint/parser@4.13.0)(eslint-import-resolver-node@0.3.9)(eslint@8.1.0)(supports-color@9.4.0) + eslint-module-utils: 2.8.0(@typescript-eslint/parser@6.21.0)(eslint-import-resolver-node@0.3.9)(eslint@8.57.1)(supports-color@9.4.0) has: 1.0.4 is-core-module: 2.13.1 is-glob: 4.0.3 @@ -3094,16 +3344,16 @@ packages: - supports-color dev: true - /eslint-plugin-no-secrets@0.8.9(eslint@8.1.0): + /eslint-plugin-no-secrets@0.8.9(eslint@8.57.1): resolution: {integrity: sha512-CqaBxXrImABCtxMWspAnm8d5UKkpNylC7zqVveb+fJHEvsSiNGJlSWzdSIvBUnW1XhJXkzifNIZQC08rEII5Ng==} engines: {node: '>=10.0.0', npm: '>=6.9.0'} peerDependencies: eslint: '>=3.0.0' dependencies: - eslint: 8.1.0(supports-color@9.4.0) + eslint: 8.57.1(supports-color@9.4.0) dev: true - /eslint-plugin-prettier@4.0.0(eslint@8.1.0)(prettier@2.4.1): + /eslint-plugin-prettier@4.0.0(eslint@8.57.1)(prettier@2.4.1): resolution: {integrity: sha512-98MqmCJ7vJodoQK359bqQWaxOE0CS8paAz/GgjaZLyex4TTk3g9HugoO89EqWCrFiOqn9EVvcoo7gZzONCWVwQ==} engines: {node: '>=6.0.0'} peerDependencies: @@ -3114,7 +3364,7 @@ packages: eslint-config-prettier: optional: true dependencies: - eslint: 8.1.0(supports-color@9.4.0) + eslint: 8.57.1(supports-color@9.4.0) prettier: 2.4.1 prettier-linter-helpers: 1.0.0 dev: true @@ -3127,63 +3377,53 @@ packages: estraverse: 4.3.0 dev: true - /eslint-scope@6.0.0: - resolution: {integrity: sha512-uRDL9MWmQCkaFus8RF5K9/L/2fn+80yoW3jkD53l4shjCh26fCtvJGasxjUqP5OT87SYTxCVA3BwTUzuELx9kA==} + /eslint-scope@7.2.2: + resolution: {integrity: sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dependencies: esrecurse: 4.3.0 estraverse: 5.3.0 dev: true - /eslint-utils@3.0.0(eslint@8.1.0): - resolution: {integrity: sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==} - engines: {node: ^10.0.0 || ^12.0.0 || >= 14.0.0} - peerDependencies: - eslint: '>=5' - dependencies: - eslint: 8.1.0(supports-color@9.4.0) - eslint-visitor-keys: 2.1.0 - dev: true - - /eslint-visitor-keys@2.1.0: - resolution: {integrity: sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==} - engines: {node: '>=10'} - dev: true - /eslint-visitor-keys@3.4.3: resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dev: true - /eslint@8.1.0(supports-color@9.4.0): - resolution: {integrity: sha512-JZvNneArGSUsluHWJ8g8MMs3CfIEzwaLx9KyH4tZ2i+R2/rPWzL8c0zg3rHdwYVpN/1sB9gqnjHwz9HoeJpGHw==} + /eslint@8.57.1(supports-color@9.4.0): + resolution: {integrity: sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} hasBin: true dependencies: - '@eslint/eslintrc': 1.4.1(supports-color@9.4.0) - '@humanwhocodes/config-array': 0.6.0(supports-color@9.4.0) + '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.1) + '@eslint-community/regexpp': 4.11.1 + '@eslint/eslintrc': 2.1.4(supports-color@9.4.0) + '@eslint/js': 8.57.1 + '@humanwhocodes/config-array': 0.13.0(supports-color@9.4.0) + '@humanwhocodes/module-importer': 1.0.1 + '@nodelib/fs.walk': 1.2.8 + '@ungap/structured-clone': 1.2.0 ajv: 6.12.6 chalk: 4.1.2 cross-spawn: 7.0.3 - debug: 4.3.4(supports-color@9.4.0) + debug: 4.3.7(supports-color@9.4.0) doctrine: 3.0.0 - enquirer: 2.4.1 escape-string-regexp: 4.0.0 - eslint-scope: 6.0.0 - eslint-utils: 3.0.0(eslint@8.1.0) + eslint-scope: 7.2.2 eslint-visitor-keys: 3.4.3 espree: 9.6.1 esquery: 1.5.0 esutils: 2.0.3 fast-deep-equal: 3.1.3 file-entry-cache: 6.0.1 - functional-red-black-tree: 1.0.1 + find-up: 5.0.0 glob-parent: 6.0.2 globals: 13.24.0 - ignore: 4.0.6 - import-fresh: 3.3.0 + graphemer: 1.4.0 + ignore: 5.3.2 imurmurhash: 0.1.4 is-glob: 4.0.3 + is-path-inside: 3.0.3 js-yaml: 4.1.0 json-stable-stringify-without-jsonify: 1.0.1 levn: 0.4.1 @@ -3191,13 +3431,8 @@ packages: minimatch: 3.1.2 natural-compare: 1.4.0 optionator: 0.9.3 - progress: 2.0.3 - regexpp: 3.2.0 - semver: 7.5.4 strip-ansi: 6.0.1 - strip-json-comments: 3.1.1 text-table: 0.2.0 - v8-compile-cache: 2.4.0 transitivePeerDependencies: - supports-color dev: true @@ -3211,12 +3446,6 @@ packages: eslint-visitor-keys: 3.4.3 dev: true - /esprima@2.7.3: - resolution: {integrity: sha512-OarPfz0lFCiW4/AV2Oy1Rp9qu0iusTKqykwTspGCZtPxmF81JR4MmIebvF1F9+UOKth2ZubLQ4XGGaU+hSn99A==} - engines: {node: '>=0.10.0'} - hasBin: true - dev: true - /esprima@4.0.1: resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} engines: {node: '>=4'} @@ -3237,11 +3466,6 @@ packages: estraverse: 5.3.0 dev: true - /estraverse@1.9.3: - resolution: {integrity: sha512-25w1fMXQrGdoquWnScXZGckOv+Wes+JDnuN/+7ex3SauFRS72r2lFDec0EKPt2YD1wUJ/IrfEex+9yp4hfSOJA==} - engines: {node: '>=0.10.0'} - dev: true - /estraverse@4.3.0: resolution: {integrity: sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==} engines: {node: '>=4.0'} @@ -3252,10 +3476,6 @@ packages: engines: {node: '>=4.0'} dev: true - /estree-walker@1.0.1: - resolution: {integrity: sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==} - dev: true - /estree-walker@2.0.2: resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} dev: true @@ -3273,6 +3493,12 @@ packages: resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==} engines: {node: '>=0.8.x'} + /evp_bytestokey@1.0.3: + resolution: {integrity: sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==} + dependencies: + md5.js: 1.3.5 + safe-buffer: 5.2.1 + /execa@5.1.1: resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==} engines: {node: '>=10'} @@ -3297,7 +3523,7 @@ packages: engines: {node: '>= 10.17.0'} hasBin: true dependencies: - debug: 4.3.4(supports-color@9.4.0) + debug: 4.3.7(supports-color@9.4.0) get-stream: 5.2.0 yauzl: 2.10.0 optionalDependencies: @@ -3314,6 +3540,10 @@ packages: resolution: {integrity: sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==} dev: true + /fast-fifo@1.3.2: + resolution: {integrity: sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==} + dev: true + /fast-glob@3.3.2: resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==} engines: {node: '>=8.6.0'} @@ -3404,14 +3634,6 @@ packages: pkg-dir: 4.2.0 dev: true - /find-up@1.1.2: - resolution: {integrity: sha512-jvElSjyuo4EMQGoTwo1uJU5pQMwTW5lS1x05zzfJuTIyLR3zwO27LYrxNg+dlvKpGOuGy/MzBdXh80g0ve5+HA==} - engines: {node: '>=0.10.0'} - dependencies: - path-exists: 2.1.0 - pinkie-promise: 2.0.1 - dev: true - /find-up@4.1.0: resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==} engines: {node: '>=8'} @@ -3446,16 +3668,6 @@ packages: resolution: {integrity: sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==} dev: true - /follow-redirects@1.15.5: - resolution: {integrity: sha512-vSFWUON1B+yAw1VN4xMfxgn5fTUiaOzAJCKBwIIgT/+7CuGy9+r+5gITvP62j3RmaD5Ph65UaERdOSRGUzZtgw==} - engines: {node: '>=4.0'} - peerDependencies: - debug: '*' - peerDependenciesMeta: - debug: - optional: true - dev: true - /follow-redirects@1.15.6: resolution: {integrity: sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==} engines: {node: '>=4.0'} @@ -3479,6 +3691,14 @@ packages: signal-exit: 3.0.7 dev: true + /foreground-child@3.3.0: + resolution: {integrity: sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==} + engines: {node: '>=14'} + dependencies: + cross-spawn: 7.0.3 + signal-exit: 4.1.0 + dev: true + /form-data@4.0.0: resolution: {integrity: sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==} engines: {node: '>= 6'} @@ -3491,10 +3711,6 @@ packages: resolution: {integrity: sha512-cHEpEQHUg0f8XdtZCc2ZAhrHzKzT0MrFUTcvx+hfxYu7rGMDc5SKoXFh+n4YigxsHXRzc6OrCshdR1bWH6HHyg==} dev: true - /fs-constants@1.0.0: - resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==} - dev: true - /fs-extra@10.1.0: resolution: {integrity: sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==} engines: {node: '>=12'} @@ -3504,6 +3720,14 @@ packages: universalify: 2.0.1 dev: true + /fs-extra@11.2.0: + resolution: {integrity: sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==} + engines: {node: '>=14.14'} + dependencies: + graceful-fs: 4.2.11 + jsonfile: 6.1.0 + universalify: 2.0.1 + /fs-extra@7.0.1: resolution: {integrity: sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==} engines: {node: '>=6 <7 || >=8'} @@ -3511,6 +3735,7 @@ packages: graceful-fs: 4.2.11 jsonfile: 4.0.0 universalify: 0.1.2 + dev: true /fs-extra@8.1.0: resolution: {integrity: sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==} @@ -3551,10 +3776,6 @@ packages: functions-have-names: 1.2.3 dev: true - /functional-red-black-tree@1.0.1: - resolution: {integrity: sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==} - dev: true - /functions-have-names@1.2.3: resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} dev: true @@ -3596,11 +3817,6 @@ packages: engines: {node: '>=8.0.0'} dev: true - /get-stdin@4.0.1: - resolution: {integrity: sha512-F5aQMywwJ2n85s4hJPTT9RPxGmubonuB10MNYo17/xph174n2MIR33HRguhzVag10O/npM7SPk73LMZNP+FaWw==} - engines: {node: '>=0.10.0'} - dev: true - /get-stream@5.2.0: resolution: {integrity: sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==} engines: {node: '>=8'} @@ -3621,6 +3837,18 @@ packages: get-intrinsic: 1.2.2 dev: true + /get-uri@6.0.3(supports-color@9.4.0): + resolution: {integrity: sha512-BzUrJBS9EcUb4cFol8r4W3v1cPsSyajLSthNkz5BxbpDcHN5tIrM10E2eNvfnvBn3DaT3DUgx0OpsBKkaOpanw==} + engines: {node: '>= 14'} + dependencies: + basic-ftp: 5.0.5 + data-uri-to-buffer: 6.0.2 + debug: 4.3.7(supports-color@9.4.0) + fs-extra: 11.2.0 + transitivePeerDependencies: + - supports-color + dev: true + /glob-parent@5.1.2: resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} engines: {node: '>= 6'} @@ -3639,18 +3867,21 @@ packages: resolution: {integrity: sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==} dev: true - /glob@5.0.15: - resolution: {integrity: sha512-c9IPMazfRITpmAAKi22dK1VKxGDX9ehhqfABDriL/lzO92xcUKEJPQHrVA/2YHSNFB4iFlykVmWvwo48nr3OxA==} + /glob@11.0.0: + resolution: {integrity: sha512-9UiX/Bl6J2yaBbxKoEBRm4Cipxgok8kQYcOPEhScPwebu2I0HoQOuYdIO6S3hLuWoZgpDpwQZMzTFxgpkyT76g==} + engines: {node: 20 || >=22} + hasBin: true dependencies: - inflight: 1.0.6 - inherits: 2.0.4 - minimatch: 3.1.2 - once: 1.4.0 - path-is-absolute: 1.0.1 + foreground-child: 3.3.0 + jackspeak: 4.0.2 + minimatch: 10.0.1 + minipass: 7.1.2 + package-json-from-dist: 1.0.1 + path-scurry: 2.0.0 dev: true - /glob@7.2.0: - resolution: {integrity: sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==} + /glob@7.2.3: + resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} dependencies: fs.realpath: 1.0.0 inflight: 1.0.6 @@ -3660,15 +3891,16 @@ packages: path-is-absolute: 1.0.1 dev: true - /glob@7.2.3: - resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} + /glob@8.1.0: + resolution: {integrity: sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==} + engines: {node: '>=12'} + deprecated: Glob versions prior to v9 are no longer supported dependencies: fs.realpath: 1.0.0 inflight: 1.0.6 inherits: 2.0.4 - minimatch: 3.1.2 + minimatch: 5.1.6 once: 1.4.0 - path-is-absolute: 1.0.1 dev: true /globalize@1.7.0: @@ -3703,7 +3935,7 @@ packages: array-union: 2.1.0 dir-glob: 3.0.1 fast-glob: 3.3.2 - ignore: 5.3.0 + ignore: 5.3.2 merge2: 1.4.1 slash: 3.0.0 dev: true @@ -3738,33 +3970,14 @@ packages: resolution: {integrity: sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==} dev: false - /growl@1.10.5: - resolution: {integrity: sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==} - engines: {node: '>=4.x'} - dev: true - - /handlebars@4.7.8: - resolution: {integrity: sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==} - engines: {node: '>=0.4.7'} - hasBin: true - dependencies: - minimist: 1.2.8 - neo-async: 2.6.2 - source-map: 0.6.1 - wordwrap: 1.0.0 - optionalDependencies: - uglify-js: 3.17.4 + /graphemer@1.4.0: + resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} dev: true /has-bigints@1.0.2: resolution: {integrity: sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==} dev: true - /has-flag@1.0.0: - resolution: {integrity: sha512-DyYHfIYwAJmjAjSSPKANxI8bFY9YtFrgkAfinBojQ8YJTOuOuav64tMUJv584SES4xl74PmuaevIyaLESHdTAA==} - engines: {node: '>=0.10.0'} - dev: true - /has-flag@3.0.0: resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==} engines: {node: '>=4'} @@ -3803,6 +4016,27 @@ packages: engines: {node: '>= 0.4.0'} dev: true + /hash-base@3.0.4: + resolution: {integrity: sha512-EeeoJKjTyt868liAlVmcv2ZsUfGHlE3Q+BICOXcZiwN3osr5Q/zFGYmTJpoIzuaSTAwndFy+GqhEwlU4L3j4Ow==} + engines: {node: '>=4'} + dependencies: + inherits: 2.0.4 + safe-buffer: 5.2.1 + + /hash-base@3.1.0: + resolution: {integrity: sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==} + engines: {node: '>=4'} + dependencies: + inherits: 2.0.4 + readable-stream: 3.6.2 + safe-buffer: 5.2.1 + + /hash.js@1.1.7: + resolution: {integrity: sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==} + dependencies: + inherits: 2.0.4 + minimalistic-assert: 1.0.1 + /hasha@5.2.2: resolution: {integrity: sha512-Hrp5vIK/xr5SkeN2onO32H0MgNZ0f17HRNH39WfL0SYUNOTZ5Lz1TJ8Pajo/87dYGEFlLMm7mIc/k/s6Bvz9HQ==} engines: {node: '>=8'} @@ -3823,21 +4057,24 @@ packages: hasBin: true dev: true - /hosted-git-info@2.8.9: - resolution: {integrity: sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==} - dev: true + /hmac-drbg@1.0.1: + resolution: {integrity: sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==} + dependencies: + hash.js: 1.1.7 + minimalistic-assert: 1.0.1 + minimalistic-crypto-utils: 1.0.1 /html-escaper@2.0.2: resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==} dev: true - /htmlparser2@6.1.0: - resolution: {integrity: sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==} + /htmlparser2@9.1.0: + resolution: {integrity: sha512-5zfg6mHUoaer/97TxnGpxmbR7zJtPwIYFMZ/H5ucTlPZhKvtum05yiPK3Mgai3a0DyVxv7qYqoweaEd2nrYQzQ==} dependencies: domelementtype: 2.3.0 - domhandler: 4.3.1 - domutils: 2.8.0 - entities: 2.2.0 + domhandler: 5.0.3 + domutils: 3.1.0 + entities: 4.5.0 dev: false /http-cache-semantics@4.1.1: @@ -3861,16 +4098,26 @@ packages: dependencies: '@tootallnate/once': 2.0.0 agent-base: 6.0.2(supports-color@9.4.0) - debug: 4.3.4(supports-color@9.4.0) + debug: 4.3.7(supports-color@9.4.0) + transitivePeerDependencies: + - supports-color + + /http-proxy-agent@7.0.2(supports-color@9.4.0): + resolution: {integrity: sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==} + engines: {node: '>= 14'} + dependencies: + agent-base: 7.1.0(supports-color@9.4.0) + debug: 4.3.7(supports-color@9.4.0) transitivePeerDependencies: - supports-color + dev: true /http-proxy@1.18.1: resolution: {integrity: sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==} engines: {node: '>=8.0.0'} dependencies: eventemitter3: 4.0.7 - follow-redirects: 1.15.5 + follow-redirects: 1.15.6 requires-port: 1.0.0 transitivePeerDependencies: - debug @@ -3878,37 +4125,30 @@ packages: /http2-wrapper@1.0.3: resolution: {integrity: sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==} - engines: {node: '>=10.19.0'} - dependencies: - quick-lru: 5.1.1 - resolve-alpn: 1.2.1 - dev: true - - /https-proxy-agent@5.0.0(supports-color@9.4.0): - resolution: {integrity: sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==} - engines: {node: '>= 6'} - dependencies: - agent-base: 6.0.2(supports-color@9.4.0) - debug: 4.3.4(supports-color@9.4.0) - transitivePeerDependencies: - - supports-color + engines: {node: '>=10.19.0'} + dependencies: + quick-lru: 5.1.1 + resolve-alpn: 1.2.1 dev: true + /https-browserify@1.0.0: + resolution: {integrity: sha512-J+FkSdyD+0mA0N+81tMotaRMfSL9SGi+xpD3T6YApKsc3bGSXJlfXri3VyFOeYkfLRQisDk1W+jIFFKBeUBbBg==} + /https-proxy-agent@5.0.1(supports-color@9.4.0): resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==} engines: {node: '>= 6'} dependencies: agent-base: 6.0.2(supports-color@9.4.0) - debug: 4.3.4(supports-color@9.4.0) + debug: 4.3.7(supports-color@9.4.0) transitivePeerDependencies: - supports-color - /https-proxy-agent@7.0.4(supports-color@9.4.0): - resolution: {integrity: sha512-wlwpilI7YdjSkWaQ/7omYBMTliDcmCN8OLihO6I9B86g06lMyAoqgoDpV0XqoaPOKj+0DIdAvnsWfyAAhmimcg==} + /https-proxy-agent@7.0.5(supports-color@9.4.0): + resolution: {integrity: sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw==} engines: {node: '>= 14'} dependencies: agent-base: 7.1.0(supports-color@9.4.0) - debug: 4.3.4(supports-color@9.4.0) + debug: 4.3.7(supports-color@9.4.0) transitivePeerDependencies: - supports-color @@ -3929,17 +4169,13 @@ packages: engines: {node: '>=0.10.0'} dependencies: safer-buffer: 2.1.2 + dev: true /ieee754@1.2.1: resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} - /ignore@4.0.6: - resolution: {integrity: sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==} - engines: {node: '>= 4'} - dev: true - - /ignore@5.3.0: - resolution: {integrity: sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg==} + /ignore@5.3.2: + resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} engines: {node: '>= 4'} dev: true @@ -3961,13 +4197,6 @@ packages: engines: {node: '>=0.8.19'} dev: true - /indent-string@2.1.0: - resolution: {integrity: sha512-aqwDFWSgSgfRaEwao5lg5KEcVd/2a+D1rvoG7NdilmYz0NwRk6StWpWdz/Hpk34MKPpx7s8XxUqimfcQK6gGlg==} - engines: {node: '>=0.10.0'} - dependencies: - repeating: 2.0.1 - dev: true - /indent-string@4.0.0: resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==} engines: {node: '>=8'} @@ -3992,6 +4221,14 @@ packages: side-channel: 1.0.4 dev: true + /ip-address@9.0.5: + resolution: {integrity: sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==} + engines: {node: '>= 12'} + dependencies: + jsbn: 1.1.0 + sprintf-js: 1.1.3 + dev: true + /is-array-buffer@3.0.2: resolution: {integrity: sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==} dependencies: @@ -4063,11 +4300,6 @@ packages: engines: {node: '>=0.10.0'} dev: true - /is-finite@1.1.0: - resolution: {integrity: sha512-cdyMtqX/BOqqNBBiKlIVkytNHm49MtMlYyn1zxzvJKWmFMlGzm+ry5BBfYyeY9YmNKbRSo/o7OX9w9ale0wg3w==} - engines: {node: '>=0.10.0'} - dev: true - /is-fullwidth-code-point@3.0.0: resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} engines: {node: '>=8'} @@ -4102,6 +4334,11 @@ packages: engines: {node: '>=0.10.0'} dev: true + /is-path-inside@3.0.3: + resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==} + engines: {node: '>=8'} + dev: true + /is-plain-obj@2.1.0: resolution: {integrity: sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==} engines: {node: '>=8'} @@ -4161,10 +4398,6 @@ packages: engines: {node: '>=10'} dev: true - /is-utf8@0.2.1: - resolution: {integrity: sha512-rMYPYvCzsXywIsldgLaSoPlw5PfoB/ssr7hY4pLfcodrA5M/eArza1a9VmTiNIBNMjOGr1Ow9mTyU2o69U6U9Q==} - dev: true - /is-weakref@1.0.2: resolution: {integrity: sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==} dependencies: @@ -4182,9 +4415,8 @@ packages: dependencies: is-docker: 2.2.1 - /isarray@0.0.1: - resolution: {integrity: sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==} - dev: true + /isarray@1.0.0: + resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==} /isarray@2.0.5: resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==} @@ -4208,11 +4440,6 @@ packages: - encoding dev: true - /istanbul-lib-coverage@2.0.5: - resolution: {integrity: sha512-8aXznuEPCJvGnMSRft4udDRDtb1V3pkQkMMI5LI+6HuQz5oQ4J2UFn1H82raA3qJtyOLkkwVqICBQkjnGtn5mA==} - engines: {node: '>=6'} - dev: true - /istanbul-lib-coverage@3.2.2: resolution: {integrity: sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==} engines: {node: '>=8'} @@ -4225,26 +4452,24 @@ packages: append-transform: 2.0.0 dev: true - /istanbul-lib-instrument@3.3.0(supports-color@9.4.0): - resolution: {integrity: sha512-5nnIN4vo5xQZHdXno/YDXJ0G+I3dAm4XgzfSVTPLQpj/zAV2dV6Juy0yaf10/zrJOJeHoN3fraFe+XRq2bFVZA==} - engines: {node: '>=6'} + /istanbul-lib-instrument@4.0.3(supports-color@9.4.0): + resolution: {integrity: sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ==} + engines: {node: '>=8'} dependencies: - '@babel/generator': 7.23.6 - '@babel/parser': 7.23.6 - '@babel/template': 7.22.15 - '@babel/traverse': 7.23.7(supports-color@9.4.0) - '@babel/types': 7.23.6 - istanbul-lib-coverage: 2.0.5 + '@babel/core': 7.23.7(supports-color@9.4.0) + '@istanbuljs/schema': 0.1.3 + istanbul-lib-coverage: 3.2.2 semver: 6.3.1 transitivePeerDependencies: - supports-color dev: true - /istanbul-lib-instrument@4.0.3(supports-color@9.4.0): - resolution: {integrity: sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ==} + /istanbul-lib-instrument@5.2.1(supports-color@9.4.0): + resolution: {integrity: sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==} engines: {node: '>=8'} dependencies: '@babel/core': 7.23.7(supports-color@9.4.0) + '@babel/parser': 7.23.6 '@istanbuljs/schema': 0.1.3 istanbul-lib-coverage: 3.2.2 semver: 6.3.1 @@ -4264,15 +4489,6 @@ packages: uuid: 8.3.2 dev: true - /istanbul-lib-report@2.0.8: - resolution: {integrity: sha512-fHBeG573EIihhAblwgxrSenp0Dby6tJMFR/HvlerBsrCTD5bkUuoNtn3gVh29ZCS824cGGBPn7Sg7cNk+2xUsQ==} - engines: {node: '>=6'} - dependencies: - istanbul-lib-coverage: 2.0.5 - make-dir: 2.1.0 - supports-color: 6.1.0 - dev: true - /istanbul-lib-report@3.0.1: resolution: {integrity: sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==} engines: {node: '>=10'} @@ -4282,19 +4498,6 @@ packages: supports-color: 7.2.0 dev: true - /istanbul-lib-source-maps@3.0.6(supports-color@9.4.0): - resolution: {integrity: sha512-R47KzMtDJH6X4/YW9XTx+jrLnZnscW4VpNN+1PViSYTejLVPWv7oov+Duf8YQSPyVRUvueQqz1TcsC6mooZTXw==} - engines: {node: '>=6'} - dependencies: - debug: 4.3.4(supports-color@9.4.0) - istanbul-lib-coverage: 2.0.5 - make-dir: 2.1.0 - rimraf: 2.7.1 - source-map: 0.6.1 - transitivePeerDependencies: - - supports-color - dev: true - /istanbul-lib-source-maps@4.0.1(supports-color@9.4.0): resolution: {integrity: sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==} engines: {node: '>=10'} @@ -4306,13 +4509,6 @@ packages: - supports-color dev: true - /istanbul-reports@2.2.7: - resolution: {integrity: sha512-uu1F/L1o5Y6LzPVSVZXNOoD/KXpJue9aeLRd0sM9uMXfZvzomB0WxVamWb5ue8kA2vVWEmW7EG+A5n3f1kqHKg==} - engines: {node: '>=6'} - dependencies: - html-escaper: 2.0.2 - dev: true - /istanbul-reports@3.1.6: resolution: {integrity: sha512-TLgnMkKg3iTDsQ9PbPTdpfAK2DzjF9mqUG7RMgcQl8oFjad8ob4laGxv5XV5U9MAfx8D6tSJiUyuAwzLicaxlg==} engines: {node: '>=8'} @@ -4321,35 +4517,18 @@ packages: istanbul-lib-report: 3.0.1 dev: true - /istanbul@0.4.5: - resolution: {integrity: sha512-nMtdn4hvK0HjUlzr1DrKSUY8ychprt8dzHOgY2KXsIhHu5PuQQEOTM27gV9Xblyon7aUH/TSFIjRHEODF/FRPg==} - deprecated: |- - This module is no longer maintained, try this instead: - npm i nyc - Visit https://istanbul.js.org/integrations for other alternatives. - hasBin: true + /jackspeak@4.0.2: + resolution: {integrity: sha512-bZsjR/iRjl1Nk1UkjGpAzLNfQtzuijhn2g+pbZb98HQ1Gk8vM9hfbxeMBP+M2/UUdwj0RqGG3mlvk2MsAqwvEw==} + engines: {node: 20 || >=22} dependencies: - abbrev: 1.0.9 - async: 1.5.2 - escodegen: 1.8.1 - esprima: 2.7.3 - glob: 5.0.15 - handlebars: 4.7.8 - js-yaml: 3.14.1 - mkdirp: 0.5.6 - nopt: 3.0.6 - once: 1.4.0 - resolve: 1.1.7 - supports-color: 3.2.3 - which: 1.3.1 - wordwrap: 1.0.0 + '@isaacs/cliui': 8.0.2 dev: true /jest-worker@27.5.1: resolution: {integrity: sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==} engines: {node: '>= 10.13.0'} dependencies: - '@types/node': 16.11.7 + '@types/node': 18.19.50 merge-stream: 2.0.0 supports-color: 8.1.1 dev: true @@ -4377,9 +4556,9 @@ packages: argparse: 2.0.1 dev: true - /jsbi@3.2.5: - resolution: {integrity: sha512-aBE4n43IPvjaddScbvWRA2YlTzKEynHzu7MqOyTipdHucf/VxS63ViCjxYRg86M8Rxwbt/GfzHl1kKERkt45fQ==} - dev: false + /jsbn@1.1.0: + resolution: {integrity: sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==} + dev: true /jsesc@2.5.2: resolution: {integrity: sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==} @@ -4399,6 +4578,10 @@ packages: resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} dev: true + /json-schema-traverse@1.0.0: + resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} + dev: true + /json-stable-stringify-without-jsonify@1.0.1: resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} dev: true @@ -4424,6 +4607,7 @@ packages: resolution: {integrity: sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==} optionalDependencies: graceful-fs: 4.2.11 + dev: true /jsonfile@6.1.0: resolution: {integrity: sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==} @@ -4431,7 +4615,6 @@ packages: universalify: 2.0.1 optionalDependencies: graceful-fs: 4.2.11 - dev: true /jsonwebtoken@9.0.2: resolution: {integrity: sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==} @@ -4446,15 +4629,15 @@ packages: lodash.isstring: 4.0.1 lodash.once: 4.1.1 ms: 2.1.3 - semver: 7.5.4 + semver: 7.6.3 /jspath@0.4.0: resolution: {integrity: sha512-2/R8wkot8NCXrppBT/onp+4mcAUAZqtPxsW6aSJU3hrFAVqKqtFYcat2XJZ7inN4RtATUxfv0UQSYOmvJKiIGA==} engines: {node: '>= 0.4.0'} dev: false - /just-extend@4.2.1: - resolution: {integrity: sha512-g3UB796vUFIY90VIv/WX3L2c8CS2MdWUww3CNrYmqza1Fg0DURc2K/O4YrnklBdQarSJ/y8JnJYDGc+1iumQjg==} + /just-extend@6.2.0: + resolution: {integrity: sha512-cYofQu2Xpom82S6qD778jBDpwvvy39s1l/hrYij2u9AMdQcGRpaBu6kY4mVhuno5kJVi1DAz4aiphA2WI1/OAw==} dev: true /jwa@1.4.1: @@ -4490,8 +4673,9 @@ packages: jwt-simple: 0.5.6 dev: true - /jwt-decode@3.1.2: - resolution: {integrity: sha512-UfpWE/VZn0iP50d8cz9NrZLM9lSWhcJ+0Gt/nm4by88UL+J1SiKN8/5dkjMmbEzwL2CAe+67GsegCbIKtbp75A==} + /jwt-decode@4.0.0: + resolution: {integrity: sha512-+KJGIyHgkGuIq3IEBNftfhW/LfWhXUIY6OmyVWjliu5KH1y0fw7VQ8YndE2O4qZdMSd9SqbnC8GOcZEy0Om7sA==} + engines: {node: '>=18'} dev: false /jwt-simple@0.5.6: @@ -4499,8 +4683,8 @@ packages: engines: {node: '>= 0.4.0'} dev: true - /karma-chrome-launcher@3.1.0: - resolution: {integrity: sha512-3dPs/n7vgz1rxxtynpzZTvb9y/GIaW8xjAwcIGttLbycqoFtI7yo1NGnQi6oFTherRE+GIhCAHZC4vEqWGhNvg==} + /karma-chrome-launcher@3.2.0: + resolution: {integrity: sha512-rE9RkUPI7I9mAxByQWkGJFXfFD6lE4gC5nPuZdobf/QdTEJI6EU4yIay/cfU/xV4ZxlM5JiTv7zWYgA64NpS5Q==} dependencies: which: 1.3.1 dev: true @@ -4513,20 +4697,16 @@ packages: resolve: 1.22.8 dev: true - /karma-coverage@2.0.0(supports-color@9.4.0): - resolution: {integrity: sha512-FFQJPrf0SDjWVVMZxqPz9ry04OjSGYEqY6uvhU9fdBYRo/RNHWayU+Jq/7E55v5zDcwN6orfTDeUrd9zWtZAkg==} - engines: {node: '>=8.0.0'} + /karma-coverage@2.2.1(supports-color@9.4.0): + resolution: {integrity: sha512-yj7hbequkQP2qOSb20GuNSIyE//PgJWHwC2IydLE6XRtsnaflv+/OSGNssPjobYUlhVVagy99TQpqUt3vAUG7A==} + engines: {node: '>=10.0.0'} dependencies: - dateformat: 1.0.12 - istanbul: 0.4.5 - istanbul-lib-coverage: 2.0.5 - istanbul-lib-instrument: 3.3.0(supports-color@9.4.0) - istanbul-lib-report: 2.0.8 - istanbul-lib-source-maps: 3.0.6(supports-color@9.4.0) - istanbul-reports: 2.2.7 - lodash: 4.17.21 + istanbul-lib-coverage: 3.2.2 + istanbul-lib-instrument: 5.2.1(supports-color@9.4.0) + istanbul-lib-report: 3.0.1 + istanbul-lib-source-maps: 4.0.1(supports-color@9.4.0) + istanbul-reports: 3.1.6 minimatch: 3.1.2 - source-map: 0.5.7 transitivePeerDependencies: - supports-color dev: true @@ -4535,24 +4715,24 @@ packages: resolution: {integrity: sha512-3FAuA0B1lS4DXNyOpD1Y+BjteVmnfX0WXUpsZ19aYykTk/GPz0kqnjzdApDiEe4sapreVeVSme2qTALnbHJb/A==} dev: true - /karma-junit-reporter@2.0.1(karma@6.3.16): + /karma-junit-reporter@2.0.1(karma@6.4.4): resolution: {integrity: sha512-VtcGfE0JE4OE1wn0LK8xxDKaTP7slN8DO3I+4xg6gAi1IoAHAXOJ1V9G/y45Xg6sxdxPOR3THCFtDlAfBo9Afw==} engines: {node: '>= 8'} peerDependencies: karma: '>=0.9' dependencies: - karma: 6.3.16(supports-color@9.4.0) + karma: 6.4.4(supports-color@9.4.0) path-is-absolute: 1.0.1 xmlbuilder: 12.0.0 dev: true - /karma-mocha-reporter@2.2.5(karma@6.3.16): + /karma-mocha-reporter@2.2.5(karma@6.4.4): resolution: {integrity: sha512-Hr6nhkIp0GIJJrvzY8JFeHpQZNseuIakGac4bpw8K1+5F0tLb6l7uvXRa8mt2Z+NVwYgCct4QAfp2R2QP6o00w==} peerDependencies: karma: '>=0.13' dependencies: chalk: 2.4.2 - karma: 6.3.16(supports-color@9.4.0) + karma: 6.4.4(supports-color@9.4.0) log-symbols: 2.2.0 strip-ansi: 4.0.0 dev: true @@ -4563,33 +4743,33 @@ packages: minimist: 1.2.8 dev: true - /karma-sourcemap-loader@0.3.8: - resolution: {integrity: sha512-zorxyAakYZuBcHRJE+vbrK2o2JXLFWK8VVjiT/6P+ltLBUGUvqTEkUiQ119MGdOrK7mrmxXHZF1/pfT6GgIZ6g==} + /karma-sourcemap-loader@0.4.0: + resolution: {integrity: sha512-xCRL3/pmhAYF3I6qOrcn0uhbQevitc2DERMPH82FMnG+4WReoGcGFZb1pURf2a5apyrOHRdvD+O6K7NljqKHyA==} dependencies: graceful-fs: 4.2.11 dev: true - /karma-webpack@5.0.0(webpack@5.76.0): - resolution: {integrity: sha512-+54i/cd3/piZuP3dr54+NcFeKOPnys5QeM1IY+0SPASwrtHsliXUiCL50iW+K9WWA7RvamC4macvvQ86l3KtaA==} - engines: {node: '>= 6'} + /karma-webpack@5.0.1(webpack@5.76.0): + resolution: {integrity: sha512-oo38O+P3W2mSPCSUrQdySSPv1LvPpXP+f+bBimNomS5sW+1V4SuhCuW8TfJzV+rDv921w2fDSDw0xJbPe6U+kQ==} + engines: {node: '>= 18'} peerDependencies: webpack: ^5.0.0 dependencies: glob: 7.2.3 - minimatch: 3.1.2 + minimatch: 9.0.5 webpack: 5.76.0 webpack-merge: 4.2.2 dev: true - /karma@6.3.16(supports-color@9.4.0): - resolution: {integrity: sha512-nEU50jLvDe5yvXqkEJRf8IuvddUkOY2x5Xc4WXHz6dxINgGDrgD2uqQWeVrJs4hbfNaotn+HQ1LZJ4yOXrL7xQ==} + /karma@6.4.4(supports-color@9.4.0): + resolution: {integrity: sha512-LrtUxbdvt1gOpo3gxG+VAJlJAEMhbWlM4YrFQgql98FwF7+K8K12LYO4hnDdUkNjeztYrOXEMqgTajSWgmtI/w==} engines: {node: '>= 10'} hasBin: true dependencies: + '@colors/colors': 1.5.0 body-parser: 1.20.2(supports-color@9.4.0) braces: 3.0.2 chokidar: 3.5.3 - colors: 1.4.0 connect: 3.7.0(supports-color@9.4.0) di: 0.0.1 dom-serialize: 2.2.1 @@ -4628,14 +4808,6 @@ packages: engines: {node: '> 0.8'} dev: true - /levn@0.3.0: - resolution: {integrity: sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==} - engines: {node: '>= 0.8.0'} - dependencies: - prelude-ls: 1.1.2 - type-check: 0.3.2 - dev: true - /levn@0.4.1: resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} engines: {node: '>= 0.8.0'} @@ -4688,17 +4860,6 @@ packages: wrap-ansi: 7.0.0 dev: true - /load-json-file@1.1.0: - resolution: {integrity: sha512-cy7ZdNRXdablkXYNI049pthVeXFurRyb9+hA/dZzerZ0pGTx42z+y+ssxBaVV2l70t1muq5IdKhn4UtcoGUY9A==} - engines: {node: '>=0.10.0'} - dependencies: - graceful-fs: 4.2.11 - parse-json: 2.2.0 - pify: 2.3.0 - pinkie-promise: 2.0.1 - strip-bom: 2.0.0 - dev: true - /loader-runner@4.3.0: resolution: {integrity: sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==} engines: {node: '>=6.11.5'} @@ -4742,6 +4903,7 @@ packages: /lodash.isequal@4.5.0: resolution: {integrity: sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==} + dev: false /lodash.isfunction@3.0.9: resolution: {integrity: sha512-AirXNj15uRIMMPihnkInB4i3NHeb4iBtNg9WRWuK2o31S+ePwwNmDPaTL3o7dTJ+VXNZim7rFs4rxN4YU1oUJw==} @@ -4838,19 +5000,16 @@ packages: js-tokens: 4.0.0 dev: true - /loud-rejection@1.6.0: - resolution: {integrity: sha512-RPNliZOFkqFumDhvYqOaNY4Uz9oJM2K9tC6JWsJJsNdhuONW4LQHRBpb0qf4pJApVffI5N39SwzWZJuEhfd7eQ==} - engines: {node: '>=0.10.0'} - dependencies: - currently-unhandled: 0.4.1 - signal-exit: 3.0.7 - dev: true - /lowercase-keys@2.0.0: resolution: {integrity: sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==} engines: {node: '>=8'} dev: true + /lru-cache@11.0.1: + resolution: {integrity: sha512-CgeuL5uom6j/ZVrg7G/+1IXqRY8JXX4Hghfy5YE0EhoYQWvndP1kufu58cmZLNIDKnRhZrXfdS9urVWx98AipQ==} + engines: {node: 20 || >=22} + dev: true + /lru-cache@5.1.1: resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} dependencies: @@ -4861,13 +5020,11 @@ packages: engines: {node: '>=10'} dependencies: yallist: 4.0.0 + dev: true - /make-dir@2.1.0: - resolution: {integrity: sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==} - engines: {node: '>=6'} - dependencies: - pify: 4.0.1 - semver: 5.7.2 + /lru-cache@7.18.3: + resolution: {integrity: sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==} + engines: {node: '>=12'} dev: true /make-dir@3.1.0: @@ -4881,39 +5038,25 @@ packages: resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==} engines: {node: '>=10'} dependencies: - semver: 7.5.4 + semver: 7.6.3 dev: true /make-error@1.3.6: resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==} dev: true - /map-obj@1.0.1: - resolution: {integrity: sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg==} - engines: {node: '>=0.10.0'} - dev: true + /md5.js@1.3.5: + resolution: {integrity: sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==} + dependencies: + hash-base: 3.1.0 + inherits: 2.0.4 + safe-buffer: 5.2.1 /media-typer@0.3.0: resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==} engines: {node: '>= 0.6'} dev: true - /meow@3.7.0: - resolution: {integrity: sha512-TNdwZs0skRlpPpCUK25StC4VH+tP5GgeY1HQOOGP+lQ2xtdkN2VtT/5tiX9k3IWpkBPV9b3LsAWXn4GGi/PrSA==} - engines: {node: '>=0.10.0'} - dependencies: - camelcase-keys: 2.1.0 - decamelize: 1.2.0 - loud-rejection: 1.6.0 - map-obj: 1.0.1 - minimist: 1.2.8 - normalize-package-data: 2.5.0 - object-assign: 4.1.1 - read-pkg-up: 1.0.1 - redent: 1.0.0 - trim-newlines: 1.0.0 - dev: true - /merge-stream@2.0.0: resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} dev: true @@ -4931,6 +5074,13 @@ packages: picomatch: 2.3.1 dev: true + /miller-rabin@4.0.1: + resolution: {integrity: sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==} + hasBin: true + dependencies: + bn.js: 4.12.0 + brorand: 1.1.0 + /mime-db@1.52.0: resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} engines: {node: '>= 0.6'} @@ -4962,6 +5112,19 @@ packages: engines: {node: '>=10'} dev: true + /minimalistic-assert@1.0.1: + resolution: {integrity: sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==} + + /minimalistic-crypto-utils@1.0.1: + resolution: {integrity: sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==} + + /minimatch@10.0.1: + resolution: {integrity: sha512-ethXTt3SGGR+95gudmqJ1eNhRO7eGEGIgYA9vnPatK4/etz2MEVDno5GMCibdMTuBMyElzIlgxMna3K94XDIDQ==} + engines: {node: 20 || >=22} + dependencies: + brace-expansion: 2.0.1 + dev: true + /minimatch@3.0.4: resolution: {integrity: sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==} dependencies: @@ -4974,12 +5137,38 @@ packages: brace-expansion: 1.1.11 dev: true + /minimatch@5.1.6: + resolution: {integrity: sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==} + engines: {node: '>=10'} + dependencies: + brace-expansion: 2.0.1 + dev: true + + /minimatch@9.0.3: + resolution: {integrity: sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==} + engines: {node: '>=16 || 14 >=14.17'} + dependencies: + brace-expansion: 2.0.1 + dev: true + + /minimatch@9.0.5: + resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} + engines: {node: '>=16 || 14 >=14.17'} + dependencies: + brace-expansion: 2.0.1 + dev: true + /minimist@1.2.8: resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} dev: true - /mkdirp-classic@0.5.3: - resolution: {integrity: sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==} + /minipass@7.1.2: + resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} + engines: {node: '>=16 || 14 >=14.17'} + dev: true + + /mitt@3.0.1: + resolution: {integrity: sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==} dev: true /mkdirp@0.5.6: @@ -4989,7 +5178,7 @@ packages: minimist: 1.2.8 dev: true - /mocha-multi-reporters@1.5.1(mocha@9.2.0)(supports-color@9.4.0): + /mocha-multi-reporters@1.5.1(mocha@10.7.3)(supports-color@9.4.0): resolution: {integrity: sha512-Yb4QJOaGLIcmB0VY7Wif5AjvLMUFAdV57D2TWEva1Y0kU/3LjKpeRVmlMIfuO1SVbauve459kgtIizADqxMWPg==} engines: {node: '>=6.0.0'} peerDependencies: @@ -4997,39 +5186,35 @@ packages: dependencies: debug: 4.3.4(supports-color@9.4.0) lodash: 4.17.21 - mocha: 9.2.0 + mocha: 10.7.3 transitivePeerDependencies: - supports-color dev: true - /mocha@9.2.0: - resolution: {integrity: sha512-kNn7E8g2SzVcq0a77dkphPsDSN7P+iYkqE0ZsGCYWRsoiKjOt+NvXfaagik8vuDa6W5Zw3qxe8Jfpt5qKf+6/Q==} - engines: {node: '>= 12.0.0'} + /mocha@10.7.3: + resolution: {integrity: sha512-uQWxAu44wwiACGqjbPYmjo7Lg8sFrS3dQe7PP2FQI+woptP4vZXSMcfMyFL/e1yFEeEpV4RtyTpZROOKmxis+A==} + engines: {node: '>= 14.0.0'} hasBin: true dependencies: - '@ungap/promise-all-settled': 1.1.2 - ansi-colors: 4.1.1 + ansi-colors: 4.1.3 browser-stdout: 1.3.1 chokidar: 3.5.3 - debug: 4.3.3(supports-color@8.1.1) - diff: 5.0.0 + debug: 4.3.7(supports-color@8.1.1) + diff: 5.2.0 escape-string-regexp: 4.0.0 find-up: 5.0.0 - glob: 7.2.0 - growl: 1.10.5 + glob: 8.1.0 he: 1.2.0 js-yaml: 4.1.0 log-symbols: 4.1.0 - minimatch: 3.0.4 + minimatch: 5.1.6 ms: 2.1.3 - nanoid: 3.2.0 - serialize-javascript: 6.0.0 + serialize-javascript: 6.0.2 strip-json-comments: 3.1.1 supports-color: 8.1.1 - which: 2.0.2 - workerpool: 6.2.0 + workerpool: 6.5.1 yargs: 16.2.0 - yargs-parser: 20.2.4 + yargs-parser: 20.2.9 yargs-unparser: 2.0.0 dev: true @@ -5051,8 +5236,8 @@ packages: yargs: 17.2.1 dev: true - /mochawesome@7.0.1(mocha@9.2.0): - resolution: {integrity: sha512-2FTU7KVNDiKohi4IG3IVmJ2OTy0Nm0Q2RjueK9hsj7blbkcrpFVH209cP8P4egi+LBidKdX+QmtN3thJde2yiQ==} + /mochawesome@7.1.3(mocha@10.7.3): + resolution: {integrity: sha512-Vkb3jR5GZ1cXohMQQ73H3cZz7RoxGjjUo0G5hu0jLaW+0FdUxUwg3Cj29bqQdh0rFcnyV06pWmqmi5eBPnEuNQ==} peerDependencies: mocha: '>=7' dependencies: @@ -5063,7 +5248,7 @@ packages: lodash.isfunction: 3.0.9 lodash.isobject: 3.0.2 lodash.isstring: 4.0.1 - mocha: 9.2.0 + mocha: 10.7.3 mochawesome-report-generator: 6.2.0 strip-ansi: 6.0.1 uuid: 8.3.2 @@ -5091,16 +5276,10 @@ packages: /ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} - /nanoid@3.2.0: - resolution: {integrity: sha512-fmsZYa9lpn69Ad5eDn7FMcnnSR+8R34W9qJEijxYhTbfOWzr22n1QxCMzXLK+ODyW2973V3Fux959iQoUxzUIA==} - engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} - hasBin: true + /natural-compare-lite@1.4.0: + resolution: {integrity: sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==} dev: true - /native-duplexpair@1.0.0: - resolution: {integrity: sha512-E7QQoM+3jvNtlmyfqRZ0/U75VFgCls+fSkbml2MpgWkWyz3ox8Y58gNhfuziuQYGNNQAbFZJQck55LHCnCK6CA==} - dev: false - /natural-compare@1.4.0: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} dev: true @@ -5114,30 +5293,19 @@ packages: resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==} dev: true - /nise@5.1.4: - resolution: {integrity: sha512-8+Ib8rRJ4L0o3kfmyVCL7gzrohyDe0cMFTBa2d364yIrEGMEoetznKJx899YxjybU6bL9SQkYPSBBs1gyYs8Xg==} - dependencies: - '@sinonjs/commons': 2.0.0 - '@sinonjs/fake-timers': 10.3.0 - '@sinonjs/text-encoding': 0.7.2 - just-extend: 4.2.1 - path-to-regexp: 1.8.0 + /netmask@2.0.2: + resolution: {integrity: sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg==} + engines: {node: '>= 0.4.0'} dev: true - /node-abort-controller@3.1.1: - resolution: {integrity: sha512-AGK2yQKIjRuqnc6VkX2Xj5d+QW8xZ87pa1UK6yA6ouUyuxfHuMP6umE5QK7UmTeOAymo+Zx1Fxiuw9rVx8taHQ==} - dev: false - - /node-fetch@2.6.7: - resolution: {integrity: sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==} - engines: {node: 4.x || >=6.0.0} - peerDependencies: - encoding: ^0.1.0 - peerDependenciesMeta: - encoding: - optional: true + /nise@5.1.9: + resolution: {integrity: sha512-qOnoujW4SV6e40dYxJOb3uvuoPHtmLzIk4TFo+j0jPJoC+5Z9xja5qH5JZobEPsa8+YYphMrOSwnrshEhG2qww==} dependencies: - whatwg-url: 5.0.0 + '@sinonjs/commons': 3.0.0 + '@sinonjs/fake-timers': 11.3.1 + '@sinonjs/text-encoding': 0.7.3 + just-extend: 6.2.0 + path-to-regexp: 6.3.0 dev: true /node-fetch@2.7.0: @@ -5162,22 +5330,6 @@ packages: resolution: {integrity: sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==} dev: true - /nopt@3.0.6: - resolution: {integrity: sha512-4GUt3kSEYmk4ITxzB/b9vaIDfUVWN/Ml1Fwl11IlnIG2iaJ9O6WXZ9SrYM9NLI8OCBieN2Y8SWC2oJV0RQ7qYg==} - hasBin: true - dependencies: - abbrev: 1.0.9 - dev: true - - /normalize-package-data@2.5.0: - resolution: {integrity: sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==} - dependencies: - hosted-git-info: 2.8.9 - resolve: 1.22.8 - semver: 5.7.2 - validate-npm-package-license: 3.0.4 - dev: true - /normalize-path@3.0.0: resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} engines: {node: '>=0.10.0'} @@ -5307,18 +5459,6 @@ packages: /openssl-wrapper@0.3.4: resolution: {integrity: sha512-iITsrx6Ho8V3/2OVtmZzzX8wQaKAaFXEJQdzoPUZDtyf5jWFlqo+h+OhGT4TATQ47f9ACKHua8nw7Qoy85aeKQ==} - /optionator@0.8.3: - resolution: {integrity: sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==} - engines: {node: '>= 0.8.0'} - dependencies: - deep-is: 0.1.4 - fast-levenshtein: 2.0.6 - levn: 0.3.0 - prelude-ls: 1.1.2 - type-check: 0.3.2 - word-wrap: 1.2.5 - dev: true - /optionator@0.9.3: resolution: {integrity: sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==} engines: {node: '>= 0.8.0'} @@ -5383,6 +5523,30 @@ packages: engines: {node: '>=6'} dev: true + /pac-proxy-agent@7.0.2(supports-color@9.4.0): + resolution: {integrity: sha512-BFi3vZnO9X5Qt6NRz7ZOaPja3ic0PhlsmCRYLOpN11+mWBCR6XJDqW5RF3j8jm4WGGQZtBA+bTfxYzeKW73eHg==} + engines: {node: '>= 14'} + dependencies: + '@tootallnate/quickjs-emscripten': 0.23.0 + agent-base: 7.1.0(supports-color@9.4.0) + debug: 4.3.7(supports-color@9.4.0) + get-uri: 6.0.3(supports-color@9.4.0) + http-proxy-agent: 7.0.2(supports-color@9.4.0) + https-proxy-agent: 7.0.5(supports-color@9.4.0) + pac-resolver: 7.0.1 + socks-proxy-agent: 8.0.4(supports-color@9.4.0) + transitivePeerDependencies: + - supports-color + dev: true + + /pac-resolver@7.0.1: + resolution: {integrity: sha512-5NPgf87AT2STgwa2ntRMr45jTKrYBGkVU36yT0ig/n/GMAa3oPqhZfIQ2kMEimReg0+t9kZViDVZ83qfVUlckg==} + engines: {node: '>= 14'} + dependencies: + degenerator: 5.0.1 + netmask: 2.0.2 + dev: true + /package-hash@4.0.0: resolution: {integrity: sha512-whdkPIooSu/bASggZ96BWVvZTRMOFxnyUG5PnTSGKoJE2gd5mbVNmR2Nj20QFzxYYgAXpoqC+AiXzl+UMRh7zQ==} engines: {node: '>=8'} @@ -5393,6 +5557,10 @@ packages: release-zalgo: 1.0.0 dev: true + /package-json-from-dist@1.0.1: + resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} + dev: true + /parent-module@1.0.1: resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} engines: {node: '>=6'} @@ -5400,12 +5568,16 @@ packages: callsites: 3.1.0 dev: true - /parse-json@2.2.0: - resolution: {integrity: sha512-QR/GGaKCkhwk1ePQNYDRKYZ3mwU9ypsKhB0XyFnLQdomyEqk3e8wpW3V5Jp88zbxK4n5ST1nqo+g9juTpownhQ==} - engines: {node: '>=0.10.0'} + /parse-asn1@5.1.7: + resolution: {integrity: sha512-CTM5kuWR3sx9IFamcl5ErfPl6ea/N8IYwiJ+vpeB2g+1iknv7zBl5uPwbMbRVznRVbrNY6lGuDoE5b30grmbqg==} + engines: {node: '>= 0.10'} dependencies: - error-ex: 1.3.2 - dev: true + asn1.js: 4.10.1 + browserify-aes: 1.2.0 + evp_bytestokey: 1.0.3 + hash-base: 3.0.4 + pbkdf2: 3.1.2 + safe-buffer: 5.2.1 /parse-json@5.2.0: resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} @@ -5422,13 +5594,6 @@ packages: engines: {node: '>= 0.8'} dev: true - /path-exists@2.1.0: - resolution: {integrity: sha512-yTltuKuhtNeFJKa1PiRzfLAU5182q1y4Eb4XCJ3PBqyzEDkAZRzBrKKBct682ls9reBVHf9udYLN5Nd+K1B9BQ==} - engines: {node: '>=0.10.0'} - dependencies: - pinkie-promise: 2.0.1 - dev: true - /path-exists@4.0.0: resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} engines: {node: '>=8'} @@ -5439,12 +5604,6 @@ packages: engines: {node: '>=0.10.0'} dev: true - /path-is-network-drive@1.0.20: - resolution: {integrity: sha512-p5wCWlRB4+ggzxWshqHH9aF3kAuVu295NaENXmVhThbZPJQBeJdxZTP6CIoUR+kWHDUW56S9YcaO1gXnc/BOxw==} - dependencies: - tslib: 2.3.1 - dev: true - /path-key@3.1.1: resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} engines: {node: '>=8'} @@ -5454,25 +5613,16 @@ packages: resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} dev: true - /path-strip-sep@1.0.17: - resolution: {integrity: sha512-+2zIC2fNgdilgV7pTrktY6oOxxZUo9x5zJYfTzxsGze5kSGDDwhA5/0WlBn+sUyv/WuuyYn3OfM+Ue5nhdQUgA==} + /path-scurry@2.0.0: + resolution: {integrity: sha512-ypGJsmGtdXUOeM5u93TyeIEfEhM6s+ljAhrk5vAvSx8uyY/02OvrZnA0YNGUrPXfpJMgI1ODd3nwz8Npx4O4cg==} + engines: {node: 20 || >=22} dependencies: - tslib: 2.3.1 - dev: true - - /path-to-regexp@1.8.0: - resolution: {integrity: sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==} - dependencies: - isarray: 0.0.1 + lru-cache: 11.0.1 + minipass: 7.1.2 dev: true - /path-type@1.1.0: - resolution: {integrity: sha512-S4eENJz1pkiQn9Znv33Q+deTOKmbl+jj1Fl+qiP/vYezj+S8x+J3Uo0ISrx/QoEvIlOaDWJhPaRd1flJ9HXZqg==} - engines: {node: '>=0.10.0'} - dependencies: - graceful-fs: 4.2.11 - pify: 2.3.0 - pinkie-promise: 2.0.1 + /path-to-regexp@6.3.0: + resolution: {integrity: sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==} dev: true /path-type@4.0.0: @@ -5489,6 +5639,16 @@ packages: engines: {node: '>= 14.16'} dev: true + /pbkdf2@3.1.2: + resolution: {integrity: sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==} + engines: {node: '>=0.12'} + dependencies: + create-hash: 1.2.0 + create-hmac: 1.1.7 + ripemd160: 2.0.2 + safe-buffer: 5.2.1 + sha.js: 2.4.11 + /pend@1.2.0: resolution: {integrity: sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==} dev: true @@ -5502,28 +5662,6 @@ packages: engines: {node: '>=8.6'} dev: true - /pify@2.3.0: - resolution: {integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==} - engines: {node: '>=0.10.0'} - dev: true - - /pify@4.0.1: - resolution: {integrity: sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==} - engines: {node: '>=6'} - dev: true - - /pinkie-promise@2.0.1: - resolution: {integrity: sha512-0Gni6D4UcLTbv9c57DfxDGdr41XfgUjqWZu492f0cIGr16zDU06BWP/RAEvOuo7CQ0CNjHaLlM59YJJFm3NWlw==} - engines: {node: '>=0.10.0'} - dependencies: - pinkie: 2.0.4 - dev: true - - /pinkie@2.0.4: - resolution: {integrity: sha512-MnUuEycAemtSaeFSjXKW/aroV7akBbY+Sv+RkyqFjgAe73F+MR0TBWKBRDkmfWq/HiFmdavfZ1G7h4SPZXaCSg==} - engines: {node: '>=0.10.0'} - dev: true - /pkg-dir@4.2.0: resolution: {integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==} engines: {node: '>=8'} @@ -5531,24 +5669,12 @@ packages: find-up: 4.1.0 dev: true - /pkg-dir@5.0.0: - resolution: {integrity: sha512-NPE8TDbzl/3YQYY7CSS228s3g2ollTFnc+Qi3tqmqJp9Vg2ovUpixcJEo2HJScN2Ez+kEaal6y70c0ehqJBJeA==} - engines: {node: '>=10'} - dependencies: - find-up: 5.0.0 - dev: true - /please-upgrade-node@3.2.0: resolution: {integrity: sha512-gQR3WpIgNIKwBMVLkpMUeR3e1/E1y42bqDQZfql+kDeXd8COYfM8PQA4X6y7a8u9Ua9FHmsrrmirW2vHs45hWg==} dependencies: semver-compare: 1.0.0 dev: true - /prelude-ls@1.1.2: - resolution: {integrity: sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==} - engines: {node: '>= 0.8.0'} - dev: true - /prelude-ls@1.2.1: resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} engines: {node: '>= 0.8.0'} @@ -5567,6 +5693,9 @@ packages: hasBin: true dev: true + /process-nextick-args@2.0.1: + resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} + /process-on-spawn@1.0.0: resolution: {integrity: sha512-1WsPDsUSMmZH5LeMLegqkPDrsGgsWwk1Exipy2hvB0o/F0ASzbpIctSCcZIK1ykJvtTJULEH+20WOFjMvGnCTg==} engines: {node: '>=8'} @@ -5591,9 +5720,35 @@ packages: react-is: 16.13.1 dev: true + /proxy-agent@6.4.0(supports-color@9.4.0): + resolution: {integrity: sha512-u0piLU+nCOHMgGjRbimiXmA9kM/L9EHh3zL81xCdp7m+Y2pHIsnmbdDoEDoAz5geaonNR6q6+yOPQs6n4T6sBQ==} + engines: {node: '>= 14'} + dependencies: + agent-base: 7.1.0(supports-color@9.4.0) + debug: 4.3.7(supports-color@9.4.0) + http-proxy-agent: 7.0.2(supports-color@9.4.0) + https-proxy-agent: 7.0.5(supports-color@9.4.0) + lru-cache: 7.18.3 + pac-proxy-agent: 7.0.2(supports-color@9.4.0) + proxy-from-env: 1.1.0 + socks-proxy-agent: 8.0.4(supports-color@9.4.0) + transitivePeerDependencies: + - supports-color + dev: true + /proxy-from-env@1.1.0: resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} + /public-encrypt@4.0.3: + resolution: {integrity: sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==} + dependencies: + bn.js: 4.12.0 + browserify-rsa: 4.1.0 + create-hash: 1.2.0 + parse-asn1: 5.1.7 + randombytes: 2.1.0 + safe-buffer: 5.2.1 + /pump@3.0.0: resolution: {integrity: sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==} dependencies: @@ -5601,32 +5756,43 @@ packages: once: 1.4.0 dev: true - /punycode@2.3.1: - resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} - engines: {node: '>=6'} - - /puppeteer@13.1.3(supports-color@9.4.0): - resolution: {integrity: sha512-nqcJNThLUG0Dgo++2mMtGR2FCyg7olJJhj/rm0A65muyN3nrH6lGvnNRzEaNmSnHWvjaDIG9ox5kxQB+nXTg5A==} - engines: {node: '>=10.18.1'} - deprecated: < 19.4.0 is no longer supported + /punycode@2.3.1: + resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} + engines: {node: '>=6'} + dev: true + + /puppeteer-core@23.4.1(supports-color@9.4.0): + resolution: {integrity: sha512-uCxGtn8VE9PlKhdFJX/zZySi9K3Ufr3qUZe28jxJoZUqiMJOi+SFh2zhiFDSjWqZIDkc0FtnaCC+rewW3MYXmg==} + engines: {node: '>=18'} + dependencies: + '@puppeteer/browsers': 2.4.0(supports-color@9.4.0) + chromium-bidi: 0.6.5(devtools-protocol@0.0.1342118) + debug: 4.3.7(supports-color@9.4.0) + devtools-protocol: 0.0.1342118 + typed-query-selector: 2.12.0 + ws: 8.18.0 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + dev: true + + /puppeteer@23.4.1(supports-color@9.4.0)(typescript@5.4.2): + resolution: {integrity: sha512-+wWfWTkQ8L9IB/3OVGSUp37c0eQ5za/85KdX+LAq2wTZkMdocgYGMCs+/91e2f/RXIYzve4x/uGxN8zG2sj8+w==} + engines: {node: '>=18'} + hasBin: true requiresBuild: true dependencies: - debug: 4.3.2(supports-color@9.4.0) - devtools-protocol: 0.0.948846 - extract-zip: 2.0.1(supports-color@9.4.0) - https-proxy-agent: 5.0.0(supports-color@9.4.0) - node-fetch: 2.6.7 - pkg-dir: 4.2.0 - progress: 2.0.3 - proxy-from-env: 1.1.0 - rimraf: 3.0.2 - tar-fs: 2.1.1 - unbzip2-stream: 1.4.3 - ws: 8.2.3 + '@puppeteer/browsers': 2.4.0(supports-color@9.4.0) + chromium-bidi: 0.6.5(devtools-protocol@0.0.1342118) + cosmiconfig: 9.0.0(typescript@5.4.2) + devtools-protocol: 0.0.1342118 + puppeteer-core: 23.4.1(supports-color@9.4.0) + typed-query-selector: 2.12.0 transitivePeerDependencies: - bufferutil - - encoding - supports-color + - typescript - utf-8-validate dev: true @@ -5646,6 +5812,10 @@ packages: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} dev: true + /queue-tick@1.0.1: + resolution: {integrity: sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag==} + dev: true + /quick-lru@5.1.1: resolution: {integrity: sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==} engines: {node: '>=10'} @@ -5659,7 +5829,12 @@ packages: resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==} dependencies: safe-buffer: 5.2.1 - dev: true + + /randomfill@1.0.4: + resolution: {integrity: sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==} + dependencies: + randombytes: 2.1.0 + safe-buffer: 5.2.1 /range-parser@1.2.1: resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==} @@ -5680,22 +5855,16 @@ packages: resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} dev: true - /read-pkg-up@1.0.1: - resolution: {integrity: sha512-WD9MTlNtI55IwYUS27iHh9tK3YoIVhxis8yKhLpTqWtml739uXc9NWTpxoHkfZf3+DkCCsXox94/VWZniuZm6A==} - engines: {node: '>=0.10.0'} - dependencies: - find-up: 1.1.2 - read-pkg: 1.1.0 - dev: true - - /read-pkg@1.1.0: - resolution: {integrity: sha512-7BGwRHqt4s/uVbuyoeejRn4YmFnYZiFl4AuaeXHlgZf3sONF0SOGlxs2Pw8g6hCKupo08RafIO5YXFNOKTfwsQ==} - engines: {node: '>=0.10.0'} + /readable-stream@2.3.8: + resolution: {integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==} dependencies: - load-json-file: 1.1.0 - normalize-package-data: 2.5.0 - path-type: 1.1.0 - dev: true + core-util-is: 1.0.3 + inherits: 2.0.4 + isarray: 1.0.0 + process-nextick-args: 2.0.1 + safe-buffer: 5.1.2 + string_decoder: 1.1.1 + util-deprecate: 1.0.2 /readable-stream@3.6.2: resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} @@ -5712,14 +5881,6 @@ packages: picomatch: 2.3.1 dev: true - /redent@1.0.0: - resolution: {integrity: sha512-qtW5hKzGQZqKoh6JNSD+4lfitfPKGz42e6QwiRmPM5mmKtR0N41AbJRYu0xJi7nhOJ4WDgRkKvAk6tw4WIwR4g==} - engines: {node: '>=0.10.0'} - dependencies: - indent-string: 2.1.0 - strip-indent: 1.0.1 - dev: true - /regenerator-runtime@0.14.1: resolution: {integrity: sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==} dev: false @@ -5733,11 +5894,6 @@ packages: set-function-name: 2.0.1 dev: true - /regexpp@3.2.0: - resolution: {integrity: sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==} - engines: {node: '>=8'} - dev: true - /release-zalgo@1.0.0: resolution: {integrity: sha512-gUAyHVHPPC5wdqX/LG4LWtRYtgjxyX78oanFNTMMyFEfOqdC54s3eE82imuWKbOeqYht2CrNf64Qb8vgmmtZGA==} engines: {node: '>=4'} @@ -5745,15 +5901,13 @@ packages: es6-error: 4.1.1 dev: true - /repeating@2.0.1: - resolution: {integrity: sha512-ZqtSMuVybkISo2OWvqvm7iHSWngvdaW3IpsT9/uP8v4gMi591LY6h35wdOfvQdWCKFWZWm2Y1Opp4kV7vQKT6A==} + /require-directory@2.1.1: + resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} engines: {node: '>=0.10.0'} - dependencies: - is-finite: 1.1.0 dev: true - /require-directory@2.1.1: - resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} + /require-from-string@2.0.2: + resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} engines: {node: '>=0.10.0'} dev: true @@ -5779,30 +5933,6 @@ packages: engines: {node: '>=8'} dev: true - /resolve@1.1.7: - resolution: {integrity: sha512-9znBF0vBcaSN3W2j7wKvdERPwqTxSpCq+if5C0WoTCyV9n24rua28jeuQ2pL/HOf+yUe/Mef+H/5p60K0Id3bg==} - dev: true - - /resolve@1.17.0: - resolution: {integrity: sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==} - dependencies: - path-parse: 1.0.7 - dev: true - - /resolve@1.19.0: - resolution: {integrity: sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg==} - dependencies: - is-core-module: 2.13.1 - path-parse: 1.0.7 - dev: true - - /resolve@1.20.0: - resolution: {integrity: sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==} - dependencies: - is-core-module: 2.13.1 - path-parse: 1.0.7 - dev: true - /resolve@1.22.8: resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==} hasBin: true @@ -5835,38 +5965,46 @@ packages: resolution: {integrity: sha512-r5a3l5HzYlIC68TpmYKlxWjmOP6wiPJ1vWv2HeLhNsRZMrCkxeqxiHlQ21oXmQ4F3SiryXBHhAD7JZqvOJjFmg==} dev: true - /rimraf@2.7.1: - resolution: {integrity: sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==} + /rimraf@3.0.2: + resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} + deprecated: Rimraf versions prior to v4 are no longer supported hasBin: true dependencies: glob: 7.2.3 dev: true - /rimraf@3.0.2: - resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} + /rimraf@6.0.1: + resolution: {integrity: sha512-9dkvaxAsk/xNXSJzMgFqqMCuFgt2+KsOFek3TMLfo8NCPfWpBmqwyNn5Y+NX56QUYfCtsyhF3ayiboEoUmJk/A==} + engines: {node: 20 || >=22} hasBin: true dependencies: - glob: 7.2.3 + glob: 11.0.0 + package-json-from-dist: 1.0.1 dev: true - /rollup-plugin-typescript2@0.31.1(rollup@2.41.0)(typescript@4.4.4): - resolution: {integrity: sha512-sklqXuQwQX+stKi4kDfEkneVESPi3YM/2S899vfRdF9Yi40vcC50Oq4A4cSZJNXsAQE/UsBZl5fAOsBLziKmjw==} + /ripemd160@2.0.2: + resolution: {integrity: sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==} + dependencies: + hash-base: 3.1.0 + inherits: 2.0.4 + + /rollup-plugin-typescript2@0.36.0(rollup@2.79.2)(typescript@5.4.2): + resolution: {integrity: sha512-NB2CSQDxSe9+Oe2ahZbf+B4bh7pHwjV5L+RSYpCu7Q5ROuN94F9b6ioWwKfz3ueL3KTtmX4o2MUH2cgHDIEUsw==} peerDependencies: rollup: '>=1.26.3' typescript: '>=2.4.0' dependencies: '@rollup/pluginutils': 4.2.1 - '@yarn-tool/resolve-package': 1.0.47 find-cache-dir: 3.3.2 - fs-extra: 8.1.0 - resolve: 1.20.0 - rollup: 2.41.0 - tslib: 2.2.0 - typescript: 4.4.4 + fs-extra: 10.1.0 + rollup: 2.79.2 + semver: 7.6.3 + tslib: 2.7.0 + typescript: 5.4.2 dev: true - /rollup@2.41.0: - resolution: {integrity: sha512-Gk76XHTggulWPH95q8V62bw6uqDH6UGvbD6LOa3QUyhuMF3eOuaeDHR7SLm1T9faitkpNrqzUAVYx47klcMnlA==} + /rollup@2.79.2: + resolution: {integrity: sha512-fS6iqSPZDs3dr/y7Od6y5nha8dW1YnbgtsyotCVvoFGKbERG++CVRFv1meyGDE1SNItQA8BrnCw7ScdAhRJ3XQ==} engines: {node: '>=10.0.0'} hasBin: true optionalDependencies: @@ -5885,7 +6023,7 @@ packages: /rxjs@7.8.1: resolution: {integrity: sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==} dependencies: - tslib: 2.3.1 + tslib: 2.7.0 dev: true /safe-array-concat@1.1.0: @@ -5898,6 +6036,9 @@ packages: isarray: 2.0.5 dev: true + /safe-buffer@5.1.2: + resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==} + /safe-buffer@5.2.1: resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} @@ -5912,6 +6053,7 @@ packages: /safer-buffer@2.1.2: resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + dev: true /sax@1.3.0: resolution: {integrity: sha512-0s+oAmw9zLl1V1cS9BtZN7JAd0cW5e0QH4W3LWEK6a4LaLEA2OTpGYWDY+6XasBLtz6wkm3u1xRw95mRuJ59WA==} @@ -5929,36 +6071,23 @@ packages: resolution: {integrity: sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow==} dev: true - /semver@5.7.2: - resolution: {integrity: sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==} - hasBin: true - dev: true - /semver@6.3.1: resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} hasBin: true dev: true - /semver@7.3.8: - resolution: {integrity: sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==} + /semver@7.5.4: + resolution: {integrity: sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==} engines: {node: '>=10'} hasBin: true dependencies: lru-cache: 6.0.0 dev: true - /semver@7.5.4: - resolution: {integrity: sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==} + /semver@7.6.3: + resolution: {integrity: sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==} engines: {node: '>=10'} hasBin: true - dependencies: - lru-cache: 6.0.0 - - /serialize-javascript@6.0.0: - resolution: {integrity: sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==} - dependencies: - randombytes: 2.1.0 - dev: true /serialize-javascript@6.0.2: resolution: {integrity: sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==} @@ -5994,6 +6123,13 @@ packages: resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} dev: true + /sha.js@2.4.11: + resolution: {integrity: sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==} + hasBin: true + dependencies: + inherits: 2.0.4 + safe-buffer: 5.2.1 + /shebang-command@2.0.0: resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} engines: {node: '>=8'} @@ -6018,6 +6154,11 @@ packages: resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} dev: true + /signal-exit@4.1.0: + resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} + engines: {node: '>=14'} + dev: true + /sinon@12.0.1: resolution: {integrity: sha512-iGu29Xhym33ydkAT+aNQFBINakjq69kKO6ByPvTsm3yyIACfyQttRTP03aBP/I8GfhFmLzrnKwNNkr0ORb1udg==} deprecated: 16.1.1 @@ -6026,7 +6167,7 @@ packages: '@sinonjs/fake-timers': 8.1.0 '@sinonjs/samsam': 6.1.3 diff: 5.1.0 - nise: 5.1.4 + nise: 5.1.9 supports-color: 7.2.0 dev: true @@ -6053,6 +6194,11 @@ packages: is-fullwidth-code-point: 3.0.0 dev: true + /smart-buffer@4.2.0: + resolution: {integrity: sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==} + engines: {node: '>= 6.0.0', npm: '>= 3.0.0'} + dev: true + /socket.io-adapter@2.5.2: resolution: {integrity: sha512-87C3LO/NOMc+eMcpcxUBebGjkpMDkNBS9tf7KJqcDsmL936EChtVva71Dw2q4tQcuVC+hAUy4an2NO/sYXmwRA==} dependencies: @@ -6067,7 +6213,7 @@ packages: engines: {node: '>=10.0.0'} dependencies: '@socket.io/component-emitter': 3.1.0 - debug: 4.3.4(supports-color@9.4.0) + debug: 4.3.7(supports-color@9.4.0) transitivePeerDependencies: - supports-color dev: true @@ -6089,6 +6235,25 @@ packages: - utf-8-validate dev: true + /socks-proxy-agent@8.0.4(supports-color@9.4.0): + resolution: {integrity: sha512-GNAq/eg8Udq2x0eNiFkr9gRg5bA7PXEWagQdeRX4cPSG+X/8V38v637gim9bjFptMk1QWsCTr0ttrJEiXbNnRw==} + engines: {node: '>= 14'} + dependencies: + agent-base: 7.1.1(supports-color@9.4.0) + debug: 4.3.7(supports-color@9.4.0) + socks: 2.8.3 + transitivePeerDependencies: + - supports-color + dev: true + + /socks@2.8.3: + resolution: {integrity: sha512-l5x7VUUWbjVFbafGLxPWkYsHIhEvmF85tbIeFZWc8ZPtoMyybuEhL7Jye/ooC4/d48FgOjSJXgsF/AJPYCW8Zw==} + engines: {node: '>= 10.0.0', npm: '>= 3.0.0'} + dependencies: + ip-address: 9.0.5 + smart-buffer: 4.2.0 + dev: true + /source-map-js@0.6.2: resolution: {integrity: sha512-/3GptzWzu0+0MBQFrDKzw/DvvMTUORvgY6k6jd/VS6iCR4RDTKWH6v6WPwQoUO8667uQEf9Oe38DxAYWY5F/Ug==} engines: {node: '>=0.10.0'} @@ -6113,20 +6278,6 @@ packages: source-map: 0.6.1 dev: true - /source-map@0.2.0: - resolution: {integrity: sha512-CBdZ2oa/BHhS4xj5DlhjWNHcan57/5YuvfdLf17iVmIpd9KRm+DFLmC6nBNj+6Ua7Kt3TmOjDpQT1aTYOQtoUA==} - engines: {node: '>=0.8.0'} - requiresBuild: true - dependencies: - amdefine: 1.0.1 - dev: true - optional: true - - /source-map@0.5.7: - resolution: {integrity: sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==} - engines: {node: '>=0.10.0'} - dev: true - /source-map@0.6.1: resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} engines: {node: '>=0.10.0'} @@ -6144,35 +6295,13 @@ packages: which: 2.0.2 dev: true - /spdx-correct@3.2.0: - resolution: {integrity: sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==} - dependencies: - spdx-expression-parse: 3.0.1 - spdx-license-ids: 3.0.16 - dev: true - - /spdx-exceptions@2.4.0: - resolution: {integrity: sha512-hcjppoJ68fhxA/cjbN4T8N6uCUejN8yFw69ttpqtBeCbF3u13n7mb31NB9jKwGTTWWnt9IbRA/mf1FprYS8wfw==} - dev: true - - /spdx-expression-parse@3.0.1: - resolution: {integrity: sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==} - dependencies: - spdx-exceptions: 2.4.0 - spdx-license-ids: 3.0.16 - dev: true - - /spdx-license-ids@3.0.16: - resolution: {integrity: sha512-eWN+LnM3GR6gPu35WxNgbGl8rmY1AEmoMDvL/QD6zYmPWgywxWqJWNdLGT+ke8dKNWrcYgYjPpG5gbTfghP8rw==} - dev: true - /sprintf-js@1.0.3: resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} dev: true /sprintf-js@1.1.3: resolution: {integrity: sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==} - dev: false + dev: true /statuses@1.5.0: resolution: {integrity: sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==} @@ -6188,17 +6317,41 @@ packages: resolution: {integrity: sha512-KXDYZ9dszj6bzvnEMRYvxgeTHU74QBFL54XKtP3nyMuJ81CFYtABZ3bAzL2EdFUaEwJOBOgENyFj3R7oTzDyyw==} engines: {node: '>=4', npm: '>=6'} + /stream-browserify@3.0.0: + resolution: {integrity: sha512-H73RAHsVBapbim0tU2JwwOiXUj+fikfiaoYAKHF3VJfA0pe2BCzkhAHBlLG6REzE+2WNZcxOXjK7lkso+9euLA==} + dependencies: + inherits: 2.0.4 + readable-stream: 3.6.2 + + /stream-http@3.2.0: + resolution: {integrity: sha512-Oq1bLqisTyK3TSCXpPbT4sdeYNdmyZJv1LxpEm2vu1ZhK89kSE5YXwZc3cWk0MagGaKriBh9mCFbVGtO+vY29A==} + dependencies: + builtin-status-codes: 3.0.0 + inherits: 2.0.4 + readable-stream: 3.6.2 + xtend: 4.0.2 + /streamroller@3.1.5(supports-color@9.4.0): resolution: {integrity: sha512-KFxaM7XT+irxvdqSP1LGLgNWbYN7ay5owZ3r/8t77p+EtSUAfUgtl7be3xtqtOmGUl9K9YPO2ca8133RlTjvKw==} engines: {node: '>=8.0'} dependencies: date-format: 4.0.14 - debug: 4.3.4(supports-color@9.4.0) + debug: 4.3.7(supports-color@9.4.0) fs-extra: 8.1.0 transitivePeerDependencies: - supports-color dev: true + /streamx@2.20.1: + resolution: {integrity: sha512-uTa0mU6WUC65iUvzKH4X9hEdvSW7rbPxPtwfWiLMSj3qTdQbAiUboZTxauKfpFuGIGa1C2BYijZ7wgdUXICJhA==} + dependencies: + fast-fifo: 1.3.2 + queue-tick: 1.0.1 + text-decoder: 1.2.0 + optionalDependencies: + bare-events: 2.5.0 + dev: true + /string-argv@0.3.1: resolution: {integrity: sha512-a1uQGz7IyVy9YwhqjZIZu1c8JO8dNIe20xBmSS6qu9kv++k3JGzCVmprbNN5Kn+BgzD5E7YYwg1CcjuJMRNsvg==} engines: {node: '>=0.6.19'} @@ -6218,6 +6371,15 @@ packages: strip-ansi: 6.0.1 dev: true + /string-width@5.1.2: + resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} + engines: {node: '>=12'} + dependencies: + eastasianwidth: 0.2.0 + emoji-regex: 9.2.2 + strip-ansi: 7.1.0 + dev: true + /string.prototype.trim@1.2.8: resolution: {integrity: sha512-lfjY4HcixfQXOfaqCvcBuOIapyaroTXhbkfJN3gcB1OtyupngWK4sEET9Knd0cXd28kTUqu/kHoV4HKSJdnjiQ==} engines: {node: '>= 0.4'} @@ -6243,6 +6405,11 @@ packages: es-abstract: 1.22.3 dev: true + /string_decoder@1.1.1: + resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==} + dependencies: + safe-buffer: 5.1.2 + /string_decoder@1.3.0: resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} dependencies: @@ -6271,11 +6438,11 @@ packages: ansi-regex: 5.0.1 dev: true - /strip-bom@2.0.0: - resolution: {integrity: sha512-kwrX1y7czp1E69n2ajbG65mIo9dqvJ+8aBQXOGVxqwvNbsXdFM6Lq37dLAY3mknUwru8CfcCbfOLL/gMo+fi3g==} - engines: {node: '>=0.10.0'} + /strip-ansi@7.1.0: + resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==} + engines: {node: '>=12'} dependencies: - is-utf8: 0.2.1 + ansi-regex: 6.1.0 dev: true /strip-bom@3.0.0: @@ -6293,14 +6460,6 @@ packages: engines: {node: '>=6'} dev: true - /strip-indent@1.0.1: - resolution: {integrity: sha512-I5iQq6aFMM62fBEAIB/hXzwJD6EEZ0xEGCX2t7oXqaKPIRgt4WruAQ285BISgdkP+HLGWyeGmNJcpIwFeRYRUA==} - engines: {node: '>=0.10.0'} - hasBin: true - dependencies: - get-stdin: 4.0.1 - dev: true - /strip-json-comments@3.1.1: resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} engines: {node: '>=8'} @@ -6317,13 +6476,6 @@ packages: resolution: {integrity: sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA==} dev: false - /supports-color@3.2.3: - resolution: {integrity: sha512-Jds2VIYDrlp5ui7t8abHN2bjAu4LV/q4N2KivFPpGH0lrka0BMq/33AmECUXlKPcHigkNaqfXRENFju+rlcy+A==} - engines: {node: '>=0.8.0'} - dependencies: - has-flag: 1.0.0 - dev: true - /supports-color@5.5.0: resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} engines: {node: '>=4'} @@ -6331,13 +6483,6 @@ packages: has-flag: 3.0.0 dev: true - /supports-color@6.1.0: - resolution: {integrity: sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==} - engines: {node: '>=6'} - dependencies: - has-flag: 3.0.0 - dev: true - /supports-color@7.2.0: resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} engines: {node: '>=8'} @@ -6366,24 +6511,22 @@ packages: engines: {node: '>=6'} dev: true - /tar-fs@2.1.1: - resolution: {integrity: sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==} + /tar-fs@3.0.6: + resolution: {integrity: sha512-iokBDQQkUyeXhgPYaZxmczGPhnhXZ0CmrqI+MOb/WFGS9DW5wnfrLgtjUJBvz50vQ3qfRwJ62QVoCFu8mPVu5w==} dependencies: - chownr: 1.1.4 - mkdirp-classic: 0.5.3 pump: 3.0.0 - tar-stream: 2.2.0 + tar-stream: 3.1.7 + optionalDependencies: + bare-fs: 2.3.5 + bare-path: 2.1.3 dev: true - /tar-stream@2.2.0: - resolution: {integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==} - engines: {node: '>=6'} + /tar-stream@3.1.7: + resolution: {integrity: sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==} dependencies: - bl: 4.1.0 - end-of-stream: 1.4.4 - fs-constants: 1.0.0 - inherits: 2.0.4 - readable-stream: 3.6.2 + b4a: 1.6.7 + fast-fifo: 1.3.2 + streamx: 2.20.1 dev: true /tcomb-validation@3.4.1: @@ -6396,24 +6539,6 @@ packages: resolution: {integrity: sha512-di2Hd1DB2Zfw6StGv861JoAF5h/uQVu/QJp2g8KVbtfKnoHdBQl5M32YWq6mnSYBQ1vFFrns5B1haWJL7rKaOQ==} dev: true - /tedious@14.3.0(supports-color@9.4.0): - resolution: {integrity: sha512-ioorVbzGpGOLF9gkd47EtlHGDh0HQc9zgjlf5lon8hDCRwYZ79Uolu9cXQZ/gOPVyG63evbU7XjzEBOQOvcHeQ==} - engines: {node: '>= 12'} - dependencies: - '@azure/identity': 2.0.1(supports-color@9.4.0) - '@azure/keyvault-keys': 4.7.2(supports-color@9.4.0) - '@js-joda/core': 4.3.1 - bl: 5.1.0 - iconv-lite: 0.6.3 - jsbi: 3.2.5 - native-duplexpair: 1.0.0 - node-abort-controller: 3.1.1 - punycode: 2.3.1 - sprintf-js: 1.1.3 - transitivePeerDependencies: - - supports-color - dev: false - /terser-webpack-plugin@5.3.10(webpack@5.76.0): resolution: {integrity: sha512-BKFPWlPDndPs+NGGCr1U59t0XScL5317Y0UReNrHaw9/FwhPENlq6bfgs+4yPfyP51vqC1bQ4rp1EfXW5ZSH9w==} engines: {node: '>= 10.13.0'} @@ -6458,6 +6583,12 @@ packages: minimatch: 3.1.2 dev: true + /text-decoder@1.2.0: + resolution: {integrity: sha512-n1yg1mOj9DNpk3NeZOx7T6jchTbyJS3i3cucbNN6FcdPriMZx7NsgrGpWWdWZZGxD7ES1XB+3uoqHMgOKaN+fg==} + dependencies: + b4a: 1.6.7 + dev: true + /text-table@0.2.0: resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} dev: true @@ -6470,10 +6601,6 @@ packages: resolution: {integrity: sha512-pkJC8uIP/gxDHxNQUBUbjHyl6oZfT+ofn7tbaHW+CFIUjI+Q2MBbHcx1JSBQfhDaTcO9bNg328q0i7Vk5PismQ==} dev: true - /timsort@0.3.0: - resolution: {integrity: sha512-qsdtZH+vMoCARQtyod4imc2nIJwg9Cc7lPRrw9CzF8ZKR0khdr8+2nX80PBhET3tcyTtJDxAffGh2rXH4tyU8A==} - dev: true - /tmp@0.2.1: resolution: {integrity: sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==} engines: {node: '>=8.17.0'} @@ -6501,11 +6628,6 @@ packages: /tr46@0.0.3: resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} - /trim-newlines@1.0.0: - resolution: {integrity: sha512-Nm4cF79FhSTzrLKGDMi3I4utBtFv8qKy4sq1enftf2gMdpqI8oVQTAfySkTz5r49giVzDj88SVZXP4CeYQwjaw==} - engines: {node: '>=0.10.0'} - dev: true - /trim-repeated@1.0.0: resolution: {integrity: sha512-pkonvlKk8/ZuR0D5tLW8ljt5I8kmxp2XKymhepUeOdCEfKpZaktSArkLHZt76OB1ZvO9bssUsDty4SWhLvZpLg==} engines: {node: '>=0.10.0'} @@ -6513,7 +6635,16 @@ packages: escape-string-regexp: 1.0.5 dev: false - /ts-loader@9.2.6(typescript@4.4.4)(webpack@5.76.0): + /ts-api-utils@1.3.0(typescript@5.4.2): + resolution: {integrity: sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==} + engines: {node: '>=16'} + peerDependencies: + typescript: '>=4.2.0' + dependencies: + typescript: 5.4.2 + dev: true + + /ts-loader@9.2.6(typescript@5.4.2)(webpack@5.76.0): resolution: {integrity: sha512-QMTC4UFzHmu9wU2VHZEmWWE9cUajjfcdcws+Gh7FhiO+Dy0RnR1bNz0YCHqhI0yRowCE9arVnNxYHqELOy9Hjw==} engines: {node: '>=12.0.0'} peerDependencies: @@ -6524,11 +6655,11 @@ packages: enhanced-resolve: 5.15.0 micromatch: 4.0.5 semver: 7.5.4 - typescript: 4.4.4 + typescript: 5.4.2 webpack: 5.76.0 dev: true - /ts-node@10.4.0(@types/node@16.11.7)(typescript@4.4.4): + /ts-node@10.4.0(@types/node@18.19.50)(typescript@5.4.2): resolution: {integrity: sha512-g0FlPvvCXSIO1JDF6S232P5jPYqBkRL9qly81ZgAOSU7rwI0stphCgd2kLiCrU9DjQCrJMWEqcNSjQL02s6d8A==} hasBin: true peerDependencies: @@ -6547,14 +6678,14 @@ packages: '@tsconfig/node12': 1.0.11 '@tsconfig/node14': 1.0.3 '@tsconfig/node16': 1.0.4 - '@types/node': 16.11.7 + '@types/node': 18.19.50 acorn: 8.11.3 acorn-walk: 8.3.2 arg: 4.1.3 create-require: 1.1.1 diff: 4.0.2 make-error: 1.3.6 - typescript: 4.4.4 + typescript: 5.4.2 yn: 3.1.1 dev: true @@ -6571,34 +6702,26 @@ packages: resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==} dev: true - /tslib@2.2.0: - resolution: {integrity: sha512-gS9GVHRU+RGn5KQM2rllAlR3dU6m7AcpJKdtH8gFvQiC4Otgk98XnmMU+nZenHt/+VhnBPWwgrJsyrdcw6i23w==} - dev: true - /tslib@2.3.1: resolution: {integrity: sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==} - /tsutils@3.21.0(typescript@4.4.4): + /tslib@2.7.0: + resolution: {integrity: sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==} + + /tsutils@3.21.0(typescript@5.4.2): resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==} engines: {node: '>= 6'} peerDependencies: typescript: '>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta' dependencies: tslib: 1.14.1 - typescript: 4.4.4 + typescript: 5.4.2 dev: true /tunnel@0.0.6: resolution: {integrity: sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==} engines: {node: '>=0.6.11 <=0.7.0 || >=0.7.3'} - /type-check@0.3.2: - resolution: {integrity: sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==} - engines: {node: '>= 0.8.0'} - dependencies: - prelude-ls: 1.1.2 - dev: true - /type-check@0.4.0: resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} engines: {node: '>= 0.8.0'} @@ -6672,21 +6795,19 @@ packages: is-typed-array: 1.1.12 dev: true + /typed-query-selector@2.12.0: + resolution: {integrity: sha512-SbklCd1F0EiZOyPiW192rrHZzZ5sBijB6xM+cpmrwDqObvdtunOHHIk9fCGsoK5JVIYXoyEp4iEdE3upFH3PAg==} + dev: true + /typedarray-to-buffer@3.1.5: resolution: {integrity: sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==} dependencies: is-typedarray: 1.0.0 dev: true - /typescript@4.4.4: - resolution: {integrity: sha512-DqGhF5IKoBl8WNf8C1gu8q0xZSInh9j1kJJMqT3a94w1JzVaBU4EXOSMrz9yDqMT0xt3selp83fuFMQ0uzv6qA==} - engines: {node: '>=4.2.0'} - hasBin: true - dev: true - - /typescript@4.5.5: - resolution: {integrity: sha512-TCTIul70LyWe6IJWT8QSYeA54WQe8EjQFU4wY52Fasj5UKx88LNYKCgBEHcOMOrFF1rKGbD8v/xcNWVUq9SymA==} - engines: {node: '>=4.2.0'} + /typescript@5.4.2: + resolution: {integrity: sha512-+2/g0Fds1ERlP6JsakQQDXjZdZMM+rqpamFZJEKh4kwTIn3iDkgKtby0CeNd5ATNZ4Ry1ax15TMx0W2V+miizQ==} + engines: {node: '>=14.17'} hasBin: true dev: true @@ -6694,14 +6815,6 @@ packages: resolution: {integrity: sha512-xV8kqRKM+jhMvcHWUKthV9fNebIzrNy//2O9ZwWcfiBFR5f25XVZPLlEajk/sf3Ra15V92isyQqnIEXRDaZWEA==} dev: true - /uglify-js@3.17.4: - resolution: {integrity: sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g==} - engines: {node: '>=0.8.0'} - hasBin: true - requiresBuild: true - dev: true - optional: true - /unbox-primitive@1.0.2: resolution: {integrity: sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==} dependencies: @@ -6718,29 +6831,23 @@ packages: through: 2.3.8 dev: true + /undici-types@5.26.5: + resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} + /universalify@0.1.2: resolution: {integrity: sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==} engines: {node: '>= 4.0.0'} + dev: true /universalify@2.0.1: resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==} engines: {node: '>= 10.0.0'} - dev: true /unpipe@1.0.0: resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} engines: {node: '>= 0.8'} dev: true - /upath2@3.1.19: - resolution: {integrity: sha512-d23dQLi8nDWSRTIQwXtaYqMrHuca0As53fNiTLLFDmsGBbepsZepISaB2H1x45bDFN/n3Qw9bydvyZEacTrEWQ==} - dependencies: - '@types/node': 16.11.7 - path-is-network-drive: 1.0.20 - path-strip-sep: 1.0.17 - tslib: 2.3.1 - dev: true - /update-browserslist-db@1.0.13(browserslist@4.22.2): resolution: {integrity: sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==} hasBin: true @@ -6762,6 +6869,10 @@ packages: resolution: {integrity: sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA==} dev: true + /urlpattern-polyfill@10.0.0: + resolution: {integrity: sha512-H/A06tKD7sS1O1X2SshBVeA5FLycRpjqiBeqGKmBwBDBy28EnRjORxTNe269KSSr5un5qyWi1iL61wLxpd+ZOg==} + dev: true + /util-deprecate@1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} @@ -6770,21 +6881,14 @@ packages: engines: {node: '>= 0.4.0'} dev: true + /uuid@10.0.0: + resolution: {integrity: sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==} + hasBin: true + /uuid@8.3.2: resolution: {integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==} hasBin: true - /v8-compile-cache@2.4.0: - resolution: {integrity: sha512-ocyWc3bAHBB/guyqJQVI5o4BZkPhznPYUG2ea80Gond/BgNWpap8TOmLSeeQG7bnh2KMISxskdADG59j7zruhw==} - dev: true - - /validate-npm-package-license@3.0.4: - resolution: {integrity: sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==} - dependencies: - spdx-correct: 3.2.0 - spdx-expression-parse: 3.0.1 - dev: true - /validator@13.11.0: resolution: {integrity: sha512-Ii+sehpSfZy+At5nPdnyMhx78fEoPDkR2XW/zimHEL3MyGJQOCQ7WeP20jPYRz7ZCpcKLB21NxuXHF3bxjStBQ==} engines: {node: '>= 0.10'} @@ -6912,17 +7016,8 @@ packages: isexe: 2.0.0 dev: true - /word-wrap@1.2.5: - resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} - engines: {node: '>=0.10.0'} - dev: true - - /wordwrap@1.0.0: - resolution: {integrity: sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==} - dev: true - - /workerpool@6.2.0: - resolution: {integrity: sha512-Rsk5qQHJ9eowMH28Jwhe8HEbmdYDX4lwoMWshiCXugjtHqMD9ZbiqSDLxcsfdqsETPzVUtX5s1Z5kStiIM6l4A==} + /workerpool@6.5.1: + resolution: {integrity: sha512-Fs4dNYcsdpYSAfVxhnl1L5zTksjvOJxtC5hzMNl+1t9B8hTJTdKDyZ5ju7ztgPy+ft9tBFXoOlDNiOT9WUXZlA==} dev: true /wrap-ansi@6.2.0: @@ -6943,6 +7038,15 @@ packages: strip-ansi: 6.0.1 dev: true + /wrap-ansi@8.1.0: + resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} + engines: {node: '>=12'} + dependencies: + ansi-styles: 6.2.1 + string-width: 5.1.2 + strip-ansi: 7.1.0 + dev: true + /wrappy@1.0.2: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} dev: true @@ -6982,12 +7086,12 @@ packages: optional: true dev: true - /ws@8.2.3: - resolution: {integrity: sha512-wBuoj1BDpC6ZQ1B7DWQBYVLphPWkm8i9Y0/3YdHjHKHiohOJ1ws+3OccDWtH+PoC9DZD5WOTrJvNbWvjS6JWaA==} + /ws@8.18.0: + resolution: {integrity: sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==} engines: {node: '>=10.0.0'} peerDependencies: bufferutil: ^4.0.1 - utf-8-validate: ^5.0.2 + utf-8-validate: '>=5.0.2' peerDependenciesMeta: bufferutil: optional: true @@ -7011,11 +7115,15 @@ packages: engines: {node: '>=6.0'} dev: true - /xpath@0.0.32: - resolution: {integrity: sha512-rxMJhSIoiO8vXcWvSifKqhvV96GjiD5wYb8/QHdoRyQvraTpp4IEv944nhGausZZ3u7dhQXteZuZbaqfpB7uYw==} + /xpath@0.0.34: + resolution: {integrity: sha512-FxF6+rkr1rNSQrhUNYrAFJpRXNzlDoMxeXN5qI84939ylEv3qqPFKa85Oxr6tDaJKqwW6KKyo2v26TSv3k6LeA==} engines: {node: '>=0.6.0'} dev: false + /xtend@4.0.2: + resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} + engines: {node: '>=0.4'} + /y18n@4.0.3: resolution: {integrity: sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==} dev: true @@ -7030,6 +7138,7 @@ packages: /yallist@4.0.0: resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} + dev: true /yaml@1.10.2: resolution: {integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==} @@ -7044,16 +7153,16 @@ packages: decamelize: 1.2.0 dev: true - /yargs-parser@20.2.4: - resolution: {integrity: sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==} - engines: {node: '>=10'} - dev: true - /yargs-parser@20.2.9: resolution: {integrity: sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==} engines: {node: '>=10'} dev: true + /yargs-parser@21.1.1: + resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} + engines: {node: '>=12'} + dev: true + /yargs-unparser@2.0.0: resolution: {integrity: sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==} engines: {node: '>=10'} @@ -7107,6 +7216,19 @@ packages: yargs-parser: 20.2.9 dev: true + /yargs@17.7.2: + resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} + engines: {node: '>=12'} + dependencies: + cliui: 8.0.1 + escalade: 3.1.1 + get-caller-file: 2.0.5 + require-directory: 2.1.1 + string-width: 4.2.3 + y18n: 5.0.8 + yargs-parser: 21.1.1 + dev: true + /yauzl@2.10.0: resolution: {integrity: sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==} dependencies: @@ -7124,17 +7246,5 @@ packages: engines: {node: '>=10'} dev: true - /z-schema@5.0.5: - resolution: {integrity: sha512-D7eujBWkLa3p2sIpJA0d1pr7es+a7m0vFAnZLlCEKq/Ij2k0MLi9Br2UPxoxdYystm5K1yeBGzub0FlYUEWj2Q==} - engines: {node: '>=8.0.0'} - hasBin: true - dependencies: - lodash.get: 4.4.2 - lodash.isequal: 4.5.0 - validator: 13.11.0 - optionalDependencies: - commander: 9.5.0 - dev: true - - /zod@3.22.4: - resolution: {integrity: sha512-iC+8Io04lddc+mVqQ9AZ7OQ2MrUKGN+oIQyq1vemgt46jwCwLfhq7/pwnBnNXXXZb8VTVLKwp9EDkx+ryxIWmg==} + /zod@3.23.8: + resolution: {integrity: sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==} diff --git a/packages/sdk/review/teamsfx.api.md b/packages/sdk/review/teamsfx.api.md index 5897d82515..ce347b4cf4 100644 --- a/packages/sdk/review/teamsfx.api.md +++ b/packages/sdk/review/teamsfx.api.md @@ -9,17 +9,13 @@ import { AccessToken } from '@azure/identity'; import { Activity } from 'botbuilder'; import { Attachment } from 'botbuilder'; -import { AuthenticationProvider } from '@microsoft/microsoft-graph-client'; import { AxiosInstance } from 'axios'; import { AxiosRequestConfig } from 'axios'; -import { BotFrameworkAdapter } from 'botbuilder'; import { CardAction } from 'botbuilder'; import { CardImage } from 'botbuilder'; import { ChannelInfo } from 'botbuilder'; -import { Client } from '@microsoft/microsoft-graph-client'; import { CloudAdapter } from 'botbuilder'; import { ComponentDialog } from 'botbuilder-dialogs'; -import { ConnectionConfig } from 'tedious'; import { ConversationReference } from 'botbuilder'; import { ConversationState } from 'botbuilder'; import { Dialog } from 'botbuilder-dialogs'; @@ -45,8 +41,6 @@ import { TokenCredential } from '@azure/identity'; import { TokenResponse } from 'botframework-schema'; import { TurnContext } from 'botbuilder'; import { UserState } from 'botbuilder'; -import { WebRequest } from 'botbuilder'; -import { WebResponse } from 'botbuilder'; // @public export enum AdaptiveCardResponse { @@ -70,24 +64,12 @@ export class ApiKeyProvider implements AuthProvider { // @public export class AppCredential implements TokenCredential { constructor(authConfig: AppCredentialAuthConfig); - constructor(authConfig: AuthenticationConfiguration); getToken(scopes: string | string[], options?: GetTokenOptions): Promise; } // @public export type AppCredentialAuthConfig = OnBehalfOfCredentialAuthConfig; -// @public @deprecated -export interface AuthenticationConfiguration { - readonly applicationIdUri?: string; - readonly authorityHost?: string; - readonly certificateContent?: string; - readonly clientId?: string; - readonly clientSecret?: string; - readonly initiateLoginEndpoint?: string; - readonly tenantId?: string; -} - // @public export interface AuthProvider { AddAuthenticationInfo: (config: AxiosRequestConfig) => Promise; @@ -109,19 +91,19 @@ export class BearerTokenAuthProvider implements AuthProvider { declare namespace BotBuilderCloudAdapter { export { - ConversationOptions_2 as ConversationOptions, - NotificationOptions_3 as NotificationOptions, - ConversationBot_2 as ConversationBot, + ConversationOptions, + NotificationOptions_2 as NotificationOptions, + ConversationBot, BotSsoExecutionDialog, - Channel_2 as Channel, - Member_2 as Member, - NotificationBot_2 as NotificationBot, - sendAdaptiveCard_2 as sendAdaptiveCard, - sendMessage_2 as sendMessage, - TeamsBotInstallation_2 as TeamsBotInstallation, - SearchScope_2 as SearchScope, - CommandBot_2 as CommandBot, - CardActionBot_2 as CardActionBot + Channel, + Member, + NotificationBot, + sendAdaptiveCard, + sendMessage, + TeamsBotInstallation, + SearchScope, + CommandBot, + CardActionBot } } export { BotBuilderCloudAdapter } @@ -130,9 +112,9 @@ export { BotBuilderCloudAdapter } export interface BotSsoConfig { aad: { scopes: string[]; - } & ((OnBehalfOfCredentialAuthConfig & { + } & OnBehalfOfCredentialAuthConfig & { initiateLoginEndpoint: string; - }) | AuthenticationConfiguration); + }; // (undocumented) dialog?: { CustomBotSsoExecutionActivityHandler?: new (ssoConfig: BotSsoConfig) => BotSsoExecutionActivityHandler; @@ -156,7 +138,6 @@ export interface BotSsoExecutionActivityHandler { // @public export class BotSsoExecutionDialog extends ComponentDialog { - constructor(dedupStorage: Storage_2, ssoPromptSettings: TeamsBotSsoPromptSettings, teamsfx: TeamsFx, dialogName?: string); constructor(dedupStorage: Storage_2, ssoPromptSettings: TeamsBotSsoPromptSettings, authConfig: OnBehalfOfCredentialAuthConfig, initiateLoginEndpoint: string, dialogName?: string); addCommand(handler: BotSsoExecutionDialogHandler, triggerPatterns: TriggerPatterns): void; protected onEndDialog(context: TurnContext): Promise; @@ -166,15 +147,8 @@ export class BotSsoExecutionDialog extends ComponentDialog { // @public (undocumented) export type BotSsoExecutionDialogHandler = (context: TurnContext, tokenResponse: TeamsBotSsoPromptTokenResponse, message: CommandMessage) => Promise; -// @public @deprecated (undocumented) -export class CardActionBot { - constructor(adapter: BotFrameworkAdapter, options?: CardActionOptions); - registerHandler(actionHandler: TeamsFxAdaptiveCardActionHandler): void; - registerHandlers(actionHandlers: TeamsFxAdaptiveCardActionHandler[]): void; -} - // @public -class CardActionBot_2 { +class CardActionBot { constructor(adapter: CloudAdapter, options?: CardActionOptions); registerHandler(actionHandler: TeamsFxAdaptiveCardActionHandler): void; registerHandlers(actionHandlers: TeamsFxAdaptiveCardActionHandler[]): void; @@ -192,37 +166,18 @@ export class CertificateAuthProvider implements AuthProvider { } // @public -export class Channel implements NotificationTarget { +class Channel implements NotificationTarget { constructor(parent: TeamsBotInstallation, info: ChannelInfo); readonly info: ChannelInfo; readonly parent: TeamsBotInstallation; sendAdaptiveCard(card: unknown, onError?: (context: TurnContext, error: Error) => Promise): Promise; - sendMessage(text: string, onError?: (context: TurnContext, error: Error) => Promise): Promise; - readonly type: NotificationTargetType; -} - -// @public -class Channel_2 implements NotificationTarget { - constructor(parent: TeamsBotInstallation_2, info: ChannelInfo); - readonly info: ChannelInfo; - readonly parent: TeamsBotInstallation_2; - sendAdaptiveCard(card: unknown, onError?: (context: TurnContext, error: Error) => Promise): Promise; // Warning: (ae-forgotten-export) The symbol "MessageResponse" needs to be exported by the entry point index.d.ts sendMessage(text: string, onError?: (context: TurnContext, error: Error) => Promise): Promise; readonly type: NotificationTargetType; } -// @public @deprecated (undocumented) -export class CommandBot { - constructor(adapter: BotFrameworkAdapter, options?: CommandOptions, ssoCommandActivityHandler?: BotSsoExecutionActivityHandler, ssoConfig?: BotSsoConfig); - registerCommand(command: TeamsFxBotCommandHandler): void; - registerCommands(commands: TeamsFxBotCommandHandler[]): void; - registerSsoCommand(ssoCommand: TeamsFxBotSsoCommandHandler): void; - registerSsoCommands(ssoCommands: TeamsFxBotSsoCommandHandler[]): void; -} - // @public -class CommandBot_2 { +class CommandBot { constructor(adapter: CloudAdapter, options?: CommandOptions, ssoCommandActivityHandler?: BotSsoExecutionActivityHandler, ssoConfig?: BotSsoConfig); registerCommand(command: TeamsFxBotCommandHandler): void; registerCommands(commands: TeamsFxBotCommandHandler[]): void; @@ -242,46 +197,18 @@ export interface CommandOptions { ssoCommands?: TeamsFxBotSsoCommandHandler[]; } -// @public @deprecated (undocumented) -export class ConversationBot { +// @public +class ConversationBot { constructor(options: ConversationOptions); - readonly adapter: BotFrameworkAdapter; + readonly adapter: CloudAdapter; readonly cardAction?: CardActionBot; readonly command?: CommandBot; readonly notification?: NotificationBot; - requestHandler(req: WebRequest, res: WebResponse, logic?: (context: TurnContext) => Promise): Promise; -} - -// @public -class ConversationBot_2 { - constructor(options: ConversationOptions_2); - readonly adapter: CloudAdapter; - readonly cardAction?: CardActionBot_2; - readonly command?: CommandBot_2; - readonly notification?: NotificationBot_2; requestHandler(req: Request_2, res: Response_2, logic?: (context: TurnContext) => Promise): Promise; } -// @public @deprecated -export interface ConversationOptions { - adapter?: BotFrameworkAdapter; - adapterConfig?: { - [key: string]: unknown; - }; - cardAction?: CardActionOptions & { - enabled?: boolean; - }; - command?: CommandOptions & { - enabled?: boolean; - }; - notification?: NotificationOptions_2 & { - enabled?: boolean; - }; - ssoConfig?: BotSsoConfig; -} - // @public -interface ConversationOptions_2 { +interface ConversationOptions { adapter?: CloudAdapter; adapterConfig?: { [key: string]: unknown; @@ -292,7 +219,7 @@ interface ConversationOptions_2 { command?: CommandOptions & { enabled?: boolean; }; - notification?: NotificationOptions_3 & { + notification?: NotificationOptions_2 & { enabled?: boolean; }; ssoConfig?: BotSsoConfig; @@ -313,14 +240,6 @@ export interface ConversationReferenceStoreAddOptions { // @public export function createApiClient(apiEndpoint: string, authProvider: AuthProvider): AxiosInstance; -// Warning: (ae-forgotten-export) The symbol "TeamsFxConfiguration" needs to be exported by the entry point index.d.ts -// -// @public @deprecated -export function createMicrosoftGraphClient(teamsfx: TeamsFxConfiguration, scopes?: string | string[]): Client; - -// @public @deprecated -export function createMicrosoftGraphClientWithCredential(credential: TokenCredential, scopes?: string | string[]): Client; - // @public export function createPemCertOption(cert: string | Buffer, key: string | Buffer, options?: { passphrase?: string; @@ -343,7 +262,6 @@ export enum ErrorCode { FailedToRetrieveSsoToken = "FailedToRetrieveSsoToken", FailedToRunDedupStep = "FailedToRunDedupStep", FailedToRunSsoStep = "FailedToRunSsoStep", - IdentityTypeNotSupported = "IdentityTypeNotSupported", InternalError = "InternalError", InvalidCertificate = "InvalidCertificate", InvalidConfiguration = "InvalidConfiguration", @@ -371,24 +289,12 @@ export interface GetTeamsUserTokenOptions extends GetTokenOptions { resources?: string[]; } -// @public @deprecated -export function getTediousConnectionConfig(teamsfx: TeamsFx, databaseName?: string): Promise; - // @public export function handleMessageExtensionLinkQueryWithSSO(context: TurnContext, config: OnBehalfOfCredentialAuthConfig, initiateLoginEndpoint: string, scopes: string | string[], logic: (token: MessageExtensionTokenResponse) => Promise): Promise; // @public export function handleMessageExtensionQueryWithSSO(context: TurnContext, config: OnBehalfOfCredentialAuthConfig, initiateLoginEndpoint: string, scopes: string | string[], logic: (token: MessageExtensionTokenResponse) => Promise): Promise; -// @public @deprecated -export function handleMessageExtensionQueryWithToken(context: TurnContext, config: AuthenticationConfiguration | null, scopes: string | string[], logic: (token: MessageExtensionTokenResponse) => Promise): Promise; - -// @public -export enum IdentityType { - App = "Application", - User = "User" -} - // @public export enum InvokeResponseErrorCode { BadRequest = 400, @@ -423,7 +329,7 @@ export enum LogLevel { } // @public -export class Member implements NotificationTarget { +class Member implements NotificationTarget { constructor(parent: TeamsBotInstallation, account: TeamsChannelAccount); readonly account: TeamsChannelAccount; readonly parent: TeamsBotInstallation; @@ -432,16 +338,6 @@ export class Member implements NotificationTarget { readonly type: NotificationTargetType; } -// @public -class Member_2 implements NotificationTarget { - constructor(parent: TeamsBotInstallation_2, account: TeamsChannelAccount); - readonly account: TeamsChannelAccount; - readonly parent: TeamsBotInstallation_2; - sendAdaptiveCard(card: unknown, onError?: (context: TurnContext, error: Error) => Promise): Promise; - sendMessage(text: string, onError?: (context: TurnContext, error: Error) => Promise): Promise; - readonly type: NotificationTargetType; -} - // @public export class MessageBuilder { static attachAdaptiveCard(cardTemplate: unknown, data: TData): Partial; @@ -461,48 +357,21 @@ export interface MessageExtensionTokenResponse extends TokenResponse { ssoTokenExpiration: string; } -// @public @deprecated -export class MsGraphAuthProvider implements AuthenticationProvider { - constructor(teamsfx: TeamsFxConfiguration, scopes?: string | string[]); - constructor(credential: TokenCredential, scopes?: string | string[]); - getAccessToken(): Promise; -} - -// @public @deprecated (undocumented) -export class NotificationBot { - constructor(adapter: BotFrameworkAdapter, options?: NotificationOptions_2); +// @public +class NotificationBot { + constructor(adapter: CloudAdapter, options?: NotificationOptions_2); + buildTeamsBotInstallation(conversationReference: Partial): TeamsBotInstallation | null; findAllChannels(predicate: (channel: Channel, teamDetails: TeamDetails | undefined) => Promise): Promise; findAllMembers(predicate: (member: Member) => Promise, scope?: SearchScope): Promise; findChannel(predicate: (channel: Channel, teamDetails: TeamDetails | undefined) => Promise): Promise; findMember(predicate: (member: Member) => Promise, scope?: SearchScope): Promise; - installations(): Promise; -} - -// @public -class NotificationBot_2 { - constructor(adapter: CloudAdapter, options?: NotificationOptions_3); - buildTeamsBotInstallation(conversationReference: Partial): TeamsBotInstallation_2 | null; - findAllChannels(predicate: (channel: Channel_2, teamDetails: TeamDetails | undefined) => Promise): Promise; - findAllMembers(predicate: (member: Member_2) => Promise, scope?: SearchScope_2): Promise; - findChannel(predicate: (channel: Channel_2, teamDetails: TeamDetails | undefined) => Promise): Promise; - findMember(predicate: (member: Member_2) => Promise, scope?: SearchScope_2): Promise; - getPagedInstallations(pageSize?: number, continuationToken?: string, validationEnabled?: boolean): Promise>; - // @deprecated - installations(): Promise; + getPagedInstallations(pageSize?: number, continuationToken?: string, validationEnabled?: boolean): Promise>; validateInstallation(conversationReference: Partial): Promise; } -// @public @deprecated -interface NotificationOptions_2 { - storage?: NotificationTargetStorage; -} -export { NotificationOptions_2 as NotificationOptions } - // @public -interface NotificationOptions_3 { +interface NotificationOptions_2 { botAppId?: string; - // @deprecated - storage?: NotificationTargetStorage; store?: ConversationReferenceStore; } @@ -513,20 +382,6 @@ export interface NotificationTarget { readonly type?: NotificationTargetType; } -// @public @deprecated -export interface NotificationTargetStorage { - delete(key: string): Promise; - list(): Promise<{ - [key: string]: unknown; - }[]>; - read(key: string): Promise<{ - [key: string]: unknown; - } | undefined>; - write(key: string, object: { - [key: string]: unknown; - }): Promise; -} - // @public export enum NotificationTargetType { Channel = "Channel", @@ -550,7 +405,6 @@ export type OnBehalfOfCredentialAuthConfig = { // @public export class OnBehalfOfUserCredential implements TokenCredential { constructor(ssoToken: string, config: OnBehalfOfCredentialAuthConfig); - constructor(ssoToken: string, config: AuthenticationConfiguration); getToken(scopes: string | string[], options?: GetTokenOptions): Promise; getUserInfo(): UserInfo; } @@ -562,7 +416,7 @@ export interface PagedData { } // @public -export enum SearchScope { +enum SearchScope { All = 7, Channel = 4, Group = 2, @@ -570,24 +424,10 @@ export enum SearchScope { } // @public -enum SearchScope_2 { - All = 7, - Channel = 4, - Group = 2, - Person = 1 -} - -// @public -export function sendAdaptiveCard(target: NotificationTarget, card: unknown, onError?: (context: TurnContext, error: Error) => Promise): Promise; +function sendAdaptiveCard(target: NotificationTarget, card: unknown, onError?: (context: TurnContext, error: Error) => Promise): Promise; // @public -function sendAdaptiveCard_2(target: NotificationTarget, card: unknown, onError?: (context: TurnContext, error: Error) => Promise): Promise; - -// @public -export function sendMessage(target: NotificationTarget, text: string, onError?: (context: TurnContext, error: Error) => Promise): Promise; - -// @public -function sendMessage_2(target: NotificationTarget, text: string, onError?: (context: TurnContext, error: Error) => Promise): Promise; +function sendMessage(target: NotificationTarget, text: string, onError?: (context: TurnContext, error: Error) => Promise): Promise; // @public export function setLogFunction(logFunction?: LogFunction): void; @@ -598,30 +438,15 @@ export function setLogger(logger?: Logger): void; // @public export function setLogLevel(level: LogLevel): void; -// @public @deprecated (undocumented) -export class TeamsBotInstallation implements NotificationTarget { - constructor(adapter: BotFrameworkAdapter, conversationReference: Partial); - readonly adapter: BotFrameworkAdapter; - channels(): Promise; - readonly conversationReference: Partial; - getTeamDetails(): Promise; - members(): Promise; - sendAdaptiveCard(card: unknown, onError?: (context: TurnContext, error: Error) => Promise): Promise; - sendMessage(text: string, onError?: (context: TurnContext, error: Error) => Promise): Promise; - readonly type?: NotificationTargetType; -} - // @public -class TeamsBotInstallation_2 implements NotificationTarget { +class TeamsBotInstallation implements NotificationTarget { constructor(adapter: CloudAdapter, conversationReference: Partial, botAppId: string); readonly adapter: CloudAdapter; readonly botAppId: string; - channels(): Promise; + channels(): Promise; readonly conversationReference: Partial; - getPagedMembers(pageSize?: number, continuationToken?: string): Promise>; + getPagedMembers(pageSize?: number, continuationToken?: string): Promise>; getTeamDetails(): Promise; - // @deprecated - members(): Promise; sendAdaptiveCard(card: unknown, onError?: (context: TurnContext, error: Error) => Promise): Promise; sendMessage(text: string, onError?: (context: TurnContext, error: Error) => Promise): Promise; readonly type?: NotificationTargetType; @@ -629,7 +454,6 @@ class TeamsBotInstallation_2 implements NotificationTarget { // @public export class TeamsBotSsoPrompt extends Dialog { - constructor(teamsfx: TeamsFx, dialogId: string, settings: TeamsBotSsoPromptSettings); constructor(authConfig: OnBehalfOfCredentialAuthConfig, initiateLoginEndpoint: string, dialogId: string, settings: TeamsBotSsoPromptSettings); beginDialog(dc: DialogContext): Promise; continueDialog(dc: DialogContext): Promise; @@ -648,19 +472,6 @@ export interface TeamsBotSsoPromptTokenResponse extends TokenResponse { ssoTokenExpiration: string; } -// @public @deprecated -export class TeamsFx implements TeamsFxConfiguration { - constructor(identityType?: IdentityType, customConfig?: Record | AuthenticationConfiguration); - getConfig(key: string): string; - getConfigs(): Record; - getCredential(): TokenCredential; - getIdentityType(): IdentityType; - getUserInfo(resources?: string[]): Promise; - hasConfig(key: string): boolean; - login(scopes: string | string[], resources?: string[]): Promise; - setSsoToken(ssoToken: string): TeamsFx; -} - // @public export interface TeamsFxAdaptiveCardActionHandler { adaptiveCardResponse?: AdaptiveCardResponse; @@ -683,7 +494,6 @@ export interface TeamsFxBotSsoCommandHandler { // @public export class TeamsUserCredential implements TokenCredential { constructor(authConfig: TeamsUserCredentialAuthConfig); - constructor(authConfig: AuthenticationConfiguration); getToken(scopes: string | string[], options?: GetTokenOptions): Promise; getUserInfo(resources?: string[]): Promise; login(scopes: string | string[], resources?: string[]): Promise; diff --git a/packages/sdk/rollup.config.js b/packages/sdk/rollup.config.js index 347fe4e1c7..1988620606 100644 --- a/packages/sdk/rollup.config.js +++ b/packages/sdk/rollup.config.js @@ -5,7 +5,7 @@ import pkg from "./package.json"; const deps = Object.keys(Object.assign({}, pkg.peerDependencies, pkg.dependencies)); -const nodeDeps = [...deps, "crypto", "fs", "path"]; +const nodeDeps = [...deps, "crypto", "fs", "path", "https"]; /** * ES5 Builds diff --git a/packages/sdk/src/bot/teamsBotSsoPrompt.browser.ts b/packages/sdk/src/bot/teamsBotSsoPrompt.browser.ts index b4a4a67c54..cc2f6da56c 100644 --- a/packages/sdk/src/bot/teamsBotSsoPrompt.browser.ts +++ b/packages/sdk/src/bot/teamsBotSsoPrompt.browser.ts @@ -4,7 +4,7 @@ import { DialogContext, DialogTurnResult } from "botbuilder-dialogs"; import { ErrorWithCode, ErrorCode, ErrorMessage } from "../core/errors"; import { formatString } from "../util/utils"; -import { TeamsFx } from "../core/teamsfx"; +import { OnBehalfOfCredentialAuthConfig } from "../models/configuration"; /** * Settings used to configure an TeamsBotSsoPrompt instance. @@ -92,9 +92,10 @@ export class TeamsBotSsoPrompt { * @throws {@link ErrorCode|RuntimeNotSupported} when runtime is browser. */ constructor( - private teamsfx: TeamsFx, + authConfig: OnBehalfOfCredentialAuthConfig, + initiateLoginEndpoint: string, dialogId: string, - private settings: TeamsBotSsoPromptSettings + settings: TeamsBotSsoPromptSettings ) { throw new ErrorWithCode( formatString(ErrorMessage.BrowserRuntimeNotSupported, "TeamsBotSsoPrompt"), diff --git a/packages/sdk/src/bot/teamsBotSsoPrompt.ts b/packages/sdk/src/bot/teamsBotSsoPrompt.ts index e87c0f0e5e..f5b9da779a 100644 --- a/packages/sdk/src/bot/teamsBotSsoPrompt.ts +++ b/packages/sdk/src/bot/teamsBotSsoPrompt.ts @@ -30,9 +30,7 @@ import { TeamsBotSsoPromptTokenResponse } from "./teamsBotSsoPromptTokenResponse import { v4 as uuidv4 } from "uuid"; import { ErrorWithCode, ErrorCode, ErrorMessage } from "../core/errors"; import { internalLogger } from "../util/logger"; -import { validateScopesType, formatString, parseJwt } from "../util/utils"; -import { TeamsFx } from "../core/teamsfx"; -import { IdentityType } from "../models/identityType"; +import { validateScopesType, formatString, parseJwt, validateConfig } from "../util/utils"; import { OnBehalfOfCredentialAuthConfig } from "../models/configuration"; import { OnBehalfOfUserCredential } from "../credential/onBehalfOfUserCredential"; @@ -133,17 +131,6 @@ export class TeamsBotSsoPrompt extends Dialog { private authConfig: OnBehalfOfCredentialAuthConfig; private initiateLoginEndpoint: string; private settings: TeamsBotSsoPromptSettings; - /** - * Constructor of TeamsBotSsoPrompt. - * - * @param {TeamsFx} teamsfx - Used to provide configuration and auth - * @param {string} dialogId Unique ID of the dialog within its parent `DialogSet` or `ComponentDialog`. - * @param {TeamsBotSsoPromptSettings} settings Settings used to configure the prompt. - * - * @throws {@link ErrorCode|InvalidParameter} when scopes is not a valid string or string array. - * @throws {@link ErrorCode|RuntimeNotSupported} when runtime is browser. - */ - constructor(teamsfx: TeamsFx, dialogId: string, settings: TeamsBotSsoPromptSettings); /** * Constructor of TeamsBotSsoPrompt. * @@ -160,21 +147,15 @@ export class TeamsBotSsoPrompt extends Dialog { initiateLoginEndpoint: string, dialogId: string, settings: TeamsBotSsoPromptSettings - ); - constructor(authConfig: TeamsFx | OnBehalfOfCredentialAuthConfig, ...args: any) { - super(arguments.length === 3 ? args[0] : args[1]); - if ((authConfig as TeamsFx).getCredential) { - const teamsfx = authConfig as TeamsFx; - this.authConfig = this.loadAndValidateConfig(teamsfx); - this.initiateLoginEndpoint = teamsfx.getConfig("initiateLoginEndpoint"); - this.settings = args[1] as TeamsBotSsoPromptSettings; - } else { - this.initiateLoginEndpoint = args[0]; - this.authConfig = authConfig as OnBehalfOfCredentialAuthConfig; - this.settings = args[2] as TeamsBotSsoPromptSettings; - } + ) { + super(dialogId); + + this.initiateLoginEndpoint = initiateLoginEndpoint; + this.authConfig = authConfig; + this.settings = settings; validateScopesType(this.settings.scopes); + validateConfig(this.authConfig); internalLogger.info("Create a new Teams Bot SSO Prompt"); } @@ -283,60 +264,6 @@ export class TeamsBotSsoPrompt extends Dialog { } } - private loadAndValidateConfig(teamsfx: TeamsFx): OnBehalfOfCredentialAuthConfig { - if (teamsfx.getIdentityType() !== IdentityType.User) { - const errorMsg = formatString( - ErrorMessage.IdentityTypeNotSupported, - teamsfx.getIdentityType().toString(), - "TeamsBotSsoPrompt" - ); - internalLogger.error(errorMsg); - throw new ErrorWithCode(errorMsg, ErrorCode.IdentityTypeNotSupported); - } - - const missingConfigurations: string[] = []; - - if (!teamsfx.hasConfig("initiateLoginEndpoint")) { - missingConfigurations.push("initiateLoginEndpoint"); - } - - if (!teamsfx.hasConfig("clientId")) { - missingConfigurations.push("clientId"); - } - - if (!teamsfx.hasConfig("tenantId")) { - missingConfigurations.push("tenantId"); - } - - if (missingConfigurations.length != 0) { - const errorMsg = formatString( - ErrorMessage.InvalidConfiguration, - missingConfigurations.join(", "), - "undefined" - ); - internalLogger.error(errorMsg); - throw new ErrorWithCode(errorMsg, ErrorCode.InvalidConfiguration); - } - - let authConfig: OnBehalfOfCredentialAuthConfig; - if (teamsfx.getConfig("clientSecret")) { - authConfig = { - authorityHost: teamsfx.getConfig("authorityHost"), - clientId: teamsfx.getConfig("clientId"), - tenantId: teamsfx.getConfig("tenantId"), - clientSecret: teamsfx.getConfig("clientSecret"), - }; - } else { - authConfig = { - authorityHost: teamsfx.getConfig("authorityHost"), - clientId: teamsfx.getConfig("clientId"), - tenantId: teamsfx.getConfig("tenantId"), - certificateContent: teamsfx.getConfig("certificateContent"), - }; - } - return authConfig; - } - /** * Ensure bot is running in MS Teams since TeamsBotSsoPrompt is only supported in MS Teams channel. * @param dc dialog context diff --git a/packages/sdk/src/conversation/cardAction.browser.ts b/packages/sdk/src/conversation/cardAction.browser.ts deleted file mode 100644 index ab93706f97..0000000000 --- a/packages/sdk/src/conversation/cardAction.browser.ts +++ /dev/null @@ -1,61 +0,0 @@ -import { BotFrameworkAdapter } from "botbuilder"; -import { CardActionMiddleware } from "./middlewares/cardActionMiddleware"; -import { CardActionOptions, TeamsFxAdaptiveCardActionHandler } from "./interface"; -import { ErrorWithCode, ErrorCode, ErrorMessage } from "../core/errors"; -import { formatString } from "../util/utils"; - -/** - * A card action bot to respond to adaptive card universal actions. - * - * @remarks - * Only work on server side. - */ - -/** - * @deprecated Use `BotBuilderCloudAdapter.CardActionBot` instead. - */ -export class CardActionBot { - private readonly adapter: BotFrameworkAdapter; - private middleware: CardActionMiddleware; - - /** - * Creates a new instance of the `CardActionBot`. - * - * @param adapter The bound `BotFrameworkAdapter`. - * @param options - initialize options - */ - constructor(adapter: BotFrameworkAdapter, options?: CardActionOptions) { - throw new ErrorWithCode( - formatString(ErrorMessage.BrowserRuntimeNotSupported, "CardActionBot"), - ErrorCode.RuntimeNotSupported - ); - } - - /** - * Registers a card action handler to the bot. - * @param actionHandler A card action handler to be registered. - * - * @remarks - * Only work on server side. - */ - registerHandler(actionHandler: TeamsFxAdaptiveCardActionHandler) { - throw new ErrorWithCode( - formatString(ErrorMessage.BrowserRuntimeNotSupported, "CardActionBot"), - ErrorCode.RuntimeNotSupported - ); - } - - /** - * Registers card action handlers to the bot. - * @param actionHandlers A set of card action handlers to be registered. - * - * @remarks - * Only work on server side. - */ - registerHandlers(actionHandlers: TeamsFxAdaptiveCardActionHandler[]) { - throw new ErrorWithCode( - formatString(ErrorMessage.BrowserRuntimeNotSupported, "CardActionBot"), - ErrorCode.RuntimeNotSupported - ); - } -} diff --git a/packages/sdk/src/conversation/cardAction.ts b/packages/sdk/src/conversation/cardAction.ts deleted file mode 100644 index 5ee2dee3ab..0000000000 --- a/packages/sdk/src/conversation/cardAction.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { BotFrameworkAdapter } from "botbuilder"; -import { CardActionMiddleware } from "./middlewares/cardActionMiddleware"; -import { CardActionOptions, TeamsFxAdaptiveCardActionHandler } from "./interface"; - -/** - * A card action bot to respond to adaptive card universal actions. - */ - -/** - * @deprecated Use `BotBuilderCloudAdapter.CardActionBot` instead. - */ -export class CardActionBot { - private readonly adapter: BotFrameworkAdapter; - private middleware: CardActionMiddleware; - - /** - * Creates a new instance of the `CardActionBot`. - * - * @param adapter The bound `BotFrameworkAdapter`. - * @param options - initialize options - */ - constructor(adapter: BotFrameworkAdapter, options?: CardActionOptions) { - this.middleware = new CardActionMiddleware(options?.actions); - this.adapter = adapter.use(this.middleware); - } - - /** - * Registers a card action handler to the bot. - * @param actionHandler A card action handler to be registered. - */ - registerHandler(actionHandler: TeamsFxAdaptiveCardActionHandler) { - if (actionHandler) { - this.middleware.actionHandlers.push(actionHandler); - } - } - - /** - * Registers card action handlers to the bot. - * @param actionHandlers A set of card action handlers to be registered. - */ - registerHandlers(actionHandlers: TeamsFxAdaptiveCardActionHandler[]) { - if (actionHandlers) { - this.middleware.actionHandlers.push(...actionHandlers); - } - } -} diff --git a/packages/sdk/src/conversation/command.browser.ts b/packages/sdk/src/conversation/command.browser.ts deleted file mode 100644 index 727fc66775..0000000000 --- a/packages/sdk/src/conversation/command.browser.ts +++ /dev/null @@ -1,90 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. - -import { BotFrameworkAdapter } from "botbuilder"; -import { ErrorWithCode, ErrorCode, ErrorMessage } from "../core/errors"; -import { formatString } from "../util/utils"; -import { TeamsFxBotCommandHandler, TeamsFxBotSsoCommandHandler } from "./interface"; -import { CommandResponseMiddleware } from "./middlewares/commandMiddleware"; - -/** - * A command bot for receiving commands and sending responses in Teams. - * - * @remarks - * Only work on server side. - */ - -/** - * @deprecated Use `BotBuilderCloudAdapter.CommandBot` instead. - */ -export class CommandBot { - private readonly adapter: BotFrameworkAdapter; - private readonly middleware: CommandResponseMiddleware; - - /** - * Creates a new instance of the `CommandBot`. - * - * @param adapter The bound `BotFrameworkAdapter`. - * @param commands The commands to registered with the command bot. Each command should implement the interface {@link TeamsFxBotCommandHandler} so that it can be correctly handled by this command bot. - */ - constructor(adapter: BotFrameworkAdapter, commands?: TeamsFxBotCommandHandler[]) { - throw new ErrorWithCode( - formatString(ErrorMessage.BrowserRuntimeNotSupported, "CommandBot"), - ErrorCode.RuntimeNotSupported - ); - } - - /** - * Registers a command into the command bot. - * - * @param command The command to registered. - * - * @remarks - * Only work on server side. - */ - public registerCommand(command: TeamsFxBotCommandHandler): void { - throw new ErrorWithCode( - formatString(ErrorMessage.BrowserRuntimeNotSupported, "CommandBot"), - ErrorCode.RuntimeNotSupported - ); - } - - /** - * Registers commands into the command bot. - * - * @param commands The command to registered. - * - * @remarks - * Only work on server side. - */ - public registerCommands(commands: TeamsFxBotCommandHandler[]): void { - throw new ErrorWithCode( - formatString(ErrorMessage.BrowserRuntimeNotSupported, "CommandBot"), - ErrorCode.RuntimeNotSupported - ); - } - - /** - * Registers a sso command into the command bot. - * - * @param command The command to register. - */ - public registerSsoCommand(ssoCommand: TeamsFxBotSsoCommandHandler): void { - throw new ErrorWithCode( - formatString(ErrorMessage.BrowserRuntimeNotSupported, "CommandBot"), - ErrorCode.RuntimeNotSupported - ); - } - - /** - * Registers commands into the command bot. - * - * @param commands The commands to register. - */ - public registerSsoCommands(ssoCommands: TeamsFxBotSsoCommandHandler[]): void { - throw new ErrorWithCode( - formatString(ErrorMessage.BrowserRuntimeNotSupported, "CommandBot"), - ErrorCode.RuntimeNotSupported - ); - } -} diff --git a/packages/sdk/src/conversation/command.ts b/packages/sdk/src/conversation/command.ts deleted file mode 100644 index a1ca2d1477..0000000000 --- a/packages/sdk/src/conversation/command.ts +++ /dev/null @@ -1,108 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. - -import { BotFrameworkAdapter } from "botbuilder"; -import { ErrorCode, ErrorMessage, ErrorWithCode } from "../core/errors"; -import { internalLogger } from "../util/logger"; -import { - CommandOptions, - BotSsoConfig, - BotSsoExecutionActivityHandler, - TeamsFxBotCommandHandler, - TeamsFxBotSsoCommandHandler, -} from "./interface"; -import { CommandResponseMiddleware } from "./middlewares/commandMiddleware"; - -/** - * A command bot for receiving commands and sending responses in Teams. - * - * @remarks - * Ensure each command should ONLY be registered with the command once, otherwise it'll cause unexpected behavior if you register the same command more than once. - */ - -/** - * @deprecated Use `BotBuilderCloudAdapter.CommandBot` instead. - */ -export class CommandBot { - private readonly adapter: BotFrameworkAdapter; - private readonly middleware: CommandResponseMiddleware; - private readonly ssoConfig: BotSsoConfig | undefined; - - /** - * Creates a new instance of the `CommandBot`. - * - * @param adapter The bound `BotFrameworkAdapter`. - * @param options - initialize options - */ - constructor( - adapter: BotFrameworkAdapter, - options?: CommandOptions, - ssoCommandActivityHandler?: BotSsoExecutionActivityHandler, - ssoConfig?: BotSsoConfig - ) { - this.ssoConfig = ssoConfig; - - this.middleware = new CommandResponseMiddleware( - options?.commands, - options?.ssoCommands, - ssoCommandActivityHandler - ); - this.adapter = adapter.use(this.middleware); - } - - /** - * Registers a command into the command bot. - * - * @param command The command to register. - */ - public registerCommand(command: TeamsFxBotCommandHandler): void { - if (command) { - this.middleware.commandHandlers.push(command); - } - } - - /** - * Registers commands into the command bot. - * - * @param commands The commands to register. - */ - public registerCommands(commands: TeamsFxBotCommandHandler[]): void { - if (commands) { - this.middleware.commandHandlers.push(...commands); - } - } - - /** - * Registers a sso command into the command bot. - * - * @param command The command to register. - */ - public registerSsoCommand(ssoCommand: TeamsFxBotSsoCommandHandler): void { - this.validateSsoActivityHandler(); - this.middleware.addSsoCommand(ssoCommand); - } - - /** - * Registers commands into the command bot. - * - * @param commands The commands to register. - */ - public registerSsoCommands(ssoCommands: TeamsFxBotSsoCommandHandler[]): void { - if (ssoCommands.length > 0) { - this.validateSsoActivityHandler(); - for (const ssoCommand of ssoCommands) { - this.middleware.addSsoCommand(ssoCommand); - } - } - } - - private validateSsoActivityHandler() { - if (!this.middleware.ssoActivityHandler) { - internalLogger.error(ErrorMessage.SsoActivityHandlerIsNull); - throw new ErrorWithCode( - ErrorMessage.SsoActivityHandlerIsNull, - ErrorCode.SsoActivityHandlerIsUndefined - ); - } - } -} diff --git a/packages/sdk/src/conversation/conversation.browser.ts b/packages/sdk/src/conversation/conversation.browser.ts deleted file mode 100644 index 4d54530b93..0000000000 --- a/packages/sdk/src/conversation/conversation.browser.ts +++ /dev/null @@ -1,83 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. - -import { BotFrameworkAdapter, TurnContext, WebRequest, WebResponse } from "botbuilder"; -import { CommandBot } from "./command.browser"; -import { ConversationOptions } from "./interface"; -import { NotificationBot } from "./notification.browser"; -import { ErrorWithCode, ErrorCode, ErrorMessage } from "../core/errors"; -import { formatString } from "../util/utils"; - -/** - * Provide utilities for bot conversation, including: - * - handle command and response. - * - send notification to varies targets (e.g., member, group, channel). - * - * @remarks - * Only work on server side. - */ - -/** - * @deprecated Use `BotBuilderCloudAdapter.ConversationBot` instead. - */ -export class ConversationBot { - /** - * The bot adapter. - * - * @remarks - * Only work on server side. - */ - public readonly adapter: BotFrameworkAdapter; - - /** - * The entrypoint of command and response. - * - * @remarks - * Only work on server side. - */ - public readonly command?: CommandBot; - - /** - * The entrypoint of notification. - * - * @remarks - * Only work on server side. - */ - public readonly notification?: NotificationBot; - - /** - * Creates new instance of the `ConversationBot`. - * - * @param options - initialize options - * - * @remarks - * Only work on server side. - */ - public constructor(options: ConversationOptions) { - throw new ErrorWithCode( - formatString(ErrorMessage.BrowserRuntimeNotSupported, "ConversationBot"), - ErrorCode.RuntimeNotSupported - ); - } - - /** - * The request handler to integrate with web request. - * - * @param req - an Express or Restify style request object. - * @param res - an Express or Restify style response object. - * @param logic - the additional function to handle bot context. - * - * @remarks - * Only work on server side. - */ - public requestHandler( - req: WebRequest, - res: WebResponse, - logic?: (context: TurnContext) => Promise - ): Promise { - throw new ErrorWithCode( - formatString(ErrorMessage.BrowserRuntimeNotSupported, "ConversationBot"), - ErrorCode.RuntimeNotSupported - ); - } -} diff --git a/packages/sdk/src/conversation/conversation.ts b/packages/sdk/src/conversation/conversation.ts deleted file mode 100644 index 06552e37c8..0000000000 --- a/packages/sdk/src/conversation/conversation.ts +++ /dev/null @@ -1,196 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. - -import { BotFrameworkAdapter, TurnContext, WebRequest, WebResponse } from "botbuilder"; -import { CardActionBot } from "./cardAction"; -import { CommandBot } from "./command"; -import { ConversationOptions, BotSsoExecutionActivityHandler } from "./interface"; -import { NotificationBot } from "./notification"; -import { DefaultBotSsoExecutionActivityHandler } from "./sso/defaultBotSsoExecutionActivityHandler"; - -/** - * Provide utilities for bot conversation, including: - * - handle command and response. - * - send notification to varies targets (e.g., member, group, channel). - * - * @example - * For command and response, you can register your commands through the constructor, or use the `registerCommand` and `registerCommands` API to add commands later. - * - * ```typescript - * // register through constructor - * const conversationBot = new ConversationBot({ - * command: { - * enabled: true, - * commands: [ new HelloWorldCommandHandler() ], - * }, - * }); - * - * // register through `register*` API - * conversationBot.command.registerCommand(new HelpCommandHandler()); - * ``` - * - * For notification, you can enable notification at initialization, then send notifications at any time. - * - * ```typescript - * // enable through constructor - * const conversationBot = new ConversationBot({ - * notification: { - * enabled: true, - * }, - * }); - * - * // get all bot installations and send message - * for (const target of await conversationBot.notification.installations()) { - * await target.sendMessage("Hello Notification"); - * } - * - * // alternative - send message to all members - * for (const target of await conversationBot.notification.installations()) { - * for (const member of await target.members()) { - * await member.sendMessage("Hello Notification"); - * } - * } - * ``` - * - * @remarks - * Set `adapter` in {@link ConversationOptions} to use your own bot adapter. - * - * For command and response, ensure each command should ONLY be registered with the command once, otherwise it'll cause unexpected behavior if you register the same command more than once. - * - * For notification, set `notification.storage` in {@link ConversationOptions} to use your own storage implementation. - */ - -/** - * @deprecated Use `BotBuilderCloudAdapter.ConversationBot` instead. - */ -export class ConversationBot { - /** - * The bot adapter. - */ - public readonly adapter: BotFrameworkAdapter; - - /** - * The entrypoint of command and response. - */ - public readonly command?: CommandBot; - - /** - * The entrypoint of notification. - */ - public readonly notification?: NotificationBot; - - /** - * The action handler used for adaptive card universal actions. - */ - public readonly cardAction?: CardActionBot; - - /** - * Creates new instance of the `ConversationBot`. - * - * @remarks - * It's recommended to create your own adapter and storage for production environment instead of the default one. - * - * @param options - initialize options - */ - public constructor(options: ConversationOptions) { - if (options.adapter) { - this.adapter = options.adapter; - } else { - this.adapter = this.createDefaultAdapter(options.adapterConfig); - } - - let ssoCommandActivityHandler: BotSsoExecutionActivityHandler | undefined; - - if (options?.ssoConfig) { - if (options.ssoConfig.dialog?.CustomBotSsoExecutionActivityHandler) { - ssoCommandActivityHandler = - new options.ssoConfig.dialog.CustomBotSsoExecutionActivityHandler(options.ssoConfig); - } else { - ssoCommandActivityHandler = new DefaultBotSsoExecutionActivityHandler(options.ssoConfig); - } - } - - if (options.command?.enabled) { - this.command = new CommandBot( - this.adapter, - options.command, - ssoCommandActivityHandler, - options.ssoConfig - ); - } - - if (options.notification?.enabled) { - this.notification = new NotificationBot(this.adapter, options.notification); - } - - if (options.cardAction?.enabled) { - this.cardAction = new CardActionBot(this.adapter, options.cardAction); - } - } - - private createDefaultAdapter(adapterConfig?: { [key: string]: unknown }): BotFrameworkAdapter { - const adapter = - adapterConfig === undefined - ? new BotFrameworkAdapter({ - appId: process.env.BOT_ID, - appPassword: process.env.BOT_PASSWORD, - }) - : new BotFrameworkAdapter(adapterConfig); - - // the default error handler - adapter.onTurnError = async (context, error) => { - // This check writes out errors to console. - // eslint-disable-next-line @typescript-eslint/restrict-template-expressions - console.error(`[onTurnError] unhandled error: ${error}`); - - // Send a trace activity, which will be displayed in Bot Framework Emulator - await context.sendTraceActivity( - "OnTurnError Trace", - // eslint-disable-next-line @typescript-eslint/restrict-template-expressions - `${error}`, - "https://www.botframework.com/schemas/error", - "TurnError" - ); - - // Send a message to the user - await context.sendActivity(`The bot encountered unhandled error: ${error.message}`); - await context.sendActivity("To continue to run this bot, please fix the bot source code."); - }; - - return adapter; - } - - /** - * The request handler to integrate with web request. - * - * @param req - an Express or Restify style request object. - * @param res - an Express or Restify style response object. - * @param logic - the additional function to handle bot context. - * - * @example - * For example, to use with Restify: - * ``` typescript - * // The default/empty behavior - * server.post("api/messages", conversationBot.requestHandler); - * - * // Or, add your own logic - * server.post("api/messages", async (req, res) => { - * await conversationBot.requestHandler(req, res, async (context) => { - * // your-own-context-logic - * }); - * }); - * ``` - */ - public async requestHandler( - req: WebRequest, - res: WebResponse, - logic?: (context: TurnContext) => Promise - ): Promise { - if (logic === undefined) { - // create empty logic - logic = async () => {}; - } - - await this.adapter.processActivity(req, res, logic); - } -} diff --git a/packages/sdk/src/conversation/interface.ts b/packages/sdk/src/conversation/interface.ts index f2a083577d..453fab6788 100644 --- a/packages/sdk/src/conversation/interface.ts +++ b/packages/sdk/src/conversation/interface.ts @@ -2,7 +2,6 @@ // Licensed under the MIT license. import { - BotFrameworkAdapter, ConversationState, ConversationReference, UserState, @@ -13,10 +12,7 @@ import { SigninStateVerificationQuery, } from "botbuilder"; import { TeamsBotSsoPromptTokenResponse } from "../bot/teamsBotSsoPromptTokenResponse"; -import { - AuthenticationConfiguration, - OnBehalfOfCredentialAuthConfig, -} from "../models/configuration"; +import { OnBehalfOfCredentialAuthConfig } from "../models/configuration"; /** * The response of a message action, e.g., `sendMessage`, `sendAdaptiveCard`. @@ -90,64 +86,6 @@ export interface NotificationTarget { ): Promise; } -/** - * Interface for a storage provider that stores and retrieves notification target references. - * - * @deprecated Use ConversationReferenceStore to customize the way - * to persist bot notification connections instead. - */ -export interface NotificationTargetStorage { - /** - * Read one notification target by its key. - * - * @param key - the key of a notification target. - * - * @returns - the notification target. Or undefined if not found. - */ - read(key: string): Promise<{ [key: string]: unknown } | undefined>; - - /** - * List all stored notification targets. - * - * @returns - an array of notification target. Or an empty array if nothing is stored. - */ - list(): Promise<{ [key: string]: unknown }[]>; - - /** - * Write one notification target by its key. - * - * @param key - the key of a notification target. - * @param object - the notification target. - */ - write(key: string, object: { [key: string]: unknown }): Promise; - - /** - * Delete one notification target by its key. - * - * @param key - the key of a notification target. - */ - delete(key: string): Promise; -} - -/** - * Options to initialize {@link NotificationBot}. - * @deprecated Please use BotBuilderCloudAdapter.NotificationOptions instead. - */ -export interface NotificationOptions { - /** - * An optional storage to persist bot notification connections. - * - * @remarks - * If `storage` is not provided, a default local file storage will be used, - * which stores notification connections into: - * - ".notification.localstore.json" if running locally - * - "${process.env.TEMP}/.notification.localstore.json" if `process.env.RUNNING_ON_AZURE` is set to "1" - * - * It's recommended to use your own shared storage for production environment. - */ - storage?: NotificationTargetStorage; -} - /** * A store to persist notification target references. */ @@ -402,12 +340,10 @@ export interface BotSsoConfig { * The list of scopes for which the token will have access */ scopes: string[]; - } & ( - | (OnBehalfOfCredentialAuthConfig & { initiateLoginEndpoint: string }) - | AuthenticationConfiguration - ); + } & OnBehalfOfCredentialAuthConfig & { initiateLoginEndpoint: string }; dialog?: { + // eslint-disable-next-line no-secrets/no-secrets /** * Custom sso execution activity handler class which should implement the interface {@link BotSsoExecutionActivityHandler}. If not provided, it will use {@link DefaultBotSsoExecutionActivityHandler} by default */ @@ -451,65 +387,7 @@ export interface BotSsoConfig { }; } -/** - * Options to initialize {@link ConversationBot} - * @deprecated Please use BotBuilderCloudAdapter.ConversationOptions instead. - */ -export interface ConversationOptions { - /** - * The bot adapter. If not provided, a default adapter will be created: - * - with `adapterConfig` as constructor parameter. - * - with a default error handler that logs error to console, sends trace activity, and sends error message to user. - * - * @remarks - * If neither `adapter` nor `adapterConfig` is provided, will use BOT_ID and BOT_PASSWORD from environment variables. - */ - adapter?: BotFrameworkAdapter; - - /** - * If `adapter` is not provided, this `adapterConfig` will be passed to the new `BotFrameworkAdapter` when created internally. - * - * @remarks - * If neither `adapter` nor `adapterConfig` is provided, will use BOT_ID and BOT_PASSWORD from environment variables. - */ - adapterConfig?: { [key: string]: unknown }; - - /** - * Configurations for sso command bot - */ - ssoConfig?: BotSsoConfig; - - /** - * The command part. - */ - command?: CommandOptions & { - /** - * Whether to enable command or not. - */ - enabled?: boolean; - }; - - /** - * The notification part. - */ - notification?: NotificationOptions & { - /** - * Whether to enable notification or not. - */ - enabled?: boolean; - }; - - /** - * The adaptive card action handler part. - */ - cardAction?: CardActionOptions & { - /** - * Whether to enable adaptive card actions or not. - */ - enabled?: boolean; - }; -} - +// eslint-disable-next-line no-secrets/no-secrets /** * Interface for user to customize SSO execution activity handler * @@ -532,6 +410,7 @@ export interface ConversationOptions { * For details information about how to implement a BotSsoExecutionActivityHandler, please refer DefaultBotSsoExecutionActivityHandler class source code: https://aka.ms/teamsfx-default-sso-execution-activity-handler */ export interface BotSsoExecutionActivityHandler { + // eslint-disable-next-line no-secrets/no-secrets /** * Add {@link TeamsFxBotSsoCommandHandler} instance to {@link BotSsoExecutionDialog} * @param handler {@link BotSsoExecutionDialogHandler} callback function diff --git a/packages/sdk/src/conversation/middlewares/cardActionMiddleware.ts b/packages/sdk/src/conversation/middlewares/cardActionMiddleware.ts index 3b78db24c5..94883da333 100644 --- a/packages/sdk/src/conversation/middlewares/cardActionMiddleware.ts +++ b/packages/sdk/src/conversation/middlewares/cardActionMiddleware.ts @@ -1,3 +1,5 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. import { ActivityTypes, CardFactory, diff --git a/packages/sdk/src/conversation/notification.browser.ts b/packages/sdk/src/conversation/notification.browser.ts deleted file mode 100644 index db069c4378..0000000000 --- a/packages/sdk/src/conversation/notification.browser.ts +++ /dev/null @@ -1,567 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. - -import { - BotFrameworkAdapter, - ChannelInfo, - ConversationReference, - TeamDetails, - TeamsChannelAccount, - TurnContext, -} from "botbuilder"; -import { ErrorWithCode, ErrorCode, ErrorMessage } from "../core/errors"; -import { formatString } from "../util/utils"; -import { MessageResponse, NotificationTarget, NotificationTargetType } from "./interface"; -import { DefaultConversationReferenceStore } from "./storage"; - -/** - * Send a plain text message to a notification target. - * - * @remarks - * Only work on server side. - * - * @param target - the notification target. - * @param text - the plain text message. - * @param onError - an optional error handler that can catch exceptions during message sending. - * @returns A `Promise` representing the asynchronous operation. - */ -export function sendMessage( - target: NotificationTarget, - text: string, - onError?: (context: TurnContext, error: Error) => Promise -): Promise { - throw new ErrorWithCode( - formatString(ErrorMessage.BrowserRuntimeNotSupported, "sendMessage"), - ErrorCode.RuntimeNotSupported - ); -} - -/** - * Send an adaptive card message to a notification target. - * - * @remarks - * Only work on server side. - * - * @param target - the notification target. - * @param card - the adaptive card raw JSON. - * @param onError - an optional error handler that can catch exceptions during adaptive card sending. - * @returns A `Promise` representing the asynchronous operation. - */ -export function sendAdaptiveCard( - target: NotificationTarget, - card: unknown, - onError?: (context: TurnContext, error: Error) => Promise -): Promise { - throw new ErrorWithCode( - formatString(ErrorMessage.BrowserRuntimeNotSupported, "sendAdaptiveCard"), - ErrorCode.RuntimeNotSupported - ); -} - -/** - * A {@link NotificationTarget} that represents a team channel. - * - * @remarks - * Only work on server side. - * - * It's recommended to get channels from {@link TeamsBotInstallation.channels()}. - */ -export class Channel implements NotificationTarget { - /** - * The parent {@link TeamsBotInstallation} where this channel is created from. - * - * @remarks - * Only work on server side. - */ - public readonly parent: TeamsBotInstallation; - - /** - * Detailed channel information. - * - * @remarks - * Only work on server side. - */ - public readonly info: ChannelInfo; - - /** - * Notification target type. For channel it's always "Channel". - * - * @remarks - * Only work on server side. - */ - public readonly type: NotificationTargetType = NotificationTargetType.Channel; - - /** - * Constructor. - * - * @remarks - * Only work on server side. - * - * It's recommended to get channels from {@link TeamsBotInstallation.channels()}, instead of using this constructor. - * - * @param parent - The parent {@link TeamsBotInstallation} where this channel is created from. - * @param info - Detailed channel information. - */ - constructor(parent: TeamsBotInstallation, info: ChannelInfo) { - throw new ErrorWithCode( - formatString(ErrorMessage.BrowserRuntimeNotSupported, "Channel"), - ErrorCode.RuntimeNotSupported - ); - } - - /** - * Send a plain text message. - * - * @remarks - * Only work on server side. - * - * @param text - the plain text message. - * @param onError - an optional error handler that can catch exceptions during message sending. - * @returns the response of sending message. - */ - public sendMessage( - text: string, - onError?: (context: TurnContext, error: Error) => Promise - ): Promise { - throw new ErrorWithCode( - formatString(ErrorMessage.BrowserRuntimeNotSupported, "Channel"), - ErrorCode.RuntimeNotSupported - ); - } - - /** - * Send an adaptive card message. - * - * @remarks - * Only work on server side. - * - * @param card - the adaptive card raw JSON. - * @param onError - an optional error handler that can catch exceptions during adaptive card sending. - * @returns the response of sending adaptive card message. - */ - public sendAdaptiveCard( - card: unknown, - onError?: (context: TurnContext, error: Error) => Promise - ): Promise { - throw new ErrorWithCode( - formatString(ErrorMessage.BrowserRuntimeNotSupported, "Channel"), - ErrorCode.RuntimeNotSupported - ); - } -} - -/** - * A {@link NotificationTarget} that represents a team member. - * - * @remarks - * Only work on server side. - * - * It's recommended to get members from {@link TeamsBotInstallation.members()}. - */ -export class Member implements NotificationTarget { - /** - * The parent {@link TeamsBotInstallation} where this member is created from. - * - * @remarks - * Only work on server side. - */ - public readonly parent: TeamsBotInstallation; - - /** - * Detailed member account information. - * - * @remarks - * Only work on server side. - */ - public readonly account: TeamsChannelAccount; - - /** - * Notification target type. For member it's always "Person". - * - * @remarks - * Only work on server side. - */ - public readonly type: NotificationTargetType = NotificationTargetType.Person; - - /** - * Constructor. - * - * @remarks - * Only work on server side. - * - * It's recommended to get members from {@link TeamsBotInstallation.members()}, instead of using this constructor. - * - * @param parent - The parent {@link TeamsBotInstallation} where this member is created from. - * @param account - Detailed member account information. - */ - constructor(parent: TeamsBotInstallation, account: TeamsChannelAccount) { - throw new ErrorWithCode( - formatString(ErrorMessage.BrowserRuntimeNotSupported, "Member"), - ErrorCode.RuntimeNotSupported - ); - } - - /** - * Send a plain text message. - * - * @remarks - * Only work on server side. - * - * @param text - the plain text message. - * @param onError - an optional error handler that can catch exceptions during message sending. - * @returns the response of sending message. - */ - public sendMessage( - text: string, - onError?: (context: TurnContext, error: Error) => Promise - ): Promise { - throw new ErrorWithCode( - formatString(ErrorMessage.BrowserRuntimeNotSupported, "Member"), - ErrorCode.RuntimeNotSupported - ); - } - - /** - * Send an adaptive card message. - * - * @remarks - * Only work on server side. - * - * @param card - the adaptive card raw JSON. - * @param onError - an optional error handler that can catch exceptions during adaptive card sending. - * @returns the response of sending adaptive card message. - */ - public sendAdaptiveCard( - card: unknown, - onError?: (context: TurnContext, error: Error) => Promise - ): Promise { - throw new ErrorWithCode( - formatString(ErrorMessage.BrowserRuntimeNotSupported, "Member"), - ErrorCode.RuntimeNotSupported - ); - } -} - -/** - * A {@link NotificationTarget} that represents a bot installation. Teams Bot could be installed into - * - Personal chat - * - Group chat - * - Team (by default the `General` channel) - * - * @remarks - * Only work on server side. - * - * It's recommended to get bot installations from {@link ConversationBot.installations()}. - */ - -/** - * @deprecated Use `BotBuilderCloudAdapter.TeamsBotInstallation` instead. - */ -export class TeamsBotInstallation implements NotificationTarget { - /** - * The bound `BotFrameworkAdapter`. - * - * @remarks - * Only work on server side. - */ - public readonly adapter: BotFrameworkAdapter; - - /** - * The bound `ConversationReference`. - * - * @remarks - * Only work on server side. - */ - public readonly conversationReference: Partial; - - /** - * Notification target type. - * - * @remarks - * Only work on server side. - * - "Channel" means bot is installed into a team and notification will be sent to its "General" channel. - * - "Group" means bot is installed into a group chat. - * - "Person" means bot is installed into a personal scope and notification will be sent to personal chat. - */ - public readonly type?: NotificationTargetType; - - /** - * Constructor - * - * @remarks - * Only work on server side. - * - * It's recommended to get bot installations from {@link ConversationBot.installations()}, instead of using this constructor. - * - * @param adapter - the bound `BotFrameworkAdapter`. - * @param conversationReference - the bound `ConversationReference`. - */ - constructor(adapter: BotFrameworkAdapter, conversationReference: Partial) { - throw new ErrorWithCode( - formatString(ErrorMessage.BrowserRuntimeNotSupported, "TeamsBotInstallation"), - ErrorCode.RuntimeNotSupported - ); - } - - /** - * Send a plain text message. - * - * @remarks - * Only work on server side. - * - * @param text - the plain text message. - * @param onError - an optional error handler that can catch exceptions during message sending. - * @returns the response of sending message. - */ - public sendMessage( - text: string, - onError?: (context: TurnContext, error: Error) => Promise - ): Promise { - throw new ErrorWithCode( - formatString(ErrorMessage.BrowserRuntimeNotSupported, "TeamsBotInstallation"), - ErrorCode.RuntimeNotSupported - ); - } - - /** - * Send an adaptive card message. - * - * @remarks - * Only work on server side. - * - * @param card - the adaptive card raw JSON. - * @param onError - an optional error handler that can catch exceptions during adaptive card sending. - * @returns the response of sending adaptive card message. - */ - public sendAdaptiveCard( - card: unknown, - onError?: (context: TurnContext, error: Error) => Promise - ): Promise { - throw new ErrorWithCode( - formatString(ErrorMessage.BrowserRuntimeNotSupported, "TeamsBotInstallation"), - ErrorCode.RuntimeNotSupported - ); - } - - /** - * Get channels from this bot installation. - * - * @remarks - * Only work on server side. - * - * @returns an array of channels if bot is installed into a team, otherwise returns an empty array. - */ - public channels(): Promise { - throw new ErrorWithCode( - formatString(ErrorMessage.BrowserRuntimeNotSupported, "TeamsBotInstallation"), - ErrorCode.RuntimeNotSupported - ); - } - - /** - * Get members from this bot installation. - * - * @remarks - * Only work on server side. - * - * @returns an array of members from where the bot is installed. - */ - public members(): Promise { - throw new ErrorWithCode( - formatString(ErrorMessage.BrowserRuntimeNotSupported, "TeamsBotInstallation"), - ErrorCode.RuntimeNotSupported - ); - } - - /** - * Get team details from this bot installation - * - * @returns the team details if bot is installed into a team, otherwise returns undefined. - */ - public getTeamDetails(): Promise { - throw new ErrorWithCode( - formatString(ErrorMessage.BrowserRuntimeNotSupported, "TeamsBotInstallation"), - ErrorCode.RuntimeNotSupported - ); - } -} - -/** - * Provide static utilities for bot notification. - * - * @remarks - * Only work on server side. - * - * @example - * Here's an example on how to send notification via Teams Bot. - * ```typescript - * // initialize (it's recommended to be called before handling any bot message) - * const notificationBot = new NotificationBot(adapter); - * - * // get all bot installations and send message - * for (const target of await notificationBot.installations()) { - * await target.sendMessage("Hello Notification"); - * } - * - * // alternative - send message to all members - * for (const target of await notificationBot.installations()) { - * for (const member of await target.members()) { - * await member.sendMessage("Hello Notification"); - * } - * } - * ``` - */ - -/** - * @deprecated Use `BotBuilderCloudAdapter.NotificationBot` instead. - */ -export class NotificationBot { - private readonly conversationReferenceStore: DefaultConversationReferenceStore; - private readonly adapter: BotFrameworkAdapter; - - /** - * constructor of the notification bot. - * - * @remarks - * Only work on server side. - * - * To ensure accuracy, it's recommended to initialize before handling any message. - * - * @param adapter - the bound `BotFrameworkAdapter` - * @param options - initialize options - */ - public constructor(adapter: BotFrameworkAdapter, options?: NotificationOptions) { - throw new ErrorWithCode( - formatString(ErrorMessage.BrowserRuntimeNotSupported, "NotificationBot"), - ErrorCode.RuntimeNotSupported - ); - } - - /** - * Get all targets where the bot is installed. - * - * @remarks - * Only work on server side. - * - * The result is retrieving from the persisted storage. - * - * @returns - an array of {@link TeamsBotInstallation}. - */ - public static installations(): Promise { - throw new ErrorWithCode( - formatString(ErrorMessage.BrowserRuntimeNotSupported, "NotificationBot"), - ErrorCode.RuntimeNotSupported - ); - } - - /** - * Returns the first {@link Member} where predicate is true, and undefined otherwise. - * - * @remarks - * Only work on server side. - * - * @param predicate find calls predicate once for each member of the installation, - * until it finds one where predicate returns true. If such a member is found, find - * immediately returns that member. Otherwise, find returns undefined. - * @param scope the scope to find members from the installations - * (personal chat, group chat, Teams channel). - * @returns the first {@link Member} where predicate is true, and undefined otherwise. - */ - public findMember( - predicate: (member: Member) => Promise, - scope?: SearchScope - ): Promise { - throw new ErrorWithCode( - formatString(ErrorMessage.BrowserRuntimeNotSupported, "NotificationBot"), - ErrorCode.RuntimeNotSupported - ); - } - - /** - * Returns the first {@link Channel} where predicate is true, and undefined otherwise. - * (Ensure the bot app is installed into the `General` channel, otherwise undefined will be returned.) - * - * @remarks - * Only work on server side. - * - * @param predicate find calls predicate once for each channel of the installation, - * until it finds one where predicate returns true. If such a channel is found, find - * immediately returns that channel. Otherwise, find returns undefined. - * @returns the first {@link Channel} where predicate is true, and undefined otherwise. - */ - public findChannel( - predicate: (channel: Channel, teamDetails: TeamDetails | undefined) => Promise - ): Promise { - throw new ErrorWithCode( - formatString(ErrorMessage.BrowserRuntimeNotSupported, "NotificationBot"), - ErrorCode.RuntimeNotSupported - ); - } - - /** - * Returns all {@link Member} where predicate is true, and empty array otherwise. - * - * @remarks - * Only work on server side. - * - * @param predicate find calls predicate for each member of the installation. - * @param scope the scope to find members from the installations - * (personal chat, group chat, Teams channel). - * @returns an array of {@link Member} where predicate is true, and empty array otherwise. - */ - public findAllMembers( - predicate: (member: Member) => Promise, - scope?: SearchScope - ): Promise { - throw new ErrorWithCode( - formatString(ErrorMessage.BrowserRuntimeNotSupported, "NotificationBot"), - ErrorCode.RuntimeNotSupported - ); - } - - /** - * Returns all {@link Channel} where predicate is true, and empty array otherwise. - * (Ensure the bot app is installed into the `General` channel, otherwise empty array will be returned.) - * - * @remarks - * Only work on server side. - * - * @param predicate find calls predicate for each channel of the installation. - * @returns an array of {@link Channel} where predicate is true, and empty array otherwise. - */ - public findAllChannels( - predicate: (channel: Channel, teamDetails: TeamDetails | undefined) => Promise - ): Promise { - throw new ErrorWithCode( - formatString(ErrorMessage.BrowserRuntimeNotSupported, "NotificationBot"), - ErrorCode.RuntimeNotSupported - ); - } -} - -/** - * The search scope when calling {@link NotificationBot.findMember} and {@link NotificationBot.findAllMembers}. - * The search scope is a flagged enum and it can be combined with `|`. - * For example, to search from personal chat and group chat, use `SearchScope.Person | SearchScope.Group`. - */ -export enum SearchScope { - /** - * Search members from the installations in personal chat only. - */ - Person = 1, - - /** - * Search members from the installations in group chat only. - */ - Group = 2, - - /** - * Search members from the installations in Teams channel only. - */ - Channel = 4, - - /** - * Search members from all installations including personal chat, group chat and Teams channel. - */ - All = Person | Group | Channel, -} diff --git a/packages/sdk/src/conversation/notification.ts b/packages/sdk/src/conversation/notification.ts deleted file mode 100644 index b9aee4cc97..0000000000 --- a/packages/sdk/src/conversation/notification.ts +++ /dev/null @@ -1,698 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. - -import { - BotFrameworkAdapter, - CardFactory, - ChannelInfo, - ConversationParameters, - ConversationReference, - TeamDetails, - TeamsChannelAccount, - TeamsInfo, - TurnContext, -} from "botbuilder"; -import type { ConnectorClient } from "botframework-connector"; -import * as path from "path"; -import { - NotificationTarget, - NotificationTargetType, - NotificationOptions, - MessageResponse, -} from "./interface"; -import { NotificationMiddleware } from "./middlewares/notificationMiddleware"; -import { DefaultConversationReferenceStore, LocalFileStorage } from "./storage"; -import * as utils from "./utils"; - -/** - * Send a plain text message to a notification target. - * - * @param target - the notification target. - * @param text - the plain text message. - * @param onError - an optional error handler that can catch exceptions during message sending. - * If not defined, error will be handled by `BotAdapter.onTurnError`. - * @returns the response of sending message. - */ -export function sendMessage( - target: NotificationTarget, - text: string, - onError?: (context: TurnContext, error: Error) => Promise -): Promise { - return target.sendMessage(text, onError); -} - -/** - * Send an adaptive card message to a notification target. - * - * @param target - the notification target. - * @param card - the adaptive card raw JSON. - * @param onError - an optional error handler that can catch exceptions during adaptive card sending. - * If not defined, error will be handled by `BotAdapter.onTurnError`. - * @returns the response of sending adaptive card message. - */ -export function sendAdaptiveCard( - target: NotificationTarget, - card: unknown, - onError?: (context: TurnContext, error: Error) => Promise -): Promise { - return target.sendAdaptiveCard(card, onError); -} - -/** - * A {@link NotificationTarget} that represents a team channel. - * - * @remarks - * It's recommended to get channels from {@link TeamsBotInstallation.channels()}. - */ -export class Channel implements NotificationTarget { - /** - * The parent {@link TeamsBotInstallation} where this channel is created from. - */ - public readonly parent: TeamsBotInstallation; - - /** - * Detailed channel information. - */ - public readonly info: ChannelInfo; - - /** - * Notification target type. For channel it's always "Channel". - */ - public readonly type: NotificationTargetType = NotificationTargetType.Channel; - - /** - * Constructor. - * - * @remarks - * It's recommended to get channels from {@link TeamsBotInstallation.channels()}, instead of using this constructor. - * - * @param parent - The parent {@link TeamsBotInstallation} where this channel is created from. - * @param info - Detailed channel information. - */ - constructor(parent: TeamsBotInstallation, info: ChannelInfo) { - this.parent = parent; - this.info = info; - } - - /** - * Send a plain text message. - * - * @param text - the plain text message. - * @param onError - an optional error handler that can catch exceptions during message sending. - * If not defined, error will be handled by `BotAdapter.onTurnError`. - * @returns the response of sending message. - */ - public async sendMessage( - text: string, - onError?: (context: TurnContext, error: Error) => Promise - ): Promise { - const response: MessageResponse = {}; - await this.parent.adapter.continueConversation( - this.parent.conversationReference, - async (context) => { - const conversation = this.newConversation(context); - await this.parent.adapter.continueConversation(conversation, async (ctx: TurnContext) => { - try { - const res = await ctx.sendActivity(text); - response.id = res?.id; - } catch (error) { - if (onError) { - await onError(ctx, error as Error); - } else { - throw error; - } - } - }); - } - ); - return response; - } - - /** - * Send an adaptive card message. - * - * @param card - the adaptive card raw JSON. - * @param onError - an optional error handler that can catch exceptions during adaptive card sending. - * If not defined, error will be handled by `BotAdapter.onTurnError`. - * @returns the response of sending adaptive card message. - */ - public async sendAdaptiveCard( - card: unknown, - onError?: (context: TurnContext, error: Error) => Promise - ): Promise { - const response: MessageResponse = {}; - await this.parent.adapter.continueConversation( - this.parent.conversationReference, - async (context) => { - const conversation = this.newConversation(context); - await this.parent.adapter.continueConversation(conversation, async (ctx: TurnContext) => { - try { - const res = await ctx.sendActivity({ - attachments: [CardFactory.adaptiveCard(card)], - }); - response.id = res?.id; - } catch (error) { - if (onError) { - await onError(ctx, error as Error); - } else { - throw error; - } - } - }); - } - ); - return response; - } - - /** - * @internal - */ - private newConversation(context: TurnContext): ConversationReference { - const reference = TurnContext.getConversationReference(context.activity); - const channelConversation = utils.cloneConversation(reference); - channelConversation.conversation.id = this.info.id || ""; - - return channelConversation; - } -} - -/** - * A {@link NotificationTarget} that represents a team member. - * - * @remarks - * It's recommended to get members from {@link TeamsBotInstallation.members()}. - */ -export class Member implements NotificationTarget { - /** - * The parent {@link TeamsBotInstallation} where this member is created from. - */ - public readonly parent: TeamsBotInstallation; - - /** - * Detailed member account information. - */ - public readonly account: TeamsChannelAccount; - - /** - * Notification target type. For member it's always "Person". - */ - public readonly type: NotificationTargetType = NotificationTargetType.Person; - - /** - * Constructor. - * - * @remarks - * It's recommended to get members from {@link TeamsBotInstallation.members()}, instead of using this constructor. - * - * @param parent - The parent {@link TeamsBotInstallation} where this member is created from. - * @param account - Detailed member account information. - */ - constructor(parent: TeamsBotInstallation, account: TeamsChannelAccount) { - this.parent = parent; - this.account = account; - } - - /** - * Send a plain text message. - * - * @param text - the plain text message. - * @param onError - an optional error handler that can catch exceptions during message sending. - * If not defined, error will be handled by `BotAdapter.onTurnError`. - * @returns the response of sending message. - */ - public async sendMessage( - text: string, - onError?: (context: TurnContext, error: Error) => Promise - ): Promise { - const response: MessageResponse = {}; - await this.parent.adapter.continueConversation( - this.parent.conversationReference, - async (context) => { - const conversation = await this.newConversation(context); - await this.parent.adapter.continueConversation(conversation, async (ctx: TurnContext) => { - try { - const res = await ctx.sendActivity(text); - response.id = res?.id; - } catch (error) { - if (onError) { - await onError(ctx, error as Error); - } else { - throw error; - } - } - }); - } - ); - return response; - } - - /** - * Send an adaptive card message. - * - * @param card - the adaptive card raw JSON. - * @param onError - an optional error handler that can catch exceptions during adaptive card sending. - * If not defined, error will be handled by `BotAdapter.onTurnError`. - * @returns the response of sending adaptive card message. - */ - public async sendAdaptiveCard( - card: unknown, - onError?: (context: TurnContext, error: Error) => Promise - ): Promise { - const response: MessageResponse = {}; - await this.parent.adapter.continueConversation( - this.parent.conversationReference, - async (context) => { - const conversation = await this.newConversation(context); - await this.parent.adapter.continueConversation(conversation, async (ctx: TurnContext) => { - try { - const res = await ctx.sendActivity({ - attachments: [CardFactory.adaptiveCard(card)], - }); - response.id = res?.id; - } catch (error) { - if (onError) { - await onError(ctx, error as Error); - } else { - throw error; - } - } - }); - } - ); - return response; - } - - /** - * @internal - */ - private async newConversation(context: TurnContext): Promise { - const reference = TurnContext.getConversationReference(context.activity); - const personalConversation = utils.cloneConversation(reference); - - const connectorClient: ConnectorClient = context.turnState.get( - this.parent.adapter.ConnectorClientKey - ); - const conversation = await connectorClient.conversations.createConversation({ - isGroup: false, - tenantId: context.activity.conversation.tenantId, - bot: context.activity.recipient, - members: [this.account], - channelData: {}, - } as ConversationParameters); - personalConversation.conversation.id = conversation.id; - - return personalConversation; - } -} - -/** - * A {@link NotificationTarget} that represents a bot installation. Teams Bot could be installed into - * - Personal chat - * - Group chat - * - Team (by default the `General` channel) - * - * @remarks - * It's recommended to get bot installations from {@link ConversationBot.installations()}. - */ - -/** - * @deprecated Use `BotBuilderCloudAdapter.TeamsBotInstallation` instead. - */ -export class TeamsBotInstallation implements NotificationTarget { - /** - * The bound `BotFrameworkAdapter`. - */ - public readonly adapter: BotFrameworkAdapter; - - /** - * The bound `ConversationReference`. - */ - public readonly conversationReference: Partial; - - /** - * Notification target type. - * - * @remarks - * - "Channel" means bot is installed into a team and notification will be sent to its "General" channel. - * - "Group" means bot is installed into a group chat. - * - "Person" means bot is installed into a personal scope and notification will be sent to personal chat. - */ - public readonly type?: NotificationTargetType; - - /** - * Constructor - * - * @remarks - * It's recommended to get bot installations from {@link ConversationBot.installations()}, instead of using this constructor. - * - * @param adapter - the bound `BotFrameworkAdapter`. - * @param conversationReference - the bound `ConversationReference`. - */ - constructor(adapter: BotFrameworkAdapter, conversationReference: Partial) { - this.adapter = adapter; - this.conversationReference = conversationReference; - this.type = utils.getTargetType(conversationReference); - } - - /** - * Send a plain text message. - * - * @param text - the plain text message. - * @param onError - an optional error handler that can catch exceptions during message sending. - * If not defined, error will be handled by `BotAdapter.onTurnError`. - * @returns the response of sending message. - */ - public async sendMessage( - text: string, - onError?: (context: TurnContext, error: Error) => Promise - ): Promise { - const response: MessageResponse = {}; - await this.adapter.continueConversation(this.conversationReference, async (context) => { - try { - const res = await context.sendActivity(text); - response.id = res?.id; - } catch (error) { - if (onError) { - await onError(context, error as Error); - } else { - throw error; - } - } - }); - return response; - } - - /** - * Send an adaptive card message. - * - * @param card - the adaptive card raw JSON. - * @param onError - an optional error handler that can catch exceptions during adaptive card sending. - * If not defined, error will be handled by `BotAdapter.onTurnError`. - * @returns the response of sending adaptive card message. - */ - public async sendAdaptiveCard( - card: unknown, - onError?: (context: TurnContext, error: Error) => Promise - ): Promise { - const response: MessageResponse = {}; - await this.adapter.continueConversation(this.conversationReference, async (context) => { - try { - const res = await context.sendActivity({ - attachments: [CardFactory.adaptiveCard(card)], - }); - response.id = res?.id; - } catch (error) { - if (onError) { - await onError(context, error as Error); - } else { - throw error; - } - } - }); - return response; - } - - /** - * Get channels from this bot installation. - * - * @returns an array of channels if bot is installed into a team, otherwise returns an empty array. - */ - public async channels(): Promise { - const channels: Channel[] = []; - if (this.type !== NotificationTargetType.Channel) { - return channels; - } - - let teamsChannels: ChannelInfo[] = []; - await this.adapter.continueConversation(this.conversationReference, async (context) => { - const teamId = utils.getTeamsBotInstallationId(context); - if (teamId !== undefined) { - teamsChannels = await TeamsInfo.getTeamChannels(context, teamId); - } - }); - - for (const channel of teamsChannels) { - channels.push(new Channel(this, channel)); - } - - return channels; - } - - /** - * Get members from this bot installation. - * - * @returns an array of members from where the bot is installed. - */ - public async members(): Promise { - const members: Member[] = []; - await this.adapter.continueConversation(this.conversationReference, async (context) => { - let continuationToken: string | undefined; - do { - const pagedMembers = await TeamsInfo.getPagedMembers(context, undefined, continuationToken); - continuationToken = pagedMembers.continuationToken; - for (const member of pagedMembers.members) { - members.push(new Member(this, member)); - } - } while (continuationToken !== undefined); - }); - - return members; - } - - /** - * Get team details from this bot installation - * - * @returns the team details if bot is installed into a team, otherwise returns undefined. - */ - public async getTeamDetails(): Promise { - if (this.type !== NotificationTargetType.Channel) { - return undefined; - } - - let teamDetails: TeamDetails | undefined; - await this.adapter.continueConversation(this.conversationReference, async (context) => { - const teamId = utils.getTeamsBotInstallationId(context); - if (teamId !== undefined) { - teamDetails = await TeamsInfo.getTeamDetails(context, teamId); - } - }); - - return teamDetails; - } -} - -/** - * Provide utilities to send notification to varies targets (e.g., member, group, channel). - */ - -/** - * @deprecated Use `BotBuilderCloudAdapter.NotificationBot` instead. - */ -export class NotificationBot { - private readonly conversationReferenceStore: DefaultConversationReferenceStore; - private readonly adapter: BotFrameworkAdapter; - - /** - * constructor of the notification bot. - * - * @remarks - * To ensure accuracy, it's recommended to initialize before handling any message. - * - * @param adapter - the bound `BotFrameworkAdapter` - * @param options - initialize options - */ - public constructor(adapter: BotFrameworkAdapter, options?: NotificationOptions) { - const storage = - options?.storage ?? - new LocalFileStorage( - path.resolve(process.env.RUNNING_ON_AZURE === "1" ? process.env.TEMP ?? "./" : "./") - ); - - this.conversationReferenceStore = new DefaultConversationReferenceStore(storage); - this.adapter = adapter.use( - new NotificationMiddleware({ - conversationReferenceStore: this.conversationReferenceStore, - }) - ); - } - - /** - * Get all targets where the bot is installed. - * - * @remarks - * The result is retrieving from the persisted storage. - * - * @returns - an array of {@link TeamsBotInstallation}. - */ - public async installations(): Promise { - if (this.conversationReferenceStore === undefined || this.adapter === undefined) { - throw new Error("NotificationBot has not been initialized."); - } - - const { data: references } = await this.conversationReferenceStore.list(); - const targets: TeamsBotInstallation[] = []; - for (const reference of references) { - // validate connection - let valid = true; - await this.adapter.continueConversation(reference, async (context) => { - try { - // try get member to see if the installation is still valid - await TeamsInfo.getPagedMembers(context, 1); - } catch (error: any) { - if ((error.code as string) === "BotNotInConversationRoster") { - valid = false; - } - } - }); - - if (valid) { - targets.push(new TeamsBotInstallation(this.adapter, reference)); - } else { - await this.conversationReferenceStore.remove(utils.getKey(reference), reference); - } - } - - return targets; - } - - /** - * Returns the first {@link Member} where predicate is true, and undefined otherwise. - * - * @param predicate find calls predicate once for each member of the installation, - * until it finds one where predicate returns true. If such a member is found, find - * immediately returns that member. Otherwise, find returns undefined. - * @param scope the scope to find members from the installations - * (personal chat, group chat, Teams channel). - * @returns the first {@link Member} where predicate is true, and undefined otherwise. - */ - public async findMember( - predicate: (member: Member) => Promise, - scope?: SearchScope - ): Promise { - for (const target of await this.installations()) { - if (this.matchSearchScope(target, scope)) { - for (const member of await target.members()) { - if (await predicate(member)) { - return member; - } - } - } - } - - return; - } - - /** - * Returns the first {@link Channel} where predicate is true, and undefined otherwise. - * (Ensure the bot app is installed into the `General` channel, otherwise undefined will be returned.) - * - * @param predicate find calls predicate once for each channel of the installation, - * until it finds one where predicate returns true. If such a channel is found, find - * immediately returns that channel. Otherwise, find returns undefined. - * @returns the first {@link Channel} where predicate is true, and undefined otherwise. - */ - public async findChannel( - predicate: (channel: Channel, teamDetails: TeamDetails | undefined) => Promise - ): Promise { - for (const target of await this.installations()) { - if (target.type === NotificationTargetType.Channel) { - const teamDetails = await target.getTeamDetails(); - for (const channel of await target.channels()) { - if (await predicate(channel, teamDetails)) { - return channel; - } - } - } - } - - return; - } - - /** - * Returns all {@link Member} where predicate is true, and empty array otherwise. - * - * @param predicate find calls predicate for each member of the installation. - * @param scope the scope to find members from the installations - * (personal chat, group chat, Teams channel). - * @returns an array of {@link Member} where predicate is true, and empty array otherwise. - */ - public async findAllMembers( - predicate: (member: Member) => Promise, - scope?: SearchScope - ): Promise { - const members: Member[] = []; - for (const target of await this.installations()) { - if (this.matchSearchScope(target, scope)) { - for (const member of await target.members()) { - if (await predicate(member)) { - members.push(member); - } - } - } - } - - return members; - } - - /** - * Returns all {@link Channel} where predicate is true, and empty array otherwise. - * (Ensure the bot app is installed into the `General` channel, otherwise empty array will be returned.) - * - * @param predicate find calls predicate for each channel of the installation. - * @returns an array of {@link Channel} where predicate is true, and empty array otherwise. - */ - public async findAllChannels( - predicate: (channel: Channel, teamDetails: TeamDetails | undefined) => Promise - ): Promise { - const channels: Channel[] = []; - for (const target of await this.installations()) { - if (target.type === NotificationTargetType.Channel) { - const teamDetails = await target.getTeamDetails(); - for (const channel of await target.channels()) { - if (await predicate(channel, teamDetails)) { - channels.push(channel); - } - } - } - } - - return channels; - } - - private matchSearchScope(target: NotificationTarget, scope?: SearchScope): boolean { - scope = scope ?? SearchScope.All; - - return ( - (target.type === NotificationTargetType.Channel && (scope & SearchScope.Channel) !== 0) || - (target.type === NotificationTargetType.Group && (scope & SearchScope.Group) !== 0) || - (target.type === NotificationTargetType.Person && (scope & SearchScope.Person) !== 0) - ); - } -} - -/** - * The search scope when calling {@link NotificationBot.findMember} and {@link NotificationBot.findAllMembers}. - * The search scope is a flagged enum and it can be combined with `|`. - * For example, to search from personal chat and group chat, use `SearchScope.Person | SearchScope.Group`. - */ -export enum SearchScope { - /** - * Search members from the installations in personal chat only. - */ - Person = 1, - - /** - * Search members from the installations in group chat only. - */ - Group = 2, - - /** - * Search members from the installations in Teams channel only. - */ - Channel = 4, - - /** - * Search members from all installations including personal chat, group chat and Teams channel. - */ - All = Person | Group | Channel, -} diff --git a/packages/sdk/src/conversation/sso/botSsoExecutionDialog.browser.ts b/packages/sdk/src/conversation/sso/botSsoExecutionDialog.browser.ts index 8b1353c667..e500e53628 100644 --- a/packages/sdk/src/conversation/sso/botSsoExecutionDialog.browser.ts +++ b/packages/sdk/src/conversation/sso/botSsoExecutionDialog.browser.ts @@ -3,11 +3,10 @@ import { formatString } from "../../util/utils"; import { ErrorWithCode, ErrorCode, ErrorMessage } from "../../core/errors"; -import { TeamsFx } from "../../core/teamsfx.browser"; import { BotSsoExecutionDialogHandler, TriggerPatterns } from "../interface"; import { StatePropertyAccessor, TurnContext, Storage } from "botbuilder"; import { OnBehalfOfCredentialAuthConfig } from "../../models/configuration"; -import { TeamsBotSsoPromptSettings } from "../../index.browser"; +import { TeamsBotSsoPromptSettings } from "../../bot/teamsBotSsoPrompt.browser"; /* * Sso execution dialog, use to handle sso command */ @@ -18,12 +17,6 @@ export class BotSsoExecutionDialog { * @remarks * Can Only works in in server side. */ - constructor( - dedupStorage: Storage, - ssoPromptSettings: TeamsBotSsoPromptSettings, - teamsfx: TeamsFx, - dialogName?: string - ); constructor( dedupStorage: Storage, ssoPromptSettings: TeamsBotSsoPromptSettings, @@ -34,7 +27,7 @@ export class BotSsoExecutionDialog { constructor( dedupStorage: Storage, ssoPromptSettings: TeamsBotSsoPromptSettings, - authConfig: TeamsFx | OnBehalfOfCredentialAuthConfig, + authConfig: OnBehalfOfCredentialAuthConfig, ...args: any ) { throw new ErrorWithCode( @@ -43,6 +36,7 @@ export class BotSsoExecutionDialog { ); } + // eslint-disable-next-line no-secrets/no-secrets /** * Add TeamsFxBotSsoCommandHandler instance * @param handler {@link BotSsoExecutionDialogHandler} callback function @@ -61,7 +55,7 @@ export class BotSsoExecutionDialog { * @param context The context object for the current turn. * @param accessor The instance of StatePropertyAccessor for dialog system. */ - public async run(context: TurnContext, accessor: StatePropertyAccessor) { + public run(context: TurnContext, accessor: StatePropertyAccessor) { throw new ErrorWithCode( formatString(ErrorMessage.BrowserRuntimeNotSupported, "BotSsoExecutionDialog"), ErrorCode.RuntimeNotSupported @@ -73,7 +67,7 @@ export class BotSsoExecutionDialog { * * @param context Context for the current turn of conversation. */ - protected async onEndDialog(context: TurnContext) { + protected onEndDialog(context: TurnContext) { throw new ErrorWithCode( formatString(ErrorMessage.BrowserRuntimeNotSupported, "BotSsoExecutionDialog"), ErrorCode.RuntimeNotSupported diff --git a/packages/sdk/src/conversation/sso/botSsoExecutionDialog.ts b/packages/sdk/src/conversation/sso/botSsoExecutionDialog.ts index b1c1012102..52ca799646 100644 --- a/packages/sdk/src/conversation/sso/botSsoExecutionDialog.ts +++ b/packages/sdk/src/conversation/sso/botSsoExecutionDialog.ts @@ -21,7 +21,6 @@ import { import { CommandMessage, BotSsoExecutionDialogHandler, TriggerPatterns } from "../interface"; import { TeamsBotSsoPrompt, TeamsBotSsoPromptSettings } from "../../bot/teamsBotSsoPrompt"; import { TeamsBotSsoPromptTokenResponse } from "../../bot/teamsBotSsoPromptTokenResponse"; -import { TeamsFx } from "../../core/teamsfx"; import { formatString } from "../../util/utils"; import { ErrorCode, ErrorMessage, ErrorWithCode } from "../../core/errors"; import { internalLogger } from "../../util/logger"; @@ -45,19 +44,6 @@ export class BotSsoExecutionDialog extends ComponentDialog { string | RegExp | (string | RegExp)[] >(); - /** - * Creates a new instance of the BotSsoExecutionDialog. - * @param {@link Storage} dedupStorage Helper storage to remove duplicated messages - * @param {@link TeamsBotSsoPromptSettings} settings The list of scopes for which the token will have access - * @param {@link TeamsFx} teamsfx instance for authentication - * @param {string} dialogName custom dialog name - */ - constructor( - dedupStorage: Storage, - ssoPromptSettings: TeamsBotSsoPromptSettings, - teamsfx: TeamsFx, - dialogName?: string - ); /** * Creates a new instance of the BotSsoExecutionDialog. * @param {@link Storage} dedupStorage Helper storage to remove duplicated messages @@ -72,15 +58,8 @@ export class BotSsoExecutionDialog extends ComponentDialog { authConfig: OnBehalfOfCredentialAuthConfig, initiateLoginEndpoint: string, dialogName?: string - ); - constructor( - dedupStorage: Storage, - ssoPromptSettings: TeamsBotSsoPromptSettings, - authConfig: TeamsFx | OnBehalfOfCredentialAuthConfig, - ...args: any ) { - super(((authConfig as TeamsFx).getCredential ? args[0] : args[1]) ?? DIALOG_NAME); - const dialogName: string = (authConfig as TeamsFx).getCredential ? args[0] : args[1]; + super(dialogName ?? DIALOG_NAME); if (dialogName) { DIALOG_NAME = dialogName; @@ -88,26 +67,14 @@ export class BotSsoExecutionDialog extends ComponentDialog { COMMAND_ROUTE_DIALOG = dialogName + COMMAND_ROUTE_DIALOG; } - let ssoDialog: TeamsBotSsoPrompt; - if ((authConfig as TeamsFx).getCredential) { - ssoDialog = new TeamsBotSsoPrompt( - authConfig as TeamsFx, - TEAMS_SSO_PROMPT_ID, - ssoPromptSettings - ); - } else { - ssoDialog = new TeamsBotSsoPrompt( - authConfig as OnBehalfOfCredentialAuthConfig, - args[0], - TEAMS_SSO_PROMPT_ID, - ssoPromptSettings - ); - } - + const ssoDialog = new TeamsBotSsoPrompt( + authConfig, + initiateLoginEndpoint, + TEAMS_SSO_PROMPT_ID, + ssoPromptSettings + ); this.addDialog(ssoDialog); - this.initialDialogId = COMMAND_ROUTE_DIALOG; - this.dedupStorage = dedupStorage; this.dedupStorageKeys = []; diff --git a/packages/sdk/src/conversation/sso/defaultBotSsoExecutionActivityHandler.browser.ts b/packages/sdk/src/conversation/sso/defaultBotSsoExecutionActivityHandler.browser.ts index e0e162faf7..b5be09225d 100644 --- a/packages/sdk/src/conversation/sso/defaultBotSsoExecutionActivityHandler.browser.ts +++ b/packages/sdk/src/conversation/sso/defaultBotSsoExecutionActivityHandler.browser.ts @@ -12,6 +12,7 @@ import { formatString } from "../../util/utils"; * Default sso execution activity handler */ export class DefaultBotSsoExecutionActivityHandler { + // eslint-disable-next-line no-secrets/no-secrets /** * Creates a new instance of the DefaultBotSsoExecutionActivityHandler. * @param ssoConfig configuration for sso command bot @@ -26,6 +27,7 @@ export class DefaultBotSsoExecutionActivityHandler { ); } + // eslint-disable-next-line no-secrets/no-secrets /** * Add TeamsFxBotSsoCommandHandler instance to sso execution dialog * @param handler {@link BotSsoExecutionDialogHandler} callback function diff --git a/packages/sdk/src/conversation/sso/defaultBotSsoExecutionActivityHandler.ts b/packages/sdk/src/conversation/sso/defaultBotSsoExecutionActivityHandler.ts index c97b4af153..771d212af0 100644 --- a/packages/sdk/src/conversation/sso/defaultBotSsoExecutionActivityHandler.ts +++ b/packages/sdk/src/conversation/sso/defaultBotSsoExecutionActivityHandler.ts @@ -12,8 +12,6 @@ import { UserState, } from "botbuilder"; import { TeamsBotSsoPromptSettings } from "../../bot/teamsBotSsoPrompt"; -import { TeamsFx } from "../../core/teamsfx"; -import { IdentityType } from "../../models/identityType"; import { BotSsoConfig, BotSsoExecutionActivityHandler, @@ -62,7 +60,7 @@ export class DefaultBotSsoExecutionActivityHandler dedupStorage, settings, customConfig as OnBehalfOfCredentialAuthConfig, - customConfig.initiateLoginEndpoint! + customConfig.initiateLoginEndpoint ); this.conversationState = conversationState; diff --git a/packages/sdk/src/conversation/storage.ts b/packages/sdk/src/conversation/storage.ts index 62bb5b70f9..3dcfb865a2 100644 --- a/packages/sdk/src/conversation/storage.ts +++ b/packages/sdk/src/conversation/storage.ts @@ -5,7 +5,6 @@ import { ConversationReference } from "botbuilder"; import * as fs from "fs"; import * as path from "path"; import { - NotificationTargetStorage, ConversationReferenceStore, ConversationReferenceStoreAddOptions, PagedData, @@ -14,7 +13,7 @@ import { /** * @internal */ -export class LocalFileStorage implements NotificationTargetStorage { +export class DefaultConversationReferenceStore implements ConversationReferenceStore { private readonly localFileName = process.env.TEAMSFX_NOTIFICATION_STORE_FILENAME ?? ".notification.localstore.json"; private readonly filePath: string; @@ -23,37 +22,29 @@ export class LocalFileStorage implements NotificationTargetStorage { this.filePath = path.resolve(fileDir, this.localFileName); } - async read(key: string): Promise<{ [key: string]: unknown } | undefined> { - if (!(await this.storeFileExists())) { - return undefined; - } - - const data = await this.readFromFile(); - - return data[key]; - } - - async list(): Promise<{ [key: string]: unknown }[]> { - if (!(await this.storeFileExists())) { - return []; + public async add( + key: string, + reference: Partial, + options: ConversationReferenceStoreAddOptions + ): Promise { + if (options.overwrite || !(await this.storeFileExists())) { + if (!(await this.storeFileExists())) { + await this.writeToFile({ [key]: reference }); + } else { + const data = await this.readFromFile(); + await this.writeToFile(Object.assign(data, { [key]: reference })); + } + return true; } - const data = await this.readFromFile(); - - return Object.entries(data).map((entry) => entry[1] as { [key: string]: unknown }); + return false; } - async write(key: string, object: { [key: string]: unknown }): Promise { + public async remove(key: string, reference: Partial): Promise { if (!(await this.storeFileExists())) { - await this.writeToFile({ [key]: object }); - return; + return false; } - const data = await this.readFromFile(); - await this.writeToFile(Object.assign(data, { [key]: object })); - } - - async delete(key: string): Promise { if (await this.storeFileExists()) { const data = await this.readFromFile(); if (data[key] !== undefined) { @@ -61,6 +52,28 @@ export class LocalFileStorage implements NotificationTargetStorage { await this.writeToFile(data); } } + return true; + } + + public async list( + pageSize?: number, + continuationToken?: string + ): Promise>> { + if (!(await this.storeFileExists())) { + return { + data: [], + continuationToken: "", + }; + } + + const fileData = await this.readFromFile(); + const data: { [key: string]: unknown }[] = Object.entries(fileData).map( + (entry) => entry[1] as { [key: string]: unknown } + ); + return { + data, + continuationToken: "", + }; } private storeFileExists(): Promise { @@ -112,54 +125,3 @@ export class LocalFileStorage implements NotificationTargetStorage { }); } } - -/** - * @internal - */ -export class DefaultConversationReferenceStore implements ConversationReferenceStore { - private readonly storage: NotificationTargetStorage; - - constructor(storage: NotificationTargetStorage) { - this.storage = storage; - } - - async add( - key: string, - reference: Partial, - options: ConversationReferenceStoreAddOptions - ): Promise { - if (options.overwrite) { - await this.storage.write(key, reference); - return true; - } - - const ref = await this.storage.read(key); - if (ref === undefined) { - await this.storage.write(key, reference); - return true; - } - - return false; - } - - async remove(key: string, reference: Partial): Promise { - const ref = await this.storage.read(key); - if (ref === undefined) { - return false; - } - - await this.storage.delete(key); - return true; - } - - async list( - pageSize?: number, - continuationToken?: string - ): Promise>> { - const data = await this.storage.list(); - return { - data, - continuationToken: "", - }; - } -} diff --git a/packages/sdk/src/conversationWithCloudAdapter/interface.ts b/packages/sdk/src/conversationWithCloudAdapter/interface.ts index 0b6f5e2563..2449f3f280 100644 --- a/packages/sdk/src/conversationWithCloudAdapter/interface.ts +++ b/packages/sdk/src/conversationWithCloudAdapter/interface.ts @@ -3,7 +3,6 @@ import { CloudAdapter } from "botbuilder"; import { - NotificationTargetStorage, BotSsoConfig, CommandOptions, CardActionOptions, @@ -33,20 +32,6 @@ export interface NotificationOptions { * It's recommended to use your own store for production environment. */ store?: ConversationReferenceStore; - /** - * An optional storage to persist bot notification target references. - * - * @remarks - * If `storage` is not provided, a default local file storage will be used, - * which stores notification target references into: - * - `.notification.localstore.json` if running locally - * - `${process.env.TEMP}/.notification.localstore.json` if `process.env.RUNNING_ON_AZURE` is set to "1" - * - * It's recommended to use your own shared storage for production environment. - * - * @deprecated Use `store` to customize the way to persist bot notification target references instead. - */ - storage?: NotificationTargetStorage; } /** diff --git a/packages/sdk/src/conversationWithCloudAdapter/notification.ts b/packages/sdk/src/conversationWithCloudAdapter/notification.ts index 3e37065b56..213a8fe700 100644 --- a/packages/sdk/src/conversationWithCloudAdapter/notification.ts +++ b/packages/sdk/src/conversationWithCloudAdapter/notification.ts @@ -23,7 +23,7 @@ import { } from "../conversation/interface"; import { NotificationOptions } from "./interface"; import { NotificationMiddleware } from "../conversation/middlewares/notificationMiddleware"; -import { DefaultConversationReferenceStore, LocalFileStorage } from "../conversation/storage"; +import { DefaultConversationReferenceStore } from "../conversation/storage"; import * as utils from "../conversation/utils"; /** @@ -518,26 +518,6 @@ export class TeamsBotInstallation implements NotificationTarget { return result; } - /** - * Get members from this bot installation. - * - * @returns An array of members from where the bot is installed. - * - * @deprecated Use `getPagedMembers` instead. - */ - public async members(): Promise { - const members: Member[] = []; - - let continuationToken: string | undefined; - do { - const pagedData = await this.getPagedMembers(undefined, continuationToken); - continuationToken = pagedData.continuationToken; - members.push(...pagedData.data); - } while (continuationToken); - - return members; - } - /** * Get team details from this bot installation * @@ -585,13 +565,9 @@ export class NotificationBot { if (options?.store) { this.conversationReferenceStore = options.store; } else { - const storage = - options?.storage ?? - new LocalFileStorage( - path.resolve(process.env.RUNNING_ON_AZURE === "1" ? process.env.TEMP ?? "./" : "./") - ); - - this.conversationReferenceStore = new DefaultConversationReferenceStore(storage); + this.conversationReferenceStore = new DefaultConversationReferenceStore( + path.resolve(process.env.RUNNING_ON_AZURE === "1" ? process.env.TEMP ?? "./" : "./") + ); } this.adapter = adapter.use( @@ -688,28 +664,6 @@ export class NotificationBot { }; } - /** - * Get all targets where the bot is installed. - * - * @remarks - * The result is retrieving from the persisted storage. - * - * @returns An array of {@link TeamsBotInstallation}. - * - * @deprecated Use getPagedInstallations instead. - */ - public async installations(): Promise { - let continuationToken: string | undefined; - const targets: TeamsBotInstallation[] = []; - do { - const result = await this.getPagedInstallations(undefined, continuationToken); - continuationToken = result.continuationToken; - targets.push(...result.data); - } while (continuationToken); - - return targets; - } - /** * Return the first {@link Member} where predicate is true, and undefined otherwise. * @@ -727,7 +681,15 @@ export class NotificationBot { ): Promise { for (const target of await this.installations()) { if (this.matchSearchScope(target, scope)) { - for (const member of await target.members()) { + const members: Member[] = []; + let continuationToken: string | undefined; + do { + const pagedData = await target.getPagedMembers(undefined, continuationToken); + continuationToken = pagedData.continuationToken; + members.push(...pagedData.data); + } while (continuationToken); + + for (const member of members) { if (await predicate(member)) { return member; } @@ -781,7 +743,15 @@ export class NotificationBot { const members: Member[] = []; for (const target of await this.installations()) { if (this.matchSearchScope(target, scope)) { - for (const member of await target.members()) { + const targetMembers: Member[] = []; + let continuationToken: string | undefined; + do { + const pagedData = await target.getPagedMembers(undefined, continuationToken); + continuationToken = pagedData.continuationToken; + targetMembers.push(...pagedData.data); + } while (continuationToken); + + for (const member of targetMembers) { if (await predicate(member)) { members.push(member); } @@ -827,6 +797,27 @@ export class NotificationBot { (target.type === NotificationTargetType.Person && (scope & SearchScope.Person) !== 0) ); } + + /** + * @internal + * Get all targets where the bot is installed. + * + * @remarks + * The result is retrieving from the persisted storage. + * + * @returns An array of {@link TeamsBotInstallation} + */ + private async installations(): Promise { + let continuationToken: string | undefined; + const targets: TeamsBotInstallation[] = []; + do { + const result = await this.getPagedInstallations(undefined, continuationToken); + continuationToken = result.continuationToken; + targets.push(...result.data); + } while (continuationToken); + + return targets; + } } /** diff --git a/packages/sdk/src/core/defaultTediousConnectionConfiguration.browser.ts b/packages/sdk/src/core/defaultTediousConnectionConfiguration.browser.ts deleted file mode 100644 index a13ebb2390..0000000000 --- a/packages/sdk/src/core/defaultTediousConnectionConfiguration.browser.ts +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. - -import { ConnectionConfig } from "tedious"; -import { ErrorWithCode, ErrorCode, ErrorMessage } from "../core/errors"; -import { TeamsFx } from "../core/teamsfx"; -import { formatString } from "../util/utils"; - -/** - * Generate connection configuration consumed by tedious. - * - * @deprecated we recommend you compose your own Tedious configuration for better flexibility. - * - * @remarks - * Only works in in server side. - */ -export function getTediousConnectionConfig( - teamsfx: TeamsFx, - databaseName?: string -): Promise { - return Promise.reject( - new ErrorWithCode( - formatString( - ErrorMessage.BrowserRuntimeNotSupported, - "DefaultTediousConnectionConfiguration" - ), - ErrorCode.RuntimeNotSupported - ) - ); -} diff --git a/packages/sdk/src/core/defaultTediousConnectionConfiguration.ts b/packages/sdk/src/core/defaultTediousConnectionConfiguration.ts deleted file mode 100644 index ecd139f685..0000000000 --- a/packages/sdk/src/core/defaultTediousConnectionConfiguration.ts +++ /dev/null @@ -1,205 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. - -import { AccessToken, ManagedIdentityCredential } from "@azure/identity"; -import { ConnectionConfig } from "tedious"; -import { ErrorWithCode, ErrorCode } from "../core/errors"; -import { internalLogger } from "../util/logger"; -import { TeamsFx } from "../core/teamsfx"; - -/** - * MSSQL default scope - * https://docs.microsoft.com/en-us/azure/app-service/app-service-web-tutorial-connect-msi - */ -const defaultSQLScope = "https://database.windows.net/"; - -/** - * Generate connection configuration consumed by tedious. - * - * @deprecated we recommend you compose your own Tedious configuration for better flexibility. - * - * @param {TeamsFx} teamsfx - Used to provide configuration and auth - * @param { string? } databaseName - specify database name to override default one if there are multiple databases. - * - * @returns Connection configuration of tedious for the SQL. - * - * @throws {@link ErrorCode|InvalidConfiguration} when SQL config resource configuration is invalid. - * @throws {@link ErrorCode|InternalError} when get user MSI token failed or MSI token is invalid. - * @throws {@link ErrorCode|RuntimeNotSupported} when runtime is browser. - */ -export async function getTediousConnectionConfig( - teamsfx: TeamsFx, - databaseName?: string -): Promise { - internalLogger.info("Get SQL configuration"); - - try { - isSQLConfigurationValid(teamsfx); - } catch (err) { - throw err; - } - - if (databaseName === "") { - internalLogger.warn(`SQL database name is empty string`); - } - const dbName: string | undefined = - databaseName ?? - (teamsfx.hasConfig("sqlDatabaseName") ? teamsfx.getConfig("sqlDatabaseName") : undefined); - if (!isMsiAuthentication(teamsfx)) { - const configWithUPS = generateDefaultConfig(teamsfx, dbName); - internalLogger.verbose("SQL configuration with username and password generated"); - return configWithUPS; - } - - try { - const configWithToken = await generateTokenConfig(teamsfx, dbName); - internalLogger.verbose("SQL configuration with MSI token generated"); - return configWithToken; - } catch (error) { - throw error; - } -} - -/** - * check configuration is an available configurations. - * @param {TeamsFx} teamsfx - Used to provide configuration and auth - * - * @returns true - SQL configuration has a valid SQL endpoints, SQL username with password or identity ID. - * false - configuration is not valid. - * @internal - */ -function isSQLConfigurationValid(teamsfx: TeamsFx) { - internalLogger.verbose("Check SQL configuration if valid"); - if (!teamsfx.hasConfig("sqlServerEndpoint")) { - internalLogger.error("SQL configuration is not valid without SQL server endpoint exist"); - throw new ErrorWithCode( - "SQL configuration error without SQL server endpoint exist", - ErrorCode.InvalidConfiguration - ); - } - if ( - !(teamsfx.hasConfig("sqlUsername") && teamsfx.hasConfig("sqlPassword")) && - !teamsfx.hasConfig("sqlIdentityId") - ) { - const errMsg = `SQL configuration is not valid without ${ - teamsfx.hasConfig("sqlIdentityId") ? "" : "identity id " - } ${teamsfx.hasConfig("sqlUsername") ? "" : "SQL username "} ${ - teamsfx.hasConfig("sqlPassword") ? "" : "SQL password" - } exist`; - internalLogger.error(errMsg); - throw new ErrorWithCode(errMsg, ErrorCode.InvalidConfiguration); - } - internalLogger.verbose("SQL configuration is valid"); -} - -/** - * Check SQL use MSI identity or username and password. - * - * @param {TeamsFx} teamsfx - Used to provide configuration and auth - * - * @returns false - login with SQL MSI identity, true - login with username and password. - * @internal - */ -function isMsiAuthentication(teamsfx: TeamsFx): boolean { - internalLogger.verbose("Check connection config using MSI access token or username and password"); - if (teamsfx.hasConfig("sqlUsername") && teamsfx.hasConfig("sqlPassword")) { - internalLogger.verbose("Login with username and password"); - return false; - } - internalLogger.verbose("Login with MSI identity"); - return true; -} - -/** - * Generate tedious connection configuration with default authentication type. - * - * @param {TeamsFx} teamsfx - Used to provide configuration and auth - * @param { string? } databaseName - specify database name to override default one if there are multiple databases. - * - * @returns Tedious connection configuration with username and password. - * @internal - */ -function generateDefaultConfig(teamsfx: TeamsFx, databaseName?: string): ConnectionConfig { - internalLogger.verbose( - `SQL server ${teamsfx.getConfig("sqlServerEndpoint")} - , user name ${teamsfx.getConfig("sqlUsername")} - , database name ${databaseName ? databaseName : ""}` - ); - - const config = { - server: teamsfx.getConfig("sqlServerEndpoint"), - authentication: { - type: TediousAuthenticationType.default, - options: { - userName: teamsfx.getConfig("sqlUsername"), - password: teamsfx.getConfig("sqlPassword"), - }, - }, - options: { - database: databaseName, - encrypt: true, - }, - }; - return config; -} - -/** - * Generate tedious connection configuration with azure-active-directory-access-token authentication type. - * - * @param {TeamsFx} teamsfx - Used to provide configuration and auth - * - * @returns Tedious connection configuration with access token. - * @internal - */ -async function generateTokenConfig( - teamsfx: TeamsFx, - databaseName?: string -): Promise { - internalLogger.verbose("Generate tedious config with MSI token"); - let token: AccessToken | null; - try { - const credential = new ManagedIdentityCredential(teamsfx.getConfig("sqlIdentityId")); - token = await credential.getToken(defaultSQLScope); - } catch (error) { - const errMsg = "Get user MSI token failed"; - internalLogger.error(errMsg); - throw new ErrorWithCode(errMsg, ErrorCode.InternalError); - } - if (token) { - const config = { - server: teamsfx.getConfig("sqlServerEndpoint"), - authentication: { - type: TediousAuthenticationType.MSI, - options: { - token: token.token, - }, - }, - options: { - database: databaseName, - encrypt: true, - }, - }; - internalLogger.verbose( - `Generate token configuration success - , server endpoint is ${teamsfx.getConfig("sqlServerEndpoint")} - , database name is ${databaseName ? databaseName : ""}` - ); - return config; - } - internalLogger.error( - `Generate token configuration - , server endpoint is ${teamsfx.getConfig("sqlServerEndpoint")} - , MSI token is not valid` - ); - throw new ErrorWithCode("MSI token is not valid", ErrorCode.InternalError); -} - -/** - * tedious connection config authentication type. - * https://tediousjs.github.io/tedious/api-connection.html - * @internal - */ -enum TediousAuthenticationType { - default = "default", - MSI = "azure-active-directory-access-token", -} diff --git a/packages/sdk/src/core/errors.ts b/packages/sdk/src/core/errors.ts index 727b4a1843..839fba8bc1 100644 --- a/packages/sdk/src/core/errors.ts +++ b/packages/sdk/src/core/errors.ts @@ -95,11 +95,6 @@ export enum ErrorCode { */ InvalidResponse = "InvalidResponse", - /** - * Identity type error. - */ - IdentityTypeNotSupported = "IdentityTypeNotSupported", - /** * Authentication info already exists error. */ @@ -147,9 +142,6 @@ export class ErrorMessage { static readonly SsoActivityHandlerIsNull = "Sso command can only be used or added when sso activity handler is not undefined"; - // IdentityTypeNotSupported Error - static readonly IdentityTypeNotSupported = "{0} identity is not supported in {1}"; - // AuthorizationInfoError static readonly AuthorizationHeaderAlreadyExists = "Authorization header already exists!"; static readonly BasicCredentialAlreadyExists = "Basic credential already exists!"; diff --git a/packages/sdk/src/core/msGraphAuthProvider.ts b/packages/sdk/src/core/msGraphAuthProvider.ts deleted file mode 100644 index 7a7019a42d..0000000000 --- a/packages/sdk/src/core/msGraphAuthProvider.ts +++ /dev/null @@ -1,100 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. - -import { AuthenticationProvider } from "@microsoft/microsoft-graph-client"; -import { ErrorWithCode, ErrorCode } from "./errors"; -import { TeamsFxConfiguration } from "../models/teamsfxConfiguration"; -import { internalLogger } from "../util/logger"; -import { validateScopesType } from "../util/utils"; -import { AccessToken, TokenCredential } from "@azure/identity"; - -const defaultScope = "https://graph.microsoft.com/.default"; - -// eslint-disable-next-line no-secrets/no-secrets -/** - * Microsoft Graph auth provider for Teams Framework - * @deprecated Use `TokenCredentialAuthenticationProvider` from `@microsoft/microsoft-graph-client/authProviders/azureTokenCredentials` instead. - */ -export class MsGraphAuthProvider implements AuthenticationProvider { - private credentialOrTeamsFx: TokenCredential | TeamsFxConfiguration; - private scopes: string | string[]; - - /** - * Constructor of MsGraphAuthProvider. - * - * @param {TeamsFxConfiguration} teamsfx - Used to provide configuration and auth. - * @param {string | string[]} scopes - The list of scopes for which the token will have access. - * - * @throws {@link ErrorCode|InvalidParameter} when scopes is not a valid string or string array. - * - * @returns An instance of MsGraphAuthProvider. - */ - constructor(teamsfx: TeamsFxConfiguration, scopes?: string | string[]); - /** - * Constructor of MsGraphAuthProvider. - * - * @param {TokenCredential} credential - credential used to provide configuration and auth. - * @param {string | string[]} scopes - The list of scopes for which the token will have access. - * - * @throws {@link ErrorCode|InvalidParameter} when scopes is not a valid string or string array. - * - * @returns An instance of MsGraphAuthProvider. - */ - constructor(credential: TokenCredential, scopes?: string | string[]); - constructor( - credentialOrTeamsFx: TeamsFxConfiguration | TokenCredential, - scopes?: string | string[] - ) { - this.credentialOrTeamsFx = credentialOrTeamsFx; - - let scopesStr = defaultScope; - if (scopes) { - validateScopesType(scopes); - scopesStr = typeof scopes === "string" ? scopes : scopes.join(" "); - if (scopesStr === "") { - scopesStr = defaultScope; - } - } - - internalLogger.info( - `Create Microsoft Graph Authentication Provider with scopes: '${scopesStr}'` - ); - - this.scopes = scopesStr; - } - - /** - * Get access token for Microsoft Graph API requests. - * - * @throws {@link ErrorCode|InternalError} when get access token failed due to empty token or unknown other problems. - * @throws {@link ErrorCode|TokenExpiredError} when SSO token has already expired. - * @throws {@link ErrorCode|UiRequiredError} when need user consent to get access token. - * @throws {@link ErrorCode|ServiceError} when failed to get access token from simple auth or AAD server. - * @throws {@link ErrorCode|InvalidParameter} when scopes is not a valid string or string array. - * - * @returns Access token from the credential. - * - */ - public async getAccessToken(): Promise { - internalLogger.info(`Get Graph Access token with scopes: '${this.scopes.toString()}'`); - - let accessToken: AccessToken | null; - if ((this.credentialOrTeamsFx as TeamsFxConfiguration).getCredential) { - accessToken = await (this.credentialOrTeamsFx as TeamsFxConfiguration) - .getCredential() - .getToken(this.scopes); - } else { - accessToken = await (this.credentialOrTeamsFx as TokenCredential).getToken(this.scopes); - } - - return new Promise((resolve, reject) => { - if (accessToken) { - resolve(accessToken.token); - } else { - const errorMsg = "Graph access token is undefined or empty"; - internalLogger.error(errorMsg); - reject(new ErrorWithCode(errorMsg, ErrorCode.InternalError)); - } - }); - } -} diff --git a/packages/sdk/src/core/msGraphClientProvider.ts b/packages/sdk/src/core/msGraphClientProvider.ts deleted file mode 100644 index 06cc8725a0..0000000000 --- a/packages/sdk/src/core/msGraphClientProvider.ts +++ /dev/null @@ -1,149 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. - -import { Client } from "@microsoft/microsoft-graph-client"; -import { MsGraphAuthProvider } from "./msGraphAuthProvider"; -import { TeamsFxConfiguration } from "../models/teamsfxConfiguration"; -import { internalLogger } from "../util/logger"; -import { TokenCredential } from "@azure/identity"; - -/** - * Get Microsoft graph client. - * @deprecated Use `TokenCredentialAuthenticationProvider` and `Client.initWithMiddleware` instead. - * ```typescript - * const authProvider = new TokenCredentialAuthenticationProvider(credential, { scopes: scope }); - * const graph = Client.initWithMiddleware({ - * authProvider: authProvider, - * }); - * ``` - * - * @example - * Get Microsoft graph client by TokenCredential - * ```typescript - * // Sso token example (Azure Function) - * const ssoToken = "YOUR_TOKEN_STRING"; - * const options = {"AAD_APP_ID", "AAD_APP_SECRET"}; - * const credential = new OnBehalfOfAADUserCredential(ssoToken, options); - * const graphClient = await createMicrosoftGraphClient(credential); - * const profile = await graphClient.api("/me").get(); - * - * // TeamsBotSsoPrompt example (Bot Application) - * const requiredScopes = ["User.Read"]; - * const config: Configuration = { - * loginUrl: loginUrl, - * clientId: clientId, - * clientSecret: clientSecret, - * tenantId: tenantId - * }; - * const prompt = new TeamsBotSsoPrompt(dialogId, { - * config: config - * scopes: ["User.Read"], - * }); - * this.addDialog(prompt); - * - * const oboCredential = new OnBehalfOfAADUserCredential( - * getUserId(dialogContext), - * { - * clientId: "AAD_APP_ID", - * clientSecret: "AAD_APP_SECRET" - * }); - * try { - * const graphClient = await createMicrosoftGraphClient(credential); - * const profile = await graphClient.api("/me").get(); - * } catch (e) { - * dialogContext.beginDialog(dialogId); - * return Dialog.endOfTurn(); - * } - * ``` - * - * @param {TeamsFx} teamsfx - Used to provide configuration and auth. - * @param scopes - The array of Microsoft Token scope of access. Default value is `[.default]`. - * - * @throws {@link ErrorCode|InvalidParameter} when scopes is not a valid string or string array. - * - * @returns Graph client with specified scopes. - */ -export function createMicrosoftGraphClient( - teamsfx: TeamsFxConfiguration, - scopes?: string | string[] -): Client { - internalLogger.info("Create Microsoft Graph Client"); - const authProvider = new MsGraphAuthProvider(teamsfx, scopes); - const graphClient = Client.initWithMiddleware({ - authProvider, - }); - - return graphClient; -} - -// eslint-disable-next-line no-secrets/no-secrets -/** - * Get Microsoft graph client. - * @deprecated Use `TokenCredentialAuthenticationProvider` and `Client.initWithMiddleware` instead. - * ```typescript - * const authProvider = new TokenCredentialAuthenticationProvider(credential, { scopes: scope }); - * const graph = Client.initWithMiddleware({ - * authProvider: authProvider, - * }); - * ``` - * - * @example - * Get Microsoft graph client by TokenCredential - * ```typescript - * // In browser: TeamsUserCredential - * const authConfig: TeamsUserCredentialAuthConfig = { - * clientId: "xxx", - initiateLoginEndpoint: "https://xxx/auth-start.html", - * }; - - * const credential = new TeamsUserCredential(authConfig); - - * const scope = "User.Read"; - * await credential.login(scope); - - * const client = createMicrosoftGraphClientWithCredential(credential, scope); - - * // In node: OnBehalfOfUserCredential - * const oboAuthConfig: OnBehalfOfCredentialAuthConfig = { - * authorityHost: "xxx", - * clientId: "xxx", - * tenantId: "xxx", - * clientSecret: "xxx", - * }; - - * const oboCredential = new OnBehalfOfUserCredential(ssoToken, oboAuthConfig); - * const scope = "User.Read"; - * const client = createMicrosoftGraphClientWithCredential(oboCredential, scope); - - * // In node: AppCredential - * const appAuthConfig: AppCredentialAuthConfig = { - * authorityHost: "xxx", - * clientId: "xxx", - * tenantId: "xxx", - * clientSecret: "xxx", - * }; - * const appCredential = new AppCredential(appAuthConfig); - * const scope = "User.Read"; - * const client = createMicrosoftGraphClientWithCredential(appCredential, scope); - * - * const profile = await client.api("/me").get(); - * ``` - * - * @param {TokenCredential} credential - Used to provide configuration and auth. - * @param scopes - The array of Microsoft Token scope of access. Default value is `[.default]`. - * - * @throws {@link ErrorCode|InvalidParameter} when scopes is not a valid string or string array. - * - * @returns Graph client with specified scopes. - */ -export function createMicrosoftGraphClientWithCredential( - credential: TokenCredential, - scopes?: string | string[] -): Client { - internalLogger.info("Create Microsoft Graph Client"); - const authProvider = new MsGraphAuthProvider(credential, scopes); - const graphClient = Client.initWithMiddleware({ - authProvider, - }); - return graphClient; -} diff --git a/packages/sdk/src/core/teamsfx.browser.ts b/packages/sdk/src/core/teamsfx.browser.ts deleted file mode 100644 index e42f221525..0000000000 --- a/packages/sdk/src/core/teamsfx.browser.ts +++ /dev/null @@ -1,132 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. - -import { TokenCredential } from "@azure/identity"; -import { TeamsUserCredential } from "../credential/teamsUserCredential.browser"; -import { IdentityType } from "../models/identityType"; -import { UserInfo } from "../models/userinfo"; -import { formatString } from "../util/utils"; -import { ErrorWithCode, ErrorCode, ErrorMessage } from "../core/errors"; -import { internalLogger } from "../util/logger"; -import { TeamsFxConfiguration } from "../models/teamsfxConfiguration"; -import { AuthenticationConfiguration } from "../models/configuration"; - -/** - * A class providing credential and configuration. - * @deprecated Please use {@link TeamsUserCredential} - * in browser environment and {@link OnBehalfOfUserCredential} or {@link AppCredential} in NodeJS. - */ -export class TeamsFx implements TeamsFxConfiguration { - private configuration: Map; - private teamsUserCredential?: TeamsUserCredential; - public identityType: IdentityType; - - constructor( - identityType?: IdentityType, - customConfig?: Record | AuthenticationConfiguration - ) { - this.identityType = identityType ?? IdentityType.User; - if (this.identityType !== IdentityType.User) { - const errorMsg = formatString( - ErrorMessage.IdentityTypeNotSupported, - this.identityType.toString(), - "TeamsFx" - ); - internalLogger.error(errorMsg); - throw new ErrorWithCode(errorMsg, ErrorCode.IdentityTypeNotSupported); - } - this.configuration = new Map(); - this.loadFromEnv(); - if (customConfig) { - const myConfig: Record = { ...customConfig }; - for (const key of Object.keys(myConfig)) { - const value = myConfig[key]; - if (value) { - this.configuration.set(key, value); - } - } - } - if (this.configuration.size === 0) { - internalLogger.warn( - "No configuration is loaded, please pass required configs to TeamsFx constructor" - ); - } - } - - private loadFromEnv(): void { - if (window && (window as any).__env__) { - // testing purpose - const env = (window as any).__env__; - this.configuration.set("authorityHost", env.REACT_APP_AUTHORITY_HOST); - this.configuration.set("tenantId", env.REACT_APP_TENANT_ID); - this.configuration.set("clientId", env.REACT_APP_CLIENT_ID); - this.configuration.set("initiateLoginEndpoint", env.REACT_APP_START_LOGIN_PAGE_URL); - this.configuration.set("applicationIdUri", env.M365_APPLICATION_ID_URI); - this.configuration.set("apiEndpoint", env.REACT_APP_FUNC_ENDPOINT); - this.configuration.set("apiName", env.REACT_APP_FUNC_NAME); - } else { - // TODO: support common environment variable name - try { - this.configuration.set("authorityHost", process.env.REACT_APP_AUTHORITY_HOST); - this.configuration.set("tenantId", process.env.REACT_APP_TENANT_ID); - this.configuration.set("clientId", process.env.REACT_APP_CLIENT_ID); - this.configuration.set("initiateLoginEndpoint", process.env.REACT_APP_START_LOGIN_PAGE_URL); - this.configuration.set("applicationIdUri", process.env.M365_APPLICATION_ID_URI); - this.configuration.set("apiEndpoint", process.env.REACT_APP_FUNC_ENDPOINT); - this.configuration.set("apiName", process.env.REACT_APP_FUNC_NAME); - } catch (_) { - internalLogger.warn( - "Cannot read process.env, please use webpack if you want to use environment variables." - ); - return; - } - } - } - - getIdentityType(): IdentityType { - return this.identityType; - } - - public getCredential(): TokenCredential { - if (!this.teamsUserCredential) { - this.teamsUserCredential = new TeamsUserCredential(Object.fromEntries(this.configuration)); - } - return this.teamsUserCredential; - } - - public async getUserInfo(resources?: string[]): Promise { - return await (this.getCredential() as TeamsUserCredential).getUserInfo(resources); - } - - public async login(scopes: string | string[], resources?: string[]): Promise { - await (this.getCredential() as TeamsUserCredential).login(scopes, resources); - } - - public setSsoToken(ssoToken: string): TeamsFx { - return this; - } - - public getConfig(key: string): string { - const value = this.configuration.get(key); - if (!value) { - throw new Error(); - } - return value; - } - - public hasConfig(key: string): boolean { - const value = this.configuration.get(key); - return !!value; - } - - public getConfigs(): Record { - const config: Record = {}; - for (const key of this.configuration.keys()) { - const value = this.configuration.get(key); - if (value) { - config[key] = value; - } - } - return config; - } -} diff --git a/packages/sdk/src/core/teamsfx.ts b/packages/sdk/src/core/teamsfx.ts deleted file mode 100644 index 2447e56da7..0000000000 --- a/packages/sdk/src/core/teamsfx.ts +++ /dev/null @@ -1,233 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. - -import { TokenCredential } from "@azure/identity"; -import { AppCredential } from "../credential/appCredential"; -import { OnBehalfOfUserCredential } from "../credential/onBehalfOfUserCredential"; -import { IdentityType } from "../models/identityType"; -import { UserInfo } from "../models/userinfo"; -import { formatString } from "../util/utils"; -import { ErrorWithCode, ErrorCode, ErrorMessage } from "../core/errors"; -import { internalLogger } from "../util/logger"; -import { TeamsFxConfiguration } from "../models/teamsfxConfiguration"; -import { AuthenticationConfiguration } from "../models/configuration"; - -// Following keys are used by SDK internally -const ReservedKey: Set = new Set([ - "authorityHost", - "tenantId", - "clientId", - "clientSecret", - "initiateLoginEndpoint", - "applicationIdUri", - "apiEndpoint", - "apiName", - "sqlServerEndpoint", - "sqlUsername", - "sqlPassword", - "sqlDatabaseName", - "sqlIdentityId", -]); - -/** - * A class providing credential and configuration. - * @deprecated Please use {@link TeamsUserCredential} - * in browser environment and {@link OnBehalfOfUserCredential} or {@link AppCredential} in NodeJS. - */ -export class TeamsFx implements TeamsFxConfiguration { - private configuration: Map; - private oboUserCredential?: OnBehalfOfUserCredential; - private appCredential?: AppCredential; - private identityType: IdentityType; - - /** - * Constructor of TeamsFx - * - * @param {IdentityType} identityType - Choose user or app identity - * @param customConfig - key/value pairs of customized configuration that overrides default ones. - * - * @throws {@link ErrorCode|IdentityTypeNotSupported} when setting app identity in browser. - */ - constructor( - identityType?: IdentityType, - customConfig?: Record | AuthenticationConfiguration - ) { - this.identityType = identityType ?? IdentityType.User; - this.configuration = new Map(); - this.loadFromEnv(); - if (customConfig) { - const myConfig: Record = { ...customConfig }; - for (const key of Object.keys(myConfig)) { - const value = myConfig[key]; - if (value) { - this.configuration.set(key, value); - } - } - } - } - - /** - * Identity type set by user. - * - * @returns identity type. - */ - getIdentityType(): IdentityType { - return this.identityType; - } - - /** - * Credential instance according to identity type choice. - * - * @remarks If user identity is chose, will return {@link TeamsUserCredential} - * in browser environment and {@link OnBehalfOfUserCredential} in NodeJS. If app - * identity is chose, will return {@link AppCredential}. - * - * @returns instance implements TokenCredential interface. - */ - public getCredential(): TokenCredential { - if (this.identityType === IdentityType.User) { - if (this.oboUserCredential) { - return this.oboUserCredential; - } - const errorMsg = "SSO token is required to user identity. Please use setSsoToken()."; - internalLogger.error(errorMsg); - throw new ErrorWithCode(errorMsg, ErrorCode.InvalidParameter); - } else { - if (!this.appCredential) { - this.appCredential = new AppCredential(Object.fromEntries(this.configuration)); - } - return this.appCredential; - } - } - - /** - * Get user information. - * @param {string[]} resources - The optional list of resources for full trust Teams apps. - * @returns UserInfo object. - */ - public async getUserInfo(resources?: string[]): Promise { - if (this.identityType !== IdentityType.User) { - const errorMsg = formatString( - ErrorMessage.IdentityTypeNotSupported, - this.identityType.toString(), - "TeamsFx" - ); - internalLogger.error(errorMsg); - throw new ErrorWithCode(errorMsg, ErrorCode.IdentityTypeNotSupported); - } - return Promise.resolve((this.getCredential() as OnBehalfOfUserCredential).getUserInfo()); - } - - /** - * Popup login page to get user's access token with specific scopes. - * - * @remarks - * Only works in Teams client APP. User will be redirected to the authorization page to login and consent. - * - * @example - * ```typescript - * await teamsfx.login(["https://graph.microsoft.com/User.Read"]); // single scope using string array - * await teamsfx.login("https://graph.microsoft.com/User.Read"); // single scopes using string - * await teamsfx.login(["https://graph.microsoft.com/User.Read", "Calendars.Read"]); // multiple scopes using string array - * await teamsfx.login("https://graph.microsoft.com/User.Read Calendars.Read"); // multiple scopes using string - * ``` - * @param scopes - The list of scopes for which the token will have access, before that, we will request user to consent. - * @param {string[]} resources - The optional list of resources for full trust Teams apps. - * - * @throws {@link ErrorCode|InternalError} when failed to login with unknown error. - * @throws {@link ErrorCode|ConsentFailed} when user canceled or failed to consent. - * @throws {@link ErrorCode|InvalidParameter} when scopes is not a valid string or string array. - * @throws {@link ErrorCode|RuntimeNotSupported} when runtime is nodeJS. - */ - public async login(scopes: string | string[], resources?: string[]): Promise { - throw new ErrorWithCode( - formatString(ErrorMessage.NodejsRuntimeNotSupported, "login"), - ErrorCode.RuntimeNotSupported - ); - } - - /** - * Set SSO token when using user identity in NodeJS. - * @param {string} ssoToken - used for on behalf of user flow. - * @returns self instance. - */ - public setSsoToken(ssoToken: string): TeamsFx { - if (this.identityType !== IdentityType.User) { - throw new Error(); - } - this.oboUserCredential = new OnBehalfOfUserCredential( - ssoToken, - Object.fromEntries(this.configuration) - ); - return this; - } - - /** - * Usually used by service plugins to retrieve specific config - * @param {string} key - configuration key. - * @returns value in configuration. - */ - public getConfig(key: string): string { - const value = this.configuration.get(key); - if (!value) { - const errorMsg = `Cannot find ${key} in configuration`; - internalLogger.error(errorMsg); - throw new ErrorWithCode(errorMsg, ErrorCode.InternalError); - } - return value; - } - - /** - * Check the value of specific key. - * @param {string} key - configuration key. - * @returns true if corresponding value is not empty string. - */ - public hasConfig(key: string): boolean { - const value = this.configuration.get(key); - return !!value; - } - - /** - * Get all configurations. - * @returns key value mappings. - */ - public getConfigs(): Record { - const config: Record = {}; - for (const key of this.configuration.keys()) { - const value = this.configuration.get(key); - if (value) { - config[key] = value; - } - } - return config; - } - - /** - * Load configuration from environment variables. - */ - private loadFromEnv(): void { - const env = process.env; - this.configuration.set("authorityHost", env.M365_AUTHORITY_HOST); - this.configuration.set("tenantId", env.M365_TENANT_ID); - this.configuration.set("clientId", env.M365_CLIENT_ID); - this.configuration.set("clientSecret", env.M365_CLIENT_SECRET); - this.configuration.set("initiateLoginEndpoint", env.INITIATE_LOGIN_ENDPOINT); - this.configuration.set("applicationIdUri", env.M365_APPLICATION_ID_URI); - this.configuration.set("apiEndpoint", env.API_ENDPOINT); - this.configuration.set("apiName", env.API_NAME); - this.configuration.set("sqlServerEndpoint", env.SQL_ENDPOINT); - this.configuration.set("sqlUsername", env.SQL_USER_NAME); - this.configuration.set("sqlPassword", env.SQL_PASSWORD); - this.configuration.set("sqlDatabaseName", env.SQL_DATABASE_NAME); - this.configuration.set("sqlIdentityId", env.IDENTITY_ID); - - Object.keys(env).forEach((key: string) => { - if (ReservedKey.has(key)) { - internalLogger.warn( - `The name of environment variable ${key} is preserved. Will not load it as configuration.` - ); - } - this.configuration.set(key, env[key]); - }); - } -} diff --git a/packages/sdk/src/credential/appCredential.browser.ts b/packages/sdk/src/credential/appCredential.browser.ts index 568f0c4199..99082da220 100644 --- a/packages/sdk/src/credential/appCredential.browser.ts +++ b/packages/sdk/src/credential/appCredential.browser.ts @@ -2,7 +2,7 @@ // Licensed under the MIT license. import { AccessToken, TokenCredential, GetTokenOptions } from "@azure/identity"; -import { AppCredentialAuthConfig, AuthenticationConfiguration } from "../models/configuration"; +import { AppCredentialAuthConfig } from "../models/configuration"; import { formatString } from "../util/utils"; import { ErrorCode, ErrorMessage, ErrorWithCode } from "../core/errors"; @@ -19,9 +19,7 @@ export class AppCredential implements TokenCredential { * @remarks * Only works in in server side. */ - constructor(authConfig: AppCredentialAuthConfig); - constructor(authConfig: AuthenticationConfiguration); - constructor(authConfig: AppCredentialAuthConfig | AuthenticationConfiguration) { + constructor(authConfig: AppCredentialAuthConfig) { throw new ErrorWithCode( formatString(ErrorMessage.BrowserRuntimeNotSupported, "AppCredential"), ErrorCode.RuntimeNotSupported diff --git a/packages/sdk/src/credential/appCredential.ts b/packages/sdk/src/credential/appCredential.ts index 69156deac4..ae6901a5b3 100644 --- a/packages/sdk/src/credential/appCredential.ts +++ b/packages/sdk/src/credential/appCredential.ts @@ -2,7 +2,7 @@ // Licensed under the MIT license. import { AccessToken, TokenCredential, GetTokenOptions } from "@azure/identity"; -import { AppCredentialAuthConfig, AuthenticationConfiguration } from "../models/configuration"; +import { AppCredentialAuthConfig } from "../models/configuration"; import { internalLogger } from "../util/logger"; import { validateScopesType, formatString, getScopesArray } from "../util/utils"; import { ErrorCode, ErrorMessage, ErrorWithCode } from "../core/errors"; @@ -35,20 +35,7 @@ export class AppCredential implements TokenCredential { * @throws {@link ErrorCode|InvalidConfiguration} when client id, client secret or tenant id is not found in config. * @throws {@link ErrorCode|RuntimeNotSupported} when runtime is nodeJS. */ - constructor(authConfig: AppCredentialAuthConfig); - /** - * Constructor of AppCredential. - * - * @remarks - * Only works in in server side. - * - * @param {AuthenticationConfiguration} authConfig - The authentication configuration. Use environment variables if not provided. - * - * @throws {@link ErrorCode|InvalidConfiguration} when client id, client secret or tenant id is not found in config. - * @throws {@link ErrorCode|RuntimeNotSupported} when runtime is nodeJS. - */ - constructor(authConfig: AuthenticationConfiguration); - constructor(authConfig: AppCredentialAuthConfig | AuthenticationConfiguration) { + constructor(authConfig: AppCredentialAuthConfig) { internalLogger.info("Create M365 tenant credential"); const config = this.loadAndValidateConfig(authConfig); @@ -122,9 +109,7 @@ export class AppCredential implements TokenCredential { * * @returns Authentication configuration */ - private loadAndValidateConfig( - config: AuthenticationConfiguration | AppCredentialAuthConfig - ): AuthenticationConfiguration | AppCredentialAuthConfig { + private loadAndValidateConfig(config: AppCredentialAuthConfig): AppCredentialAuthConfig { internalLogger.verbose("Validate authentication configuration"); if ( diff --git a/packages/sdk/src/credential/onBehalfOfUserCredential.browser.ts b/packages/sdk/src/credential/onBehalfOfUserCredential.browser.ts index 11673c21c5..cb8ae12546 100644 --- a/packages/sdk/src/credential/onBehalfOfUserCredential.browser.ts +++ b/packages/sdk/src/credential/onBehalfOfUserCredential.browser.ts @@ -3,10 +3,7 @@ import { AccessToken, GetTokenOptions, TokenCredential } from "@azure/identity"; import { UserInfo } from "../models/userinfo"; -import { - AuthenticationConfiguration, - OnBehalfOfCredentialAuthConfig, -} from "../models/configuration"; +import { OnBehalfOfCredentialAuthConfig } from "../models/configuration"; import { formatString } from "../util/utils"; import { ErrorWithCode, ErrorCode, ErrorMessage } from "../core/errors"; @@ -23,12 +20,7 @@ export class OnBehalfOfUserCredential implements TokenCredential { * @remarks * Can Only works in in server side. */ - constructor(ssoToken: string, config: OnBehalfOfCredentialAuthConfig); - constructor(ssoToken: string, config: AuthenticationConfiguration); - constructor( - ssoToken: string, - config: OnBehalfOfCredentialAuthConfig | AuthenticationConfiguration - ) { + constructor(ssoToken: string, config: OnBehalfOfCredentialAuthConfig) { throw new ErrorWithCode( formatString(ErrorMessage.BrowserRuntimeNotSupported, "OnBehalfOfUserCredential"), ErrorCode.RuntimeNotSupported diff --git a/packages/sdk/src/credential/onBehalfOfUserCredential.ts b/packages/sdk/src/credential/onBehalfOfUserCredential.ts index c1cb64fbf3..acef49fccf 100644 --- a/packages/sdk/src/credential/onBehalfOfUserCredential.ts +++ b/packages/sdk/src/credential/onBehalfOfUserCredential.ts @@ -4,10 +4,7 @@ import { AccessToken, GetTokenOptions, TokenCredential } from "@azure/identity"; import { AuthenticationResult, ConfidentialClientApplication } from "@azure/msal-node"; import { UserInfo } from "../models/userinfo"; -import { - AuthenticationConfiguration, - OnBehalfOfCredentialAuthConfig, -} from "../models/configuration"; +import { OnBehalfOfCredentialAuthConfig } from "../models/configuration"; import { internalLogger } from "../util/logger"; import { formatString, @@ -47,25 +44,7 @@ export class OnBehalfOfUserCredential implements TokenCredential { * @throws {@link ErrorCode|InternalError} when SSO token is not valid. * @throws {@link ErrorCode|RuntimeNotSupported} when runtime is browser. */ - constructor(ssoToken: string, config: OnBehalfOfCredentialAuthConfig); - /** - * Constructor of OnBehalfOfUserCredential - * - * @remarks - * Only works in in server side. - * - * @param {string} ssoToken - User token provided by Teams SSO feature. - * @param {AuthenticationConfiguration} config - The authentication configuration. Use environment variables if not provided. - * - * @throws {@link ErrorCode|InvalidConfiguration} when client id, client secret, certificate content, authority host or tenant id is not found in config. - * @throws {@link ErrorCode|InternalError} when SSO token is not valid. - * @throws {@link ErrorCode|RuntimeNotSupported} when runtime is browser. - */ - constructor(ssoToken: string, config: AuthenticationConfiguration); - constructor( - ssoToken: string, - config: OnBehalfOfCredentialAuthConfig | AuthenticationConfiguration - ) { + constructor(ssoToken: string, config: OnBehalfOfCredentialAuthConfig) { internalLogger.info("Get on behalf of user credential"); const missingConfigurations: string[] = []; diff --git a/packages/sdk/src/credential/teamsUserCredential.browser.ts b/packages/sdk/src/credential/teamsUserCredential.browser.ts index 4cb31540c5..7cf6e0e077 100644 --- a/packages/sdk/src/credential/teamsUserCredential.browser.ts +++ b/packages/sdk/src/credential/teamsUserCredential.browser.ts @@ -6,10 +6,7 @@ import { GetTeamsUserTokenOptions } from "../models/teamsUserTokenOptions"; import { UserInfo } from "../models/userinfo"; import { ErrorCode, ErrorMessage, ErrorWithCode } from "../core/errors"; import { app, authentication } from "@microsoft/teams-js"; -import { - AuthenticationConfiguration, - TeamsUserCredentialAuthConfig, -} from "../models/configuration"; +import { TeamsUserCredentialAuthConfig } from "../models/configuration"; import { validateScopesType, getUserInfoFromSsoToken, @@ -32,7 +29,7 @@ const loginPageHeight = 535; * Can only be used within Teams. */ export class TeamsUserCredential implements TokenCredential { - private readonly config: AuthenticationConfiguration; + private readonly config: TeamsUserCredentialAuthConfig; private ssoToken: AccessToken | null; private initialized: boolean; private msalInstance?: PublicClientApplication; @@ -57,30 +54,7 @@ export class TeamsUserCredential implements TokenCredential { * @throws {@link ErrorCode|InvalidConfiguration} when client id, initiate login endpoint or simple auth endpoint is not found in config. * @throws {@link ErrorCode|RuntimeNotSupported} when runtime is nodeJS. */ - constructor(authConfig: TeamsUserCredentialAuthConfig); - // eslint-disable-next-line no-secrets/no-secrets - /** - * Constructor of TeamsUserCredential. - * @deprecated - * @example - * ```typescript - * const config: AuthenticationConfiguration = { - * initiateLoginEndpoint: "https://localhost:3000/auth-start.html", - * clientId: "xxx" - * } - * // Use default configuration provided by Teams Toolkit - * const credential = new TeamsUserCredential(); - * // Use a customized configuration - * const anotherCredential = new TeamsUserCredential(config); - * ``` - * - * @param {TeamsUserCredentialAuthConfig} authConfig - The authentication configuration. - * - * @throws {@link ErrorCode|InvalidConfiguration} when client id, initiate login endpoint or simple auth endpoint is not found in config. - * @throws {@link ErrorCode|RuntimeNotSupported} when runtime is nodeJS. - */ - constructor(authConfig: AuthenticationConfiguration); - constructor(authConfig: TeamsUserCredentialAuthConfig | AuthenticationConfiguration) { + constructor(authConfig: TeamsUserCredentialAuthConfig) { internalLogger.info("Create teams user credential"); this.config = this.loadAndValidateConfig(authConfig); this.ssoToken = null; @@ -307,7 +281,7 @@ export class TeamsUserCredential implements TokenCredential { const msalConfig = { auth: { - clientId: this.config.clientId!, + clientId: this.config.clientId, authority: `https://login.microsoftonline.com/${this.tid}`, }, cache: { @@ -384,8 +358,8 @@ export class TeamsUserCredential implements TokenCredential { * @returns Authentication configuration */ private loadAndValidateConfig( - config: AuthenticationConfiguration | TeamsUserCredentialAuthConfig - ): AuthenticationConfiguration { + config: TeamsUserCredentialAuthConfig + ): TeamsUserCredentialAuthConfig { internalLogger.verbose("Validate authentication configuration"); if (config.initiateLoginEndpoint && config.clientId) { return config; diff --git a/packages/sdk/src/credential/teamsUserCredential.ts b/packages/sdk/src/credential/teamsUserCredential.ts index bdb69afbf2..92b4c204a2 100644 --- a/packages/sdk/src/credential/teamsUserCredential.ts +++ b/packages/sdk/src/credential/teamsUserCredential.ts @@ -3,10 +3,7 @@ import { AccessToken, TokenCredential, GetTokenOptions } from "@azure/identity"; import { UserInfo } from "../models/userinfo"; -import { - AuthenticationConfiguration, - TeamsUserCredentialAuthConfig, -} from "../models/configuration"; +import { TeamsUserCredentialAuthConfig } from "../models/configuration"; import { ErrorWithCode, ErrorCode, ErrorMessage } from "../core/errors"; import { formatString } from "../util/utils"; @@ -22,9 +19,7 @@ export class TeamsUserCredential implements TokenCredential { * @remarks * Can only be used within Teams. */ - constructor(authConfig: TeamsUserCredentialAuthConfig); - constructor(authConfig: AuthenticationConfiguration); - constructor(authConfig: TeamsUserCredentialAuthConfig | AuthenticationConfiguration) { + constructor(authConfig: TeamsUserCredentialAuthConfig) { throw new ErrorWithCode( formatString(ErrorMessage.NodejsRuntimeNotSupported, "TeamsUserCredential"), ErrorCode.RuntimeNotSupported diff --git a/packages/sdk/src/index.browser.ts b/packages/sdk/src/index.browser.ts index 1f16eab80e..48b1747691 100644 --- a/packages/sdk/src/index.browser.ts +++ b/packages/sdk/src/index.browser.ts @@ -7,19 +7,11 @@ export { AppCredential } from "./credential/appCredential.browser"; export { OnBehalfOfUserCredential } from "./credential/onBehalfOfUserCredential.browser"; export { TeamsUserCredential } from "./credential/teamsUserCredential.browser"; -export { MsGraphAuthProvider } from "./core/msGraphAuthProvider"; -export { - createMicrosoftGraphClient, - createMicrosoftGraphClientWithCredential, -} from "./core/msGraphClientProvider"; -export { getTediousConnectionConfig } from "./core/defaultTediousConnectionConfiguration.browser"; - export { TeamsBotSsoPrompt, TeamsBotSsoPromptSettings } from "./bot/teamsBotSsoPrompt.browser"; export { TeamsBotSsoPromptTokenResponse } from "./bot/teamsBotSsoPromptTokenResponse"; export { UserInfo } from "./models/userinfo"; export { - AuthenticationConfiguration, AppCredentialAuthConfig, OnBehalfOfCredentialAuthConfig, TeamsUserCredentialAuthConfig, @@ -48,18 +40,12 @@ export { createPfxCertOption, } from "./apiClient/certificateAuthProvider.browser"; -export { TeamsFx } from "./core/teamsfx.browser"; -export { IdentityType } from "./models/identityType"; - export { AdaptiveCardResponse, CommandMessage, CommandOptions, CardActionOptions, - ConversationOptions, - NotificationOptions, NotificationTarget, - NotificationTargetStorage, NotificationTargetType, InvokeResponseErrorCode, TriggerPatterns, @@ -70,22 +56,8 @@ export { BotSsoConfig, BotSsoExecutionDialogHandler, } from "./conversation/interface"; -export { ConversationBot } from "./conversation/conversation.browser"; export { BotSsoExecutionDialog } from "./conversation/sso/botSsoExecutionDialog.browser"; -export { - Channel, - Member, - NotificationBot, - sendAdaptiveCard, - sendMessage, - TeamsBotInstallation, -} from "./conversation/notification.browser"; -export { CommandBot } from "./conversation/command.browser"; -export { CardActionBot } from "./conversation/cardAction.browser"; -export { - handleMessageExtensionQueryWithToken, - handleMessageExtensionQueryWithSSO, -} from "./messageExtension/executeWithSSO.browser"; +export { handleMessageExtensionQueryWithSSO } from "./messageExtension/executeWithSSO.browser"; export { MessageExtensionTokenResponse } from "./messageExtension/teamsMsgExtTokenResponse"; import * as BotBuilderCloudAdapter from "./conversationWithCloudAdapter/conversationWithCloudAdapter.browser"; diff --git a/packages/sdk/src/index.ts b/packages/sdk/src/index.ts index cfbfc6d0e1..8a756accd9 100644 --- a/packages/sdk/src/index.ts +++ b/packages/sdk/src/index.ts @@ -7,19 +7,11 @@ export { AppCredential } from "./credential/appCredential"; export { OnBehalfOfUserCredential } from "./credential/onBehalfOfUserCredential"; export { TeamsUserCredential } from "./credential/teamsUserCredential"; -export { MsGraphAuthProvider } from "./core/msGraphAuthProvider"; -export { - createMicrosoftGraphClient, - createMicrosoftGraphClientWithCredential, -} from "./core/msGraphClientProvider"; -export { getTediousConnectionConfig } from "./core/defaultTediousConnectionConfiguration"; - export { TeamsBotSsoPrompt, TeamsBotSsoPromptSettings } from "./bot/teamsBotSsoPrompt"; export { TeamsBotSsoPromptTokenResponse } from "./bot/teamsBotSsoPromptTokenResponse"; export { UserInfo } from "./models/userinfo"; export { - AuthenticationConfiguration, AppCredentialAuthConfig, OnBehalfOfCredentialAuthConfig, TeamsUserCredentialAuthConfig, @@ -48,18 +40,12 @@ export { createPfxCertOption, } from "./apiClient/certificateAuthProvider"; -export { TeamsFx } from "./core/teamsfx"; -export { IdentityType } from "./models/identityType"; - export { AdaptiveCardResponse, CommandMessage, CommandOptions, CardActionOptions, - ConversationOptions, - NotificationOptions, NotificationTarget, - NotificationTargetStorage, NotificationTargetType, ConversationReferenceStore, ConversationReferenceStoreAddOptions, @@ -73,23 +59,10 @@ export { BotSsoConfig, BotSsoExecutionDialogHandler, } from "./conversation/interface"; -export { ConversationBot } from "./conversation/conversation"; export { BotSsoExecutionDialog } from "./conversation/sso/botSsoExecutionDialog"; -export { - Channel, - Member, - NotificationBot, - sendAdaptiveCard, - sendMessage, - TeamsBotInstallation, - SearchScope, -} from "./conversation/notification"; -export { CommandBot } from "./conversation/command"; -export { CardActionBot } from "./conversation/cardAction"; export { MessageBuilder } from "./conversation/messageBuilder"; export { InvokeResponseFactory } from "./conversation/invokeResponseFactory"; export { - handleMessageExtensionQueryWithToken, handleMessageExtensionQueryWithSSO, handleMessageExtensionLinkQueryWithSSO, } from "./messageExtension/executeWithSSO"; diff --git a/packages/sdk/src/messageExtension/executeWithSSO.browser.ts b/packages/sdk/src/messageExtension/executeWithSSO.browser.ts index 8aaa49310a..29be0fd26f 100644 --- a/packages/sdk/src/messageExtension/executeWithSSO.browser.ts +++ b/packages/sdk/src/messageExtension/executeWithSSO.browser.ts @@ -1,33 +1,11 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT license. -import { TurnContext, MessagingExtensionResponse } from "botbuilder"; -import { - AuthenticationConfiguration, - OnBehalfOfCredentialAuthConfig, -} from "../models/configuration"; +import { TurnContext } from "botbuilder"; +import { OnBehalfOfCredentialAuthConfig } from "../models/configuration"; import { MessageExtensionTokenResponse } from "./teamsMsgExtTokenResponse"; import { ErrorWithCode, ErrorMessage, ErrorCode } from "../core/errors"; import { formatString } from "../util/utils"; -// eslint-disable-next-line no-secrets/no-secrets -/** - * Users execute query with SSO or Access Token. - * @deprecated - * @remarks - * Only works in in server side. - */ -export function handleMessageExtensionQueryWithToken( - context: TurnContext, - config: AuthenticationConfiguration, - scopes: string | string[], - logic: (token: MessageExtensionTokenResponse) => Promise -): Promise { - throw new ErrorWithCode( - formatString(ErrorMessage.BrowserRuntimeNotSupported, "queryWithToken in message extension"), - ErrorCode.RuntimeNotSupported - ); -} - /** * Users execute query with SSO or Access Token. * @remarks diff --git a/packages/sdk/src/messageExtension/executeWithSSO.ts b/packages/sdk/src/messageExtension/executeWithSSO.ts index 009aaed8dc..61fd19393f 100644 --- a/packages/sdk/src/messageExtension/executeWithSSO.ts +++ b/packages/sdk/src/messageExtension/executeWithSSO.ts @@ -6,13 +6,8 @@ import { TurnContext, MessagingExtensionResponse, ActivityTypes } from "botbuild import { parseJwt, getScopesArray, formatString } from "../util/utils"; import { MessageExtensionTokenResponse } from "./teamsMsgExtTokenResponse"; import { ErrorWithCode, ErrorCode, ErrorMessage } from "../core/errors"; -import { - AuthenticationConfiguration, - OnBehalfOfCredentialAuthConfig, -} from "../models/configuration"; -import { IdentityType } from "../models/identityType"; +import { OnBehalfOfCredentialAuthConfig } from "../models/configuration"; import { internalLogger } from "../util/logger"; -import { TeamsFx } from "../core/teamsfx"; import { OnBehalfOfUserCredential } from "../credential/onBehalfOfUserCredential"; /** * Retrieve the OAuth Sign in Link to use in the MessagingExtensionResult Suggested Actions. @@ -84,36 +79,6 @@ function getSignInResponseForMessageExtensionWithAuthConfig( }; } -/** - * Retrieve the OAuth Sign in Link to use in the MessagingExtensionResult Suggested Actions. - * This method only work on MessageExtension with Query now. - * - * @param {TeamsFx} teamsfx - Used to provide configuration and auth. - * @param {string | string[]} scopes - The list of scopes for which the token will have access. - * - * @returns SignIn link CardAction with 200 status code. - */ -function getSignInResponseForMessageExtension(teamsfx: TeamsFx, scopes: string | string[]): any { - const scopesArray = getScopesArray(scopes); - const signInLink = `${teamsfx.getConfig("initiateLoginEndpoint")}?scope=${encodeURI( - scopesArray.join(" ") - )}&clientId=${teamsfx.getConfig("clientId")}&tenantId=${teamsfx.getConfig("tenantId")}`; - return { - composeExtension: { - type: "silentAuth", - suggestedActions: { - actions: [ - { - type: "openUrl", - value: signInLink, - title: "Message Extension OAuth", - }, - ], - }, - }, - }; -} - /** * execution in message extension with SSO token. * @@ -192,96 +157,6 @@ export async function executionWithTokenAndConfig( } } -/** - * execution in message extension with SSO token. - * @deprecated Use {@link executionWithTokenAndConfig} instead. - * - * @param {TurnContext} context - The context object for the current turn. - * @param {AuthenticationConfiguration} config - User custom the message extension authentication configuration. - * @param {string[]} scopes - The list of scopes for which the token will have access. - * @param {function} logic - Business logic when executing the query in message extension with SSO or access token. - * - * @throws {@link ErrorCode|InternalError} when failed to get access token with unknown error. - * @throws {@link ErrorCode|TokenExpiredError} when SSO token has already expired. - * @throws {@link ErrorCode|ServiceError} when failed to get access token from simple auth server. - * @throws {@link ErrorCode|InvalidParameter} when scopes is not a valid string or string array. - * @throws {@link ErrorCode|RuntimeNotSupported} when runtime is nodeJS. - * - * @returns A MessageExtension Response for the activity. If the logic not return any, return void instead. - */ -export async function executionWithToken( - context: TurnContext, - config: AuthenticationConfiguration, - scopes: string | string[], - logic?: (token: MessageExtensionTokenResponse) => Promise -): Promise { - const valueObj = context.activity.value; - if (!valueObj.authentication || !valueObj.authentication.token) { - internalLogger.verbose("No AccessToken in request, return silentAuth for AccessToken"); - return getSignInResponseForMessageExtension(new TeamsFx(IdentityType.User, config), scopes); - } - try { - const teamsfx = new TeamsFx(IdentityType.User, config).setSsoToken( - valueObj.authentication.token - ); - const token: AccessToken | null = await teamsfx.getCredential().getToken(scopes); - const ssoTokenExpiration: number = parseJwt(valueObj.authentication.token).exp; - const tokenRes: MessageExtensionTokenResponse = { - ssoToken: valueObj.authentication.token, - ssoTokenExpiration: new Date(ssoTokenExpiration * 1000).toISOString(), - token: token!.token, - expiration: token!.expiresOnTimestamp.toString(), - connectionName: "", - }; - if (logic) { - return await logic(tokenRes); - } - } catch (err) { - if (err instanceof ErrorWithCode && err.code === ErrorCode.UiRequiredError) { - internalLogger.verbose("User not consent yet, return 412 to user consent first."); - const response = { status: 412 }; - await context.sendActivity({ value: response, type: ActivityTypes.InvokeResponse }); - return; - } - throw err; - } -} - -// eslint-disable-next-line no-secrets/no-secrets -/** - * Users execute query in message extension with SSO or access token. - * @deprecated Use {@link handleMessageExtensionQueryWithSSO} instead. - * - * @param {TurnContext} context - The context object for the current turn. - * @param {AuthenticationConfiguration} config - User custom the message extension authentication configuration. - * @param {string| string[]} scopes - The list of scopes for which the token will have access. - * @param {function} logic - Business logic when executing the query in message extension with SSO or access token. - * - * @throws {@link ErrorCode|InternalError} when User invoke not response to message extension query. - * @throws {@link ErrorCode|InternalError} when failed to get access token with unknown error. - * @throws {@link ErrorCode|TokenExpiredError} when SSO token has already expired. - * @throws {@link ErrorCode|ServiceError} when failed to get access token from simple auth server. - * @throws {@link ErrorCode|InvalidParameter} when scopes is not a valid string or string array. - * @throws {@link ErrorCode|RuntimeNotSupported} when runtime is nodeJS. - * - * @returns A MessageExtension Response for the activity. If the logic not return any, return void instead. - */ -export async function handleMessageExtensionQueryWithToken( - context: TurnContext, - config: AuthenticationConfiguration | null, - scopes: string | string[], - logic: (token: MessageExtensionTokenResponse) => Promise -): Promise { - if (context.activity.name != "composeExtension/query") { - internalLogger.error(ErrorMessage.OnlySupportInQueryActivity); - throw new ErrorWithCode( - formatString(ErrorMessage.OnlySupportInQueryActivity), - ErrorCode.FailedOperation - ); - } - return await executionWithToken(context, config ?? {}, scopes, logic); -} - /** * Users execute query in message extension with SSO or access token. * diff --git a/packages/sdk/src/models/configuration.ts b/packages/sdk/src/models/configuration.ts index 0735e8adf6..513ef55c6b 100644 --- a/packages/sdk/src/models/configuration.ts +++ b/packages/sdk/src/models/configuration.ts @@ -1,61 +1,6 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT license. -// eslint-disable-next-line no-secrets/no-secrets -/** - * Authentication related configuration. - * @deprecated Please use {@link TeamsUserCredentialAuthConfig} - * or {@link OnBehalfOfCredentialAuthConfig} or {@link AppCredentialAuthConfig} instead. - */ -export interface AuthenticationConfiguration { - /** - * Hostname of AAD authority. Default value comes from M365_AUTHORITY_HOST environment variable. - * - * @readonly - */ - readonly authorityHost?: string; - - /** - * AAD tenant id, default value comes from M365_TENANT_ID environment variable. - * - * @readonly - */ - readonly tenantId?: string; - - /** - * The client (application) ID of an App Registration in the tenant, default value comes from M365_CLIENT_ID environment variable - * - * @readonly - */ - readonly clientId?: string; - - /** - * Secret string that the application uses when requesting a token. Only used in confidential client applications. Can be created in the Azure app registration portal. Default value comes from M365_CLIENT_SECRET environment variable - * - * @readonly - */ - readonly clientSecret?: string; - - /** - * The content of a PEM-encoded public/private key certificate. - * - * @readonly - */ - readonly certificateContent?: string; - - /** - * Login page for Teams to redirect to. Default value comes from INITIATE_LOGIN_ENDPOINT environment variable. - * - * @readonly - */ - readonly initiateLoginEndpoint?: string; - - /** - * Application ID URI. Default value comes from M365_APPLICATION_ID_URI environment variable. - */ - readonly applicationIdUri?: string; -} - /** * Authentication configuration for TeamsUserCredential used in browser environment */ diff --git a/packages/sdk/src/models/identityType.ts b/packages/sdk/src/models/identityType.ts deleted file mode 100644 index 345c80b352..0000000000 --- a/packages/sdk/src/models/identityType.ts +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. - -/** - * Identity type to use in authentication. - */ -export enum IdentityType { - /** - * Represents the current user of Teams. - */ - User = "User", - /** - * Represents the application itself. - */ - App = "Application", -} diff --git a/packages/sdk/src/models/teamsfxConfiguration.ts b/packages/sdk/src/models/teamsfxConfiguration.ts deleted file mode 100644 index a82d7824cf..0000000000 --- a/packages/sdk/src/models/teamsfxConfiguration.ts +++ /dev/null @@ -1,87 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. - -import { TokenCredential } from "@azure/identity"; -import { IdentityType, UserInfo } from ".."; - -/** - * TeamsFx interface that provides credential and configuration. - * @deprecated Please use {@link TeamsUserCredential} - * in browser environment and {@link OnBehalfOfUserCredential} or {@link AppCredential} in NodeJS. - */ -export interface TeamsFxConfiguration { - /** - * Identity type set by user. - * - * @returns identity type. - */ - getIdentityType(): IdentityType; - - /** - * Credential instance according to identity type choice. - * - * @remarks If user identity is chose, will return {@link TeamsUserCredential} - * in browser environment and {@link OnBehalfOfUserCredential} in NodeJS. If app - * identity is chose, will return {@link AppCredential}. - * - * @returns instance implements TokenCredential interface. - */ - getCredential(): TokenCredential; - - /** - * Get user information. - * @param {string[]} resources - The optional list of resources for full trust Teams apps. - * @returns UserInfo object. - */ - getUserInfo(resources?: string[]): Promise; - - /** - * Popup login page to get user's access token with specific scopes. - * - * @remarks - * Only works in Teams client APP. User will be redirected to the authorization page to login and consent. - * - * @example - * ```typescript - * await teamsfx.login(["https://graph.microsoft.com/User.Read"]); // single scope using string array - * await teamsfx.login("https://graph.microsoft.com/User.Read"); // single scopes using string - * await teamsfx.login(["https://graph.microsoft.com/User.Read", "Calendars.Read"]); // multiple scopes using string array - * await teamsfx.login("https://graph.microsoft.com/User.Read Calendars.Read"); // multiple scopes using string - * ``` - * @param scopes - The list of scopes for which the token will have access, before that, we will request user to consent. - * @param {string[]} resources - The optional list of resources for full trust Teams apps. - * - * @throws {@link ErrorCode|InternalError} when failed to login with unknown error. - * @throws {@link ErrorCode|ConsentFailed} when user canceled or failed to consent. - * @throws {@link ErrorCode|InvalidParameter} when scopes is not a valid string or string array. - * @throws {@link ErrorCode|RuntimeNotSupported} when runtime is nodeJS. - */ - login(scopes: string | string[], resources?: string[]): Promise; - - /** - * Set SSO token when using user identity in NodeJS. - * @param {string} ssoToken - used for on behalf of user flow. - * @returns self instance. - */ - setSsoToken(ssoToken: string): TeamsFxConfiguration; - - /** - * Usually used by service plugins to retrieve specific config - * @param {string} key - configuration key. - * @returns value in configuration. - */ - getConfig(key: string): string; - - /** - * Check the value of specific key. - * @param {string} key - configuration key. - * @returns true if corresponding value is not empty string. - */ - hasConfig(key: string): boolean; - - /** - * Get all configurations. - * @returns key value mappings. - */ - getConfigs(): Record; -} diff --git a/packages/sdk/src/util/utils.node.ts b/packages/sdk/src/util/utils.node.ts index 48eca6c310..d2d39b6663 100644 --- a/packages/sdk/src/util/utils.node.ts +++ b/packages/sdk/src/util/utils.node.ts @@ -1,11 +1,7 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT license. import { ConfidentialClientApplication, NodeAuthOptions } from "@azure/msal-node"; -import { - AppCredentialAuthConfig, - AuthenticationConfiguration, - OnBehalfOfCredentialAuthConfig, -} from "../models/configuration"; +import { AppCredentialAuthConfig, OnBehalfOfCredentialAuthConfig } from "../models/configuration"; import { ClientCertificate, getAuthority } from "./utils"; import { internalLogger } from "./logger"; import { ErrorWithCode, ErrorCode } from "../core/errors"; @@ -15,18 +11,15 @@ import { createHash } from "crypto"; * @internal */ export function createConfidentialClientApplication( - authentication: - | AuthenticationConfiguration - | AppCredentialAuthConfig - | OnBehalfOfCredentialAuthConfig + authentication: AppCredentialAuthConfig | OnBehalfOfCredentialAuthConfig ): ConfidentialClientApplication { - const authority = getAuthority(authentication.authorityHost!, authentication.tenantId!); + const authority = getAuthority(authentication.authorityHost, authentication.tenantId); const clientCertificate: ClientCertificate | undefined = parseCertificate( authentication.certificateContent ); const auth: NodeAuthOptions = { - clientId: authentication.clientId!, + clientId: authentication.clientId, authority: authority, }; @@ -59,13 +52,13 @@ export function parseCertificate( internalLogger.error(errorMsg); throw new ErrorWithCode(errorMsg, ErrorCode.InvalidCertificate); } - const thumbprint = createHash("sha1") + const thumbprint = createHash("sha256") .update(Buffer.from(match[3], "base64")) .digest("hex") .toUpperCase(); return { - thumbprint: thumbprint, + thumbprintSha256: thumbprint, privateKey: certificateContent, }; } diff --git a/packages/sdk/src/util/utils.ts b/packages/sdk/src/util/utils.ts index 7f5a1d8d5c..7960cced3b 100644 --- a/packages/sdk/src/util/utils.ts +++ b/packages/sdk/src/util/utils.ts @@ -1,9 +1,9 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT license. -import { ErrorWithCode, ErrorCode } from "../core/errors"; +import { ErrorWithCode, ErrorCode, ErrorMessage } from "../core/errors"; import { SSOTokenInfoBase, SSOTokenV1Info, SSOTokenV2Info } from "../models/ssoTokenInfo"; import { UserInfo, UserTenantIdAndLoginHint } from "../models/userinfo"; -import jwt_decode from "jwt-decode"; +import { jwtDecode } from "jwt-decode"; import { internalLogger } from "./logger"; import { AccessToken } from "@azure/identity"; import { AuthenticationResult } from "@azure/msal-browser"; @@ -19,7 +19,7 @@ import { AuthenticationResult } from "@azure/msal-browser"; */ export function parseJwt(token: string): SSOTokenInfoBase { try { - const tokenObj: SSOTokenInfoBase = jwt_decode(token); + const tokenObj: SSOTokenInfoBase = jwtDecode(token); if (!tokenObj || !tokenObj.exp) { throw new ErrorWithCode( "Decoded token is null or exp claim does not exists.", @@ -185,10 +185,50 @@ export function getAuthority(authorityHost: string, tenantId: string): string { return normalizedAuthorityHost + "/" + tenantId; } +/** + * @internal + */ +export function validateConfig(config: any): void { + if ( + config.clientId && + (config.clientSecret || config.certificateContent) && + config.tenantId && + config.authorityHost + ) { + return; + } + + const missingValues = []; + + if (!config.clientId) { + missingValues.push("clientId"); + } + + if (!config.clientSecret && !config.certificateContent) { + missingValues.push("clientSecret or certificateContent"); + } + + if (!config.tenantId) { + missingValues.push("tenantId"); + } + + if (!config.authorityHost) { + missingValues.push("authorityHost"); + } + + const errorMsg = formatString( + ErrorMessage.InvalidConfiguration, + missingValues.join(", "), + "undefined" + ); + internalLogger.error(errorMsg); + throw new ErrorWithCode(errorMsg, ErrorCode.InvalidConfiguration); +} + /** * @internal */ export interface ClientCertificate { - thumbprint: string; + thumbprintSha256: string; privateKey: string; } diff --git a/packages/sdk/test/e2e/browser/msGraphAuthProvider.browser.spec.ts b/packages/sdk/test/e2e/browser/msGraphAuthProvider.browser.spec.ts deleted file mode 100644 index 557a8744a5..0000000000 --- a/packages/sdk/test/e2e/browser/msGraphAuthProvider.browser.spec.ts +++ /dev/null @@ -1,168 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. - -import { AccessToken } from "@azure/core-auth"; -import { assert, use as chaiUse } from "chai"; -import * as chaiPromises from "chai-as-promised"; -import { - MsGraphAuthProvider, - TeamsFx, - IdentityType, - TeamsUserCredentialAuthConfig, -} from "../../../src/index.browser"; -import { TeamsUserCredential } from "../../../src/credential/teamsUserCredential.browser"; -import * as sinon from "sinon"; -import { - getSSOToken, - AADJwtPayLoad, - SSOToken, - getGraphToken, - extractIntegrationEnvVariables, -} from "../helper.browser"; -import jwtDecode from "jwt-decode"; - -chaiUse(chaiPromises); -extractIntegrationEnvVariables(); -const env = (window as any).__env__; - -describe("MsGraphAuthProvider Tests - Browser", () => { - let ssoToken: SSOToken; - - beforeEach(async function () { - ssoToken = await getSSOToken(); - - // mock getting sso token. - sinon - .stub(TeamsUserCredential.prototype, "getSSOToken") - .callsFake((): Promise => { - return new Promise((resolve) => { - resolve({ - token: ssoToken.token!, - expiresOnTimestamp: ssoToken.expire_time!, - }); - }); - }); - - sinon - .stub(TeamsUserCredential.prototype, "getToken") - .callsFake(async (scopes: string | string[]): Promise => { - const graphToken = await getGraphToken(ssoToken, scopes); - return new Promise((resolve) => { - resolve({ - token: graphToken, - expiresOnTimestamp: ssoToken.expire_time!, - }); - }); - }); - }); - - afterEach(() => { - sinon.restore(); - }); - - it("getAccessToken with user.read scopes should get valid access token", async function () { - const scopes = "User.Read"; - const teamsfx = new TeamsFx(IdentityType.User, { - initiateLoginEndpoint: "fake_login_url", - clientId: env.SDK_INTEGRATION_TEST_M365_AAD_CLIENT_ID, - }); - - const authProvider: MsGraphAuthProvider = new MsGraphAuthProvider(teamsfx, scopes); - const accessToken = await authProvider.getAccessToken(); - - const decodedToken = jwtDecode(accessToken); - assert.strictEqual(decodedToken.aud, "00000003-0000-0000-c000-000000000000"); - assert.strictEqual(decodedToken.appid, env.SDK_INTEGRATION_TEST_M365_AAD_CLIENT_ID); - assert.strictEqual(decodedToken.idtyp, "user"); - assert.strictEqual(decodedToken.upn, env.SDK_INTEGRATION_TEST_ACCOUNT_NAME); - assert.isTrue(decodedToken.scp!.indexOf(scopes) >= 0); - }); - - it("getAccessToken without scopes should get access token with default scope", async function () { - const teamsfx = new TeamsFx(IdentityType.User, { - initiateLoginEndpoint: "fake_login_url", - clientId: env.SDK_INTEGRATION_TEST_M365_AAD_CLIENT_ID, - }); - const authProvider: MsGraphAuthProvider = new MsGraphAuthProvider(teamsfx); - const accessToken = await authProvider.getAccessToken(); - - const decodedToken = jwtDecode(accessToken); - assert.strictEqual(decodedToken.aud, "https://graph.microsoft.com"); - assert.strictEqual(decodedToken.appid, env.SDK_INTEGRATION_TEST_M365_AAD_CLIENT_ID); - assert.strictEqual(decodedToken.idtyp, "user"); - assert.strictEqual(decodedToken.upn, env.SDK_INTEGRATION_TEST_ACCOUNT_NAME); - assert.isTrue(decodedToken.scp!.indexOf("User.Read") >= 0); - }); -}); - -describe("MsGraphAuthProvider Tests with Credential - Browser", () => { - let ssoToken: SSOToken; - - beforeEach(async function () { - ssoToken = await getSSOToken(); - - // mock getting sso token. - sinon - .stub(TeamsUserCredential.prototype, "getSSOToken") - .callsFake((): Promise => { - return new Promise((resolve) => { - resolve({ - token: ssoToken.token!, - expiresOnTimestamp: ssoToken.expire_time!, - }); - }); - }); - - sinon - .stub(TeamsUserCredential.prototype, "getToken") - .callsFake(async (scopes: string | string[]): Promise => { - const graphToken = await getGraphToken(ssoToken, scopes); - return new Promise((resolve) => { - resolve({ - token: graphToken, - expiresOnTimestamp: ssoToken.expire_time!, - }); - }); - }); - }); - - afterEach(() => { - sinon.restore(); - }); - - it("getAccessToken with user.read scopes should get valid access token", async function () { - const scopes = "User.Read"; - const authConfig: TeamsUserCredentialAuthConfig = { - initiateLoginEndpoint: "fake_login_url", - clientId: env.SDK_INTEGRATION_TEST_M365_AAD_CLIENT_ID, - }; - const credential: TeamsUserCredential = new TeamsUserCredential(authConfig); - - const authProvider: MsGraphAuthProvider = new MsGraphAuthProvider(credential, scopes); - const accessToken = await authProvider.getAccessToken(); - - const decodedToken = jwtDecode(accessToken); - assert.strictEqual(decodedToken.aud, "00000003-0000-0000-c000-000000000000"); - assert.strictEqual(decodedToken.appid, env.SDK_INTEGRATION_TEST_M365_AAD_CLIENT_ID); - assert.strictEqual(decodedToken.idtyp, "user"); - assert.strictEqual(decodedToken.upn, env.SDK_INTEGRATION_TEST_ACCOUNT_NAME); - assert.isTrue(decodedToken.scp!.indexOf(scopes) >= 0); - }); - - it("getAccessToken without scopes should get access token with default scope", async function () { - const authConfig: TeamsUserCredentialAuthConfig = { - initiateLoginEndpoint: "fake_login_url", - clientId: env.SDK_INTEGRATION_TEST_M365_AAD_CLIENT_ID, - }; - const credential: TeamsUserCredential = new TeamsUserCredential(authConfig); - const authProvider: MsGraphAuthProvider = new MsGraphAuthProvider(credential); - const accessToken = await authProvider.getAccessToken(); - - const decodedToken = jwtDecode(accessToken); - assert.strictEqual(decodedToken.aud, "https://graph.microsoft.com"); - assert.strictEqual(decodedToken.appid, env.SDK_INTEGRATION_TEST_M365_AAD_CLIENT_ID); - assert.strictEqual(decodedToken.idtyp, "user"); - assert.strictEqual(decodedToken.upn, env.SDK_INTEGRATION_TEST_ACCOUNT_NAME); - assert.isTrue(decodedToken.scp!.indexOf("User.Read") >= 0); - }); -}); diff --git a/packages/sdk/test/e2e/browser/msGraphClientProvider.browser.spec.ts b/packages/sdk/test/e2e/browser/msGraphClientProvider.browser.spec.ts deleted file mode 100644 index 66ac8e12d9..0000000000 --- a/packages/sdk/test/e2e/browser/msGraphClientProvider.browser.spec.ts +++ /dev/null @@ -1,183 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. - -import { assert, expect, use as chaiUse } from "chai"; -import * as chaiPromises from "chai-as-promised"; -import { - createMicrosoftGraphClient, - TeamsFx, - IdentityType, - TeamsUserCredentialAuthConfig, - createMicrosoftGraphClientWithCredential, -} from "../../../src/index.browser"; -import { TeamsUserCredential } from "../../../src/credential/teamsUserCredential.browser"; -import { - extractIntegrationEnvVariables, - getGraphToken, - getSSOToken, - SSOToken, -} from "../helper.browser"; -import * as sinon from "sinon"; -import { AccessToken } from "@azure/core-auth"; - -chaiUse(chaiPromises); -extractIntegrationEnvVariables(); -const env = (window as any).__env__; - -describe("MsGraphClientProvider Tests - Browser", () => { - let ssoToken: SSOToken; - - beforeEach(async function () { - ssoToken = await getSSOToken(); - - // mock getting sso token. - sinon - .stub(TeamsUserCredential.prototype, "getSSOToken") - .callsFake((): Promise => { - return new Promise((resolve) => { - resolve({ - token: ssoToken.token!, - expiresOnTimestamp: ssoToken.expire_time!, - }); - }); - }); - - sinon - .stub(TeamsUserCredential.prototype, "getToken") - .callsFake(async (scopes: string | string[]): Promise => { - const graphToken = await getGraphToken(ssoToken, scopes); - return new Promise((resolve) => { - resolve({ - token: graphToken, - expiresOnTimestamp: ssoToken.expire_time!, - }); - }); - }); - }); - - afterEach(() => { - sinon.restore(); - }); - - it("create graph client with user.read scope should be able to get user profile", async function () { - const scopes = ["User.Read"]; - const teamsfx = new TeamsFx(IdentityType.User, { - initiateLoginEndpoint: "fake_login_url", - clientId: env.SDK_INTEGRATION_TEST_M365_AAD_CLIENT_ID, - }); - const graphClient: any = createMicrosoftGraphClient(teamsfx, scopes); - const profile = await graphClient.api("/me").get(); - assert.strictEqual(profile.userPrincipalName, env.SDK_INTEGRATION_TEST_ACCOUNT_NAME); - }); - - it("create graph client with empty scope should have the default scope", async function () { - const emptyScope = ""; - const teamsfx = new TeamsFx(IdentityType.User, { - initiateLoginEndpoint: "fake_login_url", - clientId: env.SDK_INTEGRATION_TEST_M365_AAD_CLIENT_ID, - }); - const graphClient: any = createMicrosoftGraphClient(teamsfx, emptyScope); - const userList = await graphClient.api("/users").get(); - assert.strictEqual( - userList["@odata.context"], - "https://graph.microsoft.com/v1.0/$metadata#users" - ); - }); - - it("create graph client without providing scope should have the default scope", async function () { - const defaultScope = "https://graph.microsoft.com/.default"; - const teamsfx = new TeamsFx(IdentityType.User, { - initiateLoginEndpoint: "fake_login_url", - clientId: env.SDK_INTEGRATION_TEST_M365_AAD_CLIENT_ID, - }); - const graphClient: any = createMicrosoftGraphClient(teamsfx); - assert.strictEqual(graphClient.config.authProvider.scopes, defaultScope); - const userList = await graphClient.api("/users").get(); - assert.strictEqual( - userList["@odata.context"], - "https://graph.microsoft.com/v1.0/$metadata#users" - ); - }); -}); - -describe("MsGraphClientProvider Tests with Credential - Browser", () => { - let ssoToken: SSOToken; - - beforeEach(async function () { - ssoToken = await getSSOToken(); - - // mock getting sso token. - sinon - .stub(TeamsUserCredential.prototype, "getSSOToken") - .callsFake((): Promise => { - return new Promise((resolve) => { - resolve({ - token: ssoToken.token!, - expiresOnTimestamp: ssoToken.expire_time!, - }); - }); - }); - - sinon - .stub(TeamsUserCredential.prototype, "getToken") - .callsFake(async (scopes: string | string[]): Promise => { - const graphToken = await getGraphToken(ssoToken, scopes); - return new Promise((resolve) => { - resolve({ - token: graphToken, - expiresOnTimestamp: ssoToken.expire_time!, - }); - }); - }); - }); - - afterEach(() => { - sinon.restore(); - }); - - it("create graph client with user.read scope should be able to get user profile", async function () { - const scopes = ["User.Read"]; - const authConfig: TeamsUserCredentialAuthConfig = { - initiateLoginEndpoint: "fake_login_url", - clientId: env.SDK_INTEGRATION_TEST_M365_AAD_CLIENT_ID, - }; - const credential: TeamsUserCredential = new TeamsUserCredential(authConfig); - - const graphClient: any = createMicrosoftGraphClientWithCredential(credential, scopes); - const profile = await graphClient.api("/me").get(); - assert.strictEqual(profile.userPrincipalName, env.SDK_INTEGRATION_TEST_ACCOUNT_NAME); - }); - - it("create graph client with empty scope should have the default scope", async function () { - const emptyScope = ""; - const authConfig: TeamsUserCredentialAuthConfig = { - initiateLoginEndpoint: "fake_login_url", - clientId: env.SDK_INTEGRATION_TEST_M365_AAD_CLIENT_ID, - }; - const credential: TeamsUserCredential = new TeamsUserCredential(authConfig); - - const graphClient: any = createMicrosoftGraphClientWithCredential(credential, emptyScope); - const userList = await graphClient.api("/users").get(); - assert.strictEqual( - userList["@odata.context"], - "https://graph.microsoft.com/v1.0/$metadata#users" - ); - }); - - it("create graph client without providing scope should have the default scope", async function () { - const defaultScope = "https://graph.microsoft.com/.default"; - const authConfig: TeamsUserCredentialAuthConfig = { - initiateLoginEndpoint: "fake_login_url", - clientId: env.SDK_INTEGRATION_TEST_M365_AAD_CLIENT_ID, - }; - const credential: TeamsUserCredential = new TeamsUserCredential(authConfig); - - const graphClient: any = createMicrosoftGraphClientWithCredential(credential); - assert.strictEqual(graphClient.config.authProvider.scopes, defaultScope); - const userList = await graphClient.api("/users").get(); - assert.strictEqual( - userList["@odata.context"], - "https://graph.microsoft.com/v1.0/$metadata#users" - ); - }); -}); diff --git a/packages/sdk/test/e2e/browser/teamsUserCredential.browser.spec.ts b/packages/sdk/test/e2e/browser/teamsUserCredential.browser.spec.ts index b1b732e3ec..d996734818 100644 --- a/packages/sdk/test/e2e/browser/teamsUserCredential.browser.spec.ts +++ b/packages/sdk/test/e2e/browser/teamsUserCredential.browser.spec.ts @@ -6,7 +6,7 @@ import { AccessToken } from "@azure/core-auth"; import * as sinon from "sinon"; import { TeamsUserCredential, ErrorWithCode } from "../../../src/index.browser"; import { getSSOToken, AADJwtPayLoad, SSOToken, getGraphToken } from "../helper.browser"; -import jwtDecode from "jwt-decode"; +import { jwtDecode } from "jwt-decode"; import { AccountInfo, AuthenticationResult, PublicClientApplication } from "@azure/msal-browser"; chai.use(chaiPromises); @@ -18,6 +18,7 @@ describe("TeamsUserCredential Tests - Browser", () => { const UIREQUIREDERROR = "UiRequiredError"; const FAKE_LOGIN_ENDPOINT = "FakeLoginEndpoint"; let ssoToken: SSOToken; + beforeEach(async () => { ssoToken = await getSSOToken(); sinon @@ -31,6 +32,7 @@ describe("TeamsUserCredential Tests - Browser", () => { }); }); }); + afterEach(() => { sinon.restore(); }); diff --git a/packages/sdk/test/e2e/helper.browser.ts b/packages/sdk/test/e2e/helper.browser.ts index 198de0dd5d..66ea61590e 100644 --- a/packages/sdk/test/e2e/helper.browser.ts +++ b/packages/sdk/test/e2e/helper.browser.ts @@ -47,15 +47,20 @@ export async function getSSOToken(): Promise { formBody.push(encodedKey + "=" + encodedValue); } const body = formBody.join("&"); - const response = await axios.post( - `https://login.microsoftonline.com/${env.SDK_INTEGRATION_TEST_AAD_TENANT_ID}/oauth2/v2.0/token`, - body, - { - headers: { - "Content-Type": "application/x-www-form-urlencoded", - }, - } - ); + const response = await axios + .post( + `https://login.microsoftonline.com/${env.SDK_INTEGRATION_TEST_AAD_TENANT_ID}/oauth2/v2.0/token`, + body, + { + headers: { + "Content-Type": "application/x-www-form-urlencoded", + }, + } + ) + .catch((e) => { + console.log(e); + throw e; + }); const SSOToken = { token: (response.data as any)["access_token"], expire_time: (response.data as any)["expires_in"], diff --git a/packages/sdk/test/e2e/helper.ts b/packages/sdk/test/e2e/helper.ts index 717a8d0848..e019a03512 100644 --- a/packages/sdk/test/e2e/helper.ts +++ b/packages/sdk/test/e2e/helper.ts @@ -1,10 +1,8 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT license. import * as msal from "@azure/msal-node"; -import mockedEnv from "mocked-env"; import { JwtPayload } from "jwt-decode"; import * as dotenv from "dotenv"; -import { AuthenticationConfiguration } from "../../src"; const urljoin = require("url-join"); export function extractIntegrationEnvVariables() { @@ -74,6 +72,7 @@ export async function getAccessToken( return response!.accessToken; } +// eslint-disable-next-line no-secrets/no-secrets /** * process.env.SDK_INTEGRATION_TEST_M365_AAD_CLIENT_ID is the Test AAD app mocking Teams first party app. * This function mocks the sso token get from Teams @@ -106,38 +105,6 @@ export async function getSsoTokenFromTeams(): Promise { ); } -/** - * Mapping environment variables from CI process to current environment for demo. - * Once invoke MockEnvironmentVariables, mock the variables in it with another value, it will take effect immediately. - */ -export function MockEnvironmentVariable(): () => void { - return mockedEnv({ - M365_CLIENT_ID: process.env.SDK_INTEGRATION_TEST_M365_AAD_CLIENT_ID, - M365_CLIENT_SECRET: process.env.SDK_INTEGRATION_TEST_M365_AAD_CLIENT_SECRET, - M365_TENANT_ID: process.env.SDK_INTEGRATION_TEST_AAD_TENANT_ID, - M365_AUTHORITY_HOST: process.env.SDK_INTEGRATION_TEST_AAD_AUTHORITY_HOST, - INITIATE_LOGIN_ENDPOINT: "fake_initiate_login_endpoint", - M365_APPLICATION_ID_URI: `api://localhost:53000/${process.env.SDK_INTEGRATION_TEST_M365_AAD_CLIENT_ID}`, - }); -} - -export function MockAuthenticationConfiguration(): AuthenticationConfiguration { - return { - clientId: process.env.SDK_INTEGRATION_TEST_M365_AAD_CLIENT_ID, - clientSecret: process.env.SDK_INTEGRATION_TEST_M365_AAD_CLIENT_SECRET, - tenantId: process.env.SDK_INTEGRATION_TEST_AAD_TENANT_ID, - authorityHost: process.env.SDK_INTEGRATION_TEST_AAD_AUTHORITY_HOST, - }; -} - -/** - * restore the mapping process environment variables. - * once invoke this method, all mock environment above will be restored. - */ -export function RestoreEnvironmentVariable(restore: () => void): void { - restore(); -} - /** * Convert one-line certificate content to original format * @param content - certificate content of one-line format diff --git a/packages/sdk/test/e2e/node/appCredential.spec.ts b/packages/sdk/test/e2e/node/appCredential.spec.ts index c273c8d711..161431b260 100644 --- a/packages/sdk/test/e2e/node/appCredential.spec.ts +++ b/packages/sdk/test/e2e/node/appCredential.spec.ts @@ -1,13 +1,13 @@ +/* eslint-disable @typescript-eslint/no-non-null-assertion */ // Copyright (c) Microsoft Corporation. // Licensed under the MIT license. import { assert, expect, use as chaiUse } from "chai"; import * as chaiPromises from "chai-as-promised"; -import { AuthenticationConfiguration, AppCredential, AppCredentialAuthConfig } from "../../../src"; +import { AppCredential, AppCredentialAuthConfig } from "../../../src"; import { ErrorCode, ErrorWithCode } from "../../../src/core/errors"; -import jwtDecode from "jwt-decode"; +import { jwtDecode } from "jwt-decode"; import { - MockAuthenticationConfiguration, AADJwtPayLoad, convertCertificateContent, extractIntegrationEnvVariables, @@ -16,83 +16,6 @@ import { chaiUse(chaiPromises); extractIntegrationEnvVariables(); -describe("AppCredential Tests - Node", () => { - const fake_client_secret = "fake_client_secret"; - const defaultGraphScope = ["https://graph.microsoft.com/.default"]; - let authConfig: AuthenticationConfiguration; - - beforeEach(function () { - authConfig = MockAuthenticationConfiguration(); - }); - - it("create AppCredential instance should success with valid configuration", function () { - const credential: any = new AppCredential(authConfig); - - assert.strictEqual(credential.msalClient.config.auth.clientId, authConfig.clientId); - assert.strictEqual( - credential.msalClient.config.auth.authority, - authConfig.authorityHost + "/" + authConfig.tenantId - ); - assert.strictEqual(credential.msalClient.config.auth.clientSecret, authConfig.clientSecret); - }); - - it("getToken should success with .default scope when authority host has tailing slash", async function () { - const credential = new AppCredential({ - ...authConfig, - authorityHost: process.env.SDK_INTEGRATION_TEST_AAD_AUTHORITY_HOST + "/", - }); - const token = await credential.getToken(defaultGraphScope); - - const decodedToken = jwtDecode(token!.token); - assert.strictEqual(decodedToken.aud, "https://graph.microsoft.com"); - assert.strictEqual(decodedToken.appid, authConfig.clientId); - assert.strictEqual(decodedToken.idtyp, "app"); - }); - - it("getToken should success with .default scope for Client Secret", async function () { - const credential = new AppCredential(authConfig); - const token = await credential.getToken(defaultGraphScope); - - const decodedToken = jwtDecode(token!.token); - assert.strictEqual(decodedToken.aud, "https://graph.microsoft.com"); - assert.strictEqual(decodedToken.appid, authConfig.clientId); - assert.strictEqual(decodedToken.idtyp, "app"); - }); - - it("getToken should success with .default scope for Client Certificate", async function () { - const credential = new AppCredential({ - clientId: process.env.SDK_INTEGRATION_TEST_M365_AAD_CLIENT_ID, - certificateContent: convertCertificateContent( - process.env.SDK_INTEGRATION_TEST_M365_AAD_CERTIFICATE_CONTENT! - ), - authorityHost: process.env.SDK_INTEGRATION_TEST_AAD_AUTHORITY_HOST, - tenantId: process.env.SDK_INTEGRATION_TEST_AAD_TENANT_ID, - }); - const token = await credential.getToken(defaultGraphScope); - - const decodedToken = jwtDecode(token!.token); - assert.strictEqual(decodedToken.aud, "https://graph.microsoft.com"); - assert.strictEqual(decodedToken.appid, authConfig.clientId); - assert.strictEqual(decodedToken.idtyp, "app"); - }); - - it("getToken should throw ServiceError with invalid secret", async function () { - const credential = new AppCredential({ - ...authConfig, - clientSecret: fake_client_secret, - }); - - const errorResult = await expect( - credential.getToken(defaultGraphScope) - ).to.eventually.be.rejectedWith(ErrorWithCode); - assert.strictEqual(errorResult.code, ErrorCode.ServiceError); - assert.include( - errorResult.message, - "Get M365 tenant credential failed with error: invalid_client: 7000215" - ); - }); -}); - describe("AppCredential Tests with Auth Config - Node", () => { const fake_client_secret = "fake_client_secret"; const defaultGraphScope = ["https://graph.microsoft.com/.default"]; @@ -179,7 +102,7 @@ describe("AppCredential Tests with Auth Config - Node", () => { assert.strictEqual(errorResult.code, ErrorCode.ServiceError); assert.include( errorResult.message, - "Get M365 tenant credential failed with error: invalid_client: 7000215" + "Get M365 tenant credential failed with error: invalid_client: Error(s): 7000215" ); }); }); diff --git a/packages/sdk/test/e2e/node/basicAuthProvider.spec.ts b/packages/sdk/test/e2e/node/basicAuthProvider.spec.ts index 86a3adea4a..ddfb1b521f 100644 --- a/packages/sdk/test/e2e/node/basicAuthProvider.spec.ts +++ b/packages/sdk/test/e2e/node/basicAuthProvider.spec.ts @@ -46,7 +46,7 @@ describe("BasicAuthProvider Tests - Node", () => { // Assert assert.equal(res.data.url, "/foo"); - const header = res.data.requestHeader!["authorization"] as string; + const header = res.data.requestHeader?.["authorization"] as string; assert.isTrue(header.startsWith("Basic ")); const token = header.split(/\s+/).pop() || ""; const auth = Buffer.from(token, "base64").toString(); diff --git a/packages/sdk/test/e2e/node/msGraphAuthProvider.spec.ts b/packages/sdk/test/e2e/node/msGraphAuthProvider.spec.ts deleted file mode 100644 index 97c6254d68..0000000000 --- a/packages/sdk/test/e2e/node/msGraphAuthProvider.spec.ts +++ /dev/null @@ -1,111 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. - -import { assert, use as chaiUse } from "chai"; -import * as chaiPromises from "chai-as-promised"; -import { - MsGraphAuthProvider, - TeamsFx, - IdentityType, - OnBehalfOfUserCredential, - OnBehalfOfCredentialAuthConfig, - AppCredentialAuthConfig, - AppCredential, -} from "../../../src"; -import { - getSsoTokenFromTeams, - MockEnvironmentVariable, - RestoreEnvironmentVariable, - AADJwtPayLoad, - extractIntegrationEnvVariables, -} from "../helper"; -import jwtDecode from "jwt-decode"; - -chaiUse(chaiPromises); -extractIntegrationEnvVariables(); -let restore: () => void; - -describe("MsGraphAuthProvider Tests - Node", () => { - let ssoToken = ""; - beforeEach(async function () { - restore = MockEnvironmentVariable(); - - ssoToken = await getSsoTokenFromTeams(); - }); - - afterEach(() => { - RestoreEnvironmentVariable(restore); - }); - - it("getAccessToken should success with OnBehalfOfUserCredential", async function () { - const scopes = "User.Read"; - const teamsfx = new TeamsFx().setSsoToken(ssoToken); - const authProvider: MsGraphAuthProvider = new MsGraphAuthProvider(teamsfx, scopes); - const accessToken = await authProvider.getAccessToken(); - - const decodedToken = jwtDecode(accessToken); - assert.strictEqual(decodedToken.aud, "00000003-0000-0000-c000-000000000000"); - assert.strictEqual(decodedToken.appid, process.env.M365_CLIENT_ID); - assert.strictEqual(decodedToken.idtyp, "user"); - assert.strictEqual(decodedToken.upn, process.env.SDK_INTEGRATION_TEST_ACCOUNT_NAME); - assert.isTrue(decodedToken.scp!.indexOf(scopes) >= 0); - }); - - it("getAccessToken should success with AppCredential", async function () { - const scopes = ["https://graph.microsoft.com/.default"]; - const teamsfx = new TeamsFx(IdentityType.App); - const authProvider: MsGraphAuthProvider = new MsGraphAuthProvider(teamsfx, scopes); - const accessToken = await authProvider.getAccessToken(); - - const decodedToken = jwtDecode(accessToken); - assert.strictEqual(decodedToken.aud, "https://graph.microsoft.com"); - assert.strictEqual(decodedToken.appid, process.env.M365_CLIENT_ID); - assert.strictEqual(decodedToken.idtyp, "app"); - }); -}); - -describe("MsGraphAuthProvider Tests with Credential - Node", () => { - let ssoToken = ""; - beforeEach(async function () { - ssoToken = await getSsoTokenFromTeams(); - }); - - it("getAccessToken should success with OnBehalfOfUserCredential", async function () { - const scopes = "User.Read"; - const authConfig: OnBehalfOfCredentialAuthConfig = { - authorityHost: process.env.SDK_INTEGRATION_TEST_AAD_AUTHORITY_HOST!, - clientId: process.env.SDK_INTEGRATION_TEST_M365_AAD_CLIENT_ID!, - tenantId: process.env.SDK_INTEGRATION_TEST_AAD_TENANT_ID!, - clientSecret: process.env.SDK_INTEGRATION_TEST_M365_AAD_CLIENT_SECRET!, - }; - const credential = new OnBehalfOfUserCredential(ssoToken, authConfig); - - const authProvider: MsGraphAuthProvider = new MsGraphAuthProvider(credential, scopes); - const accessToken = await authProvider.getAccessToken(); - - const decodedToken = jwtDecode(accessToken); - assert.strictEqual(decodedToken.aud, "00000003-0000-0000-c000-000000000000"); - assert.strictEqual(decodedToken.appid, process.env.SDK_INTEGRATION_TEST_M365_AAD_CLIENT_ID); - assert.strictEqual(decodedToken.idtyp, "user"); - assert.strictEqual(decodedToken.upn, process.env.SDK_INTEGRATION_TEST_ACCOUNT_NAME); - assert.isTrue(decodedToken.scp!.indexOf(scopes) >= 0); - }); - - it("getAccessToken should success with AppCredential", async function () { - const scopes = ["https://graph.microsoft.com/.default"]; - const authConfig: AppCredentialAuthConfig = { - authorityHost: process.env.SDK_INTEGRATION_TEST_AAD_AUTHORITY_HOST!, - clientId: process.env.SDK_INTEGRATION_TEST_M365_AAD_CLIENT_ID!, - tenantId: process.env.SDK_INTEGRATION_TEST_AAD_TENANT_ID!, - clientSecret: process.env.SDK_INTEGRATION_TEST_M365_AAD_CLIENT_SECRET!, - }; - const credential: AppCredential = new AppCredential(authConfig); - const authProvider: MsGraphAuthProvider = new MsGraphAuthProvider(credential, scopes); - const accessToken = await authProvider.getAccessToken(); - - const decodedToken = jwtDecode(accessToken); - assert.strictEqual(decodedToken.aud, "https://graph.microsoft.com"); - assert.strictEqual(decodedToken.appid, process.env.SDK_INTEGRATION_TEST_M365_AAD_CLIENT_ID); - assert.strictEqual(decodedToken.idtyp, "app"); - }); -}); diff --git a/packages/sdk/test/e2e/node/msGraphClientProvider.spec.ts b/packages/sdk/test/e2e/node/msGraphClientProvider.spec.ts deleted file mode 100644 index 462c6112e7..0000000000 --- a/packages/sdk/test/e2e/node/msGraphClientProvider.spec.ts +++ /dev/null @@ -1,103 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. - -import { assert, expect, use as chaiUse } from "chai"; -import "isomorphic-fetch"; -import * as chaiPromises from "chai-as-promised"; -import { - createMicrosoftGraphClient, - TeamsFx, - IdentityType, - OnBehalfOfUserCredential, - createMicrosoftGraphClientWithCredential, - AppCredential, -} from "../../../src"; -import { - extractIntegrationEnvVariables, - getSsoTokenFromTeams, - MockEnvironmentVariable, - RestoreEnvironmentVariable, -} from "../helper"; -import { - AppCredentialAuthConfig, - OnBehalfOfCredentialAuthConfig, -} from "../../../src/models/configuration"; - -chaiUse(chaiPromises); -extractIntegrationEnvVariables(); -let restore: () => void; - -describe("createMicrosoftGraphClient Tests - Node", () => { - let ssoToken = ""; - beforeEach(async function () { - restore = MockEnvironmentVariable(); - - ssoToken = await getSsoTokenFromTeams(); - }); - - afterEach(() => { - RestoreEnvironmentVariable(restore); - }); - - it("call graph API should success with OnBehalfOfUserCredential", async function () { - const scopes = ["User.Read"]; - const teamsfx = new TeamsFx().setSsoToken(ssoToken); - const graphClient: any = createMicrosoftGraphClient(teamsfx, scopes); - const profile = await graphClient.api("/me").get(); - assert.strictEqual(profile.userPrincipalName, process.env.SDK_INTEGRATION_TEST_ACCOUNT_NAME); - }); - - it("call graph API should failed when AppCredential credential do not have admin permission", async function () { - const scopes = ["https://graph.microsoft.com/.default"]; - const teamsfx = new TeamsFx(IdentityType.App); - const graphClient: any = createMicrosoftGraphClient(teamsfx, scopes); - - // Current test user does not have admin permission so application credential can not perform any request successfully. - const errorResult = await expect(graphClient.api("/users").get()).to.eventually.be.rejectedWith( - Error - ); - assert.include(errorResult.message, "Insufficient privileges to complete the operation."); - }); -}); - -describe("createMicrosoftGraphClientWithCredential Tests - Node", () => { - let ssoToken = ""; - beforeEach(async function () { - ssoToken = await getSsoTokenFromTeams(); - }); - - it("call graph API should success with OnBehalfOfUserCredential", async function () { - const scopes = ["User.Read"]; - const authConfig: OnBehalfOfCredentialAuthConfig = { - authorityHost: process.env.SDK_INTEGRATION_TEST_AAD_AUTHORITY_HOST!, - clientId: process.env.SDK_INTEGRATION_TEST_M365_AAD_CLIENT_ID!, - tenantId: process.env.SDK_INTEGRATION_TEST_AAD_TENANT_ID!, - clientSecret: process.env.SDK_INTEGRATION_TEST_M365_AAD_CLIENT_SECRET!, - }; - - const oboCredential = new OnBehalfOfUserCredential(ssoToken, authConfig); - - const graphClient: any = createMicrosoftGraphClientWithCredential(oboCredential, scopes); - const profile = await graphClient.api("/me").get(); - assert.strictEqual(profile.userPrincipalName, process.env.SDK_INTEGRATION_TEST_ACCOUNT_NAME); - }); - - it("call graph API should failed when AppCredential credential do not have admin permission", async function () { - const scopes = ["https://graph.microsoft.com/.default"]; - const authConfig: AppCredentialAuthConfig = { - authorityHost: process.env.SDK_INTEGRATION_TEST_AAD_AUTHORITY_HOST!, - clientId: process.env.SDK_INTEGRATION_TEST_M365_AAD_CLIENT_ID!, - tenantId: process.env.SDK_INTEGRATION_TEST_AAD_TENANT_ID!, - clientSecret: process.env.SDK_INTEGRATION_TEST_M365_AAD_CLIENT_SECRET!, - }; - - const appCredential = new AppCredential(authConfig); - const graphClient: any = createMicrosoftGraphClientWithCredential(appCredential, scopes); - - // Current test user does not have admin permission so application credential can not perform any request successfully. - const errorResult = await expect(graphClient.api("/users").get()).to.eventually.be.rejectedWith( - Error - ); - assert.include(errorResult.message, "Insufficient privileges to complete the operation."); - }); -}); diff --git a/packages/sdk/test/e2e/node/onBehalfOfUserCredential.spec.ts b/packages/sdk/test/e2e/node/onBehalfOfUserCredential.spec.ts index 2cd1747a47..b3c0e08322 100644 --- a/packages/sdk/test/e2e/node/onBehalfOfUserCredential.spec.ts +++ b/packages/sdk/test/e2e/node/onBehalfOfUserCredential.spec.ts @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/no-non-null-assertion */ // Copyright (c) Microsoft Corporation. // Licensed under the MIT license. @@ -6,7 +7,6 @@ import { assert, expect, use as chaiUse } from "chai"; import * as chaiPromises from "chai-as-promised"; import { - AuthenticationConfiguration, ErrorCode, ErrorWithCode, OnBehalfOfCredentialAuthConfig, @@ -18,122 +18,12 @@ import { convertCertificateContent, extractIntegrationEnvVariables, getSsoTokenFromTeams, - MockAuthenticationConfiguration, - MockEnvironmentVariable, - RestoreEnvironmentVariable, } from "../helper"; chaiUse(chaiPromises); extractIntegrationEnvVariables(); -let restore: () => void; let ssoToken: string; -describe("OnBehalfOfUserCredential Tests - Node", () => { - const defaultScope = "https://graph.microsoft.com/User.Read"; - const expiredSsoToken = - // eslint-disable-next-line no-secrets/no-secrets - "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6Imk2bEdrM0ZaenhSY1ViMkMzbkVRN3N5SEpsWSIsImtpZCI6Imk2bEdrM0ZaenhSY1ViMkMzbkVRN3N5SEpsWSJ9.eyJhdWQiOiJlZjFkYTlkNC1mZjc3LTRjM2UtYTAwNS04NDBjM2Y4MzA3NDUiLCJpc3MiOiJodHRwczovL3N0cy53aW5kb3dzLm5ldC9mYTE1ZDY5Mi1lOWM3LTQ0NjAtYTc0My0yOWYyOTUyMjIyOS8iLCJpYXQiOjE1MzcyMzMxMDYsIm5iZiI6MTUzNzIzMzEwNiwiZXhwIjoxNTM3MjM3MDA2LCJhY3IiOiIxIiwiYWlvIjoiQVhRQWkvOElBQUFBRm0rRS9RVEcrZ0ZuVnhMaldkdzhLKzYxQUdyU091TU1GNmViYU1qN1hPM0libUQzZkdtck95RCtOdlp5R24yVmFUL2tES1h3NE1JaHJnR1ZxNkJuOHdMWG9UMUxrSVorRnpRVmtKUFBMUU9WNEtjWHFTbENWUERTL0RpQ0RnRTIyMlRJbU12V05hRU1hVU9Uc0lHdlRRPT0iLCJhbXIiOlsid2lhIl0sImFwcGlkIjoiNzVkYmU3N2YtMTBhMy00ZTU5LTg1ZmQtOGMxMjc1NDRmMTdjIiwiYXBwaWRhY3IiOiIwIiwiZW1haWwiOiJBYmVMaUBtaWNyb3NvZnQuY29tIiwiZmFtaWx5X25hbWUiOiJMaW5jb2xuIiwiZ2l2ZW5fbmFtZSI6IkFiZSAoTVNGVCkiLCJpZHAiOiJodHRwczovL3N0cy53aW5kb3dzLm5ldC83MmY5ODhiZi04NmYxLTQxYWYtOTFhYi0yZDdjZDAxMjIyNDcvIiwiaXBhZGRyIjoiMjIyLjIyMi4yMjIuMjIiLCJuYW1lIjoiYWJlbGkiLCJvaWQiOiIwMjIyM2I2Yi1hYTFkLTQyZDQtOWVjMC0xYjJiYjkxOTQ0MzgiLCJyaCI6IkkiLCJzY3AiOiJ1c2VyX2ltcGVyc29uYXRpb24iLCJzdWIiOiJsM19yb0lTUVUyMjJiVUxTOXlpMmswWHBxcE9pTXo1SDNaQUNvMUdlWEEiLCJ0aWQiOiJmYTE1ZDY5Mi1lOWM3LTQ0NjAtYTc0My0yOWYyOTU2ZmQ0MjkiLCJ1bmlxdWVfbmFtZSI6ImFiZWxpQG1pY3Jvc29mdC5jb20iLCJ1dGkiOiJGVnNHeFlYSTMwLVR1aWt1dVVvRkFBIiwidmVyIjoiMS4wIn0.D3H6pMUtQnoJAGq6AHd"; - let authConfig: AuthenticationConfiguration; - - before(async () => { - restore = MockEnvironmentVariable(); - ssoToken = await getSsoTokenFromTeams(); - }); - - beforeEach(async () => { - restore = MockEnvironmentVariable(); - authConfig = MockAuthenticationConfiguration(); - }); - - it("getToken should success with valid config", async function () { - const credential = new OnBehalfOfUserCredential(ssoToken, authConfig); - let ssoTokenFromCredential = await credential.getToken([]); - assert.strictEqual(ssoTokenFromCredential!.token, ssoToken); - - ssoTokenFromCredential = await credential.getToken(""); - assert.strictEqual(ssoTokenFromCredential!.token, ssoToken); - }); - - it("get sso token should throw TokenExpiredError when sso token is expired", async function () { - const credential = new OnBehalfOfUserCredential(expiredSsoToken, authConfig); - let err = await expect(credential.getToken([])).to.eventually.be.rejectedWith(ErrorWithCode); - assert.strictEqual(err.code, ErrorCode.TokenExpiredError); - - err = await expect(credential.getToken("")).to.eventually.be.rejectedWith(ErrorWithCode); - assert.strictEqual(err.code, ErrorCode.TokenExpiredError); - }); - - it("getUserInfo should success with valid config", async function () { - const credential = new OnBehalfOfUserCredential(ssoToken, authConfig); - const userInfo = await credential.getUserInfo(); - const tokenObject = parseJwt(ssoToken) as SSOTokenV2Info; - assert.strictEqual(userInfo.preferredUserName, tokenObject.preferred_username); - assert.strictEqual(userInfo.tenantId, tokenObject.tid); - assert.strictEqual(userInfo.objectId, tokenObject.oid); - assert.strictEqual(userInfo.displayName, tokenObject.name); - }); - - it("get graph access token should success with valid config for Client Secret", async function () { - const credential = new OnBehalfOfUserCredential(ssoToken, authConfig); - const graphToken = await credential.getToken(defaultScope); - const tokenObject = parseJwt(graphToken!.token); - const userInfo = await credential.getUserInfo(); - assert.strictEqual(tokenObject.oid, userInfo.objectId); - assert.strictEqual(tokenObject.aud, "https://graph.microsoft.com"); - assert.include(tokenObject.scp, "User.Read"); - }); - - it("get graph access token should success with valid config for Client Certificate", async function () { - const credential = new OnBehalfOfUserCredential(ssoToken, { - clientId: process.env.SDK_INTEGRATION_TEST_M365_AAD_CLIENT_ID, - certificateContent: convertCertificateContent( - process.env.SDK_INTEGRATION_TEST_M365_AAD_CERTIFICATE_CONTENT! - ), - authorityHost: process.env.SDK_INTEGRATION_TEST_AAD_AUTHORITY_HOST, - tenantId: process.env.SDK_INTEGRATION_TEST_AAD_TENANT_ID, - }); - const graphToken = await credential.getToken(defaultScope); - - const tokenObject = parseJwt(graphToken!.token); - const userInfo = await credential.getUserInfo(); - assert.strictEqual(tokenObject.oid, userInfo.objectId); - assert.strictEqual(tokenObject.aud, "https://graph.microsoft.com"); - assert.include(tokenObject.scp, "User.Read"); - }); - - it("get graph access token should success when authority host has tailing slash", async function () { - const credential = new OnBehalfOfUserCredential(ssoToken, { - ...authConfig, - authorityHost: process.env.SDK_INTEGRATION_TEST_AAD_AUTHORITY_HOST + "/", - }); - const graphToken = await credential.getToken(defaultScope); - const tokenObject = parseJwt(graphToken!.token); - const userInfo = await credential.getUserInfo(); - assert.strictEqual(tokenObject.oid, userInfo.objectId); - assert.strictEqual(tokenObject.aud, "https://graph.microsoft.com"); - assert.include(tokenObject.scp, "User.Read"); - }); - - it("get graph access token should throw UiRequiredError without permission", async function () { - const credential = new OnBehalfOfUserCredential(ssoToken, authConfig); - await expect(credential.getToken("https://graph.microsoft.com/Calendars.Read")) - .to.eventually.be.rejectedWith(ErrorWithCode) - .and.property("code", ErrorCode.UiRequiredError); - }); - - it("get graph access token should throw TokenExpiredError when sso token is expired", async function () { - const credential = new OnBehalfOfUserCredential(expiredSsoToken, authConfig); - const err = await expect(credential.getToken(defaultScope)).to.eventually.be.rejectedWith( - ErrorWithCode - ); - - assert.strictEqual(err.code, ErrorCode.TokenExpiredError); - }); - - afterEach(() => { - RestoreEnvironmentVariable(restore); - }); -}); describe("OnBehalfOfUserCredential Tests with obo auth config - Node", () => { const defaultScope = "https://graph.microsoft.com/User.Read"; @@ -272,8 +162,4 @@ describe("OnBehalfOfUserCredential Tests with obo auth config - Node", () => { assert.strictEqual(err.code, ErrorCode.TokenExpiredError); }); - - afterEach(() => { - RestoreEnvironmentVariable(restore); - }); }); diff --git a/packages/sdk/test/e2e/node/teamsBotSsoPrompt.spec.ts b/packages/sdk/test/e2e/node/teamsBotSsoPrompt.spec.ts index aaff3a74b7..73aa05bca0 100644 --- a/packages/sdk/test/e2e/node/teamsBotSsoPrompt.spec.ts +++ b/packages/sdk/test/e2e/node/teamsBotSsoPrompt.spec.ts @@ -21,251 +21,17 @@ import { TeamsBotSsoPrompt, TeamsBotSsoPromptTokenResponse, TeamsBotSsoPromptSettings, - TeamsFx, OnBehalfOfCredentialAuthConfig, } from "../../../src"; import { assert, use as chaiUse } from "chai"; import * as chaiPromises from "chai-as-promised"; -import { - extractIntegrationEnvVariables, - getSsoTokenFromTeams, - MockEnvironmentVariable, - RestoreEnvironmentVariable, -} from "../helper"; +import { extractIntegrationEnvVariables, getSsoTokenFromTeams } from "../helper"; import { parseJwt } from "../../../src/util/utils"; import * as sinon from "sinon"; import { TeamsInfo } from "botbuilder"; chaiUse(chaiPromises); extractIntegrationEnvVariables(); -let restore: () => void; - -describe("TeamsBotSsoPrompt Tests - Node", () => { - const initiateLoginEndpoint = "fake_initiate_login_endpoint"; - const userPrincipalName = "fake_userPrincipalName"; - - const TeamsBotSsoPromptId = "TEAMS_BOT_SSO_PROMPT"; - const requiredScopes: string[] = ["User.Read"]; - const invokeResponseActivityType = "invokeResponse"; - const id = "fake_id"; - - let ssoToken: string; - enum SsoLogInResult { - Success = "Success", - Fail = "Fail", - } - const sandbox = sinon.createSandbox(); - - before(async function () { - restore = MockEnvironmentVariable(); - ssoToken = await getSsoTokenFromTeams(); - sandbox.stub(TeamsInfo, "getMember").callsFake(async () => { - const account: TeamsChannelAccount = { - id: "fake_id", - name: "fake_name", - userPrincipalName: userPrincipalName, - }; - return account; - }); - }); - - after(function () { - RestoreEnvironmentVariable(restore); - sandbox.restore(); - }); - - it("teams bot sso prompt should not be able to sign user in and get exchange tokens when not consent", async function () { - this.timeout(5000); - - const notConsentScopes = ["Calendars.Read"]; - const adapter: TestAdapter = await initializeTestEnv({ scopes: notConsentScopes }); - - await adapter - .send("Hello") - .assertReply((activity) => { - // Assert bot send out OAuthCard - assertTeamsSsoOauthCardActivity(activity, notConsentScopes); - - // Mock Teams sends signin/tokenExchange message with SSO token back to the bot - mockTeamsSendsTokenExchangeInvokeActivityWithSsoToken(adapter, activity); - }) - .assertReply((activity) => { - // User has not consent. Assert bot send out 412 - assert.strictEqual(activity.type, invokeResponseActivityType); - assert.strictEqual(activity.value.status, StatusCodes.PRECONDITION_FAILED); - assert.strictEqual( - activity.value.body.failureDetail, - "The bot is unable to exchange token. Ask for user consent." - ); - }); - }); - - it("teams bot sso prompt should be able to sign user in and get exchange tokens when consent", async function () { - this.timeout(5000); - - const adapter: TestAdapter = await initializeTestEnv({}); - - await adapter - .send("Hello") - .assertReply((activity) => { - // Assert bot send out OAuthCard - assertTeamsSsoOauthCardActivity(activity); - - // Mock Teams sends signin/tokenExchange message with SSO token back to the bot - mockTeamsSendsTokenExchangeInvokeActivityWithSsoToken(adapter, activity); - }) - .assertReply((activity) => { - // Assert bot send out invoke response status 200 to Teams to signal verifivation invoke has been received - assert.strictEqual(activity.type, invokeResponseActivityType); - assert.strictEqual(activity.value.status, StatusCodes.OK); - }) - .assertReply(SsoLogInResult.Success) - .assertReply((activity) => { - // Assert prompt result has exchanged token and sso token. - const result = JSON.parse(activity.text as string) as TeamsBotSsoPromptTokenResponse; - assert.strictEqual(result.ssoToken, ssoToken); - const accessTokenObj = parseJwt(result.token); - const ssoTokenObj = parseJwt(result.ssoToken); - assert.strictEqual(accessTokenObj.oid, ssoTokenObj.oid); - }); - }); - - it("teams bot sso prompt should not end on invalid message when endOnInvalidMessage set to false", async function () { - const adapter: TestAdapter = await initializeTestEnv({ endOnInvalidMessage: false }); - - await adapter - .send("Hello") - .assertReply((activity) => { - // Assert bot send out OAuthCard - assertTeamsSsoOauthCardActivity(activity); - - // Mock User send invalid message, wchich should be ignored. - const messageActivity = createReply(ActivityTypes.Message, activity); - messageActivity.text = "user sends invalid message during auth flow"; - adapter.send(messageActivity); - - // Mock Teams sends signin/tokenExchange message with SSO token back to the bot - mockTeamsSendsTokenExchangeInvokeActivityWithSsoToken(adapter, activity); - }) - .assertReply((activity) => { - // Assert bot send out invoke response status 200 to Teams to signal token response request invoke has been received - assert.strictEqual(activity.type, invokeResponseActivityType); - assert.strictEqual(activity.value.status, StatusCodes.OK); - assert.strictEqual(activity.value.body.id, id); - }) - .assertReply(SsoLogInResult.Success) - .assertReply((activity) => { - // Assert prompt result has exchanged token and sso token. - const result = JSON.parse(activity.text as string) as TeamsBotSsoPromptTokenResponse; - assert.strictEqual(result.ssoToken, ssoToken); - const accessTokenObj = parseJwt(result.token); - const ssoTokenObj = parseJwt(result.ssoToken); - assert.strictEqual(accessTokenObj.oid, ssoTokenObj.oid); - }); - }); - - function createReply(type: ActivityTypes, activity: Partial): Partial { - return { - type: type, - from: { id: activity.recipient!.id, name: activity.recipient!.name }, - recipient: { id: activity.from!.id, name: activity.from!.name }, - replyToId: activity.id, - serviceUrl: activity.serviceUrl, - channelId: activity.channelId, - conversation: { - isGroup: activity.conversation!.isGroup, - id: activity.conversation!.id, - name: activity.conversation!.name, - conversationType: "personal", - tenantId: process.env.SDK_INTEGRATION_TEST_AAD_TENANT_ID, - }, - }; - } - - function assertTeamsSsoOauthCardActivity( - activity: Partial, - scopes: string[] = ["User.Read"] - ): void { - assert.isArray(activity.attachments); - assert.strictEqual(activity.attachments?.length, 1); - assert.strictEqual(activity.attachments![0].contentType, CardFactory.contentTypes.oauthCard); - assert.strictEqual(activity.inputHint, InputHints.AcceptingInput); - - assert.strictEqual(activity.attachments![0].content.buttons[0].type, ActionTypes.Signin); - assert.strictEqual(activity.attachments![0].content.buttons[0].title, "Teams SSO Sign In"); - assert.strictEqual( - activity.attachments![0].content.buttons[0].value, - `${initiateLoginEndpoint}?scope=${encodeURI(scopes.join(" "))}&clientId=${ - process.env.SDK_INTEGRATION_TEST_M365_AAD_CLIENT_ID - }&tenantId=${process.env.SDK_INTEGRATION_TEST_AAD_TENANT_ID}&loginHint=${userPrincipalName}` - ); - } - - function mockTeamsSendsTokenExchangeInvokeActivityWithSsoToken( - adapter: TestAdapter, - activity: Partial - ): void { - const invokeActivity: Partial = createReply(ActivityTypes.Invoke, activity); - invokeActivity.name = tokenExchangeOperationName; - invokeActivity.value = { - id: id, - token: ssoToken, - }; - adapter.send(invokeActivity); - } - - /** - * Initialize dialogs, adds teamsBotSsoPrompt in dialog set and initialize testAdapter for test case. - * @param timeout_value positive number set to teamsSsoPromptSettings.timeout property - * @param endOnInvalidMessage boolean value set to teamsSsoPromptSettings.endOnInvalidMessage property - * @param channelId value set to dialog context activity channel. Defaults to `Channels.MSteams`. - */ - async function initializeTestEnv(param: InitializeParams): Promise { - // Create new ConversationState with MemoryStorage - const convoState: ConversationState = new ConversationState(new MemoryStorage()); - - // Create a DialogState property, DialogSet and TeamsBotSsoPrompt - const dialogState: StatePropertyAccessor = - convoState.createProperty("dialogState"); - const dialogs: DialogSet = new DialogSet(dialogState); - - let botScopes = param.scopes; - if (!botScopes) { - botScopes = requiredScopes; - } - - const settings: TeamsBotSsoPromptSettings = { - scopes: botScopes, - timeout: param.timeout_value, - endOnInvalidMessage: param.endOnInvalidMessage, - }; - - const teamsfx = new TeamsFx(); - dialogs.add(new TeamsBotSsoPrompt(teamsfx, TeamsBotSsoPromptId, settings)); - - // Initialize TestAdapter. - const adapter: TestAdapter = new TestAdapter(async (turnContext) => { - const dc = await dialogs.createContext(turnContext); - dc.context.activity.channelId = - param.channelId === undefined ? Channels.Msteams : param.channelId; - - const results = await dc.continueDialog(); - if (results.status === DialogTurnStatus.empty) { - await dc.beginDialog(TeamsBotSsoPromptId); - } else if (results.status === DialogTurnStatus.complete) { - if (results.result?.token) { - await turnContext.sendActivity(SsoLogInResult.Success); - const resultStr = JSON.stringify(results.result); - await turnContext.sendActivity(resultStr); - } else { - await turnContext.sendActivity(SsoLogInResult.Fail); - } - } - await convoState.saveChanges(turnContext); - }); - return adapter; - } -}); describe("TeamsBotSsoPrompt Tests with Auth Config - Node", () => { const initiateLoginEndpoint = "fake_initiate_login_endpoint"; diff --git a/packages/sdk/test/unit/browser/msGraphAuthProvider.browser.spec.ts b/packages/sdk/test/unit/browser/msGraphAuthProvider.browser.spec.ts deleted file mode 100644 index 4634930d96..0000000000 --- a/packages/sdk/test/unit/browser/msGraphAuthProvider.browser.spec.ts +++ /dev/null @@ -1,90 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. - -import { AccessToken } from "@azure/core-auth"; -import { assert, expect, use as chaiUse } from "chai"; -import * as chaiPromises from "chai-as-promised"; -import { - TeamsFx, - IdentityType, - MsGraphAuthProvider, - TeamsUserCredential, - ErrorWithCode, - ErrorCode, -} from "../../../src/index.browser"; -import * as sinon from "sinon"; - -chaiUse(chaiPromises); -describe("MsGraphAuthProvider Tests - Browser", () => { - const clientId = "fake_client_id"; - const loginUrl = "fake_login_url"; - const authEndpoint = "fake_auth_endpoint"; - const scopes = "fake_scope"; - const emptyScope = ""; - const defaultScope = "https://graph.microsoft.com/.default"; - const accessToken = "fake_access_token"; - const teamsfx = new TeamsFx(IdentityType.User, { - initiateLoginEndpoint: loginUrl, - simpleAuthEndpoint: authEndpoint, - clientId: clientId, - }); - - it("create MsGraphAuthProvider instance should throw InvalidParameter error with invalid scope", function () { - const invalidScopes: any = [10, 20]; - expect(() => { - new MsGraphAuthProvider(teamsfx, invalidScopes); - }) - .to.throw(ErrorWithCode, "The type of scopes is not valid, it must be string or string array") - .with.property("code", ErrorCode.InvalidParameter); - }); - - it("create MsGraphAuthProvider instance should success with given scopes", async function () { - const authProvider: any = new MsGraphAuthProvider(teamsfx, scopes); - assert.strictEqual(authProvider.scopes, scopes); - }); - - it("create MsGraphAuthProvider instance should success with empty scope", async function () { - const authProvider: any = new MsGraphAuthProvider(teamsfx, emptyScope); - assert.strictEqual(authProvider.scopes, defaultScope); - }); - - it("create MsGraphAuthProvider instance should success without providing scope", async function () { - const authProvider: any = new MsGraphAuthProvider(teamsfx); - assert.strictEqual(authProvider.scopes, defaultScope); - }); - - it("getAccessToken should success with valid config", async function () { - sinon - .stub(TeamsUserCredential.prototype, "getToken") - .callsFake((): Promise => { - const token: AccessToken = { - token: accessToken, - expiresOnTimestamp: Date.now(), - }; - return new Promise((resolve) => { - resolve(token); - }); - }); - const authProvider = new MsGraphAuthProvider(teamsfx, scopes); - const token = await authProvider.getAccessToken(); - assert.strictEqual(token, accessToken); - sinon.restore(); - }); - - it("getAccessToken should throw UiRequiredError with unconsent scope", async function () { - sinon - .stub(TeamsUserCredential.prototype, "getToken") - .callsFake((): Promise => { - throw new ErrorWithCode( - "Failed to get access token from authentication server, please login first.", - ErrorCode.UiRequiredError - ); - }); - const unconsentScopes = "unconsent_scope"; - const authProvider = new MsGraphAuthProvider(teamsfx, unconsentScopes); - await expect(authProvider.getAccessToken()) - .to.eventually.be.rejectedWith(ErrorWithCode) - .and.property("code", ErrorCode.UiRequiredError); - sinon.restore(); - }); -}); diff --git a/packages/sdk/test/unit/browser/msGraphClientProvider.browser.spec.ts b/packages/sdk/test/unit/browser/msGraphClientProvider.browser.spec.ts deleted file mode 100644 index 3247fa2c00..0000000000 --- a/packages/sdk/test/unit/browser/msGraphClientProvider.browser.spec.ts +++ /dev/null @@ -1,94 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. - -import { assert, expect, use as chaiUse } from "chai"; -import * as chaiPromises from "chai-as-promised"; -import { - TeamsUserCredential, - createMicrosoftGraphClient, - ErrorCode, - ErrorWithCode, - TeamsFx, - IdentityType, - createMicrosoftGraphClientWithCredential, -} from "../../../src/index.browser"; -import { TeamsUserCredentialAuthConfig } from "../../../src/models/configuration"; - -chaiUse(chaiPromises); -describe("MsGraphClientProvider Tests - Browser", () => { - const clientId = "fake_client_id"; - const loginUrl = "fake_login_url"; - const authEndpoint = "fake_auth_endpoint"; - const scopes = "fake_scope"; - const emptyScope = ""; - const defaultScope = "https://graph.microsoft.com/.default"; - const teamsfx = new TeamsFx(IdentityType.User, { - initiateLoginEndpoint: loginUrl, - simpleAuthEndpoint: authEndpoint, - clientId: clientId, - }); - - it("createMicrosoftGraphClient should throw InvalidParameter error with invalid scope", function () { - const invalidScopes: any = [10, 20]; - expect(() => { - createMicrosoftGraphClient(teamsfx, invalidScopes); - }) - .to.throw(ErrorWithCode, "The type of scopes is not valid, it must be string or string array") - .with.property("code", ErrorCode.InvalidParameter); - }); - - it("createMicrosoftGraphClient should success with given scopes", function () { - const graphClient: any = createMicrosoftGraphClient(teamsfx, scopes); - assert.strictEqual(graphClient.config.authProvider.scopes, scopes); - }); - - it("createMicrosoftGraphClient should success with empty scope", function () { - const graphClient: any = createMicrosoftGraphClient(teamsfx, emptyScope); - assert.strictEqual(graphClient.config.authProvider.scopes, defaultScope); - }); - - it("createMicrosoftGraphClient should success without providing scope", function () { - const graphClient: any = createMicrosoftGraphClient(teamsfx); - assert.strictEqual(graphClient.config.authProvider.scopes, defaultScope); - }); -}); - -describe("MsGraphClientProvider Tests for createMicrosoftGraphClientWithCredential - Browser", () => { - const clientId = "fake_client_id"; - const loginUrl = "fake_login_url"; - const scopes = "fake_scope"; - const emptyScope = ""; - const defaultScope = "https://graph.microsoft.com/.default"; - const authConfig: TeamsUserCredentialAuthConfig = { - clientId: clientId, - initiateLoginEndpoint: loginUrl, - }; - - it("createMicrosoftGraphClientWithCredential should throw InvalidParameter error with invalid scope", function () { - const invalidScopes: any = [10, 20]; - expect(() => { - const credential = new TeamsUserCredential(authConfig); - createMicrosoftGraphClientWithCredential(credential, invalidScopes); - }) - .to.throw(ErrorWithCode, "The type of scopes is not valid, it must be string or string array") - .with.property("code", ErrorCode.InvalidParameter); - }); - - it("createMicrosoftGraphClient should success with given scopes", function () { - const credential = new TeamsUserCredential(authConfig); - const graphClient: any = createMicrosoftGraphClientWithCredential(credential, scopes); - assert.strictEqual(graphClient.config.authProvider.scopes, scopes); - }); - - it("createMicrosoftGraphClient should success with empty scope", function () { - const credential = new TeamsUserCredential(authConfig); - const graphClient: any = createMicrosoftGraphClientWithCredential(credential, emptyScope); - assert.strictEqual(graphClient.config.authProvider.scopes, defaultScope); - }); - - it("createMicrosoftGraphClient should success without providing scope", function () { - const credential = new TeamsUserCredential(authConfig); - const graphClient: any = createMicrosoftGraphClientWithCredential(credential); - assert.strictEqual(graphClient.config.authProvider.scopes, defaultScope); - }); -}); diff --git a/packages/sdk/test/unit/browser/teamsFx.spec.ts b/packages/sdk/test/unit/browser/teamsFx.spec.ts deleted file mode 100644 index 68ca21f86b..0000000000 --- a/packages/sdk/test/unit/browser/teamsFx.spec.ts +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. - -import { AccessToken, GetTokenOptions, TokenCredential } from "@azure/identity"; -import * as sinon from "sinon"; -import { TeamsFx } from "../../../src/index.browser"; - -describe("TeamsFx Tests - Browser", () => { - afterEach(() => { - sinon.restore(); - }); - - it("should not have breaking change for the interface", () => { - const teamsfx = new TeamsFx(); - const scope = ["User.Read"]; - - // Breaking changes in TeamsFx class for below interfaces may break graph toolkit teamsfx auth provider - // Please contact rentu@microsoft.com before you making breaking changes for this class - sinon - .stub(TeamsFx.prototype, "login") - .callsFake(async (scopes: string | string[]): Promise => {}); - - sinon.stub(TeamsFx.prototype, "getCredential").callsFake((): TokenCredential => { - return { - getToken: async ( - scopes: string | string[], - options?: GetTokenOptions - ): Promise => { - return null; - }, - }; - }); - teamsfx.getCredential().getToken(scope); - teamsfx.login(scope); - }); -}); diff --git a/packages/sdk/test/unit/browser/teamsUserCredential.browser.spec.ts b/packages/sdk/test/unit/browser/teamsUserCredential.browser.spec.ts index 18f14b9d99..edc14bee06 100644 --- a/packages/sdk/test/unit/browser/teamsUserCredential.browser.spec.ts +++ b/packages/sdk/test/unit/browser/teamsUserCredential.browser.spec.ts @@ -4,7 +4,7 @@ import { AccessToken } from "@azure/core-auth"; import { assert, expect, use as chaiUse } from "chai"; import * as chaiPromises from "chai-as-promised"; -import { TeamsUserCredential } from "../../../src/index.browser"; +import { TeamsUserCredential, TeamsUserCredentialAuthConfig } from "../../../src/index.browser"; import * as sinon from "sinon"; import { ErrorCode, ErrorWithCode } from "../../../src/core/errors"; import { AccountInfo, AuthenticationResult, PublicClientApplication } from "@azure/msal-browser"; @@ -211,7 +211,7 @@ describe("TeamsUserCredential Tests - Browser", () => { expect(() => { new TeamsUserCredential({ initiateLoginEndpoint: loginUrl, - }); + } as TeamsUserCredentialAuthConfig); }) .to.throw(ErrorWithCode, "clientId in configuration is invalid: undefined.") .with.property("code", ErrorCode.InvalidConfiguration); diff --git a/packages/sdk/test/unit/node/appCredential.spec.ts b/packages/sdk/test/unit/node/appCredential.spec.ts index 6ff07e1642..5e27dc8800 100644 --- a/packages/sdk/test/unit/node/appCredential.spec.ts +++ b/packages/sdk/test/unit/node/appCredential.spec.ts @@ -4,7 +4,7 @@ import { assert, expect, use as chaiUse } from "chai"; import * as chaiPromises from "chai-as-promised"; import * as sinon from "sinon"; -import { AppCredential } from "../../../src"; +import { AppCredential, AppCredentialAuthConfig } from "../../../src"; import { ErrorCode, ErrorWithCode } from "../../../src/core/errors"; import { AuthenticationResult, ConfidentialClientApplication } from "@azure/msal-node"; @@ -62,8 +62,8 @@ fakeCert assert.strictEqual(credential.msalClient.config.auth.clientId, clientId); assert.strictEqual(credential.msalClient.config.auth.authority, authorityHost + "/" + tenantId); assert.strictEqual( - credential.msalClient.config.auth.clientCertificate.thumbprint, - "06BA994A93FF2138DC51E669EB284ABAB8112153" // thumbprint is calculated from certificate content "fakeCert" + credential.msalClient.config.auth.clientCertificate.thumbprintSha256, + "90AF5A3B906DCC32226BCCD6D369165CFB9F1E0FE123F0D18B7CC48261995A6C" // thumbprint is calculated from certificate content "fakeCert" ); assert.strictEqual(credential.msalClient.config.auth.clientSecret, ""); }); @@ -75,7 +75,7 @@ fakeCert certificateContent: certificateContent, authorityHost: authorityHost, tenantId: tenantId, - }); + } as unknown as AppCredentialAuthConfig); // certificateContent has higher priority than clientSecret assert.exists(credential.msalClient); @@ -84,7 +84,7 @@ fakeCert it("create AppCredential instance should throw InvalidConfiguration when configuration is not valid", function () { expect(() => { - new AppCredential({}); + new AppCredential({} as unknown as AppCredentialAuthConfig); }) .to.throw( ErrorWithCode, @@ -93,7 +93,7 @@ fakeCert .with.property("code", ErrorCode.InvalidConfiguration); expect(() => { - new AppCredential({ clientId: clientId }); + new AppCredential({ clientId: clientId } as unknown as AppCredentialAuthConfig); }) .to.throw( ErrorWithCode, @@ -102,7 +102,7 @@ fakeCert .with.property("code", ErrorCode.InvalidConfiguration); expect(() => { - new AppCredential({ tenantId: tenantId }); + new AppCredential({ tenantId: tenantId } as unknown as AppCredentialAuthConfig); }) .to.throw( ErrorWithCode, @@ -111,7 +111,7 @@ fakeCert .with.property("code", ErrorCode.InvalidConfiguration); expect(() => { - new AppCredential({ authorityHost: authorityHost }); + new AppCredential({ authorityHost: authorityHost } as unknown as AppCredentialAuthConfig); }) .to.throw( ErrorWithCode, diff --git a/packages/sdk/test/unit/node/bot/teamsBotSsoPrompt.spec.ts b/packages/sdk/test/unit/node/bot/teamsBotSsoPrompt.spec.ts index 937da03de5..81d30e532a 100644 --- a/packages/sdk/test/unit/node/bot/teamsBotSsoPrompt.spec.ts +++ b/packages/sdk/test/unit/node/bot/teamsBotSsoPrompt.spec.ts @@ -22,22 +22,19 @@ import { TeamsBotSsoPrompt, TeamsBotSsoPromptTokenResponse, OnBehalfOfUserCredential, + OnBehalfOfCredentialAuthConfig, ErrorWithCode, ErrorCode, TeamsBotSsoPromptSettings, - TeamsFx, - IdentityType, } from "../../../../src"; import { assert, expect, use as chaiUse } from "chai"; import * as chaiPromises from "chai-as-promised"; import * as sinon from "sinon"; -import mockedEnv from "mocked-env"; import { AccessToken } from "@azure/identity"; import { promisify } from "util"; import { TeamsInfo } from "botbuilder"; chaiUse(chaiPromises); -let mockedEnvRestore: () => void; describe("TeamsBotSsoPrompt Tests - Node", () => { const sleep = promisify(setTimeout); @@ -56,6 +53,13 @@ describe("TeamsBotSsoPrompt Tests - Node", () => { const id = "fake_id"; const exchangeToken = "fake_exchange_token"; + const OnBehalfOfCredentialAuthConfig = { + authorityHost: authorityHost, + clientId: clientId, + clientSecret: clientSecret, + tenantId: tenantId, + }; + /** * { * "aud": "test_audience", @@ -89,14 +93,6 @@ describe("TeamsBotSsoPrompt Tests - Node", () => { const sandbox = sinon.createSandbox(); beforeEach(function () { - mockedEnvRestore = mockedEnv({ - INITIATE_LOGIN_ENDPOINT: initiateLoginEndpoint, - M365_CLIENT_ID: clientId, - M365_CLIENT_SECRET: clientSecret, - M365_TENANT_ID: tenantId, - M365_AUTHORITY_HOST: authorityHost, - }); - // Mock onBehalfOfUserCredential implementation const onBehalfOfUserCredentialStub_GetToken = sandbox.stub( OnBehalfOfUserCredential.prototype, @@ -129,7 +125,6 @@ describe("TeamsBotSsoPrompt Tests - Node", () => { afterEach(function () { sandbox.restore(); - mockedEnvRestore(); }); it("teams bot sso prompt should be able to sign user in and get exchange tokens when consent", async function () { @@ -357,7 +352,7 @@ describe("TeamsBotSsoPrompt Tests - Node", () => { await adapter.send("Hello").assertReply((activity) => { // Assert bot send out OAuthCard assert.strictEqual( - activity.attachments![0].content.buttons[0].value, + activity.attachments?.[0].content.buttons[0].value, `${initiateLoginEndpoint}?scope=${encodeURI( requiredScopes.join(" ") )}&clientId=${clientId}&tenantId=${tenantId}&loginHint=` @@ -372,37 +367,33 @@ describe("TeamsBotSsoPrompt Tests - Node", () => { }; expect(() => { - new TeamsBotSsoPrompt(new TeamsFx(), TeamsBotSsoPromptId, settings); + new TeamsBotSsoPrompt( + OnBehalfOfCredentialAuthConfig, + initiateLoginEndpoint, + TeamsBotSsoPromptId, + settings + ); }) .to.throw(ErrorWithCode, "The type of scopes is not valid, it must be string or string array") .with.property("code", ErrorCode.InvalidParameter); }); - it("create TeamsBotSsoPrompt instance should throw IdentityTypeNotSupported error with invalid identity type", async function () { - const settings: any = { - scopes: requiredScopes, - }; - - expect(() => { - new TeamsBotSsoPrompt(new TeamsFx(IdentityType.App), TeamsBotSsoPromptId, settings); - }) - .to.throw(ErrorWithCode, "Application identity is not supported in TeamsBotSsoPrompt") - .with.property("code", ErrorCode.IdentityTypeNotSupported); - }); - it("create TeamsBotSsoPrompt instance should throw InvalidConfiguration error with empty configuration", async function () { - mockedEnvRestore(); - mockedEnvRestore = mockedEnv({}); const settings: any = { scopes: requiredScopes, }; expect(() => { - new TeamsBotSsoPrompt(new TeamsFx(), TeamsBotSsoPromptId, settings); + new TeamsBotSsoPrompt( + {} as OnBehalfOfCredentialAuthConfig, + "", + TeamsBotSsoPromptId, + settings + ); }) .to.throw( ErrorWithCode, - "initiateLoginEndpoint, clientId, tenantId in configuration is invalid: undefined." + "clientId, clientSecret or certificateContent, tenantId, authorityHost in configuration is invalid: undefined." ) .with.property("code", ErrorCode.InvalidConfiguration); }); @@ -410,15 +401,15 @@ describe("TeamsBotSsoPrompt Tests - Node", () => { function createReply(type: ActivityTypes, activity: Partial): Partial { return { type: type, - from: { id: activity.recipient!.id, name: activity.recipient!.name }, - recipient: { id: activity.from!.id, name: activity.from!.name }, + from: { id: activity.recipient?.id as string, name: activity.recipient?.name as string }, + recipient: { id: activity.from?.id as string, name: activity.from?.name as string }, replyToId: activity.id, serviceUrl: activity.serviceUrl, channelId: activity.channelId, conversation: { - isGroup: activity.conversation!.isGroup, - id: activity.conversation!.id, - name: activity.conversation!.name, + isGroup: activity.conversation?.isGroup as boolean, + id: activity.conversation?.id as string, + name: activity.conversation?.name as string, conversationType: "personal", tenantId: tenantId, }, @@ -428,14 +419,14 @@ describe("TeamsBotSsoPrompt Tests - Node", () => { function assertTeamsSsoOauthCardActivity(activity: Partial): void { assert.isArray(activity.attachments); assert.strictEqual(activity.attachments?.length, 1); - assert.strictEqual(activity.attachments![0].contentType, CardFactory.contentTypes.oauthCard); + assert.strictEqual(activity.attachments?.[0].contentType, CardFactory.contentTypes.oauthCard); assert.strictEqual(activity.inputHint, InputHints.AcceptingInput); - assert.strictEqual(activity.attachments![0].content.buttons[0].type, ActionTypes.Signin); - assert.strictEqual(activity.attachments![0].content.buttons[0].title, "Teams SSO Sign In"); + assert.strictEqual(activity.attachments?.[0].content.buttons[0].type, ActionTypes.Signin); + assert.strictEqual(activity.attachments?.[0].content.buttons[0].title, "Teams SSO Sign In"); assert.strictEqual( - activity.attachments![0].content.buttons[0].value, + activity.attachments?.[0].content.buttons[0].value, `${initiateLoginEndpoint}?scope=${encodeURI( requiredScopes.join(" ") )}&clientId=${clientId}&tenantId=${tenantId}&loginHint=${userPrincipalName}` @@ -479,8 +470,14 @@ describe("TeamsBotSsoPrompt Tests - Node", () => { endOnInvalidMessage: endOnInvalidMessage, }; - const teamsfx = new TeamsFx(); - dialogs.add(new TeamsBotSsoPrompt(teamsfx, TeamsBotSsoPromptId, settings)); + dialogs.add( + new TeamsBotSsoPrompt( + OnBehalfOfCredentialAuthConfig, + initiateLoginEndpoint, + TeamsBotSsoPromptId, + settings + ) + ); // Initialize TestAdapter. const adapter: TestAdapter = new TestAdapter(async (turnContext) => { diff --git a/packages/sdk/test/unit/node/conversation/cardAction.spec.ts b/packages/sdk/test/unit/node/conversation/cardAction.spec.ts deleted file mode 100644 index 9e2730674c..0000000000 --- a/packages/sdk/test/unit/node/conversation/cardAction.spec.ts +++ /dev/null @@ -1,155 +0,0 @@ -import { assert } from "chai"; -import { BotFrameworkAdapter, ConversationReference, StatusCodes, TurnContext } from "botbuilder"; -import * as sinon from "sinon"; -import { CardActionBot } from "../../../../src/conversation/cardAction"; -import { CardActionMiddleware } from "../../../../src/conversation/middlewares/cardActionMiddleware"; -import { - MockActionInvokeContext, - MockCardActionHandler, - MockCardActionHandlerWithErrorResponse, -} from "./testUtils"; -import { InvokeResponseErrorCode } from "../../../../src/conversation/interface"; - -describe("Card Action Handler - Node", () => { - it("handler should send text message response correctly", async () => { - const doStuffAction = new MockCardActionHandler("doStuff", "sample-response"); - const testContext = new MockActionInvokeContext("doStuff"); - const middleware = new CardActionMiddleware([doStuffAction]); - await middleware.onTurn(testContext as any, async () => {}); - - assert.isTrue(doStuffAction.isInvoked); - assert.strictEqual(testContext.content, "sample-response"); - }); - - it("handler should send adaptive card response correctly", async () => { - const responseCard = { - version: "1.0.0", - type: "AdaptiveCard", - body: [ - { - type: "TextBlock", - text: `Hello World!`, - }, - ], - }; - - const doStuffAction = new MockCardActionHandler("doStuff", responseCard); - const testContext = new MockActionInvokeContext("doStuff"); - const middleware = new CardActionMiddleware([doStuffAction]); - await middleware.onTurn(testContext as any, async () => {}); - - assert.isTrue(doStuffAction.isInvoked); - assert.deepEqual(testContext.content, responseCard); - }); - - it("handler should send user error response correctly", async () => { - const errorMessage = "Invalid request"; - const doStuffAction = new MockCardActionHandlerWithErrorResponse( - "doStuff", - InvokeResponseErrorCode.BadRequest, - errorMessage - ); - const testContext = new MockActionInvokeContext("doStuff"); - const middleware = new CardActionMiddleware([doStuffAction]); - await middleware.onTurn(testContext as any, async () => {}); - - assert.isTrue(doStuffAction.isInvoked); - assert.isNotNull(testContext.content); - assert.strictEqual(testContext.content.message, errorMessage); - assert.strictEqual(testContext.content.code, StatusCodes.BAD_REQUEST.toString()); - }); - - it("handler should send server error response correctly", async () => { - const errorMessage = "Internal server error"; - const doStuffAction = new MockCardActionHandlerWithErrorResponse( - "doStuff", - InvokeResponseErrorCode.InternalServerError, - errorMessage - ); - const testContext = new MockActionInvokeContext("doStuff"); - const middleware = new CardActionMiddleware([doStuffAction]); - await middleware.onTurn(testContext as any, async () => {}); - - assert.isTrue(doStuffAction.isInvoked); - assert.isNotNull(testContext.content); - assert.strictEqual(testContext.content.message, errorMessage); - assert.strictEqual(testContext.content.code, StatusCodes.INTERNAL_SERVER_ERROR.toString()); - }); - - it("handler should get action data correctly", async () => { - const doStuffAction = new MockCardActionHandler("doStuff", "sampleResponse"); - const testContext = new MockActionInvokeContext("doStuff", { foo: "bar" }); - const middleware = new CardActionMiddleware([doStuffAction]); - await middleware.onTurn(testContext as any, async () => {}); - - assert.isTrue(doStuffAction.isInvoked); - assert.deepEqual(doStuffAction.actionData, { foo: "bar" }); - }); -}); - -describe("ard Action Bot Tests - Node", () => { - const sandbox = sinon.createSandbox(); - let adapter: BotFrameworkAdapter; - let middlewares: any[]; - - beforeEach(() => { - middlewares = []; - const stubContext = sandbox.createStubInstance(TurnContext); - const stubAdapter = sandbox.createStubInstance(BotFrameworkAdapter); - stubAdapter.use.callsFake((args) => { - middlewares.push(args); - return stubAdapter; - }); - ( - stubAdapter.continueConversation as unknown as sinon.SinonStub< - [Partial, (context: TurnContext) => Promise], - Promise - > - ).callsFake(async (ref, logic) => { - await logic(stubContext); - }); - adapter = stubAdapter; - }); - - afterEach(() => { - sandbox.restore(); - }); - - it("initialize cardAction should create correct middleware", () => { - const cardAction = new CardActionBot(adapter); - assert.strictEqual(middlewares.length, 1); - assert.isTrue(middlewares[0] instanceof CardActionMiddleware); - }); - - it("registerHandler should add card action successfully", () => { - const cardAction = new CardActionBot(adapter); - cardAction.registerHandler(new MockCardActionHandler("myAction")); - - assert.strictEqual(middlewares.length, 1); - assert.isTrue(middlewares[0] instanceof CardActionMiddleware); - const middleware = middlewares[0] as CardActionMiddleware; - - assert.isNotEmpty(middleware.actionHandlers); - assert.isTrue(middleware.actionHandlers.length === 1); - assert.isTrue(middleware.actionHandlers[0] instanceof MockCardActionHandler); - }); - - it("registerHandlers should add card actions successfully", () => { - const cardAction = new CardActionBot(adapter); - cardAction.registerHandlers([ - new MockCardActionHandler("myAction1"), - new MockCardActionHandler("myAction2"), - ]); - - assert.strictEqual(middlewares.length, 1); - assert.isTrue(middlewares[0] instanceof CardActionMiddleware); - const middleware = middlewares[0] as CardActionMiddleware; - - assert.isNotEmpty(middleware.actionHandlers); - assert.isTrue(middleware.actionHandlers.length === 2); - assert.isTrue(middleware.actionHandlers[0] instanceof MockCardActionHandler); - assert.isTrue(middleware.actionHandlers[0].triggerVerb == "myAction1"); - assert.isTrue(middleware.actionHandlers[1] instanceof MockCardActionHandler); - assert.isTrue(middleware.actionHandlers[1].triggerVerb == "myAction2"); - }); -}); diff --git a/packages/sdk/test/unit/node/conversation/command.spec.ts b/packages/sdk/test/unit/node/conversation/command.spec.ts deleted file mode 100644 index d821739f9a..0000000000 --- a/packages/sdk/test/unit/node/conversation/command.spec.ts +++ /dev/null @@ -1,168 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. - -import { assert, expect } from "chai"; -import { BotFrameworkAdapter, ConversationReference, TeamsInfo, TurnContext } from "botbuilder"; -import * as sinon from "sinon"; -import { CommandBot } from "../../../../src/conversation/command"; -import { CommandResponseMiddleware } from "../../../../src/conversation/middlewares/commandMiddleware"; -import { TestCommandHandler, TestSsoCommandHandler } from "./testUtils"; -import mockedEnv from "mocked-env"; -import { DefaultBotSsoExecutionActivityHandler } from "../../../../src/conversation/sso/defaultBotSsoExecutionActivityHandler"; -import { BotSsoConfig } from "../../../../src"; - -describe("CommandBot Tests - Node", () => { - let mockedEnvRestore: () => void; - - const sandbox = sinon.createSandbox(); - let adapter: BotFrameworkAdapter; - let middlewares: any[]; - - const clientId = "fake_client_id"; - const clientSecret = "fake_client_secret"; - const tenantId = "fake_tenant"; - const authorityHost = "fake_authority_host"; - const initiateLoginEndpoint = "fake_initiate_login_endpoint"; - const ssoConfig: BotSsoConfig = { - aad: { - scopes: ["User.Read"], - }, - }; - - beforeEach(() => { - mockedEnvRestore = mockedEnv({ - INITIATE_LOGIN_ENDPOINT: initiateLoginEndpoint, - M365_CLIENT_ID: clientId, - M365_CLIENT_SECRET: clientSecret, - M365_TENANT_ID: tenantId, - M365_AUTHORITY_HOST: authorityHost, - }); - - middlewares = []; - const stubContext = sandbox.createStubInstance(TurnContext); - const stubAdapter = sandbox.createStubInstance(BotFrameworkAdapter); - stubAdapter.use.callsFake((args) => { - middlewares.push(args); - return stubAdapter; - }); - ( - stubAdapter.continueConversation as unknown as sinon.SinonStub< - [Partial, (context: TurnContext) => Promise], - Promise - > - ).callsFake(async (ref, logic) => { - await logic(stubContext); - }); - adapter = stubAdapter; - }); - - afterEach(() => { - sandbox.restore(); - mockedEnvRestore(); - }); - - it("create command bot should add correct middleware", () => { - const commandBot = new CommandBot(adapter); - assert.isTrue(middlewares[0] instanceof CommandResponseMiddleware); - }); - - it("command should be added through registerCommand API", () => { - const commandBot = new CommandBot(adapter); - commandBot.registerCommand(new TestCommandHandler("test")); - - assert.isTrue(middlewares[0] instanceof CommandResponseMiddleware); - const middleware = middlewares[0] as CommandResponseMiddleware; - - assert.isNotEmpty(middleware.commandHandlers); - assert.isTrue(middleware.commandHandlers.length === 1); - assert.isTrue(middleware.commandHandlers[0] instanceof TestCommandHandler); - }); - - it("commands should be added through registerCommands API", () => { - const commandBot = new CommandBot(adapter); - const stringPattern = "test"; - const regExpPattern = /^test (.*?)$/i; - commandBot.registerCommands([ - new TestCommandHandler(stringPattern), - new TestCommandHandler(regExpPattern), - ]); - - assert.isTrue(middlewares[0] instanceof CommandResponseMiddleware); - const middleware = middlewares[0] as CommandResponseMiddleware; - - assert.isNotEmpty(middleware.commandHandlers); - assert.isTrue(middleware.commandHandlers.length === 2); - assert.isTrue(typeof middleware.commandHandlers[0].triggerPatterns === "string"); - assert.isTrue(middleware.commandHandlers[1].triggerPatterns instanceof RegExp); - }); - - it("create sso command bot should add correct activity handler", () => { - const defaultSsoHandler = new DefaultBotSsoExecutionActivityHandler(ssoConfig); - const commandBot = new CommandBot( - adapter, - { - ssoCommands: [new TestSsoCommandHandler("test")], - }, - defaultSsoHandler - ); - assert.isTrue(middlewares[0] instanceof CommandResponseMiddleware); - const middleware = middlewares[0] as CommandResponseMiddleware; - - assert.isDefined(middleware.ssoActivityHandler); - assert.isTrue(middleware.ssoActivityHandler instanceof DefaultBotSsoExecutionActivityHandler); - assert.isTrue(middleware.ssoCommandHandlers.length == 1); - }); - - it("add sso command should throw error if sso activity handler is undefined", () => { - const commandBot = new CommandBot(adapter); - assert.isUndefined((middlewares[0] as CommandResponseMiddleware).ssoActivityHandler); - - expect(() => { - commandBot.registerSsoCommand(new TestSsoCommandHandler("test")); - }).to.throw("Sso command can only be used or added when sso activity handler is not undefined"); - }); - - it("add sso command handler should add correct activity handler", () => { - const commandBot = new CommandBot( - adapter, - undefined, - new DefaultBotSsoExecutionActivityHandler(ssoConfig) - ); - const middleware = middlewares[0] as CommandResponseMiddleware; - commandBot.registerSsoCommand(new TestSsoCommandHandler("test")); - assert.isDefined(middleware.ssoActivityHandler); - assert.isTrue(middleware.ssoActivityHandler instanceof DefaultBotSsoExecutionActivityHandler); - assert.isTrue(middleware.ssoCommandHandlers.length == 1); - }); - - it("add sso command handlers should add correct activity handler", () => { - const commandBot = new CommandBot( - adapter, - undefined, - new DefaultBotSsoExecutionActivityHandler(ssoConfig) - ); - const middleware = middlewares[0] as CommandResponseMiddleware; - commandBot.registerSsoCommands([ - new TestSsoCommandHandler("test"), - new TestSsoCommandHandler("test2"), - ]); - assert.isDefined(middleware.ssoActivityHandler); - assert.isTrue(middleware.ssoActivityHandler instanceof DefaultBotSsoExecutionActivityHandler); - assert.isTrue(middleware.ssoCommandHandlers.length == 2); - }); - - it("add both normal command and sso command should add correct activity handler", () => { - const commandBot = new CommandBot( - adapter, - undefined, - new DefaultBotSsoExecutionActivityHandler(ssoConfig) - ); - const middleware = middlewares[0] as CommandResponseMiddleware; - commandBot.registerCommand(new TestCommandHandler("test")); - commandBot.registerSsoCommand(new TestSsoCommandHandler("test")); - assert.isDefined(middleware.ssoActivityHandler); - assert.isTrue(middleware.ssoActivityHandler instanceof DefaultBotSsoExecutionActivityHandler); - assert.isTrue(middleware.commandHandlers.length == 1); - assert.isTrue(middleware.ssoCommandHandlers.length == 1); - }); -}); diff --git a/packages/sdk/test/unit/node/conversation/conversation.spec.ts b/packages/sdk/test/unit/node/conversation/conversation.spec.ts deleted file mode 100644 index c7af256108..0000000000 --- a/packages/sdk/test/unit/node/conversation/conversation.spec.ts +++ /dev/null @@ -1,107 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. - -import { BotFrameworkAdapter, TurnContext } from "botbuilder"; -import { assert, use as chaiUse } from "chai"; -import * as chaiPromises from "chai-as-promised"; -import mockedEnv from "mocked-env"; -import * as sinon from "sinon"; -import { ConversationBot } from "../../../../src/conversation/conversation"; - -chaiUse(chaiPromises); - -describe("ConversationBot Tests - Node", () => { - const clientId = "fake_client_id"; - const clientSecret = "fake_client_secret"; - const tenantId = "fake_tenant"; - const authorityHost = "fake_authority_host"; - const initiateLoginEndpoint = "fake_initiate_login_endpoint"; - let mockedEnvRestore: () => void; - - const sandbox = sinon.createSandbox(); - - beforeEach(() => { - mockedEnvRestore = mockedEnv({ - INITIATE_LOGIN_ENDPOINT: initiateLoginEndpoint, - M365_CLIENT_ID: clientId, - M365_CLIENT_SECRET: clientSecret, - M365_TENANT_ID: tenantId, - M365_AUTHORITY_HOST: authorityHost, - }); - }); - - afterEach(() => { - mockedEnvRestore(); - sandbox.restore(); - }); - - it("Create with default options", () => { - const conversationBot = new ConversationBot({}); - assert.isDefined(conversationBot.adapter); - assert.isDefined(conversationBot.adapter.onTurnError); - assert.isUndefined(conversationBot.command); - assert.isUndefined(conversationBot.notification); - assert.isUndefined(conversationBot.cardAction); - }); - - it("Create with customized adapter", () => { - const adapter = sandbox.createStubInstance(BotFrameworkAdapter); - const conversationBot = new ConversationBot({ adapter: adapter }); - assert.isDefined(conversationBot.adapter); - assert.equal(conversationBot.adapter, adapter); - assert.isUndefined(conversationBot.command); - assert.isUndefined(conversationBot.notification); - assert.isUndefined(conversationBot.cardAction); - }); - - it("Create with customized adapterConfig", () => { - const conversationBot = new ConversationBot({ adapterConfig: { foo: "bar" } }); - assert.isDefined(conversationBot.adapter); - assert.isDefined(conversationBot.adapter.onTurnError); - assert.isUndefined(conversationBot.command); - assert.isUndefined(conversationBot.notification); - assert.isUndefined(conversationBot.cardAction); - }); - - it("Create with all enabled", () => { - const conversationBot = new ConversationBot({ - command: { enabled: true }, - notification: { enabled: true }, - cardAction: { enabled: true }, - }); - assert.isDefined(conversationBot.adapter); - assert.isDefined(conversationBot.adapter.onTurnError); - assert.isDefined(conversationBot.command); - assert.isDefined(conversationBot.notification); - assert.isDefined(conversationBot.cardAction); - }); - - it("requestHandler correctly handles empty logic", async () => { - const adapter = sandbox.createStubInstance(BotFrameworkAdapter); - const context = sandbox.createStubInstance(TurnContext); - let called = false; - adapter.processActivity.callsFake(async (req, res, logic) => { - await logic(context); - called = true; - }); - - const conversationBot = new ConversationBot({ adapter: adapter }); - await conversationBot.requestHandler({} as any, {} as any); - assert.isTrue(called); - }); - - it("requestHandler correctly handles non-empty logic", async () => { - const adapter = sandbox.createStubInstance(BotFrameworkAdapter); - const context = sandbox.createStubInstance(TurnContext); - adapter.processActivity.callsFake(async (req, res, logic) => { - await logic(context); - }); - - let called = false; - const conversationBot = new ConversationBot({ adapter: adapter }); - await conversationBot.requestHandler({} as any, {} as any, async (ctx) => { - called = true; - }); - assert.isTrue(called); - }); -}); diff --git a/packages/sdk/test/unit/node/conversation/middleware.spec.ts b/packages/sdk/test/unit/node/conversation/middleware.spec.ts deleted file mode 100644 index 1ec02f7042..0000000000 --- a/packages/sdk/test/unit/node/conversation/middleware.spec.ts +++ /dev/null @@ -1,573 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. - -import { ConversationReference, TurnContext } from "botbuilder"; -import { assert, expect, use as chaiUse } from "chai"; -import * as chaiPromises from "chai-as-promised"; -import mockedEnv from "mocked-env"; -import * as sinon from "sinon"; -import { CommandResponseMiddleware } from "../../../../src/conversation/middlewares/commandMiddleware"; -import { DefaultConversationReferenceStore } from "../../../../src/conversation/storage"; -import { - MockActionInvokeContext, - MockCardActionHandler, - MockContext, - TestCommandHandler, - TestSsoCommandHandler, - TestStorage, -} from "./testUtils"; -import { CardActionMiddleware } from "../../../../src/conversation/middlewares/cardActionMiddleware"; -import { DefaultBotSsoExecutionActivityHandler } from "../../../../src/conversation/sso/defaultBotSsoExecutionActivityHandler"; -import { NotificationMiddleware } from "../../../../src/conversation/middlewares/notificationMiddleware"; -import { BotSsoConfig } from "../../../../src/conversation/interface"; -chaiUse(chaiPromises); - -describe("CommandResponse Middleware Tests - Node", () => { - const clientId = "fake_client_id"; - const clientSecret = "fake_client_secret"; - const tenantId = "fake_tenant"; - const authorityHost = "fake_authority_host"; - const initiateLoginEndpoint = "fake_initiate_login_endpoint"; - const ssoConfig: BotSsoConfig = { - aad: { - scopes: ["User.Read"], - }, - }; - let mockedEnvRestore: () => void; - - beforeEach(() => { - mockedEnvRestore = mockedEnv({ - INITIATE_LOGIN_ENDPOINT: initiateLoginEndpoint, - M365_CLIENT_ID: clientId, - M365_CLIENT_SECRET: clientSecret, - M365_TENANT_ID: tenantId, - M365_AUTHORITY_HOST: authorityHost, - }); - }); - afterEach(() => { - sinon.restore(); - mockedEnvRestore(); - }); - - it("add sso command should work", async () => { - const testCommandHandler = new TestCommandHandler("test"); - const middleware = new CommandResponseMiddleware([testCommandHandler]); - - const testSsoCommand = new TestSsoCommandHandler("test"); - middleware.addSsoCommand(testSsoCommand); - assert.isTrue(middleware.hasSsoCommand); - assert.isTrue(middleware.ssoCommandHandlers.length === 1); - }); - - it("onTurn should correctly trigger command if matches string", async () => { - const testContext = new MockContext("test"); - - const testCommandHandler = new TestCommandHandler("test"); - const middleware = new CommandResponseMiddleware([testCommandHandler]); - await middleware.onTurn(testContext as any, async () => {}); - - // Assert the test command handler is invoked - assert.isTrue(testCommandHandler.isInvoked); - }); - - it("onTurn should correctly trigger command if matches string array", async () => { - const testContext1 = new MockContext("test1"); - const testContext2 = new MockContext("tes2"); - - const testCommandHandler = new TestCommandHandler(["test1", "test2"]); - const middleware = new CommandResponseMiddleware([testCommandHandler]); - await middleware.onTurn(testContext1 as any, async () => {}); - - // Assert the test command handler is invoked - assert.isTrue(testCommandHandler.isInvoked); - - await middleware.onTurn(testContext2 as any, async () => {}); - - // Assert the test command handler is invoked - assert.isTrue(testCommandHandler.isInvoked); - }); - - it("onTurn should correctly handle command if matches regexp", async () => { - const testContext = new MockContext("test some-input"); - - const testCommandHandler = new TestCommandHandler(/^test (.*?)$/i); - const middleware = new CommandResponseMiddleware([testCommandHandler]); - await middleware.onTurn(testContext as any, async () => {}); - - // Assert the test command handler is invoked - assert.isTrue(testCommandHandler.isInvoked); - assert.isDefined(testCommandHandler.lastReceivedMessage); - - const args = testCommandHandler.lastReceivedMessage?.matches as RegExpMatchArray; - assert.isTrue(args.length === 2); - assert.isTrue(args[1] === "some-input"); - }); - - it("onTurn should correctly handle command if matches regexp array", async () => { - const testContext1 = new MockContext("test1 some-input"); - const testContext2 = new MockContext("test2 some-input"); - - const testCommandHandler = new TestCommandHandler([/^test1 (.*?)$/i, /^test2 (.*?)$/i]); - const middleware = new CommandResponseMiddleware([testCommandHandler]); - await middleware.onTurn(testContext1 as any, async () => {}); - - // Assert the test command handler is invoked - assert.isTrue(testCommandHandler.isInvoked); - - await middleware.onTurn(testContext2 as any, async () => {}); - - // Assert the test command handler is invoked - assert.isTrue(testCommandHandler.isInvoked); - }); - - it("onTurn should skip handling command if the text is not acceptable ", async () => { - const testContext = new MockContext("invalid input"); - - const testCommandHandler = new TestCommandHandler("test"); - const middleware = new CommandResponseMiddleware([testCommandHandler]); - await middleware.onTurn(testContext as any, async () => {}); - - // Assert the test command handler is invoked - assert.isFalse(testCommandHandler.isInvoked); - }); - - it("onTurn should correctly trigger sso command activity handler", async () => { - const testContext = new MockContext("test"); - const testSsoCommand = new TestSsoCommandHandler("test"); - const defaultBotSsoExecutionActivityHandler = new DefaultBotSsoExecutionActivityHandler( - ssoConfig - ); - const stub = sinon.stub(defaultBotSsoExecutionActivityHandler, "run").resolves(); - - const middleware = new CommandResponseMiddleware( - [], - [testSsoCommand], - defaultBotSsoExecutionActivityHandler - ); - - await middleware.onTurn(testContext as any, async () => {}); - expect(stub.called).to.be.true; - expect(stub.calledOnceWith(testContext as any)); - }); - - it("onTurn should be called if context is not a message activity", async () => { - const testContext = new MockContext("test", "invoke"); - const testSsoCommand = new TestSsoCommandHandler("test"); - const defaultBotSsoExecutionActivityHandler = new DefaultBotSsoExecutionActivityHandler( - ssoConfig - ); - const stub = sinon.stub(defaultBotSsoExecutionActivityHandler, "run").resolves(); - - const middleware = new CommandResponseMiddleware( - [], - [testSsoCommand], - defaultBotSsoExecutionActivityHandler - ); - - await middleware.onTurn(testContext as any, async () => {}); - expect(stub.called).to.be.true; - expect(stub.calledOnceWith(testContext as any)); - }); -}); - -describe("CardAction Middleware Tests - Node", () => { - it("onTurn should invoke card action handler if verb is matched", async () => { - const doStuffAction = new MockCardActionHandler("doStuff", "myResponseMessage"); - const middleware = new CardActionMiddleware([doStuffAction]); - - const testContext = new MockActionInvokeContext("doStuff"); - await middleware.onTurn(testContext as any, async () => {}); - - // Assert the card action handler is invoked - assert.isTrue(doStuffAction.isInvoked); - }); - - it("onTurn shouldn't invoke card action handler if verb is not matched", async () => { - const doStuffAction = new MockCardActionHandler("doStuff", "myResponseMessage"); - const middleware = new CardActionMiddleware([doStuffAction]); - - const testContext = new MockActionInvokeContext("inconsistent-verb"); - await middleware.onTurn(testContext as any, async () => {}); - - // Assert the card action handler is not invoked - assert.isFalse(doStuffAction.isInvoked); - }); -}); - -describe("Notification Middleware Tests - Node", () => { - const sandbox = sinon.createSandbox(); - const testStorage = new TestStorage(); - const middleware = new NotificationMiddleware({ - conversationReferenceStore: new DefaultConversationReferenceStore(testStorage), - }); - - beforeEach(() => { - testStorage.items = {}; - sandbox.stub(TurnContext, "getConversationReference").callsFake((activity) => { - const reference = { - channelId: activity.channelId, - conversation: { - id: activity.conversation?.id, - tenantId: activity.conversation?.tenantId, - }, - } as ConversationReference; - if (activity.conversation?.conversationType !== undefined) { - reference.conversation.conversationType = activity.conversation?.conversationType; - } - return reference; - }); - }); - - afterEach(() => { - sandbox.restore(); - }); - - it("onTurn should correctly handle bot installed", async () => { - const testContext = { - activity: { - action: "add", - type: "installationUpdate", - channelId: "1", - conversation: { - id: "1", - tenantId: "a", - }, - recipient: { - id: "A", - }, - }, - }; - await middleware.onTurn(testContext as any, async () => {}); - assert.deepStrictEqual(testStorage.items, { - _a_1: { - channelId: "1", - conversation: { - id: "1", - tenantId: "a", - }, - }, - }); - }); - - it("onTurn should correctly handle bot uninstalled", async () => { - testStorage.items = { - _a_1: { - channelId: "1", - conversation: { - id: "1", - tenantId: "a", - }, - }, - }; - const testContext = { - activity: { - action: "remove", - type: "installationUpdate", - channelId: "1", - conversation: { - id: "1", - tenantId: "a", - }, - recipient: { - id: "A", - }, - }, - }; - await middleware.onTurn(testContext as any, async () => {}); - assert.deepStrictEqual(testStorage.items, {}); - }); - - it("onTurn should correctly handle bot messaged in general channel (new)", async () => { - const testContext = { - activity: { - type: "message", - channelId: "1", - channelData: { - team: { - id: "X", - }, - }, - conversation: { - id: "1", - conversationType: "channel", - tenantId: "a", - }, - recipient: { - id: "A", - }, - }, - }; - await middleware.onTurn(testContext as any, async () => {}); - assert.deepStrictEqual(testStorage.items, { - _a_X: { - channelId: "1", - conversation: { - id: "X", - conversationType: "channel", - tenantId: "a", - }, - }, - }); - }); - - it("onTurn should correctly handle bot messaged in general channel (exist)", async () => { - testStorage.items = { - _a_X: { - channelId: "1", - conversation: { - id: "X", - conversationType: "channel", - tenantId: "a", - }, - }, - }; - const testContext = { - activity: { - type: "message", - channelId: "xxxxxxxxx", - channelData: { - team: { - id: "X", - }, - }, - conversation: { - id: "1", - conversationType: "channel", - tenantId: "a", - }, - recipient: { - id: "A", - }, - }, - }; - await middleware.onTurn(testContext as any, async () => {}); - assert.deepStrictEqual(testStorage.items, { - _a_X: { - channelId: "1", - conversation: { - id: "X", - conversationType: "channel", - tenantId: "a", - }, - }, - }); - }); - - it("onTurn should correctly handle bot messaged in general channel (channelId)", async () => { - const testContext = { - activity: { - type: "message", - channelId: "1", - channelData: { - team: { - id: "X", - }, - channel: { - id: "X", - }, - }, - conversation: { - id: "1", - conversationType: "channel", - tenantId: "a", - }, - recipient: { - id: "A", - }, - }, - }; - await middleware.onTurn(testContext as any, async () => {}); - assert.deepStrictEqual(testStorage.items, { - _a_X: { - channelId: "1", - conversation: { - id: "X", - conversationType: "channel", - tenantId: "a", - }, - }, - }); - }); - - it("onTurn should ignore bot messaged in non-general channel", async () => { - const testContext = { - activity: { - type: "message", - channelId: "1", - channelData: { - team: { - id: "X", - }, - channel: { - id: "X-channel", - }, - }, - conversation: { - id: "1", - conversationType: "channel", - tenantId: "a", - }, - recipient: { - id: "A", - }, - }, - }; - await middleware.onTurn(testContext as any, async () => {}); - assert.deepStrictEqual(testStorage.items, {}); - }); - - it("onTurn should ignore bot messaged in channel (invalid data)", async () => { - const testContext = { - activity: { - type: "message", - channelId: "1", - conversation: { - id: "1", - conversationType: "channel", - tenantId: "a", - }, - recipient: { - id: "A", - }, - }, - }; - await middleware.onTurn(testContext as any, async () => {}); - assert.deepStrictEqual(testStorage.items, {}); - }); - - it("onTurn should correctly handle bot messaged in chat (new)", async () => { - const testContext = { - activity: { - type: "message", - channelId: "1", - conversation: { - id: "1", - conversationType: "groupChat", - tenantId: "a", - }, - recipient: { - id: "A", - }, - }, - }; - await middleware.onTurn(testContext as any, async () => {}); - assert.deepStrictEqual(testStorage.items, { - _a_1: { - channelId: "1", - conversation: { - id: "1", - conversationType: "groupChat", - tenantId: "a", - }, - }, - }); - }); - - it("onTurn should ignore bot messaged in chat (exist)", async () => { - testStorage.items = { - _a_1: { - channelId: "1", - conversation: { - id: "1", - tenantId: "a", - }, - }, - }; - const testContext = { - activity: { - type: "message", - channelId: "xxxxxxxxx", - conversation: { - id: "1", - conversationType: "groupChat", - tenantId: "a", - }, - recipient: { - id: "A", - }, - }, - }; - await middleware.onTurn(testContext as any, async () => {}); - assert.deepStrictEqual(testStorage.items, { - _a_1: { - channelId: "1", - conversation: { - id: "1", - tenantId: "a", - }, - }, - }); - }); - - it("onTurn should correctly handle team deleted", async () => { - testStorage.items = { - _a_1: { - channelId: "1", - conversation: { - id: "1", - tenantId: "a", - }, - }, - }; - const testContext = { - activity: { - type: "conversationUpdate", - channelId: "1", - conversation: { - id: "1", - tenantId: "a", - }, - recipient: { - id: "A", - }, - channelData: { - eventType: "teamDeleted", - }, - }, - }; - await middleware.onTurn(testContext as any, async () => {}); - assert.deepStrictEqual(testStorage.items, {}); - }); - - it("onTurn should correctly handle team restored", async () => { - const testContext = { - activity: { - type: "conversationUpdate", - channelId: "1", - conversation: { - id: "1", - tenantId: "a", - }, - recipient: { - id: "A", - }, - channelData: { - eventType: "teamRestored", - }, - }, - }; - await middleware.onTurn(testContext as any, async () => {}); - assert.deepStrictEqual(testStorage.items, { - _a_1: { - channelId: "1", - conversation: { - id: "1", - tenantId: "a", - }, - }, - }); - }); - - it("onTurn should ignore non-bot event", async () => { - const testContext = { - activity: { - channelId: "1", - recipient: { - id: "B", - }, - }, - }; - await middleware.onTurn(testContext as any, async () => {}); - assert.deepStrictEqual(testStorage.items, {}); - }); -}); diff --git a/packages/sdk/test/unit/node/conversation/middlewares/cardActionMiddleware.spec.ts b/packages/sdk/test/unit/node/conversation/middlewares/cardActionMiddleware.spec.ts new file mode 100644 index 0000000000..a3eda139df --- /dev/null +++ b/packages/sdk/test/unit/node/conversation/middlewares/cardActionMiddleware.spec.ts @@ -0,0 +1,33 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +import { assert, use as chaiUse } from "chai"; +import * as chaiPromises from "chai-as-promised"; +import { MockActionInvokeContext, MockCardActionHandler } from "../testUtils"; +import { CardActionMiddleware } from "../../../../../src/conversation/middlewares/cardActionMiddleware"; + +chaiUse(chaiPromises); + +describe("CardAction Middleware Tests - Node", () => { + it("onTurn should invoke card action handler if verb is matched", async () => { + const doStuffAction = new MockCardActionHandler("doStuff", "myResponseMessage"); + const middleware = new CardActionMiddleware([doStuffAction]); + + const testContext = new MockActionInvokeContext("doStuff"); + await middleware.onTurn(testContext as any, async () => {}); + + // Assert the card action handler is invoked + assert.isTrue(doStuffAction.isInvoked); + }); + + it("onTurn shouldn't invoke card action handler if verb is not matched", async () => { + const doStuffAction = new MockCardActionHandler("doStuff", "myResponseMessage"); + const middleware = new CardActionMiddleware([doStuffAction]); + + const testContext = new MockActionInvokeContext("inconsistent-verb"); + await middleware.onTurn(testContext as any, async () => {}); + + // Assert the card action handler is not invoked + assert.isFalse(doStuffAction.isInvoked); + }); +}); diff --git a/packages/sdk/test/unit/node/conversation/middlewares/commandMiddleware.spec.ts b/packages/sdk/test/unit/node/conversation/middlewares/commandMiddleware.spec.ts new file mode 100644 index 0000000000..05aa445303 --- /dev/null +++ b/packages/sdk/test/unit/node/conversation/middlewares/commandMiddleware.spec.ts @@ -0,0 +1,153 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +import { assert, expect, use as chaiUse } from "chai"; +import * as chaiPromises from "chai-as-promised"; +import * as sinon from "sinon"; +import { CommandResponseMiddleware } from "../../../../../src/conversation/middlewares/commandMiddleware"; +import { MockContext, TestCommandHandler, TestSsoCommandHandler } from "../testUtils"; +import { DefaultBotSsoExecutionActivityHandler } from "../../../../../src/conversation/sso/defaultBotSsoExecutionActivityHandler"; +import { BotSsoConfig } from "../../../../../src/conversation/interface"; +chaiUse(chaiPromises); + +describe("CommandResponse Middleware Tests - Node", () => { + const clientId = "fake_client_id"; + const clientSecret = "fake_client_secret"; + const tenantId = "fake_tenant"; + const authorityHost = "fake_authority_host"; + const initiateLoginEndpoint = "fake_initiate_login_endpoint"; + const ssoConfig: BotSsoConfig = { + aad: { + scopes: ["User.Read"], + clientId, + clientSecret, + tenantId, + authorityHost, + initiateLoginEndpoint, + }, + }; + + afterEach(() => { + sinon.restore(); + }); + + it("add sso command should work", async () => { + const testCommandHandler = new TestCommandHandler("test"); + const middleware = new CommandResponseMiddleware([testCommandHandler]); + + const testSsoCommand = new TestSsoCommandHandler("test"); + middleware.addSsoCommand(testSsoCommand); + assert.isTrue(middleware.hasSsoCommand); + assert.isTrue(middleware.ssoCommandHandlers.length === 1); + }); + + it("onTurn should correctly trigger command if matches string", async () => { + const testContext = new MockContext("test"); + + const testCommandHandler = new TestCommandHandler("test"); + const middleware = new CommandResponseMiddleware([testCommandHandler]); + await middleware.onTurn(testContext as any, async () => {}); + + // Assert the test command handler is invoked + assert.isTrue(testCommandHandler.isInvoked); + }); + + it("onTurn should correctly trigger command if matches string array", async () => { + const testContext1 = new MockContext("test1"); + const testContext2 = new MockContext("tes2"); + + const testCommandHandler = new TestCommandHandler(["test1", "test2"]); + const middleware = new CommandResponseMiddleware([testCommandHandler]); + await middleware.onTurn(testContext1 as any, async () => {}); + + // Assert the test command handler is invoked + assert.isTrue(testCommandHandler.isInvoked); + + await middleware.onTurn(testContext2 as any, async () => {}); + + // Assert the test command handler is invoked + assert.isTrue(testCommandHandler.isInvoked); + }); + + it("onTurn should correctly handle command if matches regexp", async () => { + const testContext = new MockContext("test some-input"); + + const testCommandHandler = new TestCommandHandler(/^test (.*?)$/i); + const middleware = new CommandResponseMiddleware([testCommandHandler]); + await middleware.onTurn(testContext as any, async () => {}); + + // Assert the test command handler is invoked + assert.isTrue(testCommandHandler.isInvoked); + assert.isDefined(testCommandHandler.lastReceivedMessage); + + const args = testCommandHandler.lastReceivedMessage?.matches as RegExpMatchArray; + assert.isTrue(args.length === 2); + assert.isTrue(args[1] === "some-input"); + }); + + it("onTurn should correctly handle command if matches regexp array", async () => { + const testContext1 = new MockContext("test1 some-input"); + const testContext2 = new MockContext("test2 some-input"); + + const testCommandHandler = new TestCommandHandler([/^test1 (.*?)$/i, /^test2 (.*?)$/i]); + const middleware = new CommandResponseMiddleware([testCommandHandler]); + await middleware.onTurn(testContext1 as any, async () => {}); + + // Assert the test command handler is invoked + assert.isTrue(testCommandHandler.isInvoked); + + await middleware.onTurn(testContext2 as any, async () => {}); + + // Assert the test command handler is invoked + assert.isTrue(testCommandHandler.isInvoked); + }); + + it("onTurn should skip handling command if the text is not acceptable ", async () => { + const testContext = new MockContext("invalid input"); + + const testCommandHandler = new TestCommandHandler("test"); + const middleware = new CommandResponseMiddleware([testCommandHandler]); + await middleware.onTurn(testContext as any, async () => {}); + + // Assert the test command handler is invoked + assert.isFalse(testCommandHandler.isInvoked); + }); + + it("onTurn should correctly trigger sso command activity handler", async () => { + const testContext = new MockContext("test"); + const testSsoCommand = new TestSsoCommandHandler("test"); + const defaultBotSsoExecutionActivityHandler = new DefaultBotSsoExecutionActivityHandler( + ssoConfig + ); + const stub = sinon.stub(defaultBotSsoExecutionActivityHandler, "run").resolves(); + + const middleware = new CommandResponseMiddleware( + [], + [testSsoCommand], + defaultBotSsoExecutionActivityHandler + ); + + await middleware.onTurn(testContext as any, async () => {}); + expect(stub.called).to.be.true; + expect(stub.calledOnceWith(testContext as any)); + }); + + it("onTurn should be called if context is not a message activity", async () => { + const testContext = new MockContext("test", "invoke"); + const testSsoCommand = new TestSsoCommandHandler("test"); + const defaultBotSsoExecutionActivityHandler = new DefaultBotSsoExecutionActivityHandler( + ssoConfig + ); + const stub = sinon.stub(defaultBotSsoExecutionActivityHandler, "run").resolves(); + + const middleware = new CommandResponseMiddleware( + [], + [testSsoCommand], + defaultBotSsoExecutionActivityHandler + ); + + await middleware.onTurn(testContext as any, async () => {}); + expect(stub.called).to.be.true; + expect(stub.calledOnceWith(testContext as any)); + }); +}); diff --git a/packages/sdk/test/unit/node/conversation/middlewares/notificationMiddleware.spec.ts b/packages/sdk/test/unit/node/conversation/middlewares/notificationMiddleware.spec.ts new file mode 100644 index 0000000000..05bb773f96 --- /dev/null +++ b/packages/sdk/test/unit/node/conversation/middlewares/notificationMiddleware.spec.ts @@ -0,0 +1,384 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +import { ConversationReference, TurnContext } from "botbuilder"; +import { assert, use as chaiUse } from "chai"; +import * as chaiPromises from "chai-as-promised"; +import * as sinon from "sinon"; +import * as fs from "fs"; +import * as path from "path"; +import { DefaultConversationReferenceStore } from "../../../../../src/conversation/storage"; +import { NotificationMiddleware } from "../../../../../src/conversation/middlewares/notificationMiddleware"; + +chaiUse(chaiPromises); + +describe("Notification Middleware Tests - Node", () => { + const sandbox = sinon.createSandbox(); + const fileDir = "./test/"; + const localFileName = ".notification.localstore.json"; + const filePath = path.join(fileDir, localFileName); + const testData = { + _a_1: { + channelId: "1", + conversation: { + id: "1", + tenantId: "a", + }, + }, + }; + let middleware: NotificationMiddleware; + + beforeEach(() => { + const conversationReferenceStore = new DefaultConversationReferenceStore(fileDir); + middleware = new NotificationMiddleware({ + conversationReferenceStore, + }); + + sandbox.stub(TurnContext, "getConversationReference").callsFake((activity) => { + const reference = { + channelId: activity.channelId, + conversation: { + id: activity.conversation?.id, + tenantId: activity.conversation?.tenantId, + }, + } as ConversationReference; + if (activity.conversation?.conversationType !== undefined) { + reference.conversation.conversationType = activity.conversation?.conversationType; + } + return reference; + }); + }); + + afterEach(() => { + if (fs.existsSync(filePath)) { + fs.unlinkSync(filePath); + } + sandbox.restore(); + }); + + it("onTurn should correctly handle bot installed", async () => { + const testContext = { + activity: { + action: "add", + type: "installationUpdate", + channelId: "1", + conversation: { + id: "1", + tenantId: "a", + }, + recipient: { + id: "A", + }, + }, + }; + await middleware.onTurn(testContext as any, async () => {}); + + const fileData = JSON.parse(fs.readFileSync(filePath, "utf8")); + assert.deepStrictEqual(fileData, { + _a_1: { + channelId: "1", + conversation: { + id: "1", + tenantId: "a", + }, + }, + }); + }); + + it("onTurn should correctly handle bot uninstalled", async () => { + fs.writeFileSync(filePath, JSON.stringify(testData), "utf8"); + const testContext = { + activity: { + action: "remove", + type: "installationUpdate", + channelId: "1", + conversation: { + id: "1", + tenantId: "a", + }, + recipient: { + id: "A", + }, + }, + }; + await middleware.onTurn(testContext as any, async () => {}); + const fileData = JSON.parse(fs.readFileSync(filePath, "utf8")); + assert.deepStrictEqual(fileData, {}); + }); + + it("onTurn should correctly handle bot messaged in general channel (new)", async () => { + const testContext = { + activity: { + type: "message", + channelId: "1", + channelData: { + team: { + id: "X", + }, + }, + conversation: { + id: "1", + conversationType: "channel", + tenantId: "a", + }, + recipient: { + id: "A", + }, + }, + }; + await middleware.onTurn(testContext as any, async () => {}); + const fileData = JSON.parse(fs.readFileSync(filePath, "utf8")); + assert.deepStrictEqual(fileData, { + _a_X: { + channelId: "1", + conversation: { + id: "X", + conversationType: "channel", + tenantId: "a", + }, + }, + }); + }); + + it("onTurn should correctly handle bot messaged in general channel (exist)", async () => { + const rawData = { + _a_X: { + channelId: "1", + conversation: { + id: "X", + conversationType: "channel", + tenantId: "a", + }, + }, + }; + fs.writeFileSync(filePath, JSON.stringify(rawData), "utf8"); + + const testContext = { + activity: { + type: "message", + channelId: "xxxxxxxxx", + channelData: { + team: { + id: "X", + }, + }, + conversation: { + id: "1", + conversationType: "channel", + tenantId: "a", + }, + recipient: { + id: "A", + }, + }, + }; + await middleware.onTurn(testContext as any, async () => {}); + const fileData = JSON.parse(fs.readFileSync(filePath, "utf8")); + assert.deepStrictEqual(fileData, rawData); + }); + + it("onTurn should correctly handle bot messaged in general channel (channelId)", async () => { + const testContext = { + activity: { + type: "message", + channelId: "1", + channelData: { + team: { + id: "X", + }, + channel: { + id: "X", + }, + }, + conversation: { + id: "1", + conversationType: "channel", + tenantId: "a", + }, + recipient: { + id: "A", + }, + }, + }; + await middleware.onTurn(testContext as any, async () => {}); + const fileData = JSON.parse(fs.readFileSync(filePath, "utf8")); + assert.deepStrictEqual(fileData, { + _a_X: { + channelId: "1", + conversation: { + id: "X", + conversationType: "channel", + tenantId: "a", + }, + }, + }); + }); + + it("onTurn should ignore bot messaged in non-general channel", async () => { + const testContext = { + activity: { + type: "message", + channelId: "1", + channelData: { + team: { + id: "X", + }, + channel: { + id: "X-channel", + }, + }, + conversation: { + id: "1", + conversationType: "channel", + tenantId: "a", + }, + recipient: { + id: "A", + }, + }, + }; + await middleware.onTurn(testContext as any, async () => {}); + const fileData = fs.existsSync(filePath) ? JSON.parse(fs.readFileSync(filePath, "utf8")) : {}; + + assert.deepStrictEqual(fileData, {}); + }); + + it("onTurn should ignore bot messaged in channel (invalid data)", async () => { + const testContext = { + activity: { + type: "message", + channelId: "1", + conversation: { + id: "1", + conversationType: "channel", + tenantId: "a", + }, + recipient: { + id: "A", + }, + }, + }; + await middleware.onTurn(testContext as any, async () => {}); + const fileData = fs.existsSync(filePath) ? JSON.parse(fs.readFileSync(filePath, "utf8")) : {}; + + assert.deepStrictEqual(fileData, {}); + }); + + it("onTurn should correctly handle bot messaged in chat (new)", async () => { + const testContext = { + activity: { + type: "message", + channelId: "1", + conversation: { + id: "1", + conversationType: "groupChat", + tenantId: "a", + }, + recipient: { + id: "A", + }, + }, + }; + await middleware.onTurn(testContext as any, async () => {}); + const fileData = JSON.parse(fs.readFileSync(filePath, "utf8")); + assert.deepStrictEqual(fileData, { + _a_1: { + channelId: "1", + conversation: { + id: "1", + conversationType: "groupChat", + tenantId: "a", + }, + }, + }); + }); + + it("onTurn should ignore bot messaged in chat (exist)", async () => { + fs.writeFileSync(filePath, JSON.stringify(testData), "utf8"); + const testContext = { + activity: { + type: "message", + channelId: "xxxxxxxxx", + conversation: { + id: "1", + conversationType: "groupChat", + tenantId: "a", + }, + recipient: { + id: "A", + }, + }, + }; + await middleware.onTurn(testContext as any, async () => {}); + const fileData = JSON.parse(fs.readFileSync(filePath, "utf8")); + assert.deepStrictEqual(fileData, testData); + }); + + it("onTurn should correctly handle team deleted", async () => { + fs.writeFileSync(filePath, JSON.stringify(testData), "utf8"); + const testContext = { + activity: { + type: "conversationUpdate", + channelId: "1", + conversation: { + id: "1", + tenantId: "a", + }, + recipient: { + id: "A", + }, + channelData: { + eventType: "teamDeleted", + }, + }, + }; + await middleware.onTurn(testContext as any, async () => {}); + const fileData = JSON.parse(fs.readFileSync(filePath, "utf8")); + assert.deepStrictEqual(fileData, {}); + }); + + it("onTurn should correctly handle team restored", async () => { + const testContext = { + activity: { + type: "conversationUpdate", + channelId: "1", + conversation: { + id: "1", + tenantId: "a", + }, + recipient: { + id: "A", + }, + channelData: { + eventType: "teamRestored", + }, + }, + }; + await middleware.onTurn(testContext as any, async () => {}); + const fileData = JSON.parse(fs.readFileSync(filePath, "utf8")); + assert.deepStrictEqual(fileData, { + _a_1: { + channelId: "1", + conversation: { + id: "1", + tenantId: "a", + }, + }, + }); + }); + + it("onTurn should ignore non-bot event", async () => { + const testContext = { + activity: { + channelId: "1", + recipient: { + id: "B", + }, + }, + }; + await middleware.onTurn(testContext as any, async () => {}); + const fileData = fs.existsSync(filePath) ? JSON.parse(fs.readFileSync(filePath, "utf8")) : {}; + + assert.deepStrictEqual(fileData, {}); + }); +}); diff --git a/packages/sdk/test/unit/node/conversation/notification.spec.ts b/packages/sdk/test/unit/node/conversation/notification.spec.ts deleted file mode 100644 index 2fc640a810..0000000000 --- a/packages/sdk/test/unit/node/conversation/notification.spec.ts +++ /dev/null @@ -1,935 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. - -import { - BotFrameworkAdapter, - CardFactory, - ChannelInfo, - ConversationReference, - TeamDetails, - TeamsChannelAccount, - TeamsInfo, - TurnContext, - TurnContextStateCollection, -} from "botbuilder"; -import { ConnectorClient } from "botframework-connector"; -import { Conversations } from "botframework-connector/lib/connectorApi/connectorClient"; -import { assert, use as chaiUse } from "chai"; -import * as chaiPromises from "chai-as-promised"; -import * as sinon from "sinon"; -import { NotificationTargetType } from "../../../../src/conversation/interface"; -import { NotificationMiddleware } from "../../../../src/conversation/middlewares/notificationMiddleware"; -import { - Channel, - Member, - NotificationBot, - sendAdaptiveCard, - sendMessage, - TeamsBotInstallation, -} from "../../../../src/conversation/notification"; -import * as utils from "../../../../src/conversation/utils"; -import { TestStorage, TestTarget } from "./testUtils"; - -chaiUse(chaiPromises); - -describe("Notification Tests - Node", () => { - it("sendMessage should send correct text", async () => { - const target = new TestTarget(); - await sendMessage(target, "test"); - assert.strictEqual(target.content, "test"); - }); - - it("sendMessage should catch and handle error", async () => { - const target = new TestTarget(); - target.error = new Error("test"); - let errorMessage = ""; - await sendMessage(target, "test", (ctx, err) => { - errorMessage = err.message; - return Promise.resolve(); - }); - assert.strictEqual(errorMessage, "test"); - }); - - it("sendAdaptiveCard should send correct card", async () => { - const target = new TestTarget(); - await sendAdaptiveCard(target, { foo: "bar" }); - assert.deepStrictEqual(target.content, { foo: "bar" }); - }); - - it("sendAdaptiveCard should catch and handle error", async () => { - const target = new TestTarget(); - target.error = new Error("test"); - let errorMessage = ""; - await sendAdaptiveCard(target, { foo: "bar" }, (ctx, err) => { - errorMessage = err.message; - return Promise.resolve(); - }); - assert.strictEqual(errorMessage, "test"); - }); - - describe("Channel Tests - Node", () => { - const sandbox = sinon.createSandbox(); - let botInstallation: TeamsBotInstallation; - let content: any; - let activityResponse: any; - let turnError: Error | undefined; - - beforeEach(() => { - content = ""; - activityResponse = {}; - turnError = undefined; - const stubContext = sandbox.createStubInstance(TurnContext); - stubContext.sendActivity.callsFake((activityOrText, speak, inputHint) => { - if (turnError) { - throw turnError; - } - return new Promise((resolve) => { - content = activityOrText; - resolve(activityResponse); - }); - }); - const stubAdapter = sandbox.createStubInstance(BotFrameworkAdapter); - ( - stubAdapter.continueConversation as unknown as sinon.SinonStub< - [Partial, (context: TurnContext) => Promise], - Promise - > - ).callsFake(async (ref, logic) => { - await logic(stubContext); - }); - const conversationRef = { - conversation: { - conversationType: "channel", - }, - }; - botInstallation = new TeamsBotInstallation(stubAdapter, conversationRef as any); - sandbox.stub(TurnContext, "getConversationReference").returns({ conversation: {} } as any); - }); - - afterEach(() => { - sandbox.restore(); - }); - - it("sendMessage should send correct text", async () => { - const channel = new Channel(botInstallation, { id: "1" } as ChannelInfo); - assert.strictEqual(channel.type, "Channel"); - activityResponse = { - id: "message-x", - }; - let res = await channel.sendMessage("text"); - assert.strictEqual(content, "text"); - assert.deepStrictEqual(res, { id: "message-x" }); - activityResponse = undefined; - res = await channel.sendMessage("text"); - assert.deepStrictEqual(res, { id: undefined }); - }); - - it("sendMessage should handle error", async () => { - const channel = new Channel(botInstallation, { id: "1" } as ChannelInfo); - activityResponse = { - id: "message-x", - }; - turnError = new Error("error-message-x"); - let errorMessage = ""; - await channel.sendMessage("text", (ctx, err) => { - errorMessage = err.message; - return Promise.resolve(); - }); - assert.strictEqual(errorMessage, "error-message-x"); - }); - - it("sendMessage should throw error if onError is undefined", async () => { - const channel = new Channel(botInstallation, { id: "1" } as ChannelInfo); - activityResponse = { - id: "message-x", - }; - turnError = new Error("error-message-x"); - let actualError: Error | undefined; - try { - await channel.sendMessage("text"); - } catch (error) { - actualError = error as Error; - } - assert.isDefined(actualError); - }); - - it("sendAdaptiveCard should send correct card", async () => { - sandbox.stub(CardFactory, "adaptiveCard").callsFake((card) => { - return { content: card } as any; - }); - const channel = new Channel(botInstallation, { id: "1" } as ChannelInfo); - assert.strictEqual(channel.type, "Channel"); - activityResponse = { - id: "message-x", - }; - let res = await channel.sendAdaptiveCard({ foo: "bar" }); - assert.deepStrictEqual(content, { - attachments: [ - { - content: { - foo: "bar", - }, - }, - ], - }); - assert.deepStrictEqual(res, { id: "message-x" }); - activityResponse = undefined; - res = await channel.sendAdaptiveCard({ foo: "bar" }); - assert.deepStrictEqual(res, { id: undefined }); - }); - - it("sendAdaptiveCard should handle error", async () => { - sandbox.stub(CardFactory, "adaptiveCard").callsFake((card) => { - return { content: card } as any; - }); - const channel = new Channel(botInstallation, { id: "1" } as ChannelInfo); - activityResponse = { - id: "message-x", - }; - turnError = new Error("error-card-x"); - let errorMessage = ""; - await channel.sendAdaptiveCard({ foo: "bar" }, (ctx, err) => { - errorMessage = err.message; - return Promise.resolve(); - }); - assert.strictEqual(errorMessage, "error-card-x"); - }); - - it("sendAdaptiveCard should throw error if onError is undefined", async () => { - sandbox.stub(CardFactory, "adaptiveCard").callsFake((card) => { - return { content: card } as any; - }); - const channel = new Channel(botInstallation, { id: "1" } as ChannelInfo); - activityResponse = { - id: "message-x", - }; - turnError = new Error("error-card-x"); - let actualError: Error | undefined; - try { - await channel.sendAdaptiveCard({ foo: "bar" }); - } catch (error) { - actualError = error as Error; - } - assert.isDefined(actualError); - }); - }); - - describe("Member Tests - Node", () => { - const sandbox = sinon.createSandbox(); - let botInstallation: TeamsBotInstallation; - let content: any; - let activityResponse: any; - let turnError: Error | undefined; - - beforeEach(() => { - content = ""; - activityResponse = {}; - turnError = undefined; - const stubConversations = sandbox.createStubInstance(Conversations); - stubConversations.createConversation.resolves({ - id: "1", - } as any); - const stubConnectorClient = sandbox.createStubInstance(ConnectorClient); - stubConnectorClient.conversations = stubConversations; - const stubTurnState = sandbox.createStubInstance(TurnContextStateCollection); - stubTurnState.get.returns(stubConnectorClient); - const stubContext = sandbox.createStubInstance(TurnContext); - stubContext.sendActivity.callsFake((activityOrText, speak, inputHint) => { - if (turnError) { - throw turnError; - } - return new Promise((resolve) => { - content = activityOrText; - resolve(activityResponse); - }); - }); - sandbox.stub(TurnContext.prototype, "turnState").get(() => stubTurnState); - sandbox.stub(TurnContext.prototype, "activity").get(() => { - return { - conversation: { - tenantId: "11", - }, - recipient: {}, - }; - }); - const stubAdapter = sandbox.createStubInstance(BotFrameworkAdapter); - ( - stubAdapter.continueConversation as unknown as sinon.SinonStub< - [Partial, (context: TurnContext) => Promise], - Promise - > - ).callsFake(async (ref, logic) => { - await logic(stubContext); - }); - const conversationRef = { - conversation: { - conversationType: "channel", - }, - }; - botInstallation = new TeamsBotInstallation(stubAdapter, conversationRef as any); - sandbox.stub(TurnContext, "getConversationReference").returns({ conversation: {} } as any); - }); - - afterEach(() => { - sandbox.restore(); - }); - - it("sendMessage should send correct text", async () => { - const member = new Member(botInstallation, { id: "1" } as TeamsChannelAccount); - assert.strictEqual(member.type, "Person"); - activityResponse = { - id: "message-y", - }; - let res = await member.sendMessage("text"); - assert.strictEqual(content, "text"); - assert.deepStrictEqual(res, { id: "message-y" }); - activityResponse = undefined; - res = await member.sendMessage("text"); - assert.deepStrictEqual(res, { id: undefined }); - }); - - it("sendMessage should handle error", async () => { - const member = new Member(botInstallation, { id: "1" } as TeamsChannelAccount); - assert.strictEqual(member.type, "Person"); - activityResponse = { - id: "message-y", - }; - turnError = new Error("error-message-y"); - let errorMessage = ""; - await member.sendMessage("text", (ctx, err) => { - errorMessage = err.message; - return Promise.resolve(); - }); - assert.strictEqual(errorMessage, "error-message-y"); - }); - - it("sendMessage should throw error if onError is undefined", async () => { - const member = new Member(botInstallation, { id: "1" } as TeamsChannelAccount); - assert.strictEqual(member.type, "Person"); - activityResponse = { - id: "message-y", - }; - turnError = new Error("error-message-y"); - let actualError: Error | undefined; - try { - await member.sendMessage("text"); - } catch (error) { - actualError = error as Error; - } - assert.isDefined(actualError); - }); - - it("sendAdaptiveCard should send correct card", async () => { - sandbox.stub(CardFactory, "adaptiveCard").callsFake((card) => { - return { content: card } as any; - }); - const member = new Member(botInstallation, { id: "1" } as TeamsChannelAccount); - assert.strictEqual(member.type, "Person"); - activityResponse = { - id: "message-y", - }; - let res = await member.sendAdaptiveCard({ foo: "bar" }); - assert.deepStrictEqual(content, { - attachments: [ - { - content: { - foo: "bar", - }, - }, - ], - }); - assert.deepStrictEqual(res, { id: "message-y" }); - activityResponse = undefined; - res = await member.sendAdaptiveCard({ foo: "bar" }); - assert.deepStrictEqual(res, { id: undefined }); - }); - - it("sendAdaptiveCard should handle error", async () => { - sandbox.stub(CardFactory, "adaptiveCard").callsFake((card) => { - return { content: card } as any; - }); - const member = new Member(botInstallation, { id: "1" } as TeamsChannelAccount); - activityResponse = { - id: "message-y", - }; - turnError = new Error("error-card-y"); - let errorMessage = ""; - await member.sendAdaptiveCard({ foo: "bar" }, (ctx, err) => { - errorMessage = err.message; - return Promise.resolve(); - }); - assert.strictEqual(errorMessage, "error-card-y"); - }); - - it("sendAdaptiveCard should throw error if onError is undefined", async () => { - sandbox.stub(CardFactory, "adaptiveCard").callsFake((card) => { - return { content: card } as any; - }); - const member = new Member(botInstallation, { id: "1" } as TeamsChannelAccount); - activityResponse = { - id: "message-y", - }; - turnError = new Error("error-card-x"); - let actualError: Error | undefined; - try { - await member.sendAdaptiveCard({ foo: "bar" }); - } catch (error) { - actualError = error as Error; - } - assert.isDefined(actualError); - }); - }); - - describe("TeamsBotInstallation Tests - Node", () => { - const sandbox = sinon.createSandbox(); - let adapter: BotFrameworkAdapter; - let context: TurnContext; - let content: any; - let activityResponse: any; - let turnError: Error | undefined; - - beforeEach(() => { - content = ""; - activityResponse = {}; - turnError = undefined; - const stubAdapter = sandbox.createStubInstance(BotFrameworkAdapter); - ( - stubAdapter.continueConversation as unknown as sinon.SinonStub< - [Partial, (context: TurnContext) => Promise], - Promise - > - ).callsFake(async (ref, logic) => { - await logic(context); - }); - adapter = stubAdapter; - const stubContext = sandbox.createStubInstance(TurnContext); - stubContext.sendActivity.callsFake((activityOrText, speak, inputHint) => { - if (turnError) { - throw turnError; - } - return new Promise((resolve) => { - content = activityOrText; - resolve(activityResponse); - }); - }); - context = stubContext; - }); - - afterEach(() => { - sandbox.restore(); - }); - - it("sendMessage should send correct text", async () => { - const conversationRef = { - conversation: { - conversationType: "channel", - }, - }; - const installation = new TeamsBotInstallation(adapter, conversationRef as any); - assert.strictEqual(installation.type, NotificationTargetType.Channel); - assert.isTrue(installation.type === "Channel"); - activityResponse = { - id: "message-a", - }; - let res = await installation.sendMessage("text"); - assert.strictEqual(content, "text"); - assert.deepStrictEqual(res, { id: "message-a" }); - activityResponse = undefined; - res = await installation.sendMessage("text"); - assert.deepStrictEqual(res, { id: undefined }); - }); - - it("sendMessage should handle error", async () => { - const conversationRef = { - conversation: { - conversationType: "channel", - }, - }; - const installation = new TeamsBotInstallation(adapter, conversationRef as any); - activityResponse = { - id: "message-a", - }; - turnError = new Error("error-message-a"); - let errorMessage = ""; - await installation.sendMessage("text", (ctx, err) => { - errorMessage = err.message; - return Promise.resolve(); - }); - assert.strictEqual(errorMessage, "error-message-a"); - }); - - it("sendMessage should throw error if onError is undefined", async () => { - const conversationRef = { - conversation: { - conversationType: "channel", - }, - }; - const installation = new TeamsBotInstallation(adapter, conversationRef as any); - activityResponse = { - id: "message-a", - }; - turnError = new Error("error-message-a"); - let actualError: Error | undefined; - try { - await installation.sendMessage("text"); - } catch (error) { - actualError = error as Error; - } - assert.isDefined(actualError); - }); - - it("sendAdaptiveCard should send correct card", async () => { - sandbox.stub(CardFactory, "adaptiveCard").callsFake((card) => { - return { content: card } as any; - }); - const conversationRef = { - conversation: { - conversationType: "channel", - }, - }; - const installation = new TeamsBotInstallation(adapter, conversationRef as any); - assert.strictEqual(installation.type, NotificationTargetType.Channel); - assert.isTrue(installation.type === "Channel"); - activityResponse = { - id: "message-a", - }; - let res = await installation.sendAdaptiveCard({ foo: "bar" }); - assert.deepStrictEqual(content, { - attachments: [ - { - content: { - foo: "bar", - }, - }, - ], - }); - assert.deepStrictEqual(res, { id: "message-a" }); - activityResponse = undefined; - res = await installation.sendAdaptiveCard({ foo: "bar" }); - assert.deepStrictEqual(res, { id: undefined }); - }); - - it("sendAdaptiveCard should handle error", async () => { - sandbox.stub(CardFactory, "adaptiveCard").callsFake((card) => { - return { content: card } as any; - }); - const conversationRef = { - conversation: { - conversationType: "channel", - }, - }; - const installation = new TeamsBotInstallation(adapter, conversationRef as any); - activityResponse = { - id: "message-a", - }; - turnError = new Error("error-card-a"); - let errorMessage = ""; - await installation.sendAdaptiveCard({ foo: "bar" }, (ctx, err) => { - errorMessage = err.message; - return Promise.resolve(); - }); - assert.strictEqual(errorMessage, "error-card-a"); - }); - - it("sendAdaptiveCard should throw error if onError is undefined", async () => { - sandbox.stub(CardFactory, "adaptiveCard").callsFake((card) => { - return { content: card } as any; - }); - const conversationRef = { - conversation: { - conversationType: "channel", - }, - }; - const installation = new TeamsBotInstallation(adapter, conversationRef as any); - activityResponse = { - id: "message-a", - }; - turnError = new Error("error-card-a"); - let actualError: Error | undefined; - try { - await installation.sendAdaptiveCard({ foo: "bar" }); - } catch (error) { - actualError = error as Error; - } - assert.isDefined(actualError); - }); - - it("channels should return correct channels", async () => { - sandbox.stub(utils, "getTeamsBotInstallationId").returns("test"); - sandbox.stub(TeamsInfo, "getTeamChannels").resolves([{} as ChannelInfo, {} as ChannelInfo]); - const conversationRef = { - conversation: { - conversationType: "channel", - }, - }; - const installation = new TeamsBotInstallation(adapter, conversationRef as any); - assert.strictEqual(installation.type, NotificationTargetType.Channel); - assert.isTrue(installation.type === "Channel"); - const channels = await installation.channels(); - assert.strictEqual(channels.length, 2); - }); - - it("channels should return empty array if no teamId", async () => { - sandbox.stub(utils, "getTeamsBotInstallationId").returns(undefined); - const conversationRef = { - conversation: { - conversationType: "channel", - }, - }; - const installation = new TeamsBotInstallation(adapter, conversationRef as any); - assert.strictEqual(installation.type, NotificationTargetType.Channel); - assert.isTrue(installation.type === "Channel"); - const channels = await installation.channels(); - assert.strictEqual(channels.length, 0); - }); - - it("channels should return empty array if conversation type is not channel", async () => { - sandbox.stub(utils, "getTeamsBotInstallationId").returns("test"); - sandbox.stub(TeamsInfo, "getTeamChannels").resolves([{} as ChannelInfo, {} as ChannelInfo]); - - const conversationRef = { - conversation: { - conversationType: "personal", - }, - }; - const installation = new TeamsBotInstallation(adapter, conversationRef as any); - assert.isTrue(installation.type !== "Channel"); - const channels = await installation.channels(); - assert.strictEqual(channels.length, 0); - }); - - it("members should return correct members", async () => { - sandbox.stub(TeamsInfo, "getPagedMembers").resolves({ - continuationToken: undefined as unknown as string, - members: [{} as TeamsChannelAccount, {} as TeamsChannelAccount], - }); - const conversationRef = { - conversation: { - conversationType: "channel", - }, - }; - const installation = new TeamsBotInstallation(adapter, conversationRef as any); - assert.strictEqual(installation.type, NotificationTargetType.Channel); - assert.isTrue(installation.type === "Channel"); - const members = await installation.members(); - assert.strictEqual(members.length, 2); - }); - - it("getTeamDetails should return correct team details", async () => { - sandbox.stub(utils, "getTeamsBotInstallationId").returns("test"); - sandbox - .stub(TeamsInfo, "getTeamDetails") - .resolves({ id: "test", name: "test-team" } as TeamDetails); - const conversationRef = { - conversation: { - conversationType: "channel", - }, - }; - const installation = new TeamsBotInstallation(adapter, conversationRef as any); - const teamDetails = await installation.getTeamDetails(); - assert.strictEqual(teamDetails?.id, "test"); - assert.strictEqual(teamDetails?.name, "test-team"); - }); - - it("getTeamDetails should return undefined if conversation type is not channel", async () => { - const conversationRef = { - conversation: { - conversationType: "personal", - }, - }; - const installation = new TeamsBotInstallation(adapter, conversationRef as any); - const teamDetails = await installation.getTeamDetails(); - assert.isUndefined(teamDetails); - }); - }); -}); - -describe("Notification Bot Tests - Node", () => { - const sandbox = sinon.createSandbox(); - let adapter: BotFrameworkAdapter; - let storage: TestStorage; - let middlewares: any[]; - - beforeEach(() => { - middlewares = []; - const stubContext = sandbox.createStubInstance(TurnContext); - const stubAdapter = sandbox.createStubInstance(BotFrameworkAdapter); - stubAdapter.use.callsFake((args) => { - middlewares.push(args); - return stubAdapter; - }); - ( - stubAdapter.continueConversation as unknown as sinon.SinonStub< - [Partial, (context: TurnContext) => Promise], - Promise - > - ).callsFake(async (ref, logic) => { - await logic(stubContext); - }); - adapter = stubAdapter; - storage = new TestStorage(); - }); - - afterEach(() => { - sandbox.restore(); - }); - - it("initialize notification should create correct middleware", () => { - const notificationBot = new NotificationBot(adapter, { storage: storage }); - assert.strictEqual(middlewares.length, 1); - assert.isTrue(middlewares[0] instanceof NotificationMiddleware); - }); - - it("installations should return correct targets", async () => { - sandbox.stub(TeamsInfo, "getPagedMembers").callsFake((ctx, pageSize, continuationToken) => { - return new Promise((resolve) => resolve({ continuationToken: "", members: [] })); - }); - - const notificationBot = new NotificationBot(adapter, { storage: storage }); - storage.items = { - _a_1: { - channelId: "1", - conversation: { - id: "1", - tenantId: "a", - }, - }, - _a_2: { - channelId: "2", - conversation: { - id: "2", - tenantId: "a", - }, - }, - }; - const installations = await notificationBot.installations(); - assert.strictEqual(installations.length, 2); - assert.strictEqual(installations[0].conversationReference.conversation?.id, "1"); - assert.strictEqual(installations[1].conversationReference.conversation?.id, "2"); - }); - - it("installations should remove invalid target", async () => { - sandbox.stub(TeamsInfo, "getPagedMembers").callsFake((ctx, pageSize, continuationToken) => { - throw { - name: "test", - message: "test", - code: "BotNotInConversationRoster", - }; - }); - - const notificationBot = new NotificationBot(adapter, { storage: storage }); - storage.items = { - _a_1: { - channelId: "1", - conversation: { - id: "1", - tenantId: "a", - }, - }, - }; - const installations = await notificationBot.installations(); - assert.strictEqual(installations.length, 0); - assert.deepStrictEqual(storage.items, {}); - }); - - it("installations should keep valid target", async () => { - sandbox.stub(TeamsInfo, "getPagedMembers").callsFake((ctx, pageSize, continuationToken) => { - throw { - name: "test", - message: "test", - code: "Throttled", - }; - }); - - const notificationBot = new NotificationBot(adapter, { storage: storage }); - storage.items = { - _a_1: { - channelId: "1", - conversation: { - id: "1", - tenantId: "a", - }, - }, - }; - const installations = await notificationBot.installations(); - assert.strictEqual(installations.length, 1); - assert.strictEqual(installations[0].conversationReference.conversation?.id, "1"); - assert.deepStrictEqual(storage.items, { - _a_1: { - channelId: "1", - conversation: { - id: "1", - tenantId: "a", - }, - }, - }); - }); - - it("findMember should return correct member", async () => { - sandbox.stub(TeamsInfo, "getPagedMembers").callsFake((ctx, pageSize, continuationToken) => { - return new Promise((resolve) => - resolve({ - continuationToken: undefined as unknown as string, - members: [ - { - id: "foo", - name: "foo", - } as TeamsChannelAccount, - ], - }) - ); - }); - - const notificationBot = new NotificationBot(adapter, { storage: storage }); - storage.items = { - _a_1: { - channelId: "1", - conversation: { - conversationType: "channel", - id: "1", - tenantId: "a", - }, - }, - }; - - const member = await notificationBot.findMember((m) => - Promise.resolve(m.account.name === "foo") - ); - assert.strictEqual(member?.account.id, "foo"); - }); - - it("findMember should return undefined", async () => { - sandbox.stub(TeamsInfo, "getPagedMembers").callsFake((ctx, pageSize, continuationToken) => { - return new Promise((resolve) => - resolve({ - continuationToken: undefined as unknown as string, - members: [], - }) - ); - }); - - const notificationBot = new NotificationBot(adapter, { storage: storage }); - const member = await notificationBot.findMember((m) => - Promise.resolve(m.account.name === "NotFound") - ); - assert.isUndefined(member); - }); - - it("findAllMembers should return an array of correct members", async () => { - sandbox.stub(TeamsInfo, "getPagedMembers").callsFake((ctx, pageSize, continuationToken) => { - return new Promise((resolve) => - resolve({ - continuationToken: undefined as unknown as string, - members: [ - { - email: "a@contoso.com", - } as TeamsChannelAccount, - { - email: "b@contoso.com", - } as TeamsChannelAccount, - { - email: "c@foo.com", - } as TeamsChannelAccount, - ], - }) - ); - }); - - const notificationBot = new NotificationBot(adapter, { storage: storage }); - storage.items = { - _a_1: { - channelId: "1", - conversation: { - conversationType: "channel", - id: "1", - tenantId: "a", - }, - }, - }; - - const members = await notificationBot.findAllMembers((m) => - Promise.resolve(m.account.email?.endsWith("contoso.com") === true) - ); - assert.lengthOf(members, 2); - }); - - it("findChannel should return correct channel", async () => { - sandbox.stub(utils, "getTeamsBotInstallationId").returns("test"); - sandbox.stub(TeamsInfo, "getTeamDetails").resolves({ id: "test" } as TeamDetails); - sandbox.stub(TeamsInfo, "getTeamChannels").resolves([{ id: "1" } as ChannelInfo]); - sandbox.stub(TeamsInfo, "getPagedMembers").callsFake((ctx, pageSize, continuationToken) => { - return new Promise((resolve) => - resolve({ - continuationToken: undefined as unknown as string, - members: [], - }) - ); - }); - - const notificationBot = new NotificationBot(adapter, { storage: storage }); - storage.items = { - _a_1: { - channelId: "1", - conversation: { - conversationType: "channel", - id: "1", - tenantId: "a", - }, - }, - }; - - const channel = await notificationBot.findChannel((c) => Promise.resolve(c.info.id === "1")); - assert.strictEqual(channel?.info.id, "1"); - }); - - it("findAllChannels should return an array of correct channel", async () => { - sandbox.stub(utils, "getTeamsBotInstallationId").returns("test"); - sandbox.stub(TeamsInfo, "getTeamDetails").resolves({ id: "test" } as TeamDetails); - sandbox.stub(TeamsInfo, "getTeamChannels").resolves([{ id: "1" } as ChannelInfo]); - sandbox.stub(TeamsInfo, "getPagedMembers").callsFake((ctx, pageSize, continuationToken) => { - return new Promise((resolve) => - resolve({ - continuationToken: undefined as unknown as string, - members: [], - }) - ); - }); - - const notificationBot = new NotificationBot(adapter, { storage: storage }); - storage.items = { - _a_1: { - channelId: "1", - conversation: { - conversationType: "channel", - id: "1", - tenantId: "a", - }, - }, - }; - - const channels = await notificationBot.findAllChannels((channel, team) => - Promise.resolve(team?.id === "test") - ); - assert.lengthOf(channels, 1); - }); - - it("findChannel should return undefined", async () => { - sandbox.stub(utils, "getTeamsBotInstallationId").returns("test"); - sandbox.stub(TeamsInfo, "getTeamDetails").resolves({ id: "test" } as TeamDetails); - sandbox.stub(TeamsInfo, "getTeamChannels").resolves([{ id: "1" } as ChannelInfo]); - sandbox.stub(TeamsInfo, "getPagedMembers").callsFake((ctx, pageSize, continuationToken) => { - return new Promise((resolve) => - resolve({ - continuationToken: undefined as unknown as string, - members: [], - }) - ); - }); - - const notificationBot = new NotificationBot(adapter, { storage: storage }); - const channel = await notificationBot.findChannel((c) => - Promise.resolve(c.info.id === "NotFound") - ); - assert.isUndefined(channel); - }); -}); diff --git a/packages/sdk/test/unit/node/conversation/sso/defaultSsoExecutionActivityHandler.spec.ts b/packages/sdk/test/unit/node/conversation/sso/defaultSsoExecutionActivityHandler.spec.ts index e94d6d8763..378bed5317 100644 --- a/packages/sdk/test/unit/node/conversation/sso/defaultSsoExecutionActivityHandler.spec.ts +++ b/packages/sdk/test/unit/node/conversation/sso/defaultSsoExecutionActivityHandler.spec.ts @@ -5,14 +5,12 @@ import { assert } from "chai"; import { ConversationState, MemoryStorage, TurnContext, UserState } from "botbuilder"; import * as sinon from "sinon"; import { CustomStorage } from "../testUtils"; -import mockedEnv from "mocked-env"; import { DefaultBotSsoExecutionActivityHandler } from "../../../../../src/conversation/sso/defaultBotSsoExecutionActivityHandler"; import { BotSsoExecutionDialog } from "../../../../../src/conversation/sso/botSsoExecutionDialog"; import { BotSsoConfig } from "../../../../../src/conversation/interface"; +// eslint-disable-next-line no-secrets/no-secrets describe("DefaultBotSsoExecutionActivityHandler Tests - Node", () => { - let mockedEnvRestore: () => void; - const sandbox = sinon.createSandbox(); const clientId = "fake_client_id"; @@ -23,21 +21,16 @@ describe("DefaultBotSsoExecutionActivityHandler Tests - Node", () => { const ssoConfig: BotSsoConfig = { aad: { scopes: ["User.Read"], + clientId, + clientSecret, + tenantId, + authorityHost, + initiateLoginEndpoint, }, }; - beforeEach(() => { - mockedEnvRestore = mockedEnv({ - INITIATE_LOGIN_ENDPOINT: initiateLoginEndpoint, - M365_CLIENT_ID: clientId, - M365_CLIENT_SECRET: clientSecret, - M365_TENANT_ID: tenantId, - M365_AUTHORITY_HOST: authorityHost, - }); - }); afterEach(() => { sandbox.restore(); - mockedEnvRestore(); }); it("create default sso execution activity handler should work", () => { @@ -71,6 +64,11 @@ describe("DefaultBotSsoExecutionActivityHandler Tests - Node", () => { }, aad: { scopes: ["User.Read"], + clientId, + clientSecret, + tenantId, + authorityHost, + initiateLoginEndpoint, }, }; const defaultBotSsoExecutionActivityHandler: any = new DefaultBotSsoExecutionActivityHandler( diff --git a/packages/sdk/test/unit/node/conversation/sso/ssoExecutionDialog.spec.ts b/packages/sdk/test/unit/node/conversation/sso/ssoExecutionDialog.spec.ts index f2289a5991..d7532e26b6 100644 --- a/packages/sdk/test/unit/node/conversation/sso/ssoExecutionDialog.spec.ts +++ b/packages/sdk/test/unit/node/conversation/sso/ssoExecutionDialog.spec.ts @@ -24,7 +24,6 @@ import { ErrorWithCode, ErrorCode, TeamsBotSsoPromptSettings, - TeamsFx, BotSsoExecutionDialog, TeamsBotSsoPromptTokenResponse, CommandMessage, @@ -59,6 +58,13 @@ describe("BotSsoExecutionDialog Tests - Node", () => { const id = "fake_id"; const exchangeToken = "fake_exchange_token"; + const OnBehalfOfCredentialAuthConfig = { + authorityHost: authorityHost, + clientId: clientId, + clientSecret: clientSecret, + tenantId: tenantId, + }; + /** * { * "aud": "test_audience", @@ -130,6 +136,30 @@ describe("BotSsoExecutionDialog Tests - Node", () => { mockedEnvRestore(); }); + it("should add TeamsBotSsoPrompt and WaterfallDialog to the dialog set", () => { + // Arrange + const mockStorage = new MemoryStorage(); + const mockSsoPromptSettings: TeamsBotSsoPromptSettings = { + scopes: requiredScopes, + }; + const mockDialogName = "testDialog"; + + const botSsoExecutionDialog = new BotSsoExecutionDialog( + mockStorage, + mockSsoPromptSettings, + OnBehalfOfCredentialAuthConfig, + initiateLoginEndpoint, + mockDialogName + ); + + // Act + const dialogs = botSsoExecutionDialog.dialogs; + + // Assert + assert.isNotNull(dialogs.find(mockDialogName + "TeamsFxSsoPrompt")); + assert.isNotNull(dialogs.find(mockDialogName + "CommandRouteDialog")); + }); + it("sso execution dialog should response 'Cannot find command' error when command doesn't exist", async function () { this.timeout(500); const adapter: TestAdapter = await initializeTestEnv(); @@ -336,14 +366,14 @@ describe("BotSsoExecutionDialog Tests - Node", () => { function assertTeamsSsoOauthCardActivity(activity: Partial): void { assert.isArray(activity.attachments); assert.strictEqual(activity.attachments?.length, 1); - assert.strictEqual(activity.attachments![0].contentType, CardFactory.contentTypes.oauthCard); + assert.strictEqual(activity.attachments?.[0].contentType, CardFactory.contentTypes.oauthCard); assert.strictEqual(activity.inputHint, InputHints.AcceptingInput); - assert.strictEqual(activity.attachments![0].content.buttons[0].type, ActionTypes.Signin); - assert.strictEqual(activity.attachments![0].content.buttons[0].title, "Teams SSO Sign In"); + assert.strictEqual(activity.attachments?.[0].content.buttons[0].type, ActionTypes.Signin); + assert.strictEqual(activity.attachments?.[0].content.buttons[0].title, "Teams SSO Sign In"); assert.strictEqual( - activity.attachments![0].content.buttons[0].value, + activity.attachments?.[0].content.buttons[0].value, `${initiateLoginEndpoint}?scope=${encodeURI( requiredScopes.join(" ") )}&clientId=${clientId}&tenantId=${tenantId}&loginHint=${userPrincipalName}` @@ -385,13 +415,17 @@ describe("BotSsoExecutionDialog Tests - Node", () => { convoState.createProperty("dialogState"); const dialogs: DialogSet = new DialogSet(dialogState); - const teamsfx = new TeamsFx(); const ssoPromptSettings: TeamsBotSsoPromptSettings = { scopes: requiredScopes, timeout: timeout_value, endOnInvalidMessage: endOnInvalidMessage, }; - const ssoExecutionDialog = new BotSsoExecutionDialog(storage, ssoPromptSettings, teamsfx); + const ssoExecutionDialog = new BotSsoExecutionDialog( + storage, + ssoPromptSettings, + OnBehalfOfCredentialAuthConfig, + initiateLoginEndpoint + ); const testHandler = new TestSsoCommandHandler(triggerPatterns, testSsoHandlerResponseMessage); ssoExecutionDialog.addCommand( async ( diff --git a/packages/sdk/test/unit/node/conversation/storage.spec.ts b/packages/sdk/test/unit/node/conversation/storage.spec.ts index 6b3f0eb126..5ca71fc619 100644 --- a/packages/sdk/test/unit/node/conversation/storage.spec.ts +++ b/packages/sdk/test/unit/node/conversation/storage.spec.ts @@ -6,222 +6,76 @@ import { assert, use as chaiUse } from "chai"; import * as chaiPromises from "chai-as-promised"; import * as fs from "fs"; import * as sinon from "sinon"; -import { - DefaultConversationReferenceStore, - LocalFileStorage, -} from "../../../../src/conversation/storage"; -import { TestStorage } from "./testUtils"; +import { DefaultConversationReferenceStore } from "../../../../src/conversation/storage"; import * as path from "path"; chaiUse(chaiPromises); -describe("Notification.Storage Tests - Node", () => { - describe("LocalFileStorage Tests - Node", () => { - const sandbox = sinon.createSandbox(); - let fileContent = ""; - let fileExists = true; - let filePath = ""; - let localFileStorage: LocalFileStorage; +describe("DefaultConversationReferenceStore Tests - Node", () => { + const testDir = "./test/"; + const localFileName = ".notification.localstore.json"; + const testPath = path.join(testDir, localFileName); + let testStore: DefaultConversationReferenceStore; - beforeEach(() => { - sandbox.stub(fs, "access").callsFake((path, cb) => { - filePath = path.toString(); - if (fileExists) { - cb(null); - } else { - cb(new Error("Test file not exist")); - } - }); - ( - sandbox.stub(fs, "readFile") as unknown as sinon.SinonStub< - [fs.PathOrFileDescriptor, any, (err: NodeJS.ErrnoException | null, data: string) => void], - void - > - ).callsFake((path, options, cb) => { - if (fileExists) { - cb(null, fileContent); - } else { - cb(new Error("Test file not exist"), ""); - } - }); - ( - sandbox.stub(fs, "writeFile") as unknown as sinon.SinonStub< - [fs.PathOrFileDescriptor, string, any, fs.NoParamCallback], - void - > - ).callsFake((path, data, options, cb) => { - fileExists = true; - fileContent = data.toString(); - cb(null); - }); - localFileStorage = new LocalFileStorage("test"); - }); - - afterEach(() => { - sandbox.restore(); - fileContent = ""; - fileExists = false; - }); - - it("read should return undefined if file not exist", async () => { - fileExists = false; - const data = await localFileStorage.read("key"); - assert.isUndefined(data); - assert.strictEqual(path.basename(filePath), ".notification.localstore.json"); - }); - - it("read should load file name from env", async () => { - const oldEnv = process.env.TEAMSFX_NOTIFICATION_STORE_FILENAME; - process.env.TEAMSFX_NOTIFICATION_STORE_FILENAME = ".notification.testtool.json"; - fileExists = false; - - const data = await localFileStorage.read("key"); - assert.isUndefined(data); - assert.strictEqual(path.basename(filePath), ".notification.testtool.json"); - - process.env.TEAMSFX_NOTIFICATION_STORE_FILENAME = oldEnv; - }); - - it("read should return correct data", async () => { - fileContent = `{ - "key1": { "foo": "bar" }, - "key2": "B" - }`; - fileExists = true; - const data = await localFileStorage.read("key1"); - assert.deepStrictEqual(data, { foo: "bar" }); - }); - - it("read should return undefined if key not exist", async () => { - fileContent = `{ - "key1": { "foo": "bar" }, - "key2": "B" - }`; - fileExists = true; - const data = await localFileStorage.read("key3"); - assert.isUndefined(data); - }); - - it("list should return empty array if file not exist", async () => { - fileExists = false; - const data = await localFileStorage.list(); - assert.strictEqual(data.length, 0); - }); - - it("list should return correct data", async () => { - fileContent = `{ - "key1": { "foo1": "bar1" }, - "key2": { "foo2": "bar2" } - }`; - fileExists = true; - const data = await localFileStorage.list(); - assert.deepStrictEqual(data, [{ foo1: "bar1" }, { foo2: "bar2" }]); - }); - - it("write should persist correct data", async () => { - fileContent = ""; - fileExists = false; - await localFileStorage.write("key1", { foo1: "bar1" }); - assert.strictEqual(fileExists, true); - assert.deepStrictEqual(JSON.parse(fileContent), { key1: { foo1: "bar1" } }); - }); - - it("write should override data", async () => { - fileContent = `{ - "key1": { "foo1": "bar1" }, - "key2": { "foo2": "bar2" } - }`; - fileExists = true; - await localFileStorage.write("key1", { fooX: "barX" }); - assert.strictEqual(fileExists, true); - assert.deepStrictEqual(JSON.parse(fileContent), { - key1: { fooX: "barX" }, - key2: { foo2: "bar2" }, - }); - }); - - it("delete should ignore if file not exist", async () => { - fileContent = ""; - fileExists = false; - await localFileStorage.delete("key"); - assert.isFalse(fileExists); - }); - - it("delete should remove correct data", async () => { - fileContent = `{ - "key1": { "foo1": "bar1" }, - "key2": { "foo2": "bar2" } - }`; - fileExists = true; - await localFileStorage.delete("key1"); - assert.strictEqual(fileExists, true); - assert.deepStrictEqual(JSON.parse(fileContent), { key2: { foo2: "bar2" } }); - }); - - it("delete should ignore if key not found", async () => { - fileContent = `{ - "key1": { "foo1": "bar1" } - }`; - fileExists = true; - await localFileStorage.delete("key2"); - assert.strictEqual(fileExists, true); - assert.deepStrictEqual(JSON.parse(fileContent), { key1: { foo1: "bar1" } }); - }); + beforeEach(() => { + testStore = new DefaultConversationReferenceStore(testDir); }); - describe("DefaultConversationReferenceStore Tests - Node", () => { - const storage = new TestStorage(); - const testStore = new DefaultConversationReferenceStore(storage); + afterEach(() => { + if (fs.existsSync(testPath)) { + fs.unlinkSync(testPath); + } + sinon.restore(); + }); - it("list should return correct data", async () => { - storage.items = {}; - storage.items["_a_1"] = { + it("list should return correct data", async () => { + fs.writeFileSync( + testPath, + JSON.stringify({ _a_1: { conversation: { id: "1", tenantId: "a" } } }), + "utf8" + ); + const { data } = await testStore.list(); + assert.deepStrictEqual(data, [ + { conversation: { id: "1", tenantId: "a", }, - }; - const { data } = await testStore.list(); - assert.deepStrictEqual(data, [ - { - conversation: { - id: "1", - tenantId: "a", - }, - } as ConversationReference, - ]); - }); + } as ConversationReference, + ]); + }); - it("list should return empty data if storage is empty", async () => { - storage.items = {}; - const { data } = await testStore.list(); - assert.strictEqual(data.length, 0); - }); + it("list should return empty data if storage is empty", async () => { + const { data } = await testStore.list(); + assert.strictEqual(data.length, 0); + }); - it("add should persist correct data", async () => { - storage.items = {}; - await testStore.add( - "_a_1", - { - conversation: { - id: "1", - tenantId: "a", - }, - } as ConversationReference, - { overwrite: true } - ); - assert.deepStrictEqual(storage.items, { - _a_1: { - conversation: { - id: "1", - tenantId: "a", - }, + it("add should persist correct data", async () => { + await testStore.add( + "_a_1", + { + conversation: { + id: "1", + tenantId: "a", + }, + } as ConversationReference, + { overwrite: true } + ); + const fileData = JSON.parse(fs.readFileSync(testPath).toString()); + assert.deepStrictEqual(fileData, { + _a_1: { + conversation: { + id: "1", + tenantId: "a", }, - }); + }, }); + }); - it("add with overwrite should update existing data", async () => { - storage.items = { + it("add with overwrite should update existing data", async () => { + fs.writeFileSync( + testPath, + JSON.stringify({ _a_1: { channelId: "1", conversation: { @@ -229,53 +83,37 @@ describe("Notification.Storage Tests - Node", () => { tenantId: "a", }, }, - }; - const added = await testStore.add( - "_a_1", - { - channelId: "2", - conversation: { - id: "1", - tenantId: "a", - }, - } as ConversationReference, - { overwrite: true } - ); - assert.isTrue(added); - assert.deepStrictEqual(storage.items, { - _a_1: { - channelId: "2", - conversation: { - id: "1", - tenantId: "a", - }, + }), + "utf8" + ); + const added = await testStore.add( + "_a_1", + { + channelId: "2", + conversation: { + id: "1", + tenantId: "a", + }, + } as ConversationReference, + { overwrite: true } + ); + assert.isTrue(added); + const fileData = JSON.parse(fs.readFileSync(testPath).toString()); + assert.deepStrictEqual(fileData, { + _a_1: { + channelId: "2", + conversation: { + id: "1", + tenantId: "a", }, - }); + }, }); + }); - it("add without overwrite should skip updating existing data", async () => { - storage.items = { - _a_1: { - channelId: "1", - conversation: { - id: "1", - tenantId: "a", - }, - }, - }; - const added = await testStore.add( - "_a_1", - { - channelId: "2", - conversation: { - id: "1", - tenantId: "a", - }, - } as ConversationReference, - { overwrite: false } - ); - assert.isFalse(added); - assert.deepStrictEqual(storage.items, { + it("add without overwrite should skip updating existing data", async () => { + fs.writeFileSync( + testPath, + JSON.stringify({ _a_1: { channelId: "1", conversation: { @@ -283,37 +121,63 @@ describe("Notification.Storage Tests - Node", () => { tenantId: "a", }, }, - }); - }); - - it("delete should remove correct data", async () => { - storage.items = {}; - storage.items["_a_1"] = { + }), + "utf8" + ); + const added = await testStore.add( + "_a_1", + { + channelId: "2", conversation: { id: "1", tenantId: "a", }, - }; - const removed = await testStore.remove("_a_1", { + } as ConversationReference, + { overwrite: false } + ); + assert.isFalse(added); + + const fileData = JSON.parse(fs.readFileSync(testPath).toString()); + assert.deepStrictEqual(fileData, { + _a_1: { + channelId: "1", conversation: { id: "1", tenantId: "a", }, - } as ConversationReference); - assert.isTrue(removed); - assert.deepStrictEqual(storage.items, {}); + }, }); + }); - it("delete non-existing data should return correct result", async () => { - storage.items = {}; - const removed = await testStore.remove("_a_1", { - conversation: { - id: "1", - tenantId: "a", - }, - } as ConversationReference); - assert.isFalse(removed); - assert.deepStrictEqual(storage.items, {}); - }); + it("delete should remove correct data", async () => { + fs.writeFileSync( + testPath, + JSON.stringify({ _a_1: { conversation: { id: "1", tenantId: "a" } } }), + "utf8" + ); + + const removed = await testStore.remove("_a_1", { + conversation: { + id: "1", + tenantId: "a", + }, + } as ConversationReference); + assert.isTrue(removed); + + const fileData = JSON.parse(fs.readFileSync(testPath).toString()); + assert.deepStrictEqual(fileData, {}); + }); + + it("delete non-existing data should return correct result", async () => { + const removed = await testStore.remove("_a_1", { + conversation: { + id: "1", + tenantId: "a", + }, + } as ConversationReference); + assert.isFalse(removed); + + const fileData = fs.existsSync(testPath) ? JSON.parse(fs.readFileSync(testPath, "utf8")) : {}; + assert.deepStrictEqual(fileData, {}); }); }); diff --git a/packages/sdk/test/unit/node/conversation/testUtils.ts b/packages/sdk/test/unit/node/conversation/testUtils.ts index 1dc1884a36..4bbf1bd48e 100644 --- a/packages/sdk/test/unit/node/conversation/testUtils.ts +++ b/packages/sdk/test/unit/node/conversation/testUtils.ts @@ -9,45 +9,15 @@ import { InvokeResponseErrorCode, MessageResponse, NotificationTarget, - NotificationTargetStorage, NotificationTargetType, TeamsFxAdaptiveCardActionHandler, TeamsFxBotCommandHandler, TeamsFxBotSsoCommandHandler, TriggerPatterns, } from "../../../../src/conversation/interface"; - import { InvokeResponseFactory } from "../../../../src/conversation/invokeResponseFactory"; import { TeamsBotSsoPromptTokenResponse } from "../../../../src"; -export class TestStorage implements NotificationTargetStorage { - public items: any = {}; - - read(key: string): Promise<{ [key: string]: unknown } | undefined> { - return new Promise((resolve) => resolve(this.items[key])); - } - - list(): Promise<{ [key: string]: unknown }[]> { - return new Promise((resolve) => - resolve(Object.entries(this.items).map((entry) => entry[1] as { [key: string]: unknown })) - ); - } - - write(key: string, object: { [key: string]: unknown }): Promise { - return new Promise((resolve) => { - this.items[key] = object; - resolve(); - }); - } - - delete(key: string): Promise { - return new Promise((resolve) => { - delete this.items[key]; - resolve(); - }); - } -} - export class TestTarget implements NotificationTarget { public content: any; public type?: NotificationTargetType | undefined; @@ -101,7 +71,7 @@ export class TestSsoCommandHandler implements TeamsFxBotSsoCommandHandler { export class TestCommandHandler implements TeamsFxBotCommandHandler { public readonly triggerPatterns: TriggerPatterns; - public isInvoked: boolean = false; + public isInvoked = false; public lastReceivedMessage: CommandMessage | undefined; constructor(patterns: TriggerPatterns) { @@ -119,7 +89,7 @@ export class TestCommandHandler implements TeamsFxBotCommandHandler { } export class MockCardActionHandler implements TeamsFxAdaptiveCardActionHandler { - isInvoked: boolean = false; + isInvoked = false; triggerVerb: string; adaptiveCardResponse: AdaptiveCardResponse = AdaptiveCardResponse.ReplaceForInteractor; invokeResponse: InvokeResponse; @@ -144,7 +114,7 @@ export class MockCardActionHandler implements TeamsFxAdaptiveCardActionHandler { } export class MockCardActionHandlerWithErrorResponse implements TeamsFxAdaptiveCardActionHandler { - isInvoked: boolean = false; + isInvoked = false; triggerVerb: string; invokeResponse: InvokeResponse; actionData: any; diff --git a/packages/sdk/test/unit/node/conversationWithCloudAdapter/command.spec.ts b/packages/sdk/test/unit/node/conversationWithCloudAdapter/command.spec.ts index 1c750059fc..c97c25fa4c 100644 --- a/packages/sdk/test/unit/node/conversationWithCloudAdapter/command.spec.ts +++ b/packages/sdk/test/unit/node/conversationWithCloudAdapter/command.spec.ts @@ -7,16 +7,13 @@ import * as sinon from "sinon"; import { CommandBot } from "../../../../src/conversationWithCloudAdapter/command"; import { CommandResponseMiddleware } from "../../../../src/conversation/middlewares/commandMiddleware"; import { TestCommandHandler, TestSsoCommandHandler } from "../conversation/testUtils"; -import mockedEnv from "mocked-env"; import { DefaultBotSsoExecutionActivityHandler } from "../../../../src/conversation/sso/defaultBotSsoExecutionActivityHandler"; import { BotSsoConfig } from "../../../../src"; describe("CommandBot Tests - Node", () => { - let mockedEnvRestore: () => void; - const sandbox = sinon.createSandbox(); let adapter: CloudAdapter; - let middlewares: any[]; + let middlewares: unknown[]; const clientId = "fake_client_id"; const clientSecret = "fake_client_secret"; @@ -26,18 +23,15 @@ describe("CommandBot Tests - Node", () => { const ssoConfig: BotSsoConfig = { aad: { scopes: ["User.Read"], + clientId, + clientSecret, + tenantId, + authorityHost, + initiateLoginEndpoint, }, }; beforeEach(() => { - mockedEnvRestore = mockedEnv({ - INITIATE_LOGIN_ENDPOINT: initiateLoginEndpoint, - M365_CLIENT_ID: clientId, - M365_CLIENT_SECRET: clientSecret, - M365_TENANT_ID: tenantId, - M365_AUTHORITY_HOST: authorityHost, - }); - middlewares = []; const stubContext = sandbox.createStubInstance(TurnContext); const stubAdapter = sandbox.createStubInstance(CloudAdapter); @@ -58,11 +52,10 @@ describe("CommandBot Tests - Node", () => { afterEach(() => { sandbox.restore(); - mockedEnvRestore(); }); it("create command bot should add correct middleware", () => { - const commandBot = new CommandBot(adapter); + new CommandBot(adapter); assert.isTrue(middlewares[0] instanceof CommandResponseMiddleware); }); @@ -98,7 +91,7 @@ describe("CommandBot Tests - Node", () => { it("create sso command bot should add correct activity handler", () => { const defaultSsoHandler = new DefaultBotSsoExecutionActivityHandler(ssoConfig); - const commandBot = new CommandBot( + new CommandBot( adapter, { ssoCommands: [new TestSsoCommandHandler("test")], diff --git a/packages/sdk/test/unit/node/conversationWithCloudAdapter/notification.spec.ts b/packages/sdk/test/unit/node/conversationWithCloudAdapter/notification.spec.ts index 581f555e33..78ce877c35 100644 --- a/packages/sdk/test/unit/node/conversationWithCloudAdapter/notification.spec.ts +++ b/packages/sdk/test/unit/node/conversationWithCloudAdapter/notification.spec.ts @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ // Copyright (c) Microsoft Corporation. // Licensed under the MIT license. @@ -17,6 +18,8 @@ import { Conversations } from "botframework-connector/lib/connectorApi/connector import { assert, use as chaiUse } from "chai"; import * as chaiPromises from "chai-as-promised"; import * as sinon from "sinon"; +import * as fs from "fs"; +import * as path from "path"; import { NotificationTargetType } from "../../../../src/conversation/interface"; import { NotificationMiddleware } from "../../../../src/conversation/middlewares/notificationMiddleware"; import { @@ -28,7 +31,8 @@ import { TeamsBotInstallation, } from "../../../../src/conversationWithCloudAdapter/notification"; import * as utils from "../../../../src/conversation/utils"; -import { TestStorage, TestTarget } from "../conversation/testUtils"; +import { TestTarget } from "../conversation/testUtils"; +import { DefaultConversationReferenceStore } from "../../../../src/conversation/storage"; chaiUse(chaiPromises); @@ -394,7 +398,6 @@ describe("Notification Tests - Node", () => { content = ""; activityResponse = {}; turnError = undefined; - const fakeBotAppId = "fakeBotAppId"; const stubAdapter = sandbox.createStubInstance(CloudAdapter); ( stubAdapter.continueConversationAsync as unknown as sinon.SinonStub< @@ -629,24 +632,6 @@ describe("Notification Tests - Node", () => { assert.strictEqual(continuationToken, "token"); }); - it("members should return correct members", async () => { - sandbox.stub(TeamsInfo, "getPagedMembers").resolves({ - continuationToken: undefined as unknown as string, - members: [{} as TeamsChannelAccount, {} as TeamsChannelAccount], - }); - const conversationRef = { - conversation: { - conversationType: "channel", - }, - }; - const fakeBotAppId = "fakeBotAppId"; - const installation = new TeamsBotInstallation(adapter, conversationRef as any, fakeBotAppId); - assert.strictEqual(installation.type, NotificationTargetType.Channel); - assert.isTrue(installation.type === "Channel"); - const members = await installation.members(); - assert.strictEqual(members.length, 2); - }); - it("getTeamDetails should return correct team details", async () => { sandbox.stub(utils, "getTeamsBotInstallationId").returns("test"); sandbox @@ -680,15 +665,27 @@ describe("Notification Tests - Node", () => { describe("Notification Bot Tests - Node", () => { const sandbox = sinon.createSandbox(); + const fileDir = "./test/"; + const localFileName = ".notification.localstore.json"; + const filePath = path.join(fileDir, localFileName); + const rawData = { + _a_1: { + channelId: "1", + conversation: { + conversationType: "channel", + id: "1", + tenantId: "a", + }, + }, + }; let adapter: CloudAdapter; - let storage: TestStorage; + let store: DefaultConversationReferenceStore; let middlewares: any[]; beforeEach(() => { middlewares = []; const stubContext = sandbox.createStubInstance(TurnContext); const stubAdapter = sandbox.createStubInstance(CloudAdapter); - const fakeBotAppId = "fakeBotAppId"; stubAdapter.use.callsFake((args) => { middlewares.push(args); return stubAdapter; @@ -702,15 +699,18 @@ describe("Notification Bot Tests - Node", () => { await logic(stubContext); }); adapter = stubAdapter; - storage = new TestStorage(); + store = new DefaultConversationReferenceStore(fileDir); }); afterEach(() => { + if (fs.existsSync(filePath)) { + fs.unlinkSync(filePath); + } sandbox.restore(); }); it("initialize notification should create correct middleware", () => { - const notificationBot = new NotificationBot(adapter, { storage: storage }); + new NotificationBot(adapter, { store }); assert.strictEqual(middlewares.length, 1); assert.isTrue(middlewares[0] instanceof NotificationMiddleware); }); @@ -720,23 +720,26 @@ describe("Notification Bot Tests - Node", () => { return new Promise((resolve) => resolve({ continuationToken: "", members: [] })); }); - const notificationBot = new NotificationBot(adapter, { storage }); - storage.items = { - _a_1: { - channelId: "1", - conversation: { - id: "1", - tenantId: "a", + const notificationBot = new NotificationBot(adapter, { store }); + fs.writeFileSync( + filePath, + JSON.stringify({ + _a_1: { + channelId: "1", + conversation: { + id: "1", + tenantId: "a", + }, }, - }, - _a_2: { - channelId: "2", - conversation: { - id: "2", - tenantId: "a", + _a_2: { + channelId: "2", + conversation: { + id: "2", + tenantId: "a", + }, }, - }, - }; + }) + ); const { data: installations, continuationToken } = await notificationBot.getPagedInstallations(); assert.strictEqual(installations.length, 2); @@ -745,34 +748,6 @@ describe("Notification Bot Tests - Node", () => { assert.strictEqual(continuationToken, ""); }); - it("installations should return correct targets", async () => { - sandbox.stub(TeamsInfo, "getPagedMembers").callsFake((ctx, pageSize, continuationToken) => { - return new Promise((resolve) => resolve({ continuationToken: "", members: [] })); - }); - - const notificationBot = new NotificationBot(adapter, { storage: storage }); - storage.items = { - _a_1: { - channelId: "1", - conversation: { - id: "1", - tenantId: "a", - }, - }, - _a_2: { - channelId: "2", - conversation: { - id: "2", - tenantId: "a", - }, - }, - }; - const installations = await notificationBot.installations(); - assert.strictEqual(installations.length, 2); - assert.strictEqual(installations[0].conversationReference.conversation?.id, "1"); - assert.strictEqual(installations[1].conversationReference.conversation?.id, "2"); - }); - it("getPagedInstallations should remove invalid target", async () => { sandbox.stub(TeamsInfo, "getPagedMembers").callsFake((ctx, pageSize, continuationToken) => { throw { @@ -782,19 +757,13 @@ describe("Notification Bot Tests - Node", () => { }; }); - const notificationBot = new NotificationBot(adapter, { storage: storage }); - storage.items = { - _a_1: { - channelId: "1", - conversation: { - id: "1", - tenantId: "a", - }, - }, - }; + const notificationBot = new NotificationBot(adapter, { store }); + + fs.writeFileSync(filePath, JSON.stringify(rawData)); const { data: installations } = await notificationBot.getPagedInstallations(); + const removedData = JSON.parse(fs.readFileSync(filePath, "utf8")); assert.strictEqual(installations.length, 0); - assert.deepStrictEqual(storage.items, {}); + assert.deepStrictEqual(removedData, {}); }); it("getPagedInstallations should skip validation", async () => { @@ -806,56 +775,18 @@ describe("Notification Bot Tests - Node", () => { }; }); - const notificationBot = new NotificationBot(adapter, { storage: storage }); - storage.items = { - _a_1: { - channelId: "1", - conversation: { - id: "1", - tenantId: "a", - }, - }, - }; + const notificationBot = new NotificationBot(adapter, { store }); + fs.writeFileSync(filePath, JSON.stringify(rawData)); + const { data: installations } = await notificationBot.getPagedInstallations( undefined, undefined, false ); + const fileData = JSON.parse(fs.readFileSync(filePath, "utf8")); assert.strictEqual(installations.length, 1); assert.strictEqual(installations[0].conversationReference.conversation?.id, "1"); - assert.deepStrictEqual(storage.items, { - _a_1: { - channelId: "1", - conversation: { - id: "1", - tenantId: "a", - }, - }, - }); - }); - - it("installations should remove invalid target", async () => { - sandbox.stub(TeamsInfo, "getPagedMembers").callsFake((ctx, pageSize, continuationToken) => { - throw { - name: "test", - message: "test", - code: "BotNotInConversationRoster", - }; - }); - - const notificationBot = new NotificationBot(adapter, { storage: storage }); - storage.items = { - _a_1: { - channelId: "1", - conversation: { - id: "1", - tenantId: "a", - }, - }, - }; - const installations = await notificationBot.installations(); - assert.strictEqual(installations.length, 0); - assert.deepStrictEqual(storage.items, {}); + assert.deepStrictEqual(fileData, rawData); }); it("getPagedInstallations should keep valid target", async () => { @@ -867,61 +798,15 @@ describe("Notification Bot Tests - Node", () => { }; }); - const notificationBot = new NotificationBot(adapter, { storage }); - storage.items = { - _a_1: { - channelId: "1", - conversation: { - id: "1", - tenantId: "a", - }, - }, - }; - const { data: installations } = await notificationBot.getPagedInstallations(); - assert.strictEqual(installations.length, 1); - assert.strictEqual(installations[0].conversationReference.conversation?.id, "1"); - assert.deepStrictEqual(storage.items, { - _a_1: { - channelId: "1", - conversation: { - id: "1", - tenantId: "a", - }, - }, - }); - }); + const notificationBot = new NotificationBot(adapter, { store }); + fs.writeFileSync(filePath, JSON.stringify(rawData)); - it("installations should keep valid target", async () => { - sandbox.stub(TeamsInfo, "getPagedMembers").callsFake((ctx, pageSize, continuationToken) => { - throw { - name: "test", - message: "test", - code: "Throttled", - }; - }); + const { data: installations } = await notificationBot.getPagedInstallations(); + const fileData = JSON.parse(fs.readFileSync(filePath, "utf8")); - const notificationBot = new NotificationBot(adapter, { storage: storage }); - storage.items = { - _a_1: { - channelId: "1", - conversation: { - id: "1", - tenantId: "a", - }, - }, - }; - const installations = await notificationBot.installations(); assert.strictEqual(installations.length, 1); assert.strictEqual(installations[0].conversationReference.conversation?.id, "1"); - assert.deepStrictEqual(storage.items, { - _a_1: { - channelId: "1", - conversation: { - id: "1", - tenantId: "a", - }, - }, - }); + assert.deepStrictEqual(fileData, rawData); }); it("findMember should return correct member", async () => { @@ -939,17 +824,8 @@ describe("Notification Bot Tests - Node", () => { ); }); - const notificationBot = new NotificationBot(adapter, { storage: storage }); - storage.items = { - _a_1: { - channelId: "1", - conversation: { - conversationType: "channel", - id: "1", - tenantId: "a", - }, - }, - }; + const notificationBot = new NotificationBot(adapter, { store }); + fs.writeFileSync(filePath, JSON.stringify(rawData)); const member = await notificationBot.findMember((m) => Promise.resolve(m.account.name === "foo") @@ -967,7 +843,7 @@ describe("Notification Bot Tests - Node", () => { ); }); - const notificationBot = new NotificationBot(adapter, { storage: storage }); + const notificationBot = new NotificationBot(adapter, { store }); const member = await notificationBot.findMember((m) => Promise.resolve(m.account.name === "NotFound") ); @@ -994,17 +870,20 @@ describe("Notification Bot Tests - Node", () => { ); }); - const notificationBot = new NotificationBot(adapter, { storage: storage }); - storage.items = { - _a_1: { - channelId: "1", - conversation: { - conversationType: "channel", - id: "1", - tenantId: "a", + const notificationBot = new NotificationBot(adapter, { store }); + fs.writeFileSync( + filePath, + JSON.stringify({ + _a_1: { + channelId: "1", + conversation: { + conversationType: "channel", + id: "1", + tenantId: "a", + }, }, - }, - }; + }) + ); const members = await notificationBot.findAllMembers((m) => Promise.resolve(m.account.email?.endsWith("contoso.com") === true) @@ -1025,17 +904,8 @@ describe("Notification Bot Tests - Node", () => { ); }); - const notificationBot = new NotificationBot(adapter, { storage: storage }); - storage.items = { - _a_1: { - channelId: "1", - conversation: { - conversationType: "channel", - id: "1", - tenantId: "a", - }, - }, - }; + const notificationBot = new NotificationBot(adapter, { store }); + fs.writeFileSync(filePath, JSON.stringify(rawData)); const channel = await notificationBot.findChannel((c) => Promise.resolve(c.info.id === "1")); assert.strictEqual(channel?.info.id, "1"); @@ -1054,17 +924,8 @@ describe("Notification Bot Tests - Node", () => { ); }); - const notificationBot = new NotificationBot(adapter, { storage: storage }); - storage.items = { - _a_1: { - channelId: "1", - conversation: { - conversationType: "channel", - id: "1", - tenantId: "a", - }, - }, - }; + const notificationBot = new NotificationBot(adapter, { store }); + fs.writeFileSync(filePath, JSON.stringify(rawData)); const channels = await notificationBot.findAllChannels((channel, team) => Promise.resolve(team?.id === "test") @@ -1085,7 +946,7 @@ describe("Notification Bot Tests - Node", () => { ); }); - const notificationBot = new NotificationBot(adapter, { storage: storage }); + const notificationBot = new NotificationBot(adapter, { store }); const channel = await notificationBot.findChannel((c) => Promise.resolve(c.info.id === "NotFound") ); @@ -1101,7 +962,7 @@ describe("Notification Bot Tests - Node", () => { tenantId: "a", }, } as ConversationReference; - const notificationBot = new NotificationBot(adapter, { storage }); + const notificationBot = new NotificationBot(adapter, { store }); const installation = notificationBot.buildTeamsBotInstallation(reference); assert.isNotNull(installation); }); diff --git a/packages/sdk/test/unit/node/core/onBehalfOfUserCredential.spec.ts b/packages/sdk/test/unit/node/core/onBehalfOfUserCredential.spec.ts index e8697ce1ce..175526037f 100644 --- a/packages/sdk/test/unit/node/core/onBehalfOfUserCredential.spec.ts +++ b/packages/sdk/test/unit/node/core/onBehalfOfUserCredential.spec.ts @@ -4,9 +4,9 @@ import { assert, expect, use as chaiUse } from "chai"; import * as chaiPromises from "chai-as-promised"; import { - AuthenticationConfiguration, ErrorCode, ErrorWithCode, + OnBehalfOfCredentialAuthConfig, OnBehalfOfUserCredential, UserInfo, } from "../../../../src"; @@ -63,7 +63,7 @@ fakeCert uti: "test_uti", ver: "2.0", }); - const authConfig: AuthenticationConfiguration = { + const authConfig: OnBehalfOfCredentialAuthConfig = { clientId: clientId, clientSecret: clientSecret, authorityHost: authorityHost, @@ -130,12 +130,12 @@ fakeCert certificateContent: certificateContent, authorityHost: authorityHost, tenantId: tenantId, - }); + } as unknown as OnBehalfOfCredentialAuthConfig); // certificateContent has higher priority than clientSecret assert.strictEqual( - oboCredential.msalClient.config.auth.clientCertificate.thumbprint, - "06BA994A93FF2138DC51E669EB284ABAB8112153" // thumbprint is calculated from certificate content "fakeCert" + oboCredential.msalClient.config.auth.clientCertificate.thumbprintSha256, + "90AF5A3B906DCC32226BCCD6D369165CFB9F1E0FE123F0D18B7CC48261995A6C" // thumbprint is calculated from certificate content "fakeCert" ); assert.strictEqual(oboCredential.msalClient.config.auth.clientSecret, ""); }); @@ -146,7 +146,7 @@ fakeCert clientSecret: clientSecret, authorityHost: authorityHost, tenantId: tenantId, - }); + } as unknown as OnBehalfOfCredentialAuthConfig); }) .to.throw(ErrorWithCode, "clientId in configuration is invalid: undefined") .with.property("code", InvalidConfiguration); @@ -158,7 +158,7 @@ fakeCert clientSecret: clientSecret, clientId: clientId, tenantId: tenantId, - }); + } as unknown as OnBehalfOfCredentialAuthConfig); }) .to.throw(ErrorWithCode, "authorityHost in configuration is invalid: undefined") .with.property("code", InvalidConfiguration); @@ -170,7 +170,7 @@ fakeCert clientId: clientId, authorityHost: authorityHost, tenantId: tenantId, - }); + } as unknown as OnBehalfOfCredentialAuthConfig); }) .to.throw( ErrorWithCode, @@ -185,7 +185,7 @@ fakeCert clientId: clientId, clientSecret: clientSecret, authorityHost: authorityHost, - }); + } as unknown as OnBehalfOfCredentialAuthConfig); }) .to.throw(ErrorWithCode, "tenantId in configuration is invalid: undefined") .with.property("code", InvalidConfiguration); @@ -193,7 +193,7 @@ fakeCert it("create OnBehalfOfUserCredential instance should throw InvalidConfiguration Error when clientId, clientSecret, certificateContent, authorityHost, tenantId not found", async function () { expect(() => { - new OnBehalfOfUserCredential(ssoToken, {}); + new OnBehalfOfUserCredential(ssoToken, {} as unknown as OnBehalfOfCredentialAuthConfig); }) .to.throw( ErrorWithCode, @@ -236,37 +236,37 @@ fakeCert tenantId: tenantId, }); const token = await oboCredential.getToken(scope); - assert.strictEqual(token!.token, accessToken); - assert.strictEqual(token!.expiresOnTimestamp, accessTokenExpNumber); + assert.strictEqual(token?.token, accessToken); + assert.strictEqual(token?.expiresOnTimestamp, accessTokenExpNumber); }); it("getToken should success when scopes is empty string", async function () { const oboCredential = new OnBehalfOfUserCredential(ssoToken, authConfig); const token = await oboCredential.getToken(""); - assert.strictEqual(token!.token, ssoToken); - assert.strictEqual(token!.expiresOnTimestamp, ssoTokenExp); + assert.strictEqual(token?.token, ssoToken); + assert.strictEqual(token?.expiresOnTimestamp, ssoTokenExp); }); it("getToken should success when scopes is empty array", async function () { const oboCredential = new OnBehalfOfUserCredential(ssoToken, authConfig); const token = await oboCredential.getToken([]); - assert.strictEqual(token!.token, ssoToken); - assert.strictEqual(token!.expiresOnTimestamp, ssoTokenExp); + assert.strictEqual(token?.token, ssoToken); + assert.strictEqual(token?.expiresOnTimestamp, ssoTokenExp); }); it("getToken should success when scopes is string", async function () { const oboCredential = new OnBehalfOfUserCredential(ssoToken, authConfig); const token = await oboCredential.getToken(scope); - assert.strictEqual(token!.token, accessToken); - assert.strictEqual(token!.expiresOnTimestamp, accessTokenExpNumber); + assert.strictEqual(token?.token, accessToken); + assert.strictEqual(token?.expiresOnTimestamp, accessTokenExpNumber); }); it("getToken should success when scopes is string array", async function () { const oboCredential = new OnBehalfOfUserCredential(ssoToken, authConfig); const scopesArray: string[] = [scope, "fake_scope_2"]; const token = await oboCredential.getToken(scopesArray); - assert.strictEqual(token!.token, accessToken); - assert.strictEqual(token!.expiresOnTimestamp, accessTokenExpNumber); + assert.strictEqual(token?.token, accessToken); + assert.strictEqual(token?.expiresOnTimestamp, accessTokenExpNumber); }); it("getToken should throw TokenExpiredError when get SSO token with sso token expired", async function () { @@ -288,16 +288,16 @@ fakeCert const credential = new OnBehalfOfUserCredential(expiredSsoToken, authConfig); let err = await expect(credential.getToken([])).to.eventually.be.rejectedWith(ErrorWithCode); assert.strictEqual(err.code, ErrorCode.TokenExpiredError); - assert.strictEqual(err.message!, "Sso token has already expired."); + assert.strictEqual(err.message, "Sso token has already expired."); err = await expect(credential.getToken("")).to.eventually.be.rejectedWith(ErrorWithCode); assert.strictEqual(err.code, ErrorCode.TokenExpiredError); - assert.strictEqual(err.message!, "Sso token has already expired."); + assert.strictEqual(err.message, "Sso token has already expired."); err = await expect(credential.getToken(scope)).to.eventually.be.rejectedWith(ErrorWithCode); assert.strictEqual(err.code, ErrorCode.TokenExpiredError); assert.isTrue( - err.message!.indexOf( + err.message?.indexOf( "Failed to get access token from AAD server, assertion is invalid because of various reasons: " ) >= 0 ); @@ -320,7 +320,7 @@ fakeCert ); assert.strictEqual(errorResult.code, ServiceError); assert.isTrue( - errorResult.message!.indexOf("Failed to acquire access token on behalf of user: ") >= 0 + errorResult.message?.indexOf("Failed to acquire access token on behalf of user: ") >= 0 ); }); diff --git a/packages/sdk/test/unit/node/messageExtension/executeWithToken.spec.ts b/packages/sdk/test/unit/node/messageExtension/executeWithToken.spec.ts index c772ea727b..ffd2c8eb45 100644 --- a/packages/sdk/test/unit/node/messageExtension/executeWithToken.spec.ts +++ b/packages/sdk/test/unit/node/messageExtension/executeWithToken.spec.ts @@ -1,10 +1,10 @@ +/* eslint-disable no-secrets/no-secrets */ // Copyright (c) Microsoft Corporation. // Licensed under the MIT license. import { AccessToken } from "@azure/identity"; import { ErrorCode, ErrorWithCode } from "../../../../src/core/errors"; import { handleMessageExtensionQueryWithSSO, - handleMessageExtensionQueryWithToken, handleMessageExtensionLinkQueryWithSSO, } from "../../../../src/messageExtension/executeWithSSO"; import { MessageExtensionTokenResponse } from "../../../../src/messageExtension/teamsMsgExtTokenResponse"; @@ -21,10 +21,7 @@ import { ConversationReference, } from "botbuilder-core"; import mockedEnv from "mocked-env"; -import { - AuthenticationConfiguration, - OnBehalfOfCredentialAuthConfig, -} from "../../../../src/models/configuration"; +import { OnBehalfOfCredentialAuthConfig } from "../../../../src/models/configuration"; chaiUse(chaiPromises); let restore: () => void; @@ -53,191 +50,6 @@ class SimpleAdapter extends BotAdapter { } } -describe("Message Extension Query With Token Tests - Node", () => { - const sandbox = sinon.createSandbox(); - const now = Math.floor(Date.now() / 1000); - const timeInterval = 4000; - const testDisplayName = "Teams Framework Unit Test"; - const testObjectId = "11111111-2222-3333-4444-555555555555"; - const testTenantId = "11111111-2222-3333-4444-555555555555"; - const testPreferredUserName = "test@microsoft.com"; - const ssoToken = jwtBuilder({ - algorithm: "HS256", - secret: "super-secret", - aud: "test_audience", - iss: "https://login.microsoftonline.com/test_aad_id/v2.0", - iat: now, - nbf: now, - exp: timeInterval, - aio: "test_aio", - name: testDisplayName, - oid: testObjectId, - preferred_username: testPreferredUserName, - rh: "test_rh", - scp: "access_as_user", - sub: "test_sub", - tid: testTenantId, - uti: "test_uti", - ver: "2.0", - }); - const activityContext = { - name: "composeExtension/query", - value: { authentication: { token: ssoToken } }, - }; - beforeEach(() => { - restore = mockedEnv({ - M365_CLIENT_ID: "fake_M365_client_id", - M365_TENANT_ID: "fake_M365_tennant_id", - M365_AUTHORITY_HOST: "https://login.microsoftonline.com", - INITIATE_LOGIN_ENDPOINT: "https://fake_domain/auth-start.html", - M365_CLIENT_SECRET: "fake_password", - }); - }); - afterEach(() => { - sandbox.restore(); - restore(); - }); - - it("handleMessageExtensionQueryWithToken failed in Message Extension Query", async () => { - try { - await handleMessageExtensionQueryWithToken( - { activity: { name: "composeExtension/queryLink", value: {} } } as TurnContext, - null, - "", - async (token: MessageExtensionTokenResponse) => { - token; - } - ); - } catch (err) { - assert.isTrue(err instanceof ErrorWithCode); - assert.strictEqual( - (err as ErrorWithCode).message, - "The handleMessageExtensionQueryWithToken only support in handleTeamsMessagingExtensionQuery with composeExtension/query type." - ); - assert.strictEqual((err as ErrorWithCode).code, "FailedOperation"); - } - }); - - it("handleMessageExtensionQueryWithToken getSignIn link with user config in MessageExtensionQuery", async () => { - const config: AuthenticationConfiguration = { - clientId: "fake_client_Id", - tenantId: "fake_tennant_Id", - authorityHost: "fake_authority_host", - initiateLoginEndpoint: "initial_endpoint", - clientSecret: "fake_client_secret", - }; - const res = await handleMessageExtensionQueryWithToken( - { activity: { name: "composeExtension/query", value: {} } } as TurnContext, - config, - ["fake_scope1", "fake_scope2"], - async (token: MessageExtensionTokenResponse) => { - token; - } - ); - assert.isNotNull(res); - assert.isNotNull(res!.composeExtension); - const signInLink = - "initial_endpoint?scope=fake_scope1%20fake_scope2&clientId=fake_client_Id&tenantId=fake_tennant_Id"; - assert.equal(res!.composeExtension!.type as string, "silentAuth"); - assert.isNotNull(res!.composeExtension!.suggestedActions!.actions); - const action = res!.composeExtension!.suggestedActions!.actions![0]; - assert.equal(action.type, "openUrl"); - assert.equal(action.value, signInLink); - assert.equal(action.title, "Message Extension OAuth"); - }); - - it("handleMessageExtensionQueryWithToken get SignIn link with default config in Message Extension Query", async () => { - const res = await handleMessageExtensionQueryWithToken( - { activity: { name: "composeExtension/query", value: {} } } as TurnContext, - null, - "fake_scope", - async (token: MessageExtensionTokenResponse) => { - token; - } - ); - assert.isNotNull(res); - assert.isNotNull(res!.composeExtension); - const signInLink = - "https://fake_domain/auth-start.html?scope=fake_scope&clientId=fake_M365_client_id&tenantId=fake_M365_tennant_id"; - assert.equal(res!.composeExtension!.type as string, "silentAuth"); - assert.isNotNull(res!.composeExtension!.suggestedActions!.actions); - const action = res!.composeExtension!.suggestedActions!.actions![0]; - assert.equal(action.type, "openUrl"); - assert.equal(action.value, signInLink); - assert.equal(action.title, "Message Extension OAuth"); - }); - - it("handleMessageExtensionQueryWithToken get 412 response in Message Extension query", async () => { - const adapter = new SimpleAdapter(); - const context: TurnContext = new TurnContext(adapter, activityContext); - const spy = sinon.spy(adapter, "sendActivities"); - sandbox - .stub(OnBehalfOfUserCredential.prototype, "getToken") - .throws( - new ErrorWithCode( - "Failed to get access token from authentication server, please login first.", - ErrorCode.UiRequiredError - ) - ); - await handleMessageExtensionQueryWithToken(context, null, "", async (token) => { - token; - }); - spy.restore(); - sinon.assert.calledOnce(spy); - assert.equal(spy.getCall(0).args[1][0].value.status, 412); - assert.equal(spy.getCall(0).args[1][0].type, "invokeResponse"); - }); - - it("handleMessageExtensionQueryWithToken with expected token in message extension query", async () => { - const tokenRes: AccessToken = { - token: "fake_access_token", - expiresOnTimestamp: now, - }; - sandbox.stub(OnBehalfOfUserCredential.prototype, "getToken").resolves(tokenRes); - const context: TurnContext = new TurnContext(new SimpleAdapter(), activityContext); - const logic = (token: MessageExtensionTokenResponse) => {}; - const callbackSpy = sinon.spy(logic); - const res = await handleMessageExtensionQueryWithToken(context, null, "", async (token) => { - callbackSpy(token); - }); - sinon.assert.calledOnce(callbackSpy); - assert.equal(callbackSpy.getCall(0).args[0].ssoToken, ssoToken); - assert.equal(callbackSpy.getCall(0).args[0].token, "fake_access_token"); - assert.equal(callbackSpy.getCall(0).args[0].expiration, now.toString()); - assert.equal( - callbackSpy.getCall(0).args[0].ssoTokenExpiration, - new Date((now + timeInterval) * 1000).toISOString() - ); - assert.isEmpty(callbackSpy.getCall(0).args[0].connectionName); - }); - - it("shold throw err once catch exceptions", async () => { - sandbox - .stub(OnBehalfOfUserCredential.prototype, "getToken") - .throws( - new ErrorWithCode( - "Failed to acquire access token on behalf of user", - ErrorCode.ServiceError - ) - ); - const adapter = new SimpleAdapter(); - const context: TurnContext = new TurnContext(adapter, activityContext); - try { - await handleMessageExtensionQueryWithToken(context, null, "", async (token) => { - token; - }); - } catch (err) { - assert.isNotNull(err); - assert.isTrue(err instanceof ErrorWithCode); - assert.strictEqual( - (err as ErrorWithCode).message, - "Failed to acquire access token on behalf of user" - ); - assert.strictEqual((err as ErrorWithCode).code, ErrorCode.ServiceError); - } - }); -}); - describe("Message Extension Query With SSO Tests - Node", () => { const sandbox = sinon.createSandbox(); const now = Math.floor(Date.now() / 1000); diff --git a/packages/sdk/test/unit/node/msGraphAuthProvider.spec.ts b/packages/sdk/test/unit/node/msGraphAuthProvider.spec.ts deleted file mode 100644 index ce5b52fcf0..0000000000 --- a/packages/sdk/test/unit/node/msGraphAuthProvider.spec.ts +++ /dev/null @@ -1,99 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. - -import { expect, use as chaiUse } from "chai"; -import * as chaiPromises from "chai-as-promised"; -import mockedEnv from "mocked-env"; -import { - TeamsFx, - OnBehalfOfUserCredential, - MsGraphAuthProvider, - ErrorWithCode, - ErrorCode, -} from "../../../src"; -import * as sinon from "sinon"; -import { AccessToken } from "@azure/core-auth"; - -chaiUse(chaiPromises); -let mockedEnvRestore: () => void; - -describe("MsGraphAuthProvider Tests - Node", () => { - const scopes = "fake_scope"; - const clientId = "fake_client_id"; - const clientSecret = "fake_client_secret"; - const tenantId = "fake_tenant"; - const authorityHost = "https://fake_authority_host"; - const initiateLoginEndpoint = "fake_initiate_login_endpoint"; - - /** - * { - * "aud": "test_audience", - * "iss": "https://login.microsoftonline.com/test_aad_id/v2.0", - * "iat": 1537231048, - * "nbf": 1537231048, - * "exp": 1537234948, - * "aio": "test_aio", - * "name": "Teams App Framework SDK Unit Test", - * "oid": "11111111-2222-3333-4444-555555555555", - * "preferred_username": "test@microsoft.com", - * "rh": "test_rh", - * "scp": "access_as_user", - * "sub": "test_sub", - * "tid": "test_tenant_id", - * "uti": "test_uti", - * "ver": "2.0" - * } - */ - const ssoToken = - // eslint-disable-next-line no-secrets/no-secrets - "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJ0ZXN0X2F1ZGllbmNlIiwiaXNzIjoiaHR0cHM6Ly9sb2dpbi5taWNyb3NvZnRvbmxpbmUuY29tL3Rlc3RfYWFkX2lkL3YyLjAiLCJpYXQiOjE1MzcyMzEwNDgsIm5iZiI6MTUzNzIzMTA0OCwiZXhwIjoxNTM3MjM0OTQ4LCJhaW8iOiJ0ZXN0X2FpbyIsIm5hbWUiOiJNT0RTIFRvb2xraXQgU0RLIFVuaXQgVGVzdCIsIm9pZCI6IjExMTExMTExLTIyMjItMzMzMy00NDQ0LTU1NTU1NTU1NTU1NSIsInByZWZlcnJlZF91c2VybmFtZSI6InRlc3RAbWljcm9zb2Z0LmNvbSIsInJoIjoidGVzdF9yaCIsInNjcCI6ImFjY2Vzc19hc191c2VyIiwic3ViIjoidGVzdF9zdWIiLCJ0aWQiOiJ0ZXN0X3RlbmFudF9pZCIsInV0aSI6InRlc3RfdXRpIiwidmVyIjoiMi4wIn0.SshbL1xuE1aNZD5swrWOQYgTR9QCNXkZqUebautBvKM"; - - beforeEach(function () { - mockedEnvRestore = mockedEnv({ - INITIATE_LOGIN_ENDPOINT: initiateLoginEndpoint, - M365_CLIENT_ID: clientId, - M365_CLIENT_SECRET: clientSecret, - M365_TENANT_ID: tenantId, - M365_AUTHORITY_HOST: authorityHost, - }); - }); - - afterEach(function () { - mockedEnvRestore(); - }); - - it("create MsGraphAuthProvider instance should throw InvalidParameter error with invalid scopes", function () { - const invalidScopes: any = [10, 20]; - expect(() => { - new MsGraphAuthProvider(new TeamsFx(), invalidScopes); - }) - .to.throw(ErrorWithCode, "The type of scopes is not valid, it must be string or string array") - .with.property("code", ErrorCode.InvalidParameter); - }); - - it("create msGraphAuthProvider instance should success with TeamsFx", function () { - const teamsfx = new TeamsFx().setSsoToken(ssoToken); - const authProvider: any = new MsGraphAuthProvider(teamsfx, scopes); - expect(authProvider.credentialOrTeamsFx).to.be.instanceOf(TeamsFx); - }); - - it("create msGraphAuthProvider instance should throw UiRequiredError with unconsent scope with OnBehalfOfUserCredential", async function () { - sinon - .stub(OnBehalfOfUserCredential.prototype, "getToken") - .callsFake((): Promise => { - throw new ErrorWithCode( - "Failed to get access token from authentication server, please login first.", - ErrorCode.UiRequiredError - ); - }); - const unconsentScopes = "unconsent_scope"; - const authProvider = new MsGraphAuthProvider( - new TeamsFx().setSsoToken(ssoToken), - unconsentScopes - ); - await expect(authProvider.getAccessToken()) - .to.eventually.be.rejectedWith(ErrorWithCode) - .and.property("code", ErrorCode.UiRequiredError); - sinon.restore(); - }); -}); diff --git a/packages/sdk/test/unit/node/msGraphClientProvider.spec.ts b/packages/sdk/test/unit/node/msGraphClientProvider.spec.ts deleted file mode 100644 index 6f90fac240..0000000000 --- a/packages/sdk/test/unit/node/msGraphClientProvider.spec.ts +++ /dev/null @@ -1,149 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. - -import { expect, use as chaiUse } from "chai"; -import "isomorphic-fetch"; -import * as chaiPromises from "chai-as-promised"; -import mockedEnv from "mocked-env"; -import { - TeamsFx, - createMicrosoftGraphClient, - ErrorWithCode, - ErrorCode, - createMicrosoftGraphClientWithCredential, - OnBehalfOfCredentialAuthConfig, - OnBehalfOfUserCredential, -} from "../../../src"; - -chaiUse(chaiPromises); -let mockedEnvRestore: () => void; - -describe("createMicrosoftGraphClient Tests - node", () => { - const scopes = "fake_scope"; - const clientId = "fake_client_id"; - const clientSecret = "fake_client_secret"; - const tenantId = "fake_tenant"; - const authorityHost = "https://fake_authority_host"; - - /** - * { - * "aud": "test_audience", - * "iss": "https://login.microsoftonline.com/test_aad_id/v2.0", - * "iat": 1537231048, - * "nbf": 1537231048, - * "exp": 1537234948, - * "aio": "test_aio", - * "name": "Teams App Framework SDK Unit Test", - * "oid": "11111111-2222-3333-4444-555555555555", - * "preferred_username": "test@microsoft.com", - * "rh": "test_rh", - * "scp": "access_as_user", - * "sub": "test_sub", - * "tid": "test_tenant_id", - * "uti": "test_uti", - * "ver": "2.0" - * } - */ - const ssoToken = - // eslint-disable-next-line no-secrets/no-secrets - "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJ0ZXN0X2F1ZGllbmNlIiwiaXNzIjoiaHR0cHM6Ly9sb2dpbi5taWNyb3NvZnRvbmxpbmUuY29tL3Rlc3RfYWFkX2lkL3YyLjAiLCJpYXQiOjE1MzcyMzEwNDgsIm5iZiI6MTUzNzIzMTA0OCwiZXhwIjoxNTM3MjM0OTQ4LCJhaW8iOiJ0ZXN0X2FpbyIsIm5hbWUiOiJNT0RTIFRvb2xraXQgU0RLIFVuaXQgVGVzdCIsIm9pZCI6IjExMTExMTExLTIyMjItMzMzMy00NDQ0LTU1NTU1NTU1NTU1NSIsInByZWZlcnJlZF91c2VybmFtZSI6InRlc3RAbWljcm9zb2Z0LmNvbSIsInJoIjoidGVzdF9yaCIsInNjcCI6ImFjY2Vzc19hc191c2VyIiwic3ViIjoidGVzdF9zdWIiLCJ0aWQiOiJ0ZXN0X3RlbmFudF9pZCIsInV0aSI6InRlc3RfdXRpIiwidmVyIjoiMi4wIn0.SshbL1xuE1aNZD5swrWOQYgTR9QCNXkZqUebautBvKM"; - - beforeEach(function () { - mockedEnvRestore = mockedEnv({ - M365_CLIENT_ID: clientId, - M365_CLIENT_SECRET: clientSecret, - M365_TENANT_ID: tenantId, - M365_AUTHORITY_HOST: authorityHost, - }); - }); - - afterEach(function () { - mockedEnvRestore(); - }); - - it("createMicrosoftGraphClient should throw InvalidParameter error with invalid scope", function () { - const invalidScopes: any = [10, 20]; - expect(() => { - createMicrosoftGraphClient(new TeamsFx().setSsoToken(ssoToken), invalidScopes); - }) - .to.throw(ErrorWithCode, "The type of scopes is not valid, it must be string or string array") - .with.property("code", ErrorCode.InvalidParameter); - }); - - it("createMicrosoftGraphClient should success with TeamsFx", async function () { - const graphClient: any = createMicrosoftGraphClient( - new TeamsFx().setSsoToken(ssoToken), - scopes - ); - expect(graphClient.config.authProvider.credentialOrTeamsFx).to.be.instanceOf(TeamsFx); - }); -}); - -describe("createMicrosoftGraphClientWithCredential Tests - node", () => { - const scopes = "fake_scope"; - const clientId = "fake_client_id"; - const clientSecret = "fake_client_secret"; - const tenantId = "fake_tenant"; - const authorityHost = "https://fake_authority_host"; - const authConfig: OnBehalfOfCredentialAuthConfig = { - clientId: clientId, - tenantId: tenantId, - authorityHost: authorityHost, - clientSecret: clientSecret, - }; - - /** - * { - * "aud": "test_audience", - * "iss": "https://login.microsoftonline.com/test_aad_id/v2.0", - * "iat": 1537231048, - * "nbf": 1537231048, - * "exp": 1537234948, - * "aio": "test_aio", - * "name": "Teams App Framework SDK Unit Test", - * "oid": "11111111-2222-3333-4444-555555555555", - * "preferred_username": "test@microsoft.com", - * "rh": "test_rh", - * "scp": "access_as_user", - * "sub": "test_sub", - * "tid": "test_tenant_id", - * "uti": "test_uti", - * "ver": "2.0" - * } - */ - const ssoToken = - // eslint-disable-next-line no-secrets/no-secrets - "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJ0ZXN0X2F1ZGllbmNlIiwiaXNzIjoiaHR0cHM6Ly9sb2dpbi5taWNyb3NvZnRvbmxpbmUuY29tL3Rlc3RfYWFkX2lkL3YyLjAiLCJpYXQiOjE1MzcyMzEwNDgsIm5iZiI6MTUzNzIzMTA0OCwiZXhwIjoxNTM3MjM0OTQ4LCJhaW8iOiJ0ZXN0X2FpbyIsIm5hbWUiOiJNT0RTIFRvb2xraXQgU0RLIFVuaXQgVGVzdCIsIm9pZCI6IjExMTExMTExLTIyMjItMzMzMy00NDQ0LTU1NTU1NTU1NTU1NSIsInByZWZlcnJlZF91c2VybmFtZSI6InRlc3RAbWljcm9zb2Z0LmNvbSIsInJoIjoidGVzdF9yaCIsInNjcCI6ImFjY2Vzc19hc191c2VyIiwic3ViIjoidGVzdF9zdWIiLCJ0aWQiOiJ0ZXN0X3RlbmFudF9pZCIsInV0aSI6InRlc3RfdXRpIiwidmVyIjoiMi4wIn0.SshbL1xuE1aNZD5swrWOQYgTR9QCNXkZqUebautBvKM"; - - beforeEach(function () { - mockedEnvRestore = mockedEnv({ - M365_CLIENT_ID: clientId, - M365_CLIENT_SECRET: clientSecret, - M365_TENANT_ID: tenantId, - M365_AUTHORITY_HOST: authorityHost, - }); - }); - - afterEach(function () { - mockedEnvRestore(); - }); - - it("createMicrosoftGraphClientWithCredential should throw InvalidParameter error with invalid scope", function () { - const invalidScopes: any = [10, 20]; - expect(() => { - const credential = new OnBehalfOfUserCredential(ssoToken, authConfig); - createMicrosoftGraphClientWithCredential(credential, invalidScopes); - }) - .to.throw(ErrorWithCode, "The type of scopes is not valid, it must be string or string array") - .with.property("code", ErrorCode.InvalidParameter); - }); - - it("createMicrosoftGraphClient should success with TeamsFx", async function () { - const credential = new OnBehalfOfUserCredential(ssoToken, authConfig); - - const graphClient: any = createMicrosoftGraphClientWithCredential(credential, scopes); - expect(graphClient.config.authProvider.credentialOrTeamsFx).to.be.instanceOf( - OnBehalfOfUserCredential - ); - }); -}); diff --git a/packages/sdk/test/unit/node/mssql/sqlConnector.spec.ts b/packages/sdk/test/unit/node/mssql/sqlConnector.spec.ts deleted file mode 100644 index a36e0f6752..0000000000 --- a/packages/sdk/test/unit/node/mssql/sqlConnector.spec.ts +++ /dev/null @@ -1,147 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. - -import { AccessToken, ManagedIdentityCredential } from "@azure/identity"; -import { assert, use as chaiUse, expect } from "chai"; -import * as chaiPromises from "chai-as-promised"; -import * as sinon from "sinon"; -import mockedEnv from "mocked-env"; -import { - getTediousConnectionConfig, - ErrorWithCode, - setLogLevel, - LogLevel, - TeamsFx, -} from "../../../../src"; - -chaiUse(chaiPromises); -let restore: () => void; - -describe("DefaultTediousConnection Tests - Node", () => { - // fake configuration for sql. - const fakeSQLServerEndpoint = "xxx.database.windows.net"; - const fakeSQLUserName = "fake_name"; - const fakeSQLPassword = "fake_password"; - const fakeSQLIdentityId = "fake_identity_id"; - const fakeSQLDataName = "fake_data_name"; - const fakeToken = "fake_token"; - const defaultAuthenticationType = "default"; - const tokenAuthenticationType = "azure-active-directory-access-token"; - - // error code. - const INVALID_CONFIGURATION = "InvalidConfiguration"; - - before(() => { - setLogLevel(LogLevel.Verbose); - }); - after(() => { - setLogLevel(LogLevel.Info); - }); - afterEach(function () { - restore(); - sinon.restore(); - }); - - it("getConfig should success with username and password", async function () { - restore = mockedEnv({ - SQL_ENDPOINT: fakeSQLServerEndpoint, - SQL_DATABASE_NAME: fakeSQLDataName, - SQL_USER_NAME: fakeSQLUserName, - SQL_PASSWORD: fakeSQLPassword, - }); - - const teamsfx = new TeamsFx(); - const tediousConnectConfig = await getTediousConnectionConfig(teamsfx); - - assert.isNotNull(tediousConnectConfig); - assert.isNotNull(tediousConnectConfig.authentication); - assert.strictEqual(tediousConnectConfig.authentication!.type, defaultAuthenticationType); - assert.strictEqual(tediousConnectConfig.server, fakeSQLServerEndpoint); - assert.strictEqual(tediousConnectConfig.authentication!.options.userName, fakeSQLUserName); - assert.strictEqual(tediousConnectConfig.authentication!.options.password, fakeSQLPassword); - assert.strictEqual(tediousConnectConfig.options?.database, fakeSQLDataName); - }); - - it("getConfig should success with access token", async function () { - restore = mockedEnv({ - SQL_ENDPOINT: fakeSQLServerEndpoint, - SQL_DATABASE: fakeSQLDataName, - IDENTITY_ID: fakeSQLIdentityId, - }); - - const identityManager_GetToken = sinon.stub(ManagedIdentityCredential.prototype, "getToken"); - identityManager_GetToken.callsFake(async () => { - return new Promise((resolve) => { - resolve({ - token: "fake_token", - expiresOnTimestamp: 12345678, - }); - }); - }); - - const teamsfx = new TeamsFx(); - const tediousConnectConfig = await getTediousConnectionConfig(teamsfx); - - assert.isNotNull(tediousConnectConfig); - assert.isNotNull(tediousConnectConfig.authentication); - assert.strictEqual(tediousConnectConfig.authentication!.type, tokenAuthenticationType); - assert.strictEqual(tediousConnectConfig.server, fakeSQLServerEndpoint); - assert.strictEqual(tediousConnectConfig.authentication!.options.token, fakeToken); - - sinon.restore(); - }); - - it("getConfig should success with specified database name", async function () { - restore = mockedEnv({ - SQL_ENDPOINT: fakeSQLServerEndpoint, - SQL_USER_NAME: fakeSQLUserName, - SQL_PASSWORD: fakeSQLPassword, - }); - - const anotherSqlDatabaseName = "another database"; - const teamsfx = new TeamsFx(); - const tediousConnectConfig = await getTediousConnectionConfig(teamsfx, anotherSqlDatabaseName); - - assert.isNotNull(tediousConnectConfig); - assert.strictEqual(tediousConnectConfig.options?.database, anotherSqlDatabaseName); - }); - - it("getConfig should warn with empty database name", async function () { - restore = mockedEnv({ - SQL_ENDPOINT: fakeSQLServerEndpoint, - SQL_USER_NAME: fakeSQLUserName, - SQL_PASSWORD: fakeSQLPassword, - }); - - const teamsfx = new TeamsFx(); - const tediousConnectConfig = await getTediousConnectionConfig(teamsfx, ""); - - assert.isNotNull(tediousConnectConfig); - assert.strictEqual(tediousConnectConfig.options?.database, ""); - }); - - it("getConfig should throw InvalidConfiguration error without host name", async function () { - restore = mockedEnv({ - SQL_DATABASE: fakeSQLDataName, - SQL_USER_NAME: fakeSQLUserName, - SQL_PASSWORD: fakeSQLPassword, - }); - - const teamsfx = new TeamsFx(); - await expect(getTediousConnectionConfig(teamsfx)) - .to.eventually.be.rejectedWith(ErrorWithCode) - .and.property("code", INVALID_CONFIGURATION); - }); - - it("getConfig should throw InvalidConfiguration error without username, password or identity id", async function () { - restore = mockedEnv({ - SQL_ENDPOINT: fakeSQLServerEndpoint, - SQL_DATABASE: fakeSQLDataName, - }); - - const teamsfx = new TeamsFx(); - await expect(getTediousConnectionConfig(teamsfx)) - .to.eventually.be.rejectedWith(ErrorWithCode) - .and.property("code", INVALID_CONFIGURATION); - }); -}); diff --git a/packages/sdk/test/unit/node/teamsFx.spec.ts b/packages/sdk/test/unit/node/teamsFx.spec.ts deleted file mode 100644 index 6681a637e3..0000000000 --- a/packages/sdk/test/unit/node/teamsFx.spec.ts +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. - -import { assert } from "chai"; -import mockedEnv from "mocked-env"; -import { TeamsFx } from "../../../src"; - -describe("TeamsFx Tests - Node", () => { - let restore: () => void; - - afterEach(() => { - restore(); - }); - - it("should load all environment variables", () => { - restore = mockedEnv({ - TEST_ENV: "test value", - }); - - const teamsFx = new TeamsFx(); - - assert.equal(teamsFx.getConfig("TEST_ENV"), "test value"); - }); - - it("should not override reserved key", () => { - restore = mockedEnv({ - clientId: "test value", - }); - - const teamsFx = new TeamsFx(undefined, { - clientId: "predefined value", - }); - - assert.equal(teamsFx.getConfig("clientId"), "predefined value"); - }); -}); diff --git a/packages/sdk/test/unit/utils.spec.ts b/packages/sdk/test/unit/utils.spec.ts index 1728574725..91a10397b5 100644 --- a/packages/sdk/test/unit/utils.spec.ts +++ b/packages/sdk/test/unit/utils.spec.ts @@ -8,23 +8,34 @@ import { validateScopesType, parseAccessTokenFromAuthCodeTokenResponse, getTenantIdAndLoginHintFromSsoToken, + parseJwt, + validateConfig, } from "../../src/util/utils"; describe("Utils Tests", () => { /** * { - * "oid": "fake-oid", - * "name": "fake-name", - * "ver": "1.0", - * "exp": 1537234948, - * "upn": "fake-upn", - * "tid": "fake-tid", - * "aud": "fake-aud" - } - */ + * oid: "fake-oid", + * name: "fake-name", + * ver: "1.0", + * exp: 1537234948, + * upn: "fake-upn", + * tid: "fake-tid", + * aud: "fake-aud", + * iss: "fake-iss", + * iat: 1537234948, + * nbf: 1537234948, + * aio: "fake-aio", + * rh: "fake-rh", + * scp: "fake-scp", + * sub: "fake-sub", + * uti: "fake-uti", + * } + **/ + const fakeSSOTokenFull = // eslint-disable-next-line no-secrets/no-secrets - "eyJhbGciOiJIUzI1NiJ9.eyJvaWQiOiJmYWtlLW9pZCIsIm5hbWUiOiJmYWtlLW5hbWUiLCJ2ZXIiOiIxLjAiLCJleHAiOjE1MzcyMzQ5NDgsInVwbiI6ImZha2UtdXBuIiwidGlkIjoiZmFrZS10aWQiLCJhdWQiOiJmYWtlLWF1ZCJ9.rLK5VlJK1FsGZJD0yb-ussSjl2Z4sSqG1Nhj7NqjNs4"; + "eyJhbGciOiJIUzI1NiJ9.eyJvaWQiOiJmYWtlLW9pZCIsIm5hbWUiOiJmYWtlLW5hbWUiLCJ2ZXIiOiIxLjAiLCJleHAiOjE1MzcyMzQ5NDgsInVwbiI6ImZha2UtdXBuIiwidGlkIjoiZmFrZS10aWQiLCJhdWQiOiJmYWtlLWF1ZCIsImlzcyI6ImZha2UtaXNzIiwiaWF0IjoxNTM3MjM0OTQ4LCJuYmYiOjE1MzcyMzQ5NDgsImFpbyI6ImZha2UtYWlvIiwicmgiOiJmYWtlLXJoIiwic2NwIjoiZmFrZS1zY3AiLCJzdWIiOiJmYWtlLXN1YiIsInV0aSI6ImZha2UtdXRpIn0.nTgx3IdZR-hqFSUiVwFx0L4kZxMPQ0sk-xI_UgexAGw"; function getAuthCodeTokenResponse(accessToken: string): AuthenticationResult { return { @@ -43,117 +54,237 @@ describe("Utils Tests", () => { }; } - it("validateScopesType should throw InvalidParameter error with invalid scopes", () => { - const invalidScopes = [1, 2]; - const expectedErrorMsg = "The type of scopes is not valid, it must be string or string array"; - expect(() => { - validateScopesType(invalidScopes); - }) - .to.throw(ErrorWithCode, expectedErrorMsg) - .with.property("code", ErrorCode.InvalidParameter); - - const invalidScopes2 = new Promise((resolve) => resolve(true)); - expect(() => { - validateScopesType(invalidScopes2); - }) - .to.throw(ErrorWithCode, expectedErrorMsg) - .with.property("code", ErrorCode.InvalidParameter); - - const invalidScopes3 = 1; - expect(() => { - validateScopesType(invalidScopes3); - }) - .to.throw(ErrorWithCode, expectedErrorMsg) - .with.property("code", ErrorCode.InvalidParameter); - - const invalidScopes4 = { scopes: "user.read" }; - expect(() => { - validateScopesType(invalidScopes4); - }) - .to.throw(ErrorWithCode, expectedErrorMsg) - .with.property("code", ErrorCode.InvalidParameter); - - const invalidScopes5 = true; - expect(() => { - validateScopesType(invalidScopes5); - }) - .to.throw(ErrorWithCode, expectedErrorMsg) - .with.property("code", ErrorCode.InvalidParameter); - - const invalidScopes6: any = null; - expect(() => { - validateScopesType(invalidScopes6); - }) - .to.throw(ErrorWithCode, expectedErrorMsg) - .with.property("code", ErrorCode.InvalidParameter); - - const invalidScopes7: any = undefined; - expect(() => { - validateScopesType(invalidScopes7); - }) - .to.throw(ErrorWithCode, expectedErrorMsg) - .with.property("code", ErrorCode.InvalidParameter); - }); + describe("parseJwt()", () => { + it("should correctly parse a valid JWT token", () => { + const expectedPayload = { + oid: "fake-oid", + name: "fake-name", + ver: "1.0", + exp: 1537234948, + upn: "fake-upn", + tid: "fake-tid", + aud: "fake-aud", + iss: "fake-iss", + iat: 1537234948, + nbf: 1537234948, + aio: "fake-aio", + rh: "fake-rh", + scp: "fake-scp", + sub: "fake-sub", + uti: "fake-uti", + }; - it("validateScopesType should success with valid scopes", () => { - const validScopes1 = "https://graph.microsoft.com/user.read"; - validateScopesType(validScopes1); + const decodedPayload = parseJwt(fakeSSOTokenFull); - const validScopes2 = ["user.read", "user.write"]; - validateScopesType(validScopes2); + assert.deepEqual(decodedPayload, expectedPayload); + }); - const validScopes3: string[] = []; - validateScopesType(validScopes3); + it("should throw an error for an invalid JWT token", () => { + // decoded - {} + // eslint-disable-next-line no-secrets/no-secrets + const invalidToken = "eyJhbGciOiJIUzI1NiJ9.e30.ZRrHA1JJJW8opsbCGfG_HACGpVUMN_a9IV7pAx_Zmeo"; - const validScopes4 = ""; - validateScopesType(validScopes4); + try { + parseJwt(invalidToken); + } catch (error) { + if (error instanceof Error) { + assert.equal( + error.message, + "Parse jwt token failed in node env with error: Decoded token is null or exp claim does not exists." + ); + assert.equal(error.name, "ErrorWithCode.InternalError"); + } + } + }); }); - it("parseAccessTokenFromAuthCodeTokenResponse should success when parameter is string type", () => { - const tokenResponse = JSON.stringify(getAuthCodeTokenResponse(fakeSSOTokenFull)); - const accessToken = parseAccessTokenFromAuthCodeTokenResponse(tokenResponse); + describe("validateScopesType()", () => { + it("should throw InvalidParameter error with invalid scopes", () => { + const invalidScopes = [1, 2]; + const expectedErrorMsg = "The type of scopes is not valid, it must be string or string array"; + expect(() => { + validateScopesType(invalidScopes); + }) + .to.throw(ErrorWithCode, expectedErrorMsg) + .with.property("code", ErrorCode.InvalidParameter); - assert.isNotNull(accessToken); - if (accessToken) { - assert.strictEqual(accessToken.token, fakeSSOTokenFull); - } - }); + const invalidScopes2 = new Promise((resolve) => resolve(true)); + expect(() => { + validateScopesType(invalidScopes2); + }) + .to.throw(ErrorWithCode, expectedErrorMsg) + .with.property("code", ErrorCode.InvalidParameter); + + const invalidScopes3 = 1; + expect(() => { + validateScopesType(invalidScopes3); + }) + .to.throw(ErrorWithCode, expectedErrorMsg) + .with.property("code", ErrorCode.InvalidParameter); + + const invalidScopes4 = { scopes: "user.read" }; + expect(() => { + validateScopesType(invalidScopes4); + }) + .to.throw(ErrorWithCode, expectedErrorMsg) + .with.property("code", ErrorCode.InvalidParameter); + + const invalidScopes5 = true; + expect(() => { + validateScopesType(invalidScopes5); + }) + .to.throw(ErrorWithCode, expectedErrorMsg) + .with.property("code", ErrorCode.InvalidParameter); + + const invalidScopes6 = null; + expect(() => { + validateScopesType(invalidScopes6); + }) + .to.throw(ErrorWithCode, expectedErrorMsg) + .with.property("code", ErrorCode.InvalidParameter); + + const invalidScopes7 = undefined; + expect(() => { + validateScopesType(invalidScopes7); + }) + .to.throw(ErrorWithCode, expectedErrorMsg) + .with.property("code", ErrorCode.InvalidParameter); + }); + + it("should success with valid scopes", () => { + const validScopes1 = "https://graph.microsoft.com/user.read"; + validateScopesType(validScopes1); + + const validScopes2 = ["user.read", "user.write"]; + validateScopesType(validScopes2); - it("parseAccessTokenFromAuthCodeTokenResponse should success when parameter is AuthenticationResult type", () => { - const accessToken = parseAccessTokenFromAuthCodeTokenResponse( - getAuthCodeTokenResponse(fakeSSOTokenFull) - ); + const validScopes3: string[] = []; + validateScopesType(validScopes3); - assert.isNotNull(accessToken); - if (accessToken) { - assert.strictEqual(accessToken.token, fakeSSOTokenFull); - } + const validScopes4 = ""; + validateScopesType(validScopes4); + }); }); - it("parseAccessTokenFromAuthCodeTokenResponse throw InternalError with empty access token", () => { - const errorMsg = "Get empty access token from Auth Code token response."; - expect(() => { - parseAccessTokenFromAuthCodeTokenResponse(getAuthCodeTokenResponse("")); - }) - .to.throw(ErrorWithCode, errorMsg) - .with.property("code", ErrorCode.InternalError); + describe("parseAccessTokenFromAuthCodeTokenResponse()", () => { + it("parseAccessTokenFromAuthCodeTokenResponse should success when parameter is string type", () => { + const tokenResponse = JSON.stringify(getAuthCodeTokenResponse(fakeSSOTokenFull)); + const accessToken = parseAccessTokenFromAuthCodeTokenResponse(tokenResponse); + + assert.isNotNull(accessToken); + if (accessToken) { + assert.strictEqual(accessToken.token, fakeSSOTokenFull); + } + }); + + it("parseAccessTokenFromAuthCodeTokenResponse should success when parameter is AuthenticationResult type", () => { + const accessToken = parseAccessTokenFromAuthCodeTokenResponse( + getAuthCodeTokenResponse(fakeSSOTokenFull) + ); + + assert.isNotNull(accessToken); + if (accessToken) { + assert.strictEqual(accessToken.token, fakeSSOTokenFull); + } + }); + + it("parseAccessTokenFromAuthCodeTokenResponse throw InternalError with empty access token", () => { + const errorMsg = "Get empty access token from Auth Code token response."; + expect(() => { + parseAccessTokenFromAuthCodeTokenResponse(getAuthCodeTokenResponse("")); + }) + .to.throw(ErrorWithCode, errorMsg) + .with.property("code", ErrorCode.InternalError); + }); }); - it("getTenantIdAndLoginHintFromSsoToken should success with valid sso token", () => { - const userInfo = getTenantIdAndLoginHintFromSsoToken(fakeSSOTokenFull); - assert.isNotNull(userInfo); - if (userInfo) { - assert.strictEqual(userInfo.tid, "fake-tid"); - assert.strictEqual(userInfo.loginHint, "fake-upn"); - } + describe("getTenantIdAndLoginHintFromSsoToken()", () => { + it("getTenantIdAndLoginHintFromSsoToken should success with valid sso token", () => { + const userInfo = getTenantIdAndLoginHintFromSsoToken(fakeSSOTokenFull); + assert.isNotNull(userInfo); + if (userInfo) { + assert.strictEqual(userInfo.tid, "fake-tid"); + assert.strictEqual(userInfo.loginHint, "fake-upn"); + } + }); + + it("getTenantIdAndLoginHintFromSsoToken throw InvalidParameter with empty sso token", () => { + const errorMsg = "SSO token is undefined."; + expect(() => { + getTenantIdAndLoginHintFromSsoToken(""); + }) + .to.throw(ErrorWithCode, errorMsg) + .with.property("code", ErrorCode.InvalidParameter); + }); }); - it("getTenantIdAndLoginHintFromSsoToken throw InvalidParameter with empty sso token", () => { - const errorMsg = "SSO token is undefined."; - expect(() => { - getTenantIdAndLoginHintFromSsoToken(""); - }) - .to.throw(ErrorWithCode, errorMsg) - .with.property("code", ErrorCode.InvalidParameter); + describe("validateConfig", () => { + it("should pass with valid config using clientSecret", () => { + const config = { + authorityHost: "https://login.microsoftonline.com", + clientId: "valid-client-id", + tenantId: "valid-tenant-id", + clientSecret: "valid-client-secret", + }; + assert.doesNotThrow(() => validateConfig(config)); + }); + + it("should pass with valid config using certificateContent", () => { + const config = { + authorityHost: "https://login.microsoftonline.com", + clientId: "valid-client-id", + tenantId: "valid-tenant-id", + certificateContent: "valid-certificate-content", + }; + assert.doesNotThrow(() => validateConfig(config)); + }); + + it("should throw error if clientId is missing", () => { + const config = { + authorityHost: "https://login.microsoftonline.com", + tenantId: "valid-tenant-id", + clientSecret: "valid-client-secret", + }; + assert.throw( + () => validateConfig(config), + "clientId in configuration is invalid: undefined." + ); + }); + + it("should throw error if both clientSecret and certificateContent are missing", () => { + const config = { + authorityHost: "https://login.microsoftonline.com", + clientId: "valid-client-id", + tenantId: "valid-tenant-id", + }; + assert.throw( + () => validateConfig(config), + "clientSecret or certificateContent in configuration is invalid: undefined." + ); + }); + + it("should throw error if tenantId is missing", () => { + const config = { + authorityHost: "https://login.microsoftonline.com", + clientId: "valid-client-id", + clientSecret: "valid-client-secret", + }; + assert.throw( + () => validateConfig(config), + "tenantId in configuration is invalid: undefined." + ); + }); + + it("should throw error if authorityHost is missing", () => { + const config = { + clientId: "valid-client-id", + tenantId: "valid-tenant-id", + clientSecret: "valid-client-secret", + }; + assert.throw( + () => validateConfig(config), + "authorityHost in configuration is invalid: undefined." + ); + }); }); }); diff --git a/packages/sdk/tsconfig.eslint.json b/packages/sdk/tsconfig.eslint.json index 283b4b75f5..09719abb50 100644 --- a/packages/sdk/tsconfig.eslint.json +++ b/packages/sdk/tsconfig.eslint.json @@ -1,14 +1,14 @@ { - // extend your base config to share compilerOptions, etc - "extends": "./tsconfig.json", - "compilerOptions": { - // ensure that nobody can accidentally use this config for a build - "noEmit": true - }, - "include": [ - // whatever paths you intend to lint - "src", - "tests" - ], - "exclude": [] -} \ No newline at end of file + // extend your base config to share compilerOptions, etc + "extends": "./tsconfig.json", + "compilerOptions": { + // ensure that nobody can accidentally use this config for a build + "noEmit": true + }, + "include": [ + // whatever paths you intend to lint + "src", + "tests" + ], + "exclude": [] +} diff --git a/packages/sdk/tsconfig.json b/packages/sdk/tsconfig.json index 8c7cd90dde..e9ac69290f 100644 --- a/packages/sdk/tsconfig.json +++ b/packages/sdk/tsconfig.json @@ -29,7 +29,8 @@ "forceConsistentCasingInFileNames": true, "moduleResolution": "node", "resolveJsonModule": true, - "downlevelIteration": true + "downlevelIteration": true, + "allowSyntheticDefaultImports": true }, "exclude": ["dist/**/*", "config/*"] } diff --git a/packages/server/src/apis.ts b/packages/server/src/apis.ts index cbc8f03a89..ff2aeee3ff 100644 --- a/packages/server/src/apis.ts +++ b/packages/server/src/apis.ts @@ -320,6 +320,6 @@ export interface DependencyStatusRPC { }; error?: { message: string; - helpLink: string; + helpLink?: string; }; } diff --git a/packages/server/src/serverConnection.ts b/packages/server/src/serverConnection.ts index 302915da16..c65c8b5526 100644 --- a/packages/server/src/serverConnection.ts +++ b/packages/server/src/serverConnection.ts @@ -14,6 +14,7 @@ import { Result, Stage, Tools, + UserError, Void, err, ok, @@ -506,7 +507,12 @@ export default class ServerConnection implements IServerConnection { command: depStatus.command, details: depStatus.details, ...(depStatus.error !== undefined - ? { error: { message: depStatus.error.message, helpLink: depStatus.error.helpLink } } + ? { + error: { + message: depStatus.error.message, + helpLink: (depStatus.error as UserError).helpLink || "", + }, + } : {}), }); } catch (error: unknown) { diff --git a/packages/server/tests/serverConnection.test.ts b/packages/server/tests/serverConnection.test.ts index 0273a8f497..f6faed55f0 100644 --- a/packages/server/tests/serverConnection.test.ts +++ b/packages/server/tests/serverConnection.test.ts @@ -15,7 +15,7 @@ import { import { DependencyStatus, DepsManager, - NodeNotFoundError, + NodejsNotFoundError, QuestionNames, SyncManifestInputs, teamsDevPortalClient, @@ -494,11 +494,12 @@ describe("serverConnections", () => { }); it("checkAndInstallTestTool DepenendencyStatus error", async () => { const connection = new ServerConnection(msgConn); + const err = new NodejsNotFoundError(); sandbox.stub(DepsManager.prototype, "ensureDependency").resolves({ isInstalled: true, command: "mock command", details: {}, - error: new NodeNotFoundError("mock message", "mock help link"), + error: err, } as DependencyStatus); const res = await connection.checkAndInstallTestTool( {} as TestToolInstallOptions & { correlationId: string }, @@ -510,8 +511,8 @@ describe("serverConnections", () => { command: "mock command", details: {}, error: { - message: "mock message", - helpLink: "mock help link", + message: err.message, + helpLink: err.helpLink, }, }); }); diff --git a/packages/tests/src/ui-test/localdebug/localdebug-chatdata-azureai-js-azureopenai.test.ts b/packages/tests/src/ui-test/localdebug/localdebug-chatdata-azureai-js-azureopenai.test.ts index 782c936f39..877017cbee 100644 --- a/packages/tests/src/ui-test/localdebug/localdebug-chatdata-azureai-js-azureopenai.test.ts +++ b/packages/tests/src/ui-test/localdebug/localdebug-chatdata-azureai-js-azureopenai.test.ts @@ -150,7 +150,7 @@ describe("Local Debug Tests", function () { throw new Error("Failed to install packages"); } - const insertDataCmd = `npm run indexer:create -- '${searchKey}' '${searchEndpoint}'`; + const insertDataCmd = `npm run indexer:create -- ${searchKey} ${azureOpenAiKey}`; const { success: insertDataSuccess } = await Executor.execute( insertDataCmd, projectPath diff --git a/packages/tests/src/ui-test/localdebug/localdebug-chatdata-azureai-ts-azureopenai.test.ts b/packages/tests/src/ui-test/localdebug/localdebug-chatdata-azureai-ts-azureopenai.test.ts index b34362fcb3..1adea19a3e 100644 --- a/packages/tests/src/ui-test/localdebug/localdebug-chatdata-azureai-ts-azureopenai.test.ts +++ b/packages/tests/src/ui-test/localdebug/localdebug-chatdata-azureai-ts-azureopenai.test.ts @@ -151,7 +151,7 @@ describe("Local Debug Tests", function () { throw new Error("Failed to install packages"); } - const insertDataCmd = `npm run indexer:create -- '${searchKey}' '${searchEndpoint}'`; + const insertDataCmd = `npm run indexer:create -- ${searchKey} ${azureOpenAiKey}`; const { success: insertDataSuccess } = await Executor.execute( insertDataCmd, projectPath diff --git a/packages/tests/src/ui-test/localdebug/localdebug-dashboard-tab-ts.test.ts b/packages/tests/src/ui-test/localdebug/localdebug-dashboard-tab-ts.test.ts index 978005f085..363743fcd4 100644 --- a/packages/tests/src/ui-test/localdebug/localdebug-dashboard-tab-ts.test.ts +++ b/packages/tests/src/ui-test/localdebug/localdebug-dashboard-tab-ts.test.ts @@ -15,6 +15,7 @@ import { Timeout, LocalDebugTaskLabel, DebugItemSelect, + LocalDebugTaskResult, } from "../../utils/constants"; import { Env } from "../../utils/env"; import { it } from "../../utils/it"; @@ -49,13 +50,13 @@ describe("Local Debug Tests", function () { localDebugTestContext.testRootFolder, localDebugTestContext.appName ); - validateFileExist(projectPath, "src/index.tsx"); + validateFileExist(projectPath, "src/main.tsx"); await startDebugging(DebugItemSelect.DebugInTeamsUsingChrome); await waitForTerminal( LocalDebugTaskLabel.StartFrontend, // [BUG] warning error message block the frontend validation - "Compiled with warnings" + LocalDebugTaskResult.FrontendReady ); const teamsAppId = await localDebugTestContext.getTeamsAppId(); diff --git a/packages/tests/src/ui-test/localdebug/localdebug-dashboard-tab.test.ts b/packages/tests/src/ui-test/localdebug/localdebug-dashboard-tab.test.ts index 11d97aa3c8..52f2588a54 100644 --- a/packages/tests/src/ui-test/localdebug/localdebug-dashboard-tab.test.ts +++ b/packages/tests/src/ui-test/localdebug/localdebug-dashboard-tab.test.ts @@ -15,6 +15,7 @@ import { Timeout, LocalDebugTaskLabel, DebugItemSelect, + LocalDebugTaskResult, } from "../../utils/constants"; import { Env } from "../../utils/env"; import { it } from "../../utils/it"; @@ -49,14 +50,14 @@ describe("Local Debug Tests", function () { localDebugTestContext.testRootFolder, localDebugTestContext.appName ); - validateFileExist(projectPath, "src/index.jsx"); + validateFileExist(projectPath, "src/main.jsx"); await startDebugging(DebugItemSelect.DebugInTeamsUsingChrome); await waitForTerminal( LocalDebugTaskLabel.StartFrontend, // [BUG] warning error message block the frontend validation - "Compiled with warnings" + LocalDebugTaskResult.FrontendReady ); const teamsAppId = await localDebugTestContext.getTeamsAppId(); diff --git a/packages/tests/src/ui-test/localdebug/localdebug-obo-tab-ts.test.ts b/packages/tests/src/ui-test/localdebug/localdebug-obo-tab-ts.test.ts index 6fa1acac72..860df66222 100644 --- a/packages/tests/src/ui-test/localdebug/localdebug-obo-tab-ts.test.ts +++ b/packages/tests/src/ui-test/localdebug/localdebug-obo-tab-ts.test.ts @@ -5,7 +5,11 @@ * @author Kuojian Lu */ import * as path from "path"; -import { startDebugging, waitForTerminal } from "../../utils/vscodeOperation"; +import { + clearNotifications, + startDebugging, + waitForTerminal, +} from "../../utils/vscodeOperation"; import { initPage, validateReactOutlookTab, @@ -16,6 +20,7 @@ import { Timeout, LocalDebugTaskLabel, LocalDebugError, + LocalDebugTaskResult, } from "../../utils/constants"; import { Env } from "../../utils/env"; import { it } from "../../utils/it"; @@ -60,12 +65,12 @@ describe("Local Debug M365 Tests", function () { try { await waitForTerminal( LocalDebugTaskLabel.StartBackend, - "Worker process started and initialized" + LocalDebugTaskResult.FunctionStarted ); - + await clearNotifications(); await waitForTerminal( LocalDebugTaskLabel.StartFrontend, - "Compiled successfully!" + LocalDebugTaskResult.FrontendReady ); } catch (error) { const errorMsg = error.toString(); @@ -91,10 +96,8 @@ describe("Local Debug M365 Tests", function () { await localDebugTestContext.validateLocalStateForTab(); await validateReactTab(page, Env.displayName, true); const m365AppId = await localDebugTestContext.getM365AppId(); - await page.goto( - `https://outlook.office.com/host/${m365AppId}/index?login_hint=${Env.username}` - ); - await validateReactOutlookTab(page, Env.displayName, true); + const url = `https://outlook.office.com/host/${m365AppId}/index?login_hint=${Env.username}`; + await validateReactOutlookTab(page, url, Env.displayName, true); } ); }); diff --git a/packages/tests/src/ui-test/localdebug/localdebug-obo-tab.test.ts b/packages/tests/src/ui-test/localdebug/localdebug-obo-tab.test.ts index e8ebe73c27..d3b78520d8 100644 --- a/packages/tests/src/ui-test/localdebug/localdebug-obo-tab.test.ts +++ b/packages/tests/src/ui-test/localdebug/localdebug-obo-tab.test.ts @@ -5,7 +5,11 @@ * @author Kuojian Lu */ import * as path from "path"; -import { startDebugging, waitForTerminal } from "../../utils/vscodeOperation"; +import { + clearNotifications, + startDebugging, + waitForTerminal, +} from "../../utils/vscodeOperation"; import { initPage, validateReactOutlookTab, @@ -16,6 +20,7 @@ import { Timeout, LocalDebugTaskLabel, LocalDebugError, + LocalDebugTaskResult, } from "../../utils/constants"; import { Env } from "../../utils/env"; import { it } from "../../utils/it"; @@ -58,12 +63,12 @@ describe("Local Debug M365 Tests", function () { try { await waitForTerminal( LocalDebugTaskLabel.StartBackend, - "Worker process started and initialized" + LocalDebugTaskResult.FunctionStarted ); - + await clearNotifications(); await waitForTerminal( LocalDebugTaskLabel.StartFrontend, - "Compiled successfully!" + LocalDebugTaskResult.FrontendReady ); } catch (error) { const errorMsg = error.toString(); @@ -89,10 +94,8 @@ describe("Local Debug M365 Tests", function () { await localDebugTestContext.validateLocalStateForTab(); await validateReactTab(page, Env.displayName, true); const m365AppId = await localDebugTestContext.getM365AppId(); - await page.goto( - `https://outlook.office.com/host/${m365AppId}/index?login_hint=${Env.username}` - ); - await validateReactOutlookTab(page, Env.displayName, true); + const url = `https://outlook.office.com/host/${m365AppId}/index?login_hint=${Env.username}`; + await validateReactOutlookTab(page, url, Env.displayName, true); } ); }); diff --git a/packages/tests/src/ui-test/localdebug/localdebug-tab-aad-deploy.test.ts b/packages/tests/src/ui-test/localdebug/localdebug-tab-aad-deploy.test.ts index dedb07fa39..faeec8796e 100644 --- a/packages/tests/src/ui-test/localdebug/localdebug-tab-aad-deploy.test.ts +++ b/packages/tests/src/ui-test/localdebug/localdebug-tab-aad-deploy.test.ts @@ -1,3 +1,6 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + /** * @author Xiaofu Huang */ @@ -5,6 +8,7 @@ import * as path from "path"; import * as chai from "chai"; import { VSBrowser } from "vscode-extension-tester"; import { + clearNotifications, getNotification, runDeployAadAppManifest, startDebugging, @@ -16,6 +20,8 @@ import { Timeout, LocalDebugTaskLabel, DebugItemSelect, + LocalDebugTaskResult, + LocalDebugError, } from "../../utils/constants"; import { Env } from "../../utils/env"; import { it } from "../../utils/it"; @@ -54,10 +60,29 @@ describe("Local Debug Tests", function () { await startDebugging(DebugItemSelect.DebugInTeamsUsingChrome); - await waitForTerminal( - LocalDebugTaskLabel.StartFrontend, - "Compiled successfully!" - ); + try { + await waitForTerminal( + LocalDebugTaskLabel.StartBackend, + LocalDebugTaskResult.FunctionStarted + ); + await clearNotifications(); + await waitForTerminal( + LocalDebugTaskLabel.StartFrontend, + LocalDebugTaskResult.FrontendReady + ); + } catch (error) { + const errorMsg = error.toString(); + if ( + // skip can't find element + errorMsg.includes(LocalDebugError.ElementNotInteractableError) || + // skip timeout + errorMsg.includes(LocalDebugError.TimeoutError) + ) { + console.log("[skip error] ", error); + } else { + chai.expect.fail(errorMsg); + } + } await stopDebugging(); diff --git a/packages/tests/src/ui-test/localdebug/localdebug-tab-regen-appid.test.ts b/packages/tests/src/ui-test/localdebug/localdebug-tab-regen-appid.test.ts index 292d4c013c..59ebead040 100644 --- a/packages/tests/src/ui-test/localdebug/localdebug-tab-regen-appid.test.ts +++ b/packages/tests/src/ui-test/localdebug/localdebug-tab-regen-appid.test.ts @@ -6,6 +6,7 @@ */ import * as path from "path"; import { + clearNotifications, startDebugging, stopDebugging, waitForTerminal, @@ -72,9 +73,11 @@ describe("Local Debug Tests", function () { await cleanAppStudio(localDebugTestContext.appName); - await startDebugging(DebugItemSelect.DebugInTeamsUsingChrome); + await driver.sleep(Timeout.shortTimeLoading); try { + await clearNotifications(); + await startDebugging(DebugItemSelect.DebugInTeamsUsingChrome); await waitForTerminal( LocalDebugTaskLabel.StartApplication, "restify listening to" @@ -86,23 +89,29 @@ describe("Local Debug Tests", function () { "restify listening to" ); } catch { - const dialog = new ModalDialog(); - console.log(`click "Cancel" button for error dialog`); - await dialog.pushButton("Cancel"); - await driver.sleep(Timeout.shortTimeLoading); - console.log( - `Clicked button "Cancel" for failing to attach to main target` - ); - await stopDebugging(); - await driver.sleep(Timeout.stopdebugging); + try { + console.log(`Try to click "Cancel" button for error dialog`); + const dialog = new ModalDialog(); + await dialog.pushButton("Cancel"); + await driver.sleep(Timeout.shortTimeLoading); + console.log( + `Clicked button "Cancel" for failing to attach to main target` + ); + await stopDebugging(); + await driver.sleep(Timeout.stopdebugging); + } catch { + console.log(`No error for failing to attach to main target`); + } + try { await killPort(53000); console.log(`close port 53000 successfully`); } catch (error) { console.log(`close port 53000 failed`); } - await startDebugging(DebugItemSelect.DebugInTeamsUsingChrome); + try { + await startDebugging(DebugItemSelect.DebugInTeamsUsingChrome); await waitForTerminal( LocalDebugTaskLabel.StartApplication, "restify listening to" @@ -114,8 +123,8 @@ describe("Local Debug Tests", function () { "restify listening to" ); } catch { + console.log(`Try to click "Debug Anyway" button for error dialog`); const dialog = new ModalDialog(); - console.log(`click "Debug Anyway" button for error dialog`); await dialog.pushButton("Debug Anyway"); console.log(`Clicked button "Debug Anyway"`); await driver.sleep(Timeout.shortTimeLoading); diff --git a/packages/tests/src/ui-test/remotedebug/remotedebug-chatdata-azureai-js-azureopenai.test.ts b/packages/tests/src/ui-test/remotedebug/remotedebug-chatdata-azureai-js-azureopenai.test.ts index 8df1a452e4..a02b2b5c5d 100644 --- a/packages/tests/src/ui-test/remotedebug/remotedebug-chatdata-azureai-js-azureopenai.test.ts +++ b/packages/tests/src/ui-test/remotedebug/remotedebug-chatdata-azureai-js-azureopenai.test.ts @@ -169,7 +169,7 @@ describe("Remote debug Tests", function () { throw new Error("Failed to install packages"); } - const insertDataCmd = `npm run indexer:create -- '${searchKey}' '${searchEndpoint}'`; + const insertDataCmd = `npm run indexer:create -- ${searchKey} ${azureOpenAiKey}`; const { success: insertDataSuccess } = await Executor.execute( insertDataCmd, projectPath diff --git a/packages/tests/src/ui-test/remotedebug/remotedebug-chatdata-azureai-ts-azureopenai.test.ts b/packages/tests/src/ui-test/remotedebug/remotedebug-chatdata-azureai-ts-azureopenai.test.ts index b74fadc532..dae010fd90 100644 --- a/packages/tests/src/ui-test/remotedebug/remotedebug-chatdata-azureai-ts-azureopenai.test.ts +++ b/packages/tests/src/ui-test/remotedebug/remotedebug-chatdata-azureai-ts-azureopenai.test.ts @@ -170,7 +170,7 @@ describe("Remote debug Tests", function () { throw new Error("Failed to install packages"); } - const insertDataCmd = `npm run indexer:create -- '${searchKey}' '${searchEndpoint}'`; + const insertDataCmd = `npm run indexer:create -- ${searchKey} ${azureOpenAiKey}`; const { success: insertDataSuccess } = await Executor.execute( insertDataCmd, projectPath diff --git a/packages/tests/src/ui-test/remotedebug/remotedebug-chatdata-customapi-js-openai-win-only.test.ts b/packages/tests/src/ui-test/remotedebug/remotedebug-chatdata-customapi-js-openai-win-only.test.ts index 5e94e8c86d..7be2ac86ea 100644 --- a/packages/tests/src/ui-test/remotedebug/remotedebug-chatdata-customapi-js-openai-win-only.test.ts +++ b/packages/tests/src/ui-test/remotedebug/remotedebug-chatdata-customapi-js-openai-win-only.test.ts @@ -58,7 +58,7 @@ describe("Remote debug Tests", function () { }); it( - "[auto][JS][Azure OpenAI] Remote debug for Custom Copilot Rag Custom Api", + "[auto][JS][OpenAI] Remote debug for Custom Copilot Rag Custom Api", { testPlanCaseId: 28891605, author: "v-annefu@microsoft.com", diff --git a/packages/tests/src/ui-test/remotedebug/remotedebug-chatdata-customapi-py-azureopenai-win-only.test.ts b/packages/tests/src/ui-test/remotedebug/remotedebug-chatdata-customapi-py-azureopenai-win-only.test.ts index 8edbdcd481..7f9905be2e 100644 --- a/packages/tests/src/ui-test/remotedebug/remotedebug-chatdata-customapi-py-azureopenai-win-only.test.ts +++ b/packages/tests/src/ui-test/remotedebug/remotedebug-chatdata-customapi-py-azureopenai-win-only.test.ts @@ -103,24 +103,54 @@ describe("Remote debug Tests", function () { Env.password ); await driver.sleep(Timeout.longTimeWait); - if (isRealKey) { - await validateCustomapi(page, { - hasWelcomeMessage: false, - hasCommandReplyValidation: true, - botCommand: "Get repairs for Karin", - expectedWelcomeMessage: ValidationContent.AiChatBotWelcomeInstruction, - expectedReplyMessage: "assignedTo: Karin", - timeout: Timeout.longTimeWait, - }); - } else { - await validateCustomapi(page, { - hasWelcomeMessage: false, - hasCommandReplyValidation: true, - botCommand: "helloWorld", - expectedWelcomeMessage: ValidationContent.AiChatBotWelcomeInstruction, - expectedReplyMessage: ValidationContent.AiBotErrorMessage, - timeout: Timeout.longTimeWait, - }); + try { + if (isRealKey) { + await validateCustomapi(page, { + hasWelcomeMessage: false, + hasCommandReplyValidation: true, + botCommand: "Get repairs for Karin", + expectedWelcomeMessage: + ValidationContent.AiChatBotWelcomeInstruction, + expectedReplyMessage: "assignedTo: Karin", + timeout: Timeout.longTimeWait, + }); + } else { + await validateCustomapi(page, { + hasWelcomeMessage: false, + hasCommandReplyValidation: true, + botCommand: "helloWorld", + expectedWelcomeMessage: + ValidationContent.AiChatBotWelcomeInstruction, + expectedReplyMessage: ValidationContent.AiBotErrorMessage, + timeout: Timeout.longTimeWait, + }); + } + } catch { + await RetryHandler.retry(async () => { + await deployProject(projectPath, Timeout.botDeploy); + await driver.sleep(Timeout.longTimeWait); + if (isRealKey) { + await validateCustomapi(page, { + hasWelcomeMessage: false, + hasCommandReplyValidation: true, + botCommand: "Get repairs for Karin", + expectedWelcomeMessage: + ValidationContent.AiChatBotWelcomeInstruction, + expectedReplyMessage: "assignedTo: Karin", + timeout: Timeout.longTimeWait, + }); + } else { + await validateCustomapi(page, { + hasWelcomeMessage: false, + hasCommandReplyValidation: true, + botCommand: "helloWorld", + expectedWelcomeMessage: + ValidationContent.AiChatBotWelcomeInstruction, + expectedReplyMessage: ValidationContent.AiBotErrorMessage, + timeout: Timeout.longTimeWait, + }); + } + }, 2); } } ); diff --git a/packages/tests/src/ui-test/remotedebug/remotedebug-chatdata-customapi-py-openai-win-only.test.ts b/packages/tests/src/ui-test/remotedebug/remotedebug-chatdata-customapi-py-openai-win-only.test.ts index 4d940edac5..4fe93c8d3b 100644 --- a/packages/tests/src/ui-test/remotedebug/remotedebug-chatdata-customapi-py-openai-win-only.test.ts +++ b/packages/tests/src/ui-test/remotedebug/remotedebug-chatdata-customapi-py-openai-win-only.test.ts @@ -88,24 +88,54 @@ describe("Remote debug Tests", function () { Env.password ); await driver.sleep(Timeout.longTimeWait); - if (isRealKey) { - await validateCustomapi(page, { - hasWelcomeMessage: false, - hasCommandReplyValidation: true, - botCommand: "Get repairs for Karin", - expectedWelcomeMessage: ValidationContent.AiChatBotWelcomeInstruction, - expectedReplyMessage: "assignedTo: Karin", - timeout: Timeout.longTimeWait, - }); - } else { - await validateCustomapi(page, { - hasWelcomeMessage: false, - hasCommandReplyValidation: true, - botCommand: "helloWorld", - expectedWelcomeMessage: ValidationContent.AiChatBotWelcomeInstruction, - expectedReplyMessage: ValidationContent.AiBotErrorMessage, - timeout: Timeout.longTimeWait, - }); + try { + if (isRealKey) { + await validateCustomapi(page, { + hasWelcomeMessage: false, + hasCommandReplyValidation: true, + botCommand: "Get repairs for Karin", + expectedWelcomeMessage: + ValidationContent.AiChatBotWelcomeInstruction, + expectedReplyMessage: "assignedTo: Karin", + timeout: Timeout.longTimeWait, + }); + } else { + await validateCustomapi(page, { + hasWelcomeMessage: false, + hasCommandReplyValidation: true, + botCommand: "helloWorld", + expectedWelcomeMessage: + ValidationContent.AiChatBotWelcomeInstruction, + expectedReplyMessage: ValidationContent.AiBotErrorMessage, + timeout: Timeout.longTimeWait, + }); + } + } catch { + await RetryHandler.retry(async () => { + await deployProject(projectPath, Timeout.botDeploy); + await driver.sleep(Timeout.longTimeWait); + if (isRealKey) { + await validateCustomapi(page, { + hasWelcomeMessage: false, + hasCommandReplyValidation: true, + botCommand: "Get repairs for Karin", + expectedWelcomeMessage: + ValidationContent.AiChatBotWelcomeInstruction, + expectedReplyMessage: "assignedTo: Karin", + timeout: Timeout.longTimeWait, + }); + } else { + await validateCustomapi(page, { + hasWelcomeMessage: false, + hasCommandReplyValidation: true, + botCommand: "helloWorld", + expectedWelcomeMessage: + ValidationContent.AiChatBotWelcomeInstruction, + expectedReplyMessage: ValidationContent.AiBotErrorMessage, + timeout: Timeout.longTimeWait, + }); + } + }, 2); } } ); diff --git a/packages/tests/src/ui-test/remotedebug/remotedebug-chatdata-customapi-ts-openai-win-only.test.ts b/packages/tests/src/ui-test/remotedebug/remotedebug-chatdata-customapi-ts-openai-win-only.test.ts index d82df59355..6bf35ea818 100644 --- a/packages/tests/src/ui-test/remotedebug/remotedebug-chatdata-customapi-ts-openai-win-only.test.ts +++ b/packages/tests/src/ui-test/remotedebug/remotedebug-chatdata-customapi-ts-openai-win-only.test.ts @@ -58,7 +58,7 @@ describe("Remote debug Tests", function () { }); it( - "[auto][TS][Azure OpenAI] Remote debug for Custom Copilot Rag Custom Api", + "[auto][TS][OpenAI] Remote debug for Custom Copilot Rag Custom Api", { testPlanCaseId: 28891618, author: "v-annefu@microsoft.com", diff --git a/packages/tests/src/utils/constants.ts b/packages/tests/src/utils/constants.ts index ed3a23ce48..a8d2f001cd 100644 --- a/packages/tests/src/utils/constants.ts +++ b/packages/tests/src/utils/constants.ts @@ -406,6 +406,8 @@ export enum LocalDebugTaskLabel { export class LocalDebugTaskResult { static readonly FrontendSuccess = "Compiled successfully"; + static readonly FrontendReady = "ready"; + static readonly FrontendNoIssue = "webpack compiled"; static readonly StartSuccess = "started successfully"; static readonly AzuriteSuccess = "Azurite Table service is successfully"; static readonly CompiledSuccess = "Found 0 errors"; @@ -418,6 +420,7 @@ export class LocalDebugTaskResult { static readonly WebServerSuccess = "press h to show help"; static readonly DockerFinish = "press any key to close it"; static readonly DevtunnelSuccess = "Ready to accept connections for tunnel:"; + static readonly FunctionStarted = "Worker process started and initialized"; } export enum LocalDebugTaskLabel2 { diff --git a/packages/tests/src/utils/playwrightOperation.ts b/packages/tests/src/utils/playwrightOperation.ts index 4cf4921f4b..0cc5f2ae57 100644 --- a/packages/tests/src/utils/playwrightOperation.ts +++ b/packages/tests/src/utils/playwrightOperation.ts @@ -1040,11 +1040,17 @@ export async function validateReactTab( export async function validateReactOutlookTab( page: Page, + url: string, displayName: string, includeFunction?: boolean ) { - try { + await RetryHandler.retry(async () => { + await Promise.all([page.goto(url), page.waitForNavigation()]); await page.waitForTimeout(Timeout.longTimeWait); + await page.waitForSelector('div[aria-label="hosted-app-tabs"]'); + }, 3); + + try { const frameElementHandle = await page.waitForSelector( 'iframe[data-tid="app-host-iframe"]' ); diff --git a/packages/vscode-extension/package.nls.json b/packages/vscode-extension/package.nls.json index 3419b0a7f6..7547e9b1fb 100644 --- a/packages/vscode-extension/package.nls.json +++ b/packages/vscode-extension/package.nls.json @@ -36,7 +36,7 @@ "teamstoolkit.capabilities.untrustedWorkspaces.description": "The Teams Toolkit extension supports limited features in untrusted workspaces.", "teamstoolkit.codeFlowLogin.loginCodeFlowFailureDescription": "Unable to get login code for token exchange. Log in with another account.", "teamstoolkit.codeFlowLogin.loginCodeFlowFailureTitle": "Login Code Error", - "teamstoolkit.codeFlowLogin.loginComponent": "Log In", + "teamstoolkit.codeFlowLogin.loginComponent": "Login", "teamstoolkit.codeFlowLogin.loginFailureDescription": "Unable to get user login information. Log in with another account.", "teamstoolkit.codeFlowLogin.loginFailureTitle": "Login unsuccessful", "teamstoolkit.codeFlowLogin.loginPortConflictDescription": "There was a delay in finding a login port. Please try again.", @@ -232,13 +232,13 @@ "teamstoolkit.handlers.autoInstallDependency": "Dependency installation in progress...", "teamstoolkit.handlers.adaptiveCardExtUsage": "Type \"Adaptive Card: Open Preview\" in command pallete to start previewing current Adaptive Card file.", "teamstoolkit.handlers.invalidProject": "Unable to debug Teams App. This is not a valid Teams project.", - "teamstoolkit.handlers.localDebugDescription": "[%s] is successfully created at [local address](%s). Continue to debug your app in Teams.", - "teamstoolkit.handlers.localDebugDescription.fallback": "[%s] is successfully created at %s. Continue to debug your app in Teams.", - "teamstoolkit.handlers.localDebugDescription.enabledTestTool": "[%s] is successfully created at [local address](%s). Continue to debug your app in Test Tool or Teams.", - "teamstoolkit.handlers.localDebugDescription.enabledTestTool.fallback": "[%s] is successfully created at %s. Continue to debug your app in Test Tool or Teams.", + "teamstoolkit.handlers.localDebugDescription": "[%s] successfully created at [local address](%s). You can now debug your app in Teams.", + "teamstoolkit.handlers.localDebugDescription.fallback": "[%s] successfully created at %s. You can now debug your app in Teams.", + "teamstoolkit.handlers.localDebugDescription.enabledTestTool": "[%s] successfully created at [local address](%s). You can now debug your app in Test Tool or Teams.", + "teamstoolkit.handlers.localDebugDescription.enabledTestTool.fallback": "[%s] successfully created at %s. You can now debug your app in Test Tool or Teams.", "teamstoolkit.handlers.localDebugTitle": "Debug", - "teamstoolkit.handlers.localPreviewDescription": "[%s] is successfully created at [local address](%s). Continue to preview your app.", - "teamstoolkit.handlers.localPreviewDescription.fallback": "[%s] is successfully created at %s. Continue to preview your app.", + "teamstoolkit.handlers.localPreviewDescription": "[%s] successfully created at [local address](%s). You can now preview your app.", + "teamstoolkit.handlers.localPreviewDescription.fallback": "[%s] successfully created at %s. You can now preview your app.", "teamstoolkit.handlers.localPreviewTitle": "Local Preview", "teamstoolkit.handlers.loginFailed": "Unable to log in. The operation is terminated.", "teamstoolkit.handlers.m365SignIn": "Successfully signed in to Microsoft 365 account.", @@ -274,10 +274,12 @@ "teamstoolkit.handlers.installOfficeAddinDependencyCancelled": "Dependency installation is canceled, but you can install dependencies manually by clicking the 'Development - Check and Install Dependencies' button on the left side.", "teamstoolkit.localDebug.learnMore": "Get More Info", "teamstoolkit.localDebug.m365TenantHintMessage": "After enrolling your developer tenant in Office 365 Target Release, enrollment may come into effect in couple of days. Click 'Get More Info' button for details on setting up dev environment to extend Teams apps across Microsoft 365.", - "teamstoolkit.handlers.askInstallCopilot": "To use GitHub Copilot, install its extension first.", - "teamstoolkit.handlers.askInstallCopilot.install": "Install", - "teamstoolkit.handlers.askInstallCopilot.cancel": "Cancel", - "teamstoolkit.handlers.installExtension.output": "You need to install %s following \"%s\" first.", + "teamstoolkit.handlers.askInstallCopilot": "To use GitHub Copilot Extension for Teams Toolkit when developing Teams apps, you need to install both GitHub Copilot and GitHub Copilot Extension for Teams Toolkit (@teamsapp).", + "_teamstoolkit.handlers.askInstallCopilot.comment": "@teamsapp is used to call Teams agent in Github Copilot Chat and should not be translated.", + "teamstoolkit.handlers.askInstallCopilot.install": "Install GitHub Copilot", + "teamstoolkit.handlers.askInstallCopilot.installTeamsApp": "Install @teamsapp", + "_teamstoolkit.handlers.askInstallCopilot.installTeamsApp.comment": "@teamsapp is used to call Teams agent in Github Copilot Chat and should not be translated.", + "teamstoolkit.handlers.installExtension.output": "To use GitHub Copilot Extension for Teams Toolkit when developing Teams apps, you need to install both GitHub Copilot Chat following \"%s\" and GitHub Copilot Extension for Teams Toolkit (@teamsapp) following \"%s\".", "teamstoolkit.handlers.installCopilotError": "Unable to install GitHub Copilot Chat. Install it following %s and try again.", "teamstoolkit.handlers.chatTeamsAgentError": "Unable to automatically focus GitHub Copilot Chat. Open GitHub Copilot Chat and start with \"%s\"", "teamstoolkit.handlers.verifyCopilotExtensionError": "Unable to verify GitHub Copilot Chat. Install it manually following %s and try again.", diff --git a/packages/vscode-extension/src/controls/sampleGallery/sampleCard.tsx b/packages/vscode-extension/src/controls/sampleGallery/sampleCard.tsx index 95e498a062..da49a08d19 100644 --- a/packages/vscode-extension/src/controls/sampleGallery/sampleCard.tsx +++ b/packages/vscode-extension/src/controls/sampleGallery/sampleCard.tsx @@ -45,7 +45,7 @@ export default class SampleCard extends React.Component sample app tags: -
+
{sample.tags && sample.tags.map((value: string) => { return ( diff --git a/packages/vscode-extension/src/debug/depsChecker/common.ts b/packages/vscode-extension/src/debug/depsChecker/common.ts index 5976599994..2afce39af6 100644 --- a/packages/vscode-extension/src/debug/depsChecker/common.ts +++ b/packages/vscode-extension/src/debug/depsChecker/common.ts @@ -16,19 +16,19 @@ import { } from "@microsoft/teamsfx-api"; import { AppStudioScopes, + CopilotDisabledError, DependencyStatus, DepsCheckerError, DepsManager, DepsType, + ErrorCategory, LocalEnvManager, - NodeNotFoundError, - NodeNotLtsError, + PackageService, + PortsConflictError, + SideloadingDisabledError, TelemetryContext, - V3NodeNotSupportedError, assembleError, getSideloadingStatus, - ErrorCategory, - PackageService, } from "@microsoft/teamsfx-core"; import * as os from "os"; import * as util from "util"; @@ -36,36 +36,36 @@ import * as vscode from "vscode"; import { signedOut } from "../../commonlib/common/constant"; import VsCodeLogInstance from "../../commonlib/log"; import M365TokenInstance from "../../commonlib/m365Login"; +import { PanelType } from "../../controls/PanelType"; +import { WebviewPanel } from "../../controls/webviewPanel"; import { ExtensionErrors, ExtensionSource } from "../../error/error"; -import { VS_CODE_UI } from "../../qm/vsc_ui"; import { tools, workspaceUri } from "../../globalVariables"; import { checkCopilotCallback } from "../../handlers/accounts/checkAccessCallback"; -import { ProgressHandler } from "../progressHandler"; +import { VS_CODE_UI } from "../../qm/vsc_ui"; import { ExtTelemetry } from "../../telemetry/extTelemetry"; import { TelemetryEvent, TelemetryProperty } from "../../telemetry/extTelemetryEvents"; -import { getDefaultString, localize } from "../../utils/localizeUtils"; -import { Step } from "../common/step"; +import { localize } from "../../utils/localizeUtils"; import { DisplayMessages, RecommendedOperations } from "../common/debugConstants"; -import { doctorConstant } from "./doctorConstant"; -import { vscodeLogger } from "./vscodeLogger"; -import { vscodeTelemetry } from "./vscodeTelemetry"; +import { Step } from "../common/step"; +import { + CheckResult, + PortCheckerInfo, + PrerequisiteCheckerInfo, + PrerequisiteOrderedChecker, +} from "../common/types"; import { localTelemetryReporter } from "../localTelemetryReporter"; +import { ProgressHandler } from "../progressHandler"; import { ProgressHelper } from "../progressHelper"; -import { WebviewPanel } from "../../controls/webviewPanel"; -import { PanelType } from "../../controls/PanelType"; +import { doctorConstant } from "./doctorConstant"; import { - ResultStatus, Checker, + DepsDisplayName, ProgressMessage, + ResultStatus, copilotCheckServiceScope, - DepsDisplayName, } from "./prerequisitesCheckerConstants"; -import { - CheckResult, - PrerequisiteOrderedChecker, - PrerequisiteCheckerInfo, - PortCheckerInfo, -} from "../common/types"; +import { vscodeLogger } from "./vscodeLogger"; +import { vscodeTelemetry } from "./vscodeTelemetry"; export async function _checkAndInstall( displayMessages: DisplayMessages, @@ -162,27 +162,11 @@ async function checkPort( ports.length > 1 ? ports.join(", ") : `${ports[0]}`; if (portsInUse.length > 0) { ctx.properties[TelemetryProperty.DebugPortsInUse] = JSON.stringify(portsInUse); - const message = util.format( - // eslint-disable-next-line no-secrets/no-secrets - getDefaultString("teamstoolkit.localDebug.portsAlreadyInUse"), - formatPortStr(portsInUse) - ); - const displayMessage = util.format( - // eslint-disable-next-line no-secrets/no-secrets - localize("teamstoolkit.localDebug.portsAlreadyInUse"), - formatPortStr(portsInUse) - ); - return { checker: Checker.Ports, result: ResultStatus.failed, failureMsg: doctorConstant.Port, - error: new UserError( - ExtensionSource, - ExtensionErrors.PortAlreadyInUse, - message, - displayMessage - ), + error: new PortsConflictError(ports, portsInUse, ExtensionSource), }; } return { @@ -314,14 +298,7 @@ async function ensureCopilotAccess( ctx.properties[TelemetryProperty.DebugHasCopilotAccess] = String(!!hasCopilotAccess); if (hasCopilotAccess === false) { // copilot disabled - return err( - new UserError( - ExtensionSource, - ExtensionErrors.PrerequisitesNoCopilotAccessError, - getDefaultString("teamstoolkit.accountTree.copilotWarningTooltip"), - localize("teamstoolkit.accountTree.copilotWarningTooltip") - ) - ); + return err(new CopilotDisabledError(ExtensionSource)); } return ok(undefined); @@ -351,14 +328,7 @@ async function ensureSideloding( ctx.properties[TelemetryProperty.DebugIsSideloadingAllowed] = String(!!isSideloadingEnabled); if (isSideloadingEnabled === false) { // sideloading disabled - return err( - new UserError( - ExtensionSource, - ExtensionErrors.PrerequisitesSideloadingDisabledError, - getDefaultString("teamstoolkit.accountTree.sideloadingWarningTooltip"), - localize("teamstoolkit.accountTree.sideloadingWarningTooltip") - ) - ); + return err(new SideloadingDisabledError(ExtensionSource)); } return ok(undefined); @@ -510,36 +480,12 @@ async function checkNode( function handleDepsCheckerError(error: any, dep?: DependencyStatus): FxError { if (dep) { - if (error instanceof NodeNotFoundError) { - handleNodeNotFoundError(error); - } - if (error instanceof V3NodeNotSupportedError) { - handleNodeNotLtsError(error); - } - if (error instanceof NodeNotLtsError) { - handleV3NodeNotSupportedError(error); - } + if (error.displayMessage) + error.displayMessage = `${error.displayMessage as string}${os.EOL}${ + doctorConstant.WhiteSpace + }${doctorConstant.RestartVSCode}`; } - return error instanceof DepsCheckerError - ? new UserError({ - error, - source: ExtensionSource, - name: ExtensionErrors.PrerequisitesValidationError, - helpLink: error.helpLink, - }) - : assembleError(error); -} - -function handleNodeNotFoundError(error: NodeNotFoundError) { - error.message = `${doctorConstant.NodeNotFound}${os.EOL}${doctorConstant.WhiteSpace}${doctorConstant.RestartVSCode}`; -} - -function handleV3NodeNotSupportedError(error: V3NodeNotSupportedError) { - error.message = `${error.message}${os.EOL}${doctorConstant.WhiteSpace}${doctorConstant.RestartVSCode}`; -} - -function handleNodeNotLtsError(error: V3NodeNotSupportedError) { - error.message = `${error.message}${os.EOL}${doctorConstant.WhiteSpace}${doctorConstant.RestartVSCode}`; + return error instanceof DepsCheckerError ? error : assembleError(error); } async function handleCheckResults( @@ -598,10 +544,7 @@ async function handleCheckResults( if (shouldStop) { await progressHelper?.stop(false); - const message = - getDefaultString(displayMessages.errorMessageKey) + - " " + - displayMessages.showDetailMessage(); + const message = failures.map((f) => f.error?.message || "").join(", "); // show failure summary in display message const displayMessage = @@ -612,20 +555,29 @@ async function handleCheckResults( localize(displayMessages.errorDisplayMessageKey) + " " + displayMessages.showDetailDisplayMessage(); - - const errorOptions: UserErrorOptions = { - source: ExtensionSource, - name: displayMessages.errorName, - message: message, - displayMessage: displayMessage, - helpLink: displayMessages.errorHelpLink, - }; - const userError = new UserError(errorOptions); - // Recommend to open test tool if M365 account check failed - if (failures.find((f) => f.checker === Checker.M365Account)) { - userError.recommendedOperation = RecommendedOperations.DebugInTestTool; + const firstFailure = failures[0]; + const firstError = firstFailure.error as UserError; + if (firstError) { + firstError.helpLink = displayMessages.errorHelpLink; + if (firstFailure.checker === Checker.M365Account) { + firstError.recommendedOperation = RecommendedOperations.DebugInTestTool; + } + throw firstError; + } else { + const errorOptions: UserErrorOptions = { + source: ExtensionSource, + name: displayMessages.errorName, + message: message, + displayMessage: displayMessage, + helpLink: displayMessages.errorHelpLink, + }; + const userError = new UserError(errorOptions); + // Recommend to open test tool if M365 account check failed + if (failures.find((f) => f.checker === Checker.M365Account)) { + userError.recommendedOperation = RecommendedOperations.DebugInTestTool; + } + throw userError; } - throw userError; } } } diff --git a/packages/vscode-extension/src/debug/depsChecker/taskChecker.ts b/packages/vscode-extension/src/debug/depsChecker/taskChecker.ts index a02ad0f4e4..7a1bec687b 100644 --- a/packages/vscode-extension/src/debug/depsChecker/taskChecker.ts +++ b/packages/vscode-extension/src/debug/depsChecker/taskChecker.ts @@ -82,9 +82,9 @@ function addCheckResultsForTelemetry( properties: { [key: string]: string }, errorProps: string[] ): void { - const [resultRaw, resultSafe] = convertCheckResultsForTelemetry(checkResults); - properties[TelemetryProperty.DebugCheckResultsSafe] = resultSafe; - properties[TelemetryProperty.DebugCheckResults] = resultRaw; + // const [resultRaw, resultSafe] = convertCheckResultsForTelemetry(checkResults); + // properties[TelemetryProperty.DebugCheckResultsSafe] = resultSafe; + // properties[TelemetryProperty.DebugCheckResults] = maskSecret(resultRaw, { replace: "***" }); // only the raw event contains error message errorProps.push(TelemetryProperty.DebugCheckResults); } diff --git a/packages/vscode-extension/src/handlers/copilotChatHandlers.ts b/packages/vscode-extension/src/handlers/copilotChatHandlers.ts index 776b2f4ed0..0c48e906e3 100644 --- a/packages/vscode-extension/src/handlers/copilotChatHandlers.ts +++ b/packages/vscode-extension/src/handlers/copilotChatHandlers.ts @@ -19,8 +19,14 @@ import { localize } from "../utils/localizeUtils"; import { showOutputChannelHandler } from "./showOutputChannel"; import { InstallCopilotChatLink } from "../constants"; import { isVSCodeInsiderVersion } from "../utils/versionUtil"; +import { VS_CODE_UI } from "../qm/vsc_ui"; const githubCopilotChatExtensionId = "github.copilot-chat"; +const teamsAgentLink = "https://aka.ms/install-teamsapp"; +enum installationTarget { + copilotChat = "copilot-chat", + teamsAgent = "teams-agent", +} function githubCopilotInstalled(): boolean { const extension = vscode.extensions.getExtension(githubCopilotChatExtensionId); @@ -58,7 +64,7 @@ async function openGithubCopilotChat(query: string): Promise> { +): Promise> { const eventName = "installCopilotChat"; const telemetryProperties = { [TelemetryProperty.TriggerFrom]: triggerFrom, @@ -68,14 +74,10 @@ export async function installGithubCopilotChatExtension( const confirmRes = await vscode.window.showInformationMessage( localize("teamstoolkit.handlers.askInstallCopilot"), localize("teamstoolkit.handlers.askInstallCopilot.install"), - localize("teamstoolkit.handlers.askInstallCopilot.cancel") + localize("teamstoolkit.handlers.askInstallCopilot.installTeamsApp") ); - if (confirmRes !== localize("teamstoolkit.handlers.askInstallCopilot.install")) { - const error = new UserCancelError(eventName, "cancel"); - ExtTelemetry.sendTelemetryErrorEvent(eventName, error, telemetryProperties); - return err(error); - } else { + if (confirmRes === localize("teamstoolkit.handlers.askInstallCopilot.install")) { await vscode.commands.executeCommand( "workbench.extensions.installExtension", githubCopilotChatExtensionId, @@ -88,9 +90,27 @@ export async function installGithubCopilotChatExtension( ExtTelemetry.sendTelemetryEvent(eventName, { ...telemetryProperties, [TelemetryProperty.Success]: TelemetrySuccess.Yes, + [TelemetryProperty.InstallTarget]: installationTarget.copilotChat, }); - return ok(null); + return ok({ installCopilot: true }); + } else if (confirmRes === localize("teamstoolkit.handlers.askInstallCopilot.installTeamsApp")) { + const openUrlRes = await VS_CODE_UI.openUrl(teamsAgentLink); + if (openUrlRes.isOk()) { + ExtTelemetry.sendTelemetryEvent(eventName, { + ...telemetryProperties, + [TelemetryProperty.Success]: TelemetrySuccess.Yes, + [TelemetryProperty.InstallTarget]: installationTarget.teamsAgent, + }); + return ok({ installCopilot: false }); + } else { + ExtTelemetry.sendTelemetryErrorEvent(eventName, openUrlRes.error, telemetryProperties); + return err(openUrlRes.error); + } + } else { + const error = new UserCancelError(eventName, "cancel"); + ExtTelemetry.sendTelemetryErrorEvent(eventName, error, telemetryProperties); + return err(error); } } catch (e) { const error = new SystemError( @@ -119,9 +139,9 @@ export async function invokeTeamsAgent(args?: any[]): Promise; const isExtensionInstalled = githubCopilotInstalled(); if (isExtensionInstalled) { @@ -130,8 +150,8 @@ export async function invokeTeamsAgent(args?: any[]): Promise ${eventName}, properties: ${JSON.stringify( + properties + )}, measurements: ${JSON.stringify(measurements)}` + ); } } @@ -144,6 +150,11 @@ export class VSCodeTelemetryReporter extends vscode.Disposable implements Teleme this.logTelemetryEvent(eventName, properties, measurements); } else { this.reporter.sendTelemetryEvent(eventName, properties, measurements); + void VSCodeLogger.debug( + `sendTelemetryEvent ===> ${eventName}, properties: ${JSON.stringify( + properties + )}, measurements: ${JSON.stringify(measurements)}` + ); } } diff --git a/packages/vscode-extension/test/handlers/copilotChatHandlers.test.ts b/packages/vscode-extension/test/handlers/copilotChatHandlers.test.ts index 6b8c580ffb..ca5f8bf30c 100644 --- a/packages/vscode-extension/test/handlers/copilotChatHandlers.test.ts +++ b/packages/vscode-extension/test/handlers/copilotChatHandlers.test.ts @@ -7,6 +7,8 @@ import * as handlers from "../../src/handlers/copilotChatHandlers"; import { ExtTelemetry } from "../../src/telemetry/extTelemetry"; import * as extTelemetryEvents from "../../src/telemetry/extTelemetryEvents"; import * as versionUtils from "../../src/utils/versionUtil"; +import { err, ok, SystemError } from "@microsoft/teamsfx-api"; +import * as vsc_ui from "../../src/qm/vsc_ui"; after(() => { sinon.restore(); @@ -37,6 +39,7 @@ describe("invokeTeamsAgent", async () => { hide: () => {}, dispose: () => {}, }); + sandbox.stub(vsc_ui, "VS_CODE_UI").value(new vsc_ui.VsCodeUI({})); }); it("no need to install Github Copilot", async () => { @@ -62,7 +65,7 @@ describe("invokeTeamsAgent", async () => { const commandStub = sandbox.stub(vscode.commands, "executeCommand").resolves(); sandbox .stub(vscode.window, "showInformationMessage") - .resolves("Install" as unknown as vscode.MessageItem); + .resolves("Install GitHub Copilot" as unknown as vscode.MessageItem); const job = handlers.invokeTeamsAgent([extTelemetryEvents.TelemetryTriggerFrom.TreeView]); await clock.tickAsync(6000); @@ -74,7 +77,55 @@ describe("invokeTeamsAgent", async () => { chai.assert.isTrue(res.isOk()); chai.assert.equal(commandStub.callCount, 3); - chai.assert.equal(commandStub.getCall(2).args[1].query, "@teams "); + chai.assert.isTrue( + (commandStub.getCall(2).args[1].query as string).startsWith("@teamsapp Use ") + ); + }); + + it("View Teams Agent link successfully", async () => { + clock = sandbox.useFakeTimers(); + sandbox.stub(versionUtils, "isVSCodeInsiderVersion").returns(true); + sandbox + .stub(vscode.extensions, "getExtension") + .onFirstCall() + .returns(undefined) + .onSecondCall() + .returns({ name: "github.copilot" } as any); + sandbox.stub(vscode.commands, "executeCommand").resolves(); + sandbox + .stub(vscode.window, "showInformationMessage") + .resolves("Install @teamsapp" as unknown as vscode.MessageItem); + const openUrlStub = sandbox.stub(vsc_ui.VS_CODE_UI, "openUrl").resolves(ok(true)); + + const res = await handlers.invokeTeamsAgent([extTelemetryEvents.TelemetryTriggerFrom.TreeView]); + + if (res.isErr()) { + console.log(res.error); + } + + chai.assert.isTrue(res.isOk()); + chai.assert.isTrue(openUrlStub.called); + }); + + it("Failed to view Teams Agent link", async () => { + clock = sandbox.useFakeTimers(); + sandbox.stub(versionUtils, "isVSCodeInsiderVersion").returns(true); + sandbox + .stub(vscode.extensions, "getExtension") + .onFirstCall() + .returns(undefined) + .onSecondCall() + .returns({ name: "github.copilot" } as any); + sandbox.stub(vscode.commands, "executeCommand").resolves(); + sandbox + .stub(vscode.window, "showInformationMessage") + .resolves("Install @teamsapp" as unknown as vscode.MessageItem); + sandbox + .stub(vsc_ui.VS_CODE_UI, "openUrl") + .resolves(err(new SystemError("source", "name", "", ""))); + const res = await handlers.invokeTeamsAgent([extTelemetryEvents.TelemetryTriggerFrom.TreeView]); + + chai.assert.isTrue(res.isErr() && res.error.source === "source"); }); it("install Github Copilot, wait and invoke Teams Agent", async () => { @@ -91,7 +142,7 @@ describe("invokeTeamsAgent", async () => { const commandStub = sandbox.stub(vscode.commands, "executeCommand").resolves(); sandbox .stub(vscode.window, "showInformationMessage") - .resolves("Install" as unknown as vscode.MessageItem); + .resolves("Install GitHub Copilot" as unknown as vscode.MessageItem); const job = handlers.invokeTeamsAgent(); await clock.tickAsync(6000); @@ -115,7 +166,7 @@ describe("invokeTeamsAgent", async () => { }); sandbox .stub(vscode.window, "showInformationMessage") - .resolves("Install" as unknown as vscode.MessageItem); + .resolves("Install GitHub Copilot" as unknown as vscode.MessageItem); sandbox.stub(VsCodeLogInstance, "error").resolves(); const res = await handlers.invokeTeamsAgent(); @@ -161,7 +212,7 @@ describe("invokeTeamsAgent", async () => { const commandStub = sandbox.stub(vscode.commands, "executeCommand").resolves(); sandbox .stub(vscode.window, "showInformationMessage") - .resolves("Install" as unknown as vscode.MessageItem); + .resolves("Install GitHub Copilot" as unknown as vscode.MessageItem); const job = handlers.invokeTeamsAgent(); await clock.tickAsync(30000); @@ -188,7 +239,7 @@ describe("invokeTeamsAgent", async () => { }); sandbox .stub(vscode.window, "showInformationMessage") - .resolves("Install" as unknown as vscode.MessageItem); + .resolves("Install GitHub Copilot" as unknown as vscode.MessageItem); const loggerError = sandbox.stub(VsCodeLogInstance, "error").resolves(); const res = await handlers.invokeTeamsAgent(); diff --git a/templates/csharp/ai-assistant-bot/{{ProjectName}}.csproj.tpl b/templates/csharp/ai-assistant-bot/{{ProjectName}}.csproj.tpl index 7f10bc3f99..9bc099bbad 100644 --- a/templates/csharp/ai-assistant-bot/{{ProjectName}}.csproj.tpl +++ b/templates/csharp/ai-assistant-bot/{{ProjectName}}.csproj.tpl @@ -23,5 +23,6 @@ + diff --git a/templates/csharp/ai-bot/{{ProjectName}}.csproj.tpl b/templates/csharp/ai-bot/{{ProjectName}}.csproj.tpl index 81c9b5bbe1..9c0607fda2 100644 --- a/templates/csharp/ai-bot/{{ProjectName}}.csproj.tpl +++ b/templates/csharp/ai-bot/{{ProjectName}}.csproj.tpl @@ -23,6 +23,7 @@ + diff --git a/templates/csharp/api-message-extension-sso/appPackage/apiSpecificationFile/repair.yml b/templates/csharp/api-message-extension-sso/appPackage/apiSpecificationFile/repair.yml index 7ca98042d0..94d0ea5dd1 100644 --- a/templates/csharp/api-message-extension-sso/appPackage/apiSpecificationFile/repair.yml +++ b/templates/csharp/api-message-extension-sso/appPackage/apiSpecificationFile/repair.yml @@ -25,26 +25,30 @@ paths: content: application/json: schema: - type: array - items: - properties: - id: - type: string - description: The unique identifier of the repair - title: - type: string - description: The short summary of the repair - description: - type: string - description: The detailed description of the repair - assignedTo: - type: string - description: The user who is responsible for the repair - date: - type: string - format: date-time - description: The date and time when the repair is scheduled or completed - image: - type: string - format: uri - description: The URL of the image of the item to be repaired or the repair process \ No newline at end of file + type: object + properties: + results: + type: array + items: + type: object + properties: + id: + type: string + description: The unique identifier of the repair + title: + type: string + description: The short summary of the repair + description: + type: string + description: The detailed description of the repair + assignedTo: + type: string + description: The user who is responsible for the repair + date: + type: string + format: date-time + description: The date and time when the repair is scheduled or completed + image: + type: string + format: uri + description: The URL of the image of the item to be repaired or the repair process \ No newline at end of file diff --git a/templates/csharp/api-plugin-from-scratch-oauth/appPackage/apiSpecificationFile/repair.dev.yml.tpl b/templates/csharp/api-plugin-from-scratch-oauth/appPackage/apiSpecificationFile/repair.dev.yml.tpl index 6dd6d35f3c..046e5f0ca1 100644 --- a/templates/csharp/api-plugin-from-scratch-oauth/appPackage/apiSpecificationFile/repair.dev.yml.tpl +++ b/templates/csharp/api-plugin-from-scratch-oauth/appPackage/apiSpecificationFile/repair.dev.yml.tpl @@ -38,10 +38,12 @@ paths: description: Returns a list of repairs with their details and images security: {{#MicrosoftEntra}} - - aadAuthCode: [] + - aadAuthCode: + - api://${{OPENAPI_SERVER_DOMAIN}}/${{AAD_APP_CLIENT_ID}}/repairs_read {{/MicrosoftEntra}} {{^MicrosoftEntra}} - - oAuth2AuthCode: [] + - oAuth2AuthCode: + - api://${{AAD_APP_CLIENT_ID}}/repairs_read {{/MicrosoftEntra}} parameters: - name: assignedTo diff --git a/templates/csharp/api-plugin-from-scratch-oauth/infra/azure.bicep.tpl b/templates/csharp/api-plugin-from-scratch-oauth/infra/azure.bicep.tpl index 5fb5177419..a57342103f 100644 --- a/templates/csharp/api-plugin-from-scratch-oauth/infra/azure.bicep.tpl +++ b/templates/csharp/api-plugin-from-scratch-oauth/infra/azure.bicep.tpl @@ -3,10 +3,6 @@ param resourceBaseName string param functionAppSKU string param aadAppClientId string -{{^MicrosoftEntra}} -@secure() -param aadAppClientSecret string -{{/MicrosoftEntra}} param aadAppTenantId string param aadAppOauthAuthorityHost string param location string = resourceGroup().location @@ -39,33 +35,15 @@ resource functionApp 'Microsoft.Web/sites@2021-02-01' = { } { name: 'FUNCTIONS_WORKER_RUNTIME' - value: 'node' // Set runtime to NodeJS + value: 'dotnet-isolated' // Use .NET isolated process } { name: 'WEBSITE_RUN_FROM_PACKAGE' value: '1' // Run Azure Functions from a package file } { - name: 'WEBSITE_NODE_DEFAULT_VERSION' - value: '~18' // Set NodeJS version to 18.x - } - { - name: 'M365_CLIENT_ID' - value: aadAppClientId - } -{{^MicrosoftEntra}} - { - name: 'M365_CLIENT_SECRET' - value: aadAppClientSecret - } -{{/MicrosoftEntra}} - { - name: 'M365_TENANT_ID' - value: aadAppTenantId - } - { - name: 'M365_AUTHORITY_HOST' - value: aadAppOauthAuthorityHost + name: 'SCM_ZIPDEPLOY_DONOT_PRESERVE_FILETIME' + value: '1' // Zipdeploy files will always be updated. Detail: https://aka.ms/teamsfx-zipdeploy-donot-preserve-filetime } ] ftpsState: 'FtpsOnly' diff --git a/templates/csharp/api-plugin-from-scratch-oauth/infra/azure.parameters.json.tpl b/templates/csharp/api-plugin-from-scratch-oauth/infra/azure.parameters.json.tpl index 2dd7c71d3d..a6fc2603cf 100644 --- a/templates/csharp/api-plugin-from-scratch-oauth/infra/azure.parameters.json.tpl +++ b/templates/csharp/api-plugin-from-scratch-oauth/infra/azure.parameters.json.tpl @@ -11,11 +11,6 @@ "aadAppClientId": { "value": "${{AAD_APP_CLIENT_ID}}" }, -{{^MicrosoftEntra}} - "aadAppClientSecret": { - "value": "${{SECRET_AAD_APP_CLIENT_SECRET}}" - }, -{{/MicrosoftEntra}} "aadAppTenantId": { "value": "${{AAD_APP_TENANT_ID}}" }, diff --git a/templates/csharp/command-and-response/{{ProjectName}}.csproj.tpl b/templates/csharp/command-and-response/{{ProjectName}}.csproj.tpl index d118067076..cd6af35da8 100644 --- a/templates/csharp/command-and-response/{{ProjectName}}.csproj.tpl +++ b/templates/csharp/command-and-response/{{ProjectName}}.csproj.tpl @@ -27,6 +27,7 @@ contentFiles + diff --git a/templates/csharp/copilot-plugin-from-scratch-api-key/appPackage/apiSpecificationFile/repair.yml b/templates/csharp/copilot-plugin-from-scratch-api-key/appPackage/apiSpecificationFile/repair.yml index fc3e5f6da5..e28f3f922d 100644 --- a/templates/csharp/copilot-plugin-from-scratch-api-key/appPackage/apiSpecificationFile/repair.yml +++ b/templates/csharp/copilot-plugin-from-scratch-api-key/appPackage/apiSpecificationFile/repair.yml @@ -32,26 +32,30 @@ paths: content: application/json: schema: - type: array - items: - properties: - id: - type: string - description: The unique identifier of the repair - title: - type: string - description: The short summary of the repair - description: - type: string - description: The detailed description of the repair - assignedTo: - type: string - description: The user who is responsible for the repair - date: - type: string - format: date-time - description: The date and time when the repair is scheduled or completed - image: - type: string - format: uri - description: The URL of the image of the item to be repaired or the repair process \ No newline at end of file + type: object + properties: + results: + type: array + items: + type: object + properties: + id: + type: string + description: The unique identifier of the repair + title: + type: string + description: The short summary of the repair + description: + type: string + description: The detailed description of the repair + assignedTo: + type: string + description: The user who is responsible for the repair + date: + type: string + format: date-time + description: The date and time when the repair is scheduled or completed + image: + type: string + format: uri + description: The URL of the image of the item to be repaired or the repair process \ No newline at end of file diff --git a/templates/csharp/copilot-plugin-from-scratch/appPackage/apiSpecificationFile/repair.yml b/templates/csharp/copilot-plugin-from-scratch/appPackage/apiSpecificationFile/repair.yml index 7ca98042d0..94d0ea5dd1 100644 --- a/templates/csharp/copilot-plugin-from-scratch/appPackage/apiSpecificationFile/repair.yml +++ b/templates/csharp/copilot-plugin-from-scratch/appPackage/apiSpecificationFile/repair.yml @@ -25,26 +25,30 @@ paths: content: application/json: schema: - type: array - items: - properties: - id: - type: string - description: The unique identifier of the repair - title: - type: string - description: The short summary of the repair - description: - type: string - description: The detailed description of the repair - assignedTo: - type: string - description: The user who is responsible for the repair - date: - type: string - format: date-time - description: The date and time when the repair is scheduled or completed - image: - type: string - format: uri - description: The URL of the image of the item to be repaired or the repair process \ No newline at end of file + type: object + properties: + results: + type: array + items: + type: object + properties: + id: + type: string + description: The unique identifier of the repair + title: + type: string + description: The short summary of the repair + description: + type: string + description: The detailed description of the repair + assignedTo: + type: string + description: The user who is responsible for the repair + date: + type: string + format: date-time + description: The date and time when the repair is scheduled or completed + image: + type: string + format: uri + description: The URL of the image of the item to be repaired or the repair process \ No newline at end of file diff --git a/templates/csharp/custom-copilot-assistant-assistants-api/{{ProjectName}}.csproj.tpl b/templates/csharp/custom-copilot-assistant-assistants-api/{{ProjectName}}.csproj.tpl index cb5a129677..f9e2143337 100644 --- a/templates/csharp/custom-copilot-assistant-assistants-api/{{ProjectName}}.csproj.tpl +++ b/templates/csharp/custom-copilot-assistant-assistants-api/{{ProjectName}}.csproj.tpl @@ -20,10 +20,11 @@ {{/isNewProjectTypeEnabled}} - - - + + + + diff --git a/templates/csharp/custom-copilot-assistant-new/{{ProjectName}}.csproj.tpl b/templates/csharp/custom-copilot-assistant-new/{{ProjectName}}.csproj.tpl index f3862dfc78..a453e7b684 100644 --- a/templates/csharp/custom-copilot-assistant-new/{{ProjectName}}.csproj.tpl +++ b/templates/csharp/custom-copilot-assistant-new/{{ProjectName}}.csproj.tpl @@ -20,10 +20,11 @@ {{/isNewProjectTypeEnabled}} - - - + + + + diff --git a/templates/csharp/custom-copilot-basic/{{ProjectName}}.csproj.tpl b/templates/csharp/custom-copilot-basic/{{ProjectName}}.csproj.tpl index 3ed873437b..63650c1e4c 100644 --- a/templates/csharp/custom-copilot-basic/{{ProjectName}}.csproj.tpl +++ b/templates/csharp/custom-copilot-basic/{{ProjectName}}.csproj.tpl @@ -20,9 +20,10 @@ {{/isNewProjectTypeEnabled}} - - - + + + + diff --git a/templates/csharp/custom-copilot-rag-azure-ai-search/{{ProjectName}}.csproj.tpl b/templates/csharp/custom-copilot-rag-azure-ai-search/{{ProjectName}}.csproj.tpl index 03e57c733e..a8bcac28a5 100644 --- a/templates/csharp/custom-copilot-rag-azure-ai-search/{{ProjectName}}.csproj.tpl +++ b/templates/csharp/custom-copilot-rag-azure-ai-search/{{ProjectName}}.csproj.tpl @@ -21,10 +21,11 @@ {{/isNewProjectTypeEnabled}} - - - - + + + + + diff --git a/templates/csharp/custom-copilot-rag-custom-api/APIActions.cs.tpl b/templates/csharp/custom-copilot-rag-custom-api/APIActions.cs.tpl index 6bd130b0c6..799ac52e67 100644 --- a/templates/csharp/custom-copilot-rag-custom-api/APIActions.cs.tpl +++ b/templates/csharp/custom-copilot-rag-custom-api/APIActions.cs.tpl @@ -15,11 +15,13 @@ namespace {{SafeProjectName}} { private APIClient Client; - public APIActions(string specPath) + public APIActions() { - Client = new APIClient(specPath); + Client = new APIClient("{{OPENAPI_SPEC_PATH}}"); } + // Replace with action code + private static IMessageActivity RenderCardToMessage(string cardTemplatePath, string data) { try @@ -48,15 +50,15 @@ namespace {{SafeProjectName}} PathObject = args.ContainsKey("path") ? args["path"] : null, HeaderObject = args.ContainsKey("header") ? args["header"] : null, QueryObject = args.ContainsKey("query") ? args["query"] : null, - RequestBody = args.ContainsKey("requestBody") ? args["requestBody"] : null + RequestBody = args.ContainsKey("body") ? args["body"] : null }; return requestParam; } [Action(AIConstants.UnknownActionName)] - public async Task UnknownAction([ActionTurnContext] TurnContext turnContext, [ActionName] string action) + public async Task UnknownActionAsync([ActionTurnContext] TurnContext turnContext, [ActionName] string action) { - await turnContext.SendActivityAsync(MessageFactory.Text("[lights off]")); + await turnContext.SendActivityAsync(MessageFactory.Text("Unable to find a matching API to call")); return "unknown action"; } } diff --git a/templates/csharp/custom-copilot-rag-custom-api/APIBot.cs.tpl b/templates/csharp/custom-copilot-rag-custom-api/APIBot.cs.tpl index 012a24dc4d..53f4ba31e2 100644 --- a/templates/csharp/custom-copilot-rag-custom-api/APIBot.cs.tpl +++ b/templates/csharp/custom-copilot-rag-custom-api/APIBot.cs.tpl @@ -5,10 +5,10 @@ namespace {{SafeProjectName}} { public class APIBot : Application { - public APIBot(ApplicationOptions options, string specPath) : base(options) + public APIBot(ApplicationOptions options) : base(options) { // Registering action handlers that will be hooked up to the planner. - AI.ImportActions(new APIActions(specPath)); + AI.ImportActions(new APIActions()); } } } \ No newline at end of file diff --git a/templates/csharp/custom-copilot-rag-custom-api/OpenAPIClient/OpenAPIClient.cs b/templates/csharp/custom-copilot-rag-custom-api/OpenAPIClient/OpenAPIClient.cs index 039341df1f..bf35d72f21 100644 --- a/templates/csharp/custom-copilot-rag-custom-api/OpenAPIClient/OpenAPIClient.cs +++ b/templates/csharp/custom-copilot-rag-custom-api/OpenAPIClient/OpenAPIClient.cs @@ -2,7 +2,6 @@ using System.Text.Json; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Readers; -using rentu_vs_ai_bot_test; using RestSharp.Authenticators; namespace OpenAPIClient diff --git a/templates/csharp/custom-copilot-rag-custom-api/Program.cs.tpl b/templates/csharp/custom-copilot-rag-custom-api/Program.cs.tpl index 75b018e932..0297691c4d 100644 --- a/templates/csharp/custom-copilot-rag-custom-api/Program.cs.tpl +++ b/templates/csharp/custom-copilot-rag-custom-api/Program.cs.tpl @@ -68,7 +68,7 @@ builder.Services.AddTransient(sp => PromptFolder = "./Prompts" }); - prompts.AddFunction("get_actions", async (context, memory, functions, tokenizer, args) => + prompts.AddFunction("getAction", async (context, memory, functions, tokenizer, args) => { var skpromptContent = File.ReadAllText("./Prompts/chat/actions.json"); return await Task.FromResult(skpromptContent); @@ -94,8 +94,7 @@ builder.Services.AddTransient(sp => Storage = sp.GetService(), AI = new(planner), LoggerFactory = loggerFactory, - }, - "./apiSpecificationFile/openapi.yaml"); + }); bot.OnConversationUpdate("membersAdded", async (turnContext, turnState, cancellationToken) => { diff --git a/templates/csharp/custom-copilot-rag-custom-api/{{ProjectName}}.csproj.tpl b/templates/csharp/custom-copilot-rag-custom-api/{{ProjectName}}.csproj.tpl index a0f4bc0920..d9887618f7 100644 --- a/templates/csharp/custom-copilot-rag-custom-api/{{ProjectName}}.csproj.tpl +++ b/templates/csharp/custom-copilot-rag-custom-api/{{ProjectName}}.csproj.tpl @@ -22,12 +22,13 @@ - - + + - + + @@ -35,17 +36,14 @@ PreserveNewest PreserveNewest - - - + + PreserveNewest PreserveNewest - - - + PreserveNewest diff --git a/templates/csharp/custom-copilot-rag-customize/{{ProjectName}}.csproj.tpl b/templates/csharp/custom-copilot-rag-customize/{{ProjectName}}.csproj.tpl index 63b83ff691..9c7b8c7e73 100644 --- a/templates/csharp/custom-copilot-rag-customize/{{ProjectName}}.csproj.tpl +++ b/templates/csharp/custom-copilot-rag-customize/{{ProjectName}}.csproj.tpl @@ -20,9 +20,10 @@ {{/isNewProjectTypeEnabled}} - - - + + + + diff --git a/templates/csharp/custom-copilot-rag-microsoft365/.gitignore b/templates/csharp/custom-copilot-rag-microsoft365/.gitignore new file mode 100644 index 0000000000..0755b1d291 --- /dev/null +++ b/templates/csharp/custom-copilot-rag-microsoft365/.gitignore @@ -0,0 +1,30 @@ +# TeamsFx files +build +appPackage/build +env/.env.*.user +env/.env.local +appsettings.Development.json +appsettings.TestTool.json +.deployment + +# User-specific files +*.user + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ + +# Notification local store +.notification.localstore.json +.notification.testtoolstore.json + +# devTools +devTools/ \ No newline at end of file diff --git a/templates/csharp/custom-copilot-rag-microsoft365/.{{NewProjectTypeName}}/README.md.tpl b/templates/csharp/custom-copilot-rag-microsoft365/.{{NewProjectTypeName}}/README.md.tpl new file mode 100644 index 0000000000..955f6ad270 --- /dev/null +++ b/templates/csharp/custom-copilot-rag-microsoft365/.{{NewProjectTypeName}}/README.md.tpl @@ -0,0 +1,69 @@ +# Overview of the Chat With Your Data (Using Microsoft 365 Data) template + +This app template showcases how to build one of the most powerful applications enabled by LLM - sophisticated question-answering (Q&A) chat bots that can answer questions about specific source information right in the Microsoft Teams. +This app template also demonstrates usage of techniques like: +- [Retrieval Augmented Generation](https://python.langchain.com/docs/use_cases/question_answering/#what-is-rag), or RAG. +- [Microsoft Graph Search API](https://learn.microsoft.com/graph/search-concept-overview) +- [Teams AI Library](https://learn.microsoft.com/microsoftteams/platform/bots/how-to/teams%20conversational%20ai/teams-conversation-ai-overview) + +## Quick Start + +**Prerequisites** +> To run the AI Chat Bot template in your local dev machine, you will need: +> +{{#useOpenAI}} +> - an account with [OpenAI](https://platform.openai.com). +{{/useOpenAI}} +{{#useAzureOpenAI}} +> - [Azure OpenAI](https://aka.ms/oai/access) resource +{{/useAzureOpenAI}} + +### Debug bot app in Teams Web Client +{{#useOpenAI}} +1. Ensure your OpenAI API Key is filled in `env/.env.local.user`. + ``` + SECRET_OPENAI_API_KEY="" + ``` +{{/useOpenAI}} +{{#useAzureOpenAI}} +1. Ensure your Azure OpenAI settings are filled in `env/.env.local.user`. + ``` + SECRET_AZURE_OPENAI_API_KEY="" + AZURE_OPENAI_ENDPOINT="" + AZURE_OPENAI_DEPLOYMENT_NAME="" + ``` +{{/useAzureOpenAI}} +1. Microsoft Graph Search API is available for searching SharePoint content, thus you just need to ensure your document in *src/data/\*.txt* is [uploaded to SharePoint / OneDrive](https://support.microsoft.com/office/upload-files-and-folders-to-a-library-da549fb1-1fcb-4167-87d0-4693e93cb7a0), no extra data ingestion required. +1. In the debug dropdown menu, select Dev Tunnels > Create A Tunnel (set authentication type to Public) or select an existing public dev tunnel. +1. Right-click your project and select Teams Toolkit > Prepare Teams App Dependencies. +1. If prompted, sign in with a Microsoft 365 account for the Teams organization you want to install the app to. +1. Press F5, or select the Debug > Start Debugging menu in Visual Studio. +1. In the launched browser, select the Add button to load the app in Teams. +1. In the chat bar, type and send anything to your bot to trigger a response. + +![M365 RAG Bot](https://github.com/OfficeDev/TeamsFx/assets/13211513/c2fff68c-53ce-445a-a101-97f0c127b825) + +> For local debugging using Teams Toolkit CLI, you need to do some extra steps described in [Set up your Teams Toolkit CLI for local debugging](https://aka.ms/teamsfx-cli-debugging). + +## Extend the AI Chat Bot template with more AI capabilities + +- You can follow [Get started with Teams AI library](https://learn.microsoft.com/en-us/microsoftteams/platform/bots/how-to/teams%20conversational%20ai/how-conversation-ai-get-started) to extend the AI Chat Bot template with more AI capabilities. +- Understand more about [how to add additional APIs](https://aka.ms/teamsfx-rag-bot#add-more-api-for-custom-api-as-data-source). + +## Additional information and references +- [Teams AI library](https://aka.ms/teams-ai-library) +- [Teams Toolkit Documentations](https://docs.microsoft.com/microsoftteams/platform/toolkit/teams-toolkit-fundamentals) +- [Teams Toolkit CLI](https://aka.ms/teamsfx-toolkit-cli) +- [Teams Toolkit Samples](https://github.com/OfficeDev/TeamsFx-Samples) + +## Learn more + +New to Teams app development or Teams Toolkit? Learn more about +Teams app manifests, deploying to the cloud, and more in the documentation +at https://aka.ms/teams-toolkit-vs-docs. + +## Report an issue + +Select Visual Studio > Help > Send Feedback > Report a Problem. +Or, you can create an issue directly in our GitHub repository: +https://github.com/OfficeDev/TeamsFx/issues. diff --git a/templates/csharp/custom-copilot-rag-microsoft365/.{{NewProjectTypeName}}/launchSettings.json.tpl b/templates/csharp/custom-copilot-rag-microsoft365/.{{NewProjectTypeName}}/launchSettings.json.tpl new file mode 100644 index 0000000000..452e60cb0f --- /dev/null +++ b/templates/csharp/custom-copilot-rag-microsoft365/.{{NewProjectTypeName}}/launchSettings.json.tpl @@ -0,0 +1,9 @@ +{ + "profiles": { + // Launch project within Teams + "Microsoft Teams (browser)": { + "commandName": "Project", + "launchUrl": "https://teams.microsoft.com/l/app/${{TEAMS_APP_ID}}?installAppPackage=true&webjoin=true&appTenantId=${{TEAMS_APP_TENANT_ID}}&login_hint=${{TEAMSFX_M365_USER_NAME}}", + } + } +} \ No newline at end of file diff --git a/templates/csharp/custom-copilot-rag-microsoft365/.{{NewProjectTypeName}}/{{NewProjectTypeName}}.{{NewProjectTypeExt}}.tpl b/templates/csharp/custom-copilot-rag-microsoft365/.{{NewProjectTypeName}}/{{NewProjectTypeName}}.{{NewProjectTypeExt}}.tpl new file mode 100644 index 0000000000..a31df153ea --- /dev/null +++ b/templates/csharp/custom-copilot-rag-microsoft365/.{{NewProjectTypeName}}/{{NewProjectTypeName}}.{{NewProjectTypeExt}}.tpl @@ -0,0 +1,6 @@ + + + + + + diff --git a/templates/csharp/custom-copilot-rag-microsoft365/.{{NewProjectTypeName}}/{{NewProjectTypeName}}.{{NewProjectTypeExt}}.user.tpl b/templates/csharp/custom-copilot-rag-microsoft365/.{{NewProjectTypeName}}/{{NewProjectTypeName}}.{{NewProjectTypeExt}}.user.tpl new file mode 100644 index 0000000000..9c141db6c7 --- /dev/null +++ b/templates/csharp/custom-copilot-rag-microsoft365/.{{NewProjectTypeName}}/{{NewProjectTypeName}}.{{NewProjectTypeExt}}.user.tpl @@ -0,0 +1,9 @@ + + + + ProjectDebugger + + + Microsoft Teams (browser) + + \ No newline at end of file diff --git a/templates/csharp/custom-copilot-rag-microsoft365/.{{NewProjectTypeName}}/{{ProjectName}}.slnLaunch.user.tpl b/templates/csharp/custom-copilot-rag-microsoft365/.{{NewProjectTypeName}}/{{ProjectName}}.slnLaunch.user.tpl new file mode 100644 index 0000000000..12c3f14c3f --- /dev/null +++ b/templates/csharp/custom-copilot-rag-microsoft365/.{{NewProjectTypeName}}/{{ProjectName}}.slnLaunch.user.tpl @@ -0,0 +1,25 @@ +[ + { + "Name": "Microsoft Teams (browser)", + "Projects": [ + { + "Path": "{{NewProjectTypeName}}\\{{NewProjectTypeName}}.{{NewProjectTypeExt}}", + "Name": "{{NewProjectTypeName}}\\{{NewProjectTypeName}}.{{NewProjectTypeExt}}", + "Action": "StartWithoutDebugging", + "DebugTarget": "Microsoft Teams (browser)" + }, + { +{{#PlaceProjectFileInSolutionDir}} + "Path": "{{ProjectName}}.csproj", + "Name": "{{ProjectName}}.csproj", +{{/PlaceProjectFileInSolutionDir}} +{{^PlaceProjectFileInSolutionDir}} + "Path": "{{ProjectName}}\\{{ProjectName}}.csproj", + "Name": "{{ProjectName}}\\{{ProjectName}}.csproj", +{{/PlaceProjectFileInSolutionDir}} + "Action": "Start", + "DebugTarget": "Start Project" + } + ] + } +] \ No newline at end of file diff --git a/templates/csharp/custom-copilot-rag-microsoft365/AdapterWithErrorHandler.cs.tpl b/templates/csharp/custom-copilot-rag-microsoft365/AdapterWithErrorHandler.cs.tpl new file mode 100644 index 0000000000..7bf4abcc44 --- /dev/null +++ b/templates/csharp/custom-copilot-rag-microsoft365/AdapterWithErrorHandler.cs.tpl @@ -0,0 +1,35 @@ +using Microsoft.Bot.Builder.Integration.AspNet.Core; +using Microsoft.Bot.Builder.TraceExtensions; +using Microsoft.Bot.Connector.Authentication; +using Microsoft.Bot.Schema; +using Microsoft.Teams.AI; + +namespace {{SafeProjectName}} +{ + public class AdapterWithErrorHandler : TeamsAdapter + { + public AdapterWithErrorHandler(IConfiguration configuration, ILogger logger) + : base(configuration, null, logger) + { + OnTurnError = async (turnContext, exception) => + { + // Log any leaked exception from the application. + // NOTE: In production environment, you should consider logging this to + // Azure Application Insights. Visit https://aka.ms/bottelemetry to see how + // to add telemetry capture to your bot. + logger.LogError(exception, $"[OnTurnError] unhandled error : {exception.Message}"); + + // Only send error message for user messages, not for other message types so the bot doesn't spam a channel or chat. + if (turnContext.Activity.Type == ActivityTypes.Message) + { + // Send a message to the user + await turnContext.SendActivityAsync($"The bot encountered an unhandled error: {exception.Message}"); + await turnContext.SendActivityAsync("To continue to run this bot, please fix the bot source code."); + + // Send a trace activity + await turnContext.TraceActivityAsync("OnTurnError Trace", exception.Message, "https://www.botframework.com/schemas/error", "TurnError"); + } + }; + } + } +} \ No newline at end of file diff --git a/templates/csharp/custom-copilot-rag-microsoft365/Config.cs.tpl b/templates/csharp/custom-copilot-rag-microsoft365/Config.cs.tpl new file mode 100644 index 0000000000..30118f1424 --- /dev/null +++ b/templates/csharp/custom-copilot-rag-microsoft365/Config.cs.tpl @@ -0,0 +1,43 @@ +namespace {{SafeProjectName}} +{ + public class ConfigOptions + { + public string BOT_ID { get; set; } + public string BOT_PASSWORD { get; set; } + public string BOT_TYPE { get; set; } + public string BOT_TENANT_ID { get; set; } + public string BOT_DOMAIN { get; set; } + public string AAD_APP_CLIENT_ID { get; set; } + public string AAD_APP_CLIENT_SECRET { get; set; } + public string AAD_APP_TENANT_ID { get; set; } + public string AAD_APP_OAUTH_AUTHORITY_HOST { get; set; } +{{#useOpenAI}} + public OpenAIConfigOptions OpenAI { get; set; } +{{/useOpenAI}} +{{#useAzureOpenAI}} + public AzureConfigOptions Azure { get; set; } +{{/useAzureOpenAI}} + } + +{{#useOpenAI}} + /// + /// Options for Open AI + /// + public class OpenAIConfigOptions + { + public string ApiKey { get; set; } + public string DefaultModel = "gpt-3.5-turbo"; + } +{{/useOpenAI}} +{{#useAzureOpenAI}} + /// + /// Options for Azure OpenAI and Azure Content Safety + /// + public class AzureConfigOptions + { + public string OpenAIApiKey { get; set; } + public string OpenAIEndpoint { get; set; } + public string OpenAIDeploymentName { get; set; } + } +{{/useAzureOpenAI}} +} diff --git a/templates/csharp/custom-copilot-rag-microsoft365/Controllers/BotController.cs.tpl b/templates/csharp/custom-copilot-rag-microsoft365/Controllers/BotController.cs.tpl new file mode 100644 index 0000000000..d64474b006 --- /dev/null +++ b/templates/csharp/custom-copilot-rag-microsoft365/Controllers/BotController.cs.tpl @@ -0,0 +1,26 @@ +using Microsoft.AspNetCore.Mvc; +using Microsoft.Bot.Builder; +using Microsoft.Teams.AI; + +namespace {{SafeProjectName}}.Controllers +{ + [Route("api/messages")] + [ApiController] + public class BotController : ControllerBase + { + private readonly TeamsAdapter Adapter; + private readonly IBot Bot; + + public BotController(TeamsAdapter adapter, IBot bot) + { + Adapter = adapter; + Bot = bot; + } + + [HttpPost] + public async Task PostAsync(CancellationToken cancellationToken = default) + { + await Adapter.ProcessAsync(Request, Response, Bot, cancellationToken); + } + } +} \ No newline at end of file diff --git a/templates/csharp/custom-copilot-rag-microsoft365/GraphDataSource.cs.tpl b/templates/csharp/custom-copilot-rag-microsoft365/GraphDataSource.cs.tpl new file mode 100644 index 0000000000..7063904229 --- /dev/null +++ b/templates/csharp/custom-copilot-rag-microsoft365/GraphDataSource.cs.tpl @@ -0,0 +1,73 @@ +using Azure; +using Microsoft.Bot.Builder; +using Microsoft.Graph.SecurityNamespace; +using Microsoft.Teams.AI.AI.DataSources; +using Microsoft.Teams.AI.AI.Prompts.Sections; +using Microsoft.Teams.AI.AI.Tokenizers; +using Microsoft.Teams.AI.State; +using System.Reflection.Metadata; +using System.Text; + +namespace {{SafeProjectName}} +{ + public class GraphDataSource : IDataSource + { + public string Name { get; } + public GraphDataSource(string name) + { + Name = name; + } + public async Task> RenderDataAsync(ITurnContext context, IMemory memory, ITokenizer tokenizer, int maxTokens, CancellationToken cancellationToken) + { + string? query = memory.GetValue("temp.input") as string; + + if (query == null) + { + return new RenderedPromptSection(string.Empty, 0); + } + var token = (memory as TurnState).Temp.AuthTokens["graph"]; + var graphClient = new SimpleGraphClient(token); + + var graphQuery = query; + if (query.ToLower().Contains("perksplus")) + { + graphQuery = "perksplus program"; + } + else if (query.ToLower().Contains("company")) + { + graphQuery = "company history"; + } + else if (query.ToLower().Contains("northwind")) + { + graphQuery = "northwind health"; + } + + var resourceUrls = await graphClient.GetQuery(graphQuery); + // Concatenate the restaurant documents (i.e json object) string into a single document + // until the maximum token limit is reached. This can be specified in the prompt template. + int usedTokens = 0; + StringBuilder doc = new StringBuilder(""); + foreach (var url in resourceUrls) + { + var content = await graphClient.DownloadSharepointFile(SimpleGraphClient.UrlToSharingToken(url)); + string document = $"{content}\n\n"; + int tokens = tokenizer.Encode(document).Count; + + if (usedTokens + tokens > maxTokens) + { + break; + } + + doc.Append(document); + usedTokens += tokens; + } + + return new RenderedPromptSection(formatDocument(doc.ToString()), usedTokens, usedTokens > maxTokens); + } + + private string formatDocument(string result) + { + return $"{result}"; + } + } +} diff --git a/templates/csharp/custom-copilot-rag-microsoft365/Model/AppState.cs.tpl b/templates/csharp/custom-copilot-rag-microsoft365/Model/AppState.cs.tpl new file mode 100644 index 0000000000..5d35ddd1af --- /dev/null +++ b/templates/csharp/custom-copilot-rag-microsoft365/Model/AppState.cs.tpl @@ -0,0 +1,52 @@ +using Microsoft.Teams.AI.State; + +namespace {{SafeProjectName}}.Model +{ + // Extend the turn state by configuring custom strongly typed state classes. + public class AppState : TurnState + { + public AppState() : base() + { + ScopeDefaults[CONVERSATION_SCOPE] = new ConversationState(); + } + + /// + /// Stores all the conversation-related state. + /// + public new ConversationState Conversation + { + get + { + TurnStateEntry scope = GetScope(CONVERSATION_SCOPE); + if (scope == null) + { + throw new ArgumentException("TurnState hasn't been loaded. Call LoadStateAsync() first."); + } + + return (ConversationState)scope.Value!; + } + set + { + TurnStateEntry scope = GetScope(CONVERSATION_SCOPE); + if (scope == null) + { + throw new ArgumentException("TurnState hasn't been loaded. Call LoadStateAsync() first."); + } + + scope.Replace(value!); + } + } + } + + // This class adds custom properties to the turn state which will be accessible in the activity handler methods. + public class ConversationState : Record + { + private const string _countKey = "countKey"; + + public int MessageCount + { + get => Get(_countKey); + set => Set(_countKey, value); + } + } +} diff --git a/templates/csharp/custom-copilot-rag-microsoft365/Program.cs.tpl b/templates/csharp/custom-copilot-rag-microsoft365/Program.cs.tpl new file mode 100644 index 0000000000..e63812619a --- /dev/null +++ b/templates/csharp/custom-copilot-rag-microsoft365/Program.cs.tpl @@ -0,0 +1,158 @@ +using {{SafeProjectName}}; +using Microsoft.Bot.Builder; +using Microsoft.Bot.Builder.Integration.AspNet.Core; +using Microsoft.Bot.Connector.Authentication; +using Microsoft.Teams.AI; +using Microsoft.Teams.AI.AI.Models; +using Microsoft.Teams.AI.AI.Planners; +using Microsoft.Teams.AI.AI.Prompts; +using Microsoft.Teams.AI.State; +using Microsoft.Identity.Client; +using Microsoft.Identity.Web; +using {{SafeProjectName}}.Model; + +var builder = WebApplication.CreateBuilder(args); + +builder.Services.AddControllers(); +builder.Services.AddHttpClient("WebClient", client => client.Timeout = TimeSpan.FromSeconds(600)); +builder.Services.AddHttpContextAccessor(); + +// Prepare Configuration for ConfigurationBotFrameworkAuthentication +var config = builder.Configuration.Get(); +builder.Configuration["MicrosoftAppType"] = config.BOT_TYPE; +builder.Configuration["MicrosoftAppId"] = config.BOT_ID; +builder.Configuration["MicrosoftAppPassword"] = config.BOT_PASSWORD; +builder.Configuration["MicrosoftAppTenantId"] = config.BOT_TENANT_ID; +// Create the Bot Framework Authentication to be used with the Bot Adapter. +builder.Services.AddSingleton(); + +// Create the Cloud Adapter with error handling enabled. +// Note: some classes expect a BotAdapter and some expect a BotFrameworkHttpAdapter, so +// register the same adapter instance for both types. +builder.Services.AddSingleton(); +builder.Services.AddSingleton(sp => sp.GetService()); +builder.Services.AddSingleton(sp => sp.GetService()); + +builder.Services.AddSingleton(); + +{{#useOpenAI}} +builder.Services.AddSingleton(sp => new( + new OpenAIModelOptions(config.OpenAI.ApiKey, config.OpenAI.DefaultModel) + { + LogRequests = true + }, + sp.GetService() +)); +{{/useOpenAI}} +{{#useAzureOpenAI}} +builder.Services.AddSingleton(sp => new( + new AzureOpenAIModelOptions( + config.Azure.OpenAIApiKey, + config.Azure.OpenAIDeploymentName, + config.Azure.OpenAIEndpoint + ) + { + LogRequests = true + }, + sp.GetService() +)); +{{/useAzureOpenAI}} + +builder.Services.AddSingleton(sp => +{ + IConfidentialClientApplication app = ConfidentialClientApplicationBuilder.Create(config.AAD_APP_CLIENT_ID) + .WithClientSecret(config.AAD_APP_CLIENT_SECRET) + .WithTenantId(config.AAD_APP_TENANT_ID) + .WithLegacyCacheCompatibility(false) + .Build(); + app.AddInMemoryTokenCache(); // For development purpose only, use distributed cache in production environment + return app; +}); + +GraphDataSource myDataSource = new GraphDataSource("graph-ai-search"); + +// Create the bot as transient. In this case the ASP Controller is expecting an IBot. +builder.Services.AddTransient(sp => +{ + // Create loggers + ILoggerFactory loggerFactory = sp.GetService(); + + // Create Prompt Manager + PromptManager prompts = new(new() + { + PromptFolder = "./Prompts" + }); + prompts.AddDataSource("graph-ai-search", myDataSource); + + // Create ActionPlanner + ActionPlanner planner = new( + options: new( + model: sp.GetService(), + prompts: prompts, + defaultPrompt: async (context, state, planner) => + { + PromptTemplate template = prompts.GetPrompt("chat"); + return await Task.FromResult(template); + } + ) + { LogRepairs = true }, + loggerFactory: loggerFactory + ); + + IStorage storage = sp.GetService()!; + TeamsAdapter adapter = sp.GetService()!; + IConfidentialClientApplication msal = sp.GetService(); + string signInLink = $"https://{config.BOT_DOMAIN}/auth-start.html"; + AuthenticationOptions options = new(); + options.AutoSignIn = (context, cancellationToken) => Task.FromResult(true); + options.AddAuthentication("graph", new TeamsSsoSettings(new string[] { "Files.Read.All" }, signInLink, msal)); + + Application app = new ApplicationBuilder() + .WithAIOptions(new(planner)) + .WithStorage(sp.GetService()) + .WithTurnStateFactory(() => new AppState()) + .WithAuthentication(adapter, options) + .Build(); + + app.OnConversationUpdate("membersAdded", async (turnContext, turnState, cancellationToken) => + { + var welcomeText = "How can I help you today?"; + foreach (var member in turnContext.Activity.MembersAdded) + { + if (member.Id != turnContext.Activity.Recipient.Id) + { + await turnContext.SendActivityAsync(MessageFactory.Text(welcomeText), cancellationToken); + } + } + }); + + app.Authentication.Get("graph").OnUserSignInSuccess(async (turnContext, turnState) => + { + // Successfully logged in + await turnContext.SendActivityAsync("You are successfully logged in. You can send a new message to talk to the bot."); + }); + app.Authentication.Get("graph").OnUserSignInFailure(async (turnContext, turnState, error) => + { + // Failed to login + await turnContext.SendActivityAsync("Failed to login"); + await turnContext.SendActivityAsync($"Error message: { error.Message}"); + }); + + return app; +}); + +var app = builder.Build(); + +if (app.Environment.IsDevelopment()) +{ + app.UseDeveloperExceptionPage(); +} + +app.UseStaticFiles(); +app.UseRouting(); +app.UseEndpoints(endpoints => +{ + endpoints.MapControllers(); +}); + +app.Run(); \ No newline at end of file diff --git a/templates/csharp/custom-copilot-rag-microsoft365/Prompts/chat/config.json b/templates/csharp/custom-copilot-rag-microsoft365/Prompts/chat/config.json new file mode 100644 index 0000000000..58858af4d3 --- /dev/null +++ b/templates/csharp/custom-copilot-rag-microsoft365/Prompts/chat/config.json @@ -0,0 +1,22 @@ +{ + "schema": 1.1, + "description": "Chat with Teams RAG.", + "type": "completion", + "completion": { + "completion_type": "chat", + "include_history": true, + "include_input": true, + "max_input_tokens": 5000, + "max_tokens": 1000, + "temperature": 0.9, + "top_p": 0.0, + "presence_penalty": 0.6, + "frequency_penalty": 0.0, + "stop_sequences": [] + }, + "augmentation": { + "data_sources": { + "graph-ai-search": 1200 + } + } +} \ No newline at end of file diff --git a/templates/csharp/custom-copilot-rag-microsoft365/Prompts/chat/skprompt.txt b/templates/csharp/custom-copilot-rag-microsoft365/Prompts/chat/skprompt.txt new file mode 100644 index 0000000000..2a2ebee5a3 --- /dev/null +++ b/templates/csharp/custom-copilot-rag-microsoft365/Prompts/chat/skprompt.txt @@ -0,0 +1,3 @@ +The following is a conversation with an AI assistant, who is an expert on answering questions over the given context. +Responses should be in a short journalistic style with no more than 80 words. +Use the context provided in the `` tags as the source for your answers. \ No newline at end of file diff --git a/templates/csharp/custom-copilot-rag-microsoft365/Properties/launchSettings.json.tpl b/templates/csharp/custom-copilot-rag-microsoft365/Properties/launchSettings.json.tpl new file mode 100644 index 0000000000..a2ef318d4d --- /dev/null +++ b/templates/csharp/custom-copilot-rag-microsoft365/Properties/launchSettings.json.tpl @@ -0,0 +1,40 @@ +{ + "profiles": { +{{^isNewProjectTypeEnabled}} + // Debug project within Teams + "Microsoft Teams (browser)": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": true, + "launchUrl": "https://teams.microsoft.com/l/app/${{TEAMS_APP_ID}}?installAppPackage=true&webjoin=true&appTenantId=${{TEAMS_APP_TENANT_ID}}&login_hint=${{TEAMSFX_M365_USER_NAME}}", + "applicationUrl": "http://localhost:5130", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + }, + "hotReloadProfile": "aspnetcore" + }, + //// Uncomment following profile to debug project only (without launching Teams) + //, + //"Start Project (not in Teams)": { + // "commandName": "Project", + // "dotnetRunMessages": true, + // "applicationUrl": "https://localhost:7130;http://localhost:5130", + // "environmentVariables": { + // "ASPNETCORE_ENVIRONMENT": "Development" + // }, + // "hotReloadProfile": "aspnetcore" + //} +{{/isNewProjectTypeEnabled}} +{{#isNewProjectTypeEnabled}} + "Start Project": { + "commandName": "Project", + "dotnetRunMessages": true, + "applicationUrl": "http://localhost:5130", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + }, + "hotReloadProfile": "aspnetcore" + }, +{{/isNewProjectTypeEnabled}} + } +} \ No newline at end of file diff --git a/templates/csharp/custom-copilot-rag-microsoft365/SimpleGraphClient.cs.tpl b/templates/csharp/custom-copilot-rag-microsoft365/SimpleGraphClient.cs.tpl new file mode 100644 index 0000000000..1fcc57e4d5 --- /dev/null +++ b/templates/csharp/custom-copilot-rag-microsoft365/SimpleGraphClient.cs.tpl @@ -0,0 +1,75 @@ +using Microsoft.Graph; +using System.Net.Http.Headers; + +namespace {{SafeProjectName}} +{ + public class SimpleGraphClient + { + private readonly string _token; + private GraphServiceClient graphClient; + + public SimpleGraphClient(string token) + { + if (string.IsNullOrWhiteSpace(token)) + { + throw new ArgumentNullException(nameof(token)); + } + + _token = token; + graphClient = GetAuthenticatedClient(); + } + + public async Task> GetQuery(string query) + { + var q = new SearchRequestObject() + { + EntityTypes = new[] + { + EntityType.DriveItem + }, + Query = new SearchQuery() + { + QueryString = query + }, + }; + var res = await graphClient.Search.Query(new List { q }).Request().PostAsync(); + var urls = res.CurrentPage[0].HitsContainers.SelectMany(hitContainer => hitContainer.Hits ?? []).Select(hit => (hit.Resource as DriveItem).WebUrl).ToList(); + return urls; + } + + public async Task DownloadSharepointFile(string contentUrl) + { + var fileContentResponse = await graphClient.HttpProvider.SendAsync(new HttpRequestMessage(HttpMethod.Get, $"https://graph.microsoft.com/v1.0/shares/{contentUrl}/driveItem/content") + { + Headers = + { + Authorization = new AuthenticationHeaderValue("Bearer", _token) + } + }); + + var fileContent = await fileContentResponse.Content.ReadAsStringAsync(); + return fileContent; + } + + // Get an Authenticated Microsoft Graph client using the token issued to the user. + private GraphServiceClient GetAuthenticatedClient() + { + var graphClient = new GraphServiceClient( + new DelegateAuthenticationProvider( + requestMessage => + { + // Append the access token to the request. + requestMessage.Headers.Authorization = new AuthenticationHeaderValue("bearer", _token); + + return Task.CompletedTask; + })); + return graphClient; + } + + public static string UrlToSharingToken(string inputUrl) + { + var base64Value = System.Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes(inputUrl)); + return "u!" + base64Value.TrimEnd('=').Replace('/', '_').Replace('+', '-'); + } + } +} diff --git a/templates/csharp/custom-copilot-rag-microsoft365/aad.manifest.json.tpl b/templates/csharp/custom-copilot-rag-microsoft365/aad.manifest.json.tpl new file mode 100644 index 0000000000..c8cbb2278e --- /dev/null +++ b/templates/csharp/custom-copilot-rag-microsoft365/aad.manifest.json.tpl @@ -0,0 +1,107 @@ +{ + "id": "${{AAD_APP_OBJECT_ID}}", + "appId": "${{AAD_APP_CLIENT_ID}}", + "name": "{{appName}}-aad", + "accessTokenAcceptedVersion": 2, + "signInAudience": "AzureADMyOrg", + "optionalClaims": { + "idToken": [], + "accessToken": [ + { + "name": "idtyp", + "source": null, + "essential": false, + "additionalProperties": [] + } + ], + "saml2Token": [] + }, + "requiredResourceAccess": [ + { + "resourceAppId": "Microsoft Graph", + "resourceAccess": [ + { + "id": "Files.Read.All", + "type": "Scope" + } + ] + } + ], + "oauth2Permissions": [ + { + "adminConsentDescription": "Allows Teams to call the app's web APIs as the current user.", + "adminConsentDisplayName": "Teams can access app's web APIs", + "id": "${{AAD_APP_ACCESS_AS_USER_PERMISSION_ID}}", + "isEnabled": true, + "type": "User", + "userConsentDescription": "Enable Teams to call this app's web APIs with the same rights that you have", + "userConsentDisplayName": "Teams can access app's web APIs and make requests on your behalf", + "value": "access_as_user" + } + ], + "preAuthorizedApplications": [ + { + "appId": "1fec8e78-bce4-4aaf-ab1b-5451cc387264", + "permissionIds": [ + "${{AAD_APP_ACCESS_AS_USER_PERMISSION_ID}}" + ] + }, + { + "appId": "5e3ce6c0-2b1f-4285-8d4b-75ee78787346", + "permissionIds": [ + "${{AAD_APP_ACCESS_AS_USER_PERMISSION_ID}}" + ] + }, + { + "appId": "d3590ed6-52b3-4102-aeff-aad2292ab01c", + "permissionIds": [ + "${{AAD_APP_ACCESS_AS_USER_PERMISSION_ID}}" + ] + }, + { + "appId": "00000002-0000-0ff1-ce00-000000000000", + "permissionIds": [ + "${{AAD_APP_ACCESS_AS_USER_PERMISSION_ID}}" + ] + }, + { + "appId": "bc59ab01-8403-45c6-8796-ac3ef710b3e3", + "permissionIds": [ + "${{AAD_APP_ACCESS_AS_USER_PERMISSION_ID}}" + ] + }, + { + "appId": "0ec893e0-5785-4de6-99da-4ed124e5296c", + "permissionIds": [ + "${{AAD_APP_ACCESS_AS_USER_PERMISSION_ID}}" + ] + }, + { + "appId": "4765445b-32c6-49b0-83e6-1d93765276ca", + "permissionIds": [ + "${{AAD_APP_ACCESS_AS_USER_PERMISSION_ID}}" + ] + }, + { + "appId": "4345a7b9-9a63-4910-a426-35363201d503", + "permissionIds": [ + "${{AAD_APP_ACCESS_AS_USER_PERMISSION_ID}}" + ] + }, + { + "appId": "27922004-5251-4030-b22d-91ecd9a37ea4", + "permissionIds": [ + "${{AAD_APP_ACCESS_AS_USER_PERMISSION_ID}}" + ] + } + ], + "identifierUris":[ + "api://botid-${{BOT_ID}}" + ], + "replyUrlsWithType":[ + { + "url": "https://${{BOT_DOMAIN}}/auth-end.html", + "type": "Web" + } + ] +} diff --git a/templates/csharp/custom-copilot-rag-microsoft365/appPackage/color.png b/templates/csharp/custom-copilot-rag-microsoft365/appPackage/color.png new file mode 100644 index 0000000000..01aa37e347 Binary files /dev/null and b/templates/csharp/custom-copilot-rag-microsoft365/appPackage/color.png differ diff --git a/templates/csharp/custom-copilot-rag-microsoft365/appPackage/manifest.json.tpl b/templates/csharp/custom-copilot-rag-microsoft365/appPackage/manifest.json.tpl new file mode 100644 index 0000000000..4035db1526 --- /dev/null +++ b/templates/csharp/custom-copilot-rag-microsoft365/appPackage/manifest.json.tpl @@ -0,0 +1,52 @@ +{ + "$schema": "https://developer.microsoft.com/en-us/json-schemas/teams/v1.17/MicrosoftTeams.schema.json", + "manifestVersion": "1.17", + "version": "1.0.0", + "id": "${{TEAMS_APP_ID}}", + "developer": { + "name": "Teams App, Inc.", + "websiteUrl": "https://www.example.com", + "privacyUrl": "https://www.example.com/privacy", + "termsOfUseUrl": "https://www.example.com/termofuse" + }, + "icons": { + "color": "color.png", + "outline": "outline.png" + }, + "name": { + "short": "{{appName}}${{APP_NAME_SUFFIX}}", + "full": "full name for {{appName}}" + }, + "description": { + "short": "Short description of {{appName}}", + "full": "Full description of {{appName}}" + }, + "accentColor": "#FFFFFF", + "bots": [ + { + "botId": "${{BOT_ID}}", + "scopes": [ + "personal", + "team", + "groupChat" + ], + "supportsFiles": false, + "isNotificationOnly": false + } + ], + "composeExtensions": [ + ], + "configurableTabs": [], + "staticTabs": [], + "permissions": [ + "identity", + "messageTeamMembers" + ], + "validDomains": [ + "${{BOT_DOMAIN}}" + ], + "webApplicationInfo": { + "id": "${{AAD_APP_CLIENT_ID}}", + "resource": "api://botid-${{BOT_ID}}" + } +} \ No newline at end of file diff --git a/templates/csharp/custom-copilot-rag-microsoft365/appPackage/outline.png b/templates/csharp/custom-copilot-rag-microsoft365/appPackage/outline.png new file mode 100644 index 0000000000..f7a4c86447 Binary files /dev/null and b/templates/csharp/custom-copilot-rag-microsoft365/appPackage/outline.png differ diff --git a/templates/csharp/custom-copilot-rag-microsoft365/appsettings.Development.json.tpl b/templates/csharp/custom-copilot-rag-microsoft365/appsettings.Development.json.tpl new file mode 100644 index 0000000000..c86385c7e1 --- /dev/null +++ b/templates/csharp/custom-copilot-rag-microsoft365/appsettings.Development.json.tpl @@ -0,0 +1,31 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft": "Information", + "Microsoft.Hosting.Lifetime": "Information", + "Microsoft.Teams.AI": "Trace" + } + }, + "AllowedHosts": "*", + "BOT_ID": "", + "BOT_PASSWORD": "", + "BOT_TYPE": "", + "BOT_DOMAIN": "", + "AAD_APP_CLIENT_ID": "", + "AAD_APP_CLIENT_SECRET": "", + "AAD_APP_TENANT_ID": "", + "AAD_APP_OAUTH_AUTHORITY_HOST": "", +{{#useOpenAI}} + "OpenAI": { + "ApiKey": "" + } +{{/useOpenAI}} +{{#useAzureOpenAI}} + "Azure": { + "OpenAIApiKey": "", + "OpenAIEndpoint": "", + "OpenAIDeploymentName": "" + } +{{/useAzureOpenAI}} +} \ No newline at end of file diff --git a/templates/csharp/custom-copilot-rag-microsoft365/appsettings.json.tpl b/templates/csharp/custom-copilot-rag-microsoft365/appsettings.json.tpl new file mode 100644 index 0000000000..615523a351 --- /dev/null +++ b/templates/csharp/custom-copilot-rag-microsoft365/appsettings.json.tpl @@ -0,0 +1,26 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft": "Information", + "Microsoft.Hosting.Lifetime": "Information" + } + }, + "AllowedHosts": "*", + "BOT_ID": "", + "BOT_PASSWORD": "", + "BOT_TYPE": "", + "BOT_TENANT_ID": "", +{{#useOpenAI}} + "OpenAI": { + "ApiKey": "" + } +{{/useOpenAI}} +{{#useAzureOpenAI}} + "Azure": { + "OpenAIApiKey": "", + "OpenAIEndpoint": "", + "OpenAIDeploymentName": "" + } +{{/useAzureOpenAI}} +} \ No newline at end of file diff --git a/templates/csharp/custom-copilot-rag-microsoft365/data/Contoso Electronics_PerkPlus_Program.md b/templates/csharp/custom-copilot-rag-microsoft365/data/Contoso Electronics_PerkPlus_Program.md new file mode 100644 index 0000000000..1d97d5117e --- /dev/null +++ b/templates/csharp/custom-copilot-rag-microsoft365/data/Contoso Electronics_PerkPlus_Program.md @@ -0,0 +1,36 @@ +# Contoso Electronics PerksPlus Program + +*Disclaimer: This document contains information generated using a language model (Azure OpenAI). The information contained in this document is only for demonstration purposes and does not reflect the opinions or beliefs of Microsoft. Microsoft makes no representations or warranties of any kind, express or implied, about the completeness, accuracy, reliability, suitability or availability with respect to the information contained in this document. All rights reserved to Microsoft.* + +## Overview +Introducing PerksPlus - the ultimate benefits program designed to support the health and wellness of employees. With PerksPlus, employees have the opportunity to expense up to $1000 for fitness-related programs, making it easier and more affordable to maintain a healthy lifestyle. PerksPlus is not only designed to support employees' physical health, but also their mental health. Regular exercise has been shown to reduce stress, improve mood, and enhance overall well-being. With PerksPlus, employees can invest in their health and wellness, while enjoying the peace of mind that comes with knowing they are getting the support they need to lead a healthy life. +What is Covered? + +PerksPlus covers a wide range of fitness activities, including but not limited to: +* Gym memberships +* Personal training sessions +* Yoga and Pilates classes +* Fitness equipment purchases +* Sports team fees +* Health retreats and spas +* Outdoor adventure activities (such as rock climbing, hiking, and kayaking) +* Group fitness classes (such as dance, martial arts, and cycling) +* Virtual fitness programs (such as online yoga and workout classes) + +In addition to the wide range of fitness activities covered by PerksPlus, the program also covers a variety of lessons and experiences that promote health and wellness. Some of the lessons covered under PerksPlus include: +* Skiing and snowboarding lessons +* Scuba diving lessons +* Surfing lessons +* Horseback riding lessons + +These lessons provide employees with the opportunity to try new things, challenge themselves, and improve their physical skills. They are also a great way to relieve stress and have fun while staying active. + +With PerksPlus, employees can choose from a variety of fitness programs to suit their individual needs and preferences. Whether you're looking to improve your physical fitness, reduce stress, or just have some fun, PerksPlus has you covered. + +## What is Not Covered? +In addition to the wide range of activities covered by PerksPlus, there is also a list of things that are not +covered under the program. These include but are not limited to: +* Non-fitness related expenses +* Medical treatments and procedures +* Travel expenses (unless related to a fitness program) +* Food and supplements \ No newline at end of file diff --git a/templates/csharp/custom-copilot-rag-microsoft365/data/Contoso_Electronics_Company_Overview.md b/templates/csharp/custom-copilot-rag-microsoft365/data/Contoso_Electronics_Company_Overview.md new file mode 100644 index 0000000000..6878a8e204 --- /dev/null +++ b/templates/csharp/custom-copilot-rag-microsoft365/data/Contoso_Electronics_Company_Overview.md @@ -0,0 +1,48 @@ +# Contoso Electronics Company Overview + +*Disclaimer: This document contains information generated using a language model (Azure OpenAI). The information contained in this document is only for demonstration purposes and does not reflect the opinions or beliefs of Microsoft. Microsoft makes no representations or warranties of any kind, express or implied, about the completeness, accuracy, reliability, suitability or availability with respect to the information contained in this document. All rights reserved to Microsoft.* + +## History + +Contoso Electronics, a pioneering force in the tech industry, was founded in 1985 by visionary entrepreneurs with a passion for innovation. Over the years, the company has played a pivotal role in shaping the landscape of consumer electronics. + +| Year | Milestone | +|------|-----------| +| 1985 | Company founded with a focus on cutting-edge technology | +| 1990 | Launched the first-ever handheld personal computer | +| 2000 | Introduced groundbreaking advancements in AI and robotics | +| 2015 | Expansion into sustainable and eco-friendly product lines | + +## Company Overview + +At Contoso Electronics, we take pride in fostering a dynamic and inclusive workplace. Our dedicated team of experts collaborates to create innovative solutions that empower and connect people globally. + +### Core Values + +- **Innovation:** Constantly pushing the boundaries of technology. +- **Diversity:** Embracing different perspectives for creative excellence. +- **Sustainability:** Committed to eco-friendly practices in our products. + +## Vacation Perks + +We believe in work-life balance and understand the importance of well-deserved breaks. Our vacation perks are designed to help our employees recharge and return with renewed enthusiasm. + +| Vacation Tier | Duration | Additional Benefits | +|---------------|----------|---------------------| +| Standard | 2 weeks | Health and wellness stipend | +| Senior | 4 weeks | Travel vouchers for a dream destination | +| Executive | 6 weeks | Luxury resort getaway with family | + +## Employee Recognition + +Recognizing the hard work and dedication of our employees is at the core of our culture. Here are some ways we celebrate achievements: + +- Monthly "Innovator of the Month" awards +- Annual gala with awards for outstanding contributions +- Team-building retreats for high-performing departments + +## Join Us! + +Contoso Electronics is always on the lookout for talented individuals who share our passion for innovation. If you're ready to be part of a dynamic team shaping the future of technology, check out our [careers page](http://www.contoso.com) for exciting opportunities. + +[Learn more about Contoso Electronics!](http://www.contoso.com) diff --git a/templates/csharp/custom-copilot-rag-microsoft365/data/Contoso_Electronics_Plan_Benefits.md b/templates/csharp/custom-copilot-rag-microsoft365/data/Contoso_Electronics_Plan_Benefits.md new file mode 100644 index 0000000000..9da5c6429d --- /dev/null +++ b/templates/csharp/custom-copilot-rag-microsoft365/data/Contoso_Electronics_Plan_Benefits.md @@ -0,0 +1,37 @@ +# Contoso Electronics Plan and Benefit Packages + +*Disclaimer: This document contains information generated using a language model (Azure OpenAI). The information contained in this document is only for demonstration purposes and does not reflect the opinions or beliefs of Microsoft. Microsoft makes no representations or warranties of any kind, express or implied, about the completeness, accuracy, reliability, suitability or availability with respect to the information contained in this document. All rights reserved to Microsoft.* + +## Northwind Health Plus + +Northwind Health Plus is a comprehensive plan that provides comprehensive coverage for medical, vision, and dental services. This plan also offers prescription drug coverage, mental health and substance abuse coverage, and coverage for preventive care services. With Northwind Health Plus, you can choose from a variety of in-network providers, including primary care physicians, specialists, hospitals, and pharmacies. + +This plan also offers coverage for emergency services, both in-network and out-of-network. + +## Northwind Standard + +Northwind Standard is a basic plan that provides coverage for medical, vision, and dental services. This plan also offers coverage for preventive care services, as well as prescription drug coverage. With Northwind Standard, you can choose from a variety of in-network providers, including primary care physicians, specialists, hospitals, and pharmacies. This plan does not offer coverage for emergency services, mental health and substance abuse coverage, or out-of-network services. + +## Comparison of Plans + +Both plans offer coverage for routine physicals, well-child visits, immunizations, and other preventive care services. The plans also cover preventive care services such as mammograms, colonoscopies, and other cancer screenings. + +Northwind Health Plus offers more comprehensive coverage than Northwind Standard. This plan offers coverage for emergency services, both in-network and out-of-network, as well as mental health and substance abuse coverage. Northwind Standard does not offer coverage for emergency services, mental health and substance abuse coverage, or out-of-network services. + +Both plans offer coverage for prescription drugs. Northwind Health Plus offers a wider range of prescription drug coverage than Northwind Standard. Northwind Health Plus covers generic, brand-name, and specialty drugs, while Northwind Standard only covers generic and brand-name drugs. + +Both plans offer coverage for vision and dental services. Northwind Health Plus offers coverage for vision exams, glasses, and contact lenses, as well as dental exams, cleanings, and fillings. Northwind Standard only offers coverage for vision exams and glasses. + +Both plans offer coverage for medical services. Northwind Health Plus offers coverage for hospital stays, doctor visits, lab tests, and X-rays. Northwind Standard only offers coverage for doctor visits and lab tests. + +Northwind Health Plus is a comprehensive plan that offers more coverage than Northwind Standard. Northwind Health Plus offers coverage for emergency services, mental health and substance abuse coverage, and out-of-network services, while Northwind Standard does not. Northwind Health Plus also offers a wider range of prescription drug coverage than Northwind Standard. Both plans offer coverage for vision and dental services, as well as medical services. + +## Cost Comparison + +Contoso Electronics deducts the employee's portion of the healthcare cost from each paycheck. This means that the cost of the health insurance will be spread out over the course of the year, rather than being paid in one lump sum. The employee's portion of the cost will be calculated based on the selected health plan and the number of people covered by the insurance. The table below shows a cost comparison between the different health plans offered by Contoso Electronics + +| | Northwind Standard | NorthWind Health Plus | +|---------------|----------|---------------------| +| Employee Only | $45.00 | $55.00 | +| Employee +1 | $65.00 | $71.00 | +| Employee +2 or more | $78.00 | $89.00 | \ No newline at end of file diff --git a/templates/csharp/custom-copilot-rag-microsoft365/env/.env.dev b/templates/csharp/custom-copilot-rag-microsoft365/env/.env.dev new file mode 100644 index 0000000000..105b5e19d0 --- /dev/null +++ b/templates/csharp/custom-copilot-rag-microsoft365/env/.env.dev @@ -0,0 +1,22 @@ +# This file includes environment variables that will be committed to git by default. + +# Built-in environment variables +TEAMSFX_ENV=dev +APP_NAME_SUFFIX=dev + +# Updating AZURE_SUBSCRIPTION_ID or AZURE_RESOURCE_GROUP_NAME after provision may also require an update to RESOURCE_SUFFIX, because some services require a globally unique name across subscriptions/resource groups. +AZURE_SUBSCRIPTION_ID= +AZURE_RESOURCE_GROUP_NAME= +RESOURCE_SUFFIX= + +# Generated during provision, you can also add your own variables. +BOT_ID= +TEAMS_APP_ID= +BOT_AZURE_APP_SERVICE_RESOURCE_ID= +BOT_DOMAIN= +AAD_APP_CLIENT_ID= +AAD_APP_OBJECT_ID= +AAD_APP_TENANT_ID= +AAD_APP_OAUTH_AUTHORITY= +AAD_APP_OAUTH_AUTHORITY_HOST= +AAD_APP_ACCESS_AS_USER_PERMISSION_ID= \ No newline at end of file diff --git a/templates/csharp/custom-copilot-rag-microsoft365/env/.env.dev.user.tpl b/templates/csharp/custom-copilot-rag-microsoft365/env/.env.dev.user.tpl new file mode 100644 index 0000000000..8ff0c80bfc --- /dev/null +++ b/templates/csharp/custom-copilot-rag-microsoft365/env/.env.dev.user.tpl @@ -0,0 +1,12 @@ +# This file includes environment variables that will not be committed to git by default. You can set these environment variables in your CI/CD system for your project. + +# Secrets. Keys prefixed with `SECRET_` will be masked in Teams Toolkit logs. +SECRET_AAD_APP_CLIENT_SECRET= +{{#useOpenAI}} +SECRET_OPENAI_API_KEY={{{openAIKey}}} +{{/useOpenAI}} +{{#useAzureOpenAI}} +SECRET_AZURE_OPENAI_API_KEY={{{azureOpenAIKey}}} +AZURE_OPENAI_ENDPOINT={{{azureOpenAIEndpoint}}} +AZURE_OPENAI_DEPLOYMENT_NAME={{{azureOpenAIDeploymentName}}} +{{/useAzureOpenAI}} diff --git a/templates/csharp/custom-copilot-rag-microsoft365/env/.env.local.tpl b/templates/csharp/custom-copilot-rag-microsoft365/env/.env.local.tpl new file mode 100644 index 0000000000..867f7c3109 --- /dev/null +++ b/templates/csharp/custom-copilot-rag-microsoft365/env/.env.local.tpl @@ -0,0 +1,17 @@ +# This file includes environment variables that can be committed to git. It's gitignored by default because it represents your local development environment. + +# Built-in environment variables +TEAMSFX_ENV=local +APP_NAME_SUFFIX=local + +# Generated during provision, you can also add your own variables. +BOT_ID= +TEAMS_APP_ID= +BOT_DOMAIN= +BOT_ENDPOINT= +AAD_APP_CLIENT_ID= +AAD_APP_OBJECT_ID= +AAD_APP_TENANT_ID= +AAD_APP_OAUTH_AUTHORITY= +AAD_APP_OAUTH_AUTHORITY_HOST= +AAD_APP_ACCESS_AS_USER_PERMISSION_ID= \ No newline at end of file diff --git a/templates/csharp/custom-copilot-rag-microsoft365/env/.env.local.user.tpl b/templates/csharp/custom-copilot-rag-microsoft365/env/.env.local.user.tpl new file mode 100644 index 0000000000..663fc9d62c --- /dev/null +++ b/templates/csharp/custom-copilot-rag-microsoft365/env/.env.local.user.tpl @@ -0,0 +1,13 @@ +# This file includes environment variables that will not be committed to git by default. You can set these environment variables in your CI/CD system for your project. + +# Secrets. Keys prefixed with `SECRET_` will be masked in Teams Toolkit logs. +SECRET_BOT_PASSWORD= +SECRET_AAD_APP_CLIENT_SECRET= +{{#useOpenAI}} +SECRET_OPENAI_API_KEY={{{openAIKey}}} +{{/useOpenAI}} +{{#useAzureOpenAI}} +SECRET_AZURE_OPENAI_API_KEY={{{azureOpenAIKey}}} +AZURE_OPENAI_ENDPOINT={{{azureOpenAIEndpoint}}} +AZURE_OPENAI_DEPLOYMENT_NAME={{{azureOpenAIDeploymentName}}} +{{/useAzureOpenAI}} diff --git a/templates/csharp/custom-copilot-rag-microsoft365/infra/azure.bicep.tpl b/templates/csharp/custom-copilot-rag-microsoft365/infra/azure.bicep.tpl new file mode 100644 index 0000000000..f8546102fa --- /dev/null +++ b/templates/csharp/custom-copilot-rag-microsoft365/infra/azure.bicep.tpl @@ -0,0 +1,111 @@ +@maxLength(20) +@minLength(4) +@description('Used to generate names for all resources in this file') +param resourceBaseName string +{{#useOpenAI}} +@secure() +param openAIApiKey string +{{/useOpenAI}} +{{#useAzureOpenAI}} +@secure() +param azureOpenAIApiKey string + +param azureOpenAIEndpoint string +param azureOpenAIDeploymentName string +{{/useAzureOpenAI}} + +param webAppSKU string + +@maxLength(42) +param botDisplayName string + +param serverfarmsName string = resourceBaseName +param webAppName string = resourceBaseName +param identityName string = resourceBaseName +param location string = resourceGroup().location + +param aadAppClientId string +param aadAppTenantId string +param aadAppOauthAuthorityHost string +@secure() +param aadAppClientSecret string + +resource identity 'Microsoft.ManagedIdentity/userAssignedIdentities@2023-01-31' = { + location: location + name: identityName +} + +// Compute resources for your Web App +resource serverfarm 'Microsoft.Web/serverfarms@2021-02-01' = { + kind: 'app' + location: location + name: serverfarmsName + sku: { + name: webAppSKU + } +} + +// Web App that hosts your bot +resource webApp 'Microsoft.Web/sites@2021-02-01' = { + kind: 'app' + location: location + name: webAppName + properties: { + serverFarmId: serverfarm.id + httpsOnly: true + siteConfig: { + alwaysOn: true + ftpsState: 'FtpsOnly' + } + } + identity: { + type: 'UserAssigned' + userAssignedIdentities: { + '${identity.id}': {} + } + } +} + +resource webAppSettings 'Microsoft.Web/sites/config@2021-02-01' = { + name: '${webAppName}/appsettings' + properties: { + WEBSITE_NODE_DEFAULT_VERSION: '~18' + WEBSITE_RUN_FROM_PACKAGE: '1' + BOT_ID: identity.properties.clientId + BOT_TENANT_ID: identity.properties.tenantId + BOT_TYPE: 'UserAssignedMsi' + BOT_DOMAIN: webApp.properties.defaultHostName + AAD_APP_CLIENT_ID: aadAppClientId + AAD_APP_CLIENT_SECRET: aadAppClientSecret + AAD_APP_TENANT_ID: aadAppTenantId + AAD_APP_OAUTH_AUTHORITY_HOST: aadAppOauthAuthorityHost + RUNNING_ON_AZURE: '1' +{{#useAzureOpenAI}} + Azure__OpenAIApiKey: azureOpenAIApiKey + Azure__OpenAIEndpoint: azureOpenAIEndpoint + Azure__OpenAIDeploymentName: azureOpenAIDeploymentName +{{/useAzureOpenAI}} +{{#useOpenAI}} + OpenAI__ApiKey: openAIApiKey +{{/useOpenAI}} + } +} + +// Register your web service as a bot with the Bot Framework +module azureBotRegistration './botRegistration/azurebot.bicep' = { + name: 'Azure-Bot-registration' + params: { + resourceBaseName: resourceBaseName + identityClientId: identity.properties.clientId + identityResourceId: identity.id + identityTenantId: identity.properties.tenantId + botAppDomain: webApp.properties.defaultHostName + botDisplayName: botDisplayName + } +} + +// The output will be persisted in .env.{envName}. Visit https://aka.ms/teamsfx-actions/arm-deploy for more details. +output BOT_AZURE_APP_SERVICE_RESOURCE_ID string = webApp.id +output BOT_DOMAIN string = webApp.properties.defaultHostName +output BOT_ID string = identity.properties.clientId +output BOT_TENANT_ID string = identity.properties.tenantId diff --git a/templates/csharp/custom-copilot-rag-microsoft365/infra/azure.parameters.json.tpl b/templates/csharp/custom-copilot-rag-microsoft365/infra/azure.parameters.json.tpl new file mode 100644 index 0000000000..7e72b6c858 --- /dev/null +++ b/templates/csharp/custom-copilot-rag-microsoft365/infra/azure.parameters.json.tpl @@ -0,0 +1,43 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "resourceBaseName": { + "value": "bot${{RESOURCE_SUFFIX}}" + }, +{{#useOpenAI}} + "openAIApiKey": { + "value": "${{SECRET_OPENAI_API_KEY}}" + }, +{{/useOpenAI}} +{{#useAzureOpenAI}} + "azureOpenAIApiKey": { + "value": "${{SECRET_AZURE_OPENAI_API_KEY}}" + }, + "azureOpenAIEndpoint": { + "value": "${{AZURE_OPENAI_ENDPOINT}}" + }, + "azureOpenAIDeploymentName": { + "value": "${{AZURE_OPENAI_DEPLOYMENT_NAME}}" + }, +{{/useAzureOpenAI}} + "webAppSKU": { + "value": "B1" + }, + "botDisplayName": { + "value": "{{appName}}" + }, + "aadAppClientId": { + "value": "${{AAD_APP_CLIENT_ID}}" + }, + "aadAppClientSecret": { + "value": "${{SECRET_AAD_APP_CLIENT_SECRET}}" + }, + "aadAppTenantId": { + "value": "${{AAD_APP_TENANT_ID}}" + }, + "aadAppOauthAuthorityHost": { + "value": "${{AAD_APP_OAUTH_AUTHORITY_HOST}}" + } + } + } \ No newline at end of file diff --git a/templates/csharp/custom-copilot-rag-microsoft365/infra/botRegistration/azurebot.bicep b/templates/csharp/custom-copilot-rag-microsoft365/infra/botRegistration/azurebot.bicep new file mode 100644 index 0000000000..a5a27b8fe4 --- /dev/null +++ b/templates/csharp/custom-copilot-rag-microsoft365/infra/botRegistration/azurebot.bicep @@ -0,0 +1,42 @@ +@maxLength(20) +@minLength(4) +@description('Used to generate names for all resources in this file') +param resourceBaseName string + +@maxLength(42) +param botDisplayName string + +param botServiceName string = resourceBaseName +param botServiceSku string = 'F0' +param identityResourceId string +param identityClientId string +param identityTenantId string +param botAppDomain string + +// Register your web service as a bot with the Bot Framework +resource botService 'Microsoft.BotService/botServices@2021-03-01' = { + kind: 'azurebot' + location: 'global' + name: botServiceName + properties: { + displayName: botDisplayName + endpoint: 'https://${botAppDomain}/api/messages' + msaAppId: identityClientId + msaAppMSIResourceId: identityResourceId + msaAppTenantId:identityTenantId + msaAppType:'UserAssignedMSI' + } + sku: { + name: botServiceSku + } +} + +// Connect the bot service to Microsoft Teams +resource botServiceMsTeamsChannel 'Microsoft.BotService/botServices/channels@2021-03-01' = { + parent: botService + location: 'global' + name: 'MsTeamsChannel' + properties: { + channelName: 'MsTeamsChannel' + } +} diff --git a/templates/csharp/custom-copilot-rag-microsoft365/infra/botRegistration/readme.md b/templates/csharp/custom-copilot-rag-microsoft365/infra/botRegistration/readme.md new file mode 100644 index 0000000000..d5416243cd --- /dev/null +++ b/templates/csharp/custom-copilot-rag-microsoft365/infra/botRegistration/readme.md @@ -0,0 +1 @@ +The `azurebot.bicep` module is provided to help you create Azure Bot service when you don't use Azure to host your app. If you use Azure as infrastrcture for your app, `azure.bicep` under infra folder already leverages this module to create Azure Bot service for you. You don't need to deploy `azurebot.bicep` again. \ No newline at end of file diff --git a/templates/csharp/custom-copilot-rag-microsoft365/teamsapp.local.yml.tpl b/templates/csharp/custom-copilot-rag-microsoft365/teamsapp.local.yml.tpl new file mode 100644 index 0000000000..84d7222569 --- /dev/null +++ b/templates/csharp/custom-copilot-rag-microsoft365/teamsapp.local.yml.tpl @@ -0,0 +1,136 @@ +# yaml-language-server: $schema=https://aka.ms/teams-toolkit/v1.7/yaml.schema.json +# Visit https://aka.ms/teamsfx-v5.0-guide for details on this file +# Visit https://aka.ms/teamsfx-actions for details on actions +version: v1.7 + +provision: + - uses: aadApp/create # Creates a new Azure Active Directory (AAD) app to authenticate users if the environment variable that stores clientId is empty + with: + name: {{appName}}-aad # Note: when you run aadApp/update, the AAD app name will be updated based on the definition in manifest. If you don't want to change the name, make sure the name in AAD manifest is the same with the name defined here. + generateClientSecret: true # If the value is false, the action will not generate client secret for you + signInAudience: "AzureADMyOrg" # Authenticate users with a Microsoft work or school account in your organization's Azure AD tenant (for example, single tenant). + writeToEnvironmentFile: # Write the information of created resources into environment file for the specified environment variable(s). + clientId: AAD_APP_CLIENT_ID + clientSecret: SECRET_AAD_APP_CLIENT_SECRET # Environment variable that starts with `SECRET_` will be stored to the .env.{envName}.user environment file + objectId: AAD_APP_OBJECT_ID + tenantId: AAD_APP_TENANT_ID + authority: AAD_APP_OAUTH_AUTHORITY + authorityHost: AAD_APP_OAUTH_AUTHORITY_HOST + + # Creates a Teams app + - uses: teamsApp/create + with: + # Teams app name + name: {{appName}}${{APP_NAME_SUFFIX}} + # Write the information of created resources into environment file for + # the specified environment variable(s). + writeToEnvironmentFile: + teamsAppId: TEAMS_APP_ID + + # Create or reuse an existing Microsoft Entra application for bot. + - uses: aadApp/create + with: + # The Microsoft Entra application's display name + name: {{appName}}${{APP_NAME_SUFFIX}} + generateClientSecret: true + signInAudience: AzureADMultipleOrgs + writeToEnvironmentFile: + # The Microsoft Entra application's client id created for bot. + clientId: BOT_ID + # The Microsoft Entra application's client secret created for bot. + clientSecret: SECRET_BOT_PASSWORD + # The Microsoft Entra application's object id created for bot. + objectId: BOT_OBJECT_ID + + # Generate runtime appsettings to JSON file + - uses: file/createOrUpdateJsonFile + with: +{{#isNewProjectTypeEnabled}} +{{#PlaceProjectFileInSolutionDir}} + target: ../appsettings.Development.json +{{/PlaceProjectFileInSolutionDir}} +{{^PlaceProjectFileInSolutionDir}} + target: ../{{appName}}/appsettings.Development.json +{{/PlaceProjectFileInSolutionDir}} +{{/isNewProjectTypeEnabled}} +{{^isNewProjectTypeEnabled}} + target: ./appsettings.Development.json +{{/isNewProjectTypeEnabled}} + content: + BOT_TYPE: 'MultiTenant' + BOT_ID: ${{BOT_ID}} + BOT_PASSWORD: ${{SECRET_BOT_PASSWORD}} + BOT_DOMAIN: ${{BOT_DOMAIN}} + AAD_APP_CLIENT_ID: ${{AAD_APP_CLIENT_ID}} + AAD_APP_CLIENT_SECRET: ${{SECRET_AAD_APP_CLIENT_SECRET}} + AAD_APP_TENANT_ID: ${{AAD_APP_TENANT_ID}} + AAD_APP_OAUTH_AUTHORITY_HOST: ${{AAD_APP_OAUTH_AUTHORITY_HOST}} +{{#useOpenAI}} + OpenAI: + ApiKey: ${{SECRET_OPENAI_API_KEY}} +{{/useOpenAI}} +{{#useAzureOpenAI}} + Azure: + OpenAIApiKey: ${{SECRET_AZURE_OPENAI_API_KEY}} + OpenAIEndpoint: ${{AZURE_OPENAI_ENDPOINT}} + OpenAIDeploymentName: ${{AZURE_OPENAI_DEPLOYMENT_NAME}} +{{/useAzureOpenAI}} + + # Create or update the bot registration on dev.botframework.com + - uses: botFramework/create + with: + botId: ${{BOT_ID}} + name: {{appName}} + messagingEndpoint: ${{BOT_ENDPOINT}}/api/messages + description: "" + channels: + - name: msteams + + - uses: aadApp/update # Apply the AAD manifest to an existing AAD app. Will use the object id in manifest file to determine which AAD app to update. + with: + manifestPath: ./aad.manifest.json # Relative path to teamsfx folder. Environment variables in manifest will be replaced before apply to AAD app + outputFilePath: ./build/aad.manifest.${{TEAMSFX_ENV}}.json + + # Validate using manifest schema + - uses: teamsApp/validateManifest + with: + # Path to manifest template + manifestPath: ./appPackage/manifest.json + # Build Teams app package with latest env value + - uses: teamsApp/zipAppPackage + with: + # Path to manifest template + manifestPath: ./appPackage/manifest.json + outputZipPath: ./appPackage/build/appPackage.${{TEAMSFX_ENV}}.zip + outputFolder: ./appPackage/build + # Validate app package using validation rules + - uses: teamsApp/validateAppPackage + with: + # Relative path to this file. This is the path for built zip file. + appPackagePath: ./appPackage/build/appPackage.${{TEAMSFX_ENV}}.zip + + # Apply the Teams app manifest to an existing Teams app in + # Teams Developer Portal. + # Will use the app id in manifest file to determine which Teams app to update. + - uses: teamsApp/update + with: + # Relative path to this file. This is the path for built zip file. + appPackagePath: ./appPackage/build/appPackage.${{TEAMSFX_ENV}}.zip +{{^isNewProjectTypeEnabled}} + + # Create or update debug profile in lauchsettings file + - uses: file/createOrUpdateJsonFile + with: + target: ./Properties/launchSettings.json + content: + profiles: + Microsoft Teams (browser): + commandName: "Project" + dotnetRunMessages: true + launchBrowser: true + launchUrl: "https://teams.microsoft.com/l/app/${{TEAMS_APP_ID}}?installAppPackage=true&webjoin=true&appTenantId=${{TEAMS_APP_TENANT_ID}}&login_hint=${{TEAMSFX_M365_USER_NAME}}" + applicationUrl: "http://localhost:5130" + environmentVariables: + ASPNETCORE_ENVIRONMENT: "Development" + hotReloadProfile: "aspnetcore" +{{/isNewProjectTypeEnabled}} diff --git a/templates/csharp/custom-copilot-rag-microsoft365/teamsapp.yml.tpl b/templates/csharp/custom-copilot-rag-microsoft365/teamsapp.yml.tpl new file mode 100644 index 0000000000..41895e30c5 --- /dev/null +++ b/templates/csharp/custom-copilot-rag-microsoft365/teamsapp.yml.tpl @@ -0,0 +1,119 @@ +# yaml-language-server: $schema=https://aka.ms/teams-toolkit/v1.7/yaml.schema.json +# Visit https://aka.ms/teamsfx-v5.0-guide for details on this file +# Visit https://aka.ms/teamsfx-actions for details on actions +version: v1.7 + +environmentFolderPath: ./env + +# Triggered when 'teamsapp provision' is executed +provision: + - uses: aadApp/create # Creates a new Azure Active Directory (AAD) app to authenticate users if the environment variable that stores clientId is empty + with: + name: {{appName}}-aad # Note: when you run aadApp/update, the AAD app name will be updated based on the definition in manifest. If you don't want to change the name, make sure the name in AAD manifest is the same with the name defined here. + generateClientSecret: true # If the value is false, the action will not generate client secret for you + signInAudience: "AzureADMyOrg" # Authenticate users with a Microsoft work or school account in your organization's Azure AD tenant (for example, single tenant). + writeToEnvironmentFile: # Write the information of created resources into environment file for the specified environment variable(s). + clientId: AAD_APP_CLIENT_ID + clientSecret: SECRET_AAD_APP_CLIENT_SECRET # Environment variable that starts with `SECRET_` will be stored to the .env.{envName}.user environment file + objectId: AAD_APP_OBJECT_ID + tenantId: AAD_APP_TENANT_ID + authority: AAD_APP_OAUTH_AUTHORITY + authorityHost: AAD_APP_OAUTH_AUTHORITY_HOST + + # Creates a Teams app + - uses: teamsApp/create + with: + # Teams app name + name: {{appName}}${{APP_NAME_SUFFIX}} + # Write the information of created resources into environment file for + # the specified environment variable(s). + writeToEnvironmentFile: + teamsAppId: TEAMS_APP_ID + + - uses: arm/deploy # Deploy given ARM templates parallelly. + with: + # AZURE_SUBSCRIPTION_ID is a built-in environment variable, + # if its value is empty, TeamsFx will prompt you to select a subscription. + # Referencing other environment variables with empty values + # will skip the subscription selection prompt. + subscriptionId: ${{AZURE_SUBSCRIPTION_ID}} + # AZURE_RESOURCE_GROUP_NAME is a built-in environment variable, + # if its value is empty, TeamsFx will prompt you to select or create one + # resource group. + # Referencing other environment variables with empty values + # will skip the resource group selection prompt. + resourceGroupName: ${{AZURE_RESOURCE_GROUP_NAME}} + templates: + - path: ./infra/azure.bicep # Relative path to this file + # Relative path to this yaml file. + # Placeholders will be replaced with corresponding environment + # variable before ARM deployment. + parameters: ./infra/azure.parameters.json + # Required when deploying ARM template + deploymentName: Create-resources-for-bot + # Teams Toolkit will download this bicep CLI version from github for you, + # will use bicep CLI in PATH if you remove this config. + bicepCliVersion: v0.9.1 + + - uses: aadApp/update # Apply the AAD manifest to an existing AAD app. Will use the object id in manifest file to determine which AAD app to update. + with: + manifestPath: ./aad.manifest.json # Relative path to teamsfx folder. Environment variables in manifest will be replaced before apply to AAD app + outputFilePath: ./build/aad.manifest.${{TEAMSFX_ENV}}.json + + # Validate using manifest schema + - uses: teamsApp/validateManifest + with: + # Path to manifest template + manifestPath: ./appPackage/manifest.json + # Build Teams app package with latest env value + - uses: teamsApp/zipAppPackage + with: + # Path to manifest template + manifestPath: ./appPackage/manifest.json + outputZipPath: ./appPackage/build/appPackage.${{TEAMSFX_ENV}}.zip + outputFolder: ./appPackage/build + # Validate app package using validation rules + - uses: teamsApp/validateAppPackage + with: + # Relative path to this file. This is the path for built zip file. + appPackagePath: ./appPackage/build/appPackage.${{TEAMSFX_ENV}}.zip + # Apply the Teams app manifest to an existing Teams app in + # Teams Developer Portal. + # Will use the app id in manifest file to determine which Teams app to update. + - uses: teamsApp/update + with: + # Relative path to this file. This is the path for built zip file. + appPackagePath: ./appPackage/build/appPackage.${{TEAMSFX_ENV}}.zip + +# Triggered when 'teamsapp deploy' is executed +deploy: + - uses: cli/runDotnetCommand + with: + args: publish --configuration Release {{ProjectName}}.csproj +{{#isNewProjectTypeEnabled}} +{{#PlaceProjectFileInSolutionDir}} + workingDirectory: .. +{{/PlaceProjectFileInSolutionDir}} +{{^PlaceProjectFileInSolutionDir}} + workingDirectory: ../{{ProjectName}} +{{/PlaceProjectFileInSolutionDir}} +{{/isNewProjectTypeEnabled}} + # Deploy your application to Azure App Service using the zip deploy feature. + # For additional details, refer to https://aka.ms/zip-deploy-to-app-services. + - uses: azureAppService/zipDeploy + with: + # Deploy base folder + artifactFolder: bin/Release/{{TargetFramework}}/publish + # The resource id of the cloud resource to be deployed to. + # This key will be generated by arm/deploy action automatically. + # You can replace it with your existing Azure Resource id + # or add it to your environment variable file. + resourceId: ${{BOT_AZURE_APP_SERVICE_RESOURCE_ID}} +{{#isNewProjectTypeEnabled}} +{{#PlaceProjectFileInSolutionDir}} + workingDirectory: .. +{{/PlaceProjectFileInSolutionDir}} +{{^PlaceProjectFileInSolutionDir}} + workingDirectory: ../{{ProjectName}} +{{/PlaceProjectFileInSolutionDir}} +{{/isNewProjectTypeEnabled}} diff --git a/templates/csharp/custom-copilot-rag-microsoft365/wwwroot/auth-end.html.tpl b/templates/csharp/custom-copilot-rag-microsoft365/wwwroot/auth-end.html.tpl new file mode 100644 index 0000000000..fd20b9cc3e --- /dev/null +++ b/templates/csharp/custom-copilot-rag-microsoft365/wwwroot/auth-end.html.tpl @@ -0,0 +1,63 @@ + + + Login End Page + + + + + +
+ + + \ No newline at end of file diff --git a/templates/csharp/custom-copilot-rag-microsoft365/wwwroot/auth-start.html.tpl b/templates/csharp/custom-copilot-rag-microsoft365/wwwroot/auth-start.html.tpl new file mode 100644 index 0000000000..a932734d6f --- /dev/null +++ b/templates/csharp/custom-copilot-rag-microsoft365/wwwroot/auth-start.html.tpl @@ -0,0 +1,177 @@ + + + + + Login Start Page + + + + + + + \ No newline at end of file diff --git a/templates/csharp/custom-copilot-rag-microsoft365/{{ProjectName}}.csproj.tpl b/templates/csharp/custom-copilot-rag-microsoft365/{{ProjectName}}.csproj.tpl new file mode 100644 index 0000000000..bb37126e64 --- /dev/null +++ b/templates/csharp/custom-copilot-rag-microsoft365/{{ProjectName}}.csproj.tpl @@ -0,0 +1,46 @@ + + + + {{TargetFramework}} + enable + + +{{^isNewProjectTypeEnabled}} + + + + + + + + + + + + +{{/isNewProjectTypeEnabled}} + + + + + + + + + + + + PreserveNewest + PreserveNewest + + + + + + + + PreserveNewest + None + + + diff --git a/templates/csharp/non-sso-tab-ssr/{{ProjectName}}.csproj.tpl b/templates/csharp/non-sso-tab-ssr/{{ProjectName}}.csproj.tpl index 617a7cc0fb..aa714eb901 100644 --- a/templates/csharp/non-sso-tab-ssr/{{ProjectName}}.csproj.tpl +++ b/templates/csharp/non-sso-tab-ssr/{{ProjectName}}.csproj.tpl @@ -20,7 +20,7 @@ - +
diff --git a/templates/csharp/non-sso-tab/{{ProjectName}}.csproj.tpl b/templates/csharp/non-sso-tab/{{ProjectName}}.csproj.tpl index 617a7cc0fb..aa714eb901 100644 --- a/templates/csharp/non-sso-tab/{{ProjectName}}.csproj.tpl +++ b/templates/csharp/non-sso-tab/{{ProjectName}}.csproj.tpl @@ -20,7 +20,7 @@ - +
diff --git a/templates/csharp/notification-http-timer-trigger-isolated/{{ProjectName}}.csproj.tpl b/templates/csharp/notification-http-timer-trigger-isolated/{{ProjectName}}.csproj.tpl index 0c360f760c..7d430f840c 100644 --- a/templates/csharp/notification-http-timer-trigger-isolated/{{ProjectName}}.csproj.tpl +++ b/templates/csharp/notification-http-timer-trigger-isolated/{{ProjectName}}.csproj.tpl @@ -42,6 +42,7 @@ contentFiles
+ diff --git a/templates/csharp/notification-http-timer-trigger/{{ProjectName}}.csproj.tpl b/templates/csharp/notification-http-timer-trigger/{{ProjectName}}.csproj.tpl index e8dea73184..064f882b97 100644 --- a/templates/csharp/notification-http-timer-trigger/{{ProjectName}}.csproj.tpl +++ b/templates/csharp/notification-http-timer-trigger/{{ProjectName}}.csproj.tpl @@ -37,6 +37,7 @@ contentFiles + diff --git a/templates/csharp/notification-http-trigger-isolated/{{ProjectName}}.csproj.tpl b/templates/csharp/notification-http-trigger-isolated/{{ProjectName}}.csproj.tpl index a689200b28..c200bec8e1 100644 --- a/templates/csharp/notification-http-trigger-isolated/{{ProjectName}}.csproj.tpl +++ b/templates/csharp/notification-http-trigger-isolated/{{ProjectName}}.csproj.tpl @@ -41,6 +41,7 @@ contentFiles + diff --git a/templates/csharp/notification-http-trigger/{{ProjectName}}.csproj.tpl b/templates/csharp/notification-http-trigger/{{ProjectName}}.csproj.tpl index e8dea73184..064f882b97 100644 --- a/templates/csharp/notification-http-trigger/{{ProjectName}}.csproj.tpl +++ b/templates/csharp/notification-http-trigger/{{ProjectName}}.csproj.tpl @@ -37,6 +37,7 @@ contentFiles + diff --git a/templates/csharp/notification-timer-trigger-isolated/{{ProjectName}}.csproj.tpl b/templates/csharp/notification-timer-trigger-isolated/{{ProjectName}}.csproj.tpl index 0c360f760c..7d430f840c 100644 --- a/templates/csharp/notification-timer-trigger-isolated/{{ProjectName}}.csproj.tpl +++ b/templates/csharp/notification-timer-trigger-isolated/{{ProjectName}}.csproj.tpl @@ -42,6 +42,7 @@ contentFiles + diff --git a/templates/csharp/notification-timer-trigger/{{ProjectName}}.csproj.tpl b/templates/csharp/notification-timer-trigger/{{ProjectName}}.csproj.tpl index e8dea73184..064f882b97 100644 --- a/templates/csharp/notification-timer-trigger/{{ProjectName}}.csproj.tpl +++ b/templates/csharp/notification-timer-trigger/{{ProjectName}}.csproj.tpl @@ -37,6 +37,7 @@ contentFiles + diff --git a/templates/csharp/notification-webapi/{{ProjectName}}.csproj.tpl b/templates/csharp/notification-webapi/{{ProjectName}}.csproj.tpl index e3c6c726ad..20678fe067 100644 --- a/templates/csharp/notification-webapi/{{ProjectName}}.csproj.tpl +++ b/templates/csharp/notification-webapi/{{ProjectName}}.csproj.tpl @@ -32,6 +32,7 @@ contentFiles + diff --git a/templates/csharp/sso-tab-ssr/{{ProjectName}}.csproj.tpl b/templates/csharp/sso-tab-ssr/{{ProjectName}}.csproj.tpl index 64d735320b..d108f1a7e0 100644 --- a/templates/csharp/sso-tab-ssr/{{ProjectName}}.csproj.tpl +++ b/templates/csharp/sso-tab-ssr/{{ProjectName}}.csproj.tpl @@ -22,7 +22,7 @@ - + diff --git a/templates/csharp/sso-tab/{{ProjectName}}.csproj.tpl b/templates/csharp/sso-tab/{{ProjectName}}.csproj.tpl index 64d735320b..d108f1a7e0 100644 --- a/templates/csharp/sso-tab/{{ProjectName}}.csproj.tpl +++ b/templates/csharp/sso-tab/{{ProjectName}}.csproj.tpl @@ -22,7 +22,7 @@ - + diff --git a/templates/csharp/workflow/{{ProjectName}}.csproj.tpl b/templates/csharp/workflow/{{ProjectName}}.csproj.tpl index d118067076..cd6af35da8 100644 --- a/templates/csharp/workflow/{{ProjectName}}.csproj.tpl +++ b/templates/csharp/workflow/{{ProjectName}}.csproj.tpl @@ -27,6 +27,7 @@ contentFiles + diff --git a/templates/js/api-message-extension-sso/appPackage/apiSpecificationFile/repair.yml b/templates/js/api-message-extension-sso/appPackage/apiSpecificationFile/repair.yml index b19421902f..94d0ea5dd1 100644 --- a/templates/js/api-message-extension-sso/appPackage/apiSpecificationFile/repair.yml +++ b/templates/js/api-message-extension-sso/appPackage/apiSpecificationFile/repair.yml @@ -25,26 +25,30 @@ paths: content: application/json: schema: - type: array - items: - properties: - id: - type: integer - description: The unique identifier of the repair - title: - type: string - description: The short summary of the repair - description: - type: string - description: The detailed description of the repair - assignedTo: - type: string - description: The user who is responsible for the repair - date: - type: string - format: date-time - description: The date and time when the repair is scheduled or completed - image: - type: string - format: uri - description: The URL of the image of the item to be repaired or the repair process \ No newline at end of file + type: object + properties: + results: + type: array + items: + type: object + properties: + id: + type: string + description: The unique identifier of the repair + title: + type: string + description: The short summary of the repair + description: + type: string + description: The detailed description of the repair + assignedTo: + type: string + description: The user who is responsible for the repair + date: + type: string + format: date-time + description: The date and time when the repair is scheduled or completed + image: + type: string + format: uri + description: The URL of the image of the item to be repaired or the repair process \ No newline at end of file diff --git a/templates/js/api-message-extension-sso/src/functions/repair.js b/templates/js/api-message-extension-sso/src/functions/repair.js index 21ad967665..ff14c11679 100644 --- a/templates/js/api-message-extension-sso/src/functions/repair.js +++ b/templates/js/api-message-extension-sso/src/functions/repair.js @@ -23,7 +23,7 @@ async function repair(req, context) { // Get the assignedTo query parameter. const assignedTo = req.query.get("assignedTo"); - // If the assignedTo query parameter is not provided, return all repair records. + // If the assignedTo query parameter is not provided, return an empty array. if (!assignedTo) { return res; } diff --git a/templates/js/api-plugin-from-scratch-oauth/appPackage/apiSpecificationFile/repair.dev.yml.tpl b/templates/js/api-plugin-from-scratch-oauth/appPackage/apiSpecificationFile/repair.dev.yml.tpl index 6dd6d35f3c..046e5f0ca1 100644 --- a/templates/js/api-plugin-from-scratch-oauth/appPackage/apiSpecificationFile/repair.dev.yml.tpl +++ b/templates/js/api-plugin-from-scratch-oauth/appPackage/apiSpecificationFile/repair.dev.yml.tpl @@ -38,10 +38,12 @@ paths: description: Returns a list of repairs with their details and images security: {{#MicrosoftEntra}} - - aadAuthCode: [] + - aadAuthCode: + - api://${{OPENAPI_SERVER_DOMAIN}}/${{AAD_APP_CLIENT_ID}}/repairs_read {{/MicrosoftEntra}} {{^MicrosoftEntra}} - - oAuth2AuthCode: [] + - oAuth2AuthCode: + - api://${{AAD_APP_CLIENT_ID}}/repairs_read {{/MicrosoftEntra}} parameters: - name: assignedTo diff --git a/templates/js/api-plugin-from-scratch-oauth/infra/azure.bicep.tpl b/templates/js/api-plugin-from-scratch-oauth/infra/azure.bicep.tpl index 5fb5177419..b38273f91a 100644 --- a/templates/js/api-plugin-from-scratch-oauth/infra/azure.bicep.tpl +++ b/templates/js/api-plugin-from-scratch-oauth/infra/azure.bicep.tpl @@ -3,10 +3,6 @@ param resourceBaseName string param functionAppSKU string param aadAppClientId string -{{^MicrosoftEntra}} -@secure() -param aadAppClientSecret string -{{/MicrosoftEntra}} param aadAppTenantId string param aadAppOauthAuthorityHost string param location string = resourceGroup().location @@ -49,24 +45,6 @@ resource functionApp 'Microsoft.Web/sites@2021-02-01' = { name: 'WEBSITE_NODE_DEFAULT_VERSION' value: '~18' // Set NodeJS version to 18.x } - { - name: 'M365_CLIENT_ID' - value: aadAppClientId - } -{{^MicrosoftEntra}} - { - name: 'M365_CLIENT_SECRET' - value: aadAppClientSecret - } -{{/MicrosoftEntra}} - { - name: 'M365_TENANT_ID' - value: aadAppTenantId - } - { - name: 'M365_AUTHORITY_HOST' - value: aadAppOauthAuthorityHost - } ] ftpsState: 'FtpsOnly' } diff --git a/templates/js/api-plugin-from-scratch-oauth/infra/azure.parameters.json.tpl b/templates/js/api-plugin-from-scratch-oauth/infra/azure.parameters.json.tpl index 2dd7c71d3d..a6fc2603cf 100644 --- a/templates/js/api-plugin-from-scratch-oauth/infra/azure.parameters.json.tpl +++ b/templates/js/api-plugin-from-scratch-oauth/infra/azure.parameters.json.tpl @@ -11,11 +11,6 @@ "aadAppClientId": { "value": "${{AAD_APP_CLIENT_ID}}" }, -{{^MicrosoftEntra}} - "aadAppClientSecret": { - "value": "${{SECRET_AAD_APP_CLIENT_SECRET}}" - }, -{{/MicrosoftEntra}} "aadAppTenantId": { "value": "${{AAD_APP_TENANT_ID}}" }, diff --git a/templates/js/copilot-plugin-from-scratch-api-key/appPackage/apiSpecificationFile/repair.yml b/templates/js/copilot-plugin-from-scratch-api-key/appPackage/apiSpecificationFile/repair.yml index f2cc3ab0cd..e28f3f922d 100644 --- a/templates/js/copilot-plugin-from-scratch-api-key/appPackage/apiSpecificationFile/repair.yml +++ b/templates/js/copilot-plugin-from-scratch-api-key/appPackage/apiSpecificationFile/repair.yml @@ -32,26 +32,30 @@ paths: content: application/json: schema: - type: array - items: - properties: - id: - type: integer - description: The unique identifier of the repair - title: - type: string - description: The short summary of the repair - description: - type: string - description: The detailed description of the repair - assignedTo: - type: string - description: The user who is responsible for the repair - date: - type: string - format: date-time - description: The date and time when the repair is scheduled or completed - image: - type: string - format: uri - description: The URL of the image of the item to be repaired or the repair process \ No newline at end of file + type: object + properties: + results: + type: array + items: + type: object + properties: + id: + type: string + description: The unique identifier of the repair + title: + type: string + description: The short summary of the repair + description: + type: string + description: The detailed description of the repair + assignedTo: + type: string + description: The user who is responsible for the repair + date: + type: string + format: date-time + description: The date and time when the repair is scheduled or completed + image: + type: string + format: uri + description: The URL of the image of the item to be repaired or the repair process \ No newline at end of file diff --git a/templates/js/copilot-plugin-from-scratch-api-key/src/functions/repair.js b/templates/js/copilot-plugin-from-scratch-api-key/src/functions/repair.js index eaea22b407..e1ca54159a 100644 --- a/templates/js/copilot-plugin-from-scratch-api-key/src/functions/repair.js +++ b/templates/js/copilot-plugin-from-scratch-api-key/src/functions/repair.js @@ -33,7 +33,7 @@ async function repair(req, context) { // Get the assignedTo query parameter. const assignedTo = req.query.get("assignedTo"); - // If the assignedTo query parameter is not provided, return all repair records. + // If the assignedTo query parameter is not provided, return an empty array. if (!assignedTo) { return res; } diff --git a/templates/js/copilot-plugin-from-scratch/appPackage/apiSpecificationFile/repair.yml b/templates/js/copilot-plugin-from-scratch/appPackage/apiSpecificationFile/repair.yml index b19421902f..94d0ea5dd1 100644 --- a/templates/js/copilot-plugin-from-scratch/appPackage/apiSpecificationFile/repair.yml +++ b/templates/js/copilot-plugin-from-scratch/appPackage/apiSpecificationFile/repair.yml @@ -25,26 +25,30 @@ paths: content: application/json: schema: - type: array - items: - properties: - id: - type: integer - description: The unique identifier of the repair - title: - type: string - description: The short summary of the repair - description: - type: string - description: The detailed description of the repair - assignedTo: - type: string - description: The user who is responsible for the repair - date: - type: string - format: date-time - description: The date and time when the repair is scheduled or completed - image: - type: string - format: uri - description: The URL of the image of the item to be repaired or the repair process \ No newline at end of file + type: object + properties: + results: + type: array + items: + type: object + properties: + id: + type: string + description: The unique identifier of the repair + title: + type: string + description: The short summary of the repair + description: + type: string + description: The detailed description of the repair + assignedTo: + type: string + description: The user who is responsible for the repair + date: + type: string + format: date-time + description: The date and time when the repair is scheduled or completed + image: + type: string + format: uri + description: The URL of the image of the item to be repaired or the repair process \ No newline at end of file diff --git a/templates/js/copilot-plugin-from-scratch/src/functions/repair.js b/templates/js/copilot-plugin-from-scratch/src/functions/repair.js index 21ad967665..ff14c11679 100644 --- a/templates/js/copilot-plugin-from-scratch/src/functions/repair.js +++ b/templates/js/copilot-plugin-from-scratch/src/functions/repair.js @@ -23,7 +23,7 @@ async function repair(req, context) { // Get the assignedTo query parameter. const assignedTo = req.query.get("assignedTo"); - // If the assignedTo query parameter is not provided, return all repair records. + // If the assignedTo query parameter is not provided, return an empty array. if (!assignedTo) { return res; } diff --git a/templates/js/custom-copilot-assistant-assistants-api/src/app/app.js.tpl b/templates/js/custom-copilot-assistant-assistants-api/src/app/app.js.tpl index e08c4d8be4..98b486840b 100644 --- a/templates/js/custom-copilot-assistant-assistants-api/src/app/app.js.tpl +++ b/templates/js/custom-copilot-assistant-assistants-api/src/app/app.js.tpl @@ -48,15 +48,6 @@ const app = new Application({ }, }); -app.conversationUpdate("membersAdded", async (turnContext) => { - const welcomeText = "How can I help you today?"; - for (const member of turnContext.activity.membersAdded) { - if (member.id !== turnContext.activity.recipient.id) { - await turnContext.sendActivity(MessageFactory.text(welcomeText)); - } - } -}); - app.feedbackLoop(async (context, state, feedbackLoopData) => { //add custom feedback process logic here console.log("Your feedback is " + JSON.stringify(context.activity.value)); diff --git a/templates/js/custom-copilot-assistant-new/src/app/app.js.tpl b/templates/js/custom-copilot-assistant-new/src/app/app.js.tpl index 90659c1db4..bbd372771d 100644 --- a/templates/js/custom-copilot-assistant-new/src/app/app.js.tpl +++ b/templates/js/custom-copilot-assistant-new/src/app/app.js.tpl @@ -42,15 +42,6 @@ const app = new Application({ }, }); -app.conversationUpdate("membersAdded", async (turnContext) => { - const welcomeText = "How can I help you today?"; - for (const member of turnContext.activity.membersAdded) { - if (member.id !== turnContext.activity.recipient.id) { - await turnContext.sendActivity(MessageFactory.text(welcomeText)); - } - } -}); - app.feedbackLoop(async (context, state, feedbackLoopData) => { //add custom feedback process logic here console.log("Your feedback is " + JSON.stringify(context.activity.value)); diff --git a/templates/js/custom-copilot-basic/src/app/app.js.tpl b/templates/js/custom-copilot-basic/src/app/app.js.tpl index 8a0cb94c0b..3e1eb18294 100644 --- a/templates/js/custom-copilot-basic/src/app/app.js.tpl +++ b/templates/js/custom-copilot-basic/src/app/app.js.tpl @@ -39,15 +39,6 @@ const app = new Application({ }, }); -app.conversationUpdate("membersAdded", async (turnContext) => { - const welcomeText = "How can I help you today?"; - for (const member of turnContext.activity.membersAdded) { - if (member.id !== turnContext.activity.recipient.id) { - await turnContext.sendActivity(MessageFactory.text(welcomeText)); - } - } -}); - app.feedbackLoop(async (context, state, feedbackLoopData) => { //add custom feedback process logic here console.log("Your feedback is " + JSON.stringify(context.activity.value)); diff --git a/templates/js/custom-copilot-rag-azure-ai-search/src/app/app.js.tpl b/templates/js/custom-copilot-rag-azure-ai-search/src/app/app.js.tpl index ea92869ba4..8ac268ffe8 100644 --- a/templates/js/custom-copilot-rag-azure-ai-search/src/app/app.js.tpl +++ b/templates/js/custom-copilot-rag-azure-ai-search/src/app/app.js.tpl @@ -61,15 +61,6 @@ const app = new Application({ }); app.ai.action(AI.SayCommandActionName, customSayCommand.sayCommand(true)); -app.conversationUpdate("membersAdded", async (turnContext) => { - const welcomeText = "How can I help you today?"; - for (const member of turnContext.activity.membersAdded) { - if (member.id !== turnContext.activity.recipient.id) { - await turnContext.sendActivity(MessageFactory.text(welcomeText)); - } - } -}); - app.feedbackLoop(async (context, state, feedbackLoopData) => { //add custom feedback process logic here console.log("Your feedback is " + JSON.stringify(context.activity.value)); diff --git a/templates/js/custom-copilot-rag-customize/src/app/app.js.tpl b/templates/js/custom-copilot-rag-customize/src/app/app.js.tpl index b4a1bc0d7b..ebae7510b3 100644 --- a/templates/js/custom-copilot-rag-customize/src/app/app.js.tpl +++ b/templates/js/custom-copilot-rag-customize/src/app/app.js.tpl @@ -47,15 +47,6 @@ const app = new Application({ }); app.ai.action(AI.SayCommandActionName, customSayCommand.sayCommand(true)); -app.conversationUpdate("membersAdded", async (turnContext) => { - const welcomeText = "How can I help you today?"; - for (const member of turnContext.activity.membersAdded) { - if (member.id !== turnContext.activity.recipient.id) { - await turnContext.sendActivity(MessageFactory.text(welcomeText)); - } - } -}); - app.feedbackLoop(async (context, state, feedbackLoopData) => { //add custom feedback process logic here console.log("Your feedback is " + JSON.stringify(context.activity.value)); diff --git a/templates/js/custom-copilot-rag-microsoft365/src/app/app.js.tpl b/templates/js/custom-copilot-rag-microsoft365/src/app/app.js.tpl index dc7de52f24..9638833df2 100644 --- a/templates/js/custom-copilot-rag-microsoft365/src/app/app.js.tpl +++ b/templates/js/custom-copilot-rag-microsoft365/src/app/app.js.tpl @@ -62,15 +62,6 @@ const app = new Application({ }); app.ai.action(AI.SayCommandActionName, customSayCommand.sayCommand(true)); -app.conversationUpdate("membersAdded", async (turnContext) => { - const welcomeText = "How can I help you today?"; - for (const member of turnContext.activity.membersAdded) { - if (member.id !== turnContext.activity.recipient.id) { - await turnContext.sendActivity(MessageFactory.text(welcomeText)); - } - } -}); - app.authentication.get("graph").onUserSignInSuccess(async (context, state) => { // Successfully logged in await context.sendActivity("You are successfully logged in. You can send a new message to talk to the bot."); diff --git a/templates/python/custom-copilot-assistant-assistants-api/appPackage/manifest.json.tpl b/templates/python/custom-copilot-assistant-assistants-api/appPackage/manifest.json.tpl index 2fdfb8ec53..523d3bc11f 100644 --- a/templates/python/custom-copilot-assistant-assistants-api/appPackage/manifest.json.tpl +++ b/templates/python/custom-copilot-assistant-assistants-api/appPackage/manifest.json.tpl @@ -31,7 +31,24 @@ "groupChat" ], "supportsFiles": false, - "isNotificationOnly": false + "isNotificationOnly": false, + "commandLists": [ + { + "scopes": [ + "personal" + ], + "commands": [ + { + "title": "Solve the equation: 3x + 11= 14", + "description": "Help me solve the equation: 3x + 11= 14" + }, + { + "title": "The weather of San Francisco", + "description": "The weather of San Francisco" + } + ] + } + ] } ], "composeExtensions": [], diff --git a/templates/python/custom-copilot-assistant-assistants-api/src/bot.py.tpl b/templates/python/custom-copilot-assistant-assistants-api/src/bot.py.tpl index 05db709c3c..2372759869 100644 --- a/templates/python/custom-copilot-assistant-assistants-api/src/bot.py.tpl +++ b/templates/python/custom-copilot-assistant-assistants-api/src/bot.py.tpl @@ -38,10 +38,6 @@ bot_app = Application[TurnState]( ai=AIOptions(planner=planner), ) ) - -@bot_app.conversation_update("membersAdded") -async def on_members_added(context: TurnContext, state: TurnState): - await context.send_activity("How can I help you today?") @bot_app.ai.action("getCurrentWeather") async def get_current_weather(context: TurnContext, state: TurnState): diff --git a/templates/python/custom-copilot-assistant-new/appPackage/manifest.json.tpl b/templates/python/custom-copilot-assistant-new/appPackage/manifest.json.tpl index 2fdfb8ec53..ee2c11b39f 100644 --- a/templates/python/custom-copilot-assistant-new/appPackage/manifest.json.tpl +++ b/templates/python/custom-copilot-assistant-new/appPackage/manifest.json.tpl @@ -31,7 +31,24 @@ "groupChat" ], "supportsFiles": false, - "isNotificationOnly": false + "isNotificationOnly": false, + "commandLists": [ + { + "scopes": [ + "personal" + ], + "commands": [ + { + "title": "Create task:remind drink tonight", + "description": "Create a task for me to remind me drink water tonight" + }, + { + "title": "Delete all my current tasks", + "description": "Delete all my current tasks" + } + ] + } + ] } ], "composeExtensions": [], diff --git a/templates/python/custom-copilot-assistant-new/src/bot.py.tpl b/templates/python/custom-copilot-assistant-new/src/bot.py.tpl index e998a50129..8a2b7c3278 100644 --- a/templates/python/custom-copilot-assistant-new/src/bot.py.tpl +++ b/templates/python/custom-copilot-assistant-new/src/bot.py.tpl @@ -55,10 +55,6 @@ bot_app = Application[AppTurnState]( ) ) -@bot_app.conversation_update("membersAdded") -async def on_members_added(context: TurnContext, state: TurnState): - await context.send_activity("How can I help you today?") - @bot_app.turn_state_factory async def turn_state_factory(context: TurnContext): return await AppTurnState.load(context, storage) diff --git a/templates/python/custom-copilot-rag-azure-ai-search/appPackage/manifest.json.tpl b/templates/python/custom-copilot-rag-azure-ai-search/appPackage/manifest.json.tpl index 2fdfb8ec53..24691b562f 100644 --- a/templates/python/custom-copilot-rag-azure-ai-search/appPackage/manifest.json.tpl +++ b/templates/python/custom-copilot-rag-azure-ai-search/appPackage/manifest.json.tpl @@ -31,7 +31,28 @@ "groupChat" ], "supportsFiles": false, - "isNotificationOnly": false + "isNotificationOnly": false, + "commandLists": [ + { + "scopes": [ + "personal" + ], + "commands": [ + { + "title": "List Contoso history in table", + "description": "Tell me the history of Contoso Electronics, format in a table." + }, + { + "title": "Compare Contoso Electronics plan", + "description": "Compare different Contoso Electronics benefit package plans" + }, + { + "title": "Summarize PerksPlus Program", + "description": "Summarize Contoso Electronics PerksPlus Program" + } + ] + } + ] } ], "composeExtensions": [], diff --git a/templates/python/custom-copilot-rag-azure-ai-search/src/bot.py.tpl b/templates/python/custom-copilot-rag-azure-ai-search/src/bot.py.tpl index c4be18578a..10a4eacb80 100644 --- a/templates/python/custom-copilot-rag-azure-ai-search/src/bot.py.tpl +++ b/templates/python/custom-copilot-rag-azure-ai-search/src/bot.py.tpl @@ -69,10 +69,6 @@ bot_app = Application[TurnState]( ) ) -@bot_app.conversation_update("membersAdded") -async def on_members_added(context: TurnContext, state: TurnState): - await context.send_activity("How can I help you today?") - @bot_app.error async def on_error(context: TurnContext, error: Exception): # This check writes out errors to console log .vs. app insights. diff --git a/templates/python/custom-copilot-rag-custom-api/appPackage/manifest.json.tpl b/templates/python/custom-copilot-rag-custom-api/appPackage/manifest.json.tpl index 2fdfb8ec53..24691b562f 100644 --- a/templates/python/custom-copilot-rag-custom-api/appPackage/manifest.json.tpl +++ b/templates/python/custom-copilot-rag-custom-api/appPackage/manifest.json.tpl @@ -31,7 +31,28 @@ "groupChat" ], "supportsFiles": false, - "isNotificationOnly": false + "isNotificationOnly": false, + "commandLists": [ + { + "scopes": [ + "personal" + ], + "commands": [ + { + "title": "List Contoso history in table", + "description": "Tell me the history of Contoso Electronics, format in a table." + }, + { + "title": "Compare Contoso Electronics plan", + "description": "Compare different Contoso Electronics benefit package plans" + }, + { + "title": "Summarize PerksPlus Program", + "description": "Summarize Contoso Electronics PerksPlus Program" + } + ] + } + ] } ], "composeExtensions": [], diff --git a/templates/python/custom-copilot-rag-custom-api/src/bot.py.tpl b/templates/python/custom-copilot-rag-custom-api/src/bot.py.tpl index 1a4f65c002..debd475e47 100644 --- a/templates/python/custom-copilot-rag-custom-api/src/bot.py.tpl +++ b/templates/python/custom-copilot-rag-custom-api/src/bot.py.tpl @@ -62,10 +62,6 @@ bot_app = Application[TurnState]( ) ) -@bot_app.conversation_update("membersAdded") -async def on_members_added(context: TurnContext, state: TurnState): - await context.send_activity("How can I help you today?") - @bot_app.error async def on_error(context: TurnContext, error: Exception): # This check writes out errors to console log .vs. app insights. diff --git a/templates/python/custom-copilot-rag-customize/appPackage/manifest.json.tpl b/templates/python/custom-copilot-rag-customize/appPackage/manifest.json.tpl index 2fdfb8ec53..24691b562f 100644 --- a/templates/python/custom-copilot-rag-customize/appPackage/manifest.json.tpl +++ b/templates/python/custom-copilot-rag-customize/appPackage/manifest.json.tpl @@ -31,7 +31,28 @@ "groupChat" ], "supportsFiles": false, - "isNotificationOnly": false + "isNotificationOnly": false, + "commandLists": [ + { + "scopes": [ + "personal" + ], + "commands": [ + { + "title": "List Contoso history in table", + "description": "Tell me the history of Contoso Electronics, format in a table." + }, + { + "title": "Compare Contoso Electronics plan", + "description": "Compare different Contoso Electronics benefit package plans" + }, + { + "title": "Summarize PerksPlus Program", + "description": "Summarize Contoso Electronics PerksPlus Program" + } + ] + } + ] } ], "composeExtensions": [], diff --git a/templates/python/custom-copilot-rag-customize/src/bot.py.tpl b/templates/python/custom-copilot-rag-customize/src/bot.py.tpl index 4a8d18ead3..84389926da 100644 --- a/templates/python/custom-copilot-rag-customize/src/bot.py.tpl +++ b/templates/python/custom-copilot-rag-customize/src/bot.py.tpl @@ -57,10 +57,6 @@ bot_app = Application[TurnState]( ) ) -@bot_app.conversation_update("membersAdded") -async def on_members_added(context: TurnContext, state: TurnState): - await context.send_activity("How can I help you today?") - @bot_app.error async def on_error(context: TurnContext, error: Exception): # This check writes out errors to console log .vs. app insights. diff --git a/templates/ts/api-message-extension-sso/appPackage/apiSpecificationFile/repair.yml b/templates/ts/api-message-extension-sso/appPackage/apiSpecificationFile/repair.yml index f4d0ab88ca..61c0b5795f 100644 --- a/templates/ts/api-message-extension-sso/appPackage/apiSpecificationFile/repair.yml +++ b/templates/ts/api-message-extension-sso/appPackage/apiSpecificationFile/repair.yml @@ -25,26 +25,30 @@ paths: content: application/json: schema: - type: array - items: - properties: - id: - type: string - description: The unique identifier of the repair - title: - type: string - description: The short summary of the repair - description: - type: string - description: The detailed description of the repair - assignedTo: - type: string - description: The user who is responsible for the repair - date: - type: string - format: date-time - description: The date and time when the repair is scheduled or completed - image: - type: string - format: uri - description: The URL of the image of the item to be repaired or the repair process \ No newline at end of file + type: object + properties: + results: + type: array + items: + type: object + properties: + id: + type: string + description: The unique identifier of the repair + title: + type: string + description: The short summary of the repair + description: + type: string + description: The detailed description of the repair + assignedTo: + type: string + description: The user who is responsible for the repair + date: + type: string + format: date-time + description: The date and time when the repair is scheduled or completed + image: + type: string + format: uri + description: The URL of the image of the item to be repaired or the repair process \ No newline at end of file diff --git a/templates/ts/api-message-extension-sso/src/functions/repair.ts b/templates/ts/api-message-extension-sso/src/functions/repair.ts index 27fbecc0f9..a475e156c3 100644 --- a/templates/ts/api-message-extension-sso/src/functions/repair.ts +++ b/templates/ts/api-message-extension-sso/src/functions/repair.ts @@ -31,7 +31,7 @@ export async function repair( // Get the assignedTo query parameter. const assignedTo = req.query.get("assignedTo"); - // If the assignedTo query parameter is not provided, return the response. + // If the assignedTo query parameter is not provided, return an empty array. if (!assignedTo) { return res; } diff --git a/templates/ts/api-plugin-from-scratch-oauth/appPackage/apiSpecificationFile/repair.dev.yml.tpl b/templates/ts/api-plugin-from-scratch-oauth/appPackage/apiSpecificationFile/repair.dev.yml.tpl index 6dd6d35f3c..046e5f0ca1 100644 --- a/templates/ts/api-plugin-from-scratch-oauth/appPackage/apiSpecificationFile/repair.dev.yml.tpl +++ b/templates/ts/api-plugin-from-scratch-oauth/appPackage/apiSpecificationFile/repair.dev.yml.tpl @@ -38,10 +38,12 @@ paths: description: Returns a list of repairs with their details and images security: {{#MicrosoftEntra}} - - aadAuthCode: [] + - aadAuthCode: + - api://${{OPENAPI_SERVER_DOMAIN}}/${{AAD_APP_CLIENT_ID}}/repairs_read {{/MicrosoftEntra}} {{^MicrosoftEntra}} - - oAuth2AuthCode: [] + - oAuth2AuthCode: + - api://${{AAD_APP_CLIENT_ID}}/repairs_read {{/MicrosoftEntra}} parameters: - name: assignedTo diff --git a/templates/ts/api-plugin-from-scratch-oauth/infra/azure.bicep.tpl b/templates/ts/api-plugin-from-scratch-oauth/infra/azure.bicep.tpl index 5fb5177419..b38273f91a 100644 --- a/templates/ts/api-plugin-from-scratch-oauth/infra/azure.bicep.tpl +++ b/templates/ts/api-plugin-from-scratch-oauth/infra/azure.bicep.tpl @@ -3,10 +3,6 @@ param resourceBaseName string param functionAppSKU string param aadAppClientId string -{{^MicrosoftEntra}} -@secure() -param aadAppClientSecret string -{{/MicrosoftEntra}} param aadAppTenantId string param aadAppOauthAuthorityHost string param location string = resourceGroup().location @@ -49,24 +45,6 @@ resource functionApp 'Microsoft.Web/sites@2021-02-01' = { name: 'WEBSITE_NODE_DEFAULT_VERSION' value: '~18' // Set NodeJS version to 18.x } - { - name: 'M365_CLIENT_ID' - value: aadAppClientId - } -{{^MicrosoftEntra}} - { - name: 'M365_CLIENT_SECRET' - value: aadAppClientSecret - } -{{/MicrosoftEntra}} - { - name: 'M365_TENANT_ID' - value: aadAppTenantId - } - { - name: 'M365_AUTHORITY_HOST' - value: aadAppOauthAuthorityHost - } ] ftpsState: 'FtpsOnly' } diff --git a/templates/ts/api-plugin-from-scratch-oauth/infra/azure.parameters.json.tpl b/templates/ts/api-plugin-from-scratch-oauth/infra/azure.parameters.json.tpl index 2dd7c71d3d..a6fc2603cf 100644 --- a/templates/ts/api-plugin-from-scratch-oauth/infra/azure.parameters.json.tpl +++ b/templates/ts/api-plugin-from-scratch-oauth/infra/azure.parameters.json.tpl @@ -11,11 +11,6 @@ "aadAppClientId": { "value": "${{AAD_APP_CLIENT_ID}}" }, -{{^MicrosoftEntra}} - "aadAppClientSecret": { - "value": "${{SECRET_AAD_APP_CLIENT_SECRET}}" - }, -{{/MicrosoftEntra}} "aadAppTenantId": { "value": "${{AAD_APP_TENANT_ID}}" }, diff --git a/templates/ts/copilot-plugin-from-scratch-api-key/appPackage/apiSpecificationFile/repair.yml b/templates/ts/copilot-plugin-from-scratch-api-key/appPackage/apiSpecificationFile/repair.yml index 32206ea0c3..27c590b45f 100644 --- a/templates/ts/copilot-plugin-from-scratch-api-key/appPackage/apiSpecificationFile/repair.yml +++ b/templates/ts/copilot-plugin-from-scratch-api-key/appPackage/apiSpecificationFile/repair.yml @@ -32,26 +32,30 @@ paths: content: application/json: schema: - type: array - items: - properties: - id: - type: integer - description: The unique identifier of the repair - title: - type: string - description: The short summary of the repair - description: - type: string - description: The detailed description of the repair - assignedTo: - type: string - description: The user who is responsible for the repair - date: - type: string - format: date-time - description: The date and time when the repair is scheduled or completed - image: - type: string - format: uri - description: The URL of the image of the item to be repaired or the repair process \ No newline at end of file + type: object + properties: + results: + type: array + items: + type: object + properties: + id: + type: string + description: The unique identifier of the repair + title: + type: string + description: The short summary of the repair + description: + type: string + description: The detailed description of the repair + assignedTo: + type: string + description: The user who is responsible for the repair + date: + type: string + format: date-time + description: The date and time when the repair is scheduled or completed + image: + type: string + format: uri + description: The URL of the image of the item to be repaired or the repair process \ No newline at end of file diff --git a/templates/ts/copilot-plugin-from-scratch-api-key/src/functions/repair.ts b/templates/ts/copilot-plugin-from-scratch-api-key/src/functions/repair.ts index a1ccdebdbe..36d0e7607e 100644 --- a/templates/ts/copilot-plugin-from-scratch-api-key/src/functions/repair.ts +++ b/templates/ts/copilot-plugin-from-scratch-api-key/src/functions/repair.ts @@ -39,7 +39,7 @@ export async function repair( // Get the assignedTo query parameter. const assignedTo = req.query.get("assignedTo"); - // If the assignedTo query parameter is not provided, return the response. + // If the assignedTo query parameter is not provided, return an empty array. if (!assignedTo) { return res; } diff --git a/templates/ts/copilot-plugin-from-scratch/appPackage/apiSpecificationFile/repair.yml b/templates/ts/copilot-plugin-from-scratch/appPackage/apiSpecificationFile/repair.yml index f4d0ab88ca..61c0b5795f 100644 --- a/templates/ts/copilot-plugin-from-scratch/appPackage/apiSpecificationFile/repair.yml +++ b/templates/ts/copilot-plugin-from-scratch/appPackage/apiSpecificationFile/repair.yml @@ -25,26 +25,30 @@ paths: content: application/json: schema: - type: array - items: - properties: - id: - type: string - description: The unique identifier of the repair - title: - type: string - description: The short summary of the repair - description: - type: string - description: The detailed description of the repair - assignedTo: - type: string - description: The user who is responsible for the repair - date: - type: string - format: date-time - description: The date and time when the repair is scheduled or completed - image: - type: string - format: uri - description: The URL of the image of the item to be repaired or the repair process \ No newline at end of file + type: object + properties: + results: + type: array + items: + type: object + properties: + id: + type: string + description: The unique identifier of the repair + title: + type: string + description: The short summary of the repair + description: + type: string + description: The detailed description of the repair + assignedTo: + type: string + description: The user who is responsible for the repair + date: + type: string + format: date-time + description: The date and time when the repair is scheduled or completed + image: + type: string + format: uri + description: The URL of the image of the item to be repaired or the repair process \ No newline at end of file diff --git a/templates/ts/copilot-plugin-from-scratch/src/functions/repair.ts b/templates/ts/copilot-plugin-from-scratch/src/functions/repair.ts index 27fbecc0f9..a475e156c3 100644 --- a/templates/ts/copilot-plugin-from-scratch/src/functions/repair.ts +++ b/templates/ts/copilot-plugin-from-scratch/src/functions/repair.ts @@ -31,7 +31,7 @@ export async function repair( // Get the assignedTo query parameter. const assignedTo = req.query.get("assignedTo"); - // If the assignedTo query parameter is not provided, return the response. + // If the assignedTo query parameter is not provided, return an empty array. if (!assignedTo) { return res; } diff --git a/templates/ts/custom-copilot-assistant-assistants-api/src/app/app.ts.tpl b/templates/ts/custom-copilot-assistant-assistants-api/src/app/app.ts.tpl index 6d7449799a..eb9ca815cb 100644 --- a/templates/ts/custom-copilot-assistant-assistants-api/src/app/app.ts.tpl +++ b/templates/ts/custom-copilot-assistant-assistants-api/src/app/app.ts.tpl @@ -49,15 +49,6 @@ const app = new Application({ }, }); -app.conversationUpdate("membersAdded", async (turnContext: TurnContext) => { - const welcomeText = "How can I help you today?"; - for (const member of turnContext.activity.membersAdded) { - if (member.id !== turnContext.activity.recipient.id) { - await turnContext.sendActivity(MessageFactory.text(welcomeText)); - } - } -}); - app.feedbackLoop(async (context, state, feedbackLoopData) => { //add custom feedback process logic here console.log("Your feedback is " + JSON.stringify(context.activity.value)); diff --git a/templates/ts/custom-copilot-assistant-new/src/app/app.ts.tpl b/templates/ts/custom-copilot-assistant-new/src/app/app.ts.tpl index 16b0b7093e..b77f65f7fb 100644 --- a/templates/ts/custom-copilot-assistant-new/src/app/app.ts.tpl +++ b/templates/ts/custom-copilot-assistant-new/src/app/app.ts.tpl @@ -42,15 +42,6 @@ const app = new Application({ }, }); -app.conversationUpdate("membersAdded", async (turnContext: TurnContext) => { - const welcomeText = "How can I help you today?"; - for (const member of turnContext.activity.membersAdded) { - if (member.id !== turnContext.activity.recipient.id) { - await turnContext.sendActivity(MessageFactory.text(welcomeText)); - } - } -}); - app.feedbackLoop(async (context, state, feedbackLoopData) => { //add custom feedback process logic here console.log("Your feedback is " + JSON.stringify(context.activity.value)); diff --git a/templates/ts/custom-copilot-basic/src/app/app.ts.tpl b/templates/ts/custom-copilot-basic/src/app/app.ts.tpl index 9ace32e75f..8e8f345573 100644 --- a/templates/ts/custom-copilot-basic/src/app/app.ts.tpl +++ b/templates/ts/custom-copilot-basic/src/app/app.ts.tpl @@ -39,15 +39,6 @@ const app = new Application({ }, }); -app.conversationUpdate("membersAdded", async (turnContext: TurnContext) => { - const welcomeText = "How can I help you today?"; - for (const member of turnContext.activity.membersAdded) { - if (member.id !== turnContext.activity.recipient.id) { - await turnContext.sendActivity(MessageFactory.text(welcomeText)); - } - } -}); - app.feedbackLoop(async (context, state, feedbackLoopData) => { //add custom feedback process logic here console.log("Your feedback is " + JSON.stringify(context.activity.value)); diff --git a/templates/ts/custom-copilot-rag-azure-ai-search/src/app/app.ts.tpl b/templates/ts/custom-copilot-rag-azure-ai-search/src/app/app.ts.tpl index 7649a0c0c2..9e1fc263b7 100644 --- a/templates/ts/custom-copilot-rag-azure-ai-search/src/app/app.ts.tpl +++ b/templates/ts/custom-copilot-rag-azure-ai-search/src/app/app.ts.tpl @@ -61,15 +61,6 @@ const app = new Application({ }); app.ai.action(AI.SayCommandActionName, customSayCommand.sayCommand(true)); -app.conversationUpdate("membersAdded", async (turnContext: TurnContext) => { - const welcomeText = "How can I help you today?"; - for (const member of turnContext.activity.membersAdded) { - if (member.id !== turnContext.activity.recipient.id) { - await turnContext.sendActivity(MessageFactory.text(welcomeText)); - } - } -}); - app.feedbackLoop(async (context, state, feedbackLoopData) => { //add custom feedback process logic here console.log("Your feedback is " + JSON.stringify(context.activity.value)); diff --git a/templates/ts/custom-copilot-rag-customize/src/app/app.ts.tpl b/templates/ts/custom-copilot-rag-customize/src/app/app.ts.tpl index b2bc16d432..db6fb153aa 100644 --- a/templates/ts/custom-copilot-rag-customize/src/app/app.ts.tpl +++ b/templates/ts/custom-copilot-rag-customize/src/app/app.ts.tpl @@ -47,15 +47,6 @@ const app = new Application({ }); app.ai.action(AI.SayCommandActionName, customSayCommand.sayCommand(true)); -app.conversationUpdate("membersAdded", async (turnContext: TurnContext) => { - const welcomeText = "How can I help you today?"; - for (const member of turnContext.activity.membersAdded) { - if (member.id !== turnContext.activity.recipient.id) { - await turnContext.sendActivity(MessageFactory.text(welcomeText)); - } - } -}); - app.feedbackLoop(async (context, state, feedbackLoopData) => { //add custom feedback process logic here console.log("Your feedback is " + JSON.stringify(context.activity.value)); diff --git a/templates/ts/custom-copilot-rag-microsoft365/src/app/app.ts.tpl b/templates/ts/custom-copilot-rag-microsoft365/src/app/app.ts.tpl index bbd0e7ed6a..191d077f28 100644 --- a/templates/ts/custom-copilot-rag-microsoft365/src/app/app.ts.tpl +++ b/templates/ts/custom-copilot-rag-microsoft365/src/app/app.ts.tpl @@ -62,15 +62,6 @@ const app = new Application({ }); app.ai.action(AI.SayCommandActionName, customSayCommand.sayCommand(true)); -app.conversationUpdate("membersAdded", async (turnContext: TurnContext) => { - const welcomeText = "How can I help you today?"; - for (const member of turnContext.activity.membersAdded) { - if (member.id !== turnContext.activity.recipient.id) { - await turnContext.sendActivity(MessageFactory.text(welcomeText)); - } - } -}); - app.authentication.get("graph").onUserSignInSuccess(async (context, state) => { // Successfully logged in await context.sendActivity("You are successfully logged in. You can send a new message to talk to the bot.");