diff --git a/.github/workflows/e2e_wsl.yml b/.github/workflows/e2e_wsl.yml index d6f1594..bc891dd 100644 --- a/.github/workflows/e2e_wsl.yml +++ b/.github/workflows/e2e_wsl.yml @@ -15,20 +15,9 @@ jobs: with: node-version: lts/* cache: 'npm' - - - name: Enable WSL - run: | - curl -L "https://cloud-images.ubuntu.com/releases/jammy/release/ubuntu-22.04-server-cloudimg-amd64-root.tar.xz" -o ubuntu-22.04.tar.xz - wsl --import glacier . ubuntu-22.04.tar.xz - - name: Install dependencies inside WSL - run: | - wsl bash -lc "sudo apt-get update" - wsl bash -lc "sudo apt-get install -y openjdk-17-jre curl unzip" - - name: Install Nextflow inside WSL - run: | - wsl bash -lc "curl -s https://get.nextflow.io | bash" - wsl bash -lc "sudo mv nextflow /usr/local/bin/" - + - name: Setup WSL + shell: pwsh + run: ./scripts/wsl-setup.ps1 - name: Install dependencies run: npm ci - name: Install Playwright Browsers diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index ed566ae..358af27 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -27,7 +27,7 @@ jobs: uses: actions/setup-java@v5 with: distribution: 'temurin' - java-version: '25' + java-version: '21' - name: Setup Node.js uses: actions/setup-node@v4 diff --git a/.gitignore b/.gitignore index 74c5831..9bb10fa 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ bundle +tests/test-data/instances* # Logs logs diff --git a/api-server/index.js b/api-server/index.js index a7356c4..41f61e9 100644 --- a/api-server/index.js +++ b/api-server/index.js @@ -38,7 +38,7 @@ async function call(fcn, ...args) { } app.post('/api/create-workflow-instance', async (req, res) => - post_response(res, collection.createWorkflowInstance(req.body.workflow_id)) + post_response(res, collection.createWorkflowInstance(req.body.workflow_id, req.body.version)) ); app.post('/api/run-workflow', async (req, res) => @@ -97,15 +97,76 @@ app.post('/api/get-available-profiles', async (req, res) => ); app.post('/api/clone-repo', async (req, res) => - post_response(res, collection.cloneRepo(req.body.repoUrl, req.body.ver)) + post_response(res, call(collection.cloneRepo.bind(collection), req.body.repoUrl, req.body.ver)) +); + +app.post('/api/is-repo-installed', async (req, res) => + post_response( + res, + call(collection.isRepoInstalled.bind(collection), req.body.repoUrl, req.body.ver) + ) ); app.post('/api/sync-repo', async (req, res) => post_response(res, collection.syncRepo(req.body.repo)) ); -app.post('/api/get-collections', async (req, res) => - post_response(res, collection.getCollections()) +app.post('/api/add-catalogue', async (req, res) => + post_response(res, call(collection.addCatalogue.bind(collection), req.body.repoUrl, req.body.ver)) +); + +app.post('/api/remove-catalogue', async (req, res) => + post_response(res, collection.removeCatalogue(req.body.catalogue_name)) +); + +app.post('/api/remove-catalogue-section', async (req, res) => + post_response( + res, + collection.removeCatalogueSection(req.body.catalogue_name, req.body.section_name) + ) +); + +app.post('/api/remove-catalogue-workflow', async (req, res) => + post_response( + res, + collection.removeCatalogueWorkflow( + req.body.catalogue_name, + req.body.section_name, + req.body.workflow_name + ) + ) +); + +app.post('/api/update-catalogue-workflow', async (req, res) => + post_response( + res, + collection.updateCatalogueWorkflow( + req.body.catalogue_name, + req.body.section_name, + req.body.workflow_name + ) + ) +); + +app.post('/api/get-catalogues', async (req, res) => + post_response(res, call(collection.getCatalogues.bind(collection))) +); + +app.post('/api/add-user-workflow', async (req, res) => + post_response( + res, + call( + collection.addUserWorkflow.bind(collection), + req.body.name, + req.body.repoUrl, + req.body.ver, + req.body.section + ) + ) +); + +app.post('/api/get-collection-repos', async (req, res) => + post_response(res, collection.getCollectionRepos()) ); app.post('/api/get-collections-path', async (req, res) => @@ -136,18 +197,6 @@ app.post('/api/get-workflow-schema', async (req, res) => post_response(res, collection.getWorkflowSchema(req.body.repoPath)) ); -app.post('/api/get-projects-list', async (req, res) => - post_response(res, collection.getProjectsList()) -); - -app.post('/api/add-project', async (req, res) => - post_response(res, collection.addProject(req.body.repoPath)) -); - -app.post('/api/remove-project', async (req, res) => - post_response(res, collection.removeProject(req.body.project)) -); - app.post('/api/get-installable-repos-list', async (req, res) => post_response(res, collection.getInstallableReposList()) ); @@ -164,10 +213,12 @@ app.post('/api/get-workflow-information', async (req, res) => post_response(res, collection.getWorkflowInformation(req.body.instance)) ); -app.post('/api/settings-get', async (req, res) => post_response(res, collection.settingsGet())); +app.post('/api/settings-get', async (req, res) => + post_response(res, collection.settingsGet(req.body.key)) +); app.post('/api/settings-set', async (req, res) => - post_response(res, collection.settingsSet(req.body.value)) + post_response(res, collection.settingsSet(req.body.key, req.body.value)) ); app.post('/api/open-web-page', async (req, res) => diff --git a/eslint.config.js b/eslint.config.js index 79d9862..8023d83 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -3,11 +3,16 @@ import react from 'eslint-plugin-react'; import reactHooks from 'eslint-plugin-react-hooks'; import jsxA11y from 'eslint-plugin-jsx-a11y'; import prettier from 'eslint-config-prettier'; +import tsParser from '@typescript-eslint/parser'; +import tsPlugin from '@typescript-eslint/eslint-plugin'; +import importPlugin from 'eslint-plugin-import'; +import { createTypeScriptImportResolver } from 'eslint-import-resolver-typescript'; +import unusedImports from 'eslint-plugin-unused-imports'; export default [ // Global ignore block { - ignores: ['node_modules', 'public', 'coverage'] + ignores: ['node_modules', 'public', 'coverage', 'dist'] }, // Vite config (ESM) @@ -16,15 +21,27 @@ export default [ languageOptions: { ecmaVersion: 'latest', sourceType: 'module' + }, + settings: { + 'import-x/resolver-next': [ + createTypeScriptImportResolver({ + project: 'src' + }) + ] } }, - // Backend (ESM) + // Backend (Node / ESM + TypeScript) { - files: ['src/main/**/*.{js,jsx}', 'src/preload/**/*.{js,jsx}', 'vite.config.js'], + files: ['src/main/**/*.{js,jsx,ts,tsx}', 'src/preload/**/*.{js,jsx,ts,tsx}', 'vite.config.js'], languageOptions: { ecmaVersion: 'latest', sourceType: 'module', + parser: tsParser, + parserOptions: { + ecmaVersion: 'latest', + sourceType: 'module' + }, globals: { require: 'readonly', module: 'readonly', @@ -32,16 +49,66 @@ export default [ process: 'readonly', URL: 'readonly' } + }, + plugins: { + '@typescript-eslint': tsPlugin, + import: importPlugin, + 'unused-imports': unusedImports, + 'jsx-a11y': jsxA11y + }, + settings: { + 'import/resolver': { + typescript: { + /* project: './tsconfig.json' or backend tsconfig */ + } + } + }, + rules: { + 'no-unused-vars': 'off', // JS core rule off + '@typescript-eslint/no-unused-vars': [ + 'warn', + { + vars: 'all', + args: 'after-used', + ignoreRestSiblings: true + } + ], + + 'unused-imports/no-unused-imports': 'warn', + 'unused-imports/no-unused-vars': 'off', + + // backend-specific import rules: + // allow devDependencies in scripts/tests but not in src + 'import/no-extraneous-dependencies': [ + 'error', + { + devDependencies: [ + 'test/**', + 'tests/**', + '**/*.test.{js,jsx,ts,tsx}', + 'scripts/**', + 'build/**', + 'tools/**' + ], + optionalDependencies: false, + peerDependencies: false + } + ], + + 'import/no-unresolved': 'error' } }, // Frontend (ESM + React) { - files: ['src/renderer/**/*.{js,jsx}'], + files: ['src/renderer/**/*.{js,jsx,ts,tsx}'], languageOptions: { ecmaVersion: 'latest', sourceType: 'module', + parser: tsParser, parserOptions: { + ecmaVersion: 'latest', + sourceType: 'module', ecmaFeatures: { jsx: true } }, globals: { @@ -53,15 +120,44 @@ export default [ plugins: { react, 'react-hooks': reactHooks, - 'jsx-a11y': jsxA11y - }, - rules: { - 'react/react-in-jsx-scope': 'off' + 'jsx-a11y': jsxA11y, + '@typescript-eslint': tsPlugin, + import: importPlugin, + 'unused-imports': unusedImports }, settings: { - react: { - version: 'detect' + react: { version: 'detect' }, + 'import/resolver': { + typescript: { + /* project: './tsconfig.json' if needed */ + } } + }, + rules: { + 'react/react-in-jsx-scope': 'off', + + 'no-unused-vars': 'off', // JS core rule off + '@typescript-eslint/no-unused-vars': [ + 'warn', + { + vars: 'all', + args: 'after-used', + ignoreRestSiblings: true + } + ], + + // unused-imports plugin (detects & can auto-fix unused imports) + 'unused-imports/no-unused-imports': 'warn', + 'unused-imports/no-unused-vars': 'off', + + // helpful import resolution rules + 'import/no-unresolved': 'error', + 'import/no-extraneous-dependencies': [ + 'error', + { + devDependencies: ['**/*.test.*', 'test/**', 'tests/**', 'scripts/**'] + } + ] } } ]; diff --git a/package-lock.json b/package-lock.json index 80c3312..26d2f31 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,11 +16,15 @@ "@jsonforms/react": "^3.7.0-alpha.1", "@mui/icons-material": "^7.2.0", "@mui/material": "^7.2.0", + "@mui/system": "^7.3.7", + "@vitejs/plugin-react": "^4.6.0", "ajv": "^8.17.1", "ansi-to-html": "^0.7.2", "dockerode": "^4.0.7", "dompurify": "^3.2.7", + "electron": "^37.3.1", "electron-store": "8.2.0", + "hast-util-sanitize": "^5.0.2", "i18next": "^25.5.2", "i18next-browser-languagedetector": "^8.2.0", "i18next-resources-to-backend": "^1.2.1", @@ -39,25 +43,28 @@ "slash": "^5.1.0", "typescript": "^5.9.3", "unique-names-generator": "^4.7.1", - "unist-util-visit": "^5.0.0" + "unist-util-visit": "^5.0.0", + "vite": "^7.1.11" }, "devDependencies": { "@playwright/test": "^1.56.1", "@types/dockerode": "^3.3.42", "@types/js-yaml": "^4.0.9", "@types/node": "^24.0.12", - "@vitejs/plugin-react": "^4.6.0", + "@typescript-eslint/eslint-plugin": "^8.54.0", + "@typescript-eslint/parser": "^8.54.0", "@vitest/coverage-v8": "^3.2.4", "css.escape": "^1.5.1", - "electron": "^37.3.1", "electron-builder": "^26.0.12", "eslint": "^9.30.1", "eslint-config-prettier": "^10.1.5", + "eslint-import-resolver-typescript": "^4.4.4", + "eslint-plugin-import": "^2.32.0", "eslint-plugin-jsx-a11y": "^6.10.2", "eslint-plugin-react": "^7.37.5", "eslint-plugin-react-hooks": "^5.2.0", + "eslint-plugin-unused-imports": "^4.3.0", "prettier": "^3.6.2", - "vite": "^7.1.11", "vitest": "^3.2.4" } }, @@ -76,9 +83,9 @@ } }, "node_modules/@babel/code-frame": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.28.6.tgz", - "integrity": "sha512-JYgintcMjRiCvS8mMECzaEn+m3PfoQiyqukOMCCVQtoJGYJw8j/8LBJEiqkHLkfwCcs74E3pbAUFNg7d9VNJ+Q==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz", + "integrity": "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==", "license": "MIT", "dependencies": { "@babel/helper-validator-identifier": "^7.28.5", @@ -90,31 +97,29 @@ } }, "node_modules/@babel/compat-data": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.6.tgz", - "integrity": "sha512-2lfu57JtzctfIrcGMz992hyLlByuzgIk58+hhGCxjKZ3rWI82NnVLjXcaTqkI2NvlcvOskZaiZ5kjUALo3Lpxg==", - "dev": true, + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.0.tgz", + "integrity": "sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg==", "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/core": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.6.tgz", - "integrity": "sha512-H3mcG6ZDLTlYfaSNi0iOKkigqMFvkTKlGUYlD8GW7nNOYRrevuA46iTypPyv+06V3fEmvvazfntkBU34L0azAw==", - "dev": true, + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.0.tgz", + "integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==", "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.28.6", - "@babel/generator": "^7.28.6", + "@babel/code-frame": "^7.29.0", + "@babel/generator": "^7.29.0", "@babel/helper-compilation-targets": "^7.28.6", "@babel/helper-module-transforms": "^7.28.6", "@babel/helpers": "^7.28.6", - "@babel/parser": "^7.28.6", + "@babel/parser": "^7.29.0", "@babel/template": "^7.28.6", - "@babel/traverse": "^7.28.6", - "@babel/types": "^7.28.6", + "@babel/traverse": "^7.29.0", + "@babel/types": "^7.29.0", "@jridgewell/remapping": "^2.3.5", "convert-source-map": "^2.0.0", "debug": "^4.1.0", @@ -134,17 +139,25 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "dev": true, "license": "MIT" }, + "node_modules/@babel/core/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, "node_modules/@babel/generator": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.6.tgz", - "integrity": "sha512-lOoVRwADj8hjf7al89tvQ2a1lf53Z+7tiXMgpZJL3maQPDxh0DgLMN62B2MKUOFcoodBHLMbDM6WAbKgNy5Suw==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.0.tgz", + "integrity": "sha512-vSH118/wwM/pLR38g/Sgk05sNtro6TlTJKuiMXDaZqPUfjTFcudpCOt00IhOfj+1BFAX+UFAlzCU+6WXr3GLFQ==", "license": "MIT", "dependencies": { - "@babel/parser": "^7.28.6", - "@babel/types": "^7.28.6", + "@babel/parser": "^7.29.0", + "@babel/types": "^7.29.0", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" @@ -157,7 +170,6 @@ "version": "7.28.6", "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.28.6.tgz", "integrity": "sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==", - "dev": true, "license": "MIT", "dependencies": { "@babel/compat-data": "^7.28.6", @@ -170,6 +182,15 @@ "node": ">=6.9.0" } }, + "node_modules/@babel/helper-compilation-targets/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, "node_modules/@babel/helper-globals": { "version": "7.28.0", "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", @@ -196,7 +217,6 @@ "version": "7.28.6", "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz", "integrity": "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-module-imports": "^7.28.6", @@ -214,7 +234,6 @@ "version": "7.28.6", "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.28.6.tgz", "integrity": "sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==", - "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -242,7 +261,6 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", - "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -252,7 +270,6 @@ "version": "7.28.6", "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.6.tgz", "integrity": "sha512-xOBvwq86HHdB7WUDTfKfT/Vuxh7gElQ+Sfti2Cy6yIWNW05P8iUslOVcZ4/sKbE+/jQaukQAdz/gf3724kYdqw==", - "dev": true, "license": "MIT", "dependencies": { "@babel/template": "^7.28.6", @@ -263,12 +280,12 @@ } }, "node_modules/@babel/parser": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.6.tgz", - "integrity": "sha512-TeR9zWR18BvbfPmGbLampPMW+uW1NZnJlRuuHso8i87QZNq2JRF9i6RgxRqtEq+wQGsS19NNTWr2duhnE49mfQ==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.0.tgz", + "integrity": "sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==", "license": "MIT", "dependencies": { - "@babel/types": "^7.28.6" + "@babel/types": "^7.29.0" }, "bin": { "parser": "bin/babel-parser.js" @@ -281,7 +298,6 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.27.1.tgz", "integrity": "sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" @@ -297,7 +313,6 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.27.1.tgz", "integrity": "sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" @@ -333,17 +348,17 @@ } }, "node_modules/@babel/traverse": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.6.tgz", - "integrity": "sha512-fgWX62k02qtjqdSNTAGxmKYY/7FSL9WAS1o2Hu5+I5m9T0yxZzr4cnrfXQ/MX0rIifthCSs6FKTlzYbJcPtMNg==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.0.tgz", + "integrity": "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==", "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.28.6", - "@babel/generator": "^7.28.6", + "@babel/code-frame": "^7.29.0", + "@babel/generator": "^7.29.0", "@babel/helper-globals": "^7.28.0", - "@babel/parser": "^7.28.6", + "@babel/parser": "^7.29.0", "@babel/template": "^7.28.6", - "@babel/types": "^7.28.6", + "@babel/types": "^7.29.0", "debug": "^4.3.1" }, "engines": { @@ -351,9 +366,9 @@ } }, "node_modules/@babel/types": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.6.tgz", - "integrity": "sha512-0ZrskXVEHSWIqZM/sQZ4EV3jZJXRkio/WCxaqKZP1g//CEWEPSfeZFcms4XeKBCHU0ZKnIkdJeU/kF+eRp5lBg==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz", + "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==", "license": "MIT", "dependencies": { "@babel/helper-string-parser": "^7.27.1", @@ -472,6 +487,17 @@ "node": ">=10.12.0" } }, + "node_modules/@electron/asar/node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, "node_modules/@electron/asar/node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -543,7 +569,6 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/@electron/get/-/get-2.0.3.tgz", "integrity": "sha512-Qkzpg2s9GnVV2I2BjRksUi43U5e6+zaQMcjoJy0C+C5oxaKl+fmckGDQFtRpZpZV0NQekuZZ+tGz7EA9TVnQtQ==", - "dev": true, "license": "MIT", "dependencies": { "debug": "^4.1.1", @@ -561,6 +586,15 @@ "global-agent": "^3.0.0" } }, + "node_modules/@electron/get/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, "node_modules/@electron/notarize": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/@electron/notarize/-/notarize-2.5.0.tgz", @@ -689,14 +723,13 @@ } }, "node_modules/@electron/rebuild": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@electron/rebuild/-/rebuild-4.0.1.tgz", - "integrity": "sha512-iMGXb6Ib7H/Q3v+BKZJoETgF9g6KMNZVbsO4b7Dmpgb5qTFqyFTzqW9F3TOSHdybv2vKYKzSS9OiZL+dcJb+1Q==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@electron/rebuild/-/rebuild-4.0.3.tgz", + "integrity": "sha512-u9vpTHRMkOYCs/1FLiSVAFZ7FbjsXK+bQuzviJZa+lG7BHZl1nz52/IcGvwa3sk80/fc3llutBkbCq10Vh8WQA==", "dev": true, "license": "MIT", "dependencies": { "@malept/cross-spawn-promise": "^2.0.0", - "chalk": "^4.0.0", "debug": "^4.1.1", "detect-libc": "^2.0.1", "got": "^11.7.0", @@ -707,7 +740,7 @@ "ora": "^5.1.0", "read-binary-file-arch": "^1.0.6", "semver": "^7.3.5", - "tar": "^6.0.5", + "tar": "^7.5.6", "yargs": "^17.0.1" }, "bin": { @@ -717,19 +750,6 @@ "node": ">=22.12.0" } }, - "node_modules/@electron/rebuild/node_modules/semver": { - "version": "7.7.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", - "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/@electron/universal": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/@electron/universal/-/universal-2.0.3.tgz", @@ -749,16 +769,6 @@ "node": ">=16.4" } }, - "node_modules/@electron/universal/node_modules/brace-expansion": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", - "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, "node_modules/@electron/universal/node_modules/fs-extra": { "version": "11.3.3", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.3.tgz", @@ -787,22 +797,6 @@ "graceful-fs": "^4.1.6" } }, - "node_modules/@electron/universal/node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/@electron/universal/node_modules/universalify": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", @@ -879,6 +873,40 @@ "node": ">= 10.0.0" } }, + "node_modules/@emnapi/core": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.8.1.tgz", + "integrity": "sha512-AvT9QFpxK0Zd8J0jopedNm+w/2fIzvtPKPjqyw9jwvBaReTTqPBk9Hixaz7KbjimP+QNz605/XnjFcDAL2pqBg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/wasi-threads": "1.1.0", + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/runtime": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.8.1.tgz", + "integrity": "sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/wasi-threads": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.1.0.tgz", + "integrity": "sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, "node_modules/@emotion/babel-plugin": { "version": "11.13.5", "resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.13.5.tgz", @@ -1032,7 +1060,6 @@ "cpu": [ "ppc64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1049,7 +1076,6 @@ "cpu": [ "arm" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1066,7 +1092,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1083,7 +1108,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1100,7 +1124,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1117,7 +1140,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1134,7 +1156,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1151,7 +1172,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1168,7 +1188,6 @@ "cpu": [ "arm" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1185,7 +1204,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1202,7 +1220,6 @@ "cpu": [ "ia32" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1219,7 +1236,6 @@ "cpu": [ "loong64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1236,7 +1252,6 @@ "cpu": [ "mips64el" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1253,7 +1268,6 @@ "cpu": [ "ppc64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1270,7 +1284,6 @@ "cpu": [ "riscv64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1287,7 +1300,6 @@ "cpu": [ "s390x" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1304,7 +1316,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1321,7 +1332,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1338,7 +1348,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1355,7 +1364,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1372,7 +1380,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1389,7 +1396,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1406,7 +1412,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1423,7 +1428,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1440,7 +1444,6 @@ "cpu": [ "ia32" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1457,7 +1460,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1486,19 +1488,6 @@ "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, - "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, "node_modules/@eslint-community/regexpp": { "version": "4.12.2", "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", @@ -1524,6 +1513,17 @@ "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, + "node_modules/@eslint/config-array/node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, "node_modules/@eslint/config-array/node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -1604,6 +1604,27 @@ "url": "https://github.com/sponsors/epoberezkin" } }, + "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@eslint/eslintrc/node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, "node_modules/@eslint/eslintrc/node_modules/json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", @@ -1918,7 +1939,6 @@ "version": "2.3.5", "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", - "dev": true, "license": "MIT", "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", @@ -2318,15 +2338,15 @@ } }, "node_modules/@mui/x-date-pickers": { - "version": "8.25.0", - "resolved": "https://registry.npmjs.org/@mui/x-date-pickers/-/x-date-pickers-8.25.0.tgz", - "integrity": "sha512-XmLQwlo9C9gPWY9OeFbQka4TGi3MXrW/jJ+E4LV1wdfg/ebOklq6KKKTbvRgTVWlMcIoQwqPbalFxcwQSUUbDw==", + "version": "8.27.0", + "resolved": "https://registry.npmjs.org/@mui/x-date-pickers/-/x-date-pickers-8.27.0.tgz", + "integrity": "sha512-mw47IgelP5qFSBANqxUhqDEly2XO9RT/BcNKwgumy8BmmdosrGAmTev8dgFMoWg20iPHxEczlpBdDGyV6ht0jg==", "license": "MIT", "peer": true, "dependencies": { "@babel/runtime": "^7.28.4", "@mui/utils": "^7.3.5", - "@mui/x-internals": "8.25.0", + "@mui/x-internals": "8.26.0", "@types/react-transition-group": "^4.4.12", "clsx": "^2.1.1", "prop-types": "^15.8.1", @@ -2385,9 +2405,9 @@ } }, "node_modules/@mui/x-internals": { - "version": "8.25.0", - "resolved": "https://registry.npmjs.org/@mui/x-internals/-/x-internals-8.25.0.tgz", - "integrity": "sha512-RKexkVaK3xvAeLBNeLAw6oJCsQrXkx7TYSRoSUmmJveydqOqoBbimv+nbc8PmL4UL0ShVNkaFL1YWY7kYCCXUA==", + "version": "8.26.0", + "resolved": "https://registry.npmjs.org/@mui/x-internals/-/x-internals-8.26.0.tgz", + "integrity": "sha512-B9OZau5IQUvIxwpJZhoFJKqRpmWf5r0yMmSXjQuqb5WuqM755EuzWJOenY48denGoENzMLT8hQpA0hRTeU2IPA==", "license": "MIT", "peer": true, "dependencies": { @@ -2407,6 +2427,19 @@ "react": "^17.0.0 || ^18.0.0 || ^19.0.0" } }, + "node_modules/@napi-rs/wasm-runtime": { + "version": "0.2.12", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.12.tgz", + "integrity": "sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "^1.4.3", + "@emnapi/runtime": "^1.4.3", + "@tybys/wasm-util": "^0.10.0" + } + }, "node_modules/@npmcli/agent": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/@npmcli/agent/-/agent-3.0.0.tgz", @@ -2444,19 +2477,6 @@ "node": "^18.17.0 || >=20.5.0" } }, - "node_modules/@npmcli/fs/node_modules/semver": { - "version": "7.7.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", - "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/@pkgjs/parseargs": { "version": "0.11.0", "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", @@ -2469,13 +2489,13 @@ } }, "node_modules/@playwright/test": { - "version": "1.57.0", - "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.57.0.tgz", - "integrity": "sha512-6TyEnHgd6SArQO8UO2OMTxshln3QMWBtPGrOCgs3wVEmQmwyuNtB10IZMfmYDE0riwNR1cu4q+pPcxMVtaG3TA==", + "version": "1.58.1", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.58.1.tgz", + "integrity": "sha512-6LdVIUERWxQMmUSSQi0I53GgCBYgM2RpGngCPY7hSeju+VrKjq3lvs7HpJoPbDiY5QM5EYRtRX5fvrinnMAz3w==", "dev": true, "license": "Apache-2.0", "dependencies": { - "playwright": "1.57.0" + "playwright": "1.58.1" }, "bin": { "playwright": "cli.js" @@ -2562,17 +2582,15 @@ "version": "1.0.0-beta.27", "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.27.tgz", "integrity": "sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA==", - "dev": true, "license": "MIT" }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.55.1.tgz", - "integrity": "sha512-9R0DM/ykwfGIlNu6+2U09ga0WXeZ9MRC2Ter8jnz8415VbuIykVuc6bhdrbORFZANDmTDvq26mJrEVTl8TdnDg==", + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.57.1.tgz", + "integrity": "sha512-A6ehUVSiSaaliTxai040ZpZ2zTevHYbvu/lDoeAteHI8QnaosIzm4qwtezfRg1jOYaUmnzLX1AOD6Z+UJjtifg==", "cpu": [ "arm" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2580,13 +2598,12 @@ ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.55.1.tgz", - "integrity": "sha512-eFZCb1YUqhTysgW3sj/55du5cG57S7UTNtdMjCW7LwVcj3dTTcowCsC8p7uBdzKsZYa8J7IDE8lhMI+HX1vQvg==", + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.57.1.tgz", + "integrity": "sha512-dQaAddCY9YgkFHZcFNS/606Exo8vcLHwArFZ7vxXq4rigo2bb494/xKMMwRRQW6ug7Js6yXmBZhSBRuBvCCQ3w==", "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2594,13 +2611,12 @@ ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.55.1.tgz", - "integrity": "sha512-p3grE2PHcQm2e8PSGZdzIhCKbMCw/xi9XvMPErPhwO17vxtvCN5FEA2mSLgmKlCjHGMQTP6phuQTYWUnKewwGg==", + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.57.1.tgz", + "integrity": "sha512-crNPrwJOrRxagUYeMn/DZwqN88SDmwaJ8Cvi/TN1HnWBU7GwknckyosC2gd0IqYRsHDEnXf328o9/HC6OkPgOg==", "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2608,13 +2624,12 @@ ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.55.1.tgz", - "integrity": "sha512-rDUjG25C9qoTm+e02Esi+aqTKSBYwVTaoS1wxcN47/Luqef57Vgp96xNANwt5npq9GDxsH7kXxNkJVEsWEOEaQ==", + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.57.1.tgz", + "integrity": "sha512-Ji8g8ChVbKrhFtig5QBV7iMaJrGtpHelkB3lsaKzadFBe58gmjfGXAOfI5FV0lYMH8wiqsxKQ1C9B0YTRXVy4w==", "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2622,13 +2637,12 @@ ] }, "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.55.1.tgz", - "integrity": "sha512-+JiU7Jbp5cdxekIgdte0jfcu5oqw4GCKr6i3PJTlXTCU5H5Fvtkpbs4XJHRmWNXF+hKmn4v7ogI5OQPaupJgOg==", + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.57.1.tgz", + "integrity": "sha512-R+/WwhsjmwodAcz65guCGFRkMb4gKWTcIeLy60JJQbXrJ97BOXHxnkPFrP+YwFlaS0m+uWJTstrUA9o+UchFug==", "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2636,13 +2650,12 @@ ] }, "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.55.1.tgz", - "integrity": "sha512-V5xC1tOVWtLLmr3YUk2f6EJK4qksksOYiz/TCsFHu/R+woubcLWdC9nZQmwjOAbmExBIVKsm1/wKmEy4z4u4Bw==", + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.57.1.tgz", + "integrity": "sha512-IEQTCHeiTOnAUC3IDQdzRAGj3jOAYNr9kBguI7MQAAZK3caezRrg0GxAb6Hchg4lxdZEI5Oq3iov/w/hnFWY9Q==", "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2650,13 +2663,12 @@ ] }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.55.1.tgz", - "integrity": "sha512-Rn3n+FUk2J5VWx+ywrG/HGPTD9jXNbicRtTM11e/uorplArnXZYsVifnPPqNNP5BsO3roI4n8332ukpY/zN7rQ==", + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.57.1.tgz", + "integrity": "sha512-F8sWbhZ7tyuEfsmOxwc2giKDQzN3+kuBLPwwZGyVkLlKGdV1nvnNwYD0fKQ8+XS6hp9nY7B+ZeK01EBUE7aHaw==", "cpu": [ "arm" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2664,13 +2676,12 @@ ] }, "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.55.1.tgz", - "integrity": "sha512-grPNWydeKtc1aEdrJDWk4opD7nFtQbMmV7769hiAaYyUKCT1faPRm2av8CX1YJsZ4TLAZcg9gTR1KvEzoLjXkg==", + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.57.1.tgz", + "integrity": "sha512-rGfNUfn0GIeXtBP1wL5MnzSj98+PZe/AXaGBCRmT0ts80lU5CATYGxXukeTX39XBKsxzFpEeK+Mrp9faXOlmrw==", "cpu": [ "arm" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2678,13 +2689,12 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.55.1.tgz", - "integrity": "sha512-a59mwd1k6x8tXKcUxSyISiquLwB5pX+fJW9TkWU46lCqD/GRDe9uDN31jrMmVP3feI3mhAdvcCClhV8V5MhJFQ==", + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.57.1.tgz", + "integrity": "sha512-MMtej3YHWeg/0klK2Qodf3yrNzz6CGjo2UntLvk2RSPlhzgLvYEB3frRvbEF2wRKh1Z2fDIg9KRPe1fawv7C+g==", "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2692,13 +2702,12 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.55.1.tgz", - "integrity": "sha512-puS1MEgWX5GsHSoiAsF0TYrpomdvkaXm0CofIMG5uVkP6IBV+ZO9xhC5YEN49nsgYo1DuuMquF9+7EDBVYu4uA==", + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.57.1.tgz", + "integrity": "sha512-1a/qhaaOXhqXGpMFMET9VqwZakkljWHLmZOX48R0I/YLbhdxr1m4gtG1Hq7++VhVUmf+L3sTAf9op4JlhQ5u1Q==", "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2706,13 +2715,12 @@ ] }, "node_modules/@rollup/rollup-linux-loong64-gnu": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.55.1.tgz", - "integrity": "sha512-r3Wv40in+lTsULSb6nnoudVbARdOwb2u5fpeoOAZjFLznp6tDU8kd+GTHmJoqZ9lt6/Sys33KdIHUaQihFcu7g==", + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.57.1.tgz", + "integrity": "sha512-QWO6RQTZ/cqYtJMtxhkRkidoNGXc7ERPbZN7dVW5SdURuLeVU7lwKMpo18XdcmpWYd0qsP1bwKPf7DNSUinhvA==", "cpu": [ "loong64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2720,13 +2728,12 @@ ] }, "node_modules/@rollup/rollup-linux-loong64-musl": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.55.1.tgz", - "integrity": "sha512-MR8c0+UxAlB22Fq4R+aQSPBayvYa3+9DrwG/i1TKQXFYEaoW3B5b/rkSRIypcZDdWjWnpcvxbNaAJDcSbJU3Lw==", + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.57.1.tgz", + "integrity": "sha512-xpObYIf+8gprgWaPP32xiN5RVTi/s5FCR+XMXSKmhfoJjrpRAjCuuqQXyxUa/eJTdAE6eJ+KDKaoEqjZQxh3Gw==", "cpu": [ "loong64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2734,13 +2741,12 @@ ] }, "node_modules/@rollup/rollup-linux-ppc64-gnu": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.55.1.tgz", - "integrity": "sha512-3KhoECe1BRlSYpMTeVrD4sh2Pw2xgt4jzNSZIIPLFEsnQn9gAnZagW9+VqDqAHgm1Xc77LzJOo2LdigS5qZ+gw==", + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.57.1.tgz", + "integrity": "sha512-4BrCgrpZo4hvzMDKRqEaW1zeecScDCR+2nZ86ATLhAoJ5FQ+lbHVD3ttKe74/c7tNT9c6F2viwB3ufwp01Oh2w==", "cpu": [ "ppc64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2748,13 +2754,12 @@ ] }, "node_modules/@rollup/rollup-linux-ppc64-musl": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.55.1.tgz", - "integrity": "sha512-ziR1OuZx0vdYZZ30vueNZTg73alF59DicYrPViG0NEgDVN8/Jl87zkAPu4u6VjZST2llgEUjaiNl9JM6HH1Vdw==", + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.57.1.tgz", + "integrity": "sha512-NOlUuzesGauESAyEYFSe3QTUguL+lvrN1HtwEEsU2rOwdUDeTMJdO5dUYl/2hKf9jWydJrO9OL/XSSf65R5+Xw==", "cpu": [ "ppc64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2762,13 +2767,12 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.55.1.tgz", - "integrity": "sha512-uW0Y12ih2XJRERZ4jAfKamTyIHVMPQnTZcQjme2HMVDAHY4amf5u414OqNYC+x+LzRdRcnIG1YodLrrtA8xsxw==", + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.57.1.tgz", + "integrity": "sha512-ptA88htVp0AwUUqhVghwDIKlvJMD/fmL/wrQj99PRHFRAG6Z5nbWoWG4o81Nt9FT+IuqUQi+L31ZKAFeJ5Is+A==", "cpu": [ "riscv64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2776,13 +2780,12 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-musl": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.55.1.tgz", - "integrity": "sha512-u9yZ0jUkOED1BFrqu3BwMQoixvGHGZ+JhJNkNKY/hyoEgOwlqKb62qu+7UjbPSHYjiVy8kKJHvXKv5coH4wDeg==", + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.57.1.tgz", + "integrity": "sha512-S51t7aMMTNdmAMPpBg7OOsTdn4tySRQvklmL3RpDRyknk87+Sp3xaumlatU+ppQ+5raY7sSTcC2beGgvhENfuw==", "cpu": [ "riscv64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2790,13 +2793,12 @@ ] }, "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.55.1.tgz", - "integrity": "sha512-/0PenBCmqM4ZUd0190j7J0UsQ/1nsi735iPRakO8iPciE7BQ495Y6msPzaOmvx0/pn+eJVVlZrNrSh4WSYLxNg==", + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.57.1.tgz", + "integrity": "sha512-Bl00OFnVFkL82FHbEqy3k5CUCKH6OEJL54KCyx2oqsmZnFTR8IoNqBF+mjQVcRCT5sB6yOvK8A37LNm/kPJiZg==", "cpu": [ "s390x" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2804,13 +2806,12 @@ ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.55.1.tgz", - "integrity": "sha512-a8G4wiQxQG2BAvo+gU6XrReRRqj+pLS2NGXKm8io19goR+K8lw269eTrPkSdDTALwMmJp4th2Uh0D8J9bEV1vg==", + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.57.1.tgz", + "integrity": "sha512-ABca4ceT4N+Tv/GtotnWAeXZUZuM/9AQyCyKYyKnpk4yoA7QIAuBt6Hkgpw8kActYlew2mvckXkvx0FfoInnLg==", "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2818,13 +2819,12 @@ ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.55.1.tgz", - "integrity": "sha512-bD+zjpFrMpP/hqkfEcnjXWHMw5BIghGisOKPj+2NaNDuVT+8Ds4mPf3XcPHuat1tz89WRL+1wbcxKY3WSbiT7w==", + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.57.1.tgz", + "integrity": "sha512-HFps0JeGtuOR2convgRRkHCekD7j+gdAuXM+/i6kGzQtFhlCtQkpwtNzkNj6QhCDp7DRJ7+qC/1Vg2jt5iSOFw==", "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2832,13 +2832,12 @@ ] }, "node_modules/@rollup/rollup-openbsd-x64": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.55.1.tgz", - "integrity": "sha512-eLXw0dOiqE4QmvikfQ6yjgkg/xDM+MdU9YJuP4ySTibXU0oAvnEWXt7UDJmD4UkYialMfOGFPJnIHSe/kdzPxg==", + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.57.1.tgz", + "integrity": "sha512-H+hXEv9gdVQuDTgnqD+SQffoWoc0Of59AStSzTEj/feWTBAnSfSD3+Dql1ZruJQxmykT/JVY0dE8Ka7z0DH1hw==", "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2846,13 +2845,12 @@ ] }, "node_modules/@rollup/rollup-openharmony-arm64": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.55.1.tgz", - "integrity": "sha512-xzm44KgEP11te3S2HCSyYf5zIzWmx3n8HDCc7EE59+lTcswEWNpvMLfd9uJvVX8LCg9QWG67Xt75AuHn4vgsXw==", + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.57.1.tgz", + "integrity": "sha512-4wYoDpNg6o/oPximyc/NG+mYUejZrCU2q+2w6YZqrAs2UcNUChIZXjtafAiiZSUc7On8v5NyNj34Kzj/Ltk6dQ==", "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2860,13 +2858,12 @@ ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.55.1.tgz", - "integrity": "sha512-yR6Bl3tMC/gBok5cz/Qi0xYnVbIxGx5Fcf/ca0eB6/6JwOY+SRUcJfI0OpeTpPls7f194as62thCt/2BjxYN8g==", + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.57.1.tgz", + "integrity": "sha512-O54mtsV/6LW3P8qdTcamQmuC990HDfR71lo44oZMZlXU4tzLrbvTii87Ni9opq60ds0YzuAlEr/GNwuNluZyMQ==", "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2874,13 +2871,12 @@ ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.55.1.tgz", - "integrity": "sha512-3fZBidchE0eY0oFZBnekYCfg+5wAB0mbpCBuofh5mZuzIU/4jIVkbESmd2dOsFNS78b53CYv3OAtwqkZZmU5nA==", + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.57.1.tgz", + "integrity": "sha512-P3dLS+IerxCT/7D2q2FYcRdWRl22dNbrbBEtxdWhXrfIMPP9lQhb5h4Du04mdl5Woq05jVCDPCMF7Ub0NAjIew==", "cpu": [ "ia32" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2888,13 +2884,12 @@ ] }, "node_modules/@rollup/rollup-win32-x64-gnu": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.55.1.tgz", - "integrity": "sha512-xGGY5pXj69IxKb4yv/POoocPy/qmEGhimy/FoTpTSVju3FYXUQQMFCaZZXJVidsmGxRioZAwpThl/4zX41gRKg==", + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.57.1.tgz", + "integrity": "sha512-VMBH2eOOaKGtIJYleXsi2B8CPVADrh+TyNxJ4mWPnKfLB/DBUmzW+5m1xUrcwWoMfSLagIRpjUFeW5CO5hyciQ==", "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2902,24 +2897,29 @@ ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.55.1.tgz", - "integrity": "sha512-SPEpaL6DX4rmcXtnhdrQYgzQ5W2uW3SCJch88lB2zImhJRhIIK44fkUrgIV/Q8yUNfw5oyZ5vkeQsZLhCb06lw==", + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.57.1.tgz", + "integrity": "sha512-mxRFDdHIWRxg3UfIIAwCm6NzvxG0jDX/wBN6KsQFTvKFqqg9vTrWUE68qEjHt19A5wwx5X5aUi2zuZT7YR0jrA==", "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "win32" ] }, + "node_modules/@rtsao/scc": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@rtsao/scc/-/scc-1.1.0.tgz", + "integrity": "sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==", + "dev": true, + "license": "MIT" + }, "node_modules/@sindresorhus/is": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz", "integrity": "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==", - "dev": true, "license": "MIT", "engines": { "node": ">=10" @@ -2932,7 +2932,6 @@ "version": "4.0.6", "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.6.tgz", "integrity": "sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==", - "dev": true, "license": "MIT", "dependencies": { "defer-to-connect": "^2.0.0" @@ -2941,11 +2940,21 @@ "node": ">=10" } }, + "node_modules/@tybys/wasm-util": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.1.tgz", + "integrity": "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, "node_modules/@types/babel__core": { "version": "7.20.5", "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", - "dev": true, "license": "MIT", "dependencies": { "@babel/parser": "^7.20.7", @@ -2959,7 +2968,6 @@ "version": "7.27.0", "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz", "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==", - "dev": true, "license": "MIT", "dependencies": { "@babel/types": "^7.0.0" @@ -2969,7 +2977,6 @@ "version": "7.4.4", "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", - "dev": true, "license": "MIT", "dependencies": { "@babel/parser": "^7.1.0", @@ -2980,7 +2987,6 @@ "version": "7.28.0", "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz", "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==", - "dev": true, "license": "MIT", "dependencies": { "@babel/types": "^7.28.2" @@ -2990,7 +2996,6 @@ "version": "6.0.3", "resolved": "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.3.tgz", "integrity": "sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw==", - "dev": true, "license": "MIT", "dependencies": { "@types/http-cache-semantics": "*", @@ -3084,10 +3089,9 @@ } }, "node_modules/@types/http-cache-semantics": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.4.tgz", - "integrity": "sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA==", - "dev": true, + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.2.0.tgz", + "integrity": "sha512-L3LgimLHXtGkWikKnsPg0/VFx9OGZaC+eN1u4r+OB1XRqH3meBIAVC2zr1WdMH+RHmnRkqliQAOHNJ/E0j/e0Q==", "license": "MIT" }, "node_modules/@types/js-yaml": { @@ -3103,11 +3107,17 @@ "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", "license": "MIT" }, - "node_modules/@types/keyv": { + "node_modules/@types/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/keyv": { "version": "3.1.4", "resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.4.tgz", "integrity": "sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==", - "dev": true, "license": "MIT", "dependencies": { "@types/node": "*" @@ -3129,9 +3139,9 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "24.10.9", - "resolved": "https://registry.npmjs.org/@types/node/-/node-24.10.9.tgz", - "integrity": "sha512-ne4A0IpG3+2ETuREInjPNhUGis1SFjv1d5asp8MzEAGtOZeTeHVDOYqOgqfhvseqg/iXty2hjBf1zAOb7RNiNw==", + "version": "24.10.10", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.10.10.tgz", + "integrity": "sha512-+0/4J266CBGPUq/ELg7QUHhN25WYjE0wYTPSQJn1xeu8DOlIOPxXxrNGiLmfAWl7HMMgWFWXpt9IDjMWrF5Iow==", "license": "MIT", "dependencies": { "undici-types": "~7.16.0" @@ -3162,9 +3172,9 @@ "license": "MIT" }, "node_modules/@types/react": { - "version": "19.2.8", - "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.8.tgz", - "integrity": "sha512-3MbSL37jEchWZz2p2mjntRZtPt837ij10ApxKfgmXCTuHWagYg7iA5bqPw6C8BMPfwidlvfPI/fxOc42HLhcyg==", + "version": "19.2.10", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.10.tgz", + "integrity": "sha512-WPigyYuGhgZ/cTPRXB2EwUw+XvsRA3GqHlsP4qteqrnnjDrApbS7MxcGr/hke5iUoeB7E/gQtrs9I37zAJ0Vjw==", "license": "MIT", "peer": true, "dependencies": { @@ -3184,7 +3194,6 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.3.tgz", "integrity": "sha512-H/+L+UkTV33uf49PH5pCAUBVPNj2nDBXTN+qS1dOwyyg24l3CcicicCA7ca+HMvJBZcFgl5r8e+RR6elsb4Lyw==", - "dev": true, "license": "MIT", "dependencies": { "@types/node": "*" @@ -3242,24 +3251,524 @@ "version": "2.10.3", "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.3.tgz", "integrity": "sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==", - "dev": true, "license": "MIT", "optional": true, "dependencies": { "@types/node": "*" } }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.54.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.54.0.tgz", + "integrity": "sha512-hAAP5io/7csFStuOmR782YmTthKBJ9ND3WVL60hcOjvtGFb+HJxH4O5huAcmcZ9v9G8P+JETiZ/G1B8MALnWZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.12.2", + "@typescript-eslint/scope-manager": "8.54.0", + "@typescript-eslint/type-utils": "8.54.0", + "@typescript-eslint/utils": "8.54.0", + "@typescript-eslint/visitor-keys": "8.54.0", + "ignore": "^7.0.5", + "natural-compare": "^1.4.0", + "ts-api-utils": "^2.4.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^8.54.0", + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "8.54.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.54.0.tgz", + "integrity": "sha512-BtE0k6cjwjLZoZixN0t5AKP0kSzlGu7FctRXYuPAm//aaiZhmfq1JwdYpYr1brzEspYyFeF+8XF5j2VK6oalrA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/scope-manager": "8.54.0", + "@typescript-eslint/types": "8.54.0", + "@typescript-eslint/typescript-estree": "8.54.0", + "@typescript-eslint/visitor-keys": "8.54.0", + "debug": "^4.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/project-service": { + "version": "8.54.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.54.0.tgz", + "integrity": "sha512-YPf+rvJ1s7MyiWM4uTRhE4DvBXrEV+d8oC3P9Y2eT7S+HBS0clybdMIPnhiATi9vZOYDc7OQ1L/i6ga6NFYK/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/tsconfig-utils": "^8.54.0", + "@typescript-eslint/types": "^8.54.0", + "debug": "^4.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "8.54.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.54.0.tgz", + "integrity": "sha512-27rYVQku26j/PbHYcVfRPonmOlVI6gihHtXFbTdB5sb6qA0wdAQAbyXFVarQ5t4HRojIz64IV90YtsjQSSGlQg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.54.0", + "@typescript-eslint/visitor-keys": "8.54.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/tsconfig-utils": { + "version": "8.54.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.54.0.tgz", + "integrity": "sha512-dRgOyT2hPk/JwxNMZDsIXDgyl9axdJI3ogZ2XWhBPsnZUv+hPesa5iuhdYt2gzwA9t8RE5ytOJ6xB0moV0Ujvw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "8.54.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.54.0.tgz", + "integrity": "sha512-hiLguxJWHjjwL6xMBwD903ciAwd7DmK30Y9Axs/etOkftC3ZNN9K44IuRD/EB08amu+Zw6W37x9RecLkOo3pMA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.54.0", + "@typescript-eslint/typescript-estree": "8.54.0", + "@typescript-eslint/utils": "8.54.0", + "debug": "^4.4.3", + "ts-api-utils": "^2.4.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/types": { + "version": "8.54.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.54.0.tgz", + "integrity": "sha512-PDUI9R1BVjqu7AUDsRBbKMtwmjWcn4J3le+5LpcFgWULN3LvHC5rkc9gCVxbrsrGmO1jfPybN5s6h4Jy+OnkAA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "8.54.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.54.0.tgz", + "integrity": "sha512-BUwcskRaPvTk6fzVWgDPdUndLjB87KYDrN5EYGetnktoeAvPtO4ONHlAZDnj5VFnUANg0Sjm7j4usBlnoVMHwA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/project-service": "8.54.0", + "@typescript-eslint/tsconfig-utils": "8.54.0", + "@typescript-eslint/types": "8.54.0", + "@typescript-eslint/visitor-keys": "8.54.0", + "debug": "^4.4.3", + "minimatch": "^9.0.5", + "semver": "^7.7.3", + "tinyglobby": "^0.2.15", + "ts-api-utils": "^2.4.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "8.54.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.54.0.tgz", + "integrity": "sha512-9Cnda8GS57AQakvRyG0PTejJNlA2xhvyNtEVIMlDWOOeEyBkYWhGPnfrIAnqxLMTSTo6q8g12XVjjev5l1NvMA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.9.1", + "@typescript-eslint/scope-manager": "8.54.0", + "@typescript-eslint/types": "8.54.0", + "@typescript-eslint/typescript-estree": "8.54.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "8.54.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.54.0.tgz", + "integrity": "sha512-VFlhGSl4opC0bprJiItPQ1RfUhGDIBokcPwaFH4yiBCaNPeld/9VeXbiPO1cLyorQi1G1vL+ecBk1x8o1axORA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.54.0", + "eslint-visitor-keys": "^4.2.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, "node_modules/@ungap/structured-clone": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz", "integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==", "license": "ISC" }, + "node_modules/@unrs/resolver-binding-android-arm-eabi": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-android-arm-eabi/-/resolver-binding-android-arm-eabi-1.11.1.tgz", + "integrity": "sha512-ppLRUgHVaGRWUx0R0Ut06Mjo9gBaBkg3v/8AxusGLhsIotbBLuRk51rAzqLC8gq6NyyAojEXglNjzf6R948DNw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@unrs/resolver-binding-android-arm64": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-android-arm64/-/resolver-binding-android-arm64-1.11.1.tgz", + "integrity": "sha512-lCxkVtb4wp1v+EoN+HjIG9cIIzPkX5OtM03pQYkG+U5O/wL53LC4QbIeazgiKqluGeVEeBlZahHalCaBvU1a2g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@unrs/resolver-binding-darwin-arm64": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-arm64/-/resolver-binding-darwin-arm64-1.11.1.tgz", + "integrity": "sha512-gPVA1UjRu1Y/IsB/dQEsp2V1pm44Of6+LWvbLc9SDk1c2KhhDRDBUkQCYVWe6f26uJb3fOK8saWMgtX8IrMk3g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@unrs/resolver-binding-darwin-x64": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-x64/-/resolver-binding-darwin-x64-1.11.1.tgz", + "integrity": "sha512-cFzP7rWKd3lZaCsDze07QX1SC24lO8mPty9vdP+YVa3MGdVgPmFc59317b2ioXtgCMKGiCLxJ4HQs62oz6GfRQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@unrs/resolver-binding-freebsd-x64": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-freebsd-x64/-/resolver-binding-freebsd-x64-1.11.1.tgz", + "integrity": "sha512-fqtGgak3zX4DCB6PFpsH5+Kmt/8CIi4Bry4rb1ho6Av2QHTREM+47y282Uqiu3ZRF5IQioJQ5qWRV6jduA+iGw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@unrs/resolver-binding-linux-arm-gnueabihf": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-gnueabihf/-/resolver-binding-linux-arm-gnueabihf-1.11.1.tgz", + "integrity": "sha512-u92mvlcYtp9MRKmP+ZvMmtPN34+/3lMHlyMj7wXJDeXxuM0Vgzz0+PPJNsro1m3IZPYChIkn944wW8TYgGKFHw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-arm-musleabihf": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-musleabihf/-/resolver-binding-linux-arm-musleabihf-1.11.1.tgz", + "integrity": "sha512-cINaoY2z7LVCrfHkIcmvj7osTOtm6VVT16b5oQdS4beibX2SYBwgYLmqhBjA1t51CarSaBuX5YNsWLjsqfW5Cw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-arm64-gnu": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-gnu/-/resolver-binding-linux-arm64-gnu-1.11.1.tgz", + "integrity": "sha512-34gw7PjDGB9JgePJEmhEqBhWvCiiWCuXsL9hYphDF7crW7UgI05gyBAi6MF58uGcMOiOqSJ2ybEeCvHcq0BCmQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-arm64-musl": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-musl/-/resolver-binding-linux-arm64-musl-1.11.1.tgz", + "integrity": "sha512-RyMIx6Uf53hhOtJDIamSbTskA99sPHS96wxVE/bJtePJJtpdKGXO1wY90oRdXuYOGOTuqjT8ACccMc4K6QmT3w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-ppc64-gnu": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-ppc64-gnu/-/resolver-binding-linux-ppc64-gnu-1.11.1.tgz", + "integrity": "sha512-D8Vae74A4/a+mZH0FbOkFJL9DSK2R6TFPC9M+jCWYia/q2einCubX10pecpDiTmkJVUH+y8K3BZClycD8nCShA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-riscv64-gnu": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-gnu/-/resolver-binding-linux-riscv64-gnu-1.11.1.tgz", + "integrity": "sha512-frxL4OrzOWVVsOc96+V3aqTIQl1O2TjgExV4EKgRY09AJ9leZpEg8Ak9phadbuX0BA4k8U5qtvMSQQGGmaJqcQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-riscv64-musl": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-musl/-/resolver-binding-linux-riscv64-musl-1.11.1.tgz", + "integrity": "sha512-mJ5vuDaIZ+l/acv01sHoXfpnyrNKOk/3aDoEdLO/Xtn9HuZlDD6jKxHlkN8ZhWyLJsRBxfv9GYM2utQ1SChKew==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-s390x-gnu": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-s390x-gnu/-/resolver-binding-linux-s390x-gnu-1.11.1.tgz", + "integrity": "sha512-kELo8ebBVtb9sA7rMe1Cph4QHreByhaZ2QEADd9NzIQsYNQpt9UkM9iqr2lhGr5afh885d/cB5QeTXSbZHTYPg==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-x64-gnu": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-gnu/-/resolver-binding-linux-x64-gnu-1.11.1.tgz", + "integrity": "sha512-C3ZAHugKgovV5YvAMsxhq0gtXuwESUKc5MhEtjBpLoHPLYM+iuwSj3lflFwK3DPm68660rZ7G8BMcwSro7hD5w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-x64-musl": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-musl/-/resolver-binding-linux-x64-musl-1.11.1.tgz", + "integrity": "sha512-rV0YSoyhK2nZ4vEswT/QwqzqQXw5I6CjoaYMOX0TqBlWhojUf8P94mvI7nuJTeaCkkds3QE4+zS8Ko+GdXuZtA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-wasm32-wasi": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-wasm32-wasi/-/resolver-binding-wasm32-wasi-1.11.1.tgz", + "integrity": "sha512-5u4RkfxJm+Ng7IWgkzi3qrFOvLvQYnPBmjmZQ8+szTK/b31fQCnleNl1GgEt7nIsZRIf5PLhPwT0WM+q45x/UQ==", + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@napi-rs/wasm-runtime": "^0.2.11" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@unrs/resolver-binding-win32-arm64-msvc": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-arm64-msvc/-/resolver-binding-win32-arm64-msvc-1.11.1.tgz", + "integrity": "sha512-nRcz5Il4ln0kMhfL8S3hLkxI85BXs3o8EYoattsJNdsX4YUU89iOkVn7g0VHSRxFuVMdM4Q1jEpIId1Ihim/Uw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@unrs/resolver-binding-win32-ia32-msvc": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-ia32-msvc/-/resolver-binding-win32-ia32-msvc-1.11.1.tgz", + "integrity": "sha512-DCEI6t5i1NmAZp6pFonpD5m7i6aFrpofcp4LA2i8IIq60Jyo28hamKBxNrZcyOwVOZkgsRp9O2sXWBWP8MnvIQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@unrs/resolver-binding-win32-x64-msvc": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-x64-msvc/-/resolver-binding-win32-x64-msvc-1.11.1.tgz", + "integrity": "sha512-lrW200hZdbfRtztbygyaq/6jP6AKE8qQN2KvPcJ+x7wiD038YtnYtZ82IMNJ69GJibV7bwL3y9FgK+5w/pYt6g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, "node_modules/@vitejs/plugin-react": { "version": "4.7.0", "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.7.0.tgz", "integrity": "sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA==", - "dev": true, "license": "MIT", "dependencies": { "@babel/core": "^7.28.0", @@ -3577,23 +4086,24 @@ "license": "MIT" }, "node_modules/app-builder-lib": { - "version": "26.4.0", - "resolved": "https://registry.npmjs.org/app-builder-lib/-/app-builder-lib-26.4.0.tgz", - "integrity": "sha512-Uas6hNe99KzP3xPWxh5LGlH8kWIVjZixzmMJHNB9+6hPyDpjc7NQMkVgi16rQDdpCFy22ZU5sp8ow7tvjeMgYQ==", + "version": "26.7.0", + "resolved": "https://registry.npmjs.org/app-builder-lib/-/app-builder-lib-26.7.0.tgz", + "integrity": "sha512-/UgCD8VrO79Wv8aBNpjMfsS1pIUfIPURoRn0Ik6tMe5avdZF+vQgl/juJgipcMmH3YS0BD573lCdCHyoi84USg==", "dev": true, "license": "MIT", "dependencies": { "@develar/schema-utils": "~2.6.5", "@electron/asar": "3.4.1", "@electron/fuses": "^1.8.0", + "@electron/get": "^3.0.0", "@electron/notarize": "2.5.0", "@electron/osx-sign": "1.3.3", - "@electron/rebuild": "4.0.1", + "@electron/rebuild": "^4.0.3", "@electron/universal": "2.0.3", "@malept/flatpak-bundler": "^0.4.0", "@types/fs-extra": "9.0.13", "async-exit-hook": "^2.0.1", - "builder-util": "26.3.4", + "builder-util": "26.4.1", "builder-util-runtime": "9.5.1", "chromium-pickle-js": "^0.2.0", "ci-info": "4.3.1", @@ -3601,7 +4111,7 @@ "dotenv": "^16.4.5", "dotenv-expand": "^11.0.6", "ejs": "^3.1.8", - "electron-publish": "26.3.4", + "electron-publish": "26.6.0", "fs-extra": "^10.1.0", "hosted-git-info": "^4.1.0", "isbinaryfile": "^5.0.0", @@ -3611,9 +4121,10 @@ "lazy-val": "^1.0.5", "minimatch": "^10.0.3", "plist": "3.1.0", + "proper-lockfile": "^4.1.2", "resedit": "^1.7.0", "semver": "~7.7.3", - "tar": "^6.1.12", + "tar": "^7.5.7", "temp-file": "^3.4.0", "tiny-async-pool": "1.3.0", "which": "^5.0.0" @@ -3622,8 +4133,71 @@ "node": ">=14.0.0" }, "peerDependencies": { - "dmg-builder": "26.4.0", - "electron-builder-squirrel-windows": "26.4.0" + "dmg-builder": "26.7.0", + "electron-builder-squirrel-windows": "26.7.0" + } + }, + "node_modules/app-builder-lib/node_modules/@electron/get": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@electron/get/-/get-3.1.0.tgz", + "integrity": "sha512-F+nKc0xW+kVbBRhFzaMgPy3KwmuNTYX1fx6+FxxoSnNgwYX6LD7AKBTWkU0MQ6IBoe7dz069CNkR673sPAgkCQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.1.1", + "env-paths": "^2.2.0", + "fs-extra": "^8.1.0", + "got": "^11.8.5", + "progress": "^2.0.3", + "semver": "^6.2.0", + "sumchecker": "^3.0.1" + }, + "engines": { + "node": ">=14" + }, + "optionalDependencies": { + "global-agent": "^3.0.0" + } + }, + "node_modules/app-builder-lib/node_modules/@electron/get/node_modules/fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "node_modules/app-builder-lib/node_modules/@electron/get/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/app-builder-lib/node_modules/ci-info": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.3.1.tgz", + "integrity": "sha512-Wdy2Igu8OcBpI2pZePZ5oWjPC38tmDVx5WKUXKwlLYkA0ozo85sLsLvkBbBn/sZaSCMFOGZJ14fvW9t5/d7kdA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "license": "MIT", + "engines": { + "node": ">=8" } }, "node_modules/app-builder-lib/node_modules/fs-extra": { @@ -3641,7 +4215,7 @@ "node": ">=12" } }, - "node_modules/app-builder-lib/node_modules/jsonfile": { + "node_modules/app-builder-lib/node_modules/fs-extra/node_modules/jsonfile": { "version": "6.2.0", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.0.tgz", "integrity": "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==", @@ -3654,20 +4228,7 @@ "graceful-fs": "^4.1.6" } }, - "node_modules/app-builder-lib/node_modules/semver": { - "version": "7.7.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", - "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/app-builder-lib/node_modules/universalify": { + "node_modules/app-builder-lib/node_modules/fs-extra/node_modules/universalify": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", @@ -3677,6 +4238,22 @@ "node": ">= 10.0.0" } }, + "node_modules/app-builder-lib/node_modules/minimatch": { + "version": "10.1.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.1.1.tgz", + "integrity": "sha512-enIvLvRAFZYXJzkCYG5RKmPfrFArdLv+R+lbQ53BmIMLIry74bjKzX6iHAm8WYamJkhSSEabrWN5D97XnKObjQ==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/brace-expansion": "^5.0.0" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", @@ -3754,6 +4331,28 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/array.prototype.findlastindex": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.6.tgz", + "integrity": "sha512-F/TKATkzseUExPlfvmwQKGITM3DGTK+vkAsCZoDc5daVygbJBnjEUCbgkAvVFsgfXfX4YIqZ/27G3k3tdXrTxQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.9", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "es-shim-unscopables": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/array.prototype.flat": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.3.tgz", @@ -3869,21 +4468,21 @@ "license": "MIT" }, "node_modules/ast-v8-to-istanbul": { - "version": "0.3.10", - "resolved": "https://registry.npmjs.org/ast-v8-to-istanbul/-/ast-v8-to-istanbul-0.3.10.tgz", - "integrity": "sha512-p4K7vMz2ZSk3wN8l5o3y2bJAoZXT3VuJI5OLTATY/01CYWumWvwkUw0SqDBnNq6IiTO3qDa1eSQDibAV8g7XOQ==", + "version": "0.3.11", + "resolved": "https://registry.npmjs.org/ast-v8-to-istanbul/-/ast-v8-to-istanbul-0.3.11.tgz", + "integrity": "sha512-Qya9fkoofMjCBNVdWINMjB5KZvkYfaO9/anwkWnjxibpWUxo5iHl2sOdP7/uAqaRuUYuoo8rDwnbaaKVFxoUvw==", "dev": true, "license": "MIT", "dependencies": { "@jridgewell/trace-mapping": "^0.3.31", "estree-walker": "^3.0.3", - "js-tokens": "^9.0.1" + "js-tokens": "^10.0.0" } }, "node_modules/ast-v8-to-istanbul/node_modules/js-tokens": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-9.0.1.tgz", - "integrity": "sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==", + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-10.0.0.tgz", + "integrity": "sha512-lM/UBzQmfJRo9ABXbPWemivdCW8V2G8FHaHdypQaIy523snUjog0W71ayWXTjiR+ixeMyVHN2XcpnTd/liPg/Q==", "dev": true, "license": "MIT" }, @@ -4045,10 +4644,9 @@ "license": "MIT" }, "node_modules/baseline-browser-mapping": { - "version": "2.9.14", - "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.9.14.tgz", - "integrity": "sha512-B0xUquLkiGLgHhpPBqvl7GWegWBUNuujQ6kXd/r1U38ElPT6Ok8KZ8e+FpUGEc2ZoRQUzq/aUnaKFc/svWUGSg==", - "dev": true, + "version": "2.9.19", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.9.19.tgz", + "integrity": "sha512-ipDqC8FrAl/76p2SSWKSI+H9tFwm7vYqXQrItCuiVPt26Km0jS+NzSsBWAaBusvSbQcfJG+JitdMm+wZAgTYqg==", "license": "Apache-2.0", "bin": { "baseline-browser-mapping": "dist/cli.js" @@ -4079,26 +4677,23 @@ "resolved": "https://registry.npmjs.org/boolean/-/boolean-3.2.0.tgz", "integrity": "sha512-d0II/GO9uf9lfUHH2BQsjxzRJZBdsjgsBiW4BvhWk/3qoKwQFjIDVN19PfX8F2D/r9PCMTtLWjYVCFrpeYUzsw==", "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.", - "dev": true, "license": "MIT", "optional": true }, "node_modules/brace-expansion": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", "dev": true, "license": "MIT", "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "balanced-match": "^1.0.0" } }, "node_modules/browserslist": { "version": "4.28.1", "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.1.tgz", "integrity": "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==", - "dev": true, "funding": [ { "type": "opencollective", @@ -4156,7 +4751,6 @@ "version": "0.2.13", "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", - "dev": true, "license": "MIT", "engines": { "node": "*" @@ -4179,9 +4773,9 @@ } }, "node_modules/builder-util": { - "version": "26.3.4", - "resolved": "https://registry.npmjs.org/builder-util/-/builder-util-26.3.4.tgz", - "integrity": "sha512-aRn88mYMktHxzdqDMF6Ayj0rKoX+ZogJ75Ck7RrIqbY/ad0HBvnS2xA4uHfzrGr5D2aLL3vU6OBEH4p0KMV2XQ==", + "version": "26.4.1", + "resolved": "https://registry.npmjs.org/builder-util/-/builder-util-26.4.1.tgz", + "integrity": "sha512-FlgH43XZ50w3UtS1RVGDWOz8v9qMXPC7upMtKMtBEnYdt1OVoS61NYhKm/4x+cIaWqJTXua0+VVPI+fSPGXNIw==", "dev": true, "license": "MIT", "dependencies": { @@ -4278,35 +4872,15 @@ "lru-cache": "^10.0.1", "minipass": "^7.0.3", "minipass-collect": "^2.0.1", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.4", - "p-map": "^7.0.2", - "ssri": "^12.0.0", - "tar": "^7.4.3", - "unique-filename": "^4.0.0" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/cacache/node_modules/brace-expansion": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", - "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/cacache/node_modules/chownr": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-3.0.0.tgz", - "integrity": "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==", - "dev": true, - "license": "BlueOak-1.0.0", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "p-map": "^7.0.2", + "ssri": "^12.0.0", + "tar": "^7.4.3", + "unique-filename": "^4.0.0" + }, "engines": { - "node": ">=18" + "node": "^18.17.0 || >=20.5.0" } }, "node_modules/cacache/node_modules/glob": { @@ -4337,54 +4911,10 @@ "dev": true, "license": "ISC" }, - "node_modules/cacache/node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/cacache/node_modules/tar": { - "version": "7.5.2", - "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.2.tgz", - "integrity": "sha512-7NyxrTE4Anh8km8iEy7o0QYPs+0JKBTj5ZaqHg6B39erLg0qYXN3BijtShwbsNSvQ+LN75+KV+C4QR/f6Gwnpg==", - "dev": true, - "license": "BlueOak-1.0.0", - "dependencies": { - "@isaacs/fs-minipass": "^4.0.0", - "chownr": "^3.0.0", - "minipass": "^7.1.2", - "minizlib": "^3.1.0", - "yallist": "^5.0.0" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/cacache/node_modules/yallist": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz", - "integrity": "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==", - "dev": true, - "license": "BlueOak-1.0.0", - "engines": { - "node": ">=18" - } - }, "node_modules/cacheable-lookup": { "version": "5.0.4", "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz", "integrity": "sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==", - "dev": true, "license": "MIT", "engines": { "node": ">=10.6.0" @@ -4394,7 +4924,6 @@ "version": "7.0.4", "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-7.0.4.tgz", "integrity": "sha512-v+p6ongsrp0yTGbJXjgxPow2+DL93DASP4kXCDKb8/bwRtt9OEF3whggkkDkGNzgcWy2XaF4a8nZglC7uElscg==", - "dev": true, "license": "MIT", "dependencies": { "clone-response": "^1.0.2", @@ -4466,10 +4995,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001764", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001764.tgz", - "integrity": "sha512-9JGuzl2M+vPL+pz70gtMF9sHdMFbY9FJaQBi186cHKH3pSzDvzoUJUPV6fqiKIMyXbud9ZLg4F3Yza1vJ1+93g==", - "dev": true, + "version": "1.0.30001767", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001767.tgz", + "integrity": "sha512-34+zUAMhSH+r+9eKmYG+k2Rpt8XttfE4yXAjoZvkAPs15xcYQhyBYdalJ65BzivAvGRMViEjy6oKr/S91loekQ==", "funding": [ { "type": "opencollective", @@ -4581,13 +5109,13 @@ } }, "node_modules/chownr": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", - "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-3.0.0.tgz", + "integrity": "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==", "dev": true, - "license": "ISC", + "license": "BlueOak-1.0.0", "engines": { - "node": ">=10" + "node": ">=18" } }, "node_modules/chromium-pickle-js": { @@ -4598,9 +5126,9 @@ "license": "MIT" }, "node_modules/ci-info": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.3.1.tgz", - "integrity": "sha512-Wdy2Igu8OcBpI2pZePZ5oWjPC38tmDVx5WKUXKwlLYkA0ozo85sLsLvkBbBn/sZaSCMFOGZJ14fvW9t5/d7kdA==", + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.4.0.tgz", + "integrity": "sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg==", "dev": true, "funding": [ { @@ -4691,7 +5219,6 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.3.tgz", "integrity": "sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==", - "dev": true, "license": "MIT", "dependencies": { "mimic-response": "^1.0.0" @@ -4801,18 +5328,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/conf/node_modules/semver": { - "version": "7.7.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", - "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/convert-source-map": { "version": "1.9.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", @@ -5049,9 +5564,9 @@ } }, "node_modules/decode-named-character-reference": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.2.0.tgz", - "integrity": "sha512-c6fcElNV6ShtZXmsgNgFFV5tVX2PaV4g+MOAkb8eXHvn6sryJBrZa9r0zV6+dtTyoCKxtDy5tyQ5ZwQuidtd+Q==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.3.0.tgz", + "integrity": "sha512-GtpQYB283KrPp6nRw50q3U9/VfOutZOe103qlN7BPP6Ad27xYnOIWv4lPzo8HCAL+mMZofJ9KEy30fq6MfaK6Q==", "license": "MIT", "dependencies": { "character-entities": "^2.0.0" @@ -5122,7 +5637,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz", "integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==", - "dev": true, "license": "MIT", "engines": { "node": ">=10" @@ -5149,7 +5663,7 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "define-data-property": "^1.0.1", @@ -5196,7 +5710,6 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==", - "dev": true, "license": "MIT", "optional": true }, @@ -5230,6 +5743,17 @@ "p-limit": "^3.1.0 " } }, + "node_modules/dir-compare/node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, "node_modules/dir-compare/node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -5244,14 +5768,14 @@ } }, "node_modules/dmg-builder": { - "version": "26.4.0", - "resolved": "https://registry.npmjs.org/dmg-builder/-/dmg-builder-26.4.0.tgz", - "integrity": "sha512-ce4Ogns4VMeisIuCSK0C62umG0lFy012jd8LMZ6w/veHUeX4fqfDrGe+HTWALAEwK6JwKP+dhPvizhArSOsFbg==", + "version": "26.7.0", + "resolved": "https://registry.npmjs.org/dmg-builder/-/dmg-builder-26.7.0.tgz", + "integrity": "sha512-uOOBA3f+kW3o4KpSoMQ6SNpdXU7WtxlJRb9vCZgOvqhTz4b3GjcoWKstdisizNZLsylhTMv8TLHFPFW0Uxsj/g==", "dev": true, "license": "MIT", "dependencies": { - "app-builder-lib": "26.4.0", - "builder-util": "26.3.4", + "app-builder-lib": "26.7.0", + "builder-util": "26.4.1", "fs-extra": "^10.1.0", "iconv-lite": "^0.6.2", "js-yaml": "^4.1.0" @@ -5501,7 +6025,6 @@ "version": "37.10.3", "resolved": "https://registry.npmjs.org/electron/-/electron-37.10.3.tgz", "integrity": "sha512-3IjCGSjQmH50IbW2PFveaTzK+KwcFX9PEhE7KXb9v5IT8cLAiryAN7qezm/XzODhDRlLu0xKG1j8xWBtZ/bx/g==", - "dev": true, "hasInstallScript": true, "license": "MIT", "dependencies": { @@ -5517,18 +6040,18 @@ } }, "node_modules/electron-builder": { - "version": "26.4.0", - "resolved": "https://registry.npmjs.org/electron-builder/-/electron-builder-26.4.0.tgz", - "integrity": "sha512-FCUqvdq2AULL+Db2SUGgjOYTbrgkPxZtCjqIZGnjH9p29pTWyesQqBIfvQBKa6ewqde87aWl49n/WyI/NyUBog==", + "version": "26.7.0", + "resolved": "https://registry.npmjs.org/electron-builder/-/electron-builder-26.7.0.tgz", + "integrity": "sha512-LoXbCvSFxLesPneQ/fM7FB4OheIDA2tjqCdUkKlObV5ZKGhYgi5VHPHO/6UUOUodAlg7SrkPx7BZJPby+Vrtbg==", "dev": true, "license": "MIT", "dependencies": { - "app-builder-lib": "26.4.0", - "builder-util": "26.3.4", + "app-builder-lib": "26.7.0", + "builder-util": "26.4.1", "builder-util-runtime": "9.5.1", "chalk": "^4.1.2", "ci-info": "^4.2.0", - "dmg-builder": "26.4.0", + "dmg-builder": "26.7.0", "fs-extra": "^10.1.0", "lazy-val": "^1.0.5", "simple-update-notifier": "2.0.0", @@ -5543,15 +6066,15 @@ } }, "node_modules/electron-builder-squirrel-windows": { - "version": "26.4.0", - "resolved": "https://registry.npmjs.org/electron-builder-squirrel-windows/-/electron-builder-squirrel-windows-26.4.0.tgz", - "integrity": "sha512-7dvalY38xBzWNaoOJ4sqy2aGIEpl2S1gLPkkB0MHu1Hu5xKQ82il1mKSFlXs6fLpXUso/NmyjdHGlSHDRoG8/w==", + "version": "26.7.0", + "resolved": "https://registry.npmjs.org/electron-builder-squirrel-windows/-/electron-builder-squirrel-windows-26.7.0.tgz", + "integrity": "sha512-3EqkQK+q0kGshdPSKEPb2p5F75TENMKu6Fe5aTdeaPfdzFK4Yjp5L0d6S7K8iyvqIsGQ/ei4bnpyX9wt+kVCKQ==", "dev": true, "license": "MIT", "peer": true, "dependencies": { - "app-builder-lib": "26.4.0", - "builder-util": "26.3.4", + "app-builder-lib": "26.7.0", + "builder-util": "26.4.1", "electron-winstaller": "5.4.0" } }, @@ -5594,17 +6117,17 @@ } }, "node_modules/electron-publish": { - "version": "26.3.4", - "resolved": "https://registry.npmjs.org/electron-publish/-/electron-publish-26.3.4.tgz", - "integrity": "sha512-5/ouDPb73SkKuay2EXisPG60LTFTMNHWo2WLrK5GDphnWK9UC+yzYrzVeydj078Yk4WUXi0+TaaZsNd6Zt5k/A==", + "version": "26.6.0", + "resolved": "https://registry.npmjs.org/electron-publish/-/electron-publish-26.6.0.tgz", + "integrity": "sha512-LsyHMMqbvJ2vsOvuWJ19OezgF2ANdCiHpIucDHNiLhuI+/F3eW98ouzWSRmXXi82ZOPZXC07jnIravY4YYwCLQ==", "dev": true, "license": "MIT", "dependencies": { "@types/fs-extra": "^9.0.11", - "builder-util": "26.3.4", + "builder-util": "26.4.1", "builder-util-runtime": "9.5.1", "chalk": "^4.1.2", - "form-data": "^4.0.0", + "form-data": "^4.0.5", "fs-extra": "^10.1.0", "lazy-val": "^1.0.5", "mime": "^2.5.2" @@ -5662,10 +6185,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.5.267", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.267.tgz", - "integrity": "sha512-0Drusm6MVRXSOJpGbaSVgcQsuB4hEkMpHXaVstcPmhu5LIedxs1xNK/nIxmQIU/RPC0+1/o0AVZfBTkTNJOdUw==", - "dev": true, + "version": "1.5.286", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.286.tgz", + "integrity": "sha512-9tfDXhJ4RKFNerfjdCcZfufu49vg620741MNs26a9+bhLThdB+plgMeou98CAaHu/WATj2iHOOHTp1hWtABj2A==", "license": "ISC" }, "node_modules/electron-winstaller": { @@ -5707,10 +6229,9 @@ } }, "node_modules/electron/node_modules/@types/node": { - "version": "22.19.7", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.19.7.tgz", - "integrity": "sha512-MciR4AKGHWl7xwxkBa6xUGxQJ4VBOmPTF7sL+iGzuahOFaO0jHCsuEfS80pan1ef4gWId1oWOweIhrDEYLuaOw==", - "dev": true, + "version": "22.19.8", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.19.8.tgz", + "integrity": "sha512-ebO/Yl+EAvVe8DnMfi+iaAyIqYdK0q/q0y0rw82INWEKJOBe6b/P3YWE8NW7oOlF/nXFNrHwhARrN/hdgDkraA==", "license": "MIT", "dependencies": { "undici-types": "~6.21.0" @@ -5720,7 +6241,6 @@ "version": "6.21.0", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", - "dev": true, "license": "MIT" }, "node_modules/emoji-regex": { @@ -5969,7 +6489,6 @@ "version": "4.1.1", "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz", "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==", - "dev": true, "license": "MIT", "optional": true }, @@ -5977,7 +6496,6 @@ "version": "0.27.2", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.2.tgz", "integrity": "sha512-HyNQImnsOC7X9PMNaCIeAm4ISCQXs5a5YasTXVliKv4uuBo1dKrG0A+uQS8M5eXjVMnLg3WgXaKvprHlFJQffw==", - "dev": true, "hasInstallScript": true, "license": "MIT", "bin": { @@ -6112,6 +6630,194 @@ "eslint": ">=7.0.0" } }, + "node_modules/eslint-import-context": { + "version": "0.1.9", + "resolved": "https://registry.npmjs.org/eslint-import-context/-/eslint-import-context-0.1.9.tgz", + "integrity": "sha512-K9Hb+yRaGAGUbwjhFNHvSmmkZs9+zbuoe3kFQ4V1wYjrepUFYM2dZAfNtjbbj3qsPfUfsA68Bx/ICWQMi+C8Eg==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-tsconfig": "^4.10.1", + "stable-hash-x": "^0.2.0" + }, + "engines": { + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint-import-context" + }, + "peerDependencies": { + "unrs-resolver": "^1.0.0" + }, + "peerDependenciesMeta": { + "unrs-resolver": { + "optional": true + } + } + }, + "node_modules/eslint-import-resolver-node": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz", + "integrity": "sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^3.2.7", + "is-core-module": "^2.13.0", + "resolve": "^1.22.4" + } + }, + "node_modules/eslint-import-resolver-node/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-import-resolver-typescript": { + "version": "4.4.4", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-4.4.4.tgz", + "integrity": "sha512-1iM2zeBvrYmUNTj2vSC/90JTHDth+dfOfiNKkxApWRsTJYNrc8rOdxxIf5vazX+BiAXTeOT0UvWpGI/7qIWQOw==", + "dev": true, + "license": "ISC", + "dependencies": { + "debug": "^4.4.1", + "eslint-import-context": "^0.1.8", + "get-tsconfig": "^4.10.1", + "is-bun-module": "^2.0.0", + "stable-hash-x": "^0.2.0", + "tinyglobby": "^0.2.14", + "unrs-resolver": "^1.7.11" + }, + "engines": { + "node": "^16.17.0 || >=18.6.0" + }, + "funding": { + "url": "https://opencollective.com/eslint-import-resolver-typescript" + }, + "peerDependencies": { + "eslint": "*", + "eslint-plugin-import": "*", + "eslint-plugin-import-x": "*" + }, + "peerDependenciesMeta": { + "eslint-plugin-import": { + "optional": true + }, + "eslint-plugin-import-x": { + "optional": true + } + } + }, + "node_modules/eslint-module-utils": { + "version": "2.12.1", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.12.1.tgz", + "integrity": "sha512-L8jSWTze7K2mTg0vos/RuLRS5soomksDPoJLXIslC7c8Wmut3bx7CPpJijDcBZtxQ5lrbUdM+s0OlNbz0DCDNw==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^3.2.7" + }, + "engines": { + "node": ">=4" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + } + } + }, + "node_modules/eslint-module-utils/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-plugin-import": { + "version": "2.32.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.32.0.tgz", + "integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rtsao/scc": "^1.1.0", + "array-includes": "^3.1.9", + "array.prototype.findlastindex": "^1.2.6", + "array.prototype.flat": "^1.3.3", + "array.prototype.flatmap": "^1.3.3", + "debug": "^3.2.7", + "doctrine": "^2.1.0", + "eslint-import-resolver-node": "^0.3.9", + "eslint-module-utils": "^2.12.1", + "hasown": "^2.0.2", + "is-core-module": "^2.16.1", + "is-glob": "^4.0.3", + "minimatch": "^3.1.2", + "object.fromentries": "^2.0.8", + "object.groupby": "^1.0.3", + "object.values": "^1.2.1", + "semver": "^6.3.1", + "string.prototype.trimend": "^1.0.9", + "tsconfig-paths": "^3.15.0" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9" + } + }, + "node_modules/eslint-plugin-import/node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/eslint-plugin-import/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-plugin-import/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/eslint-plugin-import/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, "node_modules/eslint-plugin-jsx-a11y": { "version": "6.10.2", "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.10.2.tgz", @@ -6142,6 +6848,17 @@ "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9" } }, + "node_modules/eslint-plugin-jsx-a11y/node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, "node_modules/eslint-plugin-jsx-a11y/node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -6201,6 +6918,17 @@ "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0" } }, + "node_modules/eslint-plugin-react/node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, "node_modules/eslint-plugin-react/node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -6232,6 +6960,32 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/eslint-plugin-react/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/eslint-plugin-unused-imports": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-unused-imports/-/eslint-plugin-unused-imports-4.3.0.tgz", + "integrity": "sha512-ZFBmXMGBYfHttdRtOG9nFFpmUvMtbHSjsKrS20vdWdbfiVYsO3yA2SGYy9i9XmZJDfMGBflZGBCm70SEnFQtOA==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@typescript-eslint/eslint-plugin": "^8.0.0-0 || ^7.0.0 || ^6.0.0 || ^5.0.0", + "eslint": "^9.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "@typescript-eslint/eslint-plugin": { + "optional": true + } + } + }, "node_modules/eslint-scope": { "version": "8.4.0", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz", @@ -6250,13 +7004,13 @@ } }, "node_modules/eslint-visitor-keys": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", - "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", "dev": true, "license": "Apache-2.0", "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { "url": "https://opencollective.com/eslint" @@ -6279,6 +7033,40 @@ "url": "https://github.com/sponsors/epoberezkin" } }, + "node_modules/eslint/node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/eslint/node_modules/eslint-visitor-keys": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, "node_modules/eslint/node_modules/json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", @@ -6317,6 +7105,19 @@ "url": "https://opencollective.com/eslint" } }, + "node_modules/espree/node_modules/eslint-visitor-keys": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, "node_modules/esquery": { "version": "1.7.0", "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz", @@ -6428,7 +7229,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz", "integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==", - "dev": true, "license": "BSD-2-Clause", "dependencies": { "debug": "^4.1.1", @@ -6496,7 +7296,6 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", - "dev": true, "license": "MIT", "dependencies": { "pend": "~1.2.0" @@ -6506,7 +7305,6 @@ "version": "6.5.0", "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", - "dev": true, "license": "MIT", "engines": { "node": ">=12.0.0" @@ -6543,16 +7341,6 @@ "minimatch": "^5.0.1" } }, - "node_modules/filelist/node_modules/brace-expansion": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", - "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, "node_modules/filelist/node_modules/minimatch": { "version": "5.1.6", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", @@ -6682,7 +7470,6 @@ "version": "8.1.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", - "dev": true, "license": "MIT", "dependencies": { "graceful-fs": "^4.2.0", @@ -6717,7 +7504,6 @@ "version": "2.3.2", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "dev": true, "hasInstallScript": true, "license": "MIT", "optional": true, @@ -6782,7 +7568,6 @@ "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -6838,7 +7623,6 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", - "dev": true, "license": "MIT", "dependencies": { "pump": "^3.0.0" @@ -6868,6 +7652,19 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/get-tsconfig": { + "version": "4.13.1", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.13.1.tgz", + "integrity": "sha512-EoY1N2xCn44xU6750Sx7OjOIT59FkmstNc3X6y5xpz7D5cBtZRe/3pSlTkDJgqsOk3WwZPkWfonhhUJfttQo3w==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, "node_modules/glob": { "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", @@ -6903,6 +7700,17 @@ "node": ">=10.13.0" } }, + "node_modules/glob/node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, "node_modules/glob/node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -6920,7 +7728,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/global-agent/-/global-agent-3.0.0.tgz", "integrity": "sha512-PT6XReJ+D07JvGoxQMkT6qji/jVNfX/h364XHZOWeRzy64sSFr+xJ5OX7LI3b4MPQzdL4H8Y8M0xzPpsVMwA8Q==", - "dev": true, "license": "BSD-3-Clause", "optional": true, "dependencies": { @@ -6935,20 +7742,6 @@ "node": ">=10.0" } }, - "node_modules/global-agent/node_modules/semver": { - "version": "7.7.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", - "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", - "dev": true, - "license": "ISC", - "optional": true, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/globals": { "version": "14.0.0", "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", @@ -6966,7 +7759,7 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "define-properties": "^1.2.1", @@ -6995,7 +7788,6 @@ "version": "11.8.6", "resolved": "https://registry.npmjs.org/got/-/got-11.8.6.tgz", "integrity": "sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g==", - "dev": true, "license": "MIT", "dependencies": { "@sindresorhus/is": "^4.0.0", @@ -7021,7 +7813,6 @@ "version": "4.2.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "dev": true, "license": "ISC" }, "node_modules/has-bigints": { @@ -7351,7 +8142,6 @@ "version": "4.2.0", "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.2.0.tgz", "integrity": "sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==", - "dev": true, "license": "BSD-2-Clause" }, "node_modules/http-proxy-agent": { @@ -7372,7 +8162,6 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-1.0.3.tgz", "integrity": "sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==", - "dev": true, "license": "MIT", "dependencies": { "quick-lru": "^5.1.1", @@ -7397,9 +8186,9 @@ } }, "node_modules/i18next": { - "version": "25.7.4", - "resolved": "https://registry.npmjs.org/i18next/-/i18next-25.7.4.tgz", - "integrity": "sha512-hRkpEblXXcXSNbw8mBNq9042OEetgyB/ahc/X17uV/khPwzV+uB8RHceHh3qavyrkPJvmXFKXME2Sy1E0KjAfw==", + "version": "25.8.1", + "resolved": "https://registry.npmjs.org/i18next/-/i18next-25.8.1.tgz", + "integrity": "sha512-nFFxhwcRNggIrkv2hx/xMYVMG7Z8iMUA4ZuH4tgcbZiI0bK1jn3kSDIXNWuQDt1xVAu7mb7Qn82TpH7ZAk/okA==", "funding": [ { "type": "individual", @@ -7497,9 +8286,10 @@ "license": "BSD-3-Clause" }, "node_modules/ignore": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", - "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", + "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", + "dev": true, "license": "MIT", "engines": { "node": ">= 4" @@ -7681,6 +8471,16 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-bun-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-bun-module/-/is-bun-module-2.0.0.tgz", + "integrity": "sha512-gNCGbnnnnFAUGKeZ9PdbyeGYJqewpmc2aKHUEMO5nQPWU9lOmv7jcmQIv+qHD8fXW6W7qfuCwX4rY9LNRjXrkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.7.1" + } + }, "node_modules/is-callable": { "version": "1.2.7", "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", @@ -8092,9 +8892,9 @@ } }, "node_modules/isomorphic-git": { - "version": "1.36.1", - "resolved": "https://registry.npmjs.org/isomorphic-git/-/isomorphic-git-1.36.1.tgz", - "integrity": "sha512-fC8SRT8MwoaXDK8G4z5biPEbqf2WyEJUb2MJ2ftSd39/UIlsnoZxLGux+lae0poLZO4AEcx6aUVOh5bV+P8zFA==", + "version": "1.36.3", + "resolved": "https://registry.npmjs.org/isomorphic-git/-/isomorphic-git-1.36.3.tgz", + "integrity": "sha512-bHF1nQTjL0IfSo13BHDO8oQ6SvYNQduTAdPJdSmrJ5JwZY2fsyjLujEXav5hqPCegSCAnc75ZsBUHqT/NqR7QA==", "license": "MIT", "dependencies": { "async-lock": "^1.4.1", @@ -8140,6 +8940,15 @@ "ieee754": "^1.2.1" } }, + "node_modules/isomorphic-git/node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, "node_modules/isomorphic-git/node_modules/readable-stream": { "version": "4.7.0", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.7.0.tgz", @@ -8266,7 +9075,7 @@ "version": "2.6.1", "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz", "integrity": "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==", - "dev": true, + "devOptional": true, "license": "MIT", "bin": { "jiti": "lib/jiti-cli.mjs" @@ -8306,7 +9115,6 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", - "dev": true, "license": "MIT" }, "node_modules/json-parse-even-better-errors": { @@ -8338,7 +9146,6 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", - "dev": true, "license": "ISC", "optional": true }, @@ -8346,7 +9153,6 @@ "version": "2.2.3", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", - "dev": true, "license": "MIT", "bin": { "json5": "lib/cli.js" @@ -8359,7 +9165,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", - "dev": true, "license": "MIT", "optionalDependencies": { "graceful-fs": "^4.1.6" @@ -8385,7 +9190,6 @@ "version": "4.5.4", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", - "dev": true, "license": "MIT", "dependencies": { "json-buffer": "3.0.1" @@ -8455,9 +9259,9 @@ } }, "node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "version": "4.17.23", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.23.tgz", + "integrity": "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==", "license": "MIT" }, "node_modules/lodash.camelcase": { @@ -8529,7 +9333,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -8539,7 +9342,6 @@ "version": "5.1.1", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "dev": true, "license": "ISC", "dependencies": { "yallist": "^3.0.2" @@ -8583,19 +9385,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/make-dir/node_modules/semver": { - "version": "7.7.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", - "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/make-fetch-happen": { "version": "14.0.3", "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-14.0.3.tgz", @@ -8633,7 +9422,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/matcher/-/matcher-3.0.0.tgz", "integrity": "sha512-OkeDaAZ/bQCxeFAozM55PKcKU0yJMPGifLwV4Qgjitu+5MoAfSQN4lsLJeXZ1b8w0x+/Emda6MZgXS1jvsapng==", - "dev": true, "license": "MIT", "optional": true, "dependencies": { @@ -9586,23 +10374,22 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", - "dev": true, "license": "MIT", "engines": { "node": ">=4" } }, "node_modules/minimatch": { - "version": "10.1.1", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.1.1.tgz", - "integrity": "sha512-enIvLvRAFZYXJzkCYG5RKmPfrFArdLv+R+lbQ53BmIMLIry74bjKzX6iHAm8WYamJkhSSEabrWN5D97XnKObjQ==", + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", "dev": true, - "license": "BlueOak-1.0.0", + "license": "ISC", "dependencies": { - "@isaacs/brace-expansion": "^5.0.0" + "brace-expansion": "^2.0.1" }, "engines": { - "node": "20 || >=22" + "node": ">=16 || 14 >=14.17" }, "funding": { "url": "https://github.com/sponsors/isaacs" @@ -9780,16 +10567,17 @@ } }, "node_modules/mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", "dev": true, "license": "MIT", + "peer": true, + "dependencies": { + "minimist": "^1.2.6" + }, "bin": { "mkdirp": "bin/cmd.js" - }, - "engines": { - "node": ">=10" } }, "node_modules/mkdirp-classic": { @@ -9805,9 +10593,9 @@ "license": "MIT" }, "node_modules/nan": { - "version": "2.24.0", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.24.0.tgz", - "integrity": "sha512-Vpf9qnVW1RaDkoNKFUvfxqAbtI8ncb8OJlqZ9wwpXzWPEsvsB1nvdUi6oYrHIkQ1Y/tMDnr1h4nczS0VB9Xykg==", + "version": "2.25.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.25.0.tgz", + "integrity": "sha512-0M90Ag7Xn5KMLLZ7zliPWP3rT90P6PN+IzVFS0VqmnPktBk3700xUVv8Ikm9EUaUE5SDWdp/BIxdENzVznpm1g==", "license": "MIT", "optional": true }, @@ -9815,7 +10603,6 @@ "version": "3.3.11", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", - "dev": true, "funding": [ { "type": "github", @@ -9830,6 +10617,22 @@ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, + "node_modules/napi-postinstall": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/napi-postinstall/-/napi-postinstall-0.3.4.tgz", + "integrity": "sha512-PHI5f1O0EP5xJ9gQmFGMS6IZcrVvTjpXjz7Na41gTE7eE2hK11lg04CECCYEEjdc17EV4DO+fkGEtt7TpTaTiQ==", + "dev": true, + "license": "MIT", + "bin": { + "napi-postinstall": "lib/cli.js" + }, + "engines": { + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/napi-postinstall" + } + }, "node_modules/natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", @@ -9848,9 +10651,9 @@ } }, "node_modules/node-abi": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-4.24.0.tgz", - "integrity": "sha512-u2EC1CeNe25uVtX3EZbdQ275c74zdZmmpzrHEQh2aIYqoVjlglfUpOX9YY85x1nlBydEKDVaSmMNhR7N82Qj8A==", + "version": "4.26.0", + "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-4.26.0.tgz", + "integrity": "sha512-8QwIZqikRvDIkXS2S93LjzhsSPJuIbfaMETWH+Bx8oOT9Sa9UsUtBFQlc3gBNd1+QINjaTloitXr1W3dQLi9Iw==", "dev": true, "license": "MIT", "dependencies": { @@ -9860,19 +10663,6 @@ "node": ">=22.12.0" } }, - "node_modules/node-abi/node_modules/semver": { - "version": "7.7.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", - "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/node-addon-api": { "version": "1.7.2", "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-1.7.2.tgz", @@ -9890,100 +10680,36 @@ "dependencies": { "semver": "^7.3.5" } - }, - "node_modules/node-api-version/node_modules/semver": { - "version": "7.7.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", - "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/node-gyp": { - "version": "11.5.0", - "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-11.5.0.tgz", - "integrity": "sha512-ra7Kvlhxn5V9Slyus0ygMa2h+UqExPqUIkfk7Pc8QTLT956JLSy51uWFwHtIYy0vI8cB4BDhc/S03+880My/LQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "env-paths": "^2.2.0", - "exponential-backoff": "^3.1.1", - "graceful-fs": "^4.2.6", - "make-fetch-happen": "^14.0.3", - "nopt": "^8.0.0", - "proc-log": "^5.0.0", - "semver": "^7.3.5", - "tar": "^7.4.3", - "tinyglobby": "^0.2.12", - "which": "^5.0.0" - }, - "bin": { - "node-gyp": "bin/node-gyp.js" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/node-gyp/node_modules/chownr": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-3.0.0.tgz", - "integrity": "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==", - "dev": true, - "license": "BlueOak-1.0.0", - "engines": { - "node": ">=18" - } - }, - "node_modules/node-gyp/node_modules/semver": { - "version": "7.7.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", - "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/node-gyp/node_modules/tar": { - "version": "7.5.2", - "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.2.tgz", - "integrity": "sha512-7NyxrTE4Anh8km8iEy7o0QYPs+0JKBTj5ZaqHg6B39erLg0qYXN3BijtShwbsNSvQ+LN75+KV+C4QR/f6Gwnpg==", - "dev": true, - "license": "BlueOak-1.0.0", - "dependencies": { - "@isaacs/fs-minipass": "^4.0.0", - "chownr": "^3.0.0", - "minipass": "^7.1.2", - "minizlib": "^3.1.0", - "yallist": "^5.0.0" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/node-gyp/node_modules/yallist": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz", - "integrity": "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==", + }, + "node_modules/node-gyp": { + "version": "11.5.0", + "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-11.5.0.tgz", + "integrity": "sha512-ra7Kvlhxn5V9Slyus0ygMa2h+UqExPqUIkfk7Pc8QTLT956JLSy51uWFwHtIYy0vI8cB4BDhc/S03+880My/LQ==", "dev": true, - "license": "BlueOak-1.0.0", + "license": "MIT", + "dependencies": { + "env-paths": "^2.2.0", + "exponential-backoff": "^3.1.1", + "graceful-fs": "^4.2.6", + "make-fetch-happen": "^14.0.3", + "nopt": "^8.0.0", + "proc-log": "^5.0.0", + "semver": "^7.3.5", + "tar": "^7.4.3", + "tinyglobby": "^0.2.12", + "which": "^5.0.0" + }, + "bin": { + "node-gyp": "bin/node-gyp.js" + }, "engines": { - "node": ">=18" + "node": "^18.17.0 || >=20.5.0" } }, "node_modules/node-releases": { "version": "2.0.27", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.27.tgz", "integrity": "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==", - "dev": true, "license": "MIT" }, "node_modules/nopt": { @@ -10006,7 +10732,6 @@ "version": "6.1.0", "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz", "integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==", - "dev": true, "license": "MIT", "engines": { "node": ">=10" @@ -10041,7 +10766,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -10103,6 +10828,21 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/object.groupby": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.3.tgz", + "integrity": "sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/object.values": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.1.tgz", @@ -10219,7 +10959,6 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.1.1.tgz", "integrity": "sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -10476,7 +11215,6 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", - "dev": true, "license": "MIT" }, "node_modules/picocolors": { @@ -10489,7 +11227,6 @@ "version": "4.0.3", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", - "dev": true, "license": "MIT", "engines": { "node": ">=12" @@ -10593,13 +11330,13 @@ } }, "node_modules/playwright": { - "version": "1.57.0", - "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.57.0.tgz", - "integrity": "sha512-ilYQj1s8sr2ppEJ2YVadYBN0Mb3mdo9J0wQ+UuDhzYqURwSoW4n1Xs5vs7ORwgDGmyEh33tRMeS8KhdkMoLXQw==", + "version": "1.58.1", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.58.1.tgz", + "integrity": "sha512-+2uTZHxSCcxjvGc5C891LrS1/NlxglGxzrC4seZiVjcYVQfUa87wBL6rTDqzGjuoWNjnBzRqKmF6zRYGMvQUaQ==", "dev": true, "license": "Apache-2.0", "dependencies": { - "playwright-core": "1.57.0" + "playwright-core": "1.58.1" }, "bin": { "playwright": "cli.js" @@ -10612,9 +11349,9 @@ } }, "node_modules/playwright-core": { - "version": "1.57.0", - "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.57.0.tgz", - "integrity": "sha512-agTcKlMw/mjBWOnD6kFZttAAGHgi/Nw0CZ2o6JqWSbMlI219lAFLZZCyqByTsvVAJq5XA5H8cA6PrvBRpBWEuQ==", + "version": "1.58.1", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.58.1.tgz", + "integrity": "sha512-bcWzOaTxcW+VOOGBCQgnaKToLJ65d6AqfLVKEWvexyS3AS6rbXl+xdpYRMGSRBClPvyj44njOWoxjNdL/H9UNg==", "dev": true, "license": "Apache-2.0", "bin": { @@ -10652,7 +11389,6 @@ "version": "8.5.6", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", - "dev": true, "funding": [ { "type": "opencollective", @@ -10718,9 +11454,9 @@ } }, "node_modules/prettier": { - "version": "3.8.0", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.0.tgz", - "integrity": "sha512-yEPsovQfpxYfgWNhCfECjG5AQaO+K3dp6XERmOepyPDVqcJm+bjyCVO3pmU+nAPe0N5dDvekfGezt/EIiRe1TA==", + "version": "3.8.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.1.tgz", + "integrity": "sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==", "dev": true, "license": "MIT", "bin": { @@ -10756,7 +11492,6 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", - "dev": true, "license": "MIT", "engines": { "node": ">=0.4.0" @@ -10793,6 +11528,18 @@ "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", "license": "MIT" }, + "node_modules/proper-lockfile": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/proper-lockfile/-/proper-lockfile-4.1.2.tgz", + "integrity": "sha512-TjNPblN4BwAWMXU8s9AEz4JmQxnD1NNL7bNOY/AKUzyamc379FWASUhc/K1pL2noVb+XmZKLL68cjzLsiOAMaA==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.4", + "retry": "^0.12.0", + "signal-exit": "^3.0.2" + } + }, "node_modules/property-information": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/property-information/-/property-information-7.1.0.tgz", @@ -10851,7 +11598,6 @@ "version": "5.1.1", "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", - "dev": true, "license": "MIT", "engines": { "node": ">=10" @@ -10861,24 +11607,24 @@ } }, "node_modules/react": { - "version": "19.2.3", - "resolved": "https://registry.npmjs.org/react/-/react-19.2.3.tgz", - "integrity": "sha512-Ku/hhYbVjOQnXDZFv2+RibmLFGwFdeeKHFcOTlrt7xplBnya5OGn/hIRDsqDiSUcfORsDC7MPxwork8jBwsIWA==", + "version": "19.2.4", + "resolved": "https://registry.npmjs.org/react/-/react-19.2.4.tgz", + "integrity": "sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==", "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/react-dom": { - "version": "19.2.3", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.3.tgz", - "integrity": "sha512-yELu4WmLPw5Mr/lmeEpox5rw3RETacE++JgHqQzd2dg+YbJuat3jH4ingc+WPZhxaoFzdv9y33G+F7Nl5O0GBg==", + "version": "19.2.4", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.4.tgz", + "integrity": "sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==", "license": "MIT", "dependencies": { "scheduler": "^0.27.0" }, "peerDependencies": { - "react": "^19.2.3" + "react": "^19.2.4" } }, "node_modules/react-i18next": { @@ -10908,9 +11654,9 @@ } }, "node_modules/react-is": { - "version": "19.2.3", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-19.2.3.tgz", - "integrity": "sha512-qJNJfu81ByyabuG7hPFEbXqNcWSU3+eVus+KJs+0ncpGfMyYdvSmxiJxbWR65lYi1I+/0HBcliO029gc4F+PnA==", + "version": "19.2.4", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-19.2.4.tgz", + "integrity": "sha512-W+EWGn2v0ApPKgKKCy/7s7WHXkboGcsrXE+2joLyVxkbyVQfO3MUEaUQDHoSmb8TFFrSKYa9mw64WZHNHSDzYA==", "license": "MIT" }, "node_modules/react-markdown": { @@ -10944,7 +11690,6 @@ "version": "0.17.0", "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.17.0.tgz", "integrity": "sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==", - "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -11225,7 +11970,6 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz", "integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==", - "dev": true, "license": "MIT" }, "node_modules/resolve-from": { @@ -11237,11 +11981,20 @@ "node": ">=4" } }, + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, "node_modules/responselike": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/responselike/-/responselike-2.0.1.tgz", "integrity": "sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw==", - "dev": true, "license": "MIT", "dependencies": { "lowercase-keys": "^2.0.0" @@ -11293,7 +12046,6 @@ "version": "2.15.4", "resolved": "https://registry.npmjs.org/roarr/-/roarr-2.15.4.tgz", "integrity": "sha512-CHhPh+UNHD2GTXNYhPWLnU8ONHdI+5DI+4EYIAOaiD63rHeYlZvyh8P+in5999TTSFgUYuKUAjzRI4mdh/p+2A==", - "dev": true, "license": "BSD-3-Clause", "optional": true, "dependencies": { @@ -11309,10 +12061,9 @@ } }, "node_modules/rollup": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.55.1.tgz", - "integrity": "sha512-wDv/Ht1BNHB4upNbK74s9usvl7hObDnvVzknxqY/E/O3X6rW1U1rV1aENEfJ54eFZDTNo7zv1f5N4edCluH7+A==", - "dev": true, + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.57.1.tgz", + "integrity": "sha512-oQL6lgK3e2QZeQ7gcgIkS2YZPg5slw37hYufJ3edKlfQSGGm8ICoxswK15ntSzF/a8+h7ekRy7k7oWc3BQ7y8A==", "license": "MIT", "dependencies": { "@types/estree": "1.0.8" @@ -11325,31 +12076,31 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.55.1", - "@rollup/rollup-android-arm64": "4.55.1", - "@rollup/rollup-darwin-arm64": "4.55.1", - "@rollup/rollup-darwin-x64": "4.55.1", - "@rollup/rollup-freebsd-arm64": "4.55.1", - "@rollup/rollup-freebsd-x64": "4.55.1", - "@rollup/rollup-linux-arm-gnueabihf": "4.55.1", - "@rollup/rollup-linux-arm-musleabihf": "4.55.1", - "@rollup/rollup-linux-arm64-gnu": "4.55.1", - "@rollup/rollup-linux-arm64-musl": "4.55.1", - "@rollup/rollup-linux-loong64-gnu": "4.55.1", - "@rollup/rollup-linux-loong64-musl": "4.55.1", - "@rollup/rollup-linux-ppc64-gnu": "4.55.1", - "@rollup/rollup-linux-ppc64-musl": "4.55.1", - "@rollup/rollup-linux-riscv64-gnu": "4.55.1", - "@rollup/rollup-linux-riscv64-musl": "4.55.1", - "@rollup/rollup-linux-s390x-gnu": "4.55.1", - "@rollup/rollup-linux-x64-gnu": "4.55.1", - "@rollup/rollup-linux-x64-musl": "4.55.1", - "@rollup/rollup-openbsd-x64": "4.55.1", - "@rollup/rollup-openharmony-arm64": "4.55.1", - "@rollup/rollup-win32-arm64-msvc": "4.55.1", - "@rollup/rollup-win32-ia32-msvc": "4.55.1", - "@rollup/rollup-win32-x64-gnu": "4.55.1", - "@rollup/rollup-win32-x64-msvc": "4.55.1", + "@rollup/rollup-android-arm-eabi": "4.57.1", + "@rollup/rollup-android-arm64": "4.57.1", + "@rollup/rollup-darwin-arm64": "4.57.1", + "@rollup/rollup-darwin-x64": "4.57.1", + "@rollup/rollup-freebsd-arm64": "4.57.1", + "@rollup/rollup-freebsd-x64": "4.57.1", + "@rollup/rollup-linux-arm-gnueabihf": "4.57.1", + "@rollup/rollup-linux-arm-musleabihf": "4.57.1", + "@rollup/rollup-linux-arm64-gnu": "4.57.1", + "@rollup/rollup-linux-arm64-musl": "4.57.1", + "@rollup/rollup-linux-loong64-gnu": "4.57.1", + "@rollup/rollup-linux-loong64-musl": "4.57.1", + "@rollup/rollup-linux-ppc64-gnu": "4.57.1", + "@rollup/rollup-linux-ppc64-musl": "4.57.1", + "@rollup/rollup-linux-riscv64-gnu": "4.57.1", + "@rollup/rollup-linux-riscv64-musl": "4.57.1", + "@rollup/rollup-linux-s390x-gnu": "4.57.1", + "@rollup/rollup-linux-x64-gnu": "4.57.1", + "@rollup/rollup-linux-x64-musl": "4.57.1", + "@rollup/rollup-openbsd-x64": "4.57.1", + "@rollup/rollup-openharmony-arm64": "4.57.1", + "@rollup/rollup-win32-arm64-msvc": "4.57.1", + "@rollup/rollup-win32-ia32-msvc": "4.57.1", + "@rollup/rollup-win32-x64-gnu": "4.57.1", + "@rollup/rollup-win32-x64-msvc": "4.57.1", "fsevents": "~2.3.2" } }, @@ -11461,20 +12212,21 @@ "license": "MIT" }, "node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", "license": "ISC", "bin": { "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" } }, "node_modules/semver-compare": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/semver-compare/-/semver-compare-1.0.0.tgz", "integrity": "sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow==", - "dev": true, "license": "MIT", "optional": true }, @@ -11482,7 +12234,6 @@ "version": "7.0.1", "resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-7.0.1.tgz", "integrity": "sha512-8I8TjW5KMOKsZQTvoxjuSIa7foAwPWGOts+6o7sgjz41/qMD9VQHEDxi6PBvK2l0MXUmqZyNpUK+T2tQaaElvw==", - "dev": true, "license": "MIT", "optional": true, "dependencies": { @@ -11499,7 +12250,6 @@ "version": "0.13.1", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.13.1.tgz", "integrity": "sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==", - "dev": true, "license": "(MIT OR CC0-1.0)", "optional": true, "engines": { @@ -11748,19 +12498,6 @@ "node": ">=10" } }, - "node_modules/simple-update-notifier/node_modules/semver": { - "version": "7.7.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", - "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/slash": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/slash/-/slash-5.1.0.tgz", @@ -11843,7 +12580,6 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", - "dev": true, "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" @@ -11890,7 +12626,6 @@ "version": "1.1.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz", "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==", - "dev": true, "license": "BSD-3-Clause", "optional": true }, @@ -11924,6 +12659,16 @@ "node": "^18.17.0 || >=20.5.0" } }, + "node_modules/stable-hash-x": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/stable-hash-x/-/stable-hash-x-0.2.0.tgz", + "integrity": "sha512-o3yWv49B/o4QZk5ZcsALc6t0+eCelPc44zZsLtCQnZPDwFpDYSWcDnrv2TtMmMbQ7uKo3J0HTURCqckw23czNQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/stackback": { "version": "0.0.2", "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", @@ -12167,6 +12912,16 @@ "node": ">=8" } }, + "node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, "node_modules/strip-json-comments": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", @@ -12228,7 +12983,6 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/sumchecker/-/sumchecker-3.0.1.tgz", "integrity": "sha512-MvjXzkz/BOfyVDkG0oFOtBxHX2u3gKbMHIF/dXblZsgD3BWOFLmHovIpZY7BykJdAjcqRCBi1WYBNdEC9yI7vg==", - "dev": true, "license": "Apache-2.0", "dependencies": { "debug": "^4.1.0" @@ -12263,21 +13017,20 @@ } }, "node_modules/tar": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz", - "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==", + "version": "7.5.7", + "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.7.tgz", + "integrity": "sha512-fov56fJiRuThVFXD6o6/Q354S7pnWMJIVlDBYijsTNx6jKSE4pvrDTs6lUnmGvNyfJwFQQwWy3owKz1ucIhveQ==", "dev": true, - "license": "ISC", + "license": "BlueOak-1.0.0", "dependencies": { - "chownr": "^2.0.0", - "fs-minipass": "^2.0.0", - "minipass": "^5.0.0", - "minizlib": "^2.1.1", - "mkdirp": "^1.0.3", - "yallist": "^4.0.0" + "@isaacs/fs-minipass": "^4.0.0", + "chownr": "^3.0.0", + "minipass": "^7.1.2", + "minizlib": "^3.1.0", + "yallist": "^5.0.0" }, "engines": { - "node": ">=10" + "node": ">=18" } }, "node_modules/tar-fs": { @@ -12314,76 +13067,16 @@ "node": ">=6" } }, - "node_modules/tar/node_modules/fs-minipass": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", - "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", - "dev": true, - "license": "ISC", - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/tar/node_modules/fs-minipass/node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "dev": true, - "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/tar/node_modules/minipass": { + "node_modules/tar/node_modules/yallist": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", - "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=8" - } - }, - "node_modules/tar/node_modules/minizlib": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", - "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", - "dev": true, - "license": "MIT", - "dependencies": { - "minipass": "^3.0.0", - "yallist": "^4.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/tar/node_modules/minizlib/node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz", + "integrity": "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==", "dev": true, - "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, + "license": "BlueOak-1.0.0", "engines": { - "node": ">=8" + "node": ">=18" } }, - "node_modules/tar/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true, - "license": "ISC" - }, "node_modules/temp": { "version": "0.9.4", "resolved": "https://registry.npmjs.org/temp/-/temp-0.9.4.tgz", @@ -12448,20 +13141,6 @@ "node": ">= 10.0.0" } }, - "node_modules/temp/node_modules/mkdirp": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", - "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "minimist": "^1.2.6" - }, - "bin": { - "mkdirp": "bin/cmd.js" - } - }, "node_modules/test-exclude": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-7.0.1.tgz", @@ -12477,16 +13156,6 @@ "node": ">=18" } }, - "node_modules/test-exclude/node_modules/brace-expansion": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", - "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, "node_modules/test-exclude/node_modules/glob": { "version": "10.5.0", "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", @@ -12508,22 +13177,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/test-exclude/node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/tiny-async-pool": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/tiny-async-pool/-/tiny-async-pool-1.3.0.tgz", @@ -12562,7 +13215,6 @@ "version": "0.2.15", "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", - "dev": true, "license": "MIT", "dependencies": { "fdir": "^6.5.0", @@ -12669,6 +13321,53 @@ "utf8-byte-length": "^1.0.1" } }, + "node_modules/ts-api-utils": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.4.0.tgz", + "integrity": "sha512-3TaVTaAv2gTiMB35i3FiGJaRfwb3Pyn/j3m/bfAvGe8FB7CF6u+LMYqYlDh7reQf7UNvoTvdfAqHGmPGOSsPmA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.12" + }, + "peerDependencies": { + "typescript": ">=4.8.4" + } + }, + "node_modules/tsconfig-paths": { + "version": "3.15.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", + "integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/json5": "^0.0.29", + "json5": "^1.0.2", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + } + }, + "node_modules/tsconfig-paths/node_modules/json5": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "dev": true, + "license": "0BSD", + "optional": true + }, "node_modules/tweetnacl": { "version": "0.14.5", "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", @@ -12909,9 +13608,9 @@ } }, "node_modules/unist-util-visit": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-5.0.0.tgz", - "integrity": "sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-5.1.0.tgz", + "integrity": "sha512-m+vIdyeCOpdr/QeQCu2EzxX/ohgS8KbnPDgFni4dQsfSCtpz8UqDyY5GjRru8PDKuYn7Fq19j1CQ+nJSsGKOzg==", "license": "MIT", "dependencies": { "@types/unist": "^3.0.0", @@ -12941,17 +13640,50 @@ "version": "0.1.2", "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", - "dev": true, "license": "MIT", "engines": { "node": ">= 4.0.0" } }, + "node_modules/unrs-resolver": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/unrs-resolver/-/unrs-resolver-1.11.1.tgz", + "integrity": "sha512-bSjt9pjaEBnNiGgc9rUiHGKv5l4/TGzDmYw3RhnkJGtLhbnnA/5qJj7x3dNDCRx/PJxu774LlH8lCOlB4hEfKg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "napi-postinstall": "^0.3.0" + }, + "funding": { + "url": "https://opencollective.com/unrs-resolver" + }, + "optionalDependencies": { + "@unrs/resolver-binding-android-arm-eabi": "1.11.1", + "@unrs/resolver-binding-android-arm64": "1.11.1", + "@unrs/resolver-binding-darwin-arm64": "1.11.1", + "@unrs/resolver-binding-darwin-x64": "1.11.1", + "@unrs/resolver-binding-freebsd-x64": "1.11.1", + "@unrs/resolver-binding-linux-arm-gnueabihf": "1.11.1", + "@unrs/resolver-binding-linux-arm-musleabihf": "1.11.1", + "@unrs/resolver-binding-linux-arm64-gnu": "1.11.1", + "@unrs/resolver-binding-linux-arm64-musl": "1.11.1", + "@unrs/resolver-binding-linux-ppc64-gnu": "1.11.1", + "@unrs/resolver-binding-linux-riscv64-gnu": "1.11.1", + "@unrs/resolver-binding-linux-riscv64-musl": "1.11.1", + "@unrs/resolver-binding-linux-s390x-gnu": "1.11.1", + "@unrs/resolver-binding-linux-x64-gnu": "1.11.1", + "@unrs/resolver-binding-linux-x64-musl": "1.11.1", + "@unrs/resolver-binding-wasm32-wasi": "1.11.1", + "@unrs/resolver-binding-win32-arm64-msvc": "1.11.1", + "@unrs/resolver-binding-win32-ia32-msvc": "1.11.1", + "@unrs/resolver-binding-win32-x64-msvc": "1.11.1" + } + }, "node_modules/update-browserslist-db": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", - "dev": true, "funding": [ { "type": "opencollective", @@ -13086,7 +13818,6 @@ "version": "7.3.1", "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.1.tgz", "integrity": "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==", - "dev": true, "license": "MIT", "dependencies": { "esbuild": "^0.27.0", @@ -13184,7 +13915,6 @@ "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, "hasInstallScript": true, "license": "MIT", "optional": true, @@ -13493,14 +14223,12 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "dev": true, "license": "ISC" }, "node_modules/yaml": { "version": "2.8.2", "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.2.tgz", "integrity": "sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==", - "dev": true, "license": "ISC", "optional": true, "peer": true, @@ -13545,7 +14273,6 @@ "version": "2.10.0", "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", - "dev": true, "license": "MIT", "dependencies": { "buffer-crc32": "~0.2.3", diff --git a/package.json b/package.json index 26c5861..2acee8c 100644 --- a/package.json +++ b/package.json @@ -59,18 +59,20 @@ "@types/dockerode": "^3.3.42", "@types/js-yaml": "^4.0.9", "@types/node": "^24.0.12", - "@vitejs/plugin-react": "^4.6.0", + "@typescript-eslint/eslint-plugin": "^8.54.0", + "@typescript-eslint/parser": "^8.54.0", "@vitest/coverage-v8": "^3.2.4", "css.escape": "^1.5.1", - "electron": "^37.3.1", "electron-builder": "^26.0.12", "eslint": "^9.30.1", "eslint-config-prettier": "^10.1.5", + "eslint-import-resolver-typescript": "^4.4.4", + "eslint-plugin-import": "^2.32.0", "eslint-plugin-jsx-a11y": "^6.10.2", "eslint-plugin-react": "^7.37.5", "eslint-plugin-react-hooks": "^5.2.0", + "eslint-plugin-unused-imports": "^4.3.0", "prettier": "^3.6.2", - "vite": "^7.1.11", "vitest": "^3.2.4" }, "dependencies": { @@ -81,11 +83,15 @@ "@jsonforms/react": "^3.7.0-alpha.1", "@mui/icons-material": "^7.2.0", "@mui/material": "^7.2.0", + "@mui/system": "^7.3.7", + "@vitejs/plugin-react": "^4.6.0", "ajv": "^8.17.1", "ansi-to-html": "^0.7.2", "dockerode": "^4.0.7", "dompurify": "^3.2.7", + "electron": "^37.3.1", "electron-store": "8.2.0", + "hast-util-sanitize": "^5.0.2", "i18next": "^25.5.2", "i18next-browser-languagedetector": "^8.2.0", "i18next-resources-to-backend": "^1.2.1", @@ -104,6 +110,7 @@ "slash": "^5.1.0", "typescript": "^5.9.3", "unique-names-generator": "^4.7.1", - "unist-util-visit": "^5.0.0" + "unist-util-visit": "^5.0.0", + "vite": "^7.1.11" } } diff --git a/scripts/prepare_bundle.js b/scripts/prepare_bundle.js index f3acf1d..8e75bce 100644 --- a/scripts/prepare_bundle.js +++ b/scripts/prepare_bundle.js @@ -21,7 +21,8 @@ import { fileURLToPath } from 'url'; const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); -const JAVA_VERSION = process.env.JAVA_VERSION || '25'; +const bundle_full_jre = false; +const JAVA_VERSION = process.env.JAVA_VERSION || '21'; const NXF_URL = process.env.NXF_URL || 'https://www.nextflow.io/releases/v25.10.2/nextflow-25.10.2-one.jar'; @@ -81,6 +82,34 @@ function downloadFile(url, destPath) { }); } +function detectJavaHome(javaCmd = 'java') { + try { + // java -XshowSettings:properties prints " java.home = /path" + const out = runOutput(`${javaCmd} -XshowSettings:properties -version 2>&1`); + const m = out.match(/^\s*java\.home = (.+)$/m); + if (m && m[1]) return m[1].trim(); + } catch (e) { + // fallback: try `which java` -> resolve path -> go up two directories + try { + const whichJava = runOutput('which java').trim(); + if (whichJava) { + // On many systems 'which java' returns the wrapper; try readlink -f + try { + const resolved = runOutput(`readlink -f ${whichJava}`).trim(); + if (resolved) { + // java binary lives in .../bin/java -> java.home is parent dir + return path.dirname(path.dirname(resolved)); + } + } catch (e2) { + // fallback to dirname(dirname(whichJava)) + return path.dirname(path.dirname(whichJava)); + } + } + } catch {} + } + return null; +} + async function main() { try { // SCRIPT_DIR logic: assume script is at scripts/prepare_bundle.js @@ -118,75 +147,160 @@ async function main() { // Prepare Java runtime const jreDir = path.join(bundleDir, 'jre'); if (!fileExists(jreDir)) { - log('Preparing Java runtime...'); - - // Ensure jdeps exists - try { - execSync('jdeps --version', { stdio: 'ignore' }); - } catch (e) { - throw new Error( - 'jdeps not found in PATH. Please install a JDK that includes jdeps and jlink.' - ); - } + if (bundle_full_jre) { + // --- Copy full JRE --- - log('Determining Java dependencies (jdeps)...'); - - // Run jdeps similar to: jdeps --multi-release $JAVA_VERSION -summary nextflow.jar | awk '/->/ {print $NF}' | grep -E '^(java\.|jdk\.)' | sort -u | paste -sd, - - const jdepsCmd = `jdeps --multi-release ${JAVA_VERSION} -summary "${nextflowJar}"`; - const jdepsOut = runOutput(jdepsCmd); - // Parse lines containing '->' and extract right-most token, then filter java./jdk. - const modules = jdepsOut - .split(/\r?\n/) - .map((l) => l.trim()) - .filter((l) => l.includes('->')) - .map((l) => { - // take last token - const parts = l.split(/\s+/); - return parts[parts.length - 1]; - }) - .filter((m) => /^java\.|^jdk\./.test(m)) - .filter(Boolean); + log('Bundling full system JRE into the app...'); - const uniqueModules = Array.from(new Set(modules)).sort(); - if (uniqueModules.length === 0) { - log('Warning: no java/jdk modules found by jdeps. Falling back to "java.base".'); - } - const MODULES = uniqueModules.length > 0 ? uniqueModules.join(',') : 'java.base'; - log('Required modules:', MODULES); - - // Ensure jlink exists - try { - execSync('jlink --version', { stdio: 'ignore' }); - } catch (e) { - throw new Error('jlink not found in PATH. Please install a JDK that includes jlink.'); - } + // allow an override for reproducible packaging + const JAVA_CMD = process.env.SYSTEM_JAVA || 'java'; + const javaHome = detectJavaHome(JAVA_CMD); + if (!javaHome) { + throw new Error( + 'Could not detect system JAVA_HOME. Set SYSTEM_JAVA env or ensure `java` is on PATH.' + ); + } + log('Detected java.home:', javaHome); - log('Creating minimal Java runtime (jlink)...'); - // Build jlink command: jlink --add-modules "$MODULES" --strip-debug --compress zip-6 --no-header-files --no-man-pages --output ./jre - const jlinkCmd = [ - 'jlink', - `--add-modules "${MODULES}"`, - '--strip-debug', - '--compress', - 'zip-6', - '--no-header-files', - '--no-man-pages', - `--output "${jreDir}"` - ].join(' '); - - run(jlinkCmd); - - log('Minimal Java runtime created.'); - - // Smoke test: run jre/bin/java -jar nextflow.jar info - const javaBin = path.join(jreDir, 'bin', 'java'); - if (!fileExists(javaBin)) { - throw new Error(`Expected java executable not found at ${javaBin}`); - } + // Copy the full JRE/JDK directory into bundle/jre + // Prefer Node's fs.cpSync (Node 16+). Fallback to system 'cp -a' or rsync. + try { + // Ensure destination parent exists + fs.mkdirSync(jreDir, { recursive: true }); + try { + // Node >= 16: use fs.cpSync for recursive copy + if (fs.cpSync) { + log('Copying JRE using fs.cpSync (fast)...'); + fs.cpSync(javaHome, jreDir, { recursive: true }); + } else { + throw new Error('fs.cpSync not available'); + } + } catch (copyErr) { + log('fs.cpSync failed or not available, falling back to system copy (cp -a)...'); + // Use POSIX cp -a (works on macOS/Linux) + run(`cp -a "${javaHome}" "${jreDir}"`); + } + } catch (copyError) { + err( + 'Failed to copy JRE into bundle:', + copyError && copyError.message ? copyError.message : copyError + ); + throw copyError; + } + + // Normalize: in some JDKs javaHome may be the JDK root (e.g. .../Contents/Home). + // Ensure bin/java exists. + let javaBin = path.join(jreDir, 'bin', 'java'); + if (!fileExists(javaBin)) { + // If the copied tree contains 'jre' inside, try that + const alt = path.join(jreDir, 'jre', 'bin', 'java'); + if (fileExists(alt)) { + javaBin = alt; + } else { + // sometimes JDK home has 'bin/java' but copy created nested structure; search + const found = runOutput( + `find "${jreDir}" -type f -name java -print -quit 2>/dev/null` + ).trim(); + if (found) javaBin = found; + } + } - log('Running smoke test...'); - run(`"${javaBin}" -jar "${nextflowJar}" info`); - log('Smoke test completed successfully.'); + if (!fileExists(javaBin)) { + throw new Error(`Expected java executable not found in copied JRE. Searched: ${javaBin}`); + } + + // Make sure java binary is executable + try { + fs.chmodSync(javaBin, 0o755); + } catch (e) { + // ignore if chmod fails due to permissions on packaging system + } + + log('Bundled java binary at:', javaBin); + log('Running smoke test with bundled JRE...'); + run(`"${javaBin}" -jar "${nextflowJar}" info`); + log('Smoke test completed successfully (full JRE).'); + } else { + // --- Minimal JRE --- + + log('Preparing minimal Java runtime...'); + + // Ensure jdeps exists + try { + execSync('jdeps --version', { stdio: 'ignore' }); + } catch (e) { + throw new Error( + 'jdeps not found in PATH. Please install a JDK that includes jdeps and jlink.' + ); + } + + log('Determining Java dependencies (jdeps)...'); + + // Run jdeps similar to: jdeps --multi-release $JAVA_VERSION -summary nextflow.jar | awk '/->/ {print $NF}' | grep -E '^(java\.|jdk\.)' | sort -u | paste -sd, - + const jdepsCmd = `jdeps --multi-release ${JAVA_VERSION} -summary "${nextflowJar}"`; + const jdepsOut = runOutput(jdepsCmd); + // Parse lines containing '->' and extract right-most token, then filter java./jdk. + const modules = jdepsOut + .split(/\r?\n/) + .map((l) => l.trim()) + .filter((l) => l.includes('->')) + .map((l) => { + // take last token + const parts = l.split(/\s+/); + return parts[parts.length - 1]; + }) + .filter((m) => /^java\.|^jdk\./.test(m)) + .filter(Boolean); + + modules.push('java.base'); + modules.push('java.net.http'); + modules.push('jdk.crypto.ec'); + modules.push('jdk.crypto.cryptoki'); + modules.push('java.security.jgss'); + modules.push('java.naming'); + modules.push('java.xml'); + + const uniqueModules = Array.from(new Set(modules)).sort(); + if (uniqueModules.length === 0) { + log('Warning: no java/jdk modules found by jdeps. Falling back to "java.base".'); + } + const MODULES = uniqueModules.length > 0 ? uniqueModules.join(',') : 'java.base'; + log('Required modules:', MODULES); + + // Ensure jlink exists + try { + execSync('jlink --version', { stdio: 'ignore' }); + } catch (e) { + throw new Error('jlink not found in PATH. Please install a JDK that includes jlink.'); + } + + log('Creating minimal Java runtime (jlink)...'); + // Build jlink command: jlink --add-modules "$MODULES" --strip-debug --compress zip-6 --no-header-files --no-man-pages --output ./jre + const jlinkCmd = [ + 'jlink', + `--add-modules "${MODULES}"`, + '--strip-debug', + '--compress', + 'zip-6', + '--no-header-files', + '--no-man-pages', + `--output "${jreDir}"` + ].join(' '); + + run(jlinkCmd); + + log('Minimal Java runtime created.'); + + // Smoke test: run jre/bin/java -jar nextflow.jar info + const javaBin = path.join(jreDir, 'bin', 'java'); + if (!fileExists(javaBin)) { + throw new Error(`Expected java executable not found at ${javaBin}`); + } + + log('Running smoke test...'); + run(`"${javaBin}" -jar "${nextflowJar}" info`); + log('Smoke test completed successfully.'); + } } else { log('Java runtime already exists. Skipping preparation.'); } diff --git a/scripts/wsl-setup.ps1 b/scripts/wsl-setup.ps1 new file mode 100644 index 0000000..6f9fcfc --- /dev/null +++ b/scripts/wsl-setup.ps1 @@ -0,0 +1,42 @@ +#!/usr/bin/env pwsh + +wsl.exe --version +wsl.exe --list + +mkdir "$env:USERPROFILE\glacier\wsl" -Force +curl.exe -L "https://cloud-images.ubuntu.com/releases/jammy/release/ubuntu-22.04-server-cloudimg-amd64-root.tar.xz" -o "$env:USERPROFILE\glacier\wsl\ubuntu-22.04.tar.xz" + +wsl.exe --import build "$env:USERPROFILE\glacier\wsl" "$env:USERPROFILE\glacier\wsl\ubuntu-22.04.tar.xz" + +wsl.exe -d build -u root -- apt update +wsl.exe -d build -u root -- apt upgrade -y +wsl.exe -d build -u root -- apt install -y docker.io openjdk-17-jre-headless +wsl.exe -d build -u root -- java -version + +wsl.exe -d build -u root -- useradd -m -s /bin/bash user +wsl.exe -d build -u root -- bash -c "echo 'user:user' | chpasswd" +wsl.exe -d build -u root -- bash -c "echo -e '[boot]\nsystemd=true\n[user]\ndefault=user' > /etc/wsl.conf" +wsl.exe -d build -u root -- usermod -aG docker user +wsl.exe -d build -u root -- bash -c "sed -i 's/127.0.1.1.*/127.0.1.1 glacier/' /etc/hosts" + +wsl.exe -t build +wsl.exe -d build -u root -- systemctl enable docker +wsl.exe -d build -u root -- systemctl start docker +wsl.exe -d build -u user -- bash -c "curl -s https://get.nextflow.io -o ~/nextflow && chmod +x ~/nextflow" +wsl.exe -d build -u root -- mv /home/user/nextflow /usr/local/bin/ + +wsl.exe -t build + +wsl.exe -d build -- nextflow -v +wsl.exe -d build -- nextflow run hello +wsl.exe -d build -- docker run hello-world + +wsl.exe -t build +wsl.exe --export build "$env:USERPROFILE\glacier\wsl\glacier-wsl.tar" +wsl.exe --unregister build + +wsl.exe --import glacier "$env:USERPROFILE\glacier\wsl" "$env:USERPROFILE\glacier\wsl\glacier-wsl.tar" + +wsl.exe -d glacier -- nextflow -v +wsl.exe -d glacier -- nextflow run hello +wsl.exe -d glacier -- docker run hello-world diff --git a/src/locales/en/translation.json b/src/locales/en/translation.json index 933f88a..bd37e46 100644 --- a/src/locales/en/translation.json +++ b/src/locales/en/translation.json @@ -2,32 +2,63 @@ "glacier": "GLACIER", "container-started": "Container built and started with ID", "common": { + "okay": "Okay", "cancel": "Cancel" }, "sidebar": { - "hub": "Hub", "library": "Library", "instances": "Instances", "settings": "Settings" }, - "hub": { - "add-workflow-from-repository": "Add Workflow from Repository", - "repo": "Repo", - "add": "Add", - "clone": "Clone", - "clone-return-none": "Clone failed or returned nothing", - "clone-failed": "Clone operation failed", - "install": "Install", - "repo-added": "Repository added successfully", - "repo-add-failed": "Failed to add repository" - }, "library": { "local-repositories": "Local Repositories", + "install": "Install", "run": "Run", "sync": "Sync", "repo-sync-success": "Repository synced successfully", "repo-sync-failed": "Repository sync failed", - "no-repos-installed": "No repositories installed. Add a repository from the Hub to get started." + "no-repos-installed": "No repositories installed. Add a repository or catalogue to get started.", + "clone-error": "Error cloning repository", + "actions": "Actions", + "add-catalogue": "Add Catalogue", + "remove-catalogue": "Remove Catalogue", + "add-section": "Add Section", + "remove-section": "Remove Section", + "add-repository": "Add Workflow", + "remove-repository": "Remove Workflow", + "install-all-workflows": "Install All Workflows", + "check-for-updates": "Check for Updates", + "confirm-remove-catalogue": "Are you sure you want to remove this catalogue? All workflows and workflow instances will remain installed.", + "catalogue-removed-success": "Catalogue removed successfully", + "catalogue-removed-failure": "Failed to remove catalogue", + "confirm-remove-section": "Are you sure you want to remove this section from the catalogue? All workflows and workflow instances will remain installed.", + "section-removed-success": "Section removed successfully", + "section-removed-failure": "Failed to remove section", + "confirm-remove-workflow": "Are you sure you want to remove this workflow from the section?", + "workflow-removed-success": "Workflow removed successfully", + "workflow-removed-failure": "Failed to remove workflow", + "workflow-updated-success": "Workflow updated successfully", + "workflow-updated-failure": "Failed to update workflow", + "installing-workflows": "Installing workflows...", + "install-workflows-completed-with-errors": "Workflow installation completed with errors.", + "add-catalogue-dialog": { + "title": "Add Catalogue", + "description": "Enter the Github organisation, or repository to add:", + "repository-url": "Repository URL", + "error-unable-to-add": "Unable to add catalogue. Please check the URL and try again.", + "error-repo-required": "Repository URL is required." + }, + "add-workflow-dialog": { + "title": "Add Workflow", + "description": "Enter the Github repository to add:", + "repository-url": "Repository URL", + "version": "Version (branch, tag, or commit)", + "section": "Section", + "name": "Workflow name (optional)", + "error-unable-to-add": "Unable to add workflow. Please check the URL and try again.", + "error-repo-required": "Repository URL is required.", + "error-section-required": "Section is required." + } }, "instances": { "title": "Instances", @@ -101,7 +132,9 @@ "general": "General", "dark-mode": "Dark Mode", "collections-path": "Library path", - "allow-arbitrary-repo-cloning": "Allow arbitrary repository cloning", + "permit-add-catalogues": "Allow adding catalogues", + "permit-catalogue-modifications": "Allow modifying catalogues", + "permit-add-repos": "Allow adding repositories", "language-select": "Language", "visual-options": "Visual", "advanced-options": "Advanced", diff --git a/src/locales/fr/translation.json b/src/locales/fr/translation.json index 0c776d4..af5dd82 100644 --- a/src/locales/fr/translation.json +++ b/src/locales/fr/translation.json @@ -2,32 +2,63 @@ "glacier": "GLACIER", "container-started": "Conteneur construit et démarré avec l'ID", "common": { + "okay": "OK", "cancel": "Annuler" }, "sidebar": { - "hub": "Hub", "library": "Bibliothèque", "instances": "Instances", "settings": "Paramètres" }, - "hub": { - "add-workflow-from-repository": "Ajouter un flux de travail depuis un dépôt", - "repo": "Dépôt", - "add": "Ajouter", - "clone": "Cloner", - "clone-return-none": "Le clonage a échoué ou n'a rien retourné", - "clone-failed": "L'opération de clonage a échoué", - "install": "Installer", - "repo-added": "Dépôt ajouté avec succès", - "repo-add-failed": "L'ajout du dépôt a échoué" - }, "library": { "local-repositories": "Dépôts locaux", + "install": "Installer", "run": "Exécuter", "sync": "Synchroniser", "repo-sync-success": "Dépôt synchronisé avec succès", "repo-sync-failed": "La synchronisation du dépôt a échoué", - "no-repos-installed": "Aucun dépôt installé. Veuillez ajouter un dépôt depuis le Hub." + "no-repos-installed": "Aucun dépôt n’est installé. Ajoutez un dépôt ou un catalogue pour commencer.", + "clone-error": "Erreur lors du clonage du dépôt", + "actions": "Actions", + "add-catalogue": "Ajouter un catalogue", + "remove-catalogue": "Supprimer le catalogue", + "add-section": "Ajouter une section", + "remove-section": "Supprimer la section", + "add-repository": "Ajouter un dépôt", + "remove-repository": "Supprimer le dépôt", + "install-all-workflows": "Installer tous les flux de travail", + "check-for-updates": "Vérifier les mises à jour", + "confirm-remove-catalogue": "Êtes-vous sûr de vouloir supprimer ce catalogue ? Tous les flux de travail et instances de flux de travail resteront installés.", + "catalogue-removed-success": "Catalogue supprimé avec succès", + "catalogue-removed-failure": "Échec de la suppression du catalogue", + "confirm-remove-section": "Êtes-vous sûr de vouloir supprimer cette section du catalogue ? Tous les flux de travail et instances de flux de travail resteront installés.", + "section-removed-success": "Section supprimée avec succès", + "section-removed-failure": "Échec de la suppression de la section", + "confirm-remove-workflow": "Êtes-vous sûr de vouloir supprimer ce flux de travail de la section ?", + "workflow-removed-success": "Flux de travail supprimé avec succès", + "workflow-removed-failure": "Échec de la suppression du flux de travail", + "workflow-updated-success": "Flux de travail mis à jour avec succès", + "workflow-updated-failure": "Échec de la mise à jour du flux de travail", + "installing-workflows": "Installation des flux de travail...", + "install-workflows-completed-with-errors": "Installation des flux de travail terminée avec des erreurs.", + "add-catalogue-dialog": { + "title": "Ajouter un catalogue", + "description": "Entrez l'URL du catalogue à ajouter:", + "repository-url": "URL du dépôt", + "error-unable-to-add": "Impossible d'ajouter le catalogue. Veuillez vérifier l'URL et réessayer.", + "error-repo-required": "L'URL du dépôt est requise." + }, + "add-workflow-dialog": { + "title": "Ajouter un flux de travail", + "description": "Ajouter un flux de travail depuis un dépôt Github.", + "repository-url": "URL du dépôt", + "version": "Version (branche, tag ou commit)", + "section": "Section", + "name": "Nom du flux de travail (optionnel)", + "error-unable-to-add": "Impossible d'ajouter le flux de travail. Veuillez vérifier l'URL et réessayer.", + "error-repo-required": "L'URL du dépôt est requise.", + "error-section-required": "Le nom de la section est requis." + } }, "instances": { "title": "Instances", @@ -101,7 +132,9 @@ "general": "Général", "dark-mode": "Mode sombre", "collections-path": "Chemin de la bibliothèque", - "allow-arbitrary-repo-cloning": "Autoriser le clonage de dépôts arbitraires", + "permit-add-catalogues": "Autoriser l'ajout de catalogues", + "permit-catalogue-modifications": "Autoriser les modifications de catalogues", + "permit-add-repos": "Autoriser l'ajout de dépôts", "language-select": "Langue", "visual-options": "Visuelles", "advanced-options": "Avancées", diff --git a/src/main/collection.ts b/src/main/collection.ts index 388d713..6c49d22 100644 --- a/src/main/collection.ts +++ b/src/main/collection.ts @@ -10,9 +10,8 @@ import { cloneRepo, ICloneRepo, getRepoTags, getRepoBranches } from './repo.js'; import { runWorkflow } from './runner.js'; import { getEnvironmentStatus, performEnvironmentAction } from '../runners/environment.js'; import { WorkflowStatus } from '../types/types.js'; -import { EnvironmentKey } from '../types/environment.js'; import { syncRepo, getWorkflowParams, getWorkflowSchema } from './repo.js'; -import { getCollectionsPath, getDefaultCollectionsDir, locateReports } from './paths.js'; +import { getCollectionsPath, locateReports } from './paths.js'; import { settings, StoreSchema } from './settings.js'; // Should remove imports from specific runners @@ -22,7 +21,28 @@ import { parseNextflowLog } from '../runners/nextflow/nf-parse.js'; const instance_database_file = 'instances.json'; -const default_repos = ['artic-network/artic-mpxv-nf', 'artic-network/amplicon-nf']; +export interface Catalogue { + name: string; + source: string; + description?: string; + icon?: string; + scheme?: Record; + sections: CatalogueSection[]; +} + +export interface CatalogueSection { + name: string; + description?: string; + icon?: string; + scheme?: Record; + workflows: CatalogueWorkflow[]; +} + +export interface CatalogueWorkflow { + name: string; + repo: string; + version?: string; +} export enum IWorkflowType { NEXTFLOW = 'nextflow', @@ -76,8 +96,6 @@ class Workflow implements IWorkflow { url: string; versions: WorkflowVersion[]; - project: IProject | null = null; // reference to project if applicable - constructor(wf: IWorkflow) { this.id = wf.id; this.name = wf.name; @@ -156,28 +174,6 @@ class WorkflowInstance implements IWorkflowInstance { } } -// A project is a collection of workflows, mainly used for branding -export interface IProject { - id: string; - name: string; - url: string; - workflows: IWorkflow[]; -} - -class Project implements IProject { - id: string; - name: string; - url: string; - workflows: IWorkflow[]; - - constructor({ id, name, url, workflows = [] }: IProject) { - this.id = id; - this.name = name; - this.url = url; - this.workflows = workflows; - } -} - // Singleton class export class Collection { // --- Class management -------------------------------------------------------------- @@ -203,7 +199,7 @@ export class Collection { root_path: string = ''; - projects: Project[] = []; + catalogues: Catalogue[] = []; workflows: Workflow[] = []; workflow_instances: WorkflowInstance[] = []; @@ -219,11 +215,16 @@ export class Collection { return path.join(this.root_path, 'instances'); } + get catalogues_path(): string { + return path.join(this.root_path, 'catalogues'); + } + // --- Logic ------------------------------------------------------------------------- async parseCollection() { this.parseWorkflows(); this.parseInstallableRepos(); + await this.parseCatalogues(); await this.parseInstances(); } @@ -273,11 +274,7 @@ export class Collection { } } - private parseInstallableRepos() { - default_repos.forEach((repo) => { - this.addInstallableRepo(repo); - }); - } + private parseInstallableRepos() {} private async parseInstances() { // Clean existing instances @@ -356,7 +353,7 @@ export class Collection { try { process.kill(pid, 0); // Check if process is running console.log(`Instance ${instance.id} has running PID: ${pid}`); - } catch (e) { + } catch { console.log(`Instance ${instance.id} PID ${pid} is not running, updating status.`); // Remove PID from instance instance.pid = instance.pid.filter((p) => p !== pid); @@ -406,6 +403,7 @@ export class Collection { } } + // eslint-disable-next-line @typescript-eslint/no-unused-vars determineWorkflowType(folder: string): IWorkflowType { // Placeholder logic, can be improved return IWorkflowType.NEXTFLOW; @@ -428,7 +426,7 @@ export class Collection { throw new Error(`Workflow ${workflow_id} has no versions.`); } let workflow_version; - if (version === undefined) { + if (version === undefined || version === 'latest') { // Local repository workflow_version = workflow.versions[0]; } else { @@ -542,12 +540,12 @@ export class Collection { try { process.kill(-pid, sig); // signal the process group return true; - } catch (e) { + } catch { // Fallback: try the single process try { process.kill(pid, sig); return true; - } catch (_) { + } catch { return false; } } @@ -739,7 +737,7 @@ export class Collection { // Check if version already exists let version = wf.versions.find((v) => v.version === repo.version); if (version !== undefined) { - throw new Error(`Workflow ${wf_id}@${repo.version} already exists.`); + return version; } version = new WorkflowVersion({ id: `${wf_id}@${repo.version}`, @@ -760,7 +758,7 @@ export class Collection { await this.parseCollection(); } - getCollections(): IRepo[] { + getCollectionRepos(): IRepo[] { const repos: IRepo[] = []; this.workflows.forEach((wf) => { wf.versions.forEach((ver) => { @@ -861,34 +859,6 @@ export class Collection { return locateReports(instance.path); } - getProjectsList(): IProject[] { - if (this.projects.length > 0) { - return this.projects; - } - return this.projects; - } - - addProject(repoPath: string): string { - // /// Replace with repo parsing logic /// - const i = this.projects.length + 1; - this.projects.push( - new Project({ - id: i.toString(), - name: `New Project ${i}`, - url: repoPath, - workflows: [] - }) - ); - return ''; - } - - removeProject(project: IProject) { - const index = this.projects.findIndex((p) => p.id === project.id); - if (index === -1) return 'Project not found in collection.'; - this.projects.splice(index, 1); - return ''; - } - getInstallableReposList(): IRepoVersions[] { return this.installable_repos; } @@ -975,4 +945,243 @@ export class Collection { async performEnvironmentAction(key: string, action: string) { return performEnvironmentAction(key, action); } + + async parseCatalogues() { + // Clear existing catalogues + this.catalogues = []; + + // Read catalogues from catalogues path + if (!fs.existsSync(this.catalogues_path)) { + console.log(`Catalogues path ${this.catalogues_path} does not exist.`); + return; + } + const owners = fs.readdirSync(this.catalogues_path); + for (const owner of owners) { + const ownerPath = path.join(this.catalogues_path, owner); + const repoDirs = fs.readdirSync(ownerPath); + for (const repo of repoDirs) { + const repoPath = path.join(ownerPath, repo); + // Read catalogue.json + const cat_file = path.join(repoPath, 'catalogue.json'); + const cat_contents = fs.readFileSync(cat_file, 'utf-8'); + const js = JSON.parse(cat_contents); + js['source'] = `${owner}/${repo}`; + js['base_dir'] = repoPath; + // Add to catalogues + this.catalogues.push(js); + } + } + } + + async addCatalogue(url: string, version: string) { + // Clone catalogue repository and refresh catalogues list + console.log(`Cloning catalogue repository ${url} version ${version}`); + const hasSlash = url.includes('/'); + if (!hasSlash) { + url = `${url}/glacier-catalogue`; + } + const repo: ICloneRepo = await cloneRepo(url, this.catalogues_path, version); + const cat_file = path.join(repo.path, 'catalogue.json'); + const contents = fs.readFileSync(cat_file, 'utf-8'); + const js = JSON.parse(contents); + js['source'] = url; + js['base_dir'] = repo.path; + this.parseCatalogues(); // update catalogue + } + + async removeCatalogue(catalogue_name: string) { + // Remove catalogue from catalogues path + const cat = this.catalogues.find((c) => c.name === catalogue_name); + if (!cat) { + throw new Error(`Catalogue ${catalogue_name} not found.`); + } + const owner = cat.source.split('/')[0]; + const repo = cat.source.split('/')[1]; + const cat_path = path.join(this.catalogues_path, owner, repo); + fs.rmSync(cat_path, { recursive: true, force: true }); + // Refresh catalogues + this.parseCatalogues(); + } + + async removeCatalogueSection(catalogue_name: string, section_name: string) { + // Remove section from catalogue + const cat = this.catalogues.find((c) => c.name === catalogue_name); + if (!cat) { + throw new Error(`Catalogue ${catalogue_name} not found.`); + } + const section_index = cat.sections.findIndex((s) => s.name === section_name); + if (section_index === -1) { + throw new Error(`Section ${section_name} not found in catalogue ${catalogue_name}.`); + } + cat.sections.splice(section_index, 1); + // Save to catalogues path + const owner = cat.source.split('/')[0]; + const repo = cat.source.split('/')[1]; + const cat_path = path.join(this.catalogues_path, owner, repo, 'catalogue.json'); + fs.writeFileSync(cat_path, JSON.stringify(cat, null, 2)); + // Refresh catalogues + this.parseCatalogues(); + } + + async removeCatalogueWorkflow( + catalogue_name: string, + section_name: string, + workflow_name: string + ) { + // Remove workflow from catalogue section + const cat = this.catalogues.find((c) => c.name === catalogue_name); + if (!cat) { + throw new Error(`Catalogue ${catalogue_name} not found.`); + } + const section = cat.sections.find((s) => s.name === section_name); + if (!section) { + throw new Error(`Section ${section_name} not found in catalogue ${catalogue_name}.`); + } + const workflow_index = section.workflows.findIndex((w) => w.name === workflow_name); + if (workflow_index === -1) { + throw new Error( + `Workflow ${workflow_name} not found in section ${section_name} of catalogue ${catalogue_name}.` + ); + } + section.workflows.splice(workflow_index, 1); + // Save to catalogues path + const owner = cat.source.split('/')[0]; + const repo = cat.source.split('/')[1]; + const cat_path = path.join(this.catalogues_path, owner, repo, 'catalogue.json'); + fs.writeFileSync(cat_path, JSON.stringify(cat, null, 2)); + // Refresh catalogues + this.parseCatalogues(); + } + + async updateCatalogueWorkflow( + catalogue_name: string, + section_name: string, + workflow_name: string + ) { + // Update workflow in catalogue section by re-fetching tags/branches + const cat = this.catalogues.find((c) => c.name === catalogue_name); + if (!cat) { + throw new Error(`Catalogue ${catalogue_name} not found.`); + } + const section = cat.sections.find((s) => s.name === section_name); + if (!section) { + throw new Error(`Section ${section_name} not found in catalogue ${catalogue_name}.`); + } + const workflow = section.workflows.find((w) => w.name === workflow_name); + if (!workflow) { + throw new Error( + `Workflow ${workflow_name} not found in section ${section_name} of catalogue ${catalogue_name}.` + ); + } + // Re-fetch tags and branches + const tags = await getRepoTags(workflow.repo); + const branches = await getRepoBranches(workflow.repo); + const all_versions = tags.concat(branches); + if (all_versions.length === 0) { + throw new Error(`No tags or branches found for repository: ${workflow.repo}`); + } + // Update version if current version not found + if (workflow.version !== 'latest' && !all_versions.includes(workflow.version || '')) { + workflow.version = all_versions[0]; + } + // Save to catalogues path + const owner = cat.source.split('/')[0]; + const repo = cat.source.split('/')[1]; + const cat_path = path.join(this.catalogues_path, owner, repo, 'catalogue.json'); + fs.writeFileSync(cat_path, JSON.stringify(cat, null, 2)); + // Refresh catalogues + this.parseCatalogues(); + } + + async addUserWorkflow(name: string, url: string, version: string, section: string) { + if (!name) { + name = url.split('/')[1]; + } + if (!section) { + section = 'My Workflows'; + } + if (!version) { + version = 'latest'; + } + // Verify that repository url exists + const tags = await getRepoTags(url); + const branches = await getRepoBranches(url); + const all_versions = tags.concat(branches); + if (all_versions.length === 0) { + throw new Error(`No tags or branches found for repository: ${url}`); + } + if (version !== 'latest' && !all_versions.includes(version)) { + throw new Error( + `Version ${version} not found for repository: ${url}. Available versions: ${all_versions.join( + ', ' + )}` + ); + } + // Add workflow to catalogue + const user_cat_path = path.join( + this.catalogues_path, + 'user_collection', + 'store', + 'catalogue.json' + ); + let user_catalogue: Catalogue; + if (fs.existsSync(user_cat_path)) { + // Read existing catalogue + const contents = fs.readFileSync(user_cat_path, 'utf-8'); + user_catalogue = JSON.parse(contents); + } else { + // Create new catalogue + user_catalogue = { + name: 'User collection', + source: 'local', + sections: [] + }; + } + // Find (or create) section + let user_section = user_catalogue.sections.find((sec) => sec.name === section); + if (!user_section) { + user_section = { + name: section, + workflows: [] + }; + user_catalogue.sections.push(user_section); + } + user_section.workflows.push({ + name: name, + repo: url, + version: version + }); + // Save to catalogues path + this.ensurePathExists(path.dirname(user_cat_path)); + fs.writeFileSync(user_cat_path, JSON.stringify(user_catalogue, null, 2)); + // Refresh catalogues + this.parseCatalogues(); + } + + async getCatalogues() { + return this.catalogues; + } + + async isRepoInstalled(url: string, version: string): Promise { + const owner = url.split('/')[0]; + const repo = url.split('/')[1]; + const wf = this.workflows.find((wf) => wf.id === `${owner}/${repo}`); + if (!wf) { + return ''; + } + if (version === 'latest') { + // Any version installed + if (wf.versions.length > 0) { + return wf.versions[0].version || ''; + } else { + return ''; + } + } + const ver = wf.versions.find((v) => v.version === version); + if (ver) { + return ver.version || ''; + } else { + return ''; + } + } } diff --git a/src/main/ipc-handlers.ts b/src/main/ipc-handlers.ts index ab03083..0ed0886 100644 --- a/src/main/ipc-handlers.ts +++ b/src/main/ipc-handlers.ts @@ -1,7 +1,3 @@ -import fs from 'fs'; -import path from 'path'; -import git from 'isomorphic-git'; -import http from 'isomorphic-git/http/node/index.cjs'; import { ipcMain } from 'electron'; import { Collection } from './collection.js'; import { StoreSchema } from './settings.js'; @@ -22,6 +18,29 @@ async function call(fcn: any, ...args: any[]): Promise> { } export function registerIpcHandlers() { + const redirect = { + 'run-workflow': collection.runWorkflow.bind(collection), + 'get-catalogues': collection.getCatalogues.bind(collection), + 'add-catalogue': collection.addCatalogue.bind(collection), + 'remove-catalogue': collection.removeCatalogue.bind(collection), + 'remove-catalogue-section': collection.removeCatalogueSection.bind(collection), + 'remove-catalogue-workflow': collection.removeCatalogueWorkflow.bind(collection), + 'update-catalogue-workflow': collection.updateCatalogueWorkflow.bind(collection), + 'add-user-workflow': collection.addUserWorkflow.bind(collection), + 'clone-repo': collection.cloneRepo.bind(collection), + 'is-repo-installed': collection.isRepoInstalled.bind(collection) + }; + + for (const [channel, fcn] of Object.entries(redirect)) { + ipcMain.handle(channel, async (event, ...args) => { + return call(fcn, ...args); + }); + } + + /* + * Legacy call format - update to use call() for consistent error handling + */ + ipcMain.handle( 'create-workflow-instance', async (event, workflow_id: string, version: string) => { @@ -81,10 +100,6 @@ export function registerIpcHandlers() { return collection.getAvailableProfiles(instance); }); - ipcMain.handle('clone-repo', async (event, repoUrl, ver) => { - return await collection.cloneRepo(repoUrl, ver); - }); - ipcMain.handle('get-collections-path', () => { return collection.getCollectionsPath(); }); @@ -93,12 +108,8 @@ export function registerIpcHandlers() { return collection.setCollectionsPath(path); }); - ipcMain.handle('get-collections', async () => { - return collection.getCollections(); - }); - - ipcMain.handle('run-workflow', async (event, ...args) => { - return call(collection.runWorkflow.bind(collection), ...args); + ipcMain.handle('get-collection-repos', async () => { + return collection.getCollectionRepos(); }); ipcMain.handle('sync-repo', async (event, path: string) => { @@ -113,19 +124,7 @@ export function registerIpcHandlers() { return collection.getWorkflowSchema(repoPath); }); - ipcMain.handle('get-projects-list', async (event) => { - return collection.getProjectsList(); - }); - - ipcMain.handle('add-project', async (event, repoPath) => { - return collection.addProject(repoPath); - }); - - ipcMain.handle('remove-project', async (event, project) => { - return collection.removeProject(project); - }); - - ipcMain.handle('get-installable-repos-list', async (event) => { + ipcMain.handle('get-installable-repos-list', async () => { return collection.getInstallableReposList(); }); diff --git a/src/main/main.ts b/src/main/main.ts index 7174d00..3addbdd 100644 --- a/src/main/main.ts +++ b/src/main/main.ts @@ -1,5 +1,4 @@ import { app, screen, BrowserWindow, ipcMain, dialog } from 'electron'; -import * as fs from 'fs'; import * as path from 'path'; import { fileURLToPath } from 'url'; import { registerIpcHandlers } from './ipc-handlers.js'; diff --git a/src/main/paths.ts b/src/main/paths.ts index 755da79..6a8794a 100644 --- a/src/main/paths.ts +++ b/src/main/paths.ts @@ -3,7 +3,6 @@ import path from 'path'; // import { userDataDir } from 'platformdirs'; import fs from 'fs'; import store from './store.js'; -import { IRepo } from './types'; export function getDefaultCollectionsDir(): string { const homeDir = os.homedir(); diff --git a/src/main/preload.ts b/src/main/preload.ts index 88faf03..03a0757 100644 --- a/src/main/preload.ts +++ b/src/main/preload.ts @@ -28,9 +28,24 @@ contextBridge.exposeInMainWorld('electronAPI', { getAvailableProfiles: (instance: any) => ipcRenderer.invoke('get-available-profiles', instance), cloneRepo: (repoUrl: string, ver: string) => ipcRenderer.invoke('clone-repo', repoUrl, ver), + isRepoInstalled: (repoUrl: string, ver: string) => + ipcRenderer.invoke('is-repo-installed', repoUrl, ver), getCollectionsPath: () => ipcRenderer.invoke('get-collections-path'), setCollectionsPath: (path: string) => ipcRenderer.invoke('set-collections-path', path), - getCollections: () => ipcRenderer.invoke('get-collections'), + getCollectionRepos: () => ipcRenderer.invoke('get-collection-repos'), + addCatalogue: (repoUrl: string, version: string) => + ipcRenderer.invoke('add-catalogue', repoUrl, version), + removeCatalogue: (catalogue_name: string) => + ipcRenderer.invoke('remove-catalogue', catalogue_name), + removeCatalogueSection: (catalogue_name: string, section_name: string) => + ipcRenderer.invoke('remove-catalogue-section', catalogue_name, section_name), + removeCatalogueWorkflow: (catalogue_name: string, section_name: string, workflow_name: string) => + ipcRenderer.invoke('remove-catalogue-workflow', catalogue_name, section_name, workflow_name), + updateCatalogueWorkflow: (catalogue_name: string, section_name: string, workflow_name: string) => + ipcRenderer.invoke('update-catalogue-workflow', catalogue_name, section_name, workflow_name), + getCatalogues: () => ipcRenderer.invoke('get-catalogues'), + addUserWorkflow: (name: string, repoUrl: string, version: string, section: string) => + ipcRenderer.invoke('add-user-workflow', name, repoUrl, version, section), syncRepo: (repo: string) => ipcRenderer.invoke('sync-repo', repo), getWorkflowParams: (repoPath: string) => ipcRenderer.invoke('get-workflow-params', repoPath), pickFile: (filters?: Electron.FileFilter[]) => ipcRenderer.invoke('pick-file', { filters }), @@ -38,9 +53,6 @@ contextBridge.exposeInMainWorld('electronAPI', { pickFileOrDirectory: (options: Electron.OpenDialogOptions) => ipcRenderer.invoke('pick-file-or-directory', options), getWorkflowSchema: (repoPath: string) => ipcRenderer.invoke('get-workflow-schema', repoPath), - getProjectsList: () => ipcRenderer.invoke('get-projects-list'), - addProject: (repoPath: string) => ipcRenderer.invoke('add-project', repoPath), - removeProject: (project: any) => ipcRenderer.invoke('remove-project', project), getInstallableReposList: () => ipcRenderer.invoke('get-installable-repos-list'), addInstallableRepo: (repoUrl: string) => ipcRenderer.invoke('add-installable-repo', repoUrl), getWorkflowInformation: (instance: any) => diff --git a/src/main/repo.ts b/src/main/repo.ts index 183b928..85676d1 100644 --- a/src/main/repo.ts +++ b/src/main/repo.ts @@ -1,10 +1,8 @@ -import { getDefaultCollectionsDir } from './paths.js'; import * as fs from 'fs'; import * as path from 'path'; import yaml from 'js-yaml'; import git from 'isomorphic-git'; import http from 'isomorphic-git/http/node'; -import { IRepo } from './types.js'; import { uniqueNamesGenerator, adjectives, animals } from 'unique-names-generator'; interface WorkflowData { @@ -55,24 +53,43 @@ export async function cloneRepo( // Determine the version to clone let version = ver || (await getDefaultBranch(url)); - if (version === null || version === '') { - version = 'main'; // Fallback + if (version === null || version === '' || version === 'latest') { + const tags = (await getRepoTags(url)) || []; + if (tags.length === 0) { + version = 'main'; + } else { + version = tags[0]; + } } // Determine and create the target directory const targetDir = path.join(workflowDir, owner, repo + '@' + version); + if (fs.existsSync(targetDir)) { + return { + owner: owner, + repo: repo, + version: version, + url: url, + path: targetDir + } as ICloneRepo; + } fs.mkdirSync(targetDir, { recursive: true }); // Clone - await git.clone({ - fs, - http, - dir: targetDir, - url: url, - ref: version, // branch or tag - singleBranch: true, - depth: 1 - }); + try { + await git.clone({ + fs, + http, + dir: targetDir, + url: url, + ref: version, // branch or tag + singleBranch: true, + depth: 1 + }); + } catch (err: unknown) { + fs.rmSync(targetDir, { recursive: true, force: true }); // Clean up on failure + throw err; + } return { owner: owner, @@ -124,22 +141,22 @@ export async function deleteRepo(repoPath: string) { } export async function getRepoTags(url: string) { - const { owner, repo, url: full_url } = parseRepoUrl(url); + const { url: full_url } = parseRepoUrl(url); try { const info = await git.getRemoteInfo({ http, url: full_url }); return Object.keys(info.refs.tags).reverse(); - } catch (err) { + } catch { console.info(`Failed to fetch tags from ${url}`); return []; } } export async function getRepoBranches(url: string) { - const { owner, repo, url: full_url } = parseRepoUrl(url); + const { url: full_url } = parseRepoUrl(url); try { const info = await git.getRemoteInfo({ http, url: full_url }); return Object.keys(info.refs.heads); - } catch (err) { + } catch { console.info(`Failed to fetch branches from ${url}`); return []; } diff --git a/src/main/runner.ts b/src/main/runner.ts index 0c1a755..bfd1f20 100644 --- a/src/main/runner.ts +++ b/src/main/runner.ts @@ -1,9 +1,3 @@ -import * as os from 'os'; -import * as path from 'path'; -import * as fs_sync from 'fs'; -import { IRepo } from './types'; -import { spawn } from 'child_process'; -import { Readable, Duplex } from 'stream'; import { promises as fs } from 'fs'; import { IWorkflowInstance, IWorkflowParams } from './collection.js'; import { diff --git a/src/main/store.ts b/src/main/store.ts index ba43128..834ea2e 100644 --- a/src/main/store.ts +++ b/src/main/store.ts @@ -3,7 +3,10 @@ import Store from 'electron-store'; // Keep in sync with types/settings.js export interface StoreSchema { collectionsPath: string; - disableProjects: boolean; + darkMode: boolean; + permitAddCatalogues: boolean; + permitCatalogueModifications: boolean; + permitAddRepos: boolean; disableSchemaValidation: boolean; } @@ -13,7 +16,19 @@ const store = new Store({ type: 'string', default: '' }, - disableProjects: { + darkMode: { + type: 'boolean', + default: false + }, + permitAddCatalogues: { + type: 'boolean', + default: true + }, + permitCatalogueModifications: { + type: 'boolean', + default: true + }, + permitAddRepos: { type: 'boolean', default: true }, diff --git a/src/renderer/pages/Hub.tsx b/src/renderer/pages/Hub.tsx deleted file mode 100644 index 7946a57..0000000 --- a/src/renderer/pages/Hub.tsx +++ /dev/null @@ -1,197 +0,0 @@ -import React, { useEffect, useState } from 'react'; -import { - Button, - Container, - Paper, - Stack, - TextField, - Typography, - Box, - Grid, - Select, - Snackbar, - Alert, - MenuItem -} from '@mui/material'; -import CircularProgress from '@mui/material/CircularProgress'; -import { API } from '../services/api.js'; -import { useTranslation } from 'react-i18next'; - -export default function HubPage({ - repoUrl, - setRepoUrl, - targetDir, - drawerOpen, - setTargetDir, - setFolderPath, - allowArbitraryRepoCloning, - logMessage, - setView -}) { - const { t } = useTranslation(); - - const [installedRepos, setInstalledRepos] = useState([]); - const [open, setOpen] = useState(false); - const [repos, setRepos] = useState([]); - - const updateInstalledRepos = async () => { - API.getCollections().then((list) => { - setInstalledRepos(list); - }); - }; - - const getInstallableRepos = () => { - API.getInstallableReposList().then((repos) => { - repos.forEach((repo) => { - repo.installing = false; - }); - setRepos(repos); - }); - }; - - useEffect(() => { - getInstallableRepos(); - updateInstalledRepos(); - }, []); - - const addRepo = (repoUrl: string) => { - API.addInstallableRepo(repoUrl) - .then(() => { - logMessage(t('hub.repo-added'), 'success'); - getInstallableRepos(); - }) - .catch((err) => { - console.error(err); - logMessage(`${t('hub.repo-add-failed')}`, 'error'); - }); - }; - - const setInstallationState = (repoUrl: string, version: string, installing: boolean) => { - const newRepos = repos.map((repo) => - repo.url === repoUrl && repo.version === version ? { ...repo, installing: installing } : repo - ); - setRepos(newRepos); - }; - - const cloneRepo = async (repoUrl: string, version: string) => { - // Clone repository - setInstallationState(repoUrl, version, true); - try { - const result = await API.cloneRepo(repoUrl, version); - if (result?.path) { - setTargetDir(result.path); - setFolderPath(result.path); - logMessage(`Cloned ${result.name} to ${result.path}`, 'success'); - setView('library'); - } else { - logMessage(t('hub.clone-return-none'), 'error'); - } - } catch (err) { - console.error(err); - logMessage(t('hub.clone-failed'), 'error'); - } - setInstallationState(repoUrl, version, false); - updateInstalledRepos(); - }; - - const isRepoInstalled = (repoUrl: string, version: string) => { - return installedRepos.some((repo) => repo.url === repoUrl && repo.version === version); - }; - - const onChangeRepoVersion = (repo, newVersion) => { - const updatedRepos = repos.map((r) => (r.url === repo.url ? { ...r, version: newVersion } : r)); - setRepos(updatedRepos); - }; - - return ( - - {' '} - {/* extra space for fixed log */} - - {allowArbitraryRepoCloning && ( - - - {t('hub.add-workflow-from-repository')} - - - {t('hub.repo')}: - setRepoUrl(e.target.value)} - size="small" - fullWidth - /> - - - {targetDir && ( - - {targetDir} - - )} - - )} - - {repos.length === 0 ? ( - - No installable workflows. - - ) : ( - - {repos.map((repo) => ( - - - - {repo.name} - - - - - - - - ))} - - )} - - - ); -} diff --git a/src/renderer/pages/Instances.tsx b/src/renderer/pages/Instances.tsx index 87a662f..8a663ee 100644 --- a/src/renderer/pages/Instances.tsx +++ b/src/renderer/pages/Instances.tsx @@ -1,16 +1,5 @@ -import React, { useState, useEffect, useMemo } from 'react'; -import { - Box, - Container, - Paper, - Stack, - Tabs, - Tab, - TextField, - Typography, - Button, - Alert -} from '@mui/material'; +import React, { useState, useEffect } from 'react'; +import { Box, Container, Paper, Typography, Button } from '@mui/material'; import Table from '@mui/material/Table'; import TableBody from '@mui/material/TableBody'; import TableCell from '@mui/material/TableCell'; @@ -20,20 +9,12 @@ import TableRow from '@mui/material/TableRow'; import Tooltip from '@mui/material/Tooltip'; import MonitorPage from './Monitor/Monitor'; import ParametersPage from './Parameters/Parameters'; -import { JsonForms } from '@jsonforms/react'; -import List from '@mui/material/List'; -import ListItem from '@mui/material/ListItem'; -import ListItemText from '@mui/material/ListItemText'; -import ListItemButton from '@mui/material/ListItemButton'; -import ListItemAvatar from '@mui/material/ListItemAvatar'; -import Avatar from '@mui/material/Avatar'; import CreatedIcon from '@mui/icons-material/PlayCircle'; import ClosedIcon from '@mui/icons-material/PlayCircle'; import RunningIcon from '@mui/icons-material/Update'; import QuestionMarkIcon from '@mui/icons-material/QuestionMark'; import CompletedIcon from '@mui/icons-material/CheckCircle'; import FailedIcon from '@mui/icons-material/Error'; -import DeleteIcon from '@mui/icons-material/Delete'; import IconButton from '@mui/material/IconButton'; import { API } from '../services/api.js'; import { useTranslation } from 'react-i18next'; @@ -119,9 +100,9 @@ const InstanceList = ({ rows, setItem, instancesList, refreshInstancesList }) => {row.workflow} - handleDeleteInstance(row.name)}> - - + ))} @@ -143,12 +124,6 @@ export default function InstancesPage({ const [rows, setRows] = useState([]); - const onLaunch = async (instance, params) => { - API.runWorkflow(instance, params, {}).then(() => { - logMessage(`Launched workflow ${instance.name}`); - }); - }; - useEffect(() => { setRows( instancesList.map((item) => diff --git a/src/renderer/pages/Library.tsx b/src/renderer/pages/Library.tsx deleted file mode 100644 index a296281..0000000 --- a/src/renderer/pages/Library.tsx +++ /dev/null @@ -1,120 +0,0 @@ -import React, { useEffect, useState } from 'react'; -import { - Button, - Container, - Paper, - Stack, - TextField, - Typography, - Box, - Grid, - Select, - Snackbar, - MenuItem, - Alert, - Link -} from '@mui/material'; -import { useTranslation } from 'react-i18next'; -import { API } from '../services/api.js'; - -export default function LibraryPage({ - repoUrl, - setRepoUrl, - targetDir, - drawerOpen, - setTargetDir, - setFolderPath, - addToInstancesList, - logMessage, - setView -}) { - const { t } = useTranslation(); - - const [repos, setRepos] = useState([]); - const [open, setOpen] = useState(false); - - const getRepos = async () => { - const list = await API.getCollections(); - const enriched = await Promise.all( - list.map(async (repo) => { - const info = await API.getWorkflowInformation(repo); - return { - ...repo, - info: { - ...(repo.info ?? {}), - title: info.title || repo.name, - description: info.description || '' - } - }; - }) - ); - setRepos(enriched); - }; - - useEffect(() => { - getRepos(); - }, []); - - const onClickSync = async (repo) => { - try { - const result = await API.syncRepo(repo.path); - if (result?.status === 'ok') { - logMessage(t('library.repo-sync-success'), 'success'); - } else { - throw new Error(result?.message || t('library.repo-sync-failed')); - } - } catch (err) { - console.error(err); - logMessage(t('library.repo-sync-failed'), 'error'); - } - }; - - return ( - - {' '} - {/* extra space for fixed log */} - - - {repos.map((repo) => ( - /* @ts-ignore */ - - - {repo.info.title} - - {repo.name} @ {repo.version} - - {repo.info.description} - - - - - - - - ))} - - - {repos.length === 0 && ( - - - {t('library.no-repos-installed')} - - - )} - - ); -} diff --git a/src/renderer/pages/Library/ActionMenu.tsx b/src/renderer/pages/Library/ActionMenu.tsx new file mode 100644 index 0000000..1dab0bb --- /dev/null +++ b/src/renderer/pages/Library/ActionMenu.tsx @@ -0,0 +1,109 @@ +import React, { useState } from 'react'; +import { Button, Box, Menu, MenuItem } from '@mui/material'; +import { useTranslation } from 'react-i18next'; +import QueryAddCatalogueDialog from './QueryAddCatalogueDialog'; +import QueryAddWorkflowDialog from './QueryAddWorkflowDialog'; +import { API } from '../../services/api.js'; + +export default function ActionMenu({ setCatalogues, permitAddCatalogues, permitAddRepos }) { + const { t } = useTranslation(); + const [showQueryCatalogueDialog, setShowQueryCatalogueDialog] = useState(false); + const [showQueryRepositoryDialog, setShowQueryRepositoryDialog] = useState(false); + const [anchorEl, setAnchorEl] = useState(null); + const menuIsOpen = Boolean(anchorEl); + + const handleMenuOpen = (event) => { + setAnchorEl(event.currentTarget); + }; + + const handleMenuClose = () => { + setAnchorEl(null); + }; + + const handleDialogClose = () => { + setShowQueryCatalogueDialog(false); + setShowQueryRepositoryDialog(false); + handleMenuClose(); + }; + + const addCatalogue = async (repo, version) => { + return API.addCatalogue(repo, version).then((result) => { + if (result.ok) { + return API.getCatalogues().then((result) => { + if (result.ok) { + setCatalogues(result.data); + } else { + throw new Error(result.error.message); + } + }); + } else { + throw new Error(result.error.message); + } + }); + }; + + const addUserWorkflow = async (name, url, version, section) => { + return API.addUserWorkflow(name, url, version, section).then((result) => { + if (result.ok) { + return API.getCatalogues().then((result) => { + if (result.ok) { + setCatalogues(result.data); + } else { + throw new Error(result.error.message); + } + }); + } else { + throw new Error(result.error.message); + } + }); + handleDialogClose(); + }; + + const display = permitAddCatalogues || permitAddRepos; + return ( + + {display && ( + <> + + + {permitAddCatalogues && ( + setShowQueryCatalogueDialog(true)} + disabled={!permitAddCatalogues} + > + {t('library.add-catalogue')} + + )} + {permitAddRepos && ( + setShowQueryRepositoryDialog(true)} + disabled={!permitAddRepos} + > + {t('library.add-repository')} + + )} + + + + + )} + + ); +} diff --git a/src/renderer/pages/Library/Library.tsx b/src/renderer/pages/Library/Library.tsx new file mode 100644 index 0000000..ed03b9a --- /dev/null +++ b/src/renderer/pages/Library/Library.tsx @@ -0,0 +1,581 @@ +import React, { useEffect, useState } from 'react'; +import { useTheme } from '@mui/material/styles'; +import { + Button, + Container, + IconButton, + Paper, + Stack, + Typography, + Box, + Grid, + Menu, + MenuItem +} from '@mui/material'; +import { useTranslation } from 'react-i18next'; +import ActionMenu from './ActionMenu'; +import ProgressDialog from './ProgressDialog'; +import MoreVertIcon from '@mui/icons-material/MoreVert'; +import { API } from '../../services/api.js'; + +const resolveHttpUrl = (path, source) => { + if (!path) return null; + if (path.startsWith('http://') || path.startsWith('https://')) { + return path; + } + if (source) { + return `${source.replace(/\/$/, '')}/${path.replace(/^\//, '')}`; + } + // Fallback + return path; +}; + +function WorkflowCard({ + workflow, + deleteWorkflow, + updateWorkflow, + scheme, + createWorkflowInstance, + refresh, + setRefresh, + logMessage +}) { + const { t } = useTranslation(); + + const [anchorEl, setAnchorEl] = useState(null); + const [isRepoInstalled, setIsRepoInstalled] = useState(false); + const [versionInstalled, setVersionInstalled] = useState(''); + const [loading, setLoading] = useState(false); + const menuIsOpen = Boolean(anchorEl); + + workflow['id'] = workflow['repo']; + workflow['version'] = workflow['version'] ?? 'latest'; + + const checkRepoInstalled = () => + API.isRepoInstalled(workflow.repo, workflow.version).then((result) => { + if (result.ok) { + const installed_version = result.data; + if (installed_version) { + setVersionInstalled(installed_version); + setIsRepoInstalled(true); + setLoading(false); + } + } else { + setIsRepoInstalled(false); + } + }); + + useEffect(() => { + checkRepoInstalled(); + }, [refresh]); + + const cloneRepo = async () => { + setLoading(true); + const result = await API.cloneRepo(workflow.repo, workflow.version); + if (result.ok) { + setLoading(false); + setRefresh(!refresh); + logMessage(`Cloned ${result.data.name} to ${result.data.path}`, 'success'); + } else { + setLoading(false); + setRefresh(!refresh); + logMessage(`${t('library.clone-error')} (${result.error.message})`, 'error'); + } + }; + + const runWorkflow = () => { + createWorkflowInstance(workflow); + }; + + const handleMenuOpen = (event) => { + setAnchorEl(event.currentTarget); + }; + + const handleMenuClose = () => { + setAnchorEl(null); + }; + + const handleDeleteWorkflow = async () => { + deleteWorkflow(); + handleMenuClose(); + }; + + const checkForUpdates = async () => { + updateWorkflow(); + handleMenuClose(); + }; + + return ( + + + {workflow.name} + + + + + + + {t('library.remove-repository')} + {workflow['version'] === 'latest' && isRepoInstalled && ( + {t('library.check-for-updates')} + )} + + + + {workflow.version}{' '} + {isRepoInstalled && workflow.version === 'latest' && `(${versionInstalled})`} + + + + {isRepoInstalled ? ( + + ) : ( + + )} + + + ); +} + +function SectionCard({ + section, + deleteSection, + deleteWorkflow, + updateWorkflow, + scheme, + source, + createWorkflowInstance, + permitCatalogueModifications, + refresh, + setRefresh, + installAllWorkflows, + logMessage +}) { + const { t } = useTranslation(); + const [anchorEl, setAnchorEl] = useState(null); + const menuIsOpen = Boolean(anchorEl); + + const handleMenuOpen = (event) => { + setAnchorEl(event.currentTarget); + }; + + const handleMenuClose = () => { + setAnchorEl(null); + }; + + const queueInstallWorkflows = async () => { + let workflows = section?.workflows || []; + await installAllWorkflows( + workflows.map((workflow) => ({ + id: `${workflow.repo}@${workflow.version}`, + repo: workflow.repo, + version: workflow.version + })) + ); + setRefresh(!refresh); + handleMenuClose(); + }; + + const handleDeleteSection = async () => { + deleteSection(); + handleMenuClose(); + }; + + return ( + + + {section?.icon && ( + { + e.currentTarget.style.display = 'none'; + }} + /> + )} + + + {section.name} + + {section.description && ( + + {section.description} + + )} + + {permitCatalogueModifications && ( + <> + + + + + + + + {t('library.install-all-workflows')} + + {t('library.remove-section')} + + + )} + + + {(section?.workflows || []).map((workflow) => ( + + deleteWorkflow(workflow)} + updateWorkflow={() => updateWorkflow(workflow)} + scheme={scheme} + createWorkflowInstance={createWorkflowInstance} + refresh={refresh} + setRefresh={setRefresh} + logMessage={logMessage} + /> + + ))} + + + ); +} + +function CatalogueCard({ + catalogue, + deleteCatalogue, + deleteSection, + deleteWorkflow, + updateWorkflow, + createWorkflowInstance, + permitCatalogueModifications, + refresh, + setRefresh, + installAllWorkflows, + logMessage +}) { + const { t } = useTranslation(); + const theme = useTheme(); + const [anchorEl, setAnchorEl] = useState(null); + const menuIsOpen = Boolean(anchorEl); + + const handleMenuOpen = (event) => { + setAnchorEl(event.currentTarget); + }; + + const handleMenuClose = () => { + setAnchorEl(null); + }; + + const queueInstallWorkflows = async () => { + let workflows = []; + for (const section of catalogue.sections || []) { + for (const workflow of section.workflows || []) { + workflows.push({ + id: `${workflow.repo}@${workflow.version}`, + repo: workflow.repo, + version: workflow.version + }); + } + } + await installAllWorkflows(workflows); + setRefresh(!refresh); + handleMenuClose(); + }; + + const handleDeleteCatalogue = async () => { + deleteCatalogue(); + handleMenuClose(); + }; + + const checkForUpdates = async () => { + await API.syncRepo(catalogue?.['base_dir']); + handleMenuClose(); + }; + + return ( + + + {catalogue?.icon && ( + { + e.currentTarget.style.display = 'none'; + }} + /> + )} + + {catalogue.name} + {catalogue.description && ( + {catalogue.description} + )} + + {permitCatalogueModifications && ( + <> + + + + + + + + {t('library.install-all-workflows')} + + {t('library.remove-catalogue')} + {catalogue?.name !== 'User collection' && ( + {t('library.check-for-updates')} + )} + + + )} + + + {(catalogue?.sections || []).map((section) => ( + deleteSection(section)} + deleteWorkflow={(workflow) => deleteWorkflow(section, workflow)} + updateWorkflow={(workflow) => updateWorkflow(section, workflow)} + scheme={catalogue?.scheme || {}} + source={catalogue?.['base_dir']} + createWorkflowInstance={createWorkflowInstance} + permitCatalogueModifications={permitCatalogueModifications} + refresh={refresh} + setRefresh={setRefresh} + installAllWorkflows={installAllWorkflows} + logMessage={logMessage} + /> + ))} + + + ); +} + +export default function LibraryPage({ + createWorkflowInstance, + permitAddCatalogues, + permitCatalogueModifications, + permitAddRepos, + logMessage +}) { + const { t } = useTranslation(); + const [catalogues, setCatalogues] = useState([]); + const [refresh, setRefresh] = useState(false); + + const [progressCount, setProgressCount] = useState(0); + const [progressValue, setProgressValue] = useState(0); + + const getCatalogues = async () => { + API.getCatalogues().then((result) => { + if (result.ok) { + setCatalogues(result.data); + } + }); + }; + + useEffect(() => { + getCatalogues(); + }, []); + + const deleteCatalogue = async (catalogue) => { + if (!window.confirm(t('library.confirm-remove-catalogue', { name: catalogue.name }))) { + return; + } + API.removeCatalogue(catalogue.name).then((result) => { + if (result.ok) { + logMessage(t('library.catalogue-removed-success', { name: catalogue.name }), 'success'); + getCatalogues(); + } else { + logMessage(t('library.catalogue-removed-failure', { name: catalogue.name }), 'error'); + } + }); + }; + + const deleteSection = async (catalogue, section) => { + if (!window.confirm(t('library.confirm-remove-section', { name: section.name }))) { + return; + } + API.removeCatalogueSection(catalogue.name, section.name).then((result) => { + if (result.ok) { + logMessage(t('library.section-removed-success', { name: section.name }), 'success'); + getCatalogues(); + } else { + logMessage(t('library.section-removed-failure', { name: section.name }), 'error'); + } + }); + }; + + const deleteWorkflow = (catalogue, section, workflow) => { + if (!window.confirm(t('library.confirm-remove-workflow', { name: workflow.name }))) { + return; + } + API.removeCatalogueWorkflow(catalogue.name, section.name, workflow.name).then((result) => { + if (result.ok) { + logMessage(t('library.workflow-removed-success', { name: workflow.name }), 'success'); + getCatalogues(); + } else { + logMessage(t('library.workflow-removed-failure', { name: workflow.name }), 'error'); + } + }); + }; + + const updateWorkflow = (catalogue, section, workflow) => { + API.updateCatalogueWorkflow(catalogue.name, section.name, workflow.name).then((result) => { + if (result.ok) { + logMessage(t('library.workflow-updated-success', { name: workflow.name }), 'success'); + getCatalogues(); + } else { + logMessage(t('library.workflow-updated-failure', { name: workflow.name }), 'error'); + } + }); + }; + + const installAllWorkflows = async (workflows) => { + // Remove duplicates + workflows = workflows.filter( + (workflow, index, self) => index === self.findIndex((w) => w.id === workflow.id) + ); + // Clone + setProgressValue(0); + setProgressCount(workflows.length); + const failed_list = []; + for (const workflow of workflows) { + const result = await API.cloneRepo(workflow.repo, workflow.version); + if (!result.ok) { + failed_list.push(workflow.id); + } + setProgressValue((prev) => prev + 1); + } + setProgressCount(0); + setProgressValue(0); + if (failed_list.length > 0) { + const failed_str = failed_list.join(', '); + logMessage(`${t('library.install-workflows-completed-with-errors')}: ${failed_str}`, 'error'); + } + setRefresh(!refresh); + }; + + return ( + + + 0} + title={t('library.installing-workflows')} + value={progressValue} + total={progressCount} + /> + + {(catalogues || []).map((catalogue) => ( + deleteCatalogue(catalogue)} + deleteSection={(section) => deleteSection(catalogue, section)} + deleteWorkflow={(section, workflow) => deleteWorkflow(catalogue, section, workflow)} + updateWorkflow={(section, workflow) => updateWorkflow(catalogue, section, workflow)} + createWorkflowInstance={createWorkflowInstance} + permitCatalogueModifications={permitCatalogueModifications} + refresh={refresh} + setRefresh={setRefresh} + installAllWorkflows={installAllWorkflows} + logMessage={logMessage} + /> + ))} + + {catalogues.length === 0 && ( + + + {t('library.no-repos-installed')} + + + )} + + ); +} diff --git a/src/renderer/pages/Library/ProgressDialog.tsx b/src/renderer/pages/Library/ProgressDialog.tsx new file mode 100644 index 0000000..cb9c137 --- /dev/null +++ b/src/renderer/pages/Library/ProgressDialog.tsx @@ -0,0 +1,48 @@ +import React, { useEffect } from 'react'; +import { + Dialog, + DialogTitle, + DialogContent, + DialogContentText, + Box, + LinearProgress +} from '@mui/material'; + +type ProgressDialogProps = { + open: boolean; + title: string; + message?: string; + value: number; + total: number; +}; + +export default function ProgressDialog({ + open, + title, + message, + value, + total +}: ProgressDialogProps) { + const [progress, setProgress] = React.useState(0); + + useEffect(() => { + if (total > 0) { + const calculatedProgress = (value / total) * 100; + setProgress(calculatedProgress); + } else { + setProgress(0); + } + }, [value, total]); + + return ( + + {title} + + {message && {message}} + + + + + + ); +} diff --git a/src/renderer/pages/Library/QueryAddCatalogueDialog.tsx b/src/renderer/pages/Library/QueryAddCatalogueDialog.tsx new file mode 100644 index 0000000..e83ca01 --- /dev/null +++ b/src/renderer/pages/Library/QueryAddCatalogueDialog.tsx @@ -0,0 +1,91 @@ +import React, { useEffect } from 'react'; +import { + Alert, + Button, + Dialog, + DialogTitle, + DialogContent, + DialogActions, + FormControl, + Typography, + TextField +} from '@mui/material'; +import { useTranslation } from 'react-i18next'; + +export default function QueryAddCatalogueDialog({ open, action, onClose }) { + const { t } = useTranslation(); + + const [repo, setRepo] = React.useState(''); + const [loading, setLoading] = React.useState(false); + const [error, setError] = React.useState(null); + + const handleLaunch = async () => { + // Validate inputs + if (!repo) { + setError(t('library.add-catalogue-dialog.error-repo-required')); + return; + } + // Perform action + const version = ''; + setLoading(true); + action(repo, version) + .then(() => { + // close the dialog after action is completed successfully + setLoading(false); + onClose(); + }) + .catch(() => { + setLoading(false); + setError(t('library.add-catalogue-dialog.error-unable-to-add')); + }); + }; + + useEffect(() => { + // Reset state when dialog is opened + setRepo(''); + setError(null); + }, [open]); + + return ( + +
{ + e.preventDefault(); + handleLaunch(); + }} + > + + {t('library.add-catalogue-dialog.title')} + + + + + {t('library.add-catalogue-dialog.description')} + + + {error && ( + + {error} + + )} + + + setRepo(e.target.value)} + autoFocus + /> + + + + + + + +
+
+ ); +} diff --git a/src/renderer/pages/Library/QueryAddWorkflowDialog.tsx b/src/renderer/pages/Library/QueryAddWorkflowDialog.tsx new file mode 100644 index 0000000..b3bd781 --- /dev/null +++ b/src/renderer/pages/Library/QueryAddWorkflowDialog.tsx @@ -0,0 +1,136 @@ +import React, { useEffect } from 'react'; +import { + Alert, + Button, + Dialog, + DialogTitle, + DialogContent, + DialogActions, + FormControl, + Typography, + TextField +} from '@mui/material'; +import { useTranslation } from 'react-i18next'; + +export default function QueryAddWorkflowDialog({ open, action, onClose }) { + const { t } = useTranslation(); + + const default_version = 'latest'; + const default_section = 'My Workflows'; + + const [name, setName] = React.useState(''); + const [repo, setRepo] = React.useState(''); + const [version, setVersion] = React.useState(default_version); + const [section, setSection] = React.useState(default_section); + + const [loading, setLoading] = React.useState(false); + const [error, setError] = React.useState(null); + + const handleLaunch = async () => { + // Validate inputs + if (!repo) { + setError(t('library.add-workflow-dialog.error-repo-required')); + return; + } + if (!section) { + setError(t('library.add-workflow-dialog.error-section-required')); + return; + } + // Perform the action + setLoading(true); + action(name, repo, version, section) + .then(() => { + // close the dialog after action is completed successfully + setLoading(false); + onClose(); + }) + .catch((error) => { + setLoading(false); + setError(`${t('library.add-workflow-dialog.error-unable-to-add')} +(${error.message})`); + }); + }; + + useEffect(() => { + // Reset state when dialog is opened + setName(''); + setRepo(''); + setVersion(default_version); + setSection(default_section); + setError(null); + }, [open]); + + return ( + +
{ + e.preventDefault(); + handleLaunch(); + }} + > + + {t('library.add-workflow-dialog.title')} + + + + + {t('library.add-workflow-dialog.description')} + + + {error && ( + + {error} + + )} + + + setRepo(e.target.value)} + autoFocus + /> + + + + setVersion(e.target.value)} + /> + + + + setName(e.target.value)} + /> + + + + setSection(e.target.value)} + /> + + + + + + + +
+
+ ); +} diff --git a/src/renderer/pages/Main.tsx b/src/renderer/pages/Main.tsx index a39ba9c..8dc3f54 100644 --- a/src/renderer/pages/Main.tsx +++ b/src/renderer/pages/Main.tsx @@ -1,81 +1,43 @@ -import React, { useState, useEffect, useMemo } from 'react'; -import { uniqueNamesGenerator, adjectives, animals } from 'unique-names-generator'; +import React, { useState, useEffect } from 'react'; import { - AppBar, Box, - Button, Drawer, - IconButton, List, ListItem, ListItemText, - Stack, - TextField, Typography, Snackbar, Paper, Alert } from '@mui/material'; import { Panel, PanelGroup, PanelResizeHandle } from 'react-resizable-panels'; -import Toolbar from '@mui/material/Toolbar'; -import MenuIcon from '@mui/icons-material/Menu'; -import HubIcon from '@mui/icons-material/Hub'; import LibraryIcon from '@mui/icons-material/Apps'; import InstancesIcon from '@mui/icons-material/Storage'; import SettingsIcon from '@mui/icons-material/Settings'; import ListItemIcon from '@mui/material/ListItemIcon'; -import Select from '@mui/material/Select'; -import MenuItem from '@mui/material/MenuItem'; +import ListItemButton from '@mui/material/ListItemButton'; import { useTranslation } from 'react-i18next'; -import HubPage from './Hub'; -import LibraryPage from './Library'; +import LibraryPage from './Library/Library'; import InstancesPage from './Instances'; import SettingsPage from './Settings/Settings'; -import TitleBar from './TitleBar'; +import { SettingsKey } from '../../types/settings.js'; import { API } from '../services/api.js'; -const defaultRepoUrl = 'jsbrittain/workflow-runner-testworkflow'; -const defaultImageName = 'testworkflow'; - -type navbar_page = 'hub' | 'library' | 'instances' | 'settings'; +type navbar_page = 'library' | 'instances' | 'settings'; type severityLevels = 'info' | 'success' | 'warning' | 'error'; -// Quick function to predict target directory based on repo URL and base collections path -// Replace this with a call to the backend -const computeTargetDir = (repoUrl, basePath) => { - try { - if (repoUrl.includes('://')) { - const url = new URL(repoUrl); - const [owner, repo] = url.pathname - .replace(/^\//, '') - .replace(/\.git$/, '') - .split('/'); - return `${basePath}/workflows/${owner}/${repo}`; - } else if (repoUrl.includes('/')) { - const [owner, repo] = repoUrl.replace(/\.git$/, '').split('/'); - return `${basePath}/workflows/${owner}/${repo}`; - } - } catch { - return ''; - } -}; - export default function MainPage({ darkMode, setDarkMode }) { const { t } = useTranslation(); - const [repoUrl, setRepoUrl] = useState(defaultRepoUrl); const [collectionsPath, setCollectionsPath] = useState(''); - const [allowArbitraryRepoCloning, setAllowArbitraryRepoCloning] = useState(true); - const [targetDir, setTargetDir] = useState(''); - const [folderPath, setFolderPath] = useState(''); - const [imageName, setImageName] = useState(defaultImageName); - const [output, setOutput] = useState(''); - const [drawerOpen, setDrawerOpen] = useState(false); - const [view, setView] = useState('hub'); + const [permitAddCatalogues, setPermitAddCatalogues] = useState(true); + const [permitCatalogueModifications, setPermitCatalogueModifications] = useState(true); + const [permitAddRepos, setPermitAddRepos] = useState(true); + const [drawerOpen] = useState(true); + const [view, setView] = useState('library'); const [instancesList, setInstancesList] = useState([]); const [log, setLog] = useState([]); - const [projectsList, setProjectsList] = useState([]); const [severity, setSeverity] = useState('info'); const [message, setMessage] = useState(''); const [open, setOpen] = useState(false); @@ -92,57 +54,24 @@ export default function MainPage({ darkMode, setDarkMode }) { }); }; - const getProjectsList = async () => { - const all_project = { - id: 'all', - name: 'All', - url: undefined, - workflows: [] - }; - API.getProjectsList().then((projects) => { - setProjectsList([all_project, ...projects]); - }); - }; - useEffect(() => { (async () => { + API.settingsGet(SettingsKey.PermitAddCatalogues).then((result) => { + setPermitAddCatalogues(result); + }); + API.settingsGet(SettingsKey.PermitCatalogueModifications).then((result) => { + setPermitCatalogueModifications(result); + }); + API.settingsGet(SettingsKey.PermitAddRepos).then((result) => { + setPermitAddRepos(result); + }); const path = await API.getCollectionsPath(); setCollectionsPath(path); refreshInstancesList(); - getProjectsList(); })(); }, []); - useEffect(() => { - const predictedPath = computeTargetDir(repoUrl, collectionsPath); - setTargetDir(predictedPath); - }, [repoUrl, collectionsPath]); - - const handlePathChange = (e) => { - const value = e.target.value; - setCollectionsPath(value); - API.setCollectionsPath(value); - }; - - const handleList = async () => { - const containers = await API.listContainers(); - setOutput(JSON.stringify(containers, null, 2)); - }; - - const generateUniqueName = (baseName, queue) => { - let newName = ''; - const existingNames = new Set(queue.map((item) => item.name)); - do { - newName = uniqueNamesGenerator({ - dictionaries: [adjectives, animals], - separator: '-', - length: 2 - }); - } while (existingNames.has(newName)); - return newName; - }; - - const addToInstancesList = async (repo) => { + const createWorkflowInstance = async (repo) => { const workflow_id = repo.id; API.createWorkflowInstance(workflow_id, repo.version).then((instance) => { setInstancesList((prev) => { @@ -163,21 +92,14 @@ export default function MainPage({ darkMode, setDarkMode }) { return ( - - theme.transitions.create('width', { @@ -187,37 +109,57 @@ export default function MainPage({ darkMode, setDarkMode }) { } }} > - - setView('hub')}> - - - - {drawerOpen && } - - setView('library')}> - - - - {drawerOpen && } + ({ + '& .MuiListItemButton-root.Mui-selected': { + boxShadow: `inset 4px 0 0 ${theme.palette.primary.main}`, + '& .MuiListItemIcon-root': { + color: theme.palette.primary.main + }, + '&:hover': { + backgroundColor: theme.palette.action.selected + } + } + })} + > + + setView('library')} + > + + + + {drawerOpen && } + - { - setItem(''); - setView('instances'); - }} - > - - - - {drawerOpen && } + + { + setItem(''); + setView('instances'); + }} + > + + + + {drawerOpen && } + - setView('settings')}> - - - - {drawerOpen && } + + setView('settings')} + > + + + + {drawerOpen && } + @@ -229,30 +171,13 @@ export default function MainPage({ darkMode, setDarkMode }) { sx={{ width: '100%', height: '100%', overflowY: 'auto', minHeight: 0, p: 3 }} square > - - {view === 'hub' ? ( - - ) : view === 'library' ? ( + {view === 'library' ? ( ) : view === 'instances' ? ( ) : null} diff --git a/src/renderer/pages/Monitor/HeaderMenu.tsx b/src/renderer/pages/Monitor/HeaderMenu.tsx index ee69e0e..4278ce6 100644 --- a/src/renderer/pages/Monitor/HeaderMenu.tsx +++ b/src/renderer/pages/Monitor/HeaderMenu.tsx @@ -1,48 +1,14 @@ -import React, { useEffect } from 'react'; -import { Box, Tabs, Tab, Paper, Typography } from '@mui/material'; +import React from 'react'; +import { Box, Typography } from '@mui/material'; import Button from '@mui/material/Button'; import Menu from '@mui/material/Menu'; import MenuItem from '@mui/material/MenuItem'; -import IconButton from '@mui/material/IconButton'; -import DoneIcon from '@mui/icons-material/Done'; -import CancelIcon from '@mui/icons-material/Cancel'; -import RefreshIcon from '@mui/icons-material/Refresh'; -import AnsiLog from '../AnsiLog.js'; import { API } from '../../services/api.js'; import { useTranslation } from 'react-i18next'; -import FolderOutlinedIcon from '@mui/icons-material/FolderOutlined'; -import DescriptionOutlinedIcon from '@mui/icons-material/DescriptionOutlined'; - -interface TabPanelProps { - children?: React.ReactNode; - index: number; - value: number; -} - -function TabPanel(props: TabPanelProps) { - const { children, value, index, ...other } = props; - return ( - - ); -} - -const SECOND = 1000; - -const STATUS_ICONS = { - created: , - starting: , - submitted: , - completed: , - error: -}; export default function HeaderMenu({ instance, logMessage }) { const { t } = useTranslation(); const [anchorEl, setAnchorEl] = React.useState(null); - const [processRunning, setProcessRunning] = React.useState(true); // ####### check if the process is running - const [processHasRunHistory, setProcessHasRunHistory] = React.useState(true); // ####### check if the process has run history const handleExecutionActionsMenuClose = () => { setAnchorEl(null); @@ -64,7 +30,7 @@ export default function HeaderMenu({ instance, logMessage }) { if (!window.confirm(t('monitor.execution.resume-confirm'))) { return; } - const id = await API.runWorkflow(instance, {}, { resume: true }); + await API.runWorkflow(instance, {}, { resume: true }); logMessage(`${t('monitor.execution.resuming')}: ${instance.id}.`); }; @@ -121,24 +87,16 @@ export default function HeaderMenu({ instance, logMessage }) { anchorOrigin={{ vertical: 'top', horizontal: 'left' }} transformOrigin={{ vertical: 'top', horizontal: 'left' }} > - handleExecutionCancel()} disabled={!processRunning}> + handleExecutionCancel()}> {t('monitor.execution.cancel')} - handleExecutionResume()} - disabled={processRunning && processHasRunHistory} - > + handleExecutionResume()}> {t('monitor.execution.resume')} - handleExecutionRestart()} - disabled={!processHasRunHistory} - > + handleExecutionRestart()}> {t('monitor.execution.restart')} - handleExecutionKill()} disabled={!processRunning}> + handleExecutionKill()}> {t('monitor.execution.kill')} diff --git a/src/renderer/pages/Monitor/HtmlReports.tsx b/src/renderer/pages/Monitor/HtmlReports.tsx index 347fb0a..993bd22 100644 --- a/src/renderer/pages/Monitor/HtmlReports.tsx +++ b/src/renderer/pages/Monitor/HtmlReports.tsx @@ -1,22 +1,10 @@ -import React, { useEffect } from 'react'; -import { Box, Tabs, Tab, Paper, Typography } from '@mui/material'; -import Button from '@mui/material/Button'; -import Menu from '@mui/material/Menu'; +import React from 'react'; +import { Box, Typography } from '@mui/material'; import MenuItem from '@mui/material/MenuItem'; import Select from '@mui/material/Select'; -import IconButton from '@mui/material/IconButton'; -import DoneIcon from '@mui/icons-material/Done'; -import CancelIcon from '@mui/icons-material/Cancel'; -import RefreshIcon from '@mui/icons-material/Refresh'; import FormControl from '@mui/material/FormControl'; -import AnsiLog from './AnsiLog.js'; import { API } from '../../services/api.js'; import { useTranslation } from 'react-i18next'; -import FolderOutlinedIcon from '@mui/icons-material/FolderOutlined'; -import DescriptionOutlinedIcon from '@mui/icons-material/DescriptionOutlined'; - -import HeaderMenu from './HeaderMenu'; -import ProgressTracker from './ProgressTracker'; export default function HtmlReports({ instance }) { const { t } = useTranslation(); diff --git a/src/renderer/pages/Monitor/Logs.tsx b/src/renderer/pages/Monitor/Logs.tsx index d307817..418a4dd 100644 --- a/src/renderer/pages/Monitor/Logs.tsx +++ b/src/renderer/pages/Monitor/Logs.tsx @@ -1,21 +1,7 @@ -import React, { useEffect } from 'react'; -import { Box, Tabs, Tab, Paper, Typography } from '@mui/material'; -import Button from '@mui/material/Button'; -import Menu from '@mui/material/Menu'; -import MenuItem from '@mui/material/MenuItem'; -import IconButton from '@mui/material/IconButton'; -import DoneIcon from '@mui/icons-material/Done'; -import CancelIcon from '@mui/icons-material/Cancel'; -import RefreshIcon from '@mui/icons-material/Refresh'; +import React from 'react'; +import { Box, Tabs, Tab, Paper } from '@mui/material'; import AnsiLog from './AnsiLog.js'; -import HtmlReports from './HtmlReports.js'; -import { API } from '../../services/api.js'; import { useTranslation } from 'react-i18next'; -import FolderOutlinedIcon from '@mui/icons-material/FolderOutlined'; -import DescriptionOutlinedIcon from '@mui/icons-material/DescriptionOutlined'; - -import HeaderMenu from './HeaderMenu'; -import ProgressTracker from './ProgressTracker'; interface TabPanelProps { children?: React.ReactNode; @@ -32,14 +18,10 @@ function TabPanel(props: TabPanelProps) { ); } -const SECOND = 1000; - -export default function LogsPage({ instance, stdOut, stdErr, nextflowLog, logMessage }) { +export default function LogsPage({ stdOut, stdErr, nextflowLog }) { const { t } = useTranslation(); - const [nextflowProgress, setNextflowProgress] = React.useState(''); const [tabSelected, setTabSelected] = React.useState(0); - const [workflowStatus, setWorkflowStatus] = React.useState('unknown'); const handleTabChange = (event, newValue) => { setTabSelected(newValue); diff --git a/src/renderer/pages/Monitor/Monitor.tsx b/src/renderer/pages/Monitor/Monitor.tsx index 28a96a3..41e2341 100644 --- a/src/renderer/pages/Monitor/Monitor.tsx +++ b/src/renderer/pages/Monitor/Monitor.tsx @@ -1,19 +1,9 @@ import React, { useEffect } from 'react'; -import { Box, Tabs, Tab, Paper, Typography } from '@mui/material'; -import Button from '@mui/material/Button'; -import Menu from '@mui/material/Menu'; -import MenuItem from '@mui/material/MenuItem'; -import IconButton from '@mui/material/IconButton'; -import DoneIcon from '@mui/icons-material/Done'; -import CancelIcon from '@mui/icons-material/Cancel'; -import RefreshIcon from '@mui/icons-material/Refresh'; -import AnsiLog from './AnsiLog.js'; +import { Box, Tabs, Tab, Paper } from '@mui/material'; import HtmlReports from './HtmlReports.js'; import LogsPage from './Logs.js'; import { API } from '../../services/api.js'; import { useTranslation } from 'react-i18next'; -import FolderOutlinedIcon from '@mui/icons-material/FolderOutlined'; -import DescriptionOutlinedIcon from '@mui/icons-material/DescriptionOutlined'; import HeaderMenu from './HeaderMenu'; import ProgressTracker from './ProgressTracker'; @@ -35,14 +25,6 @@ function TabPanel(props: TabPanelProps) { const SECOND = 1000; -const STATUS_ICONS = { - created: , - starting: , - submitted: , - completed: , - error: -}; - export default function MonitorPage({ instance, logMessage }) { const { t } = useTranslation(); @@ -115,13 +97,7 @@ export default function MonitorPage({ instance, logMessage }) { - + ); diff --git a/src/renderer/pages/Monitor/ProgressTracker.tsx b/src/renderer/pages/Monitor/ProgressTracker.tsx index 752c2b2..879499d 100644 --- a/src/renderer/pages/Monitor/ProgressTracker.tsx +++ b/src/renderer/pages/Monitor/ProgressTracker.tsx @@ -1,8 +1,5 @@ import React, { useEffect } from 'react'; -import { Box, Tabs, Tab, Paper, Typography } from '@mui/material'; -import Button from '@mui/material/Button'; -import Menu from '@mui/material/Menu'; -import MenuItem from '@mui/material/MenuItem'; +import { Box, Typography } from '@mui/material'; import IconButton from '@mui/material/IconButton'; import DoneIcon from '@mui/icons-material/Done'; import CancelIcon from '@mui/icons-material/Cancel'; @@ -55,7 +52,7 @@ export default function ProgressTracker({ instance, nextflowProgress, workflowSt return () => clearInterval(interval); }, [showWork]); - const FormatWorkflowStatus = ({ workflowStatus: string }) => { + const FormatWorkflowStatus = ({ workflowStatus }: { workflowStatus: string }) => { let color_palette = 'info'; if (workflowStatus === WorkflowStatus.Failed) { color_palette = 'error'; diff --git a/src/renderer/pages/Parameters/FilePathControl.tsx b/src/renderer/pages/Parameters/FilePathControl.tsx index 46bd6cc..050d7f0 100644 --- a/src/renderer/pages/Parameters/FilePathControl.tsx +++ b/src/renderer/pages/Parameters/FilePathControl.tsx @@ -47,7 +47,6 @@ function InnerFilePathControl(props: ControlProps) { (uischema as any)?.options?.description ?? schema?.description ?? (schema as any)?.help_text; const showDesc = !isDescriptionHidden(visible, description, config); - const accept = (uischema as any)?.options?.accept as string | undefined; type PickerMode = 'file' | 'directory' | 'both'; diff --git a/src/renderer/pages/Parameters/Parameters.tsx b/src/renderer/pages/Parameters/Parameters.tsx index a1430fc..09dcfc3 100644 --- a/src/renderer/pages/Parameters/Parameters.tsx +++ b/src/renderer/pages/Parameters/Parameters.tsx @@ -1,26 +1,6 @@ import React, { useState, useEffect, useMemo } from 'react'; -import { - Box, - Container, - Paper, - Stack, - Tabs, - Tab, - TextField, - Typography, - Button, - Alert -} from '@mui/material'; +import { Box, Paper, Stack, Tabs, Tab, Typography, Button } from '@mui/material'; import { JsonForms } from '@jsonforms/react'; -import List from '@mui/material/List'; -import ListItem from '@mui/material/ListItem'; -import ListItemText from '@mui/material/ListItemText'; -import ListItemButton from '@mui/material/ListItemButton'; -import ListItemAvatar from '@mui/material/ListItemAvatar'; -import Avatar from '@mui/material/Avatar'; -import NotStartedIcon from '@mui/icons-material/NotStarted'; -import DeleteIcon from '@mui/icons-material/Delete'; -import IconButton from '@mui/material/IconButton'; import Ajv, { ErrorObject } from 'ajv'; // ajv is also used by jsonforms import { buildUISchema } from './buildUISchema'; import { renderers } from './renderers'; @@ -72,19 +52,18 @@ export default function ParametersPage({ instance, refreshInstancesList, logMess const profile = params['profile'] || default_profile; delete call_params['profile']; // Return PID on success - const res = await API.runWorkflow(instance, call_params, { profile: profile }); - if (!res.ok) { - logMessage(`Error launching workflow: ${res.error.message || 'Unknown error'}`, 'error'); + const result = await API.runWorkflow(instance, call_params, { profile: profile }); + if (!result.ok) { + logMessage(`Error launching workflow: ${result.error.message || 'Unknown error'}`, 'error'); return; } - const id = res.data as number; logMessage(`Launched workflow ${instance.name}`); refreshInstancesList(); }; const onTestLaunchWorkflow = async (testProfiles) => { const test_profiles_str = testProfiles.join(','); - const id = await API.runWorkflow(instance, {}, { profile: test_profiles_str }); + await API.runWorkflow(instance, {}, { profile: test_profiles_str }); logMessage(`Launched test workflow ${instance.name}`); refreshInstancesList(); }; @@ -216,7 +195,7 @@ export default function ParametersPage({ instance, refreshInstancesList, logMess uischema={uischema} data={params} renderers={renderers} - onChange={({ data, errors }) => setParams(data)} + onChange={({ data }) => setParams(data)} ajv={disableSchemaValidation ? undefined : ajv} /> ) : ( diff --git a/src/renderer/pages/Settings/Environment.tsx b/src/renderer/pages/Settings/Environment.tsx index d2faa57..d96e684 100644 --- a/src/renderer/pages/Settings/Environment.tsx +++ b/src/renderer/pages/Settings/Environment.tsx @@ -5,7 +5,7 @@ import { EnvironmentKey } from '../../../types/environment.js'; import { useTranslation } from 'react-i18next'; export default function EnvironmentPage() { - const { t, i18n } = useTranslation(); + const { t } = useTranslation(); const [nextflowStatus, setNextflowStatus] = React.useState([]); const [performingAction, setPerformingAction] = React.useState(null); @@ -21,7 +21,7 @@ export default function EnvironmentPage() { const handlePerformAction = async (id: string) => { setPerformingAction(id); - API.performEnvironmentAction(EnvironmentKey.Nextflow, id).then((msg) => { + API.performEnvironmentAction(EnvironmentKey.Nextflow, id).then(() => { getEnvironmentStatus(); // refresh status after action setPerformingAction(null); }); @@ -39,7 +39,7 @@ export default function EnvironmentPage() { {item.description} - {(item?.actions || []).map((action, actionIndex) => ( + {(item?.actions || []).map((action) => ( diff --git a/src/renderer/pages/Settings/ProjectsList.tsx b/src/renderer/pages/Settings/ProjectsList.tsx deleted file mode 100644 index e920bca..0000000 --- a/src/renderer/pages/Settings/ProjectsList.tsx +++ /dev/null @@ -1,88 +0,0 @@ -import React from 'react'; -import { - Container, - Box, - Button, - Typography, - Switch, - FormControlLabel, - TextField, - Select, - MenuItem, - Paper, - IconButton -} from '@mui/material'; -import DeleteIcon from '@mui/icons-material/Delete'; -import { useTranslation } from 'react-i18next'; -import { API } from '../../services/api.js'; - -export default function ProjectsList({ projectsList, getProjectsList, logMessage }) { - const { t } = useTranslation(); - const [projectUrl, setProjectUrl] = React.useState(''); - - const onClickRemoveProject = (project) => { - API.removeProject(project).then((msg) => { - if (msg) { - logMessage(`${t('settings.projects.remove-failure')}: ${msg}`, 'error'); - } else { - getProjectsList(); - } - }); - }; - - const onClickAddProject = () => { - API.addProject(projectUrl).then((msg) => { - if (!msg) { - // success - getProjectsList(); - setProjectUrl(''); - } else { - logMessage(`${t('settings.projects.add-failure')}: ${msg}`, 'error'); - } - }); - }; - - const onKeyDownUrl = (e) => { - if (e.key === 'Enter') { - onClickAddProject(); - } - }; - - return ( - - {projectsList.map((project, index) => { - if (project.name === 'All' || project.url === undefined) return null; - return ( - - - {project.name || t('settings.projects.unnamed')} - {project.url} - - onClickRemoveProject(project)}> - - - - ); - })} - - {projectsList.length < 2 && ( - - {t('settings.projects.no-projects')} - - )} - - setProjectUrl(e.target.value)} - onKeyDown={onKeyDownUrl} - /> - - - - ); -} diff --git a/src/renderer/pages/Settings/Settings.tsx b/src/renderer/pages/Settings/Settings.tsx index ef02051..9e8c901 100644 --- a/src/renderer/pages/Settings/Settings.tsx +++ b/src/renderer/pages/Settings/Settings.tsx @@ -1,7 +1,6 @@ import React, { useEffect } from 'react'; import { Box, - Container, Typography, Switch, FormControlLabel, @@ -13,12 +12,10 @@ import { Tab, Tabs } from '@mui/material'; -import ProjectsList from './ProjectsList.js'; import EnvironmentPage from './Environment.js'; import LicensesPage from './Licenses.js'; import { API } from '../../services/api.js'; import { SettingsKey } from '../../../types/settings.js'; -import { EnvironmentKey } from '../../../types/environment.js'; import { useTranslation } from 'react-i18next'; export default function SettingsPage({ @@ -26,20 +23,19 @@ export default function SettingsPage({ setDarkMode, collectionsPath, setCollectionsPath, - allowArbitraryRepoCloning, - setAllowArbitraryRepoCloning, - projectsList, - getProjectsList, - logMessage + permitAddCatalogues, + setPermitAddCatalogues, + permitCatalogueModifications, + setPermitCatalogueModifications, + permitAddRepos, + setPermitAddRepos }) { const { t, i18n } = useTranslation(); const pathRef = React.useRef(null); const [language, setLanguage] = React.useState(i18n.language || 'en'); const [tabValue, setTabValue] = React.useState(0); - const [disableProjects, setDisableProjects] = React.useState(false); const [disableSchemaValidation, setDisableSchemaValidation] = React.useState(false); - const [nextflowStatus, setNextflowStatus] = React.useState([]); const handlePathKeyDown = (e) => { if (e.key === 'Enter') { @@ -64,9 +60,24 @@ export default function SettingsPage({ i18n.changeLanguage(newLang); }; - const handleDisableProjects = (value) => { - setDisableProjects(value); - API.settingsSet(SettingsKey.DisableProjects, value); + const handlePermitAddCatalogues = (value) => { + setPermitAddCatalogues(value); + API.settingsSet(SettingsKey.PermitAddCatalogues, value); + }; + + const handlePermitCatalogueModifications = (value) => { + setPermitCatalogueModifications(value); + API.settingsSet(SettingsKey.PermitCatalogueModifications, value); + }; + + const handlePermitAddRepos = (value) => { + setPermitAddRepos(value); + API.settingsSet(SettingsKey.PermitAddRepos, value); + }; + + const handleDarkMode = (value) => { + setDarkMode(value); + API.settingsSet(SettingsKey.DarkMode, value); }; const handleDisableSchemaValidation = (value) => { @@ -75,14 +86,20 @@ export default function SettingsPage({ }; useEffect(() => { - API.settingsGet(SettingsKey.DisableSchemaValidation).then((value) => { - setDisableSchemaValidation(value); + API.settingsGet(SettingsKey.DarkMode).then((value) => { + setDarkMode(value); + }); + API.settingsGet(SettingsKey.PermitAddCatalogues).then((value) => { + setPermitAddCatalogues(value); }); - API.settingsGet(SettingsKey.DisableProjects).then((value) => { - setDisableProjects(value); + API.settingsGet(SettingsKey.PermitCatalogueModifications).then((value) => { + setPermitCatalogueModifications(value); }); - API.getEnvironmentStatus(EnvironmentKey.Nextflow).then((status) => { - setNextflowStatus(status); + API.settingsGet(SettingsKey.PermitAddRepos).then((value) => { + setPermitAddRepos(value); + }); + API.settingsGet(SettingsKey.DisableSchemaValidation).then((value) => { + setDisableSchemaValidation(value); }); if (pathRef.current && document.activeElement !== pathRef.current) { pathRef.current.value = collectionsPath ?? ''; @@ -125,11 +142,6 @@ export default function SettingsPage({ sx={{ borderRight: 1, borderColor: 'divider' }} > - @@ -148,34 +160,46 @@ export default function SettingsPage({ onBlur={handlePathBlur} sx={{ mt: 2 }} /> - setAllowArbitraryRepoCloning(!allowArbitraryRepoCloning)} + id="settings-permit-add-catalogues" + checked={permitAddCatalogues} + onChange={() => handlePermitAddCatalogues(!permitAddCatalogues)} /> } - label={t('settings.allow-arbitrary-repo-cloning')} + label={t('settings.permit-add-catalogues')} /> - - - - handlePermitCatalogueModifications(!permitCatalogueModifications)} + /> + } + label={t('settings.permit-catalogue-modifications')} + /> + handlePermitAddRepos(!permitAddRepos)} + /> + } + label={t('settings.permit-add-repos')} /> - + setDarkMode(!darkMode)} />} + control={ handleDarkMode(!darkMode)} />} label={t('settings.dark-mode')} /> - + onChangeProject(e.target.value)} - size="small" - > - {projectsList.map((proj, index) => ( - {proj.name} - ))} - - )} diff --git a/src/renderer/services/api.ts b/src/renderer/services/api.ts index 90a828f..b64967e 100644 --- a/src/renderer/services/api.ts +++ b/src/renderer/services/api.ts @@ -25,10 +25,21 @@ const electronAPI = isElectron getWorkLog: (instance, workID, logType) => window.electronAPI.getWorkLog(instance, workID, logType), getAvailableProfiles: (instance) => window.electronAPI.getAvailableProfiles(instance), - cloneRepo: (repoUrl, ver) => window.electronAPI.cloneRepo(repoUrl, ver), + isRepoInstalled: (repoUrl, ver) => window.electronAPI.isRepoInstalled(repoUrl, ver), syncRepo: (repo) => window.electronAPI.syncRepo(repo), - getCollections: () => window.electronAPI.getCollections(), + addCatalogue: (repoUrl, ver) => window.electronAPI.addCatalogue(repoUrl, ver), + removeCatalogue: (catalogue_name) => window.electronAPI.removeCatalogue(catalogue_name), + removeCatalogueSection: (catalogue_name, section_name) => + window.electronAPI.removeCatalogueSection(catalogue_name, section_name), + removeCatalogueWorkflow: (catalogue_name, section_name, workflow_name) => + window.electronAPI.removeCatalogueWorkflow(catalogue_name, section_name, workflow_name), + updateCatalogueWorkflow: (catalogue_name, section_name, workflow_name) => + window.electronAPI.updateCatalogueWorkflow(catalogue_name, section_name, workflow_name), + getCatalogues: () => window.electronAPI.getCatalogues(), + addUserWorkflow: (name, repoUrl, ver, section) => + window.electronAPI.addUserWorkflow(name, repoUrl, ver, section), + getCollectionRepos: () => window.electronAPI.getCollectionRepos(), getCollectionsPath: () => window.electronAPI.getCollectionsPath(), setCollectionsPath: (path) => window.electronAPI.setCollectionsPath(path), getContainerLogs: (containerId) => window.electronAPI.getContainerLogs(containerId), @@ -36,9 +47,6 @@ const electronAPI = isElectron deleteRepo: (repoPath) => window.electronAPI.deleteRepo(repoPath), getWorkflowParams: (repoPath) => window.electronAPI.getWorkflowParams(repoPath), getWorkflowSchema: (repoPath) => window.electronAPI.getWorkflowSchema(repoPath), - getProjectsList: () => window.electronAPI.getProjectsList(), - addProject: (repoPath) => window.electronAPI.addProject(repoPath), - removeProject: (project) => window.electronAPI.removeProject(project), getInstallableReposList: () => window.electronAPI.getInstallableReposList(), addInstallableRepo: (repoUrl) => window.electronAPI.addInstallableRepo(repoUrl), getWorkflowInformation: (instance) => window.electronAPI.getWorkflowInformation(instance), @@ -60,7 +68,8 @@ const httpDispatch = async (endpoint, method = 'GET', body = null) => { } const res = await fetch(endpoint, options); if (!res.ok) throw new Error(`HTTP error at ${endpoint}, status: ${res.status}`); - return res.json(); + const js = res.json(); + return js; }; const httpAPI = { @@ -96,8 +105,31 @@ const httpAPI = { getAvailableProfiles: async (instance) => httpDispatch('/api/get-available-profiles', 'POST', { instance }), cloneRepo: async (repoUrl, ver) => httpDispatch('/api/clone-repo', 'POST', { repoUrl, ver }), + isRepoInstalled: async (repoUrl, ver) => + httpDispatch('/api/is-repo-installed', 'POST', { repoUrl, ver }), syncRepo: async (repo) => httpDispatch('/api/sync-repo', 'POST', { repo }), - getCollections: async () => httpDispatch('/api/get-collections', 'POST', {}), + addCatalogue: async (repoUrl, ver) => + httpDispatch('/api/add-catalogue', 'POST', { repoUrl, ver }), + removeCatalogue: async (catalogue_name) => + httpDispatch('/api/remove-catalogue', 'POST', { catalogue_name }), + removeCatalogueSection: async (catalogue_name, section_name) => + httpDispatch('/api/remove-catalogue-section', 'POST', { catalogue_name, section_name }), + removeCatalogueWorkflow: async (catalogue_name, section_name, workflow_name) => + httpDispatch('/api/remove-catalogue-workflow', 'POST', { + catalogue_name, + section_name, + workflow_name + }), + updateCatalogueWorkflow: async (catalogue_name, section_name, workflow_name) => + httpDispatch('/api/update-catalogue-workflow', 'POST', { + catalogue_name, + section_name, + workflow_name + }), + getCatalogues: async () => httpDispatch('/api/get-catalogues', 'POST', {}), + addUserWorkflow: async (name, repoUrl, ver, section) => + httpDispatch('/api/add-user-workflow', 'POST', { name, repoUrl, ver, section }), + getCollectionRepos: async () => httpDispatch('/api/get-collection-repos', 'POST', {}), getCollectionsPath: async () => httpDispatch('/api/get-collections-path', 'POST', {}), setCollectionsPath: async (path) => httpDispatch('/api/set-collections-path', 'POST', { path }), getContainerLogs: async (containerId) => @@ -109,9 +141,6 @@ const httpAPI = { httpDispatch('/api/get-workflow-params', 'POST', { repoPath }), getWorkflowSchema: async (repoPath) => httpDispatch('/api/get-workflow-schema', 'POST', { repoPath }), - getProjectsList: async () => httpDispatch('/api/get-projects-list', 'POST', {}), - addProject: async (repoPath) => httpDispatch('/api/add-project', 'POST', { repoPath }), - removeProject: async (project) => httpDispatch('/api/remove-project', 'POST', { project }), getInstallableReposList: async () => httpDispatch('/api/get-installable-repos-list', 'POST', {}), addInstallableRepo: async (repoUrl) => httpDispatch('/api/add-installable-repo', 'POST', { repoUrl }), diff --git a/src/runners/nextflow/nextflow.ts b/src/runners/nextflow/nextflow.ts index fd25646..968f309 100644 --- a/src/runners/nextflow/nextflow.ts +++ b/src/runners/nextflow/nextflow.ts @@ -19,7 +19,12 @@ export interface IRunWorkflowOpts { const is_windows = process.platform === 'win32'; const toPosixPath = (base: string) => { - return slash(base).replace('C:', '/mnt/c'); + return slash( + base.replace( + /^([A-Za-z]):\\/, + (_, drive) => `/mnt/${drive.toLowerCase()}/` + ) + ); }; const resolvePath = (base: string, name: string) => { @@ -205,12 +210,34 @@ export async function runWorkflow( '-Dcapsule.trampoline', '-Dcom.sun.security.enableAIAcaIssuers=true', '-Djava.awt.headless=true', + + // performance '-XX:+TieredCompilation', '-XX:TieredStopAtLevel=1', + + // Native access + '--enable-native-access=ALL-UNNAMED', + + // Core reflection (Groovy / Nextflow) '--add-opens=java.base/java.lang=ALL-UNNAMED', + '--add-opens=java.base/java.lang.reflect=ALL-UNNAMED', '--add-opens=java.base/java.io=ALL-UNNAMED', - '--enable-native-access=ALL-UNNAMED', - '--sun-misc-unsafe-memory-access=allow' + + // Collections / Kryo serializers + '--add-opens=java.base/java.util=ALL-UNNAMED', + '--add-opens=java.base/java.util.concurrent=ALL-UNNAMED', + + // FileSystemProvider injection + '--add-opens=java.base/java.nio.file.spi=ALL-UNNAMED', + '--add-exports=java.base/java.nio.file.spi=ALL-UNNAMED', + + // FTP support (Nextflow HTTP/FTP provider) + '--add-exports=java.base/sun.net.www.protocol.ftp=ALL-UNNAMED', + '--add-opens=java.base/sun.net.www.protocol.ftp=ALL-UNNAMED', + + // Internal memory access + '--add-exports=java.base/jdk.internal.misc=ALL-UNNAMED', + '--add-opens=java.base/jdk.internal.misc=ALL-UNNAMED' ]; console.log(`Spawning nextflow with command: nextflow ${cmd.join(' ')} from ${instancePath}`); diff --git a/src/types/settings.ts b/src/types/settings.ts index 7585dbb..d1f29ec 100644 --- a/src/types/settings.ts +++ b/src/types/settings.ts @@ -1,7 +1,10 @@ // Keep in sync with main/store.js export const SettingsKey = { CollectionsPath: 'collectionsPath', - DisableProjects: 'disableProjects', + DarkMode: 'darkMode', + PermitAddCatalogues: 'permitAddCatalogues', + PermitCatalogueModifications: 'permitCatalogueModifications', + PermitAddRepos: 'permitAddRepos', DisableSchemaValidation: 'disableSchemaValidation' } as const; diff --git a/tests/e2e/fixtures.ts b/tests/e2e/fixtures.ts index a763c3d..e5a722a 100644 --- a/tests/e2e/fixtures.ts +++ b/tests/e2e/fixtures.ts @@ -7,11 +7,24 @@ type Fixtures = { export const test = base.extend({ page: async ({ browser, page }, use, testInfo) => { if (testInfo.project.name.includes('Electron')) { + + // Electron mode + const electronApp: ElectronApplication = await electron.launch({ args: ['.', '--fullscreen', '--no-sandbox'] }); + + // Capture main process stdout/stderr + const proc = await electronApp.process(); + proc.stdout.on('data', (chunk) => process.stdout.write(`[main] ${chunk}`)); + proc.stderr.on('data', (chunk) => process.stderr.write(`[main:error] ${chunk}`)); + const win = await electronApp.firstWindow(); + // Capture renderer console + win.on('console', (msg) => console.log(`[renderer:${msg.type()}] ${msg.text()}`)); + win.on('pageerror', (err) => console.error(`[renderer:error] ${err}`)); + await electronApp.evaluate(({ BrowserWindow }) => { const win = BrowserWindow.getAllWindows()[0]; win.setBounds({ width: 1024, height: 768 }); diff --git a/tests/e2e/ui.spec.ts b/tests/e2e/ui.spec.ts index e97e89f..a84fb62 100644 --- a/tests/e2e/ui.spec.ts +++ b/tests/e2e/ui.spec.ts @@ -39,6 +39,12 @@ test('clone a repository', async ({ page }) => { const library_path = path.resolve(path.join(glacier_path, 'library')); fs.mkdirSync(library_path, { recursive: true }); // rebuild await page.fill('#settings-collections-path', `${library_path}`); + await page.locator('#settings-collections-path').blur(); + + // Ensure repositories and catalogues can be modified in settings + await page.check('#settings-permit-add-catalogues'); + await page.check('#settings-permit-catalogue-modifications'); + await page.check('#settings-permit-add-repos'); // Use English language for this test await page.click('#settings-language-panel'); @@ -49,46 +55,27 @@ test('clone a repository', async ({ page }) => { // Check that the Library is empty await page.click('#sidebar-library-button'); - expect(await page.locator('[id^="collections-sync-"]').count()).toBe(0); - - // --- Navigate to Hub page - await page.click('#sidebar-hub-button'); + await expect(page.getByText('No repositories installed.')).toBeVisible({ timeout: TIMEOUT_10s }); // Add repository const repo_owner = 'jsbrittain'; const repo_name = 'workflow-runner-test-nextflow'; - await page.fill('#collections-repo-url', `${repo_owner}/${repo_name}`); - await page.click('#collections-add-button'); - await page.waitForSelector('#hub-install-workflow-runner-test-nextflow', { - timeout: TIMEOUT_10s - }); - - // Clone the new repository - await page.click('#hub-install-workflow-runner-test-nextflow'); - // --- Navigate to Library page - await page.click('#sidebar-library-button'); - for (let i = 0; i < 30; i++) { - if ((await page.locator(`[id="collections-sync-${cssEscape(repo_name)}"]`).count()) == 1) { - break; - } - await page.reload(); - await page.waitForLoadState('networkidle'); - await page.click('#sidebar-library-button'); - await page.waitForTimeout(1000); - } - - // Find the cloned workflow - await expect(page.locator('h6').filter({ hasText: 'workflow-runner-test-nextflow' })).toBeVisible( - { timeout: TIMEOUT_10s } - ); - - // Sync the repository - await page.click(`#collections-sync-${cssEscape(repo_name)}`); - await waitForLogLine(page, 'Repository synced'); + // Click Actions menu button + await page.click('#library-actions-menu-button'); + await page.click('#library-actions-menu-add-repo'); + // Fill in repo details + await page.fill('#query-add-workflow-repo-url', `${repo_owner}/${repo_name}`); + await page.fill('#query-add-workflow-repo-version', 'main'); + await page.click('#query-add-workflow-dialog-okay-button'); + // Wait for workflow to be added + await expect(page.getByText('User collection')).toBeVisible({ timeout: TIMEOUT_10s }); + await expect(page.getByText(repo_name)).toBeVisible({ timeout: TIMEOUT_10s }); + // Click Install (clone the repository) + await page.click(`#install-${cssEscape(repo_name)}`); // Create an instance of the workflow (redirects to Parameters page) - await page.click(`#collections-run-${cssEscape(repo_name)}`); + await page.click(`#run-${cssEscape(repo_name)}`); // 'Launch Workflow' button should now be visible await expect(page.getByRole('button', { name: 'Launch Workflow' })).toBeVisible({ timeout: TIMEOUT_10s @@ -96,43 +83,22 @@ test('clone a repository', async ({ page }) => { }); test('launch local workflow', async ({ page }) => { - const local_workflow_path = path.resolve( - path.join(__dirname, '..', 'test-data', 'sleep@undefined') - ); + const local_collections_path = path.resolve(path.join(__dirname, '..', 'test-data')); // Navigate to Settings page await page.click('#sidebar-settings-button'); // Get the library path await page.click('#settings-general-panel'); - const library_path = await page.inputValue('#settings-collections-path'); - const dest_path = path.join(library_path, 'workflows', 'local', 'sleep@undefined'); - - // Copy the local workflow to the library path - fs.cpSync(local_workflow_path, dest_path, { recursive: true }); - - // Check folder exists - if (!fs.existsSync(dest_path)) { - throw new Error(`Failed to copy local workflow to library: ${dest_path}`); - } - - // Force refresh of workflows (change collections-path twice) - await page.fill('#settings-collections-path', library_path + '_temp'); - await page.locator('#settings-collections-path').blur(); // trigger change event - await page.fill('#settings-collections-path', library_path); + await page.fill('#settings-collections-path', `${local_collections_path}`); await page.locator('#settings-collections-path').blur(); // --- Navigate to Library page await page.click('#sidebar-library-button'); const repo_name = 'sleep'; - // Find the cloned workflow - await expect(page.locator('h6').filter({ hasText: repo_name })).toBeVisible({ - timeout: TIMEOUT_10s - }); - // Create an instance of the workflow (redirects to Parameters page) - await page.click(`#collections-run-${cssEscape(repo_name)}`); + await page.click(`#run-${cssEscape(repo_name)}`); // Default display is Description, switch to Parameters tab await page.click('#parameters-params-tab'); diff --git a/tests/test-data/catalogues/user_collection/store/catalogue.json b/tests/test-data/catalogues/user_collection/store/catalogue.json new file mode 100644 index 0000000..9de4286 --- /dev/null +++ b/tests/test-data/catalogues/user_collection/store/catalogue.json @@ -0,0 +1,16 @@ +{ + "name": "User collection", + "source": "local", + "sections": [ + { + "name": "My Workflows", + "workflows": [ + { + "name": "sleep", + "repo": "glacier/sleep", + "version": "main" + } + ] + } + ] +} diff --git a/tests/test-data/sleep@undefined/main.nf b/tests/test-data/workflows/glacier/sleep@main/main.nf similarity index 100% rename from tests/test-data/sleep@undefined/main.nf rename to tests/test-data/workflows/glacier/sleep@main/main.nf diff --git a/tests/test-data/sleep@undefined/nextflow_schema.json b/tests/test-data/workflows/glacier/sleep@main/nextflow_schema.json similarity index 100% rename from tests/test-data/sleep@undefined/nextflow_schema.json rename to tests/test-data/workflows/glacier/sleep@main/nextflow_schema.json diff --git a/tests/test-data/sleep@undefined/params.json b/tests/test-data/workflows/glacier/sleep@main/params.json similarity index 100% rename from tests/test-data/sleep@undefined/params.json rename to tests/test-data/workflows/glacier/sleep@main/params.json