From 9219756e436f11488aaceb8b159861972558447f Mon Sep 17 00:00:00 2001 From: Nabin Kawan Date: Mon, 22 Apr 2024 10:15:44 +0545 Subject: [PATCH 001/125] Test deploy token --- .github/workflows/test_integration_playwright.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/test_integration_playwright.yml b/.github/workflows/test_integration_playwright.yml index 87ce009d7..d7f0ff4aa 100644 --- a/.github/workflows/test_integration_playwright.yml +++ b/.github/workflows/test_integration_playwright.yml @@ -78,7 +78,7 @@ jobs: ref: gh-pages path: gh-pages repository: ${{vars.GH_PAGES}} - token: ${{ secrets.PERSONAL_TOKEN }} + ssh-key: ${{ secrets.DEPLOY_KEY }} - name: Register report id: register-project @@ -89,7 +89,7 @@ jobs: - if: steps.register-project.outputs.project_exists != 'true' uses: JamesIves/github-pages-deploy-action@v4 with: - token: ${{ secrets.PERSONAL_TOKEN }} + ssh-key: ${{ secrets.DEPLOY_KEY }} repository-name: ${{vars.GH_PAGES}} branch: gh-pages folder: project @@ -121,7 +121,7 @@ jobs: - name: Deploy report to Github Pages uses: JamesIves/github-pages-deploy-action@v4 with: - token: ${{ secrets.PERSONAL_TOKEN }} + ssh-key: ${{ secrets.DEPLOY_KEY }} repository-name: ${{vars.GH_PAGES}} branch: gh-pages folder: build From db1ddb2518124d035d3a447bb60d2fc761ebaafa Mon Sep 17 00:00:00 2001 From: Nabin Kawan Date: Mon, 22 Apr 2024 10:35:42 +0545 Subject: [PATCH 002/125] Add env and readme for deploy key setup --- .../govtool-frontend/playwright/.env.example | 18 ++++++++++++ tests/govtool-frontend/playwright/README.md | 29 +++++++++++++++++++ 2 files changed, 47 insertions(+) create mode 100644 tests/govtool-frontend/playwright/.env.example create mode 100644 tests/govtool-frontend/playwright/README.md diff --git a/tests/govtool-frontend/playwright/.env.example b/tests/govtool-frontend/playwright/.env.example new file mode 100644 index 000000000..c5f2ff3d1 --- /dev/null +++ b/tests/govtool-frontend/playwright/.env.example @@ -0,0 +1,18 @@ +FRONTEND_URL=http://localhost:8080 +API_URL=http://localhost:8080/api + +DOCS_URL=https://docs.sanchogov.tools + +# 1 for testnet, 0 for mainnet +NETWORK_ID=1, + +# Create mock wallets if true +ONE_TIME_WALLET_SETUP=false, + +# Faucet +FAUCET_API_URL=https://faucet.sanchonet.world.dev.cardano.org +FAUCET_API_KEY= + +# Kuber +KUBER_API_URL=https://sanchonet.kuber.cardanoapi.io +KUBER_API_KEY= \ No newline at end of file diff --git a/tests/govtool-frontend/playwright/README.md b/tests/govtool-frontend/playwright/README.md new file mode 100644 index 000000000..47a5edca3 --- /dev/null +++ b/tests/govtool-frontend/playwright/README.md @@ -0,0 +1,29 @@ +# GitHub Pages Deployment SSH Deploy Key Generation Guide + +This guide walks you through the process of generating an SSH deploy key for GitHub Pages deployment and securely integrating it into your workflow. + +## Generating the SSH Deploy Key + +Execute the following command in your terminal to generate the SSH deploy key: + +```bash +ssh-keygen -t rsa -b 4096 -C "$(git config user.email)" -f gh-pages -N "" +``` + +This command will generate two files: + +- `gh-pages.pub`: Public key +- `gh-pages`: Private key + +## Integration Steps + +1. **Repository Settings:** + + - Navigate to your repository settings. + +2. **Adding Public Key to Deploy Keys: Add to** [`https://github.com/cardanoapi/govtool-test-reports`](https://github.com/cardanoapi/govtool-test-reports) + + - Go to Deploy Keys and add your public key. Make sure to grant it write access. + +3. **Adding Private Key to Secrets:** + - Go to Secrets and add your private key as `DEPLOY_KEY`. From a873b1026361d7c2a8a9d3b417647ee2d9929b4e Mon Sep 17 00:00:00 2001 From: Adam Guderski Date: Wed, 24 Apr 2024 12:51:38 +0200 Subject: [PATCH 003/125] [#849] Configure sanchogov.tools sub-domain for the analytics service This adds Terraform code that creats "participation" subdomains for each environments. The exception is the beta environment, where DNS records are not handled with TF, but need to be created manually. --- infra/terraform/modules/govtool-ec2/main.tf | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/infra/terraform/modules/govtool-ec2/main.tf b/infra/terraform/modules/govtool-ec2/main.tf index 40ad6f6cd..bddf37ce7 100644 --- a/infra/terraform/modules/govtool-ec2/main.tf +++ b/infra/terraform/modules/govtool-ec2/main.tf @@ -193,3 +193,12 @@ resource "aws_route53_record" "frontend" { ttl = 180 records = [aws_eip.govtool.public_ip] } + +resource "aws_route53_record" "participation" { + count = var.app_env == "beta" ? 0 : 1 + zone_id = var.dns_zone_id + name = "${var.custom_subdomain != "" ? "participation.${var.custom_subdomain}" : "participation.${var.app_env}-${var.cardano_network}"}" + type = "A" + ttl = 180 + records = [aws_eip.govtool.public_ip] +} \ No newline at end of file From 9fbd99c1f1913e21452fa9badb3df98cb22f717d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Placzy=C5=84ski?= Date: Wed, 24 Apr 2024 14:45:36 +0200 Subject: [PATCH 004/125] [#849] Move Makefiles to scripts directory Moved the Makefiles from various directories to the scripts directory for better organization and consistency. Renamed the Makefiles accordingly and updated the references within other files to use the new paths in the scripts directory. This restructuring helps in streamlining the build processes and eases maintenance tasks related to the make files. --- .../{Makefile => status-service.mk} | 2 +- scripts/govtool/Makefile | 8 +++---- .../Makefile => scripts/govtool/backend.mk | 2 +- scripts/govtool/config.mk | 2 +- .../Makefile => scripts/govtool/frontend.mk | 2 +- .../govtool/metadata-validation.mk | 2 +- scripts/govtool/status-service.mk | 21 +++++++++++++++++++ 7 files changed, 30 insertions(+), 9 deletions(-) rename govtool/status-service/{Makefile => status-service.mk} (94%) rename govtool/backend/Makefile => scripts/govtool/backend.mk (96%) rename govtool/frontend/Makefile => scripts/govtool/frontend.mk (95%) rename govtool/metadata-validation/Makefile => scripts/govtool/metadata-validation.mk (94%) create mode 100644 scripts/govtool/status-service.mk diff --git a/govtool/status-service/Makefile b/govtool/status-service/status-service.mk similarity index 94% rename from govtool/status-service/Makefile rename to govtool/status-service/status-service.mk index 07d975981..1337f776a 100644 --- a/govtool/status-service/Makefile +++ b/govtool/status-service/status-service.mk @@ -1,4 +1,4 @@ -common_mk := ../../scripts/govtool/common.mk +common_mk := common.mk ifeq ($(origin $(common_mk)), undefined) $(eval $(common_mk) := included) include $(common_mk) diff --git a/scripts/govtool/Makefile b/scripts/govtool/Makefile index 281de5f36..3fab57890 100644 --- a/scripts/govtool/Makefile +++ b/scripts/govtool/Makefile @@ -1,7 +1,7 @@ -include ../../govtool/backend/Makefile -include ../../govtool/frontend/Makefile -include ../../govtool/status-service/Makefile -include ../../govtool/metadata-validation/Makefile +include backend.mk +include frontend.mk +include status-service.mk +include metadata-validation.mk include utils.mk include info.mk include config.mk diff --git a/govtool/backend/Makefile b/scripts/govtool/backend.mk similarity index 96% rename from govtool/backend/Makefile rename to scripts/govtool/backend.mk index 1919d4847..a523973dd 100644 --- a/govtool/backend/Makefile +++ b/scripts/govtool/backend.mk @@ -1,4 +1,4 @@ -common_mk := ../../scripts/govtool/common.mk +common_mk := common.mk ifeq ($(origin $(common_mk)), undefined) $(eval $(common_mk) := included) include $(common_mk) diff --git a/scripts/govtool/config.mk b/scripts/govtool/config.mk index 87c424d03..2a7c4b770 100644 --- a/scripts/govtool/config.mk +++ b/scripts/govtool/config.mk @@ -1,4 +1,4 @@ -common_mk := ../../scripts/govtool/common.mk +common_mk := common.mk ifeq ($(origin $(common_mk)), undefined) $(eval $(common_mk) := included) include $(common_mk) diff --git a/govtool/frontend/Makefile b/scripts/govtool/frontend.mk similarity index 95% rename from govtool/frontend/Makefile rename to scripts/govtool/frontend.mk index a9c19da18..97caf9bef 100644 --- a/govtool/frontend/Makefile +++ b/scripts/govtool/frontend.mk @@ -1,4 +1,4 @@ -common_mk := ../../scripts/govtool/common.mk +common_mk := common.mk ifeq ($(origin $(common_mk)), undefined) $(eval $(common_mk) := included) include $(common_mk) diff --git a/govtool/metadata-validation/Makefile b/scripts/govtool/metadata-validation.mk similarity index 94% rename from govtool/metadata-validation/Makefile rename to scripts/govtool/metadata-validation.mk index 10b0379db..d9ab1a150 100644 --- a/govtool/metadata-validation/Makefile +++ b/scripts/govtool/metadata-validation.mk @@ -1,4 +1,4 @@ -common_mk := ../../scripts/govtool/common.mk +common_mk := common.mk ifeq ($(origin $(common_mk)), undefined) $(eval $(common_mk) := included) include $(common_mk) diff --git a/scripts/govtool/status-service.mk b/scripts/govtool/status-service.mk new file mode 100644 index 000000000..1337f776a --- /dev/null +++ b/scripts/govtool/status-service.mk @@ -0,0 +1,21 @@ +common_mk := common.mk +ifeq ($(origin $(common_mk)), undefined) + $(eval $(common_mk) := included) + include $(common_mk) +endif + +.DEFAULT_GOAL := push-status-service + +# image tags +status_service_image_tag := $(shell git log -n 1 --format="%H" -- $(root_dir)/govtool/status-service) + +.PHONY: build-status-service +build-status-service: docker-login + $(call check_image_on_ecr,status-service,$(status_service_image_tag)) || \ + $(docker) build --tag "$(repo_url)/status-service:$(status_service_image_tag)" \ + $(root_dir)/govtool/status-service + +.PHONY: push-status-service +push-status-service: build-status-service + $(call check_image_on_ecr,status-service,$(status_service_image_tag)) || \ + $(docker) push $(repo_url)/status-service:$(status_service_image_tag) From bafb119b81c57d3a6a015a2c6c91130f38d4c77f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Placzy=C5=84ski?= Date: Wed, 24 Apr 2024 15:16:59 +0200 Subject: [PATCH 005/125] [#849] Use a more recent version of nixpkgs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit …for scripts and infrastructure to meet the requirements stated in the terraform configuration In this commit, changes have been made to the `flake.nix` file to utilize a more recent version of nixpkgs for both scripts and infrastructure. The modifications ensure that the scripts and infrastructure align with the specified requirements in the terraform configuration. Specifically, the nodePkgs import has been updated to allow unfree packages, and the packages.scripts and packages.infra sections have been adjusted to utilize the nodePkgs instead of defaultPkgs. This adjustment guarantees that the scripts and infrastructure components are in line with the necessary configurations, enhancing compatibility and meeting the user story's demands. --- flake.nix | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/flake.nix b/flake.nix index 1e8abffbf..10b2a4c29 100644 --- a/flake.nix +++ b/flake.nix @@ -9,12 +9,12 @@ flake-utils.lib.eachDefaultSystem (system: let defaultPkgs = import default_nixpkgs { inherit system; config.allowBroken = true; }; - nodePkgs = import node_nixpkgs { inherit system; }; + nodePkgs = import node_nixpkgs { inherit system; config.allowUnfree = true; }; frontend = nodePkgs.callPackage ./govtool/frontend { pkgs = nodePkgs; }; in { - packages.scripts = defaultPkgs.callPackage ./scripts/govtool { pkgs = defaultPkgs; }; - packages.infra = defaultPkgs.callPackage ./infra/terraform { pkgs = defaultPkgs; }; + packages.scripts = defaultPkgs.callPackage ./scripts/govtool { pkgs = nodePkgs; }; + packages.infra = defaultPkgs.callPackage ./infra/terraform { pkgs = nodePkgs; }; packages.backend = defaultPkgs.callPackage ./govtool/backend { pkgs = defaultPkgs; }; packages.frontendModules = frontend.nodeModules; packages.frontend = frontend.staticSite; From dafa29fef61f90c0eefa046524c6e21d80ae69a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Placzy=C5=84ski?= Date: Wed, 24 Apr 2024 15:40:32 +0200 Subject: [PATCH 006/125] [#849] Add a registry for the analytics-dashboard module A registry has been incorporated for the analytics-dashboard module within the Terraform configuration. This modification introduces a new module named "govtool-ecr-analytics-dashboard" sourced from "./modules/ecr" with the repository name set to "analytics-dashboard." By including this new module, the analytics-dashboard component is now integrated into the infrastructure setup, aligning with the user story's objective of configuring the sanchogov.tools sub-domain for the analytics service. --- infra/terraform/main.tf | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/infra/terraform/main.tf b/infra/terraform/main.tf index 18e24437e..198b64c3c 100644 --- a/infra/terraform/main.tf +++ b/infra/terraform/main.tf @@ -36,6 +36,11 @@ module "govtool-ecr-metadata-validation" { repo_name = "metadata-validation" } +module "govtool-ecr-analytics-dashboard" { + source = "./modules/ecr" + repo_name = "analytics-dashboard" +} + resource "aws_iam_policy" "cicd_ecr" { name = "CICD_ECR" policy = jsonencode({ @@ -51,7 +56,8 @@ resource "aws_iam_policy" "cicd_ecr" { module.govtool-ecr-backend-base.repo_arn, module.govtool-ecr-frontend.repo_arn, module.govtool-ecr-status-service.repo_arn, - module.govtool-ecr-metadata-validation.repo_arn + module.govtool-ecr-metadata-validation.repo_arn, + module.govtool-ecr-analytics-dashboard.repo_arn ] }, { @@ -125,6 +131,10 @@ output "govtool-ecr-metadata-validation-url" { value = module.govtool-ecr-metadata-validation.repo_url } +output "govtool-ecr-analytics-dashboard-url" { + value = module.govtool-ecr-analytics-dashboard.repo_url +} + output "govtool-dev-sanchonet-frontend-domain" { value = module.govtool-dev-sanchonet.frontend_domain } From be58a70e5a3ba87e170284d3b68d929b50b43db6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Sworze=C5=84?= Date: Thu, 25 Apr 2024 10:02:07 +0200 Subject: [PATCH 007/125] fix show more button display --- govtool/frontend/src/pages/DRepDirectoryContent.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/govtool/frontend/src/pages/DRepDirectoryContent.tsx b/govtool/frontend/src/pages/DRepDirectoryContent.tsx index 6192fa9a3..efd8a61ad 100644 --- a/govtool/frontend/src/pages/DRepDirectoryContent.tsx +++ b/govtool/frontend/src/pages/DRepDirectoryContent.tsx @@ -193,7 +193,7 @@ export const DRepDirectoryContent: FC = ({ })} - {dRepListHasNextPage && ( + {dRepListHasNextPage && dRepList.length >= 10 && ( + theme.zIndex.drawer + 100 }} + open={loading} + onClick={() => closeLoader()} + // ref={loaderRef} + > + + + ); +}; + +export default Loader; diff --git a/src/components/ThemeProviderWrapper/index.js b/src/components/ThemeProviderWrapper/index.js new file mode 100644 index 000000000..0dbcc9118 --- /dev/null +++ b/src/components/ThemeProviderWrapper/index.js @@ -0,0 +1,153 @@ +'use client'; +import { Sidebar } from '@/components'; +import Loader from '@/components/Loader'; +import { useAppContext } from '@/context/context'; +import { usePathname } from '@/navigation'; +import { Box } from '@mui/material'; +import { + ThemeProvider, + createTheme, + responsiveFontSizes, +} from '@mui/material/styles'; +import { useEffect, useRef, useState } from 'react'; + +let theme = createTheme({ + components: { + MuiButton: { + styleOverrides: { + root: { + fontFamily: 'Poppins', + padding: '12px 24px', + borderRadius: 100, + textTransform: 'none', + }, + }, + }, + MuiCard: { + styleOverrides: { + root: { borderRadius: 16 }, + }, + }, + MuiCardContent: { + styleOverrides: { + root: { padding: '20px 24px' }, + }, + }, + MuiTypography: { + styleOverrides: { + root: { fontFamily: 'Poppins' }, + h4: { fontWeight: 500, color: '#212A3D' }, + body1: { color: '#506288' }, + subtitle2: { color: '#506288' }, + caption: { color: '#212A3D', fontWeight: 400 }, + }, + defaultProps: { + variantMapping: { + h4: 'h1', + }, + }, + }, + MuiInputBase: { + styleOverrides: { + input: { + fontFamily: 'Poppins', + }, + root: { + fontFamily: 'Poppins', + } + }, + }, + MuiOutlinedInput: { + styleOverrides: { + input: { + fontFamily: 'Poppins', + }, + root: { + fontFamily: 'Poppins', + } + }, + }, + }, + palette: { + primary: { + main: '#3052F5', + }, + secondary: { + main: '#D63F1E', + }, + text: { + main: '#fff', + gray: '#506288', + black: '#212A3D', + primaryBlue: "#0033AD" + }, + background: { + default: '#F2F4F8', + primaryContainer: '#0114BC', + info: '#EDEBFF', + white: '#fff', + }, + success: { + main: '#CEF3D4', + }, + icon: { + disabled: '#BDBDBD' + } + }, +}); +theme.typography = { + ...theme.typography, + fontFamily: 'Poppins, sans-serif', +}; +theme = responsiveFontSizes(theme); + +function ThemeProviderWrapper({ children }) { + const { pageBackground } = useAppContext(); + const [windowWidth, setWindowWidth] = useState(0); + + const drawerWidth = 340; + const pathname = usePathname(); + + useEffect(() => { + if (window) { + setWindowWidth(window?.innerWidth); + } + const handleResize = () => { + setWindowWidth(window?.innerWidth); + }; + + window?.addEventListener('resize', handleResize); + + return () => window?.removeEventListener('resize', handleResize); + }, []); + + + + return ( + + {/* */} + {pathname.includes('/dashboard') && ( + + )} + + + {children} + + + ); +} + +export default ThemeProviderWrapper; \ No newline at end of file diff --git a/src/components/index.js b/src/components/index.js new file mode 100644 index 000000000..e69de29bb diff --git a/src/constants/index.js b/src/constants/index.js new file mode 100644 index 000000000..8e019e3a6 --- /dev/null +++ b/src/constants/index.js @@ -0,0 +1,10 @@ +// This file consolidates default values and constants used throughout the application, +// such as pagination settings (size and default page), default locale, and more. +// These constants ensure uniform behavior and settings across different parts of the app. +// Refer to this file to use or update default configurations for consistent application functionality. + +// Define an array of available language locales for the application. +export const locales = ["en", "de"]; + +// Set the default language locale for the application. +export const defaultLocale = "en"; diff --git a/src/context/context.js b/src/context/context.js new file mode 100644 index 000000000..6a9f219d4 --- /dev/null +++ b/src/context/context.js @@ -0,0 +1,43 @@ +// The "use client" directive indicates that this module is intended to run in the client environment, +// which is particularly relevant for Next.js applications that support server-side rendering (SSR). +"use client"; + +// Import createContext and useContext hooks from React to create and consume the context. +import { createContext, useContext } from "react"; + +// Create a new Context object. This will be used to provide and consume the context. +const AppContext = createContext(); + +// Define a provider component. This component will wrap the part of your app where you want the context to be accessible. +export function AppContextProvider({ children }) { + // Define any values or functions you want to make available throughout your component tree. + const testValue = "Test"; + const testFunction = () => { + return null; + }; + + // Render the provider component of your context, passing in the values or functions as the value prop. + // Any child components will be able to access these values via the useAppContext hook. + return ( + + {children} + + ); +} + +// Define a custom hook to provide a convenient way to access the context values. +// This hook abstracts away the useContext hook specifically for this context. +export function useAppContext() { + const context = useContext(AppContext); + + // Perform a check to ensure that this hook is used within a component wrapped in AppContextProvider. + // This helps prevent errors from occurring if the context is used outside of the provider. + if (context === undefined) { + throw new Error( + "useAppContext must be used within a AppContextProvider" + ); + } + + // Return the context value, making it accessible to components that call this hook. + return context; +} diff --git a/src/i18n.js b/src/i18n.js new file mode 100644 index 000000000..151bc5b83 --- /dev/null +++ b/src/i18n.js @@ -0,0 +1,16 @@ +// Import getRequestConfig from next-intl for configuring request-level internationalization. +import { getRequestConfig } from "next-intl/server"; +import { notFound } from "next/navigation"; +import { locales } from "./constants"; + +// This setup function is called for each request to determine the appropriate locale messages to load. +export default getRequestConfig(async ({ locale }) => { + // Check if the requested locale is supported. If not, trigger a notFound response. + if (!locales.includes(locale)) notFound(); + + // Dynamically import the JSON messages file for the requested locale and return it. + // This allows serving locale-specific content without hardcoding the locale data. + return { + messages: (await import(`../messages/${locale}.json`)).default, + }; +}); diff --git a/src/lib/api.js b/src/lib/api.js new file mode 100644 index 000000000..f07f263de --- /dev/null +++ b/src/lib/api.js @@ -0,0 +1,13 @@ +import axiosInstance from "@/lib/axiosInstance"; + +//This file contains API functions to interact with the backend +async function getGoogleData() { + try { + const { data } = await axiosInstance.get('/api/analytics'); + return data; + } catch (error) { + return []; + } +} + +export default getGoogleData; \ No newline at end of file diff --git a/src/lib/axiosInstance.js b/src/lib/axiosInstance.js new file mode 100644 index 000000000..cb182f142 --- /dev/null +++ b/src/lib/axiosInstance.js @@ -0,0 +1,19 @@ +// Import the Axios library, which is used for making HTTP requests. +import axios from "axios"; + +// Define the base URL for the Axios instance. This uses an environment variable for flexibility, +// defaulting to "http://localhost:1337" if the environment variable is not set. +// This is useful for differentiating between development and production environments. +const baseURL = process.env.NEXT_PUBLIC_API_URL || "http://localhost:3000"; + +// Create a customized instance of Axios with the defined base URL. +// This instance will inherit all the default settings of Axios, but will use the specified baseURL +// for all the requests, making it unnecessary to repeatedly specify the baseURL in every request. +const axiosInstance = axios.create({ + baseURL, +}); + +// Export the customized Axios instance for use throughout the application. +// This allows for a consistent configuration and simplifies making API requests by +// pre-configuring the base part of the request URLs. +export default axiosInstance; diff --git a/src/lib/helpers.js b/src/lib/helpers.js new file mode 100644 index 000000000..d5cf1446a --- /dev/null +++ b/src/lib/helpers.js @@ -0,0 +1,4 @@ +// helpers.js +// This file contains helper functions used throughout the application for performing common tasks. +// Functions include operations such as date formatting, array and object manipulation, and input validation. +// Use these functions to keep your code clean and avoid duplicating code in different parts of the application. diff --git a/src/lib/utils.js b/src/lib/utils.js new file mode 100644 index 000000000..aff2c0a04 --- /dev/null +++ b/src/lib/utils.js @@ -0,0 +1,9 @@ +// utils.js +// This file is designed to house small, reusable utility functions that serve as building blocks for constructing more complex functionalities within the application. +// It includes a range of generic helpers for tasks like data manipulation, formatting, and validation. +// Additionally, this file may contain functions for testing purposes, providing a toolkit for verifying the correctness and efficiency of larger functions. +// By centralizing these utilities, we promote a modular and maintainable codebase, facilitating ease of development and testing. + +export const sumTestExample = (a, b) => { + return a + b; +}; diff --git a/src/middleware.js b/src/middleware.js new file mode 100644 index 000000000..8067190ce --- /dev/null +++ b/src/middleware.js @@ -0,0 +1,16 @@ +// Import createMiddleware from next-intl to configure internationalization middleware for Next.js. +import createMiddleware from "next-intl/middleware"; +import { defaultLocale, locales } from "./constants"; + +// Export the middleware configuration to define supported locales and the default locale. +// This setup applies internationalization strategies across the application. +export default createMiddleware({ + locales: locales, // Specify the supported locales for the application. + defaultLocale: defaultLocale, // Set the default locale to be used when no other locale matches. +}); + +// Define and export a config object to specify which paths the middleware should apply to. +// This ensures the internationalization logic only runs for specified routes. +export const config = { + matcher: ["/", "/(de|en)/:path*"], // Apply middleware to the root path and any path prefixed with supported locales. +}; diff --git a/src/navigation.js b/src/navigation.js new file mode 100644 index 000000000..769f08af1 --- /dev/null +++ b/src/navigation.js @@ -0,0 +1,12 @@ +// Importing createSharedPathnamesNavigation from next-intl/navigation to initialize locale-aware navigation helpers. +import { createSharedPathnamesNavigation } from "next-intl/navigation"; +import { locales } from "./constants"; + +// Setting the locale prefixing strategy to 'always', ensuring URLs always include the locale. +export const localePrefix = "always"; // Default + +// Destructuring and exporting the navigation helpers from createSharedPathnamesNavigation. +// This creates and configures custom Link, redirect, usePathname, and useRouter functions that are aware of the defined locales and prefixing strategy. +// These helpers should be used throughout the application to ensure navigation is handled correctly with respect to the active locale. +export const { Link, redirect, usePathname, useRouter } = + createSharedPathnamesNavigation({ locales: locales, localePrefix }); diff --git a/src/pages/api/analytics.js b/src/pages/api/analytics.js new file mode 100644 index 000000000..6a7ccae2c --- /dev/null +++ b/src/pages/api/analytics.js @@ -0,0 +1,35 @@ +import { BetaAnalyticsDataClient } from '@google-analytics/data'; + +const analyticsDataClient = new BetaAnalyticsDataClient({ + credentials: { + client_email: process.env.GA_CLIENT_EMAIL, + private_key: process.env.GA_PRIVATE_KEY.replace(/\\n/g, '\n') + } +}) + +const propertyId = process.env.NEXT_PUBLIC_GA4_PROPERTY_ID; + +export default async function handler(req, res) { + try { + const [response] = await analyticsDataClient.runReport({ + property: `properties/${propertyId}`, + dateRanges: [{ + startDate: '2024-01-01', + endDate: 'today', + }], + dimensions: [{ name: 'eventName' }], + metrics: [{ name: 'eventCount' }], + limit: 1000 + }); + + const events = response.rows.map(row => ({ + eventName: row.dimensionValues[0].value, + eventCount: row.metricValues[0].value + })); + + res.status(200).json(events); + } catch (error) { + console.error('Error running report:', error); + res.status(500).json({ message: 'Failed to fetch data' }); + } +} diff --git a/src/styles/index.css b/src/styles/index.css new file mode 100644 index 000000000..ab0ddb29e --- /dev/null +++ b/src/styles/index.css @@ -0,0 +1,20 @@ +@font-face { + font-family: 'Poppins'; + src: url('/fonts/Poppins-Medium.ttf'); + font-style: normal; + font-weight: 500; +} + +@font-face { + font-family: 'Poppins'; + src: url('/fonts/Poppins-Bold.ttf'); + font-style: normal; + font-weight: 700; +} + +@font-face { + font-family: 'Poppins'; + src: url('/fonts/Poppins-Regular.ttf'); + font-style: normal; + font-weight: 400; +} diff --git a/src/tests/components/componentExample.test.js b/src/tests/components/componentExample.test.js new file mode 100644 index 000000000..c0c32c584 --- /dev/null +++ b/src/tests/components/componentExample.test.js @@ -0,0 +1,9 @@ +import React from "react"; +import { render, screen } from "@testing-library/react"; +import ComponentExample from "@/components/ComponentExample"; + +test("renders the sum of two numbers", () => { + render(); + const sumElement = screen.getByText("5"); + expect(sumElement).toBeInTheDocument(); +}); diff --git a/src/tests/utils/exampleUtil.test.js b/src/tests/utils/exampleUtil.test.js new file mode 100644 index 000000000..2e6974f56 --- /dev/null +++ b/src/tests/utils/exampleUtil.test.js @@ -0,0 +1,7 @@ +import { sumTestExample } from "@/lib/utils"; + +describe("sum module", () => { + test("adds 1 + 2 to equal 3", () => { + expect(sumTestExample(1, 2)).toBe(3); + }); +}); From 4829b313301c9d2403456214d2d47cc05e7b0ea8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Placzy=C5=84ski?= Date: Thu, 25 Apr 2024 14:51:23 +0200 Subject: [PATCH 018/125] [#849] Fix broken docker compose In this commit, the docker-compose file was modified to include the `google-credentials.json` file as a secret volume. This change was made to ensure that the necessary Google credentials are available for the analytics service running on the `participation.sanchogov.tools` sub-domain. Including the `google-credentials.json` file in the docker-compose configuration is crucial for the proper functioning of the analytics dashboard service. --- scripts/govtool/config/templates/docker-compose.yml.tpl | 2 ++ 1 file changed, 2 insertions(+) diff --git a/scripts/govtool/config/templates/docker-compose.yml.tpl b/scripts/govtool/config/templates/docker-compose.yml.tpl index 4ec065705..e997a52b7 100644 --- a/scripts/govtool/config/templates/docker-compose.yml.tpl +++ b/scripts/govtool/config/templates/docker-compose.yml.tpl @@ -291,6 +291,8 @@ secrets: file: /home//config/dbsync-secrets/postgres_user backend-config.json: file: /home//config/backend-config.json + google-credentials.json: + file: /home//config/google-credentials.json volumes: letsencrypt: From af3051a7e6e28cbb5dbb5b7826476a38ca764b5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Placzy=C5=84ski?= Date: Thu, 25 Apr 2024 14:52:16 +0200 Subject: [PATCH 019/125] [#849] Add build arg for docker image for analytics-dashboard In this commit, an argument (`NEXT_PUBLIC_API_URL`) was added to the `Dockerfile` of the analytics-dasboard service. This change is necessary to dynamically specify the API URL that the dashboard should connect to. By introducing this build arg, the analytics dashboard service can now adapt to different environments, like the `participation.sanchogov.tools` sub-domain, as part of configuring the analytics service under one domain tree. --- govtool/analytics-dashboard/Dockerfile | 3 ++- scripts/govtool/analytics-dashboard.mk | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/govtool/analytics-dashboard/Dockerfile b/govtool/analytics-dashboard/Dockerfile index 89776f804..6128db7ff 100644 --- a/govtool/analytics-dashboard/Dockerfile +++ b/govtool/analytics-dashboard/Dockerfile @@ -17,6 +17,7 @@ RUN \ # Rebuild the source code only when needed FROM base AS builder +ARG NEXT_PUBLIC_API_URL WORKDIR /app COPY --from=deps /app/node_modules ./node_modules COPY . . @@ -62,4 +63,4 @@ ENV PORT 3000 ENV HOSTNAME "0.0.0.0" # server.js is created by next build from the standalone output -CMD ["node", "server.js"] \ No newline at end of file +CMD ["node", "server.js"] diff --git a/scripts/govtool/analytics-dashboard.mk b/scripts/govtool/analytics-dashboard.mk index f56f89b92..98d2ae7e3 100644 --- a/scripts/govtool/analytics-dashboard.mk +++ b/scripts/govtool/analytics-dashboard.mk @@ -12,7 +12,9 @@ analytics_dashboard_image_tag := $(shell git log -n 1 --format="%H" -- $(root_di .PHONY: build-analytics-dashboard build-analytics-dashboard: $(call check_image_on_ecr,analytics-dashboard,$(analytics_dashboard_image_tag)) || \ - $(docker) build --tag "$(repo_url)/analytics-dashboard:$(analytics_dashboard_image_tag)" $(root_dir)/govtool/analytics-dashboard + $(docker) build --tag "$(repo_url)/analytics-dashboard:$(analytics_dashboard_image_tag)" \ + --build-arg NEXT_PUBLIC_API_URL="$${NEXT_PUBLIC_API_URL}" \ + $(root_dir)/govtool/analytics-dashboard .PHONY: push-analytics-dashboard push-analytics-dashboard: build-analytics-dashboard From f3fe31c9fe72666237d68baa8640215b3a384e4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Sworze=C5=84?= Date: Mon, 29 Apr 2024 09:51:05 +0200 Subject: [PATCH 020/125] change way to add certs --- govtool/frontend/src/context/wallet.tsx | 59 +++++++------------ .../frontend/src/hooks/useDelegateToDrep.ts | 17 +++++- 2 files changed, 36 insertions(+), 40 deletions(-) diff --git a/govtool/frontend/src/context/wallet.tsx b/govtool/frontend/src/context/wallet.tsx index b9f8bfbf3..245762665 100644 --- a/govtool/frontend/src/context/wallet.tsx +++ b/govtool/frontend/src/context/wallet.tsx @@ -96,7 +96,7 @@ type TreasuryProps = { }; type BuildSignSubmitConwayCertTxArgs = { - certBuilder?: CertificatesBuilder; + certBuilder?: CertificatesBuilder | Certificate; govActionBuilder?: VotingProposalBuilder; votingBuilder?: VotingBuilder; voterDeposit?: string; @@ -128,18 +128,10 @@ interface CardanoContextType { votingBuilder, voterDeposit, }: BuildSignSubmitConwayCertTxArgs) => Promise; - buildDRepRegCert: ( - url?: string, - hash?: string, - ) => Promise; + buildDRepRegCert: (url?: string, hash?: string) => Promise; buildVoteDelegationCert: (vote: string) => Promise; - buildDRepUpdateCert: ( - url?: string, - hash?: string, - ) => Promise; - buildDRepRetirementCert: ( - voterDeposit: string, - ) => Promise; + buildDRepUpdateCert: (url?: string, hash?: string) => Promise; + buildDRepRetirementCert: (voterDeposit: string) => Promise; buildVote: ( voteChoice: string, txHash: string, @@ -445,7 +437,13 @@ const CardanoProvider = (props: Props) => { } if (certBuilder) { - txBuilder.set_certs_builder(certBuilder); + if (certBuilder instanceof Certificate) { + const builder = CertificatesBuilder.new(); + builder.add(certBuilder); + txBuilder.set_certs_builder(builder); + } else { + txBuilder.set_certs_builder(certBuilder); + } } if (votingBuilder) { @@ -473,7 +471,9 @@ const CardanoProvider = (props: Props) => { let outputValue = BigNum.from_str("1000000"); if ( - (type === "retireAsDrep" || type === "retireAsSoleVoter") && + (type === "retireAsDrep" || + type === "retireAsSoleVoter" || + type === "delegate") && voterDeposit ) { outputValue = outputValue.checked_add(BigNum.from_str(voterDeposit)); @@ -612,11 +612,8 @@ const CardanoProvider = (props: Props) => { async ( cip95MetadataURL?: string, cip95MetadataHash?: string, - ): Promise => { + ): Promise => { try { - // Build DRep Registration Certificate - const certBuilder = CertificatesBuilder.new(); - // Get wallet's DRep key const dRepKeyHash = Ed25519KeyHash.from_hex(dRepID); const dRepCred = Credential.from_keyhash(dRepKeyHash); @@ -638,9 +635,7 @@ const CardanoProvider = (props: Props) => { BigNum.from_str(`${epochParams.drep_deposit}`), ); } - // add cert to tbuilder - certBuilder.add(Certificate.new_drep_registration(dRepRegCert)); - return certBuilder; + return Certificate.new_drep_registration(dRepRegCert); } catch (e) { Sentry.captureException(e); console.error(e); @@ -650,16 +645,12 @@ const CardanoProvider = (props: Props) => { [epochParams, dRepID], ); - // conway alpha const buildDRepUpdateCert = useCallback( async ( cip95MetadataURL?: string, cip95MetadataHash?: string, - ): Promise => { + ): Promise => { try { - // Build DRep Registration Certificate - const certBuilder = CertificatesBuilder.new(); - // Get wallet's DRep key const dRepKeyHash = Ed25519KeyHash.from_hex(dRepID); const dRepCred = Credential.from_keyhash(dRepKeyHash); @@ -673,9 +664,7 @@ const CardanoProvider = (props: Props) => { } else { dRepUpdateCert = DrepUpdate.new(dRepCred); } - // add cert to tbuilder - certBuilder.add(Certificate.new_drep_update(dRepUpdateCert)); - return certBuilder; + return Certificate.new_drep_update(dRepUpdateCert); } catch (e) { Sentry.captureException(e); console.error(e); @@ -685,12 +674,9 @@ const CardanoProvider = (props: Props) => { [dRepID], ); - // conway alpha const buildDRepRetirementCert = useCallback( - async (voterDeposit: string): Promise => { + async (voterDeposit: string): Promise => { try { - // Build DRep Registration Certificate - const certBuilder = CertificatesBuilder.new(); // Get wallet's DRep key const dRepKeyHash = Ed25519KeyHash.from_hex(dRepID); const dRepCred = Credential.from_keyhash(dRepKeyHash); @@ -699,11 +685,8 @@ const CardanoProvider = (props: Props) => { dRepCred, BigNum.from_str(voterDeposit), ); - // add cert to tbuilder - certBuilder.add( - Certificate.new_drep_deregistration(dRepRetirementCert), - ); - return certBuilder; + + return Certificate.new_drep_deregistration(dRepRetirementCert); } catch (e) { Sentry.captureException(e); console.error(e); diff --git a/govtool/frontend/src/hooks/useDelegateToDrep.ts b/govtool/frontend/src/hooks/useDelegateToDrep.ts index 5a4394446..09d015976 100644 --- a/govtool/frontend/src/hooks/useDelegateToDrep.ts +++ b/govtool/frontend/src/hooks/useDelegateToDrep.ts @@ -1,13 +1,18 @@ import { useCallback, useState } from "react"; import * as Sentry from "@sentry/react"; -import { useTranslation, useWalletErrorModal } from "@hooks"; +import { useGetVoterInfo, useTranslation, useWalletErrorModal } from "@hooks"; import { useCardano, useSnackbar } from "@/context"; export const useDelegateTodRep = () => { - const { buildSignSubmitConwayCertTx, buildVoteDelegationCert } = useCardano(); + const { + buildSignSubmitConwayCertTx, + buildVoteDelegationCert, + buildDRepRetirementCert, + } = useCardano(); const { t } = useTranslation(); const { addSuccessAlert, addErrorAlert } = useSnackbar(); const openWalletErrorModal = useWalletErrorModal(); + const { voter } = useGetVoterInfo(); const [isDelegating, setIsDelegating] = useState(false); @@ -16,11 +21,19 @@ export const useDelegateTodRep = () => { if (!dRepId) return; setIsDelegating(true); try { + if (!voter?.deposit) { + throw new Error(t("errors.appCannotGetDeposit")); + } + const retirementCert = await buildDRepRetirementCert( + voter?.deposit?.toString(), + ); const certBuilder = await buildVoteDelegationCert(dRepId); + certBuilder.add(retirementCert); const result = await buildSignSubmitConwayCertTx({ certBuilder, type: "delegate", resourceId: dRepId, + voterDeposit: voter?.deposit?.toString(), }); if (result) { addSuccessAlert(t("alerts.delegate.success")); From c04c9c4ada0f279ae481b6f02fe66a5f69d77241 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Sworze=C5=84?= Date: Mon, 29 Apr 2024 11:57:15 +0200 Subject: [PATCH 021/125] change way to generate certs --- .../GovernanceActionDetailsCardLinks.tsx | 2 +- .../DashboardCards/DelegateDashboardCard.tsx | 6 ++---- .../WhatRetirementMeans.tsx | 2 +- govtool/frontend/src/context/wallet.tsx | 16 ++++++++------- .../frontend/src/hooks/useDelegateToDrep.ts | 20 ++++++++++++------- .../src/pages/RegisterAsSoleVoter.tsx | 14 ++++++++++--- .../frontend/src/pages/RetireAsSoleVoter.tsx | 2 +- 7 files changed, 38 insertions(+), 24 deletions(-) diff --git a/govtool/frontend/src/components/molecules/GovernanceActionDetailsCardLinks.tsx b/govtool/frontend/src/components/molecules/GovernanceActionDetailsCardLinks.tsx index 9dcd48dfe..c362db759 100644 --- a/govtool/frontend/src/components/molecules/GovernanceActionDetailsCardLinks.tsx +++ b/govtool/frontend/src/components/molecules/GovernanceActionDetailsCardLinks.tsx @@ -16,7 +16,7 @@ export const GovernanceActionDetailsCardLinks = ({ const { openModal } = useModal(); return ( - links && ( + !!links?.length && ( <> {displayedDelegationId && ( @@ -190,7 +188,7 @@ const getDisplayedDelegationId = ({ } if (!restrictedNames.includes(currentDelegation ?? "")) { - return formHexToBech32(currentDelegation ?? ""); + return currentDelegation ?? ""; } return undefined; }; diff --git a/govtool/frontend/src/components/organisms/RegisterAsDRepSteps/WhatRetirementMeans.tsx b/govtool/frontend/src/components/organisms/RegisterAsDRepSteps/WhatRetirementMeans.tsx index 4a95e2ddf..5b7db0914 100644 --- a/govtool/frontend/src/components/organisms/RegisterAsDRepSteps/WhatRetirementMeans.tsx +++ b/govtool/frontend/src/components/organisms/RegisterAsDRepSteps/WhatRetirementMeans.tsx @@ -47,7 +47,7 @@ export const WhatRetirementMeans = ({ const result = await buildSignSubmitConwayCertTx({ certBuilder, type: "retireAsDrep", - voterDeposit: voter?.deposit.toString(), + voter, }); if (result) { openModal({ diff --git a/govtool/frontend/src/context/wallet.tsx b/govtool/frontend/src/context/wallet.tsx index 245762665..eeea7683e 100644 --- a/govtool/frontend/src/context/wallet.tsx +++ b/govtool/frontend/src/context/wallet.tsx @@ -48,7 +48,7 @@ import * as Sentry from "@sentry/react"; import { Trans } from "react-i18next"; import { PATHS } from "@consts"; -import { CardanoApiWallet, Protocol } from "@models"; +import { CardanoApiWallet, Protocol, VoterInfo } from "@models"; import type { StatusModalState } from "@organisms"; import { checkIsMaintenanceOn, @@ -99,7 +99,7 @@ type BuildSignSubmitConwayCertTxArgs = { certBuilder?: CertificatesBuilder | Certificate; govActionBuilder?: VotingProposalBuilder; votingBuilder?: VotingBuilder; - voterDeposit?: string; + voter?: VoterInfo; } & ( | Pick | Pick @@ -126,7 +126,7 @@ interface CardanoContextType { resourceId, type, votingBuilder, - voterDeposit, + voter, }: BuildSignSubmitConwayCertTxArgs) => Promise; buildDRepRegCert: (url?: string, hash?: string) => Promise; buildVoteDelegationCert: (vote: string) => Promise; @@ -423,7 +423,7 @@ const CardanoProvider = (props: Props) => { resourceId, type, votingBuilder, - voterDeposit, + voter, }: BuildSignSubmitConwayCertTxArgs) => { await checkIsMaintenanceOn(); const isPendingTx = isPendingTransaction(); @@ -473,10 +473,12 @@ const CardanoProvider = (props: Props) => { if ( (type === "retireAsDrep" || type === "retireAsSoleVoter" || - type === "delegate") && - voterDeposit + (type === "delegate" && voter?.isRegisteredAsSoleVoter)) && + voter?.deposit ) { - outputValue = outputValue.checked_add(BigNum.from_str(voterDeposit)); + outputValue = outputValue.checked_add( + BigNum.from_str(voter?.deposit?.toString()), + ); } txBuilder.add_output( diff --git a/govtool/frontend/src/hooks/useDelegateToDrep.ts b/govtool/frontend/src/hooks/useDelegateToDrep.ts index 09d015976..718a17ef7 100644 --- a/govtool/frontend/src/hooks/useDelegateToDrep.ts +++ b/govtool/frontend/src/hooks/useDelegateToDrep.ts @@ -1,7 +1,8 @@ import { useCallback, useState } from "react"; import * as Sentry from "@sentry/react"; + +import { useCardano, useSnackbar } from "@context"; import { useGetVoterInfo, useTranslation, useWalletErrorModal } from "@hooks"; -import { useCardano, useSnackbar } from "@/context"; export const useDelegateTodRep = () => { const { @@ -21,19 +22,22 @@ export const useDelegateTodRep = () => { if (!dRepId) return; setIsDelegating(true); try { - if (!voter?.deposit) { + if (voter?.isRegisteredAsSoleVoter && !voter?.deposit) { throw new Error(t("errors.appCannotGetDeposit")); } - const retirementCert = await buildDRepRetirementCert( - voter?.deposit?.toString(), - ); + const certBuilder = await buildVoteDelegationCert(dRepId); - certBuilder.add(retirementCert); + if (voter?.isRegisteredAsSoleVoter) { + const retirementCert = await buildDRepRetirementCert( + voter?.deposit?.toString(), + ); + certBuilder.add(retirementCert); + } const result = await buildSignSubmitConwayCertTx({ certBuilder, type: "delegate", resourceId: dRepId, - voterDeposit: voter?.deposit?.toString(), + voter, }); if (result) { addSuccessAlert(t("alerts.delegate.success")); @@ -54,6 +58,8 @@ export const useDelegateTodRep = () => { buildSignSubmitConwayCertTx, buildVoteDelegationCert, t, + voter?.deposit, + voter?.isRegisteredAsSoleVoter, ], ); diff --git a/govtool/frontend/src/pages/RegisterAsSoleVoter.tsx b/govtool/frontend/src/pages/RegisterAsSoleVoter.tsx index ad387b4da..f90373921 100644 --- a/govtool/frontend/src/pages/RegisterAsSoleVoter.tsx +++ b/govtool/frontend/src/pages/RegisterAsSoleVoter.tsx @@ -30,17 +30,24 @@ export const RegisterAsSoleVoter = () => { const { isMobile } = useScreenDimension(); const { voter } = useGetVoterInfo(); const openWalletErrorModal = useWalletErrorModal(); - const { buildSignSubmitConwayCertTx, buildDRepRegCert, buildDRepUpdateCert } = - useCardano(); + const { + buildSignSubmitConwayCertTx, + buildDRepRegCert, + buildDRepUpdateCert, + buildVoteDelegationCert, + dRepID, + } = useCardano(); const { openModal, closeModal } = useModal(); const onRegister = useCallback(async () => { setIsLoading(true); try { - const certBuilder = voter?.isRegisteredAsDRep + const certBuilder = await buildVoteDelegationCert(dRepID); + const registerCert = voter?.isRegisteredAsDRep ? await buildDRepUpdateCert() : await buildDRepRegCert(); + certBuilder.add(registerCert); const result = await buildSignSubmitConwayCertTx({ certBuilder, type: "registerAsSoleVoter", @@ -76,6 +83,7 @@ export const RegisterAsSoleVoter = () => { }, [ buildSignSubmitConwayCertTx, buildDRepRegCert, + dRepID, openModal, voter?.isRegisteredAsDRep, ]); diff --git a/govtool/frontend/src/pages/RetireAsSoleVoter.tsx b/govtool/frontend/src/pages/RetireAsSoleVoter.tsx index 369575572..ab6ecda39 100644 --- a/govtool/frontend/src/pages/RetireAsSoleVoter.tsx +++ b/govtool/frontend/src/pages/RetireAsSoleVoter.tsx @@ -38,7 +38,7 @@ export const RetireAsSoleVoter = () => { const result = await buildSignSubmitConwayCertTx({ certBuilder, type: "retireAsSoleVoter", - voterDeposit: voter?.deposit?.toString(), + voter, }); if (result) { openModal({ From 6e096bf2aba2b9f7edbb798ea08a47832255d6ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Sworze=C5=84?= Date: Mon, 29 Apr 2024 12:01:22 +0200 Subject: [PATCH 022/125] delete unnecesary code --- .../organisms/RetireAsSoleVoterBox.tsx | 87 ------------------- .../organisms/RetireAsSoleVoterBoxContent.tsx | 42 --------- .../src/components/organisms/index.ts | 2 - 3 files changed, 131 deletions(-) delete mode 100644 govtool/frontend/src/components/organisms/RetireAsSoleVoterBox.tsx delete mode 100644 govtool/frontend/src/components/organisms/RetireAsSoleVoterBoxContent.tsx diff --git a/govtool/frontend/src/components/organisms/RetireAsSoleVoterBox.tsx b/govtool/frontend/src/components/organisms/RetireAsSoleVoterBox.tsx deleted file mode 100644 index d8acfa91e..000000000 --- a/govtool/frontend/src/components/organisms/RetireAsSoleVoterBox.tsx +++ /dev/null @@ -1,87 +0,0 @@ -import { useCallback, useState } from "react"; -import { useNavigate } from "react-router-dom"; -import { useTranslation } from "react-i18next"; - -import { PATHS } from "@consts"; -import { CenteredBoxBottomButtons } from "@molecules"; -import { useCardano, useModal } from "@context"; -import { RetireAsSoleVoterBoxContent } from "@organisms"; -import { useGetVoterInfo, useWalletErrorModal } from "@hooks"; - -export const RetireAsSoleVoterBox = () => { - const [isLoading, setIsLoading] = useState(false); - - const navigate = useNavigate(); - const { - buildDRepRetirementCert, - buildSignSubmitConwayCertTx, - isPendingTransaction, - } = useCardano(); - const { openModal, closeModal } = useModal(); - const { t } = useTranslation(); - const { voter } = useGetVoterInfo(); - const openWalletErrorModal = useWalletErrorModal(); - - const onRetire = useCallback(async () => { - try { - setIsLoading(true); - const isPendingTx = isPendingTransaction(); - if (isPendingTx) return; - if (!voter?.deposit) { - throw new Error(t("errors.appCannotGetDeposit")); - } - const certBuilder = await buildDRepRetirementCert( - voter?.deposit?.toString(), - ); - const result = await buildSignSubmitConwayCertTx({ - certBuilder, - type: "retireAsSoleVoter", - voterDeposit: voter?.deposit?.toString(), - }); - if (result) { - openModal({ - type: "statusModal", - state: { - status: "success", - title: t("modals.retirement.title"), - message: t("modals.retirement.message"), - link: `https://sancho.cexplorer.io/tx/${result}`, - buttonText: t("modals.common.goToDashboard"), - dataTestId: "retirement-transaction-submitted-modal", - onSubmit: () => { - navigate(PATHS.dashboard); - closeModal(); - }, - }, - }); - } - // eslint-disable-next-line @typescript-eslint/no-explicit-any - } catch (error: any) { - openWalletErrorModal({ - error, - buttonText: t("modals.common.goToDashboard"), - onSumbit: () => navigate(PATHS.dashboard), - dataTestId: "retirement-transaction-error-modal", - }); - } finally { - setIsLoading(false); - } - }, [ - buildDRepRetirementCert, - buildSignSubmitConwayCertTx, - isPendingTransaction, - openModal, - voter?.deposit, - ]); - - return ( - <> - - navigate(PATHS.dashboard)} - onActionButton={onRetire} - isLoading={isLoading} - /> - - ); -}; diff --git a/govtool/frontend/src/components/organisms/RetireAsSoleVoterBoxContent.tsx b/govtool/frontend/src/components/organisms/RetireAsSoleVoterBoxContent.tsx deleted file mode 100644 index 776b3b724..000000000 --- a/govtool/frontend/src/components/organisms/RetireAsSoleVoterBoxContent.tsx +++ /dev/null @@ -1,42 +0,0 @@ -import { Link } from "@mui/material"; -import { Trans } from "react-i18next"; - -import { Typography } from "@atoms"; -import { useGetVoterInfo, useScreenDimension, useTranslation } from "@hooks"; -import { correctAdaFormat, openInNewTab } from "@utils"; - -export const RetireAsSoleVoterBoxContent = () => { - const { isMobile } = useScreenDimension(); - const { t } = useTranslation(); - const { voter } = useGetVoterInfo(); - - return ( - <> - - {t("soleVoter.retirementHeading")} - - - openInNewTab("https://sancho.network/")} - sx={{ cursor: "pointer", textDecoration: "none" }} - key="0" - />, - ]} - /> - - - ); -}; diff --git a/govtool/frontend/src/components/organisms/index.ts b/govtool/frontend/src/components/organisms/index.ts index 298b66492..fbaf6231d 100644 --- a/govtool/frontend/src/components/organisms/index.ts +++ b/govtool/frontend/src/components/organisms/index.ts @@ -24,8 +24,6 @@ export * from "./HomeCards"; export * from "./RegisterAsDRepSteps"; export * from "./RegisterAsSoleVoterBox"; export * from "./RegisterAsSoleVoterBoxContent"; -export * from "./RetireAsSoleVoterBox"; -export * from "./RetireAsSoleVoterBoxContent"; export * from "./Slider"; export * from "./TopNav"; export * from "./VoteContext"; From 4d947b39d5755931353832bbcb23ebf442e8f204 Mon Sep 17 00:00:00 2001 From: weronika Date: Mon, 29 Apr 2024 22:55:21 +0200 Subject: [PATCH 023/125] change padding on buttons; remove LoadingButton and add isLoading props to Button --- .../frontend/src/components/atoms/Button.tsx | 15 +++++- .../components/atoms/LoadingButton.test.tsx | 53 ------------------- .../src/components/atoms/LoadingButton.tsx | 32 ----------- .../frontend/src/components/atoms/index.ts | 1 - .../frontend/src/components/atoms/types.ts | 1 + .../molecules/AutomatedVotingCard.tsx | 6 +-- .../molecules/CenteredBoxBottomButtons.tsx | 6 +-- .../molecules/DashboardActionCard.tsx | 4 +- .../components/molecules/VoteActionForm.tsx | 10 ++-- .../src/components/organisms/BgCard.tsx | 6 +-- govtool/frontend/src/pages/DRepDetails.tsx | 6 +-- .../frontend/src/stories/Button.stories.ts | 9 ++++ .../src/stories/LoadingButton.stories.tsx | 31 ----------- 13 files changed, 43 insertions(+), 137 deletions(-) delete mode 100644 govtool/frontend/src/components/atoms/LoadingButton.test.tsx delete mode 100644 govtool/frontend/src/components/atoms/LoadingButton.tsx delete mode 100644 govtool/frontend/src/stories/LoadingButton.stories.tsx diff --git a/govtool/frontend/src/components/atoms/Button.tsx b/govtool/frontend/src/components/atoms/Button.tsx index 5ce22bf48..d5ecf71e2 100644 --- a/govtool/frontend/src/components/atoms/Button.tsx +++ b/govtool/frontend/src/components/atoms/Button.tsx @@ -1,10 +1,11 @@ -import { Button as MUIButton } from "@mui/material"; +import { CircularProgress, Button as MUIButton } from "@mui/material"; import { ButtonProps } from "."; export const Button = ({ size = "large", variant = "contained", sx, + isLoading, ...props }: ButtonProps) => { const buttonHeight = { @@ -14,17 +15,29 @@ export const Button = ({ small: 32, }[size]; + const buttonPaddingHorizontal = { + extraLarge: 3.5, + large: 3.25, + medium: 3, + small: 3, + }[size]; + return ( + {isLoading && ( + + )} {props.children} ); diff --git a/govtool/frontend/src/components/atoms/LoadingButton.test.tsx b/govtool/frontend/src/components/atoms/LoadingButton.test.tsx deleted file mode 100644 index f6e543bd9..000000000 --- a/govtool/frontend/src/components/atoms/LoadingButton.test.tsx +++ /dev/null @@ -1,53 +0,0 @@ -import { describe, it, expect } from "vitest"; -import { render, screen } from "@testing-library/react"; -import { LoadingButton } from "@atoms"; - -describe("LoadingButton", () => { - it("renders its children", () => { - render(Click me); - expect(screen.getByText("Click me")).toBeInTheDocument(); - }); - - it("is disabled when isLoading is true", () => { - render(Loading...); - expect(screen.getByRole("button", { name: "Loading..." })).toBeDisabled(); - }); - - it("is disabled when disabled prop is true", () => { - render(Disabled); - expect(screen.getByRole("button", { name: "Disabled" })).toBeDisabled(); - }); - - it("shows a CircularProgress when isLoading", () => { - render(Loading...); - expect(screen.getByRole("progressbar")).toBeInTheDocument(); - }); - - it("applies different heights based on size prop", () => { - const { rerender } = render( - Small Button, - ); - - expect(screen.getByText("Small Button")).toHaveStyle({ height: "32px" }); - - rerender(Medium Button); - expect(screen.getByText("Medium Button")).toHaveStyle({ height: "36px" }); - - rerender(Large Button); - expect(screen.getByText("Large Button")).toHaveStyle({ height: "40px" }); - - rerender( - Extra Large Button, - ); - expect(screen.getByText("Extra Large Button")).toHaveStyle("height: 48px"); - }); - - it("applies custom styles via sx prop", () => { - const customStyles = { backgroundColor: "specialCyan" }; - render(Styled Button); - - expect(screen.getByText("Styled Button")).toHaveStyle({ - backgroundColor: "specialCyan", - }); - }); -}); diff --git a/govtool/frontend/src/components/atoms/LoadingButton.tsx b/govtool/frontend/src/components/atoms/LoadingButton.tsx deleted file mode 100644 index 11a22d56f..000000000 --- a/govtool/frontend/src/components/atoms/LoadingButton.tsx +++ /dev/null @@ -1,32 +0,0 @@ -import { Button, CircularProgress } from "@mui/material"; - -import { LoadingButtonProps } from "./types"; - -export const LoadingButton = ({ - isLoading, - disabled, - children, - size = "large", - sx, - ...rest -}: LoadingButtonProps) => { - const buttonHeight = { - extraLarge: 48, - large: 40, - medium: 36, - small: 32, - }[size]; - - return ( - - ); -}; diff --git a/govtool/frontend/src/components/atoms/index.ts b/govtool/frontend/src/components/atoms/index.ts index 4fe856a38..3e80b5f59 100644 --- a/govtool/frontend/src/components/atoms/index.ts +++ b/govtool/frontend/src/components/atoms/index.ts @@ -12,7 +12,6 @@ export * from "./HighlightedText"; export * from "./InfoText"; export * from "./Input"; export * from "./Link"; -export * from "./LoadingButton"; export * from "./modal/Modal"; export * from "./modal/ModalContents"; export * from "./modal/ModalHeader"; diff --git a/govtool/frontend/src/components/atoms/types.ts b/govtool/frontend/src/components/atoms/types.ts index 2a02f519b..94ab87d4f 100644 --- a/govtool/frontend/src/components/atoms/types.ts +++ b/govtool/frontend/src/components/atoms/types.ts @@ -10,6 +10,7 @@ import { import * as TooltipMUI from "@mui/material/Tooltip"; export type ButtonProps = Omit & { + isLoading?: boolean; size?: "small" | "medium" | "large" | "extraLarge"; dataTestId?: string; }; diff --git a/govtool/frontend/src/components/molecules/AutomatedVotingCard.tsx b/govtool/frontend/src/components/molecules/AutomatedVotingCard.tsx index 7734f9f30..ec1d75171 100644 --- a/govtool/frontend/src/components/molecules/AutomatedVotingCard.tsx +++ b/govtool/frontend/src/components/molecules/AutomatedVotingCard.tsx @@ -1,6 +1,6 @@ import { Box, Divider } from "@mui/material"; -import { Button, LoadingButton, Typography } from "@atoms"; +import { Button, Typography } from "@atoms"; import { primaryBlue } from "@consts"; import { useModal } from "@context"; import { useScreenDimension, useTranslation } from "@hooks"; @@ -141,7 +141,7 @@ export const AutomatedVotingCard = ({ ) : ( !isSelected && ( - {t("delegate")} - + ) )} diff --git a/govtool/frontend/src/components/molecules/CenteredBoxBottomButtons.tsx b/govtool/frontend/src/components/molecules/CenteredBoxBottomButtons.tsx index 101787797..7c93938c4 100644 --- a/govtool/frontend/src/components/molecules/CenteredBoxBottomButtons.tsx +++ b/govtool/frontend/src/components/molecules/CenteredBoxBottomButtons.tsx @@ -1,7 +1,7 @@ import { useMemo } from "react"; import { Box } from "@mui/material"; -import { Button, LoadingButton } from "@atoms"; +import { Button } from "@atoms"; import { useScreenDimension, useTranslation } from "@hooks"; interface Props { @@ -41,7 +41,7 @@ export const CenteredBoxBottomButtons = ({ const renderActionButton = useMemo( () => ( - {actionButtonText ?? t("continue")} - + ), [isLoading, isMobile], ); diff --git a/govtool/frontend/src/components/molecules/DashboardActionCard.tsx b/govtool/frontend/src/components/molecules/DashboardActionCard.tsx index a3d127e56..243287f36 100644 --- a/govtool/frontend/src/components/molecules/DashboardActionCard.tsx +++ b/govtool/frontend/src/components/molecules/DashboardActionCard.tsx @@ -1,7 +1,7 @@ import { Box, Skeleton } from "@mui/material"; import { FC, ReactNode } from "react"; -import { Button, LoadingButton, LoadingButtonProps, Typography } from "@atoms"; +import { Button, LoadingButtonProps, Typography } from "@atoms"; import { useScreenDimension, useTranslation } from "@hooks"; import { openInNewTab } from "@utils"; @@ -141,7 +141,7 @@ export const DashboardActionCard: FC = ({ ) : ( buttons?.map(({ dataTestId, ...buttonProps }) => ( - ( - {t("govActions.changeVote")} - + ), [confirmVote, areFormErrors, vote, isVoteLoading], ); @@ -372,7 +372,7 @@ export const VoteActionForm = ({ {isMobile ? renderCancelButton : renderChangeVoteButton} ) : ( - {t("govActions.vote")} - + )} ); diff --git a/govtool/frontend/src/components/organisms/BgCard.tsx b/govtool/frontend/src/components/organisms/BgCard.tsx index 748674365..5d2a3b1f3 100644 --- a/govtool/frontend/src/components/organisms/BgCard.tsx +++ b/govtool/frontend/src/components/organisms/BgCard.tsx @@ -2,7 +2,7 @@ import { useCallback, useMemo } from "react"; import { useNavigate } from "react-router-dom"; import { Box } from "@mui/material"; -import { Button, LoadingButton } from "@atoms"; +import { Button } from "@atoms"; import { PATHS } from "@consts"; import { useScreenDimension, useTranslation } from "@hooks"; import { theme } from "@/theme"; @@ -50,7 +50,7 @@ export const BgCard = ({ const renderContinueButton = useMemo( () => ( - {actionButtonLabel} - + ), [ actionButtonLabel, diff --git a/govtool/frontend/src/pages/DRepDetails.tsx b/govtool/frontend/src/pages/DRepDetails.tsx index 1734fb7a7..f33a20880 100644 --- a/govtool/frontend/src/pages/DRepDetails.tsx +++ b/govtool/frontend/src/pages/DRepDetails.tsx @@ -2,7 +2,7 @@ import { PropsWithChildren } from "react"; import { Navigate, useNavigate, useParams } from "react-router-dom"; import { Box, ButtonBase, Chip, CircularProgress } from "@mui/material"; -import { Button, LoadingButton, StatusPill, Typography } from "@atoms"; +import { Button, StatusPill, Typography } from "@atoms"; import { ICONS, PATHS } from "@consts"; import { useCardano, useModal } from "@context"; import { @@ -185,7 +185,7 @@ export const DRepDetails = ({ isConnected }: DRepDetailsProps) => { }} > {isConnected && status === "Active" && !isMyDrep && ( - { variant="contained" > {t("delegate")} - + )} {!isConnected && status === "Active" && ( + {type === "DRep" && ( + + )} {status === "Active" && isConnected && onDelegate && From 5927c45efd9616fdf0771d67698e3cfd3ed2006d Mon Sep 17 00:00:00 2001 From: weronika Date: Tue, 30 Apr 2024 12:40:48 +0200 Subject: [PATCH 029/125] change padding on chip in DRepCard --- govtool/frontend/src/components/atoms/StatusPill.tsx | 12 +++++++++++- .../frontend/src/components/organisms/DRepCard.tsx | 2 +- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/govtool/frontend/src/components/atoms/StatusPill.tsx b/govtool/frontend/src/components/atoms/StatusPill.tsx index ae35d1190..70b789c6c 100644 --- a/govtool/frontend/src/components/atoms/StatusPill.tsx +++ b/govtool/frontend/src/components/atoms/StatusPill.tsx @@ -15,7 +15,17 @@ export const StatusPill = ({ size = "small", sx, }: StatusPillProps) => ( - + ); const bgColor = { diff --git a/govtool/frontend/src/components/organisms/DRepCard.tsx b/govtool/frontend/src/components/organisms/DRepCard.tsx index 6ba6b201c..cd4d6d34d 100644 --- a/govtool/frontend/src/components/organisms/DRepCard.tsx +++ b/govtool/frontend/src/components/organisms/DRepCard.tsx @@ -128,7 +128,7 @@ export const DRepCard = ({ > {t("status")} - + From c69b157149a91bc82aa7fa19ff0a89246c846bdf Mon Sep 17 00:00:00 2001 From: weronika Date: Tue, 30 Apr 2024 15:42:56 +0200 Subject: [PATCH 030/125] align items in drep card and change format of numbers; change position of yourself chip --- .../src/components/atoms/StatusPill.tsx | 9 +++-- .../src/components/organisms/DRepCard.tsx | 33 +++++++++++++------ govtool/frontend/src/models/api.ts | 1 + govtool/frontend/src/utils/adaFormat.ts | 8 +++++ .../src/utils/tests/adaFormat.test.ts | 16 ++++++++- 5 files changed, 54 insertions(+), 13 deletions(-) diff --git a/govtool/frontend/src/components/atoms/StatusPill.tsx b/govtool/frontend/src/components/atoms/StatusPill.tsx index ae35d1190..91df7913e 100644 --- a/govtool/frontend/src/components/atoms/StatusPill.tsx +++ b/govtool/frontend/src/components/atoms/StatusPill.tsx @@ -1,6 +1,7 @@ import { Chip, ChipProps, styled } from "@mui/material"; import { cyan, errorRed, successGreen } from "@/consts"; import { DRepStatus } from "@/models"; +import { theme } from "@/theme"; interface StatusPillProps { status: DRepStatus; @@ -22,20 +23,24 @@ const bgColor = { [DRepStatus.Active]: successGreen.c200, [DRepStatus.Inactive]: errorRed.c100, [DRepStatus.Retired]: cyan.c100, + [DRepStatus.Yourself]: theme.palette.lightBlue, }; const textColor = { [DRepStatus.Active]: successGreen.c700, [DRepStatus.Inactive]: errorRed.c500, [DRepStatus.Retired]: cyan.c500, + [DRepStatus.Yourself]: theme.palette.textBlack, }; const StyledChip = styled(Chip)<{ status: DRepStatus }>( - ({ theme, status }) => ({ + ({ theme: themeStyles, status }) => ({ backgroundColor: bgColor[status], color: textColor[status], - border: `2px solid ${theme.palette.neutralWhite}`, fontSize: "0.75rem", textTransform: "capitalize", + ...(status !== DRepStatus.Yourself && { + border: `2px solid ${themeStyles.palette.neutralWhite}`, + }), }), ); diff --git a/govtool/frontend/src/components/organisms/DRepCard.tsx b/govtool/frontend/src/components/organisms/DRepCard.tsx index 6ba6b201c..b3a8b618e 100644 --- a/govtool/frontend/src/components/organisms/DRepCard.tsx +++ b/govtool/frontend/src/components/organisms/DRepCard.tsx @@ -5,9 +5,9 @@ import { Button, StatusPill, Typography } from "@atoms"; import { ICONS, PATHS } from "@consts"; import { useModal, useSnackbar } from "@context"; import { useTranslation } from "@hooks"; -import { DRepData } from "@models"; +import { DRepData, DRepStatus } from "@models"; import { Card } from "@molecules"; -import { correctAdaFormat } from "@utils"; +import { correctDRepDirectoryFormat } from "@utils"; type DRepCardProps = { dRep: DRepData; @@ -44,7 +44,6 @@ export const DRepCard = ({ + {isMe && ( + + )} - + {type} - + - ₳ {correctAdaFormat(votingPower)} + ₳ {correctDRepDirectoryFormat(votingPower)} {t("status")} - + + + {isMe && ( + + )} + @@ -136,12 +149,12 @@ export const DRepCard = ({ diff --git a/govtool/frontend/src/models/api.ts b/govtool/frontend/src/models/api.ts index ba1b2eb28..cb2d700ad 100644 --- a/govtool/frontend/src/models/api.ts +++ b/govtool/frontend/src/models/api.ts @@ -16,6 +16,7 @@ export enum DRepStatus { Active = "Active", Inactive = "Inactive", Retired = "Retired", + Yourself = "Yourself", } export enum DRepListSort { diff --git a/govtool/frontend/src/utils/adaFormat.ts b/govtool/frontend/src/utils/adaFormat.ts index 269b0f307..43664103e 100644 --- a/govtool/frontend/src/utils/adaFormat.ts +++ b/govtool/frontend/src/utils/adaFormat.ts @@ -7,3 +7,11 @@ export const correctAdaFormat = (lovelace: number | undefined) => { } return 0; }; + +export const correctDRepDirectoryFormat = (lovelace: number | undefined) => { + if (lovelace) { + return Number((lovelace / LOVELACE).toFixed(0))?.toLocaleString("en-US"); + } + + return 0; +}; diff --git a/govtool/frontend/src/utils/tests/adaFormat.test.ts b/govtool/frontend/src/utils/tests/adaFormat.test.ts index 79d8c0f3b..8693c55f4 100644 --- a/govtool/frontend/src/utils/tests/adaFormat.test.ts +++ b/govtool/frontend/src/utils/tests/adaFormat.test.ts @@ -1,4 +1,4 @@ -import { correctAdaFormat } from ".."; +import { correctAdaFormat, correctDRepDirectoryFormat } from ".."; describe("correctAdaFormat", () => { const LOVELACE = 1000000; @@ -34,3 +34,17 @@ describe("correctAdaFormat", () => { expect(correctAdaFormat(lovelace)).toBe(0); }); }); + +describe("correctDRepDirectoryFormat", () => { + test("Correctly formats lovelace value to directory format", () => { + const lovelace = 143500000000; + const expectedResult = "143,500"; + expect(correctDRepDirectoryFormat(lovelace)).toBe(expectedResult); + }); + + test("Returns 0 for undefined input", () => { + const lovelace = undefined; + const expectedResult = "0"; + expect(correctDRepDirectoryFormat(lovelace)).toBe(expectedResult); + }); +}); From 37ded5d1f5f4e1032ff536650c8630170efbb5e6 Mon Sep 17 00:00:00 2001 From: weronika Date: Tue, 30 Apr 2024 15:56:29 +0200 Subject: [PATCH 031/125] change naming of consts in button --- govtool/frontend/src/components/atoms/Button.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/govtool/frontend/src/components/atoms/Button.tsx b/govtool/frontend/src/components/atoms/Button.tsx index d5ecf71e2..3bfb290fd 100644 --- a/govtool/frontend/src/components/atoms/Button.tsx +++ b/govtool/frontend/src/components/atoms/Button.tsx @@ -8,14 +8,14 @@ export const Button = ({ isLoading, ...props }: ButtonProps) => { - const buttonHeight = { + const height = { extraLarge: 48, large: 40, medium: 36, small: 32, }[size]; - const buttonPaddingHorizontal = { + const px = { extraLarge: 3.5, large: 3.25, medium: 3, @@ -27,8 +27,8 @@ export const Button = ({ disabled={isLoading || props?.disabled} sx={{ fontSize: size === "extraLarge" ? 16 : 14, - height: buttonHeight, - px: buttonPaddingHorizontal, + height, + px, whiteSpace: "nowrap", ...sx, }} From 50744ce1fa7e7912748a7861477acacf3fc53552 Mon Sep 17 00:00:00 2001 From: weronika Date: Tue, 30 Apr 2024 16:03:14 +0200 Subject: [PATCH 032/125] change px to smaller --- govtool/frontend/src/components/atoms/StatusPill.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/govtool/frontend/src/components/atoms/StatusPill.tsx b/govtool/frontend/src/components/atoms/StatusPill.tsx index 70b789c6c..df17ea51f 100644 --- a/govtool/frontend/src/components/atoms/StatusPill.tsx +++ b/govtool/frontend/src/components/atoms/StatusPill.tsx @@ -20,7 +20,7 @@ export const StatusPill = ({ size={size} label={label} sx={{ - px: 1.5, + px: 0.5, py: 0.5, height: 24, ...sx, From 5163e472e8c873628242e4e7614cdab6238e3862 Mon Sep 17 00:00:00 2001 From: weronika Date: Tue, 30 Apr 2024 16:12:41 +0200 Subject: [PATCH 033/125] fix tests --- govtool/frontend/src/utils/adaFormat.ts | 2 +- govtool/frontend/src/utils/tests/adaFormat.test.ts | 8 +++++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/govtool/frontend/src/utils/adaFormat.ts b/govtool/frontend/src/utils/adaFormat.ts index 43664103e..d76cdd7d7 100644 --- a/govtool/frontend/src/utils/adaFormat.ts +++ b/govtool/frontend/src/utils/adaFormat.ts @@ -13,5 +13,5 @@ export const correctDRepDirectoryFormat = (lovelace: number | undefined) => { return Number((lovelace / LOVELACE).toFixed(0))?.toLocaleString("en-US"); } - return 0; + return "0"; }; diff --git a/govtool/frontend/src/utils/tests/adaFormat.test.ts b/govtool/frontend/src/utils/tests/adaFormat.test.ts index 8693c55f4..688b8d12a 100644 --- a/govtool/frontend/src/utils/tests/adaFormat.test.ts +++ b/govtool/frontend/src/utils/tests/adaFormat.test.ts @@ -42,7 +42,13 @@ describe("correctDRepDirectoryFormat", () => { expect(correctDRepDirectoryFormat(lovelace)).toBe(expectedResult); }); - test("Returns 0 for undefined input", () => { + test("Returns 0 for numbers smaller than one million", () => { + const lovelace = 143; + const expectedResult = "0"; + expect(correctDRepDirectoryFormat(lovelace)).toBe(expectedResult); + }); + + test("Returns result without comma", () => { const lovelace = undefined; const expectedResult = "0"; expect(correctDRepDirectoryFormat(lovelace)).toBe(expectedResult); From a3dbac6c263f8212ee5b7485462122efc0e0eb9a Mon Sep 17 00:00:00 2001 From: weronika Date: Tue, 30 Apr 2024 16:57:22 +0200 Subject: [PATCH 034/125] add other number to test --- govtool/frontend/src/utils/tests/adaFormat.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/govtool/frontend/src/utils/tests/adaFormat.test.ts b/govtool/frontend/src/utils/tests/adaFormat.test.ts index 688b8d12a..cbd125f52 100644 --- a/govtool/frontend/src/utils/tests/adaFormat.test.ts +++ b/govtool/frontend/src/utils/tests/adaFormat.test.ts @@ -43,7 +43,7 @@ describe("correctDRepDirectoryFormat", () => { }); test("Returns 0 for numbers smaller than one million", () => { - const lovelace = 143; + const lovelace = 1435; const expectedResult = "0"; expect(correctDRepDirectoryFormat(lovelace)).toBe(expectedResult); }); From d868fe985ad7a189f9b5c5318390cb1281a4fe19 Mon Sep 17 00:00:00 2001 From: Sudip Bhattarai Date: Mon, 29 Apr 2024 17:23:04 +0545 Subject: [PATCH 035/125] Add metadata api for tests --- tests/test-metadata-api/.dockerignore | 3 + tests/test-metadata-api/.gitignore | 2 + tests/test-metadata-api/Dockerfile | 8 ++ tests/test-metadata-api/README.md | 35 ++++++++ tests/test-metadata-api/index.js | 110 ++++++++++++++++++++++++++ 5 files changed, 158 insertions(+) create mode 100644 tests/test-metadata-api/.dockerignore create mode 100644 tests/test-metadata-api/.gitignore create mode 100644 tests/test-metadata-api/Dockerfile create mode 100644 tests/test-metadata-api/README.md create mode 100644 tests/test-metadata-api/index.js diff --git a/tests/test-metadata-api/.dockerignore b/tests/test-metadata-api/.dockerignore new file mode 100644 index 000000000..7501e1983 --- /dev/null +++ b/tests/test-metadata-api/.dockerignore @@ -0,0 +1,3 @@ +json_files +Dockerfile +README.md \ No newline at end of file diff --git a/tests/test-metadata-api/.gitignore b/tests/test-metadata-api/.gitignore new file mode 100644 index 000000000..995da051a --- /dev/null +++ b/tests/test-metadata-api/.gitignore @@ -0,0 +1,2 @@ +json_files +node_modules \ No newline at end of file diff --git a/tests/test-metadata-api/Dockerfile b/tests/test-metadata-api/Dockerfile new file mode 100644 index 000000000..3e589c8ea --- /dev/null +++ b/tests/test-metadata-api/Dockerfile @@ -0,0 +1,8 @@ +FROM node:18-alpine +WORKDIR /src +COPY package.json yarn.lock ./ +RUN yarn install +COPY . . +VOLUME /data +EXPOSE 3000 +CMD [ "yarn", "start"] \ No newline at end of file diff --git a/tests/test-metadata-api/README.md b/tests/test-metadata-api/README.md new file mode 100644 index 000000000..a876a802e --- /dev/null +++ b/tests/test-metadata-api/README.md @@ -0,0 +1,35 @@ +Test medatada API +================= + +Simple service to host json metadata during testing. + +## Installation + +``` +git clone https://github.com/your/repository.git +yarn install +yarn start +``` +#### Swagger UI + +``` +http://localhost:3000/docs +``` + + +## Available Endpoints + +### Save File + +- **Endpoint:** `PUT /data/{filename}` +- **Description:** Saves data to a file with the specified filename. + +### Get File + +- **Endpoint:** `GET /data/{filename}` +- **Description:** Retrieves the content of the file with the specified filename. + +### Delete File + +- **Endpoint:** `DELETE /data/{filename}` +- **Description:** Deletes the file with the specified filename. \ No newline at end of file diff --git a/tests/test-metadata-api/index.js b/tests/test-metadata-api/index.js new file mode 100644 index 000000000..08e7c8dc7 --- /dev/null +++ b/tests/test-metadata-api/index.js @@ -0,0 +1,110 @@ +const express = require('express'); +const fs = require('fs'); +const path = require('path'); +const swaggerUi = require('swagger-ui-express'); +const swaggerJsdoc = require('swagger-jsdoc'); + +const app = express(); + + +const dataDir = process.env.DATA_DIR || path.join(__dirname, 'json_files'); + +if (!fs.existsSync(dataDir)) { + fs.mkdirSync(dataDir, { recursive: true }); +} +// Middleware to parse text request bodies +app.use(express.text()); + +// Swagger configuration +const swaggerOptions = { + definition: { + openapi: '3.0.0', + info: { + title: 'File API', + version: '1.0.0', + description: 'API for saving and deleting files', + }, + }, + apis: ['index.js'], // Update the path to reflect the compiled JavaScript file +}; + +const swaggerSpec = swaggerJsdoc(swaggerOptions); + +// Serve Swagger UI +app.use('/docs', swaggerUi.serve, swaggerUi.setup(swaggerSpec)); + +// PUT endpoint to save a file +/** + * @swagger + * /data/{filename}: + * put: + * summary: Save data to a file + * parameters: + * - in: path + * name: filename + * schema: + * type: string + * required: true + * description: The name of the file to save + * requestBody: + * required: true + * content: + * text/plain: + * schema: + * type: string + * responses: + * '201': + * description: File saved successfully + */ +app.put('/data/:filename', (req, res) => { + const filename = req.params.filename; + const filePath = path.join(dataDir, filename); + + fs.writeFile(filePath, req.body, (err) => { + if (err) { + console.error(err); + return res.status(500).send('Failed to save file'); + } + res.status(201).send({'success': true}); + }); +}); + + +// DELETE endpoint to delete a file +/** + * @swagger + * /data/{filename}: + * delete: + * summary: Delete a file + * parameters: + * - in: path + * name: filename + * schema: + * type: string + * required: true + * description: The name of the file to delete + * responses: + * '200': + * description: File deleted successfully + */ +app.delete('/data/:filename', (req, res) => { + const filename = req.params.filename; + const filePath = path.join(dataDir, filename); + + fs.unlink(filePath, (err) => { + if (err) { + console.error(err); + return res.status(500).send({'message':'Failed to delete file'}); + } + res.send('File deleted successfully'); + }); +}); + +// Serve the directory where the files are saved +app.use('/json_files', express.static(dataDir)); + +// Start the server +const PORT = process.env.PORT || 3000; +app.listen(PORT, () => { + console.log(`Server is running on port ${PORT}`); +}); From 68edfe8194dfed7fd68dd435ec0e025bc9e8f332 Mon Sep 17 00:00:00 2001 From: Sudip Bhattarai Date: Thu, 2 May 2024 10:47:54 +0545 Subject: [PATCH 036/125] Add locks api --- .gitignore | 4 + tests/test-metadata-api/Dockerfile | 1 + tests/test-metadata-api/README.md | 26 +- tests/test-metadata-api/index.js | 51 +- tests/test-metadata-api/locks_api.js | 79 ++++ tests/test-metadata-api/package.json | 14 + tests/test-metadata-api/yarn.lock | 678 +++++++++++++++++++++++++++ 7 files changed, 841 insertions(+), 12 deletions(-) create mode 100644 tests/test-metadata-api/locks_api.js create mode 100644 tests/test-metadata-api/package.json create mode 100644 tests/test-metadata-api/yarn.lock diff --git a/.gitignore b/.gitignore index 2bad55163..ce63fca47 100644 --- a/.gitignore +++ b/.gitignore @@ -139,3 +139,7 @@ scripts/govtool/dev-postgres_password # nodejs/yarn node_modules + + +# sonar scanner +.scannerwork/ \ No newline at end of file diff --git a/tests/test-metadata-api/Dockerfile b/tests/test-metadata-api/Dockerfile index 3e589c8ea..b30a1fd6b 100644 --- a/tests/test-metadata-api/Dockerfile +++ b/tests/test-metadata-api/Dockerfile @@ -4,5 +4,6 @@ COPY package.json yarn.lock ./ RUN yarn install COPY . . VOLUME /data +ENV DATA_DIR=/data EXPOSE 3000 CMD [ "yarn", "start"] \ No newline at end of file diff --git a/tests/test-metadata-api/README.md b/tests/test-metadata-api/README.md index a876a802e..3a98a748b 100644 --- a/tests/test-metadata-api/README.md +++ b/tests/test-metadata-api/README.md @@ -1,4 +1,4 @@ -Test medatada API +Test metadata API ================= Simple service to host json metadata during testing. @@ -16,20 +16,32 @@ yarn start http://localhost:3000/docs ``` +## Metadata Endpoints -## Available Endpoints - -### Save File +### 1. Save File - **Endpoint:** `PUT /data/{filename}` - **Description:** Saves data to a file with the specified filename. -### Get File +### 2. Get File - **Endpoint:** `GET /data/{filename}` - **Description:** Retrieves the content of the file with the specified filename. -### Delete File +### 3. Delete File - **Endpoint:** `DELETE /data/{filename}` -- **Description:** Deletes the file with the specified filename. \ No newline at end of file +- **Description:** Deletes the file with the specified filename. + +## Locks Endpoint +### 1. Acquire Lock +- **Endpoint:** `POST /lock/{key}?expiry={expiry_secs}` +- **Description:** Acquire a lock for the specified key for given time. By default the lock is set for 180 secs. +- **Responses:** + - `200 OK`: Lock acquired successfully. + - `423 Locked`: Lock not available. + +### 2. Release Lock + +- **Endpoint:** `POST/unlock/{key}` +- **Description:** Release a lock for the specified key. diff --git a/tests/test-metadata-api/index.js b/tests/test-metadata-api/index.js index 08e7c8dc7..b689ac0f1 100644 --- a/tests/test-metadata-api/index.js +++ b/tests/test-metadata-api/index.js @@ -1,9 +1,10 @@ const express = require('express'); const fs = require('fs'); const path = require('path'); +const lock_api = require('./locks_api') + const swaggerUi = require('swagger-ui-express'); const swaggerJsdoc = require('swagger-jsdoc'); - const app = express(); @@ -25,7 +26,7 @@ const swaggerOptions = { description: 'API for saving and deleting files', }, }, - apis: ['index.js'], // Update the path to reflect the compiled JavaScript file + apis: ['index.js','locks_api.js'], // Update the path to reflect the compiled JavaScript file }; const swaggerSpec = swaggerJsdoc(swaggerOptions); @@ -39,6 +40,7 @@ app.use('/docs', swaggerUi.serve, swaggerUi.setup(swaggerSpec)); * /data/{filename}: * put: * summary: Save data to a file + * tags: [Metadata File] * parameters: * - in: path * name: filename @@ -70,12 +72,50 @@ app.put('/data/:filename', (req, res) => { }); +// GET endpoint to retrieve a file +/** + * @swagger + * /data/{filename}: + * get: + * summary: Get a file + * tags: [Metadata File] + * parameters: + * - in: path + * name: filename + * schema: + * type: string + * required: true + * description: The name of the file to retrieve + * responses: + * '200': + * description: File retrieved successfully + * content: + * text/plain: + * schema: + * type: string + */ +app.get('/data/:filename', (req, res) => { + const filename = req.params.filename; + const filePath = path.join(dataDir, filename); + + fs.readFile(filePath, 'utf8', (err, data) => { + if (err) { + console.error(err); + return res.status(404).send({'message': 'File not found'}); + } + res.status(200).send(data); + }); +}); + + + // DELETE endpoint to delete a file /** * @swagger * /data/{filename}: * delete: * summary: Delete a file + * tags: [Metadata File] * parameters: * - in: path * name: filename @@ -100,9 +140,10 @@ app.delete('/data/:filename', (req, res) => { }); }); -// Serve the directory where the files are saved -app.use('/json_files', express.static(dataDir)); - +app.get('/', (req, res) => { + res.redirect('/docs'); +}); +lock_api.setup(app) // Start the server const PORT = process.env.PORT || 3000; app.listen(PORT, () => { diff --git a/tests/test-metadata-api/locks_api.js b/tests/test-metadata-api/locks_api.js new file mode 100644 index 000000000..9ad9a4a43 --- /dev/null +++ b/tests/test-metadata-api/locks_api.js @@ -0,0 +1,79 @@ +const lock = {}; + +function acquireLock(key) { + return new Promise((resolve, reject) => { + if (!lock[key]) { + lock[key] = true; + resolve(); + } else { + reject({ status: 423, message: 'Lock not available' }); + } + }); +} + +function releaseLock(key) { + lock[key] = false; +} + +function setup(app) { + /** + * @swagger + * tags: + * name: Locks + * description: API endpoints for managing locks + */ + + /** + * @swagger + * /lock/{key}: + * post: + * summary: Acquire lock + * tags: [Locks] + * parameters: + * - in: path + * name: key + * schema: + * type: string + * required: true + * description: The key of the lock to acquire + * responses: + * '200': + * description: Lock acquired successfully + * '423': + * description: Lock not available + */ + app.post('/lock/:key', async (req, res) => { + const key = req.params.key; + try { + await acquireLock(key); + res.send('Lock acquired.'); + } catch (error) { + res.status(error.status).send(error.message); + } + }); + + /** + * @swagger + * /unlock/{key}: + * post: + * summary: Release lock + * tags: [Locks] + * parameters: + * - in: path + * name: key + * schema: + * type: string + * required: true + * description: The key of the lock to release + * responses: + * '200': + * description: Lock released successfully + */ + app.post('/unlock/:key', (req, res) => { + const key = req.params.key; + releaseLock(key); + res.send('Lock released.'); + }); +} + +module.exports.setup = setup; diff --git a/tests/test-metadata-api/package.json b/tests/test-metadata-api/package.json new file mode 100644 index 000000000..408c3f036 --- /dev/null +++ b/tests/test-metadata-api/package.json @@ -0,0 +1,14 @@ +{ + "name": "test-metadata-api", + "version": "0.0.1", + "main": "index.js", + "license": "MIT", + "scripts": { + "start": "node index.js" + }, + "dependencies": { + "express": "^4.19.2", + "swagger-jsdoc": "^6.2.8", + "swagger-ui-express": "^5.0.0" + } +} \ No newline at end of file diff --git a/tests/test-metadata-api/yarn.lock b/tests/test-metadata-api/yarn.lock new file mode 100644 index 000000000..a23104223 --- /dev/null +++ b/tests/test-metadata-api/yarn.lock @@ -0,0 +1,678 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@apidevtools/json-schema-ref-parser@^9.0.6": + version "9.1.2" + resolved "https://registry.yarnpkg.com/@apidevtools/json-schema-ref-parser/-/json-schema-ref-parser-9.1.2.tgz#8ff5386b365d4c9faa7c8b566ff16a46a577d9b8" + integrity sha512-r1w81DpR+KyRWd3f+rk6TNqMgedmAxZP5v5KWlXQWlgMUUtyEJch0DKEci1SorPMiSeM8XPl7MZ3miJ60JIpQg== + dependencies: + "@jsdevtools/ono" "^7.1.3" + "@types/json-schema" "^7.0.6" + call-me-maybe "^1.0.1" + js-yaml "^4.1.0" + +"@apidevtools/openapi-schemas@^2.0.4": + version "2.1.0" + resolved "https://registry.yarnpkg.com/@apidevtools/openapi-schemas/-/openapi-schemas-2.1.0.tgz#9fa08017fb59d80538812f03fc7cac5992caaa17" + integrity sha512-Zc1AlqrJlX3SlpupFGpiLi2EbteyP7fXmUOGup6/DnkRgjP9bgMM/ag+n91rsv0U1Gpz0H3VILA/o3bW7Ua6BQ== + +"@apidevtools/swagger-methods@^3.0.2": + version "3.0.2" + resolved "https://registry.yarnpkg.com/@apidevtools/swagger-methods/-/swagger-methods-3.0.2.tgz#b789a362e055b0340d04712eafe7027ddc1ac267" + integrity sha512-QAkD5kK2b1WfjDS/UQn/qQkbwF31uqRjPTrsCs5ZG9BQGAkjwvqGFjjPqAuzac/IYzpPtRzjCP1WrTuAIjMrXg== + +"@apidevtools/swagger-parser@10.0.3": + version "10.0.3" + resolved "https://registry.yarnpkg.com/@apidevtools/swagger-parser/-/swagger-parser-10.0.3.tgz#32057ae99487872c4dd96b314a1ab4b95d89eaf5" + integrity sha512-sNiLY51vZOmSPFZA5TF35KZ2HbgYklQnTSDnkghamzLb3EkNtcQnrBQEj5AOCxHpTtXpqMCRM1CrmV2rG6nw4g== + dependencies: + "@apidevtools/json-schema-ref-parser" "^9.0.6" + "@apidevtools/openapi-schemas" "^2.0.4" + "@apidevtools/swagger-methods" "^3.0.2" + "@jsdevtools/ono" "^7.1.3" + call-me-maybe "^1.0.1" + z-schema "^5.0.1" + +"@jsdevtools/ono@^7.1.3": + version "7.1.3" + resolved "https://registry.yarnpkg.com/@jsdevtools/ono/-/ono-7.1.3.tgz#9df03bbd7c696a5c58885c34aa06da41c8543796" + integrity sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg== + +"@types/json-schema@^7.0.6": + version "7.0.15" + resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841" + integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA== + +accepts@~1.3.8: + version "1.3.8" + resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.8.tgz#0bf0be125b67014adcb0b0921e62db7bffe16b2e" + integrity sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw== + dependencies: + mime-types "~2.1.34" + negotiator "0.6.3" + +argparse@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" + integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== + +array-flatten@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" + integrity sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg== + +balanced-match@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" + integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== + +body-parser@1.20.2: + version "1.20.2" + resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.2.tgz#6feb0e21c4724d06de7ff38da36dad4f57a747fd" + integrity sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA== + dependencies: + bytes "3.1.2" + content-type "~1.0.5" + debug "2.6.9" + depd "2.0.0" + destroy "1.2.0" + http-errors "2.0.0" + iconv-lite "0.4.24" + on-finished "2.4.1" + qs "6.11.0" + raw-body "2.5.2" + type-is "~1.6.18" + unpipe "1.0.0" + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +bytes@3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5" + integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg== + +call-bind@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.7.tgz#06016599c40c56498c18769d2730be242b6fa3b9" + integrity sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w== + dependencies: + es-define-property "^1.0.0" + es-errors "^1.3.0" + function-bind "^1.1.2" + get-intrinsic "^1.2.4" + set-function-length "^1.2.1" + +call-me-maybe@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/call-me-maybe/-/call-me-maybe-1.0.2.tgz#03f964f19522ba643b1b0693acb9152fe2074baa" + integrity sha512-HpX65o1Hnr9HH25ojC1YGs7HCQLq0GCOibSaWER0eNpgJ/Z1MZv2mTc7+xh6WOPxbRVcmgbv4hGU+uSQ/2xFZQ== + +commander@6.2.0: + version "6.2.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-6.2.0.tgz#b990bfb8ac030aedc6d11bc04d1488ffef56db75" + integrity sha512-zP4jEKbe8SHzKJYQmq8Y9gYjtO/POJLgIdKgV7B9qNmABVFVc+ctqSX6iXh4mCpJfRBOabiZ2YKPg8ciDw6C+Q== + +commander@^10.0.0: + version "10.0.1" + resolved "https://registry.yarnpkg.com/commander/-/commander-10.0.1.tgz#881ee46b4f77d1c1dccc5823433aa39b022cbe06" + integrity sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug== + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== + +content-disposition@0.5.4: + version "0.5.4" + resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.4.tgz#8b82b4efac82512a02bb0b1dcec9d2c5e8eb5bfe" + integrity sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ== + dependencies: + safe-buffer "5.2.1" + +content-type@~1.0.4, content-type@~1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.5.tgz#8b773162656d1d1086784c8f23a54ce6d73d7918" + integrity sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA== + +cookie-signature@1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" + integrity sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ== + +cookie@0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.6.0.tgz#2798b04b071b0ecbff0dbb62a505a8efa4e19051" + integrity sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw== + +debug@2.6.9: + version "2.6.9" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" + integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== + dependencies: + ms "2.0.0" + +define-data-property@^1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/define-data-property/-/define-data-property-1.1.4.tgz#894dc141bb7d3060ae4366f6a0107e68fbe48c5e" + integrity sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A== + dependencies: + es-define-property "^1.0.0" + es-errors "^1.3.0" + gopd "^1.0.1" + +depd@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df" + integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw== + +destroy@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.2.0.tgz#4803735509ad8be552934c67df614f94e66fa015" + integrity sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg== + +doctrine@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" + integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== + dependencies: + esutils "^2.0.2" + +ee-first@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" + integrity sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow== + +encodeurl@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" + integrity sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w== + +es-define-property@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/es-define-property/-/es-define-property-1.0.0.tgz#c7faefbdff8b2696cf5f46921edfb77cc4ba3845" + integrity sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ== + dependencies: + get-intrinsic "^1.2.4" + +es-errors@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/es-errors/-/es-errors-1.3.0.tgz#05f75a25dab98e4fb1dcd5e1472c0546d5057c8f" + integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw== + +escape-html@~1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" + integrity sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow== + +esutils@^2.0.2: + version "2.0.3" + resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" + integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== + +etag@~1.8.1: + version "1.8.1" + resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" + integrity sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg== + +express@^4.19.2: + version "4.19.2" + resolved "https://registry.yarnpkg.com/express/-/express-4.19.2.tgz#e25437827a3aa7f2a827bc8171bbbb664a356465" + integrity sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q== + dependencies: + accepts "~1.3.8" + array-flatten "1.1.1" + body-parser "1.20.2" + content-disposition "0.5.4" + content-type "~1.0.4" + cookie "0.6.0" + cookie-signature "1.0.6" + debug "2.6.9" + depd "2.0.0" + encodeurl "~1.0.2" + escape-html "~1.0.3" + etag "~1.8.1" + finalhandler "1.2.0" + fresh "0.5.2" + http-errors "2.0.0" + merge-descriptors "1.0.1" + methods "~1.1.2" + on-finished "2.4.1" + parseurl "~1.3.3" + path-to-regexp "0.1.7" + proxy-addr "~2.0.7" + qs "6.11.0" + range-parser "~1.2.1" + safe-buffer "5.2.1" + send "0.18.0" + serve-static "1.15.0" + setprototypeof "1.2.0" + statuses "2.0.1" + type-is "~1.6.18" + utils-merge "1.0.1" + vary "~1.1.2" + +finalhandler@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.2.0.tgz#7d23fe5731b207b4640e4fcd00aec1f9207a7b32" + integrity sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg== + dependencies: + debug "2.6.9" + encodeurl "~1.0.2" + escape-html "~1.0.3" + on-finished "2.4.1" + parseurl "~1.3.3" + statuses "2.0.1" + unpipe "~1.0.0" + +forwarded@0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811" + integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow== + +fresh@0.5.2: + version "0.5.2" + resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" + integrity sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q== + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== + +function-bind@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c" + integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== + +get-intrinsic@^1.1.3, get-intrinsic@^1.2.4: + version "1.2.4" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.4.tgz#e385f5a4b5227d449c3eabbad05494ef0abbeadd" + integrity sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ== + dependencies: + es-errors "^1.3.0" + function-bind "^1.1.2" + has-proto "^1.0.1" + has-symbols "^1.0.3" + hasown "^2.0.0" + +glob@7.1.6: + version "7.1.6" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6" + integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + +gopd@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.0.1.tgz#29ff76de69dac7489b7c0918a5788e56477c332c" + integrity sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA== + dependencies: + get-intrinsic "^1.1.3" + +has-property-descriptors@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz#963ed7d071dc7bf5f084c5bfbe0d1b6222586854" + integrity sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg== + dependencies: + es-define-property "^1.0.0" + +has-proto@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has-proto/-/has-proto-1.0.3.tgz#b31ddfe9b0e6e9914536a6ab286426d0214f77fd" + integrity sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q== + +has-symbols@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8" + integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== + +hasown@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003" + integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ== + dependencies: + function-bind "^1.1.2" + +http-errors@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-2.0.0.tgz#b7774a1486ef73cf7667ac9ae0858c012c57b9d3" + integrity sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ== + dependencies: + depd "2.0.0" + inherits "2.0.4" + setprototypeof "1.2.0" + statuses "2.0.1" + toidentifier "1.0.1" + +iconv-lite@0.4.24: + version "0.4.24" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" + integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== + dependencies: + safer-buffer ">= 2.1.2 < 3" + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2, inherits@2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +ipaddr.js@1.9.1: + version "1.9.1" + resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3" + integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g== + +js-yaml@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" + integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== + dependencies: + argparse "^2.0.1" + +lodash.get@^4.4.2: + version "4.4.2" + resolved "https://registry.yarnpkg.com/lodash.get/-/lodash.get-4.4.2.tgz#2d177f652fa31e939b4438d5341499dfa3825e99" + integrity sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ== + +lodash.isequal@^4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0" + integrity sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ== + +lodash.mergewith@^4.6.2: + version "4.6.2" + resolved "https://registry.yarnpkg.com/lodash.mergewith/-/lodash.mergewith-4.6.2.tgz#617121f89ac55f59047c7aec1ccd6654c6590f55" + integrity sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ== + +media-typer@0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" + integrity sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ== + +merge-descriptors@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" + integrity sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w== + +methods@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" + integrity sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w== + +mime-db@1.52.0: + version "1.52.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" + integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== + +mime-types@~2.1.24, mime-types@~2.1.34: + version "2.1.35" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" + integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== + dependencies: + mime-db "1.52.0" + +mime@1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" + integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== + +minimatch@^3.0.4: + version "3.1.2" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" + integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== + dependencies: + brace-expansion "^1.1.7" + +ms@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" + integrity sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A== + +ms@2.1.3: + version "2.1.3" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" + integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== + +negotiator@0.6.3: + version "0.6.3" + resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd" + integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg== + +object-inspect@^1.13.1: + version "1.13.1" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.1.tgz#b96c6109324ccfef6b12216a956ca4dc2ff94bc2" + integrity sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ== + +on-finished@2.4.1: + version "2.4.1" + resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.4.1.tgz#58c8c44116e54845ad57f14ab10b03533184ac3f" + integrity sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg== + dependencies: + ee-first "1.1.1" + +once@^1.3.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== + dependencies: + wrappy "1" + +parseurl@~1.3.3: + version "1.3.3" + resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" + integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== + +path-to-regexp@0.1.7: + version "0.1.7" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" + integrity sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ== + +proxy-addr@~2.0.7: + version "2.0.7" + resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.7.tgz#f19fe69ceab311eeb94b42e70e8c2070f9ba1025" + integrity sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg== + dependencies: + forwarded "0.2.0" + ipaddr.js "1.9.1" + +qs@6.11.0: + version "6.11.0" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.0.tgz#fd0d963446f7a65e1367e01abd85429453f0c37a" + integrity sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q== + dependencies: + side-channel "^1.0.4" + +range-parser@~1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" + integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg== + +raw-body@2.5.2: + version "2.5.2" + resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.5.2.tgz#99febd83b90e08975087e8f1f9419a149366b68a" + integrity sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA== + dependencies: + bytes "3.1.2" + http-errors "2.0.0" + iconv-lite "0.4.24" + unpipe "1.0.0" + +safe-buffer@5.2.1: + version "5.2.1" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" + integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== + +"safer-buffer@>= 2.1.2 < 3": + version "2.1.2" + resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== + +send@0.18.0: + version "0.18.0" + resolved "https://registry.yarnpkg.com/send/-/send-0.18.0.tgz#670167cc654b05f5aa4a767f9113bb371bc706be" + integrity sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg== + dependencies: + debug "2.6.9" + depd "2.0.0" + destroy "1.2.0" + encodeurl "~1.0.2" + escape-html "~1.0.3" + etag "~1.8.1" + fresh "0.5.2" + http-errors "2.0.0" + mime "1.6.0" + ms "2.1.3" + on-finished "2.4.1" + range-parser "~1.2.1" + statuses "2.0.1" + +serve-static@1.15.0: + version "1.15.0" + resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.15.0.tgz#faaef08cffe0a1a62f60cad0c4e513cff0ac9540" + integrity sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g== + dependencies: + encodeurl "~1.0.2" + escape-html "~1.0.3" + parseurl "~1.3.3" + send "0.18.0" + +set-function-length@^1.2.1: + version "1.2.2" + resolved "https://registry.yarnpkg.com/set-function-length/-/set-function-length-1.2.2.tgz#aac72314198eaed975cf77b2c3b6b880695e5449" + integrity sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg== + dependencies: + define-data-property "^1.1.4" + es-errors "^1.3.0" + function-bind "^1.1.2" + get-intrinsic "^1.2.4" + gopd "^1.0.1" + has-property-descriptors "^1.0.2" + +setprototypeof@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.2.0.tgz#66c9a24a73f9fc28cbe66b09fed3d33dcaf1b424" + integrity sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw== + +side-channel@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.6.tgz#abd25fb7cd24baf45466406b1096b7831c9215f2" + integrity sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA== + dependencies: + call-bind "^1.0.7" + es-errors "^1.3.0" + get-intrinsic "^1.2.4" + object-inspect "^1.13.1" + +statuses@2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-2.0.1.tgz#55cb000ccf1d48728bd23c685a063998cf1a1b63" + integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ== + +swagger-jsdoc@^6.2.8: + version "6.2.8" + resolved "https://registry.yarnpkg.com/swagger-jsdoc/-/swagger-jsdoc-6.2.8.tgz#6d33d9fb07ff4a7c1564379c52c08989ec7d0256" + integrity sha512-VPvil1+JRpmJ55CgAtn8DIcpBs0bL5L3q5bVQvF4tAW/k/9JYSj7dCpaYCAv5rufe0vcCbBRQXGvzpkWjvLklQ== + dependencies: + commander "6.2.0" + doctrine "3.0.0" + glob "7.1.6" + lodash.mergewith "^4.6.2" + swagger-parser "^10.0.3" + yaml "2.0.0-1" + +swagger-parser@^10.0.3: + version "10.0.3" + resolved "https://registry.yarnpkg.com/swagger-parser/-/swagger-parser-10.0.3.tgz#04cb01c18c3ac192b41161c77f81e79309135d03" + integrity sha512-nF7oMeL4KypldrQhac8RyHerJeGPD1p2xDh900GPvc+Nk7nWP6jX2FcC7WmkinMoAmoO774+AFXcWsW8gMWEIg== + dependencies: + "@apidevtools/swagger-parser" "10.0.3" + +swagger-ui-dist@>=5.0.0: + version "5.17.2" + resolved "https://registry.yarnpkg.com/swagger-ui-dist/-/swagger-ui-dist-5.17.2.tgz#de31813b18ff34e9a428cd6b9ede521164621996" + integrity sha512-V/NqUw6QoTrjSpctp2oLQvxrl3vW29UsUtZyq7B1CF0v870KOFbYGDQw8rpKaKm0JxTwHpWnW1SN9YuKZdiCyw== + +swagger-ui-express@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/swagger-ui-express/-/swagger-ui-express-5.0.0.tgz#7a00a18dd909574cb0d628574a299b9ba53d4d49" + integrity sha512-tsU9tODVvhyfkNSvf03E6FAk+z+5cU3lXAzMy6Pv4av2Gt2xA0++fogwC4qo19XuFf6hdxevPuVCSKFuMHJhFA== + dependencies: + swagger-ui-dist ">=5.0.0" + +toidentifier@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35" + integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA== + +type-is@~1.6.18: + version "1.6.18" + resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" + integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g== + dependencies: + media-typer "0.3.0" + mime-types "~2.1.24" + +unpipe@1.0.0, unpipe@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" + integrity sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ== + +utils-merge@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" + integrity sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA== + +validator@^13.7.0: + version "13.11.0" + resolved "https://registry.yarnpkg.com/validator/-/validator-13.11.0.tgz#23ab3fd59290c61248364eabf4067f04955fbb1b" + integrity sha512-Ii+sehpSfZy+At5nPdnyMhx78fEoPDkR2XW/zimHEL3MyGJQOCQ7WeP20jPYRz7ZCpcKLB21NxuXHF3bxjStBQ== + +vary@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" + integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg== + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== + +yaml@2.0.0-1: + version "2.0.0-1" + resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.0.0-1.tgz#8c3029b3ee2028306d5bcf396980623115ff8d18" + integrity sha512-W7h5dEhywMKenDJh2iX/LABkbFnBxasD27oyXWDS/feDsxiw0dD5ncXdYXgkvAsXIY2MpW/ZKkr9IU30DBdMNQ== + +z-schema@^5.0.1: + version "5.0.6" + resolved "https://registry.yarnpkg.com/z-schema/-/z-schema-5.0.6.tgz#46d6a687b15e4a4369e18d6cb1c7b8618fc256c5" + integrity sha512-+XR1GhnWklYdfr8YaZv/iu+vY+ux7V5DS5zH1DQf6bO5ufrt/5cgNhVO5qyhsjFXvsqQb/f08DWE9b6uPscyAg== + dependencies: + lodash.get "^4.4.2" + lodash.isequal "^4.5.0" + validator "^13.7.0" + optionalDependencies: + commander "^10.0.0" From d37fc23ba16adfdb6d74730468950727d5e3d853 Mon Sep 17 00:00:00 2001 From: Sudip Bhattarai Date: Thu, 2 May 2024 11:39:57 +0545 Subject: [PATCH 037/125] Add lock expiry. --- tests/test-metadata-api/locks_api.js | 80 +++++++++++++++++++--------- tests/test-metadata-api/package.json | 5 +- tests/test-metadata-api/yarn.lock | 5 ++ 3 files changed, 63 insertions(+), 27 deletions(-) diff --git a/tests/test-metadata-api/locks_api.js b/tests/test-metadata-api/locks_api.js index 9ad9a4a43..5196a70ea 100644 --- a/tests/test-metadata-api/locks_api.js +++ b/tests/test-metadata-api/locks_api.js @@ -1,28 +1,32 @@ +const { v4: uuidv4 } = require('uuid'); const lock = {}; -function acquireLock(key) { - return new Promise((resolve, reject) => { - if (!lock[key]) { - lock[key] = true; - resolve(); - } else { - reject({ status: 423, message: 'Lock not available' }); +function acquireLock(key, expiry_secs = 180) { + const now = Date.now(); + if (!lock[key] || lock[key].expiry < now) { + const uuid = uuidv4(); + lock[key] = { + locked: true, + expiry: now + expiry_secs * 1000, + uuid: uuid, + }; + return uuid + } +} +function releaseLock(key,uuid) { + if(uuid){ + _lock=lock[key] + if(_lock && (_lock.uuid != uuid)){ + // if the uuid doesn't match, the lock should + // have expired and obtained by process. + return; } - }); + } + delete lock[key]; } -function releaseLock(key) { - lock[key] = false; -} function setup(app) { - /** - * @swagger - * tags: - * name: Locks - * description: API endpoints for managing locks - */ - /** * @swagger * /lock/{key}: @@ -36,19 +40,36 @@ function setup(app) { * type: string * required: true * description: The key of the lock to acquire + * - in: query + * name: expiry_secs + * schema: + * type: integer + * minimum: 1 + * default: 180 + * description: The expiration time of the lock in seconds (default is 180s) * responses: * '200': * description: Lock acquired successfully + * content: + * application/json: + * schema: + * type: object + * properties: + * uuid: + * type: string + * description: The UUID of the acquired lock * '423': * description: Lock not available */ - app.post('/lock/:key', async (req, res) => { + app.post('/lock/:key', (req, res) => { const key = req.params.key; - try { - await acquireLock(key); - res.send('Lock acquired.'); - } catch (error) { - res.status(error.status).send(error.message); + const expiry_secs = req.query.expiry_secs ? parseInt(req.query.expiry_secs) : 180; + const lock_uuid=acquireLock(key, expiry_secs) + if(lock_uuid){ + res.json({ uuid: lock_uuid }) + }else{ + res.status(423).json({ status: 423, message: 'Lock not available' }); + } }); @@ -65,14 +86,23 @@ function setup(app) { * type: string * required: true * description: The key of the lock to release + * - in: query + * name: uuid + * schema: + * type: string + * required: false + * description: The UUID of the lock to release * responses: * '200': * description: Lock released successfully */ app.post('/unlock/:key', (req, res) => { const key = req.params.key; - releaseLock(key); + const uuid = req.query.uuid; + + releaseLock(key, uuid); res.send('Lock released.'); + }); } diff --git a/tests/test-metadata-api/package.json b/tests/test-metadata-api/package.json index 408c3f036..520a75019 100644 --- a/tests/test-metadata-api/package.json +++ b/tests/test-metadata-api/package.json @@ -9,6 +9,7 @@ "dependencies": { "express": "^4.19.2", "swagger-jsdoc": "^6.2.8", - "swagger-ui-express": "^5.0.0" + "swagger-ui-express": "^5.0.0", + "uuid": "^9.0.1" } -} \ No newline at end of file +} diff --git a/tests/test-metadata-api/yarn.lock b/tests/test-metadata-api/yarn.lock index a23104223..cf7a4ed22 100644 --- a/tests/test-metadata-api/yarn.lock +++ b/tests/test-metadata-api/yarn.lock @@ -646,6 +646,11 @@ utils-merge@1.0.1: resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" integrity sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA== +uuid@^9.0.1: + version "9.0.1" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-9.0.1.tgz#e188d4c8853cc722220392c424cd637f32293f30" + integrity sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA== + validator@^13.7.0: version "13.11.0" resolved "https://registry.yarnpkg.com/validator/-/validator-13.11.0.tgz#23ab3fd59290c61248364eabf4067f04955fbb1b" From 5a70c942515018e84adb9e5eb8aab28544638e27 Mon Sep 17 00:00:00 2001 From: Nabin Kawan Date: Fri, 3 May 2024 15:02:06 +0545 Subject: [PATCH 038/125] Update env variables --- .github/workflows/test_integration_playwright.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/test_integration_playwright.yml b/.github/workflows/test_integration_playwright.yml index d7f0ff4aa..f9e10d27b 100644 --- a/.github/workflows/test_integration_playwright.yml +++ b/.github/workflows/test_integration_playwright.yml @@ -50,14 +50,14 @@ jobs: path: tests/govtool-frontend/playwright/allure-results env: - FRONTEND_URL: ${{vars.FRONTEND_URL}} - API_URL: ${{vars.API_URL}} + FRONTEND_URL: ${{vars.HOST_URL}} + API_URL: ${{vars.HOST_URL}}/api DOCS_URL: ${{ vars.DOCS_URL }} FAUCET_API_URL: ${{ vars.FAUCET_API_URL }} FAUCET_API_KEY: ${{secrets.FAUCET_API_KEY}} KUBER_API_URL: ${{vars.KUBER_API_URL}} KUBER_API_KEY: ${{secrets.KUBER_API_KEY}} - WORKERS: ${{vars.WORKERS}} + WORKERS: ${{vars.TEST_WORKERS}} publish-report: runs-on: ubuntu-latest From 0b90757b4dd4838ca87e2d9ffc13e8f69d5caa52 Mon Sep 17 00:00:00 2001 From: Sudip Bhattarai Date: Mon, 6 May 2024 11:57:40 +0545 Subject: [PATCH 039/125] Remove un-used services --- tests/test-infrastructure/.env.example | 2 +- tests/test-infrastructure/docker-compose.yml | 74 ++------------------ 2 files changed, 6 insertions(+), 70 deletions(-) diff --git a/tests/test-infrastructure/.env.example b/tests/test-infrastructure/.env.example index fd9687eeb..92570776c 100644 --- a/tests/test-infrastructure/.env.example +++ b/tests/test-infrastructure/.env.example @@ -1,4 +1,4 @@ STACK_NAME=govtool -BASE_DOMAIN=cardanoapi.io +BASE_DOMAIN=govtool.cardanoapi.io BLOCKFROST_API_URL="" BLOCKFROST_PROJECT_ID="" diff --git a/tests/test-infrastructure/docker-compose.yml b/tests/test-infrastructure/docker-compose.yml index 9e8f77da5..ca923effd 100644 --- a/tests/test-infrastructure/docker-compose.yml +++ b/tests/test-infrastructure/docker-compose.yml @@ -39,50 +39,13 @@ networks: external: true services: - metabase: - image: metabase/metabase:v0.46.6.2 - hostname: metabase - volumes: - - /dev/urandom:/dev/random:ro - environment: - VIRTUAL_HOST: https://metabase.${BASE_DOMAIN} - MB_DB_TYPE: postgres - MB_DB_DBNAME: ${STACK_NAME}_metabase - MB_DB_PORT: 5432 - MB_DB_USER_FILE: /run/secrets/postgres_user - MB_DB_PASS_FILE: /run/secrets/postgres_password - MB_DB_HOST: postgres - networks: - - postgres - - frontend - secrets: - - postgres_password - - postgres_user - deploy: - placement: - constraints: - - node.labels.govtool-test-stack == true - restart_policy: - delay: "30s" - resources: - limits: - memory: 3G - reservations: - memory: 1.8G - - healthcheck: - test: curl --fail -I http://localhost:3000/api/health || exit 1 - interval: 15s - timeout: 5s - retries: 5 - metrics_api: image: voltaire-era/govtool-metrics-api build: context: ../test-metrics-api environment: - VIRTUAL_HOST: https://metrics.${BASE_DOMAIN}/ -> :3000/ + VIRTUAL_HOST: https://metrics-${BASE_DOMAIN}/ -> :3000/ PGHOST: postgres PGDATABASE: ${STACK_NAME}_metrics secrets: @@ -110,7 +73,7 @@ services: lhci-server: image: patrickhulce/lhci-server:0.12.0 environment: - VIRTUAL_HOST: https://lighthouse.${BASE_DOMAIN} -> :9001 + VIRTUAL_HOST: https://lighthouse-${BASE_DOMAIN} -> :9001 volumes: - lhci_data:/data secrets: @@ -137,7 +100,7 @@ services: context: ../../src/gov-action-loader-fe dockerfile: Dockerfile environment: - VIRTUAL_HOST: https://govtool-governance.${BASE_DOMAIN} + VIRTUAL_HOST: https://governance-${BASE_DOMAIN} networks: - frontend deploy: @@ -162,7 +125,7 @@ services: KUBER_API_KEY: "" BLOCKFROST_API_URL: "${BLOCKFROST_API_URL}" BLOCKFROST_PROJECT_ID: "${BLOCKFROST_PROJECT_ID}" - VIRTUAL_HOST: https://govtool-governance.${BASE_DOMAIN}/api/ -> /api/ + VIRTUAL_HOST: https://governance-${BASE_DOMAIN}/api/ -> /api/ networks: - default - frontend @@ -177,33 +140,6 @@ services: memory: 1G reservations: memory: 500M - - sonarqube_server: - image: mc1arke/sonarqube-with-community-branch-plugin:9.9-community - networks: - - frontend - - postgres - environment: - SONAR_JDBC_URL: jdbc:postgresql://postgres:5432/${STACK_NAME}_sonarqube - VIRTUAL_HOST: https+wss://sonarqube.${BASE_DOMAIN} -> :9000 - SONAR_JDBC_USERNAME: postgres - volumes: - - sonar_data:/opt/sonarqube/data - - sonar_logs:/opt/sonarqube/logs - entrypoint: "sh -c 'SONAR_JDBC_PASSWORD=\"$$( cat /run/secrets/postgres_password )\" /opt/sonarqube/docker/entrypoint.sh'" - secrets: - - postgres_password - deploy: - placement: - constraints: - - node.labels.govtool-test-stack == true - restart_policy: - delay: 15s - resources: - limits: - memory: 3.5G - reservations: - memory: 2.2G cardano-node: image: ghcr.io/intersectmbo/cardano-node:8.7.1-pre environment: @@ -233,7 +169,7 @@ services: image: dquadrant/kuber environment: CARDANO_NODE_SOCKET_PATH: /ipc/node.socket - VIRTUAL_HOST: https://kuber.${BASE_DOMAIN} + VIRTUAL_HOST: https://kuber-${BASE_DOMAIN} NETWORK: 4 START_ERA: CONWAY volumes: From d86245ac03e386b85b61eaa1aad32dedf5ada16d Mon Sep 17 00:00:00 2001 From: Sudip Bhattarai Date: Mon, 6 May 2024 12:33:20 +0545 Subject: [PATCH 040/125] Fix paths of gov-action-loader --- tests/test-infrastructure/README.md | 6 +++--- tests/test-infrastructure/docker-compose.yml | 8 +++++--- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/tests/test-infrastructure/README.md b/tests/test-infrastructure/README.md index d91eeaa44..c0775d8eb 100644 --- a/tests/test-infrastructure/README.md +++ b/tests/test-infrastructure/README.md @@ -20,7 +20,7 @@ Services required for testing GovTool `docker stack deploy` command doesn't support `.env` file secret/config files. There's a helper script `deploy-swarm.sh` to load the environment variables from `.env` file and generate rendered docker compose file. ```bash -cd ./test/test-infrastructire # cd into the test-infrastructure folder +cd ./test/test-infrastructure # cd into the test-infrastructure folder docker swarm init # if swarm mode is not enabled yet. docker compose build # build the images docker node update xxxx --label-add govtool-test-stack=true ## set the node to be used for deploying the services @@ -73,7 +73,7 @@ It is used for visualizing the test metrics and the api response times over time **Docker Image:** [metabase/metabase:v0.46.6.4](https://hub.docker.com/layers/metabase/metabase/v0.46.6.4/images/sha256-95c60db0c87c5da9cb81f6aefd0cd548fe2c14ff8c8dcba2ea58a338865cdbd9?context=explore) ### Initial Configuration - - Setup initial account for ligin via the webapp. + - Setup initial account for login via the webapp. - Under database section in admin settings, add the `govtool_lithghouse` and `govtool_metrics` databases - Select the database and add visualizations, queries for the data. @@ -82,7 +82,7 @@ It is used for visualizing the test metrics and the api response times over time - postgres database #### Used by -- Github Action to submit lighthouse report. +- GitHub Action to submit lighthouse report. Lighthouse has audits for performance, accessibility, progressive web apps, SEO, and more. Lighthouse-Server is used to host and display the audits generated by lighthouse. diff --git a/tests/test-infrastructure/docker-compose.yml b/tests/test-infrastructure/docker-compose.yml index ca923effd..ae0942db9 100644 --- a/tests/test-infrastructure/docker-compose.yml +++ b/tests/test-infrastructure/docker-compose.yml @@ -97,7 +97,7 @@ services: governance-action-loader-ui: image: voltaire-era/govtool-governance-action-loader build: - context: ../../src/gov-action-loader-fe + context: ../../gov-action-loader/frontend dockerfile: Dockerfile environment: VIRTUAL_HOST: https://governance-${BASE_DOMAIN} @@ -118,7 +118,7 @@ services: governance-action-loader-api: image: voltaire-era/govtool-kuber-proposal-loader-proxy build: - context: ../../src/gov-action-loader-be + context: ../../gov-action-loader/backend dockerfile: Dockerfile environment: KUBER_API_URL: "http://kuber:8081" @@ -140,6 +140,7 @@ services: memory: 1G reservations: memory: 500M + cardano-node: image: ghcr.io/intersectmbo/cardano-node:8.7.1-pre environment: @@ -165,8 +166,9 @@ services: restart_policy: condition: on-failure delay: 15s + kuber: - image: dquadrant/kuber + image: dquadrant/kuber:4c3c5230db9a9b8ac84487fbc11ccd28b0cd5917-amd64 environment: CARDANO_NODE_SOCKET_PATH: /ipc/node.socket VIRTUAL_HOST: https://kuber-${BASE_DOMAIN} From 5dc86402cb2b2407dd65a7634d38900cec90b737 Mon Sep 17 00:00:00 2001 From: Sudip Bhattarai Date: Mon, 6 May 2024 13:17:34 +0545 Subject: [PATCH 041/125] Add dbsync service --- .../configs_template/postgres_db_setup.sql | 2 +- tests/test-infrastructure/docker-compose.yml | 40 ++++++++++++++++++- tests/test-infrastructure/gen-configs.sh | 6 ++- 3 files changed, 44 insertions(+), 4 deletions(-) diff --git a/tests/test-infrastructure/configs_template/postgres_db_setup.sql b/tests/test-infrastructure/configs_template/postgres_db_setup.sql index 2934a2840..7a40fccd8 100644 --- a/tests/test-infrastructure/configs_template/postgres_db_setup.sql +++ b/tests/test-infrastructure/configs_template/postgres_db_setup.sql @@ -1,4 +1,4 @@ -CREATE database ${STACK_NAME}_metabase; CREATE database ${STACK_NAME}_lighthouse; CREATE database ${STACK_NAME}_metrics; CREATE database ${STACK_NAME}_sonarqube; +CREATE database ${STACK_NAME}_dbsync; \ No newline at end of file diff --git a/tests/test-infrastructure/docker-compose.yml b/tests/test-infrastructure/docker-compose.yml index ae0942db9..75281d5ef 100644 --- a/tests/test-infrastructure/docker-compose.yml +++ b/tests/test-infrastructure/docker-compose.yml @@ -12,6 +12,9 @@ secrets: metrics_api_secret_token: external: true name: ${STACK_NAME}_metrics_api_secret + dbsync_database: + external: true + name: ${STACK_NAME}_dbsync_database ## secrets syntax for docker compose stack # secrets: @@ -31,6 +34,7 @@ volumes: sonar_logs: node_data: node_ipc: + dbsync_data: networks: postgres: @@ -142,7 +146,7 @@ services: memory: 500M cardano-node: - image: ghcr.io/intersectmbo/cardano-node:8.7.1-pre + image: ghcr.io/intersectmbo/cardano-node:8.10.0-pre environment: NETWORK: sanchonet volumes: @@ -166,7 +170,39 @@ services: restart_policy: condition: on-failure delay: 15s - + dbsync: + image: ghcr.io/intersectmbo/cardano-db-sync:sancho-4-2-1 + networks: + - postgres + environment: + NETWORK: sanchonet + POSTGRES_HOST: postgres + POSTGRES_PORT: 5432 + DISABLE_CACHE: "" + DISABLE_LEDGER: "" + DISABLE_EPOCH: "" + secrets: + - postgres_user + - source: dbsync_database + target: postgres_db + - postgres_password + volumes: + - dbsync_data:/var/lib/cexplorer + - node_ipc:/node-ipc + logging: + driver: "json-file" + options: + max-size: "200k" + max-file: "10" + deploy: + labels: + "co_elastic_logs/enable": "false" + placement: + constraints: + - node.labels.govtool-test-stack == true + restart_policy: + condition: on-failure + delay: 15s kuber: image: dquadrant/kuber:4c3c5230db9a9b8ac84487fbc11ccd28b0cd5917-amd64 environment: diff --git a/tests/test-infrastructure/gen-configs.sh b/tests/test-infrastructure/gen-configs.sh index 19acbcc75..b7e65678b 100755 --- a/tests/test-infrastructure/gen-configs.sh +++ b/tests/test-infrastructure/gen-configs.sh @@ -63,7 +63,8 @@ mkdir -p ./secrets; echo -n $POSTGRES_USER > ./secrets/govtool_postgres_user echo -n $POSTGRES_PASSWORD > ./secrets/govtool_postgres_password echo -n $metrics_api_secret > ./secrets/govtool_metrics_api_secret - +$DBSYNC_DATABASE="${STACK_NAME}_dbsync" +echo -n "$DBSYNC_DATABASE" > ./secrets/govtool_dbsync_database ## loop over templates and updaete them. @@ -93,6 +94,9 @@ echo "$POSTGRES_USER" | (docker secret create "${STACK_NAME}_postgres_user" - ) echo "Generating Secret: ${STACK_NAME}_postgres_password" echo "$POSTGRES_PASSWORD" | (docker secret create "${STACK_NAME}_postgres_password" - ) || true +echo "Generating Secret: ${STACK_NAME}_dbsync_database" +echo "$DBSYNC_DATABASE" | (docker secret create "${STACK_NAME}_dbsync_database" - ) || true + echo "Generating Secret: ${STACK_NAME}_metrics_api_secret" echo "$metrics_api_secret" | (docker secret create "${STACK_NAME}_metrics_api_secret" - )|| true From 0fc0f03e12344f1752bd68445e3f0d19c8082509 Mon Sep 17 00:00:00 2001 From: Sudip Bhattarai Date: Mon, 6 May 2024 14:07:05 +0545 Subject: [PATCH 042/125] Refactor config generation script --- tests/test-infrastructure/gen-configs.sh | 99 +++++++++++------------- 1 file changed, 47 insertions(+), 52 deletions(-) diff --git a/tests/test-infrastructure/gen-configs.sh b/tests/test-infrastructure/gen-configs.sh index b7e65678b..38497990e 100755 --- a/tests/test-infrastructure/gen-configs.sh +++ b/tests/test-infrastructure/gen-configs.sh @@ -2,51 +2,53 @@ ####### Script for generating docker secret files and configs. ####### If the docker is in swarm mode, it will also generate the docker swarm secrets. ####### +set -e if ! [ -f ./.env ] then echo ".env file is missing" exit 1 fi + set -a . ./.env set +a + # Function to generate a random secret in base64 format without padding and '+' function generate_secret() { openssl rand -base64 16 | tr -d '=+/' } -# Generate random secrets -export POSTGRES_USER=postgres -export POSTGRES_PASSWORD=$(generate_secret) -metrics_api_secret=$(generate_secret) - if [ "$1" == "clean" ]; then - set -x - rm -rf ./configs; - rm -rf ./secrets; - - set +x - docker info | grep 'Swarm: active' > /dev/null 2>/dev/null || exit 0 - for CONFIG_FILE in $(ls ./configs_template) + # Create secrets from files + for SECRET_FILE in $(ls ./secrets) do - echo -n "Removing Config : " - docker config rm "${STACK_NAME}_${CONFIG_FILE}" || true + SECRET_NAME="$(basename $SECRET_FILE)" + echo -n "Removing secret: ${STACK_NAME}_${SECRET_NAME}" + docker secret rm "${STACK_NAME}_${SECRET_NAME}" || true done - for SECRET_FILE in "$(ls ./secrets_template)" "postgres_user" "postgres_password" "metrics_api_secret" + # Create configs from files + for CONFIG_FILE in $(ls ./configs) do - echo -n "Removing Secret : " - docker secret rm "${STACK_NAME}_${SECRET_FILE}" ||true + CONFIG_NAME=$(basename $CONFIG_FILE) + echo -n "Removing config: ${STACK_NAME}_${CONFIG_NAME}" + docker config rm "${STACK_NAME}_${CONFIG_NAME}" || true done + + set -x + rm -rf ./configs; + rm -rf ./secrets; + + set +x; exit 0 fi ## Check if one fo the secrets already exists -if [[ -f ./secrets/govtool_postgres_user ]] +if [[ -f ./secrets/postgres_user ]] then - echo "File ./secrets/govtool_postgres_user already exists." + echo "File ./secrets/postgres_user already exists." echo "Assuming that the secrets were already generated" echo " Use:" echo " > ./gen-configs.sh clean" @@ -58,58 +60,51 @@ fi mkdir -p ./configs; mkdir -p ./secrets; +# Generate random secrets +export POSTGRES_USER=postgres +export POSTGRES_PASSWORD=$(generate_secret) +metrics_api_secret=$(generate_secret) +DBSYNC_DATABASE="${STACK_NAME}_dbsync" + -## save secrets to secrets folder -echo -n $POSTGRES_USER > ./secrets/govtool_postgres_user -echo -n $POSTGRES_PASSWORD > ./secrets/govtool_postgres_password -echo -n $metrics_api_secret > ./secrets/govtool_metrics_api_secret -$DBSYNC_DATABASE="${STACK_NAME}_dbsync" -echo -n "$DBSYNC_DATABASE" > ./secrets/govtool_dbsync_database -## loop over templates and updaete them. +# Save secrets to files +echo -n $POSTGRES_USER > ./secrets/postgres_user +echo -n $POSTGRES_PASSWORD > ./secrets/postgres_password +echo -n $metrics_api_secret > ./secrets/metrics_api_secret +echo -n "$DBSYNC_DATABASE" > ./secrets/dbsync_database +## loop over templates and update them. for CONFIG_FILE in $(ls ./configs_template) do echo -n "Config ${STACK_NAME}_${CONFIG_FILE}: " - envsubst < "./configs_template/$CONFIG_FILE" > "./configs/${STACK_NAME}_${CONFIG_FILE}" + envsubst < "./configs_template/$CONFIG_FILE" > "./configs/${CONFIG_FILE}" done for SECRET_FILE in $(ls ./secrets_template) do echo -n "Secret ${STACK_NAME}_${SECRET_FILE}: " - envsubst < "./secrets_template/$SECRET_FILE" > "./secrets/${STACK_NAME}_${SECRET_FILE}" + envsubst < "./secrets_template/$SECRET_FILE" > "./secrets/${SECRET_FILE}" done - - ################################################################################ ################ Create secret/config for swarm ############################### ################################################################################ docker info | grep 'Swarm: active' > /dev/null 2>/dev/null || exit 0 -echo "Creating Secret: ${STACK_NAME}_postgres_user" -echo "$POSTGRES_USER" | (docker secret create "${STACK_NAME}_postgres_user" - ) || true - -echo "Generating Secret: ${STACK_NAME}_postgres_password" -echo "$POSTGRES_PASSWORD" | (docker secret create "${STACK_NAME}_postgres_password" - ) || true - -echo "Generating Secret: ${STACK_NAME}_dbsync_database" -echo "$DBSYNC_DATABASE" | (docker secret create "${STACK_NAME}_dbsync_database" - ) || true - -echo "Generating Secret: ${STACK_NAME}_metrics_api_secret" -echo "$metrics_api_secret" | (docker secret create "${STACK_NAME}_metrics_api_secret" - )|| true - - - -for CONFIG_FILE in $(ls ./configs_template) -do - echo -n "Creating Config: ${STACK_NAME}_${CONFIG_FILE} " - cat "./configs/${STACK_NAME}_${CONFIG_FILE}" | docker config create "${STACK_NAME}_${CONFIG_FILE}" - || true +# Create secrets from files +ls ./secrets | while IFS= read -r SECRET_FILE; do + SECRET_NAME=$(basename "$SECRET_FILE") + echo -n "Creating Secret: ${STACK_NAME}_${SECRET_NAME}: " + cat "./secrets/$SECRET_NAME" | (docker secret create "${STACK_NAME}_${SECRET_NAME}" -) || true done -for SECRET_FILE in $(ls ./secrets_template) + +# Create configs from files +for CONFIG_FILE in $(ls ./configs) do - echo -n "Creating Secret: ${STACK_NAME}_${SECRET_FILE} " - cat "./secrets/${STACK_NAME}_${SECRET_FILE}" | docker secret create "${STACK_NAME}_${SECRET_FILE}" - ||true -done + CONFIG_NAME=$(basename $CONFIG_FILE) + echo -n "Creating Config: ${STACK_NAME}_${CONFIG_NAME}: " + cat "./configs/$CONFIG_NAME" | (docker config create "${STACK_NAME}_${CONFIG_NAME}" -) || true +done \ No newline at end of file From 3a689e7e8a0f83308e85487e79a3cda5c4da8cfd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Sworze=C5=84?= Date: Mon, 6 May 2024 14:23:11 +0200 Subject: [PATCH 043/125] add wallet conncetor package --- .../wallet-connector/WalletProvider.tsx | 63 +++++++++++++++++ .../wallet-connector/WalletService.ts | 37 ++++++++++ govtool/packages/wallet-connector/index.ts | 3 + .../packages/wallet-connector/package.json | 12 ++++ govtool/packages/wallet-connector/types.ts | 69 +++++++++++++++++++ govtool/packages/wallet-connector/yarn.lock | 40 +++++++++++ 6 files changed, 224 insertions(+) create mode 100644 govtool/packages/wallet-connector/WalletProvider.tsx create mode 100644 govtool/packages/wallet-connector/WalletService.ts create mode 100644 govtool/packages/wallet-connector/index.ts create mode 100644 govtool/packages/wallet-connector/package.json create mode 100644 govtool/packages/wallet-connector/types.ts create mode 100644 govtool/packages/wallet-connector/yarn.lock diff --git a/govtool/packages/wallet-connector/WalletProvider.tsx b/govtool/packages/wallet-connector/WalletProvider.tsx new file mode 100644 index 000000000..4aee24e44 --- /dev/null +++ b/govtool/packages/wallet-connector/WalletProvider.tsx @@ -0,0 +1,63 @@ +import React, { createContext, useContext, useMemo, useState } from "react"; + +import { WalletService } from "./WalletService"; +import { + TWalletAPI, + WalletContextProviderProps, + WalletConnectorErrors, + WalletContextValues, +} from "./types"; + +const WalletContext = createContext(null); + +const WalletProvider = ({ children }: WalletContextProviderProps) => { + const [isEnableLoading, setIsEnableLoading] = useState(false); + const [enableError, setEnableError] = useState(null); + const [walletAPI, setWalletAPI] = useState(null); + + const enableWallet = async (walletName: string): Promise => { + setEnableError(null); + setIsEnableLoading(true); + try { + const newWalletAPI = await WalletService.enableWallet(walletName); + + if (newWalletAPI) setWalletAPI(newWalletAPI); + } catch (e) { + setEnableError(e); + throw e; + } finally { + setIsEnableLoading(false); + } + }; + + const disconnectWallet = () => { + setWalletAPI(null); + }; + + const value = useMemo( + () => ({ + disconnectWallet, + enableError, + enableWallet, + isEnableLoading, + walletAPI, + }), + [disconnectWallet, enableError, enableWallet, isEnableLoading, walletAPI] + ); + + return ( + {children} + ); +}; + +const useWalletContext = (): WalletContextValues => { + const context = useContext(WalletContext); + if (!context) + throw new Error( + WalletConnectorErrors.USE_WALLET_CONTEXT_USED_WITHOUT_PROVIDER + ); + + return context; +}; + +export default { useWalletContext, WalletProvider }; diff --git a/govtool/packages/wallet-connector/WalletService.ts b/govtool/packages/wallet-connector/WalletService.ts new file mode 100644 index 000000000..ead05b1e5 --- /dev/null +++ b/govtool/packages/wallet-connector/WalletService.ts @@ -0,0 +1,37 @@ +import { TWalletAPI, WalletConnectorErrors } from "./types"; + +export namespace WalletService { + export const enableWallet = async ( + walletName: string + ): Promise => { + try { + if (!window.cardano[walletName].supportedExtensions) + throw new Error( + WalletConnectorErrors.NO_CIP30_SUPPORT.replace( + "%WALLET_NAME%", + walletName + ) + ); + + if ( + !window.cardano[walletName].supportedExtensions.some( + (item) => item.cip === 95 + ) + ) + throw new Error( + WalletConnectorErrors.NO_CIP95_SUPPORT.replace( + "%WALLET_NAME%", + walletName + ) + ); + + const walletApi = await window.cardano[walletName].enable({ + extensions: [{ cip: 95 }], + }); + + return walletApi; + } catch (e) { + throw e; + } + }; +} diff --git a/govtool/packages/wallet-connector/index.ts b/govtool/packages/wallet-connector/index.ts new file mode 100644 index 000000000..39513db0e --- /dev/null +++ b/govtool/packages/wallet-connector/index.ts @@ -0,0 +1,3 @@ +export * from "./WalletProvider"; +export * from "./WalletService"; +export * from "./types"; diff --git a/govtool/packages/wallet-connector/package.json b/govtool/packages/wallet-connector/package.json new file mode 100644 index 000000000..c2848cfb6 --- /dev/null +++ b/govtool/packages/wallet-connector/package.json @@ -0,0 +1,12 @@ +{ + "name": "wallet-connector", + "version": "1.0.0", + "main": "index.ts", + "license": "MIT", + "dependencies": { + "react": "^18.3.1" + }, + "devDependencies": { + "@types/react": "^18.3.1" + } +} diff --git a/govtool/packages/wallet-connector/types.ts b/govtool/packages/wallet-connector/types.ts new file mode 100644 index 000000000..8bae56adf --- /dev/null +++ b/govtool/packages/wallet-connector/types.ts @@ -0,0 +1,69 @@ +import { ReactNode } from "react"; + +export type WalletContextProviderProps = { + children: ReactNode; +}; + +export type WalletContextValues = { + disconnectWallet: () => void; + enableError: string | null; + enableWallet: (walletName: string) => Promise; + isEnableLoading: boolean; + walletAPI: TWalletAPI | null; +}; + +export type Extension = { + cip: number; +}; + +export type TWalletAPI = { + cip95: { + getPubDRepKey(): Promise; + getRegisteredPubStakeKeys(): Promise; + getUnregisteredPubStakeKeys(): Promise; + signData(arg0: any, arg1: any): Promise; + }; + experimantal: { + on(arg0: any, arg1: any): any; + off(arg0: any, arg1: any): any; + getCollateral(): any; + }; + getBalance(): Promise; + getChangeAddress(): Promise; + getExtensions(): Promise; + getNetworkId(): Promise; + getRewardAddresses(): Promise; + getUnusedAddresses(): Promise; + getUsedAddresses(): Promise; + getUtxos(): Promise; + signData(arg0: any, arg1?: any): Promise; + signTx(arg0: any, arg1?: any): Promise; + submitTx(arg0: any): Promise; +}; + +export type EnableExtensionPayload = { + extensions: Extension[]; +}; + +export type CardanoBrowserWallet = { + apiVersion: string; + enable(extensions?: EnableExtensionPayload): Promise; + icon: string; + isEnabled(): Promise; + name: string; + supportedExtensions: Extension[]; +}; + +declare global { + interface Window { + cardano: { + [key: string]: CardanoBrowserWallet; + }; + } +} + +export enum WalletConnectorErrors { + NO_CIP30_SUPPORT = "%WALLET_NAME% wallet doesn't support CIP 30 extension.", + NO_CIP95_SUPPORT = "%WALLET_NAME% wallet doesn't support CIP 95 extension.", + USE_WALLET_CONTEXT_USED_WITHOUT_PROVIDER = "useWalletContext must be used in the WalletProvider.", +} diff --git a/govtool/packages/wallet-connector/yarn.lock b/govtool/packages/wallet-connector/yarn.lock new file mode 100644 index 000000000..bafef23bc --- /dev/null +++ b/govtool/packages/wallet-connector/yarn.lock @@ -0,0 +1,40 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@types/prop-types@*": + version "15.7.12" + resolved "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.12.tgz" + integrity sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q== + +"@types/react@^18.3.1": + version "18.3.1" + resolved "https://registry.npmjs.org/@types/react/-/react-18.3.1.tgz" + integrity sha512-V0kuGBX3+prX+DQ/7r2qsv1NsdfnCLnTgnRJ1pYnxykBhGMz+qj+box5lq7XsO5mtZsBqpjwwTu/7wszPfMBcw== + dependencies: + "@types/prop-types" "*" + csstype "^3.0.2" + +csstype@^3.0.2: + version "3.1.3" + resolved "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz" + integrity sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw== + +"js-tokens@^3.0.0 || ^4.0.0": + version "4.0.0" + resolved "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz" + integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== + +loose-envify@^1.1.0: + version "1.4.0" + resolved "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz" + integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== + dependencies: + js-tokens "^3.0.0 || ^4.0.0" + +react@^18.3.1: + version "18.3.1" + resolved "https://registry.npmjs.org/react/-/react-18.3.1.tgz" + integrity sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ== + dependencies: + loose-envify "^1.1.0" From 10564fafa6de160a7ab8c7a40068ecc3d36d55a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Sworze=C5=84?= Date: Mon, 6 May 2024 14:24:47 +0200 Subject: [PATCH 044/125] add to changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2627e3823..e649f9835 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ changes. ## [Unreleased] +- Add wallet connector package [Issue 898](https://github.com/IntersectMBO/govtool/issues/898) - Change DRep without metadata name from "Sole Voter" to "Direct Voter" [Issue 880](https://github.com/IntersectMBO/govtool/issues/880) - Inicialize Usersnap into App [Issue 546](https://github.com/IntersectMBO/govtool/issues/546) - Integrate frontend with metadata validation service [Issue 617](https://github.com/IntersectMBO/govtool/issues/617) From d9c5e08a68487af20c2280e3e49e588906321773 Mon Sep 17 00:00:00 2001 From: Sudip Bhattarai Date: Tue, 7 May 2024 12:02:20 +0545 Subject: [PATCH 045/125] Add govtool stack and update configs --- tests/test-infrastructure/.gitignore | 5 +- tests/test-infrastructure/build-images.sh | 7 +++ .../configs_template/backend_config.json | 13 +++++ tests/test-infrastructure/deploy-swarm.sh | 12 ++--- .../docker-compose-govtool.yml | 51 +++++++++++++++++++ tests/test-infrastructure/docker-compose.yml | 3 +- tests/test-infrastructure/gen-configs.sh | 38 ++++++-------- .../scripts/deploy-stack.sh | 47 +++++++++++++++++ 8 files changed, 143 insertions(+), 33 deletions(-) create mode 100755 tests/test-infrastructure/build-images.sh create mode 100644 tests/test-infrastructure/configs_template/backend_config.json create mode 100644 tests/test-infrastructure/docker-compose-govtool.yml create mode 100755 tests/test-infrastructure/scripts/deploy-stack.sh diff --git a/tests/test-infrastructure/.gitignore b/tests/test-infrastructure/.gitignore index e433f6cb7..990529fba 100644 --- a/tests/test-infrastructure/.gitignore +++ b/tests/test-infrastructure/.gitignore @@ -1,5 +1,4 @@ secrets/ configs/ -docker-compose-rendered.yml -docker-compose-swarm-rendered.yml -docker-compose-services-rendered.yml +/*-rendered.yml + diff --git a/tests/test-infrastructure/build-images.sh b/tests/test-infrastructure/build-images.sh new file mode 100755 index 000000000..4f6796166 --- /dev/null +++ b/tests/test-infrastructure/build-images.sh @@ -0,0 +1,7 @@ +#!/bin/bash + +export BASE_IMAGE_NAME="govtool" +# build the base image +docker build -t "$BASE_IMAGE_NAME"/backend-base -f ../../govtool/backend/Dockerfile.base ../../govtool/backend +docker compose -f ./docker-compose-govtool.yml build +docker compose -f ./docker-compose.yml build diff --git a/tests/test-infrastructure/configs_template/backend_config.json b/tests/test-infrastructure/configs_template/backend_config.json new file mode 100644 index 000000000..dbb489e80 --- /dev/null +++ b/tests/test-infrastructure/configs_template/backend_config.json @@ -0,0 +1,13 @@ +{ + "dbsyncconfig" : { + "host" : "postgres", + "dbname" : "${DBSYNC_DATABASE}", + "user" : "postgres", + "password" : "${POSTGRES_PASSWORD}", + "port" : 5432 + }, + "port" : 8080, + "host" : "0.0.0.0", + "cachedurationseconds": 20, + "sentrydsn": "https://username:password@senty.host/id" +} diff --git a/tests/test-infrastructure/deploy-swarm.sh b/tests/test-infrastructure/deploy-swarm.sh index 90c7fc269..d9d475971 100755 --- a/tests/test-infrastructure/deploy-swarm.sh +++ b/tests/test-infrastructure/deploy-swarm.sh @@ -5,9 +5,8 @@ ## ./deploy-swarm prepare ## set -eo pipefail -set -a -. ./.env -set +a +. ./scripts/deploy-stack.sh +load_env if [ "$1" == "destroy" ] then @@ -33,15 +32,14 @@ elif [ "$1" == "prepare" ] then ## apply the enviroment to services compose file ## and deploy the stack - envsubst < ./docker-compose-services.yml > ./docker-compose-services-rendered.yml - docker stack deploy -c './docker-compose-services-rendered.yml' ${STACK_NAME}-services + deploy-stack ${STACK_NAME}-services './docker-compose-services-rendered.yml' elif [ "$1" == "finalize" ] then ## apply the environment to compose file ## deploy the govtool test infrastructure stack - envsubst < ./docker-compose.yml > ./docker-compose-rendered.yml - docker stack deploy -c './docker-compose-rendered.yml' ${STACK_NAME} + deploy-stack ${STACK_NAME} './docker-compose-rendered.yml' + else echo "Something is wrong with the command" echo diff --git a/tests/test-infrastructure/docker-compose-govtool.yml b/tests/test-infrastructure/docker-compose-govtool.yml new file mode 100644 index 000000000..2d1e9ce25 --- /dev/null +++ b/tests/test-infrastructure/docker-compose-govtool.yml @@ -0,0 +1,51 @@ +version: "3.9" +networks: + frontend: + external: true + postgres: + external: true +configs: + config.json: + name: govtool_backend_config.json + external: true +services: + backend: + image: govtool/backend + build: + context: ../../govtool/backend + args: + BASE_IMAGE_TAG: govtool/backend-base + entrypoint: + - sh + - -c + - vva-be -c /config.json start-app + environment: + VIRTUAL_HOST: https://${BASE_DOMAIN} -> :8080 + VIRTUAL_HOST_2: https://${BASE_DOMAIN}/swagger -> :8080/swagger + VIRTUAL_HOST_3: https://${BASE_DOMAIN}/api/ -> :8080/ + + networks: + - frontend + - postgres + configs: + - config.json + deploy: + restart_policy: + delay: "30s" + placement: + constraints: + - node.labels.govtool==true + frontend: + image: govtool/frontend + build: + context: ../../govtool/frontend + environment: + VIRTUAL_HOST: https://${BASE_DOMAIN} + networks: + - frontend + deploy: + restart_policy: + delay: "30s" + placement: + constraints: + - node.labels.govtool==true \ No newline at end of file diff --git a/tests/test-infrastructure/docker-compose.yml b/tests/test-infrastructure/docker-compose.yml index 75281d5ef..73b26faa8 100644 --- a/tests/test-infrastructure/docker-compose.yml +++ b/tests/test-infrastructure/docker-compose.yml @@ -16,7 +16,8 @@ secrets: external: true name: ${STACK_NAME}_dbsync_database -## secrets syntax for docker compose stack +# secrets syntax for docker compose stack +## # secrets: # postgres_user: # file: "./secrets/${STACK_NAME}_postgres_user" diff --git a/tests/test-infrastructure/gen-configs.sh b/tests/test-infrastructure/gen-configs.sh index 38497990e..33b925726 100755 --- a/tests/test-infrastructure/gen-configs.sh +++ b/tests/test-infrastructure/gen-configs.sh @@ -15,10 +15,17 @@ set +a # Function to generate a random secret in base64 format without padding and '+' function generate_secret() { - openssl rand -base64 16 | tr -d '=+/' + local filename=$2 + local var_name=$1 + if [ -s "$filename" ]; then + export "$var_name"=$(<"$filename") + else + local secret=$(openssl rand -base64 16 | tr -d '=+/') + echo -n "$secret" > "$filename" + export "$var_name"="$secret" + fi } - if [ "$1" == "clean" ]; then # Create secrets from files @@ -45,35 +52,22 @@ if [ "$1" == "clean" ]; then exit 0 fi -## Check if one fo the secrets already exists -if [[ -f ./secrets/postgres_user ]] -then - echo "File ./secrets/postgres_user already exists." - echo "Assuming that the secrets were already generated" - echo " Use:" - echo " > ./gen-configs.sh clean" - echo " To clean up the configs and secrets" - exit 0 -fi - ## create dir if not present. mkdir -p ./configs; mkdir -p ./secrets; + # Generate random secrets export POSTGRES_USER=postgres -export POSTGRES_PASSWORD=$(generate_secret) -metrics_api_secret=$(generate_secret) -DBSYNC_DATABASE="${STACK_NAME}_dbsync" - - +export DBSYNC_DATABASE="${STACK_NAME}_dbsync" # Save secrets to files echo -n $POSTGRES_USER > ./secrets/postgres_user -echo -n $POSTGRES_PASSWORD > ./secrets/postgres_password -echo -n $metrics_api_secret > ./secrets/metrics_api_secret echo -n "$DBSYNC_DATABASE" > ./secrets/dbsync_database +# generate or load the secret +generate_secret "POSTGRES_PASSWORD" "./secrets/postgres_password" + ## loop over templates and update them. for CONFIG_FILE in $(ls ./configs_template) do @@ -96,7 +90,7 @@ docker info | grep 'Swarm: active' > /dev/null 2>/dev/null || exit 0 # Create secrets from files ls ./secrets | while IFS= read -r SECRET_FILE; do SECRET_NAME=$(basename "$SECRET_FILE") - echo -n "Creating Secret: ${STACK_NAME}_${SECRET_NAME}: " + echo -n "Secret: ${STACK_NAME}_${SECRET_NAME}: " cat "./secrets/$SECRET_NAME" | (docker secret create "${STACK_NAME}_${SECRET_NAME}" -) || true done @@ -105,6 +99,6 @@ done for CONFIG_FILE in $(ls ./configs) do CONFIG_NAME=$(basename $CONFIG_FILE) - echo -n "Creating Config: ${STACK_NAME}_${CONFIG_NAME}: " + echo -n "Config: ${STACK_NAME}_${CONFIG_NAME}: " cat "./configs/$CONFIG_NAME" | (docker config create "${STACK_NAME}_${CONFIG_NAME}" -) || true done \ No newline at end of file diff --git a/tests/test-infrastructure/scripts/deploy-stack.sh b/tests/test-infrastructure/scripts/deploy-stack.sh new file mode 100755 index 000000000..c1b942e34 --- /dev/null +++ b/tests/test-infrastructure/scripts/deploy-stack.sh @@ -0,0 +1,47 @@ +#!/bin/bash +## Docker swarm doesn't read .env file. +## This script reads env file and variables +## and apply them to compose file and +## then execute `docker stack deploy` + +set -eo pipefail + +function load_env(){ + set -a + . ./.env + set +a +} + +function help_deploy(){ + echo "Something is wrong with the command" + echo + echo " Usage:" + echo " $0 [stack-name] [filename]" + echo +} + +function deploy-stack(){ + ## apply the environment to compose file + ## deploy the govtool test infrastructure stack + ## first argument is stack name and 2nd argument is the file name + STACK_NAME=$1 + COMPOSE_FILE=$2 + FILENAME=$(basename -- "$COMPOSE_FILE") + EXTENSION="${FILENAME##*.}" + FILENAME_WITHOUT_EXT="${FILENAME%.*}" + RENDERED_FILENAME="${FILENAME_WITHOUT_EXT}-rendered.${EXTENSION}" + envsubst < "$COMPOSE_FILE" > "$RENDERED_FILENAME" + echo docker stack deploy -c "$RENDERED_FILENAME" ${STACK_NAME} +} + + +if [ "$#" -eq 0 ]; then + exit 0 +elif [ "$#" -ne 2 ]; +then + help_deploy + exit 1 +else + load_env + deploy-stack "$1" "$2" +fi From 1152f709ae62b51a379001e3d1621392b8d08cf5 Mon Sep 17 00:00:00 2001 From: Sudip Bhattarai Date: Tue, 7 May 2024 13:04:14 +0545 Subject: [PATCH 046/125] Update deploy command --- tests/test-infrastructure/deploy-swarm.sh | 30 ++++++++++++++++--- .../scripts/deploy-stack.sh | 25 ++-------------- 2 files changed, 29 insertions(+), 26 deletions(-) diff --git a/tests/test-infrastructure/deploy-swarm.sh b/tests/test-infrastructure/deploy-swarm.sh index d9d475971..5a700622a 100755 --- a/tests/test-infrastructure/deploy-swarm.sh +++ b/tests/test-infrastructure/deploy-swarm.sh @@ -5,6 +5,7 @@ ## ./deploy-swarm prepare ## set -eo pipefail +set -vx . ./scripts/deploy-stack.sh load_env @@ -32,22 +33,43 @@ elif [ "$1" == "prepare" ] then ## apply the enviroment to services compose file ## and deploy the stack - deploy-stack ${STACK_NAME}-services './docker-compose-services-rendered.yml' + deploy-stack ${STACK_NAME}-services './docker-compose-services.yml' elif [ "$1" == "finalize" ] then ## apply the environment to compose file ## deploy the govtool test infrastructure stack - deploy-stack ${STACK_NAME} './docker-compose-rendered.yml' - + deploy-stack ${STACK_NAME}-base './docker-compose.yml' +elif [ "$1" == 'stack' ] +then + if [ "$#" -ne 2 ] + then + echo 'stack requires the stack name "govtool" | "services" | "test"' + else + case "$2" in + govtool) + deploy-stack ${STACK_NAME} './docker-compose.yml' + ;; + services) + deploy-stack ${STACK_NAME}-services './docker-compose.yml' + ;; + base) + deploy-stack ${STACK_NAME}-base './docker-compose.yml' + ;; + *) + echo 'Invalid stack name. Valid options are "base", "services", or "govtool"' + ;; + esac + fi else echo "Something is wrong with the command" echo echo " Usage:" - echo " $0 (prepare | destroy | finalize)" + echo " $0 (prepare | destroy | finalize | deploy)" echo '' echo " Options:" echo " prepare -> deploys the services required by the test stack. i.e 'postgres' and 'reverse-proxy'" echo " finalize -> deploys the test infrastructure services" echo " destroy -> teardown everything except the volumes" + echo " deploy [stack_name] -> Deploy the stack." fi diff --git a/tests/test-infrastructure/scripts/deploy-stack.sh b/tests/test-infrastructure/scripts/deploy-stack.sh index c1b942e34..577eb5445 100755 --- a/tests/test-infrastructure/scripts/deploy-stack.sh +++ b/tests/test-infrastructure/scripts/deploy-stack.sh @@ -12,15 +12,8 @@ function load_env(){ set +a } -function help_deploy(){ - echo "Something is wrong with the command" - echo - echo " Usage:" - echo " $0 [stack-name] [filename]" - echo -} - function deploy-stack(){ + echo "++ deploy-stack" "$@" ## apply the environment to compose file ## deploy the govtool test infrastructure stack ## first argument is stack name and 2nd argument is the file name @@ -31,17 +24,5 @@ function deploy-stack(){ FILENAME_WITHOUT_EXT="${FILENAME%.*}" RENDERED_FILENAME="${FILENAME_WITHOUT_EXT}-rendered.${EXTENSION}" envsubst < "$COMPOSE_FILE" > "$RENDERED_FILENAME" - echo docker stack deploy -c "$RENDERED_FILENAME" ${STACK_NAME} -} - - -if [ "$#" -eq 0 ]; then - exit 0 -elif [ "$#" -ne 2 ]; -then - help_deploy - exit 1 -else - load_env - deploy-stack "$1" "$2" -fi + docker stack deploy -c "$RENDERED_FILENAME" ${STACK_NAME} +} \ No newline at end of file From d683b13ad55736de0f95e9d319de3e4652fc33ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Placzy=C5=84ski?= Date: Tue, 7 May 2024 12:15:51 +0200 Subject: [PATCH 047/125] Fix building analytics image for multiple environments The current commit modifies the script `analytics-dashboard.mk` in the `govtool` directory to address the issue of building the analytics image for multiple environments. Previously, the image tag was being generated based on the latest commit hash for the `analytics-dashboard`, which was not sufficient for distinguishing between different environments. To solve this, the script now appends the `$(env)` variable to the image tag, allowing for unique identification of images across various environments. --- scripts/govtool/analytics-dashboard.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/govtool/analytics-dashboard.mk b/scripts/govtool/analytics-dashboard.mk index 98d2ae7e3..59dae3974 100644 --- a/scripts/govtool/analytics-dashboard.mk +++ b/scripts/govtool/analytics-dashboard.mk @@ -7,7 +7,7 @@ endif .DEFAULT_GOAL := push-analytics-dashboard # image tags -analytics_dashboard_image_tag := $(shell git log -n 1 --format="%H" -- $(root_dir)/govtool/analytics-dashboard) +analytics_dashboard_image_tag := $(shell git log -n 1 --format="%H" -- $(root_dir)/govtool/analytics-dashboard)-$(env) .PHONY: build-analytics-dashboard build-analytics-dashboard: From db8bcefb9492d7b8d9e5f6d5fcc32a9bb4757e12 Mon Sep 17 00:00:00 2001 From: Sudip Bhattarai Date: Tue, 7 May 2024 16:12:51 +0545 Subject: [PATCH 048/125] Separate out individual stacks --- tests/test-infrastructure/deploy-swarm.sh | 23 +- ....yml => docker-compose-basic-services.yml} | 9 - .../docker-compose-cardano.yml | 102 ++++++++ .../docker-compose-govaction-loader.yml | 56 +++++ .../docker-compose-test.yml | 81 +++++++ tests/test-infrastructure/docker-compose.yml | 221 ------------------ 6 files changed, 251 insertions(+), 241 deletions(-) rename tests/test-infrastructure/{docker-compose-services.yml => docker-compose-basic-services.yml} (85%) create mode 100644 tests/test-infrastructure/docker-compose-cardano.yml create mode 100644 tests/test-infrastructure/docker-compose-govaction-loader.yml create mode 100644 tests/test-infrastructure/docker-compose-test.yml delete mode 100644 tests/test-infrastructure/docker-compose.yml diff --git a/tests/test-infrastructure/deploy-swarm.sh b/tests/test-infrastructure/deploy-swarm.sh index 5a700622a..71bb38d9e 100755 --- a/tests/test-infrastructure/deploy-swarm.sh +++ b/tests/test-infrastructure/deploy-swarm.sh @@ -33,13 +33,13 @@ elif [ "$1" == "prepare" ] then ## apply the enviroment to services compose file ## and deploy the stack - deploy-stack ${STACK_NAME}-services './docker-compose-services.yml' + deploy-stack ${STACK_NAME}-services './docker-compose-basic-services.yml' elif [ "$1" == "finalize" ] then ## apply the environment to compose file ## deploy the govtool test infrastructure stack - deploy-stack ${STACK_NAME}-base './docker-compose.yml' + deploy-stack ${STACK_NAME}-base './docker-compose-cardano.yml' elif [ "$1" == 'stack' ] then if [ "$#" -ne 2 ] @@ -47,17 +47,18 @@ then echo 'stack requires the stack name "govtool" | "services" | "test"' else case "$2" in - govtool) - deploy-stack ${STACK_NAME} './docker-compose.yml' - ;; - services) - deploy-stack ${STACK_NAME}-services './docker-compose.yml' - ;; - base) - deploy-stack ${STACK_NAME}-base './docker-compose.yml' + all) + for DEPLOY_STACK in "basic-services" "cardano" "govaction-loader" "govtool" "test"; do + deploy-stack $DEPLOY_STACK "docker-compose-$DEPLOY_STACK.yml" + done ;; *) - echo 'Invalid stack name. Valid options are "base", "services", or "govtool"' + if [[ ! -f ./"docker-compose-$2.yml" ]] + then + echo "Invalid stack name. $2" + else + deploy-stack $2 "docker-compose-$2.yml" + fi ;; esac fi diff --git a/tests/test-infrastructure/docker-compose-services.yml b/tests/test-infrastructure/docker-compose-basic-services.yml similarity index 85% rename from tests/test-infrastructure/docker-compose-services.yml rename to tests/test-infrastructure/docker-compose-basic-services.yml index d7563a2ad..96d9deaf6 100644 --- a/tests/test-infrastructure/docker-compose-services.yml +++ b/tests/test-infrastructure/docker-compose-basic-services.yml @@ -11,15 +11,6 @@ configs: external: true name: ${STACK_NAME}_postgres_db_setup.sql -### secrets and configs in docker compose -# secrets: -# postgres_user: -# file: "./secrets/${STACK_NAME}_postgres_user" -# postgres_password: -# file: "./secrets/${STACK_NAME}_postgres_password" -# configs: -# postgres_db_setup.sql: -# file: "./configs/${STACK_NAME}_postgres_db_setup.sql" volumes: postgres: nginx_dhparam: diff --git a/tests/test-infrastructure/docker-compose-cardano.yml b/tests/test-infrastructure/docker-compose-cardano.yml new file mode 100644 index 000000000..c9e3b69d6 --- /dev/null +++ b/tests/test-infrastructure/docker-compose-cardano.yml @@ -0,0 +1,102 @@ +version: "3.9" +secrets: + postgres_user: + external: true + name: ${STACK_NAME}_postgres_user + postgres_password: + external: true + name: ${STACK_NAME}_postgres_password + dbsync_database: + external: true + name: ${STACK_NAME}_dbsync_database + +volumes: + node_data: + node_ipc: + dbsync_data: + +networks: + postgres: + external: true + frontend: + external: true + cardano: + attachable: true + name: cardano + +services: + cardano-node: + image: ghcr.io/intersectmbo/cardano-node:8.10.0-pre + environment: + NETWORK: sanchonet + volumes: + - node_data:/data + - node_ipc:/ipc + stop_grace_period: 1m + logging: + driver: "json-file" + options: + max-size: "200k" + max-file: "10" + ports: + - target: 3001 + published: 30004 + protocol: tcp + mode: host + deploy: + placement: + constraints: + - node.labels.blockchain== true + restart_policy: + condition: on-failure + delay: 15s + dbsync: + image: ghcr.io/intersectmbo/cardano-db-sync:sancho-4-2-1 + networks: + - postgres + environment: + NETWORK: sanchonet + POSTGRES_HOST: postgres + POSTGRES_PORT: 5432 + DISABLE_CACHE: "" + DISABLE_LEDGER: "" + DISABLE_EPOCH: "" + secrets: + - postgres_user + - source: dbsync_database + target: postgres_db + - postgres_password + volumes: + - dbsync_data:/var/lib/cexplorer + - node_ipc:/node-ipc + logging: + driver: "json-file" + options: + max-size: "200k" + max-file: "10" + deploy: + labels: + "co_elastic_logs/enable": "false" + placement: + constraints: + - node.labels.blockchain== true + restart_policy: + condition: on-failure + delay: 15s + kuber: + image: dquadrant/kuber:4c3c5230db9a9b8ac84487fbc11ccd28b0cd5917-amd64 + environment: + CARDANO_NODE_SOCKET_PATH: /ipc/node.socket + VIRTUAL_HOST: https://kuber-${BASE_DOMAIN} + NETWORK: 4 + START_ERA: CONWAY + volumes: + - node_ipc:/ipc/ + networks: + - cardano + deploy: + placement: + constraints: + - node.labels.blockchain== true + restart_policy: + delay: "30s" diff --git a/tests/test-infrastructure/docker-compose-govaction-loader.yml b/tests/test-infrastructure/docker-compose-govaction-loader.yml new file mode 100644 index 000000000..96e10f556 --- /dev/null +++ b/tests/test-infrastructure/docker-compose-govaction-loader.yml @@ -0,0 +1,56 @@ +version: "3.9" + +networks: + frontend: + external: true + cardano: + external: true + +services: + + governance-action-loader-ui: + image: govtool/gov-action-loader-frontend + build: + context: ../../gov-action-loader/frontend + dockerfile: Dockerfile + environment: + VIRTUAL_HOST: https://governance-${BASE_DOMAIN} + networks: + - frontend + deploy: + placement: + constraints: + - node.labels.govtool-test-stack == true + restart_policy: + delay: "30s" + resources: + limits: + memory: 500M + reservations: + memory: 100M + + governance-action-loader-api: + image: govtool/gov-action-loader-backend + build: + context: ../../gov-action-loader/backend + dockerfile: Dockerfile + environment: + KUBER_API_URL: "http://kuber:8081" + KUBER_API_KEY: "" + BLOCKFROST_API_URL: "${BLOCKFROST_API_URL}" + BLOCKFROST_PROJECT_ID: "${BLOCKFROST_PROJECT_ID}" + VIRTUAL_HOST: https://governance-${BASE_DOMAIN}/api/ -> /api/ + networks: + - default + - frontend + deploy: + placement: + constraints: + - node.labels.govtool-test-stack == true + restart_policy: + delay: "30s" + resources: + limits: + memory: 1G + reservations: + memory: 500M \ No newline at end of file diff --git a/tests/test-infrastructure/docker-compose-test.yml b/tests/test-infrastructure/docker-compose-test.yml new file mode 100644 index 000000000..891e88253 --- /dev/null +++ b/tests/test-infrastructure/docker-compose-test.yml @@ -0,0 +1,81 @@ +version: "3.9" +secrets: + postgres_user: + external: true + name: ${STACK_NAME}_postgres_user + postgres_password: + external: true + name: ${STACK_NAME}_postgres_password + lighthouserc.json: + external: true + name: ${STACK_NAME}_lighthouserc.json + metrics_api_secret_token: + external: true + name: ${STACK_NAME}_metrics_api_secret + +volumes: + lhci_data: + node_data: + node_ipc: + dbsync_data: + +networks: + postgres: + external: true + frontend: + external: true + +services: + metrics_api: + image: voltaire-era/govtool-metrics-api + build: + context: ../test-metrics-api + environment: + VIRTUAL_HOST: https://metrics-${BASE_DOMAIN}/ -> :3000/ + PGHOST: postgres + PGDATABASE: ${STACK_NAME}_metrics + secrets: + - source: postgres_password + target: /run/secrets/pgpassword + - source: postgres_user + target: /run/secrets/pguser + - source: metrics_api_secret_token + target: /run/secrets/api_secret_token + networks: + - postgres + - frontend + deploy: + placement: + constraints: + - node.labels.govtool-test-stack == true + restart_policy: + delay: "30s" + resources: + limits: + memory: 600M + reservations: + memory: 100M + + lhci-server: + image: patrickhulce/lhci-server:0.12.0 + environment: + VIRTUAL_HOST: https://lighthouse-${BASE_DOMAIN} -> :9001 + volumes: + - lhci_data:/data + secrets: + - source: lighthouserc.json + target: /usr/src/lhci/lighthouserc.json + networks: + - postgres + - frontend + deploy: + placement: + constraints: + - node.labels.govtool-test-stack == true + restart_policy: + delay: "30s" + resources: + limits: + memory: 1G + reservations: + memory: 300M \ No newline at end of file diff --git a/tests/test-infrastructure/docker-compose.yml b/tests/test-infrastructure/docker-compose.yml deleted file mode 100644 index 73b26faa8..000000000 --- a/tests/test-infrastructure/docker-compose.yml +++ /dev/null @@ -1,221 +0,0 @@ -version: "3.9" -secrets: - postgres_user: - external: true - name: ${STACK_NAME}_postgres_user - postgres_password: - external: true - name: ${STACK_NAME}_postgres_password - lighthouserc.json: - external: true - name: ${STACK_NAME}_lighthouserc.json - metrics_api_secret_token: - external: true - name: ${STACK_NAME}_metrics_api_secret - dbsync_database: - external: true - name: ${STACK_NAME}_dbsync_database - -# secrets syntax for docker compose stack -## -# secrets: -# postgres_user: -# file: "./secrets/${STACK_NAME}_postgres_user" -# postgres_password: -# file: "./secrets/${STACK_NAME}_postgres_password" -# postgres_db: -# file: "./secrets/${STACK_NAME}_postgres_user" -# lighthouserc.json: -# file: "./secrets/${STACK_NAME}_lighthouserc.json" -# metrics_api_secret_token: -# file: "./secrets/${STACK_NAME}_metrics_api_secret" -volumes: - lhci_data: - sonar_data: - sonar_logs: - node_data: - node_ipc: - dbsync_data: - -networks: - postgres: - external: true - frontend: - external: true - -services: - metrics_api: - image: voltaire-era/govtool-metrics-api - build: - context: ../test-metrics-api - - environment: - VIRTUAL_HOST: https://metrics-${BASE_DOMAIN}/ -> :3000/ - PGHOST: postgres - PGDATABASE: ${STACK_NAME}_metrics - secrets: - - source: postgres_password - target: /run/secrets/pgpassword - - source: postgres_user - target: /run/secrets/pguser - - source: metrics_api_secret_token - target: /run/secrets/api_secret_token - networks: - - postgres - - frontend - deploy: - placement: - constraints: - - node.labels.govtool-test-stack == true - restart_policy: - delay: "30s" - resources: - limits: - memory: 600M - reservations: - memory: 100M - - lhci-server: - image: patrickhulce/lhci-server:0.12.0 - environment: - VIRTUAL_HOST: https://lighthouse-${BASE_DOMAIN} -> :9001 - volumes: - - lhci_data:/data - secrets: - - source: lighthouserc.json - target: /usr/src/lhci/lighthouserc.json - networks: - - postgres - - frontend - deploy: - placement: - constraints: - - node.labels.govtool-test-stack == true - restart_policy: - delay: "30s" - resources: - limits: - memory: 1G - reservations: - memory: 300M - - governance-action-loader-ui: - image: voltaire-era/govtool-governance-action-loader - build: - context: ../../gov-action-loader/frontend - dockerfile: Dockerfile - environment: - VIRTUAL_HOST: https://governance-${BASE_DOMAIN} - networks: - - frontend - deploy: - placement: - constraints: - - node.labels.govtool-test-stack == true - restart_policy: - delay: "30s" - resources: - limits: - memory: 500M - reservations: - memory: 100M - - governance-action-loader-api: - image: voltaire-era/govtool-kuber-proposal-loader-proxy - build: - context: ../../gov-action-loader/backend - dockerfile: Dockerfile - environment: - KUBER_API_URL: "http://kuber:8081" - KUBER_API_KEY: "" - BLOCKFROST_API_URL: "${BLOCKFROST_API_URL}" - BLOCKFROST_PROJECT_ID: "${BLOCKFROST_PROJECT_ID}" - VIRTUAL_HOST: https://governance-${BASE_DOMAIN}/api/ -> /api/ - networks: - - default - - frontend - deploy: - placement: - constraints: - - node.labels.govtool-test-stack == true - restart_policy: - delay: "30s" - resources: - limits: - memory: 1G - reservations: - memory: 500M - - cardano-node: - image: ghcr.io/intersectmbo/cardano-node:8.10.0-pre - environment: - NETWORK: sanchonet - volumes: - - node_data:/data - - node_ipc:/ipc - stop_grace_period: 1m - logging: - driver: "json-file" - options: - max-size: "200k" - max-file: "10" - ports: - - target: 3001 - published: 30004 - protocol: tcp - mode: host - deploy: - placement: - constraints: - - node.labels.govtool-test-stack == true - restart_policy: - condition: on-failure - delay: 15s - dbsync: - image: ghcr.io/intersectmbo/cardano-db-sync:sancho-4-2-1 - networks: - - postgres - environment: - NETWORK: sanchonet - POSTGRES_HOST: postgres - POSTGRES_PORT: 5432 - DISABLE_CACHE: "" - DISABLE_LEDGER: "" - DISABLE_EPOCH: "" - secrets: - - postgres_user - - source: dbsync_database - target: postgres_db - - postgres_password - volumes: - - dbsync_data:/var/lib/cexplorer - - node_ipc:/node-ipc - logging: - driver: "json-file" - options: - max-size: "200k" - max-file: "10" - deploy: - labels: - "co_elastic_logs/enable": "false" - placement: - constraints: - - node.labels.govtool-test-stack == true - restart_policy: - condition: on-failure - delay: 15s - kuber: - image: dquadrant/kuber:4c3c5230db9a9b8ac84487fbc11ccd28b0cd5917-amd64 - environment: - CARDANO_NODE_SOCKET_PATH: /ipc/node.socket - VIRTUAL_HOST: https://kuber-${BASE_DOMAIN} - NETWORK: 4 - START_ERA: CONWAY - volumes: - - node_ipc:/ipc/ - deploy: - placement: - constraints: - - node.labels.govtool-test-stack == true - restart_policy: - delay: "30s" From 492b2a012223256454233a9dff13dd6a85479b57 Mon Sep 17 00:00:00 2001 From: Jan Jaroszczak Date: Tue, 7 May 2024 12:44:26 +0200 Subject: [PATCH 049/125] [#897] Slow delegation issue // usePendingTransaction fixes --- .../pendingTransaction/usePendingTransaction.ts | 9 ++++++++- .../frontend/src/context/pendingTransaction/utils.tsx | 10 ++++++++-- govtool/frontend/src/hooks/useDelegateToDrep.ts | 5 +---- 3 files changed, 17 insertions(+), 7 deletions(-) diff --git a/govtool/frontend/src/context/pendingTransaction/usePendingTransaction.ts b/govtool/frontend/src/context/pendingTransaction/usePendingTransaction.ts index cd47982b0..8828d62eb 100644 --- a/govtool/frontend/src/context/pendingTransaction/usePendingTransaction.ts +++ b/govtool/frontend/src/context/pendingTransaction/usePendingTransaction.ts @@ -80,6 +80,7 @@ export const usePendingTransaction = ({ if (status.transactionConfirmed) { clearInterval(interval); + if (isEnabled) { const desiredResult = getDesiredResult(type, resourceId); const queryKey = getQueryKey(type, transaction); @@ -89,7 +90,13 @@ export const usePendingTransaction = ({ while (!isDBSyncUpdated && count < DB_SYNC_MAX_ATTEMPTS) { count++; // eslint-disable-next-line no-await-in-loop - const data = await refetchData(type, queryClient, queryKey); + const data = await refetchData( + type, + queryClient, + queryKey, + resourceId, + ); + if (desiredResult === data) { addSuccessAlert(t(`alerts.${type}.success`)); resetTransaction(); diff --git a/govtool/frontend/src/context/pendingTransaction/utils.tsx b/govtool/frontend/src/context/pendingTransaction/utils.tsx index 96d553071..38c80fc77 100644 --- a/govtool/frontend/src/context/pendingTransaction/utils.tsx +++ b/govtool/frontend/src/context/pendingTransaction/utils.tsx @@ -50,6 +50,7 @@ export const refetchData = async ( type: TransactionType, queryClient: QueryClient, queryKey: QueryKey | undefined, + resourceId: string | undefined, ) => { if (queryKey === undefined) return; @@ -58,10 +59,15 @@ export const refetchData = async ( // eslint-disable-next-line @typescript-eslint/no-explicit-any const data = await queryClient.getQueryData(queryKey); - if (type === "delegate") return data; + if (type === "delegate") { + if (resourceId === "no confidence" || resourceId === "abstain") { + return data.dRepView; + } + return data.dRepHash; + } if (type === "registerAsDrep" || type === "retireAsDrep") return data.isRegisteredAsDRep; if (type === "registerAsDirectVoter" || type === "retireAsDirectVoter") - return data.isRegisteredAsDirectVoter; + return data.isRegisteredAsSoleVoter; return undefined; }; diff --git a/govtool/frontend/src/hooks/useDelegateToDrep.ts b/govtool/frontend/src/hooks/useDelegateToDrep.ts index 718a17ef7..9a835951f 100644 --- a/govtool/frontend/src/hooks/useDelegateToDrep.ts +++ b/govtool/frontend/src/hooks/useDelegateToDrep.ts @@ -33,15 +33,12 @@ export const useDelegateTodRep = () => { ); certBuilder.add(retirementCert); } - const result = await buildSignSubmitConwayCertTx({ + await buildSignSubmitConwayCertTx({ certBuilder, type: "delegate", resourceId: dRepId, voter, }); - if (result) { - addSuccessAlert(t("alerts.delegate.success")); - } } catch (error) { openWalletErrorModal({ error, From 05d1462e595db64eb4c586915c32c43cb0b65bc6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Sworze=C5=84?= Date: Tue, 7 May 2024 12:58:25 +0200 Subject: [PATCH 050/125] add simple README for wallet-connector --- govtool/packages/wallet-connector/README.md | 56 +++++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 govtool/packages/wallet-connector/README.md diff --git a/govtool/packages/wallet-connector/README.md b/govtool/packages/wallet-connector/README.md new file mode 100644 index 000000000..77638db0b --- /dev/null +++ b/govtool/packages/wallet-connector/README.md @@ -0,0 +1,56 @@ +# Wallet Service + +The WalletService.ts file contains the implementation of a wallet service, designed to manage wallet. It includes the enableWallet function responsible for enabling the wallet connection and allows get cip95 functions. + +1. Install wallet-connector package. + +```sh +yarn install wallet-connector +``` + +2. Import service from wallet-connector. + +```javascript +import { WalletService } from "@wallet-connector"; +``` + +3. Usage - for enable your browser wallet extension. + EXAMPLE: + +```javascript +const newWalletAPI = await WalletService.enableWallet("%WALLET_NAME%"); +``` + +# Wallet Provider + +WalletProvider component which serves as a React Context Provider to facilitate wallet integration across components. + +1. Install wallet-connector package + +```sh +yarn install wallet-connector +``` + +2. Import WalletProvider from wallet-connector and wrap your app. + +```javascript +import { WalletProvider } from "@wallet-connector"; + + + +; +``` + +3. Usage + +```javascript +import { useWalletContext } from "@wallet-connector"; + +const { + disconnectWallet, + enableError, + enableWallet, + isEnableLoading, + walletAPI, +} = useWalletContext(); +``` From 731facb97ce776dee97bbdfe764043c420ac6b07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Sworze=C5=84?= Date: Tue, 7 May 2024 13:00:00 +0200 Subject: [PATCH 051/125] change install to add --- govtool/packages/wallet-connector/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/govtool/packages/wallet-connector/README.md b/govtool/packages/wallet-connector/README.md index 77638db0b..43aef18cf 100644 --- a/govtool/packages/wallet-connector/README.md +++ b/govtool/packages/wallet-connector/README.md @@ -5,7 +5,7 @@ The WalletService.ts file contains the implementation of a wallet service, desig 1. Install wallet-connector package. ```sh -yarn install wallet-connector +yarn add wallet-connector ``` 2. Import service from wallet-connector. @@ -28,7 +28,7 @@ WalletProvider component which serves as a React Context Provider to facilitate 1. Install wallet-connector package ```sh -yarn install wallet-connector +yarn add wallet-connector ``` 2. Import WalletProvider from wallet-connector and wrap your app. From c9d0c5a8fde514a38c3bf22d9387cebb9b79cc37 Mon Sep 17 00:00:00 2001 From: Jan Jaroszczak Date: Tue, 7 May 2024 22:53:29 +0200 Subject: [PATCH 052/125] [#920 - bug 2] DRep details page Back button fix --- govtool/frontend/src/pages/DRepDetails.tsx | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/govtool/frontend/src/pages/DRepDetails.tsx b/govtool/frontend/src/pages/DRepDetails.tsx index f33a20880..440e93750 100644 --- a/govtool/frontend/src/pages/DRepDetails.tsx +++ b/govtool/frontend/src/pages/DRepDetails.tsx @@ -76,12 +76,8 @@ export const DRepDetails = ({ isConnected }: DRepDetailsProps) => { <> - navigate( - isConnected ? PATHS.dashboardDRepDirectory : PATHS.dRepDirectory, - ) - } + label={t("back")} + onClick={() => navigate(-1)} sx={{ mb: 2 }} /> Date: Sat, 4 May 2024 17:11:03 +0545 Subject: [PATCH 053/125] Add playwright tests --- .../govtool-frontend/playwright/.env.example | 18 +- tests/govtool-frontend/playwright/.gitignore | 16 + .../playwright/.prettierignore | 6 + .../playwright/lib/constants/environments.ts | 23 + .../playwright/lib/constants/staticWallets.ts | 122 + .../playwright/lib/datafactory/createAuth.ts | 44 + .../playwright/lib/fixtures/createWallet.ts | 34 + .../playwright/lib/fixtures/importWallet.ts | 14 + .../playwright/lib/fixtures/loadExtension.ts | 28 + .../lib/fixtures/walletExtension.ts | 25 + .../lib/helpers/cborEncodeDecode.ts | 7 + .../playwright/lib/helpers/computeTxHash.ts | 8 + .../lib/helpers/convertBufferToHex.ts | 3 + .../playwright/lib/helpers/crypto.ts | 251 + .../helpers/extractDRepsFromStakePubkey.ts | 10 + .../lib/helpers/generateShellyWallets.ts | 15 + .../playwright/lib/helpers/page.ts | 25 + .../playwright/lib/helpers/removeAllSpaces.ts | 3 + .../playwright/lib/helpers/setupWallets.ts | 23 + .../playwright/lib/helpers/transaction.ts | 52 + .../playwright/lib/lockInterceptor.ts | 132 + .../lib/pages/dRepRegistrationPage.ts | 52 + .../playwright/lib/pages/delegationPage.ts | 51 + .../lib/pages/governanceActionDetailsPage.ts | 53 + .../lib/pages/governanceActionsPage.ts | 159 + .../playwright/lib/pages/loginPage.ts | 62 + .../playwright/lib/services/faucetService.ts | 34 + .../playwright/lib/services/kuberService.ts | 417 ++ .../govtool-frontend/playwright/lib/types.ts | 52 + .../playwright/package-lock.json | 5158 +++++++++++++++++ .../govtool-frontend/playwright/package.json | 45 + .../playwright/playwright.config.ts | 57 +- .../walletConnect.loggedin.spec.ts | 13 + .../1-wallet-connect/walletConnect.spec.ts | 52 + .../2-delegation/delegation.dRep.spec.ts | 66 + .../2-delegation/delegation.loggedin.spec.ts | 49 + .../tests/2-delegation/delegation.spec.ts | 14 + .../tests/2-delegation/delegation.tx.spec.ts | 21 + .../dRepRegistration.dRep.spec.ts | 127 + .../dRepRegistration.loggedin.spec.ts | 65 + .../dRepRegistration.spec.ts | 10 + .../dRepRegistration.tx.spec.ts | 16 + .../proposalVisibility.loggedin.spec.ts | 120 + .../proposalVisibility.spec.ts | 21 + .../proposalFunctionality.dRep.spec.ts | 182 + .../miscellaneous.loggedin.spec.ts | 34 + .../6-miscellaneous/miscellaneous.spec.ts | 31 + .../playwright/tests/adaholder.teardown.ts | 15 + .../playwright/tests/auth.setup.ts | 44 + .../playwright/tests/dRep.setup.ts | 42 + .../playwright/tests/wallet.bootstrap.ts | 81 + .../govtool-frontend/playwright/tsconfig.json | 17 + 52 files changed, 8005 insertions(+), 14 deletions(-) create mode 100644 tests/govtool-frontend/playwright/.gitignore create mode 100644 tests/govtool-frontend/playwright/.prettierignore create mode 100644 tests/govtool-frontend/playwright/lib/constants/environments.ts create mode 100644 tests/govtool-frontend/playwright/lib/constants/staticWallets.ts create mode 100644 tests/govtool-frontend/playwright/lib/datafactory/createAuth.ts create mode 100644 tests/govtool-frontend/playwright/lib/fixtures/createWallet.ts create mode 100644 tests/govtool-frontend/playwright/lib/fixtures/importWallet.ts create mode 100644 tests/govtool-frontend/playwright/lib/fixtures/loadExtension.ts create mode 100644 tests/govtool-frontend/playwright/lib/fixtures/walletExtension.ts create mode 100644 tests/govtool-frontend/playwright/lib/helpers/cborEncodeDecode.ts create mode 100644 tests/govtool-frontend/playwright/lib/helpers/computeTxHash.ts create mode 100644 tests/govtool-frontend/playwright/lib/helpers/convertBufferToHex.ts create mode 100644 tests/govtool-frontend/playwright/lib/helpers/crypto.ts create mode 100644 tests/govtool-frontend/playwright/lib/helpers/extractDRepsFromStakePubkey.ts create mode 100644 tests/govtool-frontend/playwright/lib/helpers/generateShellyWallets.ts create mode 100644 tests/govtool-frontend/playwright/lib/helpers/page.ts create mode 100644 tests/govtool-frontend/playwright/lib/helpers/removeAllSpaces.ts create mode 100644 tests/govtool-frontend/playwright/lib/helpers/setupWallets.ts create mode 100644 tests/govtool-frontend/playwright/lib/helpers/transaction.ts create mode 100644 tests/govtool-frontend/playwright/lib/lockInterceptor.ts create mode 100644 tests/govtool-frontend/playwright/lib/pages/dRepRegistrationPage.ts create mode 100644 tests/govtool-frontend/playwright/lib/pages/delegationPage.ts create mode 100644 tests/govtool-frontend/playwright/lib/pages/governanceActionDetailsPage.ts create mode 100644 tests/govtool-frontend/playwright/lib/pages/governanceActionsPage.ts create mode 100644 tests/govtool-frontend/playwright/lib/pages/loginPage.ts create mode 100644 tests/govtool-frontend/playwright/lib/services/faucetService.ts create mode 100644 tests/govtool-frontend/playwright/lib/services/kuberService.ts create mode 100644 tests/govtool-frontend/playwright/lib/types.ts create mode 100644 tests/govtool-frontend/playwright/package-lock.json create mode 100644 tests/govtool-frontend/playwright/package.json create mode 100644 tests/govtool-frontend/playwright/tests/1-wallet-connect/walletConnect.loggedin.spec.ts create mode 100644 tests/govtool-frontend/playwright/tests/1-wallet-connect/walletConnect.spec.ts create mode 100644 tests/govtool-frontend/playwright/tests/2-delegation/delegation.dRep.spec.ts create mode 100644 tests/govtool-frontend/playwright/tests/2-delegation/delegation.loggedin.spec.ts create mode 100644 tests/govtool-frontend/playwright/tests/2-delegation/delegation.spec.ts create mode 100644 tests/govtool-frontend/playwright/tests/2-delegation/delegation.tx.spec.ts create mode 100644 tests/govtool-frontend/playwright/tests/3-drep-registration/dRepRegistration.dRep.spec.ts create mode 100644 tests/govtool-frontend/playwright/tests/3-drep-registration/dRepRegistration.loggedin.spec.ts create mode 100644 tests/govtool-frontend/playwright/tests/3-drep-registration/dRepRegistration.spec.ts create mode 100644 tests/govtool-frontend/playwright/tests/3-drep-registration/dRepRegistration.tx.spec.ts create mode 100644 tests/govtool-frontend/playwright/tests/4-proposal-visibility/proposalVisibility.loggedin.spec.ts create mode 100644 tests/govtool-frontend/playwright/tests/4-proposal-visibility/proposalVisibility.spec.ts create mode 100644 tests/govtool-frontend/playwright/tests/5-proposal-functionality/proposalFunctionality.dRep.spec.ts create mode 100644 tests/govtool-frontend/playwright/tests/6-miscellaneous/miscellaneous.loggedin.spec.ts create mode 100644 tests/govtool-frontend/playwright/tests/6-miscellaneous/miscellaneous.spec.ts create mode 100644 tests/govtool-frontend/playwright/tests/adaholder.teardown.ts create mode 100644 tests/govtool-frontend/playwright/tests/auth.setup.ts create mode 100644 tests/govtool-frontend/playwright/tests/dRep.setup.ts create mode 100644 tests/govtool-frontend/playwright/tests/wallet.bootstrap.ts create mode 100644 tests/govtool-frontend/playwright/tsconfig.json diff --git a/tests/govtool-frontend/playwright/.env.example b/tests/govtool-frontend/playwright/.env.example index c5f2ff3d1..7dbc8561a 100644 --- a/tests/govtool-frontend/playwright/.env.example +++ b/tests/govtool-frontend/playwright/.env.example @@ -1,13 +1,13 @@ -FRONTEND_URL=http://localhost:8080 -API_URL=http://localhost:8080/api +FRONTEND_URL=http://localhost:3000 +API_URL=http://localhost:3000/api DOCS_URL=https://docs.sanchogov.tools -# 1 for testnet, 0 for mainnet -NETWORK_ID=1, +# 0 for testnet, 1 for mainnet +NETWORK_ID=0 # Create mock wallets if true -ONE_TIME_WALLET_SETUP=false, +ONE_TIME_WALLET_SETUP=false # Faucet FAUCET_API_URL=https://faucet.sanchonet.world.dev.cardano.org @@ -15,4 +15,10 @@ FAUCET_API_KEY= # Kuber KUBER_API_URL=https://sanchonet.kuber.cardanoapi.io -KUBER_API_KEY= \ No newline at end of file +KUBER_API_KEY= + +# Transaction timeout +TX_TIMEOUT=120000 # milliseconds + +# Metadata Bucket +METADATA_BUCKET_URL=https://metadata.cardanoapi.io/data \ No newline at end of file diff --git a/tests/govtool-frontend/playwright/.gitignore b/tests/govtool-frontend/playwright/.gitignore new file mode 100644 index 000000000..0a969ff71 --- /dev/null +++ b/tests/govtool-frontend/playwright/.gitignore @@ -0,0 +1,16 @@ +node_modules/ +/test-results/ +/playwright-report/ +/blob-report/ +/playwright/.cache/ +.env +tests-out/ +.auth/ +.download/ +lib/_mock/ +allure-results/ +allure-report/ +.secrets +.vars +.lock-pool/ +.logs/ diff --git a/tests/govtool-frontend/playwright/.prettierignore b/tests/govtool-frontend/playwright/.prettierignore new file mode 100644 index 000000000..944d08317 --- /dev/null +++ b/tests/govtool-frontend/playwright/.prettierignore @@ -0,0 +1,6 @@ +# Ignore artifacts: +.github +node_modules +playwright-report +test-results +playwright.config.ts diff --git a/tests/govtool-frontend/playwright/lib/constants/environments.ts b/tests/govtool-frontend/playwright/lib/constants/environments.ts new file mode 100644 index 000000000..f4474c818 --- /dev/null +++ b/tests/govtool-frontend/playwright/lib/constants/environments.ts @@ -0,0 +1,23 @@ +const environments = { + frontendUrl: process.env.HOST_URL || "http://localhost:5173", + apiUrl: `${process.env.HOST_URL}/api` || "http://localhost:9999", + docsUrl: process.env.DOCS_URL || "https://docs.sanchogov.tools", + networkId: parseInt(process.env.NETWORK_ID) || 0, + oneTimeWalletSetup: process.env.ONE_TIME_WALLET_SETUP === "true" || false, + faucet: { + apiUrl: + process.env.FAUCET_API_URL || + "https://faucet.sanchonet.world.dev.cardano.org", + apiKey: process.env.FAUCET_API_KEY || "", + }, + kuber: { + apiUrl: + process.env.KUBER_API_URL || "https://sanchonet.kuber.cardanoapi.io", + apiKey: process.env.KUBER_API_KEY || "", + }, + txTimeOut: parseInt(process.env.TX_TIMEOUT) || 120000, + metadataBucketUrl: + process.env.METADATA_BUCKET_URL || "https://metadata.cardanoapi.io/data", +}; + +export default environments; diff --git a/tests/govtool-frontend/playwright/lib/constants/staticWallets.ts b/tests/govtool-frontend/playwright/lib/constants/staticWallets.ts new file mode 100644 index 000000000..037ccd3ce --- /dev/null +++ b/tests/govtool-frontend/playwright/lib/constants/staticWallets.ts @@ -0,0 +1,122 @@ +import { StaticWallet } from "@types"; + +export const faucetWallet: StaticWallet = { + payment: { + pkh: "b5187cdefbc5b49ddc17b423c079f0717721a03882a3b265bd4c12e0", + private: "11abec096ef0ea7edbeeee01a1a3f0e9f24a7225c2ee99687fb328146fe85ba6", + public: "b6a42d4ccc4d26adaec67e8578bf31f13b1b7e640527356248f2ec547f9de6e4", + }, + stake: { + pkh: "80f326af300273d19d5a541d45baa42ebc04265816735b026b5f34a4", + private: "283fd7625ef596f04f21b50ee14a9f4b49f8b1a6f17773cd2e1e69841a111bc1", + public: "86b08ee3d86cb72d026197a5a710e248d66f28fcff21b4467b75f876b4e6d050", + }, + dRepId: "drep1zg6zq3ku422ppvfm835rnvzf9ckxtzmy3ayjwylck6s4q9zr5ve", + address: + "addr_test1qz63slx7l0zmf8wuz76z8sre7pchwgdq8zp28vn9h4xp9cyq7vn27vqzw0ge6kj5r4zm4fpwhszzvkqkwddsy66lxjjqxnc9zk", +}; + +export const dRep01Wallet: StaticWallet = { + payment: { + private: "2f1053f22707b9881ea6112024027a660bd5508e22081cf5e4e95cc663802dd9", + public: "891ed5096ee248bc7f31a3094ea90f34485483eb1050c7ee368e64d04b90a009", + pkh: "5775ad2fb14ca1b45381a40e40f0c06081edaf2261e02bbcebcf8dc3", + }, + stake: { + private: "39db531b1ba6d659f0e09ed609e86a080ba2a5629dc5fad3b29890bdba64a014", + public: "45a35ffab6c467531ee528fbdbe1a629de806c7af19dcb5aacb70e4286fd6b9a", + pkh: "46a95c1337b27332131f3c1b9d8e7689edd2f593e7e69bf5dcf0c278", + }, + address: + "addr_test1qpthttf0k9x2rdznsxjqus8scpsgrmd0yfs7q2aua08cms6x49wpxdajwvepx8eurwwcua5fahf0tyl8u6dlth8scfuqk8r352", + dRepId: "drep1g654cyehkfenyycl8sdemrnk38ka9avnulnfhawu7rp8skl824l", +}; + +// export const dRep02Wallet: StaticWallet = { +// payment: { +// private: "71120ea01dc0c367da113a7ee7b3744a46f793edb4f30a06b46d800324b2c999", +// public: "66724455eaacb6dea6686ba09bc159d5deef3d82ebf9c6a60d61748b59e32627", +// pkh: "363547ffb44d337f8055515e75e8af516e557b3270bfa4d9198e7195", +// }, +// stake: { +// private: "4dfc89a9d680b237146dde69282c709e93ba91ac0b028e980bc40ec573c77f0f", +// public: "009c10056aff887d66135886d1fb9f046190bdf1d90a3f9cff954386f7cf37fb", +// pkh: "4d52d1d178157ab4c5ab6f8cb109ff91f750b367830463ef8344007e", +// }, +// address: +// "addr_test1qqmr23llk3xnxluq24g4ua0g4agku4tmxfctlfxerx88r92d2tgaz7q4026vt2m03jcsnlu37agtxeurq337lq6yqplqftpnqu", +// dRepId: "drep1f4fdr5tcz4atf3dtd7xtzz0lj8m4pvm8svzx8murgsq8u6dkmf4", +// }; + +export const adaHolder01Wallet: StaticWallet = { + payment: { + private: "63be29a8c8a73571ab410062f4555998c45a61f96a9bf1c5308c4f3eb7e4453f", + public: "dd1e7ca0deb26499a1336fbe2a5169ba3043a27763bb9e600625a95728be6167", + pkh: "daa1dd48181133eb21a376da773a1d31f72281008d790ecac885ff97", + }, + stake: { + private: "13e9e60b51768367c0d4c07a9f02b90d6511a9d7f7215b465fd87488171c687f", + public: "2819c4d6a988746ac7f5be3edc93c86d4cd0e3fae9c23a6ceeb23e6d0b207ad0", + pkh: "56ffa2a26e57c5b14c7c8d58455ebc24ce628f1c456be7e2e7448c8f", + }, + address: + "addr_test1qrd2rh2grqgn86ep5dmd5ae6r5clwg5pqzxhjrk2ezzll96kl732ymjhckc5clydtpz4a0pyee3g78z9d0n79e6y3j8smc7gzu", + dRepId: "drep12ml69gnw2lzmznru34vy2h4uyn8x9rcug4470ch8gjxg74htere", +}; + +export const adaHolder02Wallet: StaticWallet = { + payment: { + private: "6794cee96fd24aa68ae6e7df8548c15c6faf0373fc53c9714517b7c09b2ba6c0", + public: "58df2c02b5a2af09b51d5357f675b4f13ee019db57686adaab7536f6a3b8c29f", + pkh: "aec3d01a7fa061d027e945aedcfcb8e32eab0390063d19ef8ab89a88", + }, + stake: { + private: "cb4fa9d68add76c15b2b16b4bb7aeab043d95f42f4adec3d9d50396e6d1760e4", + public: "45dec9c5c130c23b1b9fedda680bdf1658e918087bd0f51c5548c471ca7d2991", + pkh: "49da6cb42b23f1c1f25f85e91dd325414b154f036bbf43a69dea27ee", + }, + address: + "addr_test1qzhv85q607sxr5p8a9z6ah8uhr3ja2crjqrr6x0032uf4zzfmfktg2er78qlyhu9aywaxf2pfv257qmthap6d802ylhqvz8qsf", + dRepId: "drep1f8dxedpty0curujlsh53m5e9g9932ncrdwl58f5aagn7u9psjya", +}; + +// export const soleVoterWallet: StaticWallet = { +// payment: { +// private: "98d35ef14dedc4520ed0153bc41e4db884deb0390f659ee1e28bb52da6045d4e", +// public: "5206735d1a1a1ac4ac625c973581ed97daec145d2e47a5c9bb14754527929f78", +// pkh: "0b5aa57cfd8010b00c649bf281520514de4efd952eba9c31eb7db187", +// }, +// stake: { +// private: "95ae1de1c2984c18207b8f57c450f1fbc54c2f0f1b878d3b24df11157277e1d1", +// public: "3bca5cb3599020808f69df269eb42b0e66ecf7455fb969e90c46ae0ac55e6572", +// pkh: "97265a1e13717c04a85e7d6dc156ba38340645b1e812a935823092f9", +// }, +// address: +// "addr_test1qq944ftulkqppvqvvjdl9q2jq52dunhaj5ht48p3ad7mrpuhyedpuym30sz2shnadhq4dw3cxsrytv0gz25ntq3sjtusesfzgd", +// dRepId: "drep1jun958snw97qf2z704kuz4468q6qv3d3aqf2jdvzxzf0jtlmwlf", +// }; + +// Does not takes part in transaction +export const user01Wallet: StaticWallet = { + payment: { + private: "a84d81412e41b55f9a484ce2cb5849660c7a8874df7ea11cb48120ec8efd2911", + public: "18cc2696ff588c19789f908df838fc58dd58986ebf6191b7b63d310c997f968b", + pkh: "56a6427fa7f8599d1e49271eb8123d0e02bc06bd44fc2d988e25455a", + }, + stake: { + private: "c3d9fde8d81c1533ab9a1e6fdbaddd792dfba8f58656c95e83f5e967087f4605", + public: "dd50a02daa77061ecd2d43d6fa1049e3db0192b94112ffc4f4e48975362987ff", + pkh: "cac600470e3b3027bf3ad3c363c35c690a54308bd001120194c1ba0b", + }, + address: + "addr_test1qpt2vsnl5lu9n8g7fyn3awqj858q90qxh4z0ctvc3cj52kk2ccqywr3mxqnm7wkncd3uxhrfpf2rpz7sqyfqr9xphg9s77zxlg", + dRepId: "drep1etrqq3cw8vcz00e660pk8s6udy99gvyt6qq3yqv5cxaqkuupyzg", +}; + +export const adaHolderWallets = [adaHolder01Wallet, adaHolder02Wallet]; + +export const userWallets = [user01Wallet]; + +export const dRepWallets = [dRep01Wallet]; + +// export const soleVoterWallets = [soleVoterWallet]; diff --git a/tests/govtool-frontend/playwright/lib/datafactory/createAuth.ts b/tests/govtool-frontend/playwright/lib/datafactory/createAuth.ts new file mode 100644 index 000000000..d297f0ddf --- /dev/null +++ b/tests/govtool-frontend/playwright/lib/datafactory/createAuth.ts @@ -0,0 +1,44 @@ +// Saves storage state to a file in the .auth directory + +import { importWallet } from "@fixtures/importWallet"; +import { ShelleyWallet } from "@helpers/crypto"; +import LoginPage from "@pages/loginPage"; +import { Page, expect } from "@playwright/test"; + +const tempDRepAuth = ".auth/tempDRepAuth.json"; +const tempUserAuth = ".auth/tempUserAuth.json"; +const tempAdaHolderAuth = ".auth/tempAdaHolderAuth.json"; + +export async function createTempDRepAuth(page: Page, wallet: ShelleyWallet) { + await importWallet(page, wallet.json()); + + const loginPage = new LoginPage(page); + await loginPage.login(); + await expect(page.getByTestId("disconnect-button")).toBeVisible(); + + await page.context().storageState({ path: tempDRepAuth }); + return tempDRepAuth; +} + +export async function createTempAdaHolderAuth( + page: Page, + wallet: ShelleyWallet +) { + await importWallet(page, wallet.json()); + + const loginPage = new LoginPage(page); + await loginPage.login(); + await expect(page.getByTestId("disconnect-button")).toBeVisible(); + + await page.context().storageState({ path: tempAdaHolderAuth }); + return tempAdaHolderAuth; +} + +export async function createTempUserAuth(page: Page) { + const loginPage = new LoginPage(page); + await loginPage.login(); + await expect(page.getByTestId("disconnect-button")).toBeVisible(); + + await page.context().storageState({ path: tempUserAuth }); + return tempUserAuth; +} diff --git a/tests/govtool-frontend/playwright/lib/fixtures/createWallet.ts b/tests/govtool-frontend/playwright/lib/fixtures/createWallet.ts new file mode 100644 index 000000000..0ab7f1c04 --- /dev/null +++ b/tests/govtool-frontend/playwright/lib/fixtures/createWallet.ts @@ -0,0 +1,34 @@ +import { + CardanoTestWallet, + CardanoTestWalletConfig, +} from "@cardanoapi/cardano-test-wallet/types"; +import { ShelleyWallet } from "@helpers/crypto"; +import { Page } from "@playwright/test"; + +export default async function createWallet( + page: Page, + config?: CardanoTestWalletConfig +) { + const wallet = (await ShelleyWallet.generate()).json(); + + const initScriptArgs: { + wallet: CardanoTestWallet; + config: CardanoTestWalletConfig; + } = { + wallet, + config: config, + }; + + await page.addInitScript(({ wallet, config }) => { + window["cardanoTestWallet"] = { + ...window["cardanoTestWallet"], + wallet: wallet, + }; + if (config) { + window["cardanoTestWallet"]["config"] = { + ...window["cardanoTestWallet"]["config"], + ...config, + }; + } + }, initScriptArgs); +} diff --git a/tests/govtool-frontend/playwright/lib/fixtures/importWallet.ts b/tests/govtool-frontend/playwright/lib/fixtures/importWallet.ts new file mode 100644 index 000000000..d825f8cf9 --- /dev/null +++ b/tests/govtool-frontend/playwright/lib/fixtures/importWallet.ts @@ -0,0 +1,14 @@ +import { CardanoTestWallet } from "@cardanoapi/cardano-test-wallet/types"; +import { Page } from "@playwright/test"; +import { StaticWallet } from "@types"; + +export async function importWallet( + page: Page, + wallet: StaticWallet | CardanoTestWallet +) { + await page.addInitScript((wallet) => { + // @ts-ignore + window.cardanoTestWallet.wallet = wallet; + //@ts-ignore + }, wallet); +} diff --git a/tests/govtool-frontend/playwright/lib/fixtures/loadExtension.ts b/tests/govtool-frontend/playwright/lib/fixtures/loadExtension.ts new file mode 100644 index 000000000..44cea5367 --- /dev/null +++ b/tests/govtool-frontend/playwright/lib/fixtures/loadExtension.ts @@ -0,0 +1,28 @@ +import { CardanoTestWalletConfig } from "@cardanoapi/cardano-test-wallet/types"; +import environments from "@constants/environments"; +import { Page } from "@playwright/test"; + +import path = require("path"); + +export default async function loadDemosExtension( + page: Page, + enableStakeSigning = false +) { + const demosBundleScriptPath = path.resolve( + __dirname, + "../../node_modules/@cardanoapi/cardano-test-wallet/script.js" + ); + let walletConfig: CardanoTestWalletConfig = { + enableStakeSigning, + kuberApiUrl: environments.kuber.apiUrl, + kuberApiKey: environments.kuber.apiKey, + }; + await page.addInitScript((walletConfig) => { + window["cardanoTestWallet"] = { + walletName: "demos", + config: walletConfig, + }; + }, walletConfig); + + await page.addInitScript({ path: demosBundleScriptPath }); +} diff --git a/tests/govtool-frontend/playwright/lib/fixtures/walletExtension.ts b/tests/govtool-frontend/playwright/lib/fixtures/walletExtension.ts new file mode 100644 index 000000000..5f1fa6e7c --- /dev/null +++ b/tests/govtool-frontend/playwright/lib/fixtures/walletExtension.ts @@ -0,0 +1,25 @@ +import { test as base } from "@playwright/test"; +import { StaticWallet } from "@types"; +import { importWallet } from "./importWallet"; +import loadDemosExtension from "./loadExtension"; + +type WalletExtensionTestOptions = { + wallet?: StaticWallet; + enableStakeSigning: boolean; +}; + +export const test = base.extend({ + wallet: [null, { option: true }], + + enableStakeSigning: [true, { option: true }], + + page: async ({ page, wallet, enableStakeSigning }, use) => { + await loadDemosExtension(page, enableStakeSigning); + + if (wallet) { + await importWallet(page, wallet); + } + + await use(page); + }, +}); diff --git a/tests/govtool-frontend/playwright/lib/helpers/cborEncodeDecode.ts b/tests/govtool-frontend/playwright/lib/helpers/cborEncodeDecode.ts new file mode 100644 index 000000000..e28c95183 --- /dev/null +++ b/tests/govtool-frontend/playwright/lib/helpers/cborEncodeDecode.ts @@ -0,0 +1,7 @@ +import { Decoder, Encoder } from "cbor-x"; + +export const cborxEncoder = new Encoder({ + mapsAsObjects: false, + useRecords: false, +}); +export const cborxDecoder = new Decoder({ mapsAsObjects: false }); diff --git a/tests/govtool-frontend/playwright/lib/helpers/computeTxHash.ts b/tests/govtool-frontend/playwright/lib/helpers/computeTxHash.ts new file mode 100644 index 000000000..4baf52026 --- /dev/null +++ b/tests/govtool-frontend/playwright/lib/helpers/computeTxHash.ts @@ -0,0 +1,8 @@ +import { blake2bHex } from "blakejs"; +import { cborxDecoder, cborxEncoder } from "./cborEncodeDecode"; + +export default function computeTxHash(tx: string) { + let decodedTx = cborxDecoder.decode(Buffer.from(tx, "hex")); + const txBody = Uint8Array.from(cborxEncoder.encode(decodedTx[0])); + return blake2bHex(txBody, undefined, 32); +} diff --git a/tests/govtool-frontend/playwright/lib/helpers/convertBufferToHex.ts b/tests/govtool-frontend/playwright/lib/helpers/convertBufferToHex.ts new file mode 100644 index 000000000..f7a9e0050 --- /dev/null +++ b/tests/govtool-frontend/playwright/lib/helpers/convertBufferToHex.ts @@ -0,0 +1,3 @@ +export default function convertBufferToHex(buffer: Uint8Array) { + return Buffer.from(buffer).toString("hex"); +} diff --git a/tests/govtool-frontend/playwright/lib/helpers/crypto.ts b/tests/govtool-frontend/playwright/lib/helpers/crypto.ts new file mode 100644 index 000000000..24fe8fd26 --- /dev/null +++ b/tests/govtool-frontend/playwright/lib/helpers/crypto.ts @@ -0,0 +1,251 @@ +import { ed25519 as ed } from "@noble/curves/ed25519"; +import { bech32 } from "bech32"; +import * as blake from "blakejs"; + +const KEY_HASH_LENGTH = 28; +const ADDR_LENGTH = KEY_HASH_LENGTH * 2 + 1; + +// Stores ed25519 KeyPair and hash of publicKey +export class Ed25519Key { + private: Uint8Array; + public: Uint8Array; + pkh: Uint8Array; + + private constructor(priv: Uint8Array, pub: Uint8Array, pkh: Uint8Array) { + this.private = priv; + this.public = pub; + this.pkh = pkh; + } + public static async generate() { + const privKey = ed.utils.randomPrivateKey(); // Secure random private key + return await Ed25519Key.fromPrivateKey(privKey); + } + + public static async fromPrivateKey(privKey: Uint8Array) { + const pubKey = ed.getPublicKey(privKey); + const pkh = blake.blake2b(pubKey, undefined, KEY_HASH_LENGTH); + const key = new Ed25519Key(privKey, pubKey, pkh); + return key; + } + public static async fromPrivateKeyHex(privKey) { + return await Ed25519Key.fromPrivateKey( + Uint8Array.from(Buffer.from(privKey, "hex")), + ); + } + + public bech32Pkh(prefix: string = "stake"): string { + return bech32.encode(prefix, bech32.toWords(this.pkh)); + } + public bech32PublicKey(prefix: string = "vk_"): string { + return bech32.encode(prefix, bech32.toWords(this.public)); + } + public bech32PrivateKey(prefix: string = "sk_"): string { + return bech32.encode(prefix, bech32.toWords(this.private)); + } + public async signRaw(message: Uint8Array) { + return ed.sign(message, this.private); + } + public async verify(message, signature) { + return ed.verify(signature, message, this.public); + } + + public json() { + return { + private: Buffer.from(this.private).toString("hex"), + public: Buffer.from(this.public).toString("hex"), + pkh: Buffer.from(this.pkh).toString("hex"), + }; + } + public static fromJson(json: any): Ed25519Key { + if (!json || typeof json !== "object") { + throw new Error( + "Invalid JSON format for Ed25519Key: Input must be a non-null object.", + ); + } + + if (!json.private || !json.public || !json.pkh) { + throw new Error( + "Invalid JSON format for Ed25519Key: Missing required fields (private, public, or pkh).", + ); + } + + return new Ed25519Key( + Uint8Array.from(Buffer.from(json.private, "hex")), + Uint8Array.from(Buffer.from(json.public, "hex")), + Uint8Array.from(Buffer.from(json.pkh, "hex")), + ); + } +} + +// Shelley Wallet has 2 ed25519 key pair +// - one for payment purpose +// - one for staking/governance purpose +export class ShelleyWallet { + paymentKey: Ed25519Key; + stakeKey: Ed25519Key; + + public constructor(payment, stake) { + this.paymentKey = payment; + this.stakeKey = stake; + } + + public static async generate() { + const wallet = new ShelleyWallet( + await Ed25519Key.generate(), + await Ed25519Key.generate(), + ); + return wallet; + } + + addressBech32(networkId: number): string { + const prefix = networkId == 0 ? "addr_test" : "addr"; + return bech32.encode( + prefix, + bech32.toWords(Buffer.from(this.addressRawBytes(networkId))), + 200, + ); + } + + addressRawBytes(networkId) { + const concatenatedArray1 = new Uint8Array(ADDR_LENGTH); + concatenatedArray1[0] = networkId; + concatenatedArray1.set(this.paymentKey.pkh, 1); + concatenatedArray1.set(this.stakeKey.pkh, KEY_HASH_LENGTH + 1); + return concatenatedArray1; + } + rewardAddressRawBytes(network: number) { + const rewardAccountPrefix = 0xe0; + const header = network | rewardAccountPrefix; + const result = new Uint8Array(KEY_HASH_LENGTH + 1); + result[0] = header; + result.set(this.stakeKey.pkh, 1); + return result; + } + + rewardAddressBech32(networkId: number): string { + const prefix = networkId == 0 ? "stake" : "stake_test"; + return bech32.encode( + prefix, + bech32.toWords(Buffer.from(this.rewardAddressRawBytes(networkId))), + 200, + ); + } + public json() { + return { + payment: this.paymentKey.json(), + stake: this.stakeKey.json(), + }; + } + + public static fromJson(obj: { + payment: object; + stake: object; + }): ShelleyWallet { + if (!obj || typeof obj !== "object") { + throw new Error("ShelleyWallet.fromJson: The input must be an object."); + } + + const paymentKey = obj.payment; + const stakeKey = obj.stake; + + if (!paymentKey || typeof paymentKey !== "object") { + throw new Error( + "ShelleyWallet.fromJson : Invalid payment key: It must be an object.", + ); + } + + if (!stakeKey || typeof stakeKey !== "object") { + throw new Error( + "ShelleyWallet.fromJson : Invalid stake key: It must be an object.", + ); + } + return new ShelleyWallet( + Ed25519Key.fromJson(paymentKey), + Ed25519Key.fromJson(stakeKey), + ); + } + + public static dummy(): ShelleyWallet { + return ShelleyWallet.fromJson({ + payment: { + pkh: "595ac9bbf256bae584f56a4b671baa4b14a18c8098b8e571834bc12c", + private: + "5a1380cd79ecaee48d66c14f7d92ddfc866490a3b59d44520e60f16309c8a17d", + public: + "8d2f4d49118eb1156048b66dd6372cdb1f82da0f8e208d9f8ea4b388c79c09ad", + }, + stake: { + pkh: "6706efab75778c2f08b9a5321ead8bfc982a5c08b51a0b2a713cac52", + private: + "24e8c012c7bef2f5823baef1c06dac253da860a43f0d1f43fc3c8349a4f719a1", + public: + "f7a1eaea2691ee80b6c0d6f27482145d7037055829b1b26224a5d8f0c2243f16", + }, + }); + } +} + +export interface Address { + toBech32(): string; + toRawBytes(): Uint8Array; + toRawBytesHex(): string; +} +export class ShelleyWalletAddress implements Address { + paymentKeyHash: Uint8Array; + stakeKeyHash: Uint8Array; + network: number; + + private constructor( + network: number | "mainnet" | "testnet", + pkh: Uint8Array, + skh: Uint8Array, + ) { + this.network = + network == "mainnet" ? 1 : network == "testnet" ? 0 : network; + this.paymentKeyHash = pkh; + this.stakeKeyHash = skh; + } + public static fromRawBytes(bytea: Uint8Array | string | Buffer) { + let bytebuffer: Buffer; + if (bytea.length == ADDR_LENGTH * 2 && typeof bytea == "string") { + bytebuffer = Buffer.from(bytea, "hex"); + } else { + if (bytea.length !== ADDR_LENGTH) { + throw Error( + "ShelleyAddress.fromRawBytes: Invalid byte array length. expected: " + + ADDR_LENGTH + + " got: " + + bytea.length, + ); + } + bytebuffer = Buffer.from(bytea); + } + + let paymentKeyHash = bytebuffer.subarray(1, 29); + let stakeKeyHash = bytebuffer.subarray(29, ADDR_LENGTH); + + return new ShelleyWalletAddress( + bytebuffer.at(0), + paymentKeyHash, + stakeKeyHash, + ); + } + toBech32(): string { + const prefix = this.network == 0 ? "addr_test" : "addr"; + return bech32.encode( + prefix, + bech32.toWords(Buffer.from(this.toRawBytes())), + 200, + ); + } + toRawBytes(): Uint8Array { + const rawBytes = new Uint8Array(ADDR_LENGTH); + rawBytes[0] = this.network; + rawBytes.set(this.paymentKeyHash, 1); + rawBytes.set(this.stakeKeyHash, KEY_HASH_LENGTH + 1); + return rawBytes; + } + toRawBytesHex(): string { + return Buffer.from(this.toRawBytes()).toString("hex"); + } +} diff --git a/tests/govtool-frontend/playwright/lib/helpers/extractDRepsFromStakePubkey.ts b/tests/govtool-frontend/playwright/lib/helpers/extractDRepsFromStakePubkey.ts new file mode 100644 index 000000000..f0983717e --- /dev/null +++ b/tests/govtool-frontend/playwright/lib/helpers/extractDRepsFromStakePubkey.ts @@ -0,0 +1,10 @@ +import { bech32 } from "bech32"; +import { blake2bHex } from "blakejs"; + +export default function extractDRepsFromStakePubKey(stakePubKey: string) { + const dRepKeyBytes = Buffer.from(stakePubKey, "hex"); + const dRepId = blake2bHex(dRepKeyBytes, undefined, 28); + const words = bech32.toWords(Buffer.from(dRepId, "hex")); + const dRepIdBech32 = bech32.encode("drep", words); + return { dRepId, dRepIdBech32 }; +} diff --git a/tests/govtool-frontend/playwright/lib/helpers/generateShellyWallets.ts b/tests/govtool-frontend/playwright/lib/helpers/generateShellyWallets.ts new file mode 100644 index 000000000..127cb577f --- /dev/null +++ b/tests/govtool-frontend/playwright/lib/helpers/generateShellyWallets.ts @@ -0,0 +1,15 @@ +import { ShelleyWallet } from "./crypto"; + +export default async function generateShellyWallets( + numWallets: number = 100, +): Promise { + const wallets: ShelleyWallet[] = []; + + for (let i = 0; i < numWallets; i++) { + const wallet = await ShelleyWallet.generate(); + + wallets.push(wallet); + } + + return wallets; +} diff --git a/tests/govtool-frontend/playwright/lib/helpers/page.ts b/tests/govtool-frontend/playwright/lib/helpers/page.ts new file mode 100644 index 000000000..7a20d6d80 --- /dev/null +++ b/tests/govtool-frontend/playwright/lib/helpers/page.ts @@ -0,0 +1,25 @@ +import { importWallet } from "@fixtures/importWallet"; +import loadDemosExtension from "@fixtures/loadExtension"; +import { Browser, Page } from "@playwright/test"; +import { ShelleyWallet } from "./crypto"; + +interface BrowserConfig { + storageState: string; + wallet: ShelleyWallet; + enableStakeSigning?: boolean; +} + +export async function createNewPageWithWallet( + browser: Browser, + { storageState, wallet, enableStakeSigning }: BrowserConfig +): Promise { + const context = await browser.newContext({ + storageState: storageState, + }); + const newPage = await context.newPage(); + + await loadDemosExtension(newPage, enableStakeSigning); + await importWallet(newPage, wallet.json()); + + return newPage; +} diff --git a/tests/govtool-frontend/playwright/lib/helpers/removeAllSpaces.ts b/tests/govtool-frontend/playwright/lib/helpers/removeAllSpaces.ts new file mode 100644 index 000000000..e7c3f95eb --- /dev/null +++ b/tests/govtool-frontend/playwright/lib/helpers/removeAllSpaces.ts @@ -0,0 +1,3 @@ +export default function removeAllSpaces(inputStr: string) { + return inputStr.replace(/\s/g, ""); +} diff --git a/tests/govtool-frontend/playwright/lib/helpers/setupWallets.ts b/tests/govtool-frontend/playwright/lib/helpers/setupWallets.ts new file mode 100644 index 000000000..b12684b3b --- /dev/null +++ b/tests/govtool-frontend/playwright/lib/helpers/setupWallets.ts @@ -0,0 +1,23 @@ +import { faucetWallet } from "@constants/staticWallets"; +import { ShelleyWallet } from "@helpers/crypto"; +import kuberService from "@services/kuberService"; +import { pollTransaction } from "./transaction"; + +/* +Registers stake & fund wallets +*/ +export default async function setupWallets(wallets: ShelleyWallet[]) { + if (wallets.length === 0) { + throw new Error("No wallets to load balance"); + } + + const signingKey = faucetWallet.payment.private; + const { txId, address } = await kuberService.initializeWallets( + faucetWallet.address, + signingKey, + wallets + ); + await pollTransaction(txId, address); + + console.debug(`[Setup Wallet] Successfully setup ${wallets.length} wallets`); +} diff --git a/tests/govtool-frontend/playwright/lib/helpers/transaction.ts b/tests/govtool-frontend/playwright/lib/helpers/transaction.ts new file mode 100644 index 000000000..63107dd9c --- /dev/null +++ b/tests/govtool-frontend/playwright/lib/helpers/transaction.ts @@ -0,0 +1,52 @@ +import environments from "@constants/environments"; +import { Page, expect } from "@playwright/test"; +import kuberService from "@services/kuberService"; +import { LockInterceptor } from "lib/lockInterceptor"; +import { Logger } from "../../../cypress/lib/logger/logger"; + +/** + * Polls the transaction status until it's resolved or times out. + * address is used to release lock of that address + */ +export async function pollTransaction(txHash: string, address?: string) { + try { + Logger.info(`Waiting for tx completion: ${txHash}`); + await expect + .poll( + async () => { + const response = await kuberService.getTransactionDetails(txHash); + const data = await response.json(); + return data.length; + }, + { message: "Transaction failed", timeout: environments.txTimeOut } + ) + .toBeGreaterThan(0); + + Logger.success("Tx completed"); + } catch (err) { + throw err; + } finally { + if (!address) return; + + await LockInterceptor.releaseLockForAddress(address); + } +} + +export async function waitForTxConfirmation(page: Page) { + let transactionHash: string | undefined; + const transactionStatusPromise = page.waitForRequest((request) => { + return request.url().includes("/transaction/status/"); + }); + + const url = (await transactionStatusPromise).url(); + const regex = /\/transaction\/status\/([^\/]+)$/; + const match = url.match(regex); + if (match) { + transactionHash = match[1]; + } + + if (transactionHash) { + await pollTransaction(transactionHash); + await page.reload(); + } +} diff --git a/tests/govtool-frontend/playwright/lib/lockInterceptor.ts b/tests/govtool-frontend/playwright/lib/lockInterceptor.ts new file mode 100644 index 000000000..aa740caa3 --- /dev/null +++ b/tests/govtool-frontend/playwright/lib/lockInterceptor.ts @@ -0,0 +1,132 @@ +import { TxSubmitResponse } from "@services/kuberService"; +import * as fs from "fs"; +import * as lockfile from "lockfile"; +import { Logger } from "../../cypress/lib/logger/logger"; + +import path = require("path"); + +export class LockInterceptor { + private static async acquireLock( + address: string, + message?: string + ): Promise { + const lockFilePath = path.resolve(__dirname, `../.lock-pool/${address}`); + + try { + await log( + `${address} -> acquiring lock` + message && `\nMessage: ${message}` + ); + await new Promise((resolve, reject) => { + lockfile.lock(lockFilePath, (err) => { + if (err) { + reject(err); + } else { + resolve(); + } + }); + }); + await log(`${address} -> acquired lock`); + } catch (err) { + Logger.fail("Failed to write lock logs"); + } + } + + private static async releaseLock( + address: string, + message?: string + ): Promise { + const lockFilePath = path.resolve(__dirname, `../.lock-pool/${address}`); + + try { + await log( + `${address} -> releasing lock` + message && `\nMessage: ${message}` + ); + await new Promise((resolve, reject) => { + lockfile.unlock(lockFilePath, async (err) => { + if (err) { + reject(err); + } else { + resolve(); + } + }); + }); + await log(`${address} -> released lock\n`); + } catch (err) { + Logger.fail("Failed to write lock logs"); + } + } + + private static async waitForReleaseLock( + address: string, + message?: string + ): Promise { + const pollInterval = 200; + + try { + await log( + `${address} -> waiting lock` + message && `\nMessage: ${message}` + ); + return new Promise((resolve, reject) => { + const pollFn = () => { + try { + const isAddressLocked = checkAddressLock(address); + if (!isAddressLocked) { + resolve(); + } else { + setTimeout(pollFn, pollInterval); + } + } catch (err) { + reject(err); + } + }; + + pollFn(); + }); + } catch (err) { + Logger.fail("Failed to write lock logs"); + } + } + + static async intercept( + address: string, + callbackFn: () => Promise, + message?: string + ): Promise { + const isAddressLocked = checkAddressLock(address); + if (isAddressLocked) { + await LockInterceptor.waitForReleaseLock(address, message); + } + + await LockInterceptor.acquireLock(address, message); + try { + const res = await callbackFn(); + return { ...res, address }; + } catch (err) { + await LockInterceptor.releaseLock(address, "Tx failure"); + throw err; + } + } + + static async releaseLockForAddress(address: string) { + await this.releaseLock(address); + } +} + +function checkAddressLock(address: string): boolean { + const lockFilePath = path.resolve(__dirname, `../.lock-pool/${address}`); + return lockfile.checkSync(lockFilePath); +} + +function log(message: string): Promise { + const logFilePath = path.resolve(__dirname, "../.logs/lock_logs.txt"); + const logMessage = `[${new Date().toISOString()}] ${message}\n`; + return new Promise((resolve, reject) => { + fs.appendFile(logFilePath, logMessage, (err) => { + if (err) { + reject(err); + } else { + resolve(); + } + }); + }); +} diff --git a/tests/govtool-frontend/playwright/lib/pages/dRepRegistrationPage.ts b/tests/govtool-frontend/playwright/lib/pages/dRepRegistrationPage.ts new file mode 100644 index 000000000..4925124d7 --- /dev/null +++ b/tests/govtool-frontend/playwright/lib/pages/dRepRegistrationPage.ts @@ -0,0 +1,52 @@ +import { Page } from "@playwright/test"; +import { IDRepInfo } from "@types"; +import environments from "lib/constants/environments"; + +export default class DRepRegistrationPage { + readonly registerBtn = this.page.getByTestId("register-button"); + readonly skipBtn = this.page.getByTestId("skip-button"); + readonly confirmBtn = this.page.getByTestId("confirm-modal-button"); + readonly registrationSuccessModal = this.page.getByTestId( + "governance-action-submitted-modal" + ); + readonly continueBtn = this.page.getByTestId("retire-button"); // BUG testId -> continue-button + readonly addLinkBtn = this.page.getByRole("button", { name: "+ Add link" }); // BUG: testId -> add-link-button + + // input fields + readonly nameInput = this.page.getByPlaceholder("ex. JohnDRep"); // BUG testId + readonly emailInput = this.page.getByPlaceholder("john.smith@email.com"); // BUG testId + readonly bioInput = this.page.getByPlaceholder("Enter your Bio"); // BUG testId + readonly linkInput = this.page.getByPlaceholder("https://website.com/"); // BUG: testId + + constructor(private readonly page: Page) {} + + async goto() { + await this.page.goto(`${environments.frontendUrl}/register_drep`); + await this.continueBtn.click(); // BUG: testId -> continue-register-button + } + + async register(dRepInfo: IDRepInfo) { + await this.nameInput.fill(dRepInfo.name); + + if (dRepInfo.email != null) { + await this.emailInput.fill(dRepInfo.email); + } + if (dRepInfo.bio != null) { + await this.bioInput.fill(dRepInfo.bio); + } + if (dRepInfo.extraContentLinks != null) { + for (let i = 0; i < dRepInfo.extraContentLinks.length; i++) { + await this.linkInput.nth(i).fill(dRepInfo.extraContentLinks[i]); + } + } + + await this.continueBtn.click(); // BUG: testId -> submit-button + await this.page.getByRole("checkbox").click(); + await this.continueBtn.click(); // BUG: testId -> submit-button + + await this.page + .getByPlaceholder("URL") + .fill(`${environments.metadataBucketUrl}/Test_dRep`); + await this.continueBtn.click(); + } +} diff --git a/tests/govtool-frontend/playwright/lib/pages/delegationPage.ts b/tests/govtool-frontend/playwright/lib/pages/delegationPage.ts new file mode 100644 index 000000000..dc4d6b1ec --- /dev/null +++ b/tests/govtool-frontend/playwright/lib/pages/delegationPage.ts @@ -0,0 +1,51 @@ +import { Page } from "@playwright/test"; +import environments from "lib/constants/environments"; + +export default class DelegationPage { + readonly otherOptionsBtn = this.page.getByText("Other options"); + readonly nextStepBtn = this.page.getByTestId("next-step-button"); + readonly dRepInput = this.page.getByRole("textbox"); + readonly searchInput = this.page.getByTestId("search-input"); + + readonly delegationOptionsDropdown = this.page.getByRole("button", { + name: "Automated Voting Options arrow", + }); // BUG: testId -> delegation-options-dropdown + + readonly delegateToDRepCard = this.page.getByTestId("delegate-to-drep-card"); + readonly signalNoConfidenceCard = this.page + .getByRole("region") + .locator("div") + .filter({ hasText: "Signal No Confidence on Every" }) + .nth(2); // BUG: testId -> signal-no-confidence-card + readonly abstainDelegationCard = this.page.getByText( + "Abstain from Every VoteSelect this to vote ABSTAIN to every vote.Voting Power₳" + );// BUG: testId -> abstain-delegation-card + + readonly delegationErrorModal = this.page.getByTestId( + "delegation-transaction-error-modal" + ); + + readonly delegateBtns = this.page.locator( + '[data-testid$="-delegate-button"]' + ); + + constructor(private readonly page: Page) {} + + async goto() { + await this.page.goto( + `${environments.frontendUrl}/connected/dRep_directory` + ); + } + + async delegateToDRep(dRepId: string) { + await this.searchInput.fill(dRepId); + await this.page.getByTestId(`${dRepId}-delegate-button`).click(); + } + + async resetDRepForm() { + if (await this.delegationErrorModal.isVisible()) { + await this.page.getByTestId("confirm-modal-button").click(); + } + await this.dRepInput.clear(); + } +} diff --git a/tests/govtool-frontend/playwright/lib/pages/governanceActionDetailsPage.ts b/tests/govtool-frontend/playwright/lib/pages/governanceActionDetailsPage.ts new file mode 100644 index 000000000..89877b9c4 --- /dev/null +++ b/tests/govtool-frontend/playwright/lib/pages/governanceActionDetailsPage.ts @@ -0,0 +1,53 @@ +import environments from "@constants/environments"; +import { Page } from "@playwright/test"; + +export default class GovernanceActionDetailsPage { + readonly voteBtn = this.page.getByTestId("vote-button"); + readonly changeVoteBtn = this.page.getByTestId("change-vote"); + readonly yesVoteRadio = this.page.getByTestId("yes-radio"); + readonly noVoteRadio = this.page.getByTestId("no-radio"); + readonly abstainRadio = this.page.getByTestId("abstain-radio"); + readonly governanceActionType = this.page.getByText( + "Governance Action Type:" + ); + readonly submittedDate = this.page.getByTestId("submission-date"); + readonly expiryDate = this.page.getByTestId("expiry-date"); + readonly externalModalBtn = this.page.getByTestId("external-modal-button"); + readonly governanceActionId = this.page.getByText("Governance Action ID:"); + + readonly contextBtn = this.page.getByRole("button", { + name: "Provide context about your", + }); // BUG testId + readonly viewOtherDetailsLink = this.page.getByTestId( + "view-other-details-button" + ); + readonly continueModalBtn = this.page.getByTestId("continue-modal-button"); + + readonly voteSuccessModal = this.page.getByTestId("alert-success"); + readonly externalLinkModal = this.page.getByTestId("external-link-modal"); + + readonly contextInput = this.page.getByPlaceholder("Provide context"); // BUG testId + readonly cancelModalBtn = this.page.getByTestId("cancel-modal-button"); + + constructor(private readonly page: Page) {} + + get currentPage(): Page { + return this.page; + } + + async goto(proposalId: string) { + await this.page.goto( + `${environments.frontendUrl}/governance_actions/${proposalId}` + ); + } + + async vote() { + await this.yesVoteRadio.click(); + await this.voteBtn.click(); + } + + async reVote() { + await this.noVoteRadio.click(); + await this.changeVoteBtn.click(); + } +} diff --git a/tests/govtool-frontend/playwright/lib/pages/governanceActionsPage.ts b/tests/govtool-frontend/playwright/lib/pages/governanceActionsPage.ts new file mode 100644 index 000000000..a74a9c8d1 --- /dev/null +++ b/tests/govtool-frontend/playwright/lib/pages/governanceActionsPage.ts @@ -0,0 +1,159 @@ +import removeAllSpaces from "@helpers/removeAllSpaces"; +import { Locator, Page, expect } from "@playwright/test"; +import { IProposal } from "@types"; +import environments from "lib/constants/environments"; +import GovernanceActionDetailsPage from "./governanceActionDetailsPage"; + +enum FilterOption { + ProtocolParameterChange = "ParameterChange", + InfoAction = "InfoAction", + TreasuryWithdrawal = "TreasuryWithdrawals", + HardFork = "HardForkInitiation", + NoConfidence = "NoConfidence", + NewCommittee = "NewCommittee", + UpdatetotheConstitution = "NewConstitution", +} + +export default class GovernanceActionsPage { + readonly filterBtn = this.page.getByTestId("filters-button"); + readonly sortBtn = this.page.getByTestId("sort-button"); + readonly votedTab = this.page.getByTestId("voted-tab"); + + constructor(private readonly page: Page) {} + + async goto() { + await this.page.goto(`${environments.frontendUrl}/governance_actions`); + } + + async viewProposal( + proposal: IProposal + ): Promise { + const proposalId = `govaction-${proposal.txHash}#${proposal.index}-view-detail`; + await this.page.getByTestId(proposalId).click(); + + return new GovernanceActionDetailsPage(this.page); + } + + async viewFirstProposal(): Promise { + await this.page + .locator('[data-testid^="govaction-"][data-testid$="-view-detail"]') + .first() + .click(); + return new GovernanceActionDetailsPage(this.page); + } + + async viewFirstVotedProposal(): Promise { + await this.page + .locator('[data-testid^="govaction-"][data-testid$="-change-your-vote"]') + .first() + .click(); + return new GovernanceActionDetailsPage(this.page); + } + + async viewVotedProposal( + proposal: IProposal + ): Promise { + const proposalId = `govaction-${proposal.txHash}#${proposal.index}-change-your-vote`; + await this.page.getByTestId(proposalId).click(); + + return new GovernanceActionDetailsPage(this.page); + } + + async filterProposalByNames(names: string[]) { + for (const name of names) { + const sanitizedProposalName = removeAllSpaces(name); + await this.page.getByTestId(`${sanitizedProposalName}-checkbox`).click(); + } + } + + async unFilterProposalByNames(names: string[]) { + for (const name of names) { + const sanitizedProposalName = removeAllSpaces(name); + await this.page.getByTestId(`${sanitizedProposalName}-checkbox`).click(); + } + } + + async validateFilters(filters: string[]) { + const proposalCards = await this.page + .locator('[data-test-id$="-card"]') + .all(); + + for (const proposalCard of proposalCards) { + const hasFilter = await this._validateFiltersInProposalCard( + proposalCard, + filters + ); + expect( + hasFilter, + "A proposal card does not contain any of the filters" + ).toBe(true); + } + } + + async sortProposal(option: string) { + await this.page.getByTestId(`${option}-radio`).check(); + } + + async validateSort( + sortOption: string, + validationFn: (p1: IProposal, p2: IProposal) => boolean, + filterKeys = Object.keys(FilterOption) + ) { + const responses = await Promise.all( + filterKeys.map((filterKey) => + this.page.waitForResponse((response) => + response + .url() + .includes(`&type[]=${FilterOption[filterKey]}&sort=${sortOption}`) + ) + ) + ); + const proposalData = await Promise.all( + responses.map(async (response) => { + return await response.json(); + }) + ); + expect(proposalData.length, "No proposals to sort").toBeGreaterThan(0); + + // API validation + proposalData.forEach(async (proposal) => { + if (proposal.elements.length <= 1) return; + + const proposals = proposal.elements as IProposal[]; + for (let i = 0; i <= proposals.length - 2; i++) { + const isValid = validationFn(proposals[i], proposals[i + 1]); + expect(isValid, "API Sorting validation failed").toBe(true); + } + }); + + // Frontend validation + const proposalCards = await Promise.all( + filterKeys.map((key) => + this.page.getByTestId(`govaction-${key}-card`).allInnerTexts() + ) + ); + + for (let dIdx = 0; dIdx <= proposalData.length - 1; dIdx++) { + const proposals = proposalData[dIdx].elements as IProposal[]; + for (let i = 0; i <= proposals.length - 1; i++) { + expect( + proposalCards[dIdx][i].includes(proposals[i].txHash), + "Frontend validation failed" + ).toBe(true); + } + } + } + + async _validateFiltersInProposalCard( + proposalCard: Locator, + filters: string[] + ): Promise { + for (const filter of filters) { + try { + await expect(proposalCard.getByText(filter)).toBeVisible(); + return true; + } catch (e) {} + return false; + } + } +} diff --git a/tests/govtool-frontend/playwright/lib/pages/loginPage.ts b/tests/govtool-frontend/playwright/lib/pages/loginPage.ts new file mode 100644 index 000000000..2baa2f0ff --- /dev/null +++ b/tests/govtool-frontend/playwright/lib/pages/loginPage.ts @@ -0,0 +1,62 @@ +import { + CIP30Instance, + Cip95Instance, +} from "@cardanoapi/cardano-test-wallet/types"; +import { Page, expect } from "@playwright/test"; + +export default class LoginPage { + readonly connectWalletBtn = this.page.getByTestId("connect-wallet-button"); + readonly demosWalletBtn = this.page.getByTestId("demos-wallet-button"); + readonly acceptSanchoNetInfoBtn = this.page + .getByTestId("confirm-modal-button") + .nth(0); + readonly disconnectWalletBtn = this.page.getByTestId("disconnect-button"); + readonly dRepIdDisplay = this.page.getByTestId("dRep-id-display"); + + constructor(private readonly page: Page) {} + + async goto() { + await this.page.goto("/"); + } + + async login() { + await this.goto(); + + await this.connectWalletBtn.click(); + await this.demosWalletBtn.click({ force: true }); + await this.acceptSanchoNetInfoBtn.click({ force: true }); + + const { stakeKeys, rewardAddresses } = await this.page.evaluate( + async () => { + const walletInstance: CIP30Instance | Cip95Instance = + await window["cardano"]["demos"].enable(); + + let stakeKeys = []; + let rewardAddresses = []; + if ("cip95" in walletInstance) { + stakeKeys = await walletInstance.cip95.getRegisteredPubStakeKeys(); + rewardAddresses = await walletInstance.getRewardAddresses(); + } + + return { stakeKeys, rewardAddresses }; + } + ); + + // Handle multiple stake keys + if (stakeKeys.length > 1) { + await this.page + .getByTestId(`${rewardAddresses[0]}-radio`) + .getByText("Voting power:") + .click({ force: true }); + await this.page.getByTestId("select-button").click(); + } + } + + async logout() { + await this.disconnectWalletBtn.click(); + } + + async isLoggedIn() { + await expect(this.disconnectWalletBtn).toBeVisible(); + } +} diff --git a/tests/govtool-frontend/playwright/lib/services/faucetService.ts b/tests/govtool-frontend/playwright/lib/services/faucetService.ts new file mode 100644 index 000000000..a2f9971e3 --- /dev/null +++ b/tests/govtool-frontend/playwright/lib/services/faucetService.ts @@ -0,0 +1,34 @@ +import environments from "lib/constants/environments"; +import fetch = require("node-fetch"); + +interface IFaucetResponse { + amount: { + lovelace: number; + }; + txid: string; + txin: string; +} + +export const loadAmountFromFaucet = async ( + walletAddress: string +): Promise => { + try { + const res = await fetchClient( + `/send-money?type=default&action=funds&address=${walletAddress}&poolid=undefined&api_key=${environments.faucet.apiKey}` + ); + const responseBody = await res.json(); + // console.debug(`faucet response: ${JSON.stringify(responseBody)}`); + + if (responseBody.error) { + throw new Error("Error in loadAmountFaucet:" + responseBody.error.tag); + } + return responseBody; + } catch (error) { + // console.error("Error in loadAmountFromFaucet:", error); + throw error; + } +}; + +const fetchClient = (url: string) => { + return fetch(environments.faucet.apiUrl + url); +}; diff --git a/tests/govtool-frontend/playwright/lib/services/kuberService.ts b/tests/govtool-frontend/playwright/lib/services/kuberService.ts new file mode 100644 index 000000000..8ba49b402 --- /dev/null +++ b/tests/govtool-frontend/playwright/lib/services/kuberService.ts @@ -0,0 +1,417 @@ +import { faucetWallet } from "@constants/staticWallets"; +import { ShelleyWallet } from "@helpers/crypto"; +import { KuberValue } from "@types"; +import * as blake from "blakejs"; +import environments from "lib/constants/environments"; +import { LockInterceptor } from "lib/lockInterceptor"; +import fetch, { BodyInit, RequestInit } from "node-fetch"; +import { cborxDecoder, cborxEncoder } from "../helpers/cborEncodeDecode"; +import convertBufferToHex from "../helpers/convertBufferToHex"; +import { Logger } from "./../../../cypress/lib/logger/logger"; + +type CertificateType = "registerstake" | "registerdrep" | "deregisterdrep"; + +export type TxSubmitResponse = { cbor: string; txId: string; address?: string }; + +type KuberBalanceResponse = { + address: string; + txin: string; + value: KuberValue; +}; + +const config = { + apiUrl: environments.kuber.apiUrl, + apiKey: environments.kuber.apiKey, +}; + +class Kuber { + walletAddr: string; + signingKey: string; + version: string; + + constructor(walletAddr: string, signingKey: string, version = "v1") { + this.walletAddr = walletAddr; + this.signingKey = signingKey; + this.version = version; + } + + static generateCert(type: CertificateType, key: string) { + if (type === "registerstake" || type === "deregisterdrep") { + return { + type: type, + key: key, + }; + } else if (type === "registerdrep") { + return { + type: "registerdrep", + key: key, + anchor: { + url: "https://bit.ly/3zCH2HL", + dataHash: + "1111111111111111111111111111111111111111111111111111111111111111", + }, + }; + } + } + signTx(tx: any) { + return { + ...tx, + selections: [ + ...(tx.selections || []), + { + type: "PaymentSigningKeyShelley_ed25519", + description: "Payment Signing Key", + cborHex: "5820" + this.signingKey, + }, + this.walletAddr, + ], + changeAddress: this.walletAddr, + }; + } + + async signAndSubmitTx(tx: any) { + const signedTx = this.signTx(tx); + const submitTxCallback = async () => { + return this.submitTx(signedTx); + }; + return LockInterceptor.intercept( + this.walletAddr, + submitTxCallback, + JSON.stringify(signedTx, null, 2) + ); + } + + async submitTx(signedTx: any) { + Logger.info(`Submitting tx: ${JSON.stringify(signedTx)}`); + + const res = (await callKuber( + `/api/${this.version}/tx?submit=true`, + "POST", + JSON.stringify(signedTx) + )) as any; + let decodedTx = cborxDecoder.decode(Buffer.from(res.cborHex, "hex")); + const submittedTxBody = Uint8Array.from(cborxEncoder.encode(decodedTx[0])); + const submittedTxHash = Buffer.from( + blake.blake2b(submittedTxBody, undefined, 32) + ).toString("hex"); + + Logger.success(`Tx submitted: ${submittedTxHash}`); + return { + cbor: res.cborHex, + txId: submittedTxHash, + }; + } +} + +const kuberService = { + initializeWallets: ( + senderAddress: string, + signingKey: string, + wallets: ShelleyWallet[] + ) => { + const kuber = new Kuber(senderAddress, signingKey); + const outputs = []; + const stakes = []; + const certificates = []; + for (let i = 0; i < wallets.length; i++) { + const wallet = wallets[i]; + const address = wallet.addressBech32(environments.networkId); + outputs.push({ + address: address, + value: 0, + }); + stakes.push({ + type: "PaymentSigningKeyShelley_ed25519", + description: "Payment Signing Key", + cborHex: "5820" + convertBufferToHex(wallet.stakeKey.private), + }); + certificates.push( + Kuber.generateCert( + "registerstake", + convertBufferToHex(wallet.stakeKey.pkh) + ) + ); + } + return kuber.signAndSubmitTx({ + selections: [...stakes], + outputs, + certificates, + }); + }, + + submitTransaction(tx: any) { + return fetch(config.apiUrl + "/api/v1/tx/submit", { + method: "POST", + headers: { + "Content-Type": "application/json", + "api-key": config.apiKey, + }, + + body: JSON.stringify({ + tx: { + description: "", + type: "Tx ConwayEra", + cborHex: tx, + }, + }), + redirect: "follow", + }); + }, + transferADA: (receiverAddressList: string[], ADA = 20) => { + const kuber = new Kuber(faucetWallet.address, faucetWallet.payment.private); + const req = { + outputs: receiverAddressList.map((addr) => { + return { + address: addr, + value: `${ADA}A`, + }; + }), + }; + return kuber.signAndSubmitTx(req); + }, + + dRepRegistration: (stakeSigningKey: string, pkh: string) => { + const kuber = new Kuber(faucetWallet.address, faucetWallet.payment.private); + const req = { + certificates: [Kuber.generateCert("registerdrep", pkh)], + selections: [ + { + type: "PaymentSigningKeyShelley_ed25519", + description: "Stake Signing Key", + cborHex: `5820${stakeSigningKey}`, + }, + ], + }; + return kuber.signAndSubmitTx(req); + }, + + dRepDeRegistration: ( + addr: string, + signingKey: string, + stakePrivateKey: string, + pkh: string + ) => { + const kuber = new Kuber(addr, signingKey); + const selections = [ + { + type: "PaymentSigningKeyShelley_ed25519", + description: "Payment Signing Key", + cborHex: "5820" + stakePrivateKey, + }, + ]; + const req = { + selections, + inputs: addr, + certificates: [Kuber.generateCert("deregisterdrep", pkh)], + }; + return kuber.signAndSubmitTx(req); + }, + + stakeDelegation: ( + addr: string, + signingKey: string, + stakePrivateKey: string, + pkh: string, + dRep: string | "abstain" | "noconfidence" + ) => { + const kuber = new Kuber(addr, signingKey); + const selections = [ + { + type: "PaymentSigningKeyShelley_ed25519", + description: "Payment Signing Key", + cborHex: "5820" + stakePrivateKey, + }, + ]; + const req = { + selections, + certificates: [ + { + type: "delegate", + key: pkh, + drep: dRep, + }, + ], + }; + return kuber.signAndSubmitTx(req); + }, + + getBalance: async (addr: string) => { + const utxos: any[] = await callKuber(`/api/v3/utxo?address=${addr}`); + const balanceInLovelace = utxos.reduce( + (acc, utxo) => acc + utxo.value.lovelace, + 0 + ); + return balanceInLovelace / 1000000; + }, + + registerStake: ( + stakePrivateKey: string, + pkh: string, + signingKey: string, + addr: string + ) => { + const kuber = new Kuber(addr, signingKey); + const selections = [ + { + type: "PaymentSigningKeyShelley_ed25519", + description: "Payment Signing Key", + cborHex: "5820" + stakePrivateKey, + }, + ]; + const req = { + selections, + certificates: [Kuber.generateCert("registerstake", pkh)], + }; + return kuber.signAndSubmitTx(req); + }, + + createGovAction(proposalsCount = 2) { + const kuber = new Kuber(faucetWallet.address, faucetWallet.payment.private); + const infoProposal = { + deposit: 1000000000, + refundAccount: { + network: "Testnet", + credential: { + "key hash": + "db1bc3c3f99ce68977ceaf27ab4dd917123ef9e73f85c304236eab23", + }, + }, + anchor: { + url: "https://bit.ly/3zCH2HL", + dataHash: + "1111111111111111111111111111111111111111111111111111111111111111", + }, + }; + const req = kuber.signTx({ + proposals: Array.from({ length: proposalsCount }, (_, i) => infoProposal), + }); + return callKuber("/api/v1/tx?submit=true", "POST", JSON.stringify(req)); + }, + + getTransactionDetails(txHash: string) { + return fetch(config.apiUrl + "/api/v3/utxo?txin=" + txHash + "%230", { + method: "GET", + headers: { + "Content-Type": "application/json", + "api-key": config.apiKey, + }, + }); + }, + + queryUtxos(address: string): Promise<[KuberBalanceResponse]> { + return callKuber("/api/v3/utxo?address=" + address) as Promise< + [KuberBalanceResponse] + >; + }, + + voteOnProposal( + addr: string, + signingKey: string, + voter: string, // dRepHash + dRepStakePrivKey: string, + proposal: string + ) { + const kuber = new Kuber(addr, signingKey); + const req = { + selections: [ + { + type: "PaymentSigningKeyShelley_ed25519", + description: "Payment Signing Key", + cborHex: "5820" + dRepStakePrivKey, + }, + ], + vote: { + voter, + role: "drep", + proposal, + vote: true, + anchor: { + url: "https://bit.ly/3zCH2HL", + dataHash: + "1111111111111111111111111111111111111111111111111111111111111111", + }, + }, + }; + return kuber.signAndSubmitTx(req); + }, + + abstainDelegations( + stakePrivKeys: string[], + stakePkhs: string[] + ): Promise { + const kuber = new Kuber(faucetWallet.address, faucetWallet.payment.private); + const selections = stakePrivKeys.map((key) => { + return { + type: "PaymentSigningKeyShelley_ed25519", + description: "Payment Signing Key", + cborHex: "5820" + key, + }; + }); + + const certificates = stakePkhs.map((pkh) => { + return { + type: "delegate", + key: pkh, + drep: "abstain", + }; + }); + const req = { + selections, + certificates, + }; + return kuber.signAndSubmitTx(req); + }, +}; +async function callKuber( + path: any, + method: "GET" | "POST" = "GET", + body?: BodyInit, + contentType = "application/json" +) { + const url = config.apiUrl + path; + + const headers: Record = { + "api-key": config.apiKey, + }; + if (contentType) { + headers["content-type"] = contentType; + } + + const options: RequestInit = { + method, + headers, + }; + + if (method === "POST") { + if (body) options.body = body; + } + + return fetch(url, options).then(async (res) => { + if (res.status === 200) { + return res.json(); + } else { + return res.text().then((txt) => { + let err; + let json: any; + try { + json = JSON.parse(txt); + if (json) { + err = Error( + `KuberApi [Status ${res.status}] : ${ + json.message ? json.message : txt + }` + ); + } else { + err = Error(`KuberApi [Status ${res.status}] : ${txt}`); + } + } catch (e) { + err = Error(`KuberApi [Status ${res.status}] : ${txt}`); + } + err.status = res.status; + throw err; + }); + } + }); +} + +export default kuberService; diff --git a/tests/govtool-frontend/playwright/lib/types.ts b/tests/govtool-frontend/playwright/lib/types.ts new file mode 100644 index 000000000..7cfb36fc8 --- /dev/null +++ b/tests/govtool-frontend/playwright/lib/types.ts @@ -0,0 +1,52 @@ +import { CardanoTestWallet } from "@cardanoapi/cardano-test-wallet/types"; + +export type StaticWallet = CardanoTestWallet & { + dRepId: string; + address: string; +}; + +export type KuberValue = { + [policyId: string]: Record | BigInt | number; +}; + +export interface IProposal { + id: string; + txHash: string; + index: number; + type: string; + details: any; + expiryDate: string; + expiryEpochNo: number; + createdDate: string; + createdEpochNo: number; + url: string; + metadataHash: string; + title: string | null; + about: string | null; + motivation: string | null; + rationale: string | null; + metadata: any; + references: any; + yesVotes: number; + noVotes: number; +} + +export type IVote = { + drepId: string; + metadataHash: string; + url: string; + proposalId: string; + vote: string; // You might want to consider using a more specific type, like 'VoteType' enum +}; + +export type IVotedProposal = { + proposal: IProposal; + vote: IVote; +}; + +export type IDRepInfo = { + name: string; + email?: string; + bio?: string; + extraContentLinks?: string[]; +}; diff --git a/tests/govtool-frontend/playwright/package-lock.json b/tests/govtool-frontend/playwright/package-lock.json new file mode 100644 index 000000000..8c1c2433c --- /dev/null +++ b/tests/govtool-frontend/playwright/package-lock.json @@ -0,0 +1,5158 @@ +{ + "name": "intersect-govtool", + "version": "1.0.0", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "intersect-govtool", + "version": "1.0.0", + "license": "MIT", + "dependencies": { + "@cardanoapi/cardano-test-wallet": "^1.0.0", + "@faker-js/faker": "^8.4.1", + "@noble/curves": "^1.3.0", + "@noble/ed25519": "^2.0.0", + "@types/seedrandom": "^3.0.8", + "bech32": "^2.0.0", + "blakejs": "^1.2.1", + "buffer": "^6.0.3", + "cbor-x": "^1.5.8", + "dotenv": "^16.4.4", + "fast-check": "^3.17.2", + "lockfile": "^1.0.4", + "node-fetch": "v2", + "path": "^0.12.7", + "seedrandom": "^3.0.5" + }, + "devDependencies": { + "@playwright/test": "^1.41.2", + "@types/node": "^20.11.17", + "@types/node-fetch": "^2.6.11", + "allure-commandline": "^2.27.0", + "allure-playwright": "^2.15.0", + "copy-webpack-plugin": "^12.0.2", + "eslint": "^8.57.0", + "prettier": "3.2.5", + "ts-loader": "^9.5.1", + "tsconfig-paths-webpack-plugin": "^4.1.0", + "typescript": "^5.4.5", + "webpack": "^5.90.3", + "webpack-cli": "^5.1.4" + } + }, + "../../../../cardano-test-wallet": { + "version": "1.0.0", + "extraneous": true, + "license": "MIT", + "dependencies": { + "@noble/curves": "^1.3.0", + "@noble/ed25519": "^2.0.0", + "@types/seedrandom": "^3.0.8", + "bech32": "^2.0.0", + "blakejs": "^1.2.1", + "buffer": "^6.0.3", + "cbor-x": "^1.5.8", + "dotenv": "^16.4.4", + "node-fetch": "v2", + "path": "^0.12.7", + "seedrandom": "^3.0.5", + "typescript": "^5.4.2" + }, + "devDependencies": { + "@types/node": "^20.11.17", + "@types/node-fetch": "^2.6.11", + "copy-webpack-plugin": "^12.0.2", + "prettier": "3.2.5", + "ts-loader": "^9.5.1", + "tsconfig-paths-webpack-plugin": "^4.1.0", + "webpack": "^5.90.3", + "webpack-cli": "^5.1.4" + } + }, + "../../../../cardano-test-wallet/dist": { + "name": "@cardanoapi/cardano-test-wallet", + "version": "1.0.0", + "extraneous": true, + "license": "MIT" + }, + "node_modules/@aashutoshrathi/word-wrap": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", + "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@cardanoapi/cardano-test-wallet": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@cardanoapi/cardano-test-wallet/-/cardano-test-wallet-1.0.0.tgz", + "integrity": "sha512-mua97Dqo0E1YbGanLTdq9AhmMe8E0HvmC6uwDFPe4LG3M817Pp/5mXxwUD6CfFbGANQ/PuSTJ8m28qerlw1Arg==" + }, + "node_modules/@cbor-extract/cbor-extract-linux-x64": { + "version": "2.2.0", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@discoveryjs/json-ext": { + "version": "0.5.7", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", + "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.10.0", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.0.tgz", + "integrity": "sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==", + "dev": true, + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", + "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", + "dev": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.6.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/@eslint/eslintrc/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/@faker-js/faker": { + "version": "8.4.1", + "resolved": "https://registry.npmjs.org/@faker-js/faker/-/faker-8.4.1.tgz", + "integrity": "sha512-XQ3cU+Q8Uqmrbf2e0cIC/QN43sTBSC8KF12u29Mb47tWrt2hAgBXSgpZMj4Ao8Uk0iJcU99QsOCaIL8934obCg==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/fakerjs" + } + ], + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0", + "npm": ">=6.14.13" + } + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.11.14", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", + "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==", + "dev": true, + "dependencies": { + "@humanwhocodes/object-schema": "^2.0.2", + "debug": "^4.3.1", + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", + "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", + "dev": true + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.4", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.1.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/source-map": { + "version": "0.3.5", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.23", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@noble/curves": { + "version": "1.3.0", + "license": "MIT", + "dependencies": { + "@noble/hashes": "1.3.3" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@noble/ed25519": { + "version": "2.0.0", + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "license": "MIT" + }, + "node_modules/@noble/hashes": { + "version": "1.3.3", + "license": "MIT", + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@playwright/test": { + "version": "1.41.2", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "playwright": "1.41.2" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/@sindresorhus/merge-streams": { + "version": "2.3.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@types/eslint": { + "version": "8.56.4", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "*", + "@types/json-schema": "*" + } + }, + "node_modules/@types/eslint-scope": { + "version": "3.7.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/eslint": "*", + "@types/estree": "*" + } + }, + "node_modules/@types/estree": { + "version": "1.0.5", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "20.11.17", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/@types/node-fetch": { + "version": "2.6.11", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "form-data": "^4.0.0" + } + }, + "node_modules/@types/node-fetch/node_modules/@types/node": { + "version": "20.11.19", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/@types/seedrandom": { + "version": "3.0.8", + "license": "MIT" + }, + "node_modules/@ungap/structured-clone": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", + "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", + "dev": true + }, + "node_modules/@webassemblyjs/ast": { + "version": "1.11.6", + "dev": true, + "license": "MIT", + "dependencies": { + "@webassemblyjs/helper-numbers": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6" + } + }, + "node_modules/@webassemblyjs/floating-point-hex-parser": { + "version": "1.11.6", + "dev": true, + "license": "MIT" + }, + "node_modules/@webassemblyjs/helper-api-error": { + "version": "1.11.6", + "dev": true, + "license": "MIT" + }, + "node_modules/@webassemblyjs/helper-buffer": { + "version": "1.11.6", + "dev": true, + "license": "MIT" + }, + "node_modules/@webassemblyjs/helper-numbers": { + "version": "1.11.6", + "dev": true, + "license": "MIT", + "dependencies": { + "@webassemblyjs/floating-point-hex-parser": "1.11.6", + "@webassemblyjs/helper-api-error": "1.11.6", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/helper-wasm-bytecode": { + "version": "1.11.6", + "dev": true, + "license": "MIT" + }, + "node_modules/@webassemblyjs/helper-wasm-section": { + "version": "1.11.6", + "dev": true, + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-buffer": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/wasm-gen": "1.11.6" + } + }, + "node_modules/@webassemblyjs/ieee754": { + "version": "1.11.6", + "dev": true, + "license": "MIT", + "dependencies": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "node_modules/@webassemblyjs/leb128": { + "version": "1.11.6", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/utf8": { + "version": "1.11.6", + "dev": true, + "license": "MIT" + }, + "node_modules/@webassemblyjs/wasm-edit": { + "version": "1.11.6", + "dev": true, + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-buffer": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/helper-wasm-section": "1.11.6", + "@webassemblyjs/wasm-gen": "1.11.6", + "@webassemblyjs/wasm-opt": "1.11.6", + "@webassemblyjs/wasm-parser": "1.11.6", + "@webassemblyjs/wast-printer": "1.11.6" + } + }, + "node_modules/@webassemblyjs/wasm-gen": { + "version": "1.11.6", + "dev": true, + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/ieee754": "1.11.6", + "@webassemblyjs/leb128": "1.11.6", + "@webassemblyjs/utf8": "1.11.6" + } + }, + "node_modules/@webassemblyjs/wasm-opt": { + "version": "1.11.6", + "dev": true, + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-buffer": "1.11.6", + "@webassemblyjs/wasm-gen": "1.11.6", + "@webassemblyjs/wasm-parser": "1.11.6" + } + }, + "node_modules/@webassemblyjs/wasm-parser": { + "version": "1.11.6", + "dev": true, + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-api-error": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/ieee754": "1.11.6", + "@webassemblyjs/leb128": "1.11.6", + "@webassemblyjs/utf8": "1.11.6" + } + }, + "node_modules/@webassemblyjs/wast-printer": { + "version": "1.11.6", + "dev": true, + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.11.6", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webpack-cli/configtest": { + "version": "2.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.15.0" + }, + "peerDependencies": { + "webpack": "5.x.x", + "webpack-cli": "5.x.x" + } + }, + "node_modules/@webpack-cli/info": { + "version": "2.0.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.15.0" + }, + "peerDependencies": { + "webpack": "5.x.x", + "webpack-cli": "5.x.x" + } + }, + "node_modules/@webpack-cli/serve": { + "version": "2.0.5", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.15.0" + }, + "peerDependencies": { + "webpack": "5.x.x", + "webpack-cli": "5.x.x" + }, + "peerDependenciesMeta": { + "webpack-dev-server": { + "optional": true + } + } + }, + "node_modules/@xtuc/ieee754": { + "version": "1.2.0", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@xtuc/long": { + "version": "4.2.2", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/acorn": { + "version": "8.11.3", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-import-assertions": { + "version": "1.9.0", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^8" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/ajv": { + "version": "8.12.0", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats": { + "version": "2.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/ajv-keywords": { + "version": "5.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/allure-commandline": { + "version": "2.27.0", + "dev": true, + "license": "Apache-2.0", + "bin": { + "allure": "bin/allure" + } + }, + "node_modules/allure-js-commons": { + "version": "2.15.0", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "md5": "^2.3.0", + "properties": "^1.2.1", + "strip-ansi": "^5.2.0" + } + }, + "node_modules/allure-playwright": { + "version": "2.15.0", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "allure-js-commons": "2.15.0" + } + }, + "node_modules/ansi-regex": { + "version": "4.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/asynckit": { + "version": "0.4.0", + "dev": true, + "license": "MIT" + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "node_modules/base64-js": { + "version": "1.5.1", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/bech32": { + "version": "2.0.0", + "license": "MIT" + }, + "node_modules/blakejs": { + "version": "1.2.1", + "license": "MIT" + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.23.0", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "caniuse-lite": "^1.0.30001587", + "electron-to-chromium": "^1.4.668", + "node-releases": "^2.0.14", + "update-browserslist-db": "^1.0.13" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/buffer": { + "version": "6.0.3", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "dev": true, + "license": "MIT" + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001591", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/cbor-extract": { + "version": "2.2.0", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "dependencies": { + "node-gyp-build-optional-packages": "5.1.1" + }, + "bin": { + "download-cbor-prebuilds": "bin/download-prebuilds.js" + }, + "optionalDependencies": { + "@cbor-extract/cbor-extract-darwin-arm64": "2.2.0", + "@cbor-extract/cbor-extract-darwin-x64": "2.2.0", + "@cbor-extract/cbor-extract-linux-arm": "2.2.0", + "@cbor-extract/cbor-extract-linux-arm64": "2.2.0", + "@cbor-extract/cbor-extract-linux-x64": "2.2.0", + "@cbor-extract/cbor-extract-win32-x64": "2.2.0" + } + }, + "node_modules/cbor-x": { + "version": "1.5.8", + "license": "MIT", + "optionalDependencies": { + "cbor-extract": "^2.2.0" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/charenc": { + "version": "0.0.2", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": "*" + } + }, + "node_modules/chrome-trace-event": { + "version": "1.0.3", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0" + } + }, + "node_modules/clone-deep": { + "version": "4.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "dev": true, + "license": "MIT" + }, + "node_modules/colorette": { + "version": "2.0.20", + "dev": true, + "license": "MIT" + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "dev": true, + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/commander": { + "version": "10.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "node_modules/copy-webpack-plugin": { + "version": "12.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-glob": "^3.3.2", + "glob-parent": "^6.0.1", + "globby": "^14.0.0", + "normalize-path": "^3.0.0", + "schema-utils": "^4.2.0", + "serialize-javascript": "^6.0.2" + }, + "engines": { + "node": ">= 18.12.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.1.0" + } + }, + "node_modules/copy-webpack-plugin/node_modules/schema-utils": { + "version": "4.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/crypt": { + "version": "0.0.2", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": "*" + } + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/detect-libc": { + "version": "2.0.2", + "license": "Apache-2.0", + "optional": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/dotenv": { + "version": "16.4.4", + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.4.685", + "dev": true, + "license": "ISC" + }, + "node_modules/enhanced-resolve": { + "version": "5.15.1", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/envinfo": { + "version": "7.11.1", + "dev": true, + "license": "MIT", + "bin": { + "envinfo": "dist/cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/es-module-lexer": { + "version": "1.4.1", + "dev": true, + "license": "MIT" + }, + "node_modules/escalade": { + "version": "3.1.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz", + "integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.4", + "@eslint/js": "8.57.0", + "@humanwhocodes/config-array": "^0.11.14", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "@ungap/structured-clone": "^1.2.0", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.2.2", + "eslint-visitor-keys": "^3.4.3", + "espree": "^9.6.1", + "esquery": "^1.4.2", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "graphemer": "^1.4.0", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "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", + "strip-ansi": "^6.0.1", + "text-table": "^0.2.0" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-scope": { + "version": "5.1.1", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/@eslint/js": { + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.0.tgz", + "integrity": "sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/eslint/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/eslint/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/eslint/node_modules/eslint-scope": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/eslint/node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/eslint/node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/espree": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "dev": true, + "dependencies": { + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", + "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", + "dev": true, + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esquery/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse/node_modules/estraverse": { + "version": "5.3.0", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "4.3.0", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/events": { + "version": "3.3.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/fast-check": { + "version": "3.17.2", + "resolved": "https://registry.npmjs.org/fast-check/-/fast-check-3.17.2.tgz", + "integrity": "sha512-+3DPTxtxABLgmmVpYxrash3DHoq0cMa1jjLYNp3qqokKKhqVEaS4lbnaDKqWU5Dd6C2pEudPPBAEEQ9nUou9OQ==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/dubzzz" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fast-check" + } + ], + "dependencies": { + "pure-rand": "^6.1.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-glob": { + "version": "3.3.2", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true + }, + "node_modules/fastest-levenshtein": { + "version": "1.0.16", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4.9.1" + } + }, + "node_modules/fastq": { + "version": "1.17.1", + "dev": true, + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "4.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/flat": { + "version": "5.0.2", + "dev": true, + "license": "BSD-3-Clause", + "bin": { + "flat": "cli.js" + } + }, + "node_modules/flat-cache": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", + "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", + "dev": true, + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.3", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flatted": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", + "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", + "dev": true + }, + "node_modules/form-data": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "node_modules/function-bind": { + "version": "1.1.2", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/glob-to-regexp": { + "version": "0.4.1", + "dev": true, + "license": "BSD-2-Clause" + }, + "node_modules/globals": { + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globby": { + "version": "14.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@sindresorhus/merge-streams": "^2.1.0", + "fast-glob": "^3.3.2", + "ignore": "^5.2.4", + "path-type": "^5.0.0", + "slash": "^5.1.0", + "unicorn-magic": "^0.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "dev": true, + "license": "ISC" + }, + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true + }, + "node_modules/has-flag": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/hasown": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/ignore": { + "version": "5.3.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/import-fresh/node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/import-local": { + "version": "3.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + }, + "bin": { + "import-local-fixture": "fixtures/cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.3", + "license": "ISC" + }, + "node_modules/interpret": { + "version": "3.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/is-buffer": { + "version": "1.1.6", + "dev": true, + "license": "MIT" + }, + "node_modules/is-core-module": { + "version": "2.13.1", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-plain-object": { + "version": "2.0.4", + "dev": true, + "license": "MIT", + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "dev": true, + "license": "ISC" + }, + "node_modules/isobject": { + "version": "3.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/jest-worker": { + "version": "27.5.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/jest-worker/node_modules/@types/node": { + "version": "20.11.19", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "dev": true, + "license": "MIT" + }, + "node_modules/json-schema-traverse": { + "version": "1.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true + }, + "node_modules/json5": { + "version": "2.2.3", + "dev": true, + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/kind-of": { + "version": "6.0.3", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/loader-runner": { + "version": "4.3.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.11.5" + } + }, + "node_modules/locate-path": { + "version": "5.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/lockfile": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/lockfile/-/lockfile-1.0.4.tgz", + "integrity": "sha512-cvbTwETRfsFh4nHsL1eGWapU1XFi5Ot9E85sWAwia7Y7EgB7vfqcZhTKZ+l7hCGxSPoushMv5GKhT5PdLv03WA==", + "dependencies": { + "signal-exit": "^3.0.2" + } + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "node_modules/lru-cache": { + "version": "6.0.0", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/md5": { + "version": "2.3.0", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "charenc": "0.0.2", + "crypt": "0.0.2", + "is-buffer": "~1.1.6" + } + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/merge2": { + "version": "1.4.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.5", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "dev": true, + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true + }, + "node_modules/neo-async": { + "version": "2.6.2", + "dev": true, + "license": "MIT" + }, + "node_modules/node-fetch": { + "version": "2.7.0", + "license": "MIT", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/node-gyp-build-optional-packages": { + "version": "5.1.1", + "license": "MIT", + "optional": true, + "dependencies": { + "detect-libc": "^2.0.1" + }, + "bin": { + "node-gyp-build-optional-packages": "bin.js", + "node-gyp-build-optional-packages-optional": "optional.js", + "node-gyp-build-optional-packages-test": "build-test.js" + } + }, + "node_modules/node-releases": { + "version": "2.0.14", + "dev": true, + "license": "MIT" + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/optionator": { + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", + "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", + "dev": true, + "dependencies": { + "@aashutoshrathi/word-wrap": "^1.2.3", + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "2.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "4.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/path": { + "version": "0.12.7", + "license": "MIT", + "dependencies": { + "process": "^0.11.1", + "util": "^0.10.3" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "dev": true, + "license": "MIT" + }, + "node_modules/path-type": { + "version": "5.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/picocolors": { + "version": "1.0.0", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pkg-dir": { + "version": "4.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/playwright": { + "version": "1.41.2", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "playwright-core": "1.41.2" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=16" + }, + "optionalDependencies": { + "fsevents": "2.3.2" + } + }, + "node_modules/playwright-core": { + "version": "1.41.2", + "dev": true, + "license": "Apache-2.0", + "bin": { + "playwright-core": "cli.js" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prettier": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.2.5.tgz", + "integrity": "sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==", + "dev": true, + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/process": { + "version": "0.11.10", + "license": "MIT", + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/properties": { + "version": "1.2.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/pure-rand": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.1.0.tgz", + "integrity": "sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/dubzzz" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fast-check" + } + ] + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/randombytes": { + "version": "2.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/rechoir": { + "version": "0.8.0", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve": "^1.20.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve": { + "version": "1.22.8", + "dev": true, + "license": "MIT", + "dependencies": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-cwd": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-from": { + "version": "5.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/schema-utils": { + "version": "3.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/schema-utils/node_modules/ajv": { + "version": "6.12.6", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/schema-utils/node_modules/ajv-keywords": { + "version": "3.5.2", + "dev": true, + "license": "MIT", + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/schema-utils/node_modules/json-schema-traverse": { + "version": "0.4.1", + "dev": true, + "license": "MIT" + }, + "node_modules/seedrandom": { + "version": "3.0.5", + "license": "MIT" + }, + "node_modules/semver": { + "version": "7.6.0", + "dev": true, + "license": "ISC", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/serialize-javascript": { + "version": "6.0.2", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/shallow-clone": { + "version": "3.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" + }, + "node_modules/slash": { + "version": "5.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/source-map": { + "version": "0.7.4", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">= 8" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/source-map-support/node_modules/source-map": { + "version": "0.6.1", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/strip-ansi": { + "version": "5.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^4.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/strip-bom": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/tapable": { + "version": "2.2.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/terser": { + "version": "5.28.1", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.8.2", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/terser-webpack-plugin": { + "version": "5.3.10", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.20", + "jest-worker": "^27.4.5", + "schema-utils": "^3.1.1", + "serialize-javascript": "^6.0.1", + "terser": "^5.26.0" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.1.0" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "uglify-js": { + "optional": true + } + } + }, + "node_modules/terser/node_modules/commander": { + "version": "2.20.3", + "dev": true, + "license": "MIT" + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/tr46": { + "version": "0.0.3", + "license": "MIT" + }, + "node_modules/ts-loader": { + "version": "9.5.1", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.1.0", + "enhanced-resolve": "^5.0.0", + "micromatch": "^4.0.0", + "semver": "^7.3.4", + "source-map": "^0.7.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "typescript": "*", + "webpack": "^5.0.0" + } + }, + "node_modules/ts-loader/node_modules/enhanced-resolve": { + "version": "5.15.0", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/tsconfig-paths": { + "version": "4.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "json5": "^2.2.2", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/tsconfig-paths-webpack-plugin": { + "version": "4.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.1.0", + "enhanced-resolve": "^5.7.0", + "tsconfig-paths": "^4.1.2" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typescript": { + "version": "5.4.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz", + "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici-types": { + "version": "5.26.5", + "dev": true, + "license": "MIT" + }, + "node_modules/unicorn-magic": { + "version": "0.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.0.13", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/util": { + "version": "0.10.4", + "license": "MIT", + "dependencies": { + "inherits": "2.0.3" + } + }, + "node_modules/watchpack": { + "version": "2.4.0", + "dev": true, + "license": "MIT", + "dependencies": { + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "license": "BSD-2-Clause" + }, + "node_modules/webpack": { + "version": "5.90.3", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/eslint-scope": "^3.7.3", + "@types/estree": "^1.0.5", + "@webassemblyjs/ast": "^1.11.5", + "@webassemblyjs/wasm-edit": "^1.11.5", + "@webassemblyjs/wasm-parser": "^1.11.5", + "acorn": "^8.7.1", + "acorn-import-assertions": "^1.9.0", + "browserslist": "^4.21.10", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^5.15.0", + "es-module-lexer": "^1.2.1", + "eslint-scope": "5.1.1", + "events": "^3.2.0", + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.2.9", + "json-parse-even-better-errors": "^2.3.1", + "loader-runner": "^4.2.0", + "mime-types": "^2.1.27", + "neo-async": "^2.6.2", + "schema-utils": "^3.2.0", + "tapable": "^2.1.1", + "terser-webpack-plugin": "^5.3.10", + "watchpack": "^2.4.0", + "webpack-sources": "^3.2.3" + }, + "bin": { + "webpack": "bin/webpack.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependenciesMeta": { + "webpack-cli": { + "optional": true + } + } + }, + "node_modules/webpack-cli": { + "version": "5.1.4", + "dev": true, + "license": "MIT", + "dependencies": { + "@discoveryjs/json-ext": "^0.5.0", + "@webpack-cli/configtest": "^2.1.1", + "@webpack-cli/info": "^2.0.2", + "@webpack-cli/serve": "^2.0.5", + "colorette": "^2.0.14", + "commander": "^10.0.1", + "cross-spawn": "^7.0.3", + "envinfo": "^7.7.3", + "fastest-levenshtein": "^1.0.12", + "import-local": "^3.0.2", + "interpret": "^3.1.1", + "rechoir": "^0.8.0", + "webpack-merge": "^5.7.3" + }, + "bin": { + "webpack-cli": "bin/cli.js" + }, + "engines": { + "node": ">=14.15.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "5.x.x" + }, + "peerDependenciesMeta": { + "@webpack-cli/generators": { + "optional": true + }, + "webpack-bundle-analyzer": { + "optional": true + }, + "webpack-dev-server": { + "optional": true + } + } + }, + "node_modules/webpack-merge": { + "version": "5.10.0", + "dev": true, + "license": "MIT", + "dependencies": { + "clone-deep": "^4.0.1", + "flat": "^5.0.2", + "wildcard": "^2.0.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/webpack-sources": { + "version": "3.2.3", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "license": "MIT", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/wildcard": { + "version": "2.0.1", + "dev": true, + "license": "MIT" + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true + }, + "node_modules/yallist": { + "version": "4.0.0", + "dev": true, + "license": "ISC" + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + }, + "dependencies": { + "@aashutoshrathi/word-wrap": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", + "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", + "dev": true + }, + "@cardanoapi/cardano-test-wallet": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@cardanoapi/cardano-test-wallet/-/cardano-test-wallet-1.0.0.tgz", + "integrity": "sha512-mua97Dqo0E1YbGanLTdq9AhmMe8E0HvmC6uwDFPe4LG3M817Pp/5mXxwUD6CfFbGANQ/PuSTJ8m28qerlw1Arg==" + }, + "@cbor-extract/cbor-extract-linux-x64": { + "version": "2.2.0", + "optional": true + }, + "@discoveryjs/json-ext": { + "version": "0.5.7", + "dev": true + }, + "@eslint-community/eslint-utils": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", + "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^3.3.0" + } + }, + "@eslint-community/regexpp": { + "version": "4.10.0", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.0.tgz", + "integrity": "sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==", + "dev": true + }, + "@eslint/eslintrc": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", + "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", + "dev": true, + "requires": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.6.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "dependencies": { + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + } + } + }, + "@faker-js/faker": { + "version": "8.4.1", + "resolved": "https://registry.npmjs.org/@faker-js/faker/-/faker-8.4.1.tgz", + "integrity": "sha512-XQ3cU+Q8Uqmrbf2e0cIC/QN43sTBSC8KF12u29Mb47tWrt2hAgBXSgpZMj4Ao8Uk0iJcU99QsOCaIL8934obCg==" + }, + "@humanwhocodes/config-array": { + "version": "0.11.14", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", + "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==", + "dev": true, + "requires": { + "@humanwhocodes/object-schema": "^2.0.2", + "debug": "^4.3.1", + "minimatch": "^3.0.5" + } + }, + "@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true + }, + "@humanwhocodes/object-schema": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", + "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", + "dev": true + }, + "@jridgewell/gen-mapping": { + "version": "0.3.4", + "dev": true, + "requires": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "@jridgewell/resolve-uri": { + "version": "3.1.2", + "dev": true + }, + "@jridgewell/set-array": { + "version": "1.1.2", + "dev": true + }, + "@jridgewell/source-map": { + "version": "0.3.5", + "dev": true, + "requires": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "dev": true + }, + "@jridgewell/trace-mapping": { + "version": "0.3.23", + "dev": true, + "requires": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "@noble/curves": { + "version": "1.3.0", + "requires": { + "@noble/hashes": "1.3.3" + } + }, + "@noble/ed25519": { + "version": "2.0.0" + }, + "@noble/hashes": { + "version": "1.3.3" + }, + "@nodelib/fs.scandir": { + "version": "2.1.5", + "dev": true, + "requires": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + } + }, + "@nodelib/fs.stat": { + "version": "2.0.5", + "dev": true + }, + "@nodelib/fs.walk": { + "version": "1.2.8", + "dev": true, + "requires": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + } + }, + "@playwright/test": { + "version": "1.41.2", + "dev": true, + "requires": { + "playwright": "1.41.2" + } + }, + "@sindresorhus/merge-streams": { + "version": "2.3.0", + "dev": true + }, + "@types/eslint": { + "version": "8.56.4", + "dev": true, + "requires": { + "@types/estree": "*", + "@types/json-schema": "*" + } + }, + "@types/eslint-scope": { + "version": "3.7.7", + "dev": true, + "requires": { + "@types/eslint": "*", + "@types/estree": "*" + } + }, + "@types/estree": { + "version": "1.0.5", + "dev": true + }, + "@types/json-schema": { + "version": "7.0.15", + "dev": true + }, + "@types/node": { + "version": "20.11.17", + "dev": true, + "requires": { + "undici-types": "~5.26.4" + } + }, + "@types/node-fetch": { + "version": "2.6.11", + "dev": true, + "requires": { + "@types/node": "*", + "form-data": "^4.0.0" + }, + "dependencies": { + "@types/node": { + "version": "20.11.19", + "dev": true, + "requires": { + "undici-types": "~5.26.4" + } + } + } + }, + "@types/seedrandom": { + "version": "3.0.8" + }, + "@ungap/structured-clone": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", + "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", + "dev": true + }, + "@webassemblyjs/ast": { + "version": "1.11.6", + "dev": true, + "requires": { + "@webassemblyjs/helper-numbers": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6" + } + }, + "@webassemblyjs/floating-point-hex-parser": { + "version": "1.11.6", + "dev": true + }, + "@webassemblyjs/helper-api-error": { + "version": "1.11.6", + "dev": true + }, + "@webassemblyjs/helper-buffer": { + "version": "1.11.6", + "dev": true + }, + "@webassemblyjs/helper-numbers": { + "version": "1.11.6", + "dev": true, + "requires": { + "@webassemblyjs/floating-point-hex-parser": "1.11.6", + "@webassemblyjs/helper-api-error": "1.11.6", + "@xtuc/long": "4.2.2" + } + }, + "@webassemblyjs/helper-wasm-bytecode": { + "version": "1.11.6", + "dev": true + }, + "@webassemblyjs/helper-wasm-section": { + "version": "1.11.6", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-buffer": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/wasm-gen": "1.11.6" + } + }, + "@webassemblyjs/ieee754": { + "version": "1.11.6", + "dev": true, + "requires": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "@webassemblyjs/leb128": { + "version": "1.11.6", + "dev": true, + "requires": { + "@xtuc/long": "4.2.2" + } + }, + "@webassemblyjs/utf8": { + "version": "1.11.6", + "dev": true + }, + "@webassemblyjs/wasm-edit": { + "version": "1.11.6", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-buffer": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/helper-wasm-section": "1.11.6", + "@webassemblyjs/wasm-gen": "1.11.6", + "@webassemblyjs/wasm-opt": "1.11.6", + "@webassemblyjs/wasm-parser": "1.11.6", + "@webassemblyjs/wast-printer": "1.11.6" + } + }, + "@webassemblyjs/wasm-gen": { + "version": "1.11.6", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/ieee754": "1.11.6", + "@webassemblyjs/leb128": "1.11.6", + "@webassemblyjs/utf8": "1.11.6" + } + }, + "@webassemblyjs/wasm-opt": { + "version": "1.11.6", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-buffer": "1.11.6", + "@webassemblyjs/wasm-gen": "1.11.6", + "@webassemblyjs/wasm-parser": "1.11.6" + } + }, + "@webassemblyjs/wasm-parser": { + "version": "1.11.6", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-api-error": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/ieee754": "1.11.6", + "@webassemblyjs/leb128": "1.11.6", + "@webassemblyjs/utf8": "1.11.6" + } + }, + "@webassemblyjs/wast-printer": { + "version": "1.11.6", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.11.6", + "@xtuc/long": "4.2.2" + } + }, + "@webpack-cli/configtest": { + "version": "2.1.1", + "dev": true, + "requires": {} + }, + "@webpack-cli/info": { + "version": "2.0.2", + "dev": true, + "requires": {} + }, + "@webpack-cli/serve": { + "version": "2.0.5", + "dev": true, + "requires": {} + }, + "@xtuc/ieee754": { + "version": "1.2.0", + "dev": true + }, + "@xtuc/long": { + "version": "4.2.2", + "dev": true + }, + "acorn": { + "version": "8.11.3", + "dev": true + }, + "acorn-import-assertions": { + "version": "1.9.0", + "dev": true, + "requires": {} + }, + "acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "requires": {} + }, + "ajv": { + "version": "8.12.0", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + } + }, + "ajv-formats": { + "version": "2.1.1", + "dev": true, + "requires": { + "ajv": "^8.0.0" + } + }, + "ajv-keywords": { + "version": "5.1.0", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.3" + } + }, + "allure-commandline": { + "version": "2.27.0", + "dev": true + }, + "allure-js-commons": { + "version": "2.15.0", + "dev": true, + "requires": { + "md5": "^2.3.0", + "properties": "^1.2.1", + "strip-ansi": "^5.2.0" + } + }, + "allure-playwright": { + "version": "2.15.0", + "dev": true, + "requires": { + "allure-js-commons": "2.15.0" + } + }, + "ansi-regex": { + "version": "4.1.1", + "dev": true + }, + "ansi-styles": { + "version": "4.3.0", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "asynckit": { + "version": "0.4.0", + "dev": true + }, + "balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "base64-js": { + "version": "1.5.1" + }, + "bech32": { + "version": "2.0.0" + }, + "blakejs": { + "version": "1.2.1" + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "3.0.2", + "dev": true, + "requires": { + "fill-range": "^7.0.1" + } + }, + "browserslist": { + "version": "4.23.0", + "dev": true, + "requires": { + "caniuse-lite": "^1.0.30001587", + "electron-to-chromium": "^1.4.668", + "node-releases": "^2.0.14", + "update-browserslist-db": "^1.0.13" + } + }, + "buffer": { + "version": "6.0.3", + "requires": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "buffer-from": { + "version": "1.1.2", + "dev": true + }, + "callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true + }, + "caniuse-lite": { + "version": "1.0.30001591", + "dev": true + }, + "cbor-extract": { + "version": "2.2.0", + "optional": true, + "requires": { + "@cbor-extract/cbor-extract-darwin-arm64": "2.2.0", + "@cbor-extract/cbor-extract-darwin-x64": "2.2.0", + "@cbor-extract/cbor-extract-linux-arm": "2.2.0", + "@cbor-extract/cbor-extract-linux-arm64": "2.2.0", + "@cbor-extract/cbor-extract-linux-x64": "2.2.0", + "@cbor-extract/cbor-extract-win32-x64": "2.2.0", + "node-gyp-build-optional-packages": "5.1.1" + } + }, + "cbor-x": { + "version": "1.5.8", + "requires": { + "cbor-extract": "^2.2.0" + } + }, + "chalk": { + "version": "4.1.2", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "charenc": { + "version": "0.0.2", + "dev": true + }, + "chrome-trace-event": { + "version": "1.0.3", + "dev": true + }, + "clone-deep": { + "version": "4.0.1", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + } + }, + "color-convert": { + "version": "2.0.1", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "dev": true + }, + "colorette": { + "version": "2.0.20", + "dev": true + }, + "combined-stream": { + "version": "1.0.8", + "dev": true, + "requires": { + "delayed-stream": "~1.0.0" + } + }, + "commander": { + "version": "10.0.1", + "dev": true + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "copy-webpack-plugin": { + "version": "12.0.2", + "dev": true, + "requires": { + "fast-glob": "^3.3.2", + "glob-parent": "^6.0.1", + "globby": "^14.0.0", + "normalize-path": "^3.0.0", + "schema-utils": "^4.2.0", + "serialize-javascript": "^6.0.2" + }, + "dependencies": { + "schema-utils": { + "version": "4.2.0", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + } + } + } + }, + "cross-spawn": { + "version": "7.0.3", + "dev": true, + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, + "crypt": { + "version": "0.0.2", + "dev": true + }, + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "delayed-stream": { + "version": "1.0.0", + "dev": true + }, + "detect-libc": { + "version": "2.0.2", + "optional": true + }, + "doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, + "dotenv": { + "version": "16.4.4" + }, + "electron-to-chromium": { + "version": "1.4.685", + "dev": true + }, + "enhanced-resolve": { + "version": "5.15.1", + "dev": true, + "requires": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + } + }, + "envinfo": { + "version": "7.11.1", + "dev": true + }, + "es-module-lexer": { + "version": "1.4.1", + "dev": true + }, + "escalade": { + "version": "3.1.2", + "dev": true + }, + "escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true + }, + "eslint": { + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz", + "integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==", + "dev": true, + "requires": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.4", + "@eslint/js": "8.57.0", + "@humanwhocodes/config-array": "^0.11.14", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "@ungap/structured-clone": "^1.2.0", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.2.2", + "eslint-visitor-keys": "^3.4.3", + "espree": "^9.6.1", + "esquery": "^1.4.2", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "graphemer": "^1.4.0", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "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", + "strip-ansi": "^6.0.1", + "text-table": "^0.2.0" + }, + "dependencies": { + "@eslint/js": { + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.0.tgz", + "integrity": "sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==", + "dev": true + }, + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true + }, + "eslint-scope": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", + "dev": true, + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + } + }, + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true + }, + "find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "requires": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + } + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "requires": { + "p-locate": "^5.0.0" + } + }, + "p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "requires": { + "yocto-queue": "^0.1.0" + } + }, + "p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "requires": { + "p-limit": "^3.0.2" + } + }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.1" + } + } + } + }, + "eslint-scope": { + "version": "5.1.1", + "dev": true, + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + } + }, + "eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true + }, + "espree": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "dev": true, + "requires": { + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" + } + }, + "esquery": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", + "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", + "dev": true, + "requires": { + "estraverse": "^5.1.0" + }, + "dependencies": { + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true + } + } + }, + "esrecurse": { + "version": "4.3.0", + "dev": true, + "requires": { + "estraverse": "^5.2.0" + }, + "dependencies": { + "estraverse": { + "version": "5.3.0", + "dev": true + } + } + }, + "estraverse": { + "version": "4.3.0", + "dev": true + }, + "esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true + }, + "events": { + "version": "3.3.0", + "dev": true + }, + "fast-check": { + "version": "3.17.2", + "resolved": "https://registry.npmjs.org/fast-check/-/fast-check-3.17.2.tgz", + "integrity": "sha512-+3DPTxtxABLgmmVpYxrash3DHoq0cMa1jjLYNp3qqokKKhqVEaS4lbnaDKqWU5Dd6C2pEudPPBAEEQ9nUou9OQ==", + "requires": { + "pure-rand": "^6.1.0" + } + }, + "fast-deep-equal": { + "version": "3.1.3", + "dev": true + }, + "fast-glob": { + "version": "3.3.2", + "dev": true, + "requires": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "dependencies": { + "glob-parent": { + "version": "5.1.2", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + } + } + }, + "fast-json-stable-stringify": { + "version": "2.1.0", + "dev": true + }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true + }, + "fastest-levenshtein": { + "version": "1.0.16", + "dev": true + }, + "fastq": { + "version": "1.17.1", + "dev": true, + "requires": { + "reusify": "^1.0.4" + } + }, + "file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "requires": { + "flat-cache": "^3.0.4" + } + }, + "fill-range": { + "version": "7.0.1", + "dev": true, + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "find-up": { + "version": "4.1.0", + "dev": true, + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "flat": { + "version": "5.0.2", + "dev": true + }, + "flat-cache": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", + "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", + "dev": true, + "requires": { + "flatted": "^3.2.9", + "keyv": "^4.5.3", + "rimraf": "^3.0.2" + } + }, + "flatted": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", + "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", + "dev": true + }, + "form-data": { + "version": "4.0.0", + "dev": true, + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "function-bind": { + "version": "1.1.2", + "dev": true + }, + "glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "glob-parent": { + "version": "6.0.2", + "dev": true, + "requires": { + "is-glob": "^4.0.3" + } + }, + "glob-to-regexp": { + "version": "0.4.1", + "dev": true + }, + "globals": { + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "dev": true, + "requires": { + "type-fest": "^0.20.2" + } + }, + "globby": { + "version": "14.0.1", + "dev": true, + "requires": { + "@sindresorhus/merge-streams": "^2.1.0", + "fast-glob": "^3.3.2", + "ignore": "^5.2.4", + "path-type": "^5.0.0", + "slash": "^5.1.0", + "unicorn-magic": "^0.1.0" + } + }, + "graceful-fs": { + "version": "4.2.11", + "dev": true + }, + "graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "dev": true + }, + "hasown": { + "version": "2.0.1", + "dev": true, + "requires": { + "function-bind": "^1.1.2" + } + }, + "ieee754": { + "version": "1.2.1" + }, + "ignore": { + "version": "5.3.1", + "dev": true + }, + "import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "dependencies": { + "resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true + } + } + }, + "import-local": { + "version": "3.1.0", + "dev": true, + "requires": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + } + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.3" + }, + "interpret": { + "version": "3.1.1", + "dev": true + }, + "is-buffer": { + "version": "1.1.6", + "dev": true + }, + "is-core-module": { + "version": "2.13.1", + "dev": true, + "requires": { + "hasown": "^2.0.0" + } + }, + "is-extglob": { + "version": "2.1.1", + "dev": true + }, + "is-glob": { + "version": "4.0.3", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-number": { + "version": "7.0.0", + "dev": true + }, + "is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true + }, + "is-plain-object": { + "version": "2.0.4", + "dev": true, + "requires": { + "isobject": "^3.0.1" + } + }, + "isexe": { + "version": "2.0.0", + "dev": true + }, + "isobject": { + "version": "3.0.1", + "dev": true + }, + "jest-worker": { + "version": "27.5.1", + "dev": true, + "requires": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "dependencies": { + "@types/node": { + "version": "20.11.19", + "dev": true, + "requires": { + "undici-types": "~5.26.4" + } + }, + "supports-color": { + "version": "8.1.1", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "requires": { + "argparse": "^2.0.1" + } + }, + "json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true + }, + "json-parse-even-better-errors": { + "version": "2.3.1", + "dev": true + }, + "json-schema-traverse": { + "version": "1.0.0", + "dev": true + }, + "json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true + }, + "json5": { + "version": "2.2.3", + "dev": true + }, + "keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "requires": { + "json-buffer": "3.0.1" + } + }, + "kind-of": { + "version": "6.0.3", + "dev": true + }, + "levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + } + }, + "loader-runner": { + "version": "4.3.0", + "dev": true + }, + "locate-path": { + "version": "5.0.0", + "dev": true, + "requires": { + "p-locate": "^4.1.0" + } + }, + "lockfile": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/lockfile/-/lockfile-1.0.4.tgz", + "integrity": "sha512-cvbTwETRfsFh4nHsL1eGWapU1XFi5Ot9E85sWAwia7Y7EgB7vfqcZhTKZ+l7hCGxSPoushMv5GKhT5PdLv03WA==", + "requires": { + "signal-exit": "^3.0.2" + } + }, + "lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "lru-cache": { + "version": "6.0.0", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + }, + "md5": { + "version": "2.3.0", + "dev": true, + "requires": { + "charenc": "0.0.2", + "crypt": "0.0.2", + "is-buffer": "~1.1.6" + } + }, + "merge-stream": { + "version": "2.0.0", + "dev": true + }, + "merge2": { + "version": "1.4.1", + "dev": true + }, + "micromatch": { + "version": "4.0.5", + "dev": true, + "requires": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + } + }, + "mime-db": { + "version": "1.52.0", + "dev": true + }, + "mime-types": { + "version": "2.1.35", + "dev": true, + "requires": { + "mime-db": "1.52.0" + } + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "1.2.8", + "dev": true + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true + }, + "neo-async": { + "version": "2.6.2", + "dev": true + }, + "node-fetch": { + "version": "2.7.0", + "requires": { + "whatwg-url": "^5.0.0" + } + }, + "node-gyp-build-optional-packages": { + "version": "5.1.1", + "optional": true, + "requires": { + "detect-libc": "^2.0.1" + } + }, + "node-releases": { + "version": "2.0.14", + "dev": true + }, + "normalize-path": { + "version": "3.0.0", + "dev": true + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "optionator": { + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", + "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", + "dev": true, + "requires": { + "@aashutoshrathi/word-wrap": "^1.2.3", + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0" + } + }, + "p-limit": { + "version": "2.3.0", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "4.1.0", + "dev": true, + "requires": { + "p-limit": "^2.2.0" + } + }, + "p-try": { + "version": "2.2.0", + "dev": true + }, + "parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "requires": { + "callsites": "^3.0.0" + } + }, + "path": { + "version": "0.12.7", + "requires": { + "process": "^0.11.1", + "util": "^0.10.3" + } + }, + "path-exists": { + "version": "4.0.0", + "dev": true + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true + }, + "path-key": { + "version": "3.1.1", + "dev": true + }, + "path-parse": { + "version": "1.0.7", + "dev": true + }, + "path-type": { + "version": "5.0.0", + "dev": true + }, + "picocolors": { + "version": "1.0.0", + "dev": true + }, + "picomatch": { + "version": "2.3.1", + "dev": true + }, + "pkg-dir": { + "version": "4.2.0", + "dev": true, + "requires": { + "find-up": "^4.0.0" + } + }, + "playwright": { + "version": "1.41.2", + "dev": true, + "requires": { + "fsevents": "2.3.2", + "playwright-core": "1.41.2" + } + }, + "playwright-core": { + "version": "1.41.2", + "dev": true + }, + "prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true + }, + "prettier": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.2.5.tgz", + "integrity": "sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==", + "dev": true + }, + "process": { + "version": "0.11.10" + }, + "properties": { + "version": "1.2.1", + "dev": true + }, + "punycode": { + "version": "2.3.1", + "dev": true + }, + "pure-rand": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.1.0.tgz", + "integrity": "sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==" + }, + "queue-microtask": { + "version": "1.2.3", + "dev": true + }, + "randombytes": { + "version": "2.1.0", + "dev": true, + "requires": { + "safe-buffer": "^5.1.0" + } + }, + "rechoir": { + "version": "0.8.0", + "dev": true, + "requires": { + "resolve": "^1.20.0" + } + }, + "require-from-string": { + "version": "2.0.2", + "dev": true + }, + "resolve": { + "version": "1.22.8", + "dev": true, + "requires": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + } + }, + "resolve-cwd": { + "version": "3.0.0", + "dev": true, + "requires": { + "resolve-from": "^5.0.0" + } + }, + "resolve-from": { + "version": "5.0.0", + "dev": true + }, + "reusify": { + "version": "1.0.4", + "dev": true + }, + "rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "run-parallel": { + "version": "1.2.0", + "dev": true, + "requires": { + "queue-microtask": "^1.2.2" + } + }, + "safe-buffer": { + "version": "5.2.1", + "dev": true + }, + "schema-utils": { + "version": "3.3.0", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "dependencies": { + "ajv": { + "version": "6.12.6", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ajv-keywords": { + "version": "3.5.2", + "dev": true, + "requires": {} + }, + "json-schema-traverse": { + "version": "0.4.1", + "dev": true + } + } + }, + "seedrandom": { + "version": "3.0.5" + }, + "semver": { + "version": "7.6.0", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, + "serialize-javascript": { + "version": "6.0.2", + "dev": true, + "requires": { + "randombytes": "^2.1.0" + } + }, + "shallow-clone": { + "version": "3.0.1", + "dev": true, + "requires": { + "kind-of": "^6.0.2" + } + }, + "shebang-command": { + "version": "2.0.0", + "dev": true, + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "dev": true + }, + "signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" + }, + "slash": { + "version": "5.1.0", + "dev": true + }, + "source-map": { + "version": "0.7.4", + "dev": true + }, + "source-map-support": { + "version": "0.5.21", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "dev": true + } + } + }, + "strip-ansi": { + "version": "5.2.0", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + }, + "strip-bom": { + "version": "3.0.0", + "dev": true + }, + "strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + }, + "supports-preserve-symlinks-flag": { + "version": "1.0.0", + "dev": true + }, + "tapable": { + "version": "2.2.1", + "dev": true + }, + "terser": { + "version": "5.28.1", + "dev": true, + "requires": { + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.8.2", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "dependencies": { + "commander": { + "version": "2.20.3", + "dev": true + } + } + }, + "terser-webpack-plugin": { + "version": "5.3.10", + "dev": true, + "requires": { + "@jridgewell/trace-mapping": "^0.3.20", + "jest-worker": "^27.4.5", + "schema-utils": "^3.1.1", + "serialize-javascript": "^6.0.1", + "terser": "^5.26.0" + } + }, + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true + }, + "to-regex-range": { + "version": "5.0.1", + "dev": true, + "requires": { + "is-number": "^7.0.0" + } + }, + "tr46": { + "version": "0.0.3" + }, + "ts-loader": { + "version": "9.5.1", + "dev": true, + "requires": { + "chalk": "^4.1.0", + "enhanced-resolve": "^5.0.0", + "micromatch": "^4.0.0", + "semver": "^7.3.4", + "source-map": "^0.7.4" + }, + "dependencies": { + "enhanced-resolve": { + "version": "5.15.0", + "dev": true, + "requires": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + } + } + } + }, + "tsconfig-paths": { + "version": "4.2.0", + "dev": true, + "requires": { + "json5": "^2.2.2", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + } + }, + "tsconfig-paths-webpack-plugin": { + "version": "4.1.0", + "dev": true, + "requires": { + "chalk": "^4.1.0", + "enhanced-resolve": "^5.7.0", + "tsconfig-paths": "^4.1.2" + } + }, + "type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1" + } + }, + "type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true + }, + "typescript": { + "version": "5.4.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz", + "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==", + "dev": true + }, + "undici-types": { + "version": "5.26.5", + "dev": true + }, + "unicorn-magic": { + "version": "0.1.0", + "dev": true + }, + "update-browserslist-db": { + "version": "1.0.13", + "dev": true, + "requires": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + } + }, + "uri-js": { + "version": "4.4.1", + "dev": true, + "requires": { + "punycode": "^2.1.0" + } + }, + "util": { + "version": "0.10.4", + "requires": { + "inherits": "2.0.3" + } + }, + "watchpack": { + "version": "2.4.0", + "dev": true, + "requires": { + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" + } + }, + "webidl-conversions": { + "version": "3.0.1" + }, + "webpack": { + "version": "5.90.3", + "dev": true, + "requires": { + "@types/eslint-scope": "^3.7.3", + "@types/estree": "^1.0.5", + "@webassemblyjs/ast": "^1.11.5", + "@webassemblyjs/wasm-edit": "^1.11.5", + "@webassemblyjs/wasm-parser": "^1.11.5", + "acorn": "^8.7.1", + "acorn-import-assertions": "^1.9.0", + "browserslist": "^4.21.10", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^5.15.0", + "es-module-lexer": "^1.2.1", + "eslint-scope": "5.1.1", + "events": "^3.2.0", + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.2.9", + "json-parse-even-better-errors": "^2.3.1", + "loader-runner": "^4.2.0", + "mime-types": "^2.1.27", + "neo-async": "^2.6.2", + "schema-utils": "^3.2.0", + "tapable": "^2.1.1", + "terser-webpack-plugin": "^5.3.10", + "watchpack": "^2.4.0", + "webpack-sources": "^3.2.3" + } + }, + "webpack-cli": { + "version": "5.1.4", + "dev": true, + "requires": { + "@discoveryjs/json-ext": "^0.5.0", + "@webpack-cli/configtest": "^2.1.1", + "@webpack-cli/info": "^2.0.2", + "@webpack-cli/serve": "^2.0.5", + "colorette": "^2.0.14", + "commander": "^10.0.1", + "cross-spawn": "^7.0.3", + "envinfo": "^7.7.3", + "fastest-levenshtein": "^1.0.12", + "import-local": "^3.0.2", + "interpret": "^3.1.1", + "rechoir": "^0.8.0", + "webpack-merge": "^5.7.3" + } + }, + "webpack-merge": { + "version": "5.10.0", + "dev": true, + "requires": { + "clone-deep": "^4.0.1", + "flat": "^5.0.2", + "wildcard": "^2.0.0" + } + }, + "webpack-sources": { + "version": "3.2.3", + "dev": true + }, + "whatwg-url": { + "version": "5.0.0", + "requires": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "which": { + "version": "2.0.2", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "wildcard": { + "version": "2.0.1", + "dev": true + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true + }, + "yallist": { + "version": "4.0.0", + "dev": true + }, + "yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true + } + } +} diff --git a/tests/govtool-frontend/playwright/package.json b/tests/govtool-frontend/playwright/package.json new file mode 100644 index 000000000..c42c5ff45 --- /dev/null +++ b/tests/govtool-frontend/playwright/package.json @@ -0,0 +1,45 @@ +{ + "name": "intersect-govtool", + "version": "1.0.0", + "license": "MIT", + "devDependencies": { + "@playwright/test": "^1.41.2", + "@types/node": "^20.11.17", + "@types/node-fetch": "^2.6.11", + "allure-commandline": "^2.27.0", + "allure-playwright": "^2.15.0", + "copy-webpack-plugin": "^12.0.2", + "eslint": "^8.57.0", + "prettier": "3.2.5", + "ts-loader": "^9.5.1", + "tsconfig-paths-webpack-plugin": "^4.1.0", + "typescript": "^5.4.5", + "webpack": "^5.90.3", + "webpack-cli": "^5.1.4" + }, + "scripts": { + "package-wallet": "tsc ./lib/_mock/cardano-test-wallet/types.ts --outDir dist/@types/cardano-test-wallet --declaration && npx webpack", + "allure:generate": "npx allure generate ./allure-results --clean", + "allure:open": "npx allure open ./allure-report", + "allure:serve": "npx allure serve", + "test": "npx playwright test", + "format": "prettier . --write" + }, + "dependencies": { + "@cardanoapi/cardano-test-wallet": "^1.0.0", + "@faker-js/faker": "^8.4.1", + "@noble/curves": "^1.3.0", + "@noble/ed25519": "^2.0.0", + "@types/seedrandom": "^3.0.8", + "bech32": "^2.0.0", + "blakejs": "^1.2.1", + "buffer": "^6.0.3", + "cbor-x": "^1.5.8", + "dotenv": "^16.4.4", + "fast-check": "^3.17.2", + "lockfile": "^1.0.4", + "node-fetch": "v2", + "path": "^0.12.7", + "seedrandom": "^3.0.5" + } +} diff --git a/tests/govtool-frontend/playwright/playwright.config.ts b/tests/govtool-frontend/playwright/playwright.config.ts index 3439dd15c..bcd673974 100644 --- a/tests/govtool-frontend/playwright/playwright.config.ts +++ b/tests/govtool-frontend/playwright/playwright.config.ts @@ -1,6 +1,7 @@ import { defineConfig, devices } from "@playwright/test"; -import { config } from "dotenv"; import { testPlanFilter } from "allure-playwright/dist/testplan"; +import { config } from "dotenv"; +import environments from "lib/constants/environments"; config(); @@ -22,30 +23,70 @@ export default defineConfig({ /* Retry on CI only */ retries: 0, /* Opt out of parallel tests on CI. */ - workers: process.env.CI ? parseInt(process.env.WORKERS) : undefined, + workers: process.env.CI ? parseInt(process.env.TEST_WORKERS) : undefined, /*use Allure Playwright's testPlanFilter() to determine the grep parameter*/ grep: testPlanFilter(), /* Reporter to use. See https://playwright.dev/docs/test-reporters */ - reporter: [["line"], ["allure-playwright"]], + reporter: process.env.CI ? [["line"], ["allure-playwright"]] : [["line"]], /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */ use: { /* Base URL to use in actions like `await page.goto('/')`. */ - baseURL: "", + baseURL: environments.frontendUrl, /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */ trace: "on-first-retry", screenshot: "only-on-failure", - // video:'retain-on-failure', + // video: "on", }, /* Configure projects for major browsers */ projects: [ { - name: "chrome", + name: "auth setup", + testMatch: "**/auth.setup.ts", + }, + { + name: "dRep setup", + testMatch: "**/dRep.setup.ts", + dependencies: process.env.CI ? ["wallet bootstrap"] : [], + }, + { + name: "wallet bootstrap", + testMatch: "**/wallet.bootstrap.ts", + }, + { + name: "transaction", use: { ...devices["Desktop Chrome"] }, + testMatch: "**/*.tx.spec.ts", + dependencies: process.env.CI ? ["auth setup", "wallet bootstrap"] : [], }, + { + name: "logged in", + use: { ...devices["Desktop Chrome"] }, + testMatch: "**/*.loggedin.spec.ts", + dependencies: process.env.CI ? ["auth setup"] : [], + }, + { + name: "dRep", + use: { ...devices["Desktop Chrome"] }, + testMatch: "**/*.dRep.spec.ts", + dependencies: process.env.CI ? ["auth setup", "dRep setup"] : [], + }, + { + name: "independent", + use: { ...devices["Desktop Chrome"] }, + testIgnore: [ + "**/*.tx.spec.ts", + "**/*.loggedin.spec.ts", + "**/*.dRep.spec.ts", + ], + }, + // { + // name: "cleanup adaHolder", + // testMatch: "**/*.teardown.ts", + // }, /* Test against mobile viewports. */ // { @@ -70,8 +111,8 @@ export default defineConfig({ /* Run your local dev server before starting the tests */ // webServer: { - // command: 'npm run start', - // url: 'http://127.0.0.1:3000', + // command: "cd govtool/frontend && npm run start", + // // url: "http://127.0.0.1:3000", // reuseExistingServer: !process.env.CI, // }, }); diff --git a/tests/govtool-frontend/playwright/tests/1-wallet-connect/walletConnect.loggedin.spec.ts b/tests/govtool-frontend/playwright/tests/1-wallet-connect/walletConnect.loggedin.spec.ts new file mode 100644 index 000000000..ab080382a --- /dev/null +++ b/tests/govtool-frontend/playwright/tests/1-wallet-connect/walletConnect.loggedin.spec.ts @@ -0,0 +1,13 @@ +import { user01Wallet } from "@constants/staticWallets"; +import { test } from "@fixtures/walletExtension"; +import LoginPage from "@pages/loginPage"; + +test.use({ storageState: ".auth/user01.json", wallet: user01Wallet }); + +test("1B: Should connect wallet with single stake key @smoke @fast", async ({ + page, +}) => { + const loginPage = new LoginPage(page); + await loginPage.goto(); + await loginPage.isLoggedIn(); +}); diff --git a/tests/govtool-frontend/playwright/tests/1-wallet-connect/walletConnect.spec.ts b/tests/govtool-frontend/playwright/tests/1-wallet-connect/walletConnect.spec.ts new file mode 100644 index 000000000..ea33fdcb4 --- /dev/null +++ b/tests/govtool-frontend/playwright/tests/1-wallet-connect/walletConnect.spec.ts @@ -0,0 +1,52 @@ +import createWallet from "@fixtures/createWallet"; +import { test } from "@fixtures/walletExtension"; +import convertBufferToHex from "@helpers/convertBufferToHex"; +import { ShelleyWallet } from "@helpers/crypto"; +import LoginPage from "@pages/loginPage"; +import { expect } from "@playwright/test"; + +test("1A. Should connect wallet and choose stake-key to use @smoke @fast", async ({ + page, +}) => { + const shellyWallet = await ShelleyWallet.generate(); + const extraPubStakeKey = convertBufferToHex(shellyWallet.stakeKey.public); + const extraRewardAddress = convertBufferToHex( + shellyWallet.rewardAddressRawBytes(0) + ); + + await createWallet(page, { + extraRegisteredPubStakeKeys: [extraPubStakeKey], + extraRewardAddresses: [extraRewardAddress], + }); + + const loginPage = new LoginPage(page); + await loginPage.login(); +}); + +test("1C: Should disconnect Wallet When connected @smoke @fast", async ({ + page, +}) => { + await createWallet(page); + + const loginPage = new LoginPage(page); + await loginPage.login(); + + await loginPage.logout(); +}); + +test("1D. Should check correct network (Testnet/Mainnet) on connection @smoke @fast", async ({ + page, +}) => { + const wrongNetworkId = 1; // mainnet network + await createWallet(page, { networkId: wrongNetworkId }); + + const errors: Array = []; + page.on("pageerror", (error) => { + errors.push(error); + }); + + const loginPage = new LoginPage(page); + await loginPage.login(); + + expect(errors).not.toHaveLength(0); +}); diff --git a/tests/govtool-frontend/playwright/tests/2-delegation/delegation.dRep.spec.ts b/tests/govtool-frontend/playwright/tests/2-delegation/delegation.dRep.spec.ts new file mode 100644 index 000000000..d027f40a2 --- /dev/null +++ b/tests/govtool-frontend/playwright/tests/2-delegation/delegation.dRep.spec.ts @@ -0,0 +1,66 @@ +import environments from "@constants/environments"; +import { adaHolder01Wallet, dRep01Wallet } from "@constants/staticWallets"; +import { createTempDRepAuth } from "@datafactory/createAuth"; +import { test } from "@fixtures/walletExtension"; +import { ShelleyWallet } from "@helpers/crypto"; +import { createNewPageWithWallet } from "@helpers/page"; +import { pollTransaction, waitForTxConfirmation } from "@helpers/transaction"; +import DelegationPage from "@pages/delegationPage"; +import { expect } from "@playwright/test"; +import kuberService from "@services/kuberService"; + +test.describe("Delegate to others", () => { + test.use({ + storageState: ".auth/adaHolder01.json", + wallet: adaHolder01Wallet, + }); + + test("2A. Should show delegated DRep Id on dashboard after delegation @slow @critical", async ({ + page, + }, testInfo) => { + test.setTimeout(testInfo.timeout + 2 * environments.txTimeOut); + + const delegationPage = new DelegationPage(page); + await delegationPage.goto(); + + delegationPage.delegateToDRep(dRep01Wallet.dRepId); + await waitForTxConfirmation(page); + + page.goto("/"); + await expect(page.getByTestId("delegated-dRep-id")).toHaveText( + dRep01Wallet.dRepId + ); + }); +}); + +test.describe("Delegate to myself", () => { + test("2E. Should register as SoleVoter @slow @critical", async ({ + page, + browser, + }, testInfo) => { + test.setTimeout(testInfo.timeout + 2 * environments.txTimeOut); + + const wallet = await ShelleyWallet.generate(); + const txRes = await kuberService.transferADA( + [wallet.addressBech32(environments.networkId)], + 600 + ); + await pollTransaction(txRes.txId, txRes.address); + const dRepAuth = await createTempDRepAuth(page, wallet); + const dRepPage = await createNewPageWithWallet(browser, { + storageState: dRepAuth, + wallet, + enableStakeSigning: true, + }); + await dRepPage.goto("/"); + await dRepPage.getByTestId("register-as-sole-voter-button").click(); + await dRepPage.getByTestId("retire-button").click(); // BUG: Incorrect test-id , it should be continue-retirement + await expect( + dRepPage.getByTestId("registration-transaction-submitted-modal") + ).toBeVisible(); + dRepPage.getByTestId("confirm-modal-button").click(); + await waitForTxConfirmation(dRepPage); + + await expect(dRepPage.getByText("You are a Sole Voter")).toBeVisible(); + }); +}); diff --git a/tests/govtool-frontend/playwright/tests/2-delegation/delegation.loggedin.spec.ts b/tests/govtool-frontend/playwright/tests/2-delegation/delegation.loggedin.spec.ts new file mode 100644 index 000000000..8d3f28652 --- /dev/null +++ b/tests/govtool-frontend/playwright/tests/2-delegation/delegation.loggedin.spec.ts @@ -0,0 +1,49 @@ +import { user01Wallet } from "@constants/staticWallets"; +import { test } from "@fixtures/walletExtension"; +import DelegationPage from "@pages/delegationPage"; +import { expect } from "@playwright/test"; + +test.use({ storageState: ".auth/user01.json", wallet: user01Wallet }); + +test("2B. Should access delegation to dRep page @smoke @fast", async ({ + page, +}) => { + await page.goto("/"); + + await page.getByTestId("delegate-button").click(); // BUG: testId -> view-dRep-directory + await expect( + page.getByRole("navigation").getByText("DRep Directory") + ).toBeVisible(); +}); + +// Skipped: No need to insert dRep id to delegate +test.skip("2I. Should check validity of DRep Id @slow", async ({ page }) => { + // const urlToIntercept = "**/utxo?**"; + // const invalidDRepId = generateRandomDRepId(); + // const validDRepId = dRep01Wallet.dRepId; + // // Invalidity checks + // const delegationPage = new DelegationPage(page); + // await delegationPage.goto(); + // await delegationPage.delegateToDRep(invalidDRepId); + // await expect(delegationPage.delegationErrorModal).toBeVisible(); + // await delegationPage.resetDRepForm(); + // // Validity checks + // await delegationPage.dRepInput.fill(validDRepId); + // await delegationPage.delegateBtn.click(); + // const response = await page.waitForResponse(urlToIntercept); + // expect(response.body.length).toEqual(0); +}); + +test("2D. Verify Delegation Behavior in Connected State @smoke @fast", async ({ + page, +}) => { + const delegationPage = new DelegationPage(page); + await delegationPage.goto(); + + // Verifying delegation options + await delegationPage.delegationOptionsDropdown.click(); + await expect(delegationPage.signalNoConfidenceCard).toBeVisible(); + await expect(delegationPage.abstainDelegationCard).toBeVisible(); + + expect(await delegationPage.delegateBtns.count()).toBeGreaterThanOrEqual(2); +}); diff --git a/tests/govtool-frontend/playwright/tests/2-delegation/delegation.spec.ts b/tests/govtool-frontend/playwright/tests/2-delegation/delegation.spec.ts new file mode 100644 index 000000000..7104d728d --- /dev/null +++ b/tests/govtool-frontend/playwright/tests/2-delegation/delegation.spec.ts @@ -0,0 +1,14 @@ +import { expect, test } from "@playwright/test"; + +test("2C. Verify DRep Behavior in Disconnected State @smoke @fast", async ({ + page, +}) => { + await page.goto("/"); + + await page.getByTestId("delegate-connect-wallet-button").click(); + await page + .locator('[data-testid$="-connect-to-delegate-button"]') + .first() + .click(); + await expect(page.getByTestId("connect-your-wallet-modal")).toBeVisible(); +}); diff --git a/tests/govtool-frontend/playwright/tests/2-delegation/delegation.tx.spec.ts b/tests/govtool-frontend/playwright/tests/2-delegation/delegation.tx.spec.ts new file mode 100644 index 000000000..a172805b7 --- /dev/null +++ b/tests/govtool-frontend/playwright/tests/2-delegation/delegation.tx.spec.ts @@ -0,0 +1,21 @@ +import { adaHolder02Wallet, dRep01Wallet } from "@constants/staticWallets"; +import { test } from "@fixtures/walletExtension"; +import { waitForTxConfirmation } from "@helpers/transaction"; +import DelegationPage from "@pages/delegationPage"; + +test.use({ storageState: ".auth/adaHolder02.json", wallet: adaHolder02Wallet }); + +// Skipped: Blocked because delegation is not working +test.skip("2F. Should change delegated dRep @slow @critical", async ({ + page, +}) => { + const delegationPage = new DelegationPage(page); + await delegationPage.goto(); + delegationPage.delegateToDRep(dRep01Wallet.dRepId); + await waitForTxConfirmation(page); + + // await delegationPage.goto("/"); + // await adaHolderPage.getByTestId("change-dRep-button").click(); + // await delegationPage.delegateToDRep(dRep02Wallet.dRepId); + // await waitForTxConfirmation(page); +}); diff --git a/tests/govtool-frontend/playwright/tests/3-drep-registration/dRepRegistration.dRep.spec.ts b/tests/govtool-frontend/playwright/tests/3-drep-registration/dRepRegistration.dRep.spec.ts new file mode 100644 index 000000000..92ed56917 --- /dev/null +++ b/tests/govtool-frontend/playwright/tests/3-drep-registration/dRepRegistration.dRep.spec.ts @@ -0,0 +1,127 @@ +import environments from "@constants/environments"; +import { dRep01Wallet } from "@constants/staticWallets"; +import { createTempDRepAuth } from "@datafactory/createAuth"; +import { test } from "@fixtures/walletExtension"; +import convertBufferToHex from "@helpers/convertBufferToHex"; +import { ShelleyWallet } from "@helpers/crypto"; +import { createNewPageWithWallet } from "@helpers/page"; +import { pollTransaction, waitForTxConfirmation } from "@helpers/transaction"; +import DRepRegistrationPage from "@pages/dRepRegistrationPage"; +import GovernanceActionsPage from "@pages/governanceActionsPage"; +import { expect } from "@playwright/test"; +import kuberService from "@services/kuberService"; + +test.describe("Logged in DReps", () => { + test.use({ storageState: ".auth/dRep01.json", wallet: dRep01Wallet }); + + test("3A. Should show dRepId on dashboard after connecting registered dRep Wallet", async ({ + page, + }) => { + await page.goto("/"); + await expect(page.getByTestId("dRep-id-display")).toContainText( + dRep01Wallet.dRepId + ); // BUG: testId -> dRep-id-display-dashboard (It is taking sidebar dRep-id) + }); +}); + +test.describe("Temporary DReps", () => { + test("3G. Should show confirmation message with link to view transaction, when DRep registration txn is submitted @slow ", async ({ + page, + browser, + }, testInfo) => { + test.setTimeout(testInfo.timeout + environments.txTimeOut); + + const wallet = await ShelleyWallet.generate(); + const res = await kuberService.transferADA( + [wallet.addressBech32(environments.networkId)], + 600 + ); + await pollTransaction(res.txId, res.address); + + const tempDRepAuth = await createTempDRepAuth(page, wallet); + const dRepPage = await createNewPageWithWallet(browser, { + storageState: tempDRepAuth, + wallet, + enableStakeSigning: true, + }); + + const dRepRegistrationPage = new DRepRegistrationPage(dRepPage); + await dRepRegistrationPage.goto(); + await dRepRegistrationPage.register({ name: "Test_dRep" }); + + await expect(dRepRegistrationPage.registrationSuccessModal).toBeVisible(); + await expect( + dRepRegistrationPage.registrationSuccessModal.getByText("this link") + ).toBeVisible(); + }); + + test("3I. Should verify retire as DRep @slow", async ({ + page, + browser, + }, testInfo) => { + test.setTimeout(testInfo.timeout + environments.txTimeOut); + + const wallet = await ShelleyWallet.generate(); + const registrationRes = await kuberService.dRepRegistration( + convertBufferToHex(wallet.stakeKey.private), + convertBufferToHex(wallet.stakeKey.pkh) + ); + await pollTransaction(registrationRes.txId, registrationRes.address); + + const tempDRepAuth = await createTempDRepAuth(page, wallet); + const dRepPage = await createNewPageWithWallet(browser, { + storageState: tempDRepAuth, + wallet, + enableStakeSigning: true, + }); + + await dRepPage.goto("/"); + await dRepPage.getByTestId("retire-button").click(); + await dRepPage.getByTestId("retire-button").click(); // BUG testId -> continue-retire-button + + await expect( + dRepPage.getByTestId("retirement-transaction-error-modal") + ).toBeVisible(); + }); + + test("3J. Verify DRep behavior in retired state", async ({ + page, + browser, + }, testInfo) => { + test.setTimeout(testInfo.timeout + 3 * environments.txTimeOut); + + const wallet = await ShelleyWallet.generate(); + const registrationRes = await kuberService.dRepRegistration( + convertBufferToHex(wallet.stakeKey.private), + convertBufferToHex(wallet.stakeKey.pkh) + ); + await pollTransaction(registrationRes.txId, registrationRes.address); + + const res = await kuberService.transferADA([ + wallet.addressBech32(environments.networkId), + ]); + await pollTransaction(res.txId, res.address); + + const dRepAuth = await createTempDRepAuth(page, wallet); + const dRepPage = await createNewPageWithWallet(browser, { + storageState: dRepAuth, + wallet, + enableStakeSigning: true, + }); + + await dRepPage.goto("/"); + await dRepPage.getByTestId("retire-button").click(); + await dRepPage.getByTestId("retire-button").click(); // BUG: testId -> continue-retire-button + await expect( + dRepPage.getByTestId("retirement-transaction-submitted-modal") + ).toBeVisible(); + dRepPage.getByTestId("confirm-modal-button").click(); + await waitForTxConfirmation(dRepPage); + + const governanceActionsPage = new GovernanceActionsPage(dRepPage); + await governanceActionsPage.goto(); + const govActionDetailsPage = + await governanceActionsPage.viewFirstProposal(); + await expect(govActionDetailsPage.voteBtn).not.toBeVisible(); + }); +}); diff --git a/tests/govtool-frontend/playwright/tests/3-drep-registration/dRepRegistration.loggedin.spec.ts b/tests/govtool-frontend/playwright/tests/3-drep-registration/dRepRegistration.loggedin.spec.ts new file mode 100644 index 000000000..a263302a8 --- /dev/null +++ b/tests/govtool-frontend/playwright/tests/3-drep-registration/dRepRegistration.loggedin.spec.ts @@ -0,0 +1,65 @@ +import { user01Wallet } from "@constants/staticWallets"; +import { faker } from "@faker-js/faker"; +import { test } from "@fixtures/walletExtension"; +import DRepRegistrationPage from "@pages/dRepRegistrationPage"; +import { expect } from "@playwright/test"; + +test.use({ + storageState: ".auth/user01.json", + wallet: user01Wallet, +}); + +test("3B. Should access DRep registration page @fast @smoke", async ({ + page, +}) => { + await page.goto("/"); + + await page.getByTestId("register-button").click(); + await expect(page.getByText("Become a DRep")).toBeVisible(); +}); + +test("3D.Verify DRep registration functionality with Wallet Connected State State @fast @smoke", async ({ + page, +}) => { + const dRepRegistrationPage = new DRepRegistrationPage(page); + await dRepRegistrationPage.goto(); + + await expect(dRepRegistrationPage.nameInput).toBeVisible(); + await expect(dRepRegistrationPage.emailInput).toBeVisible(); + await expect(dRepRegistrationPage.bioInput).toBeVisible(); + await expect(dRepRegistrationPage.linkInput).toBeVisible(); + await expect(dRepRegistrationPage.addLinkBtn).toBeVisible(); + await expect(dRepRegistrationPage.continueBtn).toBeVisible(); +}); + +// Skipped: Because there are no fields for url and hash inputs. +test.skip("3E. Should reject invalid data and accept valid data @smoke @fast", async ({ + page, +}) => { + const dRepRegistrationPage = new DRepRegistrationPage(page); + await dRepRegistrationPage.goto(); + + // Invalidity test + faker.helpers + .multiple(() => faker.internet.displayName(), { count: 100 }) + .forEach(async (dRepName) => { + await dRepRegistrationPage.nameInput.fill(dRepName); + await dRepRegistrationPage.nameInput.clear({ force: true }); + }); + + // Validity test +}); + +test("3F. Should create proper DRep registration request, when registered with data @slow", async ({ + page, +}) => { + const urlToIntercept = "**/utxo?**"; + + const dRepRegistrationPage = new DRepRegistrationPage(page); + await dRepRegistrationPage.goto(); + + await dRepRegistrationPage.register({ name: "Test_dRep" }); + + const response = await page.waitForResponse(urlToIntercept); + expect(response.body.length).toEqual(0); +}); diff --git a/tests/govtool-frontend/playwright/tests/3-drep-registration/dRepRegistration.spec.ts b/tests/govtool-frontend/playwright/tests/3-drep-registration/dRepRegistration.spec.ts new file mode 100644 index 000000000..9daf86969 --- /dev/null +++ b/tests/govtool-frontend/playwright/tests/3-drep-registration/dRepRegistration.spec.ts @@ -0,0 +1,10 @@ +import { test, expect } from "@playwright/test"; + +test("3C. Should open wallet connection popup, when Register as DRep from wallet unconnected state @smoke @fast", async ({ + page, +}) => { + await page.goto("/"); + + await page.getByTestId("register-connect-wallet-button").click(); + await expect(page.getByTestId("connect-your-wallet-modal")).toBeVisible(); +}); diff --git a/tests/govtool-frontend/playwright/tests/3-drep-registration/dRepRegistration.tx.spec.ts b/tests/govtool-frontend/playwright/tests/3-drep-registration/dRepRegistration.tx.spec.ts new file mode 100644 index 000000000..50798e04b --- /dev/null +++ b/tests/govtool-frontend/playwright/tests/3-drep-registration/dRepRegistration.tx.spec.ts @@ -0,0 +1,16 @@ +import { dRep01Wallet } from "@constants/staticWallets"; +import { test } from "@fixtures/walletExtension"; +import { expect } from "@playwright/test"; +import * as crypto from "crypto"; + +test.describe("Logged in", () => { + test.use({ storageState: ".auth/dRep01.json", wallet: dRep01Wallet }); + + // Skipped: No option to update metadata + test.skip("3H. Should be able to update metadata @slow", async ({ page }) => { + page.getByTestId("change-metadata-button").click(); + page.getByTestId("url-input").fill("https://google.com"); + page.getByTestId("hash-input").fill(crypto.randomBytes(32).toString("hex")); + await expect(page.getByTestId("confirm-modal-button")).toBeVisible(); + }); +}); diff --git a/tests/govtool-frontend/playwright/tests/4-proposal-visibility/proposalVisibility.loggedin.spec.ts b/tests/govtool-frontend/playwright/tests/4-proposal-visibility/proposalVisibility.loggedin.spec.ts new file mode 100644 index 000000000..cc5a182b5 --- /dev/null +++ b/tests/govtool-frontend/playwright/tests/4-proposal-visibility/proposalVisibility.loggedin.spec.ts @@ -0,0 +1,120 @@ +import { user01Wallet } from "@constants/staticWallets"; +import { test } from "@fixtures/walletExtension"; +import removeAllSpaces from "@helpers/removeAllSpaces"; +import GovernanceActionsPage from "@pages/governanceActionsPage"; +import { expect } from "@playwright/test"; + +const filterOptionNames = [ + "Protocol Parameter Change", + "New Committee", + "Hard Fork", + "No Confidence", + "Info Action", + "Treasury Withdrawal", + "Update to the Constitution", +]; + +enum SortOption { + SoonToExpire = "SoonestToExpire", + NewestFirst = "NewestCreated", + HighestYesVotes = "MostYesVotes", +} + +test.use({ storageState: ".auth/user01.json", wallet: user01Wallet }); + +test("4A.1: Should access Governance Actions page with connecting wallet @smoke @fast", async ({ + page, +}) => { + await page.goto("/"); + + await page.getByTestId("governance-actions-link").click(); + await expect(page.getByText(/Governance Actions/i)).toHaveCount(2); +}); + +test("4B.1: Should restrict voting for users who are not registered as DReps (with wallet connected) @fast", async ({ + page, +}) => { + const govActionsPage = new GovernanceActionsPage(page); + await govActionsPage.goto(); + + const govActionDetailsPage = await govActionsPage.viewFirstProposal(); + await expect(govActionDetailsPage.voteBtn).not.toBeVisible(); +}); + +test("4C.1: Should filter Governance Action Type on governance actions page @slow", async ({ + page, +}) => { + test.slow(); + + const govActionsPage = new GovernanceActionsPage(page); + await govActionsPage.goto(); + + await govActionsPage.filterBtn.click(); + + // Single filter + for (const option of filterOptionNames) { + await govActionsPage.filterProposalByNames([option]); + await govActionsPage.validateFilters([option]); + await govActionsPage.unFilterProposalByNames([option]); + } + + // Multiple filters + const multipleFilterOptionNames = [...filterOptionNames]; + while (multipleFilterOptionNames.length > 1) { + await govActionsPage.filterProposalByNames(multipleFilterOptionNames); + await govActionsPage.validateFilters(multipleFilterOptionNames); + await govActionsPage.unFilterProposalByNames(multipleFilterOptionNames); + multipleFilterOptionNames.pop(); + } +}); + +test("4C.2: Should sort Governance Action Type on governance actions page @slow", async ({ + page, +}) => { + test.slow(); + + const govActionsPage = new GovernanceActionsPage(page); + await govActionsPage.goto(); + + await govActionsPage.sortBtn.click(); + + govActionsPage.sortProposal(SortOption.SoonToExpire); + await govActionsPage.validateSort( + SortOption.SoonToExpire, + (p1, p2) => p1.expiryDate <= p2.expiryDate + ); + + govActionsPage.sortProposal(SortOption.NewestFirst); + await govActionsPage.validateSort( + SortOption.NewestFirst, + (p1, p2) => p1.createdDate >= p2.createdDate + ); + + govActionsPage.sortProposal(SortOption.HighestYesVotes); + await govActionsPage.validateSort( + SortOption.HighestYesVotes, + (p1, p2) => p1.yesVotes >= p2.yesVotes + ); +}); + +test("4D: Should filter and sort Governance Action Type on governance actions page @slow", async ({ + page, +}) => { + test.slow(); + + const govActionsPage = new GovernanceActionsPage(page); + await govActionsPage.goto(); + + await govActionsPage.sortBtn.click(); + await govActionsPage.sortProposal(SortOption.SoonToExpire); + + await govActionsPage.filterBtn.click(); + govActionsPage.filterProposalByNames([filterOptionNames[0]]); + + await govActionsPage.validateSort( + SortOption.SoonToExpire, + (p1, p2) => p1.expiryDate <= p2.expiryDate, + [removeAllSpaces(filterOptionNames[0])] + ); + await govActionsPage.validateFilters([filterOptionNames[0]]); +}); diff --git a/tests/govtool-frontend/playwright/tests/4-proposal-visibility/proposalVisibility.spec.ts b/tests/govtool-frontend/playwright/tests/4-proposal-visibility/proposalVisibility.spec.ts new file mode 100644 index 000000000..19b5e5364 --- /dev/null +++ b/tests/govtool-frontend/playwright/tests/4-proposal-visibility/proposalVisibility.spec.ts @@ -0,0 +1,21 @@ +import GovernanceActionsPage from "@pages/governanceActionsPage"; +import { expect, test } from "@playwright/test"; + +test("4A.2: Should access Governance Actions page without connecting wallet @smoke @fast", async ({ + page, +}) => { + await page.goto("/"); + await page.getByTestId("move-to-governance-actions-button").click(); + + await expect(page.getByText(/Governance actions/i)).toHaveCount(2); +}); + +test("4B.2: Should restrict voting for users who are not registered as DReps (without wallet connected) @flaky @fast", async ({ + page, +}) => { + const govActionsPage = new GovernanceActionsPage(page); + await govActionsPage.goto(); + + const govActionDetailsPage = await govActionsPage.viewFirstProposal(); + await expect(govActionDetailsPage.voteBtn).not.toBeVisible(); +}); diff --git a/tests/govtool-frontend/playwright/tests/5-proposal-functionality/proposalFunctionality.dRep.spec.ts b/tests/govtool-frontend/playwright/tests/5-proposal-functionality/proposalFunctionality.dRep.spec.ts new file mode 100644 index 000000000..2844c24b8 --- /dev/null +++ b/tests/govtool-frontend/playwright/tests/5-proposal-functionality/proposalFunctionality.dRep.spec.ts @@ -0,0 +1,182 @@ +import environments from "@constants/environments"; +import { dRep01Wallet } from "@constants/staticWallets"; +import { createTempDRepAuth } from "@datafactory/createAuth"; +import { test } from "@fixtures/walletExtension"; +import convertBufferToHex from "@helpers/convertBufferToHex"; +import { ShelleyWallet } from "@helpers/crypto"; +import { createNewPageWithWallet } from "@helpers/page"; +import { pollTransaction, waitForTxConfirmation } from "@helpers/transaction"; +import GovernanceActionDetailsPage from "@pages/governanceActionDetailsPage"; +import GovernanceActionsPage from "@pages/governanceActionsPage"; +import { expect } from "@playwright/test"; +import kuberService from "@services/kuberService"; + +test.describe("Proposal checks", () => { + test.use({ storageState: ".auth/dRep01.json", wallet: dRep01Wallet }); + + let govActionDetailsPage: GovernanceActionDetailsPage; + + test.beforeEach(async ({ page }) => { + const govActionsPage = new GovernanceActionsPage(page); + await govActionsPage.goto(); + + govActionDetailsPage = await govActionsPage.viewFirstProposal(); + }); + + test("5A. Should show relevant details about governance action as DRep @slow", async () => { + await expect(govActionDetailsPage.governanceActionType).toBeVisible(); + await expect(govActionDetailsPage.submittedDate).toBeVisible(); + await expect(govActionDetailsPage.expiryDate).toBeVisible(); + + await expect(govActionDetailsPage.externalModalBtn).toBeVisible(); + await expect(govActionDetailsPage.contextBtn).toBeVisible(); + + await expect(govActionDetailsPage.voteBtn).toBeVisible(); + await expect(govActionDetailsPage.yesVoteRadio).toBeVisible(); + await expect(govActionDetailsPage.noVoteRadio).toBeVisible(); + await expect(govActionDetailsPage.abstainRadio).toBeVisible(); + }); + + test("5B. Should view Vote button on governance action item on registered as DRep @slow", async () => { + await expect(govActionDetailsPage.voteBtn).toBeVisible(); + }); + + test("5C. Should show required field in proposal voting on registered as DRep @slow", async () => { + await expect(govActionDetailsPage.voteBtn).toBeVisible(); + await expect(govActionDetailsPage.yesVoteRadio).toBeVisible(); + await expect(govActionDetailsPage.noVoteRadio).toBeVisible(); + await expect(govActionDetailsPage.abstainRadio).toBeVisible(); + + await govActionDetailsPage.contextBtn.click(); + + await expect(govActionDetailsPage.contextInput).toBeVisible(); + await govActionDetailsPage.cancelModalBtn.click(); + + await govActionDetailsPage.yesVoteRadio.click(); + await expect(govActionDetailsPage.voteBtn).toBeEnabled(); + }); + + // Skipped: No url/hash input to validate + test.skip("5D. Should validate proposal voting @slow", async () => { + // const invalidURLs = ["testdotcom", "https://testdotcom", "https://test.c"]; + // invalidURLs.forEach(async (url) => { + // govActionDetailsPage.urlInput.fill(url); + // await expect(govActionDetailsPage.urlInputError).toBeVisible(); + // }); + // const validURLs = ["https://test.com"]; + // validURLs.forEach(async (url) => { + // govActionDetailsPage.urlInput.fill(url); + // await expect(govActionDetailsPage.urlInputError).not.toBeVisible(); + // }); + // const invalidHashes = [ + // randomBytes(20).toString("hex"), + // randomBytes(32).toString(), + // ]; + // invalidHashes.forEach(async (hash) => { + // govActionDetailsPage.hashInput.fill(hash); + // await expect(govActionDetailsPage.hashInputError).toBeVisible(); + // }); + // const validHash = randomBytes(32).toString("hex"); + // govActionDetailsPage.hashInput.fill(validHash); + // await expect(govActionDetailsPage.hashInputError).not.toBeVisible(); + }); + + test("5G. Should show warning to the users to visit the site at their own risk, when external url is opened", async () => { + await govActionDetailsPage.externalModalBtn.click(); + + await expect(govActionDetailsPage.externalLinkModal).toBeVisible(); + await expect( + govActionDetailsPage.currentPage.getByText("Be careful", { exact: false }) + ).toBeVisible(); + }); + + test("5H. Should open a new tab, when external URL is opened", async ({ + page, + }) => { + await govActionDetailsPage.externalModalBtn.click(); + await govActionDetailsPage.continueModalBtn.click(); + + const existingPages = page.context().pages(); + expect(existingPages).toHaveLength(1); + }); +}); + +test.describe("Perform voting", () => { + let govActionDetailsPage: GovernanceActionDetailsPage; + + test.beforeEach(async ({ page, browser }, testInfo) => { + test.setTimeout(testInfo.timeout + 2 * environments.txTimeOut); + + const wallet = await ShelleyWallet.generate(); + const registrationRes = await kuberService.dRepRegistration( + convertBufferToHex(wallet.stakeKey.private), + convertBufferToHex(wallet.stakeKey.pkh) + ); + await pollTransaction(registrationRes.txId, registrationRes.address); + + const res = await kuberService.transferADA( + [wallet.addressBech32(environments.networkId)], + 40 + ); + await pollTransaction(res.txId, registrationRes.address); + + const tempDRepAuth = await createTempDRepAuth(page, wallet); + + const dRepPage = await createNewPageWithWallet(browser, { + storageState: tempDRepAuth, + wallet, + enableStakeSigning: true, + }); + + const govActionsPage = new GovernanceActionsPage(dRepPage); + await govActionsPage.goto(); + + govActionDetailsPage = await govActionsPage.viewFirstProposal(); + }); + + test("5E. Should re-vote with new data on a already voted governance action", async ({}, testInfo) => { + test.setTimeout(testInfo.timeout + 2 * environments.txTimeOut); + + govActionDetailsPage.vote(); + await waitForTxConfirmation(govActionDetailsPage.currentPage); + + const governanceActionsPage = new GovernanceActionsPage( + govActionDetailsPage.currentPage + ); + await governanceActionsPage.goto(); + await governanceActionsPage.votedTab.click(); + await expect( + govActionDetailsPage.currentPage.getByTestId("my-vote").getByText("Yes") + ).toBeVisible(); + + govActionDetailsPage = await governanceActionsPage.viewFirstVotedProposal(); + govActionDetailsPage.reVote(); + await waitForTxConfirmation(govActionDetailsPage.currentPage); + + await governanceActionsPage.votedTab.click(); + await expect( + govActionDetailsPage.currentPage.getByTestId("my-vote").getByText("No") + ).toBeVisible(); + }); + + test("5F. Should show notification of casted vote after vote", async ({}) => { + await govActionDetailsPage.vote(); + await expect(govActionDetailsPage.voteSuccessModal).toBeVisible(); + }); + + test("5I. Should view the vote details,when viewing governance action already voted by the DRep", async ({}, testInfo) => { + test.setTimeout(testInfo.timeout + environments.txTimeOut); + + govActionDetailsPage.vote(); + await waitForTxConfirmation(govActionDetailsPage.currentPage); + + const governanceActionsPage = new GovernanceActionsPage( + govActionDetailsPage.currentPage + ); + await governanceActionsPage.goto(); + await governanceActionsPage.votedTab.click(); + await expect( + govActionDetailsPage.currentPage.getByTestId("my-vote").getByText("Yes") + ).toBeVisible(); + }); +}); diff --git a/tests/govtool-frontend/playwright/tests/6-miscellaneous/miscellaneous.loggedin.spec.ts b/tests/govtool-frontend/playwright/tests/6-miscellaneous/miscellaneous.loggedin.spec.ts new file mode 100644 index 000000000..39f9e7a8e --- /dev/null +++ b/tests/govtool-frontend/playwright/tests/6-miscellaneous/miscellaneous.loggedin.spec.ts @@ -0,0 +1,34 @@ +import { test } from "@fixtures/walletExtension"; +import { user01Wallet } from "@constants/staticWallets"; +import { expect } from "@playwright/test"; +import DRepRegistrationPage from "@pages/dRepRegistrationPage"; +import DelegationPage from "@pages/delegationPage"; + +test.use({ storageState: ".auth/user01.json", wallet: user01Wallet }); + +// Skipped: No dRepId to validate +test.skip("6B. Provides error for invalid format @fast @smoke", async ({ page }) => { + // invalid dRep delegation + const delegationPage = new DelegationPage(page); + await delegationPage.goto(); + await delegationPage.delegateToDRep("Random values"); + await expect(delegationPage.delegationErrorModal).toBeVisible(); + + // invalid dRep registration + const dRepRegistrationPage = new DRepRegistrationPage(page); + await dRepRegistrationPage.goto(); + + await dRepRegistrationPage.urlInput.fill("abc"); + await expect(dRepRegistrationPage.urlInputError).toBeVisible(); + + await dRepRegistrationPage.hashInput.fill("abc"); + await expect(dRepRegistrationPage.hashInputError).toBeVisible(); +}); + +test("6D: Proper label and recognition of the testnet network @fast @smoke", async ({ + page, +}) => { + await page.goto("/"); + + await expect(page.getByText("testnet")).toBeVisible(); +}); diff --git a/tests/govtool-frontend/playwright/tests/6-miscellaneous/miscellaneous.spec.ts b/tests/govtool-frontend/playwright/tests/6-miscellaneous/miscellaneous.spec.ts new file mode 100644 index 000000000..b1f72c811 --- /dev/null +++ b/tests/govtool-frontend/playwright/tests/6-miscellaneous/miscellaneous.spec.ts @@ -0,0 +1,31 @@ +import { expect, test } from "@playwright/test"; +import environments from "lib/constants/environments"; + +test("6C. Navigation within the dApp @smoke @fast", async ({ + page, + context, +}) => { + await page.goto("/"); + + await page.getByTestId("governance-actions-link").click(); + await expect(page).toHaveURL(/\/governance_actions/); + + const [guidesPage] = await Promise.all([ + context.waitForEvent("page"), + page.getByTestId("guides-link").click(), + ]); + + await expect(guidesPage).toHaveURL( + `${environments.docsUrl}/about/what-is-sanchonet-govtool` + ); + + const [faqsPage] = await Promise.all([ + context.waitForEvent("page"), + page.getByTestId("faqs-link").click(), + ]); + + await expect(faqsPage).toHaveURL(`${environments.docsUrl}/faqs`); + + await page.getByTestId("dashboard-link").click(); + expect(page.url()).toEqual(`${environments.frontendUrl}/`); +}); diff --git a/tests/govtool-frontend/playwright/tests/adaholder.teardown.ts b/tests/govtool-frontend/playwright/tests/adaholder.teardown.ts new file mode 100644 index 000000000..49c21b8cc --- /dev/null +++ b/tests/govtool-frontend/playwright/tests/adaholder.teardown.ts @@ -0,0 +1,15 @@ +import { adaHolderWallets } from "@constants/staticWallets"; +import { pollTransaction } from "@helpers/transaction"; +import { test as cleanup } from "@playwright/test"; +import kuberService from "@services/kuberService"; + +cleanup(`Abstain delegation`, async () => { + const stakePrivKeys = adaHolderWallets.map((wallet) => wallet.stake.private); + const stakePkhs = adaHolderWallets.map((wallet) => wallet.stake.pkh); + + const { txId, address } = await kuberService.abstainDelegations( + stakePrivKeys, + stakePkhs + ); + await pollTransaction(txId, address); +}); diff --git a/tests/govtool-frontend/playwright/tests/auth.setup.ts b/tests/govtool-frontend/playwright/tests/auth.setup.ts new file mode 100644 index 000000000..d2206b142 --- /dev/null +++ b/tests/govtool-frontend/playwright/tests/auth.setup.ts @@ -0,0 +1,44 @@ +// Saves storage state to a file in the .auth directory + +import { + adaHolder01Wallet, + dRep01Wallet, + user01Wallet, +} from "@constants/staticWallets"; +import { importWallet } from "@fixtures/importWallet"; +import { test as setup } from "@fixtures/walletExtension"; +import LoginPage from "@pages/loginPage"; + +const dRep01AuthFile = ".auth/dRep01.json"; +const adaHolder01AuthFile = ".auth/adaHolder01.json"; +const user01AuthFile = ".auth/user01.json"; + +setup("Create DRep 01 auth", async ({ page, context }) => { + await importWallet(page, dRep01Wallet); + + const loginPage = new LoginPage(page); + await loginPage.login(); + await loginPage.isLoggedIn(); + + await context.storageState({ path: dRep01AuthFile }); +}); + +setup("Create User 01 auth", async ({ page, context }) => { + await importWallet(page, user01Wallet); + + const loginPage = new LoginPage(page); + await loginPage.login(); + await loginPage.isLoggedIn(); + + await context.storageState({ path: user01AuthFile }); +}); + +setup("Create AdaHolder 01 auth", async ({ page, context }) => { + await importWallet(page, adaHolder01Wallet); + + const loginPage = new LoginPage(page); + await loginPage.login(); + await loginPage.isLoggedIn(); + + await context.storageState({ path: adaHolder01AuthFile }); +}); diff --git a/tests/govtool-frontend/playwright/tests/dRep.setup.ts b/tests/govtool-frontend/playwright/tests/dRep.setup.ts new file mode 100644 index 000000000..3e844251a --- /dev/null +++ b/tests/govtool-frontend/playwright/tests/dRep.setup.ts @@ -0,0 +1,42 @@ +import environments from "@constants/environments"; +import { dRepWallets } from "@constants/staticWallets"; +import { pollTransaction } from "@helpers/transaction"; +import { expect, test as setup } from "@playwright/test"; +import kuberService from "@services/kuberService"; +import { Logger } from "../../cypress/lib/logger/logger"; +import fetch = require("node-fetch"); + +const dRepInfo = require("../lib/_mock/dRepInfo.json"); + +setup.describe.configure({ timeout: environments.txTimeOut }); + +dRepWallets.forEach((wallet) => { + setup(`Register DRep of wallet: ${wallet.address}`, async () => { + try { + const res = await kuberService.dRepRegistration( + wallet.stake.private, + wallet.stake.pkh + ); + + await pollTransaction(res.txId, res.address); + } catch (err) { + if (err.status === 400) { + expect(true, "DRep already registered").toBeTruthy(); + } else { + throw err; + } + } + }); +}); + +setup("Setup dRep metadata", async () => { + try { + const res = await fetch(`${environments.metadataBucketUrl}/Test_dRep`, { + method: "PUT", + body: JSON.stringify(dRepInfo), + }); + Logger.success("Uploaded dRep metadata to bucket"); + } catch (e) { + Logger.fail(`Failed to upload dRep metadata: ${e}`); + } +}); diff --git a/tests/govtool-frontend/playwright/tests/wallet.bootstrap.ts b/tests/govtool-frontend/playwright/tests/wallet.bootstrap.ts new file mode 100644 index 000000000..55ded87ff --- /dev/null +++ b/tests/govtool-frontend/playwright/tests/wallet.bootstrap.ts @@ -0,0 +1,81 @@ +import { + adaHolderWallets, + dRepWallets, + faucetWallet, +} from "@constants/staticWallets"; +import { ShelleyWallet } from "@helpers/crypto"; +import extractDRepsFromStakePubKey from "@helpers/extractDRepsFromStakePubkey"; +import generateShellyWallets from "@helpers/generateShellyWallets"; +import setupWallets from "@helpers/setupWallets"; +import { pollTransaction } from "@helpers/transaction"; +import { expect, test as setup } from "@playwright/test"; +import { loadAmountFromFaucet } from "@services/faucetService"; +import kuberService from "@services/kuberService"; +import { writeFile } from "fs"; +import environments from "lib/constants/environments"; + +setup.describe.configure({ mode: "serial", timeout: environments.txTimeOut }); + +setup("Setup mock wallets", async () => { + setup.skip(!environments.oneTimeWalletSetup); + + const wallets = await generateShellyWallets(6); + await setupWallets(wallets); + saveWallets(wallets); +}); + +setup("Fund faucet wallet", async () => { + const balance = await kuberService.getBalance(faucetWallet.address); + if (balance > 2000) return; + + const res = await loadAmountFromFaucet(faucetWallet.address); + await pollTransaction(res.txid); +}); + +setup("Fund static wallets", async () => { + const addresses = [...adaHolderWallets, ...dRepWallets].map((e) => e.address); + const res = await kuberService.transferADA(addresses); + await pollTransaction(res.txId, res.address); +}); + +for (const wallet of [...adaHolderWallets, ...dRepWallets]) { + setup(`Register stake of static wallet: ${wallet.address}`, async () => { + try { + const { txId, address } = await kuberService.registerStake( + wallet.stake.private, + wallet.stake.pkh, + wallet.payment.private, + wallet.address + ); + await pollTransaction(txId, address); + } catch (err) { + if (err.status === 400) { + expect(true, "Stake already registered").toBeTruthy(); + } else { + throw Error(err); + } + } + }); +} + +function saveWallets(wallets: ShelleyWallet[]) { + const jsonWallets = []; + for (let i = 0; i < wallets.length; i++) { + const stakePublicKey = Buffer.from(wallets[i].stakeKey.public).toString( + "hex" + ); + const { dRepIdBech32 } = extractDRepsFromStakePubKey(stakePublicKey); + + jsonWallets.push({ + ...wallets[i].json(), + address: wallets[i].addressBech32(environments.networkId), + dRepId: dRepIdBech32, + }); + } + const jsonString = JSON.stringify(jsonWallets, null, 2); + writeFile("lib/_mock/wallets.json", jsonString, "utf-8", (err) => { + if (err) { + throw Error("Failed to write wallets into file"); + } + }); +} diff --git a/tests/govtool-frontend/playwright/tsconfig.json b/tests/govtool-frontend/playwright/tsconfig.json new file mode 100644 index 000000000..0209bfb32 --- /dev/null +++ b/tests/govtool-frontend/playwright/tsconfig.json @@ -0,0 +1,17 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "baseUrl": "./", // This must be specified if "paths" is. + "paths": { + "@mock/*": ["lib/_mock/*"], + "@fixtures/*": ["lib/fixtures/*"], + "@helpers/*": ["lib/helpers/*"], + "@pages/*": ["lib/pages/*"], + "@services/*": ["lib/services/*"], + "@types": ["lib/types.ts"], + "@constants/*": ["lib/constants/*"], + "@datafactory/*": ["lib/datafactory/*"] + } + } +} From b2c848d44387eabbdce2f8ebb44585143e221eb0 Mon Sep 17 00:00:00 2001 From: Nabin Kawan Date: Mon, 6 May 2024 13:28:16 +0545 Subject: [PATCH 054/125] 6A: Add/Refactor tests for mobile accessibility --- .../playwright/lib/constants/environments.ts | 4 +- .../playwright/lib/datafactory/createAuth.ts | 8 +-- .../playwright/lib/helpers/mobile.ts | 16 ++++++ .../playwright/lib/pages/loginPage.ts | 16 +++++- .../playwright/playwright.config.ts | 52 +++++++------------ .../2-delegation/delegation.loggedin.spec.ts | 2 +- .../proposalVisibility.loggedin.spec.ts | 4 ++ .../6-miscellaneous/miscellaneous.spec.ts | 13 +++++ .../playwright/tests/example.spec.ts | 22 -------- 9 files changed, 73 insertions(+), 64 deletions(-) create mode 100644 tests/govtool-frontend/playwright/lib/helpers/mobile.ts delete mode 100644 tests/govtool-frontend/playwright/tests/example.spec.ts diff --git a/tests/govtool-frontend/playwright/lib/constants/environments.ts b/tests/govtool-frontend/playwright/lib/constants/environments.ts index f4474c818..eea7478db 100644 --- a/tests/govtool-frontend/playwright/lib/constants/environments.ts +++ b/tests/govtool-frontend/playwright/lib/constants/environments.ts @@ -1,6 +1,6 @@ const environments = { - frontendUrl: process.env.HOST_URL || "http://localhost:5173", - apiUrl: `${process.env.HOST_URL}/api` || "http://localhost:9999", + frontendUrl: process.env.HOST_URL || "http://localhost:8080", + apiUrl: `${process.env.HOST_URL}/api` || "http://localhost:8080/api", docsUrl: process.env.DOCS_URL || "https://docs.sanchogov.tools", networkId: parseInt(process.env.NETWORK_ID) || 0, oneTimeWalletSetup: process.env.ONE_TIME_WALLET_SETUP === "true" || false, diff --git a/tests/govtool-frontend/playwright/lib/datafactory/createAuth.ts b/tests/govtool-frontend/playwright/lib/datafactory/createAuth.ts index d297f0ddf..2525ed5dc 100644 --- a/tests/govtool-frontend/playwright/lib/datafactory/createAuth.ts +++ b/tests/govtool-frontend/playwright/lib/datafactory/createAuth.ts @@ -3,7 +3,7 @@ import { importWallet } from "@fixtures/importWallet"; import { ShelleyWallet } from "@helpers/crypto"; import LoginPage from "@pages/loginPage"; -import { Page, expect } from "@playwright/test"; +import { Page } from "@playwright/test"; const tempDRepAuth = ".auth/tempDRepAuth.json"; const tempUserAuth = ".auth/tempUserAuth.json"; @@ -14,7 +14,7 @@ export async function createTempDRepAuth(page: Page, wallet: ShelleyWallet) { const loginPage = new LoginPage(page); await loginPage.login(); - await expect(page.getByTestId("disconnect-button")).toBeVisible(); + await loginPage.isLoggedIn(); await page.context().storageState({ path: tempDRepAuth }); return tempDRepAuth; @@ -28,7 +28,7 @@ export async function createTempAdaHolderAuth( const loginPage = new LoginPage(page); await loginPage.login(); - await expect(page.getByTestId("disconnect-button")).toBeVisible(); + await loginPage.isLoggedIn(); await page.context().storageState({ path: tempAdaHolderAuth }); return tempAdaHolderAuth; @@ -37,7 +37,7 @@ export async function createTempAdaHolderAuth( export async function createTempUserAuth(page: Page) { const loginPage = new LoginPage(page); await loginPage.login(); - await expect(page.getByTestId("disconnect-button")).toBeVisible(); + await loginPage.isLoggedIn(); await page.context().storageState({ path: tempUserAuth }); return tempUserAuth; diff --git a/tests/govtool-frontend/playwright/lib/helpers/mobile.ts b/tests/govtool-frontend/playwright/lib/helpers/mobile.ts new file mode 100644 index 000000000..b0c0329ca --- /dev/null +++ b/tests/govtool-frontend/playwright/lib/helpers/mobile.ts @@ -0,0 +1,16 @@ +import { Page } from "@playwright/test"; + +export function isMobile(page: Page) { + const { width } = page.viewportSize(); + if (width <= 414) return true; + + return false; +} + +export async function openDrawer(page: Page) { + await page.getByRole("img", { name: "drawer-icon" }).click(); //BUG testId +} + +export async function openDrawerLoggedIn(page: Page) { + await page.getByTestId("open-drawer-button").click(); +} diff --git a/tests/govtool-frontend/playwright/lib/pages/loginPage.ts b/tests/govtool-frontend/playwright/lib/pages/loginPage.ts index 2baa2f0ff..964b14ff8 100644 --- a/tests/govtool-frontend/playwright/lib/pages/loginPage.ts +++ b/tests/govtool-frontend/playwright/lib/pages/loginPage.ts @@ -2,6 +2,7 @@ import { CIP30Instance, Cip95Instance, } from "@cardanoapi/cardano-test-wallet/types"; +import { isMobile, openDrawer, openDrawerLoggedIn } from "@helpers/mobile"; import { Page, expect } from "@playwright/test"; export default class LoginPage { @@ -22,7 +23,14 @@ export default class LoginPage { async login() { await this.goto(); - await this.connectWalletBtn.click(); + if (isMobile(this.page)) { + await openDrawer(this.page); + await this.page + .getByRole("button", { name: "Connect your wallet" }) // BUG testId should be same as connect-wallet-button + .click(); + } else { + await this.connectWalletBtn.click(); + } await this.demosWalletBtn.click({ force: true }); await this.acceptSanchoNetInfoBtn.click({ force: true }); @@ -53,10 +61,16 @@ export default class LoginPage { } async logout() { + if (isMobile(this.page)) { + await openDrawerLoggedIn(this.page); + } await this.disconnectWalletBtn.click(); } async isLoggedIn() { + if (isMobile(this.page)) { + await openDrawerLoggedIn(this.page); + } await expect(this.disconnectWalletBtn).toBeVisible(); } } diff --git a/tests/govtool-frontend/playwright/playwright.config.ts b/tests/govtool-frontend/playwright/playwright.config.ts index bcd673974..caf1350e7 100644 --- a/tests/govtool-frontend/playwright/playwright.config.ts +++ b/tests/govtool-frontend/playwright/playwright.config.ts @@ -27,7 +27,7 @@ export default defineConfig({ /*use Allure Playwright's testPlanFilter() to determine the grep parameter*/ grep: testPlanFilter(), /* Reporter to use. See https://playwright.dev/docs/test-reporters */ - reporter: process.env.CI ? [["line"], ["allure-playwright"]] : [["line"]], + reporter: process.env.CI ? [["dot"], ["allure-playwright"]] : [["dot"]], /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */ use: { /* Base URL to use in actions like `await page.goto('/')`. */ @@ -63,11 +63,17 @@ export default defineConfig({ dependencies: process.env.CI ? ["auth setup", "wallet bootstrap"] : [], }, { - name: "logged in", + name: "loggedin (desktop)", use: { ...devices["Desktop Chrome"] }, testMatch: "**/*.loggedin.spec.ts", dependencies: process.env.CI ? ["auth setup"] : [], }, + { + name: "loggedin (mobile)", + use: { ...devices["Pixel 5"] }, + testMatch: "**/*.loggedin.spec.ts", + dependencies: process.env.CI ? ["auth setup"] : [], + }, { name: "dRep", use: { ...devices["Desktop Chrome"] }, @@ -75,7 +81,7 @@ export default defineConfig({ dependencies: process.env.CI ? ["auth setup", "dRep setup"] : [], }, { - name: "independent", + name: "independent (desktop)", use: { ...devices["Desktop Chrome"] }, testIgnore: [ "**/*.tx.spec.ts", @@ -83,36 +89,14 @@ export default defineConfig({ "**/*.dRep.spec.ts", ], }, - // { - // name: "cleanup adaHolder", - // testMatch: "**/*.teardown.ts", - // }, - - /* Test against mobile viewports. */ - // { - // name: 'Mobile Chrome', - // use: { ...devices['Pixel 5'] }, - // }, - // { - // name: 'Mobile Safari', - // use: { ...devices['iPhone 12'] }, - // }, - - /* Test against branded browsers. */ - // { - // name: 'Microsoft Edge', - // use: { ...devices['Desktop Edge'], channel: 'msedge' }, - // }, - // { - // name: 'Google Chrome', - // use: { ...devices['Desktop Chrome'], channel: 'chrome' }, - // }, + { + name: "independent (mobile)", + use: { ...devices["Pixel 5"] }, + testIgnore: [ + "**/*.tx.spec.ts", + "**/*.loggedin.spec.ts", + "**/*.dRep.spec.ts", + ], + }, ], - - /* Run your local dev server before starting the tests */ - // webServer: { - // command: "cd govtool/frontend && npm run start", - // // url: "http://127.0.0.1:3000", - // reuseExistingServer: !process.env.CI, - // }, }); diff --git a/tests/govtool-frontend/playwright/tests/2-delegation/delegation.loggedin.spec.ts b/tests/govtool-frontend/playwright/tests/2-delegation/delegation.loggedin.spec.ts index 8d3f28652..969607c1f 100644 --- a/tests/govtool-frontend/playwright/tests/2-delegation/delegation.loggedin.spec.ts +++ b/tests/govtool-frontend/playwright/tests/2-delegation/delegation.loggedin.spec.ts @@ -10,7 +10,7 @@ test("2B. Should access delegation to dRep page @smoke @fast", async ({ }) => { await page.goto("/"); - await page.getByTestId("delegate-button").click(); // BUG: testId -> view-dRep-directory + await page.getByTestId("delegate-button").click(); // BUG incorrect test ID await expect( page.getByRole("navigation").getByText("DRep Directory") ).toBeVisible(); diff --git a/tests/govtool-frontend/playwright/tests/4-proposal-visibility/proposalVisibility.loggedin.spec.ts b/tests/govtool-frontend/playwright/tests/4-proposal-visibility/proposalVisibility.loggedin.spec.ts index cc5a182b5..d55c62514 100644 --- a/tests/govtool-frontend/playwright/tests/4-proposal-visibility/proposalVisibility.loggedin.spec.ts +++ b/tests/govtool-frontend/playwright/tests/4-proposal-visibility/proposalVisibility.loggedin.spec.ts @@ -1,5 +1,6 @@ import { user01Wallet } from "@constants/staticWallets"; import { test } from "@fixtures/walletExtension"; +import { isMobile, openDrawerLoggedIn } from "@helpers/mobile"; import removeAllSpaces from "@helpers/removeAllSpaces"; import GovernanceActionsPage from "@pages/governanceActionsPage"; import { expect } from "@playwright/test"; @@ -26,6 +27,9 @@ test("4A.1: Should access Governance Actions page with connecting wallet @smoke page, }) => { await page.goto("/"); + if (isMobile(page)) { + await openDrawerLoggedIn(page); + } await page.getByTestId("governance-actions-link").click(); await expect(page.getByText(/Governance Actions/i)).toHaveCount(2); diff --git a/tests/govtool-frontend/playwright/tests/6-miscellaneous/miscellaneous.spec.ts b/tests/govtool-frontend/playwright/tests/6-miscellaneous/miscellaneous.spec.ts index b1f72c811..d26feb683 100644 --- a/tests/govtool-frontend/playwright/tests/6-miscellaneous/miscellaneous.spec.ts +++ b/tests/govtool-frontend/playwright/tests/6-miscellaneous/miscellaneous.spec.ts @@ -1,3 +1,4 @@ +import { isMobile, openDrawer } from "@helpers/mobile"; import { expect, test } from "@playwright/test"; import environments from "lib/constants/environments"; @@ -7,9 +8,15 @@ test("6C. Navigation within the dApp @smoke @fast", async ({ }) => { await page.goto("/"); + if (isMobile(page)) { + await openDrawer(page); + } await page.getByTestId("governance-actions-link").click(); await expect(page).toHaveURL(/\/governance_actions/); + if (isMobile(page)) { + await openDrawer(page); + } const [guidesPage] = await Promise.all([ context.waitForEvent("page"), page.getByTestId("guides-link").click(), @@ -19,6 +26,9 @@ test("6C. Navigation within the dApp @smoke @fast", async ({ `${environments.docsUrl}/about/what-is-sanchonet-govtool` ); + if (isMobile(page)) { + await openDrawer(page); + } const [faqsPage] = await Promise.all([ context.waitForEvent("page"), page.getByTestId("faqs-link").click(), @@ -26,6 +36,9 @@ test("6C. Navigation within the dApp @smoke @fast", async ({ await expect(faqsPage).toHaveURL(`${environments.docsUrl}/faqs`); + if (isMobile(page)) { + await openDrawer(page); + } await page.getByTestId("dashboard-link").click(); expect(page.url()).toEqual(`${environments.frontendUrl}/`); }); diff --git a/tests/govtool-frontend/playwright/tests/example.spec.ts b/tests/govtool-frontend/playwright/tests/example.spec.ts deleted file mode 100644 index 190e698e2..000000000 --- a/tests/govtool-frontend/playwright/tests/example.spec.ts +++ /dev/null @@ -1,22 +0,0 @@ -import test, { expect } from "@playwright/test"; - -test.describe("Example test specs", () => { - test("has title", async ({ page }) => { - await page.goto("https://playwright.dev/"); - - // Expect a title "to contain" a substring. - await expect(page).toHaveTitle(/Playwright/); - }); - - test("get started link", async ({ page }) => { - await page.goto("https://playwright.dev/"); - - // Click the get started link. - await page.getByRole("link", { name: "Get started" }).click(); - - // Expects page to have a heading with the name of Installation. - await expect( - page.getByRole("heading", { name: "Installation" }) - ).toBeVisible(); - }); -}); From bc5cb0fafea034aad0fea3daddb30e022bb8ac32 Mon Sep 17 00:00:00 2001 From: Nabin Kawan Date: Wed, 8 May 2024 14:16:30 +0545 Subject: [PATCH 055/125] fix: Transaction locking --- .../playwright/lib/constants/environments.ts | 8 +- .../playwright/lib/constants/staticWallets.ts | 2 +- .../playwright/lib/helpers/transaction.ts | 33 +++++-- .../playwright/lib/lockInterceptor.ts | 98 ++++++++++++++----- .../playwright/lib/services/kuberService.ts | 28 +++--- .../playwright/package-lock.json | 14 +-- .../govtool-frontend/playwright/package.json | 2 +- .../playwright/playwright.config.ts | 34 +++++-- ....spec.ts => delegation.delegation.spec.ts} | 30 +++++- .../tests/2-delegation/delegation.tx.spec.ts | 21 ---- .../dRepRegistration.dRep.spec.ts | 19 +++- .../dRepRegistration.tx.spec.ts | 16 --- .../proposalFunctionality.dRep.spec.ts | 4 +- .../miscellaneous.loggedin.spec.ts | 16 +-- .../playwright/tests/dRep.setup.ts | 7 +- ...der.teardown.ts => delegation.teardown.ts} | 7 +- .../playwright/tests/faucet.setup.ts | 16 +++ .../playwright/tests/wallet.bootstrap.ts | 21 +--- 18 files changed, 241 insertions(+), 135 deletions(-) rename tests/govtool-frontend/playwright/tests/2-delegation/{delegation.dRep.spec.ts => delegation.delegation.spec.ts} (72%) delete mode 100644 tests/govtool-frontend/playwright/tests/2-delegation/delegation.tx.spec.ts delete mode 100644 tests/govtool-frontend/playwright/tests/3-drep-registration/dRepRegistration.tx.spec.ts rename tests/govtool-frontend/playwright/tests/{adaholder.teardown.ts => delegation.teardown.ts} (66%) create mode 100644 tests/govtool-frontend/playwright/tests/faucet.setup.ts diff --git a/tests/govtool-frontend/playwright/lib/constants/environments.ts b/tests/govtool-frontend/playwright/lib/constants/environments.ts index eea7478db..ccdfd8c14 100644 --- a/tests/govtool-frontend/playwright/lib/constants/environments.ts +++ b/tests/govtool-frontend/playwright/lib/constants/environments.ts @@ -15,9 +15,13 @@ const environments = { process.env.KUBER_API_URL || "https://sanchonet.kuber.cardanoapi.io", apiKey: process.env.KUBER_API_KEY || "", }, - txTimeOut: parseInt(process.env.TX_TIMEOUT) || 120000, + txTimeOut: parseInt(process.env.TX_TIMEOUT) || 240000, metadataBucketUrl: - process.env.METADATA_BUCKET_URL || "https://metadata.cardanoapi.io/data", + `${process.env.CARDANOAPI_METADATA_URL}/data` || + "https://metadata.cardanoapi.io/data", + lockInterceptorUrl: + `${process.env.CARDANOAPI_METADATA_URL}/data` || + "https://metadata.cardanoapi.io/lock", }; export default environments; diff --git a/tests/govtool-frontend/playwright/lib/constants/staticWallets.ts b/tests/govtool-frontend/playwright/lib/constants/staticWallets.ts index 037ccd3ce..21a0289e6 100644 --- a/tests/govtool-frontend/playwright/lib/constants/staticWallets.ts +++ b/tests/govtool-frontend/playwright/lib/constants/staticWallets.ts @@ -18,8 +18,8 @@ export const faucetWallet: StaticWallet = { export const dRep01Wallet: StaticWallet = { payment: { - private: "2f1053f22707b9881ea6112024027a660bd5508e22081cf5e4e95cc663802dd9", public: "891ed5096ee248bc7f31a3094ea90f34485483eb1050c7ee368e64d04b90a009", + private: "2f1053f22707b9881ea6112024027a660bd5508e22081cf5e4e95cc663802dd9", pkh: "5775ad2fb14ca1b45381a40e40f0c06081edaf2261e02bbcebcf8dc3", }, stake: { diff --git a/tests/govtool-frontend/playwright/lib/helpers/transaction.ts b/tests/govtool-frontend/playwright/lib/helpers/transaction.ts index 63107dd9c..d85dc2efa 100644 --- a/tests/govtool-frontend/playwright/lib/helpers/transaction.ts +++ b/tests/govtool-frontend/playwright/lib/helpers/transaction.ts @@ -1,14 +1,17 @@ import environments from "@constants/environments"; import { Page, expect } from "@playwright/test"; import kuberService from "@services/kuberService"; -import { LockInterceptor } from "lib/lockInterceptor"; +import { LockInterceptor, LockInterceptorInfo } from "lib/lockInterceptor"; import { Logger } from "../../../cypress/lib/logger/logger"; /** * Polls the transaction status until it's resolved or times out. * address is used to release lock of that address */ -export async function pollTransaction(txHash: string, address?: string) { +export async function pollTransaction( + txHash: string, + lockInfo?: LockInterceptorInfo +) { try { Logger.info(`Waiting for tx completion: ${txHash}`); await expect @@ -18,17 +21,33 @@ export async function pollTransaction(txHash: string, address?: string) { const data = await response.json(); return data.length; }, - { message: "Transaction failed", timeout: environments.txTimeOut } + { + timeout: environments.txTimeOut, + } ) .toBeGreaterThan(0); Logger.success("Tx completed"); + + if (!lockInfo) return; + + await LockInterceptor.releaseLockForAddress( + lockInfo.address, + lockInfo.lockId, + `Task completed for:${lockInfo.lockId}` + ); } catch (err) { - throw err; - } finally { - if (!address) return; + if (lockInfo) { + const errorMessage = { lockInfo, error: JSON.stringify(err) }; - await LockInterceptor.releaseLockForAddress(address); + await LockInterceptor.releaseLockForAddress( + lockInfo.address, + lockInfo.lockId, + `Task failure: \n${JSON.stringify(errorMessage)}` + ); + } + + throw err; } } diff --git a/tests/govtool-frontend/playwright/lib/lockInterceptor.ts b/tests/govtool-frontend/playwright/lib/lockInterceptor.ts index aa740caa3..a3b13cda7 100644 --- a/tests/govtool-frontend/playwright/lib/lockInterceptor.ts +++ b/tests/govtool-frontend/playwright/lib/lockInterceptor.ts @@ -5,16 +5,29 @@ import { Logger } from "../../cypress/lib/logger/logger"; import path = require("path"); +export interface LockInterceptorInfo { + lockId: string; + address: string; +} + +abstract class BaseLock { + abstract acquireLock(key: string, id?: string): Promise; + + abstract releaseLock(key: string, id?: string): Promise; + + abstract checkLock(key: string): Promise; +} + export class LockInterceptor { private static async acquireLock( address: string, - message?: string + lockId: string ): Promise { const lockFilePath = path.resolve(__dirname, `../.lock-pool/${address}`); try { await log( - `${address} -> acquiring lock` + message && `\nMessage: ${message}` + `Initiator: ${address} \n---------------------> acquiring lock for:${lockId}` ); await new Promise((resolve, reject) => { lockfile.lock(lockFilePath, (err) => { @@ -25,21 +38,23 @@ export class LockInterceptor { } }); }); - await log(`${address} -> acquired lock`); + await log( + `Initiator: ${address} \n---------------------> acquired lock for:${lockId}` + ); } catch (err) { - Logger.fail("Failed to write lock logs"); + throw err; } } private static async releaseLock( address: string, - message?: string + lockId: string ): Promise { const lockFilePath = path.resolve(__dirname, `../.lock-pool/${address}`); try { await log( - `${address} -> releasing lock` + message && `\nMessage: ${message}` + `Initiator: ${address} \n---------------------> releasing lock for:${lockId}` ); await new Promise((resolve, reject) => { lockfile.unlock(lockFilePath, async (err) => { @@ -50,21 +65,23 @@ export class LockInterceptor { } }); }); - await log(`${address} -> released lock\n`); + await log( + `Initiator: ${address} \n---------------------> released lock for:${lockId}\n` + ); } catch (err) { - Logger.fail("Failed to write lock logs"); + throw err; } } private static async waitForReleaseLock( address: string, - message?: string + lockId: string ): Promise { - const pollInterval = 200; + const pollInterval = 4000; // 4 secs try { await log( - `${address} -> waiting lock` + message && `\nMessage: ${message}` + `Initiator: ${address} \n ---------------------> waiting lock for:${lockId}` ); return new Promise((resolve, reject) => { const pollFn = () => { @@ -83,32 +100,57 @@ export class LockInterceptor { pollFn(); }); } catch (err) { - Logger.fail("Failed to write lock logs"); + throw err; } } static async intercept( address: string, callbackFn: () => Promise, - message?: string + lockId: string, + provider: "local" | "server" = "local" ): Promise { - const isAddressLocked = checkAddressLock(address); - if (isAddressLocked) { - await LockInterceptor.waitForReleaseLock(address, message); - } + while (true) { + const isAddressLocked = checkAddressLock(address); + if (isAddressLocked) { + await LockInterceptor.waitForReleaseLock(address, lockId); + } - await LockInterceptor.acquireLock(address, message); + try { + await LockInterceptor.acquireLock(address, lockId); + break; + } catch (err) { + if (err.code === "EEXIST") { + await new Promise((resolve) => setTimeout(resolve, 1000)); // timeout for retry + continue; + } else { + throw err; + } + } + } try { const res = await callbackFn(); - return { ...res, address }; + return { ...res, lockInfo: { lockId, address } }; } catch (err) { - await LockInterceptor.releaseLock(address, "Tx failure"); + const errorMessage = { lock_id: lockId, error: JSON.stringify(err) }; + await log(`Task failure: \n${JSON.stringify(errorMessage)}`); + await LockInterceptor.releaseLock(address, lockId); throw err; } } - static async releaseLockForAddress(address: string) { - await this.releaseLock(address); + static async releaseLockForAddress( + address: string, + lockId: string, + message?: string + ) { + try { + message && (await log(message)); + + await this.releaseLock(address, lockId); + } catch { + Logger.fail("Failed to write lock logs"); + } } } @@ -118,8 +160,18 @@ function checkAddressLock(address: string): boolean { } function log(message: string): Promise { + const options: Intl.DateTimeFormatOptions = { + year: "numeric", + month: "2-digit", + day: "2-digit", + hour: "2-digit", + minute: "2-digit", + second: "2-digit", + hour12: false, + timeZone: "Asia/Kathmandu", + }; const logFilePath = path.resolve(__dirname, "../.logs/lock_logs.txt"); - const logMessage = `[${new Date().toISOString()}] ${message}\n`; + const logMessage = `[${new Date().toLocaleString("en-US", options)}] ${message}\n`; return new Promise((resolve, reject) => { fs.appendFile(logFilePath, logMessage, (err) => { if (err) { diff --git a/tests/govtool-frontend/playwright/lib/services/kuberService.ts b/tests/govtool-frontend/playwright/lib/services/kuberService.ts index 8ba49b402..65190100e 100644 --- a/tests/govtool-frontend/playwright/lib/services/kuberService.ts +++ b/tests/govtool-frontend/playwright/lib/services/kuberService.ts @@ -3,7 +3,7 @@ import { ShelleyWallet } from "@helpers/crypto"; import { KuberValue } from "@types"; import * as blake from "blakejs"; import environments from "lib/constants/environments"; -import { LockInterceptor } from "lib/lockInterceptor"; +import { LockInterceptor, LockInterceptorInfo } from "lib/lockInterceptor"; import fetch, { BodyInit, RequestInit } from "node-fetch"; import { cborxDecoder, cborxEncoder } from "../helpers/cborEncodeDecode"; import convertBufferToHex from "../helpers/convertBufferToHex"; @@ -11,12 +11,16 @@ import { Logger } from "./../../../cypress/lib/logger/logger"; type CertificateType = "registerstake" | "registerdrep" | "deregisterdrep"; -export type TxSubmitResponse = { cbor: string; txId: string; address?: string }; +export type TxSubmitResponse = { + cbor: string; + txId: string; + lockInfo?: LockInterceptorInfo; +}; type KuberBalanceResponse = { - address: string; txin: string; value: KuberValue; + address?: string; }; const config = { @@ -71,18 +75,20 @@ class Kuber { async signAndSubmitTx(tx: any) { const signedTx = this.signTx(tx); + const signedTxBody = Uint8Array.from(cborxEncoder.encode(tx)); + const lockId = Buffer.from( + blake.blake2b(signedTxBody, undefined, 32) + ).toString("hex"); const submitTxCallback = async () => { - return this.submitTx(signedTx); + return this.submitTx(signedTx, lockId); }; - return LockInterceptor.intercept( - this.walletAddr, - submitTxCallback, - JSON.stringify(signedTx, null, 2) - ); + return LockInterceptor.intercept(this.walletAddr, submitTxCallback, lockId); } - async submitTx(signedTx: any) { - Logger.info(`Submitting tx: ${JSON.stringify(signedTx)}`); + async submitTx(signedTx: any, lockId?: string) { + Logger.info( + `Submitting tx: ${JSON.stringify({ lock_id: lockId, tx: signedTx })}` + ); const res = (await callKuber( `/api/${this.version}/tx?submit=true`, diff --git a/tests/govtool-frontend/playwright/package-lock.json b/tests/govtool-frontend/playwright/package-lock.json index 8c1c2433c..f229e2e72 100644 --- a/tests/govtool-frontend/playwright/package-lock.json +++ b/tests/govtool-frontend/playwright/package-lock.json @@ -9,7 +9,7 @@ "version": "1.0.0", "license": "MIT", "dependencies": { - "@cardanoapi/cardano-test-wallet": "^1.0.0", + "@cardanoapi/cardano-test-wallet": "^1.0.2", "@faker-js/faker": "^8.4.1", "@noble/curves": "^1.3.0", "@noble/ed25519": "^2.0.0", @@ -86,9 +86,9 @@ } }, "node_modules/@cardanoapi/cardano-test-wallet": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@cardanoapi/cardano-test-wallet/-/cardano-test-wallet-1.0.0.tgz", - "integrity": "sha512-mua97Dqo0E1YbGanLTdq9AhmMe8E0HvmC6uwDFPe4LG3M817Pp/5mXxwUD6CfFbGANQ/PuSTJ8m28qerlw1Arg==" + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@cardanoapi/cardano-test-wallet/-/cardano-test-wallet-1.0.2.tgz", + "integrity": "sha512-ABOOSoB0DUggcIwl6nj1v4/IhzFKPPV6krGLAv9RRmX5trkiOBLqGuSNrOlFU+7XELJzagDDwYS1ykhyuVD/HA==" }, "node_modules/@cbor-extract/cbor-extract-linux-x64": { "version": "2.2.0", @@ -3206,9 +3206,9 @@ "dev": true }, "@cardanoapi/cardano-test-wallet": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@cardanoapi/cardano-test-wallet/-/cardano-test-wallet-1.0.0.tgz", - "integrity": "sha512-mua97Dqo0E1YbGanLTdq9AhmMe8E0HvmC6uwDFPe4LG3M817Pp/5mXxwUD6CfFbGANQ/PuSTJ8m28qerlw1Arg==" + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@cardanoapi/cardano-test-wallet/-/cardano-test-wallet-1.0.2.tgz", + "integrity": "sha512-ABOOSoB0DUggcIwl6nj1v4/IhzFKPPV6krGLAv9RRmX5trkiOBLqGuSNrOlFU+7XELJzagDDwYS1ykhyuVD/HA==" }, "@cbor-extract/cbor-extract-linux-x64": { "version": "2.2.0", diff --git a/tests/govtool-frontend/playwright/package.json b/tests/govtool-frontend/playwright/package.json index c42c5ff45..3cb14402e 100644 --- a/tests/govtool-frontend/playwright/package.json +++ b/tests/govtool-frontend/playwright/package.json @@ -26,7 +26,7 @@ "format": "prettier . --write" }, "dependencies": { - "@cardanoapi/cardano-test-wallet": "^1.0.0", + "@cardanoapi/cardano-test-wallet": "^1.0.2", "@faker-js/faker": "^8.4.1", "@noble/curves": "^1.3.0", "@noble/ed25519": "^2.0.0", diff --git a/tests/govtool-frontend/playwright/playwright.config.ts b/tests/govtool-frontend/playwright/playwright.config.ts index caf1350e7..a2adcef75 100644 --- a/tests/govtool-frontend/playwright/playwright.config.ts +++ b/tests/govtool-frontend/playwright/playwright.config.ts @@ -27,7 +27,7 @@ export default defineConfig({ /*use Allure Playwright's testPlanFilter() to determine the grep parameter*/ grep: testPlanFilter(), /* Reporter to use. See https://playwright.dev/docs/test-reporters */ - reporter: process.env.CI ? [["dot"], ["allure-playwright"]] : [["dot"]], + reporter: process.env.CI ? [["line"], ["allure-playwright"]] : [["line"]], /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */ use: { /* Base URL to use in actions like `await page.goto('/')`. */ @@ -43,6 +43,10 @@ export default defineConfig({ /* Configure projects for major browsers */ projects: [ + { + name: "faucet setup", + testMatch: "**/faucet.setup.ts", + }, { name: "auth setup", testMatch: "**/auth.setup.ts", @@ -50,18 +54,19 @@ export default defineConfig({ { name: "dRep setup", testMatch: "**/dRep.setup.ts", - dependencies: process.env.CI ? ["wallet bootstrap"] : [], + dependencies: ["faucet setup"], }, { name: "wallet bootstrap", testMatch: "**/wallet.bootstrap.ts", + dependencies: ["faucet setup"], }, - { - name: "transaction", - use: { ...devices["Desktop Chrome"] }, - testMatch: "**/*.tx.spec.ts", - dependencies: process.env.CI ? ["auth setup", "wallet bootstrap"] : [], - }, + // { + // name: "transaction", + // use: { ...devices["Desktop Chrome"] }, + // testMatch: "**/*.tx.spec.ts", + // dependencies: process.env.CI ? ["auth setup", "wallet bootstrap"] : [], + // }, { name: "loggedin (desktop)", use: { ...devices["Desktop Chrome"] }, @@ -80,11 +85,18 @@ export default defineConfig({ testMatch: "**/*.dRep.spec.ts", dependencies: process.env.CI ? ["auth setup", "dRep setup"] : [], }, + { + name: "delegation", + use: { ...devices["Desktop Chrome"] }, + testMatch: "**/*.delegation.spec.ts", + dependencies: process.env.CI ? ["auth setup", "dRep setup"] : [], + teardown: "cleanup delegation", + }, { name: "independent (desktop)", use: { ...devices["Desktop Chrome"] }, testIgnore: [ - "**/*.tx.spec.ts", + "**/*.delegation.spec.ts", "**/*.loggedin.spec.ts", "**/*.dRep.spec.ts", ], @@ -98,5 +110,9 @@ export default defineConfig({ "**/*.dRep.spec.ts", ], }, + { + name: "cleanup delegation", + testMatch: "delegation.teardown.ts", + }, ], }); diff --git a/tests/govtool-frontend/playwright/tests/2-delegation/delegation.dRep.spec.ts b/tests/govtool-frontend/playwright/tests/2-delegation/delegation.delegation.spec.ts similarity index 72% rename from tests/govtool-frontend/playwright/tests/2-delegation/delegation.dRep.spec.ts rename to tests/govtool-frontend/playwright/tests/2-delegation/delegation.delegation.spec.ts index d027f40a2..92811984f 100644 --- a/tests/govtool-frontend/playwright/tests/2-delegation/delegation.dRep.spec.ts +++ b/tests/govtool-frontend/playwright/tests/2-delegation/delegation.delegation.spec.ts @@ -1,5 +1,9 @@ import environments from "@constants/environments"; -import { adaHolder01Wallet, dRep01Wallet } from "@constants/staticWallets"; +import { + adaHolder01Wallet, + adaHolder02Wallet, + dRep01Wallet, +} from "@constants/staticWallets"; import { createTempDRepAuth } from "@datafactory/createAuth"; import { test } from "@fixtures/walletExtension"; import { ShelleyWallet } from "@helpers/crypto"; @@ -45,7 +49,7 @@ test.describe("Delegate to myself", () => { [wallet.addressBech32(environments.networkId)], 600 ); - await pollTransaction(txRes.txId, txRes.address); + await pollTransaction(txRes.txId, txRes.lockInfo); const dRepAuth = await createTempDRepAuth(page, wallet); const dRepPage = await createNewPageWithWallet(browser, { storageState: dRepAuth, @@ -64,3 +68,25 @@ test.describe("Delegate to myself", () => { await expect(dRepPage.getByText("You are a Sole Voter")).toBeVisible(); }); }); + +test.describe("Change Delegation", () => { + test.use({ + storageState: ".auth/adaHolder02.json", + wallet: adaHolder02Wallet, + }); + + // Skipped: Blocked because delegation is not working + test.skip("2F. Should change delegated dRep @slow @critical", async ({ + page, + }) => { + const delegationPage = new DelegationPage(page); + await delegationPage.goto(); + delegationPage.delegateToDRep(dRep01Wallet.dRepId); + await waitForTxConfirmation(page); + + // await delegationPage.goto("/"); + // await adaHolderPage.getByTestId("change-dRep-button").click(); + // await delegationPage.delegateToDRep(dRep02Wallet.dRepId); + // await waitForTxConfirmation(page); + }); +}); diff --git a/tests/govtool-frontend/playwright/tests/2-delegation/delegation.tx.spec.ts b/tests/govtool-frontend/playwright/tests/2-delegation/delegation.tx.spec.ts deleted file mode 100644 index a172805b7..000000000 --- a/tests/govtool-frontend/playwright/tests/2-delegation/delegation.tx.spec.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { adaHolder02Wallet, dRep01Wallet } from "@constants/staticWallets"; -import { test } from "@fixtures/walletExtension"; -import { waitForTxConfirmation } from "@helpers/transaction"; -import DelegationPage from "@pages/delegationPage"; - -test.use({ storageState: ".auth/adaHolder02.json", wallet: adaHolder02Wallet }); - -// Skipped: Blocked because delegation is not working -test.skip("2F. Should change delegated dRep @slow @critical", async ({ - page, -}) => { - const delegationPage = new DelegationPage(page); - await delegationPage.goto(); - delegationPage.delegateToDRep(dRep01Wallet.dRepId); - await waitForTxConfirmation(page); - - // await delegationPage.goto("/"); - // await adaHolderPage.getByTestId("change-dRep-button").click(); - // await delegationPage.delegateToDRep(dRep02Wallet.dRepId); - // await waitForTxConfirmation(page); -}); diff --git a/tests/govtool-frontend/playwright/tests/3-drep-registration/dRepRegistration.dRep.spec.ts b/tests/govtool-frontend/playwright/tests/3-drep-registration/dRepRegistration.dRep.spec.ts index 92ed56917..2e633866d 100644 --- a/tests/govtool-frontend/playwright/tests/3-drep-registration/dRepRegistration.dRep.spec.ts +++ b/tests/govtool-frontend/playwright/tests/3-drep-registration/dRepRegistration.dRep.spec.ts @@ -10,6 +10,7 @@ import DRepRegistrationPage from "@pages/dRepRegistrationPage"; import GovernanceActionsPage from "@pages/governanceActionsPage"; import { expect } from "@playwright/test"; import kuberService from "@services/kuberService"; +import * as crypto from "crypto"; test.describe("Logged in DReps", () => { test.use({ storageState: ".auth/dRep01.json", wallet: dRep01Wallet }); @@ -22,6 +23,16 @@ test.describe("Logged in DReps", () => { dRep01Wallet.dRepId ); // BUG: testId -> dRep-id-display-dashboard (It is taking sidebar dRep-id) }); + + test.use({ storageState: ".auth/dRep01.json", wallet: dRep01Wallet }); + + // Skipped: No option to update metadata + test.skip("3H. Should be able to update metadata @slow", async ({ page }) => { + page.getByTestId("change-metadata-button").click(); + page.getByTestId("url-input").fill("https://google.com"); + page.getByTestId("hash-input").fill(crypto.randomBytes(32).toString("hex")); + await expect(page.getByTestId("confirm-modal-button")).toBeVisible(); + }); }); test.describe("Temporary DReps", () => { @@ -36,7 +47,7 @@ test.describe("Temporary DReps", () => { [wallet.addressBech32(environments.networkId)], 600 ); - await pollTransaction(res.txId, res.address); + await pollTransaction(res.txId, res.lockInfo); const tempDRepAuth = await createTempDRepAuth(page, wallet); const dRepPage = await createNewPageWithWallet(browser, { @@ -66,7 +77,7 @@ test.describe("Temporary DReps", () => { convertBufferToHex(wallet.stakeKey.private), convertBufferToHex(wallet.stakeKey.pkh) ); - await pollTransaction(registrationRes.txId, registrationRes.address); + await pollTransaction(registrationRes.txId, registrationRes.lockInfo); const tempDRepAuth = await createTempDRepAuth(page, wallet); const dRepPage = await createNewPageWithWallet(browser, { @@ -95,12 +106,12 @@ test.describe("Temporary DReps", () => { convertBufferToHex(wallet.stakeKey.private), convertBufferToHex(wallet.stakeKey.pkh) ); - await pollTransaction(registrationRes.txId, registrationRes.address); + await pollTransaction(registrationRes.txId, registrationRes.lockInfo); const res = await kuberService.transferADA([ wallet.addressBech32(environments.networkId), ]); - await pollTransaction(res.txId, res.address); + await pollTransaction(res.txId, res.lockInfo); const dRepAuth = await createTempDRepAuth(page, wallet); const dRepPage = await createNewPageWithWallet(browser, { diff --git a/tests/govtool-frontend/playwright/tests/3-drep-registration/dRepRegistration.tx.spec.ts b/tests/govtool-frontend/playwright/tests/3-drep-registration/dRepRegistration.tx.spec.ts deleted file mode 100644 index 50798e04b..000000000 --- a/tests/govtool-frontend/playwright/tests/3-drep-registration/dRepRegistration.tx.spec.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { dRep01Wallet } from "@constants/staticWallets"; -import { test } from "@fixtures/walletExtension"; -import { expect } from "@playwright/test"; -import * as crypto from "crypto"; - -test.describe("Logged in", () => { - test.use({ storageState: ".auth/dRep01.json", wallet: dRep01Wallet }); - - // Skipped: No option to update metadata - test.skip("3H. Should be able to update metadata @slow", async ({ page }) => { - page.getByTestId("change-metadata-button").click(); - page.getByTestId("url-input").fill("https://google.com"); - page.getByTestId("hash-input").fill(crypto.randomBytes(32).toString("hex")); - await expect(page.getByTestId("confirm-modal-button")).toBeVisible(); - }); -}); diff --git a/tests/govtool-frontend/playwright/tests/5-proposal-functionality/proposalFunctionality.dRep.spec.ts b/tests/govtool-frontend/playwright/tests/5-proposal-functionality/proposalFunctionality.dRep.spec.ts index 2844c24b8..dd13ab19b 100644 --- a/tests/govtool-frontend/playwright/tests/5-proposal-functionality/proposalFunctionality.dRep.spec.ts +++ b/tests/govtool-frontend/playwright/tests/5-proposal-functionality/proposalFunctionality.dRep.spec.ts @@ -112,13 +112,13 @@ test.describe("Perform voting", () => { convertBufferToHex(wallet.stakeKey.private), convertBufferToHex(wallet.stakeKey.pkh) ); - await pollTransaction(registrationRes.txId, registrationRes.address); + await pollTransaction(registrationRes.txId, registrationRes.lockInfo); const res = await kuberService.transferADA( [wallet.addressBech32(environments.networkId)], 40 ); - await pollTransaction(res.txId, registrationRes.address); + await pollTransaction(res.txId, registrationRes.lockInfo); const tempDRepAuth = await createTempDRepAuth(page, wallet); diff --git a/tests/govtool-frontend/playwright/tests/6-miscellaneous/miscellaneous.loggedin.spec.ts b/tests/govtool-frontend/playwright/tests/6-miscellaneous/miscellaneous.loggedin.spec.ts index 39f9e7a8e..8f58286fb 100644 --- a/tests/govtool-frontend/playwright/tests/6-miscellaneous/miscellaneous.loggedin.spec.ts +++ b/tests/govtool-frontend/playwright/tests/6-miscellaneous/miscellaneous.loggedin.spec.ts @@ -1,13 +1,15 @@ -import { test } from "@fixtures/walletExtension"; import { user01Wallet } from "@constants/staticWallets"; -import { expect } from "@playwright/test"; +import { test } from "@fixtures/walletExtension"; import DRepRegistrationPage from "@pages/dRepRegistrationPage"; import DelegationPage from "@pages/delegationPage"; +import { expect } from "@playwright/test"; test.use({ storageState: ".auth/user01.json", wallet: user01Wallet }); // Skipped: No dRepId to validate -test.skip("6B. Provides error for invalid format @fast @smoke", async ({ page }) => { +test.skip("6B. Provides error for invalid format @fast @smoke", async ({ + page, +}) => { // invalid dRep delegation const delegationPage = new DelegationPage(page); await delegationPage.goto(); @@ -18,11 +20,11 @@ test.skip("6B. Provides error for invalid format @fast @smoke", async ({ page }) const dRepRegistrationPage = new DRepRegistrationPage(page); await dRepRegistrationPage.goto(); - await dRepRegistrationPage.urlInput.fill("abc"); - await expect(dRepRegistrationPage.urlInputError).toBeVisible(); + // await dRepRegistrationPage.urlInput.fill("abc"); + // await expect(dRepRegistrationPage.urlInputError).toBeVisible(); - await dRepRegistrationPage.hashInput.fill("abc"); - await expect(dRepRegistrationPage.hashInputError).toBeVisible(); + // await dRepRegistrationPage.hashInput.fill("abc"); + // await expect(dRepRegistrationPage.hashInputError).toBeVisible(); }); test("6D: Proper label and recognition of the testnet network @fast @smoke", async ({ diff --git a/tests/govtool-frontend/playwright/tests/dRep.setup.ts b/tests/govtool-frontend/playwright/tests/dRep.setup.ts index 3e844251a..38c587663 100644 --- a/tests/govtool-frontend/playwright/tests/dRep.setup.ts +++ b/tests/govtool-frontend/playwright/tests/dRep.setup.ts @@ -18,7 +18,7 @@ dRepWallets.forEach((wallet) => { wallet.stake.pkh ); - await pollTransaction(res.txId, res.address); + await pollTransaction(res.txId, res.lockInfo); } catch (err) { if (err.status === 400) { expect(true, "DRep already registered").toBeTruthy(); @@ -36,7 +36,8 @@ setup("Setup dRep metadata", async () => { body: JSON.stringify(dRepInfo), }); Logger.success("Uploaded dRep metadata to bucket"); - } catch (e) { - Logger.fail(`Failed to upload dRep metadata: ${e}`); + } catch (err) { + Logger.fail(`Failed to upload dRep metadata: ${err}`); + throw err; } }); diff --git a/tests/govtool-frontend/playwright/tests/adaholder.teardown.ts b/tests/govtool-frontend/playwright/tests/delegation.teardown.ts similarity index 66% rename from tests/govtool-frontend/playwright/tests/adaholder.teardown.ts rename to tests/govtool-frontend/playwright/tests/delegation.teardown.ts index 49c21b8cc..986ab1a45 100644 --- a/tests/govtool-frontend/playwright/tests/adaholder.teardown.ts +++ b/tests/govtool-frontend/playwright/tests/delegation.teardown.ts @@ -1,15 +1,18 @@ +import environments from "@constants/environments"; import { adaHolderWallets } from "@constants/staticWallets"; import { pollTransaction } from "@helpers/transaction"; import { test as cleanup } from "@playwright/test"; import kuberService from "@services/kuberService"; +cleanup.describe.configure({ timeout: environments.txTimeOut }); + cleanup(`Abstain delegation`, async () => { const stakePrivKeys = adaHolderWallets.map((wallet) => wallet.stake.private); const stakePkhs = adaHolderWallets.map((wallet) => wallet.stake.pkh); - const { txId, address } = await kuberService.abstainDelegations( + const { txId, lockInfo } = await kuberService.abstainDelegations( stakePrivKeys, stakePkhs ); - await pollTransaction(txId, address); + await pollTransaction(txId, lockInfo); }); diff --git a/tests/govtool-frontend/playwright/tests/faucet.setup.ts b/tests/govtool-frontend/playwright/tests/faucet.setup.ts new file mode 100644 index 000000000..5aeb32639 --- /dev/null +++ b/tests/govtool-frontend/playwright/tests/faucet.setup.ts @@ -0,0 +1,16 @@ +import { faucetWallet } from "@constants/staticWallets"; +import { pollTransaction } from "@helpers/transaction"; +import { test as setup } from "@playwright/test"; +import { loadAmountFromFaucet } from "@services/faucetService"; +import kuberService from "@services/kuberService"; +import environments from "lib/constants/environments"; + +setup.describe.configure({ mode: "serial", timeout: environments.txTimeOut }); + +setup("Fund faucet wallet", async () => { + const balance = await kuberService.getBalance(faucetWallet.address); + if (balance > 2000) return; + + const res = await loadAmountFromFaucet(faucetWallet.address); + await pollTransaction(res.txid); +}); diff --git a/tests/govtool-frontend/playwright/tests/wallet.bootstrap.ts b/tests/govtool-frontend/playwright/tests/wallet.bootstrap.ts index 55ded87ff..1d7397fda 100644 --- a/tests/govtool-frontend/playwright/tests/wallet.bootstrap.ts +++ b/tests/govtool-frontend/playwright/tests/wallet.bootstrap.ts @@ -1,15 +1,10 @@ -import { - adaHolderWallets, - dRepWallets, - faucetWallet, -} from "@constants/staticWallets"; +import { adaHolderWallets, dRepWallets } from "@constants/staticWallets"; import { ShelleyWallet } from "@helpers/crypto"; import extractDRepsFromStakePubKey from "@helpers/extractDRepsFromStakePubkey"; import generateShellyWallets from "@helpers/generateShellyWallets"; import setupWallets from "@helpers/setupWallets"; import { pollTransaction } from "@helpers/transaction"; import { expect, test as setup } from "@playwright/test"; -import { loadAmountFromFaucet } from "@services/faucetService"; import kuberService from "@services/kuberService"; import { writeFile } from "fs"; import environments from "lib/constants/environments"; @@ -24,30 +19,22 @@ setup("Setup mock wallets", async () => { saveWallets(wallets); }); -setup("Fund faucet wallet", async () => { - const balance = await kuberService.getBalance(faucetWallet.address); - if (balance > 2000) return; - - const res = await loadAmountFromFaucet(faucetWallet.address); - await pollTransaction(res.txid); -}); - setup("Fund static wallets", async () => { const addresses = [...adaHolderWallets, ...dRepWallets].map((e) => e.address); const res = await kuberService.transferADA(addresses); - await pollTransaction(res.txId, res.address); + await pollTransaction(res.txId); }); for (const wallet of [...adaHolderWallets, ...dRepWallets]) { setup(`Register stake of static wallet: ${wallet.address}`, async () => { try { - const { txId, address } = await kuberService.registerStake( + const { txId, lockInfo } = await kuberService.registerStake( wallet.stake.private, wallet.stake.pkh, wallet.payment.private, wallet.address ); - await pollTransaction(txId, address); + await pollTransaction(txId, lockInfo); } catch (err) { if (err.status === 400) { expect(true, "Stake already registered").toBeTruthy(); From f73e09d15a637e35dfb0f181cbd4481f8123b8a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Sworze=C5=84?= Date: Wed, 8 May 2024 10:59:23 +0200 Subject: [PATCH 056/125] change disconnectWallet to disableWallet --- govtool/packages/wallet-connector/WalletProvider.tsx | 6 +++--- govtool/packages/wallet-connector/types.ts | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/govtool/packages/wallet-connector/WalletProvider.tsx b/govtool/packages/wallet-connector/WalletProvider.tsx index 4aee24e44..bc03bcc3a 100644 --- a/govtool/packages/wallet-connector/WalletProvider.tsx +++ b/govtool/packages/wallet-connector/WalletProvider.tsx @@ -30,19 +30,19 @@ const WalletProvider = ({ children }: WalletContextProviderProps) => { } }; - const disconnectWallet = () => { + const disableWallet = () => { setWalletAPI(null); }; const value = useMemo( () => ({ - disconnectWallet, + disableWallet, enableError, enableWallet, isEnableLoading, walletAPI, }), - [disconnectWallet, enableError, enableWallet, isEnableLoading, walletAPI] + [disableWallet, enableError, enableWallet, isEnableLoading, walletAPI] ); return ( diff --git a/govtool/packages/wallet-connector/types.ts b/govtool/packages/wallet-connector/types.ts index 8bae56adf..f937d094d 100644 --- a/govtool/packages/wallet-connector/types.ts +++ b/govtool/packages/wallet-connector/types.ts @@ -5,7 +5,7 @@ export type WalletContextProviderProps = { }; export type WalletContextValues = { - disconnectWallet: () => void; + disableWallet: () => void; enableError: string | null; enableWallet: (walletName: string) => Promise; isEnableLoading: boolean; From de9194c8d5c5d5c974982d6789742aea03867669 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Placzy=C5=84ski?= Date: Wed, 8 May 2024 12:31:43 +0200 Subject: [PATCH 057/125] Set participation.sanchogov.tools domain to dev service only The participation.sanchogov.tools domain has been configured to route exclusively to the dev service. This change affects the build and deploy workflows for beta, dev, staging, and test environments, as well as the Dockerfile and Docker Compose configuration for the analytics dashboard. --- .github/workflows/build-and-deploy-beta.yml | 2 +- .github/workflows/build-and-deploy-dev.yml | 2 +- .github/workflows/build-and-deploy-staging.yml | 2 +- .github/workflows/build-and-deploy-test.yml | 2 +- govtool/analytics-dashboard/Dockerfile | 1 + scripts/govtool/config/templates/docker-compose.yml.tpl | 3 +-- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/build-and-deploy-beta.yml b/.github/workflows/build-and-deploy-beta.yml index 9418abaf0..4f1647eae 100644 --- a/.github/workflows/build-and-deploy-beta.yml +++ b/.github/workflows/build-and-deploy-beta.yml @@ -30,7 +30,7 @@ jobs: GTM_ID: ${{ secrets.GTM_ID }} IP_ADDRESS_BYPASSING_BASIC_AUTH1: ${{ secrets.IP_ADDRESS_BYPASSING_BASIC_AUTH1 }} IP_ADDRESS_BYPASSING_BASIC_AUTH2: ${{ secrets.IP_ADDRESS_BYPASSING_BASIC_AUTH2 }} - NEXT_PUBLIC_API_URL: "https://sanchogov.tools/api" + NEXT_PUBLIC_API_URL: "https://participation.sanchogov.tools" NEXT_PUBLIC_GA4_PROPERTY_ID: ${{ secrets.NEXT_PUBLIC_GA4_PROPERTY_ID }} NGINX_BASIC_AUTH: ${{ secrets.NGINX_BASIC_AUTH }} PIPELINE_URL: https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }} diff --git a/.github/workflows/build-and-deploy-dev.yml b/.github/workflows/build-and-deploy-dev.yml index e8e1863b0..e618b165e 100644 --- a/.github/workflows/build-and-deploy-dev.yml +++ b/.github/workflows/build-and-deploy-dev.yml @@ -29,7 +29,7 @@ jobs: GTM_ID: ${{ secrets.GTM_ID }} IP_ADDRESS_BYPASSING_BASIC_AUTH1: ${{ secrets.IP_ADDRESS_BYPASSING_BASIC_AUTH1 }} IP_ADDRESS_BYPASSING_BASIC_AUTH2: ${{ secrets.IP_ADDRESS_BYPASSING_BASIC_AUTH2 }} - NEXT_PUBLIC_API_URL: "https://dev-sanchonet.govtool.byron.network/api" + NEXT_PUBLIC_API_URL: "https://participation.sanchogov.tools" NEXT_PUBLIC_GA4_PROPERTY_ID: ${{ secrets.NEXT_PUBLIC_GA4_PROPERTY_ID }} NGINX_BASIC_AUTH: ${{ secrets.NGINX_BASIC_AUTH }} PIPELINE_URL: https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }} diff --git a/.github/workflows/build-and-deploy-staging.yml b/.github/workflows/build-and-deploy-staging.yml index 439bcd0e1..c47365565 100644 --- a/.github/workflows/build-and-deploy-staging.yml +++ b/.github/workflows/build-and-deploy-staging.yml @@ -31,7 +31,7 @@ jobs: GTM_ID: ${{ secrets.GTM_ID }} IP_ADDRESS_BYPASSING_BASIC_AUTH1: ${{ secrets.IP_ADDRESS_BYPASSING_BASIC_AUTH1 }} IP_ADDRESS_BYPASSING_BASIC_AUTH2: ${{ secrets.IP_ADDRESS_BYPASSING_BASIC_AUTH2 }} - NEXT_PUBLIC_API_URL: "https://staging.govtool.byron.network/api" + NEXT_PUBLIC_API_URL: "https://participation.sanchogov.tools" NEXT_PUBLIC_GA4_PROPERTY_ID: ${{ secrets.NEXT_PUBLIC_GA4_PROPERTY_ID }} NGINX_BASIC_AUTH: ${{ secrets.NGINX_BASIC_AUTH }} PIPELINE_URL: https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }} diff --git a/.github/workflows/build-and-deploy-test.yml b/.github/workflows/build-and-deploy-test.yml index 38c8d04aa..c5788056f 100644 --- a/.github/workflows/build-and-deploy-test.yml +++ b/.github/workflows/build-and-deploy-test.yml @@ -31,7 +31,7 @@ jobs: GTM_ID: ${{ secrets.GTM_ID }} IP_ADDRESS_BYPASSING_BASIC_AUTH1: ${{ secrets.IP_ADDRESS_BYPASSING_BASIC_AUTH1 }} IP_ADDRESS_BYPASSING_BASIC_AUTH2: ${{ secrets.IP_ADDRESS_BYPASSING_BASIC_AUTH2 }} - NEXT_PUBLIC_API_URL: "https://test-sanchonet.govtool.byron.network/api" + NEXT_PUBLIC_API_URL: "https://participation.sanchogov.tools" NEXT_PUBLIC_GA4_PROPERTY_ID: ${{ secrets.NEXT_PUBLIC_GA4_PROPERTY_ID }} NGINX_BASIC_AUTH: ${{ secrets.NGINX_BASIC_AUTH }} PIPELINE_URL: https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }} diff --git a/govtool/analytics-dashboard/Dockerfile b/govtool/analytics-dashboard/Dockerfile index 6128db7ff..91c295f53 100644 --- a/govtool/analytics-dashboard/Dockerfile +++ b/govtool/analytics-dashboard/Dockerfile @@ -17,6 +17,7 @@ RUN \ # Rebuild the source code only when needed FROM base AS builder +# Set the build arguments ARG NEXT_PUBLIC_API_URL WORKDIR /app COPY --from=deps /app/node_modules ./node_modules diff --git a/scripts/govtool/config/templates/docker-compose.yml.tpl b/scripts/govtool/config/templates/docker-compose.yml.tpl index e997a52b7..42c09f083 100644 --- a/scripts/govtool/config/templates/docker-compose.yml.tpl +++ b/scripts/govtool/config/templates/docker-compose.yml.tpl @@ -214,7 +214,6 @@ services: environment: - GA_CLIENT_EMAIL=${GA_CLIENT_EMAIL} - GA_PRIVATE_KEY=${GA_PRIVATE_KEY} - - GOOGLE_APPLICATION_CREDENTIALS=${GOOGLE_APPLICATION_CREDENTIALS} - GOOGLE_APPLICATION_CREDENTIALS=/run/secrets/google-credentials.json - NEXT_PUBLIC_API_URL=${NEXT_PUBLIC_API_URL} - NEXT_PUBLIC_GA4_PROPERTY_ID=${NEXT_PUBLIC_GA4_PROPERTY_ID} @@ -225,7 +224,7 @@ services: restart: always labels: - "traefik.enable=true" - - "traefik.http.routers.to-analytics-dashboard.rule=Host(`participation.`)" + - "traefik.http.routers.to-analytics-dashboard.rule=Host(`participation.sanchogov.tools`)" - "traefik.http.routers.to-analytics-dashboard.entrypoints=websecure" - "traefik.http.routers.to-analytics-dashboard.tls.certresolver=myresolver" - "traefik.http.services.analytics-dashboard.loadbalancer.server.port=3000" From 52d9e0d1d012693a45b6b29fc1ec9f039f4bfb90 Mon Sep 17 00:00:00 2001 From: Sudip Bhattarai Date: Wed, 8 May 2024 16:19:59 +0545 Subject: [PATCH 058/125] Refactor build scripts and gh-action --- .github/workflows/build-and-deploy-test.yml | 35 +--- gov-action-loader/backend/.env.example | 4 - gov-action-loader/backend/app/settings.py | 11 +- govtool/backend/Dockerfile | 5 +- tests/test-infrastructure/.env.example | 6 +- tests/test-infrastructure/README.md | 155 ++++-------------- tests/test-infrastructure/build-and-deploy.sh | 30 ++++ tests/test-infrastructure/build-images.sh | 15 +- .../configs_template/postgres_db_setup.sql | 8 +- tests/test-infrastructure/deploy-swarm.sh | 76 --------- tests/test-infrastructure/deploy.sh | 112 +++++++++++++ .../docker-compose-basic-services.yml | 12 +- .../docker-compose-cardano.yml | 20 +-- .../docker-compose-govaction-loader.yml | 12 +- .../docker-compose-govtool.yml | 28 +++- .../docker-compose-test.yml | 41 +---- tests/test-infrastructure/gen-configs.sh | 22 +-- .../scripts/deploy-stack.sh | 44 ++++- .../secrets_template/lighthouserc.json | 2 +- tests/test-infrastructure/sync.sh | 2 + 20 files changed, 305 insertions(+), 335 deletions(-) create mode 100755 tests/test-infrastructure/build-and-deploy.sh delete mode 100755 tests/test-infrastructure/deploy-swarm.sh create mode 100755 tests/test-infrastructure/deploy.sh create mode 100755 tests/test-infrastructure/sync.sh diff --git a/.github/workflows/build-and-deploy-test.yml b/.github/workflows/build-and-deploy-test.yml index 44c064aa3..755e615c1 100644 --- a/.github/workflows/build-and-deploy-test.yml +++ b/.github/workflows/build-and-deploy-test.yml @@ -4,12 +4,11 @@ run-name: Deploy by @${{ github.actor }} on: push: branches: - - test + - test-deployment env: ENVIRONMENT: "test" CARDANO_NETWORK: "sanchonet" - DOMAIN: "test-sanchonet.govtool.byron.network" jobs: deploy: @@ -17,22 +16,16 @@ jobs: runs-on: ubuntu-latest defaults: run: - working-directory: ./scripts/govtool + working-directory: ./tests/test-infrastructure env: - DBSYNC_POSTGRES_DB: "cexplorer" - DBSYNC_POSTGRES_USER: "postgres" - DBSYNC_POSTGRES_PASSWORD: "pSa8JCpQOACMUdGb" + DOCKER_HOST: ssh://ec2-user@${{secrets.TEST_STACK_SERVER_IP }} GRAFANA_ADMIN_PASSWORD: ${{ secrets.GRAFANA_ADMIN_PASSWORD }} GRAFANA_SLACK_RECIPIENT: ${{ secrets.GRAFANA_SLACK_RECIPIENT }} GRAFANA_SLACK_OAUTH_TOKEN: ${{ secrets.GRAFANA_SLACK_OAUTH_TOKEN }} - NGINX_BASIC_AUTH: ${{ secrets.NGINX_BASIC_AUTH }} SENTRY_DSN_BACKEND: ${{ secrets.SENTRY_DSN_BACKEND }} - TRAEFIK_LE_EMAIL: "admin+govtool@binarapps.com" GTM_ID: ${{ secrets.GTM_ID }} SENTRY_DSN: ${{ secrets.SENTRY_DSN_FRONTEND }} PIPELINE_URL: https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }} - IP_ADDRESS_BYPASSING_BASIC_AUTH1: ${{ secrets.IP_ADDRESS_BYPASSING_BASIC_AUTH1 }} - IP_ADDRESS_BYPASSING_BASIC_AUTH2: ${{ secrets.IP_ADDRESS_BYPASSING_BASIC_AUTH2 }} USERSNAP_SPACE_API_KEY: ${{ secrets.USERSNAP_SPACE_API_KEY }} steps: - name: Checkout code @@ -40,28 +33,12 @@ jobs: with: fetch-depth: 0 - - name: Configure AWS credentials - uses: aws-actions/configure-aws-credentials@v3 - with: - aws-access-key-id: ${{ secrets.GHA_AWS_ACCESS_KEY_ID }} - aws-secret-access-key: ${{ secrets.GHA_AWS_SECRET_ACCESS_KEY }} - aws-region: eu-west-1 - - - name: Login to AWS ECR - uses: aws-actions/configure-aws-credentials@v2 - with: - aws-region: eu-west-1 - name: Setup SSH agent uses: webfactory/ssh-agent@v0.8.0 with: - ssh-private-key: ${{ secrets.GHA_SSH_PRIVATE_KEY }} - - - name: Deploy app - run: | - make --debug=b all + ssh-private-key: ${{ secrets.TEST_STACK_SSH_KEY }} - - name: Reprovision Grafana + - name: Update images run: | - sleep 30 # give grafana time to start up - make --debug=b reload-grafana + ./build-and-deploy.sh update-images diff --git a/gov-action-loader/backend/.env.example b/gov-action-loader/backend/.env.example index 654ec757e..8997b5adf 100644 --- a/gov-action-loader/backend/.env.example +++ b/gov-action-loader/backend/.env.example @@ -1,6 +1,2 @@ KUBER_API_URL=https://sanchonet.kuber.cardanoapi.io KUBER_API_KEY=xxxxxxxxxxxxx - -## Not required anymore -BLOCKFROST_API_URL= -BLOCKFROST_PROJECT_ID= diff --git a/gov-action-loader/backend/app/settings.py b/gov-action-loader/backend/app/settings.py index ce543cf33..4175277df 100644 --- a/gov-action-loader/backend/app/settings.py +++ b/gov-action-loader/backend/app/settings.py @@ -1,12 +1,9 @@ -from pydantic_settings import BaseSettings +from pydantic import BaseModel -class Settings(BaseSettings): +class Settings(BaseModel): kuber_api_url: str - kuber_api_key: str + kuber_api_key: str = "" # Default value is an empty string - blockfrost_api_url: str - blockfrost_project_id: str - -settings = Settings() +settings = Settings(kuber_api_url="your_api_url_here") \ No newline at end of file diff --git a/govtool/backend/Dockerfile b/govtool/backend/Dockerfile index b8882627d..7da291284 100644 --- a/govtool/backend/Dockerfile +++ b/govtool/backend/Dockerfile @@ -1,5 +1,6 @@ -ARG BASE_IMAGE_TAG -FROM 733019650473.dkr.ecr.eu-west-1.amazonaws.com/backend-base:$BASE_IMAGE_TAG +ARG BASE_IMAGE_TAG=latest +ARG BASE_IMAGE_REPO=733019650473.dkr.ecr.eu-west-1.amazonaws.com/backend-base +FROM $BASE_IMAGE_REPO:$BASE_IMAGE_TAG WORKDIR /src COPY . . RUN cabal build diff --git a/tests/test-infrastructure/.env.example b/tests/test-infrastructure/.env.example index 92570776c..81ff08a2b 100644 --- a/tests/test-infrastructure/.env.example +++ b/tests/test-infrastructure/.env.example @@ -1,4 +1,4 @@ -STACK_NAME=govtool +PROJECT_NAME=govtool +CARDANO_NETWORK=sanchonet BASE_DOMAIN=govtool.cardanoapi.io -BLOCKFROST_API_URL="" -BLOCKFROST_PROJECT_ID="" +GOVTOOL_TAG=test \ No newline at end of file diff --git a/tests/test-infrastructure/README.md b/tests/test-infrastructure/README.md index c0775d8eb..054cda6f5 100644 --- a/tests/test-infrastructure/README.md +++ b/tests/test-infrastructure/README.md @@ -1,134 +1,41 @@ GovTool Test Infrastructure ==================== -Services required for testing GovTool +Compose files and scripts to deploy and test environment of govtool. +Additionally, it deploys services required to perform integration test on the environment -## 1. Setting up the services +## Compose files and services +1. [basic-services](./docker-compose-basic-services.yml) : postgres and gateway +2. [cardano](./docker-compose-cardano.yml) : node, dbsync and kuber +3. [govtool](./docker-compose-govtool.yml) : govtool-frontend and govtool-backend +4. [govaction-loader](./docker-compose-govaction-loader.yml) : govaction-loader frontend and badkcne +5. [test](./docker-compose-test.yml) : lighthouse-server and metadata-api +## Setting up the services -#### a. Deploy with docker on swarm mode. + +#### a. Update .env file and DNS records - Create `.env` file by copying `.env.example` and update it. - Make sure that DNS is pointed to the right server. Following are the domains used. - - lighthouse.BASE_DOMAIN - - metabase.BASE_DOMAIN - - sonarqube.BASE_DOMAIN - - metrics.BASE_DOMAIN - - kuber.BASE_DOMAIN - - -`docker stack deploy` command doesn't support `.env` file secret/config files. -There's a helper script `deploy-swarm.sh` to load the environment variables from `.env` file and generate rendered docker compose file. -```bash -cd ./test/test-infrastructure # cd into the test-infrastructure folder -docker swarm init # if swarm mode is not enabled yet. -docker compose build # build the images -docker node update xxxx --label-add govtool-test-stack=true ## set the node to be used for deploying the services -./gen-configs.sh # generate configs and secrets. -./deploy-swarm.sh prepare # start postgres and nginx -sleep 30 # wait for 30 secs for postgres to be healthy -./deploy-swarm.sh finalize # deploy all the required services. -``` - -#### b. Setup -When the stack is ready, further configuration is required it the services and github repo secrets and workflow files. - -# 2. Services List - -## SonarQube Server -#### Requires -- postgres database - -#### Used by -- Github Action to submit sonar-sacanner result - -`sonar-scanner` is used for static analysis of code. -The analysis generated by sonar-scanner is saved to SonarQube server for better visibility and to see progress over time. - - -**Docker Image:** [mc1arke/sonarqube-with-community-branch-plugin:9.9-community](https://hub.docker.com/layers/mc1arke/sonarqube-with-community-branch-plugin/9.9-community/images/sha256-b91ac551bea0fc3b394eaf7f82ea79115e03db9ab47d26610b9e1566723a07a5?context=explore) - -**See :** [sonar-scanner](https://docs.sonarsource.com/sonarqube/latest/analyzing-source-code/scanners/sonarscanner/), [actions/sonar-scanner](https://github.com/marketplace/actions/sonar-scanner) - -### Initial configuration. - -- Login and change the initial password. -``` -username: admin -password: admin -``` -- Create new project and set the projectKey in file [govtool/frontend/sonar-project.properties](../../govtool/frontend/sonar-project.properties) -- Update the github action secrets - - SONAR_HOST_URL - - SONAR_TOKEN - - -## Metabase Server -#### Requires -- postgres database - -Metabase provides UI to show graphs and visualization from different datasource. -It is used for visualizing the test metrics and the api response times over time. - -**Docker Image:** [metabase/metabase:v0.46.6.4](https://hub.docker.com/layers/metabase/metabase/v0.46.6.4/images/sha256-95c60db0c87c5da9cb81f6aefd0cd548fe2c14ff8c8dcba2ea58a338865cdbd9?context=explore) - -### Initial Configuration - - Setup initial account for login via the webapp. - - Under database section in admin settings, add the `govtool_lithghouse` and `govtool_metrics` databases - - Select the database and add visualizations, queries for the data. - -## LightHouse Report Server -#### Requires -- postgres database - -#### Used by -- GitHub Action to submit lighthouse report. - -Lighthouse has audits for performance, accessibility, progressive web apps, SEO, and more. -Lighthouse-Server is used to host and display the audits generated by lighthouse. - -**Docker Image:** [patrickhulce/lhci-server:0.12.0](https://hub.docker.com/r/patrickhulce/lhci-server) - -### Initial Configuration -- install lhci locally and run `lhci wizard` to setup project -- update `--serverBaseUrl={{...}}` parameter in [.github/workflows/lighthouse.yml](../../.github/workflows/lighthouse.yml) -- update `LHCI_SERVER_TOKEN` in github secrets. -- install lighthouse github app on the repo -- obtain app token from lighthouse app and update `LHCI_GITHUB_APP_TOKEN` secret - -See: **[lighthouse-server-docs](https://googlechrome.github.io/lighthouse-ci/docs/server.html)** - - -## Metrics API Server -#### Requires -- postgres database -- metabase *(for result visualization) - - -#### Used by -- Github Action - backend test to submit test metrics. - -Metrics API Server receives metrics collected during backend test and saves them to database. -The results are visualized in metabase. - -### Initial Configuration -- update `RECORD_METRICS_API` variable in file [.github/workflows/test_backend.yml](../../.github/workflows/test_backend.yml) - - -**Source Code:** [tests/test-metrics-api](../test-metrics-api) - -## Kuber Server -#### Requires -- cardano-node's socket connection - -#### Used by -- Cypress integration test -- Governance Data Loader - -Opensource API server for transaction building and querying the ledger . -Kuber makes it easy to construct and submit transaction from the frontend. - -**Docker Image:** [dquadrant/kuber:70be9b0166177eab5cf33e603fd3dc579e14cf31](https://hub.docker.com/layers/dquadrant/kuber/70be9b0166177eab5cf33e603fd3dc579e14cf31/images/sha256-d3b3f7c2304da8c4777155b26220238b682c81a3ff2b14753a5dc41c4f151364?context=explore) + - lighthouse-{BASE_DOMAIN} + - kuber-{BASE_DOMAIN} + - metadata-{BASE_DOMAIN} + - governance-{BASE_DOMAIN} + +### b. Prepare the machine. + - Buy a virtual server + - Install `docker` and enable `docker compose` plugin. + - execute `docker swarm init` command. + +### c. One time setup on the machine. + - Generate secrets and configurations required by the services + `./gen-configs.sh` + - Mark the nodes with labels to specify where the services should be run. In case of single node + docker swarm, all labels can be set to single node. + `./deploy.sh prepare` + +### d. Build images and deploy the stacks. + - `./build-images.sh` + - `./deploy.sh stack all` -### Initial Configuration -- update `CYPRESS_kuberApiUrl` variable in [.github/workflows/test_integration_cypress.yml](../../.github/workflows/test_integration_cypress.yml) diff --git a/tests/test-infrastructure/build-and-deploy.sh b/tests/test-infrastructure/build-and-deploy.sh new file mode 100755 index 000000000..8c5c1568f --- /dev/null +++ b/tests/test-infrastructure/build-and-deploy.sh @@ -0,0 +1,30 @@ +#!/bin/bash + +BASE_IMAGE_NAME=govtool +export GOVTOOL_TAG="$(git rev-parse HEAD)" +export PROJECT_NAME=govtool +export CARDANO_NETWORK=sanchonet +export BASE_DOMAIN=govtool.cardanoapi.io + +. ./scripts/deploy-stack.sh + +check_env + +# Build images +./build-images.sh +function update-service(){ + docker service update --image "$2" "$1" +} + +if [[ "$1" == "update-images" ]] + + update-service govtool_backend "$BASE_IMAGE_NAME"/backend:${GOVTOOL_TAG} + update-service govtool_frontend "$BASE_IMAGE_NAME"/frontend:${GOVTOOL_TAG} + update-service govtool_metadata-validation "$BASE_IMAGE_NAME"/metadata-validation:${GOVTOOL_TAG} + + update-service govaction-loader_backend "$BASE_IMAGE_NAME"/gov-action-loader-frontend:${GOVTOOL_TAG} + update-service govaction-loader_frontend "$BASE_IMAGE_NAME"/gov-action-loader-backend:${GOVTOOL_TAG} + +elif [[ $1 == "full" ]] + ./deploy stack all +fi diff --git a/tests/test-infrastructure/build-images.sh b/tests/test-infrastructure/build-images.sh index 4f6796166..b74a8721d 100755 --- a/tests/test-infrastructure/build-images.sh +++ b/tests/test-infrastructure/build-images.sh @@ -1,7 +1,14 @@ #!/bin/bash - +set -e export BASE_IMAGE_NAME="govtool" -# build the base image -docker build -t "$BASE_IMAGE_NAME"/backend-base -f ../../govtool/backend/Dockerfile.base ../../govtool/backend +BASE_IMAGE_EXISTS=$(docker images -q "$BASE_IMAGE_NAME"/backend-base 2> /dev/null) + +if [ -z "$BASE_IMAGE_EXISTS" ]; then + echo "Building the base image..." + docker build -t "$BASE_IMAGE_NAME"/backend-base -f ../../govtool/backend/Dockerfile.base ../../govtool/backend +else + echo "Base image already exists. Skipping build." +fi + docker compose -f ./docker-compose-govtool.yml build -docker compose -f ./docker-compose.yml build +docker compose -f ./docker-compose-govaction-loader.yml build \ No newline at end of file diff --git a/tests/test-infrastructure/configs_template/postgres_db_setup.sql b/tests/test-infrastructure/configs_template/postgres_db_setup.sql index 7a40fccd8..1c87ab3f1 100644 --- a/tests/test-infrastructure/configs_template/postgres_db_setup.sql +++ b/tests/test-infrastructure/configs_template/postgres_db_setup.sql @@ -1,4 +1,4 @@ -CREATE database ${STACK_NAME}_lighthouse; -CREATE database ${STACK_NAME}_metrics; -CREATE database ${STACK_NAME}_sonarqube; -CREATE database ${STACK_NAME}_dbsync; \ No newline at end of file +CREATE database ${PROJECT_NAME}_lighthouse; +CREATE database ${PROJECT_NAME}_metrics; +CREATE database ${PROJECT_NAME}_sonarqube; +CREATE database ${PROJECßT_NAME}_dbsync; \ No newline at end of file diff --git a/tests/test-infrastructure/deploy-swarm.sh b/tests/test-infrastructure/deploy-swarm.sh deleted file mode 100755 index 71bb38d9e..000000000 --- a/tests/test-infrastructure/deploy-swarm.sh +++ /dev/null @@ -1,76 +0,0 @@ -#!/bin/bash -## Load environment variables and deploy to the docker swarm. -## -## Usages: -## ./deploy-swarm prepare -## -set -eo pipefail -set -vx -. ./scripts/deploy-stack.sh -load_env - -if [ "$1" == "destroy" ] -then - echo "This will remove everything in your stack including volumes" - echo "Are you Sure? (Y/N)" - read user_input - if ! ( [ "$user_input" = "y" ] || [ "$user_input" = "Y" ]) - then - exit 1 - fi - echo "Proceeding..." # Delete the Docker stack if "destroy" argument is provided - docker stack rm "${STACK_NAME}-services" || echo "${STACK_NAME}-services doesn't exist" - docker stack rm ${STACK_NAME} || echo "${STACK_NAME} doesn't exist" - ./gen-configs.sh clean - - for VOLUME in $(docker volume ls --filter "label=com.docker.stack.namespace=${STACK_NAME}" -q) "${STACK_NAME}-services_postgres" - do - echo -n "Removing Volume : " - docker volume rm "$VOLUME" - done - -elif [ "$1" == "prepare" ] -then - ## apply the enviroment to services compose file - ## and deploy the stack - deploy-stack ${STACK_NAME}-services './docker-compose-basic-services.yml' - -elif [ "$1" == "finalize" ] -then - ## apply the environment to compose file - ## deploy the govtool test infrastructure stack - deploy-stack ${STACK_NAME}-base './docker-compose-cardano.yml' -elif [ "$1" == 'stack' ] -then - if [ "$#" -ne 2 ] - then - echo 'stack requires the stack name "govtool" | "services" | "test"' - else - case "$2" in - all) - for DEPLOY_STACK in "basic-services" "cardano" "govaction-loader" "govtool" "test"; do - deploy-stack $DEPLOY_STACK "docker-compose-$DEPLOY_STACK.yml" - done - ;; - *) - if [[ ! -f ./"docker-compose-$2.yml" ]] - then - echo "Invalid stack name. $2" - else - deploy-stack $2 "docker-compose-$2.yml" - fi - ;; - esac - fi -else - echo "Something is wrong with the command" - echo - echo " Usage:" - echo " $0 (prepare | destroy | finalize | deploy)" - echo '' - echo " Options:" - echo " prepare -> deploys the services required by the test stack. i.e 'postgres' and 'reverse-proxy'" - echo " finalize -> deploys the test infrastructure services" - echo " destroy -> teardown everything except the volumes" - echo " deploy [stack_name] -> Deploy the stack." -fi diff --git a/tests/test-infrastructure/deploy.sh b/tests/test-infrastructure/deploy.sh new file mode 100755 index 000000000..c14d575b9 --- /dev/null +++ b/tests/test-infrastructure/deploy.sh @@ -0,0 +1,112 @@ +#!/bin/bash +## Load environment variables and deploy to the docker swarm. +## +## Usages: +## ./deploy-swarm prepare +## +set -eo pipefail +. ./scripts/deploy-stack.sh +load_env + +DOCKER_STACKS=("basic-services" "cardano" "govaction-loader" "govtool" "test") + +if [ "$1" == "destroy" ] +then + echo "This will remove everything in your stack except volumes, configs and secrets" + echo "Are you Sure? (Y/N)" + read user_input + if ! ( [ "$user_input" = "y" ] || [ "$user_input" = "Y" ]) + then + exit 1 + fi + echo "Proceeding..." # Delete the Docker stack if "destroy" argument is provided + + REVERSE_STACKS=() + for ((i=${#STACKS[@]}-1; i>=0; i--)); do + REVERSE_STACKS+=("${STACKS[i]}") + done + + for CUR_STACK in "${REVERSE_STACKS[@]}"; do + docker stack rm "$CUR_STACK" + sleep 6 # wait 6 seconds for each stack cleanup. + done + +# ./gen-configs.sh clean + +# for VOLUME in $(docker volume ls --filter "label=com.docker.stack.namespace=${STACK_NAME}" -q) "${STACK_NAME}-services_postgres" +# do +# echo -n "Removing Volume : " +# docker volume rm "$VOLUME" +# done +elif [ "$1" == 'prepare' ] +then + + # Get the number of nodes in the swarm + NODES=$(docker node ls --format "{{.ID}}" | wc -l) + + # If there is only one node, set the labels + if [ "$NODES" -eq 1 ]; then + NODE_ID=$(docker node ls --format "{{.ID}}") + + docker node update --label-add govtool-test-stack=true \ + --label-add blockchain=true \ + --label-add gateway=true \ + --label-add govtool=true \ + --label-add gov-action-loader=true \ + "$NODE_ID" + + echo "Labels set on node: $NODE_ID" + else + echo "There are multiple nodes in the docker swarm." + echo "Please set the following labels to correct nodes manually." + echo " - govtool-test-stack " + echo " - blockchain" + echo " - gateway" + echo " - govtool" + echo " - gov-action-loader" + echo "" + echo " e.g. $ docker node update xxxx --label-add gateway=true" + + exit 1 + fi + +elif [ "$1" == 'stack' ] +then + if [ "$#" -ne 2 ] + then + echo "stack requires the stack name". + echo "Usage :" + echo " > $0 stack [stack-name]". + echo "" + echo " stack-name : One of the following"ß + echo " $DOCKER_STACKS" + else + case "$2" in + all) + + for DEPLOY_STACK in "${DOCKER_STACKS[@]}"; do + deploy-stack "$DEPLOY_STACK" "docker-compose-$DEPLOY_STACK.yml" + done + + ;; + *) + if [[ ! -f ./"docker-compose-$2.yml" ]] + then + echo "Invalid stack name. $2" + else + deploy-stack $2 "docker-compose-$2.yml" + fi + ;; + esac + fi +else + echo "Something is wrong with the command" + echo + echo " Usage:" + echo " $0 (prepare | destroy | deploy)" + echo '' + echo " Options:" + echo " prepare -> set required labels to docker swarm node." + echo " destroy -> teardown everything except the volumes" + echo " deploy [stack_name] -> Deploy the stack." +fi diff --git a/tests/test-infrastructure/docker-compose-basic-services.yml b/tests/test-infrastructure/docker-compose-basic-services.yml index 96d9deaf6..e0b417494 100644 --- a/tests/test-infrastructure/docker-compose-basic-services.yml +++ b/tests/test-infrastructure/docker-compose-basic-services.yml @@ -2,14 +2,14 @@ version: "3.9" secrets: postgres_user: external: true - name: ${STACK_NAME}_postgres_user + name: ${PROJECT_NAME}_postgres_user postgres_password: external: true - name: ${STACK_NAME}_postgres_password + name: ${PROJECT_NAME}_postgres_password configs: postgres_db_setup.sql: external: true - name: ${STACK_NAME}_postgres_db_setup.sql + name: ${PROJECT_NAME}_postgres_db_setup.sql volumes: postgres: @@ -45,7 +45,7 @@ services: deploy: placement: constraints: - - node.labels.govtool-test-stack == true + - node.labels.gateway == true restart_policy: delay: "10s" postgres: @@ -64,6 +64,8 @@ services: - postgres volumes: - postgres:/var/lib/postgresql/data + ports: + - 5432:5432 restart: always healthcheck: test: ["CMD-SHELL", "pg_isready -U postgres"] @@ -74,6 +76,6 @@ services: deploy: placement: constraints: - - node.labels.govtool-test-stack == true + - node.labels.blockchain == true restart_policy: delay: "30s" diff --git a/tests/test-infrastructure/docker-compose-cardano.yml b/tests/test-infrastructure/docker-compose-cardano.yml index c9e3b69d6..c2d262628 100644 --- a/tests/test-infrastructure/docker-compose-cardano.yml +++ b/tests/test-infrastructure/docker-compose-cardano.yml @@ -2,13 +2,13 @@ version: "3.9" secrets: postgres_user: external: true - name: ${STACK_NAME}_postgres_user + name: ${PROJECT_NAME}_postgres_user postgres_password: external: true - name: ${STACK_NAME}_postgres_password + name: ${PROJECT_NAME}_postgres_password dbsync_database: external: true - name: ${STACK_NAME}_dbsync_database + name: ${PROJECT_NAME}_dbsync_database volumes: node_data: @@ -25,10 +25,10 @@ networks: name: cardano services: - cardano-node: + node: image: ghcr.io/intersectmbo/cardano-node:8.10.0-pre environment: - NETWORK: sanchonet + NETWORK: ${CARDANO_NETWORK} volumes: - node_data:/data - node_ipc:/ipc @@ -36,17 +36,17 @@ services: logging: driver: "json-file" options: - max-size: "200k" + max-size: "10M" max-file: "10" ports: - target: 3001 - published: 30004 + published: 3001 protocol: tcp mode: host deploy: placement: constraints: - - node.labels.blockchain== true + - node.labels.blockchain==true restart_policy: condition: on-failure delay: 15s @@ -55,7 +55,7 @@ services: networks: - postgres environment: - NETWORK: sanchonet + NETWORK: ${CARDANO_NETWORK} POSTGRES_HOST: postgres POSTGRES_PORT: 5432 DISABLE_CACHE: "" @@ -72,7 +72,7 @@ services: logging: driver: "json-file" options: - max-size: "200k" + max-size: "10M" max-file: "10" deploy: labels: diff --git a/tests/test-infrastructure/docker-compose-govaction-loader.yml b/tests/test-infrastructure/docker-compose-govaction-loader.yml index 96e10f556..97cddc345 100644 --- a/tests/test-infrastructure/docker-compose-govaction-loader.yml +++ b/tests/test-infrastructure/docker-compose-govaction-loader.yml @@ -8,8 +8,8 @@ networks: services: - governance-action-loader-ui: - image: govtool/gov-action-loader-frontend + frontend: + image: govtool/gov-action-loader-frontend:${GOVTOOL_TAG} build: context: ../../gov-action-loader/frontend dockerfile: Dockerfile @@ -20,7 +20,7 @@ services: deploy: placement: constraints: - - node.labels.govtool-test-stack == true + - node.labels.gov-action-loader == true restart_policy: delay: "30s" resources: @@ -29,8 +29,8 @@ services: reservations: memory: 100M - governance-action-loader-api: - image: govtool/gov-action-loader-backend + backend: + image: govtool/gov-action-loader-backend:${GOVTOOL_TAG} build: context: ../../gov-action-loader/backend dockerfile: Dockerfile @@ -46,7 +46,7 @@ services: deploy: placement: constraints: - - node.labels.govtool-test-stack == true + - node.labels.gov-action-loader == true restart_policy: delay: "30s" resources: diff --git a/tests/test-infrastructure/docker-compose-govtool.yml b/tests/test-infrastructure/docker-compose-govtool.yml index 2d1e9ce25..68f96b8d7 100644 --- a/tests/test-infrastructure/docker-compose-govtool.yml +++ b/tests/test-infrastructure/docker-compose-govtool.yml @@ -10,19 +10,18 @@ configs: external: true services: backend: - image: govtool/backend + image: govtool/backend:${GOVTOOL_TAG} build: context: ../../govtool/backend args: - BASE_IMAGE_TAG: govtool/backend-base + BASE_IMAGE_REPO: govtool/backend-base entrypoint: - sh - -c - vva-be -c /config.json start-app environment: - VIRTUAL_HOST: https://${BASE_DOMAIN} -> :8080 + VIRTUAL_HOST: https://${BASE_DOMAIN}/api/ -> :8080/ VIRTUAL_HOST_2: https://${BASE_DOMAIN}/swagger -> :8080/swagger - VIRTUAL_HOST_3: https://${BASE_DOMAIN}/api/ -> :8080/ networks: - frontend @@ -36,9 +35,11 @@ services: constraints: - node.labels.govtool==true frontend: - image: govtool/frontend + image: govtool/frontend:${GOVTOOL_TAG} build: context: ../../govtool/frontend + args: + VITE_BASE_URL: "" environment: VIRTUAL_HOST: https://${BASE_DOMAIN} networks: @@ -48,4 +49,19 @@ services: delay: "30s" placement: constraints: - - node.labels.govtool==true \ No newline at end of file + - node.labels.govtool==true + metadata-validation: + image: govtool/metadata-validation:${GOVTOOL_TAG} + build: + context: ../../govtool/metadata-validation + environment: + VIRTUAL_HOST: https://${BASE_DOMAIN}/metadata-validation/ -> :3000 + PORT: '3000' + networks: + - frontend + deploy: + restart_policy: + delay: "30s" + placement: + constraints: + - node.labels.govtool==true diff --git a/tests/test-infrastructure/docker-compose-test.yml b/tests/test-infrastructure/docker-compose-test.yml index 891e88253..ef350c4ee 100644 --- a/tests/test-infrastructure/docker-compose-test.yml +++ b/tests/test-infrastructure/docker-compose-test.yml @@ -1,17 +1,8 @@ version: "3.9" secrets: - postgres_user: - external: true - name: ${STACK_NAME}_postgres_user - postgres_password: - external: true - name: ${STACK_NAME}_postgres_password lighthouserc.json: external: true - name: ${STACK_NAME}_lighthouserc.json - metrics_api_secret_token: - external: true - name: ${STACK_NAME}_metrics_api_secret + name: ${PROJECT_NAME}_lighthouserc.json volumes: lhci_data: @@ -26,36 +17,6 @@ networks: external: true services: - metrics_api: - image: voltaire-era/govtool-metrics-api - build: - context: ../test-metrics-api - environment: - VIRTUAL_HOST: https://metrics-${BASE_DOMAIN}/ -> :3000/ - PGHOST: postgres - PGDATABASE: ${STACK_NAME}_metrics - secrets: - - source: postgres_password - target: /run/secrets/pgpassword - - source: postgres_user - target: /run/secrets/pguser - - source: metrics_api_secret_token - target: /run/secrets/api_secret_token - networks: - - postgres - - frontend - deploy: - placement: - constraints: - - node.labels.govtool-test-stack == true - restart_policy: - delay: "30s" - resources: - limits: - memory: 600M - reservations: - memory: 100M - lhci-server: image: patrickhulce/lhci-server:0.12.0 environment: diff --git a/tests/test-infrastructure/gen-configs.sh b/tests/test-infrastructure/gen-configs.sh index 33b925726..7d8d83e65 100755 --- a/tests/test-infrastructure/gen-configs.sh +++ b/tests/test-infrastructure/gen-configs.sh @@ -32,16 +32,16 @@ if [ "$1" == "clean" ]; then for SECRET_FILE in $(ls ./secrets) do SECRET_NAME="$(basename $SECRET_FILE)" - echo -n "Removing secret: ${STACK_NAME}_${SECRET_NAME}" - docker secret rm "${STACK_NAME}_${SECRET_NAME}" || true + echo -n "Removing secret: ${PROJECT_NAME}_${SECRET_NAME}" + docker secret rm "${PROJECT_NAME}_${SECRET_NAME}" || true done # Create configs from files for CONFIG_FILE in $(ls ./configs) do CONFIG_NAME=$(basename $CONFIG_FILE) - echo -n "Removing config: ${STACK_NAME}_${CONFIG_NAME}" - docker config rm "${STACK_NAME}_${CONFIG_NAME}" || true + echo -n "Removing config: ${PROJECT_NAME}_${CONFIG_NAME}" + docker config rm "${PROJECT_NAME}_${CONFIG_NAME}" || true done set -x @@ -59,7 +59,7 @@ mkdir -p ./secrets; # Generate random secrets export POSTGRES_USER=postgres -export DBSYNC_DATABASE="${STACK_NAME}_dbsync" +export DBSYNC_DATABASE="${PROJECT_NAME}_dbsync" # Save secrets to files echo -n $POSTGRES_USER > ./secrets/postgres_user @@ -71,13 +71,13 @@ generate_secret "POSTGRES_PASSWORD" "./secrets/postgres_password" ## loop over templates and update them. for CONFIG_FILE in $(ls ./configs_template) do - echo -n "Config ${STACK_NAME}_${CONFIG_FILE}: " + echo -n "Config ${PROJECT_NAME}_${CONFIG_FILE}: " envsubst < "./configs_template/$CONFIG_FILE" > "./configs/${CONFIG_FILE}" done for SECRET_FILE in $(ls ./secrets_template) do - echo -n "Secret ${STACK_NAME}_${SECRET_FILE}: " + echo -n "Secret ${PROJECT_NAME}_${SECRET_FILE}: " envsubst < "./secrets_template/$SECRET_FILE" > "./secrets/${SECRET_FILE}" done @@ -90,8 +90,8 @@ docker info | grep 'Swarm: active' > /dev/null 2>/dev/null || exit 0 # Create secrets from files ls ./secrets | while IFS= read -r SECRET_FILE; do SECRET_NAME=$(basename "$SECRET_FILE") - echo -n "Secret: ${STACK_NAME}_${SECRET_NAME}: " - cat "./secrets/$SECRET_NAME" | (docker secret create "${STACK_NAME}_${SECRET_NAME}" -) || true + echo -n "Secret: ${PROJECT_NAME}_${SECRET_NAME}: " + cat "./secrets/$SECRET_NAME" | (docker secret create "${PROJECT_NAME}_${SECRET_NAME}" -) || true done @@ -99,6 +99,6 @@ done for CONFIG_FILE in $(ls ./configs) do CONFIG_NAME=$(basename $CONFIG_FILE) - echo -n "Config: ${STACK_NAME}_${CONFIG_NAME}: " - cat "./configs/$CONFIG_NAME" | (docker config create "${STACK_NAME}_${CONFIG_NAME}" -) || true + echo -n "Config: ${PROJECT_NAME}_${CONFIG_NAME}: " + cat "./configs/$CONFIG_NAME" | (docker config create "${PROJECT_NAME}_${CONFIG_NAME}" -) || true done \ No newline at end of file diff --git a/tests/test-infrastructure/scripts/deploy-stack.sh b/tests/test-infrastructure/scripts/deploy-stack.sh index 577eb5445..0e53de421 100755 --- a/tests/test-infrastructure/scripts/deploy-stack.sh +++ b/tests/test-infrastructure/scripts/deploy-stack.sh @@ -7,11 +7,49 @@ set -eo pipefail function load_env(){ - set -a - . ./.env - set +a + if [[ -f ./.env ]] + then + set -a + . ./.env + set +a + fi + check_env } + +function check_env(){ + + # Path to the .env.example file + EXAMPLE_FILE=".env.example" + + unset_keys=() + + # Read each line of the .env.example file + while IFS= read -r line || [ -n "$line" ]; do + # Skip empty lines + if [ -z "$line" ]; then + continue + fi + + line=$(echo "$line" | sed -e 's/^[[:space:]]*//') + + # Extract the key from each line + key=$(echo "$line" | cut -d'=' -f1) + + if [ -z "${!key}" ]; then + unset_keys+=("$key") + fi + done < "$EXAMPLE_FILE" + + # Print error message for unset keys + if [ ${#unset_keys[@]} -gt 0 ]; then + echo "The following keys are not set in the environment:" + for key in "${unset_keys[@]}"; do + echo "- $key" + done + exit 1 + fi +} function deploy-stack(){ echo "++ deploy-stack" "$@" ## apply the environment to compose file diff --git a/tests/test-infrastructure/secrets_template/lighthouserc.json b/tests/test-infrastructure/secrets_template/lighthouserc.json index 65930f8fa..ee7be38d2 100644 --- a/tests/test-infrastructure/secrets_template/lighthouserc.json +++ b/tests/test-infrastructure/secrets_template/lighthouserc.json @@ -3,7 +3,7 @@ "server": { "storage": { "sqlDialect": "postgres", - "sqlConnectionUrl": "postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@postgres/${STACK_NAME}_lighthouse?application_name=lighthouse-ci-server" + "sqlConnectionUrl": "postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@postgres/${PROJECT_NAME}_lighthouse?application_name=lighthouse-ci-server" } } } diff --git a/tests/test-infrastructure/sync.sh b/tests/test-infrastructure/sync.sh new file mode 100755 index 000000000..d2a7058ad --- /dev/null +++ b/tests/test-infrastructure/sync.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env sh +rsync --rsync-path="sudo rsync" -ravz ./ intersect:/root/govtool/tests/test-infrastructure From b8e3aa3afe850b5671f9377c3f30e1fd8de1c477 Mon Sep 17 00:00:00 2001 From: jankun4 Date: Wed, 8 May 2024 12:37:49 +0200 Subject: [PATCH 059/125] [#876] add metadata/validate endpoint --- CHANGELOG.md | 1 + govtool/backend/app/Main.hs | 11 ++- govtool/backend/example-config.json | 4 +- govtool/backend/src/VVA/API.hs | 57 ++++++++----- govtool/backend/src/VVA/API/Types.hs | 101 +++++++++++++++++++++++- govtool/backend/src/VVA/Config.hs | 40 ++++++++-- govtool/backend/src/VVA/Metadata.hs | 45 +++++++++++ govtool/backend/src/VVA/Types.hs | 17 +++- govtool/backend/vva-be.cabal | 4 +- govtool/metadata-validation/src/main.ts | 2 +- 10 files changed, 248 insertions(+), 34 deletions(-) create mode 100644 govtool/backend/src/VVA/Metadata.hs diff --git a/CHANGELOG.md b/CHANGELOG.md index fee94d409..e19d14f47 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,7 @@ changes. ### Added +- added `metadata/validate` endpoint [Issue 876](https://github.com/IntersectMBO/govtool/issues/876) - added pagination to `drep/list` [Issue 756](https://github.com/IntersectMBO/govtool/issues/756) - added search query param to the `drep/getVotes` [Issue 640](https://github.com/IntersectMBO/govtool/issues/640) - added filtering and sorting capabilities to the `drep/list` [Issue 722](https://github.com/IntersectMBO/govtool/issues/722) diff --git a/govtool/backend/app/Main.hs b/govtool/backend/app/Main.hs index f4df1c03c..5ca505210 100644 --- a/govtool/backend/app/Main.hs +++ b/govtool/backend/app/Main.hs @@ -70,8 +70,10 @@ import VVA.API.Types import VVA.CommandLine import VVA.Config import VVA.Types (AppEnv (..), - AppError (CriticalError, NotFoundError, ValidationError), + AppError (CriticalError, NotFoundError, ValidationError, InternalError), CacheEnv (..)) +import Network.HTTP.Client hiding (Proxy, Request) +import Network.HTTP.Client.TLS proxyAPI :: Proxy (VVAApi :<|> SwaggerAPI) proxyAPI = Proxy @@ -113,6 +115,7 @@ startApp vvaConfig = do dRepVotingPowerCache <- newCache dRepListCache <- newCache networkMetricsCache <- newCache + metadataValidationCache <- newCache return $ CacheEnv { proposalListCache , getProposalCache @@ -124,10 +127,12 @@ startApp vvaConfig = do , dRepVotingPowerCache , dRepListCache , networkMetricsCache + , metadataValidationCache } connectionPool <- createPool (connectPostgreSQL (encodeUtf8 (dbSyncConnectionString $ getter vvaConfig))) close 1 1 60 + vvaTlsManager <- newManager tlsManagerSettings - let appEnv = AppEnv {vvaConfig=vvaConfig, vvaCache=cacheEnv, vvaConnectionPool=connectionPool} + let appEnv = AppEnv {vvaConfig=vvaConfig, vvaCache=cacheEnv, vvaConnectionPool=connectionPool, vvaTlsManager} server' <- mkVVAServer appEnv runSettings settings server' @@ -252,7 +257,7 @@ liftServer appEnv = handleErrors (Left (ValidationError msg)) = throwError $ err400 { errBody = BS.fromStrict $ encodeUtf8 msg } handleErrors (Left (NotFoundError msg)) = throwError $ err404 { errBody = BS.fromStrict $ encodeUtf8 msg } handleErrors (Left (CriticalError msg)) = throwError $ err500 { errBody = BS.fromStrict $ encodeUtf8 msg } - + handleErrors (Left (InternalError msg)) = throwError $ err500 { errBody = BS.fromStrict $ encodeUtf8 msg } -- * Swagger type SwaggerAPI = SwaggerSchemaUI "swagger-ui" "swagger.json" diff --git a/govtool/backend/example-config.json b/govtool/backend/example-config.json index 7d7d8ba41..756e75282 100644 --- a/govtool/backend/example-config.json +++ b/govtool/backend/example-config.json @@ -9,5 +9,7 @@ "port" : 9999, "host" : "localhost", "cachedurationseconds": 20, - "sentrydsn": "https://username:password@senty.host/id" + "sentrydsn": "https://username:password@senty.host/id", + "metadatavalidationhost": "localhost", + "metadatavalidationport": 3001 } diff --git a/govtool/backend/src/VVA/API.hs b/govtool/backend/src/VVA/API.hs index d982c61dd..d860fd391 100644 --- a/govtool/backend/src/VVA/API.hs +++ b/govtool/backend/src/VVA/API.hs @@ -11,7 +11,7 @@ module VVA.API where import Control.Exception (throw) import Control.Monad.Except (throwError) import Control.Monad.Reader - +import Data.Aeson (Result(Error, Success), fromJSON) import Data.Bool (Bool) import Data.List (sortOn) import qualified Data.Map as Map @@ -39,8 +39,9 @@ import qualified VVA.Proposal as Proposal import qualified VVA.Transaction as Transaction import qualified VVA.Types as Types import VVA.Types (App, AppEnv (..), - AppError (CriticalError, ValidationError), + AppError (CriticalError, ValidationError, InternalError), CacheEnv (..)) +import qualified VVA.Metadata as Metadata type VVAApi = "drep" :> "list" @@ -73,6 +74,7 @@ type VVAApi = :<|> "transaction" :> "status" :> Capture "transactionId" HexText :> Get '[JSON] GetTransactionStatusResponse :<|> "throw500" :> Get '[JSON] () :<|> "network" :> "metrics" :> Get '[JSON] GetNetworkMetricsResponse + :<|> "metadata" :> "validate" :> ReqBody '[JSON] MetadataValidationParams :> Post '[JSON] MetadataValidationResponse server :: App m => ServerT VVAApi m server = drepList @@ -87,6 +89,7 @@ server = drepList :<|> getTransactionStatus :<|> throw500 :<|> getNetworkMetrics + :<|> validateMetadata mapDRepType :: Types.DRepType -> DRepType @@ -174,8 +177,8 @@ getVotingPower (unHexText -> dRepId) = do cacheRequest dRepVotingPowerCache dRepId $ DRep.getVotingPower dRepId -proposalToResponse :: Types.Proposal -> ProposalResponse -proposalToResponse Types.Proposal {..} = +proposalToResponse :: Types.Proposal -> MetadataValidationResponse -> ProposalResponse +proposalToResponse Types.Proposal {..} metadataValidationResponse = ProposalResponse { proposalResponseId = pack $ show proposalId, proposalResponseTxHash = HexText proposalTxHash, @@ -196,7 +199,8 @@ proposalToResponse Types.Proposal {..} = proposalResponseReferences = GovernanceActionReferences <$> proposalReferences, proposalResponseYesVotes = proposalYesVotes, proposalResponseNoVotes = proposalNoVotes, - proposalResponseAbstainVotes = proposalAbstainVotes + proposalResponseAbstainVotes = proposalAbstainVotes, + proposalResponseMetadataStatus = Just metadataValidationResponse } voteToResponse :: Types.Vote -> VoteParams @@ -214,16 +218,17 @@ voteToResponse Types.Vote {..} = mapSortAndFilterProposals - :: [GovernanceActionType] + :: App m + => [GovernanceActionType] -> Maybe GovernanceActionSortMode -> [Types.Proposal] - -> [ProposalResponse] -mapSortAndFilterProposals selectedTypes sortMode proposals = - let mappedProposals = - map - proposalToResponse + -> m [ProposalResponse] +mapSortAndFilterProposals selectedTypes sortMode proposals = do + mappedProposals <- + mapM + (\proposal@Types.Proposal {proposalUrl, proposalDocHash} -> proposalToResponse proposal <$> validateMetadata (MetadataValidationParams proposalUrl $ HexText proposalDocHash)) proposals - filteredProposals = + let filteredProposals = if null selectedTypes then mappedProposals else @@ -232,19 +237,19 @@ mapSortAndFilterProposals selectedTypes sortMode proposals = proposalResponseType `elem` selectedTypes ) mappedProposals - sortedProposals = case sortMode of + let sortedProposals = case sortMode of Nothing -> filteredProposals Just NewestCreated -> sortOn (Down . proposalResponseCreatedDate) filteredProposals Just SoonestToExpire -> sortOn proposalResponseExpiryDate filteredProposals Just MostYesVotes -> sortOn (Down . proposalResponseYesVotes) filteredProposals - in sortedProposals + return sortedProposals getVotes :: App m => HexText -> [GovernanceActionType] -> Maybe GovernanceActionSortMode -> Maybe Text -> m [VoteResponse] getVotes (unHexText -> dRepId) selectedTypes sortMode mSearch = do CacheEnv {dRepGetVotesCache} <- asks vvaCache (votes, proposals) <- cacheRequest dRepGetVotesCache dRepId $ DRep.getVotes dRepId [] let voteMap = Map.fromList $ map (\vote@Types.Vote {..} -> (voteProposalId, vote)) votes - let processedProposals = filter (isProposalSearchedFor mSearch) $ mapSortAndFilterProposals selectedTypes sortMode proposals + processedProposals <- filter (isProposalSearchedFor mSearch) <$> mapSortAndFilterProposals selectedTypes sortMode proposals return $ [ VoteResponse { voteResponseVote = voteToResponse (voteMap Map.! read (unpack proposalResponseId)) @@ -321,12 +326,14 @@ listProposals selectedTypes sortMode mPage mPageSize mDrepRaw mSearchQuery = do CacheEnv {proposalListCache} <- asks vvaCache - mappedAndSortedProposals <- - filter + mappedAndSortedProposals <- do + proposals <- cacheRequest proposalListCache () Proposal.listProposals + mappedSortedAndFilteredProposals <- mapSortAndFilterProposals selectedTypes sortMode proposals + return $ filter ( \p@ProposalResponse {proposalResponseId} -> proposalResponseId `notElem` proposalsToRemove && isProposalSearchedFor mSearchQuery p - ) . mapSortAndFilterProposals selectedTypes sortMode <$> cacheRequest proposalListCache () Proposal.listProposals + ) mappedSortedAndFilteredProposals let total = length mappedAndSortedProposals :: Int @@ -343,7 +350,9 @@ getProposal :: App m => GovActionId -> Maybe HexText -> m GetProposalResponse getProposal g@(GovActionId govActionTxHash govActionIndex) mDrepId' = do let mDrepId = unHexText <$> mDrepId' CacheEnv {getProposalCache} <- asks vvaCache - proposalResponse <- proposalToResponse <$> cacheRequest getProposalCache (unHexText govActionTxHash, govActionIndex) (Proposal.getProposal (unHexText govActionTxHash) govActionIndex) + proposal@Types.Proposal {proposalUrl, proposalDocHash} <- cacheRequest getProposalCache (unHexText govActionTxHash, govActionIndex) (Proposal.getProposal (unHexText govActionTxHash) govActionIndex) + metadataStatus <- validateMetadata $ MetadataValidationParams proposalUrl $ HexText proposalDocHash + let proposalResponse = proposalToResponse proposal metadataStatus voteResponse <- case mDrepId of Nothing -> return Nothing Just drepId -> do @@ -390,3 +399,13 @@ getNetworkMetrics = do , getNetworkMetricsResponseAlwaysAbstainVotingPower = networkMetricsAlwaysAbstainVotingPower , getNetworkMetricsResponseAlwaysNoConfidenceVotingPower = networkMetricsAlwaysNoConfidenceVotingPower } + +validateMetadata :: App m => MetadataValidationParams -> m MetadataValidationResponse +validateMetadata MetadataValidationParams {..} = do + CacheEnv {metadataValidationCache} <- asks vvaCache + result <- cacheRequest metadataValidationCache (metadataValidationParamsUrl, unHexText metadataValidationParamsHash) + $ Metadata.validateMetadata metadataValidationParamsUrl (unHexText metadataValidationParamsHash) + + case fromJSON result of + Error e -> throwError $ InternalError $ pack $ show e + Success a -> return a diff --git a/govtool/backend/src/VVA/API/Types.hs b/govtool/backend/src/VVA/API/Types.hs index e911afa35..6eebd5d7c 100644 --- a/govtool/backend/src/VVA/API/Types.hs +++ b/govtool/backend/src/VVA/API/Types.hs @@ -90,6 +90,102 @@ instance ToSchema HexText where & schema . format ?~ "hex" & schema . example ?~ toJSON (HexText "a1b2c3") +newtype AnyValue + = AnyValue { unAnyValue :: Maybe Value } + deriving newtype (Show) + +instance FromJSON AnyValue where + parseJSON = pure . AnyValue . Just + +instance ToJSON AnyValue where + toJSON (AnyValue Nothing) = Null + toJSON (AnyValue (Just params)) = toJSON params + +exampleAnyValue :: Text +exampleAnyValue = + "{ \"any\": \"value\"}" + +instance ToSchema AnyValue where + declareNamedSchema _ = pure $ NamedSchema (Just "AnyValue") $ mempty + & type_ ?~ OpenApiObject + & description ?~ "Any value" + & example + ?~ toJSON exampleAnyValue + +data MetadataValidationStatus + = IncorrectFormat + | IncorrectJSONLD + | IncorrectHash + | UrlNotFound + deriving (Show, Eq) + +instance ToJSON MetadataValidationStatus where + toJSON IncorrectFormat = "INCORRECT_FORMTAT" + toJSON IncorrectJSONLD = "INVALID_JSONLD" + toJSON IncorrectHash = "INVALID_HASH" + toJSON UrlNotFound = "URL_NOT_FOUND" + +instance FromJSON MetadataValidationStatus where + parseJSON (String s) = case s of + "INCORRECT_FORMTAT" -> pure IncorrectFormat + "INVALID_JSONLD" -> pure IncorrectJSONLD + "INVALID_HASH" -> pure IncorrectHash + "URL_NOT_FOUND" -> pure UrlNotFound + _ -> fail "Invalid MetadataValidationStatus" + parseJSON _ = fail "Invalid MetadataValidationStatus" + +instance ToSchema MetadataValidationStatus where + declareNamedSchema _ = pure $ NamedSchema (Just "MetadataValidationStatus") $ mempty + & type_ ?~ OpenApiString + & description ?~ "Metadata Validation Status" + & enum_ ?~ map toJSON [IncorrectFormat, IncorrectJSONLD, IncorrectHash, UrlNotFound] + +data MetadataValidationResponse + = MetadataValidationResponse + { metadataValidationResponseStatus :: Maybe MetadataValidationStatus + , metadataValidationResponseValid :: Bool + } + deriving (Generic, Show) + +deriveJSON (jsonOptions "metadataValidationResponse") ''MetadataValidationResponse + +instance ToSchema MetadataValidationResponse where + declareNamedSchema _ = do + NamedSchema name_ schema_ <- + genericDeclareNamedSchema + ( fromAesonOptions $ jsonOptions "metadataValidationResponse" ) + (Proxy :: Proxy MetadataValidationResponse) + return $ + NamedSchema name_ $ + schema_ + & description ?~ "Metadata Validation Response" + & example + ?~ toJSON ("{\"status\": \"INCORRECT_FORMTAT\", \"valid\":false}" :: Text) + +data MetadataValidationParams + = MetadataValidationParams + { metadataValidationParamsUrl :: Text + , metadataValidationParamsHash :: HexText + } + deriving (Generic, Show) + +deriveJSON (jsonOptions "metadataValidationParams") ''MetadataValidationParams + +instance ToSchema MetadataValidationParams where + declareNamedSchema proxy = do + NamedSchema name_ schema_ <- + genericDeclareNamedSchema + ( fromAesonOptions $ jsonOptions "metadataValidationParams" ) + proxy + return $ + NamedSchema name_ $ + schema_ + & description ?~ "Metadata Validation Params" + & example + ?~ toJSON ("{\"url\": \"https://metadata.xyz\", \"hash\": \"9af10e89979e51b8cdc827c963124a1ef4920d1253eef34a1d5cfe76438e3f11\"}" :: Text) + + + data GovActionId = GovActionId { govActionIdTxHash :: HexText @@ -349,6 +445,7 @@ data ProposalResponse , proposalResponseYesVotes :: Integer , proposalResponseNoVotes :: Integer , proposalResponseAbstainVotes :: Integer + , proposalResponseMetadataStatus :: Maybe MetadataValidationResponse } deriving (Generic, Show) @@ -374,7 +471,8 @@ exampleProposalResponse = "{ \"id\": \"proposalId123\"," <> "\"references\": [{\"uri\": \"google.com\", \"@type\": \"Other\", \"label\": \"example label\"}]," <> "\"yesVotes\": 0," <> "\"noVotes\": 0," - <> "\"abstainVotes\": 0}" + <> "\"abstainVotes\": 0" + <> "\"metadataStatus\": {\"status\": null, \"valid\": true}}" instance ToSchema ProposalResponse where declareNamedSchema proxy = do @@ -841,3 +939,4 @@ instance ToSchema GetNetworkMetricsResponse where & description ?~ "GetNetworkMetricsResponse" & example ?~ toJSON exampleGetNetworkMetricsResponse + diff --git a/govtool/backend/src/VVA/Config.hs b/govtool/backend/src/VVA/Config.hs index 7055c33ed..c4781681f 100644 --- a/govtool/backend/src/VVA/Config.hs +++ b/govtool/backend/src/VVA/Config.hs @@ -24,6 +24,8 @@ module VVA.Config , getServerHost , getServerPort , vvaConfigToText + , getMetadataValidationHost + , getMetadataValidationPort ) where import Conferer @@ -69,15 +71,19 @@ instance DefaultConfig DBConfig where data VVAConfigInternal = VVAConfigInternal { -- | db-sync database access. - vVAConfigInternalDbsyncconfig :: DBConfig + vVAConfigInternalDbsyncconfig :: DBConfig -- | Server port. - , vVAConfigInternalPort :: Int + , vVAConfigInternalPort :: Int -- | Server host. - , vVAConfigInternalHost :: Text + , vVAConfigInternalHost :: Text -- | Request cache duration - , vVaConfigInternalCacheDurationSeconds :: Int + , vVaConfigInternalCacheDurationSeconds :: Int -- | Sentry DSN - , vVAConfigInternalSentrydsn :: String + , vVAConfigInternalSentrydsn :: String + -- | Metadata validation service host + , vVAConfigInternalMetadataValidationHost :: Text + -- | Metadata validation service port + , vVAConfigInternalMetadataValidationPort :: Int } deriving (FromConfig, Generic, Show) @@ -88,7 +94,9 @@ instance DefaultConfig VVAConfigInternal where vVAConfigInternalPort = 3000, vVAConfigInternalHost = "localhost", vVaConfigInternalCacheDurationSeconds = 20, - vVAConfigInternalSentrydsn = "https://username:password@senty.host/id" + vVAConfigInternalSentrydsn = "https://username:password@senty.host/id", + vVAConfigInternalMetadataValidationHost = "localhost", + vVAConfigInternalMetadataValidationPort = 3001 } -- | DEX configuration. @@ -104,6 +112,10 @@ data VVAConfig , cacheDurationSeconds :: Int -- | Sentry DSN , sentryDSN :: String + -- | Metadata validation service host + , metadataValidationHost :: Text + -- | Metadata validation service port + , metadataValidationPort :: Int } deriving (Generic, Show, ToJSON) @@ -143,7 +155,9 @@ convertConfig VVAConfigInternal {..} = serverPort = vVAConfigInternalPort, serverHost = vVAConfigInternalHost, cacheDurationSeconds = vVaConfigInternalCacheDurationSeconds, - sentryDSN = vVAConfigInternalSentrydsn + sentryDSN = vVAConfigInternalSentrydsn, + metadataValidationHost = vVAConfigInternalMetadataValidationHost, + metadataValidationPort = vVAConfigInternalMetadataValidationPort } -- | Load configuration from a file specified on the command line. Load from @@ -181,3 +195,15 @@ getServerHost :: (Has VVAConfig r, MonadReader r m) => m Text getServerHost = asks (serverHost . getter) + +-- | Access MetadataValidationService host +getMetadataValidationHost :: + (Has VVAConfig r, MonadReader r m) => + m Text +getMetadataValidationHost = asks (metadataValidationHost . getter) + +-- | Access MetadataValidationService port +getMetadataValidationPort :: + (Has VVAConfig r, MonadReader r m) => + m Int +getMetadataValidationPort = asks (metadataValidationPort . getter) diff --git a/govtool/backend/src/VVA/Metadata.hs b/govtool/backend/src/VVA/Metadata.hs new file mode 100644 index 000000000..d6033633f --- /dev/null +++ b/govtool/backend/src/VVA/Metadata.hs @@ -0,0 +1,45 @@ +{-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE OverloadedStrings #-} + +module VVA.Metadata where + +import Control.Monad.Except (MonadError, throwError) +import Control.Monad.Reader + +import Data.Aeson (Value, decode, encode, object, (.=)) +import Data.Maybe (fromJust) +import Data.ByteString (ByteString) +import Data.FileEmbed (embedFile) +import Data.Has (Has, getter) +import Data.String (fromString) +import Data.Text (Text, unpack) +import qualified Data.Text.Encoding as Text +import Data.Time.Clock + +import qualified Database.PostgreSQL.Simple as SQL + +import VVA.Config +import VVA.Pool (ConnectionPool, withPool) +import VVA.Types +import Network.HTTP.Client +import Network.HTTP.Client.TLS +import Data.Aeson (encode, object, (.=)) + +validateMetadata + :: (Has VVAConfig r, Has Manager r, MonadReader r m, MonadIO m, MonadError AppError m) + => Text + -> Text + -> m Value +validateMetadata url hash = do + metadataHost <- getMetadataValidationHost + metadataPort <- getMetadataValidationPort + manager <- asks getter + let requestBody = encode $ object ["url" .= unpack url, "hash" .= unpack hash] + initialRequest <- liftIO $ parseRequest (unpack metadataHost <> ":" <> show metadataPort <> "/validate") + let request = initialRequest + { method = "POST" + , requestBody = RequestBodyLBS requestBody + , requestHeaders = [("Content-Type", "application/json")] + } + response <- liftIO $ httpLbs request manager + return $ fromJust $ decode $ responseBody response diff --git a/govtool/backend/src/VVA/Types.hs b/govtool/backend/src/VVA/Types.hs index 7b128045c..fba1e2321 100644 --- a/govtool/backend/src/VVA/Types.hs +++ b/govtool/backend/src/VVA/Types.hs @@ -23,6 +23,7 @@ import Database.PostgreSQL.Simple (Connection) import VVA.Cache import VVA.Config +import Network.HTTP.Client (Manager) type App m = (MonadReader AppEnv m, MonadIO m, MonadFail m, MonadError AppError m) @@ -31,6 +32,7 @@ data AppEnv { vvaConfig :: VVAConfig , vvaCache :: CacheEnv , vvaConnectionPool :: Pool Connection + , vvaTlsManager :: Manager } instance Has VVAConfig AppEnv where @@ -45,10 +47,15 @@ instance Has (Pool Connection) AppEnv where getter AppEnv {vvaConnectionPool} = vvaConnectionPool modifier f a@AppEnv {vvaConnectionPool} = a {vvaConnectionPool = f vvaConnectionPool} +instance Has Manager AppEnv where + getter AppEnv {vvaTlsManager} = vvaTlsManager + modifier f a@AppEnv {vvaTlsManager} = a {vvaTlsManager = f vvaTlsManager} + data AppError = ValidationError Text | NotFoundError Text | CriticalError Text + | InternalError Text deriving (Show) instance Exception AppError @@ -138,6 +145,7 @@ data CacheEnv , dRepVotingPowerCache :: Cache.Cache Text Integer , dRepListCache :: Cache.Cache () [DRepRegistration] , networkMetricsCache :: Cache.Cache () NetworkMetrics + , metadataValidationCache :: Cache.Cache (Text, Text) Value } data NetworkMetrics @@ -159,4 +167,11 @@ data Delegation { delegationDRepHash :: Maybe Text , delegationDRepView :: Text , delegationTxHash :: Text - } \ No newline at end of file + } + + +data MetadataValidationStatus + = IncorrectFormat + | IncorrectJSONLD + | IncorrectHash + | UrlNotFound \ No newline at end of file diff --git a/govtool/backend/vva-be.cabal b/govtool/backend/vva-be.cabal index ccd247dc4..be278ec8f 100644 --- a/govtool/backend/vva-be.cabal +++ b/govtool/backend/vva-be.cabal @@ -98,7 +98,8 @@ library , data-has , resource-pool , swagger2 - + , http-client + , http-client-tls exposed-modules: VVA.Config , VVA.CommandLine @@ -114,3 +115,4 @@ library , VVA.Pool , VVA.Types , VVA.Network + , VVA.Metadata diff --git a/govtool/metadata-validation/src/main.ts b/govtool/metadata-validation/src/main.ts index c27be2ac4..7ab38cb38 100644 --- a/govtool/metadata-validation/src/main.ts +++ b/govtool/metadata-validation/src/main.ts @@ -5,7 +5,7 @@ import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger'; import { AppModule } from './app.module'; async function bootstrap() { - const app = await NestFactory.create(AppModule); + const app = await NestFactory.create(AppModule, { cors: true }); const config = new DocumentBuilder() .setTitle('Submission Tool') From 0277fa1cceb9397d1398685e5226cdf940270297 Mon Sep 17 00:00:00 2001 From: Sudip Bhattarai Date: Wed, 8 May 2024 16:30:06 +0545 Subject: [PATCH 060/125] Add debug log --- .github/workflows/build-and-deploy-test.yml | 7 ++++--- tests/test-infrastructure/build-and-deploy.sh | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build-and-deploy-test.yml b/.github/workflows/build-and-deploy-test.yml index 755e615c1..c1b99afe3 100644 --- a/.github/workflows/build-and-deploy-test.yml +++ b/.github/workflows/build-and-deploy-test.yml @@ -14,9 +14,6 @@ jobs: deploy: name: Deploy app runs-on: ubuntu-latest - defaults: - run: - working-directory: ./tests/test-infrastructure env: DOCKER_HOST: ssh://ec2-user@${{secrets.TEST_STACK_SERVER_IP }} GRAFANA_ADMIN_PASSWORD: ${{ secrets.GRAFANA_ADMIN_PASSWORD }} @@ -40,5 +37,9 @@ jobs: ssh-private-key: ${{ secrets.TEST_STACK_SSH_KEY }} - name: Update images + working-directory: "./tests/test-infrastructure" run: | + pwd + ls + set +x ./build-and-deploy.sh update-images diff --git a/tests/test-infrastructure/build-and-deploy.sh b/tests/test-infrastructure/build-and-deploy.sh index 8c5c1568f..30e6cd66a 100755 --- a/tests/test-infrastructure/build-and-deploy.sh +++ b/tests/test-infrastructure/build-and-deploy.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash BASE_IMAGE_NAME=govtool export GOVTOOL_TAG="$(git rev-parse HEAD)" From e9b6786f2809b58cf556739e0210939e4953fadf Mon Sep 17 00:00:00 2001 From: Jan Jaroszczak Date: Wed, 8 May 2024 12:52:52 +0200 Subject: [PATCH 061/125] [#920 - bug 2] Fix after CR --- .../src/components/organisms/DRepCard.tsx | 1 + .../DashboardCards/DRepDashboardCard.tsx | 5 ++- .../DashboardCards/DelegateDashboardCard.tsx | 1 + govtool/frontend/src/i18n/locales/en.ts | 1 + govtool/frontend/src/pages/DRepDetails.tsx | 36 ++++++++++++++----- 5 files changed, 35 insertions(+), 9 deletions(-) diff --git a/govtool/frontend/src/components/organisms/DRepCard.tsx b/govtool/frontend/src/components/organisms/DRepCard.tsx index 95ab2581f..dd3db318b 100644 --- a/govtool/frontend/src/components/organisms/DRepCard.tsx +++ b/govtool/frontend/src/components/organisms/DRepCard.tsx @@ -168,6 +168,7 @@ export const DRepCard = ({ ? PATHS.dashboardDRepDirectoryDRep : PATHS.dRepDirectoryDRep ).replace(":dRepId", view), + { state: { enteredFromWithinApp: true } }, ) } > diff --git a/govtool/frontend/src/components/organisms/DashboardCards/DRepDashboardCard.tsx b/govtool/frontend/src/components/organisms/DashboardCards/DRepDashboardCard.tsx index 65c9fd22b..0ac90b61f 100644 --- a/govtool/frontend/src/components/organisms/DashboardCards/DRepDashboardCard.tsx +++ b/govtool/frontend/src/components/organisms/DashboardCards/DRepDashboardCard.tsx @@ -42,7 +42,10 @@ export const DRepDashboardCard = ({ }; const navigateToDrepDirectory = () => - navigate(PATHS.dashboardDRepDirectoryDRep.replace(":dRepId", dRepIDBech32)); + navigate( + PATHS.dashboardDRepDirectoryDRep.replace(":dRepId", dRepIDBech32), + { state: { enteredFromWithinApp: true } }, + ); const cardProps: Partial = (() => { // transaction in progress diff --git a/govtool/frontend/src/components/organisms/DashboardCards/DelegateDashboardCard.tsx b/govtool/frontend/src/components/organisms/DashboardCards/DelegateDashboardCard.tsx index f11f76dca..f399b2740 100644 --- a/govtool/frontend/src/components/organisms/DashboardCards/DelegateDashboardCard.tsx +++ b/govtool/frontend/src/components/organisms/DashboardCards/DelegateDashboardCard.tsx @@ -104,6 +104,7 @@ export const DelegateDashboardCard = ({ ":dRepId", displayedDelegationId || "", ), + { state: { enteredFromWithinApp: true } }, ), [displayedDelegationId], ); diff --git a/govtool/frontend/src/i18n/locales/en.ts b/govtool/frontend/src/i18n/locales/en.ts index 4644a6b91..70a2cb72b 100644 --- a/govtool/frontend/src/i18n/locales/en.ts +++ b/govtool/frontend/src/i18n/locales/en.ts @@ -251,6 +251,7 @@ export const en = { editBtn: "Edit DRep data", delegationOptions: "Delegation Options", filterTitle: "DRep Status", + goToDRepDirectory: "Go to DRep Directory", meAsDRep: "This DRep ID is connected to your wallet", myDelegation: "You have delegated ₳ {{ada}} to:", myDRep: "This is your DRep", diff --git a/govtool/frontend/src/pages/DRepDetails.tsx b/govtool/frontend/src/pages/DRepDetails.tsx index 440e93750..a184ef66d 100644 --- a/govtool/frontend/src/pages/DRepDetails.tsx +++ b/govtool/frontend/src/pages/DRepDetails.tsx @@ -1,5 +1,10 @@ import { PropsWithChildren } from "react"; -import { Navigate, useNavigate, useParams } from "react-router-dom"; +import { + Navigate, + useLocation, + useNavigate, + useParams, +} from "react-router-dom"; import { Box, ButtonBase, Chip, CircularProgress } from "@mui/material"; import { Button, StatusPill, Typography } from "@atoms"; @@ -35,12 +40,14 @@ export const DRepDetails = ({ isConnected }: DRepDetailsProps) => { const { dRepID: myDRepId, pendingTransaction } = useCardano(); const { t } = useTranslation(); const navigate = useNavigate(); + const location = useLocation(); const { openModal } = useModal(); const { screenWidth } = useScreenDimension(); const { dRepId: dRepParam } = useParams(); - const { delegate, isDelegating } = useDelegateTodRep(); + const displayBackButton = location.state?.enteredFromWithinApp || false; + const { dRepData, isDRepListLoading } = useGetDRepListInfiniteQuery({ searchPhrase: dRepParam, }); @@ -74,12 +81,25 @@ export const DRepDetails = ({ isConnected }: DRepDetailsProps) => { return ( <> - navigate(-1)} - sx={{ mb: 2 }} - /> + {displayBackButton ? ( + navigate(-1)} + sx={{ mb: 2 }} + /> + ) : ( + + navigate( + isConnected ? PATHS.dashboardDRepDirectory : PATHS.dRepDirectory, + ) + } + sx={{ mb: 2 }} + /> + )} Date: Wed, 8 May 2024 16:33:56 +0545 Subject: [PATCH 062/125] Add set -x command --- .github/workflows/build-and-deploy-test.yml | 2 +- tests/test-infrastructure/build-and-deploy.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-and-deploy-test.yml b/.github/workflows/build-and-deploy-test.yml index c1b99afe3..a2c7f6e55 100644 --- a/.github/workflows/build-and-deploy-test.yml +++ b/.github/workflows/build-and-deploy-test.yml @@ -41,5 +41,5 @@ jobs: run: | pwd ls - set +x + set -x; ./build-and-deploy.sh update-images diff --git a/tests/test-infrastructure/build-and-deploy.sh b/tests/test-infrastructure/build-and-deploy.sh index 30e6cd66a..f9fe96b88 100755 --- a/tests/test-infrastructure/build-and-deploy.sh +++ b/tests/test-infrastructure/build-and-deploy.sh @@ -1,5 +1,5 @@ #!/usr/bin/env bash - +set -vx; BASE_IMAGE_NAME=govtool export GOVTOOL_TAG="$(git rev-parse HEAD)" export PROJECT_NAME=govtool From d05fb439616d8e4bbb21c2b8fdf8ba57529a8994 Mon Sep 17 00:00:00 2001 From: Sudip Bhattarai Date: Wed, 8 May 2024 16:47:33 +0545 Subject: [PATCH 063/125] Add exit code --- tests/test-infrastructure/build-and-deploy.sh | 2 +- tests/test-infrastructure/build-images.sh | 2 +- tests/test-infrastructure/scripts/deploy-stack.sh | 5 +++-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/tests/test-infrastructure/build-and-deploy.sh b/tests/test-infrastructure/build-and-deploy.sh index f9fe96b88..43a0faf1f 100755 --- a/tests/test-infrastructure/build-and-deploy.sh +++ b/tests/test-infrastructure/build-and-deploy.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash set -vx; -BASE_IMAGE_NAME=govtool +export BASE_IMAGE_NAME=govtool export GOVTOOL_TAG="$(git rev-parse HEAD)" export PROJECT_NAME=govtool export CARDANO_NETWORK=sanchonet diff --git a/tests/test-infrastructure/build-images.sh b/tests/test-infrastructure/build-images.sh index b74a8721d..b471ba6fe 100755 --- a/tests/test-infrastructure/build-images.sh +++ b/tests/test-infrastructure/build-images.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash set -e export BASE_IMAGE_NAME="govtool" BASE_IMAGE_EXISTS=$(docker images -q "$BASE_IMAGE_NAME"/backend-base 2> /dev/null) diff --git a/tests/test-infrastructure/scripts/deploy-stack.sh b/tests/test-infrastructure/scripts/deploy-stack.sh index 0e53de421..38920f07e 100755 --- a/tests/test-infrastructure/scripts/deploy-stack.sh +++ b/tests/test-infrastructure/scripts/deploy-stack.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash ## Docker swarm doesn't read .env file. ## This script reads env file and variables ## and apply them to compose file and @@ -47,7 +47,8 @@ function check_env(){ for key in "${unset_keys[@]}"; do echo "- $key" done - exit 1 + echo " Exiting due to missing env variables" + exit 2 fi } function deploy-stack(){ From ca66de011ff6b5743f6b9923f2a5eda86ab67b8f Mon Sep 17 00:00:00 2001 From: Sudip Bhattarai Date: Wed, 8 May 2024 16:49:43 +0545 Subject: [PATCH 064/125] Add debug log on build-images --- tests/test-infrastructure/build-images.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/test-infrastructure/build-images.sh b/tests/test-infrastructure/build-images.sh index b471ba6fe..3621fddcc 100755 --- a/tests/test-infrastructure/build-images.sh +++ b/tests/test-infrastructure/build-images.sh @@ -1,5 +1,6 @@ #!/usr/bin/env bash set -e +set -vx; export BASE_IMAGE_NAME="govtool" BASE_IMAGE_EXISTS=$(docker images -q "$BASE_IMAGE_NAME"/backend-base 2> /dev/null) From b5fd880b172af9ea053aaf4d5e0958d106e70a58 Mon Sep 17 00:00:00 2001 From: Sudip Bhattarai Date: Wed, 8 May 2024 16:51:57 +0545 Subject: [PATCH 065/125] Remove pipe to /dev/null --- tests/test-infrastructure/build-images.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test-infrastructure/build-images.sh b/tests/test-infrastructure/build-images.sh index 3621fddcc..4a8b19e17 100755 --- a/tests/test-infrastructure/build-images.sh +++ b/tests/test-infrastructure/build-images.sh @@ -2,7 +2,7 @@ set -e set -vx; export BASE_IMAGE_NAME="govtool" -BASE_IMAGE_EXISTS=$(docker images -q "$BASE_IMAGE_NAME"/backend-base 2> /dev/null) +BASE_IMAGE_EXISTS=$(docker images -q "$BASE_IMAGE_NAME"/backend-base) if [ -z "$BASE_IMAGE_EXISTS" ]; then echo "Building the base image..." From 42088b6ce7cc5c3cb1310da519b12e0197b264cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Sza=C5=82owski?= Date: Tue, 7 May 2024 20:35:18 +0200 Subject: [PATCH 066/125] feat(942): create govtool metadata submission service --- govtool/packages/submission-tool/.gitignore | 2 + govtool/packages/submission-tool/README.md | 70 + .../packages/submission-tool/babel.config.js | 6 + govtool/packages/submission-tool/index.ts | 1 + .../packages/submission-tool/jest.config.js | 21 + .../packages/submission-tool/jest.setup.js | 5 + govtool/packages/submission-tool/package.json | 30 + .../submission-tool/src/consts/context.ts | 49 + .../submission-tool/src/consts/index.ts | 1 + govtool/packages/submission-tool/src/index.ts | 4 + .../src/providers/MetadataProvider.test.tsx | 42 + .../src/providers/MetadataProvider.tsx | 65 + .../submission-tool/src/schemas/cipSchemas.ts | 14 + .../submission-tool/src/schemas/index.ts | 1 + .../src/services/MetadataService.test.ts | 53 + .../src/services/MetadataService.ts | 142 + .../submission-tool/src/services/index.ts | 1 + .../submission-tool/src/types/index.ts | 23 + .../packages/submission-tool/tsconfig.json | 23 + govtool/packages/submission-tool/yarn.lock | 3701 +++++++++++++++++ 20 files changed, 4254 insertions(+) create mode 100644 govtool/packages/submission-tool/.gitignore create mode 100644 govtool/packages/submission-tool/README.md create mode 100644 govtool/packages/submission-tool/babel.config.js create mode 100644 govtool/packages/submission-tool/index.ts create mode 100644 govtool/packages/submission-tool/jest.config.js create mode 100644 govtool/packages/submission-tool/jest.setup.js create mode 100644 govtool/packages/submission-tool/package.json create mode 100644 govtool/packages/submission-tool/src/consts/context.ts create mode 100644 govtool/packages/submission-tool/src/consts/index.ts create mode 100644 govtool/packages/submission-tool/src/index.ts create mode 100644 govtool/packages/submission-tool/src/providers/MetadataProvider.test.tsx create mode 100644 govtool/packages/submission-tool/src/providers/MetadataProvider.tsx create mode 100644 govtool/packages/submission-tool/src/schemas/cipSchemas.ts create mode 100644 govtool/packages/submission-tool/src/schemas/index.ts create mode 100644 govtool/packages/submission-tool/src/services/MetadataService.test.ts create mode 100644 govtool/packages/submission-tool/src/services/MetadataService.ts create mode 100644 govtool/packages/submission-tool/src/services/index.ts create mode 100644 govtool/packages/submission-tool/src/types/index.ts create mode 100644 govtool/packages/submission-tool/tsconfig.json create mode 100644 govtool/packages/submission-tool/yarn.lock diff --git a/govtool/packages/submission-tool/.gitignore b/govtool/packages/submission-tool/.gitignore new file mode 100644 index 000000000..7cafbdb49 --- /dev/null +++ b/govtool/packages/submission-tool/.gitignore @@ -0,0 +1,2 @@ +coverage +node_modules \ No newline at end of file diff --git a/govtool/packages/submission-tool/README.md b/govtool/packages/submission-tool/README.md new file mode 100644 index 000000000..1b042e17e --- /dev/null +++ b/govtool/packages/submission-tool/README.md @@ -0,0 +1,70 @@ +# Metadata Service Package + +🔍 This package provides a set of tools for managing metadata. It includes a `MetadataService` for handling metadata operations and a `MetadataProvider` for providing metadata context to React components. + +![Statements](https://img.shields.io/badge/statements-96.33%25-brightgreen.svg?style=flat) +![Branches](https://img.shields.io/badge/branches-80%25-yellow.svg?style=flat) +![Functions](https://img.shields.io/badge/functions-90.9%25-brightgreen.svg?style=flat) +![Lines](https://img.shields.io/badge/lines-96.33%25-brightgreen.svg?style=flat) + +## Getting started + +First, install the package in your project: + +```bash +yarn add metadata-service +``` + +### MetadataProvider + +Wrap your application in the `MetadataProvider`: + +```jsx +import { MetadataProvider } from "metadata-service"; + +function App() { + return ( + + + + ); +} +``` + +Now you can use the `useMetadata` hook to access metadata context in your components: + +```jsx +import { useMetadata } from "metadata-service"; + +function YourComponent() { + const metadata = useMetadata(); + + // Use the metadata here... + + return
{/* Your component's JSX... */}
; +} +``` + +### MetadataService + +You can also use the `MetadataService` directly to perform metadata operations: + +```jsx +import { MetadataService } from "metadata-service"; + +const metadataService = new MetadataService({ + cip: CIP_Reference["0108"], + hashAlgorithm: "blake2b-256", + body: { + title: "My title", + abstract: "My abstract", + motivation: "My motivation", + rationale: "My rationale", + references: [{ label: "some url", uri: "http://some.url" }], + }, +}); + +metadataService.initialize().then((service) => { + // ...use the service here +}); +``` diff --git a/govtool/packages/submission-tool/babel.config.js b/govtool/packages/submission-tool/babel.config.js new file mode 100644 index 000000000..95e596179 --- /dev/null +++ b/govtool/packages/submission-tool/babel.config.js @@ -0,0 +1,6 @@ +module.exports = { + presets: [ + "@babel/preset-env", // Include any other presets you may need + "@babel/preset-react", // Add @babel/preset-react + ], +}; diff --git a/govtool/packages/submission-tool/index.ts b/govtool/packages/submission-tool/index.ts new file mode 100644 index 000000000..3bd16e178 --- /dev/null +++ b/govtool/packages/submission-tool/index.ts @@ -0,0 +1 @@ +export * from "./src"; diff --git a/govtool/packages/submission-tool/jest.config.js b/govtool/packages/submission-tool/jest.config.js new file mode 100644 index 000000000..aceffb8b4 --- /dev/null +++ b/govtool/packages/submission-tool/jest.config.js @@ -0,0 +1,21 @@ +/** + * For a detailed explanation regarding each configuration property, visit: + * https://jestjs.io/docs/configuration + */ + +/** @type {import('jest').Config} */ +const config = { + clearMocks: true, + collectCoverage: true, + coverageDirectory: "coverage", + coverageProvider: "v8", + coverageReporters: ["json-summary"], + testEnvironment: "jsdom", + preset: "ts-jest", + setupFilesAfterEnv: ["/jest.setup.js"], + moduleNameMapper: { + "^@/(.*)$": "/src/$1", + }, +}; + +module.exports = config; diff --git a/govtool/packages/submission-tool/jest.setup.js b/govtool/packages/submission-tool/jest.setup.js new file mode 100644 index 000000000..4d94207b3 --- /dev/null +++ b/govtool/packages/submission-tool/jest.setup.js @@ -0,0 +1,5 @@ +require("@testing-library/jest-dom"); + +const { TextDecoder, TextEncoder } = require("text-encoding"); +global.TextDecoder = TextDecoder; +global.TextEncoder = TextEncoder; diff --git a/govtool/packages/submission-tool/package.json b/govtool/packages/submission-tool/package.json new file mode 100644 index 000000000..94e737bdc --- /dev/null +++ b/govtool/packages/submission-tool/package.json @@ -0,0 +1,30 @@ +{ + "name": "submission-tool", + "packageManager": "yarn@3.6.4", + "scripts": { + "test": "jest" + }, + "dependencies": { + "blakejs": "^1.2.1", + "jsonld": "^8.3.2", + "react": "^18.3.1", + "react-dom": "^18.3.1", + "zod": "^3.23.6" + }, + "devDependencies": { + "@babel/preset-env": "^7.24.5", + "@babel/preset-react": "^7.24.1", + "@testing-library/dom": "^10.1.0", + "@testing-library/jest-dom": "^6.4.5", + "@testing-library/react": "^15.0.7", + "@types/jest": "^29.5.12", + "@types/jsonld": "^1.5.13", + "@types/react": "^18.3.1", + "@types/text-encoding": "^0.0.39", + "jest": "^29.7.0", + "jest-environment-jsdom": "^29.7.0", + "text-encoding": "^0.7.0", + "ts-jest": "^29.1.2", + "typescript": "^5.4.5" + } +} diff --git a/govtool/packages/submission-tool/src/consts/context.ts b/govtool/packages/submission-tool/src/consts/context.ts new file mode 100644 index 000000000..9e3110de9 --- /dev/null +++ b/govtool/packages/submission-tool/src/consts/context.ts @@ -0,0 +1,49 @@ +export const CIP_0108_CONTEXT = { + "@language": "en-us", + CIP100: + "https://github.com/cardano-foundation/CIPs/blob/master/CIP-0100/README.md#", + CIP108: + "https://github.com/cardano-foundation/CIPs/blob/master/CIP-0108/README.md#", + hashAlgorithm: "CIP100:hashAlgorithm", + body: { + "@id": "CIP108:body", + "@context": { + references: { + "@id": "CIP108:references", + "@container": "@set" as const, + "@context": { + GovernanceMetadata: "CIP100:GovernanceMetadataReference", + Other: "CIP100:OtherReference", + label: "CIP100:reference-label", + uri: "CIP100:reference-uri", + referenceHash: { + "@id": "CIP108:referenceHash", + "@context": { + hashDigest: "CIP108:hashDigest", + hashAlgorithm: "CIP100:hashAlgorithm", + }, + }, + }, + }, + title: "CIP108:title", + abstract: "CIP108:abstract", + motivation: "CIP108:motivation", + rationale: "CIP108:rationale", + }, + }, + authors: { + "@id": "CIP100:authors", + "@container": "@set" as const, + "@context": { + name: "http://xmlns.com/foaf/0.1/name", + witness: { + "@id": "CIP100:witness", + "@context": { + witnessAlgorithm: "CIP100:witnessAlgorithm", + publicKey: "CIP100:publicKey", + signature: "CIP100:signature", + }, + }, + }, + }, +}; diff --git a/govtool/packages/submission-tool/src/consts/index.ts b/govtool/packages/submission-tool/src/consts/index.ts new file mode 100644 index 000000000..2edd280c7 --- /dev/null +++ b/govtool/packages/submission-tool/src/consts/index.ts @@ -0,0 +1 @@ +export * from "./context"; diff --git a/govtool/packages/submission-tool/src/index.ts b/govtool/packages/submission-tool/src/index.ts new file mode 100644 index 000000000..9810623dd --- /dev/null +++ b/govtool/packages/submission-tool/src/index.ts @@ -0,0 +1,4 @@ +export * from "./consts"; +export * from "./schemas"; +export * from "./services"; +export * from "./types"; diff --git a/govtool/packages/submission-tool/src/providers/MetadataProvider.test.tsx b/govtool/packages/submission-tool/src/providers/MetadataProvider.test.tsx new file mode 100644 index 000000000..5395a2974 --- /dev/null +++ b/govtool/packages/submission-tool/src/providers/MetadataProvider.test.tsx @@ -0,0 +1,42 @@ +import { render, screen } from "@testing-library/react"; +import { MetadataProvider, useMetadata } from "@/providers/MetadataProvider"; + +describe("MetadataProvider", () => { + it("renders its children", () => { + render( + +
Child Component
+
+ ); + + const childComponent = screen.getByText("Child Component"); + expect(childComponent).toBeDefined(); + }); + + it("provides the validate and build functions in the context", () => { + const TestComponent = () => { + const { validate, build } = useMetadata(); + expect(typeof validate).toBe("function"); + expect(typeof build).toBe("function"); + + return null; + }; + + render( + + + + ); + }); + + it("throws an error when useMetadata is used outside of MetadataProvider", () => { + const TestComponent = () => { + useMetadata(); + return null; + }; + + expect(() => render()).toThrow( + "useMetadata must be used within a MetadataProvider" + ); + }); +}); diff --git a/govtool/packages/submission-tool/src/providers/MetadataProvider.tsx b/govtool/packages/submission-tool/src/providers/MetadataProvider.tsx new file mode 100644 index 000000000..0571c6eff --- /dev/null +++ b/govtool/packages/submission-tool/src/providers/MetadataProvider.tsx @@ -0,0 +1,65 @@ +import { + createContext, + useContext, + useMemo, + useCallback, + PropsWithChildren, +} from "react"; + +import { MetadataService } from "@/services"; +import { MetadataConfig } from "@/types"; + +type MetadataContextValues = { + validate: (data: MetadataConfig) => void; + build: (config: MetadataConfig) => Promise; +}; + +const MetadataContext = createContext(null); + +/** + * Provides metadata validation and building functionality to its children components. + * @param children - The child components to be wrapped by the MetadataProvider. + */ +export const MetadataProvider = ({ children }: PropsWithChildren) => { + /** + * Validates the metadata configuration. + * + * @param data - The metadata configuration to validate. + * @returns A promise that resolves to the validation result. + */ + const validate = useCallback( + (data: MetadataConfig) => new MetadataService(data).validateMetadata(), + [] + ); + + /** + * Builds the metadata using the provided configuration. + * @param config The configuration for building the metadata. + * @returns A promise that resolves to the built metadata. + */ + const build = useCallback( + (config: MetadataConfig) => new MetadataService(config).build(), + [] + ); + + const value = useMemo(() => ({ validate, build }), [validate, build]); + + return ( + + {children} + + ); +}; + +/** + * Custom hook that provides access to the metadata context. + * @returns The metadata context. + * @throws {Error} If used outside of a MetadataProvider. + */ +export const useMetadata = () => { + const context = useContext(MetadataContext); + if (!context) { + throw new Error("useMetadata must be used within a MetadataProvider"); + } + return context; +}; diff --git a/govtool/packages/submission-tool/src/schemas/cipSchemas.ts b/govtool/packages/submission-tool/src/schemas/cipSchemas.ts new file mode 100644 index 000000000..b706910a1 --- /dev/null +++ b/govtool/packages/submission-tool/src/schemas/cipSchemas.ts @@ -0,0 +1,14 @@ +import { z } from "zod"; + +export const CIP0108ValidationSchema = z.object({ + title: z.string().max(80), + abstract: z.string().max(2500), + motivation: z.string(), + rationale: z.string(), + references: z.array( + z.object({ + label: z.string(), + uri: z.string().url(), + }) + ), +}); diff --git a/govtool/packages/submission-tool/src/schemas/index.ts b/govtool/packages/submission-tool/src/schemas/index.ts new file mode 100644 index 000000000..5c7d7b564 --- /dev/null +++ b/govtool/packages/submission-tool/src/schemas/index.ts @@ -0,0 +1 @@ +export * from "./cipSchemas"; diff --git a/govtool/packages/submission-tool/src/services/MetadataService.test.ts b/govtool/packages/submission-tool/src/services/MetadataService.test.ts new file mode 100644 index 000000000..122a9d8c2 --- /dev/null +++ b/govtool/packages/submission-tool/src/services/MetadataService.test.ts @@ -0,0 +1,53 @@ +import { CIP_Reference } from ".."; +import { MetadataService } from "./MetadataService"; + +describe("MetadataService", () => { + it("should initialize jsonld and hash", async () => { + // Arrange + const metadataService = new MetadataService({ + cip: CIP_Reference["0108"], + hashAlgorithm: "blake2b-256", + body: { + title: "123", + abstract: "My abstract", + motivation: "My motivation", + rationale: "My rationale", + references: [{ label: "some url", uri: "http://some.url" }], + }, + }); + + // Act + await metadataService.initialize(); + const jsonld = metadataService.jsonld; + const hash = metadataService.hash; + + // Assert + expect(jsonld).toBeDefined(); + expect(jsonld).not.toBeNull(); + // TODO: Add structure assertions to the jsonld + + expect(hash).toBeDefined(); + expect(hash).not.toBeNull(); + }); + + it("should fail on body validation", async () => { + try { + new MetadataService({ + cip: CIP_Reference["0108"], + hashAlgorithm: "blake2b-256", + body: { + // For the testing purposes + // @ts-expect-error + title: 123, + abstract: "My abstract", + motivation: "My motivation", + rationale: "My rationale", + references: [{ label: "some url", uri: "http://some.url" }], + }, + }); + } catch (error) { + expect(error).toBeDefined(); + expect((error as any).message).toBe("Invalid metadata body"); + } + }); +}); diff --git a/govtool/packages/submission-tool/src/services/MetadataService.ts b/govtool/packages/submission-tool/src/services/MetadataService.ts new file mode 100644 index 000000000..67b853fac --- /dev/null +++ b/govtool/packages/submission-tool/src/services/MetadataService.ts @@ -0,0 +1,142 @@ +import * as jsonld from "jsonld"; +import { blake2bHex } from "blakejs"; + +import { CIP_0108_CONTEXT } from "@/consts"; +import { MetadataConfig, CIP_Reference } from "@/types"; +import { CIP0108ValidationSchema } from "@/schemas"; + +/** + * Represents a service for handling metadata. + */ +export class MetadataService { + public hash: string | null; + public jsonld: jsonld.NodeObject | null; + private cip: CIP_Reference; + private config: MetadataConfig; + + /** + * Constructs a new instance of the MetadataService class. + * @param config - The metadata configuration data. + */ + constructor(config: MetadataConfig) { + this.config = config; + this.hash = null; + this.jsonld = null; + this.cip = config.cip; + } + + /** + * Generates the metadata body based on the provided data. + * @returns The generated metadata body. + */ + private generateMetadataBody() { + const docBody = Object.entries(this.config.body).map(([key, value]) => [ + this.config.cip + key, + value, + ]); + + const references = this.config.body.references.map((reference) => ({ + "@type": "Other", + [`${this.config.cip}reference-label`]: reference.label, + [`${this.config.cip}reference-uri`]: reference.uri, + })); + + const body = Object.fromEntries(docBody); + + if (references) { + body[`${this.config.cip}references`] = references; + } + + return body; + } + + /** + * Generates the JSON-LD document based on the metadata configuration data. + * @param config - The metadata configuration data. + * @returns A promise that resolves to the MetadataService class. + */ + private async generateJsonld() { + const body = this.generateMetadataBody(); + const jsonLDDoc: jsonld.JsonLdDocument = { + [`${this.cip}body`]: body, + [`${CIP_Reference["0100"]}hashAlgorithm`]: this.config.hashAlgorithm, + [`${CIP_Reference["0100"]}authors`]: [], + }; + const context = this.getContext(); + + this.jsonld = await jsonld.compact(jsonLDDoc, context); + + return this; + } + + /** + * Gets the context based on the CIP version. + * @returns The context for the JSON-LD document. + */ + private getContext() { + switch (this.cip) { + case CIP_Reference["0108"]: + return CIP_0108_CONTEXT; + default: + return CIP_0108_CONTEXT; + } + } + + /** + * Generates the hash for the JSON-LD document. + * @returns A promise that resolves to the MetadataService class. + * @throws An error if the JSON-LD document is not generated. + */ + private async generateHash() { + if (!this.jsonld) { + throw new Error("JSON-LD document is not generated"); + } + + const canonizedJson = await jsonld.canonize(this.jsonld); + + this.hash = await blake2bHex(canonizedJson, undefined, 32); + + return this; + } + + /** + * Initializes the MetadataService. + * @returns A promise that resolves to a new instance of the MetadataService class. + */ + public async initialize() { + this.validateMetadata(); + + await this.generateJsonld(); + await this.generateHash(); + + return this; + } + + /** + * Validates the metadata based on the CIP version. + * @throws An error if the CIP version is invalid. + */ + public validateMetadata() { + // Only CIP 0108 is supported + if (this.config.cip !== CIP_Reference["0108"]) { + throw new Error("Invalid CIP version"); + } + + try { + CIP0108ValidationSchema.parse(this.config.body); + } catch (error) { + throw new Error("Invalid metadata body"); + } + } + + /** + * Builds the metadata service with the provided configuration. + * @param config The configuration for the metadata service. + * @returns A promise that resolves to the built metadata service. + */ + public async build() { + await this.initialize(); + + return this; + } +} diff --git a/govtool/packages/submission-tool/src/services/index.ts b/govtool/packages/submission-tool/src/services/index.ts new file mode 100644 index 000000000..d6326b873 --- /dev/null +++ b/govtool/packages/submission-tool/src/services/index.ts @@ -0,0 +1 @@ +export * from "./MetadataService"; diff --git a/govtool/packages/submission-tool/src/types/index.ts b/govtool/packages/submission-tool/src/types/index.ts new file mode 100644 index 000000000..43db25c20 --- /dev/null +++ b/govtool/packages/submission-tool/src/types/index.ts @@ -0,0 +1,23 @@ +export enum CIP_Reference { + "0100" = "https://github.com/cardano-foundation/CIPs/blob/master/CIP-0100/README.md#", + "0108" = "https://github.com/cardano-foundation/CIPs/blob/master/CIP-0108/README.md#", +} + +export type MetadataReference = { + label: string; + uri: string; +}; + +export type MetadataBody = { + title: string; + abstract: string; + motivation: string; + rationale: string; + references: MetadataReference[]; +}; + +export type MetadataConfig = { + cip: CIP_Reference; + body: MetadataBody; + hashAlgorithm: string; +}; diff --git a/govtool/packages/submission-tool/tsconfig.json b/govtool/packages/submission-tool/tsconfig.json new file mode 100644 index 000000000..fe86556c9 --- /dev/null +++ b/govtool/packages/submission-tool/tsconfig.json @@ -0,0 +1,23 @@ +{ + "compilerOptions": { + "lib": ["ESNext"], + "target": "ESNext", + "module": "CommonJS", + "esModuleInterop": true, + "resolveJsonModule": true, + "skipLibCheck": true, + "allowSyntheticDefaultImports": true, + "isolatedModules": true, + "jsx": "react-jsx", + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true, + "baseUrl": ".", + "paths": { + "@/*": ["./src/*"] + } + }, + "include": ["src/**/*"], + "exclude": ["node_modules", "build", "dist"] +} diff --git a/govtool/packages/submission-tool/yarn.lock b/govtool/packages/submission-tool/yarn.lock new file mode 100644 index 000000000..f2ea8606b --- /dev/null +++ b/govtool/packages/submission-tool/yarn.lock @@ -0,0 +1,3701 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@adobe/css-tools@^4.3.2": + version "4.3.3" + resolved "https://registry.yarnpkg.com/@adobe/css-tools/-/css-tools-4.3.3.tgz#90749bde8b89cd41764224f5aac29cd4138f75ff" + integrity sha512-rE0Pygv0sEZ4vBWHlAgJLGDU7Pm8xoO6p3wsEceb7GYAjScrOHpEo8KK/eVkAcnSM+slAEtXjA2JpdjLp4fJQQ== + +"@ampproject/remapping@^2.2.0": + version "2.3.0" + resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.3.0.tgz#ed441b6fa600072520ce18b43d2c8cc8caecc7f4" + integrity sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw== + dependencies: + "@jridgewell/gen-mapping" "^0.3.5" + "@jridgewell/trace-mapping" "^0.3.24" + +"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.10.4", "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.23.5", "@babel/code-frame@^7.24.2": + version "7.24.2" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.24.2.tgz#718b4b19841809a58b29b68cde80bc5e1aa6d9ae" + integrity sha512-y5+tLQyV8pg3fsiln67BVLD1P13Eg4lh5RW9mF0zUuvLrv9uIQ4MCL+CRT+FTsBlBjcIan6PGsLcBN0m3ClUyQ== + dependencies: + "@babel/highlight" "^7.24.2" + picocolors "^1.0.0" + +"@babel/compat-data@^7.22.6", "@babel/compat-data@^7.23.5", "@babel/compat-data@^7.24.4": + version "7.24.4" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.24.4.tgz#6f102372e9094f25d908ca0d34fc74c74606059a" + integrity sha512-vg8Gih2MLK+kOkHJp4gBEIkyaIi00jgWot2D9QOmmfLC8jINSOzmCLta6Bvz/JSBCqnegV0L80jhxkol5GWNfQ== + +"@babel/core@^7.11.6", "@babel/core@^7.12.3", "@babel/core@^7.23.9": + version "7.24.5" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.24.5.tgz#15ab5b98e101972d171aeef92ac70d8d6718f06a" + integrity sha512-tVQRucExLQ02Boi4vdPp49svNGcfL2GhdTCT9aldhXgCJVAI21EtRfBettiuLUwce/7r6bFdgs6JFkcdTiFttA== + dependencies: + "@ampproject/remapping" "^2.2.0" + "@babel/code-frame" "^7.24.2" + "@babel/generator" "^7.24.5" + "@babel/helper-compilation-targets" "^7.23.6" + "@babel/helper-module-transforms" "^7.24.5" + "@babel/helpers" "^7.24.5" + "@babel/parser" "^7.24.5" + "@babel/template" "^7.24.0" + "@babel/traverse" "^7.24.5" + "@babel/types" "^7.24.5" + convert-source-map "^2.0.0" + debug "^4.1.0" + gensync "^1.0.0-beta.2" + json5 "^2.2.3" + semver "^6.3.1" + +"@babel/generator@^7.24.5", "@babel/generator@^7.7.2": + version "7.24.5" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.24.5.tgz#e5afc068f932f05616b66713e28d0f04e99daeb3" + integrity sha512-x32i4hEXvr+iI0NEoEfDKzlemF8AmtOP8CcrRaEcpzysWuoEb1KknpcvMsHKPONoKZiDuItklgWhB18xEhr9PA== + dependencies: + "@babel/types" "^7.24.5" + "@jridgewell/gen-mapping" "^0.3.5" + "@jridgewell/trace-mapping" "^0.3.25" + jsesc "^2.5.1" + +"@babel/helper-annotate-as-pure@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.22.5.tgz#e7f06737b197d580a01edf75d97e2c8be99d3882" + integrity sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg== + dependencies: + "@babel/types" "^7.22.5" + +"@babel/helper-builder-binary-assignment-operator-visitor@^7.22.15": + version "7.22.15" + resolved "https://registry.yarnpkg.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.22.15.tgz#5426b109cf3ad47b91120f8328d8ab1be8b0b956" + integrity sha512-QkBXwGgaoC2GtGZRoma6kv7Szfv06khvhFav67ZExau2RaXzy8MpHSMO2PNoP2XtmQphJQRHFfg77Bq731Yizw== + dependencies: + "@babel/types" "^7.22.15" + +"@babel/helper-compilation-targets@^7.22.6", "@babel/helper-compilation-targets@^7.23.6": + version "7.23.6" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.23.6.tgz#4d79069b16cbcf1461289eccfbbd81501ae39991" + integrity sha512-9JB548GZoQVmzrFgp8o7KxdgkTGm6xs9DW0o/Pim72UDjzr5ObUQ6ZzYPqA+g9OTS2bBQoctLJrky0RDCAWRgQ== + dependencies: + "@babel/compat-data" "^7.23.5" + "@babel/helper-validator-option" "^7.23.5" + browserslist "^4.22.2" + lru-cache "^5.1.1" + semver "^6.3.1" + +"@babel/helper-create-class-features-plugin@^7.24.1", "@babel/helper-create-class-features-plugin@^7.24.4", "@babel/helper-create-class-features-plugin@^7.24.5": + version "7.24.5" + resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.24.5.tgz#7d19da92c7e0cd8d11c09af2ce1b8e7512a6e723" + integrity sha512-uRc4Cv8UQWnE4NXlYTIIdM7wfFkOqlFztcC/gVXDKohKoVB3OyonfelUBaJzSwpBntZ2KYGF/9S7asCHsXwW6g== + dependencies: + "@babel/helper-annotate-as-pure" "^7.22.5" + "@babel/helper-environment-visitor" "^7.22.20" + "@babel/helper-function-name" "^7.23.0" + "@babel/helper-member-expression-to-functions" "^7.24.5" + "@babel/helper-optimise-call-expression" "^7.22.5" + "@babel/helper-replace-supers" "^7.24.1" + "@babel/helper-skip-transparent-expression-wrappers" "^7.22.5" + "@babel/helper-split-export-declaration" "^7.24.5" + semver "^6.3.1" + +"@babel/helper-create-regexp-features-plugin@^7.18.6", "@babel/helper-create-regexp-features-plugin@^7.22.15", "@babel/helper-create-regexp-features-plugin@^7.22.5": + version "7.22.15" + resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.22.15.tgz#5ee90093914ea09639b01c711db0d6775e558be1" + integrity sha512-29FkPLFjn4TPEa3RE7GpW+qbE8tlsu3jntNYNfcGsc49LphF1PQIiD+vMZ1z1xVOKt+93khA9tc2JBs3kBjA7w== + dependencies: + "@babel/helper-annotate-as-pure" "^7.22.5" + regexpu-core "^5.3.1" + semver "^6.3.1" + +"@babel/helper-define-polyfill-provider@^0.6.1", "@babel/helper-define-polyfill-provider@^0.6.2": + version "0.6.2" + resolved "https://registry.yarnpkg.com/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.2.tgz#18594f789c3594acb24cfdb4a7f7b7d2e8bd912d" + integrity sha512-LV76g+C502biUK6AyZ3LK10vDpDyCzZnhZFXkH1L75zHPj68+qc8Zfpx2th+gzwA2MzyK+1g/3EPl62yFnVttQ== + dependencies: + "@babel/helper-compilation-targets" "^7.22.6" + "@babel/helper-plugin-utils" "^7.22.5" + debug "^4.1.1" + lodash.debounce "^4.0.8" + resolve "^1.14.2" + +"@babel/helper-environment-visitor@^7.22.20": + version "7.22.20" + resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz#96159db61d34a29dba454c959f5ae4a649ba9167" + integrity sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA== + +"@babel/helper-function-name@^7.23.0": + version "7.23.0" + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz#1f9a3cdbd5b2698a670c30d2735f9af95ed52759" + integrity sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw== + dependencies: + "@babel/template" "^7.22.15" + "@babel/types" "^7.23.0" + +"@babel/helper-hoist-variables@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz#c01a007dac05c085914e8fb652b339db50d823bb" + integrity sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw== + dependencies: + "@babel/types" "^7.22.5" + +"@babel/helper-member-expression-to-functions@^7.23.0", "@babel/helper-member-expression-to-functions@^7.24.5": + version "7.24.5" + resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.24.5.tgz#5981e131d5c7003c7d1fa1ad49e86c9b097ec475" + integrity sha512-4owRteeihKWKamtqg4JmWSsEZU445xpFRXPEwp44HbgbxdWlUV1b4Agg4lkA806Lil5XM/e+FJyS0vj5T6vmcA== + dependencies: + "@babel/types" "^7.24.5" + +"@babel/helper-module-imports@^7.22.15", "@babel/helper-module-imports@^7.24.1", "@babel/helper-module-imports@^7.24.3": + version "7.24.3" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.24.3.tgz#6ac476e6d168c7c23ff3ba3cf4f7841d46ac8128" + integrity sha512-viKb0F9f2s0BCS22QSF308z/+1YWKV/76mwt61NBzS5izMzDPwdq1pTrzf+Li3npBWX9KdQbkeCt1jSAM7lZqg== + dependencies: + "@babel/types" "^7.24.0" + +"@babel/helper-module-transforms@^7.23.3", "@babel/helper-module-transforms@^7.24.5": + version "7.24.5" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.24.5.tgz#ea6c5e33f7b262a0ae762fd5986355c45f54a545" + integrity sha512-9GxeY8c2d2mdQUP1Dye0ks3VDyIMS98kt/llQ2nUId8IsWqTF0l1LkSX0/uP7l7MCDrzXS009Hyhe2gzTiGW8A== + dependencies: + "@babel/helper-environment-visitor" "^7.22.20" + "@babel/helper-module-imports" "^7.24.3" + "@babel/helper-simple-access" "^7.24.5" + "@babel/helper-split-export-declaration" "^7.24.5" + "@babel/helper-validator-identifier" "^7.24.5" + +"@babel/helper-optimise-call-expression@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.22.5.tgz#f21531a9ccbff644fdd156b4077c16ff0c3f609e" + integrity sha512-HBwaojN0xFRx4yIvpwGqxiV2tUfl7401jlok564NgB9EHS1y6QT17FmKWm4ztqjeVdXLuC4fSvHc5ePpQjoTbw== + dependencies: + "@babel/types" "^7.22.5" + +"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.18.6", "@babel/helper-plugin-utils@^7.22.5", "@babel/helper-plugin-utils@^7.24.0", "@babel/helper-plugin-utils@^7.24.5", "@babel/helper-plugin-utils@^7.8.0", "@babel/helper-plugin-utils@^7.8.3": + version "7.24.5" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.5.tgz#a924607dd254a65695e5bd209b98b902b3b2f11a" + integrity sha512-xjNLDopRzW2o6ba0gKbkZq5YWEBaK3PCyTOY1K2P/O07LGMhMqlMXPxwN4S5/RhWuCobT8z0jrlKGlYmeR1OhQ== + +"@babel/helper-remap-async-to-generator@^7.22.20": + version "7.22.20" + resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.22.20.tgz#7b68e1cb4fa964d2996fd063723fb48eca8498e0" + integrity sha512-pBGyV4uBqOns+0UvhsTO8qgl8hO89PmiDYv+/COyp1aeMcmfrfruz+/nCMFiYyFF/Knn0yfrC85ZzNFjembFTw== + dependencies: + "@babel/helper-annotate-as-pure" "^7.22.5" + "@babel/helper-environment-visitor" "^7.22.20" + "@babel/helper-wrap-function" "^7.22.20" + +"@babel/helper-replace-supers@^7.24.1": + version "7.24.1" + resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.24.1.tgz#7085bd19d4a0b7ed8f405c1ed73ccb70f323abc1" + integrity sha512-QCR1UqC9BzG5vZl8BMicmZ28RuUBnHhAMddD8yHFHDRH9lLTZ9uUPehX8ctVPT8l0TKblJidqcgUUKGVrePleQ== + dependencies: + "@babel/helper-environment-visitor" "^7.22.20" + "@babel/helper-member-expression-to-functions" "^7.23.0" + "@babel/helper-optimise-call-expression" "^7.22.5" + +"@babel/helper-simple-access@^7.22.5", "@babel/helper-simple-access@^7.24.5": + version "7.24.5" + resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.24.5.tgz#50da5b72f58c16b07fbd992810be6049478e85ba" + integrity sha512-uH3Hmf5q5n7n8mz7arjUlDOCbttY/DW4DYhE6FUsjKJ/oYC1kQQUvwEQWxRwUpX9qQKRXeqLwWxrqilMrf32sQ== + dependencies: + "@babel/types" "^7.24.5" + +"@babel/helper-skip-transparent-expression-wrappers@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.22.5.tgz#007f15240b5751c537c40e77abb4e89eeaaa8847" + integrity sha512-tK14r66JZKiC43p8Ki33yLBVJKlQDFoA8GYN67lWCDCqoL6EMMSuM9b+Iff2jHaM/RRFYl7K+iiru7hbRqNx8Q== + dependencies: + "@babel/types" "^7.22.5" + +"@babel/helper-split-export-declaration@^7.24.5": + version "7.24.5" + resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.5.tgz#b9a67f06a46b0b339323617c8c6213b9055a78b6" + integrity sha512-5CHncttXohrHk8GWOFCcCl4oRD9fKosWlIRgWm4ql9VYioKm52Mk2xsmoohvm7f3JoiLSM5ZgJuRaf5QZZYd3Q== + dependencies: + "@babel/types" "^7.24.5" + +"@babel/helper-string-parser@^7.24.1": + version "7.24.1" + resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.24.1.tgz#f99c36d3593db9540705d0739a1f10b5e20c696e" + integrity sha512-2ofRCjnnA9y+wk8b9IAREroeUP02KHp431N2mhKniy2yKIDKpbrHv9eXwm8cBeWQYcJmzv5qKCu65P47eCF7CQ== + +"@babel/helper-validator-identifier@^7.22.20", "@babel/helper-validator-identifier@^7.24.5": + version "7.24.5" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.5.tgz#918b1a7fa23056603506370089bd990d8720db62" + integrity sha512-3q93SSKX2TWCG30M2G2kwaKeTYgEUp5Snjuj8qm729SObL6nbtUldAi37qbxkD5gg3xnBio+f9nqpSepGZMvxA== + +"@babel/helper-validator-option@^7.23.5": + version "7.23.5" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.23.5.tgz#907a3fbd4523426285365d1206c423c4c5520307" + integrity sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw== + +"@babel/helper-wrap-function@^7.22.20": + version "7.24.5" + resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.24.5.tgz#335f934c0962e2c1ed1fb9d79e06a56115067c09" + integrity sha512-/xxzuNvgRl4/HLNKvnFwdhdgN3cpLxgLROeLDl83Yx0AJ1SGvq1ak0OszTOjDfiB8Vx03eJbeDWh9r+jCCWttw== + dependencies: + "@babel/helper-function-name" "^7.23.0" + "@babel/template" "^7.24.0" + "@babel/types" "^7.24.5" + +"@babel/helpers@^7.24.5": + version "7.24.5" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.24.5.tgz#fedeb87eeafa62b621160402181ad8585a22a40a" + integrity sha512-CiQmBMMpMQHwM5m01YnrM6imUG1ebgYJ+fAIW4FZe6m4qHTPaRHti+R8cggAwkdz4oXhtO4/K9JWlh+8hIfR2Q== + dependencies: + "@babel/template" "^7.24.0" + "@babel/traverse" "^7.24.5" + "@babel/types" "^7.24.5" + +"@babel/highlight@^7.24.2": + version "7.24.5" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.24.5.tgz#bc0613f98e1dd0720e99b2a9ee3760194a704b6e" + integrity sha512-8lLmua6AVh/8SLJRRVD6V8p73Hir9w5mJrhE+IPpILG31KKlI9iz5zmBYKcWPS59qSfgP9RaSBQSHHE81WKuEw== + dependencies: + "@babel/helper-validator-identifier" "^7.24.5" + chalk "^2.4.2" + js-tokens "^4.0.0" + picocolors "^1.0.0" + +"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.20.7", "@babel/parser@^7.23.9", "@babel/parser@^7.24.0", "@babel/parser@^7.24.5": + version "7.24.5" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.24.5.tgz#4a4d5ab4315579e5398a82dcf636ca80c3392790" + integrity sha512-EOv5IK8arwh3LI47dz1b0tKUb/1uhHAnHJOrjgtQMIpu1uXd9mlFrJg9IUgGUgZ41Ch0K8REPTYpO7B76b4vJg== + +"@babel/plugin-bugfix-firefox-class-in-computed-class-key@^7.24.5": + version "7.24.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.24.5.tgz#4c3685eb9cd790bcad2843900fe0250c91ccf895" + integrity sha512-LdXRi1wEMTrHVR4Zc9F8OewC3vdm5h4QB6L71zy6StmYeqGi1b3ttIO8UC+BfZKcH9jdr4aI249rBkm+3+YvHw== + dependencies: + "@babel/helper-environment-visitor" "^7.22.20" + "@babel/helper-plugin-utils" "^7.24.5" + +"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@^7.24.1": + version "7.24.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.24.1.tgz#b645d9ba8c2bc5b7af50f0fe949f9edbeb07c8cf" + integrity sha512-y4HqEnkelJIOQGd+3g1bTeKsA5c6qM7eOn7VggGVbBc0y8MLSKHacwcIE2PplNlQSj0PqS9rrXL/nkPVK+kUNg== + dependencies: + "@babel/helper-plugin-utils" "^7.24.0" + +"@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@^7.24.1": + version "7.24.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.24.1.tgz#da8261f2697f0f41b0855b91d3a20a1fbfd271d3" + integrity sha512-Hj791Ii4ci8HqnaKHAlLNs+zaLXb0EzSDhiAWp5VNlyvCNymYfacs64pxTxbH1znW/NcArSmwpmG9IKE/TUVVQ== + dependencies: + "@babel/helper-plugin-utils" "^7.24.0" + "@babel/helper-skip-transparent-expression-wrappers" "^7.22.5" + "@babel/plugin-transform-optional-chaining" "^7.24.1" + +"@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@^7.24.1": + version "7.24.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.24.1.tgz#1181d9685984c91d657b8ddf14f0487a6bab2988" + integrity sha512-m9m/fXsXLiHfwdgydIFnpk+7jlVbnvlK5B2EKiPdLUb6WX654ZaaEWJUjk8TftRbZpK0XibovlLWX4KIZhV6jw== + dependencies: + "@babel/helper-environment-visitor" "^7.22.20" + "@babel/helper-plugin-utils" "^7.24.0" + +"@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2": + version "7.21.0-placeholder-for-preset-env.2" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz#7844f9289546efa9febac2de4cfe358a050bd703" + integrity sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w== + +"@babel/plugin-syntax-async-generators@^7.8.4": + version "7.8.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz#a983fb1aeb2ec3f6ed042a210f640e90e786fe0d" + integrity sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-bigint@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz#4c9a6f669f5d0cdf1b90a1671e9a146be5300cea" + integrity sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-class-properties@^7.12.13", "@babel/plugin-syntax-class-properties@^7.8.3": + version "7.12.13" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz#b5c987274c4a3a82b89714796931a6b53544ae10" + integrity sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA== + dependencies: + "@babel/helper-plugin-utils" "^7.12.13" + +"@babel/plugin-syntax-class-static-block@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz#195df89b146b4b78b3bf897fd7a257c84659d406" + integrity sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-syntax-dynamic-import@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz#62bf98b2da3cd21d626154fc96ee5b3cb68eacb3" + integrity sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-export-namespace-from@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz#028964a9ba80dbc094c915c487ad7c4e7a66465a" + integrity sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-syntax-import-assertions@^7.24.1": + version "7.24.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.24.1.tgz#db3aad724153a00eaac115a3fb898de544e34971" + integrity sha512-IuwnI5XnuF189t91XbxmXeCDz3qs6iDRO7GJ++wcfgeXNs/8FmIlKcpDSXNVyuLQxlwvskmI3Ct73wUODkJBlQ== + dependencies: + "@babel/helper-plugin-utils" "^7.24.0" + +"@babel/plugin-syntax-import-attributes@^7.24.1": + version "7.24.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.24.1.tgz#c66b966c63b714c4eec508fcf5763b1f2d381093" + integrity sha512-zhQTMH0X2nVLnb04tz+s7AMuasX8U0FnpE+nHTOhSOINjWMnopoZTxtIKsd45n4GQ/HIZLyfIpoul8e2m0DnRA== + dependencies: + "@babel/helper-plugin-utils" "^7.24.0" + +"@babel/plugin-syntax-import-meta@^7.10.4", "@babel/plugin-syntax-import-meta@^7.8.3": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz#ee601348c370fa334d2207be158777496521fd51" + integrity sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-json-strings@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz#01ca21b668cd8218c9e640cb6dd88c5412b2c96a" + integrity sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-jsx@^7.23.3", "@babel/plugin-syntax-jsx@^7.7.2": + version "7.24.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.24.1.tgz#3f6ca04b8c841811dbc3c5c5f837934e0d626c10" + integrity sha512-2eCtxZXf+kbkMIsXS4poTvT4Yu5rXiRa+9xGVT56raghjmBTKMpFNc9R4IDiB4emao9eO22Ox7CxuJG7BgExqA== + dependencies: + "@babel/helper-plugin-utils" "^7.24.0" + +"@babel/plugin-syntax-logical-assignment-operators@^7.10.4", "@babel/plugin-syntax-logical-assignment-operators@^7.8.3": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz#ca91ef46303530448b906652bac2e9fe9941f699" + integrity sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-nullish-coalescing-operator@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz#167ed70368886081f74b5c36c65a88c03b66d1a9" + integrity sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-numeric-separator@^7.10.4", "@babel/plugin-syntax-numeric-separator@^7.8.3": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz#b9b070b3e33570cd9fd07ba7fa91c0dd37b9af97" + integrity sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-object-rest-spread@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz#60e225edcbd98a640332a2e72dd3e66f1af55871" + integrity sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-optional-catch-binding@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz#6111a265bcfb020eb9efd0fdfd7d26402b9ed6c1" + integrity sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-optional-chaining@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz#4f69c2ab95167e0180cd5336613f8c5788f7d48a" + integrity sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-private-property-in-object@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz#0dc6671ec0ea22b6e94a1114f857970cd39de1ad" + integrity sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-syntax-top-level-await@^7.14.5", "@babel/plugin-syntax-top-level-await@^7.8.3": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz#c1cfdadc35a646240001f06138247b741c34d94c" + integrity sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-syntax-typescript@^7.7.2": + version "7.24.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.24.1.tgz#b3bcc51f396d15f3591683f90239de143c076844" + integrity sha512-Yhnmvy5HZEnHUty6i++gcfH1/l68AHnItFHnaCv6hn9dNh0hQvvQJsxpi4BMBFN5DLeHBuucT/0DgzXif/OyRw== + dependencies: + "@babel/helper-plugin-utils" "^7.24.0" + +"@babel/plugin-syntax-unicode-sets-regex@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz#d49a3b3e6b52e5be6740022317580234a6a47357" + integrity sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-arrow-functions@^7.24.1": + version "7.24.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.24.1.tgz#2bf263617060c9cc45bcdbf492b8cc805082bf27" + integrity sha512-ngT/3NkRhsaep9ck9uj2Xhv9+xB1zShY3tM3g6om4xxCELwCDN4g4Aq5dRn48+0hasAql7s2hdBOysCfNpr4fw== + dependencies: + "@babel/helper-plugin-utils" "^7.24.0" + +"@babel/plugin-transform-async-generator-functions@^7.24.3": + version "7.24.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.24.3.tgz#8fa7ae481b100768cc9842c8617808c5352b8b89" + integrity sha512-Qe26CMYVjpQxJ8zxM1340JFNjZaF+ISWpr1Kt/jGo+ZTUzKkfw/pphEWbRCb+lmSM6k/TOgfYLvmbHkUQ0asIg== + dependencies: + "@babel/helper-environment-visitor" "^7.22.20" + "@babel/helper-plugin-utils" "^7.24.0" + "@babel/helper-remap-async-to-generator" "^7.22.20" + "@babel/plugin-syntax-async-generators" "^7.8.4" + +"@babel/plugin-transform-async-to-generator@^7.24.1": + version "7.24.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.24.1.tgz#0e220703b89f2216800ce7b1c53cb0cf521c37f4" + integrity sha512-AawPptitRXp1y0n4ilKcGbRYWfbbzFWz2NqNu7dacYDtFtz0CMjG64b3LQsb3KIgnf4/obcUL78hfaOS7iCUfw== + dependencies: + "@babel/helper-module-imports" "^7.24.1" + "@babel/helper-plugin-utils" "^7.24.0" + "@babel/helper-remap-async-to-generator" "^7.22.20" + +"@babel/plugin-transform-block-scoped-functions@^7.24.1": + version "7.24.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.24.1.tgz#1c94799e20fcd5c4d4589523bbc57b7692979380" + integrity sha512-TWWC18OShZutrv9C6mye1xwtam+uNi2bnTOCBUd5sZxyHOiWbU6ztSROofIMrK84uweEZC219POICK/sTYwfgg== + dependencies: + "@babel/helper-plugin-utils" "^7.24.0" + +"@babel/plugin-transform-block-scoping@^7.24.5": + version "7.24.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.24.5.tgz#89574191397f85661d6f748d4b89ee4d9ee69a2a" + integrity sha512-sMfBc3OxghjC95BkYrYocHL3NaOplrcaunblzwXhGmlPwpmfsxr4vK+mBBt49r+S240vahmv+kUxkeKgs+haCw== + dependencies: + "@babel/helper-plugin-utils" "^7.24.5" + +"@babel/plugin-transform-class-properties@^7.24.1": + version "7.24.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.24.1.tgz#bcbf1aef6ba6085cfddec9fc8d58871cf011fc29" + integrity sha512-OMLCXi0NqvJfORTaPQBwqLXHhb93wkBKZ4aNwMl6WtehO7ar+cmp+89iPEQPqxAnxsOKTaMcs3POz3rKayJ72g== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.24.1" + "@babel/helper-plugin-utils" "^7.24.0" + +"@babel/plugin-transform-class-static-block@^7.24.4": + version "7.24.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.24.4.tgz#1a4653c0cf8ac46441ec406dece6e9bc590356a4" + integrity sha512-B8q7Pz870Hz/q9UgP8InNpY01CSLDSCyqX7zcRuv3FcPl87A2G17lASroHWaCtbdIcbYzOZ7kWmXFKbijMSmFg== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.24.4" + "@babel/helper-plugin-utils" "^7.24.0" + "@babel/plugin-syntax-class-static-block" "^7.14.5" + +"@babel/plugin-transform-classes@^7.24.5": + version "7.24.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.24.5.tgz#05e04a09df49a46348299a0e24bfd7e901129339" + integrity sha512-gWkLP25DFj2dwe9Ck8uwMOpko4YsqyfZJrOmqqcegeDYEbp7rmn4U6UQZNj08UF6MaX39XenSpKRCvpDRBtZ7Q== + dependencies: + "@babel/helper-annotate-as-pure" "^7.22.5" + "@babel/helper-compilation-targets" "^7.23.6" + "@babel/helper-environment-visitor" "^7.22.20" + "@babel/helper-function-name" "^7.23.0" + "@babel/helper-plugin-utils" "^7.24.5" + "@babel/helper-replace-supers" "^7.24.1" + "@babel/helper-split-export-declaration" "^7.24.5" + globals "^11.1.0" + +"@babel/plugin-transform-computed-properties@^7.24.1": + version "7.24.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.24.1.tgz#bc7e787f8e021eccfb677af5f13c29a9934ed8a7" + integrity sha512-5pJGVIUfJpOS+pAqBQd+QMaTD2vCL/HcePooON6pDpHgRp4gNRmzyHTPIkXntwKsq3ayUFVfJaIKPw2pOkOcTw== + dependencies: + "@babel/helper-plugin-utils" "^7.24.0" + "@babel/template" "^7.24.0" + +"@babel/plugin-transform-destructuring@^7.24.5": + version "7.24.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.24.5.tgz#80843ee6a520f7362686d1a97a7b53544ede453c" + integrity sha512-SZuuLyfxvsm+Ah57I/i1HVjveBENYK9ue8MJ7qkc7ndoNjqquJiElzA7f5yaAXjyW2hKojosOTAQQRX50bPSVg== + dependencies: + "@babel/helper-plugin-utils" "^7.24.5" + +"@babel/plugin-transform-dotall-regex@^7.24.1": + version "7.24.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.24.1.tgz#d56913d2f12795cc9930801b84c6f8c47513ac13" + integrity sha512-p7uUxgSoZwZ2lPNMzUkqCts3xlp8n+o05ikjy7gbtFJSt9gdU88jAmtfmOxHM14noQXBxfgzf2yRWECiNVhTCw== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.22.15" + "@babel/helper-plugin-utils" "^7.24.0" + +"@babel/plugin-transform-duplicate-keys@^7.24.1": + version "7.24.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.24.1.tgz#5347a797fe82b8d09749d10e9f5b83665adbca88" + integrity sha512-msyzuUnvsjsaSaocV6L7ErfNsa5nDWL1XKNnDePLgmz+WdU4w/J8+AxBMrWfi9m4IxfL5sZQKUPQKDQeeAT6lA== + dependencies: + "@babel/helper-plugin-utils" "^7.24.0" + +"@babel/plugin-transform-dynamic-import@^7.24.1": + version "7.24.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.24.1.tgz#2a5a49959201970dd09a5fca856cb651e44439dd" + integrity sha512-av2gdSTyXcJVdI+8aFZsCAtR29xJt0S5tas+Ef8NvBNmD1a+N/3ecMLeMBgfcK+xzsjdLDT6oHt+DFPyeqUbDA== + dependencies: + "@babel/helper-plugin-utils" "^7.24.0" + "@babel/plugin-syntax-dynamic-import" "^7.8.3" + +"@babel/plugin-transform-exponentiation-operator@^7.24.1": + version "7.24.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.24.1.tgz#6650ebeb5bd5c012d5f5f90a26613a08162e8ba4" + integrity sha512-U1yX13dVBSwS23DEAqU+Z/PkwE9/m7QQy8Y9/+Tdb8UWYaGNDYwTLi19wqIAiROr8sXVum9A/rtiH5H0boUcTw== + dependencies: + "@babel/helper-builder-binary-assignment-operator-visitor" "^7.22.15" + "@babel/helper-plugin-utils" "^7.24.0" + +"@babel/plugin-transform-export-namespace-from@^7.24.1": + version "7.24.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.24.1.tgz#f033541fc036e3efb2dcb58eedafd4f6b8078acd" + integrity sha512-Ft38m/KFOyzKw2UaJFkWG9QnHPG/Q/2SkOrRk4pNBPg5IPZ+dOxcmkK5IyuBcxiNPyyYowPGUReyBvrvZs7IlQ== + dependencies: + "@babel/helper-plugin-utils" "^7.24.0" + "@babel/plugin-syntax-export-namespace-from" "^7.8.3" + +"@babel/plugin-transform-for-of@^7.24.1": + version "7.24.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.24.1.tgz#67448446b67ab6c091360ce3717e7d3a59e202fd" + integrity sha512-OxBdcnF04bpdQdR3i4giHZNZQn7cm8RQKcSwA17wAAqEELo1ZOwp5FFgeptWUQXFyT9kwHo10aqqauYkRZPCAg== + dependencies: + "@babel/helper-plugin-utils" "^7.24.0" + "@babel/helper-skip-transparent-expression-wrappers" "^7.22.5" + +"@babel/plugin-transform-function-name@^7.24.1": + version "7.24.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.24.1.tgz#8cba6f7730626cc4dfe4ca2fa516215a0592b361" + integrity sha512-BXmDZpPlh7jwicKArQASrj8n22/w6iymRnvHYYd2zO30DbE277JO20/7yXJT3QxDPtiQiOxQBbZH4TpivNXIxA== + dependencies: + "@babel/helper-compilation-targets" "^7.23.6" + "@babel/helper-function-name" "^7.23.0" + "@babel/helper-plugin-utils" "^7.24.0" + +"@babel/plugin-transform-json-strings@^7.24.1": + version "7.24.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.24.1.tgz#08e6369b62ab3e8a7b61089151b161180c8299f7" + integrity sha512-U7RMFmRvoasscrIFy5xA4gIp8iWnWubnKkKuUGJjsuOH7GfbMkB+XZzeslx2kLdEGdOJDamEmCqOks6e8nv8DQ== + dependencies: + "@babel/helper-plugin-utils" "^7.24.0" + "@babel/plugin-syntax-json-strings" "^7.8.3" + +"@babel/plugin-transform-literals@^7.24.1": + version "7.24.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.24.1.tgz#0a1982297af83e6b3c94972686067df588c5c096" + integrity sha512-zn9pwz8U7nCqOYIiBaOxoQOtYmMODXTJnkxG4AtX8fPmnCRYWBOHD0qcpwS9e2VDSp1zNJYpdnFMIKb8jmwu6g== + dependencies: + "@babel/helper-plugin-utils" "^7.24.0" + +"@babel/plugin-transform-logical-assignment-operators@^7.24.1": + version "7.24.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.24.1.tgz#719d8aded1aa94b8fb34e3a785ae8518e24cfa40" + integrity sha512-OhN6J4Bpz+hIBqItTeWJujDOfNP+unqv/NJgyhlpSqgBTPm37KkMmZV6SYcOj+pnDbdcl1qRGV/ZiIjX9Iy34w== + dependencies: + "@babel/helper-plugin-utils" "^7.24.0" + "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" + +"@babel/plugin-transform-member-expression-literals@^7.24.1": + version "7.24.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.24.1.tgz#896d23601c92f437af8b01371ad34beb75df4489" + integrity sha512-4ojai0KysTWXzHseJKa1XPNXKRbuUrhkOPY4rEGeR+7ChlJVKxFa3H3Bz+7tWaGKgJAXUWKOGmltN+u9B3+CVg== + dependencies: + "@babel/helper-plugin-utils" "^7.24.0" + +"@babel/plugin-transform-modules-amd@^7.24.1": + version "7.24.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.24.1.tgz#b6d829ed15258536977e9c7cc6437814871ffa39" + integrity sha512-lAxNHi4HVtjnHd5Rxg3D5t99Xm6H7b04hUS7EHIXcUl2EV4yl1gWdqZrNzXnSrHveL9qMdbODlLF55mvgjAfaQ== + dependencies: + "@babel/helper-module-transforms" "^7.23.3" + "@babel/helper-plugin-utils" "^7.24.0" + +"@babel/plugin-transform-modules-commonjs@^7.24.1": + version "7.24.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.24.1.tgz#e71ba1d0d69e049a22bf90b3867e263823d3f1b9" + integrity sha512-szog8fFTUxBfw0b98gEWPaEqF42ZUD/T3bkynW/wtgx2p/XCP55WEsb+VosKceRSd6njipdZvNogqdtI4Q0chw== + dependencies: + "@babel/helper-module-transforms" "^7.23.3" + "@babel/helper-plugin-utils" "^7.24.0" + "@babel/helper-simple-access" "^7.22.5" + +"@babel/plugin-transform-modules-systemjs@^7.24.1": + version "7.24.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.24.1.tgz#2b9625a3d4e445babac9788daec39094e6b11e3e" + integrity sha512-mqQ3Zh9vFO1Tpmlt8QPnbwGHzNz3lpNEMxQb1kAemn/erstyqw1r9KeOlOfo3y6xAnFEcOv2tSyrXfmMk+/YZA== + dependencies: + "@babel/helper-hoist-variables" "^7.22.5" + "@babel/helper-module-transforms" "^7.23.3" + "@babel/helper-plugin-utils" "^7.24.0" + "@babel/helper-validator-identifier" "^7.22.20" + +"@babel/plugin-transform-modules-umd@^7.24.1": + version "7.24.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.24.1.tgz#69220c66653a19cf2c0872b9c762b9a48b8bebef" + integrity sha512-tuA3lpPj+5ITfcCluy6nWonSL7RvaG0AOTeAuvXqEKS34lnLzXpDb0dcP6K8jD0zWZFNDVly90AGFJPnm4fOYg== + dependencies: + "@babel/helper-module-transforms" "^7.23.3" + "@babel/helper-plugin-utils" "^7.24.0" + +"@babel/plugin-transform-named-capturing-groups-regex@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.22.5.tgz#67fe18ee8ce02d57c855185e27e3dc959b2e991f" + integrity sha512-YgLLKmS3aUBhHaxp5hi1WJTgOUb/NCuDHzGT9z9WTt3YG+CPRhJs6nprbStx6DnWM4dh6gt7SU3sZodbZ08adQ== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.22.5" + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-new-target@^7.24.1": + version "7.24.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.24.1.tgz#29c59988fa3d0157de1c871a28cd83096363cc34" + integrity sha512-/rurytBM34hYy0HKZQyA0nHbQgQNFm4Q/BOc9Hflxi2X3twRof7NaE5W46j4kQitm7SvACVRXsa6N/tSZxvPug== + dependencies: + "@babel/helper-plugin-utils" "^7.24.0" + +"@babel/plugin-transform-nullish-coalescing-operator@^7.24.1": + version "7.24.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.24.1.tgz#0cd494bb97cb07d428bd651632cb9d4140513988" + integrity sha512-iQ+caew8wRrhCikO5DrUYx0mrmdhkaELgFa+7baMcVuhxIkN7oxt06CZ51D65ugIb1UWRQ8oQe+HXAVM6qHFjw== + dependencies: + "@babel/helper-plugin-utils" "^7.24.0" + "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" + +"@babel/plugin-transform-numeric-separator@^7.24.1": + version "7.24.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.24.1.tgz#5bc019ce5b3435c1cadf37215e55e433d674d4e8" + integrity sha512-7GAsGlK4cNL2OExJH1DzmDeKnRv/LXq0eLUSvudrehVA5Rgg4bIrqEUW29FbKMBRT0ztSqisv7kjP+XIC4ZMNw== + dependencies: + "@babel/helper-plugin-utils" "^7.24.0" + "@babel/plugin-syntax-numeric-separator" "^7.10.4" + +"@babel/plugin-transform-object-rest-spread@^7.24.5": + version "7.24.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.24.5.tgz#f91bbcb092ff957c54b4091c86bda8372f0b10ef" + integrity sha512-7EauQHszLGM3ay7a161tTQH7fj+3vVM/gThlz5HpFtnygTxjrlvoeq7MPVA1Vy9Q555OB8SnAOsMkLShNkkrHA== + dependencies: + "@babel/helper-compilation-targets" "^7.23.6" + "@babel/helper-plugin-utils" "^7.24.5" + "@babel/plugin-syntax-object-rest-spread" "^7.8.3" + "@babel/plugin-transform-parameters" "^7.24.5" + +"@babel/plugin-transform-object-super@^7.24.1": + version "7.24.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.24.1.tgz#e71d6ab13483cca89ed95a474f542bbfc20a0520" + integrity sha512-oKJqR3TeI5hSLRxudMjFQ9re9fBVUU0GICqM3J1mi8MqlhVr6hC/ZN4ttAyMuQR6EZZIY6h/exe5swqGNNIkWQ== + dependencies: + "@babel/helper-plugin-utils" "^7.24.0" + "@babel/helper-replace-supers" "^7.24.1" + +"@babel/plugin-transform-optional-catch-binding@^7.24.1": + version "7.24.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.24.1.tgz#92a3d0efe847ba722f1a4508669b23134669e2da" + integrity sha512-oBTH7oURV4Y+3EUrf6cWn1OHio3qG/PVwO5J03iSJmBg6m2EhKjkAu/xuaXaYwWW9miYtvbWv4LNf0AmR43LUA== + dependencies: + "@babel/helper-plugin-utils" "^7.24.0" + "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" + +"@babel/plugin-transform-optional-chaining@^7.24.1", "@babel/plugin-transform-optional-chaining@^7.24.5": + version "7.24.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.24.5.tgz#a6334bebd7f9dd3df37447880d0bd64b778e600f" + integrity sha512-xWCkmwKT+ihmA6l7SSTpk8e4qQl/274iNbSKRRS8mpqFR32ksy36+a+LWY8OXCCEefF8WFlnOHVsaDI2231wBg== + dependencies: + "@babel/helper-plugin-utils" "^7.24.5" + "@babel/helper-skip-transparent-expression-wrappers" "^7.22.5" + "@babel/plugin-syntax-optional-chaining" "^7.8.3" + +"@babel/plugin-transform-parameters@^7.24.5": + version "7.24.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.24.5.tgz#5c3b23f3a6b8fed090f9b98f2926896d3153cc62" + integrity sha512-9Co00MqZ2aoky+4j2jhofErthm6QVLKbpQrvz20c3CH9KQCLHyNB+t2ya4/UrRpQGR+Wrwjg9foopoeSdnHOkA== + dependencies: + "@babel/helper-plugin-utils" "^7.24.5" + +"@babel/plugin-transform-private-methods@^7.24.1": + version "7.24.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.24.1.tgz#a0faa1ae87eff077e1e47a5ec81c3aef383dc15a" + integrity sha512-tGvisebwBO5em4PaYNqt4fkw56K2VALsAbAakY0FjTYqJp7gfdrgr7YX76Or8/cpik0W6+tj3rZ0uHU9Oil4tw== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.24.1" + "@babel/helper-plugin-utils" "^7.24.0" + +"@babel/plugin-transform-private-property-in-object@^7.24.5": + version "7.24.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.24.5.tgz#f5d1fcad36e30c960134cb479f1ca98a5b06eda5" + integrity sha512-JM4MHZqnWR04jPMujQDTBVRnqxpLLpx2tkn7iPn+Hmsc0Gnb79yvRWOkvqFOx3Z7P7VxiRIR22c4eGSNj87OBQ== + dependencies: + "@babel/helper-annotate-as-pure" "^7.22.5" + "@babel/helper-create-class-features-plugin" "^7.24.5" + "@babel/helper-plugin-utils" "^7.24.5" + "@babel/plugin-syntax-private-property-in-object" "^7.14.5" + +"@babel/plugin-transform-property-literals@^7.24.1": + version "7.24.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.24.1.tgz#d6a9aeab96f03749f4eebeb0b6ea8e90ec958825" + integrity sha512-LetvD7CrHmEx0G442gOomRr66d7q8HzzGGr4PMHGr+5YIm6++Yke+jxj246rpvsbyhJwCLxcTn6zW1P1BSenqA== + dependencies: + "@babel/helper-plugin-utils" "^7.24.0" + +"@babel/plugin-transform-react-display-name@^7.24.1": + version "7.24.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.24.1.tgz#554e3e1a25d181f040cf698b93fd289a03bfdcdb" + integrity sha512-mvoQg2f9p2qlpDQRBC7M3c3XTr0k7cp/0+kFKKO/7Gtu0LSw16eKB+Fabe2bDT/UpsyasTBBkAnbdsLrkD5XMw== + dependencies: + "@babel/helper-plugin-utils" "^7.24.0" + +"@babel/plugin-transform-react-jsx-development@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.22.5.tgz#e716b6edbef972a92165cd69d92f1255f7e73e87" + integrity sha512-bDhuzwWMuInwCYeDeMzyi7TaBgRQei6DqxhbyniL7/VG4RSS7HtSL2QbY4eESy1KJqlWt8g3xeEBGPuo+XqC8A== + dependencies: + "@babel/plugin-transform-react-jsx" "^7.22.5" + +"@babel/plugin-transform-react-jsx@^7.22.5", "@babel/plugin-transform-react-jsx@^7.23.4": + version "7.23.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.23.4.tgz#393f99185110cea87184ea47bcb4a7b0c2e39312" + integrity sha512-5xOpoPguCZCRbo/JeHlloSkTA8Bld1J/E1/kLfD1nsuiW1m8tduTA1ERCgIZokDflX/IBzKcqR3l7VlRgiIfHA== + dependencies: + "@babel/helper-annotate-as-pure" "^7.22.5" + "@babel/helper-module-imports" "^7.22.15" + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/plugin-syntax-jsx" "^7.23.3" + "@babel/types" "^7.23.4" + +"@babel/plugin-transform-react-pure-annotations@^7.24.1": + version "7.24.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.24.1.tgz#c86bce22a53956331210d268e49a0ff06e392470" + integrity sha512-+pWEAaDJvSm9aFvJNpLiM2+ktl2Sn2U5DdyiWdZBxmLc6+xGt88dvFqsHiAiDS+8WqUwbDfkKz9jRxK3M0k+kA== + dependencies: + "@babel/helper-annotate-as-pure" "^7.22.5" + "@babel/helper-plugin-utils" "^7.24.0" + +"@babel/plugin-transform-regenerator@^7.24.1": + version "7.24.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.24.1.tgz#625b7545bae52363bdc1fbbdc7252b5046409c8c" + integrity sha512-sJwZBCzIBE4t+5Q4IGLaaun5ExVMRY0lYwos/jNecjMrVCygCdph3IKv0tkP5Fc87e/1+bebAmEAGBfnRD+cnw== + dependencies: + "@babel/helper-plugin-utils" "^7.24.0" + regenerator-transform "^0.15.2" + +"@babel/plugin-transform-reserved-words@^7.24.1": + version "7.24.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.24.1.tgz#8de729f5ecbaaf5cf83b67de13bad38a21be57c1" + integrity sha512-JAclqStUfIwKN15HrsQADFgeZt+wexNQ0uLhuqvqAUFoqPMjEcFCYZBhq0LUdz6dZK/mD+rErhW71fbx8RYElg== + dependencies: + "@babel/helper-plugin-utils" "^7.24.0" + +"@babel/plugin-transform-shorthand-properties@^7.24.1": + version "7.24.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.24.1.tgz#ba9a09144cf55d35ec6b93a32253becad8ee5b55" + integrity sha512-LyjVB1nsJ6gTTUKRjRWx9C1s9hE7dLfP/knKdrfeH9UPtAGjYGgxIbFfx7xyLIEWs7Xe1Gnf8EWiUqfjLhInZA== + dependencies: + "@babel/helper-plugin-utils" "^7.24.0" + +"@babel/plugin-transform-spread@^7.24.1": + version "7.24.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.24.1.tgz#a1acf9152cbf690e4da0ba10790b3ac7d2b2b391" + integrity sha512-KjmcIM+fxgY+KxPVbjelJC6hrH1CgtPmTvdXAfn3/a9CnWGSTY7nH4zm5+cjmWJybdcPSsD0++QssDsjcpe47g== + dependencies: + "@babel/helper-plugin-utils" "^7.24.0" + "@babel/helper-skip-transparent-expression-wrappers" "^7.22.5" + +"@babel/plugin-transform-sticky-regex@^7.24.1": + version "7.24.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.24.1.tgz#f03e672912c6e203ed8d6e0271d9c2113dc031b9" + integrity sha512-9v0f1bRXgPVcPrngOQvLXeGNNVLc8UjMVfebo9ka0WF3/7+aVUHmaJVT3sa0XCzEFioPfPHZiOcYG9qOsH63cw== + dependencies: + "@babel/helper-plugin-utils" "^7.24.0" + +"@babel/plugin-transform-template-literals@^7.24.1": + version "7.24.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.24.1.tgz#15e2166873a30d8617e3e2ccadb86643d327aab7" + integrity sha512-WRkhROsNzriarqECASCNu/nojeXCDTE/F2HmRgOzi7NGvyfYGq1NEjKBK3ckLfRgGc6/lPAqP0vDOSw3YtG34g== + dependencies: + "@babel/helper-plugin-utils" "^7.24.0" + +"@babel/plugin-transform-typeof-symbol@^7.24.5": + version "7.24.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.24.5.tgz#703cace5ef74155fb5eecab63cbfc39bdd25fe12" + integrity sha512-UTGnhYVZtTAjdwOTzT+sCyXmTn8AhaxOS/MjG9REclZ6ULHWF9KoCZur0HSGU7hk8PdBFKKbYe6+gqdXWz84Jg== + dependencies: + "@babel/helper-plugin-utils" "^7.24.5" + +"@babel/plugin-transform-unicode-escapes@^7.24.1": + version "7.24.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.24.1.tgz#fb3fa16676549ac7c7449db9b342614985c2a3a4" + integrity sha512-RlkVIcWT4TLI96zM660S877E7beKlQw7Ig+wqkKBiWfj0zH5Q4h50q6er4wzZKRNSYpfo6ILJ+hrJAGSX2qcNw== + dependencies: + "@babel/helper-plugin-utils" "^7.24.0" + +"@babel/plugin-transform-unicode-property-regex@^7.24.1": + version "7.24.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.24.1.tgz#56704fd4d99da81e5e9f0c0c93cabd91dbc4889e" + integrity sha512-Ss4VvlfYV5huWApFsF8/Sq0oXnGO+jB+rijFEFugTd3cwSObUSnUi88djgR5528Csl0uKlrI331kRqe56Ov2Ng== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.22.15" + "@babel/helper-plugin-utils" "^7.24.0" + +"@babel/plugin-transform-unicode-regex@^7.24.1": + version "7.24.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.24.1.tgz#57c3c191d68f998ac46b708380c1ce4d13536385" + integrity sha512-2A/94wgZgxfTsiLaQ2E36XAOdcZmGAaEEgVmxQWwZXWkGhvoHbaqXcKnU8zny4ycpu3vNqg0L/PcCiYtHtA13g== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.22.15" + "@babel/helper-plugin-utils" "^7.24.0" + +"@babel/plugin-transform-unicode-sets-regex@^7.24.1": + version "7.24.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.24.1.tgz#c1ea175b02afcffc9cf57a9c4658326625165b7f" + integrity sha512-fqj4WuzzS+ukpgerpAoOnMfQXwUHFxXUZUE84oL2Kao2N8uSlvcpnAidKASgsNgzZHBsHWvcm8s9FPWUhAb8fA== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.22.15" + "@babel/helper-plugin-utils" "^7.24.0" + +"@babel/preset-env@^7.24.5": + version "7.24.5" + resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.24.5.tgz#6a9ac90bd5a5a9dae502af60dfc58c190551bbcd" + integrity sha512-UGK2ifKtcC8i5AI4cH+sbLLuLc2ktYSFJgBAXorKAsHUZmrQ1q6aQ6i3BvU24wWs2AAKqQB6kq3N9V9Gw1HiMQ== + dependencies: + "@babel/compat-data" "^7.24.4" + "@babel/helper-compilation-targets" "^7.23.6" + "@babel/helper-plugin-utils" "^7.24.5" + "@babel/helper-validator-option" "^7.23.5" + "@babel/plugin-bugfix-firefox-class-in-computed-class-key" "^7.24.5" + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression" "^7.24.1" + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining" "^7.24.1" + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly" "^7.24.1" + "@babel/plugin-proposal-private-property-in-object" "7.21.0-placeholder-for-preset-env.2" + "@babel/plugin-syntax-async-generators" "^7.8.4" + "@babel/plugin-syntax-class-properties" "^7.12.13" + "@babel/plugin-syntax-class-static-block" "^7.14.5" + "@babel/plugin-syntax-dynamic-import" "^7.8.3" + "@babel/plugin-syntax-export-namespace-from" "^7.8.3" + "@babel/plugin-syntax-import-assertions" "^7.24.1" + "@babel/plugin-syntax-import-attributes" "^7.24.1" + "@babel/plugin-syntax-import-meta" "^7.10.4" + "@babel/plugin-syntax-json-strings" "^7.8.3" + "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" + "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" + "@babel/plugin-syntax-numeric-separator" "^7.10.4" + "@babel/plugin-syntax-object-rest-spread" "^7.8.3" + "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" + "@babel/plugin-syntax-optional-chaining" "^7.8.3" + "@babel/plugin-syntax-private-property-in-object" "^7.14.5" + "@babel/plugin-syntax-top-level-await" "^7.14.5" + "@babel/plugin-syntax-unicode-sets-regex" "^7.18.6" + "@babel/plugin-transform-arrow-functions" "^7.24.1" + "@babel/plugin-transform-async-generator-functions" "^7.24.3" + "@babel/plugin-transform-async-to-generator" "^7.24.1" + "@babel/plugin-transform-block-scoped-functions" "^7.24.1" + "@babel/plugin-transform-block-scoping" "^7.24.5" + "@babel/plugin-transform-class-properties" "^7.24.1" + "@babel/plugin-transform-class-static-block" "^7.24.4" + "@babel/plugin-transform-classes" "^7.24.5" + "@babel/plugin-transform-computed-properties" "^7.24.1" + "@babel/plugin-transform-destructuring" "^7.24.5" + "@babel/plugin-transform-dotall-regex" "^7.24.1" + "@babel/plugin-transform-duplicate-keys" "^7.24.1" + "@babel/plugin-transform-dynamic-import" "^7.24.1" + "@babel/plugin-transform-exponentiation-operator" "^7.24.1" + "@babel/plugin-transform-export-namespace-from" "^7.24.1" + "@babel/plugin-transform-for-of" "^7.24.1" + "@babel/plugin-transform-function-name" "^7.24.1" + "@babel/plugin-transform-json-strings" "^7.24.1" + "@babel/plugin-transform-literals" "^7.24.1" + "@babel/plugin-transform-logical-assignment-operators" "^7.24.1" + "@babel/plugin-transform-member-expression-literals" "^7.24.1" + "@babel/plugin-transform-modules-amd" "^7.24.1" + "@babel/plugin-transform-modules-commonjs" "^7.24.1" + "@babel/plugin-transform-modules-systemjs" "^7.24.1" + "@babel/plugin-transform-modules-umd" "^7.24.1" + "@babel/plugin-transform-named-capturing-groups-regex" "^7.22.5" + "@babel/plugin-transform-new-target" "^7.24.1" + "@babel/plugin-transform-nullish-coalescing-operator" "^7.24.1" + "@babel/plugin-transform-numeric-separator" "^7.24.1" + "@babel/plugin-transform-object-rest-spread" "^7.24.5" + "@babel/plugin-transform-object-super" "^7.24.1" + "@babel/plugin-transform-optional-catch-binding" "^7.24.1" + "@babel/plugin-transform-optional-chaining" "^7.24.5" + "@babel/plugin-transform-parameters" "^7.24.5" + "@babel/plugin-transform-private-methods" "^7.24.1" + "@babel/plugin-transform-private-property-in-object" "^7.24.5" + "@babel/plugin-transform-property-literals" "^7.24.1" + "@babel/plugin-transform-regenerator" "^7.24.1" + "@babel/plugin-transform-reserved-words" "^7.24.1" + "@babel/plugin-transform-shorthand-properties" "^7.24.1" + "@babel/plugin-transform-spread" "^7.24.1" + "@babel/plugin-transform-sticky-regex" "^7.24.1" + "@babel/plugin-transform-template-literals" "^7.24.1" + "@babel/plugin-transform-typeof-symbol" "^7.24.5" + "@babel/plugin-transform-unicode-escapes" "^7.24.1" + "@babel/plugin-transform-unicode-property-regex" "^7.24.1" + "@babel/plugin-transform-unicode-regex" "^7.24.1" + "@babel/plugin-transform-unicode-sets-regex" "^7.24.1" + "@babel/preset-modules" "0.1.6-no-external-plugins" + babel-plugin-polyfill-corejs2 "^0.4.10" + babel-plugin-polyfill-corejs3 "^0.10.4" + babel-plugin-polyfill-regenerator "^0.6.1" + core-js-compat "^3.31.0" + semver "^6.3.1" + +"@babel/preset-modules@0.1.6-no-external-plugins": + version "0.1.6-no-external-plugins" + resolved "https://registry.yarnpkg.com/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz#ccb88a2c49c817236861fee7826080573b8a923a" + integrity sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/types" "^7.4.4" + esutils "^2.0.2" + +"@babel/preset-react@^7.24.1": + version "7.24.1" + resolved "https://registry.yarnpkg.com/@babel/preset-react/-/preset-react-7.24.1.tgz#2450c2ac5cc498ef6101a6ca5474de251e33aa95" + integrity sha512-eFa8up2/8cZXLIpkafhaADTXSnl7IsUFCYenRWrARBz0/qZwcT0RBXpys0LJU4+WfPoF2ZG6ew6s2V6izMCwRA== + dependencies: + "@babel/helper-plugin-utils" "^7.24.0" + "@babel/helper-validator-option" "^7.23.5" + "@babel/plugin-transform-react-display-name" "^7.24.1" + "@babel/plugin-transform-react-jsx" "^7.23.4" + "@babel/plugin-transform-react-jsx-development" "^7.22.5" + "@babel/plugin-transform-react-pure-annotations" "^7.24.1" + +"@babel/regjsgen@^0.8.0": + version "0.8.0" + resolved "https://registry.yarnpkg.com/@babel/regjsgen/-/regjsgen-0.8.0.tgz#f0ba69b075e1f05fb2825b7fad991e7adbb18310" + integrity sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA== + +"@babel/runtime@^7.12.5", "@babel/runtime@^7.8.4", "@babel/runtime@^7.9.2": + version "7.24.5" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.24.5.tgz#230946857c053a36ccc66e1dd03b17dd0c4ed02c" + integrity sha512-Nms86NXrsaeU9vbBJKni6gXiEXZ4CVpYVzEjDH9Sb8vmZ3UljyA1GSOJl/6LGPO8EHLuSF9H+IxNXHPX8QHJ4g== + dependencies: + regenerator-runtime "^0.14.0" + +"@babel/template@^7.22.15", "@babel/template@^7.24.0", "@babel/template@^7.3.3": + version "7.24.0" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.24.0.tgz#c6a524aa93a4a05d66aaf31654258fae69d87d50" + integrity sha512-Bkf2q8lMB0AFpX0NFEqSbx1OkTHf0f+0j82mkw+ZpzBnkk7e9Ql0891vlfgi+kHwOk8tQjiQHpqh4LaSa0fKEA== + dependencies: + "@babel/code-frame" "^7.23.5" + "@babel/parser" "^7.24.0" + "@babel/types" "^7.24.0" + +"@babel/traverse@^7.24.5": + version "7.24.5" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.24.5.tgz#972aa0bc45f16983bf64aa1f877b2dd0eea7e6f8" + integrity sha512-7aaBLeDQ4zYcUFDUD41lJc1fG8+5IU9DaNSJAgal866FGvmD5EbWQgnEC6kO1gGLsX0esNkfnJSndbTXA3r7UA== + dependencies: + "@babel/code-frame" "^7.24.2" + "@babel/generator" "^7.24.5" + "@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.24.5" + "@babel/parser" "^7.24.5" + "@babel/types" "^7.24.5" + debug "^4.3.1" + globals "^11.1.0" + +"@babel/types@^7.0.0", "@babel/types@^7.20.7", "@babel/types@^7.22.15", "@babel/types@^7.22.5", "@babel/types@^7.23.0", "@babel/types@^7.23.4", "@babel/types@^7.24.0", "@babel/types@^7.24.5", "@babel/types@^7.3.3", "@babel/types@^7.4.4": + version "7.24.5" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.24.5.tgz#7661930afc638a5383eb0c4aee59b74f38db84d7" + integrity sha512-6mQNsaLeXTw0nxYUYu+NSa4Hx4BlF1x1x8/PMFbiR+GBSr+2DkECc69b8hgy2frEodNcvPffeH8YfWd3LI6jhQ== + dependencies: + "@babel/helper-string-parser" "^7.24.1" + "@babel/helper-validator-identifier" "^7.24.5" + to-fast-properties "^2.0.0" + +"@bcoe/v8-coverage@^0.2.3": + version "0.2.3" + resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" + integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== + +"@digitalbazaar/http-client@^3.4.1": + version "3.4.1" + resolved "https://registry.yarnpkg.com/@digitalbazaar/http-client/-/http-client-3.4.1.tgz#5116fc44290d647cfe4b615d1f3fad9d6005e44d" + integrity sha512-Ahk1N+s7urkgj7WvvUND5f8GiWEPfUw0D41hdElaqLgu8wZScI8gdI0q+qWw5N1d35x7GCRH2uk9mi+Uzo9M3g== + dependencies: + ky "^0.33.3" + ky-universal "^0.11.0" + undici "^5.21.2" + +"@fastify/busboy@^2.0.0": + version "2.1.1" + resolved "https://registry.yarnpkg.com/@fastify/busboy/-/busboy-2.1.1.tgz#b9da6a878a371829a0502c9b6c1c143ef6663f4d" + integrity sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA== + +"@istanbuljs/load-nyc-config@^1.0.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz#fd3db1d59ecf7cf121e80650bb86712f9b55eced" + integrity sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ== + dependencies: + camelcase "^5.3.1" + find-up "^4.1.0" + get-package-type "^0.1.0" + js-yaml "^3.13.1" + resolve-from "^5.0.0" + +"@istanbuljs/schema@^0.1.2", "@istanbuljs/schema@^0.1.3": + version "0.1.3" + resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.3.tgz#e45e384e4b8ec16bce2fd903af78450f6bf7ec98" + integrity sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA== + +"@jest/console@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/console/-/console-29.7.0.tgz#cd4822dbdb84529265c5a2bdb529a3c9cc950ffc" + integrity sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg== + dependencies: + "@jest/types" "^29.6.3" + "@types/node" "*" + chalk "^4.0.0" + jest-message-util "^29.7.0" + jest-util "^29.7.0" + slash "^3.0.0" + +"@jest/core@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/core/-/core-29.7.0.tgz#b6cccc239f30ff36609658c5a5e2291757ce448f" + integrity sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg== + dependencies: + "@jest/console" "^29.7.0" + "@jest/reporters" "^29.7.0" + "@jest/test-result" "^29.7.0" + "@jest/transform" "^29.7.0" + "@jest/types" "^29.6.3" + "@types/node" "*" + ansi-escapes "^4.2.1" + chalk "^4.0.0" + ci-info "^3.2.0" + exit "^0.1.2" + graceful-fs "^4.2.9" + jest-changed-files "^29.7.0" + jest-config "^29.7.0" + jest-haste-map "^29.7.0" + jest-message-util "^29.7.0" + jest-regex-util "^29.6.3" + jest-resolve "^29.7.0" + jest-resolve-dependencies "^29.7.0" + jest-runner "^29.7.0" + jest-runtime "^29.7.0" + jest-snapshot "^29.7.0" + jest-util "^29.7.0" + jest-validate "^29.7.0" + jest-watcher "^29.7.0" + micromatch "^4.0.4" + pretty-format "^29.7.0" + slash "^3.0.0" + strip-ansi "^6.0.0" + +"@jest/environment@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-29.7.0.tgz#24d61f54ff1f786f3cd4073b4b94416383baf2a7" + integrity sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw== + dependencies: + "@jest/fake-timers" "^29.7.0" + "@jest/types" "^29.6.3" + "@types/node" "*" + jest-mock "^29.7.0" + +"@jest/expect-utils@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/expect-utils/-/expect-utils-29.7.0.tgz#023efe5d26a8a70f21677d0a1afc0f0a44e3a1c6" + integrity sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA== + dependencies: + jest-get-type "^29.6.3" + +"@jest/expect@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/expect/-/expect-29.7.0.tgz#76a3edb0cb753b70dfbfe23283510d3d45432bf2" + integrity sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ== + dependencies: + expect "^29.7.0" + jest-snapshot "^29.7.0" + +"@jest/fake-timers@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-29.7.0.tgz#fd91bf1fffb16d7d0d24a426ab1a47a49881a565" + integrity sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ== + dependencies: + "@jest/types" "^29.6.3" + "@sinonjs/fake-timers" "^10.0.2" + "@types/node" "*" + jest-message-util "^29.7.0" + jest-mock "^29.7.0" + jest-util "^29.7.0" + +"@jest/globals@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/globals/-/globals-29.7.0.tgz#8d9290f9ec47ff772607fa864ca1d5a2efae1d4d" + integrity sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ== + dependencies: + "@jest/environment" "^29.7.0" + "@jest/expect" "^29.7.0" + "@jest/types" "^29.6.3" + jest-mock "^29.7.0" + +"@jest/reporters@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-29.7.0.tgz#04b262ecb3b8faa83b0b3d321623972393e8f4c7" + integrity sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg== + dependencies: + "@bcoe/v8-coverage" "^0.2.3" + "@jest/console" "^29.7.0" + "@jest/test-result" "^29.7.0" + "@jest/transform" "^29.7.0" + "@jest/types" "^29.6.3" + "@jridgewell/trace-mapping" "^0.3.18" + "@types/node" "*" + chalk "^4.0.0" + collect-v8-coverage "^1.0.0" + exit "^0.1.2" + glob "^7.1.3" + graceful-fs "^4.2.9" + istanbul-lib-coverage "^3.0.0" + istanbul-lib-instrument "^6.0.0" + istanbul-lib-report "^3.0.0" + istanbul-lib-source-maps "^4.0.0" + istanbul-reports "^3.1.3" + jest-message-util "^29.7.0" + jest-util "^29.7.0" + jest-worker "^29.7.0" + slash "^3.0.0" + string-length "^4.0.1" + strip-ansi "^6.0.0" + v8-to-istanbul "^9.0.1" + +"@jest/schemas@^29.6.3": + version "29.6.3" + resolved "https://registry.yarnpkg.com/@jest/schemas/-/schemas-29.6.3.tgz#430b5ce8a4e0044a7e3819663305a7b3091c8e03" + integrity sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA== + dependencies: + "@sinclair/typebox" "^0.27.8" + +"@jest/source-map@^29.6.3": + version "29.6.3" + resolved "https://registry.yarnpkg.com/@jest/source-map/-/source-map-29.6.3.tgz#d90ba772095cf37a34a5eb9413f1b562a08554c4" + integrity sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw== + dependencies: + "@jridgewell/trace-mapping" "^0.3.18" + callsites "^3.0.0" + graceful-fs "^4.2.9" + +"@jest/test-result@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-29.7.0.tgz#8db9a80aa1a097bb2262572686734baed9b1657c" + integrity sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA== + dependencies: + "@jest/console" "^29.7.0" + "@jest/types" "^29.6.3" + "@types/istanbul-lib-coverage" "^2.0.0" + collect-v8-coverage "^1.0.0" + +"@jest/test-sequencer@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/test-sequencer/-/test-sequencer-29.7.0.tgz#6cef977ce1d39834a3aea887a1726628a6f072ce" + integrity sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw== + dependencies: + "@jest/test-result" "^29.7.0" + graceful-fs "^4.2.9" + jest-haste-map "^29.7.0" + slash "^3.0.0" + +"@jest/transform@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-29.7.0.tgz#df2dd9c346c7d7768b8a06639994640c642e284c" + integrity sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw== + dependencies: + "@babel/core" "^7.11.6" + "@jest/types" "^29.6.3" + "@jridgewell/trace-mapping" "^0.3.18" + babel-plugin-istanbul "^6.1.1" + chalk "^4.0.0" + convert-source-map "^2.0.0" + fast-json-stable-stringify "^2.1.0" + graceful-fs "^4.2.9" + jest-haste-map "^29.7.0" + jest-regex-util "^29.6.3" + jest-util "^29.7.0" + micromatch "^4.0.4" + pirates "^4.0.4" + slash "^3.0.0" + write-file-atomic "^4.0.2" + +"@jest/types@^29.6.3": + version "29.6.3" + resolved "https://registry.yarnpkg.com/@jest/types/-/types-29.6.3.tgz#1131f8cf634e7e84c5e77bab12f052af585fba59" + integrity sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw== + dependencies: + "@jest/schemas" "^29.6.3" + "@types/istanbul-lib-coverage" "^2.0.0" + "@types/istanbul-reports" "^3.0.0" + "@types/node" "*" + "@types/yargs" "^17.0.8" + chalk "^4.0.0" + +"@jridgewell/gen-mapping@^0.3.5": + version "0.3.5" + resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz#dcce6aff74bdf6dad1a95802b69b04a2fcb1fb36" + integrity sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg== + dependencies: + "@jridgewell/set-array" "^1.2.1" + "@jridgewell/sourcemap-codec" "^1.4.10" + "@jridgewell/trace-mapping" "^0.3.24" + +"@jridgewell/resolve-uri@^3.1.0": + version "3.1.2" + resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz#7a0ee601f60f99a20c7c7c5ff0c80388c1189bd6" + integrity sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw== + +"@jridgewell/set-array@^1.2.1": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.2.1.tgz#558fb6472ed16a4c850b889530e6b36438c49280" + integrity sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A== + +"@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.14": + version "1.4.15" + resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz#d7c6e6755c78567a951e04ab52ef0fd26de59f32" + integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg== + +"@jridgewell/trace-mapping@^0.3.12", "@jridgewell/trace-mapping@^0.3.18", "@jridgewell/trace-mapping@^0.3.24", "@jridgewell/trace-mapping@^0.3.25": + version "0.3.25" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz#15f190e98895f3fc23276ee14bc76b675c2e50f0" + integrity sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ== + dependencies: + "@jridgewell/resolve-uri" "^3.1.0" + "@jridgewell/sourcemap-codec" "^1.4.14" + +"@sinclair/typebox@^0.27.8": + version "0.27.8" + resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.27.8.tgz#6667fac16c436b5434a387a34dedb013198f6e6e" + integrity sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA== + +"@sinonjs/commons@^3.0.0": + version "3.0.1" + resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-3.0.1.tgz#1029357e44ca901a615585f6d27738dbc89084cd" + integrity sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ== + dependencies: + type-detect "4.0.8" + +"@sinonjs/fake-timers@^10.0.2": + version "10.3.0" + resolved "https://registry.yarnpkg.com/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz#55fdff1ecab9f354019129daf4df0dd4d923ea66" + integrity sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA== + dependencies: + "@sinonjs/commons" "^3.0.0" + +"@testing-library/dom@^10.0.0", "@testing-library/dom@^10.1.0": + version "10.1.0" + resolved "https://registry.yarnpkg.com/@testing-library/dom/-/dom-10.1.0.tgz#2d073e49771ad614da999ca48f199919e5176fb6" + integrity sha512-wdsYKy5zupPyLCW2Je5DLHSxSfbIp6h80WoHOQc+RPtmPGA52O9x5MJEkv92Sjonpq+poOAtUKhh1kBGAXBrNA== + dependencies: + "@babel/code-frame" "^7.10.4" + "@babel/runtime" "^7.12.5" + "@types/aria-query" "^5.0.1" + aria-query "5.3.0" + chalk "^4.1.0" + dom-accessibility-api "^0.5.9" + lz-string "^1.5.0" + pretty-format "^27.0.2" + +"@testing-library/jest-dom@^6.4.5": + version "6.4.5" + resolved "https://registry.yarnpkg.com/@testing-library/jest-dom/-/jest-dom-6.4.5.tgz#badb40296477149136dabef32b572ddd3b56adf1" + integrity sha512-AguB9yvTXmCnySBP1lWjfNNUwpbElsaQ567lt2VdGqAdHtpieLgjmcVyv1q7PMIvLbgpDdkWV5Ydv3FEejyp2A== + dependencies: + "@adobe/css-tools" "^4.3.2" + "@babel/runtime" "^7.9.2" + aria-query "^5.0.0" + chalk "^3.0.0" + css.escape "^1.5.1" + dom-accessibility-api "^0.6.3" + lodash "^4.17.21" + redent "^3.0.0" + +"@testing-library/react@^15.0.7": + version "15.0.7" + resolved "https://registry.yarnpkg.com/@testing-library/react/-/react-15.0.7.tgz#ff733ce0893c875cb5a47672e8e772897128f4ae" + integrity sha512-cg0RvEdD1TIhhkm1IeYMQxrzy0MtUNfa3minv4MjbgcYzJAZ7yD0i0lwoPOTPr+INtiXFezt2o8xMSnyHhEn2Q== + dependencies: + "@babel/runtime" "^7.12.5" + "@testing-library/dom" "^10.0.0" + "@types/react-dom" "^18.0.0" + +"@tootallnate/once@2": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-2.0.0.tgz#f544a148d3ab35801c1f633a7441fd87c2e484bf" + integrity sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A== + +"@types/aria-query@^5.0.1": + version "5.0.4" + resolved "https://registry.yarnpkg.com/@types/aria-query/-/aria-query-5.0.4.tgz#1a31c3d378850d2778dabb6374d036dcba4ba708" + integrity sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw== + +"@types/babel__core@^7.1.14": + version "7.20.5" + resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.20.5.tgz#3df15f27ba85319caa07ba08d0721889bb39c017" + integrity sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA== + dependencies: + "@babel/parser" "^7.20.7" + "@babel/types" "^7.20.7" + "@types/babel__generator" "*" + "@types/babel__template" "*" + "@types/babel__traverse" "*" + +"@types/babel__generator@*": + version "7.6.8" + resolved "https://registry.yarnpkg.com/@types/babel__generator/-/babel__generator-7.6.8.tgz#f836c61f48b1346e7d2b0d93c6dacc5b9535d3ab" + integrity sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw== + dependencies: + "@babel/types" "^7.0.0" + +"@types/babel__template@*": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@types/babel__template/-/babel__template-7.4.4.tgz#5672513701c1b2199bc6dad636a9d7491586766f" + integrity sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A== + dependencies: + "@babel/parser" "^7.1.0" + "@babel/types" "^7.0.0" + +"@types/babel__traverse@*", "@types/babel__traverse@^7.0.6": + version "7.20.5" + resolved "https://registry.yarnpkg.com/@types/babel__traverse/-/babel__traverse-7.20.5.tgz#7b7502be0aa80cc4ef22978846b983edaafcd4dd" + integrity sha512-WXCyOcRtH37HAUkpXhUduaxdm82b4GSlyTqajXviN4EfiuPgNYR109xMCKvpl6zPIpua0DGlMEDCq+g8EdoheQ== + dependencies: + "@babel/types" "^7.20.7" + +"@types/graceful-fs@^4.1.3": + version "4.1.9" + resolved "https://registry.yarnpkg.com/@types/graceful-fs/-/graceful-fs-4.1.9.tgz#2a06bc0f68a20ab37b3e36aa238be6abdf49e8b4" + integrity sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ== + dependencies: + "@types/node" "*" + +"@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0", "@types/istanbul-lib-coverage@^2.0.1": + version "2.0.6" + resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz#7739c232a1fee9b4d3ce8985f314c0c6d33549d7" + integrity sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w== + +"@types/istanbul-lib-report@*": + version "3.0.3" + resolved "https://registry.yarnpkg.com/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz#53047614ae72e19fc0401d872de3ae2b4ce350bf" + integrity sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA== + dependencies: + "@types/istanbul-lib-coverage" "*" + +"@types/istanbul-reports@^3.0.0": + version "3.0.4" + resolved "https://registry.yarnpkg.com/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz#0f03e3d2f670fbdac586e34b433783070cc16f54" + integrity sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ== + dependencies: + "@types/istanbul-lib-report" "*" + +"@types/jest@^29.5.12": + version "29.5.12" + resolved "https://registry.yarnpkg.com/@types/jest/-/jest-29.5.12.tgz#7f7dc6eb4cf246d2474ed78744b05d06ce025544" + integrity sha512-eDC8bTvT/QhYdxJAulQikueigY5AsdBRH2yDKW3yveW7svY3+DzN84/2NUgkw10RTiJbWqZrTtoGVdYlvFJdLw== + dependencies: + expect "^29.0.0" + pretty-format "^29.0.0" + +"@types/jsdom@^20.0.0": + version "20.0.1" + resolved "https://registry.yarnpkg.com/@types/jsdom/-/jsdom-20.0.1.tgz#07c14bc19bd2f918c1929541cdaacae894744808" + integrity sha512-d0r18sZPmMQr1eG35u12FZfhIXNrnsPU/g5wvRKCUf/tOGilKKwYMYGqh33BNR6ba+2gkHw1EUiHoN3mn7E5IQ== + dependencies: + "@types/node" "*" + "@types/tough-cookie" "*" + parse5 "^7.0.0" + +"@types/jsonld@^1.5.13": + version "1.5.13" + resolved "https://registry.yarnpkg.com/@types/jsonld/-/jsonld-1.5.13.tgz#32cb7bf8893ff811036b5025edaf626593a6f36f" + integrity sha512-n7fUU6W4kSYK8VQlf/LsE9kddBHPKhODoVOjsZswmve+2qLwBy6naWxs/EiuSZN9NU0N06Ra01FR+j87C62T0A== + +"@types/node@*": + version "20.12.10" + resolved "https://registry.yarnpkg.com/@types/node/-/node-20.12.10.tgz#8f0c3f12b0f075eee1fe20c1afb417e9765bef76" + integrity sha512-Eem5pH9pmWBHoGAT8Dr5fdc5rYA+4NAovdM4EktRPVAAiJhmWWfQrA0cFhAbOsQdSfIHjAud6YdkbL69+zSKjw== + dependencies: + undici-types "~5.26.4" + +"@types/prop-types@*": + version "15.7.12" + resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.12.tgz#12bb1e2be27293c1406acb6af1c3f3a1481d98c6" + integrity sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q== + +"@types/react-dom@^18.0.0": + version "18.3.0" + resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-18.3.0.tgz#0cbc818755d87066ab6ca74fbedb2547d74a82b0" + integrity sha512-EhwApuTmMBmXuFOikhQLIBUn6uFg81SwLMOAUgodJF14SOBOCMdU04gDoYi0WOJJHD144TL32z4yDqCW3dnkQg== + dependencies: + "@types/react" "*" + +"@types/react@*", "@types/react@^18.3.1": + version "18.3.1" + resolved "https://registry.yarnpkg.com/@types/react/-/react-18.3.1.tgz#fed43985caa834a2084d002e4771e15dfcbdbe8e" + integrity sha512-V0kuGBX3+prX+DQ/7r2qsv1NsdfnCLnTgnRJ1pYnxykBhGMz+qj+box5lq7XsO5mtZsBqpjwwTu/7wszPfMBcw== + dependencies: + "@types/prop-types" "*" + csstype "^3.0.2" + +"@types/stack-utils@^2.0.0": + version "2.0.3" + resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.3.tgz#6209321eb2c1712a7e7466422b8cb1fc0d9dd5d8" + integrity sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw== + +"@types/text-encoding@^0.0.39": + version "0.0.39" + resolved "https://registry.yarnpkg.com/@types/text-encoding/-/text-encoding-0.0.39.tgz#6f6436ceb843d96a2306a87dc7e2286e62c2177c" + integrity sha512-gRPvgL1aMgP6Pv92Rs310cJvVQ86DSF62E7K30g1FoGmmYWXoNuXT8PV835iAVeiAZkRwr2IW37KuyDn9ljmeA== + +"@types/tough-cookie@*": + version "4.0.5" + resolved "https://registry.yarnpkg.com/@types/tough-cookie/-/tough-cookie-4.0.5.tgz#cb6e2a691b70cb177c6e3ae9c1d2e8b2ea8cd304" + integrity sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA== + +"@types/yargs-parser@*": + version "21.0.3" + resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-21.0.3.tgz#815e30b786d2e8f0dcd85fd5bcf5e1a04d008f15" + integrity sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ== + +"@types/yargs@^17.0.8": + version "17.0.32" + resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-17.0.32.tgz#030774723a2f7faafebf645f4e5a48371dca6229" + integrity sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog== + dependencies: + "@types/yargs-parser" "*" + +abab@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.6.tgz#41b80f2c871d19686216b82309231cfd3cb3d291" + integrity sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA== + +abort-controller@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/abort-controller/-/abort-controller-3.0.0.tgz#eaf54d53b62bae4138e809ca225c8439a6efb392" + integrity sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg== + dependencies: + event-target-shim "^5.0.0" + +acorn-globals@^7.0.0: + version "7.0.1" + resolved "https://registry.yarnpkg.com/acorn-globals/-/acorn-globals-7.0.1.tgz#0dbf05c44fa7c94332914c02066d5beff62c40c3" + integrity sha512-umOSDSDrfHbTNPuNpC2NSnnA3LUrqpevPb4T9jRx4MagXNS0rs+gwiTcAvqCRmsD6utzsrzNt+ebm00SNWiC3Q== + dependencies: + acorn "^8.1.0" + acorn-walk "^8.0.2" + +acorn-walk@^8.0.2: + version "8.3.2" + resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.3.2.tgz#7703af9415f1b6db9315d6895503862e231d34aa" + integrity sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A== + +acorn@^8.1.0, acorn@^8.8.1: + version "8.11.3" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.11.3.tgz#71e0b14e13a4ec160724b38fb7b0f233b1b81d7a" + integrity sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg== + +agent-base@6: + version "6.0.2" + resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77" + integrity sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ== + dependencies: + debug "4" + +ansi-escapes@^4.2.1: + version "4.3.2" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e" + integrity sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ== + dependencies: + type-fest "^0.21.3" + +ansi-regex@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" + integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== + +ansi-styles@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" + integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== + dependencies: + color-convert "^1.9.0" + +ansi-styles@^4.0.0, ansi-styles@^4.1.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" + integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== + dependencies: + color-convert "^2.0.1" + +ansi-styles@^5.0.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-5.2.0.tgz#07449690ad45777d1924ac2abb2fc8895dba836b" + integrity sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA== + +anymatch@^3.0.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.3.tgz#790c58b19ba1720a84205b57c618d5ad8524973e" + integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw== + dependencies: + normalize-path "^3.0.0" + picomatch "^2.0.4" + +argparse@^1.0.7: + version "1.0.10" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" + integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== + dependencies: + sprintf-js "~1.0.2" + +aria-query@5.3.0, aria-query@^5.0.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/aria-query/-/aria-query-5.3.0.tgz#650c569e41ad90b51b3d7df5e5eed1c7549c103e" + integrity sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A== + dependencies: + dequal "^2.0.3" + +asynckit@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" + integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q== + +babel-jest@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-29.7.0.tgz#f4369919225b684c56085998ac63dbd05be020d5" + integrity sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg== + dependencies: + "@jest/transform" "^29.7.0" + "@types/babel__core" "^7.1.14" + babel-plugin-istanbul "^6.1.1" + babel-preset-jest "^29.6.3" + chalk "^4.0.0" + graceful-fs "^4.2.9" + slash "^3.0.0" + +babel-plugin-istanbul@^6.1.1: + version "6.1.1" + resolved "https://registry.yarnpkg.com/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz#fa88ec59232fd9b4e36dbbc540a8ec9a9b47da73" + integrity sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@istanbuljs/load-nyc-config" "^1.0.0" + "@istanbuljs/schema" "^0.1.2" + istanbul-lib-instrument "^5.0.4" + test-exclude "^6.0.0" + +babel-plugin-jest-hoist@^29.6.3: + version "29.6.3" + resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.6.3.tgz#aadbe943464182a8922c3c927c3067ff40d24626" + integrity sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg== + dependencies: + "@babel/template" "^7.3.3" + "@babel/types" "^7.3.3" + "@types/babel__core" "^7.1.14" + "@types/babel__traverse" "^7.0.6" + +babel-plugin-polyfill-corejs2@^0.4.10: + version "0.4.11" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.11.tgz#30320dfe3ffe1a336c15afdcdafd6fd615b25e33" + integrity sha512-sMEJ27L0gRHShOh5G54uAAPaiCOygY/5ratXuiyb2G46FmlSpc9eFCzYVyDiPxfNbwzA7mYahmjQc5q+CZQ09Q== + dependencies: + "@babel/compat-data" "^7.22.6" + "@babel/helper-define-polyfill-provider" "^0.6.2" + semver "^6.3.1" + +babel-plugin-polyfill-corejs3@^0.10.4: + version "0.10.4" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.10.4.tgz#789ac82405ad664c20476d0233b485281deb9c77" + integrity sha512-25J6I8NGfa5YkCDogHRID3fVCadIR8/pGl1/spvCkzb6lVn6SR3ojpx9nOn9iEBcUsjY24AmdKm5khcfKdylcg== + dependencies: + "@babel/helper-define-polyfill-provider" "^0.6.1" + core-js-compat "^3.36.1" + +babel-plugin-polyfill-regenerator@^0.6.1: + version "0.6.2" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.2.tgz#addc47e240edd1da1058ebda03021f382bba785e" + integrity sha512-2R25rQZWP63nGwaAswvDazbPXfrM3HwVoBXK6HcqeKrSrL/JqcC/rDcf95l4r7LXLyxDXc8uQDa064GubtCABg== + dependencies: + "@babel/helper-define-polyfill-provider" "^0.6.2" + +babel-preset-current-node-syntax@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz#b4399239b89b2a011f9ddbe3e4f401fc40cff73b" + integrity sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ== + dependencies: + "@babel/plugin-syntax-async-generators" "^7.8.4" + "@babel/plugin-syntax-bigint" "^7.8.3" + "@babel/plugin-syntax-class-properties" "^7.8.3" + "@babel/plugin-syntax-import-meta" "^7.8.3" + "@babel/plugin-syntax-json-strings" "^7.8.3" + "@babel/plugin-syntax-logical-assignment-operators" "^7.8.3" + "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" + "@babel/plugin-syntax-numeric-separator" "^7.8.3" + "@babel/plugin-syntax-object-rest-spread" "^7.8.3" + "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" + "@babel/plugin-syntax-optional-chaining" "^7.8.3" + "@babel/plugin-syntax-top-level-await" "^7.8.3" + +babel-preset-jest@^29.6.3: + version "29.6.3" + resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-29.6.3.tgz#fa05fa510e7d493896d7b0dd2033601c840f171c" + integrity sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA== + dependencies: + babel-plugin-jest-hoist "^29.6.3" + babel-preset-current-node-syntax "^1.0.0" + +balanced-match@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" + integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== + +blakejs@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/blakejs/-/blakejs-1.2.1.tgz#5057e4206eadb4a97f7c0b6e197a505042fc3814" + integrity sha512-QXUSXI3QVc/gJME0dBpXrag1kbzOqCjCX8/b54ntNyW6sjtoqxqRk3LTmXzaJoh71zMsDCjM+47jS7XiwN/+fQ== + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +braces@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" + integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== + dependencies: + fill-range "^7.0.1" + +browserslist@^4.22.2, browserslist@^4.23.0: + version "4.23.0" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.23.0.tgz#8f3acc2bbe73af7213399430890f86c63a5674ab" + integrity sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ== + dependencies: + caniuse-lite "^1.0.30001587" + electron-to-chromium "^1.4.668" + node-releases "^2.0.14" + update-browserslist-db "^1.0.13" + +bs-logger@0.x: + version "0.2.6" + resolved "https://registry.yarnpkg.com/bs-logger/-/bs-logger-0.2.6.tgz#eb7d365307a72cf974cc6cda76b68354ad336bd8" + integrity sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog== + dependencies: + fast-json-stable-stringify "2.x" + +bser@2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/bser/-/bser-2.1.1.tgz#e6787da20ece9d07998533cfd9de6f5c38f4bc05" + integrity sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ== + dependencies: + node-int64 "^0.4.0" + +buffer-from@^1.0.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" + integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== + +callsites@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" + integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== + +camelcase@^5.3.1: + version "5.3.1" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" + integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== + +camelcase@^6.2.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a" + integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== + +caniuse-lite@^1.0.30001587: + version "1.0.30001616" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001616.tgz#4342712750d35f71ebba9fcac65e2cf8870013c3" + integrity sha512-RHVYKov7IcdNjVHJFNY/78RdG4oGVjbayxv8u5IO74Wv7Hlq4PnJE6mo/OjFijjVFNy5ijnCt6H3IIo4t+wfEw== + +canonicalize@^1.0.1: + version "1.0.8" + resolved "https://registry.yarnpkg.com/canonicalize/-/canonicalize-1.0.8.tgz#24d1f1a00ed202faafd9bf8e63352cd4450c6df1" + integrity sha512-0CNTVCLZggSh7bc5VkX5WWPWO+cyZbNd07IHIsSXLia/eAq+r836hgk+8BKoEh7949Mda87VUOitx5OddVj64A== + +chalk@^2.4.2: + version "2.4.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" + integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.0" + +chalk@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-3.0.0.tgz#3f73c2bf526591f574cc492c51e2456349f844e4" + integrity sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + +chalk@^4.0.0, chalk@^4.1.0: + version "4.1.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" + integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + +char-regex@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/char-regex/-/char-regex-1.0.2.tgz#d744358226217f981ed58f479b1d6bcc29545dcf" + integrity sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw== + +ci-info@^3.2.0: + version "3.9.0" + resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.9.0.tgz#4279a62028a7b1f262f3473fc9605f5e218c59b4" + integrity sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ== + +cjs-module-lexer@^1.0.0: + version "1.3.1" + resolved "https://registry.yarnpkg.com/cjs-module-lexer/-/cjs-module-lexer-1.3.1.tgz#c485341ae8fd999ca4ee5af2d7a1c9ae01e0099c" + integrity sha512-a3KdPAANPbNE4ZUv9h6LckSl9zLsYOP4MBmhIPkRaeyybt+r4UghLvq+xw/YwUcC1gqylCkL4rdVs3Lwupjm4Q== + +cliui@^8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-8.0.1.tgz#0c04b075db02cbfe60dc8e6cf2f5486b1a3608aa" + integrity sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ== + dependencies: + string-width "^4.2.0" + strip-ansi "^6.0.1" + wrap-ansi "^7.0.0" + +co@^4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" + integrity sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ== + +collect-v8-coverage@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/collect-v8-coverage/-/collect-v8-coverage-1.0.2.tgz#c0b29bcd33bcd0779a1344c2136051e6afd3d9e9" + integrity sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q== + +color-convert@^1.9.0: + version "1.9.3" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" + integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== + dependencies: + color-name "1.1.3" + +color-convert@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" + integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== + dependencies: + color-name "~1.1.4" + +color-name@1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" + integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== + +color-name@~1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + +combined-stream@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" + integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== + dependencies: + delayed-stream "~1.0.0" + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== + +convert-source-map@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-2.0.0.tgz#4b560f649fc4e918dd0ab75cf4961e8bc882d82a" + integrity sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg== + +core-js-compat@^3.31.0, core-js-compat@^3.36.1: + version "3.37.0" + resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.37.0.tgz#d9570e544163779bb4dff1031c7972f44918dc73" + integrity sha512-vYq4L+T8aS5UuFg4UwDhc7YNRWVeVZwltad9C/jV3R2LgVOpS9BDr7l/WL6BN0dbV3k1XejPTHqqEzJgsa0frA== + dependencies: + browserslist "^4.23.0" + +create-jest@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/create-jest/-/create-jest-29.7.0.tgz#a355c5b3cb1e1af02ba177fe7afd7feee49a5320" + integrity sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q== + dependencies: + "@jest/types" "^29.6.3" + chalk "^4.0.0" + exit "^0.1.2" + graceful-fs "^4.2.9" + jest-config "^29.7.0" + jest-util "^29.7.0" + prompts "^2.0.1" + +cross-spawn@^7.0.3: + version "7.0.3" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" + integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== + dependencies: + path-key "^3.1.0" + shebang-command "^2.0.0" + which "^2.0.1" + +css.escape@^1.5.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/css.escape/-/css.escape-1.5.1.tgz#42e27d4fa04ae32f931a4b4d4191fa9cddee97cb" + integrity sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg== + +cssom@^0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.5.0.tgz#d254fa92cd8b6fbd83811b9fbaed34663cc17c36" + integrity sha512-iKuQcq+NdHqlAcwUY0o/HL69XQrUaQdMjmStJ8JFmUaiiQErlhrmuigkg/CU4E2J0IyUKUrMAgl36TvN67MqTw== + +cssom@~0.3.6: + version "0.3.8" + resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.3.8.tgz#9f1276f5b2b463f2114d3f2c75250af8c1a36f4a" + integrity sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg== + +cssstyle@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/cssstyle/-/cssstyle-2.3.0.tgz#ff665a0ddbdc31864b09647f34163443d90b0852" + integrity sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A== + dependencies: + cssom "~0.3.6" + +csstype@^3.0.2: + version "3.1.3" + resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.3.tgz#d80ff294d114fb0e6ac500fbf85b60137d7eff81" + integrity sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw== + +data-uri-to-buffer@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz#d8feb2b2881e6a4f58c2e08acfd0e2834e26222e" + integrity sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A== + +data-urls@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/data-urls/-/data-urls-3.0.2.tgz#9cf24a477ae22bcef5cd5f6f0bfbc1d2d3be9143" + integrity sha512-Jy/tj3ldjZJo63sVAvg6LHt2mHvl4V6AgRAmNDtLdm7faqtsx+aJG42rsyCo9JCoRVKwPFzKlIPx3DIibwSIaQ== + dependencies: + abab "^2.0.6" + whatwg-mimetype "^3.0.0" + whatwg-url "^11.0.0" + +debug@4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1: + version "4.3.4" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" + integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== + dependencies: + ms "2.1.2" + +decimal.js@^10.4.2: + version "10.4.3" + resolved "https://registry.yarnpkg.com/decimal.js/-/decimal.js-10.4.3.tgz#1044092884d245d1b7f65725fa4ad4c6f781cc23" + integrity sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA== + +dedent@^1.0.0: + version "1.5.3" + resolved "https://registry.yarnpkg.com/dedent/-/dedent-1.5.3.tgz#99aee19eb9bae55a67327717b6e848d0bf777e5a" + integrity sha512-NHQtfOOW68WD8lgypbLA5oT+Bt0xXJhiYvoR6SmmNXZfpzOGXwdKWmcwG8N7PwVVWV3eF/68nmD9BaJSsTBhyQ== + +deepmerge@^4.2.2: + version "4.3.1" + resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.3.1.tgz#44b5f2147cd3b00d4b56137685966f26fd25dd4a" + integrity sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A== + +delayed-stream@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" + integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ== + +dequal@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/dequal/-/dequal-2.0.3.tgz#2644214f1997d39ed0ee0ece72335490a7ac67be" + integrity sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA== + +detect-newline@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-3.1.0.tgz#576f5dfc63ae1a192ff192d8ad3af6308991b651" + integrity sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA== + +diff-sequences@^29.6.3: + version "29.6.3" + resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-29.6.3.tgz#4deaf894d11407c51efc8418012f9e70b84ea921" + integrity sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q== + +dom-accessibility-api@^0.5.9: + version "0.5.16" + resolved "https://registry.yarnpkg.com/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz#5a7429e6066eb3664d911e33fb0e45de8eb08453" + integrity sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg== + +dom-accessibility-api@^0.6.3: + version "0.6.3" + resolved "https://registry.yarnpkg.com/dom-accessibility-api/-/dom-accessibility-api-0.6.3.tgz#993e925cc1d73f2c662e7d75dd5a5445259a8fd8" + integrity sha512-7ZgogeTnjuHbo+ct10G9Ffp0mif17idi0IyWNVA/wcwcm7NPOD/WEHVP3n7n3MhXqxoIYm8d6MuZohYWIZ4T3w== + +domexception@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/domexception/-/domexception-4.0.0.tgz#4ad1be56ccadc86fc76d033353999a8037d03673" + integrity sha512-A2is4PLG+eeSfoTMA95/s4pvAoSo2mKtiM5jlHkAVewmiO8ISFTFKZjH7UAM1Atli/OT/7JHOrJRJiMKUZKYBw== + dependencies: + webidl-conversions "^7.0.0" + +electron-to-chromium@^1.4.668: + version "1.4.757" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.757.tgz#45f7c9341b538f8c4b9ca8af9692e0ed1a776a44" + integrity sha512-jftDaCknYSSt/+KKeXzH3LX5E2CvRLm75P3Hj+J/dv3CL0qUYcOt13d5FN1NiL5IJbbhzHrb3BomeG2tkSlZmw== + +emittery@^0.13.1: + version "0.13.1" + resolved "https://registry.yarnpkg.com/emittery/-/emittery-0.13.1.tgz#c04b8c3457490e0847ae51fced3af52d338e3dad" + integrity sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ== + +emoji-regex@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" + integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== + +entities@^4.4.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/entities/-/entities-4.5.0.tgz#5d268ea5e7113ec74c4d033b79ea5a35a488fb48" + integrity sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw== + +error-ex@^1.3.1: + version "1.3.2" + resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" + integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== + dependencies: + is-arrayish "^0.2.1" + +escalade@^3.1.1, escalade@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.2.tgz#54076e9ab29ea5bf3d8f1ed62acffbb88272df27" + integrity sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA== + +escape-string-regexp@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== + +escape-string-regexp@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz#a30304e99daa32e23b2fd20f51babd07cffca344" + integrity sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w== + +escodegen@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-2.1.0.tgz#ba93bbb7a43986d29d6041f99f5262da773e2e17" + integrity sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w== + dependencies: + esprima "^4.0.1" + estraverse "^5.2.0" + esutils "^2.0.2" + optionalDependencies: + source-map "~0.6.1" + +esprima@^4.0.0, esprima@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" + integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== + +estraverse@^5.2.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" + integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== + +esutils@^2.0.2: + version "2.0.3" + resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" + integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== + +event-target-shim@^5.0.0: + version "5.0.1" + resolved "https://registry.yarnpkg.com/event-target-shim/-/event-target-shim-5.0.1.tgz#5d4d3ebdf9583d63a5333ce2deb7480ab2b05789" + integrity sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ== + +execa@^5.0.0: + version "5.1.1" + resolved "https://registry.yarnpkg.com/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd" + integrity sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg== + dependencies: + cross-spawn "^7.0.3" + get-stream "^6.0.0" + human-signals "^2.1.0" + is-stream "^2.0.0" + merge-stream "^2.0.0" + npm-run-path "^4.0.1" + onetime "^5.1.2" + signal-exit "^3.0.3" + strip-final-newline "^2.0.0" + +exit@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" + integrity sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ== + +expect@^29.0.0, expect@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/expect/-/expect-29.7.0.tgz#578874590dcb3214514084c08115d8aee61e11bc" + integrity sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw== + dependencies: + "@jest/expect-utils" "^29.7.0" + jest-get-type "^29.6.3" + jest-matcher-utils "^29.7.0" + jest-message-util "^29.7.0" + jest-util "^29.7.0" + +fast-json-stable-stringify@2.x, fast-json-stable-stringify@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" + integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== + +fb-watchman@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/fb-watchman/-/fb-watchman-2.0.2.tgz#e9524ee6b5c77e9e5001af0f85f3adbb8623255c" + integrity sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA== + dependencies: + bser "2.1.1" + +fetch-blob@^3.1.2, fetch-blob@^3.1.4: + version "3.2.0" + resolved "https://registry.yarnpkg.com/fetch-blob/-/fetch-blob-3.2.0.tgz#f09b8d4bbd45adc6f0c20b7e787e793e309dcce9" + integrity sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ== + dependencies: + node-domexception "^1.0.0" + web-streams-polyfill "^3.0.3" + +fill-range@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" + integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== + dependencies: + to-regex-range "^5.0.1" + +find-up@^4.0.0, find-up@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19" + integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw== + dependencies: + locate-path "^5.0.0" + path-exists "^4.0.0" + +form-data@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452" + integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.8" + mime-types "^2.1.12" + +formdata-polyfill@^4.0.10: + version "4.0.10" + resolved "https://registry.yarnpkg.com/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz#24807c31c9d402e002ab3d8c720144ceb8848423" + integrity sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g== + dependencies: + fetch-blob "^3.1.2" + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== + +fsevents@^2.3.2: + version "2.3.3" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" + integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== + +function-bind@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c" + integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== + +gensync@^1.0.0-beta.2: + version "1.0.0-beta.2" + resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" + integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== + +get-caller-file@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" + integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== + +get-package-type@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/get-package-type/-/get-package-type-0.1.0.tgz#8de2d803cff44df3bc6c456e6668b36c3926e11a" + integrity sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q== + +get-stream@^6.0.0: + version "6.0.1" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" + integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== + +glob@^7.1.3, glob@^7.1.4: + version "7.2.3" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" + integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.1.1" + once "^1.3.0" + path-is-absolute "^1.0.0" + +globals@^11.1.0: + version "11.12.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" + integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== + +graceful-fs@^4.2.9: + version "4.2.11" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" + integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== + +has-flag@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" + integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw== + +has-flag@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" + integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== + +hasown@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003" + integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ== + dependencies: + function-bind "^1.1.2" + +html-encoding-sniffer@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/html-encoding-sniffer/-/html-encoding-sniffer-3.0.0.tgz#2cb1a8cf0db52414776e5b2a7a04d5dd98158de9" + integrity sha512-oWv4T4yJ52iKrufjnyZPkrN0CH3QnrUqdB6In1g5Fe1mia8GmF36gnfNySxoZtxD5+NmYw1EElVXiBk93UeskA== + dependencies: + whatwg-encoding "^2.0.0" + +html-escaper@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/html-escaper/-/html-escaper-2.0.2.tgz#dfd60027da36a36dfcbe236262c00a5822681453" + integrity sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg== + +http-proxy-agent@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz#5129800203520d434f142bc78ff3c170800f2b43" + integrity sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w== + dependencies: + "@tootallnate/once" "2" + agent-base "6" + debug "4" + +https-proxy-agent@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz#c59ef224a04fe8b754f3db0063a25ea30d0005d6" + integrity sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA== + dependencies: + agent-base "6" + debug "4" + +human-signals@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0" + integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw== + +iconv-lite@0.6.3: + version "0.6.3" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.3.tgz#a52f80bf38da1952eb5c681790719871a1a72501" + integrity sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw== + dependencies: + safer-buffer ">= 2.1.2 < 3.0.0" + +import-local@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/import-local/-/import-local-3.1.0.tgz#b4479df8a5fd44f6cdce24070675676063c95cb4" + integrity sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg== + dependencies: + pkg-dir "^4.2.0" + resolve-cwd "^3.0.0" + +imurmurhash@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" + integrity sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA== + +indent-string@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-4.0.0.tgz#624f8f4497d619b2d9768531d58f4122854d7251" + integrity sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg== + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +is-arrayish@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" + integrity sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg== + +is-core-module@^2.13.0: + version "2.13.1" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.13.1.tgz#ad0d7532c6fea9da1ebdc82742d74525c6273384" + integrity sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw== + dependencies: + hasown "^2.0.0" + +is-fullwidth-code-point@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" + integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== + +is-generator-fn@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-generator-fn/-/is-generator-fn-2.1.0.tgz#7d140adc389aaf3011a8f2a2a4cfa6faadffb118" + integrity sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ== + +is-number@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" + integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== + +is-potential-custom-element-name@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz#171ed6f19e3ac554394edf78caa05784a45bebb5" + integrity sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ== + +is-stream@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077" + integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg== + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== + +istanbul-lib-coverage@^3.0.0, istanbul-lib-coverage@^3.2.0: + version "3.2.2" + resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz#2d166c4b0644d43a39f04bf6c2edd1e585f31756" + integrity sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg== + +istanbul-lib-instrument@^5.0.4: + version "5.2.1" + resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz#d10c8885c2125574e1c231cacadf955675e1ce3d" + integrity sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg== + dependencies: + "@babel/core" "^7.12.3" + "@babel/parser" "^7.14.7" + "@istanbuljs/schema" "^0.1.2" + istanbul-lib-coverage "^3.2.0" + semver "^6.3.0" + +istanbul-lib-instrument@^6.0.0: + version "6.0.2" + resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.2.tgz#91655936cf7380e4e473383081e38478b69993b1" + integrity sha512-1WUsZ9R1lA0HtBSohTkm39WTPlNKSJ5iFk7UwqXkBLoHQT+hfqPsfsTDVuZdKGaBwn7din9bS7SsnoAr943hvw== + dependencies: + "@babel/core" "^7.23.9" + "@babel/parser" "^7.23.9" + "@istanbuljs/schema" "^0.1.3" + istanbul-lib-coverage "^3.2.0" + semver "^7.5.4" + +istanbul-lib-report@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz#908305bac9a5bd175ac6a74489eafd0fc2445a7d" + integrity sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw== + dependencies: + istanbul-lib-coverage "^3.0.0" + make-dir "^4.0.0" + supports-color "^7.1.0" + +istanbul-lib-source-maps@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz#895f3a709fcfba34c6de5a42939022f3e4358551" + integrity sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw== + dependencies: + debug "^4.1.1" + istanbul-lib-coverage "^3.0.0" + source-map "^0.6.1" + +istanbul-reports@^3.1.3: + version "3.1.7" + resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-3.1.7.tgz#daed12b9e1dca518e15c056e1e537e741280fa0b" + integrity sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g== + dependencies: + html-escaper "^2.0.0" + istanbul-lib-report "^3.0.0" + +jest-changed-files@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-29.7.0.tgz#1c06d07e77c78e1585d020424dedc10d6e17ac3a" + integrity sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w== + dependencies: + execa "^5.0.0" + jest-util "^29.7.0" + p-limit "^3.1.0" + +jest-circus@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-circus/-/jest-circus-29.7.0.tgz#b6817a45fcc835d8b16d5962d0c026473ee3668a" + integrity sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw== + dependencies: + "@jest/environment" "^29.7.0" + "@jest/expect" "^29.7.0" + "@jest/test-result" "^29.7.0" + "@jest/types" "^29.6.3" + "@types/node" "*" + chalk "^4.0.0" + co "^4.6.0" + dedent "^1.0.0" + is-generator-fn "^2.0.0" + jest-each "^29.7.0" + jest-matcher-utils "^29.7.0" + jest-message-util "^29.7.0" + jest-runtime "^29.7.0" + jest-snapshot "^29.7.0" + jest-util "^29.7.0" + p-limit "^3.1.0" + pretty-format "^29.7.0" + pure-rand "^6.0.0" + slash "^3.0.0" + stack-utils "^2.0.3" + +jest-cli@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-29.7.0.tgz#5592c940798e0cae677eec169264f2d839a37995" + integrity sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg== + dependencies: + "@jest/core" "^29.7.0" + "@jest/test-result" "^29.7.0" + "@jest/types" "^29.6.3" + chalk "^4.0.0" + create-jest "^29.7.0" + exit "^0.1.2" + import-local "^3.0.2" + jest-config "^29.7.0" + jest-util "^29.7.0" + jest-validate "^29.7.0" + yargs "^17.3.1" + +jest-config@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-29.7.0.tgz#bcbda8806dbcc01b1e316a46bb74085a84b0245f" + integrity sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ== + dependencies: + "@babel/core" "^7.11.6" + "@jest/test-sequencer" "^29.7.0" + "@jest/types" "^29.6.3" + babel-jest "^29.7.0" + chalk "^4.0.0" + ci-info "^3.2.0" + deepmerge "^4.2.2" + glob "^7.1.3" + graceful-fs "^4.2.9" + jest-circus "^29.7.0" + jest-environment-node "^29.7.0" + jest-get-type "^29.6.3" + jest-regex-util "^29.6.3" + jest-resolve "^29.7.0" + jest-runner "^29.7.0" + jest-util "^29.7.0" + jest-validate "^29.7.0" + micromatch "^4.0.4" + parse-json "^5.2.0" + pretty-format "^29.7.0" + slash "^3.0.0" + strip-json-comments "^3.1.1" + +jest-diff@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-29.7.0.tgz#017934a66ebb7ecf6f205e84699be10afd70458a" + integrity sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw== + dependencies: + chalk "^4.0.0" + diff-sequences "^29.6.3" + jest-get-type "^29.6.3" + pretty-format "^29.7.0" + +jest-docblock@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-29.7.0.tgz#8fddb6adc3cdc955c93e2a87f61cfd350d5d119a" + integrity sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g== + dependencies: + detect-newline "^3.0.0" + +jest-each@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-29.7.0.tgz#162a9b3f2328bdd991beaabffbb74745e56577d1" + integrity sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ== + dependencies: + "@jest/types" "^29.6.3" + chalk "^4.0.0" + jest-get-type "^29.6.3" + jest-util "^29.7.0" + pretty-format "^29.7.0" + +jest-environment-jsdom@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-environment-jsdom/-/jest-environment-jsdom-29.7.0.tgz#d206fa3551933c3fd519e5dfdb58a0f5139a837f" + integrity sha512-k9iQbsf9OyOfdzWH8HDmrRT0gSIcX+FLNW7IQq94tFX0gynPwqDTW0Ho6iMVNjGz/nb+l/vW3dWM2bbLLpkbXA== + dependencies: + "@jest/environment" "^29.7.0" + "@jest/fake-timers" "^29.7.0" + "@jest/types" "^29.6.3" + "@types/jsdom" "^20.0.0" + "@types/node" "*" + jest-mock "^29.7.0" + jest-util "^29.7.0" + jsdom "^20.0.0" + +jest-environment-node@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-29.7.0.tgz#0b93e111dda8ec120bc8300e6d1fb9576e164376" + integrity sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw== + dependencies: + "@jest/environment" "^29.7.0" + "@jest/fake-timers" "^29.7.0" + "@jest/types" "^29.6.3" + "@types/node" "*" + jest-mock "^29.7.0" + jest-util "^29.7.0" + +jest-get-type@^29.6.3: + version "29.6.3" + resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-29.6.3.tgz#36f499fdcea197c1045a127319c0481723908fd1" + integrity sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw== + +jest-haste-map@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-29.7.0.tgz#3c2396524482f5a0506376e6c858c3bbcc17b104" + integrity sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA== + dependencies: + "@jest/types" "^29.6.3" + "@types/graceful-fs" "^4.1.3" + "@types/node" "*" + anymatch "^3.0.3" + fb-watchman "^2.0.0" + graceful-fs "^4.2.9" + jest-regex-util "^29.6.3" + jest-util "^29.7.0" + jest-worker "^29.7.0" + micromatch "^4.0.4" + walker "^1.0.8" + optionalDependencies: + fsevents "^2.3.2" + +jest-leak-detector@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-29.7.0.tgz#5b7ec0dadfdfec0ca383dc9aa016d36b5ea4c728" + integrity sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw== + dependencies: + jest-get-type "^29.6.3" + pretty-format "^29.7.0" + +jest-matcher-utils@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz#ae8fec79ff249fd592ce80e3ee474e83a6c44f12" + integrity sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g== + dependencies: + chalk "^4.0.0" + jest-diff "^29.7.0" + jest-get-type "^29.6.3" + pretty-format "^29.7.0" + +jest-message-util@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-29.7.0.tgz#8bc392e204e95dfe7564abbe72a404e28e51f7f3" + integrity sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w== + dependencies: + "@babel/code-frame" "^7.12.13" + "@jest/types" "^29.6.3" + "@types/stack-utils" "^2.0.0" + chalk "^4.0.0" + graceful-fs "^4.2.9" + micromatch "^4.0.4" + pretty-format "^29.7.0" + slash "^3.0.0" + stack-utils "^2.0.3" + +jest-mock@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-29.7.0.tgz#4e836cf60e99c6fcfabe9f99d017f3fdd50a6347" + integrity sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw== + dependencies: + "@jest/types" "^29.6.3" + "@types/node" "*" + jest-util "^29.7.0" + +jest-pnp-resolver@^1.2.2: + version "1.2.3" + resolved "https://registry.yarnpkg.com/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz#930b1546164d4ad5937d5540e711d4d38d4cad2e" + integrity sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w== + +jest-regex-util@^29.6.3: + version "29.6.3" + resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-29.6.3.tgz#4a556d9c776af68e1c5f48194f4d0327d24e8a52" + integrity sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg== + +jest-resolve-dependencies@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-29.7.0.tgz#1b04f2c095f37fc776ff40803dc92921b1e88428" + integrity sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA== + dependencies: + jest-regex-util "^29.6.3" + jest-snapshot "^29.7.0" + +jest-resolve@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-29.7.0.tgz#64d6a8992dd26f635ab0c01e5eef4399c6bcbc30" + integrity sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA== + dependencies: + chalk "^4.0.0" + graceful-fs "^4.2.9" + jest-haste-map "^29.7.0" + jest-pnp-resolver "^1.2.2" + jest-util "^29.7.0" + jest-validate "^29.7.0" + resolve "^1.20.0" + resolve.exports "^2.0.0" + slash "^3.0.0" + +jest-runner@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-29.7.0.tgz#809af072d408a53dcfd2e849a4c976d3132f718e" + integrity sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ== + dependencies: + "@jest/console" "^29.7.0" + "@jest/environment" "^29.7.0" + "@jest/test-result" "^29.7.0" + "@jest/transform" "^29.7.0" + "@jest/types" "^29.6.3" + "@types/node" "*" + chalk "^4.0.0" + emittery "^0.13.1" + graceful-fs "^4.2.9" + jest-docblock "^29.7.0" + jest-environment-node "^29.7.0" + jest-haste-map "^29.7.0" + jest-leak-detector "^29.7.0" + jest-message-util "^29.7.0" + jest-resolve "^29.7.0" + jest-runtime "^29.7.0" + jest-util "^29.7.0" + jest-watcher "^29.7.0" + jest-worker "^29.7.0" + p-limit "^3.1.0" + source-map-support "0.5.13" + +jest-runtime@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-29.7.0.tgz#efecb3141cf7d3767a3a0cc8f7c9990587d3d817" + integrity sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ== + dependencies: + "@jest/environment" "^29.7.0" + "@jest/fake-timers" "^29.7.0" + "@jest/globals" "^29.7.0" + "@jest/source-map" "^29.6.3" + "@jest/test-result" "^29.7.0" + "@jest/transform" "^29.7.0" + "@jest/types" "^29.6.3" + "@types/node" "*" + chalk "^4.0.0" + cjs-module-lexer "^1.0.0" + collect-v8-coverage "^1.0.0" + glob "^7.1.3" + graceful-fs "^4.2.9" + jest-haste-map "^29.7.0" + jest-message-util "^29.7.0" + jest-mock "^29.7.0" + jest-regex-util "^29.6.3" + jest-resolve "^29.7.0" + jest-snapshot "^29.7.0" + jest-util "^29.7.0" + slash "^3.0.0" + strip-bom "^4.0.0" + +jest-snapshot@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-29.7.0.tgz#c2c574c3f51865da1bb329036778a69bf88a6be5" + integrity sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw== + dependencies: + "@babel/core" "^7.11.6" + "@babel/generator" "^7.7.2" + "@babel/plugin-syntax-jsx" "^7.7.2" + "@babel/plugin-syntax-typescript" "^7.7.2" + "@babel/types" "^7.3.3" + "@jest/expect-utils" "^29.7.0" + "@jest/transform" "^29.7.0" + "@jest/types" "^29.6.3" + babel-preset-current-node-syntax "^1.0.0" + chalk "^4.0.0" + expect "^29.7.0" + graceful-fs "^4.2.9" + jest-diff "^29.7.0" + jest-get-type "^29.6.3" + jest-matcher-utils "^29.7.0" + jest-message-util "^29.7.0" + jest-util "^29.7.0" + natural-compare "^1.4.0" + pretty-format "^29.7.0" + semver "^7.5.3" + +jest-util@^29.0.0, jest-util@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-29.7.0.tgz#23c2b62bfb22be82b44de98055802ff3710fc0bc" + integrity sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA== + dependencies: + "@jest/types" "^29.6.3" + "@types/node" "*" + chalk "^4.0.0" + ci-info "^3.2.0" + graceful-fs "^4.2.9" + picomatch "^2.2.3" + +jest-validate@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-29.7.0.tgz#7bf705511c64da591d46b15fce41400d52147d9c" + integrity sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw== + dependencies: + "@jest/types" "^29.6.3" + camelcase "^6.2.0" + chalk "^4.0.0" + jest-get-type "^29.6.3" + leven "^3.1.0" + pretty-format "^29.7.0" + +jest-watcher@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-29.7.0.tgz#7810d30d619c3a62093223ce6bb359ca1b28a2f2" + integrity sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g== + dependencies: + "@jest/test-result" "^29.7.0" + "@jest/types" "^29.6.3" + "@types/node" "*" + ansi-escapes "^4.2.1" + chalk "^4.0.0" + emittery "^0.13.1" + jest-util "^29.7.0" + string-length "^4.0.1" + +jest-worker@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-29.7.0.tgz#acad073acbbaeb7262bd5389e1bcf43e10058d4a" + integrity sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw== + dependencies: + "@types/node" "*" + jest-util "^29.7.0" + merge-stream "^2.0.0" + supports-color "^8.0.0" + +jest@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest/-/jest-29.7.0.tgz#994676fc24177f088f1c5e3737f5697204ff2613" + integrity sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw== + dependencies: + "@jest/core" "^29.7.0" + "@jest/types" "^29.6.3" + import-local "^3.0.2" + jest-cli "^29.7.0" + +"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" + integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== + +js-yaml@^3.13.1: + version "3.14.1" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.1.tgz#dae812fdb3825fa306609a8717383c50c36a0537" + integrity sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g== + dependencies: + argparse "^1.0.7" + esprima "^4.0.0" + +jsdom@^20.0.0: + version "20.0.3" + resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-20.0.3.tgz#886a41ba1d4726f67a8858028c99489fed6ad4db" + integrity sha512-SYhBvTh89tTfCD/CRdSOm13mOBa42iTaTyfyEWBdKcGdPxPtLFBXuHR8XHb33YNYaP+lLbmSvBTsnoesCNJEsQ== + dependencies: + abab "^2.0.6" + acorn "^8.8.1" + acorn-globals "^7.0.0" + cssom "^0.5.0" + cssstyle "^2.3.0" + data-urls "^3.0.2" + decimal.js "^10.4.2" + domexception "^4.0.0" + escodegen "^2.0.0" + form-data "^4.0.0" + html-encoding-sniffer "^3.0.0" + http-proxy-agent "^5.0.0" + https-proxy-agent "^5.0.1" + is-potential-custom-element-name "^1.0.1" + nwsapi "^2.2.2" + parse5 "^7.1.1" + saxes "^6.0.0" + symbol-tree "^3.2.4" + tough-cookie "^4.1.2" + 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.11.0" + xml-name-validator "^4.0.0" + +jsesc@^2.5.1: + version "2.5.2" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" + integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== + +jsesc@~0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" + integrity sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA== + +json-parse-even-better-errors@^2.3.0: + version "2.3.1" + resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d" + integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w== + +json5@^2.2.3: + version "2.2.3" + resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283" + integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg== + +jsonld@^8.3.2: + version "8.3.2" + resolved "https://registry.yarnpkg.com/jsonld/-/jsonld-8.3.2.tgz#7033f8994aed346b536e9046025f7f1fe9669934" + integrity sha512-MwBbq95szLwt8eVQ1Bcfwmgju/Y5P2GdtlHE2ncyfuYjIdEhluUVyj1eudacf1mOkWIoS9GpDBTECqhmq7EOaA== + dependencies: + "@digitalbazaar/http-client" "^3.4.1" + canonicalize "^1.0.1" + lru-cache "^6.0.0" + rdf-canonize "^3.4.0" + +kleur@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e" + integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w== + +ky-universal@^0.11.0: + version "0.11.0" + resolved "https://registry.yarnpkg.com/ky-universal/-/ky-universal-0.11.0.tgz#f5edf857865aaaea416a1968222148ad7d9e4017" + integrity sha512-65KyweaWvk+uKKkCrfAf+xqN2/epw1IJDtlyCPxYffFCMR8u1sp2U65NtWpnozYfZxQ6IUzIlvUcw+hQ82U2Xw== + dependencies: + abort-controller "^3.0.0" + node-fetch "^3.2.10" + +ky@^0.33.3: + version "0.33.3" + resolved "https://registry.yarnpkg.com/ky/-/ky-0.33.3.tgz#bf1ad322a3f2c3428c13cfa4b3af95e6c4a2f543" + integrity sha512-CasD9OCEQSFIam2U8efFK81Yeg8vNMTBUqtMOHlrcWQHqUX3HeCl9Dr31u4toV7emlH8Mymk5+9p0lL6mKb/Xw== + +leven@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/leven/-/leven-3.1.0.tgz#77891de834064cccba82ae7842bb6b14a13ed7f2" + integrity sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A== + +lines-and-columns@^1.1.6: + version "1.2.4" + resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" + integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== + +locate-path@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0" + integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g== + dependencies: + p-locate "^4.1.0" + +lodash.debounce@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af" + integrity sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow== + +lodash.memoize@4.x: + version "4.1.2" + resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe" + integrity sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag== + +lodash@^4.17.21: + version "4.17.21" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" + integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== + +loose-envify@^1.1.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" + integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== + dependencies: + js-tokens "^3.0.0 || ^4.0.0" + +lru-cache@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" + integrity sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w== + dependencies: + yallist "^3.0.2" + +lru-cache@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" + integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== + dependencies: + yallist "^4.0.0" + +lz-string@^1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/lz-string/-/lz-string-1.5.0.tgz#c1ab50f77887b712621201ba9fd4e3a6ed099941" + integrity sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ== + +make-dir@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-4.0.0.tgz#c3c2307a771277cd9638305f915c29ae741b614e" + integrity sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw== + dependencies: + semver "^7.5.3" + +make-error@1.x: + version "1.3.6" + resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" + integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== + +makeerror@1.0.12: + version "1.0.12" + resolved "https://registry.yarnpkg.com/makeerror/-/makeerror-1.0.12.tgz#3e5dd2079a82e812e983cc6610c4a2cb0eaa801a" + integrity sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg== + dependencies: + tmpl "1.0.5" + +merge-stream@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" + integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== + +micromatch@^4.0.4: + version "4.0.5" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6" + integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA== + dependencies: + braces "^3.0.2" + picomatch "^2.3.1" + +mime-db@1.52.0: + version "1.52.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" + integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== + +mime-types@^2.1.12: + version "2.1.35" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" + integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== + dependencies: + mime-db "1.52.0" + +mimic-fn@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" + integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== + +min-indent@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/min-indent/-/min-indent-1.0.1.tgz#a63f681673b30571fbe8bc25686ae746eefa9869" + integrity sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg== + +minimatch@^3.0.4, minimatch@^3.1.1: + version "3.1.2" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" + integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== + dependencies: + brace-expansion "^1.1.7" + +ms@2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" + integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== + +natural-compare@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" + integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== + +node-domexception@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/node-domexception/-/node-domexception-1.0.0.tgz#6888db46a1f71c0b76b3f7555016b63fe64766e5" + integrity sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ== + +node-fetch@^3.2.10: + version "3.3.2" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-3.3.2.tgz#d1e889bacdf733b4ff3b2b243eb7a12866a0b78b" + integrity sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA== + dependencies: + data-uri-to-buffer "^4.0.0" + fetch-blob "^3.1.4" + formdata-polyfill "^4.0.10" + +node-int64@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" + integrity sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw== + +node-releases@^2.0.14: + version "2.0.14" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.14.tgz#2ffb053bceb8b2be8495ece1ab6ce600c4461b0b" + integrity sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw== + +normalize-path@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" + integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== + +npm-run-path@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea" + integrity sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw== + dependencies: + path-key "^3.0.0" + +nwsapi@^2.2.2: + version "2.2.9" + resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.2.9.tgz#7f3303218372db2e9f27c27766bcfc59ae7e61c6" + integrity sha512-2f3F0SEEer8bBu0dsNCFF50N0cTThV1nWFYcEYFZttdW0lDAoybv9cQoK7X7/68Z89S7FoRrVjP1LPX4XRf9vg== + +once@^1.3.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== + dependencies: + wrappy "1" + +onetime@^5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" + integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== + dependencies: + mimic-fn "^2.1.0" + +p-limit@^2.2.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" + integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== + dependencies: + p-try "^2.0.0" + +p-limit@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" + integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== + dependencies: + yocto-queue "^0.1.0" + +p-locate@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07" + integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A== + dependencies: + p-limit "^2.2.0" + +p-try@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" + integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== + +parse-json@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd" + integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg== + dependencies: + "@babel/code-frame" "^7.0.0" + error-ex "^1.3.1" + json-parse-even-better-errors "^2.3.0" + lines-and-columns "^1.1.6" + +parse5@^7.0.0, parse5@^7.1.1: + version "7.1.2" + resolved "https://registry.yarnpkg.com/parse5/-/parse5-7.1.2.tgz#0736bebbfd77793823240a23b7fc5e010b7f8e32" + integrity sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw== + dependencies: + entities "^4.4.0" + +path-exists@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" + integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== + +path-key@^3.0.0, path-key@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" + integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== + +path-parse@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" + integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== + +picocolors@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" + integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== + +picomatch@^2.0.4, picomatch@^2.2.3, picomatch@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" + integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== + +pirates@^4.0.4: + version "4.0.6" + resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.6.tgz#3018ae32ecfcff6c29ba2267cbf21166ac1f36b9" + integrity sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg== + +pkg-dir@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3" + integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ== + dependencies: + find-up "^4.0.0" + +pretty-format@^27.0.2: + version "27.5.1" + resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-27.5.1.tgz#2181879fdea51a7a5851fb39d920faa63f01d88e" + integrity sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ== + dependencies: + ansi-regex "^5.0.1" + ansi-styles "^5.0.0" + react-is "^17.0.1" + +pretty-format@^29.0.0, pretty-format@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-29.7.0.tgz#ca42c758310f365bfa71a0bda0a807160b776812" + integrity sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ== + dependencies: + "@jest/schemas" "^29.6.3" + ansi-styles "^5.0.0" + react-is "^18.0.0" + +prompts@^2.0.1: + version "2.4.2" + resolved "https://registry.yarnpkg.com/prompts/-/prompts-2.4.2.tgz#7b57e73b3a48029ad10ebd44f74b01722a4cb069" + integrity sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q== + dependencies: + kleur "^3.0.3" + sisteransi "^1.0.5" + +psl@^1.1.33: + version "1.9.0" + resolved "https://registry.yarnpkg.com/psl/-/psl-1.9.0.tgz#d0df2a137f00794565fcaf3b2c00cd09f8d5a5a7" + integrity sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag== + +punycode@^2.1.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.1.tgz#027422e2faec0b25e1549c3e1bd8309b9133b6e5" + integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg== + +pure-rand@^6.0.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/pure-rand/-/pure-rand-6.1.0.tgz#d173cf23258231976ccbdb05247c9787957604f2" + integrity sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA== + +querystringify@^2.1.1: + version "2.2.0" + resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-2.2.0.tgz#3345941b4153cb9d082d8eee4cda2016a9aef7f6" + integrity sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ== + +rdf-canonize@^3.4.0: + version "3.4.0" + resolved "https://registry.yarnpkg.com/rdf-canonize/-/rdf-canonize-3.4.0.tgz#87f88342b173cc371d812a07de350f0c1aa9f058" + integrity sha512-fUeWjrkOO0t1rg7B2fdyDTvngj+9RlUyL92vOdiB7c0FPguWVsniIMjEtHH+meLBO9rzkUlUzBVXgWrjI8P9LA== + dependencies: + setimmediate "^1.0.5" + +react-dom@^18.3.1: + version "18.3.1" + resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-18.3.1.tgz#c2265d79511b57d479b3dd3fdfa51536494c5cb4" + integrity sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw== + dependencies: + loose-envify "^1.1.0" + scheduler "^0.23.2" + +react-is@^17.0.1: + version "17.0.2" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0" + integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w== + +react-is@^18.0.0: + version "18.3.1" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.3.1.tgz#e83557dc12eae63a99e003a46388b1dcbb44db7e" + integrity sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg== + +react@^18.3.1: + version "18.3.1" + resolved "https://registry.yarnpkg.com/react/-/react-18.3.1.tgz#49ab892009c53933625bd16b2533fc754cab2891" + integrity sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ== + dependencies: + loose-envify "^1.1.0" + +redent@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/redent/-/redent-3.0.0.tgz#e557b7998316bb53c9f1f56fa626352c6963059f" + integrity sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg== + dependencies: + indent-string "^4.0.0" + strip-indent "^3.0.0" + +regenerate-unicode-properties@^10.1.0: + version "10.1.1" + resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.1.tgz#6b0e05489d9076b04c436f318d9b067bba459480" + integrity sha512-X007RyZLsCJVVrjgEFVpLUTZwyOZk3oiL75ZcuYjlIWd6rNJtOjkBwQc5AsRrpbKVkxN6sklw/k/9m2jJYOf8Q== + dependencies: + regenerate "^1.4.2" + +regenerate@^1.4.2: + version "1.4.2" + resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.2.tgz#b9346d8827e8f5a32f7ba29637d398b69014848a" + integrity sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A== + +regenerator-runtime@^0.14.0: + version "0.14.1" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz#356ade10263f685dda125100cd862c1db895327f" + integrity sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw== + +regenerator-transform@^0.15.2: + version "0.15.2" + resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.15.2.tgz#5bbae58b522098ebdf09bca2f83838929001c7a4" + integrity sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg== + dependencies: + "@babel/runtime" "^7.8.4" + +regexpu-core@^5.3.1: + version "5.3.2" + resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-5.3.2.tgz#11a2b06884f3527aec3e93dbbf4a3b958a95546b" + integrity sha512-RAM5FlZz+Lhmo7db9L298p2vHP5ZywrVXmVXpmAD9GuL5MPH6t9ROw1iA/wfHkQ76Qe7AaPF0nGuim96/IrQMQ== + dependencies: + "@babel/regjsgen" "^0.8.0" + regenerate "^1.4.2" + regenerate-unicode-properties "^10.1.0" + regjsparser "^0.9.1" + unicode-match-property-ecmascript "^2.0.0" + unicode-match-property-value-ecmascript "^2.1.0" + +regjsparser@^0.9.1: + version "0.9.1" + resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.9.1.tgz#272d05aa10c7c1f67095b1ff0addae8442fc5709" + integrity sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ== + dependencies: + jsesc "~0.5.0" + +require-directory@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" + integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q== + +requires-port@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" + integrity sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ== + +resolve-cwd@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-3.0.0.tgz#0f0075f1bb2544766cf73ba6a6e2adfebcb13f2d" + integrity sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg== + dependencies: + resolve-from "^5.0.0" + +resolve-from@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69" + integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw== + +resolve.exports@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/resolve.exports/-/resolve.exports-2.0.2.tgz#f8c934b8e6a13f539e38b7098e2e36134f01e800" + integrity sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg== + +resolve@^1.14.2, resolve@^1.20.0: + version "1.22.8" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.8.tgz#b6c87a9f2aa06dfab52e3d70ac8cde321fa5a48d" + integrity sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw== + dependencies: + is-core-module "^2.13.0" + path-parse "^1.0.7" + supports-preserve-symlinks-flag "^1.0.0" + +"safer-buffer@>= 2.1.2 < 3.0.0": + version "2.1.2" + resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== + +saxes@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/saxes/-/saxes-6.0.0.tgz#fe5b4a4768df4f14a201b1ba6a65c1f3d9988cc5" + integrity sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA== + dependencies: + xmlchars "^2.2.0" + +scheduler@^0.23.2: + version "0.23.2" + resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.23.2.tgz#414ba64a3b282892e944cf2108ecc078d115cdc3" + integrity sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ== + dependencies: + loose-envify "^1.1.0" + +semver@^6.3.0, semver@^6.3.1: + version "6.3.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" + integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== + +semver@^7.5.3, semver@^7.5.4: + version "7.6.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.1.tgz#60bfe090bf907a25aa8119a72b9f90ef7ca281b2" + integrity sha512-f/vbBsu+fOiYt+lmwZV0rVwJScl46HppnOA1ZvIuBWKOTlllpyJ3bfVax76/OrhCH38dyxoDIA8K7uB963IYgA== + +setimmediate@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" + integrity sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA== + +shebang-command@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" + integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== + dependencies: + shebang-regex "^3.0.0" + +shebang-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" + integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== + +signal-exit@^3.0.3, signal-exit@^3.0.7: + version "3.0.7" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" + integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== + +sisteransi@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/sisteransi/-/sisteransi-1.0.5.tgz#134d681297756437cc05ca01370d3a7a571075ed" + integrity sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg== + +slash@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" + integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== + +source-map-support@0.5.13: + version "0.5.13" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.13.tgz#31b24a9c2e73c2de85066c0feb7d44767ed52932" + integrity sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w== + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" + +source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== + +sprintf-js@~1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" + integrity sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g== + +stack-utils@^2.0.3: + version "2.0.6" + resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-2.0.6.tgz#aaf0748169c02fc33c8232abccf933f54a1cc34f" + integrity sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ== + dependencies: + escape-string-regexp "^2.0.0" + +string-length@^4.0.1: + version "4.0.2" + resolved "https://registry.yarnpkg.com/string-length/-/string-length-4.0.2.tgz#a8a8dc7bd5c1a82b9b3c8b87e125f66871b6e57a" + integrity sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ== + dependencies: + char-regex "^1.0.2" + strip-ansi "^6.0.0" + +string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: + version "4.2.3" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + +strip-ansi@^6.0.0, strip-ansi@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + +strip-bom@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-4.0.0.tgz#9c3505c1db45bcedca3d9cf7a16f5c5aa3901878" + integrity sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w== + +strip-final-newline@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad" + integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA== + +strip-indent@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-3.0.0.tgz#c32e1cee940b6b3432c771bc2c54bcce73cd3001" + integrity sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ== + dependencies: + min-indent "^1.0.0" + +strip-json-comments@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" + integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== + +supports-color@^5.3.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" + integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== + dependencies: + has-flag "^3.0.0" + +supports-color@^7.1.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" + integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== + dependencies: + has-flag "^4.0.0" + +supports-color@^8.0.0: + version "8.1.1" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" + integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== + dependencies: + has-flag "^4.0.0" + +supports-preserve-symlinks-flag@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" + integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== + +symbol-tree@^3.2.4: + version "3.2.4" + resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2" + integrity sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw== + +test-exclude@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-6.0.0.tgz#04a8698661d805ea6fa293b6cb9e63ac044ef15e" + integrity sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w== + dependencies: + "@istanbuljs/schema" "^0.1.2" + glob "^7.1.4" + minimatch "^3.0.4" + +text-encoding@^0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/text-encoding/-/text-encoding-0.7.0.tgz#f895e836e45990624086601798ea98e8f36ee643" + integrity sha512-oJQ3f1hrOnbRLOcwKz0Liq2IcrvDeZRHXhd9RgLrsT+DjWY/nty1Hi7v3dtkaEYbPYe0mUoOfzRrMwfXXwgPUA== + +tmpl@1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.5.tgz#8683e0b902bb9c20c4f726e3c0b69f36518c07cc" + integrity sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw== + +to-fast-properties@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" + integrity sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog== + +to-regex-range@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" + integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== + dependencies: + is-number "^7.0.0" + +tough-cookie@^4.1.2: + version "4.1.4" + resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-4.1.4.tgz#945f1461b45b5a8c76821c33ea49c3ac192c1b36" + integrity sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag== + dependencies: + psl "^1.1.33" + punycode "^2.1.1" + universalify "^0.2.0" + url-parse "^1.5.3" + +tr46@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/tr46/-/tr46-3.0.0.tgz#555c4e297a950617e8eeddef633c87d4d9d6cbf9" + integrity sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA== + dependencies: + punycode "^2.1.1" + +ts-jest@^29.1.2: + version "29.1.2" + resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-29.1.2.tgz#7613d8c81c43c8cb312c6904027257e814c40e09" + integrity sha512-br6GJoH/WUX4pu7FbZXuWGKGNDuU7b8Uj77g/Sp7puZV6EXzuByl6JrECvm0MzVzSTkSHWTihsXt+5XYER5b+g== + dependencies: + bs-logger "0.x" + fast-json-stable-stringify "2.x" + jest-util "^29.0.0" + json5 "^2.2.3" + lodash.memoize "4.x" + make-error "1.x" + semver "^7.5.3" + yargs-parser "^21.0.1" + +type-detect@4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" + integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g== + +type-fest@^0.21.3: + version "0.21.3" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37" + integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w== + +typescript@^5.4.5: + version "5.4.5" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.4.5.tgz#42ccef2c571fdbd0f6718b1d1f5e6e5ef006f611" + integrity sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ== + +undici-types@~5.26.4: + version "5.26.5" + resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-5.26.5.tgz#bcd539893d00b56e964fd2657a4866b221a65617" + integrity sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA== + +undici@^5.21.2: + version "5.28.4" + resolved "https://registry.yarnpkg.com/undici/-/undici-5.28.4.tgz#6b280408edb6a1a604a9b20340f45b422e373068" + integrity sha512-72RFADWFqKmUb2hmmvNODKL3p9hcB6Gt2DOQMis1SEBaV6a4MH8soBvzg+95CYhCKPFedut2JY9bMfrDl9D23g== + dependencies: + "@fastify/busboy" "^2.0.0" + +unicode-canonical-property-names-ecmascript@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz#301acdc525631670d39f6146e0e77ff6bbdebddc" + integrity sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ== + +unicode-match-property-ecmascript@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz#54fd16e0ecb167cf04cf1f756bdcc92eba7976c3" + integrity sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q== + dependencies: + unicode-canonical-property-names-ecmascript "^2.0.0" + unicode-property-aliases-ecmascript "^2.0.0" + +unicode-match-property-value-ecmascript@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.1.0.tgz#cb5fffdcd16a05124f5a4b0bf7c3770208acbbe0" + integrity sha512-qxkjQt6qjg/mYscYMC0XKRn3Rh0wFPlfxB0xkt9CfyTvpX1Ra0+rAmdX2QyAobptSEvuy4RtpPRui6XkV+8wjA== + +unicode-property-aliases-ecmascript@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz#43d41e3be698bd493ef911077c9b131f827e8ccd" + integrity sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w== + +universalify@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.2.0.tgz#6451760566fa857534745ab1dde952d1b1761be0" + integrity sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg== + +update-browserslist-db@^1.0.13: + version "1.0.15" + resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.15.tgz#60ed9f8cba4a728b7ecf7356f641a31e3a691d97" + integrity sha512-K9HWH62x3/EalU1U6sjSZiylm9C8tgq2mSvshZpqc7QE69RaA2qjhkW2HlNA0tFpEbtyFz7HTqbSdN4MSwUodA== + dependencies: + escalade "^3.1.2" + picocolors "^1.0.0" + +url-parse@^1.5.3: + version "1.5.10" + resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.5.10.tgz#9d3c2f736c1d75dd3bd2be507dcc111f1e2ea9c1" + integrity sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ== + dependencies: + querystringify "^2.1.1" + requires-port "^1.0.0" + +v8-to-istanbul@^9.0.1: + version "9.2.0" + resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-9.2.0.tgz#2ed7644a245cddd83d4e087b9b33b3e62dfd10ad" + integrity sha512-/EH/sDgxU2eGxajKdwLCDmQ4FWq+kpi3uCmBGpw1xJtnAxEjlD8j8PEiGWpCIMIs3ciNAgH0d3TTJiUkYzyZjA== + dependencies: + "@jridgewell/trace-mapping" "^0.3.12" + "@types/istanbul-lib-coverage" "^2.0.1" + convert-source-map "^2.0.0" + +w3c-xmlserializer@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/w3c-xmlserializer/-/w3c-xmlserializer-4.0.0.tgz#aebdc84920d806222936e3cdce408e32488a3073" + integrity sha512-d+BFHzbiCx6zGfz0HyQ6Rg69w9k19nviJspaj4yNscGjrHu94sVP+aRm75yEbCh+r2/yR+7q6hux9LVtbuTGBw== + dependencies: + xml-name-validator "^4.0.0" + +walker@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/walker/-/walker-1.0.8.tgz#bd498db477afe573dc04185f011d3ab8a8d7653f" + integrity sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ== + dependencies: + makeerror "1.0.12" + +web-streams-polyfill@^3.0.3: + version "3.3.3" + resolved "https://registry.yarnpkg.com/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz#2073b91a2fdb1fbfbd401e7de0ac9f8214cecb4b" + integrity sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw== + +webidl-conversions@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-7.0.0.tgz#256b4e1882be7debbf01d05f0aa2039778ea080a" + integrity sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g== + +whatwg-encoding@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/whatwg-encoding/-/whatwg-encoding-2.0.0.tgz#e7635f597fd87020858626805a2729fa7698ac53" + integrity sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg== + dependencies: + iconv-lite "0.6.3" + +whatwg-mimetype@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/whatwg-mimetype/-/whatwg-mimetype-3.0.0.tgz#5fa1a7623867ff1af6ca3dc72ad6b8a4208beba7" + integrity sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q== + +whatwg-url@^11.0.0: + version "11.0.0" + resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-11.0.0.tgz#0a849eebb5faf2119b901bb76fd795c2848d4018" + integrity sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ== + dependencies: + tr46 "^3.0.0" + webidl-conversions "^7.0.0" + +which@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" + integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== + dependencies: + isexe "^2.0.0" + +wrap-ansi@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== + +write-file-atomic@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-4.0.2.tgz#a9df01ae5b77858a027fd2e80768ee433555fcfd" + integrity sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg== + dependencies: + imurmurhash "^0.1.4" + signal-exit "^3.0.7" + +ws@^8.11.0: + version "8.17.0" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.17.0.tgz#d145d18eca2ed25aaf791a183903f7be5e295fea" + integrity sha512-uJq6108EgZMAl20KagGkzCKfMEjxmKvZHG7Tlq0Z6nOky7YF7aq4mOx6xK8TJ/i1LeK4Qus7INktacctDgY8Ow== + +xml-name-validator@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-4.0.0.tgz#79a006e2e63149a8600f15430f0a4725d1524835" + integrity sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw== + +xmlchars@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/xmlchars/-/xmlchars-2.2.0.tgz#060fe1bcb7f9c76fe2a17db86a9bc3ab894210cb" + integrity sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw== + +y18n@^5.0.5: + version "5.0.8" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" + integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== + +yallist@^3.0.2: + version "3.1.1" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" + integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== + +yallist@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" + integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== + +yargs-parser@^21.0.1, yargs-parser@^21.1.1: + version "21.1.1" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.1.1.tgz#9096bceebf990d21bb31fa9516e0ede294a77d35" + integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw== + +yargs@^17.3.1: + version "17.7.2" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.7.2.tgz#991df39aca675a192b816e1e0363f9d75d2aa269" + integrity sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w== + 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.5" + yargs-parser "^21.1.1" + +yocto-queue@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" + integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== + +zod@^3.23.6: + version "3.23.6" + resolved "https://registry.yarnpkg.com/zod/-/zod-3.23.6.tgz#c08a977e2255dab1fdba933651584a05fcbf19e1" + integrity sha512-RTHJlZhsRbuA8Hmp/iNL7jnfc4nZishjsanDAfEY1QpDQZCahUp3xDzl+zfweE9BklxMUcgBgS1b7Lvie/ZVwA== From 0e6b56d76cc8e04765e6fff73cf80c7380f3ba48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Sza=C5=82owski?= Date: Wed, 8 May 2024 13:43:14 +0200 Subject: [PATCH 067/125] feat(942): update govtool packages name --- govtool/packages/submission-tool/package.json | 4 ++-- govtool/packages/wallet-connector/package.json | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/govtool/packages/submission-tool/package.json b/govtool/packages/submission-tool/package.json index 94e737bdc..7a28f8953 100644 --- a/govtool/packages/submission-tool/package.json +++ b/govtool/packages/submission-tool/package.json @@ -1,6 +1,6 @@ { - "name": "submission-tool", - "packageManager": "yarn@3.6.4", + "name": "govtool-submission-tool", + "version": "0.0.1", "scripts": { "test": "jest" }, diff --git a/govtool/packages/wallet-connector/package.json b/govtool/packages/wallet-connector/package.json index c2848cfb6..8471b0c61 100644 --- a/govtool/packages/wallet-connector/package.json +++ b/govtool/packages/wallet-connector/package.json @@ -1,6 +1,6 @@ { - "name": "wallet-connector", - "version": "1.0.0", + "name": "govtool-wallet-connector", + "version": "0.0.1", "main": "index.ts", "license": "MIT", "dependencies": { From 424a0c268481744e235c72ff4fbe9ad9bbab7c22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Sza=C5=82owski?= Date: Wed, 8 May 2024 15:33:40 +0200 Subject: [PATCH 068/125] chore: configure tsup for building govtool packages --- govtool/packages/submission-tool/.gitignore | 3 +- govtool/packages/submission-tool/package.json | 14 + .../packages/submission-tool/tsup.config.ts | 10 + govtool/packages/submission-tool/yarn.lock | 707 ++++++++++++- govtool/packages/wallet-connector/.gitignore | 2 + .../wallet-connector/WalletProvider.tsx | 4 +- .../packages/wallet-connector/package.json | 18 +- .../packages/wallet-connector/tsconfig.json | 109 ++ .../packages/wallet-connector/tsup.config.ts | 10 + govtool/packages/wallet-connector/yarn.lock | 980 ++++++++++++++++++ 10 files changed, 1840 insertions(+), 17 deletions(-) create mode 100644 govtool/packages/submission-tool/tsup.config.ts create mode 100644 govtool/packages/wallet-connector/.gitignore create mode 100644 govtool/packages/wallet-connector/tsconfig.json create mode 100644 govtool/packages/wallet-connector/tsup.config.ts diff --git a/govtool/packages/submission-tool/.gitignore b/govtool/packages/submission-tool/.gitignore index 7cafbdb49..f142f4c13 100644 --- a/govtool/packages/submission-tool/.gitignore +++ b/govtool/packages/submission-tool/.gitignore @@ -1,2 +1,3 @@ coverage -node_modules \ No newline at end of file +node_modules +dist \ No newline at end of file diff --git a/govtool/packages/submission-tool/package.json b/govtool/packages/submission-tool/package.json index 7a28f8953..d531f4082 100644 --- a/govtool/packages/submission-tool/package.json +++ b/govtool/packages/submission-tool/package.json @@ -1,7 +1,20 @@ { "name": "govtool-submission-tool", + "description": "A utility tool for creating the govtool metadata jsonld and hash.", "version": "0.0.1", + "main": "./dist/index.js", + "module": "./dist/index.mjs", + "types": "./dist/index.d.ts", + "license": "MIT", + "keywords": [ + "govtool", + "metadata", + "jsonld", + "hash" + ], + "author": "IntersectMBO", "scripts": { + "build": "tsup", "test": "jest" }, "dependencies": { @@ -25,6 +38,7 @@ "jest-environment-jsdom": "^29.7.0", "text-encoding": "^0.7.0", "ts-jest": "^29.1.2", + "tsup": "^8.0.2", "typescript": "^5.4.5" } } diff --git a/govtool/packages/submission-tool/tsup.config.ts b/govtool/packages/submission-tool/tsup.config.ts new file mode 100644 index 000000000..0653a5af9 --- /dev/null +++ b/govtool/packages/submission-tool/tsup.config.ts @@ -0,0 +1,10 @@ +import { defineConfig } from "tsup"; + +export default defineConfig({ + entry: ["index.ts"], + format: ["cjs", "esm"], + dts: true, + splitting: false, + sourcemap: true, + clean: true, +}); diff --git a/govtool/packages/submission-tool/yarn.lock b/govtool/packages/submission-tool/yarn.lock index f2ea8606b..5ec3ecd00 100644 --- a/govtool/packages/submission-tool/yarn.lock +++ b/govtool/packages/submission-tool/yarn.lock @@ -1036,11 +1036,138 @@ ky-universal "^0.11.0" undici "^5.21.2" +"@esbuild/aix-ppc64@0.19.12": + version "0.19.12" + resolved "https://registry.yarnpkg.com/@esbuild/aix-ppc64/-/aix-ppc64-0.19.12.tgz#d1bc06aedb6936b3b6d313bf809a5a40387d2b7f" + integrity sha512-bmoCYyWdEL3wDQIVbcyzRyeKLgk2WtWLTWz1ZIAZF/EGbNOwSA6ew3PftJ1PqMiOOGu0OyFMzG53L0zqIpPeNA== + +"@esbuild/android-arm64@0.19.12": + version "0.19.12" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.19.12.tgz#7ad65a36cfdb7e0d429c353e00f680d737c2aed4" + integrity sha512-P0UVNGIienjZv3f5zq0DP3Nt2IE/3plFzuaS96vihvD0Hd6H/q4WXUGpCxD/E8YrSXfNyRPbpTq+T8ZQioSuPA== + +"@esbuild/android-arm@0.19.12": + version "0.19.12" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.19.12.tgz#b0c26536f37776162ca8bde25e42040c203f2824" + integrity sha512-qg/Lj1mu3CdQlDEEiWrlC4eaPZ1KztwGJ9B6J+/6G+/4ewxJg7gqj8eVYWvao1bXrqGiW2rsBZFSX3q2lcW05w== + +"@esbuild/android-x64@0.19.12": + version "0.19.12" + resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.19.12.tgz#cb13e2211282012194d89bf3bfe7721273473b3d" + integrity sha512-3k7ZoUW6Q6YqhdhIaq/WZ7HwBpnFBlW905Fa4s4qWJyiNOgT1dOqDiVAQFwBH7gBRZr17gLrlFCRzF6jFh7Kew== + +"@esbuild/darwin-arm64@0.19.12": + version "0.19.12" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.19.12.tgz#cbee41e988020d4b516e9d9e44dd29200996275e" + integrity sha512-B6IeSgZgtEzGC42jsI+YYu9Z3HKRxp8ZT3cqhvliEHovq8HSX2YX8lNocDn79gCKJXOSaEot9MVYky7AKjCs8g== + +"@esbuild/darwin-x64@0.19.12": + version "0.19.12" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.19.12.tgz#e37d9633246d52aecf491ee916ece709f9d5f4cd" + integrity sha512-hKoVkKzFiToTgn+41qGhsUJXFlIjxI/jSYeZf3ugemDYZldIXIxhvwN6erJGlX4t5h417iFuheZ7l+YVn05N3A== + +"@esbuild/freebsd-arm64@0.19.12": + version "0.19.12" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.19.12.tgz#1ee4d8b682ed363b08af74d1ea2b2b4dbba76487" + integrity sha512-4aRvFIXmwAcDBw9AueDQ2YnGmz5L6obe5kmPT8Vd+/+x/JMVKCgdcRwH6APrbpNXsPz+K653Qg8HB/oXvXVukA== + +"@esbuild/freebsd-x64@0.19.12": + version "0.19.12" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.19.12.tgz#37a693553d42ff77cd7126764b535fb6cc28a11c" + integrity sha512-EYoXZ4d8xtBoVN7CEwWY2IN4ho76xjYXqSXMNccFSx2lgqOG/1TBPW0yPx1bJZk94qu3tX0fycJeeQsKovA8gg== + +"@esbuild/linux-arm64@0.19.12": + version "0.19.12" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.19.12.tgz#be9b145985ec6c57470e0e051d887b09dddb2d4b" + integrity sha512-EoTjyYyLuVPfdPLsGVVVC8a0p1BFFvtpQDB/YLEhaXyf/5bczaGeN15QkR+O4S5LeJ92Tqotve7i1jn35qwvdA== + +"@esbuild/linux-arm@0.19.12": + version "0.19.12" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.19.12.tgz#207ecd982a8db95f7b5279207d0ff2331acf5eef" + integrity sha512-J5jPms//KhSNv+LO1S1TX1UWp1ucM6N6XuL6ITdKWElCu8wXP72l9MM0zDTzzeikVyqFE6U8YAV9/tFyj0ti+w== + +"@esbuild/linux-ia32@0.19.12": + version "0.19.12" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.19.12.tgz#d0d86b5ca1562523dc284a6723293a52d5860601" + integrity sha512-Thsa42rrP1+UIGaWz47uydHSBOgTUnwBwNq59khgIwktK6x60Hivfbux9iNR0eHCHzOLjLMLfUMLCypBkZXMHA== + +"@esbuild/linux-loong64@0.19.12": + version "0.19.12" + resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.19.12.tgz#9a37f87fec4b8408e682b528391fa22afd952299" + integrity sha512-LiXdXA0s3IqRRjm6rV6XaWATScKAXjI4R4LoDlvO7+yQqFdlr1Bax62sRwkVvRIrwXxvtYEHHI4dm50jAXkuAA== + +"@esbuild/linux-mips64el@0.19.12": + version "0.19.12" + resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.19.12.tgz#4ddebd4e6eeba20b509d8e74c8e30d8ace0b89ec" + integrity sha512-fEnAuj5VGTanfJ07ff0gOA6IPsvrVHLVb6Lyd1g2/ed67oU1eFzL0r9WL7ZzscD+/N6i3dWumGE1Un4f7Amf+w== + +"@esbuild/linux-ppc64@0.19.12": + version "0.19.12" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.19.12.tgz#adb67dadb73656849f63cd522f5ecb351dd8dee8" + integrity sha512-nYJA2/QPimDQOh1rKWedNOe3Gfc8PabU7HT3iXWtNUbRzXS9+vgB0Fjaqr//XNbd82mCxHzik2qotuI89cfixg== + +"@esbuild/linux-riscv64@0.19.12": + version "0.19.12" + resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.19.12.tgz#11bc0698bf0a2abf8727f1c7ace2112612c15adf" + integrity sha512-2MueBrlPQCw5dVJJpQdUYgeqIzDQgw3QtiAHUC4RBz9FXPrskyyU3VI1hw7C0BSKB9OduwSJ79FTCqtGMWqJHg== + +"@esbuild/linux-s390x@0.19.12": + version "0.19.12" + resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.19.12.tgz#e86fb8ffba7c5c92ba91fc3b27ed5a70196c3cc8" + integrity sha512-+Pil1Nv3Umes4m3AZKqA2anfhJiVmNCYkPchwFJNEJN5QxmTs1uzyy4TvmDrCRNT2ApwSari7ZIgrPeUx4UZDg== + +"@esbuild/linux-x64@0.19.12": + version "0.19.12" + resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.19.12.tgz#5f37cfdc705aea687dfe5dfbec086a05acfe9c78" + integrity sha512-B71g1QpxfwBvNrfyJdVDexenDIt1CiDN1TIXLbhOw0KhJzE78KIFGX6OJ9MrtC0oOqMWf+0xop4qEU8JrJTwCg== + +"@esbuild/netbsd-x64@0.19.12": + version "0.19.12" + resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.19.12.tgz#29da566a75324e0d0dd7e47519ba2f7ef168657b" + integrity sha512-3ltjQ7n1owJgFbuC61Oj++XhtzmymoCihNFgT84UAmJnxJfm4sYCiSLTXZtE00VWYpPMYc+ZQmB6xbSdVh0JWA== + +"@esbuild/openbsd-x64@0.19.12": + version "0.19.12" + resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.19.12.tgz#306c0acbdb5a99c95be98bdd1d47c916e7dc3ff0" + integrity sha512-RbrfTB9SWsr0kWmb9srfF+L933uMDdu9BIzdA7os2t0TXhCRjrQyCeOt6wVxr79CKD4c+p+YhCj31HBkYcXebw== + +"@esbuild/sunos-x64@0.19.12": + version "0.19.12" + resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.19.12.tgz#0933eaab9af8b9b2c930236f62aae3fc593faf30" + integrity sha512-HKjJwRrW8uWtCQnQOz9qcU3mUZhTUQvi56Q8DPTLLB+DawoiQdjsYq+j+D3s9I8VFtDr+F9CjgXKKC4ss89IeA== + +"@esbuild/win32-arm64@0.19.12": + version "0.19.12" + resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.19.12.tgz#773bdbaa1971b36db2f6560088639ccd1e6773ae" + integrity sha512-URgtR1dJnmGvX864pn1B2YUYNzjmXkuJOIqG2HdU62MVS4EHpU2946OZoTMnRUHklGtJdJZ33QfzdjGACXhn1A== + +"@esbuild/win32-ia32@0.19.12": + version "0.19.12" + resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.19.12.tgz#000516cad06354cc84a73f0943a4aa690ef6fd67" + integrity sha512-+ZOE6pUkMOJfmxmBZElNOx72NKpIa/HFOMGzu8fqzQJ5kgf6aTGrcJaFsNiVMH4JKpMipyK+7k0n2UXN7a8YKQ== + +"@esbuild/win32-x64@0.19.12": + version "0.19.12" + resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.19.12.tgz#c57c8afbb4054a3ab8317591a0b7320360b444ae" + integrity sha512-T1QyPSDCyMXaO3pzBkF96E8xMkiRYbUEZADd29SyPGabqxMViNoii+NcK7eWJAEoU6RZyEm5lVSIjTmcdoB9HA== + "@fastify/busboy@^2.0.0": version "2.1.1" resolved "https://registry.yarnpkg.com/@fastify/busboy/-/busboy-2.1.1.tgz#b9da6a878a371829a0502c9b6c1c143ef6663f4d" integrity sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA== +"@isaacs/cliui@^8.0.2": + version "8.0.2" + resolved "https://registry.yarnpkg.com/@isaacs/cliui/-/cliui-8.0.2.tgz#b37667b7bc181c168782259bab42474fbf52b550" + integrity sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA== + dependencies: + string-width "^5.1.2" + string-width-cjs "npm:string-width@^4.2.0" + strip-ansi "^7.0.1" + strip-ansi-cjs "npm:strip-ansi@^6.0.1" + wrap-ansi "^8.1.0" + wrap-ansi-cjs "npm:wrap-ansi@^7.0.0" + "@istanbuljs/load-nyc-config@^1.0.0": version "1.1.0" resolved "https://registry.yarnpkg.com/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz#fd3db1d59ecf7cf121e80650bb86712f9b55eced" @@ -1249,7 +1376,7 @@ "@types/yargs" "^17.0.8" chalk "^4.0.0" -"@jridgewell/gen-mapping@^0.3.5": +"@jridgewell/gen-mapping@^0.3.2", "@jridgewell/gen-mapping@^0.3.5": version "0.3.5" resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz#dcce6aff74bdf6dad1a95802b69b04a2fcb1fb36" integrity sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg== @@ -1281,6 +1408,112 @@ "@jridgewell/resolve-uri" "^3.1.0" "@jridgewell/sourcemap-codec" "^1.4.14" +"@nodelib/fs.scandir@2.1.5": + version "2.1.5" + resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" + integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g== + dependencies: + "@nodelib/fs.stat" "2.0.5" + run-parallel "^1.1.9" + +"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2": + version "2.0.5" + resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b" + integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== + +"@nodelib/fs.walk@^1.2.3": + version "1.2.8" + resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a" + integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== + dependencies: + "@nodelib/fs.scandir" "2.1.5" + fastq "^1.6.0" + +"@pkgjs/parseargs@^0.11.0": + version "0.11.0" + resolved "https://registry.yarnpkg.com/@pkgjs/parseargs/-/parseargs-0.11.0.tgz#a77ea742fab25775145434eb1d2328cf5013ac33" + integrity sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg== + +"@rollup/rollup-android-arm-eabi@4.17.2": + version "4.17.2" + resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.17.2.tgz#1a32112822660ee104c5dd3a7c595e26100d4c2d" + integrity sha512-NM0jFxY8bB8QLkoKxIQeObCaDlJKewVlIEkuyYKm5An1tdVZ966w2+MPQ2l8LBZLjR+SgyV+nRkTIunzOYBMLQ== + +"@rollup/rollup-android-arm64@4.17.2": + version "4.17.2" + resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.17.2.tgz#5aeef206d65ff4db423f3a93f71af91b28662c5b" + integrity sha512-yeX/Usk7daNIVwkq2uGoq2BYJKZY1JfyLTaHO/jaiSwi/lsf8fTFoQW/n6IdAsx5tx+iotu2zCJwz8MxI6D/Bw== + +"@rollup/rollup-darwin-arm64@4.17.2": + version "4.17.2" + resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.17.2.tgz#6b66aaf003c70454c292cd5f0236ebdc6ffbdf1a" + integrity sha512-kcMLpE6uCwls023+kknm71ug7MZOrtXo+y5p/tsg6jltpDtgQY1Eq5sGfHcQfb+lfuKwhBmEURDga9N0ol4YPw== + +"@rollup/rollup-darwin-x64@4.17.2": + version "4.17.2" + resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.17.2.tgz#f64fc51ed12b19f883131ccbcea59fc68cbd6c0b" + integrity sha512-AtKwD0VEx0zWkL0ZjixEkp5tbNLzX+FCqGG1SvOu993HnSz4qDI6S4kGzubrEJAljpVkhRSlg5bzpV//E6ysTQ== + +"@rollup/rollup-linux-arm-gnueabihf@4.17.2": + version "4.17.2" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.17.2.tgz#1a7641111be67c10111f7122d1e375d1226cbf14" + integrity sha512-3reX2fUHqN7sffBNqmEyMQVj/CKhIHZd4y631duy0hZqI8Qoqf6lTtmAKvJFYa6bhU95B1D0WgzHkmTg33In0A== + +"@rollup/rollup-linux-arm-musleabihf@4.17.2": + version "4.17.2" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.17.2.tgz#c93fd632923e0fee25aacd2ae414288d0b7455bb" + integrity sha512-uSqpsp91mheRgw96xtyAGP9FW5ChctTFEoXP0r5FAzj/3ZRv3Uxjtc7taRQSaQM/q85KEKjKsZuiZM3GyUivRg== + +"@rollup/rollup-linux-arm64-gnu@4.17.2": + version "4.17.2" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.17.2.tgz#fa531425dd21d058a630947527b4612d9d0b4a4a" + integrity sha512-EMMPHkiCRtE8Wdk3Qhtciq6BndLtstqZIroHiiGzB3C5LDJmIZcSzVtLRbwuXuUft1Cnv+9fxuDtDxz3k3EW2A== + +"@rollup/rollup-linux-arm64-musl@4.17.2": + version "4.17.2" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.17.2.tgz#8acc16f095ceea5854caf7b07e73f7d1802ac5af" + integrity sha512-NMPylUUZ1i0z/xJUIx6VUhISZDRT+uTWpBcjdv0/zkp7b/bQDF+NfnfdzuTiB1G6HTodgoFa93hp0O1xl+/UbA== + +"@rollup/rollup-linux-powerpc64le-gnu@4.17.2": + version "4.17.2" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.17.2.tgz#94e69a8499b5cf368911b83a44bb230782aeb571" + integrity sha512-T19My13y8uYXPw/L/k0JYaX1fJKFT/PWdXiHr8mTbXWxjVF1t+8Xl31DgBBvEKclw+1b00Chg0hxE2O7bTG7GQ== + +"@rollup/rollup-linux-riscv64-gnu@4.17.2": + version "4.17.2" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.17.2.tgz#7ef1c781c7e59e85a6ce261cc95d7f1e0b56db0f" + integrity sha512-BOaNfthf3X3fOWAB+IJ9kxTgPmMqPPH5f5k2DcCsRrBIbWnaJCgX2ll77dV1TdSy9SaXTR5iDXRL8n7AnoP5cg== + +"@rollup/rollup-linux-s390x-gnu@4.17.2": + version "4.17.2" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.17.2.tgz#f15775841c3232fca9b78cd25a7a0512c694b354" + integrity sha512-W0UP/x7bnn3xN2eYMql2T/+wpASLE5SjObXILTMPUBDB/Fg/FxC+gX4nvCfPBCbNhz51C+HcqQp2qQ4u25ok6g== + +"@rollup/rollup-linux-x64-gnu@4.17.2": + version "4.17.2" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.17.2.tgz#b521d271798d037ad70c9f85dd97d25f8a52e811" + integrity sha512-Hy7pLwByUOuyaFC6mAr7m+oMC+V7qyifzs/nW2OJfC8H4hbCzOX07Ov0VFk/zP3kBsELWNFi7rJtgbKYsav9QQ== + +"@rollup/rollup-linux-x64-musl@4.17.2": + version "4.17.2" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.17.2.tgz#9254019cc4baac35800991315d133cc9fd1bf385" + integrity sha512-h1+yTWeYbRdAyJ/jMiVw0l6fOOm/0D1vNLui9iPuqgRGnXA0u21gAqOyB5iHjlM9MMfNOm9RHCQ7zLIzT0x11Q== + +"@rollup/rollup-win32-arm64-msvc@4.17.2": + version "4.17.2" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.17.2.tgz#27f65a89f6f52ee9426ec11e3571038e4671790f" + integrity sha512-tmdtXMfKAjy5+IQsVtDiCfqbynAQE/TQRpWdVataHmhMb9DCoJxp9vLcCBjEQWMiUYxO1QprH/HbY9ragCEFLA== + +"@rollup/rollup-win32-ia32-msvc@4.17.2": + version "4.17.2" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.17.2.tgz#a2fbf8246ed0bb014f078ca34ae6b377a90cb411" + integrity sha512-7II/QCSTAHuE5vdZaQEwJq2ZACkBpQDOmQsE6D6XUbnBHW8IAhm4eTufL6msLJorzrHDFv3CF8oCA/hSIRuZeQ== + +"@rollup/rollup-win32-x64-msvc@4.17.2": + version "4.17.2" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.17.2.tgz#5a2d08b81e8064b34242d5cc9973ef8dd1e60503" + integrity sha512-TGGO7v7qOq4CYmSBVEYpI1Y5xDuCEnbVC5Vth8mOsW0gDSzxNrVERPc790IGHsrT2dQSimgMr9Ub3Y1Jci5/8w== + "@sinclair/typebox@^0.27.8": version "0.27.8" resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.27.8.tgz#6667fac16c436b5434a387a34dedb013198f6e6e" @@ -1380,6 +1613,11 @@ dependencies: "@babel/types" "^7.20.7" +"@types/estree@1.0.5": + version "1.0.5" + resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.5.tgz#a6ce3e556e00fd9895dd872dd172ad0d4bd687f4" + integrity sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw== + "@types/graceful-fs@^4.1.3": version "4.1.9" resolved "https://registry.yarnpkg.com/@types/graceful-fs/-/graceful-fs-4.1.9.tgz#2a06bc0f68a20ab37b3e36aa238be6abdf49e8b4" @@ -1531,6 +1769,11 @@ ansi-regex@^5.0.1: resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== +ansi-regex@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-6.0.1.tgz#3183e38fae9a65d7cb5e53945cd5897d0260a06a" + integrity sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA== + ansi-styles@^3.2.1: version "3.2.1" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" @@ -1550,7 +1793,17 @@ ansi-styles@^5.0.0: resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-5.2.0.tgz#07449690ad45777d1924ac2abb2fc8895dba836b" integrity sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA== -anymatch@^3.0.3: +ansi-styles@^6.1.0: + version "6.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-6.2.1.tgz#0e62320cf99c21afff3b3012192546aacbfb05c5" + integrity sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug== + +any-promise@^1.0.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/any-promise/-/any-promise-1.3.0.tgz#abc6afeedcea52e809cdc0376aed3ce39635d17f" + integrity sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A== + +anymatch@^3.0.3, anymatch@~3.1.2: version "3.1.3" resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.3.tgz#790c58b19ba1720a84205b57c618d5ad8524973e" integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw== @@ -1572,6 +1825,11 @@ aria-query@5.3.0, aria-query@^5.0.0: dependencies: dequal "^2.0.3" +array-union@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" + integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== + asynckit@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" @@ -1666,6 +1924,11 @@ balanced-match@^1.0.0: resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== +binary-extensions@^2.0.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.3.0.tgz#f6e14a97858d327252200242d4ccfe522c445522" + integrity sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw== + blakejs@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/blakejs/-/blakejs-1.2.1.tgz#5057e4206eadb4a97f7c0b6e197a505042fc3814" @@ -1679,7 +1942,14 @@ brace-expansion@^1.1.7: balanced-match "^1.0.0" concat-map "0.0.1" -braces@^3.0.2: +brace-expansion@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae" + integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA== + dependencies: + balanced-match "^1.0.0" + +braces@^3.0.2, braces@~3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== @@ -1715,6 +1985,18 @@ buffer-from@^1.0.0: resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== +bundle-require@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/bundle-require/-/bundle-require-4.1.0.tgz#3d5fcd19d5160d4cbac5e95ed5a394d1ecd40ce6" + integrity sha512-FeArRFM+ziGkRViKRnSTbHZc35dgmR9yNog05Kn0+ItI59pOAISGvnnIwW1WgFZQW59IxD9QpJnUPkdIPfZuXg== + dependencies: + load-tsconfig "^0.2.3" + +cac@^6.7.12: + version "6.7.14" + resolved "https://registry.yarnpkg.com/cac/-/cac-6.7.14.tgz#804e1e6f506ee363cb0e3ccbb09cad5dd9870959" + integrity sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ== + callsites@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" @@ -1770,6 +2052,21 @@ char-regex@^1.0.2: resolved "https://registry.yarnpkg.com/char-regex/-/char-regex-1.0.2.tgz#d744358226217f981ed58f479b1d6bcc29545dcf" integrity sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw== +chokidar@^3.5.1: + version "3.6.0" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.6.0.tgz#197c6cc669ef2a8dc5e7b4d97ee4e092c3eb0d5b" + integrity sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw== + dependencies: + anymatch "~3.1.2" + braces "~3.0.2" + glob-parent "~5.1.2" + is-binary-path "~2.1.0" + is-glob "~4.0.1" + normalize-path "~3.0.0" + readdirp "~3.6.0" + optionalDependencies: + fsevents "~2.3.2" + ci-info@^3.2.0: version "3.9.0" resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.9.0.tgz#4279a62028a7b1f262f3473fc9605f5e218c59b4" @@ -1830,6 +2127,11 @@ combined-stream@^1.0.8: dependencies: delayed-stream "~1.0.0" +commander@^4.0.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/commander/-/commander-4.1.1.tgz#9fd602bd936294e9e9ef46a3f4d6964044b18068" + integrity sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA== + concat-map@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" @@ -1860,7 +2162,7 @@ create-jest@^29.7.0: jest-util "^29.7.0" prompts "^2.0.1" -cross-spawn@^7.0.3: +cross-spawn@^7.0.0, cross-spawn@^7.0.3: version "7.0.3" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== @@ -1952,6 +2254,13 @@ diff-sequences@^29.6.3: resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-29.6.3.tgz#4deaf894d11407c51efc8418012f9e70b84ea921" integrity sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q== +dir-glob@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" + integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA== + dependencies: + path-type "^4.0.0" + dom-accessibility-api@^0.5.9: version "0.5.16" resolved "https://registry.yarnpkg.com/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz#5a7429e6066eb3664d911e33fb0e45de8eb08453" @@ -1969,6 +2278,11 @@ domexception@^4.0.0: dependencies: webidl-conversions "^7.0.0" +eastasianwidth@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/eastasianwidth/-/eastasianwidth-0.2.0.tgz#696ce2ec0aa0e6ea93a397ffcf24aa7840c827cb" + integrity sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA== + electron-to-chromium@^1.4.668: version "1.4.757" resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.757.tgz#45f7c9341b538f8c4b9ca8af9692e0ed1a776a44" @@ -1984,6 +2298,11 @@ emoji-regex@^8.0.0: resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== +emoji-regex@^9.2.2: + version "9.2.2" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-9.2.2.tgz#840c8803b0d8047f4ff0cf963176b32d4ef3ed72" + integrity sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg== + entities@^4.4.0: version "4.5.0" resolved "https://registry.yarnpkg.com/entities/-/entities-4.5.0.tgz#5d268ea5e7113ec74c4d033b79ea5a35a488fb48" @@ -1996,6 +2315,35 @@ error-ex@^1.3.1: dependencies: is-arrayish "^0.2.1" +esbuild@^0.19.2: + version "0.19.12" + resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.19.12.tgz#dc82ee5dc79e82f5a5c3b4323a2a641827db3e04" + integrity sha512-aARqgq8roFBj054KvQr5f1sFu0D65G+miZRCuJyJ0G13Zwx7vRar5Zhn2tkQNzIXcBrNVsv/8stehpj+GAjgbg== + optionalDependencies: + "@esbuild/aix-ppc64" "0.19.12" + "@esbuild/android-arm" "0.19.12" + "@esbuild/android-arm64" "0.19.12" + "@esbuild/android-x64" "0.19.12" + "@esbuild/darwin-arm64" "0.19.12" + "@esbuild/darwin-x64" "0.19.12" + "@esbuild/freebsd-arm64" "0.19.12" + "@esbuild/freebsd-x64" "0.19.12" + "@esbuild/linux-arm" "0.19.12" + "@esbuild/linux-arm64" "0.19.12" + "@esbuild/linux-ia32" "0.19.12" + "@esbuild/linux-loong64" "0.19.12" + "@esbuild/linux-mips64el" "0.19.12" + "@esbuild/linux-ppc64" "0.19.12" + "@esbuild/linux-riscv64" "0.19.12" + "@esbuild/linux-s390x" "0.19.12" + "@esbuild/linux-x64" "0.19.12" + "@esbuild/netbsd-x64" "0.19.12" + "@esbuild/openbsd-x64" "0.19.12" + "@esbuild/sunos-x64" "0.19.12" + "@esbuild/win32-arm64" "0.19.12" + "@esbuild/win32-ia32" "0.19.12" + "@esbuild/win32-x64" "0.19.12" + escalade@^3.1.1, escalade@^3.1.2: version "3.1.2" resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.2.tgz#54076e9ab29ea5bf3d8f1ed62acffbb88272df27" @@ -2073,11 +2421,29 @@ expect@^29.0.0, expect@^29.7.0: jest-message-util "^29.7.0" jest-util "^29.7.0" +fast-glob@^3.2.9: + version "3.3.2" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.2.tgz#a904501e57cfdd2ffcded45e99a54fef55e46129" + integrity sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow== + dependencies: + "@nodelib/fs.stat" "^2.0.2" + "@nodelib/fs.walk" "^1.2.3" + glob-parent "^5.1.2" + merge2 "^1.3.0" + micromatch "^4.0.4" + fast-json-stable-stringify@2.x, fast-json-stable-stringify@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== +fastq@^1.6.0: + version "1.17.1" + resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.17.1.tgz#2a523f07a4e7b1e81a42b91b8bf2254107753b47" + integrity sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w== + dependencies: + reusify "^1.0.4" + fb-watchman@^2.0.0: version "2.0.2" resolved "https://registry.yarnpkg.com/fb-watchman/-/fb-watchman-2.0.2.tgz#e9524ee6b5c77e9e5001af0f85f3adbb8623255c" @@ -2108,6 +2474,14 @@ find-up@^4.0.0, find-up@^4.1.0: locate-path "^5.0.0" path-exists "^4.0.0" +foreground-child@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/foreground-child/-/foreground-child-3.1.1.tgz#1d173e776d75d2772fed08efe4a0de1ea1b12d0d" + integrity sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg== + dependencies: + cross-spawn "^7.0.0" + signal-exit "^4.0.1" + form-data@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452" @@ -2129,7 +2503,7 @@ fs.realpath@^1.0.0: resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== -fsevents@^2.3.2: +fsevents@^2.3.2, fsevents@~2.3.2: version "2.3.3" resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== @@ -2159,6 +2533,24 @@ get-stream@^6.0.0: resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== +glob-parent@^5.1.2, glob-parent@~5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" + integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== + dependencies: + is-glob "^4.0.1" + +glob@^10.3.10: + version "10.3.12" + resolved "https://registry.yarnpkg.com/glob/-/glob-10.3.12.tgz#3a65c363c2e9998d220338e88a5f6ac97302960b" + integrity sha512-TCNv8vJ+xz4QiqTpfOJA7HvYv+tNIRHKfUWw/q+v2jdgN4ebz+KY9tGx5J4rHP0o84mNP+ApH66HRX8us3Khqg== + dependencies: + foreground-child "^3.1.0" + jackspeak "^2.3.6" + minimatch "^9.0.1" + minipass "^7.0.4" + path-scurry "^1.10.2" + glob@^7.1.3, glob@^7.1.4: version "7.2.3" resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" @@ -2176,6 +2568,18 @@ globals@^11.1.0: resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== +globby@^11.0.3: + version "11.1.0" + resolved "https://registry.yarnpkg.com/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b" + integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g== + dependencies: + array-union "^2.1.0" + dir-glob "^3.0.1" + fast-glob "^3.2.9" + ignore "^5.2.0" + merge2 "^1.4.1" + slash "^3.0.0" + graceful-fs@^4.2.9: version "4.2.11" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" @@ -2239,6 +2643,11 @@ iconv-lite@0.6.3: dependencies: safer-buffer ">= 2.1.2 < 3.0.0" +ignore@^5.2.0: + version "5.3.1" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.1.tgz#5073e554cd42c5b33b394375f538b8593e34d4ef" + integrity sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw== + import-local@^3.0.2: version "3.1.0" resolved "https://registry.yarnpkg.com/import-local/-/import-local-3.1.0.tgz#b4479df8a5fd44f6cdce24070675676063c95cb4" @@ -2275,6 +2684,13 @@ is-arrayish@^0.2.1: resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" integrity sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg== +is-binary-path@~2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" + integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== + dependencies: + binary-extensions "^2.0.0" + is-core-module@^2.13.0: version "2.13.1" resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.13.1.tgz#ad0d7532c6fea9da1ebdc82742d74525c6273384" @@ -2282,6 +2698,11 @@ is-core-module@^2.13.0: dependencies: hasown "^2.0.0" +is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== + is-fullwidth-code-point@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" @@ -2292,6 +2713,13 @@ is-generator-fn@^2.0.0: resolved "https://registry.yarnpkg.com/is-generator-fn/-/is-generator-fn-2.1.0.tgz#7d140adc389aaf3011a8f2a2a4cfa6faadffb118" integrity sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ== +is-glob@^4.0.1, is-glob@~4.0.1: + version "4.0.3" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" + integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== + dependencies: + is-extglob "^2.1.1" + is-number@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" @@ -2365,6 +2793,15 @@ istanbul-reports@^3.1.3: html-escaper "^2.0.0" istanbul-lib-report "^3.0.0" +jackspeak@^2.3.6: + version "2.3.6" + resolved "https://registry.yarnpkg.com/jackspeak/-/jackspeak-2.3.6.tgz#647ecc472238aee4b06ac0e461acc21a8c505ca8" + integrity sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ== + dependencies: + "@isaacs/cliui" "^8.0.2" + optionalDependencies: + "@pkgjs/parseargs" "^0.11.0" + jest-changed-files@^29.7.0: version "29.7.0" resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-29.7.0.tgz#1c06d07e77c78e1585d020424dedc10d6e17ac3a" @@ -2737,6 +3174,11 @@ jest@^29.7.0: import-local "^3.0.2" jest-cli "^29.7.0" +joycon@^3.0.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/joycon/-/joycon-3.1.1.tgz#bce8596d6ae808f8b68168f5fc69280996894f03" + integrity sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw== + "js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" @@ -2835,11 +3277,21 @@ leven@^3.1.0: resolved "https://registry.yarnpkg.com/leven/-/leven-3.1.0.tgz#77891de834064cccba82ae7842bb6b14a13ed7f2" integrity sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A== +lilconfig@^3.0.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-3.1.1.tgz#9d8a246fa753106cfc205fd2d77042faca56e5e3" + integrity sha512-O18pf7nyvHTckunPWCV1XUNXU1piu01y2b7ATJ0ppkUkk8ocqVWBrYjJBCwHDjD/ZWcfyrA0P4gKhzWGi5EINQ== + lines-and-columns@^1.1.6: version "1.2.4" resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== +load-tsconfig@^0.2.3: + version "0.2.5" + resolved "https://registry.yarnpkg.com/load-tsconfig/-/load-tsconfig-0.2.5.tgz#453b8cd8961bfb912dea77eb6c168fe8cca3d3a1" + integrity sha512-IXO6OCs9yg8tMKzfPZ1YmheJbZCiEsnBdcB03l0OcfK9prKnJb96siuHCr5Fl37/yo9DnKU+TLpxzTUspw9shg== + locate-path@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0" @@ -2857,6 +3309,11 @@ lodash.memoize@4.x: resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe" integrity sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag== +lodash.sortby@^4.7.0: + version "4.7.0" + resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438" + integrity sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA== + lodash@^4.17.21: version "4.17.21" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" @@ -2869,6 +3326,11 @@ loose-envify@^1.1.0: dependencies: js-tokens "^3.0.0 || ^4.0.0" +lru-cache@^10.2.0: + version "10.2.2" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.2.2.tgz#48206bc114c1252940c41b25b41af5b545aca878" + integrity sha512-9hp3Vp2/hFQUiIwKo8XCeFVnrg8Pk3TYNPIR7tJADKi5YfcF7vEaK7avFHTlSy3kOKYaJQaalfEo6YuXdceBOQ== + lru-cache@^5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" @@ -2912,6 +3374,11 @@ merge-stream@^2.0.0: resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== +merge2@^1.3.0, merge2@^1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" + integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== + micromatch@^4.0.4: version "4.0.5" resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6" @@ -2949,11 +3416,32 @@ minimatch@^3.0.4, minimatch@^3.1.1: dependencies: brace-expansion "^1.1.7" +minimatch@^9.0.1: + version "9.0.4" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.4.tgz#8e49c731d1749cbec05050ee5145147b32496a51" + integrity sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw== + dependencies: + brace-expansion "^2.0.1" + +"minipass@^5.0.0 || ^6.0.2 || ^7.0.0", minipass@^7.0.4: + version "7.1.0" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-7.1.0.tgz#b545f84af94e567386770159302ca113469c80b8" + integrity sha512-oGZRv2OT1lO2UF1zUcwdTb3wqUwI0kBGTgt/T7OdSj6M6N5m3o5uPf0AIW6lVxGGoiWUR7e2AwTE+xiwK8WQig== + ms@2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== +mz@^2.7.0: + version "2.7.0" + resolved "https://registry.yarnpkg.com/mz/-/mz-2.7.0.tgz#95008057a56cafadc2bc63dde7f9ff6955948e32" + integrity sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q== + dependencies: + any-promise "^1.0.0" + object-assign "^4.0.1" + thenify-all "^1.0.0" + natural-compare@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" @@ -2983,7 +3471,7 @@ node-releases@^2.0.14: resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.14.tgz#2ffb053bceb8b2be8495ece1ab6ce600c4461b0b" integrity sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw== -normalize-path@^3.0.0: +normalize-path@^3.0.0, normalize-path@~3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== @@ -3000,6 +3488,11 @@ nwsapi@^2.2.2: resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.2.9.tgz#7f3303218372db2e9f27c27766bcfc59ae7e61c6" integrity sha512-2f3F0SEEer8bBu0dsNCFF50N0cTThV1nWFYcEYFZttdW0lDAoybv9cQoK7X7/68Z89S7FoRrVjP1LPX4XRf9vg== +object-assign@^4.0.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== + once@^1.3.0: version "1.4.0" resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" @@ -3077,17 +3570,30 @@ path-parse@^1.0.7: resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== +path-scurry@^1.10.2: + version "1.10.2" + resolved "https://registry.yarnpkg.com/path-scurry/-/path-scurry-1.10.2.tgz#8f6357eb1239d5fa1da8b9f70e9c080675458ba7" + integrity sha512-7xTavNy5RQXnsjANvVvMkEjvloOinkAjv/Z6Ildz9v2RinZ4SBKTWFOVRbaF8p0vpHnyjV/UwNDdKuUv6M5qcA== + dependencies: + lru-cache "^10.2.0" + minipass "^5.0.0 || ^6.0.2 || ^7.0.0" + +path-type@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" + integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== + picocolors@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== -picomatch@^2.0.4, picomatch@^2.2.3, picomatch@^2.3.1: +picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.3, picomatch@^2.3.1: version "2.3.1" resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== -pirates@^4.0.4: +pirates@^4.0.1, pirates@^4.0.4: version "4.0.6" resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.6.tgz#3018ae32ecfcff6c29ba2267cbf21166ac1f36b9" integrity sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg== @@ -3099,6 +3605,14 @@ pkg-dir@^4.2.0: dependencies: find-up "^4.0.0" +postcss-load-config@^4.0.1: + version "4.0.2" + resolved "https://registry.yarnpkg.com/postcss-load-config/-/postcss-load-config-4.0.2.tgz#7159dcf626118d33e299f485d6afe4aff7c4a3e3" + integrity sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ== + dependencies: + lilconfig "^3.0.0" + yaml "^2.3.4" + pretty-format@^27.0.2: version "27.5.1" resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-27.5.1.tgz#2181879fdea51a7a5851fb39d920faa63f01d88e" @@ -3130,7 +3644,7 @@ psl@^1.1.33: resolved "https://registry.yarnpkg.com/psl/-/psl-1.9.0.tgz#d0df2a137f00794565fcaf3b2c00cd09f8d5a5a7" integrity sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag== -punycode@^2.1.1: +punycode@^2.1.0, punycode@^2.1.1: version "2.3.1" resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.1.tgz#027422e2faec0b25e1549c3e1bd8309b9133b6e5" integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg== @@ -3145,6 +3659,11 @@ querystringify@^2.1.1: resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-2.2.0.tgz#3345941b4153cb9d082d8eee4cda2016a9aef7f6" integrity sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ== +queue-microtask@^1.2.2: + version "1.2.3" + resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" + integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== + rdf-canonize@^3.4.0: version "3.4.0" resolved "https://registry.yarnpkg.com/rdf-canonize/-/rdf-canonize-3.4.0.tgz#87f88342b173cc371d812a07de350f0c1aa9f058" @@ -3177,6 +3696,13 @@ react@^18.3.1: dependencies: loose-envify "^1.1.0" +readdirp@~3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" + integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA== + dependencies: + picomatch "^2.2.1" + redent@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/redent/-/redent-3.0.0.tgz#e557b7998316bb53c9f1f56fa626352c6963059f" @@ -3264,6 +3790,43 @@ resolve@^1.14.2, resolve@^1.20.0: path-parse "^1.0.7" supports-preserve-symlinks-flag "^1.0.0" +reusify@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" + integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== + +rollup@^4.0.2: + version "4.17.2" + resolved "https://registry.yarnpkg.com/rollup/-/rollup-4.17.2.tgz#26d1785d0144122277fdb20ab3a24729ae68301f" + integrity sha512-/9ClTJPByC0U4zNLowV1tMBe8yMEAxewtR3cUNX5BoEpGH3dQEWpJLr6CLp0fPdYRF/fzVOgvDb1zXuakwF5kQ== + dependencies: + "@types/estree" "1.0.5" + optionalDependencies: + "@rollup/rollup-android-arm-eabi" "4.17.2" + "@rollup/rollup-android-arm64" "4.17.2" + "@rollup/rollup-darwin-arm64" "4.17.2" + "@rollup/rollup-darwin-x64" "4.17.2" + "@rollup/rollup-linux-arm-gnueabihf" "4.17.2" + "@rollup/rollup-linux-arm-musleabihf" "4.17.2" + "@rollup/rollup-linux-arm64-gnu" "4.17.2" + "@rollup/rollup-linux-arm64-musl" "4.17.2" + "@rollup/rollup-linux-powerpc64le-gnu" "4.17.2" + "@rollup/rollup-linux-riscv64-gnu" "4.17.2" + "@rollup/rollup-linux-s390x-gnu" "4.17.2" + "@rollup/rollup-linux-x64-gnu" "4.17.2" + "@rollup/rollup-linux-x64-musl" "4.17.2" + "@rollup/rollup-win32-arm64-msvc" "4.17.2" + "@rollup/rollup-win32-ia32-msvc" "4.17.2" + "@rollup/rollup-win32-x64-msvc" "4.17.2" + fsevents "~2.3.2" + +run-parallel@^1.1.9: + version "1.2.0" + resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" + integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA== + dependencies: + queue-microtask "^1.2.2" + "safer-buffer@>= 2.1.2 < 3.0.0": version "2.1.2" resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" @@ -3315,6 +3878,11 @@ signal-exit@^3.0.3, signal-exit@^3.0.7: resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== +signal-exit@^4.0.1: + version "4.1.0" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-4.1.0.tgz#952188c1cbd546070e2dd20d0f41c0ae0530cb04" + integrity sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw== + sisteransi@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/sisteransi/-/sisteransi-1.0.5.tgz#134d681297756437cc05ca01370d3a7a571075ed" @@ -3333,6 +3901,13 @@ source-map-support@0.5.13: buffer-from "^1.0.0" source-map "^0.6.0" +source-map@0.8.0-beta.0: + version "0.8.0-beta.0" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.8.0-beta.0.tgz#d4c1bb42c3f7ee925f005927ba10709e0d1d1f11" + integrity sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA== + dependencies: + whatwg-url "^7.0.0" + source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" @@ -3358,7 +3933,7 @@ string-length@^4.0.1: char-regex "^1.0.2" strip-ansi "^6.0.0" -string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: +"string-width-cjs@npm:string-width@^4.2.0", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: version "4.2.3" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== @@ -3367,13 +3942,29 @@ string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: is-fullwidth-code-point "^3.0.0" strip-ansi "^6.0.1" -strip-ansi@^6.0.0, strip-ansi@^6.0.1: +string-width@^5.0.1, string-width@^5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-5.1.2.tgz#14f8daec6d81e7221d2a357e668cab73bdbca794" + integrity sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA== + dependencies: + eastasianwidth "^0.2.0" + emoji-regex "^9.2.2" + strip-ansi "^7.0.1" + +"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== dependencies: ansi-regex "^5.0.1" +strip-ansi@^7.0.1: + version "7.1.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.1.0.tgz#d5b6568ca689d8561370b0707685d22434faff45" + integrity sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ== + dependencies: + ansi-regex "^6.0.1" + strip-bom@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-4.0.0.tgz#9c3505c1db45bcedca3d9cf7a16f5c5aa3901878" @@ -3396,6 +3987,19 @@ strip-json-comments@^3.1.1: resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== +sucrase@^3.20.3: + version "3.35.0" + resolved "https://registry.yarnpkg.com/sucrase/-/sucrase-3.35.0.tgz#57f17a3d7e19b36d8995f06679d121be914ae263" + integrity sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA== + dependencies: + "@jridgewell/gen-mapping" "^0.3.2" + commander "^4.0.0" + glob "^10.3.10" + lines-and-columns "^1.1.6" + mz "^2.7.0" + pirates "^4.0.1" + ts-interface-checker "^0.1.9" + supports-color@^5.3.0: version "5.5.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" @@ -3441,6 +4045,20 @@ text-encoding@^0.7.0: resolved "https://registry.yarnpkg.com/text-encoding/-/text-encoding-0.7.0.tgz#f895e836e45990624086601798ea98e8f36ee643" integrity sha512-oJQ3f1hrOnbRLOcwKz0Liq2IcrvDeZRHXhd9RgLrsT+DjWY/nty1Hi7v3dtkaEYbPYe0mUoOfzRrMwfXXwgPUA== +thenify-all@^1.0.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/thenify-all/-/thenify-all-1.6.0.tgz#1a1918d402d8fc3f98fbf234db0bcc8cc10e9726" + integrity sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA== + dependencies: + thenify ">= 3.1.0 < 4" + +"thenify@>= 3.1.0 < 4": + version "3.3.1" + resolved "https://registry.yarnpkg.com/thenify/-/thenify-3.3.1.tgz#8932e686a4066038a016dd9e2ca46add9838a95f" + integrity sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw== + dependencies: + any-promise "^1.0.0" + tmpl@1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.5.tgz#8683e0b902bb9c20c4f726e3c0b69f36518c07cc" @@ -3468,6 +4086,13 @@ tough-cookie@^4.1.2: universalify "^0.2.0" url-parse "^1.5.3" +tr46@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/tr46/-/tr46-1.0.1.tgz#a8b13fd6bfd2489519674ccde55ba3693b706d09" + integrity sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA== + dependencies: + punycode "^2.1.0" + tr46@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/tr46/-/tr46-3.0.0.tgz#555c4e297a950617e8eeddef633c87d4d9d6cbf9" @@ -3475,6 +4100,16 @@ tr46@^3.0.0: dependencies: punycode "^2.1.1" +tree-kill@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/tree-kill/-/tree-kill-1.2.2.tgz#4ca09a9092c88b73a7cdc5e8a01b507b0790a0cc" + integrity sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A== + +ts-interface-checker@^0.1.9: + version "0.1.13" + resolved "https://registry.yarnpkg.com/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz#784fd3d679722bc103b1b4b8030bcddb5db2a699" + integrity sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA== + ts-jest@^29.1.2: version "29.1.2" resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-29.1.2.tgz#7613d8c81c43c8cb312c6904027257e814c40e09" @@ -3489,6 +4124,26 @@ ts-jest@^29.1.2: semver "^7.5.3" yargs-parser "^21.0.1" +tsup@^8.0.2: + version "8.0.2" + resolved "https://registry.yarnpkg.com/tsup/-/tsup-8.0.2.tgz#c63192a08386515103e2c44ac5a23bdff75c5fa1" + integrity sha512-NY8xtQXdH7hDUAZwcQdY/Vzlw9johQsaqf7iwZ6g1DOUlFYQ5/AtVAjTvihhEyeRlGo4dLRVHtrRaL35M1daqQ== + dependencies: + bundle-require "^4.0.0" + cac "^6.7.12" + chokidar "^3.5.1" + debug "^4.3.1" + esbuild "^0.19.2" + execa "^5.0.0" + globby "^11.0.3" + joycon "^3.0.1" + postcss-load-config "^4.0.1" + resolve-from "^5.0.0" + rollup "^4.0.2" + source-map "0.8.0-beta.0" + sucrase "^3.20.3" + tree-kill "^1.2.2" + type-detect@4.0.8: version "4.0.8" resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" @@ -3588,6 +4243,11 @@ web-streams-polyfill@^3.0.3: resolved "https://registry.yarnpkg.com/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz#2073b91a2fdb1fbfbd401e7de0ac9f8214cecb4b" integrity sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw== +webidl-conversions@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-4.0.2.tgz#a855980b1f0b6b359ba1d5d9fb39ae941faa63ad" + integrity sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg== + webidl-conversions@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-7.0.0.tgz#256b4e1882be7debbf01d05f0aa2039778ea080a" @@ -3613,6 +4273,15 @@ whatwg-url@^11.0.0: tr46 "^3.0.0" webidl-conversions "^7.0.0" +whatwg-url@^7.0.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-7.1.0.tgz#c2c492f1eca612988efd3d2266be1b9fc6170d06" + integrity sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg== + dependencies: + lodash.sortby "^4.7.0" + tr46 "^1.0.1" + webidl-conversions "^4.0.2" + which@^2.0.1: version "2.0.2" resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" @@ -3620,7 +4289,7 @@ which@^2.0.1: dependencies: isexe "^2.0.0" -wrap-ansi@^7.0.0: +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== @@ -3629,6 +4298,15 @@ wrap-ansi@^7.0.0: string-width "^4.1.0" strip-ansi "^6.0.0" +wrap-ansi@^8.1.0: + version "8.1.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214" + integrity sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ== + dependencies: + ansi-styles "^6.1.0" + string-width "^5.0.1" + strip-ansi "^7.0.1" + wrappy@1: version "1.0.2" resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" @@ -3672,6 +4350,11 @@ yallist@^4.0.0: resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== +yaml@^2.3.4: + version "2.4.2" + resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.4.2.tgz#7a2b30f2243a5fc299e1f14ca58d475ed4bc5362" + integrity sha512-B3VqDZ+JAg1nZpaEmWtTXUlBneoGx6CPM9b0TENK6aoSu5t73dItudwdgmi6tHlIZZId4dZ9skcAQ2UbcyAeVA== + yargs-parser@^21.0.1, yargs-parser@^21.1.1: version "21.1.1" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.1.1.tgz#9096bceebf990d21bb31fa9516e0ede294a77d35" diff --git a/govtool/packages/wallet-connector/.gitignore b/govtool/packages/wallet-connector/.gitignore new file mode 100644 index 000000000..76add878f --- /dev/null +++ b/govtool/packages/wallet-connector/.gitignore @@ -0,0 +1,2 @@ +node_modules +dist \ No newline at end of file diff --git a/govtool/packages/wallet-connector/WalletProvider.tsx b/govtool/packages/wallet-connector/WalletProvider.tsx index bc03bcc3a..2c4cd6f24 100644 --- a/govtool/packages/wallet-connector/WalletProvider.tsx +++ b/govtool/packages/wallet-connector/WalletProvider.tsx @@ -1,4 +1,4 @@ -import React, { createContext, useContext, useMemo, useState } from "react"; +import { createContext, useContext, useMemo, useState } from "react"; import { WalletService } from "./WalletService"; import { @@ -23,7 +23,7 @@ const WalletProvider = ({ children }: WalletContextProviderProps) => { if (newWalletAPI) setWalletAPI(newWalletAPI); } catch (e) { - setEnableError(e); + setEnableError(e as string); throw e; } finally { setIsEnableLoading(false); diff --git a/govtool/packages/wallet-connector/package.json b/govtool/packages/wallet-connector/package.json index 8471b0c61..cb2fb4dc4 100644 --- a/govtool/packages/wallet-connector/package.json +++ b/govtool/packages/wallet-connector/package.json @@ -1,12 +1,26 @@ { "name": "govtool-wallet-connector", + "description": "A wallet connector for the GovTool platform", "version": "0.0.1", - "main": "index.ts", + "main": "./dist/index.js", + "module": "./dist/index.mjs", + "types": "./dist/index.d.ts", "license": "MIT", + "keywords": [ + "govtool", + "wallet", + "connector" + ], + "author": "IntersectMBO", + "scripts": { + "build": "tsup" + }, "dependencies": { "react": "^18.3.1" }, "devDependencies": { - "@types/react": "^18.3.1" + "@types/react": "^18.3.1", + "tsup": "^8.0.2", + "typescript": "^5.4.5" } } diff --git a/govtool/packages/wallet-connector/tsconfig.json b/govtool/packages/wallet-connector/tsconfig.json new file mode 100644 index 000000000..584c1990d --- /dev/null +++ b/govtool/packages/wallet-connector/tsconfig.json @@ -0,0 +1,109 @@ +{ + "compilerOptions": { + /* Visit https://aka.ms/tsconfig to read more about this file */ + + /* Projects */ + // "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */ + // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ + // "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */ + // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */ + // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ + // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ + + /* Language and Environment */ + "target": "es2016" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */, + // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ + "jsx": "react-jsx" /* Specify what JSX code is generated. */, + // "experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */ + // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ + // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */ + // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */ + // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */ + // "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */ + // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ + // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ + // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */ + + /* Modules */ + "module": "commonjs" /* Specify what module code is generated. */, + // "rootDir": "./", /* Specify the root folder within your source files. */ + // "moduleResolution": "node10", /* Specify how TypeScript looks up a file from a given module specifier. */ + // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ + // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ + // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ + // "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */ + // "types": [], /* Specify type package names to be included without being referenced in a source file. */ + // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ + // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */ + // "allowImportingTsExtensions": true, /* Allow imports to include TypeScript file extensions. Requires '--moduleResolution bundler' and either '--noEmit' or '--emitDeclarationOnly' to be set. */ + // "resolvePackageJsonExports": true, /* Use the package.json 'exports' field when resolving package imports. */ + // "resolvePackageJsonImports": true, /* Use the package.json 'imports' field when resolving imports. */ + // "customConditions": [], /* Conditions to set in addition to the resolver-specific defaults when resolving imports. */ + // "resolveJsonModule": true, /* Enable importing .json files. */ + // "allowArbitraryExtensions": true, /* Enable importing files with any extension, provided a declaration file is present. */ + // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */ + + /* JavaScript Support */ + // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */ + // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ + // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */ + + /* Emit */ + // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ + // "declarationMap": true, /* Create sourcemaps for d.ts files. */ + // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ + // "sourceMap": true, /* Create source map files for emitted JavaScript files. */ + // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ + // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */ + // "outDir": "./", /* Specify an output folder for all emitted files. */ + // "removeComments": true, /* Disable emitting comments. */ + // "noEmit": true, /* Disable emitting files from a compilation. */ + // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ + // "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types. */ + // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */ + // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */ + // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ + // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */ + // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */ + // "newLine": "crlf", /* Set the newline character for emitting files. */ + // "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */ + // "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */ + // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */ + // "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */ + // "declarationDir": "./", /* Specify the output directory for generated declaration files. */ + // "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */ + + /* Interop Constraints */ + // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ + // "verbatimModuleSyntax": true, /* Do not transform or elide any imports or exports not marked as type-only, ensuring they are written in the output file's format based on the 'module' setting. */ + // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ + "esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */, + // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ + "forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */, + + /* Type Checking */ + "strict": true /* Enable all strict type-checking options. */, + // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */ + // "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */ + // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ + // "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */ + // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */ + // "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */ + // "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */ + // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */ + // "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */ + // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */ + // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */ + // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */ + // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */ + // "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */ + // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */ + // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */ + // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */ + // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */ + + /* Completeness */ + // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ + "skipLibCheck": true /* Skip type checking all .d.ts files. */ + } +} diff --git a/govtool/packages/wallet-connector/tsup.config.ts b/govtool/packages/wallet-connector/tsup.config.ts new file mode 100644 index 000000000..0653a5af9 --- /dev/null +++ b/govtool/packages/wallet-connector/tsup.config.ts @@ -0,0 +1,10 @@ +import { defineConfig } from "tsup"; + +export default defineConfig({ + entry: ["index.ts"], + format: ["cjs", "esm"], + dts: true, + splitting: false, + sourcemap: true, + clean: true, +}); diff --git a/govtool/packages/wallet-connector/yarn.lock b/govtool/packages/wallet-connector/yarn.lock index bafef23bc..959093ed8 100644 --- a/govtool/packages/wallet-connector/yarn.lock +++ b/govtool/packages/wallet-connector/yarn.lock @@ -2,6 +2,276 @@ # yarn lockfile v1 +"@esbuild/aix-ppc64@0.19.12": + version "0.19.12" + resolved "https://registry.yarnpkg.com/@esbuild/aix-ppc64/-/aix-ppc64-0.19.12.tgz#d1bc06aedb6936b3b6d313bf809a5a40387d2b7f" + integrity sha512-bmoCYyWdEL3wDQIVbcyzRyeKLgk2WtWLTWz1ZIAZF/EGbNOwSA6ew3PftJ1PqMiOOGu0OyFMzG53L0zqIpPeNA== + +"@esbuild/android-arm64@0.19.12": + version "0.19.12" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.19.12.tgz#7ad65a36cfdb7e0d429c353e00f680d737c2aed4" + integrity sha512-P0UVNGIienjZv3f5zq0DP3Nt2IE/3plFzuaS96vihvD0Hd6H/q4WXUGpCxD/E8YrSXfNyRPbpTq+T8ZQioSuPA== + +"@esbuild/android-arm@0.19.12": + version "0.19.12" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.19.12.tgz#b0c26536f37776162ca8bde25e42040c203f2824" + integrity sha512-qg/Lj1mu3CdQlDEEiWrlC4eaPZ1KztwGJ9B6J+/6G+/4ewxJg7gqj8eVYWvao1bXrqGiW2rsBZFSX3q2lcW05w== + +"@esbuild/android-x64@0.19.12": + version "0.19.12" + resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.19.12.tgz#cb13e2211282012194d89bf3bfe7721273473b3d" + integrity sha512-3k7ZoUW6Q6YqhdhIaq/WZ7HwBpnFBlW905Fa4s4qWJyiNOgT1dOqDiVAQFwBH7gBRZr17gLrlFCRzF6jFh7Kew== + +"@esbuild/darwin-arm64@0.19.12": + version "0.19.12" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.19.12.tgz#cbee41e988020d4b516e9d9e44dd29200996275e" + integrity sha512-B6IeSgZgtEzGC42jsI+YYu9Z3HKRxp8ZT3cqhvliEHovq8HSX2YX8lNocDn79gCKJXOSaEot9MVYky7AKjCs8g== + +"@esbuild/darwin-x64@0.19.12": + version "0.19.12" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.19.12.tgz#e37d9633246d52aecf491ee916ece709f9d5f4cd" + integrity sha512-hKoVkKzFiToTgn+41qGhsUJXFlIjxI/jSYeZf3ugemDYZldIXIxhvwN6erJGlX4t5h417iFuheZ7l+YVn05N3A== + +"@esbuild/freebsd-arm64@0.19.12": + version "0.19.12" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.19.12.tgz#1ee4d8b682ed363b08af74d1ea2b2b4dbba76487" + integrity sha512-4aRvFIXmwAcDBw9AueDQ2YnGmz5L6obe5kmPT8Vd+/+x/JMVKCgdcRwH6APrbpNXsPz+K653Qg8HB/oXvXVukA== + +"@esbuild/freebsd-x64@0.19.12": + version "0.19.12" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.19.12.tgz#37a693553d42ff77cd7126764b535fb6cc28a11c" + integrity sha512-EYoXZ4d8xtBoVN7CEwWY2IN4ho76xjYXqSXMNccFSx2lgqOG/1TBPW0yPx1bJZk94qu3tX0fycJeeQsKovA8gg== + +"@esbuild/linux-arm64@0.19.12": + version "0.19.12" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.19.12.tgz#be9b145985ec6c57470e0e051d887b09dddb2d4b" + integrity sha512-EoTjyYyLuVPfdPLsGVVVC8a0p1BFFvtpQDB/YLEhaXyf/5bczaGeN15QkR+O4S5LeJ92Tqotve7i1jn35qwvdA== + +"@esbuild/linux-arm@0.19.12": + version "0.19.12" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.19.12.tgz#207ecd982a8db95f7b5279207d0ff2331acf5eef" + integrity sha512-J5jPms//KhSNv+LO1S1TX1UWp1ucM6N6XuL6ITdKWElCu8wXP72l9MM0zDTzzeikVyqFE6U8YAV9/tFyj0ti+w== + +"@esbuild/linux-ia32@0.19.12": + version "0.19.12" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.19.12.tgz#d0d86b5ca1562523dc284a6723293a52d5860601" + integrity sha512-Thsa42rrP1+UIGaWz47uydHSBOgTUnwBwNq59khgIwktK6x60Hivfbux9iNR0eHCHzOLjLMLfUMLCypBkZXMHA== + +"@esbuild/linux-loong64@0.19.12": + version "0.19.12" + resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.19.12.tgz#9a37f87fec4b8408e682b528391fa22afd952299" + integrity sha512-LiXdXA0s3IqRRjm6rV6XaWATScKAXjI4R4LoDlvO7+yQqFdlr1Bax62sRwkVvRIrwXxvtYEHHI4dm50jAXkuAA== + +"@esbuild/linux-mips64el@0.19.12": + version "0.19.12" + resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.19.12.tgz#4ddebd4e6eeba20b509d8e74c8e30d8ace0b89ec" + integrity sha512-fEnAuj5VGTanfJ07ff0gOA6IPsvrVHLVb6Lyd1g2/ed67oU1eFzL0r9WL7ZzscD+/N6i3dWumGE1Un4f7Amf+w== + +"@esbuild/linux-ppc64@0.19.12": + version "0.19.12" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.19.12.tgz#adb67dadb73656849f63cd522f5ecb351dd8dee8" + integrity sha512-nYJA2/QPimDQOh1rKWedNOe3Gfc8PabU7HT3iXWtNUbRzXS9+vgB0Fjaqr//XNbd82mCxHzik2qotuI89cfixg== + +"@esbuild/linux-riscv64@0.19.12": + version "0.19.12" + resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.19.12.tgz#11bc0698bf0a2abf8727f1c7ace2112612c15adf" + integrity sha512-2MueBrlPQCw5dVJJpQdUYgeqIzDQgw3QtiAHUC4RBz9FXPrskyyU3VI1hw7C0BSKB9OduwSJ79FTCqtGMWqJHg== + +"@esbuild/linux-s390x@0.19.12": + version "0.19.12" + resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.19.12.tgz#e86fb8ffba7c5c92ba91fc3b27ed5a70196c3cc8" + integrity sha512-+Pil1Nv3Umes4m3AZKqA2anfhJiVmNCYkPchwFJNEJN5QxmTs1uzyy4TvmDrCRNT2ApwSari7ZIgrPeUx4UZDg== + +"@esbuild/linux-x64@0.19.12": + version "0.19.12" + resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.19.12.tgz#5f37cfdc705aea687dfe5dfbec086a05acfe9c78" + integrity sha512-B71g1QpxfwBvNrfyJdVDexenDIt1CiDN1TIXLbhOw0KhJzE78KIFGX6OJ9MrtC0oOqMWf+0xop4qEU8JrJTwCg== + +"@esbuild/netbsd-x64@0.19.12": + version "0.19.12" + resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.19.12.tgz#29da566a75324e0d0dd7e47519ba2f7ef168657b" + integrity sha512-3ltjQ7n1owJgFbuC61Oj++XhtzmymoCihNFgT84UAmJnxJfm4sYCiSLTXZtE00VWYpPMYc+ZQmB6xbSdVh0JWA== + +"@esbuild/openbsd-x64@0.19.12": + version "0.19.12" + resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.19.12.tgz#306c0acbdb5a99c95be98bdd1d47c916e7dc3ff0" + integrity sha512-RbrfTB9SWsr0kWmb9srfF+L933uMDdu9BIzdA7os2t0TXhCRjrQyCeOt6wVxr79CKD4c+p+YhCj31HBkYcXebw== + +"@esbuild/sunos-x64@0.19.12": + version "0.19.12" + resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.19.12.tgz#0933eaab9af8b9b2c930236f62aae3fc593faf30" + integrity sha512-HKjJwRrW8uWtCQnQOz9qcU3mUZhTUQvi56Q8DPTLLB+DawoiQdjsYq+j+D3s9I8VFtDr+F9CjgXKKC4ss89IeA== + +"@esbuild/win32-arm64@0.19.12": + version "0.19.12" + resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.19.12.tgz#773bdbaa1971b36db2f6560088639ccd1e6773ae" + integrity sha512-URgtR1dJnmGvX864pn1B2YUYNzjmXkuJOIqG2HdU62MVS4EHpU2946OZoTMnRUHklGtJdJZ33QfzdjGACXhn1A== + +"@esbuild/win32-ia32@0.19.12": + version "0.19.12" + resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.19.12.tgz#000516cad06354cc84a73f0943a4aa690ef6fd67" + integrity sha512-+ZOE6pUkMOJfmxmBZElNOx72NKpIa/HFOMGzu8fqzQJ5kgf6aTGrcJaFsNiVMH4JKpMipyK+7k0n2UXN7a8YKQ== + +"@esbuild/win32-x64@0.19.12": + version "0.19.12" + resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.19.12.tgz#c57c8afbb4054a3ab8317591a0b7320360b444ae" + integrity sha512-T1QyPSDCyMXaO3pzBkF96E8xMkiRYbUEZADd29SyPGabqxMViNoii+NcK7eWJAEoU6RZyEm5lVSIjTmcdoB9HA== + +"@isaacs/cliui@^8.0.2": + version "8.0.2" + resolved "https://registry.yarnpkg.com/@isaacs/cliui/-/cliui-8.0.2.tgz#b37667b7bc181c168782259bab42474fbf52b550" + integrity sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA== + dependencies: + string-width "^5.1.2" + string-width-cjs "npm:string-width@^4.2.0" + strip-ansi "^7.0.1" + strip-ansi-cjs "npm:strip-ansi@^6.0.1" + wrap-ansi "^8.1.0" + wrap-ansi-cjs "npm:wrap-ansi@^7.0.0" + +"@jridgewell/gen-mapping@^0.3.2": + version "0.3.5" + resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz#dcce6aff74bdf6dad1a95802b69b04a2fcb1fb36" + integrity sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg== + dependencies: + "@jridgewell/set-array" "^1.2.1" + "@jridgewell/sourcemap-codec" "^1.4.10" + "@jridgewell/trace-mapping" "^0.3.24" + +"@jridgewell/resolve-uri@^3.1.0": + version "3.1.2" + resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz#7a0ee601f60f99a20c7c7c5ff0c80388c1189bd6" + integrity sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw== + +"@jridgewell/set-array@^1.2.1": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.2.1.tgz#558fb6472ed16a4c850b889530e6b36438c49280" + integrity sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A== + +"@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.14": + version "1.4.15" + resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz#d7c6e6755c78567a951e04ab52ef0fd26de59f32" + integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg== + +"@jridgewell/trace-mapping@^0.3.24": + version "0.3.25" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz#15f190e98895f3fc23276ee14bc76b675c2e50f0" + integrity sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ== + dependencies: + "@jridgewell/resolve-uri" "^3.1.0" + "@jridgewell/sourcemap-codec" "^1.4.14" + +"@nodelib/fs.scandir@2.1.5": + version "2.1.5" + resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" + integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g== + dependencies: + "@nodelib/fs.stat" "2.0.5" + run-parallel "^1.1.9" + +"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2": + version "2.0.5" + resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b" + integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== + +"@nodelib/fs.walk@^1.2.3": + version "1.2.8" + resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a" + integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== + dependencies: + "@nodelib/fs.scandir" "2.1.5" + fastq "^1.6.0" + +"@pkgjs/parseargs@^0.11.0": + version "0.11.0" + resolved "https://registry.yarnpkg.com/@pkgjs/parseargs/-/parseargs-0.11.0.tgz#a77ea742fab25775145434eb1d2328cf5013ac33" + integrity sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg== + +"@rollup/rollup-android-arm-eabi@4.17.2": + version "4.17.2" + resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.17.2.tgz#1a32112822660ee104c5dd3a7c595e26100d4c2d" + integrity sha512-NM0jFxY8bB8QLkoKxIQeObCaDlJKewVlIEkuyYKm5An1tdVZ966w2+MPQ2l8LBZLjR+SgyV+nRkTIunzOYBMLQ== + +"@rollup/rollup-android-arm64@4.17.2": + version "4.17.2" + resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.17.2.tgz#5aeef206d65ff4db423f3a93f71af91b28662c5b" + integrity sha512-yeX/Usk7daNIVwkq2uGoq2BYJKZY1JfyLTaHO/jaiSwi/lsf8fTFoQW/n6IdAsx5tx+iotu2zCJwz8MxI6D/Bw== + +"@rollup/rollup-darwin-arm64@4.17.2": + version "4.17.2" + resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.17.2.tgz#6b66aaf003c70454c292cd5f0236ebdc6ffbdf1a" + integrity sha512-kcMLpE6uCwls023+kknm71ug7MZOrtXo+y5p/tsg6jltpDtgQY1Eq5sGfHcQfb+lfuKwhBmEURDga9N0ol4YPw== + +"@rollup/rollup-darwin-x64@4.17.2": + version "4.17.2" + resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.17.2.tgz#f64fc51ed12b19f883131ccbcea59fc68cbd6c0b" + integrity sha512-AtKwD0VEx0zWkL0ZjixEkp5tbNLzX+FCqGG1SvOu993HnSz4qDI6S4kGzubrEJAljpVkhRSlg5bzpV//E6ysTQ== + +"@rollup/rollup-linux-arm-gnueabihf@4.17.2": + version "4.17.2" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.17.2.tgz#1a7641111be67c10111f7122d1e375d1226cbf14" + integrity sha512-3reX2fUHqN7sffBNqmEyMQVj/CKhIHZd4y631duy0hZqI8Qoqf6lTtmAKvJFYa6bhU95B1D0WgzHkmTg33In0A== + +"@rollup/rollup-linux-arm-musleabihf@4.17.2": + version "4.17.2" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.17.2.tgz#c93fd632923e0fee25aacd2ae414288d0b7455bb" + integrity sha512-uSqpsp91mheRgw96xtyAGP9FW5ChctTFEoXP0r5FAzj/3ZRv3Uxjtc7taRQSaQM/q85KEKjKsZuiZM3GyUivRg== + +"@rollup/rollup-linux-arm64-gnu@4.17.2": + version "4.17.2" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.17.2.tgz#fa531425dd21d058a630947527b4612d9d0b4a4a" + integrity sha512-EMMPHkiCRtE8Wdk3Qhtciq6BndLtstqZIroHiiGzB3C5LDJmIZcSzVtLRbwuXuUft1Cnv+9fxuDtDxz3k3EW2A== + +"@rollup/rollup-linux-arm64-musl@4.17.2": + version "4.17.2" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.17.2.tgz#8acc16f095ceea5854caf7b07e73f7d1802ac5af" + integrity sha512-NMPylUUZ1i0z/xJUIx6VUhISZDRT+uTWpBcjdv0/zkp7b/bQDF+NfnfdzuTiB1G6HTodgoFa93hp0O1xl+/UbA== + +"@rollup/rollup-linux-powerpc64le-gnu@4.17.2": + version "4.17.2" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.17.2.tgz#94e69a8499b5cf368911b83a44bb230782aeb571" + integrity sha512-T19My13y8uYXPw/L/k0JYaX1fJKFT/PWdXiHr8mTbXWxjVF1t+8Xl31DgBBvEKclw+1b00Chg0hxE2O7bTG7GQ== + +"@rollup/rollup-linux-riscv64-gnu@4.17.2": + version "4.17.2" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.17.2.tgz#7ef1c781c7e59e85a6ce261cc95d7f1e0b56db0f" + integrity sha512-BOaNfthf3X3fOWAB+IJ9kxTgPmMqPPH5f5k2DcCsRrBIbWnaJCgX2ll77dV1TdSy9SaXTR5iDXRL8n7AnoP5cg== + +"@rollup/rollup-linux-s390x-gnu@4.17.2": + version "4.17.2" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.17.2.tgz#f15775841c3232fca9b78cd25a7a0512c694b354" + integrity sha512-W0UP/x7bnn3xN2eYMql2T/+wpASLE5SjObXILTMPUBDB/Fg/FxC+gX4nvCfPBCbNhz51C+HcqQp2qQ4u25ok6g== + +"@rollup/rollup-linux-x64-gnu@4.17.2": + version "4.17.2" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.17.2.tgz#b521d271798d037ad70c9f85dd97d25f8a52e811" + integrity sha512-Hy7pLwByUOuyaFC6mAr7m+oMC+V7qyifzs/nW2OJfC8H4hbCzOX07Ov0VFk/zP3kBsELWNFi7rJtgbKYsav9QQ== + +"@rollup/rollup-linux-x64-musl@4.17.2": + version "4.17.2" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.17.2.tgz#9254019cc4baac35800991315d133cc9fd1bf385" + integrity sha512-h1+yTWeYbRdAyJ/jMiVw0l6fOOm/0D1vNLui9iPuqgRGnXA0u21gAqOyB5iHjlM9MMfNOm9RHCQ7zLIzT0x11Q== + +"@rollup/rollup-win32-arm64-msvc@4.17.2": + version "4.17.2" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.17.2.tgz#27f65a89f6f52ee9426ec11e3571038e4671790f" + integrity sha512-tmdtXMfKAjy5+IQsVtDiCfqbynAQE/TQRpWdVataHmhMb9DCoJxp9vLcCBjEQWMiUYxO1QprH/HbY9ragCEFLA== + +"@rollup/rollup-win32-ia32-msvc@4.17.2": + version "4.17.2" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.17.2.tgz#a2fbf8246ed0bb014f078ca34ae6b377a90cb411" + integrity sha512-7II/QCSTAHuE5vdZaQEwJq2ZACkBpQDOmQsE6D6XUbnBHW8IAhm4eTufL6msLJorzrHDFv3CF8oCA/hSIRuZeQ== + +"@rollup/rollup-win32-x64-msvc@4.17.2": + version "4.17.2" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.17.2.tgz#5a2d08b81e8064b34242d5cc9973ef8dd1e60503" + integrity sha512-TGGO7v7qOq4CYmSBVEYpI1Y5xDuCEnbVC5Vth8mOsW0gDSzxNrVERPc790IGHsrT2dQSimgMr9Ub3Y1Jci5/8w== + +"@types/estree@1.0.5": + version "1.0.5" + resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.5.tgz#a6ce3e556e00fd9895dd872dd172ad0d4bd687f4" + integrity sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw== + "@types/prop-types@*": version "15.7.12" resolved "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.12.tgz" @@ -15,16 +285,362 @@ "@types/prop-types" "*" csstype "^3.0.2" +ansi-regex@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" + integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== + +ansi-regex@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-6.0.1.tgz#3183e38fae9a65d7cb5e53945cd5897d0260a06a" + integrity sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA== + +ansi-styles@^4.0.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" + integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== + dependencies: + color-convert "^2.0.1" + +ansi-styles@^6.1.0: + version "6.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-6.2.1.tgz#0e62320cf99c21afff3b3012192546aacbfb05c5" + integrity sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug== + +any-promise@^1.0.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/any-promise/-/any-promise-1.3.0.tgz#abc6afeedcea52e809cdc0376aed3ce39635d17f" + integrity sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A== + +anymatch@~3.1.2: + version "3.1.3" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.3.tgz#790c58b19ba1720a84205b57c618d5ad8524973e" + integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw== + dependencies: + normalize-path "^3.0.0" + picomatch "^2.0.4" + +array-union@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" + integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== + +balanced-match@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" + integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== + +binary-extensions@^2.0.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.3.0.tgz#f6e14a97858d327252200242d4ccfe522c445522" + integrity sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw== + +brace-expansion@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae" + integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA== + dependencies: + balanced-match "^1.0.0" + +braces@^3.0.2, braces@~3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" + integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== + dependencies: + fill-range "^7.0.1" + +bundle-require@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/bundle-require/-/bundle-require-4.1.0.tgz#3d5fcd19d5160d4cbac5e95ed5a394d1ecd40ce6" + integrity sha512-FeArRFM+ziGkRViKRnSTbHZc35dgmR9yNog05Kn0+ItI59pOAISGvnnIwW1WgFZQW59IxD9QpJnUPkdIPfZuXg== + dependencies: + load-tsconfig "^0.2.3" + +cac@^6.7.12: + version "6.7.14" + resolved "https://registry.yarnpkg.com/cac/-/cac-6.7.14.tgz#804e1e6f506ee363cb0e3ccbb09cad5dd9870959" + integrity sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ== + +chokidar@^3.5.1: + version "3.6.0" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.6.0.tgz#197c6cc669ef2a8dc5e7b4d97ee4e092c3eb0d5b" + integrity sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw== + dependencies: + anymatch "~3.1.2" + braces "~3.0.2" + glob-parent "~5.1.2" + is-binary-path "~2.1.0" + is-glob "~4.0.1" + normalize-path "~3.0.0" + readdirp "~3.6.0" + optionalDependencies: + fsevents "~2.3.2" + +color-convert@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" + integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== + dependencies: + color-name "~1.1.4" + +color-name@~1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + +commander@^4.0.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/commander/-/commander-4.1.1.tgz#9fd602bd936294e9e9ef46a3f4d6964044b18068" + integrity sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA== + +cross-spawn@^7.0.0, cross-spawn@^7.0.3: + version "7.0.3" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" + integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== + dependencies: + path-key "^3.1.0" + shebang-command "^2.0.0" + which "^2.0.1" + csstype@^3.0.2: version "3.1.3" resolved "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz" integrity sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw== +debug@^4.3.1: + version "4.3.4" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" + integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== + dependencies: + ms "2.1.2" + +dir-glob@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" + integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA== + dependencies: + path-type "^4.0.0" + +eastasianwidth@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/eastasianwidth/-/eastasianwidth-0.2.0.tgz#696ce2ec0aa0e6ea93a397ffcf24aa7840c827cb" + integrity sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA== + +emoji-regex@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" + integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== + +emoji-regex@^9.2.2: + version "9.2.2" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-9.2.2.tgz#840c8803b0d8047f4ff0cf963176b32d4ef3ed72" + integrity sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg== + +esbuild@^0.19.2: + version "0.19.12" + resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.19.12.tgz#dc82ee5dc79e82f5a5c3b4323a2a641827db3e04" + integrity sha512-aARqgq8roFBj054KvQr5f1sFu0D65G+miZRCuJyJ0G13Zwx7vRar5Zhn2tkQNzIXcBrNVsv/8stehpj+GAjgbg== + optionalDependencies: + "@esbuild/aix-ppc64" "0.19.12" + "@esbuild/android-arm" "0.19.12" + "@esbuild/android-arm64" "0.19.12" + "@esbuild/android-x64" "0.19.12" + "@esbuild/darwin-arm64" "0.19.12" + "@esbuild/darwin-x64" "0.19.12" + "@esbuild/freebsd-arm64" "0.19.12" + "@esbuild/freebsd-x64" "0.19.12" + "@esbuild/linux-arm" "0.19.12" + "@esbuild/linux-arm64" "0.19.12" + "@esbuild/linux-ia32" "0.19.12" + "@esbuild/linux-loong64" "0.19.12" + "@esbuild/linux-mips64el" "0.19.12" + "@esbuild/linux-ppc64" "0.19.12" + "@esbuild/linux-riscv64" "0.19.12" + "@esbuild/linux-s390x" "0.19.12" + "@esbuild/linux-x64" "0.19.12" + "@esbuild/netbsd-x64" "0.19.12" + "@esbuild/openbsd-x64" "0.19.12" + "@esbuild/sunos-x64" "0.19.12" + "@esbuild/win32-arm64" "0.19.12" + "@esbuild/win32-ia32" "0.19.12" + "@esbuild/win32-x64" "0.19.12" + +execa@^5.0.0: + version "5.1.1" + resolved "https://registry.yarnpkg.com/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd" + integrity sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg== + dependencies: + cross-spawn "^7.0.3" + get-stream "^6.0.0" + human-signals "^2.1.0" + is-stream "^2.0.0" + merge-stream "^2.0.0" + npm-run-path "^4.0.1" + onetime "^5.1.2" + signal-exit "^3.0.3" + strip-final-newline "^2.0.0" + +fast-glob@^3.2.9: + version "3.3.2" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.2.tgz#a904501e57cfdd2ffcded45e99a54fef55e46129" + integrity sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow== + dependencies: + "@nodelib/fs.stat" "^2.0.2" + "@nodelib/fs.walk" "^1.2.3" + glob-parent "^5.1.2" + merge2 "^1.3.0" + micromatch "^4.0.4" + +fastq@^1.6.0: + version "1.17.1" + resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.17.1.tgz#2a523f07a4e7b1e81a42b91b8bf2254107753b47" + integrity sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w== + dependencies: + reusify "^1.0.4" + +fill-range@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" + integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== + dependencies: + to-regex-range "^5.0.1" + +foreground-child@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/foreground-child/-/foreground-child-3.1.1.tgz#1d173e776d75d2772fed08efe4a0de1ea1b12d0d" + integrity sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg== + dependencies: + cross-spawn "^7.0.0" + signal-exit "^4.0.1" + +fsevents@~2.3.2: + version "2.3.3" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" + integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== + +get-stream@^6.0.0: + version "6.0.1" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" + integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== + +glob-parent@^5.1.2, glob-parent@~5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" + integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== + dependencies: + is-glob "^4.0.1" + +glob@^10.3.10: + version "10.3.12" + resolved "https://registry.yarnpkg.com/glob/-/glob-10.3.12.tgz#3a65c363c2e9998d220338e88a5f6ac97302960b" + integrity sha512-TCNv8vJ+xz4QiqTpfOJA7HvYv+tNIRHKfUWw/q+v2jdgN4ebz+KY9tGx5J4rHP0o84mNP+ApH66HRX8us3Khqg== + dependencies: + foreground-child "^3.1.0" + jackspeak "^2.3.6" + minimatch "^9.0.1" + minipass "^7.0.4" + path-scurry "^1.10.2" + +globby@^11.0.3: + version "11.1.0" + resolved "https://registry.yarnpkg.com/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b" + integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g== + dependencies: + array-union "^2.1.0" + dir-glob "^3.0.1" + fast-glob "^3.2.9" + ignore "^5.2.0" + merge2 "^1.4.1" + slash "^3.0.0" + +human-signals@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0" + integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw== + +ignore@^5.2.0: + version "5.3.1" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.1.tgz#5073e554cd42c5b33b394375f538b8593e34d4ef" + integrity sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw== + +is-binary-path@~2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" + integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== + dependencies: + binary-extensions "^2.0.0" + +is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== + +is-fullwidth-code-point@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" + integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== + +is-glob@^4.0.1, is-glob@~4.0.1: + version "4.0.3" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" + integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== + dependencies: + is-extglob "^2.1.1" + +is-number@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" + integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== + +is-stream@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077" + integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg== + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== + +jackspeak@^2.3.6: + version "2.3.6" + resolved "https://registry.yarnpkg.com/jackspeak/-/jackspeak-2.3.6.tgz#647ecc472238aee4b06ac0e461acc21a8c505ca8" + integrity sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ== + dependencies: + "@isaacs/cliui" "^8.0.2" + optionalDependencies: + "@pkgjs/parseargs" "^0.11.0" + +joycon@^3.0.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/joycon/-/joycon-3.1.1.tgz#bce8596d6ae808f8b68168f5fc69280996894f03" + integrity sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw== + "js-tokens@^3.0.0 || ^4.0.0": version "4.0.0" resolved "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz" integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== +lilconfig@^3.0.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-3.1.1.tgz#9d8a246fa753106cfc205fd2d77042faca56e5e3" + integrity sha512-O18pf7nyvHTckunPWCV1XUNXU1piu01y2b7ATJ0ppkUkk8ocqVWBrYjJBCwHDjD/ZWcfyrA0P4gKhzWGi5EINQ== + +lines-and-columns@^1.1.6: + version "1.2.4" + resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" + integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== + +load-tsconfig@^0.2.3: + version "0.2.5" + resolved "https://registry.yarnpkg.com/load-tsconfig/-/load-tsconfig-0.2.5.tgz#453b8cd8961bfb912dea77eb6c168fe8cca3d3a1" + integrity sha512-IXO6OCs9yg8tMKzfPZ1YmheJbZCiEsnBdcB03l0OcfK9prKnJb96siuHCr5Fl37/yo9DnKU+TLpxzTUspw9shg== + +lodash.sortby@^4.7.0: + version "4.7.0" + resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438" + integrity sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA== + loose-envify@^1.1.0: version "1.4.0" resolved "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz" @@ -32,9 +648,373 @@ loose-envify@^1.1.0: dependencies: js-tokens "^3.0.0 || ^4.0.0" +lru-cache@^10.2.0: + version "10.2.2" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.2.2.tgz#48206bc114c1252940c41b25b41af5b545aca878" + integrity sha512-9hp3Vp2/hFQUiIwKo8XCeFVnrg8Pk3TYNPIR7tJADKi5YfcF7vEaK7avFHTlSy3kOKYaJQaalfEo6YuXdceBOQ== + +merge-stream@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" + integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== + +merge2@^1.3.0, merge2@^1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" + integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== + +micromatch@^4.0.4: + version "4.0.5" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6" + integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA== + dependencies: + braces "^3.0.2" + picomatch "^2.3.1" + +mimic-fn@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" + integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== + +minimatch@^9.0.1: + version "9.0.4" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.4.tgz#8e49c731d1749cbec05050ee5145147b32496a51" + integrity sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw== + dependencies: + brace-expansion "^2.0.1" + +"minipass@^5.0.0 || ^6.0.2 || ^7.0.0", minipass@^7.0.4: + version "7.1.0" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-7.1.0.tgz#b545f84af94e567386770159302ca113469c80b8" + integrity sha512-oGZRv2OT1lO2UF1zUcwdTb3wqUwI0kBGTgt/T7OdSj6M6N5m3o5uPf0AIW6lVxGGoiWUR7e2AwTE+xiwK8WQig== + +ms@2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" + integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== + +mz@^2.7.0: + version "2.7.0" + resolved "https://registry.yarnpkg.com/mz/-/mz-2.7.0.tgz#95008057a56cafadc2bc63dde7f9ff6955948e32" + integrity sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q== + dependencies: + any-promise "^1.0.0" + object-assign "^4.0.1" + thenify-all "^1.0.0" + +normalize-path@^3.0.0, normalize-path@~3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" + integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== + +npm-run-path@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea" + integrity sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw== + dependencies: + path-key "^3.0.0" + +object-assign@^4.0.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== + +onetime@^5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" + integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== + dependencies: + mimic-fn "^2.1.0" + +path-key@^3.0.0, path-key@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" + integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== + +path-scurry@^1.10.2: + version "1.10.2" + resolved "https://registry.yarnpkg.com/path-scurry/-/path-scurry-1.10.2.tgz#8f6357eb1239d5fa1da8b9f70e9c080675458ba7" + integrity sha512-7xTavNy5RQXnsjANvVvMkEjvloOinkAjv/Z6Ildz9v2RinZ4SBKTWFOVRbaF8p0vpHnyjV/UwNDdKuUv6M5qcA== + dependencies: + lru-cache "^10.2.0" + minipass "^5.0.0 || ^6.0.2 || ^7.0.0" + +path-type@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" + integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== + +picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" + integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== + +pirates@^4.0.1: + version "4.0.6" + resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.6.tgz#3018ae32ecfcff6c29ba2267cbf21166ac1f36b9" + integrity sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg== + +postcss-load-config@^4.0.1: + version "4.0.2" + resolved "https://registry.yarnpkg.com/postcss-load-config/-/postcss-load-config-4.0.2.tgz#7159dcf626118d33e299f485d6afe4aff7c4a3e3" + integrity sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ== + dependencies: + lilconfig "^3.0.0" + yaml "^2.3.4" + +punycode@^2.1.0: + version "2.3.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.1.tgz#027422e2faec0b25e1549c3e1bd8309b9133b6e5" + integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg== + +queue-microtask@^1.2.2: + version "1.2.3" + resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" + integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== + react@^18.3.1: version "18.3.1" resolved "https://registry.npmjs.org/react/-/react-18.3.1.tgz" integrity sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ== dependencies: loose-envify "^1.1.0" + +readdirp@~3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" + integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA== + dependencies: + picomatch "^2.2.1" + +resolve-from@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69" + integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw== + +reusify@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" + integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== + +rollup@^4.0.2: + version "4.17.2" + resolved "https://registry.yarnpkg.com/rollup/-/rollup-4.17.2.tgz#26d1785d0144122277fdb20ab3a24729ae68301f" + integrity sha512-/9ClTJPByC0U4zNLowV1tMBe8yMEAxewtR3cUNX5BoEpGH3dQEWpJLr6CLp0fPdYRF/fzVOgvDb1zXuakwF5kQ== + dependencies: + "@types/estree" "1.0.5" + optionalDependencies: + "@rollup/rollup-android-arm-eabi" "4.17.2" + "@rollup/rollup-android-arm64" "4.17.2" + "@rollup/rollup-darwin-arm64" "4.17.2" + "@rollup/rollup-darwin-x64" "4.17.2" + "@rollup/rollup-linux-arm-gnueabihf" "4.17.2" + "@rollup/rollup-linux-arm-musleabihf" "4.17.2" + "@rollup/rollup-linux-arm64-gnu" "4.17.2" + "@rollup/rollup-linux-arm64-musl" "4.17.2" + "@rollup/rollup-linux-powerpc64le-gnu" "4.17.2" + "@rollup/rollup-linux-riscv64-gnu" "4.17.2" + "@rollup/rollup-linux-s390x-gnu" "4.17.2" + "@rollup/rollup-linux-x64-gnu" "4.17.2" + "@rollup/rollup-linux-x64-musl" "4.17.2" + "@rollup/rollup-win32-arm64-msvc" "4.17.2" + "@rollup/rollup-win32-ia32-msvc" "4.17.2" + "@rollup/rollup-win32-x64-msvc" "4.17.2" + fsevents "~2.3.2" + +run-parallel@^1.1.9: + version "1.2.0" + resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" + integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA== + dependencies: + queue-microtask "^1.2.2" + +shebang-command@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" + integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== + dependencies: + shebang-regex "^3.0.0" + +shebang-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" + integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== + +signal-exit@^3.0.3: + version "3.0.7" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" + integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== + +signal-exit@^4.0.1: + version "4.1.0" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-4.1.0.tgz#952188c1cbd546070e2dd20d0f41c0ae0530cb04" + integrity sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw== + +slash@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" + integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== + +source-map@0.8.0-beta.0: + version "0.8.0-beta.0" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.8.0-beta.0.tgz#d4c1bb42c3f7ee925f005927ba10709e0d1d1f11" + integrity sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA== + dependencies: + whatwg-url "^7.0.0" + +"string-width-cjs@npm:string-width@^4.2.0", string-width@^4.1.0: + version "4.2.3" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + +string-width@^5.0.1, string-width@^5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-5.1.2.tgz#14f8daec6d81e7221d2a357e668cab73bdbca794" + integrity sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA== + dependencies: + eastasianwidth "^0.2.0" + emoji-regex "^9.2.2" + strip-ansi "^7.0.1" + +"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + +strip-ansi@^7.0.1: + version "7.1.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.1.0.tgz#d5b6568ca689d8561370b0707685d22434faff45" + integrity sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ== + dependencies: + ansi-regex "^6.0.1" + +strip-final-newline@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad" + integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA== + +sucrase@^3.20.3: + version "3.35.0" + resolved "https://registry.yarnpkg.com/sucrase/-/sucrase-3.35.0.tgz#57f17a3d7e19b36d8995f06679d121be914ae263" + integrity sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA== + dependencies: + "@jridgewell/gen-mapping" "^0.3.2" + commander "^4.0.0" + glob "^10.3.10" + lines-and-columns "^1.1.6" + mz "^2.7.0" + pirates "^4.0.1" + ts-interface-checker "^0.1.9" + +thenify-all@^1.0.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/thenify-all/-/thenify-all-1.6.0.tgz#1a1918d402d8fc3f98fbf234db0bcc8cc10e9726" + integrity sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA== + dependencies: + thenify ">= 3.1.0 < 4" + +"thenify@>= 3.1.0 < 4": + version "3.3.1" + resolved "https://registry.yarnpkg.com/thenify/-/thenify-3.3.1.tgz#8932e686a4066038a016dd9e2ca46add9838a95f" + integrity sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw== + dependencies: + any-promise "^1.0.0" + +to-regex-range@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" + integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== + dependencies: + is-number "^7.0.0" + +tr46@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/tr46/-/tr46-1.0.1.tgz#a8b13fd6bfd2489519674ccde55ba3693b706d09" + integrity sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA== + dependencies: + punycode "^2.1.0" + +tree-kill@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/tree-kill/-/tree-kill-1.2.2.tgz#4ca09a9092c88b73a7cdc5e8a01b507b0790a0cc" + integrity sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A== + +ts-interface-checker@^0.1.9: + version "0.1.13" + resolved "https://registry.yarnpkg.com/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz#784fd3d679722bc103b1b4b8030bcddb5db2a699" + integrity sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA== + +tsup@^8.0.2: + version "8.0.2" + resolved "https://registry.yarnpkg.com/tsup/-/tsup-8.0.2.tgz#c63192a08386515103e2c44ac5a23bdff75c5fa1" + integrity sha512-NY8xtQXdH7hDUAZwcQdY/Vzlw9johQsaqf7iwZ6g1DOUlFYQ5/AtVAjTvihhEyeRlGo4dLRVHtrRaL35M1daqQ== + dependencies: + bundle-require "^4.0.0" + cac "^6.7.12" + chokidar "^3.5.1" + debug "^4.3.1" + esbuild "^0.19.2" + execa "^5.0.0" + globby "^11.0.3" + joycon "^3.0.1" + postcss-load-config "^4.0.1" + resolve-from "^5.0.0" + rollup "^4.0.2" + source-map "0.8.0-beta.0" + sucrase "^3.20.3" + tree-kill "^1.2.2" + +typescript@^5.4.5: + version "5.4.5" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.4.5.tgz#42ccef2c571fdbd0f6718b1d1f5e6e5ef006f611" + integrity sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ== + +webidl-conversions@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-4.0.2.tgz#a855980b1f0b6b359ba1d5d9fb39ae941faa63ad" + integrity sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg== + +whatwg-url@^7.0.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-7.1.0.tgz#c2c492f1eca612988efd3d2266be1b9fc6170d06" + integrity sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg== + dependencies: + lodash.sortby "^4.7.0" + tr46 "^1.0.1" + webidl-conversions "^4.0.2" + +which@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" + integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== + dependencies: + isexe "^2.0.0" + +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": + version "7.0.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + +wrap-ansi@^8.1.0: + version "8.1.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214" + integrity sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ== + dependencies: + ansi-styles "^6.1.0" + string-width "^5.0.1" + strip-ansi "^7.0.1" + +yaml@^2.3.4: + version "2.4.2" + resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.4.2.tgz#7a2b30f2243a5fc299e1f14ca58d475ed4bc5362" + integrity sha512-B3VqDZ+JAg1nZpaEmWtTXUlBneoGx6CPM9b0TENK6aoSu5t73dItudwdgmi6tHlIZZId4dZ9skcAQ2UbcyAeVA== From 3ef72f25fc642334101262f28e79d3ac6531874d Mon Sep 17 00:00:00 2001 From: Jan Jaroszczak Date: Wed, 8 May 2024 15:47:27 +0200 Subject: [PATCH 069/125] [#937] Missing Test IDs --- .../src/components/molecules/AutomatedVotingCard.tsx | 1 + .../src/components/molecules/VoteActionForm.tsx | 1 + .../components/organisms/AutomatedVotingOptions.tsx | 5 ++++- govtool/frontend/src/components/organisms/BgCard.tsx | 3 ++- .../organisms/DashboardCards/DRepDashboardCard.tsx | 2 +- .../DashboardCards/DelegateDashboardCard.tsx | 2 +- .../frontend/src/components/organisms/HomeCards.tsx | 2 +- .../RegisterAsDRepSteps/DRepStorageInformation.tsx | 1 + .../RegisterAsDRepSteps/RegisterAsDRepForm.tsx | 11 ++++++++++- .../RegisterAsDRepSteps/WhatRetirementMeans.tsx | 1 + govtool/frontend/src/components/organisms/TopNav.tsx | 1 + .../organisms/VoteContext/VoteContextText.tsx | 1 + govtool/frontend/src/components/organisms/types.ts | 1 + 13 files changed, 26 insertions(+), 6 deletions(-) diff --git a/govtool/frontend/src/components/molecules/AutomatedVotingCard.tsx b/govtool/frontend/src/components/molecules/AutomatedVotingCard.tsx index ec1d75171..cc56895d3 100644 --- a/govtool/frontend/src/components/molecules/AutomatedVotingCard.tsx +++ b/govtool/frontend/src/components/molecules/AutomatedVotingCard.tsx @@ -50,6 +50,7 @@ export const AutomatedVotingCard = ({ mt: inProgress || isSelected ? 2 : 0, py: 2.25, }} + data-testid={`${testIdLabel}-card`} > {voteContextText ? t("govActions.provideNewContextAboutYourVote") diff --git a/govtool/frontend/src/components/organisms/AutomatedVotingOptions.tsx b/govtool/frontend/src/components/organisms/AutomatedVotingOptions.tsx index 52772f98d..92fac90e4 100644 --- a/govtool/frontend/src/components/organisms/AutomatedVotingOptions.tsx +++ b/govtool/frontend/src/components/organisms/AutomatedVotingOptions.tsx @@ -74,7 +74,10 @@ export const AutomatedVotingOptions = ({ /> )} - + ( ) : null} diff --git a/govtool/frontend/src/components/organisms/RegisterAsDRepSteps/WhatRetirementMeans.tsx b/govtool/frontend/src/components/organisms/RegisterAsDRepSteps/WhatRetirementMeans.tsx index 5b7db0914..36e6459ac 100644 --- a/govtool/frontend/src/components/organisms/RegisterAsDRepSteps/WhatRetirementMeans.tsx +++ b/govtool/frontend/src/components/organisms/RegisterAsDRepSteps/WhatRetirementMeans.tsx @@ -85,6 +85,7 @@ export const WhatRetirementMeans = ({ return ( { alt="drawer-icon" src={ICONS.drawerIcon} onClick={openDrawer} + data-testid="open-drawer-button" /> )} diff --git a/govtool/frontend/src/components/organisms/VoteContext/VoteContextText.tsx b/govtool/frontend/src/components/organisms/VoteContext/VoteContextText.tsx index f241de814..3ac7117e2 100644 --- a/govtool/frontend/src/components/organisms/VoteContext/VoteContextText.tsx +++ b/govtool/frontend/src/components/organisms/VoteContext/VoteContextText.tsx @@ -71,6 +71,7 @@ export const VoteContextText = ({ {...{ control, errors }} {...fieldProps} isModifiedLayout + data-testid="provide-context-input" /> ); diff --git a/govtool/frontend/src/components/organisms/types.ts b/govtool/frontend/src/components/organisms/types.ts index 4207dd2db..1cd327aed 100644 --- a/govtool/frontend/src/components/organisms/types.ts +++ b/govtool/frontend/src/components/organisms/types.ts @@ -3,6 +3,7 @@ import { Dispatch, SetStateAction } from "react"; export type BgCardProps = { actionButtonLabel: string; + actionButtonDataTestId?: string; backButtonLabel?: string; children: React.ReactNode; isLoadingActionButton?: boolean; From b1ce62ff7188a8296734dc61d1571753861be32f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Sworze=C5=84?= Date: Wed, 8 May 2024 16:17:13 +0200 Subject: [PATCH 070/125] change way to valid metadata --- govtool/frontend/src/models/metadataValidation.ts | 5 ----- govtool/frontend/src/services/API.ts | 12 ++---------- .../requests/metadataValidation/postValidate.ts | 6 +++--- .../src/utils/tests/validateMetadataHash.test.ts | 6 +----- govtool/frontend/src/utils/validateMetadataHash.ts | 3 +-- 5 files changed, 7 insertions(+), 25 deletions(-) diff --git a/govtool/frontend/src/models/metadataValidation.ts b/govtool/frontend/src/models/metadataValidation.ts index bb4a4edcc..5b471ed27 100644 --- a/govtool/frontend/src/models/metadataValidation.ts +++ b/govtool/frontend/src/models/metadataValidation.ts @@ -13,12 +13,7 @@ export type ValidateMetadataResult = { metadata?: any; }; -export enum MetadataStandard { - CIP108 = "CIP108", -} - export type MetadataValidationDTO = { url: string; hash: string; - standard?: MetadataStandard; }; diff --git a/govtool/frontend/src/services/API.ts b/govtool/frontend/src/services/API.ts index 54c09aa7f..3e3d8e1d7 100644 --- a/govtool/frontend/src/services/API.ts +++ b/govtool/frontend/src/services/API.ts @@ -3,19 +3,11 @@ import { NavigateFunction } from "react-router-dom"; import { PATHS } from "@consts"; -const TIMEOUT_IN_SECONDS = 30 * 1000; // 1000 ms is 1 s then its 10 s +const TIMEOUT_IN_SECONDS = 30 * 1000; // 1000 ms is 1 s then its 30 s const BASE_URL = import.meta.env.VITE_BASE_URL; -// Validation should be performed directly on the server -// than no metadata service is needed and `/api` might be removed export const API = axios.create({ - baseURL: `${BASE_URL}/api`, - timeout: TIMEOUT_IN_SECONDS, -}); - -// TODO: Remove this service and use the API service -export const METADATA_VALIDATION_API = axios.create({ - baseURL: `${BASE_URL}/metadata-validation`, + baseURL: `${BASE_URL}`, timeout: TIMEOUT_IN_SECONDS, }); diff --git a/govtool/frontend/src/services/requests/metadataValidation/postValidate.ts b/govtool/frontend/src/services/requests/metadataValidation/postValidate.ts index 4dd95281b..5ff52b8c0 100644 --- a/govtool/frontend/src/services/requests/metadataValidation/postValidate.ts +++ b/govtool/frontend/src/services/requests/metadataValidation/postValidate.ts @@ -1,9 +1,9 @@ import type { MetadataValidationDTO, ValidateMetadataResult } from "@models"; -import { METADATA_VALIDATION_API } from "../../API"; +import { API } from "@services"; export const postValidate = async (body: MetadataValidationDTO) => { - const response = await METADATA_VALIDATION_API.post( - `/validate`, + const response = await API.post( + `/metadata/validate`, body, ); diff --git a/govtool/frontend/src/utils/tests/validateMetadataHash.test.ts b/govtool/frontend/src/utils/tests/validateMetadataHash.test.ts index ea9b1e78e..c1b29a37f 100644 --- a/govtool/frontend/src/utils/tests/validateMetadataHash.test.ts +++ b/govtool/frontend/src/utils/tests/validateMetadataHash.test.ts @@ -1,7 +1,7 @@ import { vi } from "vitest"; import { postValidate } from "@services"; import { checkIsMissingGAMetadata } from ".."; -import { MetadataStandard, MetadataValidationStatus } from "@/models"; +import { MetadataValidationStatus } from "@/models"; const url = "https://example.com"; const hash = "abcdefg"; @@ -28,7 +28,6 @@ describe("checkIsMissingGAMetadata", () => { expect(mockPostValidate).toHaveBeenCalledWith({ url, hash, - standard: MetadataStandard.CIP108, }); }); @@ -44,7 +43,6 @@ describe("checkIsMissingGAMetadata", () => { expect(mockPostValidate).toHaveBeenCalledWith({ url, hash, - standard: MetadataStandard.CIP108, }); }); @@ -60,7 +58,6 @@ describe("checkIsMissingGAMetadata", () => { expect(mockPostValidate).toHaveBeenCalledWith({ url, hash, - standard: MetadataStandard.CIP108, }); }); @@ -73,7 +70,6 @@ describe("checkIsMissingGAMetadata", () => { expect(mockPostValidate).toHaveBeenCalledWith({ url, hash, - standard: MetadataStandard.CIP108, }); }); }); diff --git a/govtool/frontend/src/utils/validateMetadataHash.ts b/govtool/frontend/src/utils/validateMetadataHash.ts index 6868cc3d6..76ac3ecfa 100644 --- a/govtool/frontend/src/utils/validateMetadataHash.ts +++ b/govtool/frontend/src/utils/validateMetadataHash.ts @@ -1,6 +1,6 @@ import { postValidate } from "@services"; -import { MetadataStandard, MetadataValidationStatus } from "@/models"; +import { MetadataValidationStatus } from "@/models"; type CheckIsMissingGAMetadataResponse = { status?: MetadataValidationStatus; @@ -20,7 +20,6 @@ export const checkIsMissingGAMetadata = async ({ const { status, metadata, valid } = await postValidate({ url, hash, - standard: MetadataStandard.CIP108, }); if (status) { return { status, valid }; From 6da4106d4cdea8a6d3073021c4b7968f48f2b368 Mon Sep 17 00:00:00 2001 From: Jan Jaroszczak Date: Wed, 8 May 2024 23:22:52 +0200 Subject: [PATCH 071/125] [#907] Move DRep yourself card to top in DRep Directory --- .../frontend/src/pages/DRepDirectoryContent.tsx | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/govtool/frontend/src/pages/DRepDirectoryContent.tsx b/govtool/frontend/src/pages/DRepDirectoryContent.tsx index efd8a61ad..49a47be2f 100644 --- a/govtool/frontend/src/pages/DRepDirectoryContent.tsx +++ b/govtool/frontend/src/pages/DRepDirectoryContent.tsx @@ -58,6 +58,11 @@ export const DRepDirectoryContent: FC = ({ ); const myDrep = myDRepList?.[0]; + const { dRepData: yourselfDRepList } = useGetDRepListInfiniteQuery({ + searchPhrase: myDRepId, + }); + const yourselfDRep = yourselfDRepList?.[0]; + const { dRepData: dRepList, isPreviousData, @@ -84,6 +89,13 @@ export const DRepDirectoryContent: FC = ({ const ada = correctAdaFormat(votingPower); + const dRepsWithoutYourself = dRepList?.filter( + (dRep) => !isSameDRep(dRep, myDRepId), + ); + const dRepListToDisplay = yourselfDRep + ? [yourselfDRep, ...dRepsWithoutYourself] + : dRepList; + return ( {/* My delegation */} @@ -96,6 +108,7 @@ export const DRepDirectoryContent: FC = ({ dRep={myDrep} isConnected={!!isConnected} isInProgress={isSameDRep(myDrep, inProgressDelegation)} + isMe={isSameDRep(myDrep, myDRepId)} /> )} @@ -175,7 +188,7 @@ export const DRepDirectoryContent: FC = ({
)} - {dRepList?.map((dRep) => { + {dRepListToDisplay?.map((dRep) => { if (isSameDRep(dRep, myDrep?.view)) { return null; } From d7b73cf663d10558d6b61e0bc4911c123e48c345 Mon Sep 17 00:00:00 2001 From: Jan Jaroszczak Date: Tue, 7 May 2024 23:38:38 +0200 Subject: [PATCH 072/125] [#904] No option to delegate to myself as a drep --- govtool/frontend/src/components/organisms/DRepCard.tsx | 5 +++-- govtool/frontend/src/i18n/locales/en.ts | 3 +++ govtool/frontend/src/models/api.ts | 2 +- govtool/frontend/src/pages/DRepDirectoryContent.tsx | 1 + 4 files changed, 8 insertions(+), 3 deletions(-) diff --git a/govtool/frontend/src/components/organisms/DRepCard.tsx b/govtool/frontend/src/components/organisms/DRepCard.tsx index 95ab2581f..d5e9af22a 100644 --- a/govtool/frontend/src/components/organisms/DRepCard.tsx +++ b/govtool/frontend/src/components/organisms/DRepCard.tsx @@ -83,7 +83,9 @@ export const DRepCard = ({ }} > - {type} + + {type === "SoleVoter" ? t("dRepDirectory.directVoter") : type} + { @@ -177,7 +179,6 @@ export const DRepCard = ({ {status === "Active" && isConnected && onDelegate && - !isMe && !isInProgress && ( )} diff --git a/govtool/frontend/src/components/molecules/types.ts b/govtool/frontend/src/components/molecules/types.ts index 01997032e..b3b5343b2 100644 --- a/govtool/frontend/src/components/molecules/types.ts +++ b/govtool/frontend/src/components/molecules/types.ts @@ -37,5 +37,5 @@ export type AutomatedVotingCardProps = { title: string; votingPower: string | number; isDelegateLoading?: boolean; - transactionId?: string; + transactionId?: string | null; }; diff --git a/govtool/frontend/src/components/organisms/AutomatedVotingOptions.tsx b/govtool/frontend/src/components/organisms/AutomatedVotingOptions.tsx index 92fac90e4..ac1a05cdf 100644 --- a/govtool/frontend/src/components/organisms/AutomatedVotingOptions.tsx +++ b/govtool/frontend/src/components/organisms/AutomatedVotingOptions.tsx @@ -1,10 +1,9 @@ -import { useState } from "react"; +import { useEffect, useState } from "react"; import { Accordion, AccordionDetails, AccordionSummary, Box, - Chip, } from "@mui/material"; import { Typography } from "@atoms"; @@ -22,6 +21,7 @@ type AutomatedVotingOptionsProps = { isConnected?: boolean; isDelegationLoading?: boolean; pendingTransaction?: PendingTransaction; + txHash?: string | null; }; export const AutomatedVotingOptions = ({ @@ -32,6 +32,7 @@ export const AutomatedVotingOptions = ({ isDelegationLoading, pendingTransaction, votingPower, + txHash, }: AutomatedVotingOptionsProps) => { const { t } = useTranslation(); @@ -40,6 +41,25 @@ export const AutomatedVotingOptions = ({ // TODO: Change to certain automated voted option if available const onClickInfo = () => openInNewTab("https://docs.sanchogov.tools/"); + const isDelegatedToAbstain = currentDelegation === "drep_always_abstain"; + const isDelegationToAbstainInProgress = delegationInProgress === "abstain"; + const isDelegatedToNoConfidence = + currentDelegation === "drep_always_no_confidence"; + const isDelegationToNoConfidenceInProgress = + delegationInProgress === "no confidence"; + + useEffect(() => { + const shouldBeSetOpen = + isDelegatedToAbstain || + isDelegatedToNoConfidence || + isDelegationToAbstainInProgress || + isDelegationToNoConfidenceInProgress; + + if (shouldBeSetOpen) { + setIsOpen(true); + } + }, [currentDelegation, delegationInProgress]); + return ( {t("dRepDirectory.automatedVotingOptions")} - {currentDelegation && !isOpen && ( - // TODO this Chip is temporary, since there were no design for this case - theme.palette.neutralWhite, - fontWeight: 400, - ml: 2, - textTransform: "uppercase", - }} - /> - )} delegate("abstain")} onClickInfo={onClickInfo} - title={t("dRepDirectory.abstainCardTitle")} + title={ + isDelegatedToAbstain + ? t("dRepDirectory.delegatedToAbstainTitle", { + ada: votingPower, + }) + : t("dRepDirectory.abstainCardDefaultTitle") + } votingPower={votingPower} transactionId={ pendingTransaction?.delegate?.resourceId === "abstain" ? pendingTransaction?.delegate?.transactionHash + : isDelegatedToAbstain + ? txHash : undefined } /> delegate("no confidence")} onClickInfo={onClickInfo} - title={t("dRepDirectory.noConfidenceTitle")} + title={ + isDelegatedToNoConfidence + ? t("dRepDirectory.delegatedToNoConfidenceTitle", { + ada: votingPower, + }) + : t("dRepDirectory.noConfidenceDefaultTitle") + } votingPower={votingPower} transactionId={ pendingTransaction?.delegate?.resourceId === "no confidence" ? pendingTransaction?.delegate?.transactionHash + : isDelegatedToNoConfidence + ? txHash : undefined } /> diff --git a/govtool/frontend/src/i18n/locales/en.ts b/govtool/frontend/src/i18n/locales/en.ts index e19d2fbe9..f54da84d1 100644 --- a/govtool/frontend/src/i18n/locales/en.ts +++ b/govtool/frontend/src/i18n/locales/en.ts @@ -245,10 +245,18 @@ export const en = { }, }, dRepDirectory: { - abstainCardDescription: "Select this to vote ABSTAIN to every vote.", - abstainCardTitle: "Abstain from Every Vote", + abstainCardDefaultDescription: + "Select this to vote ABSTAIN to every vote.", + abstainCardDefaultTitle: "Abstain from Every Vote", automatedVotingOptions: "Automated Voting Options", editBtn: "Edit DRep data", + delegatedToAbstainTitle: "You have delegated ₳{{ada}} to “Abstain”", + delegatedToNoConfidenceTitle: + "You have delegated ₳{{ada}} to “No Confidence”", + delegatedToAbstainDescription: + "You have selected to apply your Voting Power to Abstain on every vote.", + delegatedToNoConfidenceDescription: + "You have selected to apply your Voting Power to No Confidence on every vote.", delegationOptions: "Delegation Options", directVoter: "Direct Voter", filterTitle: "DRep Status", @@ -259,9 +267,9 @@ export const en = { "You have delegated ₳ {{ada}} to yourself:", myDRep: "This is your DRep", listTitle: "Find a DRep", - noConfidenceDescription: + noConfidenceDefaultDescription: "Select this to signal no confidence in the current constitutional committee by voting NO on every proposal and voting YES to no confidence proposals", - noConfidenceTitle: "Signal No Confidence on Every Vote", + noConfidenceDefaultTitle: "Signal No Confidence on Every Vote", noResultsForTheSearchTitle: "No DReps found", noResultsForTheSearchDescription: "Please try a different search", title: "DRep Directory", diff --git a/govtool/frontend/src/pages/DRepDirectoryContent.tsx b/govtool/frontend/src/pages/DRepDirectoryContent.tsx index 49a47be2f..b8837547e 100644 --- a/govtool/frontend/src/pages/DRepDirectoryContent.tsx +++ b/govtool/frontend/src/pages/DRepDirectoryContent.tsx @@ -95,6 +95,11 @@ export const DRepDirectoryContent: FC = ({ const dRepListToDisplay = yourselfDRep ? [yourselfDRep, ...dRepsWithoutYourself] : dRepList; + const isAnAutomatedOptionChosen = + currentDelegation?.dRepView && + ["drep_always_abstain", "drep_always_no_confidence"].includes( + currentDelegation?.dRepView, + ); return ( @@ -121,11 +126,7 @@ export const DRepDirectoryContent: FC = ({ = ({ isDelegationLoading={isDelegating} votingPower={ada.toString()} pendingTransaction={pendingTransaction} + txHash={ + !pendingTransaction.delegate && isAnAutomatedOptionChosen + ? currentDelegation?.txHash + : undefined + } /> )} From 902d64242534d58fbea7665c74411321198d0371 Mon Sep 17 00:00:00 2001 From: Sudip Bhattarai Date: Thu, 9 May 2024 16:19:29 +0545 Subject: [PATCH 081/125] BugFix: Rename metadata api service name to metadata-api --- tests/test-infrastructure/docker-compose-test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test-infrastructure/docker-compose-test.yml b/tests/test-infrastructure/docker-compose-test.yml index 21b634b18..6b03e358d 100644 --- a/tests/test-infrastructure/docker-compose-test.yml +++ b/tests/test-infrastructure/docker-compose-test.yml @@ -38,7 +38,7 @@ services: reservations: memory: 300M - metadata: + metadata-api: image: govtool/metadata-api:${GOVTOOL_TAG} build: context: ../test-metadata-api From 386b3fa505cdf702dd57bff5dceb4e4bbe835158 Mon Sep 17 00:00:00 2001 From: Jan Jaroszczak Date: Thu, 9 May 2024 10:04:19 +0200 Subject: [PATCH 082/125] [#918] Fixes after CR --- .../organisms/AutomatedVotingOptions.tsx | 30 ++++++++++++++----- .../DashboardCards/DelegateDashboardCard.tsx | 28 ++++++++++------- .../src/context/pendingTransaction/utils.tsx | 15 ++++++++-- govtool/frontend/src/context/wallet.tsx | 5 ++-- .../src/pages/DRepDirectoryContent.tsx | 23 +++++++++----- .../src/types/automatedVotingOptions.ts | 9 ++++++ 6 files changed, 80 insertions(+), 30 deletions(-) create mode 100644 govtool/frontend/src/types/automatedVotingOptions.ts diff --git a/govtool/frontend/src/components/organisms/AutomatedVotingOptions.tsx b/govtool/frontend/src/components/organisms/AutomatedVotingOptions.tsx index ac1a05cdf..5844caf52 100644 --- a/govtool/frontend/src/components/organisms/AutomatedVotingOptions.tsx +++ b/govtool/frontend/src/components/organisms/AutomatedVotingOptions.tsx @@ -12,6 +12,10 @@ import { PendingTransaction } from "@context"; import { useTranslation } from "@hooks"; import { AutomatedVotingCard } from "@molecules"; import { openInNewTab } from "@/utils"; +import { + AutomatedVotingOptionCurrentDelegation, + AutomatedVotingOptionDelegationId, +} from "@/types/automatedVotingOptions"; type AutomatedVotingOptionsProps = { currentDelegation?: string | null; @@ -41,12 +45,16 @@ export const AutomatedVotingOptions = ({ // TODO: Change to certain automated voted option if available const onClickInfo = () => openInNewTab("https://docs.sanchogov.tools/"); - const isDelegatedToAbstain = currentDelegation === "drep_always_abstain"; - const isDelegationToAbstainInProgress = delegationInProgress === "abstain"; + const isDelegatedToAbstain = + currentDelegation === + AutomatedVotingOptionCurrentDelegation.drep_always_abstain; + const isDelegationToAbstainInProgress = + delegationInProgress === AutomatedVotingOptionDelegationId.abstain; const isDelegatedToNoConfidence = - currentDelegation === "drep_always_no_confidence"; + currentDelegation === + AutomatedVotingOptionCurrentDelegation.drep_always_no_confidence; const isDelegationToNoConfidenceInProgress = - delegationInProgress === "no confidence"; + delegationInProgress === AutomatedVotingOptionDelegationId.no_confidence; useEffect(() => { const shouldBeSetOpen = @@ -98,7 +106,9 @@ export const AutomatedVotingOptions = ({ isConnected={isConnected} isDelegateLoading={isDelegationLoading} isSelected={isDelegatedToAbstain} - onClickDelegate={() => delegate("abstain")} + onClickDelegate={() => + delegate(AutomatedVotingOptionDelegationId.abstain) + } onClickInfo={onClickInfo} title={ isDelegatedToAbstain @@ -109,7 +119,8 @@ export const AutomatedVotingOptions = ({ } votingPower={votingPower} transactionId={ - pendingTransaction?.delegate?.resourceId === "abstain" + pendingTransaction?.delegate?.resourceId === + AutomatedVotingOptionDelegationId.abstain ? pendingTransaction?.delegate?.transactionHash : isDelegatedToAbstain ? txHash @@ -126,7 +137,9 @@ export const AutomatedVotingOptions = ({ isConnected={isConnected} isDelegateLoading={isDelegationLoading} isSelected={isDelegatedToNoConfidence} - onClickDelegate={() => delegate("no confidence")} + onClickDelegate={() => + delegate(AutomatedVotingOptionDelegationId.no_confidence) + } onClickInfo={onClickInfo} title={ isDelegatedToNoConfidence @@ -137,7 +150,8 @@ export const AutomatedVotingOptions = ({ } votingPower={votingPower} transactionId={ - pendingTransaction?.delegate?.resourceId === "no confidence" + pendingTransaction?.delegate?.resourceId === + AutomatedVotingOptionDelegationId.no_confidence ? pendingTransaction?.delegate?.transactionHash : isDelegatedToNoConfidence ? txHash diff --git a/govtool/frontend/src/components/organisms/DashboardCards/DelegateDashboardCard.tsx b/govtool/frontend/src/components/organisms/DashboardCards/DelegateDashboardCard.tsx index 9d9b03aba..ea2bde854 100644 --- a/govtool/frontend/src/components/organisms/DashboardCards/DelegateDashboardCard.tsx +++ b/govtool/frontend/src/components/organisms/DashboardCards/DelegateDashboardCard.tsx @@ -12,6 +12,10 @@ import { DelegationAction, } from "@molecules"; import { correctAdaFormat, formHexToBech32, openInNewTab } from "@utils"; +import { + AutomatedVotingOptionCurrentDelegation, + AutomatedVotingOptionDelegationId, +} from "@/types/automatedVotingOptions"; type DelegateDashboardCardProps = { currentDelegation: CurrentDelegation; @@ -129,9 +133,11 @@ export const DelegateDashboardCard = ({ const getDelegationTitle = (currentDelegation: string | null, ada: number) => { const key = - currentDelegation === "drep_always_no_confidence" + currentDelegation === + AutomatedVotingOptionCurrentDelegation.drep_always_no_confidence ? "dashboard.cards.delegation.noConfidenceDelegationTitle" - : currentDelegation === "drep_always_abstain" + : currentDelegation === + AutomatedVotingOptionCurrentDelegation.drep_always_abstain ? "dashboard.cards.delegation.abstainDelegationTitle" : "dashboard.cards.delegation.dRepDelegationTitle"; @@ -140,9 +146,11 @@ const getDelegationTitle = (currentDelegation: string | null, ada: number) => { const getDelegationDescription = (currentDelegation: string | null) => { const key = - currentDelegation === "drep_always_no_confidence" + currentDelegation === + AutomatedVotingOptionCurrentDelegation.drep_always_no_confidence ? "dashboard.cards.delegation.noDescription" - : currentDelegation === "drep_always_abstain" + : currentDelegation === + AutomatedVotingOptionCurrentDelegation.drep_always_abstain ? "dashboard.cards.delegation.abstainDescription" : undefined; return ; @@ -152,9 +160,9 @@ const getProgressDescription = (delegateTo: string, ada: number) => { const key = (() => { if (!delegateTo) return undefined; switch (delegateTo) { - case "no confidence": + case AutomatedVotingOptionDelegationId.no_confidence: return "dashboard.cards.delegation.inProgress.no"; - case "abstain": + case AutomatedVotingOptionDelegationId.abstain: return "dashboard.cards.delegation.inProgress.abstain"; default: return "dashboard.cards.delegation.inProgress.dRep"; @@ -174,10 +182,10 @@ const getDisplayedDelegationId = ({ }) => { const restrictedNames = [ dRepID, - "drep_always_abstain", - "drep_always_no_confidence", - "abstain", - "no confidence", + AutomatedVotingOptionCurrentDelegation.drep_always_abstain, + AutomatedVotingOptionCurrentDelegation.drep_always_no_confidence, + AutomatedVotingOptionDelegationId.abstain, + AutomatedVotingOptionDelegationId.no_confidence, ]; if (delegateTo) { if (!restrictedNames.includes(delegateTo)) { diff --git a/govtool/frontend/src/context/pendingTransaction/utils.tsx b/govtool/frontend/src/context/pendingTransaction/utils.tsx index 38c80fc77..ffa97b22a 100644 --- a/govtool/frontend/src/context/pendingTransaction/utils.tsx +++ b/govtool/frontend/src/context/pendingTransaction/utils.tsx @@ -1,6 +1,10 @@ import { QueryClient, QueryKey } from "react-query"; import { QUERY_KEYS } from "@/consts"; import { TransactionType, TransactionState } from "./types"; +import { + AutomatedVotingOptionCurrentDelegation, + AutomatedVotingOptionDelegationId, +} from "@/types/automatedVotingOptions"; export const getDesiredResult = ( type: TransactionType, @@ -9,8 +13,10 @@ export const getDesiredResult = ( switch (type) { case "delegate": { // current delegation - if (resourceId === "no confidence") return "drep_always_no_confidence"; - if (resourceId === "abstain") return "drep_always_abstain"; + if (resourceId === AutomatedVotingOptionDelegationId.no_confidence) + return AutomatedVotingOptionCurrentDelegation.drep_always_no_confidence; + if (resourceId === AutomatedVotingOptionDelegationId.abstain) + return AutomatedVotingOptionCurrentDelegation.drep_always_abstain; return resourceId; } case "registerAsDrep": @@ -60,7 +66,10 @@ export const refetchData = async ( const data = await queryClient.getQueryData(queryKey); if (type === "delegate") { - if (resourceId === "no confidence" || resourceId === "abstain") { + if ( + resourceId === AutomatedVotingOptionDelegationId.no_confidence || + resourceId === AutomatedVotingOptionDelegationId.abstain + ) { return data.dRepView; } return data.dRepHash; diff --git a/govtool/frontend/src/context/wallet.tsx b/govtool/frontend/src/context/wallet.tsx index 3f5b4aa72..8e33395d8 100644 --- a/govtool/frontend/src/context/wallet.tsx +++ b/govtool/frontend/src/context/wallet.tsx @@ -72,6 +72,7 @@ import { TransactionStateWithoutResource, usePendingTransaction, } from "./pendingTransaction"; +import { AutomatedVotingOptionDelegationId } from "@/types/automatedVotingOptions"; interface Props { children: React.ReactNode; @@ -585,9 +586,9 @@ const CardanoProvider = (props: Props) => { // Create correct DRep let targetDRep; - if (target === "abstain") { + if (target === AutomatedVotingOptionDelegationId.abstain) { targetDRep = DRep.new_always_abstain(); - } else if (target === "no confidence") { + } else if (target === AutomatedVotingOptionDelegationId.no_confidence) { targetDRep = DRep.new_always_no_confidence(); } else if (target.includes("drep")) { targetDRep = DRep.new_key_hash(Ed25519KeyHash.from_bech32(target)); diff --git a/govtool/frontend/src/pages/DRepDirectoryContent.tsx b/govtool/frontend/src/pages/DRepDirectoryContent.tsx index b8837547e..d1843e279 100644 --- a/govtool/frontend/src/pages/DRepDirectoryContent.tsx +++ b/govtool/frontend/src/pages/DRepDirectoryContent.tsx @@ -15,6 +15,10 @@ import { Card, DataActionsBar } from "@molecules"; import { AutomatedVotingOptions, DRepCard } from "@organisms"; import { correctAdaFormat, formHexToBech32, isSameDRep } from "@utils"; import { DRepListSort, DRepStatus } from "@models"; +import { + AutomatedVotingOptionCurrentDelegation, + AutomatedVotingOptionDelegationId, +} from "@/types/automatedVotingOptions"; interface DRepDirectoryContentProps { isConnected?: boolean; @@ -95,11 +99,13 @@ export const DRepDirectoryContent: FC = ({ const dRepListToDisplay = yourselfDRep ? [yourselfDRep, ...dRepsWithoutYourself] : dRepList; - const isAnAutomatedOptionChosen = + + const isAnAutomatedVotingOptionChosen = currentDelegation?.dRepView && - ["drep_always_abstain", "drep_always_no_confidence"].includes( - currentDelegation?.dRepView, - ); + (currentDelegation?.dRepView === + AutomatedVotingOptionCurrentDelegation.drep_always_abstain || + currentDelegation?.dRepView === + AutomatedVotingOptionCurrentDelegation.drep_always_no_confidence); return ( @@ -126,14 +132,17 @@ export const DRepDirectoryContent: FC = ({ = ({ votingPower={ada.toString()} pendingTransaction={pendingTransaction} txHash={ - !pendingTransaction.delegate && isAnAutomatedOptionChosen + !pendingTransaction.delegate && isAnAutomatedVotingOptionChosen ? currentDelegation?.txHash : undefined } diff --git a/govtool/frontend/src/types/automatedVotingOptions.ts b/govtool/frontend/src/types/automatedVotingOptions.ts new file mode 100644 index 000000000..93f0bbdc6 --- /dev/null +++ b/govtool/frontend/src/types/automatedVotingOptions.ts @@ -0,0 +1,9 @@ +export enum AutomatedVotingOptionCurrentDelegation { + drep_always_abstain = "drep_always_abstain", + drep_always_no_confidence = "drep_always_no_confidence", +} + +export enum AutomatedVotingOptionDelegationId { + abstain = "abstain", + no_confidence = "no_confidence", +} From 3221dceaff7f918bafd30814c83bbcd34f5e0c3d Mon Sep 17 00:00:00 2001 From: Bartlomiej Sworzen Date: Thu, 9 May 2024 12:58:28 +0200 Subject: [PATCH 083/125] Update API.ts Signed-off-by: Bartlomiej Sworzen --- govtool/frontend/src/services/API.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/govtool/frontend/src/services/API.ts b/govtool/frontend/src/services/API.ts index 3e3d8e1d7..a3ad6398a 100644 --- a/govtool/frontend/src/services/API.ts +++ b/govtool/frontend/src/services/API.ts @@ -7,7 +7,7 @@ const TIMEOUT_IN_SECONDS = 30 * 1000; // 1000 ms is 1 s then its 30 s const BASE_URL = import.meta.env.VITE_BASE_URL; export const API = axios.create({ - baseURL: `${BASE_URL}`, + baseURL: BASE_URL, timeout: TIMEOUT_IN_SECONDS, }); From 9508e77b6a01e2f5d6129fa7e4b1f5e19382994d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Sworze=C5=84?= Date: Thu, 9 May 2024 15:30:19 +0200 Subject: [PATCH 084/125] change navto items --- govtool/frontend/src/pages/DRepDetails.tsx | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/govtool/frontend/src/pages/DRepDetails.tsx b/govtool/frontend/src/pages/DRepDetails.tsx index a184ef66d..2e79470ed 100644 --- a/govtool/frontend/src/pages/DRepDetails.tsx +++ b/govtool/frontend/src/pages/DRepDetails.tsx @@ -175,9 +175,11 @@ export const DRepDetails = ({ isConnected }: DRepDetailsProps) => { {/* TODO: fetch metadata, add views for metadata errors */} + {/* TODO: change email*/} @@ -187,8 +189,13 @@ export const DRepDetails = ({ isConnected }: DRepDetailsProps) => { flexDirection="column" gap={1.5} > + {/* TODO: update links*/} {LINKS.map((link) => ( - + ))} @@ -299,10 +306,12 @@ const DRepId = ({ children }: PropsWithChildren) => ( type LinkWithIconProps = { label: string; navTo: string; + isEmail?: boolean; }; -const MoreInfoLink = ({ label, navTo }: LinkWithIconProps) => { - const openLink = () => openInNewTab(navTo); +const MoreInfoLink = ({ label, navTo, isEmail = false }: LinkWithIconProps) => { + const openLink = () => + isEmail ? window.location.assign(`mailto:${navTo}`) : openInNewTab(navTo); return ( Date: Thu, 9 May 2024 15:36:32 +0200 Subject: [PATCH 085/125] fix lint --- govtool/frontend/src/pages/DRepDetails.tsx | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/govtool/frontend/src/pages/DRepDetails.tsx b/govtool/frontend/src/pages/DRepDetails.tsx index 2e79470ed..d79ffcb46 100644 --- a/govtool/frontend/src/pages/DRepDetails.tsx +++ b/govtool/frontend/src/pages/DRepDetails.tsx @@ -175,7 +175,7 @@ export const DRepDetails = ({ isConnected }: DRepDetailsProps) => { {/* TODO: fetch metadata, add views for metadata errors */} - {/* TODO: change email*/} + {/* TODO: change email */} { flexDirection="column" gap={1.5} > - {/* TODO: update links*/} + {/* TODO: update links */} {LINKS.map((link) => ( { - const openLink = () => - isEmail ? window.location.assign(`mailto:${navTo}`) : openInNewTab(navTo); + const openLink = () => { + if (isEmail) { + window.location.assign(`mailto:${navTo}`); + + return; + } + openInNewTab(navTo); + }; return ( Date: Fri, 10 May 2024 11:52:44 +0545 Subject: [PATCH 086/125] Set VITE_BASE_URL=/api on test deployment --- tests/test-infrastructure/docker-compose-govtool.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test-infrastructure/docker-compose-govtool.yml b/tests/test-infrastructure/docker-compose-govtool.yml index 68f96b8d7..b31f5b9ae 100644 --- a/tests/test-infrastructure/docker-compose-govtool.yml +++ b/tests/test-infrastructure/docker-compose-govtool.yml @@ -39,7 +39,7 @@ services: build: context: ../../govtool/frontend args: - VITE_BASE_URL: "" + VITE_BASE_URL: "/api" environment: VIRTUAL_HOST: https://${BASE_DOMAIN} networks: From b32b13877a64eb8084e42ca910f34bbf890f0fa4 Mon Sep 17 00:00:00 2001 From: Jan Jaroszczak Date: Fri, 10 May 2024 10:03:25 +0200 Subject: [PATCH 087/125] [#926] DRep panel needs to be clickable --- govtool/frontend/src/components/molecules/Card.tsx | 3 +++ .../src/components/molecules/DelegationAction.tsx | 10 ++++------ govtool/frontend/src/components/molecules/types.ts | 2 +- .../organisms/DashboardCards/DelegateDashboardCard.tsx | 2 +- 4 files changed, 9 insertions(+), 8 deletions(-) diff --git a/govtool/frontend/src/components/molecules/Card.tsx b/govtool/frontend/src/components/molecules/Card.tsx index a6ef31177..a5af603fe 100644 --- a/govtool/frontend/src/components/molecules/Card.tsx +++ b/govtool/frontend/src/components/molecules/Card.tsx @@ -10,6 +10,7 @@ type CardProps = PropsWithChildren & { label?: string; sx?: SxProps; variant?: "default" | "error" | "primary" | "success" | "warning"; + onCardClick?: () => void; }; const COLORS = { @@ -42,6 +43,7 @@ export const Card = ({ elevation = 3, label, sx, + onCardClick, }: CardProps) => { const colors = COLORS[variant]; @@ -57,6 +59,7 @@ export const Card = ({ position: "relative", ...sx, }} + onClick={onCardClick} > {label && ( { const { t } = useTranslation(); @@ -27,8 +27,10 @@ export const DelegationAction = ({ justifyContent: "space-between", px: 1.5, py: 1, + cursor: "pointer", ...sx, }} + onCardClick={onCardClick} > @@ -45,11 +47,7 @@ export const DelegationAction = ({ {dRepId} - +
); }; diff --git a/govtool/frontend/src/components/molecules/types.ts b/govtool/frontend/src/components/molecules/types.ts index b3b5343b2..5ec91cd3a 100644 --- a/govtool/frontend/src/components/molecules/types.ts +++ b/govtool/frontend/src/components/molecules/types.ts @@ -18,7 +18,7 @@ export type StepProps = { export type DirectVoterActionProps = { dRepId: string; - onClickArrow: () => void; + onCardClick: () => void; sx?: SxProps; }; diff --git a/govtool/frontend/src/components/organisms/DashboardCards/DelegateDashboardCard.tsx b/govtool/frontend/src/components/organisms/DashboardCards/DelegateDashboardCard.tsx index ea2bde854..6d59122d9 100644 --- a/govtool/frontend/src/components/organisms/DashboardCards/DelegateDashboardCard.tsx +++ b/govtool/frontend/src/components/organisms/DashboardCards/DelegateDashboardCard.tsx @@ -123,7 +123,7 @@ export const DelegateDashboardCard = ({ {displayedDelegationId && ( )} From 4d4670a311fa411b2d78083ff60745aad0ecc137 Mon Sep 17 00:00:00 2001 From: Sudip Bhattarai Date: Fri, 10 May 2024 15:49:45 +0545 Subject: [PATCH 088/125] Update lighthouse action --- .github/workflows/lighthouse.yml | 36 +++++++++--------------------- govtool/frontend/.lighthouserc.yml | 5 +++-- 2 files changed, 13 insertions(+), 28 deletions(-) diff --git a/.github/workflows/lighthouse.yml b/.github/workflows/lighthouse.yml index 2bf75ada6..1b9f8c40c 100644 --- a/.github/workflows/lighthouse.yml +++ b/.github/workflows/lighthouse.yml @@ -2,9 +2,13 @@ name: Lighthouse on: push: - paths: - - govtool/frontend/** - - .github/workflows/lighthouse.yml + branches: + - tests/lighthouse + workflow_run: + workflows: + - Build and deploy GovTool to TEST server + types: + - completed jobs: lighthouse: @@ -17,31 +21,16 @@ jobs: with: node-version: 16 - - name: Install dependencies - run: npm install - working-directory: ./govtool/frontend - - - name: Cache npm dependencies - id: npm-cache - uses: actions/cache@v3 - with: - path: | - ~/.npm - key: ${{ runner.os }}-npm-${{ hashFiles('govtool/frontend/package-lock.json', 'tests/govtool-frontend/package-lock.json') }} - restore-keys: | - ${{ runner.os }}-npm- - - run: npm install -g @lhci/cli@0.12.x - - name: Run build and lighthouse task + - name: Run lighthouse task working-directory: ./govtool/frontend run: | - npm install - VITE_BASE_URL=https://staging.govtool.byron.network/ npm run build lhci collect - name: Evaluate reports if: github.repository_owner != 'IntersectMBO' + working-directory: ./govtool/frontend run: | lhci assert --preset "lighthouse:recommended" @@ -50,9 +39,4 @@ jobs: if: github.repository_owner == 'IntersectMBO' run: | lhci assert --preset lighthouse:recommended || echo "LightHouse Assertion error ignored ..." - lhci upload --githubAppToken="${{ secrets.LHCI_GITHUB_APP_TOKEN }}" --token="${{ secrets.LHCI_SERVER_TOKEN }}" --serverBaseUrl=https://lighthouse.cardanoapi.io --ignoreDuplicateBuildFailure - curl -X POST https://ligththouse.cardanoapi.io/api/metrics/build-reports \ - -d "@./lighthouseci/$(ls ./.lighthouseci |grep 'lhr.*\.json' | head -n 1)" \ - -H "commit-hash: $(git rev-parse HEAD)" \ - -H "secret-token: ${{ secrets.METRICS_SERVER_SECRET_TOKEN }}" \ - -H 'Content-Type: application/json' || echo "Metric Upload error ignored ..." + lhci upload --githubAppToken="${{ secrets.LHCI_GITHUB_APP_TOKEN }}" --token="${{ secrets.LHCI_SERVER_TOKEN }}" --serverBaseUrl=https://lighthouse-govtool.cardanoapi.io --ignoreDuplicateBuildFailure diff --git a/govtool/frontend/.lighthouserc.yml b/govtool/frontend/.lighthouserc.yml index 5e963f7ae..fe06450bb 100644 --- a/govtool/frontend/.lighthouserc.yml +++ b/govtool/frontend/.lighthouserc.yml @@ -1,5 +1,6 @@ ci: collect: - staticDistDir: "./dist" url: - - "http://localhost" + - https://govtool.cardanoapi.io + - https://govtool.cardanoapi.io/drep_directory + - https://govtool.cardanoapi.io/governance_actions \ No newline at end of file From 38ce897381c70e7b81f8740d5f5ac7ee2a33e29f Mon Sep 17 00:00:00 2001 From: Sudip Bhattarai Date: Fri, 10 May 2024 15:55:16 +0545 Subject: [PATCH 089/125] Remove unused node options --- .github/workflows/lighthouse.yml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/.github/workflows/lighthouse.yml b/.github/workflows/lighthouse.yml index 1b9f8c40c..a7263ebd6 100644 --- a/.github/workflows/lighthouse.yml +++ b/.github/workflows/lighthouse.yml @@ -1,9 +1,6 @@ name: Lighthouse on: - push: - branches: - - tests/lighthouse workflow_run: workflows: - Build and deploy GovTool to TEST server @@ -13,8 +10,6 @@ on: jobs: lighthouse: runs-on: ubuntu-latest - env: - NODE_OPTIONS: --max_old_space_size=4096 steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v3 From d57c6d203d965d552a41b204e457a0b8494943c1 Mon Sep 17 00:00:00 2001 From: Sudip Bhattarai Date: Thu, 2 May 2024 16:41:24 +0545 Subject: [PATCH 090/125] Configure sonar-scanner --- .github/workflows/frontend_sonar_scan.yml | 2 +- .gitignore | 3 +++ govtool/frontend/sonar-project.properties | 8 +++++++- govtool/frontend/vite.config.ts | 9 +++++++-- 4 files changed, 18 insertions(+), 4 deletions(-) diff --git a/.github/workflows/frontend_sonar_scan.yml b/.github/workflows/frontend_sonar_scan.yml index 8a4df29ab..9827056d6 100644 --- a/.github/workflows/frontend_sonar_scan.yml +++ b/.github/workflows/frontend_sonar_scan.yml @@ -20,7 +20,7 @@ jobs: projectBaseDir: govtool/frontend env: SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} - SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }} + SONAR_HOST_URL: https://sonarcloud.io # Fail the build if it doesn't meet quality gate # - uses: sonarsource/sonarqube-quality-gate-action@master diff --git a/.gitignore b/.gitignore index 2bad55163..c242ad8d8 100644 --- a/.gitignore +++ b/.gitignore @@ -139,3 +139,6 @@ scripts/govtool/dev-postgres_password # nodejs/yarn node_modules + +# sonar scanner +.scannerwork/ \ No newline at end of file diff --git a/govtool/frontend/sonar-project.properties b/govtool/frontend/sonar-project.properties index e31d782bf..b7334acaf 100644 --- a/govtool/frontend/sonar-project.properties +++ b/govtool/frontend/sonar-project.properties @@ -1 +1,7 @@ -sonar.projectKey=voltaire-era_AYra4oOPzihwqYo-BApS +sonar.projectKey=intersect-govtool +sonar.sources=./src +sonar.host.url=https://sonarcloud.io +sonar.organization=intersect +sonar.javascript.lcov.reportPaths=./coverage/lcov.info +sonar.junit.reportsPath=./junit-report.xml +sonar.exclusions=node_modules \ No newline at end of file diff --git a/govtool/frontend/vite.config.ts b/govtool/frontend/vite.config.ts index 4316c151e..0442b81a1 100644 --- a/govtool/frontend/vite.config.ts +++ b/govtool/frontend/vite.config.ts @@ -51,7 +51,11 @@ const vitestConfig = defineVitestConfig({ setupFiles: "./src/setupTests.ts", globals: true, environment: "jsdom", - reporters: ["verbose", "junit"], + reporters: ["default","junit"], + outputFile: { + junit: './junit-report.xml', + json: './json-report.json', + }, coverage: { include: [ "src/components/**/*", @@ -62,7 +66,8 @@ const vitestConfig = defineVitestConfig({ "src/utils/**/*", ], provider: "v8", - reporter: ["json-summary"], + reporter: ["json-summary","lcov"], + reportOnFailure: true, enabled: true, }, }, From 90f1e02ab7411d2da637564e2fd7c83beece44ca Mon Sep 17 00:00:00 2001 From: jankun4 Date: Mon, 13 May 2024 10:36:03 +0200 Subject: [PATCH 091/125] [#957] drep/list drep type fix --- CHANGELOG.md | 1 + govtool/backend/sql/list-dreps.sql | 32 +++++++++++++++++++++++++++--- govtool/backend/src/VVA/DRep.hs | 9 ++++++--- 3 files changed, 36 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e637a8779..a94b2f2e9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -63,6 +63,7 @@ changes. ### Fixed +- drep/list sql fix (now the drep type is correct) [Issue 957](https://github.com/IntersectMBO/govtool/issues/957) - drep/list sql fix (now the latest tx date is correct) [Issue 826](https://github.com/IntersectMBO/govtool/issues/826) - drep/info no longer returns null values [Issue 720](https://github.com/IntersectMBO/govtool/issues/720) - drep/getVotes no longer returns 500 [Issue 685](https://github.com/IntersectMBO/govtool/issues/685) diff --git a/govtool/backend/sql/list-dreps.sql b/govtool/backend/sql/list-dreps.sql index 74def83c8..399b50874 100644 --- a/govtool/backend/sql/list-dreps.sql +++ b/govtool/backend/sql/list-dreps.sql @@ -26,9 +26,10 @@ SELECT dr_deposit.deposit, DRepDistr.amount, (DRepActivity.epoch_no - Max(coalesce(block.epoch_no, block_first_register.epoch_no))) <= DRepActivity.drep_activity AS active, - second_to_newest_drep_registration.voting_anchor_id IS NOT NULL AS has_voting_anchor, encode(dr_voting_anchor.tx_hash, 'hex') AS tx_hash, - newestRegister.time AS last_register_time + newestRegister.time AS last_register_time, + COALESCE(latestDeposit.deposit, 0), + non_deregister_voting_anchor.url IS NOT NULL AS has_non_deregister_voting_anchor FROM drep_hash dh JOIN ( @@ -42,6 +43,15 @@ FROM WHERE dr.deposit IS NOT NULL) AS dr_deposit ON dr_deposit.drep_hash_id = dh.id AND dr_deposit.rn = 1 + JOIN ( + SELECT + dr.id, + dr.drep_hash_id, + dr.deposit, + ROW_NUMBER() OVER (PARTITION BY dr.drep_hash_id ORDER BY dr.tx_id DESC) AS rn + FROM + drep_registration dr) AS latestDeposit ON latestDeposit.drep_hash_id = dh.id + AND latestDeposit.rn = 1 LEFT JOIN ( SELECT dr.id, @@ -53,6 +63,19 @@ FROM drep_registration dr JOIN tx ON tx.id = dr.tx_id) AS dr_voting_anchor ON dr_voting_anchor.drep_hash_id = dh.id AND dr_voting_anchor.rn = 1 + LEFT JOIN ( + SELECT + dr.id, + dr.drep_hash_id, + dr.voting_anchor_id, + ROW_NUMBER() OVER (PARTITION BY dr.drep_hash_id ORDER BY dr.tx_id DESC) AS rn, + tx.hash AS tx_hash + FROM + drep_registration dr + JOIN tx ON tx.id = dr.tx_id + WHERE dr.deposit is not null + AND dr.deposit >= 0) AS dr_non_deregister_voting_anchor ON dr_non_deregister_voting_anchor.drep_hash_id = dh.id + AND dr_non_deregister_voting_anchor.rn = 1 LEFT JOIN ( SELECT dr.id, @@ -65,6 +88,7 @@ FROM LEFT JOIN DRepDistr ON DRepDistr.hash_id = dh.id AND DRepDistr.rn = 1 LEFT JOIN voting_anchor va ON va.id = dr_voting_anchor.voting_anchor_id + LEFT JOIN voting_anchor non_deregister_voting_anchor on non_deregister_voting_anchor.id = dr_non_deregister_voting_anchor.voting_anchor_id CROSS JOIN DRepActivity LEFT JOIN voting_procedure AS voting_procedure ON voting_procedure.drep_voter = dh.id LEFT JOIN tx AS tx ON tx.id = voting_procedure.tx_id @@ -102,4 +126,6 @@ GROUP BY DRepActivity.epoch_no, DRepActivity.drep_activity, dr_voting_anchor.tx_hash, - newestRegister.time + newestRegister.time, + latestDeposit.deposit, + non_deregister_voting_anchor.url diff --git a/govtool/backend/src/VVA/DRep.hs b/govtool/backend/src/VVA/DRep.hs index d5db8d115..347527337 100644 --- a/govtool/backend/src/VVA/DRep.hs +++ b/govtool/backend/src/VVA/DRep.hs @@ -62,13 +62,16 @@ listDReps = withPool $ \conn -> do timeZone <- liftIO getCurrentTimeZone return [ DRepRegistration drepHash drepView url dataHash (floor @Scientific deposit) votingPower status drepType txHash (localTimeToUTC timeZone date) - | (drepHash, drepView, url, dataHash, deposit, votingPower, isActive, wasDRep, txHash, date) <- results + | (drepHash, drepView, url, dataHash, deposit, votingPower, isActive, txHash, date, latestDeposit, latestNonDeregisterVotingAnchorWasNotNull) <- results , let status = case (isActive, deposit) of (_, d) | d < 0 -> Retired (isActive, d) | d >= 0 && isActive -> Active | d >= 0 && not isActive -> Inactive - , let drepType | isNothing url && wasDRep = DRep - | isNothing url && not wasDRep = SoleVoter + , let latestDeposit' = floor @Scientific latestDeposit :: Integer + , let drepType | latestDeposit' >= 0 && isNothing url = SoleVoter + | latestDeposit' >= 0 && not (isNothing url) = DRep + | latestDeposit' < 0 && not latestNonDeregisterVotingAnchorWasNotNull = SoleVoter + | latestDeposit' < 0 && latestNonDeregisterVotingAnchorWasNotNull = DRep | Data.Maybe.isJust url = DRep ] From 6ba37d8c62c37979d88faae1d98082380721e21c Mon Sep 17 00:00:00 2001 From: Sudip Bhattarai Date: Mon, 13 May 2024 16:21:50 +0545 Subject: [PATCH 092/125] Use docker image to run sonar-scanner --- .github/workflows/frontend_sonar_scan.yml | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/.github/workflows/frontend_sonar_scan.yml b/.github/workflows/frontend_sonar_scan.yml index 9827056d6..1d565e8a6 100644 --- a/.github/workflows/frontend_sonar_scan.yml +++ b/.github/workflows/frontend_sonar_scan.yml @@ -15,15 +15,11 @@ jobs: - uses: actions/checkout@v4 with: fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis - - uses: sonarsource/sonarqube-scan-action@master - with: - projectBaseDir: govtool/frontend - env: - SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} - SONAR_HOST_URL: https://sonarcloud.io - - # Fail the build if it doesn't meet quality gate - # - uses: sonarsource/sonarqube-quality-gate-action@master - # timeout-minutes: 5 - # env: - # SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} + - name: Run SonarQube Scanner + run: | + docker run --rm \ + -e SONAR_HOST_URL="https://sonarcloud.io" \ + -e SONAR_TOKEN="ec4183646e59dd70c8077acfabe52062ccbea7a9" \ + -v "$(pwd):/usr/src" \ + --workdir=/usr/src/govtool/frontend \ + sonarsource/sonar-scanner-cli:5.0.1 \ No newline at end of file From 6353ee406c6ad008b76618f166547af6ec150def Mon Sep 17 00:00:00 2001 From: Sudip Bhattarai Date: Mon, 13 May 2024 16:34:38 +0545 Subject: [PATCH 093/125] Run tests before sonar scan --- .github/workflows/frontend_sonar_scan.yml | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/.github/workflows/frontend_sonar_scan.yml b/.github/workflows/frontend_sonar_scan.yml index 1d565e8a6..9e9b599cc 100644 --- a/.github/workflows/frontend_sonar_scan.yml +++ b/.github/workflows/frontend_sonar_scan.yml @@ -15,6 +15,26 @@ jobs: - uses: actions/checkout@v4 with: fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis + + - name: Cache dependencies + uses: actions/cache@v2 + with: + path: govtool/frontend/node_modules + key: ${{ runner.os }}-node-${{ hashFiles('govtool/frontend/package-lock.json') }} + + - name: Set up Node.js + uses: actions/setup-node@v4 + with: + node-version-file: "govtool/frontend/.nvmrc" + + - name: 🧪 Test + working-directory: govtool/frontend + env: + NODE_OPTIONS: "--max_old_space_size=4096" + run: | + npm install + npm run test:coverage + - name: Run SonarQube Scanner run: | docker run --rm \ From 3f583da0256ffa8b0737b0a7d37b1b55d2bc40de Mon Sep 17 00:00:00 2001 From: Sudip Bhattarai Date: Mon, 13 May 2024 16:48:20 +0545 Subject: [PATCH 094/125] Use sonar scanner action with coverage reports. --- .github/workflows/frontend_sonar_scan.yml | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/.github/workflows/frontend_sonar_scan.yml b/.github/workflows/frontend_sonar_scan.yml index 9e9b599cc..071f85836 100644 --- a/.github/workflows/frontend_sonar_scan.yml +++ b/.github/workflows/frontend_sonar_scan.yml @@ -35,11 +35,18 @@ jobs: npm install npm run test:coverage - - name: Run SonarQube Scanner - run: | - docker run --rm \ - -e SONAR_HOST_URL="https://sonarcloud.io" \ - -e SONAR_TOKEN="ec4183646e59dd70c8077acfabe52062ccbea7a9" \ - -v "$(pwd):/usr/src" \ - --workdir=/usr/src/govtool/frontend \ - sonarsource/sonar-scanner-cli:5.0.1 \ No newline at end of file +# - name: Run SonarQube Scanner +# run: | +# docker run --rm \ +# -e SONAR_HOST_URL="https://sonarcloud.io" \ +# -e SONAR_TOKEN="ec4183646e59dd70c8077acfabe52062ccbea7a9" \ +# -v "$(pwd):/usr/src" \ +# --workdir=/usr/src/govtool/frontend \ +# sonarsource/sonar-scanner-cli:5.0.1 + + - uses: sonarsource/sonarqube-scan-action@master + with: + projectBaseDir: govtool/frontend + env: + SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} + SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }} From 0cef8a736dba7976f8b50838ef5a058f06b01430 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Sza=C5=82owski?= Date: Mon, 13 May 2024 15:55:27 +0200 Subject: [PATCH 095/125] fix: fix frontend makefile --- scripts/govtool/frontend.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/govtool/frontend.mk b/scripts/govtool/frontend.mk index 97caf9bef..fb74d798b 100644 --- a/scripts/govtool/frontend.mk +++ b/scripts/govtool/frontend.mk @@ -15,7 +15,7 @@ build-frontend: docker-login if [[ "$(cardano_network)" = "mainnet" ]]; then NETWORK_FLAG=1; else NETWORK_FLAG=0; fi; \ $(call check_image_on_ecr,frontend,$(frontend_image_tag)) || \ $(docker) build --tag "$(repo_url)/frontend:$(frontend_image_tag)" \ - --build-arg VITE_BASE_URL="https://$(domain)" \ + --build-arg VITE_BASE_URL="https://$(domain)/api" \ --build-arg VITE_GTM_ID="$${GTM_ID}" \ --build-arg VITE_NETWORK_FLAG="$$NETWORK_FLAG" \ --build-arg VITE_SENTRY_DSN="$${SENTRY_DSN}" \ From e129f0aeaa0e34eafdaf67e5a0b27a2c940c4439 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Placzy=C5=84ski?= Date: Mon, 13 May 2024 16:47:31 +0200 Subject: [PATCH 096/125] Allow backend to receive POST mehod MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In order to facilitate the metadata validation on backend service we set the POST method to be allowed in CORS. Signed-off-by: Paweł Placzyński --- scripts/govtool/config/templates/docker-compose.yml.tpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/govtool/config/templates/docker-compose.yml.tpl b/scripts/govtool/config/templates/docker-compose.yml.tpl index 42c09f083..975895d30 100644 --- a/scripts/govtool/config/templates/docker-compose.yml.tpl +++ b/scripts/govtool/config/templates/docker-compose.yml.tpl @@ -244,7 +244,7 @@ services: labels: - "traefik.enable=true" - "traefik.http.middlewares.backend-stripprefix.stripprefix.prefixes=/api" - - "traefik.http.middlewares.backend-cors.headers.accesscontrolallowmethods=GET,HEAD,OPTIONS" + - "traefik.http.middlewares.backend-cors.headers.accesscontrolallowmethods=GET,POST,HEAD,OPTIONS" - "traefik.http.middlewares.backend-cors.headers.accesscontrolallowheaders=*" - "traefik.http.middlewares.backend-cors.headers.accesscontrolalloworiginlist=https://" - "traefik.http.middlewares.backend-cors.headers.accesscontrolmaxage=100" From 1eb3d99e2d67324defe76bc51e8e9541571c578f Mon Sep 17 00:00:00 2001 From: jankun4 Date: Mon, 13 May 2024 16:22:13 +0200 Subject: [PATCH 097/125] fix backend config --- scripts/govtool/config/templates/backend-config.json.tpl | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/scripts/govtool/config/templates/backend-config.json.tpl b/scripts/govtool/config/templates/backend-config.json.tpl index c3851bbe1..1cc59533e 100644 --- a/scripts/govtool/config/templates/backend-config.json.tpl +++ b/scripts/govtool/config/templates/backend-config.json.tpl @@ -9,5 +9,7 @@ "port" : 9876, "host" : "0.0.0.0", "cachedurationseconds": 20, - "sentrydsn": "" + "sentrydsn": "", + "metadatavalidationhost": "metadata-validation", + "3000" } From 59596807487423f7bb2a4f08280d604e662f6592 Mon Sep 17 00:00:00 2001 From: jankun4 Date: Mon, 13 May 2024 16:23:19 +0200 Subject: [PATCH 098/125] fix backend config --- scripts/govtool/config/templates/backend-config.json.tpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/govtool/config/templates/backend-config.json.tpl b/scripts/govtool/config/templates/backend-config.json.tpl index 1cc59533e..31a141afd 100644 --- a/scripts/govtool/config/templates/backend-config.json.tpl +++ b/scripts/govtool/config/templates/backend-config.json.tpl @@ -11,5 +11,5 @@ "cachedurationseconds": 20, "sentrydsn": "", "metadatavalidationhost": "metadata-validation", - "3000" + "metadatavalidationport": "3000" } From 8b910317c7ff2bbb45d66b1b842fc9d94d78383f Mon Sep 17 00:00:00 2001 From: Jan Jaroszczak Date: Fri, 10 May 2024 10:53:05 +0200 Subject: [PATCH 099/125] [#927] Your DRep needs showing on detail page --- govtool/frontend/src/pages/DRepDetails.tsx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/govtool/frontend/src/pages/DRepDetails.tsx b/govtool/frontend/src/pages/DRepDetails.tsx index d79ffcb46..40849e0bb 100644 --- a/govtool/frontend/src/pages/DRepDetails.tsx +++ b/govtool/frontend/src/pages/DRepDetails.tsx @@ -23,6 +23,7 @@ import { openInNewTab, testIdFromLabel, } from "@utils"; +import { DRepStatus } from "@/models"; const LINKS = [ "darlenelonglink1.DRepwebsiteorwhatever.com", @@ -166,6 +167,9 @@ export const DRepDetails = ({ isConnected }: DRepDetailsProps) => { + {isMe && ( + + )} From e33383bbe242779005f9cf364f9dd9ccb82c7b57 Mon Sep 17 00:00:00 2001 From: Jan Jaroszczak Date: Mon, 13 May 2024 14:11:26 +0200 Subject: [PATCH 100/125] [#927] Fixes after CR --- govtool/frontend/public/icons/Edit.svg | 4 + govtool/frontend/src/consts/icons.ts | 1 + govtool/frontend/src/i18n/locales/en.ts | 4 +- govtool/frontend/src/pages/DRepDetails.tsx | 132 ++++++++++++++------- govtool/frontend/src/utils/dRep.ts | 2 +- 5 files changed, 95 insertions(+), 48 deletions(-) create mode 100644 govtool/frontend/public/icons/Edit.svg diff --git a/govtool/frontend/public/icons/Edit.svg b/govtool/frontend/public/icons/Edit.svg new file mode 100644 index 000000000..a2c68c344 --- /dev/null +++ b/govtool/frontend/public/icons/Edit.svg @@ -0,0 +1,4 @@ + + + + diff --git a/govtool/frontend/src/consts/icons.ts b/govtool/frontend/src/consts/icons.ts index dff246b62..bd70a2b06 100644 --- a/govtool/frontend/src/consts/icons.ts +++ b/govtool/frontend/src/consts/icons.ts @@ -17,6 +17,7 @@ export const ICONS = { drawerIcon: "/icons/DrawerIcon.svg", dRepDirectoryActiveIcon: "/icons/DRepDirectoryActive.svg", dRepDirectoryIcon: "/icons/DRepDirectory.svg", + editIcon: "/icons/Edit.svg", externalLinkIcon: "/icons/ExternalLink.svg", faqsActiveIcon: "/icons/FaqsActive.svg", faqsIcon: "/icons/Faqs.svg", diff --git a/govtool/frontend/src/i18n/locales/en.ts b/govtool/frontend/src/i18n/locales/en.ts index f54da84d1..56d199455 100644 --- a/govtool/frontend/src/i18n/locales/en.ts +++ b/govtool/frontend/src/i18n/locales/en.ts @@ -261,11 +261,11 @@ export const en = { directVoter: "Direct Voter", filterTitle: "DRep Status", goToDRepDirectory: "Go to DRep Directory", - meAsDRep: "This DRep ID is connected to your wallet", + meAsDRep: "This DRep ID is connected to your wallet", myDelegation: "You have delegated ₳ {{ada}} to:", myDelegationToYourself: "You have delegated ₳ {{ada}} to yourself:", - myDRep: "This is your DRep", + myDRep: "This is your DRep profile", listTitle: "Find a DRep", noConfidenceDefaultDescription: "Select this to signal no confidence in the current constitutional committee by voting NO on every proposal and voting YES to no confidence proposals", diff --git a/govtool/frontend/src/pages/DRepDetails.tsx b/govtool/frontend/src/pages/DRepDetails.tsx index 40849e0bb..b797f2feb 100644 --- a/govtool/frontend/src/pages/DRepDetails.tsx +++ b/govtool/frontend/src/pages/DRepDetails.tsx @@ -12,6 +12,7 @@ import { ICONS, PATHS } from "@consts"; import { useCardano, useModal } from "@context"; import { useDelegateTodRep, + useGetAdaHolderCurrentDelegationQuery, useGetDRepListInfiniteQuery, useScreenDimension, useTranslation, @@ -23,7 +24,6 @@ import { openInNewTab, testIdFromLabel, } from "@utils"; -import { DRepStatus } from "@/models"; const LINKS = [ "darlenelonglink1.DRepwebsiteorwhatever.com", @@ -38,7 +38,7 @@ type DRepDetailsProps = { }; export const DRepDetails = ({ isConnected }: DRepDetailsProps) => { - const { dRepID: myDRepId, pendingTransaction } = useCardano(); + const { dRepID: myDRepId, pendingTransaction, stakeKey } = useCardano(); const { t } = useTranslation(); const navigate = useNavigate(); const location = useLocation(); @@ -46,6 +46,7 @@ export const DRepDetails = ({ isConnected }: DRepDetailsProps) => { const { screenWidth } = useScreenDimension(); const { dRepId: dRepParam } = useParams(); const { delegate, isDelegating } = useDelegateTodRep(); + const { currentDelegation } = useGetAdaHolderCurrentDelegationQuery(stakeKey); const displayBackButton = location.state?.enteredFromWithinApp || false; @@ -74,7 +75,7 @@ export const DRepDetails = ({ isConnected }: DRepDetailsProps) => { const { view, status, votingPower, type } = dRep; const isMe = isSameDRep(dRep, myDRepId); - const isMyDrep = isSameDRep(dRep, myDRepId); + const isMyDrep = isSameDRep(dRep, currentDelegation?.dRepView); const isMyDrepInProgress = isSameDRep( dRep, pendingTransaction.delegate?.resourceId, @@ -118,58 +119,99 @@ export const DRepDetails = ({ isConnected }: DRepDetailsProps) => { }} > {(isMe || isMyDrep) && ( - theme.shadows[2], - color: (theme) => theme.palette.text.primary, - mb: 1.5, - px: 2, - py: 0.5, - width: "100%", + display: "flex", + alignItems: "center", + justifyContent: "space-between", + mb: "18px", + ...(screenWidth <= 1020 && { + flexDirection: "column", + gap: 3, + }), }} - /> - )} - - - {type} - - {isMe && ( - - )} - - + theme.shadows[2], + color: (theme) => theme.palette.text.primary, + px: 2, + py: 0.5, + ...(isMe && { + width: "351px", + }), + ...(isMyDrep && + !isMe && { + width: "100%", + }), + ...(screenWidth <= 1020 && { + width: "100%", + }), + }} + /> + {isMe && ( + + + {screenWidth > 1020 && } + + )} +
+ )} + + + {type} + + {(screenWidth <= 1020 || !isMe) && ( + + )} + {view} - {isMe && ( - - )} diff --git a/govtool/frontend/src/utils/dRep.ts b/govtool/frontend/src/utils/dRep.ts index 7743a017e..1521fda5d 100644 --- a/govtool/frontend/src/utils/dRep.ts +++ b/govtool/frontend/src/utils/dRep.ts @@ -2,7 +2,7 @@ import { DRepData } from "@/models"; export const isSameDRep = ( { drepId, view }: DRepData, - dRepIdOrView: string | undefined, + dRepIdOrView: string | undefined | null, ) => { if (!dRepIdOrView) { return false; From c9788e5f067028b530092e10bc375546304ea371 Mon Sep 17 00:00:00 2001 From: Jan Jaroszczak Date: Mon, 13 May 2024 22:47:23 +0200 Subject: [PATCH 101/125] [#932] Automated voting options voting power fix --- .../organisms/AutomatedVotingOptions.tsx | 20 +++++++++++++++---- govtool/frontend/src/consts/queryKeys.ts | 1 + govtool/frontend/src/hooks/queries/index.ts | 1 + .../src/hooks/queries/useGetNetworkMetrics.ts | 17 ++++++++++++++++ .../services/requests/getNetworkMetrics.ts | 7 +++++++ .../frontend/src/services/requests/index.ts | 1 + 6 files changed, 43 insertions(+), 4 deletions(-) create mode 100644 govtool/frontend/src/hooks/queries/useGetNetworkMetrics.ts create mode 100644 govtool/frontend/src/services/requests/getNetworkMetrics.ts diff --git a/govtool/frontend/src/components/organisms/AutomatedVotingOptions.tsx b/govtool/frontend/src/components/organisms/AutomatedVotingOptions.tsx index 5844caf52..dd32f0658 100644 --- a/govtool/frontend/src/components/organisms/AutomatedVotingOptions.tsx +++ b/govtool/frontend/src/components/organisms/AutomatedVotingOptions.tsx @@ -9,9 +9,9 @@ import { import { Typography } from "@atoms"; import { ICONS } from "@consts"; import { PendingTransaction } from "@context"; -import { useTranslation } from "@hooks"; +import { useGetNetworkMetrics, useTranslation } from "@hooks"; import { AutomatedVotingCard } from "@molecules"; -import { openInNewTab } from "@/utils"; +import { correctAdaFormat, openInNewTab } from "@/utils"; import { AutomatedVotingOptionCurrentDelegation, AutomatedVotingOptionDelegationId, @@ -42,6 +42,8 @@ export const AutomatedVotingOptions = ({ const [isOpen, setIsOpen] = useState(false); + const { networkMetrics } = useGetNetworkMetrics(); + // TODO: Change to certain automated voted option if available const onClickInfo = () => openInNewTab("https://docs.sanchogov.tools/"); @@ -117,7 +119,11 @@ export const AutomatedVotingOptions = ({ }) : t("dRepDirectory.abstainCardDefaultTitle") } - votingPower={votingPower} + votingPower={ + networkMetrics + ? correctAdaFormat(networkMetrics?.alwaysAbstainVotingPower) + : "" + } transactionId={ pendingTransaction?.delegate?.resourceId === AutomatedVotingOptionDelegationId.abstain @@ -148,7 +154,13 @@ export const AutomatedVotingOptions = ({ }) : t("dRepDirectory.noConfidenceDefaultTitle") } - votingPower={votingPower} + votingPower={ + networkMetrics + ? correctAdaFormat( + networkMetrics?.alwaysNoConfidenceVotingPower, + ) + : "" + } transactionId={ pendingTransaction?.delegate?.resourceId === AutomatedVotingOptionDelegationId.no_confidence diff --git a/govtool/frontend/src/consts/queryKeys.ts b/govtool/frontend/src/consts/queryKeys.ts index ccfdffe3f..0a8c7fdf1 100644 --- a/govtool/frontend/src/consts/queryKeys.ts +++ b/govtool/frontend/src/consts/queryKeys.ts @@ -4,6 +4,7 @@ export const QUERY_KEYS = { useGetDRepListInfiniteKey: "useGetDRepListInfiniteKey", useGetDRepVotesKey: "useGetDRepVotesKey", useGetDRepVotingPowerKey: "useGetDRepVotingPowerKey", + useGetNetworkMetricsKey: "useGetNetworkMetricsKey", useGetProposalKey: "useGetProposalKey", useGetProposalsKey: "useGetProposalsKey", useGetProposalsInfiniteKey: "useGetProposalsInfiniteKey", diff --git a/govtool/frontend/src/hooks/queries/index.ts b/govtool/frontend/src/hooks/queries/index.ts index f088d04fb..2b888a14b 100644 --- a/govtool/frontend/src/hooks/queries/index.ts +++ b/govtool/frontend/src/hooks/queries/index.ts @@ -4,6 +4,7 @@ export * from "./useGetVoterInfoQuery"; export * from "./useGetDRepListQuery"; export * from "./useGetDRepVotesQuery"; export * from "./useGetDRepVotingPowerQuery"; +export * from "./useGetNetworkMetrics"; export * from "./useGetProposalQuery"; export * from "./useGetProposalsQuery"; export * from "./useGetProposalsInfiniteQuery"; diff --git a/govtool/frontend/src/hooks/queries/useGetNetworkMetrics.ts b/govtool/frontend/src/hooks/queries/useGetNetworkMetrics.ts new file mode 100644 index 000000000..f83b5646f --- /dev/null +++ b/govtool/frontend/src/hooks/queries/useGetNetworkMetrics.ts @@ -0,0 +1,17 @@ +import { useQuery } from "react-query"; + +import { getNetworkMetrics } from "@services"; +import { QUERY_KEYS } from "@consts"; +import { useCardano } from "@/context"; + +export const useGetNetworkMetrics = () => { + const { isEnabled } = useCardano(); + + const { data } = useQuery({ + queryKey: QUERY_KEYS.useGetNetworkMetricsKey, + queryFn: () => getNetworkMetrics(), + enabled: isEnabled, + }); + + return { networkMetrics: data }; +}; diff --git a/govtool/frontend/src/services/requests/getNetworkMetrics.ts b/govtool/frontend/src/services/requests/getNetworkMetrics.ts new file mode 100644 index 000000000..59fd0c674 --- /dev/null +++ b/govtool/frontend/src/services/requests/getNetworkMetrics.ts @@ -0,0 +1,7 @@ +import { API } from "../API"; + +export const getNetworkMetrics = async () => { + const response = await API.get("/network/metrics"); + + return response.data; +}; diff --git a/govtool/frontend/src/services/requests/index.ts b/govtool/frontend/src/services/requests/index.ts index 3121e4c5c..f6721175a 100644 --- a/govtool/frontend/src/services/requests/index.ts +++ b/govtool/frontend/src/services/requests/index.ts @@ -18,3 +18,4 @@ export * from "./postDRepRemoveVote"; export * from "./postDRepRetire"; export * from "./postDRepVote"; export * from "./metadataValidation"; +export * from "./getNetworkMetrics"; From 5248e87cd78e7dce12a1c57b6926305f2c783453 Mon Sep 17 00:00:00 2001 From: Jan Jaroszczak Date: Mon, 13 May 2024 23:47:14 +0200 Subject: [PATCH 102/125] [#925] In Progress DRep cards display fixes --- .../organisms/AutomatedVotingOptions.tsx | 11 +++++++---- .../src/pages/DRepDirectoryContent.tsx | 19 ++++++++++++++++--- 2 files changed, 23 insertions(+), 7 deletions(-) diff --git a/govtool/frontend/src/components/organisms/AutomatedVotingOptions.tsx b/govtool/frontend/src/components/organisms/AutomatedVotingOptions.tsx index 5844caf52..213ad8a13 100644 --- a/govtool/frontend/src/components/organisms/AutomatedVotingOptions.tsx +++ b/govtool/frontend/src/components/organisms/AutomatedVotingOptions.tsx @@ -63,10 +63,13 @@ export const AutomatedVotingOptions = ({ isDelegationToAbstainInProgress || isDelegationToNoConfidenceInProgress; - if (shouldBeSetOpen) { - setIsOpen(true); - } - }, [currentDelegation, delegationInProgress]); + setIsOpen(shouldBeSetOpen); + }, [ + isDelegatedToAbstain, + isDelegatedToNoConfidence, + isDelegationToAbstainInProgress, + isDelegationToNoConfidenceInProgress, + ]); return ( = ({ const dRepListToDisplay = yourselfDRep ? [yourselfDRep, ...dRepsWithoutYourself] : dRepList; + const inProgressDelegationDRepData = dRepListToDisplay.find( + (dRep) => dRep.drepId === inProgressDelegation, + ); const isAnAutomatedVotingOptionChosen = currentDelegation?.dRepView && @@ -110,7 +113,7 @@ export const DRepDirectoryContent: FC = ({ return ( {/* My delegation */} - {myDrep && ( + {myDrep && !inProgressDelegation && (
@@ -123,6 +126,14 @@ export const DRepDirectoryContent: FC = ({ />
)} + {inProgressDelegation && inProgressDelegationDRepData && ( + + )} {/* Automated voting options */} {isConnected && ( @@ -204,7 +215,10 @@ export const DRepDirectoryContent: FC = ({
)} {dRepListToDisplay?.map((dRep) => { - if (isSameDRep(dRep, myDrep?.view)) { + if ( + isSameDRep(dRep, myDrep?.view) || + isSameDRep(dRep, inProgressDelegation) + ) { return null; } return ( @@ -212,7 +226,6 @@ export const DRepDirectoryContent: FC = ({ delegate(dRep.drepId)} /> From 23ddf9eff8962ed9ee9517e3ec94b2abc0377b5a Mon Sep 17 00:00:00 2001 From: Sudip Bhattarai Date: Mon, 13 May 2024 16:51:28 +0545 Subject: [PATCH 103/125] Remove sonar host configuration --- .github/workflows/frontend_sonar_scan.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/frontend_sonar_scan.yml b/.github/workflows/frontend_sonar_scan.yml index 071f85836..09b8f994f 100644 --- a/.github/workflows/frontend_sonar_scan.yml +++ b/.github/workflows/frontend_sonar_scan.yml @@ -35,6 +35,8 @@ jobs: npm install npm run test:coverage +# Running with docker +# # - name: Run SonarQube Scanner # run: | # docker run --rm \ @@ -49,4 +51,4 @@ jobs: projectBaseDir: govtool/frontend env: SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} - SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }} + SONAR_HOST_URL: https://sonarcloud.io \ No newline at end of file From 4f32371b6fa3e64191ac34a86abcc18d5035ea0a Mon Sep 17 00:00:00 2001 From: Sudip Bhattarai Date: Tue, 14 May 2024 11:55:37 +0545 Subject: [PATCH 104/125] Expose kuber-api for tests --- tests/test-infrastructure/docker-compose-cardano.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/test-infrastructure/docker-compose-cardano.yml b/tests/test-infrastructure/docker-compose-cardano.yml index c2d262628..6805696bd 100644 --- a/tests/test-infrastructure/docker-compose-cardano.yml +++ b/tests/test-infrastructure/docker-compose-cardano.yml @@ -94,6 +94,7 @@ services: - node_ipc:/ipc/ networks: - cardano + - frontend deploy: placement: constraints: From 9de73995f55c8f69ffe6c2ea817a81fab20ae20c Mon Sep 17 00:00:00 2001 From: weronika Date: Tue, 14 May 2024 10:06:35 +0200 Subject: [PATCH 105/125] move no results card to component and replace with loader in drep details --- .../molecules/EmptyStateDrepDirectory.tsx | 30 +++++++++++++++++++ .../src/components/molecules/index.ts | 1 + govtool/frontend/src/pages/DRepDetails.tsx | 25 ++++++++++------ .../src/pages/DRepDirectoryContent.tsx | 23 ++------------ 4 files changed, 49 insertions(+), 30 deletions(-) create mode 100644 govtool/frontend/src/components/molecules/EmptyStateDrepDirectory.tsx diff --git a/govtool/frontend/src/components/molecules/EmptyStateDrepDirectory.tsx b/govtool/frontend/src/components/molecules/EmptyStateDrepDirectory.tsx new file mode 100644 index 000000000..c6bc23f45 --- /dev/null +++ b/govtool/frontend/src/components/molecules/EmptyStateDrepDirectory.tsx @@ -0,0 +1,30 @@ +import { useTranslation } from "@hooks"; + +import { Card } from "./Card"; +import { Typography } from "../atoms"; + +export const EmptyStateDrepDirectory = () => { + const { t } = useTranslation(); + + return ( + + + {t("dRepDirectory.noResultsForTheSearchTitle")} + + + {t("dRepDirectory.noResultsForTheSearchDescription")} + + + ); +}; diff --git a/govtool/frontend/src/components/molecules/index.ts b/govtool/frontend/src/components/molecules/index.ts index 1a33c71f7..937824d48 100644 --- a/govtool/frontend/src/components/molecules/index.ts +++ b/govtool/frontend/src/components/molecules/index.ts @@ -12,6 +12,7 @@ export * from "./DataActionsSorting"; export * from "./DataMissingInfoBox"; export * from "./DelegationAction"; export * from "./DRepInfoCard"; +export * from "./EmptyStateDrepDirectory"; export * from "./EmptyStateGovernanceActionsCategory"; export * from "./Field"; export * from "./GovActionDetails"; diff --git a/govtool/frontend/src/pages/DRepDetails.tsx b/govtool/frontend/src/pages/DRepDetails.tsx index d79ffcb46..1f2c51fb0 100644 --- a/govtool/frontend/src/pages/DRepDetails.tsx +++ b/govtool/frontend/src/pages/DRepDetails.tsx @@ -1,10 +1,5 @@ import { PropsWithChildren } from "react"; -import { - Navigate, - useLocation, - useNavigate, - useParams, -} from "react-router-dom"; +import { useLocation, useNavigate, useParams } from "react-router-dom"; import { Box, ButtonBase, Chip, CircularProgress } from "@mui/material"; import { Button, StatusPill, Typography } from "@atoms"; @@ -16,7 +11,7 @@ import { useScreenDimension, useTranslation, } from "@hooks"; -import { Card, LinkWithIcon, Share } from "@molecules"; +import { Card, EmptyStateDrepDirectory, LinkWithIcon, Share } from "@molecules"; import { correctAdaFormat, isSameDRep, @@ -53,7 +48,7 @@ export const DRepDetails = ({ isConnected }: DRepDetailsProps) => { }); const dRep = dRepData?.[0]; - if (dRep === undefined || isDRepListLoading) + if (isDRepListLoading) return ( { ); - if (!dRep) return ; + if (!dRep) + return ( + + + + ); const { view, status, votingPower, type } = dRep; diff --git a/govtool/frontend/src/pages/DRepDirectoryContent.tsx b/govtool/frontend/src/pages/DRepDirectoryContent.tsx index d1843e279..a9cbc550b 100644 --- a/govtool/frontend/src/pages/DRepDirectoryContent.tsx +++ b/govtool/frontend/src/pages/DRepDirectoryContent.tsx @@ -11,7 +11,7 @@ import { useGetAdaHolderVotingPowerQuery, useGetDRepListInfiniteQuery, } from "@hooks"; -import { Card, DataActionsBar } from "@molecules"; +import { DataActionsBar, EmptyStateDrepDirectory } from "@molecules"; import { AutomatedVotingOptions, DRepCard } from "@organisms"; import { correctAdaFormat, formHexToBech32, isSameDRep } from "@utils"; import { DRepListSort, DRepStatus } from "@models"; @@ -183,26 +183,7 @@ export const DRepDirectoryContent: FC = ({ flex: 1, }} > - {dRepList?.length === 0 && ( - - - {t("dRepDirectory.noResultsForTheSearchTitle")} - - - {t("dRepDirectory.noResultsForTheSearchDescription")} - - - )} + {dRepList?.length === 0 && } {dRepListToDisplay?.map((dRep) => { if (isSameDRep(dRep, myDrep?.view)) { return null; From 3a948e2d116504dc0de87e8203883311715b3e2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Placzy=C5=84ski?= Date: Tue, 14 May 2024 11:22:17 +0200 Subject: [PATCH 106/125] [#1003] Apply basic auth on staging environment In this commit, basic authentication has been implemented on the staging environment to ensure that only authorized users can access it. Different environment variables have been set up for each environment (dev, test, staging) to provide different configurations. This allows for specifying the basic authentication credentials specific to the staging environment. The changes made include modifying the .envrc file to set environment variables based on the selected environment, as well as updating the configuration in config.mk to generate the appropriate nginx authentication file based on the environment chosen. --- scripts/govtool/.envrc | 14 +++++++++++++- scripts/govtool/config.mk | 6 +++--- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/scripts/govtool/.envrc b/scripts/govtool/.envrc index 0e49e3cbd..fa6f7d8f1 100644 --- a/scripts/govtool/.envrc +++ b/scripts/govtool/.envrc @@ -1,4 +1,16 @@ source_up -env_vars_required ENVIRONMENT AWS_PROFILE CARDANO_NETWORK DBSYNC_POSTGRES_USER DBSYNC_POSTGRES_PASSWORD DBSYNC_POSTGRES_DB TRAEFIK_LE_EMAIL GTM_ID SENTRY_DSN_BACKEND SENTRY_DSN SENTRY_ENVIRONMENT GRAFANA_ADMIN_PASSWORD GRAFANA_SLACK_RECIPIENT NGINX_BASIC_AUTH GRAFANA_SLACK_OAUTH_TOKEN IP_ADDRESS_BYPASSING_BASIC_AUTH1 IP_ADDRESS_BYPASSING_BASIC_AUTH2 +env_vars_required ENVIRONMENT AWS_PROFILE CARDANO_NETWORK DBSYNC_POSTGRES_USER DBSYNC_POSTGRES_PASSWORD DBSYNC_POSTGRES_DB TRAEFIK_LE_EMAIL GTM_ID SENTRY_DSN_BACKEND SENTRY_DSN SENTRY_ENVIRONMENT GRAFANA_ADMIN_PASSWORD GRAFANA_SLACK_RECIPIENT GRAFANA_SLACK_OAUTH_TOKEN IP_ADDRESS_BYPASSING_BASIC_AUTH1 IP_ADDRESS_BYPASSING_BASIC_AUTH2 + +case "$ENVIRONMENT" in + "dev") + env_vars_required DEV_NGINX_BASIC_AUTH + ;; + "test") + env_vars_required TEST_NGINX_BASIC_AUTH + ;; + "staging") + env_vars_required STAGING_NGINX_BASIC_AUTH + ;; +esac use flake --extra-experimental-features nix-command --extra-experimental-features flakes ../..#scripts diff --git a/scripts/govtool/config.mk b/scripts/govtool/config.mk index 2a7c4b770..439d75495 100644 --- a/scripts/govtool/config.mk +++ b/scripts/govtool/config.mk @@ -112,9 +112,9 @@ $(target_config_dir)/nginx/auth.conf: $(target_config_dir)/nginx/ fi $(target_config_dir)/nginx/govtool.htpasswd: $(target_config_dir)/nginx/ - @:$(call check_defined, domain) - if [[ "$(domain)" == *"sanchonet.govtool.byron.network"* ]]; then \ - echo "$${NGINX_BASIC_AUTH}" > $@; \ + @:$(call check_defined, env) + if [[ "$(env)" != "beta" ]]; then \ + echo "$${$(shell echo $(env) | tr a-z A-Z)_NGINX_BASIC_AUTH}" > $@; \ else \ echo > $@; \ fi From 06675fc60f38656c46f326d4e7cc4574622bc9a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Placzy=C5=84ski?= Date: Tue, 14 May 2024 11:39:21 +0200 Subject: [PATCH 107/125] [#1003] Apply environment variables for basic authentication in GitHub Actions In this commit, the necessary changes have been made in the GitHub Actions workflows to apply the basic authentication environment variables where needed. This update ensures that the correct credentials are utilized for basic authentication in the different environments (beta, dev, staging, test). The workflow files for these environments have been modified to include the specific environment variables related to basic authentication. For instance, in the build-and-deploy-staging.yml file, the environment variable `STAGING_NGINX_BASIC_AUTH` has been introduced to set the basic authentication credentials for the staging environment. --- .github/workflows/build-and-deploy-beta.yml | 2 -- .github/workflows/build-and-deploy-dev.yml | 3 +-- .github/workflows/build-and-deploy-staging.yml | 3 +-- .github/workflows/build-and-deploy-test.yml | 3 +-- 4 files changed, 3 insertions(+), 8 deletions(-) diff --git a/.github/workflows/build-and-deploy-beta.yml b/.github/workflows/build-and-deploy-beta.yml index 4f1647eae..b5e6da758 100644 --- a/.github/workflows/build-and-deploy-beta.yml +++ b/.github/workflows/build-and-deploy-beta.yml @@ -23,7 +23,6 @@ jobs: DBSYNC_POSTGRES_USER: "postgres" GA_CLIENT_EMAIL: ${{ secrets.GA_CLIENT_EMAIL }} GA_PRIVATE_KEY: ${{ secrets.GA_PRIVATE_KEY }} - GOOGLE_APPLICATION_CREDENTIALS: ${{ secrets.GOOGLE_APPLICATION_CREDENTIALS }} GRAFANA_ADMIN_PASSWORD: ${{ secrets.GRAFANA_ADMIN_PASSWORD }} GRAFANA_SLACK_OAUTH_TOKEN: ${{ secrets.GRAFANA_SLACK_OAUTH_TOKEN }} GRAFANA_SLACK_RECIPIENT: ${{ secrets.GRAFANA_SLACK_RECIPIENT }} @@ -32,7 +31,6 @@ jobs: IP_ADDRESS_BYPASSING_BASIC_AUTH2: ${{ secrets.IP_ADDRESS_BYPASSING_BASIC_AUTH2 }} NEXT_PUBLIC_API_URL: "https://participation.sanchogov.tools" NEXT_PUBLIC_GA4_PROPERTY_ID: ${{ secrets.NEXT_PUBLIC_GA4_PROPERTY_ID }} - NGINX_BASIC_AUTH: ${{ secrets.NGINX_BASIC_AUTH }} PIPELINE_URL: https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }} SENTRY_DSN: ${{ secrets.SENTRY_DSN_FRONTEND }} SENTRY_DSN_BACKEND: ${{ secrets.SENTRY_DSN_BACKEND }} diff --git a/.github/workflows/build-and-deploy-dev.yml b/.github/workflows/build-and-deploy-dev.yml index e618b165e..bf11bbb39 100644 --- a/.github/workflows/build-and-deploy-dev.yml +++ b/.github/workflows/build-and-deploy-dev.yml @@ -22,7 +22,6 @@ jobs: DBSYNC_POSTGRES_USER: "postgres" GA_CLIENT_EMAIL: ${{ secrets.GA_CLIENT_EMAIL }} GA_PRIVATE_KEY: ${{ secrets.GA_PRIVATE_KEY }} - GOOGLE_APPLICATION_CREDENTIALS: ${{ secrets.GOOGLE_APPLICATION_CREDENTIALS }} GRAFANA_ADMIN_PASSWORD: ${{ secrets.GRAFANA_ADMIN_PASSWORD }} GRAFANA_SLACK_OAUTH_TOKEN: ${{ secrets.GRAFANA_SLACK_OAUTH_TOKEN }} GRAFANA_SLACK_RECIPIENT: ${{ secrets.GRAFANA_SLACK_RECIPIENT }} @@ -31,7 +30,7 @@ jobs: IP_ADDRESS_BYPASSING_BASIC_AUTH2: ${{ secrets.IP_ADDRESS_BYPASSING_BASIC_AUTH2 }} NEXT_PUBLIC_API_URL: "https://participation.sanchogov.tools" NEXT_PUBLIC_GA4_PROPERTY_ID: ${{ secrets.NEXT_PUBLIC_GA4_PROPERTY_ID }} - NGINX_BASIC_AUTH: ${{ secrets.NGINX_BASIC_AUTH }} + DEV_NGINX_BASIC_AUTH: ${{ secrets.DEV_NGINX_BASIC_AUTH }} PIPELINE_URL: https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }} SENTRY_DSN: ${{ secrets.SENTRY_DSN_FRONTEND }} SENTRY_DSN_BACKEND: ${{ secrets.SENTRY_DSN_BACKEND }} diff --git a/.github/workflows/build-and-deploy-staging.yml b/.github/workflows/build-and-deploy-staging.yml index c47365565..6b00eec0c 100644 --- a/.github/workflows/build-and-deploy-staging.yml +++ b/.github/workflows/build-and-deploy-staging.yml @@ -24,7 +24,6 @@ jobs: DBSYNC_POSTGRES_USER: "postgres" GA_CLIENT_EMAIL: ${{ secrets.GA_CLIENT_EMAIL }} GA_PRIVATE_KEY: ${{ secrets.GA_PRIVATE_KEY }} - GOOGLE_APPLICATION_CREDENTIALS: ${{ secrets.GOOGLE_APPLICATION_CREDENTIALS }} GRAFANA_ADMIN_PASSWORD: ${{ secrets.GRAFANA_ADMIN_PASSWORD }} GRAFANA_SLACK_OAUTH_TOKEN: ${{ secrets.GRAFANA_SLACK_OAUTH_TOKEN }} GRAFANA_SLACK_RECIPIENT: ${{ secrets.GRAFANA_SLACK_RECIPIENT }} @@ -33,7 +32,7 @@ jobs: IP_ADDRESS_BYPASSING_BASIC_AUTH2: ${{ secrets.IP_ADDRESS_BYPASSING_BASIC_AUTH2 }} NEXT_PUBLIC_API_URL: "https://participation.sanchogov.tools" NEXT_PUBLIC_GA4_PROPERTY_ID: ${{ secrets.NEXT_PUBLIC_GA4_PROPERTY_ID }} - NGINX_BASIC_AUTH: ${{ secrets.NGINX_BASIC_AUTH }} + STAGING_NGINX_BASIC_AUTH: ${{ secrets.STAGING_NGINX_BASIC_AUTH }} PIPELINE_URL: https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }} SENTRY_DSN: ${{ secrets.SENTRY_DSN_FRONTEND }} SENTRY_DSN_BACKEND: ${{ secrets.SENTRY_DSN_BACKEND }} diff --git a/.github/workflows/build-and-deploy-test.yml b/.github/workflows/build-and-deploy-test.yml index c5788056f..ef22dd7c1 100644 --- a/.github/workflows/build-and-deploy-test.yml +++ b/.github/workflows/build-and-deploy-test.yml @@ -24,7 +24,6 @@ jobs: DBSYNC_POSTGRES_USER: "postgres" GA_CLIENT_EMAIL: ${{ secrets.GA_CLIENT_EMAIL }} GA_PRIVATE_KEY: ${{ secrets.GA_PRIVATE_KEY }} - GOOGLE_APPLICATION_CREDENTIALS: ${{ secrets.GOOGLE_APPLICATION_CREDENTIALS }} GRAFANA_ADMIN_PASSWORD: ${{ secrets.GRAFANA_ADMIN_PASSWORD }} GRAFANA_SLACK_OAUTH_TOKEN: ${{ secrets.GRAFANA_SLACK_OAUTH_TOKEN }} GRAFANA_SLACK_RECIPIENT: ${{ secrets.GRAFANA_SLACK_RECIPIENT }} @@ -33,7 +32,7 @@ jobs: IP_ADDRESS_BYPASSING_BASIC_AUTH2: ${{ secrets.IP_ADDRESS_BYPASSING_BASIC_AUTH2 }} NEXT_PUBLIC_API_URL: "https://participation.sanchogov.tools" NEXT_PUBLIC_GA4_PROPERTY_ID: ${{ secrets.NEXT_PUBLIC_GA4_PROPERTY_ID }} - NGINX_BASIC_AUTH: ${{ secrets.NGINX_BASIC_AUTH }} + TEST_NGINX_BASIC_AUTH: ${{ secrets.TEST_NGINX_BASIC_AUTH }} PIPELINE_URL: https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }} SENTRY_DSN: ${{ secrets.SENTRY_DSN_FRONTEND }} SENTRY_DSN_BACKEND: ${{ secrets.SENTRY_DSN_BACKEND }} From 350df520423839db8e876b08abace277230b710d Mon Sep 17 00:00:00 2001 From: weronika Date: Tue, 14 May 2024 11:45:15 +0200 Subject: [PATCH 108/125] add conditional for yourselfDRep --- govtool/frontend/src/pages/DRepDirectoryContent.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/govtool/frontend/src/pages/DRepDirectoryContent.tsx b/govtool/frontend/src/pages/DRepDirectoryContent.tsx index d1843e279..b7b342b64 100644 --- a/govtool/frontend/src/pages/DRepDirectoryContent.tsx +++ b/govtool/frontend/src/pages/DRepDirectoryContent.tsx @@ -65,7 +65,7 @@ export const DRepDirectoryContent: FC = ({ const { dRepData: yourselfDRepList } = useGetDRepListInfiniteQuery({ searchPhrase: myDRepId, }); - const yourselfDRep = yourselfDRepList?.[0]; + const yourselfDRep = isConnected ? yourselfDRepList?.[0] : undefined; const { dRepData: dRepList, From 8dfaf813b342bc57224024aec0cdfc39980af4cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Placzy=C5=84ski?= Date: Tue, 14 May 2024 12:20:45 +0200 Subject: [PATCH 109/125] Update backend config with metadata-validation service address MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is a hotfix that solves problem with wrong request configuration to metadata-validation service. Signed-off-by: Paweł Placzyński --- scripts/govtool/config/templates/backend-config.json.tpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/govtool/config/templates/backend-config.json.tpl b/scripts/govtool/config/templates/backend-config.json.tpl index 31a141afd..9ff9f2f11 100644 --- a/scripts/govtool/config/templates/backend-config.json.tpl +++ b/scripts/govtool/config/templates/backend-config.json.tpl @@ -10,6 +10,6 @@ "host" : "0.0.0.0", "cachedurationseconds": 20, "sentrydsn": "", - "metadatavalidationhost": "metadata-validation", + "metadatavalidationhost": "http://metadata-validation", "metadatavalidationport": "3000" } From dd2c5aef66cbbf1423a51a78e9b4bbfbd7ccc6aa Mon Sep 17 00:00:00 2001 From: weronika Date: Tue, 14 May 2024 13:39:24 +0200 Subject: [PATCH 110/125] change condition for more cases --- govtool/frontend/src/pages/DRepDirectoryContent.tsx | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/govtool/frontend/src/pages/DRepDirectoryContent.tsx b/govtool/frontend/src/pages/DRepDirectoryContent.tsx index b7b342b64..c986a402e 100644 --- a/govtool/frontend/src/pages/DRepDirectoryContent.tsx +++ b/govtool/frontend/src/pages/DRepDirectoryContent.tsx @@ -65,7 +65,12 @@ export const DRepDirectoryContent: FC = ({ const { dRepData: yourselfDRepList } = useGetDRepListInfiniteQuery({ searchPhrase: myDRepId, }); - const yourselfDRep = isConnected ? yourselfDRepList?.[0] : undefined; + + const yourselfDRep = + !!isConnected && + (debouncedSearchText === myDRepId || debouncedSearchText === "") + ? yourselfDRepList?.[0] + : undefined; const { dRepData: dRepList, From 7aff6e43f81f964dce318e7b2aa49bcd0e8aebfd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Sza=C5=82owski?= Date: Tue, 14 May 2024 15:14:24 +0200 Subject: [PATCH 111/125] fix: fix test deployment workflow file --- .github/workflows/build-and-deploy-dev.yml | 2 +- .github/workflows/build-and-deploy-test.yml | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build-and-deploy-dev.yml b/.github/workflows/build-and-deploy-dev.yml index bf11bbb39..32edb1af4 100644 --- a/.github/workflows/build-and-deploy-dev.yml +++ b/.github/workflows/build-and-deploy-dev.yml @@ -23,8 +23,8 @@ jobs: GA_CLIENT_EMAIL: ${{ secrets.GA_CLIENT_EMAIL }} GA_PRIVATE_KEY: ${{ secrets.GA_PRIVATE_KEY }} GRAFANA_ADMIN_PASSWORD: ${{ secrets.GRAFANA_ADMIN_PASSWORD }} - GRAFANA_SLACK_OAUTH_TOKEN: ${{ secrets.GRAFANA_SLACK_OAUTH_TOKEN }} GRAFANA_SLACK_RECIPIENT: ${{ secrets.GRAFANA_SLACK_RECIPIENT }} + GRAFANA_SLACK_OAUTH_TOKEN: ${{ secrets.GRAFANA_SLACK_OAUTH_TOKEN }} GTM_ID: ${{ secrets.GTM_ID }} IP_ADDRESS_BYPASSING_BASIC_AUTH1: ${{ secrets.IP_ADDRESS_BYPASSING_BASIC_AUTH1 }} IP_ADDRESS_BYPASSING_BASIC_AUTH2: ${{ secrets.IP_ADDRESS_BYPASSING_BASIC_AUTH2 }} diff --git a/.github/workflows/build-and-deploy-test.yml b/.github/workflows/build-and-deploy-test.yml index 55ade7aea..388b40dd0 100644 --- a/.github/workflows/build-and-deploy-test.yml +++ b/.github/workflows/build-and-deploy-test.yml @@ -23,7 +23,6 @@ jobs: GRAFANA_ADMIN_PASSWORD: ${{ secrets.GRAFANA_ADMIN_PASSWORD }} GRAFANA_SLACK_RECIPIENT: ${{ secrets.GRAFANA_SLACK_RECIPIENT }} GRAFANA_SLACK_OAUTH_TOKEN: ${{ secrets.GRAFANA_SLACK_OAUTH_TOKEN }} - SENTRY_DSN_BACKEND: ${{ secrets.SENTRY_DSN_BACKEND }} GTM_ID: ${{ secrets.GTM_ID }} IP_ADDRESS_BYPASSING_BASIC_AUTH1: ${{ secrets.IP_ADDRESS_BYPASSING_BASIC_AUTH1 }} IP_ADDRESS_BYPASSING_BASIC_AUTH2: ${{ secrets.IP_ADDRESS_BYPASSING_BASIC_AUTH2 }} @@ -32,7 +31,9 @@ jobs: TEST_NGINX_BASIC_AUTH: ${{ secrets.TEST_NGINX_BASIC_AUTH }} PIPELINE_URL: https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }} SENTRY_DSN: ${{ secrets.SENTRY_DSN_FRONTEND }} - PIPELINE_URL: https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }} + SENTRY_DSN_BACKEND: ${{ secrets.SENTRY_DSN_BACKEND }} + SENTRY_IGNORE_API_RESOLUTION_ERROR: "1" + TRAEFIK_LE_EMAIL: "admin+govtool@binarapps.com" USERSNAP_SPACE_API_KEY: ${{ secrets.USERSNAP_SPACE_API_KEY }} steps: - name: Checkout code @@ -57,4 +58,4 @@ jobs: options: | --verbose env: - GOVTOOL_TAG: ${{ github.sha }} \ No newline at end of file + GOVTOOL_TAG: ${{ github.sha }} From 348ece0d3719e61fafdbc920c045c608e32d0b5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Sza=C5=82owski?= Date: Wed, 15 May 2024 10:31:34 +0200 Subject: [PATCH 112/125] [#1028] fix: remove incorrectly appended filter yourself to drep directory --- CHANGELOG.md | 1 + .../src/consts/dRepDirectory/filters.test.ts | 27 +++++++++++++++++++ .../src/consts/dRepDirectory/filters.ts | 11 +++++--- 3 files changed, 35 insertions(+), 4 deletions(-) create mode 100644 govtool/frontend/src/consts/dRepDirectory/filters.test.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index e637a8779..ca70a6183 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -86,6 +86,7 @@ changes. - Fix all the existing eslint errors [Issue 514](https://github.com/IntersectMBO/govtool/issues/514) - Fix all the existing typescript errors [Issue 514](https://github.com/IntersectMBO/govtool/issues/514) - Fix endless spinner on a dashboard [Issue 539](https://github.com/IntersectMBO/govtool/issues/539) +- Remove wrongly appended `Yourself` filter on DRep Directory [Issue 1028](https://github.com/IntersectMBO/govtool/issues/1028) ### Changed diff --git a/govtool/frontend/src/consts/dRepDirectory/filters.test.ts b/govtool/frontend/src/consts/dRepDirectory/filters.test.ts new file mode 100644 index 000000000..a48868c04 --- /dev/null +++ b/govtool/frontend/src/consts/dRepDirectory/filters.test.ts @@ -0,0 +1,27 @@ +import { DREP_DIRECTORY_FILTERS } from "./filters"; + +describe("DREP_DIRECTORY_FILTERS", () => { + it("should exclude 'Yourself' from filters", () => { + // Arrange + const expectedFilters = [ + { + key: "Active", + label: "Active", + }, + { + key: "Inactive", + label: "Inactive", + }, + { + key: "Retired", + label: "Retired", + }, + ]; + + // Act + const actualFilters = DREP_DIRECTORY_FILTERS; + + // Assert + expect(actualFilters).toEqual(expectedFilters); + }); +}); diff --git a/govtool/frontend/src/consts/dRepDirectory/filters.ts b/govtool/frontend/src/consts/dRepDirectory/filters.ts index f6a089f8e..bb1fa6ff5 100644 --- a/govtool/frontend/src/consts/dRepDirectory/filters.ts +++ b/govtool/frontend/src/consts/dRepDirectory/filters.ts @@ -1,6 +1,9 @@ import { DRepStatus } from "@/models"; -export const DREP_DIRECTORY_FILTERS = Object.values(DRepStatus).map((status) => ({ - key: status, - label: status, -})); +export const DREP_DIRECTORY_FILTERS = Object.values(DRepStatus) + // `Yourself` should be excluded from filters + .filter((status) => status !== DRepStatus.Yourself) + .map((status) => ({ + key: status, + label: status, + })); From 0da210949ae59a4c93852fb690306c628b83c8fd Mon Sep 17 00:00:00 2001 From: Jan Jaroszczak Date: Wed, 15 May 2024 13:03:48 +0200 Subject: [PATCH 113/125] [#1031] Update GA links type --- .../molecules/GovernanceActionDetailsCardLinks.tsx | 8 ++++---- .../components/organisms/GovernanceActionDetailsCard.tsx | 2 +- .../organisms/GovernanceActionDetailsCardData.tsx | 2 +- govtool/frontend/src/types/global.d.ts | 6 ++++++ 4 files changed, 12 insertions(+), 6 deletions(-) diff --git a/govtool/frontend/src/components/molecules/GovernanceActionDetailsCardLinks.tsx b/govtool/frontend/src/components/molecules/GovernanceActionDetailsCardLinks.tsx index c362db759..08ed07aa6 100644 --- a/govtool/frontend/src/components/molecules/GovernanceActionDetailsCardLinks.tsx +++ b/govtool/frontend/src/components/molecules/GovernanceActionDetailsCardLinks.tsx @@ -9,7 +9,7 @@ import { LinkWithIcon } from "@molecules"; export const GovernanceActionDetailsCardLinks = ({ links, }: { - links?: string[]; + links?: GovernanceActionLink[]; }) => { const { isMobile } = useScreenDimension(); const { t } = useTranslation(); @@ -43,13 +43,13 @@ export const GovernanceActionDetailsCardLinks = ({ > {links.map((link) => ( { openModal({ type: "externalLink", state: { - externalLink: link, + externalLink: link.uri, }, }); }} diff --git a/govtool/frontend/src/components/organisms/GovernanceActionDetailsCard.tsx b/govtool/frontend/src/components/organisms/GovernanceActionDetailsCard.tsx index 7cc4656ee..9eed968ea 100644 --- a/govtool/frontend/src/components/organisms/GovernanceActionDetailsCard.tsx +++ b/govtool/frontend/src/components/organisms/GovernanceActionDetailsCard.tsx @@ -24,7 +24,7 @@ type GovernanceActionDetailsCardProps = { motivation?: string; rationale?: string; yesVotes: number; - links?: string[]; + links?: GovernanceActionLink[]; govActionId: string; isDataMissing: boolean | MetadataValidationStatus; isDashboard?: boolean; diff --git a/govtool/frontend/src/components/organisms/GovernanceActionDetailsCardData.tsx b/govtool/frontend/src/components/organisms/GovernanceActionDetailsCardData.tsx index 7032ed8c9..51f6e087d 100644 --- a/govtool/frontend/src/components/organisms/GovernanceActionDetailsCardData.tsx +++ b/govtool/frontend/src/components/organisms/GovernanceActionDetailsCardData.tsx @@ -26,7 +26,7 @@ type GovernanceActionDetailsCardDataProps = { isInProgress?: boolean; isOneColumn: boolean; isSubmitted?: boolean; - links?: string[]; + links?: GovernanceActionLink[]; motivation?: string; rationale?: string; title?: string; diff --git a/govtool/frontend/src/types/global.d.ts b/govtool/frontend/src/types/global.d.ts index 6204ffc90..2cd73ebcc 100644 --- a/govtool/frontend/src/types/global.d.ts +++ b/govtool/frontend/src/types/global.d.ts @@ -75,4 +75,10 @@ declare global { type ArrayElement = ArrayType extends readonly (infer ElementType)[] ? ElementType : never; + + type GovernanceActionLink = { + "@type": string; + label: string; + uri: string; + }; } From 4d6ab36a29467e60dbd7ec3ab4c7d51a4c32d5de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Sza=C5=82owski?= Date: Wed, 15 May 2024 14:10:02 +0200 Subject: [PATCH 114/125] Update govtool/frontend/src/components/molecules/GovernanceActionDetailsCardLinks.tsx MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Michał Szałowski --- .../components/molecules/GovernanceActionDetailsCardLinks.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/govtool/frontend/src/components/molecules/GovernanceActionDetailsCardLinks.tsx b/govtool/frontend/src/components/molecules/GovernanceActionDetailsCardLinks.tsx index 08ed07aa6..e3763567e 100644 --- a/govtool/frontend/src/components/molecules/GovernanceActionDetailsCardLinks.tsx +++ b/govtool/frontend/src/components/molecules/GovernanceActionDetailsCardLinks.tsx @@ -44,7 +44,7 @@ export const GovernanceActionDetailsCardLinks = ({ {links.map((link) => ( { openModal({ type: "externalLink", From ad557ddf6ffc61de162f3f54304accee151285de Mon Sep 17 00:00:00 2001 From: Nabin Kawan Date: Wed, 15 May 2024 16:03:40 +0545 Subject: [PATCH 115/125] fix: Delegation timeout --- .../playwright/lib/helpers/transaction.ts | 13 +- .../playwright/lib/lockInterceptor.ts | 8 -- .../playwright/lib/pages/delegationPage.ts | 6 +- .../lib/pages/governanceActionDetailsPage.ts | 36 ++++- .../playwright/lib/transaction.decorator.ts | 12 ++ .../playwright/package-lock.json | 14 +- .../govtool-frontend/playwright/package.json | 2 +- .../playwright/playwright.config.ts | 2 +- .../delegation.delegation.spec.ts | 8 +- .../proposalVisibility.dRep.spec.ts | 131 ++++++++++++++++++ 10 files changed, 204 insertions(+), 28 deletions(-) create mode 100644 tests/govtool-frontend/playwright/lib/transaction.decorator.ts create mode 100644 tests/govtool-frontend/playwright/tests/4-proposal-visibility/proposalVisibility.dRep.spec.ts diff --git a/tests/govtool-frontend/playwright/lib/helpers/transaction.ts b/tests/govtool-frontend/playwright/lib/helpers/transaction.ts index d85dc2efa..bf496ba8f 100644 --- a/tests/govtool-frontend/playwright/lib/helpers/transaction.ts +++ b/tests/govtool-frontend/playwright/lib/helpers/transaction.ts @@ -51,12 +51,23 @@ export async function pollTransaction( } } -export async function waitForTxConfirmation(page: Page) { +export async function waitForTxConfirmation( + page: Page, + triggerCallback?: () => Promise, +) { let transactionHash: string | undefined; const transactionStatusPromise = page.waitForRequest((request) => { return request.url().includes("/transaction/status/"); }); + await triggerCallback?.call(this); + await expect( + page + .getByTestId("alert-warning") + .getByText("Transaction in progress", { exact: false }), + ).toBeVisible({ + timeout: 10000, + }); const url = (await transactionStatusPromise).url(); const regex = /\/transaction\/status\/([^\/]+)$/; const match = url.match(regex); diff --git a/tests/govtool-frontend/playwright/lib/lockInterceptor.ts b/tests/govtool-frontend/playwright/lib/lockInterceptor.ts index a3b13cda7..a749d26c8 100644 --- a/tests/govtool-frontend/playwright/lib/lockInterceptor.ts +++ b/tests/govtool-frontend/playwright/lib/lockInterceptor.ts @@ -10,14 +10,6 @@ export interface LockInterceptorInfo { address: string; } -abstract class BaseLock { - abstract acquireLock(key: string, id?: string): Promise; - - abstract releaseLock(key: string, id?: string): Promise; - - abstract checkLock(key: string): Promise; -} - export class LockInterceptor { private static async acquireLock( address: string, diff --git a/tests/govtool-frontend/playwright/lib/pages/delegationPage.ts b/tests/govtool-frontend/playwright/lib/pages/delegationPage.ts index dc4d6b1ec..b0a818c40 100644 --- a/tests/govtool-frontend/playwright/lib/pages/delegationPage.ts +++ b/tests/govtool-frontend/playwright/lib/pages/delegationPage.ts @@ -1,5 +1,6 @@ -import { Page } from "@playwright/test"; +import { Page, expect } from "@playwright/test"; import environments from "lib/constants/environments"; +import { withTxConfirmation } from "lib/transaction.decorator"; export default class DelegationPage { readonly otherOptionsBtn = this.page.getByText("Other options"); @@ -37,8 +38,11 @@ export default class DelegationPage { ); } + @withTxConfirmation async delegateToDRep(dRepId: string) { await this.searchInput.fill(dRepId); + const delegateBtn = this.page.getByTestId(`${dRepId}-delegate-button`); + await expect(delegateBtn).toBeVisible(); await this.page.getByTestId(`${dRepId}-delegate-button`).click(); } diff --git a/tests/govtool-frontend/playwright/lib/pages/governanceActionDetailsPage.ts b/tests/govtool-frontend/playwright/lib/pages/governanceActionDetailsPage.ts index 89877b9c4..843a242c9 100644 --- a/tests/govtool-frontend/playwright/lib/pages/governanceActionDetailsPage.ts +++ b/tests/govtool-frontend/playwright/lib/pages/governanceActionDetailsPage.ts @@ -1,5 +1,8 @@ import environments from "@constants/environments"; -import { Page } from "@playwright/test"; +import { downloadMetadata } from "@helpers/metadata"; +import { Download, Page } from "@playwright/test"; +import metadataBucketService from "@services/metadataBucketService"; +import { withTxConfirmation } from "lib/transaction.decorator"; export default class GovernanceActionDetailsPage { readonly voteBtn = this.page.getByTestId("vote-button"); @@ -8,7 +11,7 @@ export default class GovernanceActionDetailsPage { readonly noVoteRadio = this.page.getByTestId("no-radio"); readonly abstainRadio = this.page.getByTestId("abstain-radio"); readonly governanceActionType = this.page.getByText( - "Governance Action Type:" + "Governance Action Type:", ); readonly submittedDate = this.page.getByTestId("submission-date"); readonly expiryDate = this.page.getByTestId("expiry-date"); @@ -19,7 +22,7 @@ export default class GovernanceActionDetailsPage { name: "Provide context about your", }); // BUG testId readonly viewOtherDetailsLink = this.page.getByTestId( - "view-other-details-button" + "view-other-details-button", ); readonly continueModalBtn = this.page.getByTestId("continue-modal-button"); @@ -37,12 +40,35 @@ export default class GovernanceActionDetailsPage { async goto(proposalId: string) { await this.page.goto( - `${environments.frontendUrl}/governance_actions/${proposalId}` + `${environments.frontendUrl}/governance_actions/${proposalId}`, ); } - async vote() { + @withTxConfirmation + async vote(context?: string) { await this.yesVoteRadio.click(); + + if (context) { + await this.contextBtn.click(); + await this.contextInput.fill(context); + await this.confirmModalBtn.click(); + await this.page.getByRole("checkbox").click(); + await this.confirmModalBtn.click(); + + this.page + .getByRole("button", { name: "download Vote_Context.jsonld" }) + .click(); + const voteMetadata = await this.downloadVoteMetadata(); + const url = await metadataBucketService.uploadMetadata( + voteMetadata.name, + voteMetadata.data, + ); + + await this.page.getByPlaceholder("URL").fill(url); + await this.confirmModalBtn.click(); + await this.page.getByTestId("go-to-vote-modal-button").click(); + } + await this.voteBtn.click(); } diff --git a/tests/govtool-frontend/playwright/lib/transaction.decorator.ts b/tests/govtool-frontend/playwright/lib/transaction.decorator.ts new file mode 100644 index 000000000..26074bb2d --- /dev/null +++ b/tests/govtool-frontend/playwright/lib/transaction.decorator.ts @@ -0,0 +1,12 @@ +import { waitForTxConfirmation } from "@helpers/transaction"; + +export function withTxConfirmation(value, { kind }) { + if (kind !== "method") return; + + return async function (...args: any) { + await waitForTxConfirmation( + this.page, + async () => await value.apply(this, args), + ); + }; +} diff --git a/tests/govtool-frontend/playwright/package-lock.json b/tests/govtool-frontend/playwright/package-lock.json index f229e2e72..6fed6820e 100644 --- a/tests/govtool-frontend/playwright/package-lock.json +++ b/tests/govtool-frontend/playwright/package-lock.json @@ -9,7 +9,7 @@ "version": "1.0.0", "license": "MIT", "dependencies": { - "@cardanoapi/cardano-test-wallet": "^1.0.2", + "@cardanoapi/cardano-test-wallet": "^1.1.1", "@faker-js/faker": "^8.4.1", "@noble/curves": "^1.3.0", "@noble/ed25519": "^2.0.0", @@ -86,9 +86,9 @@ } }, "node_modules/@cardanoapi/cardano-test-wallet": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@cardanoapi/cardano-test-wallet/-/cardano-test-wallet-1.0.2.tgz", - "integrity": "sha512-ABOOSoB0DUggcIwl6nj1v4/IhzFKPPV6krGLAv9RRmX5trkiOBLqGuSNrOlFU+7XELJzagDDwYS1ykhyuVD/HA==" + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@cardanoapi/cardano-test-wallet/-/cardano-test-wallet-1.1.1.tgz", + "integrity": "sha512-bNseN0PY0vQ7o7FPKRQW3ZGhUgjQ9bavbbvUiIJ/oTTCwItAq1ds7CGRuVH4hDr8kPSUB76pHQMk8QvEXdMs5A==" }, "node_modules/@cbor-extract/cbor-extract-linux-x64": { "version": "2.2.0", @@ -3206,9 +3206,9 @@ "dev": true }, "@cardanoapi/cardano-test-wallet": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@cardanoapi/cardano-test-wallet/-/cardano-test-wallet-1.0.2.tgz", - "integrity": "sha512-ABOOSoB0DUggcIwl6nj1v4/IhzFKPPV6krGLAv9RRmX5trkiOBLqGuSNrOlFU+7XELJzagDDwYS1ykhyuVD/HA==" + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@cardanoapi/cardano-test-wallet/-/cardano-test-wallet-1.1.1.tgz", + "integrity": "sha512-bNseN0PY0vQ7o7FPKRQW3ZGhUgjQ9bavbbvUiIJ/oTTCwItAq1ds7CGRuVH4hDr8kPSUB76pHQMk8QvEXdMs5A==" }, "@cbor-extract/cbor-extract-linux-x64": { "version": "2.2.0", diff --git a/tests/govtool-frontend/playwright/package.json b/tests/govtool-frontend/playwright/package.json index 3cb14402e..23e5ab032 100644 --- a/tests/govtool-frontend/playwright/package.json +++ b/tests/govtool-frontend/playwright/package.json @@ -26,7 +26,7 @@ "format": "prettier . --write" }, "dependencies": { - "@cardanoapi/cardano-test-wallet": "^1.0.2", + "@cardanoapi/cardano-test-wallet": "^1.1.1", "@faker-js/faker": "^8.4.1", "@noble/curves": "^1.3.0", "@noble/ed25519": "^2.0.0", diff --git a/tests/govtool-frontend/playwright/playwright.config.ts b/tests/govtool-frontend/playwright/playwright.config.ts index a2adcef75..43a5cc701 100644 --- a/tests/govtool-frontend/playwright/playwright.config.ts +++ b/tests/govtool-frontend/playwright/playwright.config.ts @@ -90,7 +90,7 @@ export default defineConfig({ use: { ...devices["Desktop Chrome"] }, testMatch: "**/*.delegation.spec.ts", dependencies: process.env.CI ? ["auth setup", "dRep setup"] : [], - teardown: "cleanup delegation", + teardown: process.env.CI && "cleanup delegation", }, { name: "independent (desktop)", diff --git a/tests/govtool-frontend/playwright/tests/2-delegation/delegation.delegation.spec.ts b/tests/govtool-frontend/playwright/tests/2-delegation/delegation.delegation.spec.ts index 92811984f..82c008d20 100644 --- a/tests/govtool-frontend/playwright/tests/2-delegation/delegation.delegation.spec.ts +++ b/tests/govtool-frontend/playwright/tests/2-delegation/delegation.delegation.spec.ts @@ -27,8 +27,9 @@ test.describe("Delegate to others", () => { const delegationPage = new DelegationPage(page); await delegationPage.goto(); - delegationPage.delegateToDRep(dRep01Wallet.dRepId); - await waitForTxConfirmation(page); + await delegationPage.delegateToDRep( + "drep1qzw234c0ly8csamxf8hrhfahvzwpllh2ckuzzvl38d22wwxxquu", + ); page.goto("/"); await expect(page.getByTestId("delegated-dRep-id")).toHaveText( @@ -81,8 +82,7 @@ test.describe("Change Delegation", () => { }) => { const delegationPage = new DelegationPage(page); await delegationPage.goto(); - delegationPage.delegateToDRep(dRep01Wallet.dRepId); - await waitForTxConfirmation(page); + await delegationPage.delegateToDRep(dRep01Wallet.dRepId); // await delegationPage.goto("/"); // await adaHolderPage.getByTestId("change-dRep-button").click(); diff --git a/tests/govtool-frontend/playwright/tests/4-proposal-visibility/proposalVisibility.dRep.spec.ts b/tests/govtool-frontend/playwright/tests/4-proposal-visibility/proposalVisibility.dRep.spec.ts new file mode 100644 index 000000000..e9b680c1f --- /dev/null +++ b/tests/govtool-frontend/playwright/tests/4-proposal-visibility/proposalVisibility.dRep.spec.ts @@ -0,0 +1,131 @@ +import environments from "@constants/environments"; +import { dRep01Wallet } from "@constants/staticWallets"; +import { createTempDRepAuth } from "@datafactory/createAuth"; +import { faker } from "@faker-js/faker"; +import { test } from "@fixtures/walletExtension"; +import { lovelaceToAda } from "@helpers/cardano"; +import convertBufferToHex from "@helpers/convertBufferToHex"; +import { ShelleyWallet } from "@helpers/crypto"; +import { createNewPageWithWallet } from "@helpers/page"; +import { pollTransaction } from "@helpers/transaction"; +import GovernanceActionsPage from "@pages/governanceActionsPage"; +import { Page, expect } from "@playwright/test"; +import kuberService from "@services/kuberService"; +import { FilterOption, IProposal } from "@types"; + +test.describe("Logged in DRep", () => { + test.use({ storageState: ".auth/dRep01.json", wallet: dRep01Wallet }); + + test("4E. Should display DRep's voting power in governance actions page", async ({ + page, + }) => { + const votingPowerPromise = page.waitForResponse("**/get-voting-power/**"); + const governanceActionsPage = new GovernanceActionsPage(page); + await governanceActionsPage.goto(); + + const res = await votingPowerPromise; + const votingPower = await res.json(); + + await expect( + page.getByText(`₳ ${lovelaceToAda(votingPower)}`), + ).toBeVisible(); + }); + + test("4F. Should Disable DRep functionality upon wallet disconnection on governance page", async ({ + page, + }) => { + const governanceActionsPage = new GovernanceActionsPage(page); + await governanceActionsPage.goto(); + + await page.getByTestId("disconnect-button").click(); + + const govActionDetailsPage = + await governanceActionsPage.viewFirstProposal(); + await expect(govActionDetailsPage.voteBtn).not.toBeVisible(); + }); + + test("4G. Should display correct vote counts on governance details page for DRep", async ({ + page, + }) => { + const responsesPromise = Object.keys(FilterOption).map((filterKey) => + page.waitForResponse((response) => + response.url().includes(`&type[]=${FilterOption[filterKey]}`), + ), + ); + + const governanceActionsPage = new GovernanceActionsPage(page); + await governanceActionsPage.goto(); + const responses = await Promise.all(responsesPromise); + const proposals: IProposal[] = ( + await Promise.all( + responses.map(async (response) => { + const data = await response.json(); + return data.elements; + }), + ) + ).flat(); + + expect(proposals.length, "No proposals found!").toBeGreaterThan(0); + + const proposalToCheck = proposals[0]; + const govActionDetailsPage = + await governanceActionsPage.viewProposal(proposalToCheck); + await govActionDetailsPage.showVotesBtn.click(); + + await expect( + page + .getByText("yes₳") + .getByText(`₳ ${lovelaceToAda(proposalToCheck.yesVotes)}`), + ).toBeVisible(); + await expect( + page + .getByText("abstain₳") + .getByText(`₳ ${lovelaceToAda(proposalToCheck.abstainVotes)}`), + ).toBeVisible(); + await expect( + page + .getByText("no₳") + .getByText(`₳ ${lovelaceToAda(proposalToCheck.noVotes)}`), + ).toBeVisible(); + }); +}); + +test.describe("Temporary DReps", async () => { + let dRepPage: Page; + + test.beforeEach(async ({ page, browser }, testInfo) => { + test.setTimeout(testInfo.timeout + 2 * environments.txTimeOut); + + const wallet = await ShelleyWallet.generate(); + const registrationRes = await kuberService.dRepRegistration( + convertBufferToHex(wallet.stakeKey.private), + convertBufferToHex(wallet.stakeKey.pkh), + ); + await pollTransaction(registrationRes.txId, registrationRes.lockInfo); + + const res = await kuberService.transferADA( + [wallet.addressBech32(environments.networkId)], + 40, + ); + await pollTransaction(res.txId, registrationRes.lockInfo); + + const tempDRepAuth = await createTempDRepAuth(page, wallet); + + dRepPage = await createNewPageWithWallet(browser, { + storageState: tempDRepAuth, + wallet, + enableStakeSigning: true, + }); + }); + + test("4J. Should include metadata anchor in the vote transaction", async () => { + const govActionsPage = new GovernanceActionsPage(dRepPage); + await govActionsPage.goto(); + + const govActionDetailsPage = await govActionsPage.viewFirstProposal(); + await govActionDetailsPage.vote(faker.lorem.sentence(200)); + await govActionsPage.votedTab.click(); + await govActionsPage.viewFirstVotedProposal(); + expect(false, "No vote context displayed").toBe(true); + }); +}); From b0944b68c311ea8d7c5a5e3877f70e1715bb8160 Mon Sep 17 00:00:00 2001 From: Nabin Kawan Date: Wed, 15 May 2024 12:03:13 +0545 Subject: [PATCH 116/125] fix: prettier formatting --- .../playwright/lib/datafactory/createAuth.ts | 2 +- .../playwright/lib/fixtures/createWallet.ts | 2 +- .../playwright/lib/fixtures/importWallet.ts | 2 +- .../playwright/lib/fixtures/loadExtension.ts | 4 +- .../playwright/lib/helpers/page.ts | 2 +- .../playwright/lib/helpers/setupWallets.ts | 2 +- .../playwright/lib/helpers/transaction.ts | 8 +-- .../playwright/lib/lockInterceptor.ts | 20 +++--- .../lib/pages/dRepRegistrationPage.ts | 23 +++++-- .../playwright/lib/pages/delegationPage.ts | 12 ++-- .../lib/pages/governanceActionsPage.ts | 34 +++++----- .../playwright/lib/pages/loginPage.ts | 2 +- .../playwright/lib/services/faucetService.ts | 4 +- .../playwright/lib/services/kuberService.ts | 30 ++++----- .../1-wallet-connect/walletConnect.spec.ts | 2 +- .../delegation.delegation.spec.ts | 6 +- .../2-delegation/delegation.loggedin.spec.ts | 2 +- .../dRepRegistration.dRep.spec.ts | 50 ++++++++++++--- .../proposalVisibility.loggedin.spec.ts | 8 +-- .../proposalFunctionality.dRep.spec.ts | 62 ++++++++++++++++--- .../6-miscellaneous/miscellaneous.spec.ts | 2 +- .../playwright/tests/dRep.setup.ts | 2 +- .../playwright/tests/delegation.teardown.ts | 2 +- .../playwright/tests/wallet.bootstrap.ts | 4 +- 24 files changed, 191 insertions(+), 96 deletions(-) diff --git a/tests/govtool-frontend/playwright/lib/datafactory/createAuth.ts b/tests/govtool-frontend/playwright/lib/datafactory/createAuth.ts index 2525ed5dc..05da4e0e5 100644 --- a/tests/govtool-frontend/playwright/lib/datafactory/createAuth.ts +++ b/tests/govtool-frontend/playwright/lib/datafactory/createAuth.ts @@ -22,7 +22,7 @@ export async function createTempDRepAuth(page: Page, wallet: ShelleyWallet) { export async function createTempAdaHolderAuth( page: Page, - wallet: ShelleyWallet + wallet: ShelleyWallet, ) { await importWallet(page, wallet.json()); diff --git a/tests/govtool-frontend/playwright/lib/fixtures/createWallet.ts b/tests/govtool-frontend/playwright/lib/fixtures/createWallet.ts index 0ab7f1c04..3d6973292 100644 --- a/tests/govtool-frontend/playwright/lib/fixtures/createWallet.ts +++ b/tests/govtool-frontend/playwright/lib/fixtures/createWallet.ts @@ -7,7 +7,7 @@ import { Page } from "@playwright/test"; export default async function createWallet( page: Page, - config?: CardanoTestWalletConfig + config?: CardanoTestWalletConfig, ) { const wallet = (await ShelleyWallet.generate()).json(); diff --git a/tests/govtool-frontend/playwright/lib/fixtures/importWallet.ts b/tests/govtool-frontend/playwright/lib/fixtures/importWallet.ts index d825f8cf9..d04a58a71 100644 --- a/tests/govtool-frontend/playwright/lib/fixtures/importWallet.ts +++ b/tests/govtool-frontend/playwright/lib/fixtures/importWallet.ts @@ -4,7 +4,7 @@ import { StaticWallet } from "@types"; export async function importWallet( page: Page, - wallet: StaticWallet | CardanoTestWallet + wallet: StaticWallet | CardanoTestWallet, ) { await page.addInitScript((wallet) => { // @ts-ignore diff --git a/tests/govtool-frontend/playwright/lib/fixtures/loadExtension.ts b/tests/govtool-frontend/playwright/lib/fixtures/loadExtension.ts index 44cea5367..5634fa3a3 100644 --- a/tests/govtool-frontend/playwright/lib/fixtures/loadExtension.ts +++ b/tests/govtool-frontend/playwright/lib/fixtures/loadExtension.ts @@ -6,11 +6,11 @@ import path = require("path"); export default async function loadDemosExtension( page: Page, - enableStakeSigning = false + enableStakeSigning = false, ) { const demosBundleScriptPath = path.resolve( __dirname, - "../../node_modules/@cardanoapi/cardano-test-wallet/script.js" + "../../node_modules/@cardanoapi/cardano-test-wallet/script.js", ); let walletConfig: CardanoTestWalletConfig = { enableStakeSigning, diff --git a/tests/govtool-frontend/playwright/lib/helpers/page.ts b/tests/govtool-frontend/playwright/lib/helpers/page.ts index 7a20d6d80..8ab66186e 100644 --- a/tests/govtool-frontend/playwright/lib/helpers/page.ts +++ b/tests/govtool-frontend/playwright/lib/helpers/page.ts @@ -11,7 +11,7 @@ interface BrowserConfig { export async function createNewPageWithWallet( browser: Browser, - { storageState, wallet, enableStakeSigning }: BrowserConfig + { storageState, wallet, enableStakeSigning }: BrowserConfig, ): Promise { const context = await browser.newContext({ storageState: storageState, diff --git a/tests/govtool-frontend/playwright/lib/helpers/setupWallets.ts b/tests/govtool-frontend/playwright/lib/helpers/setupWallets.ts index b12684b3b..ad64c4c85 100644 --- a/tests/govtool-frontend/playwright/lib/helpers/setupWallets.ts +++ b/tests/govtool-frontend/playwright/lib/helpers/setupWallets.ts @@ -15,7 +15,7 @@ export default async function setupWallets(wallets: ShelleyWallet[]) { const { txId, address } = await kuberService.initializeWallets( faucetWallet.address, signingKey, - wallets + wallets, ); await pollTransaction(txId, address); diff --git a/tests/govtool-frontend/playwright/lib/helpers/transaction.ts b/tests/govtool-frontend/playwright/lib/helpers/transaction.ts index bf496ba8f..5d455dd6f 100644 --- a/tests/govtool-frontend/playwright/lib/helpers/transaction.ts +++ b/tests/govtool-frontend/playwright/lib/helpers/transaction.ts @@ -10,7 +10,7 @@ import { Logger } from "../../../cypress/lib/logger/logger"; */ export async function pollTransaction( txHash: string, - lockInfo?: LockInterceptorInfo + lockInfo?: LockInterceptorInfo, ) { try { Logger.info(`Waiting for tx completion: ${txHash}`); @@ -23,7 +23,7 @@ export async function pollTransaction( }, { timeout: environments.txTimeOut, - } + }, ) .toBeGreaterThan(0); @@ -34,7 +34,7 @@ export async function pollTransaction( await LockInterceptor.releaseLockForAddress( lockInfo.address, lockInfo.lockId, - `Task completed for:${lockInfo.lockId}` + `Task completed for:${lockInfo.lockId}`, ); } catch (err) { if (lockInfo) { @@ -43,7 +43,7 @@ export async function pollTransaction( await LockInterceptor.releaseLockForAddress( lockInfo.address, lockInfo.lockId, - `Task failure: \n${JSON.stringify(errorMessage)}` + `Task failure: \n${JSON.stringify(errorMessage)}`, ); } diff --git a/tests/govtool-frontend/playwright/lib/lockInterceptor.ts b/tests/govtool-frontend/playwright/lib/lockInterceptor.ts index a749d26c8..6e56e237f 100644 --- a/tests/govtool-frontend/playwright/lib/lockInterceptor.ts +++ b/tests/govtool-frontend/playwright/lib/lockInterceptor.ts @@ -13,13 +13,13 @@ export interface LockInterceptorInfo { export class LockInterceptor { private static async acquireLock( address: string, - lockId: string + lockId: string, ): Promise { const lockFilePath = path.resolve(__dirname, `../.lock-pool/${address}`); try { await log( - `Initiator: ${address} \n---------------------> acquiring lock for:${lockId}` + `Initiator: ${address} \n---------------------> acquiring lock for:${lockId}`, ); await new Promise((resolve, reject) => { lockfile.lock(lockFilePath, (err) => { @@ -31,7 +31,7 @@ export class LockInterceptor { }); }); await log( - `Initiator: ${address} \n---------------------> acquired lock for:${lockId}` + `Initiator: ${address} \n---------------------> acquired lock for:${lockId}`, ); } catch (err) { throw err; @@ -40,13 +40,13 @@ export class LockInterceptor { private static async releaseLock( address: string, - lockId: string + lockId: string, ): Promise { const lockFilePath = path.resolve(__dirname, `../.lock-pool/${address}`); try { await log( - `Initiator: ${address} \n---------------------> releasing lock for:${lockId}` + `Initiator: ${address} \n---------------------> releasing lock for:${lockId}`, ); await new Promise((resolve, reject) => { lockfile.unlock(lockFilePath, async (err) => { @@ -58,7 +58,7 @@ export class LockInterceptor { }); }); await log( - `Initiator: ${address} \n---------------------> released lock for:${lockId}\n` + `Initiator: ${address} \n---------------------> released lock for:${lockId}\n`, ); } catch (err) { throw err; @@ -67,13 +67,13 @@ export class LockInterceptor { private static async waitForReleaseLock( address: string, - lockId: string + lockId: string, ): Promise { const pollInterval = 4000; // 4 secs try { await log( - `Initiator: ${address} \n ---------------------> waiting lock for:${lockId}` + `Initiator: ${address} \n ---------------------> waiting lock for:${lockId}`, ); return new Promise((resolve, reject) => { const pollFn = () => { @@ -100,7 +100,7 @@ export class LockInterceptor { address: string, callbackFn: () => Promise, lockId: string, - provider: "local" | "server" = "local" + provider: "local" | "server" = "local", ): Promise { while (true) { const isAddressLocked = checkAddressLock(address); @@ -134,7 +134,7 @@ export class LockInterceptor { static async releaseLockForAddress( address: string, lockId: string, - message?: string + message?: string, ) { try { message && (await log(message)); diff --git a/tests/govtool-frontend/playwright/lib/pages/dRepRegistrationPage.ts b/tests/govtool-frontend/playwright/lib/pages/dRepRegistrationPage.ts index 4925124d7..766c95534 100644 --- a/tests/govtool-frontend/playwright/lib/pages/dRepRegistrationPage.ts +++ b/tests/govtool-frontend/playwright/lib/pages/dRepRegistrationPage.ts @@ -1,4 +1,6 @@ -import { Page } from "@playwright/test"; +import { downloadMetadata } from "@helpers/metadata"; +import { Download, Page } from "@playwright/test"; +import metadataBucketService from "@services/metadataBucketService"; import { IDRepInfo } from "@types"; import environments from "lib/constants/environments"; @@ -7,7 +9,7 @@ export default class DRepRegistrationPage { readonly skipBtn = this.page.getByTestId("skip-button"); readonly confirmBtn = this.page.getByTestId("confirm-modal-button"); readonly registrationSuccessModal = this.page.getByTestId( - "governance-action-submitted-modal" + "governance-action-submitted-modal", ); readonly continueBtn = this.page.getByTestId("retire-button"); // BUG testId -> continue-button readonly addLinkBtn = this.page.getByRole("button", { name: "+ Add link" }); // BUG: testId -> add-link-button @@ -40,13 +42,24 @@ export default class DRepRegistrationPage { } } + this.page + .getByRole("button", { name: "download Vote_Context.jsonld" }) + .click(); + const dRepMetadata = await this.downloadVoteMetadata(); + const url = await metadataBucketService.uploadMetadata( + dRepMetadata.name, + dRepMetadata.data, + ); await this.continueBtn.click(); // BUG: testId -> submit-button await this.page.getByRole("checkbox").click(); await this.continueBtn.click(); // BUG: testId -> submit-button - await this.page - .getByPlaceholder("URL") - .fill(`${environments.metadataBucketUrl}/Test_dRep`); + await this.page.getByPlaceholder("URL").fill(url); await this.continueBtn.click(); } + + async downloadVoteMetadata() { + const download: Download = await this.page.waitForEvent("download"); + return downloadMetadata(download); + } } diff --git a/tests/govtool-frontend/playwright/lib/pages/delegationPage.ts b/tests/govtool-frontend/playwright/lib/pages/delegationPage.ts index b0a818c40..50a0f8f1e 100644 --- a/tests/govtool-frontend/playwright/lib/pages/delegationPage.ts +++ b/tests/govtool-frontend/playwright/lib/pages/delegationPage.ts @@ -19,22 +19,22 @@ export default class DelegationPage { .filter({ hasText: "Signal No Confidence on Every" }) .nth(2); // BUG: testId -> signal-no-confidence-card readonly abstainDelegationCard = this.page.getByText( - "Abstain from Every VoteSelect this to vote ABSTAIN to every vote.Voting Power₳" - );// BUG: testId -> abstain-delegation-card + "Abstain from Every VoteSelect this to vote ABSTAIN to every vote.Voting Power₳", + ); // BUG: testId -> abstain-delegation-card readonly delegationErrorModal = this.page.getByTestId( - "delegation-transaction-error-modal" + "delegation-transaction-error-modal", ); readonly delegateBtns = this.page.locator( - '[data-testid$="-delegate-button"]' - ); + '[data-testid$="-delegate-button"]', + ); constructor(private readonly page: Page) {} async goto() { await this.page.goto( - `${environments.frontendUrl}/connected/dRep_directory` + `${environments.frontendUrl}/connected/dRep_directory`, ); } diff --git a/tests/govtool-frontend/playwright/lib/pages/governanceActionsPage.ts b/tests/govtool-frontend/playwright/lib/pages/governanceActionsPage.ts index a74a9c8d1..03cde5992 100644 --- a/tests/govtool-frontend/playwright/lib/pages/governanceActionsPage.ts +++ b/tests/govtool-frontend/playwright/lib/pages/governanceActionsPage.ts @@ -26,7 +26,7 @@ export default class GovernanceActionsPage { } async viewProposal( - proposal: IProposal + proposal: IProposal, ): Promise { const proposalId = `govaction-${proposal.txHash}#${proposal.index}-view-detail`; await this.page.getByTestId(proposalId).click(); @@ -51,7 +51,7 @@ export default class GovernanceActionsPage { } async viewVotedProposal( - proposal: IProposal + proposal: IProposal, ): Promise { const proposalId = `govaction-${proposal.txHash}#${proposal.index}-change-your-vote`; await this.page.getByTestId(proposalId).click(); @@ -73,19 +73,21 @@ export default class GovernanceActionsPage { } } + async getAllProposals() { + return this.page.locator('[data-test-id$="-card"]').all(); + } + async validateFilters(filters: string[]) { - const proposalCards = await this.page - .locator('[data-test-id$="-card"]') - .all(); + const proposalCards = await this.getAllProposals(); for (const proposalCard of proposalCards) { const hasFilter = await this._validateFiltersInProposalCard( proposalCard, - filters + filters, ); expect( hasFilter, - "A proposal card does not contain any of the filters" + "A proposal card does not contain any of the filters", ).toBe(true); } } @@ -97,21 +99,21 @@ export default class GovernanceActionsPage { async validateSort( sortOption: string, validationFn: (p1: IProposal, p2: IProposal) => boolean, - filterKeys = Object.keys(FilterOption) + filterKeys = Object.keys(FilterOption), ) { const responses = await Promise.all( filterKeys.map((filterKey) => this.page.waitForResponse((response) => response .url() - .includes(`&type[]=${FilterOption[filterKey]}&sort=${sortOption}`) - ) - ) + .includes(`&type[]=${FilterOption[filterKey]}&sort=${sortOption}`), + ), + ), ); const proposalData = await Promise.all( responses.map(async (response) => { return await response.json(); - }) + }), ); expect(proposalData.length, "No proposals to sort").toBeGreaterThan(0); @@ -129,8 +131,8 @@ export default class GovernanceActionsPage { // Frontend validation const proposalCards = await Promise.all( filterKeys.map((key) => - this.page.getByTestId(`govaction-${key}-card`).allInnerTexts() - ) + this.page.getByTestId(`govaction-${key}-card`).allInnerTexts(), + ), ); for (let dIdx = 0; dIdx <= proposalData.length - 1; dIdx++) { @@ -138,7 +140,7 @@ export default class GovernanceActionsPage { for (let i = 0; i <= proposals.length - 1; i++) { expect( proposalCards[dIdx][i].includes(proposals[i].txHash), - "Frontend validation failed" + "Frontend validation failed", ).toBe(true); } } @@ -146,7 +148,7 @@ export default class GovernanceActionsPage { async _validateFiltersInProposalCard( proposalCard: Locator, - filters: string[] + filters: string[], ): Promise { for (const filter of filters) { try { diff --git a/tests/govtool-frontend/playwright/lib/pages/loginPage.ts b/tests/govtool-frontend/playwright/lib/pages/loginPage.ts index 964b14ff8..1eaabc96f 100644 --- a/tests/govtool-frontend/playwright/lib/pages/loginPage.ts +++ b/tests/govtool-frontend/playwright/lib/pages/loginPage.ts @@ -47,7 +47,7 @@ export default class LoginPage { } return { stakeKeys, rewardAddresses }; - } + }, ); // Handle multiple stake keys diff --git a/tests/govtool-frontend/playwright/lib/services/faucetService.ts b/tests/govtool-frontend/playwright/lib/services/faucetService.ts index a2f9971e3..446ab78eb 100644 --- a/tests/govtool-frontend/playwright/lib/services/faucetService.ts +++ b/tests/govtool-frontend/playwright/lib/services/faucetService.ts @@ -10,11 +10,11 @@ interface IFaucetResponse { } export const loadAmountFromFaucet = async ( - walletAddress: string + walletAddress: string, ): Promise => { try { const res = await fetchClient( - `/send-money?type=default&action=funds&address=${walletAddress}&poolid=undefined&api_key=${environments.faucet.apiKey}` + `/send-money?type=default&action=funds&address=${walletAddress}&poolid=undefined&api_key=${environments.faucet.apiKey}`, ); const responseBody = await res.json(); // console.debug(`faucet response: ${JSON.stringify(responseBody)}`); diff --git a/tests/govtool-frontend/playwright/lib/services/kuberService.ts b/tests/govtool-frontend/playwright/lib/services/kuberService.ts index 65190100e..a1cdaea6d 100644 --- a/tests/govtool-frontend/playwright/lib/services/kuberService.ts +++ b/tests/govtool-frontend/playwright/lib/services/kuberService.ts @@ -77,7 +77,7 @@ class Kuber { const signedTx = this.signTx(tx); const signedTxBody = Uint8Array.from(cborxEncoder.encode(tx)); const lockId = Buffer.from( - blake.blake2b(signedTxBody, undefined, 32) + blake.blake2b(signedTxBody, undefined, 32), ).toString("hex"); const submitTxCallback = async () => { return this.submitTx(signedTx, lockId); @@ -87,18 +87,18 @@ class Kuber { async submitTx(signedTx: any, lockId?: string) { Logger.info( - `Submitting tx: ${JSON.stringify({ lock_id: lockId, tx: signedTx })}` + `Submitting tx: ${JSON.stringify({ lock_id: lockId, tx: signedTx })}`, ); const res = (await callKuber( `/api/${this.version}/tx?submit=true`, "POST", - JSON.stringify(signedTx) + JSON.stringify(signedTx), )) as any; let decodedTx = cborxDecoder.decode(Buffer.from(res.cborHex, "hex")); const submittedTxBody = Uint8Array.from(cborxEncoder.encode(decodedTx[0])); const submittedTxHash = Buffer.from( - blake.blake2b(submittedTxBody, undefined, 32) + blake.blake2b(submittedTxBody, undefined, 32), ).toString("hex"); Logger.success(`Tx submitted: ${submittedTxHash}`); @@ -113,7 +113,7 @@ const kuberService = { initializeWallets: ( senderAddress: string, signingKey: string, - wallets: ShelleyWallet[] + wallets: ShelleyWallet[], ) => { const kuber = new Kuber(senderAddress, signingKey); const outputs = []; @@ -134,8 +134,8 @@ const kuberService = { certificates.push( Kuber.generateCert( "registerstake", - convertBufferToHex(wallet.stakeKey.pkh) - ) + convertBufferToHex(wallet.stakeKey.pkh), + ), ); } return kuber.signAndSubmitTx({ @@ -195,7 +195,7 @@ const kuberService = { addr: string, signingKey: string, stakePrivateKey: string, - pkh: string + pkh: string, ) => { const kuber = new Kuber(addr, signingKey); const selections = [ @@ -218,7 +218,7 @@ const kuberService = { signingKey: string, stakePrivateKey: string, pkh: string, - dRep: string | "abstain" | "noconfidence" + dRep: string | "abstain" | "noconfidence", ) => { const kuber = new Kuber(addr, signingKey); const selections = [ @@ -245,7 +245,7 @@ const kuberService = { const utxos: any[] = await callKuber(`/api/v3/utxo?address=${addr}`); const balanceInLovelace = utxos.reduce( (acc, utxo) => acc + utxo.value.lovelace, - 0 + 0, ); return balanceInLovelace / 1000000; }, @@ -254,7 +254,7 @@ const kuberService = { stakePrivateKey: string, pkh: string, signingKey: string, - addr: string + addr: string, ) => { const kuber = new Kuber(addr, signingKey); const selections = [ @@ -315,7 +315,7 @@ const kuberService = { signingKey: string, voter: string, // dRepHash dRepStakePrivKey: string, - proposal: string + proposal: string, ) { const kuber = new Kuber(addr, signingKey); const req = { @@ -343,7 +343,7 @@ const kuberService = { abstainDelegations( stakePrivKeys: string[], - stakePkhs: string[] + stakePkhs: string[], ): Promise { const kuber = new Kuber(faucetWallet.address, faucetWallet.payment.private); const selections = stakePrivKeys.map((key) => { @@ -372,7 +372,7 @@ async function callKuber( path: any, method: "GET" | "POST" = "GET", body?: BodyInit, - contentType = "application/json" + contentType = "application/json", ) { const url = config.apiUrl + path; @@ -405,7 +405,7 @@ async function callKuber( err = Error( `KuberApi [Status ${res.status}] : ${ json.message ? json.message : txt - }` + }`, ); } else { err = Error(`KuberApi [Status ${res.status}] : ${txt}`); diff --git a/tests/govtool-frontend/playwright/tests/1-wallet-connect/walletConnect.spec.ts b/tests/govtool-frontend/playwright/tests/1-wallet-connect/walletConnect.spec.ts index ea33fdcb4..500786d0a 100644 --- a/tests/govtool-frontend/playwright/tests/1-wallet-connect/walletConnect.spec.ts +++ b/tests/govtool-frontend/playwright/tests/1-wallet-connect/walletConnect.spec.ts @@ -11,7 +11,7 @@ test("1A. Should connect wallet and choose stake-key to use @smoke @fast", async const shellyWallet = await ShelleyWallet.generate(); const extraPubStakeKey = convertBufferToHex(shellyWallet.stakeKey.public); const extraRewardAddress = convertBufferToHex( - shellyWallet.rewardAddressRawBytes(0) + shellyWallet.rewardAddressRawBytes(0), ); await createWallet(page, { diff --git a/tests/govtool-frontend/playwright/tests/2-delegation/delegation.delegation.spec.ts b/tests/govtool-frontend/playwright/tests/2-delegation/delegation.delegation.spec.ts index 82c008d20..88749ea26 100644 --- a/tests/govtool-frontend/playwright/tests/2-delegation/delegation.delegation.spec.ts +++ b/tests/govtool-frontend/playwright/tests/2-delegation/delegation.delegation.spec.ts @@ -33,7 +33,7 @@ test.describe("Delegate to others", () => { page.goto("/"); await expect(page.getByTestId("delegated-dRep-id")).toHaveText( - dRep01Wallet.dRepId + dRep01Wallet.dRepId, ); }); }); @@ -48,7 +48,7 @@ test.describe("Delegate to myself", () => { const wallet = await ShelleyWallet.generate(); const txRes = await kuberService.transferADA( [wallet.addressBech32(environments.networkId)], - 600 + 600, ); await pollTransaction(txRes.txId, txRes.lockInfo); const dRepAuth = await createTempDRepAuth(page, wallet); @@ -61,7 +61,7 @@ test.describe("Delegate to myself", () => { await dRepPage.getByTestId("register-as-sole-voter-button").click(); await dRepPage.getByTestId("retire-button").click(); // BUG: Incorrect test-id , it should be continue-retirement await expect( - dRepPage.getByTestId("registration-transaction-submitted-modal") + dRepPage.getByTestId("registration-transaction-submitted-modal"), ).toBeVisible(); dRepPage.getByTestId("confirm-modal-button").click(); await waitForTxConfirmation(dRepPage); diff --git a/tests/govtool-frontend/playwright/tests/2-delegation/delegation.loggedin.spec.ts b/tests/govtool-frontend/playwright/tests/2-delegation/delegation.loggedin.spec.ts index 969607c1f..6beb4a2ed 100644 --- a/tests/govtool-frontend/playwright/tests/2-delegation/delegation.loggedin.spec.ts +++ b/tests/govtool-frontend/playwright/tests/2-delegation/delegation.loggedin.spec.ts @@ -12,7 +12,7 @@ test("2B. Should access delegation to dRep page @smoke @fast", async ({ await page.getByTestId("delegate-button").click(); // BUG incorrect test ID await expect( - page.getByRole("navigation").getByText("DRep Directory") + page.getByRole("navigation").getByText("DRep Directory"), ).toBeVisible(); }); diff --git a/tests/govtool-frontend/playwright/tests/3-drep-registration/dRepRegistration.dRep.spec.ts b/tests/govtool-frontend/playwright/tests/3-drep-registration/dRepRegistration.dRep.spec.ts index 2e633866d..d31e2a91a 100644 --- a/tests/govtool-frontend/playwright/tests/3-drep-registration/dRepRegistration.dRep.spec.ts +++ b/tests/govtool-frontend/playwright/tests/3-drep-registration/dRepRegistration.dRep.spec.ts @@ -1,6 +1,7 @@ import environments from "@constants/environments"; import { dRep01Wallet } from "@constants/staticWallets"; import { createTempDRepAuth } from "@datafactory/createAuth"; +import { faker } from "@faker-js/faker"; import { test } from "@fixtures/walletExtension"; import convertBufferToHex from "@helpers/convertBufferToHex"; import { ShelleyWallet } from "@helpers/crypto"; @@ -20,7 +21,7 @@ test.describe("Logged in DReps", () => { }) => { await page.goto("/"); await expect(page.getByTestId("dRep-id-display")).toContainText( - dRep01Wallet.dRepId + dRep01Wallet.dRepId, ); // BUG: testId -> dRep-id-display-dashboard (It is taking sidebar dRep-id) }); @@ -45,7 +46,7 @@ test.describe("Temporary DReps", () => { const wallet = await ShelleyWallet.generate(); const res = await kuberService.transferADA( [wallet.addressBech32(environments.networkId)], - 600 + 600, ); await pollTransaction(res.txId, res.lockInfo); @@ -58,11 +59,11 @@ test.describe("Temporary DReps", () => { const dRepRegistrationPage = new DRepRegistrationPage(dRepPage); await dRepRegistrationPage.goto(); - await dRepRegistrationPage.register({ name: "Test_dRep" }); + await dRepRegistrationPage.register({ name: faker.person.firstName() }); await expect(dRepRegistrationPage.registrationSuccessModal).toBeVisible(); await expect( - dRepRegistrationPage.registrationSuccessModal.getByText("this link") + dRepRegistrationPage.registrationSuccessModal.getByText("this link"), ).toBeVisible(); }); @@ -75,7 +76,7 @@ test.describe("Temporary DReps", () => { const wallet = await ShelleyWallet.generate(); const registrationRes = await kuberService.dRepRegistration( convertBufferToHex(wallet.stakeKey.private), - convertBufferToHex(wallet.stakeKey.pkh) + convertBufferToHex(wallet.stakeKey.pkh), ); await pollTransaction(registrationRes.txId, registrationRes.lockInfo); @@ -91,7 +92,7 @@ test.describe("Temporary DReps", () => { await dRepPage.getByTestId("retire-button").click(); // BUG testId -> continue-retire-button await expect( - dRepPage.getByTestId("retirement-transaction-error-modal") + dRepPage.getByTestId("retirement-transaction-error-modal"), ).toBeVisible(); }); @@ -104,7 +105,7 @@ test.describe("Temporary DReps", () => { const wallet = await ShelleyWallet.generate(); const registrationRes = await kuberService.dRepRegistration( convertBufferToHex(wallet.stakeKey.private), - convertBufferToHex(wallet.stakeKey.pkh) + convertBufferToHex(wallet.stakeKey.pkh), ); await pollTransaction(registrationRes.txId, registrationRes.lockInfo); @@ -124,7 +125,7 @@ test.describe("Temporary DReps", () => { await dRepPage.getByTestId("retire-button").click(); await dRepPage.getByTestId("retire-button").click(); // BUG: testId -> continue-retire-button await expect( - dRepPage.getByTestId("retirement-transaction-submitted-modal") + dRepPage.getByTestId("retirement-transaction-submitted-modal"), ).toBeVisible(); dRepPage.getByTestId("confirm-modal-button").click(); await waitForTxConfirmation(dRepPage); @@ -135,4 +136,37 @@ test.describe("Temporary DReps", () => { await governanceActionsPage.viewFirstProposal(); await expect(govActionDetailsPage.voteBtn).not.toBeVisible(); }); + + test("3K. Should display 'In Progress' status on dashboard until blockchain confirms DRep registration", async ({ + page, + browser, + }, testInfo) => { + test.setTimeout(testInfo.timeout + environments.txTimeOut); + + const wallet = await ShelleyWallet.generate(); + + const res = await kuberService.transferADA( + [wallet.addressBech32(environments.networkId)], + 600, + ); + await pollTransaction(res.txId, res.lockInfo); + + const dRepAuth = await createTempDRepAuth(page, wallet); + const dRepPage = await createNewPageWithWallet(browser, { + storageState: dRepAuth, + wallet, + enableStakeSigning: true, + }); + + const dRepRegistrationPage = new DRepRegistrationPage(dRepPage); + await dRepRegistrationPage.goto(); + await dRepRegistrationPage.register({ name: faker.person.firstName() }); + dRepRegistrationPage.registrationSuccessModal + .getByTestId("confirm-modal-button") + .click(); + + await expect( + dRepPage.locator("span").filter({ hasText: "In Progress" }), + ).toBeVisible(); // BUG add proper testId for dRep registration card + }); }); diff --git a/tests/govtool-frontend/playwright/tests/4-proposal-visibility/proposalVisibility.loggedin.spec.ts b/tests/govtool-frontend/playwright/tests/4-proposal-visibility/proposalVisibility.loggedin.spec.ts index d55c62514..3efed401f 100644 --- a/tests/govtool-frontend/playwright/tests/4-proposal-visibility/proposalVisibility.loggedin.spec.ts +++ b/tests/govtool-frontend/playwright/tests/4-proposal-visibility/proposalVisibility.loggedin.spec.ts @@ -85,19 +85,19 @@ test("4C.2: Should sort Governance Action Type on governance actions page @slow" govActionsPage.sortProposal(SortOption.SoonToExpire); await govActionsPage.validateSort( SortOption.SoonToExpire, - (p1, p2) => p1.expiryDate <= p2.expiryDate + (p1, p2) => p1.expiryDate <= p2.expiryDate, ); govActionsPage.sortProposal(SortOption.NewestFirst); await govActionsPage.validateSort( SortOption.NewestFirst, - (p1, p2) => p1.createdDate >= p2.createdDate + (p1, p2) => p1.createdDate >= p2.createdDate, ); govActionsPage.sortProposal(SortOption.HighestYesVotes); await govActionsPage.validateSort( SortOption.HighestYesVotes, - (p1, p2) => p1.yesVotes >= p2.yesVotes + (p1, p2) => p1.yesVotes >= p2.yesVotes, ); }); @@ -118,7 +118,7 @@ test("4D: Should filter and sort Governance Action Type on governance actions pa await govActionsPage.validateSort( SortOption.SoonToExpire, (p1, p2) => p1.expiryDate <= p2.expiryDate, - [removeAllSpaces(filterOptionNames[0])] + [removeAllSpaces(filterOptionNames[0])], ); await govActionsPage.validateFilters([filterOptionNames[0]]); }); diff --git a/tests/govtool-frontend/playwright/tests/5-proposal-functionality/proposalFunctionality.dRep.spec.ts b/tests/govtool-frontend/playwright/tests/5-proposal-functionality/proposalFunctionality.dRep.spec.ts index dd13ab19b..055f53925 100644 --- a/tests/govtool-frontend/playwright/tests/5-proposal-functionality/proposalFunctionality.dRep.spec.ts +++ b/tests/govtool-frontend/playwright/tests/5-proposal-functionality/proposalFunctionality.dRep.spec.ts @@ -86,7 +86,9 @@ test.describe("Proposal checks", () => { await expect(govActionDetailsPage.externalLinkModal).toBeVisible(); await expect( - govActionDetailsPage.currentPage.getByText("Be careful", { exact: false }) + govActionDetailsPage.currentPage.getByText("Be careful", { + exact: false, + }), ).toBeVisible(); }); @@ -110,13 +112,13 @@ test.describe("Perform voting", () => { const wallet = await ShelleyWallet.generate(); const registrationRes = await kuberService.dRepRegistration( convertBufferToHex(wallet.stakeKey.private), - convertBufferToHex(wallet.stakeKey.pkh) + convertBufferToHex(wallet.stakeKey.pkh), ); await pollTransaction(registrationRes.txId, registrationRes.lockInfo); const res = await kuberService.transferADA( [wallet.addressBech32(environments.networkId)], - 40 + 40, ); await pollTransaction(res.txId, registrationRes.lockInfo); @@ -141,12 +143,12 @@ test.describe("Perform voting", () => { await waitForTxConfirmation(govActionDetailsPage.currentPage); const governanceActionsPage = new GovernanceActionsPage( - govActionDetailsPage.currentPage + govActionDetailsPage.currentPage, ); await governanceActionsPage.goto(); await governanceActionsPage.votedTab.click(); await expect( - govActionDetailsPage.currentPage.getByTestId("my-vote").getByText("Yes") + govActionDetailsPage.currentPage.getByTestId("my-vote").getByText("Yes"), ).toBeVisible(); govActionDetailsPage = await governanceActionsPage.viewFirstVotedProposal(); @@ -155,7 +157,7 @@ test.describe("Perform voting", () => { await governanceActionsPage.votedTab.click(); await expect( - govActionDetailsPage.currentPage.getByTestId("my-vote").getByText("No") + govActionDetailsPage.currentPage.getByTestId("my-vote").getByText("No"), ).toBeVisible(); }); @@ -171,12 +173,56 @@ test.describe("Perform voting", () => { await waitForTxConfirmation(govActionDetailsPage.currentPage); const governanceActionsPage = new GovernanceActionsPage( - govActionDetailsPage.currentPage + govActionDetailsPage.currentPage, ); await governanceActionsPage.goto(); await governanceActionsPage.votedTab.click(); await expect( - govActionDetailsPage.currentPage.getByTestId("my-vote").getByText("Yes") + govActionDetailsPage.currentPage.getByTestId("my-vote").getByText("Yes"), ).toBeVisible(); }); }); + +test.describe("Check voting power", () => { + test("5K. Should return deposit on DRep retirement", async ({ + page, + browser, + }, testInfo) => { + test.setTimeout(testInfo.timeout + 2 * environments.txTimeOut); + + const wallet = await ShelleyWallet.generate(); + const registrationRes = await kuberService.dRepRegistration( + convertBufferToHex(wallet.stakeKey.private), + convertBufferToHex(wallet.stakeKey.pkh), + ); + await pollTransaction(registrationRes.txId, registrationRes.lockInfo); + + const res = await kuberService.transferADA( + [wallet.addressBech32(environments.networkId)], + 40, + ); + await pollTransaction(res.txId, registrationRes.lockInfo); + + const tempDRepAuth = await createTempDRepAuth(page, wallet); + + const dRepPage = await createNewPageWithWallet(browser, { + storageState: tempDRepAuth, + wallet, + enableStakeSigning: true, + }); + + await dRepPage.goto("/"); + await dRepPage.getByTestId("retire-button").click(); + await dRepPage.getByTestId("retire-button").click(); // BUG: testId -> continue-retire-button + await expect( + dRepPage.getByTestId("retirement-transaction-submitted-modal"), + ).toBeVisible(); + dRepPage.getByTestId("confirm-modal-button").click(); + await waitForTxConfirmation(dRepPage); + + const balance = await kuberService.getBalance( + wallet.addressBech32(environments.networkId), + ); + expect(balance, "Retirement deposit not returned").toBeGreaterThan(500); + }); +}); diff --git a/tests/govtool-frontend/playwright/tests/6-miscellaneous/miscellaneous.spec.ts b/tests/govtool-frontend/playwright/tests/6-miscellaneous/miscellaneous.spec.ts index d26feb683..0b9a7a33d 100644 --- a/tests/govtool-frontend/playwright/tests/6-miscellaneous/miscellaneous.spec.ts +++ b/tests/govtool-frontend/playwright/tests/6-miscellaneous/miscellaneous.spec.ts @@ -23,7 +23,7 @@ test("6C. Navigation within the dApp @smoke @fast", async ({ ]); await expect(guidesPage).toHaveURL( - `${environments.docsUrl}/about/what-is-sanchonet-govtool` + `${environments.docsUrl}/about/what-is-sanchonet-govtool`, ); if (isMobile(page)) { diff --git a/tests/govtool-frontend/playwright/tests/dRep.setup.ts b/tests/govtool-frontend/playwright/tests/dRep.setup.ts index 38c587663..5203f1e47 100644 --- a/tests/govtool-frontend/playwright/tests/dRep.setup.ts +++ b/tests/govtool-frontend/playwright/tests/dRep.setup.ts @@ -15,7 +15,7 @@ dRepWallets.forEach((wallet) => { try { const res = await kuberService.dRepRegistration( wallet.stake.private, - wallet.stake.pkh + wallet.stake.pkh, ); await pollTransaction(res.txId, res.lockInfo); diff --git a/tests/govtool-frontend/playwright/tests/delegation.teardown.ts b/tests/govtool-frontend/playwright/tests/delegation.teardown.ts index 986ab1a45..2831db009 100644 --- a/tests/govtool-frontend/playwright/tests/delegation.teardown.ts +++ b/tests/govtool-frontend/playwright/tests/delegation.teardown.ts @@ -12,7 +12,7 @@ cleanup(`Abstain delegation`, async () => { const { txId, lockInfo } = await kuberService.abstainDelegations( stakePrivKeys, - stakePkhs + stakePkhs, ); await pollTransaction(txId, lockInfo); }); diff --git a/tests/govtool-frontend/playwright/tests/wallet.bootstrap.ts b/tests/govtool-frontend/playwright/tests/wallet.bootstrap.ts index 1d7397fda..80c9848c2 100644 --- a/tests/govtool-frontend/playwright/tests/wallet.bootstrap.ts +++ b/tests/govtool-frontend/playwright/tests/wallet.bootstrap.ts @@ -32,7 +32,7 @@ for (const wallet of [...adaHolderWallets, ...dRepWallets]) { wallet.stake.private, wallet.stake.pkh, wallet.payment.private, - wallet.address + wallet.address, ); await pollTransaction(txId, lockInfo); } catch (err) { @@ -49,7 +49,7 @@ function saveWallets(wallets: ShelleyWallet[]) { const jsonWallets = []; for (let i = 0; i < wallets.length; i++) { const stakePublicKey = Buffer.from(wallets[i].stakeKey.public).toString( - "hex" + "hex", ); const { dRepIdBech32 } = extractDRepsFromStakePubKey(stakePublicKey); From d07fb9d1405ec662d2918ba623ee047ee6ebdfa5 Mon Sep 17 00:00:00 2001 From: Nabin Kawan Date: Wed, 15 May 2024 11:59:15 +0545 Subject: [PATCH 117/125] test: Metadata anchor in vote transaction --- .../playwright/lib/helpers/logger.ts | 13 +++++++++++ .../playwright/lib/helpers/metadata.ts | 13 +++++++++++ .../lib/pages/governanceActionDetailsPage.ts | 8 ++++++- .../lib/services/metadataBucketService.ts | 22 +++++++++++++++++++ .../proposalVisibility.dRep.spec.ts | 18 +++++++-------- 5 files changed, 64 insertions(+), 10 deletions(-) create mode 100644 tests/govtool-frontend/playwright/lib/helpers/logger.ts create mode 100644 tests/govtool-frontend/playwright/lib/helpers/metadata.ts create mode 100644 tests/govtool-frontend/playwright/lib/services/metadataBucketService.ts diff --git a/tests/govtool-frontend/playwright/lib/helpers/logger.ts b/tests/govtool-frontend/playwright/lib/helpers/logger.ts new file mode 100644 index 000000000..282544bb5 --- /dev/null +++ b/tests/govtool-frontend/playwright/lib/helpers/logger.ts @@ -0,0 +1,13 @@ +export class Logger { + static success(msg: string) { + console.debug(`\x1b[32m✔ ${msg}\x1b[0m`); // Green color + } + + static fail(msg) { + console.debug(`\x1b[33m✖ ${msg}\x1b[0m`); // Orange color + } + + static info(msg: string) { + console.debug(`\x1b[36mℹ ${msg}\x1b[0m`); // Cyan color + } +} diff --git a/tests/govtool-frontend/playwright/lib/helpers/metadata.ts b/tests/govtool-frontend/playwright/lib/helpers/metadata.ts new file mode 100644 index 000000000..9c3657f95 --- /dev/null +++ b/tests/govtool-frontend/playwright/lib/helpers/metadata.ts @@ -0,0 +1,13 @@ +import { Download } from "@playwright/test"; +import * as fs from "fs"; + +export async function downloadMetadata(download: Download): Promise<{ + name: string; + data: JSON; +}> { + const path = `.download/${download.suggestedFilename()}`; + await download.saveAs(path); + const fileContent = fs.readFileSync(path, "utf-8"); + const jsonData = JSON.parse(fileContent); + return { name: download.suggestedFilename(), data: jsonData }; +} diff --git a/tests/govtool-frontend/playwright/lib/pages/governanceActionDetailsPage.ts b/tests/govtool-frontend/playwright/lib/pages/governanceActionDetailsPage.ts index 843a242c9..31fee6f1b 100644 --- a/tests/govtool-frontend/playwright/lib/pages/governanceActionDetailsPage.ts +++ b/tests/govtool-frontend/playwright/lib/pages/governanceActionDetailsPage.ts @@ -25,6 +25,7 @@ export default class GovernanceActionDetailsPage { "view-other-details-button", ); readonly continueModalBtn = this.page.getByTestId("continue-modal-button"); + readonly confirmModalBtn = this.page.getByTestId("confirm-modal-button"); readonly voteSuccessModal = this.page.getByTestId("alert-success"); readonly externalLinkModal = this.page.getByTestId("external-link-modal"); @@ -61,7 +62,7 @@ export default class GovernanceActionDetailsPage { const voteMetadata = await this.downloadVoteMetadata(); const url = await metadataBucketService.uploadMetadata( voteMetadata.name, - voteMetadata.data, + voteMetadata.data ); await this.page.getByPlaceholder("URL").fill(url); @@ -72,6 +73,11 @@ export default class GovernanceActionDetailsPage { await this.voteBtn.click(); } + async downloadVoteMetadata() { + const download: Download = await this.page.waitForEvent("download"); + return downloadMetadata(download); + } + async reVote() { await this.noVoteRadio.click(); await this.changeVoteBtn.click(); diff --git a/tests/govtool-frontend/playwright/lib/services/metadataBucketService.ts b/tests/govtool-frontend/playwright/lib/services/metadataBucketService.ts new file mode 100644 index 000000000..2765f09e6 --- /dev/null +++ b/tests/govtool-frontend/playwright/lib/services/metadataBucketService.ts @@ -0,0 +1,22 @@ +import environments from "@constants/environments"; +import { Logger } from "@helpers/logger"; + +import fetch = require("node-fetch"); + +const metadataBucketService = { + uploadMetadata: async (name: string, data: JSON) => { + try { + const res = await fetch(`${environments.metadataBucketUrl}/${name}`, { + method: "PUT", + body: JSON.stringify(data), + }); + Logger.success(`Uploaded ${name} metadata to bucket`); + return `${environments.metadataBucketUrl}/${name}`; + } catch (err) { + Logger.fail(`Failed to upload ${name} metadata: ${err}`); + throw err; + } + }, +}; + +export default metadataBucketService; diff --git a/tests/govtool-frontend/playwright/tests/4-proposal-visibility/proposalVisibility.dRep.spec.ts b/tests/govtool-frontend/playwright/tests/4-proposal-visibility/proposalVisibility.dRep.spec.ts index e9b680c1f..66c27eac7 100644 --- a/tests/govtool-frontend/playwright/tests/4-proposal-visibility/proposalVisibility.dRep.spec.ts +++ b/tests/govtool-frontend/playwright/tests/4-proposal-visibility/proposalVisibility.dRep.spec.ts @@ -27,7 +27,7 @@ test.describe("Logged in DRep", () => { const votingPower = await res.json(); await expect( - page.getByText(`₳ ${lovelaceToAda(votingPower)}`), + page.getByText(`₳ ${lovelaceToAda(votingPower)}`) ).toBeVisible(); }); @@ -49,8 +49,8 @@ test.describe("Logged in DRep", () => { }) => { const responsesPromise = Object.keys(FilterOption).map((filterKey) => page.waitForResponse((response) => - response.url().includes(`&type[]=${FilterOption[filterKey]}`), - ), + response.url().includes(`&type[]=${FilterOption[filterKey]}`) + ) ); const governanceActionsPage = new GovernanceActionsPage(page); @@ -61,7 +61,7 @@ test.describe("Logged in DRep", () => { responses.map(async (response) => { const data = await response.json(); return data.elements; - }), + }) ) ).flat(); @@ -75,17 +75,17 @@ test.describe("Logged in DRep", () => { await expect( page .getByText("yes₳") - .getByText(`₳ ${lovelaceToAda(proposalToCheck.yesVotes)}`), + .getByText(`₳ ${lovelaceToAda(proposalToCheck.yesVotes)}`) ).toBeVisible(); await expect( page .getByText("abstain₳") - .getByText(`₳ ${lovelaceToAda(proposalToCheck.abstainVotes)}`), + .getByText(`₳ ${lovelaceToAda(proposalToCheck.abstainVotes)}`) ).toBeVisible(); await expect( page .getByText("no₳") - .getByText(`₳ ${lovelaceToAda(proposalToCheck.noVotes)}`), + .getByText(`₳ ${lovelaceToAda(proposalToCheck.noVotes)}`) ).toBeVisible(); }); }); @@ -99,13 +99,13 @@ test.describe("Temporary DReps", async () => { const wallet = await ShelleyWallet.generate(); const registrationRes = await kuberService.dRepRegistration( convertBufferToHex(wallet.stakeKey.private), - convertBufferToHex(wallet.stakeKey.pkh), + convertBufferToHex(wallet.stakeKey.pkh) ); await pollTransaction(registrationRes.txId, registrationRes.lockInfo); const res = await kuberService.transferADA( [wallet.addressBech32(environments.networkId)], - 40, + 40 ); await pollTransaction(res.txId, registrationRes.lockInfo); From 63ee2d1417c7eee5f0b170fc1d0a23d0d5b71e26 Mon Sep 17 00:00:00 2001 From: Nabin Kawan Date: Mon, 13 May 2024 19:25:17 +0545 Subject: [PATCH 118/125] test: Expired governance actions should not be displayed --- .../lib/helpers/extractExpiryDateFromText.ts | 29 +++++++++++++++++++ .../proposalVisibility.loggedin.spec.ts | 19 ++++++++++++ 2 files changed, 48 insertions(+) create mode 100644 tests/govtool-frontend/playwright/lib/helpers/extractExpiryDateFromText.ts diff --git a/tests/govtool-frontend/playwright/lib/helpers/extractExpiryDateFromText.ts b/tests/govtool-frontend/playwright/lib/helpers/extractExpiryDateFromText.ts new file mode 100644 index 000000000..833fe3064 --- /dev/null +++ b/tests/govtool-frontend/playwright/lib/helpers/extractExpiryDateFromText.ts @@ -0,0 +1,29 @@ +const monthNames = [ + "Jan", + "Feb", + "Mar", + "Apr", + "May", + "Jun", + "Jul", + "Aug", + "Sep", + "Oct", + "Nov", + "Dec", +]; + +export default function extractExpiryDateFromText(text: string): Date | null { + const regex = /(\d{1,2})th ([\w]{3}) (\d{4})/; + const match = text.match(regex); + + if (match) { + const day = parseInt(match[1]); + const month = match[2]; + const year = parseInt(match[3]); + + return new Date(year, monthNames.indexOf(month), day); + } else { + return null; + } +} diff --git a/tests/govtool-frontend/playwright/tests/4-proposal-visibility/proposalVisibility.loggedin.spec.ts b/tests/govtool-frontend/playwright/tests/4-proposal-visibility/proposalVisibility.loggedin.spec.ts index 3efed401f..0432f37bd 100644 --- a/tests/govtool-frontend/playwright/tests/4-proposal-visibility/proposalVisibility.loggedin.spec.ts +++ b/tests/govtool-frontend/playwright/tests/4-proposal-visibility/proposalVisibility.loggedin.spec.ts @@ -1,5 +1,6 @@ import { user01Wallet } from "@constants/staticWallets"; import { test } from "@fixtures/walletExtension"; +import extractExpiryDateFromText from "@helpers/extractExpiryDateFromText"; import { isMobile, openDrawerLoggedIn } from "@helpers/mobile"; import removeAllSpaces from "@helpers/removeAllSpaces"; import GovernanceActionsPage from "@pages/governanceActionsPage"; @@ -122,3 +123,21 @@ test("4D: Should filter and sort Governance Action Type on governance actions pa ); await govActionsPage.validateFilters([filterOptionNames[0]]); }); + +test("4H. Should verify none of the displayed governance actions have expired", async ({ + page, +}) => { + const govActionsPage = new GovernanceActionsPage(page); + await govActionsPage.goto(); + + await page.waitForTimeout(4000); // BUG: Delay to load governance actions + const proposalCards = await govActionsPage.getAllProposals(); + + for (const proposalCard of proposalCards) { + const expiryDateEl = proposalCard.getByTestId("expiry-date"); + const expiryDateTxt = await expiryDateEl.innerText(); + const expiryDate = extractExpiryDateFromText(expiryDateTxt); + const today = new Date(); + expect(today <= expiryDate).toBeTruthy(); + } +}); From 2bc0272b9981ec6835ca4e7510aaff968be8ceee Mon Sep 17 00:00:00 2001 From: Nabin Kawan Date: Mon, 13 May 2024 12:11:43 +0545 Subject: [PATCH 119/125] test: Return deposit on DRep retirement --- .../proposalFunctionality.dRep.spec.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/govtool-frontend/playwright/tests/5-proposal-functionality/proposalFunctionality.dRep.spec.ts b/tests/govtool-frontend/playwright/tests/5-proposal-functionality/proposalFunctionality.dRep.spec.ts index 055f53925..6729b8e09 100644 --- a/tests/govtool-frontend/playwright/tests/5-proposal-functionality/proposalFunctionality.dRep.spec.ts +++ b/tests/govtool-frontend/playwright/tests/5-proposal-functionality/proposalFunctionality.dRep.spec.ts @@ -193,13 +193,13 @@ test.describe("Check voting power", () => { const wallet = await ShelleyWallet.generate(); const registrationRes = await kuberService.dRepRegistration( convertBufferToHex(wallet.stakeKey.private), - convertBufferToHex(wallet.stakeKey.pkh), + convertBufferToHex(wallet.stakeKey.pkh) ); await pollTransaction(registrationRes.txId, registrationRes.lockInfo); const res = await kuberService.transferADA( [wallet.addressBech32(environments.networkId)], - 40, + 40 ); await pollTransaction(res.txId, registrationRes.lockInfo); @@ -215,13 +215,13 @@ test.describe("Check voting power", () => { await dRepPage.getByTestId("retire-button").click(); await dRepPage.getByTestId("retire-button").click(); // BUG: testId -> continue-retire-button await expect( - dRepPage.getByTestId("retirement-transaction-submitted-modal"), + dRepPage.getByTestId("retirement-transaction-submitted-modal") ).toBeVisible(); dRepPage.getByTestId("confirm-modal-button").click(); await waitForTxConfirmation(dRepPage); const balance = await kuberService.getBalance( - wallet.addressBech32(environments.networkId), + wallet.addressBech32(environments.networkId) ); expect(balance, "Retirement deposit not returned").toBeGreaterThan(500); }); From eb63afd543a1fe45fd105ec1df481e7792842f6c Mon Sep 17 00:00:00 2001 From: Nabin Kawan Date: Mon, 13 May 2024 10:09:41 +0545 Subject: [PATCH 120/125] test: Hide retirement option for non-DRep --- .../proposalFunctionality.loggedin.spec.ts | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 tests/govtool-frontend/playwright/tests/5-proposal-functionality/proposalFunctionality.loggedin.spec.ts diff --git a/tests/govtool-frontend/playwright/tests/5-proposal-functionality/proposalFunctionality.loggedin.spec.ts b/tests/govtool-frontend/playwright/tests/5-proposal-functionality/proposalFunctionality.loggedin.spec.ts new file mode 100644 index 000000000..17034e23e --- /dev/null +++ b/tests/govtool-frontend/playwright/tests/5-proposal-functionality/proposalFunctionality.loggedin.spec.ts @@ -0,0 +1,12 @@ +import { user01Wallet } from "@constants/staticWallets"; +import { test } from "@fixtures/walletExtension"; +import { expect } from "@playwright/test"; + +test.use({ storageState: ".auth/user01.json", wallet: user01Wallet }); + +test("5J. Should hide retirement option for non-registered DRep", async ({ + page, +}) => { + await page.goto("/"); + await expect(page.getByTestId("retire-button")).not.toBeVisible(); +}); From e217ace2bbf7698a6c2d2c551413481170774c23 Mon Sep 17 00:00:00 2001 From: Nabin Kawan Date: Fri, 10 May 2024 22:41:07 +0545 Subject: [PATCH 121/125] Add util lovelace-to-ada conversion --- tests/govtool-frontend/playwright/lib/helpers/cardano.ts | 5 +++++ .../playwright/lib/pages/governanceActionDetailsPage.ts | 1 + .../4-proposal-visibility/proposalVisibility.dRep.spec.ts | 4 ++-- 3 files changed, 8 insertions(+), 2 deletions(-) create mode 100644 tests/govtool-frontend/playwright/lib/helpers/cardano.ts diff --git a/tests/govtool-frontend/playwright/lib/helpers/cardano.ts b/tests/govtool-frontend/playwright/lib/helpers/cardano.ts new file mode 100644 index 000000000..3718d13a3 --- /dev/null +++ b/tests/govtool-frontend/playwright/lib/helpers/cardano.ts @@ -0,0 +1,5 @@ +export function lovelaceToAda(lovelace: number) { + if (lovelace === 0) return 0; + + return lovelace / 1e6; +} diff --git a/tests/govtool-frontend/playwright/lib/pages/governanceActionDetailsPage.ts b/tests/govtool-frontend/playwright/lib/pages/governanceActionDetailsPage.ts index 31fee6f1b..49cffbe00 100644 --- a/tests/govtool-frontend/playwright/lib/pages/governanceActionDetailsPage.ts +++ b/tests/govtool-frontend/playwright/lib/pages/governanceActionDetailsPage.ts @@ -13,6 +13,7 @@ export default class GovernanceActionDetailsPage { readonly governanceActionType = this.page.getByText( "Governance Action Type:", ); + readonly showVotesBtn = this.page.getByTestId("show-votes-button"); readonly submittedDate = this.page.getByTestId("submission-date"); readonly expiryDate = this.page.getByTestId("expiry-date"); readonly externalModalBtn = this.page.getByTestId("external-modal-button"); diff --git a/tests/govtool-frontend/playwright/tests/4-proposal-visibility/proposalVisibility.dRep.spec.ts b/tests/govtool-frontend/playwright/tests/4-proposal-visibility/proposalVisibility.dRep.spec.ts index 66c27eac7..f9ec27ab8 100644 --- a/tests/govtool-frontend/playwright/tests/4-proposal-visibility/proposalVisibility.dRep.spec.ts +++ b/tests/govtool-frontend/playwright/tests/4-proposal-visibility/proposalVisibility.dRep.spec.ts @@ -23,8 +23,8 @@ test.describe("Logged in DRep", () => { const governanceActionsPage = new GovernanceActionsPage(page); await governanceActionsPage.goto(); - const res = await votingPowerPromise; - const votingPower = await res.json(); + const res = await votingPowerPromise; + const votingPower = await res.json(); await expect( page.getByText(`₳ ${lovelaceToAda(votingPower)}`) From acd088e54e5d5f2a333f81fc6bcf1d2f68dd6647 Mon Sep 17 00:00:00 2001 From: Nabin Kawan Date: Fri, 10 May 2024 22:36:36 +0545 Subject: [PATCH 122/125] test: Display correct vote counts --- .../lib/pages/governanceActionsPage.ts | 12 +---- .../govtool-frontend/playwright/lib/types.ts | 10 +++++ .../proposalVisibility.dRep.spec.ts | 45 +++++++++++++++++++ 3 files changed, 56 insertions(+), 11 deletions(-) diff --git a/tests/govtool-frontend/playwright/lib/pages/governanceActionsPage.ts b/tests/govtool-frontend/playwright/lib/pages/governanceActionsPage.ts index 03cde5992..07bd1b603 100644 --- a/tests/govtool-frontend/playwright/lib/pages/governanceActionsPage.ts +++ b/tests/govtool-frontend/playwright/lib/pages/governanceActionsPage.ts @@ -1,19 +1,9 @@ import removeAllSpaces from "@helpers/removeAllSpaces"; import { Locator, Page, expect } from "@playwright/test"; -import { IProposal } from "@types"; +import { FilterOption, IProposal } from "@types"; import environments from "lib/constants/environments"; import GovernanceActionDetailsPage from "./governanceActionDetailsPage"; -enum FilterOption { - ProtocolParameterChange = "ParameterChange", - InfoAction = "InfoAction", - TreasuryWithdrawal = "TreasuryWithdrawals", - HardFork = "HardForkInitiation", - NoConfidence = "NoConfidence", - NewCommittee = "NewCommittee", - UpdatetotheConstitution = "NewConstitution", -} - export default class GovernanceActionsPage { readonly filterBtn = this.page.getByTestId("filters-button"); readonly sortBtn = this.page.getByTestId("sort-button"); diff --git a/tests/govtool-frontend/playwright/lib/types.ts b/tests/govtool-frontend/playwright/lib/types.ts index 7cfb36fc8..6cefe5543 100644 --- a/tests/govtool-frontend/playwright/lib/types.ts +++ b/tests/govtool-frontend/playwright/lib/types.ts @@ -29,6 +29,7 @@ export interface IProposal { references: any; yesVotes: number; noVotes: number; + abstainVotes: number; } export type IVote = { @@ -50,3 +51,12 @@ export type IDRepInfo = { bio?: string; extraContentLinks?: string[]; }; +export enum FilterOption { + ProtocolParameterChange = "ParameterChange", + InfoAction = "InfoAction", + TreasuryWithdrawal = "TreasuryWithdrawals", + HardFork = "HardForkInitiation", + NoConfidence = "NoConfidence", + NewCommittee = "NewCommittee", + UpdatetotheConstitution = "NewConstitution", +} diff --git a/tests/govtool-frontend/playwright/tests/4-proposal-visibility/proposalVisibility.dRep.spec.ts b/tests/govtool-frontend/playwright/tests/4-proposal-visibility/proposalVisibility.dRep.spec.ts index f9ec27ab8..6a03d23c3 100644 --- a/tests/govtool-frontend/playwright/tests/4-proposal-visibility/proposalVisibility.dRep.spec.ts +++ b/tests/govtool-frontend/playwright/tests/4-proposal-visibility/proposalVisibility.dRep.spec.ts @@ -129,3 +129,48 @@ test.describe("Temporary DReps", async () => { expect(false, "No vote context displayed").toBe(true); }); }); + +test("4G. Should display correct vote counts on governance details page for DRep", async ({ + page, +}) => { + const responsesPromise = Object.keys(FilterOption).map((filterKey) => + page.waitForResponse((response) => + response.url().includes(`&type[]=${FilterOption[filterKey]}`) + ) + ); + + const governanceActionsPage = new GovernanceActionsPage(page); + await governanceActionsPage.goto(); + const responses = await Promise.all(responsesPromise); + const proposals: IProposal[] = ( + await Promise.all( + responses.map(async (response) => { + const data = await response.json(); + return data.elements; + }) + ) + ).flat(); + + expect(proposals.length, "No proposals found!").toBeGreaterThan(0); + + const proposalToCheck = proposals[0]; + const govActionDetailsPage = + await governanceActionsPage.viewProposal(proposalToCheck); + await govActionDetailsPage.showVotesBtn.click(); + + await expect( + page + .getByText("yes₳") + .getByText(`₳ ${lovelaceToAda(proposalToCheck.yesVotes)}`) + ).toBeVisible(); + await expect( + page + .getByText("abstain₳") + .getByText(`₳ ${lovelaceToAda(proposalToCheck.abstainVotes)}`) + ).toBeVisible(); + await expect( + page + .getByText("no₳") + .getByText(`₳ ${lovelaceToAda(proposalToCheck.noVotes)}`) + ).toBeVisible(); +}); From 6b52800a5a9bc204353b8fee2837eb498aa94751 Mon Sep 17 00:00:00 2001 From: Nabin Kawan Date: Fri, 10 May 2024 15:37:07 +0545 Subject: [PATCH 123/125] test: Disable DRep functionality upon wallet disconnect on govactions page --- .../proposalVisibility.dRep.spec.ts | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tests/govtool-frontend/playwright/tests/4-proposal-visibility/proposalVisibility.dRep.spec.ts b/tests/govtool-frontend/playwright/tests/4-proposal-visibility/proposalVisibility.dRep.spec.ts index 6a03d23c3..417eb6598 100644 --- a/tests/govtool-frontend/playwright/tests/4-proposal-visibility/proposalVisibility.dRep.spec.ts +++ b/tests/govtool-frontend/playwright/tests/4-proposal-visibility/proposalVisibility.dRep.spec.ts @@ -174,3 +174,15 @@ test("4G. Should display correct vote counts on governance details page for DRep .getByText(`₳ ${lovelaceToAda(proposalToCheck.noVotes)}`) ).toBeVisible(); }); + +test("4F. Should Disable DRep functionality upon wallet disconnection on governance page", async ({ + page, +}) => { + const governanceActionsPage = new GovernanceActionsPage(page); + await governanceActionsPage.goto(); + + await page.getByTestId("disconnect-button").click(); + + const govActionDetailsPage = await governanceActionsPage.viewFirstProposal(); + await expect(govActionDetailsPage.voteBtn).not.toBeVisible(); +}); From 36fab448a463cf6e25b61cc78ec2ec0d7663e30b Mon Sep 17 00:00:00 2001 From: Nabin Kawan Date: Fri, 10 May 2024 13:32:20 +0545 Subject: [PATCH 124/125] test: Display 'In Progress' status on transaction --- .../playwright/lib/pages/dRepRegistrationPage.ts | 2 +- .../tests/3-drep-registration/dRepRegistration.dRep.spec.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/govtool-frontend/playwright/lib/pages/dRepRegistrationPage.ts b/tests/govtool-frontend/playwright/lib/pages/dRepRegistrationPage.ts index 766c95534..124f2e560 100644 --- a/tests/govtool-frontend/playwright/lib/pages/dRepRegistrationPage.ts +++ b/tests/govtool-frontend/playwright/lib/pages/dRepRegistrationPage.ts @@ -27,7 +27,7 @@ export default class DRepRegistrationPage { await this.continueBtn.click(); // BUG: testId -> continue-register-button } - async register(dRepInfo: IDRepInfo) { + async register(dRepInfo: IDRepInfo = { name: "Test_dRep" }) { await this.nameInput.fill(dRepInfo.name); if (dRepInfo.email != null) { diff --git a/tests/govtool-frontend/playwright/tests/3-drep-registration/dRepRegistration.dRep.spec.ts b/tests/govtool-frontend/playwright/tests/3-drep-registration/dRepRegistration.dRep.spec.ts index d31e2a91a..e54e1c838 100644 --- a/tests/govtool-frontend/playwright/tests/3-drep-registration/dRepRegistration.dRep.spec.ts +++ b/tests/govtool-frontend/playwright/tests/3-drep-registration/dRepRegistration.dRep.spec.ts @@ -147,7 +147,7 @@ test.describe("Temporary DReps", () => { const res = await kuberService.transferADA( [wallet.addressBech32(environments.networkId)], - 600, + 600 ); await pollTransaction(res.txId, res.lockInfo); @@ -166,7 +166,7 @@ test.describe("Temporary DReps", () => { .click(); await expect( - dRepPage.locator("span").filter({ hasText: "In Progress" }), + dRepPage.locator("span").filter({ hasText: "In Progress" }) ).toBeVisible(); // BUG add proper testId for dRep registration card }); }); From d516bd6a09b5be90d9d9e9055fa61e1c149e06be Mon Sep 17 00:00:00 2001 From: Nabin Kawan Date: Thu, 9 May 2024 20:40:21 +0545 Subject: [PATCH 125/125] 1E. Should hide incompatible wallets when connecting --- .../tests/1-wallet-connect/walletConnect.spec.ts | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/tests/govtool-frontend/playwright/tests/1-wallet-connect/walletConnect.spec.ts b/tests/govtool-frontend/playwright/tests/1-wallet-connect/walletConnect.spec.ts index 500786d0a..980271dbc 100644 --- a/tests/govtool-frontend/playwright/tests/1-wallet-connect/walletConnect.spec.ts +++ b/tests/govtool-frontend/playwright/tests/1-wallet-connect/walletConnect.spec.ts @@ -38,7 +38,9 @@ test("1D. Should check correct network (Testnet/Mainnet) on connection @smoke @f page, }) => { const wrongNetworkId = 1; // mainnet network - await createWallet(page, { networkId: wrongNetworkId }); + await createWallet(page, { + networkId: wrongNetworkId, + }); const errors: Array = []; page.on("pageerror", (error) => { @@ -50,3 +52,15 @@ test("1D. Should check correct network (Testnet/Mainnet) on connection @smoke @f expect(errors).not.toHaveLength(0); }); + +test("1E. Should hide incompatible wallets when connecting", async ({ + page, +}) => { + // Disabling cip95 support for wallet + await createWallet(page, { supportedExtensions: [] }); + + await page.goto("/"); + await page.getByTestId("connect-wallet-button").click(); + + await expect(page.getByTestId("demos-wallet-button")).not.toBeVisible(); +});