From e47ab474de88f5c027f6f48c75b0620fc4efadf3 Mon Sep 17 00:00:00 2001 From: "Marios.Tsigkas" Date: Mon, 10 Mar 2025 14:53:56 +0200 Subject: [PATCH 01/96] Initialize React + TypeScript + Vite project with essential configuration and files --- .gitignore | 24 + catApi-react/README.md | 54 ++ eslint.config.js | 28 + index.html | 13 + package.json | 29 + pnpm-lock.yaml | 1748 ++++++++++++++++++++++++++++++++++++++++ public/vite.svg | 1 + src/App.css | 42 + src/App.tsx | 35 + src/assets/react.svg | 1 + src/index.css | 68 ++ src/main.tsx | 10 + src/vite-env.d.ts | 1 + tsconfig.app.json | 26 + tsconfig.json | 7 + tsconfig.node.json | 24 + vite.config.ts | 7 + 17 files changed, 2118 insertions(+) create mode 100644 .gitignore create mode 100644 catApi-react/README.md create mode 100644 eslint.config.js create mode 100644 index.html create mode 100644 package.json create mode 100644 pnpm-lock.yaml create mode 100644 public/vite.svg create mode 100644 src/App.css create mode 100644 src/App.tsx create mode 100644 src/assets/react.svg create mode 100644 src/index.css create mode 100644 src/main.tsx create mode 100644 src/vite-env.d.ts create mode 100644 tsconfig.app.json create mode 100644 tsconfig.json create mode 100644 tsconfig.node.json create mode 100644 vite.config.ts diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..a547bf36 --- /dev/null +++ b/.gitignore @@ -0,0 +1,24 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +dist-ssr +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? diff --git a/catApi-react/README.md b/catApi-react/README.md new file mode 100644 index 00000000..40ede56e --- /dev/null +++ b/catApi-react/README.md @@ -0,0 +1,54 @@ +# React + TypeScript + Vite + +This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules. + +Currently, two official plugins are available: + +- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md) uses [Babel](https://babeljs.io/) for Fast Refresh +- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh + +## Expanding the ESLint configuration + +If you are developing a production application, we recommend updating the configuration to enable type-aware lint rules: + +```js +export default tseslint.config({ + extends: [ + // Remove ...tseslint.configs.recommended and replace with this + ...tseslint.configs.recommendedTypeChecked, + // Alternatively, use this for stricter rules + ...tseslint.configs.strictTypeChecked, + // Optionally, add this for stylistic rules + ...tseslint.configs.stylisticTypeChecked, + ], + languageOptions: { + // other options... + parserOptions: { + project: ['./tsconfig.node.json', './tsconfig.app.json'], + tsconfigRootDir: import.meta.dirname, + }, + }, +}) +``` + +You can also install [eslint-plugin-react-x](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-x) and [eslint-plugin-react-dom](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-dom) for React-specific lint rules: + +```js +// eslint.config.js +import reactX from 'eslint-plugin-react-x' +import reactDom from 'eslint-plugin-react-dom' + +export default tseslint.config({ + plugins: { + // Add the react-x and react-dom plugins + 'react-x': reactX, + 'react-dom': reactDom, + }, + rules: { + // other rules... + // Enable its recommended typescript rules + ...reactX.configs['recommended-typescript'].rules, + ...reactDom.configs.recommended.rules, + }, +}) +``` diff --git a/eslint.config.js b/eslint.config.js new file mode 100644 index 00000000..092408a9 --- /dev/null +++ b/eslint.config.js @@ -0,0 +1,28 @@ +import js from '@eslint/js' +import globals from 'globals' +import reactHooks from 'eslint-plugin-react-hooks' +import reactRefresh from 'eslint-plugin-react-refresh' +import tseslint from 'typescript-eslint' + +export default tseslint.config( + { ignores: ['dist'] }, + { + extends: [js.configs.recommended, ...tseslint.configs.recommended], + files: ['**/*.{ts,tsx}'], + languageOptions: { + ecmaVersion: 2020, + globals: globals.browser, + }, + plugins: { + 'react-hooks': reactHooks, + 'react-refresh': reactRefresh, + }, + rules: { + ...reactHooks.configs.recommended.rules, + 'react-refresh/only-export-components': [ + 'warn', + { allowConstantExport: true }, + ], + }, + }, +) diff --git a/index.html b/index.html new file mode 100644 index 00000000..e4b78eae --- /dev/null +++ b/index.html @@ -0,0 +1,13 @@ + + + + + + + Vite + React + TS + + +
+ + + diff --git a/package.json b/package.json new file mode 100644 index 00000000..78566d72 --- /dev/null +++ b/package.json @@ -0,0 +1,29 @@ +{ + "name": "catapi-react", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "tsc -b && vite build", + "lint": "eslint .", + "preview": "vite preview" + }, + "dependencies": { + "react": "^19.0.0", + "react-dom": "^19.0.0" + }, + "devDependencies": { + "@eslint/js": "^9.21.0", + "@types/react": "^19.0.10", + "@types/react-dom": "^19.0.4", + "@vitejs/plugin-react-swc": "^3.8.0", + "eslint": "^9.21.0", + "eslint-plugin-react-hooks": "^5.1.0", + "eslint-plugin-react-refresh": "^0.4.19", + "globals": "^15.15.0", + "typescript": "~5.7.2", + "typescript-eslint": "^8.24.1", + "vite": "^6.2.0" + } +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml new file mode 100644 index 00000000..f1666c69 --- /dev/null +++ b/pnpm-lock.yaml @@ -0,0 +1,1748 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + dependencies: + react: + specifier: ^19.0.0 + version: 19.0.0 + react-dom: + specifier: ^19.0.0 + version: 19.0.0(react@19.0.0) + devDependencies: + '@eslint/js': + specifier: ^9.21.0 + version: 9.22.0 + '@types/react': + specifier: ^19.0.10 + version: 19.0.10 + '@types/react-dom': + specifier: ^19.0.4 + version: 19.0.4(@types/react@19.0.10) + '@vitejs/plugin-react-swc': + specifier: ^3.8.0 + version: 3.8.0(vite@6.2.1) + eslint: + specifier: ^9.21.0 + version: 9.22.0 + eslint-plugin-react-hooks: + specifier: ^5.1.0 + version: 5.2.0(eslint@9.22.0) + eslint-plugin-react-refresh: + specifier: ^0.4.19 + version: 0.4.19(eslint@9.22.0) + globals: + specifier: ^15.15.0 + version: 15.15.0 + typescript: + specifier: ~5.7.2 + version: 5.7.3 + typescript-eslint: + specifier: ^8.24.1 + version: 8.26.0(eslint@9.22.0)(typescript@5.7.3) + vite: + specifier: ^6.2.0 + version: 6.2.1 + +packages: + + '@esbuild/aix-ppc64@0.25.1': + resolution: {integrity: sha512-kfYGy8IdzTGy+z0vFGvExZtxkFlA4zAxgKEahG9KE1ScBjpQnFsNOX8KTU5ojNru5ed5CVoJYXFtoxaq5nFbjQ==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + + '@esbuild/android-arm64@0.25.1': + resolution: {integrity: sha512-50tM0zCJW5kGqgG7fQ7IHvQOcAn9TKiVRuQ/lN0xR+T2lzEFvAi1ZcS8DiksFcEpf1t/GYOeOfCAgDHFpkiSmA==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm@0.25.1': + resolution: {integrity: sha512-dp+MshLYux6j/JjdqVLnMglQlFu+MuVeNrmT5nk6q07wNhCdSnB7QZj+7G8VMUGh1q+vj2Bq8kRsuyA00I/k+Q==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + + '@esbuild/android-x64@0.25.1': + resolution: {integrity: sha512-GCj6WfUtNldqUzYkN/ITtlhwQqGWu9S45vUXs7EIYf+7rCiiqH9bCloatO9VhxsL0Pji+PF4Lz2XXCES+Q8hDw==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + + '@esbuild/darwin-arm64@0.25.1': + resolution: {integrity: sha512-5hEZKPf+nQjYoSr/elb62U19/l1mZDdqidGfmFutVUjjUZrOazAtwK+Kr+3y0C/oeJfLlxo9fXb1w7L+P7E4FQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-x64@0.25.1': + resolution: {integrity: sha512-hxVnwL2Dqs3fM1IWq8Iezh0cX7ZGdVhbTfnOy5uURtao5OIVCEyj9xIzemDi7sRvKsuSdtCAhMKarxqtlyVyfA==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + + '@esbuild/freebsd-arm64@0.25.1': + resolution: {integrity: sha512-1MrCZs0fZa2g8E+FUo2ipw6jw5qqQiH+tERoS5fAfKnRx6NXH31tXBKI3VpmLijLH6yriMZsxJtaXUyFt/8Y4A==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.25.1': + resolution: {integrity: sha512-0IZWLiTyz7nm0xuIs0q1Y3QWJC52R8aSXxe40VUxm6BB1RNmkODtW6LHvWRrGiICulcX7ZvyH6h5fqdLu4gkww==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + + '@esbuild/linux-arm64@0.25.1': + resolution: {integrity: sha512-jaN3dHi0/DDPelk0nLcXRm1q7DNJpjXy7yWaWvbfkPvI+7XNSc/lDOnCLN7gzsyzgu6qSAmgSvP9oXAhP973uQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm@0.25.1': + resolution: {integrity: sha512-NdKOhS4u7JhDKw9G3cY6sWqFcnLITn6SqivVArbzIaf3cemShqfLGHYMx8Xlm/lBit3/5d7kXvriTUGa5YViuQ==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + + '@esbuild/linux-ia32@0.25.1': + resolution: {integrity: sha512-OJykPaF4v8JidKNGz8c/q1lBO44sQNUQtq1KktJXdBLn1hPod5rE/Hko5ugKKZd+D2+o1a9MFGUEIUwO2YfgkQ==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + + '@esbuild/linux-loong64@0.25.1': + resolution: {integrity: sha512-nGfornQj4dzcq5Vp835oM/o21UMlXzn79KobKlcs3Wz9smwiifknLy4xDCLUU0BWp7b/houtdrgUz7nOGnfIYg==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-mips64el@0.25.1': + resolution: {integrity: sha512-1osBbPEFYwIE5IVB/0g2X6i1qInZa1aIoj1TdL4AaAb55xIIgbg8Doq6a5BzYWgr+tEcDzYH67XVnTmUzL+nXg==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-ppc64@0.25.1': + resolution: {integrity: sha512-/6VBJOwUf3TdTvJZ82qF3tbLuWsscd7/1w+D9LH0W/SqUgM5/JJD0lrJ1fVIfZsqB6RFmLCe0Xz3fmZc3WtyVg==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-riscv64@0.25.1': + resolution: {integrity: sha512-nSut/Mx5gnilhcq2yIMLMe3Wl4FK5wx/o0QuuCLMtmJn+WeWYoEGDN1ipcN72g1WHsnIbxGXd4i/MF0gTcuAjQ==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-s390x@0.25.1': + resolution: {integrity: sha512-cEECeLlJNfT8kZHqLarDBQso9a27o2Zd2AQ8USAEoGtejOrCYHNtKP8XQhMDJMtthdF4GBmjR2au3x1udADQQQ==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + + '@esbuild/linux-x64@0.25.1': + resolution: {integrity: sha512-xbfUhu/gnvSEg+EGovRc+kjBAkrvtk38RlerAzQxvMzlB4fXpCFCeUAYzJvrnhFtdeyVCDANSjJvOvGYoeKzFA==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + + '@esbuild/netbsd-arm64@0.25.1': + resolution: {integrity: sha512-O96poM2XGhLtpTh+s4+nP7YCCAfb4tJNRVZHfIE7dgmax+yMP2WgMd2OecBuaATHKTHsLWHQeuaxMRnCsH8+5g==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + + '@esbuild/netbsd-x64@0.25.1': + resolution: {integrity: sha512-X53z6uXip6KFXBQ+Krbx25XHV/NCbzryM6ehOAeAil7X7oa4XIq+394PWGnwaSQ2WRA0KI6PUO6hTO5zeF5ijA==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + + '@esbuild/openbsd-arm64@0.25.1': + resolution: {integrity: sha512-Na9T3szbXezdzM/Kfs3GcRQNjHzM6GzFBeU1/6IV/npKP5ORtp9zbQjvkDJ47s6BCgaAZnnnu/cY1x342+MvZg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + + '@esbuild/openbsd-x64@0.25.1': + resolution: {integrity: sha512-T3H78X2h1tszfRSf+txbt5aOp/e7TAz3ptVKu9Oyir3IAOFPGV6O9c2naym5TOriy1l0nNf6a4X5UXRZSGX/dw==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + + '@esbuild/sunos-x64@0.25.1': + resolution: {integrity: sha512-2H3RUvcmULO7dIE5EWJH8eubZAI4xw54H1ilJnRNZdeo8dTADEZ21w6J22XBkXqGJbe0+wnNJtw3UXRoLJnFEg==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + + '@esbuild/win32-arm64@0.25.1': + resolution: {integrity: sha512-GE7XvrdOzrb+yVKB9KsRMq+7a2U/K5Cf/8grVFRAGJmfADr/e/ODQ134RK2/eeHqYV5eQRFxb1hY7Nr15fv1NQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-ia32@0.25.1': + resolution: {integrity: sha512-uOxSJCIcavSiT6UnBhBzE8wy3n0hOkJsBOzy7HDAuTDE++1DJMRRVCPGisULScHL+a/ZwdXPpXD3IyFKjA7K8A==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + + '@esbuild/win32-x64@0.25.1': + resolution: {integrity: sha512-Y1EQdcfwMSeQN/ujR5VayLOJ1BHaK+ssyk0AEzPjC+t1lITgsnccPqFjb6V+LsTp/9Iov4ysfjxLaGJ9RPtkVg==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + + '@eslint-community/eslint-utils@4.4.1': + resolution: {integrity: sha512-s3O3waFUrMV8P/XaF/+ZTp1X9XBZW1a4B97ZnjQF2KYWaFD2A8KyFBsrsfSjEmjn3RGWAIuvlneuZm3CUK3jbA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 + + '@eslint-community/regexpp@4.12.1': + resolution: {integrity: sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==} + engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} + + '@eslint/config-array@0.19.2': + resolution: {integrity: sha512-GNKqxfHG2ySmJOBSHg7LxeUx4xpuCoFjacmlCoYWEbaPXLwvfIjixRI12xCQZeULksQb23uiA8F40w5TojpV7w==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/config-helpers@0.1.0': + resolution: {integrity: sha512-kLrdPDJE1ckPo94kmPPf9Hfd0DU0Jw6oKYrhe+pwSC0iTUInmTa+w6fw8sGgcfkFJGNdWOUeOaDM4quW4a7OkA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/core@0.12.0': + resolution: {integrity: sha512-cmrR6pytBuSMTaBweKoGMwu3EiHiEC+DoyupPmlZ0HxBJBtIxwe+j/E4XPIKNx+Q74c8lXKPwYawBf5glsTkHg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/eslintrc@3.3.0': + resolution: {integrity: sha512-yaVPAiNAalnCZedKLdR21GOGILMLKPyqSLWaAjQFvYA2i/ciDi8ArYVr69Anohb6cH2Ukhqti4aFnYyPm8wdwQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/js@9.22.0': + resolution: {integrity: sha512-vLFajx9o8d1/oL2ZkpMYbkLv8nDB6yaIwFNt7nI4+I80U/z03SxmfOMsLbvWr3p7C+Wnoh//aOu2pQW8cS0HCQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/object-schema@2.1.6': + resolution: {integrity: sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/plugin-kit@0.2.7': + resolution: {integrity: sha512-JubJ5B2pJ4k4yGxaNLdbjrnk9d/iDz6/q8wOilpIowd6PJPgaxCuHBnBszq7Ce2TyMrywm5r4PnKm6V3iiZF+g==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@humanfs/core@0.19.1': + resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==} + engines: {node: '>=18.18.0'} + + '@humanfs/node@0.16.6': + resolution: {integrity: sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==} + engines: {node: '>=18.18.0'} + + '@humanwhocodes/module-importer@1.0.1': + resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} + engines: {node: '>=12.22'} + + '@humanwhocodes/retry@0.3.1': + resolution: {integrity: sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==} + engines: {node: '>=18.18'} + + '@humanwhocodes/retry@0.4.2': + resolution: {integrity: sha512-xeO57FpIu4p1Ri3Jq/EXq4ClRm86dVF2z/+kvFnyqVYRavTZmaFaUBbWCOuuTh0o/g7DSsk6kc2vrS4Vl5oPOQ==} + engines: {node: '>=18.18'} + + '@nodelib/fs.scandir@2.1.5': + resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} + engines: {node: '>= 8'} + + '@nodelib/fs.stat@2.0.5': + resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} + engines: {node: '>= 8'} + + '@nodelib/fs.walk@1.2.8': + resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} + engines: {node: '>= 8'} + + '@rollup/rollup-android-arm-eabi@4.35.0': + resolution: {integrity: sha512-uYQ2WfPaqz5QtVgMxfN6NpLD+no0MYHDBywl7itPYd3K5TjjSghNKmX8ic9S8NU8w81NVhJv/XojcHptRly7qQ==} + cpu: [arm] + os: [android] + + '@rollup/rollup-android-arm64@4.35.0': + resolution: {integrity: sha512-FtKddj9XZudurLhdJnBl9fl6BwCJ3ky8riCXjEw3/UIbjmIY58ppWwPEvU3fNu+W7FUsAsB1CdH+7EQE6CXAPA==} + cpu: [arm64] + os: [android] + + '@rollup/rollup-darwin-arm64@4.35.0': + resolution: {integrity: sha512-Uk+GjOJR6CY844/q6r5DR/6lkPFOw0hjfOIzVx22THJXMxktXG6CbejseJFznU8vHcEBLpiXKY3/6xc+cBm65Q==} + cpu: [arm64] + os: [darwin] + + '@rollup/rollup-darwin-x64@4.35.0': + resolution: {integrity: sha512-3IrHjfAS6Vkp+5bISNQnPogRAW5GAV1n+bNCrDwXmfMHbPl5EhTmWtfmwlJxFRUCBZ+tZ/OxDyU08aF6NI/N5Q==} + cpu: [x64] + os: [darwin] + + '@rollup/rollup-freebsd-arm64@4.35.0': + resolution: {integrity: sha512-sxjoD/6F9cDLSELuLNnY0fOrM9WA0KrM0vWm57XhrIMf5FGiN8D0l7fn+bpUeBSU7dCgPV2oX4zHAsAXyHFGcQ==} + cpu: [arm64] + os: [freebsd] + + '@rollup/rollup-freebsd-x64@4.35.0': + resolution: {integrity: sha512-2mpHCeRuD1u/2kruUiHSsnjWtHjqVbzhBkNVQ1aVD63CcexKVcQGwJ2g5VphOd84GvxfSvnnlEyBtQCE5hxVVw==} + cpu: [x64] + os: [freebsd] + + '@rollup/rollup-linux-arm-gnueabihf@4.35.0': + resolution: {integrity: sha512-mrA0v3QMy6ZSvEuLs0dMxcO2LnaCONs1Z73GUDBHWbY8tFFocM6yl7YyMu7rz4zS81NDSqhrUuolyZXGi8TEqg==} + cpu: [arm] + os: [linux] + + '@rollup/rollup-linux-arm-musleabihf@4.35.0': + resolution: {integrity: sha512-DnYhhzcvTAKNexIql8pFajr0PiDGrIsBYPRvCKlA5ixSS3uwo/CWNZxB09jhIapEIg945KOzcYEAGGSmTSpk7A==} + cpu: [arm] + os: [linux] + + '@rollup/rollup-linux-arm64-gnu@4.35.0': + resolution: {integrity: sha512-uagpnH2M2g2b5iLsCTZ35CL1FgyuzzJQ8L9VtlJ+FckBXroTwNOaD0z0/UF+k5K3aNQjbm8LIVpxykUOQt1m/A==} + cpu: [arm64] + os: [linux] + + '@rollup/rollup-linux-arm64-musl@4.35.0': + resolution: {integrity: sha512-XQxVOCd6VJeHQA/7YcqyV0/88N6ysSVzRjJ9I9UA/xXpEsjvAgDTgH3wQYz5bmr7SPtVK2TsP2fQ2N9L4ukoUg==} + cpu: [arm64] + os: [linux] + + '@rollup/rollup-linux-loongarch64-gnu@4.35.0': + resolution: {integrity: sha512-5pMT5PzfgwcXEwOaSrqVsz/LvjDZt+vQ8RT/70yhPU06PTuq8WaHhfT1LW+cdD7mW6i/J5/XIkX/1tCAkh1W6g==} + cpu: [loong64] + os: [linux] + + '@rollup/rollup-linux-powerpc64le-gnu@4.35.0': + resolution: {integrity: sha512-c+zkcvbhbXF98f4CtEIP1EBA/lCic5xB0lToneZYvMeKu5Kamq3O8gqrxiYYLzlZH6E3Aq+TSW86E4ay8iD8EA==} + cpu: [ppc64] + os: [linux] + + '@rollup/rollup-linux-riscv64-gnu@4.35.0': + resolution: {integrity: sha512-s91fuAHdOwH/Tad2tzTtPX7UZyytHIRR6V4+2IGlV0Cej5rkG0R61SX4l4y9sh0JBibMiploZx3oHKPnQBKe4g==} + cpu: [riscv64] + os: [linux] + + '@rollup/rollup-linux-s390x-gnu@4.35.0': + resolution: {integrity: sha512-hQRkPQPLYJZYGP+Hj4fR9dDBMIM7zrzJDWFEMPdTnTy95Ljnv0/4w/ixFw3pTBMEuuEuoqtBINYND4M7ujcuQw==} + cpu: [s390x] + os: [linux] + + '@rollup/rollup-linux-x64-gnu@4.35.0': + resolution: {integrity: sha512-Pim1T8rXOri+0HmV4CdKSGrqcBWX0d1HoPnQ0uw0bdp1aP5SdQVNBy8LjYncvnLgu3fnnCt17xjWGd4cqh8/hA==} + cpu: [x64] + os: [linux] + + '@rollup/rollup-linux-x64-musl@4.35.0': + resolution: {integrity: sha512-QysqXzYiDvQWfUiTm8XmJNO2zm9yC9P/2Gkrwg2dH9cxotQzunBHYr6jk4SujCTqnfGxduOmQcI7c2ryuW8XVg==} + cpu: [x64] + os: [linux] + + '@rollup/rollup-win32-arm64-msvc@4.35.0': + resolution: {integrity: sha512-OUOlGqPkVJCdJETKOCEf1mw848ZyJ5w50/rZ/3IBQVdLfR5jk/6Sr5m3iO2tdPgwo0x7VcncYuOvMhBWZq8ayg==} + cpu: [arm64] + os: [win32] + + '@rollup/rollup-win32-ia32-msvc@4.35.0': + resolution: {integrity: sha512-2/lsgejMrtwQe44glq7AFFHLfJBPafpsTa6JvP2NGef/ifOa4KBoglVf7AKN7EV9o32evBPRqfg96fEHzWo5kw==} + cpu: [ia32] + os: [win32] + + '@rollup/rollup-win32-x64-msvc@4.35.0': + resolution: {integrity: sha512-PIQeY5XDkrOysbQblSW7v3l1MDZzkTEzAfTPkj5VAu3FW8fS4ynyLg2sINp0fp3SjZ8xkRYpLqoKcYqAkhU1dw==} + cpu: [x64] + os: [win32] + + '@swc/core-darwin-arm64@1.11.8': + resolution: {integrity: sha512-rrSsunyJWpHN+5V1zumndwSSifmIeFQBK9i2RMQQp15PgbgUNxHK5qoET1n20pcUrmZeT6jmJaEWlQchkV//Og==} + engines: {node: '>=10'} + cpu: [arm64] + os: [darwin] + + '@swc/core-darwin-x64@1.11.8': + resolution: {integrity: sha512-44goLqQuuo0HgWnG8qC+ZFw/qnjCVVeqffhzFr9WAXXotogVaxM8ze6egE58VWrfEc8me8yCcxOYL9RbtjhS/Q==} + engines: {node: '>=10'} + cpu: [x64] + os: [darwin] + + '@swc/core-linux-arm-gnueabihf@1.11.8': + resolution: {integrity: sha512-Mzo8umKlhTWwF1v8SLuTM1z2A+P43UVhf4R8RZDhzIRBuB2NkeyE+c0gexIOJBuGSIATryuAF4O4luDu727D1w==} + engines: {node: '>=10'} + cpu: [arm] + os: [linux] + + '@swc/core-linux-arm64-gnu@1.11.8': + resolution: {integrity: sha512-EyhO6U+QdoGYC1MeHOR0pyaaSaKYyNuT4FQNZ1eZIbnuueXpuICC7iNmLIOfr3LE5bVWcZ7NKGVPlM2StJEcgA==} + engines: {node: '>=10'} + cpu: [arm64] + os: [linux] + + '@swc/core-linux-arm64-musl@1.11.8': + resolution: {integrity: sha512-QU6wOkZnS6/QuBN1MHD6G2BgFxB0AclvTVGbqYkRA7MsVkcC29PffESqzTXnypzB252/XkhQjoB2JIt9rPYf6A==} + engines: {node: '>=10'} + cpu: [arm64] + os: [linux] + + '@swc/core-linux-x64-gnu@1.11.8': + resolution: {integrity: sha512-r72onUEIU1iJi9EUws3R28pztQ/eM3EshNpsPRBfuLwKy+qn3et55vXOyDhIjGCUph5Eg2Yn8H3h6MTxDdLd+w==} + engines: {node: '>=10'} + cpu: [x64] + os: [linux] + + '@swc/core-linux-x64-musl@1.11.8': + resolution: {integrity: sha512-294k8cLpO103++f4ZUEDr3vnBeUfPitW6G0a3qeVZuoXFhFgaW7ANZIWknUc14WiLOMfMecphJAEiy9C8OeYSw==} + engines: {node: '>=10'} + cpu: [x64] + os: [linux] + + '@swc/core-win32-arm64-msvc@1.11.8': + resolution: {integrity: sha512-EbjOzQ+B85rumHyeesBYxZ+hq3ZQn+YAAT1ZNE9xW1/8SuLoBmHy/K9YniRGVDq/2NRmp5kI5+5h5TX0asIS9A==} + engines: {node: '>=10'} + cpu: [arm64] + os: [win32] + + '@swc/core-win32-ia32-msvc@1.11.8': + resolution: {integrity: sha512-Z+FF5kgLHfQWIZ1KPdeInToXLzbY0sMAashjd/igKeP1Lz0qKXVAK+rpn6ASJi85Fn8wTftCGCyQUkRVn0bTDg==} + engines: {node: '>=10'} + cpu: [ia32] + os: [win32] + + '@swc/core-win32-x64-msvc@1.11.8': + resolution: {integrity: sha512-j6B6N0hChCeAISS6xp/hh6zR5CSCr037BAjCxNLsT8TGe5D+gYZ57heswUWXRH8eMKiRDGiLCYpPB2pkTqxCSw==} + engines: {node: '>=10'} + cpu: [x64] + os: [win32] + + '@swc/core@1.11.8': + resolution: {integrity: sha512-UAL+EULxrc0J73flwYHfu29mO8CONpDJiQv1QPDXsyCvDUcEhqAqUROVTgC+wtJCFFqMQdyr4stAA5/s0KSOmA==} + engines: {node: '>=10'} + peerDependencies: + '@swc/helpers': '*' + peerDependenciesMeta: + '@swc/helpers': + optional: true + + '@swc/counter@0.1.3': + resolution: {integrity: sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==} + + '@swc/types@0.1.19': + resolution: {integrity: sha512-WkAZaAfj44kh/UFdAQcrMP1I0nwRqpt27u+08LMBYMqmQfwwMofYoMh/48NGkMMRfC4ynpfwRbJuu8ErfNloeA==} + + '@types/estree@1.0.6': + resolution: {integrity: sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==} + + '@types/json-schema@7.0.15': + resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} + + '@types/react-dom@19.0.4': + resolution: {integrity: sha512-4fSQ8vWFkg+TGhePfUzVmat3eC14TXYSsiiDSLI0dVLsrm9gZFABjPy/Qu6TKgl1tq1Bu1yDsuQgY3A3DOjCcg==} + peerDependencies: + '@types/react': ^19.0.0 + + '@types/react@19.0.10': + resolution: {integrity: sha512-JuRQ9KXLEjaUNjTWpzuR231Z2WpIwczOkBEIvbHNCzQefFIT0L8IqE6NV6ULLyC1SI/i234JnDoMkfg+RjQj2g==} + + '@typescript-eslint/eslint-plugin@8.26.0': + resolution: {integrity: sha512-cLr1J6pe56zjKYajK6SSSre6nl1Gj6xDp1TY0trpgPzjVbgDwd09v2Ws37LABxzkicmUjhEeg/fAUjPJJB1v5Q==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + '@typescript-eslint/parser': ^8.0.0 || ^8.0.0-alpha.0 + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <5.9.0' + + '@typescript-eslint/parser@8.26.0': + resolution: {integrity: sha512-mNtXP9LTVBy14ZF3o7JG69gRPBK/2QWtQd0j0oH26HcY/foyJJau6pNUez7QrM5UHnSvwlQcJXKsk0I99B9pOA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <5.9.0' + + '@typescript-eslint/scope-manager@8.26.0': + resolution: {integrity: sha512-E0ntLvsfPqnPwng8b8y4OGuzh/iIOm2z8U3S9zic2TeMLW61u5IH2Q1wu0oSTkfrSzwbDJIB/Lm8O3//8BWMPA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@typescript-eslint/type-utils@8.26.0': + resolution: {integrity: sha512-ruk0RNChLKz3zKGn2LwXuVoeBcUMh+jaqzN461uMMdxy5H9epZqIBtYj7UiPXRuOpaALXGbmRuZQhmwHhaS04Q==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <5.9.0' + + '@typescript-eslint/types@8.26.0': + resolution: {integrity: sha512-89B1eP3tnpr9A8L6PZlSjBvnJhWXtYfZhECqlBl1D9Lme9mHO6iWlsprBtVenQvY1HMhax1mWOjhtL3fh/u+pA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@typescript-eslint/typescript-estree@8.26.0': + resolution: {integrity: sha512-tiJ1Hvy/V/oMVRTbEOIeemA2XoylimlDQ03CgPPNaHYZbpsc78Hmngnt+WXZfJX1pjQ711V7g0H7cSJThGYfPQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <5.9.0' + + '@typescript-eslint/utils@8.26.0': + resolution: {integrity: sha512-2L2tU3FVwhvU14LndnQCA2frYC8JnPDVKyQtWFPf8IYFMt/ykEN1bPolNhNbCVgOmdzTlWdusCTKA/9nKrf8Ig==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <5.9.0' + + '@typescript-eslint/visitor-keys@8.26.0': + resolution: {integrity: sha512-2z8JQJWAzPdDd51dRQ/oqIJxe99/hoLIqmf8RMCAJQtYDc535W/Jt2+RTP4bP0aKeBG1F65yjIZuczOXCmbWwg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@vitejs/plugin-react-swc@3.8.0': + resolution: {integrity: sha512-T4sHPvS+DIqDP51ifPqa9XIRAz/kIvIi8oXcnOZZgHmMotgmmdxe/DD5tMFlt5nuIRzT0/QuiwmKlH0503Aapw==} + peerDependencies: + vite: ^4 || ^5 || ^6 + + acorn-jsx@5.3.2: + resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} + peerDependencies: + acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + + acorn@8.14.1: + resolution: {integrity: sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==} + engines: {node: '>=0.4.0'} + hasBin: true + + ajv@6.12.6: + resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} + + ansi-styles@4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} + + argparse@2.0.1: + resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + + balanced-match@1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + + brace-expansion@1.1.11: + resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} + + brace-expansion@2.0.1: + resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} + + braces@3.0.3: + resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} + engines: {node: '>=8'} + + callsites@3.1.0: + resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} + engines: {node: '>=6'} + + chalk@4.1.2: + resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} + engines: {node: '>=10'} + + color-convert@2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} + + color-name@1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + + concat-map@0.0.1: + resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + + cross-spawn@7.0.6: + resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} + engines: {node: '>= 8'} + + csstype@3.1.3: + resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} + + debug@4.4.0: + resolution: {integrity: sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + deep-is@0.1.4: + resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} + + esbuild@0.25.1: + resolution: {integrity: sha512-BGO5LtrGC7vxnqucAe/rmvKdJllfGaYWdyABvyMoXQlfYMb2bbRuReWR5tEGE//4LcNJj9XrkovTqNYRFZHAMQ==} + engines: {node: '>=18'} + hasBin: true + + escape-string-regexp@4.0.0: + resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} + engines: {node: '>=10'} + + eslint-plugin-react-hooks@5.2.0: + resolution: {integrity: sha512-+f15FfK64YQwZdJNELETdn5ibXEUQmW1DZL6KXhNnc2heoy/sg9VJJeT7n8TlMWouzWqSWavFkIhHyIbIAEapg==} + engines: {node: '>=10'} + peerDependencies: + eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0 + + eslint-plugin-react-refresh@0.4.19: + resolution: {integrity: sha512-eyy8pcr/YxSYjBoqIFSrlbn9i/xvxUFa8CjzAYo9cFjgGXqq1hyjihcpZvxRLalpaWmueWR81xn7vuKmAFijDQ==} + peerDependencies: + eslint: '>=8.40' + + eslint-scope@8.3.0: + resolution: {integrity: sha512-pUNxi75F8MJ/GdeKtVLSbYg4ZI34J6C0C7sbL4YOp2exGwen7ZsuBqKzUhXd0qMQ362yET3z+uPwKeg/0C2XCQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + eslint-visitor-keys@3.4.3: + resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + eslint-visitor-keys@4.2.0: + resolution: {integrity: sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + eslint@9.22.0: + resolution: {integrity: sha512-9V/QURhsRN40xuHXWjV64yvrzMjcz7ZyNoF2jJFmy9j/SLk0u1OLSZgXi28MrXjymnjEGSR80WCdab3RGMDveQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + hasBin: true + peerDependencies: + jiti: '*' + peerDependenciesMeta: + jiti: + optional: true + + espree@10.3.0: + resolution: {integrity: sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + esquery@1.6.0: + resolution: {integrity: sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==} + engines: {node: '>=0.10'} + + esrecurse@4.3.0: + resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} + engines: {node: '>=4.0'} + + estraverse@5.3.0: + resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} + engines: {node: '>=4.0'} + + esutils@2.0.3: + resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} + engines: {node: '>=0.10.0'} + + fast-deep-equal@3.1.3: + resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + + fast-glob@3.3.3: + resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==} + engines: {node: '>=8.6.0'} + + fast-json-stable-stringify@2.1.0: + resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} + + fast-levenshtein@2.0.6: + resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} + + fastq@1.19.1: + resolution: {integrity: sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==} + + file-entry-cache@8.0.0: + resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} + engines: {node: '>=16.0.0'} + + fill-range@7.1.1: + resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} + engines: {node: '>=8'} + + find-up@5.0.0: + resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} + engines: {node: '>=10'} + + flat-cache@4.0.1: + resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==} + engines: {node: '>=16'} + + flatted@3.3.3: + resolution: {integrity: sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==} + + fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + + glob-parent@5.1.2: + resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} + engines: {node: '>= 6'} + + glob-parent@6.0.2: + resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} + engines: {node: '>=10.13.0'} + + globals@14.0.0: + resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==} + engines: {node: '>=18'} + + globals@15.15.0: + resolution: {integrity: sha512-7ACyT3wmyp3I61S4fG682L0VA2RGD9otkqGJIwNUMF1SWUombIIk+af1unuDYgMm082aHYwD+mzJvv9Iu8dsgg==} + engines: {node: '>=18'} + + graphemer@1.4.0: + resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} + + has-flag@4.0.0: + resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} + engines: {node: '>=8'} + + ignore@5.3.2: + resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} + engines: {node: '>= 4'} + + import-fresh@3.3.1: + resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==} + engines: {node: '>=6'} + + imurmurhash@0.1.4: + resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} + engines: {node: '>=0.8.19'} + + is-extglob@2.1.1: + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} + engines: {node: '>=0.10.0'} + + is-glob@4.0.3: + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} + engines: {node: '>=0.10.0'} + + is-number@7.0.0: + resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} + engines: {node: '>=0.12.0'} + + isexe@2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + + js-yaml@4.1.0: + resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} + hasBin: true + + json-buffer@3.0.1: + resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} + + json-schema-traverse@0.4.1: + resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} + + json-stable-stringify-without-jsonify@1.0.1: + resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} + + keyv@4.5.4: + resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} + + levn@0.4.1: + resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} + engines: {node: '>= 0.8.0'} + + locate-path@6.0.0: + resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} + engines: {node: '>=10'} + + lodash.merge@4.6.2: + resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} + + merge2@1.4.1: + resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} + engines: {node: '>= 8'} + + micromatch@4.0.8: + resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} + engines: {node: '>=8.6'} + + minimatch@3.1.2: + resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} + + minimatch@9.0.5: + resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} + engines: {node: '>=16 || 14 >=14.17'} + + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + + nanoid@3.3.9: + resolution: {integrity: sha512-SppoicMGpZvbF1l3z4x7No3OlIjP7QJvC9XR7AhZr1kL133KHnKPztkKDc+Ir4aJ/1VhTySrtKhrsycmrMQfvg==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + + natural-compare@1.4.0: + resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} + + optionator@0.9.4: + resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} + engines: {node: '>= 0.8.0'} + + p-limit@3.1.0: + resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} + engines: {node: '>=10'} + + p-locate@5.0.0: + resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} + engines: {node: '>=10'} + + parent-module@1.0.1: + resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} + engines: {node: '>=6'} + + path-exists@4.0.0: + resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} + engines: {node: '>=8'} + + path-key@3.1.1: + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} + engines: {node: '>=8'} + + picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + + picomatch@2.3.1: + resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} + engines: {node: '>=8.6'} + + postcss@8.5.3: + resolution: {integrity: sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==} + engines: {node: ^10 || ^12 || >=14} + + prelude-ls@1.2.1: + resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} + engines: {node: '>= 0.8.0'} + + punycode@2.3.1: + resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} + engines: {node: '>=6'} + + queue-microtask@1.2.3: + resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + + react-dom@19.0.0: + resolution: {integrity: sha512-4GV5sHFG0e/0AD4X+ySy6UJd3jVl1iNsNHdpad0qhABJ11twS3TTBnseqsKurKcsNqCEFeGL3uLpVChpIO3QfQ==} + peerDependencies: + react: ^19.0.0 + + react@19.0.0: + resolution: {integrity: sha512-V8AVnmPIICiWpGfm6GLzCR/W5FXLchHop40W4nXBmdlEceh16rCN8O8LNWm5bh5XUX91fh7KpA+W0TgMKmgTpQ==} + engines: {node: '>=0.10.0'} + + resolve-from@4.0.0: + resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} + engines: {node: '>=4'} + + reusify@1.1.0: + resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} + engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + + rollup@4.35.0: + resolution: {integrity: sha512-kg6oI4g+vc41vePJyO6dHt/yl0Rz3Thv0kJeVQ3D1kS3E5XSuKbPc29G4IpT/Kv1KQwgHVcN+HtyS+HYLNSvQg==} + engines: {node: '>=18.0.0', npm: '>=8.0.0'} + hasBin: true + + run-parallel@1.2.0: + resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + + scheduler@0.25.0: + resolution: {integrity: sha512-xFVuu11jh+xcO7JOAGJNOXld8/TcEHK/4CituBUeUb5hqxJLj9YuemAEuvm9gQ/+pgXYfbQuqAkiYu+u7YEsNA==} + + semver@7.7.1: + resolution: {integrity: sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==} + engines: {node: '>=10'} + hasBin: true + + shebang-command@2.0.0: + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} + engines: {node: '>=8'} + + shebang-regex@3.0.0: + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} + engines: {node: '>=8'} + + source-map-js@1.2.1: + resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} + engines: {node: '>=0.10.0'} + + strip-json-comments@3.1.1: + resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} + engines: {node: '>=8'} + + supports-color@7.2.0: + resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} + engines: {node: '>=8'} + + to-regex-range@5.0.1: + resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} + engines: {node: '>=8.0'} + + ts-api-utils@2.0.1: + resolution: {integrity: sha512-dnlgjFSVetynI8nzgJ+qF62efpglpWRk8isUEWZGWlJYySCTD6aKvbUDu+zbPeDakk3bg5H4XpitHukgfL1m9w==} + engines: {node: '>=18.12'} + peerDependencies: + typescript: '>=4.8.4' + + type-check@0.4.0: + resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} + engines: {node: '>= 0.8.0'} + + typescript-eslint@8.26.0: + resolution: {integrity: sha512-PtVz9nAnuNJuAVeUFvwztjuUgSnJInODAUx47VDwWPXzd5vismPOtPtt83tzNXyOjVQbPRp786D6WFW/M2koIA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <5.9.0' + + typescript@5.7.3: + resolution: {integrity: sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==} + engines: {node: '>=14.17'} + hasBin: true + + uri-js@4.4.1: + resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + + vite@6.2.1: + resolution: {integrity: sha512-n2GnqDb6XPhlt9B8olZPrgMD/es/Nd1RdChF6CBD/fHW6pUyUTt2sQW2fPRX5GiD9XEa6+8A6A4f2vT6pSsE7Q==} + engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} + hasBin: true + peerDependencies: + '@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0 + jiti: '>=1.21.0' + less: '*' + lightningcss: ^1.21.0 + sass: '*' + sass-embedded: '*' + stylus: '*' + sugarss: '*' + terser: ^5.16.0 + tsx: ^4.8.1 + yaml: ^2.4.2 + peerDependenciesMeta: + '@types/node': + optional: true + jiti: + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + tsx: + optional: true + yaml: + optional: true + + which@2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} + hasBin: true + + word-wrap@1.2.5: + resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} + engines: {node: '>=0.10.0'} + + yocto-queue@0.1.0: + resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} + engines: {node: '>=10'} + +snapshots: + + '@esbuild/aix-ppc64@0.25.1': + optional: true + + '@esbuild/android-arm64@0.25.1': + optional: true + + '@esbuild/android-arm@0.25.1': + optional: true + + '@esbuild/android-x64@0.25.1': + optional: true + + '@esbuild/darwin-arm64@0.25.1': + optional: true + + '@esbuild/darwin-x64@0.25.1': + optional: true + + '@esbuild/freebsd-arm64@0.25.1': + optional: true + + '@esbuild/freebsd-x64@0.25.1': + optional: true + + '@esbuild/linux-arm64@0.25.1': + optional: true + + '@esbuild/linux-arm@0.25.1': + optional: true + + '@esbuild/linux-ia32@0.25.1': + optional: true + + '@esbuild/linux-loong64@0.25.1': + optional: true + + '@esbuild/linux-mips64el@0.25.1': + optional: true + + '@esbuild/linux-ppc64@0.25.1': + optional: true + + '@esbuild/linux-riscv64@0.25.1': + optional: true + + '@esbuild/linux-s390x@0.25.1': + optional: true + + '@esbuild/linux-x64@0.25.1': + optional: true + + '@esbuild/netbsd-arm64@0.25.1': + optional: true + + '@esbuild/netbsd-x64@0.25.1': + optional: true + + '@esbuild/openbsd-arm64@0.25.1': + optional: true + + '@esbuild/openbsd-x64@0.25.1': + optional: true + + '@esbuild/sunos-x64@0.25.1': + optional: true + + '@esbuild/win32-arm64@0.25.1': + optional: true + + '@esbuild/win32-ia32@0.25.1': + optional: true + + '@esbuild/win32-x64@0.25.1': + optional: true + + '@eslint-community/eslint-utils@4.4.1(eslint@9.22.0)': + dependencies: + eslint: 9.22.0 + eslint-visitor-keys: 3.4.3 + + '@eslint-community/regexpp@4.12.1': {} + + '@eslint/config-array@0.19.2': + dependencies: + '@eslint/object-schema': 2.1.6 + debug: 4.4.0 + minimatch: 3.1.2 + transitivePeerDependencies: + - supports-color + + '@eslint/config-helpers@0.1.0': {} + + '@eslint/core@0.12.0': + dependencies: + '@types/json-schema': 7.0.15 + + '@eslint/eslintrc@3.3.0': + dependencies: + ajv: 6.12.6 + debug: 4.4.0 + espree: 10.3.0 + globals: 14.0.0 + ignore: 5.3.2 + import-fresh: 3.3.1 + js-yaml: 4.1.0 + minimatch: 3.1.2 + strip-json-comments: 3.1.1 + transitivePeerDependencies: + - supports-color + + '@eslint/js@9.22.0': {} + + '@eslint/object-schema@2.1.6': {} + + '@eslint/plugin-kit@0.2.7': + dependencies: + '@eslint/core': 0.12.0 + levn: 0.4.1 + + '@humanfs/core@0.19.1': {} + + '@humanfs/node@0.16.6': + dependencies: + '@humanfs/core': 0.19.1 + '@humanwhocodes/retry': 0.3.1 + + '@humanwhocodes/module-importer@1.0.1': {} + + '@humanwhocodes/retry@0.3.1': {} + + '@humanwhocodes/retry@0.4.2': {} + + '@nodelib/fs.scandir@2.1.5': + dependencies: + '@nodelib/fs.stat': 2.0.5 + run-parallel: 1.2.0 + + '@nodelib/fs.stat@2.0.5': {} + + '@nodelib/fs.walk@1.2.8': + dependencies: + '@nodelib/fs.scandir': 2.1.5 + fastq: 1.19.1 + + '@rollup/rollup-android-arm-eabi@4.35.0': + optional: true + + '@rollup/rollup-android-arm64@4.35.0': + optional: true + + '@rollup/rollup-darwin-arm64@4.35.0': + optional: true + + '@rollup/rollup-darwin-x64@4.35.0': + optional: true + + '@rollup/rollup-freebsd-arm64@4.35.0': + optional: true + + '@rollup/rollup-freebsd-x64@4.35.0': + optional: true + + '@rollup/rollup-linux-arm-gnueabihf@4.35.0': + optional: true + + '@rollup/rollup-linux-arm-musleabihf@4.35.0': + optional: true + + '@rollup/rollup-linux-arm64-gnu@4.35.0': + optional: true + + '@rollup/rollup-linux-arm64-musl@4.35.0': + optional: true + + '@rollup/rollup-linux-loongarch64-gnu@4.35.0': + optional: true + + '@rollup/rollup-linux-powerpc64le-gnu@4.35.0': + optional: true + + '@rollup/rollup-linux-riscv64-gnu@4.35.0': + optional: true + + '@rollup/rollup-linux-s390x-gnu@4.35.0': + optional: true + + '@rollup/rollup-linux-x64-gnu@4.35.0': + optional: true + + '@rollup/rollup-linux-x64-musl@4.35.0': + optional: true + + '@rollup/rollup-win32-arm64-msvc@4.35.0': + optional: true + + '@rollup/rollup-win32-ia32-msvc@4.35.0': + optional: true + + '@rollup/rollup-win32-x64-msvc@4.35.0': + optional: true + + '@swc/core-darwin-arm64@1.11.8': + optional: true + + '@swc/core-darwin-x64@1.11.8': + optional: true + + '@swc/core-linux-arm-gnueabihf@1.11.8': + optional: true + + '@swc/core-linux-arm64-gnu@1.11.8': + optional: true + + '@swc/core-linux-arm64-musl@1.11.8': + optional: true + + '@swc/core-linux-x64-gnu@1.11.8': + optional: true + + '@swc/core-linux-x64-musl@1.11.8': + optional: true + + '@swc/core-win32-arm64-msvc@1.11.8': + optional: true + + '@swc/core-win32-ia32-msvc@1.11.8': + optional: true + + '@swc/core-win32-x64-msvc@1.11.8': + optional: true + + '@swc/core@1.11.8': + dependencies: + '@swc/counter': 0.1.3 + '@swc/types': 0.1.19 + optionalDependencies: + '@swc/core-darwin-arm64': 1.11.8 + '@swc/core-darwin-x64': 1.11.8 + '@swc/core-linux-arm-gnueabihf': 1.11.8 + '@swc/core-linux-arm64-gnu': 1.11.8 + '@swc/core-linux-arm64-musl': 1.11.8 + '@swc/core-linux-x64-gnu': 1.11.8 + '@swc/core-linux-x64-musl': 1.11.8 + '@swc/core-win32-arm64-msvc': 1.11.8 + '@swc/core-win32-ia32-msvc': 1.11.8 + '@swc/core-win32-x64-msvc': 1.11.8 + + '@swc/counter@0.1.3': {} + + '@swc/types@0.1.19': + dependencies: + '@swc/counter': 0.1.3 + + '@types/estree@1.0.6': {} + + '@types/json-schema@7.0.15': {} + + '@types/react-dom@19.0.4(@types/react@19.0.10)': + dependencies: + '@types/react': 19.0.10 + + '@types/react@19.0.10': + dependencies: + csstype: 3.1.3 + + '@typescript-eslint/eslint-plugin@8.26.0(@typescript-eslint/parser@8.26.0(eslint@9.22.0)(typescript@5.7.3))(eslint@9.22.0)(typescript@5.7.3)': + dependencies: + '@eslint-community/regexpp': 4.12.1 + '@typescript-eslint/parser': 8.26.0(eslint@9.22.0)(typescript@5.7.3) + '@typescript-eslint/scope-manager': 8.26.0 + '@typescript-eslint/type-utils': 8.26.0(eslint@9.22.0)(typescript@5.7.3) + '@typescript-eslint/utils': 8.26.0(eslint@9.22.0)(typescript@5.7.3) + '@typescript-eslint/visitor-keys': 8.26.0 + eslint: 9.22.0 + graphemer: 1.4.0 + ignore: 5.3.2 + natural-compare: 1.4.0 + ts-api-utils: 2.0.1(typescript@5.7.3) + typescript: 5.7.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/parser@8.26.0(eslint@9.22.0)(typescript@5.7.3)': + dependencies: + '@typescript-eslint/scope-manager': 8.26.0 + '@typescript-eslint/types': 8.26.0 + '@typescript-eslint/typescript-estree': 8.26.0(typescript@5.7.3) + '@typescript-eslint/visitor-keys': 8.26.0 + debug: 4.4.0 + eslint: 9.22.0 + typescript: 5.7.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/scope-manager@8.26.0': + dependencies: + '@typescript-eslint/types': 8.26.0 + '@typescript-eslint/visitor-keys': 8.26.0 + + '@typescript-eslint/type-utils@8.26.0(eslint@9.22.0)(typescript@5.7.3)': + dependencies: + '@typescript-eslint/typescript-estree': 8.26.0(typescript@5.7.3) + '@typescript-eslint/utils': 8.26.0(eslint@9.22.0)(typescript@5.7.3) + debug: 4.4.0 + eslint: 9.22.0 + ts-api-utils: 2.0.1(typescript@5.7.3) + typescript: 5.7.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/types@8.26.0': {} + + '@typescript-eslint/typescript-estree@8.26.0(typescript@5.7.3)': + dependencies: + '@typescript-eslint/types': 8.26.0 + '@typescript-eslint/visitor-keys': 8.26.0 + debug: 4.4.0 + fast-glob: 3.3.3 + is-glob: 4.0.3 + minimatch: 9.0.5 + semver: 7.7.1 + ts-api-utils: 2.0.1(typescript@5.7.3) + typescript: 5.7.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/utils@8.26.0(eslint@9.22.0)(typescript@5.7.3)': + dependencies: + '@eslint-community/eslint-utils': 4.4.1(eslint@9.22.0) + '@typescript-eslint/scope-manager': 8.26.0 + '@typescript-eslint/types': 8.26.0 + '@typescript-eslint/typescript-estree': 8.26.0(typescript@5.7.3) + eslint: 9.22.0 + typescript: 5.7.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/visitor-keys@8.26.0': + dependencies: + '@typescript-eslint/types': 8.26.0 + eslint-visitor-keys: 4.2.0 + + '@vitejs/plugin-react-swc@3.8.0(vite@6.2.1)': + dependencies: + '@swc/core': 1.11.8 + vite: 6.2.1 + transitivePeerDependencies: + - '@swc/helpers' + + acorn-jsx@5.3.2(acorn@8.14.1): + dependencies: + acorn: 8.14.1 + + acorn@8.14.1: {} + + ajv@6.12.6: + dependencies: + fast-deep-equal: 3.1.3 + fast-json-stable-stringify: 2.1.0 + json-schema-traverse: 0.4.1 + uri-js: 4.4.1 + + ansi-styles@4.3.0: + dependencies: + color-convert: 2.0.1 + + argparse@2.0.1: {} + + balanced-match@1.0.2: {} + + brace-expansion@1.1.11: + dependencies: + balanced-match: 1.0.2 + concat-map: 0.0.1 + + brace-expansion@2.0.1: + dependencies: + balanced-match: 1.0.2 + + braces@3.0.3: + dependencies: + fill-range: 7.1.1 + + callsites@3.1.0: {} + + chalk@4.1.2: + dependencies: + ansi-styles: 4.3.0 + supports-color: 7.2.0 + + color-convert@2.0.1: + dependencies: + color-name: 1.1.4 + + color-name@1.1.4: {} + + concat-map@0.0.1: {} + + cross-spawn@7.0.6: + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + + csstype@3.1.3: {} + + debug@4.4.0: + dependencies: + ms: 2.1.3 + + deep-is@0.1.4: {} + + esbuild@0.25.1: + optionalDependencies: + '@esbuild/aix-ppc64': 0.25.1 + '@esbuild/android-arm': 0.25.1 + '@esbuild/android-arm64': 0.25.1 + '@esbuild/android-x64': 0.25.1 + '@esbuild/darwin-arm64': 0.25.1 + '@esbuild/darwin-x64': 0.25.1 + '@esbuild/freebsd-arm64': 0.25.1 + '@esbuild/freebsd-x64': 0.25.1 + '@esbuild/linux-arm': 0.25.1 + '@esbuild/linux-arm64': 0.25.1 + '@esbuild/linux-ia32': 0.25.1 + '@esbuild/linux-loong64': 0.25.1 + '@esbuild/linux-mips64el': 0.25.1 + '@esbuild/linux-ppc64': 0.25.1 + '@esbuild/linux-riscv64': 0.25.1 + '@esbuild/linux-s390x': 0.25.1 + '@esbuild/linux-x64': 0.25.1 + '@esbuild/netbsd-arm64': 0.25.1 + '@esbuild/netbsd-x64': 0.25.1 + '@esbuild/openbsd-arm64': 0.25.1 + '@esbuild/openbsd-x64': 0.25.1 + '@esbuild/sunos-x64': 0.25.1 + '@esbuild/win32-arm64': 0.25.1 + '@esbuild/win32-ia32': 0.25.1 + '@esbuild/win32-x64': 0.25.1 + + escape-string-regexp@4.0.0: {} + + eslint-plugin-react-hooks@5.2.0(eslint@9.22.0): + dependencies: + eslint: 9.22.0 + + eslint-plugin-react-refresh@0.4.19(eslint@9.22.0): + dependencies: + eslint: 9.22.0 + + eslint-scope@8.3.0: + dependencies: + esrecurse: 4.3.0 + estraverse: 5.3.0 + + eslint-visitor-keys@3.4.3: {} + + eslint-visitor-keys@4.2.0: {} + + eslint@9.22.0: + dependencies: + '@eslint-community/eslint-utils': 4.4.1(eslint@9.22.0) + '@eslint-community/regexpp': 4.12.1 + '@eslint/config-array': 0.19.2 + '@eslint/config-helpers': 0.1.0 + '@eslint/core': 0.12.0 + '@eslint/eslintrc': 3.3.0 + '@eslint/js': 9.22.0 + '@eslint/plugin-kit': 0.2.7 + '@humanfs/node': 0.16.6 + '@humanwhocodes/module-importer': 1.0.1 + '@humanwhocodes/retry': 0.4.2 + '@types/estree': 1.0.6 + '@types/json-schema': 7.0.15 + ajv: 6.12.6 + chalk: 4.1.2 + cross-spawn: 7.0.6 + debug: 4.4.0 + escape-string-regexp: 4.0.0 + eslint-scope: 8.3.0 + eslint-visitor-keys: 4.2.0 + espree: 10.3.0 + esquery: 1.6.0 + esutils: 2.0.3 + fast-deep-equal: 3.1.3 + file-entry-cache: 8.0.0 + find-up: 5.0.0 + glob-parent: 6.0.2 + ignore: 5.3.2 + imurmurhash: 0.1.4 + is-glob: 4.0.3 + json-stable-stringify-without-jsonify: 1.0.1 + lodash.merge: 4.6.2 + minimatch: 3.1.2 + natural-compare: 1.4.0 + optionator: 0.9.4 + transitivePeerDependencies: + - supports-color + + espree@10.3.0: + dependencies: + acorn: 8.14.1 + acorn-jsx: 5.3.2(acorn@8.14.1) + eslint-visitor-keys: 4.2.0 + + esquery@1.6.0: + dependencies: + estraverse: 5.3.0 + + esrecurse@4.3.0: + dependencies: + estraverse: 5.3.0 + + estraverse@5.3.0: {} + + esutils@2.0.3: {} + + fast-deep-equal@3.1.3: {} + + fast-glob@3.3.3: + dependencies: + '@nodelib/fs.stat': 2.0.5 + '@nodelib/fs.walk': 1.2.8 + glob-parent: 5.1.2 + merge2: 1.4.1 + micromatch: 4.0.8 + + fast-json-stable-stringify@2.1.0: {} + + fast-levenshtein@2.0.6: {} + + fastq@1.19.1: + dependencies: + reusify: 1.1.0 + + file-entry-cache@8.0.0: + dependencies: + flat-cache: 4.0.1 + + fill-range@7.1.1: + dependencies: + to-regex-range: 5.0.1 + + find-up@5.0.0: + dependencies: + locate-path: 6.0.0 + path-exists: 4.0.0 + + flat-cache@4.0.1: + dependencies: + flatted: 3.3.3 + keyv: 4.5.4 + + flatted@3.3.3: {} + + fsevents@2.3.3: + optional: true + + glob-parent@5.1.2: + dependencies: + is-glob: 4.0.3 + + glob-parent@6.0.2: + dependencies: + is-glob: 4.0.3 + + globals@14.0.0: {} + + globals@15.15.0: {} + + graphemer@1.4.0: {} + + has-flag@4.0.0: {} + + ignore@5.3.2: {} + + import-fresh@3.3.1: + dependencies: + parent-module: 1.0.1 + resolve-from: 4.0.0 + + imurmurhash@0.1.4: {} + + is-extglob@2.1.1: {} + + is-glob@4.0.3: + dependencies: + is-extglob: 2.1.1 + + is-number@7.0.0: {} + + isexe@2.0.0: {} + + js-yaml@4.1.0: + dependencies: + argparse: 2.0.1 + + json-buffer@3.0.1: {} + + json-schema-traverse@0.4.1: {} + + json-stable-stringify-without-jsonify@1.0.1: {} + + keyv@4.5.4: + dependencies: + json-buffer: 3.0.1 + + levn@0.4.1: + dependencies: + prelude-ls: 1.2.1 + type-check: 0.4.0 + + locate-path@6.0.0: + dependencies: + p-locate: 5.0.0 + + lodash.merge@4.6.2: {} + + merge2@1.4.1: {} + + micromatch@4.0.8: + dependencies: + braces: 3.0.3 + picomatch: 2.3.1 + + minimatch@3.1.2: + dependencies: + brace-expansion: 1.1.11 + + minimatch@9.0.5: + dependencies: + brace-expansion: 2.0.1 + + ms@2.1.3: {} + + nanoid@3.3.9: {} + + natural-compare@1.4.0: {} + + optionator@0.9.4: + dependencies: + deep-is: 0.1.4 + fast-levenshtein: 2.0.6 + levn: 0.4.1 + prelude-ls: 1.2.1 + type-check: 0.4.0 + word-wrap: 1.2.5 + + p-limit@3.1.0: + dependencies: + yocto-queue: 0.1.0 + + p-locate@5.0.0: + dependencies: + p-limit: 3.1.0 + + parent-module@1.0.1: + dependencies: + callsites: 3.1.0 + + path-exists@4.0.0: {} + + path-key@3.1.1: {} + + picocolors@1.1.1: {} + + picomatch@2.3.1: {} + + postcss@8.5.3: + dependencies: + nanoid: 3.3.9 + picocolors: 1.1.1 + source-map-js: 1.2.1 + + prelude-ls@1.2.1: {} + + punycode@2.3.1: {} + + queue-microtask@1.2.3: {} + + react-dom@19.0.0(react@19.0.0): + dependencies: + react: 19.0.0 + scheduler: 0.25.0 + + react@19.0.0: {} + + resolve-from@4.0.0: {} + + reusify@1.1.0: {} + + rollup@4.35.0: + dependencies: + '@types/estree': 1.0.6 + optionalDependencies: + '@rollup/rollup-android-arm-eabi': 4.35.0 + '@rollup/rollup-android-arm64': 4.35.0 + '@rollup/rollup-darwin-arm64': 4.35.0 + '@rollup/rollup-darwin-x64': 4.35.0 + '@rollup/rollup-freebsd-arm64': 4.35.0 + '@rollup/rollup-freebsd-x64': 4.35.0 + '@rollup/rollup-linux-arm-gnueabihf': 4.35.0 + '@rollup/rollup-linux-arm-musleabihf': 4.35.0 + '@rollup/rollup-linux-arm64-gnu': 4.35.0 + '@rollup/rollup-linux-arm64-musl': 4.35.0 + '@rollup/rollup-linux-loongarch64-gnu': 4.35.0 + '@rollup/rollup-linux-powerpc64le-gnu': 4.35.0 + '@rollup/rollup-linux-riscv64-gnu': 4.35.0 + '@rollup/rollup-linux-s390x-gnu': 4.35.0 + '@rollup/rollup-linux-x64-gnu': 4.35.0 + '@rollup/rollup-linux-x64-musl': 4.35.0 + '@rollup/rollup-win32-arm64-msvc': 4.35.0 + '@rollup/rollup-win32-ia32-msvc': 4.35.0 + '@rollup/rollup-win32-x64-msvc': 4.35.0 + fsevents: 2.3.3 + + run-parallel@1.2.0: + dependencies: + queue-microtask: 1.2.3 + + scheduler@0.25.0: {} + + semver@7.7.1: {} + + shebang-command@2.0.0: + dependencies: + shebang-regex: 3.0.0 + + shebang-regex@3.0.0: {} + + source-map-js@1.2.1: {} + + strip-json-comments@3.1.1: {} + + supports-color@7.2.0: + dependencies: + has-flag: 4.0.0 + + to-regex-range@5.0.1: + dependencies: + is-number: 7.0.0 + + ts-api-utils@2.0.1(typescript@5.7.3): + dependencies: + typescript: 5.7.3 + + type-check@0.4.0: + dependencies: + prelude-ls: 1.2.1 + + typescript-eslint@8.26.0(eslint@9.22.0)(typescript@5.7.3): + dependencies: + '@typescript-eslint/eslint-plugin': 8.26.0(@typescript-eslint/parser@8.26.0(eslint@9.22.0)(typescript@5.7.3))(eslint@9.22.0)(typescript@5.7.3) + '@typescript-eslint/parser': 8.26.0(eslint@9.22.0)(typescript@5.7.3) + '@typescript-eslint/utils': 8.26.0(eslint@9.22.0)(typescript@5.7.3) + eslint: 9.22.0 + typescript: 5.7.3 + transitivePeerDependencies: + - supports-color + + typescript@5.7.3: {} + + uri-js@4.4.1: + dependencies: + punycode: 2.3.1 + + vite@6.2.1: + dependencies: + esbuild: 0.25.1 + postcss: 8.5.3 + rollup: 4.35.0 + optionalDependencies: + fsevents: 2.3.3 + + which@2.0.2: + dependencies: + isexe: 2.0.0 + + word-wrap@1.2.5: {} + + yocto-queue@0.1.0: {} diff --git a/public/vite.svg b/public/vite.svg new file mode 100644 index 00000000..e7b8dfb1 --- /dev/null +++ b/public/vite.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/App.css b/src/App.css new file mode 100644 index 00000000..b9d355df --- /dev/null +++ b/src/App.css @@ -0,0 +1,42 @@ +#root { + max-width: 1280px; + margin: 0 auto; + padding: 2rem; + text-align: center; +} + +.logo { + height: 6em; + padding: 1.5em; + will-change: filter; + transition: filter 300ms; +} +.logo:hover { + filter: drop-shadow(0 0 2em #646cffaa); +} +.logo.react:hover { + filter: drop-shadow(0 0 2em #61dafbaa); +} + +@keyframes logo-spin { + from { + transform: rotate(0deg); + } + to { + transform: rotate(360deg); + } +} + +@media (prefers-reduced-motion: no-preference) { + a:nth-of-type(2) .logo { + animation: logo-spin infinite 20s linear; + } +} + +.card { + padding: 2em; +} + +.read-the-docs { + color: #888; +} diff --git a/src/App.tsx b/src/App.tsx new file mode 100644 index 00000000..3d7ded3f --- /dev/null +++ b/src/App.tsx @@ -0,0 +1,35 @@ +import { useState } from 'react' +import reactLogo from './assets/react.svg' +import viteLogo from '/vite.svg' +import './App.css' + +function App() { + const [count, setCount] = useState(0) + + return ( + <> +
+ + Vite logo + + + React logo + +
+

Vite + React

+
+ +

+ Edit src/App.tsx and save to test HMR +

+
+

+ Click on the Vite and React logos to learn more +

+ + ) +} + +export default App diff --git a/src/assets/react.svg b/src/assets/react.svg new file mode 100644 index 00000000..6c87de9b --- /dev/null +++ b/src/assets/react.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/index.css b/src/index.css new file mode 100644 index 00000000..08a3ac9e --- /dev/null +++ b/src/index.css @@ -0,0 +1,68 @@ +:root { + font-family: system-ui, Avenir, Helvetica, Arial, sans-serif; + line-height: 1.5; + font-weight: 400; + + color-scheme: light dark; + color: rgba(255, 255, 255, 0.87); + background-color: #242424; + + font-synthesis: none; + text-rendering: optimizeLegibility; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +a { + font-weight: 500; + color: #646cff; + text-decoration: inherit; +} +a:hover { + color: #535bf2; +} + +body { + margin: 0; + display: flex; + place-items: center; + min-width: 320px; + min-height: 100vh; +} + +h1 { + font-size: 3.2em; + line-height: 1.1; +} + +button { + border-radius: 8px; + border: 1px solid transparent; + padding: 0.6em 1.2em; + font-size: 1em; + font-weight: 500; + font-family: inherit; + background-color: #1a1a1a; + cursor: pointer; + transition: border-color 0.25s; +} +button:hover { + border-color: #646cff; +} +button:focus, +button:focus-visible { + outline: 4px auto -webkit-focus-ring-color; +} + +@media (prefers-color-scheme: light) { + :root { + color: #213547; + background-color: #ffffff; + } + a:hover { + color: #747bff; + } + button { + background-color: #f9f9f9; + } +} diff --git a/src/main.tsx b/src/main.tsx new file mode 100644 index 00000000..bef5202a --- /dev/null +++ b/src/main.tsx @@ -0,0 +1,10 @@ +import { StrictMode } from 'react' +import { createRoot } from 'react-dom/client' +import './index.css' +import App from './App.tsx' + +createRoot(document.getElementById('root')!).render( + + + , +) diff --git a/src/vite-env.d.ts b/src/vite-env.d.ts new file mode 100644 index 00000000..11f02fe2 --- /dev/null +++ b/src/vite-env.d.ts @@ -0,0 +1 @@ +/// diff --git a/tsconfig.app.json b/tsconfig.app.json new file mode 100644 index 00000000..358ca9ba --- /dev/null +++ b/tsconfig.app.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2020", + "useDefineForClassFields": true, + "lib": ["ES2020", "DOM", "DOM.Iterable"], + "module": "ESNext", + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "isolatedModules": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 00000000..1ffef600 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/tsconfig.node.json b/tsconfig.node.json new file mode 100644 index 00000000..db0becc8 --- /dev/null +++ b/tsconfig.node.json @@ -0,0 +1,24 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2022", + "lib": ["ES2023"], + "module": "ESNext", + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "isolatedModules": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/vite.config.ts b/vite.config.ts new file mode 100644 index 00000000..2328e170 --- /dev/null +++ b/vite.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from 'vite' +import react from '@vitejs/plugin-react-swc' + +// https://vite.dev/config/ +export default defineConfig({ + plugins: [react()], +}) From fb0936524fcbd49ae988c4e1674fbd8592bf5d07 Mon Sep 17 00:00:00 2001 From: Marios Tsigkas Date: Mon, 10 Mar 2025 17:50:10 +0200 Subject: [PATCH 02/96] Refactor App component button click handler and enhance error handling in main.tsx; update ESLint configuration for stricter rules and add new plugins; remove outdated README.md --- catApi-react/README.md | 54 ------------ eslint.config.js | 17 +++- package.json | 2 + pnpm-lock.yaml | 193 +++++++++++++++++++++++++++++++++++++++++ src/App.tsx | 2 +- src/main.tsx | 8 +- tsconfig.json | 14 ++- 7 files changed, 230 insertions(+), 60 deletions(-) delete mode 100644 catApi-react/README.md diff --git a/catApi-react/README.md b/catApi-react/README.md deleted file mode 100644 index 40ede56e..00000000 --- a/catApi-react/README.md +++ /dev/null @@ -1,54 +0,0 @@ -# React + TypeScript + Vite - -This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules. - -Currently, two official plugins are available: - -- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md) uses [Babel](https://babeljs.io/) for Fast Refresh -- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh - -## Expanding the ESLint configuration - -If you are developing a production application, we recommend updating the configuration to enable type-aware lint rules: - -```js -export default tseslint.config({ - extends: [ - // Remove ...tseslint.configs.recommended and replace with this - ...tseslint.configs.recommendedTypeChecked, - // Alternatively, use this for stricter rules - ...tseslint.configs.strictTypeChecked, - // Optionally, add this for stylistic rules - ...tseslint.configs.stylisticTypeChecked, - ], - languageOptions: { - // other options... - parserOptions: { - project: ['./tsconfig.node.json', './tsconfig.app.json'], - tsconfigRootDir: import.meta.dirname, - }, - }, -}) -``` - -You can also install [eslint-plugin-react-x](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-x) and [eslint-plugin-react-dom](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-dom) for React-specific lint rules: - -```js -// eslint.config.js -import reactX from 'eslint-plugin-react-x' -import reactDom from 'eslint-plugin-react-dom' - -export default tseslint.config({ - plugins: { - // Add the react-x and react-dom plugins - 'react-x': reactX, - 'react-dom': reactDom, - }, - rules: { - // other rules... - // Enable its recommended typescript rules - ...reactX.configs['recommended-typescript'].rules, - ...reactDom.configs.recommended.rules, - }, -}) -``` diff --git a/eslint.config.js b/eslint.config.js index 092408a9..e82f2683 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -3,22 +3,37 @@ import globals from 'globals' import reactHooks from 'eslint-plugin-react-hooks' import reactRefresh from 'eslint-plugin-react-refresh' import tseslint from 'typescript-eslint' +import reactX from 'eslint-plugin-react-x' +import reactDom from 'eslint-plugin-react-dom' export default tseslint.config( { ignores: ['dist'] }, { - extends: [js.configs.recommended, ...tseslint.configs.recommended], + extends: [ + js.configs.recommended, + ...tseslint.configs.recommendedTypeChecked, + ...tseslint.configs.strictTypeChecked, + ...tseslint.configs.stylisticTypeChecked, + ], files: ['**/*.{ts,tsx}'], languageOptions: { ecmaVersion: 2020, globals: globals.browser, + parserOptions: { + project: ['./tsconfig.node.json', './tsconfig.app.json'], + tsconfigRootDir: import.meta.dirname, + }, }, plugins: { 'react-hooks': reactHooks, 'react-refresh': reactRefresh, + 'react-x': reactX, + 'react-dom': reactDom, }, rules: { ...reactHooks.configs.recommended.rules, + ...reactX.configs['recommended-typescript'].rules, + ...reactDom.configs.recommended.rules, 'react-refresh/only-export-components': [ 'warn', { allowConstantExport: true }, diff --git a/package.json b/package.json index 78566d72..6d8c7fea 100644 --- a/package.json +++ b/package.json @@ -19,8 +19,10 @@ "@types/react-dom": "^19.0.4", "@vitejs/plugin-react-swc": "^3.8.0", "eslint": "^9.21.0", + "eslint-plugin-react-dom": "^1.31.0", "eslint-plugin-react-hooks": "^5.1.0", "eslint-plugin-react-refresh": "^0.4.19", + "eslint-plugin-react-x": "^1.31.0", "globals": "^15.15.0", "typescript": "~5.7.2", "typescript-eslint": "^8.24.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f1666c69..adbac792 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -30,12 +30,18 @@ importers: eslint: specifier: ^9.21.0 version: 9.22.0 + eslint-plugin-react-dom: + specifier: ^1.31.0 + version: 1.31.0(eslint@9.22.0)(typescript@5.7.3) eslint-plugin-react-hooks: specifier: ^5.1.0 version: 5.2.0(eslint@9.22.0) eslint-plugin-react-refresh: specifier: ^0.4.19 version: 0.4.19(eslint@9.22.0) + eslint-plugin-react-x: + specifier: ^1.31.0 + version: 1.31.0(eslint@9.22.0)(ts-api-utils@2.0.1(typescript@5.7.3))(typescript@5.7.3) globals: specifier: ^15.15.0 version: 15.15.0 @@ -211,6 +217,30 @@ packages: resolution: {integrity: sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==} engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} + '@eslint-react/ast@1.31.0': + resolution: {integrity: sha512-grHVhrUDxWJxH1sV21Tsn3Rvy55j9JiCqWynGCtQ1UL0dFvVWI+7sUGvt0oIFtJn6aMZrJQ8BBqpWZEtNdrjjQ==} + engines: {bun: '>=1.0.15', node: '>=18.18.0'} + + '@eslint-react/core@1.31.0': + resolution: {integrity: sha512-oWP/On0GQE67SyrglNwmocghOZHicl7EEzJcTc5nOsALFK7qeQil8GGu71bZ02vzAL8f9BkcD/DrxQKZZ+lp/A==} + engines: {bun: '>=1.0.15', node: '>=18.18.0'} + + '@eslint-react/eff@1.31.0': + resolution: {integrity: sha512-vimMkCQ9xJ09ECVVuW7aRiQD23XFij9TISs/AZsMRvezwou36vzT05qX5nkArkVALAzqIGSuEX8ez2r5N0vZ2g==} + engines: {bun: '>=1.0.15', node: '>=18.18.0'} + + '@eslint-react/jsx@1.31.0': + resolution: {integrity: sha512-DrsZz5yRFkCasUHMa+dov23/o2uU1QAv6ncwnK3aJh4tf6wKhnB55AAaSRaiTaHC4TH6c3yYVJ2SAbDNXsgUTg==} + engines: {bun: '>=1.0.15', node: '>=18.18.0'} + + '@eslint-react/shared@1.31.0': + resolution: {integrity: sha512-hB0mJATryhnwSG1zEIblOj/X159CpHyDqXExd3El1LovyVP/rbMccZ8qscNuYwnAsTU1FTZBZboIbSplxxumug==} + engines: {bun: '>=1.0.15', node: '>=18.18.0'} + + '@eslint-react/var@1.31.0': + resolution: {integrity: sha512-4jiAqBfX6JgnmKVhuOIqHT5gAvZF5I/xXU32E79EFIgaDs0rFEy0KL+EcZJsXB20cMajg0pEiKXVWFgFwbxFPw==} + engines: {bun: '>=1.0.15', node: '>=18.18.0'} + '@eslint/config-array@0.19.2': resolution: {integrity: sha512-GNKqxfHG2ySmJOBSHg7LxeUx4xpuCoFjacmlCoYWEbaPXLwvfIjixRI12xCQZeULksQb23uiA8F40w5TojpV7w==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -530,6 +560,9 @@ packages: balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + birecord@0.1.1: + resolution: {integrity: sha512-VUpsf/qykW0heRlC8LooCq28Kxn3mAqKohhDG/49rrsQ1dT1CXyj/pgXS+5BSRzFTR/3DyIBOqQOrGyZOh71Aw==} + brace-expansion@1.1.11: resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} @@ -555,6 +588,9 @@ packages: color-name@1.1.4: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + compare-versions@6.1.1: + resolution: {integrity: sha512-4hm4VPpIecmlg59CHXnRDnqGplJFrbLG4aFEl5vl6cK1u76ws3LLvX7ikFnTDl5vo39sjWD6AaDPYodJp/NNHg==} + concat-map@0.0.1: resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} @@ -586,6 +622,16 @@ packages: resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} engines: {node: '>=10'} + eslint-plugin-react-dom@1.31.0: + resolution: {integrity: sha512-ZVh59dIoJl2Rjqe49zLy+AHPFVo9RWHH49eAHP7+eTNAdmec6/7xHlsj8TWTpoSkBbU/VgxLjNKl5Tn2umd+qQ==} + engines: {bun: '>=1.0.15', node: '>=18.18.0'} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: ^4.9.5 || ^5.3.3 + peerDependenciesMeta: + typescript: + optional: true + eslint-plugin-react-hooks@5.2.0: resolution: {integrity: sha512-+f15FfK64YQwZdJNELETdn5ibXEUQmW1DZL6KXhNnc2heoy/sg9VJJeT7n8TlMWouzWqSWavFkIhHyIbIAEapg==} engines: {node: '>=10'} @@ -597,6 +643,19 @@ packages: peerDependencies: eslint: '>=8.40' + eslint-plugin-react-x@1.31.0: + resolution: {integrity: sha512-Et3f++0KSaPprNO4sJMambTkSwbx1Vc9G5he5yP781RqLXCpL/Kt+PuW/FgJz8M0dK8Aol8NoXvRYgXB2NL0Ew==} + engines: {bun: '>=1.0.15', node: '>=18.18.0'} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + ts-api-utils: ^2.0.1 + typescript: ^4.9.5 || ^5.3.3 + peerDependenciesMeta: + ts-api-utils: + optional: true + typescript: + optional: true + eslint-scope@8.3.0: resolution: {integrity: sha512-pUNxi75F8MJ/GdeKtVLSbYg4ZI34J6C0C7sbL4YOp2exGwen7ZsuBqKzUhXd0qMQ362yET3z+uPwKeg/0C2XCQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -813,6 +872,10 @@ packages: resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} engines: {node: '>=8.6'} + picomatch@4.0.2: + resolution: {integrity: sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==} + engines: {node: '>=12'} + postcss@8.5.3: resolution: {integrity: sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==} engines: {node: ^10 || ^12 || >=14} @@ -873,6 +936,9 @@ packages: resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} engines: {node: '>=0.10.0'} + string-ts@2.2.1: + resolution: {integrity: sha512-Q2u0gko67PLLhbte5HmPfdOjNvUKbKQM+mCNQae6jE91DmoFHY6HH9GcdqCeNx87DZ2KKjiFxmA0R/42OneGWw==} + strip-json-comments@3.1.1: resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} engines: {node: '>=8'} @@ -891,6 +957,9 @@ packages: peerDependencies: typescript: '>=4.8.4' + ts-pattern@5.6.2: + resolution: {integrity: sha512-d4IxJUXROL5NCa3amvMg6VQW2HVtZYmUTPfvVtO7zJWGYLJ+mry9v2OmYm+z67aniQoQ8/yFNadiEwtNS9qQiw==} + type-check@0.4.0: resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} engines: {node: '>= 0.8.0'} @@ -1047,6 +1116,78 @@ snapshots: '@eslint-community/regexpp@4.12.1': {} + '@eslint-react/ast@1.31.0(eslint@9.22.0)(typescript@5.7.3)': + dependencies: + '@eslint-react/eff': 1.31.0 + '@typescript-eslint/types': 8.26.0 + '@typescript-eslint/typescript-estree': 8.26.0(typescript@5.7.3) + '@typescript-eslint/utils': 8.26.0(eslint@9.22.0)(typescript@5.7.3) + string-ts: 2.2.1 + ts-pattern: 5.6.2 + transitivePeerDependencies: + - eslint + - supports-color + - typescript + + '@eslint-react/core@1.31.0(eslint@9.22.0)(typescript@5.7.3)': + dependencies: + '@eslint-react/ast': 1.31.0(eslint@9.22.0)(typescript@5.7.3) + '@eslint-react/eff': 1.31.0 + '@eslint-react/jsx': 1.31.0(eslint@9.22.0)(typescript@5.7.3) + '@eslint-react/shared': 1.31.0(eslint@9.22.0)(typescript@5.7.3) + '@eslint-react/var': 1.31.0(eslint@9.22.0)(typescript@5.7.3) + '@typescript-eslint/scope-manager': 8.26.0 + '@typescript-eslint/type-utils': 8.26.0(eslint@9.22.0)(typescript@5.7.3) + '@typescript-eslint/types': 8.26.0 + '@typescript-eslint/utils': 8.26.0(eslint@9.22.0)(typescript@5.7.3) + birecord: 0.1.1 + ts-pattern: 5.6.2 + transitivePeerDependencies: + - eslint + - supports-color + - typescript + + '@eslint-react/eff@1.31.0': {} + + '@eslint-react/jsx@1.31.0(eslint@9.22.0)(typescript@5.7.3)': + dependencies: + '@eslint-react/ast': 1.31.0(eslint@9.22.0)(typescript@5.7.3) + '@eslint-react/eff': 1.31.0 + '@eslint-react/var': 1.31.0(eslint@9.22.0)(typescript@5.7.3) + '@typescript-eslint/scope-manager': 8.26.0 + '@typescript-eslint/types': 8.26.0 + '@typescript-eslint/utils': 8.26.0(eslint@9.22.0)(typescript@5.7.3) + ts-pattern: 5.6.2 + transitivePeerDependencies: + - eslint + - supports-color + - typescript + + '@eslint-react/shared@1.31.0(eslint@9.22.0)(typescript@5.7.3)': + dependencies: + '@eslint-react/eff': 1.31.0 + '@typescript-eslint/utils': 8.26.0(eslint@9.22.0)(typescript@5.7.3) + picomatch: 4.0.2 + ts-pattern: 5.6.2 + transitivePeerDependencies: + - eslint + - supports-color + - typescript + + '@eslint-react/var@1.31.0(eslint@9.22.0)(typescript@5.7.3)': + dependencies: + '@eslint-react/ast': 1.31.0(eslint@9.22.0)(typescript@5.7.3) + '@eslint-react/eff': 1.31.0 + '@typescript-eslint/scope-manager': 8.26.0 + '@typescript-eslint/types': 8.26.0 + '@typescript-eslint/utils': 8.26.0(eslint@9.22.0)(typescript@5.7.3) + string-ts: 2.2.1 + ts-pattern: 5.6.2 + transitivePeerDependencies: + - eslint + - supports-color + - typescript + '@eslint/config-array@0.19.2': dependencies: '@eslint/object-schema': 2.1.6 @@ -1335,6 +1476,8 @@ snapshots: balanced-match@1.0.2: {} + birecord@0.1.1: {} + brace-expansion@1.1.11: dependencies: balanced-match: 1.0.2 @@ -1361,6 +1504,8 @@ snapshots: color-name@1.1.4: {} + compare-versions@6.1.1: {} + concat-map@0.0.1: {} cross-spawn@7.0.6: @@ -1407,6 +1552,26 @@ snapshots: escape-string-regexp@4.0.0: {} + eslint-plugin-react-dom@1.31.0(eslint@9.22.0)(typescript@5.7.3): + dependencies: + '@eslint-react/ast': 1.31.0(eslint@9.22.0)(typescript@5.7.3) + '@eslint-react/core': 1.31.0(eslint@9.22.0)(typescript@5.7.3) + '@eslint-react/eff': 1.31.0 + '@eslint-react/jsx': 1.31.0(eslint@9.22.0)(typescript@5.7.3) + '@eslint-react/shared': 1.31.0(eslint@9.22.0)(typescript@5.7.3) + '@eslint-react/var': 1.31.0(eslint@9.22.0)(typescript@5.7.3) + '@typescript-eslint/scope-manager': 8.26.0 + '@typescript-eslint/types': 8.26.0 + '@typescript-eslint/utils': 8.26.0(eslint@9.22.0)(typescript@5.7.3) + compare-versions: 6.1.1 + eslint: 9.22.0 + string-ts: 2.2.1 + ts-pattern: 5.6.2 + optionalDependencies: + typescript: 5.7.3 + transitivePeerDependencies: + - supports-color + eslint-plugin-react-hooks@5.2.0(eslint@9.22.0): dependencies: eslint: 9.22.0 @@ -1415,6 +1580,28 @@ snapshots: dependencies: eslint: 9.22.0 + eslint-plugin-react-x@1.31.0(eslint@9.22.0)(ts-api-utils@2.0.1(typescript@5.7.3))(typescript@5.7.3): + dependencies: + '@eslint-react/ast': 1.31.0(eslint@9.22.0)(typescript@5.7.3) + '@eslint-react/core': 1.31.0(eslint@9.22.0)(typescript@5.7.3) + '@eslint-react/eff': 1.31.0 + '@eslint-react/jsx': 1.31.0(eslint@9.22.0)(typescript@5.7.3) + '@eslint-react/shared': 1.31.0(eslint@9.22.0)(typescript@5.7.3) + '@eslint-react/var': 1.31.0(eslint@9.22.0)(typescript@5.7.3) + '@typescript-eslint/scope-manager': 8.26.0 + '@typescript-eslint/type-utils': 8.26.0(eslint@9.22.0)(typescript@5.7.3) + '@typescript-eslint/types': 8.26.0 + '@typescript-eslint/utils': 8.26.0(eslint@9.22.0)(typescript@5.7.3) + compare-versions: 6.1.1 + eslint: 9.22.0 + string-ts: 2.2.1 + ts-pattern: 5.6.2 + optionalDependencies: + ts-api-utils: 2.0.1(typescript@5.7.3) + typescript: 5.7.3 + transitivePeerDependencies: + - supports-color + eslint-scope@8.3.0: dependencies: esrecurse: 4.3.0 @@ -1633,6 +1820,8 @@ snapshots: picomatch@2.3.1: {} + picomatch@4.0.2: {} + postcss@8.5.3: dependencies: nanoid: 3.3.9 @@ -1697,6 +1886,8 @@ snapshots: source-map-js@1.2.1: {} + string-ts@2.2.1: {} + strip-json-comments@3.1.1: {} supports-color@7.2.0: @@ -1711,6 +1902,8 @@ snapshots: dependencies: typescript: 5.7.3 + ts-pattern@5.6.2: {} + type-check@0.4.0: dependencies: prelude-ls: 1.2.1 diff --git a/src/App.tsx b/src/App.tsx index 3d7ded3f..d6045e8d 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -18,7 +18,7 @@ function App() {

Vite + React

-

diff --git a/src/main.tsx b/src/main.tsx index bef5202a..e3c887b3 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -3,7 +3,13 @@ import { createRoot } from 'react-dom/client' import './index.css' import App from './App.tsx' -createRoot(document.getElementById('root')!).render( +const rootElement = document.getElementById('root') + +if (!rootElement) { + throw new Error('No root element found') +} + +createRoot(rootElement).render( , diff --git a/tsconfig.json b/tsconfig.json index 1ffef600..eb47006c 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,7 +1,15 @@ { + "compilerOptions": { + "forceConsistentCasingInFileNames": true, + "strict": true + }, "files": [], "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } + { + "path": "./tsconfig.app.json" + }, + { + "path": "./tsconfig.node.json" + } ] -} +} \ No newline at end of file From 7276229a2734a3ce8890191f2235c6d02313dde3 Mon Sep 17 00:00:00 2001 From: Marios Tsigkas Date: Mon, 10 Mar 2025 18:03:03 +0200 Subject: [PATCH 03/96] Add Tailwind CSS and PostCSS configuration; update package.json dependencies --- package.json | 7 +- pnpm-lock.yaml | 787 ++++++++++++++++++++++++++++++++++++++++----- postcss.config.js | 6 + src/index.css | 11 +- tailwind.config.js | 11 + 5 files changed, 747 insertions(+), 75 deletions(-) create mode 100644 postcss.config.js create mode 100644 tailwind.config.js diff --git a/package.json b/package.json index 6d8c7fea..15e496a2 100644 --- a/package.json +++ b/package.json @@ -26,6 +26,9 @@ "globals": "^15.15.0", "typescript": "~5.7.2", "typescript-eslint": "^8.24.1", - "vite": "^6.2.0" + "vite": "^6.2.0", + "autoprefixer": "^10.4.18", + "postcss": "^8.4.35", + "tailwindcss": "^3.4.1" } -} +} \ No newline at end of file diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index adbac792..5f8b3b19 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -26,37 +26,50 @@ importers: version: 19.0.4(@types/react@19.0.10) '@vitejs/plugin-react-swc': specifier: ^3.8.0 - version: 3.8.0(vite@6.2.1) + version: 3.8.0(vite@6.2.1(jiti@1.21.7)(yaml@2.7.0)) + autoprefixer: + specifier: ^10.4.18 + version: 10.4.21(postcss@8.5.3) eslint: specifier: ^9.21.0 - version: 9.22.0 + version: 9.22.0(jiti@1.21.7) eslint-plugin-react-dom: specifier: ^1.31.0 - version: 1.31.0(eslint@9.22.0)(typescript@5.7.3) + version: 1.31.0(eslint@9.22.0(jiti@1.21.7))(typescript@5.7.3) eslint-plugin-react-hooks: specifier: ^5.1.0 - version: 5.2.0(eslint@9.22.0) + version: 5.2.0(eslint@9.22.0(jiti@1.21.7)) eslint-plugin-react-refresh: specifier: ^0.4.19 - version: 0.4.19(eslint@9.22.0) + version: 0.4.19(eslint@9.22.0(jiti@1.21.7)) eslint-plugin-react-x: specifier: ^1.31.0 - version: 1.31.0(eslint@9.22.0)(ts-api-utils@2.0.1(typescript@5.7.3))(typescript@5.7.3) + version: 1.31.0(eslint@9.22.0(jiti@1.21.7))(ts-api-utils@2.0.1(typescript@5.7.3))(typescript@5.7.3) globals: specifier: ^15.15.0 version: 15.15.0 + postcss: + specifier: ^8.4.35 + version: 8.5.3 + tailwindcss: + specifier: ^3.4.1 + version: 3.4.17 typescript: specifier: ~5.7.2 version: 5.7.3 typescript-eslint: specifier: ^8.24.1 - version: 8.26.0(eslint@9.22.0)(typescript@5.7.3) + version: 8.26.0(eslint@9.22.0(jiti@1.21.7))(typescript@5.7.3) vite: specifier: ^6.2.0 - version: 6.2.1 + version: 6.2.1(jiti@1.21.7)(yaml@2.7.0) packages: + '@alloc/quick-lru@5.2.0': + resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==} + engines: {node: '>=10'} + '@esbuild/aix-ppc64@0.25.1': resolution: {integrity: sha512-kfYGy8IdzTGy+z0vFGvExZtxkFlA4zAxgKEahG9KE1ScBjpQnFsNOX8KTU5ojNru5ed5CVoJYXFtoxaq5nFbjQ==} engines: {node: '>=18'} @@ -289,6 +302,28 @@ packages: resolution: {integrity: sha512-xeO57FpIu4p1Ri3Jq/EXq4ClRm86dVF2z/+kvFnyqVYRavTZmaFaUBbWCOuuTh0o/g7DSsk6kc2vrS4Vl5oPOQ==} engines: {node: '>=18.18'} + '@isaacs/cliui@8.0.2': + resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} + engines: {node: '>=12'} + + '@jridgewell/gen-mapping@0.3.8': + resolution: {integrity: sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==} + engines: {node: '>=6.0.0'} + + '@jridgewell/resolve-uri@3.1.2': + resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} + engines: {node: '>=6.0.0'} + + '@jridgewell/set-array@1.2.1': + resolution: {integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==} + engines: {node: '>=6.0.0'} + + '@jridgewell/sourcemap-codec@1.5.0': + resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==} + + '@jridgewell/trace-mapping@0.3.25': + resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==} + '@nodelib/fs.scandir@2.1.5': resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} engines: {node: '>= 8'} @@ -301,6 +336,10 @@ packages: resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} engines: {node: '>= 8'} + '@pkgjs/parseargs@0.11.0': + resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} + engines: {node: '>=14'} + '@rollup/rollup-android-arm-eabi@4.35.0': resolution: {integrity: sha512-uYQ2WfPaqz5QtVgMxfN6NpLD+no0MYHDBywl7itPYd3K5TjjSghNKmX8ic9S8NU8w81NVhJv/XojcHptRly7qQ==} cpu: [arm] @@ -550,16 +589,49 @@ packages: ajv@6.12.6: resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} + ansi-regex@5.0.1: + resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} + engines: {node: '>=8'} + + ansi-regex@6.1.0: + resolution: {integrity: sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==} + engines: {node: '>=12'} + ansi-styles@4.3.0: resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} engines: {node: '>=8'} + ansi-styles@6.2.1: + resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==} + engines: {node: '>=12'} + + any-promise@1.3.0: + resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==} + + anymatch@3.1.3: + resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} + engines: {node: '>= 8'} + + arg@5.0.2: + resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==} + argparse@2.0.1: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + autoprefixer@10.4.21: + resolution: {integrity: sha512-O+A6LWV5LDHSJD3LjHYoNi4VLsj/Whi7k6zG12xTYaU4cQ8oxQGckXNX8cRHK5yOZ/ppVHe0ZBXGzSV9jXdVbQ==} + engines: {node: ^10 || ^12 || >=14} + hasBin: true + peerDependencies: + postcss: ^8.1.0 + balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + binary-extensions@2.3.0: + resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} + engines: {node: '>=8'} + birecord@0.1.1: resolution: {integrity: sha512-VUpsf/qykW0heRlC8LooCq28Kxn3mAqKohhDG/49rrsQ1dT1CXyj/pgXS+5BSRzFTR/3DyIBOqQOrGyZOh71Aw==} @@ -573,14 +645,30 @@ packages: resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} engines: {node: '>=8'} + browserslist@4.24.4: + resolution: {integrity: sha512-KDi1Ny1gSePi1vm0q4oxSF8b4DR44GF4BbmS2YdhPLOEqd8pDviZOGH/GsmRwoWJ2+5Lr085X7naowMwKHDG1A==} + engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} + hasBin: true + callsites@3.1.0: resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} engines: {node: '>=6'} + camelcase-css@2.0.1: + resolution: {integrity: sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==} + engines: {node: '>= 6'} + + caniuse-lite@1.0.30001703: + resolution: {integrity: sha512-kRlAGTRWgPsOj7oARC9m1okJEXdL/8fekFVcxA8Hl7GH4r/sN4OJn/i6Flde373T50KS7Y37oFbMwlE8+F42kQ==} + chalk@4.1.2: resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} engines: {node: '>=10'} + chokidar@3.6.0: + resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} + engines: {node: '>= 8.10.0'} + color-convert@2.0.1: resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} engines: {node: '>=7.0.0'} @@ -588,6 +676,10 @@ packages: color-name@1.1.4: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + commander@4.1.1: + resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} + engines: {node: '>= 6'} + compare-versions@6.1.1: resolution: {integrity: sha512-4hm4VPpIecmlg59CHXnRDnqGplJFrbLG4aFEl5vl6cK1u76ws3LLvX7ikFnTDl5vo39sjWD6AaDPYodJp/NNHg==} @@ -598,6 +690,11 @@ packages: resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} engines: {node: '>= 8'} + cssesc@3.0.0: + resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} + engines: {node: '>=4'} + hasBin: true + csstype@3.1.3: resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} @@ -613,11 +710,33 @@ packages: deep-is@0.1.4: resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} + didyoumean@1.2.2: + resolution: {integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==} + + dlv@1.1.3: + resolution: {integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==} + + eastasianwidth@0.2.0: + resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} + + electron-to-chromium@1.5.114: + resolution: {integrity: sha512-DFptFef3iktoKlFQK/afbo274/XNWD00Am0xa7M8FZUepHlHT8PEuiNBoRfFHbH1okqN58AlhbJ4QTkcnXorjA==} + + emoji-regex@8.0.0: + resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + + emoji-regex@9.2.2: + resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} + esbuild@0.25.1: resolution: {integrity: sha512-BGO5LtrGC7vxnqucAe/rmvKdJllfGaYWdyABvyMoXQlfYMb2bbRuReWR5tEGE//4LcNJj9XrkovTqNYRFZHAMQ==} engines: {node: '>=18'} hasBin: true + escalade@3.2.0: + resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} + engines: {node: '>=6'} + escape-string-regexp@4.0.0: resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} engines: {node: '>=10'} @@ -733,11 +852,21 @@ packages: flatted@3.3.3: resolution: {integrity: sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==} + foreground-child@3.3.1: + resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==} + engines: {node: '>=14'} + + fraction.js@4.3.7: + resolution: {integrity: sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==} + fsevents@2.3.3: resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} os: [darwin] + function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + glob-parent@5.1.2: resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} engines: {node: '>= 6'} @@ -746,6 +875,10 @@ packages: resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} engines: {node: '>=10.13.0'} + glob@10.4.5: + resolution: {integrity: sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==} + hasBin: true + globals@14.0.0: resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==} engines: {node: '>=18'} @@ -761,6 +894,10 @@ packages: resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} engines: {node: '>=8'} + hasown@2.0.2: + resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} + engines: {node: '>= 0.4'} + ignore@5.3.2: resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} engines: {node: '>= 4'} @@ -773,10 +910,22 @@ packages: resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} engines: {node: '>=0.8.19'} + is-binary-path@2.1.0: + resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} + engines: {node: '>=8'} + + is-core-module@2.16.1: + resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==} + engines: {node: '>= 0.4'} + is-extglob@2.1.1: resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} engines: {node: '>=0.10.0'} + is-fullwidth-code-point@3.0.0: + resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} + engines: {node: '>=8'} + is-glob@4.0.3: resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} engines: {node: '>=0.10.0'} @@ -788,6 +937,13 @@ packages: isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + jackspeak@3.4.3: + resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==} + + jiti@1.21.7: + resolution: {integrity: sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==} + hasBin: true + js-yaml@4.1.0: resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} hasBin: true @@ -808,6 +964,13 @@ packages: resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} engines: {node: '>= 0.8.0'} + lilconfig@3.1.3: + resolution: {integrity: sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==} + engines: {node: '>=14'} + + lines-and-columns@1.2.4: + resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} + locate-path@6.0.0: resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} engines: {node: '>=10'} @@ -815,6 +978,9 @@ packages: lodash.merge@4.6.2: resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} + lru-cache@10.4.3: + resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} + merge2@1.4.1: resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} engines: {node: '>= 8'} @@ -830,9 +996,16 @@ packages: resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} engines: {node: '>=16 || 14 >=14.17'} + minipass@7.1.2: + resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} + engines: {node: '>=16 || 14 >=14.17'} + ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + mz@2.7.0: + resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} + nanoid@3.3.9: resolution: {integrity: sha512-SppoicMGpZvbF1l3z4x7No3OlIjP7QJvC9XR7AhZr1kL133KHnKPztkKDc+Ir4aJ/1VhTySrtKhrsycmrMQfvg==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} @@ -841,6 +1014,25 @@ packages: natural-compare@1.4.0: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} + node-releases@2.0.19: + resolution: {integrity: sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==} + + normalize-path@3.0.0: + resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} + engines: {node: '>=0.10.0'} + + normalize-range@0.1.2: + resolution: {integrity: sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==} + engines: {node: '>=0.10.0'} + + object-assign@4.1.1: + resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} + engines: {node: '>=0.10.0'} + + object-hash@3.0.0: + resolution: {integrity: sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==} + engines: {node: '>= 6'} + optionator@0.9.4: resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} engines: {node: '>= 0.8.0'} @@ -853,6 +1045,9 @@ packages: resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} engines: {node: '>=10'} + package-json-from-dist@1.0.1: + resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} + parent-module@1.0.1: resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} engines: {node: '>=6'} @@ -865,6 +1060,13 @@ packages: resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} engines: {node: '>=8'} + path-parse@1.0.7: + resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} + + path-scurry@1.11.1: + resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} + engines: {node: '>=16 || 14 >=14.18'} + picocolors@1.1.1: resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} @@ -876,6 +1078,51 @@ packages: resolution: {integrity: sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==} engines: {node: '>=12'} + pify@2.3.0: + resolution: {integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==} + engines: {node: '>=0.10.0'} + + pirates@4.0.6: + resolution: {integrity: sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==} + engines: {node: '>= 6'} + + postcss-import@15.1.0: + resolution: {integrity: sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==} + engines: {node: '>=14.0.0'} + peerDependencies: + postcss: ^8.0.0 + + postcss-js@4.0.1: + resolution: {integrity: sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==} + engines: {node: ^12 || ^14 || >= 16} + peerDependencies: + postcss: ^8.4.21 + + postcss-load-config@4.0.2: + resolution: {integrity: sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==} + engines: {node: '>= 14'} + peerDependencies: + postcss: '>=8.0.9' + ts-node: '>=9.0.0' + peerDependenciesMeta: + postcss: + optional: true + ts-node: + optional: true + + postcss-nested@6.2.0: + resolution: {integrity: sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==} + engines: {node: '>=12.0'} + peerDependencies: + postcss: ^8.2.14 + + postcss-selector-parser@6.1.2: + resolution: {integrity: sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==} + engines: {node: '>=4'} + + postcss-value-parser@4.2.0: + resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==} + postcss@8.5.3: resolution: {integrity: sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==} engines: {node: ^10 || ^12 || >=14} @@ -900,10 +1147,22 @@ packages: resolution: {integrity: sha512-V8AVnmPIICiWpGfm6GLzCR/W5FXLchHop40W4nXBmdlEceh16rCN8O8LNWm5bh5XUX91fh7KpA+W0TgMKmgTpQ==} engines: {node: '>=0.10.0'} + read-cache@1.0.0: + resolution: {integrity: sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==} + + readdirp@3.6.0: + resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} + engines: {node: '>=8.10.0'} + resolve-from@4.0.0: resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} engines: {node: '>=4'} + resolve@1.22.10: + resolution: {integrity: sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==} + engines: {node: '>= 0.4'} + hasBin: true + reusify@1.1.0: resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} engines: {iojs: '>=1.0.0', node: '>=0.10.0'} @@ -932,6 +1191,10 @@ packages: resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} engines: {node: '>=8'} + signal-exit@4.1.0: + resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} + engines: {node: '>=14'} + source-map-js@1.2.1: resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} engines: {node: '>=0.10.0'} @@ -939,14 +1202,51 @@ packages: string-ts@2.2.1: resolution: {integrity: sha512-Q2u0gko67PLLhbte5HmPfdOjNvUKbKQM+mCNQae6jE91DmoFHY6HH9GcdqCeNx87DZ2KKjiFxmA0R/42OneGWw==} + string-width@4.2.3: + resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} + engines: {node: '>=8'} + + string-width@5.1.2: + resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} + engines: {node: '>=12'} + + strip-ansi@6.0.1: + resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} + engines: {node: '>=8'} + + strip-ansi@7.1.0: + resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==} + engines: {node: '>=12'} + strip-json-comments@3.1.1: resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} engines: {node: '>=8'} + sucrase@3.35.0: + resolution: {integrity: sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==} + engines: {node: '>=16 || 14 >=14.17'} + hasBin: true + supports-color@7.2.0: resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} engines: {node: '>=8'} + supports-preserve-symlinks-flag@1.0.0: + resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} + engines: {node: '>= 0.4'} + + tailwindcss@3.4.17: + resolution: {integrity: sha512-w33E2aCvSDP0tW9RZuNXadXlkHXqFzSkQew/aIa2i/Sj8fThxwovwlXHSPXTbAHwEIhBFXAedUhP2tueAKP8Og==} + engines: {node: '>=14.0.0'} + hasBin: true + + thenify-all@1.6.0: + resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==} + engines: {node: '>=0.8'} + + thenify@3.3.1: + resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==} + to-regex-range@5.0.1: resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} engines: {node: '>=8.0'} @@ -957,6 +1257,9 @@ packages: peerDependencies: typescript: '>=4.8.4' + ts-interface-checker@0.1.13: + resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} + ts-pattern@5.6.2: resolution: {integrity: sha512-d4IxJUXROL5NCa3amvMg6VQW2HVtZYmUTPfvVtO7zJWGYLJ+mry9v2OmYm+z67aniQoQ8/yFNadiEwtNS9qQiw==} @@ -976,9 +1279,18 @@ packages: engines: {node: '>=14.17'} hasBin: true + update-browserslist-db@1.1.3: + resolution: {integrity: sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==} + hasBin: true + peerDependencies: + browserslist: '>= 4.21.0' + uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + util-deprecate@1.0.2: + resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + vite@6.2.1: resolution: {integrity: sha512-n2GnqDb6XPhlt9B8olZPrgMD/es/Nd1RdChF6CBD/fHW6pUyUTt2sQW2fPRX5GiD9XEa6+8A6A4f2vT6pSsE7Q==} engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} @@ -1028,12 +1340,27 @@ packages: resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} engines: {node: '>=0.10.0'} + wrap-ansi@7.0.0: + resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} + engines: {node: '>=10'} + + wrap-ansi@8.1.0: + resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} + engines: {node: '>=12'} + + yaml@2.7.0: + resolution: {integrity: sha512-+hSoy/QHluxmC9kCIJyL/uyFmLmc+e5CFR5Wa+bpIhIj85LVb9ZH2nVnqrHoSvKogwODv0ClqZkmiSSaIH5LTA==} + engines: {node: '>= 14'} + hasBin: true + yocto-queue@0.1.0: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} snapshots: + '@alloc/quick-lru@5.2.0': {} + '@esbuild/aix-ppc64@0.25.1': optional: true @@ -1109,19 +1436,19 @@ snapshots: '@esbuild/win32-x64@0.25.1': optional: true - '@eslint-community/eslint-utils@4.4.1(eslint@9.22.0)': + '@eslint-community/eslint-utils@4.4.1(eslint@9.22.0(jiti@1.21.7))': dependencies: - eslint: 9.22.0 + eslint: 9.22.0(jiti@1.21.7) eslint-visitor-keys: 3.4.3 '@eslint-community/regexpp@4.12.1': {} - '@eslint-react/ast@1.31.0(eslint@9.22.0)(typescript@5.7.3)': + '@eslint-react/ast@1.31.0(eslint@9.22.0(jiti@1.21.7))(typescript@5.7.3)': dependencies: '@eslint-react/eff': 1.31.0 '@typescript-eslint/types': 8.26.0 '@typescript-eslint/typescript-estree': 8.26.0(typescript@5.7.3) - '@typescript-eslint/utils': 8.26.0(eslint@9.22.0)(typescript@5.7.3) + '@typescript-eslint/utils': 8.26.0(eslint@9.22.0(jiti@1.21.7))(typescript@5.7.3) string-ts: 2.2.1 ts-pattern: 5.6.2 transitivePeerDependencies: @@ -1129,17 +1456,17 @@ snapshots: - supports-color - typescript - '@eslint-react/core@1.31.0(eslint@9.22.0)(typescript@5.7.3)': + '@eslint-react/core@1.31.0(eslint@9.22.0(jiti@1.21.7))(typescript@5.7.3)': dependencies: - '@eslint-react/ast': 1.31.0(eslint@9.22.0)(typescript@5.7.3) + '@eslint-react/ast': 1.31.0(eslint@9.22.0(jiti@1.21.7))(typescript@5.7.3) '@eslint-react/eff': 1.31.0 - '@eslint-react/jsx': 1.31.0(eslint@9.22.0)(typescript@5.7.3) - '@eslint-react/shared': 1.31.0(eslint@9.22.0)(typescript@5.7.3) - '@eslint-react/var': 1.31.0(eslint@9.22.0)(typescript@5.7.3) + '@eslint-react/jsx': 1.31.0(eslint@9.22.0(jiti@1.21.7))(typescript@5.7.3) + '@eslint-react/shared': 1.31.0(eslint@9.22.0(jiti@1.21.7))(typescript@5.7.3) + '@eslint-react/var': 1.31.0(eslint@9.22.0(jiti@1.21.7))(typescript@5.7.3) '@typescript-eslint/scope-manager': 8.26.0 - '@typescript-eslint/type-utils': 8.26.0(eslint@9.22.0)(typescript@5.7.3) + '@typescript-eslint/type-utils': 8.26.0(eslint@9.22.0(jiti@1.21.7))(typescript@5.7.3) '@typescript-eslint/types': 8.26.0 - '@typescript-eslint/utils': 8.26.0(eslint@9.22.0)(typescript@5.7.3) + '@typescript-eslint/utils': 8.26.0(eslint@9.22.0(jiti@1.21.7))(typescript@5.7.3) birecord: 0.1.1 ts-pattern: 5.6.2 transitivePeerDependencies: @@ -1149,24 +1476,24 @@ snapshots: '@eslint-react/eff@1.31.0': {} - '@eslint-react/jsx@1.31.0(eslint@9.22.0)(typescript@5.7.3)': + '@eslint-react/jsx@1.31.0(eslint@9.22.0(jiti@1.21.7))(typescript@5.7.3)': dependencies: - '@eslint-react/ast': 1.31.0(eslint@9.22.0)(typescript@5.7.3) + '@eslint-react/ast': 1.31.0(eslint@9.22.0(jiti@1.21.7))(typescript@5.7.3) '@eslint-react/eff': 1.31.0 - '@eslint-react/var': 1.31.0(eslint@9.22.0)(typescript@5.7.3) + '@eslint-react/var': 1.31.0(eslint@9.22.0(jiti@1.21.7))(typescript@5.7.3) '@typescript-eslint/scope-manager': 8.26.0 '@typescript-eslint/types': 8.26.0 - '@typescript-eslint/utils': 8.26.0(eslint@9.22.0)(typescript@5.7.3) + '@typescript-eslint/utils': 8.26.0(eslint@9.22.0(jiti@1.21.7))(typescript@5.7.3) ts-pattern: 5.6.2 transitivePeerDependencies: - eslint - supports-color - typescript - '@eslint-react/shared@1.31.0(eslint@9.22.0)(typescript@5.7.3)': + '@eslint-react/shared@1.31.0(eslint@9.22.0(jiti@1.21.7))(typescript@5.7.3)': dependencies: '@eslint-react/eff': 1.31.0 - '@typescript-eslint/utils': 8.26.0(eslint@9.22.0)(typescript@5.7.3) + '@typescript-eslint/utils': 8.26.0(eslint@9.22.0(jiti@1.21.7))(typescript@5.7.3) picomatch: 4.0.2 ts-pattern: 5.6.2 transitivePeerDependencies: @@ -1174,13 +1501,13 @@ snapshots: - supports-color - typescript - '@eslint-react/var@1.31.0(eslint@9.22.0)(typescript@5.7.3)': + '@eslint-react/var@1.31.0(eslint@9.22.0(jiti@1.21.7))(typescript@5.7.3)': dependencies: - '@eslint-react/ast': 1.31.0(eslint@9.22.0)(typescript@5.7.3) + '@eslint-react/ast': 1.31.0(eslint@9.22.0(jiti@1.21.7))(typescript@5.7.3) '@eslint-react/eff': 1.31.0 '@typescript-eslint/scope-manager': 8.26.0 '@typescript-eslint/types': 8.26.0 - '@typescript-eslint/utils': 8.26.0(eslint@9.22.0)(typescript@5.7.3) + '@typescript-eslint/utils': 8.26.0(eslint@9.22.0(jiti@1.21.7))(typescript@5.7.3) string-ts: 2.2.1 ts-pattern: 5.6.2 transitivePeerDependencies: @@ -1238,6 +1565,32 @@ snapshots: '@humanwhocodes/retry@0.4.2': {} + '@isaacs/cliui@8.0.2': + dependencies: + string-width: 5.1.2 + string-width-cjs: string-width@4.2.3 + strip-ansi: 7.1.0 + strip-ansi-cjs: strip-ansi@6.0.1 + wrap-ansi: 8.1.0 + wrap-ansi-cjs: wrap-ansi@7.0.0 + + '@jridgewell/gen-mapping@0.3.8': + dependencies: + '@jridgewell/set-array': 1.2.1 + '@jridgewell/sourcemap-codec': 1.5.0 + '@jridgewell/trace-mapping': 0.3.25 + + '@jridgewell/resolve-uri@3.1.2': {} + + '@jridgewell/set-array@1.2.1': {} + + '@jridgewell/sourcemap-codec@1.5.0': {} + + '@jridgewell/trace-mapping@0.3.25': + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.0 + '@nodelib/fs.scandir@2.1.5': dependencies: '@nodelib/fs.stat': 2.0.5 @@ -1250,6 +1603,9 @@ snapshots: '@nodelib/fs.scandir': 2.1.5 fastq: 1.19.1 + '@pkgjs/parseargs@0.11.0': + optional: true + '@rollup/rollup-android-arm-eabi@4.35.0': optional: true @@ -1371,15 +1727,15 @@ snapshots: dependencies: csstype: 3.1.3 - '@typescript-eslint/eslint-plugin@8.26.0(@typescript-eslint/parser@8.26.0(eslint@9.22.0)(typescript@5.7.3))(eslint@9.22.0)(typescript@5.7.3)': + '@typescript-eslint/eslint-plugin@8.26.0(@typescript-eslint/parser@8.26.0(eslint@9.22.0(jiti@1.21.7))(typescript@5.7.3))(eslint@9.22.0(jiti@1.21.7))(typescript@5.7.3)': dependencies: '@eslint-community/regexpp': 4.12.1 - '@typescript-eslint/parser': 8.26.0(eslint@9.22.0)(typescript@5.7.3) + '@typescript-eslint/parser': 8.26.0(eslint@9.22.0(jiti@1.21.7))(typescript@5.7.3) '@typescript-eslint/scope-manager': 8.26.0 - '@typescript-eslint/type-utils': 8.26.0(eslint@9.22.0)(typescript@5.7.3) - '@typescript-eslint/utils': 8.26.0(eslint@9.22.0)(typescript@5.7.3) + '@typescript-eslint/type-utils': 8.26.0(eslint@9.22.0(jiti@1.21.7))(typescript@5.7.3) + '@typescript-eslint/utils': 8.26.0(eslint@9.22.0(jiti@1.21.7))(typescript@5.7.3) '@typescript-eslint/visitor-keys': 8.26.0 - eslint: 9.22.0 + eslint: 9.22.0(jiti@1.21.7) graphemer: 1.4.0 ignore: 5.3.2 natural-compare: 1.4.0 @@ -1388,14 +1744,14 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@8.26.0(eslint@9.22.0)(typescript@5.7.3)': + '@typescript-eslint/parser@8.26.0(eslint@9.22.0(jiti@1.21.7))(typescript@5.7.3)': dependencies: '@typescript-eslint/scope-manager': 8.26.0 '@typescript-eslint/types': 8.26.0 '@typescript-eslint/typescript-estree': 8.26.0(typescript@5.7.3) '@typescript-eslint/visitor-keys': 8.26.0 debug: 4.4.0 - eslint: 9.22.0 + eslint: 9.22.0(jiti@1.21.7) typescript: 5.7.3 transitivePeerDependencies: - supports-color @@ -1405,12 +1761,12 @@ snapshots: '@typescript-eslint/types': 8.26.0 '@typescript-eslint/visitor-keys': 8.26.0 - '@typescript-eslint/type-utils@8.26.0(eslint@9.22.0)(typescript@5.7.3)': + '@typescript-eslint/type-utils@8.26.0(eslint@9.22.0(jiti@1.21.7))(typescript@5.7.3)': dependencies: '@typescript-eslint/typescript-estree': 8.26.0(typescript@5.7.3) - '@typescript-eslint/utils': 8.26.0(eslint@9.22.0)(typescript@5.7.3) + '@typescript-eslint/utils': 8.26.0(eslint@9.22.0(jiti@1.21.7))(typescript@5.7.3) debug: 4.4.0 - eslint: 9.22.0 + eslint: 9.22.0(jiti@1.21.7) ts-api-utils: 2.0.1(typescript@5.7.3) typescript: 5.7.3 transitivePeerDependencies: @@ -1432,13 +1788,13 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@8.26.0(eslint@9.22.0)(typescript@5.7.3)': + '@typescript-eslint/utils@8.26.0(eslint@9.22.0(jiti@1.21.7))(typescript@5.7.3)': dependencies: - '@eslint-community/eslint-utils': 4.4.1(eslint@9.22.0) + '@eslint-community/eslint-utils': 4.4.1(eslint@9.22.0(jiti@1.21.7)) '@typescript-eslint/scope-manager': 8.26.0 '@typescript-eslint/types': 8.26.0 '@typescript-eslint/typescript-estree': 8.26.0(typescript@5.7.3) - eslint: 9.22.0 + eslint: 9.22.0(jiti@1.21.7) typescript: 5.7.3 transitivePeerDependencies: - supports-color @@ -1448,10 +1804,10 @@ snapshots: '@typescript-eslint/types': 8.26.0 eslint-visitor-keys: 4.2.0 - '@vitejs/plugin-react-swc@3.8.0(vite@6.2.1)': + '@vitejs/plugin-react-swc@3.8.0(vite@6.2.1(jiti@1.21.7)(yaml@2.7.0))': dependencies: '@swc/core': 1.11.8 - vite: 6.2.1 + vite: 6.2.1(jiti@1.21.7)(yaml@2.7.0) transitivePeerDependencies: - '@swc/helpers' @@ -1468,14 +1824,41 @@ snapshots: json-schema-traverse: 0.4.1 uri-js: 4.4.1 + ansi-regex@5.0.1: {} + + ansi-regex@6.1.0: {} + ansi-styles@4.3.0: dependencies: color-convert: 2.0.1 + ansi-styles@6.2.1: {} + + any-promise@1.3.0: {} + + anymatch@3.1.3: + dependencies: + normalize-path: 3.0.0 + picomatch: 2.3.1 + + arg@5.0.2: {} + argparse@2.0.1: {} + autoprefixer@10.4.21(postcss@8.5.3): + dependencies: + browserslist: 4.24.4 + caniuse-lite: 1.0.30001703 + fraction.js: 4.3.7 + normalize-range: 0.1.2 + picocolors: 1.1.1 + postcss: 8.5.3 + postcss-value-parser: 4.2.0 + balanced-match@1.0.2: {} + binary-extensions@2.3.0: {} + birecord@0.1.1: {} brace-expansion@1.1.11: @@ -1491,19 +1874,44 @@ snapshots: dependencies: fill-range: 7.1.1 + browserslist@4.24.4: + dependencies: + caniuse-lite: 1.0.30001703 + electron-to-chromium: 1.5.114 + node-releases: 2.0.19 + update-browserslist-db: 1.1.3(browserslist@4.24.4) + callsites@3.1.0: {} + camelcase-css@2.0.1: {} + + caniuse-lite@1.0.30001703: {} + chalk@4.1.2: dependencies: ansi-styles: 4.3.0 supports-color: 7.2.0 + chokidar@3.6.0: + dependencies: + anymatch: 3.1.3 + braces: 3.0.3 + glob-parent: 5.1.2 + is-binary-path: 2.1.0 + is-glob: 4.0.3 + normalize-path: 3.0.0 + readdirp: 3.6.0 + optionalDependencies: + fsevents: 2.3.3 + color-convert@2.0.1: dependencies: color-name: 1.1.4 color-name@1.1.4: {} + commander@4.1.1: {} + compare-versions@6.1.1: {} concat-map@0.0.1: {} @@ -1514,6 +1922,8 @@ snapshots: shebang-command: 2.0.0 which: 2.0.2 + cssesc@3.0.0: {} + csstype@3.1.3: {} debug@4.4.0: @@ -1522,6 +1932,18 @@ snapshots: deep-is@0.1.4: {} + didyoumean@1.2.2: {} + + dlv@1.1.3: {} + + eastasianwidth@0.2.0: {} + + electron-to-chromium@1.5.114: {} + + emoji-regex@8.0.0: {} + + emoji-regex@9.2.2: {} + esbuild@0.25.1: optionalDependencies: '@esbuild/aix-ppc64': 0.25.1 @@ -1550,21 +1972,23 @@ snapshots: '@esbuild/win32-ia32': 0.25.1 '@esbuild/win32-x64': 0.25.1 + escalade@3.2.0: {} + escape-string-regexp@4.0.0: {} - eslint-plugin-react-dom@1.31.0(eslint@9.22.0)(typescript@5.7.3): + eslint-plugin-react-dom@1.31.0(eslint@9.22.0(jiti@1.21.7))(typescript@5.7.3): dependencies: - '@eslint-react/ast': 1.31.0(eslint@9.22.0)(typescript@5.7.3) - '@eslint-react/core': 1.31.0(eslint@9.22.0)(typescript@5.7.3) + '@eslint-react/ast': 1.31.0(eslint@9.22.0(jiti@1.21.7))(typescript@5.7.3) + '@eslint-react/core': 1.31.0(eslint@9.22.0(jiti@1.21.7))(typescript@5.7.3) '@eslint-react/eff': 1.31.0 - '@eslint-react/jsx': 1.31.0(eslint@9.22.0)(typescript@5.7.3) - '@eslint-react/shared': 1.31.0(eslint@9.22.0)(typescript@5.7.3) - '@eslint-react/var': 1.31.0(eslint@9.22.0)(typescript@5.7.3) + '@eslint-react/jsx': 1.31.0(eslint@9.22.0(jiti@1.21.7))(typescript@5.7.3) + '@eslint-react/shared': 1.31.0(eslint@9.22.0(jiti@1.21.7))(typescript@5.7.3) + '@eslint-react/var': 1.31.0(eslint@9.22.0(jiti@1.21.7))(typescript@5.7.3) '@typescript-eslint/scope-manager': 8.26.0 '@typescript-eslint/types': 8.26.0 - '@typescript-eslint/utils': 8.26.0(eslint@9.22.0)(typescript@5.7.3) + '@typescript-eslint/utils': 8.26.0(eslint@9.22.0(jiti@1.21.7))(typescript@5.7.3) compare-versions: 6.1.1 - eslint: 9.22.0 + eslint: 9.22.0(jiti@1.21.7) string-ts: 2.2.1 ts-pattern: 5.6.2 optionalDependencies: @@ -1572,28 +1996,28 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-plugin-react-hooks@5.2.0(eslint@9.22.0): + eslint-plugin-react-hooks@5.2.0(eslint@9.22.0(jiti@1.21.7)): dependencies: - eslint: 9.22.0 + eslint: 9.22.0(jiti@1.21.7) - eslint-plugin-react-refresh@0.4.19(eslint@9.22.0): + eslint-plugin-react-refresh@0.4.19(eslint@9.22.0(jiti@1.21.7)): dependencies: - eslint: 9.22.0 + eslint: 9.22.0(jiti@1.21.7) - eslint-plugin-react-x@1.31.0(eslint@9.22.0)(ts-api-utils@2.0.1(typescript@5.7.3))(typescript@5.7.3): + eslint-plugin-react-x@1.31.0(eslint@9.22.0(jiti@1.21.7))(ts-api-utils@2.0.1(typescript@5.7.3))(typescript@5.7.3): dependencies: - '@eslint-react/ast': 1.31.0(eslint@9.22.0)(typescript@5.7.3) - '@eslint-react/core': 1.31.0(eslint@9.22.0)(typescript@5.7.3) + '@eslint-react/ast': 1.31.0(eslint@9.22.0(jiti@1.21.7))(typescript@5.7.3) + '@eslint-react/core': 1.31.0(eslint@9.22.0(jiti@1.21.7))(typescript@5.7.3) '@eslint-react/eff': 1.31.0 - '@eslint-react/jsx': 1.31.0(eslint@9.22.0)(typescript@5.7.3) - '@eslint-react/shared': 1.31.0(eslint@9.22.0)(typescript@5.7.3) - '@eslint-react/var': 1.31.0(eslint@9.22.0)(typescript@5.7.3) + '@eslint-react/jsx': 1.31.0(eslint@9.22.0(jiti@1.21.7))(typescript@5.7.3) + '@eslint-react/shared': 1.31.0(eslint@9.22.0(jiti@1.21.7))(typescript@5.7.3) + '@eslint-react/var': 1.31.0(eslint@9.22.0(jiti@1.21.7))(typescript@5.7.3) '@typescript-eslint/scope-manager': 8.26.0 - '@typescript-eslint/type-utils': 8.26.0(eslint@9.22.0)(typescript@5.7.3) + '@typescript-eslint/type-utils': 8.26.0(eslint@9.22.0(jiti@1.21.7))(typescript@5.7.3) '@typescript-eslint/types': 8.26.0 - '@typescript-eslint/utils': 8.26.0(eslint@9.22.0)(typescript@5.7.3) + '@typescript-eslint/utils': 8.26.0(eslint@9.22.0(jiti@1.21.7))(typescript@5.7.3) compare-versions: 6.1.1 - eslint: 9.22.0 + eslint: 9.22.0(jiti@1.21.7) string-ts: 2.2.1 ts-pattern: 5.6.2 optionalDependencies: @@ -1611,9 +2035,9 @@ snapshots: eslint-visitor-keys@4.2.0: {} - eslint@9.22.0: + eslint@9.22.0(jiti@1.21.7): dependencies: - '@eslint-community/eslint-utils': 4.4.1(eslint@9.22.0) + '@eslint-community/eslint-utils': 4.4.1(eslint@9.22.0(jiti@1.21.7)) '@eslint-community/regexpp': 4.12.1 '@eslint/config-array': 0.19.2 '@eslint/config-helpers': 0.1.0 @@ -1648,6 +2072,8 @@ snapshots: minimatch: 3.1.2 natural-compare: 1.4.0 optionator: 0.9.4 + optionalDependencies: + jiti: 1.21.7 transitivePeerDependencies: - supports-color @@ -1707,9 +2133,18 @@ snapshots: flatted@3.3.3: {} + foreground-child@3.3.1: + dependencies: + cross-spawn: 7.0.6 + signal-exit: 4.1.0 + + fraction.js@4.3.7: {} + fsevents@2.3.3: optional: true + function-bind@1.1.2: {} + glob-parent@5.1.2: dependencies: is-glob: 4.0.3 @@ -1718,6 +2153,15 @@ snapshots: dependencies: is-glob: 4.0.3 + glob@10.4.5: + dependencies: + foreground-child: 3.3.1 + jackspeak: 3.4.3 + minimatch: 9.0.5 + minipass: 7.1.2 + package-json-from-dist: 1.0.1 + path-scurry: 1.11.1 + globals@14.0.0: {} globals@15.15.0: {} @@ -1726,6 +2170,10 @@ snapshots: has-flag@4.0.0: {} + hasown@2.0.2: + dependencies: + function-bind: 1.1.2 + ignore@5.3.2: {} import-fresh@3.3.1: @@ -1735,8 +2183,18 @@ snapshots: imurmurhash@0.1.4: {} + is-binary-path@2.1.0: + dependencies: + binary-extensions: 2.3.0 + + is-core-module@2.16.1: + dependencies: + hasown: 2.0.2 + is-extglob@2.1.1: {} + is-fullwidth-code-point@3.0.0: {} + is-glob@4.0.3: dependencies: is-extglob: 2.1.1 @@ -1745,6 +2203,14 @@ snapshots: isexe@2.0.0: {} + jackspeak@3.4.3: + dependencies: + '@isaacs/cliui': 8.0.2 + optionalDependencies: + '@pkgjs/parseargs': 0.11.0 + + jiti@1.21.7: {} + js-yaml@4.1.0: dependencies: argparse: 2.0.1 @@ -1764,12 +2230,18 @@ snapshots: prelude-ls: 1.2.1 type-check: 0.4.0 + lilconfig@3.1.3: {} + + lines-and-columns@1.2.4: {} + locate-path@6.0.0: dependencies: p-locate: 5.0.0 lodash.merge@4.6.2: {} + lru-cache@10.4.3: {} + merge2@1.4.1: {} micromatch@4.0.8: @@ -1785,12 +2257,30 @@ snapshots: dependencies: brace-expansion: 2.0.1 + minipass@7.1.2: {} + ms@2.1.3: {} + mz@2.7.0: + dependencies: + any-promise: 1.3.0 + object-assign: 4.1.1 + thenify-all: 1.6.0 + nanoid@3.3.9: {} natural-compare@1.4.0: {} + node-releases@2.0.19: {} + + normalize-path@3.0.0: {} + + normalize-range@0.1.2: {} + + object-assign@4.1.1: {} + + object-hash@3.0.0: {} + optionator@0.9.4: dependencies: deep-is: 0.1.4 @@ -1808,6 +2298,8 @@ snapshots: dependencies: p-limit: 3.1.0 + package-json-from-dist@1.0.1: {} + parent-module@1.0.1: dependencies: callsites: 3.1.0 @@ -1816,12 +2308,54 @@ snapshots: path-key@3.1.1: {} + path-parse@1.0.7: {} + + path-scurry@1.11.1: + dependencies: + lru-cache: 10.4.3 + minipass: 7.1.2 + picocolors@1.1.1: {} picomatch@2.3.1: {} picomatch@4.0.2: {} + pify@2.3.0: {} + + pirates@4.0.6: {} + + postcss-import@15.1.0(postcss@8.5.3): + dependencies: + postcss: 8.5.3 + postcss-value-parser: 4.2.0 + read-cache: 1.0.0 + resolve: 1.22.10 + + postcss-js@4.0.1(postcss@8.5.3): + dependencies: + camelcase-css: 2.0.1 + postcss: 8.5.3 + + postcss-load-config@4.0.2(postcss@8.5.3): + dependencies: + lilconfig: 3.1.3 + yaml: 2.7.0 + optionalDependencies: + postcss: 8.5.3 + + postcss-nested@6.2.0(postcss@8.5.3): + dependencies: + postcss: 8.5.3 + postcss-selector-parser: 6.1.2 + + postcss-selector-parser@6.1.2: + dependencies: + cssesc: 3.0.0 + util-deprecate: 1.0.2 + + postcss-value-parser@4.2.0: {} + postcss@8.5.3: dependencies: nanoid: 3.3.9 @@ -1841,8 +2375,22 @@ snapshots: react@19.0.0: {} + read-cache@1.0.0: + dependencies: + pify: 2.3.0 + + readdirp@3.6.0: + dependencies: + picomatch: 2.3.1 + resolve-from@4.0.0: {} + resolve@1.22.10: + dependencies: + is-core-module: 2.16.1 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + reusify@1.1.0: {} rollup@4.35.0: @@ -1884,16 +2432,85 @@ snapshots: shebang-regex@3.0.0: {} + signal-exit@4.1.0: {} + source-map-js@1.2.1: {} string-ts@2.2.1: {} + string-width@4.2.3: + dependencies: + emoji-regex: 8.0.0 + is-fullwidth-code-point: 3.0.0 + strip-ansi: 6.0.1 + + string-width@5.1.2: + dependencies: + eastasianwidth: 0.2.0 + emoji-regex: 9.2.2 + strip-ansi: 7.1.0 + + strip-ansi@6.0.1: + dependencies: + ansi-regex: 5.0.1 + + strip-ansi@7.1.0: + dependencies: + ansi-regex: 6.1.0 + strip-json-comments@3.1.1: {} + sucrase@3.35.0: + dependencies: + '@jridgewell/gen-mapping': 0.3.8 + commander: 4.1.1 + glob: 10.4.5 + lines-and-columns: 1.2.4 + mz: 2.7.0 + pirates: 4.0.6 + ts-interface-checker: 0.1.13 + supports-color@7.2.0: dependencies: has-flag: 4.0.0 + supports-preserve-symlinks-flag@1.0.0: {} + + tailwindcss@3.4.17: + dependencies: + '@alloc/quick-lru': 5.2.0 + arg: 5.0.2 + chokidar: 3.6.0 + didyoumean: 1.2.2 + dlv: 1.1.3 + fast-glob: 3.3.3 + glob-parent: 6.0.2 + is-glob: 4.0.3 + jiti: 1.21.7 + lilconfig: 3.1.3 + micromatch: 4.0.8 + normalize-path: 3.0.0 + object-hash: 3.0.0 + picocolors: 1.1.1 + postcss: 8.5.3 + postcss-import: 15.1.0(postcss@8.5.3) + postcss-js: 4.0.1(postcss@8.5.3) + postcss-load-config: 4.0.2(postcss@8.5.3) + postcss-nested: 6.2.0(postcss@8.5.3) + postcss-selector-parser: 6.1.2 + resolve: 1.22.10 + sucrase: 3.35.0 + transitivePeerDependencies: + - ts-node + + thenify-all@1.6.0: + dependencies: + thenify: 3.3.1 + + thenify@3.3.1: + dependencies: + any-promise: 1.3.0 + to-regex-range@5.0.1: dependencies: is-number: 7.0.0 @@ -1902,35 +2519,47 @@ snapshots: dependencies: typescript: 5.7.3 + ts-interface-checker@0.1.13: {} + ts-pattern@5.6.2: {} type-check@0.4.0: dependencies: prelude-ls: 1.2.1 - typescript-eslint@8.26.0(eslint@9.22.0)(typescript@5.7.3): + typescript-eslint@8.26.0(eslint@9.22.0(jiti@1.21.7))(typescript@5.7.3): dependencies: - '@typescript-eslint/eslint-plugin': 8.26.0(@typescript-eslint/parser@8.26.0(eslint@9.22.0)(typescript@5.7.3))(eslint@9.22.0)(typescript@5.7.3) - '@typescript-eslint/parser': 8.26.0(eslint@9.22.0)(typescript@5.7.3) - '@typescript-eslint/utils': 8.26.0(eslint@9.22.0)(typescript@5.7.3) - eslint: 9.22.0 + '@typescript-eslint/eslint-plugin': 8.26.0(@typescript-eslint/parser@8.26.0(eslint@9.22.0(jiti@1.21.7))(typescript@5.7.3))(eslint@9.22.0(jiti@1.21.7))(typescript@5.7.3) + '@typescript-eslint/parser': 8.26.0(eslint@9.22.0(jiti@1.21.7))(typescript@5.7.3) + '@typescript-eslint/utils': 8.26.0(eslint@9.22.0(jiti@1.21.7))(typescript@5.7.3) + eslint: 9.22.0(jiti@1.21.7) typescript: 5.7.3 transitivePeerDependencies: - supports-color typescript@5.7.3: {} + update-browserslist-db@1.1.3(browserslist@4.24.4): + dependencies: + browserslist: 4.24.4 + escalade: 3.2.0 + picocolors: 1.1.1 + uri-js@4.4.1: dependencies: punycode: 2.3.1 - vite@6.2.1: + util-deprecate@1.0.2: {} + + vite@6.2.1(jiti@1.21.7)(yaml@2.7.0): dependencies: esbuild: 0.25.1 postcss: 8.5.3 rollup: 4.35.0 optionalDependencies: fsevents: 2.3.3 + jiti: 1.21.7 + yaml: 2.7.0 which@2.0.2: dependencies: @@ -1938,4 +2567,18 @@ snapshots: word-wrap@1.2.5: {} + wrap-ansi@7.0.0: + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + + wrap-ansi@8.1.0: + dependencies: + ansi-styles: 6.2.1 + string-width: 5.1.2 + strip-ansi: 7.1.0 + + yaml@2.7.0: {} + yocto-queue@0.1.0: {} diff --git a/postcss.config.js b/postcss.config.js new file mode 100644 index 00000000..2e7af2b7 --- /dev/null +++ b/postcss.config.js @@ -0,0 +1,6 @@ +export default { + plugins: { + tailwindcss: {}, + autoprefixer: {}, + }, +} diff --git a/src/index.css b/src/index.css index 08a3ac9e..d3deb51a 100644 --- a/src/index.css +++ b/src/index.css @@ -1,3 +1,7 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; + :root { font-family: system-ui, Avenir, Helvetica, Arial, sans-serif; line-height: 1.5; @@ -18,6 +22,7 @@ a { color: #646cff; text-decoration: inherit; } + a:hover { color: #535bf2; } @@ -46,9 +51,11 @@ button { cursor: pointer; transition: border-color 0.25s; } + button:hover { border-color: #646cff; } + button:focus, button:focus-visible { outline: 4px auto -webkit-focus-ring-color; @@ -59,10 +66,12 @@ button:focus-visible { color: #213547; background-color: #ffffff; } + a:hover { color: #747bff; } + button { background-color: #f9f9f9; } -} +} \ No newline at end of file diff --git a/tailwind.config.js b/tailwind.config.js new file mode 100644 index 00000000..dca8ba02 --- /dev/null +++ b/tailwind.config.js @@ -0,0 +1,11 @@ +/** @type {import('tailwindcss').Config} */ +export default { + content: [ + "./index.html", + "./src/**/*.{js,ts,jsx,tsx}", + ], + theme: { + extend: {}, + }, + plugins: [], +} From f0a3d9806bc76c23f56d2cdc60f63a32e5ecc0eb Mon Sep 17 00:00:00 2001 From: Marios Tsigkas Date: Mon, 10 Mar 2025 18:45:04 +0200 Subject: [PATCH 04/96] Add API integration for cat images and breeds; implement data parsing and type definitions --- package.json | 12 ++- pnpm-lock.yaml | 233 +++++++++++++++++++++++++++++++++++++++++++++ src/api/catApi.ts | 20 ++++ src/api/parsers.ts | 40 ++++++++ src/api/types.ts | 11 +++ src/main.tsx | 5 +- 6 files changed, 315 insertions(+), 6 deletions(-) create mode 100644 src/api/catApi.ts create mode 100644 src/api/parsers.ts create mode 100644 src/api/types.ts diff --git a/package.json b/package.json index 15e496a2..4d349c6a 100644 --- a/package.json +++ b/package.json @@ -10,25 +10,27 @@ "preview": "vite preview" }, "dependencies": { + "axios": "^1.8.2", "react": "^19.0.0", - "react-dom": "^19.0.0" + "react-dom": "^19.0.0", + "react-router-dom": "^7.3.0" }, "devDependencies": { "@eslint/js": "^9.21.0", "@types/react": "^19.0.10", "@types/react-dom": "^19.0.4", "@vitejs/plugin-react-swc": "^3.8.0", + "autoprefixer": "^10.4.18", "eslint": "^9.21.0", "eslint-plugin-react-dom": "^1.31.0", "eslint-plugin-react-hooks": "^5.1.0", "eslint-plugin-react-refresh": "^0.4.19", "eslint-plugin-react-x": "^1.31.0", "globals": "^15.15.0", + "postcss": "^8.4.35", + "tailwindcss": "^3.4.1", "typescript": "~5.7.2", "typescript-eslint": "^8.24.1", - "vite": "^6.2.0", - "autoprefixer": "^10.4.18", - "postcss": "^8.4.35", - "tailwindcss": "^3.4.1" + "vite": "^6.2.0" } } \ No newline at end of file diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 5f8b3b19..685ebe8a 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -8,12 +8,18 @@ importers: .: dependencies: + axios: + specifier: ^1.8.2 + version: 1.8.2 react: specifier: ^19.0.0 version: 19.0.0 react-dom: specifier: ^19.0.0 version: 19.0.0(react@19.0.0) + react-router-dom: + specifier: ^7.3.0 + version: 7.3.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0) devDependencies: '@eslint/js': specifier: ^9.21.0 @@ -510,6 +516,9 @@ packages: '@swc/types@0.1.19': resolution: {integrity: sha512-WkAZaAfj44kh/UFdAQcrMP1I0nwRqpt27u+08LMBYMqmQfwwMofYoMh/48NGkMMRfC4ynpfwRbJuu8ErfNloeA==} + '@types/cookie@0.6.0': + resolution: {integrity: sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==} + '@types/estree@1.0.6': resolution: {integrity: sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==} @@ -618,6 +627,9 @@ packages: argparse@2.0.1: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + asynckit@0.4.0: + resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} + autoprefixer@10.4.21: resolution: {integrity: sha512-O+A6LWV5LDHSJD3LjHYoNi4VLsj/Whi7k6zG12xTYaU4cQ8oxQGckXNX8cRHK5yOZ/ppVHe0ZBXGzSV9jXdVbQ==} engines: {node: ^10 || ^12 || >=14} @@ -625,6 +637,9 @@ packages: peerDependencies: postcss: ^8.1.0 + axios@1.8.2: + resolution: {integrity: sha512-ls4GYBm5aig9vWx8AWDSGLpnpDQRtWAfrjU+EuytuODrFBkqesN2RkOQCBzrA1RQNHw1SmRMSDDDSwzNAYQ6Rg==} + balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} @@ -650,6 +665,10 @@ packages: engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true + call-bind-apply-helpers@1.0.2: + resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} + engines: {node: '>= 0.4'} + callsites@3.1.0: resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} engines: {node: '>=6'} @@ -676,6 +695,10 @@ packages: color-name@1.1.4: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + combined-stream@1.0.8: + resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} + engines: {node: '>= 0.8'} + commander@4.1.1: resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} engines: {node: '>= 6'} @@ -686,6 +709,10 @@ packages: concat-map@0.0.1: resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + cookie@1.0.2: + resolution: {integrity: sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==} + engines: {node: '>=18'} + cross-spawn@7.0.6: resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} engines: {node: '>= 8'} @@ -710,12 +737,20 @@ packages: deep-is@0.1.4: resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} + delayed-stream@1.0.0: + resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} + engines: {node: '>=0.4.0'} + didyoumean@1.2.2: resolution: {integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==} dlv@1.1.3: resolution: {integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==} + dunder-proto@1.0.1: + resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} + engines: {node: '>= 0.4'} + eastasianwidth@0.2.0: resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} @@ -728,6 +763,22 @@ packages: emoji-regex@9.2.2: resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} + es-define-property@1.0.1: + resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} + engines: {node: '>= 0.4'} + + es-errors@1.3.0: + resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} + engines: {node: '>= 0.4'} + + es-object-atoms@1.1.1: + resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} + engines: {node: '>= 0.4'} + + es-set-tostringtag@2.1.0: + resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==} + engines: {node: '>= 0.4'} + esbuild@0.25.1: resolution: {integrity: sha512-BGO5LtrGC7vxnqucAe/rmvKdJllfGaYWdyABvyMoXQlfYMb2bbRuReWR5tEGE//4LcNJj9XrkovTqNYRFZHAMQ==} engines: {node: '>=18'} @@ -852,10 +903,23 @@ packages: flatted@3.3.3: resolution: {integrity: sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==} + follow-redirects@1.15.9: + resolution: {integrity: sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==} + engines: {node: '>=4.0'} + peerDependencies: + debug: '*' + peerDependenciesMeta: + debug: + optional: true + foreground-child@3.3.1: resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==} engines: {node: '>=14'} + form-data@4.0.2: + resolution: {integrity: sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w==} + engines: {node: '>= 6'} + fraction.js@4.3.7: resolution: {integrity: sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==} @@ -867,6 +931,14 @@ packages: function-bind@1.1.2: resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + get-intrinsic@1.3.0: + resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} + engines: {node: '>= 0.4'} + + get-proto@1.0.1: + resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} + engines: {node: '>= 0.4'} + glob-parent@5.1.2: resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} engines: {node: '>= 6'} @@ -887,6 +959,10 @@ packages: resolution: {integrity: sha512-7ACyT3wmyp3I61S4fG682L0VA2RGD9otkqGJIwNUMF1SWUombIIk+af1unuDYgMm082aHYwD+mzJvv9Iu8dsgg==} engines: {node: '>=18'} + gopd@1.2.0: + resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} + engines: {node: '>= 0.4'} + graphemer@1.4.0: resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} @@ -894,6 +970,14 @@ packages: resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} engines: {node: '>=8'} + has-symbols@1.1.0: + resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} + engines: {node: '>= 0.4'} + + has-tostringtag@1.0.2: + resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} + engines: {node: '>= 0.4'} + hasown@2.0.2: resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} engines: {node: '>= 0.4'} @@ -981,6 +1065,10 @@ packages: lru-cache@10.4.3: resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} + math-intrinsics@1.1.0: + resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} + engines: {node: '>= 0.4'} + merge2@1.4.1: resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} engines: {node: '>= 8'} @@ -989,6 +1077,14 @@ packages: resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} engines: {node: '>=8.6'} + mime-db@1.52.0: + resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} + engines: {node: '>= 0.6'} + + mime-types@2.1.35: + resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} + engines: {node: '>= 0.6'} + minimatch@3.1.2: resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} @@ -1131,6 +1227,9 @@ packages: resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} engines: {node: '>= 0.8.0'} + proxy-from-env@1.1.0: + resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} + punycode@2.3.1: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} @@ -1143,6 +1242,23 @@ packages: peerDependencies: react: ^19.0.0 + react-router-dom@7.3.0: + resolution: {integrity: sha512-z7Q5FTiHGgQfEurX/FBinkOXhWREJIAB2RiU24lvcBa82PxUpwqvs/PAXb9lJyPjTs2jrl6UkLvCZVGJPeNuuQ==} + engines: {node: '>=20.0.0'} + peerDependencies: + react: '>=18' + react-dom: '>=18' + + react-router@7.3.0: + resolution: {integrity: sha512-466f2W7HIWaNXTKM5nHTqNxLrHTyXybm7R0eBlVSt0k/u55tTCDO194OIx/NrYD4TS5SXKTNekXfT37kMKUjgw==} + engines: {node: '>=20.0.0'} + peerDependencies: + react: '>=18' + react-dom: '>=18' + peerDependenciesMeta: + react-dom: + optional: true + react@19.0.0: resolution: {integrity: sha512-V8AVnmPIICiWpGfm6GLzCR/W5FXLchHop40W4nXBmdlEceh16rCN8O8LNWm5bh5XUX91fh7KpA+W0TgMKmgTpQ==} engines: {node: '>=0.10.0'} @@ -1183,6 +1299,9 @@ packages: engines: {node: '>=10'} hasBin: true + set-cookie-parser@2.7.1: + resolution: {integrity: sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ==} + shebang-command@2.0.0: resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} engines: {node: '>=8'} @@ -1263,6 +1382,9 @@ packages: ts-pattern@5.6.2: resolution: {integrity: sha512-d4IxJUXROL5NCa3amvMg6VQW2HVtZYmUTPfvVtO7zJWGYLJ+mry9v2OmYm+z67aniQoQ8/yFNadiEwtNS9qQiw==} + turbo-stream@2.4.0: + resolution: {integrity: sha512-FHncC10WpBd2eOmGwpmQsWLDoK4cqsA/UT/GqNoaKOQnT8uzhtCbg3EoUDMvqpOSAI0S26mr0rkjzbOO6S3v1g==} + type-check@0.4.0: resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} engines: {node: '>= 0.8.0'} @@ -1715,6 +1837,8 @@ snapshots: dependencies: '@swc/counter': 0.1.3 + '@types/cookie@0.6.0': {} + '@types/estree@1.0.6': {} '@types/json-schema@7.0.15': {} @@ -1845,6 +1969,8 @@ snapshots: argparse@2.0.1: {} + asynckit@0.4.0: {} + autoprefixer@10.4.21(postcss@8.5.3): dependencies: browserslist: 4.24.4 @@ -1855,6 +1981,14 @@ snapshots: postcss: 8.5.3 postcss-value-parser: 4.2.0 + axios@1.8.2: + dependencies: + follow-redirects: 1.15.9 + form-data: 4.0.2 + proxy-from-env: 1.1.0 + transitivePeerDependencies: + - debug + balanced-match@1.0.2: {} binary-extensions@2.3.0: {} @@ -1881,6 +2015,11 @@ snapshots: node-releases: 2.0.19 update-browserslist-db: 1.1.3(browserslist@4.24.4) + call-bind-apply-helpers@1.0.2: + dependencies: + es-errors: 1.3.0 + function-bind: 1.1.2 + callsites@3.1.0: {} camelcase-css@2.0.1: {} @@ -1910,12 +2049,18 @@ snapshots: color-name@1.1.4: {} + combined-stream@1.0.8: + dependencies: + delayed-stream: 1.0.0 + commander@4.1.1: {} compare-versions@6.1.1: {} concat-map@0.0.1: {} + cookie@1.0.2: {} + cross-spawn@7.0.6: dependencies: path-key: 3.1.1 @@ -1932,10 +2077,18 @@ snapshots: deep-is@0.1.4: {} + delayed-stream@1.0.0: {} + didyoumean@1.2.2: {} dlv@1.1.3: {} + dunder-proto@1.0.1: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-errors: 1.3.0 + gopd: 1.2.0 + eastasianwidth@0.2.0: {} electron-to-chromium@1.5.114: {} @@ -1944,6 +2097,21 @@ snapshots: emoji-regex@9.2.2: {} + es-define-property@1.0.1: {} + + es-errors@1.3.0: {} + + es-object-atoms@1.1.1: + dependencies: + es-errors: 1.3.0 + + es-set-tostringtag@2.1.0: + dependencies: + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + has-tostringtag: 1.0.2 + hasown: 2.0.2 + esbuild@0.25.1: optionalDependencies: '@esbuild/aix-ppc64': 0.25.1 @@ -2133,11 +2301,20 @@ snapshots: flatted@3.3.3: {} + follow-redirects@1.15.9: {} + foreground-child@3.3.1: dependencies: cross-spawn: 7.0.6 signal-exit: 4.1.0 + form-data@4.0.2: + dependencies: + asynckit: 0.4.0 + combined-stream: 1.0.8 + es-set-tostringtag: 2.1.0 + mime-types: 2.1.35 + fraction.js@4.3.7: {} fsevents@2.3.3: @@ -2145,6 +2322,24 @@ snapshots: function-bind@1.1.2: {} + get-intrinsic@1.3.0: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-define-property: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + function-bind: 1.1.2 + get-proto: 1.0.1 + gopd: 1.2.0 + has-symbols: 1.1.0 + hasown: 2.0.2 + math-intrinsics: 1.1.0 + + get-proto@1.0.1: + dependencies: + dunder-proto: 1.0.1 + es-object-atoms: 1.1.1 + glob-parent@5.1.2: dependencies: is-glob: 4.0.3 @@ -2166,10 +2361,18 @@ snapshots: globals@15.15.0: {} + gopd@1.2.0: {} + graphemer@1.4.0: {} has-flag@4.0.0: {} + has-symbols@1.1.0: {} + + has-tostringtag@1.0.2: + dependencies: + has-symbols: 1.1.0 + hasown@2.0.2: dependencies: function-bind: 1.1.2 @@ -2242,6 +2445,8 @@ snapshots: lru-cache@10.4.3: {} + math-intrinsics@1.1.0: {} + merge2@1.4.1: {} micromatch@4.0.8: @@ -2249,6 +2454,12 @@ snapshots: braces: 3.0.3 picomatch: 2.3.1 + mime-db@1.52.0: {} + + mime-types@2.1.35: + dependencies: + mime-db: 1.52.0 + minimatch@3.1.2: dependencies: brace-expansion: 1.1.11 @@ -2364,6 +2575,8 @@ snapshots: prelude-ls@1.2.1: {} + proxy-from-env@1.1.0: {} + punycode@2.3.1: {} queue-microtask@1.2.3: {} @@ -2373,6 +2586,22 @@ snapshots: react: 19.0.0 scheduler: 0.25.0 + react-router-dom@7.3.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0): + dependencies: + react: 19.0.0 + react-dom: 19.0.0(react@19.0.0) + react-router: 7.3.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + + react-router@7.3.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0): + dependencies: + '@types/cookie': 0.6.0 + cookie: 1.0.2 + react: 19.0.0 + set-cookie-parser: 2.7.1 + turbo-stream: 2.4.0 + optionalDependencies: + react-dom: 19.0.0(react@19.0.0) + react@19.0.0: {} read-cache@1.0.0: @@ -2426,6 +2655,8 @@ snapshots: semver@7.7.1: {} + set-cookie-parser@2.7.1: {} + shebang-command@2.0.0: dependencies: shebang-regex: 3.0.0 @@ -2523,6 +2754,8 @@ snapshots: ts-pattern@5.6.2: {} + turbo-stream@2.4.0: {} + type-check@0.4.0: dependencies: prelude-ls: 1.2.1 diff --git a/src/api/catApi.ts b/src/api/catApi.ts new file mode 100644 index 00000000..44294f57 --- /dev/null +++ b/src/api/catApi.ts @@ -0,0 +1,20 @@ +import axios from 'axios' +import { parseCatImages, parseBreeds } from './parsers' +import { CatImage, Breed } from './types' + +const BASE_URL = 'https://api.thecatapi.com/v1' + +export const getRandomImages = async (limit = 10): Promise => { + const res = await axios.get(`${BASE_URL}/images/search?limit=${limit.toString()}`) + return parseCatImages(res.data) +} + +export const getBreeds = async (): Promise => { + const res = await axios.get(`${BASE_URL}/breeds`) + return parseBreeds(res.data) +} + +export const getBreedImages = async (breedId: string, limit = 10): Promise => { + const res = await axios.get(`${BASE_URL}/images/search?breed_ids=${breedId}&limit=${limit.toString()}`) + return parseCatImages(res.data) +} diff --git a/src/api/parsers.ts b/src/api/parsers.ts new file mode 100644 index 00000000..a3d974c4 --- /dev/null +++ b/src/api/parsers.ts @@ -0,0 +1,40 @@ +import { CatImage, Breed } from './types' + +export const parseCatImages = (data: unknown): CatImage[] => { + if (!Array.isArray(data)) { + throw new Error("Invalid data: Expected an array for CatImages") + } + return data.map((item: unknown) => { + if (typeof item !== 'object' || item === null || !('id' in item) || !('url' in item)) { + throw new Error("Invalid data: Expected an object with id, name and description for Breed") + } + return { + id: String(item.id), + url: String(item.url), + breeds: 'breeds' in item ? parseBreeds(item.breeds) : undefined, + } + }) +} + +export const parseBreeds = (data: unknown): Breed[] => { + if (!Array.isArray(data)) { + throw new Error("Invalid data: Expected an array for Breeds") + } + return data.map((item: unknown) => { + if ( + typeof item !== 'object' || + item === null || + !('id' in item) || + !('name' in item) || + !('description' in item) + ) { + throw new Error("Invalid data: Expected an object with id, name and description for Breed") + } + + return { + id: String(item.id), + name: String(item.name), + description: String(item.description), + } + }) +} diff --git a/src/api/types.ts b/src/api/types.ts new file mode 100644 index 00000000..1ce97d5c --- /dev/null +++ b/src/api/types.ts @@ -0,0 +1,11 @@ +export interface CatImage { + id: string + url: string + breeds?: Breed[] +} + +export interface Breed { + id: string + name: string + description: string +} diff --git a/src/main.tsx b/src/main.tsx index e3c887b3..ba09b2fa 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -1,5 +1,6 @@ import { StrictMode } from 'react' import { createRoot } from 'react-dom/client' +import { BrowserRouter } from 'react-router-dom' import './index.css' import App from './App.tsx' @@ -11,6 +12,8 @@ if (!rootElement) { createRoot(rootElement).render( - + + + , ) From c0e7447dc0b9b5e6a770863d83e96824ea7cc601 Mon Sep 17 00:00:00 2001 From: Marios Tsigkas Date: Mon, 10 Mar 2025 19:25:54 +0200 Subject: [PATCH 05/96] Add Vitest configuration and tests for cat API; implement data parsing and error handling --- package.json | 9 +- pnpm-lock.yaml | 833 +++++++++++++++++++++++++++++- src/api/__tests__/catApi.test.ts | 122 +++++ src/api/__tests__/parsers.test.ts | 71 +++ vite.config.ts | 10 +- 5 files changed, 1041 insertions(+), 4 deletions(-) create mode 100644 src/api/__tests__/catApi.test.ts create mode 100644 src/api/__tests__/parsers.test.ts diff --git a/package.json b/package.json index 4d349c6a..9fdb9d85 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,9 @@ "dev": "vite", "build": "tsc -b && vite build", "lint": "eslint .", - "preview": "vite preview" + "preview": "vite preview", + "test": "vitest", + "coverage": "vitest run --coverage" }, "dependencies": { "axios": "^1.8.2", @@ -20,6 +22,7 @@ "@types/react": "^19.0.10", "@types/react-dom": "^19.0.4", "@vitejs/plugin-react-swc": "^3.8.0", + "@vitest/coverage-v8": "^1.5.0", "autoprefixer": "^10.4.18", "eslint": "^9.21.0", "eslint-plugin-react-dom": "^1.31.0", @@ -27,10 +30,12 @@ "eslint-plugin-react-refresh": "^0.4.19", "eslint-plugin-react-x": "^1.31.0", "globals": "^15.15.0", + "jsdom": "^24.0.0", "postcss": "^8.4.35", "tailwindcss": "^3.4.1", "typescript": "~5.7.2", "typescript-eslint": "^8.24.1", - "vite": "^6.2.0" + "vite": "^6.2.1", + "vitest": "^3.0.8" } } \ No newline at end of file diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 685ebe8a..70f50762 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -33,6 +33,9 @@ importers: '@vitejs/plugin-react-swc': specifier: ^3.8.0 version: 3.8.0(vite@6.2.1(jiti@1.21.7)(yaml@2.7.0)) + '@vitest/coverage-v8': + specifier: ^1.5.0 + version: 1.6.1(vitest@3.0.8(jiti@1.21.7)(jsdom@24.1.3)(yaml@2.7.0)) autoprefixer: specifier: ^10.4.18 version: 10.4.21(postcss@8.5.3) @@ -54,6 +57,9 @@ importers: globals: specifier: ^15.15.0 version: 15.15.0 + jsdom: + specifier: ^24.0.0 + version: 24.1.3 postcss: specifier: ^8.4.35 version: 8.5.3 @@ -67,8 +73,11 @@ importers: specifier: ^8.24.1 version: 8.26.0(eslint@9.22.0(jiti@1.21.7))(typescript@5.7.3) vite: - specifier: ^6.2.0 + specifier: ^6.2.1 version: 6.2.1(jiti@1.21.7)(yaml@2.7.0) + vitest: + specifier: ^3.0.8 + version: 3.0.8(jiti@1.21.7)(jsdom@24.1.3)(yaml@2.7.0) packages: @@ -76,6 +85,61 @@ packages: resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==} engines: {node: '>=10'} + '@ampproject/remapping@2.3.0': + resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} + engines: {node: '>=6.0.0'} + + '@asamuzakjp/css-color@3.1.1': + resolution: {integrity: sha512-hpRD68SV2OMcZCsrbdkccTw5FXjNDLo5OuqSHyHZfwweGsDWZwDJ2+gONyNAbazZclobMirACLw0lk8WVxIqxA==} + + '@babel/helper-string-parser@7.25.9': + resolution: {integrity: sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-identifier@7.25.9': + resolution: {integrity: sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==} + engines: {node: '>=6.9.0'} + + '@babel/parser@7.26.9': + resolution: {integrity: sha512-81NWa1njQblgZbQHxWHpxxCzNsa3ZwvFqpUg7P+NNUU6f3UU2jBEg4OlF/J6rl8+PQGh1q6/zWScd001YwcA5A==} + engines: {node: '>=6.0.0'} + hasBin: true + + '@babel/types@7.26.9': + resolution: {integrity: sha512-Y3IR1cRnOxOCDvMmNiym7XpXQ93iGDDPHx+Zj+NM+rg0fBaShfQLkg+hKPaZCEvg5N/LeCo4+Rj/i3FuJsIQaw==} + engines: {node: '>=6.9.0'} + + '@bcoe/v8-coverage@0.2.3': + resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==} + + '@csstools/color-helpers@5.0.2': + resolution: {integrity: sha512-JqWH1vsgdGcw2RR6VliXXdA0/59LttzlU8UlRT/iUUsEeWfYq8I+K0yhihEUTTHLRm1EXvpsCx3083EU15ecsA==} + engines: {node: '>=18'} + + '@csstools/css-calc@2.1.2': + resolution: {integrity: sha512-TklMyb3uBB28b5uQdxjReG4L80NxAqgrECqLZFQbyLekwwlcDDS8r3f07DKqeo8C4926Br0gf/ZDe17Zv4wIuw==} + engines: {node: '>=18'} + peerDependencies: + '@csstools/css-parser-algorithms': ^3.0.4 + '@csstools/css-tokenizer': ^3.0.3 + + '@csstools/css-color-parser@3.0.8': + resolution: {integrity: sha512-pdwotQjCCnRPuNi06jFuP68cykU1f3ZWExLe/8MQ1LOs8Xq+fTkYgd+2V8mWUWMrOn9iS2HftPVaMZDaXzGbhQ==} + engines: {node: '>=18'} + peerDependencies: + '@csstools/css-parser-algorithms': ^3.0.4 + '@csstools/css-tokenizer': ^3.0.3 + + '@csstools/css-parser-algorithms@3.0.4': + resolution: {integrity: sha512-Up7rBoV77rv29d3uKHUIVubz1BTcgyUK72IvCQAbfbMv584xHcGKCKbWh7i8hPrRJ7qU4Y8IO3IY9m+iTB7P3A==} + engines: {node: '>=18'} + peerDependencies: + '@csstools/css-tokenizer': ^3.0.3 + + '@csstools/css-tokenizer@3.0.3': + resolution: {integrity: sha512-UJnjoFsmxfKUdNYdWgOB0mWUypuLvAfQPH1+pyvRJs6euowbFkFC6P13w1l8mJyi3vxYMxc9kld5jZEGRQs6bw==} + engines: {node: '>=18'} + '@esbuild/aix-ppc64@0.25.1': resolution: {integrity: sha512-kfYGy8IdzTGy+z0vFGvExZtxkFlA4zAxgKEahG9KE1ScBjpQnFsNOX8KTU5ojNru5ed5CVoJYXFtoxaq5nFbjQ==} engines: {node: '>=18'} @@ -312,6 +376,10 @@ packages: resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} engines: {node: '>=12'} + '@istanbuljs/schema@0.1.3': + resolution: {integrity: sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==} + engines: {node: '>=8'} + '@jridgewell/gen-mapping@0.3.8': resolution: {integrity: sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==} engines: {node: '>=6.0.0'} @@ -585,6 +653,40 @@ packages: peerDependencies: vite: ^4 || ^5 || ^6 + '@vitest/coverage-v8@1.6.1': + resolution: {integrity: sha512-6YeRZwuO4oTGKxD3bijok756oktHSIm3eczVVzNe3scqzuhLwltIF3S9ZL/vwOVIpURmU6SnZhziXXAfw8/Qlw==} + peerDependencies: + vitest: 1.6.1 + + '@vitest/expect@3.0.8': + resolution: {integrity: sha512-Xu6TTIavTvSSS6LZaA3EebWFr6tsoXPetOWNMOlc7LO88QVVBwq2oQWBoDiLCN6YTvNYsGSjqOO8CAdjom5DCQ==} + + '@vitest/mocker@3.0.8': + resolution: {integrity: sha512-n3LjS7fcW1BCoF+zWZxG7/5XvuYH+lsFg+BDwwAz0arIwHQJFUEsKBQ0BLU49fCxuM/2HSeBPHQD8WjgrxMfow==} + peerDependencies: + msw: ^2.4.9 + vite: ^5.0.0 || ^6.0.0 + peerDependenciesMeta: + msw: + optional: true + vite: + optional: true + + '@vitest/pretty-format@3.0.8': + resolution: {integrity: sha512-BNqwbEyitFhzYMYHUVbIvepOyeQOSFA/NeJMIP9enMntkkxLgOcgABH6fjyXG85ipTgvero6noreavGIqfJcIg==} + + '@vitest/runner@3.0.8': + resolution: {integrity: sha512-c7UUw6gEcOzI8fih+uaAXS5DwjlBaCJUo7KJ4VvJcjL95+DSR1kova2hFuRt3w41KZEFcOEiq098KkyrjXeM5w==} + + '@vitest/snapshot@3.0.8': + resolution: {integrity: sha512-x8IlMGSEMugakInj44nUrLSILh/zy1f2/BgH0UeHpNyOocG18M9CWVIFBaXPt8TrqVZWmcPjwfG/ht5tnpba8A==} + + '@vitest/spy@3.0.8': + resolution: {integrity: sha512-MR+PzJa+22vFKYb934CejhR4BeRpMSoxkvNoDit68GQxRLSf11aT6CTj3XaqUU9rxgWJFnqicN/wxw6yBRkI1Q==} + + '@vitest/utils@3.0.8': + resolution: {integrity: sha512-nkBC3aEhfX2PdtQI/QwAWp8qZWwzASsU4Npbcd5RdMPBSSLCpkZp52P3xku3s3uA0HIEhGvEcF8rNkBsz9dQ4Q==} + acorn-jsx@5.3.2: resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} peerDependencies: @@ -595,6 +697,10 @@ packages: engines: {node: '>=0.4.0'} hasBin: true + agent-base@7.1.3: + resolution: {integrity: sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==} + engines: {node: '>= 14'} + ajv@6.12.6: resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} @@ -627,6 +733,10 @@ packages: argparse@2.0.1: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + assertion-error@2.0.1: + resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} + engines: {node: '>=12'} + asynckit@0.4.0: resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} @@ -665,6 +775,10 @@ packages: engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true + cac@6.7.14: + resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} + engines: {node: '>=8'} + call-bind-apply-helpers@1.0.2: resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} engines: {node: '>= 0.4'} @@ -680,10 +794,18 @@ packages: caniuse-lite@1.0.30001703: resolution: {integrity: sha512-kRlAGTRWgPsOj7oARC9m1okJEXdL/8fekFVcxA8Hl7GH4r/sN4OJn/i6Flde373T50KS7Y37oFbMwlE8+F42kQ==} + chai@5.2.0: + resolution: {integrity: sha512-mCuXncKXk5iCLhfhwTc0izo0gtEmpz5CtG2y8GiOINBlMVS6v8TMRc5TaLWKS6692m9+dVVfzgeVxR5UxWHTYw==} + engines: {node: '>=12'} + chalk@4.1.2: resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} engines: {node: '>=10'} + check-error@2.1.1: + resolution: {integrity: sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==} + engines: {node: '>= 16'} + chokidar@3.6.0: resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} engines: {node: '>= 8.10.0'} @@ -722,9 +844,17 @@ packages: engines: {node: '>=4'} hasBin: true + cssstyle@4.3.0: + resolution: {integrity: sha512-6r0NiY0xizYqfBvWp1G7WXJ06/bZyrk7Dc6PHql82C/pKGUTKu4yAX4Y8JPamb1ob9nBKuxWzCGTRuGwU3yxJQ==} + engines: {node: '>=18'} + csstype@3.1.3: resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} + data-urls@5.0.0: + resolution: {integrity: sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg==} + engines: {node: '>=18'} + debug@4.4.0: resolution: {integrity: sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==} engines: {node: '>=6.0'} @@ -734,6 +864,13 @@ packages: supports-color: optional: true + decimal.js@10.5.0: + resolution: {integrity: sha512-8vDa8Qxvr/+d94hSh5P3IJwI5t8/c0KsMp+g8bNw9cY2icONa5aPfvKeieW1WlG0WQYwwhJ7mjui2xtiePQSXw==} + + deep-eql@5.0.2: + resolution: {integrity: sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==} + engines: {node: '>=6'} + deep-is@0.1.4: resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} @@ -763,6 +900,10 @@ packages: emoji-regex@9.2.2: resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} + entities@4.5.0: + resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} + engines: {node: '>=0.12'} + es-define-property@1.0.1: resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} engines: {node: '>= 0.4'} @@ -771,6 +912,9 @@ packages: resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} engines: {node: '>= 0.4'} + es-module-lexer@1.6.0: + resolution: {integrity: sha512-qqnD1yMU6tk/jnaMosogGySTZP8YtUgAffA9nMN+E/rjxcfRQ6IEk7IiozUjgxKoFHBGjTLnrHB/YC45r/59EQ==} + es-object-atoms@1.1.1: resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} engines: {node: '>= 0.4'} @@ -864,10 +1008,17 @@ packages: resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} engines: {node: '>=4.0'} + estree-walker@3.0.3: + resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} + esutils@2.0.3: resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} engines: {node: '>=0.10.0'} + expect-type@1.2.0: + resolution: {integrity: sha512-80F22aiJ3GLyVnS/B3HzgR6RelZVumzj9jkL0Rhz4h0xYbNW9PjlQz5h3J/SShErbXBc295vseR4/MIbVmUbeA==} + engines: {node: '>=12.0.0'} + fast-deep-equal@3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} @@ -923,6 +1074,9 @@ packages: fraction.js@4.3.7: resolution: {integrity: sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==} + fs.realpath@1.0.0: + resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} + fsevents@2.3.3: resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} @@ -951,6 +1105,10 @@ packages: resolution: {integrity: sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==} hasBin: true + glob@7.2.3: + resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} + deprecated: Glob versions prior to v9 are no longer supported + globals@14.0.0: resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==} engines: {node: '>=18'} @@ -982,6 +1140,25 @@ packages: resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} engines: {node: '>= 0.4'} + html-encoding-sniffer@4.0.0: + resolution: {integrity: sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==} + engines: {node: '>=18'} + + html-escaper@2.0.2: + resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==} + + http-proxy-agent@7.0.2: + resolution: {integrity: sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==} + engines: {node: '>= 14'} + + https-proxy-agent@7.0.6: + resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==} + engines: {node: '>= 14'} + + iconv-lite@0.6.3: + resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} + engines: {node: '>=0.10.0'} + ignore@5.3.2: resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} engines: {node: '>= 4'} @@ -994,6 +1171,13 @@ packages: resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} engines: {node: '>=0.8.19'} + inflight@1.0.6: + resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} + deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful. + + inherits@2.0.4: + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + is-binary-path@2.1.0: resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} engines: {node: '>=8'} @@ -1018,9 +1202,28 @@ packages: resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} engines: {node: '>=0.12.0'} + is-potential-custom-element-name@1.0.1: + resolution: {integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==} + isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + istanbul-lib-coverage@3.2.2: + resolution: {integrity: sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==} + engines: {node: '>=8'} + + istanbul-lib-report@3.0.1: + resolution: {integrity: sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==} + engines: {node: '>=10'} + + istanbul-lib-source-maps@5.0.6: + resolution: {integrity: sha512-yg2d+Em4KizZC5niWhQaIomgf5WlL4vOOjZ5xGCmF8SnPE/mDWWXgvRExdcpCgh9lLRRa1/fSYp2ymmbJ1pI+A==} + engines: {node: '>=10'} + + istanbul-reports@3.1.7: + resolution: {integrity: sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==} + engines: {node: '>=8'} + jackspeak@3.4.3: resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==} @@ -1028,10 +1231,22 @@ packages: resolution: {integrity: sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==} hasBin: true + js-tokens@9.0.1: + resolution: {integrity: sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==} + js-yaml@4.1.0: resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} hasBin: true + jsdom@24.1.3: + resolution: {integrity: sha512-MyL55p3Ut3cXbeBEG7Hcv0mVM8pp8PBNWxRqchZnSfAiES1v1mRnMeFfaHWIPULpwsYfvO+ZmMZz5tGCnjzDUQ==} + engines: {node: '>=18'} + peerDependencies: + canvas: ^2.11.2 + peerDependenciesMeta: + canvas: + optional: true + json-buffer@3.0.1: resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} @@ -1062,9 +1277,22 @@ packages: lodash.merge@4.6.2: resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} + loupe@3.1.3: + resolution: {integrity: sha512-kkIp7XSkP78ZxJEsSxW3712C6teJVoeHHwgo9zJ380de7IYyJ2ISlxojcH2pC5OFLewESmnRi/+XCDIEEVyoug==} + lru-cache@10.4.3: resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} + magic-string@0.30.17: + resolution: {integrity: sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==} + + magicast@0.3.5: + resolution: {integrity: sha512-L0WhttDl+2BOsybvEOLK7fW3UA0OQ0IQ2d6Zl2x/a6vVRs3bAY0ECOSHHeL5jD+SbOpOCUEi0y1DgHEn9Qn1AQ==} + + make-dir@4.0.0: + resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==} + engines: {node: '>=10'} + math-intrinsics@1.1.0: resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} engines: {node: '>= 0.4'} @@ -1121,6 +1349,9 @@ packages: resolution: {integrity: sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==} engines: {node: '>=0.10.0'} + nwsapi@2.2.18: + resolution: {integrity: sha512-p1TRH/edngVEHVbwqWnxUViEmq5znDvyB+Sik5cmuLpGOIfDf/39zLiq3swPF8Vakqn+gvNiOQAZu8djYlQILA==} + object-assign@4.1.1: resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} engines: {node: '>=0.10.0'} @@ -1129,6 +1360,9 @@ packages: resolution: {integrity: sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==} engines: {node: '>= 6'} + once@1.4.0: + resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + optionator@0.9.4: resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} engines: {node: '>= 0.8.0'} @@ -1148,10 +1382,17 @@ packages: resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} engines: {node: '>=6'} + parse5@7.2.1: + resolution: {integrity: sha512-BuBYQYlv1ckiPdQi/ohiivi9Sagc9JG+Ozs0r7b/0iK3sKmrb0b9FdWdBbOdx6hBCM/F9Ir82ofnBhtZOjCRPQ==} + path-exists@4.0.0: resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} engines: {node: '>=8'} + path-is-absolute@1.0.1: + resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} + engines: {node: '>=0.10.0'} + path-key@3.1.1: resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} engines: {node: '>=8'} @@ -1163,6 +1404,13 @@ packages: resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} engines: {node: '>=16 || 14 >=14.18'} + pathe@2.0.3: + resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} + + pathval@2.0.0: + resolution: {integrity: sha512-vE7JKRyES09KiunauX7nd2Q9/L7lhok4smP9RZTDeD4MVs72Dp2qNFVz39Nz5a0FVEW0BJR6C0DYrq6unoziZA==} + engines: {node: '>= 14.16'} + picocolors@1.1.1: resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} @@ -1230,10 +1478,16 @@ packages: proxy-from-env@1.1.0: resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} + psl@1.15.0: + resolution: {integrity: sha512-JZd3gMVBAVQkSs6HdNZo9Sdo0LNcQeMNP3CozBJb3JYC/QUYZTnKxP+f8oWRX4rHP5EurWxqAHTSwUCjlNKa1w==} + punycode@2.3.1: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} + querystringify@2.2.0: + resolution: {integrity: sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==} + queue-microtask@1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} @@ -1270,6 +1524,9 @@ packages: resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} engines: {node: '>=8.10.0'} + requires-port@1.0.0: + resolution: {integrity: sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==} + resolve-from@4.0.0: resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} engines: {node: '>=4'} @@ -1288,9 +1545,22 @@ packages: engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true + rrweb-cssom@0.7.1: + resolution: {integrity: sha512-TrEMa7JGdVm0UThDJSx7ddw5nVm3UJS9o9CCIZ72B1vSyEZoziDqBYP3XIoi/12lKrJR8rE3jeFHMok2F/Mnsg==} + + rrweb-cssom@0.8.0: + resolution: {integrity: sha512-guoltQEx+9aMf2gDZ0s62EcV8lsXR+0w8915TC3ITdn2YueuNjdAYh/levpU9nFaoChh9RUS5ZdQMrKfVEN9tw==} + run-parallel@1.2.0: resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + safer-buffer@2.1.2: + resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + + saxes@6.0.0: + resolution: {integrity: sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==} + engines: {node: '>=v12.22.7'} + scheduler@0.25.0: resolution: {integrity: sha512-xFVuu11jh+xcO7JOAGJNOXld8/TcEHK/4CituBUeUb5hqxJLj9YuemAEuvm9gQ/+pgXYfbQuqAkiYu+u7YEsNA==} @@ -1310,6 +1580,9 @@ packages: resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} engines: {node: '>=8'} + siginfo@2.0.0: + resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} + signal-exit@4.1.0: resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} engines: {node: '>=14'} @@ -1318,6 +1591,12 @@ packages: resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} engines: {node: '>=0.10.0'} + stackback@0.0.2: + resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} + + std-env@3.8.1: + resolution: {integrity: sha512-vj5lIj3Mwf9D79hBkltk5qmkFI+biIKWS2IBxEyEU3AX1tUf7AoL8nSazCOiiqQsGKIq01SClsKEzweu34uwvA==} + string-ts@2.2.1: resolution: {integrity: sha512-Q2u0gko67PLLhbte5HmPfdOjNvUKbKQM+mCNQae6jE91DmoFHY6HH9GcdqCeNx87DZ2KKjiFxmA0R/42OneGWw==} @@ -1341,6 +1620,9 @@ packages: resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} engines: {node: '>=8'} + strip-literal@2.1.1: + resolution: {integrity: sha512-631UJ6O00eNGfMiWG78ck80dfBab8X6IVFB51jZK5Icd7XAs60Z5y7QdSd/wGIklnWvRbUNloVzhOKKmutxQ6Q==} + sucrase@3.35.0: resolution: {integrity: sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==} engines: {node: '>=16 || 14 >=14.17'} @@ -1354,11 +1636,18 @@ packages: resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} engines: {node: '>= 0.4'} + symbol-tree@3.2.4: + resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==} + tailwindcss@3.4.17: resolution: {integrity: sha512-w33E2aCvSDP0tW9RZuNXadXlkHXqFzSkQew/aIa2i/Sj8fThxwovwlXHSPXTbAHwEIhBFXAedUhP2tueAKP8Og==} engines: {node: '>=14.0.0'} hasBin: true + test-exclude@6.0.0: + resolution: {integrity: sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==} + engines: {node: '>=8'} + thenify-all@1.6.0: resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==} engines: {node: '>=0.8'} @@ -1366,10 +1655,36 @@ packages: thenify@3.3.1: resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==} + tinybench@2.9.0: + resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} + + tinyexec@0.3.2: + resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==} + + tinypool@1.0.2: + resolution: {integrity: sha512-al6n+QEANGFOMf/dmUMsuS5/r9B06uwlyNjZZql/zv8J7ybHCgoihBNORZCY2mzUuAnomQa2JdhyHKzZxPCrFA==} + engines: {node: ^18.0.0 || >=20.0.0} + + tinyrainbow@2.0.0: + resolution: {integrity: sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==} + engines: {node: '>=14.0.0'} + + tinyspy@3.0.2: + resolution: {integrity: sha512-n1cw8k1k0x4pgA2+9XrOkFydTerNcJ1zWCO5Nn9scWHTD+5tp8dghT2x1uduQePZTZgd3Tupf+x9BxJjeJi77Q==} + engines: {node: '>=14.0.0'} + to-regex-range@5.0.1: resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} engines: {node: '>=8.0'} + tough-cookie@4.1.4: + resolution: {integrity: sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==} + engines: {node: '>=6'} + + tr46@5.0.0: + resolution: {integrity: sha512-tk2G5R2KRwBd+ZN0zaEXpmzdKyOYksXwywulIX95MBODjSzMIuQnQ3m8JxgbhnL1LeVo7lqQKsYa1O3Htl7K5g==} + engines: {node: '>=18'} + ts-api-utils@2.0.1: resolution: {integrity: sha512-dnlgjFSVetynI8nzgJ+qF62efpglpWRk8isUEWZGWlJYySCTD6aKvbUDu+zbPeDakk3bg5H4XpitHukgfL1m9w==} engines: {node: '>=18.12'} @@ -1401,6 +1716,10 @@ packages: engines: {node: '>=14.17'} hasBin: true + universalify@0.2.0: + resolution: {integrity: sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==} + engines: {node: '>= 4.0.0'} + update-browserslist-db@1.1.3: resolution: {integrity: sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==} hasBin: true @@ -1410,9 +1729,17 @@ packages: uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + url-parse@1.5.10: + resolution: {integrity: sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==} + util-deprecate@1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + vite-node@3.0.8: + resolution: {integrity: sha512-6PhR4H9VGlcwXZ+KWCdMqbtG649xCPZqfI9j2PsK1FcXgEzro5bGHcVKFCTqPLaNKZES8Evqv4LwvZARsq5qlg==} + engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} + hasBin: true + vite@6.2.1: resolution: {integrity: sha512-n2GnqDb6XPhlt9B8olZPrgMD/es/Nd1RdChF6CBD/fHW6pUyUTt2sQW2fPRX5GiD9XEa6+8A6A4f2vT6pSsE7Q==} engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} @@ -1453,11 +1780,64 @@ packages: yaml: optional: true + vitest@3.0.8: + resolution: {integrity: sha512-dfqAsNqRGUc8hB9OVR2P0w8PZPEckti2+5rdZip0WIz9WW0MnImJ8XiR61QhqLa92EQzKP2uPkzenKOAHyEIbA==} + engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} + hasBin: true + peerDependencies: + '@edge-runtime/vm': '*' + '@types/debug': ^4.1.12 + '@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0 + '@vitest/browser': 3.0.8 + '@vitest/ui': 3.0.8 + happy-dom: '*' + jsdom: '*' + peerDependenciesMeta: + '@edge-runtime/vm': + optional: true + '@types/debug': + optional: true + '@types/node': + optional: true + '@vitest/browser': + optional: true + '@vitest/ui': + optional: true + happy-dom: + optional: true + jsdom: + optional: true + + w3c-xmlserializer@5.0.0: + resolution: {integrity: sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==} + engines: {node: '>=18'} + + webidl-conversions@7.0.0: + resolution: {integrity: sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==} + engines: {node: '>=12'} + + whatwg-encoding@3.1.1: + resolution: {integrity: sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==} + engines: {node: '>=18'} + + whatwg-mimetype@4.0.0: + resolution: {integrity: sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==} + engines: {node: '>=18'} + + whatwg-url@14.1.1: + resolution: {integrity: sha512-mDGf9diDad/giZ/Sm9Xi2YcyzaFpbdLpJPr+E9fSkyQ7KpQD4SdFcugkRQYzhmfI4KeV4Qpnn2sKPdo+kmsgRQ==} + engines: {node: '>=18'} + which@2.0.2: resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} engines: {node: '>= 8'} hasBin: true + why-is-node-running@2.3.0: + resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==} + engines: {node: '>=8'} + hasBin: true + word-wrap@1.2.5: resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} engines: {node: '>=0.10.0'} @@ -1470,6 +1850,28 @@ packages: resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} engines: {node: '>=12'} + wrappy@1.0.2: + resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + + ws@8.18.1: + resolution: {integrity: sha512-RKW2aJZMXeMxVpnZ6bck+RswznaxmzdULiBr6KY7XkTnW8uvt0iT9H5DkHUChXrc+uurzwa0rVI16n/Xzjdz1w==} + engines: {node: '>=10.0.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: '>=5.0.2' + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + + xml-name-validator@5.0.0: + resolution: {integrity: sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==} + engines: {node: '>=18'} + + xmlchars@2.2.0: + resolution: {integrity: sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==} + yaml@2.7.0: resolution: {integrity: sha512-+hSoy/QHluxmC9kCIJyL/uyFmLmc+e5CFR5Wa+bpIhIj85LVb9ZH2nVnqrHoSvKogwODv0ClqZkmiSSaIH5LTA==} engines: {node: '>= 14'} @@ -1483,6 +1885,54 @@ snapshots: '@alloc/quick-lru@5.2.0': {} + '@ampproject/remapping@2.3.0': + dependencies: + '@jridgewell/gen-mapping': 0.3.8 + '@jridgewell/trace-mapping': 0.3.25 + + '@asamuzakjp/css-color@3.1.1': + dependencies: + '@csstools/css-calc': 2.1.2(@csstools/css-parser-algorithms@3.0.4(@csstools/css-tokenizer@3.0.3))(@csstools/css-tokenizer@3.0.3) + '@csstools/css-color-parser': 3.0.8(@csstools/css-parser-algorithms@3.0.4(@csstools/css-tokenizer@3.0.3))(@csstools/css-tokenizer@3.0.3) + '@csstools/css-parser-algorithms': 3.0.4(@csstools/css-tokenizer@3.0.3) + '@csstools/css-tokenizer': 3.0.3 + lru-cache: 10.4.3 + + '@babel/helper-string-parser@7.25.9': {} + + '@babel/helper-validator-identifier@7.25.9': {} + + '@babel/parser@7.26.9': + dependencies: + '@babel/types': 7.26.9 + + '@babel/types@7.26.9': + dependencies: + '@babel/helper-string-parser': 7.25.9 + '@babel/helper-validator-identifier': 7.25.9 + + '@bcoe/v8-coverage@0.2.3': {} + + '@csstools/color-helpers@5.0.2': {} + + '@csstools/css-calc@2.1.2(@csstools/css-parser-algorithms@3.0.4(@csstools/css-tokenizer@3.0.3))(@csstools/css-tokenizer@3.0.3)': + dependencies: + '@csstools/css-parser-algorithms': 3.0.4(@csstools/css-tokenizer@3.0.3) + '@csstools/css-tokenizer': 3.0.3 + + '@csstools/css-color-parser@3.0.8(@csstools/css-parser-algorithms@3.0.4(@csstools/css-tokenizer@3.0.3))(@csstools/css-tokenizer@3.0.3)': + dependencies: + '@csstools/color-helpers': 5.0.2 + '@csstools/css-calc': 2.1.2(@csstools/css-parser-algorithms@3.0.4(@csstools/css-tokenizer@3.0.3))(@csstools/css-tokenizer@3.0.3) + '@csstools/css-parser-algorithms': 3.0.4(@csstools/css-tokenizer@3.0.3) + '@csstools/css-tokenizer': 3.0.3 + + '@csstools/css-parser-algorithms@3.0.4(@csstools/css-tokenizer@3.0.3)': + dependencies: + '@csstools/css-tokenizer': 3.0.3 + + '@csstools/css-tokenizer@3.0.3': {} + '@esbuild/aix-ppc64@0.25.1': optional: true @@ -1696,6 +2146,8 @@ snapshots: wrap-ansi: 8.1.0 wrap-ansi-cjs: wrap-ansi@7.0.0 + '@istanbuljs/schema@0.1.3': {} + '@jridgewell/gen-mapping@0.3.8': dependencies: '@jridgewell/set-array': 1.2.1 @@ -1935,12 +2387,73 @@ snapshots: transitivePeerDependencies: - '@swc/helpers' + '@vitest/coverage-v8@1.6.1(vitest@3.0.8(jiti@1.21.7)(jsdom@24.1.3)(yaml@2.7.0))': + dependencies: + '@ampproject/remapping': 2.3.0 + '@bcoe/v8-coverage': 0.2.3 + debug: 4.4.0 + istanbul-lib-coverage: 3.2.2 + istanbul-lib-report: 3.0.1 + istanbul-lib-source-maps: 5.0.6 + istanbul-reports: 3.1.7 + magic-string: 0.30.17 + magicast: 0.3.5 + picocolors: 1.1.1 + std-env: 3.8.1 + strip-literal: 2.1.1 + test-exclude: 6.0.0 + vitest: 3.0.8(jiti@1.21.7)(jsdom@24.1.3)(yaml@2.7.0) + transitivePeerDependencies: + - supports-color + + '@vitest/expect@3.0.8': + dependencies: + '@vitest/spy': 3.0.8 + '@vitest/utils': 3.0.8 + chai: 5.2.0 + tinyrainbow: 2.0.0 + + '@vitest/mocker@3.0.8(vite@6.2.1(jiti@1.21.7)(yaml@2.7.0))': + dependencies: + '@vitest/spy': 3.0.8 + estree-walker: 3.0.3 + magic-string: 0.30.17 + optionalDependencies: + vite: 6.2.1(jiti@1.21.7)(yaml@2.7.0) + + '@vitest/pretty-format@3.0.8': + dependencies: + tinyrainbow: 2.0.0 + + '@vitest/runner@3.0.8': + dependencies: + '@vitest/utils': 3.0.8 + pathe: 2.0.3 + + '@vitest/snapshot@3.0.8': + dependencies: + '@vitest/pretty-format': 3.0.8 + magic-string: 0.30.17 + pathe: 2.0.3 + + '@vitest/spy@3.0.8': + dependencies: + tinyspy: 3.0.2 + + '@vitest/utils@3.0.8': + dependencies: + '@vitest/pretty-format': 3.0.8 + loupe: 3.1.3 + tinyrainbow: 2.0.0 + acorn-jsx@5.3.2(acorn@8.14.1): dependencies: acorn: 8.14.1 acorn@8.14.1: {} + agent-base@7.1.3: {} + ajv@6.12.6: dependencies: fast-deep-equal: 3.1.3 @@ -1969,6 +2482,8 @@ snapshots: argparse@2.0.1: {} + assertion-error@2.0.1: {} + asynckit@0.4.0: {} autoprefixer@10.4.21(postcss@8.5.3): @@ -2015,6 +2530,8 @@ snapshots: node-releases: 2.0.19 update-browserslist-db: 1.1.3(browserslist@4.24.4) + cac@6.7.14: {} + call-bind-apply-helpers@1.0.2: dependencies: es-errors: 1.3.0 @@ -2026,11 +2543,21 @@ snapshots: caniuse-lite@1.0.30001703: {} + chai@5.2.0: + dependencies: + assertion-error: 2.0.1 + check-error: 2.1.1 + deep-eql: 5.0.2 + loupe: 3.1.3 + pathval: 2.0.0 + chalk@4.1.2: dependencies: ansi-styles: 4.3.0 supports-color: 7.2.0 + check-error@2.1.1: {} + chokidar@3.6.0: dependencies: anymatch: 3.1.3 @@ -2069,12 +2596,26 @@ snapshots: cssesc@3.0.0: {} + cssstyle@4.3.0: + dependencies: + '@asamuzakjp/css-color': 3.1.1 + rrweb-cssom: 0.8.0 + csstype@3.1.3: {} + data-urls@5.0.0: + dependencies: + whatwg-mimetype: 4.0.0 + whatwg-url: 14.1.1 + debug@4.4.0: dependencies: ms: 2.1.3 + decimal.js@10.5.0: {} + + deep-eql@5.0.2: {} + deep-is@0.1.4: {} delayed-stream@1.0.0: {} @@ -2097,10 +2638,14 @@ snapshots: emoji-regex@9.2.2: {} + entities@4.5.0: {} + es-define-property@1.0.1: {} es-errors@1.3.0: {} + es-module-lexer@1.6.0: {} + es-object-atoms@1.1.1: dependencies: es-errors: 1.3.0 @@ -2261,8 +2806,14 @@ snapshots: estraverse@5.3.0: {} + estree-walker@3.0.3: + dependencies: + '@types/estree': 1.0.6 + esutils@2.0.3: {} + expect-type@1.2.0: {} + fast-deep-equal@3.1.3: {} fast-glob@3.3.3: @@ -2317,6 +2868,8 @@ snapshots: fraction.js@4.3.7: {} + fs.realpath@1.0.0: {} + fsevents@2.3.3: optional: true @@ -2357,6 +2910,15 @@ snapshots: package-json-from-dist: 1.0.1 path-scurry: 1.11.1 + glob@7.2.3: + dependencies: + fs.realpath: 1.0.0 + inflight: 1.0.6 + inherits: 2.0.4 + minimatch: 3.1.2 + once: 1.4.0 + path-is-absolute: 1.0.1 + globals@14.0.0: {} globals@15.15.0: {} @@ -2377,6 +2939,30 @@ snapshots: dependencies: function-bind: 1.1.2 + html-encoding-sniffer@4.0.0: + dependencies: + whatwg-encoding: 3.1.1 + + html-escaper@2.0.2: {} + + http-proxy-agent@7.0.2: + dependencies: + agent-base: 7.1.3 + debug: 4.4.0 + transitivePeerDependencies: + - supports-color + + https-proxy-agent@7.0.6: + dependencies: + agent-base: 7.1.3 + debug: 4.4.0 + transitivePeerDependencies: + - supports-color + + iconv-lite@0.6.3: + dependencies: + safer-buffer: 2.1.2 + ignore@5.3.2: {} import-fresh@3.3.1: @@ -2386,6 +2972,13 @@ snapshots: imurmurhash@0.1.4: {} + inflight@1.0.6: + dependencies: + once: 1.4.0 + wrappy: 1.0.2 + + inherits@2.0.4: {} + is-binary-path@2.1.0: dependencies: binary-extensions: 2.3.0 @@ -2404,8 +2997,31 @@ snapshots: is-number@7.0.0: {} + is-potential-custom-element-name@1.0.1: {} + isexe@2.0.0: {} + istanbul-lib-coverage@3.2.2: {} + + istanbul-lib-report@3.0.1: + dependencies: + istanbul-lib-coverage: 3.2.2 + make-dir: 4.0.0 + supports-color: 7.2.0 + + istanbul-lib-source-maps@5.0.6: + dependencies: + '@jridgewell/trace-mapping': 0.3.25 + debug: 4.4.0 + istanbul-lib-coverage: 3.2.2 + transitivePeerDependencies: + - supports-color + + istanbul-reports@3.1.7: + dependencies: + html-escaper: 2.0.2 + istanbul-lib-report: 3.0.1 + jackspeak@3.4.3: dependencies: '@isaacs/cliui': 8.0.2 @@ -2414,10 +3030,40 @@ snapshots: jiti@1.21.7: {} + js-tokens@9.0.1: {} + js-yaml@4.1.0: dependencies: argparse: 2.0.1 + jsdom@24.1.3: + dependencies: + cssstyle: 4.3.0 + data-urls: 5.0.0 + decimal.js: 10.5.0 + form-data: 4.0.2 + html-encoding-sniffer: 4.0.0 + http-proxy-agent: 7.0.2 + https-proxy-agent: 7.0.6 + is-potential-custom-element-name: 1.0.1 + nwsapi: 2.2.18 + parse5: 7.2.1 + rrweb-cssom: 0.7.1 + saxes: 6.0.0 + symbol-tree: 3.2.4 + tough-cookie: 4.1.4 + w3c-xmlserializer: 5.0.0 + webidl-conversions: 7.0.0 + whatwg-encoding: 3.1.1 + whatwg-mimetype: 4.0.0 + whatwg-url: 14.1.1 + ws: 8.18.1 + xml-name-validator: 5.0.0 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + json-buffer@3.0.1: {} json-schema-traverse@0.4.1: {} @@ -2443,8 +3089,24 @@ snapshots: lodash.merge@4.6.2: {} + loupe@3.1.3: {} + lru-cache@10.4.3: {} + magic-string@0.30.17: + dependencies: + '@jridgewell/sourcemap-codec': 1.5.0 + + magicast@0.3.5: + dependencies: + '@babel/parser': 7.26.9 + '@babel/types': 7.26.9 + source-map-js: 1.2.1 + + make-dir@4.0.0: + dependencies: + semver: 7.7.1 + math-intrinsics@1.1.0: {} merge2@1.4.1: {} @@ -2488,10 +3150,16 @@ snapshots: normalize-range@0.1.2: {} + nwsapi@2.2.18: {} + object-assign@4.1.1: {} object-hash@3.0.0: {} + once@1.4.0: + dependencies: + wrappy: 1.0.2 + optionator@0.9.4: dependencies: deep-is: 0.1.4 @@ -2515,8 +3183,14 @@ snapshots: dependencies: callsites: 3.1.0 + parse5@7.2.1: + dependencies: + entities: 4.5.0 + path-exists@4.0.0: {} + path-is-absolute@1.0.1: {} + path-key@3.1.1: {} path-parse@1.0.7: {} @@ -2526,6 +3200,10 @@ snapshots: lru-cache: 10.4.3 minipass: 7.1.2 + pathe@2.0.3: {} + + pathval@2.0.0: {} + picocolors@1.1.1: {} picomatch@2.3.1: {} @@ -2577,8 +3255,14 @@ snapshots: proxy-from-env@1.1.0: {} + psl@1.15.0: + dependencies: + punycode: 2.3.1 + punycode@2.3.1: {} + querystringify@2.2.0: {} + queue-microtask@1.2.3: {} react-dom@19.0.0(react@19.0.0): @@ -2612,6 +3296,8 @@ snapshots: dependencies: picomatch: 2.3.1 + requires-port@1.0.0: {} + resolve-from@4.0.0: {} resolve@1.22.10: @@ -2647,10 +3333,20 @@ snapshots: '@rollup/rollup-win32-x64-msvc': 4.35.0 fsevents: 2.3.3 + rrweb-cssom@0.7.1: {} + + rrweb-cssom@0.8.0: {} + run-parallel@1.2.0: dependencies: queue-microtask: 1.2.3 + safer-buffer@2.1.2: {} + + saxes@6.0.0: + dependencies: + xmlchars: 2.2.0 + scheduler@0.25.0: {} semver@7.7.1: {} @@ -2663,10 +3359,16 @@ snapshots: shebang-regex@3.0.0: {} + siginfo@2.0.0: {} + signal-exit@4.1.0: {} source-map-js@1.2.1: {} + stackback@0.0.2: {} + + std-env@3.8.1: {} + string-ts@2.2.1: {} string-width@4.2.3: @@ -2691,6 +3393,10 @@ snapshots: strip-json-comments@3.1.1: {} + strip-literal@2.1.1: + dependencies: + js-tokens: 9.0.1 + sucrase@3.35.0: dependencies: '@jridgewell/gen-mapping': 0.3.8 @@ -2707,6 +3413,8 @@ snapshots: supports-preserve-symlinks-flag@1.0.0: {} + symbol-tree@3.2.4: {} + tailwindcss@3.4.17: dependencies: '@alloc/quick-lru': 5.2.0 @@ -2734,6 +3442,12 @@ snapshots: transitivePeerDependencies: - ts-node + test-exclude@6.0.0: + dependencies: + '@istanbuljs/schema': 0.1.3 + glob: 7.2.3 + minimatch: 3.1.2 + thenify-all@1.6.0: dependencies: thenify: 3.3.1 @@ -2742,10 +3456,31 @@ snapshots: dependencies: any-promise: 1.3.0 + tinybench@2.9.0: {} + + tinyexec@0.3.2: {} + + tinypool@1.0.2: {} + + tinyrainbow@2.0.0: {} + + tinyspy@3.0.2: {} + to-regex-range@5.0.1: dependencies: is-number: 7.0.0 + tough-cookie@4.1.4: + dependencies: + psl: 1.15.0 + punycode: 2.3.1 + universalify: 0.2.0 + url-parse: 1.5.10 + + tr46@5.0.0: + dependencies: + punycode: 2.3.1 + ts-api-utils@2.0.1(typescript@5.7.3): dependencies: typescript: 5.7.3 @@ -2772,6 +3507,8 @@ snapshots: typescript@5.7.3: {} + universalify@0.2.0: {} + update-browserslist-db@1.1.3(browserslist@4.24.4): dependencies: browserslist: 4.24.4 @@ -2782,8 +3519,34 @@ snapshots: dependencies: punycode: 2.3.1 + url-parse@1.5.10: + dependencies: + querystringify: 2.2.0 + requires-port: 1.0.0 + util-deprecate@1.0.2: {} + vite-node@3.0.8(jiti@1.21.7)(yaml@2.7.0): + dependencies: + cac: 6.7.14 + debug: 4.4.0 + es-module-lexer: 1.6.0 + pathe: 2.0.3 + vite: 6.2.1(jiti@1.21.7)(yaml@2.7.0) + transitivePeerDependencies: + - '@types/node' + - jiti + - less + - lightningcss + - sass + - sass-embedded + - stylus + - sugarss + - supports-color + - terser + - tsx + - yaml + vite@6.2.1(jiti@1.21.7)(yaml@2.7.0): dependencies: esbuild: 0.25.1 @@ -2794,10 +3557,70 @@ snapshots: jiti: 1.21.7 yaml: 2.7.0 + vitest@3.0.8(jiti@1.21.7)(jsdom@24.1.3)(yaml@2.7.0): + dependencies: + '@vitest/expect': 3.0.8 + '@vitest/mocker': 3.0.8(vite@6.2.1(jiti@1.21.7)(yaml@2.7.0)) + '@vitest/pretty-format': 3.0.8 + '@vitest/runner': 3.0.8 + '@vitest/snapshot': 3.0.8 + '@vitest/spy': 3.0.8 + '@vitest/utils': 3.0.8 + chai: 5.2.0 + debug: 4.4.0 + expect-type: 1.2.0 + magic-string: 0.30.17 + pathe: 2.0.3 + std-env: 3.8.1 + tinybench: 2.9.0 + tinyexec: 0.3.2 + tinypool: 1.0.2 + tinyrainbow: 2.0.0 + vite: 6.2.1(jiti@1.21.7)(yaml@2.7.0) + vite-node: 3.0.8(jiti@1.21.7)(yaml@2.7.0) + why-is-node-running: 2.3.0 + optionalDependencies: + jsdom: 24.1.3 + transitivePeerDependencies: + - jiti + - less + - lightningcss + - msw + - sass + - sass-embedded + - stylus + - sugarss + - supports-color + - terser + - tsx + - yaml + + w3c-xmlserializer@5.0.0: + dependencies: + xml-name-validator: 5.0.0 + + webidl-conversions@7.0.0: {} + + whatwg-encoding@3.1.1: + dependencies: + iconv-lite: 0.6.3 + + whatwg-mimetype@4.0.0: {} + + whatwg-url@14.1.1: + dependencies: + tr46: 5.0.0 + webidl-conversions: 7.0.0 + which@2.0.2: dependencies: isexe: 2.0.0 + why-is-node-running@2.3.0: + dependencies: + siginfo: 2.0.0 + stackback: 0.0.2 + word-wrap@1.2.5: {} wrap-ansi@7.0.0: @@ -2812,6 +3635,14 @@ snapshots: string-width: 5.1.2 strip-ansi: 7.1.0 + wrappy@1.0.2: {} + + ws@8.18.1: {} + + xml-name-validator@5.0.0: {} + + xmlchars@2.2.0: {} + yaml@2.7.0: {} yocto-queue@0.1.0: {} diff --git a/src/api/__tests__/catApi.test.ts b/src/api/__tests__/catApi.test.ts new file mode 100644 index 00000000..0c42ace9 --- /dev/null +++ b/src/api/__tests__/catApi.test.ts @@ -0,0 +1,122 @@ +import { describe, it, expect, vi, afterEach } from 'vitest' +import axios from 'axios' +import { getRandomImages, getBreeds, getBreedImages } from '../catApi' +import { parseCatImages, parseBreeds } from '../parsers' + +vi.mock('axios') + +const mockedAxios = vi.mocked(axios, { deep: true }) +const mockedAxiosGet = mockedAxios.get + +describe('catApi', () => { + const mockData = [ + { + id: '1', + url: 'https://example.com/cat1.jpg', + breeds: [ + { + id: 'b1', + name: 'Breed 1', + description: 'Description 1', + }, + ], + }, + ] + + afterEach(() => { + vi.clearAllMocks() + }) + + describe('getRandomImages', () => { + it('should call the correct API endpoint', async () => { + mockedAxios.get.mockResolvedValue({ data: mockData }) + + await getRandomImages() + + expect(mockedAxiosGet).toHaveBeenCalledWith( + 'https://api.thecatapi.com/v1/images/search?limit=10', + ) + }) + + it('should return an array of cat images', async () => { + mockedAxios.get.mockResolvedValue({ data: mockData }) + + const images = await getRandomImages() + + expect(images).toEqual(parseCatImages(mockData)) + }) + + it('should handle errors', async () => { + mockedAxios.get.mockRejectedValue(new Error('Failed to fetch')) + + await expect(getRandomImages()).rejects.toThrow('Failed to fetch') + }) + }) + + describe('getBreeds', () => { + it('should call the correct API endpoint', async () => { + mockedAxios.get.mockResolvedValue({ + data: [ + { + id: 'b1', + name: 'Breed 1', + description: 'Description 1', + }, + ], + }) + + await getBreeds() + + expect(mockedAxiosGet).toHaveBeenCalledWith( + 'https://api.thecatapi.com/v1/breeds', + ) + }) + + it('should return an array of breeds', async () => { + const breedData = [ + { + id: 'b1', + name: 'Breed 1', + description: 'Description 1', + }, + ] + mockedAxios.get.mockResolvedValue({ data: breedData }) + + const breeds = await getBreeds() + + expect(breeds).toEqual(parseBreeds(breedData)) + }) + + it('should handle errors', async () => { + mockedAxios.get.mockRejectedValue(new Error('Failed to fetch')) + + await expect(getBreeds()).rejects.toThrow('Failed to fetch') + }) + }) + + describe('getBreedImages', () => { + it('should call the correct API endpoint', async () => { + mockedAxios.get.mockResolvedValue({ data: mockData }) + + await getBreedImages('b1') + + expect(mockedAxiosGet).toHaveBeenCalledWith( + 'https://api.thecatapi.com/v1/images/search?breed_ids=b1&limit=10', + ) + }) + + it('should return an array of cat images for a specific breed', async () => { + mockedAxios.get.mockResolvedValue({ data: mockData }) + + const images = await getBreedImages('b1') + + expect(images).toEqual(parseCatImages(mockData)) + }) + + it('should handle errors', async () => { + mockedAxios.get.mockRejectedValue(new Error('Failed to fetch')) + + await expect(getBreedImages('b1')).rejects.toThrow('Failed to fetch') + }) + }) +}) diff --git a/src/api/__tests__/parsers.test.ts b/src/api/__tests__/parsers.test.ts new file mode 100644 index 00000000..df4f7f56 --- /dev/null +++ b/src/api/__tests__/parsers.test.ts @@ -0,0 +1,71 @@ +import { describe, it, expect } from 'vitest' +import { parseCatImages, parseBreeds } from '../parsers' + +describe('parseCatImages', () => { + const catImageData = [ + { + id: '1', + url: 'https://example.com/cat1.jpg', + breeds: [ + { + id: 'b1', + name: 'Breed 1', + description: 'Description 1', + }, + ], + }, + ] + + it('should parse the catImageData of a valid cat', () => { + expect(parseCatImages(catImageData)).toEqual(catImageData) + }) + + it('should handle missing breeds property', () => { + const data = [ + { + id: '2', + url: 'https://example.com/cat2.jpg', + }, + ] + expect(parseCatImages(data)[0].breeds).toBeUndefined() + }) + + it('should throw an error if the data is not an array', () => { + expect(() => parseCatImages({})).toThrowError( + 'Invalid data: Expected an array for CatImages', + ) + }) + + it('should throw an error if the data is missing required properties', () => { + const data = [{ id: '1' }] + expect(() => parseCatImages(data)).toThrowError( + 'Invalid data: Expected an object with id, name and description for Breed', + ) + }) +}) + +describe('parseBreeds', () => { + const breedData = [ + { + id: 'b1', + name: 'Breed 1', + description: 'Description 1', + }, + ] + it('should parse the breedData of valid breeds', () => { + expect(parseBreeds(breedData)).toEqual(breedData) + }) + + it('should throw an error if the data is not an array', () => { + expect(() => parseBreeds({})).toThrowError( + 'Invalid data: Expected an array for Breeds', + ) + }) + + it('should throw an error if the data is missing required properties', () => { + const data = [{ id: 'b1' }] + expect(() => parseBreeds(data)).toThrowError( + 'Invalid data: Expected an object with id, name and description for Breed', + ) + }) +}) diff --git a/vite.config.ts b/vite.config.ts index 2328e170..8a5717dd 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -1,7 +1,15 @@ -import { defineConfig } from 'vite' +import { defineConfig } from 'vitest/config' import react from '@vitejs/plugin-react-swc' // https://vite.dev/config/ export default defineConfig({ plugins: [react()], + test: { + environment: 'jsdom', + globals: true, + // setupFiles: ['./src/setupTests.ts'], + coverage: { + reporter: ['text', 'json', 'html'], + }, + }, }) From cad04d1f50a23604d1c1bf0093c1f3ce4992d079 Mon Sep 17 00:00:00 2001 From: Marios Tsigkas Date: Tue, 11 Mar 2025 14:56:36 +0200 Subject: [PATCH 06/96] Add unit tests for cat API and parsers; implement mocking and error handling --- src/api/__mocks__/catApi.ts | 3 + src/setupTests.ts | 22 +++++++ tests/catApi.test.ts | 122 ++++++++++++++++++++++++++++++++++++ tests/parsers.test.ts | 100 +++++++++++++++++++++++++++++ 4 files changed, 247 insertions(+) create mode 100644 src/api/__mocks__/catApi.ts create mode 100644 src/setupTests.ts create mode 100644 tests/catApi.test.ts create mode 100644 tests/parsers.test.ts diff --git a/src/api/__mocks__/catApi.ts b/src/api/__mocks__/catApi.ts new file mode 100644 index 00000000..bb54d62b --- /dev/null +++ b/src/api/__mocks__/catApi.ts @@ -0,0 +1,3 @@ +import { vi } from 'vitest' + +export const getRandomImages = vi.fn().mockResolvedValue([]) diff --git a/src/setupTests.ts b/src/setupTests.ts new file mode 100644 index 00000000..650a7fc6 --- /dev/null +++ b/src/setupTests.ts @@ -0,0 +1,22 @@ +import '@testing-library/jest-dom' +import { cleanup } from '@testing-library/react' +import { afterEach, beforeAll, vi } from 'vitest' +console.log('setupTests') + + +// beforeAll(() => { +// vi.mock('../../api/catApi', () => ({ +// getRandomImages: vi.fn(() => []) +// })) +// vi.mock('../../hooks/useFavorites', () => ({ +// useFavorites: () => ({ +// addFavorite: vi.fn() +// }) +// })) +// }) + +// Ensure mocks are cleared after each test +afterEach(() => { + cleanup() + vi.clearAllMocks() +}) diff --git a/tests/catApi.test.ts b/tests/catApi.test.ts new file mode 100644 index 00000000..49be79a5 --- /dev/null +++ b/tests/catApi.test.ts @@ -0,0 +1,122 @@ +import { describe, it, expect, vi, afterEach } from 'vitest' +import axios from 'axios' +import { getRandomImages, getBreeds, getBreedImages } from '../src/api/catApi' +import { parseCatImages, parseBreeds } from '../src/api/parsers' + +vi.mock('axios') + +const mockedAxios = vi.mocked(axios, { deep: true }) +const mockedAxiosGet = mockedAxios.get; + +describe('catApi', () => { + const mockData = [ + { + id: '1', + url: 'https://example.com/cat1.jpg', + breeds: [ + { + id: 'b1', + name: 'Breed 1', + description: 'Description 1', + }, + ], + }, + ] + + afterEach(() => { + vi.clearAllMocks() + }) + + describe('getRandomImages', () => { + it('should call the correct API endpoint', async () => { + mockedAxios.get.mockResolvedValue({ data: mockData }) + + await getRandomImages() + + expect(mockedAxiosGet).toHaveBeenCalledWith( + 'https://api.thecatapi.com/v1/images/search?limit=10', + ) + }) + + it('should return an array of cat images', async () => { + mockedAxios.get.mockResolvedValue({ data: mockData }) + + const images = await getRandomImages() + + expect(images).toEqual(parseCatImages(mockData)) + }) + + it('should handle errors', async () => { + mockedAxios.get.mockRejectedValue(new Error('Failed to fetch')) + + await expect(getRandomImages()).rejects.toThrow('Failed to fetch') + }) + }) + + describe('getBreeds', () => { + it('should call the correct API endpoint', async () => { + mockedAxios.get.mockResolvedValue({ + data: [ + { + id: 'b1', + name: 'Breed 1', + description: 'Description 1', + }, + ], + }) + + await getBreeds() + + expect(mockedAxiosGet).toHaveBeenCalledWith( + 'https://api.thecatapi.com/v1/breeds', + ) + }) + + it('should return an array of breeds', async () => { + const breedData = [ + { + id: 'b1', + name: 'Breed 1', + description: 'Description 1', + }, + ] + mockedAxios.get.mockResolvedValue({ data: breedData }) + + const breeds = await getBreeds() + + expect(breeds).toEqual(parseBreeds(breedData)) + }) + + it('should handle errors', async () => { + mockedAxios.get.mockRejectedValue(new Error('Failed to fetch')) + + await expect(getBreeds()).rejects.toThrow('Failed to fetch') + }) + }) + + describe('getBreedImages', () => { + it('should call the correct API endpoint', async () => { + mockedAxios.get.mockResolvedValue({ data: mockData }) + + await getBreedImages('b1') + + expect(mockedAxiosGet).toHaveBeenCalledWith( + 'https://api.thecatapi.com/v1/images/search?breed_ids=b1&limit=10', + ) + }) + + it('should return an array of cat images for a specific breed', async () => { + mockedAxios.get.mockResolvedValue({ data: mockData }) + + const images = await getBreedImages('b1') + + expect(images).toEqual(parseCatImages(mockData)) + }) + + it('should handle errors', async () => { + mockedAxios.get.mockRejectedValue(new Error('Failed to fetch')) + + await expect(getBreedImages('b1')).rejects.toThrow('Failed to fetch') + }) + }) +}) diff --git a/tests/parsers.test.ts b/tests/parsers.test.ts new file mode 100644 index 00000000..f26f55ed --- /dev/null +++ b/tests/parsers.test.ts @@ -0,0 +1,100 @@ +import { describe, it, expect } from 'vitest' +import { parseCatImages, parseBreeds } from '../src/api/parsers' + +describe('parseCatImages', () => { + const catImageData = [ + { + id: '1', + url: 'https://example.com/cat1.jpg', + breeds: [ + { + id: 'b1', + name: 'Breed 1', + description: 'Description 1', + }, + ], + }, + ] + + it('should parse the id of a valid cat image', () => { + const expectedId = '1' + expect(parseCatImages(catImageData)[0].id).toEqual(expectedId) + }) + + it('should parse the url of a valid cat image', () => { + const expectedUrl = 'https://example.com/cat1.jpg' + expect(parseCatImages(catImageData)[0].url).toEqual(expectedUrl) + }) + + it('should parse the breeds of a valid cat image', () => { + const expectedBreeds = [ + { + id: 'b1', + name: 'Breed 1', + description: 'Description 1', + }, + ] + expect(parseCatImages(catImageData)[0].breeds).toEqual(expectedBreeds) + }) + + it('should handle missing breeds property', () => { + const data = [ + { + id: '2', + url: 'https://example.com/cat2.jpg', + }, + ] + expect(parseCatImages(data)[0].breeds).toBeUndefined() + }) + + it('should throw an error if the data is not an array', () => { + expect(() => parseCatImages({})).toThrowError( + 'Invalid data: Expected an array for CatImages', + ) + }) + + it('should throw an error if the data is missing required properties', () => { + const data = [{ id: '1' }] + expect(() => parseCatImages(data)).toThrowError( + 'Invalid data: Expected an object with id, name and description for Breed', + ) + }) +}) + +describe('parseBreeds', () => { + const breedData = [ + { + id: 'b1', + name: 'Breed 1', + description: 'Description 1', + }, + ] + + it('should parse the id of a valid breed', () => { + const expectedId = 'b1' + expect(parseBreeds(breedData)[0].id).toEqual(expectedId) + }) + + it('should parse the name of a valid breed', () => { + const expectedName = 'Breed 1' + expect(parseBreeds(breedData)[0].name).toEqual(expectedName) + }) + + it('should parse the description of a valid breed', () => { + const expectedDescription = 'Description 1' + expect(parseBreeds(breedData)[0].description).toEqual(expectedDescription) + }) + + it('should throw an error if the data is not an array', () => { + expect(() => parseBreeds({})).toThrowError( + 'Invalid data: Expected an array for Breeds', + ) + }) + + it('should throw an error if the data is missing required properties', () => { + const data = [{ id: 'b1' }] + expect(() => parseBreeds(data)).toThrowError( + 'Invalid data: Expected an object with id, name and description for Breed', + ) + }) +}) From d2073622c0c6c46dcfe870011ba4933677cd5337 Mon Sep 17 00:00:00 2001 From: Marios Tsigkas Date: Tue, 11 Mar 2025 15:19:16 +0200 Subject: [PATCH 07/96] Add favorites functionality and image viewing; implement hooks for fetching and managing favorites, create modal for image display, and update routing --- package.json | 2 + pnpm-lock.yaml | 196 ++++++++++++++++++++++++++++++ src/App.tsx | 36 ++---- src/__mocks__/useFavorites.ts | 9 ++ src/components/Modal.tsx | 32 +++++ src/hooks/useFavorites.ts | 21 ++++ src/hooks/useFetchedImages.ts | 36 ++++++ src/views/Home.tsx | 48 ++++++++ src/views/ImageView.tsx | 52 ++++++++ src/views/__tests__/Home.test.tsx | 24 ++++ vite.config.ts | 2 +- 11 files changed, 430 insertions(+), 28 deletions(-) create mode 100644 src/__mocks__/useFavorites.ts create mode 100644 src/components/Modal.tsx create mode 100644 src/hooks/useFavorites.ts create mode 100644 src/hooks/useFetchedImages.ts create mode 100644 src/views/Home.tsx create mode 100644 src/views/ImageView.tsx create mode 100644 src/views/__tests__/Home.test.tsx diff --git a/package.json b/package.json index 9fdb9d85..d3faf74b 100644 --- a/package.json +++ b/package.json @@ -19,6 +19,8 @@ }, "devDependencies": { "@eslint/js": "^9.21.0", + "@testing-library/jest-dom": "^6.6.3", + "@testing-library/react": "^16.2.0", "@types/react": "^19.0.10", "@types/react-dom": "^19.0.4", "@vitejs/plugin-react-swc": "^3.8.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 70f50762..081cd03b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -24,6 +24,12 @@ importers: '@eslint/js': specifier: ^9.21.0 version: 9.22.0 + '@testing-library/jest-dom': + specifier: ^6.6.3 + version: 6.6.3 + '@testing-library/react': + specifier: ^16.2.0 + version: 16.2.0(@testing-library/dom@10.4.0)(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) '@types/react': specifier: ^19.0.10 version: 19.0.10 @@ -81,6 +87,9 @@ importers: packages: + '@adobe/css-tools@4.4.2': + resolution: {integrity: sha512-baYZExFpsdkBNuvGKTKWCwKH57HRZLVtycZS05WTQNVOiXVSeAki3nU35zlRbToeMW8aHlJfyS+1C4BOv27q0A==} + '@alloc/quick-lru@5.2.0': resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==} engines: {node: '>=10'} @@ -92,6 +101,10 @@ packages: '@asamuzakjp/css-color@3.1.1': resolution: {integrity: sha512-hpRD68SV2OMcZCsrbdkccTw5FXjNDLo5OuqSHyHZfwweGsDWZwDJ2+gONyNAbazZclobMirACLw0lk8WVxIqxA==} + '@babel/code-frame@7.26.2': + resolution: {integrity: sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==} + engines: {node: '>=6.9.0'} + '@babel/helper-string-parser@7.25.9': resolution: {integrity: sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==} engines: {node: '>=6.9.0'} @@ -105,6 +118,10 @@ packages: engines: {node: '>=6.0.0'} hasBin: true + '@babel/runtime@7.26.9': + resolution: {integrity: sha512-aA63XwOkcl4xxQa3HjPMqOP6LiK0ZDv3mUPYEFXkpHbaFjtGggE1A61FjFzJnB+p7/oy2gA8E+rcBNl/zC1tMg==} + engines: {node: '>=6.9.0'} + '@babel/types@7.26.9': resolution: {integrity: sha512-Y3IR1cRnOxOCDvMmNiym7XpXQ93iGDDPHx+Zj+NM+rg0fBaShfQLkg+hKPaZCEvg5N/LeCo4+Rj/i3FuJsIQaw==} engines: {node: '>=6.9.0'} @@ -584,6 +601,32 @@ packages: '@swc/types@0.1.19': resolution: {integrity: sha512-WkAZaAfj44kh/UFdAQcrMP1I0nwRqpt27u+08LMBYMqmQfwwMofYoMh/48NGkMMRfC4ynpfwRbJuu8ErfNloeA==} + '@testing-library/dom@10.4.0': + resolution: {integrity: sha512-pemlzrSESWbdAloYml3bAJMEfNh1Z7EduzqPKprCH5S341frlpYnUEW0H72dLxa6IsYr+mPno20GiSm+h9dEdQ==} + engines: {node: '>=18'} + + '@testing-library/jest-dom@6.6.3': + resolution: {integrity: sha512-IteBhl4XqYNkM54f4ejhLRJiZNqcSCoXUOG2CPK7qbD322KjQozM4kHQOfkG2oln9b9HTYqs+Sae8vBATubxxA==} + engines: {node: '>=14', npm: '>=6', yarn: '>=1'} + + '@testing-library/react@16.2.0': + resolution: {integrity: sha512-2cSskAvA1QNtKc8Y9VJQRv0tm3hLVgxRGDB+KYhIaPQJ1I+RHbhIXcM+zClKXzMes/wshsMVzf4B9vS4IZpqDQ==} + engines: {node: '>=18'} + peerDependencies: + '@testing-library/dom': ^10.0.0 + '@types/react': ^18.0.0 || ^19.0.0 + '@types/react-dom': ^18.0.0 || ^19.0.0 + react: ^18.0.0 || ^19.0.0 + react-dom: ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@types/aria-query@5.0.4': + resolution: {integrity: sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==} + '@types/cookie@0.6.0': resolution: {integrity: sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==} @@ -716,6 +759,10 @@ packages: resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} engines: {node: '>=8'} + ansi-styles@5.2.0: + resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==} + engines: {node: '>=10'} + ansi-styles@6.2.1: resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==} engines: {node: '>=12'} @@ -733,6 +780,9 @@ packages: argparse@2.0.1: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + aria-query@5.3.0: + resolution: {integrity: sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==} + assertion-error@2.0.1: resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} engines: {node: '>=12'} @@ -798,6 +848,10 @@ packages: resolution: {integrity: sha512-mCuXncKXk5iCLhfhwTc0izo0gtEmpz5CtG2y8GiOINBlMVS6v8TMRc5TaLWKS6692m9+dVVfzgeVxR5UxWHTYw==} engines: {node: '>=12'} + chalk@3.0.0: + resolution: {integrity: sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==} + engines: {node: '>=8'} + chalk@4.1.2: resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} engines: {node: '>=10'} @@ -839,6 +893,9 @@ packages: resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} engines: {node: '>= 8'} + css.escape@1.5.1: + resolution: {integrity: sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==} + cssesc@3.0.0: resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} engines: {node: '>=4'} @@ -878,12 +935,22 @@ packages: resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} engines: {node: '>=0.4.0'} + dequal@2.0.3: + resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} + engines: {node: '>=6'} + didyoumean@1.2.2: resolution: {integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==} dlv@1.1.3: resolution: {integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==} + dom-accessibility-api@0.5.16: + resolution: {integrity: sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==} + + dom-accessibility-api@0.6.3: + resolution: {integrity: sha512-7ZgogeTnjuHbo+ct10G9Ffp0mif17idi0IyWNVA/wcwcm7NPOD/WEHVP3n7n3MhXqxoIYm8d6MuZohYWIZ4T3w==} + dunder-proto@1.0.1: resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} engines: {node: '>= 0.4'} @@ -1171,6 +1238,10 @@ packages: resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} engines: {node: '>=0.8.19'} + indent-string@4.0.0: + resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==} + engines: {node: '>=8'} + inflight@1.0.6: resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful. @@ -1231,6 +1302,9 @@ packages: resolution: {integrity: sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==} hasBin: true + js-tokens@4.0.0: + resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + js-tokens@9.0.1: resolution: {integrity: sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==} @@ -1277,12 +1351,19 @@ packages: lodash.merge@4.6.2: resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} + lodash@4.17.21: + resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} + loupe@3.1.3: resolution: {integrity: sha512-kkIp7XSkP78ZxJEsSxW3712C6teJVoeHHwgo9zJ380de7IYyJ2ISlxojcH2pC5OFLewESmnRi/+XCDIEEVyoug==} lru-cache@10.4.3: resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} + lz-string@1.5.0: + resolution: {integrity: sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==} + hasBin: true + magic-string@0.30.17: resolution: {integrity: sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==} @@ -1313,6 +1394,10 @@ packages: resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} engines: {node: '>= 0.6'} + min-indent@1.0.1: + resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==} + engines: {node: '>=4'} + minimatch@3.1.2: resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} @@ -1475,6 +1560,10 @@ packages: resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} engines: {node: '>= 0.8.0'} + pretty-format@27.5.1: + resolution: {integrity: sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==} + engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + proxy-from-env@1.1.0: resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} @@ -1496,6 +1585,9 @@ packages: peerDependencies: react: ^19.0.0 + react-is@17.0.2: + resolution: {integrity: sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==} + react-router-dom@7.3.0: resolution: {integrity: sha512-z7Q5FTiHGgQfEurX/FBinkOXhWREJIAB2RiU24lvcBa82PxUpwqvs/PAXb9lJyPjTs2jrl6UkLvCZVGJPeNuuQ==} engines: {node: '>=20.0.0'} @@ -1524,6 +1616,13 @@ packages: resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} engines: {node: '>=8.10.0'} + redent@3.0.0: + resolution: {integrity: sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==} + engines: {node: '>=8'} + + regenerator-runtime@0.14.1: + resolution: {integrity: sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==} + requires-port@1.0.0: resolution: {integrity: sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==} @@ -1616,6 +1715,10 @@ packages: resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==} engines: {node: '>=12'} + strip-indent@3.0.0: + resolution: {integrity: sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==} + engines: {node: '>=8'} + strip-json-comments@3.1.1: resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} engines: {node: '>=8'} @@ -1883,6 +1986,8 @@ packages: snapshots: + '@adobe/css-tools@4.4.2': {} + '@alloc/quick-lru@5.2.0': {} '@ampproject/remapping@2.3.0': @@ -1898,6 +2003,12 @@ snapshots: '@csstools/css-tokenizer': 3.0.3 lru-cache: 10.4.3 + '@babel/code-frame@7.26.2': + dependencies: + '@babel/helper-validator-identifier': 7.25.9 + js-tokens: 4.0.0 + picocolors: 1.1.1 + '@babel/helper-string-parser@7.25.9': {} '@babel/helper-validator-identifier@7.25.9': {} @@ -1906,6 +2017,10 @@ snapshots: dependencies: '@babel/types': 7.26.9 + '@babel/runtime@7.26.9': + dependencies: + regenerator-runtime: 0.14.1 + '@babel/types@7.26.9': dependencies: '@babel/helper-string-parser': 7.25.9 @@ -2289,6 +2404,39 @@ snapshots: dependencies: '@swc/counter': 0.1.3 + '@testing-library/dom@10.4.0': + dependencies: + '@babel/code-frame': 7.26.2 + '@babel/runtime': 7.26.9 + '@types/aria-query': 5.0.4 + aria-query: 5.3.0 + chalk: 4.1.2 + dom-accessibility-api: 0.5.16 + lz-string: 1.5.0 + pretty-format: 27.5.1 + + '@testing-library/jest-dom@6.6.3': + dependencies: + '@adobe/css-tools': 4.4.2 + aria-query: 5.3.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@16.2.0(@testing-library/dom@10.4.0)(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + dependencies: + '@babel/runtime': 7.26.9 + '@testing-library/dom': 10.4.0 + react: 19.0.0 + react-dom: 19.0.0(react@19.0.0) + optionalDependencies: + '@types/react': 19.0.10 + '@types/react-dom': 19.0.4(@types/react@19.0.10) + + '@types/aria-query@5.0.4': {} + '@types/cookie@0.6.0': {} '@types/estree@1.0.6': {} @@ -2469,6 +2617,8 @@ snapshots: dependencies: color-convert: 2.0.1 + ansi-styles@5.2.0: {} + ansi-styles@6.2.1: {} any-promise@1.3.0: {} @@ -2482,6 +2632,10 @@ snapshots: argparse@2.0.1: {} + aria-query@5.3.0: + dependencies: + dequal: 2.0.3 + assertion-error@2.0.1: {} asynckit@0.4.0: {} @@ -2551,6 +2705,11 @@ snapshots: loupe: 3.1.3 pathval: 2.0.0 + chalk@3.0.0: + dependencies: + ansi-styles: 4.3.0 + supports-color: 7.2.0 + chalk@4.1.2: dependencies: ansi-styles: 4.3.0 @@ -2594,6 +2753,8 @@ snapshots: shebang-command: 2.0.0 which: 2.0.2 + css.escape@1.5.1: {} + cssesc@3.0.0: {} cssstyle@4.3.0: @@ -2620,10 +2781,16 @@ snapshots: delayed-stream@1.0.0: {} + dequal@2.0.3: {} + didyoumean@1.2.2: {} dlv@1.1.3: {} + dom-accessibility-api@0.5.16: {} + + dom-accessibility-api@0.6.3: {} + dunder-proto@1.0.1: dependencies: call-bind-apply-helpers: 1.0.2 @@ -2972,6 +3139,8 @@ snapshots: imurmurhash@0.1.4: {} + indent-string@4.0.0: {} + inflight@1.0.6: dependencies: once: 1.4.0 @@ -3030,6 +3199,8 @@ snapshots: jiti@1.21.7: {} + js-tokens@4.0.0: {} + js-tokens@9.0.1: {} js-yaml@4.1.0: @@ -3089,10 +3260,14 @@ snapshots: lodash.merge@4.6.2: {} + lodash@4.17.21: {} + loupe@3.1.3: {} lru-cache@10.4.3: {} + lz-string@1.5.0: {} + magic-string@0.30.17: dependencies: '@jridgewell/sourcemap-codec': 1.5.0 @@ -3122,6 +3297,8 @@ snapshots: dependencies: mime-db: 1.52.0 + min-indent@1.0.1: {} + minimatch@3.1.2: dependencies: brace-expansion: 1.1.11 @@ -3253,6 +3430,12 @@ snapshots: prelude-ls@1.2.1: {} + pretty-format@27.5.1: + dependencies: + ansi-regex: 5.0.1 + ansi-styles: 5.2.0 + react-is: 17.0.2 + proxy-from-env@1.1.0: {} psl@1.15.0: @@ -3270,6 +3453,8 @@ snapshots: react: 19.0.0 scheduler: 0.25.0 + react-is@17.0.2: {} + react-router-dom@7.3.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0): dependencies: react: 19.0.0 @@ -3296,6 +3481,13 @@ snapshots: dependencies: picomatch: 2.3.1 + redent@3.0.0: + dependencies: + indent-string: 4.0.0 + strip-indent: 3.0.0 + + regenerator-runtime@0.14.1: {} + requires-port@1.0.0: {} resolve-from@4.0.0: {} @@ -3391,6 +3583,10 @@ snapshots: dependencies: ansi-regex: 6.1.0 + strip-indent@3.0.0: + dependencies: + min-indent: 1.0.1 + strip-json-comments@3.1.1: {} strip-literal@2.1.1: diff --git a/src/App.tsx b/src/App.tsx index d6045e8d..9234128c 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,34 +1,16 @@ -import { useState } from 'react' -import reactLogo from './assets/react.svg' -import viteLogo from '/vite.svg' +import { Routes, Route } from 'react-router-dom' +import Home from './views/Home' +import ImageView from './views/ImageView' // added ImageView import import './App.css' function App() { - const [count, setCount] = useState(0) - return ( - <> -

- - Vite logo - - - React logo - -
-

Vite + React

-
- -

- Edit src/App.tsx and save to test HMR -

-
-

- Click on the Vite and React logos to learn more -

- +
+ + } /> + } /> // updated route with parameter + +
) } diff --git a/src/__mocks__/useFavorites.ts b/src/__mocks__/useFavorites.ts new file mode 100644 index 00000000..dc700cad --- /dev/null +++ b/src/__mocks__/useFavorites.ts @@ -0,0 +1,9 @@ +import { vi } from 'vitest' + +export const useFavorites = () => ({ + favorites: [], + addFavorite: vi.fn(), + removeFavorite: vi.fn(), + isLoading: false, + error: null +}) diff --git a/src/components/Modal.tsx b/src/components/Modal.tsx new file mode 100644 index 00000000..e241356e --- /dev/null +++ b/src/components/Modal.tsx @@ -0,0 +1,32 @@ +import React from 'react' + +interface ModalProps { + children: React.ReactNode + onClose: () => void +} + +function Modal({ children, onClose }: ModalProps): JSX.Element { + return ( +
+
{ e.stopPropagation(); }} + > + + {children} +
+
+ ) +} + +export default Modal diff --git a/src/hooks/useFavorites.ts b/src/hooks/useFavorites.ts new file mode 100644 index 00000000..8507d969 --- /dev/null +++ b/src/hooks/useFavorites.ts @@ -0,0 +1,21 @@ +import { useState, useEffect } from 'react' +import { parseCatImages } from '../api/parsers' +import { CatImage } from '../api/types' + +export function useFavorites() { + const [favorites, setFavorites] = useState([]) + + useEffect(() => { + const favs: unknown = JSON.parse(localStorage.getItem('favorites') ?? '[]') + const favsParsed = parseCatImages(favs) + setFavorites(favsParsed) + }, []) + + const addFavorite = (img: CatImage) => { + const updatedFavorites = [...favorites, img] + setFavorites(updatedFavorites) + localStorage.setItem('favorites', JSON.stringify(updatedFavorites)) + } + + return { favorites, addFavorite } +} diff --git a/src/hooks/useFetchedImages.ts b/src/hooks/useFetchedImages.ts new file mode 100644 index 00000000..44abc050 --- /dev/null +++ b/src/hooks/useFetchedImages.ts @@ -0,0 +1,36 @@ +import { useState, useCallback, useEffect } from 'react' +import { getRandomImages } from '../api/catApi' +import { CatImage } from '../api/types' +import { parseCatImages } from '../api/parsers' + +const useFetchedImages = () => { + const [images, setImages] = useState(() => { + const stored = localStorage.getItem('fetchedImages') + return stored ? parseCatImages(JSON.parse(stored)) : [] + }) + const [isLoading, setIsLoading] = useState(false) + const [error, setError] = useState(null) + + const fetchImages = useCallback(async () => { + if (isLoading) return + setIsLoading(true) + setError(null) + try { + const data = await getRandomImages(10) + setImages(data) + } catch (err) { + console.error(err) + setError('Failed to fetch images') + } finally { + setIsLoading(false) + } + }, [isLoading]) + + useEffect(() => { + localStorage.setItem('fetchedImages', JSON.stringify(images)) + }, [images]) + + return [images, fetchImages, isLoading, error] as const +} + +export default useFetchedImages diff --git a/src/views/Home.tsx b/src/views/Home.tsx new file mode 100644 index 00000000..89dc4afb --- /dev/null +++ b/src/views/Home.tsx @@ -0,0 +1,48 @@ +import { JSX, useEffect } from 'react' +import { useNavigate } from 'react-router-dom' +import { CatImage } from '../api/types' +import useFetchedImages from '../hooks/useFetchedImages' + +function Home(): JSX.Element { + const [images, fetchImages, isLoading, error] = useFetchedImages() + const navigate = useNavigate() + + useEffect(() => { + if (isLoading) return + void fetchImages() + }, []) + + const openModal = (img: CatImage) => { + return navigate(`/image/${img.id}`) + } + + return ( +
+

Random Cats

+ {isLoading &&

Loading...

} + {error &&

{error}

} + {!isLoading &&
+
+ {images?.map(img => ( + cat { void openModal(img) }} + /> + ))} +
+ +
} +
+ ) +} + +export default Home diff --git a/src/views/ImageView.tsx b/src/views/ImageView.tsx new file mode 100644 index 00000000..71bfd696 --- /dev/null +++ b/src/views/ImageView.tsx @@ -0,0 +1,52 @@ +import { useState, useEffect, JSX } from 'react' +import { useNavigate, useParams } from 'react-router-dom' +import Modal from '../components/Modal' +import { CatImage } from '../api/types' +import { useFavorites } from '../hooks/useFavorites' +import useFetchedImages from '../hooks/useFetchedImages' + +function ImageView(): JSX.Element { + const [selectedImage, setSelectedImage] = useState(null) + const [images] = useFetchedImages() + const navigate = useNavigate() + const { imageId } = useParams() // use route parameter + const { addFavorite } = useFavorites() + + useEffect(() => { + if (imageId && images.length > 0) { + const img = images.find(i => i.id === imageId) + if (img) { + setSelectedImage(img) + } + } + }, [imageId, images]) + + const closeModal = () => { + void navigate('/') + } + + const markAsFavourite = (img: CatImage) => { + addFavorite(img) + } + + if (!selectedImage) return
Loading...
+ + return ( + + cat + {selectedImage.breeds && selectedImage.breeds.length > 0 ? ( + <> +

{selectedImage.breeds[0].name}

+

{selectedImage.breeds[0].description}

+ + ) : ( +

No breed info available

+ )} + +
+ ) +} + +export default ImageView diff --git a/src/views/__tests__/Home.test.tsx b/src/views/__tests__/Home.test.tsx new file mode 100644 index 00000000..b3728f8f --- /dev/null +++ b/src/views/__tests__/Home.test.tsx @@ -0,0 +1,24 @@ +import { act, render } from '@testing-library/react' +import { BrowserRouter } from 'react-router-dom' +import { describe, expect, it, vi } from 'vitest' +import Home from '../Home' +import * as catApi from '../../api/catApi' + + +describe('Home', () => { + it('should call getRandomImages once on mount', () => { + const mockGetRandomImages = vi.spyOn(catApi, 'getRandomImages') + mockGetRandomImages.mockResolvedValue([]) + + act(() => { + render( + + + + ) + }) + + expect(mockGetRandomImages).toHaveBeenCalledTimes(1) + expect(mockGetRandomImages).toHaveBeenCalledWith(10) + }) +}) diff --git a/vite.config.ts b/vite.config.ts index 8a5717dd..636fe36c 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -7,7 +7,7 @@ export default defineConfig({ test: { environment: 'jsdom', globals: true, - // setupFiles: ['./src/setupTests.ts'], + setupFiles: ['./src/setupTests.ts'], coverage: { reporter: ['text', 'json', 'html'], }, From a0fd274573a3ac7e0ca7dd5caadf203d45f556f2 Mon Sep 17 00:00:00 2001 From: Marios Tsigkas Date: Tue, 11 Mar 2025 15:34:42 +0200 Subject: [PATCH 08/96] Add favorites view and functionality; implement navigation links, remove favorite feature, and update image fetching hook return structure --- src/App.tsx | 14 ++++++++++++-- src/hooks/useFavorites.ts | 8 +++++++- src/hooks/useFetchedImages.ts | 4 ++-- src/views/Favorites.tsx | 31 +++++++++++++++++++++++++++++++ src/views/Home.tsx | 6 +++--- 5 files changed, 55 insertions(+), 8 deletions(-) create mode 100644 src/views/Favorites.tsx diff --git a/src/App.tsx b/src/App.tsx index 9234128c..4943386a 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,14 +1,24 @@ -import { Routes, Route } from 'react-router-dom' +import { Routes, Route, Link } from 'react-router-dom' import Home from './views/Home' import ImageView from './views/ImageView' // added ImageView import import './App.css' +import Favorites from './views/Favorites' function App() { return (
+ + } /> - } /> // updated route with parameter + } /> + } />
) diff --git a/src/hooks/useFavorites.ts b/src/hooks/useFavorites.ts index 8507d969..75ddb1f2 100644 --- a/src/hooks/useFavorites.ts +++ b/src/hooks/useFavorites.ts @@ -17,5 +17,11 @@ export function useFavorites() { localStorage.setItem('favorites', JSON.stringify(updatedFavorites)) } - return { favorites, addFavorite } + const removeFavorite = (id: string) => { + const newFavorites = favorites.filter(fav => fav.id !== id) + setFavorites(newFavorites) + localStorage.setItem('favorites', JSON.stringify(newFavorites)) + } + + return { favorites, addFavorite, removeFavorite } } diff --git a/src/hooks/useFetchedImages.ts b/src/hooks/useFetchedImages.ts index 44abc050..af1cbab9 100644 --- a/src/hooks/useFetchedImages.ts +++ b/src/hooks/useFetchedImages.ts @@ -4,7 +4,7 @@ import { CatImage } from '../api/types' import { parseCatImages } from '../api/parsers' const useFetchedImages = () => { - const [images, setImages] = useState(() => { + const [images, setImages] = useState(() => { const stored = localStorage.getItem('fetchedImages') return stored ? parseCatImages(JSON.parse(stored)) : [] }) @@ -30,7 +30,7 @@ const useFetchedImages = () => { localStorage.setItem('fetchedImages', JSON.stringify(images)) }, [images]) - return [images, fetchImages, isLoading, error] as const + return { images, fetchImages, isLoading, error } } export default useFetchedImages diff --git a/src/views/Favorites.tsx b/src/views/Favorites.tsx new file mode 100644 index 00000000..f5bbe9ac --- /dev/null +++ b/src/views/Favorites.tsx @@ -0,0 +1,31 @@ +import { JSX } from 'react' +import { useFavorites } from '../hooks/useFavorites' + +function Favorites(): JSX.Element { + const { favorites, removeFavorite } = useFavorites() + + return ( +
+

Favourite Cats

+
+ {favorites.length ? ( + favorites.map(fav => ( +
+ cat + +
+ )) + ) : ( +

No favourites yet.

+ )} +
+
+ ) +} + +export default Favorites diff --git a/src/views/Home.tsx b/src/views/Home.tsx index 89dc4afb..8d15d0fa 100644 --- a/src/views/Home.tsx +++ b/src/views/Home.tsx @@ -4,7 +4,7 @@ import { CatImage } from '../api/types' import useFetchedImages from '../hooks/useFetchedImages' function Home(): JSX.Element { - const [images, fetchImages, isLoading, error] = useFetchedImages() + const { images, fetchImages, isLoading, error } = useFetchedImages() const navigate = useNavigate() useEffect(() => { @@ -21,9 +21,9 @@ function Home(): JSX.Element {

Random Cats

{isLoading &&

Loading...

} {error &&

{error}

} - {!isLoading &&
+ {!isLoading && images.length &&
- {images?.map(img => ( + {images.map(img => ( Date: Tue, 11 Mar 2025 17:00:02 +0200 Subject: [PATCH 09/96] Add breeds functionality; implement breeds view, breed detail view, and image gallery component --- src/App.tsx | 14 ++++++- src/api/parsers.ts | 44 ++++++++++++---------- src/components/ImageGallery.tsx | 25 +++++++++++++ src/components/Modal.tsx | 15 ++------ src/views/BreedDetail.tsx | 65 +++++++++++++++++++++++++++++++++ src/views/Breeds.tsx | 43 ++++++++++++++++++++++ src/views/Home.tsx | 20 +--------- src/views/ImageView.tsx | 2 +- 8 files changed, 177 insertions(+), 51 deletions(-) create mode 100644 src/components/ImageGallery.tsx create mode 100644 src/views/BreedDetail.tsx create mode 100644 src/views/Breeds.tsx diff --git a/src/App.tsx b/src/App.tsx index 4943386a..16421211 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -3,21 +3,31 @@ import Home from './views/Home' import ImageView from './views/ImageView' // added ImageView import import './App.css' import Favorites from './views/Favorites' +import Breeds from './views/Breeds' +import BreedDetail from './views/BreedDetail' function App() { return (
} /> } /> + } /> + } /> } />
diff --git a/src/api/parsers.ts b/src/api/parsers.ts index a3d974c4..522360b4 100644 --- a/src/api/parsers.ts +++ b/src/api/parsers.ts @@ -2,7 +2,7 @@ import { CatImage, Breed } from './types' export const parseCatImages = (data: unknown): CatImage[] => { if (!Array.isArray(data)) { - throw new Error("Invalid data: Expected an array for CatImages") + return [] } return data.map((item: unknown) => { if (typeof item !== 'object' || item === null || !('id' in item) || !('url' in item)) { @@ -15,26 +15,32 @@ export const parseCatImages = (data: unknown): CatImage[] => { } }) } +export const parseBreed = (item: unknown): Breed => { + if ( + typeof item !== 'object' || + item === null || + !('id' in item) || + !('name' in item) || + !('description' in item) + ) { + throw new Error("Invalid data: Expected an object with id, name and description for Breed") + } + + return { + id: String(item.id), + name: String(item.name), + description: String(item.description), + } +} + + export const parseBreeds = (data: unknown): Breed[] => { if (!Array.isArray(data)) { - throw new Error("Invalid data: Expected an array for Breeds") + return [] } - return data.map((item: unknown) => { - if ( - typeof item !== 'object' || - item === null || - !('id' in item) || - !('name' in item) || - !('description' in item) - ) { - throw new Error("Invalid data: Expected an object with id, name and description for Breed") - } - - return { - id: String(item.id), - name: String(item.name), - description: String(item.description), - } - }) + return data.map((item: unknown) => + parseBreed(item) +) } + diff --git a/src/components/ImageGallery.tsx b/src/components/ImageGallery.tsx new file mode 100644 index 00000000..e4fa5b46 --- /dev/null +++ b/src/components/ImageGallery.tsx @@ -0,0 +1,25 @@ +import { JSX } from 'react' +import { CatImage } from '../api/types' +import { Link } from 'react-router-dom' + +interface ImageGalleryProps { + images: CatImage[] +} + +const ImageGallery = ({ images }: ImageGalleryProps): JSX.Element => { + return ( +
+ {images.map(img => ( + + cat + + ))} +
+ ) +} + +export default ImageGallery diff --git a/src/components/Modal.tsx b/src/components/Modal.tsx index e241356e..f3ca2790 100644 --- a/src/components/Modal.tsx +++ b/src/components/Modal.tsx @@ -1,4 +1,4 @@ -import React from 'react' +import { JSX } from 'react' interface ModalProps { children: React.ReactNode @@ -8,21 +8,14 @@ interface ModalProps { function Modal({ children, onClose }: ModalProps): JSX.Element { return (
{ e.stopPropagation(); }} > - + {children}
diff --git a/src/views/BreedDetail.tsx b/src/views/BreedDetail.tsx new file mode 100644 index 00000000..ee265493 --- /dev/null +++ b/src/views/BreedDetail.tsx @@ -0,0 +1,65 @@ +import { useEffect, useState, JSX } from 'react' +import { useLocation, useNavigate, useParams, Location } from 'react-router-dom' +import Modal from '../components/Modal' +import { getBreedImages } from '../api/catApi' +import ImageGallery from '../components/ImageGallery' +import { parseBreed } from '../api/parsers' + +interface Breed { + id: string + name: string + description: string +} + +interface CatImage { + id: string + url: string +} + +function BreedDetail(): JSX.Element { + const location: Location = useLocation() + const navigate = useNavigate() + const { breedId } = useParams<{ breedId: string }>() + const [breedImages, setBreedImages] = useState([]) + const breedUnParsed: unknown = typeof location.state === 'object'&& location.state && 'breed' in location.state + ? location.state.breed : undefined + + let breed: Breed | undefined; + const navigateBreeds = () => navigate('/breeds') + try { + breed = parseBreed(breedUnParsed) + } catch { + void navigateBreeds() + } + + useEffect(() => { + if (breedId) { + void fetchBreedImages(breedId) + } + }, [breedId]) + + const fetchBreedImages = async (breedId: string) => { + try { + const data = await getBreedImages(breedId, 10) + setBreedImages(data) + } catch (error) { + console.error(error) + } + } + + const closeModal = () => { + void navigateBreeds() + } + + if (!breed) return <> + + return ( + +

{breed.name}

+

{breed.description}

+ +
+ ) +} + +export default BreedDetail diff --git a/src/views/Breeds.tsx b/src/views/Breeds.tsx new file mode 100644 index 00000000..0b58aefa --- /dev/null +++ b/src/views/Breeds.tsx @@ -0,0 +1,43 @@ +import { useState, useEffect, JSX } from 'react' +import { Link } from 'react-router-dom' +import { getBreeds } from '../api/catApi' + +interface Breed { + id: string + name: string + description: string +} + +function Breeds(): JSX.Element { + const [breeds, setBreeds] = useState([]) + + useEffect(() => { + void fetchBreeds() + }, []) + + const fetchBreeds = async () => { + try { + const data = await getBreeds() + setBreeds(data) + } catch (error) { + console.error(error) + } + } + + return ( +
+

Cat Breeds

+
    + {breeds.map(breed => ( +
  • + + {breed.name} + +
  • + ))} +
+
+ ) +} + +export default Breeds diff --git a/src/views/Home.tsx b/src/views/Home.tsx index 8d15d0fa..9592a2c3 100644 --- a/src/views/Home.tsx +++ b/src/views/Home.tsx @@ -1,38 +1,22 @@ import { JSX, useEffect } from 'react' -import { useNavigate } from 'react-router-dom' -import { CatImage } from '../api/types' import useFetchedImages from '../hooks/useFetchedImages' +import ImageGallery from '../components/ImageGallery' function Home(): JSX.Element { const { images, fetchImages, isLoading, error } = useFetchedImages() - const navigate = useNavigate() useEffect(() => { if (isLoading) return void fetchImages() }, []) - const openModal = (img: CatImage) => { - return navigate(`/image/${img.id}`) - } - return (

Random Cats

{isLoading &&

Loading...

} {error &&

{error}

} {!isLoading && images.length &&
-
- {images.map(img => ( - cat { void openModal(img) }} - /> - ))} -
+ From 6548986d3fc55b334c795328125135542dacf3c9 Mon Sep 17 00:00:00 2001 From: Marios Tsigkas Date: Tue, 11 Mar 2025 18:04:20 +0200 Subject: [PATCH 13/96] Add image fetching by ID and enhance Modal for loading and error states --- src/api/catApi.ts | 5 ++++ src/components/Modal.tsx | 10 ++++++-- src/views/ImageView.tsx | 53 +++++++++++++++++++++++++++++++--------- 3 files changed, 54 insertions(+), 14 deletions(-) diff --git a/src/api/catApi.ts b/src/api/catApi.ts index 44294f57..06f01782 100644 --- a/src/api/catApi.ts +++ b/src/api/catApi.ts @@ -18,3 +18,8 @@ export const getBreedImages = async (breedId: string, limit = 10): Promise => { + const res = await axios.get(`${BASE_URL}/images/${imageId}`) + return parseCatImages([res.data])[0] +} diff --git a/src/components/Modal.tsx b/src/components/Modal.tsx index f3ca2790..2547eb35 100644 --- a/src/components/Modal.tsx +++ b/src/components/Modal.tsx @@ -3,9 +3,15 @@ import { JSX } from 'react' interface ModalProps { children: React.ReactNode onClose: () => void + isLoading?: boolean + error?: string } -function Modal({ children, onClose }: ModalProps): JSX.Element { +function Modal({ children, onClose, isLoading, error }: ModalProps): JSX.Element { + const renderLoadingOrError = () => { + if (isLoading) return

Loading...

+ if (error) return

{error}

+ } return (
{ e.stopPropagation(); }} > - {children} + {renderLoadingOrError() ?? children}
) diff --git a/src/views/ImageView.tsx b/src/views/ImageView.tsx index 3a37f3a9..c9a06ea5 100644 --- a/src/views/ImageView.tsx +++ b/src/views/ImageView.tsx @@ -4,29 +4,58 @@ import Modal from '../components/Modal' import { CatImage } from '../api/types' import { useFavorites } from '../hooks/useFavorites' import { parseCatImages } from '../api/parsers' +import { getImageById } from '../api/catApi' function ImageView(): JSX.Element { const [selectedImage, setSelectedImage] = useState(null) + const [isLoading, setIsLoading] = useState(true) + const [error, setError] = useState(null) const navigate = useNavigate() const location: Location = useLocation() const { imageId } = useParams() const { addFavorite } = useFavorites() - useEffect(() => { - const imageUnParsed = (typeof location.state === 'object' + const fetchImageFromState = () => { + const imageFromState = typeof location.state === 'object' && location.state - && 'image' in location.state) - ? location.state.image - : undefined + && 'image' in location.state + ? location.state.image + : undefined + if (imageFromState) { + try { + const [image] = parseCatImages([imageFromState]) + setSelectedImage(image) + return + } catch (error) { + console.error('Invalid state data:', error) + } + } + } + + const fetchImageFromApi = async (imageId: string) => { try { - const [image] = parseCatImages([imageUnParsed]) + const image = await getImageById(imageId) setSelectedImage(image) - } catch (error) { - console.error('Invalid image data:', error) + } catch (err) { + console.error('Failed to fetch image:', err) + setError('Failed to load image') void navigate('/') } - }, [location.state, navigate]) + } + const fetchImage = async () => { + if (!imageId) return + setIsLoading(true) + fetchImageFromState() + if (!selectedImage) { + await fetchImageFromApi(imageId) + } + setIsLoading(false) + } + + useEffect(() => { + void fetchImage() + }, [imageId]) const closeModal = () => { void navigate('/') @@ -36,10 +65,9 @@ function ImageView(): JSX.Element { addFavorite(img) } - if (!selectedImage) return
Loading...
- return ( - + + {selectedImage && <> cat {selectedImage.breeds && selectedImage.breeds.length > 0 ? ( <> @@ -55,6 +83,7 @@ function ImageView(): JSX.Element { > Mark as Favourite + } ) } From 5d8311e0174b1e68c0e068176ae1c9dc5dd68988 Mon Sep 17 00:00:00 2001 From: Marios Tsigkas Date: Tue, 11 Mar 2025 18:53:44 +0200 Subject: [PATCH 14/96] Refactor ImageGallery and Breeds components for performance; implement memoization and clean up code --- src/App.tsx | 2 +- src/components/ImageGallery.tsx | 31 +++++++++++++++++-------------- src/setupTests.ts | 1 - src/views/Breeds.tsx | 26 ++++++++++++++++++-------- src/views/ImageView.tsx | 9 +++++++-- 5 files changed, 43 insertions(+), 26 deletions(-) diff --git a/src/App.tsx b/src/App.tsx index 16421211..aa7f9ae9 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,6 +1,6 @@ import { Routes, Route, Link } from 'react-router-dom' import Home from './views/Home' -import ImageView from './views/ImageView' // added ImageView import +import ImageView from './views/ImageView' import './App.css' import Favorites from './views/Favorites' import Breeds from './views/Breeds' diff --git a/src/components/ImageGallery.tsx b/src/components/ImageGallery.tsx index 6fee4981..4501751a 100644 --- a/src/components/ImageGallery.tsx +++ b/src/components/ImageGallery.tsx @@ -1,4 +1,4 @@ -import { JSX } from 'react' +import { JSX, memo } from 'react' import { CatImage } from '../api/types' import { Link } from 'react-router-dom' @@ -6,22 +6,25 @@ interface ImageGalleryProps { images: CatImage[] } +const MemoizedImageItem = memo(({ image }: { image: CatImage }) => ( + + cat + +)) + const ImageGallery = ({ images }: ImageGalleryProps): JSX.Element => { return (
- {images.map(img => ( - - cat - + {images.map(image => ( + ))}
) diff --git a/src/setupTests.ts b/src/setupTests.ts index 41d4401a..2fa3d6e2 100644 --- a/src/setupTests.ts +++ b/src/setupTests.ts @@ -14,7 +14,6 @@ import { afterEach, vi } from 'vitest' // })) // }) -// Ensure mocks are cleared after each test afterEach(() => { cleanup() vi.clearAllMocks() diff --git a/src/views/Breeds.tsx b/src/views/Breeds.tsx index 0b58aefa..4b59c3b3 100644 --- a/src/views/Breeds.tsx +++ b/src/views/Breeds.tsx @@ -1,4 +1,4 @@ -import { useState, useEffect, JSX } from 'react' +import { useState, useEffect, useMemo, JSX, memo } from 'react' import { Link } from 'react-router-dom' import { getBreeds } from '../api/catApi' @@ -8,6 +8,16 @@ interface Breed { description: string } +const BreedListItem = memo(({ breed }: { breed: Breed }) => { + return ( +
  • + + {breed.name} + +
  • + ) +}) + function Breeds(): JSX.Element { const [breeds, setBreeds] = useState([]) @@ -24,17 +34,17 @@ function Breeds(): JSX.Element { } } + const listItems = useMemo(() => { + return breeds.map(breed => ( + + )) + }, [breeds]) + return (

    Cat Breeds

      - {breeds.map(breed => ( -
    • - - {breed.name} - -
    • - ))} + {listItems}
    ) diff --git a/src/views/ImageView.tsx b/src/views/ImageView.tsx index c9a06ea5..d9bb7bdb 100644 --- a/src/views/ImageView.tsx +++ b/src/views/ImageView.tsx @@ -1,4 +1,4 @@ -import { useState, useEffect, JSX } from 'react' +import { useState, useEffect, JSX, useMemo } from 'react' import { useNavigate, useParams, useLocation, Location } from 'react-router-dom' import Modal from '../components/Modal' import { CatImage } from '../api/types' @@ -65,8 +65,13 @@ function ImageView(): JSX.Element { addFavorite(img) } + const errorMessage = useMemo(() => + (error ?? !selectedImage) ? 'Error loading image' : undefined, + [error, selectedImage] + ) + return ( - + {selectedImage && <> cat {selectedImage.breeds && selectedImage.breeds.length > 0 ? ( From df3c762fff7496b8a0a4f24b32f8b41fecd38b23 Mon Sep 17 00:00:00 2001 From: Marios Tsigkas Date: Tue, 11 Mar 2025 19:56:48 +0200 Subject: [PATCH 15/96] Enhance ImageGallery and Favorites components; add renderAfterImage prop for custom rendering and improve favorite removal logic --- src/components/ImageGallery.tsx | 33 ++++++++++++++++++--------------- src/hooks/useFavorites.ts | 4 ++-- src/views/Favorites.tsx | 30 +++++++++++++----------------- src/views/ImageView.tsx | 25 ++++++++++++++++++------- 4 files changed, 51 insertions(+), 41 deletions(-) diff --git a/src/components/ImageGallery.tsx b/src/components/ImageGallery.tsx index 4501751a..dd8e18c1 100644 --- a/src/components/ImageGallery.tsx +++ b/src/components/ImageGallery.tsx @@ -3,28 +3,31 @@ import { CatImage } from '../api/types' import { Link } from 'react-router-dom' interface ImageGalleryProps { - images: CatImage[] + images: CatImage[], + renderAfterImage?: (image: CatImage) => JSX.Element } -const MemoizedImageItem = memo(({ image }: { image: CatImage }) => ( - - cat - +const MemoizedImageItem = memo(({ image, renderAfterImage }: { image: CatImage, renderAfterImage: ImageGalleryProps['renderAfterImage'] }) => ( +
    + + cat + + {renderAfterImage?.(image)} +
    )) -const ImageGallery = ({ images }: ImageGalleryProps): JSX.Element => { +const ImageGallery = ({ images, renderAfterImage }: ImageGalleryProps): JSX.Element => { return (
    {images.map(image => ( - + ))}
    ) diff --git a/src/hooks/useFavorites.ts b/src/hooks/useFavorites.ts index 75ddb1f2..d4de7b42 100644 --- a/src/hooks/useFavorites.ts +++ b/src/hooks/useFavorites.ts @@ -17,8 +17,8 @@ export function useFavorites() { localStorage.setItem('favorites', JSON.stringify(updatedFavorites)) } - const removeFavorite = (id: string) => { - const newFavorites = favorites.filter(fav => fav.id !== id) + const removeFavorite = (img: CatImage) => { + const newFavorites = favorites.filter(fav => fav.id !== img.id) setFavorites(newFavorites) localStorage.setItem('favorites', JSON.stringify(newFavorites)) } diff --git a/src/views/Favorites.tsx b/src/views/Favorites.tsx index f5bbe9ac..6f1a8913 100644 --- a/src/views/Favorites.tsx +++ b/src/views/Favorites.tsx @@ -1,29 +1,25 @@ import { JSX } from 'react' import { useFavorites } from '../hooks/useFavorites' +import ImageGallery from '../components/ImageGallery'; +import { CatImage } from '../api/types'; function Favorites(): JSX.Element { const { favorites, removeFavorite } = useFavorites() + const removeFavoriteButton = (fav: CatImage) => { + return + } + + return (

    Favourite Cats

    -
    - {favorites.length ? ( - favorites.map(fav => ( -
    - cat - -
    - )) - ) : ( -

    No favourites yet.

    - )} -
    +
    ) } diff --git a/src/views/ImageView.tsx b/src/views/ImageView.tsx index d9bb7bdb..61d23b3b 100644 --- a/src/views/ImageView.tsx +++ b/src/views/ImageView.tsx @@ -13,7 +13,7 @@ function ImageView(): JSX.Element { const navigate = useNavigate() const location: Location = useLocation() const { imageId } = useParams() - const { addFavorite } = useFavorites() + const { addFavorite, removeFavorite, favorites } = useFavorites() const fetchImageFromState = () => { const imageFromState = typeof location.state === 'object' @@ -58,17 +58,26 @@ function ImageView(): JSX.Element { }, [imageId]) const closeModal = () => { - void navigate('/') + void navigate(-1) } - const markAsFavourite = (img: CatImage) => { - addFavorite(img) - } + const isFavorite = useMemo(() => + selectedImage ? favorites.some(fav => fav.id === selectedImage.id) : false, + [selectedImage, favorites] + ) const errorMessage = useMemo(() => (error ?? !selectedImage) ? 'Error loading image' : undefined, [error, selectedImage] ) + const clickFavoriteButton = (selectedImage: CatImage) => { + if (isFavorite) { + removeFavorite(selectedImage) } + else{ + addFavorite(selectedImage) + } + } + return ( @@ -84,9 +93,11 @@ function ImageView(): JSX.Element { )} } From 6a9f7590545ad8fc91f583e74a8452d2830c469f Mon Sep 17 00:00:00 2001 From: Marios Tsigkas Date: Wed, 12 Mar 2025 15:18:21 +0200 Subject: [PATCH 16/96] Optimize image fetching functions with useCallback for improved performance and stability --- src/views/ImageView.tsx | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/views/ImageView.tsx b/src/views/ImageView.tsx index 61d23b3b..653c2bbb 100644 --- a/src/views/ImageView.tsx +++ b/src/views/ImageView.tsx @@ -1,4 +1,4 @@ -import { useState, useEffect, JSX, useMemo } from 'react' +import { useState, useEffect, JSX, useMemo, useCallback } from 'react' import { useNavigate, useParams, useLocation, Location } from 'react-router-dom' import Modal from '../components/Modal' import { CatImage } from '../api/types' @@ -15,7 +15,7 @@ function ImageView(): JSX.Element { const { imageId } = useParams() const { addFavorite, removeFavorite, favorites } = useFavorites() - const fetchImageFromState = () => { + const fetchImageFromState = useCallback(() => { const imageFromState = typeof location.state === 'object' && location.state && 'image' in location.state @@ -31,9 +31,9 @@ function ImageView(): JSX.Element { console.error('Invalid state data:', error) } } - } + },[location.state]) - const fetchImageFromApi = async (imageId: string) => { + const fetchImageFromApi = useCallback(async (imageId: string) => { try { const image = await getImageById(imageId) setSelectedImage(image) @@ -42,8 +42,9 @@ function ImageView(): JSX.Element { setError('Failed to load image') void navigate('/') } - } - const fetchImage = async () => { + }, [navigate]) + + const fetchImage = useCallback(async () => { if (!imageId) return setIsLoading(true) fetchImageFromState() @@ -51,11 +52,11 @@ function ImageView(): JSX.Element { await fetchImageFromApi(imageId) } setIsLoading(false) - } + }, [fetchImageFromApi, fetchImageFromState, imageId]) useEffect(() => { void fetchImage() - }, [imageId]) + }, [imageId, fetchImage]) const closeModal = () => { void navigate(-1) From d39b95af5627caf95f121ea6b061b8c4c9f5d7e8 Mon Sep 17 00:00:00 2001 From: Marios Tsigkas Date: Wed, 12 Mar 2025 15:44:22 +0200 Subject: [PATCH 17/96] Add breed fetching by ID and enhance BreedDetail component with loading and error handling --- src/api/catApi.ts | 5 +++ src/views/BreedDetail.tsx | 75 ++++++++++++++++++++++++--------------- 2 files changed, 52 insertions(+), 28 deletions(-) diff --git a/src/api/catApi.ts b/src/api/catApi.ts index 06f01782..ca2d382a 100644 --- a/src/api/catApi.ts +++ b/src/api/catApi.ts @@ -23,3 +23,8 @@ export const getImageById = async (imageId: string): Promise => { const res = await axios.get(`${BASE_URL}/images/${imageId}`) return parseCatImages([res.data])[0] } + +export const getBreedById = async (breedId: string): Promise => { + const res = await axios.get(`${BASE_URL}/breeds/${breedId}`) + return parseBreeds([res.data])[0] +} diff --git a/src/views/BreedDetail.tsx b/src/views/BreedDetail.tsx index ee265493..00f90af7 100644 --- a/src/views/BreedDetail.tsx +++ b/src/views/BreedDetail.tsx @@ -1,42 +1,56 @@ -import { useEffect, useState, JSX } from 'react' +import { useEffect, useState, JSX, useCallback, useMemo } from 'react' import { useLocation, useNavigate, useParams, Location } from 'react-router-dom' import Modal from '../components/Modal' -import { getBreedImages } from '../api/catApi' +import { getBreedById, getBreedImages } from '../api/catApi' import ImageGallery from '../components/ImageGallery' import { parseBreed } from '../api/parsers' - -interface Breed { - id: string - name: string - description: string -} - -interface CatImage { - id: string - url: string -} +import { Breed, CatImage } from '../api/types' function BreedDetail(): JSX.Element { const location: Location = useLocation() const navigate = useNavigate() const { breedId } = useParams<{ breedId: string }>() const [breedImages, setBreedImages] = useState([]) - const breedUnParsed: unknown = typeof location.state === 'object'&& location.state && 'breed' in location.state - ? location.state.breed : undefined + const [isLoading, setIsLoading] = useState(true) + const [error, setError] = useState(null) + const [breed, setBreed] = useState(null); + const navigateBreeds = useCallback(() => navigate('/breeds'), [navigate]) + + const fetchBreedFromState = useCallback(() => { + const breedUnParsed: unknown = (typeof location.state === 'object' + && location.state && 'breed' in location.state) + ? location.state.breed + : undefined + if (breedUnParsed) { + try { + setBreed(parseBreed(breedUnParsed)) + } catch { + console.error('Invalid state data:') + }} + }, [location.state]) + + const fetchBreedFromApi = useCallback(async (id: string) => { + try { + const breed = await getBreedById(id) + setBreed(breed) + } catch (err) { + console.error('Failed to fetch image:', err) + setError('Failed to load image') + void navigate('/') + } + }, [navigate]) - let breed: Breed | undefined; - const navigateBreeds = () => navigate('/breeds') - try { - breed = parseBreed(breedUnParsed) - } catch { - void navigateBreeds() - } useEffect(() => { + if (!breedId) return + setIsLoading(true) + fetchBreedFromState() if (breedId) { void fetchBreedImages(breedId) + void fetchBreedFromApi(breedId) } - }, [breedId]) + setIsLoading(false) + }, [breedId, fetchBreedFromApi, fetchBreedFromState]) const fetchBreedImages = async (breedId: string) => { try { @@ -51,13 +65,18 @@ function BreedDetail(): JSX.Element { void navigateBreeds() } - if (!breed) return <> + const errorMessage = useMemo(() => + (error ?? !breed) ? 'Error loading breed' : undefined, + [error, breed] + ) return ( - -

    {breed.name}

    -

    {breed.description}

    - + + {breed && <> +

    {breed.name}

    +

    {breed.description}

    + + }
    ) } From 15f045ccd7731ed7cc2491109dbd2f1168c5b3ee Mon Sep 17 00:00:00 2001 From: Marios Tsigkas Date: Wed, 12 Mar 2025 15:49:04 +0200 Subject: [PATCH 18/96] Enhance Modal component with improved loading and error message styling; update BreedDetail to prevent navigation on image fetch error --- src/components/Modal.tsx | 6 +++--- src/views/BreedDetail.tsx | 3 +-- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/components/Modal.tsx b/src/components/Modal.tsx index 2547eb35..b92f35e6 100644 --- a/src/components/Modal.tsx +++ b/src/components/Modal.tsx @@ -9,8 +9,8 @@ interface ModalProps { function Modal({ children, onClose, isLoading, error }: ModalProps): JSX.Element { const renderLoadingOrError = () => { - if (isLoading) return

    Loading...

    - if (error) return

    {error}

    + if (isLoading) return

    Loading...

    + if (error) return

    {error}

    } return (
    { e.stopPropagation(); }} > diff --git a/src/views/BreedDetail.tsx b/src/views/BreedDetail.tsx index 00f90af7..804063b8 100644 --- a/src/views/BreedDetail.tsx +++ b/src/views/BreedDetail.tsx @@ -36,9 +36,8 @@ function BreedDetail(): JSX.Element { } catch (err) { console.error('Failed to fetch image:', err) setError('Failed to load image') - void navigate('/') } - }, [navigate]) + }, []) useEffect(() => { From 42d12a342d0f5fa5d6ef72746640319698f89a79 Mon Sep 17 00:00:00 2001 From: Marios Tsigkas Date: Wed, 12 Mar 2025 16:14:30 +0200 Subject: [PATCH 19/96] Add API functions for fetching images and breeds by ID; enhance tests for Home component and improve ImageGallery layout --- src/api/__tests__/catApi.test.ts | 60 ++++++++++++++++++- src/components/ImageGallery.tsx | 2 +- src/components/Modal.tsx | 2 +- src/views/__tests__/Home.test.tsx | 23 +++---- .../__snapshots__/Home.test.tsx.snap | 3 + 5 files changed, 77 insertions(+), 13 deletions(-) create mode 100644 src/views/__tests__/__snapshots__/Home.test.tsx.snap diff --git a/src/api/__tests__/catApi.test.ts b/src/api/__tests__/catApi.test.ts index 88535528..60842e71 100644 --- a/src/api/__tests__/catApi.test.ts +++ b/src/api/__tests__/catApi.test.ts @@ -1,6 +1,6 @@ import { describe, it, expect, vi, afterEach } from 'vitest' import axios from 'axios' -import { getRandomImages, getBreeds, getBreedImages } from '../catApi' +import { getRandomImages, getBreeds, getBreedImages, getImageById, getBreedById } from '../catApi' import { parseCatImages, parseBreeds } from '../parsers' vi.mock('axios') @@ -120,4 +120,62 @@ describe('catApi', () => { await expect(getBreedImages('b1')).rejects.toThrow('Failed to fetch') }) }) + + describe('getImageById', () => { + it('should call the correct API endpoint', async () => { + const imageId = '2' + const mockImage = { id: imageId, url: 'https://example.com/cat2.jpg' } + mockedAxios.get.mockResolvedValue({ data: mockImage }) + + await getImageById(imageId) + + expect(mockedAxiosGet).toHaveBeenCalledWith(`https://api.thecatapi.com/v1/images/${imageId}`) + }) + + it('should return a cat image', async () => { + const imageId = '2' + const mockImage = { id: imageId, url: 'https://example.com/cat2.jpg' } + mockedAxios.get.mockResolvedValue({ data: mockImage }) + + const image = await getImageById(imageId) + + expect(image).toEqual(parseCatImages([mockImage])[0]) + }) + + it('should handle errors', async () => { + const imageId = '2' + mockedAxios.get.mockRejectedValue(new Error('Failed to fetch')) + + await expect(getImageById(imageId)).rejects.toThrow('Failed to fetch') + }) + }) + + describe('getBreedById', () => { + it('should call the correct API endpoint', async () => { + const breedId = 'b2' + const mockBreed = { id: breedId, name: 'Breed 2', description: 'Description 2' } + mockedAxios.get.mockResolvedValue({ data: mockBreed }) + + await getBreedById(breedId) + + expect(mockedAxiosGet).toHaveBeenCalledWith(`https://api.thecatapi.com/v1/breeds/${breedId}`) + }) + + it('should return a breed', async () => { + const breedId = 'b2' + const mockBreed = { id: breedId, name: 'Breed 2', description: 'Description 2' } + mockedAxios.get.mockResolvedValue({ data: mockBreed }) + + const breed = await getBreedById(breedId) + + expect(breed).toEqual(parseBreeds([mockBreed])[0]) + }) + + it('should handle errors', async () => { + const breedId = 'b2' + mockedAxios.get.mockRejectedValue(new Error('Failed to fetch')) + + await expect(getBreedById(breedId)).rejects.toThrow('Failed to fetch') + }) + }) }) diff --git a/src/components/ImageGallery.tsx b/src/components/ImageGallery.tsx index dd8e18c1..ebe73a93 100644 --- a/src/components/ImageGallery.tsx +++ b/src/components/ImageGallery.tsx @@ -25,7 +25,7 @@ const MemoizedImageItem = memo(({ image, renderAfterImage }: { image: CatImage, const ImageGallery = ({ images, renderAfterImage }: ImageGalleryProps): JSX.Element => { return ( -
    +
    {images.map(image => ( ))} diff --git a/src/components/Modal.tsx b/src/components/Modal.tsx index b92f35e6..dc81eeb8 100644 --- a/src/components/Modal.tsx +++ b/src/components/Modal.tsx @@ -21,7 +21,7 @@ function Modal({ children, onClose, isLoading, error }: ModalProps): JSX.Element className='p-6 relative max-h-screen overflow-y-auto' onClick={e => { e.stopPropagation(); }} > - + {renderLoadingOrError() ?? children}
    diff --git a/src/views/__tests__/Home.test.tsx b/src/views/__tests__/Home.test.tsx index b3728f8f..3c06d5e0 100644 --- a/src/views/__tests__/Home.test.tsx +++ b/src/views/__tests__/Home.test.tsx @@ -1,24 +1,27 @@ import { act, render } from '@testing-library/react' -import { BrowserRouter } from 'react-router-dom' -import { describe, expect, it, vi } from 'vitest' +import { beforeEach, describe, expect, it, vi } from 'vitest' import Home from '../Home' import * as catApi from '../../api/catApi' describe('Home', () => { - it('should call getRandomImages once on mount', () => { - const mockGetRandomImages = vi.spyOn(catApi, 'getRandomImages') - mockGetRandomImages.mockResolvedValue([]) + const mockGetRandomImages = vi.spyOn(catApi, 'getRandomImages') + mockGetRandomImages.mockResolvedValue([]) + let rendered: ReturnType; + beforeEach(() => { act(() => { - render( - + rendered = render( - - ) - }) + ); + }); + }) + it('should call getRandomImages once on mount', () => { expect(mockGetRandomImages).toHaveBeenCalledTimes(1) expect(mockGetRandomImages).toHaveBeenCalledWith(10) }) + it('should have the same snapshot as befoere', () => { + expect(rendered.baseElement).toMatchSnapshot() + }) }) diff --git a/src/views/__tests__/__snapshots__/Home.test.tsx.snap b/src/views/__tests__/__snapshots__/Home.test.tsx.snap new file mode 100644 index 00000000..c4363e66 --- /dev/null +++ b/src/views/__tests__/__snapshots__/Home.test.tsx.snap @@ -0,0 +1,3 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`Home > should have the same snapshot as befoere 1`] = `undefined`; From 03674c884a94beb9e8160ae8c571fe5abeecae29 Mon Sep 17 00:00:00 2001 From: Marios Tsigkas Date: Wed, 12 Mar 2025 16:25:49 +0200 Subject: [PATCH 20/96] Add Cypress configuration and tests for breeds and home pages; update .gitignore to exclude video files --- .gitignore | 5 + cypress.config.js | 7 + cypress/e2e/breeds.spec.ts | 19 + cypress/e2e/home.spec.ts | 22 + package.json | 5 +- pnpm-lock.yaml | 997 ++++++++++++++++++++++++++++++++++++- 6 files changed, 1041 insertions(+), 14 deletions(-) create mode 100644 cypress.config.js create mode 100644 cypress/e2e/breeds.spec.ts create mode 100644 cypress/e2e/home.spec.ts diff --git a/.gitignore b/.gitignore index a547bf36..4e22b9b8 100644 --- a/.gitignore +++ b/.gitignore @@ -12,6 +12,11 @@ dist dist-ssr *.local +*.mp4 +*.mov +*.avi +*.mkv + # Editor directories and files .vscode/* !.vscode/extensions.json diff --git a/cypress.config.js b/cypress.config.js new file mode 100644 index 00000000..0be30a76 --- /dev/null +++ b/cypress.config.js @@ -0,0 +1,7 @@ +export default { + e2e: { + baseUrl: 'http://localhost:5173', + specPattern: 'cypress/e2e/**/*.{js,jsx,ts,tsx}', + supportFile: false, + }, +}; diff --git a/cypress/e2e/breeds.spec.ts b/cypress/e2e/breeds.spec.ts new file mode 100644 index 00000000..c8c4a77d --- /dev/null +++ b/cypress/e2e/breeds.spec.ts @@ -0,0 +1,19 @@ +describe('Breeds Page', () => { + beforeEach(() => { + cy.visit('/breeds') + }) + + it('displays the header "Cat Breeds"', () => { + cy.get('h1').contains('Cat Breeds').should('exist') + }) + + it('renders at least one breed list item', () => { + cy.get('ul li').its('length').should('be.gt', 0) + }) + + // New test: clicking on a breed navigates to breed detail view + it('navigates to breed detail on breed click', () => { + cy.get('ul li').first().click(); + cy.url().should('include', '/breed-detail/'); + }); +}) diff --git a/cypress/e2e/home.spec.ts b/cypress/e2e/home.spec.ts new file mode 100644 index 00000000..b680d3a9 --- /dev/null +++ b/cypress/e2e/home.spec.ts @@ -0,0 +1,22 @@ +describe('Home Page', () => { + beforeEach(() => { + cy.visit('/'); + }); + + it('displays the header "Random Cats"', () => { + cy.get('h1').contains('Random Cats').should('exist'); + }); + + it('loads images and shows the "Load New" button', () => { + // Check that at least one image is rendered + cy.get('img').should('have.length.greaterThan', 0); + // Check for the existence of the load button + cy.get('button').contains('Load New').should('exist'); + }); + + // New test: clicking on an image navigates to image detail view + it('navigates to image detail on image click', () => { + cy.get('img').first().click(); + cy.url().should('include', '/image/'); + }); +}); diff --git a/package.json b/package.json index d3faf74b..a9dcc574 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,9 @@ "lint": "eslint .", "preview": "vite preview", "test": "vitest", - "coverage": "vitest run --coverage" + "coverage": "vitest run --coverage", + "cypress:open": "cypress open", + "cypress:run": "cypress run" }, "dependencies": { "axios": "^1.8.2", @@ -26,6 +28,7 @@ "@vitejs/plugin-react-swc": "^3.8.0", "@vitest/coverage-v8": "^1.5.0", "autoprefixer": "^10.4.18", + "cypress": "^12.12.0", "eslint": "^9.21.0", "eslint-plugin-react-dom": "^1.31.0", "eslint-plugin-react-hooks": "^5.1.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 081cd03b..582335ce 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -45,6 +45,9 @@ importers: autoprefixer: specifier: ^10.4.18 version: 10.4.21(postcss@8.5.3) + cypress: + specifier: ^12.12.0 + version: 12.17.4 eslint: specifier: ^9.21.0 version: 9.22.0(jiti@1.21.7) @@ -129,6 +132,10 @@ packages: '@bcoe/v8-coverage@0.2.3': resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==} + '@colors/colors@1.5.0': + resolution: {integrity: sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==} + engines: {node: '>=0.1.90'} + '@csstools/color-helpers@5.0.2': resolution: {integrity: sha512-JqWH1vsgdGcw2RR6VliXXdA0/59LttzlU8UlRT/iUUsEeWfYq8I+K0yhihEUTTHLRm1EXvpsCx3083EU15ecsA==} engines: {node: '>=18'} @@ -157,6 +164,13 @@ packages: resolution: {integrity: sha512-UJnjoFsmxfKUdNYdWgOB0mWUypuLvAfQPH1+pyvRJs6euowbFkFC6P13w1l8mJyi3vxYMxc9kld5jZEGRQs6bw==} engines: {node: '>=18'} + '@cypress/request@2.88.12': + resolution: {integrity: sha512-tOn+0mDZxASFM+cuAP9szGUGPI1HwWVSvdzm7V4cCsPdFTx6qMj29CwaQmRAMIEhORIUBFBsYROYJcveK4uOjA==} + engines: {node: '>= 6'} + + '@cypress/xvfb@1.2.4': + resolution: {integrity: sha512-skbBzPggOVYCbnGgV+0dmBdW/s77ZkAOXIC1knS8NagwDjBrNC1LuXtQJeiN6l+m7lzmHtaoUw/ctJKdqkG57Q==} + '@esbuild/aix-ppc64@0.25.1': resolution: {integrity: sha512-kfYGy8IdzTGy+z0vFGvExZtxkFlA4zAxgKEahG9KE1ScBjpQnFsNOX8KTU5ojNru5ed5CVoJYXFtoxaq5nFbjQ==} engines: {node: '>=18'} @@ -636,6 +650,9 @@ packages: '@types/json-schema@7.0.15': resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} + '@types/node@16.18.126': + resolution: {integrity: sha512-OTcgaiwfGFBKacvfwuHzzn1KLxH/er8mluiy8/uM3sGXHaRe73RrSIj01jow9t4kJEW633Ov+cOexXeiApTyAw==} + '@types/react-dom@19.0.4': resolution: {integrity: sha512-4fSQ8vWFkg+TGhePfUzVmat3eC14TXYSsiiDSLI0dVLsrm9gZFABjPy/Qu6TKgl1tq1Bu1yDsuQgY3A3DOjCcg==} peerDependencies: @@ -644,6 +661,15 @@ packages: '@types/react@19.0.10': resolution: {integrity: sha512-JuRQ9KXLEjaUNjTWpzuR231Z2WpIwczOkBEIvbHNCzQefFIT0L8IqE6NV6ULLyC1SI/i234JnDoMkfg+RjQj2g==} + '@types/sinonjs__fake-timers@8.1.1': + resolution: {integrity: sha512-0kSuKjAS0TrGLJ0M/+8MaFkGsQhZpB6pxOmvS3K8FYI72K//YmdfoW9X2qPsAKh1mkwxGD5zib9s1FIFed6E8g==} + + '@types/sizzle@2.3.9': + resolution: {integrity: sha512-xzLEyKB50yqCUPUJkIsrVvoWNfFUbIZI+RspLWt8u+tIW/BetMBZtgV2LY/2o+tYH8dRvQ+eoPf3NdhQCcLE2w==} + + '@types/yauzl@2.10.3': + resolution: {integrity: sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==} + '@typescript-eslint/eslint-plugin@8.26.0': resolution: {integrity: sha512-cLr1J6pe56zjKYajK6SSSre6nl1Gj6xDp1TY0trpgPzjVbgDwd09v2Ws37LABxzkicmUjhEeg/fAUjPJJB1v5Q==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -744,9 +770,21 @@ packages: resolution: {integrity: sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==} engines: {node: '>= 14'} + aggregate-error@3.1.0: + resolution: {integrity: sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==} + engines: {node: '>=8'} + ajv@6.12.6: resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} + ansi-colors@4.1.3: + resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==} + engines: {node: '>=6'} + + ansi-escapes@4.3.2: + resolution: {integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==} + engines: {node: '>=8'} + ansi-regex@5.0.1: resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} engines: {node: '>=8'} @@ -774,6 +812,9 @@ packages: resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} engines: {node: '>= 8'} + arch@2.2.0: + resolution: {integrity: sha512-Of/R0wqp83cgHozfIYLbBMnej79U/SVGOOyuB3VVFv1NRM/PSFMK12x9KVtiYzJqmnU5WR2qp0Z5rHb7sWGnFQ==} + arg@5.0.2: resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==} @@ -783,13 +824,31 @@ packages: aria-query@5.3.0: resolution: {integrity: sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==} + asn1@0.2.6: + resolution: {integrity: sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==} + + assert-plus@1.0.0: + resolution: {integrity: sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==} + engines: {node: '>=0.8'} + assertion-error@2.0.1: resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} engines: {node: '>=12'} + astral-regex@2.0.0: + resolution: {integrity: sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==} + engines: {node: '>=8'} + + async@3.2.6: + resolution: {integrity: sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==} + asynckit@0.4.0: resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} + at-least-node@1.0.0: + resolution: {integrity: sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==} + engines: {node: '>= 4.0.0'} + autoprefixer@10.4.21: resolution: {integrity: sha512-O+A6LWV5LDHSJD3LjHYoNi4VLsj/Whi7k6zG12xTYaU4cQ8oxQGckXNX8cRHK5yOZ/ppVHe0ZBXGzSV9jXdVbQ==} engines: {node: ^10 || ^12 || >=14} @@ -797,12 +856,24 @@ packages: peerDependencies: postcss: ^8.1.0 + aws-sign2@0.7.0: + resolution: {integrity: sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==} + + aws4@1.13.2: + resolution: {integrity: sha512-lHe62zvbTB5eEABUVi/AwVh0ZKY9rMMDhmm+eeyuuUQbQ3+J+fONVQOZyj+DdrvD4BY33uYniyRJ4UJIaSKAfw==} + axios@1.8.2: resolution: {integrity: sha512-ls4GYBm5aig9vWx8AWDSGLpnpDQRtWAfrjU+EuytuODrFBkqesN2RkOQCBzrA1RQNHw1SmRMSDDDSwzNAYQ6Rg==} balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + base64-js@1.5.1: + resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} + + bcrypt-pbkdf@1.0.2: + resolution: {integrity: sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==} + binary-extensions@2.3.0: resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} engines: {node: '>=8'} @@ -810,6 +881,12 @@ packages: birecord@0.1.1: resolution: {integrity: sha512-VUpsf/qykW0heRlC8LooCq28Kxn3mAqKohhDG/49rrsQ1dT1CXyj/pgXS+5BSRzFTR/3DyIBOqQOrGyZOh71Aw==} + blob-util@2.0.2: + resolution: {integrity: sha512-T7JQa+zsXXEa6/8ZhHcQEW1UFfVM49Ts65uBkFL6fz2QmrElqmbajIDJvuA0tEhRe5eIjpV9ZF+0RfZR9voJFQ==} + + bluebird@3.7.2: + resolution: {integrity: sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==} + brace-expansion@1.1.11: resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} @@ -825,14 +902,28 @@ packages: engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true + buffer-crc32@0.2.13: + resolution: {integrity: sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==} + + buffer@5.7.1: + resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==} + cac@6.7.14: resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} engines: {node: '>=8'} + cachedir@2.4.0: + resolution: {integrity: sha512-9EtFOZR8g22CL7BWjJ9BUx1+A/djkofnyW3aOXZORNW2kxoUpx2h+uN2cOqwPmFhnpVmxg+KW2OjOSgChTEvsQ==} + engines: {node: '>=6'} + call-bind-apply-helpers@1.0.2: resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} engines: {node: '>= 0.4'} + call-bound@1.0.4: + resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==} + engines: {node: '>= 0.4'} + callsites@3.1.0: resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} engines: {node: '>=6'} @@ -844,6 +935,9 @@ packages: caniuse-lite@1.0.30001703: resolution: {integrity: sha512-kRlAGTRWgPsOj7oARC9m1okJEXdL/8fekFVcxA8Hl7GH4r/sN4OJn/i6Flde373T50KS7Y37oFbMwlE8+F42kQ==} + caseless@0.12.0: + resolution: {integrity: sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==} + chai@5.2.0: resolution: {integrity: sha512-mCuXncKXk5iCLhfhwTc0izo0gtEmpz5CtG2y8GiOINBlMVS6v8TMRc5TaLWKS6692m9+dVVfzgeVxR5UxWHTYw==} engines: {node: '>=12'} @@ -860,10 +954,34 @@ packages: resolution: {integrity: sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==} engines: {node: '>= 16'} + check-more-types@2.24.0: + resolution: {integrity: sha512-Pj779qHxV2tuapviy1bSZNEL1maXr13bPYpsvSDB68HlYcYuhlDrmGd63i0JHMCLKzc7rUSNIrpdJlhVlNwrxA==} + engines: {node: '>= 0.8.0'} + chokidar@3.6.0: resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} engines: {node: '>= 8.10.0'} + ci-info@3.9.0: + resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==} + engines: {node: '>=8'} + + clean-stack@2.2.0: + resolution: {integrity: sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==} + engines: {node: '>=6'} + + cli-cursor@3.1.0: + resolution: {integrity: sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==} + engines: {node: '>=8'} + + cli-table3@0.6.5: + resolution: {integrity: sha512-+W/5efTR7y5HRD7gACw9yQjqMVvEMLBHmboM/kPWam+H+Hmyrgjh6YncVKK122YZkXrLudzTuAukUw9FnMf7IQ==} + engines: {node: 10.* || >= 12.*} + + cli-truncate@2.1.0: + resolution: {integrity: sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==} + engines: {node: '>=8'} + color-convert@2.0.1: resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} engines: {node: '>=7.0.0'} @@ -871,6 +989,9 @@ packages: color-name@1.1.4: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + colorette@2.0.20: + resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==} + combined-stream@1.0.8: resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} engines: {node: '>= 0.8'} @@ -879,6 +1000,14 @@ packages: resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} engines: {node: '>= 6'} + commander@6.2.1: + resolution: {integrity: sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==} + engines: {node: '>= 6'} + + common-tags@1.8.2: + resolution: {integrity: sha512-gk/Z852D2Wtb//0I+kRFNKKE9dIIVirjoqPoA1wJU+XePVXZfGeBpk45+A1rKO4Q43prqWBNY/MiIeRLbPWUaA==} + engines: {node: '>=4.0.0'} + compare-versions@6.1.1: resolution: {integrity: sha512-4hm4VPpIecmlg59CHXnRDnqGplJFrbLG4aFEl5vl6cK1u76ws3LLvX7ikFnTDl5vo39sjWD6AaDPYodJp/NNHg==} @@ -889,6 +1018,9 @@ packages: resolution: {integrity: sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==} engines: {node: '>=18'} + core-util-is@1.0.2: + resolution: {integrity: sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==} + cross-spawn@7.0.6: resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} engines: {node: '>= 8'} @@ -908,10 +1040,30 @@ packages: csstype@3.1.3: resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} + cypress@12.17.4: + resolution: {integrity: sha512-gAN8Pmns9MA5eCDFSDJXWKUpaL3IDd89N9TtIupjYnzLSmlpVr+ZR+vb4U/qaMp+lB6tBvAmt7504c3Z4RU5KQ==} + engines: {node: ^14.0.0 || ^16.0.0 || >=18.0.0} + hasBin: true + + dashdash@1.14.1: + resolution: {integrity: sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==} + engines: {node: '>=0.10'} + data-urls@5.0.0: resolution: {integrity: sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg==} engines: {node: '>=18'} + dayjs@1.11.13: + resolution: {integrity: sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==} + + debug@3.2.7: + resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + debug@4.4.0: resolution: {integrity: sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==} engines: {node: '>=6.0'} @@ -958,6 +1110,9 @@ packages: eastasianwidth@0.2.0: resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} + ecc-jsbn@0.1.2: + resolution: {integrity: sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==} + electron-to-chromium@1.5.114: resolution: {integrity: sha512-DFptFef3iktoKlFQK/afbo274/XNWD00Am0xa7M8FZUepHlHT8PEuiNBoRfFHbH1okqN58AlhbJ4QTkcnXorjA==} @@ -967,6 +1122,13 @@ packages: emoji-regex@9.2.2: resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} + end-of-stream@1.4.4: + resolution: {integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==} + + enquirer@2.4.1: + resolution: {integrity: sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==} + engines: {node: '>=8.6'} + entities@4.5.0: resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} engines: {node: '>=0.12'} @@ -999,6 +1161,10 @@ packages: resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} engines: {node: '>=6'} + escape-string-regexp@1.0.5: + resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} + engines: {node: '>=0.8.0'} + escape-string-regexp@4.0.0: resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} engines: {node: '>=10'} @@ -1082,10 +1248,33 @@ packages: resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} engines: {node: '>=0.10.0'} + eventemitter2@6.4.7: + resolution: {integrity: sha512-tYUSVOGeQPKt/eC1ABfhHy5Xd96N3oIijJvN3O9+TsC28T5V9yX9oEfEK5faP0EFSNVOG97qtAS68GBrQB2hDg==} + + execa@4.1.0: + resolution: {integrity: sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==} + engines: {node: '>=10'} + + executable@4.1.1: + resolution: {integrity: sha512-8iA79xD3uAch729dUG8xaaBBFGaEa0wdD2VkYLFHwlqosEj/jT66AzcreRDSgV7ehnNLBW2WR5jIXwGKjVdTLg==} + engines: {node: '>=4'} + expect-type@1.2.0: resolution: {integrity: sha512-80F22aiJ3GLyVnS/B3HzgR6RelZVumzj9jkL0Rhz4h0xYbNW9PjlQz5h3J/SShErbXBc295vseR4/MIbVmUbeA==} engines: {node: '>=12.0.0'} + extend@3.0.2: + resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==} + + extract-zip@2.0.1: + resolution: {integrity: sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==} + engines: {node: '>= 10.17.0'} + hasBin: true + + extsprintf@1.3.0: + resolution: {integrity: sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==} + engines: {'0': node >=0.6.0} + fast-deep-equal@3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} @@ -1102,6 +1291,13 @@ packages: fastq@1.19.1: resolution: {integrity: sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==} + fd-slicer@1.1.0: + resolution: {integrity: sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==} + + figures@3.2.0: + resolution: {integrity: sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==} + engines: {node: '>=8'} + file-entry-cache@8.0.0: resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} engines: {node: '>=16.0.0'} @@ -1134,6 +1330,13 @@ packages: resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==} engines: {node: '>=14'} + forever-agent@0.6.1: + resolution: {integrity: sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==} + + form-data@2.3.3: + resolution: {integrity: sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==} + engines: {node: '>= 0.12'} + form-data@4.0.2: resolution: {integrity: sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w==} engines: {node: '>= 6'} @@ -1141,6 +1344,10 @@ packages: fraction.js@4.3.7: resolution: {integrity: sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==} + fs-extra@9.1.0: + resolution: {integrity: sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==} + engines: {node: '>=10'} + fs.realpath@1.0.0: resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} @@ -1160,6 +1367,16 @@ packages: resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} engines: {node: '>= 0.4'} + get-stream@5.2.0: + resolution: {integrity: sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==} + engines: {node: '>=8'} + + getos@3.2.1: + resolution: {integrity: sha512-U56CfOK17OKgTVqozZjUKNdkfEv6jk5WISBJ8SHoagjE6L69zOwl3Z+O8myjY9MEW3i2HPWQBt/LTbCgcC973Q==} + + getpass@0.1.7: + resolution: {integrity: sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==} + glob-parent@5.1.2: resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} engines: {node: '>= 6'} @@ -1176,6 +1393,10 @@ packages: resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} deprecated: Glob versions prior to v9 are no longer supported + global-dirs@3.0.1: + resolution: {integrity: sha512-NBcGGFbBA9s1VzD41QXDG+3++t9Mn5t1FpLdhESY6oKY4gYTFpX4wO3sqGUa0Srjtbfj3szX0RnemmrVRUdULA==} + engines: {node: '>=10'} + globals@14.0.0: resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==} engines: {node: '>=18'} @@ -1188,6 +1409,9 @@ packages: resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} engines: {node: '>= 0.4'} + graceful-fs@4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + graphemer@1.4.0: resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} @@ -1218,14 +1442,25 @@ packages: resolution: {integrity: sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==} engines: {node: '>= 14'} + http-signature@1.3.6: + resolution: {integrity: sha512-3adrsD6zqo4GsTqtO7FyrejHNv+NgiIfAfv68+jVlFmSr9OGy7zrxONceFRLKvnnZA5jbxQBX1u9PpB6Wi32Gw==} + engines: {node: '>=0.10'} + https-proxy-agent@7.0.6: resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==} engines: {node: '>= 14'} + human-signals@1.1.1: + resolution: {integrity: sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==} + engines: {node: '>=8.12.0'} + iconv-lite@0.6.3: resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} engines: {node: '>=0.10.0'} + ieee754@1.2.1: + resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} + ignore@5.3.2: resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} engines: {node: '>= 4'} @@ -1249,10 +1484,18 @@ packages: inherits@2.0.4: resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + ini@2.0.0: + resolution: {integrity: sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==} + engines: {node: '>=10'} + is-binary-path@2.1.0: resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} engines: {node: '>=8'} + is-ci@3.0.1: + resolution: {integrity: sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ==} + hasBin: true + is-core-module@2.16.1: resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==} engines: {node: '>= 0.4'} @@ -1269,16 +1512,38 @@ packages: resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} engines: {node: '>=0.10.0'} + is-installed-globally@0.4.0: + resolution: {integrity: sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ==} + engines: {node: '>=10'} + is-number@7.0.0: resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} engines: {node: '>=0.12.0'} + is-path-inside@3.0.3: + resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==} + engines: {node: '>=8'} + is-potential-custom-element-name@1.0.1: resolution: {integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==} + is-stream@2.0.1: + resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} + engines: {node: '>=8'} + + is-typedarray@1.0.0: + resolution: {integrity: sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==} + + is-unicode-supported@0.1.0: + resolution: {integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==} + engines: {node: '>=10'} + isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + isstream@0.1.2: + resolution: {integrity: sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==} + istanbul-lib-coverage@3.2.2: resolution: {integrity: sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==} engines: {node: '>=8'} @@ -1312,6 +1577,9 @@ packages: resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} hasBin: true + jsbn@0.1.1: + resolution: {integrity: sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==} + jsdom@24.1.3: resolution: {integrity: sha512-MyL55p3Ut3cXbeBEG7Hcv0mVM8pp8PBNWxRqchZnSfAiES1v1mRnMeFfaHWIPULpwsYfvO+ZmMZz5tGCnjzDUQ==} engines: {node: '>=18'} @@ -1327,12 +1595,29 @@ packages: json-schema-traverse@0.4.1: resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} + json-schema@0.4.0: + resolution: {integrity: sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==} + json-stable-stringify-without-jsonify@1.0.1: resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} + json-stringify-safe@5.0.1: + resolution: {integrity: sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==} + + jsonfile@6.1.0: + resolution: {integrity: sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==} + + jsprim@2.0.2: + resolution: {integrity: sha512-gqXddjPqQ6G40VdnI6T6yObEC+pDNvyP95wdQhkWkg7crHH3km5qP1FsOXEkzEQwnz6gz5qGTn1c2Y52wP3OyQ==} + engines: {'0': node >=0.6.0} + keyv@4.5.4: resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} + lazy-ass@1.6.0: + resolution: {integrity: sha512-cc8oEVoctTvsFZ/Oje/kGnHbpWHYBe8IAJe4C0QNc3t8uM/0Y8+erSz/7Y1ALuXTEZTMvxXwO6YbX1ey3ujiZw==} + engines: {node: '> 0.8'} + levn@0.4.1: resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} engines: {node: '>= 0.8.0'} @@ -1344,6 +1629,15 @@ packages: lines-and-columns@1.2.4: resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} + listr2@3.14.0: + resolution: {integrity: sha512-TyWI8G99GX9GjE54cJ+RrNMcIFBfwMPxc3XTFiAYGN4s10hWROGtOg7+O6u6LE3mNkyld7RSLE6nrKBvTfcs3g==} + engines: {node: '>=10.0.0'} + peerDependencies: + enquirer: '>= 2.3.0 < 3' + peerDependenciesMeta: + enquirer: + optional: true + locate-path@6.0.0: resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} engines: {node: '>=10'} @@ -1351,9 +1645,20 @@ packages: lodash.merge@4.6.2: resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} + lodash.once@4.1.1: + resolution: {integrity: sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==} + lodash@4.17.21: resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} + log-symbols@4.1.0: + resolution: {integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==} + engines: {node: '>=10'} + + log-update@4.0.0: + resolution: {integrity: sha512-9fkkDevMefjg0mmzWFBW8YkFP91OrizzkW3diF7CpG+S2EYdy4+TVfGwz1zeF8x7hCx1ovSPTOE9Ngib74qqUg==} + engines: {node: '>=10'} + loupe@3.1.3: resolution: {integrity: sha512-kkIp7XSkP78ZxJEsSxW3712C6teJVoeHHwgo9zJ380de7IYyJ2ISlxojcH2pC5OFLewESmnRi/+XCDIEEVyoug==} @@ -1378,6 +1683,9 @@ packages: resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} engines: {node: '>= 0.4'} + merge-stream@2.0.0: + resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} + merge2@1.4.1: resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} engines: {node: '>= 8'} @@ -1394,6 +1702,10 @@ packages: resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} engines: {node: '>= 0.6'} + mimic-fn@2.1.0: + resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} + engines: {node: '>=6'} + min-indent@1.0.1: resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==} engines: {node: '>=4'} @@ -1405,6 +1717,9 @@ packages: resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} engines: {node: '>=16 || 14 >=14.17'} + minimist@1.2.8: + resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} + minipass@7.1.2: resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} engines: {node: '>=16 || 14 >=14.17'} @@ -1434,6 +1749,10 @@ packages: resolution: {integrity: sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==} engines: {node: '>=0.10.0'} + npm-run-path@4.0.1: + resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==} + engines: {node: '>=8'} + nwsapi@2.2.18: resolution: {integrity: sha512-p1TRH/edngVEHVbwqWnxUViEmq5znDvyB+Sik5cmuLpGOIfDf/39zLiq3swPF8Vakqn+gvNiOQAZu8djYlQILA==} @@ -1445,13 +1764,24 @@ packages: resolution: {integrity: sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==} engines: {node: '>= 6'} + object-inspect@1.13.4: + resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==} + engines: {node: '>= 0.4'} + once@1.4.0: resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + onetime@5.1.2: + resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==} + engines: {node: '>=6'} + optionator@0.9.4: resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} engines: {node: '>= 0.8.0'} + ospath@1.2.2: + resolution: {integrity: sha512-o6E5qJV5zkAbIDNhGSIlyOhScKXgQrSRMilfph0clDfM0nEnBOlKlH4sWDmG95BW/CvwNz0vmm7dJVtU2KlMiA==} + p-limit@3.1.0: resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} engines: {node: '>=10'} @@ -1460,6 +1790,10 @@ packages: resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} engines: {node: '>=10'} + p-map@4.0.0: + resolution: {integrity: sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==} + engines: {node: '>=10'} + package-json-from-dist@1.0.1: resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} @@ -1496,6 +1830,12 @@ packages: resolution: {integrity: sha512-vE7JKRyES09KiunauX7nd2Q9/L7lhok4smP9RZTDeD4MVs72Dp2qNFVz39Nz5a0FVEW0BJR6C0DYrq6unoziZA==} engines: {node: '>= 14.16'} + pend@1.2.0: + resolution: {integrity: sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==} + + performance-now@2.1.0: + resolution: {integrity: sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==} + picocolors@1.1.1: resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} @@ -1560,20 +1900,38 @@ packages: resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} engines: {node: '>= 0.8.0'} + pretty-bytes@5.6.0: + resolution: {integrity: sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==} + engines: {node: '>=6'} + pretty-format@27.5.1: resolution: {integrity: sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + process@0.11.10: + resolution: {integrity: sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==} + engines: {node: '>= 0.6.0'} + + proxy-from-env@1.0.0: + resolution: {integrity: sha512-F2JHgJQ1iqwnHDcQjVBsq3n/uoaFL+iPW/eAeL7kVxy/2RrWaN4WroKjjvbsoRtv0ftelNyC01bjRhn/bhcf4A==} + proxy-from-env@1.1.0: resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} psl@1.15.0: resolution: {integrity: sha512-JZd3gMVBAVQkSs6HdNZo9Sdo0LNcQeMNP3CozBJb3JYC/QUYZTnKxP+f8oWRX4rHP5EurWxqAHTSwUCjlNKa1w==} + pump@3.0.2: + resolution: {integrity: sha512-tUPXtzlGM8FE3P0ZL6DVs/3P58k9nk8/jZeQCurTJylQA8qFYzHFfhBJkuqyE0FifOsQ0uKWekiZ5g8wtr28cw==} + punycode@2.3.1: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} + qs@6.10.4: + resolution: {integrity: sha512-OQiU+C+Ds5qiH91qh/mg0w+8nwQuLjM4F4M/PbmhDOoYehPh+Fb0bDjtR1sOvy7YKxvj28Y/M0PhP5uVX0kB+g==} + engines: {node: '>=0.6'} + querystringify@2.2.0: resolution: {integrity: sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==} @@ -1623,6 +1981,9 @@ packages: regenerator-runtime@0.14.1: resolution: {integrity: sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==} + request-progress@3.0.0: + resolution: {integrity: sha512-MnWzEHHaxHO2iWiQuHrUPBi/1WeBf5PkxQqNyNvLl9VAYSdXkP8tQ3pBSeCPD+yw0v0Aq1zosWLz0BdeXpWwZg==} + requires-port@1.0.0: resolution: {integrity: sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==} @@ -1635,10 +1996,17 @@ packages: engines: {node: '>= 0.4'} hasBin: true + restore-cursor@3.1.0: + resolution: {integrity: sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==} + engines: {node: '>=8'} + reusify@1.1.0: resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + rfdc@1.4.1: + resolution: {integrity: sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==} + rollup@4.35.0: resolution: {integrity: sha512-kg6oI4g+vc41vePJyO6dHt/yl0Rz3Thv0kJeVQ3D1kS3E5XSuKbPc29G4IpT/Kv1KQwgHVcN+HtyS+HYLNSvQg==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} @@ -1653,6 +2021,12 @@ packages: run-parallel@1.2.0: resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + rxjs@7.8.2: + resolution: {integrity: sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==} + + safe-buffer@5.2.1: + resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + safer-buffer@2.1.2: resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} @@ -1679,17 +2053,49 @@ packages: resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} engines: {node: '>=8'} + side-channel-list@1.0.0: + resolution: {integrity: sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==} + engines: {node: '>= 0.4'} + + side-channel-map@1.0.1: + resolution: {integrity: sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==} + engines: {node: '>= 0.4'} + + side-channel-weakmap@1.0.2: + resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==} + engines: {node: '>= 0.4'} + + side-channel@1.1.0: + resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==} + engines: {node: '>= 0.4'} + siginfo@2.0.0: resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} + signal-exit@3.0.7: + resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} + signal-exit@4.1.0: resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} engines: {node: '>=14'} + slice-ansi@3.0.0: + resolution: {integrity: sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==} + engines: {node: '>=8'} + + slice-ansi@4.0.0: + resolution: {integrity: sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==} + engines: {node: '>=10'} + source-map-js@1.2.1: resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} engines: {node: '>=0.10.0'} + sshpk@1.18.0: + resolution: {integrity: sha512-2p2KJZTSqQ/I3+HX42EpYOa2l3f8Erv8MWKsy2I9uf4wA7yFIkXRffYdsx86y6z4vHtV8u7g+pPlr8/4ouAxsQ==} + engines: {node: '>=0.10.0'} + hasBin: true + stackback@0.0.2: resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} @@ -1715,6 +2121,10 @@ packages: resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==} engines: {node: '>=12'} + strip-final-newline@2.0.0: + resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==} + engines: {node: '>=6'} + strip-indent@3.0.0: resolution: {integrity: sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==} engines: {node: '>=8'} @@ -1735,6 +2145,10 @@ packages: resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} engines: {node: '>=8'} + supports-color@8.1.1: + resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} + engines: {node: '>=10'} + supports-preserve-symlinks-flag@1.0.0: resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} engines: {node: '>= 0.4'} @@ -1758,6 +2172,12 @@ packages: thenify@3.3.1: resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==} + throttleit@1.0.1: + resolution: {integrity: sha512-vDZpf9Chs9mAdfY046mcPt8fg5QSZr37hEH4TXYBnDF+izxgrbRGUAAaBvIk/fJm9aOFCGFd1EsNg5AZCbnQCQ==} + + through@2.3.8: + resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==} + tinybench@2.9.0: resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} @@ -1776,6 +2196,10 @@ packages: resolution: {integrity: sha512-n1cw8k1k0x4pgA2+9XrOkFydTerNcJ1zWCO5Nn9scWHTD+5tp8dghT2x1uduQePZTZgd3Tupf+x9BxJjeJi77Q==} engines: {node: '>=14.0.0'} + tmp@0.2.3: + resolution: {integrity: sha512-nZD7m9iCPC5g0pYmcaxogYKggSfLsdxl8of3Q/oIbqCqLLIO9IAF0GWjX1z9NZRHPiXv8Wex4yDCaZsgEw0Y8w==} + engines: {node: '>=14.14'} + to-regex-range@5.0.1: resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} engines: {node: '>=8.0'} @@ -1800,13 +2224,26 @@ packages: ts-pattern@5.6.2: resolution: {integrity: sha512-d4IxJUXROL5NCa3amvMg6VQW2HVtZYmUTPfvVtO7zJWGYLJ+mry9v2OmYm+z67aniQoQ8/yFNadiEwtNS9qQiw==} + tslib@2.8.1: + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + + tunnel-agent@0.6.0: + resolution: {integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==} + turbo-stream@2.4.0: resolution: {integrity: sha512-FHncC10WpBd2eOmGwpmQsWLDoK4cqsA/UT/GqNoaKOQnT8uzhtCbg3EoUDMvqpOSAI0S26mr0rkjzbOO6S3v1g==} + tweetnacl@0.14.5: + resolution: {integrity: sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==} + type-check@0.4.0: resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} engines: {node: '>= 0.8.0'} + type-fest@0.21.3: + resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==} + engines: {node: '>=10'} + typescript-eslint@8.26.0: resolution: {integrity: sha512-PtVz9nAnuNJuAVeUFvwztjuUgSnJInODAUx47VDwWPXzd5vismPOtPtt83tzNXyOjVQbPRp786D6WFW/M2koIA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -1823,6 +2260,14 @@ packages: resolution: {integrity: sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==} engines: {node: '>= 4.0.0'} + universalify@2.0.1: + resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==} + engines: {node: '>= 10.0.0'} + + untildify@4.0.0: + resolution: {integrity: sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==} + engines: {node: '>=8'} + update-browserslist-db@1.1.3: resolution: {integrity: sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==} hasBin: true @@ -1838,6 +2283,14 @@ packages: util-deprecate@1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + uuid@8.3.2: + resolution: {integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==} + hasBin: true + + verror@1.10.0: + resolution: {integrity: sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==} + engines: {'0': node >=0.6.0} + vite-node@3.0.8: resolution: {integrity: sha512-6PhR4H9VGlcwXZ+KWCdMqbtG649xCPZqfI9j2PsK1FcXgEzro5bGHcVKFCTqPLaNKZES8Evqv4LwvZARsq5qlg==} engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} @@ -1945,6 +2398,10 @@ packages: resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} engines: {node: '>=0.10.0'} + wrap-ansi@6.2.0: + resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==} + engines: {node: '>=8'} + wrap-ansi@7.0.0: resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} engines: {node: '>=10'} @@ -1980,6 +2437,9 @@ packages: engines: {node: '>= 14'} hasBin: true + yauzl@2.10.0: + resolution: {integrity: sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==} + yocto-queue@0.1.0: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} @@ -2028,6 +2488,9 @@ snapshots: '@bcoe/v8-coverage@0.2.3': {} + '@colors/colors@1.5.0': + optional: true + '@csstools/color-helpers@5.0.2': {} '@csstools/css-calc@2.1.2(@csstools/css-parser-algorithms@3.0.4(@csstools/css-tokenizer@3.0.3))(@csstools/css-tokenizer@3.0.3)': @@ -2048,6 +2511,34 @@ snapshots: '@csstools/css-tokenizer@3.0.3': {} + '@cypress/request@2.88.12': + dependencies: + aws-sign2: 0.7.0 + aws4: 1.13.2 + caseless: 0.12.0 + combined-stream: 1.0.8 + extend: 3.0.2 + forever-agent: 0.6.1 + form-data: 2.3.3 + http-signature: 1.3.6 + is-typedarray: 1.0.0 + isstream: 0.1.2 + json-stringify-safe: 5.0.1 + mime-types: 2.1.35 + performance-now: 2.1.0 + qs: 6.10.4 + safe-buffer: 5.2.1 + tough-cookie: 4.1.4 + tunnel-agent: 0.6.0 + uuid: 8.3.2 + + '@cypress/xvfb@1.2.4(supports-color@8.1.1)': + dependencies: + debug: 3.2.7(supports-color@8.1.1) + lodash.once: 4.1.1 + transitivePeerDependencies: + - supports-color + '@esbuild/aix-ppc64@0.25.1': optional: true @@ -2205,7 +2696,7 @@ snapshots: '@eslint/config-array@0.19.2': dependencies: '@eslint/object-schema': 2.1.6 - debug: 4.4.0 + debug: 4.4.0(supports-color@8.1.1) minimatch: 3.1.2 transitivePeerDependencies: - supports-color @@ -2219,7 +2710,7 @@ snapshots: '@eslint/eslintrc@3.3.0': dependencies: ajv: 6.12.6 - debug: 4.4.0 + debug: 4.4.0(supports-color@8.1.1) espree: 10.3.0 globals: 14.0.0 ignore: 5.3.2 @@ -2443,6 +2934,8 @@ snapshots: '@types/json-schema@7.0.15': {} + '@types/node@16.18.126': {} + '@types/react-dom@19.0.4(@types/react@19.0.10)': dependencies: '@types/react': 19.0.10 @@ -2451,6 +2944,15 @@ snapshots: dependencies: csstype: 3.1.3 + '@types/sinonjs__fake-timers@8.1.1': {} + + '@types/sizzle@2.3.9': {} + + '@types/yauzl@2.10.3': + dependencies: + '@types/node': 16.18.126 + optional: true + '@typescript-eslint/eslint-plugin@8.26.0(@typescript-eslint/parser@8.26.0(eslint@9.22.0(jiti@1.21.7))(typescript@5.7.3))(eslint@9.22.0(jiti@1.21.7))(typescript@5.7.3)': dependencies: '@eslint-community/regexpp': 4.12.1 @@ -2474,7 +2976,7 @@ snapshots: '@typescript-eslint/types': 8.26.0 '@typescript-eslint/typescript-estree': 8.26.0(typescript@5.7.3) '@typescript-eslint/visitor-keys': 8.26.0 - debug: 4.4.0 + debug: 4.4.0(supports-color@8.1.1) eslint: 9.22.0(jiti@1.21.7) typescript: 5.7.3 transitivePeerDependencies: @@ -2489,7 +2991,7 @@ snapshots: dependencies: '@typescript-eslint/typescript-estree': 8.26.0(typescript@5.7.3) '@typescript-eslint/utils': 8.26.0(eslint@9.22.0(jiti@1.21.7))(typescript@5.7.3) - debug: 4.4.0 + debug: 4.4.0(supports-color@8.1.1) eslint: 9.22.0(jiti@1.21.7) ts-api-utils: 2.0.1(typescript@5.7.3) typescript: 5.7.3 @@ -2502,7 +3004,7 @@ snapshots: dependencies: '@typescript-eslint/types': 8.26.0 '@typescript-eslint/visitor-keys': 8.26.0 - debug: 4.4.0 + debug: 4.4.0(supports-color@8.1.1) fast-glob: 3.3.3 is-glob: 4.0.3 minimatch: 9.0.5 @@ -2539,7 +3041,7 @@ snapshots: dependencies: '@ampproject/remapping': 2.3.0 '@bcoe/v8-coverage': 0.2.3 - debug: 4.4.0 + debug: 4.4.0(supports-color@8.1.1) istanbul-lib-coverage: 3.2.2 istanbul-lib-report: 3.0.1 istanbul-lib-source-maps: 5.0.6 @@ -2602,6 +3104,11 @@ snapshots: agent-base@7.1.3: {} + aggregate-error@3.1.0: + dependencies: + clean-stack: 2.2.0 + indent-string: 4.0.0 + ajv@6.12.6: dependencies: fast-deep-equal: 3.1.3 @@ -2609,6 +3116,12 @@ snapshots: json-schema-traverse: 0.4.1 uri-js: 4.4.1 + ansi-colors@4.1.3: {} + + ansi-escapes@4.3.2: + dependencies: + type-fest: 0.21.3 + ansi-regex@5.0.1: {} ansi-regex@6.1.0: {} @@ -2628,6 +3141,8 @@ snapshots: normalize-path: 3.0.0 picomatch: 2.3.1 + arch@2.2.0: {} + arg@5.0.2: {} argparse@2.0.1: {} @@ -2636,10 +3151,22 @@ snapshots: dependencies: dequal: 2.0.3 + asn1@0.2.6: + dependencies: + safer-buffer: 2.1.2 + + assert-plus@1.0.0: {} + assertion-error@2.0.1: {} + astral-regex@2.0.0: {} + + async@3.2.6: {} + asynckit@0.4.0: {} + at-least-node@1.0.0: {} + autoprefixer@10.4.21(postcss@8.5.3): dependencies: browserslist: 4.24.4 @@ -2650,6 +3177,10 @@ snapshots: postcss: 8.5.3 postcss-value-parser: 4.2.0 + aws-sign2@0.7.0: {} + + aws4@1.13.2: {} + axios@1.8.2: dependencies: follow-redirects: 1.15.9 @@ -2660,10 +3191,20 @@ snapshots: balanced-match@1.0.2: {} + base64-js@1.5.1: {} + + bcrypt-pbkdf@1.0.2: + dependencies: + tweetnacl: 0.14.5 + binary-extensions@2.3.0: {} birecord@0.1.1: {} + blob-util@2.0.2: {} + + bluebird@3.7.2: {} + brace-expansion@1.1.11: dependencies: balanced-match: 1.0.2 @@ -2684,19 +3225,35 @@ snapshots: node-releases: 2.0.19 update-browserslist-db: 1.1.3(browserslist@4.24.4) + buffer-crc32@0.2.13: {} + + buffer@5.7.1: + dependencies: + base64-js: 1.5.1 + ieee754: 1.2.1 + cac@6.7.14: {} + cachedir@2.4.0: {} + call-bind-apply-helpers@1.0.2: dependencies: es-errors: 1.3.0 function-bind: 1.1.2 + call-bound@1.0.4: + dependencies: + call-bind-apply-helpers: 1.0.2 + get-intrinsic: 1.3.0 + callsites@3.1.0: {} camelcase-css@2.0.1: {} caniuse-lite@1.0.30001703: {} + caseless@0.12.0: {} + chai@5.2.0: dependencies: assertion-error: 2.0.1 @@ -2717,6 +3274,8 @@ snapshots: check-error@2.1.1: {} + check-more-types@2.24.0: {} + chokidar@3.6.0: dependencies: anymatch: 3.1.3 @@ -2729,24 +3288,51 @@ snapshots: optionalDependencies: fsevents: 2.3.3 + ci-info@3.9.0: {} + + clean-stack@2.2.0: {} + + cli-cursor@3.1.0: + dependencies: + restore-cursor: 3.1.0 + + cli-table3@0.6.5: + dependencies: + string-width: 4.2.3 + optionalDependencies: + '@colors/colors': 1.5.0 + + cli-truncate@2.1.0: + dependencies: + slice-ansi: 3.0.0 + string-width: 4.2.3 + color-convert@2.0.1: dependencies: color-name: 1.1.4 color-name@1.1.4: {} + colorette@2.0.20: {} + combined-stream@1.0.8: dependencies: delayed-stream: 1.0.0 commander@4.1.1: {} + commander@6.2.1: {} + + common-tags@1.8.2: {} + compare-versions@6.1.1: {} concat-map@0.0.1: {} cookie@1.0.2: {} + core-util-is@1.0.2: {} + cross-spawn@7.0.6: dependencies: path-key: 3.1.1 @@ -2764,14 +3350,74 @@ snapshots: csstype@3.1.3: {} + cypress@12.17.4: + dependencies: + '@cypress/request': 2.88.12 + '@cypress/xvfb': 1.2.4(supports-color@8.1.1) + '@types/node': 16.18.126 + '@types/sinonjs__fake-timers': 8.1.1 + '@types/sizzle': 2.3.9 + arch: 2.2.0 + blob-util: 2.0.2 + bluebird: 3.7.2 + buffer: 5.7.1 + cachedir: 2.4.0 + chalk: 4.1.2 + check-more-types: 2.24.0 + cli-cursor: 3.1.0 + cli-table3: 0.6.5 + commander: 6.2.1 + common-tags: 1.8.2 + dayjs: 1.11.13 + debug: 4.4.0(supports-color@8.1.1) + enquirer: 2.4.1 + eventemitter2: 6.4.7 + execa: 4.1.0 + executable: 4.1.1 + extract-zip: 2.0.1(supports-color@8.1.1) + figures: 3.2.0 + fs-extra: 9.1.0 + getos: 3.2.1 + is-ci: 3.0.1 + is-installed-globally: 0.4.0 + lazy-ass: 1.6.0 + listr2: 3.14.0(enquirer@2.4.1) + lodash: 4.17.21 + log-symbols: 4.1.0 + minimist: 1.2.8 + ospath: 1.2.2 + pretty-bytes: 5.6.0 + process: 0.11.10 + proxy-from-env: 1.0.0 + request-progress: 3.0.0 + semver: 7.7.1 + supports-color: 8.1.1 + tmp: 0.2.3 + untildify: 4.0.0 + yauzl: 2.10.0 + + dashdash@1.14.1: + dependencies: + assert-plus: 1.0.0 + data-urls@5.0.0: dependencies: whatwg-mimetype: 4.0.0 whatwg-url: 14.1.1 - debug@4.4.0: + dayjs@1.11.13: {} + + debug@3.2.7(supports-color@8.1.1): + dependencies: + ms: 2.1.3 + optionalDependencies: + supports-color: 8.1.1 + + debug@4.4.0(supports-color@8.1.1): dependencies: ms: 2.1.3 + optionalDependencies: + supports-color: 8.1.1 decimal.js@10.5.0: {} @@ -2799,12 +3445,26 @@ snapshots: eastasianwidth@0.2.0: {} + ecc-jsbn@0.1.2: + dependencies: + jsbn: 0.1.1 + safer-buffer: 2.1.2 + electron-to-chromium@1.5.114: {} emoji-regex@8.0.0: {} emoji-regex@9.2.2: {} + end-of-stream@1.4.4: + dependencies: + once: 1.4.0 + + enquirer@2.4.1: + dependencies: + ansi-colors: 4.1.3 + strip-ansi: 6.0.1 + entities@4.5.0: {} es-define-property@1.0.1: {} @@ -2854,6 +3514,8 @@ snapshots: escalade@3.2.0: {} + escape-string-regexp@1.0.5: {} + escape-string-regexp@4.0.0: {} eslint-plugin-react-dom@1.31.0(eslint@9.22.0(jiti@1.21.7))(typescript@5.7.3): @@ -2933,7 +3595,7 @@ snapshots: ajv: 6.12.6 chalk: 4.1.2 cross-spawn: 7.0.6 - debug: 4.4.0 + debug: 4.4.0(supports-color@8.1.1) escape-string-regexp: 4.0.0 eslint-scope: 8.3.0 eslint-visitor-keys: 4.2.0 @@ -2979,8 +3641,40 @@ snapshots: esutils@2.0.3: {} + eventemitter2@6.4.7: {} + + execa@4.1.0: + dependencies: + cross-spawn: 7.0.6 + get-stream: 5.2.0 + human-signals: 1.1.1 + is-stream: 2.0.1 + merge-stream: 2.0.0 + npm-run-path: 4.0.1 + onetime: 5.1.2 + signal-exit: 3.0.7 + strip-final-newline: 2.0.0 + + executable@4.1.1: + dependencies: + pify: 2.3.0 + expect-type@1.2.0: {} + extend@3.0.2: {} + + extract-zip@2.0.1(supports-color@8.1.1): + dependencies: + debug: 4.4.0(supports-color@8.1.1) + get-stream: 5.2.0 + yauzl: 2.10.0 + optionalDependencies: + '@types/yauzl': 2.10.3 + transitivePeerDependencies: + - supports-color + + extsprintf@1.3.0: {} + fast-deep-equal@3.1.3: {} fast-glob@3.3.3: @@ -2999,6 +3693,14 @@ snapshots: dependencies: reusify: 1.1.0 + fd-slicer@1.1.0: + dependencies: + pend: 1.2.0 + + figures@3.2.0: + dependencies: + escape-string-regexp: 1.0.5 + file-entry-cache@8.0.0: dependencies: flat-cache: 4.0.1 @@ -3026,6 +3728,14 @@ snapshots: cross-spawn: 7.0.6 signal-exit: 4.1.0 + forever-agent@0.6.1: {} + + form-data@2.3.3: + dependencies: + asynckit: 0.4.0 + combined-stream: 1.0.8 + mime-types: 2.1.35 + form-data@4.0.2: dependencies: asynckit: 0.4.0 @@ -3035,6 +3745,13 @@ snapshots: fraction.js@4.3.7: {} + fs-extra@9.1.0: + dependencies: + at-least-node: 1.0.0 + graceful-fs: 4.2.11 + jsonfile: 6.1.0 + universalify: 2.0.1 + fs.realpath@1.0.0: {} fsevents@2.3.3: @@ -3060,6 +3777,18 @@ snapshots: dunder-proto: 1.0.1 es-object-atoms: 1.1.1 + get-stream@5.2.0: + dependencies: + pump: 3.0.2 + + getos@3.2.1: + dependencies: + async: 3.2.6 + + getpass@0.1.7: + dependencies: + assert-plus: 1.0.0 + glob-parent@5.1.2: dependencies: is-glob: 4.0.3 @@ -3086,12 +3815,18 @@ snapshots: once: 1.4.0 path-is-absolute: 1.0.1 + global-dirs@3.0.1: + dependencies: + ini: 2.0.0 + globals@14.0.0: {} globals@15.15.0: {} gopd@1.2.0: {} + graceful-fs@4.2.11: {} + graphemer@1.4.0: {} has-flag@4.0.0: {} @@ -3115,21 +3850,31 @@ snapshots: http-proxy-agent@7.0.2: dependencies: agent-base: 7.1.3 - debug: 4.4.0 + debug: 4.4.0(supports-color@8.1.1) transitivePeerDependencies: - supports-color + http-signature@1.3.6: + dependencies: + assert-plus: 1.0.0 + jsprim: 2.0.2 + sshpk: 1.18.0 + https-proxy-agent@7.0.6: dependencies: agent-base: 7.1.3 - debug: 4.4.0 + debug: 4.4.0(supports-color@8.1.1) transitivePeerDependencies: - supports-color + human-signals@1.1.1: {} + iconv-lite@0.6.3: dependencies: safer-buffer: 2.1.2 + ieee754@1.2.1: {} + ignore@5.3.2: {} import-fresh@3.3.1: @@ -3148,10 +3893,16 @@ snapshots: inherits@2.0.4: {} + ini@2.0.0: {} + is-binary-path@2.1.0: dependencies: binary-extensions: 2.3.0 + is-ci@3.0.1: + dependencies: + ci-info: 3.9.0 + is-core-module@2.16.1: dependencies: hasown: 2.0.2 @@ -3164,12 +3915,27 @@ snapshots: dependencies: is-extglob: 2.1.1 + is-installed-globally@0.4.0: + dependencies: + global-dirs: 3.0.1 + is-path-inside: 3.0.3 + is-number@7.0.0: {} + is-path-inside@3.0.3: {} + is-potential-custom-element-name@1.0.1: {} + is-stream@2.0.1: {} + + is-typedarray@1.0.0: {} + + is-unicode-supported@0.1.0: {} + isexe@2.0.0: {} + isstream@0.1.2: {} + istanbul-lib-coverage@3.2.2: {} istanbul-lib-report@3.0.1: @@ -3181,7 +3947,7 @@ snapshots: istanbul-lib-source-maps@5.0.6: dependencies: '@jridgewell/trace-mapping': 0.3.25 - debug: 4.4.0 + debug: 4.4.0(supports-color@8.1.1) istanbul-lib-coverage: 3.2.2 transitivePeerDependencies: - supports-color @@ -3207,6 +3973,8 @@ snapshots: dependencies: argparse: 2.0.1 + jsbn@0.1.1: {} + jsdom@24.1.3: dependencies: cssstyle: 4.3.0 @@ -3239,12 +4007,31 @@ snapshots: json-schema-traverse@0.4.1: {} + json-schema@0.4.0: {} + json-stable-stringify-without-jsonify@1.0.1: {} + json-stringify-safe@5.0.1: {} + + jsonfile@6.1.0: + dependencies: + universalify: 2.0.1 + optionalDependencies: + graceful-fs: 4.2.11 + + jsprim@2.0.2: + dependencies: + assert-plus: 1.0.0 + extsprintf: 1.3.0 + json-schema: 0.4.0 + verror: 1.10.0 + keyv@4.5.4: dependencies: json-buffer: 3.0.1 + lazy-ass@1.6.0: {} + levn@0.4.1: dependencies: prelude-ls: 1.2.1 @@ -3254,14 +4041,41 @@ snapshots: lines-and-columns@1.2.4: {} + listr2@3.14.0(enquirer@2.4.1): + dependencies: + cli-truncate: 2.1.0 + colorette: 2.0.20 + log-update: 4.0.0 + p-map: 4.0.0 + rfdc: 1.4.1 + rxjs: 7.8.2 + through: 2.3.8 + wrap-ansi: 7.0.0 + optionalDependencies: + enquirer: 2.4.1 + locate-path@6.0.0: dependencies: p-locate: 5.0.0 lodash.merge@4.6.2: {} + lodash.once@4.1.1: {} + lodash@4.17.21: {} + log-symbols@4.1.0: + dependencies: + chalk: 4.1.2 + is-unicode-supported: 0.1.0 + + log-update@4.0.0: + dependencies: + ansi-escapes: 4.3.2 + cli-cursor: 3.1.0 + slice-ansi: 4.0.0 + wrap-ansi: 6.2.0 + loupe@3.1.3: {} lru-cache@10.4.3: {} @@ -3284,6 +4098,8 @@ snapshots: math-intrinsics@1.1.0: {} + merge-stream@2.0.0: {} + merge2@1.4.1: {} micromatch@4.0.8: @@ -3297,6 +4113,8 @@ snapshots: dependencies: mime-db: 1.52.0 + mimic-fn@2.1.0: {} + min-indent@1.0.1: {} minimatch@3.1.2: @@ -3307,6 +4125,8 @@ snapshots: dependencies: brace-expansion: 2.0.1 + minimist@1.2.8: {} + minipass@7.1.2: {} ms@2.1.3: {} @@ -3327,16 +4147,26 @@ snapshots: normalize-range@0.1.2: {} + npm-run-path@4.0.1: + dependencies: + path-key: 3.1.1 + nwsapi@2.2.18: {} object-assign@4.1.1: {} object-hash@3.0.0: {} + object-inspect@1.13.4: {} + once@1.4.0: dependencies: wrappy: 1.0.2 + onetime@5.1.2: + dependencies: + mimic-fn: 2.1.0 + optionator@0.9.4: dependencies: deep-is: 0.1.4 @@ -3346,6 +4176,8 @@ snapshots: type-check: 0.4.0 word-wrap: 1.2.5 + ospath@1.2.2: {} + p-limit@3.1.0: dependencies: yocto-queue: 0.1.0 @@ -3354,6 +4186,10 @@ snapshots: dependencies: p-limit: 3.1.0 + p-map@4.0.0: + dependencies: + aggregate-error: 3.1.0 + package-json-from-dist@1.0.1: {} parent-module@1.0.1: @@ -3381,6 +4217,10 @@ snapshots: pathval@2.0.0: {} + pend@1.2.0: {} + + performance-now@2.1.0: {} + picocolors@1.1.1: {} picomatch@2.3.1: {} @@ -3430,20 +4270,35 @@ snapshots: prelude-ls@1.2.1: {} + pretty-bytes@5.6.0: {} + pretty-format@27.5.1: dependencies: ansi-regex: 5.0.1 ansi-styles: 5.2.0 react-is: 17.0.2 + process@0.11.10: {} + + proxy-from-env@1.0.0: {} + proxy-from-env@1.1.0: {} psl@1.15.0: dependencies: punycode: 2.3.1 + pump@3.0.2: + dependencies: + end-of-stream: 1.4.4 + once: 1.4.0 + punycode@2.3.1: {} + qs@6.10.4: + dependencies: + side-channel: 1.1.0 + querystringify@2.2.0: {} queue-microtask@1.2.3: {} @@ -3488,6 +4343,10 @@ snapshots: regenerator-runtime@0.14.1: {} + request-progress@3.0.0: + dependencies: + throttleit: 1.0.1 + requires-port@1.0.0: {} resolve-from@4.0.0: {} @@ -3498,8 +4357,15 @@ snapshots: path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 + restore-cursor@3.1.0: + dependencies: + onetime: 5.1.2 + signal-exit: 3.0.7 + reusify@1.1.0: {} + rfdc@1.4.1: {} + rollup@4.35.0: dependencies: '@types/estree': 1.0.6 @@ -3533,6 +4399,12 @@ snapshots: dependencies: queue-microtask: 1.2.3 + rxjs@7.8.2: + dependencies: + tslib: 2.8.1 + + safe-buffer@5.2.1: {} + safer-buffer@2.1.2: {} saxes@6.0.0: @@ -3551,12 +4423,66 @@ snapshots: shebang-regex@3.0.0: {} + side-channel-list@1.0.0: + dependencies: + es-errors: 1.3.0 + object-inspect: 1.13.4 + + side-channel-map@1.0.1: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + object-inspect: 1.13.4 + + side-channel-weakmap@1.0.2: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + object-inspect: 1.13.4 + side-channel-map: 1.0.1 + + side-channel@1.1.0: + dependencies: + es-errors: 1.3.0 + object-inspect: 1.13.4 + side-channel-list: 1.0.0 + side-channel-map: 1.0.1 + side-channel-weakmap: 1.0.2 + siginfo@2.0.0: {} + signal-exit@3.0.7: {} + signal-exit@4.1.0: {} + slice-ansi@3.0.0: + dependencies: + ansi-styles: 4.3.0 + astral-regex: 2.0.0 + is-fullwidth-code-point: 3.0.0 + + slice-ansi@4.0.0: + dependencies: + ansi-styles: 4.3.0 + astral-regex: 2.0.0 + is-fullwidth-code-point: 3.0.0 + source-map-js@1.2.1: {} + sshpk@1.18.0: + dependencies: + asn1: 0.2.6 + assert-plus: 1.0.0 + bcrypt-pbkdf: 1.0.2 + dashdash: 1.14.1 + ecc-jsbn: 0.1.2 + getpass: 0.1.7 + jsbn: 0.1.1 + safer-buffer: 2.1.2 + tweetnacl: 0.14.5 + stackback@0.0.2: {} std-env@3.8.1: {} @@ -3583,6 +4509,8 @@ snapshots: dependencies: ansi-regex: 6.1.0 + strip-final-newline@2.0.0: {} + strip-indent@3.0.0: dependencies: min-indent: 1.0.1 @@ -3607,6 +4535,10 @@ snapshots: dependencies: has-flag: 4.0.0 + supports-color@8.1.1: + dependencies: + has-flag: 4.0.0 + supports-preserve-symlinks-flag@1.0.0: {} symbol-tree@3.2.4: {} @@ -3652,6 +4584,10 @@ snapshots: dependencies: any-promise: 1.3.0 + throttleit@1.0.1: {} + + through@2.3.8: {} + tinybench@2.9.0: {} tinyexec@0.3.2: {} @@ -3662,6 +4598,8 @@ snapshots: tinyspy@3.0.2: {} + tmp@0.2.3: {} + to-regex-range@5.0.1: dependencies: is-number: 7.0.0 @@ -3685,12 +4623,22 @@ snapshots: ts-pattern@5.6.2: {} + tslib@2.8.1: {} + + tunnel-agent@0.6.0: + dependencies: + safe-buffer: 5.2.1 + turbo-stream@2.4.0: {} + tweetnacl@0.14.5: {} + type-check@0.4.0: dependencies: prelude-ls: 1.2.1 + type-fest@0.21.3: {} + typescript-eslint@8.26.0(eslint@9.22.0(jiti@1.21.7))(typescript@5.7.3): dependencies: '@typescript-eslint/eslint-plugin': 8.26.0(@typescript-eslint/parser@8.26.0(eslint@9.22.0(jiti@1.21.7))(typescript@5.7.3))(eslint@9.22.0(jiti@1.21.7))(typescript@5.7.3) @@ -3705,6 +4653,10 @@ snapshots: universalify@0.2.0: {} + universalify@2.0.1: {} + + untildify@4.0.0: {} + update-browserslist-db@1.1.3(browserslist@4.24.4): dependencies: browserslist: 4.24.4 @@ -3722,10 +4674,18 @@ snapshots: util-deprecate@1.0.2: {} + uuid@8.3.2: {} + + verror@1.10.0: + dependencies: + assert-plus: 1.0.0 + core-util-is: 1.0.2 + extsprintf: 1.3.0 + vite-node@3.0.8(jiti@1.21.7)(yaml@2.7.0): dependencies: cac: 6.7.14 - debug: 4.4.0 + debug: 4.4.0(supports-color@8.1.1) es-module-lexer: 1.6.0 pathe: 2.0.3 vite: 6.2.1(jiti@1.21.7)(yaml@2.7.0) @@ -3763,7 +4723,7 @@ snapshots: '@vitest/spy': 3.0.8 '@vitest/utils': 3.0.8 chai: 5.2.0 - debug: 4.4.0 + debug: 4.4.0(supports-color@8.1.1) expect-type: 1.2.0 magic-string: 0.30.17 pathe: 2.0.3 @@ -3819,6 +4779,12 @@ snapshots: word-wrap@1.2.5: {} + wrap-ansi@6.2.0: + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi@7.0.0: dependencies: ansi-styles: 4.3.0 @@ -3841,4 +4807,9 @@ snapshots: yaml@2.7.0: {} + yauzl@2.10.0: + dependencies: + buffer-crc32: 0.2.13 + fd-slicer: 1.1.0 + yocto-queue@0.1.0: {} From 30619a25fe88bff356f9583f1bef0205ce0dcd02 Mon Sep 17 00:00:00 2001 From: Marios Tsigkas Date: Wed, 12 Mar 2025 16:33:03 +0200 Subject: [PATCH 21/96] Update ESLint config for Cypress support --- cypress/e2e/breeds.spec.ts | 1 - cypress/e2e/home.spec.ts | 3 --- eslint.config.js | 2 +- tsconfig.cypress.json | 15 +++++++++++++++ 4 files changed, 16 insertions(+), 5 deletions(-) create mode 100644 tsconfig.cypress.json diff --git a/cypress/e2e/breeds.spec.ts b/cypress/e2e/breeds.spec.ts index c8c4a77d..2e47292e 100644 --- a/cypress/e2e/breeds.spec.ts +++ b/cypress/e2e/breeds.spec.ts @@ -11,7 +11,6 @@ describe('Breeds Page', () => { cy.get('ul li').its('length').should('be.gt', 0) }) - // New test: clicking on a breed navigates to breed detail view it('navigates to breed detail on breed click', () => { cy.get('ul li').first().click(); cy.url().should('include', '/breed-detail/'); diff --git a/cypress/e2e/home.spec.ts b/cypress/e2e/home.spec.ts index b680d3a9..f5a03247 100644 --- a/cypress/e2e/home.spec.ts +++ b/cypress/e2e/home.spec.ts @@ -8,13 +8,10 @@ describe('Home Page', () => { }); it('loads images and shows the "Load New" button', () => { - // Check that at least one image is rendered cy.get('img').should('have.length.greaterThan', 0); - // Check for the existence of the load button cy.get('button').contains('Load New').should('exist'); }); - // New test: clicking on an image navigates to image detail view it('navigates to image detail on image click', () => { cy.get('img').first().click(); cy.url().should('include', '/image/'); diff --git a/eslint.config.js b/eslint.config.js index e82f2683..34a46155 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -20,7 +20,7 @@ export default tseslint.config( ecmaVersion: 2020, globals: globals.browser, parserOptions: { - project: ['./tsconfig.node.json', './tsconfig.app.json'], + project: ['./tsconfig.node.json', './tsconfig.app.json', './tsconfig.cypress.json'], tsconfigRootDir: import.meta.dirname, }, }, diff --git a/tsconfig.cypress.json b/tsconfig.cypress.json new file mode 100644 index 00000000..872be564 --- /dev/null +++ b/tsconfig.cypress.json @@ -0,0 +1,15 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "types": [ + "cypress" + ], + "strict": true, + "strictNullChecks": true, + "isolatedModules": false + }, + "include": [ + "cypress/**/*.ts", + "cypress/**/*.tsx" + ] +} \ No newline at end of file From abca2dc43abca0c3496f7edba9aafbe56705d1be Mon Sep 17 00:00:00 2001 From: Marios Tsigkas Date: Wed, 12 Mar 2025 16:49:02 +0200 Subject: [PATCH 22/96] Rename "Load New" button to "Load More" and update image fetching logic to append new images --- cypress/e2e/home.spec.ts | 4 ++-- src/hooks/useFetchedImages.ts | 6 +++--- src/views/Home.tsx | 6 ++++-- src/views/ImageView.tsx | 2 ++ 4 files changed, 11 insertions(+), 7 deletions(-) diff --git a/cypress/e2e/home.spec.ts b/cypress/e2e/home.spec.ts index f5a03247..01df2b43 100644 --- a/cypress/e2e/home.spec.ts +++ b/cypress/e2e/home.spec.ts @@ -7,9 +7,9 @@ describe('Home Page', () => { cy.get('h1').contains('Random Cats').should('exist'); }); - it('loads images and shows the "Load New" button', () => { + it('loads images and shows the "Load More" button', () => { cy.get('img').should('have.length.greaterThan', 0); - cy.get('button').contains('Load New').should('exist'); + cy.get('button').contains('Load More').should('exist'); }); it('navigates to image detail on image click', () => { diff --git a/src/hooks/useFetchedImages.ts b/src/hooks/useFetchedImages.ts index af1cbab9..313e9f02 100644 --- a/src/hooks/useFetchedImages.ts +++ b/src/hooks/useFetchedImages.ts @@ -11,13 +11,13 @@ const useFetchedImages = () => { const [isLoading, setIsLoading] = useState(false) const [error, setError] = useState(null) - const fetchImages = useCallback(async () => { + const fetchImages = useCallback(async (reset = true) => { if (isLoading) return setIsLoading(true) setError(null) try { - const data = await getRandomImages(10) - setImages(data) + const newImages = await getRandomImages(10) + setImages(prev => reset ? newImages : [...prev, ...newImages]) } catch (err) { console.error(err) setError('Failed to fetch images') diff --git a/src/views/Home.tsx b/src/views/Home.tsx index 9592a2c3..2fa5bba9 100644 --- a/src/views/Home.tsx +++ b/src/views/Home.tsx @@ -8,6 +8,8 @@ function Home(): JSX.Element { useEffect(() => { if (isLoading) return void fetchImages() + // we only want to fetch new images when the component mounts + // eslint-disable-next-line react-hooks/exhaustive-deps }, []) return ( @@ -19,10 +21,10 @@ function Home(): JSX.Element {
    }
    diff --git a/src/views/ImageView.tsx b/src/views/ImageView.tsx index 653c2bbb..7baefe19 100644 --- a/src/views/ImageView.tsx +++ b/src/views/ImageView.tsx @@ -52,6 +52,8 @@ function ImageView(): JSX.Element { await fetchImageFromApi(imageId) } setIsLoading(false) + // this sets selectedImage, so it cannot rely on this + // eslint-disable-next-line react-hooks/exhaustive-deps }, [fetchImageFromApi, fetchImageFromState, imageId]) useEffect(() => { From f03c86ae2d8d861c55cbfc77cb0df285ddf4bb7d Mon Sep 17 00:00:00 2001 From: Marios Tsigkas Date: Wed, 12 Mar 2025 16:53:15 +0200 Subject: [PATCH 23/96] Reorder loading and error messages in Home component for improved user experience --- src/views/Home.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/views/Home.tsx b/src/views/Home.tsx index 2fa5bba9..514ef9af 100644 --- a/src/views/Home.tsx +++ b/src/views/Home.tsx @@ -15,9 +15,7 @@ function Home(): JSX.Element { return (

    Random Cats

    - {isLoading &&

    Loading...

    } - {error &&

    {error}

    } - {!isLoading && images.length &&
    + {images.length &&
    } + {isLoading &&

    Loading...

    } + {error &&

    {error}

    }
    ) } From 2ec6f46454fb54e5f75dc5a9560202691026053a Mon Sep 17 00:00:00 2001 From: Marios Tsigkas Date: Wed, 12 Mar 2025 17:09:22 +0200 Subject: [PATCH 24/96] Refactor Cypress configuration: migrate from cypress.config.js to cypress.config.ts and update tsconfig files for improved module resolution --- cypress.config.js | 7 ------- cypress.config.ts | 9 +++++++++ tsconfig.app.json | 1 - tsconfig.node.json | 4 ++-- 4 files changed, 11 insertions(+), 10 deletions(-) delete mode 100644 cypress.config.js create mode 100644 cypress.config.ts diff --git a/cypress.config.js b/cypress.config.js deleted file mode 100644 index 0be30a76..00000000 --- a/cypress.config.js +++ /dev/null @@ -1,7 +0,0 @@ -export default { - e2e: { - baseUrl: 'http://localhost:5173', - specPattern: 'cypress/e2e/**/*.{js,jsx,ts,tsx}', - supportFile: false, - }, -}; diff --git a/cypress.config.ts b/cypress.config.ts new file mode 100644 index 00000000..3d64405e --- /dev/null +++ b/cypress.config.ts @@ -0,0 +1,9 @@ +import { defineConfig } from 'cypress' + +export default defineConfig({ + e2e: { + baseUrl: 'http://localhost:5173', + specPattern: 'cypress/e2e/**/*.{js,jsx,ts,tsx}', + supportFile: false, + }, +}) diff --git a/tsconfig.app.json b/tsconfig.app.json index 492ac615..68a079ef 100644 --- a/tsconfig.app.json +++ b/tsconfig.app.json @@ -10,7 +10,6 @@ ], "module": "ESNext", "skipLibCheck": true, - /* Bundler mode */ "moduleResolution": "bundler", "allowImportingTsExtensions": true, "isolatedModules": true, diff --git a/tsconfig.node.json b/tsconfig.node.json index 616f384e..8abb67ff 100644 --- a/tsconfig.node.json +++ b/tsconfig.node.json @@ -7,7 +7,6 @@ ], "module": "ESNext", "skipLibCheck": true, - /* Bundler mode */ "moduleResolution": "bundler", "allowImportingTsExtensions": true, "isolatedModules": true, @@ -22,6 +21,7 @@ "noUncheckedSideEffectImports": true }, "include": [ - "vite.config.ts" + "vite.config.ts", + "cypress.config.ts" ] } \ No newline at end of file From 8ef1b5a4b3ff93bbc0afb887bda4d0980d673438 Mon Sep 17 00:00:00 2001 From: Marios Tsigkas Date: Wed, 12 Mar 2025 17:18:32 +0200 Subject: [PATCH 25/96] Update README.md with setup instructions, testing guidelines, and tech stack details --- README.md | 55 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/README.md b/README.md index 91d4d5b9..dd30bbbc 100644 --- a/README.md +++ b/README.md @@ -19,3 +19,58 @@ We give you a lot of freedom in technologies and ways of doing things. We only i Once you have built your app, share your code in the mean suits you best Good luck, potential colleague! + +# Platform Cat Api React Solution + +## Prerequisites +- nvm (Node Version Manager) or Node v22 + +## Setup + +1. Clone the repository: +```bash +git clone https://github.com/mariosh346/platform-catApi-react.git +cd platform-catApi-react +``` + +2. Install Node.js using nvm: +```bash +nvm install 22 +nvm use 22 +``` + +3. Install pnpm: +```bash +npm install -g pnpm +``` + +4. Install dependencies using pnpm: +```bash +pnpm install +``` + +## Running the Application + +- Start the development server: +```bash +pnpm dev +``` + +- Build for production: +```bash +pnpm build +``` + +## Testing + +Run Cypress tests: +```bash +pnpm cypress +``` + +## Tech Stack + +- React +- TypeScript +- Vite +- Cypress From 38c098bb80ca3feb2a6ef504e488df3d902ed041 Mon Sep 17 00:00:00 2001 From: Marios Tsigkas Date: Wed, 12 Mar 2025 17:39:37 +0200 Subject: [PATCH 26/96] Add deployment instructions and update configuration for GitHub Pages --- README.md | 8 ++ package.json | 8 +- pnpm-lock.yaml | 199 +++++++++++++++++++++++++++++++++++++++++++++++++ vite.config.ts | 1 + 4 files changed, 214 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index dd30bbbc..0708e6dc 100644 --- a/README.md +++ b/README.md @@ -68,6 +68,14 @@ Run Cypress tests: pnpm cypress ``` +## Deployment + +To deploy the project to GitHub Pages, run the following command: + +```sh +pnpm deploy +``` + ## Tech Stack - React diff --git a/package.json b/package.json index a9dcc574..c8a192a8 100644 --- a/package.json +++ b/package.json @@ -2,6 +2,7 @@ "name": "catapi-react", "private": true, "version": "0.0.0", + "homepage": "https://mariosh346.github.io/platform-catApi-react/", "type": "module", "scripts": { "dev": "vite", @@ -11,7 +12,9 @@ "test": "vitest", "coverage": "vitest run --coverage", "cypress:open": "cypress open", - "cypress:run": "cypress run" + "cypress:run": "cypress run", + "predeploy": "pnpm build", + "deploy": "gh-pages -d dist" }, "dependencies": { "axios": "^1.8.2", @@ -41,6 +44,7 @@ "typescript": "~5.7.2", "typescript-eslint": "^8.24.1", "vite": "^6.2.1", - "vitest": "^3.0.8" + "vitest": "^3.0.8", + "gh-pages": "^5.0.0" } } \ No newline at end of file diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 582335ce..b88527aa 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -63,6 +63,9 @@ importers: eslint-plugin-react-x: specifier: ^1.31.0 version: 1.31.0(eslint@9.22.0(jiti@1.21.7))(ts-api-utils@2.0.1(typescript@5.7.3))(typescript@5.7.3) + gh-pages: + specifier: ^5.0.0 + version: 5.0.0 globals: specifier: ^15.15.0 version: 15.15.0 @@ -824,6 +827,14 @@ packages: aria-query@5.3.0: resolution: {integrity: sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==} + array-union@1.0.2: + resolution: {integrity: sha512-Dxr6QJj/RdU/hCaBjOfxW+q6lyuVE6JFWIrAUpuOOhoJJoQ99cUn3igRaHVB5P9WrgFVN0FfArM3x0cueOU8ng==} + engines: {node: '>=0.10.0'} + + array-uniq@1.0.3: + resolution: {integrity: sha512-MNha4BWQ6JbwhFhj03YK552f7cb3AzoE8SzeljgChvL1dl3IcvggXVz1DilzySZkCja+CXuZbdW7yATchWn8/Q==} + engines: {node: '>=0.10.0'} + asn1@0.2.6: resolution: {integrity: sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==} @@ -996,6 +1007,9 @@ packages: resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} engines: {node: '>= 0.8'} + commander@2.20.3: + resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} + commander@4.1.1: resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} engines: {node: '>= 6'} @@ -1008,6 +1022,9 @@ packages: resolution: {integrity: sha512-gk/Z852D2Wtb//0I+kRFNKKE9dIIVirjoqPoA1wJU+XePVXZfGeBpk45+A1rKO4Q43prqWBNY/MiIeRLbPWUaA==} engines: {node: '>=4.0.0'} + commondir@1.0.1: + resolution: {integrity: sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==} + compare-versions@6.1.1: resolution: {integrity: sha512-4hm4VPpIecmlg59CHXnRDnqGplJFrbLG4aFEl5vl6cK1u76ws3LLvX7ikFnTDl5vo39sjWD6AaDPYodJp/NNHg==} @@ -1116,6 +1133,9 @@ packages: electron-to-chromium@1.5.114: resolution: {integrity: sha512-DFptFef3iktoKlFQK/afbo274/XNWD00Am0xa7M8FZUepHlHT8PEuiNBoRfFHbH1okqN58AlhbJ4QTkcnXorjA==} + email-addresses@5.0.0: + resolution: {integrity: sha512-4OIPYlA6JXqtVn8zpHpGiI7vE6EQOAg16aGnDMIAlZVinnoZ8208tW1hAbjWydgN/4PLTT9q+O1K6AH/vALJGw==} + emoji-regex@8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} @@ -1302,10 +1322,26 @@ packages: resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} engines: {node: '>=16.0.0'} + filename-reserved-regex@2.0.0: + resolution: {integrity: sha512-lc1bnsSr4L4Bdif8Xb/qrtokGbq5zlsms/CYH8PP+WtCkGNF65DPiQY8vG3SakEdRn8Dlnm+gW/qWKKjS5sZzQ==} + engines: {node: '>=4'} + + filenamify@4.3.0: + resolution: {integrity: sha512-hcFKyUG57yWGAzu1CMt/dPzYZuv+jAJUT85bL8mrXvNe6hWj6yEHEc4EdcgiA6Z3oi1/9wXJdZPXF2dZNgwgOg==} + engines: {node: '>=8'} + fill-range@7.1.1: resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} engines: {node: '>=8'} + find-cache-dir@3.3.2: + resolution: {integrity: sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==} + engines: {node: '>=8'} + + find-up@4.1.0: + resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==} + engines: {node: '>=8'} + find-up@5.0.0: resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} engines: {node: '>=10'} @@ -1344,6 +1380,10 @@ packages: fraction.js@4.3.7: resolution: {integrity: sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==} + fs-extra@8.1.0: + resolution: {integrity: sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==} + engines: {node: '>=6 <7 || >=8'} + fs-extra@9.1.0: resolution: {integrity: sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==} engines: {node: '>=10'} @@ -1377,6 +1417,11 @@ packages: getpass@0.1.7: resolution: {integrity: sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==} + gh-pages@5.0.0: + resolution: {integrity: sha512-Nqp1SjkPIB94Xw/3yYNTUL+G2dxlhjvv1zeN/4kMC1jfViTEqhtVz/Ba1zSXHuvXCN9ADNS1dN4r5/J/nZWEQQ==} + engines: {node: '>=10'} + hasBin: true + glob-parent@5.1.2: resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} engines: {node: '>= 6'} @@ -1405,6 +1450,10 @@ packages: resolution: {integrity: sha512-7ACyT3wmyp3I61S4fG682L0VA2RGD9otkqGJIwNUMF1SWUombIIk+af1unuDYgMm082aHYwD+mzJvv9Iu8dsgg==} engines: {node: '>=18'} + globby@6.1.0: + resolution: {integrity: sha512-KVbFv2TQtbzCoxAnfD6JcHZTYCzyliEaaeM/gH8qQdkKr5s0OP9scEgvdcngyk7AVdY6YVW/TJHd+lQ/Df3Daw==} + engines: {node: '>=0.10.0'} + gopd@1.2.0: resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} engines: {node: '>= 0.4'} @@ -1604,6 +1653,9 @@ packages: json-stringify-safe@5.0.1: resolution: {integrity: sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==} + jsonfile@4.0.0: + resolution: {integrity: sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==} + jsonfile@6.1.0: resolution: {integrity: sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==} @@ -1638,6 +1690,10 @@ packages: enquirer: optional: true + locate-path@5.0.0: + resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==} + engines: {node: '>=8'} + locate-path@6.0.0: resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} engines: {node: '>=10'} @@ -1675,6 +1731,10 @@ packages: magicast@0.3.5: resolution: {integrity: sha512-L0WhttDl+2BOsybvEOLK7fW3UA0OQ0IQ2d6Zl2x/a6vVRs3bAY0ECOSHHeL5jD+SbOpOCUEi0y1DgHEn9Qn1AQ==} + make-dir@3.1.0: + resolution: {integrity: sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==} + engines: {node: '>=8'} + make-dir@4.0.0: resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==} engines: {node: '>=10'} @@ -1782,10 +1842,18 @@ packages: ospath@1.2.2: resolution: {integrity: sha512-o6E5qJV5zkAbIDNhGSIlyOhScKXgQrSRMilfph0clDfM0nEnBOlKlH4sWDmG95BW/CvwNz0vmm7dJVtU2KlMiA==} + p-limit@2.3.0: + resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==} + engines: {node: '>=6'} + p-limit@3.1.0: resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} engines: {node: '>=10'} + p-locate@4.1.0: + resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==} + engines: {node: '>=8'} + p-locate@5.0.0: resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} engines: {node: '>=10'} @@ -1794,6 +1862,10 @@ packages: resolution: {integrity: sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==} engines: {node: '>=10'} + p-try@2.2.0: + resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} + engines: {node: '>=6'} + package-json-from-dist@1.0.1: resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} @@ -1851,10 +1923,22 @@ packages: resolution: {integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==} engines: {node: '>=0.10.0'} + pinkie-promise@2.0.1: + resolution: {integrity: sha512-0Gni6D4UcLTbv9c57DfxDGdr41XfgUjqWZu492f0cIGr16zDU06BWP/RAEvOuo7CQ0CNjHaLlM59YJJFm3NWlw==} + engines: {node: '>=0.10.0'} + + pinkie@2.0.4: + resolution: {integrity: sha512-MnUuEycAemtSaeFSjXKW/aroV7akBbY+Sv+RkyqFjgAe73F+MR0TBWKBRDkmfWq/HiFmdavfZ1G7h4SPZXaCSg==} + engines: {node: '>=0.10.0'} + pirates@4.0.6: resolution: {integrity: sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==} engines: {node: '>= 6'} + pkg-dir@4.2.0: + resolution: {integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==} + engines: {node: '>=8'} + postcss-import@15.1.0: resolution: {integrity: sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==} engines: {node: '>=14.0.0'} @@ -2037,6 +2121,10 @@ packages: scheduler@0.25.0: resolution: {integrity: sha512-xFVuu11jh+xcO7JOAGJNOXld8/TcEHK/4CituBUeUb5hqxJLj9YuemAEuvm9gQ/+pgXYfbQuqAkiYu+u7YEsNA==} + semver@6.3.1: + resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} + hasBin: true + semver@7.7.1: resolution: {integrity: sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==} engines: {node: '>=10'} @@ -2136,6 +2224,10 @@ packages: strip-literal@2.1.1: resolution: {integrity: sha512-631UJ6O00eNGfMiWG78ck80dfBab8X6IVFB51jZK5Icd7XAs60Z5y7QdSd/wGIklnWvRbUNloVzhOKKmutxQ6Q==} + strip-outer@1.0.1: + resolution: {integrity: sha512-k55yxKHwaXnpYGsOzg4Vl8+tDrWylxDEpknGjhTiZB8dFRU5rTo9CAzeycivxV3s+zlTKwrs6WxMxR95n26kwg==} + engines: {node: '>=0.10.0'} + sucrase@3.35.0: resolution: {integrity: sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==} engines: {node: '>=16 || 14 >=14.17'} @@ -2212,6 +2304,10 @@ packages: resolution: {integrity: sha512-tk2G5R2KRwBd+ZN0zaEXpmzdKyOYksXwywulIX95MBODjSzMIuQnQ3m8JxgbhnL1LeVo7lqQKsYa1O3Htl7K5g==} engines: {node: '>=18'} + trim-repeated@1.0.0: + resolution: {integrity: sha512-pkonvlKk8/ZuR0D5tLW8ljt5I8kmxp2XKymhepUeOdCEfKpZaktSArkLHZt76OB1ZvO9bssUsDty4SWhLvZpLg==} + engines: {node: '>=0.10.0'} + ts-api-utils@2.0.1: resolution: {integrity: sha512-dnlgjFSVetynI8nzgJ+qF62efpglpWRk8isUEWZGWlJYySCTD6aKvbUDu+zbPeDakk3bg5H4XpitHukgfL1m9w==} engines: {node: '>=18.12'} @@ -2256,6 +2352,10 @@ packages: engines: {node: '>=14.17'} hasBin: true + universalify@0.1.2: + resolution: {integrity: sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==} + engines: {node: '>= 4.0.0'} + universalify@0.2.0: resolution: {integrity: sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==} engines: {node: '>= 4.0.0'} @@ -3151,6 +3251,12 @@ snapshots: dependencies: dequal: 2.0.3 + array-union@1.0.2: + dependencies: + array-uniq: 1.0.3 + + array-uniq@1.0.3: {} + asn1@0.2.6: dependencies: safer-buffer: 2.1.2 @@ -3319,12 +3425,16 @@ snapshots: dependencies: delayed-stream: 1.0.0 + commander@2.20.3: {} + commander@4.1.1: {} commander@6.2.1: {} common-tags@1.8.2: {} + commondir@1.0.1: {} + compare-versions@6.1.1: {} concat-map@0.0.1: {} @@ -3452,6 +3562,8 @@ snapshots: electron-to-chromium@1.5.114: {} + email-addresses@5.0.0: {} + emoji-regex@8.0.0: {} emoji-regex@9.2.2: {} @@ -3705,10 +3817,29 @@ snapshots: dependencies: flat-cache: 4.0.1 + filename-reserved-regex@2.0.0: {} + + filenamify@4.3.0: + dependencies: + filename-reserved-regex: 2.0.0 + strip-outer: 1.0.1 + trim-repeated: 1.0.0 + fill-range@7.1.1: dependencies: to-regex-range: 5.0.1 + find-cache-dir@3.3.2: + dependencies: + commondir: 1.0.1 + make-dir: 3.1.0 + pkg-dir: 4.2.0 + + find-up@4.1.0: + dependencies: + locate-path: 5.0.0 + path-exists: 4.0.0 + find-up@5.0.0: dependencies: locate-path: 6.0.0 @@ -3745,6 +3876,12 @@ snapshots: fraction.js@4.3.7: {} + fs-extra@8.1.0: + dependencies: + graceful-fs: 4.2.11 + jsonfile: 4.0.0 + universalify: 0.1.2 + fs-extra@9.1.0: dependencies: at-least-node: 1.0.0 @@ -3789,6 +3926,16 @@ snapshots: dependencies: assert-plus: 1.0.0 + gh-pages@5.0.0: + dependencies: + async: 3.2.6 + commander: 2.20.3 + email-addresses: 5.0.0 + filenamify: 4.3.0 + find-cache-dir: 3.3.2 + fs-extra: 8.1.0 + globby: 6.1.0 + glob-parent@5.1.2: dependencies: is-glob: 4.0.3 @@ -3823,6 +3970,14 @@ snapshots: globals@15.15.0: {} + globby@6.1.0: + dependencies: + array-union: 1.0.2 + glob: 7.2.3 + object-assign: 4.1.1 + pify: 2.3.0 + pinkie-promise: 2.0.1 + gopd@1.2.0: {} graceful-fs@4.2.11: {} @@ -4013,6 +4168,10 @@ snapshots: json-stringify-safe@5.0.1: {} + jsonfile@4.0.0: + optionalDependencies: + graceful-fs: 4.2.11 + jsonfile@6.1.0: dependencies: universalify: 2.0.1 @@ -4054,6 +4213,10 @@ snapshots: optionalDependencies: enquirer: 2.4.1 + locate-path@5.0.0: + dependencies: + p-locate: 4.1.0 + locate-path@6.0.0: dependencies: p-locate: 5.0.0 @@ -4092,6 +4255,10 @@ snapshots: '@babel/types': 7.26.9 source-map-js: 1.2.1 + make-dir@3.1.0: + dependencies: + semver: 6.3.1 + make-dir@4.0.0: dependencies: semver: 7.7.1 @@ -4178,10 +4345,18 @@ snapshots: ospath@1.2.2: {} + p-limit@2.3.0: + dependencies: + p-try: 2.2.0 + p-limit@3.1.0: dependencies: yocto-queue: 0.1.0 + p-locate@4.1.0: + dependencies: + p-limit: 2.3.0 + p-locate@5.0.0: dependencies: p-limit: 3.1.0 @@ -4190,6 +4365,8 @@ snapshots: dependencies: aggregate-error: 3.1.0 + p-try@2.2.0: {} + package-json-from-dist@1.0.1: {} parent-module@1.0.1: @@ -4229,8 +4406,18 @@ snapshots: pify@2.3.0: {} + pinkie-promise@2.0.1: + dependencies: + pinkie: 2.0.4 + + pinkie@2.0.4: {} + pirates@4.0.6: {} + pkg-dir@4.2.0: + dependencies: + find-up: 4.1.0 + postcss-import@15.1.0(postcss@8.5.3): dependencies: postcss: 8.5.3 @@ -4413,6 +4600,8 @@ snapshots: scheduler@0.25.0: {} + semver@6.3.1: {} + semver@7.7.1: {} set-cookie-parser@2.7.1: {} @@ -4521,6 +4710,10 @@ snapshots: dependencies: js-tokens: 9.0.1 + strip-outer@1.0.1: + dependencies: + escape-string-regexp: 1.0.5 + sucrase@3.35.0: dependencies: '@jridgewell/gen-mapping': 0.3.8 @@ -4615,6 +4808,10 @@ snapshots: dependencies: punycode: 2.3.1 + trim-repeated@1.0.0: + dependencies: + escape-string-regexp: 1.0.5 + ts-api-utils@2.0.1(typescript@5.7.3): dependencies: typescript: 5.7.3 @@ -4651,6 +4848,8 @@ snapshots: typescript@5.7.3: {} + universalify@0.1.2: {} + universalify@0.2.0: {} universalify@2.0.1: {} diff --git a/vite.config.ts b/vite.config.ts index 636fe36c..2350f241 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -3,6 +3,7 @@ import react from '@vitejs/plugin-react-swc' // https://vite.dev/config/ export default defineConfig({ + base: '/platform-catApi-react/', plugins: [react()], test: { environment: 'jsdom', From 0e8592f655bee958a9d8c1c55589722b6a2e754b Mon Sep 17 00:00:00 2001 From: Marios Tsigkas Date: Wed, 12 Mar 2025 17:54:01 +0200 Subject: [PATCH 27/96] Fix paths for favicon and main script in index.html; set basename for BrowserRouter in main.tsx --- index.html | 4 ++-- src/main.tsx | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/index.html b/index.html index f5032d04..5ab5f135 100644 --- a/index.html +++ b/index.html @@ -3,14 +3,14 @@ - + Marios' Cat Api
    - + \ No newline at end of file diff --git a/src/main.tsx b/src/main.tsx index ba09b2fa..1564bdec 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -12,7 +12,7 @@ if (!rootElement) { createRoot(rootElement).render( - + , From d124429eb2f594a47f29d0add2642a3412676953 Mon Sep 17 00:00:00 2001 From: Marios Tsigkas Date: Wed, 12 Mar 2025 18:15:51 +0200 Subject: [PATCH 28/96] Add BASENAME_ROUTE constant and update routing configuration; refactor favorites storage key --- README.md | 3 +++ package.json | 5 ++-- pnpm-lock.yaml | 53 ++++++++++++++++++++++++++------------- src/constants/index.ts | 1 + src/hooks/useFavorites.ts | 8 +++--- src/main.tsx | 3 ++- vite.config.ts | 5 ++-- 7 files changed, 52 insertions(+), 26 deletions(-) create mode 100644 src/constants/index.ts diff --git a/README.md b/README.md index 0708e6dc..7c6b68ce 100644 --- a/README.md +++ b/README.md @@ -21,6 +21,7 @@ Once you have built your app, share your code in the mean suits you best Good luck, potential colleague! # Platform Cat Api React Solution +Check the live site on GitHub Pages at https://mariosh346.github.io/platform-catApi-react/ ## Prerequisites - nvm (Node Version Manager) or Node v22 @@ -76,6 +77,8 @@ To deploy the project to GitHub Pages, run the following command: pnpm deploy ``` +Note: Once deployed, check the live site on GitHub Pages at https://mariosh346.github.io/platform-catApi-react/ + ## Tech Stack - React diff --git a/package.json b/package.json index c8a192a8..bfe360f4 100644 --- a/package.json +++ b/package.json @@ -26,6 +26,7 @@ "@eslint/js": "^9.21.0", "@testing-library/jest-dom": "^6.6.3", "@testing-library/react": "^16.2.0", + "@types/node": "^22.13.10", "@types/react": "^19.0.10", "@types/react-dom": "^19.0.4", "@vitejs/plugin-react-swc": "^3.8.0", @@ -37,6 +38,7 @@ "eslint-plugin-react-hooks": "^5.1.0", "eslint-plugin-react-refresh": "^0.4.19", "eslint-plugin-react-x": "^1.31.0", + "gh-pages": "^5.0.0", "globals": "^15.15.0", "jsdom": "^24.0.0", "postcss": "^8.4.35", @@ -44,7 +46,6 @@ "typescript": "~5.7.2", "typescript-eslint": "^8.24.1", "vite": "^6.2.1", - "vitest": "^3.0.8", - "gh-pages": "^5.0.0" + "vitest": "^3.0.8" } } \ No newline at end of file diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b88527aa..f218cb78 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -30,6 +30,9 @@ importers: '@testing-library/react': specifier: ^16.2.0 version: 16.2.0(@testing-library/dom@10.4.0)(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@types/node': + specifier: ^22.13.10 + version: 22.13.10 '@types/react': specifier: ^19.0.10 version: 19.0.10 @@ -38,10 +41,10 @@ importers: version: 19.0.4(@types/react@19.0.10) '@vitejs/plugin-react-swc': specifier: ^3.8.0 - version: 3.8.0(vite@6.2.1(jiti@1.21.7)(yaml@2.7.0)) + version: 3.8.0(vite@6.2.1(@types/node@22.13.10)(jiti@1.21.7)(yaml@2.7.0)) '@vitest/coverage-v8': specifier: ^1.5.0 - version: 1.6.1(vitest@3.0.8(jiti@1.21.7)(jsdom@24.1.3)(yaml@2.7.0)) + version: 1.6.1(vitest@3.0.8(@types/node@22.13.10)(jiti@1.21.7)(jsdom@24.1.3)(yaml@2.7.0)) autoprefixer: specifier: ^10.4.18 version: 10.4.21(postcss@8.5.3) @@ -86,10 +89,10 @@ importers: version: 8.26.0(eslint@9.22.0(jiti@1.21.7))(typescript@5.7.3) vite: specifier: ^6.2.1 - version: 6.2.1(jiti@1.21.7)(yaml@2.7.0) + version: 6.2.1(@types/node@22.13.10)(jiti@1.21.7)(yaml@2.7.0) vitest: specifier: ^3.0.8 - version: 3.0.8(jiti@1.21.7)(jsdom@24.1.3)(yaml@2.7.0) + version: 3.0.8(@types/node@22.13.10)(jiti@1.21.7)(jsdom@24.1.3)(yaml@2.7.0) packages: @@ -656,6 +659,9 @@ packages: '@types/node@16.18.126': resolution: {integrity: sha512-OTcgaiwfGFBKacvfwuHzzn1KLxH/er8mluiy8/uM3sGXHaRe73RrSIj01jow9t4kJEW633Ov+cOexXeiApTyAw==} + '@types/node@22.13.10': + resolution: {integrity: sha512-I6LPUvlRH+O6VRUqYOcMudhaIdUVWfsjnZavnsraHvpBwaEyMN29ry+0UVJhImYL16xsscu0aske3yA+uPOWfw==} + '@types/react-dom@19.0.4': resolution: {integrity: sha512-4fSQ8vWFkg+TGhePfUzVmat3eC14TXYSsiiDSLI0dVLsrm9gZFABjPy/Qu6TKgl1tq1Bu1yDsuQgY3A3DOjCcg==} peerDependencies: @@ -2352,6 +2358,9 @@ packages: engines: {node: '>=14.17'} hasBin: true + undici-types@6.20.0: + resolution: {integrity: sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==} + universalify@0.1.2: resolution: {integrity: sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==} engines: {node: '>= 4.0.0'} @@ -3036,6 +3045,10 @@ snapshots: '@types/node@16.18.126': {} + '@types/node@22.13.10': + dependencies: + undici-types: 6.20.0 + '@types/react-dom@19.0.4(@types/react@19.0.10)': dependencies: '@types/react': 19.0.10 @@ -3050,7 +3063,7 @@ snapshots: '@types/yauzl@2.10.3': dependencies: - '@types/node': 16.18.126 + '@types/node': 22.13.10 optional: true '@typescript-eslint/eslint-plugin@8.26.0(@typescript-eslint/parser@8.26.0(eslint@9.22.0(jiti@1.21.7))(typescript@5.7.3))(eslint@9.22.0(jiti@1.21.7))(typescript@5.7.3)': @@ -3130,14 +3143,14 @@ snapshots: '@typescript-eslint/types': 8.26.0 eslint-visitor-keys: 4.2.0 - '@vitejs/plugin-react-swc@3.8.0(vite@6.2.1(jiti@1.21.7)(yaml@2.7.0))': + '@vitejs/plugin-react-swc@3.8.0(vite@6.2.1(@types/node@22.13.10)(jiti@1.21.7)(yaml@2.7.0))': dependencies: '@swc/core': 1.11.8 - vite: 6.2.1(jiti@1.21.7)(yaml@2.7.0) + vite: 6.2.1(@types/node@22.13.10)(jiti@1.21.7)(yaml@2.7.0) transitivePeerDependencies: - '@swc/helpers' - '@vitest/coverage-v8@1.6.1(vitest@3.0.8(jiti@1.21.7)(jsdom@24.1.3)(yaml@2.7.0))': + '@vitest/coverage-v8@1.6.1(vitest@3.0.8(@types/node@22.13.10)(jiti@1.21.7)(jsdom@24.1.3)(yaml@2.7.0))': dependencies: '@ampproject/remapping': 2.3.0 '@bcoe/v8-coverage': 0.2.3 @@ -3152,7 +3165,7 @@ snapshots: std-env: 3.8.1 strip-literal: 2.1.1 test-exclude: 6.0.0 - vitest: 3.0.8(jiti@1.21.7)(jsdom@24.1.3)(yaml@2.7.0) + vitest: 3.0.8(@types/node@22.13.10)(jiti@1.21.7)(jsdom@24.1.3)(yaml@2.7.0) transitivePeerDependencies: - supports-color @@ -3163,13 +3176,13 @@ snapshots: chai: 5.2.0 tinyrainbow: 2.0.0 - '@vitest/mocker@3.0.8(vite@6.2.1(jiti@1.21.7)(yaml@2.7.0))': + '@vitest/mocker@3.0.8(vite@6.2.1(@types/node@22.13.10)(jiti@1.21.7)(yaml@2.7.0))': dependencies: '@vitest/spy': 3.0.8 estree-walker: 3.0.3 magic-string: 0.30.17 optionalDependencies: - vite: 6.2.1(jiti@1.21.7)(yaml@2.7.0) + vite: 6.2.1(@types/node@22.13.10)(jiti@1.21.7)(yaml@2.7.0) '@vitest/pretty-format@3.0.8': dependencies: @@ -4848,6 +4861,8 @@ snapshots: typescript@5.7.3: {} + undici-types@6.20.0: {} + universalify@0.1.2: {} universalify@0.2.0: {} @@ -4881,13 +4896,13 @@ snapshots: core-util-is: 1.0.2 extsprintf: 1.3.0 - vite-node@3.0.8(jiti@1.21.7)(yaml@2.7.0): + vite-node@3.0.8(@types/node@22.13.10)(jiti@1.21.7)(yaml@2.7.0): dependencies: cac: 6.7.14 debug: 4.4.0(supports-color@8.1.1) es-module-lexer: 1.6.0 pathe: 2.0.3 - vite: 6.2.1(jiti@1.21.7)(yaml@2.7.0) + vite: 6.2.1(@types/node@22.13.10)(jiti@1.21.7)(yaml@2.7.0) transitivePeerDependencies: - '@types/node' - jiti @@ -4902,20 +4917,21 @@ snapshots: - tsx - yaml - vite@6.2.1(jiti@1.21.7)(yaml@2.7.0): + vite@6.2.1(@types/node@22.13.10)(jiti@1.21.7)(yaml@2.7.0): dependencies: esbuild: 0.25.1 postcss: 8.5.3 rollup: 4.35.0 optionalDependencies: + '@types/node': 22.13.10 fsevents: 2.3.3 jiti: 1.21.7 yaml: 2.7.0 - vitest@3.0.8(jiti@1.21.7)(jsdom@24.1.3)(yaml@2.7.0): + vitest@3.0.8(@types/node@22.13.10)(jiti@1.21.7)(jsdom@24.1.3)(yaml@2.7.0): dependencies: '@vitest/expect': 3.0.8 - '@vitest/mocker': 3.0.8(vite@6.2.1(jiti@1.21.7)(yaml@2.7.0)) + '@vitest/mocker': 3.0.8(vite@6.2.1(@types/node@22.13.10)(jiti@1.21.7)(yaml@2.7.0)) '@vitest/pretty-format': 3.0.8 '@vitest/runner': 3.0.8 '@vitest/snapshot': 3.0.8 @@ -4931,10 +4947,11 @@ snapshots: tinyexec: 0.3.2 tinypool: 1.0.2 tinyrainbow: 2.0.0 - vite: 6.2.1(jiti@1.21.7)(yaml@2.7.0) - vite-node: 3.0.8(jiti@1.21.7)(yaml@2.7.0) + vite: 6.2.1(@types/node@22.13.10)(jiti@1.21.7)(yaml@2.7.0) + vite-node: 3.0.8(@types/node@22.13.10)(jiti@1.21.7)(yaml@2.7.0) why-is-node-running: 2.3.0 optionalDependencies: + '@types/node': 22.13.10 jsdom: 24.1.3 transitivePeerDependencies: - jiti diff --git a/src/constants/index.ts b/src/constants/index.ts new file mode 100644 index 00000000..970d5359 --- /dev/null +++ b/src/constants/index.ts @@ -0,0 +1 @@ +export const BASENAME_ROUTE = process.env.NODE_ENV === 'production' ? '/platform-catApi-react/' : '/'; \ No newline at end of file diff --git a/src/hooks/useFavorites.ts b/src/hooks/useFavorites.ts index d4de7b42..e74f3888 100644 --- a/src/hooks/useFavorites.ts +++ b/src/hooks/useFavorites.ts @@ -2,11 +2,13 @@ import { useState, useEffect } from 'react' import { parseCatImages } from '../api/parsers' import { CatImage } from '../api/types' +const LOCAL_STORAGE_FAVORITES_KEY = 'favorites' + export function useFavorites() { const [favorites, setFavorites] = useState([]) useEffect(() => { - const favs: unknown = JSON.parse(localStorage.getItem('favorites') ?? '[]') + const favs: unknown = JSON.parse(localStorage.getItem(LOCAL_STORAGE_FAVORITES_KEY) ?? '[]') const favsParsed = parseCatImages(favs) setFavorites(favsParsed) }, []) @@ -14,13 +16,13 @@ export function useFavorites() { const addFavorite = (img: CatImage) => { const updatedFavorites = [...favorites, img] setFavorites(updatedFavorites) - localStorage.setItem('favorites', JSON.stringify(updatedFavorites)) + localStorage.setItem(LOCAL_STORAGE_FAVORITES_KEY, JSON.stringify(updatedFavorites)) } const removeFavorite = (img: CatImage) => { const newFavorites = favorites.filter(fav => fav.id !== img.id) setFavorites(newFavorites) - localStorage.setItem('favorites', JSON.stringify(newFavorites)) + localStorage.setItem(LOCAL_STORAGE_FAVORITES_KEY, JSON.stringify(newFavorites)) } return { favorites, addFavorite, removeFavorite } diff --git a/src/main.tsx b/src/main.tsx index 1564bdec..ec9cfa08 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -3,6 +3,7 @@ import { createRoot } from 'react-dom/client' import { BrowserRouter } from 'react-router-dom' import './index.css' import App from './App.tsx' +import { BASENAME_ROUTE } from './constants/index.ts' const rootElement = document.getElementById('root') @@ -12,7 +13,7 @@ if (!rootElement) { createRoot(rootElement).render( - + , diff --git a/vite.config.ts b/vite.config.ts index 2350f241..28cdc508 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -1,9 +1,10 @@ import { defineConfig } from 'vitest/config' import react from '@vitejs/plugin-react-swc' +import { BASENAME_ROUTE } from './src/constants' // https://vite.dev/config/ export default defineConfig({ - base: '/platform-catApi-react/', + base: BASENAME_ROUTE, plugins: [react()], test: { environment: 'jsdom', @@ -12,5 +13,5 @@ export default defineConfig({ coverage: { reporter: ['text', 'json', 'html'], }, - }, + } }) From 8efe65f92b3c3f839ff28f9987767c90ab156dd2 Mon Sep 17 00:00:00 2001 From: Marios Tsigkas Date: Thu, 13 Mar 2025 14:49:49 +0200 Subject: [PATCH 29/96] Update README.md with next steps --- README.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/README.md b/README.md index 7c6b68ce..7b1d8e2b 100644 --- a/README.md +++ b/README.md @@ -79,6 +79,13 @@ pnpm deploy Note: Once deployed, check the live site on GitHub Pages at https://mariosh346.github.io/platform-catApi-react/ +## Next steps + +- Add state management like redux +- Use useQuery for caching apis +- Make components async for better load speed + + ## Tech Stack - React From b1d79fddd8811a390c72458b480342e4b4efed6c Mon Sep 17 00:00:00 2001 From: Marios Tsigkas Date: Thu, 13 Mar 2025 19:32:48 +0200 Subject: [PATCH 30/96] Implement code splitting with lazy loading for views; enhance navigation with preloading on mouse enter --- src/App.tsx | 42 ++++++++++++++++++++------------- src/components/ImageGallery.tsx | 1 + src/viewLoaders.ts | 5 ++++ src/views/Breeds.tsx | 2 +- 4 files changed, 33 insertions(+), 17 deletions(-) create mode 100644 src/viewLoaders.ts diff --git a/src/App.tsx b/src/App.tsx index aa7f9ae9..71c24e3c 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,35 +1,45 @@ import { Routes, Route, Link } from 'react-router-dom' -import Home from './views/Home' -import ImageView from './views/ImageView' +import { lazy, Suspense } from 'react' import './App.css' -import Favorites from './views/Favorites' -import Breeds from './views/Breeds' -import BreedDetail from './views/BreedDetail' + +const loadHome = () => import('./views/Home') +const loadImageView = () => import('./views/ImageView') +const loadFavorites = () => import('./views/Favorites') +const loadBreeds = () => import('./views/Breeds') +const loadBreedDetail = () => import('./views/BreedDetail') + +const Home = lazy(loadHome) +const ImageView = lazy(loadImageView) +const Favorites = lazy(loadFavorites) +const Breeds = lazy(loadBreeds) +const BreedDetail = lazy(loadBreedDetail) function App() { return (
    - - - } /> - } /> - } /> - } /> - } /> - + + Loading...
    }> + + } /> + } /> + } /> + } /> + } /> + +
    ) } diff --git a/src/components/ImageGallery.tsx b/src/components/ImageGallery.tsx index ebe73a93..ee789fe1 100644 --- a/src/components/ImageGallery.tsx +++ b/src/components/ImageGallery.tsx @@ -12,6 +12,7 @@ const MemoizedImageItem = memo(({ image, renderAfterImage }: { image: CatImage, void import('../views/ImageView')} > import('./views/Home') +export const loadImageView = () => import('./views/ImageView') +export const loadFavorites = () => import('./views/Favorites') +export const loadBreeds = () => import('./views/Breeds') +export const loadBreedDetail = () => import('./views/BreedDetail') \ No newline at end of file diff --git a/src/views/Breeds.tsx b/src/views/Breeds.tsx index 4b59c3b3..84e9eadb 100644 --- a/src/views/Breeds.tsx +++ b/src/views/Breeds.tsx @@ -11,7 +11,7 @@ interface Breed { const BreedListItem = memo(({ breed }: { breed: Breed }) => { return (
  • - + void import('./BreedDetail')}> {breed.name}
  • From bc70468cd514d3be83f945bfdd3b394b66c73907 Mon Sep 17 00:00:00 2001 From: Marios Tsigkas Date: Thu, 13 Mar 2025 20:05:37 +0200 Subject: [PATCH 31/96] Add axios-cache-interceptor for caching API responses; update catApi to use cached axios instance --- README.md | 2 -- package.json | 1 + pnpm-lock.yaml | 31 +++++++++++++++++++++++++++++++ src/api/catApi.ts | 17 ++++++++++++----- 4 files changed, 44 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 7b1d8e2b..14921ac7 100644 --- a/README.md +++ b/README.md @@ -82,8 +82,6 @@ Note: Once deployed, check the live site on GitHub Pages at https://mariosh346.g ## Next steps - Add state management like redux -- Use useQuery for caching apis -- Make components async for better load speed ## Tech Stack diff --git a/package.json b/package.json index bfe360f4..3f06d416 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,7 @@ }, "dependencies": { "axios": "^1.8.2", + "axios-cache-interceptor": "^1.6.2", "react": "^19.0.0", "react-dom": "^19.0.0", "react-router-dom": "^7.3.0" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f218cb78..b033a88f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -11,6 +11,9 @@ importers: axios: specifier: ^1.8.2 version: 1.8.2 + axios-cache-interceptor: + specifier: ^1.6.2 + version: 1.6.2(axios@1.8.2) react: specifier: ^19.0.0 version: 19.0.0 @@ -879,6 +882,12 @@ packages: aws4@1.13.2: resolution: {integrity: sha512-lHe62zvbTB5eEABUVi/AwVh0ZKY9rMMDhmm+eeyuuUQbQ3+J+fONVQOZyj+DdrvD4BY33uYniyRJ4UJIaSKAfw==} + axios-cache-interceptor@1.6.2: + resolution: {integrity: sha512-YLbAODIHZZIcD4b3WYFVQOa5W2TY/WnJ6sBHqAg6Z+hx+RVj8/OcjQyRopO6awn7/kOkGL5X9TP16AucnlJ/lw==} + engines: {node: '>=12'} + peerDependencies: + axios: ^1 + axios@1.8.2: resolution: {integrity: sha512-ls4GYBm5aig9vWx8AWDSGLpnpDQRtWAfrjU+EuytuODrFBkqesN2RkOQCBzrA1RQNHw1SmRMSDDDSwzNAYQ6Rg==} @@ -929,6 +938,9 @@ packages: resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} engines: {node: '>=8'} + cache-parser@1.2.5: + resolution: {integrity: sha512-Md/4VhAHByQ9frQ15WD6LrMNiVw9AEl/J7vWIXw+sxT6fSOpbtt6LHTp76vy8+bOESPBO94117Hm2bIjlI7XjA==} + cachedir@2.4.0: resolution: {integrity: sha512-9EtFOZR8g22CL7BWjJ9BUx1+A/djkofnyW3aOXZORNW2kxoUpx2h+uN2cOqwPmFhnpVmxg+KW2OjOSgChTEvsQ==} engines: {node: '>=6'} @@ -1304,6 +1316,9 @@ packages: fast-deep-equal@3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + fast-defer@1.1.8: + resolution: {integrity: sha512-lEJeOH5VL5R09j6AA0D4Uvq7AgsHw0dAImQQ+F3iSyHZuAxyQfWobsagGpTcOPvJr3urmKRHrs+Gs9hV+/Qm/Q==} + fast-glob@3.3.3: resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==} engines: {node: '>=8.6.0'} @@ -1826,6 +1841,9 @@ packages: resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} engines: {node: '>=0.10.0'} + object-code@1.3.3: + resolution: {integrity: sha512-/Ds4Xd5xzrtUOJ+xJQ57iAy0BZsZltOHssnDgcZ8DOhgh41q1YJCnTPnWdWSLkNGNnxYzhYChjc5dgC9mEERCA==} + object-hash@3.0.0: resolution: {integrity: sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==} engines: {node: '>= 6'} @@ -3300,6 +3318,13 @@ snapshots: aws4@1.13.2: {} + axios-cache-interceptor@1.6.2(axios@1.8.2): + dependencies: + axios: 1.8.2 + cache-parser: 1.2.5 + fast-defer: 1.1.8 + object-code: 1.3.3 + axios@1.8.2: dependencies: follow-redirects: 1.15.9 @@ -3353,6 +3378,8 @@ snapshots: cac@6.7.14: {} + cache-parser@1.2.5: {} + cachedir@2.4.0: {} call-bind-apply-helpers@1.0.2: @@ -3802,6 +3829,8 @@ snapshots: fast-deep-equal@3.1.3: {} + fast-defer@1.1.8: {} + fast-glob@3.3.3: dependencies: '@nodelib/fs.stat': 2.0.5 @@ -4335,6 +4364,8 @@ snapshots: object-assign@4.1.1: {} + object-code@1.3.3: {} + object-hash@3.0.0: {} object-inspect@1.13.4: {} diff --git a/src/api/catApi.ts b/src/api/catApi.ts index ca2d382a..0e56316c 100644 --- a/src/api/catApi.ts +++ b/src/api/catApi.ts @@ -1,30 +1,37 @@ import axios from 'axios' import { parseCatImages, parseBreeds } from './parsers' import { CatImage, Breed } from './types' +import { setupCache } from 'axios-cache-interceptor'; const BASE_URL = 'https://api.thecatapi.com/v1' +const axiosInstance = axios.create({ + baseURL: BASE_URL, +}); + +const axiosCached = setupCache(axiosInstance, { ttl: 60 * 60 * 1000 }) + export const getRandomImages = async (limit = 10): Promise => { - const res = await axios.get(`${BASE_URL}/images/search?limit=${limit.toString()}`) + const res = await axiosCached.get(`/images/search?limit=${limit.toString()}`) return parseCatImages(res.data) } export const getBreeds = async (): Promise => { - const res = await axios.get(`${BASE_URL}/breeds`) + const res = await axiosCached.get(`/breeds`) return parseBreeds(res.data) } export const getBreedImages = async (breedId: string, limit = 10): Promise => { - const res = await axios.get(`${BASE_URL}/images/search?breed_ids=${breedId}&limit=${limit.toString()}`) + const res = await axiosCached.get(`/images/search?breed_ids=${breedId}&limit=${limit.toString()}`) return parseCatImages(res.data) } export const getImageById = async (imageId: string): Promise => { - const res = await axios.get(`${BASE_URL}/images/${imageId}`) + const res = await axiosCached.get(`/images/${imageId}`) return parseCatImages([res.data])[0] } export const getBreedById = async (breedId: string): Promise => { - const res = await axios.get(`${BASE_URL}/breeds/${breedId}`) + const res = await axiosCached.get(`/breeds/${breedId}`) return parseBreeds([res.data])[0] } From 0b606e8b1d941140833bca741b93870e9c4ef670 Mon Sep 17 00:00:00 2001 From: Marios Tsigkas Date: Thu, 13 Mar 2025 20:10:51 +0200 Subject: [PATCH 32/96] Add next step to README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 14921ac7..3b823847 100644 --- a/README.md +++ b/README.md @@ -82,7 +82,7 @@ Note: Once deployed, check the live site on GitHub Pages at https://mariosh346.g ## Next steps - Add state management like redux - +- Introduce small reusable components like Button, Link ## Tech Stack From 864197d0cc7e0dac18ab4372859008fb4d421fb8 Mon Sep 17 00:00:00 2001 From: Marios Tsigkas Date: Thu, 13 Mar 2025 21:04:58 +0200 Subject: [PATCH 33/96] Update Modal component styles and adjust ImageView image class --- src/components/Modal.tsx | 2 +- src/views/ImageView.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/Modal.tsx b/src/components/Modal.tsx index dc81eeb8..90bb3edf 100644 --- a/src/components/Modal.tsx +++ b/src/components/Modal.tsx @@ -14,7 +14,7 @@ function Modal({ children, onClose, isLoading, error }: ModalProps): JSX.Element } return (
    {selectedImage && <> - cat + cat {selectedImage.breeds && selectedImage.breeds.length > 0 ? ( <>

    {selectedImage.breeds[0].name}

    From 34ca7625419197edd7b4727e7d349f5d5e2feda7 Mon Sep 17 00:00:00 2001 From: Marios Tsigkas Date: Thu, 27 Mar 2025 19:07:01 +0200 Subject: [PATCH 34/96] Add CI workflow for testing and deployment; include setup script for environment --- .github/workflows/deploy.yml | 46 ++++++++++++++++++++++++++++++++++++ scripts/setup.sh | 4 ++++ 2 files changed, 50 insertions(+) create mode 100644 .github/workflows/deploy.yml create mode 100644 scripts/setup.sh diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml new file mode 100644 index 00000000..eea21bee --- /dev/null +++ b/.github/workflows/deploy.yml @@ -0,0 +1,46 @@ +name: CI & Deploy + +on: + push: + branches: [ main ] + pull_request: + branches: [ main ] + +# Define common steps as an anchor +x-common-steps: &common-steps + - name: Checkout Repository + uses: actions/checkout@v3 + - name: Setup Node.js + uses: actions/setup-node@v3 + with: + node-version: '22' + cache: 'pnpm' + - name: Setup Environment + run: bash scripts/setup.sh + +jobs: + vitest: + runs-on: ubuntu-latest + steps: + <<: *common-steps + - name: Run Vitest Tests + run: pnpm test + + cypress: + runs-on: ubuntu-latest + steps: + <<: *common-steps + - name: Run Cypress Tests + run: pnpm cypress:run + + build-deploy: + runs-on: ubuntu-latest + needs: [vitest, cypress] + steps: + <<: *common-steps + - name: Build Application + run: pnpm build + - name: Deploy to GitHub Pages + run: pnpm deploy + env: + GHPAGES_TOKEN: ${{ secrets.GHPAGES_TOKEN }} diff --git a/scripts/setup.sh b/scripts/setup.sh new file mode 100644 index 00000000..6bc28954 --- /dev/null +++ b/scripts/setup.sh @@ -0,0 +1,4 @@ +#!/bin/bash +# Shared setup commands for CI jobs +npm install -g pnpm +pnpm install From 648296e08d8b0d458498dbbeb3c7cedaa87304e4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 27 Mar 2025 17:12:25 +0000 Subject: [PATCH 35/96] Bump vite in the npm_and_yarn group across 1 directory Bumps the npm_and_yarn group with 1 update in the / directory: [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite). Updates `vite` from 6.2.1 to 6.2.3 - [Release notes](https://github.com/vitejs/vite/releases) - [Changelog](https://github.com/vitejs/vite/blob/v6.2.3/packages/vite/CHANGELOG.md) - [Commits](https://github.com/vitejs/vite/commits/v6.2.3/packages/vite) --- updated-dependencies: - dependency-name: vite dependency-type: direct:development dependency-group: npm_and_yarn ... Signed-off-by: dependabot[bot] --- package.json | 2 +- pnpm-lock.yaml | 212 +++++++++++++++++++++++++++---------------------- 2 files changed, 118 insertions(+), 96 deletions(-) diff --git a/package.json b/package.json index 3f06d416..f967ba08 100644 --- a/package.json +++ b/package.json @@ -46,7 +46,7 @@ "tailwindcss": "^3.4.1", "typescript": "~5.7.2", "typescript-eslint": "^8.24.1", - "vite": "^6.2.1", + "vite": "^6.2.3", "vitest": "^3.0.8" } } \ No newline at end of file diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b033a88f..d3acb1c2 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -44,7 +44,7 @@ importers: version: 19.0.4(@types/react@19.0.10) '@vitejs/plugin-react-swc': specifier: ^3.8.0 - version: 3.8.0(vite@6.2.1(@types/node@22.13.10)(jiti@1.21.7)(yaml@2.7.0)) + version: 3.8.0(vite@6.2.3(@types/node@22.13.10)(jiti@1.21.7)(yaml@2.7.0)) '@vitest/coverage-v8': specifier: ^1.5.0 version: 1.6.1(vitest@3.0.8(@types/node@22.13.10)(jiti@1.21.7)(jsdom@24.1.3)(yaml@2.7.0)) @@ -91,8 +91,8 @@ importers: specifier: ^8.24.1 version: 8.26.0(eslint@9.22.0(jiti@1.21.7))(typescript@5.7.3) vite: - specifier: ^6.2.1 - version: 6.2.1(@types/node@22.13.10)(jiti@1.21.7)(yaml@2.7.0) + specifier: ^6.2.3 + version: 6.2.3(@types/node@22.13.10)(jiti@1.21.7)(yaml@2.7.0) vitest: specifier: ^3.0.8 version: 3.0.8(@types/node@22.13.10)(jiti@1.21.7)(jsdom@24.1.3)(yaml@2.7.0) @@ -134,6 +134,10 @@ packages: resolution: {integrity: sha512-aA63XwOkcl4xxQa3HjPMqOP6LiK0ZDv3mUPYEFXkpHbaFjtGggE1A61FjFzJnB+p7/oy2gA8E+rcBNl/zC1tMg==} engines: {node: '>=6.9.0'} + '@babel/runtime@7.27.0': + resolution: {integrity: sha512-VtPOkrdPHZsKc/clNqyi9WUA8TINkZ4cGk63UUE3u4pmB2k+ZMQRDuIOagv8UVd6j7k0T3+RRIb7beKTebNbcw==} + engines: {node: '>=6.9.0'} + '@babel/types@7.26.9': resolution: {integrity: sha512-Y3IR1cRnOxOCDvMmNiym7XpXQ93iGDDPHx+Zj+NM+rg0fBaShfQLkg+hKPaZCEvg5N/LeCo4+Rj/i3FuJsIQaw==} engines: {node: '>=6.9.0'} @@ -454,98 +458,103 @@ packages: resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} engines: {node: '>=14'} - '@rollup/rollup-android-arm-eabi@4.35.0': - resolution: {integrity: sha512-uYQ2WfPaqz5QtVgMxfN6NpLD+no0MYHDBywl7itPYd3K5TjjSghNKmX8ic9S8NU8w81NVhJv/XojcHptRly7qQ==} + '@rollup/rollup-android-arm-eabi@4.37.0': + resolution: {integrity: sha512-l7StVw6WAa8l3vA1ov80jyetOAEo1FtHvZDbzXDO/02Sq/QVvqlHkYoFwDJPIMj0GKiistsBudfx5tGFnwYWDQ==} cpu: [arm] os: [android] - '@rollup/rollup-android-arm64@4.35.0': - resolution: {integrity: sha512-FtKddj9XZudurLhdJnBl9fl6BwCJ3ky8riCXjEw3/UIbjmIY58ppWwPEvU3fNu+W7FUsAsB1CdH+7EQE6CXAPA==} + '@rollup/rollup-android-arm64@4.37.0': + resolution: {integrity: sha512-6U3SlVyMxezt8Y+/iEBcbp945uZjJwjZimu76xoG7tO1av9VO691z8PkhzQ85ith2I8R2RddEPeSfcbyPfD4hA==} cpu: [arm64] os: [android] - '@rollup/rollup-darwin-arm64@4.35.0': - resolution: {integrity: sha512-Uk+GjOJR6CY844/q6r5DR/6lkPFOw0hjfOIzVx22THJXMxktXG6CbejseJFznU8vHcEBLpiXKY3/6xc+cBm65Q==} + '@rollup/rollup-darwin-arm64@4.37.0': + resolution: {integrity: sha512-+iTQ5YHuGmPt10NTzEyMPbayiNTcOZDWsbxZYR1ZnmLnZxG17ivrPSWFO9j6GalY0+gV3Jtwrrs12DBscxnlYA==} cpu: [arm64] os: [darwin] - '@rollup/rollup-darwin-x64@4.35.0': - resolution: {integrity: sha512-3IrHjfAS6Vkp+5bISNQnPogRAW5GAV1n+bNCrDwXmfMHbPl5EhTmWtfmwlJxFRUCBZ+tZ/OxDyU08aF6NI/N5Q==} + '@rollup/rollup-darwin-x64@4.37.0': + resolution: {integrity: sha512-m8W2UbxLDcmRKVjgl5J/k4B8d7qX2EcJve3Sut7YGrQoPtCIQGPH5AMzuFvYRWZi0FVS0zEY4c8uttPfX6bwYQ==} cpu: [x64] os: [darwin] - '@rollup/rollup-freebsd-arm64@4.35.0': - resolution: {integrity: sha512-sxjoD/6F9cDLSELuLNnY0fOrM9WA0KrM0vWm57XhrIMf5FGiN8D0l7fn+bpUeBSU7dCgPV2oX4zHAsAXyHFGcQ==} + '@rollup/rollup-freebsd-arm64@4.37.0': + resolution: {integrity: sha512-FOMXGmH15OmtQWEt174v9P1JqqhlgYge/bUjIbiVD1nI1NeJ30HYT9SJlZMqdo1uQFyt9cz748F1BHghWaDnVA==} cpu: [arm64] os: [freebsd] - '@rollup/rollup-freebsd-x64@4.35.0': - resolution: {integrity: sha512-2mpHCeRuD1u/2kruUiHSsnjWtHjqVbzhBkNVQ1aVD63CcexKVcQGwJ2g5VphOd84GvxfSvnnlEyBtQCE5hxVVw==} + '@rollup/rollup-freebsd-x64@4.37.0': + resolution: {integrity: sha512-SZMxNttjPKvV14Hjck5t70xS3l63sbVwl98g3FlVVx2YIDmfUIy29jQrsw06ewEYQ8lQSuY9mpAPlmgRD2iSsA==} cpu: [x64] os: [freebsd] - '@rollup/rollup-linux-arm-gnueabihf@4.35.0': - resolution: {integrity: sha512-mrA0v3QMy6ZSvEuLs0dMxcO2LnaCONs1Z73GUDBHWbY8tFFocM6yl7YyMu7rz4zS81NDSqhrUuolyZXGi8TEqg==} + '@rollup/rollup-linux-arm-gnueabihf@4.37.0': + resolution: {integrity: sha512-hhAALKJPidCwZcj+g+iN+38SIOkhK2a9bqtJR+EtyxrKKSt1ynCBeqrQy31z0oWU6thRZzdx53hVgEbRkuI19w==} cpu: [arm] os: [linux] - '@rollup/rollup-linux-arm-musleabihf@4.35.0': - resolution: {integrity: sha512-DnYhhzcvTAKNexIql8pFajr0PiDGrIsBYPRvCKlA5ixSS3uwo/CWNZxB09jhIapEIg945KOzcYEAGGSmTSpk7A==} + '@rollup/rollup-linux-arm-musleabihf@4.37.0': + resolution: {integrity: sha512-jUb/kmn/Gd8epbHKEqkRAxq5c2EwRt0DqhSGWjPFxLeFvldFdHQs/n8lQ9x85oAeVb6bHcS8irhTJX2FCOd8Ag==} cpu: [arm] os: [linux] - '@rollup/rollup-linux-arm64-gnu@4.35.0': - resolution: {integrity: sha512-uagpnH2M2g2b5iLsCTZ35CL1FgyuzzJQ8L9VtlJ+FckBXroTwNOaD0z0/UF+k5K3aNQjbm8LIVpxykUOQt1m/A==} + '@rollup/rollup-linux-arm64-gnu@4.37.0': + resolution: {integrity: sha512-oNrJxcQT9IcbcmKlkF+Yz2tmOxZgG9D9GRq+1OE6XCQwCVwxixYAa38Z8qqPzQvzt1FCfmrHX03E0pWoXm1DqA==} cpu: [arm64] os: [linux] - '@rollup/rollup-linux-arm64-musl@4.35.0': - resolution: {integrity: sha512-XQxVOCd6VJeHQA/7YcqyV0/88N6ysSVzRjJ9I9UA/xXpEsjvAgDTgH3wQYz5bmr7SPtVK2TsP2fQ2N9L4ukoUg==} + '@rollup/rollup-linux-arm64-musl@4.37.0': + resolution: {integrity: sha512-pfxLBMls+28Ey2enpX3JvjEjaJMBX5XlPCZNGxj4kdJyHduPBXtxYeb8alo0a7bqOoWZW2uKynhHxF/MWoHaGQ==} cpu: [arm64] os: [linux] - '@rollup/rollup-linux-loongarch64-gnu@4.35.0': - resolution: {integrity: sha512-5pMT5PzfgwcXEwOaSrqVsz/LvjDZt+vQ8RT/70yhPU06PTuq8WaHhfT1LW+cdD7mW6i/J5/XIkX/1tCAkh1W6g==} + '@rollup/rollup-linux-loongarch64-gnu@4.37.0': + resolution: {integrity: sha512-yCE0NnutTC/7IGUq/PUHmoeZbIwq3KRh02e9SfFh7Vmc1Z7atuJRYWhRME5fKgT8aS20mwi1RyChA23qSyRGpA==} cpu: [loong64] os: [linux] - '@rollup/rollup-linux-powerpc64le-gnu@4.35.0': - resolution: {integrity: sha512-c+zkcvbhbXF98f4CtEIP1EBA/lCic5xB0lToneZYvMeKu5Kamq3O8gqrxiYYLzlZH6E3Aq+TSW86E4ay8iD8EA==} + '@rollup/rollup-linux-powerpc64le-gnu@4.37.0': + resolution: {integrity: sha512-NxcICptHk06E2Lh3a4Pu+2PEdZ6ahNHuK7o6Np9zcWkrBMuv21j10SQDJW3C9Yf/A/P7cutWoC/DptNLVsZ0VQ==} cpu: [ppc64] os: [linux] - '@rollup/rollup-linux-riscv64-gnu@4.35.0': - resolution: {integrity: sha512-s91fuAHdOwH/Tad2tzTtPX7UZyytHIRR6V4+2IGlV0Cej5rkG0R61SX4l4y9sh0JBibMiploZx3oHKPnQBKe4g==} + '@rollup/rollup-linux-riscv64-gnu@4.37.0': + resolution: {integrity: sha512-PpWwHMPCVpFZLTfLq7EWJWvrmEuLdGn1GMYcm5MV7PaRgwCEYJAwiN94uBuZev0/J/hFIIJCsYw4nLmXA9J7Pw==} cpu: [riscv64] os: [linux] - '@rollup/rollup-linux-s390x-gnu@4.35.0': - resolution: {integrity: sha512-hQRkPQPLYJZYGP+Hj4fR9dDBMIM7zrzJDWFEMPdTnTy95Ljnv0/4w/ixFw3pTBMEuuEuoqtBINYND4M7ujcuQw==} + '@rollup/rollup-linux-riscv64-musl@4.37.0': + resolution: {integrity: sha512-DTNwl6a3CfhGTAOYZ4KtYbdS8b+275LSLqJVJIrPa5/JuIufWWZ/QFvkxp52gpmguN95eujrM68ZG+zVxa8zHA==} + cpu: [riscv64] + os: [linux] + + '@rollup/rollup-linux-s390x-gnu@4.37.0': + resolution: {integrity: sha512-hZDDU5fgWvDdHFuExN1gBOhCuzo/8TMpidfOR+1cPZJflcEzXdCy1LjnklQdW8/Et9sryOPJAKAQRw8Jq7Tg+A==} cpu: [s390x] os: [linux] - '@rollup/rollup-linux-x64-gnu@4.35.0': - resolution: {integrity: sha512-Pim1T8rXOri+0HmV4CdKSGrqcBWX0d1HoPnQ0uw0bdp1aP5SdQVNBy8LjYncvnLgu3fnnCt17xjWGd4cqh8/hA==} + '@rollup/rollup-linux-x64-gnu@4.37.0': + resolution: {integrity: sha512-pKivGpgJM5g8dwj0ywBwe/HeVAUSuVVJhUTa/URXjxvoyTT/AxsLTAbkHkDHG7qQxLoW2s3apEIl26uUe08LVQ==} cpu: [x64] os: [linux] - '@rollup/rollup-linux-x64-musl@4.35.0': - resolution: {integrity: sha512-QysqXzYiDvQWfUiTm8XmJNO2zm9yC9P/2Gkrwg2dH9cxotQzunBHYr6jk4SujCTqnfGxduOmQcI7c2ryuW8XVg==} + '@rollup/rollup-linux-x64-musl@4.37.0': + resolution: {integrity: sha512-E2lPrLKE8sQbY/2bEkVTGDEk4/49UYRVWgj90MY8yPjpnGBQ+Xi1Qnr7b7UIWw1NOggdFQFOLZ8+5CzCiz143w==} cpu: [x64] os: [linux] - '@rollup/rollup-win32-arm64-msvc@4.35.0': - resolution: {integrity: sha512-OUOlGqPkVJCdJETKOCEf1mw848ZyJ5w50/rZ/3IBQVdLfR5jk/6Sr5m3iO2tdPgwo0x7VcncYuOvMhBWZq8ayg==} + '@rollup/rollup-win32-arm64-msvc@4.37.0': + resolution: {integrity: sha512-Jm7biMazjNzTU4PrQtr7VS8ibeys9Pn29/1bm4ph7CP2kf21950LgN+BaE2mJ1QujnvOc6p54eWWiVvn05SOBg==} cpu: [arm64] os: [win32] - '@rollup/rollup-win32-ia32-msvc@4.35.0': - resolution: {integrity: sha512-2/lsgejMrtwQe44glq7AFFHLfJBPafpsTa6JvP2NGef/ifOa4KBoglVf7AKN7EV9o32evBPRqfg96fEHzWo5kw==} + '@rollup/rollup-win32-ia32-msvc@4.37.0': + resolution: {integrity: sha512-e3/1SFm1OjefWICB2Ucstg2dxYDkDTZGDYgwufcbsxTHyqQps1UQf33dFEChBNmeSsTOyrjw2JJq0zbG5GF6RA==} cpu: [ia32] os: [win32] - '@rollup/rollup-win32-x64-msvc@4.35.0': - resolution: {integrity: sha512-PIQeY5XDkrOysbQblSW7v3l1MDZzkTEzAfTPkj5VAu3FW8fS4ynyLg2sINp0fp3SjZ8xkRYpLqoKcYqAkhU1dw==} + '@rollup/rollup-win32-x64-msvc@4.37.0': + resolution: {integrity: sha512-LWbXUBwn/bcLx2sSsqy7pK5o+Nr+VCoRoAohfJ5C/aBio9nfJmGQqHAhU6pwxV/RmyTk5AqdySma7uwWGlmeuA==} cpu: [x64] os: [win32] @@ -656,6 +665,9 @@ packages: '@types/estree@1.0.6': resolution: {integrity: sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==} + '@types/estree@1.0.7': + resolution: {integrity: sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==} + '@types/json-schema@7.0.15': resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} @@ -2115,8 +2127,8 @@ packages: rfdc@1.4.1: resolution: {integrity: sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==} - rollup@4.35.0: - resolution: {integrity: sha512-kg6oI4g+vc41vePJyO6dHt/yl0Rz3Thv0kJeVQ3D1kS3E5XSuKbPc29G4IpT/Kv1KQwgHVcN+HtyS+HYLNSvQg==} + rollup@4.37.0: + resolution: {integrity: sha512-iAtQy/L4QFU+rTJ1YUjXqJOJzuwEghqWzCEYD2FEghT7Gsy1VdABntrO4CLopA5IkflTyqNiLNwPcOJ3S7UKLg==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true @@ -2423,8 +2435,8 @@ packages: engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} hasBin: true - vite@6.2.1: - resolution: {integrity: sha512-n2GnqDb6XPhlt9B8olZPrgMD/es/Nd1RdChF6CBD/fHW6pUyUTt2sQW2fPRX5GiD9XEa6+8A6A4f2vT6pSsE7Q==} + vite@6.2.3: + resolution: {integrity: sha512-IzwM54g4y9JA/xAeBPNaDXiBF8Jsgl3VBQ2YQ/wOY6fyW3xMdSoltIV3Bo59DErdqdE6RxUfv8W69DvUorE4Eg==} engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} hasBin: true peerDependencies: @@ -2608,6 +2620,10 @@ snapshots: dependencies: regenerator-runtime: 0.14.1 + '@babel/runtime@7.27.0': + dependencies: + regenerator-runtime: 0.14.1 + '@babel/types@7.26.9': dependencies: '@babel/helper-string-parser': 7.25.9 @@ -2913,61 +2929,64 @@ snapshots: '@pkgjs/parseargs@0.11.0': optional: true - '@rollup/rollup-android-arm-eabi@4.35.0': + '@rollup/rollup-android-arm-eabi@4.37.0': + optional: true + + '@rollup/rollup-android-arm64@4.37.0': optional: true - '@rollup/rollup-android-arm64@4.35.0': + '@rollup/rollup-darwin-arm64@4.37.0': optional: true - '@rollup/rollup-darwin-arm64@4.35.0': + '@rollup/rollup-darwin-x64@4.37.0': optional: true - '@rollup/rollup-darwin-x64@4.35.0': + '@rollup/rollup-freebsd-arm64@4.37.0': optional: true - '@rollup/rollup-freebsd-arm64@4.35.0': + '@rollup/rollup-freebsd-x64@4.37.0': optional: true - '@rollup/rollup-freebsd-x64@4.35.0': + '@rollup/rollup-linux-arm-gnueabihf@4.37.0': optional: true - '@rollup/rollup-linux-arm-gnueabihf@4.35.0': + '@rollup/rollup-linux-arm-musleabihf@4.37.0': optional: true - '@rollup/rollup-linux-arm-musleabihf@4.35.0': + '@rollup/rollup-linux-arm64-gnu@4.37.0': optional: true - '@rollup/rollup-linux-arm64-gnu@4.35.0': + '@rollup/rollup-linux-arm64-musl@4.37.0': optional: true - '@rollup/rollup-linux-arm64-musl@4.35.0': + '@rollup/rollup-linux-loongarch64-gnu@4.37.0': optional: true - '@rollup/rollup-linux-loongarch64-gnu@4.35.0': + '@rollup/rollup-linux-powerpc64le-gnu@4.37.0': optional: true - '@rollup/rollup-linux-powerpc64le-gnu@4.35.0': + '@rollup/rollup-linux-riscv64-gnu@4.37.0': optional: true - '@rollup/rollup-linux-riscv64-gnu@4.35.0': + '@rollup/rollup-linux-riscv64-musl@4.37.0': optional: true - '@rollup/rollup-linux-s390x-gnu@4.35.0': + '@rollup/rollup-linux-s390x-gnu@4.37.0': optional: true - '@rollup/rollup-linux-x64-gnu@4.35.0': + '@rollup/rollup-linux-x64-gnu@4.37.0': optional: true - '@rollup/rollup-linux-x64-musl@4.35.0': + '@rollup/rollup-linux-x64-musl@4.37.0': optional: true - '@rollup/rollup-win32-arm64-msvc@4.35.0': + '@rollup/rollup-win32-arm64-msvc@4.37.0': optional: true - '@rollup/rollup-win32-ia32-msvc@4.35.0': + '@rollup/rollup-win32-ia32-msvc@4.37.0': optional: true - '@rollup/rollup-win32-x64-msvc@4.35.0': + '@rollup/rollup-win32-x64-msvc@4.37.0': optional: true '@swc/core-darwin-arm64@1.11.8': @@ -3025,7 +3044,7 @@ snapshots: '@testing-library/dom@10.4.0': dependencies: '@babel/code-frame': 7.26.2 - '@babel/runtime': 7.26.9 + '@babel/runtime': 7.27.0 '@types/aria-query': 5.0.4 aria-query: 5.3.0 chalk: 4.1.2 @@ -3059,6 +3078,8 @@ snapshots: '@types/estree@1.0.6': {} + '@types/estree@1.0.7': {} + '@types/json-schema@7.0.15': {} '@types/node@16.18.126': {} @@ -3161,10 +3182,10 @@ snapshots: '@typescript-eslint/types': 8.26.0 eslint-visitor-keys: 4.2.0 - '@vitejs/plugin-react-swc@3.8.0(vite@6.2.1(@types/node@22.13.10)(jiti@1.21.7)(yaml@2.7.0))': + '@vitejs/plugin-react-swc@3.8.0(vite@6.2.3(@types/node@22.13.10)(jiti@1.21.7)(yaml@2.7.0))': dependencies: '@swc/core': 1.11.8 - vite: 6.2.1(@types/node@22.13.10)(jiti@1.21.7)(yaml@2.7.0) + vite: 6.2.3(@types/node@22.13.10)(jiti@1.21.7)(yaml@2.7.0) transitivePeerDependencies: - '@swc/helpers' @@ -3194,13 +3215,13 @@ snapshots: chai: 5.2.0 tinyrainbow: 2.0.0 - '@vitest/mocker@3.0.8(vite@6.2.1(@types/node@22.13.10)(jiti@1.21.7)(yaml@2.7.0))': + '@vitest/mocker@3.0.8(vite@6.2.3(@types/node@22.13.10)(jiti@1.21.7)(yaml@2.7.0))': dependencies: '@vitest/spy': 3.0.8 estree-walker: 3.0.3 magic-string: 0.30.17 optionalDependencies: - vite: 6.2.1(@types/node@22.13.10)(jiti@1.21.7)(yaml@2.7.0) + vite: 6.2.3(@types/node@22.13.10)(jiti@1.21.7)(yaml@2.7.0) '@vitest/pretty-format@3.0.8': dependencies: @@ -3789,7 +3810,7 @@ snapshots: estree-walker@3.0.3: dependencies: - '@types/estree': 1.0.6 + '@types/estree': 1.0.7 esutils@2.0.3: {} @@ -4597,29 +4618,30 @@ snapshots: rfdc@1.4.1: {} - rollup@4.35.0: + rollup@4.37.0: dependencies: '@types/estree': 1.0.6 optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.35.0 - '@rollup/rollup-android-arm64': 4.35.0 - '@rollup/rollup-darwin-arm64': 4.35.0 - '@rollup/rollup-darwin-x64': 4.35.0 - '@rollup/rollup-freebsd-arm64': 4.35.0 - '@rollup/rollup-freebsd-x64': 4.35.0 - '@rollup/rollup-linux-arm-gnueabihf': 4.35.0 - '@rollup/rollup-linux-arm-musleabihf': 4.35.0 - '@rollup/rollup-linux-arm64-gnu': 4.35.0 - '@rollup/rollup-linux-arm64-musl': 4.35.0 - '@rollup/rollup-linux-loongarch64-gnu': 4.35.0 - '@rollup/rollup-linux-powerpc64le-gnu': 4.35.0 - '@rollup/rollup-linux-riscv64-gnu': 4.35.0 - '@rollup/rollup-linux-s390x-gnu': 4.35.0 - '@rollup/rollup-linux-x64-gnu': 4.35.0 - '@rollup/rollup-linux-x64-musl': 4.35.0 - '@rollup/rollup-win32-arm64-msvc': 4.35.0 - '@rollup/rollup-win32-ia32-msvc': 4.35.0 - '@rollup/rollup-win32-x64-msvc': 4.35.0 + '@rollup/rollup-android-arm-eabi': 4.37.0 + '@rollup/rollup-android-arm64': 4.37.0 + '@rollup/rollup-darwin-arm64': 4.37.0 + '@rollup/rollup-darwin-x64': 4.37.0 + '@rollup/rollup-freebsd-arm64': 4.37.0 + '@rollup/rollup-freebsd-x64': 4.37.0 + '@rollup/rollup-linux-arm-gnueabihf': 4.37.0 + '@rollup/rollup-linux-arm-musleabihf': 4.37.0 + '@rollup/rollup-linux-arm64-gnu': 4.37.0 + '@rollup/rollup-linux-arm64-musl': 4.37.0 + '@rollup/rollup-linux-loongarch64-gnu': 4.37.0 + '@rollup/rollup-linux-powerpc64le-gnu': 4.37.0 + '@rollup/rollup-linux-riscv64-gnu': 4.37.0 + '@rollup/rollup-linux-riscv64-musl': 4.37.0 + '@rollup/rollup-linux-s390x-gnu': 4.37.0 + '@rollup/rollup-linux-x64-gnu': 4.37.0 + '@rollup/rollup-linux-x64-musl': 4.37.0 + '@rollup/rollup-win32-arm64-msvc': 4.37.0 + '@rollup/rollup-win32-ia32-msvc': 4.37.0 + '@rollup/rollup-win32-x64-msvc': 4.37.0 fsevents: 2.3.3 rrweb-cssom@0.7.1: {} @@ -4933,7 +4955,7 @@ snapshots: debug: 4.4.0(supports-color@8.1.1) es-module-lexer: 1.6.0 pathe: 2.0.3 - vite: 6.2.1(@types/node@22.13.10)(jiti@1.21.7)(yaml@2.7.0) + vite: 6.2.3(@types/node@22.13.10)(jiti@1.21.7)(yaml@2.7.0) transitivePeerDependencies: - '@types/node' - jiti @@ -4948,11 +4970,11 @@ snapshots: - tsx - yaml - vite@6.2.1(@types/node@22.13.10)(jiti@1.21.7)(yaml@2.7.0): + vite@6.2.3(@types/node@22.13.10)(jiti@1.21.7)(yaml@2.7.0): dependencies: esbuild: 0.25.1 postcss: 8.5.3 - rollup: 4.35.0 + rollup: 4.37.0 optionalDependencies: '@types/node': 22.13.10 fsevents: 2.3.3 @@ -4962,7 +4984,7 @@ snapshots: vitest@3.0.8(@types/node@22.13.10)(jiti@1.21.7)(jsdom@24.1.3)(yaml@2.7.0): dependencies: '@vitest/expect': 3.0.8 - '@vitest/mocker': 3.0.8(vite@6.2.1(@types/node@22.13.10)(jiti@1.21.7)(yaml@2.7.0)) + '@vitest/mocker': 3.0.8(vite@6.2.3(@types/node@22.13.10)(jiti@1.21.7)(yaml@2.7.0)) '@vitest/pretty-format': 3.0.8 '@vitest/runner': 3.0.8 '@vitest/snapshot': 3.0.8 @@ -4978,7 +5000,7 @@ snapshots: tinyexec: 0.3.2 tinypool: 1.0.2 tinyrainbow: 2.0.0 - vite: 6.2.1(@types/node@22.13.10)(jiti@1.21.7)(yaml@2.7.0) + vite: 6.2.3(@types/node@22.13.10)(jiti@1.21.7)(yaml@2.7.0) vite-node: 3.0.8(@types/node@22.13.10)(jiti@1.21.7)(yaml@2.7.0) why-is-node-running: 2.3.0 optionalDependencies: From b9a183ed4fdffff7e7b79f0bc392fe598e6df120 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 27 Mar 2025 17:12:33 +0000 Subject: [PATCH 36/96] Bump @babel/runtime in the npm_and_yarn group across 1 directory Bumps the npm_and_yarn group with 1 update in the / directory: [@babel/runtime](https://github.com/babel/babel/tree/HEAD/packages/babel-runtime). Updates `@babel/runtime` from 7.26.9 to 7.27.0 - [Release notes](https://github.com/babel/babel/releases) - [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md) - [Commits](https://github.com/babel/babel/commits/v7.27.0/packages/babel-runtime) --- updated-dependencies: - dependency-name: "@babel/runtime" dependency-type: indirect dependency-group: npm_and_yarn ... Signed-off-by: dependabot[bot] --- pnpm-lock.yaml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b033a88f..b37463bc 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -130,8 +130,8 @@ packages: engines: {node: '>=6.0.0'} hasBin: true - '@babel/runtime@7.26.9': - resolution: {integrity: sha512-aA63XwOkcl4xxQa3HjPMqOP6LiK0ZDv3mUPYEFXkpHbaFjtGggE1A61FjFzJnB+p7/oy2gA8E+rcBNl/zC1tMg==} + '@babel/runtime@7.27.0': + resolution: {integrity: sha512-VtPOkrdPHZsKc/clNqyi9WUA8TINkZ4cGk63UUE3u4pmB2k+ZMQRDuIOagv8UVd6j7k0T3+RRIb7beKTebNbcw==} engines: {node: '>=6.9.0'} '@babel/types@7.26.9': @@ -2604,7 +2604,7 @@ snapshots: dependencies: '@babel/types': 7.26.9 - '@babel/runtime@7.26.9': + '@babel/runtime@7.27.0': dependencies: regenerator-runtime: 0.14.1 @@ -3025,7 +3025,7 @@ snapshots: '@testing-library/dom@10.4.0': dependencies: '@babel/code-frame': 7.26.2 - '@babel/runtime': 7.26.9 + '@babel/runtime': 7.27.0 '@types/aria-query': 5.0.4 aria-query: 5.3.0 chalk: 4.1.2 @@ -3045,7 +3045,7 @@ snapshots: '@testing-library/react@16.2.0(@testing-library/dom@10.4.0)(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': dependencies: - '@babel/runtime': 7.26.9 + '@babel/runtime': 7.27.0 '@testing-library/dom': 10.4.0 react: 19.0.0 react-dom: 19.0.0(react@19.0.0) From 983b3f3f0a7e4aa1a2b70f2cde1e106e477bf90d Mon Sep 17 00:00:00 2001 From: Marios Tsigkas Date: Thu, 27 Mar 2025 19:18:05 +0200 Subject: [PATCH 37/96] Update GitHub Actions workflow to set permissions for pull requests and read access --- .github/workflows/deploy.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index eea21bee..4a3bcef6 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -6,6 +6,10 @@ on: pull_request: branches: [ main ] +# Default permissions for all jobs +permissions: + contents: read + # Define common steps as an anchor x-common-steps: &common-steps - name: Checkout Repository From d20958c8c9721898f6d8cf02644fd565ca7a3612 Mon Sep 17 00:00:00 2001 From: Marios Tsigkas Date: Thu, 27 Mar 2025 19:26:37 +0200 Subject: [PATCH 38/96] Refactor GitHub Actions workflow to use a composite action for shared setup commands --- .github/actions/setup.yml | 8 ++++++++ .github/workflows/deploy.yml | 30 ++++++++++++------------------ 2 files changed, 20 insertions(+), 18 deletions(-) create mode 100644 .github/actions/setup.yml diff --git a/.github/actions/setup.yml b/.github/actions/setup.yml new file mode 100644 index 00000000..6e285a0f --- /dev/null +++ b/.github/actions/setup.yml @@ -0,0 +1,8 @@ +name: "My Composite Action" +description: "Runs shared setup commands for CI jobs" +inputs: {} +runs: + using: "composite" + steps: + - name: Setup Environment + run: bash scripts/setup.sh diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 4a3bcef6..a036e7ad 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -6,34 +6,27 @@ on: pull_request: branches: [ main ] -# Default permissions for all jobs permissions: contents: read -# Define common steps as an anchor -x-common-steps: &common-steps - - name: Checkout Repository - uses: actions/checkout@v3 - - name: Setup Node.js - uses: actions/setup-node@v3 - with: - node-version: '22' - cache: 'pnpm' - - name: Setup Environment - run: bash scripts/setup.sh - jobs: vitest: runs-on: ubuntu-latest steps: - <<: *common-steps + - name: Checkout Repository + uses: actions/checkout@v3 + - name: Run Composite Action + uses: ./.github/actions/setup.yml - name: Run Vitest Tests run: pnpm test cypress: runs-on: ubuntu-latest steps: - <<: *common-steps + - name: Checkout Repository + uses: actions/checkout@v3 + - name: Run Composite Action + uses: ./.github/actions/setup.yml - name: Run Cypress Tests run: pnpm cypress:run @@ -41,9 +34,10 @@ jobs: runs-on: ubuntu-latest needs: [vitest, cypress] steps: - <<: *common-steps - - name: Build Application - run: pnpm build + - name: Checkout Repository + uses: actions/checkout@v3 + - name: Run Composite Action + uses: ./.github/actions/setup.yml - name: Deploy to GitHub Pages run: pnpm deploy env: From c9a92638cc801852bc41a6f3df3c14d001592fd3 Mon Sep 17 00:00:00 2001 From: Marios Tsigkas Date: Thu, 27 Mar 2025 19:31:06 +0200 Subject: [PATCH 39/96] Refactor GitHub Actions setup by moving composite action to a dedicated directory --- .github/actions/{setup.yml => setup/action.yml} | 0 .github/workflows/deploy.yml | 6 +++--- 2 files changed, 3 insertions(+), 3 deletions(-) rename .github/actions/{setup.yml => setup/action.yml} (100%) diff --git a/.github/actions/setup.yml b/.github/actions/setup/action.yml similarity index 100% rename from .github/actions/setup.yml rename to .github/actions/setup/action.yml diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index a036e7ad..7928f343 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -16,7 +16,7 @@ jobs: - name: Checkout Repository uses: actions/checkout@v3 - name: Run Composite Action - uses: ./.github/actions/setup.yml + uses: ./.github/actions/setup - name: Run Vitest Tests run: pnpm test @@ -26,7 +26,7 @@ jobs: - name: Checkout Repository uses: actions/checkout@v3 - name: Run Composite Action - uses: ./.github/actions/setup.yml + uses: ./.github/actions/setup - name: Run Cypress Tests run: pnpm cypress:run @@ -37,7 +37,7 @@ jobs: - name: Checkout Repository uses: actions/checkout@v3 - name: Run Composite Action - uses: ./.github/actions/setup.yml + uses: ./.github/actions/setup - name: Deploy to GitHub Pages run: pnpm deploy env: From 2ffb7aa05b9871201bc2600dc54c2f30f7ef37de Mon Sep 17 00:00:00 2001 From: Marios Tsigkas Date: Thu, 27 Mar 2025 19:40:04 +0200 Subject: [PATCH 40/96] Refactor GitHub Actions deploy workflow to use a common anchor for checkout steps --- .github/workflows/deploy.yml | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 7928f343..14f1d511 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -9,24 +9,25 @@ on: permissions: contents: read +# Define a common anchor for the checkout step +x-checkout: &default-checkout + - name: Checkout Repository + uses: actions/checkout@v3 + - name: Setup Environment + run: bash scripts/setup.sh + jobs: vitest: runs-on: ubuntu-latest steps: - - name: Checkout Repository - uses: actions/checkout@v3 - - name: Run Composite Action - uses: ./.github/actions/setup + - *default-checkout - name: Run Vitest Tests run: pnpm test cypress: runs-on: ubuntu-latest steps: - - name: Checkout Repository - uses: actions/checkout@v3 - - name: Run Composite Action - uses: ./.github/actions/setup + - *default-checkout - name: Run Cypress Tests run: pnpm cypress:run @@ -34,10 +35,7 @@ jobs: runs-on: ubuntu-latest needs: [vitest, cypress] steps: - - name: Checkout Repository - uses: actions/checkout@v3 - - name: Run Composite Action - uses: ./.github/actions/setup + - *default-checkout - name: Deploy to GitHub Pages run: pnpm deploy env: From 0c5e7a71286d5b180e86222391755ab7414850d9 Mon Sep 17 00:00:00 2001 From: Marios Tsigkas Date: Thu, 27 Mar 2025 19:47:41 +0200 Subject: [PATCH 41/96] Refactor GitHub Actions workflow to consolidate checkout steps and streamline job dependencies --- .github/workflows/deploy.yml | 23 +++++++++++++---------- scripts/setup.sh | 1 - 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 14f1d511..b67208bd 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -9,30 +9,33 @@ on: permissions: contents: read -# Define a common anchor for the checkout step -x-checkout: &default-checkout - - name: Checkout Repository - uses: actions/checkout@v3 - - name: Setup Environment - run: bash scripts/setup.sh - jobs: + setup: + runs-on: &runs_on ubuntu-latest + steps: + - &default-checkout + - name: Checkout Repository + uses: actions/checkout@v3 + - name: Setup Environment + run: bash scripts/setup.sh vitest: - runs-on: ubuntu-latest + needs: setup + runs-on: *runs_on steps: - *default-checkout - name: Run Vitest Tests run: pnpm test cypress: - runs-on: ubuntu-latest + needs: setup + runs-on: *runs_on steps: - *default-checkout - name: Run Cypress Tests run: pnpm cypress:run build-deploy: - runs-on: ubuntu-latest + runs-on: *runs_on needs: [vitest, cypress] steps: - *default-checkout diff --git a/scripts/setup.sh b/scripts/setup.sh index 6bc28954..49d9039c 100644 --- a/scripts/setup.sh +++ b/scripts/setup.sh @@ -1,4 +1,3 @@ #!/bin/bash -# Shared setup commands for CI jobs npm install -g pnpm pnpm install From ae8e863654c6b09162f0330190f09d9b83c56d38 Mon Sep 17 00:00:00 2001 From: Marios Tsigkas Date: Thu, 27 Mar 2025 20:02:55 +0200 Subject: [PATCH 42/96] Refactor GitHub Actions deploy workflow to use explicit checkout steps --- .github/workflows/deploy.yml | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index b67208bd..609c7182 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -19,26 +19,33 @@ jobs: - name: Setup Environment run: bash scripts/setup.sh vitest: - needs: setup - runs-on: *runs_on + runs-on: ubuntu-latest steps: - - *default-checkout - - name: Run Vitest Tests - run: pnpm test + - name: checkout repository + uses: actions/checkout@v3 + - name: setup environment + run: bash scripts/setup.sh + - name: Run Vitest Tests + run: pnpm test cypress: - needs: setup - runs-on: *runs_on + runs-on: ubuntu-latest steps: - - *default-checkout + - name: checkout repository + uses: actions/checkout@v3 + - name: setup environment + run: bash scripts/setup.sh - name: Run Cypress Tests run: pnpm cypress:run build-deploy: - runs-on: *runs_on + runs-on: ubuntu-latest needs: [vitest, cypress] steps: - - *default-checkout + - name: checkout repository + uses: actions/checkout@v3 + - name: setup environment + run: bash scripts/setup.sh - name: Deploy to GitHub Pages run: pnpm deploy env: From ecf8fcffb8556630b9af1691e2535f594765651b Mon Sep 17 00:00:00 2001 From: Marios Tsigkas Date: Thu, 27 Mar 2025 20:03:56 +0200 Subject: [PATCH 43/96] Refactor GitHub Actions deploy workflow by removing redundant setup job --- .github/workflows/deploy.yml | 8 -------- 1 file changed, 8 deletions(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 609c7182..36a86c35 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -10,14 +10,6 @@ permissions: contents: read jobs: - setup: - runs-on: &runs_on ubuntu-latest - steps: - - &default-checkout - - name: Checkout Repository - uses: actions/checkout@v3 - - name: Setup Environment - run: bash scripts/setup.sh vitest: runs-on: ubuntu-latest steps: From 6aa31b098c394d5d90a4971ca4ef3a99999d03fa Mon Sep 17 00:00:00 2001 From: Marios Tsigkas Date: Thu, 27 Mar 2025 20:10:11 +0200 Subject: [PATCH 44/96] Update GitHub Actions workflow to use actions/checkout@v4 and replace Cypress test step with cypress-io/github-action --- .github/workflows/deploy.yml | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 36a86c35..e1723145 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -14,7 +14,7 @@ jobs: runs-on: ubuntu-latest steps: - name: checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: setup environment run: bash scripts/setup.sh - name: Run Vitest Tests @@ -24,18 +24,21 @@ jobs: runs-on: ubuntu-latest steps: - name: checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: setup environment run: bash scripts/setup.sh - - name: Run Cypress Tests - run: pnpm cypress:run + - name: Cypress run + uses: cypress-io/github-action@v6 + with: + build: pnpm build + start: pnpm start build-deploy: runs-on: ubuntu-latest needs: [vitest, cypress] steps: - name: checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: setup environment run: bash scripts/setup.sh - name: Deploy to GitHub Pages From b1e327069100649dc86ff531f0141ce8e5d5aa75 Mon Sep 17 00:00:00 2001 From: Marios Tsigkas Date: Thu, 27 Mar 2025 20:42:32 +0200 Subject: [PATCH 45/96] Add engines field to package.json specifying Node and pnpm versions --- package.json | 4 ++ pnpm-lock.yaml | 184 ++++++++++++++++++++++--------------------------- 2 files changed, 85 insertions(+), 103 deletions(-) diff --git a/package.json b/package.json index f967ba08..1b20c69e 100644 --- a/package.json +++ b/package.json @@ -48,5 +48,9 @@ "typescript-eslint": "^8.24.1", "vite": "^6.2.3", "vitest": "^3.0.8" + }, + "engines": { + "node": "^22", + "pnpm": ">= 6.13.4" } } \ No newline at end of file diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 046fee00..43c0005e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -134,10 +134,6 @@ packages: resolution: {integrity: sha512-VtPOkrdPHZsKc/clNqyi9WUA8TINkZ4cGk63UUE3u4pmB2k+ZMQRDuIOagv8UVd6j7k0T3+RRIb7beKTebNbcw==} engines: {node: '>=6.9.0'} - '@babel/runtime@7.27.0': - resolution: {integrity: sha512-VtPOkrdPHZsKc/clNqyi9WUA8TINkZ4cGk63UUE3u4pmB2k+ZMQRDuIOagv8UVd6j7k0T3+RRIb7beKTebNbcw==} - engines: {node: '>=6.9.0'} - '@babel/types@7.26.9': resolution: {integrity: sha512-Y3IR1cRnOxOCDvMmNiym7XpXQ93iGDDPHx+Zj+NM+rg0fBaShfQLkg+hKPaZCEvg5N/LeCo4+Rj/i3FuJsIQaw==} engines: {node: '>=6.9.0'} @@ -458,103 +454,98 @@ packages: resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} engines: {node: '>=14'} - '@rollup/rollup-android-arm-eabi@4.37.0': - resolution: {integrity: sha512-l7StVw6WAa8l3vA1ov80jyetOAEo1FtHvZDbzXDO/02Sq/QVvqlHkYoFwDJPIMj0GKiistsBudfx5tGFnwYWDQ==} + '@rollup/rollup-android-arm-eabi@4.35.0': + resolution: {integrity: sha512-uYQ2WfPaqz5QtVgMxfN6NpLD+no0MYHDBywl7itPYd3K5TjjSghNKmX8ic9S8NU8w81NVhJv/XojcHptRly7qQ==} cpu: [arm] os: [android] - '@rollup/rollup-android-arm64@4.37.0': - resolution: {integrity: sha512-6U3SlVyMxezt8Y+/iEBcbp945uZjJwjZimu76xoG7tO1av9VO691z8PkhzQ85ith2I8R2RddEPeSfcbyPfD4hA==} + '@rollup/rollup-android-arm64@4.35.0': + resolution: {integrity: sha512-FtKddj9XZudurLhdJnBl9fl6BwCJ3ky8riCXjEw3/UIbjmIY58ppWwPEvU3fNu+W7FUsAsB1CdH+7EQE6CXAPA==} cpu: [arm64] os: [android] - '@rollup/rollup-darwin-arm64@4.37.0': - resolution: {integrity: sha512-+iTQ5YHuGmPt10NTzEyMPbayiNTcOZDWsbxZYR1ZnmLnZxG17ivrPSWFO9j6GalY0+gV3Jtwrrs12DBscxnlYA==} + '@rollup/rollup-darwin-arm64@4.35.0': + resolution: {integrity: sha512-Uk+GjOJR6CY844/q6r5DR/6lkPFOw0hjfOIzVx22THJXMxktXG6CbejseJFznU8vHcEBLpiXKY3/6xc+cBm65Q==} cpu: [arm64] os: [darwin] - '@rollup/rollup-darwin-x64@4.37.0': - resolution: {integrity: sha512-m8W2UbxLDcmRKVjgl5J/k4B8d7qX2EcJve3Sut7YGrQoPtCIQGPH5AMzuFvYRWZi0FVS0zEY4c8uttPfX6bwYQ==} + '@rollup/rollup-darwin-x64@4.35.0': + resolution: {integrity: sha512-3IrHjfAS6Vkp+5bISNQnPogRAW5GAV1n+bNCrDwXmfMHbPl5EhTmWtfmwlJxFRUCBZ+tZ/OxDyU08aF6NI/N5Q==} cpu: [x64] os: [darwin] - '@rollup/rollup-freebsd-arm64@4.37.0': - resolution: {integrity: sha512-FOMXGmH15OmtQWEt174v9P1JqqhlgYge/bUjIbiVD1nI1NeJ30HYT9SJlZMqdo1uQFyt9cz748F1BHghWaDnVA==} + '@rollup/rollup-freebsd-arm64@4.35.0': + resolution: {integrity: sha512-sxjoD/6F9cDLSELuLNnY0fOrM9WA0KrM0vWm57XhrIMf5FGiN8D0l7fn+bpUeBSU7dCgPV2oX4zHAsAXyHFGcQ==} cpu: [arm64] os: [freebsd] - '@rollup/rollup-freebsd-x64@4.37.0': - resolution: {integrity: sha512-SZMxNttjPKvV14Hjck5t70xS3l63sbVwl98g3FlVVx2YIDmfUIy29jQrsw06ewEYQ8lQSuY9mpAPlmgRD2iSsA==} + '@rollup/rollup-freebsd-x64@4.35.0': + resolution: {integrity: sha512-2mpHCeRuD1u/2kruUiHSsnjWtHjqVbzhBkNVQ1aVD63CcexKVcQGwJ2g5VphOd84GvxfSvnnlEyBtQCE5hxVVw==} cpu: [x64] os: [freebsd] - '@rollup/rollup-linux-arm-gnueabihf@4.37.0': - resolution: {integrity: sha512-hhAALKJPidCwZcj+g+iN+38SIOkhK2a9bqtJR+EtyxrKKSt1ynCBeqrQy31z0oWU6thRZzdx53hVgEbRkuI19w==} + '@rollup/rollup-linux-arm-gnueabihf@4.35.0': + resolution: {integrity: sha512-mrA0v3QMy6ZSvEuLs0dMxcO2LnaCONs1Z73GUDBHWbY8tFFocM6yl7YyMu7rz4zS81NDSqhrUuolyZXGi8TEqg==} cpu: [arm] os: [linux] - '@rollup/rollup-linux-arm-musleabihf@4.37.0': - resolution: {integrity: sha512-jUb/kmn/Gd8epbHKEqkRAxq5c2EwRt0DqhSGWjPFxLeFvldFdHQs/n8lQ9x85oAeVb6bHcS8irhTJX2FCOd8Ag==} + '@rollup/rollup-linux-arm-musleabihf@4.35.0': + resolution: {integrity: sha512-DnYhhzcvTAKNexIql8pFajr0PiDGrIsBYPRvCKlA5ixSS3uwo/CWNZxB09jhIapEIg945KOzcYEAGGSmTSpk7A==} cpu: [arm] os: [linux] - '@rollup/rollup-linux-arm64-gnu@4.37.0': - resolution: {integrity: sha512-oNrJxcQT9IcbcmKlkF+Yz2tmOxZgG9D9GRq+1OE6XCQwCVwxixYAa38Z8qqPzQvzt1FCfmrHX03E0pWoXm1DqA==} + '@rollup/rollup-linux-arm64-gnu@4.35.0': + resolution: {integrity: sha512-uagpnH2M2g2b5iLsCTZ35CL1FgyuzzJQ8L9VtlJ+FckBXroTwNOaD0z0/UF+k5K3aNQjbm8LIVpxykUOQt1m/A==} cpu: [arm64] os: [linux] - '@rollup/rollup-linux-arm64-musl@4.37.0': - resolution: {integrity: sha512-pfxLBMls+28Ey2enpX3JvjEjaJMBX5XlPCZNGxj4kdJyHduPBXtxYeb8alo0a7bqOoWZW2uKynhHxF/MWoHaGQ==} + '@rollup/rollup-linux-arm64-musl@4.35.0': + resolution: {integrity: sha512-XQxVOCd6VJeHQA/7YcqyV0/88N6ysSVzRjJ9I9UA/xXpEsjvAgDTgH3wQYz5bmr7SPtVK2TsP2fQ2N9L4ukoUg==} cpu: [arm64] os: [linux] - '@rollup/rollup-linux-loongarch64-gnu@4.37.0': - resolution: {integrity: sha512-yCE0NnutTC/7IGUq/PUHmoeZbIwq3KRh02e9SfFh7Vmc1Z7atuJRYWhRME5fKgT8aS20mwi1RyChA23qSyRGpA==} + '@rollup/rollup-linux-loongarch64-gnu@4.35.0': + resolution: {integrity: sha512-5pMT5PzfgwcXEwOaSrqVsz/LvjDZt+vQ8RT/70yhPU06PTuq8WaHhfT1LW+cdD7mW6i/J5/XIkX/1tCAkh1W6g==} cpu: [loong64] os: [linux] - '@rollup/rollup-linux-powerpc64le-gnu@4.37.0': - resolution: {integrity: sha512-NxcICptHk06E2Lh3a4Pu+2PEdZ6ahNHuK7o6Np9zcWkrBMuv21j10SQDJW3C9Yf/A/P7cutWoC/DptNLVsZ0VQ==} + '@rollup/rollup-linux-powerpc64le-gnu@4.35.0': + resolution: {integrity: sha512-c+zkcvbhbXF98f4CtEIP1EBA/lCic5xB0lToneZYvMeKu5Kamq3O8gqrxiYYLzlZH6E3Aq+TSW86E4ay8iD8EA==} cpu: [ppc64] os: [linux] - '@rollup/rollup-linux-riscv64-gnu@4.37.0': - resolution: {integrity: sha512-PpWwHMPCVpFZLTfLq7EWJWvrmEuLdGn1GMYcm5MV7PaRgwCEYJAwiN94uBuZev0/J/hFIIJCsYw4nLmXA9J7Pw==} + '@rollup/rollup-linux-riscv64-gnu@4.35.0': + resolution: {integrity: sha512-s91fuAHdOwH/Tad2tzTtPX7UZyytHIRR6V4+2IGlV0Cej5rkG0R61SX4l4y9sh0JBibMiploZx3oHKPnQBKe4g==} cpu: [riscv64] os: [linux] - '@rollup/rollup-linux-riscv64-musl@4.37.0': - resolution: {integrity: sha512-DTNwl6a3CfhGTAOYZ4KtYbdS8b+275LSLqJVJIrPa5/JuIufWWZ/QFvkxp52gpmguN95eujrM68ZG+zVxa8zHA==} - cpu: [riscv64] - os: [linux] - - '@rollup/rollup-linux-s390x-gnu@4.37.0': - resolution: {integrity: sha512-hZDDU5fgWvDdHFuExN1gBOhCuzo/8TMpidfOR+1cPZJflcEzXdCy1LjnklQdW8/Et9sryOPJAKAQRw8Jq7Tg+A==} + '@rollup/rollup-linux-s390x-gnu@4.35.0': + resolution: {integrity: sha512-hQRkPQPLYJZYGP+Hj4fR9dDBMIM7zrzJDWFEMPdTnTy95Ljnv0/4w/ixFw3pTBMEuuEuoqtBINYND4M7ujcuQw==} cpu: [s390x] os: [linux] - '@rollup/rollup-linux-x64-gnu@4.37.0': - resolution: {integrity: sha512-pKivGpgJM5g8dwj0ywBwe/HeVAUSuVVJhUTa/URXjxvoyTT/AxsLTAbkHkDHG7qQxLoW2s3apEIl26uUe08LVQ==} + '@rollup/rollup-linux-x64-gnu@4.35.0': + resolution: {integrity: sha512-Pim1T8rXOri+0HmV4CdKSGrqcBWX0d1HoPnQ0uw0bdp1aP5SdQVNBy8LjYncvnLgu3fnnCt17xjWGd4cqh8/hA==} cpu: [x64] os: [linux] - '@rollup/rollup-linux-x64-musl@4.37.0': - resolution: {integrity: sha512-E2lPrLKE8sQbY/2bEkVTGDEk4/49UYRVWgj90MY8yPjpnGBQ+Xi1Qnr7b7UIWw1NOggdFQFOLZ8+5CzCiz143w==} + '@rollup/rollup-linux-x64-musl@4.35.0': + resolution: {integrity: sha512-QysqXzYiDvQWfUiTm8XmJNO2zm9yC9P/2Gkrwg2dH9cxotQzunBHYr6jk4SujCTqnfGxduOmQcI7c2ryuW8XVg==} cpu: [x64] os: [linux] - '@rollup/rollup-win32-arm64-msvc@4.37.0': - resolution: {integrity: sha512-Jm7biMazjNzTU4PrQtr7VS8ibeys9Pn29/1bm4ph7CP2kf21950LgN+BaE2mJ1QujnvOc6p54eWWiVvn05SOBg==} + '@rollup/rollup-win32-arm64-msvc@4.35.0': + resolution: {integrity: sha512-OUOlGqPkVJCdJETKOCEf1mw848ZyJ5w50/rZ/3IBQVdLfR5jk/6Sr5m3iO2tdPgwo0x7VcncYuOvMhBWZq8ayg==} cpu: [arm64] os: [win32] - '@rollup/rollup-win32-ia32-msvc@4.37.0': - resolution: {integrity: sha512-e3/1SFm1OjefWICB2Ucstg2dxYDkDTZGDYgwufcbsxTHyqQps1UQf33dFEChBNmeSsTOyrjw2JJq0zbG5GF6RA==} + '@rollup/rollup-win32-ia32-msvc@4.35.0': + resolution: {integrity: sha512-2/lsgejMrtwQe44glq7AFFHLfJBPafpsTa6JvP2NGef/ifOa4KBoglVf7AKN7EV9o32evBPRqfg96fEHzWo5kw==} cpu: [ia32] os: [win32] - '@rollup/rollup-win32-x64-msvc@4.37.0': - resolution: {integrity: sha512-LWbXUBwn/bcLx2sSsqy7pK5o+Nr+VCoRoAohfJ5C/aBio9nfJmGQqHAhU6pwxV/RmyTk5AqdySma7uwWGlmeuA==} + '@rollup/rollup-win32-x64-msvc@4.35.0': + resolution: {integrity: sha512-PIQeY5XDkrOysbQblSW7v3l1MDZzkTEzAfTPkj5VAu3FW8fS4ynyLg2sINp0fp3SjZ8xkRYpLqoKcYqAkhU1dw==} cpu: [x64] os: [win32] @@ -665,9 +656,6 @@ packages: '@types/estree@1.0.6': resolution: {integrity: sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==} - '@types/estree@1.0.7': - resolution: {integrity: sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==} - '@types/json-schema@7.0.15': resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} @@ -2127,8 +2115,8 @@ packages: rfdc@1.4.1: resolution: {integrity: sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==} - rollup@4.37.0: - resolution: {integrity: sha512-iAtQy/L4QFU+rTJ1YUjXqJOJzuwEghqWzCEYD2FEghT7Gsy1VdABntrO4CLopA5IkflTyqNiLNwPcOJ3S7UKLg==} + rollup@4.35.0: + resolution: {integrity: sha512-kg6oI4g+vc41vePJyO6dHt/yl0Rz3Thv0kJeVQ3D1kS3E5XSuKbPc29G4IpT/Kv1KQwgHVcN+HtyS+HYLNSvQg==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true @@ -2620,10 +2608,6 @@ snapshots: dependencies: regenerator-runtime: 0.14.1 - '@babel/runtime@7.27.0': - dependencies: - regenerator-runtime: 0.14.1 - '@babel/types@7.26.9': dependencies: '@babel/helper-string-parser': 7.25.9 @@ -2929,64 +2913,61 @@ snapshots: '@pkgjs/parseargs@0.11.0': optional: true - '@rollup/rollup-android-arm-eabi@4.37.0': + '@rollup/rollup-android-arm-eabi@4.35.0': optional: true - '@rollup/rollup-android-arm64@4.37.0': + '@rollup/rollup-android-arm64@4.35.0': optional: true - '@rollup/rollup-darwin-arm64@4.37.0': + '@rollup/rollup-darwin-arm64@4.35.0': optional: true - '@rollup/rollup-darwin-x64@4.37.0': + '@rollup/rollup-darwin-x64@4.35.0': optional: true - '@rollup/rollup-freebsd-arm64@4.37.0': + '@rollup/rollup-freebsd-arm64@4.35.0': optional: true - '@rollup/rollup-freebsd-x64@4.37.0': + '@rollup/rollup-freebsd-x64@4.35.0': optional: true - '@rollup/rollup-linux-arm-gnueabihf@4.37.0': + '@rollup/rollup-linux-arm-gnueabihf@4.35.0': optional: true - '@rollup/rollup-linux-arm-musleabihf@4.37.0': + '@rollup/rollup-linux-arm-musleabihf@4.35.0': optional: true - '@rollup/rollup-linux-arm64-gnu@4.37.0': + '@rollup/rollup-linux-arm64-gnu@4.35.0': optional: true - '@rollup/rollup-linux-arm64-musl@4.37.0': + '@rollup/rollup-linux-arm64-musl@4.35.0': optional: true - '@rollup/rollup-linux-loongarch64-gnu@4.37.0': + '@rollup/rollup-linux-loongarch64-gnu@4.35.0': optional: true - '@rollup/rollup-linux-powerpc64le-gnu@4.37.0': + '@rollup/rollup-linux-powerpc64le-gnu@4.35.0': optional: true - '@rollup/rollup-linux-riscv64-gnu@4.37.0': + '@rollup/rollup-linux-riscv64-gnu@4.35.0': optional: true - '@rollup/rollup-linux-riscv64-musl@4.37.0': + '@rollup/rollup-linux-s390x-gnu@4.35.0': optional: true - '@rollup/rollup-linux-s390x-gnu@4.37.0': + '@rollup/rollup-linux-x64-gnu@4.35.0': optional: true - '@rollup/rollup-linux-x64-gnu@4.37.0': + '@rollup/rollup-linux-x64-musl@4.35.0': optional: true - '@rollup/rollup-linux-x64-musl@4.37.0': + '@rollup/rollup-win32-arm64-msvc@4.35.0': optional: true - '@rollup/rollup-win32-arm64-msvc@4.37.0': + '@rollup/rollup-win32-ia32-msvc@4.35.0': optional: true - '@rollup/rollup-win32-ia32-msvc@4.37.0': - optional: true - - '@rollup/rollup-win32-x64-msvc@4.37.0': + '@rollup/rollup-win32-x64-msvc@4.35.0': optional: true '@swc/core-darwin-arm64@1.11.8': @@ -3078,8 +3059,6 @@ snapshots: '@types/estree@1.0.6': {} - '@types/estree@1.0.7': {} - '@types/json-schema@7.0.15': {} '@types/node@16.18.126': {} @@ -3810,7 +3789,7 @@ snapshots: estree-walker@3.0.3: dependencies: - '@types/estree': 1.0.7 + '@types/estree': 1.0.6 esutils@2.0.3: {} @@ -4618,30 +4597,29 @@ snapshots: rfdc@1.4.1: {} - rollup@4.37.0: + rollup@4.35.0: dependencies: '@types/estree': 1.0.6 optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.37.0 - '@rollup/rollup-android-arm64': 4.37.0 - '@rollup/rollup-darwin-arm64': 4.37.0 - '@rollup/rollup-darwin-x64': 4.37.0 - '@rollup/rollup-freebsd-arm64': 4.37.0 - '@rollup/rollup-freebsd-x64': 4.37.0 - '@rollup/rollup-linux-arm-gnueabihf': 4.37.0 - '@rollup/rollup-linux-arm-musleabihf': 4.37.0 - '@rollup/rollup-linux-arm64-gnu': 4.37.0 - '@rollup/rollup-linux-arm64-musl': 4.37.0 - '@rollup/rollup-linux-loongarch64-gnu': 4.37.0 - '@rollup/rollup-linux-powerpc64le-gnu': 4.37.0 - '@rollup/rollup-linux-riscv64-gnu': 4.37.0 - '@rollup/rollup-linux-riscv64-musl': 4.37.0 - '@rollup/rollup-linux-s390x-gnu': 4.37.0 - '@rollup/rollup-linux-x64-gnu': 4.37.0 - '@rollup/rollup-linux-x64-musl': 4.37.0 - '@rollup/rollup-win32-arm64-msvc': 4.37.0 - '@rollup/rollup-win32-ia32-msvc': 4.37.0 - '@rollup/rollup-win32-x64-msvc': 4.37.0 + '@rollup/rollup-android-arm-eabi': 4.35.0 + '@rollup/rollup-android-arm64': 4.35.0 + '@rollup/rollup-darwin-arm64': 4.35.0 + '@rollup/rollup-darwin-x64': 4.35.0 + '@rollup/rollup-freebsd-arm64': 4.35.0 + '@rollup/rollup-freebsd-x64': 4.35.0 + '@rollup/rollup-linux-arm-gnueabihf': 4.35.0 + '@rollup/rollup-linux-arm-musleabihf': 4.35.0 + '@rollup/rollup-linux-arm64-gnu': 4.35.0 + '@rollup/rollup-linux-arm64-musl': 4.35.0 + '@rollup/rollup-linux-loongarch64-gnu': 4.35.0 + '@rollup/rollup-linux-powerpc64le-gnu': 4.35.0 + '@rollup/rollup-linux-riscv64-gnu': 4.35.0 + '@rollup/rollup-linux-s390x-gnu': 4.35.0 + '@rollup/rollup-linux-x64-gnu': 4.35.0 + '@rollup/rollup-linux-x64-musl': 4.35.0 + '@rollup/rollup-win32-arm64-msvc': 4.35.0 + '@rollup/rollup-win32-ia32-msvc': 4.35.0 + '@rollup/rollup-win32-x64-msvc': 4.35.0 fsevents: 2.3.3 rrweb-cssom@0.7.1: {} @@ -4974,7 +4952,7 @@ snapshots: dependencies: esbuild: 0.25.1 postcss: 8.5.3 - rollup: 4.37.0 + rollup: 4.35.0 optionalDependencies: '@types/node': 22.13.10 fsevents: 2.3.3 From 17d05b234f7524867ae839825956d8f26d486a27 Mon Sep 17 00:00:00 2001 From: Marios Tsigkas Date: Sat, 29 Mar 2025 13:19:54 +0200 Subject: [PATCH 46/96] Remove dependency on vitest and cypress from build-deploy job in GitHub Actions workflow --- .github/workflows/deploy.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index e1723145..63aeb069 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -35,7 +35,7 @@ jobs: build-deploy: runs-on: ubuntu-latest - needs: [vitest, cypress] + # needs: [vitest, cypress] steps: - name: checkout repository uses: actions/checkout@v4 From 93ba15d9091c79c023ef2904bf03e8518c018d9a Mon Sep 17 00:00:00 2001 From: Marios Tsigkas Date: Sat, 29 Mar 2025 13:38:14 +0200 Subject: [PATCH 47/96] Fix deploy command in GitHub Actions workflow to use 'pnpm run deploy' --- .github/workflows/deploy.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 63aeb069..8889e7ee 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -42,6 +42,6 @@ jobs: - name: setup environment run: bash scripts/setup.sh - name: Deploy to GitHub Pages - run: pnpm deploy + run: pnpm run deploy env: GHPAGES_TOKEN: ${{ secrets.GHPAGES_TOKEN }} From a072c3c4c189ceeb61eb9e918d42fdbeb525dd63 Mon Sep 17 00:00:00 2001 From: Marios Tsigkas Date: Sat, 29 Mar 2025 13:43:26 +0200 Subject: [PATCH 48/96] Refactor API calls to use cached axios instance and update and fix tests --- .../__snapshots__/axiosCached.test.ts.snap | 12 +++++ src/api/__tests__/axiosCached.test.ts | 29 +++++++++++ src/api/__tests__/catApi.test.ts | 48 +++++++++---------- src/api/axiosCached.ts | 7 +++ src/api/catApi.ts | 21 +++----- .../__snapshots__/Home.test.tsx.snap | 16 ++++++- 6 files changed, 92 insertions(+), 41 deletions(-) create mode 100644 src/api/__tests__/__snapshots__/axiosCached.test.ts.snap create mode 100644 src/api/__tests__/axiosCached.test.ts create mode 100644 src/api/axiosCached.ts diff --git a/src/api/__tests__/__snapshots__/axiosCached.test.ts.snap b/src/api/__tests__/__snapshots__/axiosCached.test.ts.snap new file mode 100644 index 00000000..beda8645 --- /dev/null +++ b/src/api/__tests__/__snapshots__/axiosCached.test.ts.snap @@ -0,0 +1,12 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`getAxios > should create a cached axios instance with axios and the correct ttl 1`] = ` +[ + { + "baseURL": "https://api.thecatapi.com/v1", + }, + { + "ttl": 3600000, + }, +] +`; diff --git a/src/api/__tests__/axiosCached.test.ts b/src/api/__tests__/axiosCached.test.ts new file mode 100644 index 00000000..c1c8ab08 --- /dev/null +++ b/src/api/__tests__/axiosCached.test.ts @@ -0,0 +1,29 @@ +import { describe, it, expect, vi, beforeEach } from 'vitest' +import { setupCache } from 'axios-cache-interceptor' +import axios from 'axios' +vi.mock('axios') + +const mockedAxios = vi.mocked(axios, { deep: true }) +const mockedAxiosCreate = vi.fn(val => val) +mockedAxios.create = mockedAxiosCreate + +vi.mock('axios-cache-interceptor', () => ({ + setupCache: vi.fn(() => ({ + cached: true, + get: vi.fn(), + })), +})) + +beforeEach(() => { + vi.clearAllMocks() +}) + +describe('getAxios', () => { + it('should create a cached axios instance with axios and the correct ttl', async () => { + const { getAxios } = await import('../axiosCached.ts') + const cachedInstance = getAxios() + expect(cachedInstance).toHaveProperty('cached', true) + const calls = vi.mocked(setupCache).mock.calls[0] + expect(calls).toMatchSnapshot() + }) +}) diff --git a/src/api/__tests__/catApi.test.ts b/src/api/__tests__/catApi.test.ts index 60842e71..68a0fcad 100644 --- a/src/api/__tests__/catApi.test.ts +++ b/src/api/__tests__/catApi.test.ts @@ -1,13 +1,11 @@ import { describe, it, expect, vi, afterEach } from 'vitest' -import axios from 'axios' import { getRandomImages, getBreeds, getBreedImages, getImageById, getBreedById } from '../catApi' import { parseCatImages, parseBreeds } from '../parsers' +import { setupCache } from 'axios-cache-interceptor' -vi.mock('axios') - -const mockedAxios = vi.mocked(axios, { deep: true }) +vi.mock('axios-cache-interceptor', () => ({setupCache: vi.fn()})) const mockedAxiosGet = vi.fn() -mockedAxios.get = mockedAxiosGet +vi.mocked(setupCache).mockReturnValue({get: mockedAxiosGet}) describe('catApi', () => { const mockData = [ @@ -30,17 +28,17 @@ describe('catApi', () => { describe('getRandomImages', () => { it('should call the correct API endpoint', async () => { - mockedAxios.get.mockResolvedValue({ data: mockData }) + mockedAxiosGet.mockResolvedValue({ data: mockData }) await getRandomImages() expect(mockedAxiosGet).toHaveBeenCalledWith( - 'https://api.thecatapi.com/v1/images/search?limit=10', + '/images/search?limit=10', ) }) it('should return an array of cat images', async () => { - mockedAxios.get.mockResolvedValue({ data: mockData }) + mockedAxiosGet.mockResolvedValue({ data: mockData }) const images = await getRandomImages() @@ -48,7 +46,7 @@ describe('catApi', () => { }) it('should handle errors', async () => { - mockedAxios.get.mockRejectedValue(new Error('Failed to fetch')) + mockedAxiosGet.mockRejectedValue(new Error('Failed to fetch')) await expect(getRandomImages()).rejects.toThrow('Failed to fetch') }) @@ -56,7 +54,7 @@ describe('catApi', () => { describe('getBreeds', () => { it('should call the correct API endpoint', async () => { - mockedAxios.get.mockResolvedValue({ + mockedAxiosGet.mockResolvedValue({ data: [ { id: 'b1', @@ -69,7 +67,7 @@ describe('catApi', () => { await getBreeds() expect(mockedAxiosGet).toHaveBeenCalledWith( - 'https://api.thecatapi.com/v1/breeds', + '/breeds', ) }) @@ -81,7 +79,7 @@ describe('catApi', () => { description: 'Description 1', }, ] - mockedAxios.get.mockResolvedValue({ data: breedData }) + mockedAxiosGet.mockResolvedValue({ data: breedData }) const breeds = await getBreeds() @@ -89,7 +87,7 @@ describe('catApi', () => { }) it('should handle errors', async () => { - mockedAxios.get.mockRejectedValue(new Error('Failed to fetch')) + mockedAxiosGet.mockRejectedValue(new Error('Failed to fetch')) await expect(getBreeds()).rejects.toThrow('Failed to fetch') }) @@ -97,17 +95,17 @@ describe('catApi', () => { describe('getBreedImages', () => { it('should call the correct API endpoint', async () => { - mockedAxios.get.mockResolvedValue({ data: mockData }) + mockedAxiosGet.mockResolvedValue({ data: mockData }) await getBreedImages('b1') expect(mockedAxiosGet).toHaveBeenCalledWith( - 'https://api.thecatapi.com/v1/images/search?breed_ids=b1&limit=10', + '/images/search?breed_ids=b1&limit=10', ) }) it('should return an array of cat images for a specific breed', async () => { - mockedAxios.get.mockResolvedValue({ data: mockData }) + mockedAxiosGet.mockResolvedValue({ data: mockData }) const images = await getBreedImages('b1') @@ -115,7 +113,7 @@ describe('catApi', () => { }) it('should handle errors', async () => { - mockedAxios.get.mockRejectedValue(new Error('Failed to fetch')) + mockedAxiosGet.mockRejectedValue(new Error('Failed to fetch')) await expect(getBreedImages('b1')).rejects.toThrow('Failed to fetch') }) @@ -125,17 +123,17 @@ describe('catApi', () => { it('should call the correct API endpoint', async () => { const imageId = '2' const mockImage = { id: imageId, url: 'https://example.com/cat2.jpg' } - mockedAxios.get.mockResolvedValue({ data: mockImage }) + mockedAxiosGet.mockResolvedValue({ data: mockImage }) await getImageById(imageId) - expect(mockedAxiosGet).toHaveBeenCalledWith(`https://api.thecatapi.com/v1/images/${imageId}`) + expect(mockedAxiosGet).toHaveBeenCalledWith(`/images/${imageId}`) }) it('should return a cat image', async () => { const imageId = '2' const mockImage = { id: imageId, url: 'https://example.com/cat2.jpg' } - mockedAxios.get.mockResolvedValue({ data: mockImage }) + mockedAxiosGet.mockResolvedValue({ data: mockImage }) const image = await getImageById(imageId) @@ -144,7 +142,7 @@ describe('catApi', () => { it('should handle errors', async () => { const imageId = '2' - mockedAxios.get.mockRejectedValue(new Error('Failed to fetch')) + mockedAxiosGet.mockRejectedValue(new Error('Failed to fetch')) await expect(getImageById(imageId)).rejects.toThrow('Failed to fetch') }) @@ -154,17 +152,17 @@ describe('catApi', () => { it('should call the correct API endpoint', async () => { const breedId = 'b2' const mockBreed = { id: breedId, name: 'Breed 2', description: 'Description 2' } - mockedAxios.get.mockResolvedValue({ data: mockBreed }) + mockedAxiosGet.mockResolvedValue({ data: mockBreed }) await getBreedById(breedId) - expect(mockedAxiosGet).toHaveBeenCalledWith(`https://api.thecatapi.com/v1/breeds/${breedId}`) + expect(mockedAxiosGet).toHaveBeenCalledWith(`/breeds/${breedId}`) }) it('should return a breed', async () => { const breedId = 'b2' const mockBreed = { id: breedId, name: 'Breed 2', description: 'Description 2' } - mockedAxios.get.mockResolvedValue({ data: mockBreed }) + mockedAxiosGet.mockResolvedValue({ data: mockBreed }) const breed = await getBreedById(breedId) @@ -173,7 +171,7 @@ describe('catApi', () => { it('should handle errors', async () => { const breedId = 'b2' - mockedAxios.get.mockRejectedValue(new Error('Failed to fetch')) + mockedAxiosGet.mockRejectedValue(new Error('Failed to fetch')) await expect(getBreedById(breedId)).rejects.toThrow('Failed to fetch') }) diff --git a/src/api/axiosCached.ts b/src/api/axiosCached.ts new file mode 100644 index 00000000..643107b0 --- /dev/null +++ b/src/api/axiosCached.ts @@ -0,0 +1,7 @@ +import axios from 'axios' +import { setupCache } from 'axios-cache-interceptor' + +const BASE_URL = 'https://api.thecatapi.com/v1' +const axiosInstance = axios.create({ baseURL: BASE_URL }) + +export const getAxios = () => setupCache(axiosInstance, { ttl: 60 * 60 * 1000 }) \ No newline at end of file diff --git a/src/api/catApi.ts b/src/api/catApi.ts index 0e56316c..2c839280 100644 --- a/src/api/catApi.ts +++ b/src/api/catApi.ts @@ -1,37 +1,28 @@ -import axios from 'axios' import { parseCatImages, parseBreeds } from './parsers' import { CatImage, Breed } from './types' -import { setupCache } from 'axios-cache-interceptor'; - -const BASE_URL = 'https://api.thecatapi.com/v1' - -const axiosInstance = axios.create({ - baseURL: BASE_URL, -}); - -const axiosCached = setupCache(axiosInstance, { ttl: 60 * 60 * 1000 }) +import { getAxios } from './axiosCached' export const getRandomImages = async (limit = 10): Promise => { - const res = await axiosCached.get(`/images/search?limit=${limit.toString()}`) + const res = await getAxios().get(`/images/search?limit=${limit.toString()}`) return parseCatImages(res.data) } export const getBreeds = async (): Promise => { - const res = await axiosCached.get(`/breeds`) + const res = await getAxios().get(`/breeds`) return parseBreeds(res.data) } export const getBreedImages = async (breedId: string, limit = 10): Promise => { - const res = await axiosCached.get(`/images/search?breed_ids=${breedId}&limit=${limit.toString()}`) + const res = await getAxios().get(`/images/search?breed_ids=${breedId}&limit=${limit.toString()}`) return parseCatImages(res.data) } export const getImageById = async (imageId: string): Promise => { - const res = await axiosCached.get(`/images/${imageId}`) + const res = await getAxios().get(`/images/${imageId}`) return parseCatImages([res.data])[0] } export const getBreedById = async (breedId: string): Promise => { - const res = await axiosCached.get(`/breeds/${breedId}`) + const res = await getAxios().get(`/breeds/${breedId}`) return parseBreeds([res.data])[0] } diff --git a/src/views/__tests__/__snapshots__/Home.test.tsx.snap b/src/views/__tests__/__snapshots__/Home.test.tsx.snap index c4363e66..e4d82ad7 100644 --- a/src/views/__tests__/__snapshots__/Home.test.tsx.snap +++ b/src/views/__tests__/__snapshots__/Home.test.tsx.snap @@ -1,3 +1,17 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html -exports[`Home > should have the same snapshot as befoere 1`] = `undefined`; +exports[`Home > should have the same snapshot as befoere 1`] = ` + +
    +
    +

    + Random Cats +

    + 0 +

    + Loading... +

    +
    +
    + +`; From bfea109f0f8465c3d85120bf9cb59af587e47c82 Mon Sep 17 00:00:00 2001 From: Marios Tsigkas Date: Sat, 29 Mar 2025 13:44:57 +0200 Subject: [PATCH 49/96] Add vitest to needs of depployment --- .github/workflows/deploy.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 8889e7ee..96ac9ed7 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -35,7 +35,7 @@ jobs: build-deploy: runs-on: ubuntu-latest - # needs: [vitest, cypress] + needs: [vitest] # , cypress steps: - name: checkout repository uses: actions/checkout@v4 From 99145dc787e43ccc25c471950e383f19529ce361 Mon Sep 17 00:00:00 2001 From: Marios Tsigkas Date: Sat, 29 Mar 2025 13:51:00 +0200 Subject: [PATCH 50/96] Transform tests to js --- .../__tests__/__snapshots__/axiosCached.test.js.snap | 12 ++++++++++++ .../{axiosCached.test.ts => axiosCached.test.js} | 0 src/api/__tests__/{catApi.test.ts => catApi.test.js} | 0 3 files changed, 12 insertions(+) create mode 100644 src/api/__tests__/__snapshots__/axiosCached.test.js.snap rename src/api/__tests__/{axiosCached.test.ts => axiosCached.test.js} (100%) rename src/api/__tests__/{catApi.test.ts => catApi.test.js} (100%) diff --git a/src/api/__tests__/__snapshots__/axiosCached.test.js.snap b/src/api/__tests__/__snapshots__/axiosCached.test.js.snap new file mode 100644 index 00000000..beda8645 --- /dev/null +++ b/src/api/__tests__/__snapshots__/axiosCached.test.js.snap @@ -0,0 +1,12 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`getAxios > should create a cached axios instance with axios and the correct ttl 1`] = ` +[ + { + "baseURL": "https://api.thecatapi.com/v1", + }, + { + "ttl": 3600000, + }, +] +`; diff --git a/src/api/__tests__/axiosCached.test.ts b/src/api/__tests__/axiosCached.test.js similarity index 100% rename from src/api/__tests__/axiosCached.test.ts rename to src/api/__tests__/axiosCached.test.js diff --git a/src/api/__tests__/catApi.test.ts b/src/api/__tests__/catApi.test.js similarity index 100% rename from src/api/__tests__/catApi.test.ts rename to src/api/__tests__/catApi.test.js From 931a20b96b569c5dc681aa06ba5518eb4ee8fc33 Mon Sep 17 00:00:00 2001 From: Marios Tsigkas Date: Sat, 29 Mar 2025 13:54:25 +0200 Subject: [PATCH 51/96] Update deployment workflow to use Ubuntu 22 --- .github/workflows/deploy.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 96ac9ed7..140ad99c 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -34,7 +34,7 @@ jobs: start: pnpm start build-deploy: - runs-on: ubuntu-latest + runs-on: ubuntu-22 needs: [vitest] # , cypress steps: - name: checkout repository From d2d6aa210609e02386cbbcec972614cf90590209 Mon Sep 17 00:00:00 2001 From: Marios Tsigkas Date: Sat, 29 Mar 2025 14:04:28 +0200 Subject: [PATCH 52/96] Add Cypress binary installation step to deployment workflow --- .github/workflows/deploy.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 140ad99c..f26c4783 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -27,6 +27,8 @@ jobs: uses: actions/checkout@v4 - name: setup environment run: bash scripts/setup.sh + - name: Install Cypress Binary + run: npx cypress install - name: Cypress run uses: cypress-io/github-action@v6 with: From 8b1cf48a081745cfafbc0283613addb3ab685f20 Mon Sep 17 00:00:00 2001 From: Marios Tsigkas Date: Sat, 29 Mar 2025 14:07:48 +0200 Subject: [PATCH 53/96] Update deployment workflow to use Ubuntu 22 for all jobs and adjust Cypress start command --- .github/workflows/deploy.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index f26c4783..6709c0e5 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -11,7 +11,7 @@ permissions: jobs: vitest: - runs-on: ubuntu-latest + runs-on: ubuntu-22 steps: - name: checkout repository uses: actions/checkout@v4 @@ -21,7 +21,7 @@ jobs: run: pnpm test cypress: - runs-on: ubuntu-latest + runs-on: ubuntu-22 steps: - name: checkout repository uses: actions/checkout@v4 @@ -33,7 +33,7 @@ jobs: uses: cypress-io/github-action@v6 with: build: pnpm build - start: pnpm start + start: pnpm preview build-deploy: runs-on: ubuntu-22 From a8eb86acdba4a2dd8a63ebfd35850ce41d3ca427 Mon Sep 17 00:00:00 2001 From: Marios Tsigkas Date: Sat, 29 Mar 2025 14:14:41 +0200 Subject: [PATCH 54/96] Update deployment workflow to use ubuntu-latest for all jobs to unblock the actions --- .github/workflows/deploy.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 6709c0e5..40664066 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -11,7 +11,7 @@ permissions: jobs: vitest: - runs-on: ubuntu-22 + runs-on: ubuntu-latest steps: - name: checkout repository uses: actions/checkout@v4 @@ -21,7 +21,7 @@ jobs: run: pnpm test cypress: - runs-on: ubuntu-22 + runs-on: ubuntu-latest steps: - name: checkout repository uses: actions/checkout@v4 @@ -36,7 +36,7 @@ jobs: start: pnpm preview build-deploy: - runs-on: ubuntu-22 + runs-on: ubuntu-latest needs: [vitest] # , cypress steps: - name: checkout repository From 3ddfeaa23e7e8037ad3436625ee24f80dbdc22b4 Mon Sep 17 00:00:00 2001 From: Marios Tsigkas Date: Sat, 29 Mar 2025 14:34:09 +0200 Subject: [PATCH 55/96] Update deployment workflow to use Ubuntu 22.04 for all jobs --- .github/workflows/deploy.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 40664066..8f158432 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -11,7 +11,7 @@ permissions: jobs: vitest: - runs-on: ubuntu-latest + runs-on: ubuntu-22.04 steps: - name: checkout repository uses: actions/checkout@v4 @@ -21,7 +21,7 @@ jobs: run: pnpm test cypress: - runs-on: ubuntu-latest + runs-on: ubuntu-22.04 steps: - name: checkout repository uses: actions/checkout@v4 @@ -36,7 +36,7 @@ jobs: start: pnpm preview build-deploy: - runs-on: ubuntu-latest + runs-on: ubuntu-22.04 needs: [vitest] # , cypress steps: - name: checkout repository From 86817002185bc338a93ceba7e311503c347c3ee6 Mon Sep 17 00:00:00 2001 From: Marios Tsigkas Date: Sat, 29 Mar 2025 14:35:13 +0200 Subject: [PATCH 56/96] Update Cypress start command to specify port 5173 in deployment workflow --- .github/workflows/deploy.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 8f158432..7b428154 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -33,7 +33,7 @@ jobs: uses: cypress-io/github-action@v6 with: build: pnpm build - start: pnpm preview + start: pnpm preview --port 5173 build-deploy: runs-on: ubuntu-22.04 From 81834de63419bca723ef5a36eadf64f56367b6bd Mon Sep 17 00:00:00 2001 From: Marios Tsigkas Date: Sun, 30 Mar 2025 14:14:20 +0300 Subject: [PATCH 57/96] Set Git commit identity in deployment workflow --- .github/workflows/deploy.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 7b428154..428f253e 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -43,6 +43,10 @@ jobs: uses: actions/checkout@v4 - name: setup environment run: bash scripts/setup.sh + - name: Set Git Commit Identity + run: | + git config --global user.email "mariosh346@gmail.com" + git config --global user.name "Marios Tsigkas" - name: Deploy to GitHub Pages run: pnpm run deploy env: From c46760a83414807ced10d85be64c22d33807de7e Mon Sep 17 00:00:00 2001 From: Marios Tsigkas Date: Sun, 30 Mar 2025 14:29:04 +0300 Subject: [PATCH 58/96] Add cypress/screenshots/ to .gitignore --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 4e22b9b8..19b3182b 100644 --- a/.gitignore +++ b/.gitignore @@ -17,6 +17,8 @@ dist-ssr *.avi *.mkv +cypress/screenshots/ + # Editor directories and files .vscode/* !.vscode/extensions.json From 540e743f049eb0b9f4107412111681ec6da68076 Mon Sep 17 00:00:00 2001 From: Marios Tsigkas Date: Sun, 30 Mar 2025 14:40:14 +0300 Subject: [PATCH 59/96] Refactor axios caching setup to use a dedicated getAxios function --- src/api/__tests__/catApi.test.js | 6 +++--- src/api/axiosCached.ts | 4 +++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/api/__tests__/catApi.test.js b/src/api/__tests__/catApi.test.js index 68a0fcad..9659e95f 100644 --- a/src/api/__tests__/catApi.test.js +++ b/src/api/__tests__/catApi.test.js @@ -1,11 +1,11 @@ import { describe, it, expect, vi, afterEach } from 'vitest' import { getRandomImages, getBreeds, getBreedImages, getImageById, getBreedById } from '../catApi' import { parseCatImages, parseBreeds } from '../parsers' -import { setupCache } from 'axios-cache-interceptor' +import { getAxios } from '../axiosCached' -vi.mock('axios-cache-interceptor', () => ({setupCache: vi.fn()})) +vi.mock('../axiosCached', () => ({getAxios: vi.fn()})) const mockedAxiosGet = vi.fn() -vi.mocked(setupCache).mockReturnValue({get: mockedAxiosGet}) +vi.mocked(getAxios).mockReturnValue({get: mockedAxiosGet}) describe('catApi', () => { const mockData = [ diff --git a/src/api/axiosCached.ts b/src/api/axiosCached.ts index 643107b0..49412218 100644 --- a/src/api/axiosCached.ts +++ b/src/api/axiosCached.ts @@ -4,4 +4,6 @@ import { setupCache } from 'axios-cache-interceptor' const BASE_URL = 'https://api.thecatapi.com/v1' const axiosInstance = axios.create({ baseURL: BASE_URL }) -export const getAxios = () => setupCache(axiosInstance, { ttl: 60 * 60 * 1000 }) \ No newline at end of file +const axiosCached = setupCache(axiosInstance, { ttl: 60 * 60 * 1000 }) + +export const getAxios = () => axiosCached \ No newline at end of file From 988a7a9dd4203a9a5a6f2aa02d0221dc82ff4850 Mon Sep 17 00:00:00 2001 From: Marios Tsigkas Date: Sun, 30 Mar 2025 15:00:56 +0300 Subject: [PATCH 60/96] Refactor deployment workflow and remove obsolete test snapshot --- .github/workflows/deploy.yml | 28 +++++++++++++------ .../__snapshots__/axiosCached.test.ts.snap | 12 -------- 2 files changed, 20 insertions(+), 20 deletions(-) delete mode 100644 src/api/__tests__/__snapshots__/axiosCached.test.ts.snap diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 428f253e..847d2f7c 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -35,7 +35,7 @@ jobs: build: pnpm build start: pnpm preview --port 5173 - build-deploy: + build: runs-on: ubuntu-22.04 needs: [vitest] # , cypress steps: @@ -43,11 +43,23 @@ jobs: uses: actions/checkout@v4 - name: setup environment run: bash scripts/setup.sh - - name: Set Git Commit Identity - run: | - git config --global user.email "mariosh346@gmail.com" - git config --global user.name "Marios Tsigkas" + + deploy: + needs: build + + # Grant GITHUB_TOKEN the permissions required to make a Pages deployment + permissions: + pages: write # to deploy to Pages + id-token: write # to verify the deployment originates from an appropriate source + + # Deploy to the github-pages environment + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + + # Specify runner + deployment step + runs-on: ubuntu-latest + steps: - name: Deploy to GitHub Pages - run: pnpm run deploy - env: - GHPAGES_TOKEN: ${{ secrets.GHPAGES_TOKEN }} + id: deployment + uses: actions/deploy-pages@v4 diff --git a/src/api/__tests__/__snapshots__/axiosCached.test.ts.snap b/src/api/__tests__/__snapshots__/axiosCached.test.ts.snap deleted file mode 100644 index beda8645..00000000 --- a/src/api/__tests__/__snapshots__/axiosCached.test.ts.snap +++ /dev/null @@ -1,12 +0,0 @@ -// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html - -exports[`getAxios > should create a cached axios instance with axios and the correct ttl 1`] = ` -[ - { - "baseURL": "https://api.thecatapi.com/v1", - }, - { - "ttl": 3600000, - }, -] -`; From ed7aa41811762d86a5ca77041cd53588f895babc Mon Sep 17 00:00:00 2001 From: Marios Tsigkas Date: Sun, 30 Mar 2025 15:05:36 +0300 Subject: [PATCH 61/96] Create jekyll-gh-pages.yml --- .github/workflows/jekyll-gh-pages.yml | 51 +++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 .github/workflows/jekyll-gh-pages.yml diff --git a/.github/workflows/jekyll-gh-pages.yml b/.github/workflows/jekyll-gh-pages.yml new file mode 100644 index 00000000..e31d81c5 --- /dev/null +++ b/.github/workflows/jekyll-gh-pages.yml @@ -0,0 +1,51 @@ +# Sample workflow for building and deploying a Jekyll site to GitHub Pages +name: Deploy Jekyll with GitHub Pages dependencies preinstalled + +on: + # Runs on pushes targeting the default branch + push: + branches: ["main"] + + # Allows you to run this workflow manually from the Actions tab + workflow_dispatch: + +# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages +permissions: + contents: read + pages: write + id-token: write + +# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued. +# However, do NOT cancel in-progress runs as we want to allow these production deployments to complete. +concurrency: + group: "pages" + cancel-in-progress: false + +jobs: + # Build job + build: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Setup Pages + uses: actions/configure-pages@v5 + - name: Build with Jekyll + uses: actions/jekyll-build-pages@v1 + with: + source: ./ + destination: ./_site + - name: Upload artifact + uses: actions/upload-pages-artifact@v3 + + # Deployment job + deploy: + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + runs-on: ubuntu-latest + needs: build + steps: + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v4 From e6e7c316fb0248a5c61971c85f48b4ea9c8e8fe3 Mon Sep 17 00:00:00 2001 From: Marios Tsigkas Date: Sun, 30 Mar 2025 15:07:14 +0300 Subject: [PATCH 62/96] Update deployment workflow to use Ubuntu 22.04 runner --- .github/workflows/deploy.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 847d2f7c..bd59fca0 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -57,8 +57,7 @@ jobs: name: github-pages url: ${{ steps.deployment.outputs.page_url }} - # Specify runner + deployment step - runs-on: ubuntu-latest + runs-on: ubuntu-22.04 steps: - name: Deploy to GitHub Pages id: deployment From 4d1246da42b1a2c40d8d4e2e93d376704276b49e Mon Sep 17 00:00:00 2001 From: Marios Tsigkas Date: Sun, 30 Mar 2025 15:11:27 +0300 Subject: [PATCH 63/96] Update deployment workflows: add artifact upload step and remove obsolete Jekyll workflow --- .github/workflows/deploy.yml | 11 +++--- .github/workflows/jekyll-gh-pages.yml | 51 --------------------------- 2 files changed, 6 insertions(+), 56 deletions(-) delete mode 100644 .github/workflows/jekyll-gh-pages.yml diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index bd59fca0..2a3346a5 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -43,20 +43,21 @@ jobs: uses: actions/checkout@v4 - name: setup environment run: bash scripts/setup.sh + - name: Upload Artifact + uses: actions/upload-pages-artifact@v3 + with: + path: ./dist deploy: needs: build - # Grant GITHUB_TOKEN the permissions required to make a Pages deployment permissions: - pages: write # to deploy to Pages - id-token: write # to verify the deployment originates from an appropriate source + pages: write + id-token: write - # Deploy to the github-pages environment environment: name: github-pages url: ${{ steps.deployment.outputs.page_url }} - runs-on: ubuntu-22.04 steps: - name: Deploy to GitHub Pages diff --git a/.github/workflows/jekyll-gh-pages.yml b/.github/workflows/jekyll-gh-pages.yml deleted file mode 100644 index e31d81c5..00000000 --- a/.github/workflows/jekyll-gh-pages.yml +++ /dev/null @@ -1,51 +0,0 @@ -# Sample workflow for building and deploying a Jekyll site to GitHub Pages -name: Deploy Jekyll with GitHub Pages dependencies preinstalled - -on: - # Runs on pushes targeting the default branch - push: - branches: ["main"] - - # Allows you to run this workflow manually from the Actions tab - workflow_dispatch: - -# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages -permissions: - contents: read - pages: write - id-token: write - -# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued. -# However, do NOT cancel in-progress runs as we want to allow these production deployments to complete. -concurrency: - group: "pages" - cancel-in-progress: false - -jobs: - # Build job - build: - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v4 - - name: Setup Pages - uses: actions/configure-pages@v5 - - name: Build with Jekyll - uses: actions/jekyll-build-pages@v1 - with: - source: ./ - destination: ./_site - - name: Upload artifact - uses: actions/upload-pages-artifact@v3 - - # Deployment job - deploy: - environment: - name: github-pages - url: ${{ steps.deployment.outputs.page_url }} - runs-on: ubuntu-latest - needs: build - steps: - - name: Deploy to GitHub Pages - id: deployment - uses: actions/deploy-pages@v4 From 5787a595420c2fb99f218134e851c6569a91b119 Mon Sep 17 00:00:00 2001 From: Marios Tsigkas Date: Sun, 30 Mar 2025 15:22:21 +0300 Subject: [PATCH 64/96] Run build on build step: add manual trigger and concurrency settings --- .github/workflows/deploy.yml | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 2a3346a5..0485f712 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -3,12 +3,16 @@ name: CI & Deploy on: push: branches: [ main ] - pull_request: - branches: [ main ] + # Allows you to run this workflow manually from the Actions tab + workflow_dispatch: permissions: contents: read +concurrency: + group: "pages" + cancel-in-progress: false + jobs: vitest: runs-on: ubuntu-22.04 @@ -21,6 +25,7 @@ jobs: run: pnpm test cypress: + needs: build runs-on: ubuntu-22.04 steps: - name: checkout repository @@ -32,7 +37,6 @@ jobs: - name: Cypress run uses: cypress-io/github-action@v6 with: - build: pnpm build start: pnpm preview --port 5173 build: @@ -43,6 +47,8 @@ jobs: uses: actions/checkout@v4 - name: setup environment run: bash scripts/setup.sh + - name: build environment + run: pnpm build - name: Upload Artifact uses: actions/upload-pages-artifact@v3 with: From ca86d06821747f33c437ebeb7a9ca467f6173d08 Mon Sep 17 00:00:00 2001 From: Marios Tsigkas Date: Sun, 30 Mar 2025 15:26:06 +0300 Subject: [PATCH 65/96] Update deployment workflow: add artifact download step for distribution --- .github/workflows/deploy.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 0485f712..ad633451 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -32,6 +32,10 @@ jobs: uses: actions/checkout@v4 - name: setup environment run: bash scripts/setup.sh + - name: Download Artifact + uses: actions/download-pages-artifact@v3 + with: + path: ./dist - name: Install Cypress Binary run: npx cypress install - name: Cypress run From 3c3370aba78812c514162c8c488ee7d5cf99cf82 Mon Sep 17 00:00:00 2001 From: Marios Tsigkas Date: Sun, 30 Mar 2025 15:29:46 +0300 Subject: [PATCH 66/96] Update deployment workflow: downgrade artifact download action to v2 --- .github/workflows/deploy.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index ad633451..edcd9c26 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -33,7 +33,7 @@ jobs: - name: setup environment run: bash scripts/setup.sh - name: Download Artifact - uses: actions/download-pages-artifact@v3 + uses: actions/download-pages-artifact@v2 with: path: ./dist - name: Install Cypress Binary From e8e03c6dff4fc1e40138463ba9bb7d08217151ff Mon Sep 17 00:00:00 2001 From: Marios Tsigkas Date: Sun, 30 Mar 2025 15:41:44 +0300 Subject: [PATCH 67/96] Update deployment workflow: remove artifact download step and adjust Cypress run configuration --- .github/workflows/deploy.yml | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index edcd9c26..b50ea7e5 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -25,22 +25,18 @@ jobs: run: pnpm test cypress: - needs: build runs-on: ubuntu-22.04 steps: - name: checkout repository uses: actions/checkout@v4 - name: setup environment run: bash scripts/setup.sh - - name: Download Artifact - uses: actions/download-pages-artifact@v2 - with: - path: ./dist - name: Install Cypress Binary run: npx cypress install - name: Cypress run uses: cypress-io/github-action@v6 with: + build: pnpm build start: pnpm preview --port 5173 build: From fdb9acd17c867e38678596f164c5e1b34f9cfa42 Mon Sep 17 00:00:00 2001 From: Marios Tsigkas Date: Sun, 30 Mar 2025 15:57:49 +0300 Subject: [PATCH 68/96] Update deployment workflow: adjust GitHub Pages URL for platform-catApi-react --- .github/workflows/deploy.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index b50ea7e5..f70b11bb 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -63,7 +63,7 @@ jobs: environment: name: github-pages - url: ${{ steps.deployment.outputs.page_url }} + url: "${{ steps.deployment.outputs.page_url }}/platform-catApi-react/" runs-on: ubuntu-22.04 steps: - name: Deploy to GitHub Pages From cbbe65e8d2eb024dcc0b92e19eb7e8c1d3e73b86 Mon Sep 17 00:00:00 2001 From: Marios Tsigkas Date: Sun, 30 Mar 2025 16:05:03 +0300 Subject: [PATCH 69/96] Update deployment workflow: switch to ubuntu-latest and upgrade Node.js version --- .github/workflows/deploy.yml | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index f70b11bb..9d74dbbc 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -15,8 +15,11 @@ concurrency: jobs: vitest: - runs-on: ubuntu-22.04 + runs-on: ubuntu-latest steps: + - uses: actions/setup-node@v4 + with: + node-version: '22' - name: checkout repository uses: actions/checkout@v4 - name: setup environment @@ -25,8 +28,11 @@ jobs: run: pnpm test cypress: - runs-on: ubuntu-22.04 + runs-on: ubuntu-latest steps: + - uses: actions/setup-node@v4 + with: + node-version: '22' - name: checkout repository uses: actions/checkout@v4 - name: setup environment @@ -40,9 +46,12 @@ jobs: start: pnpm preview --port 5173 build: - runs-on: ubuntu-22.04 + runs-on: ubuntu-latest needs: [vitest] # , cypress steps: + - uses: actions/setup-node@v4 + with: + node-version: '22' - name: checkout repository uses: actions/checkout@v4 - name: setup environment @@ -64,7 +73,7 @@ jobs: environment: name: github-pages url: "${{ steps.deployment.outputs.page_url }}/platform-catApi-react/" - runs-on: ubuntu-22.04 + runs-on: ubuntu-latest steps: - name: Deploy to GitHub Pages id: deployment From ecb3cf6e90c5d6671db2beb292b9707546b0044e Mon Sep 17 00:00:00 2001 From: Marios Tsigkas Date: Sun, 30 Mar 2025 16:08:23 +0300 Subject: [PATCH 70/96] Update deployment workflow: use docker Node.js 22-alpine container for all jobs --- .github/workflows/deploy.yml | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 9d74dbbc..98eeba83 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -16,10 +16,9 @@ concurrency: jobs: vitest: runs-on: ubuntu-latest + container: + image: node:22-alpine steps: - - uses: actions/setup-node@v4 - with: - node-version: '22' - name: checkout repository uses: actions/checkout@v4 - name: setup environment @@ -29,10 +28,9 @@ jobs: cypress: runs-on: ubuntu-latest + container: + image: node:22-alpine steps: - - uses: actions/setup-node@v4 - with: - node-version: '22' - name: checkout repository uses: actions/checkout@v4 - name: setup environment @@ -47,11 +45,10 @@ jobs: build: runs-on: ubuntu-latest + container: + image: node:22-alpine needs: [vitest] # , cypress steps: - - uses: actions/setup-node@v4 - with: - node-version: '22' - name: checkout repository uses: actions/checkout@v4 - name: setup environment @@ -74,6 +71,8 @@ jobs: name: github-pages url: "${{ steps.deployment.outputs.page_url }}/platform-catApi-react/" runs-on: ubuntu-latest + container: + image: node:22-alpine steps: - name: Deploy to GitHub Pages id: deployment From c1af50fbd85e2eef023430ca725fe6074889120c Mon Sep 17 00:00:00 2001 From: Marios Tsigkas Date: Sun, 30 Mar 2025 16:44:50 +0300 Subject: [PATCH 71/96] Update deployment workflow: switch Node.js image from 22-alpine to 22 --- .github/workflows/deploy.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 98eeba83..b0d51b72 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -17,7 +17,7 @@ jobs: vitest: runs-on: ubuntu-latest container: - image: node:22-alpine + image: node:22 steps: - name: checkout repository uses: actions/checkout@v4 @@ -29,7 +29,7 @@ jobs: cypress: runs-on: ubuntu-latest container: - image: node:22-alpine + image: node:22 steps: - name: checkout repository uses: actions/checkout@v4 @@ -46,7 +46,7 @@ jobs: build: runs-on: ubuntu-latest container: - image: node:22-alpine + image: node:22 needs: [vitest] # , cypress steps: - name: checkout repository @@ -72,7 +72,7 @@ jobs: url: "${{ steps.deployment.outputs.page_url }}/platform-catApi-react/" runs-on: ubuntu-latest container: - image: node:22-alpine + image: node:22 steps: - name: Deploy to GitHub Pages id: deployment From 36306701556609e31aa6d236147f02d47af35cc2 Mon Sep 17 00:00:00 2001 From: Marios Tsigkas Date: Sun, 30 Mar 2025 16:45:59 +0300 Subject: [PATCH 72/96] Update deployment workflow: switch Node.js image to 22-alpine for all jobs and change bash to sh --- .github/workflows/deploy.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index b0d51b72..4b5a1f51 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -17,24 +17,24 @@ jobs: vitest: runs-on: ubuntu-latest container: - image: node:22 + image: node:22-alpine steps: - name: checkout repository uses: actions/checkout@v4 - name: setup environment - run: bash scripts/setup.sh + run: sh scripts/setup.sh - name: Run Vitest Tests run: pnpm test cypress: runs-on: ubuntu-latest container: - image: node:22 + image: node:22-alpine steps: - name: checkout repository uses: actions/checkout@v4 - name: setup environment - run: bash scripts/setup.sh + run: sh scripts/setup.sh - name: Install Cypress Binary run: npx cypress install - name: Cypress run @@ -46,13 +46,13 @@ jobs: build: runs-on: ubuntu-latest container: - image: node:22 + image: node:22-alpine needs: [vitest] # , cypress steps: - name: checkout repository uses: actions/checkout@v4 - name: setup environment - run: bash scripts/setup.sh + run: sh scripts/setup.sh - name: build environment run: pnpm build - name: Upload Artifact @@ -72,7 +72,7 @@ jobs: url: "${{ steps.deployment.outputs.page_url }}/platform-catApi-react/" runs-on: ubuntu-latest container: - image: node:22 + image: node:22-alpine steps: - name: Deploy to GitHub Pages id: deployment From 4d2dc729b4c2885c356c7436ec95e4b68e65ea59 Mon Sep 17 00:00:00 2001 From: Marios Tsigkas Date: Sun, 30 Mar 2025 17:43:40 +0300 Subject: [PATCH 73/96] Update deployment workflow: revert from docker to gh --- .github/workflows/deploy.yml | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 4b5a1f51..9d74dbbc 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -16,25 +16,27 @@ concurrency: jobs: vitest: runs-on: ubuntu-latest - container: - image: node:22-alpine steps: + - uses: actions/setup-node@v4 + with: + node-version: '22' - name: checkout repository uses: actions/checkout@v4 - name: setup environment - run: sh scripts/setup.sh + run: bash scripts/setup.sh - name: Run Vitest Tests run: pnpm test cypress: runs-on: ubuntu-latest - container: - image: node:22-alpine steps: + - uses: actions/setup-node@v4 + with: + node-version: '22' - name: checkout repository uses: actions/checkout@v4 - name: setup environment - run: sh scripts/setup.sh + run: bash scripts/setup.sh - name: Install Cypress Binary run: npx cypress install - name: Cypress run @@ -45,14 +47,15 @@ jobs: build: runs-on: ubuntu-latest - container: - image: node:22-alpine needs: [vitest] # , cypress steps: + - uses: actions/setup-node@v4 + with: + node-version: '22' - name: checkout repository uses: actions/checkout@v4 - name: setup environment - run: sh scripts/setup.sh + run: bash scripts/setup.sh - name: build environment run: pnpm build - name: Upload Artifact @@ -71,8 +74,6 @@ jobs: name: github-pages url: "${{ steps.deployment.outputs.page_url }}/platform-catApi-react/" runs-on: ubuntu-latest - container: - image: node:22-alpine steps: - name: Deploy to GitHub Pages id: deployment From 0da78d34061e71c0400f6e506394ee85a098a5bc Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 31 Mar 2025 18:54:08 +0000 Subject: [PATCH 74/96] Bump vite in the npm_and_yarn group across 1 directory Bumps the npm_and_yarn group with 1 update in the / directory: [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite). Updates `vite` from 6.2.3 to 6.2.4 - [Release notes](https://github.com/vitejs/vite/releases) - [Changelog](https://github.com/vitejs/vite/blob/v6.2.4/packages/vite/CHANGELOG.md) - [Commits](https://github.com/vitejs/vite/commits/v6.2.4/packages/vite) --- updated-dependencies: - dependency-name: vite dependency-type: direct:development dependency-group: npm_and_yarn ... Signed-off-by: dependabot[bot] --- package.json | 2 +- pnpm-lock.yaml | 412 +++++++++++++++++++++++++------------------------ 2 files changed, 214 insertions(+), 200 deletions(-) diff --git a/package.json b/package.json index 1b20c69e..ee1a6163 100644 --- a/package.json +++ b/package.json @@ -46,7 +46,7 @@ "tailwindcss": "^3.4.1", "typescript": "~5.7.2", "typescript-eslint": "^8.24.1", - "vite": "^6.2.3", + "vite": "^6.2.4", "vitest": "^3.0.8" }, "engines": { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 43c0005e..37bd6705 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -44,7 +44,7 @@ importers: version: 19.0.4(@types/react@19.0.10) '@vitejs/plugin-react-swc': specifier: ^3.8.0 - version: 3.8.0(vite@6.2.3(@types/node@22.13.10)(jiti@1.21.7)(yaml@2.7.0)) + version: 3.8.0(vite@6.2.4(@types/node@22.13.10)(jiti@1.21.7)(yaml@2.7.0)) '@vitest/coverage-v8': specifier: ^1.5.0 version: 1.6.1(vitest@3.0.8(@types/node@22.13.10)(jiti@1.21.7)(jsdom@24.1.3)(yaml@2.7.0)) @@ -91,8 +91,8 @@ importers: specifier: ^8.24.1 version: 8.26.0(eslint@9.22.0(jiti@1.21.7))(typescript@5.7.3) vite: - specifier: ^6.2.3 - version: 6.2.3(@types/node@22.13.10)(jiti@1.21.7)(yaml@2.7.0) + specifier: ^6.2.4 + version: 6.2.4(@types/node@22.13.10)(jiti@1.21.7)(yaml@2.7.0) vitest: specifier: ^3.0.8 version: 3.0.8(@types/node@22.13.10)(jiti@1.21.7)(jsdom@24.1.3)(yaml@2.7.0) @@ -180,152 +180,152 @@ packages: '@cypress/xvfb@1.2.4': resolution: {integrity: sha512-skbBzPggOVYCbnGgV+0dmBdW/s77ZkAOXIC1knS8NagwDjBrNC1LuXtQJeiN6l+m7lzmHtaoUw/ctJKdqkG57Q==} - '@esbuild/aix-ppc64@0.25.1': - resolution: {integrity: sha512-kfYGy8IdzTGy+z0vFGvExZtxkFlA4zAxgKEahG9KE1ScBjpQnFsNOX8KTU5ojNru5ed5CVoJYXFtoxaq5nFbjQ==} + '@esbuild/aix-ppc64@0.25.2': + resolution: {integrity: sha512-wCIboOL2yXZym2cgm6mlA742s9QeJ8DjGVaL39dLN4rRwrOgOyYSnOaFPhKZGLb2ngj4EyfAFjsNJwPXZvseag==} engines: {node: '>=18'} cpu: [ppc64] os: [aix] - '@esbuild/android-arm64@0.25.1': - resolution: {integrity: sha512-50tM0zCJW5kGqgG7fQ7IHvQOcAn9TKiVRuQ/lN0xR+T2lzEFvAi1ZcS8DiksFcEpf1t/GYOeOfCAgDHFpkiSmA==} + '@esbuild/android-arm64@0.25.2': + resolution: {integrity: sha512-5ZAX5xOmTligeBaeNEPnPaeEuah53Id2tX4c2CVP3JaROTH+j4fnfHCkr1PjXMd78hMst+TlkfKcW/DlTq0i4w==} engines: {node: '>=18'} cpu: [arm64] os: [android] - '@esbuild/android-arm@0.25.1': - resolution: {integrity: sha512-dp+MshLYux6j/JjdqVLnMglQlFu+MuVeNrmT5nk6q07wNhCdSnB7QZj+7G8VMUGh1q+vj2Bq8kRsuyA00I/k+Q==} + '@esbuild/android-arm@0.25.2': + resolution: {integrity: sha512-NQhH7jFstVY5x8CKbcfa166GoV0EFkaPkCKBQkdPJFvo5u+nGXLEH/ooniLb3QI8Fk58YAx7nsPLozUWfCBOJA==} engines: {node: '>=18'} cpu: [arm] os: [android] - '@esbuild/android-x64@0.25.1': - resolution: {integrity: sha512-GCj6WfUtNldqUzYkN/ITtlhwQqGWu9S45vUXs7EIYf+7rCiiqH9bCloatO9VhxsL0Pji+PF4Lz2XXCES+Q8hDw==} + '@esbuild/android-x64@0.25.2': + resolution: {integrity: sha512-Ffcx+nnma8Sge4jzddPHCZVRvIfQ0kMsUsCMcJRHkGJ1cDmhe4SsrYIjLUKn1xpHZybmOqCWwB0zQvsjdEHtkg==} engines: {node: '>=18'} cpu: [x64] os: [android] - '@esbuild/darwin-arm64@0.25.1': - resolution: {integrity: sha512-5hEZKPf+nQjYoSr/elb62U19/l1mZDdqidGfmFutVUjjUZrOazAtwK+Kr+3y0C/oeJfLlxo9fXb1w7L+P7E4FQ==} + '@esbuild/darwin-arm64@0.25.2': + resolution: {integrity: sha512-MpM6LUVTXAzOvN4KbjzU/q5smzryuoNjlriAIx+06RpecwCkL9JpenNzpKd2YMzLJFOdPqBpuub6eVRP5IgiSA==} engines: {node: '>=18'} cpu: [arm64] os: [darwin] - '@esbuild/darwin-x64@0.25.1': - resolution: {integrity: sha512-hxVnwL2Dqs3fM1IWq8Iezh0cX7ZGdVhbTfnOy5uURtao5OIVCEyj9xIzemDi7sRvKsuSdtCAhMKarxqtlyVyfA==} + '@esbuild/darwin-x64@0.25.2': + resolution: {integrity: sha512-5eRPrTX7wFyuWe8FqEFPG2cU0+butQQVNcT4sVipqjLYQjjh8a8+vUTfgBKM88ObB85ahsnTwF7PSIt6PG+QkA==} engines: {node: '>=18'} cpu: [x64] os: [darwin] - '@esbuild/freebsd-arm64@0.25.1': - resolution: {integrity: sha512-1MrCZs0fZa2g8E+FUo2ipw6jw5qqQiH+tERoS5fAfKnRx6NXH31tXBKI3VpmLijLH6yriMZsxJtaXUyFt/8Y4A==} + '@esbuild/freebsd-arm64@0.25.2': + resolution: {integrity: sha512-mLwm4vXKiQ2UTSX4+ImyiPdiHjiZhIaE9QvC7sw0tZ6HoNMjYAqQpGyui5VRIi5sGd+uWq940gdCbY3VLvsO1w==} engines: {node: '>=18'} cpu: [arm64] os: [freebsd] - '@esbuild/freebsd-x64@0.25.1': - resolution: {integrity: sha512-0IZWLiTyz7nm0xuIs0q1Y3QWJC52R8aSXxe40VUxm6BB1RNmkODtW6LHvWRrGiICulcX7ZvyH6h5fqdLu4gkww==} + '@esbuild/freebsd-x64@0.25.2': + resolution: {integrity: sha512-6qyyn6TjayJSwGpm8J9QYYGQcRgc90nmfdUb0O7pp1s4lTY+9D0H9O02v5JqGApUyiHOtkz6+1hZNvNtEhbwRQ==} engines: {node: '>=18'} cpu: [x64] os: [freebsd] - '@esbuild/linux-arm64@0.25.1': - resolution: {integrity: sha512-jaN3dHi0/DDPelk0nLcXRm1q7DNJpjXy7yWaWvbfkPvI+7XNSc/lDOnCLN7gzsyzgu6qSAmgSvP9oXAhP973uQ==} + '@esbuild/linux-arm64@0.25.2': + resolution: {integrity: sha512-gq/sjLsOyMT19I8obBISvhoYiZIAaGF8JpeXu1u8yPv8BE5HlWYobmlsfijFIZ9hIVGYkbdFhEqC0NvM4kNO0g==} engines: {node: '>=18'} cpu: [arm64] os: [linux] - '@esbuild/linux-arm@0.25.1': - resolution: {integrity: sha512-NdKOhS4u7JhDKw9G3cY6sWqFcnLITn6SqivVArbzIaf3cemShqfLGHYMx8Xlm/lBit3/5d7kXvriTUGa5YViuQ==} + '@esbuild/linux-arm@0.25.2': + resolution: {integrity: sha512-UHBRgJcmjJv5oeQF8EpTRZs/1knq6loLxTsjc3nxO9eXAPDLcWW55flrMVc97qFPbmZP31ta1AZVUKQzKTzb0g==} engines: {node: '>=18'} cpu: [arm] os: [linux] - '@esbuild/linux-ia32@0.25.1': - resolution: {integrity: sha512-OJykPaF4v8JidKNGz8c/q1lBO44sQNUQtq1KktJXdBLn1hPod5rE/Hko5ugKKZd+D2+o1a9MFGUEIUwO2YfgkQ==} + '@esbuild/linux-ia32@0.25.2': + resolution: {integrity: sha512-bBYCv9obgW2cBP+2ZWfjYTU+f5cxRoGGQ5SeDbYdFCAZpYWrfjjfYwvUpP8MlKbP0nwZ5gyOU/0aUzZ5HWPuvQ==} engines: {node: '>=18'} cpu: [ia32] os: [linux] - '@esbuild/linux-loong64@0.25.1': - resolution: {integrity: sha512-nGfornQj4dzcq5Vp835oM/o21UMlXzn79KobKlcs3Wz9smwiifknLy4xDCLUU0BWp7b/houtdrgUz7nOGnfIYg==} + '@esbuild/linux-loong64@0.25.2': + resolution: {integrity: sha512-SHNGiKtvnU2dBlM5D8CXRFdd+6etgZ9dXfaPCeJtz+37PIUlixvlIhI23L5khKXs3DIzAn9V8v+qb1TRKrgT5w==} engines: {node: '>=18'} cpu: [loong64] os: [linux] - '@esbuild/linux-mips64el@0.25.1': - resolution: {integrity: sha512-1osBbPEFYwIE5IVB/0g2X6i1qInZa1aIoj1TdL4AaAb55xIIgbg8Doq6a5BzYWgr+tEcDzYH67XVnTmUzL+nXg==} + '@esbuild/linux-mips64el@0.25.2': + resolution: {integrity: sha512-hDDRlzE6rPeoj+5fsADqdUZl1OzqDYow4TB4Y/3PlKBD0ph1e6uPHzIQcv2Z65u2K0kpeByIyAjCmjn1hJgG0Q==} engines: {node: '>=18'} cpu: [mips64el] os: [linux] - '@esbuild/linux-ppc64@0.25.1': - resolution: {integrity: sha512-/6VBJOwUf3TdTvJZ82qF3tbLuWsscd7/1w+D9LH0W/SqUgM5/JJD0lrJ1fVIfZsqB6RFmLCe0Xz3fmZc3WtyVg==} + '@esbuild/linux-ppc64@0.25.2': + resolution: {integrity: sha512-tsHu2RRSWzipmUi9UBDEzc0nLc4HtpZEI5Ba+Omms5456x5WaNuiG3u7xh5AO6sipnJ9r4cRWQB2tUjPyIkc6g==} engines: {node: '>=18'} cpu: [ppc64] os: [linux] - '@esbuild/linux-riscv64@0.25.1': - resolution: {integrity: sha512-nSut/Mx5gnilhcq2yIMLMe3Wl4FK5wx/o0QuuCLMtmJn+WeWYoEGDN1ipcN72g1WHsnIbxGXd4i/MF0gTcuAjQ==} + '@esbuild/linux-riscv64@0.25.2': + resolution: {integrity: sha512-k4LtpgV7NJQOml/10uPU0s4SAXGnowi5qBSjaLWMojNCUICNu7TshqHLAEbkBdAszL5TabfvQ48kK84hyFzjnw==} engines: {node: '>=18'} cpu: [riscv64] os: [linux] - '@esbuild/linux-s390x@0.25.1': - resolution: {integrity: sha512-cEECeLlJNfT8kZHqLarDBQso9a27o2Zd2AQ8USAEoGtejOrCYHNtKP8XQhMDJMtthdF4GBmjR2au3x1udADQQQ==} + '@esbuild/linux-s390x@0.25.2': + resolution: {integrity: sha512-GRa4IshOdvKY7M/rDpRR3gkiTNp34M0eLTaC1a08gNrh4u488aPhuZOCpkF6+2wl3zAN7L7XIpOFBhnaE3/Q8Q==} engines: {node: '>=18'} cpu: [s390x] os: [linux] - '@esbuild/linux-x64@0.25.1': - resolution: {integrity: sha512-xbfUhu/gnvSEg+EGovRc+kjBAkrvtk38RlerAzQxvMzlB4fXpCFCeUAYzJvrnhFtdeyVCDANSjJvOvGYoeKzFA==} + '@esbuild/linux-x64@0.25.2': + resolution: {integrity: sha512-QInHERlqpTTZ4FRB0fROQWXcYRD64lAoiegezDunLpalZMjcUcld3YzZmVJ2H/Cp0wJRZ8Xtjtj0cEHhYc/uUg==} engines: {node: '>=18'} cpu: [x64] os: [linux] - '@esbuild/netbsd-arm64@0.25.1': - resolution: {integrity: sha512-O96poM2XGhLtpTh+s4+nP7YCCAfb4tJNRVZHfIE7dgmax+yMP2WgMd2OecBuaATHKTHsLWHQeuaxMRnCsH8+5g==} + '@esbuild/netbsd-arm64@0.25.2': + resolution: {integrity: sha512-talAIBoY5M8vHc6EeI2WW9d/CkiO9MQJ0IOWX8hrLhxGbro/vBXJvaQXefW2cP0z0nQVTdQ/eNyGFV1GSKrxfw==} engines: {node: '>=18'} cpu: [arm64] os: [netbsd] - '@esbuild/netbsd-x64@0.25.1': - resolution: {integrity: sha512-X53z6uXip6KFXBQ+Krbx25XHV/NCbzryM6ehOAeAil7X7oa4XIq+394PWGnwaSQ2WRA0KI6PUO6hTO5zeF5ijA==} + '@esbuild/netbsd-x64@0.25.2': + resolution: {integrity: sha512-voZT9Z+tpOxrvfKFyfDYPc4DO4rk06qamv1a/fkuzHpiVBMOhpjK+vBmWM8J1eiB3OLSMFYNaOaBNLXGChf5tg==} engines: {node: '>=18'} cpu: [x64] os: [netbsd] - '@esbuild/openbsd-arm64@0.25.1': - resolution: {integrity: sha512-Na9T3szbXezdzM/Kfs3GcRQNjHzM6GzFBeU1/6IV/npKP5ORtp9zbQjvkDJ47s6BCgaAZnnnu/cY1x342+MvZg==} + '@esbuild/openbsd-arm64@0.25.2': + resolution: {integrity: sha512-dcXYOC6NXOqcykeDlwId9kB6OkPUxOEqU+rkrYVqJbK2hagWOMrsTGsMr8+rW02M+d5Op5NNlgMmjzecaRf7Tg==} engines: {node: '>=18'} cpu: [arm64] os: [openbsd] - '@esbuild/openbsd-x64@0.25.1': - resolution: {integrity: sha512-T3H78X2h1tszfRSf+txbt5aOp/e7TAz3ptVKu9Oyir3IAOFPGV6O9c2naym5TOriy1l0nNf6a4X5UXRZSGX/dw==} + '@esbuild/openbsd-x64@0.25.2': + resolution: {integrity: sha512-t/TkWwahkH0Tsgoq1Ju7QfgGhArkGLkF1uYz8nQS/PPFlXbP5YgRpqQR3ARRiC2iXoLTWFxc6DJMSK10dVXluw==} engines: {node: '>=18'} cpu: [x64] os: [openbsd] - '@esbuild/sunos-x64@0.25.1': - resolution: {integrity: sha512-2H3RUvcmULO7dIE5EWJH8eubZAI4xw54H1ilJnRNZdeo8dTADEZ21w6J22XBkXqGJbe0+wnNJtw3UXRoLJnFEg==} + '@esbuild/sunos-x64@0.25.2': + resolution: {integrity: sha512-cfZH1co2+imVdWCjd+D1gf9NjkchVhhdpgb1q5y6Hcv9TP6Zi9ZG/beI3ig8TvwT9lH9dlxLq5MQBBgwuj4xvA==} engines: {node: '>=18'} cpu: [x64] os: [sunos] - '@esbuild/win32-arm64@0.25.1': - resolution: {integrity: sha512-GE7XvrdOzrb+yVKB9KsRMq+7a2U/K5Cf/8grVFRAGJmfADr/e/ODQ134RK2/eeHqYV5eQRFxb1hY7Nr15fv1NQ==} + '@esbuild/win32-arm64@0.25.2': + resolution: {integrity: sha512-7Loyjh+D/Nx/sOTzV8vfbB3GJuHdOQyrOryFdZvPHLf42Tk9ivBU5Aedi7iyX+x6rbn2Mh68T4qq1SDqJBQO5Q==} engines: {node: '>=18'} cpu: [arm64] os: [win32] - '@esbuild/win32-ia32@0.25.1': - resolution: {integrity: sha512-uOxSJCIcavSiT6UnBhBzE8wy3n0hOkJsBOzy7HDAuTDE++1DJMRRVCPGisULScHL+a/ZwdXPpXD3IyFKjA7K8A==} + '@esbuild/win32-ia32@0.25.2': + resolution: {integrity: sha512-WRJgsz9un0nqZJ4MfhabxaD9Ft8KioqU3JMinOTvobbX6MOSUigSBlogP8QB3uxpJDsFS6yN+3FDBdqE5lg9kg==} engines: {node: '>=18'} cpu: [ia32] os: [win32] - '@esbuild/win32-x64@0.25.1': - resolution: {integrity: sha512-Y1EQdcfwMSeQN/ujR5VayLOJ1BHaK+ssyk0AEzPjC+t1lITgsnccPqFjb6V+LsTp/9Iov4ysfjxLaGJ9RPtkVg==} + '@esbuild/win32-x64@0.25.2': + resolution: {integrity: sha512-kM3HKb16VIXZyIeVrM1ygYmZBKybX8N4p754bw390wGO3Tf2j4L2/WYL+4suWujpgf6GBYs3jv7TyUivdd05JA==} engines: {node: '>=18'} cpu: [x64] os: [win32] @@ -454,98 +454,103 @@ packages: resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} engines: {node: '>=14'} - '@rollup/rollup-android-arm-eabi@4.35.0': - resolution: {integrity: sha512-uYQ2WfPaqz5QtVgMxfN6NpLD+no0MYHDBywl7itPYd3K5TjjSghNKmX8ic9S8NU8w81NVhJv/XojcHptRly7qQ==} + '@rollup/rollup-android-arm-eabi@4.38.0': + resolution: {integrity: sha512-ldomqc4/jDZu/xpYU+aRxo3V4mGCV9HeTgUBANI3oIQMOL+SsxB+S2lxMpkFp5UamSS3XuTMQVbsS24R4J4Qjg==} cpu: [arm] os: [android] - '@rollup/rollup-android-arm64@4.35.0': - resolution: {integrity: sha512-FtKddj9XZudurLhdJnBl9fl6BwCJ3ky8riCXjEw3/UIbjmIY58ppWwPEvU3fNu+W7FUsAsB1CdH+7EQE6CXAPA==} + '@rollup/rollup-android-arm64@4.38.0': + resolution: {integrity: sha512-VUsgcy4GhhT7rokwzYQP+aV9XnSLkkhlEJ0St8pbasuWO/vwphhZQxYEKUP3ayeCYLhk6gEtacRpYP/cj3GjyQ==} cpu: [arm64] os: [android] - '@rollup/rollup-darwin-arm64@4.35.0': - resolution: {integrity: sha512-Uk+GjOJR6CY844/q6r5DR/6lkPFOw0hjfOIzVx22THJXMxktXG6CbejseJFznU8vHcEBLpiXKY3/6xc+cBm65Q==} + '@rollup/rollup-darwin-arm64@4.38.0': + resolution: {integrity: sha512-buA17AYXlW9Rn091sWMq1xGUvWQFOH4N1rqUxGJtEQzhChxWjldGCCup7r/wUnaI6Au8sKXpoh0xg58a7cgcpg==} cpu: [arm64] os: [darwin] - '@rollup/rollup-darwin-x64@4.35.0': - resolution: {integrity: sha512-3IrHjfAS6Vkp+5bISNQnPogRAW5GAV1n+bNCrDwXmfMHbPl5EhTmWtfmwlJxFRUCBZ+tZ/OxDyU08aF6NI/N5Q==} + '@rollup/rollup-darwin-x64@4.38.0': + resolution: {integrity: sha512-Mgcmc78AjunP1SKXl624vVBOF2bzwNWFPMP4fpOu05vS0amnLcX8gHIge7q/lDAHy3T2HeR0TqrriZDQS2Woeg==} cpu: [x64] os: [darwin] - '@rollup/rollup-freebsd-arm64@4.35.0': - resolution: {integrity: sha512-sxjoD/6F9cDLSELuLNnY0fOrM9WA0KrM0vWm57XhrIMf5FGiN8D0l7fn+bpUeBSU7dCgPV2oX4zHAsAXyHFGcQ==} + '@rollup/rollup-freebsd-arm64@4.38.0': + resolution: {integrity: sha512-zzJACgjLbQTsscxWqvrEQAEh28hqhebpRz5q/uUd1T7VTwUNZ4VIXQt5hE7ncs0GrF+s7d3S4on4TiXUY8KoQA==} cpu: [arm64] os: [freebsd] - '@rollup/rollup-freebsd-x64@4.35.0': - resolution: {integrity: sha512-2mpHCeRuD1u/2kruUiHSsnjWtHjqVbzhBkNVQ1aVD63CcexKVcQGwJ2g5VphOd84GvxfSvnnlEyBtQCE5hxVVw==} + '@rollup/rollup-freebsd-x64@4.38.0': + resolution: {integrity: sha512-hCY/KAeYMCyDpEE4pTETam0XZS4/5GXzlLgpi5f0IaPExw9kuB+PDTOTLuPtM10TlRG0U9OSmXJ+Wq9J39LvAg==} cpu: [x64] os: [freebsd] - '@rollup/rollup-linux-arm-gnueabihf@4.35.0': - resolution: {integrity: sha512-mrA0v3QMy6ZSvEuLs0dMxcO2LnaCONs1Z73GUDBHWbY8tFFocM6yl7YyMu7rz4zS81NDSqhrUuolyZXGi8TEqg==} + '@rollup/rollup-linux-arm-gnueabihf@4.38.0': + resolution: {integrity: sha512-mimPH43mHl4JdOTD7bUMFhBdrg6f9HzMTOEnzRmXbOZqjijCw8LA5z8uL6LCjxSa67H2xiLFvvO67PT05PRKGg==} cpu: [arm] os: [linux] - '@rollup/rollup-linux-arm-musleabihf@4.35.0': - resolution: {integrity: sha512-DnYhhzcvTAKNexIql8pFajr0PiDGrIsBYPRvCKlA5ixSS3uwo/CWNZxB09jhIapEIg945KOzcYEAGGSmTSpk7A==} + '@rollup/rollup-linux-arm-musleabihf@4.38.0': + resolution: {integrity: sha512-tPiJtiOoNuIH8XGG8sWoMMkAMm98PUwlriOFCCbZGc9WCax+GLeVRhmaxjJtz6WxrPKACgrwoZ5ia/uapq3ZVg==} cpu: [arm] os: [linux] - '@rollup/rollup-linux-arm64-gnu@4.35.0': - resolution: {integrity: sha512-uagpnH2M2g2b5iLsCTZ35CL1FgyuzzJQ8L9VtlJ+FckBXroTwNOaD0z0/UF+k5K3aNQjbm8LIVpxykUOQt1m/A==} + '@rollup/rollup-linux-arm64-gnu@4.38.0': + resolution: {integrity: sha512-wZco59rIVuB0tjQS0CSHTTUcEde+pXQWugZVxWaQFdQQ1VYub/sTrNdY76D1MKdN2NB48JDuGABP6o6fqos8mA==} cpu: [arm64] os: [linux] - '@rollup/rollup-linux-arm64-musl@4.35.0': - resolution: {integrity: sha512-XQxVOCd6VJeHQA/7YcqyV0/88N6ysSVzRjJ9I9UA/xXpEsjvAgDTgH3wQYz5bmr7SPtVK2TsP2fQ2N9L4ukoUg==} + '@rollup/rollup-linux-arm64-musl@4.38.0': + resolution: {integrity: sha512-fQgqwKmW0REM4LomQ+87PP8w8xvU9LZfeLBKybeli+0yHT7VKILINzFEuggvnV9M3x1Ed4gUBmGUzCo/ikmFbQ==} cpu: [arm64] os: [linux] - '@rollup/rollup-linux-loongarch64-gnu@4.35.0': - resolution: {integrity: sha512-5pMT5PzfgwcXEwOaSrqVsz/LvjDZt+vQ8RT/70yhPU06PTuq8WaHhfT1LW+cdD7mW6i/J5/XIkX/1tCAkh1W6g==} + '@rollup/rollup-linux-loongarch64-gnu@4.38.0': + resolution: {integrity: sha512-hz5oqQLXTB3SbXpfkKHKXLdIp02/w3M+ajp8p4yWOWwQRtHWiEOCKtc9U+YXahrwdk+3qHdFMDWR5k+4dIlddg==} cpu: [loong64] os: [linux] - '@rollup/rollup-linux-powerpc64le-gnu@4.35.0': - resolution: {integrity: sha512-c+zkcvbhbXF98f4CtEIP1EBA/lCic5xB0lToneZYvMeKu5Kamq3O8gqrxiYYLzlZH6E3Aq+TSW86E4ay8iD8EA==} + '@rollup/rollup-linux-powerpc64le-gnu@4.38.0': + resolution: {integrity: sha512-NXqygK/dTSibQ+0pzxsL3r4Xl8oPqVoWbZV9niqOnIHV/J92fe65pOir0xjkUZDRSPyFRvu+4YOpJF9BZHQImw==} cpu: [ppc64] os: [linux] - '@rollup/rollup-linux-riscv64-gnu@4.35.0': - resolution: {integrity: sha512-s91fuAHdOwH/Tad2tzTtPX7UZyytHIRR6V4+2IGlV0Cej5rkG0R61SX4l4y9sh0JBibMiploZx3oHKPnQBKe4g==} + '@rollup/rollup-linux-riscv64-gnu@4.38.0': + resolution: {integrity: sha512-GEAIabR1uFyvf/jW/5jfu8gjM06/4kZ1W+j1nWTSSB3w6moZEBm7iBtzwQ3a1Pxos2F7Gz+58aVEnZHU295QTg==} cpu: [riscv64] os: [linux] - '@rollup/rollup-linux-s390x-gnu@4.35.0': - resolution: {integrity: sha512-hQRkPQPLYJZYGP+Hj4fR9dDBMIM7zrzJDWFEMPdTnTy95Ljnv0/4w/ixFw3pTBMEuuEuoqtBINYND4M7ujcuQw==} + '@rollup/rollup-linux-riscv64-musl@4.38.0': + resolution: {integrity: sha512-9EYTX+Gus2EGPbfs+fh7l95wVADtSQyYw4DfSBcYdUEAmP2lqSZY0Y17yX/3m5VKGGJ4UmIH5LHLkMJft3bYoA==} + cpu: [riscv64] + os: [linux] + + '@rollup/rollup-linux-s390x-gnu@4.38.0': + resolution: {integrity: sha512-Mpp6+Z5VhB9VDk7RwZXoG2qMdERm3Jw07RNlXHE0bOnEeX+l7Fy4bg+NxfyN15ruuY3/7Vrbpm75J9QHFqj5+Q==} cpu: [s390x] os: [linux] - '@rollup/rollup-linux-x64-gnu@4.35.0': - resolution: {integrity: sha512-Pim1T8rXOri+0HmV4CdKSGrqcBWX0d1HoPnQ0uw0bdp1aP5SdQVNBy8LjYncvnLgu3fnnCt17xjWGd4cqh8/hA==} + '@rollup/rollup-linux-x64-gnu@4.38.0': + resolution: {integrity: sha512-vPvNgFlZRAgO7rwncMeE0+8c4Hmc+qixnp00/Uv3ht2x7KYrJ6ERVd3/R0nUtlE6/hu7/HiiNHJ/rP6knRFt1w==} cpu: [x64] os: [linux] - '@rollup/rollup-linux-x64-musl@4.35.0': - resolution: {integrity: sha512-QysqXzYiDvQWfUiTm8XmJNO2zm9yC9P/2Gkrwg2dH9cxotQzunBHYr6jk4SujCTqnfGxduOmQcI7c2ryuW8XVg==} + '@rollup/rollup-linux-x64-musl@4.38.0': + resolution: {integrity: sha512-q5Zv+goWvQUGCaL7fU8NuTw8aydIL/C9abAVGCzRReuj5h30TPx4LumBtAidrVOtXnlB+RZkBtExMsfqkMfb8g==} cpu: [x64] os: [linux] - '@rollup/rollup-win32-arm64-msvc@4.35.0': - resolution: {integrity: sha512-OUOlGqPkVJCdJETKOCEf1mw848ZyJ5w50/rZ/3IBQVdLfR5jk/6Sr5m3iO2tdPgwo0x7VcncYuOvMhBWZq8ayg==} + '@rollup/rollup-win32-arm64-msvc@4.38.0': + resolution: {integrity: sha512-u/Jbm1BU89Vftqyqbmxdq14nBaQjQX1HhmsdBWqSdGClNaKwhjsg5TpW+5Ibs1mb8Es9wJiMdl86BcmtUVXNZg==} cpu: [arm64] os: [win32] - '@rollup/rollup-win32-ia32-msvc@4.35.0': - resolution: {integrity: sha512-2/lsgejMrtwQe44glq7AFFHLfJBPafpsTa6JvP2NGef/ifOa4KBoglVf7AKN7EV9o32evBPRqfg96fEHzWo5kw==} + '@rollup/rollup-win32-ia32-msvc@4.38.0': + resolution: {integrity: sha512-mqu4PzTrlpNHHbu5qleGvXJoGgHpChBlrBx/mEhTPpnAL1ZAYFlvHD7rLK839LLKQzqEQMFJfGrrOHItN4ZQqA==} cpu: [ia32] os: [win32] - '@rollup/rollup-win32-x64-msvc@4.35.0': - resolution: {integrity: sha512-PIQeY5XDkrOysbQblSW7v3l1MDZzkTEzAfTPkj5VAu3FW8fS4ynyLg2sINp0fp3SjZ8xkRYpLqoKcYqAkhU1dw==} + '@rollup/rollup-win32-x64-msvc@4.38.0': + resolution: {integrity: sha512-jjqy3uWlecfB98Psxb5cD6Fny9Fupv9LrDSPTQZUROqjvZmcCqNu4UMl7qqhlUUGpwiAkotj6GYu4SZdcr/nLw==} cpu: [x64] os: [win32] @@ -656,6 +661,9 @@ packages: '@types/estree@1.0.6': resolution: {integrity: sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==} + '@types/estree@1.0.7': + resolution: {integrity: sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==} + '@types/json-schema@7.0.15': resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} @@ -1190,8 +1198,8 @@ packages: resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==} engines: {node: '>= 0.4'} - esbuild@0.25.1: - resolution: {integrity: sha512-BGO5LtrGC7vxnqucAe/rmvKdJllfGaYWdyABvyMoXQlfYMb2bbRuReWR5tEGE//4LcNJj9XrkovTqNYRFZHAMQ==} + esbuild@0.25.2: + resolution: {integrity: sha512-16854zccKPnC+toMywC+uKNeYSv+/eXkevRAfwRD/G9Cleq66m8XFIrigkbvauLLlCfDL45Q2cWegSg53gGBnQ==} engines: {node: '>=18'} hasBin: true @@ -2115,8 +2123,8 @@ packages: rfdc@1.4.1: resolution: {integrity: sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==} - rollup@4.35.0: - resolution: {integrity: sha512-kg6oI4g+vc41vePJyO6dHt/yl0Rz3Thv0kJeVQ3D1kS3E5XSuKbPc29G4IpT/Kv1KQwgHVcN+HtyS+HYLNSvQg==} + rollup@4.38.0: + resolution: {integrity: sha512-5SsIRtJy9bf1ErAOiFMFzl64Ex9X5V7bnJ+WlFMb+zmP459OSWCEG7b0ERZ+PEU7xPt4OG3RHbrp1LJlXxYTrw==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true @@ -2423,8 +2431,8 @@ packages: engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} hasBin: true - vite@6.2.3: - resolution: {integrity: sha512-IzwM54g4y9JA/xAeBPNaDXiBF8Jsgl3VBQ2YQ/wOY6fyW3xMdSoltIV3Bo59DErdqdE6RxUfv8W69DvUorE4Eg==} + vite@6.2.4: + resolution: {integrity: sha512-veHMSew8CcRzhL5o8ONjy8gkfmFJAd5Ac16oxBUjlwgX3Gq2Wqr+qNC3TjPIpy7TPV/KporLga5GT9HqdrCizw==} engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} hasBin: true peerDependencies: @@ -2666,79 +2674,79 @@ snapshots: transitivePeerDependencies: - supports-color - '@esbuild/aix-ppc64@0.25.1': + '@esbuild/aix-ppc64@0.25.2': optional: true - '@esbuild/android-arm64@0.25.1': + '@esbuild/android-arm64@0.25.2': optional: true - '@esbuild/android-arm@0.25.1': + '@esbuild/android-arm@0.25.2': optional: true - '@esbuild/android-x64@0.25.1': + '@esbuild/android-x64@0.25.2': optional: true - '@esbuild/darwin-arm64@0.25.1': + '@esbuild/darwin-arm64@0.25.2': optional: true - '@esbuild/darwin-x64@0.25.1': + '@esbuild/darwin-x64@0.25.2': optional: true - '@esbuild/freebsd-arm64@0.25.1': + '@esbuild/freebsd-arm64@0.25.2': optional: true - '@esbuild/freebsd-x64@0.25.1': + '@esbuild/freebsd-x64@0.25.2': optional: true - '@esbuild/linux-arm64@0.25.1': + '@esbuild/linux-arm64@0.25.2': optional: true - '@esbuild/linux-arm@0.25.1': + '@esbuild/linux-arm@0.25.2': optional: true - '@esbuild/linux-ia32@0.25.1': + '@esbuild/linux-ia32@0.25.2': optional: true - '@esbuild/linux-loong64@0.25.1': + '@esbuild/linux-loong64@0.25.2': optional: true - '@esbuild/linux-mips64el@0.25.1': + '@esbuild/linux-mips64el@0.25.2': optional: true - '@esbuild/linux-ppc64@0.25.1': + '@esbuild/linux-ppc64@0.25.2': optional: true - '@esbuild/linux-riscv64@0.25.1': + '@esbuild/linux-riscv64@0.25.2': optional: true - '@esbuild/linux-s390x@0.25.1': + '@esbuild/linux-s390x@0.25.2': optional: true - '@esbuild/linux-x64@0.25.1': + '@esbuild/linux-x64@0.25.2': optional: true - '@esbuild/netbsd-arm64@0.25.1': + '@esbuild/netbsd-arm64@0.25.2': optional: true - '@esbuild/netbsd-x64@0.25.1': + '@esbuild/netbsd-x64@0.25.2': optional: true - '@esbuild/openbsd-arm64@0.25.1': + '@esbuild/openbsd-arm64@0.25.2': optional: true - '@esbuild/openbsd-x64@0.25.1': + '@esbuild/openbsd-x64@0.25.2': optional: true - '@esbuild/sunos-x64@0.25.1': + '@esbuild/sunos-x64@0.25.2': optional: true - '@esbuild/win32-arm64@0.25.1': + '@esbuild/win32-arm64@0.25.2': optional: true - '@esbuild/win32-ia32@0.25.1': + '@esbuild/win32-ia32@0.25.2': optional: true - '@esbuild/win32-x64@0.25.1': + '@esbuild/win32-x64@0.25.2': optional: true '@eslint-community/eslint-utils@4.4.1(eslint@9.22.0(jiti@1.21.7))': @@ -2913,61 +2921,64 @@ snapshots: '@pkgjs/parseargs@0.11.0': optional: true - '@rollup/rollup-android-arm-eabi@4.35.0': + '@rollup/rollup-android-arm-eabi@4.38.0': optional: true - '@rollup/rollup-android-arm64@4.35.0': + '@rollup/rollup-android-arm64@4.38.0': optional: true - '@rollup/rollup-darwin-arm64@4.35.0': + '@rollup/rollup-darwin-arm64@4.38.0': optional: true - '@rollup/rollup-darwin-x64@4.35.0': + '@rollup/rollup-darwin-x64@4.38.0': optional: true - '@rollup/rollup-freebsd-arm64@4.35.0': + '@rollup/rollup-freebsd-arm64@4.38.0': optional: true - '@rollup/rollup-freebsd-x64@4.35.0': + '@rollup/rollup-freebsd-x64@4.38.0': optional: true - '@rollup/rollup-linux-arm-gnueabihf@4.35.0': + '@rollup/rollup-linux-arm-gnueabihf@4.38.0': optional: true - '@rollup/rollup-linux-arm-musleabihf@4.35.0': + '@rollup/rollup-linux-arm-musleabihf@4.38.0': optional: true - '@rollup/rollup-linux-arm64-gnu@4.35.0': + '@rollup/rollup-linux-arm64-gnu@4.38.0': optional: true - '@rollup/rollup-linux-arm64-musl@4.35.0': + '@rollup/rollup-linux-arm64-musl@4.38.0': optional: true - '@rollup/rollup-linux-loongarch64-gnu@4.35.0': + '@rollup/rollup-linux-loongarch64-gnu@4.38.0': optional: true - '@rollup/rollup-linux-powerpc64le-gnu@4.35.0': + '@rollup/rollup-linux-powerpc64le-gnu@4.38.0': optional: true - '@rollup/rollup-linux-riscv64-gnu@4.35.0': + '@rollup/rollup-linux-riscv64-gnu@4.38.0': optional: true - '@rollup/rollup-linux-s390x-gnu@4.35.0': + '@rollup/rollup-linux-riscv64-musl@4.38.0': optional: true - '@rollup/rollup-linux-x64-gnu@4.35.0': + '@rollup/rollup-linux-s390x-gnu@4.38.0': optional: true - '@rollup/rollup-linux-x64-musl@4.35.0': + '@rollup/rollup-linux-x64-gnu@4.38.0': optional: true - '@rollup/rollup-win32-arm64-msvc@4.35.0': + '@rollup/rollup-linux-x64-musl@4.38.0': optional: true - '@rollup/rollup-win32-ia32-msvc@4.35.0': + '@rollup/rollup-win32-arm64-msvc@4.38.0': optional: true - '@rollup/rollup-win32-x64-msvc@4.35.0': + '@rollup/rollup-win32-ia32-msvc@4.38.0': + optional: true + + '@rollup/rollup-win32-x64-msvc@4.38.0': optional: true '@swc/core-darwin-arm64@1.11.8': @@ -3059,6 +3070,8 @@ snapshots: '@types/estree@1.0.6': {} + '@types/estree@1.0.7': {} + '@types/json-schema@7.0.15': {} '@types/node@16.18.126': {} @@ -3161,10 +3174,10 @@ snapshots: '@typescript-eslint/types': 8.26.0 eslint-visitor-keys: 4.2.0 - '@vitejs/plugin-react-swc@3.8.0(vite@6.2.3(@types/node@22.13.10)(jiti@1.21.7)(yaml@2.7.0))': + '@vitejs/plugin-react-swc@3.8.0(vite@6.2.4(@types/node@22.13.10)(jiti@1.21.7)(yaml@2.7.0))': dependencies: '@swc/core': 1.11.8 - vite: 6.2.3(@types/node@22.13.10)(jiti@1.21.7)(yaml@2.7.0) + vite: 6.2.4(@types/node@22.13.10)(jiti@1.21.7)(yaml@2.7.0) transitivePeerDependencies: - '@swc/helpers' @@ -3194,13 +3207,13 @@ snapshots: chai: 5.2.0 tinyrainbow: 2.0.0 - '@vitest/mocker@3.0.8(vite@6.2.3(@types/node@22.13.10)(jiti@1.21.7)(yaml@2.7.0))': + '@vitest/mocker@3.0.8(vite@6.2.4(@types/node@22.13.10)(jiti@1.21.7)(yaml@2.7.0))': dependencies: '@vitest/spy': 3.0.8 estree-walker: 3.0.3 magic-string: 0.30.17 optionalDependencies: - vite: 6.2.3(@types/node@22.13.10)(jiti@1.21.7)(yaml@2.7.0) + vite: 6.2.4(@types/node@22.13.10)(jiti@1.21.7)(yaml@2.7.0) '@vitest/pretty-format@3.0.8': dependencies: @@ -3636,33 +3649,33 @@ snapshots: has-tostringtag: 1.0.2 hasown: 2.0.2 - esbuild@0.25.1: + esbuild@0.25.2: optionalDependencies: - '@esbuild/aix-ppc64': 0.25.1 - '@esbuild/android-arm': 0.25.1 - '@esbuild/android-arm64': 0.25.1 - '@esbuild/android-x64': 0.25.1 - '@esbuild/darwin-arm64': 0.25.1 - '@esbuild/darwin-x64': 0.25.1 - '@esbuild/freebsd-arm64': 0.25.1 - '@esbuild/freebsd-x64': 0.25.1 - '@esbuild/linux-arm': 0.25.1 - '@esbuild/linux-arm64': 0.25.1 - '@esbuild/linux-ia32': 0.25.1 - '@esbuild/linux-loong64': 0.25.1 - '@esbuild/linux-mips64el': 0.25.1 - '@esbuild/linux-ppc64': 0.25.1 - '@esbuild/linux-riscv64': 0.25.1 - '@esbuild/linux-s390x': 0.25.1 - '@esbuild/linux-x64': 0.25.1 - '@esbuild/netbsd-arm64': 0.25.1 - '@esbuild/netbsd-x64': 0.25.1 - '@esbuild/openbsd-arm64': 0.25.1 - '@esbuild/openbsd-x64': 0.25.1 - '@esbuild/sunos-x64': 0.25.1 - '@esbuild/win32-arm64': 0.25.1 - '@esbuild/win32-ia32': 0.25.1 - '@esbuild/win32-x64': 0.25.1 + '@esbuild/aix-ppc64': 0.25.2 + '@esbuild/android-arm': 0.25.2 + '@esbuild/android-arm64': 0.25.2 + '@esbuild/android-x64': 0.25.2 + '@esbuild/darwin-arm64': 0.25.2 + '@esbuild/darwin-x64': 0.25.2 + '@esbuild/freebsd-arm64': 0.25.2 + '@esbuild/freebsd-x64': 0.25.2 + '@esbuild/linux-arm': 0.25.2 + '@esbuild/linux-arm64': 0.25.2 + '@esbuild/linux-ia32': 0.25.2 + '@esbuild/linux-loong64': 0.25.2 + '@esbuild/linux-mips64el': 0.25.2 + '@esbuild/linux-ppc64': 0.25.2 + '@esbuild/linux-riscv64': 0.25.2 + '@esbuild/linux-s390x': 0.25.2 + '@esbuild/linux-x64': 0.25.2 + '@esbuild/netbsd-arm64': 0.25.2 + '@esbuild/netbsd-x64': 0.25.2 + '@esbuild/openbsd-arm64': 0.25.2 + '@esbuild/openbsd-x64': 0.25.2 + '@esbuild/sunos-x64': 0.25.2 + '@esbuild/win32-arm64': 0.25.2 + '@esbuild/win32-ia32': 0.25.2 + '@esbuild/win32-x64': 0.25.2 escalade@3.2.0: {} @@ -3789,7 +3802,7 @@ snapshots: estree-walker@3.0.3: dependencies: - '@types/estree': 1.0.6 + '@types/estree': 1.0.7 esutils@2.0.3: {} @@ -4597,29 +4610,30 @@ snapshots: rfdc@1.4.1: {} - rollup@4.35.0: + rollup@4.38.0: dependencies: - '@types/estree': 1.0.6 + '@types/estree': 1.0.7 optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.35.0 - '@rollup/rollup-android-arm64': 4.35.0 - '@rollup/rollup-darwin-arm64': 4.35.0 - '@rollup/rollup-darwin-x64': 4.35.0 - '@rollup/rollup-freebsd-arm64': 4.35.0 - '@rollup/rollup-freebsd-x64': 4.35.0 - '@rollup/rollup-linux-arm-gnueabihf': 4.35.0 - '@rollup/rollup-linux-arm-musleabihf': 4.35.0 - '@rollup/rollup-linux-arm64-gnu': 4.35.0 - '@rollup/rollup-linux-arm64-musl': 4.35.0 - '@rollup/rollup-linux-loongarch64-gnu': 4.35.0 - '@rollup/rollup-linux-powerpc64le-gnu': 4.35.0 - '@rollup/rollup-linux-riscv64-gnu': 4.35.0 - '@rollup/rollup-linux-s390x-gnu': 4.35.0 - '@rollup/rollup-linux-x64-gnu': 4.35.0 - '@rollup/rollup-linux-x64-musl': 4.35.0 - '@rollup/rollup-win32-arm64-msvc': 4.35.0 - '@rollup/rollup-win32-ia32-msvc': 4.35.0 - '@rollup/rollup-win32-x64-msvc': 4.35.0 + '@rollup/rollup-android-arm-eabi': 4.38.0 + '@rollup/rollup-android-arm64': 4.38.0 + '@rollup/rollup-darwin-arm64': 4.38.0 + '@rollup/rollup-darwin-x64': 4.38.0 + '@rollup/rollup-freebsd-arm64': 4.38.0 + '@rollup/rollup-freebsd-x64': 4.38.0 + '@rollup/rollup-linux-arm-gnueabihf': 4.38.0 + '@rollup/rollup-linux-arm-musleabihf': 4.38.0 + '@rollup/rollup-linux-arm64-gnu': 4.38.0 + '@rollup/rollup-linux-arm64-musl': 4.38.0 + '@rollup/rollup-linux-loongarch64-gnu': 4.38.0 + '@rollup/rollup-linux-powerpc64le-gnu': 4.38.0 + '@rollup/rollup-linux-riscv64-gnu': 4.38.0 + '@rollup/rollup-linux-riscv64-musl': 4.38.0 + '@rollup/rollup-linux-s390x-gnu': 4.38.0 + '@rollup/rollup-linux-x64-gnu': 4.38.0 + '@rollup/rollup-linux-x64-musl': 4.38.0 + '@rollup/rollup-win32-arm64-msvc': 4.38.0 + '@rollup/rollup-win32-ia32-msvc': 4.38.0 + '@rollup/rollup-win32-x64-msvc': 4.38.0 fsevents: 2.3.3 rrweb-cssom@0.7.1: {} @@ -4933,7 +4947,7 @@ snapshots: debug: 4.4.0(supports-color@8.1.1) es-module-lexer: 1.6.0 pathe: 2.0.3 - vite: 6.2.3(@types/node@22.13.10)(jiti@1.21.7)(yaml@2.7.0) + vite: 6.2.4(@types/node@22.13.10)(jiti@1.21.7)(yaml@2.7.0) transitivePeerDependencies: - '@types/node' - jiti @@ -4948,11 +4962,11 @@ snapshots: - tsx - yaml - vite@6.2.3(@types/node@22.13.10)(jiti@1.21.7)(yaml@2.7.0): + vite@6.2.4(@types/node@22.13.10)(jiti@1.21.7)(yaml@2.7.0): dependencies: - esbuild: 0.25.1 + esbuild: 0.25.2 postcss: 8.5.3 - rollup: 4.35.0 + rollup: 4.38.0 optionalDependencies: '@types/node': 22.13.10 fsevents: 2.3.3 @@ -4962,7 +4976,7 @@ snapshots: vitest@3.0.8(@types/node@22.13.10)(jiti@1.21.7)(jsdom@24.1.3)(yaml@2.7.0): dependencies: '@vitest/expect': 3.0.8 - '@vitest/mocker': 3.0.8(vite@6.2.3(@types/node@22.13.10)(jiti@1.21.7)(yaml@2.7.0)) + '@vitest/mocker': 3.0.8(vite@6.2.4(@types/node@22.13.10)(jiti@1.21.7)(yaml@2.7.0)) '@vitest/pretty-format': 3.0.8 '@vitest/runner': 3.0.8 '@vitest/snapshot': 3.0.8 @@ -4978,7 +4992,7 @@ snapshots: tinyexec: 0.3.2 tinypool: 1.0.2 tinyrainbow: 2.0.0 - vite: 6.2.3(@types/node@22.13.10)(jiti@1.21.7)(yaml@2.7.0) + vite: 6.2.4(@types/node@22.13.10)(jiti@1.21.7)(yaml@2.7.0) vite-node: 3.0.8(@types/node@22.13.10)(jiti@1.21.7)(yaml@2.7.0) why-is-node-running: 2.3.0 optionalDependencies: From 509f8cdb09471f514e607f43fb9729515794ca11 Mon Sep 17 00:00:00 2001 From: Marios Tsigkas Date: Wed, 2 Apr 2025 01:57:05 +0300 Subject: [PATCH 75/96] make home cats fetch only once --- src/views/Home.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/views/Home.tsx b/src/views/Home.tsx index 514ef9af..ee8541f0 100644 --- a/src/views/Home.tsx +++ b/src/views/Home.tsx @@ -6,7 +6,7 @@ function Home(): JSX.Element { const { images, fetchImages, isLoading, error } = useFetchedImages() useEffect(() => { - if (isLoading) return + if (isLoading || images.length > 0) return void fetchImages() // we only want to fetch new images when the component mounts // eslint-disable-next-line react-hooks/exhaustive-deps From 0f3f043ead626bf8caf5fc2bb3310ea899aaa151 Mon Sep 17 00:00:00 2001 From: Marios Tsigkas Date: Mon, 7 Apr 2025 17:54:04 +0300 Subject: [PATCH 76/96] Update deployment workflow: add baseUrl configuration for ci cy tests --- .github/workflows/deploy.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 9d74dbbc..bdc8a606 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -44,6 +44,7 @@ jobs: with: build: pnpm build start: pnpm preview --port 5173 + config: 'baseUrl=http://localhost:5173/platform-catApi-react' build: runs-on: ubuntu-latest From 5ddb822c3bf4ed3fb46e3a416daff460a1fb3d4a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 7 Apr 2025 16:02:02 +0000 Subject: [PATCH 77/96] Bump vite in the npm_and_yarn group across 1 directory Bumps the npm_and_yarn group with 1 update in the / directory: [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite). Updates `vite` from 6.2.4 to 6.2.5 - [Release notes](https://github.com/vitejs/vite/releases) - [Changelog](https://github.com/vitejs/vite/blob/v6.2.5/packages/vite/CHANGELOG.md) - [Commits](https://github.com/vitejs/vite/commits/v6.2.5/packages/vite) --- updated-dependencies: - dependency-name: vite dependency-version: 6.2.5 dependency-type: direct:development dependency-group: npm_and_yarn ... Signed-off-by: dependabot[bot] --- package.json | 2 +- pnpm-lock.yaml | 194 ++++++++++++++++++++++++------------------------- 2 files changed, 98 insertions(+), 98 deletions(-) diff --git a/package.json b/package.json index ee1a6163..f75a64e6 100644 --- a/package.json +++ b/package.json @@ -46,7 +46,7 @@ "tailwindcss": "^3.4.1", "typescript": "~5.7.2", "typescript-eslint": "^8.24.1", - "vite": "^6.2.4", + "vite": "^6.2.5", "vitest": "^3.0.8" }, "engines": { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 37bd6705..437b2d09 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -44,7 +44,7 @@ importers: version: 19.0.4(@types/react@19.0.10) '@vitejs/plugin-react-swc': specifier: ^3.8.0 - version: 3.8.0(vite@6.2.4(@types/node@22.13.10)(jiti@1.21.7)(yaml@2.7.0)) + version: 3.8.0(vite@6.2.5(@types/node@22.13.10)(jiti@1.21.7)(yaml@2.7.0)) '@vitest/coverage-v8': specifier: ^1.5.0 version: 1.6.1(vitest@3.0.8(@types/node@22.13.10)(jiti@1.21.7)(jsdom@24.1.3)(yaml@2.7.0)) @@ -91,8 +91,8 @@ importers: specifier: ^8.24.1 version: 8.26.0(eslint@9.22.0(jiti@1.21.7))(typescript@5.7.3) vite: - specifier: ^6.2.4 - version: 6.2.4(@types/node@22.13.10)(jiti@1.21.7)(yaml@2.7.0) + specifier: ^6.2.5 + version: 6.2.5(@types/node@22.13.10)(jiti@1.21.7)(yaml@2.7.0) vitest: specifier: ^3.0.8 version: 3.0.8(@types/node@22.13.10)(jiti@1.21.7)(jsdom@24.1.3)(yaml@2.7.0) @@ -454,103 +454,103 @@ packages: resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} engines: {node: '>=14'} - '@rollup/rollup-android-arm-eabi@4.38.0': - resolution: {integrity: sha512-ldomqc4/jDZu/xpYU+aRxo3V4mGCV9HeTgUBANI3oIQMOL+SsxB+S2lxMpkFp5UamSS3XuTMQVbsS24R4J4Qjg==} + '@rollup/rollup-android-arm-eabi@4.39.0': + resolution: {integrity: sha512-lGVys55Qb00Wvh8DMAocp5kIcaNzEFTmGhfFd88LfaogYTRKrdxgtlO5H6S49v2Nd8R2C6wLOal0qv6/kCkOwA==} cpu: [arm] os: [android] - '@rollup/rollup-android-arm64@4.38.0': - resolution: {integrity: sha512-VUsgcy4GhhT7rokwzYQP+aV9XnSLkkhlEJ0St8pbasuWO/vwphhZQxYEKUP3ayeCYLhk6gEtacRpYP/cj3GjyQ==} + '@rollup/rollup-android-arm64@4.39.0': + resolution: {integrity: sha512-It9+M1zE31KWfqh/0cJLrrsCPiF72PoJjIChLX+rEcujVRCb4NLQ5QzFkzIZW8Kn8FTbvGQBY5TkKBau3S8cCQ==} cpu: [arm64] os: [android] - '@rollup/rollup-darwin-arm64@4.38.0': - resolution: {integrity: sha512-buA17AYXlW9Rn091sWMq1xGUvWQFOH4N1rqUxGJtEQzhChxWjldGCCup7r/wUnaI6Au8sKXpoh0xg58a7cgcpg==} + '@rollup/rollup-darwin-arm64@4.39.0': + resolution: {integrity: sha512-lXQnhpFDOKDXiGxsU9/l8UEGGM65comrQuZ+lDcGUx+9YQ9dKpF3rSEGepyeR5AHZ0b5RgiligsBhWZfSSQh8Q==} cpu: [arm64] os: [darwin] - '@rollup/rollup-darwin-x64@4.38.0': - resolution: {integrity: sha512-Mgcmc78AjunP1SKXl624vVBOF2bzwNWFPMP4fpOu05vS0amnLcX8gHIge7q/lDAHy3T2HeR0TqrriZDQS2Woeg==} + '@rollup/rollup-darwin-x64@4.39.0': + resolution: {integrity: sha512-mKXpNZLvtEbgu6WCkNij7CGycdw9cJi2k9v0noMb++Vab12GZjFgUXD69ilAbBh034Zwn95c2PNSz9xM7KYEAQ==} cpu: [x64] os: [darwin] - '@rollup/rollup-freebsd-arm64@4.38.0': - resolution: {integrity: sha512-zzJACgjLbQTsscxWqvrEQAEh28hqhebpRz5q/uUd1T7VTwUNZ4VIXQt5hE7ncs0GrF+s7d3S4on4TiXUY8KoQA==} + '@rollup/rollup-freebsd-arm64@4.39.0': + resolution: {integrity: sha512-jivRRlh2Lod/KvDZx2zUR+I4iBfHcu2V/BA2vasUtdtTN2Uk3jfcZczLa81ESHZHPHy4ih3T/W5rPFZ/hX7RtQ==} cpu: [arm64] os: [freebsd] - '@rollup/rollup-freebsd-x64@4.38.0': - resolution: {integrity: sha512-hCY/KAeYMCyDpEE4pTETam0XZS4/5GXzlLgpi5f0IaPExw9kuB+PDTOTLuPtM10TlRG0U9OSmXJ+Wq9J39LvAg==} + '@rollup/rollup-freebsd-x64@4.39.0': + resolution: {integrity: sha512-8RXIWvYIRK9nO+bhVz8DwLBepcptw633gv/QT4015CpJ0Ht8punmoHU/DuEd3iw9Hr8UwUV+t+VNNuZIWYeY7Q==} cpu: [x64] os: [freebsd] - '@rollup/rollup-linux-arm-gnueabihf@4.38.0': - resolution: {integrity: sha512-mimPH43mHl4JdOTD7bUMFhBdrg6f9HzMTOEnzRmXbOZqjijCw8LA5z8uL6LCjxSa67H2xiLFvvO67PT05PRKGg==} + '@rollup/rollup-linux-arm-gnueabihf@4.39.0': + resolution: {integrity: sha512-mz5POx5Zu58f2xAG5RaRRhp3IZDK7zXGk5sdEDj4o96HeaXhlUwmLFzNlc4hCQi5sGdR12VDgEUqVSHer0lI9g==} cpu: [arm] os: [linux] - '@rollup/rollup-linux-arm-musleabihf@4.38.0': - resolution: {integrity: sha512-tPiJtiOoNuIH8XGG8sWoMMkAMm98PUwlriOFCCbZGc9WCax+GLeVRhmaxjJtz6WxrPKACgrwoZ5ia/uapq3ZVg==} + '@rollup/rollup-linux-arm-musleabihf@4.39.0': + resolution: {integrity: sha512-+YDwhM6gUAyakl0CD+bMFpdmwIoRDzZYaTWV3SDRBGkMU/VpIBYXXEvkEcTagw/7VVkL2vA29zU4UVy1mP0/Yw==} cpu: [arm] os: [linux] - '@rollup/rollup-linux-arm64-gnu@4.38.0': - resolution: {integrity: sha512-wZco59rIVuB0tjQS0CSHTTUcEde+pXQWugZVxWaQFdQQ1VYub/sTrNdY76D1MKdN2NB48JDuGABP6o6fqos8mA==} + '@rollup/rollup-linux-arm64-gnu@4.39.0': + resolution: {integrity: sha512-EKf7iF7aK36eEChvlgxGnk7pdJfzfQbNvGV/+l98iiMwU23MwvmV0Ty3pJ0p5WQfm3JRHOytSIqD9LB7Bq7xdQ==} cpu: [arm64] os: [linux] - '@rollup/rollup-linux-arm64-musl@4.38.0': - resolution: {integrity: sha512-fQgqwKmW0REM4LomQ+87PP8w8xvU9LZfeLBKybeli+0yHT7VKILINzFEuggvnV9M3x1Ed4gUBmGUzCo/ikmFbQ==} + '@rollup/rollup-linux-arm64-musl@4.39.0': + resolution: {integrity: sha512-vYanR6MtqC7Z2SNr8gzVnzUul09Wi1kZqJaek3KcIlI/wq5Xtq4ZPIZ0Mr/st/sv/NnaPwy/D4yXg5x0B3aUUA==} cpu: [arm64] os: [linux] - '@rollup/rollup-linux-loongarch64-gnu@4.38.0': - resolution: {integrity: sha512-hz5oqQLXTB3SbXpfkKHKXLdIp02/w3M+ajp8p4yWOWwQRtHWiEOCKtc9U+YXahrwdk+3qHdFMDWR5k+4dIlddg==} + '@rollup/rollup-linux-loongarch64-gnu@4.39.0': + resolution: {integrity: sha512-NMRUT40+h0FBa5fb+cpxtZoGAggRem16ocVKIv5gDB5uLDgBIwrIsXlGqYbLwW8YyO3WVTk1FkFDjMETYlDqiw==} cpu: [loong64] os: [linux] - '@rollup/rollup-linux-powerpc64le-gnu@4.38.0': - resolution: {integrity: sha512-NXqygK/dTSibQ+0pzxsL3r4Xl8oPqVoWbZV9niqOnIHV/J92fe65pOir0xjkUZDRSPyFRvu+4YOpJF9BZHQImw==} + '@rollup/rollup-linux-powerpc64le-gnu@4.39.0': + resolution: {integrity: sha512-0pCNnmxgduJ3YRt+D+kJ6Ai/r+TaePu9ZLENl+ZDV/CdVczXl95CbIiwwswu4L+K7uOIGf6tMo2vm8uadRaICQ==} cpu: [ppc64] os: [linux] - '@rollup/rollup-linux-riscv64-gnu@4.38.0': - resolution: {integrity: sha512-GEAIabR1uFyvf/jW/5jfu8gjM06/4kZ1W+j1nWTSSB3w6moZEBm7iBtzwQ3a1Pxos2F7Gz+58aVEnZHU295QTg==} + '@rollup/rollup-linux-riscv64-gnu@4.39.0': + resolution: {integrity: sha512-t7j5Zhr7S4bBtksT73bO6c3Qa2AV/HqiGlj9+KB3gNF5upcVkx+HLgxTm8DK4OkzsOYqbdqbLKwvGMhylJCPhQ==} cpu: [riscv64] os: [linux] - '@rollup/rollup-linux-riscv64-musl@4.38.0': - resolution: {integrity: sha512-9EYTX+Gus2EGPbfs+fh7l95wVADtSQyYw4DfSBcYdUEAmP2lqSZY0Y17yX/3m5VKGGJ4UmIH5LHLkMJft3bYoA==} + '@rollup/rollup-linux-riscv64-musl@4.39.0': + resolution: {integrity: sha512-m6cwI86IvQ7M93MQ2RF5SP8tUjD39Y7rjb1qjHgYh28uAPVU8+k/xYWvxRO3/tBN2pZkSMa5RjnPuUIbrwVxeA==} cpu: [riscv64] os: [linux] - '@rollup/rollup-linux-s390x-gnu@4.38.0': - resolution: {integrity: sha512-Mpp6+Z5VhB9VDk7RwZXoG2qMdERm3Jw07RNlXHE0bOnEeX+l7Fy4bg+NxfyN15ruuY3/7Vrbpm75J9QHFqj5+Q==} + '@rollup/rollup-linux-s390x-gnu@4.39.0': + resolution: {integrity: sha512-iRDJd2ebMunnk2rsSBYlsptCyuINvxUfGwOUldjv5M4tpa93K8tFMeYGpNk2+Nxl+OBJnBzy2/JCscGeO507kA==} cpu: [s390x] os: [linux] - '@rollup/rollup-linux-x64-gnu@4.38.0': - resolution: {integrity: sha512-vPvNgFlZRAgO7rwncMeE0+8c4Hmc+qixnp00/Uv3ht2x7KYrJ6ERVd3/R0nUtlE6/hu7/HiiNHJ/rP6knRFt1w==} + '@rollup/rollup-linux-x64-gnu@4.39.0': + resolution: {integrity: sha512-t9jqYw27R6Lx0XKfEFe5vUeEJ5pF3SGIM6gTfONSMb7DuG6z6wfj2yjcoZxHg129veTqU7+wOhY6GX8wmf90dA==} cpu: [x64] os: [linux] - '@rollup/rollup-linux-x64-musl@4.38.0': - resolution: {integrity: sha512-q5Zv+goWvQUGCaL7fU8NuTw8aydIL/C9abAVGCzRReuj5h30TPx4LumBtAidrVOtXnlB+RZkBtExMsfqkMfb8g==} + '@rollup/rollup-linux-x64-musl@4.39.0': + resolution: {integrity: sha512-ThFdkrFDP55AIsIZDKSBWEt/JcWlCzydbZHinZ0F/r1h83qbGeenCt/G/wG2O0reuENDD2tawfAj2s8VK7Bugg==} cpu: [x64] os: [linux] - '@rollup/rollup-win32-arm64-msvc@4.38.0': - resolution: {integrity: sha512-u/Jbm1BU89Vftqyqbmxdq14nBaQjQX1HhmsdBWqSdGClNaKwhjsg5TpW+5Ibs1mb8Es9wJiMdl86BcmtUVXNZg==} + '@rollup/rollup-win32-arm64-msvc@4.39.0': + resolution: {integrity: sha512-jDrLm6yUtbOg2TYB3sBF3acUnAwsIksEYjLeHL+TJv9jg+TmTwdyjnDex27jqEMakNKf3RwwPahDIt7QXCSqRQ==} cpu: [arm64] os: [win32] - '@rollup/rollup-win32-ia32-msvc@4.38.0': - resolution: {integrity: sha512-mqu4PzTrlpNHHbu5qleGvXJoGgHpChBlrBx/mEhTPpnAL1ZAYFlvHD7rLK839LLKQzqEQMFJfGrrOHItN4ZQqA==} + '@rollup/rollup-win32-ia32-msvc@4.39.0': + resolution: {integrity: sha512-6w9uMuza+LbLCVoNKL5FSLE7yvYkq9laSd09bwS0tMjkwXrmib/4KmoJcrKhLWHvw19mwU+33ndC69T7weNNjQ==} cpu: [ia32] os: [win32] - '@rollup/rollup-win32-x64-msvc@4.38.0': - resolution: {integrity: sha512-jjqy3uWlecfB98Psxb5cD6Fny9Fupv9LrDSPTQZUROqjvZmcCqNu4UMl7qqhlUUGpwiAkotj6GYu4SZdcr/nLw==} + '@rollup/rollup-win32-x64-msvc@4.39.0': + resolution: {integrity: sha512-yAkUOkIKZlK5dl7u6dg897doBgLXmUHhIINM2c+sND3DZwnrdQkkSiDh7N75Ll4mM4dxSkYfXqU9fW3lLkMFug==} cpu: [x64] os: [win32] @@ -2123,8 +2123,8 @@ packages: rfdc@1.4.1: resolution: {integrity: sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==} - rollup@4.38.0: - resolution: {integrity: sha512-5SsIRtJy9bf1ErAOiFMFzl64Ex9X5V7bnJ+WlFMb+zmP459OSWCEG7b0ERZ+PEU7xPt4OG3RHbrp1LJlXxYTrw==} + rollup@4.39.0: + resolution: {integrity: sha512-thI8kNc02yNvnmJp8dr3fNWJ9tCONDhp6TV35X6HkKGGs9E6q7YWCHbe5vKiTa7TAiNcFEmXKj3X/pG2b3ci0g==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true @@ -2431,8 +2431,8 @@ packages: engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} hasBin: true - vite@6.2.4: - resolution: {integrity: sha512-veHMSew8CcRzhL5o8ONjy8gkfmFJAd5Ac16oxBUjlwgX3Gq2Wqr+qNC3TjPIpy7TPV/KporLga5GT9HqdrCizw==} + vite@6.2.5: + resolution: {integrity: sha512-j023J/hCAa4pRIUH6J9HemwYfjB5llR2Ps0CWeikOtdR8+pAURAk0DoJC5/mm9kd+UgdnIy7d6HE4EAvlYhPhA==} engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} hasBin: true peerDependencies: @@ -2921,64 +2921,64 @@ snapshots: '@pkgjs/parseargs@0.11.0': optional: true - '@rollup/rollup-android-arm-eabi@4.38.0': + '@rollup/rollup-android-arm-eabi@4.39.0': optional: true - '@rollup/rollup-android-arm64@4.38.0': + '@rollup/rollup-android-arm64@4.39.0': optional: true - '@rollup/rollup-darwin-arm64@4.38.0': + '@rollup/rollup-darwin-arm64@4.39.0': optional: true - '@rollup/rollup-darwin-x64@4.38.0': + '@rollup/rollup-darwin-x64@4.39.0': optional: true - '@rollup/rollup-freebsd-arm64@4.38.0': + '@rollup/rollup-freebsd-arm64@4.39.0': optional: true - '@rollup/rollup-freebsd-x64@4.38.0': + '@rollup/rollup-freebsd-x64@4.39.0': optional: true - '@rollup/rollup-linux-arm-gnueabihf@4.38.0': + '@rollup/rollup-linux-arm-gnueabihf@4.39.0': optional: true - '@rollup/rollup-linux-arm-musleabihf@4.38.0': + '@rollup/rollup-linux-arm-musleabihf@4.39.0': optional: true - '@rollup/rollup-linux-arm64-gnu@4.38.0': + '@rollup/rollup-linux-arm64-gnu@4.39.0': optional: true - '@rollup/rollup-linux-arm64-musl@4.38.0': + '@rollup/rollup-linux-arm64-musl@4.39.0': optional: true - '@rollup/rollup-linux-loongarch64-gnu@4.38.0': + '@rollup/rollup-linux-loongarch64-gnu@4.39.0': optional: true - '@rollup/rollup-linux-powerpc64le-gnu@4.38.0': + '@rollup/rollup-linux-powerpc64le-gnu@4.39.0': optional: true - '@rollup/rollup-linux-riscv64-gnu@4.38.0': + '@rollup/rollup-linux-riscv64-gnu@4.39.0': optional: true - '@rollup/rollup-linux-riscv64-musl@4.38.0': + '@rollup/rollup-linux-riscv64-musl@4.39.0': optional: true - '@rollup/rollup-linux-s390x-gnu@4.38.0': + '@rollup/rollup-linux-s390x-gnu@4.39.0': optional: true - '@rollup/rollup-linux-x64-gnu@4.38.0': + '@rollup/rollup-linux-x64-gnu@4.39.0': optional: true - '@rollup/rollup-linux-x64-musl@4.38.0': + '@rollup/rollup-linux-x64-musl@4.39.0': optional: true - '@rollup/rollup-win32-arm64-msvc@4.38.0': + '@rollup/rollup-win32-arm64-msvc@4.39.0': optional: true - '@rollup/rollup-win32-ia32-msvc@4.38.0': + '@rollup/rollup-win32-ia32-msvc@4.39.0': optional: true - '@rollup/rollup-win32-x64-msvc@4.38.0': + '@rollup/rollup-win32-x64-msvc@4.39.0': optional: true '@swc/core-darwin-arm64@1.11.8': @@ -3174,10 +3174,10 @@ snapshots: '@typescript-eslint/types': 8.26.0 eslint-visitor-keys: 4.2.0 - '@vitejs/plugin-react-swc@3.8.0(vite@6.2.4(@types/node@22.13.10)(jiti@1.21.7)(yaml@2.7.0))': + '@vitejs/plugin-react-swc@3.8.0(vite@6.2.5(@types/node@22.13.10)(jiti@1.21.7)(yaml@2.7.0))': dependencies: '@swc/core': 1.11.8 - vite: 6.2.4(@types/node@22.13.10)(jiti@1.21.7)(yaml@2.7.0) + vite: 6.2.5(@types/node@22.13.10)(jiti@1.21.7)(yaml@2.7.0) transitivePeerDependencies: - '@swc/helpers' @@ -3207,13 +3207,13 @@ snapshots: chai: 5.2.0 tinyrainbow: 2.0.0 - '@vitest/mocker@3.0.8(vite@6.2.4(@types/node@22.13.10)(jiti@1.21.7)(yaml@2.7.0))': + '@vitest/mocker@3.0.8(vite@6.2.5(@types/node@22.13.10)(jiti@1.21.7)(yaml@2.7.0))': dependencies: '@vitest/spy': 3.0.8 estree-walker: 3.0.3 magic-string: 0.30.17 optionalDependencies: - vite: 6.2.4(@types/node@22.13.10)(jiti@1.21.7)(yaml@2.7.0) + vite: 6.2.5(@types/node@22.13.10)(jiti@1.21.7)(yaml@2.7.0) '@vitest/pretty-format@3.0.8': dependencies: @@ -4610,30 +4610,30 @@ snapshots: rfdc@1.4.1: {} - rollup@4.38.0: + rollup@4.39.0: dependencies: '@types/estree': 1.0.7 optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.38.0 - '@rollup/rollup-android-arm64': 4.38.0 - '@rollup/rollup-darwin-arm64': 4.38.0 - '@rollup/rollup-darwin-x64': 4.38.0 - '@rollup/rollup-freebsd-arm64': 4.38.0 - '@rollup/rollup-freebsd-x64': 4.38.0 - '@rollup/rollup-linux-arm-gnueabihf': 4.38.0 - '@rollup/rollup-linux-arm-musleabihf': 4.38.0 - '@rollup/rollup-linux-arm64-gnu': 4.38.0 - '@rollup/rollup-linux-arm64-musl': 4.38.0 - '@rollup/rollup-linux-loongarch64-gnu': 4.38.0 - '@rollup/rollup-linux-powerpc64le-gnu': 4.38.0 - '@rollup/rollup-linux-riscv64-gnu': 4.38.0 - '@rollup/rollup-linux-riscv64-musl': 4.38.0 - '@rollup/rollup-linux-s390x-gnu': 4.38.0 - '@rollup/rollup-linux-x64-gnu': 4.38.0 - '@rollup/rollup-linux-x64-musl': 4.38.0 - '@rollup/rollup-win32-arm64-msvc': 4.38.0 - '@rollup/rollup-win32-ia32-msvc': 4.38.0 - '@rollup/rollup-win32-x64-msvc': 4.38.0 + '@rollup/rollup-android-arm-eabi': 4.39.0 + '@rollup/rollup-android-arm64': 4.39.0 + '@rollup/rollup-darwin-arm64': 4.39.0 + '@rollup/rollup-darwin-x64': 4.39.0 + '@rollup/rollup-freebsd-arm64': 4.39.0 + '@rollup/rollup-freebsd-x64': 4.39.0 + '@rollup/rollup-linux-arm-gnueabihf': 4.39.0 + '@rollup/rollup-linux-arm-musleabihf': 4.39.0 + '@rollup/rollup-linux-arm64-gnu': 4.39.0 + '@rollup/rollup-linux-arm64-musl': 4.39.0 + '@rollup/rollup-linux-loongarch64-gnu': 4.39.0 + '@rollup/rollup-linux-powerpc64le-gnu': 4.39.0 + '@rollup/rollup-linux-riscv64-gnu': 4.39.0 + '@rollup/rollup-linux-riscv64-musl': 4.39.0 + '@rollup/rollup-linux-s390x-gnu': 4.39.0 + '@rollup/rollup-linux-x64-gnu': 4.39.0 + '@rollup/rollup-linux-x64-musl': 4.39.0 + '@rollup/rollup-win32-arm64-msvc': 4.39.0 + '@rollup/rollup-win32-ia32-msvc': 4.39.0 + '@rollup/rollup-win32-x64-msvc': 4.39.0 fsevents: 2.3.3 rrweb-cssom@0.7.1: {} @@ -4947,7 +4947,7 @@ snapshots: debug: 4.4.0(supports-color@8.1.1) es-module-lexer: 1.6.0 pathe: 2.0.3 - vite: 6.2.4(@types/node@22.13.10)(jiti@1.21.7)(yaml@2.7.0) + vite: 6.2.5(@types/node@22.13.10)(jiti@1.21.7)(yaml@2.7.0) transitivePeerDependencies: - '@types/node' - jiti @@ -4962,11 +4962,11 @@ snapshots: - tsx - yaml - vite@6.2.4(@types/node@22.13.10)(jiti@1.21.7)(yaml@2.7.0): + vite@6.2.5(@types/node@22.13.10)(jiti@1.21.7)(yaml@2.7.0): dependencies: esbuild: 0.25.2 postcss: 8.5.3 - rollup: 4.38.0 + rollup: 4.39.0 optionalDependencies: '@types/node': 22.13.10 fsevents: 2.3.3 @@ -4976,7 +4976,7 @@ snapshots: vitest@3.0.8(@types/node@22.13.10)(jiti@1.21.7)(jsdom@24.1.3)(yaml@2.7.0): dependencies: '@vitest/expect': 3.0.8 - '@vitest/mocker': 3.0.8(vite@6.2.4(@types/node@22.13.10)(jiti@1.21.7)(yaml@2.7.0)) + '@vitest/mocker': 3.0.8(vite@6.2.5(@types/node@22.13.10)(jiti@1.21.7)(yaml@2.7.0)) '@vitest/pretty-format': 3.0.8 '@vitest/runner': 3.0.8 '@vitest/snapshot': 3.0.8 @@ -4992,7 +4992,7 @@ snapshots: tinyexec: 0.3.2 tinypool: 1.0.2 tinyrainbow: 2.0.0 - vite: 6.2.4(@types/node@22.13.10)(jiti@1.21.7)(yaml@2.7.0) + vite: 6.2.5(@types/node@22.13.10)(jiti@1.21.7)(yaml@2.7.0) vite-node: 3.0.8(@types/node@22.13.10)(jiti@1.21.7)(yaml@2.7.0) why-is-node-running: 2.3.0 optionalDependencies: From 5af6d3977414b1ee89d861e6673566ff391665c7 Mon Sep 17 00:00:00 2001 From: Marios Tsigkas Date: Tue, 8 Apr 2025 18:43:33 +0300 Subject: [PATCH 78/96] Update deployment workflow to include cypress as a dependency for the build job --- .github/workflows/deploy.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index bdc8a606..fd72289a 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -48,7 +48,7 @@ jobs: build: runs-on: ubuntu-latest - needs: [vitest] # , cypress + needs: [vitest, cypress] steps: - uses: actions/setup-node@v4 with: From f47cb2c4e7816bf845ef57bb74112810728f6d44 Mon Sep 17 00:00:00 2001 From: Marios Tsigkas Date: Tue, 8 Apr 2025 18:49:13 +0300 Subject: [PATCH 79/96] Add SSH key setup instructions to README --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index 3b823847..ec5e81bd 100644 --- a/README.md +++ b/README.md @@ -62,6 +62,12 @@ pnpm dev pnpm build ``` +## Commit +1. create ssh keys https://docs.github.com/en/authentication/connecting-to-github-with-ssh/generating-a-new-ssh-key-and-adding-it-to-the-ssh-agent +2. git config --global gpg.format ssh +3. git config --global user.signingkey git config --global user.signingkey C:\Users\mario\.ssh\id_XXXX.pub +4. Add the .pub data to https://github.com/settings/keys as signing key + ## Testing Run Cypress tests: From 3f4250937d897a1d826c0a61b91671a776f1fa90 Mon Sep 17 00:00:00 2001 From: Marios Tsigkas Date: Wed, 9 Apr 2025 17:13:38 +0300 Subject: [PATCH 80/96] Add instructions for auto-signing commits and tags in README --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index ec5e81bd..323dfa61 100644 --- a/README.md +++ b/README.md @@ -67,6 +67,10 @@ pnpm build 2. git config --global gpg.format ssh 3. git config --global user.signingkey git config --global user.signingkey C:\Users\mario\.ssh\id_XXXX.pub 4. Add the .pub data to https://github.com/settings/keys as signing key +5. Auto sign all commits ```bash +git config --global commit.gpgsign true +git config --global tag.gpgSign true +``` ## Testing From aab4822e3b41d07d42ff72c450fc376c77fd5a99 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 11 Apr 2025 16:11:41 +0000 Subject: [PATCH 81/96] Bump vite in the npm_and_yarn group across 1 directory Bumps the npm_and_yarn group with 1 update in the / directory: [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite). Updates `vite` from 6.2.5 to 6.2.6 - [Release notes](https://github.com/vitejs/vite/releases) - [Changelog](https://github.com/vitejs/vite/blob/v6.2.6/packages/vite/CHANGELOG.md) - [Commits](https://github.com/vitejs/vite/commits/v6.2.6/packages/vite) --- updated-dependencies: - dependency-name: vite dependency-version: 6.2.6 dependency-type: direct:development dependency-group: npm_and_yarn ... Signed-off-by: dependabot[bot] --- package.json | 2 +- pnpm-lock.yaml | 26 +++++++++++++------------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/package.json b/package.json index f75a64e6..75879baa 100644 --- a/package.json +++ b/package.json @@ -46,7 +46,7 @@ "tailwindcss": "^3.4.1", "typescript": "~5.7.2", "typescript-eslint": "^8.24.1", - "vite": "^6.2.5", + "vite": "^6.2.6", "vitest": "^3.0.8" }, "engines": { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 437b2d09..a8a177ff 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -44,7 +44,7 @@ importers: version: 19.0.4(@types/react@19.0.10) '@vitejs/plugin-react-swc': specifier: ^3.8.0 - version: 3.8.0(vite@6.2.5(@types/node@22.13.10)(jiti@1.21.7)(yaml@2.7.0)) + version: 3.8.0(vite@6.2.6(@types/node@22.13.10)(jiti@1.21.7)(yaml@2.7.0)) '@vitest/coverage-v8': specifier: ^1.5.0 version: 1.6.1(vitest@3.0.8(@types/node@22.13.10)(jiti@1.21.7)(jsdom@24.1.3)(yaml@2.7.0)) @@ -91,8 +91,8 @@ importers: specifier: ^8.24.1 version: 8.26.0(eslint@9.22.0(jiti@1.21.7))(typescript@5.7.3) vite: - specifier: ^6.2.5 - version: 6.2.5(@types/node@22.13.10)(jiti@1.21.7)(yaml@2.7.0) + specifier: ^6.2.6 + version: 6.2.6(@types/node@22.13.10)(jiti@1.21.7)(yaml@2.7.0) vitest: specifier: ^3.0.8 version: 3.0.8(@types/node@22.13.10)(jiti@1.21.7)(jsdom@24.1.3)(yaml@2.7.0) @@ -2431,8 +2431,8 @@ packages: engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} hasBin: true - vite@6.2.5: - resolution: {integrity: sha512-j023J/hCAa4pRIUH6J9HemwYfjB5llR2Ps0CWeikOtdR8+pAURAk0DoJC5/mm9kd+UgdnIy7d6HE4EAvlYhPhA==} + vite@6.2.6: + resolution: {integrity: sha512-9xpjNl3kR4rVDZgPNdTL0/c6ao4km69a/2ihNQbcANz8RuCOK3hQBmLSJf3bRKVQjVMda+YvizNE8AwvogcPbw==} engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} hasBin: true peerDependencies: @@ -3174,10 +3174,10 @@ snapshots: '@typescript-eslint/types': 8.26.0 eslint-visitor-keys: 4.2.0 - '@vitejs/plugin-react-swc@3.8.0(vite@6.2.5(@types/node@22.13.10)(jiti@1.21.7)(yaml@2.7.0))': + '@vitejs/plugin-react-swc@3.8.0(vite@6.2.6(@types/node@22.13.10)(jiti@1.21.7)(yaml@2.7.0))': dependencies: '@swc/core': 1.11.8 - vite: 6.2.5(@types/node@22.13.10)(jiti@1.21.7)(yaml@2.7.0) + vite: 6.2.6(@types/node@22.13.10)(jiti@1.21.7)(yaml@2.7.0) transitivePeerDependencies: - '@swc/helpers' @@ -3207,13 +3207,13 @@ snapshots: chai: 5.2.0 tinyrainbow: 2.0.0 - '@vitest/mocker@3.0.8(vite@6.2.5(@types/node@22.13.10)(jiti@1.21.7)(yaml@2.7.0))': + '@vitest/mocker@3.0.8(vite@6.2.6(@types/node@22.13.10)(jiti@1.21.7)(yaml@2.7.0))': dependencies: '@vitest/spy': 3.0.8 estree-walker: 3.0.3 magic-string: 0.30.17 optionalDependencies: - vite: 6.2.5(@types/node@22.13.10)(jiti@1.21.7)(yaml@2.7.0) + vite: 6.2.6(@types/node@22.13.10)(jiti@1.21.7)(yaml@2.7.0) '@vitest/pretty-format@3.0.8': dependencies: @@ -4947,7 +4947,7 @@ snapshots: debug: 4.4.0(supports-color@8.1.1) es-module-lexer: 1.6.0 pathe: 2.0.3 - vite: 6.2.5(@types/node@22.13.10)(jiti@1.21.7)(yaml@2.7.0) + vite: 6.2.6(@types/node@22.13.10)(jiti@1.21.7)(yaml@2.7.0) transitivePeerDependencies: - '@types/node' - jiti @@ -4962,7 +4962,7 @@ snapshots: - tsx - yaml - vite@6.2.5(@types/node@22.13.10)(jiti@1.21.7)(yaml@2.7.0): + vite@6.2.6(@types/node@22.13.10)(jiti@1.21.7)(yaml@2.7.0): dependencies: esbuild: 0.25.2 postcss: 8.5.3 @@ -4976,7 +4976,7 @@ snapshots: vitest@3.0.8(@types/node@22.13.10)(jiti@1.21.7)(jsdom@24.1.3)(yaml@2.7.0): dependencies: '@vitest/expect': 3.0.8 - '@vitest/mocker': 3.0.8(vite@6.2.5(@types/node@22.13.10)(jiti@1.21.7)(yaml@2.7.0)) + '@vitest/mocker': 3.0.8(vite@6.2.6(@types/node@22.13.10)(jiti@1.21.7)(yaml@2.7.0)) '@vitest/pretty-format': 3.0.8 '@vitest/runner': 3.0.8 '@vitest/snapshot': 3.0.8 @@ -4992,7 +4992,7 @@ snapshots: tinyexec: 0.3.2 tinypool: 1.0.2 tinyrainbow: 2.0.0 - vite: 6.2.5(@types/node@22.13.10)(jiti@1.21.7)(yaml@2.7.0) + vite: 6.2.6(@types/node@22.13.10)(jiti@1.21.7)(yaml@2.7.0) vite-node: 3.0.8(@types/node@22.13.10)(jiti@1.21.7)(yaml@2.7.0) why-is-node-running: 2.3.0 optionalDependencies: From fa830ede6bd9a997166b358f38b55ae23e20a7f5 Mon Sep 17 00:00:00 2001 From: Marios Tsigkas Date: Sat, 19 Apr 2025 12:33:20 +0300 Subject: [PATCH 82/96] Update README to reflect deployment process on GitHub Pages using GitHub Actions --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 323dfa61..6eea609e 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ Once you have built your app, share your code in the mean suits you best Good luck, potential colleague! # Platform Cat Api React Solution -Check the live site on GitHub Pages at https://mariosh346.github.io/platform-catApi-react/ +Deploy after every commit on GitHub Pages at https://mariosh346.github.io/platform-catApi-react/ with the help of Github Actions ## Prerequisites - nvm (Node Version Manager) or Node v22 From 7b5f83e0ead1220ebfb4653670576144f39d9d42 Mon Sep 17 00:00:00 2001 From: Marios Tsigkas Date: Sat, 19 Apr 2025 13:03:21 +0300 Subject: [PATCH 83/96] Update README to reflect project name change and streamline content --- README.md | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 6eea609e..82f5d2a8 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,6 @@ -# GlobalWebIndex Engineering Challenge +## Project: CatLover -## Exercise: CatLover - -Create a React application for cat lovers which is going to build upon thecatapi.com and will have 3 views. +A React application for cat lovers which is going to build upon thecatapi.com and will have 3 views. The **first** view displays a list of 10 random cat images and a button to load more. Clicking on any of those images opens a modal view with the image and the information about the cat’s breed if available. This would be a link to the second view below - the breed detail. The modal should also contain a form to mark the image as your favourite (a part of the third view as well). Make sure you can copy-paste the URL of the modal and send it to your friends - they should see the same image as you can see. The **second** view displays a list of cat breeds. Each breed opens a modal again with a list of cat images of that breed. Each of those images must be a link to the image detail from the previous point. @@ -12,16 +10,10 @@ The **third** view allows you do the following things: - Display your favourite cats - Remove an image from your favourites (use any UX option you like) -You can find the API documentation here: https://developers.thecatapi.com/ -We give you a lot of freedom in technologies and ways of doing things. We only insist on you using React.js. Get creative as much as you want, we WILL appreciate it. You will not be evaluated based on how well you follow these instructions, but based on how sensible your solution will be. In case you are not able to implement something you would normally implement for time reasons, make it clear with a comment. - -## Submission - -Once you have built your app, share your code in the mean suits you best -Good luck, potential colleague! +API documentation here: https://developers.thecatapi.com/ -# Platform Cat Api React Solution -Deploy after every commit on GitHub Pages at https://mariosh346.github.io/platform-catApi-react/ with the help of Github Actions +# Solution +Deploying after every commit on GitHub Pages at https://mariosh346.github.io/platform-catApi-react/ with the help of Github Actions ## Prerequisites - nvm (Node Version Manager) or Node v22 From ba4f5146664eec7a1b8c3dc16ad8293ed52583b4 Mon Sep 17 00:00:00 2001 From: Marios Tsigkas Date: Tue, 20 May 2025 17:36:11 +0300 Subject: [PATCH 84/96] Update react-router-dom to version 7.6.0 --- package.json | 2 +- pnpm-lock.yaml | 54 +++++++++++++++++++++++++------------------------- 2 files changed, 28 insertions(+), 28 deletions(-) diff --git a/package.json b/package.json index f75a64e6..4f9f7b8d 100644 --- a/package.json +++ b/package.json @@ -21,7 +21,7 @@ "axios-cache-interceptor": "^1.6.2", "react": "^19.0.0", "react-dom": "^19.0.0", - "react-router-dom": "^7.3.0" + "react-router-dom": "^7.6.0" }, "devDependencies": { "@eslint/js": "^9.21.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 437b2d09..33298c4b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -21,8 +21,8 @@ importers: specifier: ^19.0.0 version: 19.0.0(react@19.0.0) react-router-dom: - specifier: ^7.3.0 - version: 7.3.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + specifier: ^7.6.0 + version: 7.6.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0) devDependencies: '@eslint/js': specifier: ^9.21.0 @@ -113,8 +113,8 @@ packages: '@asamuzakjp/css-color@3.1.1': resolution: {integrity: sha512-hpRD68SV2OMcZCsrbdkccTw5FXjNDLo5OuqSHyHZfwweGsDWZwDJ2+gONyNAbazZclobMirACLw0lk8WVxIqxA==} - '@babel/code-frame@7.26.2': - resolution: {integrity: sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==} + '@babel/code-frame@7.27.1': + resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==} engines: {node: '>=6.9.0'} '@babel/helper-string-parser@7.25.9': @@ -125,6 +125,10 @@ packages: resolution: {integrity: sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==} engines: {node: '>=6.9.0'} + '@babel/helper-validator-identifier@7.27.1': + resolution: {integrity: sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==} + engines: {node: '>=6.9.0'} + '@babel/parser@7.26.9': resolution: {integrity: sha512-81NWa1njQblgZbQHxWHpxxCzNsa3ZwvFqpUg7P+NNUU6f3UU2jBEg4OlF/J6rl8+PQGh1q6/zWScd001YwcA5A==} engines: {node: '>=6.0.0'} @@ -134,6 +138,10 @@ packages: resolution: {integrity: sha512-VtPOkrdPHZsKc/clNqyi9WUA8TINkZ4cGk63UUE3u4pmB2k+ZMQRDuIOagv8UVd6j7k0T3+RRIb7beKTebNbcw==} engines: {node: '>=6.9.0'} + '@babel/runtime@7.27.1': + resolution: {integrity: sha512-1x3D2xEk2fRo3PAhwQwu5UubzgiVWSXTBfWpVd2Mx2AzRqJuDJCsgaDVZ7HB5iGzDW1Hl1sWN2mFyKjmR9uAog==} + engines: {node: '>=6.9.0'} + '@babel/types@7.26.9': resolution: {integrity: sha512-Y3IR1cRnOxOCDvMmNiym7XpXQ93iGDDPHx+Zj+NM+rg0fBaShfQLkg+hKPaZCEvg5N/LeCo4+Rj/i3FuJsIQaw==} engines: {node: '>=6.9.0'} @@ -655,9 +663,6 @@ packages: '@types/aria-query@5.0.4': resolution: {integrity: sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==} - '@types/cookie@0.6.0': - resolution: {integrity: sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==} - '@types/estree@1.0.6': resolution: {integrity: sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==} @@ -2062,15 +2067,15 @@ packages: react-is@17.0.2: resolution: {integrity: sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==} - react-router-dom@7.3.0: - resolution: {integrity: sha512-z7Q5FTiHGgQfEurX/FBinkOXhWREJIAB2RiU24lvcBa82PxUpwqvs/PAXb9lJyPjTs2jrl6UkLvCZVGJPeNuuQ==} + react-router-dom@7.6.0: + resolution: {integrity: sha512-DYgm6RDEuKdopSyGOWZGtDfSm7Aofb8CCzgkliTjtu/eDuB0gcsv6qdFhhi8HdtmA+KHkt5MfZ5K2PdzjugYsA==} engines: {node: '>=20.0.0'} peerDependencies: react: '>=18' react-dom: '>=18' - react-router@7.3.0: - resolution: {integrity: sha512-466f2W7HIWaNXTKM5nHTqNxLrHTyXybm7R0eBlVSt0k/u55tTCDO194OIx/NrYD4TS5SXKTNekXfT37kMKUjgw==} + react-router@7.6.0: + resolution: {integrity: sha512-GGufuHIVCJDbnIAXP3P9Sxzq3UUsddG3rrI3ut1q6m0FI6vxVBF3JoPQ38+W/blslLH4a5Yutp8drkEpXoddGQ==} engines: {node: '>=20.0.0'} peerDependencies: react: '>=18' @@ -2358,9 +2363,6 @@ packages: tunnel-agent@0.6.0: resolution: {integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==} - turbo-stream@2.4.0: - resolution: {integrity: sha512-FHncC10WpBd2eOmGwpmQsWLDoK4cqsA/UT/GqNoaKOQnT8uzhtCbg3EoUDMvqpOSAI0S26mr0rkjzbOO6S3v1g==} - tweetnacl@0.14.5: resolution: {integrity: sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==} @@ -2598,9 +2600,9 @@ snapshots: '@csstools/css-tokenizer': 3.0.3 lru-cache: 10.4.3 - '@babel/code-frame@7.26.2': + '@babel/code-frame@7.27.1': dependencies: - '@babel/helper-validator-identifier': 7.25.9 + '@babel/helper-validator-identifier': 7.27.1 js-tokens: 4.0.0 picocolors: 1.1.1 @@ -2608,6 +2610,8 @@ snapshots: '@babel/helper-validator-identifier@7.25.9': {} + '@babel/helper-validator-identifier@7.27.1': {} + '@babel/parser@7.26.9': dependencies: '@babel/types': 7.26.9 @@ -2616,6 +2620,8 @@ snapshots: dependencies: regenerator-runtime: 0.14.1 + '@babel/runtime@7.27.1': {} + '@babel/types@7.26.9': dependencies: '@babel/helper-string-parser': 7.25.9 @@ -3035,8 +3041,8 @@ snapshots: '@testing-library/dom@10.4.0': dependencies: - '@babel/code-frame': 7.26.2 - '@babel/runtime': 7.27.0 + '@babel/code-frame': 7.27.1 + '@babel/runtime': 7.27.1 '@types/aria-query': 5.0.4 aria-query: 5.3.0 chalk: 4.1.2 @@ -3066,8 +3072,6 @@ snapshots: '@types/aria-query@5.0.4': {} - '@types/cookie@0.6.0': {} - '@types/estree@1.0.6': {} '@types/estree@1.0.7': {} @@ -4554,19 +4558,17 @@ snapshots: react-is@17.0.2: {} - react-router-dom@7.3.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0): + react-router-dom@7.6.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0): dependencies: react: 19.0.0 react-dom: 19.0.0(react@19.0.0) - react-router: 7.3.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + react-router: 7.6.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - react-router@7.3.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0): + react-router@7.6.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0): dependencies: - '@types/cookie': 0.6.0 cookie: 1.0.2 react: 19.0.0 set-cookie-parser: 2.7.1 - turbo-stream: 2.4.0 optionalDependencies: react-dom: 19.0.0(react@19.0.0) @@ -4884,8 +4886,6 @@ snapshots: dependencies: safe-buffer: 5.2.1 - turbo-stream@2.4.0: {} - tweetnacl@0.14.5: {} type-check@0.4.0: From fa647c4f2303ab2d11b706d3b001d3f916ba4bab Mon Sep 17 00:00:00 2001 From: Marios Tsigkas Date: Tue, 20 May 2025 17:38:02 +0300 Subject: [PATCH 85/96] Update vite dependency from 6.2.6 to 6.3.5 --- package.json | 2 +- pnpm-lock.yaml | 50 +++++++++++++++++++++++++++++++++++++------------- 2 files changed, 38 insertions(+), 14 deletions(-) diff --git a/package.json b/package.json index 7c73523e..cb05c0b8 100644 --- a/package.json +++ b/package.json @@ -46,7 +46,7 @@ "tailwindcss": "^3.4.1", "typescript": "~5.7.2", "typescript-eslint": "^8.24.1", - "vite": "^6.2.6", + "vite": "^6.3.5", "vitest": "^3.0.8" }, "engines": { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d3958842..6fd61a87 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -44,7 +44,7 @@ importers: version: 19.0.4(@types/react@19.0.10) '@vitejs/plugin-react-swc': specifier: ^3.8.0 - version: 3.8.0(vite@6.2.6(@types/node@22.13.10)(jiti@1.21.7)(yaml@2.7.0)) + version: 3.8.0(vite@6.3.5(@types/node@22.13.10)(jiti@1.21.7)(yaml@2.7.0)) '@vitest/coverage-v8': specifier: ^1.5.0 version: 1.6.1(vitest@3.0.8(@types/node@22.13.10)(jiti@1.21.7)(jsdom@24.1.3)(yaml@2.7.0)) @@ -91,8 +91,8 @@ importers: specifier: ^8.24.1 version: 8.26.0(eslint@9.22.0(jiti@1.21.7))(typescript@5.7.3) vite: - specifier: ^6.2.6 - version: 6.2.6(@types/node@22.13.10)(jiti@1.21.7)(yaml@2.7.0) + specifier: ^6.3.5 + version: 6.3.5(@types/node@22.13.10)(jiti@1.21.7)(yaml@2.7.0) vitest: specifier: ^3.0.8 version: 3.0.8(@types/node@22.13.10)(jiti@1.21.7)(jsdom@24.1.3)(yaml@2.7.0) @@ -1348,6 +1348,14 @@ packages: fd-slicer@1.1.0: resolution: {integrity: sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==} + fdir@6.4.4: + resolution: {integrity: sha512-1NZP+GK4GfuAv3PqKvxQRDMjdSRZjnkq7KfhlNrCNNlZ0ygQFpebfrnfnq/W7fpUnAv9aGWmY1zKx7FYL3gwhg==} + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true + figures@3.2.0: resolution: {integrity: sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==} engines: {node: '>=8'} @@ -2313,6 +2321,10 @@ packages: tinyexec@0.3.2: resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==} + tinyglobby@0.2.13: + resolution: {integrity: sha512-mEwzpUgrLySlveBwEVDMKk5B57bhLPYovRfPAXD5gA/98Opn0rCDj3GtLwFvCvH5RK9uPCExUROW5NjDwvqkxw==} + engines: {node: '>=12.0.0'} + tinypool@1.0.2: resolution: {integrity: sha512-al6n+QEANGFOMf/dmUMsuS5/r9B06uwlyNjZZql/zv8J7ybHCgoihBNORZCY2mzUuAnomQa2JdhyHKzZxPCrFA==} engines: {node: ^18.0.0 || >=20.0.0} @@ -2433,8 +2445,8 @@ packages: engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} hasBin: true - vite@6.2.6: - resolution: {integrity: sha512-9xpjNl3kR4rVDZgPNdTL0/c6ao4km69a/2ihNQbcANz8RuCOK3hQBmLSJf3bRKVQjVMda+YvizNE8AwvogcPbw==} + vite@6.3.5: + resolution: {integrity: sha512-cZn6NDFE7wdTpINgs++ZJ4N49W2vRp8LCKrn3Ob1kYNtOo21vfDoaV5GzBfLU4MovSAB8uNRm4jgzVQZ+mBzPQ==} engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} hasBin: true peerDependencies: @@ -3178,10 +3190,10 @@ snapshots: '@typescript-eslint/types': 8.26.0 eslint-visitor-keys: 4.2.0 - '@vitejs/plugin-react-swc@3.8.0(vite@6.2.6(@types/node@22.13.10)(jiti@1.21.7)(yaml@2.7.0))': + '@vitejs/plugin-react-swc@3.8.0(vite@6.3.5(@types/node@22.13.10)(jiti@1.21.7)(yaml@2.7.0))': dependencies: '@swc/core': 1.11.8 - vite: 6.2.6(@types/node@22.13.10)(jiti@1.21.7)(yaml@2.7.0) + vite: 6.3.5(@types/node@22.13.10)(jiti@1.21.7)(yaml@2.7.0) transitivePeerDependencies: - '@swc/helpers' @@ -3211,13 +3223,13 @@ snapshots: chai: 5.2.0 tinyrainbow: 2.0.0 - '@vitest/mocker@3.0.8(vite@6.2.6(@types/node@22.13.10)(jiti@1.21.7)(yaml@2.7.0))': + '@vitest/mocker@3.0.8(vite@6.3.5(@types/node@22.13.10)(jiti@1.21.7)(yaml@2.7.0))': dependencies: '@vitest/spy': 3.0.8 estree-walker: 3.0.3 magic-string: 0.30.17 optionalDependencies: - vite: 6.2.6(@types/node@22.13.10)(jiti@1.21.7)(yaml@2.7.0) + vite: 6.3.5(@types/node@22.13.10)(jiti@1.21.7)(yaml@2.7.0) '@vitest/pretty-format@3.0.8': dependencies: @@ -3868,6 +3880,10 @@ snapshots: dependencies: pend: 1.2.0 + fdir@6.4.4(picomatch@4.0.2): + optionalDependencies: + picomatch: 4.0.2 + figures@3.2.0: dependencies: escape-string-regexp: 1.0.5 @@ -4845,6 +4861,11 @@ snapshots: tinyexec@0.3.2: {} + tinyglobby@0.2.13: + dependencies: + fdir: 6.4.4(picomatch@4.0.2) + picomatch: 4.0.2 + tinypool@1.0.2: {} tinyrainbow@2.0.0: {} @@ -4947,7 +4968,7 @@ snapshots: debug: 4.4.0(supports-color@8.1.1) es-module-lexer: 1.6.0 pathe: 2.0.3 - vite: 6.2.6(@types/node@22.13.10)(jiti@1.21.7)(yaml@2.7.0) + vite: 6.3.5(@types/node@22.13.10)(jiti@1.21.7)(yaml@2.7.0) transitivePeerDependencies: - '@types/node' - jiti @@ -4962,11 +4983,14 @@ snapshots: - tsx - yaml - vite@6.2.6(@types/node@22.13.10)(jiti@1.21.7)(yaml@2.7.0): + vite@6.3.5(@types/node@22.13.10)(jiti@1.21.7)(yaml@2.7.0): dependencies: esbuild: 0.25.2 + fdir: 6.4.4(picomatch@4.0.2) + picomatch: 4.0.2 postcss: 8.5.3 rollup: 4.39.0 + tinyglobby: 0.2.13 optionalDependencies: '@types/node': 22.13.10 fsevents: 2.3.3 @@ -4976,7 +5000,7 @@ snapshots: vitest@3.0.8(@types/node@22.13.10)(jiti@1.21.7)(jsdom@24.1.3)(yaml@2.7.0): dependencies: '@vitest/expect': 3.0.8 - '@vitest/mocker': 3.0.8(vite@6.2.6(@types/node@22.13.10)(jiti@1.21.7)(yaml@2.7.0)) + '@vitest/mocker': 3.0.8(vite@6.3.5(@types/node@22.13.10)(jiti@1.21.7)(yaml@2.7.0)) '@vitest/pretty-format': 3.0.8 '@vitest/runner': 3.0.8 '@vitest/snapshot': 3.0.8 @@ -4992,7 +5016,7 @@ snapshots: tinyexec: 0.3.2 tinypool: 1.0.2 tinyrainbow: 2.0.0 - vite: 6.2.6(@types/node@22.13.10)(jiti@1.21.7)(yaml@2.7.0) + vite: 6.3.5(@types/node@22.13.10)(jiti@1.21.7)(yaml@2.7.0) vite-node: 3.0.8(@types/node@22.13.10)(jiti@1.21.7)(yaml@2.7.0) why-is-node-running: 2.3.0 optionalDependencies: From a8a7d945d5398ec0ef1aca8d3d903cb29b631256 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 12 Jun 2025 13:28:24 +0000 Subject: [PATCH 86/96] Bump brace-expansion in the npm_and_yarn group across 1 directory Bumps the npm_and_yarn group with 1 update in the / directory: [brace-expansion](https://github.com/juliangruber/brace-expansion). Updates `brace-expansion` from 1.1.11 to 1.1.12 - [Release notes](https://github.com/juliangruber/brace-expansion/releases) - [Commits](https://github.com/juliangruber/brace-expansion/compare/1.1.11...v1.1.12) --- updated-dependencies: - dependency-name: brace-expansion dependency-version: 1.1.12 dependency-type: indirect dependency-group: npm_and_yarn ... Signed-off-by: dependabot[bot] --- pnpm-lock.yaml | 39 ++++++++++++++------------------------- 1 file changed, 14 insertions(+), 25 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6fd61a87..aeb2d879 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -121,10 +121,6 @@ packages: resolution: {integrity: sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==} engines: {node: '>=6.9.0'} - '@babel/helper-validator-identifier@7.25.9': - resolution: {integrity: sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==} - engines: {node: '>=6.9.0'} - '@babel/helper-validator-identifier@7.27.1': resolution: {integrity: sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==} engines: {node: '>=6.9.0'} @@ -138,8 +134,8 @@ packages: resolution: {integrity: sha512-VtPOkrdPHZsKc/clNqyi9WUA8TINkZ4cGk63UUE3u4pmB2k+ZMQRDuIOagv8UVd6j7k0T3+RRIb7beKTebNbcw==} engines: {node: '>=6.9.0'} - '@babel/runtime@7.27.1': - resolution: {integrity: sha512-1x3D2xEk2fRo3PAhwQwu5UubzgiVWSXTBfWpVd2Mx2AzRqJuDJCsgaDVZ7HB5iGzDW1Hl1sWN2mFyKjmR9uAog==} + '@babel/runtime@7.27.6': + resolution: {integrity: sha512-vbavdySgbTTrmFE+EsiqUTzlOr5bzlnJtUv9PynGCAKvfQqjIXbvFdumPM/GxMDfyuGMJaJAU6TO4zc1Jf1i8Q==} engines: {node: '>=6.9.0'} '@babel/types@7.26.9': @@ -663,9 +659,6 @@ packages: '@types/aria-query@5.0.4': resolution: {integrity: sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==} - '@types/estree@1.0.6': - resolution: {integrity: sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==} - '@types/estree@1.0.7': resolution: {integrity: sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==} @@ -926,11 +919,11 @@ packages: bluebird@3.7.2: resolution: {integrity: sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==} - brace-expansion@1.1.11: - resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} + brace-expansion@1.1.12: + resolution: {integrity: sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==} - brace-expansion@2.0.1: - resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} + brace-expansion@2.0.2: + resolution: {integrity: sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==} braces@3.0.3: resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} @@ -2620,8 +2613,6 @@ snapshots: '@babel/helper-string-parser@7.25.9': {} - '@babel/helper-validator-identifier@7.25.9': {} - '@babel/helper-validator-identifier@7.27.1': {} '@babel/parser@7.26.9': @@ -2632,12 +2623,12 @@ snapshots: dependencies: regenerator-runtime: 0.14.1 - '@babel/runtime@7.27.1': {} + '@babel/runtime@7.27.6': {} '@babel/types@7.26.9': dependencies: '@babel/helper-string-parser': 7.25.9 - '@babel/helper-validator-identifier': 7.25.9 + '@babel/helper-validator-identifier': 7.27.1 '@bcoe/v8-coverage@0.2.3': {} @@ -3054,7 +3045,7 @@ snapshots: '@testing-library/dom@10.4.0': dependencies: '@babel/code-frame': 7.27.1 - '@babel/runtime': 7.27.1 + '@babel/runtime': 7.27.6 '@types/aria-query': 5.0.4 aria-query: 5.3.0 chalk: 4.1.2 @@ -3084,8 +3075,6 @@ snapshots: '@types/aria-query@5.0.4': {} - '@types/estree@1.0.6': {} - '@types/estree@1.0.7': {} '@types/json-schema@7.0.15': {} @@ -3378,12 +3367,12 @@ snapshots: bluebird@3.7.2: {} - brace-expansion@1.1.11: + brace-expansion@1.1.12: dependencies: balanced-match: 1.0.2 concat-map: 0.0.1 - brace-expansion@2.0.1: + brace-expansion@2.0.2: dependencies: balanced-match: 1.0.2 @@ -3771,7 +3760,7 @@ snapshots: '@humanfs/node': 0.16.6 '@humanwhocodes/module-importer': 1.0.1 '@humanwhocodes/retry': 0.4.2 - '@types/estree': 1.0.6 + '@types/estree': 1.0.7 '@types/json-schema': 7.0.15 ajv: 6.12.6 chalk: 4.1.2 @@ -4361,11 +4350,11 @@ snapshots: minimatch@3.1.2: dependencies: - brace-expansion: 1.1.11 + brace-expansion: 1.1.12 minimatch@9.0.5: dependencies: - brace-expansion: 2.0.1 + brace-expansion: 2.0.2 minimist@1.2.8: {} From 20e19ec0dd51ef43cfa1b7c1932ff6498cf3d91f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 19 Sep 2025 14:40:04 +0000 Subject: [PATCH 87/96] Bump the npm_and_yarn group across 1 directory with 4 updates Bumps the npm_and_yarn group with 4 updates in the / directory: [axios](https://github.com/axios/axios), [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite), [@eslint/plugin-kit](https://github.com/eslint/rewrite/tree/HEAD/packages/plugin-kit) and [tmp](https://github.com/raszi/node-tmp). Updates `axios` from 1.8.2 to 1.12.0 - [Release notes](https://github.com/axios/axios/releases) - [Changelog](https://github.com/axios/axios/blob/v1.x/CHANGELOG.md) - [Commits](https://github.com/axios/axios/compare/v1.8.2...v1.12.0) Updates `vite` from 6.3.5 to 6.3.6 - [Release notes](https://github.com/vitejs/vite/releases) - [Changelog](https://github.com/vitejs/vite/blob/v6.3.6/packages/vite/CHANGELOG.md) - [Commits](https://github.com/vitejs/vite/commits/v6.3.6/packages/vite) Updates `@eslint/plugin-kit` from 0.2.7 to 0.2.8 - [Release notes](https://github.com/eslint/rewrite/releases) - [Changelog](https://github.com/eslint/rewrite/blob/main/packages/plugin-kit/CHANGELOG.md) - [Commits](https://github.com/eslint/rewrite/commits/plugin-kit-v0.2.8/packages/plugin-kit) Updates `tmp` from 0.2.3 to 0.2.5 - [Changelog](https://github.com/raszi/node-tmp/blob/master/CHANGELOG.md) - [Commits](https://github.com/raszi/node-tmp/compare/v0.2.3...v0.2.5) --- updated-dependencies: - dependency-name: axios dependency-version: 1.12.0 dependency-type: direct:production dependency-group: npm_and_yarn - dependency-name: vite dependency-version: 6.3.6 dependency-type: direct:development dependency-group: npm_and_yarn - dependency-name: "@eslint/plugin-kit" dependency-version: 0.2.8 dependency-type: indirect dependency-group: npm_and_yarn - dependency-name: tmp dependency-version: 0.2.5 dependency-type: indirect dependency-group: npm_and_yarn ... Signed-off-by: dependabot[bot] --- package.json | 4 +- pnpm-lock.yaml | 535 ++++++++++++++++++++++++++----------------------- 2 files changed, 284 insertions(+), 255 deletions(-) diff --git a/package.json b/package.json index cb05c0b8..3962d8d0 100644 --- a/package.json +++ b/package.json @@ -17,7 +17,7 @@ "deploy": "gh-pages -d dist" }, "dependencies": { - "axios": "^1.8.2", + "axios": "^1.12.0", "axios-cache-interceptor": "^1.6.2", "react": "^19.0.0", "react-dom": "^19.0.0", @@ -46,7 +46,7 @@ "tailwindcss": "^3.4.1", "typescript": "~5.7.2", "typescript-eslint": "^8.24.1", - "vite": "^6.3.5", + "vite": "^6.3.6", "vitest": "^3.0.8" }, "engines": { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index aeb2d879..8dc37ff1 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -9,11 +9,11 @@ importers: .: dependencies: axios: - specifier: ^1.8.2 - version: 1.8.2 + specifier: ^1.12.0 + version: 1.12.0 axios-cache-interceptor: specifier: ^1.6.2 - version: 1.6.2(axios@1.8.2) + version: 1.6.2(axios@1.12.0) react: specifier: ^19.0.0 version: 19.0.0 @@ -44,7 +44,7 @@ importers: version: 19.0.4(@types/react@19.0.10) '@vitejs/plugin-react-swc': specifier: ^3.8.0 - version: 3.8.0(vite@6.3.5(@types/node@22.13.10)(jiti@1.21.7)(yaml@2.7.0)) + version: 3.8.0(vite@6.3.6(@types/node@22.13.10)(jiti@1.21.7)(yaml@2.7.0)) '@vitest/coverage-v8': specifier: ^1.5.0 version: 1.6.1(vitest@3.0.8(@types/node@22.13.10)(jiti@1.21.7)(jsdom@24.1.3)(yaml@2.7.0)) @@ -91,8 +91,8 @@ importers: specifier: ^8.24.1 version: 8.26.0(eslint@9.22.0(jiti@1.21.7))(typescript@5.7.3) vite: - specifier: ^6.3.5 - version: 6.3.5(@types/node@22.13.10)(jiti@1.21.7)(yaml@2.7.0) + specifier: ^6.3.6 + version: 6.3.6(@types/node@22.13.10)(jiti@1.21.7)(yaml@2.7.0) vitest: specifier: ^3.0.8 version: 3.0.8(@types/node@22.13.10)(jiti@1.21.7)(jsdom@24.1.3)(yaml@2.7.0) @@ -134,8 +134,8 @@ packages: resolution: {integrity: sha512-VtPOkrdPHZsKc/clNqyi9WUA8TINkZ4cGk63UUE3u4pmB2k+ZMQRDuIOagv8UVd6j7k0T3+RRIb7beKTebNbcw==} engines: {node: '>=6.9.0'} - '@babel/runtime@7.27.6': - resolution: {integrity: sha512-vbavdySgbTTrmFE+EsiqUTzlOr5bzlnJtUv9PynGCAKvfQqjIXbvFdumPM/GxMDfyuGMJaJAU6TO4zc1Jf1i8Q==} + '@babel/runtime@7.28.4': + resolution: {integrity: sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==} engines: {node: '>=6.9.0'} '@babel/types@7.26.9': @@ -184,152 +184,158 @@ packages: '@cypress/xvfb@1.2.4': resolution: {integrity: sha512-skbBzPggOVYCbnGgV+0dmBdW/s77ZkAOXIC1knS8NagwDjBrNC1LuXtQJeiN6l+m7lzmHtaoUw/ctJKdqkG57Q==} - '@esbuild/aix-ppc64@0.25.2': - resolution: {integrity: sha512-wCIboOL2yXZym2cgm6mlA742s9QeJ8DjGVaL39dLN4rRwrOgOyYSnOaFPhKZGLb2ngj4EyfAFjsNJwPXZvseag==} + '@esbuild/aix-ppc64@0.25.10': + resolution: {integrity: sha512-0NFWnA+7l41irNuaSVlLfgNT12caWJVLzp5eAVhZ0z1qpxbockccEt3s+149rE64VUI3Ml2zt8Nv5JVc4QXTsw==} engines: {node: '>=18'} cpu: [ppc64] os: [aix] - '@esbuild/android-arm64@0.25.2': - resolution: {integrity: sha512-5ZAX5xOmTligeBaeNEPnPaeEuah53Id2tX4c2CVP3JaROTH+j4fnfHCkr1PjXMd78hMst+TlkfKcW/DlTq0i4w==} + '@esbuild/android-arm64@0.25.10': + resolution: {integrity: sha512-LSQa7eDahypv/VO6WKohZGPSJDq5OVOo3UoFR1E4t4Gj1W7zEQMUhI+lo81H+DtB+kP+tDgBp+M4oNCwp6kffg==} engines: {node: '>=18'} cpu: [arm64] os: [android] - '@esbuild/android-arm@0.25.2': - resolution: {integrity: sha512-NQhH7jFstVY5x8CKbcfa166GoV0EFkaPkCKBQkdPJFvo5u+nGXLEH/ooniLb3QI8Fk58YAx7nsPLozUWfCBOJA==} + '@esbuild/android-arm@0.25.10': + resolution: {integrity: sha512-dQAxF1dW1C3zpeCDc5KqIYuZ1tgAdRXNoZP7vkBIRtKZPYe2xVr/d3SkirklCHudW1B45tGiUlz2pUWDfbDD4w==} engines: {node: '>=18'} cpu: [arm] os: [android] - '@esbuild/android-x64@0.25.2': - resolution: {integrity: sha512-Ffcx+nnma8Sge4jzddPHCZVRvIfQ0kMsUsCMcJRHkGJ1cDmhe4SsrYIjLUKn1xpHZybmOqCWwB0zQvsjdEHtkg==} + '@esbuild/android-x64@0.25.10': + resolution: {integrity: sha512-MiC9CWdPrfhibcXwr39p9ha1x0lZJ9KaVfvzA0Wxwz9ETX4v5CHfF09bx935nHlhi+MxhA63dKRRQLiVgSUtEg==} engines: {node: '>=18'} cpu: [x64] os: [android] - '@esbuild/darwin-arm64@0.25.2': - resolution: {integrity: sha512-MpM6LUVTXAzOvN4KbjzU/q5smzryuoNjlriAIx+06RpecwCkL9JpenNzpKd2YMzLJFOdPqBpuub6eVRP5IgiSA==} + '@esbuild/darwin-arm64@0.25.10': + resolution: {integrity: sha512-JC74bdXcQEpW9KkV326WpZZjLguSZ3DfS8wrrvPMHgQOIEIG/sPXEN/V8IssoJhbefLRcRqw6RQH2NnpdprtMA==} engines: {node: '>=18'} cpu: [arm64] os: [darwin] - '@esbuild/darwin-x64@0.25.2': - resolution: {integrity: sha512-5eRPrTX7wFyuWe8FqEFPG2cU0+butQQVNcT4sVipqjLYQjjh8a8+vUTfgBKM88ObB85ahsnTwF7PSIt6PG+QkA==} + '@esbuild/darwin-x64@0.25.10': + resolution: {integrity: sha512-tguWg1olF6DGqzws97pKZ8G2L7Ig1vjDmGTwcTuYHbuU6TTjJe5FXbgs5C1BBzHbJ2bo1m3WkQDbWO2PvamRcg==} engines: {node: '>=18'} cpu: [x64] os: [darwin] - '@esbuild/freebsd-arm64@0.25.2': - resolution: {integrity: sha512-mLwm4vXKiQ2UTSX4+ImyiPdiHjiZhIaE9QvC7sw0tZ6HoNMjYAqQpGyui5VRIi5sGd+uWq940gdCbY3VLvsO1w==} + '@esbuild/freebsd-arm64@0.25.10': + resolution: {integrity: sha512-3ZioSQSg1HT2N05YxeJWYR+Libe3bREVSdWhEEgExWaDtyFbbXWb49QgPvFH8u03vUPX10JhJPcz7s9t9+boWg==} engines: {node: '>=18'} cpu: [arm64] os: [freebsd] - '@esbuild/freebsd-x64@0.25.2': - resolution: {integrity: sha512-6qyyn6TjayJSwGpm8J9QYYGQcRgc90nmfdUb0O7pp1s4lTY+9D0H9O02v5JqGApUyiHOtkz6+1hZNvNtEhbwRQ==} + '@esbuild/freebsd-x64@0.25.10': + resolution: {integrity: sha512-LLgJfHJk014Aa4anGDbh8bmI5Lk+QidDmGzuC2D+vP7mv/GeSN+H39zOf7pN5N8p059FcOfs2bVlrRr4SK9WxA==} engines: {node: '>=18'} cpu: [x64] os: [freebsd] - '@esbuild/linux-arm64@0.25.2': - resolution: {integrity: sha512-gq/sjLsOyMT19I8obBISvhoYiZIAaGF8JpeXu1u8yPv8BE5HlWYobmlsfijFIZ9hIVGYkbdFhEqC0NvM4kNO0g==} + '@esbuild/linux-arm64@0.25.10': + resolution: {integrity: sha512-5luJWN6YKBsawd5f9i4+c+geYiVEw20FVW5x0v1kEMWNq8UctFjDiMATBxLvmmHA4bf7F6hTRaJgtghFr9iziQ==} engines: {node: '>=18'} cpu: [arm64] os: [linux] - '@esbuild/linux-arm@0.25.2': - resolution: {integrity: sha512-UHBRgJcmjJv5oeQF8EpTRZs/1knq6loLxTsjc3nxO9eXAPDLcWW55flrMVc97qFPbmZP31ta1AZVUKQzKTzb0g==} + '@esbuild/linux-arm@0.25.10': + resolution: {integrity: sha512-oR31GtBTFYCqEBALI9r6WxoU/ZofZl962pouZRTEYECvNF/dtXKku8YXcJkhgK/beU+zedXfIzHijSRapJY3vg==} engines: {node: '>=18'} cpu: [arm] os: [linux] - '@esbuild/linux-ia32@0.25.2': - resolution: {integrity: sha512-bBYCv9obgW2cBP+2ZWfjYTU+f5cxRoGGQ5SeDbYdFCAZpYWrfjjfYwvUpP8MlKbP0nwZ5gyOU/0aUzZ5HWPuvQ==} + '@esbuild/linux-ia32@0.25.10': + resolution: {integrity: sha512-NrSCx2Kim3EnnWgS4Txn0QGt0Xipoumb6z6sUtl5bOEZIVKhzfyp/Lyw4C1DIYvzeW/5mWYPBFJU3a/8Yr75DQ==} engines: {node: '>=18'} cpu: [ia32] os: [linux] - '@esbuild/linux-loong64@0.25.2': - resolution: {integrity: sha512-SHNGiKtvnU2dBlM5D8CXRFdd+6etgZ9dXfaPCeJtz+37PIUlixvlIhI23L5khKXs3DIzAn9V8v+qb1TRKrgT5w==} + '@esbuild/linux-loong64@0.25.10': + resolution: {integrity: sha512-xoSphrd4AZda8+rUDDfD9J6FUMjrkTz8itpTITM4/xgerAZZcFW7Dv+sun7333IfKxGG8gAq+3NbfEMJfiY+Eg==} engines: {node: '>=18'} cpu: [loong64] os: [linux] - '@esbuild/linux-mips64el@0.25.2': - resolution: {integrity: sha512-hDDRlzE6rPeoj+5fsADqdUZl1OzqDYow4TB4Y/3PlKBD0ph1e6uPHzIQcv2Z65u2K0kpeByIyAjCmjn1hJgG0Q==} + '@esbuild/linux-mips64el@0.25.10': + resolution: {integrity: sha512-ab6eiuCwoMmYDyTnyptoKkVS3k8fy/1Uvq7Dj5czXI6DF2GqD2ToInBI0SHOp5/X1BdZ26RKc5+qjQNGRBelRA==} engines: {node: '>=18'} cpu: [mips64el] os: [linux] - '@esbuild/linux-ppc64@0.25.2': - resolution: {integrity: sha512-tsHu2RRSWzipmUi9UBDEzc0nLc4HtpZEI5Ba+Omms5456x5WaNuiG3u7xh5AO6sipnJ9r4cRWQB2tUjPyIkc6g==} + '@esbuild/linux-ppc64@0.25.10': + resolution: {integrity: sha512-NLinzzOgZQsGpsTkEbdJTCanwA5/wozN9dSgEl12haXJBzMTpssebuXR42bthOF3z7zXFWH1AmvWunUCkBE4EA==} engines: {node: '>=18'} cpu: [ppc64] os: [linux] - '@esbuild/linux-riscv64@0.25.2': - resolution: {integrity: sha512-k4LtpgV7NJQOml/10uPU0s4SAXGnowi5qBSjaLWMojNCUICNu7TshqHLAEbkBdAszL5TabfvQ48kK84hyFzjnw==} + '@esbuild/linux-riscv64@0.25.10': + resolution: {integrity: sha512-FE557XdZDrtX8NMIeA8LBJX3dC2M8VGXwfrQWU7LB5SLOajfJIxmSdyL/gU1m64Zs9CBKvm4UAuBp5aJ8OgnrA==} engines: {node: '>=18'} cpu: [riscv64] os: [linux] - '@esbuild/linux-s390x@0.25.2': - resolution: {integrity: sha512-GRa4IshOdvKY7M/rDpRR3gkiTNp34M0eLTaC1a08gNrh4u488aPhuZOCpkF6+2wl3zAN7L7XIpOFBhnaE3/Q8Q==} + '@esbuild/linux-s390x@0.25.10': + resolution: {integrity: sha512-3BBSbgzuB9ajLoVZk0mGu+EHlBwkusRmeNYdqmznmMc9zGASFjSsxgkNsqmXugpPk00gJ0JNKh/97nxmjctdew==} engines: {node: '>=18'} cpu: [s390x] os: [linux] - '@esbuild/linux-x64@0.25.2': - resolution: {integrity: sha512-QInHERlqpTTZ4FRB0fROQWXcYRD64lAoiegezDunLpalZMjcUcld3YzZmVJ2H/Cp0wJRZ8Xtjtj0cEHhYc/uUg==} + '@esbuild/linux-x64@0.25.10': + resolution: {integrity: sha512-QSX81KhFoZGwenVyPoberggdW1nrQZSvfVDAIUXr3WqLRZGZqWk/P4T8p2SP+de2Sr5HPcvjhcJzEiulKgnxtA==} engines: {node: '>=18'} cpu: [x64] os: [linux] - '@esbuild/netbsd-arm64@0.25.2': - resolution: {integrity: sha512-talAIBoY5M8vHc6EeI2WW9d/CkiO9MQJ0IOWX8hrLhxGbro/vBXJvaQXefW2cP0z0nQVTdQ/eNyGFV1GSKrxfw==} + '@esbuild/netbsd-arm64@0.25.10': + resolution: {integrity: sha512-AKQM3gfYfSW8XRk8DdMCzaLUFB15dTrZfnX8WXQoOUpUBQ+NaAFCP1kPS/ykbbGYz7rxn0WS48/81l9hFl3u4A==} engines: {node: '>=18'} cpu: [arm64] os: [netbsd] - '@esbuild/netbsd-x64@0.25.2': - resolution: {integrity: sha512-voZT9Z+tpOxrvfKFyfDYPc4DO4rk06qamv1a/fkuzHpiVBMOhpjK+vBmWM8J1eiB3OLSMFYNaOaBNLXGChf5tg==} + '@esbuild/netbsd-x64@0.25.10': + resolution: {integrity: sha512-7RTytDPGU6fek/hWuN9qQpeGPBZFfB4zZgcz2VK2Z5VpdUxEI8JKYsg3JfO0n/Z1E/6l05n0unDCNc4HnhQGig==} engines: {node: '>=18'} cpu: [x64] os: [netbsd] - '@esbuild/openbsd-arm64@0.25.2': - resolution: {integrity: sha512-dcXYOC6NXOqcykeDlwId9kB6OkPUxOEqU+rkrYVqJbK2hagWOMrsTGsMr8+rW02M+d5Op5NNlgMmjzecaRf7Tg==} + '@esbuild/openbsd-arm64@0.25.10': + resolution: {integrity: sha512-5Se0VM9Wtq797YFn+dLimf2Zx6McttsH2olUBsDml+lm0GOCRVebRWUvDtkY4BWYv/3NgzS8b/UM3jQNh5hYyw==} engines: {node: '>=18'} cpu: [arm64] os: [openbsd] - '@esbuild/openbsd-x64@0.25.2': - resolution: {integrity: sha512-t/TkWwahkH0Tsgoq1Ju7QfgGhArkGLkF1uYz8nQS/PPFlXbP5YgRpqQR3ARRiC2iXoLTWFxc6DJMSK10dVXluw==} + '@esbuild/openbsd-x64@0.25.10': + resolution: {integrity: sha512-XkA4frq1TLj4bEMB+2HnI0+4RnjbuGZfet2gs/LNs5Hc7D89ZQBHQ0gL2ND6Lzu1+QVkjp3x1gIcPKzRNP8bXw==} engines: {node: '>=18'} cpu: [x64] os: [openbsd] - '@esbuild/sunos-x64@0.25.2': - resolution: {integrity: sha512-cfZH1co2+imVdWCjd+D1gf9NjkchVhhdpgb1q5y6Hcv9TP6Zi9ZG/beI3ig8TvwT9lH9dlxLq5MQBBgwuj4xvA==} + '@esbuild/openharmony-arm64@0.25.10': + resolution: {integrity: sha512-AVTSBhTX8Y/Fz6OmIVBip9tJzZEUcY8WLh7I59+upa5/GPhh2/aM6bvOMQySspnCCHvFi79kMtdJS1w0DXAeag==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openharmony] + + '@esbuild/sunos-x64@0.25.10': + resolution: {integrity: sha512-fswk3XT0Uf2pGJmOpDB7yknqhVkJQkAQOcW/ccVOtfx05LkbWOaRAtn5SaqXypeKQra1QaEa841PgrSL9ubSPQ==} engines: {node: '>=18'} cpu: [x64] os: [sunos] - '@esbuild/win32-arm64@0.25.2': - resolution: {integrity: sha512-7Loyjh+D/Nx/sOTzV8vfbB3GJuHdOQyrOryFdZvPHLf42Tk9ivBU5Aedi7iyX+x6rbn2Mh68T4qq1SDqJBQO5Q==} + '@esbuild/win32-arm64@0.25.10': + resolution: {integrity: sha512-ah+9b59KDTSfpaCg6VdJoOQvKjI33nTaQr4UluQwW7aEwZQsbMCfTmfEO4VyewOxx4RaDT/xCy9ra2GPWmO7Kw==} engines: {node: '>=18'} cpu: [arm64] os: [win32] - '@esbuild/win32-ia32@0.25.2': - resolution: {integrity: sha512-WRJgsz9un0nqZJ4MfhabxaD9Ft8KioqU3JMinOTvobbX6MOSUigSBlogP8QB3uxpJDsFS6yN+3FDBdqE5lg9kg==} + '@esbuild/win32-ia32@0.25.10': + resolution: {integrity: sha512-QHPDbKkrGO8/cz9LKVnJU22HOi4pxZnZhhA2HYHez5Pz4JeffhDjf85E57Oyco163GnzNCVkZK0b/n4Y0UHcSw==} engines: {node: '>=18'} cpu: [ia32] os: [win32] - '@esbuild/win32-x64@0.25.2': - resolution: {integrity: sha512-kM3HKb16VIXZyIeVrM1ygYmZBKybX8N4p754bw390wGO3Tf2j4L2/WYL+4suWujpgf6GBYs3jv7TyUivdd05JA==} + '@esbuild/win32-x64@0.25.10': + resolution: {integrity: sha512-9KpxSVFCu0iK1owoez6aC/s/EdUQLDN3adTxGCqxMVhrPDj6bt5dbrHDXUuq+Bs2vATFBBrQS5vdQ/Ed2P+nbw==} engines: {node: '>=18'} cpu: [x64] os: [win32] @@ -380,6 +386,10 @@ packages: resolution: {integrity: sha512-cmrR6pytBuSMTaBweKoGMwu3EiHiEC+DoyupPmlZ0HxBJBtIxwe+j/E4XPIKNx+Q74c8lXKPwYawBf5glsTkHg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@eslint/core@0.13.0': + resolution: {integrity: sha512-yfkgDw1KR66rkT5A8ci4irzDysN7FRpq3ttJolR88OqQikAWqwA8j5VZyas+vjyBNFIJ7MfybJ9plMILI2UrCw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@eslint/eslintrc@3.3.0': resolution: {integrity: sha512-yaVPAiNAalnCZedKLdR21GOGILMLKPyqSLWaAjQFvYA2i/ciDi8ArYVr69Anohb6cH2Ukhqti4aFnYyPm8wdwQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -392,8 +402,8 @@ packages: resolution: {integrity: sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@eslint/plugin-kit@0.2.7': - resolution: {integrity: sha512-JubJ5B2pJ4k4yGxaNLdbjrnk9d/iDz6/q8wOilpIowd6PJPgaxCuHBnBszq7Ce2TyMrywm5r4PnKm6V3iiZF+g==} + '@eslint/plugin-kit@0.2.8': + resolution: {integrity: sha512-ZAoA40rNMPwSm+AeHpCq8STiNAwzWLJuP8Xv4CHIc9wv/PSuExjMrmjfYNj682vW0OOiZ1HKxzvjQr9XZIisQA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@humanfs/core@0.19.1': @@ -458,103 +468,108 @@ packages: resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} engines: {node: '>=14'} - '@rollup/rollup-android-arm-eabi@4.39.0': - resolution: {integrity: sha512-lGVys55Qb00Wvh8DMAocp5kIcaNzEFTmGhfFd88LfaogYTRKrdxgtlO5H6S49v2Nd8R2C6wLOal0qv6/kCkOwA==} + '@rollup/rollup-android-arm-eabi@4.51.0': + resolution: {integrity: sha512-VyfldO8T/C5vAXBGIobrAnUE+VJNVLw5z9h4NgSDq/AJZWt/fXqdW+0PJbk+M74xz7yMDRiHtlsuDV7ew6K20w==} cpu: [arm] os: [android] - '@rollup/rollup-android-arm64@4.39.0': - resolution: {integrity: sha512-It9+M1zE31KWfqh/0cJLrrsCPiF72PoJjIChLX+rEcujVRCb4NLQ5QzFkzIZW8Kn8FTbvGQBY5TkKBau3S8cCQ==} + '@rollup/rollup-android-arm64@4.51.0': + resolution: {integrity: sha512-Z3ujzDZgsEVSokgIhmOAReh9SGT2qloJJX2Xo1Q3nPU1EhCXrV0PbpR3r7DWRgozqnjrPZQkLe5cgBPIYp70Vg==} cpu: [arm64] os: [android] - '@rollup/rollup-darwin-arm64@4.39.0': - resolution: {integrity: sha512-lXQnhpFDOKDXiGxsU9/l8UEGGM65comrQuZ+lDcGUx+9YQ9dKpF3rSEGepyeR5AHZ0b5RgiligsBhWZfSSQh8Q==} + '@rollup/rollup-darwin-arm64@4.51.0': + resolution: {integrity: sha512-T3gskHgArUdR6TCN69li5VELVAZK+iQ4iwMoSMNYixoj+56EC9lTj35rcxhXzIJt40YfBkvDy3GS+t5zh7zM6g==} cpu: [arm64] os: [darwin] - '@rollup/rollup-darwin-x64@4.39.0': - resolution: {integrity: sha512-mKXpNZLvtEbgu6WCkNij7CGycdw9cJi2k9v0noMb++Vab12GZjFgUXD69ilAbBh034Zwn95c2PNSz9xM7KYEAQ==} + '@rollup/rollup-darwin-x64@4.51.0': + resolution: {integrity: sha512-Hh7n/fh0g5UjH6ATDF56Qdf5bzdLZKIbhp5KftjMYG546Ocjeyg15dxphCpH1FFY2PJ2G6MiOVL4jMq5VLTyrQ==} cpu: [x64] os: [darwin] - '@rollup/rollup-freebsd-arm64@4.39.0': - resolution: {integrity: sha512-jivRRlh2Lod/KvDZx2zUR+I4iBfHcu2V/BA2vasUtdtTN2Uk3jfcZczLa81ESHZHPHy4ih3T/W5rPFZ/hX7RtQ==} + '@rollup/rollup-freebsd-arm64@4.51.0': + resolution: {integrity: sha512-0EddADb6FBvfqYoxwVom3hAbAvpSVUbZqmR1wmjk0MSZ06hn/UxxGHKRqEQDMkts7XiZjejVB+TLF28cDTU+gA==} cpu: [arm64] os: [freebsd] - '@rollup/rollup-freebsd-x64@4.39.0': - resolution: {integrity: sha512-8RXIWvYIRK9nO+bhVz8DwLBepcptw633gv/QT4015CpJ0Ht8punmoHU/DuEd3iw9Hr8UwUV+t+VNNuZIWYeY7Q==} + '@rollup/rollup-freebsd-x64@4.51.0': + resolution: {integrity: sha512-MpqaEDLo3JuVPF+wWV4mK7V8akL76WCz8ndfz1aVB7RhvXFO3k7yT7eu8OEuog4VTSyNu5ibvN9n6lgjq/qLEQ==} cpu: [x64] os: [freebsd] - '@rollup/rollup-linux-arm-gnueabihf@4.39.0': - resolution: {integrity: sha512-mz5POx5Zu58f2xAG5RaRRhp3IZDK7zXGk5sdEDj4o96HeaXhlUwmLFzNlc4hCQi5sGdR12VDgEUqVSHer0lI9g==} + '@rollup/rollup-linux-arm-gnueabihf@4.51.0': + resolution: {integrity: sha512-WEWAGFNFFpvSWAIT3MYvxTkYHv/cJl9yWKpjhheg7ONfB0hetZt/uwBnM3GZqSHrk5bXCDYTFXg3jQyk/j7eXQ==} cpu: [arm] os: [linux] - '@rollup/rollup-linux-arm-musleabihf@4.39.0': - resolution: {integrity: sha512-+YDwhM6gUAyakl0CD+bMFpdmwIoRDzZYaTWV3SDRBGkMU/VpIBYXXEvkEcTagw/7VVkL2vA29zU4UVy1mP0/Yw==} + '@rollup/rollup-linux-arm-musleabihf@4.51.0': + resolution: {integrity: sha512-9bxtxj8QoAp++LOq5PGDGkEEOpCDk9rOEHUcXadnijedDH8IXrBt6PnBa4Y6NblvGWdoxvXZYghZLaliTCmAng==} cpu: [arm] os: [linux] - '@rollup/rollup-linux-arm64-gnu@4.39.0': - resolution: {integrity: sha512-EKf7iF7aK36eEChvlgxGnk7pdJfzfQbNvGV/+l98iiMwU23MwvmV0Ty3pJ0p5WQfm3JRHOytSIqD9LB7Bq7xdQ==} + '@rollup/rollup-linux-arm64-gnu@4.51.0': + resolution: {integrity: sha512-DdqA+fARqIsfqDYkKo2nrWMp0kvu/wPJ2G8lZ4DjYhn+8QhrjVuzmsh7tTkhULwjvHTN59nWVzAixmOi6rqjNA==} cpu: [arm64] os: [linux] - '@rollup/rollup-linux-arm64-musl@4.39.0': - resolution: {integrity: sha512-vYanR6MtqC7Z2SNr8gzVnzUul09Wi1kZqJaek3KcIlI/wq5Xtq4ZPIZ0Mr/st/sv/NnaPwy/D4yXg5x0B3aUUA==} + '@rollup/rollup-linux-arm64-musl@4.51.0': + resolution: {integrity: sha512-2XVRNzcUJE1UJua8P4a1GXS5jafFWE+pQ6zhUbZzptOu/70p1F6+0FTi6aGPd6jNtnJqGMjtBCXancC2dhYlWw==} cpu: [arm64] os: [linux] - '@rollup/rollup-linux-loongarch64-gnu@4.39.0': - resolution: {integrity: sha512-NMRUT40+h0FBa5fb+cpxtZoGAggRem16ocVKIv5gDB5uLDgBIwrIsXlGqYbLwW8YyO3WVTk1FkFDjMETYlDqiw==} + '@rollup/rollup-linux-loong64-gnu@4.51.0': + resolution: {integrity: sha512-R8QhY0kLIPCAVXWi2yftDSpn7Jtejey/WhMoBESSfwGec5SKdFVupjxFlKoQ7clVRuaDpiQf7wNx3EBZf4Ey6g==} cpu: [loong64] os: [linux] - '@rollup/rollup-linux-powerpc64le-gnu@4.39.0': - resolution: {integrity: sha512-0pCNnmxgduJ3YRt+D+kJ6Ai/r+TaePu9ZLENl+ZDV/CdVczXl95CbIiwwswu4L+K7uOIGf6tMo2vm8uadRaICQ==} + '@rollup/rollup-linux-ppc64-gnu@4.51.0': + resolution: {integrity: sha512-I498RPfxx9cMv1KTHQ9tg2Ku1utuQm+T5B+Xro+WNu3FzAFSKp4awKfgMoZwjoPgNbaFGINaOM25cQW6WuBhiQ==} cpu: [ppc64] os: [linux] - '@rollup/rollup-linux-riscv64-gnu@4.39.0': - resolution: {integrity: sha512-t7j5Zhr7S4bBtksT73bO6c3Qa2AV/HqiGlj9+KB3gNF5upcVkx+HLgxTm8DK4OkzsOYqbdqbLKwvGMhylJCPhQ==} + '@rollup/rollup-linux-riscv64-gnu@4.51.0': + resolution: {integrity: sha512-o8COudsb8lvtdm9ixg9aKjfX5aeoc2x9KGE7WjtrmQFquoCRZ9jtzGlonujE4WhvXFepTraWzT4RcwyDDeHXjA==} cpu: [riscv64] os: [linux] - '@rollup/rollup-linux-riscv64-musl@4.39.0': - resolution: {integrity: sha512-m6cwI86IvQ7M93MQ2RF5SP8tUjD39Y7rjb1qjHgYh28uAPVU8+k/xYWvxRO3/tBN2pZkSMa5RjnPuUIbrwVxeA==} + '@rollup/rollup-linux-riscv64-musl@4.51.0': + resolution: {integrity: sha512-0shJPgSXMdYzOQzpM5BJN2euXY1f8uV8mS6AnrbMcH2KrkNsbpMxWB1wp8UEdiJ1NtyBkCk3U/HfX5mEONBq6w==} cpu: [riscv64] os: [linux] - '@rollup/rollup-linux-s390x-gnu@4.39.0': - resolution: {integrity: sha512-iRDJd2ebMunnk2rsSBYlsptCyuINvxUfGwOUldjv5M4tpa93K8tFMeYGpNk2+Nxl+OBJnBzy2/JCscGeO507kA==} + '@rollup/rollup-linux-s390x-gnu@4.51.0': + resolution: {integrity: sha512-L7pV+ny7865jamSCQwyozBYjFRUKaTsPqDz7ClOtJCDu4paf2uAa0mrcHwSt4XxZP2ogFZS9uuitH3NXdeBEJA==} cpu: [s390x] os: [linux] - '@rollup/rollup-linux-x64-gnu@4.39.0': - resolution: {integrity: sha512-t9jqYw27R6Lx0XKfEFe5vUeEJ5pF3SGIM6gTfONSMb7DuG6z6wfj2yjcoZxHg129veTqU7+wOhY6GX8wmf90dA==} + '@rollup/rollup-linux-x64-gnu@4.51.0': + resolution: {integrity: sha512-4YHhP+Rv3T3+H3TPbUvWOw5tuSwhrVhkHHZhk4hC9VXeAOKR26/IsUAT4FsB4mT+kfIdxxb1BezQDEg/voPO8A==} cpu: [x64] os: [linux] - '@rollup/rollup-linux-x64-musl@4.39.0': - resolution: {integrity: sha512-ThFdkrFDP55AIsIZDKSBWEt/JcWlCzydbZHinZ0F/r1h83qbGeenCt/G/wG2O0reuENDD2tawfAj2s8VK7Bugg==} + '@rollup/rollup-linux-x64-musl@4.51.0': + resolution: {integrity: sha512-P7U7U03+E5w7WgJtvSseNLOX1UhknVPmEaqgUENFWfNxNBa1OhExT6qYGmyF8gepcxWSaSfJsAV5UwhWrYefdQ==} cpu: [x64] os: [linux] - '@rollup/rollup-win32-arm64-msvc@4.39.0': - resolution: {integrity: sha512-jDrLm6yUtbOg2TYB3sBF3acUnAwsIksEYjLeHL+TJv9jg+TmTwdyjnDex27jqEMakNKf3RwwPahDIt7QXCSqRQ==} + '@rollup/rollup-openharmony-arm64@4.51.0': + resolution: {integrity: sha512-FuD8g3u9W6RPwdO1R45hZFORwa1g9YXEMesAKP/sOi7mDqxjbni8S3zAXJiDcRfGfGBqpRYVuH54Gu3FTuSoEw==} + cpu: [arm64] + os: [openharmony] + + '@rollup/rollup-win32-arm64-msvc@4.51.0': + resolution: {integrity: sha512-zST+FdMCX3QAYfmZX3dp/Fy8qLUetfE17QN5ZmmFGPrhl86qvRr+E9u2bk7fzkIXsfQR30Z7ZRS7WMryPPn4rQ==} cpu: [arm64] os: [win32] - '@rollup/rollup-win32-ia32-msvc@4.39.0': - resolution: {integrity: sha512-6w9uMuza+LbLCVoNKL5FSLE7yvYkq9laSd09bwS0tMjkwXrmib/4KmoJcrKhLWHvw19mwU+33ndC69T7weNNjQ==} + '@rollup/rollup-win32-ia32-msvc@4.51.0': + resolution: {integrity: sha512-U+qhoCVAZmTHCmUKxdQxw1jwAFNFXmOpMME7Npt5GTb1W/7itfgAgNluVOvyeuSeqW+dEQLFuNZF3YZPO8XkMg==} cpu: [ia32] os: [win32] - '@rollup/rollup-win32-x64-msvc@4.39.0': - resolution: {integrity: sha512-yAkUOkIKZlK5dl7u6dg897doBgLXmUHhIINM2c+sND3DZwnrdQkkSiDh7N75Ll4mM4dxSkYfXqU9fW3lLkMFug==} + '@rollup/rollup-win32-x64-msvc@4.51.0': + resolution: {integrity: sha512-z6UpFzMhXSD8NNUfCi2HO+pbpSzSWIIPgb1TZsEZjmZYtk6RUIC63JYjlFBwbBZS3jt3f1q6IGfkj3g+GnBt2Q==} cpu: [x64] os: [win32] @@ -659,8 +674,8 @@ packages: '@types/aria-query@5.0.4': resolution: {integrity: sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==} - '@types/estree@1.0.7': - resolution: {integrity: sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==} + '@types/estree@1.0.8': + resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} '@types/json-schema@7.0.15': resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} @@ -894,8 +909,8 @@ packages: peerDependencies: axios: ^1 - axios@1.8.2: - resolution: {integrity: sha512-ls4GYBm5aig9vWx8AWDSGLpnpDQRtWAfrjU+EuytuODrFBkqesN2RkOQCBzrA1RQNHw1SmRMSDDDSwzNAYQ6Rg==} + axios@1.12.0: + resolution: {integrity: sha512-oXTDccv8PcfjZmPGlWsPSwtOJCZ/b6W5jAMCNcfwJbCzDckwG0jrYJFaWH1yvivfCXjVzV/SPDEhMB3Q+DSurg==} balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} @@ -1196,8 +1211,8 @@ packages: resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==} engines: {node: '>= 0.4'} - esbuild@0.25.2: - resolution: {integrity: sha512-16854zccKPnC+toMywC+uKNeYSv+/eXkevRAfwRD/G9Cleq66m8XFIrigkbvauLLlCfDL45Q2cWegSg53gGBnQ==} + esbuild@0.25.10: + resolution: {integrity: sha512-9RiGKvCwaqxO2owP61uQ4BgNborAQskMR6QusfWzQqv7AZOg5oGehdY2pRJMTKuwxd1IDBP4rSbI5lHzU7SMsQ==} engines: {node: '>=18'} hasBin: true @@ -1341,8 +1356,9 @@ packages: fd-slicer@1.1.0: resolution: {integrity: sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==} - fdir@6.4.4: - resolution: {integrity: sha512-1NZP+GK4GfuAv3PqKvxQRDMjdSRZjnkq7KfhlNrCNNlZ0ygQFpebfrnfnq/W7fpUnAv9aGWmY1zKx7FYL3gwhg==} + fdir@6.5.0: + resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} + engines: {node: '>=12.0.0'} peerDependencies: picomatch: ^3 || ^4 peerDependenciesMeta: @@ -1388,8 +1404,8 @@ packages: flatted@3.3.3: resolution: {integrity: sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==} - follow-redirects@1.15.9: - resolution: {integrity: sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==} + follow-redirects@1.15.11: + resolution: {integrity: sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==} engines: {node: '>=4.0'} peerDependencies: debug: '*' @@ -1408,8 +1424,8 @@ packages: resolution: {integrity: sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==} engines: {node: '>= 0.12'} - form-data@4.0.2: - resolution: {integrity: sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w==} + form-data@4.0.4: + resolution: {integrity: sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==} engines: {node: '>= 6'} fraction.js@4.3.7: @@ -1953,8 +1969,8 @@ packages: resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} engines: {node: '>=8.6'} - picomatch@4.0.2: - resolution: {integrity: sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==} + picomatch@4.0.3: + resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} engines: {node: '>=12'} pify@2.3.0: @@ -2129,8 +2145,8 @@ packages: rfdc@1.4.1: resolution: {integrity: sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==} - rollup@4.39.0: - resolution: {integrity: sha512-thI8kNc02yNvnmJp8dr3fNWJ9tCONDhp6TV35X6HkKGGs9E6q7YWCHbe5vKiTa7TAiNcFEmXKj3X/pG2b3ci0g==} + rollup@4.51.0: + resolution: {integrity: sha512-7cR0XWrdp/UAj2HMY/Y4QQEUjidn3l2AY1wSeZoFjMbD8aOMPoV9wgTFYbrJpPzzvejDEini1h3CiUP8wLzxQA==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true @@ -2314,8 +2330,8 @@ packages: tinyexec@0.3.2: resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==} - tinyglobby@0.2.13: - resolution: {integrity: sha512-mEwzpUgrLySlveBwEVDMKk5B57bhLPYovRfPAXD5gA/98Opn0rCDj3GtLwFvCvH5RK9uPCExUROW5NjDwvqkxw==} + tinyglobby@0.2.15: + resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==} engines: {node: '>=12.0.0'} tinypool@1.0.2: @@ -2330,8 +2346,8 @@ packages: resolution: {integrity: sha512-n1cw8k1k0x4pgA2+9XrOkFydTerNcJ1zWCO5Nn9scWHTD+5tp8dghT2x1uduQePZTZgd3Tupf+x9BxJjeJi77Q==} engines: {node: '>=14.0.0'} - tmp@0.2.3: - resolution: {integrity: sha512-nZD7m9iCPC5g0pYmcaxogYKggSfLsdxl8of3Q/oIbqCqLLIO9IAF0GWjX1z9NZRHPiXv8Wex4yDCaZsgEw0Y8w==} + tmp@0.2.5: + resolution: {integrity: sha512-voyz6MApa1rQGUxT3E+BK7/ROe8itEx7vD8/HEvt4xwXucvQ5G5oeEiHkmHZJuBO21RpOf+YYm9MOivj709jow==} engines: {node: '>=14.14'} to-regex-range@5.0.1: @@ -2438,8 +2454,8 @@ packages: engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} hasBin: true - vite@6.3.5: - resolution: {integrity: sha512-cZn6NDFE7wdTpINgs++ZJ4N49W2vRp8LCKrn3Ob1kYNtOo21vfDoaV5GzBfLU4MovSAB8uNRm4jgzVQZ+mBzPQ==} + vite@6.3.6: + resolution: {integrity: sha512-0msEVHJEScQbhkbVTb/4iHZdJ6SXp/AvxL2sjwYQFfBqleHtnCqv1J3sa9zbWz/6kW1m9Tfzn92vW+kZ1WV6QA==} engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} hasBin: true peerDependencies: @@ -2623,7 +2639,7 @@ snapshots: dependencies: regenerator-runtime: 0.14.1 - '@babel/runtime@7.27.6': {} + '@babel/runtime@7.28.4': {} '@babel/types@7.26.9': dependencies: @@ -2683,79 +2699,82 @@ snapshots: transitivePeerDependencies: - supports-color - '@esbuild/aix-ppc64@0.25.2': + '@esbuild/aix-ppc64@0.25.10': optional: true - '@esbuild/android-arm64@0.25.2': + '@esbuild/android-arm64@0.25.10': optional: true - '@esbuild/android-arm@0.25.2': + '@esbuild/android-arm@0.25.10': optional: true - '@esbuild/android-x64@0.25.2': + '@esbuild/android-x64@0.25.10': optional: true - '@esbuild/darwin-arm64@0.25.2': + '@esbuild/darwin-arm64@0.25.10': optional: true - '@esbuild/darwin-x64@0.25.2': + '@esbuild/darwin-x64@0.25.10': optional: true - '@esbuild/freebsd-arm64@0.25.2': + '@esbuild/freebsd-arm64@0.25.10': optional: true - '@esbuild/freebsd-x64@0.25.2': + '@esbuild/freebsd-x64@0.25.10': optional: true - '@esbuild/linux-arm64@0.25.2': + '@esbuild/linux-arm64@0.25.10': optional: true - '@esbuild/linux-arm@0.25.2': + '@esbuild/linux-arm@0.25.10': optional: true - '@esbuild/linux-ia32@0.25.2': + '@esbuild/linux-ia32@0.25.10': optional: true - '@esbuild/linux-loong64@0.25.2': + '@esbuild/linux-loong64@0.25.10': optional: true - '@esbuild/linux-mips64el@0.25.2': + '@esbuild/linux-mips64el@0.25.10': optional: true - '@esbuild/linux-ppc64@0.25.2': + '@esbuild/linux-ppc64@0.25.10': optional: true - '@esbuild/linux-riscv64@0.25.2': + '@esbuild/linux-riscv64@0.25.10': optional: true - '@esbuild/linux-s390x@0.25.2': + '@esbuild/linux-s390x@0.25.10': optional: true - '@esbuild/linux-x64@0.25.2': + '@esbuild/linux-x64@0.25.10': optional: true - '@esbuild/netbsd-arm64@0.25.2': + '@esbuild/netbsd-arm64@0.25.10': optional: true - '@esbuild/netbsd-x64@0.25.2': + '@esbuild/netbsd-x64@0.25.10': optional: true - '@esbuild/openbsd-arm64@0.25.2': + '@esbuild/openbsd-arm64@0.25.10': optional: true - '@esbuild/openbsd-x64@0.25.2': + '@esbuild/openbsd-x64@0.25.10': optional: true - '@esbuild/sunos-x64@0.25.2': + '@esbuild/openharmony-arm64@0.25.10': optional: true - '@esbuild/win32-arm64@0.25.2': + '@esbuild/sunos-x64@0.25.10': optional: true - '@esbuild/win32-ia32@0.25.2': + '@esbuild/win32-arm64@0.25.10': optional: true - '@esbuild/win32-x64@0.25.2': + '@esbuild/win32-ia32@0.25.10': + optional: true + + '@esbuild/win32-x64@0.25.10': optional: true '@eslint-community/eslint-utils@4.4.1(eslint@9.22.0(jiti@1.21.7))': @@ -2816,7 +2835,7 @@ snapshots: dependencies: '@eslint-react/eff': 1.31.0 '@typescript-eslint/utils': 8.26.0(eslint@9.22.0(jiti@1.21.7))(typescript@5.7.3) - picomatch: 4.0.2 + picomatch: 4.0.3 ts-pattern: 5.6.2 transitivePeerDependencies: - eslint @@ -2851,6 +2870,10 @@ snapshots: dependencies: '@types/json-schema': 7.0.15 + '@eslint/core@0.13.0': + dependencies: + '@types/json-schema': 7.0.15 + '@eslint/eslintrc@3.3.0': dependencies: ajv: 6.12.6 @@ -2869,9 +2892,9 @@ snapshots: '@eslint/object-schema@2.1.6': {} - '@eslint/plugin-kit@0.2.7': + '@eslint/plugin-kit@0.2.8': dependencies: - '@eslint/core': 0.12.0 + '@eslint/core': 0.13.0 levn: 0.4.1 '@humanfs/core@0.19.1': {} @@ -2930,64 +2953,67 @@ snapshots: '@pkgjs/parseargs@0.11.0': optional: true - '@rollup/rollup-android-arm-eabi@4.39.0': + '@rollup/rollup-android-arm-eabi@4.51.0': + optional: true + + '@rollup/rollup-android-arm64@4.51.0': optional: true - '@rollup/rollup-android-arm64@4.39.0': + '@rollup/rollup-darwin-arm64@4.51.0': optional: true - '@rollup/rollup-darwin-arm64@4.39.0': + '@rollup/rollup-darwin-x64@4.51.0': optional: true - '@rollup/rollup-darwin-x64@4.39.0': + '@rollup/rollup-freebsd-arm64@4.51.0': optional: true - '@rollup/rollup-freebsd-arm64@4.39.0': + '@rollup/rollup-freebsd-x64@4.51.0': optional: true - '@rollup/rollup-freebsd-x64@4.39.0': + '@rollup/rollup-linux-arm-gnueabihf@4.51.0': optional: true - '@rollup/rollup-linux-arm-gnueabihf@4.39.0': + '@rollup/rollup-linux-arm-musleabihf@4.51.0': optional: true - '@rollup/rollup-linux-arm-musleabihf@4.39.0': + '@rollup/rollup-linux-arm64-gnu@4.51.0': optional: true - '@rollup/rollup-linux-arm64-gnu@4.39.0': + '@rollup/rollup-linux-arm64-musl@4.51.0': optional: true - '@rollup/rollup-linux-arm64-musl@4.39.0': + '@rollup/rollup-linux-loong64-gnu@4.51.0': optional: true - '@rollup/rollup-linux-loongarch64-gnu@4.39.0': + '@rollup/rollup-linux-ppc64-gnu@4.51.0': optional: true - '@rollup/rollup-linux-powerpc64le-gnu@4.39.0': + '@rollup/rollup-linux-riscv64-gnu@4.51.0': optional: true - '@rollup/rollup-linux-riscv64-gnu@4.39.0': + '@rollup/rollup-linux-riscv64-musl@4.51.0': optional: true - '@rollup/rollup-linux-riscv64-musl@4.39.0': + '@rollup/rollup-linux-s390x-gnu@4.51.0': optional: true - '@rollup/rollup-linux-s390x-gnu@4.39.0': + '@rollup/rollup-linux-x64-gnu@4.51.0': optional: true - '@rollup/rollup-linux-x64-gnu@4.39.0': + '@rollup/rollup-linux-x64-musl@4.51.0': optional: true - '@rollup/rollup-linux-x64-musl@4.39.0': + '@rollup/rollup-openharmony-arm64@4.51.0': optional: true - '@rollup/rollup-win32-arm64-msvc@4.39.0': + '@rollup/rollup-win32-arm64-msvc@4.51.0': optional: true - '@rollup/rollup-win32-ia32-msvc@4.39.0': + '@rollup/rollup-win32-ia32-msvc@4.51.0': optional: true - '@rollup/rollup-win32-x64-msvc@4.39.0': + '@rollup/rollup-win32-x64-msvc@4.51.0': optional: true '@swc/core-darwin-arm64@1.11.8': @@ -3045,7 +3071,7 @@ snapshots: '@testing-library/dom@10.4.0': dependencies: '@babel/code-frame': 7.27.1 - '@babel/runtime': 7.27.6 + '@babel/runtime': 7.28.4 '@types/aria-query': 5.0.4 aria-query: 5.3.0 chalk: 4.1.2 @@ -3075,7 +3101,7 @@ snapshots: '@types/aria-query@5.0.4': {} - '@types/estree@1.0.7': {} + '@types/estree@1.0.8': {} '@types/json-schema@7.0.15': {} @@ -3179,10 +3205,10 @@ snapshots: '@typescript-eslint/types': 8.26.0 eslint-visitor-keys: 4.2.0 - '@vitejs/plugin-react-swc@3.8.0(vite@6.3.5(@types/node@22.13.10)(jiti@1.21.7)(yaml@2.7.0))': + '@vitejs/plugin-react-swc@3.8.0(vite@6.3.6(@types/node@22.13.10)(jiti@1.21.7)(yaml@2.7.0))': dependencies: '@swc/core': 1.11.8 - vite: 6.3.5(@types/node@22.13.10)(jiti@1.21.7)(yaml@2.7.0) + vite: 6.3.6(@types/node@22.13.10)(jiti@1.21.7)(yaml@2.7.0) transitivePeerDependencies: - '@swc/helpers' @@ -3212,13 +3238,13 @@ snapshots: chai: 5.2.0 tinyrainbow: 2.0.0 - '@vitest/mocker@3.0.8(vite@6.3.5(@types/node@22.13.10)(jiti@1.21.7)(yaml@2.7.0))': + '@vitest/mocker@3.0.8(vite@6.3.6(@types/node@22.13.10)(jiti@1.21.7)(yaml@2.7.0))': dependencies: '@vitest/spy': 3.0.8 estree-walker: 3.0.3 magic-string: 0.30.17 optionalDependencies: - vite: 6.3.5(@types/node@22.13.10)(jiti@1.21.7)(yaml@2.7.0) + vite: 6.3.6(@types/node@22.13.10)(jiti@1.21.7)(yaml@2.7.0) '@vitest/pretty-format@3.0.8': dependencies: @@ -3336,17 +3362,17 @@ snapshots: aws4@1.13.2: {} - axios-cache-interceptor@1.6.2(axios@1.8.2): + axios-cache-interceptor@1.6.2(axios@1.12.0): dependencies: - axios: 1.8.2 + axios: 1.12.0 cache-parser: 1.2.5 fast-defer: 1.1.8 object-code: 1.3.3 - axios@1.8.2: + axios@1.12.0: dependencies: - follow-redirects: 1.15.9 - form-data: 4.0.2 + follow-redirects: 1.15.11 + form-data: 4.0.4 proxy-from-env: 1.1.0 transitivePeerDependencies: - debug @@ -3560,7 +3586,7 @@ snapshots: request-progress: 3.0.0 semver: 7.7.1 supports-color: 8.1.1 - tmp: 0.2.3 + tmp: 0.2.5 untildify: 4.0.0 yauzl: 2.10.0 @@ -3654,33 +3680,34 @@ snapshots: has-tostringtag: 1.0.2 hasown: 2.0.2 - esbuild@0.25.2: + esbuild@0.25.10: optionalDependencies: - '@esbuild/aix-ppc64': 0.25.2 - '@esbuild/android-arm': 0.25.2 - '@esbuild/android-arm64': 0.25.2 - '@esbuild/android-x64': 0.25.2 - '@esbuild/darwin-arm64': 0.25.2 - '@esbuild/darwin-x64': 0.25.2 - '@esbuild/freebsd-arm64': 0.25.2 - '@esbuild/freebsd-x64': 0.25.2 - '@esbuild/linux-arm': 0.25.2 - '@esbuild/linux-arm64': 0.25.2 - '@esbuild/linux-ia32': 0.25.2 - '@esbuild/linux-loong64': 0.25.2 - '@esbuild/linux-mips64el': 0.25.2 - '@esbuild/linux-ppc64': 0.25.2 - '@esbuild/linux-riscv64': 0.25.2 - '@esbuild/linux-s390x': 0.25.2 - '@esbuild/linux-x64': 0.25.2 - '@esbuild/netbsd-arm64': 0.25.2 - '@esbuild/netbsd-x64': 0.25.2 - '@esbuild/openbsd-arm64': 0.25.2 - '@esbuild/openbsd-x64': 0.25.2 - '@esbuild/sunos-x64': 0.25.2 - '@esbuild/win32-arm64': 0.25.2 - '@esbuild/win32-ia32': 0.25.2 - '@esbuild/win32-x64': 0.25.2 + '@esbuild/aix-ppc64': 0.25.10 + '@esbuild/android-arm': 0.25.10 + '@esbuild/android-arm64': 0.25.10 + '@esbuild/android-x64': 0.25.10 + '@esbuild/darwin-arm64': 0.25.10 + '@esbuild/darwin-x64': 0.25.10 + '@esbuild/freebsd-arm64': 0.25.10 + '@esbuild/freebsd-x64': 0.25.10 + '@esbuild/linux-arm': 0.25.10 + '@esbuild/linux-arm64': 0.25.10 + '@esbuild/linux-ia32': 0.25.10 + '@esbuild/linux-loong64': 0.25.10 + '@esbuild/linux-mips64el': 0.25.10 + '@esbuild/linux-ppc64': 0.25.10 + '@esbuild/linux-riscv64': 0.25.10 + '@esbuild/linux-s390x': 0.25.10 + '@esbuild/linux-x64': 0.25.10 + '@esbuild/netbsd-arm64': 0.25.10 + '@esbuild/netbsd-x64': 0.25.10 + '@esbuild/openbsd-arm64': 0.25.10 + '@esbuild/openbsd-x64': 0.25.10 + '@esbuild/openharmony-arm64': 0.25.10 + '@esbuild/sunos-x64': 0.25.10 + '@esbuild/win32-arm64': 0.25.10 + '@esbuild/win32-ia32': 0.25.10 + '@esbuild/win32-x64': 0.25.10 escalade@3.2.0: {} @@ -3756,11 +3783,11 @@ snapshots: '@eslint/core': 0.12.0 '@eslint/eslintrc': 3.3.0 '@eslint/js': 9.22.0 - '@eslint/plugin-kit': 0.2.7 + '@eslint/plugin-kit': 0.2.8 '@humanfs/node': 0.16.6 '@humanwhocodes/module-importer': 1.0.1 '@humanwhocodes/retry': 0.4.2 - '@types/estree': 1.0.7 + '@types/estree': 1.0.8 '@types/json-schema': 7.0.15 ajv: 6.12.6 chalk: 4.1.2 @@ -3807,7 +3834,7 @@ snapshots: estree-walker@3.0.3: dependencies: - '@types/estree': 1.0.7 + '@types/estree': 1.0.8 esutils@2.0.3: {} @@ -3869,9 +3896,9 @@ snapshots: dependencies: pend: 1.2.0 - fdir@6.4.4(picomatch@4.0.2): + fdir@6.5.0(picomatch@4.0.3): optionalDependencies: - picomatch: 4.0.2 + picomatch: 4.0.3 figures@3.2.0: dependencies: @@ -3916,7 +3943,7 @@ snapshots: flatted@3.3.3: {} - follow-redirects@1.15.9: {} + follow-redirects@1.15.11: {} foreground-child@3.3.1: dependencies: @@ -3931,11 +3958,12 @@ snapshots: combined-stream: 1.0.8 mime-types: 2.1.35 - form-data@4.0.2: + form-data@4.0.4: dependencies: asynckit: 0.4.0 combined-stream: 1.0.8 es-set-tostringtag: 2.1.0 + hasown: 2.0.2 mime-types: 2.1.35 fraction.js@4.3.7: {} @@ -4199,7 +4227,7 @@ snapshots: cssstyle: 4.3.0 data-urls: 5.0.0 decimal.js: 10.5.0 - form-data: 4.0.2 + form-data: 4.0.4 html-encoding-sniffer: 4.0.0 http-proxy-agent: 7.0.2 https-proxy-agent: 7.0.6 @@ -4468,7 +4496,7 @@ snapshots: picomatch@2.3.1: {} - picomatch@4.0.2: {} + picomatch@4.0.3: {} pify@2.3.0: {} @@ -4617,30 +4645,31 @@ snapshots: rfdc@1.4.1: {} - rollup@4.39.0: + rollup@4.51.0: dependencies: - '@types/estree': 1.0.7 + '@types/estree': 1.0.8 optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.39.0 - '@rollup/rollup-android-arm64': 4.39.0 - '@rollup/rollup-darwin-arm64': 4.39.0 - '@rollup/rollup-darwin-x64': 4.39.0 - '@rollup/rollup-freebsd-arm64': 4.39.0 - '@rollup/rollup-freebsd-x64': 4.39.0 - '@rollup/rollup-linux-arm-gnueabihf': 4.39.0 - '@rollup/rollup-linux-arm-musleabihf': 4.39.0 - '@rollup/rollup-linux-arm64-gnu': 4.39.0 - '@rollup/rollup-linux-arm64-musl': 4.39.0 - '@rollup/rollup-linux-loongarch64-gnu': 4.39.0 - '@rollup/rollup-linux-powerpc64le-gnu': 4.39.0 - '@rollup/rollup-linux-riscv64-gnu': 4.39.0 - '@rollup/rollup-linux-riscv64-musl': 4.39.0 - '@rollup/rollup-linux-s390x-gnu': 4.39.0 - '@rollup/rollup-linux-x64-gnu': 4.39.0 - '@rollup/rollup-linux-x64-musl': 4.39.0 - '@rollup/rollup-win32-arm64-msvc': 4.39.0 - '@rollup/rollup-win32-ia32-msvc': 4.39.0 - '@rollup/rollup-win32-x64-msvc': 4.39.0 + '@rollup/rollup-android-arm-eabi': 4.51.0 + '@rollup/rollup-android-arm64': 4.51.0 + '@rollup/rollup-darwin-arm64': 4.51.0 + '@rollup/rollup-darwin-x64': 4.51.0 + '@rollup/rollup-freebsd-arm64': 4.51.0 + '@rollup/rollup-freebsd-x64': 4.51.0 + '@rollup/rollup-linux-arm-gnueabihf': 4.51.0 + '@rollup/rollup-linux-arm-musleabihf': 4.51.0 + '@rollup/rollup-linux-arm64-gnu': 4.51.0 + '@rollup/rollup-linux-arm64-musl': 4.51.0 + '@rollup/rollup-linux-loong64-gnu': 4.51.0 + '@rollup/rollup-linux-ppc64-gnu': 4.51.0 + '@rollup/rollup-linux-riscv64-gnu': 4.51.0 + '@rollup/rollup-linux-riscv64-musl': 4.51.0 + '@rollup/rollup-linux-s390x-gnu': 4.51.0 + '@rollup/rollup-linux-x64-gnu': 4.51.0 + '@rollup/rollup-linux-x64-musl': 4.51.0 + '@rollup/rollup-openharmony-arm64': 4.51.0 + '@rollup/rollup-win32-arm64-msvc': 4.51.0 + '@rollup/rollup-win32-ia32-msvc': 4.51.0 + '@rollup/rollup-win32-x64-msvc': 4.51.0 fsevents: 2.3.3 rrweb-cssom@0.7.1: {} @@ -4850,10 +4879,10 @@ snapshots: tinyexec@0.3.2: {} - tinyglobby@0.2.13: + tinyglobby@0.2.15: dependencies: - fdir: 6.4.4(picomatch@4.0.2) - picomatch: 4.0.2 + fdir: 6.5.0(picomatch@4.0.3) + picomatch: 4.0.3 tinypool@1.0.2: {} @@ -4861,7 +4890,7 @@ snapshots: tinyspy@3.0.2: {} - tmp@0.2.3: {} + tmp@0.2.5: {} to-regex-range@5.0.1: dependencies: @@ -4957,7 +4986,7 @@ snapshots: debug: 4.4.0(supports-color@8.1.1) es-module-lexer: 1.6.0 pathe: 2.0.3 - vite: 6.3.5(@types/node@22.13.10)(jiti@1.21.7)(yaml@2.7.0) + vite: 6.3.6(@types/node@22.13.10)(jiti@1.21.7)(yaml@2.7.0) transitivePeerDependencies: - '@types/node' - jiti @@ -4972,14 +5001,14 @@ snapshots: - tsx - yaml - vite@6.3.5(@types/node@22.13.10)(jiti@1.21.7)(yaml@2.7.0): + vite@6.3.6(@types/node@22.13.10)(jiti@1.21.7)(yaml@2.7.0): dependencies: - esbuild: 0.25.2 - fdir: 6.4.4(picomatch@4.0.2) - picomatch: 4.0.2 + esbuild: 0.25.10 + fdir: 6.5.0(picomatch@4.0.3) + picomatch: 4.0.3 postcss: 8.5.3 - rollup: 4.39.0 - tinyglobby: 0.2.13 + rollup: 4.51.0 + tinyglobby: 0.2.15 optionalDependencies: '@types/node': 22.13.10 fsevents: 2.3.3 @@ -4989,7 +5018,7 @@ snapshots: vitest@3.0.8(@types/node@22.13.10)(jiti@1.21.7)(jsdom@24.1.3)(yaml@2.7.0): dependencies: '@vitest/expect': 3.0.8 - '@vitest/mocker': 3.0.8(vite@6.3.5(@types/node@22.13.10)(jiti@1.21.7)(yaml@2.7.0)) + '@vitest/mocker': 3.0.8(vite@6.3.6(@types/node@22.13.10)(jiti@1.21.7)(yaml@2.7.0)) '@vitest/pretty-format': 3.0.8 '@vitest/runner': 3.0.8 '@vitest/snapshot': 3.0.8 @@ -5005,7 +5034,7 @@ snapshots: tinyexec: 0.3.2 tinypool: 1.0.2 tinyrainbow: 2.0.0 - vite: 6.3.5(@types/node@22.13.10)(jiti@1.21.7)(yaml@2.7.0) + vite: 6.3.6(@types/node@22.13.10)(jiti@1.21.7)(yaml@2.7.0) vite-node: 3.0.8(@types/node@22.13.10)(jiti@1.21.7)(yaml@2.7.0) why-is-node-running: 2.3.0 optionalDependencies: From c2bf947972032648d667064e9a201af5a3aa1015 Mon Sep 17 00:00:00 2001 From: Marios Tsigkas Date: Fri, 19 Sep 2025 21:05:04 +0300 Subject: [PATCH 88/96] Splitting files into more files --- cypress.config.ts | 2 +- cypress/e2e/home.spec.ts | 102 ++++++++++++ cypress/fixtures/catImages.json | 58 +++++++ cypress/support/e2e.ts | 1 + package.json | 1 + pnpm-lock.yaml | 23 +++ src/components/ImageGallery.tsx | 43 ++--- src/components/Modal.tsx | 103 ++++++++++-- src/components/atoms/Button.tsx | 42 +++++ src/components/atoms/Loader.tsx | 16 ++ src/components/atoms/SkeletonCard.tsx | 11 ++ src/components/molecules/ImageCard.tsx | 30 ++++ src/hooks/useFetchBreedDetail.ts | 56 +++++++ src/hooks/useFetchBreeds.ts | 36 ++++ ...eFetchedImages.ts => useFetchCatImages.ts} | 0 src/hooks/useFetchImageDetail.ts | 51 ++++++ src/index.css | 23 --- src/views/BreedDetail.tsx | 100 ++++------- src/views/Breeds.tsx | 52 +++--- src/views/Favorites.tsx | 39 +++-- src/views/Home.tsx | 52 +++--- src/views/ImageView.tsx | 157 ++++++++---------- 22 files changed, 706 insertions(+), 292 deletions(-) create mode 100644 cypress/fixtures/catImages.json create mode 100644 cypress/support/e2e.ts create mode 100644 src/components/atoms/Button.tsx create mode 100644 src/components/atoms/Loader.tsx create mode 100644 src/components/atoms/SkeletonCard.tsx create mode 100644 src/components/molecules/ImageCard.tsx create mode 100644 src/hooks/useFetchBreedDetail.ts create mode 100644 src/hooks/useFetchBreeds.ts rename src/hooks/{useFetchedImages.ts => useFetchCatImages.ts} (100%) create mode 100644 src/hooks/useFetchImageDetail.ts diff --git a/cypress.config.ts b/cypress.config.ts index 3d64405e..0dca5807 100644 --- a/cypress.config.ts +++ b/cypress.config.ts @@ -4,6 +4,6 @@ export default defineConfig({ e2e: { baseUrl: 'http://localhost:5173', specPattern: 'cypress/e2e/**/*.{js,jsx,ts,tsx}', - supportFile: false, + supportFile: 'cypress/support/e2e.ts', }, }) diff --git a/cypress/e2e/home.spec.ts b/cypress/e2e/home.spec.ts index 01df2b43..d0937e3e 100644 --- a/cypress/e2e/home.spec.ts +++ b/cypress/e2e/home.spec.ts @@ -1,3 +1,6 @@ +// eslint-disable-next-line @typescript-eslint/triple-slash-reference +/// + describe('Home Page', () => { beforeEach(() => { cy.visit('/'); @@ -8,12 +11,111 @@ describe('Home Page', () => { }); it('loads images and shows the "Load More" button', () => { + cy.intercept('GET', '**/images/search?limit=10', { fixture: 'catImages.json' }).as('getCatImages'); + cy.visit('/'); + cy.wait('@getCatImages'); cy.get('img').should('have.length.greaterThan', 0); cy.get('button').contains('Load More').should('exist'); }); + it('displays a loader while fetching images', () => { + cy.intercept('GET', '**/images/search?limit=10', (req) => { + req.reply({ + delay: 500, // Simulate network delay + fixture: 'catImages.json', + }); + }).as('getCatImagesDelayed'); + cy.visit('/'); + cy.get('.animate-spin').should('exist'); // Check for the loader spinner + cy.wait('@getCatImagesDelayed'); + cy.get('.animate-spin').should('not.exist'); + cy.get('img').should('have.length.greaterThan', 0); + }); + + it('displays an error message on API failure', () => { + cy.intercept('GET', '**/images/search?limit=10', { statusCode: 500, body: 'Internal Server Error' }).as('getCatImagesError'); + cy.visit('/'); + cy.wait('@getCatImagesError'); + cy.get('p.text-red-500').contains('Failed to fetch images').should('exist'); + cy.get('button').contains('Load More').should('be.disabled'); // Button should be disabled on error + }); + + it('displays "No images found." when API returns empty data', () => { + cy.intercept('GET', '**/images/search?limit=10', { body: [] }).as('getCatImagesEmpty'); + cy.visit('/'); + cy.wait('@getCatImagesEmpty'); + cy.get('p').contains('No images found.').should('exist'); + cy.get('button').contains('Load More').should('exist'); // Button should still be there to try again + }); + it('navigates to image detail on image click', () => { + cy.intercept('GET', '**/images/search?limit=10', { fixture: 'catImages.json' }).as('getCatImages'); + cy.visit('/'); + cy.wait('@getCatImages'); cy.get('img').first().click(); cy.url().should('include', '/image/'); + cy.get('[role="dialog"]').should('be.visible'); + }); + + it('closes the modal on Escape key press', () => { + cy.intercept('GET', '**/images/search?limit=10', { fixture: 'catImages.json' }).as('getCatImages'); + cy.visit('/'); + cy.wait('@getCatImages'); + cy.get('img').first().click(); + cy.get('[role="dialog"]').should('be.visible'); + cy.get('body').trigger('keydown', { keyCode: 27 }); // Escape key + cy.get('[role="dialog"]').should('not.exist'); + }); + + it('traps focus within the modal', () => { + cy.intercept('GET', '**/images/search?limit=10', { fixture: 'catImages.json' }).as('getCatImages'); + cy.visit('/'); + cy.wait('@getCatImages'); + cy.get('img').first().click(); + cy.get('[role="dialog"]').should('be.visible'); + + // Assuming the modal has a close button and a favorite button + cy.get('[role="dialog"]').find('button').first().as('firstFocusable'); + cy.get('[role="dialog"]').find('button').contains('Mark as Favourite').as('lastFocusable'); + + cy.get('@firstFocusable').focus(); + cy.focused().should('eq', cy.get('@firstFocusable')); + + cy.focused().tab(); + cy.focused().should('eq', cy.get('@lastFocusable')); + + cy.focused().tab({ shift: true }); + cy.focused().should('eq', cy.get('@firstFocusable')); + }); + + it('adds and removes image from favorites', () => { + cy.intercept('GET', '**/images/search?limit=10', { fixture: 'catImages.json' }).as('getCatImages'); + cy.visit('/'); + cy.wait('@getCatImages'); + cy.get('img').first().click(); + cy.get('[role="dialog"]').should('be.visible'); + + // Mark as favorite + cy.get('button').contains('Mark as Favourite').click(); + cy.get('button').contains('Remove from Favourites').should('exist'); + cy.get('body').trigger('keydown', { keyCode: 27 }); // Close modal + + // Navigate to favorites page + cy.get('nav').contains('Favorites').click(); + cy.url().should('include', '/favorites'); + cy.get('img').should('have.length', 1); // Should have 1 favorite image + + // Open the favorite image from the favorites page + cy.get('img').first().click(); + cy.get('[role="dialog"]').should('be.visible'); + cy.get('button').contains('Remove from Favourites').should('exist'); + + // Remove from favorites + cy.get('button').contains('Remove from Favourites').click(); + cy.get('button').contains('Mark as Favourite').should('exist'); // Button text changes back + cy.get('body').trigger('keydown', { keyCode: 27 }); // Close modal + + // Verify no favorites + cy.get('p').contains('No favorite cats yet.').should('exist'); }); }); diff --git a/cypress/fixtures/catImages.json b/cypress/fixtures/catImages.json new file mode 100644 index 00000000..c44b0135 --- /dev/null +++ b/cypress/fixtures/catImages.json @@ -0,0 +1,58 @@ +[ + { + "id": "image1", + "url": "https://cdn2.thecatapi.com/images/image1.jpg", + "breeds": [ + { + "id": "breed1", + "name": "Bengal", + "description": "Bengal cats are a domesticated cat breed created from hybrids of domestic cats, especially the Egyptian Mau, with the Asian leopard cat (Prionailurus bengalensis)." + } + ] + }, + { + "id": "image2", + "url": "https://cdn2.thecatapi.com/images/image2.jpg", + "breeds": [] + }, + { + "id": "image3", + "url": "https://cdn2.thecatapi.com/images/image3.jpg", + "breeds": [] + }, + { + "id": "image4", + "url": "https://cdn2.thecatapi.com/images/image4.jpg", + "breeds": [] + }, + { + "id": "image5", + "url": "https://cdn2.thecatapi.com/images/image5.jpg", + "breeds": [] + }, + { + "id": "image6", + "url": "https://cdn2.thecatapi.com/images/image6.jpg", + "breeds": [] + }, + { + "id": "image7", + "url": "https://cdn2.thecatapi.com/images/image7.jpg", + "breeds": [] + }, + { + "id": "image8", + "url": "https://cdn2.thecatapi.com/images/image8.jpg", + "breeds": [] + }, + { + "id": "image9", + "url": "https://cdn2.thecatapi.com/images/image9.jpg", + "breeds": [] + }, + { + "id": "image10", + "url": "https://cdn2.thecatapi.com/images/image10.jpg", + "breeds": [] + } +] \ No newline at end of file diff --git a/cypress/support/e2e.ts b/cypress/support/e2e.ts new file mode 100644 index 00000000..cff68f6e --- /dev/null +++ b/cypress/support/e2e.ts @@ -0,0 +1 @@ +import 'cypress-plugin-tab'; diff --git a/package.json b/package.json index 3962d8d0..c93f3a7b 100644 --- a/package.json +++ b/package.json @@ -34,6 +34,7 @@ "@vitest/coverage-v8": "^1.5.0", "autoprefixer": "^10.4.18", "cypress": "^12.12.0", + "cypress-plugin-tab": "^1.0.5", "eslint": "^9.21.0", "eslint-plugin-react-dom": "^1.31.0", "eslint-plugin-react-hooks": "^5.1.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 8dc37ff1..01144909 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -54,6 +54,9 @@ importers: cypress: specifier: ^12.12.0 version: 12.17.4 + cypress-plugin-tab: + specifier: ^1.0.5 + version: 1.0.5 eslint: specifier: ^9.21.0 version: 9.22.0(jiti@1.21.7) @@ -810,6 +813,9 @@ packages: ajv@6.12.6: resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} + ally.js@1.4.1: + resolution: {integrity: sha512-ZewdfuwP6VewtMN36QY0gmiyvBfMnmEaNwbVu2nTS6zRt069viTgkYgaDiqu6vRJ1VJCriNqV0jGMu44R8zNbA==} + ansi-colors@4.1.3: resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==} engines: {node: '>=6'} @@ -1096,6 +1102,9 @@ packages: csstype@3.1.3: resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} + cypress-plugin-tab@1.0.5: + resolution: {integrity: sha512-QtTJcifOVwwbeMP3hsOzQOKf3EqKsLyjtg9ZAGlYDntrCRXrsQhe4ZQGIthRMRLKpnP6/tTk6G0gJ2sZUfRliQ==} + cypress@12.17.4: resolution: {integrity: sha512-gAN8Pmns9MA5eCDFSDJXWKUpaL3IDd89N9TtIupjYnzLSmlpVr+ZR+vb4U/qaMp+lB6tBvAmt7504c3Z4RU5KQ==} engines: {node: ^14.0.0 || ^16.0.0 || >=18.0.0} @@ -1993,6 +2002,9 @@ packages: resolution: {integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==} engines: {node: '>=8'} + platform@1.3.3: + resolution: {integrity: sha512-VJK1SRmXBpjwsB4YOHYSturx48rLKMzHgCqDH2ZDa6ZbMS/N5huoNqyQdK5Fj/xayu3fqbXckn5SeCS1EbMDZg==} + postcss-import@15.1.0: resolution: {integrity: sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==} engines: {node: '>=14.0.0'} @@ -3291,6 +3303,11 @@ snapshots: json-schema-traverse: 0.4.1 uri-js: 4.4.1 + ally.js@1.4.1: + dependencies: + css.escape: 1.5.1 + platform: 1.3.3 + ansi-colors@4.1.3: {} ansi-escapes@4.3.2: @@ -3544,6 +3561,10 @@ snapshots: csstype@3.1.3: {} + cypress-plugin-tab@1.0.5: + dependencies: + ally.js: 1.4.1 + cypress@12.17.4: dependencies: '@cypress/request': 2.88.12 @@ -4512,6 +4533,8 @@ snapshots: dependencies: find-up: 4.1.0 + platform@1.3.3: {} + postcss-import@15.1.0(postcss@8.5.3): dependencies: postcss: 8.5.3 diff --git a/src/components/ImageGallery.tsx b/src/components/ImageGallery.tsx index ee789fe1..7d239bdc 100644 --- a/src/components/ImageGallery.tsx +++ b/src/components/ImageGallery.tsx @@ -1,37 +1,26 @@ -import { JSX, memo } from 'react' -import { CatImage } from '../api/types' -import { Link } from 'react-router-dom' +import { JSX } from 'react'; +import { CatImage } from '../api/types'; +import ImageCard from './molecules/ImageCard'; +import SkeletonCard from './atoms/SkeletonCard'; interface ImageGalleryProps { - images: CatImage[], - renderAfterImage?: (image: CatImage) => JSX.Element + images: CatImage[]; + renderAfterImage?: (image: CatImage) => JSX.Element; + isLoading?: boolean; // Added isLoading prop } -const MemoizedImageItem = memo(({ image, renderAfterImage }: { image: CatImage, renderAfterImage: ImageGalleryProps['renderAfterImage'] }) => ( -
    - void import('../views/ImageView')} - > - cat - - {renderAfterImage?.(image)} -
    -)) +const ImageGallery = ({ images, renderAfterImage, isLoading = false }: ImageGalleryProps): JSX.Element => { + const numberOfSkeletons = 10; // Display 10 skeleton cards while loading -const ImageGallery = ({ images, renderAfterImage }: ImageGalleryProps): JSX.Element => { return (
    - {images.map(image => ( - - ))} + {isLoading && images.length === 0 + ? Array.from({ length: numberOfSkeletons }).map((_, index) => ) + : images.map((image) => ( + + ))}
    - ) -} + ); +}; export default ImageGallery diff --git a/src/components/Modal.tsx b/src/components/Modal.tsx index 90bb3edf..32a34272 100644 --- a/src/components/Modal.tsx +++ b/src/components/Modal.tsx @@ -1,31 +1,106 @@ -import { JSX } from 'react' +import { JSX, useEffect, useRef, useCallback, useMemo } from 'react'; interface ModalProps { - children: React.ReactNode - onClose: () => void - isLoading?: boolean - error?: string + children: React.ReactNode; + onClose: () => void; + isLoading?: boolean; + error?: string; + title?: string; // Added for ARIA-labelledby + description?: string; // Added for ARIA-describedby } -function Modal({ children, onClose, isLoading, error }: ModalProps): JSX.Element { +function Modal({ children, onClose, isLoading, error, title, description }: ModalProps): JSX.Element { + const modalRef = useRef(null); + + const handleKeyDown = useCallback( + (event: KeyboardEvent) => { + if (event.key === 'Escape') { + onClose(); + } + }, + [onClose], + ); + + useEffect(() => { + document.addEventListener('keydown', handleKeyDown); + return () => { + document.removeEventListener('keydown', handleKeyDown); + }; + }, [handleKeyDown]); + + // Basic focus trap (can be enhanced with a library like react-focus-lock) + useEffect(() => { + const focusableElements = + modalRef.current?.querySelectorAll( + 'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])', + ) || []; + const firstElement = focusableElements[0] as HTMLElement; + const lastElement = focusableElements[focusableElements.length - 1] as HTMLElement; + + const handleTabKeyPress = (event: KeyboardEvent) => { + if (event.key === 'Tab') { + if (event.shiftKey) { + if (document.activeElement === firstElement) { + lastElement.focus(); + event.preventDefault(); + } + } else { + if (document.activeElement === lastElement) { + firstElement.focus(); + event.preventDefault(); + } + } + } + }; + + modalRef.current?.addEventListener('keydown', handleTabKeyPress); + firstElement?.focus(); // Focus on the first element when modal opens + + return () => { + modalRef.current?.removeEventListener('keydown', handleTabKeyPress); + }; + }, [isLoading, error, children]); // Re-run when modal content changes + const renderLoadingOrError = () => { - if (isLoading) return

    Loading...

    - if (error) return

    {error}

    - } + if (isLoading) return

    Loading...

    ; + if (error) return

    {error}

    ; + }; + + const modalId = useMemo(() => `modal-${Math.random().toString(36).substring(2, 9)}`, []); + const titleId = title ? `${modalId}-title` : undefined; + const descriptionId = description ? `${modalId}-description` : undefined; + return (
    { e.stopPropagation(); }} + ref={modalRef} + className='p-6 relative max-h-screen overflow-y-auto bg-white rounded-lg shadow-xl' + onClick={(e) => { + e.stopPropagation(); + }} + tabIndex={-1} // Make modal content focusable > - + + {title &&

    {title}

    } + {description &&

    {description}

    } {renderLoadingOrError() ?? children}
    - ) + ); } export default Modal diff --git a/src/components/atoms/Button.tsx b/src/components/atoms/Button.tsx new file mode 100644 index 00000000..14ed1c72 --- /dev/null +++ b/src/components/atoms/Button.tsx @@ -0,0 +1,42 @@ +import { ButtonHTMLAttributes, DetailedHTMLProps, JSX } from 'react'; + +interface ButtonProps extends DetailedHTMLProps, HTMLButtonElement> { + children: React.ReactNode; + variant?: 'primary' | 'secondary' | 'danger'; + size?: 'small' | 'medium' | 'large'; + isLoading?: boolean; +} + +const Button = ({ + children, + variant = 'primary', + size = 'medium', + isLoading = false, + className = '', + disabled, + ...rest +}: ButtonProps): JSX.Element => { + const baseStyles = 'font-bold py-2 px-4 rounded focus:outline-none focus:shadow-outline'; + const variantStyles = { + primary: 'bg-blue-500 hover:bg-blue-700 text-white', + secondary: 'bg-gray-300 hover:bg-gray-400 text-gray-800', + danger: 'bg-red-500 hover:bg-red-700 text-white', + }; + const sizeStyles = { + small: 'text-sm', + medium: 'text-base', + large: 'text-lg', + }; + + return ( + + ); +}; + +export default Button; diff --git a/src/components/atoms/Loader.tsx b/src/components/atoms/Loader.tsx new file mode 100644 index 00000000..ba4b48bb --- /dev/null +++ b/src/components/atoms/Loader.tsx @@ -0,0 +1,16 @@ +import { JSX } from 'react'; + +interface LoaderProps { + message?: string; +} + +const Loader = ({ message = 'Loading...' }: LoaderProps): JSX.Element => { + return ( +
    +
    +

    {message}

    +
    + ); +}; + +export default Loader; diff --git a/src/components/atoms/SkeletonCard.tsx b/src/components/atoms/SkeletonCard.tsx new file mode 100644 index 00000000..1e466097 --- /dev/null +++ b/src/components/atoms/SkeletonCard.tsx @@ -0,0 +1,11 @@ +import { JSX } from 'react'; + +const SkeletonCard = (): JSX.Element => { + return ( +
    +
    +
    + ); +}; + +export default SkeletonCard; diff --git a/src/components/molecules/ImageCard.tsx b/src/components/molecules/ImageCard.tsx new file mode 100644 index 00000000..77cff100 --- /dev/null +++ b/src/components/molecules/ImageCard.tsx @@ -0,0 +1,30 @@ +import { JSX, memo } from 'react'; +import { Link } from 'react-router-dom'; +import { CatImage } from '../../api/types'; + +interface ImageCardProps { + image: CatImage; + renderAfterImage?: (image: CatImage) => JSX.Element; +} + +const ImageCard = memo(({ image, renderAfterImage }: ImageCardProps): JSX.Element => { + return ( +
    + void import('../../views/ImageView')} + > + cat + + {renderAfterImage?.(image)} +
    + ); +}); + +export default ImageCard; diff --git a/src/hooks/useFetchBreedDetail.ts b/src/hooks/useFetchBreedDetail.ts new file mode 100644 index 00000000..5aa2a66c --- /dev/null +++ b/src/hooks/useFetchBreedDetail.ts @@ -0,0 +1,56 @@ +import { useState, useEffect, useCallback } from 'react'; +import { getBreedById, getBreedImages } from '../api/catApi'; +import { Breed, CatImage } from '../api/types'; +import { parseBreed } from '../api/parsers'; + +interface UseFetchBreedDetailResult { + breed: Breed | null; + breedImages: CatImage[]; + isLoading: boolean; + error: string | null; + fetchBreedDetail: (breedId: string, initialBreed?: unknown) => Promise; +} + +const useFetchBreedDetail = (): UseFetchBreedDetailResult => { + const [breed, setBreed] = useState(null); + const [breedImages, setBreedImages] = useState([]); + const [isLoading, setIsLoading] = useState(false); + const [error, setError] = useState(null); + + const fetchBreedDetail = useCallback(async (breedId: string, initialBreed?: unknown) => { + setIsLoading(true); + setError(null); + try { + let fetchedBreed: Breed | null = null; + + // Try to parse from initialBreed (e.g., from location.state) + if (initialBreed) { + try { + fetchedBreed = parseBreed(initialBreed); + } catch (e) { + console.warn('Invalid initial breed data from state, fetching from API:', e); + } + } + + // If not found in initialBreed or parsing failed, fetch from API + if (!fetchedBreed) { + fetchedBreed = await getBreedById(breedId); + } + + setBreed(fetchedBreed); + + // Fetch images for the breed + const images = await getBreedImages(breedId, 10); + setBreedImages(images); + } catch (err) { + console.error('Failed to fetch breed details or images:', err); + setError('Failed to load breed details or images.'); + } finally { + setIsLoading(false); + } + }, []); + + return { breed, breedImages, isLoading, error, fetchBreedDetail }; +}; + +export default useFetchBreedDetail; diff --git a/src/hooks/useFetchBreeds.ts b/src/hooks/useFetchBreeds.ts new file mode 100644 index 00000000..4c5e739c --- /dev/null +++ b/src/hooks/useFetchBreeds.ts @@ -0,0 +1,36 @@ +import { useState, useCallback, useEffect } from 'react'; +import { getBreeds } from '../api/catApi'; +import { Breed } from '../api/types'; +import { parseBreeds } from '../api/parsers'; + +const useFetchBreeds = () => { + const [breeds, setBreeds] = useState(() => { + const stored = localStorage.getItem('fetchedBreeds'); + return stored ? parseBreeds(JSON.parse(stored)) : []; + }); + const [isLoading, setIsLoading] = useState(false); + const [error, setError] = useState(null); + + const fetchBreeds = useCallback(async () => { + if (isLoading) return; + setIsLoading(true); + setError(null); + try { + const newBreeds = await getBreeds(); + setBreeds(newBreeds); + } catch (err) { + console.error(err); + setError('Failed to fetch breeds'); + } finally { + setIsLoading(false); + } + }, [isLoading]); + + useEffect(() => { + localStorage.setItem('fetchedBreeds', JSON.stringify(breeds)); + }, [breeds]); + + return { breeds, fetchBreeds, isLoading, error }; +}; + +export default useFetchBreeds; diff --git a/src/hooks/useFetchedImages.ts b/src/hooks/useFetchCatImages.ts similarity index 100% rename from src/hooks/useFetchedImages.ts rename to src/hooks/useFetchCatImages.ts diff --git a/src/hooks/useFetchImageDetail.ts b/src/hooks/useFetchImageDetail.ts new file mode 100644 index 00000000..c7412f64 --- /dev/null +++ b/src/hooks/useFetchImageDetail.ts @@ -0,0 +1,51 @@ +import { useState, useEffect, useCallback } from 'react'; +import { getImageById } from '../api/catApi'; +import { CatImage } from '../api/types'; +import { parseCatImages } from '../api/parsers'; + +interface UseFetchImageDetailResult { + selectedImage: CatImage | null; + isLoading: boolean; + error: string | null; + fetchImageDetail: (imageId: string, initialImage?: unknown) => Promise; +} + +const useFetchImageDetail = (): UseFetchImageDetailResult => { + const [selectedImage, setSelectedImage] = useState(null); + const [isLoading, setIsLoading] = useState(false); + const [error, setError] = useState(null); + + const fetchImageDetail = useCallback(async (imageId: string, initialImage?: unknown) => { + setIsLoading(true); + setError(null); + try { + let fetchedImage: CatImage | null = null; + + // Try to parse from initialImage (e.g., from location.state) + if (initialImage) { + try { + const [image] = parseCatImages([initialImage]); + fetchedImage = image; + } catch (e) { + console.warn('Invalid initial image data from state, fetching from API:', e); + } + } + + // If not found in initialImage or parsing failed, fetch from API + if (!fetchedImage) { + fetchedImage = await getImageById(imageId); + } + + setSelectedImage(fetchedImage); + } catch (err) { + console.error('Failed to fetch image details:', err); + setError('Failed to load image details.'); + } finally { + setIsLoading(false); + } + }, []); + + return { selectedImage, isLoading, error, fetchImageDetail }; +}; + +export default useFetchImageDetail; diff --git a/src/index.css b/src/index.css index d3deb51a..2bfcc406 100644 --- a/src/index.css +++ b/src/index.css @@ -40,26 +40,6 @@ h1 { line-height: 1.1; } -button { - border-radius: 8px; - border: 1px solid transparent; - padding: 0.6em 1.2em; - font-size: 1em; - font-weight: 500; - font-family: inherit; - background-color: #1a1a1a; - cursor: pointer; - transition: border-color 0.25s; -} - -button:hover { - border-color: #646cff; -} - -button:focus, -button:focus-visible { - outline: 4px auto -webkit-focus-ring-color; -} @media (prefers-color-scheme: light) { :root { @@ -71,7 +51,4 @@ button:focus-visible { color: #747bff; } - button { - background-color: #f9f9f9; - } } \ No newline at end of file diff --git a/src/views/BreedDetail.tsx b/src/views/BreedDetail.tsx index 804063b8..8f133b98 100644 --- a/src/views/BreedDetail.tsx +++ b/src/views/BreedDetail.tsx @@ -1,83 +1,49 @@ -import { useEffect, useState, JSX, useCallback, useMemo } from 'react' -import { useLocation, useNavigate, useParams, Location } from 'react-router-dom' -import Modal from '../components/Modal' -import { getBreedById, getBreedImages } from '../api/catApi' -import ImageGallery from '../components/ImageGallery' -import { parseBreed } from '../api/parsers' -import { Breed, CatImage } from '../api/types' +import { useEffect, JSX, useCallback, useMemo } from 'react'; +import { useLocation, useNavigate, useParams, Location } from 'react-router-dom'; +import Modal from '../components/Modal'; +import ImageGallery from '../components/ImageGallery'; +import useFetchBreedDetail from '../hooks/useFetchBreedDetail'; +import Loader from '../components/atoms/Loader'; function BreedDetail(): JSX.Element { - const location: Location = useLocation() - const navigate = useNavigate() - const { breedId } = useParams<{ breedId: string }>() - const [breedImages, setBreedImages] = useState([]) - const [isLoading, setIsLoading] = useState(true) - const [error, setError] = useState(null) - const [breed, setBreed] = useState(null); - const navigateBreeds = useCallback(() => navigate('/breeds'), [navigate]) - - const fetchBreedFromState = useCallback(() => { - const breedUnParsed: unknown = (typeof location.state === 'object' - && location.state && 'breed' in location.state) - ? location.state.breed - : undefined - if (breedUnParsed) { - try { - setBreed(parseBreed(breedUnParsed)) - } catch { - console.error('Invalid state data:') - }} - }, [location.state]) - - const fetchBreedFromApi = useCallback(async (id: string) => { - try { - const breed = await getBreedById(id) - setBreed(breed) - } catch (err) { - console.error('Failed to fetch image:', err) - setError('Failed to load image') - } - }, []) + const location: Location = useLocation(); + const navigate = useNavigate(); + const { breedId } = useParams<{ breedId: string }>(); + const { breed, breedImages, isLoading, error, fetchBreedDetail } = useFetchBreedDetail(); + const navigateBreeds = useCallback(() => navigate('/breeds'), [navigate]); useEffect(() => { - if (!breedId) return - setIsLoading(true) - fetchBreedFromState() - if (breedId) { - void fetchBreedImages(breedId) - void fetchBreedFromApi(breedId) - } - setIsLoading(false) - }, [breedId, fetchBreedFromApi, fetchBreedFromState]) - - const fetchBreedImages = async (breedId: string) => { - try { - const data = await getBreedImages(breedId, 10) - setBreedImages(data) - } catch (error) { - console.error(error) + if (!breedId) { + navigateBreeds(); + return; } - } + const initialBreed = + typeof location.state === 'object' && location.state && 'breed' in location.state + ? location.state.breed + : undefined; + void fetchBreedDetail(breedId, initialBreed); + }, [breedId, fetchBreedDetail, location.state, navigateBreeds]); const closeModal = () => { - void navigateBreeds() - } + void navigateBreeds(); + }; - const errorMessage = useMemo(() => - (error ?? !breed) ? 'Error loading breed' : undefined, - [error, breed] - ) + const errorMessage = useMemo(() => (error ?? !breed) ? 'Error loading breed' : undefined, [error, breed]); return ( - {breed && <> -

    {breed.name}

    -

    {breed.description}

    - - } + {isLoading && !breed && } + {error && !breed &&

    {error}

    } + {breed && ( + <> +

    {breed.name}

    +

    {breed.description}

    + + + )}
    - ) + ); } export default BreedDetail diff --git a/src/views/Breeds.tsx b/src/views/Breeds.tsx index 84e9eadb..abc43b88 100644 --- a/src/views/Breeds.tsx +++ b/src/views/Breeds.tsx @@ -1,53 +1,41 @@ -import { useState, useEffect, useMemo, JSX, memo } from 'react' -import { Link } from 'react-router-dom' -import { getBreeds } from '../api/catApi' +import { useMemo, JSX, memo, useEffect } from 'react'; +import { Link } from 'react-router-dom'; +import { Breed } from '../api/types'; +import useFetchBreeds from '../hooks/useFetchBreeds'; +import Loader from '../components/atoms/Loader'; -interface Breed { - id: string - name: string - description: string -} - -const BreedListItem = memo(({ breed }: { breed: Breed }) => { +const BreedListItem = memo(({ breed }: { breed: Breed }): JSX.Element => { return (
  • void import('./BreedDetail')}> {breed.name}
  • - ) -}) + ); +}); function Breeds(): JSX.Element { - const [breeds, setBreeds] = useState([]) + const { breeds, fetchBreeds, isLoading, error } = useFetchBreeds(); useEffect(() => { - void fetchBreeds() - }, []) - - const fetchBreeds = async () => { - try { - const data = await getBreeds() - setBreeds(data) - } catch (error) { - console.error(error) - } - } + if (isLoading || breeds.length > 0) return; + void fetchBreeds(); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); const listItems = useMemo(() => { - return breeds.map(breed => ( - - )) - }, [breeds]) + return breeds.map((breed) => ); + }, [breeds]); return (

    Cat Breeds

    -
      - {listItems} -
    + {isLoading && } + {error &&

    {error}

    } + {!isLoading && !error && breeds.length > 0 &&
      {listItems}
    } + {!isLoading && !error && breeds.length === 0 &&

    No breeds found.

    }
    - ) + ); } export default Breeds diff --git a/src/views/Favorites.tsx b/src/views/Favorites.tsx index 6f1a8913..19b12ecf 100644 --- a/src/views/Favorites.tsx +++ b/src/views/Favorites.tsx @@ -1,27 +1,38 @@ -import { JSX } from 'react' -import { useFavorites } from '../hooks/useFavorites' +import { JSX, useCallback } from 'react'; +import { useFavorites } from '../hooks/useFavorites'; import ImageGallery from '../components/ImageGallery'; import { CatImage } from '../api/types'; +import Button from '../components/atoms/Button'; function Favorites(): JSX.Element { - const { favorites, removeFavorite } = useFavorites() - const removeFavoriteButton = (fav: CatImage) => { - return - } - + const { favorites, removeFavorite } = useFavorites(); + const renderRemoveFavoriteButton = useCallback((fav: CatImage): JSX.Element => { + return ( + + ); + }, [removeFavorite]); return (

    Favourite Cats

    - + {favorites.length > 0 ? ( + + ) : ( +

    No favorite cats yet.

    + )}
    - ) + ); } export default Favorites diff --git a/src/views/Home.tsx b/src/views/Home.tsx index ee8541f0..b08e725a 100644 --- a/src/views/Home.tsx +++ b/src/views/Home.tsx @@ -1,34 +1,42 @@ -import { JSX, useEffect } from 'react' -import useFetchedImages from '../hooks/useFetchedImages' -import ImageGallery from '../components/ImageGallery' +import { JSX, useEffect } from 'react'; +import useFetchCatImages from '../hooks/useFetchCatImages'; +import ImageGallery from '../components/ImageGallery'; +import Button from '../components/atoms/Button'; +import Loader from '../components/atoms/Loader'; function Home(): JSX.Element { - const { images, fetchImages, isLoading, error } = useFetchedImages() + const { images, fetchImages, isLoading, error } = useFetchCatImages(); useEffect(() => { - if (isLoading || images.length > 0) return - void fetchImages() - // we only want to fetch new images when the component mounts - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []) + if (isLoading || images.length > 0) return; + void fetchImages(); + // we only want to fetch new images when the component mounts + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); return (

    Random Cats

    - {images.length &&
    - - -
    } - {isLoading &&

    Loading...

    } - {error &&

    {error}

    } + {images.length > 0 || isLoading ? ( +
    + +
    + +
    +
    + ) : ( +

    No images found.

    + )} + {error &&

    {error}

    }
    - ) + ); } export default Home diff --git a/src/views/ImageView.tsx b/src/views/ImageView.tsx index 3dc472c4..407b1937 100644 --- a/src/views/ImageView.tsx +++ b/src/views/ImageView.tsx @@ -1,110 +1,83 @@ -import { useState, useEffect, JSX, useMemo, useCallback } from 'react' -import { useNavigate, useParams, useLocation, Location } from 'react-router-dom' -import Modal from '../components/Modal' -import { CatImage } from '../api/types' -import { useFavorites } from '../hooks/useFavorites' -import { parseCatImages } from '../api/parsers' -import { getImageById } from '../api/catApi' +import { useEffect, JSX, useMemo, useCallback } from 'react'; +import { useNavigate, useParams, useLocation, Location } from 'react-router-dom'; +import Modal from '../components/Modal'; +import { CatImage } from '../api/types'; +import { useFavorites } from '../hooks/useFavorites'; +import useFetchImageDetail from '../hooks/useFetchImageDetail'; +import Button from '../components/atoms/Button'; +import Loader from '../components/atoms/Loader'; function ImageView(): JSX.Element { - const [selectedImage, setSelectedImage] = useState(null) - const [isLoading, setIsLoading] = useState(true) - const [error, setError] = useState(null) - const navigate = useNavigate() - const location: Location = useLocation() - const { imageId } = useParams() - const { addFavorite, removeFavorite, favorites } = useFavorites() + const navigate = useNavigate(); + const location: Location = useLocation(); + const { imageId } = useParams<{ imageId: string }>(); + const { addFavorite, removeFavorite, favorites } = useFavorites(); + const { selectedImage, isLoading, error, fetchImageDetail } = useFetchImageDetail(); - const fetchImageFromState = useCallback(() => { - const imageFromState = typeof location.state === 'object' - && location.state - && 'image' in location.state - ? location.state.image - : undefined - - if (imageFromState) { - try { - const [image] = parseCatImages([imageFromState]) - setSelectedImage(image) - return - } catch (error) { - console.error('Invalid state data:', error) - } - } - },[location.state]) - - const fetchImageFromApi = useCallback(async (imageId: string) => { - try { - const image = await getImageById(imageId) - setSelectedImage(image) - } catch (err) { - console.error('Failed to fetch image:', err) - setError('Failed to load image') - void navigate('/') - } - }, [navigate]) - - const fetchImage = useCallback(async () => { - if (!imageId) return - setIsLoading(true) - fetchImageFromState() - if (!selectedImage) { - await fetchImageFromApi(imageId) - } - setIsLoading(false) - // this sets selectedImage, so it cannot rely on this - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [fetchImageFromApi, fetchImageFromState, imageId]) + const navigateHome = useCallback(() => navigate('/'), [navigate]); useEffect(() => { - void fetchImage() - }, [imageId, fetchImage]) + if (!imageId) { + navigateHome(); + return; + } + const initialImage = + typeof location.state === 'object' && location.state && 'image' in location.state + ? location.state.image + : undefined; + void fetchImageDetail(imageId, initialImage); + }, [imageId, fetchImageDetail, location.state, navigateHome]); const closeModal = () => { - void navigate(-1) - } + void navigate(-1); + }; - const isFavorite = useMemo(() => - selectedImage ? favorites.some(fav => fav.id === selectedImage.id) : false, - [selectedImage, favorites] - ) + const isFavorite = useMemo( + () => (selectedImage ? favorites.some((fav) => fav.id === selectedImage.id) : false), + [selectedImage, favorites], + ); - const errorMessage = useMemo(() => - (error ?? !selectedImage) ? 'Error loading image' : undefined, - [error, selectedImage] - ) - const clickFavoriteButton = (selectedImage: CatImage) => { + const errorMessage = useMemo(() => (error ?? !selectedImage) ? 'Error loading image' : undefined, [ + error, + selectedImage, + ]); + + const clickFavoriteButton = (image: CatImage) => { if (isFavorite) { - removeFavorite(selectedImage) } - else{ - addFavorite(selectedImage) + removeFavorite(image); + } else { + addFavorite(image); } - } - + }; return ( - - {selectedImage && <> - cat - {selectedImage.breeds && selectedImage.breeds.length > 0 ? ( - <> -

    {selectedImage.breeds[0].name}

    -

    {selectedImage.breeds[0].description}

    - - ) : ( -

    No breed info available

    + + {isLoading && !selectedImage && } + {error && !selectedImage &&

    {error}

    } + {selectedImage && ( +
    + cat + {selectedImage.breeds && selectedImage.breeds.length > 0 ? ( + <> +

    {selectedImage.breeds[0].name}

    +

    {selectedImage.breeds[0].description}

    + + ) : ( +

    No breed info available

    + )} + +
    )} - - }
    - ) + ); } export default ImageView From c88320aa8169614676a84ea7803984eeb4f29e38 Mon Sep 17 00:00:00 2001 From: Marios Tsigkas Date: Sat, 20 Sep 2025 14:15:25 +0300 Subject: [PATCH 89/96] Fix cy tests --- cypress/e2e/home.spec.ts | 40 +++++++++++---------------------- cypress/support/e2e.ts | 1 + package.json | 1 + pnpm-lock.yaml | 12 ++++++++++ src/components/ImageGallery.tsx | 2 +- src/views/Favorites.tsx | 2 +- src/views/Home.tsx | 31 ++++++++++++------------- tsconfig.cypress.json | 3 ++- 8 files changed, 45 insertions(+), 47 deletions(-) diff --git a/cypress/e2e/home.spec.ts b/cypress/e2e/home.spec.ts index d0937e3e..b99eef0d 100644 --- a/cypress/e2e/home.spec.ts +++ b/cypress/e2e/home.spec.ts @@ -3,6 +3,7 @@ describe('Home Page', () => { beforeEach(() => { + cy.clearLocalStorage('favorites'); // Clear favorites before each test cy.visit('/'); }); @@ -18,7 +19,7 @@ describe('Home Page', () => { cy.get('button').contains('Load More').should('exist'); }); - it('displays a loader while fetching images', () => { + it('displays skeleton loaders while fetching images', () => { cy.intercept('GET', '**/images/search?limit=10', (req) => { req.reply({ delay: 500, // Simulate network delay @@ -26,9 +27,9 @@ describe('Home Page', () => { }); }).as('getCatImagesDelayed'); cy.visit('/'); - cy.get('.animate-spin').should('exist'); // Check for the loader spinner + cy.get('.animate-pulse').should('have.length', 10); // Check for 10 skeleton cards cy.wait('@getCatImagesDelayed'); - cy.get('.animate-spin').should('not.exist'); + cy.get('.animate-pulse').should('not.exist'); cy.get('img').should('have.length.greaterThan', 0); }); @@ -37,7 +38,7 @@ describe('Home Page', () => { cy.visit('/'); cy.wait('@getCatImagesError'); cy.get('p.text-red-500').contains('Failed to fetch images').should('exist'); - cy.get('button').contains('Load More').should('be.disabled'); // Button should be disabled on error + cy.get('button').contains('Load More').should('not.be.disabled'); // Button should be enabled to allow retry }); it('displays "No images found." when API returns empty data', () => { @@ -63,31 +64,16 @@ describe('Home Page', () => { cy.wait('@getCatImages'); cy.get('img').first().click(); cy.get('[role="dialog"]').should('be.visible'); - cy.get('body').trigger('keydown', { keyCode: 27 }); // Escape key + cy.realPress('{esc}'); // Use cypress-real-events for Escape key cy.get('[role="dialog"]').should('not.exist'); }); - it('traps focus within the modal', () => { - cy.intercept('GET', '**/images/search?limit=10', { fixture: 'catImages.json' }).as('getCatImages'); - cy.visit('/'); - cy.wait('@getCatImages'); - cy.get('img').first().click(); - cy.get('[role="dialog"]').should('be.visible'); - - // Assuming the modal has a close button and a favorite button - cy.get('[role="dialog"]').find('button').first().as('firstFocusable'); - cy.get('[role="dialog"]').find('button').contains('Mark as Favourite').as('lastFocusable'); - - cy.get('@firstFocusable').focus(); - cy.focused().should('eq', cy.get('@firstFocusable')); - - cy.focused().tab(); - cy.focused().should('eq', cy.get('@lastFocusable')); - - cy.focused().tab({ shift: true }); - cy.focused().should('eq', cy.get('@firstFocusable')); + it('displays "No favorite cats yet." when favorites are empty', () => { + cy.visit('/favorites'); + cy.get('[data-cy="no-favorites-message"]').contains('No favorite cats yet.').should('exist'); }); + it('adds and removes image from favorites', () => { cy.intercept('GET', '**/images/search?limit=10', { fixture: 'catImages.json' }).as('getCatImages'); cy.visit('/'); @@ -98,7 +84,7 @@ describe('Home Page', () => { // Mark as favorite cy.get('button').contains('Mark as Favourite').click(); cy.get('button').contains('Remove from Favourites').should('exist'); - cy.get('body').trigger('keydown', { keyCode: 27 }); // Close modal + cy.realPress('{esc}'); // Close modal // Navigate to favorites page cy.get('nav').contains('Favorites').click(); @@ -113,9 +99,9 @@ describe('Home Page', () => { // Remove from favorites cy.get('button').contains('Remove from Favourites').click(); cy.get('button').contains('Mark as Favourite').should('exist'); // Button text changes back - cy.get('body').trigger('keydown', { keyCode: 27 }); // Close modal + cy.get('[data-cy="close-modal-button"]').click(); // Close modal by clicking the close button // Verify no favorites - cy.get('p').contains('No favorite cats yet.').should('exist'); + cy.get('[data-cy="no-favorites-message"]').contains('No favorite cats yet.').should('exist'); }); }); diff --git a/cypress/support/e2e.ts b/cypress/support/e2e.ts index cff68f6e..5816bb8e 100644 --- a/cypress/support/e2e.ts +++ b/cypress/support/e2e.ts @@ -1 +1,2 @@ import 'cypress-plugin-tab'; +import 'cypress-real-events'; diff --git a/package.json b/package.json index c93f3a7b..af258554 100644 --- a/package.json +++ b/package.json @@ -35,6 +35,7 @@ "autoprefixer": "^10.4.18", "cypress": "^12.12.0", "cypress-plugin-tab": "^1.0.5", + "cypress-real-events": "^1.15.0", "eslint": "^9.21.0", "eslint-plugin-react-dom": "^1.31.0", "eslint-plugin-react-hooks": "^5.1.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 01144909..13c9d736 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -57,6 +57,9 @@ importers: cypress-plugin-tab: specifier: ^1.0.5 version: 1.0.5 + cypress-real-events: + specifier: ^1.15.0 + version: 1.15.0(cypress@12.17.4) eslint: specifier: ^9.21.0 version: 9.22.0(jiti@1.21.7) @@ -1105,6 +1108,11 @@ packages: cypress-plugin-tab@1.0.5: resolution: {integrity: sha512-QtTJcifOVwwbeMP3hsOzQOKf3EqKsLyjtg9ZAGlYDntrCRXrsQhe4ZQGIthRMRLKpnP6/tTk6G0gJ2sZUfRliQ==} + cypress-real-events@1.15.0: + resolution: {integrity: sha512-in98xxTnnM9Z7lZBvvVozm99PBT2eEOjXRG5LKWyYvQnj9mGWXMiPNpfw7e7WiraBFh7XlXIxnE9Cu5o+52kQQ==} + peerDependencies: + cypress: ^4.x || ^5.x || ^6.x || ^7.x || ^8.x || ^9.x || ^10.x || ^11.x || ^12.x || ^13.x || ^14.x || ^15.x + cypress@12.17.4: resolution: {integrity: sha512-gAN8Pmns9MA5eCDFSDJXWKUpaL3IDd89N9TtIupjYnzLSmlpVr+ZR+vb4U/qaMp+lB6tBvAmt7504c3Z4RU5KQ==} engines: {node: ^14.0.0 || ^16.0.0 || >=18.0.0} @@ -3565,6 +3573,10 @@ snapshots: dependencies: ally.js: 1.4.1 + cypress-real-events@1.15.0(cypress@12.17.4): + dependencies: + cypress: 12.17.4 + cypress@12.17.4: dependencies: '@cypress/request': 2.88.12 diff --git a/src/components/ImageGallery.tsx b/src/components/ImageGallery.tsx index 7d239bdc..165c2c71 100644 --- a/src/components/ImageGallery.tsx +++ b/src/components/ImageGallery.tsx @@ -13,7 +13,7 @@ const ImageGallery = ({ images, renderAfterImage, isLoading = false }: ImageGall const numberOfSkeletons = 10; // Display 10 skeleton cards while loading return ( -
    +
    {isLoading && images.length === 0 ? Array.from({ length: numberOfSkeletons }).map((_, index) => ) : images.map((image) => ( diff --git a/src/views/Favorites.tsx b/src/views/Favorites.tsx index 19b12ecf..2c72540a 100644 --- a/src/views/Favorites.tsx +++ b/src/views/Favorites.tsx @@ -29,7 +29,7 @@ function Favorites(): JSX.Element { {favorites.length > 0 ? ( ) : ( -

    No favorite cats yet.

    +

    No favorite cats yet.

    )}
    ); diff --git a/src/views/Home.tsx b/src/views/Home.tsx index b08e725a..a170ef4a 100644 --- a/src/views/Home.tsx +++ b/src/views/Home.tsx @@ -2,7 +2,6 @@ import { JSX, useEffect } from 'react'; import useFetchCatImages from '../hooks/useFetchCatImages'; import ImageGallery from '../components/ImageGallery'; import Button from '../components/atoms/Button'; -import Loader from '../components/atoms/Loader'; function Home(): JSX.Element { const { images, fetchImages, isLoading, error } = useFetchCatImages(); @@ -17,24 +16,22 @@ function Home(): JSX.Element { return (

    Random Cats

    - {images.length > 0 || isLoading ? ( -
    - -
    - -
    -
    - ) : ( + {error &&

    {error}

    } + {images.length === 0 && !isLoading && !error && (

    No images found.

    )} - {error &&

    {error}

    } + +
    + +
    ); } diff --git a/tsconfig.cypress.json b/tsconfig.cypress.json index 872be564..b8f04923 100644 --- a/tsconfig.cypress.json +++ b/tsconfig.cypress.json @@ -2,7 +2,8 @@ "extends": "./tsconfig.json", "compilerOptions": { "types": [ - "cypress" + "cypress", + "cypress-plugin-tab" ], "strict": true, "strictNullChecks": true, From ebda36e0e8a1036c5df3e52df9bbc5f06ebcb5a3 Mon Sep 17 00:00:00 2001 From: Marios Tsigkas Date: Sat, 20 Sep 2025 15:44:15 +0300 Subject: [PATCH 90/96] Refactor components to improve loading states and error handling; replace Loader with Skeleton and ErrorMessage components. --- src/components/ImageGallery.tsx | 10 +++++----- src/components/Modal.tsx | 13 +++---------- src/components/atoms/Button.tsx | 4 ++-- src/components/atoms/ErrorMessage.tsx | 24 ++++++++++++++++++++++++ src/components/atoms/Loader.tsx | 16 ---------------- src/components/atoms/Skeleton.tsx | 20 ++++++++++++++++++++ src/components/atoms/SkeletonCard.tsx | 11 ----------- src/components/molecules/ImageCard.tsx | 13 +++++++++---- src/views/BreedDetail.tsx | 25 +++++++++++++++++++------ src/views/Breeds.tsx | 13 +++++++++---- src/views/Home.tsx | 7 ++++--- src/views/ImageView.tsx | 21 +++++++++++++++------ 12 files changed, 110 insertions(+), 67 deletions(-) create mode 100644 src/components/atoms/ErrorMessage.tsx delete mode 100644 src/components/atoms/Loader.tsx create mode 100644 src/components/atoms/Skeleton.tsx delete mode 100644 src/components/atoms/SkeletonCard.tsx diff --git a/src/components/ImageGallery.tsx b/src/components/ImageGallery.tsx index 165c2c71..871e2c36 100644 --- a/src/components/ImageGallery.tsx +++ b/src/components/ImageGallery.tsx @@ -1,7 +1,7 @@ -import { JSX } from 'react'; +import React, { JSX } from 'react'; import { CatImage } from '../api/types'; import ImageCard from './molecules/ImageCard'; -import SkeletonCard from './atoms/SkeletonCard'; +import Skeleton from './atoms/Skeleton'; interface ImageGalleryProps { images: CatImage[]; @@ -9,18 +9,18 @@ interface ImageGalleryProps { isLoading?: boolean; // Added isLoading prop } -const ImageGallery = ({ images, renderAfterImage, isLoading = false }: ImageGalleryProps): JSX.Element => { +const ImageGallery = React.memo(({ images, renderAfterImage, isLoading = false }: ImageGalleryProps): JSX.Element => { const numberOfSkeletons = 10; // Display 10 skeleton cards while loading return (
    {isLoading && images.length === 0 - ? Array.from({ length: numberOfSkeletons }).map((_, index) => ) + ? Array.from({ length: numberOfSkeletons }).map((_, index) => ) : images.map((image) => ( ))}
    ); -}; +}); export default ImageGallery diff --git a/src/components/Modal.tsx b/src/components/Modal.tsx index 32a34272..be45fc05 100644 --- a/src/components/Modal.tsx +++ b/src/components/Modal.tsx @@ -3,13 +3,11 @@ import { JSX, useEffect, useRef, useCallback, useMemo } from 'react'; interface ModalProps { children: React.ReactNode; onClose: () => void; - isLoading?: boolean; - error?: string; title?: string; // Added for ARIA-labelledby description?: string; // Added for ARIA-describedby } -function Modal({ children, onClose, isLoading, error, title, description }: ModalProps): JSX.Element { +function Modal({ children, onClose, title, description }: ModalProps): JSX.Element { const modalRef = useRef(null); const handleKeyDown = useCallback( @@ -59,12 +57,7 @@ function Modal({ children, onClose, isLoading, error, title, description }: Moda return () => { modalRef.current?.removeEventListener('keydown', handleTabKeyPress); }; - }, [isLoading, error, children]); // Re-run when modal content changes - - const renderLoadingOrError = () => { - if (isLoading) return

    Loading...

    ; - if (error) return

    {error}

    ; - }; + }, [children]); // Re-run when modal content changes const modalId = useMemo(() => `modal-${Math.random().toString(36).substring(2, 9)}`, []); const titleId = title ? `${modalId}-title` : undefined; @@ -97,7 +90,7 @@ function Modal({ children, onClose, isLoading, error, title, description }: Moda {title &&

    {title}

    } {description &&

    {description}

    } - {renderLoadingOrError() ?? children} +
    {children}
    ); diff --git a/src/components/atoms/Button.tsx b/src/components/atoms/Button.tsx index 14ed1c72..646e401d 100644 --- a/src/components/atoms/Button.tsx +++ b/src/components/atoms/Button.tsx @@ -1,4 +1,4 @@ -import { ButtonHTMLAttributes, DetailedHTMLProps, JSX } from 'react'; +import React, { ButtonHTMLAttributes, DetailedHTMLProps, JSX } from 'react'; interface ButtonProps extends DetailedHTMLProps, HTMLButtonElement> { children: React.ReactNode; @@ -30,7 +30,7 @@ const Button = ({ return ( + )} +
    + ); +}); + +export default ErrorMessage; diff --git a/src/components/atoms/Loader.tsx b/src/components/atoms/Loader.tsx deleted file mode 100644 index ba4b48bb..00000000 --- a/src/components/atoms/Loader.tsx +++ /dev/null @@ -1,16 +0,0 @@ -import { JSX } from 'react'; - -interface LoaderProps { - message?: string; -} - -const Loader = ({ message = 'Loading...' }: LoaderProps): JSX.Element => { - return ( -
    -
    -

    {message}

    -
    - ); -}; - -export default Loader; diff --git a/src/components/atoms/Skeleton.tsx b/src/components/atoms/Skeleton.tsx new file mode 100644 index 00000000..6d83bd0d --- /dev/null +++ b/src/components/atoms/Skeleton.tsx @@ -0,0 +1,20 @@ +import React, { JSX } from 'react'; + +interface SkeletonProps { + width?: string; + height?: string; + className?: string; +} + +const Skeleton = React.memo(({ width = '100%', height = '100%', className = '' }: SkeletonProps): JSX.Element => { + return ( +
    + ); +}); + +export default Skeleton; diff --git a/src/components/atoms/SkeletonCard.tsx b/src/components/atoms/SkeletonCard.tsx deleted file mode 100644 index 1e466097..00000000 --- a/src/components/atoms/SkeletonCard.tsx +++ /dev/null @@ -1,11 +0,0 @@ -import { JSX } from 'react'; - -const SkeletonCard = (): JSX.Element => { - return ( -
    -
    -
    - ); -}; - -export default SkeletonCard; diff --git a/src/components/molecules/ImageCard.tsx b/src/components/molecules/ImageCard.tsx index 77cff100..93ed178d 100644 --- a/src/components/molecules/ImageCard.tsx +++ b/src/components/molecules/ImageCard.tsx @@ -1,6 +1,7 @@ -import { JSX, memo } from 'react'; +import { JSX, memo, useState } from 'react'; import { Link } from 'react-router-dom'; import { CatImage } from '../../api/types'; +import Skeleton from '../atoms/Skeleton'; interface ImageCardProps { image: CatImage; @@ -8,18 +9,22 @@ interface ImageCardProps { } const ImageCard = memo(({ image, renderAfterImage }: ImageCardProps): JSX.Element => { + const [isLoadingImage, setIsLoadingImage] = useState(true); + return ( -
    +
    void import('../../views/ImageView')} > + {isLoadingImage && } cat setIsLoadingImage(false)} /> {renderAfterImage?.(image)} diff --git a/src/views/BreedDetail.tsx b/src/views/BreedDetail.tsx index 8f133b98..3dd23f35 100644 --- a/src/views/BreedDetail.tsx +++ b/src/views/BreedDetail.tsx @@ -1,9 +1,10 @@ -import { useEffect, JSX, useCallback, useMemo } from 'react'; +import React, { useEffect, JSX, useCallback, useMemo } from 'react'; import { useLocation, useNavigate, useParams, Location } from 'react-router-dom'; import Modal from '../components/Modal'; import ImageGallery from '../components/ImageGallery'; import useFetchBreedDetail from '../hooks/useFetchBreedDetail'; -import Loader from '../components/atoms/Loader'; +import Skeleton from '../components/atoms/Skeleton'; +import ErrorMessage from '../components/atoms/ErrorMessage'; function BreedDetail(): JSX.Element { const location: Location = useLocation(); @@ -29,12 +30,23 @@ function BreedDetail(): JSX.Element { void navigateBreeds(); }; - const errorMessage = useMemo(() => (error ?? !breed) ? 'Error loading breed' : undefined, [error, breed]); + const errorMessage = useMemo(() => (error ?? !breed) ? 'Failed to load breed details.' : undefined, [error, breed]); return ( - - {isLoading && !breed && } - {error && !breed &&

    {error}

    } + + {isLoading && !breed && ( +
    + + + +
    + {Array.from({ length: 4 }).map((_, i) => ( + + ))} +
    +
    + )} + {error && !breed && void fetchBreedDetail(breedId!)} />} {breed && ( <>

    {breed.name}

    @@ -42,6 +54,7 @@ function BreedDetail(): JSX.Element { )} + {!isLoading && !error && !breed &&

    No breed details found.

    }
    ); } diff --git a/src/views/Breeds.tsx b/src/views/Breeds.tsx index abc43b88..801f28e7 100644 --- a/src/views/Breeds.tsx +++ b/src/views/Breeds.tsx @@ -1,8 +1,9 @@ -import { useMemo, JSX, memo, useEffect } from 'react'; +import React, { useMemo, JSX, memo, useEffect } from 'react'; import { Link } from 'react-router-dom'; import { Breed } from '../api/types'; import useFetchBreeds from '../hooks/useFetchBreeds'; -import Loader from '../components/atoms/Loader'; +import Skeleton from '../components/atoms/Skeleton'; +import ErrorMessage from '../components/atoms/ErrorMessage'; const BreedListItem = memo(({ breed }: { breed: Breed }): JSX.Element => { return ( @@ -30,8 +31,12 @@ function Breeds(): JSX.Element { return (

    Cat Breeds

    - {isLoading && } - {error &&

    {error}

    } + {isLoading && ( + Array.from({ length: 20 }).map((_, i) => ( + + )) + )} + {error && void fetchBreeds()} />} {!isLoading && !error && breeds.length > 0 &&
      {listItems}
    } {!isLoading && !error && breeds.length === 0 &&

    No breeds found.

    }
    diff --git a/src/views/Home.tsx b/src/views/Home.tsx index a170ef4a..bbe655b7 100644 --- a/src/views/Home.tsx +++ b/src/views/Home.tsx @@ -1,7 +1,8 @@ -import { JSX, useEffect } from 'react'; +import React, { JSX, useEffect } from 'react'; import useFetchCatImages from '../hooks/useFetchCatImages'; import ImageGallery from '../components/ImageGallery'; import Button from '../components/atoms/Button'; +import ErrorMessage from '../components/atoms/ErrorMessage'; function Home(): JSX.Element { const { images, fetchImages, isLoading, error } = useFetchCatImages(); @@ -16,8 +17,8 @@ function Home(): JSX.Element { return (

    Random Cats

    - {error &&

    {error}

    } - {images.length === 0 && !isLoading && !error && ( + {error && void fetchImages()} />} + {!isLoading && !error && images.length === 0 && (

    No images found.

    )} diff --git a/src/views/ImageView.tsx b/src/views/ImageView.tsx index 407b1937..d6077cd4 100644 --- a/src/views/ImageView.tsx +++ b/src/views/ImageView.tsx @@ -1,11 +1,12 @@ -import { useEffect, JSX, useMemo, useCallback } from 'react'; +import React, { useEffect, JSX, useMemo, useCallback } from 'react'; import { useNavigate, useParams, useLocation, Location } from 'react-router-dom'; import Modal from '../components/Modal'; import { CatImage } from '../api/types'; import { useFavorites } from '../hooks/useFavorites'; import useFetchImageDetail from '../hooks/useFetchImageDetail'; import Button from '../components/atoms/Button'; -import Loader from '../components/atoms/Loader'; +import Skeleton from '../components/atoms/Skeleton'; +import ErrorMessage from '../components/atoms/ErrorMessage'; function ImageView(): JSX.Element { const navigate = useNavigate(); @@ -37,7 +38,7 @@ function ImageView(): JSX.Element { [selectedImage, favorites], ); - const errorMessage = useMemo(() => (error ?? !selectedImage) ? 'Error loading image' : undefined, [ + const errorMessage = useMemo(() => (error ?? !selectedImage) ? 'Failed to load image details.' : undefined, [ error, selectedImage, ]); @@ -51,9 +52,16 @@ function ImageView(): JSX.Element { }; return ( - - {isLoading && !selectedImage && } - {error && !selectedImage &&

    {error}

    } + + {isLoading && !selectedImage && ( +
    + + + + +
    + )} + {error && !selectedImage && void fetchImageDetail(imageId!)} />} {selectedImage && (
    cat @@ -76,6 +84,7 @@ function ImageView(): JSX.Element {
    )} + {!isLoading && !error && !selectedImage &&

    No image details found.

    }
    ); } From f6faffec72f3933446d92fd7da722dcd8d1b09e9 Mon Sep 17 00:00:00 2001 From: Marios Tsigkas Date: Mon, 22 Sep 2025 13:07:15 +0300 Subject: [PATCH 91/96] Enhance loading states in ImageGallery and Modal components update snapshots for Home test --- src/components/ImageGallery.tsx | 4 +- src/components/Modal.tsx | 8 +- src/hooks/useFetchBreedDetail.ts | 5 +- src/hooks/useFetchImageDetail.ts | 2 - .../__snapshots__/Home.test.tsx.snap | 79 ++++++++++++++++++- 5 files changed, 82 insertions(+), 16 deletions(-) diff --git a/src/components/ImageGallery.tsx b/src/components/ImageGallery.tsx index 871e2c36..a6582461 100644 --- a/src/components/ImageGallery.tsx +++ b/src/components/ImageGallery.tsx @@ -6,11 +6,11 @@ import Skeleton from './atoms/Skeleton'; interface ImageGalleryProps { images: CatImage[]; renderAfterImage?: (image: CatImage) => JSX.Element; - isLoading?: boolean; // Added isLoading prop + isLoading?: boolean; } const ImageGallery = React.memo(({ images, renderAfterImage, isLoading = false }: ImageGalleryProps): JSX.Element => { - const numberOfSkeletons = 10; // Display 10 skeleton cards while loading + const numberOfSkeletons = 10; return (
    diff --git a/src/components/Modal.tsx b/src/components/Modal.tsx index be45fc05..699fb1b8 100644 --- a/src/components/Modal.tsx +++ b/src/components/Modal.tsx @@ -3,8 +3,8 @@ import { JSX, useEffect, useRef, useCallback, useMemo } from 'react'; interface ModalProps { children: React.ReactNode; onClose: () => void; - title?: string; // Added for ARIA-labelledby - description?: string; // Added for ARIA-describedby + title?: string; + description?: string; } function Modal({ children, onClose, title, description }: ModalProps): JSX.Element { @@ -52,12 +52,12 @@ function Modal({ children, onClose, title, description }: ModalProps): JSX.Eleme }; modalRef.current?.addEventListener('keydown', handleTabKeyPress); - firstElement?.focus(); // Focus on the first element when modal opens + firstElement?.focus(); return () => { modalRef.current?.removeEventListener('keydown', handleTabKeyPress); }; - }, [children]); // Re-run when modal content changes + }, [children]); const modalId = useMemo(() => `modal-${Math.random().toString(36).substring(2, 9)}`, []); const titleId = title ? `${modalId}-title` : undefined; diff --git a/src/hooks/useFetchBreedDetail.ts b/src/hooks/useFetchBreedDetail.ts index 5aa2a66c..65de39a0 100644 --- a/src/hooks/useFetchBreedDetail.ts +++ b/src/hooks/useFetchBreedDetail.ts @@ -1,4 +1,4 @@ -import { useState, useEffect, useCallback } from 'react'; +import { useState, useCallback } from 'react'; import { getBreedById, getBreedImages } from '../api/catApi'; import { Breed, CatImage } from '../api/types'; import { parseBreed } from '../api/parsers'; @@ -23,7 +23,6 @@ const useFetchBreedDetail = (): UseFetchBreedDetailResult => { try { let fetchedBreed: Breed | null = null; - // Try to parse from initialBreed (e.g., from location.state) if (initialBreed) { try { fetchedBreed = parseBreed(initialBreed); @@ -32,14 +31,12 @@ const useFetchBreedDetail = (): UseFetchBreedDetailResult => { } } - // If not found in initialBreed or parsing failed, fetch from API if (!fetchedBreed) { fetchedBreed = await getBreedById(breedId); } setBreed(fetchedBreed); - // Fetch images for the breed const images = await getBreedImages(breedId, 10); setBreedImages(images); } catch (err) { diff --git a/src/hooks/useFetchImageDetail.ts b/src/hooks/useFetchImageDetail.ts index c7412f64..4265bb2a 100644 --- a/src/hooks/useFetchImageDetail.ts +++ b/src/hooks/useFetchImageDetail.ts @@ -21,7 +21,6 @@ const useFetchImageDetail = (): UseFetchImageDetailResult => { try { let fetchedImage: CatImage | null = null; - // Try to parse from initialImage (e.g., from location.state) if (initialImage) { try { const [image] = parseCatImages([initialImage]); @@ -31,7 +30,6 @@ const useFetchImageDetail = (): UseFetchImageDetailResult => { } } - // If not found in initialImage or parsing failed, fetch from API if (!fetchedImage) { fetchedImage = await getImageById(imageId); } diff --git a/src/views/__tests__/__snapshots__/Home.test.tsx.snap b/src/views/__tests__/__snapshots__/Home.test.tsx.snap index e4d82ad7..c417dd3f 100644 --- a/src/views/__tests__/__snapshots__/Home.test.tsx.snap +++ b/src/views/__tests__/__snapshots__/Home.test.tsx.snap @@ -7,10 +7,81 @@ exports[`Home > should have the same snapshot as befoere 1`] = `

    Random Cats

    - 0 -

    - Loading... -

    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    + +
    From bda36a0a1321ddd80a63e6043bbd5fd5f11e9599 Mon Sep 17 00:00:00 2001 From: Marios Tsigkas Date: Mon, 22 Sep 2025 14:26:06 +0300 Subject: [PATCH 92/96] Update ImageCard layout to use flex-col for better alignment --- src/components/molecules/ImageCard.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/molecules/ImageCard.tsx b/src/components/molecules/ImageCard.tsx index 93ed178d..95631957 100644 --- a/src/components/molecules/ImageCard.tsx +++ b/src/components/molecules/ImageCard.tsx @@ -12,7 +12,7 @@ const ImageCard = memo(({ image, renderAfterImage }: ImageCardProps): JSX.Elemen const [isLoadingImage, setIsLoadingImage] = useState(true); return ( -
    +
    Date: Mon, 22 Sep 2025 14:58:23 +0300 Subject: [PATCH 93/96] add data attributes for Cypress testing --- cypress/e2e/home.spec.ts | 47 +++++++++++++------------- src/App.tsx | 8 ++--- src/components/atoms/Button.tsx | 1 + src/components/atoms/ErrorMessage.tsx | 3 +- src/components/atoms/Skeleton.tsx | 1 + src/components/molecules/ImageCard.tsx | 2 +- src/views/Home.tsx | 5 +-- 7 files changed, 35 insertions(+), 32 deletions(-) diff --git a/cypress/e2e/home.spec.ts b/cypress/e2e/home.spec.ts index b99eef0d..a4e09b71 100644 --- a/cypress/e2e/home.spec.ts +++ b/cypress/e2e/home.spec.ts @@ -1,22 +1,22 @@ // eslint-disable-next-line @typescript-eslint/triple-slash-reference /// -describe('Home Page', () => { +describe('Home Page Tests', () => { beforeEach(() => { cy.clearLocalStorage('favorites'); // Clear favorites before each test - cy.visit('/'); }); it('displays the header "Random Cats"', () => { - cy.get('h1').contains('Random Cats').should('exist'); + cy.visit('/'); + cy.get('[data-cy="home-header"]').contains('Random Cats').should('exist'); }); it('loads images and shows the "Load More" button', () => { cy.intercept('GET', '**/images/search?limit=10', { fixture: 'catImages.json' }).as('getCatImages'); cy.visit('/'); cy.wait('@getCatImages'); - cy.get('img').should('have.length.greaterThan', 0); - cy.get('button').contains('Load More').should('exist'); + cy.get('[data-cy="image-card-image"]').should('have.length.greaterThan', 0); + cy.get('[data-cy="load-more-button"]').should('exist'); }); it('displays skeleton loaders while fetching images', () => { @@ -27,33 +27,33 @@ describe('Home Page', () => { }); }).as('getCatImagesDelayed'); cy.visit('/'); - cy.get('.animate-pulse').should('have.length', 10); // Check for 10 skeleton cards + cy.get('[data-cy="skeleton-loader"]').should('have.length', 10); // Check for 10 skeleton cards cy.wait('@getCatImagesDelayed'); - cy.get('.animate-pulse').should('not.exist'); - cy.get('img').should('have.length.greaterThan', 0); + cy.get('[data-cy="skeleton-loader"]').should('not.exist'); + cy.get('[data-cy="image-card-image"]').should('have.length.greaterThan', 0); }); it('displays an error message on API failure', () => { cy.intercept('GET', '**/images/search?limit=10', { statusCode: 500, body: 'Internal Server Error' }).as('getCatImagesError'); cy.visit('/'); cy.wait('@getCatImagesError'); - cy.get('p.text-red-500').contains('Failed to fetch images').should('exist'); - cy.get('button').contains('Load More').should('not.be.disabled'); // Button should be enabled to allow retry + cy.get('[data-cy="error-message"]').contains('Failed to load images.').should('exist'); + cy.get('[data-cy="load-more-button"]').should('not.be.disabled'); // Button should be enabled to allow retry }); it('displays "No images found." when API returns empty data', () => { cy.intercept('GET', '**/images/search?limit=10', { body: [] }).as('getCatImagesEmpty'); cy.visit('/'); cy.wait('@getCatImagesEmpty'); - cy.get('p').contains('No images found.').should('exist'); - cy.get('button').contains('Load More').should('exist'); // Button should still be there to try again + cy.get('[data-cy="no-images-found-message"]').contains('No images found.').should('exist'); + cy.get('[data-cy="load-more-button"]').should('exist'); // Button should still be there to try again }); it('navigates to image detail on image click', () => { cy.intercept('GET', '**/images/search?limit=10', { fixture: 'catImages.json' }).as('getCatImages'); cy.visit('/'); cy.wait('@getCatImages'); - cy.get('img').first().click(); + cy.get('[data-cy="image-card-image"]').first().click(); cy.url().should('include', '/image/'); cy.get('[role="dialog"]').should('be.visible'); }); @@ -62,7 +62,7 @@ describe('Home Page', () => { cy.intercept('GET', '**/images/search?limit=10', { fixture: 'catImages.json' }).as('getCatImages'); cy.visit('/'); cy.wait('@getCatImages'); - cy.get('img').first().click(); + cy.get('[data-cy="image-card-image"]').first().click(); cy.get('[role="dialog"]').should('be.visible'); cy.realPress('{esc}'); // Use cypress-real-events for Escape key cy.get('[role="dialog"]').should('not.exist'); @@ -73,32 +73,31 @@ describe('Home Page', () => { cy.get('[data-cy="no-favorites-message"]').contains('No favorite cats yet.').should('exist'); }); - it('adds and removes image from favorites', () => { cy.intercept('GET', '**/images/search?limit=10', { fixture: 'catImages.json' }).as('getCatImages'); cy.visit('/'); cy.wait('@getCatImages'); - cy.get('img').first().click(); + cy.get('[data-cy="image-card-image"]').first().click(); cy.get('[role="dialog"]').should('be.visible'); // Mark as favorite - cy.get('button').contains('Mark as Favourite').click(); - cy.get('button').contains('Remove from Favourites').should('exist'); + cy.get('[data-cy="mark-as-favourite-button"]').click(); + cy.get('[data-cy="remove-from-favourites-button"]').should('exist'); cy.realPress('{esc}'); // Close modal // Navigate to favorites page - cy.get('nav').contains('Favorites').click(); + cy.get('[data-cy="favorites-link"]').click(); cy.url().should('include', '/favorites'); - cy.get('img').should('have.length', 1); // Should have 1 favorite image + cy.get('[data-cy="image-card-image"]').should('have.length', 1); // Should have 1 favorite image // Open the favorite image from the favorites page - cy.get('img').first().click(); + cy.get('[data-cy="image-card-image"]').first().click(); cy.get('[role="dialog"]').should('be.visible'); - cy.get('button').contains('Remove from Favourites').should('exist'); + cy.get('[data-cy="remove-from-favourites-button"]').should('exist'); // Remove from favorites - cy.get('button').contains('Remove from Favourites').click(); - cy.get('button').contains('Mark as Favourite').should('exist'); // Button text changes back + cy.get('[data-cy="remove-from-favourites-button"]').click(); + cy.get('[data-cy="mark-as-favourite-button"]').should('exist'); // Button text changes back cy.get('[data-cy="close-modal-button"]').click(); // Close modal by clicking the close button // Verify no favorites diff --git a/src/App.tsx b/src/App.tsx index 71c24e3c..8979c2ae 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -18,19 +18,19 @@ function App() { return (
    - + Loading...
    }> } /> diff --git a/src/components/atoms/Button.tsx b/src/components/atoms/Button.tsx index 646e401d..d3bd8ee2 100644 --- a/src/components/atoms/Button.tsx +++ b/src/components/atoms/Button.tsx @@ -32,6 +32,7 @@ const Button = ({ diff --git a/src/components/atoms/Skeleton.tsx b/src/components/atoms/Skeleton.tsx index 6d83bd0d..ee67800e 100644 --- a/src/components/atoms/Skeleton.tsx +++ b/src/components/atoms/Skeleton.tsx @@ -13,6 +13,7 @@ const Skeleton = React.memo(({ width = '100%', height = '100%', className = '' } aria-label="loading" className={`bg-gray-300 rounded-lg shadow-md animate-pulse ${className}`} style={{ width, height }} + data-cy="skeleton-loader" >
    ); }); diff --git a/src/components/molecules/ImageCard.tsx b/src/components/molecules/ImageCard.tsx index 95631957..8a9736b9 100644 --- a/src/components/molecules/ImageCard.tsx +++ b/src/components/molecules/ImageCard.tsx @@ -18,7 +18,7 @@ const ImageCard = memo(({ image, renderAfterImage }: ImageCardProps): JSX.Elemen state={{ image }} onMouseEnter={() => void import('../../views/ImageView')} > - {isLoadingImage && } + {isLoadingImage && } cat -

    Random Cats

    +

    Random Cats

    {error && void fetchImages()} />} {!isLoading && !error && images.length === 0 && ( -

    No images found.

    +

    No images found.

    )}
    @@ -29,6 +29,7 @@ function Home(): JSX.Element { }} isLoading={isLoading} disabled={isLoading} + data-cy="load-more-button" > Load More From 2e45fac4109b87665525c920333ff0cfca03b7fa Mon Sep 17 00:00:00 2001 From: Marios Tsigkas Date: Mon, 22 Sep 2025 15:29:20 +0300 Subject: [PATCH 94/96] Add tests for Favorites page and refactor Home page tests for reusability --- cypress/e2e/favorites.spec.ts | 6 +++++ cypress/e2e/home.spec.ts | 36 ++++++++------------------ src/components/molecules/ImageCard.tsx | 1 + 3 files changed, 18 insertions(+), 25 deletions(-) create mode 100644 cypress/e2e/favorites.spec.ts diff --git a/cypress/e2e/favorites.spec.ts b/cypress/e2e/favorites.spec.ts new file mode 100644 index 00000000..851d6d18 --- /dev/null +++ b/cypress/e2e/favorites.spec.ts @@ -0,0 +1,6 @@ +describe('Favorites Page Tests', () => { + it('displays "No favorite cats yet." when favorites are empty', () => { + cy.visit('/favorites'); + cy.get('[data-cy="no-favorites-message"]').contains('No favorite cats yet.').should('exist'); + }); +}); \ No newline at end of file diff --git a/cypress/e2e/home.spec.ts b/cypress/e2e/home.spec.ts index a4e09b71..4fb60219 100644 --- a/cypress/e2e/home.spec.ts +++ b/cypress/e2e/home.spec.ts @@ -1,31 +1,28 @@ // eslint-disable-next-line @typescript-eslint/triple-slash-reference /// +const visitHomePage = () => { + cy.visit('/'); +}; + describe('Home Page Tests', () => { beforeEach(() => { cy.clearLocalStorage('favorites'); // Clear favorites before each test }); it('displays the header "Random Cats"', () => { - cy.visit('/'); + visitHomePage(); cy.get('[data-cy="home-header"]').contains('Random Cats').should('exist'); }); it('loads images and shows the "Load More" button', () => { - cy.intercept('GET', '**/images/search?limit=10', { fixture: 'catImages.json' }).as('getCatImages'); - cy.visit('/'); - cy.wait('@getCatImages'); + visitHomePage(); cy.get('[data-cy="image-card-image"]').should('have.length.greaterThan', 0); cy.get('[data-cy="load-more-button"]').should('exist'); }); it('displays skeleton loaders while fetching images', () => { - cy.intercept('GET', '**/images/search?limit=10', (req) => { - req.reply({ - delay: 500, // Simulate network delay - fixture: 'catImages.json', - }); - }).as('getCatImagesDelayed'); + cy.intercept('GET', '**/images/search?limit=10').as('getCatImagesDelayed'); cy.visit('/'); cy.get('[data-cy="skeleton-loader"]').should('have.length', 10); // Check for 10 skeleton cards cy.wait('@getCatImagesDelayed'); @@ -50,33 +47,22 @@ describe('Home Page Tests', () => { }); it('navigates to image detail on image click', () => { - cy.intercept('GET', '**/images/search?limit=10', { fixture: 'catImages.json' }).as('getCatImages'); - cy.visit('/'); - cy.wait('@getCatImages'); + visitHomePage(); cy.get('[data-cy="image-card-image"]').first().click(); cy.url().should('include', '/image/'); cy.get('[role="dialog"]').should('be.visible'); }); it('closes the modal on Escape key press', () => { - cy.intercept('GET', '**/images/search?limit=10', { fixture: 'catImages.json' }).as('getCatImages'); - cy.visit('/'); - cy.wait('@getCatImages'); + visitHomePage(); cy.get('[data-cy="image-card-image"]').first().click(); cy.get('[role="dialog"]').should('be.visible'); cy.realPress('{esc}'); // Use cypress-real-events for Escape key cy.get('[role="dialog"]').should('not.exist'); }); - it('displays "No favorite cats yet." when favorites are empty', () => { - cy.visit('/favorites'); - cy.get('[data-cy="no-favorites-message"]').contains('No favorite cats yet.').should('exist'); - }); - it('adds and removes image from favorites', () => { - cy.intercept('GET', '**/images/search?limit=10', { fixture: 'catImages.json' }).as('getCatImages'); - cy.visit('/'); - cy.wait('@getCatImages'); + visitHomePage(); cy.get('[data-cy="image-card-image"]').first().click(); cy.get('[role="dialog"]').should('be.visible'); @@ -98,7 +84,7 @@ describe('Home Page Tests', () => { // Remove from favorites cy.get('[data-cy="remove-from-favourites-button"]').click(); cy.get('[data-cy="mark-as-favourite-button"]').should('exist'); // Button text changes back - cy.get('[data-cy="close-modal-button"]').click(); // Close modal by clicking the close button + cy.get('[aria-label="Close modal"]').click(); // Close modal by clicking the close button // Verify no favorites cy.get('[data-cy="no-favorites-message"]').contains('No favorite cats yet.').should('exist'); diff --git a/src/components/molecules/ImageCard.tsx b/src/components/molecules/ImageCard.tsx index 8a9736b9..e98477ed 100644 --- a/src/components/molecules/ImageCard.tsx +++ b/src/components/molecules/ImageCard.tsx @@ -22,6 +22,7 @@ const ImageCard = memo(({ image, renderAfterImage }: ImageCardProps): JSX.Elemen cat setIsLoadingImage(false)} From 90b5087a56bc4d17c83dff288fc6c4b2df07e0b0 Mon Sep 17 00:00:00 2001 From: Marios Tsigkas Date: Mon, 22 Sep 2025 17:09:17 +0300 Subject: [PATCH 95/96] Update snapshot --- .../__tests__/__snapshots__/Home.test.tsx.snap | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/views/__tests__/__snapshots__/Home.test.tsx.snap b/src/views/__tests__/__snapshots__/Home.test.tsx.snap index c417dd3f..207d3dcc 100644 --- a/src/views/__tests__/__snapshots__/Home.test.tsx.snap +++ b/src/views/__tests__/__snapshots__/Home.test.tsx.snap @@ -4,7 +4,9 @@ exports[`Home > should have the same snapshot as befoere 1`] = `
    -

    +

    Random Cats

    should have the same snapshot as befoere 1`] = `
    @@ -77,6 +89,7 @@ exports[`Home > should have the same snapshot as befoere 1`] = ` >